Merge branch 'x86-build-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 Mar 2020 17:51:12 +0000 (10:51 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 Mar 2020 17:51:12 +0000 (10:51 -0700)
Pull x86 build updates from Ingo Molnar:
 "A handful of updates: two linker script cleanups and a stock
  defconfig+allmodconfig bootability fix"

* 'x86-build-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/vdso: Discard .note.gnu.property sections in vDSO
  x86, vmlinux.lds: Add RUNTIME_DISCARD_EXIT to generic DISCARDS
  x86/Kconfig: Make CMDLINE_OVERRIDE depend on non-empty CMDLINE

3657 files changed:
.clang-format
.mailmap
CREDITS
Documentation/ABI/removed/sysfs-kernel-uids [moved from Documentation/ABI/testing/sysfs-kernel-uids with 91% similarity]
Documentation/ABI/testing/configfs-most [moved from drivers/staging/most/Documentation/ABI/configfs-most.txt with 94% similarity]
Documentation/ABI/testing/sysfs-bus-counter-104-quad-8
Documentation/ABI/testing/sysfs-bus-iio-adc-ad7192
Documentation/ABI/testing/sysfs-bus-most [moved from drivers/staging/most/Documentation/ABI/sysfs-bus-most.txt with 92% similarity]
Documentation/ABI/testing/sysfs-class-typec
Documentation/Makefile
Documentation/PCI/pci.rst
Documentation/RCU/Design/Memory-Ordering/Tree-RCU-Memory-Ordering.rst
Documentation/RCU/listRCU.rst
Documentation/RCU/rcu.rst
Documentation/RCU/torture.txt
Documentation/accounting/psi.rst
Documentation/admin-guide/acpi/fan_performance_states.rst
Documentation/admin-guide/binfmt-misc.rst
Documentation/admin-guide/blockdev/zram.rst
Documentation/admin-guide/bootconfig.rst
Documentation/admin-guide/cgroup-v1/index.rst
Documentation/admin-guide/cgroup-v2.rst
Documentation/admin-guide/edid.rst [moved from Documentation/driver-api/edid.rst with 98% similarity]
Documentation/admin-guide/hw-vuln/tsx_async_abort.rst
Documentation/admin-guide/index.rst
Documentation/admin-guide/iostats.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/kernel-per-CPU-kthreads.rst
Documentation/admin-guide/perf/imx-ddr.rst
Documentation/admin-guide/pm/cpufreq_drivers.rst [new file with mode: 0644]
Documentation/admin-guide/pm/cpuidle.rst
Documentation/admin-guide/pm/intel_pstate.rst
Documentation/admin-guide/pm/working-state.rst
Documentation/admin-guide/sysctl/kernel.rst
Documentation/arm/tcm.rst
Documentation/arm64/amu.rst [new file with mode: 0644]
Documentation/arm64/booting.rst
Documentation/arm64/index.rst
Documentation/arm64/silicon-errata.rst
Documentation/block/capability.rst
Documentation/conf.py
Documentation/core-api/index.rst
Documentation/core-api/kobject.rst [moved from Documentation/kobject.txt with 87% similarity]
Documentation/cpu-freq/amd-powernow.txt [deleted file]
Documentation/cpu-freq/core.rst [moved from Documentation/cpu-freq/core.txt with 69% similarity]
Documentation/cpu-freq/cpu-drivers.rst [moved from Documentation/cpu-freq/cpu-drivers.txt with 72% similarity]
Documentation/cpu-freq/cpufreq-nforce2.txt [deleted file]
Documentation/cpu-freq/cpufreq-stats.rst [moved from Documentation/cpu-freq/cpufreq-stats.txt with 53% similarity]
Documentation/cpu-freq/index.rst [new file with mode: 0644]
Documentation/cpu-freq/index.txt [deleted file]
Documentation/cpu-freq/pcc-cpufreq.txt [deleted file]
Documentation/debugging-modules.txt [deleted file]
Documentation/dev-tools/gcov.rst
Documentation/dev-tools/kmemleak.rst
Documentation/dev-tools/kunit/usage.rst
Documentation/devicetree/bindings/arm/arm,scmi.txt
Documentation/devicetree/bindings/arm/arm,scpi.txt
Documentation/devicetree/bindings/arm/bcm/brcm,bcm63138.txt
Documentation/devicetree/bindings/arm/cpus.yaml
Documentation/devicetree/bindings/arm/fsl.yaml
Documentation/devicetree/bindings/arm/hisilicon/hi3519-sysctrl.txt
Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt
Documentation/devicetree/bindings/arm/omap/mpu.txt
Documentation/devicetree/bindings/arm/psci.yaml
Documentation/devicetree/bindings/arm/stm32/st,mlahb.yaml
Documentation/devicetree/bindings/bus/allwinner,sun8i-a23-rsb.yaml
Documentation/devicetree/bindings/clock/allwinner,sun4i-a10-osc-clk.yaml
Documentation/devicetree/bindings/clock/allwinner,sun9i-a80-gt-clk.yaml
Documentation/devicetree/bindings/clock/qcom,gcc-apq8064.yaml
Documentation/devicetree/bindings/crypto/allwinner,sun4i-a10-crypto.yaml
Documentation/devicetree/bindings/display/allwinner,sun4i-a10-tv-encoder.yaml
Documentation/devicetree/bindings/display/bridge/anx6345.yaml
Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt
Documentation/devicetree/bindings/display/panel/leadtek,ltk500hd1829.yaml
Documentation/devicetree/bindings/display/panel/xinpeng,xpp055c272.yaml
Documentation/devicetree/bindings/display/simple-framebuffer.yaml
Documentation/devicetree/bindings/display/tilcdc/tilcdc.txt
Documentation/devicetree/bindings/dma/ti/k3-udma.yaml
Documentation/devicetree/bindings/edac/dmc-520.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/gpu/arm,mali-bifrost.yaml
Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml
Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/adt7475.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/hwmon/ltc2978.txt
Documentation/devicetree/bindings/iio/adc/adi,ad7923.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/max1363.txt [deleted file]
Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/maxim,max1363.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/nuvoton,npcm-adc.txt
Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml
Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt [deleted file]
Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt [deleted file]
Documentation/devicetree/bindings/iio/chemical/atlas,orp-sm.txt [deleted file]
Documentation/devicetree/bindings/iio/chemical/atlas,ph-sm.txt [deleted file]
Documentation/devicetree/bindings/iio/chemical/atlas,sensor.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/dac/ltc2632.txt
Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
Documentation/devicetree/bindings/iio/light/dynaimage,al3010.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/light/dynaimage,al3320a.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/light/sharp,gp2ap002.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/iio/proximity/devantech-srf04.yaml
Documentation/devicetree/bindings/input/cypress,tm2-touchkey.txt
Documentation/devicetree/bindings/input/touchscreen/goodix.yaml
Documentation/devicetree/bindings/input/twl4030-pwrbutton.txt
Documentation/devicetree/bindings/interrupt-controller/loongson,htpic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/interrupt-controller/loongson,liointc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/leds/common.yaml
Documentation/devicetree/bindings/leds/register-bit-led.txt
Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/allwinner,sun8i-h3-deinterlace.yaml
Documentation/devicetree/bindings/media/aspeed-video.txt
Documentation/devicetree/bindings/media/i2c/imx219.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/i2c/tvp5150.txt
Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/qcom,msm8916-venus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/qcom,msm8996-venus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/qcom,sdm845-venus.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/qcom,venus.txt [deleted file]
Documentation/devicetree/bindings/media/rc.yaml
Documentation/devicetree/bindings/media/rockchip-rga.txt
Documentation/devicetree/bindings/media/ti,cal.yaml
Documentation/devicetree/bindings/memory-controllers/ti/emif.txt
Documentation/devicetree/bindings/mfd/max77650.yaml
Documentation/devicetree/bindings/mfd/qcom-rpm.txt
Documentation/devicetree/bindings/mfd/tps65910.txt
Documentation/devicetree/bindings/mfd/twl-family.txt [moved from Documentation/devicetree/bindings/mfd/twl-familly.txt with 100% similarity]
Documentation/devicetree/bindings/mfd/zii,rave-sp.txt
Documentation/devicetree/bindings/mips/loongson/devices.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
Documentation/devicetree/bindings/mmc/mmc-controller.yaml
Documentation/devicetree/bindings/mtd/cadence-nand-controller.txt
Documentation/devicetree/bindings/net/brcm,bcm7445-switch-v4.0.txt
Documentation/devicetree/bindings/net/fsl-fman.txt
Documentation/devicetree/bindings/nvmem/nvmem.yaml
Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
Documentation/devicetree/bindings/phy/allwinner,sun4i-a10-usb-phy.yaml
Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml
Documentation/devicetree/bindings/phy/phy-cadence-dp.txt [deleted file]
Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt
Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom-dwc3-usb-phy.txt [deleted file]
Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt [deleted file]
Documentation/devicetree/bindings/phy/ti-phy-gmii-sel.txt
Documentation/devicetree/bindings/phy/uniphier-pcie-phy.txt
Documentation/devicetree/bindings/phy/uniphier-usb3-hsphy.txt
Documentation/devicetree/bindings/phy/uniphier-usb3-ssphy.txt
Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml
Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml
Documentation/devicetree/bindings/power/domain-idle-state.txt [deleted file]
Documentation/devicetree/bindings/power/domain-idle-state.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/power/power-domain.yaml
Documentation/devicetree/bindings/power/power_domain.txt
Documentation/devicetree/bindings/regulator/mp886x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/mps,mp5416.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.txt
Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.txt
Documentation/devicetree/bindings/regulator/regulator.yaml
Documentation/devicetree/bindings/regulator/vqmmc-ipq4019-regulator.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/reset/intel,rcu-gw.yaml
Documentation/devicetree/bindings/reset/st,stm32mp1-rcc.txt
Documentation/devicetree/bindings/sound/st,stm32-sai.txt
Documentation/devicetree/bindings/sound/st,stm32-spdifrx.txt
Documentation/devicetree/bindings/spi/amlogic,meson-gx-spicc.yaml
Documentation/devicetree/bindings/spi/fsl-imx-cspi.txt
Documentation/devicetree/bindings/spi/qca,ar934x-spi.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-controller.yaml
Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt
Documentation/devicetree/bindings/spi/spi-mtk-nor.txt [moved from Documentation/devicetree/bindings/mtd/mtk-quadspi.txt with 75% similarity]
Documentation/devicetree/bindings/spi/spi-mux.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi-nxp-fspi.txt
Documentation/devicetree/bindings/spi/spi-rockchip.txt [deleted file]
Documentation/devicetree/bindings/spi/spi-rockchip.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/spi/st,stm32-spi.yaml
Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml
Documentation/devicetree/bindings/thermal/brcm,avs-ro-thermal.yaml
Documentation/devicetree/bindings/timer/allwinner,sun4i-a10-timer.yaml
Documentation/devicetree/bindings/timer/faraday,fttmr010.txt
Documentation/devicetree/bindings/timer/ingenic,tcu.txt
Documentation/devicetree/bindings/trivial-devices.yaml
Documentation/devicetree/bindings/usb/amlogic,meson-g12a-usb-ctrl.yaml
Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/dwc2.yaml
Documentation/devicetree/bindings/usb/dwc3.txt
Documentation/devicetree/bindings/usb/generic.txt
Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt [deleted file]
Documentation/devicetree/bindings/usb/ingenic,jz4770-phy.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/ingenic,musb.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/usb/maxim,max3420-udc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/vendor-prefixes.yaml
Documentation/driver-api/80211/mac80211-advanced.rst
Documentation/driver-api/dmaengine/client.rst
Documentation/driver-api/dmaengine/index.rst
Documentation/driver-api/dmaengine/provider.rst
Documentation/driver-api/driver-model/driver.rst
Documentation/driver-api/firmware/efi/index.rst [new file with mode: 0644]
Documentation/driver-api/firmware/fallback-mechanisms.rst
Documentation/driver-api/firmware/index.rst
Documentation/driver-api/firmware/lookup-order.rst
Documentation/driver-api/firmware/request_firmware.rst
Documentation/driver-api/index.rst
Documentation/driver-api/io-mapping.rst [moved from Documentation/io-mapping.txt with 100% similarity]
Documentation/driver-api/io_ordering.rst [moved from Documentation/io_ordering.txt with 100% similarity]
Documentation/driver-api/ioctl.rst [moved from Documentation/core-api/ioctl.rst with 100% similarity]
Documentation/driver-api/usb/typec_bus.rst
Documentation/features/vm/pte_special/arch-support.txt
Documentation/filesystems/9p.rst [moved from Documentation/filesystems/9p.txt with 63% similarity]
Documentation/filesystems/adfs.rst [moved from Documentation/filesystems/adfs.txt with 85% similarity]
Documentation/filesystems/affs.rst [moved from Documentation/filesystems/affs.txt with 86% similarity]
Documentation/filesystems/afs.rst [moved from Documentation/filesystems/afs.txt with 90% similarity]
Documentation/filesystems/autofs-mount-control.rst [moved from Documentation/filesystems/autofs-mount-control.txt with 89% similarity]
Documentation/filesystems/befs.rst [moved from Documentation/filesystems/befs.txt with 83% similarity]
Documentation/filesystems/bfs.rst [moved from Documentation/filesystems/bfs.txt with 71% similarity]
Documentation/filesystems/btrfs.rst [moved from Documentation/filesystems/btrfs.txt with 96% similarity]
Documentation/filesystems/ceph.rst [moved from Documentation/filesystems/ceph.txt with 91% similarity]
Documentation/filesystems/cifs/cifsroot.txt
Documentation/filesystems/cramfs.rst [moved from Documentation/filesystems/cramfs.txt with 88% similarity]
Documentation/filesystems/debugfs.rst [moved from Documentation/filesystems/debugfs.txt with 88% similarity]
Documentation/filesystems/dlmfs.rst [moved from Documentation/filesystems/dlmfs.txt with 86% similarity]
Documentation/filesystems/ecryptfs.rst [moved from Documentation/filesystems/ecryptfs.txt with 62% similarity]
Documentation/filesystems/efivarfs.rst [moved from Documentation/filesystems/efivarfs.txt with 85% similarity]
Documentation/filesystems/erofs.rst [moved from Documentation/filesystems/erofs.txt with 54% similarity]
Documentation/filesystems/ext2.rst [moved from Documentation/filesystems/ext2.txt with 91% similarity]
Documentation/filesystems/ext3.rst [moved from Documentation/filesystems/ext3.txt with 88% similarity]
Documentation/filesystems/f2fs.rst [moved from Documentation/filesystems/f2fs.txt with 84% similarity]
Documentation/filesystems/fuse.rst
Documentation/filesystems/gfs2-uevents.rst [moved from Documentation/filesystems/gfs2-uevents.txt with 94% similarity]
Documentation/filesystems/gfs2.rst [moved from Documentation/filesystems/gfs2.txt with 76% similarity]
Documentation/filesystems/hfs.rst [moved from Documentation/filesystems/hfs.txt with 80% similarity]
Documentation/filesystems/hfsplus.rst [moved from Documentation/filesystems/hfsplus.txt with 95% similarity]
Documentation/filesystems/hpfs.rst [moved from Documentation/filesystems/hpfs.txt with 66% similarity]
Documentation/filesystems/index.rst
Documentation/filesystems/inotify.rst [moved from Documentation/filesystems/inotify.txt with 83% similarity]
Documentation/filesystems/isofs.rst [new file with mode: 0644]
Documentation/filesystems/isofs.txt [deleted file]
Documentation/filesystems/nfs/index.rst [new file with mode: 0644]
Documentation/filesystems/nfs/knfsd-stats.rst [moved from Documentation/filesystems/nfs/knfsd-stats.txt with 95% similarity]
Documentation/filesystems/nfs/nfs41-server.rst [new file with mode: 0644]
Documentation/filesystems/nfs/nfs41-server.txt [deleted file]
Documentation/filesystems/nfs/pnfs.rst [moved from Documentation/filesystems/nfs/pnfs.txt with 87% similarity]
Documentation/filesystems/nfs/rpc-cache.rst [moved from Documentation/filesystems/nfs/rpc-cache.txt with 66% similarity]
Documentation/filesystems/nfs/rpc-server-gss.rst [moved from Documentation/filesystems/nfs/rpc-server-gss.txt with 92% similarity]
Documentation/filesystems/nilfs2.rst [moved from Documentation/filesystems/nilfs2.txt with 89% similarity]
Documentation/filesystems/ntfs.rst [moved from Documentation/filesystems/ntfs.txt with 85% similarity]
Documentation/filesystems/ocfs2-online-filecheck.rst [moved from Documentation/filesystems/ocfs2-online-filecheck.txt with 77% similarity]
Documentation/filesystems/ocfs2.rst [moved from Documentation/filesystems/ocfs2.txt with 88% similarity]
Documentation/filesystems/omfs.rst [new file with mode: 0644]
Documentation/filesystems/omfs.txt [deleted file]
Documentation/filesystems/orangefs.rst [moved from Documentation/filesystems/orangefs.txt with 83% similarity]
Documentation/filesystems/porting.rst
Documentation/filesystems/proc.rst [moved from Documentation/filesystems/proc.txt with 65% similarity]
Documentation/filesystems/qnx6.rst [moved from Documentation/filesystems/qnx6.txt with 98% similarity]
Documentation/filesystems/ramfs-rootfs-initramfs.rst [moved from Documentation/filesystems/ramfs-rootfs-initramfs.txt with 91% similarity]
Documentation/filesystems/relay.rst [moved from Documentation/filesystems/relay.txt with 91% similarity]
Documentation/filesystems/romfs.rst [moved from Documentation/filesystems/romfs.txt with 86% similarity]
Documentation/filesystems/squashfs.rst [moved from Documentation/filesystems/squashfs.txt with 91% similarity]
Documentation/filesystems/sysfs.rst [moved from Documentation/filesystems/sysfs.txt with 56% similarity]
Documentation/filesystems/sysv-fs.rst [moved from Documentation/filesystems/sysv-fs.txt with 73% similarity]
Documentation/filesystems/tmpfs.rst [moved from Documentation/filesystems/tmpfs.txt with 86% similarity]
Documentation/filesystems/ubifs-authentication.rst
Documentation/filesystems/ubifs.rst [moved from Documentation/filesystems/ubifs.txt with 91% similarity]
Documentation/filesystems/udf.rst [moved from Documentation/filesystems/udf.txt with 83% similarity]
Documentation/filesystems/virtiofs.rst
Documentation/filesystems/zonefs.rst [moved from Documentation/filesystems/zonefs.txt with 86% similarity]
Documentation/gpu/i915.rst
Documentation/hwmon/adm1177.rst
Documentation/hwmon/index.rst
Documentation/hwmon/isl68137.rst
Documentation/hwmon/k10temp.rst
Documentation/hwmon/ltc2978.rst
Documentation/hwmon/pmbus-core.rst
Documentation/hwmon/pmbus.rst
Documentation/hwmon/tps53679.rst [new file with mode: 0644]
Documentation/index.rst
Documentation/kbuild/gcc-plugins.rst [moved from Documentation/core-api/gcc-plugins.rst with 98% similarity]
Documentation/kbuild/index.rst
Documentation/kbuild/kbuild.rst
Documentation/kbuild/kconfig-macro-language.rst
Documentation/kbuild/makefiles.rst
Documentation/kbuild/modules.rst
Documentation/kernel-hacking/hacking.rst
Documentation/kernel-hacking/locking.rst
Documentation/kref.txt
Documentation/locking/index.rst
Documentation/locking/locktypes.rst [new file with mode: 0644]
Documentation/media/kapi/csi2.rst
Documentation/media/kapi/v4l2-controls.rst
Documentation/media/kapi/v4l2-dev.rst
Documentation/media/uapi/cec/cec-ioc-adap-g-conn-info.rst
Documentation/media/uapi/cec/cec-ioc-dqevent.rst
Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst
Documentation/media/uapi/v4l/buffer.rst
Documentation/media/uapi/v4l/dev-sliced-vbi.rst
Documentation/media/uapi/v4l/ext-ctrls-codec.rst
Documentation/media/uapi/v4l/pixfmt-bayer.rst
Documentation/media/uapi/v4l/pixfmt-srggb14.rst [new file with mode: 0644]
Documentation/media/uapi/v4l/pixfmt-v4l2-mplane.rst
Documentation/media/uapi/v4l/pixfmt-v4l2.rst
Documentation/media/uapi/v4l/pixfmt-y14.rst [new file with mode: 0644]
Documentation/media/uapi/v4l/subdev-formats.rst
Documentation/media/uapi/v4l/vidioc-dbg-g-chip-info.rst
Documentation/media/uapi/v4l/vidioc-dbg-g-register.rst
Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst
Documentation/media/uapi/v4l/vidioc-dqevent.rst
Documentation/media/uapi/v4l/vidioc-dv-timings-cap.rst
Documentation/media/uapi/v4l/vidioc-enum-frameintervals.rst
Documentation/media/uapi/v4l/vidioc-enum-framesizes.rst
Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst
Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst
Documentation/media/uapi/v4l/vidioc-g-fmt.rst
Documentation/media/uapi/v4l/vidioc-g-parm.rst
Documentation/media/uapi/v4l/vidioc-queryctrl.rst
Documentation/media/uapi/v4l/yuv-formats.rst
Documentation/media/v4l-drivers/ipu3.rst
Documentation/media/v4l-drivers/vivid.rst
Documentation/memory-barriers.txt
Documentation/mips/au1xxx_ide.rst [deleted file]
Documentation/mips/index.rst
Documentation/misc-devices/index.rst
Documentation/misc-devices/mic/index.rst [moved from Documentation/mic/index.rst with 100% similarity]
Documentation/misc-devices/mic/mic_overview.rst [moved from Documentation/mic/mic_overview.rst with 100% similarity]
Documentation/misc-devices/mic/scif_overview.rst [moved from Documentation/mic/scif_overview.rst with 100% similarity]
Documentation/networking/devlink/devlink-region.rst
Documentation/networking/net_failover.rst
Documentation/networking/phy.rst
Documentation/networking/rds.txt
Documentation/networking/snmp_counter.rst
Documentation/power/index.rst
Documentation/power/pm_qos_interface.rst
Documentation/power/runtime_pm.rst
Documentation/power/userland-swsusp.rst
Documentation/powerpc/ultravisor.rst
Documentation/process/2.Process.rst
Documentation/process/coding-style.rst
Documentation/process/deprecated.rst
Documentation/process/email-clients.rst
Documentation/process/howto.rst
Documentation/process/kernel-docs.rst
Documentation/process/management-style.rst
Documentation/robust-futex-ABI.txt
Documentation/scsi/scsi_mid_low_api.txt
Documentation/security/siphash.rst
Documentation/sphinx/parallel-wrapper.sh
Documentation/target/tcmu-design.rst
Documentation/trace/events-power.rst
Documentation/trace/events.rst
Documentation/translations/it_IT/networking/netdev-FAQ.rst
Documentation/translations/it_IT/process/programming-language.rst
Documentation/translations/zh_CN/filesystems/index.rst [new file with mode: 0644]
Documentation/translations/zh_CN/filesystems/virtiofs.rst [new file with mode: 0644]
Documentation/translations/zh_CN/index.rst
Documentation/translations/zh_CN/io_ordering.txt
Documentation/translations/zh_CN/process/5.Posting.rst
Documentation/translations/zh_CN/video4linux/v4l2-framework.txt
Documentation/usb/index.rst
Documentation/usb/raw-gadget.rst [new file with mode: 0644]
Documentation/userspace-api/ioctl/ioctl-number.rst
Documentation/virt/kvm/amd-memory-encryption.rst
Documentation/virt/kvm/api.rst
Documentation/x86/boot.rst
Documentation/x86/exception-tables.rst
Documentation/x86/index.rst
Documentation/x86/intel-iommu.rst
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/include/asm/futex.h
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/irq_i8259.c
arch/alpha/kernel/irq_impl.h
arch/alpha/kernel/irq_pyxis.c
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_miata.c
arch/alpha/kernel/sys_ruffian.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_sx164.c
arch/alpha/kernel/sys_wildfire.c
arch/alpha/kernel/time.c
arch/arc/Kconfig
arch/arc/configs/nps_defconfig
arch/arc/configs/nsimosci_defconfig
arch/arc/configs/nsimosci_hs_defconfig
arch/arc/configs/nsimosci_hs_smp_defconfig
arch/arc/include/asm/fpu.h
arch/arc/include/asm/futex.h
arch/arc/include/asm/linkage.h
arch/arc/kernel/setup.c
arch/arc/kernel/troubleshoot.c
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/compressed/Makefile
arch/arm/boot/compressed/efi-header.S
arch/arm/boot/compressed/head.S
arch/arm/boot/dts/am437x-idk-evm.dts
arch/arm/boot/dts/aspeed-g4.dtsi
arch/arm/boot/dts/aspeed-g5.dtsi
arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi
arch/arm/boot/dts/aspeed-g6.dtsi
arch/arm/boot/dts/bcm2711-rpi-4-b.dts
arch/arm/boot/dts/bcm2835-rpi-zero-w.dts
arch/arm/boot/dts/bcm2835-rpi.dtsi
arch/arm/boot/dts/bcm2837-rpi-3-a-plus.dts
arch/arm/boot/dts/bcm2837-rpi-3-b-plus.dts
arch/arm/boot/dts/dm8148-evm.dts
arch/arm/boot/dts/dm8148-t410.dts
arch/arm/boot/dts/dra62x-j5eco-evm.dts
arch/arm/boot/dts/dra7-evm.dts
arch/arm/boot/dts/dra7-l4.dtsi
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/dra76x.dtsi
arch/arm/boot/dts/dra7xx-clocks.dtsi
arch/arm/boot/dts/exynos4412-galaxy-s3.dtsi
arch/arm/boot/dts/exynos4412-n710x.dts
arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
arch/arm/boot/dts/imx6qdl-phytec-phycore-som.dtsi
arch/arm/boot/dts/imx7-colibri.dtsi
arch/arm/boot/dts/imx7d.dtsi
arch/arm/boot/dts/ls1021a.dtsi
arch/arm/boot/dts/motorola-mapphone-common.dtsi
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/ox810se.dtsi
arch/arm/boot/dts/ox820.dtsi
arch/arm/boot/dts/r8a7779.dtsi
arch/arm/boot/dts/sun8i-a33.dtsi
arch/arm/boot/dts/sun8i-a83t-tbs-a711.dts
arch/arm/boot/dts/sun8i-a83t.dtsi
arch/arm/boot/dts/sun8i-r40.dtsi
arch/arm/common/sa1111.c
arch/arm/configs/bcm2835_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/configs/socfpga_defconfig
arch/arm/include/asm/clocksource.h
arch/arm/include/asm/cp15.h
arch/arm/include/asm/floppy.h
arch/arm/include/asm/futex.h
arch/arm/include/asm/kvm_host.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/topology.h
arch/arm/include/asm/vdso/clocksource.h [new file with mode: 0644]
arch/arm/include/asm/vdso/cp15.h [new file with mode: 0644]
arch/arm/include/asm/vdso/gettimeofday.h
arch/arm/include/asm/vdso/processor.h [new file with mode: 0644]
arch/arm/include/asm/vdso/vsyscall.h
arch/arm/kernel/reboot.c
arch/arm/kernel/vdso.c
arch/arm/lib/copy_from_user.S
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/common.h
arch/arm/mach-imx/resume-imx6.S [new file with mode: 0644]
arch/arm/mach-imx/suspend-imx6.S
arch/arm/mach-meson/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/io.c
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/boot/dts/amlogic/meson-gxbb-kii-pro.dts
arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1043-post.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb.dts
arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
arch/arm64/boot/dts/freescale/imx8qxp-mek.dts
arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
arch/arm64/boot/dts/sprd/sc9863a.dtsi
arch/arm64/configs/defconfig
arch/arm64/crypto/aes-ce.S
arch/arm64/crypto/aes-modes.S
arch/arm64/crypto/aes-neon.S
arch/arm64/crypto/chacha-neon-glue.c
arch/arm64/crypto/ghash-ce-core.S
arch/arm64/include/asm/alternative.h
arch/arm64/include/asm/arch_gicv3.h
arch/arm64/include/asm/asm_pointer_auth.h [new file with mode: 0644]
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cache.h
arch/arm64/include/asm/cacheflush.h
arch/arm64/include/asm/checksum.h
arch/arm64/include/asm/clocksource.h
arch/arm64/include/asm/compiler.h [new file with mode: 0644]
arch/arm64/include/asm/cpu_ops.h
arch/arm64/include/asm/cpucaps.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/efi.h
arch/arm64/include/asm/esr.h
arch/arm64/include/asm/futex.h
arch/arm64/include/asm/io.h
arch/arm64/include/asm/kvm_arm.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/kvm_mmu.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/page.h
arch/arm64/include/asm/perf_event.h
arch/arm64/include/asm/pgtable-prot.h
arch/arm64/include/asm/pointer_auth.h
arch/arm64/include/asm/proc-fns.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/smp.h
arch/arm64/include/asm/stackprotector.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/thread_info.h
arch/arm64/include/asm/topology.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/vdso/clocksource.h [new file with mode: 0644]
arch/arm64/include/asm/vdso/compat_gettimeofday.h
arch/arm64/include/asm/vdso/gettimeofday.h
arch/arm64/include/asm/vdso/processor.h [new file with mode: 0644]
arch/arm64/include/asm/vdso/vsyscall.h
arch/arm64/include/asm/virt.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/armv8_deprecated.c
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/cpu-reset.S
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpu_ops.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuidle.c
arch/arm64/kernel/efi-entry.S
arch/arm64/kernel/efi-header.S
arch/arm64/kernel/entry-common.c
arch/arm64/kernel/entry-ftrace.S
arch/arm64/kernel/entry.S
arch/arm64/kernel/head.S
arch/arm64/kernel/hibernate-asm.S
arch/arm64/kernel/hibernate.c
arch/arm64/kernel/hyp-stub.S
arch/arm64/kernel/image-vars.h
arch/arm64/kernel/machine_kexec_file.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/pointer_auth.c
arch/arm64/kernel/process.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/relocate_kernel.S
arch/arm64/kernel/setup.c
arch/arm64/kernel/sleep.S
arch/arm64/kernel/smp.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/topology.c
arch/arm64/kernel/vdso/sigreturn.S
arch/arm64/kernel/vdso/vgettimeofday.c
arch/arm64/kernel/vdso32/Makefile
arch/arm64/kernel/vdso32/sigreturn.S
arch/arm64/kernel/vdso32/vgettimeofday.c
arch/arm64/kvm/hyp-init.S
arch/arm64/kvm/hyp.S
arch/arm64/kvm/hyp/fpsimd.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/sys_regs.c
arch/arm64/lib/csum.c
arch/arm64/lib/strcmp.S
arch/arm64/mm/context.c
arch/arm64/mm/mmu.c
arch/arm64/mm/proc.S
arch/arm64/mm/ptdump_debugfs.c
arch/c6x/platforms/timer64.c
arch/csky/include/asm/uaccess.h
arch/hexagon/include/asm/futex.h
arch/hexagon/include/asm/uaccess.h
arch/hexagon/kernel/smp.c
arch/hexagon/kernel/time.c
arch/ia64/include/asm/futex.h
arch/ia64/include/asm/hw_irq.h
arch/ia64/include/asm/uaccess.h
arch/ia64/kernel/efi.c
arch/ia64/kernel/esi.c
arch/ia64/kernel/irq.h [new file with mode: 0644]
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/process.c
arch/ia64/kernel/time.c
arch/ia64/mm/ioremap.c
arch/m68k/Kconfig.bus
arch/m68k/Kconfig.debug
arch/m68k/Kconfig.machine
arch/m68k/configs/amiga_defconfig
arch/m68k/configs/apollo_defconfig
arch/m68k/configs/atari_defconfig
arch/m68k/configs/bvme6000_defconfig
arch/m68k/configs/hp300_defconfig
arch/m68k/configs/mac_defconfig
arch/m68k/configs/multi_defconfig
arch/m68k/configs/mvme147_defconfig
arch/m68k/configs/mvme16x_defconfig
arch/m68k/configs/q40_defconfig
arch/m68k/configs/sun3_defconfig
arch/m68k/configs/sun3x_defconfig
arch/m68k/emu/nfblock.c
arch/m68k/include/asm/Kbuild
arch/m68k/include/asm/hardirq.h [deleted file]
arch/m68k/include/asm/mcf_pgalloc.h
arch/m68k/include/asm/motorola_pgalloc.h
arch/m68k/include/asm/motorola_pgtable.h
arch/m68k/include/asm/page.h
arch/m68k/include/asm/pgtable_mm.h
arch/m68k/include/asm/uaccess_no.h
arch/m68k/mm/init.c
arch/m68k/mm/kmap.c
arch/m68k/mm/memory.c
arch/m68k/mm/motorola.c
arch/microblaze/Kconfig
arch/microblaze/include/asm/Kbuild
arch/microblaze/include/asm/barrier.h [new file with mode: 0644]
arch/microblaze/include/asm/cache.h
arch/microblaze/include/asm/cacheflush.h
arch/microblaze/include/asm/checksum.h
arch/microblaze/include/asm/cmpxchg.h
arch/microblaze/include/asm/cpuinfo.h
arch/microblaze/include/asm/cputable.h [deleted file]
arch/microblaze/include/asm/current.h
arch/microblaze/include/asm/delay.h
arch/microblaze/include/asm/dma.h
arch/microblaze/include/asm/elf.h
arch/microblaze/include/asm/entry.h
arch/microblaze/include/asm/exceptions.h
arch/microblaze/include/asm/fixmap.h
arch/microblaze/include/asm/flat.h
arch/microblaze/include/asm/futex.h
arch/microblaze/include/asm/hw_irq.h [deleted file]
arch/microblaze/include/asm/io.h
arch/microblaze/include/asm/irq.h
arch/microblaze/include/asm/irqflags.h
arch/microblaze/include/asm/mmu.h
arch/microblaze/include/asm/mmu_context_mm.h
arch/microblaze/include/asm/module.h
arch/microblaze/include/asm/page.h
arch/microblaze/include/asm/pgalloc.h
arch/microblaze/include/asm/pgtable.h
arch/microblaze/include/asm/processor.h
arch/microblaze/include/asm/ptrace.h
arch/microblaze/include/asm/pvr.h
arch/microblaze/include/asm/registers.h
arch/microblaze/include/asm/sections.h
arch/microblaze/include/asm/setup.h
arch/microblaze/include/asm/string.h
arch/microblaze/include/asm/switch_to.h
arch/microblaze/include/asm/thread_info.h
arch/microblaze/include/asm/timex.h
arch/microblaze/include/asm/tlb.h [deleted file]
arch/microblaze/include/asm/tlbflush.h
arch/microblaze/include/asm/uaccess.h
arch/microblaze/include/asm/unaligned.h
arch/microblaze/include/asm/unistd.h
arch/microblaze/include/asm/unwind.h
arch/microblaze/include/asm/user.h [deleted file]
arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
arch/microblaze/kernel/cpu/pvr.c
arch/microblaze/kernel/entry.S
arch/microblaze/kernel/irq.c
arch/microblaze/kernel/misc.S
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/timer.c
arch/microblaze/kernel/vmlinux.lds.S
arch/microblaze/mm/init.c
arch/mips/Kconfig
arch/mips/alchemy/common/time.c
arch/mips/ar7/irq.c
arch/mips/ath25/ar2315.c
arch/mips/ath25/ar5312.c
arch/mips/ath79/setup.c
arch/mips/bcm63xx/irq.c
arch/mips/bmips/setup.c
arch/mips/boot/dts/Makefile
arch/mips/boot/dts/ingenic/ci20.dts
arch/mips/boot/dts/ingenic/jz4740.dtsi
arch/mips/boot/dts/ingenic/jz4780.dtsi
arch/mips/boot/dts/ingenic/x1000.dtsi
arch/mips/boot/dts/loongson/Makefile [new file with mode: 0644]
arch/mips/boot/dts/loongson/loongson3-package.dtsi [new file with mode: 0644]
arch/mips/boot/dts/loongson/loongson3_4core_rs780e.dts [new file with mode: 0644]
arch/mips/boot/dts/loongson/loongson3_8core_rs780e.dts [new file with mode: 0644]
arch/mips/boot/dts/loongson/rs780e-pch.dtsi [new file with mode: 0644]
arch/mips/cavium-octeon/executive/cvmx-helper-board.c
arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c
arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c
arch/mips/cavium-octeon/executive/cvmx-helper-spi.c
arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
arch/mips/cavium-octeon/executive/cvmx-helper.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/cobalt/irq.c
arch/mips/configs/ar7_defconfig
arch/mips/configs/ath25_defconfig
arch/mips/configs/ath79_defconfig
arch/mips/configs/bcm63xx_defconfig
arch/mips/configs/bmips_be_defconfig
arch/mips/configs/bmips_stb_defconfig
arch/mips/configs/ci20_defconfig
arch/mips/configs/db1xxx_defconfig
arch/mips/configs/generic/board-ni169445.config
arch/mips/configs/jazz_defconfig
arch/mips/configs/lasat_defconfig
arch/mips/configs/lemote2f_defconfig
arch/mips/configs/loongson3_defconfig
arch/mips/configs/msp71xx_defconfig
arch/mips/configs/pnx8335_stb225_defconfig
arch/mips/configs/rb532_defconfig
arch/mips/configs/rt305x_defconfig
arch/mips/configs/xway_defconfig
arch/mips/dec/setup.c
arch/mips/emma/markeins/irq.c
arch/mips/fw/lib/cmdline.c
arch/mips/generic/init.c
arch/mips/include/asm/clocksource.h
arch/mips/include/asm/dmi.h [new file with mode: 0644]
arch/mips/include/asm/elf.h
arch/mips/include/asm/futex.h
arch/mips/include/asm/i8259.h
arch/mips/include/asm/mach-ar7/irq.h
arch/mips/include/asm/mach-ath79/irq.h
arch/mips/include/asm/mach-au1x00/au1xxx_ide.h [deleted file]
arch/mips/include/asm/mach-emma2rh/irq.h
arch/mips/include/asm/mach-ip27/irq.h
arch/mips/include/asm/mach-ip30/irq.h
arch/mips/include/asm/mach-lantiq/falcon/irq.h
arch/mips/include/asm/mach-lantiq/xway/irq.h
arch/mips/include/asm/mach-lasat/irq.h
arch/mips/include/asm/mach-loongson64/boot_param.h
arch/mips/include/asm/mach-loongson64/builtin_dtbs.h [new file with mode: 0644]
arch/mips/include/asm/mach-loongson64/irq.h
arch/mips/include/asm/mach-loongson64/loongson.h
arch/mips/include/asm/mach-malta/irq.h
arch/mips/include/asm/mach-pic32/irq.h
arch/mips/include/asm/mach-pistachio/irq.h
arch/mips/include/asm/mach-ralink/irq.h
arch/mips/include/asm/mach-rm/mc146818rtc.h
arch/mips/include/asm/mach-vr41xx/irq.h
arch/mips/include/asm/mach-xilfpga/irq.h
arch/mips/include/asm/octeon/cvmx-helper-board.h
arch/mips/include/asm/octeon/cvmx-helper-rgmii.h
arch/mips/include/asm/octeon/cvmx-helper-sgmii.h
arch/mips/include/asm/octeon/cvmx-helper-spi.h
arch/mips/include/asm/octeon/cvmx-helper-util.h
arch/mips/include/asm/octeon/cvmx-helper-xaui.h
arch/mips/include/asm/octeon/cvmx-helper.h
arch/mips/include/asm/octeon/cvmx-pko.h
arch/mips/include/asm/octeon/cvmx-pow.h
arch/mips/include/asm/octeon/cvmx-wqe.h
arch/mips/include/asm/processor.h
arch/mips/include/asm/sni.h
arch/mips/include/asm/sync.h
arch/mips/include/asm/vdso/clocksource.h [new file with mode: 0644]
arch/mips/include/asm/vdso/gettimeofday.h
arch/mips/include/asm/vdso/processor.h [new file with mode: 0644]
arch/mips/include/asm/vdso/vsyscall.h
arch/mips/jazz/irq.c
arch/mips/jz4740/time.c
arch/mips/kernel/cevt-bcm1480.c
arch/mips/kernel/cevt-ds1287.c
arch/mips/kernel/cevt-gt641xx.c
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/cevt-sb1250.c
arch/mips/kernel/cevt-txx9.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/csrc-r4k.c
arch/mips/kernel/i8253.c
arch/mips/kernel/process.c
arch/mips/kernel/rtlx-mt.c
arch/mips/kernel/setup.c
arch/mips/kernel/smp.c
arch/mips/kernel/vdso.c
arch/mips/kernel/vpe.c
arch/mips/lasat/interrupt.c
arch/mips/lib/delay.c
arch/mips/lib/memcpy.S
arch/mips/loongson2ef/common/bonito-irq.c
arch/mips/loongson2ef/common/cs5536/cs5536_mfgpt.c
arch/mips/loongson2ef/fuloong-2e/irq.c
arch/mips/loongson2ef/lemote-2f/irq.c
arch/mips/loongson32/common/irq.c
arch/mips/loongson32/common/time.c
arch/mips/loongson64/Makefile
arch/mips/loongson64/env.c
arch/mips/loongson64/hpet.c
arch/mips/loongson64/init.c
arch/mips/loongson64/irq.c [deleted file]
arch/mips/loongson64/numa.c
arch/mips/loongson64/setup.c
arch/mips/loongson64/smp.c
arch/mips/mm/c-octeon.c
arch/mips/mm/c-r3k.c
arch/mips/mm/c-r4k.c
arch/mips/mm/c-tx39.c
arch/mips/mm/tlbex.c
arch/mips/mti-malta/malta-int.c
arch/mips/netlogic/xlr/fmn.c
arch/mips/pic32/pic32mzda/time.c
arch/mips/pistachio/time.c
arch/mips/pmcs-msp71xx/msp_irq.c
arch/mips/pmcs-msp71xx/msp_smp.c
arch/mips/pmcs-msp71xx/msp_time.c
arch/mips/ralink/Kconfig
arch/mips/ralink/cevt-rt3352.c
arch/mips/ralink/mt7621.c
arch/mips/ralink/timer-gic.c
arch/mips/sgi-ip22/ip22-eisa.c
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sni/a20r.c
arch/mips/sni/irq.c
arch/mips/sni/pcit.c
arch/mips/sni/rm200.c
arch/mips/sni/time.c
arch/mips/vdso/Makefile
arch/mips/vr41xx/common/irq.c
arch/nds32/include/asm/futex.h
arch/nds32/include/asm/uaccess.h
arch/openrisc/include/asm/futex.h
arch/parisc/Kconfig
arch/parisc/Makefile
arch/parisc/include/asm/futex.h
arch/parisc/kernel/processor.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/futex.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/kexec/core_64.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/mm/kasan/kasan_init_32.c
arch/powerpc/mm/mem.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/platforms/ps3/device-init.c
arch/riscv/Kconfig
arch/riscv/Kconfig.socs
arch/riscv/Makefile
arch/riscv/boot/.gitignore
arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dts
arch/riscv/configs/defconfig
arch/riscv/configs/rv32_defconfig
arch/riscv/include/asm/clint.h
arch/riscv/include/asm/csr.h
arch/riscv/include/asm/futex.h
arch/riscv/include/asm/pgtable.h
arch/riscv/include/asm/syscall.h
arch/riscv/include/asm/uaccess.h
arch/riscv/kernel/entry.S
arch/riscv/kernel/head.S
arch/riscv/kernel/module.c
arch/riscv/kernel/ptrace.c
arch/riscv/kernel/smp.c
arch/riscv/kernel/traps.c
arch/riscv/lib/Makefile
arch/riscv/mm/init.c
arch/riscv/mm/kasan_init.c
arch/s390/include/asm/futex.h
arch/s390/include/asm/pgtable.h
arch/s390/kvm/kvm-s390.c
arch/s390/pci/pci.c
arch/sh/boards/mach-cayman/irq.c
arch/sh/drivers/dma/dma-pvr2.c
arch/sh/include/asm/futex.h
arch/sparc/Kconfig
arch/sparc/include/asm/futex_64.h
arch/sparc/kernel/ds.c
arch/unicore32/include/asm/io.h
arch/unicore32/kernel/time.c
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/Makefile
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/eboot.h [deleted file]
arch/x86/boot/compressed/efi_thunk_64.S
arch/x86/boot/compressed/head_32.S
arch/x86/boot/compressed/head_64.S
arch/x86/boot/compressed/misc.h
arch/x86/boot/header.S
arch/x86/boot/setup.ld
arch/x86/boot/tools/build.c
arch/x86/crypto/Makefile
arch/x86/crypto/aesni-intel_glue.c
arch/x86/crypto/crc32-pclmul_glue.c
arch/x86/crypto/crc32c-intel_glue.c
arch/x86/crypto/crct10dif-pclmul_glue.c
arch/x86/crypto/ghash-clmulni-intel_glue.c
arch/x86/entry/Makefile
arch/x86/entry/common.c
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/entry/syscall_32.c
arch/x86/entry/syscall_64.c
arch/x86/entry/syscall_x32.c [new file with mode: 0644]
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/syscalls/syscall_64.tbl
arch/x86/entry/syscalls/syscallhdr.sh
arch/x86/entry/syscalls/syscalltbl.sh
arch/x86/entry/thunk_32.S
arch/x86/entry/thunk_64.S
arch/x86/entry/vdso/vdso32/vclock_gettime.c
arch/x86/entry/vdso/vma.c
arch/x86/events/amd/power.c
arch/x86/events/amd/uncore.c
arch/x86/events/intel/core.c
arch/x86/events/intel/cstate.c
arch/x86/events/intel/lbr.c
arch/x86/events/intel/rapl.c
arch/x86/events/intel/uncore.c
arch/x86/events/intel/uncore.h
arch/x86/events/intel/uncore_snb.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/ia32/Makefile
arch/x86/include/asm/amd_nb.h
arch/x86/include/asm/clocksource.h
arch/x86/include/asm/cpu.h
arch/x86/include/asm/cpu_device_id.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/dwarf2.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/futex.h
arch/x86/include/asm/intel-family.h
arch/x86/include/asm/io_bitmap.h
arch/x86/include/asm/irq.h
arch/x86/include/asm/kprobes.h
arch/x86/include/asm/kvm_emulate.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/mshyperv.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/preempt.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/sections.h
arch/x86/include/asm/sighandling.h
arch/x86/include/asm/syscall.h
arch/x86/include/asm/syscall_wrapper.h
arch/x86/include/asm/syscalls.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/traps.h
arch/x86/include/asm/uaccess.h
arch/x86/include/asm/unistd.h
arch/x86/include/asm/vdso/clocksource.h [new file with mode: 0644]
arch/x86/include/asm/vdso/gettimeofday.h
arch/x86/include/asm/vdso/processor.h [new file with mode: 0644]
arch/x86/include/asm/vdso/vsyscall.h
arch/x86/include/asm/vgtod.h
arch/x86/include/asm/vmx.h
arch/x86/include/asm/vmxfeatures.h
arch/x86/include/uapi/asm/kvm.h
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/acpi/sleep.h
arch/x86/kernel/amd_nb.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/asm-offsets_32.c
arch/x86/kernel/asm-offsets_64.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/match.c
arch/x86/kernel/cpu/mce/core.c
arch/x86/kernel/cpu/mce/dev-mcelog.c
arch/x86/kernel/cpu/mce/intel.c
arch/x86/kernel/cpu/mce/internal.h
arch/x86/kernel/cpu/mce/therm_throt.c
arch/x86/kernel/head_32.S
arch/x86/kernel/ima_arch.c
arch/x86/kernel/irq.c
arch/x86/kernel/kexec-bzimage64.c
arch/x86/kernel/kprobes/opt.c
arch/x86/kernel/kvm.c
arch/x86/kernel/kvmclock.c
arch/x86/kernel/ldt.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/process.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/pvclock.c
arch/x86/kernel/relocate_kernel_64.S
arch/x86/kernel/setup.c
arch/x86/kernel/signal.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/sys_ia32.c [moved from arch/x86/ia32/sys_ia32.c with 78% similarity]
arch/x86/kernel/sys_x86_64.c
arch/x86/kernel/time.c
arch/x86/kernel/topology.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/tsc_msr.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kvm/Kconfig
arch/x86/kvm/Makefile
arch/x86/kvm/emulate.c
arch/x86/kvm/ioapic.c
arch/x86/kvm/irq_comm.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmutrace.h
arch/x86/kvm/svm.c
arch/x86/kvm/trace.h
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/nested.h
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/x86.c
arch/x86/mm/dump_pagetables.c
arch/x86/mm/fault.c
arch/x86/mm/ioremap.c
arch/x86/mm/mmio-mod.c
arch/x86/net/bpf_jit_comp32.c
arch/x86/platform/atom/punit_atom_debug.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_32.c
arch/x86/platform/efi/efi_64.c
arch/x86/platform/efi/efi_stub_32.S
arch/x86/platform/efi/quirks.c
arch/x86/platform/intel-mid/device_libs/platform_bt.c
arch/x86/platform/intel-quark/imr.c
arch/x86/platform/intel-quark/imr_selftest.c
arch/x86/platform/intel/iosf_mbi.c
arch/x86/power/cpu.c
arch/x86/realmode/rm/Makefile
arch/x86/realmode/rm/realmode.lds.S
arch/x86/um/Makefile
arch/x86/um/sys_call_table_32.c
arch/x86/um/sys_call_table_64.c
arch/x86/um/user-offsets.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/smp.c
arch/x86/xen/time.c
arch/xtensa/include/asm/futex.h
arch/xtensa/platforms/iss/simdisk.c
block/Makefile
block/bfq-cgroup.c
block/bfq-iosched.c
block/bfq-iosched.h
block/bio.c
block/blk-cgroup.c
block/blk-core.c
block/blk-flush.c
block/blk-ioc.c
block/blk-iocost.c
block/blk-map.c
block/blk-mq-sched.c
block/blk-mq-tag.c
block/blk-mq-tag.h
block/blk-mq.c
block/blk-mq.h
block/blk-settings.c
block/blk-zoned.c
block/blk.h
block/genhd.c
block/ioctl.c
block/opal_proto.h
block/partitions/Makefile
block/partitions/acorn.c
block/partitions/acorn.h [deleted file]
block/partitions/aix.c
block/partitions/aix.h [deleted file]
block/partitions/amiga.c
block/partitions/amiga.h [deleted file]
block/partitions/atari.h
block/partitions/check.c [deleted file]
block/partitions/check.h
block/partitions/cmdline.c
block/partitions/cmdline.h [deleted file]
block/partitions/core.c [moved from block/partition-generic.c with 72% similarity]
block/partitions/efi.c
block/partitions/efi.h
block/partitions/ibm.c
block/partitions/ibm.h [deleted file]
block/partitions/karma.c
block/partitions/karma.h [deleted file]
block/partitions/ldm.c
block/partitions/ldm.h
block/partitions/mac.h
block/partitions/msdos.c
block/partitions/msdos.h [deleted file]
block/partitions/osf.c
block/partitions/osf.h [deleted file]
block/partitions/sgi.c
block/partitions/sgi.h [deleted file]
block/partitions/sun.c
block/partitions/sun.h [deleted file]
block/partitions/sysv68.c
block/partitions/sysv68.h [deleted file]
block/partitions/ultrix.c
block/partitions/ultrix.h [deleted file]
block/sed-opal.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/ac.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_video.c
drivers/acpi/acpi_watchdog.c
drivers/acpi/acpica/acconvert.h
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/acmacros.h
drivers/acpi/acpica/evevent.c
drivers/acpi/acpica/evxfgpe.c
drivers/acpi/acpica/hwgpe.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/nsnames.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/tbxface.c
drivers/acpi/acpica/utobject.c
drivers/acpi/apei/ghes.c
drivers/acpi/battery.c
drivers/acpi/button.c
drivers/acpi/ec.c
drivers/acpi/fan.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/pci_root.c
drivers/acpi/proc.c
drivers/acpi/sleep.c
drivers/acpi/tiny-power-button.c [new file with mode: 0644]
drivers/acpi/wakeup.c
drivers/acpi/x86/utils.c
drivers/android/binder.c
drivers/android/binder_internal.h
drivers/android/binderfs.c
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-pata-timings.c [new file with mode: 0644]
drivers/ata/libata-sata.c [new file with mode: 0644]
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata-transport.c
drivers/ata/libata.h
drivers/ata/sata_promise.c
drivers/atm/nicstar.c
drivers/auxdisplay/Kconfig
drivers/auxdisplay/charlcd.c
drivers/auxdisplay/img-ascii-lcd.c
drivers/base/arch_topology.c
drivers/base/component.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/dd.c
drivers/base/firmware_loader/Makefile
drivers/base/firmware_loader/fallback.c
drivers/base/firmware_loader/fallback.h
drivers/base/firmware_loader/fallback_platform.c [new file with mode: 0644]
drivers/base/firmware_loader/firmware.h
drivers/base/firmware_loader/main.c
drivers/base/memory.c
drivers/base/platform.c
drivers/base/power/domain.c
drivers/base/power/main.c
drivers/base/power/runtime.c
drivers/base/power/wakeup.c
drivers/base/property.c
drivers/base/swnode.c
drivers/block/Makefile
drivers/block/aoe/aoeblk.c
drivers/block/brd.c
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_worker.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/null_blk.h
drivers/block/null_blk_main.c
drivers/block/null_blk_trace.c [new file with mode: 0644]
drivers/block/null_blk_trace.h [new file with mode: 0644]
drivers/block/null_blk_zoned.c
drivers/block/paride/pcd.c
drivers/block/pktcdvd.c
drivers/block/ps3vram.c
drivers/block/rsxx/dev.c
drivers/block/rsxx/dma.c
drivers/block/umem.c
drivers/block/virtio_blk.c
drivers/block/xen-blkfront.c
drivers/block/zram/zram_drv.c
drivers/bus/sunxi-rsb.c
drivers/bus/ti-sysc.c
drivers/cdrom/gdrom.c
drivers/char/agp/amd64-agp.c
drivers/char/hw_random/via-rng.c
drivers/char/ipmi/ipmi_si_platform.c
drivers/char/tpm/eventlog/common.c
drivers/char/tpm/eventlog/of.c
drivers/char/tpm/eventlog/tpm1.c
drivers/char/tpm/eventlog/tpm2.c
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm2-cmd.c
drivers/char/tpm/tpm_ibmvtpm.c
drivers/char/tpm/tpm_ibmvtpm.h
drivers/char/tpm/tpm_tis_spi_cr50.c
drivers/char/tpm/tpm_tis_spi_main.c
drivers/clk/clk.c
drivers/clk/imx/clk-imx8mp.c
drivers/clk/imx/clk-scu.c
drivers/clk/qcom/dispcc-sc7180.c
drivers/clk/qcom/videocc-sc7180.c
drivers/clk/ti/clk-43xx.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/arm_arch_timer.c
drivers/clocksource/bcm2835_timer.c
drivers/clocksource/bcm_kona_timer.c
drivers/clocksource/dw_apb_timer.c
drivers/clocksource/exynos_mct.c
drivers/clocksource/hyperv_timer.c
drivers/clocksource/ingenic-ost.c [new file with mode: 0644]
drivers/clocksource/ingenic-timer.c
drivers/clocksource/mips-gic-timer.c
drivers/clocksource/mxs_timer.c
drivers/clocksource/nomadik-mtu.c
drivers/clocksource/samsung_pwm_timer.c
drivers/clocksource/timer-atlas7.c
drivers/clocksource/timer-cs5535.c
drivers/clocksource/timer-efm32.c
drivers/clocksource/timer-fsl-ftm.c
drivers/clocksource/timer-fttmr010.c
drivers/clocksource/timer-imx-gpt.c
drivers/clocksource/timer-imx-sysctr.c
drivers/clocksource/timer-imx-tpm.c
drivers/clocksource/timer-integrator-ap.c
drivers/clocksource/timer-meson6.c
drivers/clocksource/timer-microchip-pit64b.c
drivers/clocksource/timer-orion.c
drivers/clocksource/timer-owl.c
drivers/clocksource/timer-prima2.c
drivers/clocksource/timer-pxa.c
drivers/clocksource/timer-sp804.c
drivers/clocksource/timer-ti-dm.c
drivers/clocksource/timer-u300.c
drivers/clocksource/timer-vf-pit.c
drivers/clocksource/timer-vt8500.c
drivers/clocksource/timer-zevio.c
drivers/counter/104-quad-8.c
drivers/counter/stm32-timer-cnt.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/Kconfig.x86
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/amd_freq_sensitivity.c
drivers/cpufreq/cpufreq-dt-platdev.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq-dt.h
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/e_powersaver.c
drivers/cpufreq/elanfreq.c
drivers/cpufreq/imx-cpufreq-dt.c
drivers/cpufreq/imx6q-cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/longhaul.c
drivers/cpufreq/longrun.c
drivers/cpufreq/p4-clockmod.c
drivers/cpufreq/powernow-k6.c
drivers/cpufreq/powernow-k7.c
drivers/cpufreq/powernow-k8.c
drivers/cpufreq/qcom-cpufreq-nvmem.c
drivers/cpufreq/sc520_freq.c
drivers/cpufreq/speedstep-centrino.c
drivers/cpufreq/speedstep-ich.c
drivers/cpufreq/speedstep-smi.c
drivers/cpufreq/ti-cpufreq.c
drivers/cpuidle/cpuidle-haltpoll.c
drivers/cpuidle/cpuidle-psci.c
drivers/cpuidle/cpuidle.c
drivers/cpuidle/governor.c
drivers/crypto/padlock-aes.c
drivers/crypto/padlock-sha.c
drivers/devfreq/devfreq.c
drivers/devfreq/governor.h
drivers/devfreq/governor_simpleondemand.c
drivers/devfreq/governor_userspace.c
drivers/devfreq/tegra30-devfreq.c
drivers/dio/dio-driver.c
drivers/dma-buf/dma-buf.c
drivers/dma/coh901318.c
drivers/dma/dmaengine.c
drivers/dma/idxd/cdev.c
drivers/dma/idxd/sysfs.c
drivers/dma/imx-sdma.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/ti/k3-udma-glue.c
drivers/dma/ti/k3-udma.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/amd64_edac.c
drivers/edac/armada_xp_edac.c
drivers/edac/dmc520_edac.c [new file with mode: 0644]
drivers/edac/edac_mc.c
drivers/edac/edac_mc.h
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_module.h
drivers/edac/ghes_edac.c
drivers/edac/i10nm_base.c
drivers/edac/mce_amd.c
drivers/edac/pnd2_edac.c
drivers/edac/sb_edac.c
drivers/edac/skx_base.c
drivers/edac/synopsys_edac.c
drivers/extcon/extcon-axp288.c
drivers/firmware/arm_sdei.c
drivers/firmware/dmi_scan.c
drivers/firmware/efi/Kconfig
drivers/firmware/efi/Makefile
drivers/firmware/efi/apple-properties.c
drivers/firmware/efi/arm-init.c
drivers/firmware/efi/arm-runtime.c
drivers/firmware/efi/capsule-loader.c
drivers/firmware/efi/dev-path-parser.c
drivers/firmware/efi/efi-bgrt.c
drivers/firmware/efi/efi-pstore.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/efivars.c
drivers/firmware/efi/embedded-firmware.c [new file with mode: 0644]
drivers/firmware/efi/esrt.c
drivers/firmware/efi/fdtparams.c [new file with mode: 0644]
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/arm-stub.c
drivers/firmware/efi/libstub/arm32-stub.c
drivers/firmware/efi/libstub/arm64-stub.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/fdt.c
drivers/firmware/efi/libstub/file.c [new file with mode: 0644]
drivers/firmware/efi/libstub/hidden.h [new file with mode: 0644]
drivers/firmware/efi/libstub/mem.c [new file with mode: 0644]
drivers/firmware/efi/libstub/random.c
drivers/firmware/efi/libstub/randomalloc.c [new file with mode: 0644]
drivers/firmware/efi/libstub/skip_spaces.c [new file with mode: 0644]
drivers/firmware/efi/libstub/string.c
drivers/firmware/efi/libstub/x86-stub.c [moved from arch/x86/boot/compressed/eboot.c with 80% similarity]
drivers/firmware/efi/memattr.c
drivers/firmware/efi/reboot.c
drivers/firmware/efi/runtime-wrappers.c
drivers/firmware/efi/vars.c
drivers/firmware/imx/imx-scu.c
drivers/firmware/imx/misc.c
drivers/firmware/imx/scu-pd.c
drivers/firmware/pcdp.c
drivers/firmware/psci/psci_checker.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/vcn_v1_0.c
drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c
drivers/gpu/drm/amd/include/asic_reg/dce/dce_12_0_offset.h
drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
drivers/gpu/drm/amd/powerplay/navi10_ppt.c
drivers/gpu/drm/amd/powerplay/renoir_ppt.c
drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drivers/gpu/drm/amd/powerplay/smu_v12_0.c
drivers/gpu/drm/arm/display/komeda/komeda_drv.c
drivers/gpu/drm/bochs/bochs_hw.c
drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_gem_shmem_helper.c
drivers/gpu/drm/drm_lease.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/exynos/exynos5433_drm_decon.c
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_drm_dma.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_rotator.c
drivers/gpu/drm/exynos/exynos_drm_scaler.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/display/intel_display_power.c
drivers/gpu/drm/i915/display/intel_dp.c
drivers/gpu/drm/i915/display/intel_psr.c
drivers/gpu/drm/i915/display/intel_psr.h
drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
drivers/gpu/drm/i915/gem/i915_gem_object.c
drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
drivers/gpu/drm/i915/gt/intel_gt_requests.c
drivers/gpu/drm/i915/gt/intel_lrc.c
drivers/gpu/drm/i915/gt/intel_timeline.c
drivers/gpu/drm/i915/gt/intel_workarounds.c
drivers/gpu/drm/i915/gvt/display.c
drivers/gpu/drm/i915/gvt/dmabuf.c
drivers/gpu/drm/i915/gvt/opregion.c
drivers/gpu/drm/i915/gvt/vgpu.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_pci.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_perf_types.h
drivers/gpu/drm/i915/i915_pmu.c
drivers/gpu/drm/i915/i915_pmu.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/i915/i915_request.h
drivers/gpu/drm/i915/i915_utils.h
drivers/gpu/drm/i915/intel_sideband.c
drivers/gpu/drm/mediatek/mtk_drm_crtc.c
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c
drivers/gpu/drm/mediatek/mtk_drm_plane.c
drivers/gpu/drm/panfrost/panfrost_mmu.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/scheduler/sched_main.c
drivers/gpu/drm/sun4i/sun8i_mixer.c
drivers/gpu/drm/sun4i/sun8i_mixer.h
drivers/gpu/drm/sun4i/sun8i_vi_layer.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/virtio/virtgpu_object.c
drivers/hid/hid-alps.c
drivers/hid/hid-apple.c
drivers/hid/hid-bigbenff.c
drivers/hid/hid-core.c
drivers/hid/hid-google-hammer.c
drivers/hid/hid-hyperv.c
drivers/hid/hid-ids.h
drivers/hid/hid-ite.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-picolcd_fb.c
drivers/hid/hid-quirks.c
drivers/hid/hid-sensor-custom.c
drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c
drivers/hid/usbhid/hiddev.c
drivers/hsi/clients/cmt_speech.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/adt7462.c
drivers/hwmon/adt7475.c
drivers/hwmon/axi-fan-control.c [new file with mode: 0644]
drivers/hwmon/coretemp.c
drivers/hwmon/ibmaem.c
drivers/hwmon/ibmpowernv.c
drivers/hwmon/k10temp.c
drivers/hwmon/lm73.c
drivers/hwmon/nct7904.c
drivers/hwmon/pmbus/Kconfig
drivers/hwmon/pmbus/adm1275.c
drivers/hwmon/pmbus/ibm-cffps.c
drivers/hwmon/pmbus/ir35221.c
drivers/hwmon/pmbus/isl68137.c
drivers/hwmon/pmbus/lm25066.c
drivers/hwmon/pmbus/ltc2978.c
drivers/hwmon/pmbus/ltc3815.c
drivers/hwmon/pmbus/max16064.c
drivers/hwmon/pmbus/max20730.c
drivers/hwmon/pmbus/max31785.c
drivers/hwmon/pmbus/max34440.c
drivers/hwmon/pmbus/max8688.c
drivers/hwmon/pmbus/pmbus.c
drivers/hwmon/pmbus/pmbus.h
drivers/hwmon/pmbus/pmbus_core.c
drivers/hwmon/pmbus/tps53679.c
drivers/hwmon/pmbus/ucd9000.c
drivers/hwmon/pmbus/xdpe12284.c
drivers/hwmon/pmbus/zl6100.c
drivers/hwmon/via-cputemp.c
drivers/hwtracing/intel_th/msu.c
drivers/hwtracing/intel_th/pci.c
drivers/hwtracing/stm/p_sys-t.c
drivers/i2c/busses/i2c-altera.c
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-gpio.c
drivers/i2c/busses/i2c-hix5hd2.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-jz4780.c
drivers/i2c/busses/i2c-nvidia-gpu.c
drivers/i2c/busses/i2c-pca-platform.c
drivers/i2c/busses/i2c-st.c
drivers/i2c/i2c-core-acpi.c
drivers/i3c/device.c
drivers/i3c/master.c
drivers/i3c/master/dw-i3c-master.c
drivers/i3c/master/i3c-master-cdns.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/au1xxx-ide.c [deleted file]
drivers/ide/ide-gd.c
drivers/idle/intel_idle.c
drivers/iio/TODO [new file with mode: 0644]
drivers/iio/accel/adis16201.c
drivers/iio/accel/adis16209.c
drivers/iio/accel/adxl372.c
drivers/iio/accel/st_accel_i2c.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/ad7124.c
drivers/iio/adc/ad7192.c [moved from drivers/staging/iio/adc/ad7192.c with 89% similarity]
drivers/iio/adc/ad7292.c
drivers/iio/adc/at91-sama5d2_adc.c
drivers/iio/adc/exynos_adc.c
drivers/iio/adc/max1118.c
drivers/iio/adc/mcp320x.c
drivers/iio/adc/npcm_adc.c
drivers/iio/adc/stm32-dfsdm-adc.c
drivers/iio/adc/ti-tlc4541.c
drivers/iio/amplifiers/Kconfig
drivers/iio/amplifiers/Makefile
drivers/iio/amplifiers/ad8366.c
drivers/iio/amplifiers/hmc425a.c [new file with mode: 0644]
drivers/iio/chemical/Kconfig
drivers/iio/chemical/atlas-sensor.c
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/dac/Kconfig
drivers/iio/dac/Makefile
drivers/iio/dac/ad5755.c
drivers/iio/dac/ad5770r.c [new file with mode: 0644]
drivers/iio/dac/ltc2632.c
drivers/iio/gyro/adis16136.c
drivers/iio/gyro/adis16260.c
drivers/iio/imu/adis.c
drivers/iio/imu/adis16400.c
drivers/iio/imu/adis16460.c
drivers/iio/imu/adis16480.c
drivers/iio/imu/adis_buffer.c
drivers/iio/imu/inv_mpu6050/Kconfig
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c
drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
drivers/iio/industrialio-core.c
drivers/iio/light/Kconfig
drivers/iio/light/Makefile
drivers/iio/light/al3010.c [new file with mode: 0644]
drivers/iio/light/al3320a.c
drivers/iio/light/gp2ap002.c [new file with mode: 0644]
drivers/iio/light/gp2ap020a00f.c
drivers/iio/light/si1133.c
drivers/iio/light/vcnl4000.c
drivers/iio/magnetometer/ak8974.c
drivers/iio/potentiostat/lmp91000.c
drivers/iio/pressure/Kconfig
drivers/iio/pressure/Makefile
drivers/iio/pressure/icp10100.c [new file with mode: 0644]
drivers/iio/proximity/ping.c
drivers/iio/proximity/srf04.c
drivers/iio/trigger/stm32-timer-trigger.c
drivers/infiniband/core/cm.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/core_priv.h
drivers/infiniband/core/device.c
drivers/infiniband/core/iwcm.c
drivers/infiniband/core/nldev.c
drivers/infiniband/core/rw.c
drivers/infiniband/core/security.c
drivers/infiniband/core/umem_odp.c
drivers/infiniband/core/user_mad.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/hfi1/efivar.c
drivers/infiniband/hw/hfi1/user_sdma.c
drivers/infiniband/hw/hfi1/verbs.c
drivers/infiniband/hw/mlx5/cq.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/odp.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/qib/qib_verbs.c
drivers/infiniband/sw/rdmavt/cq.c
drivers/infiniband/sw/siw/siw_main.c
drivers/input/input.c
drivers/input/keyboard/tm2-touchkey.c
drivers/input/mouse/synaptics.c
drivers/input/rmi4/rmi_f11.c
drivers/input/touchscreen/chipone_icn8505.c
drivers/input/touchscreen/raydium_i2c_ts.c
drivers/input/touchscreen/silead.c
drivers/interconnect/core.c
drivers/iommu/amd_iommu.c
drivers/iommu/dma-iommu.c
drivers/iommu/dmar.c
drivers/iommu/intel-iommu-debugfs.c
drivers/iommu/intel-iommu.c
drivers/iommu/io-pgtable-arm.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-atmel-aic.c
drivers/irqchip/irq-atmel-aic5.c
drivers/irqchip/irq-bcm2835.c
drivers/irqchip/irq-bcm7038-l1.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-gic-v4.c
drivers/irqchip/irq-i8259.c
drivers/irqchip/irq-ingenic-tcu.c
drivers/irqchip/irq-ingenic.c
drivers/irqchip/irq-loongson-htpic.c [new file with mode: 0644]
drivers/irqchip/irq-loongson-liointc.c [new file with mode: 0644]
drivers/irqchip/irq-renesas-intc-irqpin.c
drivers/irqchip/irq-sifive-plic.c
drivers/irqchip/irq-stm32-exti.c
drivers/irqchip/irq-versatile-fpga.c
drivers/irqchip/irq-vic.c
drivers/irqchip/irq-xilinx-intc.c
drivers/irqchip/qcom-irq-combiner.c
drivers/lightnvm/core.c
drivers/lightnvm/pblk-sysfs.c
drivers/macintosh/therm_windtunnel.c
drivers/macintosh/windfarm_ad7417_sensor.c
drivers/macintosh/windfarm_fcu_controls.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_lm87_sensor.c
drivers/macintosh/windfarm_max6690_sensor.c
drivers/macintosh/windfarm_smu_sat.c
drivers/md/bcache/alloc.c
drivers/md/bcache/btree.c
drivers/md/bcache/btree.h
drivers/md/bcache/request.c
drivers/md/bcache/request.h
drivers/md/bcache/super.c
drivers/md/bcache/sysfs.c
drivers/md/bcache/writeback.c
drivers/md/bcache/writeback.h
drivers/md/dm-bio-record.h
drivers/md/dm-cache-target.c
drivers/md/dm-integrity.c
drivers/md/dm-mpath.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-verity-target.c
drivers/md/dm-writecache.c
drivers/md/dm-zoned-target.c
drivers/md/dm.c
drivers/md/md.c
drivers/media/Kconfig
drivers/media/cec/cec-notifier.c
drivers/media/common/saa7146/saa7146_fops.c
drivers/media/common/siano/smsdvb-debugfs.c
drivers/media/common/videobuf2/videobuf2-core.c
drivers/media/common/videobuf2/videobuf2-dma-contig.c
drivers/media/dvb-frontends/drx39xyj/drxj.c
drivers/media/dvb-frontends/m88ds3103.c
drivers/media/dvb-frontends/m88ds3103_priv.h
drivers/media/dvb-frontends/tda10071.c
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/adv7180.c
drivers/media/i2c/imx214.c
drivers/media/i2c/imx219.c [new file with mode: 0644]
drivers/media/i2c/ov5675.c
drivers/media/i2c/ov5695.c
drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
drivers/media/i2c/smiapp/smiapp-core.c
drivers/media/i2c/smiapp/smiapp-reg.h
drivers/media/i2c/smiapp/smiapp-regs.c
drivers/media/i2c/smiapp/smiapp.h
drivers/media/i2c/tvp5150.c
drivers/media/i2c/video-i2c.c
drivers/media/mc/mc-entity.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/cobalt/cobalt-v4l2.c
drivers/media/pci/cx18/cx18-streams.c
drivers/media/pci/cx23885/cx23885-417.c
drivers/media/pci/cx23885/cx23885-video.c
drivers/media/pci/cx25821/cx25821-video.c
drivers/media/pci/cx88/cx88-blackbird.c
drivers/media/pci/cx88/cx88-video.c
drivers/media/pci/dt3155/dt3155.c
drivers/media/pci/intel/ipu3/ipu3-cio2.c
drivers/media/pci/ivtv/ivtv-streams.c
drivers/media/pci/meye/meye.c
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134-empress.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/saa7146/hexium_gemini.c
drivers/media/pci/saa7146/hexium_orion.c
drivers/media/pci/saa7146/mxb.c
drivers/media/pci/saa7164/saa7164-encoder.c
drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
drivers/media/pci/solo6x10/solo6x10-v4l2.c
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/pci/ttpci/av7110_v4l.c
drivers/media/pci/ttpci/budget-av.c
drivers/media/pci/tw5864/tw5864-video.c
drivers/media/pci/tw68/tw68-video.c
drivers/media/pci/tw686x/tw686x-video.c
drivers/media/platform/Kconfig
drivers/media/platform/am437x/am437x-vpfe.c
drivers/media/platform/aspeed-video.c
drivers/media/platform/atmel/atmel-isc-base.c
drivers/media/platform/atmel/atmel-isc.h
drivers/media/platform/atmel/atmel-isi.c
drivers/media/platform/coda/coda-common.c
drivers/media/platform/davinci/isif.c
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpfe_capture.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/exynos-gsc/gsc-m2m.c
drivers/media/platform/exynos4-is/Kconfig
drivers/media/platform/exynos4-is/fimc-capture.c
drivers/media/platform/exynos4-is/fimc-isp-video.c
drivers/media/platform/exynos4-is/fimc-lite.c
drivers/media/platform/exynos4-is/fimc-m2m.c
drivers/media/platform/fsl-viu.c
drivers/media/platform/imx-pxp.c
drivers/media/platform/m2m-deinterlace.c
drivers/media/platform/marvell-ccic/mcam-core.c
drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
drivers/media/platform/mtk-mdp/mtk_mdp_comp.c
drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c
drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
drivers/media/platform/mtk-vcodec/venc_vpu_if.c
drivers/media/platform/mtk-vpu/mtk_vpu.c
drivers/media/platform/mtk-vpu/mtk_vpu.h
drivers/media/platform/mx2_emmaprp.c
drivers/media/platform/omap/omap_vout.c
drivers/media/platform/omap3isp/ispccdc.c
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/pxa_camera.c
drivers/media/platform/qcom/camss/camss-video.c
drivers/media/platform/qcom/venus/Makefile
drivers/media/platform/qcom/venus/core.c
drivers/media/platform/qcom/venus/core.h
drivers/media/platform/qcom/venus/firmware.c
drivers/media/platform/qcom/venus/helpers.c
drivers/media/platform/qcom/venus/helpers.h
drivers/media/platform/qcom/venus/hfi_cmds.c
drivers/media/platform/qcom/venus/hfi_helper.h
drivers/media/platform/qcom/venus/hfi_parser.c
drivers/media/platform/qcom/venus/hfi_parser.h
drivers/media/platform/qcom/venus/pm_helpers.c [new file with mode: 0644]
drivers/media/platform/qcom/venus/pm_helpers.h [new file with mode: 0644]
drivers/media/platform/qcom/venus/vdec.c
drivers/media/platform/qcom/venus/venc.c
drivers/media/platform/qcom/venus/venc_ctrls.c
drivers/media/platform/rcar-vin/rcar-dma.c
drivers/media/platform/rcar-vin/rcar-v4l2.c
drivers/media/platform/rcar-vin/rcar-vin.h
drivers/media/platform/rcar_drif.c
drivers/media/platform/rcar_fdp1.c
drivers/media/platform/rcar_jpu.c
drivers/media/platform/renesas-ceu.c
drivers/media/platform/rockchip/rga/rga.c
drivers/media/platform/s3c-camif/camif-capture.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/sh_veu.c
drivers/media/platform/sh_vou.c
drivers/media/platform/sti/bdisp/bdisp-v4l2.c
drivers/media/platform/sti/delta/delta-v4l2.c
drivers/media/platform/sti/hva/hva-v4l2.c
drivers/media/platform/stm32/stm32-cec.c
drivers/media/platform/stm32/stm32-dcmi.c
drivers/media/platform/sunxi/Makefile
drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
drivers/media/platform/sunxi/sun8i-rotate/Makefile [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-rotate/sun8i_formats.c [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c [new file with mode: 0644]
drivers/media/platform/ti-vpe/cal.c
drivers/media/platform/ti-vpe/vpe.c
drivers/media/platform/via-camera.c
drivers/media/platform/vicodec/codec-v4l2-fwht.c
drivers/media/platform/vicodec/vicodec-core.c
drivers/media/platform/vim2m.c
drivers/media/platform/vimc/vimc-capture.c
drivers/media/platform/vimc/vimc-common.c
drivers/media/platform/vimc/vimc-common.h
drivers/media/platform/vimc/vimc-core.c
drivers/media/platform/vimc/vimc-debayer.c
drivers/media/platform/vimc/vimc-scaler.c
drivers/media/platform/vimc/vimc-sensor.c
drivers/media/platform/vimc/vimc-streamer.c
drivers/media/platform/vivid/vivid-core.c
drivers/media/platform/vsp1/vsp1_histo.c
drivers/media/platform/vsp1/vsp1_regs.h
drivers/media/platform/vsp1/vsp1_video.c
drivers/media/platform/xilinx/xilinx-dma.c
drivers/media/radio/si470x/Kconfig
drivers/media/rc/bpf-lirc.c
drivers/media/rc/iguanair.c
drivers/media/rc/ir-xmp-decoder.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-videostrong-kii-pro.c [new file with mode: 0644]
drivers/media/rc/lirc_dev.c
drivers/media/rc/nuvoton-cir.c
drivers/media/rc/rc-main.c
drivers/media/spi/gs1662.c
drivers/media/usb/Kconfig
drivers/media/usb/Makefile
drivers/media/usb/au0828/au0828-video.c
drivers/media/usb/b2c2/flexcop-usb.c
drivers/media/usb/cpia2/cpia2_v4l.c
drivers/media/usb/cx231xx/cx231xx-417.c
drivers/media/usb/cx231xx/cx231xx-dvb.c
drivers/media/usb/cx231xx/cx231xx-video.c
drivers/media/usb/dvb-usb-v2/anysee.c
drivers/media/usb/dvb-usb-v2/lmedm04.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/dvb-usb/cxusb-analog.c
drivers/media/usb/dvb-usb/dib0700_core.c
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/go7007/go7007-usb.c
drivers/media/usb/go7007/go7007-v4l2.c
drivers/media/usb/gspca/gspca.c
drivers/media/usb/gspca/ov519.c
drivers/media/usb/gspca/stv06xx/stv06xx.c
drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c
drivers/media/usb/gspca/xirlink_cit.c
drivers/media/usb/hdpvr/hdpvr-video.c
drivers/media/usb/pulse8-cec/pulse8-cec.c
drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
drivers/media/usb/pwc/pwc-if.c
drivers/media/usb/s2255/s2255drv.c
drivers/media/usb/stk1160/stk1160-v4l.c
drivers/media/usb/stkwebcam/stk-webcam.c
drivers/media/usb/tm6000/tm6000-video.c
drivers/media/usb/usbtv/usbtv-core.c
drivers/media/usb/usbtv/usbtv-video.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/zr364xx/zr364xx.c
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-device.c
drivers/media/v4l2-core/v4l2-fwnode.c
drivers/media/v4l2-core/v4l2-i2c.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-mc.c
drivers/media/v4l2-core/v4l2-mem2mem.c
drivers/misc/altera-stapl/altera.c
drivers/misc/cardreader/rts5227.c
drivers/misc/cardreader/rts5249.c
drivers/misc/cardreader/rts5260.c
drivers/misc/cardreader/rts5261.c
drivers/misc/eeprom/at24.c
drivers/misc/lkdtm/bugs.c
drivers/misc/lkdtm/core.c
drivers/misc/lkdtm/lkdtm.h
drivers/mmc/core/core.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-cadence.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-at91.c
drivers/mmc/host/sdhci-omap.c
drivers/mmc/host/sdhci-pci-gli.c
drivers/mmc/host/sdhci-tegra.c
drivers/most/Kconfig [new file with mode: 0644]
drivers/most/Makefile [new file with mode: 0644]
drivers/most/configfs.c [moved from drivers/staging/most/configfs.c with 99% similarity]
drivers/most/core.c [moved from drivers/staging/most/core.c with 99% similarity]
drivers/mtd/spi-nor/Kconfig
drivers/mtd/spi-nor/Makefile
drivers/mtd/spi-nor/mtk-quadspi.c [deleted file]
drivers/net/Kconfig
drivers/net/bonding/bond_alb.c
drivers/net/caif/caif_spi.c
drivers/net/can/dev.c
drivers/net/can/slcan.c
drivers/net/dsa/bcm_sf2.c
drivers/net/dsa/mt7530.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/mv88e6xxx/global1.c
drivers/net/dsa/mv88e6xxx/global2.c
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/ethernet/amazon/ena/ena_netdev.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_dcb.c
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmgenet.h
drivers/net/ethernet/broadcom/genet/bcmgenet_wol.c
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fman/Kconfig
drivers/net/ethernet/freescale/fman/fman.c
drivers/net/ethernet/freescale/fman/fman.h
drivers/net/ethernet/freescale/fman/fman_memac.c
drivers/net/ethernet/hisilicon/hns3/hclge_mbx.h
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c
drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c
drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c
drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
drivers/net/ethernet/huawei/hinic/hinic_hw_eqs.c
drivers/net/ethernet/huawei/hinic/hinic_hw_if.h
drivers/net/ethernet/huawei/hinic/hinic_hw_mgmt.c
drivers/net/ethernet/huawei/hinic/hinic_hw_qp.h
drivers/net/ethernet/huawei/hinic/hinic_main.c
drivers/net/ethernet/huawei/hinic/hinic_rx.c
drivers/net/ethernet/huawei/hinic/hinic_tx.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/marvell/mvmdio.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/mellanox/mlx4/mcg.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/health.h
drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en/txrx.h
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls.h
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_txrx.c
drivers/net/ethernet/mellanox/mlx5/core/lag.c
drivers/net/ethernet/mellanox/mlx5/core/lag.h
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_action.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_send.c
drivers/net/ethernet/mellanox/mlx5/core/vport.c
drivers/net/ethernet/mellanox/mlxsw/pci.c
drivers/net/ethernet/mellanox/mlxsw/pci_hw.h
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c
drivers/net/ethernet/micrel/ks8851_mll.c
drivers/net/ethernet/mscc/ocelot.c
drivers/net/ethernet/neterion/vxge/vxge-config.h
drivers/net/ethernet/neterion/vxge/vxge-main.h
drivers/net/ethernet/netronome/nfp/nfpcore/nfp6000_pcie.c
drivers/net/ethernet/pensando/ionic/ionic_if.h
drivers/net/ethernet/pensando/ionic/ionic_lif.c
drivers/net/ethernet/pensando/ionic/ionic_regs.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/efx_channels.c
drivers/net/ethernet/sfc/mcdi.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/ptp.c
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/sfc/tx_common.c
drivers/net/ethernet/sfc/tx_common.h
drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/xilinx/ll_temac.h
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/geneve.c
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/ifb.c
drivers/net/ipvlan/ipvlan_core.c
drivers/net/ipvlan/ipvlan_main.c
drivers/net/macsec.c
drivers/net/macvlan.c
drivers/net/netdevsim/ipsec.c
drivers/net/phy/bcm63xx.c
drivers/net/phy/dp83867.c
drivers/net/phy/marvell.c
drivers/net/phy/mdio-bcm-unimac.c
drivers/net/phy/mdio-mux-bcm-iproc.c
drivers/net/phy/mscc.c
drivers/net/phy/phy-c45.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/phy/phylink.c
drivers/net/phy/sfp-bus.c
drivers/net/slip/slhc.c
drivers/net/slip/slip.c
drivers/net/team/team.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/veth.c
drivers/net/vxlan.c
drivers/net/wireguard/device.c
drivers/net/wireguard/netlink.c
drivers/net/wireguard/noise.c
drivers/net/wireguard/noise.h
drivers/net/wireguard/peer.c
drivers/net/wireguard/queueing.h
drivers/net/wireguard/receive.c
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/intel/ipw2x00/ipw2100.c
drivers/net/wireless/intel/iwlwifi/cfg/22000.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.c
drivers/net/wireless/intel/iwlwifi/fw/acpi.h
drivers/net/wireless/intel/iwlwifi/fw/dbg.c
drivers/net/wireless/intel/iwlwifi/fw/dbg.h
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intersil/orinoco/orinoco_usb.c
drivers/net/wireless/mediatek/mt76/dma.c
drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.h
drivers/net/wireless/ti/wlcore/main.c
drivers/nfc/fdp/fdp.c
drivers/nvdimm/blk.c
drivers/nvdimm/btt.c
drivers/nvdimm/pmem.c
drivers/nvme/host/Kconfig
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fc.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/configfs.c
drivers/nvme/target/core.c
drivers/nvme/target/loop.c
drivers/nvme/target/nvmet.h
drivers/nvme/target/rdma.c
drivers/nvme/target/tcp.c
drivers/of/of_mdio.c
drivers/of/property.c
drivers/pci/controller/pcie-brcmstb.c
drivers/pci/pci-mid.c
drivers/pci/pcie/Kconfig
drivers/pci/pcie/aer_inject.c
drivers/pci/switch/switchtec.c
drivers/perf/arm-ccn.c
drivers/perf/arm_pmu_acpi.c
drivers/perf/arm_spe_pmu.c
drivers/perf/fsl_imx8_ddr_perf.c
drivers/phy/allwinner/phy-sun50i-usb3.c
drivers/phy/amlogic/phy-meson-g12a-usb2.c
drivers/phy/broadcom/phy-brcm-sata.c
drivers/phy/cadence/Kconfig
drivers/phy/cadence/Makefile
drivers/phy/cadence/phy-cadence-dp.c [deleted file]
drivers/phy/cadence/phy-cadence-torrent.c [new file with mode: 0644]
drivers/phy/mediatek/phy-mtk-tphy.c
drivers/phy/motorola/phy-mapphone-mdm6600.c
drivers/phy/phy-core.c
drivers/phy/qualcomm/Kconfig
drivers/phy/qualcomm/Makefile
drivers/phy/qualcomm/phy-qcom-qmp.c
drivers/phy/qualcomm/phy-qcom-qmp.h
drivers/phy/qualcomm/phy-qcom-qusb2.c
drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c [new file with mode: 0644]
drivers/phy/qualcomm/phy-qcom-usb-ss.c [new file with mode: 0644]
drivers/phy/rockchip/phy-rockchip-inno-usb2.c
drivers/phy/socionext/phy-uniphier-pcie.c
drivers/phy/socionext/phy-uniphier-usb3hs.c
drivers/phy/socionext/phy-uniphier-usb3ss.c
drivers/phy/tegra/Kconfig
drivers/phy/tegra/Makefile
drivers/phy/tegra/xusb-tegra124.c
drivers/phy/tegra/xusb-tegra186.c
drivers/phy/tegra/xusb-tegra210.c
drivers/phy/tegra/xusb.c
drivers/phy/tegra/xusb.h
drivers/phy/ti/phy-gmii-sel.c
drivers/pinctrl/cirrus/pinctrl-madera-core.c
drivers/pinctrl/core.c
drivers/pinctrl/devicetree.c
drivers/pinctrl/freescale/pinctrl-scu.c
drivers/pinctrl/meson/pinctrl-meson-gxl.c
drivers/pinctrl/pinctrl-falcon.c
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/platform/chrome/wilco_ec/properties.c
drivers/platform/x86/Kconfig
drivers/platform/x86/dell-smo8800.c
drivers/platform/x86/intel-uncore-frequency.c
drivers/platform/x86/intel_int0002_vgpio.c
drivers/platform/x86/intel_mid_powerbtn.c
drivers/platform/x86/intel_pmc_core.c
drivers/platform/x86/intel_pmc_core_pltdrv.c
drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c
drivers/platform/x86/intel_telemetry_debugfs.c
drivers/platform/x86/intel_telemetry_pltdrv.c
drivers/platform/x86/intel_turbo_max_3.c
drivers/platform/x86/touchscreen_dmi.c
drivers/platform/x86/wmi.c
drivers/powercap/idle_inject.c
drivers/powercap/intel_rapl_common.c
drivers/pwm/pwm-omap-dmtimer.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/anatop-regulator.c
drivers/regulator/axp20x-regulator.c
drivers/regulator/core.c
drivers/regulator/da9062-regulator.c
drivers/regulator/da9063-regulator.c
drivers/regulator/mp5416.c [new file with mode: 0644]
drivers/regulator/mp8859.c
drivers/regulator/mp886x.c [new file with mode: 0644]
drivers/regulator/pwm-regulator.c
drivers/regulator/qcom_rpm-regulator.c
drivers/regulator/qcom_smd-regulator.c
drivers/regulator/stm32-vrefbuf.c
drivers/reset/Kconfig
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-efi-platform.c [deleted file]
drivers/s390/block/dasd.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dcssblk.c
drivers/s390/block/xpram.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_core_sys.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/net/qeth_l3_sys.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_sysfs.c
drivers/scsi/BusLogic.c
drivers/scsi/Kconfig
drivers/scsi/aacraid/linit.c
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/isci/init.c
drivers/scsi/libfc/fc_disc.c
drivers/scsi/libsas/Kconfig
drivers/scsi/megaraid.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsicam.c
drivers/scsi/sd.c
drivers/scsi/sd_zbc.c
drivers/scsi/sr.c
drivers/scsi/ufs/ufshcd.c
drivers/slimbus/qcom-ngd-ctrl.c
drivers/soc/fsl/dpio/dpio-driver.c
drivers/soc/imx/soc-imx-scu.c
drivers/soc/samsung/exynos-chipid.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel-quadspi.c
drivers/spi/spi-ar934x.c [new file with mode: 0644]
drivers/spi/spi-bcm63xx-hsspi.c
drivers/spi/spi-efm32.c
drivers/spi/spi-fsi.c [new file with mode: 0644]
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-lpspi.c
drivers/spi/spi-fsl-qspi.c
drivers/spi/spi-geni-qcom.c
drivers/spi/spi-hisi-sfc-v3xx.c
drivers/spi/spi-mem.c
drivers/spi/spi-meson-spicc.c
drivers/spi/spi-mtk-nor.c [new file with mode: 0644]
drivers/spi/spi-mux.c [new file with mode: 0644]
drivers/spi/spi-mxs.c
drivers/spi/spi-nxp-fspi.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-qup.c
drivers/spi/spi-rockchip.c
drivers/spi/spi-rspi.c
drivers/spi/spi-s3c24xx.c
drivers/spi/spi-stm32-qspi.c
drivers/spi/spi-stm32.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/spi/spi.c
drivers/spi/spidev.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/comedi/drivers/dt282x.c
drivers/staging/comedi/drivers/dt3000.c
drivers/staging/comedi/drivers/ni_660x.c
drivers/staging/comedi/drivers/ni_atmio16d.c
drivers/staging/comedi/drivers/ni_labpc_common.c
drivers/staging/comedi/drivers/ni_mio_common.c
drivers/staging/comedi/drivers/ni_pcimio.c
drivers/staging/comedi/drivers/ni_routes.c
drivers/staging/comedi/drivers/ni_routes.h
drivers/staging/comedi/drivers/ni_stc.h
drivers/staging/comedi/drivers/ni_tio.c
drivers/staging/comedi/drivers/rtd520.c
drivers/staging/comedi/drivers/s626.c
drivers/staging/exfat/Kconfig [deleted file]
drivers/staging/exfat/Makefile [deleted file]
drivers/staging/exfat/TODO [deleted file]
drivers/staging/exfat/exfat.h [deleted file]
drivers/staging/exfat/exfat_blkdev.c [deleted file]
drivers/staging/exfat/exfat_cache.c [deleted file]
drivers/staging/exfat/exfat_core.c [deleted file]
drivers/staging/exfat/exfat_nls.c [deleted file]
drivers/staging/exfat/exfat_super.c [deleted file]
drivers/staging/exfat/exfat_upcase.c [deleted file]
drivers/staging/fbtft/fbtft-core.c
drivers/staging/fbtft/fbtft-sysfs.c
drivers/staging/fbtft/fbtft.h
drivers/staging/fsl-dpaa2/ethsw/ethsw.c
drivers/staging/gasket/gasket_core.c
drivers/staging/gdm724x/gdm_lte.c
drivers/staging/gdm724x/gdm_mux.h
drivers/staging/gdm724x/hci_packet.h
drivers/staging/gdm724x/netlink_k.c
drivers/staging/gdm724x/netlink_k.h
drivers/staging/greybus/audio_apbridgea.h
drivers/staging/greybus/gpio.c
drivers/staging/greybus/i2c.c
drivers/staging/greybus/raw.c
drivers/staging/greybus/tools/loopback_test.c
drivers/staging/hp/Kconfig [deleted file]
drivers/staging/hp/Makefile [deleted file]
drivers/staging/hp/hp100.c [deleted file]
drivers/staging/hp/hp100.h [deleted file]
drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192 [deleted file]
drivers/staging/iio/TODO
drivers/staging/iio/accel/adis16203.c
drivers/staging/iio/accel/adis16240.c
drivers/staging/iio/adc/Kconfig
drivers/staging/iio/adc/Makefile
drivers/staging/iio/adc/ad7280a.c
drivers/staging/kpc2000/kpc2000/core.c
drivers/staging/kpc2000/kpc2000_spi.c
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/ks7010/ks7010_sdio.c
drivers/staging/ks7010/ks_hostif.h
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/allegro-dvt/Makefile
drivers/staging/media/allegro-dvt/allegro-core.c
drivers/staging/media/allegro-dvt/allegro-mail.c [new file with mode: 0644]
drivers/staging/media/allegro-dvt/allegro-mail.h [new file with mode: 0644]
drivers/staging/media/hantro/Kconfig
drivers/staging/media/hantro/Makefile
drivers/staging/media/hantro/hantro.h
drivers/staging/media/hantro/hantro_drv.c
drivers/staging/media/hantro/hantro_h1_jpeg_enc.c
drivers/staging/media/hantro/hantro_hw.h
drivers/staging/media/hantro/hantro_jpeg.c
drivers/staging/media/hantro/hantro_jpeg.h
drivers/staging/media/hantro/hantro_postproc.c
drivers/staging/media/hantro/hantro_v4l2.c
drivers/staging/media/hantro/imx8m_vpu_hw.c [new file with mode: 0644]
drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c
drivers/staging/media/imx/imx-media-capture.c
drivers/staging/media/imx/imx-media-csc-scaler.c
drivers/staging/media/imx/imx-media-csi.c
drivers/staging/media/imx/imx-media-utils.c
drivers/staging/media/imx/imx6-mipi-csi2.c
drivers/staging/media/imx/imx7-media-csi.c
drivers/staging/media/imx/imx7-mipi-csis.c
drivers/staging/media/ipu3/TODO
drivers/staging/media/ipu3/ipu3-css.c
drivers/staging/media/ipu3/ipu3-css.h
drivers/staging/media/ipu3/ipu3-mmu.c
drivers/staging/media/ipu3/ipu3-v4l2.c
drivers/staging/media/ipu3/ipu3.c
drivers/staging/media/meson/vdec/Makefile
drivers/staging/media/meson/vdec/codec_h264.c [new file with mode: 0644]
drivers/staging/media/meson/vdec/codec_h264.h [new file with mode: 0644]
drivers/staging/media/meson/vdec/codec_hevc_common.c [new file with mode: 0644]
drivers/staging/media/meson/vdec/codec_hevc_common.h [new file with mode: 0644]
drivers/staging/media/meson/vdec/codec_vp9.c [new file with mode: 0644]
drivers/staging/media/meson/vdec/codec_vp9.h [new file with mode: 0644]
drivers/staging/media/meson/vdec/esparser.c
drivers/staging/media/meson/vdec/hevc_regs.h [new file with mode: 0644]
drivers/staging/media/meson/vdec/vdec.c
drivers/staging/media/meson/vdec/vdec.h
drivers/staging/media/meson/vdec/vdec_helpers.c
drivers/staging/media/meson/vdec/vdec_helpers.h
drivers/staging/media/meson/vdec/vdec_hevc.c [new file with mode: 0644]
drivers/staging/media/meson/vdec/vdec_hevc.h [new file with mode: 0644]
drivers/staging/media/meson/vdec/vdec_platform.c
drivers/staging/media/omap4iss/iss_video.c
drivers/staging/media/rkisp1/TODO
drivers/staging/media/rkisp1/rkisp1-capture.c
drivers/staging/media/rkisp1/rkisp1-common.h
drivers/staging/media/rkisp1/rkisp1-dev.c
drivers/staging/media/rkisp1/rkisp1-isp.c
drivers/staging/media/rkisp1/rkisp1-params.c
drivers/staging/media/rkisp1/rkisp1-resizer.c
drivers/staging/media/rkisp1/rkisp1-stats.c
drivers/staging/media/soc_camera/soc_camera.c
drivers/staging/media/sunxi/cedrus/cedrus.c
drivers/staging/media/sunxi/cedrus/cedrus_h264.c
drivers/staging/media/tegra-vde/vde.c
drivers/staging/media/usbvision/Kconfig [moved from drivers/media/usb/usbvision/Kconfig with 51% similarity]
drivers/staging/media/usbvision/Makefile [moved from drivers/media/usb/usbvision/Makefile with 100% similarity]
drivers/staging/media/usbvision/TODO [new file with mode: 0644]
drivers/staging/media/usbvision/usbvision-cards.c [moved from drivers/media/usb/usbvision/usbvision-cards.c with 100% similarity]
drivers/staging/media/usbvision/usbvision-cards.h [moved from drivers/media/usb/usbvision/usbvision-cards.h with 100% similarity]
drivers/staging/media/usbvision/usbvision-core.c [moved from drivers/media/usb/usbvision/usbvision-core.c with 100% similarity]
drivers/staging/media/usbvision/usbvision-i2c.c [moved from drivers/media/usb/usbvision/usbvision-i2c.c with 100% similarity]
drivers/staging/media/usbvision/usbvision-video.c [moved from drivers/media/usb/usbvision/usbvision-video.c with 99% similarity]
drivers/staging/media/usbvision/usbvision.h [moved from drivers/media/usb/usbvision/usbvision.h with 100% similarity]
drivers/staging/most/Kconfig
drivers/staging/most/Makefile
drivers/staging/most/cdev/cdev.c
drivers/staging/most/dim2/dim2.c
drivers/staging/most/i2c/i2c.c
drivers/staging/most/net/net.c
drivers/staging/most/sound/sound.c
drivers/staging/most/usb/usb.c
drivers/staging/most/video/video.c
drivers/staging/mt7621-dma/mtk-hsdma.c
drivers/staging/mt7621-dts/gbpc1.dts
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/platform_net.h
drivers/staging/netlogic/xlr_net.h
drivers/staging/octeon-usb/Kconfig [new file with mode: 0644]
drivers/staging/octeon-usb/Makefile [new file with mode: 0644]
drivers/staging/octeon-usb/TODO [new file with mode: 0644]
drivers/staging/octeon-usb/octeon-hcd.c [new file with mode: 0644]
drivers/staging/octeon-usb/octeon-hcd.h [new file with mode: 0644]
drivers/staging/octeon/Kconfig [new file with mode: 0644]
drivers/staging/octeon/Makefile [new file with mode: 0644]
drivers/staging/octeon/TODO [new file with mode: 0644]
drivers/staging/octeon/ethernet-defines.h [new file with mode: 0644]
drivers/staging/octeon/ethernet-mdio.c [new file with mode: 0644]
drivers/staging/octeon/ethernet-mdio.h [new file with mode: 0644]
drivers/staging/octeon/ethernet-mem.c [new file with mode: 0644]
drivers/staging/octeon/ethernet-mem.h [new file with mode: 0644]
drivers/staging/octeon/ethernet-rgmii.c [new file with mode: 0644]
drivers/staging/octeon/ethernet-rx.c [new file with mode: 0644]
drivers/staging/octeon/ethernet-rx.h [new file with mode: 0644]
drivers/staging/octeon/ethernet-sgmii.c [new file with mode: 0644]
drivers/staging/octeon/ethernet-spi.c [new file with mode: 0644]
drivers/staging/octeon/ethernet-tx.c [new file with mode: 0644]
drivers/staging/octeon/ethernet-tx.h [new file with mode: 0644]
drivers/staging/octeon/ethernet-util.h [new file with mode: 0644]
drivers/staging/octeon/ethernet.c [new file with mode: 0644]
drivers/staging/octeon/octeon-ethernet.h [new file with mode: 0644]
drivers/staging/octeon/octeon-stubs.h [new file with mode: 0644]
drivers/staging/pi433/Documentation/devicetree/pi433-overlay.dts
drivers/staging/pi433/pi433_if.h
drivers/staging/pi433/rf69.h
drivers/staging/pi433/rf69_enum.h
drivers/staging/pi433/rf69_registers.h
drivers/staging/qlge/qlge.h
drivers/staging/qlge/qlge_dbg.c
drivers/staging/qlge/qlge_ethtool.c
drivers/staging/qlge/qlge_main.c
drivers/staging/qlge/qlge_mpi.c
drivers/staging/rtl8188eu/core/rtw_cmd.c
drivers/staging/rtl8188eu/core/rtw_debug.c
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/hal/hal_com.c
drivers/staging/rtl8188eu/hal/odm.c
drivers/staging/rtl8188eu/hal/odm_hwconfig.c
drivers/staging/rtl8188eu/hal/phy.c
drivers/staging/rtl8188eu/hal/pwrseqcmd.c
drivers/staging/rtl8188eu/hal/rf.c
drivers/staging/rtl8188eu/hal/rf_cfg.c
drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
drivers/staging/rtl8188eu/hal/rtl8188e_rxdesc.c
drivers/staging/rtl8188eu/hal/rtl8188eu_xmit.c
drivers/staging/rtl8188eu/include/rtw_xmit.h
drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
drivers/staging/rtl8188eu/os_dep/osdep_service.c
drivers/staging/rtl8188eu/os_dep/usb_intf.c
drivers/staging/rtl8192e/rtl8192e/r8192E_dev.c
drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
drivers/staging/rtl8192e/rtl8192e/rtl_core.c
drivers/staging/rtl8192e/rtl819x_BAProc.c
drivers/staging/rtl8192e/rtl819x_HTProc.c
drivers/staging/rtl8192e/rtl819x_TSProc.c
drivers/staging/rtl8192e/rtllib.h
drivers/staging/rtl8192e/rtllib_rx.c
drivers/staging/rtl8192e/rtllib_tx.c
drivers/staging/rtl8192e/rtllib_wx.c
drivers/staging/rtl8192u/ieee80211/ieee80211.h
drivers/staging/rtl8192u/ieee80211/ieee80211_crypt_tkip.c
drivers/staging/rtl8192u/ieee80211/ieee80211_module.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_wx.c
drivers/staging/rtl8192u/r819xU_phy.c
drivers/staging/rtl8712/Kconfig
drivers/staging/rtl8712/ieee80211.h
drivers/staging/rtl8712/rtl871x_cmd.h
drivers/staging/rtl8712/rtl871x_mp.c
drivers/staging/rtl8712/rtl871x_mp_ioctl.h
drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
drivers/staging/rtl8712/rtl871x_recv.h
drivers/staging/rtl8723bs/core/rtw_ap.c
drivers/staging/rtl8723bs/core/rtw_cmd.c
drivers/staging/rtl8723bs/core/rtw_efuse.c
drivers/staging/rtl8723bs/core/rtw_ieee80211.c
drivers/staging/rtl8723bs/core/rtw_io.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_security.c
drivers/staging/rtl8723bs/core/rtw_wlan_util.c
drivers/staging/rtl8723bs/core/rtw_xmit.c
drivers/staging/rtl8723bs/hal/Hal8723BReg.h
drivers/staging/rtl8723bs/hal/HalBtc8723b1Ant.c
drivers/staging/rtl8723bs/hal/HalBtc8723b2Ant.c
drivers/staging/rtl8723bs/hal/HalBtcOutSrc.h
drivers/staging/rtl8723bs/hal/HalPhyRf.c
drivers/staging/rtl8723bs/hal/HalPwrSeqCmd.c
drivers/staging/rtl8723bs/hal/hal_com.c
drivers/staging/rtl8723bs/hal/hal_com_phycfg.c
drivers/staging/rtl8723bs/hal/hal_intf.c
drivers/staging/rtl8723bs/hal/odm.h
drivers/staging/rtl8723bs/hal/odm_CfoTracking.c
drivers/staging/rtl8723bs/hal/odm_HWConfig.c
drivers/staging/rtl8723bs/hal/odm_debug.h
drivers/staging/rtl8723bs/hal/odm_types.h
drivers/staging/rtl8723bs/hal/rtl8723b_cmd.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/include/HalVerDef.h
drivers/staging/rtl8723bs/include/cmd_osdep.h
drivers/staging/rtl8723bs/include/drv_types.h
drivers/staging/rtl8723bs/include/hal_com.h
drivers/staging/rtl8723bs/include/hal_com_h2c.h
drivers/staging/rtl8723bs/include/hal_com_phycfg.h
drivers/staging/rtl8723bs/include/hal_com_reg.h
drivers/staging/rtl8723bs/include/hal_intf.h
drivers/staging/rtl8723bs/include/hal_phy.h
drivers/staging/rtl8723bs/include/hal_phy_cfg.h
drivers/staging/rtl8723bs/include/hal_pwr_seq.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/osdep_service_linux.h
drivers/staging/rtl8723bs/include/recv_osdep.h
drivers/staging/rtl8723bs/include/rtl8723b_cmd.h
drivers/staging/rtl8723bs/include/rtl8723b_rf.h
drivers/staging/rtl8723bs/include/rtl8723b_xmit.h
drivers/staging/rtl8723bs/include/rtw_byteorder.h
drivers/staging/rtl8723bs/include/rtw_cmd.h
drivers/staging/rtl8723bs/include/rtw_debug.h
drivers/staging/rtl8723bs/include/rtw_eeprom.h
drivers/staging/rtl8723bs/include/rtw_efuse.h
drivers/staging/rtl8723bs/include/rtw_event.h
drivers/staging/rtl8723bs/include/rtw_ht.h
drivers/staging/rtl8723bs/include/rtw_io.h
drivers/staging/rtl8723bs/include/rtw_mlme.h
drivers/staging/rtl8723bs/include/rtw_mlme_ext.h
drivers/staging/rtl8723bs/include/rtw_mp.h
drivers/staging/rtl8723bs/include/rtw_recv.h
drivers/staging/rtl8723bs/include/rtw_security.h
drivers/staging/rtl8723bs/include/rtw_xmit.h
drivers/staging/rtl8723bs/include/sta_info.h
drivers/staging/rtl8723bs/include/wifi.h
drivers/staging/rtl8723bs/include/xmit_osdep.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/sdio_intf.c
drivers/staging/rtl8723bs/os_dep/xmit_linux.c
drivers/staging/rts5208/rtsx_chip.c
drivers/staging/sm750fb/Makefile
drivers/staging/speakup/keyhelp.c
drivers/staging/speakup/main.c
drivers/staging/speakup/selection.c
drivers/staging/speakup/speakup_soft.c
drivers/staging/speakup/spk_priv.h
drivers/staging/speakup/spk_ttyio.c
drivers/staging/speakup/spk_types.h
drivers/staging/unisys/Documentation/overview.txt
drivers/staging/unisys/visorinput/visorinput.c
drivers/staging/uwb/Kconfig [deleted file]
drivers/staging/uwb/Makefile [deleted file]
drivers/staging/uwb/TODO [deleted file]
drivers/staging/uwb/address.c [deleted file]
drivers/staging/uwb/allocator.c [deleted file]
drivers/staging/uwb/beacon.c [deleted file]
drivers/staging/uwb/driver.c [deleted file]
drivers/staging/uwb/drp-avail.c [deleted file]
drivers/staging/uwb/drp-ie.c [deleted file]
drivers/staging/uwb/drp.c [deleted file]
drivers/staging/uwb/est.c [deleted file]
drivers/staging/uwb/hwa-rc.c [deleted file]
drivers/staging/uwb/i1480/Makefile [deleted file]
drivers/staging/uwb/i1480/dfu/Makefile [deleted file]
drivers/staging/uwb/i1480/dfu/dfu.c [deleted file]
drivers/staging/uwb/i1480/dfu/i1480-dfu.h [deleted file]
drivers/staging/uwb/i1480/dfu/mac.c [deleted file]
drivers/staging/uwb/i1480/dfu/phy.c [deleted file]
drivers/staging/uwb/i1480/dfu/usb.c [deleted file]
drivers/staging/uwb/i1480/i1480-est.c [deleted file]
drivers/staging/uwb/ie-rcv.c [deleted file]
drivers/staging/uwb/ie.c [deleted file]
drivers/staging/uwb/include/debug-cmd.h [deleted file]
drivers/staging/uwb/include/spec.h [deleted file]
drivers/staging/uwb/include/umc.h [deleted file]
drivers/staging/uwb/include/whci.h [deleted file]
drivers/staging/uwb/lc-dev.c [deleted file]
drivers/staging/uwb/lc-rc.c [deleted file]
drivers/staging/uwb/neh.c [deleted file]
drivers/staging/uwb/pal.c [deleted file]
drivers/staging/uwb/radio.c [deleted file]
drivers/staging/uwb/reset.c [deleted file]
drivers/staging/uwb/rsv.c [deleted file]
drivers/staging/uwb/scan.c [deleted file]
drivers/staging/uwb/umc-bus.c [deleted file]
drivers/staging/uwb/umc-dev.c [deleted file]
drivers/staging/uwb/umc-drv.c [deleted file]
drivers/staging/uwb/uwb-debug.c [deleted file]
drivers/staging/uwb/uwb-internal.h [deleted file]
drivers/staging/uwb/uwb.h [deleted file]
drivers/staging/uwb/uwbd.c [deleted file]
drivers/staging/uwb/whc-rc.c [deleted file]
drivers/staging/uwb/whci.c [deleted file]
drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
drivers/staging/vc04_services/bcm2835-camera/controls.c
drivers/staging/vc04_services/interface/vchi/vchi_common.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_core.c
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h
drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h
drivers/staging/vt6655/card.h
drivers/staging/vt6655/device_main.c
drivers/staging/vt6655/power.c
drivers/staging/vt6656/Makefile
drivers/staging/vt6656/baseband.c
drivers/staging/vt6656/card.c
drivers/staging/vt6656/desc.h
drivers/staging/vt6656/device.h
drivers/staging/vt6656/dpc.c [deleted file]
drivers/staging/vt6656/dpc.h [deleted file]
drivers/staging/vt6656/int.c [deleted file]
drivers/staging/vt6656/int.h [deleted file]
drivers/staging/vt6656/key.c
drivers/staging/vt6656/mac.h
drivers/staging/vt6656/main_usb.c
drivers/staging/vt6656/rxtx.c
drivers/staging/vt6656/rxtx.h
drivers/staging/vt6656/usbpipe.c
drivers/staging/vt6656/usbpipe.h
drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt
drivers/staging/wfx/bh.c
drivers/staging/wfx/bus_sdio.c
drivers/staging/wfx/bus_spi.c
drivers/staging/wfx/data_rx.c
drivers/staging/wfx/data_tx.c
drivers/staging/wfx/data_tx.h
drivers/staging/wfx/hif_api_cmd.h
drivers/staging/wfx/hif_tx.c
drivers/staging/wfx/hif_tx.h
drivers/staging/wfx/hif_tx_mib.h
drivers/staging/wfx/hwio.c
drivers/staging/wfx/main.c
drivers/staging/wfx/main.h
drivers/staging/wfx/queue.c
drivers/staging/wfx/sta.c
drivers/staging/wilc1000/Kconfig
drivers/staging/wilc1000/cfg80211.c
drivers/staging/wilc1000/hif.c
drivers/staging/wilc1000/microchip,wilc1000,sdio.txt [deleted file]
drivers/staging/wilc1000/microchip,wilc1000,spi.txt [deleted file]
drivers/staging/wilc1000/microchip,wilc1000.yaml [new file with mode: 0644]
drivers/staging/wilc1000/mon.c
drivers/staging/wilc1000/netdev.c
drivers/staging/wilc1000/netdev.h
drivers/staging/wilc1000/sdio.c
drivers/staging/wilc1000/spi.c
drivers/staging/wilc1000/wlan.c
drivers/staging/wilc1000/wlan.h
drivers/staging/wlan-ng/hfa384x.h
drivers/staging/wlan-ng/hfa384x_usb.c
drivers/staging/wlan-ng/p80211types.h
drivers/staging/wlan-ng/prism2usb.c
drivers/staging/wusbcore/Documentation/wusb-cbaf [deleted file]
drivers/staging/wusbcore/Documentation/wusb-design-overview.rst [deleted file]
drivers/staging/wusbcore/Kconfig [deleted file]
drivers/staging/wusbcore/Makefile [deleted file]
drivers/staging/wusbcore/TODO [deleted file]
drivers/staging/wusbcore/cbaf.c [deleted file]
drivers/staging/wusbcore/crypto.c [deleted file]
drivers/staging/wusbcore/dev-sysfs.c [deleted file]
drivers/staging/wusbcore/devconnect.c [deleted file]
drivers/staging/wusbcore/host/Kconfig [deleted file]
drivers/staging/wusbcore/host/Makefile [deleted file]
drivers/staging/wusbcore/host/hwa-hc.c [deleted file]
drivers/staging/wusbcore/host/whci/Makefile [deleted file]
drivers/staging/wusbcore/host/whci/asl.c [deleted file]
drivers/staging/wusbcore/host/whci/debug.c [deleted file]
drivers/staging/wusbcore/host/whci/hcd.c [deleted file]
drivers/staging/wusbcore/host/whci/hw.c [deleted file]
drivers/staging/wusbcore/host/whci/init.c [deleted file]
drivers/staging/wusbcore/host/whci/int.c [deleted file]
drivers/staging/wusbcore/host/whci/pzl.c [deleted file]
drivers/staging/wusbcore/host/whci/qset.c [deleted file]
drivers/staging/wusbcore/host/whci/whcd.h [deleted file]
drivers/staging/wusbcore/host/whci/whci-hc.h [deleted file]
drivers/staging/wusbcore/host/whci/wusb.c [deleted file]
drivers/staging/wusbcore/include/association.h [deleted file]
drivers/staging/wusbcore/include/wusb-wa.h [deleted file]
drivers/staging/wusbcore/include/wusb.h [deleted file]
drivers/staging/wusbcore/mmc.c [deleted file]
drivers/staging/wusbcore/pal.c [deleted file]
drivers/staging/wusbcore/reservation.c [deleted file]
drivers/staging/wusbcore/rh.c [deleted file]
drivers/staging/wusbcore/security.c [deleted file]
drivers/staging/wusbcore/wa-hc.c [deleted file]
drivers/staging/wusbcore/wa-hc.h [deleted file]
drivers/staging/wusbcore/wa-nep.c [deleted file]
drivers/staging/wusbcore/wa-rpipe.c [deleted file]
drivers/staging/wusbcore/wa-xfer.c [deleted file]
drivers/staging/wusbcore/wusbhc.c [deleted file]
drivers/staging/wusbcore/wusbhc.h [deleted file]
drivers/tee/amdtee/Kconfig
drivers/tee/amdtee/core.c
drivers/thermal/cpufreq_cooling.c
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
drivers/thermal/intel/intel_powerclamp.c
drivers/thermal/intel/intel_quark_dts_thermal.c
drivers/thermal/intel/intel_soc_dts_thermal.c
drivers/thermal/intel/x86_pkg_temp_thermal.c
drivers/thunderbolt/domain.c
drivers/thunderbolt/eeprom.c
drivers/thunderbolt/icm.c
drivers/thunderbolt/switch.c
drivers/thunderbolt/usb4.c
drivers/tty/serdev/core.c
drivers/tty/serial/8250/8250_exar.c
drivers/tty/serial/8250/8250_omap.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/mvebu-uart.c
drivers/tty/serial/omap-serial.c
drivers/tty/tty_io.c
drivers/tty/vt/selection.c
drivers/tty/vt/vt.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/atm/usbatm.h
drivers/usb/c67x00/c67x00-hcd.h
drivers/usb/c67x00/c67x00.h
drivers/usb/cdns3/cdns3-pci-wrap.c
drivers/usb/cdns3/cdns3-ti.c
drivers/usb/cdns3/core.c
drivers/usb/cdns3/gadget.c
drivers/usb/cdns3/gadget.h
drivers/usb/chipidea/bits.h
drivers/usb/chipidea/ci.h
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/ci_hdrc_imx.h
drivers/usb/chipidea/core.c
drivers/usb/chipidea/otg.c
drivers/usb/chipidea/otg.h
drivers/usb/chipidea/otg_fsm.h
drivers/usb/chipidea/udc.c
drivers/usb/chipidea/udc.h
drivers/usb/class/cdc-acm.c
drivers/usb/core/driver.c
drivers/usb/core/generic.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/port.c
drivers/usb/core/quirks.c
drivers/usb/core/sysfs.c
drivers/usb/core/usb-acpi.c
drivers/usb/core/usb.h
drivers/usb/dwc2/core.h
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/hcd.h
drivers/usb/dwc2/hw.h
drivers/usb/dwc2/params.c
drivers/usb/dwc2/platform.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/drd.c
drivers/usb/dwc3/dwc3-exynos.c
drivers/usb/dwc3/dwc3-meson-g12a.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/host.c
drivers/usb/dwc3/trace.h
drivers/usb/gadget/composite.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_phonet.c
drivers/usb/gadget/function/f_uac1_legacy.c
drivers/usb/gadget/function/f_uvc.c
drivers/usb/gadget/legacy/Kconfig
drivers/usb/gadget/legacy/Makefile
drivers/usb/gadget/legacy/gmidi.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/legacy/raw_gadget.c [new file with mode: 0644]
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/Makefile
drivers/usb/gadget/udc/amd5536udc.h
drivers/usb/gadget/udc/amd5536udc_pci.c
drivers/usb/gadget/udc/aspeed-vhub/Kconfig
drivers/usb/gadget/udc/aspeed-vhub/core.c
drivers/usb/gadget/udc/aspeed-vhub/dev.c
drivers/usb/gadget/udc/aspeed-vhub/epn.c
drivers/usb/gadget/udc/aspeed-vhub/hub.c
drivers/usb/gadget/udc/aspeed-vhub/vhub.h
drivers/usb/gadget/udc/at91_udc.c
drivers/usb/gadget/udc/dummy_hcd.c
drivers/usb/gadget/udc/fotg210-udc.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/fusb300_udc.c
drivers/usb/gadget/udc/goku_udc.c
drivers/usb/gadget/udc/lpc32xx_udc.c
drivers/usb/gadget/udc/m66592-udc.c
drivers/usb/gadget/udc/max3420_udc.c [new file with mode: 0644]
drivers/usb/gadget/udc/net2280.c
drivers/usb/gadget/udc/omap_udc.c
drivers/usb/gadget/udc/r8a66597-udc.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/gadget/udc/s3c-hsudc.c
drivers/usb/gadget/udc/tegra-xudc.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci.h
drivers/usb/host/fhci-hcd.c
drivers/usb/host/fotg210.h
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci.h
drivers/usb/host/sl811-hcd.c
drivers/usb/host/uhci-pci.c
drivers/usb/host/xhci-histb.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-mtk.h
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci-tegra.c
drivers/usb/host/xhci-trace.h
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/apple-mfi-fastcharge.c [new file with mode: 0644]
drivers/usb/misc/usb251xb.c
drivers/usb/mon/mon_text.c
drivers/usb/mtu3/mtu3_dr.c
drivers/usb/musb/Kconfig
drivers/usb/musb/jz4740.c
drivers/usb/musb/mediatek.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/tusb6010.c
drivers/usb/phy/Kconfig
drivers/usb/phy/Makefile
drivers/usb/phy/phy-jz4770.c [new file with mode: 0644]
drivers/usb/phy/phy-tegra-usb.c
drivers/usb/roles/class.c
drivers/usb/roles/intel-xhci-usb-role-switch.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/f81232.c
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_usbvend.h
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/usb/storage/usb.h
drivers/usb/storage/usual-tables.c
drivers/usb/typec/bus.c
drivers/usb/typec/bus.h
drivers/usb/typec/class.c
drivers/usb/typec/mux.c
drivers/usb/typec/mux/Kconfig
drivers/usb/typec/mux/Makefile
drivers/usb/typec/mux/intel_pmc_mux.c [new file with mode: 0644]
drivers/usb/typec/tcpm/tcpm.c
drivers/usb/typec/ucsi/displayport.c
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi.h
drivers/usb/typec/ucsi/ucsi_ccg.c
drivers/vhost/net.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/led_bl.c [new file with mode: 0644]
drivers/video/console/vgacon.c
drivers/video/fbdev/c2p_core.h
drivers/video/fbdev/g364fb.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_ring.c
drivers/watchdog/iTCO_vendor.h
drivers/watchdog/iTCO_vendor_support.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/wdat_wdt.c
drivers/xen/cpu_hotplug.c
drivers/xen/xen-pciback/pciback.h
drivers/xen/xenbus/xenbus_comms.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenbus/xenbus_probe_backend.c
drivers/xen/xenbus/xenbus_xs.c
drivers/zorro/zorro-driver.c
drivers/zorro/zorro.c
drivers/zorro/zorro.h
fs/afs/addr_list.c
fs/afs/cmservice.c
fs/afs/fs_probe.c
fs/afs/internal.h
fs/afs/rxrpc.c
fs/block_dev.c
fs/btrfs/block-group.c
fs/btrfs/inode.c
fs/buffer.c
fs/ceph/file.c
fs/ceph/snap.c
fs/cifs/cifs_dfs_ref.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smb1ops.c
fs/cifs/smb2inode.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/crypto/keysetup.c
fs/debugfs/file.c
fs/debugfs/inode.c
fs/efivarfs/super.c
fs/erofs/decompressor.c
fs/erofs/internal.h
fs/erofs/super.c
fs/erofs/utils.c
fs/erofs/zdata.c
fs/eventpoll.c
fs/exec.c
fs/ext4/page-io.c
fs/ext4/super.c
fs/ext4/sysfs.c
fs/f2fs/f2fs.h
fs/f2fs/super.c
fs/fat/inode.c
fs/fcntl.c
fs/file.c
fs/fuse/dev.c
fs/fuse/fuse_i.h
fs/gfs2/inode.c
fs/inode.c
fs/internal.h
fs/io-wq.c
fs/io-wq.h
fs/io_uring.c
fs/jbd2/transaction.c
fs/libfs.c
fs/locks.c
fs/nfs/Kconfig
fs/nfs/client.c
fs/nfs/dir.c
fs/nfs/fs_context.c
fs/nfs/fscache.c
fs/nfs/namespace.c
fs/nfs/nfs4client.c
fs/ntfs/aops.c
fs/open.c
fs/overlayfs/Kconfig
fs/overlayfs/file.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/pstore/inode.c
fs/pstore/platform.c
fs/pstore/ram.c
fs/pstore/ram_core.c
fs/reiserfs/journal.c
fs/splice.c
fs/zonefs/Kconfig
fs/zonefs/super.c
include/acpi/acpi_bus.h
include/acpi/acpixf.h
include/acpi/actbl1.h
include/acpi/actypes.h
include/acpi/button.h
include/asm-generic/bitops.h
include/asm-generic/futex.h
include/asm-generic/vdso/vsyscall.h
include/clocksource/timer-ti-dm.h
include/crypto/curve25519.h
include/drm/drm_dp_mst_helper.h
include/drm/drm_gem_shmem_helper.h
include/dt-bindings/clock/imx8mn-clock.h
include/dt-bindings/display/sdtv-standards.h [new file with mode: 0644]
include/dt-bindings/media/tvp5150.h
include/kvm/arm_vgic.h
include/linux/arch_topology.h
include/linux/atmel-isc-media.h [new file with mode: 0644]
include/linux/bio.h
include/linux/bits.h
include/linux/blk-mq.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/bootconfig.h
include/linux/bpf.h
include/linux/buffer_head.h
include/linux/ceph/messenger.h
include/linux/ceph/osdmap.h
include/linux/ceph/rados.h
include/linux/cgroup.h
include/linux/clk-provider.h
include/linux/clocksource.h
include/linux/completion.h
include/linux/const.h
include/linux/cpu.h
include/linux/cpufreq.h
include/linux/cpuhotplug.h
include/linux/cpumask.h
include/linux/debugfs.h
include/linux/devfreq.h
include/linux/device.h
include/linux/device/driver.h
include/linux/dio.h
include/linux/dmar.h
include/linux/dsa/8021q.h
include/linux/dw_apb_timer.h
include/linux/edac.h
include/linux/efi.h
include/linux/efi_embedded_fw.h [new file with mode: 0644]
include/linux/elfnote.h
include/linux/file.h
include/linux/firmware.h
include/linux/fs.h
include/linux/futex.h
include/linux/fwnode.h
include/linux/genhd.h
include/linux/hardirq.h
include/linux/hid.h
include/linux/i2c.h
include/linux/icmpv6.h
include/linux/ieee80211.h
include/linux/iio/iio.h
include/linux/iio/imu/adis.h
include/linux/inet_diag.h
include/linux/intel-iommu.h
include/linux/interrupt.h
include/linux/io-mapping.h
include/linux/ioc3.h [deleted file]
include/linux/iocontext.h
include/linux/irq.h
include/linux/irq_work.h
include/linux/irqchip/arm-gic-common.h
include/linux/irqchip/arm-gic-v3.h
include/linux/irqchip/arm-gic-v4.h
include/linux/irqflags.h
include/linux/jiffies.h
include/linux/kernel.h
include/linux/ktime.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/limits.h
include/linux/lockdep.h
include/linux/math64.h
include/linux/memcontrol.h
include/linux/min_heap.h [new file with mode: 0644]
include/linux/mm.h
include/linux/mmc/host.h
include/linux/mod_devicetable.h
include/linux/most.h [moved from drivers/staging/most/most.h with 100% similarity]
include/linux/msdos_partition.h [new file with mode: 0644]
include/linux/mutex.h
include/linux/netfilter/ipset/ip_set.h
include/linux/netlink.h
include/linux/of_clk.h
include/linux/page-flags.h
include/linux/part_stat.h [new file with mode: 0644]
include/linux/pci_ids.h
include/linux/pe.h
include/linux/percpu-rwsem.h
include/linux/perf/arm_pmu.h
include/linux/perf_event.h
include/linux/phy.h
include/linux/phy/tegra/xusb.h
include/linux/platform_data/dmtimer-omap.h
include/linux/platform_data/spi-omap2-mcspi.h
include/linux/platform_device.h
include/linux/pm_qos.h
include/linux/pm_runtime.h
include/linux/pnp.h
include/linux/posix-timers.h
include/linux/preempt.h
include/linux/psi.h
include/linux/psi_types.h
include/linux/raid/detect.h [new file with mode: 0644]
include/linux/rculist.h
include/linux/rcutiny.h
include/linux/rcutree.h
include/linux/rcuwait.h
include/linux/regmap.h
include/linux/regulator/driver.h
include/linux/rhashtable.h
include/linux/rwlock_types.h
include/linux/rwsem.h
include/linux/sched.h
include/linux/sched/topology.h
include/linux/seccomp.h
include/linux/skbuff.h
include/linux/soc/qcom/smd-rpm.h
include/linux/socket.h
include/linux/spi/spi.h
include/linux/spinlock.h
include/linux/spinlock_types.h
include/linux/splice.h
include/linux/stackprotector.h
include/linux/threads.h
include/linux/time.h
include/linux/time32.h
include/linux/time64.h
include/linux/timer.h
include/linux/usb.h
include/linux/usb/audio-v2.h
include/linux/usb/audio-v3.h
include/linux/usb/ehci_def.h
include/linux/usb/gadget.h
include/linux/usb/hcd.h
include/linux/usb/role.h
include/linux/usb/typec.h
include/linux/usb/typec_altmode.h
include/linux/usb/typec_mux.h
include/linux/usb/typec_tbt.h [new file with mode: 0644]
include/linux/usb_usual.h
include/linux/usbdevice_fs.h
include/linux/vmalloc.h
include/linux/wait.h
include/linux/workqueue.h
include/linux/zorro.h
include/media/cec-notifier.h
include/media/h264-ctrls.h
include/media/i2c/smiapp.h [deleted file]
include/media/rc-core.h
include/media/rc-map.h
include/media/v4l2-dev.h
include/media/v4l2-device.h
include/media/v4l2-fwnode.h
include/media/v4l2-mc.h
include/media/v4l2-mem2mem.h
include/media/v4l2-subdev.h
include/media/videobuf2-core.h
include/net/af_rxrpc.h
include/net/compat.h
include/net/fib_rules.h
include/net/sch_generic.h
include/scsi/scsicam.h
include/soc/mscc/ocelot_dev.h
include/sound/soc.h
include/trace/events/afs.h
include/trace/events/io_uring.h
include/trace/events/power.h
include/trace/events/rcu.h
include/trace/events/sched.h
include/uapi/linux/dm-ioctl.h
include/uapi/linux/fdreg.h
include/uapi/linux/in.h
include/uapi/linux/input-event-codes.h
include/uapi/linux/io_uring.h
include/uapi/linux/media-bus-format.h
include/uapi/linux/perf_event.h
include/uapi/linux/seccomp.h
include/uapi/linux/serio.h
include/uapi/linux/usb/raw_gadget.h [new file with mode: 0644]
include/uapi/linux/v4l2-controls.h
include/uapi/linux/videodev2.h
include/vdso/bits.h [new file with mode: 0644]
include/vdso/clocksource.h [new file with mode: 0644]
include/vdso/const.h [new file with mode: 0644]
include/vdso/datapage.h
include/vdso/jiffies.h [new file with mode: 0644]
include/vdso/ktime.h [new file with mode: 0644]
include/vdso/limits.h [new file with mode: 0644]
include/vdso/math64.h [new file with mode: 0644]
include/vdso/processor.h [new file with mode: 0644]
include/vdso/time.h [new file with mode: 0644]
include/vdso/time32.h [new file with mode: 0644]
include/vdso/time64.h [new file with mode: 0644]
include/xen/interface/io/tpmif.h
include/xen/xenbus.h
init/Kconfig
init/do_mounts.c
init/main.c
kernel/audit.c
kernel/auditfilter.c
kernel/bpf/bpf_struct_ops.c
kernel/bpf/btf.c
kernel/bpf/cgroup.c
kernel/bpf/syscall.c
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c
kernel/context_tracking.c
kernel/cpu.c
kernel/events/core.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/irq/Kconfig
kernel/irq/chip.c
kernel/irq/debugfs.c
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/irq/resend.c
kernel/irq_work.c
kernel/kthread.c
kernel/locking/lockdep.c
kernel/locking/lockdep_internals.h
kernel/locking/lockdep_proc.c
kernel/locking/locktorture.c
kernel/locking/mutex-debug.c
kernel/locking/percpu-rwsem.c
kernel/locking/rtmutex.c
kernel/locking/rwsem.c
kernel/locking/rwsem.h
kernel/locking/spinlock_debug.c
kernel/notifier.c
kernel/pid.c
kernel/power/qos.c
kernel/power/snapshot.c
kernel/power/user.c
kernel/rcu/Makefile
kernel/rcu/rcu.h
kernel/rcu/rcu_segcblist.c
kernel/rcu/rcuperf.c
kernel/rcu/rcutorture.c
kernel/rcu/srcutree.c
kernel/rcu/tree.c
kernel/rcu/tree.h
kernel/rcu/tree_exp.h
kernel/rcu/tree_plugin.h
kernel/rcu/tree_stall.h
kernel/rcu/update.c
kernel/sched/completion.c
kernel/sched/core.c
kernel/sched/cpupri.c
kernel/sched/cpupri.h
kernel/sched/cputime.c
kernel/sched/deadline.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/pelt.c
kernel/sched/pelt.h
kernel/sched/psi.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/sched/stats.h
kernel/sched/swait.c
kernel/sched/topology.c
kernel/seccomp.c
kernel/signal.c
kernel/smp.c
kernel/softirq.c
kernel/sys.c
kernel/task_work.c
kernel/time/clocksource.c
kernel/time/hrtimer.c
kernel/time/jiffies.c
kernel/time/namespace.c
kernel/time/posix-cpu-timers.c
kernel/time/posix-timers.c
kernel/time/sched_clock.c
kernel/time/tick-common.c
kernel/time/tick-sched.c
kernel/time/timekeeping.c
kernel/time/timekeeping.h
kernel/time/timer.c
kernel/time/vsyscall.c
kernel/torture.c
kernel/trace/Kconfig
kernel/trace/blktrace.c
kernel/trace/bpf_trace.c
kernel/trace/ftrace.c
kernel/trace/synth_event_gen_test.c
kernel/trace/trace.c
kernel/trace/trace_events_hist.c
kernel/workqueue.c
lib/Kconfig.debug
lib/Makefile
lib/bootconfig.c
lib/cpumask.c
lib/crypto/chacha20poly1305-selftest.c
lib/crypto/chacha20poly1305.c
lib/test_firmware.c
lib/test_min_heap.c [new file with mode: 0644]
lib/vdso/gettimeofday.c
mm/huge_memory.c
mm/hugetlb_cgroup.c
mm/madvise.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/mmu_notifier.c
mm/mprotect.c
mm/mremap.c
mm/nommu.c
mm/shmem.c
mm/slub.c
mm/sparse.c
mm/swapfile.c
mm/vmalloc.c
mm/z3fold.c
net/Kconfig
net/batman-adv/bat_iv_ogm.c
net/bpfilter/main.c
net/bridge/br_device.c
net/caif/caif_dev.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/compat.c
net/core/dev.c
net/core/devlink.c
net/core/netclassid_cgroup.c
net/core/pktgen.c
net/core/sock.c
net/core/sock_map.c
net/dsa/dsa_priv.h
net/dsa/port.c
net/dsa/slave.c
net/dsa/tag_8021q.c
net/dsa/tag_brcm.c
net/dsa/tag_sja1105.c
net/ethtool/bitset.c
net/ethtool/bitset.h
net/ethtool/debug.c
net/ethtool/linkinfo.c
net/ethtool/linkmodes.c
net/ethtool/netlink.c
net/ethtool/wol.c
net/hsr/hsr_framereg.c
net/hsr/hsr_netlink.c
net/hsr/hsr_slave.c
net/ieee802154/nl_policy.c
net/ipv4/Kconfig
net/ipv4/bpf_tcp_ca.c
net/ipv4/cipso_ipv4.c
net/ipv4/fib_frontend.c
net/ipv4/gre_demux.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_diag.c
net/ipv4/ip_gre.c
net/ipv4/ip_vti.c
net/ipv4/ipconfig.c
net/ipv4/raw_diag.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv4/udp_diag.c
net/ipv6/addrconf.c
net/ipv6/ip6_vti.c
net/ipv6/ipv6_sockglue.c
net/ipv6/seg6_iptunnel.c
net/ipv6/seg6_local.c
net/ipv6/xfrm6_tunnel.c
net/mac80211/debugfs_sta.c
net/mac80211/key.c
net/mac80211/mesh_hwmp.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mptcp/options.c
net/mptcp/protocol.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_flow_table_ip.c
net/netfilter/nf_flow_table_offload.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink_cthelper.c
net/netfilter/nft_chain_nat.c
net/netfilter/nft_fwd_netdev.c
net/netfilter/nft_payload.c
net/netfilter/nft_set_pipapo.c
net/netfilter/nft_set_rbtree.c
net/netfilter/nft_tunnel.c
net/netfilter/x_tables.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_recent.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/nfc/hci/core.c
net/nfc/netlink.c
net/openvswitch/datapath.c
net/packet/af_packet.c
net/packet/internal.h
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/call_object.c
net/rxrpc/conn_client.c
net/rxrpc/input.c
net/rxrpc/sendmsg.c
net/sched/act_api.c
net/sched/act_ct.c
net/sched/act_mirred.c
net/sched/cls_route.c
net/sched/cls_tcindex.c
net/sched/sch_cbs.c
net/sched/sch_fq.c
net/sched/sch_taprio.c
net/sctp/diag.c
net/smc/af_smc.c
net/smc/smc_core.c
net/smc/smc_core.h
net/smc/smc_ib.c
net/socket.c
net/tipc/netlink.c
net/unix/af_unix.c
net/vmw_vsock/af_vsock.c
net/vmw_vsock/hyperv_transport.c
net/vmw_vsock/virtio_transport_common.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/scan.c
net/xfrm/xfrm_device.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
samples/v4l/v4l2-pci-skeleton.c
scripts/Kconfig.include
scripts/Makefile.extrawarn
scripts/Makefile.lib
scripts/check-sysctl-docs [new file with mode: 0755]
scripts/documentation-file-ref-check
scripts/dtc/dtc-lexer.l
scripts/export_report.pl
scripts/gcc-plugins/Kconfig
scripts/kallsyms.c
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c
scripts/mod/modpost.c
scripts/parse-maintainers.pl [changed mode: 0644->0755]
scripts/sphinx-pre-install
security/integrity/platform_certs/load_uefi.c
security/keys/key.c
security/keys/keyctl.c
sound/core/oss/pcm_plugin.c
sound/core/pcm_native.c
sound/core/seq/oss/seq_oss_midi.c
sound/core/seq/seq_virmidi.c
sound/mips/sgio2audio.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/Kconfig
sound/soc/codecs/pcm512x.c
sound/soc/codecs/rt1015.c
sound/soc/codecs/tas2562.c
sound/soc/intel/atom/sst/sst.c
sound/soc/intel/atom/sst/sst_loader.c
sound/soc/intel/common/soc-intel-quirks.h
sound/soc/intel/skylake/skl-debug.c
sound/soc/intel/skylake/skl-ssp-clk.c
sound/soc/meson/g12a-tohdmitx.c
sound/soc/soc-component.c
sound/soc/soc-compress.c
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/soc-topology.c
sound/soc/sof/ipc.c
sound/soc/stm/stm32_sai_sub.c
sound/soc/ti/omap-dmic.c
sound/soc/ti/omap-mcbsp.c
sound/soc/ti/omap-mcpdm.c
sound/usb/line6/driver.c
sound/usb/line6/midibuf.c
tools/arch/x86/include/asm/msr-index.h
tools/arch/x86/include/uapi/asm/kvm.h
tools/bootconfig/include/linux/printk.h
tools/bootconfig/main.c
tools/bootconfig/samples/bad-mixed-kv1.bconf [new file with mode: 0644]
tools/bootconfig/samples/bad-mixed-kv2.bconf [new file with mode: 0644]
tools/bootconfig/samples/bad-samekey.bconf [new file with mode: 0644]
tools/bootconfig/test-bootconfig.sh
tools/edid/1024x768.S [moved from Documentation/EDID/1024x768.S with 100% similarity]
tools/edid/1280x1024.S [moved from Documentation/EDID/1280x1024.S with 100% similarity]
tools/edid/1600x1200.S [moved from Documentation/EDID/1600x1200.S with 100% similarity]
tools/edid/1680x1050.S [moved from Documentation/EDID/1680x1050.S with 100% similarity]
tools/edid/1920x1080.S [moved from Documentation/EDID/1920x1080.S with 100% similarity]
tools/edid/800x600.S [moved from Documentation/EDID/800x600.S with 100% similarity]
tools/edid/Makefile [moved from Documentation/EDID/Makefile with 100% similarity]
tools/edid/edid.S [moved from Documentation/EDID/edid.S with 100% similarity]
tools/edid/hex [moved from Documentation/EDID/hex with 100% similarity]
tools/include/linux/irqflags.h
tools/include/uapi/asm/errno.h
tools/include/uapi/linux/in.h
tools/include/uapi/linux/perf_event.h
tools/lib/api/fs/Build
tools/lib/api/fs/cgroup.c [new file with mode: 0644]
tools/lib/api/fs/fs.h
tools/lib/perf/Documentation/examples/counting.c [new file with mode: 0644]
tools/lib/traceevent/event-parse.c
tools/objtool/Build
tools/objtool/builtin-check.c
tools/objtool/builtin.h
tools/objtool/check.c
tools/objtool/check.h
tools/objtool/elf.c
tools/objtool/elf.h
tools/objtool/orc_gen.c
tools/objtool/special.c
tools/objtool/warn.h
tools/perf/Documentation/Makefile
tools/perf/Documentation/intel-pt.txt
tools/perf/Documentation/perf-config.txt
tools/perf/Documentation/perf-inject.txt
tools/perf/Documentation/perf-intel-pt.txt [new file with mode: 0644]
tools/perf/Documentation/perf-record.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-script.txt
tools/perf/Documentation/perf-stat.txt
tools/perf/Makefile
tools/perf/arch/arm/util/cs-etm.c
tools/perf/arch/arm64/util/arm-spe.c
tools/perf/arch/arm64/util/perf_regs.c
tools/perf/arch/powerpc/entry/syscalls/syscall.tbl
tools/perf/arch/powerpc/util/perf_regs.c
tools/perf/arch/x86/util/auxtrace.c
tools/perf/arch/x86/util/event.c
tools/perf/arch/x86/util/header.c
tools/perf/arch/x86/util/intel-bts.c
tools/perf/arch/x86/util/intel-pt.c
tools/perf/arch/x86/util/machine.c
tools/perf/arch/x86/util/perf_regs.c
tools/perf/arch/x86/util/pmu.c
tools/perf/bench/bench.h
tools/perf/bench/epoll-ctl.c
tools/perf/bench/epoll-wait.c
tools/perf/bench/futex-hash.c
tools/perf/bench/futex-lock-pi.c
tools/perf/bench/futex-requeue.c
tools/perf/bench/futex-wake-parallel.c
tools/perf/bench/futex-wake.c
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-probe.c
tools/perf/builtin-report.c
tools/perf/builtin-script.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/include/bpf/pid_filter.h
tools/perf/include/bpf/stdio.h
tools/perf/include/bpf/unistd.h
tools/perf/pmu-events/arch/s390/cf_z15/crypto6.json
tools/perf/pmu-events/arch/s390/cf_z15/extended.json
tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json
tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json
tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json
tools/perf/pmu-events/jevents.c
tools/perf/pmu-events/jevents.h
tools/perf/pmu-events/pmu-events.h
tools/perf/scripts/perl/check-perf-trace.pl
tools/perf/scripts/perl/failed-syscalls.pl
tools/perf/scripts/perl/rw-by-file.pl
tools/perf/scripts/perl/rw-by-pid.pl
tools/perf/scripts/perl/rwtop.pl
tools/perf/scripts/perl/wakeup-latency.pl
tools/perf/tests/bp_account.c
tools/perf/tests/builtin-test.c
tools/perf/tests/expr.c
tools/perf/tests/sample-parsing.c
tools/perf/tests/shell/lib/probe_vfs_getname.sh
tools/perf/ui/browsers/annotate.c
tools/perf/ui/gtk/annotate.c
tools/perf/util/Build
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/auxtrace.c
tools/perf/util/auxtrace.h
tools/perf/util/block-info.c
tools/perf/util/block-info.h
tools/perf/util/branch.h
tools/perf/util/cgroup.c
tools/perf/util/config.c
tools/perf/util/config.h
tools/perf/util/cs-etm.c
tools/perf/util/env.c
tools/perf/util/event.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/expr.c [new file with mode: 0644]
tools/perf/util/expr.h
tools/perf/util/expr.l [new file with mode: 0644]
tools/perf/util/expr.y
tools/perf/util/header.c
tools/perf/util/hist.c
tools/perf/util/intel-pt.c
tools/perf/util/llvm-utils.c
tools/perf/util/machine.c
tools/perf/util/map.c
tools/perf/util/metricgroup.c
tools/perf/util/mmap.c
tools/perf/util/parse-events.c
tools/perf/util/perf_event_attr_fprintf.c
tools/perf/util/probe-file.c
tools/perf/util/probe-finder.c
tools/perf/util/scripting-engines/trace-event-python.c
tools/perf/util/session.c
tools/perf/util/setup.py
tools/perf/util/stat-display.c
tools/perf/util/stat-shadow.c
tools/perf/util/stat.h
tools/perf/util/symbol.c
tools/perf/util/synthetic-events.c
tools/perf/util/util.c
tools/perf/util/util.h
tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
tools/power/x86/turbostat/Makefile
tools/power/x86/turbostat/turbostat.c
tools/scripts/Makefile.include
tools/spi/Makefile
tools/spi/spidev_test.c
tools/testing/ktest/ktest.pl
tools/testing/ktest/sample.conf
tools/testing/kunit/kunit.py
tools/testing/kunit/kunit_kernel.py
tools/testing/selftests/Makefile
tools/testing/selftests/bpf/prog_tests/send_signal_sched_switch.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/test_send_signal_kern.c
tools/testing/selftests/bpf/test_btf.c
tools/testing/selftests/bpf/verifier/jmp32.c
tools/testing/selftests/firmware/Makefile
tools/testing/selftests/firmware/fw_filesystem.sh
tools/testing/selftests/firmware/fw_namespace.c [new file with mode: 0644]
tools/testing/selftests/firmware/fw_run_tests.sh
tools/testing/selftests/ftrace/Makefile
tools/testing/selftests/livepatch/Makefile
tools/testing/selftests/lkdtm/.gitignore [new file with mode: 0644]
tools/testing/selftests/net/Makefile
tools/testing/selftests/net/fib_tests.sh
tools/testing/selftests/net/forwarding/Makefile [new file with mode: 0644]
tools/testing/selftests/net/forwarding/ethtool_lib.sh [changed mode: 0755->0644]
tools/testing/selftests/net/mptcp/Makefile
tools/testing/selftests/net/reuseport_addr_any.c
tools/testing/selftests/netfilter/Makefile
tools/testing/selftests/netfilter/config
tools/testing/selftests/netfilter/nf-queue.c [new file with mode: 0644]
tools/testing/selftests/netfilter/nft_concat_range.sh
tools/testing/selftests/netfilter/nft_queue.sh [new file with mode: 0755]
tools/testing/selftests/pidfd/.gitignore
tools/testing/selftests/rcutorture/bin/functions.sh
tools/testing/selftests/rcutorture/bin/kvm-find-errors.sh
tools/testing/selftests/rcutorture/bin/kvm-recheck.sh
tools/testing/selftests/rcutorture/bin/kvm.sh
tools/testing/selftests/rcutorture/configs/rcu/CFcommon
tools/testing/selftests/rcutorture/configs/rcu/TREE10 [new file with mode: 0644]
tools/testing/selftests/rseq/Makefile
tools/testing/selftests/rtc/Makefile
tools/testing/selftests/seccomp/seccomp_bpf.c
tools/testing/selftests/tc-testing/config
tools/testing/selftests/wireguard/netns.sh
tools/testing/selftests/wireguard/qemu/Makefile
tools/testing/selftests/wireguard/qemu/init.c
tools/testing/selftests/wireguard/qemu/kernel.config
usr/Kconfig
virt/kvm/arm/arm.c
virt/kvm/arm/trace.h
virt/kvm/arm/vgic/vgic-v3.c
virt/kvm/arm/vgic/vgic-v4.c

index 196ca31..6ec5558 100644 (file)
@@ -86,6 +86,8 @@ ForEachMacros:
   - 'bio_for_each_segment_all'
   - 'bio_list_for_each'
   - 'bip_for_each_vec'
+  - 'bitmap_for_each_clear_region'
+  - 'bitmap_for_each_set_region'
   - 'blkg_for_each_descendant_post'
   - 'blkg_for_each_descendant_pre'
   - 'blk_queue_for_each_rl'
@@ -115,6 +117,7 @@ ForEachMacros:
   - 'drm_client_for_each_connector_iter'
   - 'drm_client_for_each_modeset'
   - 'drm_connector_for_each_possible_encoder'
+  - 'drm_for_each_bridge_in_chain'
   - 'drm_for_each_connector_iter'
   - 'drm_for_each_crtc'
   - 'drm_for_each_encoder'
@@ -136,9 +139,10 @@ ForEachMacros:
   - 'for_each_bio'
   - 'for_each_board_func_rsrc'
   - 'for_each_bvec'
+  - 'for_each_card_auxs'
+  - 'for_each_card_auxs_safe'
   - 'for_each_card_components'
-  - 'for_each_card_links'
-  - 'for_each_card_links_safe'
+  - 'for_each_card_pre_auxs'
   - 'for_each_card_prelinks'
   - 'for_each_card_rtds'
   - 'for_each_card_rtds_safe'
@@ -166,6 +170,7 @@ ForEachMacros:
   - 'for_each_dpcm_fe'
   - 'for_each_drhd_unit'
   - 'for_each_dss_dev'
+  - 'for_each_efi_handle'
   - 'for_each_efi_memory_desc'
   - 'for_each_efi_memory_desc_in_map'
   - 'for_each_element'
@@ -190,6 +195,7 @@ ForEachMacros:
   - 'for_each_lru'
   - 'for_each_matching_node'
   - 'for_each_matching_node_and_match'
+  - 'for_each_member'
   - 'for_each_memblock'
   - 'for_each_memblock_type'
   - 'for_each_memcg_cache_index'
@@ -200,9 +206,11 @@ ForEachMacros:
   - 'for_each_msi_entry'
   - 'for_each_msi_entry_safe'
   - 'for_each_net'
+  - 'for_each_net_continue_reverse'
   - 'for_each_netdev'
   - 'for_each_netdev_continue'
   - 'for_each_netdev_continue_rcu'
+  - 'for_each_netdev_continue_reverse'
   - 'for_each_netdev_feature'
   - 'for_each_netdev_in_bond_rcu'
   - 'for_each_netdev_rcu'
@@ -254,10 +262,10 @@ ForEachMacros:
   - 'for_each_reserved_mem_region'
   - 'for_each_rtd_codec_dai'
   - 'for_each_rtd_codec_dai_rollback'
-  - 'for_each_rtdcom'
-  - 'for_each_rtdcom_safe'
+  - 'for_each_rtd_components'
   - 'for_each_set_bit'
   - 'for_each_set_bit_from'
+  - 'for_each_set_clump8'
   - 'for_each_sg'
   - 'for_each_sg_dma_page'
   - 'for_each_sg_page'
@@ -267,6 +275,7 @@ ForEachMacros:
   - 'for_each_subelement_id'
   - '__for_each_thread'
   - 'for_each_thread'
+  - 'for_each_wakeup_source'
   - 'for_each_zone'
   - 'for_each_zone_zonelist'
   - 'for_each_zone_zonelist_nodemask'
@@ -330,6 +339,7 @@ ForEachMacros:
   - 'list_for_each'
   - 'list_for_each_codec'
   - 'list_for_each_codec_safe'
+  - 'list_for_each_continue'
   - 'list_for_each_entry'
   - 'list_for_each_entry_continue'
   - 'list_for_each_entry_continue_rcu'
@@ -351,6 +361,7 @@ ForEachMacros:
   - 'llist_for_each_entry'
   - 'llist_for_each_entry_safe'
   - 'llist_for_each_safe'
+  - 'mci_for_each_dimm'
   - 'media_device_for_each_entity'
   - 'media_device_for_each_intf'
   - 'media_device_for_each_link'
@@ -444,10 +455,16 @@ ForEachMacros:
   - 'virtio_device_for_each_vq'
   - 'xa_for_each'
   - 'xa_for_each_marked'
+  - 'xa_for_each_range'
   - 'xa_for_each_start'
   - 'xas_for_each'
   - 'xas_for_each_conflict'
   - 'xas_for_each_marked'
+  - 'xbc_array_for_each_value'
+  - 'xbc_for_each_key_value'
+  - 'xbc_node_for_each_array_value'
+  - 'xbc_node_for_each_child'
+  - 'xbc_node_for_each_key_value'
   - 'zorro_for_each_dev'
 
 #IncludeBlocks: Preserve # Unknown to clang-format-5.0
index ffb8f28..9198a93 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -225,6 +225,7 @@ Pratyush Anand <pratyush.anand@gmail.com> <pratyush.anand@st.com>
 Praveen BP <praveenbp@ti.com>
 Punit Agrawal <punitagrawal@gmail.com> <punit.agrawal@arm.com>
 Qais Yousef <qsyousef@gmail.com> <qais.yousef@imgtec.com>
+Quentin Monnet <quentin@isovalent.com> <quentin.monnet@netronome.com>
 Quentin Perret <qperret@qperret.net> <quentin.perret@arm.com>
 Rafael J. Wysocki <rjw@rjwysocki.net> <rjw@sisk.pl>
 Rajesh Shah <rajesh.shah@intel.com>
@@ -243,6 +244,7 @@ Santosh Shilimkar <ssantosh@kernel.org>
 Santosh Shilimkar <santosh.shilimkar@oracle.org>
 Sascha Hauer <s.hauer@pengutronix.de>
 S.Çağlar Onur <caglar@pardus.org.tr>
+Sakari Ailus <sakari.ailus@linux.intel.com> <sakari.ailus@iki.fi>
 Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk>
 Sebastian Reichel <sre@kernel.org> <sre@debian.org>
 Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk>
diff --git a/CREDITS b/CREDITS
index a97d328..032b599 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -567,6 +567,11 @@ D: Original author of Amiga FFS filesystem
 S: Orlando, Florida
 S: USA
 
+N: Paul Burton
+E: paulburton@kernel.org
+W: https://pburton.com
+D: MIPS maintainer 2018-2020
+
 N: Lennert Buytenhek
 E: kernel@wantstofly.org
 D: Original (2.4) rewrite of the ethernet bridging code
similarity index 91%
rename from Documentation/ABI/testing/sysfs-kernel-uids
rename to Documentation/ABI/removed/sysfs-kernel-uids
index 4182b70..dc4463f 100644 (file)
@@ -1,5 +1,5 @@
 What:          /sys/kernel/uids/<uid>/cpu_shares
-Date:          December 2007
+Date:          December 2007, finally removed in kernel v2.6.34-rc1
 Contact:       Dhaval Giani <dhaval@linux.vnet.ibm.com>
                Srivatsa Vaddagiri <vatsa@linux.vnet.ibm.com>
 Description:
@@ -194,11 +194,3 @@ Description:
 
                destroy_link    write '1' to this attribute to destroy an
                                active link
-
-What:          /sys/kernel/config/rdma_cm/<hca>/ports/<port-num>/default_roce_tos
-Date:          March 8, 2019
-KernelVersion:  5.2
-Description:   RDMA-CM QPs from HCA <hca> at port <port-num>
-               will be created with this TOS as default.
-               This can be overridden by using the rdma_set_option API.
-               The possible RoCE TOS values are 0-255.
index 46b1f33..eac3218 100644 (file)
@@ -1,3 +1,28 @@
+What:          /sys/bus/counter/devices/counterX/signalY/cable_fault
+KernelVersion: 5.7
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Read-only attribute that indicates whether a differential
+               encoder cable fault (not connected or loose wires) is detected
+               for the respective channel of Signal Y. Valid attribute values
+               are boolean. Detection must first be enabled via the
+               corresponding cable_fault_enable attribute.
+
+What:          /sys/bus/counter/devices/counterX/signalY/cable_fault_enable
+KernelVersion: 5.7
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Whether detection of differential encoder cable faults for the
+               respective channel of Signal Y is enabled. Valid attribute
+               values are boolean.
+
+What:          /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler
+KernelVersion: 5.7
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Filter clock factor for input Signal Y. This prescaler value
+               affects the inputs of both quadrature pair signals.
+
 What:          /sys/bus/counter/devices/counterX/signalY/index_polarity
 KernelVersion: 5.2
 Contact:       linux-iio@vger.kernel.org
index 7627d3b..f831520 100644 (file)
@@ -2,17 +2,22 @@ What:         /sys/bus/iio/devices/iio:deviceX/ac_excitation_en
 KernelVersion:
 Contact:       linux-iio@vger.kernel.org
 Description:
-               Reading gives the state of AC excitation.
-               Writing '1' enables AC excitation.
+               This attribute, if available, is used to enable the AC
+               excitation mode found on some converters. In ac excitation mode,
+               the polarity of the excitation voltage is reversed on
+               alternate cycles, to eliminate DC errors.
 
 What:          /sys/bus/iio/devices/iio:deviceX/bridge_switch_en
 KernelVersion:
 Contact:       linux-iio@vger.kernel.org
 Description:
-               This bridge switch is used to disconnect it when there is a
-               need to minimize the system current consumption.
-               Reading gives the state of the bridge switch.
-               Writing '1' enables the bridge switch.
+               This attribute, if available, is used to close or open the
+               bridge power down switch found on some converters.
+               In bridge applications, such as strain gauges and load cells,
+               the bridge itself consumes the majority of the current in the
+               system. To minimize the current consumption of the system,
+               the bridge can be disconnected (when it is not being used
+               using the bridge_switch_en attribute.
 
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration
 KernelVersion:
@@ -21,6 +26,13 @@ Description:
                Initiates the system calibration procedure. This is done on a
                single channel at a time. Write '1' to start the calibration.
 
+What:          /sys/bus/iio/devices/iio:deviceX/in_voltage2-voltage2_shorted_raw
+KernelVersion:
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Measure voltage from AIN2 pin connected to AIN(+)
+               and AIN(-) shorted.
+
 What:          /sys/bus/iio/devices/iio:deviceX/in_voltagex_sys_calibration_mode_available
 KernelVersion:
 Contact:       linux-iio@vger.kernel.org
@@ -5,7 +5,7 @@ Contact:        Christian Gromm <christian.gromm@microchip.com>
 Description:
                Provides information about the interface type and the physical
                location of the device. Hardware attached via USB, for instance,
-               might return <usb_device 1-1.1:1.0>
+               might return <1-1.1:1.0>
 Users:
 
 What:          /sys/bus/most/devices/.../interface
@@ -278,25 +278,7 @@ Description:
                Indicates whether current channel ran out of buffers.
 Users:
 
-What:          /sys/bus/most/drivers/mostcore/add_link
-Date:          March 2017
-KernelVersion: 4.15
-Contact:       Christian Gromm <christian.gromm@microchip.com>
-Description:
-               This is used to link a channel to a component of the
-               mostcore. A link created by writing to this file is
-               referred to as pipe.
-Users:
-
-What:          /sys/bus/most/drivers/mostcore/remove_link
-Date:          March 2017
-KernelVersion: 4.15
-Contact:       Christian Gromm <christian.gromm@microchip.com>
-Description:
-               This is used to unlink a channel from a component.
-Users:
-
-What:          /sys/bus/most/drivers/mostcore/components
+What:          /sys/bus/most/drivers/most_core/components
 Date:          March 2017
 KernelVersion: 4.15
 Contact:       Christian Gromm <christian.gromm@microchip.com>
@@ -304,7 +286,7 @@ Description:
                This is used to retrieve a list of registered components.
 Users:
 
-What:          /sys/bus/most/drivers/mostcore/links
+What:          /sys/bus/most/drivers/most_core/links
 Date:          March 2017
 KernelVersion: 4.15
 Contact:       Christian Gromm <christian.gromm@microchip.com>
index d7647b2..b834671 100644 (file)
@@ -20,13 +20,13 @@ Date:               April 2017
 Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
 Description:
                The supported power roles. This attribute can be used to request
-               power role swap on the port when the port supports USB Power
-               Delivery. Swapping is supported as synchronous operation, so
-               write(2) to the attribute will not return until the operation
-               has finished. The attribute is notified about role changes so
-               that poll(2) on the attribute wakes up. Change on the role will
-               also generate uevent KOBJ_CHANGE. The current role is show in
-               brackets, for example "[source] sink" when in source mode.
+               power role swap on the port. Swapping is supported as
+               synchronous operation, so write(2) to the attribute will not
+               return until the operation has finished. The attribute is
+               notified about role changes so that poll(2) on the attribute
+               wakes up. Change on the role will also generate uevent
+               KOBJ_CHANGE. The current role is show in brackets, for example
+               "[source] sink" when in source mode.
 
                Valid values: source, sink
 
@@ -108,6 +108,15 @@ Contact:   Heikki Krogerus <heikki.krogerus@linux.intel.com>
 Description:
                Revision number of the supported USB Type-C specification.
 
+What:          /sys/class/typec/<port>/orientation
+Date:          February 2020
+Contact:       Badhri Jagan Sridharan <badhri@google.com>
+Description:
+               Indicates the active orientation of the Type-C connector.
+               Valid values:
+               - "normal": CC1 orientation
+               - "reverse": CC2 orientation
+               - "unknown": Orientation cannot be determined.
 
 USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
 
index d77bb60..79ecee6 100644 (file)
@@ -13,7 +13,7 @@ endif
 SPHINXBUILD   = sphinx-build
 SPHINXOPTS    =
 SPHINXDIRS    = .
-_SPHINXDIRS   = $(patsubst $(srctree)/Documentation/%/index.rst,%,$(wildcard $(srctree)/Documentation/*/index.rst))
+_SPHINXDIRS   = $(sort $(patsubst $(srctree)/Documentation/%/index.rst,%,$(wildcard $(srctree)/Documentation/*/index.rst)))
 SPHINX_CONF   = conf.py
 PAPER         =
 BUILDDIR      = $(obj)/output
index 6864f9a..8c016d8 100644 (file)
@@ -239,7 +239,7 @@ from the PCI device config space. Use the values in the pci_dev structure
 as the PCI "bus address" might have been remapped to a "host physical"
 address by the arch/chip-set specific kernel support.
 
-See Documentation/io-mapping.txt for how to access device registers
+See Documentation/driver-api/io-mapping.rst for how to access device registers
 or device memory.
 
 The device driver needs to call pci_request_region() to verify
index 1a8b129..83ae3b7 100644 (file)
@@ -4,7 +4,7 @@ A Tour Through TREE_RCU's Grace-Period Memory Ordering
 
 August 8, 2017
 
-This article was contributed by Paul E.&nbsp;McKenney
+This article was contributed by Paul E. McKenney
 
 Introduction
 ============
@@ -48,7 +48,7 @@ Tree RCU Grace Period Memory Ordering Building Blocks
 
 The workhorse for RCU's grace-period memory ordering is the
 critical section for the ``rcu_node`` structure's
-``-&gt;lock``. These critical sections use helper functions for lock
+``->lock``. These critical sections use helper functions for lock
 acquisition, including ``raw_spin_lock_rcu_node()``,
 ``raw_spin_lock_irq_rcu_node()``, and ``raw_spin_lock_irqsave_rcu_node()``.
 Their lock-release counterparts are ``raw_spin_unlock_rcu_node()``,
@@ -102,9 +102,9 @@ lock-acquisition and lock-release functions::
    23   r3 = READ_ONCE(x);
    24 }
    25
-   26 WARN_ON(r1 == 0 &amp;&amp; r2 == 0 &amp;&amp; r3 == 0);
+   26 WARN_ON(r1 == 0 && r2 == 0 && r3 == 0);
 
-The ``WARN_ON()`` is evaluated at &ldquo;the end of time&rdquo;,
+The ``WARN_ON()`` is evaluated at "the end of time",
 after all changes have propagated throughout the system.
 Without the ``smp_mb__after_unlock_lock()`` provided by the
 acquisition functions, this ``WARN_ON()`` could trigger, for example
index 7956ff3..2a643e2 100644 (file)
@@ -4,12 +4,61 @@ Using RCU to Protect Read-Mostly Linked Lists
 =============================================
 
 One of the best applications of RCU is to protect read-mostly linked lists
-("struct list_head" in list.h).  One big advantage of this approach
+(``struct list_head`` in list.h).  One big advantage of this approach
 is that all of the required memory barriers are included for you in
 the list macros.  This document describes several applications of RCU,
 with the best fits first.
 
-Example 1: Read-Side Action Taken Outside of Lock, No In-Place Updates
+
+Example 1: Read-mostly list: Deferred Destruction
+-------------------------------------------------
+
+A widely used usecase for RCU lists in the kernel is lockless iteration over
+all processes in the system. ``task_struct::tasks`` represents the list node that
+links all the processes. The list can be traversed in parallel to any list
+additions or removals.
+
+The traversal of the list is done using ``for_each_process()`` which is defined
+by the 2 macros::
+
+       #define next_task(p) \
+               list_entry_rcu((p)->tasks.next, struct task_struct, tasks)
+
+       #define for_each_process(p) \
+               for (p = &init_task ; (p = next_task(p)) != &init_task ; )
+
+The code traversing the list of all processes typically looks like::
+
+       rcu_read_lock();
+       for_each_process(p) {
+               /* Do something with p */
+       }
+       rcu_read_unlock();
+
+The simplified code for removing a process from a task list is::
+
+       void release_task(struct task_struct *p)
+       {
+               write_lock(&tasklist_lock);
+               list_del_rcu(&p->tasks);
+               write_unlock(&tasklist_lock);
+               call_rcu(&p->rcu, delayed_put_task_struct);
+       }
+
+When a process exits, ``release_task()`` calls ``list_del_rcu(&p->tasks)`` under
+``tasklist_lock`` writer lock protection, to remove the task from the list of
+all tasks. The ``tasklist_lock`` prevents concurrent list additions/removals
+from corrupting the list. Readers using ``for_each_process()`` are not protected
+with the ``tasklist_lock``. To prevent readers from noticing changes in the list
+pointers, the ``task_struct`` object is freed only after one or more grace
+periods elapse (with the help of call_rcu()). This deferring of destruction
+ensures that any readers traversing the list will see valid ``p->tasks.next``
+pointers and deletion/freeing can happen in parallel with traversal of the list.
+This pattern is also called an **existence lock**, since RCU pins the object in
+memory until all existing readers finish.
+
+
+Example 2: Read-Side Action Taken Outside of Lock: No In-Place Updates
 ----------------------------------------------------------------------
 
 The best applications are cases where, if reader-writer locking were
@@ -26,7 +75,7 @@ added or deleted, rather than being modified in place.
 
 A straightforward example of this use of RCU may be found in the
 system-call auditing support.  For example, a reader-writer locked
-implementation of audit_filter_task() might be as follows::
+implementation of ``audit_filter_task()`` might be as follows::
 
        static enum audit_state audit_filter_task(struct task_struct *tsk)
        {
@@ -34,7 +83,7 @@ implementation of audit_filter_task() might be as follows::
                enum audit_state   state;
 
                read_lock(&auditsc_lock);
-               /* Note: audit_netlink_sem held by caller. */
+               /* Note: audit_filter_mutex held by caller. */
                list_for_each_entry(e, &audit_tsklist, list) {
                        if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
                                read_unlock(&auditsc_lock);
@@ -58,7 +107,7 @@ This means that RCU can be easily applied to the read side, as follows::
                enum audit_state   state;
 
                rcu_read_lock();
-               /* Note: audit_netlink_sem held by caller. */
+               /* Note: audit_filter_mutex held by caller. */
                list_for_each_entry_rcu(e, &audit_tsklist, list) {
                        if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
                                rcu_read_unlock();
@@ -69,18 +118,18 @@ This means that RCU can be easily applied to the read side, as follows::
                return AUDIT_BUILD_CONTEXT;
        }
 
-The read_lock() and read_unlock() calls have become rcu_read_lock()
+The ``read_lock()`` and ``read_unlock()`` calls have become rcu_read_lock()
 and rcu_read_unlock(), respectively, and the list_for_each_entry() has
-become list_for_each_entry_rcu().  The _rcu() list-traversal primitives
+become list_for_each_entry_rcu().  The **_rcu()** list-traversal primitives
 insert the read-side memory barriers that are required on DEC Alpha CPUs.
 
-The changes to the update side are also straightforward.  A reader-writer
-lock might be used as follows for deletion and insertion::
+The changes to the update side are also straightforward. A reader-writer lock
+might be used as follows for deletion and insertion::
 
        static inline int audit_del_rule(struct audit_rule *rule,
                                         struct list_head *list)
        {
-               struct audit_entry  *e;
+               struct audit_entry *e;
 
                write_lock(&auditsc_lock);
                list_for_each_entry(e, list, list) {
@@ -113,9 +162,9 @@ Following are the RCU equivalents for these two functions::
        static inline int audit_del_rule(struct audit_rule *rule,
                                         struct list_head *list)
        {
-               struct audit_entry  *e;
+               struct audit_entry *e;
 
-               /* Do not use the _rcu iterator here, since this is the only
+               /* No need to use the _rcu iterator here, since this is the only
                 * deletion routine. */
                list_for_each_entry(e, list, list) {
                        if (!audit_compare_rule(rule, &e->rule)) {
@@ -139,45 +188,45 @@ Following are the RCU equivalents for these two functions::
                return 0;
        }
 
-Normally, the write_lock() and write_unlock() would be replaced by
-a spin_lock() and a spin_unlock(), but in this case, all callers hold
-audit_netlink_sem, so no additional locking is required.  The auditsc_lock
-can therefore be eliminated, since use of RCU eliminates the need for
-writers to exclude readers.  Normally, the write_lock() calls would
-be converted into spin_lock() calls.
+Normally, the ``write_lock()`` and ``write_unlock()`` would be replaced by a
+spin_lock() and a spin_unlock(). But in this case, all callers hold
+``audit_filter_mutex``, so no additional locking is required. The
+``auditsc_lock`` can therefore be eliminated, since use of RCU eliminates the
+need for writers to exclude readers.
 
 The list_del(), list_add(), and list_add_tail() primitives have been
 replaced by list_del_rcu(), list_add_rcu(), and list_add_tail_rcu().
-The _rcu() list-manipulation primitives add memory barriers that are
-needed on weakly ordered CPUs (most of them!).  The list_del_rcu()
-primitive omits the pointer poisoning debug-assist code that would
-otherwise cause concurrent readers to fail spectacularly.
+The **_rcu()** list-manipulation primitives add memory barriers that are needed on
+weakly ordered CPUs (most of them!).  The list_del_rcu() primitive omits the
+pointer poisoning debug-assist code that would otherwise cause concurrent
+readers to fail spectacularly.
 
-So, when readers can tolerate stale data and when entries are either added
-or deleted, without in-place modification, it is very easy to use RCU!
+So, when readers can tolerate stale data and when entries are either added or
+deleted, without in-place modification, it is very easy to use RCU!
 
-Example 2: Handling In-Place Updates
+
+Example 3: Handling In-Place Updates
 ------------------------------------
 
-The system-call auditing code does not update auditing rules in place.
-However, if it did, reader-writer-locked code to do so might look as
-follows (presumably, the field_count is only permitted to decrease,
-otherwise, the added fields would need to be filled in)::
+The system-call auditing code does not update auditing rules in place.  However,
+if it did, the reader-writer-locked code to do so might look as follows
+(assuming only ``field_count`` is updated, otherwise, the added fields would
+need to be filled in)::
 
        static inline int audit_upd_rule(struct audit_rule *rule,
                                         struct list_head *list,
                                         __u32 newaction,
                                         __u32 newfield_count)
        {
-               struct audit_entry  *e;
-               struct audit_newentry *ne;
+               struct audit_entry *e;
+               struct audit_entry *ne;
 
                write_lock(&auditsc_lock);
-               /* Note: audit_netlink_sem held by caller. */
+               /* Note: audit_filter_mutex held by caller. */
                list_for_each_entry(e, list, list) {
                        if (!audit_compare_rule(rule, &e->rule)) {
                                e->rule.action = newaction;
-                               e->rule.file_count = newfield_count;
+                               e->rule.field_count = newfield_count;
                                write_unlock(&auditsc_lock);
                                return 0;
                        }
@@ -188,16 +237,16 @@ otherwise, the added fields would need to be filled in)::
 
 The RCU version creates a copy, updates the copy, then replaces the old
 entry with the newly updated entry.  This sequence of actions, allowing
-concurrent reads while doing a copy to perform an update, is what gives
-RCU ("read-copy update") its name.  The RCU code is as follows::
+concurrent reads while making a copy to perform an update, is what gives
+RCU (*read-copy update*) its name.  The RCU code is as follows::
 
        static inline int audit_upd_rule(struct audit_rule *rule,
                                         struct list_head *list,
                                         __u32 newaction,
                                         __u32 newfield_count)
        {
-               struct audit_entry  *e;
-               struct audit_newentry *ne;
+               struct audit_entry *e;
+               struct audit_entry *ne;
 
                list_for_each_entry(e, list, list) {
                        if (!audit_compare_rule(rule, &e->rule)) {
@@ -206,7 +255,7 @@ RCU ("read-copy update") its name.  The RCU code is as follows::
                                        return -ENOMEM;
                                audit_copy_rule(&ne->rule, &e->rule);
                                ne->rule.action = newaction;
-                               ne->rule.file_count = newfield_count;
+                               ne->rule.field_count = newfield_count;
                                list_replace_rcu(&e->list, &ne->list);
                                call_rcu(&e->rcu, audit_free_rule);
                                return 0;
@@ -215,34 +264,45 @@ RCU ("read-copy update") its name.  The RCU code is as follows::
                return -EFAULT;         /* No matching rule */
        }
 
-Again, this assumes that the caller holds audit_netlink_sem.  Normally,
-the reader-writer lock would become a spinlock in this sort of code.
+Again, this assumes that the caller holds ``audit_filter_mutex``.  Normally, the
+writer lock would become a spinlock in this sort of code.
 
-Example 3: Eliminating Stale Data
+Another use of this pattern can be found in the openswitch driver's *connection
+tracking table* code in ``ct_limit_set()``.  The table holds connection tracking
+entries and has a limit on the maximum entries.  There is one such table
+per-zone and hence one *limit* per zone.  The zones are mapped to their limits
+through a hashtable using an RCU-managed hlist for the hash chains. When a new
+limit is set, a new limit object is allocated and ``ct_limit_set()`` is called
+to replace the old limit object with the new one using list_replace_rcu().
+The old limit object is then freed after a grace period using kfree_rcu().
+
+
+Example 4: Eliminating Stale Data
 ---------------------------------
 
-The auditing examples above tolerate stale data, as do most algorithms
+The auditing example above tolerates stale data, as do most algorithms
 that are tracking external state.  Because there is a delay from the
 time the external state changes before Linux becomes aware of the change,
-additional RCU-induced staleness is normally not a problem.
+additional RCU-induced staleness is generally not a problem.
 
 However, there are many examples where stale data cannot be tolerated.
-One example in the Linux kernel is the System V IPC (see the ipc_lock()
-function in ipc/util.c).  This code checks a "deleted" flag under a
-per-entry spinlock, and, if the "deleted" flag is set, pretends that the
+One example in the Linux kernel is the System V IPC (see the shm_lock()
+function in ipc/shm.c).  This code checks a *deleted* flag under a
+per-entry spinlock, and, if the *deleted* flag is set, pretends that the
 entry does not exist.  For this to be helpful, the search function must
-return holding the per-entry spinlock, as ipc_lock() does in fact do.
+return holding the per-entry spinlock, as shm_lock() does in fact do.
+
+.. _quick_quiz:
 
 Quick Quiz:
-       Why does the search function need to return holding the per-entry lock for
-       this deleted-flag technique to be helpful?
+       For the deleted-flag technique to be helpful, why is it necessary
+       to hold the per-entry lock while returning from the search function?
 
-:ref:`Answer to Quick Quiz <answer_quick_quiz_list>`
+:ref:`Answer to Quick Quiz <quick_quiz_answer>`
 
-If the system-call audit module were to ever need to reject stale data,
-one way to accomplish this would be to add a "deleted" flag and a "lock"
-spinlock to the audit_entry structure, and modify audit_filter_task()
-as follows::
+If the system-call audit module were to ever need to reject stale data, one way
+to accomplish this would be to add a ``deleted`` flag and a ``lock`` spinlock to the
+audit_entry structure, and modify ``audit_filter_task()`` as follows::
 
        static enum audit_state audit_filter_task(struct task_struct *tsk)
        {
@@ -267,20 +327,20 @@ as follows::
        }
 
 Note that this example assumes that entries are only added and deleted.
-Additional mechanism is required to deal correctly with the
-update-in-place performed by audit_upd_rule().  For one thing,
-audit_upd_rule() would need additional memory barriers to ensure
-that the list_add_rcu() was really executed before the list_del_rcu().
+Additional mechanism is required to deal correctly with the update-in-place
+performed by ``audit_upd_rule()``.  For one thing, ``audit_upd_rule()`` would
+need additional memory barriers to ensure that the list_add_rcu() was really
+executed before the list_del_rcu().
 
-The audit_del_rule() function would need to set the "deleted"
-flag under the spinlock as follows::
+The ``audit_del_rule()`` function would need to set the ``deleted`` flag under the
+spinlock as follows::
 
        static inline int audit_del_rule(struct audit_rule *rule,
                                         struct list_head *list)
        {
-               struct audit_entry  *e;
+               struct audit_entry *e;
 
-               /* Do not need to use the _rcu iterator here, since this
+               /* No need to use the _rcu iterator here, since this
                 * is the only deletion routine. */
                list_for_each_entry(e, list, list) {
                        if (!audit_compare_rule(rule, &e->rule)) {
@@ -295,6 +355,91 @@ flag under the spinlock as follows::
                return -EFAULT;         /* No matching rule */
        }
 
+This too assumes that the caller holds ``audit_filter_mutex``.
+
+
+Example 5: Skipping Stale Objects
+---------------------------------
+
+For some usecases, reader performance can be improved by skipping stale objects
+during read-side list traversal if the object in concern is pending destruction
+after one or more grace periods. One such example can be found in the timerfd
+subsystem. When a ``CLOCK_REALTIME`` clock is reprogrammed - for example due to
+setting of the system time, then all programmed timerfds that depend on this
+clock get triggered and processes waiting on them to expire are woken up in
+advance of their scheduled expiry. To facilitate this, all such timers are added
+to an RCU-managed ``cancel_list`` when they are setup in
+``timerfd_setup_cancel()``::
+
+       static void timerfd_setup_cancel(struct timerfd_ctx *ctx, int flags)
+       {
+               spin_lock(&ctx->cancel_lock);
+               if ((ctx->clockid == CLOCK_REALTIME &&
+                   (flags & TFD_TIMER_ABSTIME) && (flags & TFD_TIMER_CANCEL_ON_SET)) {
+                       if (!ctx->might_cancel) {
+                               ctx->might_cancel = true;
+                               spin_lock(&cancel_lock);
+                               list_add_rcu(&ctx->clist, &cancel_list);
+                               spin_unlock(&cancel_lock);
+                       }
+               }
+               spin_unlock(&ctx->cancel_lock);
+       }
+
+When a timerfd is freed (fd is closed), then the ``might_cancel`` flag of the
+timerfd object is cleared, the object removed from the ``cancel_list`` and
+destroyed::
+
+       int timerfd_release(struct inode *inode, struct file *file)
+       {
+               struct timerfd_ctx *ctx = file->private_data;
+
+               spin_lock(&ctx->cancel_lock);
+               if (ctx->might_cancel) {
+                       ctx->might_cancel = false;
+                       spin_lock(&cancel_lock);
+                       list_del_rcu(&ctx->clist);
+                       spin_unlock(&cancel_lock);
+               }
+               spin_unlock(&ctx->cancel_lock);
+
+               hrtimer_cancel(&ctx->t.tmr);
+               kfree_rcu(ctx, rcu);
+               return 0;
+       }
+
+If the ``CLOCK_REALTIME`` clock is set, for example by a time server, the
+hrtimer framework calls ``timerfd_clock_was_set()`` which walks the
+``cancel_list`` and wakes up processes waiting on the timerfd. While iterating
+the ``cancel_list``, the ``might_cancel`` flag is consulted to skip stale
+objects::
+
+       void timerfd_clock_was_set(void)
+       {
+               struct timerfd_ctx *ctx;
+               unsigned long flags;
+
+               rcu_read_lock();
+               list_for_each_entry_rcu(ctx, &cancel_list, clist) {
+                       if (!ctx->might_cancel)
+                               continue;
+                       spin_lock_irqsave(&ctx->wqh.lock, flags);
+                       if (ctx->moffs != ktime_mono_to_real(0)) {
+                               ctx->moffs = KTIME_MAX;
+                               ctx->ticks++;
+                               wake_up_locked_poll(&ctx->wqh, EPOLLIN);
+                       }
+                       spin_unlock_irqrestore(&ctx->wqh.lock, flags);
+               }
+               rcu_read_unlock();
+       }
+
+The key point here is, because RCU-traversal of the ``cancel_list`` happens
+while objects are being added and removed to the list, sometimes the traversal
+can step on an object that has been removed from the list. In this example, it
+is seen that it is better to skip such objects using a flag.
+
+
 Summary
 -------
 
@@ -303,19 +448,21 @@ the most amenable to use of RCU.  The simplest case is where entries are
 either added or deleted from the data structure (or atomically modified
 in place), but non-atomic in-place modifications can be handled by making
 a copy, updating the copy, then replacing the original with the copy.
-If stale data cannot be tolerated, then a "deleted" flag may be used
+If stale data cannot be tolerated, then a *deleted* flag may be used
 in conjunction with a per-entry spinlock in order to allow the search
 function to reject newly deleted data.
 
-.. _answer_quick_quiz_list:
+.. _quick_quiz_answer:
 
 Answer to Quick Quiz:
-       Why does the search function need to return holding the per-entry
-       lock for this deleted-flag technique to be helpful?
+       For the deleted-flag technique to be helpful, why is it necessary
+       to hold the per-entry lock while returning from the search function?
 
        If the search function drops the per-entry lock before returning,
        then the caller will be processing stale data in any case.  If it
        is really OK to be processing stale data, then you don't need a
-       "deleted" flag.  If processing stale data really is a problem,
+       *deleted* flag.  If processing stale data really is a problem,
        then you need to hold the per-entry lock across all of the code
        that uses the value that was returned.
+
+:ref:`Back to Quick Quiz <quick_quiz>`
index 8dfb437..0e03c6e 100644 (file)
@@ -11,8 +11,8 @@ must be long enough that any readers accessing the item being deleted have
 since dropped their references.  For example, an RCU-protected deletion
 from a linked list would first remove the item from the list, wait for
 a grace period to elapse, then free the element.  See the
-Documentation/RCU/listRCU.rst file for more information on using RCU with
-linked lists.
+:ref:`Documentation/RCU/listRCU.rst <list_rcu_doc>` for more information on
+using RCU with linked lists.
 
 Frequently Asked Questions
 --------------------------
@@ -50,7 +50,7 @@ Frequently Asked Questions
 - If I am running on a uniprocessor kernel, which can only do one
   thing at a time, why should I wait for a grace period?
 
-  See the Documentation/RCU/UP.rst file for more information.
+  See :ref:`Documentation/RCU/UP.rst <up_doc>` for more information.
 
 - How can I see where RCU is currently used in the Linux kernel?
 
@@ -68,18 +68,18 @@ Frequently Asked Questions
 
 - Why the name "RCU"?
 
-  "RCU" stands for "read-copy update".  The file Documentation/RCU/listRCU.rst
-  has more information on where this name came from, search for
-  "read-copy update" to find it.
+  "RCU" stands for "read-copy update".
+  :ref:`Documentation/RCU/listRCU.rst <list_rcu_doc>` has more information on where
+  this name came from, search for "read-copy update" to find it.
 
 - I hear that RCU is patented?  What is with that?
 
   Yes, it is.  There are several known patents related to RCU,
-  search for the string "Patent" in RTFP.txt to find them.
+  search for the string "Patent" in Documentation/RCU/RTFP.txt to find them.
   Of these, one was allowed to lapse by the assignee, and the
   others have been contributed to the Linux kernel under GPL.
   There are now also LGPL implementations of user-level RCU
-  available (http://liburcu.org/).
+  available (https://liburcu.org/).
 
 - I hear that RCU needs work in order to support realtime kernels?
 
@@ -88,5 +88,5 @@ Frequently Asked Questions
 
 - Where can I find more information on RCU?
 
-  See the RTFP.txt file in this directory.
+  See the Documentation/RCU/RTFP.txt file.
   Or point your browser at (http://www.rdrop.com/users/paulmck/RCU/).
index a41a038..af712a3 100644 (file)
@@ -124,9 +124,14 @@ using a dynamically allocated srcu_struct (hence "srcud-" rather than
 debugging.  The final "T" entry contains the totals of the counters.
 
 
-USAGE
+USAGE ON SPECIFIC KERNEL BUILDS
 
-The following script may be used to torture RCU:
+It is sometimes desirable to torture RCU on a specific kernel build,
+for example, when preparing to put that kernel build into production.
+In that case, the kernel should be built with CONFIG_RCU_TORTURE_TEST=m
+so that the test can be started using modprobe and terminated using rmmod.
+
+For example, the following script may be used to torture RCU:
 
        #!/bin/sh
 
@@ -142,8 +147,136 @@ checked for such errors.  The "rmmod" command forces a "SUCCESS",
 two are self-explanatory, while the last indicates that while there
 were no RCU failures, CPU-hotplug problems were detected.
 
-However, the tools/testing/selftests/rcutorture/bin/kvm.sh script
-provides better automation, including automatic failure analysis.
-It assumes a qemu/kvm-enabled platform, and runs guest OSes out of initrd.
-See tools/testing/selftests/rcutorture/doc/initrd.txt for instructions
-on setting up such an initrd.
+
+USAGE ON MAINLINE KERNELS
+
+When using rcutorture to test changes to RCU itself, it is often
+necessary to build a number of kernels in order to test that change
+across a broad range of combinations of the relevant Kconfig options
+and of the relevant kernel boot parameters.  In this situation, use
+of modprobe and rmmod can be quite time-consuming and error-prone.
+
+Therefore, the tools/testing/selftests/rcutorture/bin/kvm.sh
+script is available for mainline testing for x86, arm64, and
+powerpc.  By default, it will run the series of tests specified by
+tools/testing/selftests/rcutorture/configs/rcu/CFLIST, with each test
+running for 30 minutes within a guest OS using a minimal userspace
+supplied by an automatically generated initrd.  After the tests are
+complete, the resulting build products and console output are analyzed
+for errors and the results of the runs are summarized.
+
+On larger systems, rcutorture testing can be accelerated by passing the
+--cpus argument to kvm.sh.  For example, on a 64-CPU system, "--cpus 43"
+would use up to 43 CPUs to run tests concurrently, which as of v5.4 would
+complete all the scenarios in two batches, reducing the time to complete
+from about eight hours to about one hour (not counting the time to build
+the sixteen kernels).  The "--dryrun sched" argument will not run tests,
+but rather tell you how the tests would be scheduled into batches.  This
+can be useful when working out how many CPUs to specify in the --cpus
+argument.
+
+Not all changes require that all scenarios be run.  For example, a change
+to Tree SRCU might run only the SRCU-N and SRCU-P scenarios using the
+--configs argument to kvm.sh as follows:  "--configs 'SRCU-N SRCU-P'".
+Large systems can run multiple copies of of the full set of scenarios,
+for example, a system with 448 hardware threads can run five instances
+of the full set concurrently.  To make this happen:
+
+       kvm.sh --cpus 448 --configs '5*CFLIST'
+
+Alternatively, such a system can run 56 concurrent instances of a single
+eight-CPU scenario:
+
+       kvm.sh --cpus 448 --configs '56*TREE04'
+
+Or 28 concurrent instances of each of two eight-CPU scenarios:
+
+       kvm.sh --cpus 448 --configs '28*TREE03 28*TREE04'
+
+Of course, each concurrent instance will use memory, which can be
+limited using the --memory argument, which defaults to 512M.  Small
+values for memory may require disabling the callback-flooding tests
+using the --bootargs parameter discussed below.
+
+Sometimes additional debugging is useful, and in such cases the --kconfig
+parameter to kvm.sh may be used, for example, "--kconfig 'CONFIG_KASAN=y'".
+
+Kernel boot arguments can also be supplied, for example, to control
+rcutorture's module parameters.  For example, to test a change to RCU's
+CPU stall-warning code, use "--bootargs 'rcutorture.stall_cpu=30'".
+This will of course result in the scripting reporting a failure, namely
+the resuling RCU CPU stall warning.  As noted above, reducing memory may
+require disabling rcutorture's callback-flooding tests:
+
+       kvm.sh --cpus 448 --configs '56*TREE04' --memory 128M \
+               --bootargs 'rcutorture.fwd_progress=0'
+
+Sometimes all that is needed is a full set of kernel builds.  This is
+what the --buildonly argument does.
+
+Finally, the --trust-make argument allows each kernel build to reuse what
+it can from the previous kernel build.
+
+There are additional more arcane arguments that are documented in the
+source code of the kvm.sh script.
+
+If a run contains failures, the number of buildtime and runtime failures
+is listed at the end of the kvm.sh output, which you really should redirect
+to a file.  The build products and console output of each run is kept in
+tools/testing/selftests/rcutorture/res in timestamped directories.  A
+given directory can be supplied to kvm-find-errors.sh in order to have
+it cycle you through summaries of errors and full error logs.  For example:
+
+       tools/testing/selftests/rcutorture/bin/kvm-find-errors.sh \
+               tools/testing/selftests/rcutorture/res/2020.01.20-15.54.23
+
+However, it is often more convenient to access the files directly.
+Files pertaining to all scenarios in a run reside in the top-level
+directory (2020.01.20-15.54.23 in the example above), while per-scenario
+files reside in a subdirectory named after the scenario (for example,
+"TREE04").  If a given scenario ran more than once (as in "--configs
+'56*TREE04'" above), the directories corresponding to the second and
+subsequent runs of that scenario include a sequence number, for example,
+"TREE04.2", "TREE04.3", and so on.
+
+The most frequently used file in the top-level directory is testid.txt.
+If the test ran in a git repository, then this file contains the commit
+that was tested and any uncommitted changes in diff format.
+
+The most frequently used files in each per-scenario-run directory are:
+
+.config: This file contains the Kconfig options.
+
+Make.out: This contains build output for a specific scenario.
+
+console.log: This contains the console output for a specific scenario.
+       This file may be examined once the kernel has booted, but
+       it might not exist if the build failed.
+
+vmlinux: This contains the kernel, which can be useful with tools like
+       objdump and gdb.
+
+A number of additional files are available, but are less frequently used.
+Many are intended for debugging of rcutorture itself or of its scripting.
+
+As of v5.4, a successful run with the default set of scenarios produces
+the following summary at the end of the run on a 12-CPU system:
+
+SRCU-N ------- 804233 GPs (148.932/s) [srcu: g10008272 f0x0 ]
+SRCU-P ------- 202320 GPs (37.4667/s) [srcud: g1809476 f0x0 ]
+SRCU-t ------- 1122086 GPs (207.794/s) [srcu: g0 f0x0 ]
+SRCU-u ------- 1111285 GPs (205.794/s) [srcud: g1 f0x0 ]
+TASKS01 ------- 19666 GPs (3.64185/s) [tasks: g0 f0x0 ]
+TASKS02 ------- 20541 GPs (3.80389/s) [tasks: g0 f0x0 ]
+TASKS03 ------- 19416 GPs (3.59556/s) [tasks: g0 f0x0 ]
+TINY01 ------- 836134 GPs (154.84/s) [rcu: g0 f0x0 ] n_max_cbs: 34198
+TINY02 ------- 850371 GPs (157.476/s) [rcu: g0 f0x0 ] n_max_cbs: 2631
+TREE01 ------- 162625 GPs (30.1157/s) [rcu: g1124169 f0x0 ]
+TREE02 ------- 333003 GPs (61.6672/s) [rcu: g2647753 f0x0 ] n_max_cbs: 35844
+TREE03 ------- 306623 GPs (56.782/s) [rcu: g2975325 f0x0 ] n_max_cbs: 1496497
+CPU count limited from 16 to 12
+TREE04 ------- 246149 GPs (45.5831/s) [rcu: g1695737 f0x0 ] n_max_cbs: 434961
+TREE05 ------- 314603 GPs (58.2598/s) [rcu: g2257741 f0x2 ] n_max_cbs: 193997
+TREE07 ------- 167347 GPs (30.9902/s) [rcu: g1079021 f0x0 ] n_max_cbs: 478732
+CPU count limited from 16 to 12
+TREE09 ------- 752238 GPs (139.303/s) [rcu: g13075057 f0x0 ] n_max_cbs: 99011
index 621111c..f2b3439 100644 (file)
@@ -1,3 +1,5 @@
+.. _psi:
+
 ================================
 PSI - Pressure Stall Information
 ================================
index 21d233c..98fe5c3 100644 (file)
@@ -18,7 +18,7 @@ may look as follows::
 
  $ ls -l /sys/bus/acpi/devices/INT3404:00/
  total 0
-...
+ ...
  -r--r--r-- 1 root root 4096 Dec 13 20:38 state0
  -r--r--r-- 1 root root 4096 Dec 13 20:38 state1
  -r--r--r-- 1 root root 4096 Dec 13 20:38 state10
@@ -38,7 +38,7 @@ where each of the "state*" files represents one performance state of the fan
 and contains a colon-separated list of 5 integer numbers (fields) with the
 following interpretation::
 
-control_percent:trip_point_index:speed_rpm:noise_level_mdb:power_mw
+  control_percent:trip_point_index:speed_rpm:noise_level_mdb:power_mw
 
 * ``control_percent``: The percent value to be used to set the fan speed to a
   specific level using the _FSL object (0-100).
index 97b0d79..95c93bb 100644 (file)
@@ -1,5 +1,5 @@
-Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
-=====================================================================
+Kernel Support for miscellaneous Binary Formats (binfmt_misc)
+=============================================================
 
 This Kernel feature allows you to invoke almost (for restrictions see below)
 every program by simply typing its name in the shell.
index 27c77d8..a6fd1f9 100644 (file)
@@ -251,8 +251,6 @@ line of text and contains the following stats separated by whitespace:
 
  ================ =============================================================
  orig_data_size   uncompressed size of data stored in this disk.
-                 This excludes same-element-filled pages (same_pages) since
-                 no memory is allocated for them.
                   Unit: bytes
  compr_data_size  compressed size of data stored in this disk
  mem_used_total   the amount of memory allocated for this disk. This
index b342a67..d6b3b77 100644 (file)
@@ -23,7 +23,7 @@ of dot-connected-words, and key and value are connected by ``=``. The value
 has to be terminated by semi-colon (``;``) or newline (``\n``).
 For array value, array entries are separated by comma (``,``). ::
 
-KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
+  KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
 
 Unlike the kernel command line syntax, spaces are OK around the comma and ``=``.
 
@@ -62,6 +62,30 @@ Or more shorter, written as following::
 In both styles, same key words are automatically merged when parsing it
 at boot time. So you can append similar trees or key-values.
 
+Same-key Values
+---------------
+
+It is prohibited that two or more values or arrays share a same-key.
+For example,::
+
+ foo = bar, baz
+ foo = qux  # !ERROR! we can not re-define same key
+
+If you want to append the value to existing key as an array member,
+you can use ``+=`` operator. For example::
+
+ foo = bar, baz
+ foo += qux
+
+In this case, the key ``foo`` has ``bar``, ``baz`` and ``qux``.
+
+However, a sub-key and a value can not co-exist under a parent key.
+For example, following config is NOT allowed.::
+
+ foo = value1
+ foo.bar = value2 # !ERROR! subkey "bar" and value "value1" can NOT co-exist
+
+
 Comments
 --------
 
@@ -102,9 +126,13 @@ Boot Kernel With a Boot Config
 ==============================
 
 Since the boot configuration file is loaded with initrd, it will be added
-to the end of the initrd (initramfs) image file. The Linux kernel decodes
-the last part of the initrd image in memory to get the boot configuration
-data.
+to the end of the initrd (initramfs) image file with size, checksum and
+12-byte magic word as below.
+
+[initrd][bootconfig][size(u32)][checksum(u32)][#BOOTCONFIG\n]
+
+The Linux kernel decodes the last part of the initrd image in memory to
+get the boot configuration data.
 Because of this "piggyback" method, there is no need to change or
 update the boot loader and the kernel image itself.
 
index 10bf48b..226f644 100644 (file)
@@ -1,3 +1,5 @@
+.. _cgroup-v1:
+
 ========================
 Control Groups version 1
 ========================
index 3f80146..fbb1116 100644 (file)
@@ -9,7 +9,7 @@ This is the authoritative documentation on the design, interface and
 conventions of cgroup v2.  It describes all userland-visible aspects
 of cgroup including core and specific controller behaviors.  All
 future changes must be reflected in this document.  Documentation for
-v1 is available under Documentation/admin-guide/cgroup-v1/.
+v1 is available under :ref:`Documentation/admin-guide/cgroup-v1/index.rst <cgroup-v1>`.
 
 .. CONTENTS
 
@@ -1023,7 +1023,7 @@ All time durations are in microseconds.
        A read-only nested-key file which exists on non-root cgroups.
 
        Shows pressure stall information for CPU. See
-       Documentation/accounting/psi.rst for details.
+       :ref:`Documentation/accounting/psi.rst <psi>` for details.
 
   cpu.uclamp.min
         A read-write single value file which exists on non-root cgroups.
@@ -1103,7 +1103,7 @@ PAGE_SIZE multiple when read back.
        proportionally to the overage, reducing reclaim pressure for
        smaller overages.
 
-       Effective min boundary is limited by memory.min values of
+       Effective min boundary is limited by memory.min values of
        all ancestor cgroups. If there is memory.min overcommitment
        (child cgroup or cgroups are requiring more protected memory
        than parent will allow), then each child cgroup will get
@@ -1313,53 +1313,41 @@ PAGE_SIZE multiple when read back.
                Number of major page faults incurred
 
          workingset_refault
-
                Number of refaults of previously evicted pages
 
          workingset_activate
-
                Number of refaulted pages that were immediately activated
 
          workingset_nodereclaim
-
                Number of times a shadow node has been reclaimed
 
          pgrefill
-
                Amount of scanned pages (in an active LRU list)
 
          pgscan
-
                Amount of scanned pages (in an inactive LRU list)
 
          pgsteal
-
                Amount of reclaimed pages
 
          pgactivate
-
                Amount of pages moved to the active LRU list
 
          pgdeactivate
-
                Amount of pages moved to the inactive LRU list
 
          pglazyfree
-
                Amount of pages postponed to be freed under memory pressure
 
          pglazyfreed
-
                Amount of reclaimed lazyfree pages
 
          thp_fault_alloc
-
                Number of transparent hugepages which were allocated to satisfy
                a page fault, including COW faults. This counter is not present
                when CONFIG_TRANSPARENT_HUGEPAGE is not set.
 
          thp_collapse_alloc
-
                Number of transparent hugepages which were allocated to allow
                collapsing an existing range of pages. This counter is not
                present when CONFIG_TRANSPARENT_HUGEPAGE is not set.
@@ -1403,7 +1391,7 @@ PAGE_SIZE multiple when read back.
        A read-only nested-key file which exists on non-root cgroups.
 
        Shows pressure stall information for memory. See
-       Documentation/accounting/psi.rst for details.
+       :ref:`Documentation/accounting/psi.rst <psi>` for details.
 
 
 Usage Guidelines
@@ -1478,7 +1466,7 @@ IO Interface Files
          dios          Number of discard IOs
          ======        =====================
 
-       An example read output follows:
+       An example read output follows::
 
          8:16 rbytes=1459200 wbytes=314773504 rios=192 wios=353 dbytes=0 dios=0
          8:0 rbytes=90430464 wbytes=299008000 rios=8950 wios=1252 dbytes=50331648 dios=3021
@@ -1643,7 +1631,7 @@ IO Interface Files
        A read-only nested-key file which exists on non-root cgroups.
 
        Shows pressure stall information for IO. See
-       Documentation/accounting/psi.rst for details.
+       :ref:`Documentation/accounting/psi.rst <psi>` for details.
 
 
 Writeback
@@ -1853,7 +1841,7 @@ Cpuset Interface Files
        from the requested CPUs.
 
        The CPU numbers are comma-separated numbers or ranges.
-       For example:
+       For example::
 
          # cat cpuset.cpus
          0-4,6,8-10
@@ -1892,7 +1880,7 @@ Cpuset Interface Files
        from the requested memory nodes.
 
        The memory node numbers are comma-separated numbers or ranges.
-       For example:
+       For example::
 
          # cat cpuset.mems
          0-1,3
similarity index 98%
rename from Documentation/driver-api/edid.rst
rename to Documentation/admin-guide/edid.rst
index b1b5acd..80deeb2 100644 (file)
@@ -11,11 +11,13 @@ Today, with the advent of Kernel Mode Setting, a graphics board is
 either correctly working because all components follow the standards -
 or the computer is unusable, because the screen remains dark after
 booting or it displays the wrong area. Cases when this happens are:
+
 - The graphics board does not recognize the monitor.
 - The graphics board is unable to detect any EDID data.
 - The graphics board incorrectly forwards EDID data to the driver.
 - The monitor sends no or bogus EDID data.
 - A KVM sends its own EDID data instead of querying the connected monitor.
+
 Adding the kernel parameter "nomodeset" helps in most cases, but causes
 restrictions later on.
 
@@ -32,7 +34,7 @@ individual data for a specific misbehaving monitor, commented sources
 and a Makefile environment are given here.
 
 To create binary EDID and C source code files from the existing data
-material, simply type "make".
+material, simply type "make" in tools/edid/.
 
 If you want to create your own EDID file, copy the file 1024x768.S,
 replace the settings with your own data and add a new target to the
index af6865b..68d96f0 100644 (file)
@@ -136,8 +136,6 @@ enables the mitigation by default.
 The mitigation can be controlled at boot time via a kernel command line option.
 See :ref:`taa_mitigation_control_command_line`.
 
-.. _virt_mechanism:
-
 Virtualization mitigation
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
index f1d0ccf..5a6269f 100644 (file)
@@ -75,6 +75,7 @@ configure specific aspects of kernel behavior to your liking.
    cputopology
    dell_rbu
    device-mapper/index
+   edid
    efi-stub
    ext4
    nfs/index
index df5b834..9b14b0c 100644 (file)
@@ -100,7 +100,7 @@ Field 10 -- # of milliseconds spent doing I/Os (unsigned int)
 
     Since 5.0 this field counts jiffies when at least one request was
     started or completed. If request runs more than 2 jiffies then some
-    I/O time will not be accounted unless there are other requests.
+    I/O time might be not accounted in case of concurrent requests.
 
 Field 11 -- weighted # of milliseconds spent doing I/Os (unsigned int)
     This field is incremented at each I/O start, I/O completion, I/O
@@ -143,6 +143,9 @@ are summed (possibly overflowing the unsigned long variable they are
 summed to) and the result given to the user.  There is no convenient
 user interface for accessing the per-CPU counters themselves.
 
+Since 4.19 request times are measured with nanoseconds precision and
+truncated to milliseconds before showing in this interface.
+
 Disks vs Partitions
 -------------------
 
index dbc22d6..cbd8bc7 100644 (file)
                        dynamic table installation which will install SSDT
                        tables to /sys/firmware/acpi/tables/dynamic.
 
+       acpi_no_watchdog        [HW,ACPI,WDT]
+                       Ignore the ACPI-based watchdog interface (WDAT) and let
+                       a native driver control the watchdog device instead.
+
        acpi_rsdp=      [ACPI,EFI,KEXEC]
                        Pass the RSDP address to the kernel, mostly used
                        on machines running EFI runtime service to boot the
        bert_disable    [ACPI]
                        Disable BERT OS support on buggy BIOSes.
 
+       bgrt_disable    [ACPI][X86]
+                       Disable BGRT to avoid flickering OEM logo.
+
        bttv.card=      [HW,V4L] bttv (bt848 + bt878 based grabber cards)
        bttv.radio=     Most important insmod options are available as
                        kernel args too.
                        A valid base address must be provided, and the serial
                        port must already be setup and configured.
 
+               ec_imx21,<addr>
+               ec_imx6q,<addr>
+                       Start an early, polled-mode, output-only console on the
+                       Freescale i.MX UART at the specified address. The UART
+                       must already be setup and configured.
+
                ar3700_uart,<addr>
                        Start an early, polled-mode console on the
                        Armada 3700 serial port at the specified
                        can be changed at run time by the max_graph_depth file
                        in the tracefs tracing directory. default: 0 (no limit)
 
+       fw_devlink=     [KNL] Create device links between consumer and supplier
+                       devices by scanning the firmware to infer the
+                       consumer/supplier relationships. This feature is
+                       especially useful when drivers are loaded as modules as
+                       it ensures proper ordering of tasks like device probing
+                       (suppliers first, then consumers), supplier boot state
+                       clean up (only after all consumers have probed),
+                       suspend/resume & runtime PM (consumers first, then
+                       suppliers).
+                       Format: { off | permissive | on | rpm }
+                       off --  Don't create device links from firmware info.
+                       permissive -- Create device links from firmware info
+                               but use it only for ordering boot state clean
+                               up (sync_state() calls).
+                       on --   Create device links from firmware info and use it
+                               to enforce probe and suspend/resume ordering.
+                       rpm --  Like "on", but also use to order runtime PM.
+
        gamecon.map[2|3]=
                        [HW,JOY] Multisystem joystick and NES/SNES/PSX pad
                        support via parallel port (up to 5 devices per port)
                        provided by tboot because it makes the system
                        vulnerable to DMA attacks.
                nobounce [Default off]
-                       Disable bounce buffer for unstrusted devices such as
+                       Disable bounce buffer for untrusted devices such as
                        the Thunderbolt devices. This will treat the untrusted
                        devices as the trusted ones, hence might expose security
                        risks of DMA attacks.
                        No delay
 
        ip=             [IP_PNP]
-                       See Documentation/filesystems/nfs/nfsroot.txt.
+                       See Documentation/admin-guide/nfs/nfsroot.rst.
 
        ipcmni_extend   [KNL] Extend the maximum number of unique System V
                        IPC identifiers from 32,768 to 16,777,216.
                        <name>,<region-number>[,<base>,<size>,<buswidth>,<altbuswidth>]
 
        mtdparts=       [MTD]
-                       See drivers/mtd/cmdlinepart.c.
+                       See drivers/mtd/parsers/cmdlinepart.c
 
        multitce=off    [PPC]  This parameter disables the use of the pSeries
                        firmware feature for updating multiple TCE entries
                        Default value is 0.
 
        nfsaddrs=       [NFS] Deprecated.  Use ip= instead.
-                       See Documentation/filesystems/nfs/nfsroot.txt.
+                       See Documentation/admin-guide/nfs/nfsroot.rst.
 
        nfsroot=        [NFS] nfs root filesystem for disk-less boxes.
-                       See Documentation/filesystems/nfs/nfsroot.txt.
+                       See Documentation/admin-guide/nfs/nfsroot.rst.
 
        nfsrootdebug    [NFS] enable nfsroot debugging messages.
-                       See Documentation/filesystems/nfs/nfsroot.txt.
+                       See Documentation/admin-guide/nfs/nfsroot.rst.
 
        nfs.callback_nr_threads=
                        [NFSv4] set the total number of threads that the
                        This can be set from sysctl after boot.
                        See Documentation/admin-guide/sysctl/vm.rst for details.
 
-       of_devlink      [OF, KNL] Create device links between consumer and
-                       supplier devices by scanning the devictree to infer the
-                       consumer/supplier relationships.  A consumer device
-                       will not be probed until all the supplier devices have
-                       probed successfully.
-
        ohci1394_dma=early      [HW] enable debugging via the ohci1394 driver.
                        See Documentation/debugging-via-ohci1394.txt for more
                        info.
                        Set threshold of queued RCU callbacks below which
                        batch limiting is re-enabled.
 
+       rcutree.qovld= [KNL]
+                       Set threshold of queued RCU callbacks beyond which
+                       RCU's force-quiescent-state scan will aggressively
+                       enlist help from cond_resched() and sched IPIs to
+                       help CPUs more quickly reach quiescent states.
+                       Set to less than zero to make this be set based
+                       on rcutree.qhimark at boot time and to zero to
+                       disable more aggressive help enlistment.
+
        rcutree.rcu_idle_gp_delay= [KNL]
                        Set wakeup interval for idle CPUs that have
                        RCU callbacks (RCU_FAST_NO_HZ=y).
        rcupdate.rcu_cpu_stall_suppress= [KNL]
                        Suppress RCU CPU stall warning messages.
 
+       rcupdate.rcu_cpu_stall_suppress_at_boot= [KNL]
+                       Suppress RCU CPU stall warning messages and
+                       rcutorture writer stall warnings that occur
+                       during early boot, that is, during the time
+                       before the init task is spawned.
+
        rcupdate.rcu_cpu_stall_timeout= [KNL]
                        Set timeout for RCU CPU stall warning messages.
 
                        incurs a small amount of overhead in the scheduler
                        but is useful for debugging and performance tuning.
 
+       sched_thermal_decay_shift=
+                       [KNL, SMP] Set a decay shift for scheduler thermal
+                       pressure signal. Thermal pressure signal follows the
+                       default decay period of other scheduler pelt
+                       signals(usually 32 ms but configurable). Setting
+                       sched_thermal_decay_shift will left shift the decay
+                       period for the thermal pressure signal by the shift
+                       value.
+                       i.e. with the default pelt decay period of 32 ms
+                       sched_thermal_decay_shift   thermal pressure decay pr
+                               1                       64 ms
+                               2                       128 ms
+                       and so on.
+                       Format: integer between 0 and 10
+                       Default is 0.
+
        skew_tick=      [KNL] Offset the periodic timer tick per cpu to mitigate
                        xtime_lock contention on larger systems, and/or RCU lock
                        contention on all systems with CONFIG_MAXSMP set.
                        Format: <integer>
 
                        A nonzero value instructs the soft-lockup detector
-                       to panic the machine when a soft-lockup occurs. This
-                       is also controlled by CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC
-                       which is the respective build-time switch to that
-                       functionality.
+                       to panic the machine when a soft-lockup occurs. It is
+                       also controlled by the kernel.softlockup_panic sysctl
+                       and CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC, which is the
+                       respective build-time switch to that functionality.
 
        softlockup_all_cpu_backtrace=
                        [KNL] Should the soft-lockup detector generate
        spia_pedr=
        spia_peddr=
 
+       split_lock_detect=
+                       [X86] Enable split lock detection
+
+                       When enabled (and if hardware support is present), atomic
+                       instructions that access data across cache line
+                       boundaries will result in an alignment check exception.
+
+                       off     - not enabled
+
+                       warn    - the kernel will emit rate limited warnings
+                                 about applications triggering the #AC
+                                 exception. This mode is the default on CPUs
+                                 that supports split lock detection.
+
+                       fatal   - the kernel will send SIGBUS to applications
+                                 that trigger the #AC exception.
+
+                       If an #AC exception is hit in the kernel or in
+                       firmware (i.e. not while executing in user mode)
+                       the kernel will oops in either "warn" or "fatal"
+                       mode.
+
        srcutree.counter_wrap_check [KNL]
                        Specifies how frequently to check for
                        grace-period sequence counter wrap for the
                        topology updates sent by the hypervisor to this
                        LPAR.
 
+       torture.disable_onoff_at_boot= [KNL]
+                       Prevent the CPU-hotplug component of torturing
+                       until after init has spawned.
+
        tp720=          [HW,PS2]
 
        tpm_suspend_pcr=[HW,TPM]
index baeeba8..21818ac 100644 (file)
@@ -234,7 +234,7 @@ To reduce its OS jitter, do any of the following:
        Such a workqueue can be confined to a given subset of the
        CPUs using the ``/sys/devices/virtual/workqueue/*/cpumask`` sysfs
        files.  The set of WQ_SYSFS workqueues can be displayed using
-       "ls sys/devices/virtual/workqueue".  That said, the workqueues
+       "ls /sys/devices/virtual/workqueue".  That said, the workqueues
        maintainer would like to caution people against indiscriminately
        sprinkling WQ_SYSFS across all the workqueues.  The reason for
        caution is that it is easy to add WQ_SYSFS, but because sysfs is
index 3726a10..f05f56c 100644 (file)
@@ -43,7 +43,8 @@ value 1 for supported.
 
   AXI_ID and AXI_MASKING are mapped on DPCR1 register in performance counter.
   When non-masked bits are matching corresponding AXI_ID bits then counter is
-  incremented. Perf counter is incremented if
+  incremented. Perf counter is incremented if::
+
         AxID && AXI_MASKING == AXI_ID && AXI_MASKING
 
   This filter doesn't support filter different AXI ID for axid-read and axid-write
diff --git a/Documentation/admin-guide/pm/cpufreq_drivers.rst b/Documentation/admin-guide/pm/cpufreq_drivers.rst
new file mode 100644 (file)
index 0000000..9a134ae
--- /dev/null
@@ -0,0 +1,274 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=======================================================
+Legacy Documentation of CPU Performance Scaling Drivers
+=======================================================
+
+Included below are historic documents describing assorted
+:doc:`CPU performance scaling <cpufreq>` drivers.  They are reproduced verbatim,
+with the original white space formatting and indentation preserved, except for
+the added leading space character in every line of text.
+
+
+AMD PowerNow! Drivers
+=====================
+
+::
+
+ PowerNow! and Cool'n'Quiet are AMD names for frequency
+ management capabilities in AMD processors. As the hardware
+ implementation changes in new generations of the processors,
+ there is a different cpu-freq driver for each generation.
+
+ Note that the driver's will not load on the "wrong" hardware,
+ so it is safe to try each driver in turn when in doubt as to
+ which is the correct driver.
+
+ Note that the functionality to change frequency (and voltage)
+ is not available in all processors. The drivers will refuse
+ to load on processors without this capability. The capability
+ is detected with the cpuid instruction.
+
+ The drivers use BIOS supplied tables to obtain frequency and
+ voltage information appropriate for a particular platform.
+ Frequency transitions will be unavailable if the BIOS does
+ not supply these tables.
+
+ 6th Generation: powernow-k6
+
+ 7th Generation: powernow-k7: Athlon, Duron, Geode.
+
+ 8th Generation: powernow-k8: Athlon, Athlon 64, Opteron, Sempron.
+ Documentation on this functionality in 8th generation processors
+ is available in the "BIOS and Kernel Developer's Guide", publication
+ 26094, in chapter 9, available for download from www.amd.com.
+
+ BIOS supplied data, for powernow-k7 and for powernow-k8, may be
+ from either the PSB table or from ACPI objects. The ACPI support
+ is only available if the kernel config sets CONFIG_ACPI_PROCESSOR.
+ The powernow-k8 driver will attempt to use ACPI if so configured,
+ and fall back to PST if that fails.
+ The powernow-k7 driver will try to use the PSB support first, and
+ fall back to ACPI if the PSB support fails. A module parameter,
+ acpi_force, is provided to force ACPI support to be used instead
+ of PSB support.
+
+
+``cpufreq-nforce2``
+===================
+
+::
+
+ The cpufreq-nforce2 driver changes the FSB on nVidia nForce2 platforms.
+
+ This works better than on other platforms, because the FSB of the CPU
+ can be controlled independently from the PCI/AGP clock.
+
+ The module has two options:
+
+       fid:     multiplier * 10 (for example 8.5 = 85)
+       min_fsb: minimum FSB
+
+ If not set, fid is calculated from the current CPU speed and the FSB.
+ min_fsb defaults to FSB at boot time - 50 MHz.
+
+ IMPORTANT: The available range is limited downwards!
+            Also the minimum available FSB can differ, for systems
+            booting with 200 MHz, 150 should always work.
+
+
+``pcc-cpufreq``
+===============
+
+::
+
+ /*
+  *  pcc-cpufreq.txt - PCC interface documentation
+  *
+  *  Copyright (C) 2009 Red Hat, Matthew Garrett <mjg@redhat.com>
+  *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+  *      Nagananda Chumbalkar <nagananda.chumbalkar@hp.com>
+  */
+
+
+                       Processor Clocking Control Driver
+                       ---------------------------------
+
+ Contents:
+ ---------
+ 1.    Introduction
+ 1.1   PCC interface
+ 1.1.1 Get Average Frequency
+ 1.1.2 Set Desired Frequency
+ 1.2   Platforms affected
+ 2.    Driver and /sys details
+ 2.1   scaling_available_frequencies
+ 2.2   cpuinfo_transition_latency
+ 2.3   cpuinfo_cur_freq
+ 2.4   related_cpus
+ 3.    Caveats
+
+ 1. Introduction:
+ ----------------
+ Processor Clocking Control (PCC) is an interface between the platform
+ firmware and OSPM. It is a mechanism for coordinating processor
+ performance (ie: frequency) between the platform firmware and the OS.
+
+ The PCC driver (pcc-cpufreq) allows OSPM to take advantage of the PCC
+ interface.
+
+ OS utilizes the PCC interface to inform platform firmware what frequency the
+ OS wants for a logical processor. The platform firmware attempts to achieve
+ the requested frequency. If the request for the target frequency could not be
+ satisfied by platform firmware, then it usually means that power budget
+ conditions are in place, and "power capping" is taking place.
+
+ 1.1 PCC interface:
+ ------------------
+ The complete PCC specification is available here:
+ https://acpica.org/sites/acpica/files/Processor-Clocking-Control-v1p0.pdf
+
+ PCC relies on a shared memory region that provides a channel for communication
+ between the OS and platform firmware. PCC also implements a "doorbell" that
+ is used by the OS to inform the platform firmware that a command has been
+ sent.
+
+ The ACPI PCCH() method is used to discover the location of the PCC shared
+ memory region. The shared memory region header contains the "command" and
+ "status" interface. PCCH() also contains details on how to access the platform
+ doorbell.
+
+ The following commands are supported by the PCC interface:
+ * Get Average Frequency
+ * Set Desired Frequency
+
+ The ACPI PCCP() method is implemented for each logical processor and is
+ used to discover the offsets for the input and output buffers in the shared
+ memory region.
+
+ When PCC mode is enabled, the platform will not expose processor performance
+ or throttle states (_PSS, _TSS and related ACPI objects) to OSPM. Therefore,
+ the native P-state driver (such as acpi-cpufreq for Intel, powernow-k8 for
+ AMD) will not load.
+
+ However, OSPM remains in control of policy. The governor (eg: "ondemand")
+ computes the required performance for each processor based on server workload.
+ The PCC driver fills in the command interface, and the input buffer and
+ communicates the request to the platform firmware. The platform firmware is
+ responsible for delivering the requested performance.
+
+ Each PCC command is "global" in scope and can affect all the logical CPUs in
+ the system. Therefore, PCC is capable of performing "group" updates. With PCC
+ the OS is capable of getting/setting the frequency of all the logical CPUs in
+ the system with a single call to the BIOS.
+
+ 1.1.1 Get Average Frequency:
+ ----------------------------
+ This command is used by the OSPM to query the running frequency of the
+ processor since the last time this command was completed. The output buffer
+ indicates the average unhalted frequency of the logical processor expressed as
+ a percentage of the nominal (ie: maximum) CPU frequency. The output buffer
+ also signifies if the CPU frequency is limited by a power budget condition.
+
+ 1.1.2 Set Desired Frequency:
+ ----------------------------
+ This command is used by the OSPM to communicate to the platform firmware the
+ desired frequency for a logical processor. The output buffer is currently
+ ignored by OSPM. The next invocation of "Get Average Frequency" will inform
+ OSPM if the desired frequency was achieved or not.
+
+ 1.2 Platforms affected:
+ -----------------------
+ The PCC driver will load on any system where the platform firmware:
+ * supports the PCC interface, and the associated PCCH() and PCCP() methods
+ * assumes responsibility for managing the hardware clocking controls in order
+ to deliver the requested processor performance
+
+ Currently, certain HP ProLiant platforms implement the PCC interface. On those
+ platforms PCC is the "default" choice.
+
+ However, it is possible to disable this interface via a BIOS setting. In
+ such an instance, as is also the case on platforms where the PCC interface
+ is not implemented, the PCC driver will fail to load silently.
+
+ 2. Driver and /sys details:
+ ---------------------------
+ When the driver loads, it merely prints the lowest and the highest CPU
+ frequencies supported by the platform firmware.
+
+ The PCC driver loads with a message such as:
+ pcc-cpufreq: (v1.00.00) driver loaded with frequency limits: 1600 MHz, 2933
+ MHz
+
+ This means that the OPSM can request the CPU to run at any frequency in
+ between the limits (1600 MHz, and 2933 MHz) specified in the message.
+
+ Internally, there is no need for the driver to convert the "target" frequency
+ to a corresponding P-state.
+
+ The VERSION number for the driver will be of the format v.xy.ab.
+ eg: 1.00.02
+    ----- --
+     |    |
+     |    -- this will increase with bug fixes/enhancements to the driver
+     |-- this is the version of the PCC specification the driver adheres to
+
+
+ The following is a brief discussion on some of the fields exported via the
+ /sys filesystem and how their values are affected by the PCC driver:
+
+ 2.1 scaling_available_frequencies:
+ ----------------------------------
+ scaling_available_frequencies is not created in /sys. No intermediate
+ frequencies need to be listed because the BIOS will try to achieve any
+ frequency, within limits, requested by the governor. A frequency does not have
+ to be strictly associated with a P-state.
+
+ 2.2 cpuinfo_transition_latency:
+ -------------------------------
+ The cpuinfo_transition_latency field is 0. The PCC specification does
+ not include a field to expose this value currently.
+
+ 2.3 cpuinfo_cur_freq:
+ ---------------------
+ A) Often cpuinfo_cur_freq will show a value different than what is declared
+ in the scaling_available_frequencies or scaling_cur_freq, or scaling_max_freq.
+ This is due to "turbo boost" available on recent Intel processors. If certain
+ conditions are met the BIOS can achieve a slightly higher speed than requested
+ by OSPM. An example:
+
+ scaling_cur_freq      : 2933000
+ cpuinfo_cur_freq      : 3196000
+
+ B) There is a round-off error associated with the cpuinfo_cur_freq value.
+ Since the driver obtains the current frequency as a "percentage" (%) of the
+ nominal frequency from the BIOS, sometimes, the values displayed by
+ scaling_cur_freq and cpuinfo_cur_freq may not match. An example:
+
+ scaling_cur_freq      : 1600000
+ cpuinfo_cur_freq      : 1583000
+
+ In this example, the nominal frequency is 2933 MHz. The driver obtains the
+ current frequency, cpuinfo_cur_freq, as 54% of the nominal frequency:
+
+       54% of 2933 MHz = 1583 MHz
+
+ Nominal frequency is the maximum frequency of the processor, and it usually
+ corresponds to the frequency of the P0 P-state.
+
+ 2.4 related_cpus:
+ -----------------
+ The related_cpus field is identical to affected_cpus.
+
+ affected_cpus : 4
+ related_cpus  : 4
+
+ Currently, the PCC driver does not evaluate _PSD. The platforms that support
+ PCC do not implement SW_ALL. So OSPM doesn't need to perform any coordination
+ to ensure that the same frequency is requested of all dependent CPUs.
+
+ 3. Caveats:
+ -----------
+ The "cpufreq_stats" module in its present form cannot be loaded and
+ expected to work with the PCC driver. Since the "cpufreq_stats" module
+ provides information wrt each P-state, it is not applicable to the PCC driver.
index 6a06dc4..5605cc6 100644 (file)
@@ -583,20 +583,17 @@ Power Management Quality of Service for CPUs
 The power management quality of service (PM QoS) framework in the Linux kernel
 allows kernel code and user space processes to set constraints on various
 energy-efficiency features of the kernel to prevent performance from dropping
-below a required level.  The PM QoS constraints can be set globally, in
-predefined categories referred to as PM QoS classes, or against individual
-devices.
+below a required level.
 
 CPU idle time management can be affected by PM QoS in two ways, through the
-global constraint in the ``PM_QOS_CPU_DMA_LATENCY`` class and through the
-resume latency constraints for individual CPUs.  Kernel code (e.g. device
-drivers) can set both of them with the help of special internal interfaces
-provided by the PM QoS framework.  User space can modify the former by opening
-the :file:`cpu_dma_latency` special device file under :file:`/dev/` and writing
-a binary value (interpreted as a signed 32-bit integer) to it.  In turn, the
-resume latency constraint for a CPU can be modified by user space by writing a
-string (representing a signed 32-bit integer) to the
-:file:`power/pm_qos_resume_latency_us` file under
+global CPU latency limit and through the resume latency constraints for
+individual CPUs.  Kernel code (e.g. device drivers) can set both of them with
+the help of special internal interfaces provided by the PM QoS framework.  User
+space can modify the former by opening the :file:`cpu_dma_latency` special
+device file under :file:`/dev/` and writing a binary value (interpreted as a
+signed 32-bit integer) to it.  In turn, the resume latency constraint for a CPU
+can be modified from user space by writing a string (representing a signed
+32-bit integer) to the :file:`power/pm_qos_resume_latency_us` file under
 :file:`/sys/devices/system/cpu/cpu<N>/` in ``sysfs``, where the CPU number
 ``<N>`` is allocated at the system initialization time.  Negative values
 will be rejected in both cases and, also in both cases, the written integer
@@ -605,32 +602,34 @@ number will be interpreted as a requested PM QoS constraint in microseconds.
 The requested value is not automatically applied as a new constraint, however,
 as it may be less restrictive (greater in this particular case) than another
 constraint previously requested by someone else.  For this reason, the PM QoS
-framework maintains a list of requests that have been made so far in each
-global class and for each device, aggregates them and applies the effective
-(minimum in this particular case) value as the new constraint.
+framework maintains a list of requests that have been made so far for the
+global CPU latency limit and for each individual CPU, aggregates them and
+applies the effective (minimum in this particular case) value as the new
+constraint.
 
 In fact, opening the :file:`cpu_dma_latency` special device file causes a new
-PM QoS request to be created and added to the priority list of requests in the
-``PM_QOS_CPU_DMA_LATENCY`` class and the file descriptor coming from the
-"open" operation represents that request.  If that file descriptor is then
-used for writing, the number written to it will be associated with the PM QoS
-request represented by it as a new requested constraint value.  Next, the
-priority list mechanism will be used to determine the new effective value of
-the entire list of requests and that effective value will be set as a new
-constraint.  Thus setting a new requested constraint value will only change the
-real constraint if the effective "list" value is affected by it.  In particular,
-for the ``PM_QOS_CPU_DMA_LATENCY`` class it only affects the real constraint if
-it is the minimum of the requested constraints in the list.  The process holding
-a file descriptor obtained by opening the :file:`cpu_dma_latency` special device
-file controls the PM QoS request associated with that file descriptor, but it
-controls this particular PM QoS request only.
+PM QoS request to be created and added to a global priority list of CPU latency
+limit requests and the file descriptor coming from the "open" operation
+represents that request.  If that file descriptor is then used for writing, the
+number written to it will be associated with the PM QoS request represented by
+it as a new requested limit value.  Next, the priority list mechanism will be
+used to determine the new effective value of the entire list of requests and
+that effective value will be set as a new CPU latency limit.  Thus requesting a
+new limit value will only change the real limit if the effective "list" value is
+affected by it, which is the case if it is the minimum of the requested values
+in the list.
+
+The process holding a file descriptor obtained by opening the
+:file:`cpu_dma_latency` special device file controls the PM QoS request
+associated with that file descriptor, but it controls this particular PM QoS
+request only.
 
 Closing the :file:`cpu_dma_latency` special device file or, more precisely, the
 file descriptor obtained while opening it, causes the PM QoS request associated
-with that file descriptor to be removed from the ``PM_QOS_CPU_DMA_LATENCY``
-class priority list and destroyed.  If that happens, the priority list mechanism
-will be used, again, to determine the new effective value for the whole list
-and that value will become the new real constraint.
+with that file descriptor to be removed from the global priority list of CPU
+latency limit requests and destroyed.  If that happens, the priority list
+mechanism will be used again, to determine the new effective value for the whole
+list and that value will become the new limit.
 
 In turn, for each CPU there is one resume latency PM QoS request associated with
 the :file:`power/pm_qos_resume_latency_us` file under
@@ -647,10 +646,10 @@ CPU in question every time the list of requests is updated this way or another
 (there may be other requests coming from kernel code in that list).
 
 CPU idle time governors are expected to regard the minimum of the global
-effective ``PM_QOS_CPU_DMA_LATENCY`` class constraint and the effective
-resume latency constraint for the given CPU as the upper limit for the exit
-latency of the idle states they can select for that CPU.  They should never
-select any idle states with exit latency beyond that limit.
+(effective) CPU latency limit and the effective resume latency constraint for
+the given CPU as the upper limit for the exit latency of the idle states that
+they are allowed to select for that CPU.  They should never select any idle
+states with exit latency beyond that limit.
 
 
 Idle States Control Via Kernel Command Line
index 67e414e..ad392f3 100644 (file)
@@ -734,10 +734,10 @@ References
 ==========
 
 .. [1] Kristen Accardi, *Balancing Power and Performance in the Linux Kernel*,
-       http://events.linuxfoundation.org/sites/events/files/slides/LinuxConEurope_2015.pdf
+       https://events.static.linuxfound.org/sites/events/files/slides/LinuxConEurope_2015.pdf
 
 .. [2] *Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3: System Programming Guide*,
-       http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-system-programming-manual-325384.html
+       https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-system-programming-manual-325384.html
 
 .. [3] *Advanced Configuration and Power Interface Specification*,
        https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
index 88f717e..0a38cdf 100644 (file)
@@ -11,4 +11,5 @@ Working-State Power Management
    intel_idle
    cpufreq
    intel_pstate
+   cpufreq_drivers
    intel_epb
index def0748..335696d 100644 (file)
 Documentation for /proc/sys/kernel/
 ===================================
 
-kernel version 2.2.10
+.. See scripts/check-sysctl-docs to keep this up to date
+
 
 Copyright (c) 1998, 1999,  Rik van Riel <riel@nl.linux.org>
 
 Copyright (c) 2009,        Shen Feng<shen@cn.fujitsu.com>
 
-For general info and legal blurb, please look in index.rst.
+For general info and legal blurb, please look in :doc:`index`.
 
 ------------------------------------------------------------------------------
 
 This file contains documentation for the sysctl files in
-/proc/sys/kernel/ and is valid for Linux kernel version 2.2.
+``/proc/sys/kernel/`` and is valid for Linux kernel version 2.2.
 
 The files in this directory can be used to tune and monitor
 miscellaneous and general things in the operation of the Linux
-kernel. Since some of the files _can_ be used to screw up your
+kernel. Since some of the files *can* be used to screw up your
 system, it is advisable to read both documentation and source
 before actually making adjustments.
 
 Currently, these files might (depending on your configuration)
-show up in /proc/sys/kernel:
-
-- acct
-- acpi_video_flags
-- auto_msgmni
-- bootloader_type           [ X86 only ]
-- bootloader_version        [ X86 only ]
-- cap_last_cap
-- core_pattern
-- core_pipe_limit
-- core_uses_pid
-- ctrl-alt-del
-- dmesg_restrict
-- domainname
-- hostname
-- hotplug
-- hardlockup_all_cpu_backtrace
-- hardlockup_panic
-- hung_task_panic
-- hung_task_check_count
-- hung_task_timeout_secs
-- hung_task_check_interval_secs
-- hung_task_warnings
-- hyperv_record_panic_msg
-- kexec_load_disabled
-- kptr_restrict
-- l2cr                        [ PPC only ]
-- modprobe                    ==> Documentation/debugging-modules.txt
-- modules_disabled
-- msg_next_id                [ sysv ipc ]
-- msgmax
-- msgmnb
-- msgmni
-- nmi_watchdog
-- osrelease
-- ostype
-- overflowgid
-- overflowuid
-- panic
-- panic_on_oops
-- panic_on_stackoverflow
-- panic_on_unrecovered_nmi
-- panic_on_warn
-- panic_print
-- panic_on_rcu_stall
-- perf_cpu_time_max_percent
-- perf_event_paranoid
-- perf_event_max_stack
-- perf_event_mlock_kb
-- perf_event_max_contexts_per_stack
-- pid_max
-- powersave-nap               [ PPC only ]
-- printk
-- printk_delay
-- printk_ratelimit
-- printk_ratelimit_burst
-- pty                         ==> Documentation/filesystems/devpts.txt
-- randomize_va_space
-- real-root-dev               ==> Documentation/admin-guide/initrd.rst
-- reboot-cmd                  [ SPARC only ]
-- rtsig-max
-- rtsig-nr
-- sched_energy_aware
-- seccomp/                    ==> Documentation/userspace-api/seccomp_filter.rst
-- sem
-- sem_next_id                [ sysv ipc ]
-- sg-big-buff                 [ generic SCSI device (sg) ]
-- shm_next_id                [ sysv ipc ]
-- shm_rmid_forced
-- shmall
-- shmmax                      [ sysv ipc ]
-- shmmni
-- softlockup_all_cpu_backtrace
-- soft_watchdog
-- stack_erasing
-- stop-a                      [ SPARC only ]
-- sysrq                       ==> Documentation/admin-guide/sysrq.rst
-- sysctl_writes_strict
-- tainted                     ==> Documentation/admin-guide/tainted-kernels.rst
-- threads-max
-- unknown_nmi_panic
-- watchdog
-- watchdog_thresh
-- version
-
-
-acct:
-=====
+show up in ``/proc/sys/kernel``:
+
+.. contents:: :local:
+
+
+acct
+====
+
+::
 
-highwater lowwater frequency
+    highwater lowwater frequency
 
 If BSD-style process accounting is enabled these values control
 its behaviour. If free space on filesystem where the log lives
-goes below <lowwater>% accounting suspends. If free space gets
-above <highwater>% accounting resumes. <Frequency> determines
+goes below ``lowwater``% accounting suspends. If free space gets
+above ``highwater``% accounting resumes. ``frequency`` determines
 how often do we check the amount of free space (value is in
 seconds). Default:
-4 2 30
-That is, suspend accounting if there left <= 2% free; resume it
-if we got >=4%; consider information about amount of free space
-valid for 30 seconds.
 
+::
 
-acpi_video_flags:
-=================
+    4 2 30
+
+That is, suspend accounting if free space drops below 2%; resume it
+if it increases to at least 4%; consider information about amount of
+free space valid for 30 seconds.
 
-flags
 
-See Doc*/kernel/power/video.txt, it allows mode of video boot to be
-set during run time.
+acpi_video_flags
+================
 
+See :doc:`/power/video`. This allows the video resume mode to be set,
+in a similar fashion to the ``acpi_sleep`` kernel parameter, by
+combining the following values:
+
+= =======
+1 s3_bios
+2 s3_mode
+4 s3_beep
+= =======
 
-auto_msgmni:
-============
+
+auto_msgmni
+===========
 
 This variable has no effect and may be removed in future kernel
 releases. Reading it always returns 0.
-Up to Linux 3.17, it enabled/disabled automatic recomputing of msgmni
-upon memory add/remove or upon ipc namespace creation/removal.
+Up to Linux 3.17, it enabled/disabled automatic recomputing of
+`msgmni`_
+upon memory add/remove or upon IPC namespace creation/removal.
 Echoing "1" into this file enabled msgmni automatic recomputing.
-Echoing "0" turned it off. auto_msgmni default value was 1.
-
+Echoing "0" turned it off. The default value was 1.
 
-bootloader_type:
-================
 
-x86 bootloader identification
+bootloader_type (x86 only)
+==========================
 
 This gives the bootloader type number as indicated by the bootloader,
 shifted left by 4, and OR'd with the low four bits of the bootloader
 version.  The reason for this encoding is that this used to match the
-type_of_loader field in the kernel header; the encoding is kept for
+``type_of_loader`` field in the kernel header; the encoding is kept for
 backwards compatibility.  That is, if the full bootloader type number
 is 0x15 and the full version number is 0x234, this file will contain
 the value 340 = 0x154.
 
-See the type_of_loader and ext_loader_type fields in
-Documentation/x86/boot.rst for additional information.
-
+See the ``type_of_loader`` and ``ext_loader_type`` fields in
+:doc:`/x86/boot` for additional information.
 
-bootloader_version:
-===================
 
-x86 bootloader version
+bootloader_version (x86 only)
+=============================
 
 The complete bootloader version number.  In the example above, this
 file will contain the value 564 = 0x234.
 
-See the type_of_loader and ext_loader_ver fields in
-Documentation/x86/boot.rst for additional information.
+See the ``type_of_loader`` and ``ext_loader_ver`` fields in
+:doc:`/x86/boot` for additional information.
 
 
-cap_last_cap:
-=============
+cap_last_cap
+============
 
 Highest valid capability of the running kernel.  Exports
-CAP_LAST_CAP from the kernel.
+``CAP_LAST_CAP`` from the kernel.
 
 
-core_pattern:
-=============
+core_pattern
+============
 
-core_pattern is used to specify a core dumpfile pattern name.
+``core_pattern`` is used to specify a core dumpfile pattern name.
 
 * max length 127 characters; default value is "core"
-* core_pattern is used as a pattern template for the output filename;
-  certain string patterns (beginning with '%') are substituted with
-  their actual values.
-* backward compatibility with core_uses_pid:
+* ``core_pattern`` is used as a pattern template for the output
+  filename; certain string patterns (beginning with '%') are
+  substituted with their actual values.
+* backward compatibility with ``core_uses_pid``:
 
-       If core_pattern does not include "%p" (default does not)
-       and core_uses_pid is set, then .PID will be appended to
+       If ``core_pattern`` does not include "%p" (default does not)
+       and ``core_uses_pid`` is set, then .PID will be appended to
        the filename.
 
-* corename format specifiers::
-
-       %<NUL>  '%' is dropped
-       %%      output one '%'
-       %p      pid
-       %P      global pid (init PID namespace)
-       %i      tid
-       %I      global tid (init PID namespace)
-       %u      uid (in initial user namespace)
-       %g      gid (in initial user namespace)
-       %d      dump mode, matches PR_SET_DUMPABLE and
-               /proc/sys/fs/suid_dumpable
-       %s      signal number
-       %t      UNIX time of dump
-       %h      hostname
-       %e      executable filename (may be shortened)
-       %E      executable path
-       %<OTHER> both are dropped
+* corename format specifiers
+
+       ========        ==========================================
+       %<NUL>          '%' is dropped
+       %%              output one '%'
+       %p              pid
+       %P              global pid (init PID namespace)
+       %i              tid
+       %I              global tid (init PID namespace)
+       %u              uid (in initial user namespace)
+       %g              gid (in initial user namespace)
+       %d              dump mode, matches ``PR_SET_DUMPABLE`` and
+                       ``/proc/sys/fs/suid_dumpable``
+       %s              signal number
+       %t              UNIX time of dump
+       %h              hostname
+       %e              executable filename (may be shortened)
+       %E              executable path
+       %c              maximum size of core file by resource limit RLIMIT_CORE
+       %<OTHER>        both are dropped
+       ========        ==========================================
 
 * If the first character of the pattern is a '|', the kernel will treat
   the rest of the pattern as a command to run.  The core dump will be
   written to the standard input of that program instead of to a file.
 
 
-core_pipe_limit:
-================
+core_pipe_limit
+===============
 
-This sysctl is only applicable when core_pattern is configured to pipe
-core files to a user space helper (when the first character of
-core_pattern is a '|', see above).  When collecting cores via a pipe
-to an application, it is occasionally useful for the collecting
-application to gather data about the crashing process from its
-/proc/pid directory.  In order to do this safely, the kernel must wait
-for the collecting process to exit, so as not to remove the crashing
-processes proc files prematurely.  This in turn creates the
-possibility that a misbehaving userspace collecting process can block
-the reaping of a crashed process simply by never exiting.  This sysctl
-defends against that.  It defines how many concurrent crashing
-processes may be piped to user space applications in parallel.  If
-this value is exceeded, then those crashing processes above that value
-are noted via the kernel log and their cores are skipped.  0 is a
-special value, indicating that unlimited processes may be captured in
-parallel, but that no waiting will take place (i.e. the collecting
-process is not guaranteed access to /proc/<crashing pid>/).  This
-value defaults to 0.
-
-
-core_uses_pid:
-==============
+This sysctl is only applicable when `core_pattern`_ is configured to
+pipe core files to a user space helper (when the first character of
+``core_pattern`` is a '|', see above).
+When collecting cores via a pipe to an application, it is occasionally
+useful for the collecting application to gather data about the
+crashing process from its ``/proc/pid`` directory.
+In order to do this safely, the kernel must wait for the collecting
+process to exit, so as not to remove the crashing processes proc files
+prematurely.
+This in turn creates the possibility that a misbehaving userspace
+collecting process can block the reaping of a crashed process simply
+by never exiting.
+This sysctl defends against that.
+It defines how many concurrent crashing processes may be piped to user
+space applications in parallel.
+If this value is exceeded, then those crashing processes above that
+value are noted via the kernel log and their cores are skipped.
+0 is a special value, indicating that unlimited processes may be
+captured in parallel, but that no waiting will take place (i.e. the
+collecting process is not guaranteed access to ``/proc/<crashing
+pid>/``).
+This value defaults to 0.
+
+
+core_uses_pid
+=============
 
 The default coredump filename is "core".  By setting
-core_uses_pid to 1, the coredump filename becomes core.PID.
-If core_pattern does not include "%p" (default does not)
-and core_uses_pid is set, then .PID will be appended to
+``core_uses_pid`` to 1, the coredump filename becomes core.PID.
+If `core_pattern`_ does not include "%p" (default does not)
+and ``core_uses_pid`` is set, then .PID will be appended to
 the filename.
 
 
-ctrl-alt-del:
-=============
+ctrl-alt-del
+============
 
 When the value in this file is 0, ctrl-alt-del is trapped and
-sent to the init(1) program to handle a graceful restart.
+sent to the ``init(1)`` program to handle a graceful restart.
 When, however, the value is > 0, Linux's reaction to a Vulcan
 Nerve Pinch (tm) will be an immediate reboot, without even
 syncing its dirty buffers.
@@ -269,21 +204,22 @@ Note:
   to decide what to do with it.
 
 
-dmesg_restrict:
-===============
+dmesg_restrict
+==============
 
 This toggle indicates whether unprivileged users are prevented
-from using dmesg(8) to view messages from the kernel's log buffer.
-When dmesg_restrict is set to (0) there are no restrictions. When
-dmesg_restrict is set set to (1), users must have CAP_SYSLOG to use
-dmesg(8).
+from using ``dmesg(8)`` to view messages from the kernel's log
+buffer.
+When ``dmesg_restrict`` is set to 0 there are no restrictions.
+When ``dmesg_restrict`` is set set to 1, users must have
+``CAP_SYSLOG`` to use ``dmesg(8)``.
 
-The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the
-default value of dmesg_restrict.
+The kernel config option ``CONFIG_SECURITY_DMESG_RESTRICT`` sets the
+default value of ``dmesg_restrict``.
 
 
-domainname & hostname:
-======================
+domainname & hostname
+=====================
 
 These files can be used to set the NIS/YP domainname and the
 hostname of your box in exactly the same way as the commands
@@ -302,167 +238,206 @@ hostname "darkstar" and DNS (Internet Domain Name Server)
 domainname "frop.org", not to be confused with the NIS (Network
 Information Service) or YP (Yellow Pages) domainname. These two
 domain names are in general different. For a detailed discussion
-see the hostname(1) man page.
+see the ``hostname(1)`` man page.
 
 
-hardlockup_all_cpu_backtrace:
-=============================
+hardlockup_all_cpu_backtrace
+============================
 
 This value controls the hard lockup detector behavior when a hard
 lockup condition is detected as to whether or not to gather further
 debug information. If enabled, arch-specific all-CPU stack dumping
 will be initiated.
 
-0: do nothing. This is the default behavior.
-
-1: on detection capture more debug information.
+= ============================================
+0 Do nothing. This is the default behavior.
+1 On detection capture more debug information.
+= ============================================
 
 
-hardlockup_panic:
-=================
+hardlockup_panic
+================
 
 This parameter can be used to control whether the kernel panics
 when a hard lockup is detected.
 
-   0 - don't panic on hard lockup
-   1 - panic on hard lockup
+= ===========================
+0 Don't panic on hard lockup.
+1 Panic on hard lockup.
+= ===========================
 
-See Documentation/admin-guide/lockup-watchdogs.rst for more information.  This can
-also be set using the nmi_watchdog kernel parameter.
+See :doc:`/admin-guide/lockup-watchdogs` for more information.
+This can also be set using the nmi_watchdog kernel parameter.
 
 
-hotplug:
-========
+hotplug
+=======
 
 Path for the hotplug policy agent.
-Default value is "/sbin/hotplug".
+Default value is "``/sbin/hotplug``".
 
 
-hung_task_panic:
-================
+hung_task_panic
+===============
 
 Controls the kernel's behavior when a hung task is detected.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
-
-0: continue operation. This is the default behavior.
+This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.
 
-1: panic immediately.
+= =================================================
+0 Continue operation. This is the default behavior.
+1 Panic immediately.
+= =================================================
 
 
-hung_task_check_count:
-======================
+hung_task_check_count
+=====================
 
 The upper bound on the number of tasks that are checked.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.
 
 
-hung_task_timeout_secs:
-=======================
+hung_task_timeout_secs
+======================
 
 When a task in D state did not get scheduled
 for more than this value report a warning.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.
 
-0: means infinite timeout - no checking done.
+0 means infinite timeout, no checking is done.
 
-Possible values to set are in range {0..LONG_MAX/HZ}.
+Possible values to set are in range {0:``LONG_MAX``/``HZ``}.
 
 
-hung_task_check_interval_secs:
-==============================
+hung_task_check_interval_secs
+=============================
 
 Hung task check interval. If hung task checking is enabled
-(see hung_task_timeout_secs), the check is done every
-hung_task_check_interval_secs seconds.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+(see `hung_task_timeout_secs`_), the check is done every
+``hung_task_check_interval_secs`` seconds.
+This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.
 
-0 (default): means use hung_task_timeout_secs as checking interval.
-Possible values to set are in range {0..LONG_MAX/HZ}.
+0 (default) means use ``hung_task_timeout_secs`` as checking
+interval.
 
+Possible values to set are in range {0:``LONG_MAX``/``HZ``}.
 
-hung_task_warnings:
-===================
+
+hung_task_warnings
+==================
 
 The maximum number of warnings to report. During a check interval
 if a hung task is detected, this value is decreased by 1.
 When this value reaches 0, no more warnings will be reported.
-This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+This file shows up if ``CONFIG_DETECT_HUNG_TASK`` is enabled.
 
 -1: report an infinite number of warnings.
 
 
-hyperv_record_panic_msg:
-========================
+hyperv_record_panic_msg
+=======================
 
 Controls whether the panic kmsg data should be reported to Hyper-V.
 
-0: do not report panic kmsg data.
+= =========================================================
+0 Do not report panic kmsg data.
+1 Report the panic kmsg data. This is the default behavior.
+= =========================================================
 
-1: report the panic kmsg data. This is the default behavior.
 
+kexec_load_disabled
+===================
 
-kexec_load_disabled:
-====================
-
-A toggle indicating if the kexec_load syscall has been disabled. This
-value defaults to 0 (false: kexec_load enabled), but can be set to 1
-(true: kexec_load disabled). Once true, kexec can no longer be used, and
-the toggle cannot be set back to false. This allows a kexec image to be
-loaded before disabling the syscall, allowing a system to set up (and
-later use) an image without it being altered. Generally used together
-with the "modules_disabled" sysctl.
+A toggle indicating if the ``kexec_load`` syscall has been disabled.
+This value defaults to 0 (false: ``kexec_load`` enabled), but can be
+set to 1 (true: ``kexec_load`` disabled).
+Once true, kexec can no longer be used, and the toggle cannot be set
+back to false.
+This allows a kexec image to be loaded before disabling the syscall,
+allowing a system to set up (and later use) an image without it being
+altered.
+Generally used together with the `modules_disabled`_ sysctl.
 
 
-kptr_restrict:
-==============
+kptr_restrict
+=============
 
 This toggle indicates whether restrictions are placed on
-exposing kernel addresses via /proc and other interfaces.
+exposing kernel addresses via ``/proc`` and other interfaces.
+
+When ``kptr_restrict`` is set to 0 (the default) the address is hashed
+before printing.
+(This is the equivalent to %p.)
+
+When ``kptr_restrict`` is set to 1, kernel pointers printed using the
+%pK format specifier will be replaced with 0s unless the user has
+``CAP_SYSLOG`` and effective user and group ids are equal to the real
+ids.
+This is because %pK checks are done at read() time rather than open()
+time, so if permissions are elevated between the open() and the read()
+(e.g via a setuid binary) then %pK will not leak kernel pointers to
+unprivileged users.
+Note, this is a temporary solution only.
+The correct long-term solution is to do the permission checks at
+open() time.
+Consider removing world read permissions from files that use %pK, and
+using `dmesg_restrict`_ to protect against uses of %pK in ``dmesg(8)``
+if leaking kernel pointer values to unprivileged users is a concern.
+
+When ``kptr_restrict`` is set to 2, kernel pointers printed using
+%pK will be replaced with 0s regardless of privileges.
+
+
+modprobe
+========
 
-When kptr_restrict is set to 0 (the default) the address is hashed before
-printing. (This is the equivalent to %p.)
+This gives the full path of the modprobe command which the kernel will
+use to load modules. This can be used to debug module loading
+requests::
 
-When kptr_restrict is set to (1), kernel pointers printed using the %pK
-format specifier will be replaced with 0's unless the user has CAP_SYSLOG
-and effective user and group ids are equal to the real ids. This is
-because %pK checks are done at read() time rather than open() time, so
-if permissions are elevated between the open() and the read() (e.g via
-a setuid binary) then %pK will not leak kernel pointers to unprivileged
-users. Note, this is a temporary solution only. The correct long-term
-solution is to do the permission checks at open() time. Consider removing
-world read permissions from files that use %pK, and using dmesg_restrict
-to protect against uses of %pK in dmesg(8) if leaking kernel pointer
-values to unprivileged users is a concern.
+    echo '#! /bin/sh' > /tmp/modprobe
+    echo 'echo "$@" >> /tmp/modprobe.log' >> /tmp/modprobe
+    echo 'exec /sbin/modprobe "$@"' >> /tmp/modprobe
+    chmod a+x /tmp/modprobe
+    echo /tmp/modprobe > /proc/sys/kernel/modprobe
 
-When kptr_restrict is set to (2), kernel pointers printed using
-%pK will be replaced with 0's regardless of privileges.
+This only applies when the *kernel* is requesting that the module be
+loaded; it won't have any effect if the module is being loaded
+explicitly using ``modprobe`` from userspace.
 
 
-l2cr: (PPC only)
+modules_disabled
 ================
 
-This flag controls the L2 cache of G3 processor boards. If
-0, the cache is disabled. Enabled if nonzero.
-
-
-modules_disabled:
-=================
-
 A toggle value indicating if modules are allowed to be loaded
 in an otherwise modular kernel.  This toggle defaults to off
 (0), but can be set true (1).  Once true, modules can be
 neither loaded nor unloaded, and the toggle cannot be set back
-to false.  Generally used with the "kexec_load_disabled" toggle.
+to false.  Generally used with the `kexec_load_disabled`_ toggle.
+
+
+.. _msgmni:
+
+msgmax, msgmnb, and msgmni
+==========================
+
+``msgmax`` is the maximum size of an IPC message, in bytes. 8192 by
+default (``MSGMAX``).
 
+``msgmnb`` is the maximum size of an IPC queue, in bytes. 16384 by
+default (``MSGMNB``).
 
-msg_next_id, sem_next_id, and shm_next_id:
-==========================================
+``msgmni`` is the maximum number of IPC queues. 32000 by default
+(``MSGMNI``).
+
+
+msg_next_id, sem_next_id, and shm_next_id (System V IPC)
+========================================================
 
 These three toggles allows to specify desired id for next allocated IPC
 object: message, semaphore or shared memory respectively.
 
 By default they are equal to -1, which means generic allocation logic.
-Possible values to set are in range {0..INT_MAX}.
+Possible values to set are in range {0:``INT_MAX``}.
 
 Notes:
   1) kernel doesn't guarantee, that new object will have desired id. So,
@@ -472,15 +447,16 @@ Notes:
      fails, it is undefined if the value remains unmodified or is reset to -1.
 
 
-nmi_watchdog:
-=============
+nmi_watchdog
+============
 
 This parameter can be used to control the NMI watchdog
 (i.e. the hard lockup detector) on x86 systems.
 
-0 - disable the hard lockup detector
-
-1 - enable the hard lockup detector
+= =================================
+0 Disable the hard lockup detector.
+1 Enable the hard lockup detector.
+= =================================
 
 The hard lockup detector monitors each CPU for its ability to respond to
 timer interrupts. The mechanism utilizes CPU performance counter registers
@@ -492,11 +468,11 @@ in a KVM virtual machine. This default can be overridden by adding::
 
    nmi_watchdog=1
 
-to the guest kernel command line (see Documentation/admin-guide/kernel-parameters.rst).
+to the guest kernel command line (see :doc:`/admin-guide/kernel-parameters`).
 
 
-numa_balancing:
-===============
+numa_balancing
+==============
 
 Enables/disables automatic page fault based NUMA memory
 balancing. Memory is moved automatically to nodes
@@ -514,9 +490,10 @@ ideally is offset by improved memory locality but there is no universal
 guarantee. If the target workload is already bound to NUMA nodes then this
 feature should be disabled. Otherwise, if the system overhead from the
 feature is too high then the rate the kernel samples for NUMA hinting
-faults may be controlled by the numa_balancing_scan_period_min_ms,
+faults may be controlled by the `numa_balancing_scan_period_min_ms,
 numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms,
-numa_balancing_scan_size_mb, and numa_balancing_settle_count sysctls.
+numa_balancing_scan_size_mb`_, and numa_balancing_settle_count sysctls.
+
 
 numa_balancing_scan_period_min_ms, numa_balancing_scan_delay_ms, numa_balancing_scan_period_max_ms, numa_balancing_scan_size_mb
 ===============================================================================================================================
@@ -542,23 +519,23 @@ workload pattern changes and minimises performance impact due to remote
 memory accesses. These sysctls control the thresholds for scan delays and
 the number of pages scanned.
 
-numa_balancing_scan_period_min_ms is the minimum time in milliseconds to
+``numa_balancing_scan_period_min_ms`` is the minimum time in milliseconds to
 scan a tasks virtual memory. It effectively controls the maximum scanning
 rate for each task.
 
-numa_balancing_scan_delay_ms is the starting "scan delay" used for a task
+``numa_balancing_scan_delay_ms`` is the starting "scan delay" used for a task
 when it initially forks.
 
-numa_balancing_scan_period_max_ms is the maximum time in milliseconds to
+``numa_balancing_scan_period_max_ms`` is the maximum time in milliseconds to
 scan a tasks virtual memory. It effectively controls the minimum scanning
 rate for each task.
 
-numa_balancing_scan_size_mb is how many megabytes worth of pages are
+``numa_balancing_scan_size_mb`` is how many megabytes worth of pages are
 scanned for a given scan.
 
 
-osrelease, ostype & version:
-============================
+osrelease, ostype & version
+===========================
 
 ::
 
@@ -569,15 +546,16 @@ osrelease, ostype & version:
   # cat version
   #5 Wed Feb 25 21:49:24 MET 1998
 
-The files osrelease and ostype should be clear enough. Version
+The files ``osrelease`` and ``ostype`` should be clear enough.
+``version``
 needs a little more clarification however. The '#5' means that
 this is the fifth kernel built from this source base and the
 date behind it indicates the time the kernel was built.
 The only way to tune these values is to rebuild the kernel :-)
 
 
-overflowgid & overflowuid:
-==========================
+overflowgid & overflowuid
+=========================
 
 if your architecture did not always support 32-bit UIDs (i.e. arm,
 i386, m68k, sh, and sparc32), a fixed UID and GID will be returned to
@@ -588,108 +566,119 @@ These sysctls allow you to change the value of the fixed UID and GID.
 The default is 65534.
 
 
+panic
+=====
+
+The value in this file determines the behaviour of the kernel on a
 panic:
-======
 
-The value in this file represents the number of seconds the kernel
-waits before rebooting on a panic. When you use the software watchdog,
-the recommended setting is 60.
+* if zero, the kernel will loop forever;
+* if negative, the kernel will reboot immediately;
+* if positive, the kernel will reboot after the corresponding number
+  of seconds.
 
+When you use the software watchdog, the recommended setting is 60.
 
-panic_on_io_nmi:
-================
+
+panic_on_io_nmi
+===============
 
 Controls the kernel's behavior when a CPU receives an NMI caused by
 an IO error.
 
-0: try to continue operation (default)
-
-1: panic immediately. The IO error triggered an NMI. This indicates a
-   serious system condition which could result in IO data corruption.
-   Rather than continuing, panicking might be a better choice. Some
-   servers issue this sort of NMI when the dump button is pushed,
-   and you can use this option to take a crash dump.
+= ==================================================================
+0 Try to continue operation (default).
+1 Panic immediately. The IO error triggered an NMI. This indicates a
+  serious system condition which could result in IO data corruption.
+  Rather than continuing, panicking might be a better choice. Some
+  servers issue this sort of NMI when the dump button is pushed,
+  and you can use this option to take a crash dump.
+= ==================================================================
 
 
-panic_on_oops:
-==============
+panic_on_oops
+=============
 
 Controls the kernel's behaviour when an oops or BUG is encountered.
 
-0: try to continue operation
-
-1: panic immediately.  If the `panic` sysctl is also non-zero then the
-   machine will be rebooted.
+= ===================================================================
+0 Try to continue operation.
+1 Panic immediately.  If the `panic` sysctl is also non-zero then the
+  machine will be rebooted.
+= ===================================================================
 
 
-panic_on_stackoverflow:
-=======================
+panic_on_stackoverflow
+======================
 
 Controls the kernel's behavior when detecting the overflows of
 kernel, IRQ and exception stacks except a user stack.
-This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled.
-
-0: try to continue operation.
+This file shows up if ``CONFIG_DEBUG_STACKOVERFLOW`` is enabled.
 
-1: panic immediately.
+= ==========================
+0 Try to continue operation.
+1 Panic immediately.
+= ==========================
 
 
-panic_on_unrecovered_nmi:
-=========================
+panic_on_unrecovered_nmi
+========================
 
 The default Linux behaviour on an NMI of either memory or unknown is
 to continue operation. For many environments such as scientific
 computing it is preferable that the box is taken out and the error
 dealt with than an uncorrected parity/ECC error get propagated.
 
-A small number of systems do generate NMI's for bizarre random reasons
+A small number of systems do generate NMIs for bizarre random reasons
 such as power management so the default is off. That sysctl works like
 the existing panic controls already in that directory.
 
 
-panic_on_warn:
-==============
+panic_on_warn
+=============
 
 Calls panic() in the WARN() path when set to 1.  This is useful to avoid
 a kernel rebuild when attempting to kdump at the location of a WARN().
 
-0: only WARN(), default behaviour.
-
-1: call panic() after printing out WARN() location.
+= ================================================
+0 Only WARN(), default behaviour.
+1 Call panic() after printing out WARN() location.
+= ================================================
 
 
-panic_print:
-============
+panic_print
+===========
 
 Bitmask for printing system info when panic happens. User can chose
 combination of the following bits:
 
-=====  ========================================
+=====  ============================================
 bit 0  print all tasks info
 bit 1  print system memory info
 bit 2  print timer info
-bit 3  print locks info if CONFIG_LOCKDEP is on
+bit 3  print locks info if ``CONFIG_LOCKDEP`` is on
 bit 4  print ftrace buffer
-=====  ========================================
+=====  ============================================
 
 So for example to print tasks and memory info on panic, user can::
 
   echo 3 > /proc/sys/kernel/panic_print
 
 
-panic_on_rcu_stall:
-===================
+panic_on_rcu_stall
+==================
 
 When set to 1, calls panic() after RCU stall detection messages. This
 is useful to define the root cause of RCU stalls using a vmcore.
 
-0: do not panic() when RCU stall takes place, default behavior.
+= ============================================================
+0 Do not panic() when RCU stall takes place, default behavior.
+1 panic() after printing RCU stall messages.
+= ============================================================
 
-1: panic() after printing RCU stall messages.
 
-
-perf_cpu_time_max_percent:
-==========================
+perf_cpu_time_max_percent
+=========================
 
 Hints to the kernel how much CPU time it should be allowed to
 use to handle perf sampling events.  If the perf subsystem
@@ -702,171 +691,179 @@ unexpectedly take too long to execute, the NMIs can become
 stacked up next to each other so much that nothing else is
 allowed to execute.
 
-0:
-   disable the mechanism.  Do not monitor or correct perf's
-   sampling rate no matter how CPU time it takes.
+===== ========================================================
+0     Disable the mechanism.  Do not monitor or correct perf's
+      sampling rate no matter how CPU time it takes.
 
-1-100:
-   attempt to throttle perf's sample rate to this
-   percentage of CPU.  Note: the kernel calculates an
-   "expected" length of each sample event.  100 here means
-   100% of that expected length.  Even if this is set to
-   100, you may still see sample throttling if this
-   length is exceeded.  Set to 0 if you truly do not care
-   how much CPU is consumed.
+1-100 Attempt to throttle perf's sample rate to this
+      percentage of CPU.  Note: the kernel calculates an
+      "expected" length of each sample event.  100 here means
+      100% of that expected length.  Even if this is set to
+      100, you may still see sample throttling if this
+      length is exceeded.  Set to 0 if you truly do not care
+      how much CPU is consumed.
+===== ========================================================
 
 
-perf_event_paranoid:
-====================
+perf_event_paranoid
+===================
 
 Controls use of the performance events system by unprivileged
 users (without CAP_SYS_ADMIN).  The default value is 2.
 
 ===  ==================================================================
- -1  Allow use of (almost) all events by all users
+ -1  Allow use of (almost) all events by all users.
 
-     Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
+     Ignore mlock limit after perf_event_mlock_kb without
+     ``CAP_IPC_LOCK``.
 
->=0  Disallow ftrace function tracepoint by users without CAP_SYS_ADMIN
+>=0  Disallow ftrace function tracepoint by users without
+     ``CAP_SYS_ADMIN``.
 
-     Disallow raw tracepoint access by users without CAP_SYS_ADMIN
+     Disallow raw tracepoint access by users without ``CAP_SYS_ADMIN``.
 
->=1  Disallow CPU event access by users without CAP_SYS_ADMIN
+>=1  Disallow CPU event access by users without ``CAP_SYS_ADMIN``.
 
->=2  Disallow kernel profiling by users without CAP_SYS_ADMIN
+>=2  Disallow kernel profiling by users without ``CAP_SYS_ADMIN``.
 ===  ==================================================================
 
 
-perf_event_max_stack:
-=====================
+perf_event_max_stack
+====================
 
-Controls maximum number of stack frames to copy for (attr.sample_type &
-PERF_SAMPLE_CALLCHAIN) configured events, for instance, when using
-'perf record -g' or 'perf trace --call-graph fp'.
+Controls maximum number of stack frames to copy for (``attr.sample_type &
+PERF_SAMPLE_CALLCHAIN``) configured events, for instance, when using
+'``perf record -g``' or '``perf trace --call-graph fp``'.
 
 This can only be done when no events are in use that have callchains
-enabled, otherwise writing to this file will return -EBUSY.
+enabled, otherwise writing to this file will return ``-EBUSY``.
 
 The default value is 127.
 
 
-perf_event_mlock_kb:
-====================
+perf_event_mlock_kb
+===================
 
 Control size of per-cpu ring buffer not counted agains mlock limit.
 
 The default value is 512 + 1 page
 
 
-perf_event_max_contexts_per_stack:
-==================================
+perf_event_max_contexts_per_stack
+=================================
 
 Controls maximum number of stack frame context entries for
-(attr.sample_type & PERF_SAMPLE_CALLCHAIN) configured events, for
-instance, when using 'perf record -g' or 'perf trace --call-graph fp'.
+(``attr.sample_type & PERF_SAMPLE_CALLCHAIN``) configured events, for
+instance, when using '``perf record -g``' or '``perf trace --call-graph fp``'.
 
 This can only be done when no events are in use that have callchains
-enabled, otherwise writing to this file will return -EBUSY.
+enabled, otherwise writing to this file will return ``-EBUSY``.
 
 The default value is 8.
 
 
-pid_max:
-========
+pid_max
+=======
 
 PID allocation wrap value.  When the kernel's next PID value
 reaches this value, it wraps back to a minimum PID value.
-PIDs of value pid_max or larger are not allocated.
+PIDs of value ``pid_max`` or larger are not allocated.
 
 
-ns_last_pid:
-============
+ns_last_pid
+===========
 
 The last pid allocated in the current (the one task using this sysctl
 lives in) pid namespace. When selecting a pid for a next task on fork
 kernel tries to allocate a number starting from this one.
 
 
-powersave-nap: (PPC only)
-=========================
+powersave-nap (PPC only)
+========================
 
 If set, Linux-PPC will use the 'nap' mode of powersaving,
 otherwise the 'doze' mode will be used.
 
+
 ==============================================================
 
-printk:
-=======
+printk
+======
 
-The four values in printk denote: console_loglevel,
-default_message_loglevel, minimum_console_loglevel and
-default_console_loglevel respectively.
+The four values in printk denote: ``console_loglevel``,
+``default_message_loglevel``, ``minimum_console_loglevel`` and
+``default_console_loglevel`` respectively.
 
 These values influence printk() behavior when printing or
-logging error messages. See 'man 2 syslog' for more info on
+logging error messages. See '``man 2 syslog``' for more info on
 the different loglevels.
 
-- console_loglevel:
-       messages with a higher priority than
-       this will be printed to the console
-- default_message_loglevel:
-       messages without an explicit priority
-       will be printed with this priority
-- minimum_console_loglevel:
-       minimum (highest) value to which
-       console_loglevel can be set
-- default_console_loglevel:
-       default value for console_loglevel
+======================== =====================================
+console_loglevel         messages with a higher priority than
+                         this will be printed to the console
+default_message_loglevel messages without an explicit priority
+                         will be printed with this priority
+minimum_console_loglevel minimum (highest) value to which
+                         console_loglevel can be set
+default_console_loglevel default value for console_loglevel
+======================== =====================================
 
 
-printk_delay:
-=============
+printk_delay
+============
 
-Delay each printk message in printk_delay milliseconds
+Delay each printk message in ``printk_delay`` milliseconds
 
 Value from 0 - 10000 is allowed.
 
 
-printk_ratelimit:
-=================
+printk_ratelimit
+================
 
-Some warning messages are rate limited. printk_ratelimit specifies
+Some warning messages are rate limited. ``printk_ratelimit`` specifies
 the minimum length of time between these messages (in seconds).
 The default value is 5 seconds.
 
 A value of 0 will disable rate limiting.
 
 
-printk_ratelimit_burst:
-=======================
+printk_ratelimit_burst
+======================
 
-While long term we enforce one message per printk_ratelimit
+While long term we enforce one message per `printk_ratelimit`_
 seconds, we do allow a burst of messages to pass through.
-printk_ratelimit_burst specifies the number of messages we can
+``printk_ratelimit_burst`` specifies the number of messages we can
 send before ratelimiting kicks in.
 
 The default value is 10 messages.
 
 
-printk_devkmsg:
-===============
-
-Control the logging to /dev/kmsg from userspace:
-
-ratelimit:
-       default, ratelimited
+printk_devkmsg
+==============
 
-on: unlimited logging to /dev/kmsg from userspace
+Control the logging to ``/dev/kmsg`` from userspace:
 
-off: logging to /dev/kmsg disabled
+========= =============================================
+ratelimit default, ratelimited
+on        unlimited logging to /dev/kmsg from userspace
+off       logging to /dev/kmsg disabled
+========= =============================================
 
-The kernel command line parameter printk.devkmsg= overrides this and is
+The kernel command line parameter ``printk.devkmsg=`` overrides this and is
 a one-time setting until next reboot: once set, it cannot be changed by
 this sysctl interface anymore.
 
+==============================================================
 
-randomize_va_space:
-===================
+
+pty
+===
+
+See Documentation/filesystems/devpts.txt.
+
+
+randomize_va_space
+==================
 
 This option can be used to select the type of process address
 space randomization that is used in the system, for architectures
@@ -881,10 +878,10 @@ that support this feature.
     This, among other things, implies that shared libraries will be
     loaded to random addresses.  Also for PIE-linked binaries, the
     location of code start is randomized.  This is the default if the
-    CONFIG_COMPAT_BRK option is enabled.
+    ``CONFIG_COMPAT_BRK`` option is enabled.
 
 2   Additionally enable heap randomization.  This is the default if
-    CONFIG_COMPAT_BRK is disabled.
+    ``CONFIG_COMPAT_BRK`` is disabled.
 
     There are a few legacy applications out there (such as some ancient
     versions of libc.so.5 from 1996) that assume that brk area starts
@@ -894,31 +891,27 @@ that support this feature.
     systems it is safe to choose full randomization.
 
     Systems with ancient and/or broken binaries should be configured
-    with CONFIG_COMPAT_BRK enabled, which excludes the heap from process
+    with ``CONFIG_COMPAT_BRK`` enabled, which excludes the heap from process
     address space randomization.
 ==  ===========================================================================
 
 
-reboot-cmd: (Sparc only)
-========================
-
-??? This seems to be a way to give an argument to the Sparc
-ROM/Flash boot loader. Maybe to tell it what to do after
-rebooting. ???
+real-root-dev
+=============
 
+See :doc:`/admin-guide/initrd`.
 
-rtsig-max & rtsig-nr:
-=====================
 
-The file rtsig-max can be used to tune the maximum number
-of POSIX realtime (queued) signals that can be outstanding
-in the system.
+reboot-cmd (SPARC only)
+=======================
 
-rtsig-nr shows the number of RT signals currently queued.
+??? This seems to be a way to give an argument to the Sparc
+ROM/Flash boot loader. Maybe to tell it what to do after
+rebooting. ???
 
 
-sched_energy_aware:
-===================
+sched_energy_aware
+==================
 
 Enables/disables Energy Aware Scheduling (EAS). EAS starts
 automatically on platforms where it can run (that is,
@@ -928,75 +921,88 @@ requirements for EAS but you do not want to use it, change
 this value to 0.
 
 
-sched_schedstats:
-=================
+sched_schedstats
+================
 
 Enables/disables scheduler statistics. Enabling this feature
 incurs a small amount of overhead in the scheduler but is
 useful for debugging and performance tuning.
 
 
-sg-big-buff:
-============
+seccomp
+=======
+
+See :doc:`/userspace-api/seccomp_filter`.
+
+
+sg-big-buff
+===========
 
 This file shows the size of the generic SCSI (sg) buffer.
 You can't tune it just yet, but you could change it on
-compile time by editing include/scsi/sg.h and changing
-the value of SG_BIG_BUFF.
+compile time by editing ``include/scsi/sg.h`` and changing
+the value of ``SG_BIG_BUFF``.
 
 There shouldn't be any reason to change this value. If
 you can come up with one, you probably know what you
 are doing anyway :)
 
 
-shmall:
-=======
+shmall
+======
 
 This parameter sets the total amount of shared memory pages that
-can be used system wide. Hence, SHMALL should always be at least
-ceil(shmmax/PAGE_SIZE).
+can be used system wide. Hence, ``shmall`` should always be at least
+``ceil(shmmax/PAGE_SIZE)``.
 
-If you are not sure what the default PAGE_SIZE is on your Linux
-system, you can run the following command:
+If you are not sure what the default ``PAGE_SIZE`` is on your Linux
+system, you can run the following command::
 
        # getconf PAGE_SIZE
 
 
-shmmax:
-=======
+shmmax
+======
 
 This value can be used to query and set the run time limit
 on the maximum shared memory segment size that can be created.
 Shared memory segments up to 1Gb are now supported in the
-kernel.  This value defaults to SHMMAX.
+kernel.  This value defaults to ``SHMMAX``.
 
 
-shm_rmid_forced:
-================
+shmmni
+======
+
+This value determines the maximum number of shared memory segments.
+4096 by default (``SHMMNI``).
+
+
+shm_rmid_forced
+===============
 
 Linux lets you set resource limits, including how much memory one
-process can consume, via setrlimit(2).  Unfortunately, shared memory
+process can consume, via ``setrlimit(2)``.  Unfortunately, shared memory
 segments are allowed to exist without association with any process, and
 thus might not be counted against any resource limits.  If enabled,
 shared memory segments are automatically destroyed when their attach
 count becomes zero after a detach or a process termination.  It will
 also destroy segments that were created, but never attached to, on exit
-from the process.  The only use left for IPC_RMID is to immediately
+from the process.  The only use left for ``IPC_RMID`` is to immediately
 destroy an unattached segment.  Of course, this breaks the way things are
 defined, so some applications might stop working.  Note that this
 feature will do you no good unless you also configure your resource
-limits (in particular, RLIMIT_AS and RLIMIT_NPROC).  Most systems don't
+limits (in particular, ``RLIMIT_AS`` and ``RLIMIT_NPROC``).  Most systems don't
 need this.
 
 Note that if you change this from 0 to 1, already created segments
 without users and with a dead originative process will be destroyed.
 
 
-sysctl_writes_strict:
-=====================
+sysctl_writes_strict
+====================
 
 Control how file position affects the behavior of updating sysctl values
-via the /proc/sys interface:
+via the ``/proc/sys`` interface:
 
   ==   ======================================================================
   -1   Legacy per-write sysctl value handling, with no printk warnings.
@@ -1013,8 +1019,8 @@ via the /proc/sys interface:
   ==   ======================================================================
 
 
-softlockup_all_cpu_backtrace:
-=============================
+softlockup_all_cpu_backtrace
+============================
 
 This value controls the soft lockup detector thread's behavior
 when a soft lockup condition is detected as to whether or not
@@ -1024,43 +1030,80 @@ be issued an NMI and instructed to capture stack trace.
 This feature is only applicable for architectures which support
 NMI.
 
-0: do nothing. This is the default behavior.
+= ============================================
+0 Do nothing. This is the default behavior.
+1 On detection capture more debug information.
+= ============================================
 
-1: on detection capture more debug information.
 
+softlockup_panic
+=================
 
-soft_watchdog:
-==============
+This parameter can be used to control whether the kernel panics
+when a soft lockup is detected.
 
-This parameter can be used to control the soft lockup detector.
+= ============================================
+0 Don't panic on soft lockup.
+1 Panic on soft lockup.
+= ============================================
 
-   0 - disable the soft lockup detector
+This can also be set using the softlockup_panic kernel parameter.
 
-   1 - enable the soft lockup detector
+
+soft_watchdog
+=============
+
+This parameter can be used to control the soft lockup detector.
+
+= =================================
+0 Disable the soft lockup detector.
+1 Enable the soft lockup detector.
+= =================================
 
 The soft lockup detector monitors CPUs for threads that are hogging the CPUs
 without rescheduling voluntarily, and thus prevent the 'watchdog/N' threads
 from running. The mechanism depends on the CPUs ability to respond to timer
 interrupts which are needed for the 'watchdog/N' threads to be woken up by
-the watchdog timer function, otherwise the NMI watchdog - if enabled - can
+the watchdog timer function, otherwise the NMI watchdog — if enabled — can
 detect a hard lockup condition.
 
 
-stack_erasing:
-==============
+stack_erasing
+=============
 
 This parameter can be used to control kernel stack erasing at the end
-of syscalls for kernels built with CONFIG_GCC_PLUGIN_STACKLEAK.
+of syscalls for kernels built with ``CONFIG_GCC_PLUGIN_STACKLEAK``.
 
 That erasing reduces the information which kernel stack leak bugs
 can reveal and blocks some uninitialized stack variable attacks.
 The tradeoff is the performance impact: on a single CPU system kernel
 compilation sees a 1% slowdown, other systems and workloads may vary.
 
-  0: kernel stack erasing is disabled, STACKLEAK_METRICS are not updated.
+= ====================================================================
+0 Kernel stack erasing is disabled, STACKLEAK_METRICS are not updated.
+1 Kernel stack erasing is enabled (default), it is performed before
+  returning to the userspace at the end of syscalls.
+= ====================================================================
+
+
+stop-a (SPARC only)
+===================
+
+Controls Stop-A:
+
+= ====================================
+0 Stop-A has no effect.
+1 Stop-A breaks to the PROM (default).
+= ====================================
+
+Stop-A is always enabled on a panic, so that the user can return to
+the boot PROM.
 
-  1: kernel stack erasing is enabled (default), it is performed before
-     returning to the userspace at the end of syscalls.
+
+sysrq
+=====
+
+See :doc:`/admin-guide/sysrq`.
 
 
 tainted
@@ -1090,30 +1133,30 @@ ORed together. The letters are seen in "Tainted" line of Oops reports.
 131072  `(T)`  The kernel was built with the struct randomization plugin
 ======  =====  ==============================================================
 
-See Documentation/admin-guide/tainted-kernels.rst for more information.
+See :doc:`/admin-guide/tainted-kernels` for more information.
 
 
-threads-max:
-============
+threads-max
+===========
 
 This value controls the maximum number of threads that can be created
-using fork().
+using ``fork()``.
 
 During initialization the kernel sets this value such that even if the
 maximum number of threads is created, the thread structures occupy only
 a part (1/8th) of the available RAM pages.
 
-The minimum value that can be written to threads-max is 1.
+The minimum value that can be written to ``threads-max`` is 1.
 
-The maximum value that can be written to threads-max is given by the
-constant FUTEX_TID_MASK (0x3fffffff).
+The maximum value that can be written to ``threads-max`` is given by the
+constant ``FUTEX_TID_MASK`` (0x3fffffff).
 
-If a value outside of this range is written to threads-max an error
-EINVAL occurs.
+If a value outside of this range is written to ``threads-max`` an
+``EINVAL`` error occurs.
 
 
-unknown_nmi_panic:
-==================
+unknown_nmi_panic
+=================
 
 The value in this file affects behavior of handling NMI. When the
 value is non-zero, unknown NMI is trapped and then panic occurs. At
@@ -1123,37 +1166,39 @@ NMI switch that most IA32 servers have fires unknown NMI up, for
 example.  If a system hangs up, try pressing the NMI switch.
 
 
-watchdog:
-=========
+watchdog
+========
 
 This parameter can be used to disable or enable the soft lockup detector
-_and_ the NMI watchdog (i.e. the hard lockup detector) at the same time.
-
-   0 - disable both lockup detectors
+*and* the NMI watchdog (i.e. the hard lockup detector) at the same time.
 
-   1 - enable both lockup detectors
+= ==============================
+0 Disable both lockup detectors.
+1 Enable both lockup detectors.
+= ==============================
 
 The soft lockup detector and the NMI watchdog can also be disabled or
-enabled individually, using the soft_watchdog and nmi_watchdog parameters.
-If the watchdog parameter is read, for example by executing::
+enabled individually, using the ``soft_watchdog`` and ``nmi_watchdog``
+parameters.
+If the ``watchdog`` parameter is read, for example by executing::
 
    cat /proc/sys/kernel/watchdog
 
-the output of this command (0 or 1) shows the logical OR of soft_watchdog
-and nmi_watchdog.
+the output of this command (0 or 1) shows the logical OR of
+``soft_watchdog`` and ``nmi_watchdog``.
 
 
-watchdog_cpumask:
-=================
+watchdog_cpumask
+================
 
 This value can be used to control on which cpus the watchdog may run.
-The default cpumask is all possible cores, but if NO_HZ_FULL is
+The default cpumask is all possible cores, but if ``NO_HZ_FULL`` is
 enabled in the kernel config, and cores are specified with the
-nohz_full= boot argument, those cores are excluded by default.
+``nohz_full=`` boot argument, those cores are excluded by default.
 Offline cores can be included in this mask, and if the core is later
 brought online, the watchdog will be started based on the mask value.
 
-Typically this value would only be touched in the nohz_full case
+Typically this value would only be touched in the ``nohz_full`` case
 to re-enable cores that by default were not running the watchdog,
 if a kernel lockup was suspected on those cores.
 
@@ -1164,12 +1209,12 @@ might say::
   echo 0,2-4 > /proc/sys/kernel/watchdog_cpumask
 
 
-watchdog_thresh:
-================
+watchdog_thresh
+===============
 
 This value can be used to control the frequency of hrtimer and NMI
 events and the soft and hard lockup thresholds. The default threshold
 is 10 seconds.
 
-The softlockup threshold is (2 * watchdog_thresh). Setting this
+The softlockup threshold is (``2 * watchdog_thresh``). Setting this
 tunable to zero will disable lockup detection altogether.
index effd9c7..b256f97 100644 (file)
@@ -4,18 +4,18 @@ ARM TCM (Tightly-Coupled Memory) handling in Linux
 
 Written by Linus Walleij <linus.walleij@stericsson.com>
 
-Some ARM SoC:s have a so-called TCM (Tightly-Coupled Memory).
+Some ARM SoCs have a so-called TCM (Tightly-Coupled Memory).
 This is usually just a few (4-64) KiB of RAM inside the ARM
 processor.
 
-Due to being embedded inside the CPU The TCM has a
+Due to being embedded inside the CPU, the TCM has a
 Harvard-architecture, so there is an ITCM (instruction TCM)
 and a DTCM (data TCM). The DTCM can not contain any
 instructions, but the ITCM can actually contain data.
 The size of DTCM or ITCM is minimum 4KiB so the typical
 minimum configuration is 4KiB ITCM and 4KiB DTCM.
 
-ARM CPU:s have special registers to read out status, physical
+ARM CPUs have special registers to read out status, physical
 location and size of TCM memories. arch/arm/include/asm/cputype.h
 defines a CPUID_TCM register that you can read out from the
 system control coprocessor. Documentation from ARM can be found
diff --git a/Documentation/arm64/amu.rst b/Documentation/arm64/amu.rst
new file mode 100644 (file)
index 0000000..5057b11
--- /dev/null
@@ -0,0 +1,112 @@
+=======================================================
+Activity Monitors Unit (AMU) extension in AArch64 Linux
+=======================================================
+
+Author: Ionela Voinescu <ionela.voinescu@arm.com>
+
+Date: 2019-09-10
+
+This document briefly describes the provision of Activity Monitors Unit
+support in AArch64 Linux.
+
+
+Architecture overview
+---------------------
+
+The activity monitors extension is an optional extension introduced by the
+ARMv8.4 CPU architecture.
+
+The activity monitors unit, implemented in each CPU, provides performance
+counters intended for system management use. The AMU extension provides a
+system register interface to the counter registers and also supports an
+optional external memory-mapped interface.
+
+Version 1 of the Activity Monitors architecture implements a counter group
+of four fixed and architecturally defined 64-bit event counters.
+  - CPU cycle counter: increments at the frequency of the CPU.
+  - Constant counter: increments at the fixed frequency of the system
+    clock.
+  - Instructions retired: increments with every architecturally executed
+    instruction.
+  - Memory stall cycles: counts instruction dispatch stall cycles caused by
+    misses in the last level cache within the clock domain.
+
+When in WFI or WFE these counters do not increment.
+
+The Activity Monitors architecture provides space for up to 16 architected
+event counters. Future versions of the architecture may use this space to
+implement additional architected event counters.
+
+Additionally, version 1 implements a counter group of up to 16 auxiliary
+64-bit event counters.
+
+On cold reset all counters reset to 0.
+
+
+Basic support
+-------------
+
+The kernel can safely run a mix of CPUs with and without support for the
+activity monitors extension. Therefore, when CONFIG_ARM64_AMU_EXTN is
+selected we unconditionally enable the capability to allow any late CPU
+(secondary or hotplugged) to detect and use the feature.
+
+When the feature is detected on a CPU, we flag the availability of the
+feature but this does not guarantee the correct functionality of the
+counters, only the presence of the extension.
+
+Firmware (code running at higher exception levels, e.g. arm-tf) support is
+needed to:
+ - Enable access for lower exception levels (EL2 and EL1) to the AMU
+   registers.
+ - Enable the counters. If not enabled these will read as 0.
+ - Save/restore the counters before/after the CPU is being put/brought up
+   from the 'off' power state.
+
+When using kernels that have this feature enabled but boot with broken
+firmware the user may experience panics or lockups when accessing the
+counter registers. Even if these symptoms are not observed, the values
+returned by the register reads might not correctly reflect reality. Most
+commonly, the counters will read as 0, indicating that they are not
+enabled.
+
+If proper support is not provided in firmware it's best to disable
+CONFIG_ARM64_AMU_EXTN. To be noted that for security reasons, this does not
+bypass the setting of AMUSERENR_EL0 to trap accesses from EL0 (userspace) to
+EL1 (kernel). Therefore, firmware should still ensure accesses to AMU registers
+are not trapped in EL2/EL3.
+
+The fixed counters of AMUv1 are accessible though the following system
+register definitions:
+ - SYS_AMEVCNTR0_CORE_EL0
+ - SYS_AMEVCNTR0_CONST_EL0
+ - SYS_AMEVCNTR0_INST_RET_EL0
+ - SYS_AMEVCNTR0_MEM_STALL_EL0
+
+Auxiliary platform specific counters can be accessed using
+SYS_AMEVCNTR1_EL0(n), where n is a value between 0 and 15.
+
+Details can be found in: arch/arm64/include/asm/sysreg.h.
+
+
+Userspace access
+----------------
+
+Currently, access from userspace to the AMU registers is disabled due to:
+ - Security reasons: they might expose information about code executed in
+   secure mode.
+ - Purpose: AMU counters are intended for system management use.
+
+Also, the presence of the feature is not visible to userspace.
+
+
+Virtualization
+--------------
+
+Currently, access from userspace (EL0) and kernelspace (EL1) on the KVM
+guest side is disabled due to:
+ - Security reasons: they might expose information about code executed
+   by other guests or the host.
+
+Any attempt to access the AMU registers will result in an UNDEFINED
+exception being injected into the guest.
index 5d78a6f..a3f1a47 100644 (file)
@@ -248,6 +248,20 @@ Before jumping into the kernel, the following conditions must be met:
     - HCR_EL2.APK (bit 40) must be initialised to 0b1
     - HCR_EL2.API (bit 41) must be initialised to 0b1
 
+  For CPUs with Activity Monitors Unit v1 (AMUv1) extension present:
+  - If EL3 is present:
+    CPTR_EL3.TAM (bit 30) must be initialised to 0b0
+    CPTR_EL2.TAM (bit 30) must be initialised to 0b0
+    AMCNTENSET0_EL0 must be initialised to 0b1111
+    AMCNTENSET1_EL0 must be initialised to a platform specific value
+    having 0b1 set for the corresponding bit for each of the auxiliary
+    counters present.
+  - If the kernel is entered at EL1:
+    AMCNTENSET0_EL0 must be initialised to 0b1111
+    AMCNTENSET1_EL0 must be initialised to a platform specific value
+    having 0b1 set for the corresponding bit for each of the auxiliary
+    counters present.
+
 The requirements described above for CPU mode, caches, MMUs, architected
 timers, coherency and system registers apply to all CPUs.  All CPUs must
 enter the kernel in the same exception level.
index 5c0c69d..09cbb4e 100644 (file)
@@ -6,6 +6,7 @@ ARM64 Architecture
     :maxdepth: 1
 
     acpi_object_usage
+    amu
     arm-acpi
     booting
     cpu-feature-registers
index 9120e59..2c08c62 100644 (file)
@@ -110,6 +110,8 @@ stable kernels.
 +----------------+-----------------+-----------------+-----------------------------+
 | Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154        |
 +----------------+-----------------+-----------------+-----------------------------+
+| Cavium         | ThunderX GICv3  | #38539          | N/A                         |
++----------------+-----------------+-----------------+-----------------------------+
 | Cavium         | ThunderX Core   | #27456          | CAVIUM_ERRATUM_27456        |
 +----------------+-----------------+-----------------+-----------------------------+
 | Cavium         | ThunderX Core   | #30115          | CAVIUM_ERRATUM_30115        |
index 2cf258d..160a514 100644 (file)
@@ -2,17 +2,9 @@
 Generic Block Device Capability
 ===============================
 
-This file documents the sysfs file block/<disk>/capability
+This file documents the sysfs file ``block/<disk>/capability``.
 
-capability is a hex word indicating which capabilities a specific disk
-supports.  For more information on bits not listed here, see
-include/linux/genhd.h
+``capability`` is a bitfield, printed in hexadecimal, indicating which
+capabilities a specific block device supports:
 
-GENHD_FL_MEDIA_CHANGE_NOTIFY
-----------------------------
-
-Value: 4
-
-When this bit is set, the disk supports Asynchronous Notification
-of media change events.  These events will be broadcast to user
-space via kernel uevent.
+.. kernel-doc:: include/linux/genhd.h
index 3c7bdf4..9ae8e9a 100644 (file)
@@ -38,7 +38,11 @@ needs_sphinx = '1.3'
 # ones.
 extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain',
               'kfigure', 'sphinx.ext.ifconfig', 'automarkup',
-              'maintainers_include']
+              'maintainers_include', 'sphinx.ext.autosectionlabel' ]
+
+# Ensure that autosectionlabel will produce unique names
+autosectionlabel_prefix_document = True
+autosectionlabel_maxdepth = 2
 
 # The name of the math extension changed on Sphinx 1.4
 if (major == 1 and minor > 3) or (major > 1):
index a501dc1..0897ad1 100644 (file)
@@ -8,41 +8,81 @@ This is the beginning of a manual for core kernel APIs.  The conversion
 Core utilities
 ==============
 
+This section has general and "core core" documentation.  The first is a
+massive grab-bag of kerneldoc info left over from the docbook days; it
+should really be broken up someday when somebody finds the energy to do
+it.
+
 .. toctree::
    :maxdepth: 1
 
    kernel-api
+   workqueue
+   printk-formats
+   symbol-namespaces
+
+Data structures and low-level utilities
+=======================================
+
+Library functionality that is used throughout the kernel.
+
+.. toctree::
+   :maxdepth: 1
+
+   kobject
    assoc_array
+   xarray
+   idr
+   circular-buffers
+   generic-radix-tree
+   packing
+   timekeeping
+   errseq
+
+Concurrency primitives
+======================
+
+How Linux keeps everything from happening at the same time.  See
+:doc:`/locking/index` for more related documentation.
+
+.. toctree::
+   :maxdepth: 1
+
    atomic_ops
-   cachetlb
    refcount-vs-atomic
-   cpu_hotplug
-   idr
    local_ops
-   workqueue
+   padata
+   ../RCU/index
+
+Low-level hardware management
+=============================
+
+Cache management, managing CPU hotplug, etc.
+
+.. toctree::
+   :maxdepth: 1
+
+   cachetlb
+   cpu_hotplug
+   memory-hotplug
    genericirq
-   xarray
-   librs
-   genalloc
-   errseq
-   packing
-   printk-formats
-   circular-buffers
-   generic-radix-tree
+   protection-keys
+
+Memory management
+=================
+
+How to allocate and use memory in the kernel.  Note that there is a lot
+more memory-management documentation in :doc:`/vm/index`.
+
+.. toctree::
+   :maxdepth: 1
+
    memory-allocation
    mm-api
+   genalloc
    pin_user_pages
-   gfp_mask-from-fs-io
-   timekeeping
    boot-time-mm
-   memory-hotplug
-   protection-keys
-   ../RCU/index
-   gcc-plugins
-   symbol-namespaces
-   padata
-   ioctl
-
+   gfp_mask-from-fs-io
 
 Interfaces for kernel debugging
 ===============================
@@ -53,6 +93,16 @@ Interfaces for kernel debugging
    debug-objects
    tracepoint
 
+Everything else
+===============
+
+Documents that don't fit elsewhere or which have yet to be categorized.
+
+.. toctree::
+   :maxdepth: 1
+
+   librs
+
 .. only:: subproject and html
 
    Indices
similarity index 87%
rename from Documentation/kobject.txt
rename to Documentation/core-api/kobject.rst
index ff4c250..1f62d4d 100644 (file)
@@ -25,7 +25,7 @@ some terms we will be working with.
    usually embedded within some other structure which contains the stuff
    the code is really interested in.
 
-   No structure should EVER have more than one kobject embedded within it.
+   No structure should **EVER** have more than one kobject embedded within it.
    If it does, the reference counting for the object is sure to be messed
    up and incorrect, and your code will be buggy.  So do not do this.
 
@@ -55,7 +55,7 @@ a larger, domain-specific object.  To this end, kobjects will be found
 embedded in other structures.  If you are used to thinking of things in
 object-oriented terms, kobjects can be seen as a top-level, abstract class
 from which other classes are derived.  A kobject implements a set of
-capabilities which are not particularly useful by themselves, but which are
+capabilities which are not particularly useful by themselves, but are
 nice to have in other objects.  The C language does not allow for the
 direct expression of inheritance, so other techniques - such as structure
 embedding - must be used.
@@ -65,12 +65,12 @@ this is analogous as to how "list_head" structs are rarely useful on
 their own, but are invariably found embedded in the larger objects of
 interest.)
 
-So, for example, the UIO code in drivers/uio/uio.c has a structure that
+So, for example, the UIO code in ``drivers/uio/uio.c`` has a structure that
 defines the memory region associated with a uio device::
 
     struct uio_map {
-       struct kobject kobj;
-       struct uio_mem *mem;
+            struct kobject kobj;
+            struct uio_mem *mem;
     };
 
 If you have a struct uio_map structure, finding its embedded kobject is
@@ -78,30 +78,30 @@ just a matter of using the kobj member.  Code that works with kobjects will
 often have the opposite problem, however: given a struct kobject pointer,
 what is the pointer to the containing structure?  You must avoid tricks
 (such as assuming that the kobject is at the beginning of the structure)
-and, instead, use the container_of() macro, found in <linux/kernel.h>::
+and, instead, use the container_of() macro, found in ``<linux/kernel.h>``::
 
     container_of(pointer, type, member)
 
 where:
 
-  * "pointer" is the pointer to the embedded kobject,
-  * "type" is the type of the containing structure, and
-  * "member" is the name of the structure field to which "pointer" points.
+  * ``pointer`` is the pointer to the embedded kobject,
+  * ``type`` is the type of the containing structure, and
+  * ``member`` is the name of the structure field to which ``pointer`` points.
 
 The return value from container_of() is a pointer to the corresponding
-container type. So, for example, a pointer "kp" to a struct kobject
-embedded *within* a struct uio_map could be converted to a pointer to the
-*containing* uio_map structure with::
+container type. So, for example, a pointer ``kp`` to a struct kobject
+embedded **within** a struct uio_map could be converted to a pointer to the
+**containing** uio_map structure with::
 
     struct uio_map *u_map = container_of(kp, struct uio_map, kobj);
 
-For convenience, programmers often define a simple macro for "back-casting"
+For convenience, programmers often define a simple macro for **back-casting**
 kobject pointers to the containing type.  Exactly this happens in the
-earlier drivers/uio/uio.c, as you can see here::
+earlier ``drivers/uio/uio.c``, as you can see here::
 
     struct uio_map {
-        struct kobject kobj;
-        struct uio_mem *mem;
+            struct kobject kobj;
+            struct uio_mem *mem;
     };
 
     #define to_map(map) container_of(map, struct uio_map, kobj)
@@ -125,7 +125,7 @@ must have an associated kobj_type.  After calling kobject_init(), to
 register the kobject with sysfs, the function kobject_add() must be called::
 
     int kobject_add(struct kobject *kobj, struct kobject *parent,
-                   const char *fmt, ...);
+                    const char *fmt, ...);
 
 This sets up the parent of the kobject and the name for the kobject
 properly.  If the kobject is to be associated with a specific kset,
@@ -172,13 +172,13 @@ call to kobject_uevent()::
 
     int kobject_uevent(struct kobject *kobj, enum kobject_action action);
 
-Use the KOBJ_ADD action for when the kobject is first added to the kernel.
+Use the **KOBJ_ADD** action for when the kobject is first added to the kernel.
 This should be done only after any attributes or children of the kobject
 have been initialized properly, as userspace will instantly start to look
 for them when this call happens.
 
 When the kobject is removed from the kernel (details on how to do that are
-below), the uevent for KOBJ_REMOVE will be automatically created by the
+below), the uevent for **KOBJ_REMOVE** will be automatically created by the
 kobject core, so the caller does not have to worry about doing that by
 hand.
 
@@ -238,7 +238,7 @@ Both types of attributes used here, with a kobject that has been created
 with the kobject_create_and_add(), can be of type kobj_attribute, so no
 special custom attribute is needed to be created.
 
-See the example module, samples/kobject/kobject-example.c for an
+See the example module, ``samples/kobject/kobject-example.c`` for an
 implementation of a simple kobject and attributes.
 
 
@@ -270,10 +270,10 @@ such a method has a form like::
 
     void my_object_release(struct kobject *kobj)
     {
-           struct my_object *mine = container_of(kobj, struct my_object, kobj);
+            struct my_object *mine = container_of(kobj, struct my_object, kobj);
 
-           /* Perform any additional cleanup on this object, then... */
-           kfree(mine);
+            /* Perform any additional cleanup on this object, then... */
+            kfree(mine);
     }
 
 One important point cannot be overstated: every kobject must have a
@@ -297,11 +297,11 @@ instead, it is associated with the ktype. So let us introduce struct
 kobj_type::
 
     struct kobj_type {
-           void (*release)(struct kobject *kobj);
-           const struct sysfs_ops *sysfs_ops;
-           struct attribute **default_attrs;
-           const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
-           const void *(*namespace)(struct kobject *kobj);
+            void (*release)(struct kobject *kobj);
+            const struct sysfs_ops *sysfs_ops;
+            struct attribute **default_attrs;
+            const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
+            const void *(*namespace)(struct kobject *kobj);
     };
 
 This structure is used to describe a particular type of kobject (or, more
@@ -352,8 +352,8 @@ created and never declared statically or on the stack.  To create a new
 kset use::
 
   struct kset *kset_create_and_add(const char *name,
-                                  struct kset_uevent_ops *u,
-                                  struct kobject *parent);
+                                   struct kset_uevent_ops *u,
+                                   struct kobject *parent);
 
 When you are finished with the kset, call::
 
@@ -365,16 +365,16 @@ Because other references to the kset may still exist, the release may happen
 after kset_unregister() returns.
 
 An example of using a kset can be seen in the
-samples/kobject/kset-example.c file in the kernel tree.
+``samples/kobject/kset-example.c`` file in the kernel tree.
 
 If a kset wishes to control the uevent operations of the kobjects
 associated with it, it can use the struct kset_uevent_ops to handle it::
 
   struct kset_uevent_ops {
-        int (*filter)(struct kset *kset, struct kobject *kobj);
-        const char *(*name)(struct kset *kset, struct kobject *kobj);
-        int (*uevent)(struct kset *kset, struct kobject *kobj,
-                      struct kobj_uevent_env *env);
+          int (*filter)(struct kset *kset, struct kobject *kobj);
+          const char *(*name)(struct kset *kset, struct kobject *kobj);
+          int (*uevent)(struct kset *kset, struct kobject *kobj,
+                        struct kobj_uevent_env *env);
   };
 
 
@@ -408,8 +408,8 @@ Kobject removal
 After a kobject has been registered with the kobject core successfully, it
 must be cleaned up when the code is finished with it.  To do that, call
 kobject_put().  By doing this, the kobject core will automatically clean up
-all of the memory allocated by this kobject.  If a KOBJ_ADD uevent has been
-sent for the object, a corresponding KOBJ_REMOVE uevent will be sent, and
+all of the memory allocated by this kobject.  If a ``KOBJ_ADD`` uevent has been
+sent for the object, a corresponding ``KOBJ_REMOVE`` uevent will be sent, and
 any other sysfs housekeeping will be handled for the caller properly.
 
 If you need to do a two-stage delete of the kobject (say you are not
@@ -430,5 +430,5 @@ Example code to copy from
 =========================
 
 For a more complete example of using ksets and kobjects properly, see the
-example programs samples/kobject/{kobject-example.c,kset-example.c},
-which will be built as loadable modules if you select CONFIG_SAMPLE_KOBJECT.
+example programs ``samples/kobject/{kobject-example.c,kset-example.c}``,
+which will be built as loadable modules if you select ``CONFIG_SAMPLE_KOBJECT``.
diff --git a/Documentation/cpu-freq/amd-powernow.txt b/Documentation/cpu-freq/amd-powernow.txt
deleted file mode 100644 (file)
index 254da15..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-
-PowerNow! and Cool'n'Quiet are AMD names for frequency
-management capabilities in AMD processors. As the hardware
-implementation changes in new generations of the processors,
-there is a different cpu-freq driver for each generation.
-
-Note that the driver's will not load on the "wrong" hardware,
-so it is safe to try each driver in turn when in doubt as to
-which is the correct driver.
-
-Note that the functionality to change frequency (and voltage)
-is not available in all processors. The drivers will refuse
-to load on processors without this capability. The capability
-is detected with the cpuid instruction.
-
-The drivers use BIOS supplied tables to obtain frequency and
-voltage information appropriate for a particular platform.
-Frequency transitions will be unavailable if the BIOS does
-not supply these tables.
-
-6th Generation: powernow-k6
-
-7th Generation: powernow-k7: Athlon, Duron, Geode.
-
-8th Generation: powernow-k8: Athlon, Athlon 64, Opteron, Sempron.
-Documentation on this functionality in 8th generation processors
-is available in the "BIOS and Kernel Developer's Guide", publication
-26094, in chapter 9, available for download from www.amd.com. 
-
-BIOS supplied data, for powernow-k7 and for powernow-k8, may be
-from either the PSB table or from ACPI objects. The ACPI support
-is only available if the kernel config sets CONFIG_ACPI_PROCESSOR.
-The powernow-k8 driver will attempt to use ACPI if so configured,
-and fall back to PST if that fails.
-The powernow-k7 driver will try to use the PSB support first, and
-fall back to ACPI if the PSB support fails. A module parameter,
-acpi_force, is provided to force ACPI support to be used instead 
-of PSB support.
similarity index 69%
rename from Documentation/cpu-freq/core.txt
rename to Documentation/cpu-freq/core.rst
index ed577d9..33cb90b 100644 (file)
@@ -1,31 +1,23 @@
-     CPU frequency and voltage scaling code in the Linux(TM) kernel
+.. SPDX-License-Identifier: GPL-2.0
 
+=============================================================
+General description of the CPUFreq core and CPUFreq notifiers
+=============================================================
 
-                        L i n u x    C P U F r e q
+Authors:
+       - Dominik Brodowski  <linux@brodo.de>
+       - David Kimdon <dwhedon@debian.org>
+       - Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+       - Viresh Kumar <viresh.kumar@linaro.org>
 
-                         C P U F r e q    C o r e
+.. Contents:
 
-
-                   Dominik Brodowski  <linux@brodo.de>
-                    David Kimdon <dwhedon@debian.org>
-               Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-                  Viresh Kumar <viresh.kumar@linaro.org>
-
-
-
-   Clock scaling allows you to change the clock speed of the CPUs on the
-    fly. This is a nice method to save battery power, because the lower
-            the clock speed, the less power the CPU consumes.
-
-
-Contents:
----------
-1.  CPUFreq core and interfaces
-2.  CPUFreq notifiers
-3.  CPUFreq Table Generation with Operating Performance Point (OPP)
+   1.  CPUFreq core and interfaces
+   2.  CPUFreq notifiers
+   3.  CPUFreq Table Generation with Operating Performance Point (OPP)
 
 1. General Information
-=======================
+======================
 
 The CPUFreq core code is located in drivers/cpufreq/cpufreq.c. This
 cpufreq code offers a standardized interface for the CPUFreq
@@ -63,7 +55,7 @@ The phase is specified in the second argument to the notifier.  The phase is
 CPUFREQ_CREATE_POLICY when the policy is first created and it is
 CPUFREQ_REMOVE_POLICY when the policy is removed.
 
-The third argument, a void *pointer, points to a struct cpufreq_policy
+The third argument, a ``void *pointer``, points to a struct cpufreq_policy
 consisting of several values, including min, max (the lower and upper
 frequencies (in kHz) of the new policy).
 
@@ -80,10 +72,13 @@ CPUFREQ_POSTCHANGE.
 
 The third argument is a struct cpufreq_freqs with the following
 values:
-cpu    - number of the affected CPU
-old    - old frequency
-new    - new frequency
-flags  - flags of the cpufreq driver
+
+=====  ===========================
+cpu    number of the affected CPU
+old    old frequency
+new    new frequency
+flags  flags of the cpufreq driver
+=====  ===========================
 
 3. CPUFreq Table Generation with Operating Performance Point (OPP)
 ==================================================================
@@ -94,9 +89,12 @@ dev_pm_opp_init_cpufreq_table -
        the OPP layer's internal information about the available frequencies
        into a format readily providable to cpufreq.
 
-       WARNING: Do not use this function in interrupt context.
+       .. Warning::
+
+          Do not use this function in interrupt context.
+
+       Example::
 
-       Example:
         soc_pm_init()
         {
                /* Do things */
@@ -106,7 +104,10 @@ dev_pm_opp_init_cpufreq_table -
                /* Do other things */
         }
 
-       NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
-       addition to CONFIG_PM_OPP.
+       .. note::
+
+          This function is available only if CONFIG_CPU_FREQ is enabled in
+          addition to CONFIG_PM_OPP.
 
-dev_pm_opp_free_cpufreq_table - Free up the table allocated by dev_pm_opp_init_cpufreq_table
+dev_pm_opp_free_cpufreq_table
+       Free up the table allocated by dev_pm_opp_init_cpufreq_table
similarity index 72%
rename from Documentation/cpu-freq/cpu-drivers.txt
rename to Documentation/cpu-freq/cpu-drivers.rst
index 6e353d0..a697278 100644 (file)
@@ -1,35 +1,27 @@
-     CPU frequency and voltage scaling code in the Linux(TM) kernel
+.. SPDX-License-Identifier: GPL-2.0
 
+===============================================
+How to Implement a new CPUFreq Processor Driver
+===============================================
 
-                        L i n u x    C P U F r e q
+Authors:
 
-                          C P U   D r i v e r s 
 
-                      - information for developers -
+       - Dominik Brodowski  <linux@brodo.de>
+       - Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+       - Viresh Kumar <viresh.kumar@linaro.org>
 
+.. Contents
 
-                   Dominik Brodowski  <linux@brodo.de>
-               Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-                  Viresh Kumar <viresh.kumar@linaro.org>
-
-
-
-   Clock scaling allows you to change the clock speed of the CPUs on the
-    fly. This is a nice method to save battery power, because the lower
-            the clock speed, the less power the CPU consumes.
-
-
-Contents:
----------
-1.   What To Do?
-1.1  Initialization
-1.2  Per-CPU Initialization
-1.3  verify
-1.4  target/target_index or setpolicy?
-1.5  target/target_index
-1.6  setpolicy
-1.7  get_intermediate and target_intermediate
-2.   Frequency Table Helpers
+   1.   What To Do?
+   1.1  Initialization
+   1.2  Per-CPU Initialization
+   1.3  verify
+   1.4  target/target_index or setpolicy?
+   1.5  target/target_index
+   1.6  setpolicy
+   1.7  get_intermediate and target_intermediate
+   2.   Frequency Table Helpers
 
 
 
@@ -49,7 +41,7 @@ function check whether this kernel runs on the right CPU and the right
 chipset. If so, register a struct cpufreq_driver with the CPUfreq core
 using cpufreq_register_driver()
 
-What shall this struct cpufreq_driver contain? 
+What shall this struct cpufreq_driver contain?
 
  .name - The name of this driver.
 
@@ -108,37 +100,42 @@ Whenever a new CPU is registered with the device model, or after the
 cpufreq driver registers itself, the per-policy initialization function
 cpufreq_driver.init is called if no cpufreq policy existed for the CPU.
 Note that the .init() and .exit() routines are called only once for the
-policy and not for each CPU managed by the policy. It takes a struct
-cpufreq_policy *policy as argument. What to do now?
+policy and not for each CPU managed by the policy. It takes a ``struct
+cpufreq_policy *policy`` as argument. What to do now?
 
 If necessary, activate the CPUfreq support on your CPU.
 
 Then, the driver must fill in the following values:
 
-policy->cpuinfo.min_freq _and_
-policy->cpuinfo.max_freq -     the minimum and maximum frequency 
-                               (in kHz) which is supported by 
-                               this CPU
-policy->cpuinfo.transition_latency   the time it takes on this CPU to
-                               switch between two frequencies in
-                               nanoseconds (if appropriate, else
-                               specify CPUFREQ_ETERNAL)
-
-policy->cur                    The current operating frequency of
-                               this CPU (if appropriate)
-policy->min, 
-policy->max, 
-policy->policy and, if necessary,
-policy->governor               must contain the "default policy" for
-                               this CPU. A few moments later,
-                               cpufreq_driver.verify and either
-                               cpufreq_driver.setpolicy or
-                               cpufreq_driver.target/target_index is called
-                               with these values.
-policy->cpus                   Update this with the masks of the
-                               (online + offline) CPUs that do DVFS
-                               along with this CPU (i.e.  that share
-                               clock/voltage rails with it).
++-----------------------------------+--------------------------------------+
+|policy->cpuinfo.min_freq _and_            |                                      |
+|policy->cpuinfo.max_freq          | the minimum and maximum frequency    |
+|                                  | (in kHz) which is supported by       |
+|                                  | this CPU                             |
++-----------------------------------+--------------------------------------+
+|policy->cpuinfo.transition_latency | the time it takes on this CPU to    |
+|                                  | switch between two frequencies in    |
+|                                  | nanoseconds (if appropriate, else    |
+|                                  | specify CPUFREQ_ETERNAL)             |
++-----------------------------------+--------------------------------------+
+|policy->cur                       | The current operating frequency of   |
+|                                  | this CPU (if appropriate)            |
++-----------------------------------+--------------------------------------+
+|policy->min,                      |                                      |
+|policy->max,                      |                                      |
+|policy->policy and, if necessary,  |                                     |
+|policy->governor                  | must contain the "default policy" for|
+|                                  | this CPU. A few moments later,       |
+|                                  | cpufreq_driver.verify and either     |
+|                                  | cpufreq_driver.setpolicy or          |
+|                                  | cpufreq_driver.target/target_index is|
+|                                  | called with these values.            |
++-----------------------------------+--------------------------------------+
+|policy->cpus                      | Update this with the masks of the    |
+|                                  | (online + offline) CPUs that do DVFS |
+|                                  | along with this CPU (i.e.  that share|
+|                                  | clock/voltage rails with it).        |
++-----------------------------------+--------------------------------------+
 
 For setting some of these values (cpuinfo.min[max]_freq, policy->min[max]), the
 frequency table helpers might be helpful. See the section 2 for more information
@@ -151,8 +148,8 @@ on them.
 When the user decides a new policy (consisting of
 "policy,governor,min,max") shall be set, this policy must be validated
 so that incompatible values can be corrected. For verifying these
-values cpufreq_verify_within_limits(struct cpufreq_policy *policy,
-unsigned int min_freq, unsigned int max_freq) function might be helpful.
+values cpufreq_verify_within_limits(``struct cpufreq_policy *policy``,
+``unsigned int min_freq``, ``unsigned int max_freq``) function might be helpful.
 See section 2 for details on frequency table helpers.
 
 You need to make sure that at least one valid frequency (or operating
@@ -163,7 +160,7 @@ policy->max first, and only if this is no solution, decrease policy->min.
 1.4 target or target_index or setpolicy or fast_switch?
 -------------------------------------------------------
 
-Most cpufreq drivers or even most cpu frequency scaling algorithms 
+Most cpufreq drivers or even most cpu frequency scaling algorithms
 only allow the CPU frequency to be set to predefined fixed values. For
 these, you use the ->target(), ->target_index() or ->fast_switch()
 callbacks.
@@ -175,8 +172,8 @@ limits on their own. These shall use the ->setpolicy() callback.
 1.5. target/target_index
 ------------------------
 
-The target_index call has two arguments: struct cpufreq_policy *policy,
-and unsigned int index (into the exposed frequency table).
+The target_index call has two arguments: ``struct cpufreq_policy *policy``,
+and ``unsigned int`` index (into the exposed frequency table).
 
 The CPUfreq driver must set the new frequency when called here. The
 actual frequency must be determined by freq_table[index].frequency.
@@ -184,9 +181,9 @@ actual frequency must be determined by freq_table[index].frequency.
 It should always restore to earlier frequency (i.e. policy->restore_freq) in
 case of errors, even if we switched to intermediate frequency earlier.
 
-Deprecated:
+Deprecated
 ----------
-The target call has three arguments: struct cpufreq_policy *policy,
+The target call has three arguments: ``struct cpufreq_policy *policy``,
 unsigned int target_frequency, unsigned int relation.
 
 The CPUfreq driver must set the new frequency when called here. The
@@ -210,14 +207,14 @@ Not all drivers are expected to implement it, as sleeping from within
 this callback isn't allowed. This callback must be highly optimized to
 do switching as fast as possible.
 
-This function has two arguments: struct cpufreq_policy *policy and
-unsigned int target_frequency.
+This function has two arguments: ``struct cpufreq_policy *policy`` and
+``unsigned int target_frequency``.
 
 
 1.7 setpolicy
 -------------
 
-The setpolicy call only takes a struct cpufreq_policy *policy as
+The setpolicy call only takes a ``struct cpufreq_policy *policy`` as
 argument. You need to set the lower limit of the in-processor or
 in-chipset dynamic frequency switching to policy->min, the upper limit
 to policy->max, and -if supported- select a performance-oriented
@@ -278,10 +275,10 @@ table.
 
 cpufreq_for_each_valid_entry(pos, table) - iterates over all entries,
 excluding CPUFREQ_ENTRY_INVALID frequencies.
-Use arguments "pos" - a cpufreq_frequency_table * as a loop cursor and
-"table" - the cpufreq_frequency_table * you want to iterate over.
+Use arguments "pos" - a ``cpufreq_frequency_table *`` as a loop cursor and
+"table" - the ``cpufreq_frequency_table *`` you want to iterate over.
 
-For example:
+For example::
 
        struct cpufreq_frequency_table *pos, *driver_freq_table;
 
diff --git a/Documentation/cpu-freq/cpufreq-nforce2.txt b/Documentation/cpu-freq/cpufreq-nforce2.txt
deleted file mode 100644 (file)
index babce13..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-The cpufreq-nforce2 driver changes the FSB on nVidia nForce2 platforms.
-
-This works better than on other platforms, because the FSB of the CPU
-can be controlled independently from the PCI/AGP clock.
-
-The module has two options:
-
-       fid:     multiplier * 10 (for example 8.5 = 85)
-       min_fsb: minimum FSB
-
-If not set, fid is calculated from the current CPU speed and the FSB.
-min_fsb defaults to FSB at boot time - 50 MHz.
-
-IMPORTANT: The available range is limited downwards!
-           Also the minimum available FSB can differ, for systems 
-           booting with 200 MHz, 150 should always work.
-
-
similarity index 53%
rename from Documentation/cpu-freq/cpufreq-stats.txt
rename to Documentation/cpu-freq/cpufreq-stats.rst
index 14378ce..9ad695b 100644 (file)
@@ -1,21 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0
 
-     CPU frequency and voltage scaling statistics in the Linux(TM) kernel
+==========================================
+General Description of sysfs CPUFreq Stats
+==========================================
 
+information for users
 
-             L i n u x    c p u f r e q - s t a t s   d r i v e r
 
-                       - information for users -
+Author: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
 
+.. Contents
 
-             Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
-
-Contents
-1. Introduction
-2. Statistics Provided (with example)
-3. Configuring cpufreq-stats
+   1. Introduction
+   2. Statistics Provided (with example)
+   3. Configuring cpufreq-stats
 
 
 1. Introduction
+===============
 
 cpufreq-stats is a driver that provides CPU frequency statistics for each CPU.
 These statistics are provided in /sysfs as a bunch of read_only interfaces. This
@@ -28,8 +30,10 @@ that may be running on your CPU. So, it will work with any cpufreq_driver.
 
 
 2. Statistics Provided (with example)
+=====================================
 
 cpufreq stats provides following statistics (explained in detail below).
+
 -  time_in_state
 -  total_trans
 -  trans_table
@@ -39,53 +43,57 @@ All the statistics will be from the time the stats driver has been inserted
 statistic is done. Obviously, stats driver will not have any information
 about the frequency transitions before the stats driver insertion.
 
---------------------------------------------------------------------------------
-<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l
-total 0
-drwxr-xr-x  2 root root    0 May 14 16:06 .
-drwxr-xr-x  3 root root    0 May 14 15:58 ..
---w-------  1 root root 4096 May 14 16:06 reset
--r--r--r--  1 root root 4096 May 14 16:06 time_in_state
--r--r--r--  1 root root 4096 May 14 16:06 total_trans
--r--r--r--  1 root root 4096 May 14 16:06 trans_table
---------------------------------------------------------------------------------
-
--  reset
+::
+
+    <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l
+    total 0
+    drwxr-xr-x  2 root root    0 May 14 16:06 .
+    drwxr-xr-x  3 root root    0 May 14 15:58 ..
+    --w-------  1 root root 4096 May 14 16:06 reset
+    -r--r--r--  1 root root 4096 May 14 16:06 time_in_state
+    -r--r--r--  1 root root 4096 May 14 16:06 total_trans
+    -r--r--r--  1 root root 4096 May 14 16:06 trans_table
+
+- **reset**
+
 Write-only attribute that can be used to reset the stat counters. This can be
 useful for evaluating system behaviour under different governors without the
 need for a reboot.
 
--  time_in_state
+- **time_in_state**
+
 This gives the amount of time spent in each of the frequencies supported by
 this CPU. The cat output will have "<frequency> <time>" pair in each line, which
 will mean this CPU spent <time> usertime units of time at <frequency>. Output
-will have one line for each of the supported frequencies. usertime units here 
+will have one line for each of the supported frequencies. usertime units here
 is 10mS (similar to other time exported in /proc).
 
---------------------------------------------------------------------------------
-<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state 
-3600000 2089
-3400000 136
-3200000 34
-3000000 67
-2800000 172488
---------------------------------------------------------------------------------
+::
 
+    <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat time_in_state
+    3600000 2089
+    3400000 136
+    3200000 34
+    3000000 67
+    2800000 172488
 
--  total_trans
-This gives the total number of frequency transitions on this CPU. The cat 
+
+- **total_trans**
+
+This gives the total number of frequency transitions on this CPU. The cat
 output will have a single count which is the total number of frequency
 transitions.
 
---------------------------------------------------------------------------------
-<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans
-20
---------------------------------------------------------------------------------
+::
+
+    <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat total_trans
+    20
+
+- **trans_table**
 
--  trans_table
 This will give a fine grained information about all the CPU frequency
 transitions. The cat output here is a two dimensional matrix, where an entry
-<i,j> (row i, column j) represents the count of number of transitions from 
+<i,j> (row i, column j) represents the count of number of transitions from
 Freq_i to Freq_j. Freq_i rows and Freq_j columns follow the sorting order in
 which the driver has provided the frequency table initially to the cpufreq core
 and so can be sorted (ascending or descending) or unsorted.  The output here
@@ -95,26 +103,27 @@ readability.
 If the transition table is bigger than PAGE_SIZE, reading this will
 return an -EFBIG error.
 
---------------------------------------------------------------------------------
-<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
-   From  :    To
-         :   3600000   3400000   3200000   3000000   2800000 
-  3600000:         0         5         0         0         0 
-  3400000:         4         0         2         0         0 
-  3200000:         0         1         0         2         0 
-  3000000:         0         0         1         0         3 
-  2800000:         0         0         0         2         0 
---------------------------------------------------------------------------------
+::
 
+    <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
+    From  :    To
+           :   3600000   3400000   3200000   3000000   2800000
+    3600000:         0         5         0         0         0
+    3400000:         4         0         2         0         0
+    3200000:         0         1         0         2         0
+    3000000:         0         0         1         0         3
+    2800000:         0         0         0         2         0
 
 3. Configuring cpufreq-stats
+============================
+
+To configure cpufreq-stats in your kernel::
 
-To configure cpufreq-stats in your kernel
-Config Main Menu
-       Power management options (ACPI, APM)  --->
-               CPU Frequency scaling  --->
-                       [*] CPU Frequency scaling
-                       [*]   CPU frequency translation statistics
+       Config Main Menu
+               Power management options (ACPI, APM)  --->
+                       CPU Frequency scaling  --->
+                               [*] CPU Frequency scaling
+                               [*]   CPU frequency translation statistics
 
 
 "CPU Frequency scaling" (CONFIG_CPU_FREQ) should be enabled to configure
diff --git a/Documentation/cpu-freq/index.rst b/Documentation/cpu-freq/index.rst
new file mode 100644 (file)
index 0000000..aba7831
--- /dev/null
@@ -0,0 +1,39 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============================================================================
+Linux CPUFreq - CPU frequency and voltage scaling code in the Linux(TM) kernel
+==============================================================================
+
+Author: Dominik Brodowski  <linux@brodo.de>
+
+   Clock scaling allows you to change the clock speed of the CPUs on the
+   fly. This is a nice method to save battery power, because the lower
+   the clock speed, the less power the CPU consumes.
+
+
+.. toctree::
+   :maxdepth: 1
+
+   core
+   cpu-drivers
+   cpufreq-stats
+
+Mailing List
+------------
+There is a CPU frequency changing CVS commit and general list where
+you can report bugs, problems or submit patches. To post a message,
+send an email to linux-pm@vger.kernel.org.
+
+Links
+-----
+the FTP archives:
+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
+
+how to access the CVS repository:
+* http://cvs.arm.linux.org.uk/
+
+the CPUFreq Mailing list:
+* http://vger.kernel.org/vger-lists.html#linux-pm
+
+Clock and voltage scaling for the SA-1100:
+* http://www.lartmaker.nl/projects/scaling
diff --git a/Documentation/cpu-freq/index.txt b/Documentation/cpu-freq/index.txt
deleted file mode 100644 (file)
index c15e753..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-     CPU frequency and voltage scaling code in the Linux(TM) kernel
-
-
-                        L i n u x    C P U F r e q
-
-
-
-
-                   Dominik Brodowski  <linux@brodo.de>
-
-
-
-   Clock scaling allows you to change the clock speed of the CPUs on the
-    fly. This is a nice method to save battery power, because the lower
-            the clock speed, the less power the CPU consumes.
-
-
-
-Documents in this directory:
-----------------------------
-
-amd-powernow.txt -     AMD powernow driver specific file.
-
-core.txt       -       General description of the CPUFreq core and
-                       of CPUFreq notifiers.
-
-cpu-drivers.txt -      How to implement a new cpufreq processor driver.
-
-cpufreq-nforce2.txt -  nVidia nForce2 platform specific file.
-
-cpufreq-stats.txt -    General description of sysfs cpufreq stats.
-
-index.txt      -       File index, Mailing list and Links (this document)
-
-pcc-cpufreq.txt -      PCC cpufreq driver specific file.
-
-
-Mailing List
-------------
-There is a CPU frequency changing CVS commit and general list where
-you can report bugs, problems or submit patches. To post a message,
-send an email to linux-pm@vger.kernel.org.
-
-Links
------
-the FTP archives:
-* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
-
-how to access the CVS repository:
-* http://cvs.arm.linux.org.uk/
-
-the CPUFreq Mailing list:
-* http://vger.kernel.org/vger-lists.html#linux-pm
-
-Clock and voltage scaling for the SA-1100:
-* http://www.lartmaker.nl/projects/scaling
diff --git a/Documentation/cpu-freq/pcc-cpufreq.txt b/Documentation/cpu-freq/pcc-cpufreq.txt
deleted file mode 100644 (file)
index 9e3c3b3..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- *  pcc-cpufreq.txt - PCC interface documentation
- *
- *  Copyright (C) 2009 Red Hat, Matthew Garrett <mjg@redhat.com>
- *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- *      Nagananda Chumbalkar <nagananda.chumbalkar@hp.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or NON
- *  INFRINGEMENT. See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-
-                       Processor Clocking Control Driver
-                       ---------------------------------
-
-Contents:
----------
-1.     Introduction
-1.1    PCC interface
-1.1.1   Get Average Frequency
-1.1.2  Set Desired Frequency
-1.2    Platforms affected
-2.     Driver and /sys details
-2.1    scaling_available_frequencies
-2.2    cpuinfo_transition_latency
-2.3    cpuinfo_cur_freq
-2.4    related_cpus
-3.     Caveats
-
-1. Introduction:
-----------------
-Processor Clocking Control (PCC) is an interface between the platform
-firmware and OSPM. It is a mechanism for coordinating processor
-performance (ie: frequency) between the platform firmware and the OS.
-
-The PCC driver (pcc-cpufreq) allows OSPM to take advantage of the PCC
-interface.
-
-OS utilizes the PCC interface to inform platform firmware what frequency the
-OS wants for a logical processor. The platform firmware attempts to achieve
-the requested frequency. If the request for the target frequency could not be
-satisfied by platform firmware, then it usually means that power budget
-conditions are in place, and "power capping" is taking place.
-
-1.1 PCC interface:
-------------------
-The complete PCC specification is available here:
-http://www.acpica.org/download/Processor-Clocking-Control-v1p0.pdf
-
-PCC relies on a shared memory region that provides a channel for communication
-between the OS and platform firmware. PCC also implements a "doorbell" that
-is used by the OS to inform the platform firmware that a command has been
-sent.
-
-The ACPI PCCH() method is used to discover the location of the PCC shared
-memory region. The shared memory region header contains the "command" and
-"status" interface. PCCH() also contains details on how to access the platform
-doorbell.
-
-The following commands are supported by the PCC interface:
-* Get Average Frequency
-* Set Desired Frequency
-
-The ACPI PCCP() method is implemented for each logical processor and is
-used to discover the offsets for the input and output buffers in the shared
-memory region.
-
-When PCC mode is enabled, the platform will not expose processor performance
-or throttle states (_PSS, _TSS and related ACPI objects) to OSPM. Therefore,
-the native P-state driver (such as acpi-cpufreq for Intel, powernow-k8 for
-AMD) will not load.
-
-However, OSPM remains in control of policy. The governor (eg: "ondemand")
-computes the required performance for each processor based on server workload.
-The PCC driver fills in the command interface, and the input buffer and
-communicates the request to the platform firmware. The platform firmware is
-responsible for delivering the requested performance.
-
-Each PCC command is "global" in scope and can affect all the logical CPUs in
-the system. Therefore, PCC is capable of performing "group" updates. With PCC
-the OS is capable of getting/setting the frequency of all the logical CPUs in
-the system with a single call to the BIOS.
-
-1.1.1 Get Average Frequency:
-----------------------------
-This command is used by the OSPM to query the running frequency of the
-processor since the last time this command was completed. The output buffer
-indicates the average unhalted frequency of the logical processor expressed as
-a percentage of the nominal (ie: maximum) CPU frequency. The output buffer
-also signifies if the CPU frequency is limited by a power budget condition.
-
-1.1.2 Set Desired Frequency:
-----------------------------
-This command is used by the OSPM to communicate to the platform firmware the
-desired frequency for a logical processor. The output buffer is currently
-ignored by OSPM. The next invocation of "Get Average Frequency" will inform
-OSPM if the desired frequency was achieved or not.
-
-1.2 Platforms affected:
------------------------
-The PCC driver will load on any system where the platform firmware:
-* supports the PCC interface, and the associated PCCH() and PCCP() methods
-* assumes responsibility for managing the hardware clocking controls in order
-to deliver the requested processor performance
-
-Currently, certain HP ProLiant platforms implement the PCC interface. On those
-platforms PCC is the "default" choice.
-
-However, it is possible to disable this interface via a BIOS setting. In
-such an instance, as is also the case on platforms where the PCC interface
-is not implemented, the PCC driver will fail to load silently.
-
-2. Driver and /sys details:
----------------------------
-When the driver loads, it merely prints the lowest and the highest CPU
-frequencies supported by the platform firmware.
-
-The PCC driver loads with a message such as:
-pcc-cpufreq: (v1.00.00) driver loaded with frequency limits: 1600 MHz, 2933
-MHz
-
-This means that the OPSM can request the CPU to run at any frequency in
-between the limits (1600 MHz, and 2933 MHz) specified in the message.
-
-Internally, there is no need for the driver to convert the "target" frequency
-to a corresponding P-state.
-
-The VERSION number for the driver will be of the format v.xy.ab.
-eg: 1.00.02
-   ----- --
-    |    |
-    |    -- this will increase with bug fixes/enhancements to the driver
-    |-- this is the version of the PCC specification the driver adheres to
-
-
-The following is a brief discussion on some of the fields exported via the
-/sys filesystem and how their values are affected by the PCC driver:
-
-2.1 scaling_available_frequencies:
-----------------------------------
-scaling_available_frequencies is not created in /sys. No intermediate
-frequencies need to be listed because the BIOS will try to achieve any
-frequency, within limits, requested by the governor. A frequency does not have
-to be strictly associated with a P-state.
-
-2.2 cpuinfo_transition_latency:
--------------------------------
-The cpuinfo_transition_latency field is 0. The PCC specification does
-not include a field to expose this value currently.
-
-2.3 cpuinfo_cur_freq:
----------------------
-A) Often cpuinfo_cur_freq will show a value different than what is declared
-in the scaling_available_frequencies or scaling_cur_freq, or scaling_max_freq.
-This is due to "turbo boost" available on recent Intel processors. If certain
-conditions are met the BIOS can achieve a slightly higher speed than requested
-by OSPM. An example:
-
-scaling_cur_freq       : 2933000
-cpuinfo_cur_freq       : 3196000
-
-B) There is a round-off error associated with the cpuinfo_cur_freq value.
-Since the driver obtains the current frequency as a "percentage" (%) of the
-nominal frequency from the BIOS, sometimes, the values displayed by
-scaling_cur_freq and cpuinfo_cur_freq may not match. An example:
-
-scaling_cur_freq       : 1600000
-cpuinfo_cur_freq       : 1583000
-
-In this example, the nominal frequency is 2933 MHz. The driver obtains the
-current frequency, cpuinfo_cur_freq, as 54% of the nominal frequency:
-
-       54% of 2933 MHz = 1583 MHz
-
-Nominal frequency is the maximum frequency of the processor, and it usually
-corresponds to the frequency of the P0 P-state.
-
-2.4 related_cpus:
------------------
-The related_cpus field is identical to affected_cpus.
-
-affected_cpus  : 4
-related_cpus   : 4
-
-Currently, the PCC driver does not evaluate _PSD. The platforms that support
-PCC do not implement SW_ALL. So OSPM doesn't need to perform any coordination
-to ensure that the same frequency is requested of all dependent CPUs.
-
-3. Caveats:
------------
-The "cpufreq_stats" module in its present form cannot be loaded and
-expected to work with the PCC driver. Since the "cpufreq_stats" module
-provides information wrt each P-state, it is not applicable to the PCC driver.
diff --git a/Documentation/debugging-modules.txt b/Documentation/debugging-modules.txt
deleted file mode 100644 (file)
index 172ad4a..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Debugging Modules after 2.6.3
------------------------------
-
-In almost all distributions, the kernel asks for modules which don't
-exist, such as "net-pf-10" or whatever.  Changing "modprobe -q" to
-"succeed" in this case is hacky and breaks some setups, and also we
-want to know if it failed for the fallback code for old aliases in
-fs/char_dev.c, for example.
-
-In the past a debugging message which would fill people's logs was
-emitted.  This debugging message has been removed.  The correct way
-of debugging module problems is something like this:
-
-echo '#! /bin/sh' > /tmp/modprobe
-echo 'echo "$@" >> /tmp/modprobe.log' >> /tmp/modprobe
-echo 'exec /sbin/modprobe "$@"' >> /tmp/modprobe
-chmod a+x /tmp/modprobe
-echo /tmp/modprobe > /proc/sys/kernel/modprobe
-
-Note that the above applies only when the *kernel* is requesting
-that the module be loaded -- it won't have any effect if that module
-is being loaded explicitly using "modprobe" from userspace.
index 46aae52..7bd0135 100644 (file)
@@ -203,7 +203,7 @@ Cause
     may not correctly copy files from sysfs.
 
 Solution
-    Use ``cat``' to read ``.gcda`` files and ``cp -d`` to copy links.
+    Use ``cat`` to read ``.gcda`` files and ``cp -d`` to copy links.
     Alternatively use the mechanism shown in Appendix B.
 
 
index 3a289e8..fce2628 100644 (file)
@@ -8,7 +8,8 @@ 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
 user-space applications.
-Kmemleak is supported on x86, arm, powerpc, sparc, sh, microblaze, ppc, mips, s390 and tile.
+Kmemleak is supported on x86, arm, arm64, powerpc, sparc, sh, microblaze, mips,
+s390, nds32, arc and xtensa.
 
 Usage
 -----
index 7cd56a1..607758a 100644 (file)
@@ -551,6 +551,7 @@ options to your ``.config``:
 Once the kernel is built and installed, a simple
 
 .. code-block:: bash
+
        modprobe example-test
 
 ...will run the tests.
index f493d69..dc102c4 100644 (file)
@@ -102,7 +102,7 @@ Required sub-node properties:
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 [2] Documentation/devicetree/bindings/power/power-domain.yaml
 [3] Documentation/devicetree/bindings/thermal/thermal.txt
-[4] Documentation/devicetree/bindings/sram/sram.txt
+[4] Documentation/devicetree/bindings/sram/sram.yaml
 [5] Documentation/devicetree/bindings/reset/reset.txt
 
 Example:
index 7b83ef4..dd04d9d 100644 (file)
@@ -109,7 +109,7 @@ Required properties:
 [0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 [2] Documentation/devicetree/bindings/thermal/thermal.txt
-[3] Documentation/devicetree/bindings/sram/sram.txt
+[3] Documentation/devicetree/bindings/sram/sram.yaml
 [4] Documentation/devicetree/bindings/power/power-domain.yaml
 
 Example:
index b82b6a0..8c7a490 100644 (file)
@@ -62,7 +62,7 @@ Timer node:
 
 Syscon reboot node:
 
-See Documentation/devicetree/bindings/power/reset/syscon-reboot.txt for the
+See Documentation/devicetree/bindings/power/reset/syscon-reboot.yaml for the
 detailed list of properties, the two values defined below are specific to the
 BCM6328-style timer:
 
index 7a9c3ce..0d5b610 100644 (file)
@@ -216,7 +216,7 @@ properties:
     $ref: '/schemas/types.yaml#/definitions/phandle-array'
     description: |
       List of phandles to idle state nodes supported
-      by this cpu (see ./idle-states.txt).
+      by this cpu (see ./idle-states.yaml).
 
   capacity-dmips-mhz:
     $ref: '/schemas/types.yaml#/definitions/uint32'
index a8e0b4a..0e17e1f 100644 (file)
@@ -160,7 +160,7 @@ properties:
         items:
           - enum:
               - armadeus,imx6dl-apf6      # APF6 (Solo) SoM
-              - armadeus,imx6dl-apf6dldev # APF6 (Solo) SoM on APF6Dev board
+              - armadeus,imx6dl-apf6dev   # APF6 (Solo) SoM on APF6Dev board
               - eckelmann,imx6dl-ci4x10
               - emtrion,emcon-mx6         # emCON-MX6S or emCON-MX6DL SoM
               - emtrion,emcon-mx6-avari   # emCON-MX6S or emCON-MX6DL SoM on Avari Base
index 115c5be..8defacc 100644 (file)
@@ -1,7 +1,7 @@
 * Hisilicon Hi3519 System Controller Block
 
 This bindings use the following binding:
-Documentation/devicetree/bindings/mfd/syscon.txt
+Documentation/devicetree/bindings/mfd/syscon.yaml
 
 Required properties:
 - compatible: "hisilicon,hi3519-sysctrl".
index 06df04c..6ce0b21 100644 (file)
@@ -81,4 +81,4 @@ Example:
                };
        };
 
-[1]. Documentation/devicetree/bindings/arm/idle-states.txt
+[1]. Documentation/devicetree/bindings/arm/idle-states.yaml
index f301e63..e41490e 100644 (file)
@@ -17,7 +17,7 @@ am335x and am437x only:
 - pm-sram: Phandles to ocmcram nodes to be used for power management.
           First should be type 'protect-exec' for the driver to use to copy
           and run PM functions, second should be regular pool to be used for
-          data region for code. See Documentation/devicetree/bindings/sram/sram.txt
+          data region for code. See Documentation/devicetree/bindings/sram/sram.yaml
           for more details.
 
 Examples:
index 8ef8542..5e66934 100644 (file)
@@ -100,13 +100,14 @@ properties:
       bindings in [1]) must specify this property.
 
       [1] Kernel documentation - ARM idle states bindings
-        Documentation/devicetree/bindings/arm/idle-states.txt
-
-  "#power-domain-cells":
-    description:
-      The number of cells in a PM domain specifier as per binding in [3].
-      Must be 0 as to represent a single PM domain.
+        Documentation/devicetree/bindings/arm/idle-states.yaml
 
+patternProperties:
+  "^power-domain-":
+    allOf:
+      - $ref: "../power/power-domain.yaml#"
+    type: object
+    description: |
       ARM systems can have multiple cores, sometimes in an hierarchical
       arrangement. This often, but not always, maps directly to the processor
       power topology of the system. Individual nodes in a topology have their
@@ -122,14 +123,8 @@ properties:
       helps to implement support for OSI mode and OS implementations may choose
       to mandate it.
 
-      [3] Documentation/devicetree/bindings/power/power_domain.txt
-      [4] Documentation/devicetree/bindings/power/domain-idle-state.txt
-
-  power-domains:
-    $ref: '/schemas/types.yaml#/definitions/phandle-array'
-    description:
-      List of phandles and PM domain specifiers, as defined by bindings of the
-      PM domain provider.
+      [3] Documentation/devicetree/bindings/power/power-domain.yaml
+      [4] Documentation/devicetree/bindings/power/domain-idle-state.yaml
 
 required:
   - compatible
@@ -199,7 +194,7 @@ examples:
 
       CPU0: cpu@0 {
         device_type = "cpu";
-        compatible = "arm,cortex-a53", "arm,armv8";
+        compatible = "arm,cortex-a53";
         reg = <0x0>;
         enable-method = "psci";
         power-domains = <&CPU_PD0>;
@@ -208,7 +203,7 @@ examples:
 
       CPU1: cpu@1 {
         device_type = "cpu";
-        compatible = "arm,cortex-a57", "arm,armv8";
+        compatible = "arm,cortex-a53";
         reg = <0x100>;
         enable-method = "psci";
         power-domains = <&CPU_PD1>;
@@ -224,6 +219,9 @@ examples:
           exit-latency-us = <10>;
           min-residency-us = <100>;
         };
+      };
+
+      domain-idle-states {
 
         CLUSTER_RET: cluster-retention {
           compatible = "domain-idle-state";
@@ -247,19 +245,19 @@ examples:
       compatible = "arm,psci-1.0";
       method = "smc";
 
-      CPU_PD0: cpu-pd0 {
+      CPU_PD0: power-domain-cpu0 {
         #power-domain-cells = <0>;
         domain-idle-states = <&CPU_PWRDN>;
         power-domains = <&CLUSTER_PD>;
       };
 
-      CPU_PD1: cpu-pd1 {
+      CPU_PD1: power-domain-cpu1 {
         #power-domain-cells = <0>;
         domain-idle-states =  <&CPU_PWRDN>;
         power-domains = <&CLUSTER_PD>;
       };
 
-      CLUSTER_PD: cluster-pd {
+      CLUSTER_PD: power-domain-cluster {
         #power-domain-cells = <0>;
         domain-idle-states = <&CLUSTER_RET>, <&CLUSTER_PWRDN>;
       };
index 68917bb..55f7938 100644 (file)
@@ -52,7 +52,7 @@ required:
 
 examples:
   - |
-    mlahb: ahb {
+    mlahb: ahb@38000000 {
       compatible = "st,mlahb", "simple-bus";
       #address-cells = <1>;
       #size-cells = <1>;
index 9fe11ce..8097361 100644 (file)
@@ -70,7 +70,6 @@ examples:
         #size-cells = <0>;
 
         pmic@3e3 {
-            compatible = "...";
             reg = <0x3e3>;
 
             /* ... */
index 69cfa4a..c604822 100644 (file)
@@ -40,7 +40,7 @@ additionalProperties: false
 
 examples:
   - |
-    osc24M: clk@01c20050 {
+    osc24M: clk@1c20050 {
         #clock-cells = <0>;
         compatible = "allwinner,sun4i-a10-osc-clk";
         reg = <0x01c20050 0x4>;
index 07f38de..43963c3 100644 (file)
@@ -41,7 +41,7 @@ additionalProperties: false
 
 examples:
   - |
-    clk@0600005c {
+    clk@600005c {
         #clock-cells = <0>;
         compatible = "allwinner,sun9i-a80-gt-clk";
         reg = <0x0600005c 0x4>;
index 17f8717..3647007 100644 (file)
@@ -42,7 +42,7 @@ properties:
       be part of GCC and hence the TSENS properties can also be part
       of the GCC/clock-controller node.
       For more details on the TSENS properties please refer
-      Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+      Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
 
   nvmem-cell-names:
     minItems: 1
index 33c7842..8b9a8f3 100644 (file)
@@ -23,6 +23,8 @@ properties:
       - items:
         - const: allwinner,sun7i-a20-crypto
         - const: allwinner,sun4i-a10-crypto
+      - items:
+        - const: allwinner,sun8i-a33-crypto
 
   reg:
     maxItems: 1
index 5d5d396..6009324 100644 (file)
@@ -49,11 +49,7 @@ examples:
         resets = <&tcon_ch0_clk 0>;
 
         port {
-            #address-cells = <1>;
-            #size-cells = <0>;
-
-            tve0_in_tcon0: endpoint@0 {
-                reg = <0>;
+            tve0_in_tcon0: endpoint {
                 remote-endpoint = <&tcon0_out_tve0>;
             };
         };
index 6d72b3d..c211038 100644 (file)
@@ -79,21 +79,15 @@ examples:
           #size-cells = <0>;
 
           anx6345_in: port@0 {
-            #address-cells = <1>;
-            #size-cells = <0>;
             reg = <0>;
-            anx6345_in_tcon0: endpoint@0 {
-              reg = <0>;
+            anx6345_in_tcon0: endpoint {
               remote-endpoint = <&tcon0_out_anx6345>;
             };
           };
 
           anx6345_out: port@1 {
-            #address-cells = <1>;
-            #size-cells = <0>;
             reg = <1>;
-            anx6345_out_panel: endpoint@0 {
-              reg = <0>;
+            anx6345_out_panel: endpoint {
               remote-endpoint = <&panel_in_edp>;
             };
           };
index 0c0970c..883bcb2 100644 (file)
@@ -6,16 +6,22 @@ Required properties:
 
 Optional properties:
 - label: a symbolic name for the connector
+- sdtv-standards: limit the supported TV standards on a connector to the given
+                  ones. If not specified all TV standards are allowed.
+                  Possible TV standards are defined in
+                  include/dt-bindings/display/sdtv-standards.h.
 
 Required nodes:
 - Video port for TV input
 
 Example
 -------
+#include <dt-bindings/display/sdtv-standards.h>
 
 tv: connector {
        compatible = "composite-video-connector";
        label = "tv";
+       sdtv-standards = <(SDTV_STD_PAL | SDTV_STD_NTSC)>;
 
        port {
                tv_connector_in: endpoint {
index 4ebcea7..a614644 100644 (file)
@@ -37,6 +37,8 @@ examples:
     dsi@ff450000 {
         #address-cells = <1>;
         #size-cells = <0>;
+        reg = <0xff450000 0x1000>;
+
         panel@0 {
             compatible = "leadtek,ltk500hd1829";
             reg = <0>;
index 186e5e1..22c91be 100644 (file)
@@ -37,6 +37,8 @@ examples:
     dsi@ff450000 {
         #address-cells = <1>;
         #size-cells = <0>;
+        reg = <0xff450000 0x1000>;
+
         panel@0 {
             compatible = "xinpeng,xpp055c272";
             reg = <0>;
index 678776b..1db608c 100644 (file)
@@ -174,10 +174,6 @@ examples:
       };
     };
 
-    soc@1c00000 {
-      lcdc0: lcdc@1c0c000 {
-        compatible = "allwinner,sun4i-a10-lcdc";
-      };
-    };
+    lcdc0: lcdc { };
 
 ...
index 7bf1bb4..aac617a 100644 (file)
@@ -37,7 +37,7 @@ Optional nodes:
    supports a single port with a single endpoint.
 
  - See also Documentation/devicetree/bindings/display/tilcdc/panel.txt and
-   Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting
+   Documentation/devicetree/bindings/display/bridge/ti,tfp410.txt for connecting
    tfp410 DVI encoder or lcd panel to lcdc
 
 [1] There is an errata about AM335x color wiring. For 16-bit color mode
index 8b5c346..34780d7 100644 (file)
@@ -143,7 +143,7 @@ examples:
             #size-cells = <2>;
             dma-coherent;
             dma-ranges;
-            ranges;
+            ranges = <0x0 0x30800000 0x0 0x30800000 0x0 0x05000000>;
 
             ti,sci-dev-id = <118>;
 
@@ -169,16 +169,4 @@ examples:
                 ti,sci-rm-range-rflow = <0x6>; /* GP RFLOW */
             };
         };
-
-        mcasp0: mcasp@02B00000 {
-            dmas = <&main_udmap 0xc400>, <&main_udmap 0x4400>;
-            dma-names = "tx", "rx";
-        };
-
-        crypto: crypto@4E00000 {
-            compatible = "ti,sa2ul-crypto";
-
-            dmas = <&main_udmap 0xc000>, <&main_udmap 0x4000>, <&main_udmap 0x4001>;
-            dma-names = "tx", "rx1", "rx2";
-        };
     };
diff --git a/Documentation/devicetree/bindings/edac/dmc-520.yaml b/Documentation/devicetree/bindings/edac/dmc-520.yaml
new file mode 100644 (file)
index 0000000..9272d2b
--- /dev/null
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/edac/dmc-520.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM DMC-520 EDAC bindings
+
+maintainers:
+  - Lei Wang <lewan@microsoft.com>
+
+description: |+
+  DMC-520 node is defined to describe DRAM error detection and correction.
+
+  https://static.docs.arm.com/100000/0200/corelink_dmc520_trm_100000_0200_01_en.pdf
+
+properties:
+  compatible:
+    items:
+      - const: brcm,dmc-520
+      - const: arm,dmc-520
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 10
+
+  interrupt-names:
+    minItems: 1
+    maxItems: 10
+    items:
+      enum:
+        - ram_ecc_errc
+        - ram_ecc_errd
+        - dram_ecc_errc
+        - dram_ecc_errd
+        - failed_access
+        - failed_prog
+        - link_err
+        - temperature_event
+        - arch_fsm
+        - phy_request
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+
+examples:
+  - |
+    dmc0: dmc@200000 {
+        compatible = "brcm,dmc-520", "arm,dmc-520";
+        reg = <0x200000 0x80000>;
+        interrupts = <0x0 0x349 0x4>, <0x0 0x34B 0x4>;
+        interrupt-names = "dram_ecc_errc", "dram_ecc_errd";
+    };
diff --git a/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml b/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml
new file mode 100644 (file)
index 0000000..893d81e
--- /dev/null
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0-or-later)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fsi/ibm,fsi2spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: IBM FSI-attached SPI controllers
+
+maintainers:
+ - Eddie James <eajames@linux.ibm.com>
+
+description: |
+  This binding describes an FSI CFAM engine called the FSI2SPI. Therefore this
+  node will always be a child of an FSI CFAM node; see fsi.txt for details on
+  FSI slave and CFAM nodes. This FSI2SPI engine provides access to a number of
+  SPI controllers.
+
+properties:
+  compatible:
+    enum:
+      - ibm,fsi2spi
+
+  reg:
+    items:
+      - description: FSI slave address
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    fsi2spi@1c00 {
+        compatible = "ibm,fsi2spi";
+        reg = <0x1c00 0x400>;
+    };
index 4ea6a87..e8b99ad 100644 (file)
@@ -84,31 +84,31 @@ examples:
     gpu_opp_table: opp_table0 {
       compatible = "operating-points-v2";
 
-      opp@533000000 {
+      opp-533000000 {
         opp-hz = /bits/ 64 <533000000>;
         opp-microvolt = <1250000>;
       };
-      opp@450000000 {
+      opp-450000000 {
         opp-hz = /bits/ 64 <450000000>;
         opp-microvolt = <1150000>;
       };
-      opp@400000000 {
+      opp-400000000 {
         opp-hz = /bits/ 64 <400000000>;
         opp-microvolt = <1125000>;
       };
-      opp@350000000 {
+      opp-350000000 {
         opp-hz = /bits/ 64 <350000000>;
         opp-microvolt = <1075000>;
       };
-      opp@266000000 {
+      opp-266000000 {
         opp-hz = /bits/ 64 <266000000>;
         opp-microvolt = <1025000>;
       };
-      opp@160000000 {
+      opp-160000000 {
         opp-hz = /bits/ 64 <160000000>;
         opp-microvolt = <925000>;
       };
-      opp@100000000 {
+      opp-100000000 {
         opp-hz = /bits/ 64 <100000000>;
         opp-microvolt = <912500>;
       };
index 36f59b3..8d966f3 100644 (file)
@@ -138,31 +138,31 @@ examples:
     gpu_opp_table: opp_table0 {
       compatible = "operating-points-v2";
 
-      opp@533000000 {
+      opp-533000000 {
         opp-hz = /bits/ 64 <533000000>;
         opp-microvolt = <1250000>;
       };
-      opp@450000000 {
+      opp-450000000 {
         opp-hz = /bits/ 64 <450000000>;
         opp-microvolt = <1150000>;
       };
-      opp@400000000 {
+      opp-400000000 {
         opp-hz = /bits/ 64 <400000000>;
         opp-microvolt = <1125000>;
       };
-      opp@350000000 {
+      opp-350000000 {
         opp-hz = /bits/ 64 <350000000>;
         opp-microvolt = <1075000>;
       };
-      opp@266000000 {
+      opp-266000000 {
         opp-hz = /bits/ 64 <266000000>;
         opp-microvolt = <1025000>;
       };
-      opp@160000000 {
+      opp-160000000 {
         opp-hz = /bits/ 64 <160000000>;
         opp-microvolt = <925000>;
       };
-      opp@100000000 {
+      opp-100000000 {
         opp-hz = /bits/ 64 <100000000>;
         opp-microvolt = <912500>;
       };
diff --git a/Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml b/Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml
new file mode 100644 (file)
index 0000000..57a240d
--- /dev/null
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright 2019 Analog Devices Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bindings/hwmon/adi,axi-fan-control.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AXI FAN Control Device Tree Bindings
+
+maintainers:
+  - Nuno Sá <nuno.sa@analog.com>
+
+description: |+
+  Bindings for the Analog Devices AXI FAN Control driver. Spefications of the
+  core can be found in:
+
+  https://wiki.analog.com/resources/fpga/docs/axi_fan_control
+
+properties:
+  compatible:
+    enum:
+        - adi,axi-fan-control-1.00.a
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  pulses-per-revolution:
+    description:
+      Value specifying the number of pulses per revolution of the controlled
+      FAN.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1, 2, 4]
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - interrupts
+  - pulses-per-revolution
+
+examples:
+  - |
+    fpga_axi: fpga-axi@0 {
+            #address-cells = <0x2>;
+            #size-cells = <0x1>;
+
+            axi_fan_control: axi-fan-control@80000000 {
+                    compatible = "adi,axi-fan-control-1.00.a";
+                    reg = <0x0 0x80000000 0x10000>;
+                    clocks = <&clk 71>;
+                    interrupts = <0 110 0>;
+                    pulses-per-revolution = <2>;
+            };
+    };
+...
diff --git a/Documentation/devicetree/bindings/hwmon/adt7475.yaml b/Documentation/devicetree/bindings/hwmon/adt7475.yaml
new file mode 100644 (file)
index 0000000..7698503
--- /dev/null
@@ -0,0 +1,84 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/adt7475.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ADT7475 hwmon sensor
+
+maintainers:
+  - Jean Delvare <jdelvare@suse.com>
+
+description: |
+  The ADT7473, ADT7475, ADT7476, and ADT7490 are thermal monitors and multiple
+  PWN fan controllers.
+
+  They support monitoring and controlling up to four fans (the ADT7490 can only
+  control up to three). They support reading a single on chip temperature
+  sensor and two off chip temperature sensors (the ADT7490 additionally
+  supports measuring up to three current external temperature sensors with
+  series resistance cancellation (SRC)).
+
+  Datasheets:
+  https://www.onsemi.com/pub/Collateral/ADT7473-D.PDF
+  https://www.onsemi.com/pub/Collateral/ADT7475-D.PDF
+  https://www.onsemi.com/pub/Collateral/ADT7476-D.PDF
+  https://www.onsemi.com/pub/Collateral/ADT7490-D.PDF
+
+  Description taken from onsemiconductors specification sheets, with minor
+  rephrasing.
+
+properties:
+  compatible:
+    enum:
+      - adi,adt7473
+      - adi,adt7475
+      - adi,adt7476
+      - adi,adt7490
+
+  reg:
+    maxItems: 1
+
+patternProperties:
+  "^adi,bypass-attenuator-in[0-4]$":
+    description: |
+      Configures bypassing the individual voltage input attenuator. If
+      set to 1 the attenuator is bypassed if set to 0 the attenuator is
+      not bypassed. If the property is absent then the attenuator
+      retains it's configuration from the bios/bootloader.
+    allOf:
+     - $ref: /schemas/types.yaml#/definitions/uint32
+     - enum: [0, 1]
+
+  "^adi,pwm-active-state$":
+    description: |
+      Integer array, represents the active state of the pwm outputs If set to 0
+      the pwm uses a logic low output for 100% duty cycle. If set to 1 the pwm
+      uses a logic high output for 100% duty cycle.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32-array
+      - minItems: 3
+        maxItems: 3
+        items:
+          enum: [0, 1]
+          default: 1
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      hwmon@2e {
+        compatible = "adi,adt7476";
+        reg = <0x2e>;
+        adi,bypass-attenuator-in0 = <1>;
+        adi,bypass-attenuator-in1 = <0>;
+        adi,pwm-active-state = <1 0 1>;
+      };
+    };
+
index b428a70..4e7f621 100644 (file)
@@ -2,20 +2,30 @@ ltc2978
 
 Required properties:
 - compatible: should contain one of:
+  * "lltc,ltc2972"
   * "lltc,ltc2974"
   * "lltc,ltc2975"
   * "lltc,ltc2977"
   * "lltc,ltc2978"
+  * "lltc,ltc2979"
   * "lltc,ltc2980"
   * "lltc,ltc3880"
   * "lltc,ltc3882"
   * "lltc,ltc3883"
+  * "lltc,ltc3884"
   * "lltc,ltc3886"
   * "lltc,ltc3887"
+  * "lltc,ltc3889"
+  * "lltc,ltc7880"
   * "lltc,ltm2987"
+  * "lltc,ltm4664"
   * "lltc,ltm4675"
   * "lltc,ltm4676"
+  * "lltc,ltm4677"
+  * "lltc,ltm4678"
+  * "lltc,ltm4680"
   * "lltc,ltm4686"
+  * "lltc,ltm4700"
 - reg: I2C slave address
 
 Optional properties:
@@ -25,13 +35,17 @@ Optional properties:
   standard binding for regulators; see regulator.txt.
 
 Valid names of regulators depend on number of supplies supported per device:
+  * ltc2972 vout0 - vout1
   * ltc2974, ltc2975 : vout0 - vout3
-  * ltc2977, ltc2980, ltm2987 : vout0 - vout7
+  * ltc2977, ltc2979, ltc2980, ltm2987 : vout0 - vout7
   * ltc2978 : vout0 - vout7
-  * ltc3880, ltc3882, ltc3886 : vout0 - vout1
+  * ltc3880, ltc3882, ltc3884, ltc3886, ltc3887, ltc3889 : vout0 - vout1
+  * ltc7880 : vout0 - vout1
   * ltc3883 : vout0
-  * ltm4676 : vout0 - vout1
-  * ltm4686 : vout0 - vout1
+  * ltm4664 : vout0 - vout1
+  * ltm4675, ltm4676, ltm4677, ltm4678 : vout0 - vout1
+  * ltm4680, ltm4686 : vout0 - vout1
+  * ltm4700 : vout0 - vout1
 
 Example:
 ltc2978@5e {
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7923.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7923.yaml
new file mode 100644 (file)
index 0000000..a11b918
--- /dev/null
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/adi,ad7923.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD7923 and similars with 4 and 8 Channel ADCs.
+
+maintainers:
+  - Michael Hennerich <michael.hennerich@analog.com>
+  - Patrick Vasseur <patrick.vasseur@c-s.fr>
+
+description: |
+  Analog Devices AD7904, AD7914, AD7923, AD7924 4 Channel ADCs, and AD7908,
+   AD7918, AD7928 8 Channels ADCs.
+
+  Specifications about the part can be found at:
+    https://www.analog.com/media/en/technical-documentation/data-sheets/AD7923.pdf
+    https://www.analog.com/media/en/technical-documentation/data-sheets/AD7904_7914_7924.pdf
+    https://www.analog.com/media/en/technical-documentation/data-sheets/AD7908_7918_7928.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,ad7904
+      - adi,ad7914
+      - adi,ad7923
+      - adi,ad7924
+      - adi,ad7908
+      - adi,ad7918
+      - adi,ad7928
+
+  reg:
+    maxItems: 1
+
+  refin-supply:
+    description: |
+      The regulator supply for ADC reference voltage.
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      ad7928: adc@0 {
+        compatible = "adi,ad7928";
+        reg = <0>;
+        spi-max-frequency = <25000000>;
+        refin-supply = <&adc_vref>;
+
+        #address-cells = <1>;
+        #size-cells = <0>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/iio/adc/max1363.txt b/Documentation/devicetree/bindings/iio/adc/max1363.txt
deleted file mode 100644 (file)
index 94a9011..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-* Maxim 1x3x/136x/116xx Analog to Digital Converter (ADC)
-
-The node for this driver must be a child node of a I2C controller, hence
-all mandatory properties for your controller must be specified. See directory:
-
-        Documentation/devicetree/bindings/i2c
-
-for more details.
-
-Required properties:
-  - compatible: Should be one of
-               "maxim,max1361"
-               "maxim,max1362"
-               "maxim,max1363"
-               "maxim,max1364"
-               "maxim,max1036"
-               "maxim,max1037"
-               "maxim,max1038"
-               "maxim,max1039"
-               "maxim,max1136"
-               "maxim,max1137"
-               "maxim,max1138"
-               "maxim,max1139"
-               "maxim,max1236"
-               "maxim,max1237"
-               "maxim,max1238"
-               "maxim,max1239"
-               "maxim,max11600"
-               "maxim,max11601"
-               "maxim,max11602"
-               "maxim,max11603"
-               "maxim,max11604"
-               "maxim,max11605"
-               "maxim,max11606"
-               "maxim,max11607"
-               "maxim,max11608"
-               "maxim,max11609"
-               "maxim,max11610"
-               "maxim,max11611"
-               "maxim,max11612"
-               "maxim,max11613"
-               "maxim,max11614"
-               "maxim,max11615"
-               "maxim,max11616"
-               "maxim,max11617"
-               "maxim,max11644"
-               "maxim,max11645"
-               "maxim,max11646"
-               "maxim,max11647"
-  - reg: Should contain the ADC I2C address
-
-Optional properties:
-  - vcc-supply: phandle to the regulator that provides power to the ADC.
-  - vref-supply: phandle to the regulator for ADC reference voltage.
-  - interrupts: IRQ line for the ADC. If not used the driver will use
-    polling.
-
-Example:
-adc: max11644@36 {
-       compatible = "maxim,max11644";
-       reg = <0x36>;
-       vref-supply = <&adc_vref>;
-};
diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1238.yaml
new file mode 100644 (file)
index 0000000..a0ebb46
--- /dev/null
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/maxim,max1238.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim MAX1238 and similar ADCs
+
+maintainers:
+  - Jonathan Cameron <jic23@kernel.org>
+
+description: |
+   Family of simple ADCs with i2c inteface and internal references.
+
+properties:
+  compatible:
+    enum:
+      - maxim,max1036
+      - maxim,max1037
+      - maxim,max1038
+      - maxim,max1039
+      - maxim,max1136
+      - maxim,max1137
+      - maxim,max1138
+      - maxim,max1139
+      - maxim,max1236
+      - maxim,max1237
+      - maxim,max1238
+      - maxim,max1239
+      - maxim,max11600
+      - maxim,max11601
+      - maxim,max11602
+      - maxim,max11603
+      - maxim,max11604
+      - maxim,max11605
+      - maxim,max11606
+      - maxim,max11607
+      - maxim,max11608
+      - maxim,max11609
+      - maxim,max11610
+      - maxim,max11611
+      - maxim,max11612
+      - maxim,max11613
+      - maxim,max11614
+      - maxim,max11615
+      - maxim,max11616
+      - maxim,max11617
+      - maxim,max11644
+      - maxim,max11645
+      - maxim,max11646
+      - maxim,max11647
+
+  reg:
+    maxItems: 1
+
+  vcc-supply: true
+  vref-supply:
+    description: Optional external reference.  If not supplied, internal
+      reference will be used.
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@36 {
+            compatible = "maxim,max1238";
+            reg = <0x36>;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max1363.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max1363.yaml
new file mode 100644 (file)
index 0000000..4837754
--- /dev/null
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/maxim,max1363.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim MAX1363 and similar ADCs
+
+maintainers:
+  - Jonathan Cameron <jic23@kernel.org>
+
+description: |
+   Family of ADCs with i2c inteface, internal references and threshold
+   monitoring.
+
+properties:
+  compatible:
+    enum:
+      - maxim,max1361
+      - maxim,max1362
+      - maxim,max1363
+      - maxim,max1364
+
+  reg:
+    maxItems: 1
+
+  vcc-supply: true
+  vref-supply:
+    description: Optional external reference.  If not supplied, internal
+      reference will be used.
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@36 {
+            compatible = "maxim,max1363";
+            reg = <0x36>;
+        };
+    };
+...
index eb939fe..ef8eeec 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
 - compatible: "nuvoton,npcm750-adc" for the NPCM7XX BMC.
 - reg: specifies physical base address and size of the registers.
 - interrupts: Contain the ADC interrupt with flags for falling edge.
+- resets : phandle to the reset control for this device.
 
 Optional properties:
 - clocks: phandle of ADC reference clock, in case the clock is not
@@ -21,4 +22,5 @@ adc: adc@f000c000 {
        reg = <0xf000c000 0x8>;
        interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
        clocks = <&clk NPCM7XX_CLK_ADC>;
+       resets = <&rstc NPCM7XX_RESET_IPSRST1 NPCM7XX_RESET_ADC>;
 };
index f46de17..cc3c8ea 100644 (file)
@@ -123,7 +123,7 @@ examples:
         samsung,syscon-phandle = <&pmu_system_controller>;
 
         /* NTC thermistor is a hwmon device */
-        ncp15wb473@0 {
+        ncp15wb473 {
             compatible = "murata,ncp15wb473";
             pullup-uv = <1800000>;
             pullup-ohm = <47000>;
diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
deleted file mode 100644 (file)
index 8de9331..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-STMicroelectronics STM32 ADC device driver
-
-STM32 ADC is a successive approximation analog-to-digital converter.
-It has several multiplexed input channels. Conversions can be performed
-in single, continuous, scan or discontinuous mode. Result of the ADC is
-stored in a left-aligned or right-aligned 32-bit data register.
-Conversions can be launched in software or using hardware triggers.
-
-The analog watchdog feature allows the application to detect if the input
-voltage goes beyond the user-defined, higher or lower thresholds.
-
-Each STM32 ADC block can have up to 3 ADC instances.
-
-Each instance supports two contexts to manage conversions, each one has its
-own configurable sequence and trigger:
-- regular conversion can be done in sequence, running in background
-- injected conversions have higher priority, and so have the ability to
-  interrupt regular conversion sequence (either triggered in SW or HW).
-  Regular sequence is resumed, in case it has been interrupted.
-
-Contents of a stm32 adc root node:
------------------------------------
-Required properties:
-- compatible: Should be one of:
-  "st,stm32f4-adc-core"
-  "st,stm32h7-adc-core"
-  "st,stm32mp1-adc-core"
-- reg: Offset and length of the ADC block register set.
-- interrupts: One or more interrupts for ADC block. Some parts like stm32f4
-  and stm32h7 share a common ADC interrupt line. stm32mp1 has two separate
-  interrupt lines, one for each ADC within ADC block.
-- clocks: Core can use up to two clocks, depending on part used:
-  - "adc" clock: for the analog circuitry, common to all ADCs.
-    It's required on stm32f4.
-    It's optional on stm32h7.
-  - "bus" clock: for registers access, common to all ADCs.
-    It's not present on stm32f4.
-    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>;
-- #size-cells = <0>;
-
-Optional properties:
-- A pinctrl state named "default" for each ADC channel may be defined to set
-  inX ADC pins in mode of operation for analog input on external pin.
-- booster-supply: Phandle to the embedded booster regulator that can be used
-  to supply ADC analog input switches on stm32h7 and stm32mp1.
-- vdd-supply: Phandle to the vdd input voltage. It can be used to supply ADC
-  analog input switches on stm32mp1.
-- st,syscfg: Phandle to system configuration controller. It can be used to
-  control the analog circuitry on stm32mp1.
-- st,max-clk-rate-hz: Allow to specify desired max clock rate used by analog
-  circuitry.
-
-Contents of a stm32 adc child node:
------------------------------------
-An ADC block node should contain at least one subnode, representing an
-ADC instance available on the machine.
-
-Required properties:
-- compatible: Should be one of:
-  "st,stm32f4-adc"
-  "st,stm32h7-adc"
-  "st,stm32mp1-adc"
-- reg: Offset of ADC instance in ADC block (e.g. may be 0x0, 0x100, 0x200).
-- clocks: Input clock private to this ADC instance. It's required only on
-  stm32f4, that has per instance clock input for registers access.
-- interrupts: IRQ Line for the ADC (e.g. may be 0 for adc@0, 1 for adc@100 or
-  2 for adc@200).
-- st,adc-channels: List of single-ended channels muxed for this ADC.
-  It can have up to 16 channels on stm32f4 or 20 channels on stm32h7, numbered
-  from 0 to 15 or 19 (resp. for in0..in15 or in0..in19).
-- st,adc-diff-channels: List of differential channels muxed for this ADC.
-  Depending on part used, some channels can be configured as differential
-  instead of single-ended (e.g. stm32h7). List here positive and negative
-  inputs pairs as <vinp vinn>, <vinp vinn>,... vinp and vinn are numbered
-  from 0 to 19 on stm32h7)
-  Note: At least one of "st,adc-channels" or "st,adc-diff-channels" is required.
-  Both properties can be used together. Some channels can be used as
-  single-ended and some other ones as differential (mixed). But channels
-  can't be configured both as single-ended and differential (invalid).
-- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
-  Documentation/devicetree/bindings/iio/iio-bindings.txt
-
-Optional properties:
-- dmas: Phandle to dma channel for this ADC instance.
-  See ../../dma/dma.txt for details.
-- dma-names: Must be "rx" when dmas property is being used.
-- assigned-resolution-bits: Resolution (bits) to use for conversions. Must
-  match device available resolutions:
-  * can be 6, 8, 10 or 12 on stm32f4
-  * can be 8, 10, 12, 14 or 16 on stm32h7
-  Default is maximum resolution if unset.
-- st,min-sample-time-nsecs: Minimum sampling time in nanoseconds.
-  Depending on hardware (board) e.g. high/low analog input source impedance,
-  fine tune of ADC sampling time may be recommended.
-  This can be either one value or an array that matches 'st,adc-channels' list,
-  to set sample time resp. for all channels, or independently for each channel.
-
-Example:
-       adc: adc@40012000 {
-               compatible = "st,stm32f4-adc-core";
-               reg = <0x40012000 0x400>;
-               interrupts = <18>;
-               clocks = <&rcc 0 168>;
-               clock-names = "adc";
-               vref-supply = <&reg_vref>;
-               interrupt-controller;
-               pinctrl-names = "default";
-               pinctrl-0 = <&adc3_in8_pin>;
-
-               #interrupt-cells = <1>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-
-               adc@0 {
-                       compatible = "st,stm32f4-adc";
-                       #io-channel-cells = <1>;
-                       reg = <0x0>;
-                       clocks = <&rcc 0 168>;
-                       interrupt-parent = <&adc>;
-                       interrupts = <0>;
-                       st,adc-channels = <8>;
-                       dmas = <&dma2 0 0 0x400 0x0>;
-                       dma-names = "rx";
-                       assigned-resolution-bits = <8>;
-               };
-               ...
-               other adc child nodes follow...
-       };
-
-Example to setup:
-- channel 1 as single-ended
-- channels 2 & 3 as differential (with resp. 6 & 7 negative inputs)
-
-       adc: adc@40022000 {
-               compatible = "st,stm32h7-adc-core";
-               ...
-               adc1: adc@0 {
-                       compatible = "st,stm32h7-adc";
-                       ...
-                       st,adc-channels = <1>;
-                       st,adc-diff-channels = <2 6>, <3 7>;
-               };
-       };
diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml
new file mode 100644 (file)
index 0000000..933ba37
--- /dev/null
@@ -0,0 +1,458 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/bindings/iio/adc/st,stm32-adc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: STMicroelectronics STM32 ADC bindings
+
+description: |
+  STM32 ADC is a successive approximation analog-to-digital converter.
+  It has several multiplexed input channels. Conversions can be performed
+  in single, continuous, scan or discontinuous mode. Result of the ADC is
+  stored in a left-aligned or right-aligned 32-bit data register.
+  Conversions can be launched in software or using hardware triggers.
+
+  The analog watchdog feature allows the application to detect if the input
+  voltage goes beyond the user-defined, higher or lower thresholds.
+
+  Each STM32 ADC block can have up to 3 ADC instances.
+
+maintainers:
+  - Fabrice Gasnier <fabrice.gasnier@st.com>
+
+properties:
+  compatible:
+    enum:
+      - st,stm32f4-adc-core
+      - st,stm32h7-adc-core
+      - st,stm32mp1-adc-core
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description: |
+      One or more interrupts for ADC block, depending on part used:
+        - stm32f4 and stm32h7 share a common ADC interrupt line.
+        - stm32mp1 has two separate interrupt lines, one for each ADC within
+          ADC block.
+    minItems: 1
+    maxItems: 2
+
+  clocks:
+    description: |
+      Core can use up to two clocks, depending on part used:
+        - "adc" clock: for the analog circuitry, common to all ADCs.
+          It's required on stm32f4.
+          It's optional on stm32h7 and stm32mp1.
+        - "bus" clock: for registers access, common to all ADCs.
+          It's not present on stm32f4.
+          It's required on stm32h7 and stm32mp1.
+
+  clock-names: true
+
+  st,max-clk-rate-hz:
+    description:
+      Allow to specify desired max clock rate used by analog circuitry.
+
+  vdda-supply:
+    description: Phandle to the vdda input analog voltage.
+
+  vref-supply:
+    description: Phandle to the vref input analog reference voltage.
+
+  booster-supply:
+    description:
+      Phandle to the embedded booster regulator that can be used to supply ADC
+      analog input switches on stm32h7 and stm32mp1.
+
+  vdd-supply:
+    description:
+      Phandle to the vdd input voltage. It can be used to supply ADC analog
+      input switches on stm32mp1.
+
+  st,syscfg:
+    description:
+      Phandle to system configuration controller. It can be used to control the
+      analog circuitry on stm32mp1.
+    allOf:
+      - $ref: "/schemas/types.yaml#/definitions/phandle-array"
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 1
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: st,stm32f4-adc-core
+
+    then:
+      properties:
+        clocks:
+          maxItems: 1
+
+        clock-names:
+          const: adc
+
+        interrupts:
+          items:
+            - description: interrupt line common for all ADCs
+
+        st,max-clk-rate-hz:
+          minimum: 600000
+          maximum: 36000000
+          default: 36000000
+
+        booster-supply: false
+
+        vdd-supply: false
+
+        st,syscfg: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: st,stm32h7-adc-core
+
+    then:
+      properties:
+        clocks:
+          minItems: 1
+          maxItems: 2
+
+        clock-names:
+          items:
+            - const: bus
+            - const: adc
+          minItems: 1
+          maxItems: 2
+
+        interrupts:
+          items:
+            - description: interrupt line common for all ADCs
+
+        st,max-clk-rate-hz:
+          minimum: 120000
+          maximum: 36000000
+          default: 36000000
+
+        vdd-supply: false
+
+        st,syscfg: false
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: st,stm32mp1-adc-core
+
+    then:
+      properties:
+        clocks:
+          minItems: 1
+          maxItems: 2
+
+        clock-names:
+          items:
+            - const: bus
+            - const: adc
+          minItems: 1
+          maxItems: 2
+
+        interrupts:
+          items:
+            - description: interrupt line for ADC1
+            - description: interrupt line for ADC2
+
+        st,max-clk-rate-hz:
+          minimum: 120000
+          maximum: 36000000
+          default: 36000000
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - vdda-supply
+  - vref-supply
+  - interrupt-controller
+  - '#interrupt-cells'
+  - '#address-cells'
+  - '#size-cells'
+
+patternProperties:
+  "^adc@[0-9]+$":
+    type: object
+    description:
+      An ADC block node should contain at least one subnode, representing an
+      ADC instance available on the machine.
+
+    properties:
+      compatible:
+        enum:
+          - st,stm32f4-adc
+          - st,stm32h7-adc
+          - st,stm32mp1-adc
+
+      reg:
+        description: |
+          Offset of ADC instance in ADC block. Valid values are:
+            - 0x0:   ADC1
+            - 0x100: ADC2
+            - 0x200: ADC3 (stm32f4 only)
+        maxItems: 1
+
+      '#io-channel-cells':
+        const: 1
+
+      interrupts:
+        description: |
+          IRQ Line for the ADC instance. Valid values are:
+            - 0 for adc@0
+            - 1 for adc@100
+            - 2 for adc@200 (stm32f4 only)
+        maxItems: 1
+
+      clocks:
+        description:
+          Input clock private to this ADC instance. It's required only on
+          stm32f4, that has per instance clock input for registers access.
+        maxItems: 1
+
+      dmas:
+        description: RX DMA Channel
+        maxItems: 1
+
+      dma-names:
+        const: rx
+
+      assigned-resolution-bits:
+        description: |
+          Resolution (bits) to use for conversions:
+            - can be 6, 8, 10 or 12 on stm32f4
+            - can be 8, 10, 12, 14 or 16 on stm32h7 and stm32mp1
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+
+      st,adc-channels:
+        description: |
+          List of single-ended channels muxed for this ADC. It can have up to:
+            - 16 channels, numbered from 0 to 15 (for in0..in15) on stm32f4
+            - 20 channels, numbered from 0 to 19 (for in0..in19) on stm32h7 and
+              stm32mp1.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-array
+
+      st,adc-diff-channels:
+        description: |
+          List of differential channels muxed for this ADC. Some channels can
+          be configured as differential instead of single-ended on stm32h7 and
+          on stm32mp1. Positive and negative inputs pairs are listed:
+          <vinp vinn>, <vinp vinn>,... vinp and vinn are numbered from 0 to 19.
+
+          Note: At least one of "st,adc-channels" or "st,adc-diff-channels" is
+          required. Both properties can be used together. Some channels can be
+          used as single-ended and some other ones as differential (mixed). But
+          channels can't be configured both as single-ended and differential.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-matrix
+          - items:
+              items:
+                - description: |
+                    "vinp" indicates positive input number
+                  minimum: 0
+                  maximum: 19
+                - description: |
+                    "vinn" indicates negative input number
+                  minimum: 0
+                  maximum: 19
+
+      st,min-sample-time-nsecs:
+        description:
+          Minimum sampling time in nanoseconds. Depending on hardware (board)
+          e.g. high/low analog input source impedance, fine tune of ADC
+          sampling time may be recommended. This can be either one value or an
+          array that matches "st,adc-channels" and/or "st,adc-diff-channels"
+          list, to set sample time resp. for all channels, or independently for
+          each channel.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32-array
+
+    allOf:
+      - if:
+          properties:
+            compatible:
+              contains:
+                const: st,stm32f4-adc
+
+        then:
+          properties:
+            reg:
+              enum:
+                - 0x0
+                - 0x100
+                - 0x200
+
+            interrupts:
+              minimum: 0
+              maximum: 2
+
+            assigned-resolution-bits:
+              enum: [6, 8, 10, 12]
+              default: 12
+
+            st,adc-channels:
+              minItems: 1
+              maxItems: 16
+              items:
+                minimum: 0
+                maximum: 15
+
+            st,adc-diff-channels: false
+
+            st,min-sample-time-nsecs:
+              minItems: 1
+              maxItems: 16
+              items:
+                minimum: 80
+
+          required:
+            - clocks
+
+      - if:
+          properties:
+            compatible:
+              contains:
+                enum:
+                  - st,stm32h7-adc
+                  - st,stm32mp1-adc
+
+        then:
+          properties:
+            reg:
+              enum:
+                - 0x0
+                - 0x100
+
+            interrupts:
+              minimum: 0
+              maximum: 1
+
+            assigned-resolution-bits:
+              enum: [8, 10, 12, 14, 16]
+              default: 16
+
+            st,adc-channels:
+              minItems: 1
+              maxItems: 20
+              items:
+                minimum: 0
+                maximum: 19
+
+            st,min-sample-time-nsecs:
+              minItems: 1
+              maxItems: 20
+              items:
+                minimum: 40
+
+    additionalProperties: false
+
+    anyOf:
+      - required:
+          - st,adc-channels
+      - required:
+          - st,adc-diff-channels
+
+    required:
+      - compatible
+      - reg
+      - interrupts
+      - '#io-channel-cells'
+
+examples:
+  - |
+    // Example 1: with stm32f429, ADC1, single-ended channel 8
+      adc123: adc@40012000 {
+        compatible = "st,stm32f4-adc-core";
+        reg = <0x40012000 0x400>;
+        interrupts = <18>;
+        clocks = <&rcc 0 168>;
+        clock-names = "adc";
+        st,max-clk-rate-hz = <36000000>;
+        vdda-supply = <&vdda>;
+        vref-supply = <&vref>;
+        interrupt-controller;
+        #interrupt-cells = <1>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        adc@0 {
+          compatible = "st,stm32f4-adc";
+          #io-channel-cells = <1>;
+          reg = <0x0>;
+          clocks = <&rcc 0 168>;
+          interrupt-parent = <&adc123>;
+          interrupts = <0>;
+          st,adc-channels = <8>;
+          dmas = <&dma2 0 0 0x400 0x0>;
+          dma-names = "rx";
+          assigned-resolution-bits = <8>;
+        };
+        // ...
+        // other adc child nodes follow...
+      };
+
+  - |
+    // Example 2: with stm32mp157c to setup ADC1 with:
+    // - channels 0 & 1 as single-ended
+    // - channels 2 & 3 as differential (with resp. 6 & 7 negative inputs)
+      #include <dt-bindings/interrupt-controller/arm-gic.h>
+      #include <dt-bindings/clock/stm32mp1-clks.h>
+      adc12: adc@48003000 {
+        compatible = "st,stm32mp1-adc-core";
+        reg = <0x48003000 0x400>;
+        interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&rcc ADC12>, <&rcc ADC12_K>;
+        clock-names = "bus", "adc";
+        booster-supply = <&booster>;
+        vdd-supply = <&vdd>;
+        vdda-supply = <&vdda>;
+        vref-supply = <&vref>;
+        st,syscfg = <&syscfg>;
+        interrupt-controller;
+        #interrupt-cells = <1>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        adc@0 {
+          compatible = "st,stm32mp1-adc";
+          #io-channel-cells = <1>;
+          reg = <0x0>;
+          interrupt-parent = <&adc12>;
+          interrupts = <0>;
+          st,adc-channels = <0 1>;
+          st,adc-diff-channels = <2 6>, <3 7>;
+          st,min-sample-time-nsecs = <5000>;
+          dmas = <&dmamux1 9 0x400 0x05>;
+          dma-names = "rx";
+        };
+        // ...
+        // other adc child node follow...
+      };
+
+...
diff --git a/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml b/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml
new file mode 100644 (file)
index 0000000..1c6d496
--- /dev/null
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/amplifiers/adi,hmc425a.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: HMC425A 6-bit Digital Step Attenuator
+
+maintainers:
+- Michael Hennerich <michael.hennerich@analog.com>
+- Beniamin Bia <beniamin.bia@analog.com>
+
+description: |
+  Digital Step Attenuator IIO device with gpio interface.
+  HMC425A 0.5 dB LSB GaAs MMIC 6-BIT DIGITAL POSITIVE CONTROL ATTENUATOR, 2.2 - 8.0 GHz
+  https://www.analog.com/media/en/technical-documentation/data-sheets/hmc425A.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,hmc425a
+
+  vcc-supply: true
+
+  ctrl-gpios:
+    description:
+      Must contain an array of 6 GPIO specifiers, referring to the GPIO pins
+      connected to the control pins V1-V6.
+    minItems: 6
+    maxItems: 6
+
+required:
+  - compatible
+  - ctrl-gpios
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    gpio_hmc425a: hmc425a {
+      compatible = "adi,hmc425a";
+      ctrl-gpios = <&gpio 40 GPIO_ACTIVE_HIGH>,
+        <&gpio 39 GPIO_ACTIVE_HIGH>,
+        <&gpio 38 GPIO_ACTIVE_HIGH>,
+        <&gpio 37 GPIO_ACTIVE_HIGH>,
+        <&gpio 36 GPIO_ACTIVE_HIGH>,
+        <&gpio 35 GPIO_ACTIVE_HIGH>;
+      vcc-supply = <&foo>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt b/Documentation/devicetree/bindings/iio/chemical/atlas,ec-sm.txt
deleted file mode 100644 (file)
index f432059..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-* Atlas Scientific EC-SM OEM sensor
-
-http://www.atlas-scientific.com/_files/_datasheets/_oem/EC_oem_datasheet.pdf
-
-Required properties:
-
-  - compatible: must be "atlas,ec-sm"
-  - reg: the I2C address of the sensor
-  - interrupts: the sole interrupt generated by the device
-
-  Refer to interrupt-controller/interrupts.txt for generic interrupt client
-  node bindings.
-
-Example:
-
-atlas@64 {
-       compatible = "atlas,ec-sm";
-       reg = <0x64>;
-       interrupt-parent = <&gpio1>;
-       interrupts = <16 2>;
-};
diff --git a/Documentation/devicetree/bindings/iio/chemical/atlas,orp-sm.txt b/Documentation/devicetree/bindings/iio/chemical/atlas,orp-sm.txt
deleted file mode 100644 (file)
index af1f5a9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-* Atlas Scientific ORP-SM OEM sensor
-
-https://www.atlas-scientific.com/_files/_datasheets/_oem/ORP_oem_datasheet.pdf
-
-Required properties:
-
-  - compatible: must be "atlas,orp-sm"
-  - reg: the I2C address of the sensor
-  - interrupts: the sole interrupt generated by the device
-
-  Refer to interrupt-controller/interrupts.txt for generic interrupt client
-  node bindings.
-
-Example:
-
-atlas@66 {
-       compatible = "atlas,orp-sm";
-       reg = <0x66>;
-       interrupt-parent = <&gpio1>;
-       interrupts = <16 2>;
-};
diff --git a/Documentation/devicetree/bindings/iio/chemical/atlas,ph-sm.txt b/Documentation/devicetree/bindings/iio/chemical/atlas,ph-sm.txt
deleted file mode 100644 (file)
index 79d90f0..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-* Atlas Scientific pH-SM OEM sensor
-
-http://www.atlas-scientific.com/_files/_datasheets/_oem/pH_oem_datasheet.pdf
-
-Required properties:
-
-  - compatible: must be "atlas,ph-sm"
-  - reg: the I2C address of the sensor
-  - interrupts: the sole interrupt generated by the device
-
-  Refer to interrupt-controller/interrupts.txt for generic interrupt client
-  node bindings.
-
-Example:
-
-atlas@65 {
-       compatible = "atlas,ph-sm";
-       reg = <0x65>;
-       interrupt-parent = <&gpio1>;
-       interrupts = <16 2>;
-};
diff --git a/Documentation/devicetree/bindings/iio/chemical/atlas,sensor.yaml b/Documentation/devicetree/bindings/iio/chemical/atlas,sensor.yaml
new file mode 100644 (file)
index 0000000..edcd290
--- /dev/null
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/chemical/atlas,sensor.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Atlas Scientific OEM sensors
+
+maintainers:
+  - Matt Ranostay <matt.ranostay@konsulko.com>
+
+description: |
+  Atlas Scientific OEM sensors connected via I2C
+
+  Datasheets:
+    http://www.atlas-scientific.com/_files/_datasheets/_oem/DO_oem_datasheet.pdf
+    http://www.atlas-scientific.com/_files/_datasheets/_oem/EC_oem_datasheet.pdf
+    http://www.atlas-scientific.com/_files/_datasheets/_oem/ORP_oem_datasheet.pdf
+    http://www.atlas-scientific.com/_files/_datasheets/_oem/pH_oem_datasheet.pdf
+
+properties:
+  compatible:
+    enum:
+      - atlas,do-sm
+      - atlas,ec-sm
+      - atlas,orp-sm
+      - atlas,ph-sm
+
+  reg:
+     maxItems: 1
+
+  interrupts:
+     maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      atlas@66 {
+        compatible = "atlas,orp-sm";
+        reg = <0x66>;
+        interrupt-parent = <&gpio1>;
+        interrupts = <16 2>;
+      };
+    };
diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5770r.yaml
new file mode 100644 (file)
index 0000000..d9c25cf
--- /dev/null
@@ -0,0 +1,185 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2020 Analog Devices Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/bindings/iio/dac/adi,ad5770r.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Analog Devices AD5770R DAC device driver
+
+maintainers:
+  - Mircea Caprioru <mircea.caprioru@analog.com>
+
+description: |
+  Bindings for the Analog Devices AD5770R current DAC device. Datasheet can be
+  found here:
+    https://www.analog.com/media/en/technical-documentation/data-sheets/AD5770R.pdf
+
+properties:
+  compatible:
+    enum:
+      - adi,ad5770r
+
+  reg:
+    maxItems: 1
+
+  avdd-supply:
+    description:
+      AVdd voltage supply. Represents two different supplies in the datasheet
+      that are in fact the same.
+
+  iovdd-supply:
+    description:
+      Voltage supply for the chip interface.
+
+  vref-supply:
+    description: Specify the voltage of the external reference used.
+      Available reference options are 1.25 V or 2.5 V. If no
+      external reference declared then the device will use the
+      internal reference of 1.25 V.
+
+  adi,external-resistor:
+    description: Specify if an external 2.5k ohm resistor is used. If not
+      specified the device will use an internal 2.5k ohm resistor.
+      The precision resistor is used for reference current generation.
+    type: boolean
+
+  reset-gpios:
+    description: GPIO spec for the RESET pin. If specified, it will be
+      asserted during driver probe.
+    maxItems: 1
+
+  channel0:
+    description: Represents an external channel which are
+      connected to the DAC. Channel 0 can act both as a current
+      source and sink.
+    type: object
+
+    properties:
+      num:
+        description: This represents the channel number.
+        items:
+          const: 0
+
+      adi,range-microamp:
+          description: Output range of the channel.
+          oneOf:
+            - $ref: /schemas/types.yaml#/definitions/int32-array
+            - items:
+                - enum: [0 300000]
+                - enum: [-60000 0]
+                - enum: [-60000 300000]
+
+  channel1:
+    description: Represents an external channel which are
+      connected to the DAC.
+    type: object
+
+    properties:
+      num:
+        description: This represents the channel number.
+        items:
+          const: 1
+
+      adi,range-microamp:
+          description: Output range of the channel.
+          oneOf:
+            - $ref: /schemas/types.yaml#/definitions/uint32-array
+            - items:
+                - enum: [0 140000]
+                - enum: [0 250000]
+
+  channel2:
+    description: Represents an external channel which are
+      connected to the DAC.
+    type: object
+
+    properties:
+      num:
+        description: This represents the channel number.
+        items:
+          const: 2
+
+      adi,range-microamp:
+          description: Output range of the channel.
+          oneOf:
+            - $ref: /schemas/types.yaml#/definitions/uint32-array
+            - items:
+                - enum: [0 140000]
+                - enum: [0 250000]
+
+patternProperties:
+  "^channel@([3-5])$":
+    type: object
+    description: Represents the external channels which are connected to the DAC.
+    properties:
+      num:
+        description: This represents the channel number.
+        items:
+          minimum: 3
+          maximum: 5
+
+      adi,range-microamp:
+          description: Output range of the channel.
+          oneOf:
+            - $ref: /schemas/types.yaml#/definitions/uint32-array
+            - items:
+                - enum: [0 45000]
+                - enum: [0 100000]
+
+required:
+- reg
+- diff-channels
+- channel0
+- channel1
+- channel2
+- channel3
+- channel4
+- channel5
+
+examples:
+  - |
+        spi {
+                #address-cells = <1>;
+                #size-cells = <0>;
+
+                ad5770r@0 {
+                        compatible = "ad5770r";
+                        reg = <0>;
+                        spi-max-frequency = <1000000>;
+                        vref-supply = <&vref>;
+                        adi,external-resistor;
+                        reset-gpios = <&gpio 22 0>;
+
+                        channel@0 {
+                                num = <0>;
+                                adi,range-microamp = <(-60000) 300000>;
+                        };
+
+                        channel@1 {
+                                num = <1>;
+                                adi,range-microamp = <0 140000>;
+                        };
+
+                        channel@2 {
+                                num = <2>;
+                                adi,range-microamp = <0 55000>;
+                        };
+
+                        channel@3 {
+                                num = <3>;
+                                adi,range-microamp = <0 45000>;
+                        };
+
+                        channel@4 {
+                                num = <4>;
+                                adi,range-microamp = <0 45000>;
+                        };
+
+                        channel@5 {
+                                num = <5>;
+                                adi,range-microamp = <0 45000>;
+                        };
+                };
+        };
+...
index e0d5fea..338c322 100644 (file)
@@ -1,4 +1,4 @@
-Linear Technology LTC2632 DAC device driver
+Linear Technology LTC2632/2636 DAC
 
 Required properties:
  - compatible: Has to contain one of the following:
@@ -8,6 +8,12 @@ Required properties:
        lltc,ltc2632-h12
        lltc,ltc2632-h10
        lltc,ltc2632-h8
+       lltc,ltc2636-l12
+       lltc,ltc2636-l10
+       lltc,ltc2636-l8
+       lltc,ltc2636-h12
+       lltc,ltc2636-h10
+       lltc,ltc2636-h8
 
 Property rules described in Documentation/devicetree/bindings/spi/spi-bus.txt
 apply. In particular, "reg" and "spi-max-frequency" properties must be given.
index c5ee8a2..f2f6474 100644 (file)
@@ -4,6 +4,7 @@ http://www.invensense.com/mems/gyro/mpu6050.html
 
 Required properties:
  - compatible : should be one of
+               "invensense,mpu6000"
                "invensense,mpu6050"
                "invensense,mpu6500"
                "invensense,mpu6515"
@@ -11,7 +12,11 @@ Required properties:
                "invensense,mpu9250"
                "invensense,mpu9255"
                "invensense,icm20608"
+               "invensense,icm20609"
+               "invensense,icm20689"
                "invensense,icm20602"
+               "invensense,icm20690"
+               "invensense,iam20680"
  - reg : the I2C address of the sensor
  - interrupts: interrupt mapping for IRQ. It should be configured with flags
    IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
diff --git a/Documentation/devicetree/bindings/iio/light/dynaimage,al3010.yaml b/Documentation/devicetree/bindings/iio/light/dynaimage,al3010.yaml
new file mode 100644 (file)
index 0000000..f671edd
--- /dev/null
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/dynaimage,al3010.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Dyna-Image AL3010 sensor
+
+maintainers:
+  - David Heidelberg <david@ixit.cz>
+
+properties:
+  compatible:
+    const: dynaimage,al3010
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vdd-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>;
+
+        light-sensor@1c {
+            compatible = "dynaimage,al3010";
+            reg = <0x1c>;
+            vdd-supply = <&vdd_reg>;
+            interrupts = <0 99 4>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/iio/light/dynaimage,al3320a.yaml b/Documentation/devicetree/bindings/iio/light/dynaimage,al3320a.yaml
new file mode 100644 (file)
index 0000000..4973002
--- /dev/null
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/dynaimage,al3320a.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Dyna-Image AL3320A sensor
+
+maintainers:
+  - David Heidelberg <david@ixit.cz>
+
+properties:
+  compatible:
+    const: dynaimage,al3320a
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  vdd-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>;
+
+        light-sensor@1c {
+            compatible = "dynaimage,al3320a";
+            reg = <0x1c>;
+            vdd-supply = <&vdd_reg>;
+            interrupts = <0 99 4>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/iio/light/sharp,gp2ap002.yaml b/Documentation/devicetree/bindings/iio/light/sharp,gp2ap002.yaml
new file mode 100644 (file)
index 0000000..12aa16f
--- /dev/null
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/light/sharp,gp2ap002.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sharp GP2AP002A00F and GP2AP002S00F proximity and ambient light sensors
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+
+description: |
+  Proximity and ambient light sensor with IR LED for the proximity
+  sensing and an analog output for light intensity. The ambient light
+  sensor output is not available on the GP2AP002S00F variant.
+
+properties:
+  compatible:
+    enum:
+      - sharp,gp2ap002a00f
+      - sharp,gp2ap002s00f
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+    description: an interrupt for proximity, usually a GPIO line
+
+  vdd-supply:
+    description: VDD power supply a phandle to a regulator
+
+  vio-supply:
+    description: VIO power supply a phandle to a regulator
+
+  io-channels:
+    maxItems: 1
+    description: ALSOUT ADC channel to read the ambient light
+
+  io-channel-names:
+    const: alsout
+
+  sharp,proximity-far-hysteresis:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description: |
+      Hysteresis setting for "far" object detection, this setting is
+      device-unique and adjust the optical setting for proximity detection
+      of a "far away" object in front of the sensor.
+
+  sharp,proximity-close-hysteresis:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description: |
+      Hysteresis setting for "close" object detection, this setting is
+      device-unique and adjust the optical setting for proximity detection
+      of a "close" object in front of the sensor.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - sharp,proximity-far-hysteresis
+  - sharp,proximity-close-hysteresis
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      light-sensor@44 {
+        compatible = "sharp,gp2ap002a00f";
+        reg = <0x44>;
+        interrupts = <18 IRQ_TYPE_EDGE_FALLING>;
+        vdd-supply = <&vdd_regulator>;
+        vio-supply = <&vio_regulator>;
+        io-channels = <&adc_channel>;
+        io-channel-names = "alsout";
+        sharp,proximity-far-hysteresis = /bits/ 8 <0x2f>;
+        sharp,proximity-close-hysteresis = /bits/ 8 <0x0f>;
+      };
+    };
+
+...
index 4e80ea7..8afbac2 100644 (file)
@@ -51,6 +51,24 @@ properties:
       the time between two interrupts is measured in the driver.
     maxItems: 1
 
+  power-gpios:
+    description:
+      Definition of the GPIO for power management of connected peripheral
+      (output).
+      This GPIO can be used by the external hardware for power management.
+      When the device gets suspended it's switched off and when it resumes
+      it's switched on again. After some period of inactivity the driver
+      get suspended automatically (autosuspend feature).
+    maxItems: 1
+
+  startup-time-ms:
+    description:
+      This is the startup time the device needs after a resume to be up and
+      running.
+    minimum: 0
+    maximum: 1000
+    default: 100
+
 required:
   - compatible
   - trig-gpios
index ef2ae72..921172f 100644 (file)
@@ -5,6 +5,7 @@ Required properties:
     * "cypress,tm2-touchkey" - for the touchkey found on the tm2 board
     * "cypress,midas-touchkey" - for the touchkey found on midas boards
     * "cypress,aries-touchkey" - for the touchkey found on aries boards
+    * "coreriver,tc360-touchkey" - for the Coreriver TouchCore 360 touchkey
 - reg: I2C address of the chip.
 - interrupts: interrupt to which the chip is connected (see interrupt
        binding[0]).
index d7c3262..c99ed39 100644 (file)
@@ -62,7 +62,7 @@ required:
 
 examples:
 - |
-    i2c@00000000 {
+    i2c {
       #address-cells = <1>;
       #size-cells = <0>;
       gt928@5d {
index c864a46..f502121 100644 (file)
@@ -1,7 +1,7 @@
 Texas Instruments TWL family (twl4030) pwrbutton module
 
 This module is part of the TWL4030. For more details about the whole
-chip see Documentation/devicetree/bindings/mfd/twl-familly.txt.
+chip see Documentation/devicetree/bindings/mfd/twl-family.txt.
 
 This module provides a simple power button event via an Interrupt.
 
diff --git a/Documentation/devicetree/bindings/interrupt-controller/loongson,htpic.yaml b/Documentation/devicetree/bindings/interrupt-controller/loongson,htpic.yaml
new file mode 100644 (file)
index 0000000..c8861cb
--- /dev/null
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/interrupt-controller/loongson,htpic.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Loongson-3 HyperTransport Interrupt Controller
+
+maintainers:
+  - Jiaxun Yang <jiaxun.yang@flygoat.com>
+
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+
+description: |
+  This interrupt controller is found in the Loongson-3 family of chips to transmit
+  interrupts from PCH PIC connected on HyperTransport bus.
+
+properties:
+  compatible:
+    const: loongson,htpic-1.0
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    minItems: 1
+    maxItems: 4
+    description: |
+      Four parent interrupts that receive chained interrupts.
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    htintc: interrupt-controller@1fb000080 {
+      compatible = "loongson,htintc-1.0";
+      reg = <0xfb000080 0x40>;
+      interrupt-controller;
+      #interrupt-cells = <1>;
+
+      interrupt-parent = <&liointc>;
+      interrupts = <24 IRQ_TYPE_LEVEL_HIGH>,
+                    <25 IRQ_TYPE_LEVEL_HIGH>,
+                    <26 IRQ_TYPE_LEVEL_HIGH>,
+                    <27 IRQ_TYPE_LEVEL_HIGH>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/interrupt-controller/loongson,liointc.yaml b/Documentation/devicetree/bindings/interrupt-controller/loongson,liointc.yaml
new file mode 100644 (file)
index 0000000..9c6b91f
--- /dev/null
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/interrupt-controller/loongson,liointc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Loongson Local I/O Interrupt Controller
+
+maintainers:
+  - Jiaxun Yang <jiaxun.yang@flygoat.com>
+
+description: |
+  This interrupt controller is found in the Loongson-3 family of chips as the primary
+  package interrupt controller which can route local I/O interrupt to interrupt lines
+  of cores.
+
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: loongson,liointc-1.0
+      - const: loongson,liointc-1.0a
+
+  reg:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  interrupts:
+    description:
+      Interrupt source of the CPU interrupts.
+    minItems: 1
+    maxItems: 4
+
+  interrupt-names:
+    description: List of names for the parent interrupts.
+    items:
+      - const: int0
+      - const: int1
+      - const: int2
+      - const: int3
+    minItems: 1
+    maxItems: 4
+
+  '#interrupt-cells':
+    const: 2
+
+  'loongson,parent_int_map':
+    description: |
+      This property points how the children interrupts will be mapped into CPU
+      interrupt lines. Each cell refers to a parent interrupt line from 0 to 3
+      and each bit in the cell refers to a children interrupt fron 0 to 31.
+      If a CPU interrupt line didn't connected with liointc, then keep it's
+      cell with zero.
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32-array
+      - items:
+          minItems: 4
+          maxItems: 4
+
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - 'loongson,parent_int_map'
+
+
+examples:
+  - |
+    iointc: interrupt-controller@3ff01400 {
+      compatible = "loongson,liointc-1.0";
+      reg = <0x3ff01400 0x64>;
+
+      interrupt-controller;
+      #interrupt-cells = <2>;
+
+      interrupt-parent = <&cpuintc>;
+      interrupts = <2>, <3>;
+      interrupt-names = "int0", "int1";
+
+      loongson,parent_int_map = <0xf0ffffff>, /* int0 */
+                                <0x0f000000>, /* int1 */
+                                <0x00000000>, /* int2 */
+                                <0x00000000>; /* int3 */
+
+    };
+
+...
index d97d099..c60b994 100644 (file)
@@ -85,7 +85,7 @@ properties:
         # LED will act as a back-light, controlled by the framebuffer system
       - backlight
         # LED will turn on (but for leds-gpio see "default-state" property in
-        # Documentation/devicetree/bindings/leds/leds-gpio.txt)
+        # Documentation/devicetree/bindings/leds/leds-gpio.yaml)
       - default-on
         # LED "double" flashes at a load average based rate
       - heartbeat
index cf1ea40..c7af6f7 100644 (file)
@@ -5,7 +5,7 @@ where single bits in a certain register can turn on/off a
 single LED. The register bit LEDs appear as children to the
 syscon device, with the proper compatible string. For the
 syscon bindings see:
-Documentation/devicetree/bindings/mfd/syscon.txt
+Documentation/devicetree/bindings/mfd/syscon.yaml
 
 Each LED is represented as a sub-node of the syscon device. Each
 node's name represents the name of the corresponding LED.
diff --git a/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
new file mode 100644 (file)
index 0000000..75196d1
--- /dev/null
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/allwinner,sun8i-a83t-de2-rotate.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A83T DE2 Rotate Device Tree Bindings
+
+maintainers:
+  - Jernej Skrabec <jernej.skrabec@siol.net>
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <mripard@kernel.org>
+
+description: |-
+  The Allwinner A83T and A64 have a rotation core used for
+  rotating and flipping images.
+
+properties:
+  compatible:
+    oneOf:
+      - const: allwinner,sun8i-a83t-de2-rotate
+      - items:
+        - const: allwinner,sun50i-a64-de2-rotate
+        - const: allwinner,sun8i-a83t-de2-rotate
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Rotate interface clock
+      - description: Rotate module clock
+
+  clock-names:
+    items:
+      - const: bus
+      - const: mod
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/sun8i-de2.h>
+    #include <dt-bindings/reset/sun8i-de2.h>
+
+    rotate: rotate@1020000 {
+        compatible = "allwinner,sun8i-a83t-de2-rotate";
+        reg = <0x1020000 0x10000>;
+        interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&display_clocks CLK_BUS_ROT>,
+                 <&display_clocks CLK_ROT>;
+        clock-names = "bus",
+                      "mod";
+        resets = <&display_clocks RST_ROT>;
+    };
+
+...
index 2e40f70..8707df6 100644 (file)
@@ -17,7 +17,11 @@ description: |-
 
 properties:
   compatible:
-    const: allwinner,sun8i-h3-deinterlace
+    oneOf:
+      - const: allwinner,sun8i-h3-deinterlace
+      - items:
+        - const: allwinner,sun50i-a64-deinterlace
+        - const: allwinner,sun8i-h3-deinterlace
 
   reg:
     maxItems: 1
index ce28945..d2ca325 100644 (file)
@@ -1,11 +1,12 @@
 * Device tree bindings for Aspeed Video Engine
 
-The Video Engine (VE) embedded in the Aspeed AST2400 and AST2500 SOCs can
+The Video Engine (VE) embedded in the Aspeed AST2400/2500/2600 SOCs can
 capture and compress video data from digital or analog sources.
 
 Required properties:
  - compatible:         "aspeed,ast2400-video-engine" or
-                       "aspeed,ast2500-video-engine"
+                       "aspeed,ast2500-video-engine" or
+                       "aspeed,ast2600-video-engine"
  - reg:                        contains the offset and length of the VE memory region
  - clocks:             clock specifiers for the syscon clocks associated with
                        the VE (ordering must match the clock-names property)
diff --git a/Documentation/devicetree/bindings/media/i2c/imx219.yaml b/Documentation/devicetree/bindings/media/i2c/imx219.yaml
new file mode 100644 (file)
index 0000000..32d6b69
--- /dev/null
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/imx219.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor
+
+maintainers:
+  - Dave Stevenson <dave.stevenson@raspberrypi.com>
+
+description: |-
+  The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor
+  with an active array size of 3280H x 2464V. It is programmable through
+  I2C interface. The I2C address is fixed to 0x10 as per sensor data sheet.
+  Image data is sent through MIPI CSI-2, which is configured as either 2 or
+  4 data lanes.
+
+properties:
+  compatible:
+    const: sony,imx219
+
+  reg:
+    description: I2C device address
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  VDIG-supply:
+    description:
+      Digital I/O voltage supply, 1.8 volts
+
+  VANA-supply:
+    description:
+      Analog voltage supply, 2.8 volts
+
+  VDDL-supply:
+    description:
+      Digital core voltage supply, 1.2 volts
+
+  reset-gpios:
+    description: |-
+      Reference to the GPIO connected to the xclr pin, if any.
+      Must be released (set high) after all supplies are applied.
+
+  # See ../video-interfaces.txt for more details
+  port:
+    type: object
+    properties:
+      endpoint:
+        type: object
+        properties:
+          data-lanes:
+            description: |-
+              The sensor supports either two-lane, or four-lane operation.
+              If this property is omitted four-lane operation is assumed.
+              For two-lane operation the property must be set to <1 2>.
+            items:
+              - const: 1
+              - const: 2
+
+          clock-noncontinuous:
+            type: boolean
+            description: |-
+              MIPI CSI-2 clock is non-continuous if this property is present,
+              otherwise it's continuous.
+
+          link-frequencies:
+            allOf:
+              - $ref: /schemas/types.yaml#/definitions/uint64-array
+            description:
+              Allowed data bus frequencies.
+
+        required:
+          - link-frequencies
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - VANA-supply
+  - VDIG-supply
+  - VDDL-supply
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c0 {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        imx219: sensor@10 {
+            compatible = "sony,imx219";
+            reg = <0x10>;
+            clocks = <&imx219_clk>;
+            VANA-supply = <&imx219_vana>;   /* 2.8v */
+            VDIG-supply = <&imx219_vdig>;   /* 1.8v */
+            VDDL-supply = <&imx219_vddl>;   /* 1.2v */
+
+            port {
+                imx219_0: endpoint {
+                    remote-endpoint = <&csi1_ep>;
+                    data-lanes = <1 2>;
+                    clock-noncontinuous;
+                    link-frequencies = /bits/ 64 <456000000>;
+                };
+            };
+        };
+    };
+
+...
index 8c0fc1a..6c88ce8 100644 (file)
@@ -5,38 +5,150 @@ The TVP5150 and TVP5151 are video decoders that convert baseband NTSC and PAL
 with discrete syncs or 8-bit ITU-R BT.656 with embedded syncs output formats.
 
 Required Properties:
-- compatible: value must be "ti,tvp5150"
-- reg: I2C slave address
+====================
+- compatible:  Value must be "ti,tvp5150".
+- reg:         I2C slave address.
 
 Optional Properties:
-- pdn-gpios: phandle for the GPIO connected to the PDN pin, if any.
-- reset-gpios: phandle for the GPIO connected to the RESETB pin, if any.
+====================
+- pdn-gpios:   Phandle for the GPIO connected to the PDN pin, if any.
+- reset-gpios: Phandle for the GPIO connected to the RESETB pin, if any.
 
-The device node must contain one 'port' child node for its digital output
-video port, in accordance with the video interface bindings defined in
-Documentation/devicetree/bindings/media/video-interfaces.txt.
+The device node must contain one 'port' child node per device physical input
+and output port, in accordance with the video interface bindings defined in
+Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes
+are numbered as follows
 
-Required Endpoint Properties for parallel synchronization:
+         Name          Type            Port
+       --------------------------------------
+         AIP1A         sink            0
+         AIP1B         sink            1
+         Y-OUT         src             2
 
-- hsync-active: active state of the HSYNC signal. Must be <1> (HIGH).
-- vsync-active: active state of the VSYNC signal. Must be <1> (HIGH).
-- field-even-active: field signal level during the even field data
-  transmission. Must be <0>.
+The device node must contain at least one sink port and the src port. Each input
+port must be linked to an endpoint defined in [1]. The port/connector layout is
+as follows
 
-If none of hsync-active, vsync-active and field-even-active is specified,
-the endpoint is assumed to use embedded BT.656 synchronization.
+tvp-5150 port@0 (AIP1A)
+       endpoint@0 -----------> Comp0-Con  port
+       endpoint@1 ------+----> Svideo-Con port
+tvp-5150 port@1 (AIP1B)  |
+       endpoint@1 ------+
+       endpoint@0 -----------> Comp1-Con  port
+tvp-5150 port@2
+       endpoint (video bitstream output at YOUT[0-7] parallel bus)
 
-Example:
+Required Endpoint Properties for parallel synchronization on output port:
+=========================================================================
+
+- hsync-active:                Active state of the HSYNC signal. Must be <1> (HIGH).
+- vsync-active:                Active state of the VSYNC signal. Must be <1> (HIGH).
+- field-even-active:   Field signal level during the even field data
+                       transmission. Must be <0>.
+
+Note: Do not specify any of these properties if you want to use the embedded
+      BT.656 synchronization.
+
+Optional Connector Properties:
+==============================
+
+- sdtv-standards: Set the possible signals to which the hardware tries to lock
+                  instead of using the autodetection mechnism. Please look at
+                  [1] for more information.
+
+[1] Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt.
+
+Example - three input sources:
+#include <dt-bindings/display/sdtv-standards.h>
+
+comp_connector_0 {
+       compatible = "composite-video-connector";
+       label = "Composite0";
+       sdtv-standards = <SDTV_STD_PAL_M>; /* limit to pal-m signals */
+
+       port {
+               composite0_to_tvp5150: endpoint {
+                       remote-endpoint = <&tvp5150_to_composite0>;
+               };
+       };
+};
+
+comp_connector_1 {
+       compatible = "composite-video-connector";
+       label = "Composite1";
+       sdtv-standards = <SDTV_STD_NTSC_M>; /* limit to ntsc-m signals */
+
+       port {
+               composite1_to_tvp5150: endpoint {
+                       remote-endpoint = <&tvp5150_to_composite1>;
+               };
+       };
+};
+
+svideo_connector {
+       compatible = "svideo-connector";
+       label = "S-Video";
+
+       port {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               svideo_luma_to_tvp5150: endpoint@0 {
+                       reg = <0>;
+                       remote-endpoint = <&tvp5150_to_svideo_luma>;
+               };
+
+               svideo_chroma_to_tvp5150: endpoint@1 {
+                       reg = <1>;
+                       remote-endpoint = <&tvp5150_to_svideo_chroma>;
+               };
+       };
+};
 
 &i2c2 {
-       ...
        tvp5150@5c {
                compatible = "ti,tvp5150";
                reg = <0x5c>;
                pdn-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
                reset-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0>;
+
+                       tvp5150_to_composite0: endpoint@0 {
+                               reg = <0>;
+                               remote-endpoint = <&composite0_to_tvp5150>;
+                       };
+
+                       tvp5150_to_svideo_luma: endpoint@1 {
+                               reg = <1>;
+                               remote-endpoint = <&svideo_luma_to_tvp5150>;
+                       };
+               };
+
+               port@1 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <1>;
+
+                       tvp5150_to_composite1: endpoint@0 {
+                               reg = <0>;
+                                remote-endpoint = <&composite1_to_tvp5150>;
+                       };
+
+                       tvp5150_to_svideo_chroma: endpoint@1 {
+                               reg = <1>;
+                               remote-endpoint = <&svideo_chroma_to_tvp5150>;
+                       };
+               };
+
+               port@2 {
+                       reg = <2>;
 
-               port {
                        tvp5150_1: endpoint {
                                remote-endpoint = <&ccdc_ep>;
                        };
diff --git a/Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml b/Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml
new file mode 100644 (file)
index 0000000..a2d1cd7
--- /dev/null
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/nxp,imx8mq-vpu.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Hantro G1/G2 VPU codecs implemented on i.MX8MQ SoCs
+
+maintainers:
+  - Philipp Zabel <p.zabel@pengutronix.de>
+
+description:
+  Hantro G1/G2 video decode accelerators present on i.MX8MQ SoCs.
+
+properties:
+  compatible:
+    const: nxp,imx8mq-vpu
+
+  reg:
+    maxItems: 3
+
+  reg-names:
+    items:
+      - const: g1
+      - const: g2
+      - const: ctrl
+
+  interrupts:
+    maxItems: 2
+
+  interrupt-names:
+    items:
+      - const: g1
+      - const: g2
+
+  clocks:
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: g1
+      - const: g2
+      - const: bus
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - interrupt-names
+  - clocks
+  - clock-names
+
+examples:
+  - |
+        #include <dt-bindings/clock/imx8mq-clock.h>
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+        vpu: video-codec@38300000 {
+                compatible = "nxp,imx8mq-vpu";
+                reg = <0x38300000 0x10000>,
+                      <0x38310000 0x10000>,
+                      <0x38320000 0x10000>;
+                reg-names = "g1", "g2", "ctrl";
+                interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>,
+                             <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+                interrupt-names = "g1", "g2";
+                clocks = <&clk IMX8MQ_CLK_VPU_G1_ROOT>,
+                         <&clk IMX8MQ_CLK_VPU_G2_ROOT>,
+                         <&clk IMX8MQ_CLK_VPU_DEC_ROOT>;
+                clock-names = "g1", "g2", "bus";
+                power-domains = <&pgc_vpu>;
+        };
diff --git a/Documentation/devicetree/bindings/media/qcom,msm8916-venus.yaml b/Documentation/devicetree/bindings/media/qcom,msm8916-venus.yaml
new file mode 100644 (file)
index 0000000..f9606df
--- /dev/null
@@ -0,0 +1,119 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/qcom,msm8916-venus.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Qualcomm Venus video encode and decode accelerators
+
+maintainers:
+  - Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+description: |
+  The Venus IP is a video encode and decode accelerator present
+  on Qualcomm platforms
+
+properties:
+  compatible:
+    const: qcom,msm8916-venus
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: core
+      - const: iface
+      - const: bus
+
+  iommus:
+    maxItems: 1
+
+  memory-region:
+    maxItems: 1
+
+  video-decoder:
+    type: object
+
+    properties:
+      compatible:
+        const: "venus-decoder"
+
+    required:
+      - compatible
+
+    additionalProperties: false
+
+  video-encoder:
+    type: object
+
+    properties:
+      compatible:
+        const: "venus-encoder"
+
+    required:
+      - compatible
+
+    additionalProperties: false
+
+  video-firmware:
+    type: object
+
+    description: |
+      Firmware subnode is needed when the platform does not
+      have TrustZone.
+
+    properties:
+      iommus:
+        maxItems: 1
+
+    required:
+      - iommus
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - power-domains
+  - clocks
+  - clock-names
+  - iommus
+  - memory-region
+  - video-decoder
+  - video-encoder
+
+examples:
+  - |
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/clock/qcom,gcc-msm8916.h>
+
+        video-codec@1d00000 {
+                compatible = "qcom,msm8916-venus";
+                reg = <0x01d00000 0xff000>;
+                interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>,
+                        <&gcc GCC_VENUS0_AHB_CLK>,
+                        <&gcc GCC_VENUS0_AXI_CLK>;
+                clock-names = "core", "iface", "bus";
+                power-domains = <&gcc VENUS_GDSC>;
+                iommus = <&apps_iommu 5>;
+                memory-region = <&venus_mem>;
+
+                video-decoder {
+                        compatible = "venus-decoder";
+                };
+
+                video-encoder {
+                        compatible = "venus-encoder";
+                };
+        };
diff --git a/Documentation/devicetree/bindings/media/qcom,msm8996-venus.yaml b/Documentation/devicetree/bindings/media/qcom,msm8996-venus.yaml
new file mode 100644 (file)
index 0000000..fa0dc6c
--- /dev/null
@@ -0,0 +1,172 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/qcom,msm8996-venus.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Qualcomm Venus video encode and decode accelerators
+
+maintainers:
+  - Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+description: |
+  The Venus IP is a video encode and decode accelerator present
+  on Qualcomm platforms
+
+properties:
+  compatible:
+    const: qcom,msm8996-venus
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    maxItems: 4
+
+  clock-names:
+    items:
+      - const: core
+      - const: iface
+      - const: bus
+      - const: mbus
+
+  iommus:
+    maxItems: 20
+
+  memory-region:
+    maxItems: 1
+
+  video-decoder:
+    type: object
+
+    properties:
+      compatible:
+        const: venus-decoder
+
+      clocks:
+        maxItems: 1
+
+      clock-names:
+        items:
+          - const: core
+
+      power-domains:
+        maxItems: 1
+
+    required:
+      - compatible
+      - clocks
+      - clock-names
+      - power-domains
+
+    additionalProperties: false
+
+  video-encoder:
+    type: object
+
+    properties:
+      compatible:
+        const: venus-encoder
+
+      clocks:
+        maxItems: 1
+
+      clock-names:
+        items:
+          - const: core
+
+      power-domains:
+        maxItems: 1
+
+    required:
+      - compatible
+      - clocks
+      - clock-names
+      - power-domains
+
+    additionalProperties: false
+
+  video-firmware:
+    type: object
+
+    description: |
+      Firmware subnode is needed when the platform does not
+      have TrustZone.
+
+    properties:
+      iommus:
+        maxItems: 1
+
+    required:
+      - iommus
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - power-domains
+  - clocks
+  - clock-names
+  - iommus
+  - memory-region
+  - video-decoder
+  - video-encoder
+
+examples:
+  - |
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/clock/qcom,mmcc-msm8996.h>
+
+        video-codec@c00000 {
+                compatible = "qcom,msm8996-venus";
+                reg = <0x00c00000 0xff000>;
+                interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&mmcc VIDEO_CORE_CLK>,
+                         <&mmcc VIDEO_AHB_CLK>,
+                         <&mmcc VIDEO_AXI_CLK>,
+                         <&mmcc VIDEO_MAXI_CLK>;
+                clock-names = "core", "iface", "bus", "mbus";
+                power-domains = <&mmcc VENUS_GDSC>;
+                iommus =  <&venus_smmu 0x00>,
+                          <&venus_smmu 0x01>,
+                          <&venus_smmu 0x0a>,
+                          <&venus_smmu 0x07>,
+                          <&venus_smmu 0x0e>,
+                          <&venus_smmu 0x0f>,
+                          <&venus_smmu 0x08>,
+                          <&venus_smmu 0x09>,
+                          <&venus_smmu 0x0b>,
+                          <&venus_smmu 0x0c>,
+                          <&venus_smmu 0x0d>,
+                          <&venus_smmu 0x10>,
+                          <&venus_smmu 0x11>,
+                          <&venus_smmu 0x21>,
+                          <&venus_smmu 0x28>,
+                          <&venus_smmu 0x29>,
+                          <&venus_smmu 0x2b>,
+                          <&venus_smmu 0x2c>,
+                          <&venus_smmu 0x2d>,
+                          <&venus_smmu 0x31>;
+                memory-region = <&venus_mem>;
+
+                video-decoder {
+                        compatible = "venus-decoder";
+                        clocks = <&mmcc VIDEO_SUBCORE0_CLK>;
+                        clock-names = "core";
+                        power-domains = <&mmcc VENUS_CORE0_GDSC>;
+                };
+
+                video-encoder {
+                        compatible = "venus-encoder";
+                        clocks = <&mmcc VIDEO_SUBCORE1_CLK>;
+                        clock-names = "core";
+                        power-domains = <&mmcc VENUS_CORE1_GDSC>;
+                };
+        };
diff --git a/Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml b/Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml
new file mode 100644 (file)
index 0000000..764affa
--- /dev/null
@@ -0,0 +1,140 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/qcom,sc7180-venus.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Qualcomm Venus video encode and decode accelerators
+
+maintainers:
+  - Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+description: |
+  The Venus IP is a video encode and decode accelerator present
+  on Qualcomm platforms
+
+properties:
+  compatible:
+    const: qcom,sc7180-venus
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 2
+
+  power-domain-names:
+    items:
+      - const: venus
+      - const: vcodec0
+
+  clocks:
+    maxItems: 5
+
+  clock-names:
+    items:
+      - const: core
+      - const: iface
+      - const: bus
+      - const: vcodec0_core
+      - const: vcodec0_bus
+
+  iommus:
+    maxItems: 1
+
+  memory-region:
+    maxItems: 1
+
+  interconnects:
+    maxItems: 2
+
+  interconnect-names:
+    items:
+      - const: video-mem
+      - const: cpu-cfg
+
+  video-decoder:
+    type: object
+
+    properties:
+      compatible:
+        const: venus-decoder
+
+    required:
+      - compatible
+
+    additionalProperties: false
+
+  video-encoder:
+    type: object
+
+    properties:
+      compatible:
+        const: venus-encoder
+
+    required:
+      - compatible
+
+    additionalProperties: false
+
+  video-firmware:
+    type: object
+
+    description: |
+      Firmware subnode is needed when the platform does not
+      have TrustZone.
+
+    properties:
+      iommus:
+        maxItems: 1
+
+    required:
+      - iommus
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - power-domains
+  - power-domain-names
+  - clocks
+  - clock-names
+  - iommus
+  - memory-region
+  - video-decoder
+  - video-encoder
+
+examples:
+  - |
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/clock/qcom,videocc-sc7180.h>
+
+        venus: video-codec@aa00000 {
+                compatible = "qcom,sc7180-venus";
+                reg = <0 0x0aa00000 0 0xff000>;
+                interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+                power-domains = <&videocc VENUS_GDSC>,
+                                <&videocc VCODEC0_GDSC>;
+                power-domain-names = "venus", "vcodec0";
+                clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>,
+                         <&videocc VIDEO_CC_VENUS_AHB_CLK>,
+                         <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>,
+                         <&videocc VIDEO_CC_VCODEC0_CORE_CLK>,
+                         <&videocc VIDEO_CC_VCODEC0_AXI_CLK>;
+                clock-names = "core", "iface", "bus",
+                              "vcodec0_core", "vcodec0_bus";
+                iommus = <&apps_smmu 0x0c00 0x60>;
+                memory-region = <&venus_mem>;
+
+                video-decoder {
+                        compatible = "venus-decoder";
+                };
+
+                video-encoder {
+                        compatible = "venus-encoder";
+                };
+        };
diff --git a/Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml b/Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml
new file mode 100644 (file)
index 0000000..8552f4a
--- /dev/null
@@ -0,0 +1,140 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/qcom,sdm845-venus-v2.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Qualcomm Venus video encode and decode accelerators
+
+maintainers:
+  - Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+description: |
+  The Venus IP is a video encode and decode accelerator present
+  on Qualcomm platforms
+
+properties:
+  compatible:
+    const: qcom,sdm845-venus-v2
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 3
+
+  power-domain-names:
+    items:
+      - const: venus
+      - const: vcodec0
+      - const: vcodec1
+
+  clocks:
+    maxItems: 7
+
+  clock-names:
+    items:
+      - const: core
+      - const: iface
+      - const: bus
+      - const: vcodec0_core
+      - const: vcodec0_bus
+      - const: vcodec1_core
+      - const: vcodec1_bus
+
+  iommus:
+    maxItems: 2
+
+  memory-region:
+    maxItems: 1
+
+  video-core0:
+    type: object
+
+    properties:
+      compatible:
+        const: venus-decoder
+
+    required:
+      - compatible
+
+    additionalProperties: false
+
+  video-core1:
+    type: object
+
+    properties:
+      compatible:
+        const: venus-encoder
+
+    required:
+      - compatible
+
+    additionalProperties: false
+
+  video-firmware:
+    type: object
+
+    description: |
+      Firmware subnode is needed when the platform does not
+      have TrustZone.
+
+    properties:
+      iommus:
+        maxItems: 1
+
+    required:
+      - iommus
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - power-domains
+  - power-domain-names
+  - clocks
+  - clock-names
+  - iommus
+  - memory-region
+  - video-core0
+  - video-core1
+
+examples:
+  - |
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/clock/qcom,videocc-sdm845.h>
+
+        video-codec@aa00000 {
+                compatible = "qcom,sdm845-venus-v2";
+                reg = <0 0x0aa00000 0 0xff000>;
+                interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>,
+                         <&videocc VIDEO_CC_VENUS_AHB_CLK>,
+                         <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>,
+                         <&videocc VIDEO_CC_VCODEC0_CORE_CLK>,
+                         <&videocc VIDEO_CC_VCODEC0_AXI_CLK>,
+                         <&videocc VIDEO_CC_VCODEC1_CORE_CLK>,
+                         <&videocc VIDEO_CC_VCODEC1_AXI_CLK>;
+                clock-names = "core", "iface", "bus",
+                              "vcodec0_core", "vcodec0_bus",
+                              "vcodec1_core", "vcodec1_bus";
+                power-domains = <&videocc VENUS_GDSC>,
+                                <&videocc VCODEC0_GDSC>,
+                                <&videocc VCODEC1_GDSC>;
+                power-domain-names = "venus", "vcodec0", "vcodec1";
+                iommus = <&apps_smmu 0x10a0 0x8>,
+                         <&apps_smmu 0x10b0 0x0>;
+                memory-region = <&venus_mem>;
+
+                video-core0 {
+                        compatible = "venus-decoder";
+                };
+
+                video-core1 {
+                        compatible = "venus-encoder";
+                };
+        };
diff --git a/Documentation/devicetree/bindings/media/qcom,sdm845-venus.yaml b/Documentation/devicetree/bindings/media/qcom,sdm845-venus.yaml
new file mode 100644 (file)
index 0000000..05cabe4
--- /dev/null
@@ -0,0 +1,156 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/qcom,sdm845-venus.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Qualcomm Venus video encode and decode accelerators
+
+maintainers:
+  - Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+description: |
+  The Venus IP is a video encode and decode accelerator present
+  on Qualcomm platforms
+
+properties:
+  compatible:
+    const: qcom,sdm845-venus
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  clocks:
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: core
+      - const: iface
+      - const: bus
+
+  iommus:
+    maxItems: 2
+
+  memory-region:
+    maxItems: 1
+
+  video-core0:
+    type: object
+
+    properties:
+      compatible:
+        const: venus-decoder
+
+      clocks:
+        maxItems: 2
+
+      clock-names:
+        items:
+          - const: core
+          - const: bus
+
+      power-domains:
+        maxItems: 1
+
+    required:
+      - compatible
+      - clocks
+      - clock-names
+      - power-domains
+
+    additionalProperties: false
+
+  video-core1:
+    type: object
+
+    properties:
+      compatible:
+        const: venus-encoder
+
+      clocks:
+        maxItems: 2
+
+      clock-names:
+        items:
+          - const: core
+          - const: bus
+
+      power-domains:
+        maxItems: 1
+
+    required:
+      - compatible
+      - clocks
+      - clock-names
+      - power-domains
+
+    additionalProperties: false
+
+  video-firmware:
+    type: object
+
+    description: |
+      Firmware subnode is needed when the platform does not
+      have TrustZone.
+
+    properties:
+      iommus:
+        maxItems: 1
+
+    required:
+      - iommus
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - power-domains
+  - clocks
+  - clock-names
+  - iommus
+  - memory-region
+  - video-core0
+  - video-core1
+
+examples:
+  - |
+        #include <dt-bindings/interrupt-controller/arm-gic.h>
+        #include <dt-bindings/clock/qcom,videocc-sdm845.h>
+
+        video-codec@aa00000 {
+                compatible = "qcom,sdm845-venus";
+                reg = <0 0x0aa00000 0 0xff000>;
+                interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>,
+                         <&videocc VIDEO_CC_VENUS_AHB_CLK>,
+                         <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>;
+                clock-names = "core", "iface", "bus";
+                power-domains = <&videocc VENUS_GDSC>;
+                iommus = <&apps_smmu 0x10a0 0x8>,
+                         <&apps_smmu 0x10b0 0x0>;
+                memory-region = <&venus_mem>;
+
+                video-core0 {
+                        compatible = "venus-decoder";
+                        clocks = <&videocc VIDEO_CC_VCODEC0_CORE_CLK>,
+                                 <&videocc VIDEO_CC_VCODEC0_AXI_CLK>;
+                        clock-names = "core", "bus";
+                        power-domains = <&videocc VCODEC0_GDSC>;
+                };
+
+                video-core1 {
+                        compatible = "venus-encoder";
+                        clocks = <&videocc VIDEO_CC_VCODEC1_CORE_CLK>,
+                                 <&videocc VIDEO_CC_VCODEC1_AXI_CLK>;
+                        clock-names = "core", "bus";
+                        power-domains = <&videocc VCODEC1_GDSC>;
+                };
+        };
diff --git a/Documentation/devicetree/bindings/media/qcom,venus.txt b/Documentation/devicetree/bindings/media/qcom,venus.txt
deleted file mode 100644 (file)
index b602c4c..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-* Qualcomm Venus video encoder/decoder accelerators
-
-- compatible:
-       Usage: required
-       Value type: <stringlist>
-       Definition: Value should contain one of:
-               - "qcom,msm8916-venus"
-               - "qcom,msm8996-venus"
-               - "qcom,sdm845-venus"
-- reg:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: Register base address and length of the register map.
-- interrupts:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: Should contain interrupt line number.
-- clocks:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: A List of phandle and clock specifier pairs as listed
-                   in clock-names property.
-- clock-names:
-       Usage: required for msm8916
-       Value type: <stringlist>
-       Definition: Should contain the following entries:
-               - "core"        Core video accelerator clock
-               - "iface"       Video accelerator AHB clock
-               - "bus"         Video accelerator AXI clock
-- clock-names:
-       Usage: required for msm8996
-       Value type: <stringlist>
-       Definition: Should contain the following entries:
-               - "core"        Core video accelerator clock
-               - "iface"       Video accelerator AHB clock
-               - "bus"         Video accelerator AXI clock
-               - "mbus"        Video MAXI clock
-- power-domains:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: A phandle and power domain specifier pairs to the
-                   power domain which is responsible for collapsing
-                   and restoring power to the peripheral.
-- iommus:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: A list of phandle and IOMMU specifier pairs.
-- memory-region:
-       Usage: required
-       Value type: <phandle>
-       Definition: reference to the reserved-memory for the firmware
-                   memory region.
-
-* Subnodes
-The Venus video-codec node must contain two subnodes representing
-video-decoder and video-encoder, and one optional firmware subnode.
-Firmware subnode is needed when the platform does not have TrustZone.
-
-Every of video-encoder or video-decoder subnode should have:
-
-- compatible:
-       Usage: required
-       Value type: <stringlist>
-       Definition: Value should contain "venus-decoder" or "venus-encoder"
-- clocks:
-       Usage: required for msm8996
-       Value type: <prop-encoded-array>
-       Definition: A List of phandle and clock specifier pairs as listed
-                   in clock-names property.
-- clock-names:
-       Usage: required for msm8996
-       Value type: <stringlist>
-       Definition: Should contain the following entries:
-               - "core"        Subcore video accelerator clock
-
-- power-domains:
-       Usage: required for msm8996
-       Value type: <prop-encoded-array>
-       Definition: A phandle and power domain specifier pairs to the
-                   power domain which is responsible for collapsing
-                   and restoring power to the subcore.
-
-The firmware subnode must have:
-
-- iommus:
-       Usage: required
-       Value type: <prop-encoded-array>
-       Definition: A list of phandle and IOMMU specifier pairs.
-
-* An Example
-       video-codec@1d00000 {
-               compatible = "qcom,msm8916-venus";
-               reg = <0x01d00000 0xff000>;
-               interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>,
-                        <&gcc GCC_VENUS0_AHB_CLK>,
-                        <&gcc GCC_VENUS0_AXI_CLK>;
-               clock-names = "core", "iface", "bus";
-               power-domains = <&gcc VENUS_GDSC>;
-               iommus = <&apps_iommu 5>;
-               memory-region = <&venus_mem>;
-
-               video-decoder {
-                       compatible = "venus-decoder";
-                       clocks = <&mmcc VIDEO_SUBCORE0_CLK>;
-                       clock-names = "core";
-                       power-domains = <&mmcc VENUS_CORE0_GDSC>;
-               };
-
-               video-encoder {
-                       compatible = "venus-encoder";
-                       clocks = <&mmcc VIDEO_SUBCORE1_CLK>;
-                       clock-names = "core";
-                       power-domains = <&mmcc VENUS_CORE1_GDSC>;
-               };
-
-               video-firmware {
-                       iommus = <&apps_iommu 0x10b2 0x0>;
-               };
-       };
index a64ee03..b27c938 100644 (file)
@@ -143,6 +143,7 @@ properties:
           - rc-videomate-k100
           - rc-videomate-s350
           - rc-videomate-tv-pvr
+          - rc-videostrong-kii-pro
           - rc-wetek-hub
           - rc-wetek-play2
           - rc-winfast
index fd5276a..c53a8e5 100644 (file)
@@ -6,8 +6,9 @@ BitBLT, alpha blending and image blur/sharpness.
 
 Required properties:
 - compatible: value should be one of the following
-               "rockchip,rk3288-rga";
-               "rockchip,rk3399-rga";
+  "rockchip,rk3228-rga", "rockchip,rk3288-rga": for Rockchip RK3228
+  "rockchip,rk3288-rga": for Rockchip RK3288
+  "rockchip,rk3399-rga": for Rockchip RK3399
 
 - interrupts: RGA interrupt specifier.
 
index 1ea7841..5e06662 100644 (file)
@@ -177,7 +177,7 @@ examples:
         };
     };
 
-    i2c5: i2c@4807c000 {
+    i2c {
         clock-frequency = <400000>;
         #address-cells = <1>;
         #size-cells = <0>;
index 44d7146..63f674f 100644 (file)
@@ -32,7 +32,7 @@ Required only for "ti,emif-am3352" and "ti,emif-am4372":
 - sram                 : Phandles for generic sram driver nodes,
   first should be type 'protect-exec' for the driver to use to copy
   and run PM functions, second should be regular pool to be used for
-  data region for code. See Documentation/devicetree/bindings/sram/sram.txt
+  data region for code. See Documentation/devicetree/bindings/sram/sram.yaml
   for more details.
 
 Optional properties:
index 4a70f87..4803857 100644 (file)
@@ -97,14 +97,14 @@ examples:
             regulators {
                 compatible = "maxim,max77650-regulator";
 
-                max77650_ldo: regulator@0 {
+                max77650_ldo: regulator-ldo {
                     regulator-compatible = "ldo";
                     regulator-name = "max77650-ldo";
                     regulator-min-microvolt = <1350000>;
                     regulator-max-microvolt = <2937500>;
                 };
 
-                max77650_sbb0: regulator@1 {
+                max77650_sbb0: regulator-sbb0 {
                     regulator-compatible = "sbb0";
                     regulator-name = "max77650-sbb0";
                     regulator-min-microvolt = <800000>;
index 3c91ad4..b823b86 100644 (file)
@@ -61,6 +61,7 @@ Regulator nodes are identified by their compatible:
                    "qcom,rpm-pm8901-regulators"
                    "qcom,rpm-pm8921-regulators"
                    "qcom,rpm-pm8018-regulators"
+                   "qcom,rpm-smb208-regulators"
 
 - vdd_l0_l1_lvs-supply:
 - vdd_l2_l11_l12-supply:
@@ -171,6 +172,9 @@ pm8018:
        s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
        l12, l14, lvs1
 
+smb208:
+       s1a, s1b, s2a, s2b
+
 The content of each sub-node is defined by the standard binding for regulators -
 see regulator.txt - with additional custom properties described below:
 
index 4f62143..a5ced46 100644 (file)
@@ -26,8 +26,8 @@ Required properties:
             ldo6, ldo7, ldo8
 
 - xxx-supply: Input voltage supply regulator.
-  These entries are require if regulators are enabled for a device. Missing of these
-  properties can cause the regulator registration fails.
+  These entries are required if regulators are enabled for a device. Missing these
+  properties can cause the regulator registration to fail.
   If some of input supply is powered through battery or always-on supply then
   also it is require to have these parameters with proper node handle of always
   on power supply.
index 088eff9..e0f901e 100644 (file)
@@ -20,7 +20,7 @@ RAVE SP consists of the following sub-devices:
 Device                          Description
 ------                          -----------
 rave-sp-wdt                    : Watchdog
-rave-sp-nvmem                  : Interface to onborad EEPROM
+rave-sp-nvmem                  : Interface to onboard EEPROM
 rave-sp-backlight              : Display backlight
 rave-sp-hwmon                  : Interface to onboard hardware sensors
 rave-sp-leds                   : Interface to onboard LEDs
diff --git a/Documentation/devicetree/bindings/mips/loongson/devices.yaml b/Documentation/devicetree/bindings/mips/loongson/devices.yaml
new file mode 100644 (file)
index 0000000..74ed4e3
--- /dev/null
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mips/loongson/devices.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Loongson based Platforms Device Tree Bindings
+
+maintainers:
+  - Jiaxun Yang <jiaxun.yang@flygoat.com>
+description: |
+  Devices with a Loongson CPU shall have the following properties.
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+
+      - description: Generic Loongson3 Quad Core + RS780E
+        items:
+          - const: loongson,loongson3-4core-rs780e
+
+      - description: Generic Loongson3 Octa Core + RS780E
+        items:
+          - const: loongson,loongson3-8core-rs780e
+...
index bb7e896..9134e9b 100644 (file)
@@ -26,7 +26,7 @@ For generic IOMMU bindings, see
 Documentation/devicetree/bindings/iommu/iommu.txt.
 
 For arm-smmu binding, see:
-Documentation/devicetree/bindings/iommu/arm,smmu.txt.
+Documentation/devicetree/bindings/iommu/arm,smmu.yaml.
 
 Required properties:
 
index 3c0df40..8fded83 100644 (file)
@@ -370,6 +370,7 @@ examples:
     mmc3: mmc@1c12000 {
         #address-cells = <1>;
         #size-cells = <0>;
+        reg = <0x1c12000 0x200>;
         pinctrl-names = "default";
         pinctrl-0 = <&mmc3_pins_a>;
         vmmc-supply = <&reg_vmmc3>;
index f3893c4..d2eada5 100644 (file)
@@ -27,7 +27,7 @@ Required properties of NAND chips:
   - reg: shall contain the native Chip Select ids from 0 to max supported by
     the cadence nand flash controller
 
-See Documentation/devicetree/bindings/mtd/nand.txt for more details on
+See Documentation/devicetree/bindings/mtd/nand-controller.yaml for more details on
 generic bindings.
 
 Example:
index 48a7f91..88b57b0 100644 (file)
@@ -45,7 +45,7 @@ Optional properties:
   switch queue
 
 - resets: a single phandle and reset identifier pair. See
-  Documentation/devicetree/binding/reset/reset.txt for details.
+  Documentation/devicetree/bindings/reset/reset.txt for details.
 
 - reset-names: If the "reset" property is specified, this property should have
   the value "switch" to denote the switch reset line.
index 250f8d8..c00fb0d 100644 (file)
@@ -110,6 +110,13 @@ PROPERTIES
                Usage: required
                Definition: See soc/fsl/qman.txt and soc/fsl/bman.txt
 
+- fsl,erratum-a050385
+               Usage: optional
+               Value type: boolean
+               Definition: A boolean property. Indicates the presence of the
+               erratum A050385 which indicates that DMA transactions that are
+               split can result in a FMan lock.
+
 =============================================================================
 FMan MURAM Node
 
index b43c6c6..6598022 100644 (file)
@@ -76,6 +76,8 @@ examples:
       qfprom: eeprom@700000 {
           #address-cells = <1>;
           #size-cells = <1>;
+          reg = <0x00700000 0x100000>;
+
           wp-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>;
 
           /* ... */
index 4751029..64f0741 100644 (file)
@@ -19,7 +19,8 @@ In 'cpu' nodes:
 
 In 'operating-points-v2' table:
 - compatible: Should be
-       - 'operating-points-v2-kryo-cpu' for apq8096 and msm8996.
+       - 'operating-points-v2-kryo-cpu' for apq8096, msm8996, msm8974,
+                                            apq8064, ipq8064, msm8960 and ipq8074.
 
 Optional properties:
 --------------------
index 020ef9e..94ac236 100644 (file)
@@ -86,7 +86,7 @@ examples:
     #include <dt-bindings/clock/sun4i-a10-ccu.h>
     #include <dt-bindings/reset/sun4i-a10-ccu.h>
 
-    usbphy: phy@01c13400 {
+    usbphy: phy@1c13400 {
         #phy-cells = <1>;
         compatible = "allwinner,sun4i-a10-usb-phy";
         reg = <0x01c13400 0x10>, <0x01c14800 0x4>, <0x01c1c800 0x4>;
index 57d8603..9e32cb4 100644 (file)
@@ -14,6 +14,7 @@ properties:
   compatible:
     enum:
       - amlogic,meson-g12a-usb2-phy
+      - amlogic,meson-a1-usb2-phy
 
   reg:
     maxItems: 1
@@ -49,6 +50,19 @@ required:
   - reset-names
   - "#phy-cells"
 
+if:
+  properties:
+    compatible:
+      enum:
+        - amlogic,meson-a1-usb-ctrl
+
+then:
+  properties:
+    power-domains:
+      maxItems: 1
+  required:
+    - power-domains
+
 examples:
   - |
     phy@36000 {
diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-dp.txt b/Documentation/devicetree/bindings/phy/phy-cadence-dp.txt
deleted file mode 100644 (file)
index 7f49fd5..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-Cadence MHDP DisplayPort SD0801 PHY binding
-===========================================
-
-This binding describes the Cadence SD0801 PHY hardware included with
-the Cadence MHDP DisplayPort controller.
-
--------------------------------------------------------------------------------
-Required properties (controller (parent) node):
-- compatible   : Should be "cdns,dp-phy"
-- reg          : Defines the following sets of registers in the parent
-                 mhdp device:
-                       - Offset of the DPTX PHY configuration registers
-                       - Offset of the SD0801 PHY configuration registers
-- #phy-cells   : from the generic PHY bindings, must be 0.
-
-Optional properties:
-- num_lanes    : Number of DisplayPort lanes to use (1, 2 or 4)
-- max_bit_rate : Maximum DisplayPort link bit rate to use, in Mbps (2160,
-                 2430, 2700, 3240, 4320, 5400 or 8100)
--------------------------------------------------------------------------------
-
-Example:
-       dp_phy: phy@f0fb030a00 {
-               compatible = "cdns,dp-phy";
-               reg = <0xf0 0xfb030a00 0x0 0x00000040>,
-                     <0xf0 0xfb500000 0x0 0x00100000>;
-               num_lanes = <4>;
-               max_bit_rate = <8100>;
-               #phy-cells = <0>;
-       };
diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml
new file mode 100644 (file)
index 0000000..c779a3c
--- /dev/null
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/phy/phy-cadence-torrent.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Cadence Torrent SD0801 PHY binding for DisplayPort
+
+description:
+  This binding describes the Cadence SD0801 PHY (also known as Torrent PHY)
+  hardware included with the Cadence MHDP DisplayPort controller.
+
+maintainers:
+  - Swapnil Jakhade <sjakhade@cadence.com>
+  - Yuti Amonkar <yamonkar@cadence.com>
+
+properties:
+  compatible:
+    enum:
+      - cdns,torrent-phy
+      - ti,j721e-serdes-10g
+
+  '#address-cells':
+    const: 1
+
+  '#size-cells':
+    const: 0
+
+  clocks:
+    maxItems: 1
+    description:
+      PHY reference clock. Must contain an entry in clock-names.
+
+  clock-names:
+    const: refclk
+
+  reg:
+    minItems: 1
+    maxItems: 2
+    items:
+      - description: Offset of the Torrent PHY configuration registers.
+      - description: Offset of the DPTX PHY configuration registers.
+
+  reg-names:
+    minItems: 1
+    maxItems: 2
+    items:
+      - const: torrent_phy
+      - const: dptx_phy
+
+  resets:
+    maxItems: 1
+    description:
+      Torrent PHY reset.
+      See Documentation/devicetree/bindings/reset/reset.txt
+
+patternProperties:
+  '^phy@[0-7]+$':
+    type: object
+    description:
+      Each group of PHY lanes with a single master lane should be represented as a sub-node.
+    properties:
+      reg:
+        description:
+          The master lane number. This is the lowest numbered lane in the lane group.
+
+      resets:
+        minItems: 1
+        maxItems: 4
+        description:
+          Contains list of resets, one per lane, to get all the link lanes out of reset.
+
+      "#phy-cells":
+        const: 0
+
+      cdns,phy-type:
+        description:
+          Specifies the type of PHY for which the group of PHY lanes is used.
+          Refer include/dt-bindings/phy/phy.h. Constants from the header should be used.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [1, 2, 3, 4, 5, 6]
+
+      cdns,num-lanes:
+        description:
+          Number of DisplayPort lanes.
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [1, 2, 4]
+        default: 4
+
+      cdns,max-bit-rate:
+        description:
+          Maximum DisplayPort link bit rate to use, in Mbps
+        allOf:
+          - $ref: /schemas/types.yaml#/definitions/uint32
+          - enum: [2160, 2430, 2700, 3240, 4320, 5400, 8100]
+        default: 8100
+
+    required:
+      - reg
+      - resets
+      - "#phy-cells"
+      - cdns,phy-type
+
+    additionalProperties: false
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+  - clocks
+  - clock-names
+  - reg
+  - reg-names
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/phy/phy.h>
+    torrent_phy: torrent-phy@f0fb500000 {
+          compatible = "cdns,torrent-phy";
+          reg = <0xf0 0xfb500000 0x0 0x00100000>,
+                <0xf0 0xfb030a00 0x0 0x00000040>;
+          reg-names = "torrent_phy", "dptx_phy";
+          resets = <&phyrst 0>;
+          clocks = <&ref_clk>;
+          clock-names = "refclk";
+          #address-cells = <1>;
+          #size-cells = <0>;
+          torrent_phy_dp: phy@0 {
+                    reg = <0>;
+                    resets = <&phyrst 1>, <&phyrst 2>,
+                             <&phyrst 3>, <&phyrst 4>;
+                    #phy-cells = <0>;
+                    cdns,phy-type = <PHY_TYPE_DP>;
+                    cdns,num-lanes = <4>;
+                    cdns,max-bit-rate = <8100>;
+          };
+    };
+...
index a5f7a4f..dd75b67 100644 (file)
@@ -13,10 +13,16 @@ Required properties (controller (parent) node):
                  "mediatek,mt8173-u3phy";
                  make use of "mediatek,generic-tphy-v1" on mt2701 instead and
                  "mediatek,generic-tphy-v2" on mt2712 instead.
- - clocks      : (deprecated, use port's clocks instead) a list of phandle +
-                 clock-specifier pairs, one for each entry in clock-names
- - clock-names : (deprecated, use port's one instead) must contain
-                 "u3phya_ref": for reference clock of usb3.0 analog phy.
+
+- #address-cells:      the number of cells used to represent physical
+               base addresses.
+- #size-cells: the number of cells used to represent the size of an address.
+- ranges:      the address mapping relationship to the parent, defined with
+               - empty value: if optional 'reg' is used.
+               - non-empty value: if optional 'reg' is not used. should set
+                       the child's base address to 0, the physical address
+                       within parent's address space, and the length of
+                       the address map.
 
 Required nodes : a sub-node is required for each port the controller
                  provides. Address range information including the usual
@@ -34,12 +40,6 @@ Optional properties (controller (parent) node):
 
 Required properties (port (child) node):
 - reg          : address and length of the register set for the port.
-- clocks       : a list of phandle + clock-specifier pairs, one for each
-                 entry in clock-names
-- clock-names  : must contain
-                 "ref": 48M reference clock for HighSpeed analog phy; and 26M
-                       reference clock for SuperSpeed analog phy, sometimes is
-                       24M, 25M or 27M, depended on platform.
 - #phy-cells   : should be 1 (See second example)
                  cell after port phandle is phy type from:
                        - PHY_TYPE_USB2
@@ -48,10 +48,22 @@ Required properties (port (child) node):
                        - PHY_TYPE_SATA
 
 Optional properties (PHY_TYPE_USB2 port (child) node):
+- clocks       : a list of phandle + clock-specifier pairs, one for each
+                 entry in clock-names
+- clock-names  : may contain
+                 "ref": 48M reference clock for HighSpeed (digital) phy; and 26M
+                       reference clock for SuperSpeed (digital) phy, sometimes is
+                       24M, 25M or 27M, depended on platform.
+                 "da_ref": the reference clock of analog phy, used if the clocks
+                       of analog and digital phys are separated, otherwise uses
+                       "ref" clock only if needed.
+
 - mediatek,eye-src     : u32, the value of slew rate calibrate
 - mediatek,eye-vrt     : u32, the selection of VRT reference voltage
 - mediatek,eye-term    : u32, the selection of HS_TX TERM reference voltage
 - mediatek,bc12        : bool, enable BC12 of u2phy if support it
+- mediatek,discth      : u32, the selection of disconnect threshold
+- mediatek,intr        : u32, the selection of internal R (resistance)
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
new file mode 100644 (file)
index 0000000..144ae29
--- /dev/null
@@ -0,0 +1,185 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/phy/qcom,qusb2-phy.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Qualcomm QUSB2 phy controller
+
+maintainers:
+  - Manu Gautam <mgautam@codeaurora.org>
+
+description:
+  QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
+
+properties:
+  compatible:
+    oneOf:
+      - items:
+        - enum:
+          - qcom,msm8996-qusb2-phy
+          - qcom,msm8998-qusb2-phy
+      - items:
+        - enum:
+          - qcom,sc7180-qusb2-phy
+          - qcom,sdm845-qusb2-phy
+        - const: qcom,qusb2-v2-phy
+  reg:
+    maxItems: 1
+
+  "#phy-cells":
+    const: 0
+
+  clocks:
+    minItems: 2
+    maxItems: 3
+    items:
+      - description: phy config clock
+      - description: 19.2 MHz ref clk
+      - description: phy interface clock (Optional)
+
+  clock-names:
+    minItems: 2
+    maxItems: 3
+    items:
+      - const: cfg_ahb
+      - const: ref
+      - const: iface
+
+  vdda-pll-supply:
+     description:
+       Phandle to 1.8V regulator supply to PHY refclk pll block.
+
+  vdda-phy-dpdm-supply:
+     description:
+       Phandle to 3.1V regulator supply to Dp/Dm port signals.
+
+  resets:
+    maxItems: 1
+    description:
+      Phandle to reset to phy block.
+
+  nvmem-cells:
+    maxItems: 1
+    description:
+        Phandle to nvmem cell that contains 'HS Tx trim'
+        tuning parameter value for qusb2 phy.
+
+  qcom,tcsr-syscon:
+    description:
+        Phandle to TCSR syscon register region.
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+if:
+  properties:
+    compatible:
+      contains:
+        const: qcom,qusb2-v2-phy
+then:
+  properties:
+    qcom,imp-res-offset-value:
+      description:
+        It is a 6 bit value that specifies offset to be
+        added to PHY refgen RESCODE via IMP_CTRL1 register. It is a PHY
+        tuning parameter that may vary for different boards of same SOC.
+      allOf:
+        - $ref: /schemas/types.yaml#/definitions/uint32
+        - minimum: 0
+          maximum: 63
+          default: 0
+
+    qcom,bias-ctrl-value:
+      description:
+        It is a 6 bit value that specifies bias-ctrl-value. It is a PHY
+        tuning parameter that may vary for different boards of same SOC.
+      allOf:
+        - $ref: /schemas/types.yaml#/definitions/uint32
+        - minimum: 0
+          maximum: 63
+          default: 0
+
+    qcom,charge-ctrl-value:
+     description:
+        It is a 2 bit value that specifies charge-ctrl-value. It is a PHY
+        tuning parameter that may vary for different boards of same SOC.
+     allOf:
+       - $ref: /schemas/types.yaml#/definitions/uint32
+       - minimum: 0
+         maximum: 3
+         default: 0
+
+    qcom,hstx-trim-value:
+      description:
+        It is a 4 bit value that specifies tuning for HSTX
+        output current.
+        Possible range is - 15mA to 24mA (stepsize of 600 uA).
+        See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
+      allOf:
+        - $ref: /schemas/types.yaml#/definitions/uint32
+        - minimum: 0
+          maximum: 15
+          default: 3
+
+    qcom,preemphasis-level:
+      description:
+        It is a 2 bit value that specifies pre-emphasis level.
+        Possible range is 0 to 15% (stepsize of 5%).
+        See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
+      allOf:
+        - $ref: /schemas/types.yaml#/definitions/uint32
+        - minimum: 0
+          maximum: 3
+          default: 2
+
+    qcom,preemphasis-width:
+      description:
+        It is a 1 bit value that specifies how long the HSTX
+        pre-emphasis (specified using qcom,preemphasis-level) must be in
+        effect. Duration could be half-bit of full-bit.
+        See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
+      allOf:
+        - $ref: /schemas/types.yaml#/definitions/uint32
+        - minimum: 0
+          maximum: 1
+          default: 0
+
+    qcom,hsdisc-trim-value:
+      description:
+        It is a 2 bit value tuning parameter that control disconnect
+        threshold and may vary for different boards of same SOC.
+      allOf:
+        - $ref: /schemas/types.yaml#/definitions/uint32
+        - minimum: 0
+          maximum: 3
+          default: 0
+
+required:
+  - compatible
+  - reg
+  - "#phy-cells"
+  - clocks
+  - clock-names
+  - vdda-pll-supply
+  - vdda-phy-dpdm-supply
+  - resets
+
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-msm8996.h>
+    hsusb_phy: phy@7411000 {
+        compatible = "qcom,msm8996-qusb2-phy";
+        reg = <0x7411000 0x180>;
+        #phy-cells = <0>;
+
+        clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
+                 <&gcc GCC_RX1_USB2_CLKREF_CLK>;
+        clock-names = "cfg_ahb", "ref";
+
+        vdda-pll-supply = <&pm8994_l12>;
+        vdda-phy-dpdm-supply = <&pm8994_l24>;
+
+        resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
+        nvmem-cells = <&qusb2p_hstx_trim>;
+    };
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml
new file mode 100644 (file)
index 0000000..ca6a083
--- /dev/null
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/phy/qcom,usb-hs-28nm.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Qualcomm Synopsys DesignWare Core 28nm High-Speed PHY
+
+maintainers:
+  - Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+
+description: |
+  Qualcomm Low-Speed, Full-Speed, Hi-Speed 28nm USB PHY
+
+properties:
+  compatible:
+    enum:
+      - qcom,usb-hs-28nm-femtophy
+
+  reg:
+    maxItems: 1
+
+  "#phy-cells":
+    const: 0
+
+  clocks:
+    items:
+      - description: rpmcc ref clock
+      - description: PHY AHB clock
+      - description: Rentention clock
+
+  clock-names:
+    items:
+      - const: ref
+      - const: ahb
+      - const: sleep
+
+  resets:
+    items:
+      - description: PHY core reset
+      - description: POR reset
+
+  reset-names:
+    items:
+      - const: phy
+      - const: por
+
+  vdd-supply:
+    description: phandle to the regulator VDD supply node.
+
+  vdda1p8-supply:
+    description: phandle to the regulator 1.8V supply node.
+
+  vdda3p3-supply:
+    description: phandle to the regulator 3.3V supply node.
+
+required:
+  - compatible
+  - reg
+  - "#phy-cells"
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - vdd-supply
+  - vdda1p8-supply
+  - vdda3p3-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-qcs404.h>
+    #include <dt-bindings/clock/qcom,rpmcc.h>
+    usb2_phy_prim: phy@7a000 {
+        compatible = "qcom,usb-hs-28nm-femtophy";
+        reg = <0x0007a000 0x200>;
+        #phy-cells = <0>;
+        clocks = <&rpmcc RPM_SMD_LN_BB_CLK>,
+                 <&gcc GCC_USB_HS_PHY_CFG_AHB_CLK>,
+                 <&gcc GCC_USB2A_PHY_SLEEP_CLK>;
+        clock-names = "ref", "ahb", "sleep";
+        resets = <&gcc GCC_USB_HS_PHY_CFG_AHB_BCR>,
+                 <&gcc GCC_USB2A_PHY_BCR>;
+        reset-names = "phy", "por";
+        vdd-supply = <&vreg_l4_1p2>;
+        vdda1p8-supply = <&vreg_l5_1p8>;
+        vdda3p3-supply = <&vreg_l12_3p3>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml
new file mode 100644 (file)
index 0000000..bd1388d
--- /dev/null
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/phy/qcom,usb-ss.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Qualcomm Synopsys 1.0.0 SuperSpeed USB PHY
+
+maintainers:
+  - Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+
+description: |
+  Qualcomm Synopsys 1.0.0 SuperSpeed USB PHY
+
+properties:
+  compatible:
+    enum:
+      - qcom,usb-ss-28nm-phy
+
+  reg:
+    maxItems: 1
+
+  "#phy-cells":
+    const: 0
+
+  clocks:
+    items:
+      - description: rpmcc clock
+      - description: PHY AHB clock
+      - description: SuperSpeed pipe clock
+
+  clock-names:
+    items:
+      - const: ref
+      - const: ahb
+      - const: pipe
+
+  vdd-supply:
+    description: phandle to the regulator VDD supply node.
+
+  vdda1p8-supply:
+    description: phandle to the regulator 1.8V supply node.
+
+  resets:
+    items:
+      - description: COM reset
+      - description: PHY reset line
+
+  reset-names:
+    items:
+      - const: com
+      - const: phy
+
+required:
+  - compatible
+  - reg
+  - "#phy-cells"
+  - clocks
+  - clock-names
+  - vdd-supply
+  - vdda1p8-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/qcom,gcc-qcs404.h>
+    #include <dt-bindings/clock/qcom,rpmcc.h>
+    usb3_phy: usb3-phy@78000 {
+        compatible = "qcom,usb-ss-28nm-phy";
+        reg = <0x78000 0x400>;
+        #phy-cells = <0>;
+        clocks = <&rpmcc RPM_SMD_LN_BB_CLK>,
+                 <&gcc GCC_USB_HS_PHY_CFG_AHB_CLK>,
+                 <&gcc GCC_USB3_PHY_PIPE_CLK>;
+        clock-names = "ref", "ahb", "pipe";
+        resets = <&gcc GCC_USB3_PHY_BCR>,
+                 <&gcc GCC_USB3PHY_PHY_BCR>;
+        reset-names = "com", "phy";
+        vdd-supply = <&vreg_l3_1p05>;
+        vdda1p8-supply = <&vreg_l5_1p8>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/phy/qcom-dwc3-usb-phy.txt b/Documentation/devicetree/bindings/phy/qcom-dwc3-usb-phy.txt
deleted file mode 100644 (file)
index a1697c2..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-Qualcomm DWC3 HS AND SS PHY CONTROLLER
---------------------------------------
-
-DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer
-controllers.  Each DWC3 PHY controller should have its own node.
-
-Required properties:
-- compatible: should contain one of the following:
-       - "qcom,dwc3-hs-usb-phy" for High Speed Synopsis PHY controller
-       - "qcom,dwc3-ss-usb-phy" for Super Speed Synopsis PHY controller
-- reg: offset and length of the DWC3 PHY controller register set
-- #phy-cells: must be zero
-- clocks: a list of phandles and clock-specifier pairs, one for each entry in
-  clock-names.
-- clock-names: Should contain "ref" for the PHY reference clock
-
-Optional clocks:
-  "xo"         External reference clock
-
-Example:
-               phy@100f8800 {
-                       compatible = "qcom,dwc3-hs-usb-phy";
-                       reg = <0x100f8800 0x30>;
-                       clocks = <&gcc USB30_0_UTMI_CLK>;
-                       clock-names = "ref";
-                       #phy-cells = <0>;
-
-               };
-
-               phy@100f8830 {
-                       compatible = "qcom,dwc3-ss-usb-phy";
-                       reg = <0x100f8830 0x30>;
-                       clocks = <&gcc USB30_0_MASTER_CLK>;
-                       clock-names = "ref";
-                       #phy-cells = <0>;
-
-               };
index eac9ad3..54d6f8d 100644 (file)
@@ -8,10 +8,13 @@ Required properties:
  - compatible: compatible list, contains:
               "qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
               "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
+              "qcom,msm8996-qmp-ufs-phy" for 14nm UFS phy on msm8996,
               "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
               "qcom,msm8998-qmp-usb3-phy" for USB3 QMP V3 phy on msm8998,
               "qcom,msm8998-qmp-ufs-phy" for UFS QMP phy on msm8998,
               "qcom,msm8998-qmp-pcie-phy" for PCIe QMP phy on msm8998,
+              "qcom,sdm845-qhp-pcie-phy" for QHP PCIe phy on sdm845,
+              "qcom,sdm845-qmp-pcie-phy" for QMP PCIe phy on sdm845,
               "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
               "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845,
               "qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845,
@@ -44,6 +47,8 @@ Required properties:
                For "qcom,ipq8074-qmp-pcie-phy": no clocks are listed.
                For "qcom,msm8996-qmp-pcie-phy" must contain:
                        "aux", "cfg_ahb", "ref".
+               For "qcom,msm8996-qmp-ufs-phy" must contain:
+                       "ref".
                For "qcom,msm8996-qmp-usb3-phy" must contain:
                        "aux", "cfg_ahb", "ref".
                For "qcom,msm8998-qmp-usb3-phy" must contain:
@@ -52,6 +57,10 @@ Required properties:
                        "ref", "ref_aux".
                For "qcom,msm8998-qmp-pcie-phy" must contain:
                        "aux", "cfg_ahb", "ref".
+               For "qcom,sdm845-qhp-pcie-phy" must contain:
+                       "aux", "cfg_ahb", "ref", "refgen".
+               For "qcom,sdm845-qmp-pcie-phy" must contain:
+                       "aux", "cfg_ahb", "ref", "refgen".
                For "qcom,sdm845-qmp-usb3-phy" must contain:
                        "aux", "cfg_ahb", "ref", "com_aux".
                For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
@@ -72,6 +81,8 @@ Required properties:
                        "phy", "common".
                For "qcom,msm8996-qmp-pcie-phy" must contain:
                        "phy", "common", "cfg".
+               For "qcom,msm8996-qmp-ufs-phy": must contain:
+                       "ufsphy".
                For "qcom,msm8996-qmp-usb3-phy" must contain
                        "phy", "common".
                For "qcom,msm8998-qmp-usb3-phy" must contain
@@ -80,6 +91,10 @@ Required properties:
                        "ufsphy".
                For "qcom,msm8998-qmp-pcie-phy" must contain:
                        "phy", "common".
+               For "qcom,sdm845-qhp-pcie-phy" must contain:
+                       "phy".
+               For "qcom,sdm845-qmp-pcie-phy" must contain:
+                       "phy".
                For "qcom,sdm845-qmp-usb3-phy" must contain:
                        "phy", "common".
                For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
diff --git a/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
deleted file mode 100644 (file)
index fe29f9e..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-Qualcomm QUSB2 phy controller
-=============================
-
-QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
-
-Required properties:
- - compatible: compatible list, contains
-              "qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
-              "qcom,msm8998-qusb2-phy" for 10nm PHY on msm8998,
-              "qcom,sdm845-qusb2-phy" for 10nm PHY on sdm845.
-
- - reg: offset and length of the PHY register set.
- - #phy-cells: must be 0.
-
- - clocks: a list of phandles and clock-specifier pairs,
-          one for each entry in clock-names.
- - clock-names: must be "cfg_ahb" for phy config clock,
-                       "ref" for 19.2 MHz ref clk,
-                       "iface" for phy interface clock (Optional).
-
- - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
- - vdda-phy-dpdm-supply: Phandle to 3.1V regulator supply to Dp/Dm port signals.
-
- - resets: Phandle to reset to phy block.
-
-Optional properties:
- - nvmem-cells: Phandle to nvmem cell that contains 'HS Tx trim'
-               tuning parameter value for qusb2 phy.
-
- - qcom,tcsr-syscon: Phandle to TCSR syscon register region.
- - qcom,imp-res-offset-value: It is a 6 bit value that specifies offset to be
-               added to PHY refgen RESCODE via IMP_CTRL1 register. It is a PHY
-               tuning parameter that may vary for different boards of same SOC.
-               This property is applicable to only QUSB2 v2 PHY (sdm845).
- - qcom,hstx-trim-value: It is a 4 bit value that specifies tuning for HSTX
-               output current.
-               Possible range is - 15mA to 24mA (stepsize of 600 uA).
-               See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
-               This property is applicable to only QUSB2 v2 PHY (sdm845).
-               Default value is 22.2mA for sdm845.
- - qcom,preemphasis-level: It is a 2 bit value that specifies pre-emphasis level.
-               Possible range is 0 to 15% (stepsize of 5%).
-               See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
-               This property is applicable to only QUSB2 v2 PHY (sdm845).
-               Default value is 10% for sdm845.
-- qcom,preemphasis-width: It is a 1 bit value that specifies how long the HSTX
-               pre-emphasis (specified using qcom,preemphasis-level) must be in
-               effect. Duration could be half-bit of full-bit.
-               See dt-bindings/phy/phy-qcom-qusb2.h for applicable values.
-               This property is applicable to only QUSB2 v2 PHY (sdm845).
-               Default value is full-bit width for sdm845.
-
-Example:
-       hsusb_phy: phy@7411000 {
-               compatible = "qcom,msm8996-qusb2-phy";
-               reg = <0x7411000 0x180>;
-               #phy-cells = <0>;
-
-               clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
-                       <&gcc GCC_RX1_USB2_CLKREF_CLK>,
-               clock-names = "cfg_ahb", "ref";
-
-               vdda-pll-supply = <&pm8994_l12>;
-               vdda-phy-dpdm-supply = <&pm8994_l24>;
-
-               resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
-               nvmem-cells = <&qusb2p_hstx_trim>;
-        };
index 50ce9ae..83b78c1 100644 (file)
@@ -40,6 +40,7 @@ Required properties:
                          "ti,dra7xx-phy-gmii-sel" for dra7xx/am57xx platform
                          "ti,am43xx-phy-gmii-sel" for am43xx platform
                          "ti,dm814-phy-gmii-sel" for dm814x platform
+                         "ti,am654-phy-gmii-sel" for AM654x/J721E platform
 - reg                  : Address and length of the register set for the device
 - #phy-cells           : must be 2.
                          cell 1 - CPSW port number (starting from 1)
index 1889d3b..3cee372 100644 (file)
@@ -5,14 +5,19 @@ PCIe controller implemented on Socionext UniPhier SoCs.
 
 Required properties:
 - compatible: Should contain one of the following:
+    "socionext,uniphier-pro5-pcie-phy" - for Pro5 PHY
     "socionext,uniphier-ld20-pcie-phy" - for LD20 PHY
     "socionext,uniphier-pxs3-pcie-phy" - for PXs3 PHY
 - reg: Specifies offset and length of the register set for the device.
 - #phy-cells: Must be zero.
-- clocks: A phandle to the clock gate for PCIe glue layer including
-       this phy.
-- resets: A phandle to the reset line for PCIe glue layer including
-       this phy.
+- clocks: A list of phandles to the clock gate for PCIe glue layer
+       including this phy.
+- clock-names: For Pro5 only, should contain the following:
+    "gio", "link" - for Pro5 SoC
+- resets: A list of phandles to the reset line for PCIe glue layer
+       including this phy.
+- reset-names: For Pro5 only, should contain the following:
+    "gio", "link" - for Pro5 SoC
 
 Optional properties:
 - socionext,syscon: A phandle to system control to set configurations
index e8d8086..093d4f0 100644 (file)
@@ -7,7 +7,7 @@ this describes about High-Speed PHY.
 
 Required properties:
 - compatible: Should contain one of the following:
-    "socionext,uniphier-pro4-usb3-hsphy" - for Pro4 SoC
+    "socionext,uniphier-pro5-usb3-hsphy" - for Pro5 SoC
     "socionext,uniphier-pxs2-usb3-hsphy" - for PXs2 SoC
     "socionext,uniphier-ld20-usb3-hsphy" - for LD20 SoC
     "socionext,uniphier-pxs3-usb3-hsphy" - for PXs3 SoC
@@ -16,13 +16,13 @@ Required properties:
 - clocks: A list of phandles to the clock gate for USB3 glue layer.
        According to the clock-names, appropriate clocks are required.
 - clock-names: Should contain the following:
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro5 SoC
     "phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional.
     "phy", "link" - for others
 - resets: A list of phandles to the reset control for USB3 glue layer.
        According to the reset-names, appropriate resets are required.
 - reset-names: Should contain the following:
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro5 SoC
     "phy", "link" - for others
 
 Optional properties:
index 490b815..9df2bc2 100644 (file)
@@ -8,6 +8,7 @@ this describes about Super-Speed PHY.
 Required properties:
 - compatible: Should contain one of the following:
     "socionext,uniphier-pro4-usb3-ssphy" - for Pro4 SoC
+    "socionext,uniphier-pro5-usb3-ssphy" - for Pro5 SoC
     "socionext,uniphier-pxs2-usb3-ssphy" - for PXs2 SoC
     "socionext,uniphier-ld20-usb3-ssphy" - for LD20 SoC
     "socionext,uniphier-pxs3-usb3-ssphy" - for PXs3 SoC
@@ -16,13 +17,13 @@ Required properties:
 - clocks: A list of phandles to the clock gate for USB3 glue layer.
        According to the clock-names, appropriate clocks are required.
 - clock-names:
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro4 and Pro5 SoC
     "phy", "phy-ext", "link" - for PXs3 SoC, "phy-ext" is optional.
     "phy", "link" - for others
 - resets: A list of phandles to the reset control for USB3 glue layer.
        According to the reset-names, appropriate resets are required.
 - reset-names:
-    "gio", "link" - for Pro4 SoC
+    "gio", "link" - for Pro4 and Pro5 SoC
     "phy", "link" - for others
 
 Optional properties:
index bb690e2..135c7df 100644 (file)
@@ -17,7 +17,7 @@ description: |+
                     "aspeed,ast2400-scu", "syscon", "simple-mfd"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
index f7f5d57..824f7fd 100644 (file)
@@ -18,7 +18,7 @@ description: |+
                        "aspeed,g5-scu", "syscon", "simple-mfd"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
index 3749fa2..ac8d1c3 100644 (file)
@@ -17,7 +17,7 @@ description: |+
                 "aspeed,ast2600-scu", "syscon", "simple-mfd"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
index 754ea7a..ef4de32 100644 (file)
@@ -248,7 +248,7 @@ examples:
       };
 
     //Example 3 pin groups
-      pinctrl@60020000 {
+      pinctrl {
         usart1_pins_a: usart1-0 {
                 pins1 {
                         pinmux = <STM32_PINMUX('A', 9, AF7)>;
index aab70e8..d3098c9 100644 (file)
@@ -18,7 +18,7 @@ description: |+
                 "amlogic,meson-gx-hhi-sysctrl", "simple-mfd", "syscon"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.txt b/Documentation/devicetree/bindings/power/domain-idle-state.txt
deleted file mode 100644 (file)
index eefc7ed..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-PM Domain Idle State Node:
-
-A domain idle state node represents the state parameters that will be used to
-select the state when there are no active components in the domain.
-
-The state node has the following parameters -
-
-- compatible:
-       Usage: Required
-       Value type: <string>
-       Definition: Must be "domain-idle-state".
-
-- entry-latency-us
-       Usage: Required
-       Value type: <prop-encoded-array>
-       Definition: u32 value representing worst case latency in
-                   microseconds required to enter the idle state.
-                   The exit-latency-us duration may be guaranteed
-                   only after entry-latency-us has passed.
-
-- exit-latency-us
-       Usage: Required
-       Value type: <prop-encoded-array>
-       Definition: u32 value representing worst case latency
-                   in microseconds required to exit the idle state.
-
-- min-residency-us
-       Usage: Required
-       Value type: <prop-encoded-array>
-       Definition: u32 value representing minimum residency duration
-                   in microseconds after which the idle state will yield
-                   power benefits after overcoming the overhead in entering
-i                  the idle state.
diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.yaml b/Documentation/devicetree/bindings/power/domain-idle-state.yaml
new file mode 100644 (file)
index 0000000..dfba1af
--- /dev/null
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/domain-idle-state.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: PM Domain Idle States binding description
+
+maintainers:
+  - Ulf Hansson <ulf.hansson@linaro.org>
+
+description:
+  A domain idle state node represents the state parameters that will be used to
+  select the state when there are no active components in the PM domain.
+
+properties:
+  $nodename:
+    const: domain-idle-states
+
+patternProperties:
+  "^(cpu|cluster|domain)-":
+    type: object
+    description:
+      Each state node represents a domain idle state description.
+
+    properties:
+      compatible:
+        const: domain-idle-state
+
+      entry-latency-us:
+        description:
+          The worst case latency in microseconds required to enter the idle
+          state. Note that, the exit-latency-us duration may be guaranteed only
+          after the entry-latency-us has passed.
+
+      exit-latency-us:
+        description:
+          The worst case latency in microseconds required to exit the idle
+          state.
+
+      min-residency-us:
+        description:
+          The minimum residency duration in microseconds after which the idle
+          state will yield power benefits, after overcoming the overhead while
+          entering the idle state.
+
+    required:
+      - compatible
+      - entry-latency-us
+      - exit-latency-us
+      - min-residency-us
+
+examples:
+  - |
+
+    domain-idle-states {
+      domain_retention: domain-retention {
+        compatible = "domain-idle-state";
+        entry-latency-us = <20>;
+        exit-latency-us = <40>;
+        min-residency-us = <80>;
+      };
+    };
+...
index 455b573..6047aac 100644 (file)
@@ -25,22 +25,20 @@ description: |+
 
 properties:
   $nodename:
-    pattern: "^(power-controller|power-domain)(@.*)?$"
+    pattern: "^(power-controller|power-domain)([@-].*)?$"
 
   domain-idle-states:
     $ref: /schemas/types.yaml#/definitions/phandle-array
-    description:
-      A phandle of an idle-state that shall be soaked into a generic domain
-      power state. The idle state definitions are compatible with
-      domain-idle-state specified in
-      Documentation/devicetree/bindings/power/domain-idle-state.txt
-      phandles that are not compatible with domain-idle-state will be ignored.
-      The domain-idle-state property reflects the idle state of this PM domain
-      and not the idle states of the devices or sub-domains in the PM domain.
-      Devices and sub-domains have their own idle-states independent
-      of the parent domain's idle states. In the absence of this property,
-      the domain would be considered as capable of being powered-on
-      or powered-off.
+    description: |
+      Phandles of idle states that defines the available states for the
+      power-domain provider. The idle state definitions are compatible with the
+      domain-idle-state bindings, specified in ./domain-idle-state.yaml.
+
+      Note that, the domain-idle-state property reflects the idle states of this
+      PM domain and not the idle states of the devices or sub-domains in the PM
+      domain. Devices and sub-domains have their own idle states independent of
+      the parent domain's idle states. In the absence of this property, the
+      domain would be considered as capable of being powered-on or powered-off.
 
   operating-points-v2:
     $ref: /schemas/types.yaml#/definitions/phandle-array
index 5b09b2d..08497ef 100644 (file)
@@ -109,4 +109,4 @@ Example:
                required-opps = <&domain1_opp_1>;
        };
 
-[1]. Documentation/devicetree/bindings/power/domain-idle-state.txt
+[1]. Documentation/devicetree/bindings/power/domain-idle-state.yaml
diff --git a/Documentation/devicetree/bindings/regulator/mp886x.txt b/Documentation/devicetree/bindings/regulator/mp886x.txt
new file mode 100644 (file)
index 0000000..5518678
--- /dev/null
@@ -0,0 +1,27 @@
+Monolithic Power Systems MP8867/MP8869 voltage regulator
+
+Required properties:
+- compatible: Must be one of the following.
+       "mps,mp8867"
+       "mps,mp8869"
+- reg: I2C slave address.
+- enable-gpios: enable gpios.
+- mps,fb-voltage-divider: An array of two integers containing the resistor
+  values R1 and R2 of the feedback voltage divider in kilo ohms.
+
+Any property defined as part of the core regulator binding, defined in
+./regulator.txt, can also be used.
+
+Example:
+
+       vcpu: regulator@62 {
+               compatible = "mps,mp8869";
+               regulator-name = "vcpu";
+               regulator-min-microvolt = <700000>;
+               regulator-max-microvolt = <850000>;
+               regulator-always-on;
+               regulator-boot-on;
+               enable-gpios = <&porta 1 GPIO_ACTIVE_LOW>;
+               mps,fb-voltage-divider = <80 240>;
+               reg = <0x62>;
+       };
diff --git a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml
new file mode 100644 (file)
index 0000000..f0acce2
--- /dev/null
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/mps,mp5416.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Monolithic Power System MP5416 PMIC
+
+maintainers:
+  - Saravanan Sekar <sravanhome@gmail.com>
+
+properties:
+  $nodename:
+    pattern: "^pmic@[0-9a-f]{1,2}$"
+  compatible:
+    enum:
+      - mps,mp5416
+
+  reg:
+    maxItems: 1
+
+  regulators:
+    type: object
+    description: |
+      list of regulators provided by this controller, must be named
+      after their hardware counterparts BUCK[1-4] and LDO[1-4]
+
+    patternProperties:
+      "^buck[1-4]$":
+        allOf:
+          - $ref: "regulator.yaml#"
+        type: object
+
+      "^ldo[1-4]$":
+        allOf:
+          - $ref: "regulator.yaml#"
+        type: object
+
+    additionalProperties: false
+  additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - regulators
+
+additionalProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        pmic@69 {
+          compatible = "mps,mp5416";
+          reg = <0x69>;
+
+          regulators {
+
+            buck1 {
+             regulator-name = "buck1";
+             regulator-min-microvolt = <600000>;
+             regulator-max-microvolt = <2187500>;
+             regulator-min-microamp  = <3800000>;
+             regulator-max-microamp  = <6800000>;
+             regulator-boot-on;
+            };
+
+            ldo2 {
+             regulator-name = "ldo2";
+             regulator-min-microvolt = <800000>;
+             regulator-max-microvolt = <3975000>;
+            };
+         };
+       };
+     };
+...
index d126df0..dea4384 100644 (file)
@@ -26,6 +26,7 @@ Regulator nodes are identified by their compatible:
                    "qcom,rpm-pm8994-regulators"
                    "qcom,rpm-pm8998-regulators"
                    "qcom,rpm-pma8084-regulators"
+                   "qcom,rpm-pmi8994-regulators"
                    "qcom,rpm-pmi8998-regulators"
                    "qcom,rpm-pms405-regulators"
 
@@ -146,6 +147,15 @@ Regulator nodes are identified by their compatible:
 - vdd_s1-supply:
 - vdd_s2-supply:
 - vdd_s3-supply:
+- vdd_bst_byp-supply:
+       Usage: optional (pmi8994 only)
+       Value type: <phandle>
+       Definition: reference to regulator supplying the input pin, as
+                   described in the data sheet
+
+- vdd_s1-supply:
+- vdd_s2-supply:
+- vdd_s3-supply:
 - vdd_s4-supply:
 - vdd_s5-supply:
 - vdd_s6-supply:
@@ -259,6 +269,9 @@ pma8084:
        l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20,
        l21, l22, l23, l24, l25, l26, l27, lvs1, lvs2, lvs3, lvs4, 5vs1
 
+pmi8994:
+       s1, s2, s3, boost-bypass
+
 pmi8998:
        bob
 
index f5cdac8..8b00519 100644 (file)
@@ -161,7 +161,7 @@ The regulator node houses sub-nodes for each regulator within the device. Each
 sub-node is identified using the node's name, with valid values listed for each
 of the PMICs below.
 
-pm8005:
+pm8004:
        s2, s5
 
 pm8005:
index 92ff2e8..91a39a3 100644 (file)
@@ -191,7 +191,7 @@ patternProperties:
 
 examples:
   - |
-    xyzreg: regulator@0 {
+    xyzreg: regulator {
       regulator-min-microvolt = <1000000>;
       regulator-max-microvolt = <2500000>;
       regulator-always-on;
diff --git a/Documentation/devicetree/bindings/regulator/vqmmc-ipq4019-regulator.yaml b/Documentation/devicetree/bindings/regulator/vqmmc-ipq4019-regulator.yaml
new file mode 100644 (file)
index 0000000..d1a79d2
--- /dev/null
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/vqmmc-ipq4019-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm IPQ4019 VQMMC SD LDO regulator
+
+maintainers:
+  - Robert Marko <robert.marko@sartura.hr>
+
+description: |
+  Qualcomm IPQ4019 SoC-s feature a built a build SD/EMMC controller,
+  in order to support both 1.8 and 3V I/O voltage levels an LDO
+  controller is also embedded.
+
+allOf:
+  - $ref: "regulator.yaml#"
+
+properties:
+  compatible:
+    const: qcom,vqmmc-ipq4019-regulator
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+examples:
+  - |
+    regulator@1948000 {
+      compatible = "qcom,vqmmc-ipq4019-regulator";
+      reg = <0x01948000 0x4>;
+      regulator-name = "vqmmc";
+      regulator-min-microvolt = <1500000>;
+      regulator-max-microvolt = <3000000>;
+      regulator-always-on;
+      status = "disabled";
+    };
+...
index 246dea8..8ac4372 100644 (file)
@@ -23,7 +23,11 @@ properties:
     description: Global reset register offset and bit offset.
     allOf:
       - $ref: /schemas/types.yaml#/definitions/uint32-array
-      - maxItems: 2
+    items:
+      - description: Register offset
+      - description: Register bit offset
+        minimum: 0
+        maximum: 31
 
   "#reset-cells":
     minimum: 2
index b4edaf7..2880d5d 100644 (file)
@@ -3,4 +3,4 @@ STMicroelectronics STM32MP1 Peripheral Reset Controller
 
 The RCC IP is both a reset and a clock controller.
 
-Please see Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt
+Please see Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.yaml
index 944743d..c42b91e 100644 (file)
@@ -36,7 +36,7 @@ SAI subnodes required properties:
   - clock-names: Must contain "sai_ck".
        Must also contain "MCLK", if SAI shares a master clock,
        with a SAI set as MCLK clock provider.
-  - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
+  - dmas: see Documentation/devicetree/bindings/dma/st,stm32-dma.yaml
   - dma-names: identifier string for each DMA request line
        "tx": if sai sub-block is configured as playback DAI
        "rx": if sai sub-block is configured as capture DAI
index 33826f2..ca91017 100644 (file)
@@ -10,7 +10,7 @@ Required properties:
   - clock-names: must contain "kclk"
   - interrupts: cpu DAI interrupt line
   - dmas: DMA specifiers for audio data DMA and iec control flow DMA
-    See STM32 DMA bindings, Documentation/devicetree/bindings/dma/stm32-dma.txt
+    See STM32 DMA bindings, Documentation/devicetree/bindings/dma/st,stm32-dma.yaml
   - dma-names: two dmas have to be defined, "rx" and "rx-ctrl"
 
 Optional properties:
index 49b617c..9147df2 100644 (file)
@@ -22,6 +22,7 @@ properties:
     enum:
       - amlogic,meson-gx-spicc # SPICC controller on Amlogic GX and compatible SoCs
       - amlogic,meson-axg-spicc # SPICC controller on Amlogic AXG and compatible SoCs
+      - amlogic,meson-g12a-spicc # SPICC controller on Amlogic G12A and compatible SoCs
 
   interrupts:
     maxItems: 1
@@ -40,6 +41,27 @@ properties:
     items:
       - const: core
 
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - amlogic,meson-g12a-spicc
+
+then:
+  properties:
+    clocks:
+      contains:
+        items:
+          - description: controller register bus clock
+          - description: baud rate generator and delay control clock
+
+    clock-names:
+      minItems: 2
+      items:
+        - const: core
+        - const: pclk
+
 required:
   - compatible
   - reg
index 2d32641..33bc58f 100644 (file)
@@ -10,7 +10,10 @@ Required properties:
   - "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35
   - "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51
   - "fsl,imx53-ecspi" for SPI compatible with the one integrated on i.MX53 and later Soc
-  - "fsl,imx8mq-ecspi" for SPI compatible with the one integrated on i.MX8M
+  - "fsl,imx8mq-ecspi" for SPI compatible with the one integrated on i.MX8MQ
+  - "fsl,imx8mm-ecspi" for SPI compatible with the one integrated on i.MX8MM
+  - "fsl,imx8mn-ecspi" for SPI compatible with the one integrated on i.MX8MN
+  - "fsl,imx8mp-ecspi" for SPI compatible with the one integrated on i.MX8MP
 - reg : Offset and length of the register set for the device
 - interrupts : Should contain CSPI/eCSPI interrupt
 - clocks : Clock specifiers for both ipg and per clocks.
diff --git a/Documentation/devicetree/bindings/spi/qca,ar934x-spi.yaml b/Documentation/devicetree/bindings/spi/qca,ar934x-spi.yaml
new file mode 100644 (file)
index 0000000..2aa7667
--- /dev/null
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/qca,ar934x-spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Atheros AR934x/QCA95xx SoC SPI controller
+
+maintainers:
+  - Chuanhong Guo <gch981213@gmail.com>
+
+allOf:
+  - $ref: spi-controller.yaml#
+
+properties:
+  compatible:
+    const: qca,ar934x-spi
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - '#address-cells'
+  - '#size-cells'
+
+examples:
+  - |
+    #include <dt-bindings/clock/ath79-clk.h>
+    spi: spi@1f000000 {
+        compatible = "qca,ar934x-spi";
+        reg = <0x1f000000 0x1c>;
+        clocks = <&pll ATH79_CLK_AHB>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+    };
index 1e0ca6c..d8e5509 100644 (file)
@@ -52,6 +52,12 @@ properties:
     description:
       The SPI controller acts as a slave, instead of a master.
 
+oneOf:
+  - required:
+      - "#address-cells"
+  - required:
+      - spi-slave
+
 patternProperties:
   "^slave$":
     type: object
@@ -114,7 +120,7 @@ patternProperties:
           - enum: [ 1, 2, 4, 8 ]
           - default: 1
         description:
-          Bus width to the SPI bus used for MISO.
+          Bus width to the SPI bus used for read transfers.
 
       spi-rx-delay-us:
         description:
@@ -126,7 +132,7 @@ patternProperties:
           - enum: [ 1, 2, 4, 8 ]
           - default: 1
         description:
-          Bus width to the SPI bus used for MOSI.
+          Bus width to the SPI bus used for write transfers.
 
       spi-tx-delay-us:
         description:
index 162e024..30a79da 100644 (file)
@@ -1,12 +1,17 @@
 ARM Freescale DSPI controller
 
 Required properties:
-- compatible : "fsl,vf610-dspi", "fsl,ls1021a-v1.0-dspi",
-               "fsl,ls2085a-dspi"
-               or
-               "fsl,ls2080a-dspi" followed by "fsl,ls2085a-dspi"
-               "fsl,ls1012a-dspi" followed by "fsl,ls1021a-v1.0-dspi"
-               "fsl,ls1088a-dspi" followed by "fsl,ls1021a-v1.0-dspi"
+- compatible : must be one of:
+       "fsl,vf610-dspi",
+       "fsl,ls1021a-v1.0-dspi",
+       "fsl,ls1012a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"),
+       "fsl,ls1028a-dspi",
+       "fsl,ls1043a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"),
+       "fsl,ls1046a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"),
+       "fsl,ls1088a-dspi" (optionally followed by "fsl,ls1021a-v1.0-dspi"),
+       "fsl,ls2080a-dspi" (optionally followed by "fsl,ls2085a-dspi"),
+       "fsl,ls2085a-dspi",
+       "fsl,lx2160a-dspi",
 - reg : Offset and length of the register set for the device
 - interrupts : Should contain SPI controller interrupt
 - clocks: from common clock binding: handle to dspi clock.
@@ -14,11 +19,11 @@ Required properties:
 - pinctrl-0: pin control group to be used for this controller.
 - pinctrl-names: must contain a "default" entry.
 - spi-num-chipselects : the number of the chipselect signals.
-- bus-num : the slave chip chipselect signal number.
 
 Optional property:
 - big-endian: If present the dspi device's registers are implemented
   in big endian mode.
+- bus-num : the slave chip chipselect signal number.
 
 Optional SPI slave node properties:
 - fsl,spi-cs-sck-delay: a delay in nanoseconds between activating chip
@@ -1,4 +1,4 @@
-* Serial NOR flash controller for MediaTek SoCs
+* Serial NOR flash controller for MediaTek ARM SoCs
 
 Required properties:
 - compatible:    For mt8173, compatible should be "mediatek,mt8173-nor",
@@ -13,6 +13,7 @@ Required properties:
                  "mediatek,mt7629-nor", "mediatek,mt8173-nor"
                  "mediatek,mt8173-nor"
 - reg:                   physical base address and length of the controller's register
+- interrupts:    Interrupt number used by the controller.
 - clocks:        the phandle of the clocks needed by the nor controller
 - clock-names:           the names of the clocks
                  the clocks should be named "spi" and "sf". "spi" is used for spi bus,
@@ -22,20 +23,16 @@ Required properties:
 - #address-cells: should be <1>
 - #size-cells:   should be <0>
 
-The SPI flash must be a child of the nor_flash node and must have a
-compatible property. Also see jedec,spi-nor.txt.
-
-Required properties:
-- compatible:    May include a device-specific string consisting of the manufacturer
-                 and name of the chip. Must also include "jedec,spi-nor" for any
-                 SPI NOR flash that can be identified by the JEDEC READ ID opcode (0x9F).
-- reg :                  Chip-Select number
+There should be only one spi slave device following generic spi bindings.
+It's not recommended to use this controller for devices other than SPI NOR
+flash due to limited transfer capability of this controller.
 
 Example:
 
 nor_flash: spi@1100d000 {
        compatible = "mediatek,mt8173-nor";
        reg = <0 0x1100d000 0 0xe0>;
+       interrupts = <&spi_flash_irq>;
        clocks = <&pericfg CLK_PERI_SPI>,
                 <&topckgen CLK_TOP_SPINFI_IFR_SEL>;
        clock-names = "spi", "sf";
diff --git a/Documentation/devicetree/bindings/spi/spi-mux.yaml b/Documentation/devicetree/bindings/spi/spi-mux.yaml
new file mode 100644 (file)
index 0000000..0ae692d
--- /dev/null
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-mux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic SPI Multiplexer
+
+description: |
+  This binding describes a SPI bus multiplexer to route the SPI chip select
+  signals. This can be used when you need more devices than the SPI controller
+  has chip selects available. An example setup is shown in ASCII art; the actual
+  setting of the multiplexer to a channel needs to be done by a specific SPI mux
+  driver.
+
+        MOSI /--------------------------------+--------+--------+--------\
+        MISO |/------------------------------+|-------+|-------+|-------\|
+         SCL ||/----------------------------+||------+||------+||------\||
+             |||                            |||      |||      |||      |||
+      +------------+                        |||      |||      |||      |||
+      | SoC  |||   |                      +-+++-+  +-+++-+  +-+++-+  +-+++-+
+      |      |||   |                      | dev |  | dev |  | dev |  | dev |
+      |   +--+++-+ | CS-X  +------+\      +--+--+  +--+--+  +--+--+  +--+--+
+      |   | SPI  +-|-------+ Mux  |\\   CS-0 |        |        |        |
+      |   +------+ |       +--+---+\\\-------/   CS-1 |        |        |
+      |            |          |    \\\----------------/   CS-2 |        |
+      |   +------+ |          |     \\-------------------------/   CS-3 |
+      |   | ?    +-|----------/      \----------------------------------/
+      |   +------+ |
+      +------------+
+
+allOf:
+  - $ref: "/schemas/spi/spi-controller.yaml#"
+
+maintainers:
+  - Chris Packham <chris.packham@alliedtelesis.co.nz>
+
+properties:
+  compatible:
+    const: spi-mux
+
+  mux-controls:
+    maxItems: 1
+
+required:
+   - compatible
+   - reg
+   - spi-max-frequency
+   - mux-controls
+
+examples:
+   - |
+     #include <dt-bindings/gpio/gpio.h>
+     mux: mux-controller {
+       compatible = "gpio-mux";
+       #mux-control-cells = <0>;
+
+       mux-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>;
+     };
+
+     spi {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       spi@0 {
+         compatible = "spi-mux";
+         reg = <0>;
+         #address-cells = <1>;
+         #size-cells = <0>;
+         spi-max-frequency = <100000000>;
+
+         mux-controls = <&mux>;
+
+         spi-flash@0 {
+           compatible = "jedec,spi-nor";
+           reg = <0>;
+           #address-cells = <1>;
+           #size-cells = <0>;
+           spi-max-frequency = <40000000>;
+         };
+
+         spi-device@1 {
+           compatible = "lineartechnology,ltc2488";
+           reg = <1>;
+           #address-cells = <1>;
+           #size-cells = <0>;
+           spi-max-frequency = <10000000>;
+         };
+       };
+     };
index 2cd67eb..7ac60d9 100644 (file)
@@ -2,6 +2,9 @@
 
 Required properties:
   - compatible : Should be "nxp,lx2160a-fspi"
+                           "nxp,imx8qxp-fspi"
+                           "nxp,imx8mm-fspi"
+
   - reg :        First contains the register location and length,
                  Second contains the memory mapping address and length
   - reg-names :  Should contain the resource reg names:
diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
deleted file mode 100644 (file)
index a0edac1..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-* Rockchip SPI Controller
-
-The Rockchip SPI controller is used to interface with various devices such as flash
-and display controllers using the SPI communication interface.
-
-Required Properties:
-
-- compatible: should be one of the following.
-    "rockchip,rv1108-spi" for rv1108 SoCs.
-    "rockchip,px30-spi", "rockchip,rk3066-spi" for px30 SoCs.
-    "rockchip,rk3036-spi" for rk3036 SoCS.
-    "rockchip,rk3066-spi" for rk3066 SoCs.
-    "rockchip,rk3188-spi" for rk3188 SoCs.
-    "rockchip,rk3228-spi" for rk3228 SoCS.
-    "rockchip,rk3288-spi" for rk3288 SoCs.
-    "rockchip,rk3368-spi" for rk3368 SoCs.
-    "rockchip,rk3399-spi" for rk3399 SoCs.
-- reg: physical base address of the controller and length of memory mapped
-       region.
-- interrupts: The interrupt number to the cpu. The interrupt specifier format
-              depends on the interrupt controller.
-- clocks: Must contain an entry for each entry in clock-names.
-- clock-names: Shall be "spiclk" for the transfer-clock, and "apb_pclk" for
-                          the peripheral clock.
-- #address-cells: should be 1.
-- #size-cells: should be 0.
-
-Optional Properties:
-
-- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
-               Documentation/devicetree/bindings/dma/dma.txt
-- dma-names: DMA request names should include "tx" and "rx" if present.
-- rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling
-               Rx data (may need to be fine tuned for high capacitance lines).
-               No delay (0) by default.
-- pinctrl-names: Names for the pin configuration(s); may be "default" or
-               "sleep", where the "sleep" configuration may describe the state
-               the pins should be in during system suspend. See also
-               pinctrl/pinctrl-bindings.txt.
-
-
-Example:
-
-       spi0: spi@ff110000 {
-               compatible = "rockchip,rk3066-spi";
-               reg = <0xff110000 0x1000>;
-               dmas = <&pdma1 11>, <&pdma1 12>;
-               dma-names = "tx", "rx";
-               rx-sample-delay-ns = <10>;
-               #address-cells = <1>;
-               #size-cells = <0>;
-               interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
-               clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
-               clock-names = "spiclk", "apb_pclk";
-               pinctrl-0 = <&spi1_pins>;
-               pinctrl-1 = <&spi1_sleep>;
-               pinctrl-names = "default", "sleep";
-       };
diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.yaml b/Documentation/devicetree/bindings/spi/spi-rockchip.yaml
new file mode 100644 (file)
index 0000000..81ad4b7
--- /dev/null
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/spi-rockchip.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip SPI Controller
+
+description:
+  The Rockchip SPI controller is used to interface with various devices such
+  as flash and display controllers using the SPI communication interface.
+
+allOf:
+  - $ref: "spi-controller.yaml#"
+
+maintainers:
+  - Heiko Stuebner <heiko@sntech.de>
+
+# Everything else is described in the common file
+properties:
+  compatible:
+    oneOf:
+      - const: rockchip,rk3036-spi
+      - const: rockchip,rk3066-spi
+      - const: rockchip,rk3228-spi
+      - const: rockchip,rv1108-spi
+      - items:
+          - enum:
+            - rockchip,px30-spi
+            - rockchip,rk3188-spi
+            - rockchip,rk3288-spi
+            - rockchip,rk3308-spi
+            - rockchip,rk3328-spi
+            - rockchip,rk3368-spi
+            - rockchip,rk3399-spi
+          - const: rockchip,rk3066-spi
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: transfer-clock
+      - description: peripheral clock
+
+  clock-names:
+    items:
+      - const: spiclk
+      - const: apb_pclk
+
+  dmas:
+    items:
+      - description: TX DMA Channel
+      - description: RX DMA Channel
+
+  dma-names:
+    items:
+      - const: tx
+      - const: rx
+
+  rx-sample-delay-ns:
+    default: 0
+    description:
+      Nano seconds to delay after the SCLK edge before sampling Rx data
+      (may need to be fine tuned for high capacitance lines).
+      If not specified 0 will be used.
+
+  pinctrl-names:
+    minItems: 1
+    items:
+      - const: default
+      - const: sleep
+    description:
+      Names for the pin configuration(s); may be "default" or "sleep",
+      where the "sleep" configuration may describe the state
+      the pins should be in during system suspend.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+examples:
+  - |
+    #include <dt-bindings/clock/rk3188-cru-common.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+    spi0: spi@ff110000 {
+      compatible = "rockchip,rk3066-spi";
+      reg = <0xff110000 0x1000>;
+      interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
+      clock-names = "spiclk", "apb_pclk";
+      dmas = <&pdma1 11>, <&pdma1 12>;
+      dma-names = "tx", "rx";
+      pinctrl-0 = <&spi1_pins>;
+      pinctrl-1 = <&spi1_sleep>;
+      pinctrl-names = "default", "sleep";
+      rx-sample-delay-ns = <10>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+    };
index f0d9796..e49ecbf 100644 (file)
@@ -49,7 +49,7 @@ properties:
   dmas:
     description: |
       DMA specifiers for tx and rx dma. DMA fifo mode must be used. See
-      the STM32 DMA bindings Documentation/devicetree/bindings/dma/stm32-dma.txt.
+      the STM32 DMA bindings Documentation/devicetree/bindings/dma/st,stm32-dma.yaml.
     items:
       - description: rx DMA channel
       - description: tx DMA channel
index 80bac7a..4b55094 100644 (file)
@@ -125,7 +125,7 @@ examples:
       #size-cells = <1>;
       ranges;
 
-      sram_a: sram@00000000 {
+      sram_a: sram@0 {
         compatible = "mmio-sram";
         reg = <0x00000000 0xc000>;
         #address-cells = <1>;
index d9fdf48..f3e68ed 100644 (file)
@@ -17,7 +17,7 @@ description: |+
                 "brcm,bcm2711-avs-monitor", "syscon", "simple-mfd"
 
   Refer to the the bindings described in
-  Documentation/devicetree/bindings/mfd/syscon.txt
+  Documentation/devicetree/bindings/mfd/syscon.yaml
 
 properties:
   compatible:
index 23e989e..d918cee 100644 (file)
@@ -87,7 +87,7 @@ additionalProperties: false
 
 examples:
   - |
-    timer {
+    timer@1c20c00 {
         compatible = "allwinner,sun4i-a10-timer";
         reg = <0x01c20c00 0x400>;
         interrupts = <22>,
index 1957922..3cb2f4c 100644 (file)
@@ -11,6 +11,7 @@ Required properties:
   "moxa,moxart-timer", "faraday,fttmr010"
   "aspeed,ast2400-timer"
   "aspeed,ast2500-timer"
+  "aspeed,ast2600-timer"
 
 - reg : Should contain registers location and length
 - interrupts : Should contain the three timer interrupts usually with
index 0b63ceb..91f7049 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
   * ingenic,jz4740-tcu
   * ingenic,jz4725b-tcu
   * ingenic,jz4770-tcu
+  * ingenic,x1000-tcu
   followed by "simple-mfd".
 - reg: Should be the offset/length value corresponding to the TCU registers
 - clocks: List of phandle & clock specifiers for clocks external to the TCU.
index 978de7d..330cab2 100644 (file)
@@ -34,14 +34,6 @@ properties:
           - adi,adt7461
             # +/-1C TDM Extended Temp Range I.C
           - adt7461
-            # +/-1C TDM Extended Temp Range I.C
-          - adi,adt7473
-            # +/-1C TDM Extended Temp Range I.C
-          - adi,adt7475
-            # +/-1C TDM Extended Temp Range I.C
-          - adi,adt7476
-            # +/-1C TDM Extended Temp Range I.C
-          - adi,adt7490
             # Three-Axis Digital Accelerometer
           - adi,adxl345
             # Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
@@ -350,6 +342,8 @@ properties:
           - ti,ads7830
             # Temperature Monitoring and Fan Control
           - ti,amc6821
+            # Temperature sensor with 2-wire interface
+          - ti,lm73
             # Temperature sensor with integrated fan control
           - ti,lm96000
             # I2C Touch-Screen Controller
index 267fce1..b0e5e0f 100644 (file)
@@ -22,10 +22,14 @@ description: |
   The DWC3 Glue controls the PHY routing and power, an interrupt line is
   connected to the Glue to serve as OTG ID change detection.
 
+  The Amlogic A1 embeds a DWC3 USB IP Core configured for USB2 in
+  host-only mode.
+
 properties:
   compatible:
     enum:
       - amlogic,meson-g12a-usb-ctrl
+      - amlogic,meson-a1-usb-ctrl
 
   ranges: true
 
@@ -84,6 +88,25 @@ required:
   - phys
   - dr_mode
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          enum:
+            - amlogic,meson-a1-usb-ctrl
+
+    then:
+      properties:
+        clocks:
+          minItems: 3
+        clock-names:
+          items:
+            - const: usb_ctrl
+            - const: usb_bus
+            - const: xtal_usb_ctrl
+      required:
+        - clock-names
+
 examples:
   - |
     usb: usb@ffe09000 {
diff --git a/Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml b/Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml
new file mode 100644 (file)
index 0000000..06399ba
--- /dev/null
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2020 Facebook Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/aspeed,usb-vhub.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ASPEED USB 2.0 Virtual Hub Controller
+
+maintainers:
+  - Benjamin Herrenschmidt <benh@kernel.crashing.org>
+
+description: |+
+  The ASPEED USB 2.0 Virtual Hub Controller implements 1 set of USB Hub
+  register and several sets of Device and Endpoint registers to support
+  the Virtual Hub's downstream USB devices.
+
+  Supported number of devices and endpoints vary depending on hardware
+  revisions. AST2400 and AST2500 Virtual Hub supports 5 downstream devices
+  and 15 generic endpoints, while AST2600 Virtual Hub supports 7 downstream
+  devices and 21 generic endpoints.
+
+properties:
+  compatible:
+    enum:
+      - aspeed,ast2400-usb-vhub
+      - aspeed,ast2500-usb-vhub
+      - aspeed,ast2600-usb-vhub
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  aspeed,vhub-downstream-ports:
+    description: Number of downstream ports supported by the Virtual Hub
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - default: 5
+        minimum: 1
+        maximum: 7
+
+  aspeed,vhub-generic-endpoints:
+    description: Number of generic endpoints supported by the Virtual Hub
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/uint32
+      - default: 15
+        minimum: 1
+        maximum: 21
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - interrupts
+  - aspeed,vhub-downstream-ports
+  - aspeed,vhub-generic-endpoints
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/aspeed-clock.h>
+    vhub: usb-vhub@1e6a0000 {
+            compatible = "aspeed,ast2500-usb-vhub";
+            reg = <0x1e6a0000 0x300>;
+            interrupts = <5>;
+            clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
+            aspeed,vhub-downstream-ports = <5>;
+            aspeed,vhub-generic-endpoints = <15>;
+            pinctrl-names = "default";
+            pinctrl-0 = <&pinctrl_usb2ad_default>;
+    };
index 71cf7ba..6baf00e 100644 (file)
@@ -18,27 +18,15 @@ properties:
           - const: rockchip,rk3066-usb
           - const: snps,dwc2
       - items:
-          - const: rockchip,px30-usb
-          - const: rockchip,rk3066-usb
-          - const: snps,dwc2
-      - items:
-          - const: rockchip,rk3036-usb
-          - const: rockchip,rk3066-usb
-          - const: snps,dwc2
-      - items:
-          - const: rockchip,rv1108-usb
-          - const: rockchip,rk3066-usb
-          - const: snps,dwc2
-      - items:
-          - const: rockchip,rk3188-usb
-          - const: rockchip,rk3066-usb
-          - const: snps,dwc2
-      - items:
-          - const: rockchip,rk3228-usb
-          - const: rockchip,rk3066-usb
-          - const: snps,dwc2
-      - items:
-          - const: rockchip,rk3288-usb
+          - enum:
+            - rockchip,px30-usb
+            - rockchip,rk3036-usb
+            - rockchip,rk3188-usb
+            - rockchip,rk3228-usb
+            - rockchip,rk3288-usb
+            - rockchip,rk3328-usb
+            - rockchip,rk3368-usb
+            - rockchip,rv1108-usb
           - const: rockchip,rk3066-usb
           - const: snps,dwc2
       - const: lantiq,arx100-usb
index 66780a4..9946ff9 100644 (file)
@@ -7,7 +7,8 @@ Required properties:
  - compatible: must be "snps,dwc3"
  - reg : Address and length of the register set for the device
  - interrupts: Interrupts used by the dwc3 controller.
- - clock-names: should contain "ref", "bus_early", "suspend"
+ - clock-names: list of clock names. Ideally should be "ref",
+                "bus_early", "suspend" but may be less or more.
  - clocks: list of phandle and clock specifier pairs corresponding to
            entries in the clock-names property.
 
@@ -36,7 +37,7 @@ Optional properties:
  - phys: from the *Generic PHY* bindings
  - phy-names: from the *Generic PHY* bindings; supported names are "usb2-phy"
        or "usb3-phy".
- - resets: a single pair of phandle and reset specifier
+ - resets: set of phandle and reset specifier pairs
  - snps,usb2-lpm-disable: indicate if we don't want to enable USB2 HW LPM
  - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable
  - snps,dis-start-transfer-quirk: when set, disable isoc START TRANSFER command
@@ -75,6 +76,8 @@ Optional properties:
                        from P0 to P1/P2/P3 without delay.
  - snps,dis-tx-ipgap-linecheck-quirk: when set, disable u2mac linestate check
                        during HS transmit.
+ - snps,parkmode-disable-ss-quirk: when set, all SuperSpeed bus instances in
+                       park mode are disabled.
  - snps,dis_metastability_quirk: when set, disable metastability workaround.
                        CAUTION: use only if you are absolutely sure of it.
  - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
index e6790d2..67c5175 100644 (file)
@@ -35,6 +35,12 @@ Optional properties:
                        the USB data role (USB host or USB device) for a given
                        USB connector, such as Type-C, Type-B(micro).
                        see connector/usb-connector.txt.
+ - role-switch-default-mode: indicating if usb-role-switch is enabled, the
+                       device default operation mode of controller while usb
+                       role is USB_ROLE_NONE. Valid arguments are "host" and
+                       "peripheral". Defaults to "peripheral" if not
+                       specified.
+
 
 This is an attribute to a USB controller such as:
 
diff --git a/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt b/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt
deleted file mode 100644 (file)
index 1680872..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-Ingenic JZ4740 MUSB driver
-
-Required properties:
-
-- compatible: Must be "ingenic,jz4740-musb"
-- reg: Address range of the UDC register set
-- interrupts: IRQ number related to the UDC hardware
-- interrupt-names: must be "mc"
-- clocks: phandle to the "udc" clock
-- clock-names: must be "udc"
-- phys: phandle to the USB PHY
-
-Example:
-
-usb_phy: usb-phy@0 {
-       compatible = "usb-nop-xceiv";
-       #phy-cells = <0>;
-};
-
-udc: usb@13040000 {
-       compatible = "ingenic,jz4740-musb";
-       reg = <0x13040000 0x10000>;
-
-       interrupt-parent = <&intc>;
-       interrupts = <24>;
-       interrupt-names = "mc";
-
-       clocks = <&cgu JZ4740_CLK_UDC>;
-       clock-names = "udc";
-
-       phys = <&usb_phy>;
-};
diff --git a/Documentation/devicetree/bindings/usb/ingenic,jz4770-phy.yaml b/Documentation/devicetree/bindings/usb/ingenic,jz4770-phy.yaml
new file mode 100644 (file)
index 0000000..a81b0b1
--- /dev/null
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/ingenic,jz4770-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ingenic JZ4770 USB PHY devicetree bindings
+
+maintainers:
+  - Paul Cercueil <paul@crapouillou.net>
+
+properties:
+  $nodename:
+    pattern: '^usb-phy@.*'
+
+  compatible:
+    enum:
+      - ingenic,jz4770-phy
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  vcc-supply:
+    description: VCC power supply
+
+  '#phy-cells':
+    const: 0
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - vcc-supply
+  - '#phy-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/jz4770-cgu.h>
+    otg_phy: usb-phy@3c {
+      compatible = "ingenic,jz4770-phy";
+      reg = <0x3c 0x10>;
+
+      vcc-supply = <&vcc>;
+      clocks = <&cgu JZ4770_CLK_OTG_PHY>;
+
+      #phy-cells = <0>;
+    };
diff --git a/Documentation/devicetree/bindings/usb/ingenic,musb.yaml b/Documentation/devicetree/bindings/usb/ingenic,musb.yaml
new file mode 100644 (file)
index 0000000..1d68778
--- /dev/null
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/ingenic,musb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ingenic JZ47xx USB IP DT bindings
+
+maintainers:
+  - Paul Cercueil <paul@crapouillou.net>
+
+properties:
+  $nodename:
+    pattern: '^usb@.*'
+
+  compatible:
+    oneOf:
+      - enum:
+        - ingenic,jz4770-musb
+        - ingenic,jz4740-musb
+      - items:
+        - const: ingenic,jz4725b-musb
+        - const: ingenic,jz4740-musb
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    items:
+      - const: udc
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-names:
+    items:
+      - const: mc
+
+  phys:
+    description: PHY specifier for the USB PHY
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - interrupts
+  - interrupt-names
+  - phys
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/jz4740-cgu.h>
+    usb_phy: usb-phy@0 {
+      compatible = "usb-nop-xceiv";
+      #phy-cells = <0>;
+    };
+
+    udc: usb@13040000 {
+      compatible = "ingenic,jz4740-musb";
+      reg = <0x13040000 0x10000>;
+
+      interrupt-parent = <&intc>;
+      interrupts = <24>;
+      interrupt-names = "mc";
+
+      clocks = <&cgu JZ4740_CLK_UDC>;
+      clock-names = "udc";
+
+      phys = <&usb_phy>;
+    };
diff --git a/Documentation/devicetree/bindings/usb/maxim,max3420-udc.yaml b/Documentation/devicetree/bindings/usb/maxim,max3420-udc.yaml
new file mode 100644 (file)
index 0000000..4241d38
--- /dev/null
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/usb/maxim,max3420-udc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MAXIM MAX3420/1 USB Peripheral Controller
+
+maintainers:
+  - Jassi Brar <jaswinder.singh@linaro.org>
+
+description: |
+  The controller provices USB2.0 compliant FullSpeed peripheral
+  implementation over the SPI interface.
+
+  Specifications about the part can be found at:
+    http://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf
+
+properties:
+  compatible:
+    enum:
+      - maxim,max3420-udc
+      - maxim,max3421-udc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: usb irq from max3420
+      - description: vbus detection irq
+    minItems: 1
+    maxItems: 2
+
+  interrupt-names:
+    items:
+      - const: udc
+      - const: vbus
+    minItems: 1
+    maxItems: 2
+
+  spi-max-frequency:
+    maximum: 26000000
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+
+additionalProperties: false
+
+examples:
+  - |
+      #include <dt-bindings/gpio/gpio.h>
+      #include <dt-bindings/interrupt-controller/irq.h>
+      spi0 {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            udc@0 {
+                  compatible = "maxim,max3420-udc";
+                  reg = <0>;
+                  interrupt-parent = <&gpio>;
+                  interrupts = <0 IRQ_TYPE_EDGE_FALLING>, <10 IRQ_TYPE_EDGE_BOTH>;
+                  interrupt-names = "udc", "vbus";
+                  spi-max-frequency = <12500000>;
+            };
+      };
index 9e67944..fba343f 100644 (file)
@@ -205,6 +205,8 @@ patternProperties:
     description: Colorful GRP, Shenzhen Xueyushi Technology Ltd.
   "^compulab,.*":
     description: CompuLab Ltd.
+  "^coreriver,.*":
+    description: CORERIVER Semiconductor Co.,Ltd.
   "^corpro,.*":
     description: Chengdu Corpro Technology Co., Ltd.
   "^cortina,.*":
@@ -267,6 +269,8 @@ patternProperties:
     description: Dragino Technology Co., Limited
   "^dserve,.*":
     description: dServe Technology B.V.
+  "^dynaimage,.*":
+    description: Dyna-Image
   "^ea,.*":
     description: Embedded Artists AB
   "^ebs-systart,.*":
index 9f1c5bb..24cb64b 100644 (file)
@@ -272,8 +272,8 @@ STA information lifetime rules
 .. kernel-doc:: net/mac80211/sta_info.c
    :doc: STA information lifetime rules
 
-Aggregation
-===========
+Aggregation Functions
+=====================
 
 .. kernel-doc:: net/mac80211/sta_info.h
    :functions: sta_ampdu_mlme
@@ -284,8 +284,8 @@ Aggregation
 .. kernel-doc:: net/mac80211/sta_info.h
    :functions: tid_ampdu_rx
 
-Synchronisation
-===============
+Synchronisation Functions
+=========================
 
 TBD
 
index e5953e7..2104830 100644 (file)
@@ -151,8 +151,8 @@ The details of these operations are:
      Note that callbacks will always be invoked from the DMA
      engines tasklet, never from interrupt context.
 
-Optional: per descriptor metadata
----------------------------------
+  **Optional: per descriptor metadata**
+
   DMAengine provides two ways for metadata support.
 
   DESC_METADATA_CLIENT
@@ -199,12 +199,15 @@ Optional: per descriptor metadata
   DESC_METADATA_CLIENT
 
     - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM:
+
       1. prepare the descriptor (dmaengine_prep_*)
          construct the metadata in the client's buffer
       2. use dmaengine_desc_attach_metadata() to attach the buffer to the
          descriptor
       3. submit the transfer
+
     - DMA_DEV_TO_MEM:
+
       1. prepare the descriptor (dmaengine_prep_*)
       2. use dmaengine_desc_attach_metadata() to attach the buffer to the
          descriptor
@@ -215,6 +218,7 @@ Optional: per descriptor metadata
   DESC_METADATA_ENGINE
 
     - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM:
+
       1. prepare the descriptor (dmaengine_prep_*)
       2. use dmaengine_desc_get_metadata_ptr() to get the pointer to the
          engine's metadata area
@@ -222,7 +226,9 @@ Optional: per descriptor metadata
       4. use dmaengine_desc_set_metadata_len()  to tell the DMA engine the
          amount of data the client has placed into the metadata buffer
       5. submit the transfer
+
     - DMA_DEV_TO_MEM:
+
       1. prepare the descriptor (dmaengine_prep_*)
       2. submit the transfer
       3. on transfer completion, use dmaengine_desc_get_metadata_ptr() to get
@@ -278,8 +284,8 @@ Optional: per descriptor metadata
 
       void dma_async_issue_pending(struct dma_chan *chan);
 
-Further APIs:
--------------
+Further APIs
+------------
 
 1. Terminate APIs
 
index b9df904..bdc45d8 100644 (file)
@@ -5,8 +5,8 @@ DMAEngine documentation
 DMAEngine documentation provides documents for various aspects of DMAEngine
 framework.
 
-DMAEngine documentation
------------------------
+DMAEngine development documentation
+-----------------------------------
 
 This book helps with DMAengine internal APIs and guide for DMAEngine device
 driver writers.
index 790a150..56e5833 100644 (file)
@@ -266,11 +266,15 @@ to use.
   attached (via the dmaengine_desc_attach_metadata() helper to the descriptor.
 
   From the DMA driver the following is expected for this mode:
+
   - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM
+
     The data from the provided metadata buffer should be prepared for the DMA
     controller to be sent alongside of the payload data. Either by copying to a
     hardware descriptor, or highly coupled packet.
+
   - DMA_DEV_TO_MEM
+
     On transfer completion the DMA driver must copy the metadata to the client
     provided metadata buffer before notifying the client about the completion.
     After the transfer completion, DMA drivers must not touch the metadata
@@ -284,10 +288,14 @@ to use.
   and dmaengine_desc_set_metadata_len() is provided as helper functions.
 
   From the DMA driver the following is expected for this mode:
-  - get_metadata_ptr
+
+  - get_metadata_ptr()
+
     Should return a pointer for the metadata buffer, the maximum size of the
     metadata buffer and the currently used / valid (if any) bytes in the buffer.
-  - set_metadata_len
+
+  - set_metadata_len()
+
     It is called by the clients after it have placed the metadata to the buffer
     to let the DMA driver know the number of valid bytes provided.
 
index baa6a85..63887b8 100644 (file)
@@ -210,7 +210,7 @@ probed.
 While the typical use case for sync_state() is to have the kernel cleanly take
 over management of devices from the bootloader, the usage of sync_state() is
 not restricted to that. Use it whenever it makes sense to take an action after
-all the consumers of a device have probed.
+all the consumers of a device have probed::
 
        int     (*remove)       (struct device *dev);
 
diff --git a/Documentation/driver-api/firmware/efi/index.rst b/Documentation/driver-api/firmware/efi/index.rst
new file mode 100644 (file)
index 0000000..4fe8abb
--- /dev/null
@@ -0,0 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============
+UEFI Support
+============
+
+UEFI stub library functions
+===========================
+
+.. kernel-doc:: drivers/firmware/efi/libstub/mem.c
+   :internal:
index 8b041d0..036383d 100644 (file)
@@ -202,3 +202,106 @@ the following file:
 
 If you echo 0 into it means MAX_JIFFY_OFFSET will be used. The data type
 for the timeout is an int.
+
+EFI embedded firmware fallback mechanism
+========================================
+
+On some devices the system's EFI code / ROM may contain an embedded copy
+of firmware for some of the system's integrated peripheral devices and
+the peripheral's Linux device-driver needs to access this firmware.
+
+Device drivers which need such firmware can use the
+firmware_request_platform() function for this, note that this is a
+separate fallback mechanism from the other fallback mechanisms and
+this does not use the sysfs interface.
+
+A device driver which needs this can describe the firmware it needs
+using an efi_embedded_fw_desc struct:
+
+.. kernel-doc:: include/linux/efi_embedded_fw.h
+   :functions: efi_embedded_fw_desc
+
+The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory
+segments for an eight byte sequence matching prefix; if the prefix is found it
+then does a sha256 over length bytes and if that matches makes a copy of length
+bytes and adds that to its list with found firmwares.
+
+To avoid doing this somewhat expensive scan on all systems, dmi matching is
+used. Drivers are expected to export a dmi_system_id array, with each entries'
+driver_data pointing to an efi_embedded_fw_desc.
+
+To register this array with the efi-embedded-fw code, a driver needs to:
+
+1. Always be builtin to the kernel or store the dmi_system_id array in a
+   separate object file which always gets builtin.
+
+2. Add an extern declaration for the dmi_system_id array to
+   include/linux/efi_embedded_fw.h.
+
+3. Add the dmi_system_id array to the embedded_fw_table in
+   drivers/firmware/efi/embedded-firmware.c wrapped in a #ifdef testing that
+   the driver is being builtin.
+
+4. Add "select EFI_EMBEDDED_FIRMWARE if EFI_STUB" to its Kconfig entry.
+
+The firmware_request_platform() function will always first try to load firmware
+with the specified name directly from the disk, so the EFI embedded-fw can
+always be overridden by placing a file under /lib/firmware.
+
+Note that:
+
+1. The code scanning for EFI embedded-firmware runs near the end
+   of start_kernel(), just before calling rest_init(). For normal drivers and
+   subsystems using subsys_initcall() to register themselves this does not
+   matter. This means that code running earlier cannot use EFI
+   embedded-firmware.
+
+2. At the moment the EFI embedded-fw code assumes that firmwares always start at
+   an offset which is a multiple of 8 bytes, if this is not true for your case
+   send in a patch to fix this.
+
+3. At the moment the EFI embedded-fw code only works on x86 because other archs
+   free EFI_BOOT_SERVICES_CODE before the EFI embedded-fw code gets a chance to
+   scan it.
+
+4. The current brute-force scanning of EFI_BOOT_SERVICES_CODE is an ad-hoc
+   brute-force solution. There has been discussion to use the UEFI Platform
+   Initialization (PI) spec's Firmware Volume protocol. This has been rejected
+   because the FV Protocol relies on *internal* interfaces of the PI spec, and:
+   1. The PI spec does not define peripheral firmware at all
+   2. The internal interfaces of the PI spec do not guarantee any backward
+   compatibility. Any implementation details in FV may be subject to change,
+   and may vary system to system. Supporting the FV Protocol would be
+   difficult as it is purposely ambiguous.
+
+Example how to check for and extract embedded firmware
+------------------------------------------------------
+
+To check for, for example Silead touchscreen controller embedded firmware,
+do the following:
+
+1. Boot the system with efi=debug on the kernel commandline
+
+2. cp /sys/kernel/debug/efi/boot_services_code? to your home dir
+
+3. Open the boot_services_code? files in a hex-editor, search for the
+   magic prefix for Silead firmware: F0 00 00 00 02 00 00 00, this gives you
+   the beginning address of the firmware inside the boot_services_code? file.
+
+4. The firmware has a specific pattern, it starts with a 8 byte page-address,
+   typically F0 00 00 00 02 00 00 00 for the first page followed by 32-bit
+   word-address + 32-bit value pairs. With the word-address incrementing 4
+   bytes (1 word) for each pair until a page is complete. A complete page is
+   followed by a new page-address, followed by more word + value pairs. This
+   leads to a very distinct pattern. Scroll down until this pattern stops,
+   this gives you the end of the firmware inside the boot_services_code? file.
+
+5. "dd if=boot_services_code? of=firmware bs=1 skip=<begin-addr> count=<len>"
+   will extract the firmware for you. Inspect the firmware file in a
+   hexeditor to make sure you got the dd parameters correct.
+
+6. Copy it to /lib/firmware under the expected name to test it.
+
+7. If the extracted firmware works, you can use the found info to fill an
+   efi_embedded_fw_desc struct to describe it, run "sha256sum firmware"
+   to get the sha256sum to put in the sha256 field.
index 29da39e..57415d6 100644 (file)
@@ -6,6 +6,7 @@ Linux Firmware API
 
    introduction
    core
+   efi/index
    request_firmware
    other_interfaces
 
index 88c8173..6064672 100644 (file)
@@ -12,6 +12,8 @@ a driver issues a firmware API call.
   return it immediately
 * The ''Direct filesystem lookup'' is performed next, if found we
   return it immediately
+* The ''Platform firmware fallback'' is performed next, but only when
+  firmware_request_platform() is used, if found we return it immediately
 * If no firmware has been found and the fallback mechanism was enabled
   the sysfs interface is created. After this either a kobject uevent
   is issued or the custom firmware loading is relied upon for firmware
index f62bdcb..cd07646 100644 (file)
@@ -25,6 +25,11 @@ firmware_request_nowarn
 .. kernel-doc:: drivers/base/firmware_loader/main.c
    :functions: firmware_request_nowarn
 
+firmware_request_platform
+-------------------------
+.. kernel-doc:: drivers/base/firmware_loader/main.c
+   :functions: firmware_request_platform
+
 request_firmware_direct
 -----------------------
 .. kernel-doc:: drivers/base/firmware_loader/main.c
index 0ebe205..d4e78cb 100644 (file)
@@ -17,6 +17,7 @@ available subsections can be seen below.
    driver-model/index
    basics
    infrastructure
+   ioctl
    early-userspace/index
    pm/index
    clk
@@ -74,11 +75,12 @@ available subsections can be seen below.
    connector
    console
    dcdbas
-   edid
    eisa
    ipmb
    isa
    isapnp
+   io-mapping
+   io_ordering
    generic-counter
    lightnvm-pblk
    memory-devices/index
index f47a69b..03dfa9c 100644 (file)
@@ -53,9 +53,7 @@ in need to reconfigure the pins on the connector, the alternate mode driver
 needs to notify the bus using :c:func:`typec_altmode_notify()`. The driver
 passes the negotiated SVID specific pin configuration value to the function as
 parameter. The bus driver will then configure the mux behind the connector using
-that value as the state value for the mux, and also call blocking notification
-chain to notify the external drivers about the state of the connector that need
-to know it.
+that value as the state value for the mux.
 
 NOTE: The SVID specific pin configuration values must always start from
 ``TYPEC_STATE_MODAL``. USB Type-C specification defines two default states for
@@ -80,19 +78,6 @@ Helper macro ``TYPEC_MODAL_STATE()`` can also be used::
 #define ALTMODEX_CONF_A = TYPEC_MODAL_STATE(0);
 #define ALTMODEX_CONF_B = TYPEC_MODAL_STATE(1);
 
-Notification chain
-~~~~~~~~~~~~~~~~~~
-
-The drivers for the components that the alternate modes are designed for need to
-get details regarding the results of the negotiation with the partner, and the
-pin configuration of the connector. In case of DisplayPort alternate mode for
-example, the GPU drivers will need to know those details. In case of
-Thunderbolt alternate mode, the thunderbolt drivers will need to know them, and
-so on.
-
-The notification chain is designed for this purpose. The drivers can register
-notifiers with :c:func:`typec_altmode_register_notifier()`.
-
 Cable plug alternate modes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -129,8 +114,3 @@ Cable Plug operations
 
 .. kernel-doc:: drivers/usb/typec/bus.c
    :functions: typec_altmode_get_plug typec_altmode_put_plug
-
-Notifications
-~~~~~~~~~~~~~
-.. kernel-doc:: drivers/usb/typec/class.c
-   :functions: typec_altmode_register_notifier typec_altmode_unregister_notifier
index 2dc5df6..3d492a3 100644 (file)
@@ -23,7 +23,7 @@
     |    openrisc: | TODO |
     |      parisc: | TODO |
     |     powerpc: |  ok  |
-    |       riscv: | TODO |
+    |       riscv: |  ok  |
     |        s390: |  ok  |
     |          sh: |  ok  |
     |       sparc: |  ok  |
similarity index 63%
rename from Documentation/filesystems/9p.txt
rename to Documentation/filesystems/9p.rst
index fec7144..f054d1c 100644 (file)
@@ -1,7 +1,10 @@
-                   v9fs: Plan 9 Resource Sharing for Linux
-                   =======================================
+.. SPDX-License-Identifier: GPL-2.0
 
-ABOUT
+=======================================
+v9fs: Plan 9 Resource Sharing for Linux
+=======================================
+
+About
 =====
 
 v9fs is a Unix implementation of the Plan 9 9p remote filesystem protocol.
@@ -14,32 +17,34 @@ and Maya Gokhale.  Additional development by Greg Watson
 
 The best detailed explanation of the Linux implementation and applications of
 the 9p client is available in the form of a USENIX paper:
+
    http://www.usenix.org/events/usenix05/tech/freenix/hensbergen.html
 
 Other applications are described in the following papers:
+
        * XCPU & Clustering
-               http://xcpu.org/papers/xcpu-talk.pdf
+         http://xcpu.org/papers/xcpu-talk.pdf
        * KVMFS: control file system for KVM
-               http://xcpu.org/papers/kvmfs.pdf
+         http://xcpu.org/papers/kvmfs.pdf
        * CellFS: A New Programming Model for the Cell BE
-               http://xcpu.org/papers/cellfs-talk.pdf
+         http://xcpu.org/papers/cellfs-talk.pdf
        * PROSE I/O: Using 9p to enable Application Partitions
-               http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf
+         http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf
        * VirtFS: A Virtualization Aware File System pass-through
-               http://goo.gl/3WPDg
+         http://goo.gl/3WPDg
 
-USAGE
+Usage
 =====
 
-For remote file server:
+For remote file server::
 
        mount -t 9p 10.10.1.2 /mnt/9
 
-For Plan 9 From User Space applications (http://swtch.com/plan9)
+For Plan 9 From User Space applications (http://swtch.com/plan9)::
 
        mount -t 9p `namespace`/acme /mnt/9 -o trans=unix,uname=$USER
 
-For server running on QEMU host with virtio transport:
+For server running on QEMU host with virtio transport::
 
        mount -t 9p -o trans=virtio <mount_tag> /mnt/9
 
@@ -48,18 +53,22 @@ mount points. Each 9P export is seen by the client as a virtio device with an
 associated "mount_tag" property. Available mount tags can be
 seen by reading /sys/bus/virtio/drivers/9pnet_virtio/virtio<n>/mount_tag files.
 
-OPTIONS
+Options
 =======
 
+  ============= ===============================================================
   trans=name   select an alternative transport.  Valid options are
                currently:
-                       unix    - specifying a named pipe mount point
-                       tcp     - specifying a normal TCP/IP connection
-                       fd      - used passed file descriptors for connection
-                                (see rfdno and wfdno)
-                       virtio  - connect to the next virtio channel available
-                               (from QEMU with trans_virtio module)
-                       rdma    - connect to a specified RDMA channel
+
+                       ========  ============================================
+                       unix      specifying a named pipe mount point
+                       tcp       specifying a normal TCP/IP connection
+                       fd        used passed file descriptors for connection
+                                  (see rfdno and wfdno)
+                       virtio    connect to the next virtio channel available
+                                 (from QEMU with trans_virtio module)
+                       rdma      connect to a specified RDMA channel
+                       ========  ============================================
 
   uname=name   user name to attempt mount as on the remote server.  The
                server may override or ignore this value.  Certain user
@@ -69,28 +78,36 @@ OPTIONS
                offering several exported file systems.
 
   cache=mode   specifies a caching policy.  By default, no caches are used.
-                        none = default no cache policy, metadata and data
+
+                        none
+                               default no cache policy, metadata and data
                                 alike are synchronous.
-                       loose = no attempts are made at consistency,
+                       loose
+                               no attempts are made at consistency,
                                 intended for exclusive, read-only mounts
-                        fscache = use FS-Cache for a persistent, read-only
+                        fscache
+                               use FS-Cache for a persistent, read-only
                                cache backend.
-                        mmap = minimal cache that is only used for read-write
+                        mmap
+                               minimal cache that is only used for read-write
                                 mmap.  Northing else is cached, like cache=none
 
   debug=n      specifies debug level.  The debug level is a bitmask.
-                       0x01  = display verbose error messages
-                       0x02  = developer debug (DEBUG_CURRENT)
-                       0x04  = display 9p trace
-                       0x08  = display VFS trace
-                       0x10  = display Marshalling debug
-                       0x20  = display RPC debug
-                       0x40  = display transport debug
-                       0x80  = display allocation debug
-                       0x100 = display protocol message debug
-                       0x200 = display Fid debug
-                       0x400 = display packet debug
-                       0x800 = display fscache tracing debug
+
+                       =====   ================================
+                       0x01    display verbose error messages
+                       0x02    developer debug (DEBUG_CURRENT)
+                       0x04    display 9p trace
+                       0x08    display VFS trace
+                       0x10    display Marshalling debug
+                       0x20    display RPC debug
+                       0x40    display transport debug
+                       0x80    display allocation debug
+                       0x100   display protocol message debug
+                       0x200   display Fid debug
+                       0x400   display packet debug
+                       0x800   display fscache tracing debug
+                       =====   ================================
 
   rfdno=n      the file descriptor for reading with trans=fd
 
@@ -103,9 +120,12 @@ OPTIONS
   noextend     force legacy mode (no 9p2000.u or 9p2000.L semantics)
 
   version=name Select 9P protocol version. Valid options are:
-                       9p2000          - Legacy mode (same as noextend)
-                       9p2000.u        - Use 9P2000.u protocol
-                       9p2000.L        - Use 9P2000.L protocol
+
+                       ========        ==============================
+                       9p2000          Legacy mode (same as noextend)
+                       9p2000.u        Use 9P2000.u protocol
+                       9p2000.L        Use 9P2000.L protocol
+                       ========        ==============================
 
   dfltuid      attempt to mount as a particular uid
 
@@ -118,22 +138,27 @@ OPTIONS
                hosts.  This functionality will be expanded in later versions.
 
   access       there are four access modes.
-                       user  = if a user tries to access a file on v9fs
+                       user
+                               if a user tries to access a file on v9fs
                                filesystem for the first time, v9fs sends an
                                attach command (Tattach) for that user.
                                This is the default mode.
-                       <uid> = allows only user with uid=<uid> to access
+                       <uid>
+                               allows only user with uid=<uid> to access
                                the files on the mounted filesystem
-                       any   = v9fs does single attach and performs all
+                       any
+                               v9fs does single attach and performs all
                                operations as one user
-                       client = ACL based access check on the 9p client
+                       clien
+                                ACL based access check on the 9p client
                                 side for access validation
 
   cachetag     cache tag to use the specified persistent cache.
                cache tags for existing cache sessions can be listed at
                /sys/fs/9p/caches. (applies only to cache=fscache)
+  ============= ===============================================================
 
-RESOURCES
+Resources
 =========
 
 Protocol specifications are maintained on github:
@@ -158,4 +183,3 @@ http://plan9.bell-labs.com/plan9
 
 For information on Plan 9 from User Space (Plan 9 applications and libraries
 ported to Linux/BSD/OSX/etc) check out http://swtch.com/plan9
-
similarity index 85%
rename from Documentation/filesystems/adfs.txt
rename to Documentation/filesystems/adfs.rst
index 0baa8e8..5b22cae 100644 (file)
@@ -1,3 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============================
+Acorn Disc Filing System - ADFS
+===============================
+
 Filesystems supported by ADFS
 -----------------------------
 
@@ -25,6 +31,7 @@ directory updates, specifically updating the access mode and timestamp.
 Mount options for ADFS
 ----------------------
 
+  ============  ======================================================
   uid=nnn      All files in the partition will be owned by
                user id nnn.  Default 0 (root).
   gid=nnn      All files in the partition will be in group
@@ -36,22 +43,23 @@ Mount options for ADFS
   ftsuffix=n   When ftsuffix=0, no file type suffix will be applied.
                When ftsuffix=1, a hexadecimal suffix corresponding to
                the RISC OS file type will be added.  Default 0.
+  ============  ======================================================
 
 Mapping of ADFS permissions to Linux permissions
 ------------------------------------------------
 
   ADFS permissions consist of the following:
 
-       Owner read
-       Owner write
-       Other read
-       Other write
+       Owner read
+       Owner write
+       Other read
+       Other write
 
   (In older versions, an 'execute' permission did exist, but this
-   does not hold the same meaning as the Linux 'execute' permission
-   and is now obsolete).
+  does not hold the same meaning as the Linux 'execute' permission
+  and is now obsolete).
 
-  The mapping is performed as follows:
+  The mapping is performed as follows::
 
        Owner read                              -> -r--r--r--
        Owner write                             -> --w--w---w
@@ -66,17 +74,18 @@ Mapping of ADFS permissions to Linux permissions
        Possible other mode permissions         -> ----rwxrwx
 
   Hence, with the default masks, if a file is owner read/write, and
-  not a UnixExec filetype, then the permissions will be:
+  not a UnixExec filetype, then the permissions will be::
 
                        -rw-------
 
   However, if the masks were ownmask=0770,othmask=0007, then this would
-  be modified to:
+  be modified to::
+
                        -rw-rw----
 
   There is no restriction on what you can do with these masks.  You may
   wish that either read bits give read access to the file for all, but
-  keep the default write protection (ownmask=0755,othmask=0577):
+  keep the default write protection (ownmask=0755,othmask=0577)::
 
                        -rw-r--r--
 
similarity index 86%
rename from Documentation/filesystems/affs.txt
rename to Documentation/filesystems/affs.rst
index 71b63c2..7f1a40d 100644 (file)
@@ -1,9 +1,13 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============================
 Overview of Amiga Filesystems
 =============================
 
 Not all varieties of the Amiga filesystems are supported for reading and
 writing. The Amiga currently knows six different filesystems:
 
+============== ===============================================================
 DOS\0          The old or original filesystem, not really suited for
                hard disks and normally not used on them, either.
                Supported read/write.
@@ -23,6 +27,7 @@ DOS\4         The original filesystem with directory cache. The directory
                sense on hard disks. Supported read only.
 
 DOS\5          The Fast File System with directory cache. Supported read only.
+============== ===============================================================
 
 All of the above filesystems allow block sizes from 512 to 32K bytes.
 Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks
@@ -36,14 +41,18 @@ are supported, too.
 Mount options for the AFFS
 ==========================
 
-protect                If this option is set, the protection bits cannot be altered.
+protect
+               If this option is set, the protection bits cannot be altered.
 
-setuid[=uid]   This sets the owner of all files and directories in the file
+setuid[=uid]
+               This sets the owner of all files and directories in the file
                system to uid or the uid of the current user, respectively.
 
-setgid[=gid]   Same as above, but for gid.
+setgid[=gid]
+               Same as above, but for gid.
 
-mode=mode      Sets the mode flags to the given (octal) value, regardless
+mode=mode
+               Sets the mode flags to the given (octal) value, regardless
                of the original permissions. Directories will get an x
                permission if the corresponding r bit is set.
                This is useful since most of the plain AmigaOS files
@@ -53,33 +62,41 @@ nofilenametruncate
                The file system will return an error when filename exceeds
                standard maximum filename length (30 characters).
 
-reserved=num   Sets the number of reserved blocks at the start of the
+reserved=num
+               Sets the number of reserved blocks at the start of the
                partition to num. You should never need this option.
                Default is 2.
 
-root=block     Sets the block number of the root block. This should never
+root=block
+               Sets the block number of the root block. This should never
                be necessary.
 
-bs=blksize     Sets the blocksize to blksize. Valid block sizes are 512,
+bs=blksize
+               Sets the blocksize to blksize. Valid block sizes are 512,
                1024, 2048 and 4096. Like the root option, this should
                never be necessary, as the affs can figure it out itself.
 
-quiet          The file system will not return an error for disallowed
+quiet
+               The file system will not return an error for disallowed
                mode changes.
 
-verbose                The volume name, file system type and block size will
+verbose
+               The volume name, file system type and block size will
                be written to the syslog when the filesystem is mounted.
 
-mufs           The filesystem is really a muFS, also it doesn't
+mufs
+               The filesystem is really a muFS, also it doesn't
                identify itself as one. This option is necessary if
                the filesystem wasn't formatted as muFS, but is used
                as one.
 
-prefix=path    Path will be prefixed to every absolute path name of
+prefix=path
+               Path will be prefixed to every absolute path name of
                symbolic links on an AFFS partition. Default = "/".
                (See below.)
 
-volume=name    When symbolic links with an absolute path are created
+volume=name
+               When symbolic links with an absolute path are created
                on an AFFS partition, name will be prepended as the
                volume name. Default = "" (empty string).
                (See below.)
@@ -119,7 +136,7 @@ The Linux rwxrwxrwx file mode is handled as follows:
 
   - All other flags (suid, sgid, ...) are ignored and will
     not be retained.
-    
+
 Newly created files and directories will get the user and group ID
 of the current user and a mode according to the umask.
 
@@ -148,11 +165,13 @@ might be "User", "WB" and "Graphics", the mount points /amiga/User,
 Examples
 ========
 
-Command line:
+Command line::
+
     mount  Archive/Amiga/Workbench3.1.adf /mnt -t affs -o loop,verbose
     mount  /dev/sda3 /Amiga -t affs
 
-/etc/fstab entry:
+/etc/fstab entry::
+
     /dev/sdb5  /amiga/Workbench    affs    noauto,user,exec,verbose 0 0
 
 IMPORTANT NOTE
@@ -170,7 +189,8 @@ before booting Windows!
 
 If the damage is already done, the following should fix the RDB
 (where <disk> is the device name).
-DO AT YOUR OWN RISK:
+
+DO AT YOUR OWN RISK::
 
   dd if=/dev/<disk> of=rdb.tmp count=1
   cp rdb.tmp rdb.fixed
@@ -189,10 +209,14 @@ By default, filenames are truncated to 30 characters without warning.
 'nofilenametruncate' mount option can change that behavior.
 
 Case is ignored by the affs in filename matching, but Linux shells
-do care about the case. Example (with /wb being an affs mounted fs):
+do care about the case. Example (with /wb being an affs mounted fs)::
+
     rm /wb/WRONGCASE
-will remove /mnt/wrongcase, but
+
+will remove /mnt/wrongcase, but::
+
     rm /wb/WR*
+
 will not since the names are matched by the shell.
 
 The block allocation is designed for hard disk partitions. If more
@@ -219,4 +243,4 @@ due to an incompatibility with the Amiga floppy controller.
 
 If you are interested in an Amiga Emulator for Linux, look at
 
-http://web.archive.org/web/*/http://www.freiburg.linux.de/~uae/
+http://web.archive.org/web/%2E/http://www.freiburg.linux.de/~uae/
similarity index 90%
rename from Documentation/filesystems/afs.txt
rename to Documentation/filesystems/afs.rst
index 8c6ea7b..c4ec39a 100644 (file)
@@ -1,8 +1,10 @@
-                            ====================
-                            kAFS: AFS FILESYSTEM
-                            ====================
+.. SPDX-License-Identifier: GPL-2.0
 
-Contents:
+====================
+kAFS: AFS FILESYSTEM
+====================
+
+.. Contents:
 
  - Overview.
  - Usage.
@@ -14,8 +16,7 @@ Contents:
  - The @sys substitution.
 
 
-========
-OVERVIEW
+Overview
 ========
 
 This filesystem provides a fairly simple secure AFS filesystem driver. It is
@@ -35,35 +36,33 @@ It does not yet support the following AFS features:
  (*) pioctl() system call.
 
 
-===========
-COMPILATION
+Compilation
 ===========
 
 The filesystem should be enabled by turning on the kernel configuration
-options:
+options::
 
        CONFIG_AF_RXRPC         - The RxRPC protocol transport
        CONFIG_RXKAD            - The RxRPC Kerberos security handler
        CONFIG_AFS              - The AFS filesystem
 
-Additionally, the following can be turned on to aid debugging:
+Additionally, the following can be turned on to aid debugging::
 
        CONFIG_AF_RXRPC_DEBUG   - Permit AF_RXRPC debugging to be enabled
        CONFIG_AFS_DEBUG        - Permit AFS debugging to be enabled
 
 They permit the debugging messages to be turned on dynamically by manipulating
-the masks in the following files:
+the masks in the following files::
 
        /sys/module/af_rxrpc/parameters/debug
        /sys/module/kafs/parameters/debug
 
 
-=====
-USAGE
+Usage
 =====
 
 When inserting the driver modules the root cell must be specified along with a
-list of volume location server IP addresses:
+list of volume location server IP addresses::
 
        modprobe rxrpc
        modprobe kafs rootcell=cambridge.redhat.com:172.16.18.73:172.16.18.91
@@ -77,14 +76,14 @@ The second module is the kerberos RxRPC security driver, and the third module
 is the actual filesystem driver for the AFS filesystem.
 
 Once the module has been loaded, more modules can be added by the following
-procedure:
+procedure::
 
        echo add grand.central.org 18.9.48.14:128.2.203.61:130.237.48.87 >/proc/fs/afs/cells
 
 Where the parameters to the "add" command are the name of a cell and a list of
 volume location servers within that cell, with the latter separated by colons.
 
-Filesystems can be mounted anywhere by commands similar to the following:
+Filesystems can be mounted anywhere by commands similar to the following::
 
        mount -t afs "%cambridge.redhat.com:root.afs." /afs
        mount -t afs "#cambridge.redhat.com:root.cell." /afs/cambridge
@@ -104,8 +103,7 @@ named volume will be looked up in the cell specified during modprobe.
 Additional cells can be added through /proc (see later section).
 
 
-===========
-MOUNTPOINTS
+Mountpoints
 ===========
 
 AFS has a concept of mountpoints. In AFS terms, these are specially formatted
@@ -123,42 +121,40 @@ culled first.  If all are culled, then the requested volume will also be
 unmounted, otherwise error EBUSY will be returned.
 
 This can be used by the administrator to attempt to unmount the whole AFS tree
-mounted on /afs in one go by doing:
+mounted on /afs in one go by doing::
 
        umount /afs
 
 
-============
-DYNAMIC ROOT
+Dynamic Root
 ============
 
 A mount option is available to create a serverless mount that is only usable
-for dynamic lookup.  Creating such a mount can be done by, for example:
+for dynamic lookup.  Creating such a mount can be done by, for example::
 
        mount -t afs none /afs -o dyn
 
 This creates a mount that just has an empty directory at the root.  Attempting
 to look up a name in this directory will cause a mountpoint to be created that
-looks up a cell of the same name, for example:
+looks up a cell of the same name, for example::
 
        ls /afs/grand.central.org/
 
 
-===============
-PROC FILESYSTEM
+Proc Filesystem
 ===============
 
 The AFS modules creates a "/proc/fs/afs/" directory and populates it:
 
   (*) A "cells" file that lists cells currently known to the afs module and
-      their usage counts:
+      their usage counts::
 
        [root@andromeda ~]# cat /proc/fs/afs/cells
        USE NAME
          3 cambridge.redhat.com
 
   (*) A directory per cell that contains files that list volume location
-      servers, volumes, and active servers known within that cell.
+      servers, volumes, and active servers known within that cell::
 
        [root@andromeda ~]# cat /proc/fs/afs/cambridge.redhat.com/servers
        USE ADDR            STATE
@@ -171,8 +167,7 @@ The AFS modules creates a "/proc/fs/afs/" directory and populates it:
          1 Val 20000000 20000001 20000002 root.afs
 
 
-=================
-THE CELL DATABASE
+The Cell Database
 =================
 
 The filesystem maintains an internal database of all the cells it knows and the
@@ -181,7 +176,7 @@ the system belongs is added to the database when modprobe is performed by the
 "rootcell=" argument or, if compiled in, using a "kafs.rootcell=" argument on
 the kernel command line.
 
-Further cells can be added by commands similar to the following:
+Further cells can be added by commands similar to the following::
 
        echo add CELLNAME VLADDR[:VLADDR][:VLADDR]... >/proc/fs/afs/cells
        echo add grand.central.org 18.9.48.14:128.2.203.61:130.237.48.87 >/proc/fs/afs/cells
@@ -189,8 +184,7 @@ Further cells can be added by commands similar to the following:
 No other cell database operations are available at this time.
 
 
-========
-SECURITY
+Security
 ========
 
 Secure operations are initiated by acquiring a key using the klog program.  A
@@ -198,17 +192,17 @@ very primitive klog program is available at:
 
        http://people.redhat.com/~dhowells/rxrpc/klog.c
 
-This should be compiled by:
+This should be compiled by::
 
        make klog LDLIBS="-lcrypto -lcrypt -lkrb4 -lkeyutils"
 
-And then run as:
+And then run as::
 
        ./klog
 
 Assuming it's successful, this adds a key of type RxRPC, named for the service
 and cell, eg: "afs@<cellname>".  This can be viewed with the keyctl program or
-by cat'ing /proc/keys:
+by cat'ing /proc/keys::
 
        [root@andromeda ~]# keyctl show
        Session Keyring
@@ -232,20 +226,19 @@ socket), then the operations on the file will be made with key that was used to
 open the file.
 
 
-=====================
-THE @SYS SUBSTITUTION
+The @sys Substitution
 =====================
 
 The list of up to 16 @sys substitutions for the current network namespace can
-be configured by writing a list to /proc/fs/afs/sysname:
+be configured by writing a list to /proc/fs/afs/sysname::
 
        [root@andromeda ~]# echo foo amd64_linux_26 >/proc/fs/afs/sysname
 
-or cleared entirely by writing an empty list:
+or cleared entirely by writing an empty list::
 
        [root@andromeda ~]# echo >/proc/fs/afs/sysname
 
-The current list for current network namespace can be retrieved by:
+The current list for current network namespace can be retrieved by::
 
        [root@andromeda ~]# cat /proc/fs/afs/sysname
        foo
@@ -1,4 +1,6 @@
+.. SPDX-License-Identifier: GPL-2.0
 
+====================================================================
 Miscellaneous Device control operations for the autofs kernel module
 ====================================================================
 
@@ -36,24 +38,24 @@ For example, there are two types of automount maps, direct (in the kernel
 module source you will see a third type called an offset, which is just
 a direct mount in disguise) and indirect.
 
-Here is a master map with direct and indirect map entries:
+Here is a master map with direct and indirect map entries::
 
-/-      /etc/auto.direct
-/test   /etc/auto.indirect
+    /-      /etc/auto.direct
+    /test   /etc/auto.indirect
 
-and the corresponding map files:
+and the corresponding map files::
 
-/etc/auto.direct:
+    /etc/auto.direct:
 
-/automount/dparse/g6  budgie:/autofs/export1
-/automount/dparse/g1  shark:/autofs/export1
-and so on.
+    /automount/dparse/g6  budgie:/autofs/export1
+    /automount/dparse/g1  shark:/autofs/export1
+    and so on.
 
-/etc/auto.indirect:
+/etc/auto.indirect::
 
-g1    shark:/autofs/export1
-g6    budgie:/autofs/export1
-and so on.
+    g1    shark:/autofs/export1
+    g6    budgie:/autofs/export1
+    and so on.
 
 For the above indirect map an autofs file system is mounted on /test and
 mounts are triggered for each sub-directory key by the inode lookup
@@ -69,23 +71,23 @@ use the follow_link inode operation to trigger the mount.
 But, each entry in direct and indirect maps can have offsets (making
 them multi-mount map entries).
 
-For example, an indirect mount map entry could also be:
+For example, an indirect mount map entry could also be::
 
-g1  \
-   /        shark:/autofs/export5/testing/test \
-   /s1      shark:/autofs/export/testing/test/s1 \
-   /s2      shark:/autofs/export5/testing/test/s2 \
-   /s1/ss1  shark:/autofs/export1 \
-   /s2/ss2  shark:/autofs/export2
+    g1  \
+    /        shark:/autofs/export5/testing/test \
+    /s1      shark:/autofs/export/testing/test/s1 \
+    /s2      shark:/autofs/export5/testing/test/s2 \
+    /s1/ss1  shark:/autofs/export1 \
+    /s2/ss2  shark:/autofs/export2
 
-and a similarly a direct mount map entry could also be:
+and a similarly a direct mount map entry could also be::
 
-/automount/dparse/g1 \
-    /       shark:/autofs/export5/testing/test \
-    /s1     shark:/autofs/export/testing/test/s1 \
-    /s2     shark:/autofs/export5/testing/test/s2 \
-    /s1/ss1 shark:/autofs/export2 \
-    /s2/ss2 shark:/autofs/export2
+    /automount/dparse/g1 \
+       /       shark:/autofs/export5/testing/test \
+       /s1     shark:/autofs/export/testing/test/s1 \
+       /s2     shark:/autofs/export5/testing/test/s2 \
+       /s1/ss1 shark:/autofs/export2 \
+       /s2/ss2 shark:/autofs/export2
 
 One of the issues with version 4 of autofs was that, when mounting an
 entry with a large number of offsets, possibly with nesting, we needed
@@ -170,32 +172,32 @@ autofs Miscellaneous Device mount control interface
 The control interface is opening a device node, typically /dev/autofs.
 
 All the ioctls use a common structure to pass the needed parameter
-information and return operation results:
-
-struct autofs_dev_ioctl {
-       __u32 ver_major;
-       __u32 ver_minor;
-       __u32 size;             /* total size of data passed in
-                                * including this struct */
-       __s32 ioctlfd;          /* automount command fd */
-
-       /* Command parameters */
-       union {
-               struct args_protover            protover;
-               struct args_protosubver         protosubver;
-               struct args_openmount           openmount;
-               struct args_ready               ready;
-               struct args_fail                fail;
-               struct args_setpipefd           setpipefd;
-               struct args_timeout             timeout;
-               struct args_requester           requester;
-               struct args_expire              expire;
-               struct args_askumount           askumount;
-               struct args_ismountpoint        ismountpoint;
-       };
-
-       char path[0];
-};
+information and return operation results::
+
+    struct autofs_dev_ioctl {
+           __u32 ver_major;
+           __u32 ver_minor;
+           __u32 size;             /* total size of data passed in
+                                   * including this struct */
+           __s32 ioctlfd;          /* automount command fd */
+
+           /* Command parameters */
+           union {
+                   struct args_protover                protover;
+                   struct args_protosubver             protosubver;
+                   struct args_openmount               openmount;
+                   struct args_ready           ready;
+                   struct args_fail            fail;
+                   struct args_setpipefd               setpipefd;
+                   struct args_timeout         timeout;
+                   struct args_requester               requester;
+                   struct args_expire          expire;
+                   struct args_askumount               askumount;
+                   struct args_ismountpoint    ismountpoint;
+           };
+
+           char path[0];
+    };
 
 The ioctlfd field is a mount point file descriptor of an autofs mount
 point. It is returned by the open call and is used by all calls except
@@ -212,7 +214,7 @@ is used account for the increased structure length when translating the
 structure sent from user space.
 
 This structure can be initialized before setting specific fields by using
-the void function call init_autofs_dev_ioctl(struct autofs_dev_ioctl *).
+the void function call init_autofs_dev_ioctl(``struct autofs_dev_ioctl *``).
 
 All of the ioctls perform a copy of this structure from user space to
 kernel space and return -EINVAL if the size parameter is smaller than
similarity index 83%
rename from Documentation/filesystems/befs.txt
rename to Documentation/filesystems/befs.rst
index da45e6c..79f9740 100644 (file)
@@ -1,48 +1,54 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================
 BeOS filesystem for Linux
+=========================
 
 Document last updated: Dec 6, 2001
 
-WARNING
+Warning
 =======
 Make sure you understand that this is alpha software.  This means that the
-implementation is neither complete nor well-tested. 
+implementation is neither complete nor well-tested.
 
 I DISCLAIM ALL RESPONSIBILITY FOR ANY POSSIBLE BAD EFFECTS OF THIS CODE!
 
-LICENSE
-=====
-This software is covered by the GNU General Public License. 
+License
+=======
+This software is covered by the GNU General Public License.
 See the file COPYING for the complete text of the license.
 Or the GNU website: <http://www.gnu.org/licenses/licenses.html>
 
-AUTHOR
-=====
+Author
+======
 The largest part of the code written by Will Dyson <will_dyson@pobox.com>
 He has been working on the code since Aug 13, 2001. See the changelog for
 details.
 
 Original Author: Makoto Kato <m_kato@ga2.so-net.ne.jp>
+
 His original code can still be found at:
 <http://hp.vector.co.jp/authors/VA008030/bfs/>
+
 Does anyone know of a more current email address for Makoto? He doesn't
 respond to the address given above...
 
 This filesystem doesn't have a maintainer.
 
-WHAT IS THIS DRIVER?
-==================
-This module implements the native filesystem of BeOS http://www.beincorporated.com/ 
+What is this Driver?
+====================
+This module implements the native filesystem of BeOS http://www.beincorporated.com/
 for the linux 2.4.1 and later kernels. Currently it is a read-only
 implementation.
 
 Which is it, BFS or BEFS?
-================
-Be, Inc said, "BeOS Filesystem is officially called BFS, not BeFS". 
+=========================
+Be, Inc said, "BeOS Filesystem is officially called BFS, not BeFS".
 But Unixware Boot Filesystem is called bfs, too. And they are already in
 the kernel. Because of this naming conflict, on Linux the BeOS
 filesystem is called befs.
 
-HOW TO INSTALL
+How to Install
 ==============
 step 1.  Install the BeFS  patch into the source code tree of linux.
 
@@ -54,16 +60,16 @@ is called patch-befs-xxx, you would do the following:
        patch -p1 < /path/to/patch-befs-xxx
 
 if the patching step fails (i.e. there are rejected hunks), you can try to
-figure it out yourself (it shouldn't be hard), or mail the maintainer 
+figure it out yourself (it shouldn't be hard), or mail the maintainer
 (Will Dyson <will_dyson@pobox.com>) for help.
 
 step 2.  Configuration & make kernel
 
 The linux kernel has many compile-time options. Most of them are beyond the
 scope of this document. I suggest the Kernel-HOWTO document as a good general
-reference on this topic. http://www.linuxdocs.org/HOWTOs/Kernel-HOWTO-4.html 
+reference on this topic. http://www.linuxdocs.org/HOWTOs/Kernel-HOWTO-4.html
 
-However, to use the BeFS module, you must enable it at configure time.
+However, to use the BeFS module, you must enable it at configure time::
 
        cd /foo/bar/linux
        make menuconfig (or xconfig)
@@ -82,35 +88,40 @@ step 3.  Install
 See the kernel howto <http://www.linux.com/howto/Kernel-HOWTO.html> for
 instructions on this critical step.
 
-USING BFS
+Using BFS
 =========
 To use the BeOS filesystem, use filesystem type 'befs'.
 
-ex)
+ex::
+
     mount -t befs /dev/fd0 /beos
 
-MOUNT OPTIONS
+Mount Options
 =============
+
+=============  ===========================================================
 uid=nnn        All files in the partition will be owned by user id nnn.
 gid=nnn               All files in the partition will be in group nnn.
 iocharset=xxx  Use xxx as the name of the NLS translation table.
 debug          The driver will output debugging information to the syslog.
+=============  ===========================================================
 
-HOW TO GET LASTEST VERSION
+How to Get Lastest Version
 ==========================
 
 The latest version is currently available at:
 <http://befs-driver.sourceforge.net/>
 
-ANY KNOWN BUGS?
-===========
+Any Known Bugs?
+===============
 As of Jan 20, 2002:
-       
+
        None
 
-SPECIAL THANKS
+Special Thanks
 ==============
 Dominic Giampalo ... Writing "Practical file system design with Be filesystem"
+
 Hiroyuki Yamada  ... Testing LinuxPPC.
 
 
similarity index 71%
rename from Documentation/filesystems/bfs.txt
rename to Documentation/filesystems/bfs.rst
index 843ce91..ce14b90 100644 (file)
@@ -1,4 +1,7 @@
-BFS FILESYSTEM FOR LINUX
+.. SPDX-License-Identifier: GPL-2.0
+
+========================
+BFS Filesystem for Linux
 ========================
 
 The BFS filesystem is used by SCO UnixWare OS for the /stand slice, which
@@ -9,22 +12,22 @@ In order to access /stand partition under Linux you obviously need to
 know the partition number and the kernel must support UnixWare disk slices
 (CONFIG_UNIXWARE_DISKLABEL config option). However BFS support does not
 depend on having UnixWare disklabel support because one can also mount
-BFS filesystem via loopback:
+BFS filesystem via loopback::
 
-# losetup /dev/loop0 stand.img
-# mount -t bfs /dev/loop0 /mnt/stand
+    # losetup /dev/loop0 stand.img
+    # mount -t bfs /dev/loop0 /mnt/stand
 
-where stand.img is a file containing the image of BFS filesystem. 
+where stand.img is a file containing the image of BFS filesystem.
 When you have finished using it and umounted you need to also deallocate
-/dev/loop0 device by:
+/dev/loop0 device by::
 
-# losetup -d /dev/loop0
+    # losetup -d /dev/loop0
 
-You can simplify mounting by just typing:
+You can simplify mounting by just typing::
 
-# mount -t bfs -o loop stand.img /mnt/stand
+    # mount -t bfs -o loop stand.img /mnt/stand
 
-this will allocate the first available loopback device (and load loop.o 
+this will allocate the first available loopback device (and load loop.o
 kernel module if necessary) automatically. If the loopback driver is not
 loaded automatically, make sure that you have compiled the module and
 that modprobe is functioning. Beware that umount will not deallocate
@@ -33,21 +36,21 @@ that modprobe is functioning. Beware that umount will not deallocate
 losetup(8). Read losetup(8) manpage for more info.
 
 To create the BFS image under UnixWare you need to find out first which
-slice contains it. The command prtvtoc(1M) is your friend:
+slice contains it. The command prtvtoc(1M) is your friend::
 
-# prtvtoc /dev/rdsk/c0b0t0d0s0
+    # prtvtoc /dev/rdsk/c0b0t0d0s0
 
 (assuming your root disk is on target=0, lun=0, bus=0, controller=0). Then you
 look for the slice with tag "STAND", which is usually slice 10. With this
-information you can use dd(1) to create the BFS image:
+information you can use dd(1) to create the BFS image::
 
-# umount /stand
-# dd if=/dev/rdsk/c0b0t0d0sa of=stand.img bs=512
+    # umount /stand
+    # dd if=/dev/rdsk/c0b0t0d0sa of=stand.img bs=512
 
 Just in case, you can verify that you have done the right thing by checking
-the magic number:
+the magic number::
 
-# od -Ad -tx4 stand.img | more
+    # od -Ad -tx4 stand.img | more
 
 The first 4 bytes should be 0x1badface.
 
similarity index 96%
rename from Documentation/filesystems/btrfs.txt
rename to Documentation/filesystems/btrfs.rst
index f9dad22..d0904f6 100644 (file)
@@ -1,3 +1,6 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====
 BTRFS
 =====
 
similarity index 91%
rename from Documentation/filesystems/ceph.txt
rename to Documentation/filesystems/ceph.rst
index b19b6a0..b46a721 100644 (file)
@@ -1,3 +1,6 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+============================
 Ceph Distributed File System
 ============================
 
@@ -15,6 +18,7 @@ Basic features include:
  * Easy deployment: most FS components are userspace daemons
 
 Also,
+
  * Flexible snapshots (on any directory)
  * Recursive accounting (nested files, directories, bytes)
 
@@ -63,7 +67,7 @@ no 'du' or similar recursive scan of the file system is required.
 Finally, Ceph also allows quotas to be set on any directory in the system.
 The quota can restrict the number of bytes or the number of files stored
 beneath that point in the directory hierarchy.  Quotas can be set using
-extended attributes 'ceph.quota.max_files' and 'ceph.quota.max_bytes', eg:
+extended attributes 'ceph.quota.max_files' and 'ceph.quota.max_bytes', eg::
 
  setfattr -n ceph.quota.max_bytes -v 100000000 /some/dir
  getfattr -n ceph.quota.max_bytes /some/dir
@@ -76,7 +80,7 @@ from writing as much data as it needs.
 Mount Syntax
 ============
 
-The basic mount syntax is:
+The basic mount syntax is::
 
  # mount -t ceph monip[:port][,monip2[:port]...]:/[subdir] mnt
 
@@ -84,7 +88,7 @@ You only need to specify a single monitor, as the client will get the
 full list when it connects.  (However, if the monitor you specify
 happens to be down, the mount won't succeed.)  The port can be left
 off if the monitor is using the default.  So if the monitor is at
-1.2.3.4,
+1.2.3.4::
 
  # mount -t ceph 1.2.3.4:/ /mnt/ceph
 
@@ -163,14 +167,14 @@ Mount Options
        available modes are "no" and "clean". The default is "no".
 
        * no: never attempt to reconnect when client detects that it has been
-       blacklisted. Operations will generally fail after being blacklisted.
+         blacklisted. Operations will generally fail after being blacklisted.
 
        * clean: client reconnects to the ceph cluster automatically when it
-       detects that it has been blacklisted. During reconnect, client drops
-       dirty data/metadata, invalidates page caches and writable file handles.
-       After reconnect, file locks become stale because the MDS loses track
-       of them. If an inode contains any stale file locks, read/write on the
-       inode is not allowed until applications release all stale file locks.
+         detects that it has been blacklisted. During reconnect, client drops
+         dirty data/metadata, invalidates page caches and writable file handles.
+         After reconnect, file locks become stale because the MDS loses track
+         of them. If an inode contains any stale file locks, read/write on the
+         inode is not allowed until applications release all stale file locks.
 
 More Information
 ================
@@ -179,8 +183,8 @@ For more information on Ceph, see the home page at
        https://ceph.com/
 
 The Linux kernel client source tree is available at
-       https://github.com/ceph/ceph-client.git
-       git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
+       https://github.com/ceph/ceph-client.git
+       git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 
 and the source for the full system is at
        https://github.com/ceph/ceph.git
index 0fa1a2c..947b7ec 100644 (file)
@@ -13,7 +13,7 @@ network by utilizing SMB or CIFS protocol.
 
 In order to mount, the network stack will also need to be set up by
 using 'ip=' config option. For more details, see
-Documentation/filesystems/nfs/nfsroot.txt.
+Documentation/admin-guide/nfs/nfsroot.rst.
 
 A CIFS root mount currently requires the use of SMB1+UNIX Extensions
 which is only supported by the Samba server. SMB1 is the older
similarity index 88%
rename from Documentation/filesystems/cramfs.txt
rename to Documentation/filesystems/cramfs.rst
index 8e19a53..afbdbde 100644 (file)
@@ -1,12 +1,15 @@
+.. SPDX-License-Identifier: GPL-2.0
 
-       Cramfs - cram a filesystem onto a small ROM
+===========================================
+Cramfs - cram a filesystem onto a small ROM
+===========================================
 
-cramfs is designed to be simple and small, and to compress things well. 
+cramfs is designed to be simple and small, and to compress things well.
 
 It uses the zlib routines to compress a file one page at a time, and
 allows random page access.  The meta-data is not compressed, but is
 expressed in a very terse representation to make it use much less
-diskspace than traditional filesystems. 
+diskspace than traditional filesystems.
 
 You can't write to a cramfs filesystem (making it compressible and
 compact also makes it _very_ hard to update on-the-fly), so you have to
@@ -28,9 +31,9 @@ issue.
 Hard links are supported, but hard linked files
 will still have a link count of 1 in the cramfs image.
 
-Cramfs directories have no `.' or `..' entries.  Directories (like
+Cramfs directories have no ``.`` or ``..`` entries.  Directories (like
 every other file on cramfs) always have a link count of 1.  (There's
-no need to use -noleaf in `find', btw.)
+no need to use -noleaf in ``find``, btw.)
 
 No timestamps are stored in a cramfs, so these default to the epoch
 (1970 GMT).  Recently-accessed files may have updated timestamps, but
@@ -70,9 +73,9 @@ MTD drivers are cfi_cmdset_0001 (Intel/Sharp CFI flash) or physmap
 (Flash device in physical memory map). MTD partitions based on such devices
 are fine too. Then that device should be specified with the "mtd:" prefix
 as the mount device argument. For example, to mount the MTD device named
-"fs_partition" on the /mnt directory:
+"fs_partition" on the /mnt directory::
 
-$ mount -t cramfs mtd:fs_partition /mnt
+    $ mount -t cramfs mtd:fs_partition /mnt
 
 To boot a kernel with this as root filesystem, suffice to specify
 something like "root=mtd:fs_partition" on the kernel command line.
@@ -90,6 +93,7 @@ https://github.com/npitre/cramfs-tools
 For /usr/share/magic
 --------------------
 
+=====  ======================= =======================
 0      ulelong 0x28cd3d45      Linux cramfs offset 0
 >4     ulelong x               size %d
 >8     ulelong x               flags 0x%x
@@ -110,6 +114,7 @@ For /usr/share/magic
 >552   ulelong x               fsid.blocks %d
 >556   ulelong x               fsid.files %d
 >560   string  >\0             name "%.16s"
+=====  ======================= =======================
 
 
 Hacker Notes
similarity index 88%
rename from Documentation/filesystems/debugfs.txt
rename to Documentation/filesystems/debugfs.rst
index dc497b9..db9ea08 100644 (file)
@@ -1,4 +1,11 @@
-Copyright 2009 Jonathan Corbet <corbet@lwn.net>
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+
+=======
+DebugFS
+=======
+
+Copyright |copy| 2009 Jonathan Corbet <corbet@lwn.net>
 
 Debugfs exists as a simple way for kernel developers to make information
 available to user space.  Unlike /proc, which is only meant for information
@@ -6,11 +13,11 @@ about a process, or sysfs, which has strict one-value-per-file rules,
 debugfs has no rules at all.  Developers can put any information they want
 there.  The debugfs filesystem is also intended to not serve as a stable
 ABI to user space; in theory, there are no stability constraints placed on
-files exported there.  The real world is not always so simple, though [1];
+files exported there.  The real world is not always so simple, though [1]_;
 even debugfs interfaces are best designed with the idea that they will need
 to be maintained forever.
 
-Debugfs is typically mounted with a command like:
+Debugfs is typically mounted with a command like::
 
     mount -t debugfs none /sys/kernel/debug
 
@@ -23,7 +30,7 @@ Note that the debugfs API is exported GPL-only to modules.
 
 Code using debugfs should include <linux/debugfs.h>.  Then, the first order
 of business will be to create at least one directory to hold a set of
-debugfs files:
+debugfs files::
 
     struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
 
@@ -36,7 +43,7 @@ something went wrong.  If ERR_PTR(-ENODEV) is returned, that is an
 indication that the kernel has been built without debugfs support and none
 of the functions described below will work.
 
-The most general way to create a file within a debugfs directory is with:
+The most general way to create a file within a debugfs directory is with::
 
     struct dentry *debugfs_create_file(const char *name, umode_t mode,
                                       struct dentry *parent, void *data,
@@ -53,12 +60,12 @@ ERR_PTR(-ERROR) on error, or ERR_PTR(-ENODEV) if debugfs support is
 missing.
 
 Create a file with an initial size, the following function can be used
-instead:
+instead::
 
-    struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
-                               struct dentry *parent, void *data,
-                               const struct file_operations *fops,
-                               loff_t file_size);
+    void debugfs_create_file_size(const char *name, umode_t mode,
+                                 struct dentry *parent, void *data,
+                                 const struct file_operations *fops,
+                                 loff_t file_size);
 
 file_size is the initial file size. The other parameters are the same
 as the function debugfs_create_file.
@@ -66,7 +73,7 @@ as the function debugfs_create_file.
 In a number of cases, the creation of a set of file operations is not
 actually necessary; the debugfs code provides a number of helper functions
 for simple situations.  Files containing a single integer value can be
-created with any of:
+created with any of::
 
     void debugfs_create_u8(const char *name, umode_t mode,
                           struct dentry *parent, u8 *value);
@@ -80,7 +87,7 @@ created with any of:
 These files support both reading and writing the given value; if a specific
 file should not be written to, simply set the mode bits accordingly.  The
 values in these files are in decimal; if hexadecimal is more appropriate,
-the following functions can be used instead:
+the following functions can be used instead::
 
     void debugfs_create_x8(const char *name, umode_t mode,
                           struct dentry *parent, u8 *value);
@@ -94,7 +101,7 @@ the following functions can be used instead:
 These functions are useful as long as the developer knows the size of the
 value to be exported.  Some types can have different widths on different
 architectures, though, complicating the situation somewhat.  There are
-functions meant to help out in such special cases:
+functions meant to help out in such special cases::
 
     void debugfs_create_size_t(const char *name, umode_t mode,
                               struct dentry *parent, size_t *value);
@@ -103,7 +110,7 @@ As might be expected, this function will create a debugfs file to represent
 a variable of type size_t.
 
 Similarly, there are helpers for variables of type unsigned long, in decimal
-and hexadecimal:
+and hexadecimal::
 
     struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
                                        struct dentry *parent,
@@ -111,7 +118,7 @@ and hexadecimal:
     void debugfs_create_xul(const char *name, umode_t mode,
                            struct dentry *parent, unsigned long *value);
 
-Boolean values can be placed in debugfs with:
+Boolean values can be placed in debugfs with::
 
     struct dentry *debugfs_create_bool(const char *name, umode_t mode,
                                       struct dentry *parent, bool *value);
@@ -120,7 +127,7 @@ A read on the resulting file will yield either Y (for non-zero values) or
 N, followed by a newline.  If written to, it will accept either upper- or
 lower-case values, or 1 or 0.  Any other input will be silently ignored.
 
-Also, atomic_t values can be placed in debugfs with:
+Also, atomic_t values can be placed in debugfs with::
 
     void debugfs_create_atomic_t(const char *name, umode_t mode,
                                 struct dentry *parent, atomic_t *value)
@@ -129,7 +136,7 @@ A read of this file will get atomic_t values, and a write of this file
 will set atomic_t values.
 
 Another option is exporting a block of arbitrary binary data, with
-this structure and function:
+this structure and function::
 
     struct debugfs_blob_wrapper {
        void *data;
@@ -151,7 +158,7 @@ If you want to dump a block of registers (something that happens quite
 often during development, even if little such code reaches mainline.
 Debugfs offers two functions: one to make a registers-only file, and
 another to insert a register block in the middle of another sequential
-file.
+file::
 
     struct debugfs_reg32 {
        char *name;
@@ -164,9 +171,9 @@ file.
        void __iomem *base;
     };
 
-    struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
-                                    struct dentry *parent,
-                                    struct debugfs_regset32 *regset);
+    debugfs_create_regset32(const char *name, umode_t mode,
+                           struct dentry *parent,
+                           struct debugfs_regset32 *regset);
 
     void debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs,
                         int nregs, void __iomem *base, char *prefix);
@@ -175,7 +182,7 @@ The "base" argument may be 0, but you may want to build the reg32 array
 using __stringify, and a number of register names (macros) are actually
 byte offsets over a base for the register block.
 
-If you want to dump an u32 array in debugfs, you can create file with:
+If you want to dump an u32 array in debugfs, you can create file with::
 
     void debugfs_create_u32_array(const char *name, umode_t mode,
                        struct dentry *parent,
@@ -185,7 +192,7 @@ The "array" argument provides data, and the "elements" argument is
 the number of elements in the array. Note: Once array is created its
 size can not be changed.
 
-There is a helper function to create device related seq_file:
+There is a helper function to create device related seq_file::
 
    struct dentry *debugfs_create_devm_seqfile(struct device *dev,
                                const char *name,
@@ -197,14 +204,14 @@ The "dev" argument is the device related to this debugfs file, and
 the "read_fn" is a function pointer which to be called to print the
 seq_file content.
 
-There are a couple of other directory-oriented helper functions:
+There are a couple of other directory-oriented helper functions::
 
-    struct dentry *debugfs_rename(struct dentry *old_dir, 
+    struct dentry *debugfs_rename(struct dentry *old_dir,
                                  struct dentry *old_dentry,
-                                 struct dentry *new_dir, 
+                                 struct dentry *new_dir,
                                  const char *new_name);
 
-    struct dentry *debugfs_create_symlink(const char *name, 
+    struct dentry *debugfs_create_symlink(const char *name,
                                           struct dentry *parent,
                                          const char *target);
 
@@ -219,7 +226,7 @@ module is unloaded without explicitly removing debugfs entries, the result
 will be a lot of stale pointers and no end of highly antisocial behavior.
 So all debugfs users - at least those which can be built as modules - must
 be prepared to remove all files and directories they create there.  A file
-can be removed with:
+can be removed with::
 
     void debugfs_remove(struct dentry *dentry);
 
@@ -229,7 +236,7 @@ be removed.
 Once upon a time, debugfs users were required to remember the dentry
 pointer for every debugfs file they created so that all files could be
 cleaned up.  We live in more civilized times now, though, and debugfs users
-can call:
+can call::
 
     void debugfs_remove_recursive(struct dentry *dentry);
 
@@ -237,5 +244,4 @@ If this function is passed a pointer for the dentry corresponding to the
 top-level directory, the entire hierarchy below that directory will be
 removed.
 
-Notes:
-       [1] http://lwn.net/Articles/309298/
+.. [1] http://lwn.net/Articles/309298/
similarity index 86%
rename from Documentation/filesystems/dlmfs.txt
rename to Documentation/filesystems/dlmfs.rst
index fcf4d50..68daaa7 100644 (file)
@@ -1,20 +1,25 @@
-dlmfs
-==================
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: <isonum.txt>
+
+=====
+DLMFS
+=====
+
 A minimal DLM userspace interface implemented via a virtual file
 system.
 
 dlmfs is built with OCFS2 as it requires most of its infrastructure.
 
-Project web page:    http://ocfs2.wiki.kernel.org
-Tools web page:      https://github.com/markfasheh/ocfs2-tools
-OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
+:Project web page:    http://ocfs2.wiki.kernel.org
+:Tools web page:      https://github.com/markfasheh/ocfs2-tools
+:OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
 All code copyright 2005 Oracle except when otherwise noted.
 
-CREDITS
+Credits
 =======
 
-Some code taken from ramfs which is Copyright (C) 2000 Linus Torvalds
+Some code taken from ramfs which is Copyright |copy| 2000 Linus Torvalds
 and Transmeta Corp.
 
 Mark Fasheh <mark.fasheh@oracle.com>
@@ -96,14 +101,19 @@ operation. If the lock succeeds, you'll get an fd.
 open(2) with O_CREAT to ensure the resource inode is created - dlmfs does
 not automatically create inodes for existing lock resources.
 
+============  ===========================
 Open Flag     Lock Request Type
----------     -----------------
+============  ===========================
 O_RDONLY      Shared Read
 O_RDWR        Exclusive
+============  ===========================
+
 
+============  ===========================
 Open Flag     Resulting Locking Behavior
----------     --------------------------
+============  ===========================
 O_NONBLOCK    Trylock operation
+============  ===========================
 
 You must provide exactly one of O_RDONLY or O_RDWR.
 
similarity index 62%
rename from Documentation/filesystems/ecryptfs.txt
rename to Documentation/filesystems/ecryptfs.rst
index 01d8a08..1f2edef 100644 (file)
@@ -1,14 +1,18 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================================
 eCryptfs: A stacked cryptographic filesystem for Linux
+======================================================
 
 eCryptfs is free software. Please see the file COPYING for details.
 For documentation, please see the files in the doc/ subdirectory.  For
 building and installation instructions please see the INSTALL file.
 
-Maintainer: Phillip Hellewell
-Lead developer: Michael A. Halcrow <mhalcrow@us.ibm.com>
-Developers: Michael C. Thompson
-            Kent Yoder
-Web Site: http://ecryptfs.sf.net
+:Maintainer: Phillip Hellewell
+:Lead developer: Michael A. Halcrow <mhalcrow@us.ibm.com>
+:Developers: Michael C. Thompson
+             Kent Yoder
+:Web Site: http://ecryptfs.sf.net
 
 This software is currently undergoing development. Make sure to
 maintain a backup copy of any data you write into eCryptfs.
@@ -19,34 +23,36 @@ SourceForge site:
 http://sourceforge.net/projects/ecryptfs/
 
 Userspace requirements include:
- - David Howells' userspace keyring headers and libraries (version
-   1.0 or higher), obtainable from
-   http://people.redhat.com/~dhowells/keyutils/
- - Libgcrypt
+
+- David Howells' userspace keyring headers and libraries (version
+  1.0 or higher), obtainable from
+  http://people.redhat.com/~dhowells/keyutils/
+- Libgcrypt
 
 
-NOTES
+.. note::
 
-In the beta/experimental releases of eCryptfs, when you upgrade
-eCryptfs, you should copy the files to an unencrypted location and
-then copy the files back into the new eCryptfs mount to migrate the
-files.
+   In the beta/experimental releases of eCryptfs, when you upgrade
+   eCryptfs, you should copy the files to an unencrypted location and
+   then copy the files back into the new eCryptfs mount to migrate the
+   files.
 
 
-MOUNT-WIDE PASSPHRASE
+Mount-wide Passphrase
+=====================
 
 Create a new directory into which eCryptfs will write its encrypted
 files (i.e., /root/crypt).  Then, create the mount point directory
-(i.e., /mnt/crypt).  Now it's time to mount eCryptfs:
+(i.e., /mnt/crypt).  Now it's time to mount eCryptfs::
 
-mount -t ecryptfs /root/crypt /mnt/crypt
+    mount -t ecryptfs /root/crypt /mnt/crypt
 
 You should be prompted for a passphrase and a salt (the salt may be
 blank).
 
-Try writing a new file:
+Try writing a new file::
 
-echo "Hello, World" > /mnt/crypt/hello.txt
+    echo "Hello, World" > /mnt/crypt/hello.txt
 
 The operation will complete.  Notice that there is a new file in
 /root/crypt that is at least 12288 bytes in size (depending on your
@@ -59,10 +65,13 @@ keyctl clear @u
 Then umount /mnt/crypt and mount again per the instructions given
 above.
 
-cat /mnt/crypt/hello.txt
+::
+
+    cat /mnt/crypt/hello.txt
 
 
-NOTES
+Notes
+=====
 
 eCryptfs version 0.1 should only be mounted on (1) empty directories
 or (2) directories containing files only created by eCryptfs. If you
similarity index 85%
rename from Documentation/filesystems/efivarfs.txt
rename to Documentation/filesystems/efivarfs.rst
index 686a64b..90ac656 100644 (file)
@@ -1,5 +1,8 @@
+.. SPDX-License-Identifier: GPL-2.0
 
+=======================================
 efivarfs - a (U)EFI variable filesystem
+=======================================
 
 The efivarfs filesystem was created to address the shortcomings of
 using entries in sysfs to maintain EFI variables. The old sysfs EFI
@@ -11,7 +14,7 @@ than a single page, sysfs isn't the best interface for this.
 Variables can be created, deleted and modified with the efivarfs
 filesystem.
 
-efivarfs is typically mounted like this,
+efivarfs is typically mounted like this::
 
        mount -t efivarfs none /sys/firmware/efi/efivars
 
similarity index 54%
rename from Documentation/filesystems/erofs.txt
rename to Documentation/filesystems/erofs.rst
index db6d39c..bf14517 100644 (file)
@@ -1,3 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================
+Enhanced Read-Only File System - EROFS
+======================================
+
 Overview
 ========
 
@@ -6,6 +12,7 @@ from other read-only file systems, it aims to be designed for flexibility,
 scalability, but be kept simple and high performance.
 
 It is designed as a better filesystem solution for the following scenarios:
+
  - read-only storage media or
 
  - part of a fully trusted read-only solution, which means it needs to be
@@ -17,6 +24,7 @@ It is designed as a better filesystem solution for the following scenarios:
    for those embedded devices with limited memory (ex, smartphone);
 
 Here is the main features of EROFS:
+
  - Little endian on-disk design;
 
  - Currently 4KB block size (nobh) and therefore maximum 16TB address space;
@@ -24,13 +32,17 @@ Here is the main features of EROFS:
  - Metadata & data could be mixed by design;
 
  - 2 inode versions for different requirements:
+
+   =====================  ============  =====================================
                           compact (v1)  extended (v2)
-   Inode metadata size:   32 bytes      64 bytes
-   Max file size:         4 GB          16 EB (also limited by max. vol size)
-   Max uids/gids:         65536         4294967296
-   File change time:      no            yes (64 + 32-bit timestamp)
-   Max hardlinks:         65536         4294967296
-   Metadata reserved:     4 bytes       14 bytes
+   =====================  ============  =====================================
+   Inode metadata size    32 bytes      64 bytes
+   Max file size          4 GB          16 EB (also limited by max. vol size)
+   Max uids/gids          65536         4294967296
+   File change time       no            yes (64 + 32-bit timestamp)
+   Max hardlinks          65536         4294967296
+   Metadata reserved      4 bytes       14 bytes
+   =====================  ============  =====================================
 
  - Support extended attributes (xattrs) as an option;
 
@@ -43,29 +55,36 @@ Here is the main features of EROFS:
 
 The following git tree provides the file system user-space tools under
 development (ex, formatting tool mkfs.erofs):
->> git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git
+
+- git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git
 
 Bugs and patches are welcome, please kindly help us and send to the following
 linux-erofs mailing list:
->> linux-erofs mailing list   <linux-erofs@lists.ozlabs.org>
+
+- linux-erofs mailing list   <linux-erofs@lists.ozlabs.org>
 
 Mount options
 =============
 
+===================    =========================================================
 (no)user_xattr         Setup Extended User Attributes. Note: xattr is enabled
                        by default if CONFIG_EROFS_FS_XATTR is selected.
 (no)acl                Setup POSIX Access Control List. Note: acl is enabled
                        by default if CONFIG_EROFS_FS_POSIX_ACL is selected.
 cache_strategy=%s      Select a strategy for cached decompression from now on:
-                         disabled: In-place I/O decompression only;
-                        readahead: Cache the last incomplete compressed physical
+
+                      ==========  =============================================
+                         disabled  In-place I/O decompression only;
+                        readahead  Cache the last incomplete compressed physical
                                    cluster for further reading. It still does
                                    in-place I/O decompression for the rest
                                    compressed physical clusters;
-                       readaround: Cache the both ends of incomplete compressed
+                       readaround  Cache the both ends of incomplete compressed
                                    physical clusters for further reading.
                                    It still does in-place I/O decompression
                                    for the rest compressed physical clusters.
+                      ==========  =============================================
+===================    =========================================================
 
 On-disk details
 ===============
@@ -73,7 +92,7 @@ On-disk details
 Summary
 -------
 Different from other read-only file systems, an EROFS volume is designed
-to be as simple as possible:
+to be as simple as possible::
 
                                 |-> aligned with the block size
    ____________________________________________________________
@@ -83,41 +102,45 @@ to be as simple as possible:
 
 All data areas should be aligned with the block size, but metadata areas
 may not. All metadatas can be now observed in two different spaces (views):
+
  1. Inode metadata space
+
     Each valid inode should be aligned with an inode slot, which is a fixed
     value (32 bytes) and designed to be kept in line with compact inode size.
 
     Each inode can be directly found with the following formula:
          inode offset = meta_blkaddr * block_size + 32 * nid
 
-                                |-> aligned with 8B
-                                           |-> followed closely
-    + meta_blkaddr blocks                                      |-> another slot
-     _____________________________________________________________________
-    |  ...   | inode |  xattrs  | extents  | data inline | ... | inode ...
-    |________|_______|(optional)|(optional)|__(optional)_|_____|__________
-             |-> aligned with the inode slot size
-                  .                   .
-                .                         .
-              .                              .
-            .                                    .
-          .                                         .
-        .                                              .
-      .____________________________________________________|-> aligned with 4B
-      | xattr_ibody_header | shared xattrs | inline xattrs |
-      |____________________|_______________|_______________|
-      |->    12 bytes    <-|->x * 4 bytes<-|               .
-                          .                .                 .
-                    .                      .                   .
-               .                           .                     .
-           ._______________________________.______________________.
-           | id | id | id | id |  ... | id | ent | ... | ent| ... |
-           |____|____|____|____|______|____|_____|_____|____|_____|
-                                           |-> aligned with 4B
-                                                       |-> aligned with 4B
+    ::
+
+                                   |-> aligned with 8B
+                                           |-> followed closely
+       + meta_blkaddr blocks                                      |-> another slot
+       _____________________________________________________________________
+       |  ...   | inode |  xattrs  | extents  | data inline | ... | inode ...
+       |________|_______|(optional)|(optional)|__(optional)_|_____|__________
+               |-> aligned with the inode slot size
+                   .                   .
+                   .                         .
+               .                              .
+               .                                    .
+           .                                         .
+           .                                              .
+       .____________________________________________________|-> aligned with 4B
+       | xattr_ibody_header | shared xattrs | inline xattrs |
+       |____________________|_______________|_______________|
+       |->    12 bytes    <-|->x * 4 bytes<-|               .
+                           .                .                 .
+                       .                      .                   .
+               .                           .                     .
+           ._______________________________.______________________.
+           | id | id | id | id |  ... | id | ent | ... | ent| ... |
+           |____|____|____|____|______|____|_____|_____|____|_____|
+                                           |-> aligned with 4B
+                                                       |-> aligned with 4B
 
     Inode could be 32 or 64 bytes, which can be distinguished from a common
-    field which all inode versions have -- i_format:
+    field which all inode versions have -- i_format::
 
         __________________               __________________
        |     i_format     |             |     i_format     |
@@ -132,16 +155,19 @@ may not. All metadatas can be now observed in two different spaces (views):
     proper alignment, and they could be optional for different data mappings.
     _currently_ total 4 valid data mappings are supported:
 
+    ==  ====================================================================
      0  flat file data without data inline (no extent);
      1  fixed-sized output data compression (with non-compacted indexes);
      2  flat file data with tail packing data inline (no extent);
      3  fixed-sized output data compression (with compacted indexes, v5.3+).
+    ==  ====================================================================
 
     The size of the optional xattrs is indicated by i_xattr_count in inode
     header. Large xattrs or xattrs shared by many different files can be
     stored in shared xattrs metadata rather than inlined right after inode.
 
  2. Shared xattrs metadata space
+
     Shared xattrs space is similar to the above inode space, started with
     a specific block indicated by xattr_blkaddr, organized one by one with
     proper align.
@@ -149,11 +175,13 @@ may not. All metadatas can be now observed in two different spaces (views):
     Each share xattr can also be directly found by the following formula:
          xattr offset = xattr_blkaddr * block_size + 4 * xattr_id
 
-                           |-> aligned by  4 bytes
-    + xattr_blkaddr blocks                     |-> aligned with 4 bytes
-     _________________________________________________________________________
-    |  ...   | xattr_entry |  xattr data | ... |  xattr_entry | xattr data  ...
-    |________|_____________|_____________|_____|______________|_______________
+    ::
+
+                           |-> aligned by  4 bytes
+       + xattr_blkaddr blocks                     |-> aligned with 4 bytes
+       _________________________________________________________________________
+       |  ...   | xattr_entry |  xattr data | ... |  xattr_entry | xattr data  ...
+       |________|_____________|_____________|_____|______________|_______________
 
 Directories
 -----------
@@ -163,19 +191,21 @@ random file lookup, and all directory entries are _strictly_ recorded in
 alphabetical order in order to support improved prefix binary search
 algorithm (could refer to the related source code).
 
-                 ___________________________
-                /                           |
-               /              ______________|________________
-              /              /              | nameoff1       | nameoffN-1
- ____________.______________._______________v________________v__________
-| dirent | dirent | ... | dirent | filename | filename | ... | filename |
-|___.0___|____1___|_____|___N-1__|____0_____|____1_____|_____|___N-1____|
-     \                           ^
-      \                          |                           * could have
-       \                         |                             trailing '\0'
-        \________________________| nameoff0
+::
+
+                   ___________________________
+                   /                           |
+               /              ______________|________________
+               /              /              | nameoff1       | nameoffN-1
+    ____________.______________._______________v________________v__________
+    | dirent | dirent | ... | dirent | filename | filename | ... | filename |
+    |___.0___|____1___|_____|___N-1__|____0_____|____1_____|_____|___N-1____|
+       \                           ^
+       \                          |                           * could have
+       \                         |                             trailing '\0'
+           \________________________| nameoff0
 
-                             Directory block
+                               Directory block
 
 Note that apart from the offset of the first filename, nameoff0 also indicates
 the total number of directory entries in this block since it is no need to
@@ -184,28 +214,27 @@ introduce another on-disk field at all.
 Compression
 -----------
 Currently, EROFS supports 4KB fixed-sized output transparent file compression,
-as illustrated below:
-
-         |---- Variant-Length Extent ----|-------- VLE --------|----- VLE -----
-         clusterofs                      clusterofs            clusterofs
-         |                               |                     |   logical data
-_________v_______________________________v_____________________v_______________
-... |    .        |             |        .    |             |  .          | ...
-____|____.________|_____________|________.____|_____________|__.__________|____
-    |-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|
-         size          size          size          size          size
-          .                             .                .                   .
-           .                       .               .                  .
-            .                  .              .                .
-      _______._____________._____________._____________._____________________
-         ... |             |             |             | ... physical data
-      _______|_____________|_____________|_____________|_____________________
-             |-> cluster <-|-> cluster <-|-> cluster <-|
-                  size          size          size
+as illustrated below::
+
+           |---- Variant-Length Extent ----|-------- VLE --------|----- VLE -----
+           clusterofs                      clusterofs            clusterofs
+           |                               |                     |   logical data
+    _________v_______________________________v_____________________v_______________
+    ... |    .        |             |        .    |             |  .          | ...
+    ____|____.________|_____________|________.____|_____________|__.__________|____
+       |-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|-> cluster <-|
+           size          size          size          size          size
+           .                             .                .                   .
+           .                       .               .                  .
+               .                  .              .                .
+       _______._____________._____________._____________._____________________
+           ... |             |             |             | ... physical data
+       _______|_____________|_____________|_____________|_____________________
+               |-> cluster <-|-> cluster <-|-> cluster <-|
+                   size          size          size
 
 Currently each on-disk physical cluster can contain 4KB (un)compressed data
 at most. For each logical cluster, there is a corresponding on-disk index to
 describe its cluster type, physical cluster address, etc.
 
 See "struct z_erofs_vle_decompressed_index" in erofs_fs.h for more details.
-
similarity index 91%
rename from Documentation/filesystems/ext2.txt
rename to Documentation/filesystems/ext2.rst
index 94c2cf0..d83dbbb 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 
 The Second Extended Filesystem
 ==============================
@@ -14,8 +16,9 @@ Options
 Most defaults are determined by the filesystem superblock, and can be
 set using tune2fs(8). Kernel-determined defaults are indicated by (*).
 
-bsddf                  (*)     Makes `df' act like BSD.
-minixdf                                Makes `df' act like Minix.
+====================    ===     ================================================
+bsddf                  (*)     Makes ``df`` act like BSD.
+minixdf                                Makes ``df`` act like Minix.
 
 check=none, nocheck    (*)     Don't do extra checking of bitmaps on mount
                                (check=normal and check=strict options removed)
@@ -62,6 +65,7 @@ quota, usrquota                       Enable user disk quota support
 
 grpquota                       Enable group disk quota support
                                (requires CONFIG_QUOTA).
+====================    ===     ================================================
 
 noquota option ls silently ignored by ext2.
 
@@ -294,9 +298,9 @@ respective fsck programs.
 If you're exceptionally paranoid, there are 3 ways of making metadata
 writes synchronous on ext2:
 
-per-file if you have the program source: use the O_SYNC flag to open()
-per-file if you don't have the source: use "chattr +S" on the file
-per-filesystem: add the "sync" option to mount (or in /etc/fstab)
+per-file if you have the program source: use the O_SYNC flag to open()
+per-file if you don't have the source: use "chattr +S" on the file
+per-filesystem: add the "sync" option to mount (or in /etc/fstab)
 
 the first and last are not ext2 specific but do force the metadata to
 be written synchronously.  See also Journaling below.
@@ -316,10 +320,12 @@ Most of these limits could be overcome with slight changes in the on-disk
 format and using a compatibility flag to signal the format change (at
 the expense of some compatibility).
 
-Filesystem block size:     1kB        2kB        4kB        8kB
-
-File size limit:          16GB      256GB     2048GB     2048GB
-Filesystem size limit:  2047GB     8192GB    16384GB    32768GB
+=====================  =======    =======    =======   ========
+Filesystem block size      1kB        2kB        4kB        8kB
+=====================  =======    =======    =======   ========
+File size limit           16GB      256GB     2048GB     2048GB
+Filesystem size limit   2047GB     8192GB    16384GB    32768GB
+=====================  =======    =======    =======   ========
 
 There is a 2.4 kernel limit of 2048GB for a single block device, so no
 filesystem larger than that can be created at this time.  There is also
@@ -370,19 +376,24 @@ ext4 and journaling.
 References
 ==========
 
+=======================        ===============================================
 The kernel source      file:/usr/src/linux/fs/ext2/
 e2fsprogs (e2fsck)     http://e2fsprogs.sourceforge.net/
 Design & Implementation        http://e2fsprogs.sourceforge.net/ext2intro.html
 Journaling (ext3)      ftp://ftp.uk.linux.org/pub/linux/sct/fs/jfs/
 Filesystem Resizing    http://ext2resize.sourceforge.net/
-Compression (*)                http://e2compr.sourceforge.net/
+Compression [1]_       http://e2compr.sourceforge.net/
+=======================        ===============================================
 
 Implementations for:
+
+=======================        ===========================================================
 Windows 95/98/NT/2000  http://www.chrysocome.net/explore2fs
-Windows 95 (*)         http://www.yipton.net/content.html#FSDEXT2
-DOS client (*)         ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/
-OS/2 (+)               ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/
+Windows 95 [1]_                http://www.yipton.net/content.html#FSDEXT2
+DOS client [1]_                ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/
+OS/2 [2]_              ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/
 RISC OS client         http://www.esw-heim.tu-clausthal.de/~marco/smorbrod/IscaFS/
+=======================        ===========================================================
 
-(*) no longer actively developed/supported (as of Apr 2001)
-(+) no longer actively developed/supported (as of Mar 2009)
+.. [1] no longer actively developed/supported (as of Apr 2001)
+.. [2] no longer actively developed/supported (as of Mar 2009)
similarity index 88%
rename from Documentation/filesystems/ext3.txt
rename to Documentation/filesystems/ext3.rst
index 58758fb..c06cec3 100644 (file)
@@ -1,4 +1,6 @@
+.. SPDX-License-Identifier: GPL-2.0
 
+===============
 Ext3 Filesystem
 ===============
 
similarity index 84%
rename from Documentation/filesystems/f2fs.txt
rename to Documentation/filesystems/f2fs.rst
index 4eb3e2d..d681203 100644 (file)
@@ -1,6 +1,8 @@
-================================================================================
+.. SPDX-License-Identifier: GPL-2.0
+
+==========================================
 WHAT IS Flash-Friendly File System (F2FS)?
-================================================================================
+==========================================
 
 NAND flash memory-based storage devices, such as SSD, eMMC, and SD cards, have
 been equipped on a variety systems ranging from mobile to server systems. Since
@@ -20,14 +22,15 @@ layout, but also for selecting allocation and cleaning algorithms.
 
 The following git tree provides the file system formatting tool (mkfs.f2fs),
 a consistency checking tool (fsck.f2fs), and a debugging tool (dump.f2fs).
->> git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
+
+- git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
 
 For reporting bugs and sending patches, please use the following mailing list:
->> linux-f2fs-devel@lists.sourceforge.net
 
-================================================================================
-BACKGROUND AND DESIGN ISSUES
-================================================================================
+- linux-f2fs-devel@lists.sourceforge.net
+
+Background and Design issues
+============================
 
 Log-structured File System (LFS)
 --------------------------------
@@ -61,6 +64,7 @@ needs to reclaim these obsolete blocks seamlessly to users. This job is called
 as a cleaning process.
 
 The process consists of three operations as follows.
+
 1. A victim segment is selected through referencing segment usage table.
 2. It loads parent index structures of all the data in the victim identified by
    segment summary blocks.
@@ -71,9 +75,8 @@ This cleaning job may cause unexpected long delays, so the most important goal
 is to hide the latencies to users. And also definitely, it should reduce the
 amount of valid data to be moved, and move them quickly as well.
 
-================================================================================
-KEY FEATURES
-================================================================================
+Key Features
+============
 
 Flash Awareness
 ---------------
@@ -94,10 +97,11 @@ Cleaning Overhead
 - Support multi-head logs for static/dynamic hot and cold data separation
 - Introduce adaptive logging for efficient block allocation
 
-================================================================================
-MOUNT OPTIONS
-================================================================================
+Mount Options
+=============
 
+
+====================== ============================================================
 background_gc=%s       Turn on/off cleaning operations, namely garbage
                        collection, triggered in background when I/O subsystem is
                        idle. If background_gc=on, it will turn on the garbage
@@ -167,7 +171,10 @@ fault_injection=%d     Enable fault injection in all supported types with
 fault_type=%d          Support configuring fault injection type, should be
                        enabled with fault_injection option, fault type value
                        is shown below, it supports single or combined type.
+
+                       ===================     ===========
                        Type_Name               Type_Value
+                       ===================     ===========
                        FAULT_KMALLOC           0x000000001
                        FAULT_KVMALLOC          0x000000002
                        FAULT_PAGE_ALLOC                0x000000004
@@ -183,6 +190,7 @@ fault_type=%d          Support configuring fault injection type, should be
                        FAULT_CHECKPOINT                0x000001000
                        FAULT_DISCARD           0x000002000
                        FAULT_WRITE_IO          0x000004000
+                       ===================     ===========
 mode=%s                Control block allocation mode which supports "adaptive"
                        and "lfs". In "lfs" mode, there should be no random
                        writes towards main area.
@@ -219,7 +227,7 @@ 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[:%u[%]]     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
@@ -246,22 +254,22 @@ compress_extension=%s  Support adding specified extension, so that f2fs can enab
                        on compression extension list and enable compression on
                        these file by default rather than to enable it via ioctl.
                        For other files, we can still enable compression via ioctl.
+====================== ============================================================
 
-================================================================================
-DEBUGFS ENTRIES
-================================================================================
+Debugfs Entries
+===============
 
 /sys/kernel/debug/f2fs/ contains information about all the partitions mounted as
 f2fs. Each file shows the whole f2fs information.
 
 /sys/kernel/debug/f2fs/status includes:
+
  - major file system information managed by f2fs currently
  - average SIT information about whole segments
  - current memory footprint consumed by f2fs.
 
-================================================================================
-SYSFS ENTRIES
-================================================================================
+Sysfs Entries
+=============
 
 Information about mounted f2fs file systems can be found in
 /sys/fs/f2fs.  Each mounted filesystem will have a directory in
@@ -271,22 +279,24 @@ The files in each per-device directory are shown in table below.
 Files in /sys/fs/f2fs/<devname>
 (see also Documentation/ABI/testing/sysfs-fs-f2fs)
 
-================================================================================
-USAGE
-================================================================================
+Usage
+=====
 
 1. Download userland tools and compile them.
 
 2. Skip, if f2fs was compiled statically inside kernel.
-   Otherwise, insert the f2fs.ko module.
- # insmod f2fs.ko
+   Otherwise, insert the f2fs.ko module::
+
+       # insmod f2fs.ko
 
-3. Create a directory trying to mount
- # mkdir /mnt/f2fs
+3. Create a directory trying to mount::
 
-4. Format the block device, and then mount as f2fs
- # mkfs.f2fs -l label /dev/block_device
- # mount -t f2fs /dev/block_device /mnt/f2fs
+       # mkdir /mnt/f2fs
+
+4. Format the block device, and then mount as f2fs::
+
+       # mkfs.f2fs -l label /dev/block_device
+       # mount -t f2fs /dev/block_device /mnt/f2fs
 
 mkfs.f2fs
 ---------
@@ -294,18 +304,26 @@ The mkfs.f2fs is for the use of formatting a partition as the f2fs filesystem,
 which builds a basic on-disk layout.
 
 The options consist of:
--l [label]   : Give a volume label, up to 512 unicode name.
--a [0 or 1]  : Split start location of each area for heap-based allocation.
-               1 is set by default, which performs this.
--o [int]     : Set overprovision ratio in percent over volume size.
-               5 is set by default.
--s [int]     : Set the number of segments per section.
-               1 is set by default.
--z [int]     : Set the number of sections per zone.
-               1 is set by default.
--e [str]     : Set basic extension list. e.g. "mp3,gif,mov"
--t [0 or 1]  : Disable discard command or not.
-               1 is set by default, which conducts discard.
+
+===============    ===========================================================
+``-l [label]``     Give a volume label, up to 512 unicode name.
+``-a [0 or 1]``    Split start location of each area for heap-based allocation.
+
+                   1 is set by default, which performs this.
+``-o [int]``       Set overprovision ratio in percent over volume size.
+
+                   5 is set by default.
+``-s [int]``       Set the number of segments per section.
+
+                   1 is set by default.
+``-z [int]``       Set the number of sections per zone.
+
+                   1 is set by default.
+``-e [str]``       Set basic extension list. e.g. "mp3,gif,mov"
+``-t [0 or 1]``    Disable discard command or not.
+
+                   1 is set by default, which conducts discard.
+===============    ===========================================================
 
 fsck.f2fs
 ---------
@@ -314,7 +332,8 @@ partition, which examines whether the filesystem metadata and user-made data
 are cross-referenced correctly or not.
 Note that, initial version of the tool does not fix any inconsistency.
 
-The options consist of:
+The options consist of::
+
   -d debug level [default:0]
 
 dump.f2fs
@@ -327,20 +346,21 @@ It shows on-disk inode information recognized by a given inode number, and is
 able to dump all the SSA and SIT entries into predefined files, ./dump_ssa and
 ./dump_sit respectively.
 
-The options consist of:
+The options consist of::
+
   -d debug level [default:0]
   -i inode no (hex)
   -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]
   -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]
 
-Examples:
-# dump.f2fs -i [ino] /dev/sdx
-# dump.f2fs -s 0~-1 /dev/sdx (SIT dump)
-# dump.f2fs -a 0~-1 /dev/sdx (SSA dump)
+Examples::
+
+    # dump.f2fs -i [ino] /dev/sdx
+    # dump.f2fs -s 0~-1 /dev/sdx (SIT dump)
+    # dump.f2fs -a 0~-1 /dev/sdx (SSA dump)
 
-================================================================================
-DESIGN
-================================================================================
+Design
+======
 
 On-disk Layout
 --------------
@@ -351,7 +371,7 @@ consists of a set of sections. By default, section and zone sizes are set to one
 segment size identically, but users can easily modify the sizes by mkfs.
 
 F2FS splits the entire volume into six areas, and all the areas except superblock
-consists of multiple segments as described below.
+consists of multiple segments as described below::
 
                                             align with the zone size <-|
                  |-> align with the segment size
@@ -373,28 +393,28 @@ consists of multiple segments as described below.
                                    |__zone__|
 
 - Superblock (SB)
: It is located at the beginning of the partition, and there exist two copies
  It is located at the beginning of the partition, and there exist two copies
    to avoid file system crash. It contains basic partition information and some
    default parameters of f2fs.
 
 - Checkpoint (CP)
: It contains file system information, bitmaps for valid NAT/SIT sets, orphan
  It contains file system information, bitmaps for valid NAT/SIT sets, orphan
    inode lists, and summary entries of current active segments.
 
 - Segment Information Table (SIT)
: It contains segment information such as valid block count and bitmap for the
  It contains segment information such as valid block count and bitmap for the
    validity of all the blocks.
 
 - Node Address Table (NAT)
: It is composed of a block address table for all the node blocks stored in
  It is composed of a block address table for all the node blocks stored in
    Main area.
 
 - Segment Summary Area (SSA)
: It contains summary entries which contains the owner information of all the
  It contains summary entries which contains the owner information of all the
    data and node blocks stored in Main area.
 
 - Main Area
: It contains file and directory data including their indices.
  It contains file and directory data including their indices.
 
 In order to avoid misalignment between file system and flash-based storage, F2FS
 aligns the start block address of CP with the segment size. Also, it aligns the
@@ -414,7 +434,7 @@ One of them always indicates the last valid data, which is called as shadow copy
 mechanism. In addition to CP, NAT and SIT also adopt the shadow copy mechanism.
 
 For file system consistency, each CP points to which NAT and SIT copies are
-valid, as shown as below.
+valid, as shown as below::
 
   +--------+----------+---------+
   |   CP   |    SIT   |   NAT   |
@@ -438,7 +458,7 @@ indirect node. F2FS assigns 4KB to an inode block which contains 923 data block
 indices, two direct node pointers, two indirect node pointers, and one double
 indirect node pointer as described below. One direct node block contains 1018
 data blocks, and one indirect node block contains also 1018 node blocks. Thus,
-one inode block (i.e., a file) covers:
+one inode block (i.e., a file) covers::
 
   4KB * (923 + 2 * 1018 + 2 * 1018 * 1018 + 1018 * 1018 * 1018) := 3.94TB.
 
@@ -473,6 +493,8 @@ A dentry block consists of 214 dentry slots and file names. Therein a bitmap is
 used to represent whether each dentry is valid or not. A dentry block occupies
 4KB with the following composition.
 
+::
+
   Dentry Block(4 K) = bitmap (27 bytes) + reserved (3 bytes) +
                      dentries(11 * 214 bytes) + file name (8 * 214 bytes)
 
@@ -498,23 +520,25 @@ F2FS implements multi-level hash tables for directory structure. Each level has
 a hash table with dedicated number of hash buckets as shown below. Note that
 "A(2B)" means a bucket includes 2 data blocks.
 
-----------------------
-A : bucket
-B : block
-N : MAX_DIR_HASH_DEPTH
-----------------------
+::
+
+    ----------------------
+    A : bucket
+    B : block
+    N : MAX_DIR_HASH_DEPTH
+    ----------------------
 
-level #0   | A(2B)
-           |
-level #1   | A(2B) - A(2B)
-           |
-level #2   | A(2B) - A(2B) - A(2B) - A(2B)
-     .     |   .       .       .       .
-level #N/2 | A(2B) - A(2B) - A(2B) - A(2B) - A(2B) - ... - A(2B)
-     .     |   .       .       .       .
-level #N   | A(4B) - A(4B) - A(4B) - A(4B) - A(4B) - ... - A(4B)
+    level #0   | A(2B)
+           |
+    level #1   | A(2B) - A(2B)
+           |
+    level #2   | A(2B) - A(2B) - A(2B) - A(2B)
+       .     |   .       .       .       .
+    level #N/2 | A(2B) - A(2B) - A(2B) - A(2B) - A(2B) - ... - A(2B)
+       .     |   .       .       .       .
+    level #N   | A(4B) - A(4B) - A(4B) - A(4B) - A(4B) - ... - A(4B)
 
-The number of blocks and buckets are determined by,
+The number of blocks and buckets are determined by::
 
                             ,- 2, if n < MAX_DIR_HASH_DEPTH / 2,
   # of blocks in level #n = |
@@ -532,7 +556,7 @@ dentry consisting of the file name and its inode number. If not found, F2FS
 scans the next hash table in level #1. In this way, F2FS scans hash tables in
 each levels incrementally from 1 to N. In each levels F2FS needs to scan only
 one bucket determined by the following equation, which shows O(log(# of files))
-complexity.
+complexity::
 
   bucket number to scan in level #n = (hash value) % (# of buckets in level #n)
 
@@ -540,7 +564,8 @@ In the case of file creation, F2FS finds empty consecutive slots that cover the
 file name. F2FS searches the empty slots in the hash tables of whole levels from
 1 to N in the same way as the lookup operation.
 
-The following figure shows an example of two cases holding children.
+The following figure shows an example of two cases holding children::
+
        --------------> Dir <--------------
        |                                 |
     child                             child
@@ -611,14 +636,15 @@ Write-hint Policy
 2) whint_mode=user-based. F2FS tries to pass down hints given by
 users.
 
+===================== ======================== ===================
 User                  F2FS                     Block
-----                  ----                     -----
+===================== ======================== ===================
                       META                     WRITE_LIFE_NOT_SET
                       HOT_NODE                 "
                       WARM_NODE                "
                       COLD_NODE                "
-*ioctl(COLD)          COLD_DATA                WRITE_LIFE_EXTREME
-*extension list       "                        "
+ioctl(COLD)           COLD_DATA                WRITE_LIFE_EXTREME
+extension list        "                        "
 
 -- buffered io
 WRITE_LIFE_EXTREME    COLD_DATA                WRITE_LIFE_EXTREME
@@ -635,11 +661,13 @@ 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
+===================== ======================== ===================
 
 3) whint_mode=fs-based. F2FS passes down hints with its policy.
 
+===================== ======================== ===================
 User                  F2FS                     Block
-----                  ----                     -----
+===================== ======================== ===================
                       META                     WRITE_LIFE_MEDIUM;
                       HOT_NODE                 WRITE_LIFE_NOT_SET
                       WARM_NODE                "
@@ -662,6 +690,7 @@ 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
 -------------------
@@ -681,6 +710,7 @@ Allocating disk space
 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)
@@ -692,39 +722,41 @@ Compression implementation
 --------------------------
 
 - New term named cluster is defined as basic unit of compression, file can
-be divided into multiple clusters logically. One cluster includes 4 << n
-(n >= 0) logical pages, compression size is also cluster size, each of
-cluster can be compressed or not.
+  be divided into multiple clusters logically. One cluster includes 4 << n
+  (n >= 0) logical pages, compression size is also cluster size, each of
+  cluster can be compressed or not.
 
 - In cluster metadata layout, one special block address is used to indicate
-cluster is compressed one or normal one, for compressed cluster, following
-metadata maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs
-stores data including compress header and compressed data.
+  cluster is compressed one or normal one, for compressed cluster, following
+  metadata maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs
+  stores data including compress header and compressed data.
 
 - In order to eliminate write amplification during overwrite, F2FS only
-support compression on write-once file, data can be compressed only when
-all logical blocks in file are valid and cluster compress ratio is lower
-than specified threshold.
+  support compression on write-once file, data can be compressed only when
+  all logical blocks in file are valid and cluster compress ratio is lower
+  than specified threshold.
 
 - To enable compression on regular inode, there are three ways:
-* chattr +c file
-* chattr +c dir; touch dir/file
-* mount w/ -o compress_extension=ext; touch file.ext
-
-Compress metadata layout:
-                             [Dnode Structure]
-             +-----------------------------------------------+
-             | cluster 1 | cluster 2 | ......... | cluster N |
-             +-----------------------------------------------+
-             .           .                       .           .
-       .                       .                .                      .
-  .         Compressed Cluster       .        .        Normal Cluster            .
-+----------+---------+---------+---------+  +---------+---------+---------+---------+
-|compr flag| block 1 | block 2 | block 3 |  | block 1 | block 2 | block 3 | block 4 |
-+----------+---------+---------+---------+  +---------+---------+---------+---------+
-           .                             .
-         .                                           .
-       .                                                           .
-      +-------------+-------------+----------+----------------------------+
-      | data length | data chksum | reserved |      compressed data       |
-      +-------------+-------------+----------+----------------------------+
+
+  * chattr +c file
+  * chattr +c dir; touch dir/file
+  * mount w/ -o compress_extension=ext; touch file.ext
+
+Compress metadata layout::
+
+                               [Dnode Structure]
+               +-----------------------------------------------+
+               | cluster 1 | cluster 2 | ......... | cluster N |
+               +-----------------------------------------------+
+               .           .                       .           .
+       .                       .                .                      .
+    .         Compressed Cluster       .        .        Normal Cluster            .
+    +----------+---------+---------+---------+  +---------+---------+---------+---------+
+    |compr flag| block 1 | block 2 | block 3 |  | block 1 | block 2 | block 3 | block 4 |
+    +----------+---------+---------+---------+  +---------+---------+---------+---------+
+           .                             .
+           .                                           .
+       .                                                           .
+       +-------------+-------------+----------+----------------------------+
+       | data length | data chksum | reserved |      compressed data       |
+       +-------------+-------------+----------+----------------------------+
index 8e45506..cd717f9 100644 (file)
@@ -1,7 +1,8 @@
 .. SPDX-License-Identifier: GPL-2.0
-==============
+
+====
 FUSE
-==============
+====
 
 Definitions
 ===========
similarity index 94%
rename from Documentation/filesystems/gfs2-uevents.txt
rename to Documentation/filesystems/gfs2-uevents.rst
index 19a19eb..f162a2c 100644 (file)
@@ -1,14 +1,18 @@
-                              uevents and GFS2
-                             ==================
+.. SPDX-License-Identifier: GPL-2.0
+
+================
+uevents and GFS2
+================
 
 During the lifetime of a GFS2 mount, a number of uevents are generated.
 This document explains what the events are and what they are used
 for (by gfs_controld in gfs2-utils).
 
 A list of GFS2 uevents
------------------------
+======================
 
 1. ADD
+------
 
 The ADD event occurs at mount time. It will always be the first
 uevent generated by the newly created filesystem. If the mount
@@ -21,6 +25,7 @@ with no journal assigned), and read-only (with journal assigned) status
 of the filesystem respectively.
 
 2. ONLINE
+---------
 
 The ONLINE uevent is generated after a successful mount or remount. It
 has the same environment variables as the ADD uevent. The ONLINE
@@ -29,6 +34,7 @@ RDONLY are a relatively recent addition (2.6.32-rc+) and will not
 be generated by older kernels.
 
 3. CHANGE
+---------
 
 The CHANGE uevent is used in two places. One is when reporting the
 successful mount of the filesystem by the first node (FIRSTMOUNT=Done).
@@ -52,6 +58,7 @@ cluster. For this reason the ONLINE uevent was used when adding a new
 uevent for a successful mount or remount.
 
 4. OFFLINE
+----------
 
 The OFFLINE uevent is only generated due to filesystem errors and is used
 as part of the "withdraw" mechanism. Currently this doesn't give any
@@ -59,6 +66,7 @@ information about what the error is, which is something that needs to
 be fixed.
 
 5. REMOVE
+---------
 
 The REMOVE uevent is generated at the end of an unsuccessful mount
 or at the end of a umount of the filesystem. All REMOVE uevents will
@@ -68,9 +76,10 @@ kobject subsystem.
 
 
 Information common to all GFS2 uevents (uevent environment variables)
-----------------------------------------------------------------------
+=====================================================================
 
 1. LOCKTABLE=
+--------------
 
 The LOCKTABLE is a string, as supplied on the mount command
 line (locktable=) or via fstab. It is used as a filesystem label
@@ -78,6 +87,7 @@ as well as providing the information for a lock_dlm mount to be
 able to join the cluster.
 
 2. LOCKPROTO=
+-------------
 
 The LOCKPROTO is a string, and its value depends on what is set
 on the mount command line, or via fstab. It will be either
@@ -85,12 +95,14 @@ lock_nolock or lock_dlm. In the future other lock managers
 may be supported.
 
 3. JOURNALID=
+-------------
 
 If a journal is in use by the filesystem (journals are not
 assigned for spectator mounts) then this will give the
 numeric journal id in all GFS2 uevents.
 
 4. UUID=
+--------
 
 With recent versions of gfs2-utils, mkfs.gfs2 writes a UUID
 into the filesystem superblock. If it exists, this will
similarity index 76%
rename from Documentation/filesystems/gfs2.txt
rename to Documentation/filesystems/gfs2.rst
index cc4f230..8d1ab58 100644 (file)
@@ -1,5 +1,8 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==================
 Global File System
-------------------
+==================
 
 https://fedorahosted.org/cluster/wiki/HomePage
 
@@ -14,16 +17,18 @@ on one machine show up immediately on all other machines in the cluster.
 GFS uses interchangeable inter-node locking mechanisms, the currently
 supported mechanisms are:
 
-  lock_nolock -- allows gfs to be used as a local file system
+  lock_nolock
+    - allows gfs to be used as a local file system
 
-  lock_dlm -- uses a distributed lock manager (dlm) for inter-node locking
-  The dlm is found at linux/fs/dlm/
+  lock_dlm
+    - uses a distributed lock manager (dlm) for inter-node locking.
+      The dlm is found at linux/fs/dlm/
 
 Lock_dlm depends on user space cluster management systems found
 at the URL above.
 
 To use gfs as a local file system, no external clustering systems are
-needed, simply:
+needed, simply::
 
   $ mkfs -t gfs2 -p lock_nolock -j 1 /dev/block_device
   $ mount -t gfs2 /dev/block_device /dir
@@ -37,9 +42,12 @@ GFS2 is not on-disk compatible with previous versions of GFS, but it
 is pretty close.
 
 The following man pages can be found at the URL above:
+
+  ============         =============================================
   fsck.gfs2            to repair a filesystem
   gfs2_grow            to expand a filesystem online
   gfs2_jadd            to add journals to a filesystem online
   tunegfs2             to manipulate, examine and tune a filesystem
-  gfs2_convert to convert a gfs filesystem to gfs2 in-place
+  gfs2_convert         to convert a gfs filesystem to gfs2 in-place
   mkfs.gfs2            to make a filesystem
+  ============         =============================================
similarity index 80%
rename from Documentation/filesystems/hfs.txt
rename to Documentation/filesystems/hfs.rst
index d096df6..ab17a00 100644 (file)
@@ -1,11 +1,16 @@
-Note: This filesystem doesn't have a maintainer.
+.. SPDX-License-Identifier: GPL-2.0
 
+==================================
 Macintosh HFS Filesystem for Linux
 ==================================
 
-HFS stands for ``Hierarchical File System'' and is the filesystem used
+
+.. Note:: This filesystem doesn't have a maintainer.
+
+
+HFS stands for ``Hierarchical File System`` and is the filesystem used
 by the Mac Plus and all later Macintosh models.  Earlier Macintosh
-models used MFS (``Macintosh File System''), which is not supported,
+models used MFS (``Macintosh File System``), which is not supported,
 MacOS 8.1 and newer support a filesystem called HFS+ that's similar to
 HFS but is extended in various areas.  Use the hfsplus filesystem driver
 to access such filesystems from Linux.
@@ -49,25 +54,25 @@ Writing to HFS Filesystems
 HFS is not a UNIX filesystem, thus it does not have the usual features you'd
 expect:
 
o You can't modify the set-uid, set-gid, sticky or executable bits or the uid
* You can't modify the set-uid, set-gid, sticky or executable bits or the uid
    and gid of files.
o You can't create hard- or symlinks, device files, sockets or FIFOs.
* You can't create hard- or symlinks, device files, sockets or FIFOs.
 
 HFS does on the other have the concepts of multiple forks per file.  These
 non-standard forks are represented as hidden additional files in the normal
 filesystems namespace which is kind of a cludge and makes the semantics for
 the a little strange:
 
o You can't create, delete or rename resource forks of files or the
* You can't create, delete or rename resource forks of files or the
    Finder's metadata.
o They are however created (with default values), deleted and renamed
* They are however created (with default values), deleted and renamed
    along with the corresponding data fork or directory.
o Copying files to a different filesystem will loose those attributes
* Copying files to a different filesystem will loose those attributes
    that are essential for MacOS to work.
 
 
 Creating HFS filesystems
-===================================
+========================
 
 The hfsutils package from Robert Leslie contains a program called
 hformat that can be used to create HFS filesystem. See
similarity index 95%
rename from Documentation/filesystems/hfsplus.txt
rename to Documentation/filesystems/hfsplus.rst
index 59f7569..f02f4f5 100644 (file)
@@ -1,4 +1,6 @@
+.. SPDX-License-Identifier: GPL-2.0
 
+======================================
 Macintosh HFSPlus Filesystem for Linux
 ======================================
 
similarity index 66%
rename from Documentation/filesystems/hpfs.txt
rename to Documentation/filesystems/hpfs.rst
index 74630bd..0db1522 100644 (file)
@@ -1,13 +1,21 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+====================
 Read/Write HPFS 2.09
+====================
+
 1998-2004, Mikulas Patocka
 
-email: mikulas@artax.karlin.mff.cuni.cz
-homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
+:email: mikulas@artax.karlin.mff.cuni.cz
+:homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi
 
-CREDITS:
+Credits
+=======
 Chris Smith, 1993, original read-only HPFS, some code and hpfs structures file
        is taken from it
+
 Jacques Gelinas, MSDos mmap, Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993)
+
 Werner Almesberger, 1992, 1993, MSDos option parser & CR/LF conversion
 
 Mount options
@@ -50,6 +58,7 @@ timeshift=(-)nnn (default 0)
 
 
 File names
+==========
 
 As in OS/2, filenames are case insensitive. However, shell thinks that names
 are case sensitive, so for example when you create a file FOO, you can use
@@ -64,6 +73,7 @@ access it under names 'a.', 'a..', 'a .  . . ' etc.
 
 
 Extended attributes
+===================
 
 On HPFS partitions, OS/2 can associate to each file a special information called
 extended attributes. Extended attributes are pairs of (key,value) where key is
@@ -88,6 +98,7 @@ values doesn't work.
 
 
 Symlinks
+========
 
 You can do symlinks on HPFS partition, symlinks are achieved by setting extended
 attribute named "SYMLINK" with symlink value. Like on ext2, you can chown and
@@ -101,6 +112,7 @@ to analyze or change OS2SYS.INI.
 
 
 Codepages
+=========
 
 HPFS can contain several uppercasing tables for several codepages and each
 file has a pointer to codepage its name is in. However OS/2 was created in
@@ -128,6 +140,7 @@ this codepage - if you don't try to do what I described above :-)
 
 
 Known bugs
+==========
 
 HPFS386 on OS/2 server is not supported. HPFS386 installed on normal OS/2 client
 should work. If you have OS/2 server, use only read-only mode. I don't know how
@@ -152,7 +165,8 @@ would result in directory tree splitting, that takes disk space. Workaround is
 to delete other files that are leaf (probability that the file is non-leaf is
 about 1/50) or to truncate file first to make some space.
 You encounter this problem only if you have many directories so that
-preallocated directory band is full i.e.
+preallocated directory band is full i.e.::
+
        number_of_directories / size_of_filesystem_in_mb > 4.
 
 You can't delete open directories.
@@ -174,6 +188,7 @@ anybody know what does it mean?
 
 
 What does "unbalanced tree" message mean?
+=========================================
 
 Old versions of this driver created sometimes unbalanced dnode trees. OS/2
 chkdsk doesn't scream if the tree is unbalanced (and sometimes creates
@@ -187,6 +202,7 @@ whole created by this driver, it is BUG - let me know about it.
 
 
 Bugs in OS/2
+============
 
 When you have two (or more) lost directories pointing each to other, chkdsk
 locks up when repairing filesystem.
@@ -199,98 +215,139 @@ File names like "a .b" are marked as 'long' by OS/2 but chkdsk "corrects" it and
 marks them as short (and writes "minor fs error corrected"). This bug is not in
 HPFS386.
 
-Codepage bugs described above.
+Codepage bugs described above
+=============================
 
 If you don't install fixpacks, there are many, many more...
 
 
 History
+=======
+
+====== =========================================================================
+0.90   First public release
+0.91   Fixed bug that caused shooting to memory when write_inode was called on
+       open inode (rarely happened)
+0.92   Fixed a little memory leak in freeing directory inodes
+0.93   Fixed bug that locked up the machine when there were too many filenames
+       with first 15 characters same
+       Fixed write_file to zero file when writing behind file end
+0.94   Fixed a little memory leak when trying to delete busy file or directory
+0.95   Fixed a bug that i_hpfs_parent_dir was not updated when moving files
+1.90   First version for 2.1.1xx kernels
+1.91   Fixed a bug that chk_sectors failed when sectors were at the end of disk
+       Fixed a race-condition when write_inode is called while deleting file
+       Fixed a bug that could possibly happen (with very low probability) when
+       using 0xff in filenames.
+
+       Rewritten locking to avoid race-conditions
+
+       Mount option 'eas' now works
+
+       Fsync no longer returns error
+
+       Files beginning with '.' are marked hidden
+
+       Remount support added
+
+       Alloc is not so slow when filesystem becomes full
+
+       Atimes are no more updated because it slows down operation
+
+       Code cleanup (removed all commented debug prints)
+1.92   Corrected a bug when sync was called just before closing file
+1.93   Modified, so that it works with kernels >= 2.1.131, I don't know if it
+       works with previous versions
+
+       Fixed a possible problem with disks > 64G (but I don't have one, so I can't
+       test it)
+
+       Fixed a file overflow at 2G
+
+       Added new option 'timeshift'
+
+       Changed behaviour on HPFS386: It is now possible to operate on HPFS386 in
+       read-only mode
+
+       Fixed a bug that slowed down alloc and prevented allocating 100% space
+       (this bug was not destructive)
+1.94   Added workaround for one bug in Linux
+
+       Fixed one buffer leak
+
+       Fixed some incompatibilities with large extended attributes (but it's still
+       not 100% ok, I have no info on it and OS/2 doesn't want to create them)
+
+       Rewritten allocation
 
-0.90 First public release
-0.91 Fixed bug that caused shooting to memory when write_inode was called on
-       open inode (rarely happened)
-0.92 Fixed a little memory leak in freeing directory inodes
-0.93 Fixed bug that locked up the machine when there were too many filenames
-       with first 15 characters same
-     Fixed write_file to zero file when writing behind file end
-0.94 Fixed a little memory leak when trying to delete busy file or directory
-0.95 Fixed a bug that i_hpfs_parent_dir was not updated when moving files
-1.90 First version for 2.1.1xx kernels
-1.91 Fixed a bug that chk_sectors failed when sectors were at the end of disk
-     Fixed a race-condition when write_inode is called while deleting file
-     Fixed a bug that could possibly happen (with very low probability) when
-       using 0xff in filenames
-     Rewritten locking to avoid race-conditions
-     Mount option 'eas' now works
-     Fsync no longer returns error
-     Files beginning with '.' are marked hidden
-     Remount support added
-     Alloc is not so slow when filesystem becomes full
-     Atimes are no more updated because it slows down operation
-     Code cleanup (removed all commented debug prints)
-1.92 Corrected a bug when sync was called just before closing file
-1.93 Modified, so that it works with kernels >= 2.1.131, I don't know if it
-       works with previous versions
-     Fixed a possible problem with disks > 64G (but I don't have one, so I can't
-       test it)
-     Fixed a file overflow at 2G
-     Added new option 'timeshift'
-     Changed behaviour on HPFS386: It is now possible to operate on HPFS386 in
-       read-only mode
-     Fixed a bug that slowed down alloc and prevented allocating 100% space
-       (this bug was not destructive)
-1.94 Added workaround for one bug in Linux
-     Fixed one buffer leak
-     Fixed some incompatibilities with large extended attributes (but it's still
-       not 100% ok, I have no info on it and OS/2 doesn't want to create them)
-     Rewritten allocation
-     Fixed a bug with i_blocks (du sometimes didn't display correct values)
-     Directories have no longer archive attribute set (some programs don't like
-       it)
-     Fixed a bug that it set badly one flag in large anode tree (it was not
-       destructive)
-1.95 Fixed one buffer leak, that could happen on corrupted filesystem
-     Fixed one bug in allocation in 1.94
-1.96 Added workaround for one bug in OS/2 (HPFS locked up, HPFS386 reported
-       error sometimes when opening directories in PMSHELL)
-     Fixed a possible bitmap race
-     Fixed possible problem on large disks
-     You can now delete open files
-     Fixed a nondestructive race in rename
-1.97 Support for HPFS v3 (on large partitions)
-     Fixed a bug that it didn't allow creation of files > 128M (it should be 2G)
+       Fixed a bug with i_blocks (du sometimes didn't display correct values)
+
+       Directories have no longer archive attribute set (some programs don't like
+       it)
+
+       Fixed a bug that it set badly one flag in large anode tree (it was not
+       destructive)
+1.95   Fixed one buffer leak, that could happen on corrupted filesystem
+
+       Fixed one bug in allocation in 1.94
+1.96   Added workaround for one bug in OS/2 (HPFS locked up, HPFS386 reported
+       error sometimes when opening directories in PMSHELL)
+
+       Fixed a possible bitmap race
+
+       Fixed possible problem on large disks
+
+       You can now delete open files
+
+       Fixed a nondestructive race in rename
+1.97   Support for HPFS v3 (on large partitions)
+
+       ZFixed a bug that it didn't allow creation of files > 128M
+       (it should be 2G)
 1.97.1 Changed names of global symbols
+
        Fixed a bug when chmoding or chowning root directory
-1.98 Fixed a deadlock when using old_readdir
-     Better directory handling; workaround for "unbalanced tree" bug in OS/2
-1.99 Corrected a possible problem when there's not enough space while deleting
-       file
-     Now it tries to truncate the file if there's not enough space when deleting
-     Removed a lot of redundant code
-2.00 Fixed a bug in rename (it was there since 1.96)
-     Better anti-fragmentation strategy
-2.01 Fixed problem with directory listing over NFS
-     Directory lseek now checks for proper parameters
-     Fixed race-condition in buffer code - it is in all filesystems in Linux;
-        when reading device (cat /dev/hda) while creating files on it, files
-        could be damaged
-2.02 Workaround for bug in breada in Linux. breada could cause accesses beyond
-        end of partition
-2.03 Char, block devices and pipes are correctly created
-     Fixed non-crashing race in unlink (Alexander Viro)
-     Now it works with Japanese version of OS/2
-2.04 Fixed error when ftruncate used to extend file
-2.05 Fixed crash when got mount parameters without =
-     Fixed crash when allocation of anode failed due to full disk
-     Fixed some crashes when block io or inode allocation failed
-2.06 Fixed some crash on corrupted disk structures
-     Better allocation strategy
-     Reschedule points added so that it doesn't lock CPU long time
-     It should work in read-only mode on Warp Server
-2.07 More fixes for Warp Server. Now it really works
-2.08 Creating new files is not so slow on large disks
-     An attempt to sync deleted file does not generate filesystem error
-2.09 Fixed error on extremely fragmented files
-
-
- vim: set textwidth=80:
+1.98   Fixed a deadlock when using old_readdir
+       Better directory handling; workaround for "unbalanced tree" bug in OS/2
+1.99   Corrected a possible problem when there's not enough space while deleting
+       file
+
+       Now it tries to truncate the file if there's not enough space when
+       deleting
+
+       Removed a lot of redundant code
+2.00   Fixed a bug in rename (it was there since 1.96)
+       Better anti-fragmentation strategy
+2.01   Fixed problem with directory listing over NFS
+
+       Directory lseek now checks for proper parameters
+
+       Fixed race-condition in buffer code - it is in all filesystems in Linux;
+       when reading device (cat /dev/hda) while creating files on it, files
+       could be damaged
+2.02   Workaround for bug in breada in Linux. breada could cause accesses beyond
+       end of partition
+2.03   Char, block devices and pipes are correctly created
+
+       Fixed non-crashing race in unlink (Alexander Viro)
+
+       Now it works with Japanese version of OS/2
+2.04   Fixed error when ftruncate used to extend file
+2.05   Fixed crash when got mount parameters without =
+
+       Fixed crash when allocation of anode failed due to full disk
+
+       Fixed some crashes when block io or inode allocation failed
+2.06   Fixed some crash on corrupted disk structures
+
+       Better allocation strategy
+
+       Reschedule points added so that it doesn't lock CPU long time
+
+       It should work in read-only mode on Warp Server
+2.07   More fixes for Warp Server. Now it really works
+2.08   Creating new files is not so slow on large disks
+
+       An attempt to sync deleted file does not generate filesystem error
+2.09   Fixed error on extremely fragmented files
+====== =========================================================================
index 386eaad..e7b46da 100644 (file)
@@ -1,3 +1,5 @@
+.. _filesystems_index:
+
 ===============================
 Filesystems in the Linux kernel
 ===============================
@@ -46,8 +48,53 @@ Documentation for filesystem implementations.
 .. toctree::
    :maxdepth: 2
 
+   9p
+   adfs
+   affs
+   afs
    autofs
+   autofs-mount-control
+   befs
+   bfs
+   btrfs
+   ceph
+   cramfs
+   debugfs
+   dlmfs
+   ecryptfs
+   efivarfs
+   erofs
+   ext2
+   ext3
+   f2fs
+   gfs2
+   gfs2-uevents
+   hfs
+   hfsplus
+   hpfs
    fuse
+   inotify
+   isofs
+   nilfs2
+   nfs/index
+   ntfs
+   ocfs2
+   ocfs2-online-filecheck
+   omfs
+   orangefs
    overlayfs
+   proc
+   qnx6
+   ramfs-rootfs-initramfs
+   relay
+   romfs
+   squashfs
+   sysfs
+   sysv-fs
+   tmpfs
+   ubifs
+   ubifs-authentication.rst
+   udf
    virtiofs
    vfat
+   zonefs
similarity index 83%
rename from Documentation/filesystems/inotify.txt
rename to Documentation/filesystems/inotify.rst
index 51f61db..7f7ef8a 100644 (file)
@@ -1,27 +1,36 @@
-                                  inotify
-           a powerful yet simple file change notification system
+.. SPDX-License-Identifier: GPL-2.0
+
+===============================================================
+Inotify - A Powerful yet Simple File Change Notification System
+===============================================================
 
 
 
 Document started 15 Mar 2005 by Robert Love <rml@novell.com>
+
 Document updated 4 Jan 2015 by Zhang Zhen <zhenzhang.zhang@huawei.com>
-       --Deleted obsoleted interface, just refer to manpages for user interface.
+
+       - Deleted obsoleted interface, just refer to manpages for user interface.
 
 (i) Rationale
 
-Q: What is the design decision behind not tying the watch to the open fd of
+Q:
+   What is the design decision behind not tying the watch to the open fd of
    the watched object?
 
-A: Watches are associated with an open inotify device, not an open file.
+A:
+   Watches are associated with an open inotify device, not an open file.
    This solves the primary problem with dnotify: keeping the file open pins
    the file and thus, worse, pins the mount.  Dnotify is therefore infeasible
    for use on a desktop system with removable media as the media cannot be
    unmounted.  Watching a file should not require that it be open.
 
-Q: What is the design decision behind using an-fd-per-instance as opposed to
+Q:
+   What is the design decision behind using an-fd-per-instance as opposed to
    an fd-per-watch?
 
-A: An fd-per-watch quickly consumes more file descriptors than are allowed,
+A:
+   An fd-per-watch quickly consumes more file descriptors than are allowed,
    more fd's than are feasible to manage, and more fd's than are optimally
    select()-able.  Yes, root can bump the per-process fd limit and yes, users
    can use epoll, but requiring both is a silly and extraneous requirement.
@@ -29,8 +38,8 @@ A: An fd-per-watch quickly consumes more file descriptors than are allowed,
    spaces is thus sensible.  The current design is what user-space developers
    want: Users initialize inotify, once, and add n watches, requiring but one
    fd and no twiddling with fd limits.  Initializing an inotify instance two
-   thousand times is silly.  If we can implement user-space's preferences 
-   cleanly--and we can, the idr layer makes stuff like this trivial--then we 
+   thousand times is silly.  If we can implement user-space's preferences
+   cleanly--and we can, the idr layer makes stuff like this trivial--then we
    should.
 
    There are other good arguments.  With a single fd, there is a single
@@ -65,9 +74,11 @@ A: An fd-per-watch quickly consumes more file descriptors than are allowed,
    need not be a one-fd-per-process mapping; it is one-fd-per-queue and a
    process can easily want more than one queue.
 
-Q: Why the system call approach?
+Q:
+   Why the system call approach?
 
-A: The poor user-space interface is the second biggest problem with dnotify.
+A:
+   The poor user-space interface is the second biggest problem with dnotify.
    Signals are a terrible, terrible interface for file notification.  Or for
    anything, for that matter.  The ideal solution, from all perspectives, is a
    file descriptor-based one that allows basic file I/O and poll/select.
diff --git a/Documentation/filesystems/isofs.rst b/Documentation/filesystems/isofs.rst
new file mode 100644 (file)
index 0000000..08fd469
--- /dev/null
@@ -0,0 +1,64 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==================
+ISO9660 Filesystem
+==================
+
+Mount options that are the same as for msdos and vfat partitions.
+
+  =========    ========================================================
+  gid=nnn      All files in the partition will be in group nnn.
+  uid=nnn      All files in the partition will be owned by user id nnn.
+  umask=nnn    The permission mask (see umask(1)) for the partition.
+  =========    ========================================================
+
+Mount options that are the same as vfat partitions. These are only useful
+when using discs encoded using Microsoft's Joliet extensions.
+
+ ==============        =============================================================
+ iocharset=name Character set to use for converting from Unicode to
+               ASCII.  Joliet filenames are stored in Unicode format, but
+               Unix for the most part doesn't know how to deal with Unicode.
+               There is also an option of doing UTF-8 translations with the
+               utf8 option.
+  utf8          Encode Unicode names in UTF-8 format. Default is no.
+ ==============        =============================================================
+
+Mount options unique to the isofs filesystem.
+
+ ================= ============================================================
+  block=512        Set the block size for the disk to 512 bytes
+  block=1024       Set the block size for the disk to 1024 bytes
+  block=2048       Set the block size for the disk to 2048 bytes
+  check=relaxed    Matches filenames with different cases
+  check=strict     Matches only filenames with the exact same case
+  cruft            Try to handle badly formatted CDs.
+  map=off          Do not map non-Rock Ridge filenames to lower case
+  map=normal       Map non-Rock Ridge filenames to lower case
+  map=acorn        As map=normal but also apply Acorn extensions if present
+  mode=xxx         Sets the permissions on files to xxx unless Rock Ridge
+                  extensions set the permissions otherwise
+  dmode=xxx        Sets the permissions on directories to xxx unless Rock Ridge
+                  extensions set the permissions otherwise
+  overriderockperm Set permissions on files and directories according to
+                  'mode' and 'dmode' even though Rock Ridge extensions are
+                  present.
+  nojoliet         Ignore Joliet extensions if they are present.
+  norock           Ignore Rock Ridge extensions if they are present.
+  hide            Completely strip hidden files from the file system.
+  showassoc       Show files marked with the 'associated' bit
+  unhide          Deprecated; showing hidden files is now default;
+                  If given, it is a synonym for 'showassoc' which will
+                  recreate previous unhide behavior
+  session=x        Select number of session on multisession CD
+  sbsector=xxx     Session begins from sector xxx
+ ================= ============================================================
+
+Recommended documents about ISO 9660 standard are located at:
+
+- http://www.y-adagio.com/
+- ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf
+
+Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically
+identical with ISO 9660.", so it is a valid and gratis substitute of the
+official ISO specification.
diff --git a/Documentation/filesystems/isofs.txt b/Documentation/filesystems/isofs.txt
deleted file mode 100644 (file)
index ba0a933..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-Mount options that are the same as for msdos and vfat partitions.
-
-  gid=nnn      All files in the partition will be in group nnn.
-  uid=nnn      All files in the partition will be owned by user id nnn.
-  umask=nnn    The permission mask (see umask(1)) for the partition.
-
-Mount options that are the same as vfat partitions. These are only useful
-when using discs encoded using Microsoft's Joliet extensions.
-  iocharset=name Character set to use for converting from Unicode to
-               ASCII.  Joliet filenames are stored in Unicode format, but
-               Unix for the most part doesn't know how to deal with Unicode.
-               There is also an option of doing UTF-8 translations with the
-               utf8 option.
-  utf8          Encode Unicode names in UTF-8 format. Default is no.
-
-Mount options unique to the isofs filesystem.
-  block=512     Set the block size for the disk to 512 bytes
-  block=1024    Set the block size for the disk to 1024 bytes
-  block=2048    Set the block size for the disk to 2048 bytes
-  check=relaxed Matches filenames with different cases
-  check=strict  Matches only filenames with the exact same case
-  cruft         Try to handle badly formatted CDs.
-  map=off       Do not map non-Rock Ridge filenames to lower case
-  map=normal    Map non-Rock Ridge filenames to lower case
-  map=acorn     As map=normal but also apply Acorn extensions if present
-  mode=xxx      Sets the permissions on files to xxx unless Rock Ridge
-               extensions set the permissions otherwise
-  dmode=xxx     Sets the permissions on directories to xxx unless Rock Ridge
-               extensions set the permissions otherwise
-  overriderockperm Set permissions on files and directories according to
-               'mode' and 'dmode' even though Rock Ridge extensions are
-               present.
-  nojoliet      Ignore Joliet extensions if they are present.
-  norock        Ignore Rock Ridge extensions if they are present.
-  hide         Completely strip hidden files from the file system.
-  showassoc    Show files marked with the 'associated' bit
-  unhide       Deprecated; showing hidden files is now default;
-               If given, it is a synonym for 'showassoc' which will
-               recreate previous unhide behavior
-  session=x     Select number of session on multisession CD
-  sbsector=xxx  Session begins from sector xxx
-
-Recommended documents about ISO 9660 standard are located at:
-http://www.y-adagio.com/
-ftp://ftp.ecma.ch/ecma-st/Ecma-119.pdf
-Quoting from the PDF "This 2nd Edition of Standard ECMA-119 is technically 
-identical with ISO 9660.", so it is a valid and gratis substitute of the
-official ISO specification.
diff --git a/Documentation/filesystems/nfs/index.rst b/Documentation/filesystems/nfs/index.rst
new file mode 100644 (file)
index 0000000..6580562
--- /dev/null
@@ -0,0 +1,13 @@
+===============================
+NFS
+===============================
+
+
+.. toctree::
+   :maxdepth: 1
+
+   pnfs
+   rpc-cache
+   rpc-server-gss
+   nfs41-server
+   knfsd-stats
@@ -1,7 +1,9 @@
-
+============================
 Kernel NFS Server Statistics
 ============================
 
+:Authors: Greg Banks <gnb@sgi.com> - 26 Mar 2009
+
 This document describes the format and semantics of the statistics
 which the kernel NFS server makes available to userspace.  These
 statistics are available in several text form pseudo files, each of
@@ -18,7 +20,7 @@ by parsing routines.  All other lines contain a sequence of fields
 separated by whitespace.
 
 /proc/fs/nfsd/pool_stats
-------------------------
+========================
 
 This file is available in kernels from 2.6.30 onwards, if the
 /proc/fs/nfsd filesystem is mounted (it almost always should be).
@@ -109,15 +111,12 @@ this case), or the transport can be enqueued for later attention
 (sockets-enqueued counts this case), or the packet can be temporarily
 deferred because the transport is currently being used by an nfsd
 thread.  This last case is not very interesting and is not explicitly
-counted, but can be inferred from the other counters thus:
+counted, but can be inferred from the other counters thus::
 
-packets-deferred = packets-arrived - ( sockets-enqueued + threads-woken )
+       packets-deferred = packets-arrived - ( sockets-enqueued + threads-woken )
 
 
 More
-----
-Descriptions of the other statistics file should go here.
-
+====
 
-Greg Banks <gnb@sgi.com>
-26 Mar 2009
+Descriptions of the other statistics file should go here.
diff --git a/Documentation/filesystems/nfs/nfs41-server.rst b/Documentation/filesystems/nfs/nfs41-server.rst
new file mode 100644 (file)
index 0000000..16b5f02
--- /dev/null
@@ -0,0 +1,256 @@
+=============================
+NFSv4.1 Server Implementation
+=============================
+
+Server support for minorversion 1 can be controlled using the
+/proc/fs/nfsd/versions control file.  The string output returned
+by reading this file will contain either "+4.1" or "-4.1"
+correspondingly.
+
+Currently, server support for minorversion 1 is enabled by default.
+It can be disabled at run time by writing the string "-4.1" to
+the /proc/fs/nfsd/versions control file.  Note that to write this
+control file, the nfsd service must be taken down.  You can use rpc.nfsd
+for this; see rpc.nfsd(8).
+
+(Warning: older servers will interpret "+4.1" and "-4.1" as "+4" and
+"-4", respectively.  Therefore, code meant to work on both new and old
+kernels must turn 4.1 on or off *before* turning support for version 4
+on or off; rpc.nfsd does this correctly.)
+
+The NFSv4 minorversion 1 (NFSv4.1) implementation in nfsd is based
+on RFC 5661.
+
+From the many new features in NFSv4.1 the current implementation
+focuses on the mandatory-to-implement NFSv4.1 Sessions, providing
+"exactly once" semantics and better control and throttling of the
+resources allocated for each client.
+
+The table below, taken from the NFSv4.1 document, lists
+the operations that are mandatory to implement (REQ), optional
+(OPT), and NFSv4.0 operations that are required not to implement (MNI)
+in minor version 1.  The first column indicates the operations that
+are not supported yet by the linux server implementation.
+
+The OPTIONAL features identified and their abbreviations are as follows:
+
+- **pNFS**     Parallel NFS
+- **FDELG**    File Delegations
+- **DDELG**    Directory Delegations
+
+The following abbreviations indicate the linux server implementation status.
+
+- **I**        Implemented NFSv4.1 operations.
+- **NS**       Not Supported.
+- **NS\***     Unimplemented optional feature.
+
+Operations
+==========
+
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| Implementation status | Operation            | REQ,REC, OPT or NMI | Feature (REQ, REC or OPT) | Definition     |
++=======================+======================+=====================+===========================+================+
+|                       | ACCESS               | REQ                 |                           | Section 18.1   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | BACKCHANNEL_CTL      | REQ                 |                           | Section 18.33  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | BIND_CONN_TO_SESSION | REQ                 |                           | Section 18.34  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | CLOSE                | REQ                 |                           | Section 18.2   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | COMMIT               | REQ                 |                           | Section 18.3   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | CREATE               | REQ                 |                           | Section 18.4   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | CREATE_SESSION       | REQ                 |                           | Section 18.36  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| NS*                   | DELEGPURGE           | OPT                 | FDELG (REQ)               | Section 18.5   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | DELEGRETURN          | OPT                 | FDELG,                    | Section 18.6   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       |                      |                     | DDELG, pNFS               |                |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       |                      |                     | (REQ)                     |                |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | DESTROY_CLIENTID     | REQ                 |                           | Section 18.50  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | DESTROY_SESSION      | REQ                 |                           | Section 18.37  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | EXCHANGE_ID          | REQ                 |                           | Section 18.35  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | FREE_STATEID         | REQ                 |                           | Section 18.38  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | GETATTR              | REQ                 |                           | Section 18.7   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | GETDEVICEINFO        | OPT                 | pNFS (REQ)                | Section 18.40  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| NS*                   | GETDEVICELIST        | OPT                 | pNFS (OPT)                | Section 18.41  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | GETFH                | REQ                 |                           | Section 18.8   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| NS*                   | GET_DIR_DELEGATION   | OPT                 | DDELG (REQ)               | Section 18.39  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | LAYOUTCOMMIT         | OPT                 | pNFS (REQ)                | Section 18.42  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | LAYOUTGET            | OPT                 | pNFS (REQ)                | Section 18.43  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | LAYOUTRETURN         | OPT                 | pNFS (REQ)                | Section 18.44  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | LINK                 | OPT                 |                           | Section 18.9   |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | LOCK                 | REQ                 |                           | Section 18.10  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | LOCKT                | REQ                 |                           | Section 18.11  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | LOCKU                | REQ                 |                           | Section 18.12  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | LOOKUP               | REQ                 |                           | Section 18.13  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | LOOKUPP              | REQ                 |                           | Section 18.14  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | NVERIFY              | REQ                 |                           | Section 18.15  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | OPEN                 | REQ                 |                           | Section 18.16  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| NS*                   | OPENATTR             | OPT                 |                           | Section 18.17  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | OPEN_CONFIRM         | MNI                 |                           | N/A            |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | OPEN_DOWNGRADE       | REQ                 |                           | Section 18.18  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | PUTFH                | REQ                 |                           | Section 18.19  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | PUTPUBFH             | REQ                 |                           | Section 18.20  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | PUTROOTFH            | REQ                 |                           | Section 18.21  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | READ                 | REQ                 |                           | Section 18.22  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | READDIR              | REQ                 |                           | Section 18.23  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | READLINK             | OPT                 |                           | Section 18.24  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | RECLAIM_COMPLETE     | REQ                 |                           | Section 18.51  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | RELEASE_LOCKOWNER    | MNI                 |                           | N/A            |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | REMOVE               | REQ                 |                           | Section 18.25  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | RENAME               | REQ                 |                           | Section 18.26  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | RENEW                | MNI                 |                           | N/A            |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | RESTOREFH            | REQ                 |                           | Section 18.27  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | SAVEFH               | REQ                 |                           | Section 18.28  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | SECINFO              | REQ                 |                           | Section 18.29  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | SECINFO_NO_NAME      | REC                 | pNFS files                | Section 18.45, |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       |                      |                     | layout (REQ)              | Section 13.12  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | SEQUENCE             | REQ                 |                           | Section 18.46  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | SETATTR              | REQ                 |                           | Section 18.30  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | SETCLIENTID          | MNI                 |                           | N/A            |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | SETCLIENTID_CONFIRM  | MNI                 |                           | N/A            |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| NS                    | SET_SSV              | REQ                 |                           | Section 18.47  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| I                     | TEST_STATEID         | REQ                 |                           | Section 18.48  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | VERIFY               | REQ                 |                           | Section 18.31  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+| NS*                   | WANT_DELEGATION      | OPT                 | FDELG (OPT)               | Section 18.49  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+|                       | WRITE                | REQ                 |                           | Section 18.32  |
++-----------------------+----------------------+---------------------+---------------------------+----------------+
+
+
+Callback Operations
+===================
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| Implementation status | Operation               | REQ,REC, OPT or NMI | Feature (REQ, REC or OPT) | Definition    |
++=======================+=========================+=====================+===========================+===============+
+|                       | CB_GETATTR              | OPT                 | FDELG (REQ)               | Section 20.1  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| I                     | CB_LAYOUTRECALL         | OPT                 | pNFS (REQ)                | Section 20.3  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| NS*                   | CB_NOTIFY               | OPT                 | DDELG (REQ)               | Section 20.4  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| NS*                   | CB_NOTIFY_DEVICEID      | OPT                 | pNFS (OPT)                | Section 20.12 |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| NS*                   | CB_NOTIFY_LOCK          | OPT                 |                           | Section 20.11 |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| NS*                   | CB_PUSH_DELEG           | OPT                 | FDELG (OPT)               | Section 20.5  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       | CB_RECALL               | OPT                 | FDELG,                    | Section 20.2  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | DDELG, pNFS               |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | (REQ)                     |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| NS*                   | CB_RECALL_ANY           | OPT                 | FDELG,                    | Section 20.6  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | DDELG, pNFS               |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | (REQ)                     |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| NS                    | CB_RECALL_SLOT          | REQ                 |                           | Section 20.8  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| NS*                   | CB_RECALLABLE_OBJ_AVAIL | OPT                 | DDELG, pNFS               | Section 20.7  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | (REQ)                     |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| I                     | CB_SEQUENCE             | OPT                 | FDELG,                    | Section 20.9  |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | DDELG, pNFS               |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | (REQ)                     |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+| NS*                   | CB_WANTS_CANCELLED      | OPT                 | FDELG,                    | Section 20.10 |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | DDELG, pNFS               |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+|                       |                         |                     | (REQ)                     |               |
++-----------------------+-------------------------+---------------------+---------------------------+---------------+
+
+
+Implementation notes:
+=====================
+
+SSV:
+  The spec claims this is mandatory, but we don't actually know of any
+  implementations, so we're ignoring it for now.  The server returns
+  NFS4ERR_ENCR_ALG_UNSUPP on EXCHANGE_ID, which should be future-proof.
+
+GSS on the backchannel:
+  Again, theoretically required but not widely implemented (in
+  particular, the current Linux client doesn't request it).  We return
+  NFS4ERR_ENCR_ALG_UNSUPP on CREATE_SESSION.
+
+DELEGPURGE:
+  mandatory only for servers that support CLAIM_DELEGATE_PREV and/or
+  CLAIM_DELEG_PREV_FH (which allows clients to keep delegations that
+  persist across client reboots).  Thus we need not implement this for
+  now.
+
+EXCHANGE_ID:
+  implementation ids are ignored
+
+CREATE_SESSION:
+  backchannel attributes are ignored
+
+SEQUENCE:
+  no support for dynamic slot table renegotiation (optional)
+
+Nonstandard compound limitations:
+  No support for a sessions fore channel RPC compound that requires both a
+  ca_maxrequestsize request and a ca_maxresponsesize reply, so we may
+  fail to live up to the promise we made in CREATE_SESSION fore channel
+  negotiation.
+
+See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues.
diff --git a/Documentation/filesystems/nfs/nfs41-server.txt b/Documentation/filesystems/nfs/nfs41-server.txt
deleted file mode 100644 (file)
index 682a59f..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-NFSv4.1 Server Implementation
-
-Server support for minorversion 1 can be controlled using the
-/proc/fs/nfsd/versions control file.  The string output returned
-by reading this file will contain either "+4.1" or "-4.1"
-correspondingly.
-
-Currently, server support for minorversion 1 is enabled by default.
-It can be disabled at run time by writing the string "-4.1" to
-the /proc/fs/nfsd/versions control file.  Note that to write this
-control file, the nfsd service must be taken down.  You can use rpc.nfsd
-for this; see rpc.nfsd(8).
-
-(Warning: older servers will interpret "+4.1" and "-4.1" as "+4" and
-"-4", respectively.  Therefore, code meant to work on both new and old
-kernels must turn 4.1 on or off *before* turning support for version 4
-on or off; rpc.nfsd does this correctly.)
-
-The NFSv4 minorversion 1 (NFSv4.1) implementation in nfsd is based
-on RFC 5661.
-
-From the many new features in NFSv4.1 the current implementation
-focuses on the mandatory-to-implement NFSv4.1 Sessions, providing
-"exactly once" semantics and better control and throttling of the
-resources allocated for each client.
-
-The table below, taken from the NFSv4.1 document, lists
-the operations that are mandatory to implement (REQ), optional
-(OPT), and NFSv4.0 operations that are required not to implement (MNI)
-in minor version 1.  The first column indicates the operations that
-are not supported yet by the linux server implementation.
-
-The OPTIONAL features identified and their abbreviations are as follows:
-       pNFS    Parallel NFS
-       FDELG   File Delegations
-       DDELG   Directory Delegations
-
-The following abbreviations indicate the linux server implementation status.
-       I       Implemented NFSv4.1 operations.
-       NS      Not Supported.
-       NS*     Unimplemented optional feature.
-
-Operations
-
-   +----------------------+------------+--------------+----------------+
-   | Operation            | REQ, REC,  | Feature      | Definition     |
-   |                      | OPT, or    | (REQ, REC,   |                |
-   |                      | MNI        | or OPT)      |                |
-   +----------------------+------------+--------------+----------------+
-   | ACCESS               | REQ        |              | Section 18.1   |
-I  | BACKCHANNEL_CTL      | REQ        |              | Section 18.33  |
-I  | BIND_CONN_TO_SESSION | REQ        |              | Section 18.34  |
-   | CLOSE                | REQ        |              | Section 18.2   |
-   | COMMIT               | REQ        |              | Section 18.3   |
-   | CREATE               | REQ        |              | Section 18.4   |
-I  | CREATE_SESSION       | REQ        |              | Section 18.36  |
-NS*| DELEGPURGE           | OPT        | FDELG (REQ)  | Section 18.5   |
-   | DELEGRETURN          | OPT        | FDELG,       | Section 18.6   |
-   |                      |            | DDELG, pNFS  |                |
-   |                      |            | (REQ)        |                |
-I  | DESTROY_CLIENTID     | REQ        |              | Section 18.50  |
-I  | DESTROY_SESSION      | REQ        |              | Section 18.37  |
-I  | EXCHANGE_ID          | REQ        |              | Section 18.35  |
-I  | FREE_STATEID         | REQ        |              | Section 18.38  |
-   | GETATTR              | REQ        |              | Section 18.7   |
-I  | GETDEVICEINFO        | OPT        | pNFS (REQ)   | Section 18.40  |
-NS*| GETDEVICELIST        | OPT        | pNFS (OPT)   | Section 18.41  |
-   | GETFH                | REQ        |              | Section 18.8   |
-NS*| GET_DIR_DELEGATION   | OPT        | DDELG (REQ)  | Section 18.39  |
-I  | LAYOUTCOMMIT         | OPT        | pNFS (REQ)   | Section 18.42  |
-I  | LAYOUTGET            | OPT        | pNFS (REQ)   | Section 18.43  |
-I  | LAYOUTRETURN         | OPT        | pNFS (REQ)   | Section 18.44  |
-   | LINK                 | OPT        |              | Section 18.9   |
-   | LOCK                 | REQ        |              | Section 18.10  |
-   | LOCKT                | REQ        |              | Section 18.11  |
-   | LOCKU                | REQ        |              | Section 18.12  |
-   | LOOKUP               | REQ        |              | Section 18.13  |
-   | LOOKUPP              | REQ        |              | Section 18.14  |
-   | NVERIFY              | REQ        |              | Section 18.15  |
-   | OPEN                 | REQ        |              | Section 18.16  |
-NS*| OPENATTR             | OPT        |              | Section 18.17  |
-   | OPEN_CONFIRM         | MNI        |              | N/A            |
-   | OPEN_DOWNGRADE       | REQ        |              | Section 18.18  |
-   | PUTFH                | REQ        |              | Section 18.19  |
-   | PUTPUBFH             | REQ        |              | Section 18.20  |
-   | PUTROOTFH            | REQ        |              | Section 18.21  |
-   | READ                 | REQ        |              | Section 18.22  |
-   | READDIR              | REQ        |              | Section 18.23  |
-   | READLINK             | OPT        |              | Section 18.24  |
-   | RECLAIM_COMPLETE     | REQ        |              | Section 18.51  |
-   | RELEASE_LOCKOWNER    | MNI        |              | N/A            |
-   | REMOVE               | REQ        |              | Section 18.25  |
-   | RENAME               | REQ        |              | Section 18.26  |
-   | RENEW                | MNI        |              | N/A            |
-   | RESTOREFH            | REQ        |              | Section 18.27  |
-   | SAVEFH               | REQ        |              | Section 18.28  |
-   | SECINFO              | REQ        |              | Section 18.29  |
-I  | SECINFO_NO_NAME      | REC        | pNFS files   | Section 18.45, |
-   |                      |            | layout (REQ) | Section 13.12  |
-I  | SEQUENCE             | REQ        |              | Section 18.46  |
-   | SETATTR              | REQ        |              | Section 18.30  |
-   | SETCLIENTID          | MNI        |              | N/A            |
-   | SETCLIENTID_CONFIRM  | MNI        |              | N/A            |
-NS | SET_SSV              | REQ        |              | Section 18.47  |
-I  | TEST_STATEID         | REQ        |              | Section 18.48  |
-   | VERIFY               | REQ        |              | Section 18.31  |
-NS*| WANT_DELEGATION      | OPT        | FDELG (OPT)  | Section 18.49  |
-   | WRITE                | REQ        |              | Section 18.32  |
-
-Callback Operations
-
-   +-------------------------+-----------+-------------+---------------+
-   | Operation               | REQ, REC, | Feature     | Definition    |
-   |                         | OPT, or   | (REQ, REC,  |               |
-   |                         | MNI       | or OPT)     |               |
-   +-------------------------+-----------+-------------+---------------+
-   | CB_GETATTR              | OPT       | FDELG (REQ) | Section 20.1  |
-I  | CB_LAYOUTRECALL         | OPT       | pNFS (REQ)  | Section 20.3  |
-NS*| CB_NOTIFY               | OPT       | DDELG (REQ) | Section 20.4  |
-NS*| CB_NOTIFY_DEVICEID      | OPT       | pNFS (OPT)  | Section 20.12 |
-NS*| CB_NOTIFY_LOCK          | OPT       |             | Section 20.11 |
-NS*| CB_PUSH_DELEG           | OPT       | FDELG (OPT) | Section 20.5  |
-   | CB_RECALL               | OPT       | FDELG,      | Section 20.2  |
-   |                         |           | DDELG, pNFS |               |
-   |                         |           | (REQ)       |               |
-NS*| CB_RECALL_ANY           | OPT       | FDELG,      | Section 20.6  |
-   |                         |           | DDELG, pNFS |               |
-   |                         |           | (REQ)       |               |
-NS | CB_RECALL_SLOT          | REQ       |             | Section 20.8  |
-NS*| CB_RECALLABLE_OBJ_AVAIL | OPT       | DDELG, pNFS | Section 20.7  |
-   |                         |           | (REQ)       |               |
-I  | CB_SEQUENCE             | OPT       | FDELG,      | Section 20.9  |
-   |                         |           | DDELG, pNFS |               |
-   |                         |           | (REQ)       |               |
-NS*| CB_WANTS_CANCELLED      | OPT       | FDELG,      | Section 20.10 |
-   |                         |           | DDELG, pNFS |               |
-   |                         |           | (REQ)       |               |
-   +-------------------------+-----------+-------------+---------------+
-
-Implementation notes:
-
-SSV:
-* The spec claims this is mandatory, but we don't actually know of any
-  implementations, so we're ignoring it for now.  The server returns
-  NFS4ERR_ENCR_ALG_UNSUPP on EXCHANGE_ID, which should be future-proof.
-
-GSS on the backchannel:
-* Again, theoretically required but not widely implemented (in
-  particular, the current Linux client doesn't request it).  We return
-  NFS4ERR_ENCR_ALG_UNSUPP on CREATE_SESSION.
-
-DELEGPURGE:
-* mandatory only for servers that support CLAIM_DELEGATE_PREV and/or
-  CLAIM_DELEG_PREV_FH (which allows clients to keep delegations that
-  persist across client reboots).  Thus we need not implement this for
-  now.
-
-EXCHANGE_ID:
-* implementation ids are ignored
-
-CREATE_SESSION:
-* backchannel attributes are ignored
-
-SEQUENCE:
-* no support for dynamic slot table renegotiation (optional)
-
-Nonstandard compound limitations:
-* No support for a sessions fore channel RPC compound that requires both a
-  ca_maxrequestsize request and a ca_maxresponsesize reply, so we may
-  fail to live up to the promise we made in CREATE_SESSION fore channel
-  negotiation.
-
-See also http://wiki.linux-nfs.org/wiki/index.php/Server_4.0_and_4.1_issues.
similarity index 87%
rename from Documentation/filesystems/nfs/pnfs.txt
rename to Documentation/filesystems/nfs/pnfs.rst
index 80dc0bd..7c470ec 100644 (file)
@@ -1,15 +1,17 @@
-Reference counting in pnfs:
+==========================
+Reference counting in pnfs
 ==========================
 
 The are several inter-related caches.  We have layouts which can
 reference multiple devices, each of which can reference multiple data servers.
 Each data server can be referenced by multiple devices.  Each device
-can be referenced by multiple layouts.  To keep all of this straight,
+can be referenced by multiple layouts. To keep all of this straight,
 we need to reference count.
 
 
 struct pnfs_layout_hdr
-----------------------
+======================
+
 The on-the-wire command LAYOUTGET corresponds to struct
 pnfs_layout_segment, usually referred to by the variable name lseg.
 Each nfs_inode may hold a pointer to a cache of these layout
@@ -25,7 +27,8 @@ the reference count, as the layout is kept around by the lseg that
 keeps it in the list.
 
 deviceid_cache
---------------
+==============
+
 lsegs reference device ids, which are resolved per nfs_client and
 layout driver type.  The device ids are held in a RCU cache (struct
 nfs4_deviceid_cache).  The cache itself is referenced across each
@@ -38,24 +41,26 @@ justification, but seems reasonable given that we can have multiple
 deviceid's per filesystem, and multiple filesystems per nfs_client.
 
 The hash code is copied from the nfsd code base.  A discussion of
-hashing and variations of this algorithm can be found at:
-http://groups.google.com/group/comp.lang.c/browse_thread/thread/9522965e2b8d3809
+hashing and variations of this algorithm can be found `here.
+<http://groups.google.com/group/comp.lang.c/browse_thread/thread/9522965e2b8d3809>`_
 
 data server cache
------------------
+=================
+
 file driver devices refer to data servers, which are kept in a module
 level cache.  Its reference is held over the lifetime of the deviceid
 pointing to it.
 
 lseg
-----
+====
+
 lseg maintains an extra reference corresponding to the NFS_LSEG_VALID
 bit which holds it in the pnfs_layout_hdr's list.  When the final lseg
 is removed from the pnfs_layout_hdr's list, the NFS_LAYOUT_DESTROYED
 bit is set, preventing any new lsegs from being added.
 
 layout drivers
---------------
+==============
 
 PNFS utilizes what is called layout drivers. The STD defines 4 basic
 layout types: "files", "objects", "blocks", and "flexfiles". For each
@@ -68,6 +73,6 @@ Blocks-layout-driver code is in: fs/nfs/blocklayout/.. directory
 Flexfiles-layout-driver code is in: fs/nfs/flexfilelayout/.. directory
 
 blocks-layout setup
--------------------
+===================
 
 TODO: Document the setup needs of the blocks layout driver
similarity index 66%
rename from Documentation/filesystems/nfs/rpc-cache.txt
rename to Documentation/filesystems/nfs/rpc-cache.rst
index c4dac82..bb164ee 100644 (file)
@@ -1,9 +1,14 @@
-       This document gives a brief introduction to the caching
+=========
+RPC Cache
+=========
+
+This document gives a brief introduction to the caching
 mechanisms in the sunrpc layer that is used, in particular,
 for NFS authentication.
 
-CACHES
+Caches
 ======
+
 The caching replaces the old exports table and allows for
 a wide variety of values to be caches.
 
@@ -12,6 +17,7 @@ quite possibly very different in content and use.  There is a corpus
 of common code for managing these caches.
 
 Examples of caches that are likely to be needed are:
+
   - mapping from IP address to client name
   - mapping from client name and filesystem to export options
   - mapping from UID to list of GIDs, to work around NFS's limitation
@@ -21,6 +27,7 @@ Examples of caches that are likely to be needed are:
   - mapping from network identify to public key for crypto authentication.
 
 The common code handles such things as:
+
    - general cache lookup with correct locking
    - supporting 'NEGATIVE' as well as positive entries
    - allowing an EXPIRED time on cache items, and removing
@@ -35,60 +42,66 @@ The common code handles such things as:
 Creating a Cache
 ----------------
 
-1/ A cache needs a datum to store.  This is in the form of a
-   structure definition that must contain a
-     struct cache_head
+-  A cache needs a datum to store.  This is in the form of a
+   structure definition that must contain a struct cache_head
    as an element, usually the first.
    It will also contain a key and some content.
    Each cache element is reference counted and contains
    expiry and update times for use in cache management.
-2/ A cache needs a "cache_detail" structure that
+ A cache needs a "cache_detail" structure that
    describes the cache.  This stores the hash table, some
    parameters for cache management, and some operations detailing how
    to work with particular cache items.
-   The operations requires are:
-       struct cache_head *alloc(void)
-               This simply allocates appropriate memory and returns
-               a pointer to the cache_detail embedded within the
-               structure
-       void cache_put(struct kref *)
-               This is called when the last reference to an item is
-               dropped.  The pointer passed is to the 'ref' field
-               in the cache_head.  cache_put should release any
-               references create by 'cache_init' and, if CACHE_VALID
-               is set, any references created by cache_update.
-               It should then release the memory allocated by
-               'alloc'.
-        int match(struct cache_head *orig, struct cache_head *new)
-               test if the keys in the two structures match.  Return
-               1 if they do, 0 if they don't.
-       void init(struct cache_head *orig, struct cache_head *new)
-               Set the 'key' fields in 'new' from 'orig'.  This may
-               include taking references to shared objects.
-       void update(struct cache_head *orig, struct cache_head *new)
-               Set the 'content' fileds in 'new' from 'orig'.
-       int cache_show(struct seq_file *m, struct cache_detail *cd,
-                       struct cache_head *h)
-               Optional.  Used to provide a /proc file that lists the
-               contents of a cache.  This should show one item,
-               usually on just one line.
-       int cache_request(struct cache_detail *cd, struct cache_head *h,
-               char **bpp, int *blen)
-               Format a request to be send to user-space for an item
-               to be instantiated.  *bpp is a buffer of size *blen.
-               bpp should be moved forward over the encoded message,
-               and  *blen should be reduced to show how much free
-               space remains.  Return 0 on success or <0 if not
-               enough room or other problem.
-       int cache_parse(struct cache_detail *cd, char *buf, int len)
-               A message from user space has arrived to fill out a
-               cache entry.  It is in 'buf' of length 'len'.
-               cache_parse should parse this, find the item in the
-               cache with sunrpc_cache_lookup_rcu, and update the item
-               with sunrpc_cache_update.
-
-
-3/ A cache needs to be registered using cache_register().  This
+
+   The operations are:
+
+    struct cache_head \*alloc(void)
+      This simply allocates appropriate memory and returns
+      a pointer to the cache_detail embedded within the
+      structure
+
+    void cache_put(struct kref \*)
+      This is called when the last reference to an item is
+      dropped.  The pointer passed is to the 'ref' field
+      in the cache_head.  cache_put should release any
+      references create by 'cache_init' and, if CACHE_VALID
+      is set, any references created by cache_update.
+      It should then release the memory allocated by
+      'alloc'.
+
+    int match(struct cache_head \*orig, struct cache_head \*new)
+      test if the keys in the two structures match.  Return
+      1 if they do, 0 if they don't.
+
+    void init(struct cache_head \*orig, struct cache_head \*new)
+      Set the 'key' fields in 'new' from 'orig'.  This may
+      include taking references to shared objects.
+
+    void update(struct cache_head \*orig, struct cache_head \*new)
+      Set the 'content' fileds in 'new' from 'orig'.
+
+    int cache_show(struct seq_file \*m, struct cache_detail \*cd, struct cache_head \*h)
+      Optional.  Used to provide a /proc file that lists the
+      contents of a cache.  This should show one item,
+      usually on just one line.
+
+    int cache_request(struct cache_detail \*cd, struct cache_head \*h, char \*\*bpp, int \*blen)
+      Format a request to be send to user-space for an item
+      to be instantiated.  \*bpp is a buffer of size \*blen.
+      bpp should be moved forward over the encoded message,
+      and  \*blen should be reduced to show how much free
+      space remains.  Return 0 on success or <0 if not
+      enough room or other problem.
+
+    int cache_parse(struct cache_detail \*cd, char \*buf, int len)
+      A message from user space has arrived to fill out a
+      cache entry.  It is in 'buf' of length 'len'.
+      cache_parse should parse this, find the item in the
+      cache with sunrpc_cache_lookup_rcu, and update the item
+      with sunrpc_cache_update.
+
+
+-  A cache needs to be registered using cache_register().  This
    includes it on a list of caches that will be regularly
    cleaned to discard old data.
 
@@ -107,7 +120,7 @@ cache_check will return -ENOENT in the entry is negative or if an up
 call is needed but not possible, -EAGAIN if an upcall is pending,
 or 0 if the data is valid;
 
-cache_check can be passed a "struct cache_req *".  This structure is
+cache_check can be passed a "struct cache_req\*".  This structure is
 typically embedded in the actual request and can be used to create a
 deferred copy of the request (struct cache_deferred_req).  This is
 done when the found cache item is not uptodate, but the is reason to
@@ -139,9 +152,11 @@ The 'channel' works a bit like a datagram socket. Each 'write' is
 passed as a whole to the cache for parsing and interpretation.
 Each cache can treat the write requests differently, but it is
 expected that a message written will contain:
+
   - a key
   - an expiry time
   - a content.
+
 with the intention that an item in the cache with the give key
 should be create or updated to have the given content, and the
 expiry time should be set on that item.
@@ -156,7 +171,8 @@ If there are no more requests to return, read will return EOF, but a
 select or poll for read will block waiting for another request to be
 added.
 
-Thus a user-space helper is likely to:
+Thus a user-space helper is likely to::
+
   open the channel.
     select for readable
     read a request
@@ -175,12 +191,13 @@ Each cache should also define a "cache_request" method which
 takes a cache item and encodes a request into the buffer
 provided.
 
-Note: If a cache has no active readers on the channel, and has had not
-active readers for more than 60 seconds, further requests will not be
-added to the channel but instead all lookups that do not find a valid
-entry will fail.  This is partly for backward compatibility: The
-previous nfs exports table was deemed to be authoritative and a
-failed lookup meant a definite 'no'.
+.. note::
+  If a cache has no active readers on the channel, and has had not
+  active readers for more than 60 seconds, further requests will not be
+  added to the channel but instead all lookups that do not find a valid
+  entry will fail.  This is partly for backward compatibility: The
+  previous nfs exports table was deemed to be authoritative and a
+  failed lookup meant a definite 'no'.
 
 request/response format
 -----------------------
@@ -193,10 +210,11 @@ with precisely one newline character which should be at the end.
 Fields within the record should be separated by spaces, normally one.
 If spaces, newlines, or nul characters are needed in a field they
 much be quoted.  two mechanisms are available:
-1/ If a field begins '\x' then it must contain an even number of
+
+-  If a field begins '\x' then it must contain an even number of
    hex digits, and pairs of these digits provide the bytes in the
    field.
-2/ otherwise a \ in the field must be followed by 3 octal digits
+ otherwise a \ in the field must be followed by 3 octal digits
    which give the code for a byte.  Other characters are treated
    as them selves.  At the very least, space, newline, nul, and
    '\' must be quoted in this way.
@@ -1,4 +1,4 @@
-
+=========================================
 rpcsec_gss support for kernel RPC servers
 =========================================
 
@@ -9,14 +9,17 @@ NFSv4.1 and higher don't require the client to act as a server for the
 purposes of authentication.)
 
 RPCGSS is specified in a few IETF documents:
+
  - RFC2203 v1: http://tools.ietf.org/rfc/rfc2203.txt
  - RFC5403 v2: http://tools.ietf.org/rfc/rfc5403.txt
+
 and there is a 3rd version  being proposed:
+
  - http://tools.ietf.org/id/draft-williams-rpcsecgssv3.txt
    (At draft n. 02 at the time of writing)
 
 Background
-----------
+==========
 
 The RPCGSS Authentication method describes a way to perform GSSAPI
 Authentication for NFS.  Although GSSAPI is itself completely mechanism
@@ -29,6 +32,7 @@ depends on GSSAPI extensions that are KRB5 specific.
 GSSAPI is a complex library, and implementing it completely in kernel is
 unwarranted. However GSSAPI operations are fundementally separable in 2
 parts:
+
 - initial context establishment
 - integrity/privacy protection (signing and encrypting of individual
   packets)
@@ -41,7 +45,7 @@ kernel, but leave the initial context establishment to userspace.  We
 need upcalls to request userspace to perform context establishment.
 
 NFS Server Legacy Upcall Mechanism
-----------------------------------
+==================================
 
 The classic upcall mechanism uses a custom text based upcall mechanism
 to talk to a custom daemon called rpc.svcgssd that is provide by the
@@ -62,21 +66,20 @@ groups) due to limitation on the size of the buffer that can be send
 back to the kernel (4KiB).
 
 NFS Server New RPC Upcall Mechanism
------------------------------------
+===================================
 
 The newer upcall mechanism uses RPC over a unix socket to a daemon
 called gss-proxy, implemented by a userspace program called Gssproxy.
 
-The gss_proxy RPC protocol is currently documented here:
-
-       https://fedorahosted.org/gss-proxy/wiki/ProtocolDocumentation
+The gss_proxy RPC protocol is currently documented `here
+<https://fedorahosted.org/gss-proxy/wiki/ProtocolDocumentation>`_.
 
 This upcall mechanism uses the kernel rpc client and connects to the gssproxy
 userspace program over a regular unix socket. The gssproxy protocol does not
 suffer from the size limitations of the legacy protocol.
 
 Negotiating Upcall Mechanisms
------------------------------
+=============================
 
 To provide backward compatibility, the kernel defaults to using the
 legacy mechanism.  To switch to the new mechanism, gss-proxy must bind
similarity index 89%
rename from Documentation/filesystems/nilfs2.txt
rename to Documentation/filesystems/nilfs2.rst
index f2f3f85..6c49f04 100644 (file)
@@ -1,5 +1,8 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======
 NILFS2
-------
+======
 
 NILFS2 is a log-structured file system (LFS) supporting continuous
 snapshotting.  In addition to versioning capability of the entire file
@@ -25,9 +28,9 @@ available from the following download page.  At least "mkfs.nilfs2",
 cleaner or garbage collector) are required.  Details on the tools are
 described in the man pages included in the package.
 
-Project web page:    https://nilfs.sourceforge.io/
-Download page:       https://nilfs.sourceforge.io/en/download.html
-List info:           http://vger.kernel.org/vger-lists.html#linux-nilfs
+:Project web page:    https://nilfs.sourceforge.io/
+:Download page:       https://nilfs.sourceforge.io/en/download.html
+:List info:           http://vger.kernel.org/vger-lists.html#linux-nilfs
 
 Caveats
 =======
@@ -47,6 +50,7 @@ Mount options
 NILFS2 supports the following mount options:
 (*) == default
 
+======================= =======================================================
 barrier(*)             This enables/disables the use of write barriers.  This
 nobarrier              requires an IO stack which can support barriers, and
                        if nilfs gets an error on a barrier write, it will
@@ -79,6 +83,7 @@ discard                       This enables/disables the use of discard/TRIM commands.
 nodiscard(*)           The discard/TRIM commands are sent to the underlying
                        block device when blocks are freed.  This is useful
                        for SSD devices and sparse/thinly-provisioned LUNs.
+======================= =======================================================
 
 Ioctls
 ======
@@ -87,9 +92,11 @@ There is some NILFS2 specific functionality which can be accessed by application
 through the system call interfaces. The list of all NILFS2 specific ioctls are
 shown in the table below.
 
-Table of NILFS2 specific ioctls
-..............................................................................
+Table of NILFS2 specific ioctls:
+
+ ============================== ===============================================
  Ioctl                         Description
+ ============================== ===============================================
  NILFS_IOCTL_CHANGE_CPMODE      Change mode of given checkpoint between
                                checkpoint and snapshot state. This ioctl is
                                used in chcp and mkcp utilities.
@@ -142,11 +149,12 @@ Table of NILFS2 specific ioctls
  NILFS_IOCTL_SET_ALLOC_RANGE    Define lower limit of segments in bytes and
                                upper limit of segments in bytes. This ioctl
                                is used by nilfs_resize utility.
+ ============================== ===============================================
 
 NILFS2 usage
 ============
 
-To use nilfs2 as a local file system, simply:
+To use nilfs2 as a local file system, simply::
 
  # mkfs -t nilfs2 /dev/block_device
  # mount -t nilfs2 /dev/block_device /dir
@@ -157,18 +165,20 @@ This will also invoke the cleaner through the mount helper program
 Checkpoints and snapshots are managed by the following commands.
 Their manpages are included in the nilfs-utils package above.
 
+  ====     ===========================================================
   lscp     list checkpoints or snapshots.
   mkcp     make a checkpoint or a snapshot.
   chcp     change an existing checkpoint to a snapshot or vice versa.
   rmcp     invalidate specified checkpoint(s).
+  ====     ===========================================================
 
-To mount a snapshot,
+To mount a snapshot::
 
  # mount -t nilfs2 -r -o cp=<cno> /dev/block_device /snap_dir
 
 where <cno> is the checkpoint number of the snapshot.
 
-To unmount the NILFS2 mount point or snapshot, simply:
+To unmount the NILFS2 mount point or snapshot, simply::
 
  # umount /dir
 
@@ -181,7 +191,7 @@ Disk format
 A nilfs2 volume is equally divided into a number of segments except
 for the super block (SB) and segment #0.  A segment is the container
 of logs.  Each log is composed of summary information blocks, payload
-blocks, and an optional super root block (SR):
+blocks, and an optional super root block (SR)::
 
    ______________________________________________________
   | |SB| | Segment | Segment | Segment | ... | Segment | |
@@ -200,7 +210,7 @@ blocks, and an optional super root block (SR):
   |_blocks__|_________________|__|
 
 The payload blocks are organized per file, and each file consists of
-data blocks and B-tree node blocks:
+data blocks and B-tree node blocks::
 
     |<---       File-A        --->|<---       File-B        --->|
    _______________________________________________________________
@@ -213,7 +223,7 @@ files without data blocks or B-tree node blocks.
 
 The organization of the blocks is recorded in the summary information
 blocks, which contains a header structure (nilfs_segment_summary), per
-file structures (nilfs_finfo), and per block structures (nilfs_binfo):
+file structures (nilfs_finfo), and per block structures (nilfs_binfo)::
 
   _________________________________________________________________________
  | Summary | finfo | binfo | ... | binfo | finfo | binfo | ... | binfo |...
@@ -223,7 +233,7 @@ file structures (nilfs_finfo), and per block structures (nilfs_binfo):
 The logs include regular files, directory files, symbolic link files
 and several meta data files.  The mata data files are the files used
 to maintain file system meta data.  The current version of NILFS2 uses
-the following meta data files:
+the following meta data files::
 
  1) Inode file (ifile)             -- Stores on-disk inodes
  2) Checkpoint file (cpfile)       -- Stores checkpoints
@@ -232,7 +242,7 @@ the following meta data files:
     (DAT)                             block numbers.  This file serves to
                                       make on-disk blocks relocatable.
 
-The following figure shows a typical organization of the logs:
+The following figure shows a typical organization of the logs::
 
   _________________________________________________________________________
  | Summary | regular file | file  | ... | ifile | cpfile | sufile | DAT |SR|
@@ -250,7 +260,7 @@ three special inodes, inodes for the DAT, cpfile, and sufile.  Inodes
 of regular files, directories, symlinks and other special files, are
 included in the ifile.  The inode of ifile itself is included in the
 corresponding checkpoint entry in the cpfile.  Thus, the hierarchy
-among NILFS2 files can be depicted as follows:
+among NILFS2 files can be depicted as follows::
 
   Super block (SB)
        |
similarity index 85%
rename from Documentation/filesystems/ntfs.txt
rename to Documentation/filesystems/ntfs.rst
index 553f10d..5bb093a 100644 (file)
@@ -1,19 +1,21 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================
 The Linux NTFS filesystem driver
 ================================
 
 
-Table of contents
-=================
+.. Table of contents
 
-- Overview
-- Web site
-- Features
-- Supported mount options
-- Known bugs and (mis-)features
-- Using NTFS volume and stripe sets
-  - The Device-Mapper driver
-  - The Software RAID / MD driver
-  - Limitations when using the MD driver
+   - Overview
+   - Web site
+   - Features
+   - Supported mount options
+   - Known bugs and (mis-)features
+   - Using NTFS volume and stripe sets
+     - The Device-Mapper driver
+     - The Software RAID / MD driver
+     - Limitations when using the MD driver
 
 
 Overview
@@ -66,8 +68,10 @@ Features
   partition by creating a large file while in Windows and then loopback
   mounting the file while in Linux and creating a Linux filesystem on it that
   is used to install Linux on it.
-- A comparison of the two drivers using:
+- A comparison of the two drivers using::
+
        time find . -type f -exec md5sum "{}" \;
+
   run three times in sequence with each driver (after a reboot) on a 1.4GiB
   NTFS partition, showed the new driver to be 20% faster in total time elapsed
   (from 9:43 minutes on average down to 7:53).  The time spent in user space
@@ -104,6 +108,7 @@ In addition to the generic mount options described by the manual page for the
 mount command (man 8 mount, also see man 5 fstab), the NTFS driver supports the
 following mount options:
 
+======================= =======================================================
 iocharset=name         Deprecated option.  Still supported but please use
                        nls=name in the future.  See description for nls=name.
 
@@ -175,16 +180,22 @@ disable_sparse=<BOOL>     If disable_sparse is specified, creation of sparse
 
 errors=opt             What to do when critical filesystem errors are found.
                        Following values can be used for "opt":
-                         continue: DEFAULT, try to clean-up as much as
+
+                         ========  =========================================
+                         continue  DEFAULT, try to clean-up as much as
                                    possible, e.g. marking a corrupt inode as
                                    bad so it is no longer accessed, and then
                                    continue.
-                         recover:  At present only supported is recovery of
+                         recover   At present only supported is recovery of
                                    the boot sector from the backup copy.
                                    If read-only mount, the recovery is done
                                    in memory only and not written to disk.
-                       Note that the options are additive, i.e. specifying:
+                         ========  =========================================
+
+                       Note that the options are additive, i.e. specifying::
+
                           errors=continue,errors=recover
+
                        means the driver will attempt to recover and if that
                        fails it will clean-up as much as possible and
                        continue.
@@ -202,12 +213,18 @@ mft_zone_multiplier=      Set the MFT zone multiplier for the volume (this
                        In general use the default.  If you have a lot of small
                        files then use a higher value.  The values have the
                        following meaning:
+
+                             =====         =================================
                              Value          MFT zone size (% of volume size)
+                             =====         =================================
                                1               12.5%
                                2               25%
                                3               37.5%
                                4               50%
+                             =====         =================================
+
                        Note this option is irrelevant for read-only mounts.
+======================= =======================================================
 
 
 Known bugs and (mis-)features
@@ -252,18 +269,18 @@ To create the table describing your volume you will need to know each of its
 components and their sizes in sectors, i.e. multiples of 512-byte blocks.
 
 For NT4 fault tolerant volumes you can obtain the sizes using fdisk.  So for
-example if one of your partitions is /dev/hda2 you would do:
+example if one of your partitions is /dev/hda2 you would do::
 
-$ fdisk -ul /dev/hda
+    $ fdisk -ul /dev/hda
 
-Disk /dev/hda: 81.9 GB, 81964302336 bytes
-255 heads, 63 sectors/track, 9964 cylinders, total 160086528 sectors
-Units = sectors of 1 * 512 = 512 bytes
+    Disk /dev/hda: 81.9 GB, 81964302336 bytes
+    255 heads, 63 sectors/track, 9964 cylinders, total 160086528 sectors
+    Units = sectors of 1 * 512 = 512 bytes
 
-   Device Boot      Start         End      Blocks   Id  System
-   /dev/hda1   *          63     4209029     2104483+  83  Linux
-   /dev/hda2         4209030    37768814    16779892+  86  NTFS
-   /dev/hda3        37768815    46170809     4200997+  83  Linux
+       Device Boot      Start         End      Blocks   Id  System
+       /dev/hda1   *          63     4209029     2104483+  83  Linux
+       /dev/hda2         4209030    37768814    16779892+  86  NTFS
+       /dev/hda3        37768815    46170809     4200997+  83  Linux
 
 And you would know that /dev/hda2 has a size of 37768814 - 4209030 + 1 =
 33559785 sectors.
@@ -271,15 +288,17 @@ And you would know that /dev/hda2 has a size of 37768814 - 4209030 + 1 =
 For Win2k and later dynamic disks, you can for example use the ldminfo utility
 which is part of the Linux LDM tools (the latest version at the time of
 writing is linux-ldm-0.0.8.tar.bz2).  You can download it from:
+
        http://www.linux-ntfs.org/
+
 Simply extract the downloaded archive (tar xvjf linux-ldm-0.0.8.tar.bz2), go
 into it (cd linux-ldm-0.0.8) and change to the test directory (cd test).  You
 will find the precompiled (i386) ldminfo utility there.  NOTE: You will not be
 able to compile this yourself easily so use the binary version!
 
-Then you would use ldminfo in dump mode to obtain the necessary information:
+Then you would use ldminfo in dump mode to obtain the necessary information::
 
-$ ./ldminfo --dump /dev/hda
+    $ ./ldminfo --dump /dev/hda
 
 This would dump the LDM database found on /dev/hda which describes all of your
 dynamic disks and all the volumes on them.  At the bottom you will see the
@@ -305,42 +324,36 @@ give you the correct information to do this.
 Assuming you know all your devices and their sizes things are easy.
 
 For a linear raid the table would look like this (note all values are in
-512-byte sectors):
+512-byte sectors)::
 
---- cut here ---
-# Offset into  Size of this    Raid type       Device          Start sector
-# volume       device                                          of device
-0              1028161         linear          /dev/hda1       0
-1028161                3903762         linear          /dev/hdb2       0
-4931923                2103211         linear          /dev/hdc1       0
---- cut here ---
+    # Offset into      Size of this    Raid type       Device          Start sector
+    # volume   device                                          of device
+    0          1028161         linear          /dev/hda1       0
+    1028161            3903762         linear          /dev/hdb2       0
+    4931923            2103211         linear          /dev/hdc1       0
 
 For a striped volume, i.e. raid level 0, you will need to know the chunk size
 you used when creating the volume.  Windows uses 64kiB as the default, so it
 will probably be this unless you changes the defaults when creating the array.
 
 For a raid level 0 the table would look like this (note all values are in
-512-byte sectors):
+512-byte sectors)::
 
---- cut here ---
-# Offset   Size            Raid     Number   Chunk  1st        Start   2nd       Start
-# into     of the   type     of              size   Device     in      Device    in
-# volume   volume           stripes                    device            device
-0         2056320  striped  2        128    /dev/hda1  0       /dev/hdb1 0
---- cut here ---
+    # Offset   Size        Raid     Number   Chunk  1st        Start   2nd       Start
+    # into     of the   type     of          size   Device     in      Device    in
+    # volume   volume       stripes                    device            device
+    0     2056320  striped  2        128    /dev/hda1  0       /dev/hdb1 0
 
 If there are more than two devices, just add each of them to the end of the
 line.
 
 Finally, for a mirrored volume, i.e. raid level 1, the table would look like
-this (note all values are in 512-byte sectors):
+this (note all values are in 512-byte sectors)::
 
---- cut here ---
-# Ofs Size   Raid   Log  Number Region Should Number Source  Start Target Start
-# in  of the type   type of log size   sync?  of     Device  in    Device in
-# vol volume            params              mirrors         Device       Device
-0    2056320 mirror core 2     16     nosync 2    /dev/hda1 0   /dev/hdb1 0
---- cut here ---
+    # Ofs Size   Raid   Log  Number Region Should Number Source  Start Target Start
+    # in  of the type   type of log size   sync?  of     Device  in    Device in
+    # vol volume                params              mirrors         Device       Device
+    0    2056320 mirror core 2 16     nosync 2    /dev/hda1 0   /dev/hdb1 0
 
 If you are mirroring to multiple devices you can specify further targets at the
 end of the line.
@@ -353,17 +366,17 @@ to the "Target Device" or if you specified multiple target devices to all of
 them.
 
 Once you have your table, save it in a file somewhere (e.g. /etc/ntfsvolume1),
-and hand it over to dmsetup to work with, like so:
+and hand it over to dmsetup to work with, like so::
 
-$ dmsetup create myvolume1 /etc/ntfsvolume1
+    $ dmsetup create myvolume1 /etc/ntfsvolume1
 
 You can obviously replace "myvolume1" with whatever name you like.
 
 If it all worked, you will now have the device /dev/device-mapper/myvolume1
 which you can then just use as an argument to the mount command as usual to
-mount the ntfs volume.  For example:
+mount the ntfs volume.  For example::
 
-$ mount -t ntfs -o ro /dev/device-mapper/myvolume1 /mnt/myvol1
+    $ mount -t ntfs -o ro /dev/device-mapper/myvolume1 /mnt/myvol1
 
 (You need to create the directory /mnt/myvol1 first and of course you can use
 anything you like instead of /mnt/myvol1 as long as it is an existing
@@ -395,18 +408,18 @@ Windows by default uses a stripe chunk size of 64k, so you probably want the
 "chunk-size 64k" option for each raid-disk, too.
 
 For example, if you have a stripe set consisting of two partitions /dev/hda5
-and /dev/hdb1 your /etc/raidtab would look like this:
-
-raiddev /dev/md0
-       raid-level      0
-       nr-raid-disks   2
-       nr-spare-disks  0
-       persistent-superblock   0
-       chunk-size      64k
-       device          /dev/hda5
-       raid-disk       0
-       device          /dev/hdb1
-       raid-disk       1
+and /dev/hdb1 your /etc/raidtab would look like this::
+
+    raiddev /dev/md0
+           raid-level  0
+           nr-raid-disks       2
+           nr-spare-disks      0
+           persistent-superblock       0
+           chunk-size  64k
+           device              /dev/hda5
+           raid-disk   0
+           device              /dev/hdb1
+           raid-disk   1
 
 For linear raid, just change the raid-level above to "raid-level linear", for
 mirrors, change it to "raid-level 1", and for stripe sets with parity, change
@@ -427,7 +440,9 @@ Once the raidtab is setup, run for example raid0run -a to start all devices or
 raid0run /dev/md0 to start a particular md device, in this case /dev/md0.
 
 Then just use the mount command as usual to mount the ntfs volume using for
-example:       mount -t ntfs -o ro /dev/md0 /mnt/myntfsvolume
+example::
+
+    mount -t ntfs -o ro /dev/md0 /mnt/myntfsvolume
 
 It is advisable to do the mount read-only to see if the md volume has been
 setup correctly to avoid the possibility of causing damage to the data on the
@@ -1,5 +1,8 @@
-                   OCFS2 online file check
-                   -----------------------
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================================
+OCFS2 file system - online file check
+=====================================
 
 This document will describe OCFS2 online file check feature.
 
@@ -40,7 +43,7 @@ When there are errors in the OCFS2 filesystem, they are usually accompanied
 by the inode number which caused the error. This inode number would be the
 input to check/fix the file.
 
-There is a sysfs directory for each OCFS2 file system mounting:
+There is a sysfs directory for each OCFS2 file system mounting::
 
   /sys/fs/ocfs2/<devname>/filecheck
 
@@ -50,34 +53,36 @@ communicate with kernel space, tell which file(inode number) will be checked or
 fixed. Currently, three operations are supported, which includes checking
 inode, fixing inode and setting the size of result record history.
 
-1. If you want to know what error exactly happened to <inode> before fixing, do
+1. If you want to know what error exactly happened to <inode> before fixing, do::
+
+    # echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/check
+    # cat /sys/fs/ocfs2/<devname>/filecheck/check
+
+The output is like this::
 
-  # echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/check
-  # cat /sys/fs/ocfs2/<devname>/filecheck/check
+    INO                DONE    ERROR
+    39502              1       GENERATION
 
-The output is like this:
-  INO          DONE    ERROR
-39502          1       GENERATION
+    <INO> lists the inode numbers.
+    <DONE> indicates whether the operation has been finished.
+    <ERROR> says what kind of errors was found. For the detailed error numbers,
+    please refer to the file linux/fs/ocfs2/filecheck.h.
 
-<INO> lists the inode numbers.
-<DONE> indicates whether the operation has been finished.
-<ERROR> says what kind of errors was found. For the detailed error numbers,
-please refer to the file linux/fs/ocfs2/filecheck.h.
+2. If you determine to fix this inode, do::
 
-2. If you determine to fix this inode, do
+    # echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/fix
+    # cat /sys/fs/ocfs2/<devname>/filecheck/fix
 
-  # echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/fix
-  # cat /sys/fs/ocfs2/<devname>/filecheck/fix
+The output is like this:::
 
-The output is like this:
-  INO          DONE    ERROR
-39502          1       SUCCESS
+    INO                DONE    ERROR
+    39502              1       SUCCESS
 
 This time, the <ERROR> column indicates whether this fix is successful or not.
 
 3. The record cache is used to store the history of check/fix results. It's
 default size is 10, and can be adjust between the range of 10 ~ 100. You can
-adjust the size like this:
+adjust the size like this::
 
   # echo "<size>" > /sys/fs/ocfs2/<devname>/filecheck/set
 
similarity index 88%
rename from Documentation/filesystems/ocfs2.txt
rename to Documentation/filesystems/ocfs2.rst
index 4c49e54..412386b 100644 (file)
@@ -1,5 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================
 OCFS2 filesystem
-==================
+================
+
 OCFS2 is a general purpose extent based shared disk cluster file
 system with many similarities to ext3. It supports 64 bit inode
 numbers, and has automatically extending metadata groups which may
@@ -14,22 +18,26 @@ OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/
 
 All code copyright 2005 Oracle except when otherwise noted.
 
-CREDITS:
+Credits
+=======
+
 Lots of code taken from ext3 and other projects.
 
 Authors in alphabetical order:
-Joel Becker   <joel.becker@oracle.com>
-Zach Brown    <zach.brown@oracle.com>
-Mark Fasheh   <mfasheh@suse.com>
-Kurt Hackel   <kurt.hackel@oracle.com>
-Tao Ma        <tao.ma@oracle.com>
-Sunil Mushran <sunil.mushran@oracle.com>
-Manish Singh  <manish.singh@oracle.com>
-Tiger Yang    <tiger.yang@oracle.com>
+
+- Joel Becker   <joel.becker@oracle.com>
+- Zach Brown    <zach.brown@oracle.com>
+- Mark Fasheh   <mfasheh@suse.com>
+- Kurt Hackel   <kurt.hackel@oracle.com>
+- Tao Ma        <tao.ma@oracle.com>
+- Sunil Mushran <sunil.mushran@oracle.com>
+- Manish Singh  <manish.singh@oracle.com>
+- Tiger Yang    <tiger.yang@oracle.com>
 
 Caveats
 =======
 Features which OCFS2 does not support yet:
+
        - Directory change notification (F_NOTIFY)
        - Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease)
 
@@ -37,8 +45,10 @@ Mount options
 =============
 
 OCFS2 supports the following mount options:
+
 (*) == default
 
+======================= ========================================================
 barrier=1              This enables/disables barriers. barrier=0 disables it,
                        barrier=1 enables it.
 errors=remount-ro(*)   Remount the filesystem read-only on an error.
@@ -104,3 +114,4 @@ journal_async_commit        Commit block can be written to disk without waiting
                        for descriptor blocks. If enabled older kernels cannot
                        mount the device. This will enable 'journal_checksum'
                        internally.
+======================= ========================================================
diff --git a/Documentation/filesystems/omfs.rst b/Documentation/filesystems/omfs.rst
new file mode 100644 (file)
index 0000000..4c8bb30
--- /dev/null
@@ -0,0 +1,112 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================
+Optimized MPEG Filesystem (OMFS)
+================================
+
+Overview
+========
+
+OMFS is a filesystem created by SonicBlue for use in the ReplayTV DVR
+and Rio Karma MP3 player.  The filesystem is extent-based, utilizing
+block sizes from 2k to 8k, with hash-based directories.  This
+filesystem driver may be used to read and write disks from these
+devices.
+
+Note, it is not recommended that this FS be used in place of a general
+filesystem for your own streaming media device.  Native Linux filesystems
+will likely perform better.
+
+More information is available at:
+
+    http://linux-karma.sf.net/
+
+Various utilities, including mkomfs and omfsck, are included with
+omfsprogs, available at:
+
+    http://bobcopeland.com/karma/
+
+Instructions are included in its README.
+
+Options
+=======
+
+OMFS supports the following mount-time options:
+
+    ============   ========================================
+    uid=n          make all files owned by specified user
+    gid=n          make all files owned by specified group
+    umask=xxx      set permission umask to xxx
+    fmask=xxx      set umask to xxx for files
+    dmask=xxx      set umask to xxx for directories
+    ============   ========================================
+
+Disk format
+===========
+
+OMFS discriminates between "sysblocks" and normal data blocks.  The sysblock
+group consists of super block information, file metadata, directory structures,
+and extents.  Each sysblock has a header containing CRCs of the entire
+sysblock, and may be mirrored in successive blocks on the disk.  A sysblock may
+have a smaller size than a data block, but since they are both addressed by the
+same 64-bit block number, any remaining space in the smaller sysblock is
+unused.
+
+Sysblock header information::
+
+    struct omfs_header {
+           __be64 h_self;                  /* FS block where this is located */
+           __be32 h_body_size;             /* size of useful data after header */
+           __be16 h_crc;                   /* crc-ccitt of body_size bytes */
+           char h_fill1[2];
+           u8 h_version;                   /* version, always 1 */
+           char h_type;                    /* OMFS_INODE_X */
+           u8 h_magic;                     /* OMFS_IMAGIC */
+           u8 h_check_xor;                 /* XOR of header bytes before this */
+           __be32 h_fill2;
+    };
+
+Files and directories are both represented by omfs_inode::
+
+    struct omfs_inode {
+           struct omfs_header i_head;      /* header */
+           __be64 i_parent;                /* parent containing this inode */
+           __be64 i_sibling;               /* next inode in hash bucket */
+           __be64 i_ctime;                 /* ctime, in milliseconds */
+           char i_fill1[35];
+           char i_type;                    /* OMFS_[DIR,FILE] */
+           __be32 i_fill2;
+           char i_fill3[64];
+           char i_name[OMFS_NAMELEN];      /* filename */
+           __be64 i_size;                  /* size of file, in bytes */
+    };
+
+Directories in OMFS are implemented as a large hash table.  Filenames are
+hashed then prepended into the bucket list beginning at OMFS_DIR_START.
+Lookup requires hashing the filename, then seeking across i_sibling pointers
+until a match is found on i_name.  Empty buckets are represented by block
+pointers with all-1s (~0).
+
+A file is an omfs_inode structure followed by an extent table beginning at
+OMFS_EXTENT_START::
+
+    struct omfs_extent_entry {
+           __be64 e_cluster;               /* start location of a set of blocks */
+           __be64 e_blocks;                /* number of blocks after e_cluster */
+    };
+
+    struct omfs_extent {
+           __be64 e_next;                  /* next extent table location */
+           __be32 e_extent_count;          /* total # extents in this table */
+           __be32 e_fill;
+           struct omfs_extent_entry e_entry;       /* start of extent entries */
+    };
+
+Each extent holds the block offset followed by number of blocks allocated to
+the extent.  The final extent in each table is a terminator with e_cluster
+being ~0 and e_blocks being ones'-complement of the total number of blocks
+in the table.
+
+If this table overflows, a continuation inode is written and pointed to by
+e_next.  These have a header but lack the rest of the inode structure.
+
diff --git a/Documentation/filesystems/omfs.txt b/Documentation/filesystems/omfs.txt
deleted file mode 100644 (file)
index 1d0d41f..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-Optimized MPEG Filesystem (OMFS)
-
-Overview
-========
-
-OMFS is a filesystem created by SonicBlue for use in the ReplayTV DVR
-and Rio Karma MP3 player.  The filesystem is extent-based, utilizing
-block sizes from 2k to 8k, with hash-based directories.  This
-filesystem driver may be used to read and write disks from these
-devices.
-
-Note, it is not recommended that this FS be used in place of a general
-filesystem for your own streaming media device.  Native Linux filesystems
-will likely perform better.
-
-More information is available at:
-
-    http://linux-karma.sf.net/
-
-Various utilities, including mkomfs and omfsck, are included with
-omfsprogs, available at:
-
-    http://bobcopeland.com/karma/
-
-Instructions are included in its README.
-
-Options
-=======
-
-OMFS supports the following mount-time options:
-
-    uid=n        - make all files owned by specified user
-    gid=n        - make all files owned by specified group
-    umask=xxx    - set permission umask to xxx
-    fmask=xxx    - set umask to xxx for files
-    dmask=xxx    - set umask to xxx for directories
-
-Disk format
-===========
-
-OMFS discriminates between "sysblocks" and normal data blocks.  The sysblock
-group consists of super block information, file metadata, directory structures,
-and extents.  Each sysblock has a header containing CRCs of the entire
-sysblock, and may be mirrored in successive blocks on the disk.  A sysblock may
-have a smaller size than a data block, but since they are both addressed by the
-same 64-bit block number, any remaining space in the smaller sysblock is
-unused.
-
-Sysblock header information:
-
-struct omfs_header {
-        __be64 h_self;                  /* FS block where this is located */
-        __be32 h_body_size;             /* size of useful data after header */
-        __be16 h_crc;                   /* crc-ccitt of body_size bytes */
-        char h_fill1[2];
-        u8 h_version;                   /* version, always 1 */
-        char h_type;                    /* OMFS_INODE_X */
-        u8 h_magic;                     /* OMFS_IMAGIC */
-        u8 h_check_xor;                 /* XOR of header bytes before this */
-        __be32 h_fill2;
-};
-
-Files and directories are both represented by omfs_inode:
-
-struct omfs_inode {
-        struct omfs_header i_head;      /* header */
-        __be64 i_parent;                /* parent containing this inode */
-        __be64 i_sibling;               /* next inode in hash bucket */
-        __be64 i_ctime;                 /* ctime, in milliseconds */
-        char i_fill1[35];
-        char i_type;                    /* OMFS_[DIR,FILE] */
-        __be32 i_fill2;
-        char i_fill3[64];
-        char i_name[OMFS_NAMELEN];      /* filename */
-        __be64 i_size;                  /* size of file, in bytes */
-};
-
-Directories in OMFS are implemented as a large hash table.  Filenames are
-hashed then prepended into the bucket list beginning at OMFS_DIR_START.
-Lookup requires hashing the filename, then seeking across i_sibling pointers
-until a match is found on i_name.  Empty buckets are represented by block
-pointers with all-1s (~0).
-
-A file is an omfs_inode structure followed by an extent table beginning at
-OMFS_EXTENT_START:
-
-struct omfs_extent_entry {
-        __be64 e_cluster;               /* start location of a set of blocks */
-        __be64 e_blocks;                /* number of blocks after e_cluster */
-};
-
-struct omfs_extent {
-        __be64 e_next;                  /* next extent table location */
-        __be32 e_extent_count;          /* total # extents in this table */
-        __be32 e_fill;
-        struct omfs_extent_entry e_entry;       /* start of extent entries */
-};
-
-Each extent holds the block offset followed by number of blocks allocated to
-the extent.  The final extent in each table is a terminator with e_cluster
-being ~0 and e_blocks being ones'-complement of the total number of blocks
-in the table.
-
-If this table overflows, a continuation inode is written and pointed to by
-e_next.  These have a header but lack the rest of the inode structure.
-
similarity index 83%
rename from Documentation/filesystems/orangefs.txt
rename to Documentation/filesystems/orangefs.rst
index f4ba949..7d6d4ca 100644 (file)
@@ -1,3 +1,6 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========
 ORANGEFS
 ========
 
@@ -21,25 +24,25 @@ Orangefs features include:
   * Stateless
 
 
-MAILING LIST ARCHIVES
+Mailing List Archives
 =====================
 
 http://lists.orangefs.org/pipermail/devel_lists.orangefs.org/
 
 
-MAILING LIST SUBMISSIONS
+Mailing List Submissions
 ========================
 
 devel@lists.orangefs.org
 
 
-DOCUMENTATION
+Documentation
 =============
 
 http://www.orangefs.org/documentation/
 
 
-USERSPACE FILESYSTEM SOURCE
+Userspace Filesystem Source
 ===========================
 
 http://www.orangefs.org/download
@@ -48,16 +51,16 @@ Orangefs versions prior to 2.9.3 would not be compatible with the
 upstream version of the kernel client.
 
 
-RUNNING ORANGEFS ON A SINGLE SERVER
+Running ORANGEFS On a Single Server
 ===================================
 
 OrangeFS is usually run in large installations with multiple servers and
 clients, but a complete filesystem can be run on a single machine for
 development and testing.
 
-On Fedora, install orangefs and orangefs-server.
+On Fedora, install orangefs and orangefs-server::
 
-dnf -y install orangefs orangefs-server
+    dnf -y install orangefs orangefs-server
 
 There is an example server configuration file in
 /etc/orangefs/orangefs.conf.  Change localhost to your hostname if
@@ -70,29 +73,29 @@ single line.  Uncomment it and change the hostname if necessary.  This
 controls clients which use libpvfs2.  This does not control the
 pvfs2-client-core.
 
-Create the filesystem.
+Create the filesystem::
 
-pvfs2-server -f /etc/orangefs/orangefs.conf
+    pvfs2-server -f /etc/orangefs/orangefs.conf
 
-Start the server.
+Start the server::
 
-systemctl start orangefs-server
+    systemctl start orangefs-server
 
-Test the server.
+Test the server::
 
-pvfs2-ping -m /pvfsmnt
+    pvfs2-ping -m /pvfsmnt
 
 Start the client.  The module must be compiled in or loaded before this
-point.
+point::
 
-systemctl start orangefs-client
+    systemctl start orangefs-client
 
-Mount the filesystem.
+Mount the filesystem::
 
-mount -t pvfs2 tcp://localhost:3334/orangefs /pvfsmnt
+    mount -t pvfs2 tcp://localhost:3334/orangefs /pvfsmnt
 
 
-BUILDING ORANGEFS ON A SINGLE SERVER
+Building ORANGEFS on a Single Server
 ====================================
 
 Where OrangeFS cannot be installed from distribution packages, it may be
@@ -102,49 +105,51 @@ You can omit --prefix if you don't care that things are sprinkled around
 in /usr/local.  As of version 2.9.6, OrangeFS uses Berkeley DB by
 default, we will probably be changing the default to LMDB soon.
 
-./configure --prefix=/opt/ofs --with-db-backend=lmdb
+::
 
-make
+    ./configure --prefix=/opt/ofs --with-db-backend=lmdb
 
-make install
+    make
 
-Create an orangefs config file.
+    make install
 
-/opt/ofs/bin/pvfs2-genconfig /etc/pvfs2.conf
+Create an orangefs config file::
 
-Create an /etc/pvfs2tab file.
+    /opt/ofs/bin/pvfs2-genconfig /etc/pvfs2.conf
 
-echo tcp://localhost:3334/orangefs /pvfsmnt pvfs2 defaults,noauto 0 0 > \
-    /etc/pvfs2tab
+Create an /etc/pvfs2tab file::
 
-Create the mount point you specified in the tab file if needed.
+    echo tcp://localhost:3334/orangefs /pvfsmnt pvfs2 defaults,noauto 0 0 > \
+       /etc/pvfs2tab
 
-mkdir /pvfsmnt
+Create the mount point you specified in the tab file if needed::
 
-Bootstrap the server.
+    mkdir /pvfsmnt
 
-/opt/ofs/sbin/pvfs2-server -f /etc/pvfs2.conf
+Bootstrap the server::
 
-Start the server.
+    /opt/ofs/sbin/pvfs2-server -f /etc/pvfs2.conf
 
-/opt/osf/sbin/pvfs2-server /etc/pvfs2.conf
+Start the server::
+
+    /opt/osf/sbin/pvfs2-server /etc/pvfs2.conf
 
 Now the server should be running. Pvfs2-ls is a simple
-test to verify that the server is running.
+test to verify that the server is running::
 
-/opt/ofs/bin/pvfs2-ls /pvfsmnt
+    /opt/ofs/bin/pvfs2-ls /pvfsmnt
 
 If stuff seems to be working, load the kernel module and
-turn on the client core.
+turn on the client core::
 
-/opt/ofs/sbin/pvfs2-client -p /opt/osf/sbin/pvfs2-client-core
+    /opt/ofs/sbin/pvfs2-client -p /opt/osf/sbin/pvfs2-client-core
 
-Mount your filesystem.
+Mount your filesystem::
 
-mount -t pvfs2 tcp://localhost:3334/orangefs /pvfsmnt
+    mount -t pvfs2 tcp://localhost:3334/orangefs /pvfsmnt
 
 
-RUNNING XFSTESTS
+Running xfstests
 ================
 
 It is useful to use a scratch filesystem with xfstests.  This can be
@@ -159,21 +164,23 @@ Then there are two FileSystem sections: orangefs and scratch.
 
 This change should be made before creating the filesystem.
 
-pvfs2-server -f /etc/orangefs/orangefs.conf
+::
+
+    pvfs2-server -f /etc/orangefs/orangefs.conf
 
-To run xfstests, create /etc/xfsqa.config.
+To run xfstests, create /etc/xfsqa.config::
 
-TEST_DIR=/orangefs
-TEST_DEV=tcp://localhost:3334/orangefs
-SCRATCH_MNT=/scratch
-SCRATCH_DEV=tcp://localhost:3334/scratch
+    TEST_DIR=/orangefs
+    TEST_DEV=tcp://localhost:3334/orangefs
+    SCRATCH_MNT=/scratch
+    SCRATCH_DEV=tcp://localhost:3334/scratch
 
-Then xfstests can be run
+Then xfstests can be run::
 
-./check -pvfs2
+    ./check -pvfs2
 
 
-OPTIONS
+Options
 =======
 
 The following mount options are accepted:
@@ -193,32 +200,32 @@ The following mount options are accepted:
     Distributed locking is being worked on for the future.
 
 
-DEBUGGING
+Debugging
 =========
 
 If you want the debug (GOSSIP) statements in a particular
-source file (inode.c for example) go to syslog:
+source file (inode.c for example) go to syslog::
 
   echo inode > /sys/kernel/debug/orangefs/kernel-debug
 
-No debugging (the default):
+No debugging (the default)::
 
   echo none > /sys/kernel/debug/orangefs/kernel-debug
 
-Debugging from several source files:
+Debugging from several source files::
 
   echo inode,dir > /sys/kernel/debug/orangefs/kernel-debug
 
-All debugging:
+All debugging::
 
   echo all > /sys/kernel/debug/orangefs/kernel-debug
 
-Get a list of all debugging keywords:
+Get a list of all debugging keywords::
 
   cat /sys/kernel/debug/orangefs/debug-help
 
 
-PROTOCOL BETWEEN KERNEL MODULE AND USERSPACE
+Protocol between Kernel Module and Userspace
 ============================================
 
 Orangefs is a user space filesystem and an associated kernel module.
@@ -234,7 +241,8 @@ The kernel module implements a pseudo device that userspace
 can read from and write to. Userspace can also manipulate the
 kernel module through the pseudo device with ioctl.
 
-THE BUFMAP:
+The Bufmap
+----------
 
 At startup userspace allocates two page-size-aligned (posix_memalign)
 mlocked memory buffers, one is used for IO and one is used for readdir
@@ -250,7 +258,8 @@ copied from user space to kernel space with copy_from_user and is used
 to initialize the kernel module's "bufmap" (struct orangefs_bufmap), which
 then contains:
 
-  * refcnt - a reference counter
+  * refcnt
+    - a reference counter
   * desc_size - PVFS2_BUFMAP_DEFAULT_DESC_SIZE (4194304) - the IO buffer's
     partition size, which represents the filesystem's block size and
     is used for s_blocksize in super blocks.
@@ -259,17 +268,19 @@ then contains:
   * desc_shift - log2(desc_size), used for s_blocksize_bits in super blocks.
   * total_size - the total size of the IO buffer.
   * page_count - the number of 4096 byte pages in the IO buffer.
-  * page_array - a pointer to page_count * (sizeof(struct page*)) bytes
+  * page_array - a pointer to ``page_count * (sizeof(struct page*))`` bytes
     of kcalloced memory. This memory is used as an array of pointers
     to each of the pages in the IO buffer through a call to get_user_pages.
-  * desc_array - a pointer to desc_count * (sizeof(struct orangefs_bufmap_desc))
+  * desc_array - a pointer to ``desc_count * (sizeof(struct orangefs_bufmap_desc))``
     bytes of kcalloced memory. This memory is further intialized:
 
       user_desc is the kernel's copy of the IO buffer's ORANGEFS_dev_map_desc
       structure. user_desc->ptr points to the IO buffer.
 
-      pages_per_desc = bufmap->desc_size / PAGE_SIZE
-      offset = 0
+      ::
+
+       pages_per_desc = bufmap->desc_size / PAGE_SIZE
+       offset = 0
 
         bufmap->desc_array[0].page_array = &bufmap->page_array[offset]
         bufmap->desc_array[0].array_count = pages_per_desc = 1024
@@ -293,7 +304,8 @@ then contains:
   * readdir_index_lock - a spinlock to protect readdir_index_array during
     update.
 
-OPERATIONS:
+Operations
+----------
 
 The kernel module builds an "op" (struct orangefs_kernel_op_s) when it
 needs to communicate with userspace. Part of the op contains the "upcall"
@@ -308,13 +320,19 @@ in flight at any given time.
 
 Ops are stateful:
 
- * unknown  - op was just initialized
- * waiting  - op is on request_list (upward bound)
- * inprogr  - op is in progress (waiting for downcall)
- * serviced - op has matching downcall; ok
- * purged   - op has to start a timer since client-core
+ * unknown
+           - op was just initialized
+ * waiting
+           - op is on request_list (upward bound)
+ * inprogr
+           - op is in progress (waiting for downcall)
+ * serviced
+           - op has matching downcall; ok
+ * purged
+           - op has to start a timer since client-core
               exited uncleanly before servicing op
- * given up - submitter has given up waiting for it
+ * given up
+           - submitter has given up waiting for it
 
 When some arbitrary userspace program needs to perform a
 filesystem operation on Orangefs (readdir, I/O, create, whatever)
@@ -389,10 +407,15 @@ union of structs, each of which is associated with a particular
 response type.
 
 The several members outside of the union are:
- - int32_t type - type of operation.
- - int32_t status - return code for the operation.
- - int64_t trailer_size - 0 unless readdir operation.
- - char *trailer_buf - initialized to NULL, used during readdir operations.
+
+ ``int32_t type``
+    - type of operation.
+ ``int32_t status``
+    - return code for the operation.
+ ``int64_t trailer_size``
+    - 0 unless readdir operation.
+ ``char *trailer_buf``
+    - initialized to NULL, used during readdir operations.
 
 The appropriate member inside the union is filled out for any
 particular response.
@@ -449,18 +472,20 @@ Userspace uses writev() on /dev/pvfs2-req to pass responses to the requests
 made by the kernel side.
 
 A buffer_list containing:
+
   - a pointer to the prepared response to the request from the
     kernel (struct pvfs2_downcall_t).
   - and also, in the case of a readdir request, a pointer to a
     buffer containing descriptors for the objects in the target
     directory.
+
 ... is sent to the function (PINT_dev_write_list) which performs
 the writev.
 
 PINT_dev_write_list has a local iovec array: struct iovec io_array[10];
 
 The first four elements of io_array are initialized like this for all
-responses:
+responses::
 
   io_array[0].iov_base = address of local variable "proto_ver" (int32_t)
   io_array[0].iov_len = sizeof(int32_t)
@@ -475,7 +500,7 @@ responses:
                          of global variable vfs_request (vfs_request_t)
   io_array[3].iov_len = sizeof(pvfs2_downcall_t)
 
-Readdir responses initialize the fifth element io_array like this:
+Readdir responses initialize the fifth element io_array like this::
 
   io_array[4].iov_base = contents of member trailer_buf (char *)
                          from out_downcall member of global variable
@@ -517,13 +542,13 @@ from a dentry is cheap, obtaining it from userspace is relatively expensive,
 hence the motivation to use the dentry when possible.
 
 The timeout values d_time and getattr_time are jiffy based, and the
-code is designed to avoid the jiffy-wrap problem:
+code is designed to avoid the jiffy-wrap problem::
 
-"In general, if the clock may have wrapped around more than once, there
-is no way to tell how much time has elapsed. However, if the times t1
-and t2 are known to be fairly close, we can reliably compute the
-difference in a way that takes into account the possibility that the
-clock may have wrapped between times."
+    "In general, if the clock may have wrapped around more than once, there
+    is no way to tell how much time has elapsed. However, if the times t1
+    and t2 are known to be fairly close, we can reliably compute the
+    difference in a way that takes into account the possibility that the
+    clock may have wrapped between times."
 
-                      from course notes by instructor Andy Wang
+from course notes by instructor Andy Wang
 
index f185060..26c0939 100644 (file)
@@ -850,3 +850,11 @@ business doing so.
 d_alloc_pseudo() is internal-only; uses outside of alloc_file_pseudo() are
 very suspect (and won't work in modules).  Such uses are very likely to
 be misspelled d_alloc_anon().
+
+---
+
+**mandatory**
+
+[should've been added in 2016] stale comment in finish_open() nonwithstanding,
+failure exits in ->atomic_open() instances should *NOT* fput() the file,
+no matter what.  Everything is handled by the caller.
similarity index 65%
rename from Documentation/filesystems/proc.txt
rename to Documentation/filesystems/proc.rst
index 99ca040..38b6069 100644 (file)
@@ -1,19 +1,20 @@
-------------------------------------------------------------------------------
-                       T H E  /proc   F I L E S Y S T E M
-------------------------------------------------------------------------------
-/proc/sys         Terrehon Bowden <terrehon@pacbell.net>        October 7 1999
-                  Bodo Bauer <bb@ricochet.net>
+.. SPDX-License-Identifier: GPL-2.0
+
+====================
+The /proc Filesystem
+====================
+
+=====================  =======================================  ================
+/proc/sys              Terrehon Bowden <terrehon@pacbell.net>,  October 7 1999
+                       Bodo Bauer <bb@ricochet.net>
+2.4.x update          Jorge Nerin <comandante@zaralinux.com>   November 14 2000
+move /proc/sys        Shen Feng <shen@cn.fujitsu.com>          April 1 2009
+fixes/update part 1.1  Stefani Seibold <stefani@seibold.net>    June 9 2009
+=====================  =======================================  ================
+
 
-2.4.x update     Jorge Nerin <comandante@zaralinux.com>      November 14 2000
-move /proc/sys   Shen Feng <shen@cn.fujitsu.com>                 April 1 2009
-------------------------------------------------------------------------------
-Version 1.3                                              Kernel version 2.2.12
-                                             Kernel version 2.4.0-test11-pre4
-------------------------------------------------------------------------------
-fixes/update part 1.1  Stefani Seibold <stefani@seibold.net>       June 9 2009
 
-Table of Contents
------------------
+.. Table of Contents
 
   0     Preface
   0.1  Introduction/Credits
@@ -50,9 +51,8 @@ Table of Contents
   4    Configuring procfs
   4.1  Mount options
 
-------------------------------------------------------------------------------
 Preface
-------------------------------------------------------------------------------
+=======
 
 0.1 Introduction/Credits
 ------------------------
@@ -95,20 +95,18 @@ We don't  guarantee  the  correctness  of this document, and if you come to us
 complaining about  how  you  screwed  up  your  system  because  of  incorrect
 documentation, we won't feel responsible...
 
-------------------------------------------------------------------------------
-CHAPTER 1: COLLECTING SYSTEM INFORMATION
-------------------------------------------------------------------------------
+Chapter 1: Collecting System Information
+========================================
 
-------------------------------------------------------------------------------
 In This Chapter
-------------------------------------------------------------------------------
+---------------
 * Investigating  the  properties  of  the  pseudo  file  system  /proc and its
   ability to provide information on the running Linux system
 * Examining /proc's structure
 * Uncovering  various  information  about the kernel and the processes running
   on the system
-------------------------------------------------------------------------------
 
+------------------------------------------------------------------------------
 
 The proc  file  system acts as an interface to internal data structures in the
 kernel. It  can  be  used to obtain information about the system and to change
@@ -134,9 +132,11 @@ never act on any new process that the kernel may, through chance, have
 also assigned the process ID <pid>. Instead, operations on these FDs
 usually fail with ESRCH.
 
-Table 1-1: Process specific entries in /proc
-..............................................................................
+.. table:: Table 1-1: Process specific entries in /proc
+
+ =============  ===============================================================
  File          Content
+ =============  ===============================================================
  clear_refs    Clears page referenced bits shown in smaps output
  cmdline       Command line arguments
  cpu           Current and last cpu in which it was executed   (2.4)(smp)
@@ -160,10 +160,10 @@ Table 1-1: Process specific entries in /proc
                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.
-..............................................................................
+ =============  ===============================================================
 
 For example, to get the status information of a process, all you have to do is
-read the file /proc/PID/status:
+read the file /proc/PID/status::
 
   >cat /proc/self/status
   Name:   cat
@@ -222,14 +222,17 @@ contains details information about the process itself.  Its fields are
 explained in Table 1-4.
 
 (for SMP CONFIG users)
+
 For making accounting scalable, RSS related information are handled in an
 asynchronous manner and the value may not be very precise. To see a precise
 snapshot of a moment, you can see /proc/<pid>/smaps file and scan page table.
 It's slow but very precise.
 
-Table 1-2: Contents of the status files (as of 4.19)
-..............................................................................
+.. table:: Table 1-2: Contents of the status files (as of 4.19)
+
+ ==========================  ===================================================
  Field                       Content
+ ==========================  ===================================================
  Name                        filename of the executable
  Umask                       file mode creation mask
  State                       state (R is running, S is sleeping, D is sleeping
@@ -254,7 +257,8 @@ Table 1-2: Contents of the status files (as of 4.19)
  VmPin                       pinned memory size
  VmHWM                       peak resident set size ("high water mark")
  VmRSS                       size of memory portions. It contains the three
-                             following parts (VmRSS = RssAnon + RssFile + RssShmem)
+                             following parts
+                             (VmRSS = RssAnon + RssFile + RssShmem)
  RssAnon                     size of resident anonymous memory
  RssFile                     size of resident file mappings
  RssShmem                    size of resident shmem memory (includes SysV shm,
@@ -292,27 +296,32 @@ Table 1-2: Contents of the status files (as of 4.19)
  Mems_allowed_list           Same as previous, but in "list format"
  voluntary_ctxt_switches     number of voluntary context switches
  nonvoluntary_ctxt_switches  number of non voluntary context switches
-..............................................................................
+ ==========================  ===================================================
 
-Table 1-3: Contents of the statm files (as of 2.6.8-rc3)
-..............................................................................
+
+.. table:: Table 1-3: Contents of the statm files (as of 2.6.8-rc3)
+
+ ======== ===============================      ==============================
  Field    Content
+ ======== ===============================      ==============================
  size     total program size (pages)           (same as VmSize in status)
  resident size of memory portions (pages)      (same as VmRSS in status)
  shared   number of pages that are shared      (i.e. backed by a file, same
                                                as RssFile+RssShmem in status)
  trs      number of pages that are 'code'      (not including libs; broken,
-                                                       includes data segment)
+                                               includes data segment)
  lrs      number of pages of library           (always 0 on 2.6)
  drs      number of pages of data/stack                (including libs; broken,
-                                                       includes library text)
+                                               includes library text)
  dt       number of dirty pages                        (always 0 on 2.6)
-..............................................................................
+ ======== ===============================      ==============================
+
 
+.. table:: Table 1-4: Contents of the stat files (as of 2.6.30-rc7)
 
-Table 1-4: Contents of the stat files (as of 2.6.30-rc7)
-..............................................................................
- Field          Content
+  ============= ===============================================================
+  Field         Content
+  ============= ===============================================================
   pid           process id
   tcomm         filename of the executable
   state         state (R is running, S is sleeping, D is sleeping in an
@@ -348,7 +357,8 @@ Table 1-4: Contents of the stat files (as of 2.6.30-rc7)
   blocked       bitmap of blocked signals
   sigign        bitmap of ignored signals
   sigcatch      bitmap of caught signals
-  0            (place holder, used to be the wchan address, use /proc/PID/wchan instead)
+  0            (place holder, used to be the wchan address,
+               use /proc/PID/wchan instead)
   0             (place holder)
   0             (place holder)
   exit_signal   signal to send to parent thread on exit
@@ -365,39 +375,40 @@ Table 1-4: Contents of the stat files (as of 2.6.30-rc7)
   arg_end       address below which program command line is placed
   env_start     address above which program environment is placed
   env_end       address below which program environment is placed
-  exit_code     the thread's exit_code in the form reported by the waitpid system call
-..............................................................................
+  exit_code     the thread's exit_code in the form reported by the waitpid
+               system call
+  ============= ===============================================================
 
 The /proc/PID/maps file contains the currently mapped memory regions and
 their access permissions.
 
-The format is:
-
-address           perms offset  dev   inode      pathname
-
-08048000-08049000 r-xp 00000000 03:00 8312       /opt/test
-08049000-0804a000 rw-p 00001000 03:00 8312       /opt/test
-0804a000-0806b000 rw-p 00000000 00:00 0          [heap]
-a7cb1000-a7cb2000 ---p 00000000 00:00 0
-a7cb2000-a7eb2000 rw-p 00000000 00:00 0
-a7eb2000-a7eb3000 ---p 00000000 00:00 0
-a7eb3000-a7ed5000 rw-p 00000000 00:00 0
-a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
-a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
-a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
-a800b000-a800e000 rw-p 00000000 00:00 0
-a800e000-a8022000 r-xp 00000000 03:00 14462      /lib/libpthread.so.0
-a8022000-a8023000 r--p 00013000 03:00 14462      /lib/libpthread.so.0
-a8023000-a8024000 rw-p 00014000 03:00 14462      /lib/libpthread.so.0
-a8024000-a8027000 rw-p 00000000 00:00 0
-a8027000-a8043000 r-xp 00000000 03:00 8317       /lib/ld-linux.so.2
-a8043000-a8044000 r--p 0001b000 03:00 8317       /lib/ld-linux.so.2
-a8044000-a8045000 rw-p 0001c000 03:00 8317       /lib/ld-linux.so.2
-aff35000-aff4a000 rw-p 00000000 00:00 0          [stack]
-ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
+The format is::
+
+    address           perms offset  dev   inode      pathname
+
+    08048000-08049000 r-xp 00000000 03:00 8312       /opt/test
+    08049000-0804a000 rw-p 00001000 03:00 8312       /opt/test
+    0804a000-0806b000 rw-p 00000000 00:00 0          [heap]
+    a7cb1000-a7cb2000 ---p 00000000 00:00 0
+    a7cb2000-a7eb2000 rw-p 00000000 00:00 0
+    a7eb2000-a7eb3000 ---p 00000000 00:00 0
+    a7eb3000-a7ed5000 rw-p 00000000 00:00 0
+    a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
+    a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
+    a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
+    a800b000-a800e000 rw-p 00000000 00:00 0
+    a800e000-a8022000 r-xp 00000000 03:00 14462      /lib/libpthread.so.0
+    a8022000-a8023000 r--p 00013000 03:00 14462      /lib/libpthread.so.0
+    a8023000-a8024000 rw-p 00014000 03:00 14462      /lib/libpthread.so.0
+    a8024000-a8027000 rw-p 00000000 00:00 0
+    a8027000-a8043000 r-xp 00000000 03:00 8317       /lib/ld-linux.so.2
+    a8043000-a8044000 r--p 0001b000 03:00 8317       /lib/ld-linux.so.2
+    a8044000-a8045000 rw-p 0001c000 03:00 8317       /lib/ld-linux.so.2
+    aff35000-aff4a000 rw-p 00000000 00:00 0          [stack]
+    ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]
 
 where "address" is the address space in the process that it occupies, "perms"
-is a set of permissions:
+is a set of permissions::
 
  r = read
  w = write
@@ -411,42 +422,44 @@ with the memory region, as the case would be with BSS (uninitialized data).
 The "pathname" shows the name associated file for this mapping.  If the mapping
 is not associated with a file:
 
- [heap]                   = the heap of the program
- [stack]                  = the stack of the main process
- [vdso]                   = the "virtual dynamic shared object",
+ =======                    ====================================
+ [heap]                     the heap of the program
+ [stack]                    the stack of the main process
+ [vdso]                     the "virtual dynamic shared object",
                             the kernel system call handler
+ =======                    ====================================
 
  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 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
-Shared_Dirty:          0 kB
-Private_Clean:         0 kB
-Private_Dirty:         0 kB
-Referenced:          892 kB
-Anonymous:             0 kB
-LazyFree:              0 kB
-AnonHugePages:         0 kB
-ShmemPmdMapped:        0 kB
-Shared_Hugetlb:        0 kB
-Private_Hugetlb:       0 kB
-Swap:                  0 kB
-SwapPss:               0 kB
-KernelPageSize:        4 kB
-MMUPageSize:           4 kB
-Locked:                0 kB
-THPeligible:           0
-VmFlags: rd ex mr mw me dw
+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
+    Shared_Dirty:          0 kB
+    Private_Clean:         0 kB
+    Private_Dirty:         0 kB
+    Referenced:          892 kB
+    Anonymous:             0 kB
+    LazyFree:              0 kB
+    AnonHugePages:         0 kB
+    ShmemPmdMapped:        0 kB
+    Shared_Hugetlb:        0 kB
+    Private_Hugetlb:       0 kB
+    Swap:                  0 kB
+    SwapPss:               0 kB
+    KernelPageSize:        4 kB
+    MMUPageSize:           4 kB
+    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.  Following lines show the size of the mapping
@@ -461,26 +474,35 @@ 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.
 So if a process has 1000 pages all to itself, and 1000 shared with one other
 process, its PSS will be 1500.
+
 Note that even a page which is part of a MAP_SHARED mapping, but has only
 a single pte mapped, i.e.  is currently used by only one process, is accounted
 as private and not as shared.
+
 "Referenced" indicates the amount of memory currently marked as referenced or
 accessed.
+
 "Anonymous" shows the amount of memory that does not belong to any file.  Even
 a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE
 and a page is modified, the file page is replaced by a private anonymous copy.
+
 "LazyFree" shows the amount of memory which is marked by madvise(MADV_FREE).
 The memory isn't freed immediately with madvise(). It's freed in memory
 pressure if the memory is clean. Please note that the printed value might
 be lower than the real value due to optimizations used in the current
 implementation. If this is not desirable please file a bug report.
+
 "AnonHugePages" shows the ammount of memory backed by transparent hugepage.
+
 "ShmemPmdMapped" shows the ammount of shared (shmem/tmpfs) memory backed by
 huge pages.
+
 "Shared_Hugetlb" and "Private_Hugetlb" show the ammounts of memory backed by
 hugetlbfs page which is *not* counted in "RSS" or "PSS" field for historical
 reasons. And these are not included in {Shared,Private}_{Clean,Dirty} field.
+
 "Swap" shows how much would-be-anonymous memory is also used, but out on swap.
+
 For shmem mappings, "Swap" includes also the size of the mapped (and not
 replaced by copy-on-write) part of the underlying shmem object out on swap.
 "SwapPss" shows proportional swap share of this mapping. Unlike "Swap", this
@@ -489,36 +511,39 @@ does not take into account swapped out page of underlying shmem objects.
 "THPeligible" indicates whether the mapping is eligible for allocating THP
 pages - 1 if true, 0 otherwise. It just shows the current status.
 
-"VmFlags" field deserves a separate description. This member represents the kernel
-flags associated with the particular virtual memory area in two letter encoded
-manner. The codes are the following:
-    rd  - readable
-    wr  - writeable
-    ex  - executable
-    sh  - shared
-    mr  - may read
-    mw  - may write
-    me  - may execute
-    ms  - may share
-    gd  - stack segment growns down
-    pf  - pure PFN range
-    dw  - disabled write to the mapped file
-    lo  - pages are locked in memory
-    io  - memory mapped I/O area
-    sr  - sequential read advise provided
-    rr  - random read advise provided
-    dc  - do not copy area on fork
-    de  - do not expand area on remapping
-    ac  - area is accountable
-    nr  - swap space is not reserved for the area
-    ht  - area uses huge tlb pages
-    ar  - architecture specific flag
-    dd  - do not include area into core dump
-    sd  - soft-dirty flag
-    mm  - mixed map area
-    hg  - huge page advise flag
-    nh  - no-huge page advise flag
-    mg  - mergable advise flag
+"VmFlags" field deserves a separate description. This member represents the
+kernel flags associated with the particular virtual memory area in two letter
+encoded manner. The codes are the following:
+
+    ==    =======================================
+    rd    readable
+    wr    writeable
+    ex    executable
+    sh    shared
+    mr    may read
+    mw    may write
+    me    may execute
+    ms    may share
+    gd    stack segment growns down
+    pf    pure PFN range
+    dw    disabled write to the mapped file
+    lo    pages are locked in memory
+    io    memory mapped I/O area
+    sr    sequential read advise provided
+    rr    random read advise provided
+    dc    do not copy area on fork
+    de    do not expand area on remapping
+    ac    area is accountable
+    nr    swap space is not reserved for the area
+    ht    area uses huge tlb pages
+    ar    architecture specific flag
+    dd    do not include area into core dump
+    sd    soft dirty flag
+    mm    mixed map area
+    hg    huge page advise flag
+    nh    no huge page advise flag
+    mg    mergable advise flag
+    ==    =======================================
 
 Note that there is no guarantee that every flag and associated mnemonic will
 be present in all further kernel releases. Things get changed, the flags may
@@ -531,6 +556,7 @@ enabled.
 
 Note: reading /proc/PID/maps or /proc/PID/smaps is inherently racy (consistent
 output can be achieved only in the single read call).
+
 This typically manifests when doing partial reads of these files while the
 memory map is being modified.  Despite the races, we do provide the following
 guarantees:
@@ -544,9 +570,9 @@ 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
+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
@@ -558,20 +584,25 @@ The /proc/PID/clear_refs is used to reset the PG_Referenced and ACCESSED/YOUNG
 bits on both physical and virtual pages associated with a process, and the
 soft-dirty bit on pte (see Documentation/admin-guide/mm/soft-dirty.rst
 for details).
-To clear the bits for all the pages associated with the process
+To clear the bits for all the pages associated with the process::
+
     > echo 1 > /proc/PID/clear_refs
 
-To clear the bits for the anonymous pages associated with the process
+To clear the bits for the anonymous pages associated with the process::
+
     > echo 2 > /proc/PID/clear_refs
 
-To clear the bits for the file mapped pages associated with the process
+To clear the bits for the file mapped pages associated with the process::
+
     > echo 3 > /proc/PID/clear_refs
 
-To clear the soft-dirty bit
+To clear the soft-dirty bit::
+
     > echo 4 > /proc/PID/clear_refs
 
 To reset the peak resident set size ("high water mark") to the process's
-current value:
+current value::
+
     > echo 5 > /proc/PID/clear_refs
 
 Any other value written to /proc/PID/clear_refs will have no effect.
@@ -584,30 +615,33 @@ Documentation/admin-guide/mm/pagemap.rst.
 The /proc/pid/numa_maps is an extension based on maps, showing the memory
 locality and binding policy, as well as the memory usage (in pages) of
 each mapping. The output follows a general format where mapping details get
-summarized separated by blank spaces, one mapping per each file line:
-
-address   policy    mapping details
-
-00400000 default file=/usr/local/bin/app mapped=1 active=0 N3=1 kernelpagesize_kB=4
-00600000 default file=/usr/local/bin/app anon=1 dirty=1 N3=1 kernelpagesize_kB=4
-3206000000 default file=/lib64/ld-2.12.so mapped=26 mapmax=6 N0=24 N3=2 kernelpagesize_kB=4
-320621f000 default file=/lib64/ld-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
-3206220000 default file=/lib64/ld-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
-3206221000 default anon=1 dirty=1 N3=1 kernelpagesize_kB=4
-3206800000 default file=/lib64/libc-2.12.so mapped=59 mapmax=21 active=55 N0=41 N3=18 kernelpagesize_kB=4
-320698b000 default file=/lib64/libc-2.12.so
-3206b8a000 default file=/lib64/libc-2.12.so anon=2 dirty=2 N3=2 kernelpagesize_kB=4
-3206b8e000 default file=/lib64/libc-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
-3206b8f000 default anon=3 dirty=3 active=1 N3=3 kernelpagesize_kB=4
-7f4dc10a2000 default anon=3 dirty=3 N3=3 kernelpagesize_kB=4
-7f4dc10b4000 default anon=2 dirty=2 active=1 N3=2 kernelpagesize_kB=4
-7f4dc1200000 default file=/anon_hugepage\040(deleted) huge anon=1 dirty=1 N3=1 kernelpagesize_kB=2048
-7fff335f0000 default stack anon=3 dirty=3 N3=3 kernelpagesize_kB=4
-7fff3369d000 default mapped=1 mapmax=35 active=0 N3=1 kernelpagesize_kB=4
+summarized separated by blank spaces, one mapping per each file line::
+
+    address   policy    mapping details
+
+    00400000 default file=/usr/local/bin/app mapped=1 active=0 N3=1 kernelpagesize_kB=4
+    00600000 default file=/usr/local/bin/app anon=1 dirty=1 N3=1 kernelpagesize_kB=4
+    3206000000 default file=/lib64/ld-2.12.so mapped=26 mapmax=6 N0=24 N3=2 kernelpagesize_kB=4
+    320621f000 default file=/lib64/ld-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
+    3206220000 default file=/lib64/ld-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
+    3206221000 default anon=1 dirty=1 N3=1 kernelpagesize_kB=4
+    3206800000 default file=/lib64/libc-2.12.so mapped=59 mapmax=21 active=55 N0=41 N3=18 kernelpagesize_kB=4
+    320698b000 default file=/lib64/libc-2.12.so
+    3206b8a000 default file=/lib64/libc-2.12.so anon=2 dirty=2 N3=2 kernelpagesize_kB=4
+    3206b8e000 default file=/lib64/libc-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
+    3206b8f000 default anon=3 dirty=3 active=1 N3=3 kernelpagesize_kB=4
+    7f4dc10a2000 default anon=3 dirty=3 N3=3 kernelpagesize_kB=4
+    7f4dc10b4000 default anon=2 dirty=2 active=1 N3=2 kernelpagesize_kB=4
+    7f4dc1200000 default file=/anon_hugepage\040(deleted) huge anon=1 dirty=1 N3=1 kernelpagesize_kB=2048
+    7fff335f0000 default stack anon=3 dirty=3 N3=3 kernelpagesize_kB=4
+    7fff3369d000 default mapped=1 mapmax=35 active=0 N3=1 kernelpagesize_kB=4
 
 Where:
+
 "address" is the starting address for the mapping;
+
 "policy" reports the NUMA memory policy set for the mapping (see Documentation/admin-guide/mm/numa_memory_policy.rst);
+
 "mapping details" summarizes mapping data such as mapping type, page usage counters,
 node locality page counters (N0 == node0, N1 == node1, ...) and the kernel page
 size, in KB, that is backing the mapping up.
@@ -621,81 +655,83 @@ the running kernel. The files used to obtain this information are contained in
 system. It  depends  on the kernel configuration and the loaded modules, which
 files are there, and which are missing.
 
-Table 1-5: Kernel info in /proc
-..............................................................................
- File        Content                                           
- apm         Advanced power management info                    
- buddyinfo   Kernel memory allocator information (see text)    (2.5)
- bus         Directory containing bus specific information     
- cmdline     Kernel command line                               
- cpuinfo     Info about the CPU                                
- devices     Available devices (block and character)           
- dma         Used DMS channels                                 
- filesystems Supported filesystems                             
- driver             Various drivers grouped here, currently rtc (2.4)
- execdomains Execdomains, related to security                  (2.4)
- fb         Frame Buffer devices                               (2.4)
- fs         File system parameters, currently nfs/exports      (2.4)
- ide         Directory containing info about the IDE subsystem 
- interrupts  Interrupt usage                                   
- iomem      Memory map                                         (2.4)
- ioports     I/O port usage                                    
- irq        Masks for irq to cpu affinity                      (2.4)(smp?)
- isapnp             ISA PnP (Plug&Play) Info                           (2.4)
- kcore       Kernel core image (can be ELF or A.OUT(deprecated in 2.4))   
- kmsg        Kernel messages                                   
- ksyms       Kernel symbol table                               
- loadavg     Load average of last 1, 5 & 15 minutes                
- locks       Kernel locks                                      
- meminfo     Memory info                                       
- misc        Miscellaneous                                     
- modules     List of loaded modules                            
- mounts      Mounted filesystems                               
- net         Networking info (see text)                        
+.. table:: Table 1-5: Kernel info in /proc
+
+ ============ ===============================================================
+ File         Content
+ ============ ===============================================================
+ apm          Advanced power management info
+ buddyinfo    Kernel memory allocator information (see text)   (2.5)
+ bus          Directory containing bus specific information
+ cmdline      Kernel command line
+ cpuinfo      Info about the CPU
+ devices      Available devices (block and character)
+ dma          Used DMS channels
+ filesystems  Supported filesystems
+ driver       Various drivers grouped here, currently rtc      (2.4)
+ execdomains  Execdomains, related to security                 (2.4)
+ fb          Frame Buffer devices                              (2.4)
+ fs          File system parameters, currently nfs/exports     (2.4)
+ ide          Directory containing info about the IDE subsystem
+ interrupts   Interrupt usage
+ iomem               Memory map                                        (2.4)
+ ioports      I/O port usage
+ irq         Masks for irq to cpu affinity                     (2.4)(smp?)
+ isapnp       ISA PnP (Plug&Play) Info                         (2.4)
+ kcore        Kernel core image (can be ELF or A.OUT(deprecated in 2.4))
+ kmsg         Kernel messages
+ ksyms        Kernel symbol table
+ loadavg      Load average of last 1, 5 & 15 minutes
+ locks        Kernel locks
+ meminfo      Memory info
+ misc         Miscellaneous
+ modules      List of loaded modules
+ mounts       Mounted filesystems
+ net          Networking info (see text)
  pagetypeinfo Additional page allocator information (see text)  (2.5)
- partitions  Table of partitions known to the system           
- pci        Deprecated info of PCI bus (new way -> /proc/bus/pci/,
-             decoupled by lspci                                        (2.4)
- rtc         Real time clock                                   
- scsi        SCSI info (see text)                              
- slabinfo    Slab pool info                                    
- softirqs    softirq usage
- stat        Overall statistics                                
- swaps       Swap space utilization                            
- sys         See chapter 2                                     
- sysvipc     Info of SysVIPC Resources (msg, sem, shm)         (2.4)
- tty        Info of tty drivers
- uptime      Wall clock since boot, combined idle time of all cpus
- version     Kernel version                                    
- video      bttv info of video resources                       (2.4)
- vmallocinfo Show vmalloced areas
-..............................................................................
+ partitions   Table of partitions known to the system
+ pci         Deprecated info of PCI bus (new way -> /proc/bus/pci/,
+              decoupled by lspci                               (2.4)
+ rtc          Real time clock
+ scsi         SCSI info (see text)
+ slabinfo     Slab pool info
+ softirqs     softirq usage
+ stat         Overall statistics
+ swaps        Swap space utilization
+ sys          See chapter 2
+ sysvipc      Info of SysVIPC Resources (msg, sem, shm)                (2.4)
+ tty         Info of tty drivers
+ uptime       Wall clock since boot, combined idle time of all cpus
+ version      Kernel version
+ video               bttv info of video resources                      (2.4)
+ vmallocinfo  Show vmalloced areas
+ ============ ===============================================================
 
 You can,  for  example,  check  which interrupts are currently in use and what
-they are used for by looking in the file /proc/interrupts:
-
-  > cat /proc/interrupts 
-             CPU0        
-    0:    8728810          XT-PIC  timer 
-    1:        895          XT-PIC  keyboard 
-    2:          0          XT-PIC  cascade 
-    3:     531695          XT-PIC  aha152x 
-    4:    2014133          XT-PIC  serial 
-    5:      44401          XT-PIC  pcnet_cs 
-    8:          2          XT-PIC  rtc 
-   11:          8          XT-PIC  i82365 
-   12:     182918          XT-PIC  PS/2 Mouse 
-   13:          1          XT-PIC  fpu 
-   14:    1232265          XT-PIC  ide0 
-   15:          7          XT-PIC  ide1 
-  NMI:          0 
+they are used for by looking in the file /proc/interrupts::
+
+  > cat /proc/interrupts
+             CPU0
+    0:    8728810          XT-PIC  timer
+    1:        895          XT-PIC  keyboard
+    2:          0          XT-PIC  cascade
+    3:     531695          XT-PIC  aha152x
+    4:    2014133          XT-PIC  serial
+    5:      44401          XT-PIC  pcnet_cs
+    8:          2          XT-PIC  rtc
+   11:          8          XT-PIC  i82365
+   12:     182918          XT-PIC  PS/2 Mouse
+   13:          1          XT-PIC  fpu
+   14:    1232265          XT-PIC  ide0
+   15:          7          XT-PIC  ide1
+  NMI:          0
 
 In 2.4.* a couple of lines where added to this file LOC & ERR (this time is the
-output of a SMP machine):
+output of a SMP machine)::
 
-  > cat /proc/interrupts 
+  > cat /proc/interrupts
 
-             CPU0       CPU1       
+             CPU0       CPU1
     0:    1243498    1214548    IO-APIC-edge  timer
     1:       8949       8958    IO-APIC-edge  keyboard
     2:          0          0          XT-PIC  cascade
@@ -708,8 +744,8 @@ output of a SMP machine):
    15:       2183       2415    IO-APIC-edge  ide1
    17:      30564      30414   IO-APIC-level  eth0
    18:        177        164   IO-APIC-level  bttv
-  NMI:    2457961    2457959 
-  LOC:    2457882    2457881 
+  NMI:    2457961    2457959
+  LOC:    2457882    2457881
   ERR:       2155
 
 NMI is incremented in this case because every timer interrupt generates a NMI
@@ -726,21 +762,25 @@ In 2.6.2* /proc/interrupts was expanded again.  This time the goal was for
 /proc/interrupts to display every IRQ vector in use by the system, not
 just those considered 'most important'.  The new vectors are:
 
-  THR -- interrupt raised when a machine check threshold counter
+THR
+  interrupt raised when a machine check threshold counter
   (typically counting ECC corrected errors of memory or cache) exceeds
   a configurable threshold.  Only available on some systems.
 
-  TRM -- a thermal event interrupt occurs when a temperature threshold
+TRM
+  a thermal event interrupt occurs when a temperature threshold
   has been exceeded for the CPU.  This interrupt may also be generated
   when the temperature drops back to normal.
 
-  SPU -- a spurious interrupt is some interrupt that was raised then lowered
+SPU
+  a spurious interrupt is some interrupt that was raised then lowered
   by some IO device before it could be fully processed by the APIC.  Hence
   the APIC sees the interrupt but does not know what device it came from.
   For this case the APIC will generate the interrupt with a IRQ vector
   of 0xff. This might also be generated by chipset bugs.
 
-  RES, CAL, TLB -- rescheduling, call and TLB flush interrupts are
+RES, CAL, TLB]
+  rescheduling, call and TLB flush interrupts are
   sent from one CPU to another per the needs of the OS.  Typically,
   their statistics are used by kernel developers and interested users to
   determine the occurrence of interrupts of the given type.
@@ -756,7 +796,8 @@ IRQ to only one CPU, or to exclude a CPU of handling IRQs. The contents of the
 irq subdir is one subdir for each IRQ, and two files; default_smp_affinity and
 prof_cpu_mask.
 
-For example 
+For example::
+
   > ls /proc/irq/
   0  10  12  14  16  18  2  4  6  8  prof_cpu_mask
   1  11  13  15  17  19  3  5  7  9  default_smp_affinity
@@ -764,20 +805,20 @@ For example
   smp_affinity
 
 smp_affinity is a bitmask, in which you can specify which CPUs can handle the
-IRQ, you can set it by doing:
+IRQ, you can set it by doing::
 
   > echo 1 > /proc/irq/10/smp_affinity
 
 This means that only the first CPU will handle the IRQ, but you can also echo
 5 which means that only the first and third CPU can handle the IRQ.
 
-The contents of each smp_affinity file is the same by default:
+The contents of each smp_affinity file is the same by default::
 
   > cat /proc/irq/0/smp_affinity
   ffffffff
 
 There is an alternate interface, smp_affinity_list which allows specifying
-a cpu range instead of a bitmask:
+a cpu range instead of a bitmask::
 
   > cat /proc/irq/0/smp_affinity_list
   1024-1031
@@ -810,46 +851,46 @@ Linux uses  slab  pools for memory management above page level in version 2.2.
 Commonly used  objects  have  their  own  slab  pool (such as network buffers,
 directory cache, and so on).
 
-..............................................................................
+::
 
-> cat /proc/buddyinfo
+    > cat /proc/buddyinfo
 
-Node 0, zone      DMA      0      4      5      4      4      3 ...
-Node 0, zone   Normal      1      0      0      1    101      8 ...
-Node 0, zone  HighMem      2      0      0      1      1      0 ...
+    Node 0, zone      DMA      0      4      5      4      4      3 ...
+    Node 0, zone   Normal      1      0      0      1    101      8 ...
+    Node 0, zone  HighMem      2      0      0      1      1      0 ...
 
 External fragmentation is a problem under some workloads, and buddyinfo is a
-useful tool for helping diagnose these problems.  Buddyinfo will give you a 
+useful tool for helping diagnose these problems.  Buddyinfo will give you a
 clue as to how big an area you can safely allocate, or why a previous
 allocation failed.
 
-Each column represents the number of pages of a certain order which are 
-available.  In this case, there are 0 chunks of 2^0*PAGE_SIZE available in 
-ZONE_DMA, 4 chunks of 2^1*PAGE_SIZE in ZONE_DMA, 101 chunks of 2^4*PAGE_SIZE 
-available in ZONE_NORMAL, etc... 
+Each column represents the number of pages of a certain order which are
+available.  In this case, there are 0 chunks of 2^0*PAGE_SIZE available in
+ZONE_DMA, 4 chunks of 2^1*PAGE_SIZE in ZONE_DMA, 101 chunks of 2^4*PAGE_SIZE
+available in ZONE_NORMAL, etc...
 
 More information relevant to external fragmentation can be found in
-pagetypeinfo.
-
-> cat /proc/pagetypeinfo
-Page block order: 9
-Pages per block:  512
-
-Free pages count per migrate type at order       0      1      2      3      4      5      6      7      8      9     10
-Node    0, zone      DMA, type    Unmovable      0      0      0      1      1      1      1      1      1      1      0
-Node    0, zone      DMA, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0
-Node    0, zone      DMA, type      Movable      1      1      2      1      2      1      1      0      1      0      2
-Node    0, zone      DMA, type      Reserve      0      0      0      0      0      0      0      0      0      1      0
-Node    0, zone      DMA, type      Isolate      0      0      0      0      0      0      0      0      0      0      0
-Node    0, zone    DMA32, type    Unmovable    103     54     77      1      1      1     11      8      7      1      9
-Node    0, zone    DMA32, type  Reclaimable      0      0      2      1      0      0      0      0      1      0      0
-Node    0, zone    DMA32, type      Movable    169    152    113     91     77     54     39     13      6      1    452
-Node    0, zone    DMA32, type      Reserve      1      2      2      2      2      0      1      1      1      1      0
-Node    0, zone    DMA32, type      Isolate      0      0      0      0      0      0      0      0      0      0      0
-
-Number of blocks type     Unmovable  Reclaimable      Movable      Reserve      Isolate
-Node 0, zone      DMA            2            0            5            1            0
-Node 0, zone    DMA32           41            6          967            2            0
+pagetypeinfo::
+
+    > cat /proc/pagetypeinfo
+    Page block order: 9
+    Pages per block:  512
+
+    Free pages count per migrate type at order       0      1      2      3      4      5      6      7      8      9     10
+    Node    0, zone      DMA, type    Unmovable      0      0      0      1      1      1      1      1      1      1      0
+    Node    0, zone      DMA, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0
+    Node    0, zone      DMA, type      Movable      1      1      2      1      2      1      1      0      1      0      2
+    Node    0, zone      DMA, type      Reserve      0      0      0      0      0      0      0      0      0      1      0
+    Node    0, zone      DMA, type      Isolate      0      0      0      0      0      0      0      0      0      0      0
+    Node    0, zone    DMA32, type    Unmovable    103     54     77      1      1      1     11      8      7      1      9
+    Node    0, zone    DMA32, type  Reclaimable      0      0      2      1      0      0      0      0      1      0      0
+    Node    0, zone    DMA32, type      Movable    169    152    113     91     77     54     39     13      6      1    452
+    Node    0, zone    DMA32, type      Reserve      1      2      2      2      2      0      1      1      1      1      0
+    Node    0, zone    DMA32, type      Isolate      0      0      0      0      0      0      0      0      0      0      0
+
+    Number of blocks type     Unmovable  Reclaimable      Movable      Reserve      Isolate
+    Node 0, zone      DMA            2            0            5            1            0
+    Node 0, zone    DMA32           41            6          967            2            0
 
 Fragmentation avoidance in the kernel works by grouping pages of different
 migrate types into the same contiguous regions of memory called page blocks.
@@ -870,59 +911,63 @@ unless memory has been mlock()'d. Some of the Reclaimable blocks should
 also be allocatable although a lot of filesystem metadata may have to be
 reclaimed to achieve this.
 
-..............................................................................
 
-meminfo:
+meminfo
+~~~~~~~
 
 Provides information about distribution and utilization of memory.  This
 varies by architecture and compile options.  The following is from a
 16GB PIII, which has highmem enabled.  You may not have all of these fields.
 
-> cat /proc/meminfo
-
-MemTotal:     16344972 kB
-MemFree:      13634064 kB
-MemAvailable: 14836172 kB
-Buffers:          3656 kB
-Cached:        1195708 kB
-SwapCached:          0 kB
-Active:         891636 kB
-Inactive:      1077224 kB
-HighTotal:    15597528 kB
-HighFree:     13629632 kB
-LowTotal:       747444 kB
-LowFree:          4432 kB
-SwapTotal:           0 kB
-SwapFree:            0 kB
-Dirty:             968 kB
-Writeback:           0 kB
-AnonPages:      861800 kB
-Mapped:         280372 kB
-Shmem:             644 kB
-KReclaimable:   168048 kB
-Slab:           284364 kB
-SReclaimable:   159856 kB
-SUnreclaim:     124508 kB
-PageTables:      24448 kB
-NFS_Unstable:        0 kB
-Bounce:              0 kB
-WritebackTmp:        0 kB
-CommitLimit:   7669796 kB
-Committed_AS:   100056 kB
-VmallocTotal:   112216 kB
-VmallocUsed:       428 kB
-VmallocChunk:   111088 kB
-Percpu:          62080 kB
-HardwareCorrupted:   0 kB
-AnonHugePages:   49152 kB
-ShmemHugePages:      0 kB
-ShmemPmdMapped:      0 kB
-
-
-    MemTotal: Total usable ram (i.e. physical ram minus a few reserved
+::
+
+    > cat /proc/meminfo
+
+    MemTotal:     16344972 kB
+    MemFree:      13634064 kB
+    MemAvailable: 14836172 kB
+    Buffers:          3656 kB
+    Cached:        1195708 kB
+    SwapCached:          0 kB
+    Active:         891636 kB
+    Inactive:      1077224 kB
+    HighTotal:    15597528 kB
+    HighFree:     13629632 kB
+    LowTotal:       747444 kB
+    LowFree:          4432 kB
+    SwapTotal:           0 kB
+    SwapFree:            0 kB
+    Dirty:             968 kB
+    Writeback:           0 kB
+    AnonPages:      861800 kB
+    Mapped:         280372 kB
+    Shmem:             644 kB
+    KReclaimable:   168048 kB
+    Slab:           284364 kB
+    SReclaimable:   159856 kB
+    SUnreclaim:     124508 kB
+    PageTables:      24448 kB
+    NFS_Unstable:        0 kB
+    Bounce:              0 kB
+    WritebackTmp:        0 kB
+    CommitLimit:   7669796 kB
+    Committed_AS:   100056 kB
+    VmallocTotal:   112216 kB
+    VmallocUsed:       428 kB
+    VmallocChunk:   111088 kB
+    Percpu:          62080 kB
+    HardwareCorrupted:   0 kB
+    AnonHugePages:   49152 kB
+    ShmemHugePages:      0 kB
+    ShmemPmdMapped:      0 kB
+
+MemTotal
+              Total usable ram (i.e. physical ram minus a few reserved
               bits and the kernel binary code)
-     MemFree: The sum of LowFree+HighFree
-MemAvailable: An estimate of how much memory is available for starting new
+MemFree
+              The sum of LowFree+HighFree
+MemAvailable
+              An estimate of how much memory is available for starting new
               applications, without swapping. Calculated from MemFree,
               SReclaimable, the size of the file LRU lists, and the low
               watermarks in each zone.
@@ -930,69 +975,99 @@ MemAvailable: An estimate of how much memory is available for starting new
               page cache to function well, and that not all reclaimable
               slab will be reclaimable, due to items being in use. The
               impact of those factors will vary from system to system.
-     Buffers: Relatively temporary storage for raw disk blocks
+Buffers
+              Relatively temporary storage for raw disk blocks
               shouldn't get tremendously large (20MB or so)
-      Cached: in-memory cache for files read from the disk (the
+Cached
+              in-memory cache for files read from the disk (the
               pagecache).  Doesn't include SwapCached
-  SwapCached: Memory that once was swapped out, is swapped back in but
+SwapCached
+              Memory that once was swapped out, is swapped back in but
               still also is in the swapfile (if memory is needed it
               doesn't need to be swapped out AGAIN because it is already
               in the swapfile. This saves I/O)
-      Active: Memory that has been used more recently and usually not
+Active
+              Memory that has been used more recently and usually not
               reclaimed unless absolutely necessary.
-    Inactive: Memory which has been less recently used.  It is more
+Inactive
+              Memory which has been less recently used.  It is more
               eligible to be reclaimed for other purposes
-   HighTotal:
-    HighFree: Highmem is all memory above ~860MB of physical memory
+HighTotal, HighFree
+              Highmem is all memory above ~860MB of physical memory
               Highmem areas are for use by userspace programs, or
               for the pagecache.  The kernel must use tricks to access
               this memory, making it slower to access than lowmem.
-    LowTotal:
-     LowFree: Lowmem is memory which can be used for everything that
+LowTotal, LowFree
+              Lowmem is memory which can be used for everything that
               highmem can be used for, but it is also available for the
               kernel's use for its own data structures.  Among many
               other things, it is where everything from the Slab is
               allocated.  Bad things happen when you're out of lowmem.
-   SwapTotal: total amount of swap space available
-    SwapFree: Memory which has been evicted from RAM, and is temporarily
+SwapTotal
+              total amount of swap space available
+SwapFree
+              Memory which has been evicted from RAM, and is temporarily
               on the disk
-       Dirty: Memory which is waiting to get written back to the disk
-   Writeback: Memory which is actively being written back to the disk
-   AnonPages: Non-file backed pages mapped into userspace page tables
-HardwareCorrupted: The amount of RAM/memory in KB, the kernel identifies as
+Dirty
+              Memory which is waiting to get written back to the disk
+Writeback
+              Memory which is actively being written back to the disk
+AnonPages
+              Non-file backed pages mapped into userspace page tables
+HardwareCorrupted
+              The amount of RAM/memory in KB, the kernel identifies as
              corrupted.
-AnonHugePages: Non-file backed huge pages mapped into userspace page tables
-      Mapped: files which have been mmaped, such as libraries
-       Shmem: Total memory used by shared memory (shmem) and tmpfs
-ShmemHugePages: Memory used by shared memory (shmem) and tmpfs allocated
+AnonHugePages
+              Non-file backed huge pages mapped into userspace page tables
+Mapped
+              files which have been mmaped, such as libraries
+Shmem
+              Total memory used by shared memory (shmem) and tmpfs
+ShmemHugePages
+              Memory used by shared memory (shmem) and tmpfs allocated
               with huge pages
-ShmemPmdMapped: Shared memory mapped into userspace with huge pages
-KReclaimable: Kernel allocations that the kernel will attempt to reclaim
+ShmemPmdMapped
+              Shared memory mapped into userspace with huge pages
+KReclaimable
+              Kernel allocations that the kernel will attempt to reclaim
               under memory pressure. Includes SReclaimable (below), and other
               direct allocations with a shrinker.
-        Slab: in-kernel data structures cache
-SReclaimable: Part of Slab, that might be reclaimed, such as caches
-  SUnreclaim: Part of Slab, that cannot be reclaimed on memory pressure
-  PageTables: amount of memory dedicated to the lowest level of page
+Slab
+              in-kernel data structures cache
+SReclaimable
+              Part of Slab, that might be reclaimed, such as caches
+SUnreclaim
+              Part of Slab, that cannot be reclaimed on memory pressure
+PageTables
+              amount of memory dedicated to the lowest level of page
               tables.
-NFS_Unstable: NFS pages sent to the server, but not yet committed to stable
+NFS_Unstable
+              NFS pages sent to the server, but not yet committed to stable
              storage
-      Bounce: Memory used for block device "bounce buffers"
-WritebackTmp: Memory used by FUSE for temporary writeback buffers
- CommitLimit: Based on the overcommit ratio ('vm.overcommit_ratio'),
+Bounce
+              Memory used for block device "bounce buffers"
+WritebackTmp
+              Memory used by FUSE for temporary writeback buffers
+CommitLimit
+              Based on the overcommit ratio ('vm.overcommit_ratio'),
               this is the total amount of  memory currently available to
               be allocated on the system. This limit is only adhered to
               if strict overcommit accounting is enabled (mode 2 in
               'vm.overcommit_memory').
-              The CommitLimit is calculated with the following formula:
-              CommitLimit = ([total RAM pages] - [total huge TLB pages]) *
-                             overcommit_ratio / 100 + [total swap pages]
+
+              The CommitLimit is calculated with the following formula::
+
+                CommitLimit = ([total RAM pages] - [total huge TLB pages]) *
+                               overcommit_ratio / 100 + [total swap pages]
+
               For example, on a system with 1G of physical RAM and 7G
               of swap with a `vm.overcommit_ratio` of 30 it would
               yield a CommitLimit of 7.3G.
+
               For more details, see the memory overcommit documentation
               in vm/overcommit-accounting.
-Committed_AS: The amount of memory presently allocated on the system.
+Committed_AS
+              The amount of memory presently allocated on the system.
               The committed memory is a sum of all of the memory which
               has been allocated by processes, even if it has not been
               "used" by them as of yet. A process which malloc()'s 1G
@@ -1005,21 +1080,25 @@ Committed_AS: The amount of memory presently allocated on the system.
               This is useful if one needs to guarantee that processes will
               not fail due to lack of memory once that memory has been
               successfully allocated.
-VmallocTotal: total size of vmalloc memory area
- VmallocUsed: amount of vmalloc area which is used
-VmallocChunk: largest contiguous block of vmalloc area which is free
-      Percpu: Memory allocated to the percpu allocator used to back percpu
+VmallocTotal
+              total size of vmalloc memory area
+VmallocUsed
+              amount of vmalloc area which is used
+VmallocChunk
+              largest contiguous block of vmalloc area which is free
+Percpu
+              Memory allocated to the percpu allocator used to back percpu
               allocations. This stat excludes the cost of metadata.
 
-..............................................................................
-
-vmallocinfo:
+vmallocinfo
+~~~~~~~~~~~
 
 Provides information about vmalloced/vmaped areas. One line per area,
 containing the virtual address range of the area, size in bytes,
 caller information of the creator, and optional information depending
 on the kind of area :
 
+ ==========  ===================================================
  pages=nr    number of pages
  phys=addr   if a physical address was specified
  ioremap     I/O mapping (ioremap() and friends)
@@ -1029,49 +1108,54 @@ on the kind of area :
  vpages      buffer for pages pointers was vmalloced (huge area)
  N<node>=nr  (Only on NUMA kernels)
              Number of pages allocated on memory node <node>
-
-> cat /proc/vmallocinfo
-0xffffc20000000000-0xffffc20000201000 2101248 alloc_large_system_hash+0x204 ...
-  /0x2c0 pages=512 vmalloc N0=128 N1=128 N2=128 N3=128
-0xffffc20000201000-0xffffc20000302000 1052672 alloc_large_system_hash+0x204 ...
-  /0x2c0 pages=256 vmalloc N0=64 N1=64 N2=64 N3=64
-0xffffc20000302000-0xffffc20000304000    8192 acpi_tb_verify_table+0x21/0x4f...
-  phys=7fee8000 ioremap
-0xffffc20000304000-0xffffc20000307000   12288 acpi_tb_verify_table+0x21/0x4f...
-  phys=7fee7000 ioremap
-0xffffc2000031d000-0xffffc2000031f000    8192 init_vdso_vars+0x112/0x210
-0xffffc2000031f000-0xffffc2000032b000   49152 cramfs_uncompress_init+0x2e ...
-  /0x80 pages=11 vmalloc N0=3 N1=3 N2=2 N3=3
-0xffffc2000033a000-0xffffc2000033d000   12288 sys_swapon+0x640/0xac0      ...
-  pages=2 vmalloc N1=2
-0xffffc20000347000-0xffffc2000034c000   20480 xt_alloc_table_info+0xfe ...
-  /0x130 [x_tables] pages=4 vmalloc N0=4
-0xffffffffa0000000-0xffffffffa000f000   61440 sys_init_module+0xc27/0x1d00 ...
-   pages=14 vmalloc N2=14
-0xffffffffa000f000-0xffffffffa0014000   20480 sys_init_module+0xc27/0x1d00 ...
-   pages=4 vmalloc N1=4
-0xffffffffa0014000-0xffffffffa0017000   12288 sys_init_module+0xc27/0x1d00 ...
-   pages=2 vmalloc N1=2
-0xffffffffa0017000-0xffffffffa0022000   45056 sys_init_module+0xc27/0x1d00 ...
-   pages=10 vmalloc N0=10
-
-..............................................................................
-
-softirqs:
+ ==========  ===================================================
+
+::
+
+    > cat /proc/vmallocinfo
+    0xffffc20000000000-0xffffc20000201000 2101248 alloc_large_system_hash+0x204 ...
+    /0x2c0 pages=512 vmalloc N0=128 N1=128 N2=128 N3=128
+    0xffffc20000201000-0xffffc20000302000 1052672 alloc_large_system_hash+0x204 ...
+    /0x2c0 pages=256 vmalloc N0=64 N1=64 N2=64 N3=64
+    0xffffc20000302000-0xffffc20000304000    8192 acpi_tb_verify_table+0x21/0x4f...
+    phys=7fee8000 ioremap
+    0xffffc20000304000-0xffffc20000307000   12288 acpi_tb_verify_table+0x21/0x4f...
+    phys=7fee7000 ioremap
+    0xffffc2000031d000-0xffffc2000031f000    8192 init_vdso_vars+0x112/0x210
+    0xffffc2000031f000-0xffffc2000032b000   49152 cramfs_uncompress_init+0x2e ...
+    /0x80 pages=11 vmalloc N0=3 N1=3 N2=2 N3=3
+    0xffffc2000033a000-0xffffc2000033d000   12288 sys_swapon+0x640/0xac0      ...
+    pages=2 vmalloc N1=2
+    0xffffc20000347000-0xffffc2000034c000   20480 xt_alloc_table_info+0xfe ...
+    /0x130 [x_tables] pages=4 vmalloc N0=4
+    0xffffffffa0000000-0xffffffffa000f000   61440 sys_init_module+0xc27/0x1d00 ...
+    pages=14 vmalloc N2=14
+    0xffffffffa000f000-0xffffffffa0014000   20480 sys_init_module+0xc27/0x1d00 ...
+    pages=4 vmalloc N1=4
+    0xffffffffa0014000-0xffffffffa0017000   12288 sys_init_module+0xc27/0x1d00 ...
+    pages=2 vmalloc N1=2
+    0xffffffffa0017000-0xffffffffa0022000   45056 sys_init_module+0xc27/0x1d00 ...
+    pages=10 vmalloc N0=10
+
+
+softirqs
+~~~~~~~~
 
 Provides counts of softirq handlers serviced since boot time, for each cpu.
 
-> cat /proc/softirqs
-                CPU0       CPU1       CPU2       CPU3
-      HI:          0          0          0          0
-   TIMER:      27166      27120      27097      27034
-  NET_TX:          0          0          0         17
-  NET_RX:         42          0          0         39
-   BLOCK:          0          0        107       1121
- TASKLET:          0          0          0        290
-   SCHED:      27035      26983      26971      26746
- HRTIMER:          0          0          0          0
-     RCU:       1678       1769       2178       2250
+::
+
+    > cat /proc/softirqs
+                   CPU0       CPU1       CPU2       CPU3
+       HI:          0          0          0          0
+    TIMER:      27166      27120      27097      27034
+    NET_TX:          0          0          0         17
+    NET_RX:         42          0          0         39
+    BLOCK:          0          0        107       1121
+    TASKLET:          0          0          0        290
+    SCHED:      27035      26983      26971      26746
+    HRTIMER:          0          0          0          0
+       RCU:       1678       1769       2178       2250
 
 
 1.3 IDE devices in /proc/ide
@@ -1083,7 +1167,7 @@ file drivers  and a link for each IDE device, pointing to the device directory
 in the controller specific subtree.
 
 The file  drivers  contains general information about the drivers used for the
-IDE devices:
+IDE devices::
 
   > cat /proc/ide/drivers
   ide-cdrom version 4.53
@@ -1094,57 +1178,61 @@ subdirectories. These  are  named  ide0,  ide1  and  so  on.  Each  of  these
 directories contains the files shown in table 1-6.
 
 
-Table 1-6: IDE controller info in  /proc/ide/ide?
-..............................................................................
- File    Content                                 
- channel IDE channel (0 or 1)                    
- config  Configuration (only for PCI/IDE bridge) 
- mate    Mate name                               
- model   Type/Chipset of IDE controller          
-..............................................................................
+.. table:: Table 1-6: IDE controller info in  /proc/ide/ide?
+
+ ======= =======================================
+ File    Content
+ ======= =======================================
+ channel IDE channel (0 or 1)
+ config  Configuration (only for PCI/IDE bridge)
+ mate    Mate name
+ model   Type/Chipset of IDE controller
+ ======= =======================================
 
 Each device  connected  to  a  controller  has  a separate subdirectory in the
 controllers directory.  The  files  listed in table 1-7 are contained in these
 directories.
 
 
-Table 1-7: IDE device information
-..............................................................................
- File             Content                                    
- cache            The cache                                  
- capacity         Capacity of the medium (in 512Byte blocks) 
- driver           driver and version                         
- geometry         physical and logical geometry              
- identify         device identify block                      
- media            media type                                 
- model            device identifier                          
- settings         device setup                               
- smart_thresholds IDE disk management thresholds             
- smart_values     IDE disk management values                 
-..............................................................................
-
-The most  interesting  file is settings. This file contains a nice overview of
-the drive parameters:
-
-  # cat /proc/ide/ide0/hda/settings 
-  name                    value           min             max             mode 
-  ----                    -----           ---             ---             ---- 
-  bios_cyl                526             0               65535           rw 
-  bios_head               255             0               255             rw 
-  bios_sect               63              0               63              rw 
-  breada_readahead        4               0               127             rw 
-  bswap                   0               0               1               r 
-  file_readahead          72              0               2097151         rw 
-  io_32bit                0               0               3               rw 
-  keepsettings            0               0               1               rw 
-  max_kb_per_request      122             1               127             rw 
-  multcount               0               0               8               rw 
-  nice1                   1               0               1               rw 
-  nowerr                  0               0               1               rw 
-  pio_mode                write-only      0               255             w 
-  slow                    0               0               1               rw 
-  unmaskirq               0               0               1               rw 
-  using_dma               0               0               1               rw 
+.. table:: Table 1-7: IDE device information
+
+ ================ ==========================================
+ File             Content
+ ================ ==========================================
+ cache            The cache
+ capacity         Capacity of the medium (in 512Byte blocks)
+ driver           driver and version
+ geometry         physical and logical geometry
+ identify         device identify block
+ media            media type
+ model            device identifier
+ settings         device setup
+ smart_thresholds IDE disk management thresholds
+ smart_values     IDE disk management values
+ ================ ==========================================
+
+The most  interesting  file is ``settings``. This file contains a nice
+overview of the drive parameters::
+
+  # cat /proc/ide/ide0/hda/settings
+  name                    value           min             max             mode
+  ----                    -----           ---             ---             ----
+  bios_cyl                526             0               65535           rw
+  bios_head               255             0               255             rw
+  bios_sect               63              0               63              rw
+  breada_readahead        4               0               127             rw
+  bswap                   0               0               1               r
+  file_readahead          72              0               2097151         rw
+  io_32bit                0               0               3               rw
+  keepsettings            0               0               1               rw
+  max_kb_per_request      122             1               127             rw
+  multcount               0               0               8               rw
+  nice1                   1               0               1               rw
+  nowerr                  0               0               1               rw
+  pio_mode                write-only      0               255             w
+  slow                    0               0               1               rw
+  unmaskirq               0               0               1               rw
+  using_dma               0               0               1               rw
 
 
 1.4 Networking info in /proc/net
@@ -1155,67 +1243,70 @@ additional values  you  get  for  IP  version 6 if you configure the kernel to
 support this. Table 1-9 lists the files and their meaning.
 
 
-Table 1-8: IPv6 info in /proc/net
-..............................................................................
- File       Content                                               
- udp6       UDP sockets (IPv6)                                    
- tcp6       TCP sockets (IPv6)                                    
- raw6       Raw device statistics (IPv6)                          
- igmp6      IP multicast addresses, which this host joined (IPv6) 
- if_inet6   List of IPv6 interface addresses                      
- ipv6_route Kernel routing table for IPv6                         
- rt6_stats  Global IPv6 routing tables statistics                 
- sockstat6  Socket statistics (IPv6)                              
- snmp6      Snmp data (IPv6)                                      
-..............................................................................
-
-
-Table 1-9: Network info in /proc/net
-..............................................................................
- File          Content                                                         
- arp           Kernel  ARP table                                               
- dev           network devices with statistics                                 
+.. table:: Table 1-8: IPv6 info in /proc/net
+
+ ========== =====================================================
+ File       Content
+ ========== =====================================================
+ udp6       UDP sockets (IPv6)
+ tcp6       TCP sockets (IPv6)
+ raw6       Raw device statistics (IPv6)
+ igmp6      IP multicast addresses, which this host joined (IPv6)
+ if_inet6   List of IPv6 interface addresses
+ ipv6_route Kernel routing table for IPv6
+ rt6_stats  Global IPv6 routing tables statistics
+ sockstat6  Socket statistics (IPv6)
+ snmp6      Snmp data (IPv6)
+ ========== =====================================================
+
+.. table:: Table 1-9: Network info in /proc/net
+
+ ============= ================================================================
+ File          Content
+ ============= ================================================================
+ arp           Kernel  ARP table
+ dev           network devices with statistics
  dev_mcast     the Layer2 multicast groups a device is listening too
                (interface index, label, number of references, number of bound
-               addresses). 
- dev_stat      network device status                                           
- ip_fwchains   Firewall chain linkage                                          
- ip_fwnames    Firewall chain names                                            
- ip_masq       Directory containing the masquerading tables                    
- ip_masquerade Major masquerading table                                        
- netstat       Network statistics                                              
- raw           raw device statistics                                           
- route         Kernel routing table                                            
- rpc           Directory containing rpc info                                   
- rt_cache      Routing cache                                                   
- snmp          SNMP data                                                       
- sockstat      Socket statistics                                               
- tcp           TCP  sockets                                                    
- udp           UDP sockets                                                     
- unix          UNIX domain sockets                                             
- wireless      Wireless interface data (Wavelan etc)                           
- igmp          IP multicast addresses, which this host joined                  
- psched        Global packet scheduler parameters.                             
- netlink       List of PF_NETLINK sockets                                      
- ip_mr_vifs    List of multicast virtual interfaces                            
- ip_mr_cache   List of multicast routing cache                                 
-..............................................................................
+               addresses).
+ dev_stat      network device status
+ ip_fwchains   Firewall chain linkage
+ ip_fwnames    Firewall chain names
+ ip_masq       Directory containing the masquerading tables
+ ip_masquerade Major masquerading table
+ netstat       Network statistics
+ raw           raw device statistics
+ route         Kernel routing table
+ rpc           Directory containing rpc info
+ rt_cache      Routing cache
+ snmp          SNMP data
+ sockstat      Socket statistics
+ tcp           TCP  sockets
+ udp           UDP sockets
+ unix          UNIX domain sockets
+ wireless      Wireless interface data (Wavelan etc)
+ igmp          IP multicast addresses, which this host joined
+ psched        Global packet scheduler parameters.
+ netlink       List of PF_NETLINK sockets
+ ip_mr_vifs    List of multicast virtual interfaces
+ ip_mr_cache   List of multicast routing cache
+ ============= ================================================================
 
 You can  use  this  information  to see which network devices are available in
-your system and how much traffic was routed over those devices:
-
-  > cat /proc/net/dev 
-  Inter-|Receive                                                   |[... 
-   face |bytes    packets errs drop fifo frame compressed multicast|[... 
-      lo:  908188   5596     0    0    0     0          0         0 [...         
-    ppp0:15475140  20721   410    0    0   410          0         0 [...  
-    eth0:  614530   7085     0    0    0     0          0         1 [... 
-   
-  ...] Transmit 
-  ...] bytes    packets errs drop fifo colls carrier compressed 
-  ...]  908188     5596    0    0    0     0       0          0 
-  ...] 1375103    17405    0    0    0     0       0          0 
-  ...] 1703981     5535    0    0    0     3       0          0 
+your system and how much traffic was routed over those devices::
+
+  > cat /proc/net/dev
+  Inter-|Receive                                                   |[...
+   face |bytes    packets errs drop fifo frame compressed multicast|[...
+      lo:  908188   5596     0    0    0     0          0         0 [...
+    ppp0:15475140  20721   410    0    0   410          0         0 [...
+    eth0:  614530   7085     0    0    0     0          0         1 [...
+
+  ...] Transmit
+  ...] bytes    packets errs drop fifo colls carrier compressed
+  ...]  908188     5596    0    0    0     0       0          0
+  ...] 1375103    17405    0    0    0     0       0          0
+  ...] 1703981     5535    0    0    0     3       0          0
 
 In addition, each Channel Bond interface has its own directory.  For
 example, the bond0 device will have a directory called /proc/net/bond0/.
@@ -1228,62 +1319,62 @@ many times the slaves link has failed.
 
 If you  have  a  SCSI  host adapter in your system, you'll find a subdirectory
 named after  the driver for this adapter in /proc/scsi. You'll also see a list
-of all recognized SCSI devices in /proc/scsi:
+of all recognized SCSI devices in /proc/scsi::
 
-  >cat /proc/scsi/scsi 
-  Attached devices: 
-  Host: scsi0 Channel: 00 Id: 00 Lun: 00 
-    Vendor: IBM      Model: DGHS09U          Rev: 03E0 
-    Type:   Direct-Access                    ANSI SCSI revision: 03 
-  Host: scsi0 Channel: 00 Id: 06 Lun: 00 
-    Vendor: PIONEER  Model: CD-ROM DR-U06S   Rev: 1.04 
-    Type:   CD-ROM                           ANSI SCSI revision: 02 
+  >cat /proc/scsi/scsi
+  Attached devices:
+  Host: scsi0 Channel: 00 Id: 00 Lun: 00
+    Vendor: IBM      Model: DGHS09U          Rev: 03E0
+    Type:   Direct-Access                    ANSI SCSI revision: 03
+  Host: scsi0 Channel: 00 Id: 06 Lun: 00
+    Vendor: PIONEER  Model: CD-ROM DR-U06S   Rev: 1.04
+    Type:   CD-ROM                           ANSI SCSI revision: 02
 
 
 The directory  named  after  the driver has one file for each adapter found in
 the system.  These  files  contain information about the controller, including
 the used  IRQ  and  the  IO  address range. The amount of information shown is
 dependent on  the adapter you use. The example shows the output for an Adaptec
-AHA-2940 SCSI adapter:
-
-  > cat /proc/scsi/aic7xxx/0 
-   
-  Adaptec AIC7xxx driver version: 5.1.19/3.2.4 
-  Compile Options: 
-    TCQ Enabled By Default : Disabled 
-    AIC7XXX_PROC_STATS     : Disabled 
-    AIC7XXX_RESET_DELAY    : 5 
-  Adapter Configuration: 
-             SCSI Adapter: Adaptec AHA-294X Ultra SCSI host adapter 
-                             Ultra Wide Controller 
-      PCI MMAPed I/O Base: 0xeb001000 
-   Adapter SEEPROM Config: SEEPROM found and used. 
-        Adaptec SCSI BIOS: Enabled 
-                      IRQ: 10 
-                     SCBs: Active 0, Max Active 2, 
-                           Allocated 15, HW 16, Page 255 
-               Interrupts: 160328 
-        BIOS Control Word: 0x18b6 
-     Adapter Control Word: 0x005b 
-     Extended Translation: Enabled 
-  Disconnect Enable Flags: 0xffff 
-       Ultra Enable Flags: 0x0001 
-   Tag Queue Enable Flags: 0x0000 
-  Ordered Queue Tag Flags: 0x0000 
-  Default Tag Queue Depth: 8 
-      Tagged Queue By Device array for aic7xxx host instance 0: 
-        {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255} 
-      Actual queue depth per device for aic7xxx host instance 0: 
-        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} 
-  Statistics: 
-  (scsi0:0:0:0) 
-    Device using Wide/Sync transfers at 40.0 MByte/sec, offset 8 
-    Transinfo settings: current(12/8/1/0), goal(12/8/1/0), user(12/15/1/0) 
-    Total transfers 160151 (74577 reads and 85574 writes) 
-  (scsi0:0:6:0) 
-    Device using Narrow/Sync transfers at 5.0 MByte/sec, offset 15 
-    Transinfo settings: current(50/15/0/0), goal(50/15/0/0), user(50/15/0/0) 
-    Total transfers 0 (0 reads and 0 writes) 
+AHA-2940 SCSI adapter::
+
+  > cat /proc/scsi/aic7xxx/0
+
+  Adaptec AIC7xxx driver version: 5.1.19/3.2.4
+  Compile Options:
+    TCQ Enabled By Default : Disabled
+    AIC7XXX_PROC_STATS     : Disabled
+    AIC7XXX_RESET_DELAY    : 5
+  Adapter Configuration:
+             SCSI Adapter: Adaptec AHA-294X Ultra SCSI host adapter
+                             Ultra Wide Controller
+      PCI MMAPed I/O Base: 0xeb001000
+   Adapter SEEPROM Config: SEEPROM found and used.
+        Adaptec SCSI BIOS: Enabled
+                      IRQ: 10
+                     SCBs: Active 0, Max Active 2,
+                           Allocated 15, HW 16, Page 255
+               Interrupts: 160328
+        BIOS Control Word: 0x18b6
+     Adapter Control Word: 0x005b
+     Extended Translation: Enabled
+  Disconnect Enable Flags: 0xffff
+       Ultra Enable Flags: 0x0001
+   Tag Queue Enable Flags: 0x0000
+  Ordered Queue Tag Flags: 0x0000
+  Default Tag Queue Depth: 8
+      Tagged Queue By Device array for aic7xxx host instance 0:
+        {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}
+      Actual queue depth per device for aic7xxx host instance 0:
+        {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
+  Statistics:
+  (scsi0:0:0:0)
+    Device using Wide/Sync transfers at 40.0 MByte/sec, offset 8
+    Transinfo settings: current(12/8/1/0), goal(12/8/1/0), user(12/15/1/0)
+    Total transfers 160151 (74577 reads and 85574 writes)
+  (scsi0:0:6:0)
+    Device using Narrow/Sync transfers at 5.0 MByte/sec, offset 15
+    Transinfo settings: current(50/15/0/0), goal(50/15/0/0), user(50/15/0/0)
+    Total transfers 0 (0 reads and 0 writes)
 
 
 1.6 Parallel port info in /proc/parport
@@ -1296,18 +1387,20 @@ number (0,1,2,...).
 These directories contain the four files shown in Table 1-10.
 
 
-Table 1-10: Files in /proc/parport
-..............................................................................
- File      Content                                                             
- autoprobe Any IEEE-1284 device ID information that has been acquired.         
+.. table:: Table 1-10: Files in /proc/parport
+
+ ========= ====================================================================
+ File      Content
+ ========= ====================================================================
+ autoprobe Any IEEE-1284 device ID information that has been acquired.
  devices   list of the device drivers using that port. A + will appear by the
            name of the device currently using the port (it might not appear
-           against any). 
- hardware  Parallel port's base address, IRQ line and DMA channel.             
+           against any).
+ hardware  Parallel port's base address, IRQ line and DMA channel.
  irq       IRQ that parport is using for that port. This is in a separate
            file to allow you to alter it by writing a new value in (IRQ
-           number or none). 
-..............................................................................
+           number or none).
+ ========= ====================================================================
 
 1.7 TTY info in /proc/tty
 -------------------------
@@ -1317,29 +1410,31 @@ directory /proc/tty.You'll  find  entries  for drivers and line disciplines in
 this directory, as shown in Table 1-11.
 
 
-Table 1-11: Files in /proc/tty
-..............................................................................
- File          Content                                        
- drivers       list of drivers and their usage                
- ldiscs        registered line disciplines                    
- driver/serial usage statistic and status of single tty lines 
-..............................................................................
+.. table:: Table 1-11: Files in /proc/tty
+
+ ============= ==============================================
+ File          Content
+ ============= ==============================================
+ drivers       list of drivers and their usage
+ ldiscs        registered line disciplines
+ driver/serial usage statistic and status of single tty lines
+ ============= ==============================================
 
 To see  which  tty's  are  currently in use, you can simply look into the file
-/proc/tty/drivers:
-
-  > cat /proc/tty/drivers 
-  pty_slave            /dev/pts      136   0-255 pty:slave 
-  pty_master           /dev/ptm      128   0-255 pty:master 
-  pty_slave            /dev/ttyp       3   0-255 pty:slave 
-  pty_master           /dev/pty        2   0-255 pty:master 
-  serial               /dev/cua        5   64-67 serial:callout 
-  serial               /dev/ttyS       4   64-67 serial 
-  /dev/tty0            /dev/tty0       4       0 system:vtmaster 
-  /dev/ptmx            /dev/ptmx       5       2 system 
-  /dev/console         /dev/console    5       1 system:console 
-  /dev/tty             /dev/tty        5       0 system:/dev/tty 
-  unknown              /dev/tty        4    1-63 console 
+/proc/tty/drivers::
+
+  > cat /proc/tty/drivers
+  pty_slave            /dev/pts      136   0-255 pty:slave
+  pty_master           /dev/ptm      128   0-255 pty:master
+  pty_slave            /dev/ttyp       3   0-255 pty:slave
+  pty_master           /dev/pty        2   0-255 pty:master
+  serial               /dev/cua        5   64-67 serial:callout
+  serial               /dev/ttyS       4   64-67 serial
+  /dev/tty0            /dev/tty0       4       0 system:vtmaster
+  /dev/ptmx            /dev/ptmx       5       2 system
+  /dev/console         /dev/console    5       1 system:console
+  /dev/tty             /dev/tty        5       0 system:/dev/tty
+  unknown              /dev/tty        4    1-63 console
 
 
 1.8 Miscellaneous kernel statistics in /proc/stat
@@ -1347,7 +1442,7 @@ To see  which  tty's  are  currently in use, you can simply look into the file
 
 Various pieces   of  information about  kernel activity  are  available in the
 /proc/stat file.  All  of  the numbers reported  in  this file are  aggregates
-since the system first booted.  For a quick look, simply cat the file:
+since the system first booted.  For a quick look, simply cat the file::
 
   > cat /proc/stat
   cpu  2255 34 2290 22625563 6290 127 456 0 0 0
@@ -1372,6 +1467,7 @@ second).  The meanings of the columns are as follows, from left to right:
 - idle: twiddling thumbs
 - iowait: In a word, iowait stands for waiting for I/O to complete. But there
   are several problems:
+
   1. Cpu will not wait for I/O to complete, iowait is the time that a task is
      waiting for I/O to complete. When cpu goes into idle state for
      outstanding task io, another task will be scheduled on this CPU.
@@ -1379,6 +1475,7 @@ second).  The meanings of the columns are as follows, from left to right:
      on any CPU, so the iowait of each CPU is difficult to calculate.
   3. The value of iowait field in /proc/stat will decrease in certain
      conditions.
+
   So, the iowait is not reliable by reading from /proc/stat.
 - irq: servicing interrupts
 - softirq: servicing softirqs
@@ -1422,18 +1519,19 @@ Information about mounted ext4 file systems can be found in
 /proc/fs/ext4/dm-0).   The files in each per-device directory are shown
 in Table 1-12, below.
 
-Table 1-12: Files in /proc/fs/ext4/<devname>
-..............................................................................
- File            Content                                        
+.. table:: Table 1-12: Files in /proc/fs/ext4/<devname>
+
+ ==============  ==========================================================
+ File            Content
  mb_groups       details of multiblock allocator buddy cache of free blocks
-..............................................................................
+ ==============  ==========================================================
 
 2.0 /proc/consoles
 ------------------
 Shows registered system console lines.
 
 To see which character device lines are currently used for the system console
-/dev/console, you may simply look into the file /proc/consoles:
+/dev/console, you may simply look into the file /proc/consoles::
 
   > cat /proc/consoles
   tty0                 -WU (ECp)       4:7
@@ -1441,41 +1539,45 @@ To see which character device lines are currently used for the system console
 
 The columns are:
 
-  device               name of the device
-  operations           R = can do read operations
-                       W = can do write operations
-                       U = can do unblank
-  flags                E = it is enabled
-                       C = it is preferred console
-                       B = it is primary boot console
-                       p = it is used for printk buffer
-                       b = it is not a TTY but a Braille device
-                       a = it is safe to use when cpu is offline
-  major:minor          major and minor number of the device separated by a colon
++--------------------+-------------------------------------------------------+
+| device             | name of the device                                    |
++====================+=======================================================+
+| operations         | * R = can do read operations                          |
+|                    | * W = can do write operations                         |
+|                    | * U = can do unblank                                  |
++--------------------+-------------------------------------------------------+
+| flags              | * E = it is enabled                                   |
+|                    | * C = it is preferred console                         |
+|                    | * B = it is primary boot console                      |
+|                    | * p = it is used for printk buffer                    |
+|                    | * b = it is not a TTY but a Braille device            |
+|                    | * a = it is safe to use when cpu is offline           |
++--------------------+-------------------------------------------------------+
+| major:minor        | major and minor number of the device separated by a   |
+|                    | colon                                                 |
++--------------------+-------------------------------------------------------+
 
-------------------------------------------------------------------------------
 Summary
-------------------------------------------------------------------------------
+-------
+
 The /proc file system serves information about the running system. It not only
 allows access to process data but also allows you to request the kernel status
 by reading files in the hierarchy.
 
 The directory  structure  of /proc reflects the types of information and makes
 it easy, if not obvious, where to look for specific data.
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-CHAPTER 2: MODIFYING SYSTEM PARAMETERS
-------------------------------------------------------------------------------
+Chapter 2: Modifying System Parameters
+======================================
 
-------------------------------------------------------------------------------
 In This Chapter
-------------------------------------------------------------------------------
+---------------
+
 * Modifying kernel parameters by writing into files found in /proc/sys
 * Exploring the files which modify certain parameters
 * Review of the /proc/sys file tree
-------------------------------------------------------------------------------
 
+------------------------------------------------------------------------------
 
 A very  interesting part of /proc is the directory /proc/sys. This is not only
 a source  of  information,  it also allows you to change parameters within the
@@ -1503,19 +1605,18 @@ kernels, and became part of it in version 2.2.1 of the Linux kernel.
 Please see: Documentation/admin-guide/sysctl/ directory for descriptions of these
 entries.
 
-------------------------------------------------------------------------------
 Summary
-------------------------------------------------------------------------------
+-------
+
 Certain aspects  of  kernel  behavior  can be modified at runtime, without the
 need to  recompile  the kernel, or even to reboot the system. The files in the
 /proc/sys tree  can  not only be read, but also modified. You can use the echo
 command to write value into these files, thereby changing the default settings
 of the kernel.
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
-CHAPTER 3: PER-PROCESS PARAMETERS
-------------------------------------------------------------------------------
+
+Chapter 3: Per-process Parameters
+=================================
 
 3.1 /proc/<pid>/oom_adj & /proc/<pid>/oom_score_adj- Adjust the oom-killer score
 --------------------------------------------------------------------------------
@@ -1588,26 +1689,28 @@ process should be killed in an out-of-memory situation.
 This file contains IO statistics for each running process
 
 Example
--------
+~~~~~~~
+
+::
 
-test:/tmp # dd if=/dev/zero of=/tmp/test.dat &
-[1] 3828
+    test:/tmp # dd if=/dev/zero of=/tmp/test.dat &
+    [1] 3828
 
-test:/tmp # cat /proc/3828/io
-rchar: 323934931
-wchar: 323929600
-syscr: 632687
-syscw: 632675
-read_bytes: 0
-write_bytes: 323932160
-cancelled_write_bytes: 0
+    test:/tmp # cat /proc/3828/io
+    rchar: 323934931
+    wchar: 323929600
+    syscr: 632687
+    syscw: 632675
+    read_bytes: 0
+    write_bytes: 323932160
+    cancelled_write_bytes: 0
 
 
 Description
------------
+~~~~~~~~~~~
 
 rchar
------
+^^^^^
 
 I/O counter: chars read
 The number of bytes which this task has caused to be read from storage. This
@@ -1618,7 +1721,7 @@ pagecache)
 
 
 wchar
------
+^^^^^
 
 I/O counter: chars written
 The number of bytes which this task has caused, or shall cause to be written
@@ -1626,7 +1729,7 @@ to disk. Similar caveats apply here as with rchar.
 
 
 syscr
------
+^^^^^
 
 I/O counter: read syscalls
 Attempt to count the number of read I/O operations, i.e. syscalls like read()
@@ -1634,7 +1737,7 @@ and pread().
 
 
 syscw
------
+^^^^^
 
 I/O counter: write syscalls
 Attempt to count the number of write I/O operations, i.e. syscalls like
@@ -1642,7 +1745,7 @@ write() and pwrite().
 
 
 read_bytes
-----------
+^^^^^^^^^^
 
 I/O counter: bytes read
 Attempt to count the number of bytes which this process really did cause to
@@ -1652,7 +1755,7 @@ CIFS at a later time>
 
 
 write_bytes
------------
+^^^^^^^^^^^
 
 I/O counter: bytes written
 Attempt to count the number of bytes which this process caused to be sent to
@@ -1660,7 +1763,7 @@ the storage layer. This is done at page-dirtying time.
 
 
 cancelled_write_bytes
----------------------
+^^^^^^^^^^^^^^^^^^^^^
 
 The big inaccuracy here is truncate. If a process writes 1MB to a file and
 then deletes the file, it will in fact perform no writeout. But it will have
@@ -1673,12 +1776,11 @@ from the truncating task's write_bytes, but there is information loss in doing
 that.
 
 
-Note
-----
+.. Note::
 
-At its current implementation state, this is a bit racy on 32-bit machines: if
-process A reads process B's /proc/pid/io while process B is updating one of
-those 64-bit counters, process A could see an intermediate result.
+   At its current implementation state, this is a bit racy on 32-bit machines:
+   if process A reads process B's /proc/pid/io while process B is updating one
+   of those 64-bit counters, process A could see an intermediate result.
 
 
 More information about this can be found within the taskstats documentation in
@@ -1698,12 +1800,13 @@ of memory types. If a bit of the bitmask is set, memory segments of the
 corresponding memory type are dumped, otherwise they are not dumped.
 
 The following 9 memory types are supported:
+
   - (bit 0) anonymous private memory
   - (bit 1) anonymous shared memory
   - (bit 2) file-backed private memory
   - (bit 3) file-backed shared memory
   - (bit 4) ELF header pages in file-backed private memory areas (it is
-            effective only if the bit 2 is cleared)
+    effective only if the bit 2 is cleared)
   - (bit 5) hugetlb private memory
   - (bit 6) hugetlb shared memory
   - (bit 7) DAX private memory
@@ -1719,13 +1822,13 @@ The default value of coredump_filter is 0x33; this means all anonymous memory
 segments, ELF header pages and hugetlb private memory are dumped.
 
 If you don't want to dump all shared memory segments attached to pid 1234,
-write 0x31 to the process's proc file.
+write 0x31 to the process's proc file::
 
   $ echo 0x31 > /proc/1234/coredump_filter
 
 When a new process is created, the process inherits the bitmask status from its
 parent. It is useful to set up coredump_filter before the program runs.
-For example:
+For example::
 
   $ echo 0x7 > /proc/self/coredump_filter
   $ ./some_program
@@ -1733,35 +1836,37 @@ For example:
 3.5    /proc/<pid>/mountinfo - Information about mounts
 --------------------------------------------------------
 
-This file contains lines of the form:
+This file contains lines of the form::
 
-36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
-(1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)
+    36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
+    (1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)
 
-(1) mount ID:  unique identifier of the mount (may be reused after umount)
-(2) parent ID:  ID of parent (or of self for the top of the mount tree)
-(3) major:minor:  value of st_dev for files on filesystem
-(4) root:  root of the mount within the filesystem
-(5) mount point:  mount point relative to the process's root
-(6) mount options:  per mount options
-(7) optional fields:  zero or more fields of the form "tag[:value]"
-(8) separator:  marks the end of the optional fields
-(9) filesystem type:  name of filesystem of the form "type[.subtype]"
-(10) mount source:  filesystem specific information or "none"
-(11) super options:  per super block options
+    (1) mount ID:  unique identifier of the mount (may be reused after umount)
+    (2) parent ID:  ID of parent (or of self for the top of the mount tree)
+    (3) major:minor:  value of st_dev for files on filesystem
+    (4) root:  root of the mount within the filesystem
+    (5) mount point:  mount point relative to the process's root
+    (6) mount options:  per mount options
+    (7) optional fields:  zero or more fields of the form "tag[:value]"
+    (8) separator:  marks the end of the optional fields
+    (9) filesystem type:  name of filesystem of the form "type[.subtype]"
+    (10) mount source:  filesystem specific information or "none"
+    (11) super options:  per super block options
 
 Parsers should ignore all unrecognised optional fields.  Currently the
 possible optional fields are:
 
-shared:X  mount is shared in peer group X
-master:X  mount is slave to peer group X
-propagate_from:X  mount is slave and receives propagation from peer group X (*)
-unbindable  mount is unbindable
+================  ==============================================================
+shared:X          mount is shared in peer group X
+master:X          mount is slave to peer group X
+propagate_from:X  mount is slave and receives propagation from peer group X [#]_
+unbindable        mount is unbindable
+================  ==============================================================
 
-(*) X is the closest dominant peer group under the process's root.  If
-X is the immediate master of the mount, or if there's no dominant peer
-group under the same root, then only the "master:X" field is present
-and not the "propagate_from:X" field.
+.. [#] X is the closest dominant peer group under the process's root.  If
+       X is the immediate master of the mount, or if there's no dominant peer
+       group under the same root, then only the "master:X" field is present
+       and not the "propagate_from:X" field.
 
 For more information on mount propagation see:
 
@@ -1804,77 +1909,86 @@ created with [see open(2) for details] and 'mnt_id' represents mount ID of
 the file system containing the opened file [see 3.5 /proc/<pid>/mountinfo
 for details].
 
-A typical output is
+A typical output is::
 
        pos:    0
        flags:  0100002
        mnt_id: 19
 
-All locks associated with a file descriptor are shown in its fdinfo too.
+All locks associated with a file descriptor are shown in its fdinfo too::
 
-lock:       1: FLOCK  ADVISORY  WRITE 359 00:13:11691 0 EOF
+    lock:       1: FLOCK  ADVISORY  WRITE 359 00:13:11691 0 EOF
 
 The files such as eventfd, fsnotify, signalfd, epoll among the regular pos/flags
 pair provide additional information particular to the objects they represent.
 
-       Eventfd files
-       ~~~~~~~~~~~~~
+Eventfd files
+~~~~~~~~~~~~~
+
+::
+
        pos:    0
        flags:  04002
        mnt_id: 9
        eventfd-count:  5a
 
-       where 'eventfd-count' is hex value of a counter.
+where 'eventfd-count' is hex value of a counter.
+
+Signalfd files
+~~~~~~~~~~~~~~
+
+::
 
-       Signalfd files
-       ~~~~~~~~~~~~~~
        pos:    0
        flags:  04002
        mnt_id: 9
        sigmask:        0000000000000200
 
-       where 'sigmask' is hex value of the signal mask associated
-       with a file.
+where 'sigmask' is hex value of the signal mask associated
+with a file.
+
+Epoll files
+~~~~~~~~~~~
+
+::
 
-       Epoll files
-       ~~~~~~~~~~~
        pos:    0
        flags:  02
        mnt_id: 9
        tfd:        5 events:       1d data: ffffffffffffffff pos:0 ino:61af sdev:7
 
-       where 'tfd' is a target file descriptor number in decimal form,
-       'events' is events mask being watched and the 'data' is data
-       associated with a target [see epoll(7) for more details].
+where 'tfd' is a target file descriptor number in decimal form,
+'events' is events mask being watched and the 'data' is data
+associated with a target [see epoll(7) for more details].
 
-       The 'pos' is current offset of the target file in decimal form
-       [see lseek(2)], 'ino' and 'sdev' are inode and device numbers
-       where target file resides, all in hex format.
+The 'pos' is current offset of the target file in decimal form
+[see lseek(2)], 'ino' and 'sdev' are inode and device numbers
+where target file resides, all in hex format.
 
-       Fsnotify files
-       ~~~~~~~~~~~~~~
-       For inotify files the format is the following
+Fsnotify files
+~~~~~~~~~~~~~~
+For inotify files the format is the following::
 
        pos:    0
        flags:  02000000
        inotify wd:3 ino:9e7e sdev:800013 mask:800afce ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:7e9e0000640d1b6d
 
-       where 'wd' is a watch descriptor in decimal form, ie a target file
-       descriptor number, 'ino' and 'sdev' are inode and device where the
-       target file resides and the 'mask' is the mask of events, all in hex
-       form [see inotify(7) for more details].
+where 'wd' is a watch descriptor in decimal form, ie a target file
+descriptor number, 'ino' and 'sdev' are inode and device where the
+target file resides and the 'mask' is the mask of events, all in hex
+form [see inotify(7) for more details].
 
-       If the kernel was built with exportfs support, the path to the target
-       file is encoded as a file handle.  The file handle is provided by three
-       fields 'fhandle-bytes', 'fhandle-type' and 'f_handle', all in hex
-       format.
+If the kernel was built with exportfs support, the path to the target
+file is encoded as a file handle.  The file handle is provided by three
+fields 'fhandle-bytes', 'fhandle-type' and 'f_handle', all in hex
+format.
 
-       If the kernel is built without exportfs support the file handle won't be
-       printed out.
+If the kernel is built without exportfs support the file handle won't be
+printed out.
 
-       If there is no inotify mark attached yet the 'inotify' line will be omitted.
+If there is no inotify mark attached yet the 'inotify' line will be omitted.
 
-       For fanotify files the format is
+For fanotify files the format is::
 
        pos:    0
        flags:  02
@@ -1883,20 +1997,22 @@ pair provide additional information particular to the objects they represent.
        fanotify mnt_id:12 mflags:40 mask:38 ignored_mask:40000003
        fanotify ino:4f969 sdev:800013 mflags:0 mask:3b ignored_mask:40000000 fhandle-bytes:8 fhandle-type:1 f_handle:69f90400c275b5b4
 
-       where fanotify 'flags' and 'event-flags' are values used in fanotify_init
-       call, 'mnt_id' is the mount point identifier, 'mflags' is the value of
-       flags associated with mark which are tracked separately from events
-       mask. 'ino', 'sdev' are target inode and device, 'mask' is the events
-       mask and 'ignored_mask' is the mask of events which are to be ignored.
-       All in hex format. Incorporation of 'mflags', 'mask' and 'ignored_mask'
-       does provide information about flags and mask used in fanotify_mark
-       call [see fsnotify manpage for details].
+where fanotify 'flags' and 'event-flags' are values used in fanotify_init
+call, 'mnt_id' is the mount point identifier, 'mflags' is the value of
+flags associated with mark which are tracked separately from events
+mask. 'ino', 'sdev' are target inode and device, 'mask' is the events
+mask and 'ignored_mask' is the mask of events which are to be ignored.
+All in hex format. Incorporation of 'mflags', 'mask' and 'ignored_mask'
+does provide information about flags and mask used in fanotify_mark
+call [see fsnotify manpage for details].
+
+While the first three lines are mandatory and always printed, the rest is
+optional and may be omitted if no marks created yet.
 
-       While the first three lines are mandatory and always printed, the rest is
-       optional and may be omitted if no marks created yet.
+Timerfd files
+~~~~~~~~~~~~~
 
-       Timerfd files
-       ~~~~~~~~~~~~~
+::
 
        pos:    0
        flags:  02
@@ -1907,18 +2023,18 @@ pair provide additional information particular to the objects they represent.
        it_value: (0, 49406829)
        it_interval: (1, 0)
 
-       where 'clockid' is the clock type and 'ticks' is the number of the timer expirations
-       that have occurred [see timerfd_create(2) for details]. 'settime flags' are
-       flags in octal form been used to setup the timer [see timerfd_settime(2) for
-       details]. 'it_value' is remaining time until the timer exiration.
-       'it_interval' is the interval for the timer. Note the timer might be set up
-       with TIMER_ABSTIME option which will be shown in 'settime flags', but 'it_value'
-       still exhibits timer's remaining time.
+where 'clockid' is the clock type and 'ticks' is the number of the timer expirations
+that have occurred [see timerfd_create(2) for details]. 'settime flags' are
+flags in octal form been used to setup the timer [see timerfd_settime(2) for
+details]. 'it_value' is remaining time until the timer exiration.
+'it_interval' is the interval for the timer. Note the timer might be set up
+with TIMER_ABSTIME option which will be shown in 'settime flags', but 'it_value'
+still exhibits timer's remaining time.
 
 3.9    /proc/<pid>/map_files - Information about memory mapped files
 ---------------------------------------------------------------------
 This directory contains symbolic links which represent memory mapped files
-the process is maintaining.  Example output:
+the process is maintaining.  Example output::
 
      | lr-------- 1 root root 64 Jan 27 11:24 333c600000-333c620000 -> /usr/lib64/ld-2.18.so
      | lr-------- 1 root root 64 Jan 27 11:24 333c81f000-333c820000 -> /usr/lib64/ld-2.18.so
@@ -1976,17 +2092,22 @@ When CONFIG_PROC_PID_ARCH_STATUS is enabled, this file displays the
 architecture specific status of the task.
 
 Example
--------
+~~~~~~~
+
+::
+
  $ cat /proc/6753/arch_status
  AVX512_elapsed_ms:      8
 
 Description
------------
+~~~~~~~~~~~
 
 x86 specific entries:
----------------------
- AVX512_elapsed_ms:
- ------------------
+~~~~~~~~~~~~~~~~~~~~~
+
+AVX512_elapsed_ms:
+^^^^^^^^^^^^^^^^^^
+
   If AVX512 is supported on the machine, this entry shows the milliseconds
   elapsed since the last time AVX512 usage was recorded. The recording
   happens on a best effort basis when a task is scheduled out. This means
@@ -2010,17 +2131,18 @@ x86 specific entries:
   the task is unlikely an AVX512 user, but depends on the workload and the
   scheduling scenario, it also could be a false negative mentioned above.
 
-------------------------------------------------------------------------------
 Configuring procfs
-------------------------------------------------------------------------------
+------------------
 
 4.1    Mount options
 ---------------------
 
 The following mount options are supported:
 
+       =========       ========================================================
        hidepid=        Set /proc/<pid>/ access mode.
        gid=            Set the group authorized to learn processes information.
+       =========       ========================================================
 
 hidepid=0 means classic mode - everybody may access all /proc/<pid>/ directories
 (default).
similarity index 98%
rename from Documentation/filesystems/qnx6.txt
rename to Documentation/filesystems/qnx6.rst
index 48ea68f..b713083 100644 (file)
@@ -1,3 +1,6 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===================
 The QNX6 Filesystem
 ===================
 
@@ -14,10 +17,12 @@ Specification
 
 qnx6fs shares many properties with traditional Unix filesystems. It has the
 concepts of blocks, inodes and directories.
+
 On QNX it is possible to create little endian and big endian qnx6 filesystems.
 This feature makes it possible to create and use a different endianness fs
 for the target (QNX is used on quite a range of embedded systems) platform
 running on a different endianness.
+
 The Linux driver handles endianness transparently. (LE and BE)
 
 Blocks
@@ -26,6 +31,7 @@ Blocks
 The space in the device or file is split up into blocks. These are a fixed
 size of 512, 1024, 2048 or 4096, which is decided when the filesystem is
 created.
+
 Blockpointers are 32bit, so the maximum space that can be addressed is
 2^32 * 4096 bytes or 16TB
 
@@ -50,6 +56,7 @@ Each of these root nodes holds information like total size of the stored
 data and the addressing levels in that specific tree.
 If the level value is 0, up to 16 direct blocks can be addressed by each
 node.
+
 Level 1 adds an additional indirect addressing level where each indirect
 addressing block holds up to blocksize / 4 bytes pointers to data blocks.
 Level 2 adds an additional indirect addressing block level (so, already up
@@ -57,11 +64,13 @@ to 16 * 256 * 256 = 1048576 blocks that can be addressed by such a tree).
 
 Unused block pointers are always set to ~0 - regardless of root node,
 indirect addressing blocks or inodes.
+
 Data leaves are always on the lowest level. So no data is stored on upper
 tree levels.
 
 The first Superblock is located at 0x2000. (0x2000 is the bootblock size)
 The Audi MMI 3G first superblock directly starts at byte 0.
+
 Second superblock position can either be calculated from the superblock
 information (total number of filesystem blocks) or by taking the highest
 device address, zeroing the last 3 bytes and then subtracting 0x1000 from
@@ -84,6 +93,7 @@ Object mode field is POSIX format. (which makes things easier)
 
 There are also pointers to the first 16 blocks, if the object data can be
 addressed with 16 direct blocks.
+
 For more than 16 blocks an indirect addressing in form of another tree is
 used. (scheme is the same as the one used for the superblock root nodes)
 
@@ -96,13 +106,18 @@ Directories
 A directory is a filesystem object and has an inode just like a file.
 It is a specially formatted file containing records which associate each
 name with an inode number.
+
 '.' inode number points to the directory inode
+
 '..' inode number points to the parent directory inode
+
 Eeach filename record additionally got a filename length field.
 
 One special case are long filenames or subdirectory names.
+
 These got set a filename length field of 0xff in the corresponding directory
 record plus the longfile inode number also stored in that record.
+
 With that longfilename inode number, the longfilename tree can be walked
 starting with the superblock longfilename root node pointers.
 
@@ -111,6 +126,7 @@ Special files
 
 Symbolic links are also filesystem objects with inodes. They got a specific
 bit in the inode mode field identifying them as symbolic link.
+
 The directory entry file inode pointer points to the target file inode.
 
 Hard links got an inode, a directory entry, but a specific mode bit set,
@@ -126,9 +142,11 @@ Long filenames
 
 Long filenames are stored in a separate addressing tree. The staring point
 is the longfilename root node in the active superblock.
+
 Each data block (tree leaves) holds one long filename. That filename is
 limited to 510 bytes. The first two starting bytes are used as length field
 for the actual filename.
+
 If that structure shall fit for all allowed blocksizes, it is clear why there
 is a limit of 510 bytes for the actual filename stored.
 
@@ -138,6 +156,7 @@ Bitmap
 The qnx6fs filesystem allocation bitmap is stored in a tree under bitmap
 root node in the superblock and each bit in the bitmap represents one
 filesystem block.
+
 The first block is block 0, which starts 0x1000 after superblock start.
 So for a normal qnx6fs 0x3000 (bootblock + superblock) is the physical
 address at which block 0 is located.
@@ -149,11 +168,14 @@ Bitmap system area
 ------------------
 
 The bitmap itself is divided into three parts.
+
 First the system area, that is split into two halves.
+
 Then userspace.
 
 The requirement for a static, fixed preallocated system area comes from how
 qnx6fs deals with writes.
+
 Each superblock got it's own half of the system area. So superblock #1
 always uses blocks from the lower half while superblock #2 just writes to
 blocks represented by the upper half bitmap system area bits.
@@ -1,5 +1,11 @@
-ramfs, rootfs and initramfs
+.. SPDX-License-Identifier: GPL-2.0
+
+===========================
+Ramfs, rootfs and initramfs
+===========================
+
 October 17, 2005
+
 Rob Landley <rob@landley.net>
 =============================
 
@@ -99,14 +105,14 @@ out of that.
 All this differs from the old initrd in several ways:
 
   - The old initrd was always a separate file, while the initramfs archive is
-    linked into the linux kernel image.  (The directory linux-*/usr is devoted
-    to generating this archive during the build.)
+    linked into the linux kernel image.  (The directory ``linux-*/usr`` is
+    devoted to generating this archive during the build.)
 
   - The old initrd file was a gzipped filesystem image (in some file format,
     such as ext2, that needed a driver built into the kernel), while the new
     initramfs archive is a gzipped cpio archive (like tar only simpler,
-    see cpio(1) and Documentation/driver-api/early-userspace/buffer-format.rst).  The
-    kernel's cpio extraction code is not only extremely small, it's also
+    see cpio(1) and Documentation/driver-api/early-userspace/buffer-format.rst).
+    The kernel's cpio extraction code is not only extremely small, it's also
     __init text and data that can be discarded during the boot process.
 
   - The program run by the old initrd (which was called /initrd, not /init) did
@@ -139,7 +145,7 @@ and living in usr/Kconfig) can be used to specify a source for the
 initramfs archive, which will automatically be incorporated into the
 resulting binary.  This option can point to an existing gzipped cpio
 archive, a directory containing files to be archived, or a text file
-specification such as the following example:
+specification such as the following example::
 
   dir /dev 755 0 0
   nod /dev/console 644 0 0 c 5 1
@@ -175,12 +181,12 @@ or extracting your own preprepared cpio files to feed to the kernel build
 (instead of a config file or directory).
 
 The following command line can extract a cpio image (either by the above script
-or by the kernel build) back into its component files:
+or by the kernel build) back into its component files::
 
   cpio -i -d -H newc -F initramfs_data.cpio --no-absolute-filenames
 
 The following shell script can create a prebuilt cpio archive you can
-use in place of the above config file:
+use in place of the above config file::
 
   #!/bin/sh
 
@@ -202,14 +208,17 @@ use in place of the above config file:
     exit 1
   fi
 
-Note: The cpio man page contains some bad advice that will break your initramfs
-archive if you follow it.  It says "A typical way to generate the list
-of filenames is with the find command; you should give find the -depth option
-to minimize problems with permissions on directories that are unwritable or not
-searchable."  Don't do this when creating initramfs.cpio.gz images, it won't
-work.  The Linux kernel cpio extractor won't create files in a directory that
-doesn't exist, so the directory entries must go before the files that go in
-those directories.  The above script gets them in the right order.
+.. Note::
+
+   The cpio man page contains some bad advice that will break your initramfs
+   archive if you follow it.  It says "A typical way to generate the list
+   of filenames is with the find command; you should give find the -depth
+   option to minimize problems with permissions on directories that are
+   unwritable or not searchable."  Don't do this when creating
+   initramfs.cpio.gz images, it won't work.  The Linux kernel cpio extractor
+   won't create files in a directory that doesn't exist, so the directory
+   entries must go before the files that go in those directories.
+   The above script gets them in the right order.
 
 External initramfs images:
 --------------------------
@@ -236,9 +245,10 @@ An initramfs archive is a complete self-contained root filesystem for Linux.
 If you don't already understand what shared libraries, devices, and paths
 you need to get a minimal root filesystem up and running, here are some
 references:
-http://www.tldp.org/HOWTO/Bootdisk-HOWTO/
-http://www.tldp.org/HOWTO/From-PowerUp-To-Bash-Prompt-HOWTO.html
-http://www.linuxfromscratch.org/lfs/view/stable/
+
+- http://www.tldp.org/HOWTO/Bootdisk-HOWTO/
+- http://www.tldp.org/HOWTO/From-PowerUp-To-Bash-Prompt-HOWTO.html
+- http://www.linuxfromscratch.org/lfs/view/stable/
 
 The "klibc" package (http://www.kernel.org/pub/linux/libs/klibc) is
 designed to be a tiny C library to statically link early userspace
@@ -255,7 +265,7 @@ name lookups, even when otherwise statically linked.)
 
 A good first step is to get initramfs to run a statically linked "hello world"
 program as init, and test it under an emulator like qemu (www.qemu.org) or
-User Mode Linux, like so:
+User Mode Linux, like so::
 
   cat > hello.c << EOF
   #include <stdio.h>
@@ -326,8 +336,8 @@ the above threads) is:
 
    explained his reasoning:
 
-      http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1550.html
-      http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1638.html
+     - http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1550.html
+     - http://www.uwsg.iu.edu/hypermail/linux/kernel/0112.2/1638.html
 
    and, most importantly, designed and implemented the initramfs code.
 
similarity index 91%
rename from Documentation/filesystems/relay.txt
rename to Documentation/filesystems/relay.rst
index cd709a9..04ad083 100644 (file)
@@ -1,3 +1,6 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==================================
 relay interface (formerly relayfs)
 ==================================
 
@@ -108,6 +111,7 @@ The relay interface implements basic file operations for user space
 access to relay channel buffer data.  Here are the file operations
 that are available and some comments regarding their behavior:
 
+=========== ============================================================
 open()     enables user to open an _existing_ channel buffer.
 
 mmap()      results in channel buffer being mapped into the caller's
@@ -136,13 +140,16 @@ poll()      POLLIN/POLLRDNORM/POLLERR supported.  User applications are
 close()     decrements the channel buffer's refcount.  When the refcount
            reaches 0, i.e. when no process or kernel client has the
            buffer open, the channel buffer is freed.
+=========== ============================================================
 
 In order for a user application to make use of relay files, the
-host filesystem must be mounted.  For example,
+host filesystem must be mounted.  For example::
 
        mount -t debugfs debugfs /sys/kernel/debug
 
-NOTE:   the host filesystem doesn't need to be mounted for kernel
+.. Note::
+
+       the host filesystem doesn't need to be mounted for kernel
        clients to create or use channels - it only needs to be
        mounted when user space applications need access to the buffer
        data.
@@ -154,7 +161,7 @@ The relay interface kernel API
 Here's a summary of the API the relay interface provides to in-kernel clients:
 
 TBD(curr. line MT:/API/)
-  channel management functions:
+  channel management functions::
 
     relay_open(base_filename, parent, subbuf_size, n_subbufs,
                callbacks, private_data)
@@ -162,17 +169,17 @@ TBD(curr. line MT:/API/)
     relay_flush(chan)
     relay_reset(chan)
 
-  channel management typically called on instigation of userspace:
+  channel management typically called on instigation of userspace::
 
     relay_subbufs_consumed(chan, cpu, subbufs_consumed)
 
-  write functions:
+  write functions::
 
     relay_write(chan, data, length)
     __relay_write(chan, data, length)
     relay_reserve(chan, length)
 
-  callbacks:
+  callbacks::
 
     subbuf_start(buf, subbuf, prev_subbuf, prev_padding)
     buf_mapped(buf, filp)
@@ -180,7 +187,7 @@ TBD(curr. line MT:/API/)
     create_buf_file(filename, parent, mode, buf, is_global)
     remove_buf_file(dentry)
 
-  helper functions:
+  helper functions::
 
     relay_buf_full(buf)
     subbuf_start_reserve(buf, length)
@@ -215,41 +222,41 @@ the file(s) created in create_buf_file() and is called during
 relay_close().
 
 Here are some typical definitions for these callbacks, in this case
-using debugfs:
-
-/*
- * create_buf_file() callback.  Creates relay file in debugfs.
- */
-static struct dentry *create_buf_file_handler(const char *filename,
-                                              struct dentry *parent,
-                                              umode_t mode,
-                                              struct rchan_buf *buf,
-                                              int *is_global)
-{
-        return debugfs_create_file(filename, mode, parent, buf,
-                                  &relay_file_operations);
-}
-
-/*
- * remove_buf_file() callback.  Removes relay file from debugfs.
- */
-static int remove_buf_file_handler(struct dentry *dentry)
-{
-        debugfs_remove(dentry);
-
-        return 0;
-}
-
-/*
- * relay interface callbacks
- */
-static struct rchan_callbacks relay_callbacks =
-{
-        .create_buf_file = create_buf_file_handler,
-        .remove_buf_file = remove_buf_file_handler,
-};
-
-And an example relay_open() invocation using them:
+using debugfs::
+
+    /*
   * create_buf_file() callback.  Creates relay file in debugfs.
   */
+    static struct dentry *create_buf_file_handler(const char *filename,
+                                               struct dentry *parent,
+                                               umode_t mode,
+                                               struct rchan_buf *buf,
+                                               int *is_global)
+    {
+           return debugfs_create_file(filename, mode, parent, buf,
+                                   &relay_file_operations);
+    }
+
+    /*
   * remove_buf_file() callback.  Removes relay file from debugfs.
   */
+    static int remove_buf_file_handler(struct dentry *dentry)
+    {
+           debugfs_remove(dentry);
+
+           return 0;
+    }
+
+    /*
   * relay interface callbacks
   */
+    static struct rchan_callbacks relay_callbacks =
+    {
+           .create_buf_file = create_buf_file_handler,
+           .remove_buf_file = remove_buf_file_handler,
+    };
+
+And an example relay_open() invocation using them::
 
   chan = relay_open("cpu", NULL, SUBBUF_SIZE, N_SUBBUFS, &relay_callbacks, NULL);
 
@@ -339,23 +346,23 @@ whether or not to actually move on to the next sub-buffer.
 
 To implement 'no-overwrite' mode, the userspace client would provide
 an implementation of the subbuf_start() callback something like the
-following:
+following::
 
-static int subbuf_start(struct rchan_buf *buf,
-                        void *subbuf,
-                       void *prev_subbuf,
-                       unsigned int prev_padding)
-{
-       if (prev_subbuf)
-               *((unsigned *)prev_subbuf) = prev_padding;
+    static int subbuf_start(struct rchan_buf *buf,
+                           void *subbuf,
+                           void *prev_subbuf,
+                           unsigned int prev_padding)
+    {
+           if (prev_subbuf)
+                   *((unsigned *)prev_subbuf) = prev_padding;
 
-       if (relay_buf_full(buf))
-               return 0;
+           if (relay_buf_full(buf))
+                   return 0;
 
-       subbuf_start_reserve(buf, sizeof(unsigned int));
+           subbuf_start_reserve(buf, sizeof(unsigned int));
 
-       return 1;
-}
+           return 1;
+    }
 
 If the current buffer is full, i.e. all sub-buffers remain unconsumed,
 the callback returns 0 to indicate that the buffer switch should not
@@ -370,20 +377,20 @@ ready sub-buffers will relay_buf_full() return 0, in which case the
 buffer switch can continue.
 
 The implementation of the subbuf_start() callback for 'overwrite' mode
-would be very similar:
+would be very similar::
 
-static int subbuf_start(struct rchan_buf *buf,
-                        void *subbuf,
-                       void *prev_subbuf,
-                       size_t prev_padding)
-{
-       if (prev_subbuf)
-               *((unsigned *)prev_subbuf) = prev_padding;
+    static int subbuf_start(struct rchan_buf *buf,
+                           void *subbuf,
+                           void *prev_subbuf,
+                           size_t prev_padding)
+    {
+           if (prev_subbuf)
+                   *((unsigned *)prev_subbuf) = prev_padding;
 
-       subbuf_start_reserve(buf, sizeof(unsigned int));
+           subbuf_start_reserve(buf, sizeof(unsigned int));
 
-       return 1;
-}
+           return 1;
+    }
 
 In this case, the relay_buf_full() check is meaningless and the
 callback always returns 1, causing the buffer switch to occur
similarity index 86%
rename from Documentation/filesystems/romfs.txt
rename to Documentation/filesystems/romfs.rst
index e2b07cc..465b11e 100644 (file)
@@ -1,4 +1,8 @@
-ROMFS - ROM FILE SYSTEM
+.. SPDX-License-Identifier: GPL-2.0
+
+=======================
+ROMFS - ROM File System
+=======================
 
 This is a quite dumb, read only filesystem, mainly for initial RAM
 disks of installation disks.  It has grown up by the need of having
@@ -51,9 +55,9 @@ the 16 byte padding for the name and the contents, also 16+14+15 = 45
 bytes.  This is quite rare however, since most file names are longer
 than 3 bytes, and shorter than 15 bytes.
 
-The layout of the filesystem is the following:
+The layout of the filesystem is the following::
 
-offset     content
+ offset            content
 
        +---+---+---+---+
   0    | - | r | o | m |  \
@@ -84,9 +88,9 @@ the source.  This algorithm was chosen because although it's not quite
 reliable, it does not require any tables, and it is very simple.
 
 The following bytes are now part of the file system; each file header
-must begin on a 16 byte boundary.
+must begin on a 16 byte boundary::
 
-offset     content
+ offset            content
 
        +---+---+---+---+
   0    | next filehdr|X|       The offset of the next file header
@@ -114,7 +118,9 @@ file is user and group 0, this should never be a problem for the
 intended use.  The mapping of the 8 possible values to file types is
 the following:
 
+==     =============== ============================================
          mapping               spec.info means
+==     =============== ============================================
  0     hard link       link destination [file header]
  1     directory       first file's header
  2     regular file    unused, must be zero [MBZ]
@@ -123,6 +129,7 @@ the following:
  5     char device                 - " -
  6     socket          unused, MBZ
  7     fifo            unused, MBZ
+==     =============== ============================================
 
 Note that hard links are specifically marked in this filesystem, but
 they will behave as you can expect (i.e. share the inode number).
@@ -158,24 +165,24 @@ to romfs-subscribe@shadow.banki.hu, the content is irrelevant.
 Pending issues:
 
 - Permissions and owner information are pretty essential features of a
-Un*x like system, but romfs does not provide the full possibilities.
-I have never found this limiting, but others might.
+  Un*x like system, but romfs does not provide the full possibilities.
+  I have never found this limiting, but others might.
 
 - The file system is read only, so it can be very small, but in case
-one would want to write _anything_ to a file system, he still needs
-a writable file system, thus negating the size advantages.  Possible
-solutions: implement write access as a compile-time option, or a new,
-similarly small writable filesystem for RAM disks.
+  one would want to write _anything_ to a file system, he still needs
+  a writable file system, thus negating the size advantages.  Possible
+  solutions: implement write access as a compile-time option, or a new,
+  similarly small writable filesystem for RAM disks.
 
 - Since the files are only required to have alignment on a 16 byte
-boundary, it is currently possibly suboptimal to read or execute files
-from the filesystem.  It might be resolved by reordering file data to
-have most of it (i.e. except the start and the end) laying at "natural"
-boundaries, thus it would be possible to directly map a big portion of
-the file contents to the mm subsystem.
+  boundary, it is currently possibly suboptimal to read or execute files
+  from the filesystem.  It might be resolved by reordering file data to
+  have most of it (i.e. except the start and the end) laying at "natural"
+  boundaries, thus it would be possible to directly map a big portion of
+  the file contents to the mm subsystem.
 
 - Compression might be an useful feature, but memory is quite a
-limiting factor in my eyes.
+  limiting factor in my eyes.
 
 - Where it is used?
 
@@ -183,4 +190,5 @@ limiting factor in my eyes.
 
 
 Have fun,
+
 Janos Farkas <chexum@shadow.banki.hu>
similarity index 91%
rename from Documentation/filesystems/squashfs.txt
rename to Documentation/filesystems/squashfs.rst
index e5274f8..df42106 100644 (file)
@@ -1,7 +1,11 @@
-SQUASHFS 4.0 FILESYSTEM
+.. SPDX-License-Identifier: GPL-2.0
+
+=======================
+Squashfs 4.0 Filesystem
 =======================
 
 Squashfs is a compressed read-only filesystem for Linux.
+
 It uses zlib, lz4, lzo, or xz compression to compress files, inodes and
 directories.  Inodes in the system are very small and all blocks are packed to
 minimise data overhead. Block sizes greater than 4K are supported up to a
@@ -15,31 +19,33 @@ needed.
 Mailing list: squashfs-devel@lists.sourceforge.net
 Web site: www.squashfs.org
 
-1. FILESYSTEM FEATURES
+1. Filesystem Features
 ----------------------
 
 Squashfs filesystem features versus Cramfs:
 
+==============================         =========               ==========
                                Squashfs                Cramfs
-
-Max filesystem size:           2^64                    256 MiB
-Max file size:                 ~ 2 TiB                 16 MiB
-Max files:                     unlimited               unlimited
-Max directories:               unlimited               unlimited
-Max entries per directory:     unlimited               unlimited
-Max block size:                        1 MiB                   4 KiB
-Metadata compression:          yes                     no
-Directory indexes:             yes                     no
-Sparse file support:           yes                     no
-Tail-end packing (fragments):  yes                     no
-Exportable (NFS etc.):         yes                     no
-Hard link support:             yes                     no
-"." and ".." in readdir:       yes                     no
-Real inode numbers:            yes                     no
-32-bit uids/gids:              yes                     no
-File creation time:            yes                     no
-Xattr support:                 yes                     no
-ACL support:                   no                      no
+==============================         =========               ==========
+Max filesystem size            2^64                    256 MiB
+Max file size                  ~ 2 TiB                 16 MiB
+Max files                      unlimited               unlimited
+Max directories                        unlimited               unlimited
+Max entries per directory      unlimited               unlimited
+Max block size                 1 MiB                   4 KiB
+Metadata compression           yes                     no
+Directory indexes              yes                     no
+Sparse file support            yes                     no
+Tail-end packing (fragments)   yes                     no
+Exportable (NFS etc.)          yes                     no
+Hard link support              yes                     no
+"." and ".." in readdir                yes                     no
+Real inode numbers             yes                     no
+32-bit uids/gids               yes                     no
+File creation time             yes                     no
+Xattr support                  yes                     no
+ACL support                    no                      no
+==============================         =========               ==========
 
 Squashfs compresses data, inodes and directories.  In addition, inode and
 directory data are highly compacted, and packed on byte boundaries.  Each
@@ -47,7 +53,7 @@ compressed inode is on average 8 bytes in length (the exact length varies on
 file type, i.e. regular file, directory, symbolic link, and block/char device
 inodes have different sizes).
 
-2. USING SQUASHFS
+2. Using Squashfs
 -----------------
 
 As squashfs is a read-only filesystem, the mksquashfs program must be used to
@@ -58,11 +64,11 @@ obtained from this site also.
 The squashfs-tools development tree is now located on kernel.org
        git://git.kernel.org/pub/scm/fs/squashfs/squashfs-tools.git
 
-3. SQUASHFS FILESYSTEM DESIGN
+3. Squashfs Filesystem Design
 -----------------------------
 
 A squashfs filesystem consists of a maximum of nine parts, packed together on a
-byte alignment:
+byte alignment::
 
         ---------------
        |  superblock   |
@@ -229,15 +235,15 @@ location of the xattr list inside each inode, a 32-bit xattr id
 is stored.  This xattr id is mapped into the location of the xattr
 list using a second xattr id lookup table.
 
-4. TODOS AND OUTSTANDING ISSUES
+4. TODOs and Outstanding Issues
 -------------------------------
 
-4.1 Todo list
+4.1 TODO list
 -------------
 
 Implement ACL support.
 
-4.2 Squashfs internal cache
+4.2 Squashfs Internal Cache
 ---------------------------
 
 Blocks in Squashfs are compressed.  To avoid repeatedly decompressing
similarity index 56%
rename from Documentation/filesystems/sysfs.txt
rename to Documentation/filesystems/sysfs.rst
index ddf15b1..290891c 100644 (file)
@@ -1,32 +1,36 @@
+.. SPDX-License-Identifier: GPL-2.0
 
-sysfs - _The_ filesystem for exporting kernel objects. 
+=====================================================
+sysfs - _The_ filesystem for exporting kernel objects
+=====================================================
 
 Patrick Mochel <mochel@osdl.org>
+
 Mike Murphy <mamurph@cs.clemson.edu>
 
-Revised:    16 August 2011
-Original:   10 January 2003
+:Revised:    16 August 2011
+:Original:   10 January 2003
 
 
 What it is:
 ~~~~~~~~~~~
 
 sysfs is a ram-based filesystem initially based on ramfs. It provides
-a means to export kernel data structures, their attributes, and the 
-linkages between them to userspace. 
+a means to export kernel data structures, their attributes, and the
+linkages between them to userspace.
 
 sysfs is tied inherently to the kobject infrastructure. Please read
 Documentation/kobject.txt for more information concerning the kobject
-interface. 
+interface.
 
 
 Using sysfs
 ~~~~~~~~~~~
 
 sysfs is always compiled in if CONFIG_SYSFS is defined. You can access
-it by doing:
+it by doing::
 
-    mount -t sysfs sysfs /sys 
+    mount -t sysfs sysfs /sys
 
 
 Directory Creation
@@ -37,7 +41,7 @@ created for it in sysfs. That directory is created as a subdirectory
 of the kobject's parent, expressing internal object hierarchies to
 userspace. Top-level directories in sysfs represent the common
 ancestors of object hierarchies; i.e. the subsystems the objects
-belong to. 
+belong to.
 
 Sysfs internally stores a pointer to the kobject that implements a
 directory in the kernfs_node object associated with the directory. In
@@ -58,63 +62,63 @@ attributes.
 Attributes should be ASCII text files, preferably with only one value
 per file. It is noted that it may not be efficient to contain only one
 value per file, so it is socially acceptable to express an array of
-values of the same type. 
+values of the same type.
 
 Mixing types, expressing multiple lines of data, and doing fancy
 formatting of data is heavily frowned upon. Doing these things may get
-you publicly humiliated and your code rewritten without notice. 
+you publicly humiliated and your code rewritten without notice.
 
 
-An attribute definition is simply:
+An attribute definition is simply::
 
-struct attribute {
-        char                    * name;
-        struct module          *owner;
-        umode_t                 mode;
-};
+    struct attribute {
+           char                    * name;
+           struct module               *owner;
+           umode_t                 mode;
+    };
 
 
-int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
-void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
+    int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
+    void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
 
 
 A bare attribute contains no means to read or write the value of the
 attribute. Subsystems are encouraged to define their own attribute
 structure and wrapper functions for adding and removing attributes for
-a specific object type. 
+a specific object type.
 
-For example, the driver model defines struct device_attribute like:
+For example, the driver model defines struct device_attribute like::
 
-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);
-};
+    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);
+    };
 
-int device_create_file(struct device *, const struct device_attribute *);
-void device_remove_file(struct device *, const struct device_attribute *);
+    int device_create_file(struct device *, const struct device_attribute *);
+    void device_remove_file(struct device *, const struct device_attribute *);
 
-It also defines this helper for defining device attributes: 
+It also defines this helper for defining device attributes::
 
-#define DEVICE_ATTR(_name, _mode, _show, _store) \
-struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
+    #define DEVICE_ATTR(_name, _mode, _show, _store) \
+    struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
 
-For example, declaring
+For example, declaring::
 
-static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
+    static DEVICE_ATTR(foo, S_IWUSR | S_IRUGO, show_foo, store_foo);
 
-is equivalent to doing:
+is equivalent to doing::
 
-static struct device_attribute dev_attr_foo = {
-       .attr = {
-               .name = "foo",
-               .mode = S_IWUSR | S_IRUGO,
-       },
-       .show = show_foo,
-       .store = store_foo,
-};
+    static struct device_attribute dev_attr_foo = {
+           .attr = {
+                   .name = "foo",
+                   .mode = S_IWUSR | S_IRUGO,
+           },
+           .show = show_foo,
+           .store = store_foo,
+    };
 
 Note as stated in include/linux/kernel.h "OTHER_WRITABLE?  Generally
 considered a bad idea." so trying to set a sysfs file writable for
@@ -127,15 +131,21 @@ readable. The above case could be shortened to:
 static struct device_attribute dev_attr_foo = __ATTR_RW(foo);
 
 the list of helpers available to define your wrapper function is:
-__ATTR_RO(name): assumes default name_show and mode 0444
-__ATTR_WO(name): assumes a name_store only and is restricted to mode
+
+__ATTR_RO(name):
+                assumes default name_show and mode 0444
+__ATTR_WO(name):
+                assumes a name_store only and is restricted to mode
                  0200 that is root write access only.
-__ATTR_RO_MODE(name, mode): fore more restrictive RO access currently
+__ATTR_RO_MODE(name, mode):
+                fore more restrictive RO access currently
                  only use case is the EFI System Resource Table
                  (see drivers/firmware/efi/esrt.c)
-__ATTR_RW(name): assumes default name_show, name_store and setting
+__ATTR_RW(name):
+                assumes default name_show, name_store and setting
                  mode to 0644.
-__ATTR_NULL: which sets the name to NULL and is used as end of list
+__ATTR_NULL:
+                which sets the name to NULL and is used as end of list
                  indicator (see: kernel/workqueue.c)
 
 Subsystem-Specific Callbacks
@@ -143,12 +153,12 @@ Subsystem-Specific Callbacks
 
 When a subsystem defines a new attribute type, it must implement a
 set of sysfs operations for forwarding read and write calls to the
-show and store methods of the attribute owners
+show and store methods of the attribute owners::
 
-struct sysfs_ops {
-        ssize_t (*show)(struct kobject *, struct attribute *, char *);
-        ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
-};
+    struct sysfs_ops {
+           ssize_t (*show)(struct kobject *, struct attribute *, char *);
+           ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
+    };
 
 [ Subsystems should have already defined a struct kobj_type as a
 descriptor for this type, which is where the sysfs_ops pointer is
@@ -157,29 +167,29 @@ stored. See the kobject documentation for more information. ]
 When a file is read or written, sysfs calls the appropriate method
 for the type. The method then translates the generic struct kobject
 and struct attribute pointers to the appropriate pointer types, and
-calls the associated methods. 
+calls the associated methods.
 
 
-To illustrate:
+To illustrate::
 
-#define to_dev(obj) container_of(obj, struct device, kobj)
-#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
+    #define to_dev(obj) container_of(obj, struct device, kobj)
+    #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
 
-static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
-                             char *buf)
-{
-        struct device_attribute *dev_attr = to_dev_attr(attr);
-        struct device *dev = to_dev(kobj);
-        ssize_t ret = -EIO;
+    static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr,
+                               char *buf)
+    {
+           struct device_attribute *dev_attr = to_dev_attr(attr);
+           struct device *dev = to_dev(kobj);
+           ssize_t ret = -EIO;
 
-        if (dev_attr->show)
-                ret = dev_attr->show(dev, dev_attr, buf);
-        if (ret >= (ssize_t)PAGE_SIZE) {
-                printk("dev_attr_show: %pS returned bad count\n",
-                                dev_attr->show);
-        }
-        return ret;
-}
+           if (dev_attr->show)
+                   ret = dev_attr->show(dev, dev_attr, buf);
+           if (ret >= (ssize_t)PAGE_SIZE) {
+                   printk("dev_attr_show: %pS returned bad count\n",
+                                   dev_attr->show);
+           }
+           return ret;
+    }
 
 
 
@@ -188,11 +198,11 @@ Reading/Writing Attribute Data
 
 To read or write attributes, show() or store() methods must be
 specified when declaring the attribute. The method types should be as
-simple as those defined for device attributes:
+simple as those defined for device attributes::
 
-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);
+    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);
 
 IOW, they should take only an object, an attribute, and a buffer as parameters.
 
@@ -200,11 +210,11 @@ IOW, they should take only an object, an attribute, and a buffer as parameters.
 sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the
 method. Sysfs will call the method exactly once for each read or
 write. This forces the following behavior on the method
-implementations: 
+implementations:
 
-- On read(2), the show() method should fill the entire buffer. 
+- On read(2), the show() method should fill the entire buffer.
   Recall that an attribute should only be exporting one value, or an
-  array of similar values, so this shouldn't be that expensive. 
+  array of similar values, so this shouldn't be that expensive.
 
   This allows userspace to do partial reads and forward seeks
   arbitrarily over the entire file at will. If userspace seeks back to
@@ -218,10 +228,10 @@ implementations:
 
   When writing sysfs files, userspace processes should first read the
   entire file, modify the values it wishes to change, then write the
-  entire buffer back. 
+  entire buffer back.
 
   Attribute method implementations should operate on an identical
-  buffer when reading and writing values. 
+  buffer when reading and writing values.
 
 Other notes:
 
@@ -229,7 +239,7 @@ Other notes:
   file position.
 
 - The buffer will always be PAGE_SIZE bytes in length. On i386, this
-  is 4096. 
+  is 4096.
 
 - show() methods should return the number of bytes printed into the
   buffer. This is the return value of scnprintf().
@@ -246,31 +256,31 @@ Other notes:
   through, be sure to return an error.
 
 - The object passed to the methods will be pinned in memory via sysfs
-  referencing counting its embedded object. However, the physical 
-  entity (e.g. device) the object represents may not be present. Be 
-  sure to have a way to check this, if necessary. 
+  referencing counting its embedded object. However, the physical
+  entity (e.g. device) the object represents may not be present. Be
+  sure to have a way to check this, if necessary.
 
 
-A very simple (and naive) implementation of a device attribute is:
+A very simple (and naive) implementation of a device attribute is::
 
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
-                         char *buf)
-{
-       return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
-}
+    static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+    {
+           return scnprintf(buf, PAGE_SIZE, "%s\n", dev->name);
+    }
 
-static ssize_t store_name(struct device *dev, struct device_attribute *attr,
-                          const char *buf, size_t count)
-{
-        snprintf(dev->name, sizeof(dev->name), "%.*s",
-                 (int)min(count, sizeof(dev->name) - 1), buf);
-       return count;
-}
+    static ssize_t store_name(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t count)
+    {
+           snprintf(dev->name, sizeof(dev->name), "%.*s",
+                   (int)min(count, sizeof(dev->name) - 1), buf);
+           return count;
+    }
 
-static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
+    static DEVICE_ATTR(name, S_IRUGO, show_name, store_name);
 
 
-(Note that the real implementation doesn't allow userspace to set the 
+(Note that the real implementation doesn't allow userspace to set the
 name for a device.)
 
 
@@ -278,25 +288,25 @@ Top Level Directory Layout
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The sysfs directory arrangement exposes the relationship of kernel
-data structures. 
+data structures.
 
-The top level sysfs directory looks like:
+The top level sysfs directory looks like::
 
-block/
-bus/
-class/
-dev/
-devices/
-firmware/
-net/
-fs/
+    block/
+    bus/
+    class/
+    dev/
+    devices/
+    firmware/
+    net/
+    fs/
 
 devices/ contains a filesystem representation of the device tree. It maps
 directly to the internal kernel device tree, which is a hierarchy of
-struct device. 
+struct device.
 
 bus/ contains flat directory layout of the various bus types in the
-kernel. Each bus's directory contains two subdirectories:
+kernel. Each bus's directory contains two subdirectories::
 
        devices/
        drivers/
@@ -331,71 +341,71 @@ Current Interfaces
 The following interface layers currently exist in sysfs:
 
 
-devices (include/linux/device.h)
-----------------------------------
-Structure:
+devices (include/linux/device.h)
+--------------------------------
+Structure::
 
-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);
-};
+    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);
+    };
 
-Declaring:
+Declaring::
 
-DEVICE_ATTR(_name, _mode, _show, _store);
+    DEVICE_ATTR(_name, _mode, _show, _store);
 
-Creation/Removal:
+Creation/Removal::
 
-int device_create_file(struct device *dev, const struct device_attribute * attr);
-void device_remove_file(struct device *dev, const struct device_attribute * attr);
+    int device_create_file(struct device *dev, const struct device_attribute * attr);
+    void device_remove_file(struct device *dev, const struct device_attribute * attr);
 
 
-bus drivers (include/linux/device.h)
---------------------------------------
-Structure:
+bus drivers (include/linux/device.h)
+------------------------------------
+Structure::
 
-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);
-};
+    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);
+    };
 
-Declaring:
+Declaring::
 
-static BUS_ATTR_RW(name);
-static BUS_ATTR_RO(name);
-static BUS_ATTR_WO(name);
+    static BUS_ATTR_RW(name);
+    static BUS_ATTR_RO(name);
+    static BUS_ATTR_WO(name);
 
-Creation/Removal:
+Creation/Removal::
 
-int bus_create_file(struct bus_type *, struct bus_attribute *);
-void bus_remove_file(struct bus_type *, struct bus_attribute *);
+    int bus_create_file(struct bus_type *, struct bus_attribute *);
+    void bus_remove_file(struct bus_type *, struct bus_attribute *);
 
 
-device drivers (include/linux/device.h)
------------------------------------------
+device drivers (include/linux/device.h)
+---------------------------------------
 
-Structure:
+Structure::
 
-struct driver_attribute {
-        struct attribute        attr;
-        ssize_t (*show)(struct device_driver *, char * buf);
-        ssize_t (*store)(struct device_driver *, const char * buf,
-                         size_t count);
-};
+    struct driver_attribute {
+           struct attribute        attr;
+           ssize_t (*show)(struct device_driver *, char * buf);
+           ssize_t (*store)(struct device_driver *, const char * buf,
+                           size_t count);
+    };
 
-Declaring:
+Declaring::
 
-DRIVER_ATTR_RO(_name)
-DRIVER_ATTR_RW(_name)
+    DRIVER_ATTR_RO(_name)
+    DRIVER_ATTR_RW(_name)
 
-Creation/Removal:
+Creation/Removal::
 
-int driver_create_file(struct device_driver *, const struct driver_attribute *);
-void driver_remove_file(struct device_driver *, const struct driver_attribute *);
+    int driver_create_file(struct device_driver *, const struct driver_attribute *);
+    void driver_remove_file(struct device_driver *, const struct driver_attribute *);
 
 
 Documentation
similarity index 73%
rename from Documentation/filesystems/sysv-fs.txt
rename to Documentation/filesystems/sysv-fs.rst
index 253b50d..89e4091 100644 (file)
@@ -1,25 +1,40 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==================
+SystemV Filesystem
+==================
+
 It implements all of
   - Xenix FS,
   - SystemV/386 FS,
   - Coherent FS.
 
 To install:
+
 * Answer the 'System V and Coherent filesystem support' question with 'y'
   when configuring the kernel.
-* To mount a disk or a partition, use
+* To mount a disk or a partition, use::
+
     mount [-r] -t sysv device mountpoint
-  The file system type names
+
+  The file system type names::
+
                -t sysv
                -t xenix
                -t coherent
+
   may be used interchangeably, but the last two will eventually disappear.
 
 Bugs in the present implementation:
+
 - Coherent FS:
+
   - The "free list interleave" n:m is currently ignored.
   - Only file systems with no filesystem name and no pack name are recognized.
-  (See Coherent "man mkfs" for a description of these features.)
+    (See Coherent "man mkfs" for a description of these features.)
+
 - SystemV Release 2 FS:
+
   The superblock is only searched in the blocks 9, 15, 18, which
   corresponds to the beginning of track 1 on floppy disks. No support
   for this FS on hard disk yet.
@@ -28,12 +43,14 @@ Bugs in the present implementation:
 These filesystems are rather similar. Here is a comparison with Minix FS:
 
 * Linux fdisk reports on partitions
+
   - Minix FS     0x81 Linux/Minix
   - Xenix FS     ??
   - SystemV FS   ??
   - Coherent FS  0x08 AIX bootable
 
 * Size of a block or zone (data allocation unit on disk)
+
   - Minix FS     1024
   - Xenix FS     1024 (also 512 ??)
   - SystemV FS   1024 (also 512 and 2048)
@@ -45,37 +62,51 @@ These filesystems are rather similar. Here is a comparison with Minix FS:
   all the block numbers (including the super block) are offset by one track.
 
 * Byte ordering of "short" (16 bit entities) on disk:
+
   - Minix FS     little endian  0 1
   - Xenix FS     little endian  0 1
   - SystemV FS   little endian  0 1
   - Coherent FS  little endian  0 1
+
   Of course, this affects only the file system, not the data of files on it!
 
 * Byte ordering of "long" (32 bit entities) on disk:
+
   - Minix FS     little endian  0 1 2 3
   - Xenix FS     little endian  0 1 2 3
   - SystemV FS   little endian  0 1 2 3
   - Coherent FS  PDP-11         2 3 0 1
+
   Of course, this affects only the file system, not the data of files on it!
 
 * Inode on disk: "short", 0 means non-existent, the root dir ino is:
-  - Minix FS                            1
-  - Xenix FS, SystemV FS, Coherent FS   2
+
+  =================================  ==
+  Minix FS                            1
+  Xenix FS, SystemV FS, Coherent FS   2
+  =================================  ==
 
 * Maximum number of hard links to a file:
-  - Minix FS     250
-  - Xenix FS     ??
-  - SystemV FS   ??
-  - Coherent FS  >=10000
+
+  ===========  =========
+  Minix FS     250
+  Xenix FS     ??
+  SystemV FS   ??
+  Coherent FS  >=10000
+  ===========  =========
 
 * Free inode management:
-  - Minix FS                             a bitmap
+
+  - Minix FS
+      a bitmap
   - Xenix FS, SystemV FS, Coherent FS
       There is a cache of a certain number of free inodes in the super-block.
       When it is exhausted, new free inodes are found using a linear search.
 
 * Free block management:
-  - Minix FS                             a bitmap
+
+  - Minix FS
+      a bitmap
   - Xenix FS, SystemV FS, Coherent FS
       Free blocks are organized in a "free list". Maybe a misleading term,
       since it is not true that every free block contains a pointer to
@@ -86,13 +117,18 @@ These filesystems are rather similar. Here is a comparison with Minix FS:
       0 on Xenix FS and SystemV FS, with a block zeroed out on Coherent FS.
 
 * Super-block location:
-  - Minix FS     block 1 = bytes 1024..2047
-  - Xenix FS     block 1 = bytes 1024..2047
-  - SystemV FS   bytes 512..1023
-  - Coherent FS  block 1 = bytes 512..1023
+
+  ===========  ==========================
+  Minix FS     block 1 = bytes 1024..2047
+  Xenix FS     block 1 = bytes 1024..2047
+  SystemV FS   bytes 512..1023
+  Coherent FS  block 1 = bytes 512..1023
+  ===========  ==========================
 
 * Super-block layout:
-  - Minix FS
+
+  - Minix FS::
+
                     unsigned short s_ninodes;
                     unsigned short s_nzones;
                     unsigned short s_imap_blocks;
@@ -101,7 +137,9 @@ These filesystems are rather similar. Here is a comparison with Minix FS:
                     unsigned short s_log_zone_size;
                     unsigned long s_max_size;
                     unsigned short s_magic;
-  - Xenix FS, SystemV FS, Coherent FS
+
+  - Xenix FS, SystemV FS, Coherent FS::
+
                     unsigned short s_firstdatazone;
                     unsigned long  s_nzones;
                     unsigned short s_fzone_count;
@@ -120,23 +158,33 @@ These filesystems are rather similar. Here is a comparison with Minix FS:
                     unsigned short s_interleave_m,s_interleave_n; -- Coherent FS only
                     char           s_fname[6];
                     char           s_fpack[6];
+
     then they differ considerably:
-        Xenix FS
+
+        Xenix FS::
+
                     char           s_clean;
                     char           s_fill[371];
                     long           s_magic;
                     long           s_type;
-        SystemV FS
+
+        SystemV FS::
+
                     long           s_fill[12 or 14];
                     long           s_state;
                     long           s_magic;
                     long           s_type;
-        Coherent FS
+
+        Coherent FS::
+
                     unsigned long  s_unique;
+
     Note that Coherent FS has no magic.
 
 * Inode layout:
-  - Minix FS
+
+  - Minix FS::
+
                     unsigned short i_mode;
                     unsigned short i_uid;
                     unsigned long  i_size;
@@ -144,7 +192,9 @@ These filesystems are rather similar. Here is a comparison with Minix FS:
                     unsigned char  i_gid;
                     unsigned char  i_nlinks;
                     unsigned short i_zone[7+1+1];
-  - Xenix FS, SystemV FS, Coherent FS
+
+  - Xenix FS, SystemV FS, Coherent FS::
+
                     unsigned short i_mode;
                     unsigned short i_nlink;
                     unsigned short i_uid;
@@ -155,38 +205,55 @@ These filesystems are rather similar. Here is a comparison with Minix FS:
                     unsigned long  i_mtime;
                     unsigned long  i_ctime;
 
+
 * Regular file data blocks are organized as
-  - Minix FS
-               7 direct blocks
-               1 indirect block (pointers to blocks)
-               1 double-indirect block (pointer to pointers to blocks)
-  - Xenix FS, SystemV FS, Coherent FS
-              10 direct blocks
-               1 indirect block (pointers to blocks)
-               1 double-indirect block (pointer to pointers to blocks)
-               1 triple-indirect block (pointer to pointers to pointers to blocks)
 
-* Inode size, inodes per block
-  - Minix FS        32   32
-  - Xenix FS        64   16
-  - SystemV FS      64   16
-  - Coherent FS     64    8
+  - Minix FS:
+
+             - 7 direct blocks
+            - 1 indirect block (pointers to blocks)
+             - 1 double-indirect block (pointer to pointers to blocks)
+
+  - Xenix FS, SystemV FS, Coherent FS:
+
+             - 10 direct blocks
+             -  1 indirect block (pointers to blocks)
+             -  1 double-indirect block (pointer to pointers to blocks)
+             -  1 triple-indirect block (pointer to pointers to pointers to blocks)
+
+
+  ===========  ==========   ================
+               Inode size   inodes per block
+  ===========  ==========   ================
+  Minix FS        32        32
+  Xenix FS        64        16
+  SystemV FS      64        16
+  Coherent FS     64        8
+  ===========  ==========   ================
 
 * Directory entry on disk
-  - Minix FS
+
+  - Minix FS::
+
                     unsigned short inode;
                     char name[14/30];
-  - Xenix FS, SystemV FS, Coherent FS
+
+  - Xenix FS, SystemV FS, Coherent FS::
+
                     unsigned short inode;
                     char name[14];
 
-* Dir entry size, dir entries per block
-  - Minix FS     16/32    64/32
-  - Xenix FS     16       64
-  - SystemV FS   16       64
-  - Coherent FS  16       32
+  ===========    ==============    =====================
+                 Dir entry size    dir entries per block
+  ===========    ==============    =====================
+  Minix FS       16/32             64/32
+  Xenix FS       16                64
+  SystemV FS     16                64
+  Coherent FS    16                32
+  ===========    ==============    =====================
 
 * How to implement symbolic links such that the host fsck doesn't scream:
+
   - Minix FS     normal
   - Xenix FS     kludge: as regular files with  chmod 1000
   - SystemV FS   ??
similarity index 86%
rename from Documentation/filesystems/tmpfs.txt
rename to Documentation/filesystems/tmpfs.rst
index 5ecbc03..4e95929 100644 (file)
@@ -1,3 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====
+Tmpfs
+=====
+
 Tmpfs is a file system which keeps all files in virtual memory.
 
 
@@ -14,7 +20,7 @@ If you compare it to ramfs (which was the template to create tmpfs)
 you gain swapping and limit checking. Another similar thing is the RAM
 disk (/dev/ram*), which simulates a fixed size hard disk in physical
 RAM, where you have to create an ordinary filesystem on top. Ramdisks
-cannot swap and you do not have the possibility to resize them. 
+cannot swap and you do not have the possibility to resize them.
 
 Since tmpfs lives completely in the page cache and on swap, all tmpfs
 pages will be shown as "Shmem" in /proc/meminfo and "Shared" in
@@ -26,7 +32,7 @@ tmpfs has the following uses:
 
 1) There is always a kernel internal mount which you will not see at
    all. This is used for shared anonymous mappings and SYSV shared
-   memory. 
+   memory.
 
    This mount does not depend on CONFIG_TMPFS. If CONFIG_TMPFS is not
    set, the user visible part of tmpfs is not build. But the internal
@@ -34,7 +40,7 @@ tmpfs has the following uses:
 
 2) glibc 2.2 and above expects tmpfs to be mounted at /dev/shm for
    POSIX shared memory (shm_open, shm_unlink). Adding the following
-   line to /etc/fstab should take care of this:
+   line to /etc/fstab should take care of this::
 
        tmpfs   /dev/shm        tmpfs   defaults        0 0
 
@@ -56,15 +62,17 @@ tmpfs has the following uses:
 
 tmpfs has three mount options for sizing:
 
-size:      The limit of allocated bytes for this tmpfs instance. The 
+=========  ============================================================
+size       The limit of allocated bytes for this tmpfs instance. The
            default is half of your physical RAM without swap. If you
            oversize your tmpfs instances the machine will deadlock
            since the OOM handler will not be able to free that memory.
-nr_blocks: The same as size, but in blocks of PAGE_SIZE.
-nr_inodes: The maximum number of inodes for this instance. The default
+nr_blocks  The same as size, but in blocks of PAGE_SIZE.
+nr_inodes  The maximum number of inodes for this instance. The default
            is half of the number of your physical RAM pages, or (on a
            machine with highmem) the number of lowmem RAM pages,
            whichever is the lower.
+=========  ============================================================
 
 These parameters accept a suffix k, m or g for kilo, mega and giga and
 can be changed on remount.  The size parameter also accepts a suffix %
@@ -82,6 +90,7 @@ tmpfs has a mount option to set the NUMA memory allocation policy for
 all files in that instance (if CONFIG_NUMA is enabled) - which can be
 adjusted on the fly via 'mount -o remount ...'
 
+======================== ==============================================
 mpol=default             use the process allocation policy
                          (see set_mempolicy(2))
 mpol=prefer:Node         prefers to allocate memory from the given Node
@@ -89,6 +98,7 @@ mpol=bind:NodeList       allocates memory only from nodes in NodeList
 mpol=interleave          prefers to allocate from each node in turn
 mpol=interleave:NodeList allocates from each node of NodeList in turn
 mpol=local              prefers to allocate memory from the local node
+======================== ==============================================
 
 NodeList format is a comma-separated list of decimal numbers and ranges,
 a range being two hyphen-separated decimal numbers, the smallest and
@@ -98,9 +108,9 @@ A memory policy with a valid NodeList will be saved, as specified, for
 use at file creation time.  When a task allocates a file in the file
 system, the mount option memory policy will be applied with a NodeList,
 if any, modified by the calling task's cpuset constraints
-[See Documentation/admin-guide/cgroup-v1/cpusets.rst] and any optional flags, listed
-below.  If the resulting NodeLists is the empty set, the effective memory
-policy for the file will revert to "default" policy.
+[See Documentation/admin-guide/cgroup-v1/cpusets.rst] and any optional flags,
+listed below.  If the resulting NodeLists is the empty set, the effective
+memory policy for the file will revert to "default" policy.
 
 NUMA memory allocation policies have optional flags that can be used in
 conjunction with their modes.  These optional flags can be specified
@@ -109,6 +119,8 @@ See Documentation/admin-guide/mm/numa_memory_policy.rst for a list of
 all available memory allocation policy mode flags and their effect on
 memory policy.
 
+::
+
        =static         is equivalent to        MPOL_F_STATIC_NODES
        =relative       is equivalent to        MPOL_F_RELATIVE_NODES
 
@@ -128,9 +140,11 @@ on MountPoint, by 'mount -o remount,mpol=Policy:NodeList MountPoint'.
 To specify the initial root directory you can use the following mount
 options:
 
-mode:  The permissions as an octal number
-uid:   The user id 
-gid:   The group id
+====   ==================================
+mode   The permissions as an octal number
+uid    The user id
+gid    The group id
+====   ==================================
 
 These options do not have any effect on remount. You can change these
 parameters with chmod(1), chown(1) and chgrp(1) on a mounted filesystem.
@@ -141,9 +155,9 @@ will give you tmpfs instance on /mytmpfs which can allocate 10GB
 RAM/SWAP in 10240 inodes and it is only accessible by root.
 
 
-Author:
+:Author:
    Christoph Rohland <cr@sap.com>, 1.12.01
-Updated:
+:Updated:
    Hugh Dickins, 4 June 2007
-Updated:
+:Updated:
    KOSAKI Motohiro, 16 Mar 2010
index 6a9584f..16efd72 100644 (file)
@@ -1,3 +1,5 @@
+.. SPDX-License-Identifier: GPL-2.0
+
 :orphan:
 
 .. UBIFS Authentication
@@ -92,11 +94,11 @@ UBIFS Index & Tree Node Cache
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Basic on-flash UBIFS entities are called *nodes*. UBIFS knows different types
-of nodes. Eg. data nodes (`struct ubifs_data_node`) which store chunks of file
-contents or inode nodes (`struct ubifs_ino_node`) which represent VFS inodes.
-Almost all types of nodes share a common header (`ubifs_ch`) containing basic
+of nodes. Eg. data nodes (``struct ubifs_data_node``) which store chunks of file
+contents or inode nodes (``struct ubifs_ino_node``) which represent VFS inodes.
+Almost all types of nodes share a common header (``ubifs_ch``) containing basic
 information like node type, node length, a sequence number, etc. (see
-`fs/ubifs/ubifs-media.h`in kernel source). Exceptions are entries of the LPT
+``fs/ubifs/ubifs-media.h`` in kernel source). Exceptions are entries of the LPT
 and some less important node types like padding nodes which are used to pad
 unusable content at the end of LEBs.
 
similarity index 91%
rename from Documentation/filesystems/ubifs.txt
rename to Documentation/filesystems/ubifs.rst
index acc8044..e6ee997 100644 (file)
@@ -1,5 +1,11 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+===============
+UBI File System
+===============
+
 Introduction
-=============
+============
 
 UBIFS file-system stands for UBI File System. UBI stands for "Unsorted
 Block Images". UBIFS is a flash file system, which means it is designed
@@ -79,6 +85,7 @@ Mount options
 
 (*) == default.
 
+====================   =======================================================
 bulk_read              read more in one go to take advantage of flash
                        media that read faster sequentially
 no_bulk_read (*)       do not bulk-read
@@ -98,6 +105,7 @@ auth_key=            specify the key used for authenticating the filesystem.
 auth_hash_name=                The hash algorithm used for authentication. Used for
                        both hashing and for creating HMACs. Typical values
                        include "sha256" or "sha512"
+====================   =======================================================
 
 
 Quick usage instructions
@@ -107,12 +115,14 @@ The UBI volume to mount is specified using "ubiX_Y" or "ubiX:NAME" syntax,
 where "X" is UBI device number, "Y" is UBI volume number, and "NAME" is
 UBI volume name.
 
-Mount volume 0 on UBI device 0 to /mnt/ubifs:
-$ mount -t ubifs ubi0_0 /mnt/ubifs
+Mount volume 0 on UBI device 0 to /mnt/ubifs::
+
+    $ mount -t ubifs ubi0_0 /mnt/ubifs
 
 Mount "rootfs" volume of UBI device 0 to /mnt/ubifs ("rootfs" is volume
-name):
-$ mount -t ubifs ubi0:rootfs /mnt/ubifs
+name)::
+
+    $ mount -t ubifs ubi0:rootfs /mnt/ubifs
 
 The following is an example of the kernel boot arguments to attach mtd0
 to UBI and mount volume "rootfs":
@@ -122,5 +132,6 @@ References
 ==========
 
 UBIFS documentation and FAQ/HOWTO at the MTD web site:
-http://www.linux-mtd.infradead.org/doc/ubifs.html
-http://www.linux-mtd.infradead.org/faq/ubifs.html
+
+- http://www.linux-mtd.infradead.org/doc/ubifs.html
+- http://www.linux-mtd.infradead.org/faq/ubifs.html
similarity index 83%
rename from Documentation/filesystems/udf.txt
rename to Documentation/filesystems/udf.rst
index e2f2faf..d9badbf 100644 (file)
@@ -1,6 +1,8 @@
-*
-* Documentation/filesystems/udf.txt
-*
+.. SPDX-License-Identifier: GPL-2.0
+
+===============
+UDF file system
+===============
 
 If you encounter problems with reading UDF discs using this driver,
 please report them according to MAINTAINERS file.
@@ -18,8 +20,10 @@ performance due to very poor read-modify-write support supplied internally
 by drive firmware.
 
 -------------------------------------------------------------------------------
+
 The following mount options are supported:
 
+       ===========     ======================================
        gid=            Set the default group.
        umask=          Set the default umask.
        mode=           Set the default file permissions.
@@ -34,6 +38,7 @@ The following mount options are supported:
        longad          Use long ad's (default)
        nostrict        Unset strict conformance
        iocharset=      Set the NLS character set
+       ===========     ======================================
 
 The uid= and gid= options need a bit more explaining.  They will accept a
 decimal numeric value and all inodes on that mount will then appear as
@@ -47,13 +52,17 @@ the interactive user will always see the files on the disk as belonging to him.
 
 The remaining are for debugging and disaster recovery:
 
-       novrs           Skip volume sequence recognition 
+       =====           ================================
+       novrs           Skip volume sequence recognition
+       =====           ================================
 
 The following expect a offset from 0.
 
+       ==========      =================================================
        session=        Set the CDROM session (default= last session)
        anchor=         Override standard anchor location. (default= 256)
        lastblock=      Set the last block of the filesystem/
+       ==========      =================================================
 
 -------------------------------------------------------------------------------
 
@@ -62,5 +71,5 @@ For the latest version and toolset see:
        https://github.com/pali/udftools
 
 Documentation on UDF and ECMA 167 is available FREE from:
-       http://www.osta.org/
-       http://www.ecma-international.org/
+       http://www.osta.org/
+       http://www.ecma-international.org/
index 4f338e3..e06e495 100644 (file)
@@ -1,5 +1,7 @@
 .. SPDX-License-Identifier: GPL-2.0
 
+.. _virtiofs_index:
+
 ===================================================
 virtiofs: virtio-fs host<->guest shared file system
 ===================================================
similarity index 86%
rename from Documentation/filesystems/zonefs.txt
rename to Documentation/filesystems/zonefs.rst
index d54fa98..71d845c 100644 (file)
@@ -1,4 +1,8 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+================================================
 ZoneFS - Zone filesystem for Zoned block devices
+================================================
 
 Introduction
 ============
@@ -29,6 +33,7 @@ Zoned block devices
 Zoned storage devices belong to a class of storage devices with an address
 space that is divided into zones. A zone is a group of consecutive LBAs and all
 zones are contiguous (there are no LBA gaps). Zones may have different types.
+
 * Conventional zones: there are no access constraints to LBAs belonging to
   conventional zones. Any read or write access can be executed, similarly to a
   regular block device.
@@ -158,6 +163,7 @@ Format options
 --------------
 
 Several optional features of zonefs can be enabled at format time.
+
 * Conventional zone aggregation: ranges of contiguous conventional zones can be
   aggregated into a single larger file instead of the default one file per zone.
 * File ownership: The owner UID and GID of zone files is by default 0 (root)
@@ -249,7 +255,7 @@ permissions.
 Further action taken by zonefs I/O error recovery can be controlled by the user
 with the "errors=xxx" mount option. The table below summarizes the result of
 zonefs I/O error processing depending on the mount option and on the zone
-conditions.
+conditions::
 
     +--------------+-----------+-----------------------------------------+
     |              |           |            Post error state             |
@@ -258,11 +264,11 @@ conditions.
     |    option    | condition | size     read    write    read    write |
     +--------------+-----------+-----------------------------------------+
     |              | good      | fixed    yes     no       yes     yes   |
-    | remount-ro   | read-only | fixed    yes     no       yes     no    |
+    | remount-ro   | read-only | as is    yes     no       yes     no    |
     | (default)    | offline   |   0      no      no       no      no    |
     +--------------+-----------+-----------------------------------------+
     |              | good      | fixed    yes     no       yes     yes   |
-    | zone-ro      | read-only | fixed    yes     no       yes     no    |
+    | zone-ro      | read-only | as is    yes     no       yes     no    |
     |              | offline   |   0      no      no       no      no    |
     +--------------+-----------+-----------------------------------------+
     |              | good      |   0      no      no       yes     yes   |
@@ -270,11 +276,12 @@ conditions.
     |              | offline   |   0      no      no       no      no    |
     +--------------+-----------+-----------------------------------------+
     |              | good      | fixed    yes     yes      yes     yes   |
-    | repair       | read-only | fixed    yes     no       yes     no    |
+    | repair       | read-only | as is    yes     no       yes     no    |
     |              | offline   |   0      no      no       no      no    |
     +--------------+-----------+-----------------------------------------+
 
 Further notes:
+
 * The "errors=remount-ro" mount option is the default behavior of zonefs I/O
   error processing if no errors mount option is specified.
 * With the "errors=remount-ro" mount option, the change of the file access
@@ -302,13 +309,22 @@ Mount options
 zonefs define the "errors=<behavior>" mount option to allow the user to specify
 zonefs behavior in response to I/O errors, inode size inconsistencies or zone
 condition changes. The defined behaviors are as follow:
+
 * remount-ro (default)
 * zone-ro
 * zone-offline
 * repair
 
-The I/O error actions defined for each behavior are detailed in the previous
-section.
+The run-time I/O error actions defined for each behavior are detailed in the
+previous section. Mount time I/O errors will cause the mount operation to fail.
+The handling of read-only zones also differs between mount-time and run-time.
+If a read-only zone is found at mount time, the zone is always treated in the
+same manner as offline zones, that is, all accesses are disabled and the zone
+file size set to 0. This is necessary as the write pointer of read-only zones
+is defined as invalib by the ZBC and ZAC standards, making it impossible to
+discover the amount of data that has been written to the zone. In the case of a
+read-only zone discovered at run-time, as indicated in the previous section.
+the size of the zone file is left unchanged from its last updated value.
 
 Zonefs User Space Tools
 =======================
@@ -325,78 +341,78 @@ Examples
 --------
 
 The following formats a 15TB host-managed SMR HDD with 256 MB zones
-with the conventional zones aggregation feature enabled.
+with the conventional zones aggregation feature enabled::
 
-# mkzonefs -o aggr_cnv /dev/sdX
-# mount -t zonefs /dev/sdX /mnt
-# ls -l /mnt/
-total 0
-dr-xr-xr-x 2 root root     1 Nov 25 13:23 cnv
-dr-xr-xr-x 2 root root 55356 Nov 25 13:23 seq
+    # mkzonefs -o aggr_cnv /dev/sdX
+    # mount -t zonefs /dev/sdX /mnt
+    # ls -l /mnt/
+    total 0
+    dr-xr-xr-x 2 root root     1 Nov 25 13:23 cnv
+    dr-xr-xr-x 2 root root 55356 Nov 25 13:23 seq
 
 The size of the zone files sub-directories indicate the number of files
 existing for each type of zones. In this example, there is only one
 conventional zone file (all conventional zones are aggregated under a single
-file).
+file)::
 
-# ls -l /mnt/cnv
-total 137101312
--rw-r----- 1 root root 140391743488 Nov 25 13:23 0
+    # ls -l /mnt/cnv
+    total 137101312
+    -rw-r----- 1 root root 140391743488 Nov 25 13:23 0
 
-This aggregated conventional zone file can be used as a regular file.
+This aggregated conventional zone file can be used as a regular file::
 
-# mkfs.ext4 /mnt/cnv/0
-# mount -o loop /mnt/cnv/0 /data
+    # mkfs.ext4 /mnt/cnv/0
+    # mount -o loop /mnt/cnv/0 /data
 
 The "seq" sub-directory grouping files for sequential write zones has in this
-example 55356 zones.
+example 55356 zones::
 
-# ls -lv /mnt/seq
-total 14511243264
--rw-r----- 1 root root 0 Nov 25 13:23 0
--rw-r----- 1 root root 0 Nov 25 13:23 1
--rw-r----- 1 root root 0 Nov 25 13:23 2
-...
--rw-r----- 1 root root 0 Nov 25 13:23 55354
--rw-r----- 1 root root 0 Nov 25 13:23 55355
+    # ls -lv /mnt/seq
+    total 14511243264
+    -rw-r----- 1 root root 0 Nov 25 13:23 0
+    -rw-r----- 1 root root 0 Nov 25 13:23 1
+    -rw-r----- 1 root root 0 Nov 25 13:23 2
+    ...
+    -rw-r----- 1 root root 0 Nov 25 13:23 55354
+    -rw-r----- 1 root root 0 Nov 25 13:23 55355
 
 For sequential write zone files, the file size changes as data is appended at
-the end of the file, similarly to any regular file system.
+the end of the file, similarly to any regular file system::
 
-# dd if=/dev/zero of=/mnt/seq/0 bs=4096 count=1 conv=notrunc oflag=direct
-1+0 records in
-1+0 records out
-4096 bytes (4.1 kB, 4.0 KiB) copied, 0.00044121 s, 9.3 MB/s
+    # dd if=/dev/zero of=/mnt/seq/0 bs=4096 count=1 conv=notrunc oflag=direct
+    1+0 records in
+    1+0 records out
+    4096 bytes (4.1 kB, 4.0 KiB) copied, 0.00044121 s, 9.3 MB/s
 
-# ls -l /mnt/seq/0
--rw-r----- 1 root root 4096 Nov 25 13:23 /mnt/seq/0
+    # ls -l /mnt/seq/0
+    -rw-r----- 1 root root 4096 Nov 25 13:23 /mnt/seq/0
 
 The written file can be truncated to the zone size, preventing any further
-write operation.
+write operation::
 
-# truncate -s 268435456 /mnt/seq/0
-# ls -l /mnt/seq/0
--rw-r----- 1 root root 268435456 Nov 25 13:49 /mnt/seq/0
+    # truncate -s 268435456 /mnt/seq/0
+    # ls -l /mnt/seq/0
+    -rw-r----- 1 root root 268435456 Nov 25 13:49 /mnt/seq/0
 
 Truncation to 0 size allows freeing the file zone storage space and restart
-append-writes to the file.
+append-writes to the file::
 
-# truncate -s 0 /mnt/seq/0
-# ls -l /mnt/seq/0
--rw-r----- 1 root root 0 Nov 25 13:49 /mnt/seq/0
+    # truncate -s 0 /mnt/seq/0
+    # ls -l /mnt/seq/0
+    -rw-r----- 1 root root 0 Nov 25 13:49 /mnt/seq/0
 
 Since files are statically mapped to zones on the disk, the number of blocks of
-a file as reported by stat() and fstat() indicates the size of the file zone.
-
-# stat /mnt/seq/0
-  File: /mnt/seq/0
-  Size: 0              Blocks: 524288     IO Block: 4096   regular empty file
-Device: 870h/2160d     Inode: 50431       Links: 1
-Access: (0640/-rw-r-----)  Uid: (    0/    root)   Gid: (    0/    root)
-Access: 2019-11-25 13:23:57.048971997 +0900
-Modify: 2019-11-25 13:52:25.553805765 +0900
-Change: 2019-11-25 13:52:25.553805765 +0900
- Birth: -
+a file as reported by stat() and fstat() indicates the size of the file zone::
+
+    # stat /mnt/seq/0
+    File: /mnt/seq/0
+    Size: 0            Blocks: 524288     IO Block: 4096   regular empty file
+    Device: 870h/2160d Inode: 50431       Links: 1
+    Access: (0640/-rw-r-----)  Uid: (    0/    root)   Gid: (    0/    root)
+    Access: 2019-11-25 13:23:57.048971997 +0900
+    Modify: 2019-11-25 13:52:25.553805765 +0900
+    Change: 2019-11-25 13:52:25.553805765 +0900
   Birth: -
 
 The number of blocks of the file ("Blocks") in units of 512B blocks gives the
 maximum file size of 524288 * 512 B = 256 MB, corresponding to the device zone
index e539c42..cc74e24 100644 (file)
@@ -207,10 +207,10 @@ DPIO
 CSR firmware support for DMC
 ----------------------------
 
-.. kernel-doc:: drivers/gpu/drm/i915/intel_csr.c
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_csr.c
    :doc: csr support for dmc
 
-.. kernel-doc:: drivers/gpu/drm/i915/intel_csr.c
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_csr.c
    :internal:
 
 Video BIOS Table (VBT)
index c81e0b4..471be1e 100644 (file)
@@ -20,8 +20,7 @@ Usage Notes
 -----------
 
 This driver does not auto-detect devices. You will have to instantiate the
-devices explicitly. Please see Documentation/i2c/instantiating-devices for
-details.
+devices explicitly. Please see :doc:`/i2c/instantiating-devices` for details.
 
 
 Sysfs entries
index b24adb6..8ef62fd 100644 (file)
@@ -162,6 +162,7 @@ Hardware Monitoring Kernel Drivers
    tmp421
    tmp513
    tps40422
+   tps53679
    twl4030-madc-hwmon
    ucd9000
    ucd9200
index a5a7c85..cc4b614 100644 (file)
@@ -3,7 +3,7 @@ Kernel driver isl68137
 
 Supported chips:
 
-  * Intersil ISL68137
+  * Renesas ISL68137
 
     Prefix: 'isl68137'
 
@@ -11,19 +11,405 @@ Supported chips:
 
     Datasheet:
 
-      Publicly available at the Intersil website
-      https://www.intersil.com/content/dam/Intersil/documents/isl6/isl68137.pdf
+      Publicly available at the Renesas website
+      https://www.renesas.com/us/en/www/doc/datasheet/isl68137.pdf
+
+  * Renesas ISL68220
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68221
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68222
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68223
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68224
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68225
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68226
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68227
+
+    Prefix: 'raa_dmpvr2_1rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68229
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68233
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL68239
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69222
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69223
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69224
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69225
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69227
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69228
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69234
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69236
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69239
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69242
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69243
+
+    Prefix: 'raa_dmpvr2_1rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69247
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69248
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69254
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69255
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69256
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69259
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69260
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69268
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69269
+
+    Prefix: 'raa_dmpvr2_3rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas ISL69298
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas RAA228000
+
+    Prefix: 'raa_dmpvr2_hv'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas RAA228004
+
+    Prefix: 'raa_dmpvr2_hv'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas RAA228006
+
+    Prefix: 'raa_dmpvr2_hv'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas RAA228228
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas RAA229001
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
+
+  * Renesas RAA229004
+
+    Prefix: 'raa_dmpvr2_2rail'
+
+    Addresses scanned: -
+
+    Datasheet:
+
+      Publicly available (after August 2020 launch) at the Renesas website
 
 Authors:
       - Maxim Sloyko <maxims@google.com>
       - Robert Lippert <rlippert@google.com>
       - Patrick Venture <venture@google.com>
+      - Grant Peltier <grant.peltier.jg@renesas.com>
 
 Description
 -----------
 
-Intersil ISL68137 is a digital output 7-phase configurable PWM
-controller with an AVSBus interface.
+This driver supports the Renesas ISL68137 and all 2nd generation Renesas
+digital multiphase voltage regulators (raa_dmpvr2). The ISL68137 is a digital
+output 7-phase configurable PWM controller with an AVSBus interface. 2nd
+generation devices are grouped into 4 distinct configurations: '1rail' for
+single-rail devices, '2rail' for dual-rail devices, '3rail' for 3-rail devices,
+and 'hv' for high voltage single-rail devices. Consult the individual datasheets
+for more information.
 
 Usage Notes
 -----------
@@ -33,10 +419,14 @@ devices explicitly.
 
 The ISL68137 AVS operation mode must be enabled/disabled at runtime.
 
-Beyond the normal sysfs pmbus attributes, the driver exposes a control attribute.
+Beyond the normal sysfs pmbus attributes, the driver exposes a control attribute
+for the ISL68137.
+
+For 2nd generation Renesas digital multiphase voltage regulators, only the
+normal sysfs pmbus attributes are supported.
 
-Additional Sysfs attributes
----------------------------
+ISL68137 sysfs attributes
+-------------------------
 
 ======================= ====================================
 avs(0|1)_enable                Controls the AVS state of each rail.
@@ -78,3 +468,138 @@ 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
 ======================= ====================================
+
+raa_dmpvr2_1rail/hv sysfs attributes
+------------------------------------
+
+======================= ==========================================
+curr1_label            "iin"
+curr1_input            Measured input current
+curr1_crit             Critical maximum current
+curr1_crit_alarm       Current critical high alarm
+
+curr2_label            "iout"
+curr2_input            Measured output current
+curr2_crit             Critical maximum current
+curr2_crit_alarm       Current critical high alarm
+
+in1_label              "vin"
+in1_input              Measured input voltage
+in1_lcrit              Critical minimum input voltage
+in1_lcrit_alarm                Input voltage critical low alarm
+in1_crit               Critical maximum input voltage
+in1_crit_alarm         Input voltage critical high alarm
+
+in2_label              "vmon"
+in2_input              Scaled VMON voltage read from the VMON pin
+
+in3_label              "vout"
+in3_input              Measured output voltage
+in3_lcrit              Critical minimum output voltage
+in3_lcrit_alarm         Output voltage critical low alarm
+in3_crit               Critical maximum output voltage
+in3_crit_alarm          Output voltage critical high alarm
+
+power1_label           "pin"
+power1_input           Measured input power
+power1_alarm           Input power high alarm
+
+power2_label           "pout"
+power2_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
+======================= ==========================================
+
+raa_dmpvr2_2rail sysfs attributes
+---------------------------------
+
+======================= ==========================================
+curr[1-2]_label                "iin[1-2]"
+curr[1-2]_input                Measured input current
+curr[1-2]_crit         Critical maximum current
+curr[1-2]_crit_alarm   Current critical high alarm
+
+curr[3-4]_label                "iout[1-2]"
+curr[3-4]_input                Measured output current
+curr[3-4]_crit         Critical maximum current
+curr[3-4]_crit_alarm   Current critical high alarm
+
+in1_label              "vin"
+in1_input              Measured input voltage
+in1_lcrit              Critical minimum input voltage
+in1_lcrit_alarm                Input voltage critical low alarm
+in1_crit               Critical maximum input voltage
+in1_crit_alarm         Input voltage critical high alarm
+
+in2_label              "vmon"
+in2_input              Scaled VMON voltage read from the VMON pin
+
+in[3-4]_label          "vout[1-2]"
+in[3-4]_input          Measured output voltage
+in[3-4]_lcrit          Critical minimum output voltage
+in[3-4]_lcrit_alarm    Output voltage critical low alarm
+in[3-4]_crit           Critical maximum output voltage
+in[3-4]_crit_alarm     Output voltage critical high alarm
+
+power[1-2]_label       "pin[1-2]"
+power[1-2]_input       Measured input power
+power[1-2]_alarm       Input power high alarm
+
+power[3-4]_label       "pout[1-2]"
+power[3-4]_input       Measured output power
+
+temp[1-5]_input                Measured temperature
+temp[1-5]_crit         Critical high temperature
+temp[1-5]_crit_alarm   Chip temperature critical high alarm
+temp[1-5]_max          Maximum temperature
+temp[1-5]_max_alarm    Chip temperature high alarm
+======================= ==========================================
+
+raa_dmpvr2_3rail sysfs attributes
+---------------------------------
+
+======================= ==========================================
+curr[1-3]_label                "iin[1-3]"
+curr[1-3]_input                Measured input current
+curr[1-3]_crit         Critical maximum current
+curr[1-3]_crit_alarm   Current critical high alarm
+
+curr[4-6]_label                "iout[1-3]"
+curr[4-6]_input                Measured output current
+curr[4-6]_crit         Critical maximum current
+curr[4-6]_crit_alarm   Current critical high alarm
+
+in1_label              "vin"
+in1_input              Measured input voltage
+in1_lcrit              Critical minimum input voltage
+in1_lcrit_alarm                Input voltage critical low alarm
+in1_crit               Critical maximum input voltage
+in1_crit_alarm         Input voltage critical high alarm
+
+in2_label              "vmon"
+in2_input              Scaled VMON voltage read from the VMON pin
+
+in[3-5]_label          "vout[1-3]"
+in[3-5]_input          Measured output voltage
+in[3-5]_lcrit          Critical minimum output voltage
+in[3-5]_lcrit_alarm    Output voltage critical low alarm
+in[3-5]_crit           Critical maximum output voltage
+in[3-5]_crit_alarm     Output voltage critical high alarm
+
+power[1-3]_label       "pin[1-3]"
+power[1-3]_input       Measured input power
+power[1-3]_alarm       Input power high alarm
+
+power[4-6]_label       "pout[1-3]"
+power[4-6]_input       Measured output power
+
+temp[1-7]_input                Measured temperature
+temp[1-7]_crit         Critical high temperature
+temp[1-7]_crit_alarm   Chip temperature critical high alarm
+temp[1-7]_max          Maximum temperature
+temp[1-7]_max_alarm    Chip temperature high alarm
+======================= ==========================================
index 4451d59..8557e26 100644 (file)
@@ -100,9 +100,10 @@ socket type, not the processor's actual capabilities.  Therefore, if you
 are using an AM3 processor on an AM2+ mainboard, you can safely use the
 "force=1" parameter.
 
-There is one temperature measurement value, available as temp1_input in
-sysfs. It is measured in degrees Celsius with a resolution of 1/8th degree.
-Please note that it is defined as a relative value; to quote the AMD manual::
+For CPUs older than Family 17h, there is one temperature measurement value,
+available as temp1_input in sysfs. It is measured in degrees Celsius with a
+resolution of 1/8th degree.  Please note that it is defined as a relative
+value; to quote the AMD manual::
 
   Tctl is the processor temperature control value, used by the platform to
   control cooling systems. Tctl is a non-physical temperature on an
@@ -126,3 +127,25 @@ it.
 
 Models from 17h family report relative temperature, the driver aims to
 compensate and report the real temperature.
+
+On Family 17h and Family 18h CPUs, additional temperature sensors may report
+Core Complex Die (CCD) temperatures. Up to 8 such temperatures are reported
+as temp{3..10}_input, labeled Tccd{1..8}. Actual support depends on the CPU
+variant.
+
+Various Family 17h and 18h CPUs report voltage and current telemetry
+information. The following attributes may be reported.
+
+Attribute      Label   Description
+===============        ======= ================
+in0_input      Vcore   Core voltage
+in1_input      Vsoc    SoC voltage
+curr1_input    Icore   Core current
+curr2_input    Isoc    SoC current
+===============        ======= ================
+
+Current values are raw (unscaled) as reported by the CPU. Core current is
+reported as multiples of 1A / LSB. SoC is reported as multiples of 0.25A
+/ LSB. The real current is board specific. Reported currents should be seen
+as rough guidance, and should be scaled using sensors3.conf as appropriate
+for a given board.
index 01a24fd..bc5270e 100644 (file)
@@ -3,13 +3,21 @@ Kernel driver ltc2978
 
 Supported chips:
 
+  * Linear Technology LTC2972
+
+    Prefix: 'ltc2972'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/ltc2972.html
+
   * Linear Technology LTC2974
 
     Prefix: 'ltc2974'
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc2974
+    Datasheet: https://www.analog.com/en/products/ltc2974
 
   * Linear Technology LTC2975
 
@@ -17,7 +25,7 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc2975
+    Datasheet: https://www.analog.com/en/products/ltc2975
 
   * Linear Technology LTC2977
 
@@ -25,7 +33,7 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc2977
+    Datasheet: https://www.analog.com/en/products/ltc2977
 
   * Linear Technology LTC2978, LTC2978A
 
@@ -33,9 +41,17 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc2978
+    Datasheet: https://www.analog.com/en/products/ltc2978
+
+              https://www.analog.com/en/products/ltc2978a
+
+  * Linear Technology LTC2979
 
-              http://www.linear.com/product/ltc2978a
+    Prefix: 'ltc2979'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/ltc2979
 
   * Linear Technology LTC2980
 
@@ -43,7 +59,7 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc2980
+    Datasheet: https://www.analog.com/en/products/ltc2980
 
   * Linear Technology LTC3880
 
@@ -51,7 +67,7 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc3880
+    Datasheet: https://www.analog.com/en/products/ltc3880
 
   * Linear Technology LTC3882
 
@@ -59,7 +75,7 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc3882
+    Datasheet: https://www.analog.com/en/products/ltc3882
 
   * Linear Technology LTC3883
 
@@ -67,7 +83,15 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc3883
+    Datasheet: https://www.analog.com/en/products/ltc3883
+
+  * Linear Technology LTC3884
+
+    Prefix: 'ltc3884'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/ltc3884
 
   * Linear Technology LTC3886
 
@@ -75,7 +99,7 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc3886
+    Datasheet: https://www.analog.com/en/products/ltc3886
 
   * Linear Technology LTC3887
 
@@ -83,7 +107,23 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltc3887
+    Datasheet: https://www.analog.com/en/products/ltc3887
+
+  * Linear Technology LTC3889
+
+    Prefix: 'ltc3889'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/ltc3889
+
+  * Linear Technology LTC7880
+
+    Prefix: 'ltc7880'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/ltc7880
 
   * Linear Technology LTM2987
 
@@ -91,15 +131,23 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltm2987
+    Datasheet: https://www.analog.com/en/products/ltm2987
 
-  * Linear Technology LTM4675
+  * Linear Technology LTM4644
+
+    Prefix: 'ltm4644'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/ltm4644
+
+   * Linear Technology LTM4675
 
     Prefix: 'ltm4675'
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltm4675
+    Datasheet: https://www.analog.com/en/products/ltm4675
 
   * Linear Technology LTM4676
 
@@ -107,7 +155,31 @@ Supported chips:
 
     Addresses scanned: -
 
-    Datasheet: http://www.linear.com/product/ltm4676
+    Datasheet: https://www.analog.com/en/products/ltm4676
+
+  * Linear Technology LTM4677
+
+    Prefix: 'ltm4677'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/ltm4677
+
+  * Linear Technology LTM4678
+
+    Prefix: 'ltm4678'
+
+    Addresses scanned: -
+
+    Datasheet: https://www.analog.com/en/products/ltm4678
+
+  * Analog Devices LTM4680
+
+    Prefix: 'ltm4680'
+
+    Addresses scanned: -
+
+    Datasheet: http://www.analog.com/ltm4680
 
   * Analog Devices LTM4686
 
@@ -117,6 +189,15 @@ Supported chips:
 
     Datasheet: http://www.analog.com/ltm4686
 
+  * Analog Devices LTM4700
+
+    Prefix: 'ltm4700'
+
+    Addresses scanned: -
+
+    Datasheet: http://www.analog.com/ltm4700
+
+
 
 Author: Guenter Roeck <linux@roeck-us.net>
 
@@ -166,13 +247,13 @@ in1_min                   Minimum input voltage.
 
 in1_max                        Maximum input voltage.
 
-                       LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
-                       LTM2987 only.
+                       LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
+                       LTC2979 and LTM2987 only.
 
 in1_lcrit              Critical minimum input voltage.
 
-                       LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
-                       LTM2987 only.
+                       LTC2972, LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
+                       LTC2979 and LTM2987 only.
 
 in1_crit               Critical maximum input voltage.
 
@@ -180,29 +261,34 @@ in1_min_alarm             Input voltage low alarm.
 
 in1_max_alarm          Input voltage high alarm.
 
-                       LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
-                       LTM2987 only.
+                       LTC2972, LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
+                       LTC2979 and LTM2987 only.
+
 in1_lcrit_alarm                Input voltage critical low alarm.
 
-                       LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
-                       LTM2987 only.
+                       LTC2972, LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
+                       LTC2979 and LTM2987 only.
+
 in1_crit_alarm         Input voltage critical high alarm.
 
 in1_lowest             Lowest input voltage.
 
-                       LTC2974, LTC2975, LTC2977, LTC2980, LTC2978, and
-                       LTM2987 only.
+                       LTC2972, LTC2974, LTC2975, LTC2977, LTC2980, LTC2978,
+                       and LTM2987 only.
+
 in1_highest            Highest input voltage.
 
 in1_reset_history      Reset input voltage history.
 
 in[N]_label            "vout[1-8]".
 
+                       - LTC2972: N=2-3
                        - LTC2974, LTC2975: N=2-5
-                       - LTC2977, LTC2980, LTM2987: N=2-9
+                       - LTC2977, LTC2979, LTC2980, LTM2987: N=2-9
                        - LTC2978: N=2-9
-                       - LTC3880, LTC3882, LTC23886 LTC3887, LTM4675, LTM4676:
-                         N=2-3
+                       - LTC3880, LTC3882, LTC3884, LTC23886 LTC3887, LTC3889,
+                         LTC7880, LTM4644, LTM4675, LTM4676, LTM4677, LTM4678,
+                         LTM4680, LTM4700: N=2-3
                        - LTC3883: N=2
 
 in[N]_input            Measured output voltage.
@@ -225,8 +311,7 @@ in[N]_crit_alarm    Output voltage critical high alarm.
 
 in[N]_lowest           Lowest output voltage.
 
-
-                       LTC2974, LTC2975,and LTC2978 only.
+                       LTC2972, LTC2974, LTC2975,and LTC2978 only.
 
 in[N]_highest          Highest output voltage.
 
@@ -234,20 +319,24 @@ in[N]_reset_history       Reset output voltage history.
 
 temp[N]_input          Measured temperature.
 
+                       - On LTC2972, temp[1-2] report external temperatures,
+                         and temp 3 reports the chip temperature.
                        - On LTC2974 and LTC2975, temp[1-4] report external
                          temperatures, and temp5 reports the chip temperature.
-                       - On LTC2977, LTC2980, LTC2978, and LTM2987, only one
-                         temperature measurement is supported and reports
-                         the chip temperature.
-                       - On LTC3880, LTC3882, LTC3887, LTM4675, and LTM4676,
-                         temp1 and temp2 report external temperatures, and
-                         temp3 reports the chip temperature.
+                       - On LTC2977, LTC2979, LTC2980, LTC2978, and LTM2987,
+                         only one temperature measurement is supported and
+                         reports the chip temperature.
+                       - On LTC3880, LTC3882, LTC3886, LTC3887, LTC3889,
+                         LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680,
+                         and LTM4700, temp1 and temp2 report external
+                         temperatures, and temp3 reports the chip temperature.
                        - On LTC3883, temp1 reports an external temperature,
                          and temp2 reports the chip temperature.
 
 temp[N]_min            Mimimum temperature.
 
-                       LTC2974, LCT2977, LTM2980, LTC2978, and LTM2987 only.
+                       LTC2972, LTC2974, LCT2977, LTM2980, LTC2978,
+                       LTC2979, and LTM2987 only.
 
 temp[N]_max            Maximum temperature.
 
@@ -257,8 +346,8 @@ temp[N]_crit                Critical high temperature.
 
 temp[N]_min_alarm      Temperature low alarm.
 
-                       LTC2974, LTC2975, LTC2977, LTM2980, LTC2978, and
-                       LTM2987 only.
+                       LTC2972, LTC2974, LTC2975, LTC2977, LTM2980, LTC2978,
+                       LTC2979, and LTM2987 only.
 
 temp[N]_max_alarm      Temperature high alarm.
 
@@ -269,8 +358,8 @@ temp[N]_crit_alarm  Temperature critical high alarm.
 
 temp[N]_lowest         Lowest measured temperature.
 
-                       - LTC2974, LTC2975, LTC2977, LTM2980, LTC2978, and
-                         LTM2987 only.
+                       - LTC2972, LTC2974, LTC2975, LTC2977, LTM2980, LTC2978,
+                         LTC2979, and LTM2987 only.
                        - Not supported for chip temperature sensor on LTC2974
                          and LTC2975.
 
@@ -290,19 +379,22 @@ power1_input              Measured input power.
 
 power[N]_label         "pout[1-4]".
 
+                       - LTC2972: N=1-2
                        - LTC2974, LTC2975: N=1-4
-                       - LTC2977, LTC2980, LTM2987: Not supported
+                       - LTC2977, LTC2979, LTC2980, LTM2987: Not supported
                        - LTC2978: Not supported
-                       - LTC3880, LTC3882, LTC3886, LTC3887, LTM4675, LTM4676:
-                         N=1-2
+                       - LTC3880, LTC3882, LTC3884, LTC3886, LTC3887, LTC3889,
+                         LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680,
+                         LTM4700: N=1-2
                        - LTC3883: N=2
 
 power[N]_input         Measured output power.
 
 curr1_label            "iin".
 
-                       LTC3880, LTC3883, LTC3886, LTC3887, LTM4675,
-                       and LTM4676 only.
+                       LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889,
+                       LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680,
+                       and LTM4700 only.
 
 curr1_input            Measured input current.
 
@@ -320,11 +412,13 @@ curr1_reset_history       Reset input current history.
 
 curr[N]_label          "iout[1-4]".
 
+                       - LTC2972: N-1-2
                        - LTC2974, LTC2975: N=1-4
-                       - LTC2977, LTC2980, LTM2987: not supported
+                       - LTC2977, LTC2979, LTC2980, LTM2987: not supported
                        - LTC2978: not supported
-                       - LTC3880, LTC3882, LTC3886, LTC3887, LTM4675, LTM4676:
-                         N=2-3
+                       - LTC3880, LTC3882, LTC3884, LTC3886, LTC3887, LTC3889,
+                         LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680,
+                         LTM4700: N=2-3
                        - LTC3883: N=2
 
 curr[N]_input          Measured output current.
@@ -335,7 +429,7 @@ curr[N]_crit                Critical high output current.
 
 curr[N]_lcrit          Critical low output current.
 
-                       LTC2974 and LTC2975 only.
+                       LTC2972, LTC2974 and LTC2975 only.
 
 curr[N]_max_alarm      Output current high alarm.
 
@@ -343,11 +437,11 @@ curr[N]_crit_alarm        Output current critical high alarm.
 
 curr[N]_lcrit_alarm    Output current critical low alarm.
 
-                       LTC2974 and LTC2975 only.
+                       LTC2972, LTC2974 and LTC2975 only.
 
 curr[N]_lowest         Lowest output current.
 
-                       LTC2974 and LTC2975 only.
+                       LTC2972, LTC2974 and LTC2975 only.
 
 curr[N]_highest                Highest output current.
 
index 92515c4..501b37b 100644 (file)
@@ -162,9 +162,12 @@ Read byte from page <page>, register <reg>.
 
 ::
 
-  int (*read_word_data)(struct i2c_client *client, int page, int reg);
+  int (*read_word_data)(struct i2c_client *client, int page, int phase,
+                        int reg);
 
-Read word from page <page>, register <reg>.
+Read word from page <page>, phase <pase>, register <reg>. If the chip does not
+support multiple phases, the phase parameter can be ignored. If the chip
+supports multiple phases, a phase value of 0xff indicates all phases.
 
 ::
 
@@ -201,16 +204,21 @@ is mandatory.
 
 ::
 
-  int pmbus_set_page(struct i2c_client *client, u8 page);
+  int pmbus_set_page(struct i2c_client *client, u8 page, u8 phase);
 
-Set PMBus page register to <page> for subsequent commands.
+Set PMBus page register to <page> and <phase> for subsequent commands.
+If the chip does not support multiple phases, the phase parameter is
+ignored. Otherwise, a phase value of 0xff selects all phases.
 
 ::
 
-  int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
+  int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 phase,
+                           u8 reg);
 
-Read word data from <page>, <reg>. Similar to i2c_smbus_read_word_data(), but
-selects page first.
+Read word data from <page>, <phase>, <reg>. Similar to
+i2c_smbus_read_word_data(), but selects page and phase first. If the chip does
+not support multiple phases, the phase parameter is ignored. Otherwise, a phase
+value of 0xff selects all phases.
 
 ::
 
index f787984..2658dde 100644 (file)
@@ -227,7 +227,9 @@ currX_lcrit_alarm   Output current critical low alarm.
                        From IOUT_UC_FAULT status.
 currX_crit_alarm       Current critical high alarm.
                        From IIN_OC_FAULT or IOUT_OC_FAULT status.
-currX_label            "iin" or "ioutY"
+currX_label            "iin", "iinY", "iinY.Z", "ioutY", or "ioutY.Z",
+                       where Y reflects the page number and Z reflects the
+                       phase.
 
 powerX_input           Measured power. From READ_PIN or READ_POUT register.
 powerX_cap             Output power cap. From POUT_MAX register.
@@ -239,7 +241,9 @@ powerX_alarm                Power high alarm.
                        From PIN_OP_WARNING or POUT_OP_WARNING status.
 powerX_crit_alarm      Output power critical high alarm.
                        From POUT_OP_FAULT status.
-powerX_label           "pin" or "poutY"
+powerX_label           "pin", "pinY", "pinY.Z", "poutY", or "poutY.Z",
+                       where Y reflects the page number and Z reflects the
+                       phase.
 
 tempX_input            Measured temperature.
                        From READ_TEMPERATURE_X register.
diff --git a/Documentation/hwmon/tps53679.rst b/Documentation/hwmon/tps53679.rst
new file mode 100644 (file)
index 0000000..be94cab
--- /dev/null
@@ -0,0 +1,178 @@
+Kernel driver tps53679
+======================
+
+Supported chips:
+
+  * Texas Instruments TPS53647
+
+    Prefix: 'tps53647'
+
+    Addresses scanned: -
+
+    Datasheet: http://www.ti.com/lit/gpn/tps53647
+
+  * Texas Instruments TPS53667
+
+    Prefix: 'tps53667'
+
+    Addresses scanned: -
+
+    Datasheet: http://www.ti.com/lit/gpn/TPS53667
+
+  * Texas Instruments TPS53679
+
+    Prefix: 'tps53679'
+
+    Addresses scanned: -
+
+    Datasheet: http://www.ti.com/lit/gpn/TPS53679 (short version)
+
+  * Texas Instruments TPS53681
+
+    Prefix: 'tps53681'
+
+    Addresses scanned: -
+
+    Datasheet: http://www.ti.com/lit/gpn/TPS53681
+
+  * Texas Instruments TPS53688
+
+    Prefix: 'tps53688'
+
+    Addresses scanned: -
+
+    Datasheet: Available under NDA
+
+
+Authors:
+       Vadim Pasternak <vadimp@mellanox.com>
+       Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+Chips in this series are multi-phase step-down converters with one or two
+output channels and up to 8 phases per channel.
+
+
+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 TPS53681 at address
+0x60 on I2C bus #1::
+
+       # modprobe tps53679
+       # echo tps53681 0x60 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs attributes
+----------------
+
+======================= ========================================================
+in1_label              "vin"
+
+in1_input              Measured input voltage.
+
+in1_lcrit              Critical minimum input voltage
+
+                       TPS53679, TPS53681, TPS53688 only.
+
+in1_lcrit_alarm                Input voltage critical low alarm.
+
+                       TPS53679, TPS53681, TPS53688 only.
+
+in1_crit               Critical maximum input voltage.
+
+in1_crit_alarm         Input voltage critical high alarm.
+
+in[N]_label            "vout[1-2]"
+
+                       - TPS53647, TPS53667: N=2
+                       - TPS53679, TPS53588: N=2,3
+
+in[N]_input            Measured output voltage.
+
+in[N]_lcrit            Critical minimum input voltage.
+
+                       TPS53679, TPS53681, TPS53688 only.
+
+in[N]_lcrit_alarm      Critical minimum voltage alarm.
+
+                       TPS53679, TPS53681, TPS53688 only.
+
+in[N]_alarm            Output voltage alarm.
+
+                       TPS53647, TPS53667 only.
+
+in[N]_crit             Critical maximum output voltage.
+
+                       TPS53679, TPS53681, TPS53688 only.
+
+in[N]_crit_alarm       Output voltage critical high alarm.
+
+                       TPS53679, TPS53681, TPS53688 only.
+
+temp[N]_input          Measured temperature.
+
+                       - TPS53647, TPS53667: N=1
+                       - TPS53679, TPS53681, TPS53588: N=1,2
+
+temp[N]_max            Maximum temperature.
+
+temp[N]_crit           Critical high temperature.
+
+temp[N]_max_alarm      Temperature high alarm.
+
+temp[N]_crit_alarm     Temperature critical high alarm.
+
+power1_label           "pin".
+
+power1_input           Measured input power.
+
+power[N]_label         "pout[1-2]".
+
+                       - TPS53647, TPS53667: N=2
+                       - TPS53679, TPS53681, TPS53588: N=2,3
+
+power[N]_input         Measured output power.
+
+curr1_label            "iin".
+
+curr1_input            Measured input current.
+
+curr1_max              Maximum input current.
+
+curr1_max_alarm                Input current high alarm.
+
+curr1_crit             Critical input current.
+
+curr1_crit_alarm       Input current critical alarm.
+
+curr[N]_label          "iout[1-2]" or "iout1.[0-5]".
+
+                       The first digit is the output channel, the second
+                       digit is the phase within the channel. Per-phase
+                       telemetry supported on TPS53681 only.
+
+                       - TPS53647, TPS53667: N=2
+                       - TPS53679, TPS53588: N=2,3
+                       - TPS53681: N=2-9
+
+curr[N]_input          Measured output current.
+
+curr[N]_max            Maximum output current.
+
+curr[N]_crit           Critical high output current.
+
+curr[N]_max_alarm      Output current high alarm.
+
+curr[N]_crit_alarm     Output current critical high alarm.
+
+                       Limit and alarm attributes are only available for
+                       non-phase telemetry (iout1, iout2).
+
+======================= ========================================================
index e99d0bd..9df95ba 100644 (file)
@@ -99,6 +99,7 @@ needed).
    accounting/index
    block/index
    cdrom/index
+   cpu-freq/index
    ide/index
    fb/index
    fpga/index
@@ -131,7 +132,6 @@ needed).
    usb/index
    PCI/index
    misc-devices/index
-   mic/index
    scheduler/index
 
 Architecture-agnostic documentation
similarity index 98%
rename from Documentation/core-api/gcc-plugins.rst
rename to Documentation/kbuild/gcc-plugins.rst
index 8502f24..4b1c10f 100644 (file)
@@ -72,6 +72,10 @@ e.g., on Ubuntu for gcc-4.9::
 
        apt-get install gcc-4.9-plugin-dev
 
+Or on Fedora::
+
+       dnf install gcc-plugin-devel
+
 Enable a GCC plugin based feature in the kernel config::
 
        CONFIG_GCC_PLUGIN_CYC_COMPLEXITY = y
index 0f144fa..82daf2e 100644 (file)
@@ -19,6 +19,7 @@ Kernel Build System
 
     issues
     reproducible-builds
+    gcc-plugins
 
 .. only::  subproject and html
 
index f1e5dce..510f38d 100644 (file)
@@ -237,7 +237,7 @@ This is solely useful to speed up test compiles.
 KBUILD_EXTRA_SYMBOLS
 --------------------
 For modules that use symbols from other modules.
-See more details in modules.txt.
+See more details in modules.rst.
 
 ALLSOURCE_ARCHS
 ---------------
index 35b3263..8b413ef 100644 (file)
@@ -44,7 +44,7 @@ intermediate::
             def_bool y
 
 Then, Kconfig moves onto the evaluation stage to resolve inter-symbol
-dependency as explained in kconfig-language.txt.
+dependency as explained in kconfig-language.rst.
 
 
 Variables
index 0e0eb2c..04d5c01 100644 (file)
@@ -765,7 +765,7 @@ is not sufficient this sometimes needs to be explicit.
        Example::
 
                #arch/x86/boot/Makefile
-               subdir- := compressed/
+               subdir- := compressed
 
 The above assignment instructs kbuild to descend down in the
 directory compressed/ when "make clean" is executed.
@@ -924,7 +924,7 @@ When kbuild executes, the following steps are followed (roughly):
        $(KBUILD_AFLAGS_MODULE) is used to add arch-specific options that
        are used for assembler.
 
-       From commandline AFLAGS_MODULE shall be used (see kbuild.txt).
+       From commandline AFLAGS_MODULE shall be used (see kbuild.rst).
 
     KBUILD_CFLAGS_KERNEL
        $(CC) options specific for built-in
@@ -937,7 +937,7 @@ When kbuild executes, the following steps are followed (roughly):
 
        $(KBUILD_CFLAGS_MODULE) is used to add arch-specific options that
        are used for $(CC).
-       From commandline CFLAGS_MODULE shall be used (see kbuild.txt).
+       From commandline CFLAGS_MODULE shall be used (see kbuild.rst).
 
     KBUILD_LDFLAGS_MODULE
        Options for $(LD) when linking modules
@@ -945,7 +945,7 @@ When kbuild executes, the following steps are followed (roughly):
        $(KBUILD_LDFLAGS_MODULE) is used to add arch-specific options
        used when linking modules. This is often a linker script.
 
-       From commandline LDFLAGS_MODULE shall be used (see kbuild.txt).
+       From commandline LDFLAGS_MODULE shall be used (see kbuild.rst).
 
     KBUILD_LDS
 
@@ -1379,9 +1379,6 @@ See subsequent chapter for the syntax of the Kbuild file.
        in arch/$(ARCH)/include/(uapi/)/asm, Kbuild will automatically generate
        a wrapper of the asm-generic one.
 
-       The convention is to list one subdir per line and
-       preferably in alphabetic order.
-
 8 Kbuild Variables
 ==================
 
index 69fa48e..e0b45a2 100644 (file)
@@ -470,9 +470,9 @@ build.
 
        The syntax of the Module.symvers file is::
 
-       <CRC>       <Symbol>          <Namespace>  <Module>                         <Export Type>
+       <CRC>       <Symbol>         <Module>                         <Export Type>     <Namespace>
 
-       0xe1cc2a05  usb_stor_suspend  USB_STORAGE  drivers/usb/storage/usb-storage  EXPORT_SYMBOL_GPL
+       0xe1cc2a05  usb_stor_suspend drivers/usb/storage/usb-storage  EXPORT_SYMBOL_GPL USB_STORAGE
 
        The fields are separated by tabs and values may be empty (e.g.
        if no namespace is defined for an exported symbol).
index d62aacb..eed2136 100644 (file)
@@ -601,7 +601,7 @@ Defined in ``include/linux/export.h``
 
 This is the variant of `EXPORT_SYMBOL()` that allows specifying a symbol
 namespace. Symbol Namespaces are documented in
-``Documentation/core-api/symbol-namespaces.rst``.
+:doc:`../core-api/symbol-namespaces`
 
 :c:func:`EXPORT_SYMBOL_NS_GPL()`
 --------------------------------
@@ -610,7 +610,7 @@ Defined in ``include/linux/export.h``
 
 This is the variant of `EXPORT_SYMBOL_GPL()` that allows specifying a symbol
 namespace. Symbol Namespaces are documented in
-``Documentation/core-api/symbol-namespaces.rst``.
+:doc:`../core-api/symbol-namespaces`
 
 Routines and Conventions
 ========================
index a8518ac..6ed806e 100644 (file)
@@ -150,17 +150,17 @@ Locking Only In User Context
 If you have a data structure which is only ever accessed from user
 context, then you can use a simple mutex (``include/linux/mutex.h``) to
 protect it. This is the most trivial case: you initialize the mutex.
-Then you can call :c:func:`mutex_lock_interruptible()` to grab the
-mutex, and :c:func:`mutex_unlock()` to release it. There is also a
-:c:func:`mutex_lock()`, which should be avoided, because it will
+Then you can call mutex_lock_interruptible() to grab the
+mutex, and mutex_unlock() to release it. There is also a
+mutex_lock(), which should be avoided, because it will
 not return if a signal is received.
 
 Example: ``net/netfilter/nf_sockopt.c`` allows registration of new
-:c:func:`setsockopt()` and :c:func:`getsockopt()` calls, with
-:c:func:`nf_register_sockopt()`. Registration and de-registration
+setsockopt() and getsockopt() calls, with
+nf_register_sockopt(). Registration and de-registration
 are only done on module load and unload (and boot time, where there is
 no concurrency), and the list of registrations is only consulted for an
-unknown :c:func:`setsockopt()` or :c:func:`getsockopt()` system
+unknown setsockopt() or getsockopt() system
 call. The ``nf_sockopt_mutex`` is perfect to protect this, especially
 since the setsockopt and getsockopt calls may well sleep.
 
@@ -170,19 +170,19 @@ Locking Between User Context and Softirqs
 If a softirq shares data with user context, you have two problems.
 Firstly, the current user context can be interrupted by a softirq, and
 secondly, the critical region could be entered from another CPU. This is
-where :c:func:`spin_lock_bh()` (``include/linux/spinlock.h``) is
+where spin_lock_bh() (``include/linux/spinlock.h``) is
 used. It disables softirqs on that CPU, then grabs the lock.
-:c:func:`spin_unlock_bh()` does the reverse. (The '_bh' suffix is
+spin_unlock_bh() does the reverse. (The '_bh' suffix is
 a historical reference to "Bottom Halves", the old name for software
 interrupts. It should really be called spin_lock_softirq()' in a
 perfect world).
 
-Note that you can also use :c:func:`spin_lock_irq()` or
-:c:func:`spin_lock_irqsave()` here, which stop hardware interrupts
+Note that you can also use spin_lock_irq() or
+spin_lock_irqsave() here, which stop hardware interrupts
 as well: see `Hard IRQ Context <#hard-irq-context>`__.
 
 This works perfectly for UP as well: the spin lock vanishes, and this
-macro simply becomes :c:func:`local_bh_disable()`
+macro simply becomes local_bh_disable()
 (``include/linux/interrupt.h``), which protects you from the softirq
 being run.
 
@@ -216,8 +216,8 @@ Different Tasklets/Timers
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
 If another tasklet/timer wants to share data with your tasklet or timer
-, you will both need to use :c:func:`spin_lock()` and
-:c:func:`spin_unlock()` calls. :c:func:`spin_lock_bh()` is
+, you will both need to use spin_lock() and
+spin_unlock() calls. spin_lock_bh() is
 unnecessary here, as you are already in a tasklet, and none will be run
 on the same CPU.
 
@@ -234,14 +234,14 @@ The same softirq can run on the other CPUs: you can use a per-CPU array
 going so far as to use a softirq, you probably care about scalable
 performance enough to justify the extra complexity.
 
-You'll need to use :c:func:`spin_lock()` and
-:c:func:`spin_unlock()` for shared data.
+You'll need to use spin_lock() and
+spin_unlock() for shared data.
 
 Different Softirqs
 ~~~~~~~~~~~~~~~~~~
 
-You'll need to use :c:func:`spin_lock()` and
-:c:func:`spin_unlock()` for shared data, whether it be a timer,
+You'll need to use spin_lock() and
+spin_unlock() for shared data, whether it be a timer,
 tasklet, different softirq or the same or another softirq: any of them
 could be running on a different CPU.
 
@@ -259,38 +259,38 @@ If a hardware irq handler shares data with a softirq, you have two
 concerns. Firstly, the softirq processing can be interrupted by a
 hardware interrupt, and secondly, the critical region could be entered
 by a hardware interrupt on another CPU. This is where
-:c:func:`spin_lock_irq()` is used. It is defined to disable
+spin_lock_irq() is used. It is defined to disable
 interrupts on that cpu, then grab the lock.
-:c:func:`spin_unlock_irq()` does the reverse.
+spin_unlock_irq() does the reverse.
 
-The irq handler does not to use :c:func:`spin_lock_irq()`, because
+The irq handler does not need to use spin_lock_irq(), because
 the softirq cannot run while the irq handler is running: it can use
-:c:func:`spin_lock()`, which is slightly faster. The only exception
+spin_lock(), which is slightly faster. The only exception
 would be if a different hardware irq handler uses the same lock:
-:c:func:`spin_lock_irq()` will stop that from interrupting us.
+spin_lock_irq() will stop that from interrupting us.
 
 This works perfectly for UP as well: the spin lock vanishes, and this
-macro simply becomes :c:func:`local_irq_disable()`
+macro simply becomes local_irq_disable()
 (``include/asm/smp.h``), which protects you from the softirq/tasklet/BH
 being run.
 
-:c:func:`spin_lock_irqsave()` (``include/linux/spinlock.h``) is a
+spin_lock_irqsave() (``include/linux/spinlock.h``) is a
 variant which saves whether interrupts were on or off in a flags word,
-which is passed to :c:func:`spin_unlock_irqrestore()`. This means
+which is passed to spin_unlock_irqrestore(). This means
 that the same code can be used inside an hard irq handler (where
 interrupts are already off) and in softirqs (where the irq disabling is
 required).
 
 Note that softirqs (and hence tasklets and timers) are run on return
-from hardware interrupts, so :c:func:`spin_lock_irq()` also stops
-these. In that sense, :c:func:`spin_lock_irqsave()` is the most
+from hardware interrupts, so spin_lock_irq() also stops
+these. In that sense, spin_lock_irqsave() is the most
 general and powerful locking function.
 
 Locking Between Two Hard IRQ Handlers
 -------------------------------------
 
 It is rare to have to share data between two IRQ handlers, but if you
-do, :c:func:`spin_lock_irqsave()` should be used: it is
+do, spin_lock_irqsave() should be used: it is
 architecture-specific whether all interrupts are disabled inside irq
 handlers themselves.
 
@@ -304,11 +304,11 @@ Pete Zaitcev gives the following summary:
    (``copy_from_user*(`` or ``kmalloc(x,GFP_KERNEL)``).
 
 -  Otherwise (== data can be touched in an interrupt), use
-   :c:func:`spin_lock_irqsave()` and
-   :c:func:`spin_unlock_irqrestore()`.
+   spin_lock_irqsave() and
+   spin_unlock_irqrestore().
 
 -  Avoid holding spinlock for more than 5 lines of code and across any
-   function call (except accessors like :c:func:`readb()`).
+   function call (except accessors like readb()).
 
 Table of Minimum Requirements
 -----------------------------
@@ -320,7 +320,7 @@ particular thread can only run on one CPU at a time, but if it needs
 shares data with another thread, locking is required).
 
 Remember the advice above: you can always use
-:c:func:`spin_lock_irqsave()`, which is a superset of all other
+spin_lock_irqsave(), which is a superset of all other
 spinlock primitives.
 
 ============== ============= ============= ========= ========= ========= ========= ======= ======= ============== ==============
@@ -363,13 +363,13 @@ They can be used if you need no access to the data protected with the
 lock when some other thread is holding the lock. You should acquire the
 lock later if you then need access to the data protected with the lock.
 
-:c:func:`spin_trylock()` does not spin but returns non-zero if it
+spin_trylock() does not spin but returns non-zero if it
 acquires the spinlock on the first try or 0 if not. This function can be
-used in all contexts like :c:func:`spin_lock()`: you must have
+used in all contexts like spin_lock(): you must have
 disabled the contexts that might interrupt you and acquire the spin
 lock.
 
-:c:func:`mutex_trylock()` does not suspend your task but returns
+mutex_trylock() does not suspend your task but returns
 non-zero if it could lock the mutex on the first try or 0 if not. This
 function cannot be safely used in hardware or software interrupt
 contexts despite not sleeping.
@@ -490,14 +490,14 @@ easy, since we copy the data for the user, and never let them access the
 objects directly.
 
 There is a slight (and common) optimization here: in
-:c:func:`cache_add()` we set up the fields of the object before
+cache_add() we set up the fields of the object before
 grabbing the lock. This is safe, as no-one else can access it until we
 put it in cache.
 
 Accessing From Interrupt Context
 --------------------------------
 
-Now consider the case where :c:func:`cache_find()` can be called
+Now consider the case where cache_find() can be called
 from interrupt context: either a hardware interrupt or a softirq. An
 example would be a timer which deletes object from the cache.
 
@@ -566,16 +566,16 @@ which are taken away, and the ``+`` are lines which are added.
              return ret;
      }
 
-Note that the :c:func:`spin_lock_irqsave()` will turn off
+Note that the spin_lock_irqsave() will turn off
 interrupts if they are on, otherwise does nothing (if we are already in
 an interrupt handler), hence these functions are safe to call from any
 context.
 
-Unfortunately, :c:func:`cache_add()` calls :c:func:`kmalloc()`
+Unfortunately, cache_add() calls kmalloc()
 with the ``GFP_KERNEL`` flag, which is only legal in user context. I
-have assumed that :c:func:`cache_add()` is still only called in
+have assumed that cache_add() is still only called in
 user context, otherwise this should become a parameter to
-:c:func:`cache_add()`.
+cache_add().
 
 Exposing Objects Outside This File
 ----------------------------------
@@ -592,7 +592,7 @@ This makes locking trickier, as it is no longer all in one place.
 The second problem is the lifetime problem: if another structure keeps a
 pointer to an object, it presumably expects that pointer to remain
 valid. Unfortunately, this is only guaranteed while you hold the lock,
-otherwise someone might call :c:func:`cache_delete()` and even
+otherwise someone might call cache_delete() and even
 worse, add another object, re-using the same address.
 
 As there is only one lock, you can't hold it forever: no-one else would
@@ -693,8 +693,8 @@ Here is the code::
 
 We encapsulate the reference counting in the standard 'get' and 'put'
 functions. Now we can return the object itself from
-:c:func:`cache_find()` which has the advantage that the user can
-now sleep holding the object (eg. to :c:func:`copy_to_user()` to
+cache_find() which has the advantage that the user can
+now sleep holding the object (eg. to copy_to_user() to
 name to userspace).
 
 The other point to note is that I said a reference should be held for
@@ -710,7 +710,7 @@ number of atomic operations defined in ``include/asm/atomic.h``: these
 are guaranteed to be seen atomically from all CPUs in the system, so no
 lock is required. In this case, it is simpler than using spinlocks,
 although for anything non-trivial using spinlocks is clearer. The
-:c:func:`atomic_inc()` and :c:func:`atomic_dec_and_test()`
+atomic_inc() and atomic_dec_and_test()
 are used instead of the standard increment and decrement operators, and
 the lock is no longer used to protect the reference count itself.
 
@@ -802,7 +802,7 @@ name to change, there are three possibilities:
 -  You can make ``cache_lock`` non-static, and tell people to grab that
    lock before changing the name in any object.
 
--  You can provide a :c:func:`cache_obj_rename()` which grabs this
+-  You can provide a cache_obj_rename() which grabs this
    lock and changes the name for the caller, and tell everyone to use
    that function.
 
@@ -861,11 +861,11 @@ Note that I decide that the popularity count should be protected by the
 ``cache_lock`` rather than the per-object lock: this is because it (like
 the :c:type:`struct list_head <list_head>` inside the object)
 is logically part of the infrastructure. This way, I don't need to grab
-the lock of every object in :c:func:`__cache_add()` when seeking
+the lock of every object in __cache_add() when seeking
 the least popular.
 
 I also decided that the id member is unchangeable, so I don't need to
-grab each object lock in :c:func:`__cache_find()` to examine the
+grab each object lock in __cache_find() to examine the
 id: the object lock is only used by a caller who wants to read or write
 the name field.
 
@@ -887,7 +887,7 @@ trivial to diagnose: not a
 stay-up-five-nights-talk-to-fluffy-code-bunnies kind of problem.
 
 For a slightly more complex case, imagine you have a region shared by a
-softirq and user context. If you use a :c:func:`spin_lock()` call
+softirq and user context. If you use a spin_lock() call
 to protect it, it is possible that the user context will be interrupted
 by the softirq while it holds the lock, and the softirq will then spin
 forever trying to get the same lock.
@@ -985,12 +985,12 @@ you might do the following::
 
 
 Sooner or later, this will crash on SMP, because a timer can have just
-gone off before the :c:func:`spin_lock_bh()`, and it will only get
-the lock after we :c:func:`spin_unlock_bh()`, and then try to free
+gone off before the spin_lock_bh(), and it will only get
+the lock after we spin_unlock_bh(), and then try to free
 the element (which has already been freed!).
 
 This can be avoided by checking the result of
-:c:func:`del_timer()`: if it returns 1, the timer has been deleted.
+del_timer(): if it returns 1, the timer has been deleted.
 If 0, it means (in this case) that it is currently running, so we can
 do::
 
@@ -1012,9 +1012,9 @@ do::
 
 
 Another common problem is deleting timers which restart themselves (by
-calling :c:func:`add_timer()` at the end of their timer function).
+calling add_timer() at the end of their timer function).
 Because this is a fairly common case which is prone to races, you should
-use :c:func:`del_timer_sync()` (``include/linux/timer.h``) to
+use del_timer_sync() (``include/linux/timer.h``) to
 handle this case. It returns the number of times the timer had to be
 deleted before we finally stopped it from adding itself back in.
 
@@ -1086,7 +1086,7 @@ adding ``new`` to a single linked list called ``list``::
             list->next = new;
 
 
-The :c:func:`wmb()` is a write memory barrier. It ensures that the
+The wmb() is a write memory barrier. It ensures that the
 first operation (setting the new element's ``next`` pointer) is complete
 and will be seen by all CPUs, before the second operation is (putting
 the new element into the list). This is important, since modern
@@ -1097,7 +1097,7 @@ rest of the list.
 
 Fortunately, there is a function to do this for standard
 :c:type:`struct list_head <list_head>` lists:
-:c:func:`list_add_rcu()` (``include/linux/list.h``).
+list_add_rcu() (``include/linux/list.h``).
 
 Removing an element from the list is even simpler: we replace the
 pointer to the old element with a pointer to its successor, and readers
@@ -1108,7 +1108,7 @@ will either see it, or skip over it.
             list->next = old->next;
 
 
-There is :c:func:`list_del_rcu()` (``include/linux/list.h``) which
+There is list_del_rcu() (``include/linux/list.h``) which
 does this (the normal version poisons the old object, which we don't
 want).
 
@@ -1116,9 +1116,9 @@ The reader must also be careful: some CPUs can look through the ``next``
 pointer to start reading the contents of the next element early, but
 don't realize that the pre-fetched contents is wrong when the ``next``
 pointer changes underneath them. Once again, there is a
-:c:func:`list_for_each_entry_rcu()` (``include/linux/list.h``)
+list_for_each_entry_rcu() (``include/linux/list.h``)
 to help you. Of course, writers can just use
-:c:func:`list_for_each_entry()`, since there cannot be two
+list_for_each_entry(), since there cannot be two
 simultaneous writers.
 
 Our final dilemma is this: when can we actually destroy the removed
@@ -1127,14 +1127,14 @@ the list right now: if we free this element and the ``next`` pointer
 changes, the reader will jump off into garbage and crash. We need to
 wait until we know that all the readers who were traversing the list
 when we deleted the element are finished. We use
-:c:func:`call_rcu()` to register a callback which will actually
+call_rcu() to register a callback which will actually
 destroy the object once all pre-existing readers are finished.
-Alternatively, :c:func:`synchronize_rcu()` may be used to block
+Alternatively, synchronize_rcu() may be used to block
 until all pre-existing are finished.
 
 But how does Read Copy Update know when the readers are finished? The
 method is this: firstly, the readers always traverse the list inside
-:c:func:`rcu_read_lock()`/:c:func:`rcu_read_unlock()` pairs:
+rcu_read_lock()/rcu_read_unlock() pairs:
 these simply disable preemption so the reader won't go to sleep while
 reading the list.
 
@@ -1223,12 +1223,12 @@ this is the fundamental idea.
      }
 
 Note that the reader will alter the popularity member in
-:c:func:`__cache_find()`, and now it doesn't hold a lock. One
+__cache_find(), and now it doesn't hold a lock. One
 solution would be to make it an ``atomic_t``, but for this usage, we
 don't really care about races: an approximate result is good enough, so
 I didn't change it.
 
-The result is that :c:func:`cache_find()` requires no
+The result is that cache_find() requires no
 synchronization with any other functions, so is almost as fast on SMP as
 it would be on UP.
 
@@ -1240,9 +1240,9 @@ and put the reference count.
 
 Now, because the 'read lock' in RCU is simply disabling preemption, a
 caller which always has preemption disabled between calling
-:c:func:`cache_find()` and :c:func:`object_put()` does not
+cache_find() and object_put() does not
 need to actually get and put the reference count: we could expose
-:c:func:`__cache_find()` by making it non-static, and such
+__cache_find() by making it non-static, and such
 callers could simply call that.
 
 The benefit here is that the reference count is not written to: the
@@ -1260,11 +1260,11 @@ counter. Nice and simple.
 If that was too slow (it's usually not, but if you've got a really big
 machine to test on and can show that it is), you could instead use a
 counter for each CPU, then none of them need an exclusive lock. See
-:c:func:`DEFINE_PER_CPU()`, :c:func:`get_cpu_var()` and
-:c:func:`put_cpu_var()` (``include/linux/percpu.h``).
+DEFINE_PER_CPU(), get_cpu_var() and
+put_cpu_var() (``include/linux/percpu.h``).
 
 Of particular use for simple per-cpu counters is the ``local_t`` type,
-and the :c:func:`cpu_local_inc()` and related functions, which are
+and the cpu_local_inc() and related functions, which are
 more efficient than simple code on some architectures
 (``include/asm/local.h``).
 
@@ -1289,10 +1289,10 @@ irq handler doesn't use a lock, and all other accesses are done as so::
         enable_irq(irq);
         spin_unlock(&lock);
 
-The :c:func:`disable_irq()` prevents the irq handler from running
+The disable_irq() prevents the irq handler from running
 (and waits for it to finish if it's currently running on other CPUs).
 The spinlock prevents any other accesses happening at the same time.
-Naturally, this is slower than just a :c:func:`spin_lock_irq()`
+Naturally, this is slower than just a spin_lock_irq()
 call, so it only makes sense if this type of access happens extremely
 rarely.
 
@@ -1315,22 +1315,22 @@ from user context, and can sleep.
 
 -  Accesses to userspace:
 
-   -  :c:func:`copy_from_user()`
+   -  copy_from_user()
 
-   -  :c:func:`copy_to_user()`
+   -  copy_to_user()
 
-   -  :c:func:`get_user()`
+   -  get_user()
 
-   -  :c:func:`put_user()`
+   -  put_user()
 
--  :c:func:`kmalloc(GFP_KERNEL) <kmalloc>`
+-  kmalloc(GP_KERNEL) <kmalloc>`
 
--  :c:func:`mutex_lock_interruptible()` and
-   :c:func:`mutex_lock()`
+-  mutex_lock_interruptible() and
+   mutex_lock()
 
-   There is a :c:func:`mutex_trylock()` which does not sleep.
+   There is a mutex_trylock() which does not sleep.
    Still, it must not be used inside interrupt context since its
-   implementation is not safe for that. :c:func:`mutex_unlock()`
+   implementation is not safe for that. mutex_unlock()
    will also never sleep. It cannot be used in interrupt context either
    since a mutex must be released by the same task that acquired it.
 
@@ -1340,11 +1340,11 @@ Some Functions Which Don't Sleep
 Some functions are safe to call from any context, or holding almost any
 lock.
 
--  :c:func:`printk()`
+-  printk()
 
--  :c:func:`kfree()`
+-  kfree()
 
--  :c:func:`add_timer()` and :c:func:`del_timer()`
+-  add_timer() and del_timer()
 
 Mutex API reference
 ===================
@@ -1400,26 +1400,26 @@ preemption
 
 bh
   Bottom Half: for historical reasons, functions with '_bh' in them often
-  now refer to any software interrupt, e.g. :c:func:`spin_lock_bh()`
+  now refer to any software interrupt, e.g. spin_lock_bh()
   blocks any software interrupt on the current CPU. Bottom halves are
   deprecated, and will eventually be replaced by tasklets. Only one bottom
   half will be running at any time.
 
 Hardware Interrupt / Hardware IRQ
-  Hardware interrupt request. :c:func:`in_irq()` returns true in a
+  Hardware interrupt request. in_irq() returns true in a
   hardware interrupt handler.
 
 Interrupt Context
   Not user context: processing a hardware irq or software irq. Indicated
-  by the :c:func:`in_interrupt()` macro returning true.
+  by the in_interrupt() macro returning true.
 
 SMP
   Symmetric Multi-Processor: kernels compiled for multiple-CPU machines.
   (``CONFIG_SMP=y``).
 
 Software Interrupt / softirq
-  Software interrupt handler. :c:func:`in_irq()` returns false;
-  :c:func:`in_softirq()` returns true. Tasklets and softirqs both
+  Software interrupt handler. in_irq() returns false;
+  in_softirq() returns true. Tasklets and softirqs both
   fall into the category of 'software interrupts'.
 
   Strictly speaking a softirq is one of up to 32 enumerated software
index 3af3841..c61eea6 100644 (file)
@@ -128,6 +128,10 @@ since we already have a valid pointer that we own a refcount for.  The
 put needs no lock because nothing tries to get the data without
 already holding a pointer.
 
+In the above example, kref_put() will be called 2 times in both success
+and error paths. This is necessary because the reference count got
+incremented 2 times by kref_init() and kref_get().
+
 Note that the "before" in rule 1 is very important.  You should never
 do something like::
 
index 626a463..5d6800a 100644 (file)
@@ -7,6 +7,7 @@ locking
 .. toctree::
     :maxdepth: 1
 
+    locktypes
     lockdep-design
     lockstat
     locktorture
diff --git a/Documentation/locking/locktypes.rst b/Documentation/locking/locktypes.rst
new file mode 100644 (file)
index 0000000..09f45ce
--- /dev/null
@@ -0,0 +1,347 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _kernel_hacking_locktypes:
+
+==========================
+Lock types and their rules
+==========================
+
+Introduction
+============
+
+The kernel provides a variety of locking primitives which can be divided
+into two categories:
+
+ - Sleeping locks
+ - Spinning locks
+
+This document conceptually describes these lock types and provides rules
+for their nesting, including the rules for use under PREEMPT_RT.
+
+
+Lock categories
+===============
+
+Sleeping locks
+--------------
+
+Sleeping locks can only be acquired in preemptible task context.
+
+Although implementations allow try_lock() from other contexts, it is
+necessary to carefully evaluate the safety of unlock() as well as of
+try_lock().  Furthermore, it is also necessary to evaluate the debugging
+versions of these primitives.  In short, don't acquire sleeping locks from
+other contexts unless there is no other option.
+
+Sleeping lock types:
+
+ - mutex
+ - rt_mutex
+ - semaphore
+ - rw_semaphore
+ - ww_mutex
+ - percpu_rw_semaphore
+
+On PREEMPT_RT kernels, these lock types are converted to sleeping locks:
+
+ - spinlock_t
+ - rwlock_t
+
+Spinning locks
+--------------
+
+ - raw_spinlock_t
+ - bit spinlocks
+
+On non-PREEMPT_RT kernels, these lock types are also spinning locks:
+
+ - spinlock_t
+ - rwlock_t
+
+Spinning locks implicitly disable preemption and the lock / unlock functions
+can have suffixes which apply further protections:
+
+ ===================  ====================================================
+ _bh()                Disable / enable bottom halves (soft interrupts)
+ _irq()               Disable / enable interrupts
+ _irqsave/restore()   Save and disable / restore interrupt disabled state
+ ===================  ====================================================
+
+Owner semantics
+===============
+
+The aforementioned lock types except semaphores have strict owner
+semantics:
+
+  The context (task) that acquired the lock must release it.
+
+rw_semaphores have a special interface which allows non-owner release for
+readers.
+
+
+rtmutex
+=======
+
+RT-mutexes are mutexes with support for priority inheritance (PI).
+
+PI has limitations on non-PREEMPT_RT kernels due to preemption and
+interrupt disabled sections.
+
+PI clearly cannot preempt preemption-disabled or interrupt-disabled
+regions of code, even on PREEMPT_RT kernels.  Instead, PREEMPT_RT kernels
+execute most such regions of code in preemptible task context, especially
+interrupt handlers and soft interrupts.  This conversion allows spinlock_t
+and rwlock_t to be implemented via RT-mutexes.
+
+
+semaphore
+=========
+
+semaphore is a counting semaphore implementation.
+
+Semaphores are often used for both serialization and waiting, but new use
+cases should instead use separate serialization and wait mechanisms, such
+as mutexes and completions.
+
+semaphores and PREEMPT_RT
+----------------------------
+
+PREEMPT_RT does not change the semaphore implementation because counting
+semaphores have no concept of owners, thus preventing PREEMPT_RT from
+providing priority inheritance for semaphores.  After all, an unknown
+owner cannot be boosted. As a consequence, blocking on semaphores can
+result in priority inversion.
+
+
+rw_semaphore
+============
+
+rw_semaphore is a multiple readers and single writer lock mechanism.
+
+On non-PREEMPT_RT kernels the implementation is fair, thus preventing
+writer starvation.
+
+rw_semaphore complies by default with the strict owner semantics, but there
+exist special-purpose interfaces that allow non-owner release for readers.
+These interfaces work independent of the kernel configuration.
+
+rw_semaphore and PREEMPT_RT
+---------------------------
+
+PREEMPT_RT kernels map rw_semaphore to a separate rt_mutex-based
+implementation, thus changing the fairness:
+
+ Because an rw_semaphore writer cannot grant its priority to multiple
+ readers, a preempted low-priority reader will continue holding its lock,
+ thus starving even high-priority writers.  In contrast, because readers
+ can grant their priority to a writer, a preempted low-priority writer will
+ have its priority boosted until it releases the lock, thus preventing that
+ writer from starving readers.
+
+
+raw_spinlock_t and spinlock_t
+=============================
+
+raw_spinlock_t
+--------------
+
+raw_spinlock_t is a strict spinning lock implementation regardless of the
+kernel configuration including PREEMPT_RT enabled kernels.
+
+raw_spinlock_t is a strict spinning lock implementation in all kernels,
+including PREEMPT_RT kernels.  Use raw_spinlock_t only in real critical
+core code, low-level interrupt handling and places where disabling
+preemption or interrupts is required, for example, to safely access
+hardware state.  raw_spinlock_t can sometimes also be used when the
+critical section is tiny, thus avoiding RT-mutex overhead.
+
+spinlock_t
+----------
+
+The semantics of spinlock_t change with the state of PREEMPT_RT.
+
+On a non-PREEMPT_RT kernel spinlock_t is mapped to raw_spinlock_t and has
+exactly the same semantics.
+
+spinlock_t and PREEMPT_RT
+-------------------------
+
+On a PREEMPT_RT kernel spinlock_t is mapped to a separate implementation
+based on rt_mutex which changes the semantics:
+
+ - Preemption is not disabled.
+
+ - The hard interrupt related suffixes for spin_lock / spin_unlock
+   operations (_irq, _irqsave / _irqrestore) do not affect the CPU's
+   interrupt disabled state.
+
+ - The soft interrupt related suffix (_bh()) still disables softirq
+   handlers.
+
+   Non-PREEMPT_RT kernels disable preemption to get this effect.
+
+   PREEMPT_RT kernels use a per-CPU lock for serialization which keeps
+   preemption disabled. The lock disables softirq handlers and also
+   prevents reentrancy due to task preemption.
+
+PREEMPT_RT kernels preserve all other spinlock_t semantics:
+
+ - Tasks holding a spinlock_t do not migrate.  Non-PREEMPT_RT kernels
+   avoid migration by disabling preemption.  PREEMPT_RT kernels instead
+   disable migration, which ensures that pointers to per-CPU variables
+   remain valid even if the task is preempted.
+
+ - Task state is preserved across spinlock acquisition, ensuring that the
+   task-state rules apply to all kernel configurations.  Non-PREEMPT_RT
+   kernels leave task state untouched.  However, PREEMPT_RT must change
+   task state if the task blocks during acquisition.  Therefore, it saves
+   the current task state before blocking and the corresponding lock wakeup
+   restores it, as shown below::
+
+    task->state = TASK_INTERRUPTIBLE
+     lock()
+       block()
+         task->saved_state = task->state
+        task->state = TASK_UNINTERRUPTIBLE
+        schedule()
+                                       lock wakeup
+                                         task->state = task->saved_state
+
+   Other types of wakeups would normally unconditionally set the task state
+   to RUNNING, but that does not work here because the task must remain
+   blocked until the lock becomes available.  Therefore, when a non-lock
+   wakeup attempts to awaken a task blocked waiting for a spinlock, it
+   instead sets the saved state to RUNNING.  Then, when the lock
+   acquisition completes, the lock wakeup sets the task state to the saved
+   state, in this case setting it to RUNNING::
+
+    task->state = TASK_INTERRUPTIBLE
+     lock()
+       block()
+         task->saved_state = task->state
+        task->state = TASK_UNINTERRUPTIBLE
+        schedule()
+                                       non lock wakeup
+                                         task->saved_state = TASK_RUNNING
+
+                                       lock wakeup
+                                         task->state = task->saved_state
+
+   This ensures that the real wakeup cannot be lost.
+
+
+rwlock_t
+========
+
+rwlock_t is a multiple readers and single writer lock mechanism.
+
+Non-PREEMPT_RT kernels implement rwlock_t as a spinning lock and the
+suffix rules of spinlock_t apply accordingly. The implementation is fair,
+thus preventing writer starvation.
+
+rwlock_t and PREEMPT_RT
+-----------------------
+
+PREEMPT_RT kernels map rwlock_t to a separate rt_mutex-based
+implementation, thus changing semantics:
+
+ - All the spinlock_t changes also apply to rwlock_t.
+
+ - Because an rwlock_t writer cannot grant its priority to multiple
+   readers, a preempted low-priority reader will continue holding its lock,
+   thus starving even high-priority writers.  In contrast, because readers
+   can grant their priority to a writer, a preempted low-priority writer
+   will have its priority boosted until it releases the lock, thus
+   preventing that writer from starving readers.
+
+
+PREEMPT_RT caveats
+==================
+
+spinlock_t and rwlock_t
+-----------------------
+
+These changes in spinlock_t and rwlock_t semantics on PREEMPT_RT kernels
+have a few implications.  For example, on a non-PREEMPT_RT kernel the
+following code sequence works as expected::
+
+   local_irq_disable();
+   spin_lock(&lock);
+
+and is fully equivalent to::
+
+   spin_lock_irq(&lock);
+
+Same applies to rwlock_t and the _irqsave() suffix variants.
+
+On PREEMPT_RT kernel this code sequence breaks because RT-mutex requires a
+fully preemptible context.  Instead, use spin_lock_irq() or
+spin_lock_irqsave() and their unlock counterparts.  In cases where the
+interrupt disabling and locking must remain separate, PREEMPT_RT offers a
+local_lock mechanism.  Acquiring the local_lock pins the task to a CPU,
+allowing things like per-CPU interrupt disabled locks to be acquired.
+However, this approach should be used only where absolutely necessary.
+
+
+raw_spinlock_t
+--------------
+
+Acquiring a raw_spinlock_t disables preemption and possibly also
+interrupts, so the critical section must avoid acquiring a regular
+spinlock_t or rwlock_t, for example, the critical section must avoid
+allocating memory.  Thus, on a non-PREEMPT_RT kernel the following code
+works perfectly::
+
+  raw_spin_lock(&lock);
+  p = kmalloc(sizeof(*p), GFP_ATOMIC);
+
+But this code fails on PREEMPT_RT kernels because the memory allocator is
+fully preemptible and therefore cannot be invoked from truly atomic
+contexts.  However, it is perfectly fine to invoke the memory allocator
+while holding normal non-raw spinlocks because they do not disable
+preemption on PREEMPT_RT kernels::
+
+  spin_lock(&lock);
+  p = kmalloc(sizeof(*p), GFP_ATOMIC);
+
+
+bit spinlocks
+-------------
+
+PREEMPT_RT cannot substitute bit spinlocks because a single bit is too
+small to accommodate an RT-mutex.  Therefore, the semantics of bit
+spinlocks are preserved on PREEMPT_RT kernels, so that the raw_spinlock_t
+caveats also apply to bit spinlocks.
+
+Some bit spinlocks are replaced with regular spinlock_t for PREEMPT_RT
+using conditional (#ifdef'ed) code changes at the usage site.  In contrast,
+usage-site changes are not needed for the spinlock_t substitution.
+Instead, conditionals in header files and the core locking implemementation
+enable the compiler to do the substitution transparently.
+
+
+Lock type nesting rules
+=======================
+
+The most basic rules are:
+
+  - Lock types of the same lock category (sleeping, spinning) can nest
+    arbitrarily as long as they respect the general lock ordering rules to
+    prevent deadlocks.
+
+  - Sleeping lock types cannot nest inside spinning lock types.
+
+  - Spinning lock types can nest inside sleeping lock types.
+
+These constraints apply both in PREEMPT_RT and otherwise.
+
+The fact that PREEMPT_RT changes the lock category of spinlock_t and
+rwlock_t from spinning to sleeping means that they cannot be acquired while
+holding a raw spinlock.  This results in the following nesting ordering:
+
+  1) Sleeping locks
+  2) spinlock_t and rwlock_t
+  3) raw_spinlock_t and bit spinlocks
+
+Lockdep will complain if these constraints are violated, both in
+PREEMPT_RT and otherwise.
index 030a5c4..e111ff7 100644 (file)
@@ -74,7 +74,7 @@ Before the receiver driver may enable the CSI-2 transmitter by using
 the :c:type:`v4l2_subdev_video_ops`->s_stream(), it must have powered
 the transmitter up by using the
 :c:type:`v4l2_subdev_core_ops`->s_power() callback. This may take
-place either indirectly by using :c:func:`v4l2_pipeline_pm_use` or
+place either indirectly by using :c:func:`v4l2_pipeline_pm_get` or
 directly.
 
 Formats
index b20800c..5129019 100644 (file)
@@ -291,8 +291,8 @@ and QUERYMENU. And G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically suppo
    In practice the basic usage as described above is sufficient for most drivers.
 
 
-Inheriting Controls
--------------------
+Inheriting Sub-device Controls
+------------------------------
 
 When a sub-device is registered with a V4L2 driver by calling
 v4l2_device_register_subdev() and the ctrl_handler fields of both v4l2_subdev
@@ -757,8 +757,8 @@ attempting to find another control from the same handler will deadlock.
 It is recommended not to use this function from inside the control ops.
 
 
-Inheriting Controls
--------------------
+Preventing Controls inheritance
+-------------------------------
 
 When one control handler is added to another using v4l2_ctrl_add_handler, then
 by default all controls from one are merged to the other. But a subdev might
index 4c5a15c..63c0648 100644 (file)
@@ -185,7 +185,7 @@ This will create the character device for you.
 
 .. code-block:: c
 
-       err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       err = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (err) {
                video_device_release(vdev); /* or kfree(my_vdev); */
                return err;
@@ -201,7 +201,7 @@ types exist:
 ========================== ====================         ==============================
 :c:type:`vfl_devnode_type` Device name          Usage
 ========================== ====================         ==============================
-``VFL_TYPE_GRABBER``       ``/dev/videoX``       for video input/output devices
+``VFL_TYPE_VIDEO``         ``/dev/videoX``       for video input/output devices
 ``VFL_TYPE_VBI``           ``/dev/vbiX``         for vertical blank data (i.e.
                                                 closed captions, teletext)
 ``VFL_TYPE_RADIO``         ``/dev/radioX``       for radio tuners
index a21659d..6818ddf 100644 (file)
@@ -44,18 +44,18 @@ is only available if the ``CEC_CAP_CONNECTOR_INFO`` capability is set.
 .. flat-table:: struct cec_connector_info
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 8
+    :widths:       1 1 8
 
     * - __u32
       - ``type``
       - The type of connector this adapter is associated with.
-    * - union
+    * - union {
       - ``(anonymous)``
-      -
-    * -
-      - ``struct cec_drm_connector_info``
+    * - ``struct cec_drm_connector_info``
       - drm
       - :ref:`cec-drm-connector-info`
+    * - }
+      -
 
 
 .. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}|
index 5e21b1f..d16b226 100644 (file)
@@ -109,35 +109,33 @@ it is guaranteed that the state did change in between the two events.
 .. flat-table:: struct cec_event
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 8
+    :widths:       1 1 8
 
     * - __u64
       - ``ts``
-      - :cspan:`1`\ Timestamp of the event in ns.
+      - Timestamp of the event in ns.
 
        The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock.
 
        To access the same clock from userspace use :c:func:`clock_gettime`.
     * - __u32
       - ``event``
-      - :cspan:`1` The CEC event type, see :ref:`cec-events`.
+      - The CEC event type, see :ref:`cec-events`.
     * - __u32
       - ``flags``
-      - :cspan:`1` Event flags, see :ref:`cec-event-flags`.
-    * - union
+      - Event flags, see :ref:`cec-event-flags`.
+    * - union {
       - (anonymous)
-      -
-      -
-    * -
-      - struct cec_event_state_change
+    * - struct cec_event_state_change
       - ``state_change``
       - The new adapter state as sent by the :ref:`CEC_EVENT_STATE_CHANGE <CEC-EVENT-STATE-CHANGE>`
        event.
-    * -
-      - struct cec_event_lost_msgs
+    * - struct cec_event_lost_msgs
       - ``lost_msgs``
       - The number of lost messages as sent by the :ref:`CEC_EVENT_LOST_MSGS <CEC-EVENT-LOST-MSGS>`
        event.
+    * - }
+      -
 
 
 .. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}|
index 6218d9c..33e2b11 100644 (file)
@@ -64,12 +64,11 @@ id's until they get an error.
 .. flat-table:: struct media_entity_desc
     :header-rows:  0
     :stub-columns: 0
-    :widths: 1 1 1 1 8
+    :widths: 2 2 1 8
 
     *  -  __u32
        -  ``id``
        -
-       -
        -  Entity ID, set by the application. When the ID is or'ed with
          ``MEDIA_ENT_ID_FLAG_NEXT``, the driver clears the flag and returns
          the first entity with a larger ID. Do not expect that the ID will
@@ -79,79 +78,70 @@ id's until they get an error.
     *  -  char
        -  ``name``\ [32]
        -
-       -
        -  Entity name as an UTF-8 NULL-terminated string. This name must be unique
           within the media topology.
 
     *  -  __u32
        -  ``type``
        -
-       -
        -  Entity type, see :ref:`media-entity-functions` for details.
 
     *  -  __u32
        -  ``revision``
        -
-       -
        -  Entity revision. Always zero (obsolete)
 
     *  -  __u32
        -  ``flags``
        -
-       -
        -  Entity flags, see :ref:`media-entity-flag` for details.
 
     *  -  __u32
        -  ``group_id``
        -
-       -
        -  Entity group ID. Always zero (obsolete)
 
     *  -  __u16
        -  ``pads``
        -
-       -
        -  Number of pads
 
     *  -  __u16
        -  ``links``
        -
-       -
        -  Total number of outbound links. Inbound links are not counted in
          this field.
 
     *  -  __u32
        -  ``reserved[4]``
        -
-       -
        -  Reserved for future extensions. Drivers and applications must set
           the array to zero.
 
-    *  -  union
+    *  -  union {
+       -  (anonymous)
 
-    *  -
-       -  struct
+    *  -  struct
        -  ``dev``
        -
        -  Valid for (sub-)devices that create a single device node.
 
     *  -
-       -
        -  __u32
        -  ``major``
        -  Device node major number.
 
     *  -
-       -
        -  __u32
        -  ``minor``
        -  Device node minor number.
 
-    *  -
-       -  __u8
+    *  -  __u8
        -  ``raw``\ [184]
        -
        -
+    *  - }
+       -
 
 
 Return Value
index 9149b57..3112300 100644 (file)
@@ -172,11 +172,10 @@ struct v4l2_buffer
 .. flat-table:: struct v4l2_buffer
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 2 1 10
+    :widths:       1 2 10
 
     * - __u32
       - ``index``
-      -
       - Number of the buffer, set by the application except when calling
        :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`, then it is set by the
        driver. This field can range from zero to the number of buffers
@@ -186,14 +185,12 @@ struct v4l2_buffer
        :ref:`VIDIOC_CREATE_BUFS` minus one.
     * - __u32
       - ``type``
-      -
       - Type of the buffer, same as struct
        :c:type:`v4l2_format` ``type`` or struct
        :c:type:`v4l2_requestbuffers` ``type``, set
        by the application. See :c:type:`v4l2_buf_type`
     * - __u32
       - ``bytesused``
-      -
       - The number of bytes occupied by the data in the buffer. It depends
        on the negotiated data format and may change with each buffer for
        compressed variable size data like JPEG images. Drivers must set
@@ -205,18 +202,15 @@ struct v4l2_buffer
        ``planes`` pointer is used instead.
     * - __u32
       - ``flags``
-      -
       - Flags set by the application or driver, see :ref:`buffer-flags`.
     * - __u32
       - ``field``
-      -
       - Indicates the field order of the image in the buffer, see
        :c:type:`v4l2_field`. This field is not used when the buffer
        contains VBI data. Drivers must set it when ``type`` refers to a
        capture stream, applications when it refers to an output stream.
     * - struct timeval
       - ``timestamp``
-      -
       - For capture streams this is time when the first data byte was
        captured, as returned by the :c:func:`clock_gettime()` function
        for the relevant clock id; see ``V4L2_BUF_FLAG_TIMESTAMP_*`` in
@@ -229,7 +223,6 @@ struct v4l2_buffer
        stream.
     * - struct :c:type:`v4l2_timecode`
       - ``timecode``
-      -
       - When the ``V4L2_BUF_FLAG_TIMECODE`` flag is set in ``flags``, this
        structure contains a frame timecode. In
        :c:type:`V4L2_FIELD_ALTERNATE <v4l2_field>` mode the top and
@@ -239,10 +232,9 @@ struct v4l2_buffer
        independent of the ``timestamp`` and ``sequence`` fields.
     * - __u32
       - ``sequence``
-      -
       - Set by the driver, counting the frames (not fields!) in sequence.
        This field is set for both input and output devices.
-    * - :cspan:`3`
+    * - :cspan:`2`
 
        In :c:type:`V4L2_FIELD_ALTERNATE <v4l2_field>` mode the top and
        bottom field have the same sequence number. The count starts at
@@ -262,13 +254,11 @@ struct v4l2_buffer
 
     * - __u32
       - ``memory``
-      -
       - This field must be set by applications and/or drivers in
        accordance with the selected I/O method. See :c:type:`v4l2_memory`
-    * - union
+    * - union {
       - ``m``
-    * -
-      - __u32
+    * - __u32
       - ``offset``
       - For the single-planar API and when ``memory`` is
        ``V4L2_MEMORY_MMAP`` this is the offset of the buffer from the
@@ -276,29 +266,27 @@ struct v4l2_buffer
        and apart of serving as parameter to the
        :ref:`mmap() <func-mmap>` function not useful for applications.
        See :ref:`mmap` for details
-    * -
-      - unsigned long
+    * - unsigned long
       - ``userptr``
       - For the single-planar API and when ``memory`` is
        ``V4L2_MEMORY_USERPTR`` this is a pointer to the buffer (casted to
        unsigned long type) in virtual memory, set by the application. See
        :ref:`userp` for details.
-    * -
-      - struct v4l2_plane
+    * - struct v4l2_plane
       - ``*planes``
       - When using the multi-planar API, contains a userspace pointer to
        an array of struct :c:type:`v4l2_plane`. The size of
        the array should be put in the ``length`` field of this
        struct :c:type:`v4l2_buffer` structure.
-    * -
-      - int
+    * - int
       - ``fd``
       - For the single-plane API and when ``memory`` is
        ``V4L2_MEMORY_DMABUF`` this is the file descriptor associated with
        a DMABUF buffer.
+    * - }
+      -
     * - __u32
       - ``length``
-      -
       - Size of the buffer (not the payload) in bytes for the
        single-planar API. This is set by the driver based on the calls to
        :ref:`VIDIOC_REQBUFS` and/or
@@ -308,12 +296,10 @@ struct v4l2_buffer
        actual number of valid elements in that array.
     * - __u32
       - ``reserved2``
-      -
       - A place holder for future extensions. Drivers and applications
        must set this to 0.
     * - __u32
       - ``request_fd``
-      -
       - The file descriptor of the request to queue the buffer to. If the flag
         ``V4L2_BUF_FLAG_REQUEST_FD`` is set, then the buffer will be
        queued to this request. If the flag is not set, then this field will
@@ -344,11 +330,10 @@ struct v4l2_plane
 .. flat-table::
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2
+    :widths:       1 1 2
 
     * - __u32
       - ``bytesused``
-      -
       - The number of bytes occupied by data in the plane (its payload).
        Drivers must set this field when ``type`` refers to a capture
        stream, applications when it refers to an output stream. If the
@@ -362,40 +347,35 @@ struct v4l2_plane
           which may not be 0.
     * - __u32
       - ``length``
-      -
       - Size in bytes of the plane (not its payload). This is set by the
        driver based on the calls to
        :ref:`VIDIOC_REQBUFS` and/or
        :ref:`VIDIOC_CREATE_BUFS`.
-    * - union
+    * - union {
       - ``m``
-      -
-      -
-    * -
-      - __u32
+    * - __u32
       - ``mem_offset``
       - When the memory type in the containing struct
        :c:type:`v4l2_buffer` is ``V4L2_MEMORY_MMAP``, this
        is the value that should be passed to :ref:`mmap() <func-mmap>`,
        similar to the ``offset`` field in struct
        :c:type:`v4l2_buffer`.
-    * -
-      - unsigned long
+    * - unsigned long
       - ``userptr``
       - When the memory type in the containing struct
        :c:type:`v4l2_buffer` is ``V4L2_MEMORY_USERPTR``,
        this is a userspace pointer to the memory allocated for this plane
        by an application.
-    * -
-      - int
+    * - int
       - ``fd``
       - When the memory type in the containing struct
        :c:type:`v4l2_buffer` is ``V4L2_MEMORY_DMABUF``,
        this is a file descriptor associated with a DMABUF buffer, similar
        to the ``fd`` field in struct :c:type:`v4l2_buffer`.
+    * - }
+      -
     * - __u32
       - ``data_offset``
-      -
       - Offset in bytes to video data in the plane. Drivers must set this
        field when ``type`` refers to a capture stream, applications when
        it refers to an output stream.
@@ -407,7 +387,6 @@ struct v4l2_plane
           at offset ``data_offset`` from the start of the plane.
     * - __u32
       - ``reserved[11]``
-      -
       - Reserved for future use. Should be zeroed by drivers and
        applications.
 
index e86346f..7b2d38d 100644 (file)
@@ -478,33 +478,30 @@ struct v4l2_mpeg_vbi_fmt_ivtv
 .. flat-table::
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2
+    :widths:       1 1 2
 
     * - __u8
       - ``magic``\ [4]
-      -
       - A "magic" constant from :ref:`v4l2-mpeg-vbi-fmt-ivtv-magic` that
        indicates this is a valid sliced VBI data payload and also
        indicates which member of the anonymous union, ``itv0`` or
        ``ITV0``, to use for the payload data.
-    * - union
+    * - union {
       - (anonymous)
-    * -
-      - struct :c:type:`v4l2_mpeg_vbi_itv0`
+    * - struct :c:type:`v4l2_mpeg_vbi_itv0`
       - ``itv0``
       - The primary form of the sliced VBI data payload that contains
        anywhere from 1 to 35 lines of sliced VBI data. Line masks are
        provided in this form of the payload indicating which VBI lines
        are provided.
-    * -
-      - struct :ref:`v4l2_mpeg_vbi_ITV0 <v4l2-mpeg-vbi-itv0-1>`
+    * - struct :ref:`v4l2_mpeg_vbi_ITV0 <v4l2-mpeg-vbi-itv0-1>`
       - ``ITV0``
       - An alternate form of the sliced VBI data payload used when 36
        lines of sliced VBI data are present. No line masks are provided
        in this form of the payload; all valid line mask bits are
        implcitly set.
-
-
+    * - }
+      -
 
 .. _v4l2-mpeg-vbi-fmt-ivtv-magic:
 
index 28313c0..d4fc5f2 100644 (file)
@@ -2028,6 +2028,22 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
     * - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM``
       - 0x00000004
       - The DPB entry is a long term reference frame
+    * - ``V4L2_H264_DPB_ENTRY_FLAG_FIELD``
+      - 0x00000008
+      - The DPB entry is a field reference, which means only one of the field
+        will be used when decoding the new frame/field. When not set the DPB
+        entry is a frame reference (both fields will be used). Note that this
+        flag does not say anything about the number of fields contained in the
+        reference frame, it just describes the one used to decode the new
+        field/frame
+    * - ``V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD``
+      - 0x00000010
+      - The DPB entry is a bottom field reference (only the bottom field of the
+        reference frame is needed to decode the new frame/field). Only valid if
+        V4L2_H264_DPB_ENTRY_FLAG_FIELD is set. When
+        V4L2_H264_DPB_ENTRY_FLAG_FIELD is set but
+        V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD is not, that means the
+        DPB entry is a top field reference
 
 ``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (enum)``
     Specifies the decoding mode to use. Currently exposes slice-based and
index cfa2f4e..807ab34 100644 (file)
@@ -34,5 +34,6 @@ orders. See also `the Wikipedia article on Bayer filter
     pixfmt-srggb10-ipu3
     pixfmt-srggb12
     pixfmt-srggb12p
+    pixfmt-srggb14
     pixfmt-srggb14p
     pixfmt-srggb16
diff --git a/Documentation/media/uapi/v4l/pixfmt-srggb14.rst b/Documentation/media/uapi/v4l/pixfmt-srggb14.rst
new file mode 100644 (file)
index 0000000..3420d4d
--- /dev/null
@@ -0,0 +1,82 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _V4L2-PIX-FMT-SRGGB14:
+.. _v4l2-pix-fmt-sbggr14:
+.. _v4l2-pix-fmt-sgbrg14:
+.. _v4l2-pix-fmt-sgrbg14:
+
+
+***************************************************************************************************************************
+V4L2_PIX_FMT_SRGGB14 ('RG14'), V4L2_PIX_FMT_SGRBG14 ('GR14'), V4L2_PIX_FMT_SGBRG14 ('GB14'), V4L2_PIX_FMT_SBGGR14 ('BG14'),
+***************************************************************************************************************************
+
+
+14-bit Bayer formats expanded to 16 bits
+
+
+Description
+===========
+
+These four pixel formats are raw sRGB / Bayer formats with 14 bits per
+colour. Each sample is stored in a 16-bit word, with two unused high
+bits filled with zeros. Each n-pixel row contains n/2 green samples
+and n/2 blue or red samples, with alternating red and blue rows. Bytes
+are stored in memory in little endian order. They are conventionally
+described as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an
+example of a small V4L2_PIX_FMT_SBGGR14 image:
+
+**Byte Order.**
+Each cell is one byte, the two most significant bits in the high bytes are
+zero.
+
+
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       2 1 1 1 1 1 1 1 1
+
+
+    * - start + 0:
+      - B\ :sub:`00low`
+      - B\ :sub:`00high`
+      - G\ :sub:`01low`
+      - G\ :sub:`01high`
+      - B\ :sub:`02low`
+      - B\ :sub:`02high`
+      - G\ :sub:`03low`
+      - G\ :sub:`03high`
+    * - start + 8:
+      - G\ :sub:`10low`
+      - G\ :sub:`10high`
+      - R\ :sub:`11low`
+      - R\ :sub:`11high`
+      - G\ :sub:`12low`
+      - G\ :sub:`12high`
+      - R\ :sub:`13low`
+      - R\ :sub:`13high`
+    * - start + 16:
+      - B\ :sub:`20low`
+      - B\ :sub:`20high`
+      - G\ :sub:`21low`
+      - G\ :sub:`21high`
+      - B\ :sub:`22low`
+      - B\ :sub:`22high`
+      - G\ :sub:`23low`
+      - G\ :sub:`23high`
+    * - start + 24:
+      - G\ :sub:`30low`
+      - G\ :sub:`30high`
+      - R\ :sub:`31low`
+      - R\ :sub:`31high`
+      - G\ :sub:`32low`
+      - G\ :sub:`32high`
+      - R\ :sub:`33low`
+      - R\ :sub:`33high`
index db43dda..054275c 100644 (file)
@@ -100,7 +100,8 @@ describing all planes of that format.
     * - __u8
       - ``flags``
       - Flags set by the application or driver, see :ref:`format-flags`.
-    * - :cspan:`2` union { (anonymous)
+    * - union {
+      - (anonymous)
     * - __u8
       - ``ycbcr_enc``
       - Y'CbCr encoding, from enum :c:type:`v4l2_ycbcr_encoding`.
@@ -113,7 +114,8 @@ describing all planes of that format.
         This information supplements the ``colorspace`` and must be set by
        the driver for capture streams and by the application for output
        streams, see :ref:`colorspaces`.
-    * - :cspan:`2` }
+    * - }
+      -
     * - __u8
       - ``quantization``
       - Quantization range, from enum :c:type:`v4l2_quantization`.
index a8321c3..a993b86 100644 (file)
@@ -143,7 +143,6 @@ Single-planar format structure
       - Flags set by the application or driver, see :ref:`format-flags`.
     * - union {
       - (anonymous)
-      -
     * - __u32
       - ``ycbcr_enc``
       - Y'CbCr encoding, from enum :c:type:`v4l2_ycbcr_encoding`.
@@ -158,7 +157,6 @@ Single-planar format structure
        streams, see :ref:`colorspaces`.
     * - }
       -
-      -
     * - __u32
       - ``quantization``
       - Quantization range, from enum :c:type:`v4l2_quantization`.
diff --git a/Documentation/media/uapi/v4l/pixfmt-y14.rst b/Documentation/media/uapi/v4l/pixfmt-y14.rst
new file mode 100644 (file)
index 0000000..5c260f8
--- /dev/null
@@ -0,0 +1,72 @@
+.. Permission is granted to copy, distribute and/or modify this
+.. document under the terms of the GNU Free Documentation License,
+.. Version 1.1 or any later version published by the Free Software
+.. Foundation, with no Invariant Sections, no Front-Cover Texts
+.. and no Back-Cover Texts. A copy of the license is included at
+.. Documentation/media/uapi/fdl-appendix.rst.
+..
+.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections
+
+.. _V4L2-PIX-FMT-Y14:
+
+*************************
+V4L2_PIX_FMT_Y14 ('Y14 ')
+*************************
+
+
+Grey-scale image
+
+
+Description
+===========
+
+This is a grey-scale image with a depth of 14 bits per pixel. Pixels are
+stored in 16-bit words with unused high bits padded with 0. The least
+significant byte is stored at lower memory addresses (little-endian).
+
+**Byte Order.**
+Each cell is one byte.
+
+
+
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+
+    * - start + 0:
+      - Y'\ :sub:`00low`
+      - Y'\ :sub:`00high`
+      - Y'\ :sub:`01low`
+      - Y'\ :sub:`01high`
+      - Y'\ :sub:`02low`
+      - Y'\ :sub:`02high`
+      - Y'\ :sub:`03low`
+      - Y'\ :sub:`03high`
+    * - start + 8:
+      - Y'\ :sub:`10low`
+      - Y'\ :sub:`10high`
+      - Y'\ :sub:`11low`
+      - Y'\ :sub:`11high`
+      - Y'\ :sub:`12low`
+      - Y'\ :sub:`12high`
+      - Y'\ :sub:`13low`
+      - Y'\ :sub:`13high`
+    * - start + 16:
+      - Y'\ :sub:`20low`
+      - Y'\ :sub:`20high`
+      - Y'\ :sub:`21low`
+      - Y'\ :sub:`21high`
+      - Y'\ :sub:`22low`
+      - Y'\ :sub:`22high`
+      - Y'\ :sub:`23low`
+      - Y'\ :sub:`23high`
+    * - start + 24:
+      - Y'\ :sub:`30low`
+      - Y'\ :sub:`30high`
+      - Y'\ :sub:`31low`
+      - Y'\ :sub:`31high`
+      - Y'\ :sub:`32low`
+      - Y'\ :sub:`32high`
+      - Y'\ :sub:`33low`
+      - Y'\ :sub:`33high`
index 15e11f2..17bfb2b 100644 (file)
@@ -5792,6 +5792,43 @@ the following codes.
       - u\ :sub:`2`
       - u\ :sub:`1`
       - u\ :sub:`0`
+    * .. _MEDIA-BUS-FMT-Y14-1X14:
+
+      - MEDIA_BUS_FMT_Y14_1X14
+      - 0x202d
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      -
+      - y\ :sub:`13`
+      - y\ :sub:`12`
+      - y\ :sub:`11`
+      - y\ :sub:`10`
+      - y\ :sub:`9`
+      - y\ :sub:`8`
+      - y\ :sub:`7`
+      - y\ :sub:`6`
+      - y\ :sub:`5`
+      - y\ :sub:`4`
+      - y\ :sub:`3`
+      - y\ :sub:`2`
+      - y\ :sub:`1`
+      - y\ :sub:`0`
     * .. _MEDIA-BUS-FMT-UYVY8-1X16:
 
       - MEDIA_BUS_FMT_UYVY8_1X16
index a1cf201..d38031d 100644 (file)
@@ -91,23 +91,23 @@ instructions.
 .. flat-table:: struct v4l2_dbg_match
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2
+    :widths:       1 1 2
 
     * - __u32
       - ``type``
       - See :ref:`name-chip-match-types` for a list of possible types.
-    * - union
+    * - union {
       - (anonymous)
-    * -
-      - __u32
+    * - __u32
       - ``addr``
       - Match a chip by this number, interpreted according to the ``type``
        field.
-    * -
-      - char
+    * - char
       - ``name[32]``
       - Match a chip by this name, interpreted according to the ``type``
        field. Currently unused.
+    * - }
+      -
 
 
 
index 29e1d4f..112597c 100644 (file)
@@ -100,23 +100,23 @@ instructions.
 .. flat-table:: struct v4l2_dbg_match
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2
+    :widths:       1 1 2
 
     * - __u32
       - ``type``
       - See :ref:`chip-match-types` for a list of possible types.
-    * - union
+    * - union {
       - (anonymous)
-    * -
-      - __u32
+    * - __u32
       - ``addr``
       - Match a chip by this number, interpreted according to the ``type``
        field.
-    * -
-      - char
+    * - char
       - ``name[32]``
       - Match a chip by this name, interpreted according to the ``type``
        field. Currently unused.
+    * - }
+      -
 
 
 
index f1a5048..784c598 100644 (file)
@@ -77,32 +77,25 @@ introduced in Linux 3.3. They are, however, mandatory for stateful mem2mem decod
 .. flat-table:: struct v4l2_decoder_cmd
     :header-rows:  0
     :stub-columns: 0
-    :widths: 11 24 12 16 106
+    :widths: 1 1 1 3
 
     * - __u32
       - ``cmd``
       -
-      -
       - The decoder command, see :ref:`decoder-cmds`.
     * - __u32
       - ``flags``
       -
-      -
       - Flags to go with the command. If no flags are defined for this
        command, drivers and applications must set this field to zero.
-    * - union
+    * - union {
       - (anonymous)
-      -
-      -
-      -
-    * -
-      - struct
+    * - struct
       - ``start``
       -
       - Structure containing additional data for the
        ``V4L2_DEC_CMD_START`` command.
     * -
-      -
       - __s32
       - ``speed``
       - Playback speed and direction. The playback speed is defined as
@@ -113,7 +106,6 @@ introduced in Linux 3.3. They are, however, mandatory for stateful mem2mem decod
        of 1 steps just one frame forward, a speed of -1 steps just one
        frame back.
     * -
-      -
       - __u32
       - ``format``
       - Format restrictions. This field is set by the driver, not the
@@ -124,30 +116,26 @@ introduced in Linux 3.3. They are, however, mandatory for stateful mem2mem decod
        GOPs, which it can then play in reverse order. So to implement
        reverse playback the application must feed the decoder the last
        GOP in the video file, then the GOP before that, etc. etc.
-    * -
-      - struct
+    * - struct
       - ``stop``
       -
       - Structure containing additional data for the ``V4L2_DEC_CMD_STOP``
        command.
     * -
-      -
       - __u64
       - ``pts``
       - Stop playback at this ``pts`` or immediately if the playback is
        already past that timestamp. Leave to 0 if you want to stop after
        the last frame was decoded.
-    * -
-      - struct
+    * - struct
       - ``raw``
-      -
-      -
     * -
-      -
       - __u32
       - ``data``\ [16]
       - Reserved for future extensions. Drivers and applications must set
        the array to zero.
+    * - }
+      -
 
 
 
index 42659a3..2f37d25 100644 (file)
@@ -55,66 +55,54 @@ call.
 .. flat-table:: struct v4l2_event
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2 1
+    :widths:       1 1 2
 
     * - __u32
       - ``type``
-      -
       - Type of the event, see :ref:`event-type`.
-    * - union
+    * - union {
       - ``u``
-      -
-      -
-    * -
-      - struct :c:type:`v4l2_event_vsync`
+    * - struct :c:type:`v4l2_event_vsync`
       - ``vsync``
       - Event data for event ``V4L2_EVENT_VSYNC``.
-    * -
-      - struct :c:type:`v4l2_event_ctrl`
+    * - struct :c:type:`v4l2_event_ctrl`
       - ``ctrl``
       - Event data for event ``V4L2_EVENT_CTRL``.
-    * -
-      - struct :c:type:`v4l2_event_frame_sync`
+    * - struct :c:type:`v4l2_event_frame_sync`
       - ``frame_sync``
       - Event data for event ``V4L2_EVENT_FRAME_SYNC``.
-    * -
-      - struct :c:type:`v4l2_event_motion_det`
+    * - struct :c:type:`v4l2_event_motion_det`
       - ``motion_det``
       - Event data for event V4L2_EVENT_MOTION_DET.
-    * -
-      - struct :c:type:`v4l2_event_src_change`
+    * - struct :c:type:`v4l2_event_src_change`
       - ``src_change``
       - Event data for event V4L2_EVENT_SOURCE_CHANGE.
-    * -
-      - __u8
+    * - __u8
       - ``data``\ [64]
       - Event data. Defined by the event type. The union should be used to
        define easily accessible type for events.
+    * - }
+      -
     * - __u32
       - ``pending``
-      -
       - Number of pending events excluding this one.
     * - __u32
       - ``sequence``
-      -
       - Event sequence number. The sequence number is incremented for
        every subscribed event that takes place. If sequence numbers are
        not contiguous it means that events have been lost.
     * - struct timespec
       - ``timestamp``
-      -
       - Event timestamp. The timestamp has been taken from the
        ``CLOCK_MONOTONIC`` clock. To access the same clock outside V4L2,
        use :c:func:`clock_gettime`.
     * - u32
       - ``id``
-      -
       - The ID associated with the event source. If the event does not
        have an associated ID (this depends on the event type), then this
        is 0.
     * - __u32
       - ``reserved``\ [8]
-      -
       - Reserved for future extensions. Drivers must set the array to
        zero.
 
@@ -233,54 +221,45 @@ call.
 .. flat-table:: struct v4l2_event_ctrl
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2 1
+    :widths:       1 1 2
 
     * - __u32
       - ``changes``
-      -
       - A bitmask that tells what has changed. See
        :ref:`ctrl-changes-flags`.
     * - __u32
       - ``type``
-      -
       - The type of the control. See enum
        :c:type:`v4l2_ctrl_type`.
-    * - union (anonymous)
-      -
-      -
-      -
-    * -
-      - __s32
+    * - union {
+      - (anonymous)
+    * - __s32
       - ``value``
       - The 32-bit value of the control for 32-bit control types. This is
        0 for string controls since the value of a string cannot be passed
        using :ref:`VIDIOC_DQEVENT`.
-    * -
-      - __s64
+    * - __s64
       - ``value64``
       - The 64-bit value of the control for 64-bit control types.
+    * - }
+      -
     * - __u32
       - ``flags``
-      -
       - The control flags. See :ref:`control-flags`.
     * - __s32
       - ``minimum``
-      -
       - The minimum value of the control. See struct
        :ref:`v4l2_queryctrl <v4l2-queryctrl>`.
     * - __s32
       - ``maximum``
-      -
       - The maximum value of the control. See struct
        :ref:`v4l2_queryctrl <v4l2-queryctrl>`.
     * - __s32
       - ``step``
-      -
       - The step value of the control. See struct
        :ref:`v4l2_queryctrl <v4l2-queryctrl>`.
     * - __s32
       - ``default_value``
-      -
       - The default value value of the control. See struct
        :ref:`v4l2_queryctrl <v4l2-queryctrl>`.
 
index e62d45d..1d0acbf 100644 (file)
@@ -112,7 +112,7 @@ that doesn't support them will return an ``EINVAL`` error code.
 .. flat-table:: struct v4l2_dv_timings_cap
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2 1
+    :widths:       1 1 2
 
     * - __u32
       - ``type``
@@ -127,16 +127,14 @@ that doesn't support them will return an ``EINVAL`` error code.
       - Reserved for future extensions.
 
        Drivers and applications must set the array to zero.
-    * - union
-      -
-      -
-    * -
-      - struct :c:type:`v4l2_bt_timings_cap`
+    * - union {
+      - (anonymous)
+    * - struct :c:type:`v4l2_bt_timings_cap`
       - ``bt``
       - BT.656/1120 timings capabilities of the hardware.
-    * -
-      - __u32
+    * - __u32
       - ``raw_data``\ [32]
+    * - }
       -
 
 .. tabularcolumns:: |p{7.0cm}|p{10.5cm}|
index 2c69f26..563a67c 100644 (file)
@@ -138,36 +138,31 @@ application should zero out all members except for the *IN* fields.
 
     * - __u32
       - ``index``
-      -
       - IN: Index of the given frame interval in the enumeration.
     * - __u32
       - ``pixel_format``
-      -
       - IN: Pixel format for which the frame intervals are enumerated.
     * - __u32
       - ``width``
-      -
       - IN: Frame width for which the frame intervals are enumerated.
     * - __u32
       - ``height``
-      -
       - IN: Frame height for which the frame intervals are enumerated.
     * - __u32
       - ``type``
-      -
       - OUT: Frame interval type the device supports.
-    * - union
-      -
-      -
+    * - union {
+      - (anonymous)
       - OUT: Frame interval with the given index.
-    * -
-      - struct :c:type:`v4l2_fract`
+    * - struct :c:type:`v4l2_fract`
       - ``discrete``
       - Frame interval [s].
-    * -
-      - struct :c:type:`v4l2_frmival_stepwise`
+    * - struct :c:type:`v4l2_frmival_stepwise`
       - ``stepwise``
       -
+    * - }
+      -
+      -
     * - __u32
       - ``reserved[2]``
       -
index cf31f54..cd97546 100644 (file)
@@ -155,31 +155,27 @@ application should zero out all members except for the *IN* fields.
 
     * - __u32
       - ``index``
-      -
       - IN: Index of the given frame size in the enumeration.
     * - __u32
       - ``pixel_format``
-      -
       - IN: Pixel format for which the frame sizes are enumerated.
     * - __u32
       - ``type``
-      -
       - OUT: Frame size type the device supports.
-    * - union
-      -
-      -
+    * - union {
+      - (anonymous)
       - OUT: Frame size with the given index.
-    * -
-      - struct :c:type:`v4l2_frmsize_discrete`
+    * - struct :c:type:`v4l2_frmsize_discrete`
       - ``discrete``
       -
-    * -
-      - struct :c:type:`v4l2_frmsize_stepwise`
+    * - struct :c:type:`v4l2_frmsize_stepwise`
       - ``stepwise``
       -
+    * - }
+      -
+      -
     * - __u32
       - ``reserved[2]``
-      -
       - Reserved space for future use. Must be zeroed by drivers and
        applications.
 
index 5c675cb..e36dd26 100644 (file)
@@ -179,23 +179,21 @@ EBUSY
 .. flat-table:: struct v4l2_dv_timings
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2 1
+    :widths:       1 1 2
 
     * - __u32
       - ``type``
-      -
       - Type of DV timings as listed in :ref:`dv-timing-types`.
-    * - union
-      -
-      -
-    * -
-      - struct :c:type:`v4l2_bt_timings`
+    * - union {
+      - (anonymous)
+    * - struct :c:type:`v4l2_bt_timings`
       - ``bt``
       - Timings defined by BT.656/1120 specifications
-    * -
-      - __u32
+    * - __u32
       - ``reserved``\ [32]
       -
+    * - }
+      -
 
 .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}|
 
index 271cac1..cdb2a2a 100644 (file)
@@ -136,15 +136,13 @@ still cause this situation.
 .. flat-table:: struct v4l2_ext_control
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2
+    :widths:       1 1 2
 
     * - __u32
       - ``id``
-      -
       - Identifies the control, set by the application.
     * - __u32
       - ``size``
-      -
       - The total size in bytes of the payload of this control. This is
        normally 0, but for pointer controls this should be set to the
        size of the memory containing the payload, or that will receive
@@ -161,55 +159,48 @@ still cause this situation.
           *length* of the string may well be much smaller.
     * - __u32
       - ``reserved2``\ [1]
-      -
       - Reserved for future extensions. Drivers and applications must set
        the array to zero.
-    * - union
+    * - union {
       - (anonymous)
-    * -
-      - __s32
+    * - __s32
       - ``value``
       - New value or current value. Valid if this control is not of type
        ``V4L2_CTRL_TYPE_INTEGER64`` and ``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is
        not set.
-    * -
-      - __s64
+    * - __s64
       - ``value64``
       - New value or current value. Valid if this control is of type
        ``V4L2_CTRL_TYPE_INTEGER64`` and ``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is
        not set.
-    * -
-      - char *
+    * - char *
       - ``string``
       - A pointer to a string. Valid if this control is of type
        ``V4L2_CTRL_TYPE_STRING``.
-    * -
-      - __u8 *
+    * - __u8 *
       - ``p_u8``
       - A pointer to a matrix control of unsigned 8-bit values. Valid if
        this control is of type ``V4L2_CTRL_TYPE_U8``.
-    * -
-      - __u16 *
+    * - __u16 *
       - ``p_u16``
       - A pointer to a matrix control of unsigned 16-bit values. Valid if
        this control is of type ``V4L2_CTRL_TYPE_U16``.
-    * -
-      - __u32 *
+    * - __u32 *
       - ``p_u32``
       - A pointer to a matrix control of unsigned 32-bit values. Valid if
        this control is of type ``V4L2_CTRL_TYPE_U32``.
-    * -
-      - :c:type:`v4l2_area` *
+    * - :c:type:`v4l2_area` *
       - ``p_area``
       - A pointer to a struct :c:type:`v4l2_area`. Valid if this control is
         of type ``V4L2_CTRL_TYPE_AREA``.
-    * -
-      - void *
+    * - void *
       - ``ptr``
       - A pointer to a compound type which can be an N-dimensional array
        and/or a compound type (the control's type is >=
        ``V4L2_CTRL_COMPOUND_TYPES``). Valid if
        ``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is set for this control.
+    * - }
+      -
 
 
 .. tabularcolumns:: |p{4.0cm}|p{2.2cm}|p{2.1cm}|p{8.2cm}|
@@ -221,12 +212,11 @@ still cause this situation.
 .. flat-table:: struct v4l2_ext_controls
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2 1
+    :widths:       1 1 2
 
-    * - union
+    * - union {
       - (anonymous)
-    * -
-      - __u32
+    * - __u32
       - ``ctrl_class``
       - The control class to which all controls belong, see
        :ref:`ctrl-class`. Drivers that use a kernel framework for
@@ -235,8 +225,7 @@ still cause this situation.
        support this can be tested by setting ``ctrl_class`` to 0 and
        calling :ref:`VIDIOC_TRY_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` with a ``count`` of 0. If that
        succeeds, then the driver supports this feature.
-    * -
-      - __u32
+    * - __u32
       - ``which``
       - Which value of the control to get/set/try.
        ``V4L2_CTRL_WHICH_CUR_VAL`` will return the current value of the
@@ -261,6 +250,8 @@ still cause this situation.
        by setting ctrl_class to ``V4L2_CTRL_WHICH_CUR_VAL`` and calling
        VIDIOC_TRY_EXT_CTRLS with a count of 0. If that fails, then the
        driver does not support ``V4L2_CTRL_WHICH_CUR_VAL``.
+    * - }
+      -
     * - __u32
       - ``count``
       - The number of controls in the controls array. May also be zero.
index e35a9ca..1e69bfc 100644 (file)
@@ -103,51 +103,44 @@ The format as returned by :ref:`VIDIOC_TRY_FMT <VIDIOC_G_FMT>` must be identical
 
     * - __u32
       - ``type``
-      -
       - Type of the data stream, see :c:type:`v4l2_buf_type`.
-    * - union
+    * - union {
       - ``fmt``
-    * -
-      - struct :c:type:`v4l2_pix_format`
+    * - struct :c:type:`v4l2_pix_format`
       - ``pix``
       - Definition of an image format, see :ref:`pixfmt`, used by video
        capture and output devices.
-    * -
-      - struct :c:type:`v4l2_pix_format_mplane`
+    * - struct :c:type:`v4l2_pix_format_mplane`
       - ``pix_mp``
       - Definition of an image format, see :ref:`pixfmt`, used by video
        capture and output devices that support the
        :ref:`multi-planar version of the API <planar-apis>`.
-    * -
-      - struct :c:type:`v4l2_window`
+    * - struct :c:type:`v4l2_window`
       - ``win``
       - Definition of an overlaid image, see :ref:`overlay`, used by
        video overlay devices.
-    * -
-      - struct :c:type:`v4l2_vbi_format`
+    * - struct :c:type:`v4l2_vbi_format`
       - ``vbi``
       - Raw VBI capture or output parameters. This is discussed in more
        detail in :ref:`raw-vbi`. Used by raw VBI capture and output
        devices.
-    * -
-      - struct :c:type:`v4l2_sliced_vbi_format`
+    * - struct :c:type:`v4l2_sliced_vbi_format`
       - ``sliced``
       - Sliced VBI capture or output parameters. See :ref:`sliced` for
        details. Used by sliced VBI capture and output devices.
-    * -
-      - struct :c:type:`v4l2_sdr_format`
+    * - struct :c:type:`v4l2_sdr_format`
       - ``sdr``
       - Definition of a data format, see :ref:`pixfmt`, used by SDR
        capture and output devices.
-    * -
-      - struct :c:type:`v4l2_meta_format`
+    * - struct :c:type:`v4l2_meta_format`
       - ``meta``
       - Definition of a metadata format, see :ref:`meta-formats`, used by
        metadata capture devices.
-    * -
-      - __u8
+    * - __u8
       - ``raw_data``\ [200]
       - Place holder for future extensions.
+    * - }
+      -
 
 
 Return Value
index d9d5d97..044a459 100644 (file)
@@ -69,33 +69,29 @@ union holding separate parameters for input and output devices.
 .. flat-table:: struct v4l2_streamparm
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2
+    :widths:       1 1 2
 
     * - __u32
       - ``type``
-      -
       - The buffer (stream) type, same as struct
        :c:type:`v4l2_format` ``type``, set by the
        application. See :c:type:`v4l2_buf_type`.
-    * - union
+    * - union {
       - ``parm``
-      -
-      -
-    * -
-      - struct :c:type:`v4l2_captureparm`
+    * - struct :c:type:`v4l2_captureparm`
       - ``capture``
       - Parameters for capture devices, used when ``type`` is
        ``V4L2_BUF_TYPE_VIDEO_CAPTURE`` or
        ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE``.
-    * -
-      - struct :c:type:`v4l2_outputparm`
+    * - struct :c:type:`v4l2_outputparm`
       - ``output``
       - Parameters for output devices, used when ``type`` is
        ``V4L2_BUF_TYPE_VIDEO_OUTPUT`` or ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE``.
-    * -
-      - __u8
+    * - __u8
       - ``raw_data``\ [200]
       - A place holder for future extensions.
+    * - }
+      -
 
 
 
index 6690928..8971f4c 100644 (file)
@@ -290,34 +290,29 @@ See also the examples in :ref:`control`.
 .. flat-table:: struct v4l2_querymenu
     :header-rows:  0
     :stub-columns: 0
-    :widths:       1 1 2 1
+    :widths:       1 1 2
 
     * - __u32
-      -
       - ``id``
       - Identifies the control, set by the application from the respective
        struct :ref:`v4l2_queryctrl <v4l2-queryctrl>` ``id``.
     * - __u32
-      -
       - ``index``
       - Index of the menu item, starting at zero, set by the application.
-    * - union
-      -
-      -
-      -
-    * -
-      - __u8
+    * - union {
+      - (anonymous)
+    * - __u8
       - ``name``\ [32]
       - Name of the menu item, a NUL-terminated ASCII string. This
        information is intended for the user. This field is valid for
        ``V4L2_CTRL_TYPE_MENU`` type controls.
-    * -
-      - __s64
+    * - __s64
       - ``value``
       - Value of the integer menu item. This field is valid for
        ``V4L2_CTRL_TYPE_INTEGER_MENU`` type controls.
-    * - __u32
+    * - }
       -
+    * - __u32
       - ``reserved``
       - Reserved for future extensions. Drivers must set the array to
        zero.
@@ -378,7 +373,7 @@ See also the examples in :ref:`control`.
       - 0
       - 0
       - A control which performs an action when set. Drivers must ignore
-       the value passed with ``VIDIOC_S_CTRL`` and return an ``EINVAL`` error
+       the value passed with ``VIDIOC_S_CTRL`` and return an ``EACCES`` error
        code on a ``VIDIOC_G_CTRL`` attempt.
     * - ``V4L2_CTRL_TYPE_INTEGER64``
       - any
index 867470e..3b259e3 100644 (file)
@@ -35,6 +35,7 @@ to brightness information.
     pixfmt-grey
     pixfmt-y10
     pixfmt-y12
+    pixfmt-y14
     pixfmt-y10b
     pixfmt-y10p
     pixfmt-y16
index e4904ab..a694f49 100644 (file)
@@ -311,10 +311,13 @@ Down Scaler and GDC blocks should be configured with the supported resolutions
 as each hardware block has its own alignment requirement.
 
 You must configure the output resolution of the hardware blocks smartly to meet
-the hardware requirement along with keeping the maximum field of view.
-The intermediate resolutions can be generated by specific tool and this
-information can be obtained by looking at the following IPU3 ImgU configuration
-table.
+the hardware requirement along with keeping the maximum field of view. The
+intermediate resolutions can be generated by specific tool -
+
+https://github.com/intel/intel-ipu3-pipecfg
+
+This tool can be used to generate intermediate resolutions. More information can
+be obtained by looking at the following IPU3 ImgU configuration table.
 
 https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/master
 
index 7082fec..52e57b7 100644 (file)
@@ -4,9 +4,9 @@ The Virtual Video Test Driver (vivid)
 =====================================
 
 This driver emulates video4linux hardware of various types: video capture, video
-output, vbi capture and output, radio receivers and transmitters and a software
-defined radio receiver. In addition a simple framebuffer device is available for
-testing capture and output overlays.
+output, vbi capture and output, metadata capture and output, radio receivers and
+transmitters, touch capture and a software defined radio receiver. In addition a
+simple framebuffer device is available for testing capture and output overlays.
 
 Up to 64 vivid instances can be created, each with up to 16 inputs and 16 outputs.
 
@@ -36,6 +36,8 @@ This document describes the features implemented by this driver:
 - Radio receiver and transmitter support, including RDS support
 - Software defined radio (SDR) support
 - Capture and output overlay support
+- Metadata capture and output support
+- Touch capture support
 
 These features will be described in more detail below.
 
@@ -69,6 +71,9 @@ all configurable using the following module options:
                - bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both
                - bit 12: Radio Transmitter node
                - bit 16: Framebuffer for testing overlays
+               - bit 17: Metadata Capture node
+               - bit 18: Metadata Output node
+               - bit 19: Touch Capture node
 
        So to create four instances, the first two with just one video capture
        device, the second two with just one video output device you would pass
@@ -175,6 +180,21 @@ all configurable using the following module options:
        give the desired swradioX start number for each SDR capture device.
        The default is -1 which will just take the first free number.
 
+- meta_cap_nr:
+
+        give the desired videoX start number for each metadata capture device.
+        The default is -1 which will just take the first free number.
+
+- meta_out_nr:
+
+        give the desired videoX start number for each metadata output device.
+        The default is -1 which will just take the first free number.
+
+- touch_cap_nr:
+
+        give the desired v4l-touchX start number for each touch capture device.
+        The default is -1 which will just take the first free number.
+
 - ccs_cap_mode:
 
        specify the allowed video capture crop/compose/scaling combination
@@ -547,6 +567,33 @@ The generated data contains the In-phase and Quadrature components of a
 1 kHz tone that has an amplitude of sqrt(2).
 
 
+Metadata Capture
+----------------
+
+The Metadata capture generates UVC format metadata. The PTS and SCR are
+transmitted based on the values set in vivid contols.
+
+The Metadata device will only work for the Webcam input, it will give
+back an error for all other inputs.
+
+
+Metadata Output
+---------------
+
+The Metadata output can be used to set brightness, contrast, saturation and hue.
+
+The Metadata device will only work for the Webcam output, it will give
+back an error for all other outputs.
+
+
+Touch Capture
+-------------
+
+The Touch capture generates touch patterns simulating single tap, double tap,
+triple tap, move from left to right, zoom in, zoom out, palm press (simulating
+a large area being pressed on a touchpad), and simulating 16 simultaneous
+touch points.
+
 Controls
 --------
 
@@ -1049,6 +1096,16 @@ FM Radio Modulator Controls
        to pass the RDS blocks to the driver, or "Controls" where the RDS data
        is Provided by the RDS controls mentioned above.
 
+Metadata Capture Controls
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Generate PTS
+
+        if set, then the generated metadata stream contains Presentation timestamp.
+
+- Generate SCR
+
+        if set, then the generated metadata stream contains Source Clock information.
 
 Video, VBI and RDS Looping
 --------------------------
index 7146da0..e1c355e 100644 (file)
@@ -185,7 +185,7 @@ As a further example, consider this sequence of events:
        =============== ===============
        { A == 1, B == 2, C == 3, P == &A, Q == &C }
        B = 4;          Q = P;
-       P = &B          D = *Q;
+       P = &B;         D = *Q;
 
 There is an obvious data dependency here, as the value loaded into D depends on
 the address retrieved from P by CPU 2.  At the end of the sequence, any of the
@@ -569,7 +569,7 @@ following sequence of events:
        { A == 1, B == 2, C == 3, P == &A, Q == &C }
        B = 4;
        <write barrier>
-       WRITE_ONCE(P, &B)
+       WRITE_ONCE(P, &B);
                              Q = READ_ONCE(P);
                              D = *Q;
 
@@ -1721,7 +1721,7 @@ of optimizations:
      and WRITE_ONCE() are more selective:  With READ_ONCE() and
      WRITE_ONCE(), the compiler need only forget the contents of the
      indicated memory locations, while with barrier() the compiler must
-     discard the value of all memory locations that it has currented
+     discard the value of all memory locations that it has currently
      cached in any machine registers.  Of course, the compiler must also
      respect the order in which the READ_ONCE()s and WRITE_ONCE()s occur,
      though the CPU of course need not do so.
@@ -1833,7 +1833,7 @@ Aside: In the case of data dependencies, the compiler would be expected
 to issue the loads in the correct order (eg. `a[b]` would have to load
 the value of b before loading a[b]), however there is no guarantee in
 the C specification that the compiler may not speculate the value of b
-(eg. is equal to 1) and load a before b (eg. tmp = a[1]; if (b != 1)
+(eg. is equal to 1) and load a[b] before b (eg. tmp = a[1]; if (b != 1)
 tmp = a[b]; ).  There is also the problem of a compiler reloading b after
 having loaded a[b], thus having a newer copy of b than a[b].  A consensus
 has not yet been reached about these problems, however the READ_ONCE()
diff --git a/Documentation/mips/au1xxx_ide.rst b/Documentation/mips/au1xxx_ide.rst
deleted file mode 100644 (file)
index 2f9c2cf..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-.. include:: <isonum.txt>
-
-======================
-MIPS AU1XXX IDE driver
-======================
-
-Released 2005-07-15
-
-About
-=====
-
-This file describes the 'drivers/ide/au1xxx-ide.c', related files and the
-services they provide.
-
-If you are short in patience and just want to know how to add your hard disc to
-the white or black list, go to the 'ADD NEW HARD DISC TO WHITE OR BLACK LIST'
-section.
-
-
-License
-=======
-
-:Copyright: |copy| 2003-2005 AMD, Personal Connectivity Solutions
-
-This program is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free Software
-Foundation; either version 2 of the License, or (at your option) any later
-version.
-
-THIS SOFTWARE IS PROVIDED ``AS IS`` AND ANY EXPRESS OR IMPLIED WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc.,
-675 Mass Ave, Cambridge, MA 02139, USA.
-
-Note:
-      for more information, please refer "AMD Alchemy Au1200/Au1550 IDE
-      Interface and Linux Device Driver" Application Note.
-
-
-Files, Configs and Compatibility
-================================
-
-Two files are introduced:
-
-  a) 'arch/mips/include/asm/mach-au1x00/au1xxx_ide.h'
-     contains : struct _auide_hwif
-
-                - timing parameters for PIO mode 0/1/2/3/4
-                - timing parameters for MWDMA 0/1/2
-
-  b) 'drivers/ide/mips/au1xxx-ide.c'
-     contains the functionality of the AU1XXX IDE driver
-
-Following extra configs variables are introduced:
-
-  CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
-       - enable the PIO+DBDMA mode
-  CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-       - enable the MWDMA mode
-
-
-Supported IDE Modes
-===================
-
-The AU1XXX IDE driver supported all PIO modes - PIO mode 0/1/2/3/4 - and all
-MWDMA modes - MWDMA 0/1/2 -. There is no support for SWDMA and UDMA mode.
-
-To change the PIO mode use the program hdparm with option -p, e.g.
-'hdparm -p0 [device]' for PIO mode 0. To enable the MWDMA mode use the option
--X, e.g. 'hdparm -X32 [device]' for MWDMA mode 0.
-
-
-Performance Configurations
-==========================
-
-If the used system doesn't need USB support enable the following kernel
-configs::
-
-    CONFIG_IDE=y
-    CONFIG_BLK_DEV_IDE=y
-    CONFIG_IDE_GENERIC=y
-    CONFIG_BLK_DEV_IDEPCI=y
-    CONFIG_BLK_DEV_GENERIC=y
-    CONFIG_BLK_DEV_IDEDMA_PCI=y
-    CONFIG_BLK_DEV_IDE_AU1XXX=y
-    CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y
-    CONFIG_BLK_DEV_IDEDMA=y
-
-Also define 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to enable
-the burst support on DBDMA controller.
-
-If the used system need the USB support enable the following kernel configs for
-high IDE to USB throughput.
-
-::
-
-    CONFIG_IDE_GENERIC=y
-    CONFIG_BLK_DEV_IDEPCI=y
-    CONFIG_BLK_DEV_GENERIC=y
-    CONFIG_BLK_DEV_IDEDMA_PCI=y
-    CONFIG_BLK_DEV_IDE_AU1XXX=y
-    CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=y
-    CONFIG_BLK_DEV_IDEDMA=y
-
-Also undefine 'IDE_AU1XXX_BURSTMODE' in 'drivers/ide/mips/au1xxx-ide.c' to
-disable the burst support on DBDMA controller.
-
-
-Acknowledgments
-===============
-
-These drivers wouldn't have been done without the base of kernel 2.4.x AU1XXX
-IDE driver from AMD.
-
-Additional input also from:
-Matthias Lenk <matthias.lenk@amd.com>
-
-Happy hacking!
-
-Enrico Walther <enrico.walther@amd.com>
index a93c2f6..d5ad8c0 100644 (file)
@@ -10,8 +10,6 @@ MIPS-specific Documentation
 
    ingenic-tcu
 
-   au1xxx_ide
-
 .. only::  subproject and html
 
    Indices
index f11c5da..c1dcd26 100644 (file)
@@ -20,4 +20,5 @@ fit into other categories.
    isl29003
    lis3lv02d
    max6875
+   mic/index
    xilinx_sdfec
index 1a7683e..8b46e85 100644 (file)
@@ -40,9 +40,6 @@ example usage
     # Delete a snapshot using:
     $ devlink region del pci/0000:00:05.0/cr-space snapshot 1
 
-    # Trigger (request) a snapshot be taken:
-    $ devlink region trigger pci/0000:00:05.0/cr-space
-
     # Dump a snapshot:
     $ devlink region dump pci/0000:00:05.0/fw-health snapshot 1
     0000000000000000 0014 95dc 0014 9514 0035 1670 0034 db30
index 06c97dc..e143ab7 100644 (file)
@@ -8,9 +8,9 @@ Overview
 ========
 
 The net_failover driver provides an automated failover mechanism via APIs
-to create and destroy a failover master netdev and mananges a primary and
+to create and destroy a failover master netdev and manages a primary and
 standby slave netdevs that get registered via the generic failover
-infrastructrure.
+infrastructure.
 
 The failover netdev acts a master device and controls 2 slave devices. The
 original paravirtual interface is registered as 'standby' slave netdev and
@@ -29,7 +29,7 @@ virtio-net accelerated datapath: STANDBY mode
 =============================================
 
 net_failover enables hypervisor controlled accelerated datapath to virtio-net
-enabled VMs in a transparent manner with no/minimal guest userspace chanages.
+enabled VMs in a transparent manner with no/minimal guest userspace changes.
 
 To support this, the hypervisor needs to enable VIRTIO_NET_F_STANDBY
 feature on the virtio-net interface and assign the same MAC address to both
index 1e4735c..2561060 100644 (file)
@@ -487,8 +487,9 @@ phy_register_fixup_for_id()::
 The stubs set one of the two matching criteria, and set the other one to
 match anything.
 
-When phy_register_fixup() or \*_for_uid()/\*_for_id() is called at module,
-unregister fixup and free allocate memory are required.
+When phy_register_fixup() or \*_for_uid()/\*_for_id() is called at module load
+time, the module needs to unregister the fixup and free allocated memory when
+it's unloaded.
 
 Call one of following function before unloading module::
 
index f2a0147..eec6169 100644 (file)
@@ -159,7 +159,7 @@ Socket Interface
        set SO_RDS_TRANSPORT on a socket for which the transport has
        been previously attached explicitly (by SO_RDS_TRANSPORT) or
        implicitly (via bind(2)) will return an error of EOPNOTSUPP.
-       An attempt to set SO_RDS_TRANSPPORT to RDS_TRANS_NONE will
+       An attempt to set SO_RDS_TRANSPORT to RDS_TRANS_NONE will
        always return EINVAL.
 
 RDMA for RDS
index 38a4edc..10e1109 100644 (file)
@@ -908,8 +908,8 @@ A TLP probe packet is sent.
 
 A packet loss is detected and recovered by TLP.
 
-TCP Fast Open
-=============
+TCP Fast Open description
+=========================
 TCP Fast Open is a technology which allows data transfer before the
 3-way handshake complete. Please refer the `TCP Fast Open wiki`_ for a
 general description.
index 002e427..ced8a80 100644 (file)
@@ -13,7 +13,6 @@ Power Management
     drivers-testing
     energy-model
     freezing-of-tasks
-    interface
     opp
     pci
     pm_qos_interface
index 0d62d50..69b0fe3 100644 (file)
@@ -7,86 +7,78 @@ performance expectations by drivers, subsystems and user space applications on
 one of the parameters.
 
 Two different PM QoS frameworks are available:
-1. PM QoS classes for cpu_dma_latency
-2. The per-device PM QoS framework provides the API to manage the
+ * CPU latency QoS.
+ * The per-device PM QoS framework provides the API to manage the
    per-device latency constraints and PM QoS flags.
 
-Each parameters have defined units:
-
- * latency: usec
- * timeout: usec
- * throughput: kbs (kilo bit / sec)
- * memory bandwidth: mbs (mega bit / sec)
+The latency unit used in the PM QoS framework is the microsecond (usec).
 
 
 1. PM QoS framework
 ===================
 
-The infrastructure exposes multiple misc device nodes one per implemented
-parameter.  The set of parameters implement is defined by pm_qos_power_init()
-and pm_qos_params.h.  This is done because having the available parameters
-being runtime configurable or changeable from a driver was seen as too easy to
-abuse.
-
-For each parameter a list of performance requests is maintained along with
-an aggregated target value.  The aggregated target value is updated with
-changes to the request list or elements of the list.  Typically the
-aggregated target value is simply the max or min of the request values held
-in the parameter list elements.
+A global list of CPU latency QoS requests is maintained along with an aggregated
+(effective) target value.  The aggregated target value is updated with changes
+to the request list or elements of the list.  For CPU latency QoS, the
+aggregated target value is simply the min of the request values held in the list
+elements.
+
 Note: the aggregated target value is implemented as an atomic variable so that
 reading the aggregated value does not require any locking mechanism.
 
+From kernel space the use of this interface is simple:
 
-From kernel mode the use of this interface is simple:
-
-void pm_qos_add_request(handle, param_class, target_value):
-  Will insert an element into the list for that identified PM QoS class with the
-  target value.  Upon change to this list the new target is recomputed and any
-  registered notifiers are called only if the target value is now different.
-  Clients of pm_qos need to save the returned handle for future use in other
-  pm_qos API functions.
+void cpu_latency_qos_add_request(handle, target_value):
+  Will insert an element into the CPU latency QoS list with the target value.
+  Upon change to this list the new target is recomputed and any registered
+  notifiers are called only if the target value is now different.
+  Clients of PM QoS need to save the returned handle for future use in other
+  PM QoS API functions.
 
-void pm_qos_update_request(handle, new_target_value):
+void cpu_latency_qos_update_request(handle, new_target_value):
   Will update the list element pointed to by the handle with the new target
   value and recompute the new aggregated target, calling the notification tree
   if the target is changed.
 
-void pm_qos_remove_request(handle):
+void cpu_latency_qos_remove_request(handle):
   Will remove the element.  After removal it will update the aggregate target
   and call the notification tree if the target was changed as a result of
   removing the request.
 
-int pm_qos_request(param_class):
-  Returns the aggregated value for a given PM QoS class.
+int cpu_latency_qos_limit():
+  Returns the aggregated value for the CPU latency QoS.
+
+int cpu_latency_qos_request_active(handle):
+  Returns if the request is still active, i.e. it has not been removed from the
+  CPU latency QoS list.
 
-int pm_qos_request_active(handle):
-  Returns if the request is still active, i.e. it has not been removed from a
-  PM QoS class constraints list.
+int cpu_latency_qos_add_notifier(notifier):
+  Adds a notification callback function to the CPU latency QoS. The callback is
+  called when the aggregated value for the CPU latency QoS is changed.
 
-int pm_qos_add_notifier(param_class, notifier):
-  Adds a notification callback function to the PM QoS class. The callback is
-  called when the aggregated value for the PM QoS class is changed.
+int cpu_latency_qos_remove_notifier(notifier):
+  Removes the notification callback function from the CPU latency QoS.
 
-int pm_qos_remove_notifier(int param_class, notifier):
-  Removes the notification callback function for the PM QoS class.
 
+From user space:
 
-From user mode:
+The infrastructure exposes one device node, /dev/cpu_dma_latency, for the CPU
+latency QoS.
 
-Only processes can register a pm_qos request.  To provide for automatic
+Only processes can register a PM QoS request.  To provide for automatic
 cleanup of a process, the interface requires the process to register its
-parameter requests in the following way:
+parameter requests as follows.
 
-To register the default pm_qos target for the specific parameter, the process
-must open /dev/cpu_dma_latency
+To register the default PM QoS target for the CPU latency QoS, the process must
+open /dev/cpu_dma_latency.
 
 As long as the device node is held open that process has a registered
 request on the parameter.
 
-To change the requested target value the process needs to write an s32 value to
-the open device node.  Alternatively the user mode program could write a hex
-string for the value using 10 char long format e.g. "0x12345678".  This
-translates to a pm_qos_update_request call.
+To change the requested target value, the process needs to write an s32 value to
+the open device node.  Alternatively, it can write a hex string for the value
+using the 10 char long format e.g. "0x12345678".  This translates to a
+cpu_latency_qos_update_request() call.
 
 To remove the user mode request for a target value simply close the device
 node.
index ab8406c..0553008 100644 (file)
@@ -382,6 +382,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       nonzero, increment the counter and return 1; otherwise return 0 without
       changing the counter
 
+  `int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count);`
+    - return -EINVAL if 'power.disable_depth' is nonzero; otherwise, if the
+      runtime PM status is RPM_ACTIVE, and either ign_usage_count is true
+      or the device's usage_count is non-zero, increment the counter and
+      return 1; otherwise return 0 without changing the counter
+
   `void pm_runtime_put_noidle(struct device *dev);`
     - decrement the device's usage counter
 
index a0fa51b..1cf62d8 100644 (file)
@@ -69,11 +69,13 @@ SNAPSHOT_PREF_IMAGE_SIZE
 
 SNAPSHOT_GET_IMAGE_SIZE
        return the actual size of the hibernation image
+       (the last argument should be a pointer to a loff_t variable that
+       will contain the result if the call is successful)
 
 SNAPSHOT_AVAIL_SWAP_SIZE
-       return the amount of available swap in bytes (the
-       last argument should be a pointer to an unsigned int variable that will
-       contain the result if the call is successful).
+       return the amount of available swap in bytes
+       (the last argument should be a pointer to a loff_t variable that
+       will contain the result if the call is successful)
 
 SNAPSHOT_ALLOC_SWAP_PAGE
        allocate a swap page from the resume partition
index 363736d..df136c8 100644 (file)
@@ -8,8 +8,8 @@ Protected Execution Facility
 .. contents::
     :depth: 3
 
-Protected Execution Facility
-############################
+Introduction
+############
 
     Protected Execution Facility (PEF) is an architectural change for
     POWER 9 that enables Secure Virtual Machines (SVMs). DD2.3 chips
index ae020d8..b21b5b2 100644 (file)
@@ -18,18 +18,18 @@ major kernel release happening every two or three months.  The recent
 release history looks like this:
 
        ======  =================
-       4.11    April 30, 2017
-       4.12    July 2, 2017
-       4.13    September 3, 2017
-       4.14    November 12, 2017
-       4.15    January 28, 2018
-       4.16    April 1, 2018
+       5.0     March 3, 2019
+       5.1     May 5, 2019
+       5.2     July 7, 2019
+       5.3     September 15, 2019
+       5.4     November 24, 2019
+       5.5     January 6, 2020
        ======  =================
 
-Every 4.x release is a major kernel release with new features, internal
-API changes, and more.  A typical 4.x release contain about 13,000
-changesets with changes to several hundred thousand lines of code.  4.x is
-thus the leading edge of Linux kernel development; the kernel uses a
+Every 5.x release is a major kernel release with new features, internal
+API changes, and more.  A typical release can contain about 13,000
+changesets with changes to several hundred thousand lines of code.  5.x is
+the leading edge of Linux kernel development; the kernel uses a
 rolling development model which is continually integrating major changes.
 
 A relatively straightforward discipline is followed with regard to the
@@ -48,9 +48,9 @@ detail later on).
 
 The merge window lasts for approximately two weeks.  At the end of this
 time, Linus Torvalds will declare that the window is closed and release the
-first of the "rc" kernels.  For the kernel which is destined to be 2.6.40,
+first of the "rc" kernels.  For the kernel which is destined to be 5.6,
 for example, the release which happens at the end of the merge window will
-be called 2.6.40-rc1.  The -rc1 release is the signal that the time to
+be called 5.6-rc1.  The -rc1 release is the signal that the time to
 merge new features has passed, and that the time to stabilize the next
 kernel has begun.
 
@@ -67,22 +67,23 @@ add at any time).
 As fixes make their way into the mainline, the patch rate will slow over
 time.  Linus releases new -rc kernels about once a week; a normal series
 will get up to somewhere between -rc6 and -rc9 before the kernel is
-considered to be sufficiently stable and the final 2.6.x release is made.
+considered to be sufficiently stable and the final release is made.
 At that point the whole process starts over again.
 
-As an example, here is how the 4.16 development cycle went (all dates in
-2018):
+As an example, here is how the 5.4 development cycle went (all dates in
+2019):
 
        ==============  ===============================
-       January 28      4.15 stable release
-       February 11     4.16-rc1, merge window closes
-       February 18     4.16-rc2
-       February 25     4.16-rc3
-       March 4         4.16-rc4
-       March 11        4.16-rc5
-       March 18        4.16-rc6
-       March 25        4.16-rc7
-       April 1         4.16 stable release
+       September 15    5.3 stable release
+       September 30    5.4-rc1, merge window closes
+       October 6       5.4-rc2
+       October 13      5.4-rc3
+       October 20      5.4-rc4
+       October 27      5.4-rc5
+       November 3      5.4-rc6
+       November 10     5.4-rc7
+       November 17     5.4-rc8
+       November 24     5.4 stable release
        ==============  ===============================
 
 How do the developers decide when to close the development cycle and create
@@ -98,43 +99,44 @@ release is made.  In the real world, this kind of perfection is hard to
 achieve; there are just too many variables in a project of this size.
 There comes a point where delaying the final release just makes the problem
 worse; the pile of changes waiting for the next merge window will grow
-larger, creating even more regressions the next time around.  So most 4.x
+larger, creating even more regressions the next time around.  So most 5.x
 kernels go out with a handful of known regressions though, hopefully, none
 of them are serious.
 
 Once a stable release is made, its ongoing maintenance is passed off to the
-"stable team," currently consisting of Greg Kroah-Hartman.  The stable team
-will release occasional updates to the stable release using the 4.x.y
-numbering scheme.  To be considered for an update release, a patch must (1)
-fix a significant bug, and (2) already be merged into the mainline for the
-next development kernel.  Kernels will typically receive stable updates for
-a little more than one development cycle past their initial release.  So,
-for example, the 4.13 kernel's history looked like:
+"stable team," currently Greg Kroah-Hartman. The stable team will release
+occasional updates to the stable release using the 5.x.y numbering scheme.
+To be considered for an update release, a patch must (1) fix a significant
+bug, and (2) already be merged into the mainline for the next development
+kernel. Kernels will typically receive stable updates for a little more
+than one development cycle past their initial release. So, for example, the
+5.2 kernel's history looked like this (all dates in 2019):
 
        ==============  ===============================
-       September 3     4.13 stable release
-       September 13    4.13.1
-       September 20    4.13.2
-       September 27    4.13.3
-       October 5       4.13.4
-       October 12      4.13.5
+       September 15    5.2 stable release
+       July 14         5.2.1
+       July 21         5.2.2
+       July 26         5.2.3
+       July 28         5.2.4
+       July 31         5.2.5
        ...             ...
-       November 24     4.13.16
+       October 11      5.2.21
        ==============  ===============================
 
-4.13.16 was the final stable update of the 4.13 release.
+5.2.21 was the final stable update of the 5.2 release.
 
 Some kernels are designated "long term" kernels; they will receive support
 for a longer period.  As of this writing, the current long term kernels
 and their maintainers are:
 
-       ======  ======================  ==============================
-       3.16    Ben Hutchings           (very long-term stable kernel)
-       4.1     Sasha Levin
-       4.4     Greg Kroah-Hartman      (very long-term stable kernel)
-       4.9     Greg Kroah-Hartman
-       4.14    Greg Kroah-Hartman
-       ======  ======================  ==============================
+       ======  ================================        =======================
+       3.16    Ben Hutchings                           (very long-term kernel)
+       4.4     Greg Kroah-Hartman & Sasha Levin        (very long-term kernel)
+       4.9     Greg Kroah-Hartman & Sasha Levin
+       4.14    Greg Kroah-Hartman & Sasha Levin
+       4.19    Greg Kroah-Hartman & Sasha Levin
+       5.4     Greg Kroah-Hartman & Sasha Levin
+       ======  ================================        =======================
 
 The selection of a kernel for long-term support is purely a matter of a
 maintainer having the need and the time to maintain that release.  There
@@ -215,12 +217,12 @@ How patches get into the Kernel
 -------------------------------
 
 There is exactly one person who can merge patches into the mainline kernel
-repository: Linus Torvalds.  But, of the over 9,500 patches which went
-into the 2.6.38 kernel, only 112 (around 1.3%) were directly chosen by Linus
-himself.  The kernel project has long since grown to a size where no single
-developer could possibly inspect and select every patch unassisted.  The
-way the kernel developers have addressed this growth is through the use of
-a lieutenant system built around a chain of trust.
+repository: Linus Torvalds. But, for example, of the over 9,500 patches
+which went into the 2.6.38 kernel, only 112 (around 1.3%) were directly
+chosen by Linus himself. The kernel project has long since grown to a size
+where no single developer could possibly inspect and select every patch
+unassisted. The way the kernel developers have addressed this growth is
+through the use of a lieutenant system built around a chain of trust.
 
 The kernel code base is logically broken down into a set of subsystems:
 networking, specific architecture support, memory management, video
index edb296c..acb2f1b 100644 (file)
@@ -284,9 +284,9 @@ context lines.
 4) Naming
 ---------
 
-C is a Spartan language, and so should your naming be.  Unlike Modula-2
-and Pascal programmers, C programmers do not use cute names like
-ThisVariableIsATemporaryCounter.  A C programmer would call that
+C is a Spartan language, and your naming conventions should follow suit.
+Unlike Modula-2 and Pascal programmers, C programmers do not use cute
+names like ThisVariableIsATemporaryCounter. A C programmer would call that
 variable ``tmp``, which is much easier to write, and not the least more
 difficult to understand.
 
@@ -300,9 +300,9 @@ that counts the number of active users, you should call that
 ``count_active_users()`` or similar, you should **not** call it ``cntusr()``.
 
 Encoding the type of a function into the name (so-called Hungarian
-notation) is brain damaged - the compiler knows the types anyway and can
-check those, and it only confuses the programmer.  No wonder MicroSoft
-makes buggy programs.
+notation) is asinine - the compiler knows the types anyway and can check
+those, and it only confuses the programmer. No wonder Microsoft makes buggy
+programs.
 
 LOCAL variable names should be short, and to the point.  If you have
 some random integer loop counter, it should probably be called ``i``.
@@ -806,9 +806,9 @@ covers RTL which is used frequently with assembly language in the kernel.
 ----------------------------
 
 Kernel developers like to be seen as literate. Do mind the spelling
-of kernel messages to make a good impression. Do not use crippled
-words like ``dont``; use ``do not`` or ``don't`` instead.  Make the messages
-concise, clear, and unambiguous.
+of kernel messages to make a good impression. Do not use incorrect
+contractions like ``dont``; use ``do not`` or ``don't`` instead. Make the
+messages concise, clear, and unambiguous.
 
 Kernel messages do not have to be terminated with a period.
 
index 179f2a5..652e2aa 100644 (file)
@@ -29,6 +29,28 @@ a header file, it isn't the full solution. Such interfaces must either
 be fully removed from the kernel, or added to this file to discourage
 others from using them in the future.
 
+BUG() and BUG_ON()
+------------------
+Use WARN() and WARN_ON() instead, and handle the "impossible"
+error condition as gracefully as possible. While the BUG()-family
+of APIs were originally designed to act as an "impossible situation"
+assert and to kill a kernel thread "safely", they turn out to just be
+too risky. (e.g. "In what order do locks need to be released? Have
+various states been restored?") Very commonly, using BUG() will
+destabilize a system or entirely break it, which makes it impossible
+to debug or even get viable crash reports. Linus has `very strong
+<https://lore.kernel.org/lkml/CA+55aFy6jNLsywVYdGp83AMrXBo_P-pkjkphPGrO=82SPKCpLQ@mail.gmail.com/>`_
+feelings `about this
+<https://lore.kernel.org/lkml/CAHk-=whDHsbK3HTOpTF=ue_o04onRwTEaK_ZoJp_fjbqq4+=Jw@mail.gmail.com/>`_.
+
+Note that the WARN()-family should only be used for "expected to
+be unreachable" situations. If you want to warn about "reachable
+but undesirable" situations, please use the pr_warn()-family of
+functions. System owners may have set the *panic_on_warn* sysctl,
+to make sure their systems do not continue running in the face of
+"unreachable" conditions. (For example, see commits like `this one
+<https://git.kernel.org/linus/d4689846881d160a4d12a514e991a740bcb5d65a>`_.)
+
 open-coded arithmetic in allocator arguments
 --------------------------------------------
 Dynamic size calculations (especially multiplication) should not be
@@ -63,51 +85,73 @@ Instead, use the helper::
 
        header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
 
-See :c:func:`array_size`, :c:func:`array3_size`, and :c:func:`struct_size`,
-for more details as well as the related :c:func:`check_add_overflow` and
-:c:func:`check_mul_overflow` family of functions.
+See array_size(), array3_size(), and struct_size(),
+for more details as well as the related check_add_overflow() and
+check_mul_overflow() family of functions.
 
 simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
 ----------------------------------------------------------------------
-The :c:func:`simple_strtol`, :c:func:`simple_strtoll`,
-:c:func:`simple_strtoul`, and :c:func:`simple_strtoull` functions
+The simple_strtol(), simple_strtoll(),
+simple_strtoul(), and simple_strtoull() functions
 explicitly ignore overflows, which may lead to unexpected results
-in callers. The respective :c:func:`kstrtol`, :c:func:`kstrtoll`,
-:c:func:`kstrtoul`, and :c:func:`kstrtoull` functions tend to be the
+in callers. The respective kstrtol(), kstrtoll(),
+kstrtoul(), and kstrtoull() functions tend to be the
 correct replacements, though note that those require the string to be
 NUL or newline terminated.
 
 strcpy()
 --------
-:c:func:`strcpy` performs no bounds checking on the destination
+strcpy() performs no bounds checking on the destination
 buffer. This could result in linear overflows beyond the
 end of the buffer, leading to all kinds of misbehaviors. While
 `CONFIG_FORTIFY_SOURCE=y` and various compiler flags help reduce the
 risk of using this function, there is no good reason to add new uses of
-this function. The safe replacement is :c:func:`strscpy`.
+this function. The safe replacement is strscpy().
 
 strncpy() on NUL-terminated strings
 -----------------------------------
-Use of :c:func:`strncpy` does not guarantee that the destination buffer
+Use of strncpy() does not guarantee that the destination buffer
 will be NUL terminated. This can lead to various linear read overflows
 and other misbehavior due to the missing termination. It also NUL-pads the
 destination buffer if the source contents are shorter than the destination
 buffer size, which may be a needless performance penalty for callers using
-only NUL-terminated strings. The safe replacement is :c:func:`strscpy`.
-(Users of :c:func:`strscpy` still needing NUL-padding will need an
-explicit :c:func:`memset` added.)
+only NUL-terminated strings. The safe replacement is strscpy().
+(Users of strscpy() still needing NUL-padding should instead
+use strscpy_pad().)
 
-If a caller is using non-NUL-terminated strings, :c:func:`strncpy()` can
+If a caller is using non-NUL-terminated strings, strncpy()() can
 still be used, but destinations should be marked with the `__nonstring
 <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
 attribute to avoid future compiler warnings.
 
 strlcpy()
 ---------
-:c:func:`strlcpy` reads the entire source buffer first, possibly exceeding
+strlcpy() reads the entire source buffer first, possibly exceeding
 the given limit of bytes to copy. This is inefficient and can lead to
 linear read overflows if a source string is not NUL-terminated. The
-safe replacement is :c:func:`strscpy`.
+safe replacement is strscpy().
+
+%p format specifier
+-------------------
+Traditionally, using "%p" in format strings would lead to regular address
+exposure flaws in dmesg, proc, sysfs, etc. Instead of leaving these to
+be exploitable, all "%p" uses in the kernel are being printed as a hashed
+value, rendering them unusable for addressing. New uses of "%p" should not
+be added to the kernel. For text addresses, using "%pS" is likely better,
+as it produces the more useful symbol name instead. For nearly everything
+else, just do not add "%p" at all.
+
+Paraphrasing Linus's current `guidance <https://lore.kernel.org/lkml/CA+55aFwQEd_d40g4mUCSsVRZzrFPUJt74vc6PPpb675hYNXcKw@mail.gmail.com/>`_:
+
+- If the hashed "%p" value is pointless, ask yourself whether the pointer
+  itself is important. Maybe it should be removed entirely?
+- If you really think the true pointer value is important, why is some
+  system state or user privilege level considered "special"? If you think
+  you can justify it (in comments and commit log) well enough to stand
+  up to Linus's scrutiny, maybe you can use "%px", along with making sure
+  you have sensible permissions.
+
+And finally, know that a toggle for "%p" hashing will `not be accepted <https://lore.kernel.org/lkml/CA+55aFwieC1-nAs+NFq9RTwaR8ef9hWa4MjNBWL41F-8wM49eA@mail.gmail.com/>`_.
 
 Variable Length Arrays (VLAs)
 -----------------------------
@@ -122,27 +166,37 @@ memory adjacent to the stack (when built without `CONFIG_VMAP_STACK=y`)
 
 Implicit switch case fall-through
 ---------------------------------
-The C language allows switch cases to "fall-through" when a "break" statement
-is missing at the end of a case. This, however, introduces ambiguity in the
-code, as it's not always clear if the missing break is intentional or a bug.
+The C language allows switch cases to fall through to the next case
+when a "break" statement is missing at the end of a case. This, however,
+introduces ambiguity in the code, as it's not always clear if the missing
+break is intentional or a bug. For example, it's not obvious just from
+looking at the code if `STATE_ONE` is intentionally designed to fall
+through into `STATE_TWO`::
+
+       switch (value) {
+       case STATE_ONE:
+               do_something();
+       case STATE_TWO:
+               do_other();
+               break;
+       default:
+               WARN("unknown state");
+       }
 
 As there have been a long list of flaws `due to missing "break" statements
 <https://cwe.mitre.org/data/definitions/484.html>`_, we no longer allow
-"implicit fall-through".
-
-In order to identify intentional fall-through cases, we have adopted a
-pseudo-keyword macro 'fallthrough' which expands to gcc's extension
-__attribute__((__fallthrough__)).  `Statement Attributes
-<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_
-
-When the C17/C18  [[fallthrough]] syntax is more commonly supported by
+implicit fall-through. In order to identify intentional fall-through
+cases, we have adopted a pseudo-keyword macro "fallthrough" which
+expands to gcc's extension `__attribute__((__fallthrough__))
+<https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html>`_.
+(When the C17/C18  `[[fallthrough]]` syntax is more commonly supported by
 C compilers, static analyzers, and IDEs, we can switch to using that syntax
-for the macro pseudo-keyword.
+for the macro pseudo-keyword.)
 
 All switch/case blocks must end in one of:
 
-       break;
-       fallthrough;
-       continue;
-       goto <label>;
-       return [expression];
+* break;
+* fallthrough;
+* continue;
+* goto <label>;
+* return [expression];
index 5273d06..c9e4ce2 100644 (file)
@@ -237,9 +237,9 @@ using Mutt to send patches through Gmail::
 
 The Mutt docs have lots more information:
 
-    http://dev.mutt.org/trac/wiki/UseCases/Gmail
+    https://gitlab.com/muttmua/mutt/-/wikis/UseCases/Gmail
 
-    http://dev.mutt.org/doc/manual.html
+    http://www.mutt.org/doc/manual/
 
 Pine (TUI)
 **********
index b6f5a37..70791e1 100644 (file)
@@ -243,10 +243,10 @@ branches.  These different branches are:
 Mainline tree
 ~~~~~~~~~~~~~
 
-Mainline tree are maintained by Linus Torvalds, and can be found at
+The mainline tree is maintained by Linus Torvalds, and can be found at
 https://kernel.org or in the repo.  Its development process is as follows:
 
-  - As soon as a new kernel is released a two weeks window is open,
+  - As soon as a new kernel is released a two week window is open,
     during this period of time maintainers can submit big diffs to
     Linus, usually the patches that have already been included in the
     linux-next for a few weeks.  The preferred way to submit big changes
@@ -281,8 +281,9 @@ Various stable trees with multiple major numbers
 
 Kernels with 3-part versions are -stable kernels. They contain
 relatively small and critical fixes for security problems or significant
-regressions discovered in a given major mainline release, with the first
-2-part of version number are the same correspondingly.
+regressions discovered in a given major mainline release. Each release
+in a major stable series increments the third part of the version
+number, keeping the first two parts the same.
 
 This is the recommended branch for users who want the most recent stable
 kernel and are not interested in helping test development/experimental
@@ -359,10 +360,10 @@ Managing bug reports
 
 One of the best ways to put into practice your hacking skills is by fixing
 bugs reported by other people. Not only you will help to make the kernel
-more stable, you'll learn to fix real world problems and you will improve
-your skills, and other developers will be aware of your presence. Fixing
-bugs is one of the best ways to get merits among other developers, because
-not many people like wasting time fixing other people's bugs.
+more stable, but you'll also learn to fix real world problems and you will
+improve your skills, and other developers will be aware of your presence.
+Fixing bugs is one of the best ways to get merits among other developers,
+because not many people like wasting time fixing other people's bugs.
 
 To work in the already reported bug reports, go to https://bugzilla.kernel.org.
 
index 7a45a8e..9d6d0ac 100644 (file)
@@ -313,7 +313,7 @@ On-line docs
       :URL: http://www.linuxjournal.com/article.php?sid=2391
       :Date: 1997
       :Keywords: RAID, MD driver.
-      :Description: Linux Journal Kernel Korner article. Here is its
+      :Description: Linux Journal Kernel Korner article.
       :Abstract: *A description of the implementation of the RAID-1,
         RAID-4 and RAID-5 personalities of the MD device driver in the
         Linux kernel, providing users with high performance and reliable,
@@ -338,7 +338,7 @@ On-line docs
       :Date: 1996
       :Keywords: device driver, module, loading/unloading modules,
         allocating resources.
-      :Description: Linux Journal Kernel Korner article. Here is its
+      :Description: Linux Journal Kernel Korner article.
       :Abstract: *This is the first of a series of four articles
         co-authored by Alessandro Rubini and Georg Zezchwitz which present
         a practical approach to writing Linux device drivers as kernel
@@ -354,7 +354,7 @@ On-line docs
       :Keywords: character driver, init_module, clean_up module,
         autodetection, mayor number, minor number, file operations,
         open(), close().
-      :Description: Linux Journal Kernel Korner article. Here is its
+      :Description: Linux Journal Kernel Korner article.
       :Abstract: *This article, the second of four, introduces part of
         the actual code to create custom module implementing a character
         device driver. It describes the code for module initialization and
@@ -367,7 +367,7 @@ On-line docs
       :Date: 1996
       :Keywords: read(), write(), select(), ioctl(), blocking/non
         blocking mode, interrupt handler.
-      :Description: Linux Journal Kernel Korner article. Here is its
+      :Description: Linux Journal Kernel Korner article.
       :Abstract: *This article, the third of four on writing character
         device drivers, introduces concepts of reading, writing, and using
         ioctl-calls*.
@@ -378,7 +378,7 @@ On-line docs
       :URL: http://www.linuxjournal.com/article.php?sid=1222
       :Date: 1996
       :Keywords: interrupts, irqs, DMA, bottom halves, task queues.
-      :Description: Linux Journal Kernel Korner article. Here is its
+      :Description: Linux Journal Kernel Korner article.
       :Abstract: *This is the fourth in a series of articles about
         writing character device drivers as loadable kernel modules. This
         month, we further investigate the field of interrupt handling.
index 186753f..dfbc69b 100644 (file)
@@ -227,7 +227,7 @@ incompetence will grudgingly admit that you at least didn't try to weasel
 out of it.
 
 Then make the developer who really screwed up (if you can find them) know
-**in_private** that they screwed up.  Not just so they can avoid it in the
+**in private** that they screwed up.  Not just so they can avoid it in the
 future, but so that they know they owe you one.  And, perhaps even more
 importantly, they're also likely the person who can fix it.  Because, let's
 face it, it sure ain't you.
index 8a5d34a..f24904f 100644 (file)
@@ -61,8 +61,8 @@ setup that list.
   address of the associated 'lock entry', plus or minus, of what will
   be called the 'lock word', from that 'lock entry'.  The 'lock word'
   is always a 32 bit word, unlike the other words above.  The 'lock
-  word' holds 3 flag bits in the upper 3 bits, and the thread id (TID)
-  of the thread holding the lock in the bottom 29 bits.  See further
+  word' holds 2 flag bits in the upper 2 bits, and the thread id (TID)
+  of the thread holding the lock in the bottom 30 bits.  See further
   below for a description of the flag bits.
 
   The third word, called 'list_op_pending', contains transient copy of
@@ -128,7 +128,7 @@ that thread's robust_futex linked lock list a given time.
 A given futex lock structure in a user shared memory region may be held
 at different times by any of the threads with access to that region. The
 thread currently holding such a lock, if any, is marked with the threads
-TID in the lower 29 bits of the 'lock word'.
+TID in the lower 30 bits of the 'lock word'.
 
 When adding or removing a lock from its list of held locks, in order for
 the kernel to correctly handle lock cleanup regardless of when the task
@@ -141,7 +141,7 @@ On insertion:
  1) set the 'list_op_pending' word to the address of the 'lock entry'
     to be inserted,
  2) acquire the futex lock,
- 3) add the lock entry, with its thread id (TID) in the bottom 29 bits
+ 3) add the lock entry, with its thread id (TID) in the bottom 30 bits
     of the 'lock word', to the linked list starting at 'head', and
  4) clear the 'list_op_pending' word.
 
@@ -155,7 +155,7 @@ On removal:
 
 On exit, the kernel will consider the address stored in
 'list_op_pending' and the address of each 'lock word' found by walking
-the list starting at 'head'.  For each such address, if the bottom 29
+the list starting at 'head'.  For each such address, if the bottom 30
 bits of the 'lock word' at offset 'offset' from that address equals the
 exiting threads TID, then the kernel will do two things:
 
@@ -180,7 +180,5 @@ any point:
     future kernel configuration changes) elements.
 
 When the kernel sees a list entry whose 'lock word' doesn't have the
-current threads TID in the lower 29 bits, it does nothing with that
+current threads TID in the lower 30 bits, it does nothing with that
 entry, and goes on to the next entry.
-
-Bit 29 (0x20000000) of the 'lock word' is reserved for future use.
index 2a4be1c..537f047 100644 (file)
@@ -299,7 +299,6 @@ Summary:
    scsi_host_alloc - return a new scsi_host instance whose refcount==1
    scsi_host_get - increments Scsi_Host instance's refcount
    scsi_host_put - decrements Scsi_Host instance's refcount (free if 0)
-   scsi_partsize - parse partition table into cylinders, heads + sectors
    scsi_register - create and register a scsi host adapter instance.
    scsi_remove_device - detach and remove a SCSI device
    scsi_remove_host - detach and remove all SCSI devices owned by host
@@ -473,26 +472,6 @@ void scsi_host_put(struct Scsi_Host *shost)
 
 
 /**
- * scsi_partsize - parse partition table into cylinders, heads + sectors
- * @buf: pointer to partition table
- * @capacity: size of (total) disk in 512 byte sectors
- * @cyls: outputs number of cylinders calculated via this pointer
- * @hds: outputs number of heads calculated via this pointer
- * @secs: outputs number of sectors calculated via this pointer
- *
- *      Returns 0 on success, -1 on failure
- *
- *      Might block: no
- *
- *      Notes: Caller owns memory returned (free with kfree() )
- *
- *      Defined in: drivers/scsi/scsicam.c
- **/
-int scsi_partsize(unsigned char *buf, unsigned long capacity,
-                  unsigned int *cyls, unsigned int *hds, unsigned int *secs)
-
-
-/**
  * scsi_register - create and register a scsi host adapter instance.
  * @sht:        pointer to scsi host template
  * @privsize:   extra bytes to allocate in hostdata array (which is the
index 9965821..4eba68c 100644 (file)
@@ -128,8 +128,8 @@ then when you can be absolutely certain that the outputs will never be
 transmitted out of the kernel. This is only remotely useful over `jhash` as a
 means of mitigating hashtable flooding denial of service attacks.
 
-Generating a key
-================
+Generating a HalfSipHash key
+============================
 
 Keys should always be generated from a cryptographically secure source of
 random numbers, either using get_random_bytes or get_random_once:
@@ -139,8 +139,8 @@ get_random_bytes(&key, sizeof(key));
 
 If you're not deriving your key from here, you're doing it wrong.
 
-Using the functions
-===================
+Using the HalfSipHash functions
+===============================
 
 There are two variants of the function, one that takes a list of integers, and
 one that takes a buffer::
index 7daf513..e54c44c 100644 (file)
@@ -30,4 +30,4 @@ if [ -n "$parallel" ] ; then
        parallel="-j$parallel"
 fi
 
-exec "$sphinx" "$parallel" "$@"
+exec "$sphinx" $parallel "$@"
index a7b4267..e47047e 100644 (file)
@@ -5,7 +5,7 @@ TCM Userspace Design
 
 .. Contents:
 
-   1) TCM Userspace Design
+   1) Design
      a) Background
      b) Benefits
      c) Design constraints
@@ -23,8 +23,8 @@ TCM Userspace Design
    3) A final note
 
 
-TCM Userspace Design
-====================
+Design
+======
 
 TCM is another name for LIO, an in-kernel iSCSI target (server).
 Existing TCM targets run in the kernel.  TCMU (TCM in Userspace)
index 2ef3189..f45bf11 100644 (file)
@@ -75,16 +75,6 @@ The PM QoS events are used for QoS add/update/remove request and for
 target/flags update.
 ::
 
-  pm_qos_add_request                 "pm_qos_class=%s value=%d"
-  pm_qos_update_request              "pm_qos_class=%s value=%d"
-  pm_qos_remove_request              "pm_qos_class=%s value=%d"
-  pm_qos_update_request_timeout      "pm_qos_class=%s value=%d, timeout_us=%ld"
-
-The first parameter gives the QoS class name (e.g. "CPU_DMA_LATENCY").
-The second parameter is value to be added/updated/removed.
-The third parameter is timeout value in usec.
-::
-
   pm_qos_update_target               "action=%s prev_value=%d curr_value=%d"
   pm_qos_update_flags                "action=%s prev_value=0x%x curr_value=0x%x"
 
@@ -92,7 +82,7 @@ The first parameter gives the QoS action name (e.g. "ADD_REQ").
 The second parameter is the previous QoS value.
 The third parameter is the current QoS value to update.
 
-And, there are also events used for device PM QoS add/update/remove request.
+There are also events used for device PM QoS add/update/remove request.
 ::
 
   dev_pm_qos_add_request             "device=%s type=%s new_value=%d"
@@ -103,3 +93,12 @@ The first parameter gives the device name which tries to add/update/remove
 QoS requests.
 The second parameter gives the request type (e.g. "DEV_PM_QOS_RESUME_LATENCY").
 The third parameter is value to be added/updated/removed.
+
+And, there are events used for CPU latency QoS add/update/remove request.
+::
+
+  pm_qos_add_request        "value=%d"
+  pm_qos_update_request     "value=%d"
+  pm_qos_remove_request     "value=%d"
+
+The parameter is the value to be added/updated/removed.
index ed79b22..4a2ebe0 100644 (file)
@@ -342,7 +342,8 @@ section of Documentation/trace/ftrace.rst), but there are major
 differences and the implementation isn't currently tied to it in any
 way, so beware about making generalizations between the two.
 
-Note: Writing into trace_marker (See Documentation/trace/ftrace.rst)
+.. Note::
+     Writing into trace_marker (See Documentation/trace/ftrace.rst)
      can also enable triggers that are written into
      /sys/kernel/tracing/events/ftrace/print/trigger
 
@@ -569,14 +570,14 @@ The first creates the event in one step, using synth_event_create().
 In this method, the name of the event to create and an array defining
 the fields is supplied to synth_event_create().  If successful, a
 synthetic event with that name and fields will exist following that
-call.  For example, to create a new "schedtest" synthetic event:
+call.  For example, to create a new "schedtest" synthetic event::
 
   ret = synth_event_create("schedtest", sched_fields,
                            ARRAY_SIZE(sched_fields), THIS_MODULE);
 
 The sched_fields param in this example points to an array of struct
 synth_field_desc, each of which describes an event field by type and
-name:
+name::
 
   static struct synth_field_desc sched_fields[] = {
         { .type = "pid_t",              .name = "next_pid_field" },
@@ -615,7 +616,7 @@ synth_event_gen_cmd_array_start(), the user should create and
 initialize a dynevent_cmd object using synth_event_cmd_init().
 
 For example, to create a new "schedtest" synthetic event with two
-fields:
+fields::
 
   struct dynevent_cmd cmd;
   char *buf;
@@ -631,7 +632,7 @@ fields:
                                   "u64", "ts_ns");
 
 Alternatively, using an array of struct synth_field_desc fields
-containing the same information:
+containing the same information::
 
   ret = synth_event_gen_cmd_array_start(&cmd, "schedtest", THIS_MODULE,
                                         fields, n_fields);
@@ -640,7 +641,7 @@ Once the synthetic event object has been created, it can then be
 populated with more fields.  Fields are added one by one using
 synth_event_add_field(), supplying the dynevent_cmd object, a field
 type, and a field name.  For example, to add a new int field named
-"intfield", the following call should be made:
+"intfield", the following call should be made::
 
   ret = synth_event_add_field(&cmd, "int", "intfield");
 
@@ -649,7 +650,7 @@ the field is considered to be an array.
 
 A group of fields can also be added all at once using an array of
 synth_field_desc with add_synth_fields().  For example, this would add
-just the first four sched_fields:
+just the first four sched_fields::
 
   ret = synth_event_add_fields(&cmd, sched_fields, 4);
 
@@ -658,7 +659,7 @@ synth_event_add_field_str() can be used to add it as-is; it will
 also automatically append a ';' to the string.
 
 Once all the fields have been added, the event should be finalized and
-registered by calling the synth_event_gen_cmd_end() function:
+registered by calling the synth_event_gen_cmd_end() function::
 
   ret = synth_event_gen_cmd_end(&cmd);
 
@@ -691,7 +692,7 @@ trace array)), along with an variable number of u64 args, one for each
 synthetic event field, and the number of values being passed.
 
 So, to trace an event corresponding to the synthetic event definition
-above, code like the following could be used:
+above, code like the following could be used::
 
   ret = synth_event_trace(create_synth_test, 7, /* number of values */
                           444,             /* next_pid_field */
@@ -715,7 +716,7 @@ trace array)), along with an array of u64, one for each synthetic
 event field.
 
 To trace an event corresponding to the synthetic event definition
-above, code like the following could be used:
+above, code like the following could be used::
 
   u64 vals[7];
 
@@ -739,7 +740,7 @@ In order to trace a synthetic event, a pointer to the trace event file
 is needed.  The trace_get_event_file() function can be used to get
 it - it will find the file in the given trace instance (in this case
 NULL since the top trace array is being used) while at the same time
-preventing the instance containing it from going away:
+preventing the instance containing it from going away::
 
        schedtest_event_file = trace_get_event_file(NULL, "synthetic",
                                                    "schedtest");
@@ -751,31 +752,31 @@ To enable a synthetic event from the kernel, trace_array_set_clr_event()
 can be used (which is not specific to synthetic events, so does need
 the "synthetic" system name to be specified explicitly).
 
-To enable the event, pass 'true' to it:
+To enable the event, pass 'true' to it::
 
        trace_array_set_clr_event(schedtest_event_file->tr,
                                  "synthetic", "schedtest", true);
 
-To disable it pass false:
+To disable it pass false::
 
        trace_array_set_clr_event(schedtest_event_file->tr,
                                  "synthetic", "schedtest", false);
 
 Finally, synth_event_trace_array() can be used to actually trace the
-event, which should be visible in the trace buffer afterwards:
+event, which should be visible in the trace buffer afterwards::
 
        ret = synth_event_trace_array(schedtest_event_file, vals,
                                      ARRAY_SIZE(vals));
 
 To remove the synthetic event, the event should be disabled, and the
-trace instance should be 'put' back using trace_put_event_file():
+trace instance should be 'put' back using trace_put_event_file()::
 
        trace_array_set_clr_event(schedtest_event_file->tr,
                                  "synthetic", "schedtest", false);
        trace_put_event_file(schedtest_event_file);
 
 If those have been successful, synth_event_delete() can be called to
-remove the event:
+remove the event::
 
        ret = synth_event_delete("schedtest");
 
@@ -784,7 +785,7 @@ remove the event:
 
 To trace a synthetic using the piecewise method described above, the
 synth_event_trace_start() function is used to 'open' the synthetic
-event trace:
+event trace::
 
        struct synth_trace_state trace_state;
 
@@ -809,7 +810,7 @@ along with the value to set the next field in the event.  After each
 field is set, the 'cursor' points to the next field, which will be set
 by the subsequent call, continuing until all the fields have been set
 in order.  The same sequence of calls as in the above examples using
-this method would be (without error-handling code):
+this method would be (without error-handling code)::
 
        /* next_pid_field */
        ret = synth_event_add_next_val(777, &trace_state);
@@ -837,7 +838,7 @@ used.  Each call is passed the same synth_trace_state object used in
 the synth_event_trace_start(), along with the field name of the field
 to set and the value to set it to.  The same sequence of calls as in
 the above examples using this method would be (without error-handling
-code):
+code)::
 
        ret = synth_event_add_val("next_pid_field", 777, &trace_state);
        ret = synth_event_add_val("next_comm_field", (u64)"silly putty",
@@ -855,7 +856,7 @@ can be used but not both at the same time.
 
 Finally, the event won't be actually traced until it's 'closed',
 which is done using synth_event_trace_end(), which takes only the
-struct synth_trace_state object used in the previous calls:
+struct synth_trace_state object used in the previous calls::
 
        ret = synth_event_trace_end(&trace_state);
 
@@ -878,7 +879,7 @@ function.  Before calling kprobe_event_gen_cmd_start(), the user
 should create and initialize a dynevent_cmd object using
 kprobe_event_cmd_init().
 
-For example, to create a new "schedtest" kprobe event with two fields:
+For example, to create a new "schedtest" kprobe event with two fields::
 
   struct dynevent_cmd cmd;
   char *buf;
@@ -900,18 +901,18 @@ Once the kprobe event object has been created, it can then be
 populated with more fields.  Fields can be added using
 kprobe_event_add_fields(), supplying the dynevent_cmd object along
 with a variable arg list of probe fields.  For example, to add a
-couple additional fields, the following call could be made:
+couple additional fields, the following call could be made::
 
   ret = kprobe_event_add_fields(&cmd, "flags=%cx", "mode=+4($stack)");
 
 Once all the fields have been added, the event should be finalized and
 registered by calling the kprobe_event_gen_cmd_end() or
 kretprobe_event_gen_cmd_end() functions, depending on whether a kprobe
-or kretprobe command was started:
+or kretprobe command was started::
 
   ret = kprobe_event_gen_cmd_end(&cmd);
 
-or
+or::
 
   ret = kretprobe_event_gen_cmd_end(&cmd);
 
@@ -920,13 +921,13 @@ events.
 
 Similarly, a kretprobe event can be created using
 kretprobe_event_gen_cmd_start() with a probe name and location and
-additional params such as $retval:
+additional params such as $retval::
 
   ret = kretprobe_event_gen_cmd_start(&cmd, "gen_kretprobe_test",
                                       "do_sys_open", "$retval");
 
 Similar to the synthetic event case, code like the following can be
-used to enable the newly created kprobe event:
+used to enable the newly created kprobe event::
 
   gen_kprobe_test = trace_get_event_file(NULL, "kprobes", "gen_kprobe_test");
 
@@ -934,7 +935,7 @@ used to enable the newly created kprobe event:
                                   "kprobes", "gen_kprobe_test", true);
 
 Finally, also similar to synthetic events, the following code can be
-used to give the kprobe event file back and delete the event:
+used to give the kprobe event file back and delete the event::
 
   trace_put_event_file(gen_kprobe_test);
 
@@ -963,7 +964,7 @@ are described below.
 
 The first step in building a new command string is to create and
 initialize an instance of a dynevent_cmd.  Here, for instance, we
-create a dynevent_cmd on the stack and initialize it:
+create a dynevent_cmd on the stack and initialize it::
 
   struct dynevent_cmd cmd;
   char *buf;
@@ -989,7 +990,7 @@ calls to argument-adding functions.
 To add a single argument, define and initialize a struct dynevent_arg
 or struct dynevent_arg_pair object.  Here's an example of the simplest
 possible arg addition, which is simply to append the given string as
-a whitespace-separated argument to the command:
+a whitespace-separated argument to the command::
 
   struct dynevent_arg arg;
 
@@ -1007,7 +1008,7 @@ the arg.
 Here's another more complicated example using an 'arg pair', which is
 used to create an argument that consists of a couple components added
 together as a unit, for example, a 'type field_name;' arg or a simple
-expression arg e.g. 'flags=%cx':
+expression arg e.g. 'flags=%cx'::
 
   struct dynevent_arg_pair arg_pair;
 
@@ -1031,7 +1032,7 @@ Any number of dynevent_*_add() calls can be made to build up the string
 (until its length surpasses cmd->maxlen).  When all the arguments have
 been added and the command string is complete, the only thing left to
 do is run the command, which happens by simply calling
-dynevent_create():
+dynevent_create()::
 
   ret = dynevent_create(&cmd);
 
index 8489ead..7e2456b 100644 (file)
@@ -1,6 +1,6 @@
 .. include:: ../disclaimer-ita.rst
 
-:Original: :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
+:Original: :ref:`Documentation/networking/netdev-FAQ.rst <netdev-FAQ>`
 
 .. _it_netdev-FAQ:
 
index f4b0063..c4fc9d3 100644 (file)
@@ -8,26 +8,26 @@
 Linguaggio di programmazione
 ============================
 
-Il kernel è scritto nel linguaggio di programmazione C [c-language]_.
-Più precisamente, il kernel viene compilato con ``gcc`` [gcc]_ usando
-l'opzione ``-std=gnu89`` [gcc-c-dialect-options]_: il dialetto GNU
+Il kernel è scritto nel linguaggio di programmazione C [it-c-language]_.
+Più precisamente, il kernel viene compilato con ``gcc`` [it-gcc]_ usando
+l'opzione ``-std=gnu89`` [it-gcc-c-dialect-options]_: il dialetto GNU
 dello standard ISO C90 (con l'aggiunta di alcune funzionalità da C99)
 
-Questo dialetto contiene diverse estensioni al linguaggio [gnu-extensions]_,
+Questo dialetto contiene diverse estensioni al linguaggio [it-gnu-extensions]_,
 e molte di queste vengono usate sistematicamente dal kernel.
 
 Il kernel offre un certo livello di supporto per la compilazione con ``clang``
-[clang]_ e ``icc`` [icc]_ su diverse architetture, tuttavia in questo momento
+[it-clang]_ e ``icc`` [it-icc]_ su diverse architetture, tuttavia in questo momento
 il supporto non è completo e richiede delle patch aggiuntive.
 
 Attributi
 ---------
 
 Una delle estensioni più comuni e usate nel kernel sono gli attributi
-[gcc-attribute-syntax]_. Gli attributi permettono di aggiungere una semantica,
+[it-gcc-attribute-syntax]_. Gli attributi permettono di aggiungere una semantica,
 definita dell'implementazione, alle entità del linguaggio (come le variabili,
 le funzioni o i tipi) senza dover fare importanti modifiche sintattiche al
-linguaggio stesso (come l'aggiunta di nuove parole chiave) [n2049]_.
+linguaggio stesso (come l'aggiunta di nuove parole chiave) [it-n2049]_.
 
 In alcuni casi, gli attributi sono opzionali (ovvero un compilatore che non
 dovesse supportarli dovrebbe produrre comunque codice corretto, anche se
@@ -41,11 +41,11 @@ possono usare e/o per accorciare il codice.
 Per maggiori informazioni consultate il file d'intestazione
 ``include/linux/compiler_attributes.h``.
 
-.. [c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards
-.. [gcc] https://gcc.gnu.org
-.. [clang] https://clang.llvm.org
-.. [icc] https://software.intel.com/en-us/c-compilers
-.. [gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
-.. [gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
-.. [gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
-.. [n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
+.. [it-c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards
+.. [it-gcc] https://gcc.gnu.org
+.. [it-clang] https://clang.llvm.org
+.. [it-icc] https://software.intel.com/en-us/c-compilers
+.. [it-gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
+.. [it-gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
+.. [it-gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+.. [it-n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
diff --git a/Documentation/translations/zh_CN/filesystems/index.rst b/Documentation/translations/zh_CN/filesystems/index.rst
new file mode 100644 (file)
index 0000000..14f155e
--- /dev/null
@@ -0,0 +1,27 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/filesystems/index.rst <filesystems_index>`
+:Translator: Wang Wenhu <wenhu.wang@vivo.com>
+
+.. _cn_filesystems_index:
+
+========================
+Linux Kernel中的文件系统
+========================
+
+这份正在开发的手册或许在未来某个辉煌的日子里以易懂的形式将Linux虚拟\
+文件系统(VFS)层以及基于其上的各种文件系统如何工作呈现给大家。当前\
+可以看到下面的内容。
+
+文件系统
+========
+
+文件系统实现文档。
+
+.. toctree::
+   :maxdepth: 2
+
+   virtiofs
+
diff --git a/Documentation/translations/zh_CN/filesystems/virtiofs.rst b/Documentation/translations/zh_CN/filesystems/virtiofs.rst
new file mode 100644 (file)
index 0000000..09bc9e0
--- /dev/null
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. include:: ../disclaimer-zh_CN.rst
+
+:Original: :ref:`Documentation/filesystems/virtiofs.rst <virtiofs_index>`
+
+译者
+::
+
+       中文版维护者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+       中文版翻译者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+       中文版校译者: 王文虎 Wang Wenhu <wenhu.wang@vivo.com>
+
+===========================================
+virtiofs: virtio-fs 主机<->客机共享文件系统
+===========================================
+
+- Copyright (C) 2020 Vivo Communication Technology Co. Ltd.
+
+介绍
+====
+Linux的virtiofs文件系统实现了一个半虚拟化VIRTIO类型“virtio-fs”设备的驱动,通过该\
+类型设备实现客机<->主机文件系统共享。它允许客机挂载一个已经导出到主机的目录。
+
+客机通常需要访问主机或者远程系统上的文件。使用场景包括:在新客机安装时让文件对其\
+可见;从主机上的根文件系统启动;对无状态或临时客机提供持久存储和在客机之间共享目录。
+
+尽管在某些任务可能通过使用已有的网络文件系统完成,但是却需要非常难以自动化的配置\
+步骤,且将存储网络暴露给客机。而virtio-fs设备通过提供不经过网络的文件系统访问文件\
+的设计方式解决了这些问题。
+
+另外,virto-fs设备发挥了主客机共存的优点提高了性能,并且提供了网络文件系统所不具备
+的一些语义功能。
+
+用法
+====
+以``myfs``标签将文件系统挂载到``/mnt``:
+
+.. code-block:: sh
+
+  guest# mount -t virtiofs myfs /mnt
+
+请查阅 https://virtio-fs.gitlab.io/ 了解配置QEMU和virtiofsd守护程序的详细信息。
+
+内幕
+====
+由于virtio-fs设备将FUSE协议用于文件系统请求,因此Linux的virtiofs文件系统与FUSE文\
+件系统客户端紧密集成在一起。客机充当FUSE客户端而主机充当FUSE服务器,内核与用户空\
+间之间的/dev/fuse接口由virtio-fs设备接口代替。
+
+FUSE请求被置于虚拟队列中由主机处理。主机填充缓冲区中的响应部分,而客机处理请求的完成部分。
+
+将/dev/fuse映射到虚拟队列需要解决/dev/fuse和虚拟队列之间语义上的差异。每次读取\
+/dev/fuse设备时,FUSE客户端都可以选择要传输的请求,从而可以使某些请求优先于其他\
+请求。虚拟队列有其队列语义,无法更改已入队请求的顺序。在虚拟队列已满的情况下尤
+其关键,因为此时不可能加入高优先级的请求。为了解决此差异,virtio-fs设备采用“hiprio”\
+(高优先级)虚拟队列,专门用于有别于普通请求的高优先级请求。
+
index d316553..76850a5 100644 (file)
@@ -14,6 +14,7 @@
    :maxdepth: 2
 
    process/index
+   filesystems/index
 
 目录和表格
 ----------
index 1f8127b..7bb3086 100644 (file)
@@ -1,4 +1,4 @@
-Chinese translated version of Documentation/io_ordering.txt
+Chinese translated version of Documentation/driver-api/io_ordering.rst
 
 If you have any comment or update to the content, please contact the
 original document maintainer directly.  However, if you have a problem
@@ -8,7 +8,7 @@ or if there is a problem with the translation.
 
 Chinese maintainer: Lin Yongting <linyongting@gmail.com>
 ---------------------------------------------------------------------
-Documentation/io_ordering.txt 的中文翻译
+Documentation/driver-api/io_ordering.rst 的中文翻译
 
 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
index 41aba21..9ff9945 100644 (file)
@@ -5,7 +5,7 @@
 
 .. _cn_development_posting:
 
-发补丁
+发补丁
 ========
 
 迟早,当您的工作准备好提交给社区进行审查,并最终包含到主线内核中时。不出所料,
index 66c7c56..9c39ee5 100644 (file)
@@ -649,7 +649,7 @@ video_device注册
 
 接下来你需要注册视频设备:这会为你创建一个字符设备。
 
-       err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       err = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (err) {
                video_device_release(vdev); /* or kfree(my_vdev); */
                return err;
@@ -660,7 +660,7 @@ video_device注册
 
 注册哪种设备是根据类型(type)参数。存在以下类型:
 
-VFL_TYPE_GRABBER: 用于视频输入/输出设备的 videoX
+VFL_TYPE_VIDEO: 用于视频输入/输出设备的 videoX
 VFL_TYPE_VBI: 用于垂直消隐数据的 vbiX (例如,隐藏式字幕,图文电视)
 VFL_TYPE_RADIO: 用于广播调谐器的 radioX
 
index 36b6ebd..b656c9b 100644 (file)
@@ -22,6 +22,7 @@ USB support
     misc_usbsevseg
     mtouchusb
     ohci
+    raw-gadget
     usbip_protocol
     usbmon
     usb-serial
diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst
new file mode 100644 (file)
index 0000000..9e78cb8
--- /dev/null
@@ -0,0 +1,61 @@
+==============
+USB Raw Gadget
+==============
+
+USB Raw Gadget is a kernel module that provides a userspace interface for
+the USB Gadget subsystem. Essentially it allows to emulate USB devices
+from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is
+currently a strictly debugging feature and shouldn't be used in
+production, use GadgetFS instead.
+
+Comparison to GadgetFS
+~~~~~~~~~~~~~~~~~~~~~~
+
+Raw Gadget is similar to GadgetFS, but provides a more low-level and
+direct access to the USB Gadget layer for the userspace. The key
+differences are:
+
+1. Every USB request is passed to the userspace to get a response, while
+   GadgetFS responds to some USB requests internally based on the provided
+   descriptors. However note, that the UDC driver might respond to some
+   requests on its own and never forward them to the Gadget layer.
+
+2. GadgetFS performs some sanity checks on the provided USB descriptors,
+   while Raw Gadget allows you to provide arbitrary data as responses to
+   USB requests.
+
+3. Raw Gadget provides a way to select a UDC device/driver to bind to,
+   while GadgetFS currently binds to the first available UDC.
+
+4. Raw Gadget uses predictable endpoint names (handles) across different
+   UDCs (as long as UDCs have enough endpoints of each required transfer
+   type).
+
+5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
+
+Userspace interface
+~~~~~~~~~~~~~~~~~~~
+
+To create a Raw Gadget instance open /dev/raw-gadget. Multiple raw-gadget
+instances (bound to different UDCs) can be used at the same time. The
+interaction with the opened file happens through the ioctl() calls, see
+comments in include/uapi/linux/usb/raw_gadget.h for details.
+
+The typical usage of Raw Gadget looks like:
+
+1. Open Raw Gadget instance via /dev/raw-gadget.
+2. Initialize the instance via USB_RAW_IOCTL_INIT.
+3. Launch the instance with USB_RAW_IOCTL_RUN.
+4. In a loop issue USB_RAW_IOCTL_EVENT_FETCH calls to receive events from
+   Raw Gadget and react to those depending on what kind of USB device
+   needs to be emulated.
+
+Potential future improvements
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Implement ioctl's for setting/clearing halt status on endpoints.
+
+- Reporting more events (suspend, resume, etc.) through
+  USB_RAW_IOCTL_EVENT_FETCH.
+
+- Support O_NONBLOCK I/O.
index 2e91370..f759eda 100644 (file)
@@ -266,7 +266,6 @@ Code  Seq#    Include File                                           Comments
 'o'   01-A1  `linux/dvb/*.h`                                         DVB
 'p'   00-0F  linux/phantom.h                                         conflict! (OpenHaptics needs this)
 'p'   00-1F  linux/rtc.h                                             conflict!
-'p'   00-3F  linux/mc146818rtc.h                                     conflict!
 'p'   40-7F  linux/nvram.h
 'p'   80-9F  linux/ppdev.h                                           user-space parport
                                                                      <mailto:tim@cyberelk.net>
index d18c97b..c3129b9 100644 (file)
@@ -53,6 +53,29 @@ key management interface to perform common hypervisor activities such as
 encrypting bootstrap code, snapshot, migrating and debugging the guest. For more
 information, see the SEV Key Management spec [api-spec]_
 
+The main ioctl to access SEV is KVM_MEM_ENCRYPT_OP.  If the argument
+to KVM_MEM_ENCRYPT_OP is NULL, the ioctl returns 0 if SEV is enabled
+and ``ENOTTY` if it is disabled (on some older versions of Linux,
+the ioctl runs normally even with a NULL argument, and therefore will
+likely return ``EFAULT``).  If non-NULL, the argument to KVM_MEM_ENCRYPT_OP
+must be a struct kvm_sev_cmd::
+
+       struct kvm_sev_cmd {
+               __u32 id;
+               __u64 data;
+               __u32 error;
+               __u32 sev_fd;
+       };
+
+
+The ``id`` field contains the subcommand, and the ``data`` field points to
+another struct containing arguments specific to command.  The ``sev_fd``
+should point to a file descriptor that is opened on the ``/dev/sev``
+device, if needed (see individual commands).
+
+On output, ``error`` is zero on success, or an error code.  Error codes
+are defined in ``<linux/psp-dev.h>`.
+
 KVM implements the following commands to support common lifecycle events of SEV
 guests, such as launching, running, snapshotting, migrating and decommissioning.
 
@@ -90,6 +113,8 @@ Returns: 0 on success, -negative on error
 
 On success, the 'handle' field contains a new handle and on error, a negative value.
 
+KVM_SEV_LAUNCH_START requires the ``sev_fd`` field to be valid.
+
 For more details, see SEV spec Section 6.2.
 
 3. KVM_SEV_LAUNCH_UPDATE_DATA
index 97a72a5..ebd383f 100644 (file)
@@ -4611,35 +4611,38 @@ unpins the VPA pages and releases all the device pages that are used to
 track the secure pages by hypervisor.
 
 4.122 KVM_S390_NORMAL_RESET
+---------------------------
 
-Capability: KVM_CAP_S390_VCPU_RESETS
-Architectures: s390
-Type: vcpu ioctl
-Parameters: none
-Returns: 0
+:Capability: KVM_CAP_S390_VCPU_RESETS
+:Architectures: s390
+:Type: vcpu ioctl
+:Parameters: none
+:Returns: 0
 
 This ioctl resets VCPU registers and control structures according to
 the cpu reset definition in the POP (Principles Of Operation).
 
 4.123 KVM_S390_INITIAL_RESET
+----------------------------
 
-Capability: none
-Architectures: s390
-Type: vcpu ioctl
-Parameters: none
-Returns: 0
+:Capability: none
+:Architectures: s390
+:Type: vcpu ioctl
+:Parameters: none
+:Returns: 0
 
 This ioctl resets VCPU registers and control structures according to
 the initial cpu reset definition in the POP. However, the cpu is not
 put into ESA mode. This reset is a superset of the normal reset.
 
 4.124 KVM_S390_CLEAR_RESET
+--------------------------
 
-Capability: KVM_CAP_S390_VCPU_RESETS
-Architectures: s390
-Type: vcpu ioctl
-Parameters: none
-Returns: 0
+:Capability: KVM_CAP_S390_VCPU_RESETS
+:Architectures: s390
+:Type: vcpu ioctl
+:Parameters: none
+:Returns: 0
 
 This ioctl resets VCPU registers and control structures according to
 the clear cpu reset definition in the POP. However, the cpu is not put
index c9c2015..fa7ddc0 100644 (file)
@@ -490,15 +490,11 @@ Protocol: 2.00+
                kernel) to not write early messages that require
                accessing the display hardware directly.
 
-  Bit 6 (write): KEEP_SEGMENTS
+  Bit 6 (obsolete): KEEP_SEGMENTS
 
        Protocol: 2.07+
 
-       - If 0, reload the segment registers in the 32bit entry point.
-       - If 1, do not reload the segment registers in the 32bit entry point.
-
-               Assume that %cs %ds %ss %es are all set to flat segments with
-               a base of 0 (or the equivalent for their environment).
+        - This flag is obsolete.
 
   Bit 7 (write): CAN_USE_HEAP
 
index ed6d4b0..81a3938 100644 (file)
@@ -257,6 +257,9 @@ the fault, in our case the actual value is c0199ff5:
 the original assembly code: > 3:      movl $-14,%eax
 and linked in vmlinux     : > c0199ff5 <.fixup+10b5> movl   $0xfffffff2,%eax
 
+If the fixup was able to handle the exception, control flow may be returned
+to the instruction after the one that triggered the fault, ie. local label 2b.
+
 The assembly code::
 
  > .section __ex_table,"a"
@@ -344,3 +347,14 @@ pointer which points to one of:
      it as special.
 
 More functions can easily be added.
+
+CONFIG_BUILDTIME_TABLE_SORT allows the __ex_table section to be sorted post
+link of the kernel image, via a host utility scripts/sorttable. It will set the
+symbol main_extable_sort_needed to 0, avoiding sorting the __ex_table section
+at boot time. With the exception table sorted, at runtime when an exception
+occurs we can quickly lookup the __ex_table entry via binary search.
+
+This is not just a boot time optimization, some architectures require this
+table to be sorted in order to handle exceptions relatively early in the boot
+process. For example, i386 makes use of this form of exception handling before
+paging support is even enabled!
index a8de2fb..265d9e9 100644 (file)
@@ -19,7 +19,6 @@ x86-specific Documentation
    tlb
    mtrr
    pat
-   intel_mpx
    intel-iommu
    intel_txt
    amd-memory-encryption
index 9dae6b4..099f13d 100644 (file)
@@ -95,9 +95,10 @@ and any RMRR's processed::
 When DMAR is enabled for use, you will notice..
 
 PCI-DMA: Using DMAR IOMMU
+-------------------------
 
 Fault reporting
----------------
+^^^^^^^^^^^^^^^
 
 ::
 
index fcd79fc..fe43e1c 100644 (file)
@@ -214,7 +214,7 @@ Q:  http://patchwork.kernel.org/project/v9fs-devel/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git
 T:     git git://github.com/martinetd/linux.git
 S:     Maintained
-F:     Documentation/filesystems/9p.txt
+F:     Documentation/filesystems/9p.rst
 F:     fs/9p/
 F:     net/9p/
 F:     include/net/9p/
@@ -584,7 +584,7 @@ AFFS FILE SYSTEM
 M:     David Sterba <dsterba@suse.com>
 L:     linux-fsdevel@vger.kernel.org
 S:     Odd Fixes
-F:     Documentation/filesystems/affs.txt
+F:     Documentation/filesystems/affs.rst
 F:     fs/affs/
 
 AFS FILESYSTEM
@@ -593,7 +593,7 @@ L:  linux-afs@lists.infradead.org
 S:     Supported
 F:     fs/afs/
 F:     include/trace/events/afs.h
-F:     Documentation/filesystems/afs.txt
+F:     Documentation/filesystems/afs.rst
 W:     https://www.infradead.org/~dhowells/kafs/
 
 AGPGART DRIVER
@@ -693,7 +693,7 @@ ALLWINNER CPUFREQ DRIVER
 M:     Yangtao Li <tiny.windzz@gmail.com>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/opp/sun50i-nvmem-cpufreq.txt
+F:     Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml
 F:     drivers/cpufreq/sun50i-cpufreq-nvmem.c
 
 ALLWINNER CRYPTO DRIVERS
@@ -931,6 +931,14 @@ S: Supported
 F:     drivers/iio/adc/ad7124.c
 F:     Documentation/devicetree/bindings/iio/adc/adi,ad7124.yaml
 
+ANALOG DEVICES INC AD7192 DRIVER
+M:     Alexandru Tachici <alexandru.tachici@analog.com>
+L:     linux-iio@vger.kernel.org
+W:     http://ez.analog.com/community/linux-device-drivers
+S:     Supported
+F:     drivers/iio/adc/ad7192.c
+F:     Documentation/devicetree/bindings/iio/adc/adi,ad7192.yaml
+
 ANALOG DEVICES INC AD7292 DRIVER
 M:     Marcelo Schmitt <marcelo.schmitt1@gmail.com>
 L:     linux-iio@vger.kernel.org
@@ -1081,6 +1089,15 @@ F:       drivers/iio/adc/ltc249*
 X:     drivers/iio/*/adjd*
 F:     drivers/staging/iio/*/ad*
 
+ANALOG DEVICES INC HMC425A DRIVER
+M:     Beniamin Bia <beniamin.bia@analog.com>
+M:     Michael Hennerich <michael.hennerich@analog.com>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+W:     http://ez.analog.com/community/linux-device-drivers
+F:     Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml
+F:     drivers/iio/amplifiers/hmc425a.c
+
 ANALOGBITS PLL LIBRARIES
 M:     Paul Walmsley <paul.walmsley@sifive.com>
 S:     Supported
@@ -2276,6 +2293,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git
 S:     Maintained
 F:     Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
 F:     Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.yaml
+F:     Documentation/devicetree/bindings/spi/spi-rockchip.yaml
 F:     arch/arm/boot/dts/rk3*
 F:     arch/arm/boot/dts/rv1108*
 F:     arch/arm/mach-rockchip/
@@ -2957,6 +2975,14 @@ S:       Maintained
 F:     Documentation/devicetree/bindings/sound/axentia,*
 F:     sound/soc/atmel/tse850-pcm5142.c
 
+AXI-FAN-CONTROL HARDWARE MONITOR DRIVER
+M:     Nuno Sá <nuno.sa@analog.com>
+W:     http://ez.analog.com/community/linux-device-drivers
+L:     linux-hwmon@vger.kernel.org
+S:     Supported
+F:     drivers/hwmon/axi-fan-control.c
+F:     Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml
+
 AXXIA I2C CONTROLLER
 M:     Krzysztof Adamski <krzysztof.adamski@nokia.com>
 L:     linux-i2c@vger.kernel.org
@@ -3063,7 +3089,7 @@ M:        Luis de Bethencourt <luisbg@kernel.org>
 M:     Salah Triki <salah.triki@gmail.com>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/luisbg/linux-befs.git
-F:     Documentation/filesystems/befs.txt
+F:     Documentation/filesystems/befs.rst
 F:     fs/befs/
 
 BFQ I/O SCHEDULER
@@ -3077,7 +3103,7 @@ F:        Documentation/block/bfq-iosched.rst
 BFS FILE SYSTEM
 M:     "Tigran A. Aivazian" <aivazian.tigran@gmail.com>
 S:     Maintained
-F:     Documentation/filesystems/bfs.txt
+F:     Documentation/filesystems/bfs.rst
 F:     fs/bfs/
 F:     include/uapi/linux/bfs_fs.h
 
@@ -3610,7 +3636,7 @@ W:        http://btrfs.wiki.kernel.org/
 Q:     http://patchwork.kernel.org/project/linux-btrfs/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git
 S:     Maintained
-F:     Documentation/filesystems/btrfs.txt
+F:     Documentation/filesystems/btrfs.rst
 F:     fs/btrfs/
 F:     include/linux/btrfs*
 F:     include/uapi/linux/btrfs*
@@ -3907,7 +3933,7 @@ W:        http://ceph.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 T:     git git://github.com/ceph/ceph-client.git
 S:     Supported
-F:     Documentation/filesystems/ceph.txt
+F:     Documentation/filesystems/ceph.rst
 F:     fs/ceph/
 
 CERTIFICATE HANDLING
@@ -3920,11 +3946,6 @@ F:       certs/
 F:     scripts/sign-file.c
 F:     scripts/extract-cert.c
 
-CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM
-L:     devel@driverdev.osuosl.org
-S:     Obsolete
-F:     drivers/staging/wusbcore/
-
 CFAG12864B LCD DRIVER
 M:     Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
 S:     Maintained
@@ -4017,7 +4038,7 @@ M:        Cheng-Yi Chiang <cychiang@chromium.org>
 S:     Maintained
 R:     Enric Balletbo i Serra <enric.balletbo@collabora.com>
 R:     Guenter Roeck <groeck@chromium.org>
-F:     Documentation/devicetree/bindings/sound/google,cros-ec-codec.txt
+F:     Documentation/devicetree/bindings/sound/google,cros-ec-codec.yaml
 F:     sound/soc/codecs/cros_ec_codec.*
 
 CIRRUS LOGIC AUDIO CODEC DRIVERS
@@ -4073,7 +4094,6 @@ F:        drivers/scsi/snic/
 CISCO VIC ETHERNET NIC DRIVER
 M:     Christian Benvenuti <benve@cisco.com>
 M:     Govindarajulu Varadarajan <_govind@gmx.com>
-M:     Parvi Kaustubhi <pkaustub@cisco.com>
 S:     Supported
 F:     drivers/net/ethernet/cisco/enic/
 
@@ -4424,7 +4444,7 @@ F:        include/linux/cpuidle.h
 CRAMFS FILESYSTEM
 M:     Nicolas Pitre <nico@fluxnic.net>
 S:     Maintained
-F:     Documentation/filesystems/cramfs.txt
+F:     Documentation/filesystems/cramfs.rst
 F:     fs/cramfs/
 
 CREATIVE SB0540
@@ -4475,7 +4495,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/platform/sunxi/sun6i-csi/
-F:     Documentation/devicetree/bindings/media/sun6i-csi.txt
+F:     Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
 
 CW1200 WLAN driver
 M:     Solomon Peachy <pizza@shaftnet.org>
@@ -4572,7 +4592,7 @@ F:        drivers/infiniband/hw/cxgb4/
 F:     include/uapi/rdma/cxgb4-abi.h
 
 CXGB4VF ETHERNET DRIVER (CXGB4VF)
-M:     Casey Leedom <leedom@chelsio.com>
+M:     Vishal Kulkarni <vishal@gmail.com>
 L:     netdev@vger.kernel.org
 W:     http://www.chelsio.com
 S:     Supported
@@ -5202,7 +5222,7 @@ M:        Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 R:     "Rafael J. Wysocki" <rafael@kernel.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
 S:     Supported
-F:     Documentation/kobject.txt
+F:     Documentation/core-api/kobject.rst
 F:     drivers/base/
 F:     fs/debugfs/
 F:     fs/sysfs/
@@ -5668,7 +5688,7 @@ L:        dri-devel@lists.freedesktop.org
 T:     git git://anongit.freedesktop.org/drm/drm-misc
 S:     Maintained
 F:     drivers/gpu/drm/stm
-F:     Documentation/devicetree/bindings/display/st,stm32-ltdc.txt
+F:     Documentation/devicetree/bindings/display/st,stm32-ltdc.yaml
 
 DRM DRIVERS FOR TI LCDC
 M:     Jyri Sarha <jsarha@ti.com>
@@ -5939,7 +5959,7 @@ W:        http://ecryptfs.org
 W:     https://launchpad.net/ecryptfs
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tyhicks/ecryptfs.git
 S:     Odd Fixes
-F:     Documentation/filesystems/ecryptfs.txt
+F:     Documentation/filesystems/ecryptfs.rst
 F:     fs/ecryptfs/
 
 EDAC-AMD64
@@ -5999,6 +6019,12 @@ F:       Documentation/driver-api/edac.rst
 F:     drivers/edac/
 F:     include/linux/edac.h
 
+EDAC-DMC520
+M:     Lei Wang <lewan@microsoft.com>
+L:     linux-edac@vger.kernel.org
+S:     Supported
+F:     drivers/edac/dmc520_edac.c
+
 EDAC-E752X
 M:     Mark Gross <mark.gross@intel.com>
 L:     linux-edac@vger.kernel.org
@@ -6198,7 +6224,6 @@ S:        Supported
 F:     drivers/scsi/be2iscsi/
 
 Emulex 10Gbps NIC BE2, BE3-R, Lancer, Skyhawk-R DRIVER (be2net)
-M:     Sathya Perla <sathya.perla@broadcom.com>
 M:     Ajit Khaparde <ajit.khaparde@broadcom.com>
 M:     Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
 M:     Somnath Kotur <somnath.kotur@broadcom.com>
@@ -6250,12 +6275,12 @@ F:      drivers/video/fbdev/s1d13xxxfb.c
 F:     include/video/s1d13xxxfb.h
 
 EROFS FILE SYSTEM
-M:     Gao Xiang <gaoxiang25@huawei.com>
+M:     Gao Xiang <xiang@kernel.org>
 M:     Chao Yu <yuchao0@huawei.com>
 L:     linux-erofs@lists.ozlabs.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
-F:     Documentation/filesystems/erofs.txt
+F:     Documentation/filesystems/erofs.rst
 F:     fs/erofs/
 F:     include/trace/events/erofs.h
 
@@ -6306,17 +6331,11 @@ F:      include/trace/events/mdio.h
 F:     include/uapi/linux/mdio.h
 F:     include/uapi/linux/mii.h
 
-EXFAT FILE SYSTEM
-M:     Valdis Kletnieks <valdis.kletnieks@vt.edu>
-L:     linux-fsdevel@vger.kernel.org
-S:     Maintained
-F:     drivers/staging/exfat/
-
 EXT2 FILE SYSTEM
 M:     Jan Kara <jack@suse.com>
 L:     linux-ext4@vger.kernel.org
 S:     Maintained
-F:     Documentation/filesystems/ext2.txt
+F:     Documentation/filesystems/ext2.rst
 F:     fs/ext2/
 F:     include/linux/ext2*
 
@@ -6344,7 +6363,6 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git
 S:     Maintained
 F:     Documentation/admin-guide/efi-stub.rst
 F:     arch/*/kernel/efi.c
-F:     arch/x86/boot/compressed/eboot.[ch]
 F:     arch/*/include/asm/efi.h
 F:     arch/x86/platform/efi/
 F:     drivers/firmware/efi/
@@ -6390,7 +6408,7 @@ L:        linux-f2fs-devel@lists.sourceforge.net
 W:     https://f2fs.wiki.kernel.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
 S:     Maintained
-F:     Documentation/filesystems/f2fs.txt
+F:     Documentation/filesystems/f2fs.rst
 F:     Documentation/ABI/testing/sysfs-fs-f2fs
 F:     fs/f2fs/
 F:     include/linux/f2fs_fs.h
@@ -6860,6 +6878,13 @@ S:       Maintained
 F:     drivers/i2c/busses/i2c-fsi.c
 F:     Documentation/devicetree/bindings/i2c/i2c-fsi.txt
 
+FSI-ATTACHED SPI DRIVER
+M:     Eddie James <eajames@linux.ibm.com>
+L:     linux-spi@vger.kernel.org
+S:     Maintained
+F:     drivers/spi/spi-fsi.c
+F:     Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml
+
 FSNOTIFY: FILESYSTEM NOTIFICATION INFRASTRUCTURE
 M:     Jan Kara <jack@suse.cz>
 R:     Amir Goldstein <amir73il@gmail.com>
@@ -6935,7 +6960,7 @@ S:        Maintained
 F:     scripts/gcc-plugins/
 F:     scripts/gcc-plugin.sh
 F:     scripts/Makefile.gcc-plugins
-F:     Documentation/core-api/gcc-plugins.rst
+F:     Documentation/kbuild/gcc-plugins.rst
 
 GASKET DRIVER FRAMEWORK
 M:     Rob Springer <rspringer@google.com>
@@ -7432,13 +7457,13 @@ F:      drivers/infiniband/hw/hfi1
 HFS FILESYSTEM
 L:     linux-fsdevel@vger.kernel.org
 S:     Orphan
-F:     Documentation/filesystems/hfs.txt
+F:     Documentation/filesystems/hfs.rst
 F:     fs/hfs/
 
 HFSPLUS FILESYSTEM
 L:     linux-fsdevel@vger.kernel.org
 S:     Orphan
-F:     Documentation/filesystems/hfsplus.txt
+F:     Documentation/filesystems/hfsplus.rst
 F:     fs/hfsplus/
 
 HGA FRAMEBUFFER DRIVER
@@ -7518,6 +7543,12 @@ F:       include/uapi/linux/if_hippi.h
 F:     net/802/hippi.c
 F:     drivers/net/hippi/
 
+HISILICON DMA DRIVER
+M:     Zhou Wang <wangzhou1@hisilicon.com>
+L:     dmaengine@vger.kernel.org
+S:     Maintained
+F:     drivers/dma/hisi_dma.c
+
 HISILICON SECURITY ENGINE V2 DRIVER (SEC2)
 M:     Zaibo Xu <xuzaibo@huawei.com>
 L:     linux-crypto@vger.kernel.org
@@ -7575,7 +7606,8 @@ F:        Documentation/admin-guide/perf/hisi-pmu.rst
 
 HISILICON ROCE DRIVER
 M:     Lijun Ou <oulijun@huawei.com>
-M:     Wei Hu(Xavier) <xavier.huwei@huawei.com>
+M:     Wei Hu(Xavier) <huwei87@hisilicon.com>
+M:     Weihang Li <liweihang@huawei.com>
 L:     linux-rdma@vger.kernel.org
 S:     Maintained
 F:     drivers/infiniband/hw/hns/
@@ -7738,7 +7770,7 @@ Hyper-V CORE AND DRIVERS
 M:     "K. Y. Srinivasan" <kys@microsoft.com>
 M:     Haiyang Zhang <haiyangz@microsoft.com>
 M:     Stephen Hemminger <sthemmin@microsoft.com>
-M:     Sasha Levin <sashal@kernel.org>
+M:     Wei Liu <wei.liu@kernel.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git
 L:     linux-hyperv@vger.kernel.org
 S:     Supported
@@ -7946,6 +7978,7 @@ L:        linux-ia64@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
 S:     Maintained
 F:     arch/ia64/
+F:     Documentation/ia64/
 
 IBM Power 842 compression accelerator
 M:     Haren Myneni <haren@us.ibm.com>
@@ -8309,7 +8342,7 @@ M:        Jan Kara <jack@suse.cz>
 R:     Amir Goldstein <amir73il@gmail.com>
 L:     linux-fsdevel@vger.kernel.org
 S:     Maintained
-F:     Documentation/filesystems/inotify.txt
+F:     Documentation/filesystems/inotify.rst
 F:     fs/notify/inotify/
 F:     include/linux/inotify.h
 F:     include/uapi/linux/inotify.h
@@ -8478,7 +8511,6 @@ L:        dmaengine@vger.kernel.org
 S:     Supported
 F:     drivers/dma/idxd/*
 F:     include/uapi/linux/idxd.h
-F:     include/linux/idxd.h
 
 INTEL IDLE DRIVER
 M:     Jacob Pan <jacob.jun.pan@linux.intel.com>
@@ -8570,15 +8602,15 @@ M:      Ashutosh Dixit <ashutosh.dixit@intel.com>
 S:     Supported
 W:     https://github.com/sudeepdutt/mic
 W:     http://software.intel.com/en-us/mic-developer
+F:     Documentation/misc-devices/mic/
+F:     drivers/dma/mic_x100_dma.c
+F:     drivers/dma/mic_x100_dma.h
+F:     drivers/misc/mic/
 F:     include/linux/mic_bus.h
 F:     include/linux/scif.h
 F:     include/uapi/linux/mic_common.h
 F:     include/uapi/linux/mic_ioctl.h
 F:     include/uapi/linux/scif_ioctl.h
-F:     drivers/misc/mic/
-F:     drivers/dma/mic_x100_dma.c
-F:     drivers/dma/mic_x100_dma.h
-F:     Documentation/mic/
 
 INTEL PMC CORE DRIVER
 M:     Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com>
@@ -8685,7 +8717,7 @@ M:        Emmanuel Grumbach <emmanuel.grumbach@intel.com>
 M:     Luca Coelho <luciano.coelho@intel.com>
 M:     Intel Linux Wireless <linuxwifi@intel.com>
 L:     linux-wireless@vger.kernel.org
-W:     http://intellinuxwireless.org
+W:     https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
 S:     Supported
 F:     drivers/net/wireless/intel/iwlwifi/
@@ -9276,8 +9308,8 @@ L:        keyrings@vger.kernel.org
 S:     Supported
 F:     Documentation/security/keys/trusted-encrypted.rst
 F:     include/keys/trusted-type.h
-F:     security/keys/trusted.c
-F:     include/keys/trusted.h
+F:     include/keys/trusted_tpm.h
+F:     security/keys/trusted-keys/
 
 KEYS/KEYRINGS
 M:     David Howells <dhowells@redhat.com>
@@ -10164,7 +10196,7 @@ MAXBOTIX ULTRASONIC RANGER IIO DRIVER
 M:     Andreas Klinger <ak@it-klinger.de>
 L:     linux-iio@vger.kernel.org
 S:     Maintained
-F:     Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt
+F:     Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.yaml
 F:     drivers/iio/proximity/mb1232.c
 
 MAXIM MAX77650 PMIC MFD DRIVER
@@ -10467,7 +10499,7 @@ M:      Hugues Fruchet <hugues.fruchet@st.com>
 L:     linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Supported
-F:     Documentation/devicetree/bindings/media/st,stm32-dcmi.txt
+F:     Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
 F:     drivers/media/platform/stm32/stm32-dcmi.c
 
 MEDIA DRIVERS FOR NVIDIA TEGRA - VDE
@@ -10945,6 +10977,7 @@ F:      drivers/media/platform/atmel/atmel-isc.h
 F:     drivers/media/platform/atmel/atmel-isc-base.c
 F:     drivers/media/platform/atmel/atmel-isc-regs.h
 F:     Documentation/devicetree/bindings/media/atmel-isc.txt
+F:     include/linux/atmel-isc-media.h
 
 MICROCHIP ISI DRIVER
 M:     Eugen Hristev <eugen.hristev@microchip.com>
@@ -11115,14 +11148,12 @@ S:    Maintained
 F:     drivers/usb/image/microtek.*
 
 MIPS
-M:     Ralf Baechle <ralf@linux-mips.org>
-M:     Paul Burton <paulburton@kernel.org>
+M:     Thomas Bogendoerfer <tsbogend@alpha.franken.de>
 L:     linux-mips@vger.kernel.org
 W:     http://www.linux-mips.org/
-T:     git git://git.linux-mips.org/pub/scm/ralf/linux.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux.git
-Q:     http://patchwork.linux-mips.org/project/linux-mips/list/
-S:     Supported
+Q:     https://patchwork.kernel.org/project/linux-mips/list/
+S:     Maintained
 F:     Documentation/devicetree/bindings/mips/
 F:     Documentation/mips/
 F:     arch/mips/
@@ -11172,6 +11203,7 @@ S:      Maintained
 F:     arch/mips/loongson64/
 F:     arch/mips/include/asm/mach-loongson64/
 F:     drivers/platform/mips/cpu_hwmon.c
+F:     drivers/irqchip/irq-loongson*
 F:     drivers/*/*loongson3*
 F:     drivers/*/*/*loongson3*
 
@@ -11260,7 +11292,8 @@ F:      drivers/tty/mxser.*
 MONOLITHIC POWER SYSTEM PMIC DRIVER
 M:     Saravanan Sekar <sravanhome@gmail.com>
 S:     Maintained
-F:     Documentation/devicetree/bindings/regulator/mpq7920.yaml
+F:     Documentation/devicetree/bindings/regulator/mps,mp*.yaml
+F:     drivers/regulator/mp5416.c
 F:     drivers/regulator/mpq7920.c
 F:     drivers/regulator/mpq7920.h
 
@@ -11792,7 +11825,7 @@ W:      https://nilfs.sourceforge.io/
 W:     https://nilfs.osdn.jp/
 T:     git git://github.com/konis/nilfs2.git
 S:     Supported
-F:     Documentation/filesystems/nilfs2.txt
+F:     Documentation/filesystems/nilfs2.rst
 F:     fs/nilfs2/
 F:     include/trace/events/nilfs2.h
 F:     include/uapi/linux/nilfs2_api.h
@@ -11901,7 +11934,7 @@ L:      linux-ntfs-dev@lists.sourceforge.net
 W:     http://www.tuxera.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs.git
 S:     Supported
-F:     Documentation/filesystems/ntfs.txt
+F:     Documentation/filesystems/ntfs.rst
 F:     fs/ntfs/
 
 NUBUS SUBSYSTEM
@@ -12247,7 +12280,7 @@ OMFS FILESYSTEM
 M:     Bob Copeland <me@bobcopeland.com>
 L:     linux-karma-devel@lists.sourceforge.net
 S:     Maintained
-F:     Documentation/filesystems/omfs.txt
+F:     Documentation/filesystems/omfs.rst
 F:     fs/omfs/
 
 OMNIKEY CARDMAN 4000 DRIVER
@@ -12496,8 +12529,8 @@ M:      Joseph Qi <joseph.qi@linux.alibaba.com>
 L:     ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
 W:     http://ocfs2.wiki.kernel.org
 S:     Supported
-F:     Documentation/filesystems/ocfs2.txt
-F:     Documentation/filesystems/dlmfs.txt
+F:     Documentation/filesystems/ocfs2.rst
+F:     Documentation/filesystems/dlmfs.rst
 F:     fs/ocfs2/
 
 ORANGEFS FILESYSTEM
@@ -12507,7 +12540,7 @@ L:      devel@lists.orangefs.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git
 S:     Supported
 F:     fs/orangefs/
-F:     Documentation/filesystems/orangefs.txt
+F:     Documentation/filesystems/orangefs.rst
 
 ORINOCO DRIVER
 L:     linux-wireless@vger.kernel.org
@@ -12741,7 +12774,7 @@ M:      Tom Joseph <tjoseph@cadence.com>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/pci/cdns,*.txt
-F:     drivers/pci/controller/pcie-cadence*
+F:     drivers/pci/controller/cadence/
 
 PCI DRIVER FOR FREESCALE LAYERSCAPE
 M:     Minghuan Lian <minghuan.Lian@nxp.com>
@@ -12954,7 +12987,6 @@ M:      Robert Richter <rrichter@marvell.com>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
-F:     Documentation/devicetree/bindings/pci/pci-thunder-*
 F:     drivers/pci/controller/pci-thunder-*
 
 PCIE DRIVER FOR HISILICON
@@ -13350,7 +13382,9 @@ F:      Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt
 
 PNP SUPPORT
 M:     "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
+L:     linux-acpi@vger.kernel.org
 S:     Maintained
+F:     include/linux/pnp.h
 F:     drivers/pnp/
 
 POSIX CLOCKS and TIMERS
@@ -13470,7 +13504,7 @@ S:      Maintained
 F:     fs/proc/
 F:     include/linux/proc_fs.h
 F:     tools/testing/selftests/proc/
-F:     Documentation/filesystems/proc.txt
+F:     Documentation/filesystems/proc.rst
 
 PROC SYSCTL
 M:     Luis Chamberlain <mcgrof@kernel.org>
@@ -13520,6 +13554,12 @@ F:     net/psample
 F:     include/net/psample.h
 F:     include/uapi/linux/psample.h
 
+PRESSURE STALL INFORMATION (PSI)
+M:     Johannes Weiner <hannes@cmpxchg.org>
+S:     Maintained
+F:     kernel/sched/psi.c
+F:     include/linux/psi*
+
 PSTORE FILESYSTEM
 M:     Kees Cook <keescook@chromium.org>
 M:     Anton Vorontsov <anton@enomsg.org>
@@ -13899,6 +13939,7 @@ L:      linux-arm-msm@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Maintained
 F:     drivers/media/platform/qcom/venus/
+F:     Documentation/devicetree/bindings/media/*venus*
 
 QUALCOMM WCN36XX WIRELESS DRIVER
 M:     Kalle Valo <kvalo@codeaurora.org>
@@ -14229,7 +14270,7 @@ F:      include/dt-bindings/reset/
 F:     include/linux/reset.h
 F:     include/linux/reset/
 F:     include/linux/reset-controller.h
-K:      \b(?:devm_|of_)?reset_control(?:ler_[a-z]+|_[a-z_]+)?\b
+K:     \b(?:devm_|of_)?reset_control(?:ler_[a-z]+|_[a-z_]+)?\b
 
 RESTARTABLE SEQUENCES SUPPORT
 M:     Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
@@ -14313,9 +14354,12 @@ F:     Documentation/devicetree/bindings/media/rockchip-rga.txt
 
 HANTRO VPU CODEC DRIVER
 M:     Ezequiel Garcia <ezequiel@collabora.com>
+M:     Philipp Zabel <p.zabel@pengutronix.de>
 L:     linux-media@vger.kernel.org
+L:     linux-rockchip@lists.infradead.org
 S:     Maintained
 F:     drivers/staging/media/hantro/
+F:     Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml
 F:     Documentation/devicetree/bindings/media/rockchip-vpu.txt
 
 ROCKER DRIVER
@@ -14362,6 +14406,14 @@ F:     include/net/rose.h
 F:     include/uapi/linux/rose.h
 F:     net/rose/
 
+ROTATION DRIVER FOR ALLWINNER A83T
+M:     Jernej Skrabec <jernej.skrabec@siol.net>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/platform/sunxi/sun8i-rotate/
+F:     Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
+
 RTL2830 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
@@ -15044,14 +15096,6 @@ M:     Dimitri Sivanich <sivanich@sgi.com>
 S:     Maintained
 F:     drivers/misc/sgi-gru/
 
-SGI SN-IA64 (Altix) SERIAL CONSOLE DRIVER
-M:     Pat Gefre <pfg@sgi.com>
-L:     linux-ia64@vger.kernel.org
-S:     Supported
-F:     Documentation/ia64/serial.rst
-F:     drivers/tty/serial/ioc?_serial.c
-F:     include/linux/ioc?.h
-
 SGI XP/XPC/XPNET DRIVER
 M:     Cliff Whickman <cpw@sgi.com>
 M:     Robin Holt <robinmholt@gmail.com>
@@ -15066,6 +15110,14 @@ W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 F:     net/smc/
 
+SHARP GP2AP002A00F/GP2AP002S00F SENSOR DRIVER
+M:     Linus Walleij <linus.walleij@linaro.org>
+L:     linux-iio@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
+S:     Maintained
+F:     drivers/iio/light/gp2ap002.c
+F:     Documentation/devicetree/bindings/iio/light/sharp,gp2ap002.yaml
+
 SHARP RJ54N1CB0C SENSOR DRIVER
 M:     Jacopo Mondi <jacopo@jmondi.org>
 L:     linux-media@vger.kernel.org
@@ -15332,11 +15384,10 @@ S:    Odd Fixes
 F:     drivers/net/ethernet/smsc/smc91x.*
 
 SMIA AND SMIA++ IMAGE SENSOR DRIVER
-M:     Sakari Ailus <sakari.ailus@iki.fi>
+M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/i2c/smiapp/
-F:     include/media/i2c/smiapp.h
 F:     drivers/media/i2c/smiapp-pll.c
 F:     drivers/media/i2c/smiapp-pll.h
 F:     include/uapi/linux/smiapp.h
@@ -15421,11 +15472,9 @@ F:     drivers/infiniband/sw/siw/
 F:     include/uapi/rdma/siw-abi.h
 
 SOFT-ROCE DRIVER (rxe)
-M:     Moni Shoua <monis@mellanox.com>
+M:     Zhu Yanjun <yanjunz@mellanox.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
-W:     https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home
-Q:     http://patchwork.kernel.org/project/linux-rdma/list/
 F:     drivers/infiniband/sw/rxe/
 F:     include/uapi/rdma/rdma_user_rxe.h
 
@@ -15517,6 +15566,14 @@ S:     Maintained
 F:     drivers/media/i2c/imx214.c
 F:     Documentation/devicetree/bindings/media/i2c/sony,imx214.txt
 
+SONY IMX219 SENSOR DRIVER
+M:     Dave Stevenson <dave.stevenson@raspberrypi.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/i2c/imx219.c
+F:     Documentation/devicetree/bindings/media/i2c/imx219.yaml
+
 SONY IMX258 SENSOR DRIVER
 M:     Sakari Ailus <sakari.ailus@linux.intel.com>
 L:     linux-media@vger.kernel.org
@@ -15739,7 +15796,7 @@ L:      squashfs-devel@lists.sourceforge.net (subscribers-only)
 W:     http://squashfs.org.uk
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-next.git
 S:     Maintained
-F:     Documentation/filesystems/squashfs.txt
+F:     Documentation/filesystems/squashfs.rst
 F:     fs/squashfs/
 
 SRM (Alpha) environment access
@@ -15924,7 +15981,7 @@ F:      drivers/*/stm32-*timer*
 F:     drivers/pwm/pwm-stm32*
 F:     include/linux/*/stm32-*tim*
 F:     Documentation/ABI/testing/*timer-stm32
-F:     Documentation/devicetree/bindings/*/stm32-*timer*
+F:     Documentation/devicetree/bindings/*/*stm32-*timer*
 F:     Documentation/devicetree/bindings/pwm/pwm-stm32*
 
 STMMAC ETHERNET DRIVER
@@ -16083,6 +16140,8 @@ SYNOPSYS DESIGNWARE 8250 UART DRIVER
 R:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 S:     Maintained
 F:     drivers/tty/serial/8250/8250_dw.c
+F:     drivers/tty/serial/8250/8250_dwlib.*
+F:     drivers/tty/serial/8250/8250_lpss.c
 
 SYNOPSYS DESIGNWARE APB GPIO DRIVER
 M:     Hoan Tran <hoan@os.amperecomputing.com>
@@ -16182,7 +16241,7 @@ F:      drivers/platform/x86/system76_acpi.c
 SYSV FILESYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
 S:     Maintained
-F:     Documentation/filesystems/sysv-fs.txt
+F:     Documentation/filesystems/sysv-fs.rst
 F:     fs/sysv/
 F:     include/linux/sysv_fs.h
 
@@ -16748,12 +16807,12 @@ F:    sound/soc/codecs/twl4030*
 TI VPE/CAL DRIVERS
 M:     Benoit Parrot <bparrot@ti.com>
 L:     linux-media@vger.kernel.org
+S:     Maintained
 W:     http://linuxtv.org/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
-S:     Maintained
-F:     drivers/media/platform/ti-vpe/
+F:     Documentation/devicetree/bindings/media/ti,cal.yaml
 F:     Documentation/devicetree/bindings/media/ti,vpe.yaml
-       Documentation/devicetree/bindings/media/ti,cal.yaml
+F:     drivers/media/platform/ti-vpe/
 
 TI WILINK WIRELESS DRIVERS
 L:     linux-wireless@vger.kernel.org
@@ -17047,7 +17106,7 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git next
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rw/ubifs.git fixes
 W:     http://www.linux-mtd.infradead.org/doc/ubifs.html
 S:     Supported
-F:     Documentation/filesystems/ubifs.txt
+F:     Documentation/filesystems/ubifs.rst
 F:     fs/ubifs/
 
 UCLINUX (M68KNOMMU AND COLDFIRE)
@@ -17066,7 +17125,7 @@ F:      arch/m68k/include/asm/*_no.*
 UDF FILESYSTEM
 M:     Jan Kara <jack@suse.com>
 S:     Maintained
-F:     Documentation/filesystems/udf.txt
+F:     Documentation/filesystems/udf.rst
 F:     fs/udf/
 
 UDRAW TABLET
@@ -17095,11 +17154,6 @@ S:     Maintained
 F:     drivers/usb/common/ulpi.c
 F:     include/linux/ulpi/
 
-ULTRA-WIDEBAND (UWB) SUBSYSTEM
-L:     devel@driverdev.osuosl.org
-S:     Obsolete
-F:     drivers/staging/uwb/
-
 UNICODE SUBSYSTEM
 M:     Gabriel Krisman Bertazi <krisman@collabora.com>
 L:     linux-fsdevel@vger.kernel.org
@@ -17183,6 +17237,12 @@ S:     Maintained
 F:     Documentation/usb/acm.rst
 F:     drivers/usb/class/cdc-acm.*
 
+USB APPLE MFI FASTCHARGE DRIVER
+M:     Bastien Nocera <hadess@hadess.net>
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+F:     drivers/usb/misc/apple-mfi-fastcharge.c
+
 USB AR5523 WIRELESS DRIVER
 M:     Pontus Fuchs <pontus.fuchs@gmail.com>
 L:     linux-wireless@vger.kernel.org
@@ -17445,7 +17505,7 @@ L:      linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 W:     https://linuxtv.org
 S:     Odd Fixes
-F:     drivers/media/usb/usbvision/
+F:     drivers/staging/media/usbvision/
 
 USB WEBCAM GADGET
 M:     Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -18505,7 +18565,7 @@ L:      linux-fsdevel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs.git
 S:     Maintained
 F:     fs/zonefs/
-F:     Documentation/filesystems/zonefs.txt
+F:     Documentation/filesystems/zonefs.rst
 
 ZPOOL COMPRESSED PAGE STORAGE API
 M:     Dan Streetman <ddstreet@ieee.org>
index 0914049..4d0711f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION =
 NAME = Kleptomaniac Octopus
 
 # *DOCUMENTATION*
@@ -68,6 +68,7 @@ unexport GREP_OPTIONS
 #
 # If KBUILD_VERBOSE equals 0 then the above command will be hidden.
 # If KBUILD_VERBOSE equals 1 then the above command is displayed.
+# If KBUILD_VERBOSE equals 2 then give the reason why each target is rebuilt.
 #
 # To put more focus on warnings, be less verbose as default
 # Use 'make V=1' to see the full commands
@@ -1238,7 +1239,7 @@ ifneq ($(dtstree),)
 %.dtb: include/config/kernel.release scripts_dtc
        $(Q)$(MAKE) $(build)=$(dtstree) $(dtstree)/$@
 
-PHONY += dtbs dtbs_install dt_binding_check
+PHONY += dtbs dtbs_install dtbs_check
 dtbs dtbs_check: include/config/kernel.release scripts_dtc
        $(Q)$(MAKE) $(build)=$(dtstree)
 
@@ -1258,6 +1259,7 @@ PHONY += scripts_dtc
 scripts_dtc: scripts_basic
        $(Q)$(MAKE) $(build)=scripts/dtc
 
+PHONY += dt_binding_check
 dt_binding_check: scripts_dtc
        $(Q)$(MAKE) $(build)=Documentation/devicetree/bindings
 
@@ -1802,7 +1804,7 @@ existing-targets := $(wildcard $(sort $(targets)))
 
 -include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd)
 
-endif # config-targets
+endif # config-build
 endif # mixed-build
 endif # need-sub-make
 
index 98de654..516f2b0 100644 (file)
@@ -540,11 +540,17 @@ config HAVE_CONTEXT_TRACKING
        help
          Provide kernel/user boundaries probes necessary for subsystems
          that need it, such as userspace RCU extended quiescent state.
-         Syscalls need to be wrapped inside user_exit()-user_enter() through
-         the slow path using TIF_NOHZ flag. Exceptions handlers must be
-         wrapped as well. Irqs are already protected inside
-         rcu_irq_enter/rcu_irq_exit() but preemption or signal handling on
-         irq exit still need to be protected.
+         Syscalls need to be wrapped inside user_exit()-user_enter(), either
+         optimized behind static key or through the slow path using TIF_NOHZ
+         flag. Exceptions handlers must be wrapped as well. Irqs are already
+         protected inside rcu_irq_enter/rcu_irq_exit() but preemption or signal
+         handling on irq exit still need to be protected.
+
+config HAVE_TIF_NOHZ
+       bool
+       help
+         Arch relies on TIF_NOHZ and syscall slow path to implement context
+         tracking calls to user_enter()/user_exit().
 
 config HAVE_VIRT_CPU_ACCOUNTING
        bool
@@ -738,8 +744,9 @@ config HAVE_STACK_VALIDATION
 config HAVE_RELIABLE_STACKTRACE
        bool
        help
-         Architecture has a save_stack_trace_tsk_reliable() function which
-         only returns a stack trace if it can guarantee the trace is reliable.
+         Architecture has either save_stack_trace_tsk_reliable() or
+         arch_stack_walk_reliable() function which only returns a stack trace
+         if it can guarantee the trace is reliable.
 
 config HAVE_ARCH_HASH
        bool
index bfd3c01..da67afd 100644 (file)
@@ -31,7 +31,8 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
 {
        int oldval = 0, ret;
 
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -53,8 +54,6 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index da3e10d..d17e44c 100644 (file)
@@ -213,32 +213,13 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
  * The special RTC interrupt type.  The interrupt itself was
  * processed by PALcode, and comes in via entInt vector 1.
  */
-
-struct irqaction timer_irqaction = {
-       .handler        = rtc_timer_interrupt,
-       .name           = "timer",
-};
-
 void __init
-init_rtc_irq(void)
+init_rtc_irq(irq_handler_t handler)
 {
        irq_set_chip_and_handler_name(RTC_IRQ, &dummy_irq_chip,
                                      handle_percpu_irq, "RTC");
-       setup_irq(RTC_IRQ, &timer_irqaction);
+       if (!handler)
+               handler = rtc_timer_interrupt;
+       if (request_irq(RTC_IRQ, handler, 0, "timer", NULL))
+               pr_err("Failed to register timer interrupt\n");
 }
-
-/* Dummy irqactions.  */
-struct irqaction isa_cascade_irqaction = {
-       .handler        = no_action,
-       .name           = "isa-cascade"
-};
-
-struct irqaction timer_cascade_irqaction = {
-       .handler        = no_action,
-       .name           = "timer-cascade"
-};
-
-struct irqaction halt_switch_irqaction = {
-       .handler        = no_action,
-       .name           = "halt-switch"
-};
index 5d54c07..1dcf0d9 100644 (file)
@@ -82,11 +82,6 @@ struct irq_chip i8259a_irq_type = {
 void __init
 init_i8259a_irqs(void)
 {
-       static struct irqaction cascade = {
-               .handler        = no_action,
-               .name           = "cascade",
-       };
-
        long i;
 
        outb(0xff, 0x21);       /* mask all of 8259A-1 */
@@ -96,7 +91,8 @@ init_i8259a_irqs(void)
                irq_set_chip_and_handler(i, &i8259a_irq_type, handle_level_irq);
        }
 
-       setup_irq(2, &cascade);
+       if (request_irq(2, no_action, 0, "cascade", NULL))
+               pr_err("Failed to request irq 2 (cascade)\n");
 }
 
 
index 16f2b02..fbf2189 100644 (file)
@@ -21,14 +21,9 @@ extern void isa_no_iack_sc_device_interrupt(unsigned long);
 extern void srm_device_interrupt(unsigned long);
 extern void pyxis_device_interrupt(unsigned long);
 
-extern struct irqaction timer_irqaction;
-extern struct irqaction isa_cascade_irqaction;
-extern struct irqaction timer_cascade_irqaction;
-extern struct irqaction halt_switch_irqaction;
-
 extern void init_srm_irqs(long, unsigned long);
 extern void init_pyxis_irqs(unsigned long);
-extern void init_rtc_irq(void);
+extern void init_rtc_irq(irq_handler_t  handler);
 
 extern void common_init_isa_dma(void);
 
index a968b10..27070b5 100644 (file)
@@ -107,5 +107,6 @@ init_pyxis_irqs(unsigned long ignore_mask)
                irq_set_status_flags(i, IRQ_LEVEL);
        }
 
-       setup_irq(16+7, &isa_cascade_irqaction);
+       if (request_irq(16 + 7, no_action, 0, "isa-cascade", NULL))
+               pr_err("Failed to register isa-cascade interrupt\n");
 }
index e56efd5..ce54300 100644 (file)
@@ -133,7 +133,8 @@ alcor_init_irq(void)
        init_i8259a_irqs();
        common_init_isa_dma();
 
-       setup_irq(16+31, &isa_cascade_irqaction);
+       if (request_irq(16 + 31, no_action, 0, "isa-cascade", NULL))
+               pr_err("Failed to register isa-cascade interrupt\n");
 }
 
 
index 10bc46a..0aa6a27 100644 (file)
@@ -112,7 +112,8 @@ common_init_irq(void (*srm_dev_int)(unsigned long v))
        }
 
        common_init_isa_dma();
-       setup_irq(16+4, &isa_cascade_irqaction);
+       if (request_irq(16 + 4, no_action, 0, "isa-cascade", NULL))
+               pr_err("Failed to register isa-cascade interrupt\n");
 }
 
 #ifndef CONFIG_ALPHA_PC164
index 5251937..1cdfe55 100644 (file)
@@ -123,7 +123,8 @@ eb64p_init_irq(void)
        }
 
        common_init_isa_dma();
-       setup_irq(16+5, &isa_cascade_irqaction);
+       if (request_irq(16 + 5, no_action, 0, "isa-cascade", NULL))
+               pr_err("Failed to register isa-cascade interrupt\n");
 }
 
 /*
index 8d34cf6..533899a 100644 (file)
@@ -397,7 +397,7 @@ marvel_init_pci(void)
 static void __init
 marvel_init_rtc(void)
 {
-       init_rtc_irq();
+       init_rtc_irq(NULL);
 }
 
 static void
index 6fa07dc..702292a 100644 (file)
@@ -81,8 +81,10 @@ miata_init_irq(void)
        init_pyxis_irqs(0x63b0000);
 
        common_init_isa_dma();
-       setup_irq(16+2, &halt_switch_irqaction);        /* SRM only? */
-       setup_irq(16+6, &timer_cascade_irqaction);
+       if (request_irq(16 + 2, no_action, 0, "halt-switch", NULL))
+               pr_err("Failed to register halt-switch interrupt\n");
+       if (request_irq(16 + 6, no_action, 0, "timer-cascade", NULL))
+               pr_err("Failed to register timer-cascade interrupt\n");
 }
 
 
index 07830cc..d330740 100644 (file)
@@ -82,7 +82,8 @@ ruffian_init_rtc(void)
        outb(0x31, 0x42);
        outb(0x13, 0x42);
 
-       setup_irq(0, &timer_irqaction);
+       if (request_irq(0, rtc_timer_interrupt, 0, "timer", NULL))
+               pr_err("Failed to request irq 0 (timer)\n");
 }
 
 static void
index a3db719..4d85eae 100644 (file)
@@ -106,7 +106,8 @@ rx164_init_irq(void)
        init_i8259a_irqs();
        common_init_isa_dma();
 
-       setup_irq(16+20, &isa_cascade_irqaction);
+       if (request_irq(16 + 20, no_action, 0, "isa-cascade", NULL))
+               pr_err("Failed to register isa-cascade interrupt\n");
 }
 
 
index 1ec638a..17cc203 100644 (file)
@@ -54,7 +54,8 @@ sx164_init_irq(void)
        else
                init_pyxis_irqs(0xff00003f0000UL);
 
-       setup_irq(16+6, &timer_cascade_irqaction);
+       if (request_irq(16 + 6, no_action, 0, "timer-cascade", NULL))
+               pr_err("Failed to register timer-cascade interrupt\n");
 }
 
 /*
index 8e64052..2191bde 100644 (file)
@@ -156,10 +156,6 @@ static void __init
 wildfire_init_irq_per_pca(int qbbno, int pcano)
 {
        int i, irq_bias;
-       static struct irqaction isa_enable = {
-               .handler        = no_action,
-               .name           = "isa_enable",
-       };
 
        irq_bias = qbbno * (WILDFIRE_PCA_PER_QBB * WILDFIRE_IRQ_PER_PCA)
                 + pcano * WILDFIRE_IRQ_PER_PCA;
@@ -198,7 +194,8 @@ wildfire_init_irq_per_pca(int qbbno, int pcano)
                irq_set_status_flags(i + irq_bias, IRQ_LEVEL);
        }
 
-       setup_irq(32+irq_bias, &isa_enable);
+       if (request_irq(32 + irq_bias, no_action, 0, "isa_enable", NULL))
+               pr_err("Failed to register isa_enable interrupt\n");
 }
 
 static void __init
index 0069360..4d01c39 100644 (file)
@@ -242,7 +242,7 @@ common_init_rtc(void)
        outb(0x31, 0x42);
        outb(0x13, 0x42);
 
-       init_rtc_irq();
+       init_rtc_irq(NULL);
 }
 
 \f
@@ -396,9 +396,7 @@ time_init(void)
        if (alpha_using_qemu) {
                clocksource_register_hz(&qemu_cs, NSEC_PER_SEC);
                init_qemu_clockevent();
-
-               timer_irqaction.handler = qemu_timer_interrupt;
-               init_rtc_irq();
+               init_rtc_irq(qemu_timer_interrupt);
                return;
        }
 
index ff2a393..7124ab8 100644 (file)
@@ -154,7 +154,7 @@ config ARC_CPU_HS
        help
          Support for ARC HS38x Cores based on ARCv2 ISA
          The notable features are:
-           - SMP configurations of upto 4 core with coherency
+           - SMP configurations of up to 4 cores with coherency
            - Optional L2 Cache and IO-Coherency
            - Revised Interrupt Architecture (multiple priorites, reg banks,
                auto stack switch, auto regfile save/restore)
@@ -192,7 +192,7 @@ config ARC_SMP_HALT_ON_RESET
        help
          In SMP configuration cores can be configured as Halt-on-reset
          or they could all start at same time. For Halt-on-reset, non
-         masters are parked until Master kicks them so they can start of
+         masters are parked until Master kicks them so they can start off
          at designated entry point. For other case, all jump to common
          entry point and spin wait for Master's signal.
 
index 07f26ed..f7a978d 100644 (file)
@@ -21,8 +21,6 @@ CONFIG_MODULES=y
 CONFIG_MODULE_FORCE_LOAD=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARC_PLAT_EZNPS=y
 CONFIG_SMP=y
 CONFIG_NR_CPUS=4096
index 5dd470b..bf39a00 100644 (file)
@@ -20,8 +20,6 @@ CONFIG_ISA_ARCOMPACT=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci"
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
index 3532e86..7121bd7 100644 (file)
@@ -19,8 +19,6 @@ CONFIG_PERF_EVENTS=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_ISA_ARCV2=y
 CONFIG_ARC_BUILTIN_DTB_NAME="nsimosci_hs"
 # CONFIG_COMPACTION is not set
index d90448b..f9863b2 100644 (file)
@@ -14,8 +14,6 @@ CONFIG_PERF_EVENTS=y
 CONFIG_KPROBES=y
 CONFIG_MODULES=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_ISA_ARCV2=y
 CONFIG_SMP=y
 # CONFIG_ARC_TIMERS_64BIT is not set
index 6434725..006bcf8 100644 (file)
@@ -43,6 +43,8 @@ extern void fpu_init_task(struct pt_regs *regs);
 
 #endif /* !CONFIG_ISA_ARCOMPACT */
 
+struct task_struct;
+
 extern void fpu_save_restore(struct task_struct *p, struct task_struct *n);
 
 #else  /* !CONFIG_ARC_FPU_SAVE_RESTORE */
index 9d0d070..607d1c1 100644 (file)
@@ -75,10 +75,12 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
 {
        int oldval = 0, ret;
 
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
+
 #ifndef CONFIG_ARC_HAS_LLSC
        preempt_disable();      /* to guarantee atomic r-m-w of futex op */
 #endif
-       pagefault_disable();
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -101,7 +103,6 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
 #ifndef CONFIG_ARC_HAS_LLSC
        preempt_enable();
 #endif
index d9ee43c..fe19f1d 100644 (file)
@@ -29,6 +29,8 @@
 .endm
 
 #define ASM_NL          `      /* use '`' to mark new line in macro */
+#define __ALIGN                .align 4
+#define __ALIGN_STR    __stringify(__ALIGN)
 
 /* annotation for data we want in DCCM - if enabled in .config */
 .macro ARCFP_DATA nm
index e1c6474..aa41af6 100644 (file)
@@ -8,11 +8,11 @@
 #include <linux/delay.h>
 #include <linux/root_dev.h>
 #include <linux/clk.h>
-#include <linux/clk-provider.h>
 #include <linux/clocksource.h>
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/cpu.h>
+#include <linux/of_clk.h>
 #include <linux/of_fdt.h>
 #include <linux/of.h>
 #include <linux/cache.h>
index b79886a..d299950 100644 (file)
@@ -104,8 +104,7 @@ static void show_faulting_vma(unsigned long address)
                        if (IS_ERR(nm))
                                nm = "?";
                }
-               pr_info("    @off 0x%lx in [%s]\n"
-                       "    VMA: 0x%08lx to 0x%08lx\n",
+               pr_info("  @off 0x%lx in [%s]  VMA: 0x%08lx to 0x%08lx\n",
                        vma->vm_start < TASK_UNMAPPED_BASE ?
                                address : address - vma->vm_start,
                        nm, vma->vm_start, vma->vm_end);
@@ -120,8 +119,6 @@ static void show_ecr_verbose(struct pt_regs *regs)
        unsigned int vec, cause_code;
        unsigned long address;
 
-       pr_info("\n[ECR   ]: 0x%08lx => ", regs->event);
-
        /* For Data fault, this is data address not instruction addr */
        address = current->thread.fault_address;
 
@@ -130,10 +127,10 @@ static void show_ecr_verbose(struct pt_regs *regs)
 
        /* For DTLB Miss or ProtV, display the memory involved too */
        if (vec == ECR_V_DTLB_MISS) {
-               pr_cont("Invalid %s @ 0x%08lx by insn @ 0x%08lx\n",
+               pr_cont("Invalid %s @ 0x%08lx by insn @ %pS\n",
                       (cause_code == 0x01) ? "Read" :
                       ((cause_code == 0x02) ? "Write" : "EX"),
-                      address, regs->ret);
+                      address, (void *)regs->ret);
        } else if (vec == ECR_V_ITLB_MISS) {
                pr_cont("Insn could not be fetched\n");
        } else if (vec == ECR_V_MACH_CHK) {
@@ -191,31 +188,31 @@ void show_regs(struct pt_regs *regs)
 
        show_ecr_verbose(regs);
 
-       pr_info("[EFA   ]: 0x%08lx\n[BLINK ]: %pS\n[ERET  ]: %pS\n",
-               current->thread.fault_address,
-               (void *)regs->blink, (void *)regs->ret);
-
        if (user_mode(regs))
                show_faulting_vma(regs->ret); /* faulting code, not data */
 
-       pr_info("[STAT32]: 0x%08lx", regs->status32);
+       pr_info("ECR: 0x%08lx EFA: 0x%08lx ERET: 0x%08lx\n",
+               regs->event, current->thread.fault_address, regs->ret);
+
+       pr_info("STAT32: 0x%08lx", regs->status32);
 
 #define STS_BIT(r, bit)        r->status32 & STATUS_##bit##_MASK ? #bit" " : ""
 
 #ifdef CONFIG_ISA_ARCOMPACT
-       pr_cont(" : %2s%2s%2s%2s%2s%2s%2s\n",
+       pr_cont(" [%2s%2s%2s%2s%2s%2s%2s]",
                        (regs->status32 & STATUS_U_MASK) ? "U " : "K ",
                        STS_BIT(regs, DE), STS_BIT(regs, AE),
                        STS_BIT(regs, A2), STS_BIT(regs, A1),
                        STS_BIT(regs, E2), STS_BIT(regs, E1));
 #else
-       pr_cont(" : %2s%2s%2s%2s\n",
+       pr_cont(" [%2s%2s%2s%2s]",
                        STS_BIT(regs, IE),
                        (regs->status32 & STATUS_U_MASK) ? "U " : "K ",
                        STS_BIT(regs, DE), STS_BIT(regs, AE));
 #endif
-       pr_info("BTA: 0x%08lx\t SP: 0x%08lx\t FP: 0x%08lx\n",
-               regs->bta, regs->sp, regs->fp);
+       pr_cont("  BTA: 0x%08lx\n", regs->bta);
+       pr_info("BLK: %pS\n SP: 0x%08lx  FP: 0x%08lx\n",
+               (void *)regs->blink, regs->sp, regs->fp);
        pr_info("LPS: 0x%08lx\tLPE: 0x%08lx\tLPC: 0x%08lx\n",
               regs->lp_start, regs->lp_end, regs->lp_count);
 
index 97864aa..03bbfc3 100644 (file)
@@ -3,7 +3,6 @@ config ARM
        bool
        default y
        select ARCH_32BIT_OFF_T
-       select ARCH_CLOCKSOURCE_DATA
        select ARCH_HAS_BINFMT_FLAT
        select ARCH_HAS_DEBUG_VIRTUAL if MMU
        select ARCH_HAS_DEVMEM_IS_ALLOWED
index db857d0..1fc32b6 100644 (file)
@@ -307,13 +307,15 @@ endif
 ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
 prepare: stack_protector_prepare
 stack_protector_prepare: prepare0
-       $(eval KBUILD_CFLAGS += \
+       $(eval SSP_PLUGIN_CFLAGS := \
                -fplugin-arg-arm_ssp_per_task_plugin-tso=$(shell        \
                        awk '{if ($$2 == "THREAD_SZ_ORDER") print $$3;}'\
                                include/generated/asm-offsets.h)        \
                -fplugin-arg-arm_ssp_per_task_plugin-offset=$(shell     \
                        awk '{if ($$2 == "TI_STACK_CANARY") print $$3;}'\
                                include/generated/asm-offsets.h))
+       $(eval KBUILD_CFLAGS += $(SSP_PLUGIN_CFLAGS))
+       $(eval GCC_PLUGINS_CFLAGS += $(SSP_PLUGIN_CFLAGS))
 endif
 
 all:   $(notdir $(KBUILD_IMAGE))
index da599c3..9c11e74 100644 (file)
@@ -101,7 +101,6 @@ clean-files += piggy_data lib1funcs.S ashldi3.S bswapsdi2.S \
                $(libfdt) $(libfdt_hdrs) hyp-stub.S
 
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
-KBUILD_CFLAGS += $(DISABLE_ARM_SSP_PER_TASK_PLUGIN)
 
 ifeq ($(CONFIG_FUNCTION_TRACER),y)
 ORIG_CFLAGS := $(KBUILD_CFLAGS)
@@ -117,7 +116,8 @@ CFLAGS_fdt_ro.o := $(nossp-flags-y)
 CFLAGS_fdt_rw.o := $(nossp-flags-y)
 CFLAGS_fdt_wip.o := $(nossp-flags-y)
 
-ccflags-y := -fpic $(call cc-option,-mno-single-pic-base,) -fno-builtin -I$(obj)
+ccflags-y := -fpic $(call cc-option,-mno-single-pic-base,) -fno-builtin \
+            -I$(obj) $(DISABLE_ARM_SSP_PER_TASK_PLUGIN)
 asflags-y := -DZIMAGE
 
 # Supply kernel BSS size to the decompressor via a linker symbol.
index a598358..62286da 100644 (file)
@@ -60,7 +60,7 @@ optional_header:
                .long   __pecoff_code_size              @ SizeOfCode
                .long   __pecoff_data_size              @ SizeOfInitializedData
                .long   0                               @ SizeOfUninitializedData
-               .long   efi_stub_entry - start          @ AddressOfEntryPoint
+               .long   efi_entry - start               @ AddressOfEntryPoint
                .long   start_offset                    @ BaseOfCode
                .long   __pecoff_data_start - start     @ BaseOfData
 
@@ -70,8 +70,8 @@ extra_header_fields:
                .long   SZ_512                          @ FileAlignment
                .short  0                               @ MajorOsVersion
                .short  0                               @ MinorOsVersion
-               .short  0                               @ MajorImageVersion
-               .short  0                               @ MinorImageVersion
+               .short  LINUX_EFISTUB_MAJOR_VERSION     @ MajorImageVersion
+               .short  LINUX_EFISTUB_MINOR_VERSION     @ MinorImageVersion
                .short  0                               @ MajorSubsystemVersion
                .short  0                               @ MinorSubsystemVersion
                .long   0                               @ Win32VersionValue
index 088b0a0..04f7721 100644 (file)
@@ -1437,29 +1437,25 @@ __enter_kernel:
 reloc_code_end:
 
 #ifdef CONFIG_EFI_STUB
-               .align  2
-_start:                .long   start - .
-
-ENTRY(efi_stub_entry)
-               @ allocate space on stack for passing current zImage address
-               @ and for the EFI stub to return of new entry point of
-               @ zImage, as EFI stub may copy the kernel. Pointer address
-               @ is passed in r2. r0 and r1 are passed through from the
-               @ EFI firmware to efi_entry
-               adr     ip, _start
-               ldr     r3, [ip]
-               add     r3, r3, ip
-               stmfd   sp!, {r3, lr}
-               mov     r2, sp                  @ pass zImage address in r2
-               bl      efi_entry
-
-               @ Check for error return from EFI stub. r0 has FDT address
-               @ or error code.
-               cmn     r0, #1
-               beq     efi_load_fail
-
-               @ Preserve return value of efi_entry() in r4
-               mov     r4, r0
+ENTRY(efi_enter_kernel)
+               mov     r7, r0                          @ preserve image base
+               mov     r4, r1                          @ preserve DT pointer
+
+               mov     r0, r4                          @ DT start
+               add     r1, r4, r2                      @ DT end
+               bl      cache_clean_flush
+
+               mov     r0, r7                          @ relocated zImage
+               ldr     r1, =_edata                     @ size of zImage
+               add     r1, r1, r0                      @ end of zImage
+               bl      cache_clean_flush
+
+               @ The PE/COFF loader might not have cleaned the code we are
+               @ running beyond the PoU, and so calling cache_off below from
+               @ inside the PE/COFF loader allocated region is unsafe unless
+               @ we explicitly clean it to the PoC.
+               adr     r0, call_cache_fn               @ region of code we will
+               adr     r1, 0f                          @ run with MMU off
                bl      cache_clean_flush
                bl      cache_off
 
@@ -1469,18 +1465,10 @@ ENTRY(efi_stub_entry)
                mov     r0, #0
                mov     r1, #0xFFFFFFFF
                mov     r2, r4
-
-               @ Branch to (possibly) relocated zImage that is in [sp]
-               ldr     lr, [sp]
-               ldr     ip, =start_offset
-               add     lr, lr, ip
-               mov     pc, lr                          @ no mode switch
-
-efi_load_fail:
-               @ Return EFI_LOAD_ERROR to EFI firmware on error.
-               ldr     r0, =0x80000001
-               ldmfd   sp!, {ip, pc}
-ENDPROC(efi_stub_entry)
+               add     r7, r7, #(__efi_start - start)
+               mov     pc, r7                          @ no mode switch
+ENDPROC(efi_enter_kernel)
+0:
 #endif
 
                .align
index f3ced6d..9f66f96 100644 (file)
         * Supply voltage supervisor on board will not allow opp50 so
         * disable it and set opp100 as suspend OPP.
         */
-       opp50@300000000 {
+       opp50-300000000 {
                status = "disabled";
        };
 
-       opp100@600000000 {
+       opp100-600000000 {
                opp-suspend;
        };
 };
index 807a0fc..8e04303 100644 (file)
                        reg = <0x1e6a0000 0x300>;
                        interrupts = <5>;
                        clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
+                       aspeed,vhub-downstream-ports = <5>;
+                       aspeed,vhub-generic-endpoints = <15>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_usb2d_default>;
                        status = "disabled";
index ebec0fa..f12ec04 100644 (file)
                        reg = <0x1e6a0000 0x300>;
                        interrupts = <5>;
                        clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
+                       aspeed,vhub-downstream-ports = <5>;
+                       aspeed,vhub-generic-endpoints = <15>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_usb2ad_default>;
                        status = "disabled";
index 045ce66..7028e21 100644 (file)
                groups = "UART9";
        };
 
+       pinctrl_usb2ah_default: usb2ah_default {
+               function = "USB2AH";
+               groups = "USBA";
+       };
+
+       pinctrl_usb2ad_default: usb2ad_default {
+               function = "USB2AD";
+               groups = "USBA";
+       };
+
+       pinctrl_usb2bh_default: usb2bh_default {
+               function = "USB2BH";
+               groups = "USBB";
+       };
+
+       pinctrl_usb2bd_default: usb2bd_default {
+               function = "USB2BD";
+               groups = "USBB";
+       };
+
+       pinctrl_usb11bhid_default: usb11bhid_default {
+               function = "USB11BHID";
+               groups = "USBB";
+       };
+
        pinctrl_vb_default: vb_default {
                function = "VB";
                groups = "VB";
index 796976d..0a29b3b 100644 (file)
                        status = "disabled";
                };
 
+               ehci0: usb@1e6a1000 {
+                       compatible = "aspeed,ast2600-ehci", "generic-ehci";
+                       reg = <0x1e6a1000 0x100>;
+                       interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_usb2ah_default>;
+                       status = "disabled";
+               };
+
+               ehci1: usb@1e6a3000 {
+                       compatible = "aspeed,ast2600-ehci", "generic-ehci";
+                       reg = <0x1e6a3000 0x100>;
+                       interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_usb2bh_default>;
+                       status = "disabled";
+               };
+
+               uhci: usb@1e6b0000 {
+                       compatible = "aspeed,ast2600-uhci", "generic-uhci";
+                       reg = <0x1e6b0000 0x100>;
+                       interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                       #ports = <2>;
+                       clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>;
+                       status = "disabled";
+                       /*
+                        * No default pinmux, it will follow EHCI, use an
+                        * explicit pinmux override if EHCI is not enabled.
+                        */
+               };
+
+               vhub: usb-vhub@1e6a0000 {
+                       compatible = "aspeed,ast2600-usb-vhub";
+                       reg = <0x1e6a0000 0x350>;
+                       interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
+                       aspeed,vhub-downstream-ports = <7>;
+                       aspeed,vhub-generic-endpoints = <21>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_usb2ad_default>;
+                       status = "disabled";
+               };
+
                apb {
                        compatible = "simple-bus";
                        #address-cells = <1>;
index 1b5a835..efea891 100644 (file)
@@ -21,6 +21,7 @@
 
        aliases {
                ethernet0 = &genet;
+               pcie0 = &pcie0;
        };
 
        leds {
@@ -31,6 +32,8 @@
                pwr {
                        label = "PWR";
                        gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+                       default-state = "keep";
+                       linux,default-trigger = "default-on";
                };
        };
 
index b75af21..4c3f606 100644 (file)
 &sdhci {
        #address-cells = <1>;
        #size-cells = <0>;
+       pinctrl-names = "default";
        pinctrl-0 = <&emmc_gpio34 &gpclk2_gpio43>;
        bus-width = <4>;
        mmc-pwrseq = <&wifi_pwrseq>;
index 394c8a7..fd2c766 100644 (file)
@@ -15,6 +15,7 @@
                firmware: firmware {
                        compatible = "raspberrypi,bcm2835-firmware", "simple-bus";
                        mboxes = <&mailbox>;
+                       dma-ranges;
                };
 
                power: power {
index 66ab35e..28be033 100644 (file)
@@ -26,6 +26,8 @@
                pwr {
                        label = "PWR";
                        gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+                       default-state = "keep";
+                       linux,default-trigger = "default-on";
                };
        };
 };
index 74ed6d0..3734314 100644 (file)
@@ -27,6 +27,8 @@
                pwr {
                        label = "PWR";
                        gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+                       default-state = "keep";
+                       linux,default-trigger = "default-on";
                };
        };
 
index 3931fb0..91d1018 100644 (file)
 
 &cpsw_emac0 {
        phy-handle = <&ethphy0>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
 };
 
 &cpsw_emac1 {
        phy-handle = <&ethphy1>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
 };
 
 &davinci_mdio {
index 9e43d5e..79ccdd4 100644 (file)
 
 &cpsw_emac0 {
        phy-handle = <&ethphy0>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
 };
 
 &cpsw_emac1 {
        phy-handle = <&ethphy1>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
 };
 
 &davinci_mdio {
index 861ab90..c16e183 100644 (file)
 
 &cpsw_emac0 {
        phy-handle = <&ethphy0>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
 };
 
 &cpsw_emac1 {
        phy-handle = <&ethphy1>;
-       phy-mode = "rgmii";
+       phy-mode = "rgmii-id";
 };
 
 &davinci_mdio {
index de7f85e..af06a55 100644 (file)
                regulator-max-microvolt = <1800000>;
        };
 
-       evm_3v3: fixedregulator-evm3v3 {
+       vsys_3v3: fixedregulator-vsys3v3 {
                /* Output of Cntlr A of TPS43351-Q1 on dra7-evm */
                compatible = "regulator-fixed";
-               regulator-name = "evm_3v3";
+               regulator-name = "vsys_3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
                vin-supply = <&evm_12v0>;
index fc41883..2119a78 100644 (file)
                                clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER13_CLKCTRL 24>;
                                clock-names = "fck";
                                interrupts = <GIC_SPI 339 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-pwm;
                        };
                };
 
                                clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER14_CLKCTRL 24>;
                                clock-names = "fck";
                                interrupts = <GIC_SPI 340 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-pwm;
                        };
                };
 
                                clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER15_CLKCTRL 24>;
                                clock-names = "fck";
                                interrupts = <GIC_SPI 341 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-pwm;
                        };
                };
 
                                clocks = <&l4per3_clkctrl DRA7_L4PER3_TIMER16_CLKCTRL 24>;
                                clock-names = "fck";
                                interrupts = <GIC_SPI 342 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,timer-pwm;
                        };
                };
 
index d78b684..5f5ee16 100644 (file)
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0x0 0x0 0x0 0xc0000000>;
+               dma-ranges = <0x80000000 0x0 0x80000000 0x80000000>;
                ti,hwmods = "l3_main_1", "l3_main_2";
                reg = <0x0 0x44000000 0x0 0x1000000>,
                      <0x0 0x45000000 0x0 0x1000>;
                                device_type = "pci";
                                ranges = <0x81000000 0 0          0x03000 0 0x00010000
                                          0x82000000 0 0x20013000 0x13000 0 0xffed000>;
+                               dma-ranges = <0x02000000 0x0 0x00000000 0x00000000 0x1 0x00000000>;
                                bus-range = <0x00 0xff>;
                                #interrupt-cells = <1>;
                                num-lanes = <1>;
                                device_type = "pci";
                                ranges = <0x81000000 0 0          0x03000 0 0x00010000
                                          0x82000000 0 0x30013000 0x13000 0 0xffed000>;
+                               dma-ranges = <0x02000000 0x0 0x00000000 0x00000000 0x1 0x00000000>;
                                bus-range = <0x00 0xff>;
                                #interrupt-cells = <1>;
                                num-lanes = <1>;
index 2f7539a..42b8a20 100644 (file)
 &usb4_tm {
        status = "disabled";
 };
+
+&mmc3 {
+       /* dra76x is not affected by i887 */
+       max-frequency = <96000000>;
+};
index 55cef4c..dc0a93b 100644 (file)
                clock-div = <1>;
        };
 
-       ipu1_gfclk_mux: ipu1_gfclk_mux@520 {
-               #clock-cells = <0>;
-               compatible = "ti,mux-clock";
-               clocks = <&dpll_abe_m2x2_ck>, <&dpll_core_h22x2_ck>;
-               ti,bit-shift = <24>;
-               reg = <0x0520>;
-               assigned-clocks = <&ipu1_gfclk_mux>;
-               assigned-clock-parents = <&dpll_core_h22x2_ck>;
-       };
-
        dummy_ck: dummy_ck {
                #clock-cells = <0>;
                compatible = "fixed-clock";
                        compatible = "ti,clkctrl";
                        reg = <0x20 0x4>;
                        #clock-cells = <2>;
+                       assigned-clocks = <&ipu1_clkctrl DRA7_IPU1_MMU_IPU1_CLKCTRL 24>;
+                       assigned-clock-parents = <&dpll_core_h22x2_ck>;
                };
 
                ipu_clkctrl: ipu-clkctrl@50 {
index 31719c0..44f9754 100644 (file)
@@ -33,7 +33,7 @@
                };
        };
 
-       lcd_vdd3_reg: voltage-regulator-6 {
+       lcd_vdd3_reg: voltage-regulator-7 {
                compatible = "regulator-fixed";
                regulator-name = "LCD_VDD_2.2V";
                regulator-min-microvolt = <2200000>;
@@ -42,7 +42,7 @@
                enable-active-high;
        };
 
-       ps_als_reg: voltage-regulator-7 {
+       ps_als_reg: voltage-regulator-8 {
                compatible = "regulator-fixed";
                regulator-name = "LED_A_3.0V";
                regulator-min-microvolt = <3000000>;
index 98cd128..4189e1f 100644 (file)
@@ -13,7 +13,7 @@
 
        /* bootargs are passed in by bootloader */
 
-       cam_vdda_reg: voltage-regulator-6 {
+       cam_vdda_reg: voltage-regulator-7 {
                compatible = "regulator-fixed";
                regulator-name = "CAM_SENSOR_CORE_1.2V";
                regulator-min-microvolt = <1200000>;
index cd07562..84fcc20 100644 (file)
 
        /* SRAM on Colibri nEXT_CS0 */
        sram@0,0 {
-               compatible = "cypress,cy7c1019dv33-10zsximtd-ram";
+               compatible = "cypress,cy7c1019dv33-10zsxi", "mtd-ram";
                reg = <0 0 0x00010000>;
                #address-cells = <1>;
                #size-cells = <1>;
 
        /* SRAM on Colibri nEXT_CS1 */
        sram@1,0 {
-               compatible = "cypress,cy7c1019dv33-10zsximtd-ram";
+               compatible = "cypress,cy7c1019dv33-10zsxi", "mtd-ram";
                reg = <1 0 0x00010000>;
                #address-cells = <1>;
                #size-cells = <1>;
index 978dc1c..77d8713 100644 (file)
                regulators {
                        vdd_arm: buck1 {
                                regulator-name = "vdd_arm";
-                               regulator-min-microvolt = <730000>;
+                               regulator-min-microvolt = <925000>;
                                regulator-max-microvolt = <1380000>;
                                regulator-initial-mode = <DA9063_BUCK_MODE_SYNC>;
                                regulator-always-on;
 
                        vdd_soc: buck2 {
                                regulator-name = "vdd_soc";
-                               regulator-min-microvolt = <730000>;
+                               regulator-min-microvolt = <1150000>;
                                regulator-max-microvolt = <1380000>;
                                regulator-initial-mode = <DA9063_BUCK_MODE_SYNC>;
                                regulator-always-on;
        pinctrl-0 = <&pinctrl_usdhc4>;
        bus-width = <8>;
        non-removable;
-       vmmc-supply = <&vdd_emmc_1p8>;
        status = "disabled";
 };
 
index d05be3f..04717cf 100644 (file)
        assigned-clock-rates = <400000000>;
        bus-width = <8>;
        fsl,tuning-step = <2>;
-       max-frequency = <100000000>;
        vmmc-supply = <&reg_module_3v3>;
        vqmmc-supply = <&reg_DCDC3>;
        non-removable;
index 92f6d0c..4c22828 100644 (file)
@@ -44,7 +44,7 @@
                        opp-hz = /bits/ 64 <792000000>;
                        opp-microvolt = <1000000>;
                        clock-latency-ns = <150000>;
-                       opp-supported-hw = <0xd>, <0xf>;
+                       opp-supported-hw = <0xd>, <0x7>;
                        opp-suspend;
                };
 
@@ -52,7 +52,7 @@
                        opp-hz = /bits/ 64 <996000000>;
                        opp-microvolt = <1100000>;
                        clock-latency-ns = <150000>;
-                       opp-supported-hw = <0xc>, <0xf>;
+                       opp-supported-hw = <0xc>, <0x7>;
                        opp-suspend;
                };
 
@@ -60,7 +60,7 @@
                        opp-hz = /bits/ 64 <1200000000>;
                        opp-microvolt = <1225000>;
                        clock-latency-ns = <150000>;
-                       opp-supported-hw = <0x8>, <0xf>;
+                       opp-supported-hw = <0x8>, <0x3>;
                        opp-suspend;
                };
        };
index 0855b1f..760a68c 100644 (file)
                };
 
                mdio0: mdio@2d24000 {
-                       compatible = "fsl,etsec2-mdio";
+                       compatible = "gianfar";
                        device_type = "mdio";
                        #address-cells = <1>;
                        #size-cells = <0>;
                };
 
                mdio1: mdio@2d64000 {
-                       compatible = "fsl,etsec2-mdio";
+                       compatible = "gianfar";
                        device_type = "mdio";
                        #address-cells = <1>;
                        #size-cells = <0>;
index 8566550..9067e0e 100644 (file)
                pwm-names = "enable", "direction";
                direction-duty-cycle-ns = <10000000>;
        };
+
+       backlight: backlight {
+               compatible = "led-backlight";
+
+               leds = <&backlight_led>;
+               brightness-levels = <31 63 95 127 159 191 223 255>;
+               default-brightness-level = <6>;
+       };
 };
 
 &dss {
                vddi-supply = <&lcd_regulator>;
                reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;      /* gpio101 */
 
+               backlight = <&backlight>;
+
                width-mm = <50>;
                height-mm = <89>;
 
                ramp-up-us = <1024>;
                ramp-down-us = <8193>;
 
-               led@0 {
+               backlight_led: led@0 {
                        reg = <0>;
                        led-sources = <2>;
                        ti,led-mode = <0>;
                        label = ":backlight";
-                       linux,default-trigger = "backlight";
                };
 
                led@1 {
                reset-gpios = <&gpio6 13 GPIO_ACTIVE_HIGH>; /* gpio173 */
 
                /* gpio_183 with sys_nirq2 pad as wakeup */
-               interrupts-extended = <&gpio6 23 IRQ_TYPE_EDGE_FALLING>,
+               interrupts-extended = <&gpio6 23 IRQ_TYPE_LEVEL_LOW>,
                                      <&omap4_pmx_core 0x160>;
                interrupt-names = "irq", "wakeup";
                wakeup-source;
index c3c6d7d..4089d97 100644 (file)
                compatible = "ti,omap2-onenand";
                reg = <0 0 0x20000>;    /* CS0, offset 0, IO size 128K */
 
+               /*
+                * These timings are based on CONFIG_OMAP_GPMC_DEBUG=y reported
+                * bootloader set values when booted with v5.1
+                * (OneNAND Manufacturer: Samsung):
+                *
+                *   cs0 GPMC_CS_CONFIG1: 0xfb001202
+                *   cs0 GPMC_CS_CONFIG2: 0x00111100
+                *   cs0 GPMC_CS_CONFIG3: 0x00020200
+                *   cs0 GPMC_CS_CONFIG4: 0x11001102
+                *   cs0 GPMC_CS_CONFIG5: 0x03101616
+                *   cs0 GPMC_CS_CONFIG6: 0x90060000
+                */
                gpmc,sync-read;
                gpmc,sync-write;
                gpmc,burst-length = <16>;
                gpmc,burst-read;
                gpmc,burst-wrap;
                gpmc,burst-write;
-               gpmc,device-width = <2>; /* GPMC_DEVWIDTH_16BIT */
-               gpmc,mux-add-data = <2>; /* GPMC_MUX_AD */
+               gpmc,device-width = <2>;
+               gpmc,mux-add-data = <2>;
                gpmc,cs-on-ns = <0>;
-               gpmc,cs-rd-off-ns = <87>;
-               gpmc,cs-wr-off-ns = <87>;
+               gpmc,cs-rd-off-ns = <102>;
+               gpmc,cs-wr-off-ns = <102>;
                gpmc,adv-on-ns = <0>;
-               gpmc,adv-rd-off-ns = <10>;
-               gpmc,adv-wr-off-ns = <10>;
-               gpmc,oe-on-ns = <15>;
-               gpmc,oe-off-ns = <87>;
+               gpmc,adv-rd-off-ns = <12>;
+               gpmc,adv-wr-off-ns = <12>;
+               gpmc,oe-on-ns = <12>;
+               gpmc,oe-off-ns = <102>;
                gpmc,we-on-ns = <0>;
-               gpmc,we-off-ns = <87>;
-               gpmc,rd-cycle-ns = <112>;
-               gpmc,wr-cycle-ns = <112>;
-               gpmc,access-ns = <81>;
-               gpmc,page-burst-access-ns = <15>;
+               gpmc,we-off-ns = <102>;
+               gpmc,rd-cycle-ns = <132>;
+               gpmc,wr-cycle-ns = <132>;
+               gpmc,access-ns = <96>;
+               gpmc,page-burst-access-ns = <18>;
                gpmc,bus-turnaround-ns = <0>;
                gpmc,cycle2cycle-delay-ns = <0>;
                gpmc,wait-monitoring-ns = <0>;
-               gpmc,clk-activation-ns = <5>;
-               gpmc,wr-data-mux-bus-ns = <30>;
-               gpmc,wr-access-ns = <81>;
+               gpmc,clk-activation-ns = <6>;
+               gpmc,wr-data-mux-bus-ns = <36>;
+               gpmc,wr-access-ns = <96>;
                gpmc,sync-clk-ps = <15000>;
 
                /*
index d0ecf54..a7562d3 100644 (file)
                #address-cells = <1>;
                #size-cells = <1>;
                ranges = <0 0 0 0xc0000000>;
+               dma-ranges = <0x80000000 0x0 0x80000000 0x80000000>;
                ti,hwmods = "l3_main_1", "l3_main_2", "l3_main_3";
                reg = <0 0x44000000 0 0x2000>,
                      <0 0x44800000 0 0x3000>,
index 9f6c2b6..0755e58 100644 (file)
                                        interrupt-controller;
                                        reg = <0 0x200>;
                                        #interrupt-cells = <1>;
-                                       valid-mask = <0xFFFFFFFF>;
-                                       clear-mask = <0>;
+                                       valid-mask = <0xffffffff>;
+                                       clear-mask = <0xffffffff>;
                                };
 
                                timer0: timer@200 {
index c9b3277..90846a7 100644 (file)
                                        reg = <0 0x200>;
                                        interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
                                        #interrupt-cells = <1>;
-                                       valid-mask = <0xFFFFFFFF>;
-                                       clear-mask = <0>;
+                                       valid-mask = <0xffffffff>;
+                                       clear-mask = <0xffffffff>;
                                };
 
                                timer0: timer@200 {
index beb9885..c0999e2 100644 (file)
        };
 
        sata: sata@fc600000 {
-               compatible = "renesas,sata-r8a7779", "renesas,rcar-sata";
+               compatible = "renesas,sata-r8a7779";
                reg = <0xfc600000 0x200000>;
                interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&mstp1_clks R8A7779_CLK_SATA>;
index 1532a0e..a2c37ad 100644 (file)
                };
 
                crypto: crypto-engine@1c15000 {
-                       compatible = "allwinner,sun4i-a10-crypto";
+                       compatible = "allwinner,sun8i-a33-crypto";
                        reg = <0x01c15000 0x1000>;
                        interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&ccu CLK_BUS_SS>, <&ccu CLK_SS>;
index 2fd31a0..e8b3669 100644 (file)
 };
 
 &reg_dldo3 {
-       regulator-min-microvolt = <2800000>;
-       regulator-max-microvolt = <2800000>;
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
        regulator-name = "vdd-csi";
 };
 
 };
 
 &usbphy {
-       usb0_id_det-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
+       usb0_id_det-gpios = <&pio 7 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; /* PH11 */
+       usb0_vbus_power-supply = <&usb_power_supply>;
        usb0_vbus-supply = <&reg_drivevbus>;
        usb1_vbus-supply = <&reg_vmain>;
        usb2_vbus-supply = <&reg_vmain>;
index 74ac7ee..e7b9bef 100644 (file)
                        reg = <0x01c30000 0x104>;
                        interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
                        interrupt-names = "macirq";
-                       resets = <&ccu CLK_BUS_EMAC>;
-                       reset-names = "stmmaceth";
-                       clocks = <&ccu RST_BUS_EMAC>;
+                       clocks = <&ccu CLK_BUS_EMAC>;
                        clock-names = "stmmaceth";
+                       resets = <&ccu RST_BUS_EMAC>;
+                       reset-names = "stmmaceth";
                        status = "disabled";
 
                        mdio: mdio {
index 8f09a24..a9d5d6d 100644 (file)
                        interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
                };
 
+               spi0: spi@1c05000 {
+                       compatible = "allwinner,sun8i-r40-spi",
+                                    "allwinner,sun8i-h3-spi";
+                       reg = <0x01c05000 0x1000>;
+                       interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
+                       clock-names = "ahb", "mod";
+                       resets = <&ccu RST_BUS_SPI0>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               spi1: spi@1c06000 {
+                       compatible = "allwinner,sun8i-r40-spi",
+                                    "allwinner,sun8i-h3-spi";
+                       reg = <0x01c06000 0x1000>;
+                       interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
+                       clock-names = "ahb", "mod";
+                       resets = <&ccu RST_BUS_SPI1>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
                csi0: csi@1c09000 {
                        compatible = "allwinner,sun8i-r40-csi0",
                                     "allwinner,sun7i-a20-csi0";
                        resets = <&ccu RST_BUS_CE>;
                };
 
+               spi2: spi@1c17000 {
+                       compatible = "allwinner,sun8i-r40-spi",
+                                    "allwinner,sun8i-h3-spi";
+                       reg = <0x01c17000 0x1000>;
+                       interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_SPI2>, <&ccu CLK_SPI2>;
+                       clock-names = "ahb", "mod";
+                       resets = <&ccu RST_BUS_SPI2>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               ahci: sata@1c18000 {
+                       compatible = "allwinner,sun8i-r40-ahci";
+                       reg = <0x01c18000 0x1000>;
+                       interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_SATA>, <&ccu CLK_SATA>;
+                       resets = <&ccu RST_BUS_SATA>;
+                       reset-names = "ahci";
+                       status = "disabled";
+               };
+
                ehci1: usb@1c19000 {
                        compatible = "allwinner,sun8i-r40-ehci", "generic-ehci";
                        reg = <0x01c19000 0x100>;
                        status = "disabled";
                };
 
+               spi3: spi@1c1f000 {
+                       compatible = "allwinner,sun8i-r40-spi",
+                                    "allwinner,sun8i-h3-spi";
+                       reg = <0x01c1f000 0x1000>;
+                       interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&ccu CLK_BUS_SPI3>, <&ccu CLK_SPI3>;
+                       clock-names = "ahb", "mod";
+                       resets = <&ccu RST_BUS_SPI3>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
                ccu: clock@1c20000 {
                        compatible = "allwinner,sun8i-r40-ccu";
                        reg = <0x01c20000 0x400>;
                        #size-cells = <0>;
                };
 
-               spi0: spi@1c05000 {
-                       compatible = "allwinner,sun8i-r40-spi",
-                                    "allwinner,sun8i-h3-spi";
-                       reg = <0x01c05000 0x1000>;
-                       interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
-                       clock-names = "ahb", "mod";
-                       resets = <&ccu RST_BUS_SPI0>;
-                       status = "disabled";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-               };
-
-               spi1: spi@1c06000 {
-                       compatible = "allwinner,sun8i-r40-spi",
-                                    "allwinner,sun8i-h3-spi";
-                       reg = <0x01c06000 0x1000>;
-                       interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_SPI1>, <&ccu CLK_SPI1>;
-                       clock-names = "ahb", "mod";
-                       resets = <&ccu RST_BUS_SPI1>;
-                       status = "disabled";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-               };
-
-               spi2: spi@1c07000 {
-                       compatible = "allwinner,sun8i-r40-spi",
-                                    "allwinner,sun8i-h3-spi";
-                       reg = <0x01c07000 0x1000>;
-                       interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_SPI2>, <&ccu CLK_SPI2>;
-                       clock-names = "ahb", "mod";
-                       resets = <&ccu RST_BUS_SPI2>;
-                       status = "disabled";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-               };
-
-               spi3: spi@1c0f000 {
-                       compatible = "allwinner,sun8i-r40-spi",
-                                    "allwinner,sun8i-h3-spi";
-                       reg = <0x01c0f000 0x1000>;
-                       interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_SPI3>, <&ccu CLK_SPI3>;
-                       clock-names = "ahb", "mod";
-                       resets = <&ccu RST_BUS_SPI3>;
-                       status = "disabled";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-               };
-
-               ahci: sata@1c18000 {
-                       compatible = "allwinner,sun8i-r40-ahci";
-                       reg = <0x01c18000 0x1000>;
-                       interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&ccu CLK_BUS_SATA>, <&ccu CLK_SATA>;
-                       resets = <&ccu RST_BUS_SATA>;
-                       reset-names = "ahci";
-                       status = "disabled";
-
-               };
-
                gmac: ethernet@1c50000 {
                        compatible = "allwinner,sun8i-r40-gmac";
                        syscon = <&ccu>;
index 947ef79..c98ebae 100644 (file)
@@ -302,10 +302,13 @@ static int sa1111_retrigger_irq(struct irq_data *d)
                        break;
        }
 
-       if (i == 8)
+       if (i == 8) {
                pr_err("Danger Will Robinson: failed to re-trigger IRQ%d\n",
                       d->irq);
-       return i == 8 ? -1 : 0;
+               return 0;
+       }
+
+       return 1;
 }
 
 static int sa1111_type_irq(struct irq_data *d, unsigned int flags)
index 519ff58..0afcae9 100644 (file)
@@ -178,6 +178,7 @@ CONFIG_SCHED_TRACER=y
 CONFIG_STACK_TRACER=y
 CONFIG_FUNCTION_PROFILER=y
 CONFIG_TEST_KSTRTOX=y
+CONFIG_DEBUG_FS=y
 CONFIG_KGDB=y
 CONFIG_KGDB_KDB=y
 CONFIG_STRICT_DEVMEM=y
index c32c338..847f987 100644 (file)
@@ -375,6 +375,7 @@ CONFIG_BACKLIGHT_GENERIC=m
 CONFIG_BACKLIGHT_PWM=m
 CONFIG_BACKLIGHT_PANDORA=m
 CONFIG_BACKLIGHT_GPIO=m
+CONFIG_BACKLIGHT_LED=m
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
 CONFIG_LOGO=y
index fe2e1e8..e73c97b 100644 (file)
@@ -157,6 +157,7 @@ CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_INFO=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_FUNCTION_TRACER=y
index 0b350a7..13651c7 100644 (file)
@@ -1,8 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 #ifndef _ASM_CLOCKSOURCE_H
 #define _ASM_CLOCKSOURCE_H
 
-struct arch_clocksource_data {
-       bool vdso_direct;       /* Usable for direct VDSO access? */
-};
+#include <asm/vdso/clocksource.h>
 
-#endif
+#endif /* _ASM_CLOCKSOURCE_H */
index d2453e2..a54230e 100644 (file)
 
 #ifdef CONFIG_CPU_CP15
 
-#define __ACCESS_CP15(CRn, Op1, CRm, Op2)      \
-       "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32
-#define __ACCESS_CP15_64(Op1, CRm)             \
-       "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64
-
-#define __read_sysreg(r, w, c, t) ({                           \
-       t __val;                                                \
-       asm volatile(r " " c : "=r" (__val));                   \
-       __val;                                                  \
-})
-#define read_sysreg(...)               __read_sysreg(__VA_ARGS__)
-
-#define __write_sysreg(v, r, w, c, t)  asm volatile(w " " c : : "r" ((t)(v)))
-#define write_sysreg(v, ...)           __write_sysreg(v, __VA_ARGS__)
-
-#define BPIALL                         __ACCESS_CP15(c7, 0, c5, 6)
-#define ICIALLU                                __ACCESS_CP15(c7, 0, c5, 0)
-
-#define CNTVCT                         __ACCESS_CP15_64(1, c14)
+#include <asm/vdso/cp15.h>
 
 extern unsigned long cr_alignment;     /* defined in entry-armv.S */
 
index f4fe4d0..79fa327 100644 (file)
@@ -8,16 +8,18 @@
  */
 #ifndef __ASM_ARM_FLOPPY_H
 #define __ASM_ARM_FLOPPY_H
-#if 0
-#include <mach/floppy.h>
-#endif
 
-#define fd_outb(val,port)                      \
-       do {                                    \
-               if ((port) == (u32)FD_DOR)      \
-                       fd_setdor((val));       \
-               else                            \
-                       outb((val),(port));     \
+#define fd_outb(val,port)                                              \
+       do {                                                            \
+               int new_val = (val);                                    \
+               if (((port) & 7) == FD_DOR) {                           \
+                       if (new_val & 0xf0)                             \
+                               new_val = (new_val & 0x0c) |            \
+                                         floppy_selects[new_val & 3];  \
+                       else                                            \
+                               new_val &= 0x0c;                        \
+               }                                                       \
+               outb(new_val, (port));                                  \
        } while(0)
 
 #define fd_inb(port)           inb((port))
@@ -53,69 +55,7 @@ static inline int fd_dma_setup(void *data, unsigned int length,
  * to a non-zero track, and then restoring it to track 0.  If an error occurs,
  * then there is no floppy drive present.       [to be put back in again]
  */
-static unsigned char floppy_selects[2][4] =
-{
-       { 0x10, 0x21, 0x23, 0x33 },
-       { 0x10, 0x21, 0x23, 0x33 }
-};
-
-#define fd_setdor(dor)                                                         \
-do {                                                                           \
-       int new_dor = (dor);                                                    \
-       if (new_dor & 0xf0)                                                     \
-               new_dor = (new_dor & 0x0c) | floppy_selects[fdc][new_dor & 3];  \
-       else                                                                    \
-               new_dor &= 0x0c;                                                \
-       outb(new_dor, FD_DOR);                                                  \
-} while (0)
-
-/*
- * Someday, we'll automatically detect which drives are present...
- */
-static inline void fd_scandrives (void)
-{
-#if 0
-       int floppy, drive_count;
-
-       fd_disable_irq();
-       raw_cmd = &default_raw_cmd;
-       raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_SEEK;
-       raw_cmd->track = 0;
-       raw_cmd->rate = ?;
-       drive_count = 0;
-       for (floppy = 0; floppy < 4; floppy ++) {
-               current_drive = drive_count;
-               /*
-                * Turn on floppy motor
-                */
-               if (start_motor(redo_fd_request))
-                       continue;
-               /*
-                * Set up FDC
-                */
-               fdc_specify();
-               /*
-                * Tell FDC to recalibrate
-                */
-               output_byte(FD_RECALIBRATE);
-               LAST_OUT(UNIT(floppy));
-               /* wait for command to complete */
-               if (!successful) {
-                       int i;
-                       for (i = drive_count; i < 3; i--)
-                               floppy_selects[fdc][i] = floppy_selects[fdc][i + 1];
-                       floppy_selects[fdc][3] = 0;
-                       floppy -= 1;
-               } else
-                       drive_count++;
-       }
-#else
-       floppy_selects[0][0] = 0x10;
-       floppy_selects[0][1] = 0x21;
-       floppy_selects[0][2] = 0x23;
-       floppy_selects[0][3] = 0x33;
-#endif
-}
+static unsigned char floppy_selects[4] = { 0x10, 0x21, 0x23, 0x33 };
 
 #define FDC1 (0x3f0)
 
@@ -135,9 +75,7 @@ static inline void fd_scandrives (void)
  */
 static void driveswap(int *ints, int dummy, int dummy2)
 {
-       floppy_selects[0][0] ^= floppy_selects[0][1];
-       floppy_selects[0][1] ^= floppy_selects[0][0];
-       floppy_selects[0][0] ^= floppy_selects[0][1];
+       swap(floppy_selects[0], floppy_selects[1]);
 }
 
 #define EXTRA_FLOPPY_PARAMS ,{ "driveswap", &driveswap, NULL, 0, 0 }
index 83c391b..e133da3 100644 (file)
@@ -134,10 +134,12 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
        int oldval = 0, ret, tmp;
 
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
+
 #ifndef CONFIG_SMP
        preempt_disable();
 #endif
-       pagefault_disable();
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -159,7 +161,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
 #ifndef CONFIG_SMP
        preempt_enable();
 #endif
index c3314b2..a827b4d 100644 (file)
@@ -392,9 +392,6 @@ static inline void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) {}
 static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {}
 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) {}
-
 #define KVM_BP_HARDEN_UNKNOWN          -1
 #define KVM_BP_HARDEN_WA_NEEDED                0
 #define KVM_BP_HARDEN_NOT_REQUIRED     1
index 614bf82..b924105 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/ptrace.h>
 #include <asm/types.h>
 #include <asm/unified.h>
+#include <asm/vdso/processor.h>
 
 #ifdef __KERNEL__
 #define STACK_TOP      ((current->personality & ADDR_LIMIT_32BIT) ? \
@@ -85,16 +86,6 @@ extern void release_thread(struct task_struct *);
 
 unsigned long get_wchan(struct task_struct *p);
 
-#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
-#define cpu_relax()                                            \
-       do {                                                    \
-               smp_mb();                                       \
-               __asm__ __volatile__("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");      \
-       } while (0)
-#else
-#define cpu_relax()                    barrier()
-#endif
-
 #define task_pt_regs(p) \
        ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
 
index 0d0d517..3609a69 100644 (file)
@@ -141,7 +141,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp *,
 #define TIF_SYSCALL_TRACEPOINT 6       /* syscall tracepoint instrumentation */
 #define TIF_SECCOMP            7       /* seccomp syscall filtering active */
 
-#define TIF_NOHZ               12      /* in adaptive nohz mode */
 #define TIF_USING_IWMMXT       17
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK    20
index 8a0fae9..435aba2 100644 (file)
@@ -16,6 +16,9 @@
 /* Enable topology flag updates */
 #define arch_update_cpu_topology topology_update_cpu_topology
 
+/* Replace task scheduler's default thermal pressure retrieve API */
+#define arch_scale_thermal_pressure topology_get_thermal_pressure
+
 #else
 
 static inline void init_cpu_topology(void) { }
diff --git a/arch/arm/include/asm/vdso/clocksource.h b/arch/arm/include/asm/vdso/clocksource.h
new file mode 100644 (file)
index 0000000..50c0b19
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_VDSOCLOCKSOURCE_H
+#define __ASM_VDSOCLOCKSOURCE_H
+
+#define VDSO_ARCH_CLOCKMODES   \
+       VDSO_CLOCKMODE_ARCHTIMER
+
+#endif /* __ASM_VDSOCLOCKSOURCE_H */
diff --git a/arch/arm/include/asm/vdso/cp15.h b/arch/arm/include/asm/vdso/cp15.h
new file mode 100644 (file)
index 0000000..bed16fa
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+#ifndef __ASM_VDSO_CP15_H
+#define __ASM_VDSO_CP15_H
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_CPU_CP15
+
+#include <linux/stringify.h>
+
+#define __ACCESS_CP15(CRn, Op1, CRm, Op2)      \
+       "mrc", "mcr", __stringify(p15, Op1, %0, CRn, CRm, Op2), u32
+#define __ACCESS_CP15_64(Op1, CRm)             \
+       "mrrc", "mcrr", __stringify(p15, Op1, %Q0, %R0, CRm), u64
+
+#define __read_sysreg(r, w, c, t) ({                           \
+       t __val;                                                \
+       asm volatile(r " " c : "=r" (__val));                   \
+       __val;                                                  \
+})
+#define read_sysreg(...)               __read_sysreg(__VA_ARGS__)
+
+#define __write_sysreg(v, r, w, c, t)  asm volatile(w " " c : : "r" ((t)(v)))
+#define write_sysreg(v, ...)           __write_sysreg(v, __VA_ARGS__)
+
+#define BPIALL                         __ACCESS_CP15(c7, 0, c5, 6)
+#define ICIALLU                                __ACCESS_CP15(c7, 0, c5, 0)
+
+#define CNTVCT                         __ACCESS_CP15_64(1, c14)
+
+#endif /* CONFIG_CPU_CP15 */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_VDSO_CP15_H */
index fe6e1f6..36dc185 100644 (file)
@@ -7,9 +7,9 @@
 
 #ifndef __ASSEMBLY__
 
-#include <asm/barrier.h>
-#include <asm/cp15.h>
+#include <asm/errno.h>
 #include <asm/unistd.h>
+#include <asm/vdso/cp15.h>
 #include <uapi/linux/time.h>
 
 #define VDSO_HAS_CLOCK_GETRES          1
@@ -106,20 +106,32 @@ static __always_inline int clock_getres32_fallback(
        return ret;
 }
 
+static inline bool arm_vdso_hres_capable(void)
+{
+       return IS_ENABLED(CONFIG_ARM_ARCH_TIMER);
+}
+#define __arch_vdso_hres_capable arm_vdso_hres_capable
+
 static __always_inline u64 __arch_get_hw_counter(int clock_mode)
 {
 #ifdef CONFIG_ARM_ARCH_TIMER
        u64 cycle_now;
 
-       if (!clock_mode)
-               return -EINVAL;
+       /*
+        * Core checks for mode already, so this raced against a concurrent
+        * update. Return something. Core will do another round and then
+        * see the mode change and fallback to the syscall.
+        */
+       if (clock_mode == VDSO_CLOCKMODE_NONE)
+               return 0;
 
        isb();
        cycle_now = read_sysreg(CNTVCT);
 
        return cycle_now;
 #else
-       return -EINVAL; /* use fallback */
+       /* Make GCC happy. This is compiled out anyway */
+       return 0;
 #endif
 }
 
diff --git a/arch/arm/include/asm/vdso/processor.h b/arch/arm/include/asm/vdso/processor.h
new file mode 100644 (file)
index 0000000..45efb3f
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+#ifndef __ASM_VDSO_PROCESSOR_H
+#define __ASM_VDSO_PROCESSOR_H
+
+#ifndef __ASSEMBLY__
+
+#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
+#define cpu_relax()                                            \
+       do {                                                    \
+               smp_mb();                                       \
+               __asm__ __volatile__("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;");      \
+       } while (0)
+#else
+#define cpu_relax()                    barrier()
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_VDSO_PROCESSOR_H */
index cff87d8..47e41ae 100644 (file)
 extern struct vdso_data *vdso_data;
 extern bool cntvct_ok;
 
-static __always_inline
-bool tk_is_cntvct(const struct timekeeper *tk)
-{
-       if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
-               return false;
-
-       if (!tk->tkr_mono.clock->archdata.vdso_direct)
-               return false;
-
-       return true;
-}
-
 /*
  * Update the vDSO data page to keep in sync with kernel timekeeping.
  */
@@ -34,29 +22,6 @@ struct vdso_data *__arm_get_k_vdso_data(void)
 #define __arch_get_k_vdso_data __arm_get_k_vdso_data
 
 static __always_inline
-bool __arm_update_vdso_data(void)
-{
-       return cntvct_ok;
-}
-#define __arch_update_vdso_data __arm_update_vdso_data
-
-static __always_inline
-int __arm_get_clock_mode(struct timekeeper *tk)
-{
-       u32 __tk_is_cntvct = tk_is_cntvct(tk);
-
-       return __tk_is_cntvct;
-}
-#define __arch_get_clock_mode __arm_get_clock_mode
-
-static __always_inline
-int __arm_use_vsyscall(struct vdso_data *vdata)
-{
-       return vdata[CS_HRES_COARSE].clock_mode;
-}
-#define __arch_use_vsyscall __arm_use_vsyscall
-
-static __always_inline
 void __arm_sync_vdso_data(struct vdso_data *vdata)
 {
        flush_dcache_page(virt_to_page(vdata));
index bb18ed0..0ce388f 100644 (file)
@@ -88,11 +88,11 @@ void soft_restart(unsigned long addr)
  * to execute e.g. a RAM-based pin loop is not sufficient. This allows the
  * kexec'd kernel to use any and all RAM as it sees fit, without having to
  * avoid any code or data used by any SW CPU pin loop. The CPU hotplug
- * functionality embodied in disable_nonboot_cpus() to achieve this.
+ * functionality embodied in smp_shutdown_nonboot_cpus() to achieve this.
  */
 void machine_shutdown(void)
 {
-       disable_nonboot_cpus();
+       smp_shutdown_nonboot_cpus(reboot_cpu);
 }
 
 /*
index c89ac1b..e0330a2 100644 (file)
@@ -95,6 +95,8 @@ static bool __init cntvct_functional(void)
         */
        np = of_find_compatible_node(NULL, NULL, "arm,armv7-timer");
        if (!np)
+               np = of_find_compatible_node(NULL, NULL, "arm,armv8-timer");
+       if (!np)
                goto out_put;
 
        if (of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
index 95b2e1c..f8016e3 100644 (file)
@@ -118,7 +118,7 @@ ENTRY(arm_copy_from_user)
 
 ENDPROC(arm_copy_from_user)
 
-       .pushsection .fixup,"ax"
+       .pushsection .text.fixup,"ax"
        .align 0
        copy_abort_preamble
        ldmfd   sp!, {r1, r2, r3}
index 35ff620..03506ce 100644 (file)
@@ -91,6 +91,8 @@ AFLAGS_suspend-imx6.o :=-Wa,-march=armv7-a
 obj-$(CONFIG_SOC_IMX6) += suspend-imx6.o
 obj-$(CONFIG_SOC_IMX53) += suspend-imx53.o
 endif
+AFLAGS_resume-imx6.o :=-Wa,-march=armv7-a
+obj-$(CONFIG_SOC_IMX6) += resume-imx6.o
 obj-$(CONFIG_SOC_IMX6) += pm-imx6.o
 
 obj-$(CONFIG_SOC_IMX1) += mach-imx1.o
index 912aece..5aa5796 100644 (file)
@@ -109,17 +109,17 @@ void imx_cpu_die(unsigned int cpu);
 int imx_cpu_kill(unsigned int cpu);
 
 #ifdef CONFIG_SUSPEND
-void v7_cpu_resume(void);
 void imx53_suspend(void __iomem *ocram_vbase);
 extern const u32 imx53_suspend_sz;
 void imx6_suspend(void __iomem *ocram_vbase);
 #else
-static inline void v7_cpu_resume(void) {}
 static inline void imx53_suspend(void __iomem *ocram_vbase) {}
 static const u32 imx53_suspend_sz;
 static inline void imx6_suspend(void __iomem *ocram_vbase) {}
 #endif
 
+void v7_cpu_resume(void);
+
 void imx6_pm_ccm_init(const char *ccm_compat);
 void imx6q_pm_init(void);
 void imx6dl_pm_init(void);
diff --git a/arch/arm/mach-imx/resume-imx6.S b/arch/arm/mach-imx/resume-imx6.S
new file mode 100644 (file)
index 0000000..5bd1ba7
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
+#include "hardware.h"
+
+/*
+ * The following code must assume it is running from physical address
+ * where absolute virtual addresses to the data section have to be
+ * turned into relative ones.
+ */
+
+ENTRY(v7_cpu_resume)
+       bl      v7_invalidate_l1
+#ifdef CONFIG_CACHE_L2X0
+       bl      l2c310_early_resume
+#endif
+       b       cpu_resume
+ENDPROC(v7_cpu_resume)
index 062391f..1eabf2d 100644 (file)
@@ -327,17 +327,3 @@ resume:
 
        ret     lr
 ENDPROC(imx6_suspend)
-
-/*
- * The following code must assume it is running from physical address
- * where absolute virtual addresses to the data section have to be
- * turned into relative ones.
- */
-
-ENTRY(v7_cpu_resume)
-       bl      v7_invalidate_l1
-#ifdef CONFIG_CACHE_L2X0
-       bl      l2c310_early_resume
-#endif
-       b       cpu_resume
-ENDPROC(v7_cpu_resume)
index 01f0f4b..75034fe 100644 (file)
@@ -9,7 +9,6 @@ menuconfig ARCH_MESON
        select CACHE_L2X0
        select PINCTRL
        select PINCTRL_MESON
-       select COMMON_CLK
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
 
index e1135b9..5017a3b 100644 (file)
@@ -16,7 +16,7 @@ hwmod-common                          = omap_hwmod.o omap_hwmod_reset.o \
 clock-common                           = clock.o
 secure-common                          = omap-smc.o omap-secure.o
 
-obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) $(secure-common)
+obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
 obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common)
 obj-$(CONFIG_ARCH_OMAP4) += $(hwmod-common) $(secure-common)
 obj-$(CONFIG_SOC_AM33XX) += $(hwmod-common) $(secure-common)
index f280472..27608d1 100644 (file)
@@ -431,7 +431,6 @@ void __init omap2420_init_early(void)
        omap_hwmod_init_postsetup();
        omap_clk_soc_init = omap2420_dt_clk_init;
        rate_table = omap2420_rate_table;
-       omap_secure_init();
 }
 
 void __init omap2420_init_late(void)
@@ -456,7 +455,6 @@ void __init omap2430_init_early(void)
        omap_hwmod_init_postsetup();
        omap_clk_soc_init = omap2430_dt_clk_init;
        rate_table = omap2430_rate_table;
-       omap_secure_init();
 }
 
 void __init omap2430_init_late(void)
index 0b30e88..6e41c4b 100644 (file)
@@ -9,7 +9,6 @@ config ARM64
        select ACPI_MCFG if (ACPI && PCI)
        select ACPI_SPCR_TABLE if ACPI
        select ACPI_PPTT if ACPI
-       select ARCH_CLOCKSOURCE_DATA
        select ARCH_HAS_DEBUG_VIRTUAL
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_DMA_PREP_COHERENT
@@ -118,6 +117,7 @@ config ARM64
        select HAVE_ALIGNED_STRUCT_PAGE if SLUB
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_ARCH_BITREVERSE
+       select HAVE_ARCH_COMPILER_H
        select HAVE_ARCH_HUGE_VMAP
        select HAVE_ARCH_JUMP_LABEL
        select HAVE_ARCH_JUMP_LABEL_RELATIVE
@@ -281,6 +281,9 @@ config ZONE_DMA32
 config ARCH_ENABLE_MEMORY_HOTPLUG
        def_bool y
 
+config ARCH_ENABLE_MEMORY_HOTREMOVE
+       def_bool y
+
 config SMP
        def_bool y
 
@@ -952,11 +955,11 @@ config HOTPLUG_CPU
 
 # Common NUMA Features
 config NUMA
-       bool "Numa Memory Allocation and Scheduler Support"
+       bool "NUMA Memory Allocation and Scheduler Support"
        select ACPI_NUMA if ACPI
        select OF_NUMA
        help
-         Enable NUMA (Non Uniform Memory Access) support.
+         Enable NUMA (Non-Uniform Memory Access) support.
 
          The kernel will try to allocate memory used by a CPU on the
          local memory of the CPU and add some more
@@ -1498,6 +1501,9 @@ config ARM64_PTR_AUTH
        bool "Enable support for pointer authentication"
        default y
        depends on !KVM || ARM64_VHE
+       depends on (CC_HAS_SIGN_RETURN_ADDRESS || CC_HAS_BRANCH_PROT_PAC_RET) && AS_HAS_PAC
+       depends on CC_IS_GCC || (CC_IS_CLANG && AS_HAS_CFI_NEGATE_RA_STATE)
+       depends on (!FUNCTION_GRAPH_TRACER || DYNAMIC_FTRACE_WITH_REGS)
        help
          Pointer authentication (part of the ARMv8.3 Extensions) provides
          instructions for signing and authenticating pointers against secret
@@ -1505,16 +1511,72 @@ config ARM64_PTR_AUTH
          and other attacks.
 
          This option enables these instructions at EL0 (i.e. for userspace).
-
          Choosing this option will cause the kernel to initialise secret keys
          for each process at exec() time, with these keys being
          context-switched along with the process.
 
+         If the compiler supports the -mbranch-protection or
+         -msign-return-address flag (e.g. GCC 7 or later), then this option
+         will also cause the kernel itself to be compiled with return address
+         protection. In this case, and if the target hardware is known to
+         support pointer authentication, then CONFIG_STACKPROTECTOR can be
+         disabled with minimal loss of protection.
+
          The feature is detected at runtime. If the feature is not present in
          hardware it will not be advertised to userspace/KVM guest nor will it
          be enabled. However, KVM guest also require VHE mode and hence
          CONFIG_ARM64_VHE=y option to use this feature.
 
+         If the feature is present on the boot CPU but not on a late CPU, then
+         the late CPU will be parked. Also, if the boot CPU does not have
+         address auth and the late CPU has then the late CPU will still boot
+         but with the feature disabled. On such a system, this option should
+         not be selected.
+
+         This feature works with FUNCTION_GRAPH_TRACER option only if
+         DYNAMIC_FTRACE_WITH_REGS is enabled.
+
+config CC_HAS_BRANCH_PROT_PAC_RET
+       # GCC 9 or later, clang 8 or later
+       def_bool $(cc-option,-mbranch-protection=pac-ret+leaf)
+
+config CC_HAS_SIGN_RETURN_ADDRESS
+       # GCC 7, 8
+       def_bool $(cc-option,-msign-return-address=all)
+
+config AS_HAS_PAC
+       def_bool $(as-option,-Wa$(comma)-march=armv8.3-a)
+
+config AS_HAS_CFI_NEGATE_RA_STATE
+       def_bool $(as-instr,.cfi_startproc\n.cfi_negate_ra_state\n.cfi_endproc\n)
+
+endmenu
+
+menu "ARMv8.4 architectural features"
+
+config ARM64_AMU_EXTN
+       bool "Enable support for the Activity Monitors Unit CPU extension"
+       default y
+       help
+         The activity monitors extension is an optional extension introduced
+         by the ARMv8.4 CPU architecture. This enables support for version 1
+         of the activity monitors architecture, AMUv1.
+
+         To enable the use of this extension on CPUs that implement it, say Y.
+
+         Note that for architectural reasons, firmware _must_ implement AMU
+         support when running on CPUs that present the activity monitors
+         extension. The required support is present in:
+           * Version 1.5 and later of the ARM Trusted Firmware
+
+         For kernels that have this configuration enabled but boot with broken
+         firmware, you may need to say N here until the firmware is fixed.
+         Otherwise you may experience firmware panics or lockups when
+         accessing the counter registers. Even if you are not observing these
+         symptoms, the values returned by the register reads might not
+         correctly reflect reality. Most commonly, the value read will be 0,
+         indicating that the counter is not enabled.
+
 endmenu
 
 menu "ARMv8.5 architectural features"
index dca1a97..f15f92b 100644 (file)
@@ -65,6 +65,17 @@ stack_protector_prepare: prepare0
                                        include/generated/asm-offsets.h))
 endif
 
+ifeq ($(CONFIG_ARM64_PTR_AUTH),y)
+branch-prot-flags-$(CONFIG_CC_HAS_SIGN_RETURN_ADDRESS) := -msign-return-address=all
+branch-prot-flags-$(CONFIG_CC_HAS_BRANCH_PROT_PAC_RET) := -mbranch-protection=pac-ret+leaf
+# -march=armv8.3-a enables the non-nops instructions for PAC, to avoid the
+# compiler to generate them and consequently to break the single image contract
+# we pass it only to the assembler. This option is utilized only in case of non
+# integrated assemblers.
+branch-prot-flags-$(CONFIG_AS_HAS_PAC) += -Wa,-march=armv8.3-a
+KBUILD_CFLAGS += $(branch-prot-flags-y)
+endif
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
 KBUILD_CPPFLAGS        += -mbig-endian
 CHECKFLAGS     += -D__AARCH64EB__
index 2f1f829..6c9cc45 100644 (file)
@@ -76,3 +76,7 @@
                };
        };
 };
+
+&ir {
+       linux,rc-map-name = "rc-videostrong-kii-pro";
+};
index f82f25c..d5dc128 100644 (file)
        #size-cells = <0>;
 
        bus-width = <4>;
-       max-frequency = <50000000>;
+       max-frequency = <60000000>;
 
        non-removable;
        disable-wp;
index a8bb3fa..cb1b48f 100644 (file)
                compatible = "brcm,bcm43438-bt";
                interrupt-parent = <&gpio_intc>;
                interrupts = <95 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "host-wakeup";
                shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>;
                max-speed = <2000000>;
                clocks = <&wifi32k>;
index 0bf375e..55b71bb 100644 (file)
@@ -53,7 +53,7 @@
                 * PSCI node is not added default, U-boot will add missing
                 * parts if it determines to use PSCI.
                 */
-               entry-method = "arm,psci";
+               entry-method = "psci";
 
                CPU_PW20: cpu-pw20 {
                          compatible = "arm,idle-state";
index 6082ae0..d237162 100644 (file)
@@ -20,6 +20,8 @@
 };
 
 &fman0 {
+       fsl,erratum-a050385;
+
        /* these aliases provide the FMan ports mapping */
        enet0: ethernet@e0000 {
        };
index 4223a23..dde50c8 100644 (file)
 
        ethernet@e4000 {
                phy-handle = <&rgmii_phy1>;
-               phy-connection-type = "rgmii-txid";
+               phy-connection-type = "rgmii-id";
        };
 
        ethernet@e6000 {
                phy-handle = <&rgmii_phy2>;
-               phy-connection-type = "rgmii-txid";
+               phy-connection-type = "rgmii-id";
        };
 
        ethernet@e8000 {
index dbc23d6..d53ccc5 100644 (file)
 &fman0 {
        ethernet@e4000 {
                phy-handle = <&rgmii_phy1>;
-               phy-connection-type = "rgmii";
+               phy-connection-type = "rgmii-id";
        };
 
        ethernet@e6000 {
                phy-handle = <&rgmii_phy2>;
-               phy-connection-type = "rgmii";
+               phy-connection-type = "rgmii-id";
        };
 
        ethernet@e8000 {
index d3d26cc..13460a3 100644 (file)
                        compatible = "ethernet-phy-ieee802.3-c22";
                        reg = <0>;
                };
-
-               ethphy1: ethernet-phy@1 {
-                       compatible = "ethernet-phy-ieee802.3-c22";
-                       reg = <1>;
-               };
        };
 };
 
index e1d357e..d8c44d3 100644 (file)
                };
 
                gmac0: ethernet@ff800000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
                        reg = <0xff800000 0x2000>;
                        interrupts = <0 90 4>;
                        interrupt-names = "macirq";
                };
 
                gmac1: ethernet@ff802000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
                        reg = <0xff802000 0x2000>;
                        interrupts = <0 91 4>;
                        interrupt-names = "macirq";
                };
 
                gmac2: ethernet@ff804000 {
-                       compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+                       compatible = "altr,socfpga-stmmac-a10-s10", "snps,dwmac-3.74a", "snps,dwmac";
                        reg = <0xff804000 0x2000>;
                        interrupts = <0 92 4>;
                        interrupt-names = "macirq";
index cd80756..2c590ca 100644 (file)
        };
 
        idle-states {
-               entry-method = "arm,psci";
+               entry-method = "psci";
                CORE_PD: core-pd {
                        compatible = "arm,idle-state";
                        entry-latency-us = <4000>;
index 905109f..e757328 100644 (file)
@@ -62,6 +62,7 @@ CONFIG_ARCH_ZX=y
 CONFIG_ARCH_ZYNQMP=y
 CONFIG_ARM64_VA_BITS_48=y
 CONFIG_SCHED_MC=y
+CONFIG_SCHED_SMT=y
 CONFIG_NUMA=y
 CONFIG_SECCOMP=y
 CONFIG_KEXEC=y
@@ -773,7 +774,7 @@ CONFIG_ARCH_R8A774A1=y
 CONFIG_ARCH_R8A774B1=y
 CONFIG_ARCH_R8A774C0=y
 CONFIG_ARCH_R8A7795=y
-CONFIG_ARCH_R8A7796=y
+CONFIG_ARCH_R8A77960=y
 CONFIG_ARCH_R8A77961=y
 CONFIG_ARCH_R8A77965=y
 CONFIG_ARCH_R8A77970=y
index 4506255..1dc5bbb 100644 (file)
@@ -9,8 +9,8 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-#define AES_ENTRY(func)                SYM_FUNC_START(ce_ ## func)
-#define AES_ENDPROC(func)      SYM_FUNC_END(ce_ ## func)
+#define AES_FUNC_START(func)           SYM_FUNC_START(ce_ ## func)
+#define AES_FUNC_END(func)             SYM_FUNC_END(ce_ ## func)
 
        .arch           armv8-a+crypto
 
index 8a2faa4..cf618d8 100644 (file)
@@ -51,7 +51,7 @@ SYM_FUNC_END(aes_decrypt_block5x)
         *                 int blocks)
         */
 
-AES_ENTRY(aes_ecb_encrypt)
+AES_FUNC_START(aes_ecb_encrypt)
        stp             x29, x30, [sp, #-16]!
        mov             x29, sp
 
@@ -79,10 +79,10 @@ ST5(        st1             {v4.16b}, [x0], #16             )
 .Lecbencout:
        ldp             x29, x30, [sp], #16
        ret
-AES_ENDPROC(aes_ecb_encrypt)
+AES_FUNC_END(aes_ecb_encrypt)
 
 
-AES_ENTRY(aes_ecb_decrypt)
+AES_FUNC_START(aes_ecb_decrypt)
        stp             x29, x30, [sp, #-16]!
        mov             x29, sp
 
@@ -110,7 +110,7 @@ ST5(        st1             {v4.16b}, [x0], #16             )
 .Lecbdecout:
        ldp             x29, x30, [sp], #16
        ret
-AES_ENDPROC(aes_ecb_decrypt)
+AES_FUNC_END(aes_ecb_decrypt)
 
 
        /*
@@ -126,7 +126,7 @@ AES_ENDPROC(aes_ecb_decrypt)
         *                       u32 const rk2[]);
         */
 
-AES_ENTRY(aes_essiv_cbc_encrypt)
+AES_FUNC_START(aes_essiv_cbc_encrypt)
        ld1             {v4.16b}, [x5]                  /* get iv */
 
        mov             w8, #14                         /* AES-256: 14 rounds */
@@ -135,7 +135,7 @@ AES_ENTRY(aes_essiv_cbc_encrypt)
        enc_switch_key  w3, x2, x6
        b               .Lcbcencloop4x
 
-AES_ENTRY(aes_cbc_encrypt)
+AES_FUNC_START(aes_cbc_encrypt)
        ld1             {v4.16b}, [x5]                  /* get iv */
        enc_prepare     w3, x2, x6
 
@@ -167,10 +167,10 @@ AES_ENTRY(aes_cbc_encrypt)
 .Lcbcencout:
        st1             {v4.16b}, [x5]                  /* return iv */
        ret
-AES_ENDPROC(aes_cbc_encrypt)
-AES_ENDPROC(aes_essiv_cbc_encrypt)
+AES_FUNC_END(aes_cbc_encrypt)
+AES_FUNC_END(aes_essiv_cbc_encrypt)
 
-AES_ENTRY(aes_essiv_cbc_decrypt)
+AES_FUNC_START(aes_essiv_cbc_decrypt)
        stp             x29, x30, [sp, #-16]!
        mov             x29, sp
 
@@ -181,7 +181,7 @@ AES_ENTRY(aes_essiv_cbc_decrypt)
        encrypt_block   cbciv, w8, x6, x7, w9
        b               .Lessivcbcdecstart
 
-AES_ENTRY(aes_cbc_decrypt)
+AES_FUNC_START(aes_cbc_decrypt)
        stp             x29, x30, [sp, #-16]!
        mov             x29, sp
 
@@ -238,8 +238,8 @@ ST5(        st1             {v4.16b}, [x0], #16             )
        st1             {cbciv.16b}, [x5]               /* return iv */
        ldp             x29, x30, [sp], #16
        ret
-AES_ENDPROC(aes_cbc_decrypt)
-AES_ENDPROC(aes_essiv_cbc_decrypt)
+AES_FUNC_END(aes_cbc_decrypt)
+AES_FUNC_END(aes_essiv_cbc_decrypt)
 
 
        /*
@@ -249,7 +249,7 @@ AES_ENDPROC(aes_essiv_cbc_decrypt)
         *                     int rounds, int bytes, u8 const iv[])
         */
 
-AES_ENTRY(aes_cbc_cts_encrypt)
+AES_FUNC_START(aes_cbc_cts_encrypt)
        adr_l           x8, .Lcts_permute_table
        sub             x4, x4, #16
        add             x9, x8, #32
@@ -276,9 +276,9 @@ AES_ENTRY(aes_cbc_cts_encrypt)
        st1             {v0.16b}, [x4]                  /* overlapping stores */
        st1             {v1.16b}, [x0]
        ret
-AES_ENDPROC(aes_cbc_cts_encrypt)
+AES_FUNC_END(aes_cbc_cts_encrypt)
 
-AES_ENTRY(aes_cbc_cts_decrypt)
+AES_FUNC_START(aes_cbc_cts_decrypt)
        adr_l           x8, .Lcts_permute_table
        sub             x4, x4, #16
        add             x9, x8, #32
@@ -305,7 +305,7 @@ AES_ENTRY(aes_cbc_cts_decrypt)
        st1             {v2.16b}, [x4]                  /* overlapping stores */
        st1             {v0.16b}, [x0]
        ret
-AES_ENDPROC(aes_cbc_cts_decrypt)
+AES_FUNC_END(aes_cbc_cts_decrypt)
 
        .section        ".rodata", "a"
        .align          6
@@ -324,7 +324,7 @@ AES_ENDPROC(aes_cbc_cts_decrypt)
         *                 int blocks, u8 ctr[])
         */
 
-AES_ENTRY(aes_ctr_encrypt)
+AES_FUNC_START(aes_ctr_encrypt)
        stp             x29, x30, [sp, #-16]!
        mov             x29, sp
 
@@ -409,7 +409,7 @@ ST5(        st1             {v4.16b}, [x0], #16             )
        rev             x7, x7
        ins             vctr.d[0], x7
        b               .Lctrcarrydone
-AES_ENDPROC(aes_ctr_encrypt)
+AES_FUNC_END(aes_ctr_encrypt)
 
 
        /*
@@ -433,7 +433,7 @@ AES_ENDPROC(aes_ctr_encrypt)
        uzp1            xtsmask.4s, xtsmask.4s, \tmp\().4s
        .endm
 
-AES_ENTRY(aes_xts_encrypt)
+AES_FUNC_START(aes_xts_encrypt)
        stp             x29, x30, [sp, #-16]!
        mov             x29, sp
 
@@ -518,9 +518,9 @@ AES_ENTRY(aes_xts_encrypt)
        st1             {v2.16b}, [x4]                  /* overlapping stores */
        mov             w4, wzr
        b               .Lxtsencctsout
-AES_ENDPROC(aes_xts_encrypt)
+AES_FUNC_END(aes_xts_encrypt)
 
-AES_ENTRY(aes_xts_decrypt)
+AES_FUNC_START(aes_xts_decrypt)
        stp             x29, x30, [sp, #-16]!
        mov             x29, sp
 
@@ -612,13 +612,13 @@ AES_ENTRY(aes_xts_decrypt)
        st1             {v2.16b}, [x4]                  /* overlapping stores */
        mov             w4, wzr
        b               .Lxtsdecctsout
-AES_ENDPROC(aes_xts_decrypt)
+AES_FUNC_END(aes_xts_decrypt)
 
        /*
         * aes_mac_update(u8 const in[], u32 const rk[], int rounds,
         *                int blocks, u8 dg[], int enc_before, int enc_after)
         */
-AES_ENTRY(aes_mac_update)
+AES_FUNC_START(aes_mac_update)
        frame_push      6
 
        mov             x19, x0
@@ -676,4 +676,4 @@ AES_ENTRY(aes_mac_update)
        ld1             {v0.16b}, [x23]                 /* get dg */
        enc_prepare     w21, x20, x0
        b               .Lmacloop4x
-AES_ENDPROC(aes_mac_update)
+AES_FUNC_END(aes_mac_update)
index 247d34d..e47d3ec 100644 (file)
@@ -8,8 +8,8 @@
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 
-#define AES_ENTRY(func)                SYM_FUNC_START(neon_ ## func)
-#define AES_ENDPROC(func)      SYM_FUNC_END(neon_ ## func)
+#define AES_FUNC_START(func)           SYM_FUNC_START(neon_ ## func)
+#define AES_FUNC_END(func)             SYM_FUNC_END(neon_ ## func)
 
        xtsmask         .req    v7
        cbciv           .req    v7
index c1f9660..37ca3e8 100644 (file)
@@ -55,10 +55,10 @@ static void chacha_doneon(u32 *state, u8 *dst, const u8 *src,
                        break;
                }
                chacha_4block_xor_neon(state, dst, src, nrounds, l);
-               bytes -= CHACHA_BLOCK_SIZE * 5;
-               src += CHACHA_BLOCK_SIZE * 5;
-               dst += CHACHA_BLOCK_SIZE * 5;
-               state[12] += 5;
+               bytes -= l;
+               src += l;
+               dst += l;
+               state[12] += DIV_ROUND_UP(l, CHACHA_BLOCK_SIZE);
        }
 }
 
index 084c6a3..6b958dc 100644 (file)
@@ -587,20 +587,20 @@ CPU_LE(   rev             w8, w8          )
         *                        struct ghash_key const *k, u64 dg[], u8 ctr[],
         *                        int rounds, u8 tag)
         */
-ENTRY(pmull_gcm_encrypt)
+SYM_FUNC_START(pmull_gcm_encrypt)
        pmull_gcm_do_crypt      1
-ENDPROC(pmull_gcm_encrypt)
+SYM_FUNC_END(pmull_gcm_encrypt)
 
        /*
         * void pmull_gcm_decrypt(int blocks, u8 dst[], const u8 src[],
         *                        struct ghash_key const *k, u64 dg[], u8 ctr[],
         *                        int rounds, u8 tag)
         */
-ENTRY(pmull_gcm_decrypt)
+SYM_FUNC_START(pmull_gcm_decrypt)
        pmull_gcm_do_crypt      0
-ENDPROC(pmull_gcm_decrypt)
+SYM_FUNC_END(pmull_gcm_decrypt)
 
-pmull_gcm_ghash_4x:
+SYM_FUNC_START_LOCAL(pmull_gcm_ghash_4x)
        movi            MASK.16b, #0xe1
        shl             MASK.2d, MASK.2d, #57
 
@@ -681,9 +681,9 @@ pmull_gcm_ghash_4x:
        eor             XL.16b, XL.16b, T2.16b
 
        ret
-ENDPROC(pmull_gcm_ghash_4x)
+SYM_FUNC_END(pmull_gcm_ghash_4x)
 
-pmull_gcm_enc_4x:
+SYM_FUNC_START_LOCAL(pmull_gcm_enc_4x)
        ld1             {KS0.16b}, [x5]                 // load upper counter
        sub             w10, w8, #4
        sub             w11, w8, #3
@@ -746,7 +746,7 @@ pmull_gcm_enc_4x:
        eor             INP3.16b, INP3.16b, KS3.16b
 
        ret
-ENDPROC(pmull_gcm_enc_4x)
+SYM_FUNC_END(pmull_gcm_enc_4x)
 
        .section        ".rodata", "a"
        .align          6
index 324e7d5..5e5dc05 100644 (file)
@@ -221,7 +221,7 @@ alternative_endif
 
 .macro user_alt, label, oldinstr, newinstr, cond
 9999:  alternative_insn "\oldinstr", "\newinstr", \cond
-       _ASM_EXTABLE 9999b, \label
+       _asm_extable 9999b, \label
 .endm
 
 /*
index 25fec4b..a358e97 100644 (file)
@@ -32,7 +32,7 @@ static inline void gic_write_eoir(u32 irq)
        isb();
 }
 
-static inline void gic_write_dir(u32 irq)
+static __always_inline void gic_write_dir(u32 irq)
 {
        write_sysreg_s(irq, SYS_ICC_DIR_EL1);
        isb();
diff --git a/arch/arm64/include/asm/asm_pointer_auth.h b/arch/arm64/include/asm/asm_pointer_auth.h
new file mode 100644 (file)
index 0000000..ce2a848
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_ASM_POINTER_AUTH_H
+#define __ASM_ASM_POINTER_AUTH_H
+
+#include <asm/alternative.h>
+#include <asm/asm-offsets.h>
+#include <asm/cpufeature.h>
+#include <asm/sysreg.h>
+
+#ifdef CONFIG_ARM64_PTR_AUTH
+/*
+ * thread.keys_user.ap* as offset exceeds the #imm offset range
+ * so use the base value of ldp as thread.keys_user and offset as
+ * thread.keys_user.ap*.
+ */
+       .macro ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
+       mov     \tmp1, #THREAD_KEYS_USER
+       add     \tmp1, \tsk, \tmp1
+alternative_if_not ARM64_HAS_ADDRESS_AUTH
+       b       .Laddr_auth_skip_\@
+alternative_else_nop_endif
+       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIA]
+       msr_s   SYS_APIAKEYLO_EL1, \tmp2
+       msr_s   SYS_APIAKEYHI_EL1, \tmp3
+       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APIB]
+       msr_s   SYS_APIBKEYLO_EL1, \tmp2
+       msr_s   SYS_APIBKEYHI_EL1, \tmp3
+       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APDA]
+       msr_s   SYS_APDAKEYLO_EL1, \tmp2
+       msr_s   SYS_APDAKEYHI_EL1, \tmp3
+       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APDB]
+       msr_s   SYS_APDBKEYLO_EL1, \tmp2
+       msr_s   SYS_APDBKEYHI_EL1, \tmp3
+.Laddr_auth_skip_\@:
+alternative_if ARM64_HAS_GENERIC_AUTH
+       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APGA]
+       msr_s   SYS_APGAKEYLO_EL1, \tmp2
+       msr_s   SYS_APGAKEYHI_EL1, \tmp3
+alternative_else_nop_endif
+       .endm
+
+       .macro ptrauth_keys_install_kernel tsk, sync, tmp1, tmp2, tmp3
+alternative_if ARM64_HAS_ADDRESS_AUTH
+       mov     \tmp1, #THREAD_KEYS_KERNEL
+       add     \tmp1, \tsk, \tmp1
+       ldp     \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APIA]
+       msr_s   SYS_APIAKEYLO_EL1, \tmp2
+       msr_s   SYS_APIAKEYHI_EL1, \tmp3
+       .if     \sync == 1
+       isb
+       .endif
+alternative_else_nop_endif
+       .endm
+
+#else /* CONFIG_ARM64_PTR_AUTH */
+
+       .macro ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3
+       .endm
+
+       .macro ptrauth_keys_install_kernel tsk, sync, tmp1, tmp2, tmp3
+       .endm
+
+#endif /* CONFIG_ARM64_PTR_AUTH */
+
+#endif /* __ASM_ASM_POINTER_AUTH_H */
index aca337d..0bff325 100644 (file)
@@ -257,12 +257,6 @@ alternative_endif
        .endm
 
 /*
- * mmid - get context id from mm pointer (mm->context.id)
- */
-       .macro  mmid, rd, rn
-       ldr     \rd, [\rn, #MM_CONTEXT_ID]
-       .endm
-/*
  * read_ctr - read CTR_EL0. If the system has mismatched register fields,
  * provide the system wide safe value from arm64_ftr_reg_ctrel0.sys_val
  */
@@ -431,6 +425,16 @@ USER(\label, ic    ivau, \tmp2)                    // invalidate I line PoU
        .endm
 
 /*
+ * reset_amuserenr_el0 - reset AMUSERENR_EL0 if AMUv1 present
+ */
+       .macro  reset_amuserenr_el0, tmpreg
+       mrs     \tmpreg, id_aa64pfr0_el1        // Check ID_AA64PFR0_EL1
+       ubfx    \tmpreg, \tmpreg, #ID_AA64PFR0_AMU_SHIFT, #4
+       cbz     \tmpreg, .Lskip_\@              // Skip if no AMU present
+       msr_s   SYS_AMUSERENR_EL0, xzr          // Disable AMU access from EL0
+.Lskip_\@:
+       .endm
+/*
  * copy_page - copy src to dest using temp registers t1-t8
  */
        .macro copy_page dest:req src:req t1:req t2:req t3:req t4:req t5:req t6:req t7:req t8:req
index 806e9dc..a4d1b5f 100644 (file)
@@ -69,7 +69,7 @@ static inline int icache_is_aliasing(void)
        return test_bit(ICACHEF_ALIASING, &__icache_flags);
 }
 
-static inline int icache_is_vpipt(void)
+static __always_inline int icache_is_vpipt(void)
 {
        return test_bit(ICACHEF_VPIPT, &__icache_flags);
 }
index 665c78e..e6cca3d 100644 (file)
@@ -145,7 +145,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
-static inline void __flush_icache_all(void)
+static __always_inline void __flush_icache_all(void)
 {
        if (cpus_have_const_cap(ARM64_HAS_CACHE_DIC))
                return;
index 8d2a7de..b6f7bc6 100644 (file)
@@ -5,7 +5,12 @@
 #ifndef __ASM_CHECKSUM_H
 #define __ASM_CHECKSUM_H
 
-#include <linux/types.h>
+#include <linux/in6.h>
+
+#define _HAVE_ARCH_IPV6_CSUM
+__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+                       const struct in6_addr *daddr,
+                       __u32 len, __u8 proto, __wsum sum);
 
 static inline __sum16 csum_fold(__wsum csum)
 {
index 0ece64a..4821855 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef _ASM_CLOCKSOURCE_H
 #define _ASM_CLOCKSOURCE_H
 
-struct arch_clocksource_data {
-       bool vdso_direct;       /* Usable for direct VDSO access? */
-};
+#include <asm/vdso/clocksource.h>
 
 #endif
diff --git a/arch/arm64/include/asm/compiler.h b/arch/arm64/include/asm/compiler.h
new file mode 100644 (file)
index 0000000..eece20d
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_COMPILER_H
+#define __ASM_COMPILER_H
+
+#if defined(CONFIG_ARM64_PTR_AUTH)
+
+/*
+ * The EL0/EL1 pointer bits used by a pointer authentication code.
+ * This is dependent on TBI0/TBI1 being enabled, or bits 63:56 would also apply.
+ */
+#define ptrauth_user_pac_mask()                GENMASK_ULL(54, vabits_actual)
+#define ptrauth_kernel_pac_mask()      GENMASK_ULL(63, vabits_actual)
+
+/* Valid for EL0 TTBR0 and EL1 TTBR1 instruction pointers */
+#define ptrauth_clear_pac(ptr)                                         \
+       ((ptr & BIT_ULL(55)) ? (ptr | ptrauth_kernel_pac_mask()) :      \
+                              (ptr & ~ptrauth_user_pac_mask()))
+
+#define __builtin_return_address(val)                                  \
+       (void *)(ptrauth_clear_pac((unsigned long)__builtin_return_address(val)))
+
+#endif /* CONFIG_ARM64_PTR_AUTH */
+
+#endif /* __ASM_COMPILER_H */
index 86aabf1..d28e8f3 100644 (file)
@@ -55,12 +55,12 @@ struct cpu_operations {
 #endif
 };
 
-extern const struct cpu_operations *cpu_ops[NR_CPUS];
-int __init cpu_read_ops(int cpu);
+int __init init_cpu_ops(int cpu);
+extern const struct cpu_operations *get_cpu_ops(int cpu);
 
-static inline void __init cpu_read_bootcpu_ops(void)
+static inline void __init init_bootcpu_ops(void)
 {
-       cpu_read_ops(0);
+       init_cpu_ops(0);
 }
 
 #endif /* ifndef __ASM_CPU_OPS_H */
index 865e025..8eb5a08 100644 (file)
 #define ARM64_WORKAROUND_SPECULATIVE_AT_NVHE   48
 #define ARM64_HAS_E0PD                         49
 #define ARM64_HAS_RNG                          50
+#define ARM64_HAS_AMU_EXTN                     51
+#define ARM64_HAS_ADDRESS_AUTH                 52
+#define ARM64_HAS_GENERIC_AUTH                 53
 
-#define ARM64_NCAPS                            51
+#define ARM64_NCAPS                            54
 
 #endif /* __ASM_CPUCAPS_H */
index 92ef953..afe0825 100644 (file)
@@ -208,6 +208,10 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
  *     In some non-typical cases either both (a) and (b), or neither,
  *     should be permitted. This can be described by including neither
  *     or both flags in the capability's type field.
+ *
+ *     In case of a conflict, the CPU is prevented from booting. If the
+ *     ARM64_CPUCAP_PANIC_ON_CONFLICT flag is specified for the capability,
+ *     then a kernel panic is triggered.
  */
 
 
@@ -240,6 +244,8 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
 #define ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU    ((u16)BIT(4))
 /* Is it safe for a late CPU to miss this capability when system has it */
 #define ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU     ((u16)BIT(5))
+/* Panic when a conflict is detected */
+#define ARM64_CPUCAP_PANIC_ON_CONFLICT         ((u16)BIT(6))
 
 /*
  * CPU errata workarounds that need to be enabled at boot time if one or
@@ -279,9 +285,20 @@ extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
 
 /*
  * CPU feature used early in the boot based on the boot CPU. All secondary
- * CPUs must match the state of the capability as detected by the boot CPU.
+ * CPUs must match the state of the capability as detected by the boot CPU. In
+ * case of a conflict, a kernel panic is triggered.
+ */
+#define ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE           \
+       (ARM64_CPUCAP_SCOPE_BOOT_CPU | ARM64_CPUCAP_PANIC_ON_CONFLICT)
+
+/*
+ * CPU feature used early in the boot based on the boot CPU. It is safe for a
+ * late CPU to have this feature even though the boot CPU hasn't enabled it,
+ * although the feature will not be used by Linux in this case. If the boot CPU
+ * has enabled this feature already, then every late CPU must have it.
  */
-#define ARM64_CPUCAP_STRICT_BOOT_CPU_FEATURE ARM64_CPUCAP_SCOPE_BOOT_CPU
+#define ARM64_CPUCAP_BOOT_CPU_FEATURE                  \
+       (ARM64_CPUCAP_SCOPE_BOOT_CPU | ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU)
 
 struct arm64_cpu_capabilities {
        const char *desc;
@@ -340,18 +357,6 @@ static inline int cpucap_default_scope(const struct arm64_cpu_capabilities *cap)
        return cap->type & ARM64_CPUCAP_SCOPE_MASK;
 }
 
-static inline bool
-cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
-{
-       return !!(cap->type & ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU);
-}
-
-static inline bool
-cpucap_late_cpu_permitted(const struct arm64_cpu_capabilities *cap)
-{
-       return !!(cap->type & ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU);
-}
-
 /*
  * Generic helper for handling capabilties with multiple (match,enable) pairs
  * of call backs, sharing the same capability bit.
@@ -390,14 +395,16 @@ unsigned long cpu_get_elf_hwcap2(void);
 #define cpu_set_named_feature(name) cpu_set_feature(cpu_feature(name))
 #define cpu_have_named_feature(name) cpu_have_feature(cpu_feature(name))
 
-/* System capability check for constant caps */
-static __always_inline bool __cpus_have_const_cap(int num)
+static __always_inline bool system_capabilities_finalized(void)
 {
-       if (num >= ARM64_NCAPS)
-               return false;
-       return static_branch_unlikely(&cpu_hwcap_keys[num]);
+       return static_branch_likely(&arm64_const_caps_ready);
 }
 
+/*
+ * Test for a capability with a runtime check.
+ *
+ * Before the capability is detected, this returns false.
+ */
 static inline bool cpus_have_cap(unsigned int num)
 {
        if (num >= ARM64_NCAPS)
@@ -405,14 +412,53 @@ static inline bool cpus_have_cap(unsigned int num)
        return test_bit(num, cpu_hwcaps);
 }
 
+/*
+ * Test for a capability without a runtime check.
+ *
+ * Before capabilities are finalized, this returns false.
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
+static __always_inline bool __cpus_have_const_cap(int num)
+{
+       if (num >= ARM64_NCAPS)
+               return false;
+       return static_branch_unlikely(&cpu_hwcap_keys[num]);
+}
+
+/*
+ * Test for a capability, possibly with a runtime check.
+ *
+ * Before capabilities are finalized, this behaves as cpus_have_cap().
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
 static __always_inline bool cpus_have_const_cap(int num)
 {
-       if (static_branch_likely(&arm64_const_caps_ready))
+       if (system_capabilities_finalized())
                return __cpus_have_const_cap(num);
        else
                return cpus_have_cap(num);
 }
 
+/*
+ * Test for a capability without a runtime check.
+ *
+ * Before capabilities are finalized, this will BUG().
+ * After capabilities are finalized, this is patched to avoid a runtime check.
+ *
+ * @num must be a compile-time constant.
+ */
+static __always_inline bool cpus_have_final_cap(int num)
+{
+       if (system_capabilities_finalized())
+               return __cpus_have_const_cap(num);
+       else
+               BUG();
+}
+
 static inline void cpus_set_cap(unsigned int num)
 {
        if (num >= ARM64_NCAPS) {
@@ -435,18 +481,41 @@ cpuid_feature_extract_signed_field(u64 features, int field)
        return cpuid_feature_extract_signed_field_width(features, field, 4);
 }
 
-static inline unsigned int __attribute_const__
+static __always_inline unsigned int __attribute_const__
 cpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
 {
        return (u64)(features << (64 - width - field)) >> (64 - width);
 }
 
-static inline unsigned int __attribute_const__
+static __always_inline unsigned int __attribute_const__
 cpuid_feature_extract_unsigned_field(u64 features, int field)
 {
        return cpuid_feature_extract_unsigned_field_width(features, field, 4);
 }
 
+/*
+ * Fields that identify the version of the Performance Monitors Extension do
+ * not follow the standard ID scheme. See ARM DDI 0487E.a page D13-2825,
+ * "Alternative ID scheme used for the Performance Monitors Extension version".
+ */
+static inline u64 __attribute_const__
+cpuid_feature_cap_perfmon_field(u64 features, int field, u64 cap)
+{
+       u64 val = cpuid_feature_extract_unsigned_field(features, field);
+       u64 mask = GENMASK_ULL(field + 3, field);
+
+       /* Treat IMPLEMENTATION DEFINED functionality as unimplemented */
+       if (val == 0xf)
+               val = 0;
+
+       if (val > cap) {
+               features &= ~mask;
+               features |= (cap << field) & mask;
+       }
+
+       return features;
+}
+
 static inline u64 arm64_ftr_mask(const struct arm64_ftr_bits *ftrp)
 {
        return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
@@ -564,7 +633,7 @@ static inline bool system_supports_mixed_endian(void)
        return val == 0x1;
 }
 
-static inline bool system_supports_fpsimd(void)
+static __always_inline bool system_supports_fpsimd(void)
 {
        return !cpus_have_const_cap(ARM64_HAS_NO_FPSIMD);
 }
@@ -575,13 +644,13 @@ static inline bool system_uses_ttbr0_pan(void)
                !cpus_have_const_cap(ARM64_HAS_PAN);
 }
 
-static inline bool system_supports_sve(void)
+static __always_inline bool system_supports_sve(void)
 {
        return IS_ENABLED(CONFIG_ARM64_SVE) &&
                cpus_have_const_cap(ARM64_SVE);
 }
 
-static inline bool system_supports_cnp(void)
+static __always_inline bool system_supports_cnp(void)
 {
        return IS_ENABLED(CONFIG_ARM64_CNP) &&
                cpus_have_const_cap(ARM64_HAS_CNP);
@@ -590,15 +659,13 @@ static inline bool system_supports_cnp(void)
 static inline bool system_supports_address_auth(void)
 {
        return IS_ENABLED(CONFIG_ARM64_PTR_AUTH) &&
-               (cpus_have_const_cap(ARM64_HAS_ADDRESS_AUTH_ARCH) ||
-                cpus_have_const_cap(ARM64_HAS_ADDRESS_AUTH_IMP_DEF));
+               cpus_have_const_cap(ARM64_HAS_ADDRESS_AUTH);
 }
 
 static inline bool system_supports_generic_auth(void)
 {
        return IS_ENABLED(CONFIG_ARM64_PTR_AUTH) &&
-               (cpus_have_const_cap(ARM64_HAS_GENERIC_AUTH_ARCH) ||
-                cpus_have_const_cap(ARM64_HAS_GENERIC_AUTH_IMP_DEF));
+               cpus_have_const_cap(ARM64_HAS_GENERIC_AUTH);
 }
 
 static inline bool system_uses_irq_prio_masking(void)
@@ -613,11 +680,6 @@ static inline bool system_has_prio_mask_debugging(void)
               system_uses_irq_prio_masking();
 }
 
-static inline bool system_capabilities_finalized(void)
-{
-       return static_branch_likely(&arm64_const_caps_ready);
-}
-
 #define ARM64_BP_HARDEN_UNKNOWN                -1
 #define ARM64_BP_HARDEN_WA_NEEDED      0
 #define ARM64_BP_HARDEN_NOT_REQUIRED   1
@@ -678,6 +740,11 @@ static inline bool cpu_has_hw_af(void)
                                                ID_AA64MMFR1_HADBS_SHIFT);
 }
 
+#ifdef CONFIG_ARM64_AMU_EXTN
+/* Check whether the cpu supports the Activity Monitors Unit (AMU) */
+extern bool cpu_has_amu_feat(int cpu);
+#endif
+
 #endif /* __ASSEMBLY__ */
 
 #endif
index 44531a6..45e8212 100644 (file)
@@ -58,13 +58,6 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
 /* arch specific definitions used by the stub code */
 
 /*
- * AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
- * start of kernel and may not cross a 2MiB boundary. We set alignment to
- * 2MiB so we know it won't cross a 2MiB boundary.
- */
-#define EFI_FDT_ALIGN  SZ_2M   /* used by allocate_new_fdt_and_exit_boot() */
-
-/*
  * In some configurations (e.g. VMAP_STACK && 64K pages), stacks built into the
  * kernel need greater alignment than we require the segments to be padded to.
  */
@@ -107,9 +100,6 @@ static inline void free_screen_info(struct screen_info *si)
 {
 }
 
-/* redeclare as 'hidden' so the compiler will generate relative references */
-extern struct screen_info screen_info __attribute__((__visibility__("hidden")));
-
 static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
 {
 }
index cb29253..6a395a7 100644 (file)
@@ -60,7 +60,7 @@
 #define ESR_ELx_EC_BKPT32      (0x38)
 /* Unallocated EC: 0x39 */
 #define ESR_ELx_EC_VECTOR32    (0x3A)  /* EL2 only */
-/* Unallocted EC: 0x3B */
+/* Unallocated EC: 0x3B */
 #define ESR_ELx_EC_BRK64       (0x3C)
 /* Unallocated EC: 0x3D - 0x3F */
 #define ESR_ELx_EC_MAX         (0x3F)
index 6cc26a1..97f6a63 100644 (file)
@@ -48,7 +48,8 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
        int oldval = 0, ret, tmp;
        u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
 
-       pagefault_disable();
+       if (!access_ok(_uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -75,8 +76,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index 4e531f5..6facd13 100644 (file)
@@ -34,7 +34,7 @@ static inline void __raw_writew(u16 val, volatile void __iomem *addr)
 }
 
 #define __raw_writel __raw_writel
-static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
 {
        asm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr));
 }
@@ -69,7 +69,7 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
 }
 
 #define __raw_readl __raw_readl
-static inline u32 __raw_readl(const volatile void __iomem *addr)
+static __always_inline u32 __raw_readl(const volatile void __iomem *addr)
 {
        u32 val;
        asm volatile(ALTERNATIVE("ldr %w0, [%1]",
index 6e5d839..51c1d99 100644 (file)
 
 /* Hyp Coprocessor Trap Register */
 #define CPTR_EL2_TCPAC (1 << 31)
+#define CPTR_EL2_TAM   (1 << 30)
 #define CPTR_EL2_TTA   (1 << 20)
 #define CPTR_EL2_TFP   (1 << CPTR_EL2_TFP_SHIFT)
 #define CPTR_EL2_TZ    (1 << 8)
index 44a2437..7c7eeea 100644 (file)
@@ -36,6 +36,8 @@
  */
 #define KVM_VECTOR_PREAMBLE    (2 * AARCH64_INSN_SIZE)
 
+#define __SMCCC_WORKAROUND_1_SMC_SZ 36
+
 #ifndef __ASSEMBLY__
 
 #include <linux/mm.h>
@@ -75,6 +77,8 @@ extern void __vgic_v3_init_lrs(void);
 
 extern u32 __kvm_get_mdcr_el2(void);
 
+extern char __smccc_workaround_1_smc[__SMCCC_WORKAROUND_1_SMC_SZ];
+
 /* Home-grown __this_cpu_{ptr,read} variants that always work at HYP */
 #define __hyp_this_cpu_ptr(sym)                                                \
        ({                                                              \
index 688c634..f658dda 100644 (file)
@@ -36,7 +36,7 @@ void kvm_inject_undef32(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt32(struct kvm_vcpu *vcpu, unsigned long addr);
 
-static inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
+static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
 {
        return !(vcpu->arch.hcr_el2 & HCR_RW);
 }
@@ -127,7 +127,7 @@ static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
        vcpu->arch.vsesr_el2 = vsesr;
 }
 
-static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
 {
        return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
 }
@@ -153,17 +153,17 @@ static inline void vcpu_write_elr_el1(const struct kvm_vcpu *vcpu, unsigned long
                *__vcpu_elr_el1(vcpu) = v;
 }
 
-static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
 {
        return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
 }
 
-static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
+static __always_inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
 {
        return !!(*vcpu_cpsr(vcpu) & PSR_MODE32_BIT);
 }
 
-static inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
 {
        if (vcpu_mode_is_32bit(vcpu))
                return kvm_condition_valid32(vcpu);
@@ -181,13 +181,13 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
  * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
  * AArch32 with banked registers.
  */
-static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
+static __always_inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
                                         u8 reg_num)
 {
        return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num];
 }
 
-static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
+static __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
                                unsigned long val)
 {
        if (reg_num != 31)
@@ -264,12 +264,12 @@ static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
        return mode != PSR_MODE_EL0t;
 }
 
-static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
+static __always_inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.fault.esr_el2;
 }
 
-static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
 {
        u32 esr = kvm_vcpu_get_hsr(vcpu);
 
@@ -279,12 +279,12 @@ static inline int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
        return -1;
 }
 
-static inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.fault.far_el2;
 }
 
-static inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
+static __always_inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
 {
        return ((phys_addr_t)vcpu->arch.fault.hpfar_el2 & HPFAR_MASK) << 8;
 }
@@ -299,7 +299,7 @@ static inline u32 kvm_vcpu_hvc_get_imm(const struct kvm_vcpu *vcpu)
        return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_xVC_IMM_MASK;
 }
 
-static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_ISV);
 }
@@ -319,17 +319,17 @@ static inline bool kvm_vcpu_dabt_issf(const struct kvm_vcpu *vcpu)
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SF);
 }
 
-static inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
 {
        return (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SRT_MASK) >> ESR_ELx_SRT_SHIFT;
 }
 
-static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW);
 }
 
-static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WNR) ||
                kvm_vcpu_dabt_iss1tw(vcpu); /* AF/DBM update */
@@ -340,18 +340,18 @@ static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_CM);
 }
 
-static inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
+static __always_inline unsigned int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
 {
        return 1 << ((kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);
 }
 
 /* This one is not specific to Data Abort */
-static inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
 {
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_IL);
 }
 
-static inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
 {
        return ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu));
 }
@@ -361,17 +361,17 @@ static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
        return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
 }
 
-static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
 {
        return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC;
 }
 
-static inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
+static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
 {
        return kvm_vcpu_get_hsr(vcpu) & ESR_ELx_FSC_TYPE;
 }
 
-static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
+static __always_inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
 {
        switch (kvm_vcpu_trap_get_fault(vcpu)) {
        case FSC_SEA:
@@ -390,7 +390,7 @@ static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
        }
 }
 
-static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
+static __always_inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 {
        u32 esr = kvm_vcpu_get_hsr(vcpu);
        return ESR_ELx_SYS64_ISS_RT(esr);
@@ -504,7 +504,7 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu,
        return data;            /* Leave LE untouched */
 }
 
-static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
+static __always_inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
 {
        if (vcpu_mode_is_32bit(vcpu))
                kvm_skip_instr32(vcpu, is_wide_instr);
@@ -519,7 +519,7 @@ static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
  * Skip an instruction which has been emulated at hyp while most guest sysregs
  * are live.
  */
-static inline void __hyp_text __kvm_skip_instr(struct kvm_vcpu *vcpu)
+static __always_inline void __hyp_text __kvm_skip_instr(struct kvm_vcpu *vcpu)
 {
        *vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR);
        vcpu->arch.ctxt.gp_regs.regs.pstate = read_sysreg_el2(SYS_SPSR);
index d87aa60..57fd46a 100644 (file)
@@ -626,38 +626,6 @@ static inline void kvm_set_pmu_events(u32 set, struct perf_event_attr *attr) {}
 static inline void kvm_clr_pmu_events(u32 clr) {}
 #endif
 
-static inline void kvm_arm_vhe_guest_enter(void)
-{
-       local_daif_mask();
-
-       /*
-        * Having IRQs masked via PMR when entering the guest means the GIC
-        * will not signal the CPU of interrupts of lower priority, and the
-        * only way to get out will be via guest exceptions.
-        * Naturally, we want to avoid this.
-        *
-        * local_daif_mask() already sets GIC_PRIO_PSR_I_SET, we just need a
-        * dsb to ensure the redistributor is forwards EL2 IRQs to the CPU.
-        */
-       pmr_sync();
-}
-
-static inline void kvm_arm_vhe_guest_exit(void)
-{
-       /*
-        * local_daif_restore() takes care to properly restore PSTATE.DAIF
-        * and the GIC PMR if the host is using IRQ priorities.
-        */
-       local_daif_restore(DAIF_PROCCTX_NOIRQ);
-
-       /*
-        * When we exit from the guest we change a number of CPU configuration
-        * parameters, such as traps.  Make sure these changes take effect
-        * before running the host or additional guests.
-        */
-       isb();
-}
-
 #define KVM_BP_HARDEN_UNKNOWN          -1
 #define KVM_BP_HARDEN_WA_NEEDED                0
 #define KVM_BP_HARDEN_NOT_REQUIRED     1
index a3a6a2b..fe57f60 100644 (file)
 #define read_sysreg_el2(r)     read_sysreg_elx(r, _EL2, _EL1)
 #define write_sysreg_el2(v,r)  write_sysreg_elx(v, r, _EL2, _EL1)
 
+/*
+ * Without an __arch_swab32(), we fall back to ___constant_swab32(), but the
+ * static inline can allow the compiler to out-of-line this. KVM always wants
+ * the macro version as its always inlined.
+ */
+#define __kvm_swab32(x)        ___constant_swab32(x)
+
 int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
index 53d846f..30b0e8d 100644 (file)
@@ -93,7 +93,7 @@ void kvm_update_va_mask(struct alt_instr *alt,
                        __le32 *origptr, __le32 *updptr, int nr_inst);
 void kvm_compute_layout(void);
 
-static inline unsigned long __kern_hyp_va(unsigned long v)
+static __always_inline unsigned long __kern_hyp_va(unsigned long v)
 {
        asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n"
                                    "ror %0, %0, #1\n"
@@ -473,6 +473,7 @@ static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa,
 extern void *__kvm_bp_vect_base;
 extern int __kvm_harden_el2_vector_slot;
 
+/*  This is only called on a VHE system */
 static inline void *kvm_get_hyp_vector(void)
 {
        struct bp_hardening_data *data = arm64_get_bp_hardening_data();
@@ -480,7 +481,7 @@ static inline void *kvm_get_hyp_vector(void)
        int slot = -1;
 
        if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR) && data->fn) {
-               vect = kern_hyp_va(kvm_ksym_ref(__bp_harden_hyp_vecs_start));
+               vect = kern_hyp_va(kvm_ksym_ref(__bp_harden_hyp_vecs));
                slot = data->hyp_vectors_slot;
        }
 
@@ -509,14 +510,13 @@ static inline int kvm_map_vectors(void)
         *  HBP +  HEL2 -> use hardened vertors and use exec mapping
         */
        if (cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR)) {
-               __kvm_bp_vect_base = kvm_ksym_ref(__bp_harden_hyp_vecs_start);
+               __kvm_bp_vect_base = kvm_ksym_ref(__bp_harden_hyp_vecs);
                __kvm_bp_vect_base = kern_hyp_va(__kvm_bp_vect_base);
        }
 
        if (cpus_have_const_cap(ARM64_HARDEN_EL2_VECTORS)) {
-               phys_addr_t vect_pa = __pa_symbol(__bp_harden_hyp_vecs_start);
-               unsigned long size = (__bp_harden_hyp_vecs_end -
-                                     __bp_harden_hyp_vecs_start);
+               phys_addr_t vect_pa = __pa_symbol(__bp_harden_hyp_vecs);
+               unsigned long size = __BP_HARDEN_HYP_VECS_SZ;
 
                /*
                 * Always allocate a spare vector slot, as we don't
index 4d94676..2be67b2 100644 (file)
@@ -54,6 +54,7 @@
 #define MODULES_VADDR          (BPF_JIT_REGION_END)
 #define MODULES_VSIZE          (SZ_128M)
 #define VMEMMAP_START          (-VMEMMAP_SIZE - SZ_2M)
+#define VMEMMAP_END            (VMEMMAP_START + VMEMMAP_SIZE)
 #define PCI_IO_END             (VMEMMAP_START - SZ_2M)
 #define PCI_IO_START           (PCI_IO_END - PCI_IO_SIZE)
 #define FIXADDR_TOP            (PCI_IO_START - SZ_2M)
index e4d8624..68140fd 100644 (file)
@@ -13,6 +13,7 @@
 #define TTBR_ASID_MASK (UL(0xffff) << 48)
 
 #define BP_HARDEN_EL2_SLOTS 4
+#define __BP_HARDEN_HYP_VECS_SZ (BP_HARDEN_EL2_SLOTS * SZ_2K)
 
 #ifndef __ASSEMBLY__
 
@@ -23,17 +24,15 @@ typedef struct {
 } mm_context_t;
 
 /*
- * This macro is only used by the TLBI code, which cannot race with an
- * ASID change and therefore doesn't need to reload the counter using
- * atomic64_read.
+ * This macro is only used by the TLBI and low-level switch_mm() code,
+ * neither of which can race with an ASID change. We therefore don't
+ * need to reload the counter using atomic64_read().
  */
 #define ASID(mm)       ((mm)->context.id.counter & 0xffff)
 
-extern bool arm64_use_ng_mappings;
-
 static inline bool arm64_kernel_unmapped_at_el0(void)
 {
-       return arm64_use_ng_mappings;
+       return cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0);
 }
 
 typedef void (*bp_hardening_cb_t)(void);
@@ -45,7 +44,8 @@ struct bp_hardening_data {
 
 #if (defined(CONFIG_HARDEN_BRANCH_PREDICTOR) ||        \
      defined(CONFIG_HARDEN_EL2_VECTORS))
-extern char __bp_harden_hyp_vecs_start[], __bp_harden_hyp_vecs_end[];
+
+extern char __bp_harden_hyp_vecs[];
 extern atomic_t arm64_el2_vector_last_slot;
 #endif  /* CONFIG_HARDEN_BRANCH_PREDICTOR || CONFIG_HARDEN_EL2_VECTORS */
 
index 3827ff4..ab46187 100644 (file)
@@ -46,6 +46,8 @@ static inline void cpu_set_reserved_ttbr0(void)
        isb();
 }
 
+void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
+
 static inline void cpu_switch_mm(pgd_t *pgd, struct mm_struct *mm)
 {
        BUG_ON(pgd == swapper_pg_dir);
index d39ddb2..75d6cd2 100644 (file)
@@ -21,6 +21,10 @@ extern void __cpu_copy_user_page(void *to, const void *from,
 extern void copy_page(void *to, const void *from);
 extern void clear_page(void *to);
 
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+       alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+
 #define clear_user_page(addr,vaddr,pg)  __cpu_clear_user_page(addr, vaddr)
 #define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr)
 
index 2bdbc79..e7765b6 100644 (file)
 #define ARMV8_PMU_PMCR_X       (1 << 4) /* Export to ETM */
 #define ARMV8_PMU_PMCR_DP      (1 << 5) /* Disable CCNT if non-invasive debug*/
 #define ARMV8_PMU_PMCR_LC      (1 << 6) /* Overflow on 64 bit cycle counter */
+#define ARMV8_PMU_PMCR_LP      (1 << 7) /* Long event counter enable */
 #define        ARMV8_PMU_PMCR_N_SHIFT  11       /* Number of counters supported */
 #define        ARMV8_PMU_PMCR_N_MASK   0x1f
-#define        ARMV8_PMU_PMCR_MASK     0x7f     /* Mask for writable bits */
+#define        ARMV8_PMU_PMCR_MASK     0xff     /* Mask for writable bits */
 
 /*
  * PMOVSR: counters overflow flag status reg
index 6f87839..1305e28 100644 (file)
 
 #include <asm/pgtable-types.h>
 
+extern bool arm64_use_ng_mappings;
+
 #define _PROT_DEFAULT          (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
 #define _PROT_SECT_DEFAULT     (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
 
-#define PTE_MAYBE_NG           (arm64_kernel_unmapped_at_el0() ? PTE_NG : 0)
-#define PMD_MAYBE_NG           (arm64_kernel_unmapped_at_el0() ? PMD_SECT_NG : 0)
+#define PTE_MAYBE_NG           (arm64_use_ng_mappings ? PTE_NG : 0)
+#define PMD_MAYBE_NG           (arm64_use_ng_mappings ? PMD_SECT_NG : 0)
 
 #define PROT_DEFAULT           (_PROT_DEFAULT | PTE_MAYBE_NG)
 #define PROT_SECT_DEFAULT      (_PROT_SECT_DEFAULT | PMD_MAYBE_NG)
index 7a24bad..70c4715 100644 (file)
@@ -22,7 +22,7 @@ struct ptrauth_key {
  * We give each process its own keys, which are shared by all threads. The keys
  * are inherited upon fork(), and reinitialised upon exec*().
  */
-struct ptrauth_keys {
+struct ptrauth_keys_user {
        struct ptrauth_key apia;
        struct ptrauth_key apib;
        struct ptrauth_key apda;
@@ -30,7 +30,11 @@ struct ptrauth_keys {
        struct ptrauth_key apga;
 };
 
-static inline void ptrauth_keys_init(struct ptrauth_keys *keys)
+struct ptrauth_keys_kernel {
+       struct ptrauth_key apia;
+};
+
+static inline void ptrauth_keys_init_user(struct ptrauth_keys_user *keys)
 {
        if (system_supports_address_auth()) {
                get_random_bytes(&keys->apia, sizeof(keys->apia));
@@ -50,48 +54,38 @@ do {                                                                \
        write_sysreg_s(__pki_v.hi, SYS_ ## k ## KEYHI_EL1);     \
 } while (0)
 
-static inline void ptrauth_keys_switch(struct ptrauth_keys *keys)
+static __always_inline void ptrauth_keys_init_kernel(struct ptrauth_keys_kernel *keys)
 {
-       if (system_supports_address_auth()) {
-               __ptrauth_key_install(APIA, keys->apia);
-               __ptrauth_key_install(APIB, keys->apib);
-               __ptrauth_key_install(APDA, keys->apda);
-               __ptrauth_key_install(APDB, keys->apdb);
-       }
+       if (system_supports_address_auth())
+               get_random_bytes(&keys->apia, sizeof(keys->apia));
+}
 
-       if (system_supports_generic_auth())
-               __ptrauth_key_install(APGA, keys->apga);
+static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kernel *keys)
+{
+       if (system_supports_address_auth())
+               __ptrauth_key_install(APIA, keys->apia);
 }
 
 extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);
 
-/*
- * The EL0 pointer bits used by a pointer authentication code.
- * This is dependent on TBI0 being enabled, or bits 63:56 would also apply.
- */
-#define ptrauth_user_pac_mask()        GENMASK(54, vabits_actual)
-
-/* Only valid for EL0 TTBR0 instruction pointers */
 static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr)
 {
-       return ptr & ~ptrauth_user_pac_mask();
+       return ptrauth_clear_pac(ptr);
 }
 
 #define ptrauth_thread_init_user(tsk)                                  \
-do {                                                                   \
-       struct task_struct *__ptiu_tsk = (tsk);                         \
-       ptrauth_keys_init(&__ptiu_tsk->thread.keys_user);               \
-       ptrauth_keys_switch(&__ptiu_tsk->thread.keys_user);             \
-} while (0)
-
-#define ptrauth_thread_switch(tsk)     \
-       ptrauth_keys_switch(&(tsk)->thread.keys_user)
+       ptrauth_keys_init_user(&(tsk)->thread.keys_user)
+#define ptrauth_thread_init_kernel(tsk)                                        \
+       ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel)
+#define ptrauth_thread_switch_kernel(tsk)                              \
+       ptrauth_keys_switch_kernel(&(tsk)->thread.keys_kernel)
 
 #else /* CONFIG_ARM64_PTR_AUTH */
 #define ptrauth_prctl_reset_keys(tsk, arg)     (-EINVAL)
 #define ptrauth_strip_insn_pac(lr)     (lr)
 #define ptrauth_thread_init_user(tsk)
-#define ptrauth_thread_switch(tsk)
+#define ptrauth_thread_init_kernel(tsk)
+#define ptrauth_thread_switch_kernel(tsk)
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
 #endif /* __ASM_POINTER_AUTH_H */
index a2ce65a..0d5d1f0 100644 (file)
 
 #include <asm/page.h>
 
-struct mm_struct;
 struct cpu_suspend_ctx;
 
 extern void cpu_do_idle(void);
-extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
 extern void cpu_do_suspend(struct cpu_suspend_ctx *ptr);
 extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr);
 
index 5ba6320..240fe5e 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/string.h>
 #include <linux/thread_info.h>
 
+#include <vdso/processor.h>
+
 #include <asm/alternative.h>
 #include <asm/cpufeature.h>
 #include <asm/hw_breakpoint.h>
@@ -146,7 +148,8 @@ struct thread_struct {
        unsigned long           fault_code;     /* ESR_EL1 value */
        struct debug_info       debug;          /* debugging */
 #ifdef CONFIG_ARM64_PTR_AUTH
-       struct ptrauth_keys     keys_user;
+       struct ptrauth_keys_user        keys_user;
+       struct ptrauth_keys_kernel      keys_kernel;
 #endif
 };
 
@@ -256,11 +259,6 @@ extern void release_thread(struct task_struct *);
 
 unsigned long get_wchan(struct task_struct *p);
 
-static inline void cpu_relax(void)
-{
-       asm volatile("yield" ::: "memory");
-}
-
 /* Thread switching */
 extern struct task_struct *cpu_switch_to(struct task_struct *prev,
                                         struct task_struct *next);
index a0c8a0b..40d5ba0 100644 (file)
 #define CPU_STUCK_REASON_52_BIT_VA     (UL(1) << CPU_STUCK_REASON_SHIFT)
 #define CPU_STUCK_REASON_NO_GRAN       (UL(2) << CPU_STUCK_REASON_SHIFT)
 
+/* Possible options for __cpu_setup */
+/* Option to setup primary cpu */
+#define ARM64_CPU_BOOT_PRIMARY         (1)
+/* Option to setup secondary cpus */
+#define ARM64_CPU_BOOT_SECONDARY       (2)
+/* Option to setup cpus for different cpu run time services */
+#define ARM64_CPU_RUNTIME              (3)
+
 #ifndef __ASSEMBLY__
 
 #include <asm/percpu.h>
@@ -30,6 +38,7 @@
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/thread_info.h>
+#include <asm/pointer_auth.h>
 
 DECLARE_PER_CPU_READ_MOSTLY(int, cpu_number);
 
@@ -87,6 +96,9 @@ asmlinkage void secondary_start_kernel(void);
 struct secondary_data {
        void *stack;
        struct task_struct *task;
+#ifdef CONFIG_ARM64_PTR_AUTH
+       struct ptrauth_keys_kernel ptrauth_key;
+#endif
        long status;
 };
 
index 5884a2b..7263e0b 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/random.h>
 #include <linux/version.h>
+#include <asm/pointer_auth.h>
 
 extern unsigned long __stack_chk_guard;
 
@@ -26,6 +27,7 @@ extern unsigned long __stack_chk_guard;
  */
 static __always_inline void boot_init_stack_canary(void)
 {
+#if defined(CONFIG_STACKPROTECTOR)
        unsigned long canary;
 
        /* Try to get a semi random initial value. */
@@ -36,6 +38,9 @@ static __always_inline void boot_init_stack_canary(void)
        current->stack_canary = canary;
        if (!IS_ENABLED(CONFIG_STACKPROTECTOR_PER_TASK))
                __stack_chk_guard = current->stack_canary;
+#endif
+       ptrauth_thread_init_kernel(current);
+       ptrauth_thread_switch_kernel(current);
 }
 
 #endif /* _ASM_STACKPROTECTOR_H */
index b91570f..ebc6224 100644 (file)
 #define SYS_TPIDR_EL0                  sys_reg(3, 3, 13, 0, 2)
 #define SYS_TPIDRRO_EL0                        sys_reg(3, 3, 13, 0, 3)
 
+/* Definitions for system register interface to AMU for ARMv8.4 onwards */
+#define SYS_AM_EL0(crm, op2)           sys_reg(3, 3, 13, (crm), (op2))
+#define SYS_AMCR_EL0                   SYS_AM_EL0(2, 0)
+#define SYS_AMCFGR_EL0                 SYS_AM_EL0(2, 1)
+#define SYS_AMCGCR_EL0                 SYS_AM_EL0(2, 2)
+#define SYS_AMUSERENR_EL0              SYS_AM_EL0(2, 3)
+#define SYS_AMCNTENCLR0_EL0            SYS_AM_EL0(2, 4)
+#define SYS_AMCNTENSET0_EL0            SYS_AM_EL0(2, 5)
+#define SYS_AMCNTENCLR1_EL0            SYS_AM_EL0(3, 0)
+#define SYS_AMCNTENSET1_EL0            SYS_AM_EL0(3, 1)
+
+/*
+ * Group 0 of activity monitors (architected):
+ *                op0  op1  CRn   CRm       op2
+ * Counter:       11   011  1101  010:n<3>  n<2:0>
+ * Type:          11   011  1101  011:n<3>  n<2:0>
+ * n: 0-15
+ *
+ * Group 1 of activity monitors (auxiliary):
+ *                op0  op1  CRn   CRm       op2
+ * Counter:       11   011  1101  110:n<3>  n<2:0>
+ * Type:          11   011  1101  111:n<3>  n<2:0>
+ * n: 0-15
+ */
+
+#define SYS_AMEVCNTR0_EL0(n)           SYS_AM_EL0(4 + ((n) >> 3), (n) & 7)
+#define SYS_AMEVTYPE0_EL0(n)           SYS_AM_EL0(6 + ((n) >> 3), (n) & 7)
+#define SYS_AMEVCNTR1_EL0(n)           SYS_AM_EL0(12 + ((n) >> 3), (n) & 7)
+#define SYS_AMEVTYPE1_EL0(n)           SYS_AM_EL0(14 + ((n) >> 3), (n) & 7)
+
+/* AMU v1: Fixed (architecturally defined) activity monitors */
+#define SYS_AMEVCNTR0_CORE_EL0         SYS_AMEVCNTR0_EL0(0)
+#define SYS_AMEVCNTR0_CONST_EL0                SYS_AMEVCNTR0_EL0(1)
+#define SYS_AMEVCNTR0_INST_RET_EL0     SYS_AMEVCNTR0_EL0(2)
+#define SYS_AMEVCNTR0_MEM_STALL                SYS_AMEVCNTR0_EL0(3)
+
 #define SYS_CNTFRQ_EL0                 sys_reg(3, 3, 14, 0, 0)
 
 #define SYS_CNTP_TVAL_EL0              sys_reg(3, 3, 14, 2, 0)
 #define ID_AA64PFR0_CSV3_SHIFT         60
 #define ID_AA64PFR0_CSV2_SHIFT         56
 #define ID_AA64PFR0_DIT_SHIFT          48
+#define ID_AA64PFR0_AMU_SHIFT          44
 #define ID_AA64PFR0_SVE_SHIFT          32
 #define ID_AA64PFR0_RAS_SHIFT          28
 #define ID_AA64PFR0_GIC_SHIFT          24
 #define ID_AA64PFR0_EL1_SHIFT          4
 #define ID_AA64PFR0_EL0_SHIFT          0
 
+#define ID_AA64PFR0_AMU                        0x1
 #define ID_AA64PFR0_SVE                        0x1
 #define ID_AA64PFR0_RAS_V1             0x1
 #define ID_AA64PFR0_FP_NI              0xf
 #define ID_AA64DFR0_TRACEVER_SHIFT     4
 #define ID_AA64DFR0_DEBUGVER_SHIFT     0
 
+#define ID_AA64DFR0_PMUVER_8_0         0x1
+#define ID_AA64DFR0_PMUVER_8_1         0x4
+#define ID_AA64DFR0_PMUVER_8_4         0x5
+#define ID_AA64DFR0_PMUVER_8_5         0x6
+#define ID_AA64DFR0_PMUVER_IMP_DEF     0xf
+
+#define ID_DFR0_PERFMON_SHIFT          24
+
+#define ID_DFR0_PERFMON_8_1            0x4
+
 #define ID_ISAR5_RDM_SHIFT             24
 #define ID_ISAR5_CRC32_SHIFT           16
 #define ID_ISAR5_SHA2_SHIFT            12
index f0cec41..512174a 100644 (file)
@@ -63,7 +63,6 @@ void arch_release_task_struct(struct task_struct *tsk);
 #define TIF_FOREIGN_FPSTATE    3       /* CPU's FP state is not current's */
 #define TIF_UPROBE             4       /* uprobe breakpoint or singlestep */
 #define TIF_FSCHECK            5       /* Check FS is USER_DS on return */
-#define TIF_NOHZ               7
 #define TIF_SYSCALL_TRACE      8       /* syscall trace active */
 #define TIF_SYSCALL_AUDIT      9       /* syscall auditing */
 #define TIF_SYSCALL_TRACEPOINT 10      /* syscall tracepoint for ftrace */
@@ -83,7 +82,6 @@ void arch_release_task_struct(struct task_struct *tsk);
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_FOREIGN_FPSTATE   (1 << TIF_FOREIGN_FPSTATE)
-#define _TIF_NOHZ              (1 << TIF_NOHZ)
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SYSCALL_TRACEPOINT        (1 << TIF_SYSCALL_TRACEPOINT)
@@ -100,7 +98,7 @@ void arch_release_task_struct(struct task_struct *tsk);
 
 #define _TIF_SYSCALL_WORK      (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
                                 _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \
-                                _TIF_NOHZ | _TIF_SYSCALL_EMU)
+                                _TIF_SYSCALL_EMU)
 
 #define INIT_THREAD_INFO(tsk)                                          \
 {                                                                      \
index a4d945d..0cc835d 100644 (file)
@@ -16,6 +16,15 @@ int pcibus_to_node(struct pci_bus *bus);
 
 #include <linux/arch_topology.h>
 
+#ifdef CONFIG_ARM64_AMU_EXTN
+/*
+ * Replace task scheduler's default counter-based
+ * frequency-invariance scale factor setting.
+ */
+void topology_scale_freq_tick(void);
+#define arch_scale_freq_tick topology_scale_freq_tick
+#endif /* CONFIG_ARM64_AMU_EXTN */
+
 /* Replace task scheduler's default frequency-invariant accounting */
 #define arch_scale_freq_capacity topology_get_freq_scale
 
@@ -25,6 +34,9 @@ int pcibus_to_node(struct pci_bus *bus);
 /* Enable topology flag updates */
 #define arch_update_cpu_topology topology_update_cpu_topology
 
+/* Replace task scheduler's default thermal pressure retrieve API */
+#define arch_scale_thermal_pressure topology_get_thermal_pressure
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_ARM_TOPOLOGY_H */
index 1dd22da..803039d 100644 (file)
@@ -25,8 +25,8 @@
 #define __NR_compat_gettimeofday       78
 #define __NR_compat_sigreturn          119
 #define __NR_compat_rt_sigreturn       173
-#define __NR_compat_clock_getres       247
 #define __NR_compat_clock_gettime      263
+#define __NR_compat_clock_getres       264
 #define __NR_compat_clock_gettime64    403
 #define __NR_compat_clock_getres_time64        406
 
diff --git a/arch/arm64/include/asm/vdso/clocksource.h b/arch/arm64/include/asm/vdso/clocksource.h
new file mode 100644 (file)
index 0000000..df6ea65
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_VDSOCLOCKSOURCE_H
+#define __ASM_VDSOCLOCKSOURCE_H
+
+#define VDSO_ARCH_CLOCKMODES   \
+       VDSO_CLOCKMODE_ARCHTIMER
+
+#endif
index 537b1e6..b6907ae 100644 (file)
@@ -8,12 +8,10 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/unistd.h>
-#include <uapi/linux/time.h>
+#include <asm/errno.h>
 
 #include <asm/vdso/compat_barrier.h>
 
-#define __VDSO_USE_SYSCALL             ULLONG_MAX
-
 #define VDSO_HAS_CLOCK_GETRES          1
 
 #define BUILD_VDSO32                   1
@@ -78,10 +76,6 @@ int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
        register long ret asm ("r0");
        register long nr asm("r7") = __NR_compat_clock_getres_time64;
 
-       /* The checks below are required for ABI consistency with arm */
-       if ((_clkid >= MAX_CLOCKS) && (_ts == NULL))
-               return -EINVAL;
-
        asm volatile(
        "       swi #0\n"
        : "=r" (ret)
@@ -99,10 +93,6 @@ int clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
        register long ret asm ("r0");
        register long nr asm("r7") = __NR_compat_clock_getres;
 
-       /* The checks below are required for ABI consistency with arm */
-       if ((_clkid >= MAX_CLOCKS) && (_ts == NULL))
-               return -EINVAL;
-
        asm volatile(
        "       swi #0\n"
        : "=r" (ret)
@@ -117,11 +107,12 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
        u64 res;
 
        /*
-        * clock_mode == 0 implies that vDSO are enabled otherwise
-        * fallback on syscall.
+        * Core checks for mode already, so this raced against a concurrent
+        * update. Return something. Core will do another round and then
+        * see the mode change and fallback to the syscall.
         */
-       if (clock_mode)
-               return __VDSO_USE_SYSCALL;
+       if (clock_mode == VDSO_CLOCKMODE_NONE)
+               return 0;
 
        /*
         * This isb() is required to prevent that the counter value
index b08f476..afba6ba 100644 (file)
@@ -8,9 +8,6 @@
 #ifndef __ASSEMBLY__
 
 #include <asm/unistd.h>
-#include <uapi/linux/time.h>
-
-#define __VDSO_USE_SYSCALL             ULLONG_MAX
 
 #define VDSO_HAS_CLOCK_GETRES          1
 
@@ -71,11 +68,12 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
        u64 res;
 
        /*
-        * clock_mode == 0 implies that vDSO are enabled otherwise
-        * fallback on syscall.
+        * Core checks for mode already, so this raced against a concurrent
+        * update. Return something. Core will do another round and then
+        * see the mode change and fallback to the syscall.
         */
-       if (clock_mode)
-               return __VDSO_USE_SYSCALL;
+       if (clock_mode == VDSO_CLOCKMODE_NONE)
+               return 0;
 
        /*
         * This isb() is required to prevent that the counter value
diff --git a/arch/arm64/include/asm/vdso/processor.h b/arch/arm64/include/asm/vdso/processor.h
new file mode 100644 (file)
index 0000000..ff830b7
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+#ifndef __ASM_VDSO_PROCESSOR_H
+#define __ASM_VDSO_PROCESSOR_H
+
+#ifndef __ASSEMBLY__
+
+static inline void cpu_relax(void)
+{
+       asm volatile("yield" ::: "memory");
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_VDSO_PROCESSOR_H */
index 0c20a7c..f94b145 100644 (file)
@@ -22,15 +22,6 @@ struct vdso_data *__arm64_get_k_vdso_data(void)
 #define __arch_get_k_vdso_data __arm64_get_k_vdso_data
 
 static __always_inline
-int __arm64_get_clock_mode(struct timekeeper *tk)
-{
-       u32 use_syscall = !tk->tkr_mono.clock->archdata.vdso_direct;
-
-       return use_syscall;
-}
-#define __arch_get_clock_mode __arm64_get_clock_mode
-
-static __always_inline
 void __arm64_update_vsyscall(struct vdso_data *vdata, struct timekeeper *tk)
 {
        vdata[CS_HRES_COARSE].mask      = VDSO_PRECISION_MASK;
index 0958ed6..61fd267 100644 (file)
@@ -83,7 +83,7 @@ static inline bool is_kernel_in_hyp_mode(void)
        return read_sysreg(CurrentEL) == CurrentEL_EL2;
 }
 
-static inline bool has_vhe(void)
+static __always_inline bool has_vhe(void)
 {
        if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
                return true;
index fc64886..4e5b8ee 100644 (file)
@@ -21,7 +21,7 @@ obj-y                 := debug-monitors.o entry.o irq.o fpsimd.o              \
                           smp.o smp_spin_table.o topology.o smccc-call.o       \
                           syscall.o
 
-extra-$(CONFIG_EFI)                    := efi-entry.o
+targets                        += efi-entry.o
 
 OBJCOPYFLAGS := --prefix-symbols=__efistub_
 $(obj)/%.stub.o: $(obj)/%.o FORCE
index 7832b32..4cc581a 100644 (file)
@@ -630,7 +630,7 @@ static int __init armv8_deprecated_init(void)
                register_insn_emulation(&cp15_barrier_ops);
 
        if (IS_ENABLED(CONFIG_SETEND_EMULATION)) {
-               if(system_supports_mixed_endian_el0())
+               if (system_supports_mixed_endian_el0())
                        register_insn_emulation(&setend_ops);
                else
                        pr_info("setend instruction emulation is not supported on this system\n");
index a5bdce8..9981a0a 100644 (file)
@@ -40,6 +40,10 @@ int main(void)
 #endif
   BLANK();
   DEFINE(THREAD_CPU_CONTEXT,   offsetof(struct task_struct, thread.cpu_context));
+#ifdef CONFIG_ARM64_PTR_AUTH
+  DEFINE(THREAD_KEYS_USER,     offsetof(struct task_struct, thread.keys_user));
+  DEFINE(THREAD_KEYS_KERNEL,   offsetof(struct task_struct, thread.keys_kernel));
+#endif
   BLANK();
   DEFINE(S_X0,                 offsetof(struct pt_regs, regs[0]));
   DEFINE(S_X2,                 offsetof(struct pt_regs, regs[2]));
@@ -88,6 +92,9 @@ int main(void)
   BLANK();
   DEFINE(CPU_BOOT_STACK,       offsetof(struct secondary_data, stack));
   DEFINE(CPU_BOOT_TASK,                offsetof(struct secondary_data, task));
+#ifdef CONFIG_ARM64_PTR_AUTH
+  DEFINE(CPU_BOOT_PTRAUTH_KEY, offsetof(struct secondary_data, ptrauth_key));
+#endif
   BLANK();
 #ifdef CONFIG_KVM_ARM_HOST
   DEFINE(VCPU_CONTEXT,         offsetof(struct kvm_vcpu, arch.ctxt));
@@ -128,5 +135,14 @@ int main(void)
   DEFINE(SDEI_EVENT_INTREGS,   offsetof(struct sdei_registered_event, interrupted_regs));
   DEFINE(SDEI_EVENT_PRIORITY,  offsetof(struct sdei_registered_event, priority));
 #endif
+#ifdef CONFIG_ARM64_PTR_AUTH
+  DEFINE(PTRAUTH_USER_KEY_APIA,                offsetof(struct ptrauth_keys_user, apia));
+  DEFINE(PTRAUTH_USER_KEY_APIB,                offsetof(struct ptrauth_keys_user, apib));
+  DEFINE(PTRAUTH_USER_KEY_APDA,                offsetof(struct ptrauth_keys_user, apda));
+  DEFINE(PTRAUTH_USER_KEY_APDB,                offsetof(struct ptrauth_keys_user, apdb));
+  DEFINE(PTRAUTH_USER_KEY_APGA,                offsetof(struct ptrauth_keys_user, apga));
+  DEFINE(PTRAUTH_KERNEL_KEY_APIA,      offsetof(struct ptrauth_keys_kernel, apia));
+  BLANK();
+#endif
   return 0;
 }
index 32c7bf8..38087b4 100644 (file)
@@ -32,7 +32,7 @@
 ENTRY(__cpu_soft_restart)
        /* Clear sctlr_el1 flags. */
        mrs     x12, sctlr_el1
-       ldr     x13, =SCTLR_ELx_FLAGS
+       mov_q   x13, SCTLR_ELx_FLAGS
        bic     x12, x12, x13
        pre_disable_mmu_workaround
        msr     sctlr_el1, x12
index 703ad0a..df56d22 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/cpufeature.h>
+#include <asm/kvm_asm.h>
 #include <asm/smp_plat.h>
 
 static bool __maybe_unused
@@ -113,13 +114,10 @@ atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1);
 DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
 
 #ifdef CONFIG_KVM_INDIRECT_VECTORS
-extern char __smccc_workaround_1_smc_start[];
-extern char __smccc_workaround_1_smc_end[];
-
 static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
                                const char *hyp_vecs_end)
 {
-       void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K);
+       void *dst = lm_alias(__bp_harden_hyp_vecs + slot * SZ_2K);
        int i;
 
        for (i = 0; i < SZ_2K; i += 0x80)
@@ -163,9 +161,6 @@ static void install_bp_hardening_cb(bp_hardening_cb_t fn,
        raw_spin_unlock(&bp_lock);
 }
 #else
-#define __smccc_workaround_1_smc_start         NULL
-#define __smccc_workaround_1_smc_end           NULL
-
 static void install_bp_hardening_cb(bp_hardening_cb_t fn,
                                      const char *hyp_vecs_start,
                                      const char *hyp_vecs_end)
@@ -176,7 +171,7 @@ static void install_bp_hardening_cb(bp_hardening_cb_t fn,
 
 #include <linux/arm-smccc.h>
 
-static void call_smc_arch_workaround_1(void)
+static void __maybe_unused call_smc_arch_workaround_1(void)
 {
        arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
 }
@@ -239,11 +234,14 @@ static int detect_harden_bp_fw(void)
                smccc_end = NULL;
                break;
 
+#if IS_ENABLED(CONFIG_KVM_ARM_HOST)
        case SMCCC_CONDUIT_SMC:
                cb = call_smc_arch_workaround_1;
-               smccc_start = __smccc_workaround_1_smc_start;
-               smccc_end = __smccc_workaround_1_smc_end;
+               smccc_start = __smccc_workaround_1_smc;
+               smccc_end = __smccc_workaround_1_smc +
+                       __SMCCC_WORKAROUND_1_SMC_SZ;
                break;
+#endif
 
        default:
                return -1;
index 7e07072..e133011 100644 (file)
 #include <asm/smp_plat.h>
 
 extern const struct cpu_operations smp_spin_table_ops;
+#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
 extern const struct cpu_operations acpi_parking_protocol_ops;
+#endif
 extern const struct cpu_operations cpu_psci_ops;
 
-const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
+static const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init;
 
 static const struct cpu_operations *const dt_supported_cpu_ops[] __initconst = {
        &smp_spin_table_ops,
@@ -94,7 +96,7 @@ static const char *__init cpu_read_enable_method(int cpu)
 /*
  * Read a cpu's enable method and record it in cpu_ops.
  */
-int __init cpu_read_ops(int cpu)
+int __init init_cpu_ops(int cpu)
 {
        const char *enable_method = cpu_read_enable_method(cpu);
 
@@ -109,3 +111,8 @@ int __init cpu_read_ops(int cpu)
 
        return 0;
 }
+
+const struct cpu_operations *get_cpu_ops(int cpu)
+{
+       return cpu_ops[cpu];
+}
index 0b67156..9fac745 100644 (file)
@@ -116,6 +116,8 @@ cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused)
 
 static void cpu_enable_cnp(struct arm64_cpu_capabilities const *cap);
 
+static bool __system_matches_cap(unsigned int n);
+
 /*
  * NOTE: Any changes to the visibility of features should be kept in
  * sync with the documentation of the CPU feature register ABI.
@@ -163,6 +165,7 @@ static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_DIT_SHIFT, 4, 0),
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_AMU_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_SVE),
                                   FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_SVE_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_RAS_SHIFT, 4, 0),
@@ -551,7 +554,7 @@ static void __init init_cpu_ftr_reg(u32 sys_reg, u64 new)
 
        BUG_ON(!reg);
 
-       for (ftrp  = reg->ftr_bits; ftrp->width; ftrp++) {
+       for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) {
                u64 ftr_mask = arm64_ftr_mask(ftrp);
                s64 ftr_new = arm64_ftr_value(ftrp, new);
 
@@ -1222,6 +1225,57 @@ static bool has_hw_dbm(const struct arm64_cpu_capabilities *cap,
 
 #endif
 
+#ifdef CONFIG_ARM64_AMU_EXTN
+
+/*
+ * The "amu_cpus" cpumask only signals that the CPU implementation for the
+ * flagged CPUs supports the Activity Monitors Unit (AMU) but does not provide
+ * information regarding all the events that it supports. When a CPU bit is
+ * set in the cpumask, the user of this feature can only rely on the presence
+ * of the 4 fixed counters for that CPU. But this does not guarantee that the
+ * counters are enabled or access to these counters is enabled by code
+ * executed at higher exception levels (firmware).
+ */
+static struct cpumask amu_cpus __read_mostly;
+
+bool cpu_has_amu_feat(int cpu)
+{
+       return cpumask_test_cpu(cpu, &amu_cpus);
+}
+
+/* Initialize the use of AMU counters for frequency invariance */
+extern void init_cpu_freq_invariance_counters(void);
+
+static void cpu_amu_enable(struct arm64_cpu_capabilities const *cap)
+{
+       if (has_cpuid_feature(cap, SCOPE_LOCAL_CPU)) {
+               pr_info("detected CPU%d: Activity Monitors Unit (AMU)\n",
+                       smp_processor_id());
+               cpumask_set_cpu(smp_processor_id(), &amu_cpus);
+               init_cpu_freq_invariance_counters();
+       }
+}
+
+static bool has_amu(const struct arm64_cpu_capabilities *cap,
+                   int __unused)
+{
+       /*
+        * The AMU extension is a non-conflicting feature: the kernel can
+        * safely run a mix of CPUs with and without support for the
+        * activity monitors extension. Therefore, unconditionally enable
+        * the capability to allow any late CPU to use the feature.
+        *
+        * With this feature unconditionally enabled, the cpu_enable
+        * function will be called for all CPUs that match the criteria,
+        * including secondary and hotplugged, marking this feature as
+        * present on that respective CPU. The enable function will also
+        * print a detection message.
+        */
+
+       return true;
+}
+#endif
+
 #ifdef CONFIG_ARM64_VHE
 static bool runs_at_el2(const struct arm64_cpu_capabilities *entry, int __unused)
 {
@@ -1316,10 +1370,18 @@ static void cpu_clear_disr(const struct arm64_cpu_capabilities *__unused)
 #endif /* CONFIG_ARM64_RAS_EXTN */
 
 #ifdef CONFIG_ARM64_PTR_AUTH
-static void cpu_enable_address_auth(struct arm64_cpu_capabilities const *cap)
+static bool has_address_auth(const struct arm64_cpu_capabilities *entry,
+                            int __unused)
 {
-       sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_ENIA | SCTLR_ELx_ENIB |
-                                      SCTLR_ELx_ENDA | SCTLR_ELx_ENDB);
+       return __system_matches_cap(ARM64_HAS_ADDRESS_AUTH_ARCH) ||
+              __system_matches_cap(ARM64_HAS_ADDRESS_AUTH_IMP_DEF);
+}
+
+static bool has_generic_auth(const struct arm64_cpu_capabilities *entry,
+                            int __unused)
+{
+       return __system_matches_cap(ARM64_HAS_GENERIC_AUTH_ARCH) ||
+              __system_matches_cap(ARM64_HAS_GENERIC_AUTH_IMP_DEF);
 }
 #endif /* CONFIG_ARM64_PTR_AUTH */
 
@@ -1347,6 +1409,25 @@ static bool can_use_gic_priorities(const struct arm64_cpu_capabilities *entry,
 }
 #endif
 
+/* Internal helper functions to match cpu capability type */
+static bool
+cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
+{
+       return !!(cap->type & ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU);
+}
+
+static bool
+cpucap_late_cpu_permitted(const struct arm64_cpu_capabilities *cap)
+{
+       return !!(cap->type & ARM64_CPUCAP_PERMITTED_FOR_LATE_CPU);
+}
+
+static bool
+cpucap_panic_on_conflict(const struct arm64_cpu_capabilities *cap)
+{
+       return !!(cap->type & ARM64_CPUCAP_PANIC_ON_CONFLICT);
+}
+
 static const struct arm64_cpu_capabilities arm64_features[] = {
        {
                .desc = "GIC system register CPU interface",
@@ -1499,6 +1580,24 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .cpu_enable = cpu_clear_disr,
        },
 #endif /* CONFIG_ARM64_RAS_EXTN */
+#ifdef CONFIG_ARM64_AMU_EXTN
+       {
+               /*
+                * The feature is enabled by default if CONFIG_ARM64_AMU_EXTN=y.
+                * Therefore, don't provide .desc as we don't want the detection
+                * message to be shown until at least one CPU is detected to
+                * support the feature.
+                */
+               .capability = ARM64_HAS_AMU_EXTN,
+               .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
+               .matches = has_amu,
+               .sys_reg = SYS_ID_AA64PFR0_EL1,
+               .sign = FTR_UNSIGNED,
+               .field_pos = ID_AA64PFR0_AMU_SHIFT,
+               .min_field_value = ID_AA64PFR0_AMU,
+               .cpu_enable = cpu_amu_enable,
+       },
+#endif /* CONFIG_ARM64_AMU_EXTN */
        {
                .desc = "Data cache clean to the PoU not required for I/D coherence",
                .capability = ARM64_HAS_CACHE_IDC,
@@ -1592,24 +1691,27 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
        {
                .desc = "Address authentication (architected algorithm)",
                .capability = ARM64_HAS_ADDRESS_AUTH_ARCH,
-               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
                .sign = FTR_UNSIGNED,
                .field_pos = ID_AA64ISAR1_APA_SHIFT,
                .min_field_value = ID_AA64ISAR1_APA_ARCHITECTED,
                .matches = has_cpuid_feature,
-               .cpu_enable = cpu_enable_address_auth,
        },
        {
                .desc = "Address authentication (IMP DEF algorithm)",
                .capability = ARM64_HAS_ADDRESS_AUTH_IMP_DEF,
-               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
                .sys_reg = SYS_ID_AA64ISAR1_EL1,
                .sign = FTR_UNSIGNED,
                .field_pos = ID_AA64ISAR1_API_SHIFT,
                .min_field_value = ID_AA64ISAR1_API_IMP_DEF,
                .matches = has_cpuid_feature,
-               .cpu_enable = cpu_enable_address_auth,
+       },
+       {
+               .capability = ARM64_HAS_ADDRESS_AUTH,
+               .type = ARM64_CPUCAP_BOOT_CPU_FEATURE,
+               .matches = has_address_auth,
        },
        {
                .desc = "Generic authentication (architected algorithm)",
@@ -1631,6 +1733,11 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
                .min_field_value = ID_AA64ISAR1_GPI_IMP_DEF,
                .matches = has_cpuid_feature,
        },
+       {
+               .capability = ARM64_HAS_GENERIC_AUTH,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .matches = has_generic_auth,
+       },
 #endif /* CONFIG_ARM64_PTR_AUTH */
 #ifdef CONFIG_ARM64_PSEUDO_NMI
        {
@@ -1980,10 +2087,8 @@ static void __init enable_cpu_capabilities(u16 scope_mask)
  * Run through the list of capabilities to check for conflicts.
  * If the system has already detected a capability, take necessary
  * action on this CPU.
- *
- * Returns "false" on conflicts.
  */
-static bool verify_local_cpu_caps(u16 scope_mask)
+static void verify_local_cpu_caps(u16 scope_mask)
 {
        int i;
        bool cpu_has_cap, system_has_cap;
@@ -2028,10 +2133,12 @@ static bool verify_local_cpu_caps(u16 scope_mask)
                pr_crit("CPU%d: Detected conflict for capability %d (%s), System: %d, CPU: %d\n",
                        smp_processor_id(), caps->capability,
                        caps->desc, system_has_cap, cpu_has_cap);
-               return false;
-       }
 
-       return true;
+               if (cpucap_panic_on_conflict(caps))
+                       cpu_panic_kernel();
+               else
+                       cpu_die_early();
+       }
 }
 
 /*
@@ -2041,12 +2148,8 @@ static bool verify_local_cpu_caps(u16 scope_mask)
 static void check_early_cpu_features(void)
 {
        verify_cpu_asid_bits();
-       /*
-        * Early features are used by the kernel already. If there
-        * is a conflict, we cannot proceed further.
-        */
-       if (!verify_local_cpu_caps(SCOPE_BOOT_CPU))
-               cpu_panic_kernel();
+
+       verify_local_cpu_caps(SCOPE_BOOT_CPU);
 }
 
 static void
@@ -2094,8 +2197,7 @@ static void verify_local_cpu_capabilities(void)
         * check_early_cpu_features(), as they need to be verified
         * on all secondary CPUs.
         */
-       if (!verify_local_cpu_caps(SCOPE_ALL & ~SCOPE_BOOT_CPU))
-               cpu_die_early();
+       verify_local_cpu_caps(SCOPE_ALL & ~SCOPE_BOOT_CPU);
 
        verify_local_elf_hwcaps(arm64_elf_hwcaps);
 
@@ -2146,6 +2248,23 @@ bool this_cpu_has_cap(unsigned int n)
        return false;
 }
 
+/*
+ * This helper function is used in a narrow window when,
+ * - The system wide safe registers are set with all the SMP CPUs and,
+ * - The SYSTEM_FEATURE cpu_hwcaps may not have been set.
+ * In all other cases cpus_have_{const_}cap() should be used.
+ */
+static bool __system_matches_cap(unsigned int n)
+{
+       if (n < ARM64_NCAPS) {
+               const struct arm64_cpu_capabilities *cap = cpu_hwcaps_ptrs[n];
+
+               if (cap)
+                       return cap->matches(cap, SCOPE_SYSTEM);
+       }
+       return false;
+}
+
 void cpu_set_feature(unsigned int num)
 {
        WARN_ON(num >= MAX_CPU_FEATURES);
@@ -2218,7 +2337,7 @@ void __init setup_cpu_features(void)
 static bool __maybe_unused
 cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused)
 {
-       return (cpus_have_const_cap(ARM64_HAS_PAN) && !cpus_have_const_cap(ARM64_HAS_UAO));
+       return (__system_matches_cap(ARM64_HAS_PAN) && !__system_matches_cap(ARM64_HAS_UAO));
 }
 
 static void __maybe_unused cpu_enable_cnp(struct arm64_cpu_capabilities const *cap)
index e4d6af2..b512b55 100644 (file)
 
 int arm_cpuidle_init(unsigned int cpu)
 {
+       const struct cpu_operations *ops = get_cpu_ops(cpu);
        int ret = -EOPNOTSUPP;
 
-       if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_suspend &&
-                       cpu_ops[cpu]->cpu_init_idle)
-               ret = cpu_ops[cpu]->cpu_init_idle(cpu);
+       if (ops && ops->cpu_suspend && ops->cpu_init_idle)
+               ret = ops->cpu_init_idle(cpu);
 
        return ret;
 }
@@ -37,8 +37,9 @@ int arm_cpuidle_init(unsigned int cpu)
 int arm_cpuidle_suspend(int index)
 {
        int cpu = smp_processor_id();
+       const struct cpu_operations *ops = get_cpu_ops(cpu);
 
-       return cpu_ops[cpu]->cpu_suspend(index);
+       return ops->cpu_suspend(index);
 }
 
 #ifdef CONFIG_ACPI
index 304d5b0..1a03618 100644 (file)
 
 #include <asm/assembler.h>
 
-#define EFI_LOAD_ERROR 0x8000000000000001
-
        __INIT
 
-       /*
-        * We arrive here from the EFI boot manager with:
-        *
-        *    * CPU in little-endian mode
-        *    * MMU on with identity-mapped RAM
-        *    * Icache and Dcache on
-        *
-        * We will most likely be running from some place other than where
-        * we want to be. The kernel image wants to be placed at TEXT_OFFSET
-        * from start of RAM.
-        */
-ENTRY(entry)
-       /*
-        * Create a stack frame to save FP/LR with extra space
-        * for image_addr variable passed to efi_entry().
-        */
-       stp     x29, x30, [sp, #-32]!
-       mov     x29, sp
-
-       /*
-        * Call efi_entry to do the real work.
-        * x0 and x1 are already set up by firmware. Current runtime
-        * address of image is calculated and passed via *image_addr.
-        *
-        * unsigned long efi_entry(void *handle,
-        *                         efi_system_table_t *sys_table,
-        *                         unsigned long *image_addr) ;
-        */
-       adr_l   x8, _text
-       add     x2, sp, 16
-       str     x8, [x2]
-       bl      efi_entry
-       cmn     x0, #1
-       b.eq    efi_load_fail
-
+SYM_CODE_START(efi_enter_kernel)
        /*
         * efi_entry() will have copied the kernel image if necessary and we
-        * return here with device tree address in x0 and the kernel entry
-        * point stored at *image_addr. Save those values in registers which
-        * are callee preserved.
-        */
-       mov     x20, x0         // DTB address
-       ldr     x0, [sp, #16]   // relocated _text address
-       ldr     w21, =stext_offset
-       add     x21, x0, x21
-
-       /*
-        * Calculate size of the kernel Image (same for original and copy).
+        * end up here with device tree address in x1 and the kernel entry
+        * point stored in x0. Save those values in registers which are
+        * callee preserved.
         */
-       adr_l   x1, _text
-       adr_l   x2, _edata
-       sub     x1, x2, x1
+       ldr     w2, =stext_offset
+       add     x19, x0, x2             // relocated Image entrypoint
+       mov     x20, x1                 // DTB address
 
        /*
-        * Flush the copied Image to the PoC, and ensure it is not shadowed by
+        * Clean the copied Image to the PoC, and ensure it is not shadowed by
         * stale icache entries from before relocation.
         */
-       bl      __flush_dcache_area
+       ldr     w1, =kernel_size
+       bl      __clean_dcache_area_poc
        ic      ialluis
 
        /*
-        * Ensure that the rest of this function (in the original Image) is
-        * visible when the caches are disabled. The I-cache can't have stale
-        * entries for the VA range of the current image, so no maintenance is
-        * necessary.
+        * Clean the remainder of this routine to the PoC
+        * so that we can safely disable the MMU and caches.
         */
-       adr     x0, entry
-       adr     x1, entry_end
-       sub     x1, x1, x0
-       bl      __flush_dcache_area
-
+       adr     x0, 0f
+       ldr     w1, 3f
+       bl      __clean_dcache_area_poc
+0:
        /* Turn off Dcache and MMU */
        mrs     x0, CurrentEL
        cmp     x0, #CurrentEL_EL2
@@ -109,12 +63,6 @@ ENTRY(entry)
        mov     x1, xzr
        mov     x2, xzr
        mov     x3, xzr
-       br      x21
-
-efi_load_fail:
-       mov     x0, #EFI_LOAD_ERROR
-       ldp     x29, x30, [sp], #32
-       ret
-
-entry_end:
-ENDPROC(entry)
+       br      x19
+SYM_CODE_END(efi_enter_kernel)
+3:     .long   . - 0b
index a7cfacc..914999c 100644 (file)
@@ -27,7 +27,7 @@ optional_header:
        .long   __initdata_begin - efi_header_end       // SizeOfCode
        .long   __pecoff_data_size                      // SizeOfInitializedData
        .long   0                                       // SizeOfUninitializedData
-       .long   __efistub_entry - _head                 // AddressOfEntryPoint
+       .long   __efistub_efi_entry - _head             // AddressOfEntryPoint
        .long   efi_header_end - _head                  // BaseOfCode
 
 extra_header_fields:
@@ -36,8 +36,8 @@ extra_header_fields:
        .long   PECOFF_FILE_ALIGNMENT                   // FileAlignment
        .short  0                                       // MajorOperatingSystemVersion
        .short  0                                       // MinorOperatingSystemVersion
-       .short  0                                       // MajorImageVersion
-       .short  0                                       // MinorImageVersion
+       .short  LINUX_EFISTUB_MAJOR_VERSION             // MajorImageVersion
+       .short  LINUX_EFISTUB_MINOR_VERSION             // MinorImageVersion
        .short  0                                       // MajorSubsystemVersion
        .short  0                                       // MinorSubsystemVersion
        .long   0                                       // Win32VersionValue
index fde5998..c839b5b 100644 (file)
@@ -175,7 +175,7 @@ NOKPROBE_SYMBOL(el0_pc);
 static void notrace el0_sp(struct pt_regs *regs, unsigned long esr)
 {
        user_exit_irqoff();
-       local_daif_restore(DAIF_PROCCTX_NOIRQ);
+       local_daif_restore(DAIF_PROCCTX);
        do_sp_pc_abort(regs->sp, esr, regs);
 }
 NOKPROBE_SYMBOL(el0_sp);
index 7d02f99..833d48c 100644 (file)
        add     x29, sp, #S_STACKFRAME
        .endm
 
-ENTRY(ftrace_regs_caller)
+SYM_CODE_START(ftrace_regs_caller)
        ftrace_regs_entry       1
        b       ftrace_common
-ENDPROC(ftrace_regs_caller)
+SYM_CODE_END(ftrace_regs_caller)
 
-ENTRY(ftrace_caller)
+SYM_CODE_START(ftrace_caller)
        ftrace_regs_entry       0
        b       ftrace_common
-ENDPROC(ftrace_caller)
+SYM_CODE_END(ftrace_caller)
 
-ENTRY(ftrace_common)
+SYM_CODE_START(ftrace_common)
        sub     x0, x30, #AARCH64_INSN_SIZE     // ip (callsite's BL insn)
        mov     x1, x9                          // parent_ip (callsite's LR)
        ldr_l   x2, function_trace_op           // op
        mov     x3, sp                          // regs
 
-GLOBAL(ftrace_call)
+SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
        bl      ftrace_stub
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-GLOBAL(ftrace_graph_call)              // ftrace_graph_caller();
+SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();
        nop                             // If enabled, this will be replaced
                                        // "b ftrace_graph_caller"
 #endif
@@ -122,17 +122,17 @@ ftrace_common_return:
        add     sp, sp, #S_FRAME_SIZE + 16
 
        ret     x9
-ENDPROC(ftrace_common)
+SYM_CODE_END(ftrace_common)
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-ENTRY(ftrace_graph_caller)
+SYM_CODE_START(ftrace_graph_caller)
        ldr     x0, [sp, #S_PC]
        sub     x0, x0, #AARCH64_INSN_SIZE      // ip (callsite's BL insn)
        add     x1, sp, #S_LR                   // parent_ip (callsite's LR)
        ldr     x2, [sp, #S_FRAME_SIZE]         // parent fp (callsite's FP)
        bl      prepare_ftrace_return
        b       ftrace_common_return
-ENDPROC(ftrace_graph_caller)
+SYM_CODE_END(ftrace_graph_caller)
 #endif
 
 #else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
@@ -218,7 +218,7 @@ ENDPROC(ftrace_graph_caller)
  *     - tracer function to probe instrumented function's entry,
  *     - ftrace_graph_caller to set up an exit hook
  */
-ENTRY(_mcount)
+SYM_FUNC_START(_mcount)
        mcount_enter
 
        ldr_l   x2, ftrace_trace_function
@@ -242,7 +242,7 @@ skip_ftrace_call:                   // }
        b.ne    ftrace_graph_caller     //     ftrace_graph_caller();
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
        mcount_exit
-ENDPROC(_mcount)
+SYM_FUNC_END(_mcount)
 EXPORT_SYMBOL(_mcount)
 NOKPROBE(_mcount)
 
@@ -253,9 +253,9 @@ NOKPROBE(_mcount)
  * and later on, NOP to branch to ftrace_caller() when enabled or branch to
  * NOP when disabled per-function base.
  */
-ENTRY(_mcount)
+SYM_FUNC_START(_mcount)
        ret
-ENDPROC(_mcount)
+SYM_FUNC_END(_mcount)
 EXPORT_SYMBOL(_mcount)
 NOKPROBE(_mcount)
 
@@ -268,24 +268,24 @@ NOKPROBE(_mcount)
  *     - tracer function to probe instrumented function's entry,
  *     - ftrace_graph_caller to set up an exit hook
  */
-ENTRY(ftrace_caller)
+SYM_FUNC_START(ftrace_caller)
        mcount_enter
 
        mcount_get_pc0  x0              //     function's pc
        mcount_get_lr   x1              //     function's lr
 
-GLOBAL(ftrace_call)                    // tracer(pc, lr);
+SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)     // tracer(pc, lr);
        nop                             // This will be replaced with "bl xxx"
                                        // where xxx can be any kind of tracer.
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-GLOBAL(ftrace_graph_call)              // ftrace_graph_caller();
+SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller();
        nop                             // If enabled, this will be replaced
                                        // "b ftrace_graph_caller"
 #endif
 
        mcount_exit
-ENDPROC(ftrace_caller)
+SYM_FUNC_END(ftrace_caller)
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -298,20 +298,20 @@ ENDPROC(ftrace_caller)
  * the call stack in order to intercept instrumented function's return path
  * and run return_to_handler() later on its exit.
  */
-ENTRY(ftrace_graph_caller)
+SYM_FUNC_START(ftrace_graph_caller)
        mcount_get_pc             x0    //     function's pc
        mcount_get_lr_addr        x1    //     pointer to function's saved lr
        mcount_get_parent_fp      x2    //     parent's fp
        bl      prepare_ftrace_return   // prepare_ftrace_return(pc, &lr, fp)
 
        mcount_exit
-ENDPROC(ftrace_graph_caller)
+SYM_FUNC_END(ftrace_graph_caller)
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */
 
-ENTRY(ftrace_stub)
+SYM_FUNC_START(ftrace_stub)
        ret
-ENDPROC(ftrace_stub)
+SYM_FUNC_END(ftrace_stub)
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 /*
@@ -320,7 +320,7 @@ ENDPROC(ftrace_stub)
  * Run ftrace_return_to_handler() before going back to parent.
  * @fp is checked against the value passed by ftrace_graph_caller().
  */
-ENTRY(return_to_handler)
+SYM_CODE_START(return_to_handler)
        /* save return value regs */
        sub sp, sp, #64
        stp x0, x1, [sp]
@@ -340,5 +340,5 @@ ENTRY(return_to_handler)
        add sp, sp, #64
 
        ret
-END(return_to_handler)
+SYM_CODE_END(return_to_handler)
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
index 9461d81..ddcde09 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/alternative.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
+#include <asm/asm_pointer_auth.h>
 #include <asm/cpufeature.h>
 #include <asm/errno.h>
 #include <asm/esr.h>
@@ -177,6 +178,7 @@ alternative_cb_end
 
        apply_ssbd 1, x22, x23
 
+       ptrauth_keys_install_kernel tsk, 1, x20, x22, x23
        .else
        add     x21, sp, #S_FRAME_SIZE
        get_current_task tsk
@@ -341,6 +343,9 @@ alternative_else_nop_endif
        msr     cntkctl_el1, x1
 4:
 #endif
+       /* No kernel C function calls after this as user keys are set. */
+       ptrauth_keys_install_user tsk, x0, x1, x2
+
        apply_ssbd 0, x0, x1
        .endif
 
@@ -465,7 +470,7 @@ alternative_endif
        .pushsection ".entry.text", "ax"
 
        .align  11
-ENTRY(vectors)
+SYM_CODE_START(vectors)
        kernel_ventry   1, sync_invalid                 // Synchronous EL1t
        kernel_ventry   1, irq_invalid                  // IRQ EL1t
        kernel_ventry   1, fiq_invalid                  // FIQ EL1t
@@ -492,7 +497,7 @@ ENTRY(vectors)
        kernel_ventry   0, fiq_invalid, 32              // FIQ 32-bit EL0
        kernel_ventry   0, error_invalid, 32            // Error 32-bit EL0
 #endif
-END(vectors)
+SYM_CODE_END(vectors)
 
 #ifdef CONFIG_VMAP_STACK
        /*
@@ -534,57 +539,57 @@ __bad_stack:
        ASM_BUG()
        .endm
 
-el0_sync_invalid:
+SYM_CODE_START_LOCAL(el0_sync_invalid)
        inv_entry 0, BAD_SYNC
-ENDPROC(el0_sync_invalid)
+SYM_CODE_END(el0_sync_invalid)
 
-el0_irq_invalid:
+SYM_CODE_START_LOCAL(el0_irq_invalid)
        inv_entry 0, BAD_IRQ
-ENDPROC(el0_irq_invalid)
+SYM_CODE_END(el0_irq_invalid)
 
-el0_fiq_invalid:
+SYM_CODE_START_LOCAL(el0_fiq_invalid)
        inv_entry 0, BAD_FIQ
-ENDPROC(el0_fiq_invalid)
+SYM_CODE_END(el0_fiq_invalid)
 
-el0_error_invalid:
+SYM_CODE_START_LOCAL(el0_error_invalid)
        inv_entry 0, BAD_ERROR
-ENDPROC(el0_error_invalid)
+SYM_CODE_END(el0_error_invalid)
 
 #ifdef CONFIG_COMPAT
-el0_fiq_invalid_compat:
+SYM_CODE_START_LOCAL(el0_fiq_invalid_compat)
        inv_entry 0, BAD_FIQ, 32
-ENDPROC(el0_fiq_invalid_compat)
+SYM_CODE_END(el0_fiq_invalid_compat)
 #endif
 
-el1_sync_invalid:
+SYM_CODE_START_LOCAL(el1_sync_invalid)
        inv_entry 1, BAD_SYNC
-ENDPROC(el1_sync_invalid)
+SYM_CODE_END(el1_sync_invalid)
 
-el1_irq_invalid:
+SYM_CODE_START_LOCAL(el1_irq_invalid)
        inv_entry 1, BAD_IRQ
-ENDPROC(el1_irq_invalid)
+SYM_CODE_END(el1_irq_invalid)
 
-el1_fiq_invalid:
+SYM_CODE_START_LOCAL(el1_fiq_invalid)
        inv_entry 1, BAD_FIQ
-ENDPROC(el1_fiq_invalid)
+SYM_CODE_END(el1_fiq_invalid)
 
-el1_error_invalid:
+SYM_CODE_START_LOCAL(el1_error_invalid)
        inv_entry 1, BAD_ERROR
-ENDPROC(el1_error_invalid)
+SYM_CODE_END(el1_error_invalid)
 
 /*
  * EL1 mode handlers.
  */
        .align  6
-el1_sync:
+SYM_CODE_START_LOCAL_NOALIGN(el1_sync)
        kernel_entry 1
        mov     x0, sp
        bl      el1_sync_handler
        kernel_exit 1
-ENDPROC(el1_sync)
+SYM_CODE_END(el1_sync)
 
        .align  6
-el1_irq:
+SYM_CODE_START_LOCAL_NOALIGN(el1_irq)
        kernel_entry 1
        gic_prio_irq_setup pmr=x20, tmp=x1
        enable_da_f
@@ -639,42 +644,42 @@ alternative_else_nop_endif
 #endif
 
        kernel_exit 1
-ENDPROC(el1_irq)
+SYM_CODE_END(el1_irq)
 
 /*
  * EL0 mode handlers.
  */
        .align  6
-el0_sync:
+SYM_CODE_START_LOCAL_NOALIGN(el0_sync)
        kernel_entry 0
        mov     x0, sp
        bl      el0_sync_handler
        b       ret_to_user
-ENDPROC(el0_sync)
+SYM_CODE_END(el0_sync)
 
 #ifdef CONFIG_COMPAT
        .align  6
-el0_sync_compat:
+SYM_CODE_START_LOCAL_NOALIGN(el0_sync_compat)
        kernel_entry 0, 32
        mov     x0, sp
        bl      el0_sync_compat_handler
        b       ret_to_user
-ENDPROC(el0_sync_compat)
+SYM_CODE_END(el0_sync_compat)
 
        .align  6
-el0_irq_compat:
+SYM_CODE_START_LOCAL_NOALIGN(el0_irq_compat)
        kernel_entry 0, 32
        b       el0_irq_naked
-ENDPROC(el0_irq_compat)
+SYM_CODE_END(el0_irq_compat)
 
-el0_error_compat:
+SYM_CODE_START_LOCAL_NOALIGN(el0_error_compat)
        kernel_entry 0, 32
        b       el0_error_naked
-ENDPROC(el0_error_compat)
+SYM_CODE_END(el0_error_compat)
 #endif
 
        .align  6
-el0_irq:
+SYM_CODE_START_LOCAL_NOALIGN(el0_irq)
        kernel_entry 0
 el0_irq_naked:
        gic_prio_irq_setup pmr=x20, tmp=x0
@@ -696,9 +701,9 @@ el0_irq_naked:
        bl      trace_hardirqs_on
 #endif
        b       ret_to_user
-ENDPROC(el0_irq)
+SYM_CODE_END(el0_irq)
 
-el1_error:
+SYM_CODE_START_LOCAL(el1_error)
        kernel_entry 1
        mrs     x1, esr_el1
        gic_prio_kentry_setup tmp=x2
@@ -706,9 +711,9 @@ el1_error:
        mov     x0, sp
        bl      do_serror
        kernel_exit 1
-ENDPROC(el1_error)
+SYM_CODE_END(el1_error)
 
-el0_error:
+SYM_CODE_START_LOCAL(el0_error)
        kernel_entry 0
 el0_error_naked:
        mrs     x25, esr_el1
@@ -720,7 +725,7 @@ el0_error_naked:
        bl      do_serror
        enable_da_f
        b       ret_to_user
-ENDPROC(el0_error)
+SYM_CODE_END(el0_error)
 
 /*
  * Ok, we need to do extra processing, enter the slow path.
@@ -832,7 +837,7 @@ alternative_else_nop_endif
        .endm
 
        .align  11
-ENTRY(tramp_vectors)
+SYM_CODE_START_NOALIGN(tramp_vectors)
        .space  0x400
 
        tramp_ventry
@@ -844,24 +849,24 @@ ENTRY(tramp_vectors)
        tramp_ventry    32
        tramp_ventry    32
        tramp_ventry    32
-END(tramp_vectors)
+SYM_CODE_END(tramp_vectors)
 
-ENTRY(tramp_exit_native)
+SYM_CODE_START(tramp_exit_native)
        tramp_exit
-END(tramp_exit_native)
+SYM_CODE_END(tramp_exit_native)
 
-ENTRY(tramp_exit_compat)
+SYM_CODE_START(tramp_exit_compat)
        tramp_exit      32
-END(tramp_exit_compat)
+SYM_CODE_END(tramp_exit_compat)
 
        .ltorg
        .popsection                             // .entry.tramp.text
 #ifdef CONFIG_RANDOMIZE_BASE
        .pushsection ".rodata", "a"
        .align PAGE_SHIFT
-       .globl  __entry_tramp_data_start
-__entry_tramp_data_start:
+SYM_DATA_START(__entry_tramp_data_start)
        .quad   vectors
+SYM_DATA_END(__entry_tramp_data_start)
        .popsection                             // .rodata
 #endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
@@ -874,7 +879,7 @@ __entry_tramp_data_start:
  * Previous and next are guaranteed not to be the same.
  *
  */
-ENTRY(cpu_switch_to)
+SYM_FUNC_START(cpu_switch_to)
        mov     x10, #THREAD_CPU_CONTEXT
        add     x8, x0, x10
        mov     x9, sp
@@ -895,21 +900,22 @@ ENTRY(cpu_switch_to)
        ldr     lr, [x8]
        mov     sp, x9
        msr     sp_el0, x1
+       ptrauth_keys_install_kernel x1, 1, x8, x9, x10
        ret
-ENDPROC(cpu_switch_to)
+SYM_FUNC_END(cpu_switch_to)
 NOKPROBE(cpu_switch_to)
 
 /*
  * This is how we return from a fork.
  */
-ENTRY(ret_from_fork)
+SYM_CODE_START(ret_from_fork)
        bl      schedule_tail
        cbz     x19, 1f                         // not a kernel thread
        mov     x0, x20
        blr     x19
 1:     get_current_task tsk
        b       ret_to_user
-ENDPROC(ret_from_fork)
+SYM_CODE_END(ret_from_fork)
 NOKPROBE(ret_from_fork)
 
 #ifdef CONFIG_ARM_SDE_INTERFACE
@@ -938,7 +944,7 @@ NOKPROBE(ret_from_fork)
  */
 .ltorg
 .pushsection ".entry.tramp.text", "ax"
-ENTRY(__sdei_asm_entry_trampoline)
+SYM_CODE_START(__sdei_asm_entry_trampoline)
        mrs     x4, ttbr1_el1
        tbz     x4, #USER_ASID_BIT, 1f
 
@@ -960,7 +966,7 @@ ENTRY(__sdei_asm_entry_trampoline)
        ldr     x4, =__sdei_asm_handler
 #endif
        br      x4
-ENDPROC(__sdei_asm_entry_trampoline)
+SYM_CODE_END(__sdei_asm_entry_trampoline)
 NOKPROBE(__sdei_asm_entry_trampoline)
 
 /*
@@ -970,21 +976,22 @@ NOKPROBE(__sdei_asm_entry_trampoline)
  * x2: exit_mode
  * x4: struct sdei_registered_event argument from registration time.
  */
-ENTRY(__sdei_asm_exit_trampoline)
+SYM_CODE_START(__sdei_asm_exit_trampoline)
        ldr     x4, [x4, #(SDEI_EVENT_INTREGS + S_ORIG_ADDR_LIMIT)]
        cbnz    x4, 1f
 
        tramp_unmap_kernel      tmp=x4
 
 1:     sdei_handler_exit exit_mode=x2
-ENDPROC(__sdei_asm_exit_trampoline)
+SYM_CODE_END(__sdei_asm_exit_trampoline)
 NOKPROBE(__sdei_asm_exit_trampoline)
        .ltorg
 .popsection            // .entry.tramp.text
 #ifdef CONFIG_RANDOMIZE_BASE
 .pushsection ".rodata", "a"
-__sdei_asm_trampoline_next_handler:
+SYM_DATA_START(__sdei_asm_trampoline_next_handler)
        .quad   __sdei_asm_handler
+SYM_DATA_END(__sdei_asm_trampoline_next_handler)
 .popsection            // .rodata
 #endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
@@ -1002,7 +1009,7 @@ __sdei_asm_trampoline_next_handler:
  * follow SMC-CC. We save (or retrieve) all the registers as the handler may
  * want them.
  */
-ENTRY(__sdei_asm_handler)
+SYM_CODE_START(__sdei_asm_handler)
        stp     x2, x3, [x1, #SDEI_EVENT_INTREGS + S_PC]
        stp     x4, x5, [x1, #SDEI_EVENT_INTREGS + 16 * 2]
        stp     x6, x7, [x1, #SDEI_EVENT_INTREGS + 16 * 3]
@@ -1085,6 +1092,6 @@ alternative_else_nop_endif
        tramp_alias     dst=x5, sym=__sdei_asm_exit_trampoline
        br      x5
 #endif
-ENDPROC(__sdei_asm_handler)
+SYM_CODE_END(__sdei_asm_handler)
 NOKPROBE(__sdei_asm_handler)
 #endif /* CONFIG_ARM_SDE_INTERFACE */
index 989b194..57a9103 100644 (file)
@@ -105,7 +105,7 @@ pe_header:
         *  x24        __primary_switch() .. relocate_kernel()
         *                                        current RELR displacement
         */
-ENTRY(stext)
+SYM_CODE_START(stext)
        bl      preserve_boot_args
        bl      el2_setup                       // Drop to EL1, w0=cpu_boot_mode
        adrp    x23, __PHYS_OFFSET
@@ -118,14 +118,15 @@ ENTRY(stext)
         * On return, the CPU will be ready for the MMU to be turned on and
         * the TCR will have been set.
         */
+       mov     x0, #ARM64_CPU_BOOT_PRIMARY
        bl      __cpu_setup                     // initialise processor
        b       __primary_switch
-ENDPROC(stext)
+SYM_CODE_END(stext)
 
 /*
  * Preserve the arguments passed by the bootloader in x0 .. x3
  */
-preserve_boot_args:
+SYM_CODE_START_LOCAL(preserve_boot_args)
        mov     x21, x0                         // x21=FDT
 
        adr_l   x0, boot_args                   // record the contents of
@@ -137,7 +138,7 @@ preserve_boot_args:
 
        mov     x1, #0x20                       // 4 x 8 bytes
        b       __inval_dcache_area             // tail call
-ENDPROC(preserve_boot_args)
+SYM_CODE_END(preserve_boot_args)
 
 /*
  * Macro to create a table entry to the next page.
@@ -275,7 +276,7 @@ ENDPROC(preserve_boot_args)
  *   - first few MB of the kernel linear mapping to jump to once the MMU has
  *     been enabled
  */
-__create_page_tables:
+SYM_FUNC_START_LOCAL(__create_page_tables)
        mov     x28, lr
 
        /*
@@ -403,15 +404,14 @@ __create_page_tables:
        bl      __inval_dcache_area
 
        ret     x28
-ENDPROC(__create_page_tables)
-       .ltorg
+SYM_FUNC_END(__create_page_tables)
 
 /*
  * The following fragment of code is executed with the MMU enabled.
  *
  *   x0 = __PHYS_OFFSET
  */
-__primary_switched:
+SYM_FUNC_START_LOCAL(__primary_switched)
        adrp    x4, init_thread_union
        add     sp, x4, #THREAD_SIZE
        adr_l   x5, init_task
@@ -456,7 +456,14 @@ __primary_switched:
        mov     x29, #0
        mov     x30, #0
        b       start_kernel
-ENDPROC(__primary_switched)
+SYM_FUNC_END(__primary_switched)
+
+       .pushsection ".rodata", "a"
+SYM_DATA_START(kimage_vaddr)
+       .quad           _text - TEXT_OFFSET
+SYM_DATA_END(kimage_vaddr)
+EXPORT_SYMBOL(kimage_vaddr)
+       .popsection
 
 /*
  * end early head section, begin head code that is also used for
@@ -464,10 +471,6 @@ ENDPROC(__primary_switched)
  */
        .section ".idmap.text","awx"
 
-ENTRY(kimage_vaddr)
-       .quad           _text - TEXT_OFFSET
-EXPORT_SYMBOL(kimage_vaddr)
-
 /*
  * If we're fortunate enough to boot at EL2, ensure that the world is
  * sane before dropping to EL1.
@@ -475,7 +478,7 @@ EXPORT_SYMBOL(kimage_vaddr)
  * Returns either BOOT_CPU_MODE_EL1 or BOOT_CPU_MODE_EL2 in w0 if
  * booted in EL1 or EL2 respectively.
  */
-ENTRY(el2_setup)
+SYM_FUNC_START(el2_setup)
        msr     SPsel, #1                       // We want to use SP_EL{1,2}
        mrs     x0, CurrentEL
        cmp     x0, #CurrentEL_EL2
@@ -599,7 +602,7 @@ set_hcr:
        isb
        ret
 
-install_el2_stub:
+SYM_INNER_LABEL(install_el2_stub, SYM_L_LOCAL)
        /*
         * When VHE is not in use, early init of EL2 and EL1 needs to be
         * done here.
@@ -636,13 +639,13 @@ install_el2_stub:
        msr     elr_el2, lr
        mov     w0, #BOOT_CPU_MODE_EL2          // This CPU booted in EL2
        eret
-ENDPROC(el2_setup)
+SYM_FUNC_END(el2_setup)
 
 /*
  * Sets the __boot_cpu_mode flag depending on the CPU boot mode passed
  * in w0. See arch/arm64/include/asm/virt.h for more info.
  */
-set_cpu_boot_mode_flag:
+SYM_FUNC_START_LOCAL(set_cpu_boot_mode_flag)
        adr_l   x1, __boot_cpu_mode
        cmp     w0, #BOOT_CPU_MODE_EL2
        b.ne    1f
@@ -651,7 +654,7 @@ set_cpu_boot_mode_flag:
        dmb     sy
        dc      ivac, x1                        // Invalidate potentially stale cache line
        ret
-ENDPROC(set_cpu_boot_mode_flag)
+SYM_FUNC_END(set_cpu_boot_mode_flag)
 
 /*
  * These values are written with the MMU off, but read with the MMU on.
@@ -667,15 +670,17 @@ ENDPROC(set_cpu_boot_mode_flag)
  * This is not in .bss, because we set it sufficiently early that the boot-time
  * zeroing of .bss would clobber it.
  */
-ENTRY(__boot_cpu_mode)
+SYM_DATA_START(__boot_cpu_mode)
        .long   BOOT_CPU_MODE_EL2
        .long   BOOT_CPU_MODE_EL1
+SYM_DATA_END(__boot_cpu_mode)
 /*
  * The booting CPU updates the failed status @__early_cpu_boot_status,
  * with MMU turned off.
  */
-ENTRY(__early_cpu_boot_status)
+SYM_DATA_START(__early_cpu_boot_status)
        .quad   0
+SYM_DATA_END(__early_cpu_boot_status)
 
        .popsection
 
@@ -683,7 +688,7 @@ ENTRY(__early_cpu_boot_status)
         * This provides a "holding pen" for platforms to hold all secondary
         * cores are held until we're ready for them to initialise.
         */
-ENTRY(secondary_holding_pen)
+SYM_FUNC_START(secondary_holding_pen)
        bl      el2_setup                       // Drop to EL1, w0=cpu_boot_mode
        bl      set_cpu_boot_mode_flag
        mrs     x0, mpidr_el1
@@ -695,31 +700,32 @@ pen:      ldr     x4, [x3]
        b.eq    secondary_startup
        wfe
        b       pen
-ENDPROC(secondary_holding_pen)
+SYM_FUNC_END(secondary_holding_pen)
 
        /*
         * Secondary entry point that jumps straight into the kernel. Only to
         * be used where CPUs are brought online dynamically by the kernel.
         */
-ENTRY(secondary_entry)
+SYM_FUNC_START(secondary_entry)
        bl      el2_setup                       // Drop to EL1
        bl      set_cpu_boot_mode_flag
        b       secondary_startup
-ENDPROC(secondary_entry)
+SYM_FUNC_END(secondary_entry)
 
-secondary_startup:
+SYM_FUNC_START_LOCAL(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
         */
        bl      __cpu_secondary_check52bitva
+       mov     x0, #ARM64_CPU_BOOT_SECONDARY
        bl      __cpu_setup                     // initialise processor
        adrp    x1, swapper_pg_dir
        bl      __enable_mmu
        ldr     x8, =__secondary_switched
        br      x8
-ENDPROC(secondary_startup)
+SYM_FUNC_END(secondary_startup)
 
-__secondary_switched:
+SYM_FUNC_START_LOCAL(__secondary_switched)
        adr_l   x5, vectors
        msr     vbar_el1, x5
        isb
@@ -734,13 +740,13 @@ __secondary_switched:
        mov     x29, #0
        mov     x30, #0
        b       secondary_start_kernel
-ENDPROC(__secondary_switched)
+SYM_FUNC_END(__secondary_switched)
 
-__secondary_too_slow:
+SYM_FUNC_START_LOCAL(__secondary_too_slow)
        wfe
        wfi
        b       __secondary_too_slow
-ENDPROC(__secondary_too_slow)
+SYM_FUNC_END(__secondary_too_slow)
 
 /*
  * The booting CPU updates the failed status @__early_cpu_boot_status,
@@ -772,7 +778,7 @@ ENDPROC(__secondary_too_slow)
  * Checks if the selected granule size is supported by the CPU.
  * If it isn't, park the CPU
  */
-ENTRY(__enable_mmu)
+SYM_FUNC_START(__enable_mmu)
        mrs     x2, ID_AA64MMFR0_EL1
        ubfx    x2, x2, #ID_AA64MMFR0_TGRAN_SHIFT, 4
        cmp     x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
@@ -796,9 +802,9 @@ ENTRY(__enable_mmu)
        dsb     nsh
        isb
        ret
-ENDPROC(__enable_mmu)
+SYM_FUNC_END(__enable_mmu)
 
-ENTRY(__cpu_secondary_check52bitva)
+SYM_FUNC_START(__cpu_secondary_check52bitva)
 #ifdef CONFIG_ARM64_VA_BITS_52
        ldr_l   x0, vabits_actual
        cmp     x0, #52
@@ -816,9 +822,9 @@ ENTRY(__cpu_secondary_check52bitva)
 
 #endif
 2:     ret
-ENDPROC(__cpu_secondary_check52bitva)
+SYM_FUNC_END(__cpu_secondary_check52bitva)
 
-__no_granule_support:
+SYM_FUNC_START_LOCAL(__no_granule_support)
        /* Indicate that this CPU can't boot and is stuck in the kernel */
        update_early_cpu_boot_status \
                CPU_STUCK_IN_KERNEL | CPU_STUCK_REASON_NO_GRAN, x1, x2
@@ -826,10 +832,10 @@ __no_granule_support:
        wfe
        wfi
        b       1b
-ENDPROC(__no_granule_support)
+SYM_FUNC_END(__no_granule_support)
 
 #ifdef CONFIG_RELOCATABLE
-__relocate_kernel:
+SYM_FUNC_START_LOCAL(__relocate_kernel)
        /*
         * Iterate over each entry in the relocation table, and apply the
         * relocations in place.
@@ -931,10 +937,10 @@ __relocate_kernel:
 #endif
        ret
 
-ENDPROC(__relocate_kernel)
+SYM_FUNC_END(__relocate_kernel)
 #endif
 
-__primary_switch:
+SYM_FUNC_START_LOCAL(__primary_switch)
 #ifdef CONFIG_RANDOMIZE_BASE
        mov     x19, x0                         // preserve new SCTLR_EL1 value
        mrs     x20, sctlr_el1                  // preserve old SCTLR_EL1 value
@@ -977,4 +983,4 @@ __primary_switch:
        ldr     x8, =__primary_switched
        adrp    x0, __PHYS_OFFSET
        br      x8
-ENDPROC(__primary_switch)
+SYM_FUNC_END(__primary_switch)
index 38bcd4d..6532105 100644 (file)
@@ -110,8 +110,6 @@ ENTRY(swsusp_arch_suspend_exit)
        cbz     x24, 3f         /* Do we need to re-initialise EL2? */
        hvc     #0
 3:     ret
-
-       .ltorg
 ENDPROC(swsusp_arch_suspend_exit)
 
 /*
index 590963c..5b73e92 100644 (file)
@@ -166,14 +166,11 @@ int arch_hibernation_header_restore(void *addr)
                sleep_cpu = -EINVAL;
                return -EINVAL;
        }
-       if (!cpu_online(sleep_cpu)) {
-               pr_info("Hibernated on a CPU that is offline! Bringing CPU up.\n");
-               ret = cpu_up(sleep_cpu);
-               if (ret) {
-                       pr_err("Failed to bring hibernate-CPU up!\n");
-                       sleep_cpu = -EINVAL;
-                       return ret;
-               }
+
+       ret = bringup_hibernate_cpu(sleep_cpu);
+       if (ret) {
+               sleep_cpu = -EINVAL;
+               return ret;
        }
 
        resume_hdr = *hdr;
index 73d4607..e473ead 100644 (file)
@@ -63,7 +63,7 @@ el1_sync:
        beq     9f                              // Nothing to reset!
 
        /* Someone called kvm_call_hyp() against the hyp-stub... */
-       ldr     x0, =HVC_STUB_ERR
+       mov_q   x0, HVC_STUB_ERR
        eret
 
 9:     mov     x0, xzr
index 25a2a9b..7f06ad9 100644 (file)
@@ -12,7 +12,9 @@
 
 #ifdef CONFIG_EFI
 
-__efistub_stext_offset = stext - _text;
+__efistub_kernel_size          = _edata - _text;
+__efistub_stext_offset         = stext - _text;
+
 
 /*
  * The EFI stub has its own symbol namespace prefixed by __efistub_, to
@@ -33,7 +35,7 @@ __efistub_strnlen             = __pi_strnlen;
 __efistub_strcmp               = __pi_strcmp;
 __efistub_strncmp              = __pi_strncmp;
 __efistub_strrchr              = __pi_strrchr;
-__efistub___flush_dcache_area  = __pi___flush_dcache_area;
+__efistub___clean_dcache_area_poc = __pi___clean_dcache_area_poc;
 
 #ifdef CONFIG_KASAN
 __efistub___memcpy             = __pi_memcpy;
@@ -45,6 +47,7 @@ __efistub__text                       = _text;
 __efistub__end                 = _end;
 __efistub__edata               = _edata;
 __efistub_screen_info          = screen_info;
+__efistub__ctype               = _ctype;
 
 #endif
 
index dd3ae80..b40c3b0 100644 (file)
@@ -121,7 +121,7 @@ static int setup_dtb(struct kimage *image,
 
        /* add kaslr-seed */
        ret = fdt_delprop(dtb, off, FDT_PROP_KASLR_SEED);
-       if  (ret == -FDT_ERR_NOTFOUND)
+       if (ret == -FDT_ERR_NOTFOUND)
                ret = 0;
        else if (ret)
                goto out;
index e40b656..4d78794 100644 (file)
@@ -285,6 +285,17 @@ static struct attribute_group armv8_pmuv3_format_attr_group = {
 #define        ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
        (ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
 
+
+/*
+ * We unconditionally enable ARMv8.5-PMU long event counter support
+ * (64-bit events) where supported. Indicate if this arm_pmu has long
+ * event counter support.
+ */
+static bool armv8pmu_has_long_event(struct arm_pmu *cpu_pmu)
+{
+       return (cpu_pmu->pmuver >= ID_AA64DFR0_PMUVER_8_5);
+}
+
 /*
  * We must chain two programmable counters for 64 bit events,
  * except when we have allocated the 64bit cycle counter (for CPU
@@ -294,9 +305,11 @@ static struct attribute_group armv8_pmuv3_format_attr_group = {
 static inline bool armv8pmu_event_is_chained(struct perf_event *event)
 {
        int idx = event->hw.idx;
+       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
 
        return !WARN_ON(idx < 0) &&
               armv8pmu_event_is_64bit(event) &&
+              !armv8pmu_has_long_event(cpu_pmu) &&
               (idx != ARMV8_IDX_CYCLE_COUNTER);
 }
 
@@ -345,7 +358,7 @@ static inline void armv8pmu_select_counter(int idx)
        isb();
 }
 
-static inline u32 armv8pmu_read_evcntr(int idx)
+static inline u64 armv8pmu_read_evcntr(int idx)
 {
        armv8pmu_select_counter(idx);
        return read_sysreg(pmxevcntr_el0);
@@ -362,6 +375,44 @@ static inline u64 armv8pmu_read_hw_counter(struct perf_event *event)
        return val;
 }
 
+/*
+ * The cycle counter is always a 64-bit counter. When ARMV8_PMU_PMCR_LP
+ * is set the event counters also become 64-bit counters. Unless the
+ * user has requested a long counter (attr.config1) then we want to
+ * interrupt upon 32-bit overflow - we achieve this by applying a bias.
+ */
+static bool armv8pmu_event_needs_bias(struct perf_event *event)
+{
+       struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+
+       if (armv8pmu_event_is_64bit(event))
+               return false;
+
+       if (armv8pmu_has_long_event(cpu_pmu) ||
+           idx == ARMV8_IDX_CYCLE_COUNTER)
+               return true;
+
+       return false;
+}
+
+static u64 armv8pmu_bias_long_counter(struct perf_event *event, u64 value)
+{
+       if (armv8pmu_event_needs_bias(event))
+               value |= GENMASK(63, 32);
+
+       return value;
+}
+
+static u64 armv8pmu_unbias_long_counter(struct perf_event *event, u64 value)
+{
+       if (armv8pmu_event_needs_bias(event))
+               value &= ~GENMASK(63, 32);
+
+       return value;
+}
+
 static u64 armv8pmu_read_counter(struct perf_event *event)
 {
        struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
@@ -377,10 +428,10 @@ static u64 armv8pmu_read_counter(struct perf_event *event)
        else
                value = armv8pmu_read_hw_counter(event);
 
-       return value;
+       return  armv8pmu_unbias_long_counter(event, value);
 }
 
-static inline void armv8pmu_write_evcntr(int idx, u32 value)
+static inline void armv8pmu_write_evcntr(int idx, u64 value)
 {
        armv8pmu_select_counter(idx);
        write_sysreg(value, pmxevcntr_el0);
@@ -405,20 +456,14 @@ static void armv8pmu_write_counter(struct perf_event *event, u64 value)
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
 
+       value = armv8pmu_bias_long_counter(event, value);
+
        if (!armv8pmu_counter_valid(cpu_pmu, idx))
                pr_err("CPU%u writing wrong counter %d\n",
                        smp_processor_id(), idx);
-       else if (idx == ARMV8_IDX_CYCLE_COUNTER) {
-               /*
-                * The cycles counter is really a 64-bit counter.
-                * When treating it as a 32-bit counter, we only count
-                * the lower 32 bits, and set the upper 32-bits so that
-                * we get an interrupt upon 32-bit overflow.
-                */
-               if (!armv8pmu_event_is_64bit(event))
-                       value |= 0xffffffff00000000ULL;
+       else if (idx == ARMV8_IDX_CYCLE_COUNTER)
                write_sysreg(value, pmccntr_el0);
-       else
+       else
                armv8pmu_write_hw_counter(event, value);
 }
 
@@ -450,86 +495,74 @@ static inline void armv8pmu_write_event_type(struct perf_event *event)
        }
 }
 
-static inline int armv8pmu_enable_counter(int idx)
+static u32 armv8pmu_event_cnten_mask(struct perf_event *event)
 {
-       u32 counter = ARMV8_IDX_TO_COUNTER(idx);
-       write_sysreg(BIT(counter), pmcntenset_el0);
-       return idx;
+       int counter = ARMV8_IDX_TO_COUNTER(event->hw.idx);
+       u32 mask = BIT(counter);
+
+       if (armv8pmu_event_is_chained(event))
+               mask |= BIT(counter - 1);
+       return mask;
+}
+
+static inline void armv8pmu_enable_counter(u32 mask)
+{
+       write_sysreg(mask, pmcntenset_el0);
 }
 
 static inline void armv8pmu_enable_event_counter(struct perf_event *event)
 {
        struct perf_event_attr *attr = &event->attr;
-       int idx = event->hw.idx;
-       u32 counter_bits = BIT(ARMV8_IDX_TO_COUNTER(idx));
+       u32 mask = armv8pmu_event_cnten_mask(event);
 
-       if (armv8pmu_event_is_chained(event))
-               counter_bits |= BIT(ARMV8_IDX_TO_COUNTER(idx - 1));
-
-       kvm_set_pmu_events(counter_bits, attr);
+       kvm_set_pmu_events(mask, attr);
 
        /* We rely on the hypervisor switch code to enable guest counters */
-       if (!kvm_pmu_counter_deferred(attr)) {
-               armv8pmu_enable_counter(idx);
-               if (armv8pmu_event_is_chained(event))
-                       armv8pmu_enable_counter(idx - 1);
-       }
+       if (!kvm_pmu_counter_deferred(attr))
+               armv8pmu_enable_counter(mask);
 }
 
-static inline int armv8pmu_disable_counter(int idx)
+static inline void armv8pmu_disable_counter(u32 mask)
 {
-       u32 counter = ARMV8_IDX_TO_COUNTER(idx);
-       write_sysreg(BIT(counter), pmcntenclr_el0);
-       return idx;
+       write_sysreg(mask, pmcntenclr_el0);
 }
 
 static inline void armv8pmu_disable_event_counter(struct perf_event *event)
 {
-       struct hw_perf_event *hwc = &event->hw;
        struct perf_event_attr *attr = &event->attr;
-       int idx = hwc->idx;
-       u32 counter_bits = BIT(ARMV8_IDX_TO_COUNTER(idx));
-
-       if (armv8pmu_event_is_chained(event))
-               counter_bits |= BIT(ARMV8_IDX_TO_COUNTER(idx - 1));
+       u32 mask = armv8pmu_event_cnten_mask(event);
 
-       kvm_clr_pmu_events(counter_bits);
+       kvm_clr_pmu_events(mask);
 
        /* We rely on the hypervisor switch code to disable guest counters */
-       if (!kvm_pmu_counter_deferred(attr)) {
-               if (armv8pmu_event_is_chained(event))
-                       armv8pmu_disable_counter(idx - 1);
-               armv8pmu_disable_counter(idx);
-       }
+       if (!kvm_pmu_counter_deferred(attr))
+               armv8pmu_disable_counter(mask);
 }
 
-static inline int armv8pmu_enable_intens(int idx)
+static inline void armv8pmu_enable_intens(u32 mask)
 {
-       u32 counter = ARMV8_IDX_TO_COUNTER(idx);
-       write_sysreg(BIT(counter), pmintenset_el1);
-       return idx;
+       write_sysreg(mask, pmintenset_el1);
 }
 
-static inline int armv8pmu_enable_event_irq(struct perf_event *event)
+static inline void armv8pmu_enable_event_irq(struct perf_event *event)
 {
-       return armv8pmu_enable_intens(event->hw.idx);
+       u32 counter = ARMV8_IDX_TO_COUNTER(event->hw.idx);
+       armv8pmu_enable_intens(BIT(counter));
 }
 
-static inline int armv8pmu_disable_intens(int idx)
+static inline void armv8pmu_disable_intens(u32 mask)
 {
-       u32 counter = ARMV8_IDX_TO_COUNTER(idx);
-       write_sysreg(BIT(counter), pmintenclr_el1);
+       write_sysreg(mask, pmintenclr_el1);
        isb();
        /* Clear the overflow flag in case an interrupt is pending. */
-       write_sysreg(BIT(counter), pmovsclr_el0);
+       write_sysreg(mask, pmovsclr_el0);
        isb();
-
-       return idx;
 }
 
-static inline int armv8pmu_disable_event_irq(struct perf_event *event)
+static inline void armv8pmu_disable_event_irq(struct perf_event *event)
 {
-       return armv8pmu_disable_intens(event->hw.idx);
+       u32 counter = ARMV8_IDX_TO_COUNTER(event->hw.idx);
+       armv8pmu_disable_intens(BIT(counter));
 }
 
 static inline u32 armv8pmu_getreset_flags(void)
@@ -743,7 +776,8 @@ static int armv8pmu_get_event_idx(struct pmu_hw_events *cpuc,
        /*
         * Otherwise use events counters
         */
-       if (armv8pmu_event_is_64bit(event))
+       if (armv8pmu_event_is_64bit(event) &&
+           !armv8pmu_has_long_event(cpu_pmu))
                return  armv8pmu_get_chain_idx(cpuc, cpu_pmu);
        else
                return armv8pmu_get_single_idx(cpuc, cpu_pmu);
@@ -815,13 +849,11 @@ static int armv8pmu_filter_match(struct perf_event *event)
 static void armv8pmu_reset(void *info)
 {
        struct arm_pmu *cpu_pmu = (struct arm_pmu *)info;
-       u32 idx, nb_cnt = cpu_pmu->num_events;
+       u32 pmcr;
 
        /* The counter and interrupt enable registers are unknown at reset. */
-       for (idx = ARMV8_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx) {
-               armv8pmu_disable_counter(idx);
-               armv8pmu_disable_intens(idx);
-       }
+       armv8pmu_disable_counter(U32_MAX);
+       armv8pmu_disable_intens(U32_MAX);
 
        /* Clear the counters we flip at guest entry/exit */
        kvm_clr_pmu_events(U32_MAX);
@@ -830,8 +862,13 @@ static void armv8pmu_reset(void *info)
         * Initialize & Reset PMNC. Request overflow interrupt for
         * 64 bit cycle counter but cheat in armv8pmu_write_counter().
         */
-       armv8pmu_pmcr_write(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C |
-                           ARMV8_PMU_PMCR_LC);
+       pmcr = ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C | ARMV8_PMU_PMCR_LC;
+
+       /* Enable long event counter support where available */
+       if (armv8pmu_has_long_event(cpu_pmu))
+               pmcr |= ARMV8_PMU_PMCR_LP;
+
+       armv8pmu_pmcr_write(pmcr);
 }
 
 static int __armv8_pmuv3_map_event(struct perf_event *event,
@@ -914,6 +951,7 @@ static void __armv8pmu_probe_pmu(void *info)
        if (pmuver == 0xf || pmuver == 0)
                return;
 
+       cpu_pmu->pmuver = pmuver;
        probe->present = true;
 
        /* Read the nb of CNTx counters supported from PMNC */
@@ -953,7 +991,10 @@ static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu)
        return probe.present ? 0 : -ENODEV;
 }
 
-static int armv8_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name,
+                         int (*map_event)(struct perf_event *event),
+                         const struct attribute_group *events,
+                         const struct attribute_group *format)
 {
        int ret = armv8pmu_probe_pmu(cpu_pmu);
        if (ret)
@@ -972,144 +1013,127 @@ static int armv8_pmu_init(struct arm_pmu *cpu_pmu)
        cpu_pmu->set_event_filter       = armv8pmu_set_event_filter;
        cpu_pmu->filter_match           = armv8pmu_filter_match;
 
+       cpu_pmu->name                   = name;
+       cpu_pmu->map_event              = map_event;
+       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] = events ?
+                       events : &armv8_pmuv3_events_attr_group;
+       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = format ?
+                       format : &armv8_pmuv3_format_attr_group;
+
        return 0;
 }
 
 static int armv8_pmuv3_init(struct arm_pmu *cpu_pmu)
 {
-       int ret = armv8_pmu_init(cpu_pmu);
-       if (ret)
-               return ret;
-
-       cpu_pmu->name                   = "armv8_pmuv3";
-       cpu_pmu->map_event              = armv8_pmuv3_map_event;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] =
-               &armv8_pmuv3_events_attr_group;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
-               &armv8_pmuv3_format_attr_group;
+       return armv8_pmu_init(cpu_pmu, "armv8_pmuv3",
+                             armv8_pmuv3_map_event, NULL, NULL);
+}
 
-       return 0;
+static int armv8_a34_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a34",
+                             armv8_pmuv3_map_event, NULL, NULL);
 }
 
 static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       int ret = armv8_pmu_init(cpu_pmu);
-       if (ret)
-               return ret;
-
-       cpu_pmu->name                   = "armv8_cortex_a35";
-       cpu_pmu->map_event              = armv8_a53_map_event;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] =
-               &armv8_pmuv3_events_attr_group;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
-               &armv8_pmuv3_format_attr_group;
-
-       return 0;
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a35",
+                             armv8_a53_map_event, NULL, NULL);
 }
 
 static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       int ret = armv8_pmu_init(cpu_pmu);
-       if (ret)
-               return ret;
-
-       cpu_pmu->name                   = "armv8_cortex_a53";
-       cpu_pmu->map_event              = armv8_a53_map_event;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] =
-               &armv8_pmuv3_events_attr_group;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
-               &armv8_pmuv3_format_attr_group;
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a53",
+                             armv8_a53_map_event, NULL, NULL);
+}
 
-       return 0;
+static int armv8_a55_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a55",
+                             armv8_pmuv3_map_event, NULL, NULL);
 }
 
 static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       int ret = armv8_pmu_init(cpu_pmu);
-       if (ret)
-               return ret;
-
-       cpu_pmu->name                   = "armv8_cortex_a57";
-       cpu_pmu->map_event              = armv8_a57_map_event;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] =
-               &armv8_pmuv3_events_attr_group;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
-               &armv8_pmuv3_format_attr_group;
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a57",
+                             armv8_a57_map_event, NULL, NULL);
+}
 
-       return 0;
+static int armv8_a65_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a65",
+                             armv8_pmuv3_map_event, NULL, NULL);
 }
 
 static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       int ret = armv8_pmu_init(cpu_pmu);
-       if (ret)
-               return ret;
-
-       cpu_pmu->name                   = "armv8_cortex_a72";
-       cpu_pmu->map_event              = armv8_a57_map_event;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] =
-               &armv8_pmuv3_events_attr_group;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
-               &armv8_pmuv3_format_attr_group;
-
-       return 0;
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a72",
+                             armv8_a57_map_event, NULL, NULL);
 }
 
 static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       int ret = armv8_pmu_init(cpu_pmu);
-       if (ret)
-               return ret;
-
-       cpu_pmu->name                   = "armv8_cortex_a73";
-       cpu_pmu->map_event              = armv8_a73_map_event;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] =
-               &armv8_pmuv3_events_attr_group;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
-               &armv8_pmuv3_format_attr_group;
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a73",
+                             armv8_a73_map_event, NULL, NULL);
+}
 
-       return 0;
+static int armv8_a75_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a75",
+                             armv8_pmuv3_map_event, NULL, NULL);
 }
 
-static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv8_a76_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       int ret = armv8_pmu_init(cpu_pmu);
-       if (ret)
-               return ret;
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a76",
+                             armv8_pmuv3_map_event, NULL, NULL);
+}
 
-       cpu_pmu->name                   = "armv8_cavium_thunder";
-       cpu_pmu->map_event              = armv8_thunder_map_event;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] =
-               &armv8_pmuv3_events_attr_group;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
-               &armv8_pmuv3_format_attr_group;
+static int armv8_a77_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return armv8_pmu_init(cpu_pmu, "armv8_cortex_a77",
+                             armv8_pmuv3_map_event, NULL, NULL);
+}
 
-       return 0;
+static int armv8_e1_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return armv8_pmu_init(cpu_pmu, "armv8_neoverse_e1",
+                             armv8_pmuv3_map_event, NULL, NULL);
 }
 
-static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu)
+static int armv8_n1_pmu_init(struct arm_pmu *cpu_pmu)
 {
-       int ret = armv8_pmu_init(cpu_pmu);
-       if (ret)
-               return ret;
+       return armv8_pmu_init(cpu_pmu, "armv8_neoverse_n1",
+                             armv8_pmuv3_map_event, NULL, NULL);
+}
 
-       cpu_pmu->name                   = "armv8_brcm_vulcan";
-       cpu_pmu->map_event              = armv8_vulcan_map_event;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_EVENTS] =
-               &armv8_pmuv3_events_attr_group;
-       cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
-               &armv8_pmuv3_format_attr_group;
+static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return armv8_pmu_init(cpu_pmu, "armv8_cavium_thunder",
+                             armv8_thunder_map_event, NULL, NULL);
+}
 
-       return 0;
+static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       return armv8_pmu_init(cpu_pmu, "armv8_brcm_vulcan",
+                             armv8_vulcan_map_event, NULL, NULL);
 }
 
 static const struct of_device_id armv8_pmu_of_device_ids[] = {
        {.compatible = "arm,armv8-pmuv3",       .data = armv8_pmuv3_init},
+       {.compatible = "arm,cortex-a34-pmu",    .data = armv8_a34_pmu_init},
        {.compatible = "arm,cortex-a35-pmu",    .data = armv8_a35_pmu_init},
        {.compatible = "arm,cortex-a53-pmu",    .data = armv8_a53_pmu_init},
+       {.compatible = "arm,cortex-a55-pmu",    .data = armv8_a55_pmu_init},
        {.compatible = "arm,cortex-a57-pmu",    .data = armv8_a57_pmu_init},
+       {.compatible = "arm,cortex-a65-pmu",    .data = armv8_a65_pmu_init},
        {.compatible = "arm,cortex-a72-pmu",    .data = armv8_a72_pmu_init},
        {.compatible = "arm,cortex-a73-pmu",    .data = armv8_a73_pmu_init},
+       {.compatible = "arm,cortex-a75-pmu",    .data = armv8_a75_pmu_init},
+       {.compatible = "arm,cortex-a76-pmu",    .data = armv8_a76_pmu_init},
+       {.compatible = "arm,cortex-a77-pmu",    .data = armv8_a77_pmu_init},
+       {.compatible = "arm,neoverse-e1-pmu",   .data = armv8_e1_pmu_init},
+       {.compatible = "arm,neoverse-n1-pmu",   .data = armv8_n1_pmu_init},
        {.compatible = "cavium,thunder-pmu",    .data = armv8_thunder_pmu_init},
        {.compatible = "brcm,vulcan-pmu",       .data = armv8_vulcan_pmu_init},
        {},
index c507b58..1e77736 100644 (file)
@@ -9,7 +9,7 @@
 
 int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg)
 {
-       struct ptrauth_keys *keys = &tsk->thread.keys_user;
+       struct ptrauth_keys_user *keys = &tsk->thread.keys_user;
        unsigned long addr_key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
                                      PR_PAC_APDAKEY | PR_PAC_APDBKEY;
        unsigned long key_mask = addr_key_mask | PR_PAC_APGAKEY;
@@ -18,8 +18,7 @@ int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg)
                return -EINVAL;
 
        if (!arg) {
-               ptrauth_keys_init(keys);
-               ptrauth_keys_switch(keys);
+               ptrauth_keys_init_user(keys);
                return 0;
        }
 
@@ -41,7 +40,5 @@ int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg)
        if (arg & PR_PAC_APGAKEY)
                get_random_bytes(&keys->apga, sizeof(keys->apga));
 
-       ptrauth_keys_switch(keys);
-
        return 0;
 }
index 0062605..56be4cb 100644 (file)
@@ -141,11 +141,11 @@ void arch_cpu_idle_dead(void)
  * to execute e.g. a RAM-based pin loop is not sufficient. This allows the
  * kexec'd kernel to use any and all RAM as it sees fit, without having to
  * avoid any code or data used by any SW CPU pin loop. The CPU hotplug
- * functionality embodied in disable_nonboot_cpus() to achieve this.
+ * functionality embodied in smpt_shutdown_nonboot_cpus() to achieve this.
  */
 void machine_shutdown(void)
 {
-       disable_nonboot_cpus();
+       smp_shutdown_nonboot_cpus(reboot_cpu);
 }
 
 /*
@@ -262,7 +262,7 @@ void __show_regs(struct pt_regs *regs)
 
        if (!user_mode(regs)) {
                printk("pc : %pS\n", (void *)regs->pc);
-               printk("lr : %pS\n", (void *)lr);
+               printk("lr : %pS\n", (void *)ptrauth_strip_insn_pac(lr));
        } else {
                printk("pc : %016llx\n", regs->pc);
                printk("lr : %016llx\n", lr);
@@ -376,6 +376,8 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long stack_start,
         */
        fpsimd_flush_task_state(p);
 
+       ptrauth_thread_init_kernel(p);
+
        if (likely(!(p->flags & PF_KTHREAD))) {
                *childregs = *current_pt_regs();
                childregs->regs[0] = 0;
@@ -512,7 +514,6 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
        contextidr_thread_switch(next);
        entry_task_switch(next);
        uao_thread_switch(next);
-       ptrauth_thread_switch(next);
        ssbs_thread_switch(next);
 
        /*
index cd6e5fa..b3d3005 100644 (file)
@@ -999,7 +999,7 @@ static struct ptrauth_key pac_key_from_user(__uint128_t ukey)
 }
 
 static void pac_address_keys_to_user(struct user_pac_address_keys *ukeys,
-                                    const struct ptrauth_keys *keys)
+                                    const struct ptrauth_keys_user *keys)
 {
        ukeys->apiakey = pac_key_to_user(&keys->apia);
        ukeys->apibkey = pac_key_to_user(&keys->apib);
@@ -1007,7 +1007,7 @@ static void pac_address_keys_to_user(struct user_pac_address_keys *ukeys,
        ukeys->apdbkey = pac_key_to_user(&keys->apdb);
 }
 
-static void pac_address_keys_from_user(struct ptrauth_keys *keys,
+static void pac_address_keys_from_user(struct ptrauth_keys_user *keys,
                                       const struct user_pac_address_keys *ukeys)
 {
        keys->apia = pac_key_from_user(ukeys->apiakey);
@@ -1021,7 +1021,7 @@ static int pac_address_keys_get(struct task_struct *target,
                                unsigned int pos, unsigned int count,
                                void *kbuf, void __user *ubuf)
 {
-       struct ptrauth_keys *keys = &target->thread.keys_user;
+       struct ptrauth_keys_user *keys = &target->thread.keys_user;
        struct user_pac_address_keys user_keys;
 
        if (!system_supports_address_auth())
@@ -1038,7 +1038,7 @@ static int pac_address_keys_set(struct task_struct *target,
                                unsigned int pos, unsigned int count,
                                const void *kbuf, const void __user *ubuf)
 {
-       struct ptrauth_keys *keys = &target->thread.keys_user;
+       struct ptrauth_keys_user *keys = &target->thread.keys_user;
        struct user_pac_address_keys user_keys;
        int ret;
 
@@ -1056,12 +1056,12 @@ static int pac_address_keys_set(struct task_struct *target,
 }
 
 static void pac_generic_keys_to_user(struct user_pac_generic_keys *ukeys,
-                                    const struct ptrauth_keys *keys)
+                                    const struct ptrauth_keys_user *keys)
 {
        ukeys->apgakey = pac_key_to_user(&keys->apga);
 }
 
-static void pac_generic_keys_from_user(struct ptrauth_keys *keys,
+static void pac_generic_keys_from_user(struct ptrauth_keys_user *keys,
                                       const struct user_pac_generic_keys *ukeys)
 {
        keys->apga = pac_key_from_user(ukeys->apgakey);
@@ -1072,7 +1072,7 @@ static int pac_generic_keys_get(struct task_struct *target,
                                unsigned int pos, unsigned int count,
                                void *kbuf, void __user *ubuf)
 {
-       struct ptrauth_keys *keys = &target->thread.keys_user;
+       struct ptrauth_keys_user *keys = &target->thread.keys_user;
        struct user_pac_generic_keys user_keys;
 
        if (!system_supports_generic_auth())
@@ -1089,7 +1089,7 @@ static int pac_generic_keys_set(struct task_struct *target,
                                unsigned int pos, unsigned int count,
                                const void *kbuf, const void __user *ubuf)
 {
-       struct ptrauth_keys *keys = &target->thread.keys_user;
+       struct ptrauth_keys_user *keys = &target->thread.keys_user;
        struct user_pac_generic_keys user_keys;
        int ret;
 
index c1d7db7..c40ce49 100644 (file)
@@ -41,7 +41,7 @@ ENTRY(arm64_relocate_new_kernel)
        cmp     x0, #CurrentEL_EL2
        b.ne    1f
        mrs     x0, sctlr_el2
-       ldr     x1, =SCTLR_ELx_FLAGS
+       mov_q   x1, SCTLR_ELx_FLAGS
        bic     x0, x0, x1
        pre_disable_mmu_workaround
        msr     sctlr_el2, x0
@@ -113,8 +113,6 @@ ENTRY(arm64_relocate_new_kernel)
 
 ENDPROC(arm64_relocate_new_kernel)
 
-.ltorg
-
 .align 3       /* To keep the 64-bit values below naturally aligned. */
 
 .Lcopy_end:
index a34890b..3fd2c11 100644 (file)
@@ -344,7 +344,7 @@ void __init setup_arch(char **cmdline_p)
        else
                psci_acpi_init();
 
-       cpu_read_bootcpu_ops();
+       init_bootcpu_ops();
        smp_init_cpus();
        smp_build_mpidr_hash();
 
@@ -371,8 +371,10 @@ void __init setup_arch(char **cmdline_p)
 static inline bool cpu_can_disable(unsigned int cpu)
 {
 #ifdef CONFIG_HOTPLUG_CPU
-       if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_can_disable)
-               return cpu_ops[cpu]->cpu_can_disable(cpu);
+       const struct cpu_operations *ops = get_cpu_ops(cpu);
+
+       if (ops && ops->cpu_can_disable)
+               return ops->cpu_can_disable(cpu);
 #endif
        return false;
 }
index f5b04dd..7b2f2e6 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/assembler.h>
+#include <asm/smp.h>
 
        .text
 /*
@@ -99,6 +100,7 @@ ENDPROC(__cpu_suspend_enter)
        .pushsection ".idmap.text", "awx"
 ENTRY(cpu_resume)
        bl      el2_setup               // if in EL2 drop to EL1 cleanly
+       mov     x0, #ARM64_CPU_RUNTIME
        bl      __cpu_setup
        /* enable the MMU early - so we can access sleep_save_stash by va */
        adrp    x1, swapper_pg_dir
index d4ed9a1..061f60f 100644 (file)
@@ -93,8 +93,10 @@ static inline int op_cpu_kill(unsigned int cpu)
  */
 static int boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
-       if (cpu_ops[cpu]->cpu_boot)
-               return cpu_ops[cpu]->cpu_boot(cpu);
+       const struct cpu_operations *ops = get_cpu_ops(cpu);
+
+       if (ops->cpu_boot)
+               return ops->cpu_boot(cpu);
 
        return -EOPNOTSUPP;
 }
@@ -112,63 +114,66 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
         */
        secondary_data.task = idle;
        secondary_data.stack = task_stack_page(idle) + THREAD_SIZE;
+#if defined(CONFIG_ARM64_PTR_AUTH)
+       secondary_data.ptrauth_key.apia.lo = idle->thread.keys_kernel.apia.lo;
+       secondary_data.ptrauth_key.apia.hi = idle->thread.keys_kernel.apia.hi;
+#endif
        update_cpu_boot_status(CPU_MMU_OFF);
        __flush_dcache_area(&secondary_data, sizeof(secondary_data));
 
-       /*
-        * Now bring the CPU into our world.
-        */
+       /* Now bring the CPU into our world */
        ret = boot_secondary(cpu, idle);
-       if (ret == 0) {
-               /*
-                * CPU was successfully started, wait for it to come online or
-                * time out.
-                */
-               wait_for_completion_timeout(&cpu_running,
-                                           msecs_to_jiffies(5000));
-
-               if (!cpu_online(cpu)) {
-                       pr_crit("CPU%u: failed to come online\n", cpu);
-                       ret = -EIO;
-               }
-       } else {
+       if (ret) {
                pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
                return ret;
        }
 
+       /*
+        * CPU was successfully started, wait for it to come online or
+        * time out.
+        */
+       wait_for_completion_timeout(&cpu_running,
+                                   msecs_to_jiffies(5000));
+       if (cpu_online(cpu))
+               return 0;
+
+       pr_crit("CPU%u: failed to come online\n", cpu);
        secondary_data.task = NULL;
        secondary_data.stack = NULL;
+#if defined(CONFIG_ARM64_PTR_AUTH)
+       secondary_data.ptrauth_key.apia.lo = 0;
+       secondary_data.ptrauth_key.apia.hi = 0;
+#endif
        __flush_dcache_area(&secondary_data, sizeof(secondary_data));
        status = READ_ONCE(secondary_data.status);
-       if (ret && status) {
-
-               if (status == CPU_MMU_OFF)
-                       status = READ_ONCE(__early_cpu_boot_status);
+       if (status == CPU_MMU_OFF)
+               status = READ_ONCE(__early_cpu_boot_status);
 
-               switch (status & CPU_BOOT_STATUS_MASK) {
-               default:
-                       pr_err("CPU%u: failed in unknown state : 0x%lx\n",
-                                       cpu, status);
-                       cpus_stuck_in_kernel++;
-                       break;
-               case CPU_KILL_ME:
-                       if (!op_cpu_kill(cpu)) {
-                               pr_crit("CPU%u: died during early boot\n", cpu);
-                               break;
-                       }
-                       pr_crit("CPU%u: may not have shut down cleanly\n", cpu);
-                       /* Fall through */
-               case CPU_STUCK_IN_KERNEL:
-                       pr_crit("CPU%u: is stuck in kernel\n", cpu);
-                       if (status & CPU_STUCK_REASON_52_BIT_VA)
-                               pr_crit("CPU%u: does not support 52-bit VAs\n", cpu);
-                       if (status & CPU_STUCK_REASON_NO_GRAN)
-                               pr_crit("CPU%u: does not support %luK granule \n", cpu, PAGE_SIZE / SZ_1K);
-                       cpus_stuck_in_kernel++;
+       switch (status & CPU_BOOT_STATUS_MASK) {
+       default:
+               pr_err("CPU%u: failed in unknown state : 0x%lx\n",
+                      cpu, status);
+               cpus_stuck_in_kernel++;
+               break;
+       case CPU_KILL_ME:
+               if (!op_cpu_kill(cpu)) {
+                       pr_crit("CPU%u: died during early boot\n", cpu);
                        break;
-               case CPU_PANIC_KERNEL:
-                       panic("CPU%u detected unsupported configuration\n", cpu);
                }
+               pr_crit("CPU%u: may not have shut down cleanly\n", cpu);
+               /* Fall through */
+       case CPU_STUCK_IN_KERNEL:
+               pr_crit("CPU%u: is stuck in kernel\n", cpu);
+               if (status & CPU_STUCK_REASON_52_BIT_VA)
+                       pr_crit("CPU%u: does not support 52-bit VAs\n", cpu);
+               if (status & CPU_STUCK_REASON_NO_GRAN) {
+                       pr_crit("CPU%u: does not support %luK granule\n",
+                               cpu, PAGE_SIZE / SZ_1K);
+               }
+               cpus_stuck_in_kernel++;
+               break;
+       case CPU_PANIC_KERNEL:
+               panic("CPU%u detected unsupported configuration\n", cpu);
        }
 
        return ret;
@@ -196,6 +201,7 @@ asmlinkage notrace void secondary_start_kernel(void)
 {
        u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
        struct mm_struct *mm = &init_mm;
+       const struct cpu_operations *ops;
        unsigned int cpu;
 
        cpu = task_cpu(current);
@@ -227,8 +233,9 @@ asmlinkage notrace void secondary_start_kernel(void)
         */
        check_local_cpu_capabilities();
 
-       if (cpu_ops[cpu]->cpu_postboot)
-               cpu_ops[cpu]->cpu_postboot();
+       ops = get_cpu_ops(cpu);
+       if (ops->cpu_postboot)
+               ops->cpu_postboot();
 
        /*
         * Log the CPU info before it is marked online and might get read.
@@ -266,19 +273,21 @@ asmlinkage notrace void secondary_start_kernel(void)
 #ifdef CONFIG_HOTPLUG_CPU
 static int op_cpu_disable(unsigned int cpu)
 {
+       const struct cpu_operations *ops = get_cpu_ops(cpu);
+
        /*
         * If we don't have a cpu_die method, abort before we reach the point
         * of no return. CPU0 may not have an cpu_ops, so test for it.
         */
-       if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_die)
+       if (!ops || !ops->cpu_die)
                return -EOPNOTSUPP;
 
        /*
         * We may need to abort a hot unplug for some other mechanism-specific
         * reason.
         */
-       if (cpu_ops[cpu]->cpu_disable)
-               return cpu_ops[cpu]->cpu_disable(cpu);
+       if (ops->cpu_disable)
+               return ops->cpu_disable(cpu);
 
        return 0;
 }
@@ -314,15 +323,17 @@ int __cpu_disable(void)
 
 static int op_cpu_kill(unsigned int cpu)
 {
+       const struct cpu_operations *ops = get_cpu_ops(cpu);
+
        /*
         * If we have no means of synchronising with the dying CPU, then assume
         * that it is really dead. We can only wait for an arbitrary length of
         * time and hope that it's dead, so let's skip the wait and just hope.
         */
-       if (!cpu_ops[cpu]->cpu_kill)
+       if (!ops->cpu_kill)
                return 0;
 
-       return cpu_ops[cpu]->cpu_kill(cpu);
+       return ops->cpu_kill(cpu);
 }
 
 /*
@@ -357,6 +368,7 @@ void __cpu_die(unsigned int cpu)
 void cpu_die(void)
 {
        unsigned int cpu = smp_processor_id();
+       const struct cpu_operations *ops = get_cpu_ops(cpu);
 
        idle_task_exit();
 
@@ -370,12 +382,22 @@ void cpu_die(void)
         * mechanism must perform all required cache maintenance to ensure that
         * no dirty lines are lost in the process of shutting down the CPU.
         */
-       cpu_ops[cpu]->cpu_die(cpu);
+       ops->cpu_die(cpu);
 
        BUG();
 }
 #endif
 
+static void __cpu_try_die(int cpu)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       const struct cpu_operations *ops = get_cpu_ops(cpu);
+
+       if (ops && ops->cpu_die)
+               ops->cpu_die(cpu);
+#endif
+}
+
 /*
  * Kill the calling secondary CPU, early in bringup before it is turned
  * online.
@@ -389,12 +411,11 @@ void cpu_die_early(void)
        /* Mark this CPU absent */
        set_cpu_present(cpu, 0);
 
-#ifdef CONFIG_HOTPLUG_CPU
-       update_cpu_boot_status(CPU_KILL_ME);
-       /* Check if we can park ourselves */
-       if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_die)
-               cpu_ops[cpu]->cpu_die(cpu);
-#endif
+       if (IS_ENABLED(CONFIG_HOTPLUG_CPU)) {
+               update_cpu_boot_status(CPU_KILL_ME);
+               __cpu_try_die(cpu);
+       }
+
        update_cpu_boot_status(CPU_STUCK_IN_KERNEL);
 
        cpu_park_loop();
@@ -488,10 +509,13 @@ static bool __init is_mpidr_duplicate(unsigned int cpu, u64 hwid)
  */
 static int __init smp_cpu_setup(int cpu)
 {
-       if (cpu_read_ops(cpu))
+       const struct cpu_operations *ops;
+
+       if (init_cpu_ops(cpu))
                return -ENODEV;
 
-       if (cpu_ops[cpu]->cpu_init(cpu))
+       ops = get_cpu_ops(cpu);
+       if (ops->cpu_init(cpu))
                return -ENODEV;
 
        set_cpu_possible(cpu, true);
@@ -714,6 +738,7 @@ void __init smp_init_cpus(void)
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
+       const struct cpu_operations *ops;
        int err;
        unsigned int cpu;
        unsigned int this_cpu;
@@ -744,10 +769,11 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                if (cpu == smp_processor_id())
                        continue;
 
-               if (!cpu_ops[cpu])
+               ops = get_cpu_ops(cpu);
+               if (!ops)
                        continue;
 
-               err = cpu_ops[cpu]->cpu_prepare(cpu);
+               err = ops->cpu_prepare(cpu);
                if (err)
                        continue;
 
@@ -863,10 +889,8 @@ static void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs)
        local_irq_disable();
        sdei_mask_local_cpu();
 
-#ifdef CONFIG_HOTPLUG_CPU
-       if (cpu_ops[cpu]->cpu_die)
-               cpu_ops[cpu]->cpu_die(cpu);
-#endif
+       if (IS_ENABLED(CONFIG_HOTPLUG_CPU))
+               __cpu_try_die(cpu);
 
        /* just in case */
        cpu_park_loop();
@@ -958,11 +982,22 @@ void tick_broadcast(const struct cpumask *mask)
 }
 #endif
 
+/*
+ * The number of CPUs online, not counting this CPU (which may not be
+ * fully online and so not counted in num_online_cpus()).
+ */
+static inline unsigned int num_other_online_cpus(void)
+{
+       unsigned int this_cpu_online = cpu_online(smp_processor_id());
+
+       return num_online_cpus() - this_cpu_online;
+}
+
 void smp_send_stop(void)
 {
        unsigned long timeout;
 
-       if (num_online_cpus() > 1) {
+       if (num_other_online_cpus()) {
                cpumask_t mask;
 
                cpumask_copy(&mask, cpu_online_mask);
@@ -975,10 +1010,10 @@ void smp_send_stop(void)
 
        /* Wait up to one second for other CPUs to stop */
        timeout = USEC_PER_SEC;
-       while (num_online_cpus() > 1 && timeout--)
+       while (num_other_online_cpus() && timeout--)
                udelay(1);
 
-       if (num_online_cpus() > 1)
+       if (num_other_online_cpus())
                pr_warn("SMP: failed to stop secondary CPUs %*pbl\n",
                        cpumask_pr_args(cpu_online_mask));
 
@@ -1001,7 +1036,11 @@ void crash_smp_send_stop(void)
 
        cpus_stopped = 1;
 
-       if (num_online_cpus() == 1) {
+       /*
+        * If this cpu is the only one alive at this point in time, online or
+        * not, there are no stop messages to be sent around, so just back out.
+        */
+       if (num_other_online_cpus() == 0) {
                sdei_mask_local_cpu();
                return;
        }
@@ -1009,7 +1048,7 @@ void crash_smp_send_stop(void)
        cpumask_copy(&mask, cpu_online_mask);
        cpumask_clear_cpu(smp_processor_id(), &mask);
 
-       atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+       atomic_set(&waiting_for_crash_ipi, num_other_online_cpus());
 
        pr_crit("SMP: stopping secondary CPUs\n");
        smp_cross_call(&mask, IPI_CPU_CRASH_STOP);
@@ -1044,8 +1083,9 @@ static bool have_cpu_die(void)
 {
 #ifdef CONFIG_HOTPLUG_CPU
        int any_cpu = raw_smp_processor_id();
+       const struct cpu_operations *ops = get_cpu_ops(any_cpu);
 
-       if (cpu_ops[any_cpu] && cpu_ops[any_cpu]->cpu_die)
+       if (ops && ops->cpu_die)
                return true;
 #endif
        return false;
index a336cb1..139679c 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/stacktrace.h>
 
 #include <asm/irq.h>
+#include <asm/pointer_auth.h>
 #include <asm/stack_pointer.h>
 #include <asm/stacktrace.h>
 
@@ -86,7 +87,7 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        if (tsk->ret_stack &&
-                       (frame->pc == (unsigned long)return_to_handler)) {
+               (ptrauth_strip_insn_pac(frame->pc) == (unsigned long)return_to_handler)) {
                struct ftrace_ret_stack *ret_stack;
                /*
                 * This is a case where function graph tracer has
@@ -101,6 +102,8 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
        }
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 
+       frame->pc = ptrauth_strip_insn_pac(frame->pc);
+
        /*
         * Frames created upon entry from EL0 have NULL FP and PC values, so
         * don't bother reporting these. Frames created by __noreturn functions
index fa9528d..0801a0f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/acpi.h>
 #include <linux/arch_topology.h>
 #include <linux/cacheinfo.h>
+#include <linux/cpufreq.h>
 #include <linux/init.h>
 #include <linux/percpu.h>
 
@@ -120,4 +121,183 @@ int __init parse_acpi_topology(void)
 }
 #endif
 
+#ifdef CONFIG_ARM64_AMU_EXTN
 
+#undef pr_fmt
+#define pr_fmt(fmt) "AMU: " fmt
+
+static DEFINE_PER_CPU_READ_MOSTLY(unsigned long, arch_max_freq_scale);
+static DEFINE_PER_CPU(u64, arch_const_cycles_prev);
+static DEFINE_PER_CPU(u64, arch_core_cycles_prev);
+static cpumask_var_t amu_fie_cpus;
+
+/* Initialize counter reference per-cpu variables for the current CPU */
+void init_cpu_freq_invariance_counters(void)
+{
+       this_cpu_write(arch_core_cycles_prev,
+                      read_sysreg_s(SYS_AMEVCNTR0_CORE_EL0));
+       this_cpu_write(arch_const_cycles_prev,
+                      read_sysreg_s(SYS_AMEVCNTR0_CONST_EL0));
+}
+
+static int validate_cpu_freq_invariance_counters(int cpu)
+{
+       u64 max_freq_hz, ratio;
+
+       if (!cpu_has_amu_feat(cpu)) {
+               pr_debug("CPU%d: counters are not supported.\n", cpu);
+               return -EINVAL;
+       }
+
+       if (unlikely(!per_cpu(arch_const_cycles_prev, cpu) ||
+                    !per_cpu(arch_core_cycles_prev, cpu))) {
+               pr_debug("CPU%d: cycle counters are not enabled.\n", cpu);
+               return -EINVAL;
+       }
+
+       /* Convert maximum frequency from KHz to Hz and validate */
+       max_freq_hz = cpufreq_get_hw_max_freq(cpu) * 1000;
+       if (unlikely(!max_freq_hz)) {
+               pr_debug("CPU%d: invalid maximum frequency.\n", cpu);
+               return -EINVAL;
+       }
+
+       /*
+        * Pre-compute the fixed ratio between the frequency of the constant
+        * counter and the maximum frequency of the CPU.
+        *
+        *                            const_freq
+        * arch_max_freq_scale =   ---------------- * SCHED_CAPACITY_SCALE²
+        *                         cpuinfo_max_freq
+        *
+        * We use a factor of 2 * SCHED_CAPACITY_SHIFT -> SCHED_CAPACITY_SCALE²
+        * in order to ensure a good resolution for arch_max_freq_scale for
+        * very low arch timer frequencies (down to the KHz range which should
+        * be unlikely).
+        */
+       ratio = (u64)arch_timer_get_rate() << (2 * SCHED_CAPACITY_SHIFT);
+       ratio = div64_u64(ratio, max_freq_hz);
+       if (!ratio) {
+               WARN_ONCE(1, "System timer frequency too low.\n");
+               return -EINVAL;
+       }
+
+       per_cpu(arch_max_freq_scale, cpu) = (unsigned long)ratio;
+
+       return 0;
+}
+
+static inline bool
+enable_policy_freq_counters(int cpu, cpumask_var_t valid_cpus)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+
+       if (!policy) {
+               pr_debug("CPU%d: No cpufreq policy found.\n", cpu);
+               return false;
+       }
+
+       if (cpumask_subset(policy->related_cpus, valid_cpus))
+               cpumask_or(amu_fie_cpus, policy->related_cpus,
+                          amu_fie_cpus);
+
+       cpufreq_cpu_put(policy);
+
+       return true;
+}
+
+static DEFINE_STATIC_KEY_FALSE(amu_fie_key);
+#define amu_freq_invariant() static_branch_unlikely(&amu_fie_key)
+
+static int __init init_amu_fie(void)
+{
+       cpumask_var_t valid_cpus;
+       bool have_policy = false;
+       int ret = 0;
+       int cpu;
+
+       if (!zalloc_cpumask_var(&valid_cpus, GFP_KERNEL))
+               return -ENOMEM;
+
+       if (!zalloc_cpumask_var(&amu_fie_cpus, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto free_valid_mask;
+       }
+
+       for_each_present_cpu(cpu) {
+               if (validate_cpu_freq_invariance_counters(cpu))
+                       continue;
+               cpumask_set_cpu(cpu, valid_cpus);
+               have_policy |= enable_policy_freq_counters(cpu, valid_cpus);
+       }
+
+       /*
+        * If we are not restricted by cpufreq policies, we only enable
+        * the use of the AMU feature for FIE if all CPUs support AMU.
+        * Otherwise, enable_policy_freq_counters has already enabled
+        * policy cpus.
+        */
+       if (!have_policy && cpumask_equal(valid_cpus, cpu_present_mask))
+               cpumask_or(amu_fie_cpus, amu_fie_cpus, valid_cpus);
+
+       if (!cpumask_empty(amu_fie_cpus)) {
+               pr_info("CPUs[%*pbl]: counters will be used for FIE.",
+                       cpumask_pr_args(amu_fie_cpus));
+               static_branch_enable(&amu_fie_key);
+       }
+
+free_valid_mask:
+       free_cpumask_var(valid_cpus);
+
+       return ret;
+}
+late_initcall_sync(init_amu_fie);
+
+bool arch_freq_counters_available(struct cpumask *cpus)
+{
+       return amu_freq_invariant() &&
+              cpumask_subset(cpus, amu_fie_cpus);
+}
+
+void topology_scale_freq_tick(void)
+{
+       u64 prev_core_cnt, prev_const_cnt;
+       u64 core_cnt, const_cnt, scale;
+       int cpu = smp_processor_id();
+
+       if (!amu_freq_invariant())
+               return;
+
+       if (!cpumask_test_cpu(cpu, amu_fie_cpus))
+               return;
+
+       const_cnt = read_sysreg_s(SYS_AMEVCNTR0_CONST_EL0);
+       core_cnt = read_sysreg_s(SYS_AMEVCNTR0_CORE_EL0);
+       prev_const_cnt = this_cpu_read(arch_const_cycles_prev);
+       prev_core_cnt = this_cpu_read(arch_core_cycles_prev);
+
+       if (unlikely(core_cnt <= prev_core_cnt ||
+                    const_cnt <= prev_const_cnt))
+               goto store_and_exit;
+
+       /*
+        *          /\core    arch_max_freq_scale
+        * scale =  ------- * --------------------
+        *          /\const   SCHED_CAPACITY_SCALE
+        *
+        * See validate_cpu_freq_invariance_counters() for details on
+        * arch_max_freq_scale and the use of SCHED_CAPACITY_SHIFT.
+        */
+       scale = core_cnt - prev_core_cnt;
+       scale *= this_cpu_read(arch_max_freq_scale);
+       scale = div64_u64(scale >> SCHED_CAPACITY_SHIFT,
+                         const_cnt - prev_const_cnt);
+
+       scale = min_t(unsigned long, scale, SCHED_CAPACITY_SCALE);
+       this_cpu_write(freq_scale, (unsigned long)scale);
+
+store_and_exit:
+       this_cpu_write(arch_core_cycles_prev, core_cnt);
+       this_cpu_write(arch_const_cycles_prev, const_cnt);
+}
+#endif /* CONFIG_ARM64_AMU_EXTN */
index 0723aa3..1232486 100644 (file)
@@ -14,7 +14,7 @@
        .text
 
        nop
-ENTRY(__kernel_rt_sigreturn)
+SYM_FUNC_START(__kernel_rt_sigreturn)
        .cfi_startproc
        .cfi_signal_frame
        .cfi_def_cfa    x29, 0
@@ -23,4 +23,4 @@ ENTRY(__kernel_rt_sigreturn)
        mov     x8, #__NR_rt_sigreturn
        svc     #0
        .cfi_endproc
-ENDPROC(__kernel_rt_sigreturn)
+SYM_FUNC_END(__kernel_rt_sigreturn)
index 7476355..4236cf3 100644 (file)
@@ -5,8 +5,6 @@
  * Copyright (C) 2018 ARM Limited
  *
  */
-#include <linux/time.h>
-#include <linux/types.h>
 
 int __kernel_clock_gettime(clockid_t clock,
                           struct __kernel_timespec *ts)
index 04df57b..3964738 100644 (file)
@@ -10,7 +10,18 @@ include $(srctree)/lib/vdso/Makefile
 
 # Same as cc-*option, but using CC_COMPAT instead of CC
 ifeq ($(CONFIG_CC_IS_CLANG), y)
+COMPAT_GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE_COMPAT)elfedit))
+COMPAT_GCC_TOOLCHAIN := $(realpath $(COMPAT_GCC_TOOLCHAIN_DIR)/..)
+
+CC_COMPAT_CLANG_FLAGS := --target=$(notdir $(CROSS_COMPILE_COMPAT:%-=%))
+CC_COMPAT_CLANG_FLAGS += --prefix=$(COMPAT_GCC_TOOLCHAIN_DIR)
+CC_COMPAT_CLANG_FLAGS += -no-integrated-as -Qunused-arguments
+ifneq ($(COMPAT_GCC_TOOLCHAIN),)
+CC_COMPAT_CLANG_FLAGS += --gcc-toolchain=$(COMPAT_GCC_TOOLCHAIN)
+endif
+
 CC_COMPAT ?= $(CC)
+CC_COMPAT += $(CC_COMPAT_CLANG_FLAGS)
 else
 CC_COMPAT ?= $(CROSS_COMPILE_COMPAT)gcc
 endif
index 1a81277..6205249 100644 (file)
 #include <asm/asm-offsets.h>
 #include <asm/unistd.h>
 
-#define ARM_ENTRY(name)                \
-       ENTRY(name)
-
-#define ARM_ENDPROC(name)      \
-       .type name, %function;  \
-       END(name)
-
        .text
 
        .arm
        .save {r0-r15}
        .pad #COMPAT_SIGFRAME_REGS_OFFSET
        nop
-ARM_ENTRY(__kernel_sigreturn_arm)
+SYM_FUNC_START(__kernel_sigreturn_arm)
        mov r7, #__NR_compat_sigreturn
        svc #0
        .fnend
-ARM_ENDPROC(__kernel_sigreturn_arm)
+SYM_FUNC_END(__kernel_sigreturn_arm)
 
        .fnstart
        .save {r0-r15}
        .pad #COMPAT_RT_SIGFRAME_REGS_OFFSET
        nop
-ARM_ENTRY(__kernel_rt_sigreturn_arm)
+SYM_FUNC_START(__kernel_rt_sigreturn_arm)
        mov r7, #__NR_compat_rt_sigreturn
        svc #0
        .fnend
-ARM_ENDPROC(__kernel_rt_sigreturn_arm)
+SYM_FUNC_END(__kernel_rt_sigreturn_arm)
 
        .thumb
        .fnstart
        .save {r0-r15}
        .pad #COMPAT_SIGFRAME_REGS_OFFSET
        nop
-ARM_ENTRY(__kernel_sigreturn_thumb)
+SYM_FUNC_START(__kernel_sigreturn_thumb)
        mov r7, #__NR_compat_sigreturn
        svc #0
        .fnend
-ARM_ENDPROC(__kernel_sigreturn_thumb)
+SYM_FUNC_END(__kernel_sigreturn_thumb)
 
        .fnstart
        .save {r0-r15}
        .pad #COMPAT_RT_SIGFRAME_REGS_OFFSET
        nop
-ARM_ENTRY(__kernel_rt_sigreturn_thumb)
+SYM_FUNC_START(__kernel_rt_sigreturn_thumb)
        mov r7, #__NR_compat_rt_sigreturn
        svc #0
        .fnend
-ARM_ENDPROC(__kernel_rt_sigreturn_thumb)
+SYM_FUNC_END(__kernel_rt_sigreturn_thumb)
index 54fc1c2..5acff29 100644 (file)
@@ -5,26 +5,16 @@
  * Copyright (C) 2018 ARM Limited
  *
  */
-#include <linux/time.h>
-#include <linux/types.h>
 
 int __vdso_clock_gettime(clockid_t clock,
                         struct old_timespec32 *ts)
 {
-       /* The checks below are required for ABI consistency with arm */
-       if ((u32)ts >= TASK_SIZE_32)
-               return -EFAULT;
-
        return __cvdso_clock_gettime32(clock, ts);
 }
 
 int __vdso_clock_gettime64(clockid_t clock,
                           struct __kernel_timespec *ts)
 {
-       /* The checks below are required for ABI consistency with arm */
-       if ((u32)ts >= TASK_SIZE_32)
-               return -EFAULT;
-
        return __cvdso_clock_gettime(clock, ts);
 }
 
@@ -37,10 +27,6 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv,
 int __vdso_clock_getres(clockid_t clock_id,
                        struct old_timespec32 *res)
 {
-       /* The checks below are required for ABI consistency with arm */
-       if ((u32)res >= TASK_SIZE_32)
-               return -EFAULT;
-
        return __cvdso_clock_getres_time32(clock_id, res);
 }
 
index 160be2b..6e6ed55 100644 (file)
@@ -18,7 +18,7 @@
 
        .align  11
 
-ENTRY(__kvm_hyp_init)
+SYM_CODE_START(__kvm_hyp_init)
        ventry  __invalid               // Synchronous EL2t
        ventry  __invalid               // IRQ EL2t
        ventry  __invalid               // FIQ EL2t
@@ -60,7 +60,7 @@ alternative_else_nop_endif
        msr     ttbr0_el2, x4
 
        mrs     x4, tcr_el1
-       ldr     x5, =TCR_EL2_MASK
+       mov_q   x5, TCR_EL2_MASK
        and     x4, x4, x5
        mov     x5, #TCR_EL2_RES1
        orr     x4, x4, x5
@@ -102,7 +102,7 @@ alternative_else_nop_endif
         * as well as the EE bit on BE. Drop the A flag since the compiler
         * is allowed to generate unaligned accesses.
         */
-       ldr     x4, =(SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A))
+       mov_q   x4, (SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A))
 CPU_BE(        orr     x4, x4, #SCTLR_ELx_EE)
        msr     sctlr_el2, x4
        isb
@@ -117,9 +117,9 @@ CPU_BE(     orr     x4, x4, #SCTLR_ELx_EE)
 
        /* Hello, World! */
        eret
-ENDPROC(__kvm_hyp_init)
+SYM_CODE_END(__kvm_hyp_init)
 
-ENTRY(__kvm_handle_stub_hvc)
+SYM_CODE_START(__kvm_handle_stub_hvc)
        cmp     x0, #HVC_SOFT_RESTART
        b.ne    1f
 
@@ -142,7 +142,7 @@ reset:
         * case we coming via HVC_SOFT_RESTART.
         */
        mrs     x5, sctlr_el2
-       ldr     x6, =SCTLR_ELx_FLAGS
+       mov_q   x6, SCTLR_ELx_FLAGS
        bic     x5, x5, x6              // Clear SCTL_M and etc
        pre_disable_mmu_workaround
        msr     sctlr_el2, x5
@@ -155,11 +155,9 @@ reset:
        eret
 
 1:     /* Bad stub call */
-       ldr     x0, =HVC_STUB_ERR
+       mov_q   x0, HVC_STUB_ERR
        eret
 
-ENDPROC(__kvm_handle_stub_hvc)
-
-       .ltorg
+SYM_CODE_END(__kvm_handle_stub_hvc)
 
        .popsection
index c0094d5..3c79a11 100644 (file)
@@ -28,7 +28,7 @@
  * and is used to implement hyp stubs in the same way as in
  * arch/arm64/kernel/hyp_stub.S.
  */
-ENTRY(__kvm_call_hyp)
+SYM_FUNC_START(__kvm_call_hyp)
        hvc     #0
        ret
-ENDPROC(__kvm_call_hyp)
+SYM_FUNC_END(__kvm_call_hyp)
index 78ff532..5b8ff51 100644 (file)
        .text
        .pushsection    .hyp.text, "ax"
 
-ENTRY(__fpsimd_save_state)
+SYM_FUNC_START(__fpsimd_save_state)
        fpsimd_save     x0, 1
        ret
-ENDPROC(__fpsimd_save_state)
+SYM_FUNC_END(__fpsimd_save_state)
 
-ENTRY(__fpsimd_restore_state)
+SYM_FUNC_START(__fpsimd_restore_state)
        fpsimd_restore  x0, 1
        ret
-ENDPROC(__fpsimd_restore_state)
+SYM_FUNC_END(__fpsimd_restore_state)
index ffa68d5..c2a13ab 100644 (file)
@@ -180,7 +180,7 @@ el2_error:
        eret
        sb
 
-ENTRY(__hyp_do_panic)
+SYM_FUNC_START(__hyp_do_panic)
        mov     lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
                      PSR_MODE_EL1h)
        msr     spsr_el2, lr
@@ -188,18 +188,19 @@ ENTRY(__hyp_do_panic)
        msr     elr_el2, lr
        eret
        sb
-ENDPROC(__hyp_do_panic)
+SYM_FUNC_END(__hyp_do_panic)
 
-ENTRY(__hyp_panic)
+SYM_CODE_START(__hyp_panic)
        get_host_ctxt x0, x1
        b       hyp_panic
-ENDPROC(__hyp_panic)
+SYM_CODE_END(__hyp_panic)
 
 .macro invalid_vector  label, target = __hyp_panic
        .align  2
+SYM_CODE_START(\label)
 \label:
        b \target
-ENDPROC(\label)
+SYM_CODE_END(\label)
 .endm
 
        /* None of these should ever happen */
@@ -246,7 +247,7 @@ check_preamble_length 661b, 662b
 check_preamble_length 661b, 662b
 .endm
 
-ENTRY(__kvm_hyp_vector)
+SYM_CODE_START(__kvm_hyp_vector)
        invalid_vect    el2t_sync_invalid       // Synchronous EL2t
        invalid_vect    el2t_irq_invalid        // IRQ EL2t
        invalid_vect    el2t_fiq_invalid        // FIQ EL2t
@@ -266,7 +267,7 @@ ENTRY(__kvm_hyp_vector)
        valid_vect      el1_irq                 // IRQ 32-bit EL1
        invalid_vect    el1_fiq_invalid         // FIQ 32-bit EL1
        valid_vect      el1_error               // Error 32-bit EL1
-ENDPROC(__kvm_hyp_vector)
+SYM_CODE_END(__kvm_hyp_vector)
 
 #ifdef CONFIG_KVM_INDIRECT_VECTORS
 .macro hyp_ventry
@@ -311,15 +312,17 @@ alternative_cb_end
 .endm
 
        .align  11
-ENTRY(__bp_harden_hyp_vecs_start)
+SYM_CODE_START(__bp_harden_hyp_vecs)
        .rept BP_HARDEN_EL2_SLOTS
        generate_vectors
        .endr
-ENTRY(__bp_harden_hyp_vecs_end)
+1:     .org __bp_harden_hyp_vecs + __BP_HARDEN_HYP_VECS_SZ
+       .org 1b
+SYM_CODE_END(__bp_harden_hyp_vecs)
 
        .popsection
 
-ENTRY(__smccc_workaround_1_smc_start)
+SYM_CODE_START(__smccc_workaround_1_smc)
        esb
        sub     sp, sp, #(8 * 4)
        stp     x2, x3, [sp, #(8 * 0)]
@@ -329,5 +332,7 @@ ENTRY(__smccc_workaround_1_smc_start)
        ldp     x2, x3, [sp, #(8 * 0)]
        ldp     x0, x1, [sp, #(8 * 2)]
        add     sp, sp, #(8 * 4)
-ENTRY(__smccc_workaround_1_smc_end)
+1:     .org __smccc_workaround_1_smc + __SMCCC_WORKAROUND_1_SMC_SZ
+       .org 1b
+SYM_CODE_END(__smccc_workaround_1_smc)
 #endif
index dfe8dd1..eaa05c3 100644 (file)
@@ -98,6 +98,18 @@ static void activate_traps_vhe(struct kvm_vcpu *vcpu)
        val = read_sysreg(cpacr_el1);
        val |= CPACR_EL1_TTA;
        val &= ~CPACR_EL1_ZEN;
+
+       /*
+        * With VHE (HCR.E2H == 1), accesses to CPACR_EL1 are routed to
+        * CPTR_EL2. In general, CPACR_EL1 has the same layout as CPTR_EL2,
+        * except for some missing controls, such as TAM.
+        * In this case, CPTR_EL2.TAM has the same position with or without
+        * VHE (HCR.E2H == 1) which allows us to use here the CPTR_EL2.TAM
+        * shift value for trapping the AMU accesses.
+        */
+
+       val |= CPTR_EL2_TAM;
+
        if (update_fp_enabled(vcpu)) {
                if (vcpu_has_sve(vcpu))
                        val |= CPACR_EL1_ZEN;
@@ -119,7 +131,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
        __activate_traps_common(vcpu);
 
        val = CPTR_EL2_DEFAULT;
-       val |= CPTR_EL2_TTA | CPTR_EL2_TZ;
+       val |= CPTR_EL2_TTA | CPTR_EL2_TZ | CPTR_EL2_TAM;
        if (!update_fp_enabled(vcpu)) {
                val |= CPTR_EL2_TFP;
                __activate_traps_fpsimd32(vcpu);
@@ -127,7 +139,7 @@ static void __hyp_text __activate_traps_nvhe(struct kvm_vcpu *vcpu)
 
        write_sysreg(val, cptr_el2);
 
-       if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
+       if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
                struct kvm_cpu_context *ctxt = &vcpu->arch.ctxt;
 
                isb();
@@ -146,12 +158,12 @@ static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
 {
        u64 hcr = vcpu->arch.hcr_el2;
 
-       if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM))
+       if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM))
                hcr |= HCR_TVM;
 
        write_sysreg(hcr, hcr_el2);
 
-       if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
+       if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE))
                write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2);
 
        if (has_vhe())
@@ -181,7 +193,7 @@ static void __hyp_text __deactivate_traps_nvhe(void)
 {
        u64 mdcr_el2 = read_sysreg(mdcr_el2);
 
-       if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
+       if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
                u64 val;
 
                /*
@@ -328,7 +340,7 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
         * resolve the IPA using the AT instruction.
         */
        if (!(esr & ESR_ELx_S1PTW) &&
-           (cpus_have_const_cap(ARM64_WORKAROUND_834220) ||
+           (cpus_have_final_cap(ARM64_WORKAROUND_834220) ||
             (esr & ESR_ELx_FSC_TYPE) == FSC_PERM)) {
                if (!__translate_far_to_hpfar(far, &hpfar))
                        return false;
@@ -498,7 +510,7 @@ static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
        if (*exit_code != ARM_EXCEPTION_TRAP)
                goto exit;
 
-       if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
+       if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
            kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 &&
            handle_tx2_tvm(vcpu))
                return true;
@@ -555,7 +567,7 @@ exit:
 
 static inline bool __hyp_text __needs_ssbd_off(struct kvm_vcpu *vcpu)
 {
-       if (!cpus_have_const_cap(ARM64_SSBD))
+       if (!cpus_have_final_cap(ARM64_SSBD))
                return false;
 
        return !(vcpu->arch.workaround_flags & VCPU_WORKAROUND_2_FLAG);
@@ -625,7 +637,7 @@ static void __hyp_text __pmu_switch_to_host(struct kvm_cpu_context *host_ctxt)
 }
 
 /* Switch to the guest for VHE systems running in EL2 */
-int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
+static int __kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpu_context *host_ctxt;
        struct kvm_cpu_context *guest_ctxt;
@@ -678,7 +690,42 @@ int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
 
        return exit_code;
 }
-NOKPROBE_SYMBOL(kvm_vcpu_run_vhe);
+NOKPROBE_SYMBOL(__kvm_vcpu_run_vhe);
+
+int kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu)
+{
+       int ret;
+
+       local_daif_mask();
+
+       /*
+        * Having IRQs masked via PMR when entering the guest means the GIC
+        * will not signal the CPU of interrupts of lower priority, and the
+        * only way to get out will be via guest exceptions.
+        * Naturally, we want to avoid this.
+        *
+        * local_daif_mask() already sets GIC_PRIO_PSR_I_SET, we just need a
+        * dsb to ensure the redistributor is forwards EL2 IRQs to the CPU.
+        */
+       pmr_sync();
+
+       ret = __kvm_vcpu_run_vhe(vcpu);
+
+       /*
+        * local_daif_restore() takes care to properly restore PSTATE.DAIF
+        * and the GIC PMR if the host is using IRQ priorities.
+        */
+       local_daif_restore(DAIF_PROCCTX_NOIRQ);
+
+       /*
+        * When we exit from the guest we change a number of CPU configuration
+        * parameters, such as traps.  Make sure these changes take effect
+        * before running the host or additional guests.
+        */
+       isb();
+
+       return ret;
+}
 
 /* Switch to the guest for legacy non-VHE systems */
 int __hyp_text __kvm_vcpu_run_nvhe(struct kvm_vcpu *vcpu)
index 7672a97..75b1925 100644 (file)
@@ -71,7 +71,7 @@ static void __hyp_text __sysreg_save_el2_return_state(struct kvm_cpu_context *ct
        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))
+       if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN))
                ctxt->sys_regs[DISR_EL1] = read_sysreg_s(SYS_VDISR_EL2);
 }
 
@@ -118,7 +118,7 @@ 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);
 
-       if (!cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
+       if (!cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
                write_sysreg_el1(ctxt->sys_regs[SCTLR_EL1],     SYS_SCTLR);
                write_sysreg_el1(ctxt->sys_regs[TCR_EL1],       SYS_TCR);
        } else  if (!ctxt->__hyp_running_vcpu) {
@@ -149,7 +149,7 @@ static void __hyp_text __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
        write_sysreg(ctxt->sys_regs[PAR_EL1],           par_el1);
        write_sysreg(ctxt->sys_regs[TPIDR_EL1],         tpidr_el1);
 
-       if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE) &&
+       if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE) &&
            ctxt->__hyp_running_vcpu) {
                /*
                 * Must only be done for host registers, hence the context
@@ -194,7 +194,7 @@ __sysreg_restore_el2_return_state(struct kvm_cpu_context *ctxt)
        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))
+       if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN))
                write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);
 }
 
index 92f560e..ceaddbe 100644 (file)
@@ -23,7 +23,7 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm,
 
        local_irq_save(cxt->flags);
 
-       if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_VHE)) {
+       if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT_VHE)) {
                /*
                 * For CPUs that are affected by ARM errata 1165522 or 1530923,
                 * we cannot trust stage-1 to be in a correct state at that
@@ -63,7 +63,7 @@ static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm,
 static void __hyp_text __tlb_switch_to_guest_nvhe(struct kvm *kvm,
                                                  struct tlb_inv_context *cxt)
 {
-       if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
+       if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
                u64 val;
 
                /*
@@ -103,7 +103,7 @@ static void __hyp_text __tlb_switch_to_host_vhe(struct kvm *kvm,
        write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
        isb();
 
-       if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_VHE)) {
+       if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT_VHE)) {
                /* Restore the registers to what they were */
                write_sysreg_el1(cxt->tcr, SYS_TCR);
                write_sysreg_el1(cxt->sctlr, SYS_SCTLR);
@@ -117,7 +117,7 @@ static void __hyp_text __tlb_switch_to_host_nvhe(struct kvm *kvm,
 {
        write_sysreg(0, vttbr_el2);
 
-       if (cpus_have_const_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
+       if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT_NVHE)) {
                /* Ensure write of the host VMID */
                isb();
                /* Restore the host's TCR_EL1 */
index 29ee1fe..4f3a087 100644 (file)
@@ -69,14 +69,14 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
                u32 data = vcpu_get_reg(vcpu, rd);
                if (__is_be(vcpu)) {
                        /* guest pre-swabbed data, undo this for writel() */
-                       data = swab32(data);
+                       data = __kvm_swab32(data);
                }
                writel_relaxed(data, addr);
        } else {
                u32 data = readl_relaxed(addr);
                if (__is_be(vcpu)) {
                        /* guest expects swabbed data */
-                       data = swab32(data);
+                       data = __kvm_swab32(data);
                }
                vcpu_set_reg(vcpu, rd, data);
        }
index 3e909b1..090f46d 100644 (file)
@@ -1003,6 +1003,20 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        { SYS_DESC(SYS_PMEVTYPERn_EL0(n)),                                      \
          access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
 
+static bool access_amu(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+                            const struct sys_reg_desc *r)
+{
+       kvm_inject_undefined(vcpu);
+
+       return false;
+}
+
+/* Macro to expand the AMU counter and type registers*/
+#define AMU_AMEVCNTR0_EL0(n) { SYS_DESC(SYS_AMEVCNTR0_EL0(n)), access_amu }
+#define AMU_AMEVTYPE0_EL0(n) { SYS_DESC(SYS_AMEVTYPE0_EL0(n)), access_amu }
+#define AMU_AMEVCNTR1_EL0(n) { SYS_DESC(SYS_AMEVCNTR1_EL0(n)), access_amu }
+#define AMU_AMEVTYPE1_EL0(n) { SYS_DESC(SYS_AMEVTYPE1_EL0(n)), access_amu }
+
 static bool trap_ptrauth(struct kvm_vcpu *vcpu,
                         struct sys_reg_params *p,
                         const struct sys_reg_desc *rd)
@@ -1078,13 +1092,25 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
                         (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
        u64 val = raz ? 0 : read_sanitised_ftr_reg(id);
 
-       if (id == SYS_ID_AA64PFR0_EL1 && !vcpu_has_sve(vcpu)) {
-               val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
+       if (id == SYS_ID_AA64PFR0_EL1) {
+               if (!vcpu_has_sve(vcpu))
+                       val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT);
+               val &= ~(0xfUL << ID_AA64PFR0_AMU_SHIFT);
        } else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) {
                val &= ~((0xfUL << ID_AA64ISAR1_APA_SHIFT) |
                         (0xfUL << ID_AA64ISAR1_API_SHIFT) |
                         (0xfUL << ID_AA64ISAR1_GPA_SHIFT) |
                         (0xfUL << ID_AA64ISAR1_GPI_SHIFT));
+       } else if (id == SYS_ID_AA64DFR0_EL1) {
+               /* Limit guests to PMUv3 for ARMv8.1 */
+               val = cpuid_feature_cap_perfmon_field(val,
+                                               ID_AA64DFR0_PMUVER_SHIFT,
+                                               ID_AA64DFR0_PMUVER_8_1);
+       } else if (id == SYS_ID_DFR0_EL1) {
+               /* Limit guests to PMUv3 for ARMv8.1 */
+               val = cpuid_feature_cap_perfmon_field(val,
+                                               ID_DFR0_PERFMON_SHIFT,
+                                               ID_DFR0_PERFMON_8_1);
        }
 
        return val;
@@ -1565,6 +1591,79 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
        { SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },
 
+       { SYS_DESC(SYS_AMCR_EL0), access_amu },
+       { SYS_DESC(SYS_AMCFGR_EL0), access_amu },
+       { SYS_DESC(SYS_AMCGCR_EL0), access_amu },
+       { SYS_DESC(SYS_AMUSERENR_EL0), access_amu },
+       { SYS_DESC(SYS_AMCNTENCLR0_EL0), access_amu },
+       { SYS_DESC(SYS_AMCNTENSET0_EL0), access_amu },
+       { SYS_DESC(SYS_AMCNTENCLR1_EL0), access_amu },
+       { SYS_DESC(SYS_AMCNTENSET1_EL0), access_amu },
+       AMU_AMEVCNTR0_EL0(0),
+       AMU_AMEVCNTR0_EL0(1),
+       AMU_AMEVCNTR0_EL0(2),
+       AMU_AMEVCNTR0_EL0(3),
+       AMU_AMEVCNTR0_EL0(4),
+       AMU_AMEVCNTR0_EL0(5),
+       AMU_AMEVCNTR0_EL0(6),
+       AMU_AMEVCNTR0_EL0(7),
+       AMU_AMEVCNTR0_EL0(8),
+       AMU_AMEVCNTR0_EL0(9),
+       AMU_AMEVCNTR0_EL0(10),
+       AMU_AMEVCNTR0_EL0(11),
+       AMU_AMEVCNTR0_EL0(12),
+       AMU_AMEVCNTR0_EL0(13),
+       AMU_AMEVCNTR0_EL0(14),
+       AMU_AMEVCNTR0_EL0(15),
+       AMU_AMEVTYPE0_EL0(0),
+       AMU_AMEVTYPE0_EL0(1),
+       AMU_AMEVTYPE0_EL0(2),
+       AMU_AMEVTYPE0_EL0(3),
+       AMU_AMEVTYPE0_EL0(4),
+       AMU_AMEVTYPE0_EL0(5),
+       AMU_AMEVTYPE0_EL0(6),
+       AMU_AMEVTYPE0_EL0(7),
+       AMU_AMEVTYPE0_EL0(8),
+       AMU_AMEVTYPE0_EL0(9),
+       AMU_AMEVTYPE0_EL0(10),
+       AMU_AMEVTYPE0_EL0(11),
+       AMU_AMEVTYPE0_EL0(12),
+       AMU_AMEVTYPE0_EL0(13),
+       AMU_AMEVTYPE0_EL0(14),
+       AMU_AMEVTYPE0_EL0(15),
+       AMU_AMEVCNTR1_EL0(0),
+       AMU_AMEVCNTR1_EL0(1),
+       AMU_AMEVCNTR1_EL0(2),
+       AMU_AMEVCNTR1_EL0(3),
+       AMU_AMEVCNTR1_EL0(4),
+       AMU_AMEVCNTR1_EL0(5),
+       AMU_AMEVCNTR1_EL0(6),
+       AMU_AMEVCNTR1_EL0(7),
+       AMU_AMEVCNTR1_EL0(8),
+       AMU_AMEVCNTR1_EL0(9),
+       AMU_AMEVCNTR1_EL0(10),
+       AMU_AMEVCNTR1_EL0(11),
+       AMU_AMEVCNTR1_EL0(12),
+       AMU_AMEVCNTR1_EL0(13),
+       AMU_AMEVCNTR1_EL0(14),
+       AMU_AMEVCNTR1_EL0(15),
+       AMU_AMEVTYPE1_EL0(0),
+       AMU_AMEVTYPE1_EL0(1),
+       AMU_AMEVTYPE1_EL0(2),
+       AMU_AMEVTYPE1_EL0(3),
+       AMU_AMEVTYPE1_EL0(4),
+       AMU_AMEVTYPE1_EL0(5),
+       AMU_AMEVTYPE1_EL0(6),
+       AMU_AMEVTYPE1_EL0(7),
+       AMU_AMEVTYPE1_EL0(8),
+       AMU_AMEVTYPE1_EL0(9),
+       AMU_AMEVTYPE1_EL0(10),
+       AMU_AMEVTYPE1_EL0(11),
+       AMU_AMEVTYPE1_EL0(12),
+       AMU_AMEVTYPE1_EL0(13),
+       AMU_AMEVTYPE1_EL0(14),
+       AMU_AMEVTYPE1_EL0(15),
+
        { SYS_DESC(SYS_CNTP_TVAL_EL0), access_arch_timer },
        { SYS_DESC(SYS_CNTP_CTL_EL0), access_arch_timer },
        { SYS_DESC(SYS_CNTP_CVAL_EL0), access_arch_timer },
index 1f82c66..60eccae 100644 (file)
@@ -124,3 +124,30 @@ unsigned int do_csum(const unsigned char *buff, int len)
 
        return sum >> 16;
 }
+
+__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+                       const struct in6_addr *daddr,
+                       __u32 len, __u8 proto, __wsum csum)
+{
+       __uint128_t src, dst;
+       u64 sum = (__force u64)csum;
+
+       src = *(const __uint128_t *)saddr->s6_addr;
+       dst = *(const __uint128_t *)daddr->s6_addr;
+
+       sum += (__force u32)htonl(len);
+#ifdef __LITTLE_ENDIAN
+       sum += (u32)proto << 24;
+#else
+       sum += proto;
+#endif
+       src += (src >> 64) | (src << 64);
+       dst += (dst >> 64) | (dst << 64);
+
+       sum = accumulate(sum, src >> 64);
+       sum = accumulate(sum, dst >> 64);
+
+       sum += ((sum >> 32) | (sum << 32));
+       return csum_fold((__force __wsum)(sum >> 32));
+}
+EXPORT_SYMBOL(csum_ipv6_magic);
index 4767540..4e79566 100644 (file)
@@ -186,7 +186,7 @@ CPU_LE( rev data2, data2 )
        * as carry-propagation can corrupt the upper bits if the trailing
        * bytes in the string contain 0x01.
        * However, if there is no NUL byte in the dword, we can generate
-       * the result directly.  We ca not just subtract the bytes as the
+       * the result directly.  We cannot just subtract the bytes as the
        * MSB might be significant.
        */
 CPU_BE( cbnz   has_nul, 1f )
index 8ef73e8..9b26f9a 100644 (file)
@@ -6,6 +6,7 @@
  * Copyright (C) 2012 ARM Ltd.
  */
 
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -254,20 +255,59 @@ switch_mm_fastpath:
 /* Errata workaround post TTBRx_EL1 update. */
 asmlinkage void post_ttbr_update_workaround(void)
 {
+       if (!IS_ENABLED(CONFIG_CAVIUM_ERRATUM_27456))
+               return;
+
        asm(ALTERNATIVE("nop; nop; nop",
                        "ic iallu; dsb nsh; isb",
-                       ARM64_WORKAROUND_CAVIUM_27456,
-                       CONFIG_CAVIUM_ERRATUM_27456));
+                       ARM64_WORKAROUND_CAVIUM_27456));
 }
 
-static int asids_init(void)
+void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm)
 {
-       asid_bits = get_cpu_asid_bits();
+       unsigned long ttbr1 = read_sysreg(ttbr1_el1);
+       unsigned long asid = ASID(mm);
+       unsigned long ttbr0 = phys_to_ttbr(pgd_phys);
+
+       /* Skip CNP for the reserved ASID */
+       if (system_supports_cnp() && asid)
+               ttbr0 |= TTBR_CNP_BIT;
+
+       /* SW PAN needs a copy of the ASID in TTBR0 for entry */
+       if (IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN))
+               ttbr0 |= FIELD_PREP(TTBR_ASID_MASK, asid);
+
+       /* Set ASID in TTBR1 since TCR.A1 is set */
+       ttbr1 &= ~TTBR_ASID_MASK;
+       ttbr1 |= FIELD_PREP(TTBR_ASID_MASK, asid);
+
+       write_sysreg(ttbr1, ttbr1_el1);
+       isb();
+       write_sysreg(ttbr0, ttbr0_el1);
+       isb();
+       post_ttbr_update_workaround();
+}
+
+static int asids_update_limit(void)
+{
+       unsigned long num_available_asids = NUM_USER_ASIDS;
+
+       if (arm64_kernel_unmapped_at_el0())
+               num_available_asids /= 2;
        /*
         * Expect allocation after rollover to fail if we don't have at least
         * one more ASID than CPUs. ASID #0 is reserved for init_mm.
         */
-       WARN_ON(NUM_USER_ASIDS - 1 <= num_possible_cpus());
+       WARN_ON(num_available_asids - 1 <= num_possible_cpus());
+       pr_info("ASID allocator initialised with %lu entries\n",
+               num_available_asids);
+       return 0;
+}
+arch_initcall(asids_update_limit);
+
+static int asids_init(void)
+{
+       asid_bits = get_cpu_asid_bits();
        atomic64_set(&asid_generation, ASID_FIRST_VERSION);
        asid_map = kcalloc(BITS_TO_LONGS(NUM_USER_ASIDS), sizeof(*asid_map),
                           GFP_KERNEL);
@@ -282,8 +322,6 @@ static int asids_init(void)
         */
        if (IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0))
                set_kpti_asid_bits();
-
-       pr_info("ASID allocator initialised with %lu entries\n", NUM_USER_ASIDS);
        return 0;
 }
 early_initcall(asids_init);
index 128f708..9b08f7c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/mman.h>
 #include <linux/nodemask.h>
 #include <linux/memblock.h>
+#include <linux/memory.h>
 #include <linux/fs.h>
 #include <linux/io.h>
 #include <linux/mm.h>
@@ -724,6 +725,312 @@ int kern_addr_valid(unsigned long addr)
 
        return pfn_valid(pte_pfn(pte));
 }
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+static void free_hotplug_page_range(struct page *page, size_t size)
+{
+       WARN_ON(PageReserved(page));
+       free_pages((unsigned long)page_address(page), get_order(size));
+}
+
+static void free_hotplug_pgtable_page(struct page *page)
+{
+       free_hotplug_page_range(page, PAGE_SIZE);
+}
+
+static bool pgtable_range_aligned(unsigned long start, unsigned long end,
+                                 unsigned long floor, unsigned long ceiling,
+                                 unsigned long mask)
+{
+       start &= mask;
+       if (start < floor)
+               return false;
+
+       if (ceiling) {
+               ceiling &= mask;
+               if (!ceiling)
+                       return false;
+       }
+
+       if (end - 1 > ceiling - 1)
+               return false;
+       return true;
+}
+
+static void unmap_hotplug_pte_range(pmd_t *pmdp, unsigned long addr,
+                                   unsigned long end, bool free_mapped)
+{
+       pte_t *ptep, pte;
+
+       do {
+               ptep = pte_offset_kernel(pmdp, addr);
+               pte = READ_ONCE(*ptep);
+               if (pte_none(pte))
+                       continue;
+
+               WARN_ON(!pte_present(pte));
+               pte_clear(&init_mm, addr, ptep);
+               flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+               if (free_mapped)
+                       free_hotplug_page_range(pte_page(pte), PAGE_SIZE);
+       } while (addr += PAGE_SIZE, addr < end);
+}
+
+static void unmap_hotplug_pmd_range(pud_t *pudp, unsigned long addr,
+                                   unsigned long end, bool free_mapped)
+{
+       unsigned long next;
+       pmd_t *pmdp, pmd;
+
+       do {
+               next = pmd_addr_end(addr, end);
+               pmdp = pmd_offset(pudp, addr);
+               pmd = READ_ONCE(*pmdp);
+               if (pmd_none(pmd))
+                       continue;
+
+               WARN_ON(!pmd_present(pmd));
+               if (pmd_sect(pmd)) {
+                       pmd_clear(pmdp);
+
+                       /*
+                        * One TLBI should be sufficient here as the PMD_SIZE
+                        * range is mapped with a single block entry.
+                        */
+                       flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+                       if (free_mapped)
+                               free_hotplug_page_range(pmd_page(pmd),
+                                                       PMD_SIZE);
+                       continue;
+               }
+               WARN_ON(!pmd_table(pmd));
+               unmap_hotplug_pte_range(pmdp, addr, next, free_mapped);
+       } while (addr = next, addr < end);
+}
+
+static void unmap_hotplug_pud_range(p4d_t *p4dp, unsigned long addr,
+                                   unsigned long end, bool free_mapped)
+{
+       unsigned long next;
+       pud_t *pudp, pud;
+
+       do {
+               next = pud_addr_end(addr, end);
+               pudp = pud_offset(p4dp, addr);
+               pud = READ_ONCE(*pudp);
+               if (pud_none(pud))
+                       continue;
+
+               WARN_ON(!pud_present(pud));
+               if (pud_sect(pud)) {
+                       pud_clear(pudp);
+
+                       /*
+                        * One TLBI should be sufficient here as the PUD_SIZE
+                        * range is mapped with a single block entry.
+                        */
+                       flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+                       if (free_mapped)
+                               free_hotplug_page_range(pud_page(pud),
+                                                       PUD_SIZE);
+                       continue;
+               }
+               WARN_ON(!pud_table(pud));
+               unmap_hotplug_pmd_range(pudp, addr, next, free_mapped);
+       } while (addr = next, addr < end);
+}
+
+static void unmap_hotplug_p4d_range(pgd_t *pgdp, unsigned long addr,
+                                   unsigned long end, bool free_mapped)
+{
+       unsigned long next;
+       p4d_t *p4dp, p4d;
+
+       do {
+               next = p4d_addr_end(addr, end);
+               p4dp = p4d_offset(pgdp, addr);
+               p4d = READ_ONCE(*p4dp);
+               if (p4d_none(p4d))
+                       continue;
+
+               WARN_ON(!p4d_present(p4d));
+               unmap_hotplug_pud_range(p4dp, addr, next, free_mapped);
+       } while (addr = next, addr < end);
+}
+
+static void unmap_hotplug_range(unsigned long addr, unsigned long end,
+                               bool free_mapped)
+{
+       unsigned long next;
+       pgd_t *pgdp, pgd;
+
+       do {
+               next = pgd_addr_end(addr, end);
+               pgdp = pgd_offset_k(addr);
+               pgd = READ_ONCE(*pgdp);
+               if (pgd_none(pgd))
+                       continue;
+
+               WARN_ON(!pgd_present(pgd));
+               unmap_hotplug_p4d_range(pgdp, addr, next, free_mapped);
+       } while (addr = next, addr < end);
+}
+
+static void free_empty_pte_table(pmd_t *pmdp, unsigned long addr,
+                                unsigned long end, unsigned long floor,
+                                unsigned long ceiling)
+{
+       pte_t *ptep, pte;
+       unsigned long i, start = addr;
+
+       do {
+               ptep = pte_offset_kernel(pmdp, addr);
+               pte = READ_ONCE(*ptep);
+
+               /*
+                * This is just a sanity check here which verifies that
+                * pte clearing has been done by earlier unmap loops.
+                */
+               WARN_ON(!pte_none(pte));
+       } while (addr += PAGE_SIZE, addr < end);
+
+       if (!pgtable_range_aligned(start, end, floor, ceiling, PMD_MASK))
+               return;
+
+       /*
+        * Check whether we can free the pte page if the rest of the
+        * entries are empty. Overlap with other regions have been
+        * handled by the floor/ceiling check.
+        */
+       ptep = pte_offset_kernel(pmdp, 0UL);
+       for (i = 0; i < PTRS_PER_PTE; i++) {
+               if (!pte_none(READ_ONCE(ptep[i])))
+                       return;
+       }
+
+       pmd_clear(pmdp);
+       __flush_tlb_kernel_pgtable(start);
+       free_hotplug_pgtable_page(virt_to_page(ptep));
+}
+
+static void free_empty_pmd_table(pud_t *pudp, unsigned long addr,
+                                unsigned long end, unsigned long floor,
+                                unsigned long ceiling)
+{
+       pmd_t *pmdp, pmd;
+       unsigned long i, next, start = addr;
+
+       do {
+               next = pmd_addr_end(addr, end);
+               pmdp = pmd_offset(pudp, addr);
+               pmd = READ_ONCE(*pmdp);
+               if (pmd_none(pmd))
+                       continue;
+
+               WARN_ON(!pmd_present(pmd) || !pmd_table(pmd) || pmd_sect(pmd));
+               free_empty_pte_table(pmdp, addr, next, floor, ceiling);
+       } while (addr = next, addr < end);
+
+       if (CONFIG_PGTABLE_LEVELS <= 2)
+               return;
+
+       if (!pgtable_range_aligned(start, end, floor, ceiling, PUD_MASK))
+               return;
+
+       /*
+        * Check whether we can free the pmd page if the rest of the
+        * entries are empty. Overlap with other regions have been
+        * handled by the floor/ceiling check.
+        */
+       pmdp = pmd_offset(pudp, 0UL);
+       for (i = 0; i < PTRS_PER_PMD; i++) {
+               if (!pmd_none(READ_ONCE(pmdp[i])))
+                       return;
+       }
+
+       pud_clear(pudp);
+       __flush_tlb_kernel_pgtable(start);
+       free_hotplug_pgtable_page(virt_to_page(pmdp));
+}
+
+static void free_empty_pud_table(p4d_t *p4dp, unsigned long addr,
+                                unsigned long end, unsigned long floor,
+                                unsigned long ceiling)
+{
+       pud_t *pudp, pud;
+       unsigned long i, next, start = addr;
+
+       do {
+               next = pud_addr_end(addr, end);
+               pudp = pud_offset(p4dp, addr);
+               pud = READ_ONCE(*pudp);
+               if (pud_none(pud))
+                       continue;
+
+               WARN_ON(!pud_present(pud) || !pud_table(pud) || pud_sect(pud));
+               free_empty_pmd_table(pudp, addr, next, floor, ceiling);
+       } while (addr = next, addr < end);
+
+       if (CONFIG_PGTABLE_LEVELS <= 3)
+               return;
+
+       if (!pgtable_range_aligned(start, end, floor, ceiling, PGDIR_MASK))
+               return;
+
+       /*
+        * Check whether we can free the pud page if the rest of the
+        * entries are empty. Overlap with other regions have been
+        * handled by the floor/ceiling check.
+        */
+       pudp = pud_offset(p4dp, 0UL);
+       for (i = 0; i < PTRS_PER_PUD; i++) {
+               if (!pud_none(READ_ONCE(pudp[i])))
+                       return;
+       }
+
+       p4d_clear(p4dp);
+       __flush_tlb_kernel_pgtable(start);
+       free_hotplug_pgtable_page(virt_to_page(pudp));
+}
+
+static void free_empty_p4d_table(pgd_t *pgdp, unsigned long addr,
+                                unsigned long end, unsigned long floor,
+                                unsigned long ceiling)
+{
+       unsigned long next;
+       p4d_t *p4dp, p4d;
+
+       do {
+               next = p4d_addr_end(addr, end);
+               p4dp = p4d_offset(pgdp, addr);
+               p4d = READ_ONCE(*p4dp);
+               if (p4d_none(p4d))
+                       continue;
+
+               WARN_ON(!p4d_present(p4d));
+               free_empty_pud_table(p4dp, addr, next, floor, ceiling);
+       } while (addr = next, addr < end);
+}
+
+static void free_empty_tables(unsigned long addr, unsigned long end,
+                             unsigned long floor, unsigned long ceiling)
+{
+       unsigned long next;
+       pgd_t *pgdp, pgd;
+
+       do {
+               next = pgd_addr_end(addr, end);
+               pgdp = pgd_offset_k(addr);
+               pgd = READ_ONCE(*pgdp);
+               if (pgd_none(pgd))
+                       continue;
+
+               WARN_ON(!pgd_present(pgd));
+               free_empty_p4d_table(pgdp, addr, next, floor, ceiling);
+       } while (addr = next, addr < end);
+}
+#endif
+
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 #if !ARM64_SWAPPER_USES_SECTION_MAPS
 int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
@@ -771,6 +1078,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
 void vmemmap_free(unsigned long start, unsigned long end,
                struct vmem_altmap *altmap)
 {
+#ifdef CONFIG_MEMORY_HOTPLUG
+       WARN_ON((start < VMEMMAP_START) || (end > VMEMMAP_END));
+
+       unmap_hotplug_range(start, end, true);
+       free_empty_tables(start, end, VMEMMAP_START, VMEMMAP_END);
+#endif
 }
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
@@ -1049,10 +1362,21 @@ int p4d_free_pud_page(p4d_t *p4d, unsigned long addr)
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
+static void __remove_pgd_mapping(pgd_t *pgdir, unsigned long start, u64 size)
+{
+       unsigned long end = start + size;
+
+       WARN_ON(pgdir != init_mm.pgd);
+       WARN_ON((start < PAGE_OFFSET) || (end > PAGE_END));
+
+       unmap_hotplug_range(start, end, false);
+       free_empty_tables(start, end, PAGE_OFFSET, PAGE_END);
+}
+
 int arch_add_memory(int nid, u64 start, u64 size,
                        struct mhp_restrictions *restrictions)
 {
-       int flags = 0;
+       int ret, flags = 0;
 
        if (rodata_full || debug_pagealloc_enabled())
                flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
@@ -1062,22 +1386,59 @@ int arch_add_memory(int nid, u64 start, u64 size,
 
        memblock_clear_nomap(start, size);
 
-       return __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT,
+       ret = __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT,
                           restrictions);
+       if (ret)
+               __remove_pgd_mapping(swapper_pg_dir,
+                                    __phys_to_virt(start), size);
+       return ret;
 }
+
 void arch_remove_memory(int nid, u64 start, u64 size,
                        struct vmem_altmap *altmap)
 {
        unsigned long start_pfn = start >> PAGE_SHIFT;
        unsigned long nr_pages = size >> PAGE_SHIFT;
 
-       /*
-        * FIXME: Cleanup page tables (also in arch_add_memory() in case
-        * adding fails). Until then, this function should only be used
-        * during memory hotplug (adding memory), not for memory
-        * unplug. ARCH_ENABLE_MEMORY_HOTREMOVE must not be
-        * unlocked yet.
-        */
        __remove_pages(start_pfn, nr_pages, altmap);
+       __remove_pgd_mapping(swapper_pg_dir, __phys_to_virt(start), size);
+}
+
+/*
+ * This memory hotplug notifier helps prevent boot memory from being
+ * inadvertently removed as it blocks pfn range offlining process in
+ * __offline_pages(). Hence this prevents both offlining as well as
+ * removal process for boot memory which is initially always online.
+ * In future if and when boot memory could be removed, this notifier
+ * should be dropped and free_hotplug_page_range() should handle any
+ * reserved pages allocated during boot.
+ */
+static int prevent_bootmem_remove_notifier(struct notifier_block *nb,
+                                          unsigned long action, void *data)
+{
+       struct mem_section *ms;
+       struct memory_notify *arg = data;
+       unsigned long end_pfn = arg->start_pfn + arg->nr_pages;
+       unsigned long pfn = arg->start_pfn;
+
+       if (action != MEM_GOING_OFFLINE)
+               return NOTIFY_OK;
+
+       for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+               ms = __pfn_to_section(pfn);
+               if (early_section(ms))
+                       return NOTIFY_BAD;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block prevent_bootmem_remove_nb = {
+       .notifier_call = prevent_bootmem_remove_notifier,
+};
+
+static int __init prevent_bootmem_remove_init(void)
+{
+       return register_memory_notifier(&prevent_bootmem_remove_nb);
 }
+device_initcall(prevent_bootmem_remove_init);
 #endif
index aafed69..197a9ba 100644 (file)
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/asm-offsets.h>
+#include <asm/asm_pointer_auth.h>
 #include <asm/hwcap.h>
 #include <asm/pgtable.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/cpufeature.h>
 #include <asm/alternative.h>
+#include <asm/smp.h>
 
 #ifdef CONFIG_ARM64_64K_PAGES
 #define TCR_TG_FLAGS   TCR_TG0_64K | TCR_TG1_64K
@@ -131,45 +133,19 @@ alternative_endif
        ubfx    x11, x11, #1, #1
        msr     oslar_el1, x11
        reset_pmuserenr_el0 x0                  // Disable PMU access from EL0
+       reset_amuserenr_el0 x0                  // Disable AMU access from EL0
 
 alternative_if ARM64_HAS_RAS_EXTN
        msr_s   SYS_DISR_EL1, xzr
 alternative_else_nop_endif
 
+       ptrauth_keys_install_kernel x14, 0, x1, x2, x3
        isb
        ret
 SYM_FUNC_END(cpu_do_resume)
        .popsection
 #endif
 
-/*
- *     cpu_do_switch_mm(pgd_phys, tsk)
- *
- *     Set the translation table base pointer to be pgd_phys.
- *
- *     - pgd_phys - physical address of new TTB
- */
-SYM_FUNC_START(cpu_do_switch_mm)
-       mrs     x2, ttbr1_el1
-       mmid    x1, x1                          // get mm->context.id
-       phys_to_ttbr x3, x0
-
-alternative_if ARM64_HAS_CNP
-       cbz     x1, 1f                          // skip CNP for reserved ASID
-       orr     x3, x3, #TTBR_CNP_BIT
-1:
-alternative_else_nop_endif
-#ifdef CONFIG_ARM64_SW_TTBR0_PAN
-       bfi     x3, x1, #48, #16                // set the ASID field in TTBR0
-#endif
-       bfi     x2, x1, #48, #16                // set the ASID
-       msr     ttbr1_el1, x2                   // in TTBR1 (since TCR.A1 is set)
-       isb
-       msr     ttbr0_el1, x3                   // now update TTBR0
-       isb
-       b       post_ttbr_update_workaround     // Back to C code...
-SYM_FUNC_END(cpu_do_switch_mm)
-
        .pushsection ".idmap.text", "awx"
 
 .macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
@@ -408,35 +384,37 @@ SYM_FUNC_END(idmap_kpti_install_ng_mappings)
 /*
  *     __cpu_setup
  *
- *     Initialise the processor for turning the MMU on.  Return in x0 the
- *     value of the SCTLR_EL1 register.
+ *     Initialise the processor for turning the MMU on.
+ *
+ * Input:
+ *     x0 with a flag ARM64_CPU_BOOT_PRIMARY/ARM64_CPU_BOOT_SECONDARY/ARM64_CPU_RUNTIME.
+ * Output:
+ *     Return in x0 the value of the SCTLR_EL1 register.
  */
        .pushsection ".idmap.text", "awx"
 SYM_FUNC_START(__cpu_setup)
        tlbi    vmalle1                         // Invalidate local TLB
        dsb     nsh
 
-       mov     x0, #3 << 20
-       msr     cpacr_el1, x0                   // Enable FP/ASIMD
-       mov     x0, #1 << 12                    // Reset mdscr_el1 and disable
-       msr     mdscr_el1, x0                   // access to the DCC from EL0
+       mov     x1, #3 << 20
+       msr     cpacr_el1, x1                   // Enable FP/ASIMD
+       mov     x1, #1 << 12                    // Reset mdscr_el1 and disable
+       msr     mdscr_el1, x1                   // access to the DCC from EL0
        isb                                     // Unmask debug exceptions now,
        enable_dbg                              // since this is per-cpu
-       reset_pmuserenr_el0 x0                  // Disable PMU access from EL0
+       reset_pmuserenr_el0 x1                  // Disable PMU access from EL0
+       reset_amuserenr_el0 x1                  // Disable AMU access from EL0
+
        /*
         * Memory region attributes
         */
        mov_q   x5, MAIR_EL1_SET
        msr     mair_el1, x5
        /*
-        * Prepare SCTLR
-        */
-       mov_q   x0, SCTLR_EL1_SET
-       /*
         * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
         * both user and kernel.
         */
-       ldr     x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
+       mov_q   x10, TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
                        TCR_TG_FLAGS | TCR_KASLR_FLAGS | TCR_ASID16 | \
                        TCR_TBI0 | TCR_A1 | TCR_KASAN_FLAGS
        tcr_clear_errata_bits x10, x9, x5
@@ -468,5 +446,51 @@ SYM_FUNC_START(__cpu_setup)
 1:
 #endif /* CONFIG_ARM64_HW_AFDBM */
        msr     tcr_el1, x10
+       mov     x1, x0
+       /*
+        * Prepare SCTLR
+        */
+       mov_q   x0, SCTLR_EL1_SET
+
+#ifdef CONFIG_ARM64_PTR_AUTH
+       /* No ptrauth setup for run time cpus */
+       cmp     x1, #ARM64_CPU_RUNTIME
+       b.eq    3f
+
+       /* Check if the CPU supports ptrauth */
+       mrs     x2, id_aa64isar1_el1
+       ubfx    x2, x2, #ID_AA64ISAR1_APA_SHIFT, #8
+       cbz     x2, 3f
+
+       /*
+        * The primary cpu keys are reset here and can be
+        * re-initialised with some proper values later.
+        */
+       msr_s   SYS_APIAKEYLO_EL1, xzr
+       msr_s   SYS_APIAKEYHI_EL1, xzr
+
+       /* Just enable ptrauth for primary cpu */
+       cmp     x1, #ARM64_CPU_BOOT_PRIMARY
+       b.eq    2f
+
+       /* if !system_supports_address_auth() then skip enable */
+alternative_if_not ARM64_HAS_ADDRESS_AUTH
+       b       3f
+alternative_else_nop_endif
+
+       /* Install ptrauth key for secondary cpus */
+       adr_l   x2, secondary_data
+       ldr     x3, [x2, #CPU_BOOT_TASK]        // get secondary_data.task
+       cbz     x3, 2f                          // check for slow booting cpus
+       ldp     x3, x4, [x2, #CPU_BOOT_PTRAUTH_KEY]
+       msr_s   SYS_APIAKEYLO_EL1, x3
+       msr_s   SYS_APIAKEYHI_EL1, x4
+
+2:     /* Enable ptrauth instructions */
+       ldr     x2, =SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \
+                    SCTLR_ELx_ENDA | SCTLR_ELx_ENDB
+       orr     x0, x0, x2
+3:
+#endif
        ret                                     // return to head.S
 SYM_FUNC_END(__cpu_setup)
index 1f2eae3..d29d722 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/debugfs.h>
+#include <linux/memory_hotplug.h>
 #include <linux/seq_file.h>
 
 #include <asm/ptdump.h>
@@ -7,7 +8,10 @@
 static int ptdump_show(struct seq_file *m, void *v)
 {
        struct ptdump_info *info = m->private;
+
+       get_online_mems();
        ptdump_walk(m, info);
+       put_online_mems();
        return 0;
 }
 DEFINE_SHOW_ATTRIBUTE(ptdump);
index d98d943..661f4c7 100644 (file)
@@ -165,13 +165,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction timer_iact = {
-       .name           = "timer",
-       .flags          = IRQF_TIMER,
-       .handler        = timer_interrupt,
-       .dev_id         = &t64_clockevent_device,
-};
-
 void __init timer64_init(void)
 {
        struct clock_event_device *cd = &t64_clockevent_device;
@@ -238,7 +231,9 @@ void __init timer64_init(void)
        cd->cpumask             = cpumask_of(smp_processor_id());
 
        clockevents_register_device(cd);
-       setup_irq(cd->irq, &timer_iact);
+       if (request_irq(cd->irq, timer_interrupt, IRQF_TIMER, "timer",
+                       &t64_clockevent_device))
+               pr_err("Failed to request irq %d (timer)\n", cd->irq);
 
 out:
        of_node_put(np);
index eaa1c34..abefa12 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/sched.h>
-#include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/version.h>
 #include <asm/segment.h>
index 0191f7c..6b9c554 100644 (file)
@@ -36,7 +36,8 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
        int oldval = 0, ret;
 
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -62,8 +63,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index 00cb38f..c1019a7 100644 (file)
@@ -10,7 +10,6 @@
 /*
  * User space memory access functions
  */
-#include <linux/mm.h>
 #include <asm/sections.h>
 
 /*
index 0bbbe65..619c564 100644 (file)
@@ -114,12 +114,6 @@ void send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg)
        local_irq_restore(flags);
 }
 
-static struct irqaction ipi_intdesc = {
-       .handler = handle_ipi,
-       .flags = IRQF_TRIGGER_RISING,
-       .name = "ipi_handler"
-};
-
 void __init smp_prepare_boot_cpu(void)
 {
 }
@@ -132,8 +126,8 @@ void __init smp_prepare_boot_cpu(void)
 
 void start_secondary(void)
 {
-       unsigned int cpu;
        unsigned long thread_ptr;
+       unsigned int cpu, irq;
 
        /*  Calculate thread_info pointer from stack pointer  */
        __asm__ __volatile__(
@@ -155,7 +149,10 @@ void start_secondary(void)
 
        cpu = smp_processor_id();
 
-       setup_irq(BASE_IPI_IRQ + cpu, &ipi_intdesc);
+       irq = BASE_IPI_IRQ + cpu;
+       if (request_irq(irq, handle_ipi, IRQF_TRIGGER_RISING, "ipi_handler",
+                       NULL))
+               pr_err("Failed to request irq %u (ipi_handler)\n", irq);
 
        /*  Register the clock_event dummy  */
        setup_percpu_clockdev();
@@ -201,7 +198,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
 
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       int i;
+       int i, irq = BASE_IPI_IRQ;
 
        /*
         * should eventually have some sort of machine
@@ -213,8 +210,11 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                set_cpu_present(i, true);
 
        /*  Also need to register the interrupts for IPI  */
-       if (max_cpus > 1)
-               setup_irq(BASE_IPI_IRQ, &ipi_intdesc);
+       if (max_cpus > 1) {
+               if (request_irq(irq, handle_ipi, IRQF_TRIGGER_RISING,
+                               "ipi_handler", NULL))
+                       pr_err("Failed to request irq %d (ipi_handler)\n", irq);
+       }
 }
 
 void smp_send_reschedule(int cpu)
index f99e925..feffe52 100644 (file)
@@ -143,13 +143,6 @@ static irqreturn_t timer_interrupt(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
-/*  This should also be pulled from devtree  */
-static struct irqaction rtos_timer_intdesc = {
-       .handler = timer_interrupt,
-       .flags = IRQF_TIMER | IRQF_TRIGGER_RISING,
-       .name = "rtos_timer"
-};
-
 /*
  * time_init_deferred - called by start_kernel to set up timer/clock source
  *
@@ -163,6 +156,7 @@ void __init time_init_deferred(void)
 {
        struct resource *resource = NULL;
        struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
+       unsigned long flag = IRQF_TIMER | IRQF_TRIGGER_RISING;
 
        ce_dev->cpumask = cpu_all_mask;
 
@@ -195,7 +189,8 @@ void __init time_init_deferred(void)
 #endif
 
        clockevents_register_device(ce_dev);
-       setup_irq(ce_dev->irq, &rtos_timer_intdesc);
+       if (request_irq(ce_dev->irq, timer_interrupt, flag, "rtos_timer", NULL))
+               pr_err("Failed to register rtos_timer interrupt\n");
 }
 
 void __init time_init(void)
index 2e106d4..1db26b4 100644 (file)
@@ -50,7 +50,8 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
        int oldval = 0, ret;
 
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -74,8 +75,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index e6385c7..f6ff95b 100644 (file)
@@ -113,7 +113,6 @@ extern struct irq_chip irq_type_ia64_lsapic;        /* CPU-internal interrupt controlle
 #define ia64_register_ipi      ia64_native_register_ipi
 #define assign_irq_vector      ia64_native_assign_irq_vector
 #define free_irq_vector                ia64_native_free_irq_vector
-#define register_percpu_irq    ia64_native_register_percpu_irq
 #define ia64_resend_irq                ia64_native_resend_irq
 
 extern void ia64_native_register_ipi(void);
@@ -123,7 +122,6 @@ extern void ia64_native_free_irq_vector (int vector);
 extern int reserve_irq_vector (int vector);
 extern void __setup_vector_irq(int cpu);
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
-extern void ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action);
 extern void destroy_and_reserve_irq (unsigned int irq);
 
 #ifdef CONFIG_SMP
index 89782ad..5c7e79e 100644 (file)
@@ -35,7 +35,6 @@
 
 #include <linux/compiler.h>
 #include <linux/page-flags.h>
-#include <linux/mm.h>
 
 #include <asm/intrinsics.h>
 #include <asm/pgtable.h>
index 0a34dcc..f69f3fe 100644 (file)
 
 #define EFI_DEBUG      0
 
+#define ESI_TABLE_GUID                                 \
+    EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3,         \
+            0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
+
+static unsigned long mps_phys = EFI_INVALID_TABLE_ADDR;
 static __initdata unsigned long palo_phys;
 
+unsigned long __initdata esi_phys = EFI_INVALID_TABLE_ADDR;
+unsigned long hcdp_phys = EFI_INVALID_TABLE_ADDR;
 unsigned long sal_systab_phys = EFI_INVALID_TABLE_ADDR;
 
-static __initdata efi_config_table_type_t arch_tables[] = {
+static const efi_config_table_type_t arch_tables[] __initconst = {
+       {ESI_TABLE_GUID, "ESI", &esi_phys},
+       {HCDP_TABLE_GUID, "HCDP", &hcdp_phys},
+       {MPS_TABLE_GUID, "MPS", &mps_phys},
        {PROCESSOR_ABSTRACTION_LAYER_OVERWRITE_GUID, "PALO", &palo_phys},
        {SAL_SYSTEM_TABLE_GUID, "SALsystab", &sal_systab_phys},
        {NULL_GUID, NULL, 0},
@@ -474,11 +484,10 @@ efi_map_pal_code (void)
 void __init
 efi_init (void)
 {
+       const efi_system_table_t *efi_systab;
        void *efi_map_start, *efi_map_end;
-       efi_char16_t *c16;
        u64 efi_desc_size;
-       char *cp, vendor[100] = "unknown";
-       int i;
+       char *cp;
 
        set_bit(EFI_BOOT, &efi.flags);
        set_bit(EFI_64BIT, &efi.flags);
@@ -508,42 +517,29 @@ efi_init (void)
                printk(KERN_INFO "Ignoring memory above %lluMB\n",
                       max_addr >> 20);
 
-       efi.systab = __va(ia64_boot_param->efi_systab);
+       efi_systab = __va(ia64_boot_param->efi_systab);
 
        /*
         * Verify the EFI Table
         */
-       if (efi.systab == NULL)
+       if (efi_systab == NULL)
                panic("Whoa! Can't find EFI system table.\n");
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+       if (efi_systab_check_header(&efi_systab->hdr, 1))
                panic("Whoa! EFI system table signature incorrect\n");
-       if ((efi.systab->hdr.revision >> 16) == 0)
-               printk(KERN_WARNING "Warning: EFI system table version "
-                      "%d.%02d, expected 1.00 or greater\n",
-                      efi.systab->hdr.revision >> 16,
-                      efi.systab->hdr.revision & 0xffff);
-
-       /* Show what we know for posterity */
-       c16 = __va(efi.systab->fw_vendor);
-       if (c16) {
-               for (i = 0;i < (int) sizeof(vendor) - 1 && *c16; ++i)
-                       vendor[i] = *c16++;
-               vendor[i] = '\0';
-       }
 
-       printk(KERN_INFO "EFI v%u.%.02u by %s:",
-              efi.systab->hdr.revision >> 16,
-              efi.systab->hdr.revision & 0xffff, vendor);
+       efi_systab_report_header(&efi_systab->hdr, efi_systab->fw_vendor);
 
        palo_phys      = EFI_INVALID_TABLE_ADDR;
 
-       if (efi_config_init(arch_tables) != 0)
+       if (efi_config_parse_tables(__va(efi_systab->tables),
+                                   efi_systab->nr_tables,
+                                   arch_tables) != 0)
                return;
 
        if (palo_phys != EFI_INVALID_TABLE_ADDR)
                handle_palo(palo_phys);
 
-       runtime = __va(efi.systab->runtime);
+       runtime = __va(efi_systab->runtime);
        efi.get_time = phys_get_time;
        efi.set_time = phys_set_time;
        efi.get_wakeup_time = phys_get_wakeup_time;
@@ -1351,3 +1347,12 @@ vmcore_find_descriptor_size (unsigned long address)
        return ret;
 }
 #endif
+
+char *efi_systab_show_arch(char *str)
+{
+       if (mps_phys != EFI_INVALID_TABLE_ADDR)
+               str += sprintf(str, "MPS=0x%lx\n", mps_phys);
+       if (hcdp_phys != EFI_INVALID_TABLE_ADDR)
+               str += sprintf(str, "HCDP=0x%lx\n", hcdp_phys);
+       return str;
+}
index cb51412..4df57c9 100644 (file)
@@ -19,10 +19,6 @@ MODULE_LICENSE("GPL");
 
 #define MODULE_NAME    "esi"
 
-#define ESI_TABLE_GUID                                 \
-    EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3,         \
-            0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
-
 enum esi_systab_entry_type {
        ESI_DESC_ENTRY_POINT = 0
 };
@@ -48,27 +44,18 @@ struct pdesc {
 
 static struct ia64_sal_systab *esi_systab;
 
+extern unsigned long esi_phys;
+
 static int __init esi_init (void)
 {
-       efi_config_table_t *config_tables;
        struct ia64_sal_systab *systab;
-       unsigned long esi = 0;
        char *p;
        int i;
 
-       config_tables = __va(efi.systab->tables);
-
-       for (i = 0; i < (int) efi.systab->nr_tables; ++i) {
-               if (efi_guidcmp(config_tables[i].guid, ESI_TABLE_GUID) == 0) {
-                       esi = config_tables[i].table;
-                       break;
-               }
-       }
-
-       if (!esi)
+       if (esi_phys == EFI_INVALID_TABLE_ADDR)
                return -ENODEV;
 
-       systab = __va(esi);
+       systab = __va(esi_phys);
 
        if (strncmp(systab->signature, "ESIT", 4) != 0) {
                printk(KERN_ERR "bad signature in ESI system table!");
diff --git a/arch/ia64/kernel/irq.h b/arch/ia64/kernel/irq.h
new file mode 100644 (file)
index 0000000..4d16f3c
--- /dev/null
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+extern void register_percpu_irq(ia64_vector vec, irq_handler_t handler,
+                               unsigned long flags, const char *name);
index 8e91c86..e7862e4 100644 (file)
@@ -351,11 +351,6 @@ static irqreturn_t smp_irq_move_cleanup_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction irq_move_irqaction = {
-       .handler =      smp_irq_move_cleanup_interrupt,
-       .name =         "irq_move"
-};
-
 static int __init parse_vector_domain(char *arg)
 {
        if (!arg)
@@ -586,28 +581,15 @@ static irqreturn_t dummy_handler (int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-static struct irqaction ipi_irqaction = {
-       .handler =      handle_IPI,
-       .name =         "IPI"
-};
-
 /*
  * KVM uses this interrupt to force a cpu out of guest mode
  */
-static struct irqaction resched_irqaction = {
-       .handler =      dummy_handler,
-       .name =         "resched"
-};
-
-static struct irqaction tlb_irqaction = {
-       .handler =      dummy_handler,
-       .name =         "tlb_flush"
-};
 
 #endif
 
 void
-ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action)
+register_percpu_irq(ia64_vector vec, irq_handler_t handler, unsigned long flags,
+                   const char *name)
 {
        unsigned int irq;
 
@@ -615,8 +597,9 @@ ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action)
        BUG_ON(bind_irq_vector(irq, vec, CPU_MASK_ALL));
        irq_set_status_flags(irq, IRQ_PER_CPU);
        irq_set_chip(irq, &irq_type_ia64_lsapic);
-       if (action)
-               setup_irq(irq, action);
+       if (handler)
+               if (request_irq(irq, handler, flags, name, NULL))
+                       pr_err("Failed to request irq %u (%s)\n", irq, name);
        irq_set_handler(irq, handle_percpu_irq);
 }
 
@@ -624,9 +607,10 @@ void __init
 ia64_native_register_ipi(void)
 {
 #ifdef CONFIG_SMP
-       register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
-       register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction);
-       register_percpu_irq(IA64_IPI_LOCAL_TLB_FLUSH, &tlb_irqaction);
+       register_percpu_irq(IA64_IPI_VECTOR, handle_IPI, 0, "IPI");
+       register_percpu_irq(IA64_IPI_RESCHEDULE, dummy_handler, 0, "resched");
+       register_percpu_irq(IA64_IPI_LOCAL_TLB_FLUSH, dummy_handler, 0,
+                           "tlb_flush");
 #endif
 }
 
@@ -635,10 +619,13 @@ init_IRQ (void)
 {
        acpi_boot_init();
        ia64_register_ipi();
-       register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
+       register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL, 0, NULL);
 #ifdef CONFIG_SMP
-       if (vector_domain_type != VECTOR_DOMAIN_NONE)
-               register_percpu_irq(IA64_IRQ_MOVE_VECTOR, &irq_move_irqaction);
+       if (vector_domain_type != VECTOR_DOMAIN_NONE) {
+               register_percpu_irq(IA64_IRQ_MOVE_VECTOR,
+                                   smp_irq_move_cleanup_interrupt, 0,
+                                   "irq_move");
+       }
 #endif
 #ifdef CONFIG_PERFMON
        pfm_init_percpu();
index bf2cb92..6fb54df 100644 (file)
 
 #include "mca_drv.h"
 #include "entry.h"
+#include "irq.h"
 
 #if defined(IA64_MCA_DEBUG_INFO)
 # define IA64_MCA_DEBUG(fmt...)        printk(fmt)
@@ -1766,36 +1767,6 @@ ia64_mca_disable_cpe_polling(char *str)
 
 __setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
 
-static struct irqaction cmci_irqaction = {
-       .handler =      ia64_mca_cmc_int_handler,
-       .name =         "cmc_hndlr"
-};
-
-static struct irqaction cmcp_irqaction = {
-       .handler =      ia64_mca_cmc_int_caller,
-       .name =         "cmc_poll"
-};
-
-static struct irqaction mca_rdzv_irqaction = {
-       .handler =      ia64_mca_rendez_int_handler,
-       .name =         "mca_rdzv"
-};
-
-static struct irqaction mca_wkup_irqaction = {
-       .handler =      ia64_mca_wakeup_int_handler,
-       .name =         "mca_wkup"
-};
-
-static struct irqaction mca_cpe_irqaction = {
-       .handler =      ia64_mca_cpe_int_handler,
-       .name =         "cpe_hndlr"
-};
-
-static struct irqaction mca_cpep_irqaction = {
-       .handler =      ia64_mca_cpe_int_caller,
-       .name =         "cpe_poll"
-};
-
 /* Minimal format of the MCA/INIT stacks.  The pseudo processes that run on
  * these stacks can never sleep, they cannot return from the kernel to user
  * space, they do not appear in a normal ps listing.  So there is no need to
@@ -2056,18 +2027,23 @@ void __init ia64_mca_irq_init(void)
         *  Configure the CMCI/P vector and handler. Interrupts for CMC are
         *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
         */
-       register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
-       register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
+       register_percpu_irq(IA64_CMC_VECTOR, ia64_mca_cmc_int_handler, 0,
+                           "cmc_hndlr");
+       register_percpu_irq(IA64_CMCP_VECTOR, ia64_mca_cmc_int_caller, 0,
+                           "cmc_poll");
        ia64_mca_cmc_vector_setup();       /* Setup vector on BSP */
 
        /* Setup the MCA rendezvous interrupt vector */
-       register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
+       register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, ia64_mca_rendez_int_handler,
+                           0, "mca_rdzv");
 
        /* Setup the MCA wakeup interrupt vector */
-       register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
+       register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, ia64_mca_wakeup_int_handler,
+                           0, "mca_wkup");
 
        /* Setup the CPEI/P handler */
-       register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
+       register_percpu_irq(IA64_CPEP_VECTOR, ia64_mca_cpe_int_caller, 0,
+                           "cpe_poll");
 }
 
 /*
@@ -2108,7 +2084,9 @@ ia64_mca_late_init(void)
                        if (irq > 0) {
                                cpe_poll_enabled = 0;
                                irq_set_status_flags(irq, IRQ_PER_CPU);
-                               setup_irq(irq, &mca_cpe_irqaction);
+                               if (request_irq(irq, ia64_mca_cpe_int_handler,
+                                               0, "cpe_hndlr", NULL))
+                                       pr_err("Failed to register cpe_hndlr interrupt\n");
                                ia64_cpe_irq = irq;
                                ia64_mca_register_cpev(cpe_vector);
                                IA64_MCA_DEBUG("%s: CPEI/P setup and enabled.\n",
index a23c393..df25700 100644 (file)
@@ -57,6 +57,8 @@
 #include <linux/uaccess.h>
 #include <asm/delay.h>
 
+#include "irq.h"
+
 #ifdef CONFIG_PERFMON
 /*
  * perfmon context state
@@ -6313,11 +6315,6 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
        }
 }
 
-static struct irqaction perfmon_irqaction = {
-       .handler = pfm_interrupt_handler,
-       .name    = "perfmon"
-};
-
 static void
 pfm_alt_save_pmu_state(void *data)
 {
@@ -6591,7 +6588,8 @@ pfm_init_percpu (void)
        pfm_unfreeze_pmu();
 
        if (first_time) {
-               register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
+               register_percpu_irq(IA64_PERFMON_VECTOR, pfm_interrupt_handler,
+                                   0, "perfmon");
                first_time=0;
        }
 
index 968b5f3..10cb938 100644 (file)
@@ -646,14 +646,8 @@ cpu_halt (void)
 
 void machine_shutdown(void)
 {
-#ifdef CONFIG_HOTPLUG_CPU
-       int cpu;
+       smp_shutdown_nonboot_cpus(reboot_cpu);
 
-       for_each_online_cpu(cpu) {
-               if (cpu != smp_processor_id())
-                       cpu_down(cpu);
-       }
-#endif
 #ifdef CONFIG_KEXEC
        kexec_disable_iosapic();
 #endif
@@ -681,3 +675,4 @@ machine_power_off (void)
        machine_halt();
 }
 
+EXPORT_SYMBOL(ia64_delay_loop);
index 91b4024..7abc5f3 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/sections.h>
 
 #include "fsyscall_gtod_data.h"
+#include "irq.h"
 
 static u64 itc_get_cycles(struct clocksource *cs);
 
@@ -380,13 +381,6 @@ static u64 itc_get_cycles(struct clocksource *cs)
        return now;
 }
 
-
-static struct irqaction timer_irqaction = {
-       .handler =      timer_interrupt,
-       .flags =        IRQF_IRQPOLL,
-       .name =         "timer"
-};
-
 void read_persistent_clock64(struct timespec64 *ts)
 {
        efi_gettimeofday(ts);
@@ -395,7 +389,8 @@ void read_persistent_clock64(struct timespec64 *ts)
 void __init
 time_init (void)
 {
-       register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction);
+       register_percpu_irq(IA64_TIMER_VECTOR, timer_interrupt, IRQF_IRQPOLL,
+                           "timer");
        ia64_init_itm();
 }
 
index a09cfa0..55fd3eb 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/efi.h>
 #include <linux/io.h>
+#include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/meminit.h>
index 9d0a3a2..f1be832 100644 (file)
@@ -66,6 +66,6 @@ endif
 if !MMU
 
 config ISA_DMA_API
-        def_bool !M5272
+       def_bool !M5272
 
 endif
index f436431..11b306b 100644 (file)
@@ -12,16 +12,16 @@ config EARLY_PRINTK
        bool "Early printk"
        depends on !(SUN3 || M68000 || COLDFIRE)
        help
-          Write kernel log output directly to a serial port.
-          Where implemented, output goes to the framebuffer as well.
-          PROM console functionality on Sun 3x is not affected by this option.
+         Write kernel log output directly to a serial port.
+         Where implemented, output goes to the framebuffer as well.
+         PROM console functionality on Sun 3x is not affected by this option.
 
-          Pass "earlyprintk" on the kernel command line to get a
-          boot console.
+         Pass "earlyprintk" on the kernel command line to get a
+         boot console.
 
-          This is useful for kernel debugging when your machine crashes very
-          early, i.e. before the normal console driver is loaded.
-          You should normally say N here, unless you want to debug such a crash.
+         This is useful for kernel debugging when your machine crashes very
+         early, i.e. before the normal console driver is loaded.
+         You should normally say N here, unless you want to debug such a crash.
 
 if !MMU
 
index c01e103..b23a66b 100644 (file)
@@ -269,10 +269,10 @@ config AMCORE
          Support for the Sysam AMCORE open-hardware generic board.
 
 config STMARK2
-        bool "Sysam stmark2 board support"
-        depends on M5441x
-        help
-          Support for the Sysam stmark2 open-hardware generic board.
+       bool "Sysam stmark2 board support"
+       depends on M5441x
+       help
+         Support for the Sysam stmark2 open-hardware generic board.
 
 config FIREBEE
        bool "FireBee board support"
index e1134c3..9818d0e 100644 (file)
@@ -173,7 +173,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -369,6 +368,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -613,9 +613,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index 484cb16..db2402c 100644 (file)
@@ -169,7 +169,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -348,6 +347,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -569,9 +569,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index eb6a46b..07a28b4 100644 (file)
@@ -176,7 +176,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -364,6 +363,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -591,9 +591,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index bee9263..0335893 100644 (file)
@@ -166,7 +166,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -346,6 +345,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -562,9 +562,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index c8847a8..ee4d02a 100644 (file)
@@ -168,7 +168,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -347,6 +346,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -571,9 +571,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index 303ffaf..442eed6 100644 (file)
@@ -167,7 +167,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -363,6 +362,7 @@ CONFIG_INPUT_ADBHID=y
 CONFIG_MAC_EMUMOUSEBTN=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -593,9 +593,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index 89a7042..1de7da7 100644 (file)
@@ -187,7 +187,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -407,6 +406,7 @@ CONFIG_INPUT_ADBHID=y
 CONFIG_MAC_EMUMOUSEBTN=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -679,9 +679,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index f62c1f4..ced341e 100644 (file)
@@ -165,7 +165,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -345,6 +344,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -561,9 +561,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index 58dcad2..006188f 100644 (file)
@@ -166,7 +166,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -346,6 +345,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -562,9 +562,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index 5d3c28d..c65d985 100644 (file)
@@ -167,7 +167,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -353,6 +352,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -580,9 +580,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index 5ef9e17..32905fe 100644 (file)
@@ -163,7 +163,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -343,6 +342,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -564,9 +564,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index 22e1acc..32b0969 100644 (file)
@@ -163,7 +163,6 @@ CONFIG_NETFILTER_XT_MATCH_NFACCT=m
 CONFIG_NETFILTER_XT_MATCH_OSF=m
 CONFIG_NETFILTER_XT_MATCH_OWNER=m
 CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
 CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
 CONFIG_NETFILTER_XT_MATCH_QUOTA=m
 CONFIG_NETFILTER_XT_MATCH_RATEEST=m
@@ -343,6 +342,7 @@ CONFIG_TCM_FILEIO=m
 CONFIG_TCM_PSCSI=m
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=m
+CONFIG_WIREGUARD=m
 CONFIG_EQUALIZER=m
 CONFIG_NET_TEAM=m
 CONFIG_NET_TEAM_MODE_BROADCAST=m
@@ -563,9 +563,6 @@ CONFIG_CRYPTO_USER_API_HASH=m
 CONFIG_CRYPTO_USER_API_SKCIPHER=m
 CONFIG_CRYPTO_USER_API_RNG=m
 CONFIG_CRYPTO_USER_API_AEAD=m
-CONFIG_CRYPTO_LIB_BLAKE2S=m
-CONFIG_CRYPTO_LIB_CURVE25519=m
-CONFIG_CRYPTO_LIB_CHACHA20POLY1305=m
 # CONFIG_CRYPTO_HW is not set
 CONFIG_CRC32_SELFTEST=m
 CONFIG_CRC64=m
index 40712e4..c3a6304 100644 (file)
@@ -118,12 +118,11 @@ static int __init nfhd_init_one(int id, u32 blocks, u32 bsize)
        dev->bsize = bsize;
        dev->bshift = ffs(bsize) - 10;
 
-       dev->queue = blk_alloc_queue(GFP_KERNEL);
+       dev->queue = blk_alloc_queue(nfhd_make_request, NUMA_NO_NODE);
        if (dev->queue == NULL)
                goto free_dev;
 
        dev->queue->queuedata = dev;
-       blk_queue_make_request(dev->queue, nfhd_make_request);
        blk_queue_logical_block_size(dev->queue, bsize);
 
        dev->disk = alloc_disk(16);
index 591d53b..63f12af 100644 (file)
@@ -8,6 +8,7 @@ generic-y += emergency-restart.h
 generic-y += exec.h
 generic-y += extable.h
 generic-y += futex.h
+generic-y += hardirq.h
 generic-y += hw_irq.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
diff --git a/arch/m68k/include/asm/hardirq.h b/arch/m68k/include/asm/hardirq.h
deleted file mode 100644 (file)
index 1179316..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __M68K_HARDIRQ_H
-#define __M68K_HARDIRQ_H
-
-#include <linux/threads.h>
-#include <linux/cache.h>
-#include <asm/irq.h>
-
-#ifdef CONFIG_MMU
-
-static inline void ack_bad_irq(unsigned int irq)
-{
-       pr_crit("unexpected IRQ trap at vector %02x\n", irq);
-}
-
-/* entry.S is sensitive to the offsets of these fields */
-typedef struct {
-       unsigned int __softirq_pending;
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
-
-#else
-
-#include <asm-generic/hardirq.h>
-
-#endif /* !CONFIG_MMU */
-
-#endif
index 82ec54c..bc1228e 100644 (file)
@@ -28,21 +28,22 @@ extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
        return (pmd_t *) pgd;
 }
 
-#define pmd_populate(mm, pmd, page) (pmd_val(*pmd) = \
-       (unsigned long)(page_address(page)))
+#define pmd_populate(mm, pmd, pte) (pmd_val(*pmd) = (unsigned long)(pte))
 
-#define pmd_populate_kernel(mm, pmd, pte) (pmd_val(*pmd) = (unsigned long)(pte))
+#define pmd_populate_kernel pmd_populate
 
-#define pmd_pgtable(pmd) pmd_page(pmd)
+#define pmd_pgtable(pmd) pfn_to_virt(pmd_val(pmd) >> PAGE_SHIFT)
 
-static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page,
+static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pgtable,
                                  unsigned long address)
 {
+       struct page *page = virt_to_page(pgtable);
+
        pgtable_pte_page_dtor(page);
        __free_page(page);
 }
 
-static inline struct page *pte_alloc_one(struct mm_struct *mm)
+static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
 {
        struct page *page = alloc_pages(GFP_DMA, 0);
        pte_t *pte;
@@ -54,20 +55,16 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm)
                return NULL;
        }
 
-       pte = kmap(page);
-       if (pte) {
-               clear_page(pte);
-               __flush_page_to_ram(pte);
-               flush_tlb_kernel_page(pte);
-               nocache_page(pte);
-       }
-       kunmap(page);
+       pte = page_address(page);
+       clear_page(pte);
 
-       return page;
+       return pte;
 }
 
-static inline void pte_free(struct mm_struct *mm, struct page *page)
+static inline void pte_free(struct mm_struct *mm, pgtable_t pgtable)
 {
+       struct page *page = virt_to_page(pgtable);
+
        pgtable_pte_page_dtor(page);
        __free_page(page);
 }
@@ -90,7 +87,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
        new_pgd = (pgd_t *)__get_free_page(GFP_DMA | __GFP_NOWARN);
        if (!new_pgd)
                return NULL;
-       memcpy(new_pgd, swapper_pg_dir, PAGE_SIZE);
+       memcpy(new_pgd, swapper_pg_dir, PTRS_PER_PGD * sizeof(pgd_t));
        memset(new_pgd, 0, PAGE_OFFSET >> PGDIR_SHIFT);
        return new_pgd;
 }
index ff9cc40..c66e429 100644 (file)
@@ -5,93 +5,71 @@
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
-extern pmd_t *get_pointer_table(void);
-extern int free_pointer_table(pmd_t *);
+extern void mmu_page_ctor(void *page);
+extern void mmu_page_dtor(void *page);
 
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
-{
-       pte_t *pte;
+enum m68k_table_types {
+       TABLE_PGD = 0,
+       TABLE_PMD = 0, /* same size as PGD */
+       TABLE_PTE = 1,
+};
 
-       pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
-       if (pte) {
-               __flush_page_to_ram(pte);
-               flush_tlb_kernel_page(pte);
-               nocache_page(pte);
-       }
+extern void init_pointer_table(void *table, int type);
+extern void *get_pointer_table(int type);
+extern int free_pointer_table(void *table, int type);
 
-       return pte;
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm)
+{
+       return get_pointer_table(TABLE_PTE);
 }
 
 static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 {
-       cache_page(pte);
-       free_page((unsigned long) pte);
+       free_pointer_table(pte, TABLE_PTE);
 }
 
 static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
 {
-       struct page *page;
-       pte_t *pte;
-
-       page = alloc_pages(GFP_KERNEL|__GFP_ZERO, 0);
-       if(!page)
-               return NULL;
-       if (!pgtable_pte_page_ctor(page)) {
-               __free_page(page);
-               return NULL;
-       }
-
-       pte = kmap(page);
-       __flush_page_to_ram(pte);
-       flush_tlb_kernel_page(pte);
-       nocache_page(pte);
-       kunmap(page);
-       return page;
+       return get_pointer_table(TABLE_PTE);
 }
 
-static inline void pte_free(struct mm_struct *mm, pgtable_t page)
+static inline void pte_free(struct mm_struct *mm, pgtable_t pgtable)
 {
-       pgtable_pte_page_dtor(page);
-       cache_page(kmap(page));
-       kunmap(page);
-       __free_page(page);
+       free_pointer_table(pgtable, TABLE_PTE);
 }
 
-static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t page,
+static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pgtable,
                                  unsigned long address)
 {
-       pgtable_pte_page_dtor(page);
-       cache_page(kmap(page));
-       kunmap(page);
-       __free_page(page);
+       free_pointer_table(pgtable, TABLE_PTE);
 }
 
 
 static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-       return get_pointer_table();
+       return get_pointer_table(TABLE_PMD);
 }
 
 static inline int pmd_free(struct mm_struct *mm, pmd_t *pmd)
 {
-       return free_pointer_table(pmd);
+       return free_pointer_table(pmd, TABLE_PMD);
 }
 
 static inline int __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
                                 unsigned long address)
 {
-       return free_pointer_table(pmd);
+       return free_pointer_table(pmd, TABLE_PMD);
 }
 
 
 static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-       pmd_free(mm, (pmd_t *)pgd);
+       free_pointer_table(pgd, TABLE_PGD);
 }
 
 static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
-       return (pgd_t *)get_pointer_table();
+       return get_pointer_table(TABLE_PGD);
 }
 
 
@@ -102,9 +80,9 @@ static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *
 
 static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pgtable_t page)
 {
-       pmd_set(pmd, page_address(page));
+       pmd_set(pmd, page);
 }
-#define pmd_pgtable(pmd) pmd_page(pmd)
+#define pmd_pgtable(pmd) ((pgtable_t)__pmd_page(pmd))
 
 static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
 {
index 62bedc6..4b91a47 100644 (file)
 #define _DESCTYPE_MASK 0x003
 
 #define _CACHEMASK040  (~0x060)
-#define _TABLE_MASK    (0xfffffe00)
+
+/*
+ * Currently set to the minimum alignment of table pointers (256 bytes).
+ * The hardware only uses the low 4 bits for state:
+ *
+ *    3 - Used
+ *    2 - Write Protected
+ *  0,1 - Descriptor Type
+ *
+ * and has the rest of the bits reserved.
+ */
+#define _TABLE_MASK    (0xffffff00)
 
 #define _PAGE_TABLE    (_PAGE_SHORT)
 #define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NOCACHE)
@@ -108,13 +119,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 
 static inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
 {
-       unsigned long ptbl = virt_to_phys(ptep) | _PAGE_TABLE | _PAGE_ACCESSED;
-       unsigned long *ptr = pmdp->pmd;
-       short i = 16;
-       while (--i >= 0) {
-               *ptr++ = ptbl;
-               ptbl += (sizeof(pte_t)*PTRS_PER_PTE/16);
-       }
+       pmd_val(*pmdp) = virt_to_phys(ptep) | _PAGE_TABLE | _PAGE_ACCESSED;
 }
 
 static inline void pud_set(pud_t *pudp, pmd_t *pmdp)
@@ -138,13 +143,14 @@ static inline void pud_set(pud_t *pudp, pmd_t *pmdp)
 #define pmd_none(pmd)          (!pmd_val(pmd))
 #define pmd_bad(pmd)           ((pmd_val(pmd) & _DESCTYPE_MASK) != _PAGE_TABLE)
 #define pmd_present(pmd)       (pmd_val(pmd) & _PAGE_TABLE)
-#define pmd_clear(pmdp) ({                     \
-       unsigned long *__ptr = pmdp->pmd;       \
-       short __i = 16;                         \
-       while (--__i >= 0)                      \
-               *__ptr++ = 0;                   \
-})
-#define pmd_page(pmd)          virt_to_page(__va(pmd_val(pmd)))
+#define pmd_clear(pmdp)                ({ pmd_val(*pmdp) = 0; })
+
+/*
+ * m68k does not have huge pages (020/030 actually could), but generic code
+ * expects pmd_page() to exists, only to then DCE it all. Provide a dummy to
+ * make the compiler happy.
+ */
+#define pmd_page(pmd)          NULL
 
 
 #define pud_none(pud)          (!pud_val(pud))
index 05e1e1e..da54648 100644 (file)
  * These are used to make use of C type-checking..
  */
 #if !defined(CONFIG_MMU) || CONFIG_PGTABLE_LEVELS == 3
-typedef struct { unsigned long pmd[16]; } pmd_t;
-#define pmd_val(x)     ((&x)->pmd[0])
-#define __pmd(x)       ((pmd_t) { { (x) }, })
+typedef struct { unsigned long pmd; } pmd_t;
+#define pmd_val(x)     ((&x)->pmd)
+#define __pmd(x)       ((pmd_t) { (x) } )
 #endif
 
 typedef struct { unsigned long pte; } pte_t;
 typedef struct { unsigned long pgd; } pgd_t;
 typedef struct { unsigned long pgprot; } pgprot_t;
+
+#if defined(CONFIG_SUN3)
+/*
+ * Sun3 still uses the asm-generic/pgalloc.h code and thus needs this
+ * definition. It would be possible to unify Sun3 and ColdFire pgalloc and have
+ * all of m68k use the same type.
+ */
 typedef struct page *pgtable_t;
+#else
+typedef pte_t *pgtable_t;
+#endif
 
 #define pte_val(x)     ((x).pte)
 #define pgd_val(x)     ((x).pgd)
index 2bf5c35..f0e5167 100644 (file)
@@ -36,7 +36,7 @@
 
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
 #if CONFIG_PGTABLE_LEVELS == 3
-#define PMD_SHIFT      22
+#define PMD_SHIFT      18
 #endif
 #define PMD_SIZE       (1UL << PMD_SHIFT)
 #define PMD_MASK       (~(PMD_SIZE-1))
@@ -67,8 +67,8 @@
 #define PTRS_PER_PMD   1
 #define PTRS_PER_PGD   1024
 #else
-#define PTRS_PER_PTE   1024
-#define PTRS_PER_PMD   8
+#define PTRS_PER_PTE   64
+#define PTRS_PER_PMD   128
 #define PTRS_PER_PGD   128
 #endif
 #define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
@@ -76,8 +76,8 @@
 
 /* Virtual address region for use by kernel_map() */
 #ifdef CONFIG_SUN3
-#define KMAP_START     0x0DC00000
-#define KMAP_END       0x0E000000
+#define KMAP_START     0x0dc00000
+#define KMAP_END       0x0e000000
 #elif defined(CONFIG_COLDFIRE)
 #define KMAP_START     0xe0000000
 #define KMAP_END       0xf0000000
index 6bc80c3..a24cfe4 100644 (file)
@@ -5,7 +5,6 @@
 /*
  * User space memory access functions
  */
-#include <linux/mm.h>
 #include <linux/string.h>
 
 #include <asm/segment.h>
index 27c453f..b88d510 100644 (file)
 void *empty_zero_page;
 EXPORT_SYMBOL(empty_zero_page);
 
-#if !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
-extern void init_pointer_table(unsigned long ptable);
-extern pmd_t *zero_pgtable;
-#endif
-
 #ifdef CONFIG_MMU
 
 pg_data_t pg_data_map[MAX_NUMNODES];
@@ -125,20 +120,31 @@ void free_initmem(void)
 static inline void init_pointer_tables(void)
 {
 #if defined(CONFIG_MMU) && !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
-       int i;
+       int i, j;
 
        /* insert pointer tables allocated so far into the tablelist */
-       init_pointer_table((unsigned long)kernel_pg_dir);
+       init_pointer_table(kernel_pg_dir, TABLE_PGD);
        for (i = 0; i < PTRS_PER_PGD; i++) {
-               pud_t *pud = (pud_t *)(&kernel_pg_dir[i]);
+               pud_t *pud = (pud_t *)&kernel_pg_dir[i];
+               pmd_t *pmd_dir;
 
-               if (pud_present(*pud))
-                       init_pointer_table(pgd_page_vaddr(kernel_pg_dir[i]));
-       }
+               if (!pud_present(*pud))
+                       continue;
+
+               pmd_dir = (pmd_t *)pgd_page_vaddr(kernel_pg_dir[i]);
+               init_pointer_table(pmd_dir, TABLE_PMD);
 
-       /* insert also pointer table that we used to unmap the zero page */
-       if (zero_pgtable)
-               init_pointer_table((unsigned long)zero_pgtable);
+               for (j = 0; j < PTRS_PER_PMD; j++) {
+                       pmd_t *pmd = &pmd_dir[j];
+                       pte_t *pte_dir;
+
+                       if (!pmd_present(*pmd))
+                               continue;
+
+                       pte_dir = (pte_t *)__pmd_page(*pmd);
+                       init_pointer_table(pte_dir, TABLE_PTE);
+               }
+       }
 #endif
 }
 
index 120030a..14d31d2 100644 (file)
@@ -24,8 +24,6 @@
 
 #undef DEBUG
 
-#define PTRTREESIZE    (256*1024)
-
 /*
  * For 040/060 we can use the virtual memory area like other architectures,
  * but for 020/030 we want to use early termination page descriptors and we
@@ -50,7 +48,7 @@ static inline void free_io_area(void *addr)
 
 #else
 
-#define IO_SIZE                (256*1024)
+#define IO_SIZE                PMD_SIZE
 
 static struct vm_struct *iolist;
 
@@ -81,14 +79,13 @@ static void __free_io_area(void *addr, unsigned long size)
 
 #if CONFIG_PGTABLE_LEVELS == 3
                if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
-                       int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
+                       int pmd_type = pmd_val(*pmd_dir) & _DESCTYPE_MASK;
 
                        if (pmd_type == _PAGE_PRESENT) {
-                               pmd_dir->pmd[pmd_off] = 0;
-                               virtaddr += PTRTREESIZE;
-                               size -= PTRTREESIZE;
-                               continue;
+                               pmd_clear(pmd_dir);
+                               virtaddr += PMD_SIZE;
+                               size -= PMD_SIZE;
+
                        } else if (pmd_type == 0)
                                continue;
                }
@@ -249,7 +246,7 @@ void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cachefla
 
        while ((long)size > 0) {
 #ifdef DEBUG
-               if (!(virtaddr & (PTRTREESIZE-1)))
+               if (!(virtaddr & (PMD_SIZE-1)))
                        printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
 #endif
                pgd_dir = pgd_offset_k(virtaddr);
@@ -263,10 +260,10 @@ void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cachefla
 
 #if CONFIG_PGTABLE_LEVELS == 3
                if (CPU_IS_020_OR_030) {
-                       pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
-                       physaddr += PTRTREESIZE;
-                       virtaddr += PTRTREESIZE;
-                       size -= PTRTREESIZE;
+                       pmd_val(*pmd_dir) = physaddr;
+                       physaddr += PMD_SIZE;
+                       virtaddr += PMD_SIZE;
+                       size -= PMD_SIZE;
                } else
 #endif
                {
@@ -367,13 +364,12 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
 
 #if CONFIG_PGTABLE_LEVELS == 3
                if (CPU_IS_020_OR_030) {
-                       int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+                       unsigned long pmd = pmd_val(*pmd_dir);
 
-                       if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
-                               pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
-                                                        _CACHEMASK040) | cmode;
-                               virtaddr += PTRTREESIZE;
-                               size -= PTRTREESIZE;
+                       if ((pmd & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+                               *pmd_dir = __pmd((pmd & _CACHEMASK040) | cmode);
+                               virtaddr += PMD_SIZE;
+                               size -= PMD_SIZE;
                                continue;
                        }
                }
index 227c04f..65e0c40 100644 (file)
 #include <asm/machdep.h>
 
 
-/* ++andreas: {get,free}_pointer_table rewritten to use unused fields from
-   struct page instead of separately kmalloced struct.  Stolen from
-   arch/sparc/mm/srmmu.c ... */
-
-typedef struct list_head ptable_desc;
-static LIST_HEAD(ptable_list);
-
-#define PD_PTABLE(page) ((ptable_desc *)&(virt_to_page(page)->lru))
-#define PD_PAGE(ptable) (list_entry(ptable, struct page, lru))
-#define PD_MARKBITS(dp) (*(unsigned char *)&PD_PAGE(dp)->index)
-
-#define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
-
-void __init init_pointer_table(unsigned long ptable)
-{
-       ptable_desc *dp;
-       unsigned long page = ptable & PAGE_MASK;
-       unsigned char mask = 1 << ((ptable - page)/PTABLE_SIZE);
-
-       dp = PD_PTABLE(page);
-       if (!(PD_MARKBITS(dp) & mask)) {
-               PD_MARKBITS(dp) = 0xff;
-               list_add(dp, &ptable_list);
-       }
-
-       PD_MARKBITS(dp) &= ~mask;
-       pr_debug("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp));
-
-       /* unreserve the page so it's possible to free that page */
-       __ClearPageReserved(PD_PAGE(dp));
-       init_page_count(PD_PAGE(dp));
-
-       return;
-}
-
-pmd_t *get_pointer_table (void)
-{
-       ptable_desc *dp = ptable_list.next;
-       unsigned char mask = PD_MARKBITS (dp);
-       unsigned char tmp;
-       unsigned int off;
-
-       /*
-        * For a pointer table for a user process address space, a
-        * table is taken from a page allocated for the purpose.  Each
-        * page can hold 8 pointer tables.  The page is remapped in
-        * virtual address space to be noncacheable.
-        */
-       if (mask == 0) {
-               void *page;
-               ptable_desc *new;
-
-               if (!(page = (void *)get_zeroed_page(GFP_KERNEL)))
-                       return NULL;
-
-               flush_tlb_kernel_page(page);
-               nocache_page(page);
-
-               new = PD_PTABLE(page);
-               PD_MARKBITS(new) = 0xfe;
-               list_add_tail(new, dp);
-
-               return (pmd_t *)page;
-       }
-
-       for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += PTABLE_SIZE)
-               ;
-       PD_MARKBITS(dp) = mask & ~tmp;
-       if (!PD_MARKBITS(dp)) {
-               /* move to end of list */
-               list_move_tail(dp, &ptable_list);
-       }
-       return (pmd_t *) (page_address(PD_PAGE(dp)) + off);
-}
-
-int free_pointer_table (pmd_t *ptable)
-{
-       ptable_desc *dp;
-       unsigned long page = (unsigned long)ptable & PAGE_MASK;
-       unsigned char mask = 1 << (((unsigned long)ptable - page)/PTABLE_SIZE);
-
-       dp = PD_PTABLE(page);
-       if (PD_MARKBITS (dp) & mask)
-               panic ("table already free!");
-
-       PD_MARKBITS (dp) |= mask;
-
-       if (PD_MARKBITS(dp) == 0xff) {
-               /* all tables in page are free, free page */
-               list_del(dp);
-               cache_page((void *)page);
-               free_page (page);
-               return 1;
-       } else if (ptable_list.next != dp) {
-               /*
-                * move this descriptor to the front of the list, since
-                * it has one or more free tables.
-                */
-               list_move(dp, &ptable_list);
-       }
-       return 0;
-}
-
 /* invalidate page in both caches */
 static inline void clear040(unsigned long paddr)
 {
index 4857985..fc16190 100644 (file)
@@ -45,34 +45,185 @@ unsigned long mm_cachebits;
 EXPORT_SYMBOL(mm_cachebits);
 #endif
 
+
+/*
+ * Motorola 680x0 user's manual recommends using uncached memory for address
+ * translation tables.
+ *
+ * Seeing how the MMU can be external on (some of) these chips, that seems like
+ * a very important recommendation to follow. Provide some helpers to combat
+ * 'variation' amongst the users of this.
+ */
+
+void mmu_page_ctor(void *page)
+{
+       __flush_page_to_ram(page);
+       flush_tlb_kernel_page(page);
+       nocache_page(page);
+}
+
+void mmu_page_dtor(void *page)
+{
+       cache_page(page);
+}
+
+/* ++andreas: {get,free}_pointer_table rewritten to use unused fields from
+   struct page instead of separately kmalloced struct.  Stolen from
+   arch/sparc/mm/srmmu.c ... */
+
+typedef struct list_head ptable_desc;
+
+static struct list_head ptable_list[2] = {
+       LIST_HEAD_INIT(ptable_list[0]),
+       LIST_HEAD_INIT(ptable_list[1]),
+};
+
+#define PD_PTABLE(page) ((ptable_desc *)&(virt_to_page(page)->lru))
+#define PD_PAGE(ptable) (list_entry(ptable, struct page, lru))
+#define PD_MARKBITS(dp) (*(unsigned int *)&PD_PAGE(dp)->index)
+
+static const int ptable_shift[2] = {
+       7+2, /* PGD, PMD */
+       6+2, /* PTE */
+};
+
+#define ptable_size(type) (1U << ptable_shift[type])
+#define ptable_mask(type) ((1U << (PAGE_SIZE / ptable_size(type))) - 1)
+
+void __init init_pointer_table(void *table, int type)
+{
+       ptable_desc *dp;
+       unsigned long ptable = (unsigned long)table;
+       unsigned long page = ptable & PAGE_MASK;
+       unsigned int mask = 1U << ((ptable - page)/ptable_size(type));
+
+       dp = PD_PTABLE(page);
+       if (!(PD_MARKBITS(dp) & mask)) {
+               PD_MARKBITS(dp) = ptable_mask(type);
+               list_add(dp, &ptable_list[type]);
+       }
+
+       PD_MARKBITS(dp) &= ~mask;
+       pr_debug("init_pointer_table: %lx, %x\n", ptable, PD_MARKBITS(dp));
+
+       /* unreserve the page so it's possible to free that page */
+       __ClearPageReserved(PD_PAGE(dp));
+       init_page_count(PD_PAGE(dp));
+
+       return;
+}
+
+void *get_pointer_table(int type)
+{
+       ptable_desc *dp = ptable_list[type].next;
+       unsigned int mask = list_empty(&ptable_list[type]) ? 0 : PD_MARKBITS(dp);
+       unsigned int tmp, off;
+
+       /*
+        * For a pointer table for a user process address space, a
+        * table is taken from a page allocated for the purpose.  Each
+        * page can hold 8 pointer tables.  The page is remapped in
+        * virtual address space to be noncacheable.
+        */
+       if (mask == 0) {
+               void *page;
+               ptable_desc *new;
+
+               if (!(page = (void *)get_zeroed_page(GFP_KERNEL)))
+                       return NULL;
+
+               if (type == TABLE_PTE) {
+                       /*
+                        * m68k doesn't have SPLIT_PTE_PTLOCKS for not having
+                        * SMP.
+                        */
+                       pgtable_pte_page_ctor(virt_to_page(page));
+               }
+
+               mmu_page_ctor(page);
+
+               new = PD_PTABLE(page);
+               PD_MARKBITS(new) = ptable_mask(type) - 1;
+               list_add_tail(new, dp);
+
+               return (pmd_t *)page;
+       }
+
+       for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += ptable_size(type))
+               ;
+       PD_MARKBITS(dp) = mask & ~tmp;
+       if (!PD_MARKBITS(dp)) {
+               /* move to end of list */
+               list_move_tail(dp, &ptable_list[type]);
+       }
+       return page_address(PD_PAGE(dp)) + off;
+}
+
+int free_pointer_table(void *table, int type)
+{
+       ptable_desc *dp;
+       unsigned long ptable = (unsigned long)table;
+       unsigned long page = ptable & PAGE_MASK;
+       unsigned int mask = 1U << ((ptable - page)/ptable_size(type));
+
+       dp = PD_PTABLE(page);
+       if (PD_MARKBITS (dp) & mask)
+               panic ("table already free!");
+
+       PD_MARKBITS (dp) |= mask;
+
+       if (PD_MARKBITS(dp) == ptable_mask(type)) {
+               /* all tables in page are free, free page */
+               list_del(dp);
+               mmu_page_dtor((void *)page);
+               if (type == TABLE_PTE)
+                       pgtable_pte_page_dtor(virt_to_page(page));
+               free_page (page);
+               return 1;
+       } else if (ptable_list[type].next != dp) {
+               /*
+                * move this descriptor to the front of the list, since
+                * it has one or more free tables.
+                */
+               list_move(dp, &ptable_list[type]);
+       }
+       return 0;
+}
+
 /* size of memory already mapped in head.S */
 extern __initdata unsigned long m68k_init_mapped_size;
 
 extern unsigned long availmem;
 
+static pte_t *last_pte_table __initdata = NULL;
+
 static pte_t * __init kernel_page_table(void)
 {
-       pte_t *ptablep;
+       pte_t *pte_table = last_pte_table;
 
-       ptablep = (pte_t *)memblock_alloc_low(PAGE_SIZE, PAGE_SIZE);
-       if (!ptablep)
-               panic("%s: Failed to allocate %lu bytes align=%lx\n",
-                     __func__, PAGE_SIZE, PAGE_SIZE);
+       if (((unsigned long)last_pte_table & ~PAGE_MASK) == 0) {
+               pte_table = (pte_t *)memblock_alloc_low(PAGE_SIZE, PAGE_SIZE);
+               if (!pte_table) {
+                       panic("%s: Failed to allocate %lu bytes align=%lx\n",
+                                       __func__, PAGE_SIZE, PAGE_SIZE);
+               }
 
-       clear_page(ptablep);
-       __flush_page_to_ram(ptablep);
-       flush_tlb_kernel_page(ptablep);
-       nocache_page(ptablep);
+               clear_page(pte_table);
+               mmu_page_ctor(pte_table);
 
-       return ptablep;
+               last_pte_table = pte_table;
+       }
+
+       last_pte_table += PTRS_PER_PTE;
+
+       return pte_table;
 }
 
-static pmd_t *last_pgtable __initdata = NULL;
-pmd_t *zero_pgtable __initdata = NULL;
+static pmd_t *last_pmd_table __initdata = NULL;
 
 static pmd_t * __init kernel_ptr_table(void)
 {
-       if (!last_pgtable) {
+       if (!last_pmd_table) {
                unsigned long pmd, last;
                int i;
 
@@ -91,33 +242,29 @@ static pmd_t * __init kernel_ptr_table(void)
                                last = pmd;
                }
 
-               last_pgtable = (pmd_t *)last;
+               last_pmd_table = (pmd_t *)last;
 #ifdef DEBUG
-               printk("kernel_ptr_init: %p\n", last_pgtable);
+               printk("kernel_ptr_init: %p\n", last_pmd_table);
 #endif
        }
 
-       last_pgtable += PTRS_PER_PMD;
-       if (((unsigned long)last_pgtable & ~PAGE_MASK) == 0) {
-               last_pgtable = (pmd_t *)memblock_alloc_low(PAGE_SIZE,
+       last_pmd_table += PTRS_PER_PMD;
+       if (((unsigned long)last_pmd_table & ~PAGE_MASK) == 0) {
+               last_pmd_table = (pmd_t *)memblock_alloc_low(PAGE_SIZE,
                                                           PAGE_SIZE);
-               if (!last_pgtable)
+               if (!last_pmd_table)
                        panic("%s: Failed to allocate %lu bytes align=%lx\n",
                              __func__, PAGE_SIZE, PAGE_SIZE);
 
-               clear_page(last_pgtable);
-               __flush_page_to_ram(last_pgtable);
-               flush_tlb_kernel_page(last_pgtable);
-               nocache_page(last_pgtable);
+               clear_page(last_pmd_table);
+               mmu_page_ctor(last_pmd_table);
        }
 
-       return last_pgtable;
+       return last_pmd_table;
 }
 
 static void __init map_node(int node)
 {
-#define PTRTREESIZE (256*1024)
-#define ROOTTREESIZE (32*1024*1024)
        unsigned long physaddr, virtaddr, size;
        pgd_t *pgd_dir;
        p4d_t *p4d_dir;
@@ -135,21 +282,21 @@ static void __init map_node(int node)
 
        while (size > 0) {
 #ifdef DEBUG
-               if (!(virtaddr & (PTRTREESIZE-1)))
+               if (!(virtaddr & (PMD_SIZE-1)))
                        printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK,
                                virtaddr);
 #endif
                pgd_dir = pgd_offset_k(virtaddr);
                if (virtaddr && CPU_IS_020_OR_030) {
-                       if (!(virtaddr & (ROOTTREESIZE-1)) &&
-                           size >= ROOTTREESIZE) {
+                       if (!(virtaddr & (PGDIR_SIZE-1)) &&
+                           size >= PGDIR_SIZE) {
 #ifdef DEBUG
                                printk ("[very early term]");
 #endif
                                pgd_val(*pgd_dir) = physaddr;
-                               size -= ROOTTREESIZE;
-                               virtaddr += ROOTTREESIZE;
-                               physaddr += ROOTTREESIZE;
+                               size -= PGDIR_SIZE;
+                               virtaddr += PGDIR_SIZE;
+                               physaddr += PGDIR_SIZE;
                                continue;
                        }
                }
@@ -169,24 +316,23 @@ static void __init map_node(int node)
 #ifdef DEBUG
                                printk ("[early term]");
 #endif
-                               pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
-                               physaddr += PTRTREESIZE;
+                               pmd_val(*pmd_dir) = physaddr;
+                               physaddr += PMD_SIZE;
                        } else {
                                int i;
 #ifdef DEBUG
                                printk ("[zero map]");
 #endif
-                               zero_pgtable = kernel_ptr_table();
-                               pte_dir = (pte_t *)zero_pgtable;
-                               pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
-                                       _PAGE_TABLE | _PAGE_ACCESSED;
+                               pte_dir = kernel_page_table();
+                               pmd_set(pmd_dir, pte_dir);
+
                                pte_val(*pte_dir++) = 0;
                                physaddr += PAGE_SIZE;
-                               for (i = 1; i < 64; physaddr += PAGE_SIZE, i++)
+                               for (i = 1; i < PTRS_PER_PTE; physaddr += PAGE_SIZE, i++)
                                        pte_val(*pte_dir++) = physaddr;
                        }
-                       size -= PTRTREESIZE;
-                       virtaddr += PTRTREESIZE;
+                       size -= PMD_SIZE;
+                       virtaddr += PMD_SIZE;
                } else {
                        if (!pmd_present(*pmd_dir)) {
 #ifdef DEBUG
index 6a331bd..242f58e 100644 (file)
@@ -47,6 +47,8 @@ config MICROBLAZE
        select CPU_NO_EFFICIENT_FFS
        select MMU_GATHER_NO_RANGE if MMU
        select SPARSE_IRQ
+       select GENERIC_IRQ_MULTI_HANDLER
+       select HANDLE_DOMAIN_IRQ
 
 # Endianness selection
 choice
index e5c9170..abb3361 100644 (file)
@@ -1,6 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 generated-y += syscall_table.h
-generic-y += barrier.h
 generic-y += bitops.h
 generic-y += bug.h
 generic-y += bugs.h
@@ -13,6 +12,7 @@ generic-y += exec.h
 generic-y += extable.h
 generic-y += fb.h
 generic-y += hardirq.h
+generic-y += hw_irq.h
 generic-y += irq_regs.h
 generic-y += irq_work.h
 generic-y += kdebug.h
@@ -31,8 +31,10 @@ generic-y += preempt.h
 generic-y += serial.h
 generic-y += shmparam.h
 generic-y += syscalls.h
+generic-y += tlb.h
 generic-y += topology.h
 generic-y += trace_clock.h
+generic-y += user.h
 generic-y += vga.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
diff --git a/arch/microblaze/include/asm/barrier.h b/arch/microblaze/include/asm/barrier.h
new file mode 100644 (file)
index 0000000..70b0a01
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2015 - 2020 Xilinx, Inc. All rights reserved.
+ */
+
+#ifndef _ASM_MICROBLAZE_BARRIER_H
+#define _ASM_MICROBLAZE_BARRIER_H
+
+#define mb()   __asm__ __volatile__ ("mbar 1" : : : "memory")
+
+#include <asm-generic/barrier.h>
+
+#endif /* _ASM_MICROBLAZE_BARRIER_H */
index 4efe96a..a149b3e 100644 (file)
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Cache operations
  *
  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2003 John Williams <jwilliams@itee.uq.edu.au>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_CACHE_H
index b091de7..11f56c8 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
@@ -5,11 +6,6 @@
  * based on v850 version which was
  * Copyright (C) 2001,02,03 NEC Electronics Corporation
  * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
- *
  */
 
 #ifndef _ASM_MICROBLAZE_CACHEFLUSH_H
index adeeceb..2e5ebd5 100644 (file)
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_CHECKSUM_H
index 596300c..3523b51 100644 (file)
@@ -2,42 +2,8 @@
 #ifndef _ASM_MICROBLAZE_CMPXCHG_H
 #define _ASM_MICROBLAZE_CMPXCHG_H
 
-#include <linux/irqflags.h>
-
-void __bad_xchg(volatile void *ptr, int size);
-
-static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
-                                                               int size)
-{
-       unsigned long ret;
-       unsigned long flags;
-
-       switch (size) {
-       case 1:
-               local_irq_save(flags);
-               ret = *(volatile unsigned char *)ptr;
-               *(volatile unsigned char *)ptr = x;
-               local_irq_restore(flags);
-               break;
-
-       case 4:
-               local_irq_save(flags);
-               ret = *(volatile unsigned long *)ptr;
-               *(volatile unsigned long *)ptr = x;
-               local_irq_restore(flags);
-               break;
-       default:
-               __bad_xchg(ptr, size), ret = 0;
-               break;
-       }
-
-       return ret;
-}
-
-#define xchg(ptr, x) \
-       ((__typeof__(*(ptr))) __xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-
-#include <asm-generic/cmpxchg.h>
-#include <asm-generic/cmpxchg-local.h>
+#ifndef CONFIG_SMP
+# include <asm-generic/cmpxchg.h>
+#endif
 
 #endif /* _ASM_MICROBLAZE_CMPXCHG_H */
index 8f49967..786ffa6 100644 (file)
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Generic support for queying CPU info
  *
  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2007 John Williams <jwilliams@itee.uq.edu.au>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_CPUINFO_H
diff --git a/arch/microblaze/include/asm/cputable.h b/arch/microblaze/include/asm/cputable.h
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
index 29303ed..a4bb45b 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_CURRENT_H
index ea2a9cd..05fe9e3 100644 (file)
@@ -1,10 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * include/asm-microblaze/delay.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
  * Copyright (C) 2008 Michal Simek
  * Copyright (C) 2007 John Williams
  * Copyright (C) 2006 Atmark Techno, Inc.
index 0d73d0c..e6cb6d0 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_DMA_H
index 6590244..5331a84 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 #ifndef _ASM_MICROBLAZE_ELF_H
 #define _ASM_MICROBLAZE_ELF_H
index 596e485..6c42bed 100644 (file)
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Definitions used by low-level trap handlers
  *
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_ENTRY_H
index e6a8dde..d67e65b 100644 (file)
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Preliminary support for HW exception handing for Microblaze
  *
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2005 John Williams <jwilliams@itee.uq.edu.au>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_EXCEPTIONS_H
index 06c0e2b..0379ce5 100644 (file)
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * fixmap.h: compile-time virtual memory allocation
  *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
  * Copyright (C) 1998 Ingo Molnar
  *
  * Copyright 2008 Freescale Semiconductor Inc.
index 1ab8677..79a749f 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * uClinux flat-format executables
  *
  * Copyright (C) 2005 John Williams <jwilliams@itee.uq.edu.au>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_FLAT_H
index 8c90357..86131ed 100644 (file)
@@ -34,7 +34,8 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
        int oldval = 0, ret;
 
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -56,8 +57,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
diff --git a/arch/microblaze/include/asm/hw_irq.h b/arch/microblaze/include/asm/hw_irq.h
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
index d33c617..1dd6fae 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_IO_H
index eac2fb4..cb6ab55 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_IRQ_H
@@ -14,7 +11,4 @@
 struct pt_regs;
 extern void do_IRQ(struct pt_regs *regs);
 
-/* should be defined in each interrupt controller driver */
-extern unsigned int xintc_get_irq(void);
-
 #endif /* _ASM_MICROBLAZE_IRQ_H */
index c9a6262..818c6c9 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_IRQFLAGS_H
index 1f9eddd..97f1243 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_MMU_H
index 97559fe..a1c7dd4 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_MMU_CONTEXT_H
index 7be1347..eda1c18 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_MODULE_H
index f4b44b2..ae7215c 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * VM ops
  *
@@ -6,10 +7,6 @@
  * Copyright (C) 2006 Atmark Techno, Inc.
  * Changes for MMU support:
  *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_PAGE_H
index fcf1e23..1d7a912 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_PGALLOC_H
index 2def331..45b3087 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_PGTABLE_H
index 66b537b..1ff5a82 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_PROCESSOR_H
index 5b18ec1..bfcb89d 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 #ifndef _ASM_MICROBLAZE_PTRACE_H
 #define _ASM_MICROBLAZE_PTRACE_H
index 4bbdb4c..186ee8c 100644 (file)
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Support for the MicroBlaze PVR (Processor Version Register)
  *
  * Copyright (C) 2009 - 2011 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
  * Copyright (C) 2007 - 2011 PetaLogix
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_PVR_H
index 68c3afb..ee81e1c 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_REGISTERS_H
index 1b281d3..a9311ad 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_SECTIONS_H
index ce9b7b7..be10da9 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 #ifndef _ASM_MICROBLAZE_SETUP_H
 #define _ASM_MICROBLAZE_SETUP_H
@@ -13,8 +10,6 @@
 #include <uapi/asm/setup.h>
 
 # ifndef __ASSEMBLY__
-extern unsigned int boot_cpuid; /* move to smp.h */
-
 extern char cmd_line[COMMAND_LINE_SIZE];
 
 extern char *klimit;
index aec2f59..34071a8 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_STRING_H
index f45baa2..5afd6d9 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_SWITCH_TO_H
index 9afe4b5..ad8e8fc 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_THREAD_INFO_H
index befcf3d..e99cc29 100644 (file)
@@ -1,9 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_TIMEX_H
diff --git a/arch/microblaze/include/asm/tlb.h b/arch/microblaze/include/asm/tlb.h
deleted file mode 100644 (file)
index 628a78e..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
- * Copyright (C) 2008-2009 PetaLogix
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_TLB_H
-#define _ASM_MICROBLAZE_TLB_H
-
-#include <linux/pagemap.h>
-#include <asm-generic/tlb.h>
-
-#endif /* _ASM_MICROBLAZE_TLB_H */
index 2e1353c..6f8f5c7 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_TLBFLUSH_H
index a1f206b..070ba61 100644 (file)
@@ -1,18 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2008-2009 PetaLogix
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_UACCESS_H
 #define _ASM_MICROBLAZE_UACCESS_H
 
 #include <linux/kernel.h>
-#include <linux/mm.h>
 
 #include <asm/mmu.h>
 #include <asm/page.h>
index b162ed8..448299b 100644 (file)
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2008 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef _ASM_MICROBLAZE_UNALIGNED_H
index d79d35a..cfe3f88 100644 (file)
@@ -1,10 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2007-2008 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 #ifndef _ASM_MICROBLAZE_UNISTD_H
 #define _ASM_MICROBLAZE_UNISTD_H
index d248b7d..c327d67 100644 (file)
@@ -1,11 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Backtrace support for Microblaze
  *
  * Copyright (C) 2010  Digital Design Corporation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
  */
 
 #ifndef __MICROBLAZE_UNWIND_H
diff --git a/arch/microblaze/include/asm/user.h b/arch/microblaze/include/asm/user.h
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
index a32daec..c7ee51b 100644 (file)
 
 #define CI(c, p) { ci->c = PVR_##p(pvr); }
 
-#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 #define err_printk(x) \
-       early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n");
-#else
-#define err_printk(x) \
-       pr_info("ERROR: Microblaze " x "-different for PVR and DTS\n");
-#endif
+       pr_err("ERROR: Microblaze " x "-different for PVR and DTS\n");
 
 void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
 {
index 8d0dc6d..f139052 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/compiler.h>
 #include <asm/exceptions.h>
 #include <asm/pvr.h>
+#include <linux/irqflags.h>
 
 /*
  * Until we get an assembler that knows about the pvr registers,
index f6ded35..b179f8f 100644 (file)
@@ -958,6 +958,7 @@ ENTRY(_switch_to)
        nop
 
 ENTRY(_reset)
+       VM_OFF
        brai    0; /* Jump to reset vector */
 
        /* These are compiled and loaded into high memory, then
index 903dad8..0b37dde 100644 (file)
 #include <linux/irqchip.h>
 #include <linux/of_irq.h>
 
-static u32 concurrent_irq;
-
 void __irq_entry do_IRQ(struct pt_regs *regs)
 {
-       unsigned int irq;
-       struct pt_regs *old_regs = set_irq_regs(regs);
        trace_hardirqs_off();
-
-       irq_enter();
-       irq = xintc_get_irq();
-next_irq:
-       BUG_ON(!irq);
-       generic_handle_irq(irq);
-
-       irq = xintc_get_irq();
-       if (irq != -1U) {
-               pr_debug("next irq: %d\n", irq);
-               ++concurrent_irq;
-               goto next_irq;
-       }
-
-       irq_exit();
-       set_irq_regs(old_regs);
+       handle_arch_irq(regs);
        trace_hardirqs_on();
 }
 
index 6759af6..1228a09 100644 (file)
@@ -39,7 +39,7 @@ _tlbia_1:
        rsubi   r11, r12, MICROBLAZE_TLB_SIZE - 1
        bneid   r11, _tlbia_1 /* loop for all entries */
        addik   r12, r12, 1
-       /* sync */
+       mbar    1 /* sync */
        rtsd    r15, 8
        nop
        .size  _tlbia, . - _tlbia
@@ -58,6 +58,7 @@ _tlbie:
        blti    r12, _tlbie_1 /* Check if found */
        mts     rtlbhi, r0 /* flush: ensure V is clear */
        nop
+       mbar    1 /* sync */
 _tlbie_1:
        rtsd    r15, 8
        nop
index 511c1ab..dd121e3 100644 (file)
@@ -41,7 +41,6 @@ DEFINE_PER_CPU(unsigned int, ENTRY_SP);       /* Saved SP on kernel entry */
 DEFINE_PER_CPU(unsigned int, R11_SAVE);        /* Temp variable for entry */
 DEFINE_PER_CPU(unsigned int, CURRENT_SAVE);    /* Saved current pointer */
 
-unsigned int boot_cpuid;
 /*
  * Placed cmd_line to .data section because can be initialized from
  * ASM code. Default position is BSS section which is cleared
@@ -54,7 +53,6 @@ void __init setup_arch(char **cmdline_p)
        *cmdline_p = boot_command_line;
 
        setup_memory();
-       parse_early_param();
 
        console_verbose();
 
index a668348..f8832cf 100644 (file)
@@ -161,13 +161,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction timer_irqaction = {
-       .handler = timer_interrupt,
-       .flags = IRQF_TIMER,
-       .name = "timer",
-       .dev_id = &clockevent_xilinx_timer,
-};
-
 static __init int xilinx_clockevent_init(void)
 {
        clockevent_xilinx_timer.mult =
@@ -309,7 +302,8 @@ static int __init xilinx_timer_init(struct device_node *timer)
 
        freq_div_hz = timer_clock_freq / HZ;
 
-       ret = setup_irq(irq, &timer_irqaction);
+       ret = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer",
+                         &clockevent_xilinx_timer);
        if (ret) {
                pr_err("Failed to setup IRQ");
                return ret;
index 2c09fa3..df07b3d 100644 (file)
@@ -13,6 +13,7 @@ ENTRY(microblaze_start)
 
 #define RO_EXCEPTION_TABLE_ALIGN       16
 
+#include <asm/cache.h>
 #include <asm/page.h>
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/thread_info.h>
@@ -89,6 +90,8 @@ SECTIONS {
                _KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ;
        }
 
+       PERCPU_SECTION(L1_CACHE_BYTES)
+
        . = ALIGN(PAGE_SIZE);
        __init_begin = .;
 
index 1056f16..1ffbfa9 100644 (file)
@@ -201,18 +201,6 @@ void __init mem_init(void)
 #endif
 
        mem_init_print_info(NULL);
-#ifdef CONFIG_MMU
-       pr_info("Kernel virtual memory layout:\n");
-       pr_info("  * 0x%08lx..0x%08lx  : fixmap\n", FIXADDR_START, FIXADDR_TOP);
-#ifdef CONFIG_HIGHMEM
-       pr_info("  * 0x%08lx..0x%08lx  : highmem PTEs\n",
-               PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP));
-#endif /* CONFIG_HIGHMEM */
-       pr_info("  * 0x%08lx..0x%08lx  : early ioremap\n",
-               ioremap_bot, ioremap_base);
-       pr_info("  * 0x%08lx..0x%08lx  : vmalloc & ioremap\n",
-               (unsigned long)VMALLOC_START, VMALLOC_END);
-#endif
        mem_init_done = 1;
 }
 
@@ -347,6 +335,8 @@ asmlinkage void __init mmu_init(void)
         * inside 768MB limit */
        memblock_set_current_limit(memory_start + lowmem_size - 1);
 
+       parse_early_param();
+
        /* CMA initialization */
        dma_contiguous_reserve(memory_start + lowmem_size - 1);
 }
index 797d7f1..f8f3dbd 100644 (file)
@@ -4,7 +4,6 @@ config MIPS
        default y
        select ARCH_32BIT_OFF_T if !64BIT
        select ARCH_BINFMT_ELF_STATE if MIPS_FP_SUPPORT
-       select ARCH_CLOCKSOURCE_DATA
        select ARCH_HAS_FORTIFY_SOURCE
        select ARCH_HAS_KCOV
        select ARCH_HAS_PTE_SPECIAL if !(32BIT && CPU_HAS_RIXI)
@@ -51,6 +50,7 @@ config MIPS
        select HAVE_ASM_MODVERSIONS
        select HAVE_CBPF_JIT if !64BIT && !CPU_MICROMIPS
        select HAVE_CONTEXT_TRACKING
+       select HAVE_TIF_NOHZ
        select HAVE_COPY_THREAD_TLS
        select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
@@ -486,9 +486,11 @@ config MACH_LOONGSON64
        select SYS_SUPPORTS_HIGHMEM
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_SUPPORTS_ZBOOT
-       select LOONGSON_MC146818
        select ZONE_DMA32
        select NUMA
+       select COMMON_CLK
+       select USE_OF
+       select BUILTIN_DTB
        help
          This enables the support of Loongson-2/3 family of machines.
 
@@ -973,6 +975,9 @@ config CAVIUM_OCTEON_SOC
        select SYS_HAS_EARLY_PRINTK
        select SYS_HAS_CPU_CAVIUM_OCTEON
        select HAVE_PCI
+       select HAVE_PLAT_DELAY
+       select HAVE_PLAT_FW_INIT_CMDLINE
+       select HAVE_PLAT_MEMCPY
        select ZONE_DMA32
        select HOLES_IN_ZONE
        select GPIOLIB
@@ -1229,6 +1234,15 @@ config GENERIC_ISA_DMA_SUPPORT_BROKEN
        bool
        select GENERIC_ISA_DMA
 
+config HAVE_PLAT_DELAY
+       bool
+
+config HAVE_PLAT_FW_INIT_CMDLINE
+       bool
+
+config HAVE_PLAT_MEMCPY
+       bool
+
 config ISA_DMA_API
        bool
 
@@ -2676,7 +2690,7 @@ config NUMA
          Say Y to compile the kernel to support NUMA (Non-Uniform Memory
          Access).  This option improves performance on systems with more
          than two nodes; on two node systems it is generally better to
-         leave it disabled; on single node systems disable this option
+         leave it disabled; on single node systems leave this option
          disabled.
 
 config SYS_SUPPORTS_NUMA
@@ -2758,6 +2772,17 @@ config HW_PERF_EVENTS
          Enable hardware performance counter support for perf events. If
          disabled, perf events will use software events only.
 
+config DMI
+       bool "Enable DMI scanning"
+       depends on MACH_LOONGSON64
+       select DMI_SCAN_MACHINE_NON_EFI_FALLBACK
+       default y
+       help
+         Enabled scanning of DMI to identify machine quirks. Say Y
+         here unless you have verified that your setup is not
+         affected by entries in the DMI blacklist. Required by PNP
+         BIOS code.
+
 config SMP
        bool "Multi-Processing support"
        depends on SYS_SUPPORTS_SMP
@@ -3070,7 +3095,7 @@ endchoice
 choice
        prompt "Kernel command line type" if !CMDLINE_OVERRIDE
        default MIPS_CMDLINE_FROM_DTB if USE_OF && !ATH79 && !MACH_INGENIC && \
-                                        !MIPS_MALTA && \
+                                        !MACH_LOONGSON64 && !MIPS_MALTA && \
                                         !CAVIUM_OCTEON_SOC
        default MIPS_CMDLINE_FROM_BOOTLOADER
 
index 3a21a6a..d794ffb 100644 (file)
@@ -72,13 +72,6 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = {
        .cpumask        = cpu_possible_mask,
 };
 
-static struct irqaction au1x_rtcmatch2_irqaction = {
-       .handler        = au1x_rtcmatch2_irq,
-       .flags          = IRQF_TIMER,
-       .name           = "timer",
-       .dev_id         = &au1x_rtcmatch2_clockdev,
-};
-
 static int __init alchemy_time_init(unsigned int m2int)
 {
        struct clock_event_device *cd = &au1x_rtcmatch2_clockdev;
@@ -130,7 +123,9 @@ static int __init alchemy_time_init(unsigned int m2int)
        cd->min_delta_ns = clockevent_delta2ns(9, cd);
        cd->min_delta_ticks = 9;        /* ~0.28ms */
        clockevents_register_device(cd);
-       setup_irq(m2int, &au1x_rtcmatch2_irqaction);
+       if (request_irq(m2int, au1x_rtcmatch2_irq, IRQF_TIMER, "timer",
+                       &au1x_rtcmatch2_clockdev))
+               pr_err("Failed to register timer interrupt\n");
 
        printk(KERN_INFO "Alchemy clocksource installed\n");
 
index 93a331f..f0a7942 100644 (file)
@@ -83,12 +83,6 @@ static struct irq_chip ar7_sec_irq_type = {
        .irq_ack = ar7_ack_sec_irq,
 };
 
-static struct irqaction ar7_cascade_action = {
-       .handler = no_action,
-       .name = "AR7 cascade interrupt",
-       .flags = IRQF_NO_THREAD,
-};
-
 static void __init ar7_irq_init(int base)
 {
        int i;
@@ -116,8 +110,14 @@ static void __init ar7_irq_init(int base)
                                                 handle_level_irq);
        }
 
-       setup_irq(2, &ar7_cascade_action);
-       setup_irq(ar7_irq_base, &ar7_cascade_action);
+       if (request_irq(2, no_action, IRQF_NO_THREAD, "AR7 cascade interrupt",
+                       NULL))
+               pr_err("Failed to request irq 2 (AR7 cascade interrupt)\n");
+       if (request_irq(ar7_irq_base, no_action, IRQF_NO_THREAD,
+                       "AR7 cascade interrupt", NULL)) {
+               pr_err("Failed to request irq %d (AR7 cascade interrupt)\n",
+                      ar7_irq_base);
+       }
        set_c0_status(IE_IRQ0);
 }
 
index 24f6191..e7b53e3 100644 (file)
@@ -64,11 +64,6 @@ static irqreturn_t ar2315_ahb_err_handler(int cpl, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction ar2315_ahb_err_interrupt  = {
-       .handler        = ar2315_ahb_err_handler,
-       .name           = "ar2315-ahb-error",
-};
-
 static void ar2315_misc_irq_handler(struct irq_desc *desc)
 {
        u32 pending = ar2315_rst_reg_read(AR2315_ISR) &
@@ -159,7 +154,9 @@ void __init ar2315_arch_init_irq(void)
                panic("Failed to add IRQ domain");
 
        irq = irq_create_mapping(domain, AR2315_MISC_IRQ_AHB);
-       setup_irq(irq, &ar2315_ahb_err_interrupt);
+       if (request_irq(irq, ar2315_ahb_err_handler, 0, "ar2315-ahb-error",
+                       NULL))
+               pr_err("Failed to register ar2315-ahb-error interrupt\n");
 
        irq_set_chained_handler_and_data(AR2315_IRQ_MISC,
                                         ar2315_misc_irq_handler, domain);
index 47f3e98..42bf2af 100644 (file)
@@ -68,11 +68,6 @@ static irqreturn_t ar5312_ahb_err_handler(int cpl, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction ar5312_ahb_err_interrupt  = {
-       .handler = ar5312_ahb_err_handler,
-       .name    = "ar5312-ahb-error",
-};
-
 static void ar5312_misc_irq_handler(struct irq_desc *desc)
 {
        u32 pending = ar5312_rst_reg_read(AR5312_ISR) &
@@ -154,7 +149,9 @@ void __init ar5312_arch_init_irq(void)
                panic("Failed to add IRQ domain");
 
        irq = irq_create_mapping(domain, AR5312_MISC_IRQ_AHB_PROC);
-       setup_irq(irq, &ar5312_ahb_err_interrupt);
+       if (request_irq(irq, ar5312_ahb_err_handler, 0, "ar5312-ahb-error",
+                       NULL))
+               pr_err("Failed to register ar5312-ahb-error interrupt\n");
 
        irq_set_chained_handler_and_data(AR5312_IRQ_MISC,
                                         ar5312_misc_irq_handler, domain);
index 484ee28..acb4fd6 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/memblock.h>
 #include <linux/err.h>
 #include <linux/clk.h>
-#include <linux/clk-provider.h>
+#include <linux/of_clk.h>
 #include <linux/of_fdt.h>
 #include <linux/irqchip.h>
 
index ec694b9..2548013 100644 (file)
@@ -399,26 +399,6 @@ static struct irq_chip bcm63xx_external_irq_chip = {
        .irq_set_type   = bcm63xx_external_irq_set_type,
 };
 
-static struct irqaction cpu_ip2_cascade_action = {
-       .handler        = no_action,
-       .name           = "cascade_ip2",
-       .flags          = IRQF_NO_THREAD,
-};
-
-#ifdef CONFIG_SMP
-static struct irqaction cpu_ip3_cascade_action = {
-       .handler        = no_action,
-       .name           = "cascade_ip3",
-       .flags          = IRQF_NO_THREAD,
-};
-#endif
-
-static struct irqaction cpu_ext_cascade_action = {
-       .handler        = no_action,
-       .name           = "cascade_extirq",
-       .flags          = IRQF_NO_THREAD,
-};
-
 static void bcm63xx_init_irq(void)
 {
        int irq_bits;
@@ -531,7 +511,7 @@ static void bcm63xx_init_irq(void)
 
 void __init arch_init_irq(void)
 {
-       int i;
+       int i, irq;
 
        bcm63xx_init_irq();
        mips_cpu_irq_init();
@@ -544,14 +524,25 @@ void __init arch_init_irq(void)
                                         handle_edge_irq);
 
        if (!is_ext_irq_cascaded) {
-               for (i = 3; i < 3 + ext_irq_count; ++i)
-                       setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action);
+               for (i = 3; i < 3 + ext_irq_count; ++i) {
+                       irq = MIPS_CPU_IRQ_BASE + i;
+                       if (request_irq(irq, no_action, IRQF_NO_THREAD,
+                                       "cascade_extirq", NULL)) {
+                               pr_err("Failed to request irq %d (cascade_extirq)\n",
+                                      irq);
+                       }
+               }
        }
 
-       setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action);
+       irq = MIPS_CPU_IRQ_BASE + 2;
+       if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade_ip2", NULL))
+               pr_err("Failed to request irq %d (cascade_ip2)\n", irq);
 #ifdef CONFIG_SMP
        if (is_ext_irq_cascaded) {
-               setup_irq(MIPS_CPU_IRQ_BASE + 3, &cpu_ip3_cascade_action);
+               irq = MIPS_CPU_IRQ_BASE + 3;
+               if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade_ip3",
+                               NULL))
+                       pr_err("Failed to request irq %d (cascade_ip3)\n", irq);
                bcm63xx_internal_irq_chip.irq_set_affinity =
                        bcm63xx_internal_set_affinity;
 
index 2f81a94..19308df 100644 (file)
 #include <linux/init.h>
 #include <linux/bitops.h>
 #include <linux/memblock.h>
-#include <linux/clk-provider.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/of_clk.h>
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
 #include <linux/libfdt.h>
index 1e79cab..d429a69 100644 (file)
@@ -4,6 +4,7 @@ subdir-y        += cavium-octeon
 subdir-y       += img
 subdir-y       += ingenic
 subdir-y       += lantiq
+subdir-y       += loongson
 subdir-y       += mscc
 subdir-y       += mti
 subdir-y       += netlogic
index 37b9316..db0ca25 100644 (file)
@@ -4,6 +4,9 @@
 #include "jz4780.dtsi"
 #include <dt-bindings/clock/ingenic,tcu.h>
 #include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/regulator/active-semi,8865-regulator.h>
 
 / {
        compatible = "img,ci20", "ingenic,jz4780";
                       0x30000000 0x30000000>;
        };
 
+       gpio-keys {
+               compatible = "gpio-keys";
+
+               sw1 {
+                       label = "ci20:sw1";
+                       linux,code = <KEY_F13>;
+                       gpios = <&gpd 17 GPIO_ACTIVE_HIGH>;
+                       wakeup-source;
+               };
+       };
+
        leds {
                compatible = "gpio-leds";
 
        eth0_power: fixedregulator@0 {
                compatible = "regulator-fixed";
                regulator-name = "eth0_power";
+               regulator-min-microvolt = <3300000>;
+               regulator-max-microvolt = <3300000>;
                gpio = <&gpb 25 GPIO_ACTIVE_LOW>;
                enable-active-high;
        };
 
+       ir: ir {
+               compatible = "gpio-ir-receiver";
+               gpios = <&gpe 3 GPIO_ACTIVE_LOW>;
+       };
+
        wlan0_power: fixedregulator@1 {
                compatible = "regulator-fixed";
                regulator-name = "wlan0_power";
 
                regulators {
                        vddcore: SUDCDC1 {
-                               regulator-name = "VDDCORE";
+                               regulator-name = "DCDC_REG1";
                                regulator-min-microvolt = <1100000>;
                                regulator-max-microvolt = <1100000>;
                                regulator-always-on;
                        };
                        vddmem: SUDCDC2 {
-                               regulator-name = "VDDMEM";
+                               regulator-name = "DCDC_REG2";
                                regulator-min-microvolt = <1500000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                        };
                        vcc_33: SUDCDC3 {
-                               regulator-name = "VCC33";
+                               regulator-name = "DCDC_REG3";
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
                        vcc_50: SUDCDC4 {
-                               regulator-name = "VCC50";
+                               regulator-name = "SUDCDC_REG4";
                                regulator-min-microvolt = <5000000>;
                                regulator-max-microvolt = <5000000>;
                                regulator-always-on;
                        };
                        vcc_25: LDO_REG5 {
-                               regulator-name = "VCC25";
+                               regulator-name = "LDO_REG5";
                                regulator-min-microvolt = <2500000>;
                                regulator-max-microvolt = <2500000>;
                                regulator-always-on;
                        };
                        wifi_io: LDO_REG6 {
-                               regulator-name = "WIFIIO";
+                               regulator-name = "LDO_REG6";
                                regulator-min-microvolt = <2500000>;
                                regulator-max-microvolt = <2500000>;
                                regulator-always-on;
                        };
                        vcc_28: LDO_REG7 {
-                               regulator-name = "VCC28";
+                               regulator-name = "LDO_REG7";
                                regulator-min-microvolt = <2800000>;
                                regulator-max-microvolt = <2800000>;
                                regulator-always-on;
                        };
                        vcc_15: LDO_REG8 {
-                               regulator-name = "VCC15";
+                               regulator-name = "LDO_REG8";
                                regulator-min-microvolt = <1500000>;
                                regulator-max-microvolt = <1500000>;
                                regulator-always-on;
                        };
-                       vcc_18: LDO_REG9 {
-                               regulator-name = "VCC18";
-                               regulator-min-microvolt = <1800000>;
-                               regulator-max-microvolt = <1800000>;
+                       vrtc_18: LDO_REG9 {
+                               regulator-name = "LDO_REG9";
+                               /* Despite the datasheet stating 3.3V
+                                * for REG9 and the driver expecting that,
+                                * REG9 outputs 1.8V.
+                                * Likely the CI20 uses a proprietary
+                                * factory programmed chip variant.
+                                * Since this is a simple on/off LDO the
+                                * exact values do not matter.
+                                */
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
                                regulator-always-on;
                        };
                        vcc_11: LDO_REG10 {
-                               regulator-name = "VCC11";
-                               regulator-min-microvolt = <1100000>;
-                               regulator-max-microvolt = <1100000>;
+                               regulator-name = "LDO_REG10";
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <1200000>;
                                regulator-always-on;
                        };
                };
                rtc@51 {
                        compatible = "nxp,pcf8563";
                        reg = <0x51>;
-                       interrupts = <110>;
+
+                       interrupt-parent = <&gpf>;
+                       interrupts = <30 IRQ_TYPE_LEVEL_LOW>;
                };
 };
 
index 5accda2..a3301ba 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <dt-bindings/clock/jz4740-cgu.h>
+#include <dt-bindings/clock/ingenic,tcu.h>
 
 / {
        #address-cells = <1>;
                #clock-cells = <1>;
        };
 
-       watchdog: watchdog@10002000 {
-               compatible = "ingenic,jz4740-watchdog";
-               reg = <0x10002000 0x10>;
-
-               clocks = <&cgu JZ4740_CLK_RTC>;
-               clock-names = "rtc";
-       };
-
        tcu: timer@10002000 {
                compatible = "ingenic,jz4740-tcu", "simple-mfd";
                reg = <0x10002000 0x1000>;
 
                interrupt-parent = <&intc>;
                interrupts = <23 22 21>;
+
+               watchdog: watchdog@0 {
+                       compatible = "ingenic,jz4740-watchdog";
+                       reg = <0x0 0xc>;
+
+                       clocks = <&tcu TCU_CLK_WDT>;
+                       clock-names = "wdt";
+               };
        };
 
        rtc_dev: rtc@10003000 {
index f928329..bb89653 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <dt-bindings/clock/jz4780-cgu.h>
+#include <dt-bindings/clock/ingenic,tcu.h>
 #include <dt-bindings/dma/jz4780-dma.h>
 
 / {
 
                interrupt-parent = <&intc>;
                interrupts = <27 26 25>;
+
+               watchdog: watchdog@0 {
+                       compatible = "ingenic,jz4780-watchdog";
+                       reg = <0x0 0xc>;
+
+                       clocks = <&tcu TCU_CLK_WDT>;
+                       clock-names = "wdt";
+               };
        };
 
        rtc_dev: rtc@10003000 {
                status = "disabled";
        };
 
-       watchdog: watchdog@10002000 {
-               compatible = "ingenic,jz4780-watchdog";
-               reg = <0x10002000 0x10>;
-
-               clocks = <&cgu JZ4780_CLK_RTCLK>;
-               clock-names = "rtc";
-       };
-
        nemc: nemc@13410000 {
                compatible = "ingenic,jz4780-nemc";
                reg = <0x13410000 0x10000>;
index 4994c69..147f7d5 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <dt-bindings/clock/ingenic,tcu.h>
 #include <dt-bindings/clock/x1000-cgu.h>
 #include <dt-bindings/dma/x1000-dma.h>
 
@@ -72,7 +73,7 @@
                        compatible = "ingenic,x1000-watchdog", "ingenic,jz4780-watchdog";
                        reg = <0x0 0x10>;
 
-                       clocks = <&cgu X1000_CLK_RTCLK>;
+                       clocks = <&tcu TCU_CLK_WDT>;
                        clock-names = "wdt";
                };
        };
        i2c0: i2c-controller@10050000 {
                compatible = "ingenic,x1000-i2c";
                reg = <0x10050000 0x1000>;
-
                #address-cells = <1>;
                #size-cells = <0>;
 
        i2c1: i2c-controller@10051000 {
                compatible = "ingenic,x1000-i2c";
                reg = <0x10051000 0x1000>;
-
                #address-cells = <1>;
                #size-cells = <0>;
 
        i2c2: i2c-controller@10052000 {
                compatible = "ingenic,x1000-i2c";
                reg = <0x10052000 0x1000>;
-
                #address-cells = <1>;
                #size-cells = <0>;
 
diff --git a/arch/mips/boot/dts/loongson/Makefile b/arch/mips/boot/dts/loongson/Makefile
new file mode 100644 (file)
index 0000000..56d3794
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX_License_Identifier: GPL_2.0
+dtb-$(CONFIG_MACH_LOONGSON64)  += loongson3_4core_rs780e.dtb loongson3_8core_rs780e.dtb
+
+obj-$(CONFIG_BUILTIN_DTB)      += $(addsuffix .o, $(dtb-y))
diff --git a/arch/mips/boot/dts/loongson/loongson3-package.dtsi b/arch/mips/boot/dts/loongson/loongson3-package.dtsi
new file mode 100644 (file)
index 0000000..5bb876a
--- /dev/null
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       cpuintc: interrupt-controller {
+               #address-cells = <0>;
+               #interrupt-cells = <1>;
+               interrupt-controller;
+               compatible = "mti,cpu-interrupt-controller";
+       };
+
+       package0: bus@1fe00000 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges = <0 0x1fe00000 0 0x1fe00000 0x100000
+                       0 0x3ff00000 0 0x3ff00000 0x100000
+                       /* 3A HT Config Space */
+                       0xefd 0xfb000000 0xefd 0xfb000000 0x10000000
+                       /* 3B HT Config Space */
+                       0x1efd 0xfb000000 0x1efd 0xfb000000 0x10000000>;
+
+               liointc: interrupt-controller@3ff01400 {
+                       compatible = "loongson,liointc-1.0";
+                       reg = <0 0x3ff01400 0x64>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+
+                       interrupt-parent = <&cpuintc>;
+                       interrupts = <2>, <3>;
+                       interrupt-names = "int0", "int1";
+
+                       loongson,parent_int_map = <0xf0ffffff>, /* int0 */
+                                               <0x0f000000>, /* int1 */
+                                               <0x00000000>, /* int2 */
+                                               <0x00000000>; /* int3 */
+
+               };
+
+               cpu_uart0: serial@1fe001e0 {
+                       compatible = "ns16550a";
+                       reg = <0 0x1fe001e0 0x8>;
+                       clock-frequency = <33000000>;
+                       interrupt-parent = <&liointc>;
+                       interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+                       no-loopback-test;
+               };
+
+               cpu_uart1: serial@1fe001e8 {
+                       status = "disabled";
+                       compatible = "ns16550a";
+                       reg = <0 0x1fe001e8 0x8>;
+                       clock-frequency = <33000000>;
+                       interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-parent = <&liointc>;
+                       no-loopback-test;
+               };
+       };
+};
diff --git a/arch/mips/boot/dts/loongson/loongson3_4core_rs780e.dts b/arch/mips/boot/dts/loongson/loongson3_4core_rs780e.dts
new file mode 100644 (file)
index 0000000..6b5694c
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/dts-v1/;
+
+#include "loongson3-package.dtsi"
+#include "rs780e-pch.dtsi"
+
+/ {
+       compatible = "loongson,loongson3-4core-rs780e";
+};
+
+&package0 {
+       htpic: interrupt-controller@efdfb000080 {
+               compatible = "loongson,htpic-1.0";
+               reg = <0xefd 0xfb000080 0x40>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+
+               interrupt-parent = <&liointc>;
+               interrupts = <24 IRQ_TYPE_LEVEL_HIGH>,
+                               <25 IRQ_TYPE_LEVEL_HIGH>,
+                               <26 IRQ_TYPE_LEVEL_HIGH>,
+                               <27 IRQ_TYPE_LEVEL_HIGH>;
+       };
+};
diff --git a/arch/mips/boot/dts/loongson/loongson3_8core_rs780e.dts b/arch/mips/boot/dts/loongson/loongson3_8core_rs780e.dts
new file mode 100644 (file)
index 0000000..ffefa2f
--- /dev/null
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/dts-v1/;
+
+#include "loongson3-package.dtsi"
+#include "rs780e-pch.dtsi"
+
+/ {
+       compatible = "loongson,loongson3-8core-rs780e";
+};
+
+&package0 {
+       htpic: interrupt-controller@1efdfb000080 {
+               compatible = "loongson,htpic-1.0";
+               reg = <0x1efd 0xfb000080 0x40>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+
+               interrupt-parent = <&liointc>;
+               interrupts = <24 IRQ_TYPE_LEVEL_HIGH>,
+                               <25 IRQ_TYPE_LEVEL_HIGH>,
+                               <26 IRQ_TYPE_LEVEL_HIGH>,
+                               <27 IRQ_TYPE_LEVEL_HIGH>;
+       };
+};
diff --git a/arch/mips/boot/dts/loongson/rs780e-pch.dtsi b/arch/mips/boot/dts/loongson/rs780e-pch.dtsi
new file mode 100644 (file)
index 0000000..45c54d5
--- /dev/null
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+       bus@10000000 {
+               compatible = "simple-bus";
+               #address-cells = <2>;
+               #size-cells = <2>;
+               ranges = <0 0x10000000 0 0x10000000 0 0x10000000
+                               0 0x40000000 0 0x40000000 0 0x40000000
+                               0xfd 0xfe000000 0xfd 0xfe000000  0 0x2000000 /* PCI Config Space */>;
+
+               isa {
+                       compatible = "isa";
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+                       ranges = <1 0 0 0 0x1000>;
+
+                       rtc0: rtc@70 {
+                               compatible = "motorola,mc146818";
+                               reg = <1 0x70 0x8>;
+                               interrupts = <8>;
+                               interrupt-parent = <&htpic>;
+                       };
+               };
+       };
+};
index 2e2d45b..abd11b7 100644 (file)
@@ -207,9 +207,9 @@ int cvmx_helper_board_get_mii_address(int ipd_port)
  * Returns The ports link status. If the link isn't fully resolved, this must
  *        return zero.
  */
-cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
+union cvmx_helper_link_info __cvmx_helper_board_link_get(int ipd_port)
 {
-       cvmx_helper_link_info_t result;
+       union cvmx_helper_link_info result;
 
        WARN(!octeon_is_simulation(),
             "Using deprecated link status - please update your DT");
index e812ed9..c4b5859 100644 (file)
@@ -261,7 +261,7 @@ int __cvmx_helper_rgmii_enable(int interface)
  *
  * Returns Link state
  */
-cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
+union cvmx_helper_link_info __cvmx_helper_rgmii_link_get(int ipd_port)
 {
        int interface = cvmx_helper_get_interface_num(ipd_port);
        int index = cvmx_helper_get_interface_index_num(ipd_port);
@@ -270,7 +270,7 @@ cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
        asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
        if (asxx_prt_loop.s.int_loop & (1 << index)) {
                /* Force 1Gbps full duplex on internal loopback */
-               cvmx_helper_link_info_t result;
+               union cvmx_helper_link_info result;
                result.u64 = 0;
                result.s.full_duplex = 1;
                result.s.link_up = 1;
@@ -292,7 +292,7 @@ cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
  * Returns Zero on success, negative on failure
  */
 int __cvmx_helper_rgmii_link_set(int ipd_port,
-                                cvmx_helper_link_info_t link_info)
+                                union cvmx_helper_link_info link_info)
 {
        int result = 0;
        int interface = cvmx_helper_get_interface_num(ipd_port);
index f6ebf63..e07d8f1 100644 (file)
@@ -200,7 +200,7 @@ static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
  */
 static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface,
                                                        int index,
-                                                       cvmx_helper_link_info_t
+                                                       union cvmx_helper_link_info
                                                        link_info)
 {
        int is_enabled;
@@ -394,9 +394,9 @@ int __cvmx_helper_sgmii_enable(int interface)
  *
  * Returns Link state
  */
-cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
+union cvmx_helper_link_info __cvmx_helper_sgmii_link_get(int ipd_port)
 {
-       cvmx_helper_link_info_t result;
+       union cvmx_helper_link_info result;
        union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
        int interface = cvmx_helper_get_interface_num(ipd_port);
        int index = cvmx_helper_get_interface_index_num(ipd_port);
@@ -505,7 +505,7 @@ cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
  * Returns Zero on success, negative on failure
  */
 int __cvmx_helper_sgmii_link_set(int ipd_port,
-                                cvmx_helper_link_info_t link_info)
+                                union cvmx_helper_link_info link_info)
 {
        int interface = cvmx_helper_get_interface_num(ipd_port);
        int index = cvmx_helper_get_interface_index_num(ipd_port);
index 2a574d2..525914e 100644 (file)
@@ -140,9 +140,9 @@ int __cvmx_helper_spi_enable(int interface)
  *
  * Returns Link state
  */
-cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port)
+union cvmx_helper_link_info __cvmx_helper_spi_link_get(int ipd_port)
 {
-       cvmx_helper_link_info_t result;
+       union cvmx_helper_link_info result;
        int interface = cvmx_helper_get_interface_num(ipd_port);
        int index = cvmx_helper_get_interface_index_num(ipd_port);
        result.u64 = 0;
@@ -193,7 +193,7 @@ cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port)
  *
  * Returns Zero on success, negative on failure
  */
-int __cvmx_helper_spi_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
+int __cvmx_helper_spi_link_set(int ipd_port, union cvmx_helper_link_info link_info)
 {
        /* Nothing to do. If we have a SPI4000 then the setup was already performed
           by cvmx_spi4000_check_speed(). If not then there isn't any link
index 93a498d..842990e 100644 (file)
@@ -259,13 +259,13 @@ int __cvmx_helper_xaui_enable(int interface)
  *
  * Returns Link state
  */
-cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
+union cvmx_helper_link_info __cvmx_helper_xaui_link_get(int ipd_port)
 {
        int interface = cvmx_helper_get_interface_num(ipd_port);
        union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
        union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
        union cvmx_pcsxx_status1_reg pcsxx_status1_reg;
-       cvmx_helper_link_info_t result;
+       union cvmx_helper_link_info result;
 
        gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
        gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
@@ -299,7 +299,7 @@ cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
  *
  * Returns Zero on success, negative on failure
  */
-int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
+int __cvmx_helper_xaui_link_set(int ipd_port, union cvmx_helper_link_info link_info)
 {
        int interface = cvmx_helper_get_interface_num(ipd_port);
        union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
index de39154..6044ff4 100644 (file)
@@ -782,9 +782,9 @@ static int __cvmx_helper_errata_fix_ipd_ptr_alignment(void)
 #define INTERFACE(port) (port >> 4)
 #define INDEX(port) (port & 0xf)
        uint64_t *p64;
-       cvmx_pko_command_word0_t pko_command;
+       union cvmx_pko_command_word0 pko_command;
        union cvmx_buf_ptr g_buffer, pkt_buffer;
-       cvmx_wqe_t *work;
+       struct cvmx_wqe *work;
        int size, num_segs = 0, wqe_pcnt, pkt_pcnt;
        union cvmx_gmxx_prtx_cfg gmx_cfg;
        int retry_cnt;
@@ -1075,9 +1075,9 @@ int cvmx_helper_initialize_packet_io_local(void)
  *
  * Returns Link state
  */
-cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
+union cvmx_helper_link_info cvmx_helper_link_get(int ipd_port)
 {
-       cvmx_helper_link_info_t result;
+       union cvmx_helper_link_info result;
        int interface = cvmx_helper_get_interface_num(ipd_port);
        int index = cvmx_helper_get_interface_index_num(ipd_port);
 
@@ -1136,7 +1136,7 @@ EXPORT_SYMBOL_GPL(cvmx_helper_link_get);
  *
  * Returns Zero on success, negative on failure
  */
-int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
+int cvmx_helper_link_set(int ipd_port, union cvmx_helper_link_info link_info)
 {
        int result = -1;
        int interface = cvmx_helper_get_interface_num(ipd_port);
index 6bd1e97..6501a84 100644 (file)
@@ -2199,6 +2199,9 @@ static int octeon_irq_cib_map(struct irq_domain *d,
        }
 
        cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+       if (!cd)
+               return -ENOMEM;
+
        cd->host_data = host_data;
        cd->bit = hw;
 
index 965c777..ead5ae4 100644 (file)
@@ -45,18 +45,20 @@ asmlinkage void plat_irq_dispatch(void)
                spurious_interrupt();
 }
 
-static struct irqaction cascade = {
-       .handler        = no_action,
-       .name           = "cascade",
-       .flags          = IRQF_NO_THREAD,
-};
-
 void __init arch_init_irq(void)
 {
        mips_cpu_irq_init();
        gt641xx_irq_init();
        init_i8259_irqs();
 
-       setup_irq(GT641XX_CASCADE_IRQ, &cascade);
-       setup_irq(I8259_CASCADE_IRQ, &cascade);
+       if (request_irq(GT641XX_CASCADE_IRQ, no_action, IRQF_NO_THREAD,
+                       "cascade", NULL)) {
+               pr_err("Failed to request irq %d (cascade)\n",
+                      GT641XX_CASCADE_IRQ);
+       }
+       if (request_irq(I8259_CASCADE_IRQ, no_action, IRQF_NO_THREAD,
+                       "cascade", NULL)) {
+               pr_err("Failed to request irq %d (cascade)\n",
+                      I8259_CASCADE_IRQ);
+       }
 }
index cef2754..cf9c632 100644 (file)
@@ -21,7 +21,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_BSD_DISKLABEL=y
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index c35add2..7143441 100644 (file)
@@ -22,7 +22,6 @@ CONFIG_HZ_100=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
index 4ffc59c..3d14d67 100644 (file)
@@ -23,7 +23,6 @@ CONFIG_PCI=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index 54e2f9a..861f680 100644 (file)
@@ -21,8 +21,6 @@ CONFIG_PCI=y
 CONFIG_PCCARD=y
 CONFIG_PCMCIA_BCM63XX=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_INET=y
index f669a40..032bb51 100644 (file)
@@ -12,8 +12,6 @@ CONFIG_NR_CPUS=4
 # CONFIG_SECCOMP is not set
 CONFIG_MIPS_O32_FP64_SUPPORT=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=y
index a0b7758..625bd2d 100644 (file)
@@ -21,8 +21,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
 CONFIG_BMIPS_CPUFREQ=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_PACKET_DIAG=y
index be41df2..0db0088 100644 (file)
@@ -1,4 +1,5 @@
 # CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_MODULES=y
 CONFIG_KERNEL_XZ=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
@@ -88,12 +89,14 @@ CONFIG_I2C_JZ4780=y
 CONFIG_SPI=y
 CONFIG_SPI_GPIO=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_KEYBOARD_GPIO=m
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_JZ4740_WDT=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR_DEBUG=y
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_ACT8865=y
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID is not set
 # CONFIG_USB_SUPPORT is not set
@@ -166,3 +169,21 @@ CONFIG_STACKTRACE=y
 # CONFIG_FTRACE is not set
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="earlycon console=ttyS4,115200 clk_ignore_unused"
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_MTD=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=y
+CONFIG_LEDS_TRIGGER_CAMERA=m
+CONFIG_LIRC=y
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_RC_DEVICES=y
+CONFIG_IR_GPIO_CIR=m
+CONFIG_IR_GPIO_TX=m
index bc9b6ae..e6f3e8e 100644 (file)
@@ -28,7 +28,6 @@ CONFIG_PCMCIA_ALCHEMY_DEVBOARD=y
 CONFIG_FIRMWARE_MEMMAP=y
 CONFIG_BLK_DEV_BSGLIB=y
 CONFIG_PARTITION_ADVANCED=y
-CONFIG_DEFAULT_NOOP=y
 CONFIG_CMA=y
 CONFIG_CMA_DEBUG=y
 CONFIG_NET=y
index 1ed0d3e..fc3580e 100644 (file)
@@ -19,7 +19,6 @@ CONFIG_MTD_NAND_ECC_SW_HAMMING=y
 CONFIG_MTD_NAND_ECC_SW_BCH=y
 CONFIG_MTD_RAW_NAND=y
 CONFIG_MTD_NAND_GPIO=y
-CONFIG_MTD_NAND_IDS=y
 
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_BLOCK=y
index 328d4df..92085df 100644 (file)
@@ -1,15 +1,17 @@
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_RELAY=y
 CONFIG_EXPERT=y
 CONFIG_SLAB=y
 CONFIG_MACH_JAZZ=y
 CONFIG_OLIVETTI_M700=y
+CONFIG_MIPS_MAGNUM_4000=y
+CONFIG_CPU_LITTLE_ENDIAN=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
@@ -18,168 +20,17 @@ CONFIG_BINFMT_MISC=m
 CONFIG_NET=y
 CONFIG_PACKET=m
 CONFIG_UNIX=y
-CONFIG_NET_KEY=m
-CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_NET_IPIP=m
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_TCP_MD5SIG=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
 CONFIG_INET6_AH=m
 CONFIG_INET6_ESP=m
 CONFIG_INET6_IPCOMP=m
-CONFIG_IPV6_TUNNEL=m
-CONFIG_NETWORK_SECMARK=y
-CONFIG_NETFILTER=y
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_SECMARK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SANE=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_SECMARK=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DCCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_AH=m
-CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_FRAG=m
-CONFIG_IP6_NF_MATCH_OPTS=m
-CONFIG_IP6_NF_MATCH_HL=m
-CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-CONFIG_IP6_NF_MATCH_MH=m
-CONFIG_IP6_NF_MATCH_RT=m
-CONFIG_IP6_NF_TARGET_HL=m
-CONFIG_IP6_NF_FILTER=m
-CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_RAW=m
-CONFIG_DECNET_NF_GRABULATOR=m
-CONFIG_BRIDGE_NF_EBTABLES=m
-CONFIG_BRIDGE_EBT_BROUTE=m
-CONFIG_BRIDGE_EBT_T_FILTER=m
-CONFIG_BRIDGE_EBT_T_NAT=m
-CONFIG_BRIDGE_EBT_802_3=m
-CONFIG_BRIDGE_EBT_AMONG=m
-CONFIG_BRIDGE_EBT_ARP=m
-CONFIG_BRIDGE_EBT_IP=m
-CONFIG_BRIDGE_EBT_LIMIT=m
-CONFIG_BRIDGE_EBT_MARK=m
-CONFIG_BRIDGE_EBT_PKTTYPE=m
-CONFIG_BRIDGE_EBT_STP=m
-CONFIG_BRIDGE_EBT_VLAN=m
-CONFIG_BRIDGE_EBT_ARPREPLY=m
-CONFIG_BRIDGE_EBT_DNAT=m
-CONFIG_BRIDGE_EBT_MARK_T=m
-CONFIG_BRIDGE_EBT_REDIRECT=m
-CONFIG_BRIDGE_EBT_SNAT=m
-CONFIG_BRIDGE_EBT_LOG=m
-CONFIG_BRIDGE=m
-CONFIG_DECNET=m
-CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_HTB=m
-CONFIG_NET_SCH_HFSC=m
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-CONFIG_NET_SCH_GRED=m
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_NETEM=m
-CONFIG_NET_CLS_BASIC=m
-CONFIG_NET_CLS_TCINDEX=m
-CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_FW=m
-CONFIG_NET_CLS_U32=m
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_RSVP6=m
-CONFIG_HAMRADIO=y
-CONFIG_AX25=m
-CONFIG_NETROM=m
-CONFIG_ROSE=m
-CONFIG_MKISS=m
-CONFIG_6PACK=m
-CONFIG_BPQETHER=m
-CONFIG_CONNECTOR=m
 CONFIG_PARPORT=m
 CONFIG_PARPORT_PC=m
 CONFIG_PARPORT_1284=y
+CONFIG_DEVTMPFS=y
 CONFIG_BLK_DEV_FD=m
-CONFIG_PARIDE=m
-CONFIG_PARIDE_PD=m
-CONFIG_PARIDE_PCD=m
-CONFIG_PARIDE_PF=m
-CONFIG_PARIDE_PT=m
-CONFIG_PARIDE_PG=m
-CONFIG_PARIDE_ATEN=m
-CONFIG_PARIDE_BPCK=m
-CONFIG_PARIDE_BPCK6=m
-CONFIG_PARIDE_COMM=m
-CONFIG_PARIDE_DSTR=m
-CONFIG_PARIDE_FIT2=m
-CONFIG_PARIDE_FIT3=m
-CONFIG_PARIDE_EPAT=m
-CONFIG_PARIDE_EPIA=m
-CONFIG_PARIDE_FRIQ=m
-CONFIG_PARIDE_FRPW=m
-CONFIG_PARIDE_KBIC=m
-CONFIG_PARIDE_KTTI=m
-CONFIG_PARIDE_ON20=m
-CONFIG_PARIDE_ON26=m
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
@@ -194,26 +45,12 @@ CONFIG_BLK_DEV_SR=m
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_SCSI_FC_ATTRS=y
-CONFIG_SCSI_SAS_ATTRS=m
 CONFIG_ISCSI_TCP=m
 CONFIG_SCSI_PPA=m
 CONFIG_SCSI_IMM=m
 CONFIG_JAZZ_ESP=y
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
-CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-CONFIG_MD_RAID10=m
-CONFIG_MD_RAID456=m
-CONFIG_MD_MULTIPATH=m
-CONFIG_MD_FAULTY=m
-CONFIG_BLK_DEV_DM=m
-CONFIG_DM_SNAPSHOT=m
-CONFIG_DM_MIRROR=m
-CONFIG_DM_ZERO=m
-CONFIG_DM_MULTIPATH=m
+CONFIG_ATA=y
+CONFIG_PATA_LEGACY=y
 CONFIG_NETDEVICES=y
 CONFIG_BONDING=m
 CONFIG_DUMMY=m
@@ -221,28 +58,18 @@ CONFIG_EQUALIZER=m
 CONFIG_TUN=m
 CONFIG_MIPS_JAZZ_SONIC=y
 CONFIG_NE2000=m
-CONFIG_PHYLIB=m
-CONFIG_CICADA_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_MARVELL_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_SMSC_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_PLIP=m
-CONFIG_INPUT_FF_MEMLESS=m
 CONFIG_SERIO_PARKBD=m
 CONFIG_SERIO_RAW=m
 CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_EXTENDED=y
 CONFIG_SERIAL_8250_SHARE_IRQ=y
 CONFIG_SERIAL_8250_DETECT_IRQ=y
 CONFIG_SERIAL_8250_RSA=y
-CONFIG_PRINTER=m
-CONFIG_PPDEV=m
-# CONFIG_HW_RANDOM is not set
-CONFIG_W1=m
+CONFIG_FB=y
+CONFIG_FB_G364=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
 # CONFIG_HWMON is not set
 CONFIG_EXT2_FS=m
 CONFIG_EXT3_FS=y
@@ -263,78 +90,8 @@ CONFIG_VFAT_FS=m
 CONFIG_NTFS_FS=m
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
-CONFIG_ADFS_FS=m
-CONFIG_AFFS_FS=m
-CONFIG_HFS_FS=m
-CONFIG_BEFS_FS=m
-CONFIG_BFS_FS=m
-CONFIG_EFS_FS=m
-CONFIG_CRAMFS=m
-CONFIG_VXFS_FS=m
-CONFIG_MINIX_FS=m
-CONFIG_HPFS_FS=m
-CONFIG_QNX4FS_FS=m
-CONFIG_ROMFS_FS=m
-CONFIG_SYSV_FS=m
 CONFIG_UFS_FS=m
 CONFIG_NFS_FS=m
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
 CONFIG_CIFS=m
-CONFIG_CODA_FS=m
-CONFIG_AFS_FS=m
-CONFIG_NLS_CODEPAGE_437=m
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
-CONFIG_NLS_UTF8=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAMELLIA=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRC_CCITT=m
index c66ca37..00cf461 100644 (file)
@@ -16,8 +16,6 @@ CONFIG_HZ_1000=y
 # CONFIG_SECCOMP is not set
 CONFIG_PCI=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index f9f9342..8254d7d 100644 (file)
@@ -26,7 +26,7 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_BLK_DEV_INTEGRITY=y
-CONFIG_IOSCHED_DEADLINE=m
+CONFIG_MQ_IOSCHED_DEADLINE=m
 CONFIG_BINFMT_MISC=m
 CONFIG_NET=y
 CONFIG_PACKET=y
index 360c6b2..51675f5 100644 (file)
@@ -38,8 +38,9 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
-CONFIG_IOSCHED_DEADLINE=m
-CONFIG_CFQ_GROUP_IOSCHED=y
+CONFIG_MQ_IOSCHED_DEADLINE=m
+CONFIG_IOSCHED_BFQ=y
+CONFIG_BFQ_GROUP_IOSCHED=y
 CONFIG_BINFMT_MISC=m
 CONFIG_KSM=y
 CONFIG_NET=y
index 0fdc03f..6ad1a23 100644 (file)
@@ -14,8 +14,6 @@ CONFIG_PCI=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_UNIX=y
 CONFIG_XFRM_USER=y
index 738ba3b..d06db6b 100644 (file)
@@ -14,8 +14,6 @@ CONFIG_HZ_128=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index 5b94718..252d472 100644 (file)
@@ -23,7 +23,6 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_MAC_PARTITION=y
 CONFIG_BSD_DISKLABEL=y
-# CONFIG_IOSCHED_CFQ is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index 110948b..8c2ead5 100644 (file)
@@ -21,7 +21,6 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_COREDUMP is not set
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
index 49b5ea6..9abbc0d 100644 (file)
@@ -23,7 +23,6 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_PARTITION_ADVANCED=y
-# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_COREDUMP is not set
 # CONFIG_COMPACTION is not set
 CONFIG_NET=y
index 61a0bf1..d4e868b 100644 (file)
@@ -103,28 +103,8 @@ int_ptr asic_mask_nr_tbl[DEC_MAX_ASIC_INTS][2] = {
 int cpu_fpu_mask = DEC_CPU_IRQ_MASK(DEC_CPU_INR_FPU);
 int *fpu_kstat_irq;
 
-static struct irqaction ioirq = {
-       .handler = no_action,
-       .name = "cascade",
-       .flags = IRQF_NO_THREAD,
-};
-static struct irqaction fpuirq = {
-       .handler = no_action,
-       .name = "fpu",
-       .flags = IRQF_NO_THREAD,
-};
-
-static struct irqaction busirq = {
-       .name = "bus error",
-       .flags = IRQF_NO_THREAD,
-};
-
-static struct irqaction haltirq = {
-       .handler = dec_intr_halt,
-       .name = "halt",
-       .flags = IRQF_NO_THREAD,
-};
-
+static irq_handler_t busirq_handler;
+static unsigned int busirq_flags = IRQF_NO_THREAD;
 
 /*
  * Bus error (DBE/IBE exceptions and bus interrupts) handling setup.
@@ -134,21 +114,21 @@ static void __init dec_be_init(void)
        switch (mips_machtype) {
        case MACH_DS23100:      /* DS2100/DS3100 Pmin/Pmax */
                board_be_handler = dec_kn01_be_handler;
-               busirq.handler = dec_kn01_be_interrupt;
-               busirq.flags |= IRQF_SHARED;
+               busirq_handler = dec_kn01_be_interrupt;
+               busirq_flags |= IRQF_SHARED;
                dec_kn01_be_init();
                break;
        case MACH_DS5000_1XX:   /* DS5000/1xx 3min */
        case MACH_DS5000_XX:    /* DS5000/xx Maxine */
                board_be_handler = dec_kn02xa_be_handler;
-               busirq.handler = dec_kn02xa_be_interrupt;
+               busirq_handler = dec_kn02xa_be_interrupt;
                dec_kn02xa_be_init();
                break;
        case MACH_DS5000_200:   /* DS5000/200 3max */
        case MACH_DS5000_2X0:   /* DS5000/240 3max+ */
        case MACH_DS5900:       /* DS5900 bigmax */
                board_be_handler = dec_ecc_be_handler;
-               busirq.handler = dec_ecc_be_interrupt;
+               busirq_handler = dec_ecc_be_interrupt;
                dec_ecc_be_init();
                break;
        }
@@ -764,20 +744,29 @@ void __init arch_init_irq(void)
                int irq_fpu;
 
                irq_fpu = dec_interrupt[DEC_IRQ_FPU];
-               setup_irq(irq_fpu, &fpuirq);
+               if (request_irq(irq_fpu, no_action, IRQF_NO_THREAD, "fpu",
+                               NULL))
+                       pr_err("Failed to register fpu interrupt\n");
                desc_fpu = irq_to_desc(irq_fpu);
                fpu_kstat_irq = this_cpu_ptr(desc_fpu->kstat_irqs);
        }
-       if (dec_interrupt[DEC_IRQ_CASCADE] >= 0)
-               setup_irq(dec_interrupt[DEC_IRQ_CASCADE], &ioirq);
-
+       if (dec_interrupt[DEC_IRQ_CASCADE] >= 0) {
+               if (request_irq(dec_interrupt[DEC_IRQ_CASCADE], no_action,
+                               IRQF_NO_THREAD, "cascade", NULL))
+                       pr_err("Failed to register cascade interrupt\n");
+       }
        /* Register the bus error interrupt. */
-       if (dec_interrupt[DEC_IRQ_BUS] >= 0 && busirq.handler)
-               setup_irq(dec_interrupt[DEC_IRQ_BUS], &busirq);
-
+       if (dec_interrupt[DEC_IRQ_BUS] >= 0 && busirq_handler) {
+               if (request_irq(dec_interrupt[DEC_IRQ_BUS], busirq_handler,
+                               busirq_flags, "bus error", busirq_handler))
+                       pr_err("Failed to register bus error interrupt\n");
+       }
        /* Register the HALT interrupt. */
-       if (dec_interrupt[DEC_IRQ_HALT] >= 0)
-               setup_irq(dec_interrupt[DEC_IRQ_HALT], &haltirq);
+       if (dec_interrupt[DEC_IRQ_HALT] >= 0) {
+               if (request_irq(dec_interrupt[DEC_IRQ_HALT], dec_intr_halt,
+                               IRQF_NO_THREAD, "halt", NULL))
+                       pr_err("Failed to register halt interrupt\n");
+       }
 }
 
 asmlinkage unsigned int dec_irq_dispatch(unsigned int irq)
index 09427a4..4aebf55 100644 (file)
@@ -153,14 +153,6 @@ void emma2rh_gpio_irq_init(void)
                                              handle_edge_irq, "edge");
 }
 
-static struct irqaction irq_cascade = {
-          .handler = no_action,
-          .flags = IRQF_NO_THREAD,
-          .name = "cascade",
-          .dev_id = NULL,
-          .next = NULL,
-};
-
 /*
  * the first level int-handler will jump here if it is a emma2rh irq
  */
@@ -236,6 +228,7 @@ void emma2rh_irq_dispatch(void)
 void __init arch_init_irq(void)
 {
        u32 reg;
+       int irq;
 
        /* by default, interrupts are disabled. */
        emma2rh_out32(EMMA2RH_BHIF_INT_EN_0, 0);
@@ -272,9 +265,15 @@ void __init arch_init_irq(void)
        mips_cpu_irq_init();
 
        /* setup cascade interrupts */
-       setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade);
-       setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_GPIO_CASCADE, &irq_cascade);
-       setup_irq(MIPS_CPU_IRQ_BASE + 2, &irq_cascade);
+       irq = EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE;
+       if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", irq);
+       irq = EMMA2RH_IRQ_BASE + EMMA2RH_GPIO_CASCADE;
+       if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", irq);
+       irq = MIPS_CPU_IRQ_BASE + 2;
+       if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", irq);
 }
 
 asmlinkage void plat_irq_dispatch(void)
index 6ecda64..f24cbb4 100644 (file)
@@ -16,6 +16,7 @@ int fw_argc;
 int *_fw_argv;
 int *_fw_envp;
 
+#ifndef CONFIG_HAVE_PLAT_FW_INIT_CMDLINE
 void __init fw_init_cmdline(void)
 {
        int i;
@@ -41,6 +42,7 @@ void __init fw_init_cmdline(void)
                        strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
        }
 }
+#endif
 
 char * __init fw_getcmdline(void)
 {
index 1de215b..805d013 100644 (file)
@@ -5,10 +5,10 @@
  */
 
 #include <linux/clk.h>
-#include <linux/clk-provider.h>
 #include <linux/clocksource.h>
 #include <linux/init.h>
 #include <linux/irqchip.h>
+#include <linux/of_clk.h>
 #include <linux/of_fdt.h>
 
 #include <asm/bootinfo.h>
index cab9ae9..2f1ebbe 100644 (file)
@@ -3,23 +3,9 @@
  * Copyright (C) 2015 Imagination Technologies
  * Author: Alex Smith <alex.smith@imgtec.com>
  */
-
 #ifndef __ASM_CLOCKSOURCE_H
 #define __ASM_CLOCKSOURCE_H
 
-#include <linux/types.h>
-
-/* VDSO clocksources. */
-#define VDSO_CLOCK_NONE                0       /* No suitable clocksource. */
-#define VDSO_CLOCK_R4K         1       /* Use the coprocessor 0 count. */
-#define VDSO_CLOCK_GIC         2       /* Use the GIC. */
-
-/**
- * struct arch_clocksource_data - Architecture-specific clocksource information.
- * @vdso_clock_mode: Method the VDSO should use to access the clocksource.
- */
-struct arch_clocksource_data {
-       u8 vdso_clock_mode;
-};
+#include <asm/vdso/clocksource.h>
 
 #endif /* __ASM_CLOCKSOURCE_H */
diff --git a/arch/mips/include/asm/dmi.h b/arch/mips/include/asm/dmi.h
new file mode 100644 (file)
index 0000000..27415a2
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_DMI_H
+#define _ASM_DMI_H
+
+#include <linux/io.h>
+#include <linux/memblock.h>
+
+#define dmi_early_remap(x, l)          ioremap_cache(x, l)
+#define dmi_early_unmap(x, l)          iounmap(x)
+#define dmi_remap(x, l)                        ioremap_cache(x, l)
+#define dmi_unmap(x)                   iounmap(x)
+
+/* MIPS initialize DMI scan before SLAB is ready, so we use memblock here */
+#define dmi_alloc(l)                   memblock_alloc_low(l, PAGE_SIZE)
+
+#if defined(CONFIG_MACH_LOONGSON64)
+#define SMBIOS_ENTRY_POINT_SCAN_START  0xFFFE000
+#endif
+
+#endif /* _ASM_DMI_H */
index f8f44b1..5aa29ce 100644 (file)
@@ -445,6 +445,9 @@ extern unsigned int elf_hwcap;
 #define ELF_PLATFORM  __elf_platform
 extern const char *__elf_platform;
 
+#define ELF_BASE_PLATFORM  __elf_base_platform
+extern const char *__elf_base_platform;
+
 /*
  * See comments in asm-alpha/elf.h, this is the same thing
  * on the MIPS.
index 1102207..2bf8f60 100644 (file)
@@ -89,7 +89,8 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
        int oldval = 0, ret;
 
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -116,8 +117,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index 97a5e41..a54b964 100644 (file)
@@ -36,6 +36,7 @@ extern raw_spinlock_t i8259A_lock;
 extern void make_8259A_irq(unsigned int irq);
 
 extern void init_i8259_irqs(void);
+extern struct irq_domain *__init_i8259_irqs(struct device_node *node);
 
 /**
  * i8159_set_poll() - Override the i8259 polling function
index 7ad10e3..46bb730 100644 (file)
@@ -11,6 +11,6 @@
 
 #define NR_IRQS 256
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* __ASM_AR7_IRQ_H */
index 2df1abf..882534b 100644 (file)
@@ -27,6 +27,6 @@
 #define ATH79_IP3_IRQ_COUNT     3
 #define ATH79_IP3_IRQ(_x)       (ATH79_IP3_IRQ_BASE + (_x))
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* __ASM_MACH_ATH79_IRQ_H */
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_ide.h b/arch/mips/include/asm/mach-au1x00/au1xxx_ide.h
deleted file mode 100644 (file)
index bb91b89..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * include/asm-mips/mach-au1x00/au1xxx_ide.h  version 01.30.00  Aug. 02 2005
- *
- * BRIEF MODULE DESCRIPTION
- * AMD Alchemy Au1xxx IDE interface routines over the Static Bus
- *
- * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE
- *      Interface and Linux Device Driver" Application Note.
- */
-
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-#define DMA_WAIT_TIMEOUT       100
-#define NUM_DESCRIPTORS                PRD_ENTRIES
-#else /* CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA */
-#define NUM_DESCRIPTORS                2
-#endif
-
-#ifndef AU1XXX_ATA_RQSIZE
-#define AU1XXX_ATA_RQSIZE      128
-#endif
-
-/* Disable Burstable-Support for DBDMA */
-#ifndef CONFIG_BLK_DEV_IDE_AU1XXX_BURSTABLE_ON
-#define CONFIG_BLK_DEV_IDE_AU1XXX_BURSTABLE_ON 0
-#endif
-
-typedef struct {
-       u32                     tx_dev_id, rx_dev_id, target_dev_id;
-       u32                     tx_chan, rx_chan;
-       void                    *tx_desc_head, *rx_desc_head;
-       ide_hwif_t              *hwif;
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-       ide_drive_t             *drive;
-       struct dbdma_cmd        *dma_table_cpu;
-       dma_addr_t              dma_table_dma;
-#endif
-       int                     irq;
-       u32                     regbase;
-       int                     ddma_id;
-} _auide_hwif;
-
-/******************************************************************************/
-/* PIO Mode timing calculation :                                             */
-/*                                                                           */
-/* Static Bus Spec   ATA Spec                                                */
-/*     Tcsoe      =    t1                                                    */
-/*     Toecs      =    t9                                                    */
-/*     Twcs       =    t9                                                    */
-/*     Tcsh       =    t2i | t2                                              */
-/*     Tcsoff     =    t2i | t2                                              */
-/*     Twp        =    t2                                                    */
-/*     Tcsw       =    t1                                                    */
-/*     Tpm        =    0                                                     */
-/*     Ta         =    t1+t2                                                 */
-/******************************************************************************/
-
-#define TCSOE_MASK             (0x07 << 29)
-#define TOECS_MASK             (0x07 << 26)
-#define TWCS_MASK              (0x07 << 28)
-#define TCSH_MASK              (0x0F << 24)
-#define TCSOFF_MASK            (0x07 << 20)
-#define TWP_MASK               (0x3F << 14)
-#define TCSW_MASK              (0x0F << 10)
-#define TPM_MASK               (0x0F << 6)
-#define TA_MASK                        (0x3F << 0)
-#define TS_MASK                        (1 << 8)
-
-/* Timing parameters PIO mode 0 */
-#define SBC_IDE_PIO0_TCSOE     (0x04 << 29)
-#define SBC_IDE_PIO0_TOECS     (0x01 << 26)
-#define SBC_IDE_PIO0_TWCS      (0x02 << 28)
-#define SBC_IDE_PIO0_TCSH      (0x08 << 24)
-#define SBC_IDE_PIO0_TCSOFF    (0x07 << 20)
-#define SBC_IDE_PIO0_TWP       (0x10 << 14)
-#define SBC_IDE_PIO0_TCSW      (0x04 << 10)
-#define SBC_IDE_PIO0_TPM       (0x00 << 6)
-#define SBC_IDE_PIO0_TA                (0x15 << 0)
-/* Timing parameters PIO mode 1 */
-#define SBC_IDE_PIO1_TCSOE     (0x03 << 29)
-#define SBC_IDE_PIO1_TOECS     (0x01 << 26)
-#define SBC_IDE_PIO1_TWCS      (0x01 << 28)
-#define SBC_IDE_PIO1_TCSH      (0x06 << 24)
-#define SBC_IDE_PIO1_TCSOFF    (0x06 << 20)
-#define SBC_IDE_PIO1_TWP       (0x08 << 14)
-#define SBC_IDE_PIO1_TCSW      (0x03 << 10)
-#define SBC_IDE_PIO1_TPM       (0x00 << 6)
-#define SBC_IDE_PIO1_TA                (0x0B << 0)
-/* Timing parameters PIO mode 2 */
-#define SBC_IDE_PIO2_TCSOE     (0x05 << 29)
-#define SBC_IDE_PIO2_TOECS     (0x01 << 26)
-#define SBC_IDE_PIO2_TWCS      (0x01 << 28)
-#define SBC_IDE_PIO2_TCSH      (0x07 << 24)
-#define SBC_IDE_PIO2_TCSOFF    (0x07 << 20)
-#define SBC_IDE_PIO2_TWP       (0x1F << 14)
-#define SBC_IDE_PIO2_TCSW      (0x05 << 10)
-#define SBC_IDE_PIO2_TPM       (0x00 << 6)
-#define SBC_IDE_PIO2_TA                (0x22 << 0)
-/* Timing parameters PIO mode 3 */
-#define SBC_IDE_PIO3_TCSOE     (0x05 << 29)
-#define SBC_IDE_PIO3_TOECS     (0x01 << 26)
-#define SBC_IDE_PIO3_TWCS      (0x01 << 28)
-#define SBC_IDE_PIO3_TCSH      (0x0D << 24)
-#define SBC_IDE_PIO3_TCSOFF    (0x0D << 20)
-#define SBC_IDE_PIO3_TWP       (0x15 << 14)
-#define SBC_IDE_PIO3_TCSW      (0x05 << 10)
-#define SBC_IDE_PIO3_TPM       (0x00 << 6)
-#define SBC_IDE_PIO3_TA                (0x1A << 0)
-/* Timing parameters PIO mode 4 */
-#define SBC_IDE_PIO4_TCSOE     (0x04 << 29)
-#define SBC_IDE_PIO4_TOECS     (0x01 << 26)
-#define SBC_IDE_PIO4_TWCS      (0x01 << 28)
-#define SBC_IDE_PIO4_TCSH      (0x04 << 24)
-#define SBC_IDE_PIO4_TCSOFF    (0x04 << 20)
-#define SBC_IDE_PIO4_TWP       (0x0D << 14)
-#define SBC_IDE_PIO4_TCSW      (0x03 << 10)
-#define SBC_IDE_PIO4_TPM       (0x00 << 6)
-#define SBC_IDE_PIO4_TA                (0x12 << 0)
-/* Timing parameters MDMA mode 0 */
-#define SBC_IDE_MDMA0_TCSOE    (0x03 << 29)
-#define SBC_IDE_MDMA0_TOECS    (0x01 << 26)
-#define SBC_IDE_MDMA0_TWCS     (0x01 << 28)
-#define SBC_IDE_MDMA0_TCSH     (0x07 << 24)
-#define SBC_IDE_MDMA0_TCSOFF   (0x07 << 20)
-#define SBC_IDE_MDMA0_TWP      (0x0C << 14)
-#define SBC_IDE_MDMA0_TCSW     (0x03 << 10)
-#define SBC_IDE_MDMA0_TPM      (0x00 << 6)
-#define SBC_IDE_MDMA0_TA       (0x0F << 0)
-/* Timing parameters MDMA mode 1 */
-#define SBC_IDE_MDMA1_TCSOE    (0x05 << 29)
-#define SBC_IDE_MDMA1_TOECS    (0x01 << 26)
-#define SBC_IDE_MDMA1_TWCS     (0x01 << 28)
-#define SBC_IDE_MDMA1_TCSH     (0x05 << 24)
-#define SBC_IDE_MDMA1_TCSOFF   (0x05 << 20)
-#define SBC_IDE_MDMA1_TWP      (0x0F << 14)
-#define SBC_IDE_MDMA1_TCSW     (0x05 << 10)
-#define SBC_IDE_MDMA1_TPM      (0x00 << 6)
-#define SBC_IDE_MDMA1_TA       (0x15 << 0)
-/* Timing parameters MDMA mode 2 */
-#define SBC_IDE_MDMA2_TCSOE    (0x04 << 29)
-#define SBC_IDE_MDMA2_TOECS    (0x01 << 26)
-#define SBC_IDE_MDMA2_TWCS     (0x01 << 28)
-#define SBC_IDE_MDMA2_TCSH     (0x04 << 24)
-#define SBC_IDE_MDMA2_TCSOFF   (0x04 << 20)
-#define SBC_IDE_MDMA2_TWP      (0x0D << 14)
-#define SBC_IDE_MDMA2_TCSW     (0x04 << 10)
-#define SBC_IDE_MDMA2_TPM      (0x00 << 6)
-#define SBC_IDE_MDMA2_TA       (0x12 << 0)
-
-#define SBC_IDE_TIMING(mode) \
-       (SBC_IDE_##mode##_TWCS | \
-        SBC_IDE_##mode##_TCSH | \
-        SBC_IDE_##mode##_TCSOFF | \
-        SBC_IDE_##mode##_TWP | \
-        SBC_IDE_##mode##_TCSW | \
-        SBC_IDE_##mode##_TPM | \
-        SBC_IDE_##mode##_TA)
index 2f7155d..d327367 100644 (file)
@@ -10,6 +10,6 @@
 
 #define NR_IRQS 256
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* __ASM_MACH_EMMA2RH_IRQ_H */
index fd91c58..f45d799 100644 (file)
@@ -12,7 +12,7 @@
 
 #define NR_IRQS 256
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #define IP27_HUB_PEND0_IRQ     (MIPS_CPU_IRQ_BASE + 2)
 #define IP27_HUB_PEND1_IRQ     (MIPS_CPU_IRQ_BASE + 3)
index e5c3dd9..27ba899 100644 (file)
@@ -76,7 +76,7 @@ extern void __init ip30_install_ipi(void);
  */
 #define IP30_POWER_IRQ         HEART_L2_INT_POWER_BTN
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #define IP30_HEART_L0_IRQ      (MIPS_CPU_IRQ_BASE + 2)
 #define IP30_HEART_L1_IRQ      (MIPS_CPU_IRQ_BASE + 3)
index 91d2bc0..c14312f 100644 (file)
@@ -11,6 +11,6 @@
 
 #define NR_IRQS 328
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif
index 76ebbf6..2980e77 100644 (file)
@@ -11,6 +11,6 @@
 
 #define NR_IRQS 256
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif
index d79cbe0..e899492 100644 (file)
@@ -9,6 +9,6 @@
 
 #define NR_IRQS                        24
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* _ASM_MACH_LASAT_IRQ_H */
index 8c286be..2ed483e 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef __ASM_MACH_LOONGSON64_BOOT_PARAM_H_
 #define __ASM_MACH_LOONGSON64_BOOT_PARAM_H_
 
+#include <linux/types.h>
+
 #define SYSTEM_RAM_LOW         1
 #define SYSTEM_RAM_HIGH                2
 #define SYSTEM_RAM_RESERVED    3
diff --git a/arch/mips/include/asm/mach-loongson64/builtin_dtbs.h b/arch/mips/include/asm/mach-loongson64/builtin_dtbs.h
new file mode 100644 (file)
index 0000000..853c6d8
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ * Built-in Generic dtbs for MACH_LOONGSON64
+ */
+
+#ifndef __ASM_MACH_LOONGSON64_BUILTIN_DTBS_H_
+#define __ASM_MACH_LOONGSON64_BUILTIN_DTBS_H_
+
+extern u32 __dtb_loongson3_4core_rs780e_begin[];
+extern u32 __dtb_loongson3_8core_rs780e_begin[];
+#endif
index 73a8991..d41dc4a 100644 (file)
@@ -7,34 +7,6 @@
 /* cpu core interrupt numbers */
 #define MIPS_CPU_IRQ_BASE 56
 
-#define LOONGSON_UART_IRQ   (MIPS_CPU_IRQ_BASE + 2) /* UART */
-#define LOONGSON_BRIDGE_IRQ (MIPS_CPU_IRQ_BASE + 3) /* CASCADE */
-#define LOONGSON_TIMER_IRQ  (MIPS_CPU_IRQ_BASE + 7) /* CPU Timer */
+#include <asm/mach-generic/irq.h>
 
-#define LOONGSON_HT1_CFG_BASE          loongson_sysconf.ht_control_base
-#define LOONGSON_HT1_INT_VECTOR_BASE   (LOONGSON_HT1_CFG_BASE + 0x80)
-#define LOONGSON_HT1_INT_EN_BASE       (LOONGSON_HT1_CFG_BASE + 0xa0)
-#define LOONGSON_HT1_INT_VECTOR(n)     \
-               LOONGSON3_REG32(LOONGSON_HT1_INT_VECTOR_BASE, 4 * (n))
-#define LOONGSON_HT1_INTN_EN(n)                \
-               LOONGSON3_REG32(LOONGSON_HT1_INT_EN_BASE, 4 * (n))
-
-#define LOONGSON_INT_ROUTER_OFFSET     0x1400
-#define LOONGSON_INT_ROUTER_INTEN      \
-         LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x24)
-#define LOONGSON_INT_ROUTER_INTENSET   \
-         LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x28)
-#define LOONGSON_INT_ROUTER_INTENCLR   \
-         LOONGSON3_REG32(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + 0x2c)
-#define LOONGSON_INT_ROUTER_ENTRY(n)   \
-         LOONGSON3_REG8(LOONGSON3_REG_BASE, LOONGSON_INT_ROUTER_OFFSET + n)
-#define LOONGSON_INT_ROUTER_LPC                LOONGSON_INT_ROUTER_ENTRY(0x0a)
-#define LOONGSON_INT_ROUTER_HT1(n)     LOONGSON_INT_ROUTER_ENTRY(n + 0x18)
-
-#define LOONGSON_INT_COREx_INTy(x, y)  (1<<(x) | 1<<(y+4))     /* route to int y of core x */
-
-extern void fixup_irqs(void);
-extern void loongson3_ipi_interrupt(struct pt_regs *regs);
-
-#include_next <irq.h>
 #endif /* __ASM_MACH_LOONGSON64_IRQ_H_ */
index a8fce11..fde1b75 100644 (file)
@@ -25,6 +25,7 @@ extern const struct plat_smp_ops loongson3_smp_ops;
 /* loongson-specific command line, env and memory initialization */
 extern void __init prom_init_memory(void);
 extern void __init prom_init_env(void);
+extern void *loongson_fdt_blob;
 
 /* irq operation functions */
 extern void mach_irq_dispatch(unsigned int pending);
index af9eeea..e1bd429 100644 (file)
@@ -5,6 +5,6 @@
 
 #define NR_IRQS 256
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* __ASM_MACH_MIPS_IRQ_H */
index d239694..ddaf999 100644 (file)
@@ -9,6 +9,6 @@
 #define NR_IRQS        256
 #define MIPS_CPU_IRQ_BASE 0
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* __ASM_MACH_PIC32_IRQ_H */
index 93bc380..74ac016 100644 (file)
@@ -10,6 +10,6 @@
 
 #define NR_IRQS 256
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* __ASM_MACH_PISTACHIO_IRQ_H */
index 86473e3..2262243 100644 (file)
@@ -5,6 +5,6 @@
 #define GIC_NUM_INTRS  64
 #define NR_IRQS 256
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif
index 145bce0..a074f4f 100644 (file)
@@ -16,6 +16,6 @@
 #define mc146818_decode_year(year) ((year) + 1980)
 #endif
 
-#include_next <mc146818rtc.h>
+#include <asm/mach-generic/mc146818rtc.h>
 
 #endif /* __ASM_MACH_RM_MC146818RTC_H */
index 3d63afa..4281b2b 100644 (file)
@@ -4,6 +4,6 @@
 
 #include <asm/vr41xx/irq.h> /* for MIPS_CPU_IRQ_BASE */
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* __ASM_MACH_VR41XX_IRQ_H */
index b8e93fa..15ad29e 100644 (file)
@@ -9,6 +9,6 @@
 
 #define NR_IRQS 32
 
-#include_next <irq.h>
+#include <asm/mach-generic/irq.h>
 
 #endif /* __MIPS_ASM_MACH_XILFPGA_IRQ_H__ */
index d7fdcf0..ce52aaf 100644 (file)
@@ -93,7 +93,7 @@ extern int cvmx_helper_board_get_mii_address(int ipd_port);
  * Returns The ports link status. If the link isn't fully resolved, this must
  *        return zero.
  */
-extern cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port);
+extern union cvmx_helper_link_info __cvmx_helper_board_link_get(int ipd_port);
 
 /**
  * This function is called by cvmx_helper_interface_probe() after it
index ac42b50..3e79a7f 100644 (file)
@@ -74,7 +74,7 @@ extern int __cvmx_helper_rgmii_enable(int interface);
  *
  * Returns Link state
  */
-extern cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port);
+extern union cvmx_helper_link_info __cvmx_helper_rgmii_link_get(int ipd_port);
 
 /**
  * Configure an IPD/PKO port for the specified link state. This
@@ -88,6 +88,6 @@ extern cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port);
  * Returns Zero on success, negative on failure
  */
 extern int __cvmx_helper_rgmii_link_set(int ipd_port,
-                                       cvmx_helper_link_info_t link_info);
+                                       union cvmx_helper_link_info link_info);
 
 #endif
index 3a54dea..8aac90f 100644 (file)
@@ -68,7 +68,7 @@ extern int __cvmx_helper_sgmii_enable(int interface);
  *
  * Returns Link state
  */
-extern cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port);
+extern union cvmx_helper_link_info __cvmx_helper_sgmii_link_get(int ipd_port);
 
 /**
  * Configure an IPD/PKO port for the specified link state. This
@@ -82,6 +82,6 @@ extern cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port);
  * Returns Zero on success, negative on failure
  */
 extern int __cvmx_helper_sgmii_link_set(int ipd_port,
-                                       cvmx_helper_link_info_t link_info);
+                                       union cvmx_helper_link_info link_info);
 
 #endif
index d5adf85..bc8cab9 100644 (file)
@@ -65,7 +65,7 @@ extern int __cvmx_helper_spi_enable(int interface);
  *
  * Returns Link state
  */
-extern cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port);
+extern union cvmx_helper_link_info __cvmx_helper_spi_link_get(int ipd_port);
 
 /**
  * Configure an IPD/PKO port for the specified link state. This
@@ -79,6 +79,6 @@ extern cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port);
  * Returns Zero on success, negative on failure
  */
 extern int __cvmx_helper_spi_link_set(int ipd_port,
-                                     cvmx_helper_link_info_t link_info);
+                                     union cvmx_helper_link_info link_info);
 
 #endif
index e9a97e7..97b27a0 100644 (file)
@@ -123,7 +123,7 @@ static inline int cvmx_helper_get_last_ipd_port(int interface)
  *
  * @work:   Work queue entry with packet to free
  */
-static inline void cvmx_helper_free_packet_data(cvmx_wqe_t *work)
+static inline void cvmx_helper_free_packet_data(struct cvmx_wqe *work)
 {
        uint64_t number_buffers;
        union cvmx_buf_ptr buffer_ptr;
index 51f45b4..c18da2e 100644 (file)
@@ -68,7 +68,7 @@ extern int __cvmx_helper_xaui_enable(int interface);
  *
  * Returns Link state
  */
-extern cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port);
+extern union cvmx_helper_link_info __cvmx_helper_xaui_link_get(int ipd_port);
 
 /**
  * Configure an IPD/PKO port for the specified link state. This
@@ -82,6 +82,6 @@ extern cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port);
  * Returns Zero on success, negative on failure
  */
 extern int __cvmx_helper_xaui_link_set(int ipd_port,
-                                      cvmx_helper_link_info_t link_info);
+                                      union cvmx_helper_link_info link_info);
 
 #endif
index ba0e76f..c6c99e2 100644 (file)
@@ -51,7 +51,7 @@ typedef enum {
        CVMX_HELPER_INTERFACE_MODE_LOOP,
 } cvmx_helper_interface_mode_t;
 
-typedef union {
+union cvmx_helper_link_info {
        uint64_t u64;
        struct {
                uint64_t reserved_20_63:44;
@@ -59,7 +59,7 @@ typedef union {
                uint64_t full_duplex:1;     /**< 1 if the link is full duplex */
                uint64_t speed:18;          /**< Speed of the link in Mbps */
        } s;
-} cvmx_helper_link_info_t;
+};
 
 #include <asm/octeon/cvmx-helper-errata.h>
 #include <asm/octeon/cvmx-helper-loop.h>
@@ -145,7 +145,7 @@ extern cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int
  *
  * Returns Link state
  */
-extern cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port);
+extern union cvmx_helper_link_info cvmx_helper_link_get(int ipd_port);
 
 /**
  * Configure an IPD/PKO port for the specified link state. This
@@ -159,7 +159,7 @@ extern cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port);
  * Returns Zero on success, negative on failure
  */
 extern int cvmx_helper_link_set(int ipd_port,
-                               cvmx_helper_link_info_t link_info);
+                               union cvmx_helper_link_info link_info);
 
 /**
  * This function probes an interface to determine the actual
index 20eb9c4..5b0b982 100644 (file)
@@ -169,7 +169,7 @@ typedef union {
 /**
  * Structure of the first packet output command word.
  */
-typedef union {
+union cvmx_pko_command_word0 {
        uint64_t u64;
        struct {
 #ifdef __BIG_ENDIAN_BITFIELD
@@ -261,7 +261,7 @@ typedef union {
                uint64_t size1:2;
 #endif
        } s;
-} cvmx_pko_command_word0_t;
+};
 
 /* CSR typedefs have been moved to cvmx-csr-*.h */
 
@@ -394,7 +394,7 @@ static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue,
                    CVMX_TAG_SW_BITS_INTERNAL << CVMX_TAG_SW_SHIFT |
                    CVMX_TAG_SUBGROUP_PKO << CVMX_TAG_SUBGROUP_SHIFT |
                    (CVMX_TAG_SUBGROUP_MASK & queue);
-               cvmx_pow_tag_sw_full((cvmx_wqe_t *) cvmx_phys_to_ptr(0x80), tag,
+               cvmx_pow_tag_sw_full((struct cvmx_wqe *) cvmx_phys_to_ptr(0x80), tag,
                                     CVMX_POW_TAG_TYPE_ATOMIC, 0);
        }
 }
@@ -419,7 +419,7 @@ static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue,
 static inline cvmx_pko_status_t cvmx_pko_send_packet_finish(
        uint64_t port,
        uint64_t queue,
-       cvmx_pko_command_word0_t pko_command,
+       union cvmx_pko_command_word0 pko_command,
        union cvmx_buf_ptr packet,
        cvmx_pko_lock_t use_locking)
 {
@@ -462,7 +462,7 @@ static inline cvmx_pko_status_t cvmx_pko_send_packet_finish(
 static inline cvmx_pko_status_t cvmx_pko_send_packet_finish3(
        uint64_t port,
        uint64_t queue,
-       cvmx_pko_command_word0_t pko_command,
+       union cvmx_pko_command_word0 pko_command,
        union cvmx_buf_ptr packet,
        uint64_t addr,
        cvmx_pko_lock_t use_locking)
index 410bb70..ba366f4 100644 (file)
@@ -1283,7 +1283,7 @@ static inline cvmx_pow_tag_req_t cvmx_pow_get_current_tag(void)
  *
  * Returns WQE pointer
  */
-static inline cvmx_wqe_t *cvmx_pow_get_current_wqp(void)
+static inline struct cvmx_wqe *cvmx_pow_get_current_wqp(void)
 {
        cvmx_pow_load_addr_t load_addr;
        cvmx_pow_tag_load_resp_t load_resp;
@@ -1296,7 +1296,7 @@ static inline cvmx_wqe_t *cvmx_pow_get_current_wqp(void)
        load_addr.sstatus.get_cur = 1;
        load_addr.sstatus.get_wqp = 1;
        load_resp.u64 = cvmx_read_csr(load_addr.u64);
-       return (cvmx_wqe_t *) cvmx_phys_to_ptr(load_resp.s_sstatus4.wqp);
+       return (struct cvmx_wqe *) cvmx_phys_to_ptr(load_resp.s_sstatus4.wqp);
 }
 
 #ifndef CVMX_MF_CHORD
@@ -1348,7 +1348,7 @@ static inline void cvmx_pow_tag_sw_wait(void)
  * Returns Returns the WQE pointer from POW. Returns NULL if no work
  * was available.
  */
-static inline cvmx_wqe_t *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t
+static inline struct cvmx_wqe *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t
                                                             wait)
 {
        cvmx_pow_load_addr_t ptr;
@@ -1368,7 +1368,7 @@ static inline cvmx_wqe_t *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t
        if (result.s_work.no_work)
                return NULL;
        else
-               return (cvmx_wqe_t *) cvmx_phys_to_ptr(result.s_work.addr);
+               return (struct cvmx_wqe *) cvmx_phys_to_ptr(result.s_work.addr);
 }
 
 /**
@@ -1382,7 +1382,7 @@ static inline cvmx_wqe_t *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_t
  * Returns Returns the WQE pointer from POW. Returns NULL if no work
  * was available.
  */
-static inline cvmx_wqe_t *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait)
+static inline struct cvmx_wqe *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait)
 {
        if (CVMX_ENABLE_POW_CHECKS)
                __cvmx_pow_warn_if_pending_switch(__func__);
@@ -1485,7 +1485,7 @@ static inline void cvmx_pow_work_request_async(int scr_addr,
  * Returns Returns the WQE from the scratch register, or NULL if no
  * work was available.
  */
-static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr)
+static inline struct cvmx_wqe *cvmx_pow_work_response_async(int scr_addr)
 {
        cvmx_pow_tag_load_resp_t result;
 
@@ -1495,7 +1495,7 @@ static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr)
        if (result.s_work.no_work)
                return NULL;
        else
-               return (cvmx_wqe_t *) cvmx_phys_to_ptr(result.s_work.addr);
+               return (struct cvmx_wqe *) cvmx_phys_to_ptr(result.s_work.addr);
 }
 
 /**
@@ -1508,7 +1508,7 @@ static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr)
  * Returns 0 if pointer is valid
  *        1 if invalid (no work was returned)
  */
-static inline uint64_t cvmx_pow_work_invalid(cvmx_wqe_t *wqe_ptr)
+static inline uint64_t cvmx_pow_work_invalid(struct cvmx_wqe *wqe_ptr)
 {
        return wqe_ptr == NULL;
 }
@@ -1638,7 +1638,7 @@ static inline void cvmx_pow_tag_sw(uint32_t tag,
  * @tag_type: type of tag
  * @group:    group value for the work queue entry.
  */
-static inline void cvmx_pow_tag_sw_full_nocheck(cvmx_wqe_t *wqp, uint32_t tag,
+static inline void cvmx_pow_tag_sw_full_nocheck(struct cvmx_wqe *wqp, uint32_t tag,
                                                enum cvmx_pow_tag_type tag_type,
                                                uint64_t group)
 {
@@ -1712,7 +1712,7 @@ static inline void cvmx_pow_tag_sw_full_nocheck(cvmx_wqe_t *wqp, uint32_t tag,
  * @tag_type: type of tag
  * @group:     group value for the work queue entry.
  */
-static inline void cvmx_pow_tag_sw_full(cvmx_wqe_t *wqp, uint32_t tag,
+static inline void cvmx_pow_tag_sw_full(struct cvmx_wqe *wqp, uint32_t tag,
                                        enum cvmx_pow_tag_type tag_type,
                                        uint64_t group)
 {
@@ -1803,7 +1803,7 @@ static inline void cvmx_pow_tag_sw_null(void)
  * @qos:      Input queue to add to.
  * @grp:      group value for the work queue entry.
  */
-static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, uint32_t tag,
+static inline void cvmx_pow_work_submit(struct cvmx_wqe *wqp, uint32_t tag,
                                        enum cvmx_pow_tag_type tag_type,
                                        uint64_t qos, uint64_t grp)
 {
index 0d697aa..9cec229 100644 (file)
@@ -547,7 +547,7 @@ union cvmx_wqe_word1 {
  *
  * must be 8-byte aligned
  */
-typedef struct {
+struct cvmx_wqe {
 
     /*****************************************************************
      * WORD 0
@@ -593,9 +593,9 @@ typedef struct {
      *
      */
 
-} CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t;
+} CVMX_CACHE_LINE_ALIGNED;
 
-static inline int cvmx_wqe_get_port(cvmx_wqe_t *work)
+static inline int cvmx_wqe_get_port(struct cvmx_wqe *work)
 {
        int port;
 
@@ -607,7 +607,7 @@ static inline int cvmx_wqe_get_port(cvmx_wqe_t *work)
        return port;
 }
 
-static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port)
+static inline void cvmx_wqe_set_port(struct cvmx_wqe *work, int port)
 {
        if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE))
                work->word2.s_cn68xx.port = port;
@@ -615,7 +615,7 @@ static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port)
                work->word1.cn38xx.ipprt = port;
 }
 
-static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work)
+static inline int cvmx_wqe_get_grp(struct cvmx_wqe *work)
 {
        int grp;
 
@@ -627,7 +627,7 @@ static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work)
        return grp;
 }
 
-static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp)
+static inline void cvmx_wqe_set_grp(struct cvmx_wqe *work, int grp)
 {
        if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE))
                work->word1.cn68xx.grp = grp;
@@ -635,7 +635,7 @@ static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp)
                work->word1.cn38xx.grp = grp;
 }
 
-static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work)
+static inline int cvmx_wqe_get_qos(struct cvmx_wqe *work)
 {
        int qos;
 
@@ -647,7 +647,7 @@ static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work)
        return qos;
 }
 
-static inline void cvmx_wqe_set_qos(cvmx_wqe_t *work, int qos)
+static inline void cvmx_wqe_set_qos(struct cvmx_wqe *work, int qos)
 {
        if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE))
                work->word1.cn68xx.qos = qos;
index 7619ad3..856e12f 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/dsemul.h>
 #include <asm/mipsregs.h>
 #include <asm/prefetch.h>
+#include <asm/vdso/processor.h>
 
 /*
  * System setup and hardware flags..
@@ -253,13 +254,13 @@ struct thread_struct {
 #ifdef CONFIG_MIPS_FP_SUPPORT
        /* Saved fpu/fpu emulator stuff. */
        struct mips_fpu_struct fpu FPU_ALIGN;
-#endif
        /* Assigned branch delay slot 'emulation' frame */
        atomic_t bd_emu_frame;
        /* PC of the branch from a branch delay slot 'emulation' */
        unsigned long bd_emu_branch_pc;
        /* PC to continue from following a branch delay slot 'emulation' */
        unsigned long bd_emu_cont_pc;
+#endif
 #ifdef CONFIG_MIPS_MT_FPAFF
        /* Emulated instruction count */
        unsigned long emulated_fp;
@@ -302,7 +303,11 @@ struct thread_struct {
                .fpr            = {{{0,},},},                   \
                .fcr31          = 0,                            \
                .msacsr         = 0,                            \
-       },
+       },                                                      \
+       /* Delay slot emulation */                              \
+       .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE),          \
+       .bd_emu_branch_pc = 0,                                  \
+       .bd_emu_cont_pc = 0,
 #else
 # define FPU_INIT
 #endif
@@ -334,10 +339,6 @@ struct thread_struct {
         * FPU affinity state (null if not FPAFF)               \
         */                                                     \
        FPAFF_INIT                                              \
-       /* Delay slot emulation */                              \
-       .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE),          \
-       .bd_emu_branch_pc = 0,                                  \
-       .bd_emu_cont_pc = 0,                                    \
        /*                                                      \
         * Saved DSP stuff                                      \
         */                                                     \
@@ -385,21 +386,6 @@ unsigned long get_wchan(struct task_struct *p);
 #define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[29])
 #define KSTK_STATUS(tsk) (task_pt_regs(tsk)->cp0_status)
 
-#ifdef CONFIG_CPU_LOONGSON64
-/*
- * Loongson-3's SFB (Store-Fill-Buffer) may buffer writes indefinitely when a
- * tight read loop is executed, because reads take priority over writes & the
- * hardware (incorrectly) doesn't ensure that writes will eventually occur.
- *
- * Since spin loops of any kind should have a cpu_relax() in them, force an SFB
- * flush from cpu_relax() such that any pending writes will become visible as
- * expected.
- */
-#define cpu_relax()    smp_mb()
-#else
-#define cpu_relax()    barrier()
-#endif
-
 /*
  * Return_address is a replacement for __builtin_return_address(count)
  * which on certain architectures cannot reasonably be implemented in GCC
index a107201..7dfa297 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef __ASM_SNI_H
 #define __ASM_SNI_H
 
+#include <linux/irqreturn.h>
+
 extern unsigned int sni_brd_type;
 
 #define SNI_BRD_10                2
@@ -239,6 +241,6 @@ static inline int sni_eisa_root_init(void)
 
 /* common irq stuff */
 extern void (*sni_hwint)(void);
-extern struct irqaction sni_isa_irq;
+extern irqreturn_t sni_isa_irq_handler(int dummy, void *p);
 
 #endif /* __ASM_SNI_H */
index 7c6a109..aabd097 100644 (file)
  * effective barrier as noted by commit 6b07d38aaa52 ("MIPS: Octeon: Use
  * optimized memory barrier primitives."). Here we specify that the affected
  * sync instructions should be emitted twice.
+ * Note that this expression is evaluated by the assembler (not the compiler),
+ * and that the assembler evaluates '==' as 0 or -1, not 0 or 1.
  */
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
-# define __SYNC_rpt(type)      (1 + (type == __SYNC_wmb))
+# define __SYNC_rpt(type)      (1 - (type == __SYNC_wmb))
 #else
 # define __SYNC_rpt(type)      1
 #endif
diff --git a/arch/mips/include/asm/vdso/clocksource.h b/arch/mips/include/asm/vdso/clocksource.h
new file mode 100644 (file)
index 0000000..510e167
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __ASM_VDSOCLOCKSOURCE_H
+#define __ASM_VDSOCLOCKSOURCE_H
+
+#define VDSO_ARCH_CLOCKMODES   \
+       VDSO_CLOCKMODE_R4K,     \
+       VDSO_CLOCKMODE_GIC
+
+#endif /* __ASM_VDSOCLOCKSOURCE_H */
index a58687e..c63ddca 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-#include <linux/compiler.h>
-#include <linux/time.h>
-
 #include <asm/vdso/vdso.h>
 #include <asm/clocksource.h>
-#include <asm/io.h>
 #include <asm/unistd.h>
 #include <asm/vdso.h>
 
 #define VDSO_HAS_CLOCK_GETRES          1
 
-#define __VDSO_USE_SYSCALL             ULLONG_MAX
-
 static __always_inline long gettimeofday_fallback(
                                struct __kernel_old_timeval *_tv,
                                struct timezone *_tz)
@@ -175,29 +169,28 @@ static __always_inline u64 read_gic_count(const struct vdso_data *data)
 
 static __always_inline u64 __arch_get_hw_counter(s32 clock_mode)
 {
-#ifdef CONFIG_CLKSRC_MIPS_GIC
-       const struct vdso_data *data = get_vdso_data();
-#endif
-       u64 cycle_now;
-
-       switch (clock_mode) {
 #ifdef CONFIG_CSRC_R4K
-       case VDSO_CLOCK_R4K:
-               cycle_now = read_r4k_count();
-               break;
+       if (clock_mode == VDSO_CLOCKMODE_R4K)
+               return read_r4k_count();
 #endif
 #ifdef CONFIG_CLKSRC_MIPS_GIC
-       case VDSO_CLOCK_GIC:
-               cycle_now = read_gic_count(data);
-               break;
+       if (clock_mode == VDSO_CLOCKMODE_GIC)
+               return read_gic_count(get_vdso_data());
 #endif
-       default:
-               cycle_now = __VDSO_USE_SYSCALL;
-               break;
-       }
+       /*
+        * Core checks mode already. So this raced against a concurrent
+        * update. Return something. Core will do another round see the
+        * change and fallback to syscall.
+        */
+       return 0;
+}
 
-       return cycle_now;
+static inline bool mips_vdso_hres_capable(void)
+{
+       return IS_ENABLED(CONFIG_CSRC_R4K) ||
+              IS_ENABLED(CONFIG_CLKSRC_MIPS_GIC);
 }
+#define __arch_vdso_hres_capable mips_vdso_hres_capable
 
 static __always_inline const struct vdso_data *__arch_get_vdso_data(void)
 {
diff --git a/arch/mips/include/asm/vdso/processor.h b/arch/mips/include/asm/vdso/processor.h
new file mode 100644 (file)
index 0000000..511c95d
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+#ifndef __ASM_VDSO_PROCESSOR_H
+#define __ASM_VDSO_PROCESSOR_H
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_CPU_LOONGSON64
+/*
+ * Loongson-3's SFB (Store-Fill-Buffer) may buffer writes indefinitely when a
+ * tight read loop is executed, because reads take priority over writes & the
+ * hardware (incorrectly) doesn't ensure that writes will eventually occur.
+ *
+ * Since spin loops of any kind should have a cpu_relax() in them, force an SFB
+ * flush from cpu_relax() such that any pending writes will become visible as
+ * expected.
+ */
+#define cpu_relax()    smp_mb()
+#else
+#define cpu_relax()    barrier()
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_VDSO_PROCESSOR_H */
index 00d41b9..47168aa 100644 (file)
@@ -19,15 +19,6 @@ struct vdso_data *__mips_get_k_vdso_data(void)
 }
 #define __arch_get_k_vdso_data __mips_get_k_vdso_data
 
-static __always_inline
-int __mips_get_clock_mode(struct timekeeper *tk)
-{
-       u32 clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode;
-
-       return clock_mode;
-}
-#define __arch_get_clock_mode __mips_get_clock_mode
-
 /* The asm-generic header needs to be included after the definitions above */
 #include <asm-generic/vdso/vsyscall.h>
 
index 5d6828b..04b9c40 100644 (file)
@@ -125,24 +125,18 @@ static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction r4030_timer_irqaction = {
-       .handler        = r4030_timer_interrupt,
-       .flags          = IRQF_TIMER,
-       .name           = "R4030 timer",
-};
-
 void __init plat_time_init(void)
 {
        struct clock_event_device *cd = &r4030_clockevent;
-       struct irqaction *action = &r4030_timer_irqaction;
        unsigned int cpu = smp_processor_id();
 
        BUG_ON(HZ != 100);
 
        cd->cpumask             = cpumask_of(cpu);
        clockevents_register_device(cd);
-       action->dev_id = cd;
-       setup_irq(JAZZ_TIMER_IRQ, action);
+       if (request_irq(JAZZ_TIMER_IRQ, r4030_timer_interrupt, IRQF_TIMER,
+                       "R4030 timer", cd))
+               pr_err("Failed to register R4030 timer interrupt\n");
 
        /*
         * Set clock to 100Hz.
index 5476899..605a84a 100644 (file)
@@ -4,8 +4,8 @@
  *  JZ4740 platform time support
  */
 
-#include <linux/clk-provider.h>
 #include <linux/clocksource.h>
+#include <linux/of_clk.h>
 
 #include <asm/mach-jz4740/timer.h>
 
index b3e8c11..d39a296 100644 (file)
@@ -91,16 +91,15 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
 }
 
 static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
-static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
 static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
 
 void sb1480_clockevent_init(void)
 {
        unsigned int cpu = smp_processor_id();
        unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
-       struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
        struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
        unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
+       unsigned long flags =  IRQF_PERCPU | IRQF_TIMER;
 
        BUG_ON(cpu > 3);        /* Only have 4 general purpose timers */
 
@@ -133,11 +132,7 @@ void sb1480_clockevent_init(void)
 
        bcm1480_unmask_irq(cpu, irq);
 
-       action->handler = sibyte_counter_handler;
-       action->flags   = IRQF_PERCPU | IRQF_TIMER;
-       action->name    = name;
-       action->dev_id  = cd;
-
        irq_set_affinity(irq, cpumask_of(cpu));
-       setup_irq(irq, action);
+       if (request_irq(irq, sibyte_counter_handler, flags, name, cd))
+               pr_err("Failed to request irq %d (%s)\n", irq, name);
 }
index 1e1edab..9a47fbc 100644 (file)
@@ -100,14 +100,9 @@ static irqreturn_t ds1287_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction ds1287_irqaction = {
-       .handler        = ds1287_interrupt,
-       .flags          = IRQF_PERCPU | IRQF_TIMER,
-       .name           = "ds1287",
-};
-
 int __init ds1287_clockevent_init(int irq)
 {
+       unsigned long flags = IRQF_PERCPU | IRQF_TIMER;
        struct clock_event_device *cd;
 
        cd = &ds1287_clockevent;
@@ -122,5 +117,5 @@ int __init ds1287_clockevent_init(int irq)
 
        clockevents_register_device(&ds1287_clockevent);
 
-       return setup_irq(irq, &ds1287_irqaction);
+       return request_irq(irq, ds1287_interrupt, flags, "ds1287", NULL);
 }
index eb53548..5b132e8 100644 (file)
@@ -120,12 +120,6 @@ static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction gt641xx_timer0_irqaction = {
-       .handler        = gt641xx_timer0_interrupt,
-       .flags          = IRQF_PERCPU | IRQF_TIMER,
-       .name           = "gt641xx_timer0",
-};
-
 static int __init gt641xx_timer0_clockevent_init(void)
 {
        struct clock_event_device *cd;
@@ -146,6 +140,7 @@ static int __init gt641xx_timer0_clockevent_init(void)
 
        clockevents_register_device(&gt641xx_timer0_clockevent);
 
-       return setup_irq(GT641XX_TIMER0_IRQ, &gt641xx_timer0_irqaction);
+       return request_irq(GT641XX_TIMER0_IRQ, gt641xx_timer0_interrupt,
+                          IRQF_PERCPU | IRQF_TIMER, "gt641xx_timer0", NULL);
 }
 arch_initcall(gt641xx_timer0_clockevent_init);
index dd6a18b..17a9cbb 100644 (file)
@@ -252,6 +252,7 @@ unsigned int __weak get_c0_compare_int(void)
 
 int r4k_clockevent_init(void)
 {
+       unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED;
        unsigned int cpu = smp_processor_id();
        struct clock_event_device *cd;
        unsigned int irq, min_delta;
@@ -291,7 +292,9 @@ int r4k_clockevent_init(void)
 
        cp0_timer_irq_installed = 1;
 
-       setup_irq(irq, &c0_compare_irqaction);
+       if (request_irq(irq, c0_compare_interrupt, flags, "timer",
+                       c0_compare_interrupt))
+               pr_err("Failed to request irq %d (timer)\n", irq);
 
        return 0;
 }
index e1a0860..0451273 100644 (file)
@@ -90,16 +90,15 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
 }
 
 static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
-static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
 static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
 
 void sb1250_clockevent_init(void)
 {
        unsigned int cpu = smp_processor_id();
        unsigned int irq = K_INT_TIMER_0 + cpu;
-       struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
        struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
        unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
+       unsigned long flags = IRQF_PERCPU | IRQF_TIMER;
 
        /* Only have 4 general purpose timers, and we use last one as hpt */
        BUG_ON(cpu > 2);
@@ -133,11 +132,7 @@ void sb1250_clockevent_init(void)
 
        sb1250_unmask_irq(cpu, irq);
 
-       action->handler = sibyte_counter_handler;
-       action->flags   = IRQF_PERCPU | IRQF_TIMER;
-       action->name    = name;
-       action->dev_id  = cd;
-
        irq_set_affinity(irq, cpumask_of(cpu));
-       setup_irq(irq, action);
+       if (request_irq(irq, sibyte_counter_handler, flags, name, cd))
+               pr_err("Failed to request irq %d (%s)\n", irq, name);
 }
index 7b17c8f..5709469 100644 (file)
@@ -174,13 +174,6 @@ static irqreturn_t txx9tmr_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction txx9tmr_irq = {
-       .handler        = txx9tmr_interrupt,
-       .flags          = IRQF_PERCPU | IRQF_TIMER,
-       .name           = "txx9tmr",
-       .dev_id         = &txx9_clock_event_device,
-};
-
 void __init txx9_clockevent_init(unsigned long baseaddr, int irq,
                                 unsigned int imbusclk)
 {
@@ -202,7 +195,9 @@ void __init txx9_clockevent_init(unsigned long baseaddr, int irq,
        cd->irq = irq;
        cd->cpumask = cpumask_of(0),
        clockevents_register_device(cd);
-       setup_irq(irq, &txx9tmr_irq);
+       if (request_irq(irq, txx9tmr_interrupt, IRQF_PERCPU | IRQF_TIMER,
+                       "txx9tmr", &txx9_clock_event_device))
+               pr_err("Failed to request irq %d (txx9tmr)\n", irq);
        printk(KERN_INFO "TXx9: clockevent device at 0x%lx, irq %d\n",
               baseaddr, irq);
 }
index 6ab6b03..f21a230 100644 (file)
@@ -513,6 +513,13 @@ static inline void set_elf_platform(int cpu, const char *plat)
                __elf_platform = plat;
 }
 
+static inline void set_elf_base_platform(const char *plat)
+{
+       if (__elf_base_platform == NULL) {
+               __elf_base_platform = plat;
+       }
+}
+
 static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
 {
 #ifdef __NEED_VMBITS_PROBE
@@ -527,36 +534,46 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
        switch (isa) {
        case MIPS_CPU_ISA_M64R2:
                c->isa_level |= MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2;
+               set_elf_base_platform("mips64r2");
                /* fall through */
        case MIPS_CPU_ISA_M64R1:
                c->isa_level |= MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1;
+               set_elf_base_platform("mips64");
                /* fall through */
        case MIPS_CPU_ISA_V:
                c->isa_level |= MIPS_CPU_ISA_V;
+               set_elf_base_platform("mips5");
                /* fall through */
        case MIPS_CPU_ISA_IV:
                c->isa_level |= MIPS_CPU_ISA_IV;
+               set_elf_base_platform("mips4");
                /* fall through */
        case MIPS_CPU_ISA_III:
                c->isa_level |= MIPS_CPU_ISA_II | MIPS_CPU_ISA_III;
+               set_elf_base_platform("mips3");
                break;
 
        /* R6 incompatible with everything else */
        case MIPS_CPU_ISA_M64R6:
                c->isa_level |= MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6;
+               set_elf_base_platform("mips64r6");
                /* fall through */
        case MIPS_CPU_ISA_M32R6:
                c->isa_level |= MIPS_CPU_ISA_M32R6;
+               set_elf_base_platform("mips32r6");
                /* Break here so we don't add incompatible ISAs */
                break;
        case MIPS_CPU_ISA_M32R2:
                c->isa_level |= MIPS_CPU_ISA_M32R2;
+               set_elf_base_platform("mips32r2");
                /* fall through */
        case MIPS_CPU_ISA_M32R1:
                c->isa_level |= MIPS_CPU_ISA_M32R1;
+               set_elf_base_platform("mips32");
                /* fall through */
        case MIPS_CPU_ISA_II:
                c->isa_level |= MIPS_CPU_ISA_II;
+               set_elf_base_platform("mips2");
                break;
        }
 }
@@ -2113,6 +2130,7 @@ EXPORT_SYMBOL(__ua_limit);
 
 const char *__cpu_name[NR_CPUS];
 const char *__elf_platform;
+const char *__elf_base_platform;
 
 void cpu_probe(void)
 {
index eed099f..437dda6 100644 (file)
@@ -78,7 +78,7 @@ int __init init_r4k_clocksource(void)
         * by the VDSO (HWREna is configured by configure_hwrena()).
         */
        if (cpu_has_mips_r2_r6 && rdhwr_count_usable())
-               clocksource_mips.archdata.vdso_clock_mode = VDSO_CLOCK_R4K;
+               clocksource_mips.vdso_clock_mode = VDSO_CLOCKMODE_R4K;
 
        clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
 
index df7ddd2..ca21210 100644 (file)
@@ -18,16 +18,13 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction irq0  = {
-       .handler = timer_interrupt,
-       .flags = IRQF_NOBALANCING | IRQF_TIMER,
-       .name = "timer"
-};
-
 void __init setup_pit_timer(void)
 {
+       unsigned long flags = IRQF_NOBALANCING | IRQF_TIMER;
+
        clockevent_i8253_init(true);
-       setup_irq(0, &irq0);
+       if (request_irq(0, timer_interrupt, flags, "timer", NULL))
+               pr_err("Failed to request irq 0 (timer)\n");
 }
 
 static int __init init_pit_clocksource(void)
index 339870e..b2a7975 100644 (file)
@@ -75,7 +75,9 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
        lose_fpu(0);
        clear_thread_flag(TIF_MSA_CTX_LIVE);
        clear_used_math();
+#ifdef CONFIG_MIPS_FP_SUPPORT
        atomic_set(&current->thread.bd_emu_frame, BD_EMUFRAME_NONE);
+#endif
        init_dsp();
        regs->cp0_epc = pc;
        regs->regs[29] = sp;
@@ -176,7 +178,9 @@ int copy_thread_tls(unsigned long clone_flags, unsigned long usp,
        clear_tsk_thread_flag(p, TIF_FPUBOUND);
 #endif /* CONFIG_MIPS_MT_FPAFF */
 
+#ifdef CONFIG_MIPS_FP_SUPPORT
        atomic_set(&p->thread.bd_emu_frame, BD_EMUFRAME_NONE);
+#endif
 
        if (clone_flags & CLONE_SETTLS)
                ti->tp_value = tls;
@@ -650,8 +654,10 @@ unsigned long mips_stack_top(void)
 {
        unsigned long top = TASK_SIZE & PAGE_MASK;
 
-       /* One page for branch delay slot "emulation" */
-       top -= PAGE_SIZE;
+       if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
+               /* One page for branch delay slot "emulation" */
+               top -= PAGE_SIZE;
+       }
 
        /* Space for the VDSO, data page & GIC user page */
        top -= PAGE_ALIGN(current->thread.abi->vdso->size);
index cb95470..38c6925 100644 (file)
@@ -51,11 +51,6 @@ static irqreturn_t rtlx_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction rtlx_irq = {
-       .handler        = rtlx_interrupt,
-       .name           = "RTLX",
-};
-
 static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;
 
 void _interrupt_sp(void)
@@ -124,8 +119,7 @@ int __init rtlx_module_init(void)
                goto out_class;
        }
 
-       rtlx_irq.dev_id = rtlx;
-       err = setup_irq(rtlx_irq_num, &rtlx_irq);
+       err = request_irq(rtlx_irq_num, rtlx_interrupt, 0, "RTLX", rtlx);
        if (err)
                goto out_class;
 
index 1ac2752..10bef8f 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/decompress/generic.h>
 #include <linux/of_fdt.h>
 #include <linux/of_reserved_mem.h>
+#include <linux/dmi.h>
 
 #include <asm/addrspace.h>
 #include <asm/bootinfo.h>
@@ -605,7 +606,8 @@ static void __init bootcmdline_init(char **cmdline_p)
         * If we're configured to take boot arguments from DT, look for those
         * now.
         */
-       if (IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB))
+       if (IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB) ||
+           IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND))
                of_scan_flat_dt(bootcmdline_scan_chosen, &dt_bootargs);
 #endif
 
@@ -798,6 +800,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        arch_mem_init(cmdline_p);
+       dmi_setup();
 
        resource_init();
        plat_smp_setup();
index f510c00..48d84d5 100644 (file)
@@ -207,25 +207,13 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction irq_resched = {
-       .handler        = ipi_resched_interrupt,
-       .flags          = IRQF_PERCPU,
-       .name           = "IPI resched"
-};
-
-static struct irqaction irq_call = {
-       .handler        = ipi_call_interrupt,
-       .flags          = IRQF_PERCPU,
-       .name           = "IPI call"
-};
-
-static void smp_ipi_init_one(unsigned int virq,
-                                   struct irqaction *action)
+static void smp_ipi_init_one(unsigned int virq, const char *name,
+                            irq_handler_t handler)
 {
        int ret;
 
        irq_set_handler(virq, handle_percpu_irq);
-       ret = setup_irq(virq, action);
+       ret = request_irq(virq, handler, IRQF_PERCPU, name, NULL);
        BUG_ON(ret);
 }
 
@@ -278,12 +266,15 @@ int mips_smp_ipi_allocate(const struct cpumask *mask)
                int cpu;
 
                for_each_cpu(cpu, mask) {
-                       smp_ipi_init_one(call_virq + cpu, &irq_call);
-                       smp_ipi_init_one(sched_virq + cpu, &irq_resched);
+                       smp_ipi_init_one(call_virq + cpu, "IPI call",
+                                        ipi_call_interrupt);
+                       smp_ipi_init_one(sched_virq + cpu, "IPI resched",
+                                        ipi_resched_interrupt);
                }
        } else {
-               smp_ipi_init_one(call_virq, &irq_call);
-               smp_ipi_init_one(sched_virq, &irq_resched);
+               smp_ipi_init_one(call_virq, "IPI call", ipi_call_interrupt);
+               smp_ipi_init_one(sched_virq, "IPI resched",
+                                ipi_resched_interrupt);
        }
 
        return 0;
@@ -311,8 +302,8 @@ int mips_smp_ipi_free(const struct cpumask *mask)
                int cpu;
 
                for_each_cpu(cpu, mask) {
-                       remove_irq(call_virq + cpu, &irq_call);
-                       remove_irq(sched_virq + cpu, &irq_resched);
+                       free_irq(call_virq + cpu, NULL);
+                       free_irq(sched_virq + cpu, NULL);
                }
        }
        irq_destroy_ipi(call_virq, mask);
@@ -696,29 +687,22 @@ EXPORT_SYMBOL(flush_tlb_one);
 
 #ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
 
-static DEFINE_PER_CPU(atomic_t, tick_broadcast_count);
 static DEFINE_PER_CPU(call_single_data_t, tick_broadcast_csd);
 
 void tick_broadcast(const struct cpumask *mask)
 {
-       atomic_t *count;
        call_single_data_t *csd;
        int cpu;
 
        for_each_cpu(cpu, mask) {
-               count = &per_cpu(tick_broadcast_count, cpu);
                csd = &per_cpu(tick_broadcast_csd, cpu);
-
-               if (atomic_inc_return(count) == 1)
-                       smp_call_function_single_async(cpu, csd);
+               smp_call_function_single_async(cpu, csd);
        }
 }
 
 static void tick_broadcast_callee(void *info)
 {
-       int cpu = smp_processor_id();
        tick_receive_broadcast();
-       atomic_set(&per_cpu(tick_broadcast_count, cpu), 0);
 }
 
 static int __init tick_broadcast_init(void)
index bc35f84..3adb735 100644 (file)
@@ -71,10 +71,12 @@ subsys_initcall(init_vdso);
 
 static unsigned long vdso_base(void)
 {
-       unsigned long base;
+       unsigned long base = STACK_TOP;
 
-       /* Skip the delay slot emulation page */
-       base = STACK_TOP + PAGE_SIZE;
+       if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
+               /* Skip the delay slot emulation page */
+               base += PAGE_SIZE;
+       }
 
        if (current->flags & PF_RANDOMIZE) {
                base += get_random_int() & (VDSO_RANDOMIZE_SIZE - 1);
@@ -95,14 +97,16 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        if (down_write_killable(&mm->mmap_sem))
                return -EINTR;
 
-       /* Map delay slot emulation page */
-       base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
-                          VM_READ | VM_EXEC |
-                          VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
-                          0, NULL);
-       if (IS_ERR_VALUE(base)) {
-               ret = base;
-               goto out;
+       if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
+               /* Map delay slot emulation page */
+               base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
+                               VM_READ | VM_EXEC |
+                               VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+                               0, NULL);
+               if (IS_ERR_VALUE(base)) {
+                       ret = base;
+                       goto out;
+               }
        }
 
        /*
index 6176b9a..d0d832a 100644 (file)
@@ -134,7 +134,7 @@ void release_vpe(struct vpe *v)
 {
        list_del(&v->list);
        if (v->load_addr)
-               release_progmem(v);
+               release_progmem(v->load_addr);
        kfree(v);
 }
 
index 0f3a897..7965bbd 100644 (file)
@@ -90,14 +90,9 @@ asmlinkage void plat_irq_dispatch(void)
        }
 }
 
-static struct irqaction cascade = {
-       .handler        = no_action,
-       .name           = "cascade",
-       .flags          = IRQF_NO_THREAD,
-};
-
 void __init arch_init_irq(void)
 {
+       int irq = LASAT_CASCADE_IRQ;
        int i;
 
        if (IS_LASAT_200()) {
@@ -119,5 +114,6 @@ void __init arch_init_irq(void)
        for (i = LASAT_IRQ_BASE; i <= LASAT_IRQ_END; i++)
                irq_set_chip_and_handler(i, &lasat_irq_type, handle_level_irq);
 
-       setup_irq(LASAT_CASCADE_IRQ, &cascade);
+       if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", irq);
 }
index 68c495e..2e8dfc1 100644 (file)
@@ -24,6 +24,8 @@
 #define GCC_DADDI_IMM_ASM() "r"
 #endif
 
+#ifndef CONFIG_HAVE_PLAT_DELAY
+
 void __delay(unsigned long loops)
 {
        __asm__ __volatile__ (
@@ -63,3 +65,5 @@ void __ndelay(unsigned long ns)
        __delay((ns * 0x00000005ull * HZ * lpj) >> 32);
 }
 EXPORT_SYMBOL(__ndelay);
+
+#endif
index f7994d9..88065ee 100644 (file)
@@ -598,6 +598,7 @@ SEXC(1)
         nop
        .endm
 
+#ifndef CONFIG_HAVE_PLAT_MEMCPY
        .align  5
 LEAF(memmove)
 EXPORT_SYMBOL(memmove)
@@ -665,6 +666,8 @@ EXPORT_SYMBOL(__copy_user)
        /* Legacy Mode, user <-> user */
        __BUILD_COPY_USER LEGACY_MODE USEROP USEROP
 
+#endif
+
 #ifdef CONFIG_EVA
 
 /*
index 82352cc..c06ad41 100644 (file)
@@ -30,11 +30,6 @@ static struct irq_chip bonito_irq_type = {
        .irq_unmask     = bonito_irq_enable,
 };
 
-static struct irqaction __maybe_unused dma_timeout_irqaction = {
-       .handler        = no_action,
-       .name           = "dma_timeout",
-};
-
 void bonito_irq_init(void)
 {
        u32 i;
@@ -44,6 +39,8 @@ void bonito_irq_init(void)
                                         handle_level_irq);
 
 #ifdef CONFIG_CPU_LOONGSON2E
-       setup_irq(LOONGSON_IRQ_BASE + 10, &dma_timeout_irqaction);
+       i = LOONGSON_IRQ_BASE + 10;
+       if (request_irq(i, no_action, 0, "dma_timeout", NULL))
+               pr_err("Failed to request irq %d (dma_timeout)\n", i);
 #endif
 }
index 30af1b7..f21a540 100644 (file)
@@ -100,12 +100,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction irq5 = {
-       .handler = timer_interrupt,
-       .flags = IRQF_NOBALANCING | IRQF_TIMER,
-       .name = "timer"
-};
-
 /*
  * Initialize the conversion factor and the min/max deltas of the clock event
  * structure and register the clock event source with the framework.
@@ -134,7 +128,9 @@ void __init setup_mfgpt0_timer(void)
 
        clockevents_register_device(cd);
 
-       setup_irq(CS5536_MFGPT_INTR, &irq5);
+       if (request_irq(CS5536_MFGPT_INTR, timer_interrupt,
+                       IRQF_NOBALANCING | IRQF_TIMER, "timer", NULL))
+               pr_err("Failed to register timer interrupt\n");
 }
 
 /*
index 32278e7..305aa2e 100644 (file)
@@ -35,14 +35,10 @@ asmlinkage void mach_irq_dispatch(unsigned int pending)
                spurious_interrupt();
 }
 
-static struct irqaction cascade_irqaction = {
-       .handler = no_action,
-       .name = "cascade",
-       .flags = IRQF_NO_THREAD,
-};
-
 void __init mach_init_irq(void)
 {
+       int irq;
+
        /* init all controller
         *   0-15         ------> i8259 interrupt
         *   16-23        ------> mips cpu interrupt
@@ -59,7 +55,11 @@ void __init mach_init_irq(void)
        bonito_irq_init();
 
        /* bonito irq at IP2 */
-       setup_irq(MIPS_CPU_IRQ_BASE + 2, &cascade_irqaction);
+       irq = MIPS_CPU_IRQ_BASE + 2;
+       if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", irq);
        /* 8259 irq at IP5 */
-       setup_irq(MIPS_CPU_IRQ_BASE + 5, &cascade_irqaction);
+       irq = MIPS_CPU_IRQ_BASE + 5;
+       if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", irq);
 }
index c58a044..6f00579 100644 (file)
@@ -90,18 +90,6 @@ static irqreturn_t ip6_action(int cpl, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction ip6_irqaction = {
-       .handler = ip6_action,
-       .name = "cascade",
-       .flags = IRQF_SHARED | IRQF_NO_THREAD,
-};
-
-static struct irqaction cascade_irqaction = {
-       .handler = no_action,
-       .name = "cascade",
-       .flags = IRQF_NO_THREAD | IRQF_NO_SUSPEND,
-};
-
 void __init mach_init_irq(void)
 {
        /* init all controller
@@ -120,7 +108,11 @@ void __init mach_init_irq(void)
        bonito_irq_init();
 
        /* setup north bridge irq (bonito) */
-       setup_irq(LOONGSON_NORTH_BRIDGE_IRQ, &ip6_irqaction);
+       if (request_irq(LOONGSON_NORTH_BRIDGE_IRQ, ip6_action,
+                       IRQF_SHARED | IRQF_NO_THREAD, "cascade", ip6_action))
+               pr_err("Failed to register north bridge cascade interrupt\n");
        /* setup source bridge irq (i8259) */
-       setup_irq(LOONGSON_SOUTH_BRIDGE_IRQ, &cascade_irqaction);
+       if (request_irq(LOONGSON_SOUTH_BRIDGE_IRQ, no_action,
+                       IRQF_NO_THREAD | IRQF_NO_SUSPEND, "cascade", NULL))
+               pr_err("Failed to register south bridge cascade interrupt\n");
 }
index 168d221..9a50070 100644 (file)
@@ -149,12 +149,6 @@ asmlinkage void plat_irq_dispatch(void)
 
 }
 
-static struct irqaction cascade_irqaction = {
-       .handler = no_action,
-       .name = "cascade",
-       .flags = IRQF_NO_THREAD,
-};
-
 static void __init ls1x_irq_init(int base)
 {
        int n;
@@ -176,12 +170,17 @@ static void __init ls1x_irq_init(int base)
                                         handle_level_irq);
        }
 
-       setup_irq(INT0_IRQ, &cascade_irqaction);
-       setup_irq(INT1_IRQ, &cascade_irqaction);
-       setup_irq(INT2_IRQ, &cascade_irqaction);
-       setup_irq(INT3_IRQ, &cascade_irqaction);
+       if (request_irq(INT0_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", INT0_IRQ);
+       if (request_irq(INT1_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", INT1_IRQ);
+       if (request_irq(INT2_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", INT2_IRQ);
+       if (request_irq(INT3_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", INT3_IRQ);
 #if defined(CONFIG_LOONGSON1_LS1C)
-       setup_irq(INT4_IRQ, &cascade_irqaction);
+       if (request_irq(INT4_IRQ, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to request irq %d (cascade)\n", INT4_IRQ);
 #endif
 }
 
index 4cc73f7..459b15c 100644 (file)
@@ -176,13 +176,6 @@ static struct clock_event_device ls1x_clockevent = {
        .tick_resume            = ls1x_clockevent_tick_resume,
 };
 
-static struct irqaction ls1x_pwmtimer_irqaction = {
-       .name           = "ls1x-pwmtimer",
-       .handler        = ls1x_clockevent_isr,
-       .dev_id         = &ls1x_clockevent,
-       .flags          = IRQF_PERCPU | IRQF_TIMER,
-};
-
 static void __init ls1x_time_init(void)
 {
        struct clock_event_device *cd = &ls1x_clockevent;
@@ -206,7 +199,10 @@ static void __init ls1x_time_init(void)
        if (ret)
                panic(KERN_ERR "Failed to register clocksource: %d\n", ret);
 
-       setup_irq(LS1X_TIMER_IRQ, &ls1x_pwmtimer_irqaction);
+       if (request_irq(LS1X_TIMER_IRQ, ls1x_clockevent_isr,
+                       IRQF_PERCPU | IRQF_TIMER, "ls1x-pwmtimer",
+                       &ls1x_clockevent))
+               pr_err("Failed to register ls1x-pwmtimer interrupt\n");
 }
 #endif /* CONFIG_CEVT_CSRC_LS1X */
 
index 7821891..b7f40b1 100644 (file)
@@ -2,7 +2,7 @@
 #
 # Makefile for Loongson-3 family machines
 #
-obj-$(CONFIG_MACH_LOONGSON64) += irq.o cop2-ex.o platform.o acpi_init.o dma.o \
+obj-$(CONFIG_MACH_LOONGSON64) += cop2-ex.o platform.o acpi_init.o dma.o \
                                setup.o init.o env.o time.o reset.o \
 
 obj-$(CONFIG_SMP)      += smp.o
index 0daeb7b..2554ef1 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/bootinfo.h>
 #include <loongson.h>
 #include <boot_param.h>
+#include <builtin_dtbs.h>
 #include <workarounds.h>
 
 u32 cpu_clock_freq;
@@ -120,6 +121,28 @@ void __init prom_init_env(void)
                loongson_sysconf.cores_per_node - 1) /
                loongson_sysconf.cores_per_node;
 
+       if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64C) {
+               switch (read_c0_prid() & PRID_REV_MASK) {
+               case PRID_REV_LOONGSON3A_R1:
+               case PRID_REV_LOONGSON3A_R2_0:
+               case PRID_REV_LOONGSON3A_R2_1:
+               case PRID_REV_LOONGSON3A_R3_0:
+               case PRID_REV_LOONGSON3A_R3_1:
+                       loongson_fdt_blob = __dtb_loongson3_4core_rs780e_begin;
+                       break;
+               case PRID_REV_LOONGSON3B_R1:
+               case PRID_REV_LOONGSON3B_R2:
+                       loongson_fdt_blob = __dtb_loongson3_8core_rs780e_begin;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+
+       if (!loongson_fdt_blob)
+               pr_err("Failed to determine built-in Loongson64 dtb\n");
+
        loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr;
        loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr;
        loongson_sysconf.pci_io_base = eirq_source->pci_io_start_addr;
index ed15430..e428259 100644 (file)
@@ -187,12 +187,6 @@ static irqreturn_t hpet_irq_handler(int irq, void *data)
        return IRQ_NONE;
 }
 
-static struct irqaction hpet_irq = {
-       .handler = hpet_irq_handler,
-       .flags = IRQF_NOBALANCING | IRQF_TIMER,
-       .name = "hpet",
-};
-
 /*
  * hpet address assignation and irq setting should be done in bios.
  * but pmon don't do this, we just setup here directly.
@@ -224,6 +218,7 @@ static void hpet_setup(void)
 
 void __init setup_hpet_timer(void)
 {
+       unsigned long flags = IRQF_NOBALANCING | IRQF_TIMER;
        unsigned int cpu = smp_processor_id();
        struct clock_event_device *cd;
 
@@ -247,7 +242,8 @@ void __init setup_hpet_timer(void)
        cd->min_delta_ticks = HPET_MIN_PROG_DELTA;
 
        clockevents_register_device(cd);
-       setup_irq(HPET_T0_IRQ, &hpet_irq);
+       if (request_irq(HPET_T0_IRQ, hpet_irq_handler, flags, "hpet", NULL))
+               pr_err("Failed to request irq %d (hpet)\n", HPET_T0_IRQ);
        pr_info("hpet clock event device register\n");
 }
 
index 5ac1a0f..da38944 100644 (file)
@@ -4,6 +4,7 @@
  * Author: Wu Zhangjin, wuzhangjin@gmail.com
  */
 
+#include <linux/irqchip.h>
 #include <linux/memblock.h>
 #include <asm/bootinfo.h>
 #include <asm/traps.h>
@@ -44,3 +45,8 @@ void __init prom_init(void)
 void __init prom_free_prom_memory(void)
 {
 }
+
+void __init arch_init_irq(void)
+{
+       irqchip_init();
+}
diff --git a/arch/mips/loongson64/irq.c b/arch/mips/loongson64/irq.c
deleted file mode 100644 (file)
index 79ad797..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <loongson.h>
-#include <irq.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <asm/irq_cpu.h>
-#include <asm/i8259.h>
-#include <asm/mipsregs.h>
-
-#include "smp.h"
-
-extern void loongson3_send_irq_by_ipi(int cpu, int irqs);
-
-unsigned int irq_cpu[16] = {[0 ... 15] = -1};
-unsigned int ht_irq[] = {0, 1, 3, 4, 5, 6, 7, 8, 12, 14, 15};
-unsigned int local_irq = 1<<0 | 1<<1 | 1<<2 | 1<<7 | 1<<8 | 1<<12;
-
-int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity,
-                         bool force)
-{
-       unsigned int cpu;
-       struct cpumask new_affinity;
-
-       /* I/O devices are connected on package-0 */
-       cpumask_copy(&new_affinity, affinity);
-       for_each_cpu(cpu, affinity)
-               if (cpu_data[cpu].package > 0)
-                       cpumask_clear_cpu(cpu, &new_affinity);
-
-       if (cpumask_empty(&new_affinity))
-               return -EINVAL;
-
-       cpumask_copy(d->common->affinity, &new_affinity);
-
-       return IRQ_SET_MASK_OK_NOCOPY;
-}
-
-static void ht_irqdispatch(void)
-{
-       unsigned int i, irq;
-       struct irq_data *irqd;
-       struct cpumask affinity;
-
-       irq = LOONGSON_HT1_INT_VECTOR(0);
-       LOONGSON_HT1_INT_VECTOR(0) = irq; /* Acknowledge the IRQs */
-
-       for (i = 0; i < ARRAY_SIZE(ht_irq); i++) {
-               if (!(irq & (0x1 << ht_irq[i])))
-                       continue;
-
-               /* handled by local core */
-               if (local_irq & (0x1 << ht_irq[i])) {
-                       do_IRQ(ht_irq[i]);
-                       continue;
-               }
-
-               irqd = irq_get_irq_data(ht_irq[i]);
-               cpumask_and(&affinity, irqd->common->affinity, cpu_active_mask);
-               if (cpumask_empty(&affinity)) {
-                       do_IRQ(ht_irq[i]);
-                       continue;
-               }
-
-               irq_cpu[ht_irq[i]] = cpumask_next(irq_cpu[ht_irq[i]], &affinity);
-               if (irq_cpu[ht_irq[i]] >= nr_cpu_ids)
-                       irq_cpu[ht_irq[i]] = cpumask_first(&affinity);
-
-               if (irq_cpu[ht_irq[i]] == 0) {
-                       do_IRQ(ht_irq[i]);
-                       continue;
-               }
-
-               /* balanced by other cores */
-               loongson3_send_irq_by_ipi(irq_cpu[ht_irq[i]], (0x1 << ht_irq[i]));
-       }
-}
-
-#define UNUSED_IPS (CAUSEF_IP5 | CAUSEF_IP4 | CAUSEF_IP1 | CAUSEF_IP0)
-
-asmlinkage void plat_irq_dispatch(void)
-{
-       unsigned int pending;
-
-       pending = read_c0_cause() & read_c0_status() & ST0_IM;
-
-       if (pending & CAUSEF_IP7)
-               do_IRQ(LOONGSON_TIMER_IRQ);
-#if defined(CONFIG_SMP)
-       if (pending & CAUSEF_IP6)
-               loongson3_ipi_interrupt(NULL);
-#endif
-       if (pending & CAUSEF_IP3)
-               ht_irqdispatch();
-       if (pending & CAUSEF_IP2)
-               do_IRQ(LOONGSON_UART_IRQ);
-       if (pending & UNUSED_IPS) {
-               pr_err("%s : spurious interrupt\n", __func__);
-               spurious_interrupt();
-       }
-}
-
-static inline void mask_loongson_irq(struct irq_data *d) { }
-static inline void unmask_loongson_irq(struct irq_data *d) { }
-
- /* For MIPS IRQs which shared by all cores */
-static struct irq_chip loongson_irq_chip = {
-       .name           = "Loongson",
-       .irq_ack        = mask_loongson_irq,
-       .irq_mask       = mask_loongson_irq,
-       .irq_mask_ack   = mask_loongson_irq,
-       .irq_unmask     = unmask_loongson_irq,
-       .irq_eoi        = unmask_loongson_irq,
-};
-
-void irq_router_init(void)
-{
-       int i;
-
-       /* route LPC int to cpu core0 int 0 */
-       LOONGSON_INT_ROUTER_LPC =
-               LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 0);
-       /* route HT1 int0 ~ int7 to cpu core0 INT1*/
-       for (i = 0; i < 8; i++)
-               LOONGSON_INT_ROUTER_HT1(i) =
-                       LOONGSON_INT_COREx_INTy(loongson_sysconf.boot_cpu_id, 1);
-       /* enable HT1 interrupt */
-       LOONGSON_HT1_INTN_EN(0) = 0xffffffff;
-       /* enable router interrupt intenset */
-       LOONGSON_INT_ROUTER_INTENSET =
-               LOONGSON_INT_ROUTER_INTEN | (0xffff << 16) | 0x1 << 10;
-}
-
-void __init arch_init_irq(void)
-{
-       struct irq_chip *chip;
-
-       clear_c0_status(ST0_IM | ST0_BEV);
-
-       irq_router_init();
-       mips_cpu_irq_init();
-       init_i8259_irqs();
-       chip = irq_get_chip(I8259A_IRQ_BASE);
-       chip->irq_set_affinity = plat_set_irq_affinity;
-
-       irq_set_chip_and_handler(LOONGSON_UART_IRQ,
-                       &loongson_irq_chip, handle_percpu_irq);
-       irq_set_chip_and_handler(LOONGSON_BRIDGE_IRQ,
-                       &loongson_irq_chip, handle_percpu_irq);
-
-       set_c0_status(STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP6);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-void fixup_irqs(void)
-{
-       irq_cpu_offline();
-       clear_c0_status(ST0_IM);
-}
-
-#endif
index e5b40c5..1ae072d 100644 (file)
@@ -122,7 +122,7 @@ static unsigned long nid_to_addroffset(unsigned int nid)
 static void __init szmem(unsigned int node)
 {
        u32 i, mem_type;
-       static unsigned long num_physpages = 0;
+       static unsigned long num_physpages;
        u64 node_id, node_psize, start_pfn, end_pfn, mem_start, mem_size;
 
        /* Parse memory information and activate */
index 4fd27f4..6fe3fff 100644 (file)
@@ -8,9 +8,15 @@
 
 #include <asm/wbflush.h>
 #include <asm/bootinfo.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+
+#include <asm/prom.h>
 
 #include <loongson.h>
 
+void *loongson_fdt_blob;
+
 static void wbflush_loongson(void)
 {
        asm(".set\tpush\n\t"
@@ -27,4 +33,14 @@ EXPORT_SYMBOL(__wbflush);
 
 void __init plat_mem_setup(void)
 {
+       if (loongson_fdt_blob)
+               __dt_setup_arch(loongson_fdt_blob);
+}
+
+void __init device_tree_init(void)
+{
+       if (!initial_boot_params)
+               return;
+
+       unflatten_and_copy_device_tree();
 }
index de8e074..e1fe8bb 100644 (file)
@@ -4,6 +4,7 @@
  * Author: Chen Huacai, chenhc@lemote.com
  */
 
+#include <irq.h>
 #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/sched.h>
@@ -25,6 +26,8 @@
 
 DEFINE_PER_CPU(int, cpu_state);
 
+#define LS_IPI_IRQ (MIPS_CPU_IRQ_BASE + 6)
+
 static void *ipi_set0_regs[16];
 static void *ipi_clear0_regs[16];
 static void *ipi_status0_regs[16];
@@ -302,20 +305,13 @@ loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
                ipi_write_action(cpu_logical_map(i), (u32)action);
 }
 
-#define IPI_IRQ_OFFSET 6
-
-void loongson3_send_irq_by_ipi(int cpu, int irqs)
-{
-       ipi_write_action(cpu_logical_map(cpu), irqs << IPI_IRQ_OFFSET);
-}
 
-void loongson3_ipi_interrupt(struct pt_regs *regs)
+static irqreturn_t loongson3_ipi_interrupt(int irq, void *dev_id)
 {
        int i, cpu = smp_processor_id();
-       unsigned int action, c0count, irqs;
+       unsigned int action, c0count;
 
        action = ipi_read_clear(cpu);
-       irqs = action >> IPI_IRQ_OFFSET;
 
        if (action & SMP_RESCHEDULE_YOURSELF)
                scheduler_ipi();
@@ -335,13 +331,7 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
                __wbflush(); /* Let others see the result ASAP */
        }
 
-       if (irqs) {
-               int irq;
-               while ((irq = ffs(irqs))) {
-                       do_IRQ(irq-1);
-                       irqs &= ~(1<<(irq-1));
-               }
-       }
+       return IRQ_HANDLED;
 }
 
 #define MAX_LOOPS 800
@@ -438,6 +428,9 @@ static void __init loongson3_smp_setup(void)
 
 static void __init loongson3_prepare_cpus(unsigned int max_cpus)
 {
+       if (request_irq(LS_IPI_IRQ, loongson3_ipi_interrupt,
+                       IRQF_PERCPU | IRQF_NO_SUSPEND, "SMP_IPI", NULL))
+               pr_err("Failed to request IPI IRQ\n");
        init_cpu_present(cpu_possible_mask);
        per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
 }
@@ -484,7 +477,8 @@ static int loongson3_cpu_disable(void)
        set_cpu_online(cpu, false);
        calculate_cpu_foreign_map();
        local_irq_save(flags);
-       fixup_irqs();
+       irq_cpu_offline();
+       clear_c0_status(ST0_IM);
        local_irq_restore(flags);
        local_flush_tlb_all();
 
index 8064821..4baf965 100644 (file)
@@ -237,17 +237,17 @@ static void probe_octeon(void)
        c->dcache.sets = dcache_size / (c->dcache.linesz * c->dcache.ways);
 
        if (smp_processor_id() == 0) {
-               pr_notice("Primary instruction cache %ldkB, %s, %d way, "
-                         "%d sets, linesize %d bytes.\n",
-                         icache_size >> 10,
-                         cpu_has_vtag_icache ?
+               pr_info("Primary instruction cache %ldkB, %s, %d way, "
+                       "%d sets, linesize %d bytes.\n",
+                       icache_size >> 10,
+                       cpu_has_vtag_icache ?
                                "virtually tagged" : "physically tagged",
-                         c->icache.ways, c->icache.sets, c->icache.linesz);
+                       c->icache.ways, c->icache.sets, c->icache.linesz);
 
-               pr_notice("Primary data cache %ldkB, %d-way, %d sets, "
-                         "linesize %d bytes.\n",
-                         dcache_size >> 10, c->dcache.ways,
-                         c->dcache.sets, c->dcache.linesz);
+               pr_info("Primary data cache %ldkB, %d-way, %d sets, "
+                       "linesize %d bytes.\n",
+                       dcache_size >> 10, c->dcache.ways,
+                       c->dcache.sets, c->dcache.linesz);
        }
 }
 
index 15bb8cf..780dd2a 100644 (file)
@@ -316,9 +316,9 @@ void r3k_cache_init(void)
        _dma_cache_wback = r3k_dma_cache_wback_inv;
        _dma_cache_inv = r3k_dma_cache_wback_inv;
 
-       printk("Primary instruction cache %ldkB, linesize %ld bytes.\n",
+       pr_info("Primary instruction cache %ldkB, linesize %ld bytes.\n",
                icache_size >> 10, icache_lsize);
-       printk("Primary data cache %ldkB, linesize %ld bytes.\n",
+       pr_info("Primary data cache %ldkB, linesize %ld bytes.\n",
                dcache_size >> 10, dcache_lsize);
 
        build_clear_page();
index 5f3d010..36a3113 100644 (file)
@@ -901,6 +901,31 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
        __sync();
 }
 
+static void prefetch_cache_inv(unsigned long addr, unsigned long size)
+{
+       unsigned int linesz = cpu_scache_line_size();
+       unsigned long addr0 = addr, addr1;
+
+       addr0 &= ~(linesz - 1);
+       addr1 = (addr0 + size - 1) & ~(linesz - 1);
+
+       protected_writeback_scache_line(addr0);
+       if (likely(addr1 != addr0))
+               protected_writeback_scache_line(addr1);
+       else
+               return;
+
+       addr0 += linesz;
+       if (likely(addr1 != addr0))
+               protected_writeback_scache_line(addr0);
+       else
+               return;
+
+       addr1 -= linesz;
+       if (likely(addr1 > addr0))
+               protected_writeback_scache_line(addr0);
+}
+
 static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
 {
        /* Catch bad driver code */
@@ -908,6 +933,10 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
                return;
 
        preempt_disable();
+
+       if (current_cpu_type() == CPU_BMIPS5000)
+               prefetch_cache_inv(addr, size);
+
        if (cpu_has_inclusive_pcaches) {
                if (size >= scache_size) {
                        if (current_cpu_type() != CPU_LOONGSON64)
@@ -1467,17 +1496,17 @@ static void probe_pcache(void)
                c->icache.ways = 1;
        }
 
-       printk("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n",
-              icache_size >> 10,
-              c->icache.flags & MIPS_CACHE_VTAG ? "VIVT" : "VIPT",
-              way_string[c->icache.ways], c->icache.linesz);
+       pr_info("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n",
+               icache_size >> 10,
+               c->icache.flags & MIPS_CACHE_VTAG ? "VIVT" : "VIPT",
+               way_string[c->icache.ways], c->icache.linesz);
 
-       printk("Primary data cache %ldkB, %s, %s, %s, linesize %d bytes\n",
-              dcache_size >> 10, way_string[c->dcache.ways],
-              (c->dcache.flags & MIPS_CACHE_PINDEX) ? "PIPT" : "VIPT",
-              (c->dcache.flags & MIPS_CACHE_ALIASES) ?
+       pr_info("Primary data cache %ldkB, %s, %s, %s, linesize %d bytes\n",
+               dcache_size >> 10, way_string[c->dcache.ways],
+               (c->dcache.flags & MIPS_CACHE_PINDEX) ? "PIPT" : "VIPT",
+               (c->dcache.flags & MIPS_CACHE_ALIASES) ?
                        "cache aliases" : "no aliases",
-              c->dcache.linesz);
+               c->dcache.linesz);
 }
 
 static void probe_vcache(void)
index 6868672..2d479cc 100644 (file)
@@ -410,9 +410,9 @@ void tx39_cache_init(void)
        current_cpu_data.icache.waybit = 0;
        current_cpu_data.dcache.waybit = 0;
 
-       printk("Primary instruction cache %ldkB, linesize %d bytes\n",
+       pr_info("Primary instruction cache %ldkB, linesize %d bytes\n",
                icache_size >> 10, current_cpu_data.icache.linesz);
-       printk("Primary data cache %ldkB, linesize %d bytes\n",
+       pr_info("Primary data cache %ldkB, linesize %d bytes\n",
                dcache_size >> 10, current_cpu_data.dcache.linesz);
 
        build_clear_page();
index 344e6e9..da407cd 100644 (file)
@@ -1480,6 +1480,7 @@ static void build_r4000_tlb_refill_handler(void)
 
 static void setup_pw(void)
 {
+       unsigned int pwctl;
        unsigned long pgd_i, pgd_w;
 #ifndef __PAGETABLE_PMD_FOLDED
        unsigned long pmd_i, pmd_w;
@@ -1506,6 +1507,7 @@ static void setup_pw(void)
 
        pte_i = ilog2(_PAGE_GLOBAL);
        pte_w = 0;
+       pwctl = 1 << 30; /* Set PWDirExt */
 
 #ifndef __PAGETABLE_PMD_FOLDED
        write_c0_pwfield(pgd_i << 24 | pmd_i << 12 | pt_i << 6 | pte_i);
@@ -1516,8 +1518,9 @@ static void setup_pw(void)
 #endif
 
 #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
-       write_c0_pwctl(1 << 6 | psn);
+       pwctl |= (1 << 6 | psn);
 #endif
+       write_c0_pwctl(pwctl);
        write_c0_kpgd((long)swapper_pg_dir);
        kscratch_used_mask |= (1 << 7); /* KScratch6 is used for KPGD */
 }
index a840e0c..03d85b2 100644 (file)
@@ -144,12 +144,6 @@ static irqreturn_t corehi_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction corehi_irqaction = {
-       .handler = corehi_handler,
-       .name = "CoreHi",
-       .flags = IRQF_NO_THREAD,
-};
-
 static msc_irqmap_t msc_irqmap[] __initdata = {
        {MSC01C_INT_TMR,                MSC01_IRQ_EDGE, 0},
        {MSC01C_INT_PCI,                MSC01_IRQ_LEVEL, 0},
@@ -223,5 +217,7 @@ void __init arch_init_irq(void)
                corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
        }
 
-       setup_irq(corehi_irq, &corehi_irqaction);
+       if (request_irq(corehi_irq, corehi_handler, IRQF_NO_THREAD, "CoreHi",
+                       NULL))
+               pr_err("Failed to request irq %d (CoreHi)\n", corehi_irq);
 }
index d428e84..d7db153 100644 (file)
@@ -110,12 +110,6 @@ static irqreturn_t fmn_message_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-struct irqaction fmn_irqaction = {
-       .handler = fmn_message_handler,
-       .flags = IRQF_PERCPU,
-       .name = "fmn",
-};
-
 void xlr_percpu_fmn_init(void)
 {
        struct xlr_fmn_info *cpu_fmn_info;
@@ -195,8 +189,9 @@ void nlm_setup_fmn_irq(void)
 {
        uint32_t flags;
 
-       /* setup irq only once */
-       setup_irq(IRQ_FMN, &fmn_irqaction);
+       /* request irq only once */
+       if (request_irq(IRQ_FMN, fmn_message_handler, IRQF_PERCPU, "fmn", NULL))
+               pr_err("Failed to request irq %d (fmn)\n", IRQ_FMN);
 
        flags = nlm_cop2_enable_irqsave();
        nlm_fmn_setup_intr(IRQ_FMN, (1 << nlm_threads_per_core) - 1);
index 905ec1d..7174e9a 100644 (file)
@@ -3,11 +3,11 @@
  * Joshua Henderson <joshua.henderson@microchip.com>
  * Copyright (C) 2015 Microchip Technology Inc.  All rights reserved.
  */
-#include <linux/clk-provider.h>
 #include <linux/clocksource.h>
 #include <linux/init.h>
 #include <linux/irqdomain.h>
 #include <linux/of.h>
+#include <linux/of_clk.h>
 #include <linux/of_irq.h>
 
 #include <asm/time.h>
@@ -23,7 +23,7 @@ static const struct of_device_id pic32_infra_match[] = {
 
 static unsigned int pic32_xlate_core_timer_irq(void)
 {
-       static struct device_node *node;
+       struct device_node *node;
        unsigned int irq;
 
        node = of_find_matching_node(NULL, pic32_infra_match);
index 3c9235c..de64751 100644 (file)
@@ -6,10 +6,10 @@
  */
 
 #include <linux/clk.h>
-#include <linux/clk-provider.h>
 #include <linux/clocksource.h>
 #include <linux/init.h>
 #include <linux/of.h>
+#include <linux/of_clk.h>
 
 #include <asm/mips-cps.h>
 #include <asm/time.h>
index 8d53d7a..d525cc9 100644 (file)
@@ -107,18 +107,6 @@ asmlinkage void plat_irq_dispatch(void)
                do_IRQ(MSP_INT_SW1);
 }
 
-static struct irqaction cic_cascade_msp = {
-       .handler = no_action,
-       .name    = "MSP CIC cascade",
-       .flags   = IRQF_NO_THREAD,
-};
-
-static struct irqaction per_cascade_msp = {
-       .handler = no_action,
-       .name    = "MSP PER cascade",
-       .flags   = IRQF_NO_THREAD,
-};
-
 void __init arch_init_irq(void)
 {
        /* assume we'll be using vectored interrupt mode except in UP mode*/
@@ -142,8 +130,12 @@ void __init arch_init_irq(void)
 #endif /* CONFIG_MIPS_MT_SMP */
 #endif /* CONFIG_MIPS_MT */
        /* setup the cascaded interrupts */
-       setup_irq(MSP_INT_CIC, &cic_cascade_msp);
-       setup_irq(MSP_INT_PER, &per_cascade_msp);
+       if (request_irq(MSP_INT_CIC, no_action, IRQF_NO_THREAD,
+                       "MSP CIC cascade", NULL))
+               pr_err("Failed to register MSP CIC cascade interrupt\n");
+       if (request_irq(MSP_INT_PER, no_action, IRQF_NO_THREAD,
+                       "MSP PER cascade", NULL))
+               pr_err("Failed to register MSP PER cascade interrupt\n");
 
 #else
        /*
@@ -153,7 +145,11 @@ void __init arch_init_irq(void)
        msp_slp_irq_init();
 
        /* setup the cascaded SLP/PER interrupts */
-       setup_irq(MSP_INT_SLP, &cic_cascade_msp);
-       setup_irq(MSP_INT_PER, &per_cascade_msp);
+       if (request_irq(MSP_INT_SLP, no_action, IRQF_NO_THREAD,
+                       "MSP CIC cascade", NULL))
+               pr_err("Failed to register MSP CIC cascade interrupt\n");
+       if (request_irq(MSP_INT_PER, no_action, IRQF_NO_THREAD,
+                       "MSP PER cascade", NULL))
+               pr_err("Failed to register MSP PER cascade interrupt\n");
 #endif
 }
index 8f00d26..00092e2 100644 (file)
@@ -38,21 +38,10 @@ static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction irq_resched = {
-       .handler        = ipi_resched_interrupt,
-       .flags          = IRQF_PERCPU,
-       .name           = "IPI_resched"
-};
-
-static struct irqaction irq_call = {
-       .handler        = ipi_call_interrupt,
-       .flags          = IRQF_PERCPU,
-       .name           = "IPI_call"
-};
-
-void __init arch_init_ipiirq(int irq, struct irqaction *action)
+void __init arch_init_ipiirq(int irq, const char *name, irq_handler_t handler)
 {
-       setup_irq(irq, action);
+       if (request_irq(irq, handler, IRQF_PERCPU, name, NULL))
+               pr_err("Failed to request irq %d (%s)\n", irq, name);
        irq_set_handler(irq, handle_percpu_irq);
 }
 
@@ -60,7 +49,8 @@ void __init msp_vsmp_int_init(void)
 {
        set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
        set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
-       arch_init_ipiirq(MIPS_CPU_IPI_RESCHED_IRQ, &irq_resched);
-       arch_init_ipiirq(MIPS_CPU_IPI_CALL_IRQ, &irq_call);
+       arch_init_ipiirq(MIPS_CPU_IPI_RESCHED_IRQ, "IPI_resched",
+                        ipi_resched_interrupt);
+       arch_init_ipiirq(MIPS_CPU_IPI_CALL_IRQ, "IPI_call", ipi_call_interrupt);
 }
 #endif /* CONFIG_MIPS_MT_SMP */
index d83de01..9c62982 100644 (file)
@@ -27,7 +27,6 @@
 #define get_current_vpe()   \
        ((read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE)
 
-static struct irqaction timer_vpe1;
 static int tim_installed;
 
 void __init plat_time_init(void)
@@ -77,10 +76,13 @@ void __init plat_time_init(void)
 
 unsigned int get_c0_compare_int(void)
 {
+       unsigned long flags = IRQF_PERCPU | IRQF_TIMER | IRQF_SHARED;
+
        /* MIPS_MT modes may want timer for second VPE */
        if ((get_current_vpe()) && !tim_installed) {
-               memcpy(&timer_vpe1, &c0_compare_irqaction, sizeof(timer_vpe1));
-               setup_irq(MSP_INT_VPE1_TIMER, &timer_vpe1);
+               if (request_irq(MSP_INT_VPE1_TIMER, c0_compare_interrupt, flags,
+                               "timer", c0_compare_interrupt))
+                       pr_err("Failed to register timer interrupt\n");
                tim_installed++;
        }
 
index 94e9ce9..35c2ebd 100644 (file)
@@ -52,6 +52,7 @@ choice
                select COMMON_CLK
                select CLKSRC_MIPS_GIC
                select HAVE_PCI if PCI_MT7621
+               select SOC_BUS
 endchoice
 
 choice
index 61a0894..269d487 100644 (file)
@@ -82,12 +82,6 @@ static struct systick_device systick = {
        },
 };
 
-static struct irqaction systick_irqaction = {
-       .handler = systick_interrupt,
-       .flags = IRQF_PERCPU | IRQF_TIMER,
-       .dev_id = &systick.dev,
-};
-
 static int systick_shutdown(struct clock_event_device *evt)
 {
        struct systick_device *sdev;
@@ -95,7 +89,7 @@ static int systick_shutdown(struct clock_event_device *evt)
        sdev = container_of(evt, struct systick_device, dev);
 
        if (sdev->irq_requested)
-               free_irq(systick.dev.irq, &systick_irqaction);
+               free_irq(systick.dev.irq, &systick.dev);
        sdev->irq_requested = 0;
        iowrite32(0, systick.membase + SYSTICK_CONFIG);
 
@@ -104,12 +98,17 @@ static int systick_shutdown(struct clock_event_device *evt)
 
 static int systick_set_oneshot(struct clock_event_device *evt)
 {
+       const char *name = systick.dev.name;
        struct systick_device *sdev;
+       int irq = systick.dev.irq;
 
        sdev = container_of(evt, struct systick_device, dev);
 
-       if (!sdev->irq_requested)
-               setup_irq(systick.dev.irq, &systick_irqaction);
+       if (!sdev->irq_requested) {
+               if (request_irq(irq, systick_interrupt,
+                               IRQF_PERCPU | IRQF_TIMER, name, &systick.dev))
+                       pr_err("Failed to request irq %d (%s)\n", irq, name);
+       }
        sdev->irq_requested = 1;
        iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN,
                  systick.membase + SYSTICK_CONFIG);
@@ -125,7 +124,6 @@ static int __init ralink_systick_init(struct device_node *np)
        if (!systick.membase)
                return -ENXIO;
 
-       systick_irqaction.name = np->name;
        systick.dev.name = np->name;
        clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
        systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
index 9415be0..0accb80 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
 
 #include <asm/mipsregs.h>
 #include <asm/smp-ops.h>
@@ -160,6 +162,33 @@ void __init ralink_of_remap(void)
                panic("Failed to remap core resources");
 }
 
+static void soc_dev_init(struct ralink_soc_info *soc_info, u32 rev)
+{
+       struct soc_device *soc_dev;
+       struct soc_device_attribute *soc_dev_attr;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return;
+
+       soc_dev_attr->soc_id = "mt7621";
+       soc_dev_attr->family = "Ralink";
+
+       if (((rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK) == 1 &&
+           (rev & CHIP_REV_ECO_MASK) == 1)
+               soc_dev_attr->revision = "E2";
+       else
+               soc_dev_attr->revision = "E1";
+
+       soc_dev_attr->data = soc_info;
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev)) {
+               kfree(soc_dev_attr);
+               return;
+       }
+}
+
 void prom_soc_init(struct ralink_soc_info *soc_info)
 {
        void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
@@ -214,6 +243,7 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
 
        rt2880_pinmux_data = mt7621_pinmux_data;
 
+       soc_dev_init(soc_info, rev);
 
        if (!register_cps_smp_ops())
                return;
index 944fbe0..dcf2a44 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/init.h>
 
 #include <linux/of.h>
-#include <linux/clk-provider.h>
+#include <linux/of_clk.h>
 #include <linux/clocksource.h>
 
 #include "common.h"
index a0a7922..f3b0e90 100644 (file)
@@ -92,11 +92,6 @@ static irqreturn_t ip22_eisa_intr(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-static struct irqaction eisa_action = {
-       .handler        = ip22_eisa_intr,
-       .name           = "EISA",
-};
-
 int __init ip22_eisa_init(void)
 {
        int i, c;
@@ -136,9 +131,8 @@ int __init ip22_eisa_init(void)
 
        init_i8259_irqs();
 
-       /* Cannot use request_irq because of kmalloc not being ready at such
-        * an early stage. Yes, I've been bitten... */
-       setup_irq(SGI_EISA_IRQ, &eisa_action);
+       if (request_irq(SGI_EISA_IRQ, ip22_eisa_intr, 0, "EISA", NULL))
+               pr_err("Failed to request irq %d (EISA)\n", SGI_EISA_IRQ);
 
        EISA_bus = 1;
        return 0;
index 3804895..96798a4 100644 (file)
@@ -159,36 +159,7 @@ static void __irq_entry indy_buserror_irq(void)
        irq_exit();
 }
 
-static struct irqaction local0_cascade = {
-       .handler        = no_action,
-       .flags          = IRQF_NO_THREAD,
-       .name           = "local0 cascade",
-};
-
-static struct irqaction local1_cascade = {
-       .handler        = no_action,
-       .flags          = IRQF_NO_THREAD,
-       .name           = "local1 cascade",
-};
-
-static struct irqaction buserr = {
-       .handler        = no_action,
-       .flags          = IRQF_NO_THREAD,
-       .name           = "Bus Error",
-};
-
-static struct irqaction map0_cascade = {
-       .handler        = no_action,
-       .flags          = IRQF_NO_THREAD,
-       .name           = "mapable0 cascade",
-};
-
 #ifdef USE_LIO3_IRQ
-static struct irqaction map1_cascade = {
-       .handler        = no_action,
-       .flags          = IRQF_NO_THREAD,
-       .name           = "mapable1 cascade",
-};
 #define SGI_INTERRUPTS SGINT_END
 #else
 #define SGI_INTERRUPTS SGINT_LOCAL3
@@ -322,14 +293,24 @@ void __init arch_init_irq(void)
        }
 
        /* vector handler. this register the IRQ as non-sharable */
-       setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade);
-       setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade);
-       setup_irq(SGI_BUSERR_IRQ, &buserr);
+       if (request_irq(SGI_LOCAL_0_IRQ, no_action, IRQF_NO_THREAD,
+                       "local0 cascade", NULL))
+               pr_err("Failed to register local0 cascade interrupt\n");
+       if (request_irq(SGI_LOCAL_1_IRQ, no_action, IRQF_NO_THREAD,
+                       "local1 cascade", NULL))
+               pr_err("Failed to register local1 cascade interrupt\n");
+       if (request_irq(SGI_BUSERR_IRQ, no_action, IRQF_NO_THREAD,
+                       "Bus Error", NULL))
+               pr_err("Failed to register Bus Error interrupt\n");
 
        /* cascade in cascade. i love Indy ;-) */
-       setup_irq(SGI_MAP_0_IRQ, &map0_cascade);
+       if (request_irq(SGI_MAP_0_IRQ, no_action, IRQF_NO_THREAD,
+                       "mapable0 cascade", NULL))
+               pr_err("Failed to register mapable0 cascade interrupt\n");
 #ifdef USE_LIO3_IRQ
-       setup_irq(SGI_MAP_1_IRQ, &map1_cascade);
+       if (request_irq(SGI_MAP_1_IRQ, no_action, IRQF_NO_THREAD,
+                       "mapable1 cascade", NULL))
+               pr_err("Failed to register mapable1 cascade interrupt\n");
 #endif
 
 #ifdef CONFIG_EISA
index a6a0ff7..1bbd5bf 100644 (file)
@@ -111,16 +111,6 @@ static inline void flush_mace_bus(void)
 extern irqreturn_t crime_memerr_intr(int irq, void *dev_id);
 extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
 
-static struct irqaction memerr_irq = {
-       .handler = crime_memerr_intr,
-       .name = "CRIME memory error",
-};
-
-static struct irqaction cpuerr_irq = {
-       .handler = crime_cpuerr_intr,
-       .name = "CRIME CPU error",
-};
-
 /*
  * This is for pure CRIME interrupts - ie not MACE.  The advantage?
  * We get to split the register in half and do faster lookups.
@@ -497,8 +487,12 @@ void __init arch_init_irq(void)
                        break;
                }
        }
-       setup_irq(CRIME_MEMERR_IRQ, &memerr_irq);
-       setup_irq(CRIME_CPUERR_IRQ, &cpuerr_irq);
+       if (request_irq(CRIME_MEMERR_IRQ, crime_memerr_intr, 0,
+                       "CRIME memory error", NULL))
+               pr_err("Failed to register CRIME memory error interrupt\n");
+       if (request_irq(CRIME_CPUERR_IRQ, crime_cpuerr_intr, 0,
+                       "CRIME CPU error", NULL))
+               pr_err("Failed to register CRIME CPU error interrupt\n");
 
 #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
        change_c0_status(ST0_IM, ALLINTS);
index f9407e1..0ecffb6 100644 (file)
@@ -222,7 +222,9 @@ void __init sni_a20r_irq_init(void)
                irq_set_chip_and_handler(i, &a20r_irq_type, handle_level_irq);
        sni_hwint = a20r_hwint;
        change_c0_status(ST0_IM, IE_IRQ0);
-       setup_irq(SNI_A20R_IRQ_BASE + 3, &sni_isa_irq);
+       if (request_irq(SNI_A20R_IRQ_BASE + 3, sni_isa_irq_handler, 0, "ISA",
+                       NULL))
+               pr_err("Failed to register ISA interrupt\n");
 }
 
 void sni_a20r_init(void)
index ac61b90..dec89af 100644 (file)
@@ -27,7 +27,7 @@ asmlinkage void plat_irq_dispatch(void)
 }
 
 /* ISA irq handler */
-static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
+irqreturn_t sni_isa_irq_handler(int dummy, void *p)
 {
        int irq;
 
@@ -39,12 +39,6 @@ static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
        return IRQ_HANDLED;
 }
 
-struct irqaction sni_isa_irq = {
-       .handler = sni_isa_irq_handler,
-       .name = "ISA",
-       .flags = IRQF_SHARED
-};
-
 /*
  * On systems with i8259-style interrupt controllers we assume for
  * driver compatibility reasons interrupts 0 - 15 to be the i8295
index 05bb516..b331fe2 100644 (file)
@@ -244,7 +244,9 @@ void __init sni_pcit_irq_init(void)
        *(volatile u32 *)SNI_PCIT_INT_REG = 0;
        sni_hwint = sni_pcit_hwint;
        change_c0_status(ST0_IM, IE_IRQ1);
-       setup_irq(SNI_PCIT_INT_START + 6, &sni_isa_irq);
+       if (request_irq(SNI_PCIT_INT_START + 6, sni_isa_irq_handler, 0, "ISA",
+                       NULL))
+               pr_err("Failed to register ISA interrupt\n");
 }
 
 void __init sni_pcit_cplus_irq_init(void)
@@ -257,7 +259,9 @@ void __init sni_pcit_cplus_irq_init(void)
        *(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000;
        sni_hwint = sni_pcit_hwint_cplus;
        change_c0_status(ST0_IM, IE_IRQ0);
-       setup_irq(MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq);
+       if (request_irq(MIPS_CPU_IRQ_BASE + 3, sni_isa_irq_handler, 0, "ISA",
+                       NULL))
+               pr_err("Failed to register ISA interrupt\n");
 }
 
 void __init sni_pcit_init(void)
index f6fa9af..d84744c 100644 (file)
@@ -356,11 +356,6 @@ void sni_rm200_init_8259A(void)
 /*
  * IRQ2 is cascade interrupt to second interrupt controller
  */
-static struct irqaction sni_rm200_irq2 = {
-       .handler = no_action,
-       .name = "cascade",
-       .flags = IRQF_NO_THREAD,
-};
 
 static struct resource sni_rm200_pic1_resource = {
        .name = "onboard ISA pic1",
@@ -389,12 +384,6 @@ static irqreturn_t sni_rm200_i8259A_irq_handler(int dummy, void *p)
        return IRQ_HANDLED;
 }
 
-struct irqaction sni_rm200_i8259A_irq = {
-       .handler = sni_rm200_i8259A_irq_handler,
-       .name = "onboard ISA",
-       .flags = IRQF_SHARED
-};
-
 void __init sni_rm200_i8259_irqs(void)
 {
        int i;
@@ -417,7 +406,9 @@ void __init sni_rm200_i8259_irqs(void)
                irq_set_chip_and_handler(i, &sni_rm200_i8259A_chip,
                                         handle_level_irq);
 
-       setup_irq(RM200_I8259A_IRQ_BASE + PIC_CASCADE_IR, &sni_rm200_irq2);
+       if (request_irq(RM200_I8259A_IRQ_BASE + PIC_CASCADE_IR, no_action,
+                       IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to register cascade interrupt\n");
 }
 
 
@@ -481,8 +472,12 @@ void __init sni_rm200_irq_init(void)
                irq_set_chip_and_handler(i, &rm200_irq_type, handle_level_irq);
        sni_hwint = sni_rm200_hwint;
        change_c0_status(ST0_IM, IE_IRQ0);
-       setup_irq(SNI_RM200_INT_START + 0, &sni_rm200_i8259A_irq);
-       setup_irq(SNI_RM200_INT_START + 1, &sni_isa_irq);
+       if (request_irq(SNI_RM200_INT_START + 0, sni_rm200_i8259A_irq_handler,
+                       0, "onboard ISA", NULL))
+               pr_err("Failed to register onboard ISA interrupt\n");
+       if (request_irq(SNI_RM200_INT_START + 1, sni_isa_irq_handler, 0, "ISA",
+                       NULL))
+               pr_err("Failed to register ISA interrupt\n");
 }
 
 void __init sni_rm200_init(void)
index dbace1f..240bb68 100644 (file)
@@ -55,12 +55,6 @@ static irqreturn_t a20r_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction a20r_irqaction = {
-       .handler        = a20r_interrupt,
-       .flags          = IRQF_PERCPU | IRQF_TIMER,
-       .name           = "a20r-timer",
-};
-
 /*
  * a20r platform uses 2 counters to divide the input frequency.
  * Counter 2 output is connected to Counter 0 & 1 input.
@@ -68,13 +62,13 @@ static struct irqaction a20r_irqaction = {
 static void __init sni_a20r_timer_setup(void)
 {
        struct clock_event_device *cd = &a20r_clockevent_device;
-       struct irqaction *action = &a20r_irqaction;
        unsigned int cpu = smp_processor_id();
 
        cd->cpumask             = cpumask_of(cpu);
        clockevents_register_device(cd);
-       action->dev_id = cd;
-       setup_irq(SNI_A20R_IRQ_TIMER, &a20r_irqaction);
+       if (request_irq(SNI_A20R_IRQ_TIMER, a20r_interrupt,
+                       IRQF_PERCPU | IRQF_TIMER, "a20r-timer", cd))
+               pr_err("Failed to register a20r-timer interrupt\n");
 }
 
 #define SNI_8254_TICK_RATE       1193182UL
index aa89a41..d7fe840 100644 (file)
@@ -33,6 +33,7 @@ endif
 cflags-vdso := $(ccflags-vdso) \
        $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
        -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \
+       -mrelax-pic-calls $(call cc-option, -mexplicit-relocs) \
        -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
        $(call cc-option, -fno-asynchronous-unwind-tables) \
        $(call cc-option, -fno-stack-protector)
@@ -51,6 +52,8 @@ endif
 
 CFLAGS_REMOVE_vgettimeofday.o = -pg
 
+DISABLE_VDSO := n
+
 #
 # For the pre-R6 code in arch/mips/vdso/vdso.h for locating
 # the base address of VDSO, the linker will emit a R_MIPS_PC32
@@ -64,11 +67,24 @@ CFLAGS_REMOVE_vgettimeofday.o = -pg
 ifndef CONFIG_CPU_MIPSR6
   ifeq ($(call ld-ifversion, -lt, 225000000, y),y)
     $(warning MIPS VDSO requires binutils >= 2.25)
-    obj-vdso-y := $(filter-out vgettimeofday.o, $(obj-vdso-y))
-    ccflags-vdso += -DDISABLE_MIPS_VDSO
+    DISABLE_VDSO := y
   endif
 endif
 
+#
+# GCC (at least up to version 9.2) appears to emit function calls that make use
+# of the GOT when targeting microMIPS, which we can't use in the VDSO due to
+# the lack of relocations. As such, we disable the VDSO for microMIPS builds.
+#
+ifdef CONFIG_CPU_MICROMIPS
+  DISABLE_VDSO := y
+endif
+
+ifeq ($(DISABLE_VDSO),y)
+  obj-vdso-y := $(filter-out vgettimeofday.o, $(obj-vdso-y))
+  ccflags-vdso += -DDISABLE_MIPS_VDSO
+endif
+
 # VDSO linker flags.
 VDSO_LDFLAGS := \
        -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1 \
@@ -81,12 +97,18 @@ GCOV_PROFILE := n
 UBSAN_SANITIZE := n
 KCOV_INSTRUMENT := n
 
+# Check that we don't have PIC 'jalr t9' calls left
+quiet_cmd_vdso_mips_check = VDSOCHK $@
+      cmd_vdso_mips_check = if $(OBJDUMP) --disassemble $@ | egrep -h "jalr.*t9" > /dev/null; \
+                      then (echo >&2 "$@: PIC 'jalr t9' calls are not supported"; \
+                            rm -f $@; /bin/false); fi
+
 #
 # Shared build commands.
 #
 
 quiet_cmd_vdsold_and_vdso_check = LD      $@
-      cmd_vdsold_and_vdso_check = $(cmd_vdsold); $(cmd_vdso_check)
+      cmd_vdsold_and_vdso_check = $(cmd_vdsold); $(cmd_vdso_check); $(cmd_vdso_mips_check)
 
 quiet_cmd_vdsold = VDSO    $@
       cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \
index 7a826fb..8f68446 100644 (file)
@@ -17,12 +17,6 @@ typedef struct irq_cascade {
 
 static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
 
-static struct irqaction cascade_irqaction = {
-       .handler        = no_action,
-       .name           = "cascade",
-       .flags          = IRQF_NO_THREAD,
-};
-
 int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int))
 {
        int retval = 0;
@@ -36,7 +30,8 @@ int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int))
        irq_cascade[irq].get_irq = get_irq;
 
        if (get_irq != NULL) {
-               retval = setup_irq(irq, &cascade_irqaction);
+               retval = request_irq(irq, no_action, IRQF_NO_THREAD,
+                                    "cascade", NULL);
                if (retval < 0)
                        irq_cascade[irq].get_irq = NULL;
        }
index 5213c65..4223f47 100644 (file)
@@ -66,8 +66,8 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
        int oldval = 0, ret;
 
-
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
        switch (op) {
        case FUTEX_OP_SET:
                __futex_atomic_op("move %0, %3", ret, oldval, tmp, uaddr,
@@ -93,8 +93,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index 8916ad9..3a9219f 100644 (file)
@@ -11,7 +11,6 @@
 #include <asm/errno.h>
 #include <asm/memory.h>
 #include <asm/types.h>
-#include <linux/mm.h>
 
 #define __asmeq(x, y)  ".ifnc " x "," y " ; .err ; .endif\n\t"
 
index fe894e6..865e9cd 100644 (file)
@@ -35,7 +35,8 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
        int oldval = 0, ret;
 
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -57,8 +58,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index 71034b5..3801a2e 100644 (file)
@@ -79,6 +79,11 @@ config MMU
 config STACK_GROWSUP
        def_bool y
 
+config ARCH_DEFCONFIG
+       string
+       default "arch/parisc/configs/generic-32bit_defconfig" if !64BIT
+       default "arch/parisc/configs/generic-64bit_defconfig" if 64BIT
+
 config GENERIC_LOCKBREAK
        bool
        default y
index dca8f2d..628cd8b 100644 (file)
@@ -34,6 +34,13 @@ CC_ARCHES    = hppa hppa2.0 hppa1.1
 LD_BFD         := elf32-hppa-linux
 endif
 
+# select defconfig based on actual architecture
+ifeq ($(shell uname -m),parisc64)
+       KBUILD_DEFCONFIG := generic-64bit_defconfig
+else
+       KBUILD_DEFCONFIG := generic-32bit_defconfig
+endif
+
 export LD_BFD
 
 ifneq ($(SUBARCH),$(UTS_MACHINE))
index d2c3e41..c459f65 100644 (file)
@@ -40,7 +40,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
        u32 tmp;
 
        _futex_spin_lock_irqsave(uaddr, &flags);
-       pagefault_disable();
 
        ret = -EFAULT;
        if (unlikely(get_user(oldval, uaddr) != 0))
@@ -73,7 +72,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -EFAULT;
 
 out_pagefault_enable:
-       pagefault_enable();
        _futex_spin_unlock_irqrestore(uaddr, &flags);
 
        if (!ret)
index 13f771f..7f2d0c0 100644 (file)
@@ -212,7 +212,7 @@ static int __init processor_probe(struct parisc_device *dev)
 #ifdef CONFIG_SMP
        if (cpuid) {
                set_cpu_present(cpuid, true);
-               cpu_up(cpuid);
+               add_cpu(cpuid);
        }
 #endif
 
index 497b7d0..6f40af2 100644 (file)
@@ -182,6 +182,7 @@ config PPC
        select HAVE_STACKPROTECTOR              if PPC64 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r13)
        select HAVE_STACKPROTECTOR              if PPC32 && $(cc-option,-mstack-protector-guard=tls -mstack-protector-guard-reg=r2)
        select HAVE_CONTEXT_TRACKING            if PPC64
+       select HAVE_TIF_NOHZ                    if PPC64
        select HAVE_COPY_THREAD_TLS
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DEBUG_STACKOVERFLOW
index bc7d9d0..f187bb5 100644 (file)
@@ -35,8 +35,9 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
 {
        int oldval = 0, ret;
 
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
        allow_read_write_user(uaddr, uaddr, sizeof(*uaddr));
-       pagefault_disable();
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -58,8 +59,6 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        *oval = oldval;
 
        prevent_read_write_user(uaddr, uaddr, sizeof(*uaddr));
index e745abc..245be4f 100644 (file)
@@ -2193,11 +2193,13 @@ static struct cpu_spec * __init setup_cpu_spec(unsigned long offset,
                 * oprofile_cpu_type already has a value, then we are
                 * possibly overriding a real PVR with a logical one,
                 * and, in that case, keep the current value for
-                * oprofile_cpu_type.
+                * oprofile_cpu_type. Futhermore, let's ensure that the
+                * fix for the PMAO bug is enabled on compatibility mode.
                 */
                if (old.oprofile_cpu_type != NULL) {
                        t->oprofile_cpu_type = old.oprofile_cpu_type;
                        t->oprofile_type = old.oprofile_type;
+                       t->cpu_features |= old.cpu_features & CPU_FTR_PMAO_BUG;
                }
        }
 
index 2462cd7..d085432 100644 (file)
@@ -331,11 +331,13 @@ int hw_breakpoint_handler(struct die_args *args)
        }
 
        info->type &= ~HW_BRK_TYPE_EXTRANEOUS_IRQ;
-       if (!dar_within_range(regs->dar, info))
-               info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
-
-       if (!IS_ENABLED(CONFIG_PPC_8xx) && !stepping_handler(regs, bp, info))
-               goto out;
+       if (IS_ENABLED(CONFIG_PPC_8xx)) {
+               if (!dar_within_range(regs->dar, info))
+                       info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
+       } else {
+               if (!stepping_handler(regs, bp, info))
+                       goto out;
+       }
 
        /*
         * As a policy, the callback is invoked in a 'trigger-after-execute'
index b4c89a1..a32d478 100644 (file)
@@ -303,6 +303,12 @@ SECTIONS
                *(.branch_lt)
        }
 
+#ifdef CONFIG_DEBUG_INFO_BTF
+       .BTF : AT(ADDR(.BTF) - LOAD_OFFSET) {
+               *(.BTF)
+       }
+#endif
+
        .opd : AT(ADDR(.opd) - LOAD_OFFSET) {
                __start_opd = .;
                KEEP(*(.opd))
index 04a7cba..b418409 100644 (file)
@@ -212,7 +212,7 @@ static void wake_offline_cpus(void)
                if (!cpu_online(cpu)) {
                        printk(KERN_INFO "kexec: Waking offline cpu %d.\n",
                               cpu);
-                       WARN_ON(cpu_up(cpu));
+                       WARN_ON(add_cpu(cpu));
                }
        }
 }
index 729a0f1..db3a873 100644 (file)
@@ -1817,6 +1817,7 @@ static void kvmppc_core_vcpu_free_pr(struct kvm_vcpu *vcpu)
 {
        struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
 
+       kvmppc_mmu_destroy_pr(vcpu);
        free_page((unsigned long)vcpu->arch.shared & PAGE_MASK);
 #ifdef CONFIG_KVM_BOOK3S_32_HANDLER
        kfree(vcpu->arch.shadow_vcpu);
index 1af96fb..302e9dc 100644 (file)
@@ -759,7 +759,6 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        return 0;
 
 out_vcpu_uninit:
-       kvmppc_mmu_destroy(vcpu);
        kvmppc_subarch_vcpu_uninit(vcpu);
        return err;
 }
@@ -792,7 +791,6 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 
        kvmppc_core_vcpu_free(vcpu);
 
-       kvmppc_mmu_destroy(vcpu);
        kvmppc_subarch_vcpu_uninit(vcpu);
 }
 
index db5664d..d2bed3f 100644 (file)
@@ -120,12 +120,6 @@ static void __init kasan_unmap_early_shadow_vmalloc(void)
        unsigned long k_cur;
        phys_addr_t pa = __pa(kasan_early_shadow_page);
 
-       if (!early_mmu_has_feature(MMU_FTR_HPTE_TABLE)) {
-               int ret = kasan_init_shadow_page_tables(k_start, k_end);
-
-               if (ret)
-                       panic("kasan: kasan_init_shadow_page_tables() failed");
-       }
        for (k_cur = k_start & PAGE_MASK; k_cur < k_end; k_cur += PAGE_SIZE) {
                pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur);
                pte_t *ptep = pte_offset_kernel(pmd, k_cur);
@@ -143,7 +137,8 @@ void __init kasan_mmu_init(void)
        int ret;
        struct memblock_region *reg;
 
-       if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE)) {
+       if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE) ||
+           IS_ENABLED(CONFIG_KASAN_VMALLOC)) {
                ret = kasan_init_shadow_page_tables(KASAN_SHADOW_START, KASAN_SHADOW_END);
 
                if (ret)
index ef7b111..1c07d5a 100644 (file)
@@ -373,7 +373,9 @@ static inline bool flush_coherent_icache(unsigned long addr)
         */
        if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
                mb(); /* sync */
+               allow_read_from_user((const void __user *)addr, L1_CACHE_BYTES);
                icbi((void *)addr);
+               prevent_read_from_user((const void __user *)addr, L1_CACHE_BYTES);
                mb(); /* sync */
                isync();
                return true;
index 3086055..3dcfecf 100644 (file)
@@ -518,6 +518,7 @@ static void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *
                }
        }
        cpuhw->bhrb_stack.nr = u_index;
+       cpuhw->bhrb_stack.hw_idx = -1ULL;
        return;
 }
 
index 2735ec9..e87360a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/reboot.h>
+#include <linux/rcuwait.h>
 
 #include <asm/firmware.h>
 #include <asm/lv1call.h>
@@ -670,7 +671,8 @@ struct ps3_notification_device {
        spinlock_t lock;
        u64 tag;
        u64 lv1_status;
-       struct completion done;
+       struct rcuwait wait;
+       bool done;
 };
 
 enum ps3_notify_type {
@@ -712,7 +714,8 @@ static irqreturn_t ps3_notification_interrupt(int irq, void *data)
                pr_debug("%s:%u: completed, status 0x%llx\n", __func__,
                         __LINE__, status);
                dev->lv1_status = status;
-               complete(&dev->done);
+               dev->done = true;
+               rcuwait_wake_up(&dev->wait);
        }
        spin_unlock(&dev->lock);
        return IRQ_HANDLED;
@@ -725,12 +728,12 @@ static int ps3_notification_read_write(struct ps3_notification_device *dev,
        unsigned long flags;
        int res;
 
-       init_completion(&dev->done);
        spin_lock_irqsave(&dev->lock, flags);
        res = write ? lv1_storage_write(dev->sbd.dev_id, 0, 0, 1, 0, lpar,
                                        &dev->tag)
                    : lv1_storage_read(dev->sbd.dev_id, 0, 0, 1, 0, lpar,
                                       &dev->tag);
+       dev->done = false;
        spin_unlock_irqrestore(&dev->lock, flags);
        if (res) {
                pr_err("%s:%u: %s failed %d\n", __func__, __LINE__, op, res);
@@ -738,14 +741,10 @@ static int ps3_notification_read_write(struct ps3_notification_device *dev,
        }
        pr_debug("%s:%u: notification %s issued\n", __func__, __LINE__, op);
 
-       res = wait_event_interruptible(dev->done.wait,
-                                      dev->done.done || kthread_should_stop());
+       rcuwait_wait_event(&dev->wait, dev->done || kthread_should_stop(), TASK_IDLE);
+
        if (kthread_should_stop())
                res = -EINTR;
-       if (res) {
-               pr_debug("%s:%u: interrupted %s\n", __func__, __LINE__, op);
-               return res;
-       }
 
        if (dev->lv1_status) {
                pr_err("%s:%u: %s not completed, status 0x%llx\n", __func__,
@@ -810,6 +809,7 @@ static int ps3_probe_thread(void *data)
        }
 
        spin_lock_init(&dev.lock);
+       rcuwait_init(&dev.wait);
 
        res = request_irq(irq, ps3_notification_interrupt, 0,
                          "ps3_notification", &dev);
index 73f029e..cd5db57 100644 (file)
@@ -50,7 +50,6 @@ config RISCV
        select PCI_DOMAINS_GENERIC if PCI
        select PCI_MSI if PCI
        select RISCV_TIMER
-       select UACCESS_MEMCPY if !MMU
        select GENERIC_IRQ_MULTI_HANDLER
        select GENERIC_ARCH_TOPOLOGY if SMP
        select ARCH_HAS_PTE_SPECIAL
@@ -121,6 +120,7 @@ config ARCH_FLATMEM_ENABLE
 
 config ARCH_SPARSEMEM_ENABLE
        def_bool y
+       depends on MMU
        select SPARSEMEM_VMEMMAP_ENABLE
 
 config ARCH_SELECT_MEMORY_MODEL
index d325b67..a131174 100644 (file)
@@ -10,4 +10,14 @@ config SOC_SIFIVE
        help
          This enables support for SiFive SoC platform hardware.
 
+config SOC_VIRT
+       bool "QEMU Virt Machine"
+       select POWER_RESET_SYSCON
+       select POWER_RESET_SYSCON_POWEROFF
+       select GOLDFISH
+       select RTC_DRV_GOLDFISH
+       select SIFIVE_PLIC
+       help
+         This enables support for QEMU Virt Machine.
+
 endmenu
index b9009a2..259cb53 100644 (file)
@@ -13,8 +13,10 @@ LDFLAGS_vmlinux :=
 ifeq ($(CONFIG_DYNAMIC_FTRACE),y)
        LDFLAGS_vmlinux := --no-relax
 endif
-KBUILD_AFLAGS_MODULE += -fPIC
-KBUILD_CFLAGS_MODULE += -fPIC
+
+ifeq ($(CONFIG_64BIT)$(CONFIG_CMODEL_MEDLOW),yy)
+KBUILD_CFLAGS_MODULE += -mcmodel=medany
+endif
 
 export BITS
 ifeq ($(CONFIG_ARCH_RV64I),y)
index 8dab0bb..8a45a37 100644 (file)
@@ -1,2 +1,4 @@
 Image
 Image.gz
+loader
+loader.lds
index 609198c..4a2729f 100644 (file)
@@ -2,6 +2,7 @@
 /* Copyright (c) 2018-2019 SiFive, Inc */
 
 #include "fu540-c000.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 /* Clock frequency (in Hz) of the PCB crystal for rtcclk */
 #define RTCCLK_FREQ            1000000
                clock-frequency = <RTCCLK_FREQ>;
                clock-output-names = "rtcclk";
        };
+       gpio-restart {
+               compatible = "gpio-restart";
+               gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
+       };
 };
 
 &uart0 {
index e2ff95c..2557c53 100644 (file)
@@ -15,6 +15,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_BPF_SYSCALL=y
 CONFIG_SOC_SIFIVE=y
+CONFIG_SOC_VIRT=y
 CONFIG_SMP=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
@@ -63,6 +64,7 @@ CONFIG_HW_RANDOM_VIRTIO=y
 CONFIG_SPI=y
 CONFIG_SPI_SIFIVE=y
 # CONFIG_PTP_1588_CLOCK is not set
+CONFIG_POWER_RESET=y
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
 CONFIG_DRM_VIRTIO_GPU=y
@@ -78,6 +80,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
 CONFIG_MMC=y
 CONFIG_MMC_SPI=y
+CONFIG_RTC_CLASS=y
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
 CONFIG_VIRTIO_INPUT=y
@@ -102,13 +105,13 @@ CONFIG_CRYPTO_DEV_VIRTIO=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SCHED_STACK_END_CHECK=y
 CONFIG_DEBUG_VM=y
 CONFIG_DEBUG_VM_PGFLAGS=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_PER_CPU_MAPS=y
 CONFIG_SOFTLOCKUP_DETECTOR=y
 CONFIG_WQ_WATCHDOG=y
-CONFIG_SCHED_STACK_END_CHECK=y
 CONFIG_DEBUG_TIMEKEEPING=y
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_SPINLOCK=y
index eb51940..0292879 100644 (file)
@@ -14,6 +14,7 @@ CONFIG_CHECKPOINT_RESTORE=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 CONFIG_BPF_SYSCALL=y
+CONFIG_SOC_VIRT=y
 CONFIG_ARCH_RV32I=y
 CONFIG_SMP=y
 CONFIG_MODULES=y
@@ -61,6 +62,7 @@ CONFIG_VIRTIO_CONSOLE=y
 CONFIG_HW_RANDOM=y
 CONFIG_HW_RANDOM_VIRTIO=y
 # CONFIG_PTP_1588_CLOCK is not set
+CONFIG_POWER_RESET=y
 CONFIG_DRM=y
 CONFIG_DRM_RADEON=y
 CONFIG_DRM_VIRTIO_GPU=y
@@ -74,13 +76,13 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_HCD_PLATFORM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_UAS=y
+CONFIG_RTC_CLASS=y
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO_BALLOON=y
 CONFIG_VIRTIO_INPUT=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_RPMSG_CHAR=y
 CONFIG_RPMSG_VIRTIO=y
-CONFIG_SIFIVE_PLIC=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_AUTOFS4_FS=y
@@ -99,13 +101,13 @@ CONFIG_CRYPTO_DEV_VIRTIO=y
 CONFIG_PRINTK_TIME=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_SCHED_STACK_END_CHECK=y
 CONFIG_DEBUG_VM=y
 CONFIG_DEBUG_VM_PGFLAGS=y
 CONFIG_DEBUG_MEMORY_INIT=y
 CONFIG_DEBUG_PER_CPU_MAPS=y
 CONFIG_SOFTLOCKUP_DETECTOR=y
 CONFIG_WQ_WATCHDOG=y
-CONFIG_SCHED_STACK_END_CHECK=y
 CONFIG_DEBUG_TIMEKEEPING=y
 CONFIG_DEBUG_RT_MUTEXES=y
 CONFIG_DEBUG_SPINLOCK=y
index 6eaa2ee..a279b17 100644 (file)
@@ -15,12 +15,12 @@ static inline void clint_send_ipi_single(unsigned long hartid)
        writel(1, clint_ipi_base + hartid);
 }
 
-static inline void clint_send_ipi_mask(const struct cpumask *hartid_mask)
+static inline void clint_send_ipi_mask(const struct cpumask *mask)
 {
-       int hartid;
+       int cpu;
 
-       for_each_cpu(hartid, hartid_mask)
-               clint_send_ipi_single(hartid);
+       for_each_cpu(cpu, mask)
+               clint_send_ipi_single(cpuid_to_hartid_map(cpu));
 }
 
 static inline void clint_clear_ipi(unsigned long hartid)
index 435b655..8e18d2c 100644 (file)
 #define EXC_LOAD_PAGE_FAULT    13
 #define EXC_STORE_PAGE_FAULT   15
 
+/* PMP configuration */
+#define PMP_R                  0x01
+#define PMP_W                  0x02
+#define PMP_X                  0x04
+#define PMP_A                  0x18
+#define PMP_A_TOR              0x08
+#define PMP_A_NA4              0x10
+#define PMP_A_NAPOT            0x18
+#define PMP_L                  0x80
+
 /* symbolic CSR names: */
 #define CSR_CYCLE              0xc00
 #define CSR_TIME               0xc01
 #define CSR_MCAUSE             0x342
 #define CSR_MTVAL              0x343
 #define CSR_MIP                        0x344
+#define CSR_PMPCFG0            0x3a0
+#define CSR_PMPADDR0           0x3b0
 #define CSR_MHARTID            0xf14
 
 #ifdef CONFIG_RISCV_M_MODE
index fdfaf7f..1b00bad 100644 (file)
@@ -46,7 +46,8 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
 {
        int oldval = 0, ret = 0;
 
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -73,8 +74,6 @@ arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index e430415..393f201 100644 (file)
 #include <asm/tlbflush.h>
 #include <linux/mm_types.h>
 
+#ifdef CONFIG_MMU
+
+#define VMALLOC_SIZE     (KERN_VIRT_SIZE >> 1)
+#define VMALLOC_END      (PAGE_OFFSET - 1)
+#define VMALLOC_START    (PAGE_OFFSET - VMALLOC_SIZE)
+
+#define BPF_JIT_REGION_SIZE    (SZ_128M)
+#define BPF_JIT_REGION_START   (PAGE_OFFSET - BPF_JIT_REGION_SIZE)
+#define BPF_JIT_REGION_END     (VMALLOC_END)
+
+/*
+ * Roughly size the vmemmap space to be large enough to fit enough
+ * struct pages to map half the virtual address space. Then
+ * position vmemmap directly below the VMALLOC region.
+ */
+#define VMEMMAP_SHIFT \
+       (CONFIG_VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)
+#define VMEMMAP_SIZE   BIT(VMEMMAP_SHIFT)
+#define VMEMMAP_END    (VMALLOC_START - 1)
+#define VMEMMAP_START  (VMALLOC_START - VMEMMAP_SIZE)
+
+/*
+ * Define vmemmap for pfn_to_page & page_to_pfn calls. Needed if kernel
+ * is configured with CONFIG_SPARSEMEM_VMEMMAP enabled.
+ */
+#define vmemmap                ((struct page *)VMEMMAP_START)
+
+#define PCI_IO_SIZE      SZ_16M
+#define PCI_IO_END       VMEMMAP_START
+#define PCI_IO_START     (PCI_IO_END - PCI_IO_SIZE)
+
+#define FIXADDR_TOP      PCI_IO_START
+#ifdef CONFIG_64BIT
+#define FIXADDR_SIZE     PMD_SIZE
+#else
+#define FIXADDR_SIZE     PGDIR_SIZE
+#endif
+#define FIXADDR_START    (FIXADDR_TOP - FIXADDR_SIZE)
+
+#endif
+
 #ifdef CONFIG_64BIT
 #include <asm/pgtable-64.h>
 #else
@@ -90,31 +131,6 @@ extern pgd_t swapper_pg_dir[];
 #define __S110 PAGE_SHARED_EXEC
 #define __S111 PAGE_SHARED_EXEC
 
-#define VMALLOC_SIZE     (KERN_VIRT_SIZE >> 1)
-#define VMALLOC_END      (PAGE_OFFSET - 1)
-#define VMALLOC_START    (PAGE_OFFSET - VMALLOC_SIZE)
-
-#define BPF_JIT_REGION_SIZE    (SZ_128M)
-#define BPF_JIT_REGION_START   (PAGE_OFFSET - BPF_JIT_REGION_SIZE)
-#define BPF_JIT_REGION_END     (VMALLOC_END)
-
-/*
- * Roughly size the vmemmap space to be large enough to fit enough
- * struct pages to map half the virtual address space. Then
- * position vmemmap directly below the VMALLOC region.
- */
-#define VMEMMAP_SHIFT \
-       (CONFIG_VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)
-#define VMEMMAP_SIZE   BIT(VMEMMAP_SHIFT)
-#define VMEMMAP_END    (VMALLOC_START - 1)
-#define VMEMMAP_START  (VMALLOC_START - VMEMMAP_SIZE)
-
-/*
- * Define vmemmap for pfn_to_page & page_to_pfn calls. Needed if kernel
- * is configured with CONFIG_SPARSEMEM_VMEMMAP enabled.
- */
-#define vmemmap                ((struct page *)VMEMMAP_START)
-
 static inline int pmd_present(pmd_t pmd)
 {
        return (pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROT_NONE));
@@ -432,18 +448,6 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
 #define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
 
-#define PCI_IO_SIZE      SZ_16M
-#define PCI_IO_END       VMEMMAP_START
-#define PCI_IO_START     (PCI_IO_END - PCI_IO_SIZE)
-
-#define FIXADDR_TOP      PCI_IO_START
-#ifdef CONFIG_64BIT
-#define FIXADDR_SIZE     PMD_SIZE
-#else
-#define FIXADDR_SIZE     PGDIR_SIZE
-#endif
-#define FIXADDR_START    (FIXADDR_TOP - FIXADDR_SIZE)
-
 /*
  * Task size is 0x4000000000 for RV64 or 0x9fc00000 for RV32.
  * Note that PGDIR_SIZE must evenly divide TASK_SIZE.
index 42347d0..49350c8 100644 (file)
@@ -28,13 +28,6 @@ static inline int syscall_get_nr(struct task_struct *task,
        return regs->a7;
 }
 
-static inline void syscall_set_nr(struct task_struct *task,
-                                 struct pt_regs *regs,
-                                 int sysno)
-{
-       regs->a7 = sysno;
-}
-
 static inline void syscall_rollback(struct task_struct *task,
                                    struct pt_regs *regs)
 {
index f462a18..8ce9d60 100644 (file)
 /*
  * User space memory access functions
  */
+
+extern unsigned long __must_check __asm_copy_to_user(void __user *to,
+       const void *from, unsigned long n);
+extern unsigned long __must_check __asm_copy_from_user(void *to,
+       const void __user *from, unsigned long n);
+
+static inline unsigned long
+raw_copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       return __asm_copy_from_user(to, from, n);
+}
+
+static inline unsigned long
+raw_copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       return __asm_copy_to_user(to, from, n);
+}
+
 #ifdef CONFIG_MMU
 #include <linux/errno.h>
 #include <linux/compiler.h>
@@ -367,24 +385,6 @@ do {                                                               \
                -EFAULT;                                        \
 })
 
-
-extern unsigned long __must_check __asm_copy_to_user(void __user *to,
-       const void *from, unsigned long n);
-extern unsigned long __must_check __asm_copy_from_user(void *to,
-       const void __user *from, unsigned long n);
-
-static inline unsigned long
-raw_copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-       return __asm_copy_from_user(to, from, n);
-}
-
-static inline unsigned long
-raw_copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-       return __asm_copy_to_user(to, from, n);
-}
-
 extern long strncpy_from_user(char *dest, const char __user *src, long count);
 
 extern long __must_check strlen_user(const char __user *str);
index bad4d85..208702d 100644 (file)
@@ -229,19 +229,12 @@ check_syscall_nr:
        li t0, __NR_syscalls
        la s0, sys_ni_syscall
        /*
-        * The tracer can change syscall number to valid/invalid value.
-        * We use syscall_set_nr helper in syscall_trace_enter thus we
-        * cannot trust the current value in a7 and have to reload from
-        * the current task pt_regs.
-        */
-       REG_L a7, PT_A7(sp)
-       /*
         * Syscall number held in a7.
         * If syscall number is above allowed value, redirect to ni_syscall.
         */
        bge a7, t0, 1f
        /*
-        * Check if syscall is rejected by tracer or seccomp, i.e., a7 == -1.
+        * Check if syscall is rejected by tracer, i.e., a7 == -1.
         * If yes, we pretend it was executed.
         */
        li t1, -1
@@ -334,6 +327,7 @@ work_resched:
 handle_syscall_trace_enter:
        move a0, sp
        call do_syscall_trace_enter
+       move t0, a0
        REG_L a0, PT_A0(sp)
        REG_L a1, PT_A1(sp)
        REG_L a2, PT_A2(sp)
@@ -342,6 +336,7 @@ handle_syscall_trace_enter:
        REG_L a5, PT_A5(sp)
        REG_L a6, PT_A6(sp)
        REG_L a7, PT_A7(sp)
+       bnez t0, ret_from_syscall_rejected
        j check_syscall_nr
 handle_syscall_trace_exit:
        move a0, sp
index 271860f..85f2073 100644 (file)
@@ -58,6 +58,12 @@ _start_kernel:
        /* Reset all registers except ra, a0, a1 */
        call reset_regs
 
+       /* Setup a PMP to permit access to all of memory. */
+       li a0, -1
+       csrw CSR_PMPADDR0, a0
+       li a0, (PMP_A_NAPOT | PMP_R | PMP_W | PMP_X)
+       csrw CSR_PMPCFG0, a0
+
        /*
         * The hartid in a0 is expected later on, and we have no firmware
         * to hand it to us.
index b740185..8bbe5db 100644 (file)
@@ -8,6 +8,10 @@
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/moduleloader.h>
+#include <linux/vmalloc.h>
+#include <linux/sizes.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
 
 static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
 {
@@ -386,3 +390,15 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 
        return 0;
 }
+
+#if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
+#define VMALLOC_MODULE_START \
+        max(PFN_ALIGN((unsigned long)&_end - SZ_2G), VMALLOC_START)
+void *module_alloc(unsigned long size)
+{
+       return __vmalloc_node_range(size, 1, VMALLOC_MODULE_START,
+                                   VMALLOC_END, GFP_KERNEL,
+                                   PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
+                                   __builtin_return_address(0));
+}
+#endif
index 4074642..444dc7b 100644 (file)
@@ -148,21 +148,19 @@ long arch_ptrace(struct task_struct *child, long request,
  * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
  * {handle,ret_from}_syscall.
  */
-__visible void do_syscall_trace_enter(struct pt_regs *regs)
+__visible int do_syscall_trace_enter(struct pt_regs *regs)
 {
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                if (tracehook_report_syscall_entry(regs))
-                       syscall_set_nr(current, regs, -1);
+                       return -1;
 
        /*
         * Do the secure computing after ptrace; failures should be fast.
         * If this fails we might have return value in a0 from seccomp
         * (via SECCOMP_RET_ERRNO/TRACE).
         */
-       if (secure_computing() == -1) {
-               syscall_set_nr(current, regs, -1);
-               return;
-       }
+       if (secure_computing() == -1)
+               return -1;
 
 #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
@@ -170,6 +168,7 @@ __visible void do_syscall_trace_enter(struct pt_regs *regs)
 #endif
 
        audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3);
+       return 0;
 }
 
 __visible void do_syscall_trace_exit(struct pt_regs *regs)
index eb878ab..e0a6293 100644 (file)
@@ -96,7 +96,7 @@ static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op)
        if (IS_ENABLED(CONFIG_RISCV_SBI))
                sbi_send_ipi(cpumask_bits(&hartid_mask));
        else
-               clint_send_ipi_mask(&hartid_mask);
+               clint_send_ipi_mask(mask);
 }
 
 static void send_ipi_single(int cpu, enum ipi_message_type op)
index f4cad51..55ea614 100644 (file)
@@ -156,6 +156,6 @@ void __init trap_init(void)
        csr_write(CSR_SCRATCH, 0);
        /* Set the exception vector address */
        csr_write(CSR_TVEC, &handle_exception);
-       /* Enable all interrupts */
-       csr_write(CSR_IE, -1);
+       /* Enable interrupts */
+       csr_write(CSR_IE, IE_SIE);
 }
index 47e7a82..0d0db80 100644 (file)
@@ -2,5 +2,5 @@
 lib-y                  += delay.o
 lib-y                  += memcpy.o
 lib-y                  += memset.o
-lib-$(CONFIG_MMU)      += uaccess.o
+lib-y                  += uaccess.o
 lib-$(CONFIG_64BIT)    += tishift.o
index 965a8cf..fab8559 100644 (file)
@@ -131,7 +131,7 @@ void __init setup_bootmem(void)
        for_each_memblock(memory, reg) {
                phys_addr_t end = reg->base + reg->size;
 
-               if (reg->base <= vmlinux_end && vmlinux_end <= end) {
+               if (reg->base <= vmlinux_start && vmlinux_end <= end) {
                        mem_size = min(reg->size, (phys_addr_t)-PAGE_OFFSET);
 
                        /*
index f0cc860..ec0ca90 100644 (file)
@@ -19,18 +19,20 @@ asmlinkage void __init kasan_early_init(void)
        for (i = 0; i < PTRS_PER_PTE; ++i)
                set_pte(kasan_early_shadow_pte + i,
                        mk_pte(virt_to_page(kasan_early_shadow_page),
-                       PAGE_KERNEL));
+                              PAGE_KERNEL));
 
        for (i = 0; i < PTRS_PER_PMD; ++i)
                set_pmd(kasan_early_shadow_pmd + i,
-                pfn_pmd(PFN_DOWN(__pa((uintptr_t)kasan_early_shadow_pte)),
-                       __pgprot(_PAGE_TABLE)));
+                       pfn_pmd(PFN_DOWN
+                               (__pa((uintptr_t) kasan_early_shadow_pte)),
+                               __pgprot(_PAGE_TABLE)));
 
        for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END;
             i += PGDIR_SIZE, ++pgd)
                set_pgd(pgd,
-                pfn_pgd(PFN_DOWN(__pa(((uintptr_t)kasan_early_shadow_pmd))),
-                       __pgprot(_PAGE_TABLE)));
+                       pfn_pgd(PFN_DOWN
+                               (__pa(((uintptr_t) kasan_early_shadow_pmd))),
+                               __pgprot(_PAGE_TABLE)));
 
        /* init for swapper_pg_dir */
        pgd = pgd_offset_k(KASAN_SHADOW_START);
@@ -38,37 +40,43 @@ asmlinkage void __init kasan_early_init(void)
        for (i = KASAN_SHADOW_START; i < KASAN_SHADOW_END;
             i += PGDIR_SIZE, ++pgd)
                set_pgd(pgd,
-                pfn_pgd(PFN_DOWN(__pa(((uintptr_t)kasan_early_shadow_pmd))),
-                       __pgprot(_PAGE_TABLE)));
+                       pfn_pgd(PFN_DOWN
+                               (__pa(((uintptr_t) kasan_early_shadow_pmd))),
+                               __pgprot(_PAGE_TABLE)));
 
        flush_tlb_all();
 }
 
 static void __init populate(void *start, void *end)
 {
-       unsigned long i;
+       unsigned long i, offset;
        unsigned long vaddr = (unsigned long)start & PAGE_MASK;
        unsigned long vend = PAGE_ALIGN((unsigned long)end);
        unsigned long n_pages = (vend - vaddr) / PAGE_SIZE;
+       unsigned long n_ptes =
+           ((n_pages + PTRS_PER_PTE) & -PTRS_PER_PTE) / PTRS_PER_PTE;
        unsigned long n_pmds =
-               (n_pages % PTRS_PER_PTE) ? n_pages / PTRS_PER_PTE + 1 :
-                                               n_pages / PTRS_PER_PTE;
+           ((n_ptes + PTRS_PER_PMD) & -PTRS_PER_PMD) / PTRS_PER_PMD;
+
+       pte_t *pte =
+           memblock_alloc(n_ptes * PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE);
+       pmd_t *pmd =
+           memblock_alloc(n_pmds * PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE);
        pgd_t *pgd = pgd_offset_k(vaddr);
-       pmd_t *pmd = memblock_alloc(n_pmds * sizeof(pmd_t), PAGE_SIZE);
-       pte_t *pte = memblock_alloc(n_pages * sizeof(pte_t), PAGE_SIZE);
 
        for (i = 0; i < n_pages; i++) {
                phys_addr_t phys = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE);
-
-               set_pte(pte + i, pfn_pte(PHYS_PFN(phys), PAGE_KERNEL));
+               set_pte(&pte[i], pfn_pte(PHYS_PFN(phys), PAGE_KERNEL));
        }
 
-       for (i = 0; i < n_pmds; ++pgd, i += PTRS_PER_PMD)
-               set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(((uintptr_t)(pmd + i)))),
+       for (i = 0, offset = 0; i < n_ptes; i++, offset += PTRS_PER_PTE)
+               set_pmd(&pmd[i],
+                       pfn_pmd(PFN_DOWN(__pa(&pte[offset])),
                                __pgprot(_PAGE_TABLE)));
 
-       for (i = 0; i < n_pages; ++pmd, i += PTRS_PER_PTE)
-               set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa((uintptr_t)(pte + i))),
+       for (i = 0, offset = 0; i < n_pmds; i++, offset += PTRS_PER_PMD)
+               set_pgd(&pgd[i],
+                       pfn_pgd(PFN_DOWN(__pa(&pmd[offset])),
                                __pgprot(_PAGE_TABLE)));
 
        flush_tlb_all();
@@ -81,7 +89,8 @@ void __init kasan_init(void)
        unsigned long i;
 
        kasan_populate_early_shadow((void *)KASAN_SHADOW_START,
-                       (void *)kasan_mem_to_shadow((void *)VMALLOC_END));
+                                   (void *)kasan_mem_to_shadow((void *)
+                                                               VMALLOC_END));
 
        for_each_memblock(memory, reg) {
                void *start = (void *)__va(reg->base);
@@ -90,14 +99,14 @@ void __init kasan_init(void)
                if (start >= end)
                        break;
 
-               populate(kasan_mem_to_shadow(start),
-                        kasan_mem_to_shadow(end));
+               populate(kasan_mem_to_shadow(start), kasan_mem_to_shadow(end));
        };
 
        for (i = 0; i < PTRS_PER_PTE; i++)
                set_pte(&kasan_early_shadow_pte[i],
                        mk_pte(virt_to_page(kasan_early_shadow_page),
-                       __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_ACCESSED)));
+                              __pgprot(_PAGE_PRESENT | _PAGE_READ |
+                                       _PAGE_ACCESSED)));
 
        memset(kasan_early_shadow_page, 0, PAGE_SIZE);
        init_task.kasan_depth = 0;
index 5e97a43..26f9144 100644 (file)
@@ -29,7 +29,6 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
        mm_segment_t old_fs;
 
        old_fs = enable_sacf_uaccess();
-       pagefault_disable();
        switch (op) {
        case FUTEX_OP_SET:
                __futex_atomic_op("lr %2,%5\n",
@@ -54,7 +53,6 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
        default:
                ret = -ENOSYS;
        }
-       pagefault_enable();
        disable_sacf_uaccess(old_fs);
 
        if (!ret)
index 137a392..6d7c3b7 100644 (file)
@@ -752,6 +752,12 @@ static inline int pmd_write(pmd_t pmd)
        return (pmd_val(pmd) & _SEGMENT_ENTRY_WRITE) != 0;
 }
 
+#define pud_write pud_write
+static inline int pud_write(pud_t pud)
+{
+       return (pud_val(pud) & _REGION3_ENTRY_WRITE) != 0;
+}
+
 static inline int pmd_dirty(pmd_t pmd)
 {
        return (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) != 0;
index d7ff30e..c2e6d4b 100644 (file)
@@ -3268,7 +3268,10 @@ static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
        /* Initial reset is a superset of the normal reset */
        kvm_arch_vcpu_ioctl_normal_reset(vcpu);
 
-       /* this equals initial cpu reset in pop, but we don't switch to ESA */
+       /*
+        * This equals initial cpu reset in pop, but we don't switch to ESA.
+        * We do not only reset the internal data, but also ...
+        */
        vcpu->arch.sie_block->gpsw.mask = 0;
        vcpu->arch.sie_block->gpsw.addr = 0;
        kvm_s390_set_prefix(vcpu, 0);
@@ -3278,6 +3281,19 @@ static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
        memset(vcpu->arch.sie_block->gcr, 0, sizeof(vcpu->arch.sie_block->gcr));
        vcpu->arch.sie_block->gcr[0] = CR0_INITIAL_MASK;
        vcpu->arch.sie_block->gcr[14] = CR14_INITIAL_MASK;
+
+       /* ... the data in sync regs */
+       memset(vcpu->run->s.regs.crs, 0, sizeof(vcpu->run->s.regs.crs));
+       vcpu->run->s.regs.ckc = 0;
+       vcpu->run->s.regs.crs[0] = CR0_INITIAL_MASK;
+       vcpu->run->s.regs.crs[14] = CR14_INITIAL_MASK;
+       vcpu->run->psw_addr = 0;
+       vcpu->run->psw_mask = 0;
+       vcpu->run->s.regs.todpr = 0;
+       vcpu->run->s.regs.cputm = 0;
+       vcpu->run->s.regs.ckc = 0;
+       vcpu->run->s.regs.pp = 0;
+       vcpu->run->s.regs.gbea = 1;
        vcpu->run->s.regs.fpc = 0;
        vcpu->arch.sie_block->gbea = 1;
        vcpu->arch.sie_block->pp = 0;
index bc61ea1..60716d1 100644 (file)
@@ -424,7 +424,7 @@ static void zpci_map_resources(struct pci_dev *pdev)
 
                if (zpci_use_mio(zdev))
                        pdev->resource[i].start =
-                               (resource_size_t __force) zdev->bars[i].mio_wb;
+                               (resource_size_t __force) zdev->bars[i].mio_wt;
                else
                        pdev->resource[i].start = (resource_size_t __force)
                                pci_iomap_range_fh(pdev, i, 0, 0);
@@ -531,7 +531,7 @@ static int zpci_setup_bus_resources(struct zpci_dev *zdev,
                        flags |= IORESOURCE_MEM_64;
 
                if (zpci_use_mio(zdev))
-                       addr = (unsigned long) zdev->bars[i].mio_wb;
+                       addr = (unsigned long) zdev->bars[i].mio_wt;
                else
                        addr = ZPCI_ADDR(entry);
                size = 1UL << zdev->bars[i].size;
index 3b6ea2d..0305d0b 100644 (file)
@@ -40,16 +40,6 @@ static irqreturn_t cayman_interrupt_pci2(int irq, void *dev_id)
        return IRQ_NONE;
 }
 
-static struct irqaction cayman_action_smsc = {
-       .name           = "Cayman SMSC Mux",
-       .handler        = cayman_interrupt_smsc,
-};
-
-static struct irqaction cayman_action_pci2 = {
-       .name           = "Cayman PCI2 Mux",
-       .handler        = cayman_interrupt_pci2,
-};
-
 static void enable_cayman_irq(struct irq_data *data)
 {
        unsigned int irq = data->irq;
@@ -149,6 +139,10 @@ void init_cayman_irq(void)
        }
 
        /* Setup the SMSC interrupt */
-       setup_irq(SMSC_IRQ, &cayman_action_smsc);
-       setup_irq(PCI2_IRQ, &cayman_action_pci2);
+       if (request_irq(SMSC_IRQ, cayman_interrupt_smsc, 0, "Cayman SMSC Mux",
+                       NULL))
+               pr_err("Failed to register Cayman SMSC Mux interrupt\n");
+       if (request_irq(PCI2_IRQ, cayman_interrupt_pci2, 0, "Cayman PCI2 Mux",
+                       NULL))
+               pr_err("Failed to register Cayman PCI2 Mux interrupt\n");
 }
index b5dbd1f..21c3475 100644 (file)
@@ -64,11 +64,6 @@ static int pvr2_xfer_dma(struct dma_channel *chan)
        return 0;
 }
 
-static struct irqaction pvr2_dma_irq = {
-       .name           = "pvr2 DMA handler",
-       .handler        = pvr2_dma_interrupt,
-};
-
 static struct dma_ops pvr2_dma_ops = {
        .request        = pvr2_request_dma,
        .get_residue    = pvr2_get_dma_residue,
@@ -84,7 +79,9 @@ static struct dma_info pvr2_dma_info = {
 
 static int __init pvr2_dma_init(void)
 {
-       setup_irq(HW_EVENT_PVR2_DMA, &pvr2_dma_irq);
+       if (request_irq(HW_EVENT_PVR2_DMA, pvr2_dma_interrupt, 0,
+                       "pvr2 DMA handler", NULL))
+               pr_err("Failed to register pvr2 DMA handler interrupt\n");
        request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade");
 
        return register_dmac(&pvr2_dma_info);
index 3190ec8..b39cda0 100644 (file)
@@ -34,8 +34,6 @@ static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
        u32 oldval, newval, prev;
        int ret;
 
-       pagefault_disable();
-
        do {
                ret = get_user(oldval, uaddr);
 
@@ -67,8 +65,6 @@ static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
                ret = futex_atomic_cmpxchg_inatomic(&prev, uaddr, oldval, newval);
        } while (!ret && prev != oldval);
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index c1dd6dd..9cc9ab0 100644 (file)
@@ -71,6 +71,7 @@ config SPARC64
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_CONTEXT_TRACKING
+       select HAVE_TIF_NOHZ
        select HAVE_DEBUG_KMEMLEAK
        select IOMMU_HELPER
        select SPARSE_IRQ
index 0865ce7..72de967 100644 (file)
@@ -38,8 +38,6 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
        if (unlikely((((unsigned long) uaddr) & 0x3UL)))
                return -EINVAL;
 
-       pagefault_disable();
-
        switch (op) {
        case FUTEX_OP_SET:
                __futex_cas_op("mov\t%4, %1", ret, oldval, uaddr, oparg);
@@ -60,8 +58,6 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index bbf59b3..75232cb 100644 (file)
@@ -555,7 +555,7 @@ static int dr_cpu_configure(struct ds_info *dp, struct ds_cap_state *cp,
 
                printk(KERN_INFO "ds-%llu: Starting cpu %d...\n",
                       dp->id, cpu);
-               err = cpu_up(cpu);
+               err = add_cpu(cpu);
                if (err) {
                        __u32 res = DR_CPU_RES_FAILURE;
                        __u32 stat = DR_CPU_STAT_UNCONFIGURED;
@@ -611,7 +611,7 @@ static int dr_cpu_unconfigure(struct ds_info *dp,
 
                printk(KERN_INFO "ds-%llu: Shutting down cpu %d...\n",
                       dp->id, cpu);
-               err = cpu_down(cpu);
+               err = remove_cpu(cpu);
                if (err)
                        dr_cpu_mark(resp, cpu, ncpus,
                                    DR_CPU_RES_FAILURE,
index 3ca74e1..bd4e7c3 100644 (file)
@@ -27,7 +27,7 @@ extern void __uc32_iounmap(volatile void __iomem *addr);
  * ioremap and friends.
  *
  * ioremap takes a PCI memory address, as specified in
- * Documentation/io-mapping.txt.
+ * Documentation/driver-api/io-mapping.rst.
  *
  */
 #define ioremap(cookie, size)          __uc32_ioremap(cookie, size)
index 8b217a7..c3a37ed 100644 (file)
@@ -72,13 +72,6 @@ static struct clocksource cksrc_puv3_oscr = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-static struct irqaction puv3_timer_irq = {
-       .name           = "ost0",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = puv3_ost0_interrupt,
-       .dev_id         = &ckevt_puv3_osmr0,
-};
-
 void __init time_init(void)
 {
        writel(0, OST_OIER);            /* disable any timer interrupts */
@@ -94,7 +87,9 @@ void __init time_init(void)
        ckevt_puv3_osmr0.min_delta_ticks = MIN_OSCR_DELTA * 2;
        ckevt_puv3_osmr0.cpumask = cpumask_of(0);
 
-       setup_irq(IRQ_TIMER0, &puv3_timer_irq);
+       if (request_irq(IRQ_TIMER0, puv3_ost0_interrupt,
+                       IRQF_TIMER | IRQF_IRQPOLL, "ost0", &ckevt_puv3_osmr0))
+               pr_err("Failed to register ost0 interrupt\n");
 
        clocksource_register_hz(&cksrc_puv3_oscr, CLOCK_TICK_RATE);
        clockevents_register_device(&ckevt_puv3_osmr0);
index b414192..ade80ca 100644 (file)
@@ -30,7 +30,6 @@ config X86_64
        select MODULES_USE_ELF_RELA
        select NEED_DMA_MAP_STATE
        select SWIOTLB
-       select ARCH_HAS_SYSCALL_WRAPPER
 
 config FORCE_DYNAMIC_FTRACE
        def_bool y
@@ -57,7 +56,6 @@ config X86
        select ACPI_LEGACY_TABLES_LOOKUP        if ACPI
        select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
        select ARCH_32BIT_OFF_T                 if X86_32
-       select ARCH_CLOCKSOURCE_DATA
        select ARCH_CLOCKSOURCE_INIT
        select ARCH_HAS_ACPI_TABLE_UPGRADE      if ACPI
        select ARCH_HAS_DEBUG_VIRTUAL
@@ -80,6 +78,7 @@ config X86
        select ARCH_HAS_STRICT_KERNEL_RWX
        select ARCH_HAS_STRICT_MODULE_RWX
        select ARCH_HAS_SYNC_CORE_BEFORE_USERMODE
+       select ARCH_HAS_SYSCALL_WRAPPER
        select ARCH_HAS_UBSAN_SANITIZE_ALL
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_MIGHT_HAVE_ACPI_PDC         if ACPI
@@ -128,6 +127,7 @@ config X86
        select GENERIC_GETTIMEOFDAY
        select GENERIC_VDSO_TIME_NS
        select GUP_GET_PTE_LOW_HIGH             if X86_PAE
+       select HARDIRQS_SW_RESEND
        select HARDLOCKUP_CHECK_TIMESTAMP       if X86_64
        select HAVE_ACPI_APEI                   if ACPI
        select HAVE_ACPI_APEI_NMI               if ACPI
@@ -1875,7 +1875,6 @@ config X86_SMAP
 
 config X86_UMIP
        def_bool y
-       depends on CPU_SUP_INTEL || CPU_SUP_AMD
        prompt "User Mode Instruction Prevention" if EXPERT
        ---help---
          User Mode Instruction Prevention (UMIP) is a security feature in
index 94df086..513a555 100644 (file)
@@ -194,9 +194,10 @@ avx2_instr :=$(call as-instr,vpbroadcastb %xmm0$(comma)%ymm1,-DCONFIG_AS_AVX2=1)
 avx512_instr :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,-DCONFIG_AS_AVX512=1)
 sha1_ni_instr :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA1_NI=1)
 sha256_ni_instr :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,-DCONFIG_AS_SHA256_NI=1)
+adx_instr := $(call as-instr,adox %r10$(comma)%r10,-DCONFIG_AS_ADX=1)
 
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr)
+KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) $(adx_instr)
+KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) $(avx2_instr) $(avx512_instr) $(sha1_ni_instr) $(sha256_ni_instr) $(adx_instr)
 
 KBUILD_LDFLAGS := -m elf_$(UTS_MACHINE)
 
index 012b82f..e17be90 100644 (file)
@@ -68,6 +68,7 @@ clean-files += cpustr.h
 KBUILD_CFLAGS  := $(REALMODE_CFLAGS) -D_SETUP
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 KBUILD_CFLAGS  += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
+KBUILD_CFLAGS  += -fno-asynchronous-unwind-tables
 GCOV_PROFILE := n
 UBSAN_SANITIZE := n
 
@@ -88,7 +89,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
 
 SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
 
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
 
 quiet_cmd_zoffset = ZOFFSET $@
       cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
index 26050ae..5f7c262 100644 (file)
@@ -39,6 +39,7 @@ KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
 KBUILD_CFLAGS += $(call cc-disable-warning, gnu)
 KBUILD_CFLAGS += -Wno-pointer-sign
 KBUILD_CFLAGS += $(call cc-option,-fmacro-prefix-map=$(srctree)/=)
+KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
 
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 GCOV_PROFILE := n
@@ -87,10 +88,7 @@ endif
 
 vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
 
-$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
-
-vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o \
-       $(objtree)/drivers/firmware/efi/libstub/lib.a
+vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
 vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
 
 # The compressed kernel is built with -fPIC/-fPIE so that a boot loader
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
deleted file mode 100644 (file)
index 99f3534..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef BOOT_COMPRESSED_EBOOT_H
-#define BOOT_COMPRESSED_EBOOT_H
-
-#define SEG_TYPE_DATA          (0 << 3)
-#define SEG_TYPE_READ_WRITE    (1 << 1)
-#define SEG_TYPE_CODE          (1 << 3)
-#define SEG_TYPE_EXEC_READ     (1 << 1)
-#define SEG_TYPE_TSS           ((1 << 3) | (1 << 0))
-#define SEG_OP_SIZE_32BIT      (1 << 0)
-#define SEG_GRANULARITY_4KB    (1 << 0)
-
-#define DESC_TYPE_CODE_DATA    (1 << 0)
-
-typedef union efi_uga_draw_protocol efi_uga_draw_protocol_t;
-
-union efi_uga_draw_protocol {
-       struct {
-               efi_status_t (__efiapi *get_mode)(efi_uga_draw_protocol_t *,
-                                                 u32*, u32*, u32*, u32*);
-               void *set_mode;
-               void *blt;
-       };
-       struct {
-               u32 get_mode;
-               u32 set_mode;
-               u32 blt;
-       } mixed_mode;
-};
-
-#endif /* BOOT_COMPRESSED_EBOOT_H */
index 8fb7f67..2b20492 100644 (file)
@@ -54,11 +54,16 @@ SYM_FUNC_START(__efi64_thunk)
         * Switch to gdt with 32-bit segments. This is the firmware GDT
         * that was installed when the kernel started executing. This
         * pointer was saved at the EFI stub entry point in head_64.S.
+        *
+        * Pass the saved DS selector to the 32-bit code, and use far return to
+        * restore the saved CS selector.
         */
        leaq    efi32_boot_gdt(%rip), %rax
        lgdt    (%rax)
 
-       pushq   $__KERNEL_CS
+       movzwl  efi32_boot_ds(%rip), %edx
+       movzwq  efi32_boot_cs(%rip), %rax
+       pushq   %rax
        leaq    efi_enter32(%rip), %rax
        pushq   %rax
        lretq
@@ -73,6 +78,10 @@ SYM_FUNC_START(__efi64_thunk)
        movl    %ebx, %es
        pop     %rbx
        movl    %ebx, %ds
+       /* Clear out 32-bit selector from FS and GS */
+       xorl    %ebx, %ebx
+       movl    %ebx, %fs
+       movl    %ebx, %gs
 
        /*
         * Convert 32-bit status code into 64-bit.
@@ -92,10 +101,12 @@ SYM_FUNC_END(__efi64_thunk)
  * The stack should represent the 32-bit calling convention.
  */
 SYM_FUNC_START_LOCAL(efi_enter32)
-       movl    $__KERNEL_DS, %eax
-       movl    %eax, %ds
-       movl    %eax, %es
-       movl    %eax, %ss
+       /* Load firmware selector into data and stack segment registers */
+       movl    %edx, %ds
+       movl    %edx, %es
+       movl    %edx, %fs
+       movl    %edx, %gs
+       movl    %edx, %ss
 
        /* Reload pgtables */
        movl    %cr3, %eax
@@ -157,6 +168,14 @@ SYM_DATA_START(efi32_boot_gdt)
        .quad   0
 SYM_DATA_END(efi32_boot_gdt)
 
+SYM_DATA_START(efi32_boot_cs)
+       .word   0
+SYM_DATA_END(efi32_boot_cs)
+
+SYM_DATA_START(efi32_boot_ds)
+       .word   0
+SYM_DATA_END(efi32_boot_ds)
+
 SYM_DATA_START(efi_gdt64)
        .word   efi_gdt64_end - efi_gdt64
        .long   0                       /* Filled out by user */
index 73f17d0..ab33070 100644 (file)
        __HEAD
 SYM_FUNC_START(startup_32)
        cld
-       /*
-        * Test KEEP_SEGMENTS flag to see if the bootloader is asking
-        * us to not reload segments
-        */
-       testb   $KEEP_SEGMENTS, BP_loadflags(%esi)
-       jnz     1f
-
        cli
-       movl    $__BOOT_DS, %eax
-       movl    %eax, %ds
-       movl    %eax, %es
-       movl    %eax, %fs
-       movl    %eax, %gs
-       movl    %eax, %ss
-1:
 
 /*
  * Calculate the delta between where we were compiled to run
@@ -89,32 +75,59 @@ SYM_FUNC_START(startup_32)
  */
        leal    (BP_scratch+4)(%esi), %esp
        call    1f
-1:     popl    %ebp
-       subl    $1b, %ebp
+1:     popl    %edx
+       subl    $1b, %edx
+
+       /* Load new GDT */
+       leal    gdt(%edx), %eax
+       movl    %eax, 2(%eax)
+       lgdt    (%eax)
+
+       /* Load segment registers with our descriptors */
+       movl    $__BOOT_DS, %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %fs
+       movl    %eax, %gs
+       movl    %eax, %ss
 
 /*
- * %ebp contains the address we are loaded at by the boot loader and %ebx
+ * %edx contains the address we are loaded at by the boot loader and %ebx
  * contains the address where we should move the kernel image temporarily
- * for safe in-place decompression.
+ * for safe in-place decompression. %ebp contains the address that the kernel
+ * will be decompressed to.
  */
 
 #ifdef CONFIG_RELOCATABLE
-       movl    %ebp, %ebx
+       movl    %edx, %ebx
+
+#ifdef CONFIG_EFI_STUB
+/*
+ * If we were loaded via the EFI LoadImage service, startup_32() will be at an
+ * offset to the start of the space allocated for the image. efi_pe_entry() will
+ * set up image_offset to tell us where the image actually starts, so that we
+ * can use the full available buffer.
+ *     image_offset = startup_32 - image_base
+ * Otherwise image_offset will be zero and has no effect on the calculations.
+ */
+       subl    image_offset(%edx), %ebx
+#endif
+
        movl    BP_kernel_alignment(%esi), %eax
        decl    %eax
        addl    %eax, %ebx
        notl    %eax
        andl    %eax, %ebx
        cmpl    $LOAD_PHYSICAL_ADDR, %ebx
-       jge     1f
+       jae     1f
 #endif
        movl    $LOAD_PHYSICAL_ADDR, %ebx
 1:
 
+       movl    %ebx, %ebp      // Save the output address for later
        /* Target address to relocate to for decompression */
-       movl    BP_init_size(%esi), %eax
-       subl    $_end, %eax
-       addl    %eax, %ebx
+       addl    BP_init_size(%esi), %ebx
+       subl    $_end, %ebx
 
        /* Set up the stack */
        leal    boot_stack_end(%ebx), %esp
@@ -128,7 +141,7 @@ SYM_FUNC_START(startup_32)
  * where decompression in place becomes safe.
  */
        pushl   %esi
-       leal    (_bss-4)(%ebp), %esi
+       leal    (_bss-4)(%edx), %esi
        leal    (_bss-4)(%ebx), %edi
        movl    $(_bss - startup_32), %ecx
        shrl    $2, %ecx
@@ -137,6 +150,15 @@ SYM_FUNC_START(startup_32)
        cld
        popl    %esi
 
+       /*
+        * The GDT may get overwritten either during the copy we just did or
+        * during extract_kernel below. To avoid any issues, repoint the GDTR
+        * to the new copy of the GDT.
+        */
+       leal    gdt(%ebx), %eax
+       movl    %eax, 2(%eax)
+       lgdt    (%eax)
+
 /*
  * Jump to the relocated address.
  */
@@ -148,9 +170,8 @@ SYM_FUNC_END(startup_32)
 SYM_FUNC_START(efi32_stub_entry)
 SYM_FUNC_START_ALIAS(efi_stub_entry)
        add     $0x4, %esp
+       movl    8(%esp), %esi   /* save boot_params pointer */
        call    efi_main
-       movl    %eax, %esi
-       movl    BP_code32_start(%esi), %eax
        leal    startup_32(%eax), %eax
        jmp     *%eax
 SYM_FUNC_END(efi32_stub_entry)
@@ -189,9 +210,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
                                /* push arguments for extract_kernel: */
        pushl   $z_output_len   /* decompressed length, end of relocs */
 
-       leal    _end(%ebx), %eax
-       subl    BP_init_size(%esi), %eax
-       pushl   %eax            /* output address */
+       pushl   %ebp            /* output address */
 
        pushl   $z_input_len    /* input_len */
        leal    input_data(%ebx), %eax
@@ -209,6 +228,21 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
        jmp     *%eax
 SYM_FUNC_END(.Lrelocated)
 
+       .data
+       .balign 8
+SYM_DATA_START_LOCAL(gdt)
+       .word   gdt_end - gdt - 1
+       .long   0
+       .word   0
+       .quad   0x0000000000000000      /* Reserved */
+       .quad   0x00cf9a000000ffff      /* __KERNEL_CS */
+       .quad   0x00cf92000000ffff      /* __KERNEL_DS */
+SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
+
+#ifdef CONFIG_EFI_STUB
+SYM_DATA(image_offset, .long 0)
+#endif
+
 /*
  * Stack and heap for uncompression
  */
index 1f1f6c8..4f7e6b8 100644 (file)
@@ -53,19 +53,7 @@ SYM_FUNC_START(startup_32)
         * all need to be under the 4G limit.
         */
        cld
-       /*
-        * Test KEEP_SEGMENTS flag to see if the bootloader is asking
-        * us to not reload segments
-        */
-       testb $KEEP_SEGMENTS, BP_loadflags(%esi)
-       jnz 1f
-
        cli
-       movl    $(__BOOT_DS), %eax
-       movl    %eax, %ds
-       movl    %eax, %es
-       movl    %eax, %ss
-1:
 
 /*
  * Calculate the delta between where we were compiled to run
@@ -80,10 +68,21 @@ SYM_FUNC_START(startup_32)
 1:     popl    %ebp
        subl    $1b, %ebp
 
+       /* Load new GDT with the 64bit segments using 32bit descriptor */
+       leal    gdt(%ebp), %eax
+       movl    %eax, 2(%eax)
+       lgdt    (%eax)
+
+       /* Load segment registers with our descriptors */
+       movl    $__BOOT_DS, %eax
+       movl    %eax, %ds
+       movl    %eax, %es
+       movl    %eax, %fs
+       movl    %eax, %gs
+       movl    %eax, %ss
+
 /* setup a stack and make sure cpu supports long mode. */
-       movl    $boot_stack_end, %eax
-       addl    %ebp, %eax
-       movl    %eax, %esp
+       leal    boot_stack_end(%ebp), %esp
 
        call    verify_cpu
        testl   %eax, %eax
@@ -100,30 +99,38 @@ SYM_FUNC_START(startup_32)
 
 #ifdef CONFIG_RELOCATABLE
        movl    %ebp, %ebx
+
+#ifdef CONFIG_EFI_STUB
+/*
+ * If we were loaded via the EFI LoadImage service, startup_32 will be at an
+ * offset to the start of the space allocated for the image. efi_pe_entry will
+ * set up image_offset to tell us where the image actually starts, so that we
+ * can use the full available buffer.
+ *     image_offset = startup_32 - image_base
+ * Otherwise image_offset will be zero and has no effect on the calculations.
+ */
+       subl    image_offset(%ebp), %ebx
+#endif
+
        movl    BP_kernel_alignment(%esi), %eax
        decl    %eax
        addl    %eax, %ebx
        notl    %eax
        andl    %eax, %ebx
        cmpl    $LOAD_PHYSICAL_ADDR, %ebx
-       jge     1f
+       jae     1f
 #endif
        movl    $LOAD_PHYSICAL_ADDR, %ebx
 1:
 
        /* Target address to relocate to for decompression */
-       movl    BP_init_size(%esi), %eax
-       subl    $_end, %eax
-       addl    %eax, %ebx
+       addl    BP_init_size(%esi), %ebx
+       subl    $_end, %ebx
 
 /*
  * Prepare for entering 64 bit mode
  */
 
-       /* Load new GDT with the 64bit segments using 32bit descriptor */
-       addl    %ebp, gdt+2(%ebp)
-       lgdt    gdt(%ebp)
-
        /* Enable PAE mode */
        movl    %cr4, %eax
        orl     $X86_CR4_PAE, %eax
@@ -212,8 +219,13 @@ SYM_FUNC_START(startup_32)
        cmp     $0, %edi
        jz      1f
        leal    efi64_stub_entry(%ebp), %eax
-       movl    %esi, %edx
        movl    efi32_boot_args+4(%ebp), %esi
+       movl    efi32_boot_args+8(%ebp), %edx   // saved bootparams pointer
+       cmpl    $0, %edx
+       jnz     1f
+       leal    efi_pe_entry(%ebp), %eax
+       movl    %edi, %ecx                      // MS calling convention
+       movl    %esi, %edx
 1:
 #endif
        pushl   %eax
@@ -238,11 +250,17 @@ SYM_FUNC_START(efi32_stub_entry)
 1:     pop     %ebp
        subl    $1b, %ebp
 
+       movl    %esi, efi32_boot_args+8(%ebp)
+SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
        movl    %ecx, efi32_boot_args(%ebp)
        movl    %edx, efi32_boot_args+4(%ebp)
-       sgdtl   efi32_boot_gdt(%ebp)
        movb    $0, efi_is64(%ebp)
 
+       /* Save firmware GDTR and code/data selectors */
+       sgdtl   efi32_boot_gdt(%ebp)
+       movw    %cs, efi32_boot_cs(%ebp)
+       movw    %ds, efi32_boot_ds(%ebp)
+
        /* Disable paging */
        movl    %cr0, %eax
        btrl    $X86_CR0_PG_BIT, %eax
@@ -266,6 +284,9 @@ SYM_CODE_START(startup_64)
         * and command line.
         */
 
+       cld
+       cli
+
        /* Setup data segments. */
        xorl    %eax, %eax
        movl    %eax, %ds
@@ -290,13 +311,27 @@ SYM_CODE_START(startup_64)
        /* Start with the delta to where the kernel will run at. */
 #ifdef CONFIG_RELOCATABLE
        leaq    startup_32(%rip) /* - $startup_32 */, %rbp
+
+#ifdef CONFIG_EFI_STUB
+/*
+ * If we were loaded via the EFI LoadImage service, startup_32 will be at an
+ * offset to the start of the space allocated for the image. efi_pe_entry will
+ * set up image_offset to tell us where the image actually starts, so that we
+ * can use the full available buffer.
+ *     image_offset = startup_32 - image_base
+ * Otherwise image_offset will be zero and has no effect on the calculations.
+ */
+       movl    image_offset(%rip), %eax
+       subq    %rax, %rbp
+#endif
+
        movl    BP_kernel_alignment(%rsi), %eax
        decl    %eax
        addq    %rax, %rbp
        notq    %rax
        andq    %rax, %rbp
        cmpq    $LOAD_PHYSICAL_ADDR, %rbp
-       jge     1f
+       jae     1f
 #endif
        movq    $LOAD_PHYSICAL_ADDR, %rbp
 1:
@@ -354,9 +389,9 @@ SYM_CODE_START(startup_64)
         */
 
        /* Make sure we have GDT with 32-bit code segment */
-       leaq    gdt(%rip), %rax
-       movq    %rax, gdt64+2(%rip)
-       lgdt    gdt64(%rip)
+       leaq    gdt64(%rip), %rax
+       addq    %rax, 2(%rax)
+       lgdt    (%rax)
 
        /*
         * paging_prepare() sets up the trampoline and checks if we need to
@@ -441,6 +476,16 @@ trampoline_return:
        cld
        popq    %rsi
 
+       /*
+        * The GDT may get overwritten either during the copy we just did or
+        * during extract_kernel below. To avoid any issues, repoint the GDTR
+        * to the new copy of the GDT.
+        */
+       leaq    gdt64(%rbx), %rax
+       leaq    gdt(%rbx), %rdx
+       movq    %rdx, 2(%rax)
+       lgdt    (%rax)
+
 /*
  * Jump to the relocated address.
  */
@@ -453,9 +498,9 @@ SYM_CODE_END(startup_64)
 SYM_FUNC_START(efi64_stub_entry)
 SYM_FUNC_START_ALIAS(efi_stub_entry)
        and     $~0xf, %rsp                     /* realign the stack */
+       movq    %rdx, %rbx                      /* save boot_params pointer */
        call    efi_main
-       movq    %rax,%rsi
-       movl    BP_code32_start(%esi), %eax
+       movq    %rbx,%rsi
        leaq    startup_64(%rax), %rax
        jmp     *%rax
 SYM_FUNC_END(efi64_stub_entry)
@@ -484,7 +529,7 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
        leaq    input_data(%rip), %rdx  /* input_data */
        movl    $z_input_len, %ecx      /* input_len */
        movq    %rbp, %r8               /* output target address */
-       movq    $z_output_len, %r9      /* decompressed length, end of relocs */
+       movl    $z_output_len, %r9d     /* decompressed length, end of relocs */
        call    extract_kernel          /* returns kernel location in %rax */
        popq    %rsi
 
@@ -613,13 +658,13 @@ SYM_FUNC_END(.Lno_longmode)
 
        .data
 SYM_DATA_START_LOCAL(gdt64)
-       .word   gdt_end - gdt
-       .quad   0
+       .word   gdt_end - gdt - 1
+       .quad   gdt - gdt64
 SYM_DATA_END(gdt64)
        .balign 8
 SYM_DATA_START_LOCAL(gdt)
-       .word   gdt_end - gdt
-       .long   gdt
+       .word   gdt_end - gdt - 1
+       .long   0
        .word   0
        .quad   0x00cf9a000000ffff      /* __KERNEL32_CS */
        .quad   0x00af9a000000ffff      /* __KERNEL_CS */
@@ -628,9 +673,97 @@ SYM_DATA_START_LOCAL(gdt)
        .quad   0x0000000000000000      /* TS continued */
 SYM_DATA_END_LABEL(gdt, SYM_L_LOCAL, gdt_end)
 
+#ifdef CONFIG_EFI_STUB
+SYM_DATA(image_offset, .long 0)
+#endif
+
 #ifdef CONFIG_EFI_MIXED
-SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0)
+SYM_DATA_LOCAL(efi32_boot_args, .long 0, 0, 0)
 SYM_DATA(efi_is64, .byte 1)
+
+#define ST32_boottime          60 // offsetof(efi_system_table_32_t, boottime)
+#define BS32_handle_protocol   88 // offsetof(efi_boot_services_32_t, handle_protocol)
+#define LI32_image_base                32 // offsetof(efi_loaded_image_32_t, image_base)
+
+       .text
+       .code32
+SYM_FUNC_START(efi32_pe_entry)
+/*
+ * efi_status_t efi32_pe_entry(efi_handle_t image_handle,
+ *                            efi_system_table_32_t *sys_table)
+ */
+
+       pushl   %ebp
+       movl    %esp, %ebp
+       pushl   %eax                            // dummy push to allocate loaded_image
+
+       pushl   %ebx                            // save callee-save registers
+       pushl   %edi
+
+       call    verify_cpu                      // check for long mode support
+       testl   %eax, %eax
+       movl    $0x80000003, %eax               // EFI_UNSUPPORTED
+       jnz     2f
+
+       call    1f
+1:     pop     %ebx
+       subl    $1b, %ebx
+
+       /* Get the loaded image protocol pointer from the image handle */
+       leal    -4(%ebp), %eax
+       pushl   %eax                            // &loaded_image
+       leal    loaded_image_proto(%ebx), %eax
+       pushl   %eax                            // pass the GUID address
+       pushl   8(%ebp)                         // pass the image handle
+
+       /*
+        * Note the alignment of the stack frame.
+        *   sys_table
+        *   handle             <-- 16-byte aligned on entry by ABI
+        *   return address
+        *   frame pointer
+        *   loaded_image       <-- local variable
+        *   saved %ebx         <-- 16-byte aligned here
+        *   saved %edi
+        *   &loaded_image
+        *   &loaded_image_proto
+        *   handle             <-- 16-byte aligned for call to handle_protocol
+        */
+
+       movl    12(%ebp), %eax                  // sys_table
+       movl    ST32_boottime(%eax), %eax       // sys_table->boottime
+       call    *BS32_handle_protocol(%eax)     // sys_table->boottime->handle_protocol
+       addl    $12, %esp                       // restore argument space
+       testl   %eax, %eax
+       jnz     2f
+
+       movl    8(%ebp), %ecx                   // image_handle
+       movl    12(%ebp), %edx                  // sys_table
+       movl    -4(%ebp), %esi                  // loaded_image
+       movl    LI32_image_base(%esi), %esi     // loaded_image->image_base
+       movl    %ebx, %ebp                      // startup_32 for efi32_pe_stub_entry
+       /*
+        * We need to set the image_offset variable here since startup_32() will
+        * use it before we get to the 64-bit efi_pe_entry() in C code.
+        */
+       subl    %esi, %ebx
+       movl    %ebx, image_offset(%ebp)        // save image_offset
+       jmp     efi32_pe_stub_entry
+
+2:     popl    %edi                            // restore callee-save registers
+       popl    %ebx
+       leave
+       ret
+SYM_FUNC_END(efi32_pe_entry)
+
+       .section ".rodata"
+       /* EFI loaded image protocol GUID */
+       .balign 4
+SYM_DATA_START_LOCAL(loaded_image_proto)
+       .long   0x5b1b31a1
+       .word   0x9562, 0x11d2
+       .byte   0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b
+SYM_DATA_END(loaded_image_proto)
 #endif
 
 /*
@@ -647,7 +780,7 @@ SYM_DATA_END_LABEL(boot_stack, SYM_L_LOCAL, boot_stack_end)
 /*
  * Space for page tables (not in .bss so not zeroed)
  */
-       .section ".pgtable","a",@nobits
+       .section ".pgtable","aw",@nobits
        .balign 4096
 SYM_DATA_LOCAL(pgtable,                .fill BOOT_PGT_SIZE, 1, 0)
 
index c818139..726e264 100644 (file)
@@ -59,7 +59,7 @@ void __puthex(unsigned long value);
 
 static inline void debug_putstr(const char *s)
 { }
-static inline void debug_puthex(const char *s)
+static inline void debug_puthex(unsigned long value)
 { }
 #define debug_putaddr(x) /* */
 
index 97d9b6d..735ad7f 100644 (file)
@@ -15,7 +15,7 @@
  * hex while segment addresses are written as segment:offset.
  *
  */
-
+#include <linux/pe.h>
 #include <asm/segment.h>
 #include <asm/boot.h>
 #include <asm/page_types.h>
@@ -43,8 +43,7 @@ SYSSEG                = 0x1000                /* historical load address >> 4 */
 bootsect_start:
 #ifdef CONFIG_EFI_STUB
        # "MZ", MS-DOS header
-       .byte 0x4d
-       .byte 0x5a
+       .word   MZ_MAGIC
 #endif
 
        # Normalize the start address
@@ -97,39 +96,30 @@ bugger_off_msg:
 
 #ifdef CONFIG_EFI_STUB
 pe_header:
-       .ascii  "PE"
-       .word   0
+       .long   PE_MAGIC
 
 coff_header:
 #ifdef CONFIG_X86_32
-       .word   0x14c                           # i386
+       .set    image_file_add_flags, IMAGE_FILE_32BIT_MACHINE
+       .set    pe_opt_magic, PE_OPT_MAGIC_PE32
+       .word   IMAGE_FILE_MACHINE_I386
 #else
-       .word   0x8664                          # x86-64
+       .set    image_file_add_flags, 0
+       .set    pe_opt_magic, PE_OPT_MAGIC_PE32PLUS
+       .word   IMAGE_FILE_MACHINE_AMD64
 #endif
-       .word   4                               # nr_sections
+       .word   section_count                   # nr_sections
        .long   0                               # TimeDateStamp
        .long   0                               # PointerToSymbolTable
        .long   1                               # NumberOfSymbols
        .word   section_table - optional_header # SizeOfOptionalHeader
-#ifdef CONFIG_X86_32
-       .word   0x306                           # Characteristics.
-                                               # IMAGE_FILE_32BIT_MACHINE |
-                                               # IMAGE_FILE_DEBUG_STRIPPED |
-                                               # IMAGE_FILE_EXECUTABLE_IMAGE |
-                                               # IMAGE_FILE_LINE_NUMS_STRIPPED
-#else
-       .word   0x206                           # Characteristics
-                                               # IMAGE_FILE_DEBUG_STRIPPED |
-                                               # IMAGE_FILE_EXECUTABLE_IMAGE |
-                                               # IMAGE_FILE_LINE_NUMS_STRIPPED
-#endif
+       .word   IMAGE_FILE_EXECUTABLE_IMAGE     | \
+               image_file_add_flags            | \
+               IMAGE_FILE_DEBUG_STRIPPED       | \
+               IMAGE_FILE_LINE_NUMS_STRIPPED   # Characteristics
 
 optional_header:
-#ifdef CONFIG_X86_32
-       .word   0x10b                           # PE32 format
-#else
-       .word   0x20b                           # PE32+ format
-#endif
+       .word   pe_opt_magic
        .byte   0x02                            # MajorLinkerVersion
        .byte   0x14                            # MinorLinkerVersion
 
@@ -148,17 +138,19 @@ optional_header:
 #endif
 
 extra_header_fields:
+       # PE specification requires ImageBase to be 64k aligned
+       .set    image_base, (LOAD_PHYSICAL_ADDR + 0xffff) & ~0xffff
 #ifdef CONFIG_X86_32
-       .long   0                               # ImageBase
+       .long   image_base                      # ImageBase
 #else
-       .quad   0                               # ImageBase
+       .quad   image_base                      # ImageBase
 #endif
        .long   0x20                            # SectionAlignment
        .long   0x20                            # FileAlignment
        .word   0                               # MajorOperatingSystemVersion
        .word   0                               # MinorOperatingSystemVersion
-       .word   0                               # MajorImageVersion
-       .word   0                               # MinorImageVersion
+       .word   LINUX_EFISTUB_MAJOR_VERSION     # MajorImageVersion
+       .word   LINUX_EFISTUB_MINOR_VERSION     # MinorImageVersion
        .word   0                               # MajorSubsystemVersion
        .word   0                               # MinorSubsystemVersion
        .long   0                               # Win32VersionValue
@@ -170,7 +162,7 @@ extra_header_fields:
 
        .long   0x200                           # SizeOfHeaders
        .long   0                               # CheckSum
-       .word   0xa                             # Subsystem (EFI application)
+       .word   IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
        .word   0                               # DllCharacteristics
 #ifdef CONFIG_X86_32
        .long   0                               # SizeOfStackReserve
@@ -184,7 +176,7 @@ extra_header_fields:
        .quad   0                               # SizeOfHeapCommit
 #endif
        .long   0                               # LoaderFlags
-       .long   0x6                             # NumberOfRvaAndSizes
+       .long   (section_table - .) / 8         # NumberOfRvaAndSizes
 
        .quad   0                               # ExportTable
        .quad   0                               # ImportTable
@@ -210,7 +202,10 @@ section_table:
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
        .word   0                               # NumberOfLineNumbers
-       .long   0x60500020                      # Characteristics (section flags)
+       .long   IMAGE_SCN_CNT_CODE              | \
+               IMAGE_SCN_MEM_READ              | \
+               IMAGE_SCN_MEM_EXECUTE           | \
+               IMAGE_SCN_ALIGN_16BYTES         # Characteristics
 
        #
        # The EFI application loader requires a relocation section
@@ -228,45 +223,53 @@ section_table:
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
        .word   0                               # NumberOfLineNumbers
-       .long   0x42100040                      # Characteristics (section flags)
+       .long   IMAGE_SCN_CNT_INITIALIZED_DATA  | \
+               IMAGE_SCN_MEM_READ              | \
+               IMAGE_SCN_MEM_DISCARDABLE       | \
+               IMAGE_SCN_ALIGN_1BYTES          # Characteristics
 
+#ifdef CONFIG_EFI_MIXED
        #
        # The offset & size fields are filled in by build.c.
        #
-       .ascii  ".text"
-       .byte   0
-       .byte   0
-       .byte   0
+       .asciz  ".compat"
        .long   0
-       .long   0x0                             # startup_{32,64}
+       .long   0x0
        .long   0                               # Size of initialized data
                                                # on disk
-       .long   0x0                             # startup_{32,64}
+       .long   0x0
        .long   0                               # PointerToRelocations
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
        .word   0                               # NumberOfLineNumbers
-       .long   0x60500020                      # Characteristics (section flags)
+       .long   IMAGE_SCN_CNT_INITIALIZED_DATA  | \
+               IMAGE_SCN_MEM_READ              | \
+               IMAGE_SCN_MEM_DISCARDABLE       | \
+               IMAGE_SCN_ALIGN_1BYTES          # Characteristics
+#endif
 
        #
        # The offset & size fields are filled in by build.c.
        #
-       .ascii  ".bss"
-       .byte   0
+       .ascii  ".text"
        .byte   0
        .byte   0
        .byte   0
        .long   0
-       .long   0x0
+       .long   0x0                             # startup_{32,64}
        .long   0                               # Size of initialized data
                                                # on disk
-       .long   0x0
+       .long   0x0                             # startup_{32,64}
        .long   0                               # PointerToRelocations
        .long   0                               # PointerToLineNumbers
        .word   0                               # NumberOfRelocations
        .word   0                               # NumberOfLineNumbers
-       .long   0xc8000080                      # Characteristics (section flags)
+       .long   IMAGE_SCN_CNT_CODE              | \
+               IMAGE_SCN_MEM_READ              | \
+               IMAGE_SCN_MEM_EXECUTE           | \
+               IMAGE_SCN_ALIGN_16BYTES         # Characteristics
 
+       .set    section_count, (. - section_table) / 40
 #endif /* CONFIG_EFI_STUB */
 
        # Kernel attributes; used by setup.  This is part 1 of the
index 3da1c37..24c9552 100644 (file)
@@ -52,7 +52,6 @@ SECTIONS
        _end = .;
 
        /DISCARD/       : {
-               *(.eh_frame)
                *(.note*)
        }
 
index 55e669d..8f8c8e3 100644 (file)
@@ -53,11 +53,20 @@ u8 buf[SETUP_SECT_MAX*512];
 
 #define PECOFF_RELOC_RESERVE 0x20
 
+#ifdef CONFIG_EFI_MIXED
+#define PECOFF_COMPAT_RESERVE 0x20
+#else
+#define PECOFF_COMPAT_RESERVE 0x0
+#endif
+
 unsigned long efi32_stub_entry;
 unsigned long efi64_stub_entry;
 unsigned long efi_pe_entry;
+unsigned long efi32_pe_entry;
 unsigned long kernel_info;
 unsigned long startup_64;
+unsigned long _ehead;
+unsigned long _end;
 
 /*----------------------------------------------------------------------*/
 
@@ -189,7 +198,10 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz
 static void update_pecoff_setup_and_reloc(unsigned int size)
 {
        u32 setup_offset = 0x200;
-       u32 reloc_offset = size - PECOFF_RELOC_RESERVE;
+       u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
+#ifdef CONFIG_EFI_MIXED
+       u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
+#endif
        u32 setup_size = reloc_offset - setup_offset;
 
        update_pecoff_section_header(".setup", setup_offset, setup_size);
@@ -201,43 +213,59 @@ static void update_pecoff_setup_and_reloc(unsigned int size)
         */
        put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
        put_unaligned_le32(10, &buf[reloc_offset + 4]);
+
+#ifdef CONFIG_EFI_MIXED
+       update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
+
+       /*
+        * Put the IA-32 machine type (0x14c) and the associated entry point
+        * address in the .compat section, so loaders can figure out which other
+        * execution modes this image supports.
+        */
+       buf[compat_offset] = 0x1;
+       buf[compat_offset + 1] = 0x8;
+       put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
+       put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
+#endif
 }
 
-static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
+static void update_pecoff_text(unsigned int text_start, unsigned int file_sz,
+                              unsigned int init_sz)
 {
        unsigned int pe_header;
        unsigned int text_sz = file_sz - text_start;
+       unsigned int bss_sz = init_sz - file_sz;
 
        pe_header = get_unaligned_le32(&buf[0x3c]);
 
        /*
+        * The PE/COFF loader may load the image at an address which is
+        * misaligned with respect to the kernel_alignment field in the setup
+        * header.
+        *
+        * In order to avoid relocating the kernel to correct the misalignment,
+        * add slack to allow the buffer to be aligned within the declared size
+        * of the image.
+        */
+       bss_sz  += CONFIG_PHYSICAL_ALIGN;
+       init_sz += CONFIG_PHYSICAL_ALIGN;
+
+       /*
         * Size of code: Subtract the size of the first sector (512 bytes)
         * which includes the header.
         */
-       put_unaligned_le32(file_sz - 512, &buf[pe_header + 0x1c]);
+       put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]);
+
+       /* Size of image */
+       put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
 
        /*
         * Address of entry point for PE/COFF executable
         */
        put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
 
-       update_pecoff_section_header(".text", text_start, text_sz);
-}
-
-static void update_pecoff_bss(unsigned int file_sz, unsigned int init_sz)
-{
-       unsigned int pe_header;
-       unsigned int bss_sz = init_sz - file_sz;
-
-       pe_header = get_unaligned_le32(&buf[0x3c]);
-
-       /* Size of uninitialized data */
-       put_unaligned_le32(bss_sz, &buf[pe_header + 0x24]);
-
-       /* Size of image */
-       put_unaligned_le32(init_sz, &buf[pe_header + 0x50]);
-
-       update_pecoff_section_header_fields(".bss", file_sz, bss_sz, 0, 0);
+       update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
+                                           text_sz, text_start);
 }
 
 static int reserve_pecoff_reloc_section(int c)
@@ -278,9 +306,8 @@ static void efi_stub_entry_update(void)
 
 static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
 static inline void update_pecoff_text(unsigned int text_start,
-                                     unsigned int file_sz) {}
-static inline void update_pecoff_bss(unsigned int file_sz,
-                                    unsigned int init_sz) {}
+                                     unsigned int file_sz,
+                                     unsigned int init_sz) {}
 static inline void efi_stub_defaults(void) {}
 static inline void efi_stub_entry_update(void) {}
 
@@ -290,6 +317,12 @@ static inline int reserve_pecoff_reloc_section(int c)
 }
 #endif /* CONFIG_EFI_STUB */
 
+static int reserve_pecoff_compat_section(int c)
+{
+       /* Reserve 0x20 bytes for .compat section */
+       memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
+       return PECOFF_COMPAT_RESERVE;
+}
 
 /*
  * Parse zoffset.h and find the entry points. We could just #include zoffset.h
@@ -322,8 +355,11 @@ static void parse_zoffset(char *fname)
                PARSE_ZOFS(p, efi32_stub_entry);
                PARSE_ZOFS(p, efi64_stub_entry);
                PARSE_ZOFS(p, efi_pe_entry);
+               PARSE_ZOFS(p, efi32_pe_entry);
                PARSE_ZOFS(p, kernel_info);
                PARSE_ZOFS(p, startup_64);
+               PARSE_ZOFS(p, _ehead);
+               PARSE_ZOFS(p, _end);
 
                p = strchr(p, '\n');
                while (p && (*p == '\r' || *p == '\n'))
@@ -365,6 +401,7 @@ int main(int argc, char ** argv)
                die("Boot block hasn't got boot flag (0xAA55)");
        fclose(file);
 
+       c += reserve_pecoff_compat_section(c);
        c += reserve_pecoff_reloc_section(c);
 
        /* Pad unused space with zeros */
@@ -406,9 +443,28 @@ int main(int argc, char ** argv)
        buf[0x1f1] = setup_sectors-1;
        put_unaligned_le32(sys_size, &buf[0x1f4]);
 
-       update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
        init_sz = get_unaligned_le32(&buf[0x260]);
-       update_pecoff_bss(i + (sys_size * 16), init_sz);
+#ifdef CONFIG_EFI_STUB
+       /*
+        * The decompression buffer will start at ImageBase. When relocating
+        * the compressed kernel to its end, we must ensure that the head
+        * section does not get overwritten.  The head section occupies
+        * [i, i + _ehead), and the destination is [init_sz - _end, init_sz).
+        *
+        * At present these should never overlap, because 'i' is at most 32k
+        * because of SETUP_SECT_MAX, '_ehead' is less than 1k, and the
+        * calculation of INIT_SIZE in boot/header.S ensures that
+        * 'init_sz - _end' is at least 64k.
+        *
+        * For future-proofing, increase init_sz if necessary.
+        */
+
+       if (init_sz - _end < i + _ehead) {
+               init_sz = (i + _ehead + _end + 4095) & ~4095;
+               put_unaligned_le32(init_sz, &buf[0x260]);
+       }
+#endif
+       update_pecoff_text(setup_sectors * 512, i + (sys_size * 16), init_sz);
 
        efi_stub_entry_update();
 
index b69e00b..8c2e9ea 100644 (file)
@@ -11,6 +11,7 @@ avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
 avx512_supported :=$(call as-instr,vpmovm2b %k1$(comma)%zmm5,yes,no)
 sha1_ni_supported :=$(call as-instr,sha1msg1 %xmm0$(comma)%xmm1,yes,no)
 sha256_ni_supported :=$(call as-instr,sha256msg1 %xmm0$(comma)%xmm1,yes,no)
+adx_supported := $(call as-instr,adox %r10$(comma)%r10,yes,no)
 
 obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o
 
@@ -39,7 +40,11 @@ obj-$(CONFIG_CRYPTO_AEGIS128_AESNI_SSE2) += aegis128-aesni.o
 
 obj-$(CONFIG_CRYPTO_NHPOLY1305_SSE2) += nhpoly1305-sse2.o
 obj-$(CONFIG_CRYPTO_NHPOLY1305_AVX2) += nhpoly1305-avx2.o
-obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o
+
+# These modules require the assembler to support ADX.
+ifeq ($(adx_supported),yes)
+       obj-$(CONFIG_CRYPTO_CURVE25519_X86) += curve25519-x86_64.o
+endif
 
 # These modules require assembler to support AVX.
 ifeq ($(avx_supported),yes)
index bbbebbd..75b6ea2 100644 (file)
@@ -1064,7 +1064,7 @@ static struct aead_alg aesni_aeads[0];
 static struct simd_aead_alg *aesni_simd_aeads[ARRAY_SIZE(aesni_aeads)];
 
 static const struct x86_cpu_id aesni_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_AES),
+       X86_MATCH_FEATURE(X86_FEATURE_AES, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id);
index 418bd88..7c4c7b2 100644 (file)
@@ -170,7 +170,7 @@ static struct shash_alg alg = {
 };
 
 static const struct x86_cpu_id crc32pclmul_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ),
+       X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, crc32pclmul_cpu_id);
index c20d1b8..d2d069b 100644 (file)
@@ -221,7 +221,7 @@ static struct shash_alg alg = {
 };
 
 static const struct x86_cpu_id crc32c_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_XMM4_2),
+       X86_MATCH_FEATURE(X86_FEATURE_XMM4_2, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, crc32c_cpu_id);
index 3c81e15..71291d5 100644 (file)
@@ -114,7 +114,7 @@ static struct shash_alg alg = {
 };
 
 static const struct x86_cpu_id crct10dif_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ),
+       X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, crct10dif_cpu_id);
index a4b7285..1f1a95f 100644 (file)
@@ -313,7 +313,7 @@ static struct ahash_alg ghash_async_alg = {
 };
 
 static const struct x86_cpu_id pcmul_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ), /* Pickle-Mickle-Duck */
+       X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL), /* Pickle-Mickle-Duck */
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
index 06fc70c..85eb381 100644 (file)
@@ -14,4 +14,5 @@ obj-y                         += vdso/
 obj-y                          += vsyscall/
 
 obj-$(CONFIG_IA32_EMULATION)   += entry_64_compat.o syscall_32.o
+obj-$(CONFIG_X86_X32_ABI)      += syscall_x32.o
 
index 9747876..6062e8e 100644 (file)
@@ -333,20 +333,7 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs)
 
        if (likely(nr < IA32_NR_syscalls)) {
                nr = array_index_nospec(nr, IA32_NR_syscalls);
-#ifdef CONFIG_IA32_EMULATION
                regs->ax = ia32_sys_call_table[nr](regs);
-#else
-               /*
-                * It's possible that a 32-bit syscall implementation
-                * takes a 64-bit parameter but nonetheless assumes that
-                * the high bits are zero.  Make sure we zero-extend all
-                * of the args.
-                */
-               regs->ax = ia32_sys_call_table[nr](
-                       (unsigned int)regs->bx, (unsigned int)regs->cx,
-                       (unsigned int)regs->dx, (unsigned int)regs->si,
-                       (unsigned int)regs->di, (unsigned int)regs->bp);
-#endif /* CONFIG_IA32_EMULATION */
        }
 
        syscall_return_slowpath(regs);
@@ -438,3 +425,8 @@ __visible long do_fast_syscall_32(struct pt_regs *regs)
 #endif
 }
 #endif
+
+SYSCALL_DEFINE0(ni_syscall)
+{
+       return -ENOSYS;
+}
index 7e05604..b67bae7 100644 (file)
@@ -1088,10 +1088,10 @@ SYM_FUNC_START(entry_INT80_32)
        STACKLEAK_ERASE
 
 restore_all:
-       TRACE_IRQS_IRET
+       TRACE_IRQS_ON
        SWITCH_TO_ENTRY_STACK
        CHECK_AND_APPLY_ESPFIX
-.Lrestore_nocheck:
+
        /* Switch back to user CR3 */
        SWITCH_TO_USER_CR3 scratch_reg=%eax
 
@@ -1290,7 +1290,7 @@ SYM_CODE_END(simd_coprocessor_error)
 
 SYM_CODE_START(device_not_available)
        ASM_CLAC
-       pushl   $-1                             # mark this as an int
+       pushl   $0
        pushl   $do_device_not_available
        jmp     common_exception
 SYM_CODE_END(device_not_available)
@@ -1365,7 +1365,7 @@ SYM_CODE_END(divide_error)
 SYM_CODE_START(machine_check)
        ASM_CLAC
        pushl   $0
-       pushl   machine_check_vector
+       pushl   $do_mce
        jmp     common_exception
 SYM_CODE_END(machine_check)
 #endif
@@ -1531,7 +1531,7 @@ SYM_CODE_START(debug)
         * Entry from sysenter is now handled in common_exception
         */
        ASM_CLAC
-       pushl   $-1                             # mark this as an int
+       pushl   $0
        pushl   $do_debug
        jmp     common_exception
 SYM_CODE_END(debug)
@@ -1682,18 +1682,13 @@ SYM_CODE_END(nmi)
 
 SYM_CODE_START(int3)
        ASM_CLAC
-       pushl   $-1                             # mark this as an int
-
-       SAVE_ALL switch_stacks=1
-       ENCODE_FRAME_POINTER
-       TRACE_IRQS_OFF
-       xorl    %edx, %edx                      # zero error code
-       movl    %esp, %eax                      # pt_regs pointer
-       call    do_int3
-       jmp     ret_from_exception
+       pushl   $0
+       pushl   $do_int3
+       jmp     common_exception
 SYM_CODE_END(int3)
 
 SYM_CODE_START(general_protection)
+       ASM_CLAC
        pushl   $do_general_protection
        jmp     common_exception
 SYM_CODE_END(general_protection)
index f2bb91e..0e9504f 100644 (file)
@@ -174,7 +174,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
        movq    %rsp, %rsi
        call    do_syscall_64           /* returns with IRQs disabled */
 
-       TRACE_IRQS_IRETQ                /* we're about to change IF */
+       TRACE_IRQS_ON                   /* return enables interrupts */
 
        /*
         * Try to use SYSRET instead of IRET if we're returning to
@@ -619,7 +619,7 @@ ret_from_intr:
 .Lretint_user:
        mov     %rsp,%rdi
        call    prepare_exit_to_usermode
-       TRACE_IRQS_IRETQ
+       TRACE_IRQS_ON
 
 SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
 #ifdef CONFIG_DEBUG_ENTRY
index 7d17b3a..86eb0d8 100644 (file)
@@ -4,29 +4,22 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
-#include <asm/asm-offsets.h>
+#include <linux/syscalls.h>
+#include <asm/unistd.h>
 #include <asm/syscall.h>
 
-#ifdef CONFIG_IA32_EMULATION
-/* On X86_64, we use struct pt_regs * to pass parameters to syscalls */
-#define __SYSCALL_I386(nr, sym, qual) extern asmlinkage long sym(const struct pt_regs *);
-#define __sys_ni_syscall __ia32_sys_ni_syscall
-#else /* CONFIG_IA32_EMULATION */
-#define __SYSCALL_I386(nr, sym, qual) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
-extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
-#define __sys_ni_syscall sys_ni_syscall
-#endif /* CONFIG_IA32_EMULATION */
+#define __SYSCALL_I386(nr, sym) extern long __ia32_##sym(const struct pt_regs *);
 
 #include <asm/syscalls_32.h>
 #undef __SYSCALL_I386
 
-#define __SYSCALL_I386(nr, sym, qual) [nr] = sym,
+#define __SYSCALL_I386(nr, sym) [nr] = __ia32_##sym,
 
-__visible const sys_call_ptr_t ia32_sys_call_table[__NR_syscall_compat_max+1] = {
+__visible const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = {
        /*
         * Smells like a compiler bug -- it doesn't work
         * when the & below is removed.
         */
-       [0 ... __NR_syscall_compat_max] = &__sys_ni_syscall,
+       [0 ... __NR_ia32_syscall_max] = &__ia32_sys_ni_syscall,
 #include <asm/syscalls_32.h>
 };
index adf619a..1594ec7 100644 (file)
@@ -5,24 +5,17 @@
 #include <linux/sys.h>
 #include <linux/cache.h>
 #include <linux/syscalls.h>
-#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
 #include <asm/syscall.h>
 
-extern asmlinkage long sys_ni_syscall(void);
+#define __SYSCALL_X32(nr, sym)
+#define __SYSCALL_COMMON(nr, sym) __SYSCALL_64(nr, sym)
 
-SYSCALL_DEFINE0(ni_syscall)
-{
-       return sys_ni_syscall();
-}
-
-#define __SYSCALL_64(nr, sym, qual) extern asmlinkage long sym(const struct pt_regs *);
-#define __SYSCALL_X32(nr, sym, qual) __SYSCALL_64(nr, sym, qual)
+#define __SYSCALL_64(nr, sym) extern long __x64_##sym(const struct pt_regs *);
 #include <asm/syscalls_64.h>
 #undef __SYSCALL_64
-#undef __SYSCALL_X32
 
-#define __SYSCALL_64(nr, sym, qual) [nr] = sym,
-#define __SYSCALL_X32(nr, sym, qual)
+#define __SYSCALL_64(nr, sym) [nr] = __x64_##sym,
 
 asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
        /*
@@ -32,25 +25,3 @@ asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
        [0 ... __NR_syscall_max] = &__x64_sys_ni_syscall,
 #include <asm/syscalls_64.h>
 };
-
-#undef __SYSCALL_64
-#undef __SYSCALL_X32
-
-#ifdef CONFIG_X86_X32_ABI
-
-#define __SYSCALL_64(nr, sym, qual)
-#define __SYSCALL_X32(nr, sym, qual) [nr] = sym,
-
-asmlinkage const sys_call_ptr_t x32_sys_call_table[__NR_syscall_x32_max+1] = {
-       /*
-        * Smells like a compiler bug -- it doesn't work
-        * when the & below is removed.
-        */
-       [0 ... __NR_syscall_x32_max] = &__x64_sys_ni_syscall,
-#include <asm/syscalls_64.h>
-};
-
-#undef __SYSCALL_64
-#undef __SYSCALL_X32
-
-#endif
diff --git a/arch/x86/entry/syscall_x32.c b/arch/x86/entry/syscall_x32.c
new file mode 100644 (file)
index 0000000..3d8d70d
--- /dev/null
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+/* System call table for x32 ABI. */
+
+#include <linux/linkage.h>
+#include <linux/sys.h>
+#include <linux/cache.h>
+#include <linux/syscalls.h>
+#include <asm/unistd.h>
+#include <asm/syscall.h>
+
+#define __SYSCALL_64(nr, sym)
+
+#define __SYSCALL_X32(nr, sym) extern long __x32_##sym(const struct pt_regs *);
+#define __SYSCALL_COMMON(nr, sym) extern long __x64_##sym(const struct pt_regs *);
+#include <asm/syscalls_64.h>
+#undef __SYSCALL_X32
+#undef __SYSCALL_COMMON
+
+#define __SYSCALL_X32(nr, sym) [nr] = __x32_##sym,
+#define __SYSCALL_COMMON(nr, sym) [nr] = __x64_##sym,
+
+asmlinkage const sys_call_ptr_t x32_sys_call_table[__NR_x32_syscall_max+1] = {
+       /*
+        * Smells like a compiler bug -- it doesn't work
+        * when the & below is removed.
+        */
+       [0 ... __NR_x32_syscall_max] = &__x64_sys_ni_syscall,
+#include <asm/syscalls_64.h>
+};
index c17cb77..54581ac 100644 (file)
 #
 # The abi is always "i386" for this file.
 #
-0      i386    restart_syscall         sys_restart_syscall             __ia32_sys_restart_syscall
-1      i386    exit                    sys_exit                        __ia32_sys_exit
-2      i386    fork                    sys_fork                        __ia32_sys_fork
-3      i386    read                    sys_read                        __ia32_sys_read
-4      i386    write                   sys_write                       __ia32_sys_write
-5      i386    open                    sys_open                        __ia32_compat_sys_open
-6      i386    close                   sys_close                       __ia32_sys_close
-7      i386    waitpid                 sys_waitpid                     __ia32_sys_waitpid
-8      i386    creat                   sys_creat                       __ia32_sys_creat
-9      i386    link                    sys_link                        __ia32_sys_link
-10     i386    unlink                  sys_unlink                      __ia32_sys_unlink
-11     i386    execve                  sys_execve                      __ia32_compat_sys_execve
-12     i386    chdir                   sys_chdir                       __ia32_sys_chdir
-13     i386    time                    sys_time32                      __ia32_sys_time32
-14     i386    mknod                   sys_mknod                       __ia32_sys_mknod
-15     i386    chmod                   sys_chmod                       __ia32_sys_chmod
-16     i386    lchown                  sys_lchown16                    __ia32_sys_lchown16
+0      i386    restart_syscall         sys_restart_syscall
+1      i386    exit                    sys_exit
+2      i386    fork                    sys_fork
+3      i386    read                    sys_read
+4      i386    write                   sys_write
+5      i386    open                    sys_open                        compat_sys_open
+6      i386    close                   sys_close
+7      i386    waitpid                 sys_waitpid
+8      i386    creat                   sys_creat
+9      i386    link                    sys_link
+10     i386    unlink                  sys_unlink
+11     i386    execve                  sys_execve                      compat_sys_execve
+12     i386    chdir                   sys_chdir
+13     i386    time                    sys_time32
+14     i386    mknod                   sys_mknod
+15     i386    chmod                   sys_chmod
+16     i386    lchown                  sys_lchown16
 17     i386    break
-18     i386    oldstat                 sys_stat                        __ia32_sys_stat
-19     i386    lseek                   sys_lseek                       __ia32_compat_sys_lseek
-20     i386    getpid                  sys_getpid                      __ia32_sys_getpid
-21     i386    mount                   sys_mount                       __ia32_compat_sys_mount
-22     i386    umount                  sys_oldumount                   __ia32_sys_oldumount
-23     i386    setuid                  sys_setuid16                    __ia32_sys_setuid16
-24     i386    getuid                  sys_getuid16                    __ia32_sys_getuid16
-25     i386    stime                   sys_stime32                     __ia32_sys_stime32
-26     i386    ptrace                  sys_ptrace                      __ia32_compat_sys_ptrace
-27     i386    alarm                   sys_alarm                       __ia32_sys_alarm
-28     i386    oldfstat                sys_fstat                       __ia32_sys_fstat
-29     i386    pause                   sys_pause                       __ia32_sys_pause
-30     i386    utime                   sys_utime32                     __ia32_sys_utime32
+18     i386    oldstat                 sys_stat
+19     i386    lseek                   sys_lseek                       compat_sys_lseek
+20     i386    getpid                  sys_getpid
+21     i386    mount                   sys_mount                       compat_sys_mount
+22     i386    umount                  sys_oldumount
+23     i386    setuid                  sys_setuid16
+24     i386    getuid                  sys_getuid16
+25     i386    stime                   sys_stime32
+26     i386    ptrace                  sys_ptrace                      compat_sys_ptrace
+27     i386    alarm                   sys_alarm
+28     i386    oldfstat                sys_fstat
+29     i386    pause                   sys_pause
+30     i386    utime                   sys_utime32
 31     i386    stty
 32     i386    gtty
-33     i386    access                  sys_access                      __ia32_sys_access
-34     i386    nice                    sys_nice                        __ia32_sys_nice
+33     i386    access                  sys_access
+34     i386    nice                    sys_nice
 35     i386    ftime
-36     i386    sync                    sys_sync                        __ia32_sys_sync
-37     i386    kill                    sys_kill                        __ia32_sys_kill
-38     i386    rename                  sys_rename                      __ia32_sys_rename
-39     i386    mkdir                   sys_mkdir                       __ia32_sys_mkdir
-40     i386    rmdir                   sys_rmdir                       __ia32_sys_rmdir
-41     i386    dup                     sys_dup                         __ia32_sys_dup
-42     i386    pipe                    sys_pipe                        __ia32_sys_pipe
-43     i386    times                   sys_times                       __ia32_compat_sys_times
+36     i386    sync                    sys_sync
+37     i386    kill                    sys_kill
+38     i386    rename                  sys_rename
+39     i386    mkdir                   sys_mkdir
+40     i386    rmdir                   sys_rmdir
+41     i386    dup                     sys_dup
+42     i386    pipe                    sys_pipe
+43     i386    times                   sys_times                       compat_sys_times
 44     i386    prof
-45     i386    brk                     sys_brk                         __ia32_sys_brk
-46     i386    setgid                  sys_setgid16                    __ia32_sys_setgid16
-47     i386    getgid                  sys_getgid16                    __ia32_sys_getgid16
-48     i386    signal                  sys_signal                      __ia32_sys_signal
-49     i386    geteuid                 sys_geteuid16                   __ia32_sys_geteuid16
-50     i386    getegid                 sys_getegid16                   __ia32_sys_getegid16
-51     i386    acct                    sys_acct                        __ia32_sys_acct
-52     i386    umount2                 sys_umount                      __ia32_sys_umount
+45     i386    brk                     sys_brk
+46     i386    setgid                  sys_setgid16
+47     i386    getgid                  sys_getgid16
+48     i386    signal                  sys_signal
+49     i386    geteuid                 sys_geteuid16
+50     i386    getegid                 sys_getegid16
+51     i386    acct                    sys_acct
+52     i386    umount2                 sys_umount
 53     i386    lock
-54     i386    ioctl                   sys_ioctl                       __ia32_compat_sys_ioctl
-55     i386    fcntl                   sys_fcntl                       __ia32_compat_sys_fcntl64
+54     i386    ioctl                   sys_ioctl                       compat_sys_ioctl
+55     i386    fcntl                   sys_fcntl                       compat_sys_fcntl64
 56     i386    mpx
-57     i386    setpgid                 sys_setpgid                     __ia32_sys_setpgid
+57     i386    setpgid                 sys_setpgid
 58     i386    ulimit
-59     i386    oldolduname             sys_olduname                    __ia32_sys_olduname
-60     i386    umask                   sys_umask                       __ia32_sys_umask
-61     i386    chroot                  sys_chroot                      __ia32_sys_chroot
-62     i386    ustat                   sys_ustat                       __ia32_compat_sys_ustat
-63     i386    dup2                    sys_dup2                        __ia32_sys_dup2
-64     i386    getppid                 sys_getppid                     __ia32_sys_getppid
-65     i386    getpgrp                 sys_getpgrp                     __ia32_sys_getpgrp
-66     i386    setsid                  sys_setsid                      __ia32_sys_setsid
-67     i386    sigaction               sys_sigaction                   __ia32_compat_sys_sigaction
-68     i386    sgetmask                sys_sgetmask                    __ia32_sys_sgetmask
-69     i386    ssetmask                sys_ssetmask                    __ia32_sys_ssetmask
-70     i386    setreuid                sys_setreuid16                  __ia32_sys_setreuid16
-71     i386    setregid                sys_setregid16                  __ia32_sys_setregid16
-72     i386    sigsuspend              sys_sigsuspend                  __ia32_sys_sigsuspend
-73     i386    sigpending              sys_sigpending                  __ia32_compat_sys_sigpending
-74     i386    sethostname             sys_sethostname                 __ia32_sys_sethostname
-75     i386    setrlimit               sys_setrlimit                   __ia32_compat_sys_setrlimit
-76     i386    getrlimit               sys_old_getrlimit               __ia32_compat_sys_old_getrlimit
-77     i386    getrusage               sys_getrusage                   __ia32_compat_sys_getrusage
-78     i386    gettimeofday            sys_gettimeofday                __ia32_compat_sys_gettimeofday
-79     i386    settimeofday            sys_settimeofday                __ia32_compat_sys_settimeofday
-80     i386    getgroups               sys_getgroups16                 __ia32_sys_getgroups16
-81     i386    setgroups               sys_setgroups16                 __ia32_sys_setgroups16
-82     i386    select                  sys_old_select                  __ia32_compat_sys_old_select
-83     i386    symlink                 sys_symlink                     __ia32_sys_symlink
-84     i386    oldlstat                sys_lstat                       __ia32_sys_lstat
-85     i386    readlink                sys_readlink                    __ia32_sys_readlink
-86     i386    uselib                  sys_uselib                      __ia32_sys_uselib
-87     i386    swapon                  sys_swapon                      __ia32_sys_swapon
-88     i386    reboot                  sys_reboot                      __ia32_sys_reboot
-89     i386    readdir                 sys_old_readdir                 __ia32_compat_sys_old_readdir
-90     i386    mmap                    sys_old_mmap                    __ia32_compat_sys_x86_mmap
-91     i386    munmap                  sys_munmap                      __ia32_sys_munmap
-92     i386    truncate                sys_truncate                    __ia32_compat_sys_truncate
-93     i386    ftruncate               sys_ftruncate                   __ia32_compat_sys_ftruncate
-94     i386    fchmod                  sys_fchmod                      __ia32_sys_fchmod
-95     i386    fchown                  sys_fchown16                    __ia32_sys_fchown16
-96     i386    getpriority             sys_getpriority                 __ia32_sys_getpriority
-97     i386    setpriority             sys_setpriority                 __ia32_sys_setpriority
+59     i386    oldolduname             sys_olduname
+60     i386    umask                   sys_umask
+61     i386    chroot                  sys_chroot
+62     i386    ustat                   sys_ustat                       compat_sys_ustat
+63     i386    dup2                    sys_dup2
+64     i386    getppid                 sys_getppid
+65     i386    getpgrp                 sys_getpgrp
+66     i386    setsid                  sys_setsid
+67     i386    sigaction               sys_sigaction                   compat_sys_sigaction
+68     i386    sgetmask                sys_sgetmask
+69     i386    ssetmask                sys_ssetmask
+70     i386    setreuid                sys_setreuid16
+71     i386    setregid                sys_setregid16
+72     i386    sigsuspend              sys_sigsuspend
+73     i386    sigpending              sys_sigpending                  compat_sys_sigpending
+74     i386    sethostname             sys_sethostname
+75     i386    setrlimit               sys_setrlimit                   compat_sys_setrlimit
+76     i386    getrlimit               sys_old_getrlimit               compat_sys_old_getrlimit
+77     i386    getrusage               sys_getrusage                   compat_sys_getrusage
+78     i386    gettimeofday            sys_gettimeofday                compat_sys_gettimeofday
+79     i386    settimeofday            sys_settimeofday                compat_sys_settimeofday
+80     i386    getgroups               sys_getgroups16
+81     i386    setgroups               sys_setgroups16
+82     i386    select                  sys_old_select                  compat_sys_old_select
+83     i386    symlink                 sys_symlink
+84     i386    oldlstat                sys_lstat
+85     i386    readlink                sys_readlink
+86     i386    uselib                  sys_uselib
+87     i386    swapon                  sys_swapon
+88     i386    reboot                  sys_reboot
+89     i386    readdir                 sys_old_readdir                 compat_sys_old_readdir
+90     i386    mmap                    sys_old_mmap                    compat_sys_ia32_mmap
+91     i386    munmap                  sys_munmap
+92     i386    truncate                sys_truncate                    compat_sys_truncate
+93     i386    ftruncate               sys_ftruncate                   compat_sys_ftruncate
+94     i386    fchmod                  sys_fchmod
+95     i386    fchown                  sys_fchown16
+96     i386    getpriority             sys_getpriority
+97     i386    setpriority             sys_setpriority
 98     i386    profil
-99     i386    statfs                  sys_statfs                      __ia32_compat_sys_statfs
-100    i386    fstatfs                 sys_fstatfs                     __ia32_compat_sys_fstatfs
-101    i386    ioperm                  sys_ioperm                      __ia32_sys_ioperm
-102    i386    socketcall              sys_socketcall                  __ia32_compat_sys_socketcall
-103    i386    syslog                  sys_syslog                      __ia32_sys_syslog
-104    i386    setitimer               sys_setitimer                   __ia32_compat_sys_setitimer
-105    i386    getitimer               sys_getitimer                   __ia32_compat_sys_getitimer
-106    i386    stat                    sys_newstat                     __ia32_compat_sys_newstat
-107    i386    lstat                   sys_newlstat                    __ia32_compat_sys_newlstat
-108    i386    fstat                   sys_newfstat                    __ia32_compat_sys_newfstat
-109    i386    olduname                sys_uname                       __ia32_sys_uname
-110    i386    iopl                    sys_iopl                        __ia32_sys_iopl
-111    i386    vhangup                 sys_vhangup                     __ia32_sys_vhangup
+99     i386    statfs                  sys_statfs                      compat_sys_statfs
+100    i386    fstatfs                 sys_fstatfs                     compat_sys_fstatfs
+101    i386    ioperm                  sys_ioperm
+102    i386    socketcall              sys_socketcall                  compat_sys_socketcall
+103    i386    syslog                  sys_syslog
+104    i386    setitimer               sys_setitimer                   compat_sys_setitimer
+105    i386    getitimer               sys_getitimer                   compat_sys_getitimer
+106    i386    stat                    sys_newstat                     compat_sys_newstat
+107    i386    lstat                   sys_newlstat                    compat_sys_newlstat
+108    i386    fstat                   sys_newfstat                    compat_sys_newfstat
+109    i386    olduname                sys_uname
+110    i386    iopl                    sys_iopl
+111    i386    vhangup                 sys_vhangup
 112    i386    idle
-113    i386    vm86old                 sys_vm86old                     __ia32_sys_ni_syscall
-114    i386    wait4                   sys_wait4                       __ia32_compat_sys_wait4
-115    i386    swapoff                 sys_swapoff                     __ia32_sys_swapoff
-116    i386    sysinfo                 sys_sysinfo                     __ia32_compat_sys_sysinfo
-117    i386    ipc                     sys_ipc                         __ia32_compat_sys_ipc
-118    i386    fsync                   sys_fsync                       __ia32_sys_fsync
-119    i386    sigreturn               sys_sigreturn                   __ia32_compat_sys_sigreturn
-120    i386    clone                   sys_clone                       __ia32_compat_sys_x86_clone
-121    i386    setdomainname           sys_setdomainname               __ia32_sys_setdomainname
-122    i386    uname                   sys_newuname                    __ia32_sys_newuname
-123    i386    modify_ldt              sys_modify_ldt                  __ia32_sys_modify_ldt
-124    i386    adjtimex                sys_adjtimex_time32                     __ia32_sys_adjtimex_time32
-125    i386    mprotect                sys_mprotect                    __ia32_sys_mprotect
-126    i386    sigprocmask             sys_sigprocmask                 __ia32_compat_sys_sigprocmask
+113    i386    vm86old                 sys_vm86old                     sys_ni_syscall
+114    i386    wait4                   sys_wait4                       compat_sys_wait4
+115    i386    swapoff                 sys_swapoff
+116    i386    sysinfo                 sys_sysinfo                     compat_sys_sysinfo
+117    i386    ipc                     sys_ipc                         compat_sys_ipc
+118    i386    fsync                   sys_fsync
+119    i386    sigreturn               sys_sigreturn                   compat_sys_sigreturn
+120    i386    clone                   sys_clone                       compat_sys_ia32_clone
+121    i386    setdomainname           sys_setdomainname
+122    i386    uname                   sys_newuname
+123    i386    modify_ldt              sys_modify_ldt
+124    i386    adjtimex                sys_adjtimex_time32
+125    i386    mprotect                sys_mprotect
+126    i386    sigprocmask             sys_sigprocmask                 compat_sys_sigprocmask
 127    i386    create_module
-128    i386    init_module             sys_init_module                 __ia32_sys_init_module
-129    i386    delete_module           sys_delete_module               __ia32_sys_delete_module
+128    i386    init_module             sys_init_module
+129    i386    delete_module           sys_delete_module
 130    i386    get_kernel_syms
-131    i386    quotactl                sys_quotactl                    __ia32_compat_sys_quotactl32
-132    i386    getpgid                 sys_getpgid                     __ia32_sys_getpgid
-133    i386    fchdir                  sys_fchdir                      __ia32_sys_fchdir
-134    i386    bdflush                 sys_bdflush                     __ia32_sys_bdflush
-135    i386    sysfs                   sys_sysfs                       __ia32_sys_sysfs
-136    i386    personality             sys_personality                 __ia32_sys_personality
+131    i386    quotactl                sys_quotactl                    compat_sys_quotactl32
+132    i386    getpgid                 sys_getpgid
+133    i386    fchdir                  sys_fchdir
+134    i386    bdflush                 sys_bdflush
+135    i386    sysfs                   sys_sysfs
+136    i386    personality             sys_personality
 137    i386    afs_syscall
-138    i386    setfsuid                sys_setfsuid16                  __ia32_sys_setfsuid16
-139    i386    setfsgid                sys_setfsgid16                  __ia32_sys_setfsgid16
-140    i386    _llseek                 sys_llseek                      __ia32_sys_llseek
-141    i386    getdents                sys_getdents                    __ia32_compat_sys_getdents
-142    i386    _newselect              sys_select                      __ia32_compat_sys_select
-143    i386    flock                   sys_flock                       __ia32_sys_flock
-144    i386    msync                   sys_msync                       __ia32_sys_msync
-145    i386    readv                   sys_readv                       __ia32_compat_sys_readv
-146    i386    writev                  sys_writev                      __ia32_compat_sys_writev
-147    i386    getsid                  sys_getsid                      __ia32_sys_getsid
-148    i386    fdatasync               sys_fdatasync                   __ia32_sys_fdatasync
-149    i386    _sysctl                 sys_sysctl                      __ia32_compat_sys_sysctl
-150    i386    mlock                   sys_mlock                       __ia32_sys_mlock
-151    i386    munlock                 sys_munlock                     __ia32_sys_munlock
-152    i386    mlockall                sys_mlockall                    __ia32_sys_mlockall
-153    i386    munlockall              sys_munlockall                  __ia32_sys_munlockall
-154    i386    sched_setparam          sys_sched_setparam              __ia32_sys_sched_setparam
-155    i386    sched_getparam          sys_sched_getparam              __ia32_sys_sched_getparam
-156    i386    sched_setscheduler      sys_sched_setscheduler          __ia32_sys_sched_setscheduler
-157    i386    sched_getscheduler      sys_sched_getscheduler          __ia32_sys_sched_getscheduler
-158    i386    sched_yield             sys_sched_yield                 __ia32_sys_sched_yield
-159    i386    sched_get_priority_max  sys_sched_get_priority_max      __ia32_sys_sched_get_priority_max
-160    i386    sched_get_priority_min  sys_sched_get_priority_min      __ia32_sys_sched_get_priority_min
-161    i386    sched_rr_get_interval   sys_sched_rr_get_interval_time32        __ia32_sys_sched_rr_get_interval_time32
-162    i386    nanosleep               sys_nanosleep_time32            __ia32_sys_nanosleep_time32
-163    i386    mremap                  sys_mremap                      __ia32_sys_mremap
-164    i386    setresuid               sys_setresuid16                 __ia32_sys_setresuid16
-165    i386    getresuid               sys_getresuid16                 __ia32_sys_getresuid16
-166    i386    vm86                    sys_vm86                        __ia32_sys_ni_syscall
+138    i386    setfsuid                sys_setfsuid16
+139    i386    setfsgid                sys_setfsgid16
+140    i386    _llseek                 sys_llseek
+141    i386    getdents                sys_getdents                    compat_sys_getdents
+142    i386    _newselect              sys_select                      compat_sys_select
+143    i386    flock                   sys_flock
+144    i386    msync                   sys_msync
+145    i386    readv                   sys_readv                       compat_sys_readv
+146    i386    writev                  sys_writev                      compat_sys_writev
+147    i386    getsid                  sys_getsid
+148    i386    fdatasync               sys_fdatasync
+149    i386    _sysctl                 sys_sysctl                      compat_sys_sysctl
+150    i386    mlock                   sys_mlock
+151    i386    munlock                 sys_munlock
+152    i386    mlockall                sys_mlockall
+153    i386    munlockall              sys_munlockall
+154    i386    sched_setparam          sys_sched_setparam
+155    i386    sched_getparam          sys_sched_getparam
+156    i386    sched_setscheduler      sys_sched_setscheduler
+157    i386    sched_getscheduler      sys_sched_getscheduler
+158    i386    sched_yield             sys_sched_yield
+159    i386    sched_get_priority_max  sys_sched_get_priority_max
+160    i386    sched_get_priority_min  sys_sched_get_priority_min
+161    i386    sched_rr_get_interval   sys_sched_rr_get_interval_time32
+162    i386    nanosleep               sys_nanosleep_time32
+163    i386    mremap                  sys_mremap
+164    i386    setresuid               sys_setresuid16
+165    i386    getresuid               sys_getresuid16
+166    i386    vm86                    sys_vm86                        sys_ni_syscall
 167    i386    query_module
-168    i386    poll                    sys_poll                        __ia32_sys_poll
+168    i386    poll                    sys_poll
 169    i386    nfsservctl
-170    i386    setresgid               sys_setresgid16                 __ia32_sys_setresgid16
-171    i386    getresgid               sys_getresgid16                 __ia32_sys_getresgid16
-172    i386    prctl                   sys_prctl                       __ia32_sys_prctl
-173    i386    rt_sigreturn            sys_rt_sigreturn                __ia32_compat_sys_rt_sigreturn
-174    i386    rt_sigaction            sys_rt_sigaction                __ia32_compat_sys_rt_sigaction
-175    i386    rt_sigprocmask          sys_rt_sigprocmask              __ia32_compat_sys_rt_sigprocmask
-176    i386    rt_sigpending           sys_rt_sigpending               __ia32_compat_sys_rt_sigpending
-177    i386    rt_sigtimedwait         sys_rt_sigtimedwait_time32      __ia32_compat_sys_rt_sigtimedwait_time32
-178    i386    rt_sigqueueinfo         sys_rt_sigqueueinfo             __ia32_compat_sys_rt_sigqueueinfo
-179    i386    rt_sigsuspend           sys_rt_sigsuspend               __ia32_compat_sys_rt_sigsuspend
-180    i386    pread64                 sys_pread64                     __ia32_compat_sys_x86_pread
-181    i386    pwrite64                sys_pwrite64                    __ia32_compat_sys_x86_pwrite
-182    i386    chown                   sys_chown16                     __ia32_sys_chown16
-183    i386    getcwd                  sys_getcwd                      __ia32_sys_getcwd
-184    i386    capget                  sys_capget                      __ia32_sys_capget
-185    i386    capset                  sys_capset                      __ia32_sys_capset
-186    i386    sigaltstack             sys_sigaltstack                 __ia32_compat_sys_sigaltstack
-187    i386    sendfile                sys_sendfile                    __ia32_compat_sys_sendfile
+170    i386    setresgid               sys_setresgid16
+171    i386    getresgid               sys_getresgid16
+172    i386    prctl                   sys_prctl
+173    i386    rt_sigreturn            sys_rt_sigreturn                compat_sys_rt_sigreturn
+174    i386    rt_sigaction            sys_rt_sigaction                compat_sys_rt_sigaction
+175    i386    rt_sigprocmask          sys_rt_sigprocmask              compat_sys_rt_sigprocmask
+176    i386    rt_sigpending           sys_rt_sigpending               compat_sys_rt_sigpending
+177    i386    rt_sigtimedwait         sys_rt_sigtimedwait_time32      compat_sys_rt_sigtimedwait_time32
+178    i386    rt_sigqueueinfo         sys_rt_sigqueueinfo             compat_sys_rt_sigqueueinfo
+179    i386    rt_sigsuspend           sys_rt_sigsuspend               compat_sys_rt_sigsuspend
+180    i386    pread64                 sys_ia32_pread64
+181    i386    pwrite64                sys_ia32_pwrite64
+182    i386    chown                   sys_chown16
+183    i386    getcwd                  sys_getcwd
+184    i386    capget                  sys_capget
+185    i386    capset                  sys_capset
+186    i386    sigaltstack             sys_sigaltstack                 compat_sys_sigaltstack
+187    i386    sendfile                sys_sendfile                    compat_sys_sendfile
 188    i386    getpmsg
 189    i386    putpmsg
-190    i386    vfork                   sys_vfork                       __ia32_sys_vfork
-191    i386    ugetrlimit              sys_getrlimit                   __ia32_compat_sys_getrlimit
-192    i386    mmap2                   sys_mmap_pgoff                  __ia32_sys_mmap_pgoff
-193    i386    truncate64              sys_truncate64                  __ia32_compat_sys_x86_truncate64
-194    i386    ftruncate64             sys_ftruncate64                 __ia32_compat_sys_x86_ftruncate64
-195    i386    stat64                  sys_stat64                      __ia32_compat_sys_x86_stat64
-196    i386    lstat64                 sys_lstat64                     __ia32_compat_sys_x86_lstat64
-197    i386    fstat64                 sys_fstat64                     __ia32_compat_sys_x86_fstat64
-198    i386    lchown32                sys_lchown                      __ia32_sys_lchown
-199    i386    getuid32                sys_getuid                      __ia32_sys_getuid
-200    i386    getgid32                sys_getgid                      __ia32_sys_getgid
-201    i386    geteuid32               sys_geteuid                     __ia32_sys_geteuid
-202    i386    getegid32               sys_getegid                     __ia32_sys_getegid
-203    i386    setreuid32              sys_setreuid                    __ia32_sys_setreuid
-204    i386    setregid32              sys_setregid                    __ia32_sys_setregid
-205    i386    getgroups32             sys_getgroups                   __ia32_sys_getgroups
-206    i386    setgroups32             sys_setgroups                   __ia32_sys_setgroups
-207    i386    fchown32                sys_fchown                      __ia32_sys_fchown
-208    i386    setresuid32             sys_setresuid                   __ia32_sys_setresuid
-209    i386    getresuid32             sys_getresuid                   __ia32_sys_getresuid
-210    i386    setresgid32             sys_setresgid                   __ia32_sys_setresgid
-211    i386    getresgid32             sys_getresgid                   __ia32_sys_getresgid
-212    i386    chown32                 sys_chown                       __ia32_sys_chown
-213    i386    setuid32                sys_setuid                      __ia32_sys_setuid
-214    i386    setgid32                sys_setgid                      __ia32_sys_setgid
-215    i386    setfsuid32              sys_setfsuid                    __ia32_sys_setfsuid
-216    i386    setfsgid32              sys_setfsgid                    __ia32_sys_setfsgid
-217    i386    pivot_root              sys_pivot_root                  __ia32_sys_pivot_root
-218    i386    mincore                 sys_mincore                     __ia32_sys_mincore
-219    i386    madvise                 sys_madvise                     __ia32_sys_madvise
-220    i386    getdents64              sys_getdents64                  __ia32_sys_getdents64
-221    i386    fcntl64                 sys_fcntl64                     __ia32_compat_sys_fcntl64
+190    i386    vfork                   sys_vfork
+191    i386    ugetrlimit              sys_getrlimit                   compat_sys_getrlimit
+192    i386    mmap2                   sys_mmap_pgoff
+193    i386    truncate64              sys_ia32_truncate64
+194    i386    ftruncate64             sys_ia32_ftruncate64
+195    i386    stat64                  sys_stat64                      compat_sys_ia32_stat64
+196    i386    lstat64                 sys_lstat64                     compat_sys_ia32_lstat64
+197    i386    fstat64                 sys_fstat64                     compat_sys_ia32_fstat64
+198    i386    lchown32                sys_lchown
+199    i386    getuid32                sys_getuid
+200    i386    getgid32                sys_getgid
+201    i386    geteuid32               sys_geteuid
+202    i386    getegid32               sys_getegid
+203    i386    setreuid32              sys_setreuid
+204    i386    setregid32              sys_setregid
+205    i386    getgroups32             sys_getgroups
+206    i386    setgroups32             sys_setgroups
+207    i386    fchown32                sys_fchown
+208    i386    setresuid32             sys_setresuid
+209    i386    getresuid32             sys_getresuid
+210    i386    setresgid32             sys_setresgid
+211    i386    getresgid32             sys_getresgid
+212    i386    chown32                 sys_chown
+213    i386    setuid32                sys_setuid
+214    i386    setgid32                sys_setgid
+215    i386    setfsuid32              sys_setfsuid
+216    i386    setfsgid32              sys_setfsgid
+217    i386    pivot_root              sys_pivot_root
+218    i386    mincore                 sys_mincore
+219    i386    madvise                 sys_madvise
+220    i386    getdents64              sys_getdents64
+221    i386    fcntl64                 sys_fcntl64                     compat_sys_fcntl64
 # 222 is unused
 # 223 is unused
-224    i386    gettid                  sys_gettid                      __ia32_sys_gettid
-225    i386    readahead               sys_readahead                   __ia32_compat_sys_x86_readahead
-226    i386    setxattr                sys_setxattr                    __ia32_sys_setxattr
-227    i386    lsetxattr               sys_lsetxattr                   __ia32_sys_lsetxattr
-228    i386    fsetxattr               sys_fsetxattr                   __ia32_sys_fsetxattr
-229    i386    getxattr                sys_getxattr                    __ia32_sys_getxattr
-230    i386    lgetxattr               sys_lgetxattr                   __ia32_sys_lgetxattr
-231    i386    fgetxattr               sys_fgetxattr                   __ia32_sys_fgetxattr
-232    i386    listxattr               sys_listxattr                   __ia32_sys_listxattr
-233    i386    llistxattr              sys_llistxattr                  __ia32_sys_llistxattr
-234    i386    flistxattr              sys_flistxattr                  __ia32_sys_flistxattr
-235    i386    removexattr             sys_removexattr                 __ia32_sys_removexattr
-236    i386    lremovexattr            sys_lremovexattr                __ia32_sys_lremovexattr
-237    i386    fremovexattr            sys_fremovexattr                __ia32_sys_fremovexattr
-238    i386    tkill                   sys_tkill                       __ia32_sys_tkill
-239    i386    sendfile64              sys_sendfile64                  __ia32_sys_sendfile64
-240    i386    futex                   sys_futex_time32                __ia32_sys_futex_time32
-241    i386    sched_setaffinity       sys_sched_setaffinity           __ia32_compat_sys_sched_setaffinity
-242    i386    sched_getaffinity       sys_sched_getaffinity           __ia32_compat_sys_sched_getaffinity
-243    i386    set_thread_area         sys_set_thread_area             __ia32_sys_set_thread_area
-244    i386    get_thread_area         sys_get_thread_area             __ia32_sys_get_thread_area
-245    i386    io_setup                sys_io_setup                    __ia32_compat_sys_io_setup
-246    i386    io_destroy              sys_io_destroy                  __ia32_sys_io_destroy
-247    i386    io_getevents            sys_io_getevents_time32         __ia32_sys_io_getevents_time32
-248    i386    io_submit               sys_io_submit                   __ia32_compat_sys_io_submit
-249    i386    io_cancel               sys_io_cancel                   __ia32_sys_io_cancel
-250    i386    fadvise64               sys_fadvise64                   __ia32_compat_sys_x86_fadvise64
+224    i386    gettid                  sys_gettid
+225    i386    readahead               sys_ia32_readahead
+226    i386    setxattr                sys_setxattr
+227    i386    lsetxattr               sys_lsetxattr
+228    i386    fsetxattr               sys_fsetxattr
+229    i386    getxattr                sys_getxattr
+230    i386    lgetxattr               sys_lgetxattr
+231    i386    fgetxattr               sys_fgetxattr
+232    i386    listxattr               sys_listxattr
+233    i386    llistxattr              sys_llistxattr
+234    i386    flistxattr              sys_flistxattr
+235    i386    removexattr             sys_removexattr
+236    i386    lremovexattr            sys_lremovexattr
+237    i386    fremovexattr            sys_fremovexattr
+238    i386    tkill                   sys_tkill
+239    i386    sendfile64              sys_sendfile64
+240    i386    futex                   sys_futex_time32
+241    i386    sched_setaffinity       sys_sched_setaffinity           compat_sys_sched_setaffinity
+242    i386    sched_getaffinity       sys_sched_getaffinity           compat_sys_sched_getaffinity
+243    i386    set_thread_area         sys_set_thread_area
+244    i386    get_thread_area         sys_get_thread_area
+245    i386    io_setup                sys_io_setup                    compat_sys_io_setup
+246    i386    io_destroy              sys_io_destroy
+247    i386    io_getevents            sys_io_getevents_time32
+248    i386    io_submit               sys_io_submit                   compat_sys_io_submit
+249    i386    io_cancel               sys_io_cancel
+250    i386    fadvise64               sys_ia32_fadvise64
 # 251 is available for reuse (was briefly sys_set_zone_reclaim)
-252    i386    exit_group              sys_exit_group                  __ia32_sys_exit_group
-253    i386    lookup_dcookie          sys_lookup_dcookie              __ia32_compat_sys_lookup_dcookie
-254    i386    epoll_create            sys_epoll_create                __ia32_sys_epoll_create
-255    i386    epoll_ctl               sys_epoll_ctl                   __ia32_sys_epoll_ctl
-256    i386    epoll_wait              sys_epoll_wait                  __ia32_sys_epoll_wait
-257    i386    remap_file_pages        sys_remap_file_pages            __ia32_sys_remap_file_pages
-258    i386    set_tid_address         sys_set_tid_address             __ia32_sys_set_tid_address
-259    i386    timer_create            sys_timer_create                __ia32_compat_sys_timer_create
-260    i386    timer_settime           sys_timer_settime32             __ia32_sys_timer_settime32
-261    i386    timer_gettime           sys_timer_gettime32             __ia32_sys_timer_gettime32
-262    i386    timer_getoverrun        sys_timer_getoverrun            __ia32_sys_timer_getoverrun
-263    i386    timer_delete            sys_timer_delete                __ia32_sys_timer_delete
-264    i386    clock_settime           sys_clock_settime32             __ia32_sys_clock_settime32
-265    i386    clock_gettime           sys_clock_gettime32             __ia32_sys_clock_gettime32
-266    i386    clock_getres            sys_clock_getres_time32         __ia32_sys_clock_getres_time32
-267    i386    clock_nanosleep         sys_clock_nanosleep_time32      __ia32_sys_clock_nanosleep_time32
-268    i386    statfs64                sys_statfs64                    __ia32_compat_sys_statfs64
-269    i386    fstatfs64               sys_fstatfs64                   __ia32_compat_sys_fstatfs64
-270    i386    tgkill                  sys_tgkill                      __ia32_sys_tgkill
-271    i386    utimes                  sys_utimes_time32               __ia32_sys_utimes_time32
-272    i386    fadvise64_64            sys_fadvise64_64                __ia32_compat_sys_x86_fadvise64_64
+252    i386    exit_group              sys_exit_group
+253    i386    lookup_dcookie          sys_lookup_dcookie              compat_sys_lookup_dcookie
+254    i386    epoll_create            sys_epoll_create
+255    i386    epoll_ctl               sys_epoll_ctl
+256    i386    epoll_wait              sys_epoll_wait
+257    i386    remap_file_pages        sys_remap_file_pages
+258    i386    set_tid_address         sys_set_tid_address
+259    i386    timer_create            sys_timer_create                compat_sys_timer_create
+260    i386    timer_settime           sys_timer_settime32
+261    i386    timer_gettime           sys_timer_gettime32
+262    i386    timer_getoverrun        sys_timer_getoverrun
+263    i386    timer_delete            sys_timer_delete
+264    i386    clock_settime           sys_clock_settime32
+265    i386    clock_gettime           sys_clock_gettime32
+266    i386    clock_getres            sys_clock_getres_time32
+267    i386    clock_nanosleep         sys_clock_nanosleep_time32
+268    i386    statfs64                sys_statfs64                    compat_sys_statfs64
+269    i386    fstatfs64               sys_fstatfs64                   compat_sys_fstatfs64
+270    i386    tgkill                  sys_tgkill
+271    i386    utimes                  sys_utimes_time32
+272    i386    fadvise64_64            sys_ia32_fadvise64_64
 273    i386    vserver
-274    i386    mbind                   sys_mbind                       __ia32_sys_mbind
-275    i386    get_mempolicy           sys_get_mempolicy               __ia32_compat_sys_get_mempolicy
-276    i386    set_mempolicy           sys_set_mempolicy               __ia32_sys_set_mempolicy
-277    i386    mq_open                 sys_mq_open                     __ia32_compat_sys_mq_open
-278    i386    mq_unlink               sys_mq_unlink                   __ia32_sys_mq_unlink
-279    i386    mq_timedsend            sys_mq_timedsend_time32         __ia32_sys_mq_timedsend_time32
-280    i386    mq_timedreceive         sys_mq_timedreceive_time32      __ia32_sys_mq_timedreceive_time32
-281    i386    mq_notify               sys_mq_notify                   __ia32_compat_sys_mq_notify
-282    i386    mq_getsetattr           sys_mq_getsetattr               __ia32_compat_sys_mq_getsetattr
-283    i386    kexec_load              sys_kexec_load                  __ia32_compat_sys_kexec_load
-284    i386    waitid                  sys_waitid                      __ia32_compat_sys_waitid
+274    i386    mbind                   sys_mbind
+275    i386    get_mempolicy           sys_get_mempolicy               compat_sys_get_mempolicy
+276    i386    set_mempolicy           sys_set_mempolicy
+277    i386    mq_open                 sys_mq_open                     compat_sys_mq_open
+278    i386    mq_unlink               sys_mq_unlink
+279    i386    mq_timedsend            sys_mq_timedsend_time32
+280    i386    mq_timedreceive         sys_mq_timedreceive_time32
+281    i386    mq_notify               sys_mq_notify                   compat_sys_mq_notify
+282    i386    mq_getsetattr           sys_mq_getsetattr               compat_sys_mq_getsetattr
+283    i386    kexec_load              sys_kexec_load                  compat_sys_kexec_load
+284    i386    waitid                  sys_waitid                      compat_sys_waitid
 # 285 sys_setaltroot
-286    i386    add_key                 sys_add_key                     __ia32_sys_add_key
-287    i386    request_key             sys_request_key                 __ia32_sys_request_key
-288    i386    keyctl                  sys_keyctl                      __ia32_compat_sys_keyctl
-289    i386    ioprio_set              sys_ioprio_set                  __ia32_sys_ioprio_set
-290    i386    ioprio_get              sys_ioprio_get                  __ia32_sys_ioprio_get
-291    i386    inotify_init            sys_inotify_init                __ia32_sys_inotify_init
-292    i386    inotify_add_watch       sys_inotify_add_watch           __ia32_sys_inotify_add_watch
-293    i386    inotify_rm_watch        sys_inotify_rm_watch            __ia32_sys_inotify_rm_watch
-294    i386    migrate_pages           sys_migrate_pages               __ia32_sys_migrate_pages
-295    i386    openat                  sys_openat                      __ia32_compat_sys_openat
-296    i386    mkdirat                 sys_mkdirat                     __ia32_sys_mkdirat
-297    i386    mknodat                 sys_mknodat                     __ia32_sys_mknodat
-298    i386    fchownat                sys_fchownat                    __ia32_sys_fchownat
-299    i386    futimesat               sys_futimesat_time32            __ia32_sys_futimesat_time32
-300    i386    fstatat64               sys_fstatat64                   __ia32_compat_sys_x86_fstatat
-301    i386    unlinkat                sys_unlinkat                    __ia32_sys_unlinkat
-302    i386    renameat                sys_renameat                    __ia32_sys_renameat
-303    i386    linkat                  sys_linkat                      __ia32_sys_linkat
-304    i386    symlinkat               sys_symlinkat                   __ia32_sys_symlinkat
-305    i386    readlinkat              sys_readlinkat                  __ia32_sys_readlinkat
-306    i386    fchmodat                sys_fchmodat                    __ia32_sys_fchmodat
-307    i386    faccessat               sys_faccessat                   __ia32_sys_faccessat
-308    i386    pselect6                sys_pselect6_time32             __ia32_compat_sys_pselect6_time32
-309    i386    ppoll                   sys_ppoll_time32                __ia32_compat_sys_ppoll_time32
-310    i386    unshare                 sys_unshare                     __ia32_sys_unshare
-311    i386    set_robust_list         sys_set_robust_list             __ia32_compat_sys_set_robust_list
-312    i386    get_robust_list         sys_get_robust_list             __ia32_compat_sys_get_robust_list
-313    i386    splice                  sys_splice                      __ia32_sys_splice
-314    i386    sync_file_range         sys_sync_file_range             __ia32_compat_sys_x86_sync_file_range
-315    i386    tee                     sys_tee                         __ia32_sys_tee
-316    i386    vmsplice                sys_vmsplice                    __ia32_compat_sys_vmsplice
-317    i386    move_pages              sys_move_pages                  __ia32_compat_sys_move_pages
-318    i386    getcpu                  sys_getcpu                      __ia32_sys_getcpu
-319    i386    epoll_pwait             sys_epoll_pwait                 __ia32_sys_epoll_pwait
-320    i386    utimensat               sys_utimensat_time32            __ia32_sys_utimensat_time32
-321    i386    signalfd                sys_signalfd                    __ia32_compat_sys_signalfd
-322    i386    timerfd_create          sys_timerfd_create              __ia32_sys_timerfd_create
-323    i386    eventfd                 sys_eventfd                     __ia32_sys_eventfd
-324    i386    fallocate               sys_fallocate                   __ia32_compat_sys_x86_fallocate
-325    i386    timerfd_settime         sys_timerfd_settime32           __ia32_sys_timerfd_settime32
-326    i386    timerfd_gettime         sys_timerfd_gettime32           __ia32_sys_timerfd_gettime32
-327    i386    signalfd4               sys_signalfd4                   __ia32_compat_sys_signalfd4
-328    i386    eventfd2                sys_eventfd2                    __ia32_sys_eventfd2
-329    i386    epoll_create1           sys_epoll_create1               __ia32_sys_epoll_create1
-330    i386    dup3                    sys_dup3                        __ia32_sys_dup3
-331    i386    pipe2                   sys_pipe2                       __ia32_sys_pipe2
-332    i386    inotify_init1           sys_inotify_init1               __ia32_sys_inotify_init1
-333    i386    preadv                  sys_preadv                      __ia32_compat_sys_preadv
-334    i386    pwritev                 sys_pwritev                     __ia32_compat_sys_pwritev
-335    i386    rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo           __ia32_compat_sys_rt_tgsigqueueinfo
-336    i386    perf_event_open         sys_perf_event_open             __ia32_sys_perf_event_open
-337    i386    recvmmsg                sys_recvmmsg_time32             __ia32_compat_sys_recvmmsg_time32
-338    i386    fanotify_init           sys_fanotify_init               __ia32_sys_fanotify_init
-339    i386    fanotify_mark           sys_fanotify_mark               __ia32_compat_sys_fanotify_mark
-340    i386    prlimit64               sys_prlimit64                   __ia32_sys_prlimit64
-341    i386    name_to_handle_at       sys_name_to_handle_at           __ia32_sys_name_to_handle_at
-342    i386    open_by_handle_at       sys_open_by_handle_at           __ia32_compat_sys_open_by_handle_at
-343    i386    clock_adjtime           sys_clock_adjtime32             __ia32_sys_clock_adjtime32
-344    i386    syncfs                  sys_syncfs                      __ia32_sys_syncfs
-345    i386    sendmmsg                sys_sendmmsg                    __ia32_compat_sys_sendmmsg
-346    i386    setns                   sys_setns                       __ia32_sys_setns
-347    i386    process_vm_readv        sys_process_vm_readv            __ia32_compat_sys_process_vm_readv
-348    i386    process_vm_writev       sys_process_vm_writev           __ia32_compat_sys_process_vm_writev
-349    i386    kcmp                    sys_kcmp                        __ia32_sys_kcmp
-350    i386    finit_module            sys_finit_module                __ia32_sys_finit_module
-351    i386    sched_setattr           sys_sched_setattr               __ia32_sys_sched_setattr
-352    i386    sched_getattr           sys_sched_getattr               __ia32_sys_sched_getattr
-353    i386    renameat2               sys_renameat2                   __ia32_sys_renameat2
-354    i386    seccomp                 sys_seccomp                     __ia32_sys_seccomp
-355    i386    getrandom               sys_getrandom                   __ia32_sys_getrandom
-356    i386    memfd_create            sys_memfd_create                __ia32_sys_memfd_create
-357    i386    bpf                     sys_bpf                         __ia32_sys_bpf
-358    i386    execveat                sys_execveat                    __ia32_compat_sys_execveat
-359    i386    socket                  sys_socket                      __ia32_sys_socket
-360    i386    socketpair              sys_socketpair                  __ia32_sys_socketpair
-361    i386    bind                    sys_bind                        __ia32_sys_bind
-362    i386    connect                 sys_connect                     __ia32_sys_connect
-363    i386    listen                  sys_listen                      __ia32_sys_listen
-364    i386    accept4                 sys_accept4                     __ia32_sys_accept4
-365    i386    getsockopt              sys_getsockopt                  __ia32_compat_sys_getsockopt
-366    i386    setsockopt              sys_setsockopt                  __ia32_compat_sys_setsockopt
-367    i386    getsockname             sys_getsockname                 __ia32_sys_getsockname
-368    i386    getpeername             sys_getpeername                 __ia32_sys_getpeername
-369    i386    sendto                  sys_sendto                      __ia32_sys_sendto
-370    i386    sendmsg                 sys_sendmsg                     __ia32_compat_sys_sendmsg
-371    i386    recvfrom                sys_recvfrom                    __ia32_compat_sys_recvfrom
-372    i386    recvmsg                 sys_recvmsg                     __ia32_compat_sys_recvmsg
-373    i386    shutdown                sys_shutdown                    __ia32_sys_shutdown
-374    i386    userfaultfd             sys_userfaultfd                 __ia32_sys_userfaultfd
-375    i386    membarrier              sys_membarrier                  __ia32_sys_membarrier
-376    i386    mlock2                  sys_mlock2                      __ia32_sys_mlock2
-377    i386    copy_file_range         sys_copy_file_range             __ia32_sys_copy_file_range
-378    i386    preadv2                 sys_preadv2                     __ia32_compat_sys_preadv2
-379    i386    pwritev2                sys_pwritev2                    __ia32_compat_sys_pwritev2
-380    i386    pkey_mprotect           sys_pkey_mprotect               __ia32_sys_pkey_mprotect
-381    i386    pkey_alloc              sys_pkey_alloc                  __ia32_sys_pkey_alloc
-382    i386    pkey_free               sys_pkey_free                   __ia32_sys_pkey_free
-383    i386    statx                   sys_statx                       __ia32_sys_statx
-384    i386    arch_prctl              sys_arch_prctl                  __ia32_compat_sys_arch_prctl
-385    i386    io_pgetevents           sys_io_pgetevents_time32        __ia32_compat_sys_io_pgetevents
-386    i386    rseq                    sys_rseq                        __ia32_sys_rseq
-393    i386    semget                  sys_semget                      __ia32_sys_semget
-394    i386    semctl                  sys_semctl                      __ia32_compat_sys_semctl
-395    i386    shmget                  sys_shmget                      __ia32_sys_shmget
-396    i386    shmctl                  sys_shmctl                      __ia32_compat_sys_shmctl
-397    i386    shmat                   sys_shmat                       __ia32_compat_sys_shmat
-398    i386    shmdt                   sys_shmdt                       __ia32_sys_shmdt
-399    i386    msgget                  sys_msgget                      __ia32_sys_msgget
-400    i386    msgsnd                  sys_msgsnd                      __ia32_compat_sys_msgsnd
-401    i386    msgrcv                  sys_msgrcv                      __ia32_compat_sys_msgrcv
-402    i386    msgctl                  sys_msgctl                      __ia32_compat_sys_msgctl
-403    i386    clock_gettime64         sys_clock_gettime               __ia32_sys_clock_gettime
-404    i386    clock_settime64         sys_clock_settime               __ia32_sys_clock_settime
-405    i386    clock_adjtime64         sys_clock_adjtime               __ia32_sys_clock_adjtime
-406    i386    clock_getres_time64     sys_clock_getres                __ia32_sys_clock_getres
-407    i386    clock_nanosleep_time64  sys_clock_nanosleep             __ia32_sys_clock_nanosleep
-408    i386    timer_gettime64         sys_timer_gettime               __ia32_sys_timer_gettime
-409    i386    timer_settime64         sys_timer_settime               __ia32_sys_timer_settime
-410    i386    timerfd_gettime64       sys_timerfd_gettime             __ia32_sys_timerfd_gettime
-411    i386    timerfd_settime64       sys_timerfd_settime             __ia32_sys_timerfd_settime
-412    i386    utimensat_time64        sys_utimensat                   __ia32_sys_utimensat
-413    i386    pselect6_time64         sys_pselect6                    __ia32_compat_sys_pselect6_time64
-414    i386    ppoll_time64            sys_ppoll                       __ia32_compat_sys_ppoll_time64
-416    i386    io_pgetevents_time64    sys_io_pgetevents               __ia32_sys_io_pgetevents
-417    i386    recvmmsg_time64         sys_recvmmsg                    __ia32_compat_sys_recvmmsg_time64
-418    i386    mq_timedsend_time64     sys_mq_timedsend                __ia32_sys_mq_timedsend
-419    i386    mq_timedreceive_time64  sys_mq_timedreceive             __ia32_sys_mq_timedreceive
-420    i386    semtimedop_time64       sys_semtimedop                  __ia32_sys_semtimedop
-421    i386    rt_sigtimedwait_time64  sys_rt_sigtimedwait             __ia32_compat_sys_rt_sigtimedwait_time64
-422    i386    futex_time64            sys_futex                       __ia32_sys_futex
-423    i386    sched_rr_get_interval_time64    sys_sched_rr_get_interval       __ia32_sys_sched_rr_get_interval
-424    i386    pidfd_send_signal       sys_pidfd_send_signal           __ia32_sys_pidfd_send_signal
-425    i386    io_uring_setup          sys_io_uring_setup              __ia32_sys_io_uring_setup
-426    i386    io_uring_enter          sys_io_uring_enter              __ia32_sys_io_uring_enter
-427    i386    io_uring_register       sys_io_uring_register           __ia32_sys_io_uring_register
-428    i386    open_tree               sys_open_tree                   __ia32_sys_open_tree
-429    i386    move_mount              sys_move_mount                  __ia32_sys_move_mount
-430    i386    fsopen                  sys_fsopen                      __ia32_sys_fsopen
-431    i386    fsconfig                sys_fsconfig                    __ia32_sys_fsconfig
-432    i386    fsmount                 sys_fsmount                     __ia32_sys_fsmount
-433    i386    fspick                  sys_fspick                      __ia32_sys_fspick
-434    i386    pidfd_open              sys_pidfd_open                  __ia32_sys_pidfd_open
-435    i386    clone3                  sys_clone3                      __ia32_sys_clone3
-437    i386    openat2                 sys_openat2                     __ia32_sys_openat2
-438    i386    pidfd_getfd             sys_pidfd_getfd                 __ia32_sys_pidfd_getfd
+286    i386    add_key                 sys_add_key
+287    i386    request_key             sys_request_key
+288    i386    keyctl                  sys_keyctl                      compat_sys_keyctl
+289    i386    ioprio_set              sys_ioprio_set
+290    i386    ioprio_get              sys_ioprio_get
+291    i386    inotify_init            sys_inotify_init
+292    i386    inotify_add_watch       sys_inotify_add_watch
+293    i386    inotify_rm_watch        sys_inotify_rm_watch
+294    i386    migrate_pages           sys_migrate_pages
+295    i386    openat                  sys_openat                      compat_sys_openat
+296    i386    mkdirat                 sys_mkdirat
+297    i386    mknodat                 sys_mknodat
+298    i386    fchownat                sys_fchownat
+299    i386    futimesat               sys_futimesat_time32
+300    i386    fstatat64               sys_fstatat64                   compat_sys_ia32_fstatat64
+301    i386    unlinkat                sys_unlinkat
+302    i386    renameat                sys_renameat
+303    i386    linkat                  sys_linkat
+304    i386    symlinkat               sys_symlinkat
+305    i386    readlinkat              sys_readlinkat
+306    i386    fchmodat                sys_fchmodat
+307    i386    faccessat               sys_faccessat
+308    i386    pselect6                sys_pselect6_time32             compat_sys_pselect6_time32
+309    i386    ppoll                   sys_ppoll_time32                compat_sys_ppoll_time32
+310    i386    unshare                 sys_unshare
+311    i386    set_robust_list         sys_set_robust_list             compat_sys_set_robust_list
+312    i386    get_robust_list         sys_get_robust_list             compat_sys_get_robust_list
+313    i386    splice                  sys_splice
+314    i386    sync_file_range         sys_ia32_sync_file_range
+315    i386    tee                     sys_tee
+316    i386    vmsplice                sys_vmsplice                    compat_sys_vmsplice
+317    i386    move_pages              sys_move_pages                  compat_sys_move_pages
+318    i386    getcpu                  sys_getcpu
+319    i386    epoll_pwait             sys_epoll_pwait
+320    i386    utimensat               sys_utimensat_time32
+321    i386    signalfd                sys_signalfd                    compat_sys_signalfd
+322    i386    timerfd_create          sys_timerfd_create
+323    i386    eventfd                 sys_eventfd
+324    i386    fallocate               sys_ia32_fallocate
+325    i386    timerfd_settime         sys_timerfd_settime32
+326    i386    timerfd_gettime         sys_timerfd_gettime32
+327    i386    signalfd4               sys_signalfd4                   compat_sys_signalfd4
+328    i386    eventfd2                sys_eventfd2
+329    i386    epoll_create1           sys_epoll_create1
+330    i386    dup3                    sys_dup3
+331    i386    pipe2                   sys_pipe2
+332    i386    inotify_init1           sys_inotify_init1
+333    i386    preadv                  sys_preadv                      compat_sys_preadv
+334    i386    pwritev                 sys_pwritev                     compat_sys_pwritev
+335    i386    rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
+336    i386    perf_event_open         sys_perf_event_open
+337    i386    recvmmsg                sys_recvmmsg_time32             compat_sys_recvmmsg_time32
+338    i386    fanotify_init           sys_fanotify_init
+339    i386    fanotify_mark           sys_fanotify_mark               compat_sys_fanotify_mark
+340    i386    prlimit64               sys_prlimit64
+341    i386    name_to_handle_at       sys_name_to_handle_at
+342    i386    open_by_handle_at       sys_open_by_handle_at           compat_sys_open_by_handle_at
+343    i386    clock_adjtime           sys_clock_adjtime32
+344    i386    syncfs                  sys_syncfs
+345    i386    sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
+346    i386    setns                   sys_setns
+347    i386    process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
+348    i386    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
+349    i386    kcmp                    sys_kcmp
+350    i386    finit_module            sys_finit_module
+351    i386    sched_setattr           sys_sched_setattr
+352    i386    sched_getattr           sys_sched_getattr
+353    i386    renameat2               sys_renameat2
+354    i386    seccomp                 sys_seccomp
+355    i386    getrandom               sys_getrandom
+356    i386    memfd_create            sys_memfd_create
+357    i386    bpf                     sys_bpf
+358    i386    execveat                sys_execveat                    compat_sys_execveat
+359    i386    socket                  sys_socket
+360    i386    socketpair              sys_socketpair
+361    i386    bind                    sys_bind
+362    i386    connect                 sys_connect
+363    i386    listen                  sys_listen
+364    i386    accept4                 sys_accept4
+365    i386    getsockopt              sys_getsockopt                  compat_sys_getsockopt
+366    i386    setsockopt              sys_setsockopt                  compat_sys_setsockopt
+367    i386    getsockname             sys_getsockname
+368    i386    getpeername             sys_getpeername
+369    i386    sendto                  sys_sendto
+370    i386    sendmsg                 sys_sendmsg                     compat_sys_sendmsg
+371    i386    recvfrom                sys_recvfrom                    compat_sys_recvfrom
+372    i386    recvmsg                 sys_recvmsg                     compat_sys_recvmsg
+373    i386    shutdown                sys_shutdown
+374    i386    userfaultfd             sys_userfaultfd
+375    i386    membarrier              sys_membarrier
+376    i386    mlock2                  sys_mlock2
+377    i386    copy_file_range         sys_copy_file_range
+378    i386    preadv2                 sys_preadv2                     compat_sys_preadv2
+379    i386    pwritev2                sys_pwritev2                    compat_sys_pwritev2
+380    i386    pkey_mprotect           sys_pkey_mprotect
+381    i386    pkey_alloc              sys_pkey_alloc
+382    i386    pkey_free               sys_pkey_free
+383    i386    statx                   sys_statx
+384    i386    arch_prctl              sys_arch_prctl                  compat_sys_arch_prctl
+385    i386    io_pgetevents           sys_io_pgetevents_time32        compat_sys_io_pgetevents
+386    i386    rseq                    sys_rseq
+393    i386    semget                  sys_semget
+394    i386    semctl                  sys_semctl                      compat_sys_semctl
+395    i386    shmget                  sys_shmget
+396    i386    shmctl                  sys_shmctl                      compat_sys_shmctl
+397    i386    shmat                   sys_shmat                       compat_sys_shmat
+398    i386    shmdt                   sys_shmdt
+399    i386    msgget                  sys_msgget
+400    i386    msgsnd                  sys_msgsnd                      compat_sys_msgsnd
+401    i386    msgrcv                  sys_msgrcv                      compat_sys_msgrcv
+402    i386    msgctl                  sys_msgctl                      compat_sys_msgctl
+403    i386    clock_gettime64         sys_clock_gettime
+404    i386    clock_settime64         sys_clock_settime
+405    i386    clock_adjtime64         sys_clock_adjtime
+406    i386    clock_getres_time64     sys_clock_getres
+407    i386    clock_nanosleep_time64  sys_clock_nanosleep
+408    i386    timer_gettime64         sys_timer_gettime
+409    i386    timer_settime64         sys_timer_settime
+410    i386    timerfd_gettime64       sys_timerfd_gettime
+411    i386    timerfd_settime64       sys_timerfd_settime
+412    i386    utimensat_time64        sys_utimensat
+413    i386    pselect6_time64         sys_pselect6                    compat_sys_pselect6_time64
+414    i386    ppoll_time64            sys_ppoll                       compat_sys_ppoll_time64
+416    i386    io_pgetevents_time64    sys_io_pgetevents
+417    i386    recvmmsg_time64         sys_recvmmsg                    compat_sys_recvmmsg_time64
+418    i386    mq_timedsend_time64     sys_mq_timedsend
+419    i386    mq_timedreceive_time64  sys_mq_timedreceive
+420    i386    semtimedop_time64       sys_semtimedop
+421    i386    rt_sigtimedwait_time64  sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait_time64
+422    i386    futex_time64            sys_futex
+423    i386    sched_rr_get_interval_time64    sys_sched_rr_get_interval
+424    i386    pidfd_send_signal       sys_pidfd_send_signal
+425    i386    io_uring_setup          sys_io_uring_setup
+426    i386    io_uring_enter          sys_io_uring_enter
+427    i386    io_uring_register       sys_io_uring_register
+428    i386    open_tree               sys_open_tree
+429    i386    move_mount              sys_move_mount
+430    i386    fsopen                  sys_fsopen
+431    i386    fsconfig                sys_fsconfig
+432    i386    fsmount                 sys_fsmount
+433    i386    fspick                  sys_fspick
+434    i386    pidfd_open              sys_pidfd_open
+435    i386    clone3                  sys_clone3
+437    i386    openat2                 sys_openat2
+438    i386    pidfd_getfd             sys_pidfd_getfd
index 44d510b..37b844f 100644 (file)
 #
 # The abi is "common", "64" or "x32" for this file.
 #
-0      common  read                    __x64_sys_read
-1      common  write                   __x64_sys_write
-2      common  open                    __x64_sys_open
-3      common  close                   __x64_sys_close
-4      common  stat                    __x64_sys_newstat
-5      common  fstat                   __x64_sys_newfstat
-6      common  lstat                   __x64_sys_newlstat
-7      common  poll                    __x64_sys_poll
-8      common  lseek                   __x64_sys_lseek
-9      common  mmap                    __x64_sys_mmap
-10     common  mprotect                __x64_sys_mprotect
-11     common  munmap                  __x64_sys_munmap
-12     common  brk                     __x64_sys_brk
-13     64      rt_sigaction            __x64_sys_rt_sigaction
-14     common  rt_sigprocmask          __x64_sys_rt_sigprocmask
-15     64      rt_sigreturn            __x64_sys_rt_sigreturn/ptregs
-16     64      ioctl                   __x64_sys_ioctl
-17     common  pread64                 __x64_sys_pread64
-18     common  pwrite64                __x64_sys_pwrite64
-19     64      readv                   __x64_sys_readv
-20     64      writev                  __x64_sys_writev
-21     common  access                  __x64_sys_access
-22     common  pipe                    __x64_sys_pipe
-23     common  select                  __x64_sys_select
-24     common  sched_yield             __x64_sys_sched_yield
-25     common  mremap                  __x64_sys_mremap
-26     common  msync                   __x64_sys_msync
-27     common  mincore                 __x64_sys_mincore
-28     common  madvise                 __x64_sys_madvise
-29     common  shmget                  __x64_sys_shmget
-30     common  shmat                   __x64_sys_shmat
-31     common  shmctl                  __x64_sys_shmctl
-32     common  dup                     __x64_sys_dup
-33     common  dup2                    __x64_sys_dup2
-34     common  pause                   __x64_sys_pause
-35     common  nanosleep               __x64_sys_nanosleep
-36     common  getitimer               __x64_sys_getitimer
-37     common  alarm                   __x64_sys_alarm
-38     common  setitimer               __x64_sys_setitimer
-39     common  getpid                  __x64_sys_getpid
-40     common  sendfile                __x64_sys_sendfile64
-41     common  socket                  __x64_sys_socket
-42     common  connect                 __x64_sys_connect
-43     common  accept                  __x64_sys_accept
-44     common  sendto                  __x64_sys_sendto
-45     64      recvfrom                __x64_sys_recvfrom
-46     64      sendmsg                 __x64_sys_sendmsg
-47     64      recvmsg                 __x64_sys_recvmsg
-48     common  shutdown                __x64_sys_shutdown
-49     common  bind                    __x64_sys_bind
-50     common  listen                  __x64_sys_listen
-51     common  getsockname             __x64_sys_getsockname
-52     common  getpeername             __x64_sys_getpeername
-53     common  socketpair              __x64_sys_socketpair
-54     64      setsockopt              __x64_sys_setsockopt
-55     64      getsockopt              __x64_sys_getsockopt
-56     common  clone                   __x64_sys_clone/ptregs
-57     common  fork                    __x64_sys_fork/ptregs
-58     common  vfork                   __x64_sys_vfork/ptregs
-59     64      execve                  __x64_sys_execve/ptregs
-60     common  exit                    __x64_sys_exit
-61     common  wait4                   __x64_sys_wait4
-62     common  kill                    __x64_sys_kill
-63     common  uname                   __x64_sys_newuname
-64     common  semget                  __x64_sys_semget
-65     common  semop                   __x64_sys_semop
-66     common  semctl                  __x64_sys_semctl
-67     common  shmdt                   __x64_sys_shmdt
-68     common  msgget                  __x64_sys_msgget
-69     common  msgsnd                  __x64_sys_msgsnd
-70     common  msgrcv                  __x64_sys_msgrcv
-71     common  msgctl                  __x64_sys_msgctl
-72     common  fcntl                   __x64_sys_fcntl
-73     common  flock                   __x64_sys_flock
-74     common  fsync                   __x64_sys_fsync
-75     common  fdatasync               __x64_sys_fdatasync
-76     common  truncate                __x64_sys_truncate
-77     common  ftruncate               __x64_sys_ftruncate
-78     common  getdents                __x64_sys_getdents
-79     common  getcwd                  __x64_sys_getcwd
-80     common  chdir                   __x64_sys_chdir
-81     common  fchdir                  __x64_sys_fchdir
-82     common  rename                  __x64_sys_rename
-83     common  mkdir                   __x64_sys_mkdir
-84     common  rmdir                   __x64_sys_rmdir
-85     common  creat                   __x64_sys_creat
-86     common  link                    __x64_sys_link
-87     common  unlink                  __x64_sys_unlink
-88     common  symlink                 __x64_sys_symlink
-89     common  readlink                __x64_sys_readlink
-90     common  chmod                   __x64_sys_chmod
-91     common  fchmod                  __x64_sys_fchmod
-92     common  chown                   __x64_sys_chown
-93     common  fchown                  __x64_sys_fchown
-94     common  lchown                  __x64_sys_lchown
-95     common  umask                   __x64_sys_umask
-96     common  gettimeofday            __x64_sys_gettimeofday
-97     common  getrlimit               __x64_sys_getrlimit
-98     common  getrusage               __x64_sys_getrusage
-99     common  sysinfo                 __x64_sys_sysinfo
-100    common  times                   __x64_sys_times
-101    64      ptrace                  __x64_sys_ptrace
-102    common  getuid                  __x64_sys_getuid
-103    common  syslog                  __x64_sys_syslog
-104    common  getgid                  __x64_sys_getgid
-105    common  setuid                  __x64_sys_setuid
-106    common  setgid                  __x64_sys_setgid
-107    common  geteuid                 __x64_sys_geteuid
-108    common  getegid                 __x64_sys_getegid
-109    common  setpgid                 __x64_sys_setpgid
-110    common  getppid                 __x64_sys_getppid
-111    common  getpgrp                 __x64_sys_getpgrp
-112    common  setsid                  __x64_sys_setsid
-113    common  setreuid                __x64_sys_setreuid
-114    common  setregid                __x64_sys_setregid
-115    common  getgroups               __x64_sys_getgroups
-116    common  setgroups               __x64_sys_setgroups
-117    common  setresuid               __x64_sys_setresuid
-118    common  getresuid               __x64_sys_getresuid
-119    common  setresgid               __x64_sys_setresgid
-120    common  getresgid               __x64_sys_getresgid
-121    common  getpgid                 __x64_sys_getpgid
-122    common  setfsuid                __x64_sys_setfsuid
-123    common  setfsgid                __x64_sys_setfsgid
-124    common  getsid                  __x64_sys_getsid
-125    common  capget                  __x64_sys_capget
-126    common  capset                  __x64_sys_capset
-127    64      rt_sigpending           __x64_sys_rt_sigpending
-128    64      rt_sigtimedwait         __x64_sys_rt_sigtimedwait
-129    64      rt_sigqueueinfo         __x64_sys_rt_sigqueueinfo
-130    common  rt_sigsuspend           __x64_sys_rt_sigsuspend
-131    64      sigaltstack             __x64_sys_sigaltstack
-132    common  utime                   __x64_sys_utime
-133    common  mknod                   __x64_sys_mknod
+0      common  read                    sys_read
+1      common  write                   sys_write
+2      common  open                    sys_open
+3      common  close                   sys_close
+4      common  stat                    sys_newstat
+5      common  fstat                   sys_newfstat
+6      common  lstat                   sys_newlstat
+7      common  poll                    sys_poll
+8      common  lseek                   sys_lseek
+9      common  mmap                    sys_mmap
+10     common  mprotect                sys_mprotect
+11     common  munmap                  sys_munmap
+12     common  brk                     sys_brk
+13     64      rt_sigaction            sys_rt_sigaction
+14     common  rt_sigprocmask          sys_rt_sigprocmask
+15     64      rt_sigreturn            sys_rt_sigreturn
+16     64      ioctl                   sys_ioctl
+17     common  pread64                 sys_pread64
+18     common  pwrite64                sys_pwrite64
+19     64      readv                   sys_readv
+20     64      writev                  sys_writev
+21     common  access                  sys_access
+22     common  pipe                    sys_pipe
+23     common  select                  sys_select
+24     common  sched_yield             sys_sched_yield
+25     common  mremap                  sys_mremap
+26     common  msync                   sys_msync
+27     common  mincore                 sys_mincore
+28     common  madvise                 sys_madvise
+29     common  shmget                  sys_shmget
+30     common  shmat                   sys_shmat
+31     common  shmctl                  sys_shmctl
+32     common  dup                     sys_dup
+33     common  dup2                    sys_dup2
+34     common  pause                   sys_pause
+35     common  nanosleep               sys_nanosleep
+36     common  getitimer               sys_getitimer
+37     common  alarm                   sys_alarm
+38     common  setitimer               sys_setitimer
+39     common  getpid                  sys_getpid
+40     common  sendfile                sys_sendfile64
+41     common  socket                  sys_socket
+42     common  connect                 sys_connect
+43     common  accept                  sys_accept
+44     common  sendto                  sys_sendto
+45     64      recvfrom                sys_recvfrom
+46     64      sendmsg                 sys_sendmsg
+47     64      recvmsg                 sys_recvmsg
+48     common  shutdown                sys_shutdown
+49     common  bind                    sys_bind
+50     common  listen                  sys_listen
+51     common  getsockname             sys_getsockname
+52     common  getpeername             sys_getpeername
+53     common  socketpair              sys_socketpair
+54     64      setsockopt              sys_setsockopt
+55     64      getsockopt              sys_getsockopt
+56     common  clone                   sys_clone
+57     common  fork                    sys_fork
+58     common  vfork                   sys_vfork
+59     64      execve                  sys_execve
+60     common  exit                    sys_exit
+61     common  wait4                   sys_wait4
+62     common  kill                    sys_kill
+63     common  uname                   sys_newuname
+64     common  semget                  sys_semget
+65     common  semop                   sys_semop
+66     common  semctl                  sys_semctl
+67     common  shmdt                   sys_shmdt
+68     common  msgget                  sys_msgget
+69     common  msgsnd                  sys_msgsnd
+70     common  msgrcv                  sys_msgrcv
+71     common  msgctl                  sys_msgctl
+72     common  fcntl                   sys_fcntl
+73     common  flock                   sys_flock
+74     common  fsync                   sys_fsync
+75     common  fdatasync               sys_fdatasync
+76     common  truncate                sys_truncate
+77     common  ftruncate               sys_ftruncate
+78     common  getdents                sys_getdents
+79     common  getcwd                  sys_getcwd
+80     common  chdir                   sys_chdir
+81     common  fchdir                  sys_fchdir
+82     common  rename                  sys_rename
+83     common  mkdir                   sys_mkdir
+84     common  rmdir                   sys_rmdir
+85     common  creat                   sys_creat
+86     common  link                    sys_link
+87     common  unlink                  sys_unlink
+88     common  symlink                 sys_symlink
+89     common  readlink                sys_readlink
+90     common  chmod                   sys_chmod
+91     common  fchmod                  sys_fchmod
+92     common  chown                   sys_chown
+93     common  fchown                  sys_fchown
+94     common  lchown                  sys_lchown
+95     common  umask                   sys_umask
+96     common  gettimeofday            sys_gettimeofday
+97     common  getrlimit               sys_getrlimit
+98     common  getrusage               sys_getrusage
+99     common  sysinfo                 sys_sysinfo
+100    common  times                   sys_times
+101    64      ptrace                  sys_ptrace
+102    common  getuid                  sys_getuid
+103    common  syslog                  sys_syslog
+104    common  getgid                  sys_getgid
+105    common  setuid                  sys_setuid
+106    common  setgid                  sys_setgid
+107    common  geteuid                 sys_geteuid
+108    common  getegid                 sys_getegid
+109    common  setpgid                 sys_setpgid
+110    common  getppid                 sys_getppid
+111    common  getpgrp                 sys_getpgrp
+112    common  setsid                  sys_setsid
+113    common  setreuid                sys_setreuid
+114    common  setregid                sys_setregid
+115    common  getgroups               sys_getgroups
+116    common  setgroups               sys_setgroups
+117    common  setresuid               sys_setresuid
+118    common  getresuid               sys_getresuid
+119    common  setresgid               sys_setresgid
+120    common  getresgid               sys_getresgid
+121    common  getpgid                 sys_getpgid
+122    common  setfsuid                sys_setfsuid
+123    common  setfsgid                sys_setfsgid
+124    common  getsid                  sys_getsid
+125    common  capget                  sys_capget
+126    common  capset                  sys_capset
+127    64      rt_sigpending           sys_rt_sigpending
+128    64      rt_sigtimedwait         sys_rt_sigtimedwait
+129    64      rt_sigqueueinfo         sys_rt_sigqueueinfo
+130    common  rt_sigsuspend           sys_rt_sigsuspend
+131    64      sigaltstack             sys_sigaltstack
+132    common  utime                   sys_utime
+133    common  mknod                   sys_mknod
 134    64      uselib
-135    common  personality             __x64_sys_personality
-136    common  ustat                   __x64_sys_ustat
-137    common  statfs                  __x64_sys_statfs
-138    common  fstatfs                 __x64_sys_fstatfs
-139    common  sysfs                   __x64_sys_sysfs
-140    common  getpriority             __x64_sys_getpriority
-141    common  setpriority             __x64_sys_setpriority
-142    common  sched_setparam          __x64_sys_sched_setparam
-143    common  sched_getparam          __x64_sys_sched_getparam
-144    common  sched_setscheduler      __x64_sys_sched_setscheduler
-145    common  sched_getscheduler      __x64_sys_sched_getscheduler
-146    common  sched_get_priority_max  __x64_sys_sched_get_priority_max
-147    common  sched_get_priority_min  __x64_sys_sched_get_priority_min
-148    common  sched_rr_get_interval   __x64_sys_sched_rr_get_interval
-149    common  mlock                   __x64_sys_mlock
-150    common  munlock                 __x64_sys_munlock
-151    common  mlockall                __x64_sys_mlockall
-152    common  munlockall              __x64_sys_munlockall
-153    common  vhangup                 __x64_sys_vhangup
-154    common  modify_ldt              __x64_sys_modify_ldt
-155    common  pivot_root              __x64_sys_pivot_root
-156    64      _sysctl                 __x64_sys_sysctl
-157    common  prctl                   __x64_sys_prctl
-158    common  arch_prctl              __x64_sys_arch_prctl
-159    common  adjtimex                __x64_sys_adjtimex
-160    common  setrlimit               __x64_sys_setrlimit
-161    common  chroot                  __x64_sys_chroot
-162    common  sync                    __x64_sys_sync
-163    common  acct                    __x64_sys_acct
-164    common  settimeofday            __x64_sys_settimeofday
-165    common  mount                   __x64_sys_mount
-166    common  umount2                 __x64_sys_umount
-167    common  swapon                  __x64_sys_swapon
-168    common  swapoff                 __x64_sys_swapoff
-169    common  reboot                  __x64_sys_reboot
-170    common  sethostname             __x64_sys_sethostname
-171    common  setdomainname           __x64_sys_setdomainname
-172    common  iopl                    __x64_sys_iopl/ptregs
-173    common  ioperm                  __x64_sys_ioperm
+135    common  personality             sys_personality
+136    common  ustat                   sys_ustat
+137    common  statfs                  sys_statfs
+138    common  fstatfs                 sys_fstatfs
+139    common  sysfs                   sys_sysfs
+140    common  getpriority             sys_getpriority
+141    common  setpriority             sys_setpriority
+142    common  sched_setparam          sys_sched_setparam
+143    common  sched_getparam          sys_sched_getparam
+144    common  sched_setscheduler      sys_sched_setscheduler
+145    common  sched_getscheduler      sys_sched_getscheduler
+146    common  sched_get_priority_max  sys_sched_get_priority_max
+147    common  sched_get_priority_min  sys_sched_get_priority_min
+148    common  sched_rr_get_interval   sys_sched_rr_get_interval
+149    common  mlock                   sys_mlock
+150    common  munlock                 sys_munlock
+151    common  mlockall                sys_mlockall
+152    common  munlockall              sys_munlockall
+153    common  vhangup                 sys_vhangup
+154    common  modify_ldt              sys_modify_ldt
+155    common  pivot_root              sys_pivot_root
+156    64      _sysctl                 sys_sysctl
+157    common  prctl                   sys_prctl
+158    common  arch_prctl              sys_arch_prctl
+159    common  adjtimex                sys_adjtimex
+160    common  setrlimit               sys_setrlimit
+161    common  chroot                  sys_chroot
+162    common  sync                    sys_sync
+163    common  acct                    sys_acct
+164    common  settimeofday            sys_settimeofday
+165    common  mount                   sys_mount
+166    common  umount2                 sys_umount
+167    common  swapon                  sys_swapon
+168    common  swapoff                 sys_swapoff
+169    common  reboot                  sys_reboot
+170    common  sethostname             sys_sethostname
+171    common  setdomainname           sys_setdomainname
+172    common  iopl                    sys_iopl
+173    common  ioperm                  sys_ioperm
 174    64      create_module
-175    common  init_module             __x64_sys_init_module
-176    common  delete_module           __x64_sys_delete_module
+175    common  init_module             sys_init_module
+176    common  delete_module           sys_delete_module
 177    64      get_kernel_syms
 178    64      query_module
-179    common  quotactl                __x64_sys_quotactl
+179    common  quotactl                sys_quotactl
 180    64      nfsservctl
 181    common  getpmsg
 182    common  putpmsg
 183    common  afs_syscall
 184    common  tuxcall
 185    common  security
-186    common  gettid                  __x64_sys_gettid
-187    common  readahead               __x64_sys_readahead
-188    common  setxattr                __x64_sys_setxattr
-189    common  lsetxattr               __x64_sys_lsetxattr
-190    common  fsetxattr               __x64_sys_fsetxattr
-191    common  getxattr                __x64_sys_getxattr
-192    common  lgetxattr               __x64_sys_lgetxattr
-193    common  fgetxattr               __x64_sys_fgetxattr
-194    common  listxattr               __x64_sys_listxattr
-195    common  llistxattr              __x64_sys_llistxattr
-196    common  flistxattr              __x64_sys_flistxattr
-197    common  removexattr             __x64_sys_removexattr
-198    common  lremovexattr            __x64_sys_lremovexattr
-199    common  fremovexattr            __x64_sys_fremovexattr
-200    common  tkill                   __x64_sys_tkill
-201    common  time                    __x64_sys_time
-202    common  futex                   __x64_sys_futex
-203    common  sched_setaffinity       __x64_sys_sched_setaffinity
-204    common  sched_getaffinity       __x64_sys_sched_getaffinity
+186    common  gettid                  sys_gettid
+187    common  readahead               sys_readahead
+188    common  setxattr                sys_setxattr
+189    common  lsetxattr               sys_lsetxattr
+190    common  fsetxattr               sys_fsetxattr
+191    common  getxattr                sys_getxattr
+192    common  lgetxattr               sys_lgetxattr
+193    common  fgetxattr               sys_fgetxattr
+194    common  listxattr               sys_listxattr
+195    common  llistxattr              sys_llistxattr
+196    common  flistxattr              sys_flistxattr
+197    common  removexattr             sys_removexattr
+198    common  lremovexattr            sys_lremovexattr
+199    common  fremovexattr            sys_fremovexattr
+200    common  tkill                   sys_tkill
+201    common  time                    sys_time
+202    common  futex                   sys_futex
+203    common  sched_setaffinity       sys_sched_setaffinity
+204    common  sched_getaffinity       sys_sched_getaffinity
 205    64      set_thread_area
-206    64      io_setup                __x64_sys_io_setup
-207    common  io_destroy              __x64_sys_io_destroy
-208    common  io_getevents            __x64_sys_io_getevents
-209    64      io_submit               __x64_sys_io_submit
-210    common  io_cancel               __x64_sys_io_cancel
+206    64      io_setup                sys_io_setup
+207    common  io_destroy              sys_io_destroy
+208    common  io_getevents            sys_io_getevents
+209    64      io_submit               sys_io_submit
+210    common  io_cancel               sys_io_cancel
 211    64      get_thread_area
-212    common  lookup_dcookie          __x64_sys_lookup_dcookie
-213    common  epoll_create            __x64_sys_epoll_create
+212    common  lookup_dcookie          sys_lookup_dcookie
+213    common  epoll_create            sys_epoll_create
 214    64      epoll_ctl_old
 215    64      epoll_wait_old
-216    common  remap_file_pages        __x64_sys_remap_file_pages
-217    common  getdents64              __x64_sys_getdents64
-218    common  set_tid_address         __x64_sys_set_tid_address
-219    common  restart_syscall         __x64_sys_restart_syscall
-220    common  semtimedop              __x64_sys_semtimedop
-221    common  fadvise64               __x64_sys_fadvise64
-222    64      timer_create            __x64_sys_timer_create
-223    common  timer_settime           __x64_sys_timer_settime
-224    common  timer_gettime           __x64_sys_timer_gettime
-225    common  timer_getoverrun        __x64_sys_timer_getoverrun
-226    common  timer_delete            __x64_sys_timer_delete
-227    common  clock_settime           __x64_sys_clock_settime
-228    common  clock_gettime           __x64_sys_clock_gettime
-229    common  clock_getres            __x64_sys_clock_getres
-230    common  clock_nanosleep         __x64_sys_clock_nanosleep
-231    common  exit_group              __x64_sys_exit_group
-232    common  epoll_wait              __x64_sys_epoll_wait
-233    common  epoll_ctl               __x64_sys_epoll_ctl
-234    common  tgkill                  __x64_sys_tgkill
-235    common  utimes                  __x64_sys_utimes
+216    common  remap_file_pages        sys_remap_file_pages
+217    common  getdents64              sys_getdents64
+218    common  set_tid_address         sys_set_tid_address
+219    common  restart_syscall         sys_restart_syscall
+220    common  semtimedop              sys_semtimedop
+221    common  fadvise64               sys_fadvise64
+222    64      timer_create            sys_timer_create
+223    common  timer_settime           sys_timer_settime
+224    common  timer_gettime           sys_timer_gettime
+225    common  timer_getoverrun        sys_timer_getoverrun
+226    common  timer_delete            sys_timer_delete
+227    common  clock_settime           sys_clock_settime
+228    common  clock_gettime           sys_clock_gettime
+229    common  clock_getres            sys_clock_getres
+230    common  clock_nanosleep         sys_clock_nanosleep
+231    common  exit_group              sys_exit_group
+232    common  epoll_wait              sys_epoll_wait
+233    common  epoll_ctl               sys_epoll_ctl
+234    common  tgkill                  sys_tgkill
+235    common  utimes                  sys_utimes
 236    64      vserver
-237    common  mbind                   __x64_sys_mbind
-238    common  set_mempolicy           __x64_sys_set_mempolicy
-239    common  get_mempolicy           __x64_sys_get_mempolicy
-240    common  mq_open                 __x64_sys_mq_open
-241    common  mq_unlink               __x64_sys_mq_unlink
-242    common  mq_timedsend            __x64_sys_mq_timedsend
-243    common  mq_timedreceive         __x64_sys_mq_timedreceive
-244    64      mq_notify               __x64_sys_mq_notify
-245    common  mq_getsetattr           __x64_sys_mq_getsetattr
-246    64      kexec_load              __x64_sys_kexec_load
-247    64      waitid                  __x64_sys_waitid
-248    common  add_key                 __x64_sys_add_key
-249    common  request_key             __x64_sys_request_key
-250    common  keyctl                  __x64_sys_keyctl
-251    common  ioprio_set              __x64_sys_ioprio_set
-252    common  ioprio_get              __x64_sys_ioprio_get
-253    common  inotify_init            __x64_sys_inotify_init
-254    common  inotify_add_watch       __x64_sys_inotify_add_watch
-255    common  inotify_rm_watch        __x64_sys_inotify_rm_watch
-256    common  migrate_pages           __x64_sys_migrate_pages
-257    common  openat                  __x64_sys_openat
-258    common  mkdirat                 __x64_sys_mkdirat
-259    common  mknodat                 __x64_sys_mknodat
-260    common  fchownat                __x64_sys_fchownat
-261    common  futimesat               __x64_sys_futimesat
-262    common  newfstatat              __x64_sys_newfstatat
-263    common  unlinkat                __x64_sys_unlinkat
-264    common  renameat                __x64_sys_renameat
-265    common  linkat                  __x64_sys_linkat
-266    common  symlinkat               __x64_sys_symlinkat
-267    common  readlinkat              __x64_sys_readlinkat
-268    common  fchmodat                __x64_sys_fchmodat
-269    common  faccessat               __x64_sys_faccessat
-270    common  pselect6                __x64_sys_pselect6
-271    common  ppoll                   __x64_sys_ppoll
-272    common  unshare                 __x64_sys_unshare
-273    64      set_robust_list         __x64_sys_set_robust_list
-274    64      get_robust_list         __x64_sys_get_robust_list
-275    common  splice                  __x64_sys_splice
-276    common  tee                     __x64_sys_tee
-277    common  sync_file_range         __x64_sys_sync_file_range
-278    64      vmsplice                __x64_sys_vmsplice
-279    64      move_pages              __x64_sys_move_pages
-280    common  utimensat               __x64_sys_utimensat
-281    common  epoll_pwait             __x64_sys_epoll_pwait
-282    common  signalfd                __x64_sys_signalfd
-283    common  timerfd_create          __x64_sys_timerfd_create
-284    common  eventfd                 __x64_sys_eventfd
-285    common  fallocate               __x64_sys_fallocate
-286    common  timerfd_settime         __x64_sys_timerfd_settime
-287    common  timerfd_gettime         __x64_sys_timerfd_gettime
-288    common  accept4                 __x64_sys_accept4
-289    common  signalfd4               __x64_sys_signalfd4
-290    common  eventfd2                __x64_sys_eventfd2
-291    common  epoll_create1           __x64_sys_epoll_create1
-292    common  dup3                    __x64_sys_dup3
-293    common  pipe2                   __x64_sys_pipe2
-294    common  inotify_init1           __x64_sys_inotify_init1
-295    64      preadv                  __x64_sys_preadv
-296    64      pwritev                 __x64_sys_pwritev
-297    64      rt_tgsigqueueinfo       __x64_sys_rt_tgsigqueueinfo
-298    common  perf_event_open         __x64_sys_perf_event_open
-299    64      recvmmsg                __x64_sys_recvmmsg
-300    common  fanotify_init           __x64_sys_fanotify_init
-301    common  fanotify_mark           __x64_sys_fanotify_mark
-302    common  prlimit64               __x64_sys_prlimit64
-303    common  name_to_handle_at       __x64_sys_name_to_handle_at
-304    common  open_by_handle_at       __x64_sys_open_by_handle_at
-305    common  clock_adjtime           __x64_sys_clock_adjtime
-306    common  syncfs                  __x64_sys_syncfs
-307    64      sendmmsg                __x64_sys_sendmmsg
-308    common  setns                   __x64_sys_setns
-309    common  getcpu                  __x64_sys_getcpu
-310    64      process_vm_readv        __x64_sys_process_vm_readv
-311    64      process_vm_writev       __x64_sys_process_vm_writev
-312    common  kcmp                    __x64_sys_kcmp
-313    common  finit_module            __x64_sys_finit_module
-314    common  sched_setattr           __x64_sys_sched_setattr
-315    common  sched_getattr           __x64_sys_sched_getattr
-316    common  renameat2               __x64_sys_renameat2
-317    common  seccomp                 __x64_sys_seccomp
-318    common  getrandom               __x64_sys_getrandom
-319    common  memfd_create            __x64_sys_memfd_create
-320    common  kexec_file_load         __x64_sys_kexec_file_load
-321    common  bpf                     __x64_sys_bpf
-322    64      execveat                __x64_sys_execveat/ptregs
-323    common  userfaultfd             __x64_sys_userfaultfd
-324    common  membarrier              __x64_sys_membarrier
-325    common  mlock2                  __x64_sys_mlock2
-326    common  copy_file_range         __x64_sys_copy_file_range
-327    64      preadv2                 __x64_sys_preadv2
-328    64      pwritev2                __x64_sys_pwritev2
-329    common  pkey_mprotect           __x64_sys_pkey_mprotect
-330    common  pkey_alloc              __x64_sys_pkey_alloc
-331    common  pkey_free               __x64_sys_pkey_free
-332    common  statx                   __x64_sys_statx
-333    common  io_pgetevents           __x64_sys_io_pgetevents
-334    common  rseq                    __x64_sys_rseq
+237    common  mbind                   sys_mbind
+238    common  set_mempolicy           sys_set_mempolicy
+239    common  get_mempolicy           sys_get_mempolicy
+240    common  mq_open                 sys_mq_open
+241    common  mq_unlink               sys_mq_unlink
+242    common  mq_timedsend            sys_mq_timedsend
+243    common  mq_timedreceive         sys_mq_timedreceive
+244    64      mq_notify               sys_mq_notify
+245    common  mq_getsetattr           sys_mq_getsetattr
+246    64      kexec_load              sys_kexec_load
+247    64      waitid                  sys_waitid
+248    common  add_key                 sys_add_key
+249    common  request_key             sys_request_key
+250    common  keyctl                  sys_keyctl
+251    common  ioprio_set              sys_ioprio_set
+252    common  ioprio_get              sys_ioprio_get
+253    common  inotify_init            sys_inotify_init
+254    common  inotify_add_watch       sys_inotify_add_watch
+255    common  inotify_rm_watch        sys_inotify_rm_watch
+256    common  migrate_pages           sys_migrate_pages
+257    common  openat                  sys_openat
+258    common  mkdirat                 sys_mkdirat
+259    common  mknodat                 sys_mknodat
+260    common  fchownat                sys_fchownat
+261    common  futimesat               sys_futimesat
+262    common  newfstatat              sys_newfstatat
+263    common  unlinkat                sys_unlinkat
+264    common  renameat                sys_renameat
+265    common  linkat                  sys_linkat
+266    common  symlinkat               sys_symlinkat
+267    common  readlinkat              sys_readlinkat
+268    common  fchmodat                sys_fchmodat
+269    common  faccessat               sys_faccessat
+270    common  pselect6                sys_pselect6
+271    common  ppoll                   sys_ppoll
+272    common  unshare                 sys_unshare
+273    64      set_robust_list         sys_set_robust_list
+274    64      get_robust_list         sys_get_robust_list
+275    common  splice                  sys_splice
+276    common  tee                     sys_tee
+277    common  sync_file_range         sys_sync_file_range
+278    64      vmsplice                sys_vmsplice
+279    64      move_pages              sys_move_pages
+280    common  utimensat               sys_utimensat
+281    common  epoll_pwait             sys_epoll_pwait
+282    common  signalfd                sys_signalfd
+283    common  timerfd_create          sys_timerfd_create
+284    common  eventfd                 sys_eventfd
+285    common  fallocate               sys_fallocate
+286    common  timerfd_settime         sys_timerfd_settime
+287    common  timerfd_gettime         sys_timerfd_gettime
+288    common  accept4                 sys_accept4
+289    common  signalfd4               sys_signalfd4
+290    common  eventfd2                sys_eventfd2
+291    common  epoll_create1           sys_epoll_create1
+292    common  dup3                    sys_dup3
+293    common  pipe2                   sys_pipe2
+294    common  inotify_init1           sys_inotify_init1
+295    64      preadv                  sys_preadv
+296    64      pwritev                 sys_pwritev
+297    64      rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo
+298    common  perf_event_open         sys_perf_event_open
+299    64      recvmmsg                sys_recvmmsg
+300    common  fanotify_init           sys_fanotify_init
+301    common  fanotify_mark           sys_fanotify_mark
+302    common  prlimit64               sys_prlimit64
+303    common  name_to_handle_at       sys_name_to_handle_at
+304    common  open_by_handle_at       sys_open_by_handle_at
+305    common  clock_adjtime           sys_clock_adjtime
+306    common  syncfs                  sys_syncfs
+307    64      sendmmsg                sys_sendmmsg
+308    common  setns                   sys_setns
+309    common  getcpu                  sys_getcpu
+310    64      process_vm_readv        sys_process_vm_readv
+311    64      process_vm_writev       sys_process_vm_writev
+312    common  kcmp                    sys_kcmp
+313    common  finit_module            sys_finit_module
+314    common  sched_setattr           sys_sched_setattr
+315    common  sched_getattr           sys_sched_getattr
+316    common  renameat2               sys_renameat2
+317    common  seccomp                 sys_seccomp
+318    common  getrandom               sys_getrandom
+319    common  memfd_create            sys_memfd_create
+320    common  kexec_file_load         sys_kexec_file_load
+321    common  bpf                     sys_bpf
+322    64      execveat                sys_execveat
+323    common  userfaultfd             sys_userfaultfd
+324    common  membarrier              sys_membarrier
+325    common  mlock2                  sys_mlock2
+326    common  copy_file_range         sys_copy_file_range
+327    64      preadv2                 sys_preadv2
+328    64      pwritev2                sys_pwritev2
+329    common  pkey_mprotect           sys_pkey_mprotect
+330    common  pkey_alloc              sys_pkey_alloc
+331    common  pkey_free               sys_pkey_free
+332    common  statx                   sys_statx
+333    common  io_pgetevents           sys_io_pgetevents
+334    common  rseq                    sys_rseq
 # don't use numbers 387 through 423, add new calls after the last
 # 'common' entry
-424    common  pidfd_send_signal       __x64_sys_pidfd_send_signal
-425    common  io_uring_setup          __x64_sys_io_uring_setup
-426    common  io_uring_enter          __x64_sys_io_uring_enter
-427    common  io_uring_register       __x64_sys_io_uring_register
-428    common  open_tree               __x64_sys_open_tree
-429    common  move_mount              __x64_sys_move_mount
-430    common  fsopen                  __x64_sys_fsopen
-431    common  fsconfig                __x64_sys_fsconfig
-432    common  fsmount                 __x64_sys_fsmount
-433    common  fspick                  __x64_sys_fspick
-434    common  pidfd_open              __x64_sys_pidfd_open
-435    common  clone3                  __x64_sys_clone3/ptregs
-437    common  openat2                 __x64_sys_openat2
-438    common  pidfd_getfd             __x64_sys_pidfd_getfd
+424    common  pidfd_send_signal       sys_pidfd_send_signal
+425    common  io_uring_setup          sys_io_uring_setup
+426    common  io_uring_enter          sys_io_uring_enter
+427    common  io_uring_register       sys_io_uring_register
+428    common  open_tree               sys_open_tree
+429    common  move_mount              sys_move_mount
+430    common  fsopen                  sys_fsopen
+431    common  fsconfig                sys_fsconfig
+432    common  fsmount                 sys_fsmount
+433    common  fspick                  sys_fspick
+434    common  pidfd_open              sys_pidfd_open
+435    common  clone3                  sys_clone3
+437    common  openat2                 sys_openat2
+438    common  pidfd_getfd             sys_pidfd_getfd
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
 # on-the-fly for compat_sys_*() compatibility system calls if X86_X32
 # is defined.
 #
-512    x32     rt_sigaction            __x32_compat_sys_rt_sigaction
-513    x32     rt_sigreturn            sys32_x32_rt_sigreturn
-514    x32     ioctl                   __x32_compat_sys_ioctl
-515    x32     readv                   __x32_compat_sys_readv
-516    x32     writev                  __x32_compat_sys_writev
-517    x32     recvfrom                __x32_compat_sys_recvfrom
-518    x32     sendmsg                 __x32_compat_sys_sendmsg
-519    x32     recvmsg                 __x32_compat_sys_recvmsg
-520    x32     execve                  __x32_compat_sys_execve/ptregs
-521    x32     ptrace                  __x32_compat_sys_ptrace
-522    x32     rt_sigpending           __x32_compat_sys_rt_sigpending
-523    x32     rt_sigtimedwait         __x32_compat_sys_rt_sigtimedwait_time64
-524    x32     rt_sigqueueinfo         __x32_compat_sys_rt_sigqueueinfo
-525    x32     sigaltstack             __x32_compat_sys_sigaltstack
-526    x32     timer_create            __x32_compat_sys_timer_create
-527    x32     mq_notify               __x32_compat_sys_mq_notify
-528    x32     kexec_load              __x32_compat_sys_kexec_load
-529    x32     waitid                  __x32_compat_sys_waitid
-530    x32     set_robust_list         __x32_compat_sys_set_robust_list
-531    x32     get_robust_list         __x32_compat_sys_get_robust_list
-532    x32     vmsplice                __x32_compat_sys_vmsplice
-533    x32     move_pages              __x32_compat_sys_move_pages
-534    x32     preadv                  __x32_compat_sys_preadv64
-535    x32     pwritev                 __x32_compat_sys_pwritev64
-536    x32     rt_tgsigqueueinfo       __x32_compat_sys_rt_tgsigqueueinfo
-537    x32     recvmmsg                __x32_compat_sys_recvmmsg_time64
-538    x32     sendmmsg                __x32_compat_sys_sendmmsg
-539    x32     process_vm_readv        __x32_compat_sys_process_vm_readv
-540    x32     process_vm_writev       __x32_compat_sys_process_vm_writev
-541    x32     setsockopt              __x32_compat_sys_setsockopt
-542    x32     getsockopt              __x32_compat_sys_getsockopt
-543    x32     io_setup                __x32_compat_sys_io_setup
-544    x32     io_submit               __x32_compat_sys_io_submit
-545    x32     execveat                __x32_compat_sys_execveat/ptregs
-546    x32     preadv2                 __x32_compat_sys_preadv64v2
-547    x32     pwritev2                __x32_compat_sys_pwritev64v2
+512    x32     rt_sigaction            compat_sys_rt_sigaction
+513    x32     rt_sigreturn            compat_sys_x32_rt_sigreturn
+514    x32     ioctl                   compat_sys_ioctl
+515    x32     readv                   compat_sys_readv
+516    x32     writev                  compat_sys_writev
+517    x32     recvfrom                compat_sys_recvfrom
+518    x32     sendmsg                 compat_sys_sendmsg
+519    x32     recvmsg                 compat_sys_recvmsg
+520    x32     execve                  compat_sys_execve
+521    x32     ptrace                  compat_sys_ptrace
+522    x32     rt_sigpending           compat_sys_rt_sigpending
+523    x32     rt_sigtimedwait         compat_sys_rt_sigtimedwait_time64
+524    x32     rt_sigqueueinfo         compat_sys_rt_sigqueueinfo
+525    x32     sigaltstack             compat_sys_sigaltstack
+526    x32     timer_create            compat_sys_timer_create
+527    x32     mq_notify               compat_sys_mq_notify
+528    x32     kexec_load              compat_sys_kexec_load
+529    x32     waitid                  compat_sys_waitid
+530    x32     set_robust_list         compat_sys_set_robust_list
+531    x32     get_robust_list         compat_sys_get_robust_list
+532    x32     vmsplice                compat_sys_vmsplice
+533    x32     move_pages              compat_sys_move_pages
+534    x32     preadv                  compat_sys_preadv64
+535    x32     pwritev                 compat_sys_pwritev64
+536    x32     rt_tgsigqueueinfo       compat_sys_rt_tgsigqueueinfo
+537    x32     recvmmsg                compat_sys_recvmmsg_time64
+538    x32     sendmmsg                compat_sys_sendmmsg
+539    x32     process_vm_readv        compat_sys_process_vm_readv
+540    x32     process_vm_writev       compat_sys_process_vm_writev
+541    x32     setsockopt              compat_sys_setsockopt
+542    x32     getsockopt              compat_sys_getsockopt
+543    x32     io_setup                compat_sys_io_setup
+544    x32     io_submit               compat_sys_io_submit
+545    x32     execveat                compat_sys_execveat
+546    x32     preadv2                 compat_sys_preadv64v2
+547    x32     pwritev2                compat_sys_pwritev64v2
index 12fbbcf..cc1e638 100644 (file)
@@ -15,14 +15,21 @@ grep -E "^[0-9A-Fa-fXx]+[[:space:]]+${my_abis}" "$in" | sort -n | (
     echo "#define ${fileguard} 1"
     echo ""
 
+    max=0
     while read nr abi name entry ; do
        if [ -z "$offset" ]; then
            echo "#define __NR_${prefix}${name} $nr"
        else
            echo "#define __NR_${prefix}${name} ($offset + $nr)"
         fi
+
+       max=$nr
     done
 
     echo ""
+    echo "#ifdef __KERNEL__"
+    echo "#define __NR_${prefix}syscall_max $max"
+    echo "#endif"
+    echo ""
     echo "#endif /* ${fileguard} */"
 ) > "$out"
index 1af2be3..929bde1 100644 (file)
@@ -9,15 +9,7 @@ syscall_macro() {
     local nr="$2"
     local entry="$3"
 
-    # Entry can be either just a function name or "function/qualifier"
-    real_entry="${entry%%/*}"
-    if [ "$entry" = "$real_entry" ]; then
-        qualifier=
-    else
-        qualifier=${entry#*/}
-    fi
-
-    echo "__SYSCALL_${abi}($nr, $real_entry, $qualifier)"
+    echo "__SYSCALL_${abi}($nr, $entry)"
 }
 
 emit() {
@@ -25,27 +17,15 @@ emit() {
     local nr="$2"
     local entry="$3"
     local compat="$4"
-    local umlentry=""
 
     if [ "$abi" != "I386" -a -n "$compat" ]; then
        echo "a compat entry ($abi: $compat) for a 64-bit syscall makes no sense" >&2
        exit 1
     fi
 
-    # For CONFIG_UML, we need to strip the __x64_sys prefix
-    if [ "$abi" = "64" -a "${entry}" != "${entry#__x64_sys}" ]; then
-           umlentry="sys${entry#__x64_sys}"
-    fi
-
     if [ -z "$compat" ]; then
-       if [ -n "$entry" -a -z "$umlentry" ]; then
-           syscall_macro "$abi" "$nr" "$entry"
-       elif [ -n "$umlentry" ]; then # implies -n "$entry"
-           echo "#ifdef CONFIG_X86"
+       if [ -n "$entry" ]; then
            syscall_macro "$abi" "$nr" "$entry"
-           echo "#else /* CONFIG_UML */"
-           syscall_macro "$abi" "$nr" "$umlentry"
-           echo "#endif"
        fi
     else
        echo "#ifdef CONFIG_X86_32"
@@ -61,24 +41,6 @@ emit() {
 grep '^[0-9]' "$in" | sort -n | (
     while read nr abi name entry compat; do
        abi=`echo "$abi" | tr '[a-z]' '[A-Z]'`
-       if [ "$abi" = "COMMON" -o "$abi" = "64" ]; then
-           emit 64 "$nr" "$entry" "$compat"
-           if [ "$abi" = "COMMON" ]; then
-               # COMMON means that this syscall exists in the same form for
-               # 64-bit and X32.
-               echo "#ifdef CONFIG_X86_X32_ABI"
-               emit X32 "$nr" "$entry" "$compat"
-               echo "#endif"
-           fi
-       elif [ "$abi" = "X32" ]; then
-           echo "#ifdef CONFIG_X86_X32_ABI"
-           emit X32 "$nr" "$entry" "$compat"
-           echo "#endif"
-       elif [ "$abi" = "I386" ]; then
-           emit "$abi" "$nr" "$entry" "$compat"
-       else
-           echo "Unknown abi $abi" >&2
-           exit 1
-       fi
+       emit "$abi" "$nr" "$entry" "$compat"
     done
 ) > "$out"
index e010d4a..3a07ce3 100644 (file)
@@ -35,9 +35,9 @@ SYM_CODE_END(\name)
 #endif
 
 #ifdef CONFIG_PREEMPTION
-       THUNK ___preempt_schedule, preempt_schedule
-       THUNK ___preempt_schedule_notrace, preempt_schedule_notrace
-       EXPORT_SYMBOL(___preempt_schedule)
-       EXPORT_SYMBOL(___preempt_schedule_notrace)
+       THUNK preempt_schedule_thunk, preempt_schedule
+       THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace
+       EXPORT_SYMBOL(preempt_schedule_thunk)
+       EXPORT_SYMBOL(preempt_schedule_notrace_thunk)
 #endif
 
index c5c3b6e..dbe4493 100644 (file)
@@ -47,10 +47,10 @@ SYM_FUNC_END(\name)
 #endif
 
 #ifdef CONFIG_PREEMPTION
-       THUNK ___preempt_schedule, preempt_schedule
-       THUNK ___preempt_schedule_notrace, preempt_schedule_notrace
-       EXPORT_SYMBOL(___preempt_schedule)
-       EXPORT_SYMBOL(___preempt_schedule_notrace)
+       THUNK preempt_schedule_thunk, preempt_schedule
+       THUNK preempt_schedule_notrace_thunk, preempt_schedule_notrace
+       EXPORT_SYMBOL(preempt_schedule_thunk)
+       EXPORT_SYMBOL(preempt_schedule_notrace_thunk)
 #endif
 
 #if defined(CONFIG_TRACE_IRQFLAGS) \
index 9242b28..1e82bd4 100644 (file)
@@ -13,6 +13,7 @@
  */
 #undef CONFIG_64BIT
 #undef CONFIG_X86_64
+#undef CONFIG_COMPAT
 #undef CONFIG_PGTABLE_LEVELS
 #undef CONFIG_ILLEGAL_POINTER_VALUE
 #undef CONFIG_SPARSEMEM_VMEMMAP
index c1b8496..43428cc 100644 (file)
@@ -38,6 +38,8 @@ struct vdso_data *arch_get_vdso_data(void *vvar_page)
 }
 #undef EMIT_VVAR
 
+unsigned int vclocks_used __read_mostly;
+
 #if defined(CONFIG_X86_64)
 unsigned int __read_mostly vdso64_enabled = 1;
 #endif
@@ -219,7 +221,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
        } else if (sym_offset == image->sym_pvclock_page) {
                struct pvclock_vsyscall_time_info *pvti =
                        pvclock_get_pvti_cpu0_va();
-               if (pvti && vclock_was_used(VCLOCK_PVCLOCK)) {
+               if (pvti && vclock_was_used(VDSO_CLOCKMODE_PVCLOCK)) {
                        return vmf_insert_pfn_prot(vma, vmf->address,
                                        __pa(pvti) >> PAGE_SHIFT,
                                        pgprot_decrypted(vma->vm_page_prot));
@@ -227,7 +229,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
        } else if (sym_offset == image->sym_hvclock_page) {
                struct ms_hyperv_tsc_page *tsc_pg = hv_get_tsc_page();
 
-               if (tsc_pg && vclock_was_used(VCLOCK_HVCLOCK))
+               if (tsc_pg && vclock_was_used(VDSO_CLOCKMODE_HVCLOCK))
                        return vmf_insert_pfn(vma, vmf->address,
                                        virt_to_phys(tsc_pg) >> PAGE_SHIFT);
        } else if (sym_offset == image->sym_timens_page) {
@@ -445,6 +447,8 @@ __setup("vdso=", vdso_setup);
 
 static int __init init_vdso(void)
 {
+       BUILD_BUG_ON(VDSO_CLOCKMODE_MAX >= 32);
+
        init_vdso_image(&vdso_image_64);
 
 #ifdef CONFIG_X86_X32_ABI
index abef513..43b09e9 100644 (file)
@@ -259,7 +259,7 @@ static int power_cpu_init(unsigned int cpu)
 }
 
 static const struct x86_cpu_id cpu_match[] = {
-       { .vendor = X86_VENDOR_AMD, .family = 0x15 },
+       X86_MATCH_VENDOR_FAM(AMD, 0x15, NULL),
        {},
 };
 
index a6ea07f..76400c0 100644 (file)
@@ -180,6 +180,31 @@ static void amd_uncore_del(struct perf_event *event, int flags)
        hwc->idx = -1;
 }
 
+/*
+ * Convert logical CPU number to L3 PMC Config ThreadMask format
+ */
+static u64 l3_thread_slice_mask(int cpu)
+{
+       u64 thread_mask, core = topology_core_id(cpu);
+       unsigned int shift, thread = 0;
+
+       if (topology_smt_supported() && !topology_is_primary_thread(cpu))
+               thread = 1;
+
+       if (boot_cpu_data.x86 <= 0x18) {
+               shift = AMD64_L3_THREAD_SHIFT + 2 * (core % 4) + thread;
+               thread_mask = BIT_ULL(shift);
+
+               return AMD64_L3_SLICE_MASK | thread_mask;
+       }
+
+       core = (core << AMD64_L3_COREID_SHIFT) & AMD64_L3_COREID_MASK;
+       shift = AMD64_L3_THREAD_SHIFT + thread;
+       thread_mask = BIT_ULL(shift);
+
+       return AMD64_L3_EN_ALL_SLICES | core | thread_mask;
+}
+
 static int amd_uncore_event_init(struct perf_event *event)
 {
        struct amd_uncore *uncore;
@@ -190,15 +215,12 @@ static int amd_uncore_event_init(struct perf_event *event)
 
        /*
         * NB and Last level cache counters (MSRs) are shared across all cores
-        * that share the same NB / Last level cache. Interrupts can be directed
-        * to a single target core, however, event counts generated by processes
-        * running on other cores cannot be masked out. So we do not support
-        * sampling and per-thread events.
+        * that share the same NB / Last level cache.  On family 16h and below,
+        * Interrupts can be directed to a single target core, however, event
+        * counts generated by processes running on other cores cannot be masked
+        * out. So we do not support sampling and per-thread events via
+        * CAP_NO_INTERRUPT, and we do not enable counter overflow interrupts:
         */
-       if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
-               return -EINVAL;
-
-       /* and we do not enable counter overflow interrupts */
        hwc->config = event->attr.config & AMD64_RAW_EVENT_MASK_NB;
        hwc->idx = -1;
 
@@ -206,18 +228,11 @@ static int amd_uncore_event_init(struct perf_event *event)
                return -EINVAL;
 
        /*
-        * SliceMask and ThreadMask need to be set for certain L3 events in
-        * Family 17h. For other events, the two fields do not affect the count.
+        * SliceMask and ThreadMask need to be set for certain L3 events.
+        * For other events, the two fields do not affect the count.
         */
-       if (l3_mask && is_llc_event(event)) {
-               int thread = 2 * (cpu_data(event->cpu).cpu_core_id % 4);
-
-               if (smp_num_siblings > 1)
-                       thread += cpu_data(event->cpu).apicid & 1;
-
-               hwc->config |= (1ULL << (AMD64_L3_THREAD_SHIFT + thread) &
-                               AMD64_L3_THREAD_MASK) | AMD64_L3_SLICE_MASK;
-       }
+       if (l3_mask && is_llc_event(event))
+               hwc->config |= l3_thread_slice_mask(event->cpu);
 
        uncore = event_to_amd_uncore(event);
        if (!uncore)
@@ -306,7 +321,7 @@ static struct pmu amd_nb_pmu = {
        .start          = amd_uncore_start,
        .stop           = amd_uncore_stop,
        .read           = amd_uncore_read,
-       .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
+       .capabilities   = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT,
 };
 
 static struct pmu amd_llc_pmu = {
@@ -317,7 +332,7 @@ static struct pmu amd_llc_pmu = {
        .start          = amd_uncore_start,
        .stop           = amd_uncore_stop,
        .read           = amd_uncore_read,
-       .capabilities   = PERF_PMU_CAP_NO_EXCLUDE,
+       .capabilities   = PERF_PMU_CAP_NO_EXCLUDE | PERF_PMU_CAP_NO_INTERRUPT,
 };
 
 static struct amd_uncore *amd_uncore_alloc(unsigned int cpu)
@@ -523,9 +538,9 @@ static int __init amd_uncore_init(void)
        if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
                return -ENODEV;
 
-       if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) {
+       if (boot_cpu_data.x86 >= 0x17) {
                /*
-                * For F17h or F18h, the Northbridge counters are
+                * For F17h and above, the Northbridge counters are
                 * repurposed as Data Fabric counters. Also, L3
                 * counters are supported too. The PMUs are exported
                 * based on family as either L2 or L3 and NB or DF.
index dff6623..332954c 100644 (file)
@@ -1945,6 +1945,14 @@ static __initconst const u64 knl_hw_cache_extra_regs
  * intel_bts events don't coexist with intel PMU's BTS events because of
  * x86_add_exclusive(x86_lbr_exclusive_lbr); there's no need to keep them
  * disabled around intel PMU's event batching etc, only inside the PMI handler.
+ *
+ * Avoid PEBS_ENABLE MSR access in PMIs.
+ * The GLOBAL_CTRL has been disabled. All the counters do not count anymore.
+ * It doesn't matter if the PEBS is enabled or not.
+ * Usually, the PEBS status are not changed in PMIs. It's unnecessary to
+ * access PEBS_ENABLE MSR in disable_all()/enable_all().
+ * However, there are some cases which may change PEBS status, e.g. PMI
+ * throttle. The PEBS_ENABLE should be updated where the status changes.
  */
 static void __intel_pmu_disable_all(void)
 {
@@ -1954,13 +1962,12 @@ static void __intel_pmu_disable_all(void)
 
        if (test_bit(INTEL_PMC_IDX_FIXED_BTS, cpuc->active_mask))
                intel_pmu_disable_bts();
-
-       intel_pmu_pebs_disable_all();
 }
 
 static void intel_pmu_disable_all(void)
 {
        __intel_pmu_disable_all();
+       intel_pmu_pebs_disable_all();
        intel_pmu_lbr_disable_all();
 }
 
@@ -1968,7 +1975,6 @@ static void __intel_pmu_enable_all(int added, bool pmi)
 {
        struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
 
-       intel_pmu_pebs_enable_all();
        intel_pmu_lbr_enable_all(pmi);
        wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL,
                        x86_pmu.intel_ctrl & ~cpuc->intel_ctrl_guest_mask);
@@ -1986,6 +1992,7 @@ static void __intel_pmu_enable_all(int added, bool pmi)
 
 static void intel_pmu_enable_all(int added)
 {
+       intel_pmu_pebs_enable_all();
        __intel_pmu_enable_all(added, false);
 }
 
@@ -2374,9 +2381,21 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status)
         * PEBS overflow sets bit 62 in the global status register
         */
        if (__test_and_clear_bit(62, (unsigned long *)&status)) {
+               u64 pebs_enabled = cpuc->pebs_enabled;
+
                handled++;
                x86_pmu.drain_pebs(regs);
                status &= x86_pmu.intel_ctrl | GLOBAL_STATUS_TRACE_TOPAPMI;
+
+               /*
+                * PMI throttle may be triggered, which stops the PEBS event.
+                * Although cpuc->pebs_enabled is updated accordingly, the
+                * MSR_IA32_PEBS_ENABLE is not updated. Because the
+                * cpuc->enabled has been forced to 0 in PMI.
+                * Update the MSR if pebs_enabled is changed.
+                */
+               if (pebs_enabled != cpuc->pebs_enabled)
+                       wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled);
        }
 
        /*
index 4814c96..e4aa20c 100644 (file)
@@ -594,63 +594,60 @@ static const struct cstate_model glm_cstates __initconst = {
 };
 
 
-#define X86_CSTATES_MODEL(model, states)                               \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long) &(states) }
-
 static const struct x86_cpu_id intel_cstates_match[] __initconst = {
-       X86_CSTATES_MODEL(INTEL_FAM6_NEHALEM,    nhm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_NEHALEM_EP, nhm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_NEHALEM_EX, nhm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM,             &nhm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EP,          &nhm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EX,          &nhm_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_WESTMERE,    nhm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_WESTMERE_EP, nhm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_WESTMERE_EX, nhm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE,            &nhm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EP,         &nhm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EX,         &nhm_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_SANDYBRIDGE,   snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_SANDYBRIDGE_X, snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE,         &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X,       &snb_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_IVYBRIDGE,   snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_IVYBRIDGE_X, snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE,           &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,         &snb_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_HASWELL,   snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_X, snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_G, snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL,             &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,           &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G,           &snb_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_HASWELL_L, hswult_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L,           &hswult_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_SILVERMONT,   slm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_SILVERMONT_D, slm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_AIRMONT,      slm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,     &slm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D,   &slm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        &slm_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL,   snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_D, snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_G, snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_BROADWELL_X, snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL,           &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,         &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G,         &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,         &snb_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_L, snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE,   snb_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_SKYLAKE_X, snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,           &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,             &snb_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,           &snb_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE_L, hswult_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_KABYLAKE,   hswult_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_COMETLAKE_L, hswult_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_COMETLAKE, hswult_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,          &hswult_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,            &hswult_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L,         &hswult_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE,           &hswult_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_CANNONLAKE_L, cnl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L,        &cnl_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNL, knl_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_XEON_PHI_KNM, knl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,        &knl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,        &knl_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT,   glm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_D, glm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_GOLDMONT_PLUS, glm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_TREMONT_D, glm_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_ATOM_TREMONT, glm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,       &glm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D,     &glm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS,  &glm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,      &glm_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT,        &glm_cstates),
 
-       X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE_L, icl_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_ICELAKE,   icl_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_TIGERLAKE_L, icl_cstates),
-       X86_CSTATES_MODEL(INTEL_FAM6_TIGERLAKE, icl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,           &icl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE,             &icl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,         &icl_cstates),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,           &icl_cstates),
        { },
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_cstates_match);
index 534c766..65113b1 100644 (file)
@@ -585,6 +585,7 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
                cpuc->lbr_entries[i].reserved   = 0;
        }
        cpuc->lbr_stack.nr = i;
+       cpuc->lbr_stack.hw_idx = tos;
 }
 
 /*
@@ -680,6 +681,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
                out++;
        }
        cpuc->lbr_stack.nr = out;
+       cpuc->lbr_stack.hw_idx = tos;
 }
 
 void intel_pmu_lbr_read(void)
@@ -1120,6 +1122,13 @@ void intel_pmu_store_pebs_lbrs(struct pebs_lbr *lbr)
        int i;
 
        cpuc->lbr_stack.nr = x86_pmu.lbr_nr;
+
+       /* Cannot get TOS for large PEBS */
+       if (cpuc->n_pebs == cpuc->n_large_pebs)
+               cpuc->lbr_stack.hw_idx = -1ULL;
+       else
+               cpuc->lbr_stack.hw_idx = intel_pmu_lbr_tos();
+
        for (i = 0; i < x86_pmu.lbr_nr; i++) {
                u64 info = lbr->lbr[i].info;
                struct perf_branch_entry *e = &cpuc->lbr_entries[i];
index 0991312..a5dbd25 100644 (file)
@@ -668,9 +668,6 @@ static int __init init_rapl_pmus(void)
        return 0;
 }
 
-#define X86_RAPL_MODEL_MATCH(model, init)      \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init }
-
 static struct rapl_model model_snb = {
        .events         = BIT(PERF_RAPL_PP0) |
                          BIT(PERF_RAPL_PKG) |
@@ -716,36 +713,35 @@ static struct rapl_model model_skl = {
 };
 
 static const struct x86_cpu_id rapl_model_match[] __initconst = {
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE,            model_snb),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X,          model_snbep),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE,              model_snb),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X,            model_snbep),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL,                model_hsw),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_X,              model_hsx),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_L,              model_hsw),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_HASWELL_G,              model_hsw),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL,              model_hsw),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_G,            model_hsw),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_X,            model_hsx),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_BROADWELL_D,            model_hsx),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL,           model_knl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM,           model_knl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_L,              model_skl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE,                model_skl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X,              model_hsx),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE_L,             model_skl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_KABYLAKE,               model_skl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_CANNONLAKE_L,           model_skl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT,          model_hsw),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_D,        model_hsw),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_ATOM_GOLDMONT_PLUS,     model_hsw),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE_L,              model_skl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_ICELAKE,                model_skl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_COMETLAKE_L,            model_skl),
-       X86_RAPL_MODEL_MATCH(INTEL_FAM6_COMETLAKE,              model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE,         &model_snb),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X,       &model_snbep),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE,           &model_snb),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,         &model_snbep),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL,             &model_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,           &model_hsx),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L,           &model_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G,           &model_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL,           &model_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G,         &model_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,         &model_hsx),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,         &model_hsx),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,        &model_knl),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,        &model_knl),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,           &model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,             &model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,           &model_hsx),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,          &model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,            &model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L,        &model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,       &model_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D,     &model_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS,  &model_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,           &model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE,             &model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L,         &model_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE,           &model_skl),
        {},
 };
-
 MODULE_DEVICE_TABLE(x86cpu, rapl_model_match);
 
 static int __init rapl_pmu_init(void)
index 86467f8..1ba72c5 100644 (file)
@@ -1392,10 +1392,6 @@ err:
        return ret;
 }
 
-
-#define X86_UNCORE_MODEL_MATCH(model, init)    \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init }
-
 struct intel_uncore_init_fun {
        void    (*cpu_init)(void);
        int     (*pci_init)(void);
@@ -1470,6 +1466,16 @@ static const struct intel_uncore_init_fun icl_uncore_init __initconst = {
        .pci_init = skl_uncore_pci_init,
 };
 
+static const struct intel_uncore_init_fun tgl_uncore_init __initconst = {
+       .cpu_init = icl_uncore_cpu_init,
+       .mmio_init = tgl_uncore_mmio_init,
+};
+
+static const struct intel_uncore_init_fun tgl_l_uncore_init __initconst = {
+       .cpu_init = icl_uncore_cpu_init,
+       .mmio_init = tgl_l_uncore_mmio_init,
+};
+
 static const struct intel_uncore_init_fun snr_uncore_init __initconst = {
        .cpu_init = snr_uncore_cpu_init,
        .pci_init = snr_uncore_pci_init,
@@ -1477,38 +1483,39 @@ static const struct intel_uncore_init_fun snr_uncore_init __initconst = {
 };
 
 static const struct x86_cpu_id intel_uncore_match[] __initconst = {
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EP,     nhm_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM,        nhm_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_WESTMERE,       nhm_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_WESTMERE_EP,    nhm_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE,    snb_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE,      ivb_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL,        hsw_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_L,      hsw_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_G,      hsw_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL,      bdw_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_G,    bdw_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SANDYBRIDGE_X,  snbep_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_NEHALEM_EX,     nhmex_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_WESTMERE_EX,    nhmex_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_IVYBRIDGE_X,    ivbep_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_HASWELL_X,      hswep_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_X,    bdx_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_BROADWELL_D,    bdx_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNL,   knl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_XEON_PHI_KNM,   knl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE,        skl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_L,      skl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_SKYLAKE_X,      skx_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE_L,     skl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_KABYLAKE,       skl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_L,      icl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE_NNPI,   icl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ICELAKE,        icl_uncore_init),
-       X86_UNCORE_MODEL_MATCH(INTEL_FAM6_ATOM_TREMONT_D, snr_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EP,          &nhm_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM,             &nhm_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE,            &nhm_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EP,         &nhm_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE,         &snb_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE,           &ivb_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL,             &hsw_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L,           &hsw_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G,           &hsw_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL,           &bdw_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G,         &bdw_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X,       &snbep_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EX,          &nhmex_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EX,         &nhmex_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,         &ivbep_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,           &hswep_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,         &bdx_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,         &bdx_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,        &knl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,        &knl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,             &skl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,           &skl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,           &skx_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,          &skl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,            &skl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,           &icl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI,        &icl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE,             &icl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,         &tgl_l_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,           &tgl_uncore_init),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,      &snr_uncore_init),
        {},
 };
-
 MODULE_DEVICE_TABLE(x86cpu, intel_uncore_match);
 
 static int __init intel_uncore_init(void)
index bbfdaa7..b30429f 100644 (file)
@@ -154,6 +154,7 @@ struct freerunning_counters {
        unsigned int box_offset;
        unsigned int num_counters;
        unsigned int bits;
+       unsigned *box_offsets;
 };
 
 struct pci2phy_map {
@@ -310,7 +311,9 @@ unsigned int uncore_freerunning_counter(struct intel_uncore_box *box,
 
        return pmu->type->freerunning[type].counter_base +
               pmu->type->freerunning[type].counter_offset * idx +
-              pmu->type->freerunning[type].box_offset * pmu->pmu_idx;
+              (pmu->type->freerunning[type].box_offsets ?
+               pmu->type->freerunning[type].box_offsets[pmu->pmu_idx] :
+               pmu->type->freerunning[type].box_offset * pmu->pmu_idx);
 }
 
 static inline
@@ -527,6 +530,8 @@ void snb_uncore_cpu_init(void);
 void nhm_uncore_cpu_init(void);
 void skl_uncore_cpu_init(void);
 void icl_uncore_cpu_init(void);
+void tgl_uncore_mmio_init(void);
+void tgl_l_uncore_mmio_init(void);
 int snb_pci2phy_map_init(int devid);
 
 /* uncore_snbep.c */
index c37cb12..3de1065 100644 (file)
 #define PCI_DEVICE_ID_INTEL_WHL_UD_IMC         0x3e35
 #define PCI_DEVICE_ID_INTEL_ICL_U_IMC          0x8a02
 #define PCI_DEVICE_ID_INTEL_ICL_U2_IMC         0x8a12
+#define PCI_DEVICE_ID_INTEL_TGL_U1_IMC         0x9a02
+#define PCI_DEVICE_ID_INTEL_TGL_U2_IMC         0x9a04
+#define PCI_DEVICE_ID_INTEL_TGL_U3_IMC         0x9a12
+#define PCI_DEVICE_ID_INTEL_TGL_U4_IMC         0x9a14
+#define PCI_DEVICE_ID_INTEL_TGL_H_IMC          0x9a36
 
 
 /* SNB event control */
@@ -1002,3 +1007,157 @@ void nhm_uncore_cpu_init(void)
 }
 
 /* end of Nehalem uncore support */
+
+/* Tiger Lake MMIO uncore support */
+
+static const struct pci_device_id tgl_uncore_pci_ids[] = {
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGL_U1_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGL_U2_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGL_U3_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGL_U4_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* IMC */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGL_H_IMC),
+               .driver_data = UNCORE_PCI_DEV_DATA(SNB_PCI_UNCORE_IMC, 0),
+       },
+       { /* end: all zeroes */ }
+};
+
+enum perf_tgl_uncore_imc_freerunning_types {
+       TGL_MMIO_UNCORE_IMC_DATA_TOTAL,
+       TGL_MMIO_UNCORE_IMC_DATA_READ,
+       TGL_MMIO_UNCORE_IMC_DATA_WRITE,
+       TGL_MMIO_UNCORE_IMC_FREERUNNING_TYPE_MAX
+};
+
+static struct freerunning_counters tgl_l_uncore_imc_freerunning[] = {
+       [TGL_MMIO_UNCORE_IMC_DATA_TOTAL]        = { 0x5040, 0x0, 0x0, 1, 64 },
+       [TGL_MMIO_UNCORE_IMC_DATA_READ]         = { 0x5058, 0x0, 0x0, 1, 64 },
+       [TGL_MMIO_UNCORE_IMC_DATA_WRITE]        = { 0x50A0, 0x0, 0x0, 1, 64 },
+};
+
+static struct freerunning_counters tgl_uncore_imc_freerunning[] = {
+       [TGL_MMIO_UNCORE_IMC_DATA_TOTAL]        = { 0xd840, 0x0, 0x0, 1, 64 },
+       [TGL_MMIO_UNCORE_IMC_DATA_READ]         = { 0xd858, 0x0, 0x0, 1, 64 },
+       [TGL_MMIO_UNCORE_IMC_DATA_WRITE]        = { 0xd8A0, 0x0, 0x0, 1, 64 },
+};
+
+static struct uncore_event_desc tgl_uncore_imc_events[] = {
+       INTEL_UNCORE_EVENT_DESC(data_total,         "event=0xff,umask=0x10"),
+       INTEL_UNCORE_EVENT_DESC(data_total.scale,   "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_total.unit,    "MiB"),
+
+       INTEL_UNCORE_EVENT_DESC(data_read,         "event=0xff,umask=0x20"),
+       INTEL_UNCORE_EVENT_DESC(data_read.scale,   "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_read.unit,    "MiB"),
+
+       INTEL_UNCORE_EVENT_DESC(data_write,        "event=0xff,umask=0x30"),
+       INTEL_UNCORE_EVENT_DESC(data_write.scale,  "6.103515625e-5"),
+       INTEL_UNCORE_EVENT_DESC(data_write.unit,   "MiB"),
+
+       { /* end: all zeroes */ }
+};
+
+static struct pci_dev *tgl_uncore_get_mc_dev(void)
+{
+       const struct pci_device_id *ids = tgl_uncore_pci_ids;
+       struct pci_dev *mc_dev = NULL;
+
+       while (ids && ids->vendor) {
+               mc_dev = pci_get_device(PCI_VENDOR_ID_INTEL, ids->device, NULL);
+               if (mc_dev)
+                       return mc_dev;
+               ids++;
+       }
+
+       return mc_dev;
+}
+
+#define TGL_UNCORE_MMIO_IMC_MEM_OFFSET         0x10000
+
+static void tgl_uncore_imc_freerunning_init_box(struct intel_uncore_box *box)
+{
+       struct pci_dev *pdev = tgl_uncore_get_mc_dev();
+       struct intel_uncore_pmu *pmu = box->pmu;
+       resource_size_t addr;
+       u32 mch_bar;
+
+       if (!pdev) {
+               pr_warn("perf uncore: Cannot find matched IMC device.\n");
+               return;
+       }
+
+       pci_read_config_dword(pdev, SNB_UNCORE_PCI_IMC_BAR_OFFSET, &mch_bar);
+       /* MCHBAR is disabled */
+       if (!(mch_bar & BIT(0))) {
+               pr_warn("perf uncore: MCHBAR is disabled. Failed to map IMC free-running counters.\n");
+               return;
+       }
+       mch_bar &= ~BIT(0);
+       addr = (resource_size_t)(mch_bar + TGL_UNCORE_MMIO_IMC_MEM_OFFSET * pmu->pmu_idx);
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       pci_read_config_dword(pdev, SNB_UNCORE_PCI_IMC_BAR_OFFSET + 4, &mch_bar);
+       addr |= ((resource_size_t)mch_bar << 32);
+#endif
+
+       box->io_addr = ioremap(addr, SNB_UNCORE_PCI_IMC_MAP_SIZE);
+}
+
+static struct intel_uncore_ops tgl_uncore_imc_freerunning_ops = {
+       .init_box       = tgl_uncore_imc_freerunning_init_box,
+       .exit_box       = uncore_mmio_exit_box,
+       .read_counter   = uncore_mmio_read_counter,
+       .hw_config      = uncore_freerunning_hw_config,
+};
+
+static struct attribute *tgl_uncore_imc_formats_attr[] = {
+       &format_attr_event.attr,
+       &format_attr_umask.attr,
+       NULL
+};
+
+static const struct attribute_group tgl_uncore_imc_format_group = {
+       .name = "format",
+       .attrs = tgl_uncore_imc_formats_attr,
+};
+
+static struct intel_uncore_type tgl_uncore_imc_free_running = {
+       .name                   = "imc_free_running",
+       .num_counters           = 3,
+       .num_boxes              = 2,
+       .num_freerunning_types  = TGL_MMIO_UNCORE_IMC_FREERUNNING_TYPE_MAX,
+       .freerunning            = tgl_uncore_imc_freerunning,
+       .ops                    = &tgl_uncore_imc_freerunning_ops,
+       .event_descs            = tgl_uncore_imc_events,
+       .format_group           = &tgl_uncore_imc_format_group,
+};
+
+static struct intel_uncore_type *tgl_mmio_uncores[] = {
+       &tgl_uncore_imc_free_running,
+       NULL
+};
+
+void tgl_l_uncore_mmio_init(void)
+{
+       tgl_uncore_imc_free_running.freerunning = tgl_l_uncore_imc_freerunning;
+       uncore_mmio_uncores = tgl_mmio_uncores;
+}
+
+void tgl_uncore_mmio_init(void)
+{
+       uncore_mmio_uncores = tgl_mmio_uncores;
+}
+
+/* end of Tiger Lake MMIO uncore support */
index ad20220..01023f0 100644 (file)
@@ -4380,10 +4380,10 @@ static struct pci_dev *snr_uncore_get_mc_dev(int id)
        return mc_dev;
 }
 
-static void snr_uncore_mmio_init_box(struct intel_uncore_box *box)
+static void __snr_uncore_mmio_init_box(struct intel_uncore_box *box,
+                                      unsigned int box_ctl, int mem_offset)
 {
        struct pci_dev *pdev = snr_uncore_get_mc_dev(box->dieid);
-       unsigned int box_ctl = uncore_mmio_box_ctl(box);
        resource_size_t addr;
        u32 pci_dword;
 
@@ -4393,7 +4393,7 @@ static void snr_uncore_mmio_init_box(struct intel_uncore_box *box)
        pci_read_config_dword(pdev, SNR_IMC_MMIO_BASE_OFFSET, &pci_dword);
        addr = (pci_dword & SNR_IMC_MMIO_BASE_MASK) << 23;
 
-       pci_read_config_dword(pdev, SNR_IMC_MMIO_MEM0_OFFSET, &pci_dword);
+       pci_read_config_dword(pdev, mem_offset, &pci_dword);
        addr |= (pci_dword & SNR_IMC_MMIO_MEM0_MASK) << 12;
 
        addr += box_ctl;
@@ -4405,6 +4405,12 @@ static void snr_uncore_mmio_init_box(struct intel_uncore_box *box)
        writel(IVBEP_PMON_BOX_CTL_INT, box->io_addr);
 }
 
+static void snr_uncore_mmio_init_box(struct intel_uncore_box *box)
+{
+       __snr_uncore_mmio_init_box(box, uncore_mmio_box_ctl(box),
+                                  SNR_IMC_MMIO_MEM0_OFFSET);
+}
+
 static void snr_uncore_mmio_disable_box(struct intel_uncore_box *box)
 {
        u32 config;
index d13b352..8e4d039 100644 (file)
@@ -3,7 +3,7 @@
 # Makefile for the ia32 kernel emulation subsystem.
 #
 
-obj-$(CONFIG_IA32_EMULATION) := sys_ia32.o ia32_signal.o
+obj-$(CONFIG_IA32_EMULATION) := ia32_signal.o
 
 obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
 
index 1ae4e57..c7df20e 100644 (file)
@@ -12,7 +12,6 @@ struct amd_nb_bus_dev_range {
        u8 dev_limit;
 };
 
-extern const struct pci_device_id amd_nb_misc_ids[];
 extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[];
 
 extern bool early_is_amd_nb(u32 value);
index dc4cfc8..dc9dc7b 100644 (file)
@@ -4,14 +4,18 @@
 #ifndef _ASM_X86_CLOCKSOURCE_H
 #define _ASM_X86_CLOCKSOURCE_H
 
-#define VCLOCK_NONE    0       /* No vDSO clock available.             */
-#define VCLOCK_TSC     1       /* vDSO should use vread_tsc.           */
-#define VCLOCK_PVCLOCK 2       /* vDSO should use vread_pvclock.       */
-#define VCLOCK_HVCLOCK 3       /* vDSO should use vread_hvclock.       */
-#define VCLOCK_MAX     3
+#include <asm/vdso/clocksource.h>
 
-struct arch_clocksource_data {
-       int vclock_mode;
-};
+extern unsigned int vclocks_used;
+
+static inline bool vclock_was_used(int vclock)
+{
+       return READ_ONCE(vclocks_used) & (1U << vclock);
+}
+
+static inline void vclocks_set_used(unsigned int which)
+{
+       WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << which));
+}
 
 #endif /* _ASM_X86_CLOCKSOURCE_H */
index adc6cc8..ff6f3ca 100644 (file)
@@ -40,4 +40,16 @@ int mwait_usable(const struct cpuinfo_x86 *);
 unsigned int x86_family(unsigned int sig);
 unsigned int x86_model(unsigned int sig);
 unsigned int x86_stepping(unsigned int sig);
+#ifdef CONFIG_CPU_SUP_INTEL
+extern void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c);
+extern void switch_to_sld(unsigned long tifn);
+extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
+#else
+static inline void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) {}
+static inline void switch_to_sld(unsigned long tifn) {}
+static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code)
+{
+       return false;
+}
+#endif
 #endif /* _ASM_X86_CPU_H */
index 31c379c..cf3d621 100644 (file)
@@ -5,9 +5,139 @@
 /*
  * Declare drivers belonging to specific x86 CPUs
  * Similar in spirit to pci_device_id and related PCI functions
+ *
+ * The wildcard initializers are in mod_devicetable.h because
+ * file2alias needs them. Sigh.
  */
-
 #include <linux/mod_devicetable.h>
+/* Get the INTEL_FAM* model defines */
+#include <asm/intel-family.h>
+/* And the X86_VENDOR_* ones */
+#include <asm/processor.h>
+
+/* Centaur FAM6 models */
+#define X86_CENTAUR_FAM6_C7_A          0xa
+#define X86_CENTAUR_FAM6_C7_D          0xd
+#define X86_CENTAUR_FAM6_NANO          0xf
+
+/**
+ * X86_MATCH_VENDOR_FAM_MODEL_FEATURE - Base macro for CPU matching
+ * @_vendor:   The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *             The name is expanded to X86_VENDOR_@_vendor
+ * @_family:   The family number or X86_FAMILY_ANY
+ * @_model:    The model number, model constant or X86_MODEL_ANY
+ * @_feature:  A X86_FEATURE bit or X86_FEATURE_ANY
+ * @_data:     Driver specific data or NULL. The internal storage
+ *             format is unsigned long. The supplied value, pointer
+ *             etc. is casted to unsigned long internally.
+ *
+ * Use only if you need all selectors. Otherwise use one of the shorter
+ * macros of the X86_MATCH_* family. If there is no matching shorthand
+ * macro, consider to add one. If you really need to wrap one of the macros
+ * into another macro at the usage site for good reasons, then please
+ * start this local macro with X86_MATCH to allow easy grepping.
+ */
+#define X86_MATCH_VENDOR_FAM_MODEL_FEATURE(_vendor, _family, _model,   \
+                                          _feature, _data) {           \
+       .vendor         = X86_VENDOR_##_vendor,                         \
+       .family         = _family,                                      \
+       .model          = _model,                                       \
+       .feature        = _feature,                                     \
+       .driver_data    = (unsigned long) _data                         \
+}
+
+/**
+ * X86_MATCH_VENDOR_FAM_FEATURE - Macro for matching vendor, family and CPU feature
+ * @vendor:    The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *             The name is expanded to X86_VENDOR_@vendor
+ * @family:    The family number or X86_FAMILY_ANY
+ * @feature:   A X86_FEATURE bit
+ * @data:      Driver specific data or NULL. The internal storage
+ *             format is unsigned long. The supplied value, pointer
+ *             etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set to wildcards.
+ */
+#define X86_MATCH_VENDOR_FAM_FEATURE(vendor, family, feature, data)    \
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(vendor, family,              \
+                                          X86_MODEL_ANY, feature, data)
+
+/**
+ * X86_MATCH_VENDOR_FEATURE - Macro for matching vendor and CPU feature
+ * @vendor:    The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *             The name is expanded to X86_VENDOR_@vendor
+ * @feature:   A X86_FEATURE bit
+ * @data:      Driver specific data or NULL. The internal storage
+ *             format is unsigned long. The supplied value, pointer
+ *             etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set to wildcards.
+ */
+#define X86_MATCH_VENDOR_FEATURE(vendor, feature, data)                        \
+       X86_MATCH_VENDOR_FAM_FEATURE(vendor, X86_FAMILY_ANY, feature, data)
+
+/**
+ * X86_MATCH_FEATURE - Macro for matching a CPU feature
+ * @feature:   A X86_FEATURE bit
+ * @data:      Driver specific data or NULL. The internal storage
+ *             format is unsigned long. The supplied value, pointer
+ *             etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set to wildcards.
+ */
+#define X86_MATCH_FEATURE(feature, data)                               \
+       X86_MATCH_VENDOR_FEATURE(ANY, feature, data)
+
+/**
+ * X86_MATCH_VENDOR_FAM_MODEL - Match vendor, family and model
+ * @vendor:    The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *             The name is expanded to X86_VENDOR_@vendor
+ * @family:    The family number or X86_FAMILY_ANY
+ * @model:     The model number, model constant or X86_MODEL_ANY
+ * @data:      Driver specific data or NULL. The internal storage
+ *             format is unsigned long. The supplied value, pointer
+ *             etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set to wildcards.
+ */
+#define X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, data)                \
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(vendor, family, model,       \
+                                          X86_FEATURE_ANY, data)
+
+/**
+ * X86_MATCH_VENDOR_FAM - Match vendor and family
+ * @vendor:    The vendor name, e.g. INTEL, AMD, HYGON, ..., ANY
+ *             The name is expanded to X86_VENDOR_@vendor
+ * @family:    The family number or X86_FAMILY_ANY
+ * @data:      Driver specific data or NULL. The internal storage
+ *             format is unsigned long. The supplied value, pointer
+ *             etc. is casted to unsigned long internally.
+ *
+ * All other missing arguments to X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are
+ * set of wildcards.
+ */
+#define X86_MATCH_VENDOR_FAM(vendor, family, data)                     \
+       X86_MATCH_VENDOR_FAM_MODEL(vendor, family, X86_MODEL_ANY, data)
+
+/**
+ * X86_MATCH_INTEL_FAM6_MODEL - Match vendor INTEL, family 6 and model
+ * @model:     The model name without the INTEL_FAM6_ prefix or ANY
+ *             The model name is expanded to INTEL_FAM6_@model internally
+ * @data:      Driver specific data or NULL. The internal storage
+ *             format is unsigned long. The supplied value, pointer
+ *             etc. is casted to unsigned long internally.
+ *
+ * The vendor is set to INTEL, the family to 6 and all other missing
+ * arguments of X86_MATCH_VENDOR_FAM_MODEL_FEATURE() are set to wildcards.
+ *
+ * See X86_MATCH_VENDOR_FAM_MODEL_FEATURE() for further information.
+ */
+#define X86_MATCH_INTEL_FAM6_MODEL(model, data)                                \
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL, 6, INTEL_FAM6_##model, data)
 
 /*
  * Match specific microcode revisions.
index f3327cb..db18994 100644 (file)
 #define X86_FEATURE_IBRS               ( 7*32+25) /* Indirect Branch Restricted Speculation */
 #define X86_FEATURE_IBPB               ( 7*32+26) /* Indirect Branch Prediction Barrier */
 #define X86_FEATURE_STIBP              ( 7*32+27) /* Single Thread Indirect Branch Predictors */
-#define X86_FEATURE_ZEN                        ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */
+#define X86_FEATURE_ZEN                        ( 7*32+28) /* "" CPU is AMD family 0x17 or above (Zen) */
 #define X86_FEATURE_L1TF_PTEINV                ( 7*32+29) /* "" L1TF workaround PTE inversion */
 #define X86_FEATURE_IBRS_ENHANCED      ( 7*32+30) /* Enhanced IBRS */
 #define X86_FEATURE_MSR_IA32_FEAT_CTL  ( 7*32+31) /* "" MSR IA32_FEAT_CTL configured */
 #define X86_FEATURE_CQM_MBM_LOCAL      (11*32+ 3) /* LLC Local MBM monitoring */
 #define X86_FEATURE_FENCE_SWAPGS_USER  (11*32+ 4) /* "" LFENCE in user entry SWAPGS path */
 #define X86_FEATURE_FENCE_SWAPGS_KERNEL        (11*32+ 5) /* "" LFENCE in kernel entry SWAPGS path */
+#define X86_FEATURE_SPLIT_LOCK_DETECT  (11*32+ 6) /* #AC for split lock */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX512_BF16                (12*32+ 5) /* AVX512 BFLOAT16 instructions */
 #define X86_FEATURE_AMD_IBRS           (13*32+14) /* "" Indirect Branch Restricted Speculation */
 #define X86_FEATURE_AMD_STIBP          (13*32+15) /* "" Single Thread Indirect Branch Predictors */
 #define X86_FEATURE_AMD_STIBP_ALWAYS_ON        (13*32+17) /* "" Single Thread Indirect Branch Predictors always-on preferred */
+#define X86_FEATURE_AMD_PPIN           (13*32+23) /* Protected Processor Inventory Number */
 #define X86_FEATURE_AMD_SSBD           (13*32+24) /* "" Speculative Store Bypass Disable */
 #define X86_FEATURE_VIRT_SSBD          (13*32+25) /* Virtualized Speculative Store Bypass Disable */
 #define X86_FEATURE_AMD_SSB_NO         (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
 #define X86_FEATURE_INTEL_STIBP                (18*32+27) /* "" Single Thread Indirect Branch Predictors */
 #define X86_FEATURE_FLUSH_L1D          (18*32+28) /* Flush L1D cache */
 #define X86_FEATURE_ARCH_CAPABILITIES  (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
+#define X86_FEATURE_CORE_CAPABILITIES  (18*32+30) /* "" IA32_CORE_CAPABILITIES MSR */
 #define X86_FEATURE_SPEC_CTRL_SSBD     (18*32+31) /* "" Speculative Store Bypass Disable */
 
 /*
index ae391f6..f71a0cc 100644 (file)
@@ -42,8 +42,8 @@
         * Emit CFI data in .debug_frame sections, not .eh_frame sections.
         * The latter we currently just discard since we don't do DWARF
         * unwinding at runtime.  So only the offline DWARF information is
-        * useful to anyone.  Note we should not use this directive if
-        * vmlinux.lds.S gets changed so it doesn't discard .eh_frame.
+        * useful to anyone.  Note we should not use this directive if we
+        * ever decide to enable DWARF unwinding at runtime.
         */
        .cfi_sections .debug_frame
 #else
index 86169a2..cdcf48d 100644 (file)
@@ -10,6 +10,8 @@
 #include <asm/mmu_context.h>
 #include <linux/build_bug.h>
 
+extern unsigned long efi_fw_vendor, efi_config_table;
+
 /*
  * We map the EFI regions needed for runtime services non-contiguously,
  * with preserved alignment on virtual addresses starting from -4G down
@@ -34,8 +36,6 @@ static inline bool efi_have_uv1_memmap(void)
 #define EFI32_LOADER_SIGNATURE "EL32"
 #define EFI64_LOADER_SIGNATURE "EL64"
 
-#define MAX_CMDLINE_ADDRESS    UINT_MAX
-
 #define ARCH_EFI_IRQ_FLAGS_MASK        X86_EFLAGS_IF
 
 /*
@@ -180,7 +180,6 @@ extern void __init efi_uv1_memmap_phys_epilog(pgd_t *save_pgd);
 
 struct efi_setup_data {
        u64 fw_vendor;
-       u64 runtime;
        u64 tables;
        u64 smbios;
        u64 reserved[8];
@@ -219,7 +218,8 @@ extern void efi_thunk_runtime_setup(void);
 efi_status_t efi_set_virtual_address_map(unsigned long memory_map_size,
                                         unsigned long descriptor_size,
                                         u32 descriptor_version,
-                                        efi_memory_desc_t *virtual_map);
+                                        efi_memory_desc_t *virtual_map,
+                                        unsigned long systab_phys);
 
 /* arch specific definitions used by the stub code */
 
@@ -270,6 +270,11 @@ static inline void *efi64_zero_upper(void *p)
        return p;
 }
 
+static inline u32 efi64_convert_status(efi_status_t status)
+{
+       return (u32)(status | (u64)status >> 32);
+}
+
 #define __efi64_argmap_free_pages(addr, size)                          \
        ((addr), 0, (size))
 
@@ -285,11 +290,21 @@ static inline void *efi64_zero_upper(void *p)
 #define __efi64_argmap_locate_protocol(protocol, reg, interface)       \
        ((protocol), (reg), efi64_zero_upper(interface))
 
+#define __efi64_argmap_locate_device_path(protocol, path, handle)      \
+       ((protocol), (path), efi64_zero_upper(handle))
+
+#define __efi64_argmap_exit(handle, status, size, data)                        \
+       ((handle), efi64_convert_status(status), (size), (data))
+
 /* PCI I/O */
 #define __efi64_argmap_get_location(protocol, seg, bus, dev, func)     \
        ((protocol), efi64_zero_upper(seg), efi64_zero_upper(bus),      \
         efi64_zero_upper(dev), efi64_zero_upper(func))
 
+/* LoadFile */
+#define __efi64_argmap_load_file(protocol, path, policy, bufsize, buf) \
+       ((protocol), (path), (policy), efi64_zero_upper(bufsize), (buf))
+
 /*
  * The macros below handle the plumbing for the argument mapping. To add a
  * mapping for a specific EFI method, simply define a macro
index 13c83fe..f9c0011 100644 (file)
 #include <asm/processor.h>
 #include <asm/smap.h>
 
-#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg)    \
-       asm volatile("\t" ASM_STAC "\n"                         \
-                    "1:\t" insn "\n"                           \
-                    "2:\t" ASM_CLAC "\n"                       \
+#define unsafe_atomic_op1(insn, oval, uaddr, oparg, label)     \
+do {                                                           \
+       int oldval = 0, ret;                                    \
+       asm volatile("1:\t" insn "\n"                           \
+                    "2:\n"                                     \
                     "\t.section .fixup,\"ax\"\n"               \
                     "3:\tmov\t%3, %1\n"                        \
                     "\tjmp\t2b\n"                              \
                     "\t.previous\n"                            \
                     _ASM_EXTABLE_UA(1b, 3b)                    \
                     : "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
-                    : "i" (-EFAULT), "0" (oparg), "1" (0))
+                    : "i" (-EFAULT), "0" (oparg), "1" (0));    \
+       if (ret)                                                \
+               goto label;                                     \
+       *oval = oldval;                                         \
+} while(0)
 
-#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg)    \
-       asm volatile("\t" ASM_STAC "\n"                         \
-                    "1:\tmovl  %2, %0\n"                       \
-                    "\tmovl\t%0, %3\n"                         \
+
+#define unsafe_atomic_op2(insn, oval, uaddr, oparg, label)     \
+do {                                                           \
+       int oldval = 0, ret, tem;                               \
+       asm volatile("1:\tmovl  %2, %0\n"                       \
+                    "2:\tmovl\t%0, %3\n"                       \
                     "\t" insn "\n"                             \
-                    "2:\t" LOCK_PREFIX "cmpxchgl %3, %2\n"     \
-                    "\tjnz\t1b\n"                              \
-                    "3:\t" ASM_CLAC "\n"                       \
+                    "3:\t" LOCK_PREFIX "cmpxchgl %3, %2\n"     \
+                    "\tjnz\t2b\n"                              \
+                    "4:\n"                                     \
                     "\t.section .fixup,\"ax\"\n"               \
-                    "4:\tmov\t%5, %1\n"                        \
-                    "\tjmp\t3b\n"                              \
+                    "5:\tmov\t%5, %1\n"                        \
+                    "\tjmp\t4b\n"                              \
                     "\t.previous\n"                            \
-                    _ASM_EXTABLE_UA(1b, 4b)                    \
-                    _ASM_EXTABLE_UA(2b, 4b)                    \
+                    _ASM_EXTABLE_UA(1b, 5b)                    \
+                    _ASM_EXTABLE_UA(3b, 5b)                    \
                     : "=&a" (oldval), "=&r" (ret),             \
                       "+m" (*uaddr), "=&r" (tem)               \
-                    : "r" (oparg), "i" (-EFAULT), "1" (0))
+                    : "r" (oparg), "i" (-EFAULT), "1" (0));    \
+       if (ret)                                                \
+               goto label;                                     \
+       *oval = oldval;                                         \
+} while(0)
 
-static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
+static __always_inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
                u32 __user *uaddr)
 {
-       int oldval = 0, ret, tem;
-
-       pagefault_disable();
+       if (!user_access_begin(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
-               __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
+               unsafe_atomic_op1("xchgl %0, %2", oval, uaddr, oparg, Efault);
                break;
        case FUTEX_OP_ADD:
-               __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
-                                  uaddr, oparg);
+               unsafe_atomic_op1(LOCK_PREFIX "xaddl %0, %2", oval,
+                                  uaddr, oparg, Efault);
                break;
        case FUTEX_OP_OR:
-               __futex_atomic_op2("orl %4, %3", ret, oldval, uaddr, oparg);
+               unsafe_atomic_op2("orl %4, %3", oval, uaddr, oparg, Efault);
                break;
        case FUTEX_OP_ANDN:
-               __futex_atomic_op2("andl %4, %3", ret, oldval, uaddr, ~oparg);
+               unsafe_atomic_op2("andl %4, %3", oval, uaddr, ~oparg, Efault);
                break;
        case FUTEX_OP_XOR:
-               __futex_atomic_op2("xorl %4, %3", ret, oldval, uaddr, oparg);
+               unsafe_atomic_op2("xorl %4, %3", oval, uaddr, oparg, Efault);
                break;
        default:
-               ret = -ENOSYS;
+               user_access_end();
+               return -ENOSYS;
        }
-
-       pagefault_enable();
-
-       if (!ret)
-               *oval = oldval;
-
-       return ret;
+       user_access_end();
+       return 0;
+Efault:
+       user_access_end();
+       return -EFAULT;
 }
 
 static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
                                                u32 oldval, u32 newval)
 {
-       return user_atomic_cmpxchg_inatomic(uval, uaddr, oldval, newval);
+       int ret = 0;
+
+       if (!user_access_begin(uaddr, sizeof(u32)))
+               return -EFAULT;
+       asm volatile("\n"
+               "1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"
+               "2:\n"
+               "\t.section .fixup, \"ax\"\n"
+               "3:\tmov     %3, %0\n"
+               "\tjmp     2b\n"
+               "\t.previous\n"
+               _ASM_EXTABLE_UA(1b, 3b)
+               : "+r" (ret), "=a" (oldval), "+m" (*uaddr)
+               : "i" (-EFAULT), "r" (newval), "1" (oldval)
+               : "memory"
+       );
+       user_access_end();
+       *uval = oldval;
+       return ret;
 }
 
 #endif
index 4981c29..8f1e94f 100644 (file)
@@ -35,6 +35,9 @@
  * The #define line may optionally include a comment including platform names.
  */
 
+/* Wildcard match for FAM6 so X86_MATCH_INTEL_FAM6_MODEL(ANY) works */
+#define INTEL_FAM6_ANY                 X86_MODEL_ANY
+
 #define INTEL_FAM6_CORE_YONAH          0x0E
 
 #define INTEL_FAM6_CORE2_MEROM         0x0F
 #define INTEL_FAM6_XEON_PHI_KNL                0x57 /* Knights Landing */
 #define INTEL_FAM6_XEON_PHI_KNM                0x85 /* Knights Mill */
 
-/* Useful macros */
-#define INTEL_CPU_FAM_ANY(_family, _model, _driver_data)       \
-{                                                              \
-       .vendor         = X86_VENDOR_INTEL,                     \
-       .family         = _family,                              \
-       .model          = _model,                               \
-       .feature        = X86_FEATURE_ANY,                      \
-       .driver_data    = (kernel_ulong_t)&_driver_data         \
-}
-
-#define INTEL_CPU_FAM6(_model, _driver_data)                   \
-       INTEL_CPU_FAM_ANY(6, INTEL_FAM6_##_model, _driver_data)
+/* Family 5 */
+#define INTEL_FAM5_QUARK_X1000         0x09 /* Quark X1000 SoC */
 
 #endif /* _ASM_X86_INTEL_FAMILY_H */
index 02c6ef8..07344d8 100644 (file)
@@ -19,7 +19,14 @@ struct task_struct;
 void io_bitmap_share(struct task_struct *tsk);
 void io_bitmap_exit(void);
 
-void tss_update_io_bitmap(void);
+void native_tss_update_io_bitmap(void);
+
+#ifdef CONFIG_PARAVIRT_XXL
+#include <asm/paravirt.h>
+#else
+#define tss_update_io_bitmap native_tss_update_io_bitmap
+#endif
+
 #else
 static inline void io_bitmap_share(struct task_struct *tsk) { }
 static inline void io_bitmap_exit(void) { }
index a176f61..72fba0e 100644 (file)
@@ -36,7 +36,7 @@ extern void native_init_IRQ(void);
 
 extern void handle_irq(struct irq_desc *desc, struct pt_regs *regs);
 
-extern __visible unsigned int do_IRQ(struct pt_regs *regs);
+extern __visible void do_IRQ(struct pt_regs *regs);
 
 extern void init_ISA_irqs(void);
 
index 95b1f05..073eb7a 100644 (file)
@@ -36,6 +36,7 @@ typedef u8 kprobe_opcode_t;
 
 /* optinsn template addresses */
 extern __visible kprobe_opcode_t optprobe_template_entry[];
+extern __visible kprobe_opcode_t optprobe_template_clac[];
 extern __visible kprobe_opcode_t optprobe_template_val[];
 extern __visible kprobe_opcode_t optprobe_template_call[];
 extern __visible kprobe_opcode_t optprobe_template_end[];
index 03946eb..c06e835 100644 (file)
@@ -292,6 +292,14 @@ enum x86emul_mode {
 #define X86EMUL_SMM_MASK             (1 << 6)
 #define X86EMUL_SMM_INSIDE_NMI_MASK  (1 << 7)
 
+/*
+ * fastop functions are declared as taking a never-defined fastop parameter,
+ * so they can't be called from C directly.
+ */
+struct fastop;
+
+typedef void (*fastop_t)(struct fastop *);
+
 struct x86_emulate_ctxt {
        const struct x86_emulate_ops *ops;
 
@@ -324,7 +332,10 @@ struct x86_emulate_ctxt {
        struct operand src;
        struct operand src2;
        struct operand dst;
-       int (*execute)(struct x86_emulate_ctxt *ctxt);
+       union {
+               int (*execute)(struct x86_emulate_ctxt *ctxt);
+               fastop_t fop;
+       };
        int (*check_perm)(struct x86_emulate_ctxt *ctxt);
        /*
         * The following six fields are cleared together,
@@ -349,7 +360,6 @@ struct x86_emulate_ctxt {
        u64 d;
        unsigned long _eip;
        struct operand memop;
-       /* Fields above regs are cleared together. */
        unsigned long _regs[NR_VCPU_REGS];
        struct operand *memopp;
        struct fetch_cache fetch;
index 40a0c0f..98959e8 100644 (file)
@@ -1122,6 +1122,7 @@ struct kvm_x86_ops {
        int (*handle_exit)(struct kvm_vcpu *vcpu,
                enum exit_fastpath_completion exit_fastpath);
        int (*skip_emulated_instruction)(struct kvm_vcpu *vcpu);
+       void (*update_emulated_instruction)(struct kvm_vcpu *vcpu);
        void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask);
        u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu);
        void (*patch_hypercall)(struct kvm_vcpu *vcpu,
@@ -1146,7 +1147,7 @@ struct kvm_x86_ops {
        void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
        void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu);
        void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa);
-       void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
+       int (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
        int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu);
        int (*set_tss_addr)(struct kvm *kvm, unsigned int addr);
        int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr);
index 4359b95..f9cea08 100644 (file)
 
 #define MCE_OVERFLOW 0         /* bit 0 in flags means overflow */
 
-#define MCE_LOG_LEN 32
+#define MCE_LOG_MIN_LEN 32U
 #define MCE_LOG_SIGNATURE      "MACHINECHECK"
 
 /* AMD Scalable MCA */
  */
 struct mce_log_buffer {
        char signature[12]; /* "MACHINECHECK" */
-       unsigned len;       /* = MCE_LOG_LEN */
+       unsigned len;       /* = elements in .mce_entry[] */
        unsigned next;
        unsigned flags;
        unsigned recordlen;     /* length of struct mce */
-       struct mce entry[MCE_LOG_LEN];
+       struct mce entry[];
 };
 
 enum mce_notifier_prios {
@@ -238,9 +238,6 @@ extern void mce_disable_bank(int bank);
 /*
  * Exception handler
  */
-
-/* Call the installed machine check handler for this CPU setup. */
-extern void (*machine_check_vector)(struct pt_regs *, long error_code);
 void do_machine_check(struct pt_regs *, long);
 
 /*
index 6b79515..edc2c58 100644 (file)
@@ -46,7 +46,9 @@ typedef int (*hyperv_fill_flush_list_func)(
 #define hv_set_reference_tsc(val) \
        wrmsrl(HV_X64_MSR_REFERENCE_TSC, val)
 #define hv_set_clocksource_vdso(val) \
-       ((val).archdata.vclock_mode = VCLOCK_HVCLOCK)
+       ((val).vdso_clock_mode = VDSO_CLOCKMODE_HVCLOCK)
+#define hv_enable_vdso_clocksource() \
+       vclocks_set_used(VDSO_CLOCKMODE_HVCLOCK);
 #define hv_get_raw_timer() rdtsc_ordered()
 
 void hyperv_callback_vector(void);
index d5e517d..12c9684 100644 (file)
 
 /* Intel MSRs. Some also available on other CPUs */
 
+#define MSR_TEST_CTRL                          0x00000033
+#define MSR_TEST_CTRL_SPLIT_LOCK_DETECT_BIT    29
+#define MSR_TEST_CTRL_SPLIT_LOCK_DETECT                BIT(MSR_TEST_CTRL_SPLIT_LOCK_DETECT_BIT)
+
 #define MSR_IA32_SPEC_CTRL             0x00000048 /* Speculation Control */
 #define SPEC_CTRL_IBRS                 BIT(0)     /* Indirect Branch Restricted Speculation */
 #define SPEC_CTRL_STIBP_SHIFT          1          /* Single Thread Indirect Branch Predictor (STIBP) bit */
  */
 #define MSR_IA32_UMWAIT_CONTROL_TIME_MASK      (~0x03U)
 
+/* Abbreviated from Intel SDM name IA32_CORE_CAPABILITIES */
+#define MSR_IA32_CORE_CAPS                       0x000000cf
+#define MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT_BIT  5
+#define MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT     BIT(MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT_BIT)
+
 #define MSR_PKG_CST_CONFIG_CONTROL     0x000000e2
 #define NHM_C3_AUTO_DEMOTE             (1UL << 25)
 #define NHM_C1_AUTO_DEMOTE             (1UL << 26)
index 86e7317..694d8da 100644 (file)
@@ -295,6 +295,13 @@ static inline void write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
        PVOP_VCALL3(cpu.write_idt_entry, dt, entry, g);
 }
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+static inline void tss_update_io_bitmap(void)
+{
+       PVOP_VCALL0(cpu.update_io_bitmap);
+}
+#endif
+
 static inline void paravirt_activate_mm(struct mm_struct *prev,
                                        struct mm_struct *next)
 {
index 8481296..732f62e 100644 (file)
@@ -140,6 +140,10 @@ struct pv_cpu_ops {
 
        void (*load_sp0)(unsigned long sp0);
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+       void (*update_io_bitmap)(void);
+#endif
+
        void (*wbinvd)(void);
 
        /* cpuid emulation, mostly so that caps bits can be disabled */
index 29964b0..e855e9c 100644 (file)
 
 #define AMD64_L3_SLICE_SHIFT                           48
 #define AMD64_L3_SLICE_MASK                            \
-       ((0xFULL) << AMD64_L3_SLICE_SHIFT)
+       (0xFULL << AMD64_L3_SLICE_SHIFT)
+#define AMD64_L3_SLICEID_MASK                          \
+       (0x7ULL << AMD64_L3_SLICE_SHIFT)
 
 #define AMD64_L3_THREAD_SHIFT                          56
 #define AMD64_L3_THREAD_MASK                           \
-       ((0xFFULL) << AMD64_L3_THREAD_SHIFT)
+       (0xFFULL << AMD64_L3_THREAD_SHIFT)
+#define AMD64_L3_F19H_THREAD_MASK                      \
+       (0x3ULL << AMD64_L3_THREAD_SHIFT)
+
+#define AMD64_L3_EN_ALL_CORES                          BIT_ULL(47)
+#define AMD64_L3_EN_ALL_SLICES                         BIT_ULL(46)
+
+#define AMD64_L3_COREID_SHIFT                          42
+#define AMD64_L3_COREID_MASK                           \
+       (0x7ULL << AMD64_L3_COREID_SHIFT)
 
 #define X86_RAW_EVENT_MASK             \
        (ARCH_PERFMON_EVENTSEL_EVENT |  \
index 3d4cb83..69485ca 100644 (file)
@@ -103,14 +103,14 @@ static __always_inline bool should_resched(int preempt_offset)
 }
 
 #ifdef CONFIG_PREEMPTION
-  extern asmlinkage void ___preempt_schedule(void);
+  extern asmlinkage void preempt_schedule_thunk(void);
 # define __preempt_schedule() \
-       asm volatile ("call ___preempt_schedule" : ASM_CALL_CONSTRAINT)
+       asm volatile ("call preempt_schedule_thunk" : ASM_CALL_CONSTRAINT)
 
   extern asmlinkage void preempt_schedule(void);
-  extern asmlinkage void ___preempt_schedule_notrace(void);
+  extern asmlinkage void preempt_schedule_notrace_thunk(void);
 # define __preempt_schedule_notrace() \
-       asm volatile ("call ___preempt_schedule_notrace" : ASM_CALL_CONSTRAINT)
+       asm volatile ("call preempt_schedule_notrace_thunk" : ASM_CALL_CONSTRAINT)
 
   extern asmlinkage void preempt_schedule_notrace(void);
 #endif
index 09705cc..94789db 100644 (file)
@@ -26,6 +26,7 @@ struct vm86;
 #include <asm/fpu/types.h>
 #include <asm/unwind_hints.h>
 #include <asm/vmxfeatures.h>
+#include <asm/vdso/processor.h>
 
 #include <linux/personality.h>
 #include <linux/cache.h>
@@ -677,17 +678,6 @@ static inline unsigned int cpuid_edx(unsigned int op)
        return edx;
 }
 
-/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-static __always_inline void rep_nop(void)
-{
-       asm volatile("rep; nop" ::: "memory");
-}
-
-static __always_inline void cpu_relax(void)
-{
-       rep_nop();
-}
-
 /*
  * This function forces the icache and prefetched instruction stream to
  * catch up with reality in two very specific cases:
index 036c360..a6e8373 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _ASM_X86_SECTIONS_H
 #define _ASM_X86_SECTIONS_H
 
+#define arch_is_kernel_initmem_freed arch_is_kernel_initmem_freed
+
 #include <asm-generic/sections.h>
 #include <asm/extable.h>
 
@@ -14,4 +16,22 @@ extern char __end_rodata_hpage_align[];
 
 extern char __end_of_kernel_reserve[];
 
+extern unsigned long _brk_start, _brk_end;
+
+static inline bool arch_is_kernel_initmem_freed(unsigned long addr)
+{
+       /*
+        * If _brk_start has not been cleared, brk allocation is incomplete,
+        * and we can not make assumptions about its use.
+        */
+       if (_brk_start)
+               return 0;
+
+       /*
+        * After brk allocation is complete, space between _brk_end and _end
+        * is available for allocation.
+        */
+       return addr >= _brk_end && addr < (unsigned long)&_end;
+}
+
 #endif /* _ASM_X86_SECTIONS_H */
index 2fcbd6f..bd26834 100644 (file)
@@ -17,9 +17,4 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
 int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
                     struct pt_regs *regs, unsigned long mask);
 
-
-#ifdef CONFIG_X86_X32_ABI
-asmlinkage long sys32_x32_rt_sigreturn(void);
-#endif
-
 #endif /* _ASM_X86_SIGHANDLING_H */
index 8db3fdb..6435294 100644 (file)
 #include <uapi/linux/audit.h>
 #include <linux/sched.h>
 #include <linux/err.h>
-#include <asm/asm-offsets.h>   /* For NR_syscalls */
 #include <asm/thread_info.h>   /* for TS_COMPAT */
 #include <asm/unistd.h>
 
-#ifdef CONFIG_X86_64
-typedef asmlinkage long (*sys_call_ptr_t)(const struct pt_regs *);
-#else
-typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long,
-                                         unsigned long, unsigned long,
-                                         unsigned long, unsigned long);
-#endif /* CONFIG_X86_64 */
+typedef long (*sys_call_ptr_t)(const struct pt_regs *);
 extern const sys_call_ptr_t sys_call_table[];
 
 #if defined(CONFIG_X86_32)
 #define ia32_sys_call_table sys_call_table
-#define __NR_syscall_compat_max __NR_syscall_max
-#define IA32_NR_syscalls NR_syscalls
 #endif
 
 #if defined(CONFIG_IA32_EMULATION)
index e2389ce..a84333a 100644 (file)
@@ -8,6 +8,50 @@
 
 struct pt_regs;
 
+extern long __x64_sys_ni_syscall(const struct pt_regs *regs);
+extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
+
+/*
+ * Instead of the generic __SYSCALL_DEFINEx() definition, the x86 version takes
+ * struct pt_regs *regs as the only argument of the syscall stub(s) named as:
+ * __x64_sys_*()         - 64-bit native syscall
+ * __ia32_sys_*()        - 32-bit native syscall or common compat syscall
+ * __ia32_compat_sys_*() - 32-bit compat syscall
+ * __x32_compat_sys_*()  - 64-bit X32 compat syscall
+ *
+ * The registers are decoded according to the ABI:
+ * 64-bit: RDI, RSI, RDX, R10, R8, R9
+ * 32-bit: EBX, ECX, EDX, ESI, EDI, EBP
+ *
+ * The stub then passes the decoded arguments to the __se_sys_*() wrapper to
+ * perform sign-extension (omitted for zero-argument syscalls).  Finally the
+ * arguments are passed to the __do_sys_*() function which is the actual
+ * syscall.  These wrappers are marked as inline so the compiler can optimize
+ * the functions where appropriate.
+ *
+ * Example assembly (slightly re-ordered for better readability):
+ *
+ * <__x64_sys_recv>:           <-- syscall with 4 parameters
+ *     callq   <__fentry__>
+ *
+ *     mov     0x70(%rdi),%rdi <-- decode regs->di
+ *     mov     0x68(%rdi),%rsi <-- decode regs->si
+ *     mov     0x60(%rdi),%rdx <-- decode regs->dx
+ *     mov     0x38(%rdi),%rcx <-- decode regs->r10
+ *
+ *     xor     %r9d,%r9d       <-- clear %r9
+ *     xor     %r8d,%r8d       <-- clear %r8
+ *
+ *     callq   __sys_recvfrom  <-- do the actual work in __sys_recvfrom()
+ *                                 which takes 6 arguments
+ *
+ *     cltq                    <-- extend return value to 64-bit
+ *     retq                    <-- return
+ *
+ * This approach avoids leaking random user-provided register content down
+ * the call chain.
+ */
+
 /* Mapping of registers to parameters for syscalls on x86-64 and x32 */
 #define SC_X86_64_REGS_TO_ARGS(x, ...)                                 \
        __MAP(x,__SC_ARGS                                               \
@@ -21,68 +65,96 @@ struct pt_regs;
              ,,(unsigned int)regs->dx,,(unsigned int)regs->si          \
              ,,(unsigned int)regs->di,,(unsigned int)regs->bp)
 
-#ifdef CONFIG_IA32_EMULATION
-/*
- * For IA32 emulation, we need to handle "compat" syscalls *and* create
- * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the
- * ia32 regs in the proper order for shared or "common" syscalls. As some
- * syscalls may not be implemented, we need to expand COND_SYSCALL in
- * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this
- * case as well.
- */
-#define __IA32_COMPAT_SYS_STUB0(x, name)                               \
-       asmlinkage long __ia32_compat_sys_##name(const struct pt_regs *regs);\
-       ALLOW_ERROR_INJECTION(__ia32_compat_sys_##name, ERRNO);         \
-       asmlinkage long __ia32_compat_sys_##name(const struct pt_regs *regs)\
+#define __SYS_STUB0(abi, name)                                         \
+       long __##abi##_##name(const struct pt_regs *regs);              \
+       ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO);                 \
+       long __##abi##_##name(const struct pt_regs *regs)               \
+               __alias(__do_##name);
+
+#define __SYS_STUBx(abi, name, ...)                                    \
+       long __##abi##_##name(const struct pt_regs *regs);              \
+       ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO);                 \
+       long __##abi##_##name(const struct pt_regs *regs)               \
        {                                                               \
-               return __se_compat_sys_##name();                        \
+               return __se_##name(__VA_ARGS__);                        \
        }
 
-#define __IA32_COMPAT_SYS_STUBx(x, name, ...)                          \
-       asmlinkage long __ia32_compat_sys##name(const struct pt_regs *regs);\
-       ALLOW_ERROR_INJECTION(__ia32_compat_sys##name, ERRNO);          \
-       asmlinkage long __ia32_compat_sys##name(const struct pt_regs *regs)\
+#define __COND_SYSCALL(abi, name)                                      \
+       __weak long __##abi##_##name(const struct pt_regs *__unused)    \
        {                                                               \
-               return __se_compat_sys##name(SC_IA32_REGS_TO_ARGS(x,__VA_ARGS__));\
+               return sys_ni_syscall();                                \
        }
 
+#define __SYS_NI(abi, name)                                            \
+       SYSCALL_ALIAS(__##abi##_##name, sys_ni_posix_timers);
+
+#ifdef CONFIG_X86_64
+#define __X64_SYS_STUB0(name)                                          \
+       __SYS_STUB0(x64, sys_##name)
+
+#define __X64_SYS_STUBx(x, name, ...)                                  \
+       __SYS_STUBx(x64, sys##name,                                     \
+                   SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
+
+#define __X64_COND_SYSCALL(name)                                       \
+       __COND_SYSCALL(x64, sys_##name)
+
+#define __X64_SYS_NI(name)                                             \
+       __SYS_NI(x64, sys_##name)
+#else /* CONFIG_X86_64 */
+#define __X64_SYS_STUB0(name)
+#define __X64_SYS_STUBx(x, name, ...)
+#define __X64_COND_SYSCALL(name)
+#define __X64_SYS_NI(name)
+#endif /* CONFIG_X86_64 */
+
+#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
+#define __IA32_SYS_STUB0(name)                                         \
+       __SYS_STUB0(ia32, sys_##name)
+
 #define __IA32_SYS_STUBx(x, name, ...)                                 \
-       asmlinkage long __ia32_sys##name(const struct pt_regs *regs);   \
-       ALLOW_ERROR_INJECTION(__ia32_sys##name, ERRNO);                 \
-       asmlinkage long __ia32_sys##name(const struct pt_regs *regs)    \
-       {                                                               \
-               return __se_sys##name(SC_IA32_REGS_TO_ARGS(x,__VA_ARGS__));\
-       }
+       __SYS_STUBx(ia32, sys##name,                                    \
+                   SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
+
+#define __IA32_COND_SYSCALL(name)                                      \
+       __COND_SYSCALL(ia32, sys_##name)
 
+#define __IA32_SYS_NI(name)                                            \
+       __SYS_NI(ia32, sys_##name)
+#else /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
+#define __IA32_SYS_STUB0(name)
+#define __IA32_SYS_STUBx(x, name, ...)
+#define __IA32_COND_SYSCALL(name)
+#define __IA32_SYS_NI(name)
+#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
+
+#ifdef CONFIG_IA32_EMULATION
 /*
- * To keep the naming coherent, re-define SYSCALL_DEFINE0 to create an alias
- * named __ia32_sys_*()
+ * For IA32 emulation, we need to handle "compat" syscalls *and* create
+ * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the
+ * ia32 regs in the proper order for shared or "common" syscalls. As some
+ * syscalls may not be implemented, we need to expand COND_SYSCALL in
+ * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this
+ * case as well.
  */
+#define __IA32_COMPAT_SYS_STUB0(name)                                  \
+       __SYS_STUB0(ia32, compat_sys_##name)
 
-#define SYSCALL_DEFINE0(sname)                                         \
-       SYSCALL_METADATA(_##sname, 0);                                  \
-       asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\
-       ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO);                \
-       SYSCALL_ALIAS(__ia32_sys_##sname, __x64_sys_##sname);           \
-       asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused)
+#define __IA32_COMPAT_SYS_STUBx(x, name, ...)                          \
+       __SYS_STUBx(ia32, compat_sys##name,                             \
+                   SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
 
-#define COND_SYSCALL(name)                                                     \
-       asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused) \
-       {                                                                       \
-               return sys_ni_syscall();                                        \
-       }                                                                       \
-       asmlinkage __weak long __ia32_sys_##name(const struct pt_regs *__unused)\
-       {                                                                       \
-               return sys_ni_syscall();                                        \
-       }
+#define __IA32_COMPAT_COND_SYSCALL(name)                               \
+       __COND_SYSCALL(ia32, compat_sys_##name)
 
-#define SYS_NI(name)                                                   \
-       SYSCALL_ALIAS(__x64_sys_##name, sys_ni_posix_timers);           \
-       SYSCALL_ALIAS(__ia32_sys_##name, sys_ni_posix_timers)
+#define __IA32_COMPAT_SYS_NI(name)                                     \
+       __SYS_NI(ia32, compat_sys_##name)
 
 #else /* CONFIG_IA32_EMULATION */
+#define __IA32_COMPAT_SYS_STUB0(name)
 #define __IA32_COMPAT_SYS_STUBx(x, name, ...)
-#define __IA32_SYS_STUBx(x, fullname, name, ...)
+#define __IA32_COMPAT_COND_SYSCALL(name)
+#define __IA32_COMPAT_SYS_NI(name)
 #endif /* CONFIG_IA32_EMULATION */
 
 
@@ -92,25 +164,23 @@ struct pt_regs;
  * of the x86-64-style parameter ordering of x32 syscalls. The syscalls common
  * with x86_64 obviously do not need such care.
  */
-#define __X32_COMPAT_SYS_STUB0(x, name, ...)                           \
-       asmlinkage long __x32_compat_sys_##name(const struct pt_regs *regs);\
-       ALLOW_ERROR_INJECTION(__x32_compat_sys_##name, ERRNO);          \
-       asmlinkage long __x32_compat_sys_##name(const struct pt_regs *regs)\
-       {                                                               \
-               return __se_compat_sys_##name();\
-       }
+#define __X32_COMPAT_SYS_STUB0(name)                                   \
+       __SYS_STUB0(x32, compat_sys_##name)
 
 #define __X32_COMPAT_SYS_STUBx(x, name, ...)                           \
-       asmlinkage long __x32_compat_sys##name(const struct pt_regs *regs);\
-       ALLOW_ERROR_INJECTION(__x32_compat_sys##name, ERRNO);           \
-       asmlinkage long __x32_compat_sys##name(const struct pt_regs *regs)\
-       {                                                               \
-               return __se_compat_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\
-       }
+       __SYS_STUBx(x32, compat_sys##name,                              \
+                   SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
+
+#define __X32_COMPAT_COND_SYSCALL(name)                                        \
+       __COND_SYSCALL(x32, compat_sys_##name)
 
+#define __X32_COMPAT_SYS_NI(name)                                      \
+       __SYS_NI(x32, compat_sys_##name)
 #else /* CONFIG_X86_X32 */
-#define __X32_COMPAT_SYS_STUB0(x, name)
+#define __X32_COMPAT_SYS_STUB0(name)
 #define __X32_COMPAT_SYS_STUBx(x, name, ...)
+#define __X32_COMPAT_COND_SYSCALL(name)
+#define __X32_COMPAT_SYS_NI(name)
 #endif /* CONFIG_X86_X32 */
 
 
@@ -121,15 +191,12 @@ struct pt_regs;
  * of them.
  */
 #define COMPAT_SYSCALL_DEFINE0(name)                                   \
-       static long __se_compat_sys_##name(void);                       \
-       static inline long __do_compat_sys_##name(void);                \
-       __IA32_COMPAT_SYS_STUB0(x, name)                                \
-       __X32_COMPAT_SYS_STUB0(x, name)                                 \
-       static long __se_compat_sys_##name(void)                        \
-       {                                                               \
-               return __do_compat_sys_##name();                        \
-       }                                                               \
-       static inline long __do_compat_sys_##name(void)
+       static long                                                     \
+       __do_compat_sys_##name(const struct pt_regs *__unused);         \
+       __IA32_COMPAT_SYS_STUB0(name)                                   \
+       __X32_COMPAT_SYS_STUB0(name)                                    \
+       static long                                                     \
+       __do_compat_sys_##name(const struct pt_regs *__unused)
 
 #define COMPAT_SYSCALL_DEFINEx(x, name, ...)                                   \
        static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));      \
@@ -148,58 +215,19 @@ struct pt_regs;
  * kernel/time/posix-stubs.c to cover this case as well.
  */
 #define COND_SYSCALL_COMPAT(name)                                      \
-       cond_syscall(__ia32_compat_sys_##name);                         \
-       cond_syscall(__x32_compat_sys_##name)
+       __IA32_COMPAT_COND_SYSCALL(name)                                \
+       __X32_COMPAT_COND_SYSCALL(name)
 
 #define COMPAT_SYS_NI(name)                                            \
-       SYSCALL_ALIAS(__ia32_compat_sys_##name, sys_ni_posix_timers);   \
-       SYSCALL_ALIAS(__x32_compat_sys_##name, sys_ni_posix_timers)
+       __IA32_COMPAT_SYS_NI(name)                                      \
+       __X32_COMPAT_SYS_NI(name)
 
 #endif /* CONFIG_COMPAT */
 
-
-/*
- * Instead of the generic __SYSCALL_DEFINEx() definition, this macro takes
- * struct pt_regs *regs as the only argument of the syscall stub named
- * __x64_sys_*(). It decodes just the registers it needs and passes them on to
- * the __se_sys_*() wrapper performing sign extension and then to the
- * __do_sys_*() function doing the actual job. These wrappers and functions
- * are inlined (at least in very most cases), meaning that the assembly looks
- * as follows (slightly re-ordered for better readability):
- *
- * <__x64_sys_recv>:           <-- syscall with 4 parameters
- *     callq   <__fentry__>
- *
- *     mov     0x70(%rdi),%rdi <-- decode regs->di
- *     mov     0x68(%rdi),%rsi <-- decode regs->si
- *     mov     0x60(%rdi),%rdx <-- decode regs->dx
- *     mov     0x38(%rdi),%rcx <-- decode regs->r10
- *
- *     xor     %r9d,%r9d       <-- clear %r9
- *     xor     %r8d,%r8d       <-- clear %r8
- *
- *     callq   __sys_recvfrom  <-- do the actual work in __sys_recvfrom()
- *                                 which takes 6 arguments
- *
- *     cltq                    <-- extend return value to 64-bit
- *     retq                    <-- return
- *
- * This approach avoids leaking random user-provided register content down
- * the call chain.
- *
- * If IA32_EMULATION is enabled, this macro generates an additional wrapper
- * named __ia32_sys_*() which decodes the struct pt_regs *regs according
- * to the i386 calling convention (bx, cx, dx, si, di, bp).
- */
 #define __SYSCALL_DEFINEx(x, name, ...)                                        \
-       asmlinkage long __x64_sys##name(const struct pt_regs *regs);    \
-       ALLOW_ERROR_INJECTION(__x64_sys##name, ERRNO);                  \
        static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));     \
        static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
-       asmlinkage long __x64_sys##name(const struct pt_regs *regs)     \
-       {                                                               \
-               return __se_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\
-       }                                                               \
+       __X64_SYS_STUBx(x, name, __VA_ARGS__)                           \
        __IA32_SYS_STUBx(x, name, __VA_ARGS__)                          \
        static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))      \
        {                                                               \
@@ -217,33 +245,28 @@ struct pt_regs;
  * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() and SYS_NI()
  * macros to work correctly.
  */
-#ifndef SYSCALL_DEFINE0
 #define SYSCALL_DEFINE0(sname)                                         \
        SYSCALL_METADATA(_##sname, 0);                                  \
-       asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\
-       ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO);                \
-       asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused)
-#endif
-
-#ifndef COND_SYSCALL
-#define COND_SYSCALL(name)                                                     \
-       asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused) \
-       {                                                                       \
-               return sys_ni_syscall();                                        \
-       }
-#endif
+       static long __do_sys_##sname(const struct pt_regs *__unused);   \
+       __X64_SYS_STUB0(sname)                                          \
+       __IA32_SYS_STUB0(sname)                                         \
+       static long __do_sys_##sname(const struct pt_regs *__unused)
+
+#define COND_SYSCALL(name)                                             \
+       __X64_COND_SYSCALL(name)                                        \
+       __IA32_COND_SYSCALL(name)
 
-#ifndef SYS_NI
-#define SYS_NI(name) SYSCALL_ALIAS(__x64_sys_##name, sys_ni_posix_timers);
-#endif
+#define SYS_NI(name)                                                   \
+       __X64_SYS_NI(name)                                              \
+       __IA32_SYS_NI(name)
 
 
 /*
  * For VSYSCALLS, we need to declare these three syscalls with the new
  * pt_regs-based calling convention for in-kernel use.
  */
-asmlinkage long __x64_sys_getcpu(const struct pt_regs *regs);
-asmlinkage long __x64_sys_gettimeofday(const struct pt_regs *regs);
-asmlinkage long __x64_sys_time(const struct pt_regs *regs);
+long __x64_sys_getcpu(const struct pt_regs *regs);
+long __x64_sys_gettimeofday(const struct pt_regs *regs);
+long __x64_sys_time(const struct pt_regs *regs);
 
 #endif /* _ASM_X86_SYSCALL_WRAPPER_H */
index 91b7b6e..6714a35 100644 (file)
@@ -8,42 +8,8 @@
 #ifndef _ASM_X86_SYSCALLS_H
 #define _ASM_X86_SYSCALLS_H
 
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-
 /* Common in X86_32 and X86_64 */
 /* kernel/ioport.c */
 long ksys_ioperm(unsigned long from, unsigned long num, int turn_on);
 
-#ifdef CONFIG_X86_32
-/*
- * These definitions are only valid on pure 32-bit systems; x86-64 uses a
- * different syscall calling convention
- */
-asmlinkage long sys_ioperm(unsigned long, unsigned long, int);
-asmlinkage long sys_iopl(unsigned int);
-
-/* kernel/ldt.c */
-asmlinkage long sys_modify_ldt(int, void __user *, unsigned long);
-
-/* kernel/signal.c */
-asmlinkage long sys_rt_sigreturn(void);
-
-/* kernel/tls.c */
-asmlinkage long sys_set_thread_area(struct user_desc __user *);
-asmlinkage long sys_get_thread_area(struct user_desc __user *);
-
-/* X86_32 only */
-
-/* kernel/signal.c */
-asmlinkage long sys_sigreturn(void);
-
-/* kernel/vm86_32.c */
-struct vm86_struct;
-asmlinkage long sys_vm86old(struct vm86_struct __user *);
-asmlinkage long sys_vm86(unsigned long, unsigned long);
-
-#endif /* CONFIG_X86_32 */
 #endif /* _ASM_X86_SYSCALLS_H */
index cf43279..8de8cec 100644 (file)
@@ -92,7 +92,7 @@ struct thread_info {
 #define TIF_NOCPUID            15      /* CPUID is not accessible in userland */
 #define TIF_NOTSC              16      /* TSC is not accessible in userland */
 #define TIF_IA32               17      /* IA32 compatibility process */
-#define TIF_NOHZ               19      /* in adaptive nohz mode */
+#define TIF_SLD                        18      /* Restore split lock detection on context switch */
 #define TIF_MEMDIE             20      /* is terminating due to OOM killer */
 #define TIF_POLLING_NRFLAG     21      /* idle is polling for TIF_NEED_RESCHED */
 #define TIF_IO_BITMAP          22      /* uses I/O bitmap */
@@ -122,7 +122,7 @@ struct thread_info {
 #define _TIF_NOCPUID           (1 << TIF_NOCPUID)
 #define _TIF_NOTSC             (1 << TIF_NOTSC)
 #define _TIF_IA32              (1 << TIF_IA32)
-#define _TIF_NOHZ              (1 << TIF_NOHZ)
+#define _TIF_SLD               (1 << TIF_SLD)
 #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
 #define _TIF_IO_BITMAP         (1 << TIF_IO_BITMAP)
 #define _TIF_FORCED_TF         (1 << TIF_FORCED_TF)
@@ -133,19 +133,15 @@ struct thread_info {
 #define _TIF_X32               (1 << TIF_X32)
 #define _TIF_FSCHECK           (1 << TIF_FSCHECK)
 
-/*
- * work to do in syscall_trace_enter().  Also includes TIF_NOHZ for
- * enter_from_user_mode()
- */
+/* Work to do before invoking the actual syscall. */
 #define _TIF_WORK_SYSCALL_ENTRY        \
        (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT |   \
-        _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT |       \
-        _TIF_NOHZ)
+        _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
 
 /* flags to check in __switch_to() */
 #define _TIF_WORK_CTXSW_BASE                                   \
        (_TIF_NOCPUID | _TIF_NOTSC | _TIF_BLOCKSTEP |           \
-        _TIF_SSBD | _TIF_SPEC_FORCE_UPDATE)
+        _TIF_SSBD | _TIF_SPEC_FORCE_UPDATE | _TIF_SLD)
 
 /*
  * Avoid calls to __switch_to_xtra() on UP as STIBP is not evaluated.
index 4b14d23..79d8d54 100644 (file)
@@ -193,4 +193,29 @@ static inline void sched_clear_itmt_support(void)
 }
 #endif /* CONFIG_SCHED_MC_PRIO */
 
+#ifdef CONFIG_SMP
+#include <asm/cpufeature.h>
+
+DECLARE_STATIC_KEY_FALSE(arch_scale_freq_key);
+
+#define arch_scale_freq_invariant() static_branch_likely(&arch_scale_freq_key)
+
+DECLARE_PER_CPU(unsigned long, arch_freq_scale);
+
+static inline long arch_scale_freq_capacity(int cpu)
+{
+       return per_cpu(arch_freq_scale, cpu);
+}
+#define arch_scale_freq_capacity arch_scale_freq_capacity
+
+extern void arch_scale_freq_tick(void);
+#define arch_scale_freq_tick arch_scale_freq_tick
+
+extern void arch_set_max_freq_ratio(bool turbo_disabled);
+#else
+static inline void arch_set_max_freq_ratio(bool turbo_disabled)
+{
+}
+#endif
+
 #endif /* _ASM_X86_TOPOLOGY_H */
index ffa0dc8..c26a7e1 100644 (file)
@@ -76,27 +76,24 @@ dotraplinkage void do_coprocessor_segment_overrun(struct pt_regs *regs, long err
 dotraplinkage void do_invalid_TSS(struct pt_regs *regs, long error_code);
 dotraplinkage void do_segment_not_present(struct pt_regs *regs, long error_code);
 dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code);
-#ifdef CONFIG_X86_64
-dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code, unsigned long address);
-asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs);
-asmlinkage __visible notrace
-struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s);
-void __init trap_init(void);
-#endif
 dotraplinkage void do_general_protection(struct pt_regs *regs, long error_code);
 dotraplinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address);
 dotraplinkage void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code);
 dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code);
 dotraplinkage void do_alignment_check(struct pt_regs *regs, long error_code);
-#ifdef CONFIG_X86_MCE
-dotraplinkage void do_machine_check(struct pt_regs *regs, long error_code);
-#endif
 dotraplinkage void do_simd_coprocessor_error(struct pt_regs *regs, long error_code);
 #ifdef CONFIG_X86_32
 dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code);
 #endif
 dotraplinkage void do_mce(struct pt_regs *regs, long error_code);
 
+#ifdef CONFIG_X86_64
+asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs);
+asmlinkage __visible notrace
+struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s);
+void __init trap_init(void);
+#endif
+
 static inline int get_si_code(unsigned long condition)
 {
        if (condition & DR_STEP)
index 61d93f0..ea6fc64 100644 (file)
@@ -584,99 +584,6 @@ extern __must_check long strnlen_user(const char __user *str, long n);
 unsigned long __must_check clear_user(void __user *mem, unsigned long len);
 unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
 
-extern void __cmpxchg_wrong_size(void)
-       __compiletime_error("Bad argument size for cmpxchg");
-
-#define __user_atomic_cmpxchg_inatomic(uval, ptr, old, new, size)      \
-({                                                                     \
-       int __ret = 0;                                                  \
-       __typeof__(*(ptr)) __old = (old);                               \
-       __typeof__(*(ptr)) __new = (new);                               \
-       __uaccess_begin_nospec();                                       \
-       switch (size) {                                                 \
-       case 1:                                                         \
-       {                                                               \
-               asm volatile("\n"                                       \
-                       "1:\t" LOCK_PREFIX "cmpxchgb %4, %2\n"          \
-                       "2:\n"                                          \
-                       "\t.section .fixup, \"ax\"\n"                   \
-                       "3:\tmov     %3, %0\n"                          \
-                       "\tjmp     2b\n"                                \
-                       "\t.previous\n"                                 \
-                       _ASM_EXTABLE_UA(1b, 3b)                         \
-                       : "+r" (__ret), "=a" (__old), "+m" (*(ptr))     \
-                       : "i" (-EFAULT), "q" (__new), "1" (__old)       \
-                       : "memory"                                      \
-               );                                                      \
-               break;                                                  \
-       }                                                               \
-       case 2:                                                         \
-       {                                                               \
-               asm volatile("\n"                                       \
-                       "1:\t" LOCK_PREFIX "cmpxchgw %4, %2\n"          \
-                       "2:\n"                                          \
-                       "\t.section .fixup, \"ax\"\n"                   \
-                       "3:\tmov     %3, %0\n"                          \
-                       "\tjmp     2b\n"                                \
-                       "\t.previous\n"                                 \
-                       _ASM_EXTABLE_UA(1b, 3b)                         \
-                       : "+r" (__ret), "=a" (__old), "+m" (*(ptr))     \
-                       : "i" (-EFAULT), "r" (__new), "1" (__old)       \
-                       : "memory"                                      \
-               );                                                      \
-               break;                                                  \
-       }                                                               \
-       case 4:                                                         \
-       {                                                               \
-               asm volatile("\n"                                       \
-                       "1:\t" LOCK_PREFIX "cmpxchgl %4, %2\n"          \
-                       "2:\n"                                          \
-                       "\t.section .fixup, \"ax\"\n"                   \
-                       "3:\tmov     %3, %0\n"                          \
-                       "\tjmp     2b\n"                                \
-                       "\t.previous\n"                                 \
-                       _ASM_EXTABLE_UA(1b, 3b)                         \
-                       : "+r" (__ret), "=a" (__old), "+m" (*(ptr))     \
-                       : "i" (-EFAULT), "r" (__new), "1" (__old)       \
-                       : "memory"                                      \
-               );                                                      \
-               break;                                                  \
-       }                                                               \
-       case 8:                                                         \
-       {                                                               \
-               if (!IS_ENABLED(CONFIG_X86_64))                         \
-                       __cmpxchg_wrong_size();                         \
-                                                                       \
-               asm volatile("\n"                                       \
-                       "1:\t" LOCK_PREFIX "cmpxchgq %4, %2\n"          \
-                       "2:\n"                                          \
-                       "\t.section .fixup, \"ax\"\n"                   \
-                       "3:\tmov     %3, %0\n"                          \
-                       "\tjmp     2b\n"                                \
-                       "\t.previous\n"                                 \
-                       _ASM_EXTABLE_UA(1b, 3b)                         \
-                       : "+r" (__ret), "=a" (__old), "+m" (*(ptr))     \
-                       : "i" (-EFAULT), "r" (__new), "1" (__old)       \
-                       : "memory"                                      \
-               );                                                      \
-               break;                                                  \
-       }                                                               \
-       default:                                                        \
-               __cmpxchg_wrong_size();                                 \
-       }                                                               \
-       __uaccess_end();                                                \
-       *(uval) = __old;                                                \
-       __ret;                                                          \
-})
-
-#define user_atomic_cmpxchg_inatomic(uval, ptr, old, new)              \
-({                                                                     \
-       access_ok((ptr), sizeof(*(ptr))) ?              \
-               __user_atomic_cmpxchg_inatomic((uval), (ptr),           \
-                               (old), (new), sizeof(*(ptr))) :         \
-               -EFAULT;                                                \
-})
-
 /*
  * movsl can be slow when source and dest are not both 8-byte aligned
  */
index a7dd080..c1c3d31 100644 (file)
 #  define __ARCH_WANT_SYS_OLD_MMAP
 #  define __ARCH_WANT_SYS_OLD_SELECT
 
+#  define __NR_ia32_syscall_max __NR_syscall_max
+
 # else
 
 #  include <asm/unistd_64.h>
 #  include <asm/unistd_64_x32.h>
+#  include <asm/unistd_32_ia32.h>
 #  define __ARCH_WANT_SYS_TIME
 #  define __ARCH_WANT_SYS_UTIME
 #  define __ARCH_WANT_COMPAT_SYS_PREADV64
 
 # endif
 
+# define NR_syscalls (__NR_syscall_max + 1)
+# define X32_NR_syscalls (__NR_x32_syscall_max + 1)
+# define IA32_NR_syscalls (__NR_ia32_syscall_max + 1)
+
 # define __ARCH_WANT_NEW_STAT
 # define __ARCH_WANT_OLD_READDIR
 # define __ARCH_WANT_OLD_STAT
diff --git a/arch/x86/include/asm/vdso/clocksource.h b/arch/x86/include/asm/vdso/clocksource.h
new file mode 100644 (file)
index 0000000..119ac86
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_VDSO_CLOCKSOURCE_H
+#define __ASM_VDSO_CLOCKSOURCE_H
+
+#define VDSO_ARCH_CLOCKMODES   \
+       VDSO_CLOCKMODE_TSC,     \
+       VDSO_CLOCKMODE_PVCLOCK, \
+       VDSO_CLOCKMODE_HVCLOCK
+
+#endif /* __ASM_VDSO_CLOCKSOURCE_H */
index 6ee1f7d..9a6dc9b 100644 (file)
@@ -243,7 +243,7 @@ static u64 vread_hvclock(void)
 
 static inline u64 __arch_get_hw_counter(s32 clock_mode)
 {
-       if (clock_mode == VCLOCK_TSC)
+       if (likely(clock_mode == VDSO_CLOCKMODE_TSC))
                return (u64)rdtsc_ordered();
        /*
         * For any memory-mapped vclock type, we need to make sure that gcc
@@ -252,13 +252,13 @@ static inline u64 __arch_get_hw_counter(s32 clock_mode)
         * question isn't enabled, which will segfault.  Hence the barriers.
         */
 #ifdef CONFIG_PARAVIRT_CLOCK
-       if (clock_mode == VCLOCK_PVCLOCK) {
+       if (clock_mode == VDSO_CLOCKMODE_PVCLOCK) {
                barrier();
                return vread_pvclock();
        }
 #endif
 #ifdef CONFIG_HYPERV_TIMER
-       if (clock_mode == VCLOCK_HVCLOCK) {
+       if (clock_mode == VDSO_CLOCKMODE_HVCLOCK) {
                barrier();
                return vread_hvclock();
        }
diff --git a/arch/x86/include/asm/vdso/processor.h b/arch/x86/include/asm/vdso/processor.h
new file mode 100644 (file)
index 0000000..57b1a70
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+#ifndef __ASM_VDSO_PROCESSOR_H
+#define __ASM_VDSO_PROCESSOR_H
+
+#ifndef __ASSEMBLY__
+
+/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
+static __always_inline void rep_nop(void)
+{
+       asm volatile("rep; nop" ::: "memory");
+}
+
+static __always_inline void cpu_relax(void)
+{
+       rep_nop();
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_VDSO_PROCESSOR_H */
index 0026ab2..be199a9 100644 (file)
@@ -10,8 +10,6 @@
 #include <asm/vgtod.h>
 #include <asm/vvar.h>
 
-int vclocks_used __read_mostly;
-
 DEFINE_VVAR(struct vdso_data, _vdso_data);
 /*
  * Update the vDSO data page to keep in sync with kernel timekeeping.
@@ -23,19 +21,6 @@ struct vdso_data *__x86_get_k_vdso_data(void)
 }
 #define __arch_get_k_vdso_data __x86_get_k_vdso_data
 
-static __always_inline
-int __x86_get_clock_mode(struct timekeeper *tk)
-{
-       int vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode;
-
-       /* Mark the new vclock used. */
-       BUILD_BUG_ON(VCLOCK_MAX >= 32);
-       WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << vclock_mode));
-
-       return vclock_mode;
-}
-#define __arch_get_clock_mode __x86_get_clock_mode
-
 /* The asm-generic header needs to be included after the definitions above */
 #include <asm-generic/vdso/vsyscall.h>
 
index a2638c6..7aa38b2 100644 (file)
@@ -2,6 +2,11 @@
 #ifndef _ASM_X86_VGTOD_H
 #define _ASM_X86_VGTOD_H
 
+/*
+ * This check is required to prevent ARCH=um to include
+ * unwanted headers.
+ */
+#ifdef CONFIG_GENERIC_GETTIMEOFDAY
 #include <linux/compiler.h>
 #include <asm/clocksource.h>
 #include <vdso/datapage.h>
@@ -14,11 +19,6 @@ typedef u64 gtod_long_t;
 #else
 typedef unsigned long gtod_long_t;
 #endif
-
-extern int vclocks_used;
-static inline bool vclock_was_used(int vclock)
-{
-       return READ_ONCE(vclocks_used) & (1 << vclock);
-}
+#endif /* CONFIG_GENERIC_GETTIMEOFDAY */
 
 #endif /* _ASM_X86_VGTOD_H */
index 2a85287..8521af3 100644 (file)
@@ -72,7 +72,7 @@
 #define SECONDARY_EXEC_MODE_BASED_EPT_EXEC     VMCS_CONTROL_BIT(MODE_BASED_EPT_EXEC)
 #define SECONDARY_EXEC_PT_USE_GPA              VMCS_CONTROL_BIT(PT_USE_GPA)
 #define SECONDARY_EXEC_TSC_SCALING              VMCS_CONTROL_BIT(TSC_SCALING)
-#define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE   0x04000000
+#define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE   VMCS_CONTROL_BIT(USR_WAIT_PAUSE)
 
 #define PIN_BASED_EXT_INTR_MASK                 VMCS_CONTROL_BIT(INTR_EXITING)
 #define PIN_BASED_NMI_EXITING                   VMCS_CONTROL_BIT(NMI_EXITING)
index a50e4a0..9915990 100644 (file)
@@ -81,6 +81,7 @@
 #define VMX_FEATURE_MODE_BASED_EPT_EXEC        ( 2*32+ 22) /* "ept_mode_based_exec" Enable separate EPT EXEC bits for supervisor vs. user */
 #define VMX_FEATURE_PT_USE_GPA         ( 2*32+ 24) /* "" Processor Trace logs GPAs */
 #define VMX_FEATURE_TSC_SCALING                ( 2*32+ 25) /* Scale hardware TSC when read in guest */
+#define VMX_FEATURE_USR_WAIT_PAUSE     ( 2*32+ 26) /* Enable TPAUSE, UMONITOR, UMWAIT in guest */
 #define VMX_FEATURE_ENCLV_EXITING      ( 2*32+ 28) /* "" VM-Exit on ENCLV (leaf dependent) */
 
 #endif /* _ASM_X86_VMXFEATURES_H */
index 503d3f4..3f3f780 100644 (file)
@@ -390,6 +390,7 @@ struct kvm_sync_regs {
 #define KVM_STATE_NESTED_GUEST_MODE    0x00000001
 #define KVM_STATE_NESTED_RUN_PENDING   0x00000002
 #define KVM_STATE_NESTED_EVMCS         0x00000004
+#define KVM_STATE_NESTED_MTF_PENDING   0x00000008
 
 #define KVM_STATE_NESTED_SMM_GUEST_MODE        0x00000001
 #define KVM_STATE_NESTED_SMM_VMXON     0x00000002
index 9b294c1..bb5abfe 100644 (file)
@@ -28,7 +28,6 @@ KASAN_SANITIZE_dumpstack_$(BITS).o                    := n
 KASAN_SANITIZE_stacktrace.o                            := n
 KASAN_SANITIZE_paravirt.o                              := n
 
-OBJECT_FILES_NON_STANDARD_relocate_kernel_$(BITS).o    := y
 OBJECT_FILES_NON_STANDARD_test_nx.o                    := y
 OBJECT_FILES_NON_STANDARD_paravirt_patch.o             := y
 
@@ -53,6 +52,8 @@ obj-y                 += setup.o x86_init.o i8259.o irqinit.o
 obj-$(CONFIG_JUMP_LABEL)       += jump_label.o
 obj-$(CONFIG_IRQ_WORK)  += irq_work.o
 obj-y                  += probe_roms.o
+obj-$(CONFIG_X86_32)   += sys_ia32.o
+obj-$(CONFIG_IA32_EMULATION)   += sys_ia32.o
 obj-$(CONFIG_X86_64)   += sys_x86_64.o
 obj-$(CONFIG_X86_ESPFIX64)     += espfix_64.o
 obj-$(CONFIG_SYSFS)    += ksysfs.o
index 04205ce..1ae5439 100644 (file)
@@ -45,6 +45,7 @@ EXPORT_SYMBOL(acpi_disabled);
 #define PREFIX                 "ACPI: "
 
 int acpi_noirq;                                /* skip ACPI IRQ initialization */
+int acpi_nobgrt;                       /* skip ACPI BGRT */
 int acpi_pci_disabled;         /* skip ACPI PCI scan and IRQ initialization */
 EXPORT_SYMBOL(acpi_pci_disabled);
 
@@ -1619,7 +1620,7 @@ int __init acpi_boot_init(void)
        acpi_process_madt();
 
        acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
-       if (IS_ENABLED(CONFIG_ACPI_BGRT))
+       if (IS_ENABLED(CONFIG_ACPI_BGRT) && !acpi_nobgrt)
                acpi_table_parse(ACPI_SIG_BGRT, acpi_parse_bgrt);
 
        if (!acpi_noirq)
@@ -1671,6 +1672,13 @@ static int __init parse_acpi(char *arg)
 }
 early_param("acpi", parse_acpi);
 
+static int __init parse_acpi_bgrt(char *arg)
+{
+       acpi_nobgrt = true;
+       return 0;
+}
+early_param("bgrt_disable", parse_acpi_bgrt);
+
 /* FIXME: Using pci= for an ACPI parameter is a travesty. */
 static int __init parse_pci(char *arg)
 {
@@ -1740,7 +1748,7 @@ int __acpi_acquire_global_lock(unsigned int *lock)
                new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1));
                val = cmpxchg(lock, old, new);
        } while (unlikely (val != old));
-       return (new < 3) ? -1 : 0;
+       return ((new & 0x3) < 3) ? -1 : 0;
 }
 
 int __acpi_release_global_lock(unsigned int *lock)
index 26b7256..ed3b044 100644 (file)
@@ -43,7 +43,7 @@ unsigned long acpi_get_wakeup_address(void)
  *
  * Wrapper around acpi_enter_sleep_state() to be called by assmebly.
  */
-acpi_status asmlinkage __visible x86_acpi_enter_sleep_state(u8 state)
+asmlinkage acpi_status __visible x86_acpi_enter_sleep_state(u8 state)
 {
        return acpi_enter_sleep_state(state);
 }
index d06c207..171a40c 100644 (file)
@@ -19,4 +19,4 @@ extern void do_suspend_lowlevel(void);
 
 extern int x86_acpi_suspend_lowlevel(void);
 
-acpi_status asmlinkage x86_acpi_enter_sleep_state(u8 state);
+asmlinkage acpi_status x86_acpi_enter_sleep_state(u8 state);
index 69aed0e..b6b3297 100644 (file)
@@ -36,10 +36,9 @@ static const struct pci_device_id amd_root_ids[] = {
        {}
 };
 
-
 #define PCI_DEVICE_ID_AMD_CNB17H_F4     0x1704
 
-const struct pci_device_id amd_nb_misc_ids[] = {
+static const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
@@ -56,7 +55,6 @@ const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_19H_DF_F3) },
        {}
 };
-EXPORT_SYMBOL_GPL(amd_nb_misc_ids);
 
 static const struct pci_device_id amd_nb_link_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
index 5f973fe..81b9c63 100644 (file)
@@ -546,12 +546,6 @@ static struct clock_event_device lapic_clockevent = {
 };
 static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
 
-#define DEADLINE_MODEL_MATCH_FUNC(model, func) \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&func }
-
-#define DEADLINE_MODEL_MATCH_REV(model, rev)   \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)rev }
-
 static u32 hsx_deadline_rev(void)
 {
        switch (boot_cpu_data.x86_stepping) {
@@ -588,23 +582,23 @@ static u32 skx_deadline_rev(void)
 }
 
 static const struct x86_cpu_id deadline_match[] = {
-       DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_HASWELL_X,        hsx_deadline_rev),
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_X,      0x0b000020),
-       DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_BROADWELL_D,      bdx_deadline_rev),
-       DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_SKYLAKE_X,        skx_deadline_rev),
+       X86_MATCH_INTEL_FAM6_MODEL( HASWELL_X,          &hsx_deadline_rev),
+       X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_X,        0x0b000020),
+       X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_D,        &bdx_deadline_rev),
+       X86_MATCH_INTEL_FAM6_MODEL( SKYLAKE_X,          &skx_deadline_rev),
 
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL,          0x22),
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_L,        0x20),
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_G,        0x17),
+       X86_MATCH_INTEL_FAM6_MODEL( HASWELL,            0x22),
+       X86_MATCH_INTEL_FAM6_MODEL( HASWELL_L,          0x20),
+       X86_MATCH_INTEL_FAM6_MODEL( HASWELL_G,          0x17),
 
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL,        0x25),
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_G,      0x17),
+       X86_MATCH_INTEL_FAM6_MODEL( BROADWELL,          0x25),
+       X86_MATCH_INTEL_FAM6_MODEL( BROADWELL_G,        0x17),
 
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_L,        0xb2),
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE,          0xb2),
+       X86_MATCH_INTEL_FAM6_MODEL( SKYLAKE_L,          0xb2),
+       X86_MATCH_INTEL_FAM6_MODEL( SKYLAKE,            0xb2),
 
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_L,       0x52),
-       DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE,         0x52),
+       X86_MATCH_INTEL_FAM6_MODEL( KABYLAKE_L,         0x52),
+       X86_MATCH_INTEL_FAM6_MODEL( KABYLAKE,           0x52),
 
        {},
 };
index 2c5676b..67768e5 100644 (file)
@@ -557,6 +557,12 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
                irqd->hwirq = virq + i;
                irqd_set_single_target(irqd);
                /*
+                * Prevent that any of these interrupts is invoked in
+                * non interrupt context via e.g. generic_handle_irq()
+                * as that can corrupt the affinity move state.
+                */
+               irqd_set_handle_enforce_irqctx(irqd);
+               /*
                 * Legacy vectors are already assigned when the IOAPIC
                 * takes them over. They stay on the same vector. This is
                 * required for check_timer() to work correctly as it might
@@ -838,13 +844,15 @@ static void free_moved_vector(struct apic_chip_data *apicd)
        bool managed = apicd->is_managed;
 
        /*
-        * This should never happen. Managed interrupts are not
-        * migrated except on CPU down, which does not involve the
-        * cleanup vector. But try to keep the accounting correct
-        * nevertheless.
+        * Managed interrupts are usually not migrated away
+        * from an online CPU, but CPU isolation 'managed_irq'
+        * can make that happen.
+        * 1) Activation does not take the isolation into account
+        *    to keep the code simple
+        * 2) Migration away from an isolated CPU can happen when
+        *    a non-isolated CPU which is in the calculated
+        *    affinity mask comes online.
         */
-       WARN_ON_ONCE(managed);
-
        trace_vector_free_moved(apicd->irq, cpu, vector, managed);
        irq_matrix_free(vector_matrix, cpu, vector, managed);
        per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
index 5c7ee3d..3ca07ad 100644 (file)
@@ -88,7 +88,6 @@ static void __used common(void)
        OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
        OFFSET(BP_init_size, boot_params, hdr.init_size);
        OFFSET(BP_pref_address, boot_params, hdr.pref_address);
-       OFFSET(BP_code32_start, boot_params, hdr.code32_start);
 
        BLANK();
        DEFINE(PTREGS_SIZE, sizeof(struct pt_regs));
index 82826f2..6e043f2 100644 (file)
@@ -3,12 +3,9 @@
 # error "Please do not build this file directly, build asm-offsets.c instead"
 #endif
 
-#include <asm/ucontext.h>
+#include <linux/efi.h>
 
-#define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
-static char syscalls[] = {
-#include <asm/syscalls_32.h>
-};
+#include <asm/ucontext.h>
 
 /* workaround for a warning with -Wmissing-prototypes */
 void foo(void);
@@ -62,6 +59,5 @@ void foo(void)
 #endif
 
        BLANK();
-       DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
-       DEFINE(NR_syscalls, sizeof(syscalls));
+       DEFINE(EFI_svam, offsetof(efi_runtime_services_t, set_virtual_address_map));
 }
index 24d2fde..c2a4701 100644 (file)
@@ -5,30 +5,6 @@
 
 #include <asm/ia32.h>
 
-#define __SYSCALL_64(nr, sym, qual) [nr] = 1,
-#define __SYSCALL_X32(nr, sym, qual)
-static char syscalls_64[] = {
-#include <asm/syscalls_64.h>
-};
-#undef __SYSCALL_64
-#undef __SYSCALL_X32
-
-#ifdef CONFIG_X86_X32_ABI
-#define __SYSCALL_64(nr, sym, qual)
-#define __SYSCALL_X32(nr, sym, qual) [nr] = 1,
-static char syscalls_x32[] = {
-#include <asm/syscalls_64.h>
-};
-#undef __SYSCALL_64
-#undef __SYSCALL_X32
-#endif
-
-#define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
-static char syscalls_ia32[] = {
-#include <asm/syscalls_32.h>
-};
-#undef __SYSCALL_I386
-
 #if defined(CONFIG_KVM_GUEST) && defined(CONFIG_PARAVIRT_SPINLOCKS)
 #include <asm/kvm_para.h>
 #endif
@@ -90,17 +66,5 @@ int main(void)
        DEFINE(stack_canary_offset, offsetof(struct fixed_percpu_data, stack_canary));
        BLANK();
 #endif
-
-       DEFINE(__NR_syscall_max, sizeof(syscalls_64) - 1);
-       DEFINE(NR_syscalls, sizeof(syscalls_64));
-
-#ifdef CONFIG_X86_X32_ABI
-       DEFINE(__NR_syscall_x32_max, sizeof(syscalls_x32) - 1);
-       DEFINE(X32_NR_syscalls, sizeof(syscalls_x32));
-#endif
-
-       DEFINE(__NR_syscall_compat_max, sizeof(syscalls_ia32) - 1);
-       DEFINE(IA32_NR_syscalls, sizeof(syscalls_ia32));
-
        return 0;
 }
index 1f875fb..547ad7b 100644 (file)
@@ -394,6 +394,35 @@ static void amd_detect_cmp(struct cpuinfo_x86 *c)
        per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
 }
 
+static void amd_detect_ppin(struct cpuinfo_x86 *c)
+{
+       unsigned long long val;
+
+       if (!cpu_has(c, X86_FEATURE_AMD_PPIN))
+               return;
+
+       /* When PPIN is defined in CPUID, still need to check PPIN_CTL MSR */
+       if (rdmsrl_safe(MSR_AMD_PPIN_CTL, &val))
+               goto clear_ppin;
+
+       /* PPIN is locked in disabled mode, clear feature bit */
+       if ((val & 3UL) == 1UL)
+               goto clear_ppin;
+
+       /* If PPIN is disabled, try to enable it */
+       if (!(val & 2UL)) {
+               wrmsrl_safe(MSR_AMD_PPIN_CTL,  val | 2UL);
+               rdmsrl_safe(MSR_AMD_PPIN_CTL, &val);
+       }
+
+       /* If PPIN_EN bit is 1, return from here; otherwise fall through */
+       if (val & 2UL)
+               return;
+
+clear_ppin:
+       clear_cpu_cap(c, X86_FEATURE_AMD_PPIN);
+}
+
 u16 amd_get_nb_id(int cpu)
 {
        return per_cpu(cpu_llc_id, cpu);
@@ -926,7 +955,8 @@ static void init_amd(struct cpuinfo_x86 *c)
        case 0x12: init_amd_ln(c); break;
        case 0x15: init_amd_bd(c); break;
        case 0x16: init_amd_jg(c); break;
-       case 0x17: init_amd_zn(c); break;
+       case 0x17: fallthrough;
+       case 0x19: init_amd_zn(c); break;
        }
 
        /*
@@ -941,6 +971,7 @@ static void init_amd(struct cpuinfo_x86 *c)
        amd_detect_cmp(c);
        amd_get_topology(c);
        srat_detect_node(c);
+       amd_detect_ppin(c);
 
        init_amd_cacheinfo(c);
 
index 52c9bfb..bed0cb8 100644 (file)
@@ -445,7 +445,7 @@ static __always_inline void setup_pku(struct cpuinfo_x86 *c)
         * cpuid bit to be set.  We need to ensure that we
         * update that bit in this CPU's "cpu_info".
         */
-       get_cpu_cap(c);
+       set_cpu_cap(c, X86_FEATURE_OSPKE);
 }
 
 #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
@@ -1008,8 +1008,8 @@ static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
 #define NO_ITLB_MULTIHIT       BIT(7)
 #define NO_SPECTRE_V2          BIT(8)
 
-#define VULNWL(_vendor, _family, _model, _whitelist)   \
-       { X86_VENDOR_##_vendor, _family, _model, X86_FEATURE_ANY, _whitelist }
+#define VULNWL(vendor, family, model, whitelist)       \
+       X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, whitelist)
 
 #define VULNWL_INTEL(model, whitelist)         \
        VULNWL(INTEL, 6, INTEL_FAM6_##model, whitelist)
@@ -1224,6 +1224,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
 
        cpu_set_bug_bits(c);
 
+       cpu_set_core_cap_bits(c);
+
        fpu__init_system(c);
 
 #ifdef CONFIG_X86_32
index be82cd5..9a26e97 100644 (file)
@@ -19,6 +19,8 @@
 #include <asm/microcode_intel.h>
 #include <asm/hwcap2.h>
 #include <asm/elf.h>
+#include <asm/cpu_device_id.h>
+#include <asm/cmdline.h>
 
 #ifdef CONFIG_X86_64
 #include <linux/topology.h>
 #include <asm/apic.h>
 #endif
 
+enum split_lock_detect_state {
+       sld_off = 0,
+       sld_warn,
+       sld_fatal,
+};
+
+/*
+ * Default to sld_off because most systems do not support split lock detection
+ * split_lock_setup() will switch this to sld_warn on systems that support
+ * split lock detect, unless there is a command line override.
+ */
+static enum split_lock_detect_state sld_state __ro_after_init = sld_off;
+static u64 msr_test_ctrl_cache __ro_after_init;
+
 /*
  * Processors which have self-snooping capability can handle conflicting
  * memory type across CPUs by snooping its own cache. However, there exists
@@ -570,6 +586,8 @@ static void init_intel_misc_features(struct cpuinfo_x86 *c)
        wrmsrl(MSR_MISC_FEATURES_ENABLES, msr);
 }
 
+static void split_lock_init(void);
+
 static void init_intel(struct cpuinfo_x86 *c)
 {
        early_init_intel(c);
@@ -684,6 +702,8 @@ static void init_intel(struct cpuinfo_x86 *c)
                tsx_enable();
        if (tsx_ctrl_state == TSX_CTRL_DISABLE)
                tsx_disable();
+
+       split_lock_init();
 }
 
 #ifdef CONFIG_X86_32
@@ -945,3 +965,166 @@ static const struct cpu_dev intel_cpu_dev = {
 };
 
 cpu_dev_register(intel_cpu_dev);
+
+#undef pr_fmt
+#define pr_fmt(fmt) "x86/split lock detection: " fmt
+
+static const struct {
+       const char                      *option;
+       enum split_lock_detect_state    state;
+} sld_options[] __initconst = {
+       { "off",        sld_off   },
+       { "warn",       sld_warn  },
+       { "fatal",      sld_fatal },
+};
+
+static inline bool match_option(const char *arg, int arglen, const char *opt)
+{
+       int len = strlen(opt);
+
+       return len == arglen && !strncmp(arg, opt, len);
+}
+
+static bool split_lock_verify_msr(bool on)
+{
+       u64 ctrl, tmp;
+
+       if (rdmsrl_safe(MSR_TEST_CTRL, &ctrl))
+               return false;
+       if (on)
+               ctrl |= MSR_TEST_CTRL_SPLIT_LOCK_DETECT;
+       else
+               ctrl &= ~MSR_TEST_CTRL_SPLIT_LOCK_DETECT;
+       if (wrmsrl_safe(MSR_TEST_CTRL, ctrl))
+               return false;
+       rdmsrl(MSR_TEST_CTRL, tmp);
+       return ctrl == tmp;
+}
+
+static void __init split_lock_setup(void)
+{
+       enum split_lock_detect_state state = sld_warn;
+       char arg[20];
+       int i, ret;
+
+       if (!split_lock_verify_msr(false)) {
+               pr_info("MSR access failed: Disabled\n");
+               return;
+       }
+
+       ret = cmdline_find_option(boot_command_line, "split_lock_detect",
+                                 arg, sizeof(arg));
+       if (ret >= 0) {
+               for (i = 0; i < ARRAY_SIZE(sld_options); i++) {
+                       if (match_option(arg, ret, sld_options[i].option)) {
+                               state = sld_options[i].state;
+                               break;
+                       }
+               }
+       }
+
+       switch (state) {
+       case sld_off:
+               pr_info("disabled\n");
+               return;
+       case sld_warn:
+               pr_info("warning about user-space split_locks\n");
+               break;
+       case sld_fatal:
+               pr_info("sending SIGBUS on user-space split_locks\n");
+               break;
+       }
+
+       rdmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache);
+
+       if (!split_lock_verify_msr(true)) {
+               pr_info("MSR access failed: Disabled\n");
+               return;
+       }
+
+       sld_state = state;
+       setup_force_cpu_cap(X86_FEATURE_SPLIT_LOCK_DETECT);
+}
+
+/*
+ * MSR_TEST_CTRL is per core, but we treat it like a per CPU MSR. Locking
+ * is not implemented as one thread could undo the setting of the other
+ * thread immediately after dropping the lock anyway.
+ */
+static void sld_update_msr(bool on)
+{
+       u64 test_ctrl_val = msr_test_ctrl_cache;
+
+       if (on)
+               test_ctrl_val |= MSR_TEST_CTRL_SPLIT_LOCK_DETECT;
+
+       wrmsrl(MSR_TEST_CTRL, test_ctrl_val);
+}
+
+static void split_lock_init(void)
+{
+       split_lock_verify_msr(sld_state != sld_off);
+}
+
+bool handle_user_split_lock(struct pt_regs *regs, long error_code)
+{
+       if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal)
+               return false;
+
+       pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n",
+                           current->comm, current->pid, regs->ip);
+
+       /*
+        * Disable the split lock detection for this task so it can make
+        * progress and set TIF_SLD so the detection is re-enabled via
+        * switch_to_sld() when the task is scheduled out.
+        */
+       sld_update_msr(false);
+       set_tsk_thread_flag(current, TIF_SLD);
+       return true;
+}
+
+/*
+ * This function is called only when switching between tasks with
+ * different split-lock detection modes. It sets the MSR for the
+ * mode of the new task. This is right most of the time, but since
+ * the MSR is shared by hyperthreads on a physical core there can
+ * be glitches when the two threads need different modes.
+ */
+void switch_to_sld(unsigned long tifn)
+{
+       sld_update_msr(!(tifn & _TIF_SLD));
+}
+
+#define SPLIT_LOCK_CPU(model) {X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY}
+
+/*
+ * The following processors have the split lock detection feature. But
+ * since they don't have the IA32_CORE_CAPABILITIES MSR, the feature cannot
+ * be enumerated. Enable it by family and model matching on these
+ * processors.
+ */
+static const struct x86_cpu_id split_lock_cpu_ids[] __initconst = {
+       SPLIT_LOCK_CPU(INTEL_FAM6_ICELAKE_X),
+       SPLIT_LOCK_CPU(INTEL_FAM6_ICELAKE_L),
+       {}
+};
+
+void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c)
+{
+       u64 ia32_core_caps = 0;
+
+       if (c->x86_vendor != X86_VENDOR_INTEL)
+               return;
+       if (cpu_has(c, X86_FEATURE_CORE_CAPABILITIES)) {
+               /* Enumerate features reported in IA32_CORE_CAPABILITIES MSR. */
+               rdmsrl(MSR_IA32_CORE_CAPS, ia32_core_caps);
+       } else if (!boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
+               /* Enumerate split lock detection by family and model. */
+               if (x86_match_cpu(split_lock_cpu_ids))
+                       ia32_core_caps |= MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT;
+       }
+
+       if (ia32_core_caps & MSR_IA32_CORE_CAPS_SPLIT_LOCK_DETECT)
+               split_lock_setup();
+}
index 6dd78d8..d3482eb 100644 (file)
  * respective wildcard entries.
  *
  * A typical table entry would be to match a specific CPU
- * { X86_VENDOR_INTEL, 6, 0x12 }
- * or to match a specific CPU feature
- * { X86_FEATURE_MATCH(X86_FEATURE_FOOBAR) }
+ *
+ * X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_BROADWELL,
+ *                                   X86_FEATURE_ANY, NULL);
  *
  * Fields can be wildcarded with %X86_VENDOR_ANY, %X86_FAMILY_ANY,
- * %X86_MODEL_ANY, %X86_FEATURE_ANY or 0 (except for vendor)
+ * %X86_MODEL_ANY, %X86_FEATURE_ANY (except for vendor)
+ *
+ * asm/cpu_device_id.h contains a set of useful macros which are shortcuts
+ * for various common selections. The above can be shortened to:
+ *
+ * X86_MATCH_INTEL_FAM6_MODEL(BROADWELL, NULL);
  *
  * Arrays used to match for this should also be declared using
  * MODULE_DEVICE_TABLE(x86cpu, ...)
index 2c4f949..54165f3 100644 (file)
@@ -142,6 +142,8 @@ void mce_setup(struct mce *m)
 
        if (this_cpu_has(X86_FEATURE_INTEL_PPIN))
                rdmsrl(MSR_PPIN, m->ppin);
+       else if (this_cpu_has(X86_FEATURE_AMD_PPIN))
+               rdmsrl(MSR_AMD_PPIN, m->ppin);
 
        m->microcode = boot_cpu_data.microcode;
 }
@@ -1213,8 +1215,14 @@ static void __mc_scan_banks(struct mce *m, struct mce *final,
  * On Intel systems this is entered on all CPUs in parallel through
  * MCE broadcast. However some CPUs might be broken beyond repair,
  * so be always careful when synchronizing with others.
+ *
+ * Tracing and kprobes are disabled: if we interrupted a kernel context
+ * with IF=1, we need to minimize stack usage.  There are also recursion
+ * issues: if the machine check was due to a failure of the memory
+ * backing the user stack, tracing that reads the user stack will cause
+ * potentially infinite recursion.
  */
-void do_machine_check(struct pt_regs *regs, long error_code)
+void notrace do_machine_check(struct pt_regs *regs, long error_code)
 {
        DECLARE_BITMAP(valid_banks, MAX_NR_BANKS);
        DECLARE_BITMAP(toclear, MAX_NR_BANKS);
@@ -1360,6 +1368,7 @@ out_ist:
        ist_exit(regs);
 }
 EXPORT_SYMBOL_GPL(do_machine_check);
+NOKPROBE_SYMBOL(do_machine_check);
 
 #ifndef CONFIG_MEMORY_FAILURE
 int memory_failure(unsigned long pfn, int flags)
@@ -1877,6 +1886,8 @@ bool filter_mce(struct mce *m)
 {
        if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
                return amd_filter_mce(m);
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+               return intel_filter_mce(m);
 
        return false;
 }
@@ -1892,10 +1903,11 @@ static void unexpected_machine_check(struct pt_regs *regs, long error_code)
 void (*machine_check_vector)(struct pt_regs *, long error_code) =
                                                unexpected_machine_check;
 
-dotraplinkage void do_mce(struct pt_regs *regs, long error_code)
+dotraplinkage notrace void do_mce(struct pt_regs *regs, long error_code)
 {
        machine_check_vector(regs, error_code);
 }
+NOKPROBE_SYMBOL(do_mce);
 
 /*
  * Called for each booted CPU to set up machine checks.
index 7c8958d..d089567 100644 (file)
@@ -29,11 +29,7 @@ static char *mce_helper_argv[2] = { mce_helper, NULL };
  * separate MCEs from kernel messages to avoid bogus bug reports.
  */
 
-static struct mce_log_buffer mcelog = {
-       .signature      = MCE_LOG_SIGNATURE,
-       .len            = MCE_LOG_LEN,
-       .recordlen      = sizeof(struct mce),
-};
+static struct mce_log_buffer *mcelog;
 
 static DECLARE_WAIT_QUEUE_HEAD(mce_chrdev_wait);
 
@@ -45,21 +41,21 @@ static int dev_mce_log(struct notifier_block *nb, unsigned long val,
 
        mutex_lock(&mce_chrdev_read_mutex);
 
-       entry = mcelog.next;
+       entry = mcelog->next;
 
        /*
         * When the buffer fills up discard new entries. Assume that the
         * earlier errors are the more interesting ones:
         */
-       if (entry >= MCE_LOG_LEN) {
-               set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog.flags);
+       if (entry >= mcelog->len) {
+               set_bit(MCE_OVERFLOW, (unsigned long *)&mcelog->flags);
                goto unlock;
        }
 
-       mcelog.next = entry + 1;
+       mcelog->next = entry + 1;
 
-       memcpy(mcelog.entry + entry, mce, sizeof(struct mce));
-       mcelog.entry[entry].finished = 1;
+       memcpy(mcelog->entry + entry, mce, sizeof(struct mce));
+       mcelog->entry[entry].finished = 1;
 
        /* wake processes polling /dev/mcelog */
        wake_up_interruptible(&mce_chrdev_wait);
@@ -214,21 +210,21 @@ static ssize_t mce_chrdev_read(struct file *filp, char __user *ubuf,
 
        /* Only supports full reads right now */
        err = -EINVAL;
-       if (*off != 0 || usize < MCE_LOG_LEN*sizeof(struct mce))
+       if (*off != 0 || usize < mcelog->len * sizeof(struct mce))
                goto out;
 
-       next = mcelog.next;
+       next = mcelog->next;
        err = 0;
 
        for (i = 0; i < next; i++) {
-               struct mce *m = &mcelog.entry[i];
+               struct mce *m = &mcelog->entry[i];
 
                err |= copy_to_user(buf, m, sizeof(*m));
                buf += sizeof(*m);
        }
 
-       memset(mcelog.entry, 0, next * sizeof(struct mce));
-       mcelog.next = 0;
+       memset(mcelog->entry, 0, next * sizeof(struct mce));
+       mcelog->next = 0;
 
        if (err)
                err = -EFAULT;
@@ -242,7 +238,7 @@ out:
 static __poll_t mce_chrdev_poll(struct file *file, poll_table *wait)
 {
        poll_wait(file, &mce_chrdev_wait, wait);
-       if (READ_ONCE(mcelog.next))
+       if (READ_ONCE(mcelog->next))
                return EPOLLIN | EPOLLRDNORM;
        if (!mce_apei_read_done && apei_check_mce())
                return EPOLLIN | EPOLLRDNORM;
@@ -261,13 +257,13 @@ static long mce_chrdev_ioctl(struct file *f, unsigned int cmd,
        case MCE_GET_RECORD_LEN:
                return put_user(sizeof(struct mce), p);
        case MCE_GET_LOG_LEN:
-               return put_user(MCE_LOG_LEN, p);
+               return put_user(mcelog->len, p);
        case MCE_GETCLEAR_FLAGS: {
                unsigned flags;
 
                do {
-                       flags = mcelog.flags;
-               } while (cmpxchg(&mcelog.flags, flags, 0) != flags);
+                       flags = mcelog->flags;
+               } while (cmpxchg(&mcelog->flags, flags, 0) != flags);
 
                return put_user(flags, p);
        }
@@ -339,8 +335,18 @@ static struct miscdevice mce_chrdev_device = {
 
 static __init int dev_mcelog_init_device(void)
 {
+       int mce_log_len;
        int err;
 
+       mce_log_len = max(MCE_LOG_MIN_LEN, num_online_cpus());
+       mcelog = kzalloc(sizeof(*mcelog) + mce_log_len * sizeof(struct mce), GFP_KERNEL);
+       if (!mcelog)
+               return -ENOMEM;
+
+       strncpy(mcelog->signature, MCE_LOG_SIGNATURE, sizeof(mcelog->signature));
+       mcelog->len = mce_log_len;
+       mcelog->recordlen = sizeof(struct mce);
+
        /* register character device /dev/mcelog */
        err = misc_register(&mce_chrdev_device);
        if (err) {
@@ -350,6 +356,7 @@ static __init int dev_mcelog_init_device(void)
                else
                        pr_err("Unable to init device /dev/mcelog (rc: %d)\n", err);
 
+               kfree(mcelog);
                return err;
        }
 
index 5627b10..d8f9230 100644 (file)
@@ -493,17 +493,18 @@ static void intel_ppin_init(struct cpuinfo_x86 *c)
                        return;
 
                if ((val & 3UL) == 1UL) {
-                       /* PPIN available but disabled: */
+                       /* PPIN locked in disabled mode */
                        return;
                }
 
-               /* If PPIN is disabled, but not locked, try to enable: */
-               if (!(val & 3UL)) {
+               /* If PPIN is disabled, try to enable */
+               if (!(val & 2UL)) {
                        wrmsrl_safe(MSR_PPIN_CTL,  val | 2UL);
                        rdmsrl_safe(MSR_PPIN_CTL, &val);
                }
 
-               if ((val & 3UL) == 2UL)
+               /* Is the enable bit set? */
+               if (val & 2UL)
                        set_cpu_cap(c, X86_FEATURE_INTEL_PPIN);
        }
 }
@@ -520,3 +521,20 @@ void mce_intel_feature_clear(struct cpuinfo_x86 *c)
 {
        intel_clear_lmce();
 }
+
+bool intel_filter_mce(struct mce *m)
+{
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+
+       /* MCE errata HSD131, HSM142, HSW131, BDM48, and HSM142 */
+       if ((c->x86 == 6) &&
+           ((c->x86_model == INTEL_FAM6_HASWELL) ||
+            (c->x86_model == INTEL_FAM6_HASWELL_L) ||
+            (c->x86_model == INTEL_FAM6_BROADWELL) ||
+            (c->x86_model == INTEL_FAM6_HASWELL_G)) &&
+           (m->bank == 0) &&
+           ((m->status & 0xa0000000ffffffff) == 0x80000000000f0005))
+               return true;
+
+       return false;
+}
index b785c0d..3b00817 100644 (file)
@@ -8,6 +8,9 @@
 #include <linux/device.h>
 #include <asm/mce.h>
 
+/* Pointer to the installed machine check handler for this CPU setup. */
+extern void (*machine_check_vector)(struct pt_regs *, long error_code);
+
 enum severity_level {
        MCE_NO_SEVERITY,
        MCE_DEFERRED_SEVERITY,
@@ -48,6 +51,7 @@ void cmci_disable_bank(int bank);
 void intel_init_cmci(void);
 void intel_init_lmce(void);
 void intel_clear_lmce(void);
+bool intel_filter_mce(struct mce *m);
 #else
 # define cmci_intel_adjust_timer mce_adjust_timer_default
 static inline bool mce_intel_cmci_poll(void) { return false; }
@@ -56,6 +60,7 @@ static inline void cmci_disable_bank(int bank) { }
 static inline void intel_init_cmci(void) { }
 static inline void intel_init_lmce(void) { }
 static inline void intel_clear_lmce(void) { }
+static inline bool intel_filter_mce(struct mce *m) { return false; };
 #endif
 
 void mce_timer_kick(unsigned long interval);
index 58b4ee3..f36dc07 100644 (file)
@@ -486,9 +486,14 @@ static int thermal_throttle_offline(unsigned int cpu)
 {
        struct thermal_state *state = &per_cpu(thermal_state, cpu);
        struct device *dev = get_cpu_device(cpu);
+       u32 l;
+
+       /* Mask the thermal vector before draining evtl. pending work */
+       l = apic_read(APIC_LVTTHMR);
+       apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
 
-       cancel_delayed_work(&state->package_throttle.therm_work);
-       cancel_delayed_work(&state->core_throttle.therm_work);
+       cancel_delayed_work_sync(&state->package_throttle.therm_work);
+       cancel_delayed_work_sync(&state->core_throttle.therm_work);
 
        state->package_throttle.rate_control_active = false;
        state->core_throttle.rate_control_active = false;
index 3923ab4..f66a6b9 100644 (file)
@@ -67,11 +67,6 @@ __HEAD
 SYM_CODE_START(startup_32)
        movl pa(initial_stack),%ecx
        
-       /* test KEEP_SEGMENTS flag to see if the bootloader is asking
-               us to not reload segments */
-       testb $KEEP_SEGMENTS, BP_loadflags(%esi)
-       jnz 2f
-
 /*
  * Set segments to known values.
  */
@@ -82,7 +77,6 @@ SYM_CODE_START(startup_32)
        movl %eax,%fs
        movl %eax,%gs
        movl %eax,%ss
-2:
        leal -__PAGE_OFFSET(%ecx),%esp
 
 /*
index 2305490..7dfb1e8 100644 (file)
@@ -17,7 +17,7 @@ static enum efi_secureboot_mode get_sb_mode(void)
 
        size = sizeof(secboot);
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
                pr_info("ima: secureboot mode unknown, no efi\n");
                return efi_secureboot_mode_unknown;
        }
index 21efee3..c7965ff 100644 (file)
@@ -230,7 +230,7 @@ u64 arch_irq_stat(void)
  * SMP cross-CPU interrupts have their own specific
  * handlers).
  */
-__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
+__visible void __irq_entry do_IRQ(struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
        struct irq_desc * desc;
@@ -263,7 +263,6 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
        exiting_irq();
 
        set_irq_regs(old_regs);
-       return 1;
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
index f293d87..db6578d 100644 (file)
@@ -141,9 +141,8 @@ prepare_add_efi_setup_data(struct boot_params *params,
        struct setup_data *sd = (void *)params + efi_setup_data_offset;
        struct efi_setup_data *esd = (void *)sd + sizeof(struct setup_data);
 
-       esd->fw_vendor = efi.fw_vendor;
-       esd->runtime = efi.runtime;
-       esd->tables = efi.config_table;
+       esd->fw_vendor = efi_fw_vendor;
+       esd->tables = efi_config_table;
        esd->smbios = efi.smbios;
 
        sd->type = SETUP_EFI;
index 3f45b5c..ea13f68 100644 (file)
@@ -71,6 +71,21 @@ found:
        return (unsigned long)buf;
 }
 
+static void synthesize_clac(kprobe_opcode_t *addr)
+{
+       /*
+        * Can't be static_cpu_has() due to how objtool treats this feature bit.
+        * This isn't a fast path anyway.
+        */
+       if (!boot_cpu_has(X86_FEATURE_SMAP))
+               return;
+
+       /* Replace the NOP3 with CLAC */
+       addr[0] = 0x0f;
+       addr[1] = 0x01;
+       addr[2] = 0xca;
+}
+
 /* Insert a move instruction which sets a pointer to eax/rdi (1st arg). */
 static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val)
 {
@@ -92,6 +107,9 @@ asm (
                        /* We don't bother saving the ss register */
                        "       pushq %rsp\n"
                        "       pushfq\n"
+                       ".global optprobe_template_clac\n"
+                       "optprobe_template_clac:\n"
+                       ASM_NOP3
                        SAVE_REGS_STRING
                        "       movq %rsp, %rsi\n"
                        ".global optprobe_template_val\n"
@@ -111,6 +129,9 @@ asm (
 #else /* CONFIG_X86_32 */
                        "       pushl %esp\n"
                        "       pushfl\n"
+                       ".global optprobe_template_clac\n"
+                       "optprobe_template_clac:\n"
+                       ASM_NOP3
                        SAVE_REGS_STRING
                        "       movl %esp, %edx\n"
                        ".global optprobe_template_val\n"
@@ -134,6 +155,8 @@ asm (
 void optprobe_template_func(void);
 STACK_FRAME_NON_STANDARD(optprobe_template_func);
 
+#define TMPL_CLAC_IDX \
+       ((long)optprobe_template_clac - (long)optprobe_template_entry)
 #define TMPL_MOVE_IDX \
        ((long)optprobe_template_val - (long)optprobe_template_entry)
 #define TMPL_CALL_IDX \
@@ -389,6 +412,8 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
        op->optinsn.size = ret;
        len = TMPL_END_IDX + op->optinsn.size;
 
+       synthesize_clac(buf + TMPL_CLAC_IDX);
+
        /* Set probe information */
        synthesize_set_arg1(buf + TMPL_MOVE_IDX, (unsigned long)op);
 
index d817f25..6efe041 100644 (file)
@@ -425,7 +425,29 @@ static void __init sev_map_percpu_data(void)
        }
 }
 
+static bool pv_tlb_flush_supported(void)
+{
+       return (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
+               !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
+               kvm_para_has_feature(KVM_FEATURE_STEAL_TIME));
+}
+
+static DEFINE_PER_CPU(cpumask_var_t, __pv_cpu_mask);
+
 #ifdef CONFIG_SMP
+
+static bool pv_ipi_supported(void)
+{
+       return kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI);
+}
+
+static bool pv_sched_yield_supported(void)
+{
+       return (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
+               !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
+           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME));
+}
+
 #define KVM_IPI_CLUSTER_SIZE   (2 * BITS_PER_LONG)
 
 static void __send_ipi_mask(const struct cpumask *mask, int vector)
@@ -490,12 +512,12 @@ static void kvm_send_ipi_mask(const struct cpumask *mask, int vector)
 static void kvm_send_ipi_mask_allbutself(const struct cpumask *mask, int vector)
 {
        unsigned int this_cpu = smp_processor_id();
-       struct cpumask new_mask;
+       struct cpumask *new_mask = this_cpu_cpumask_var_ptr(__pv_cpu_mask);
        const struct cpumask *local_mask;
 
-       cpumask_copy(&new_mask, mask);
-       cpumask_clear_cpu(this_cpu, &new_mask);
-       local_mask = &new_mask;
+       cpumask_copy(new_mask, mask);
+       cpumask_clear_cpu(this_cpu, new_mask);
+       local_mask = new_mask;
        __send_ipi_mask(local_mask, vector);
 }
 
@@ -575,7 +597,6 @@ static void __init kvm_apf_trap_init(void)
        update_intr_gate(X86_TRAP_PF, async_page_fault);
 }
 
-static DEFINE_PER_CPU(cpumask_var_t, __pv_tlb_mask);
 
 static void kvm_flush_tlb_others(const struct cpumask *cpumask,
                        const struct flush_tlb_info *info)
@@ -583,7 +604,7 @@ static void kvm_flush_tlb_others(const struct cpumask *cpumask,
        u8 state;
        int cpu;
        struct kvm_steal_time *src;
-       struct cpumask *flushmask = this_cpu_cpumask_var_ptr(__pv_tlb_mask);
+       struct cpumask *flushmask = this_cpu_cpumask_var_ptr(__pv_cpu_mask);
 
        cpumask_copy(flushmask, cpumask);
        /*
@@ -619,11 +640,10 @@ static void __init kvm_guest_init(void)
                pv_ops.time.steal_clock = kvm_steal_clock;
        }
 
-       if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
-           !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
-           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
+       if (pv_tlb_flush_supported()) {
                pv_ops.mmu.flush_tlb_others = kvm_flush_tlb_others;
                pv_ops.mmu.tlb_remove_table = tlb_remove_table;
+               pr_info("KVM setup pv remote TLB flush\n");
        }
 
        if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
@@ -632,9 +652,7 @@ 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)) {
+       if (pv_sched_yield_supported()) {
                smp_ops.send_call_func_ipi = kvm_smp_send_call_func_ipi;
                pr_info("KVM setup pv sched yield\n");
        }
@@ -700,7 +718,7 @@ static uint32_t __init kvm_detect(void)
 static void __init kvm_apic_init(void)
 {
 #if defined(CONFIG_SMP)
-       if (kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI))
+       if (pv_ipi_supported())
                kvm_setup_pv_ipi();
 #endif
 }
@@ -732,26 +750,31 @@ static __init int activate_jump_labels(void)
 }
 arch_initcall(activate_jump_labels);
 
-static __init int kvm_setup_pv_tlb_flush(void)
+static __init int kvm_alloc_cpumask(void)
 {
        int cpu;
+       bool alloc = false;
 
        if (!kvm_para_available() || nopv)
                return 0;
 
-       if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
-           !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
-           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
+       if (pv_tlb_flush_supported())
+               alloc = true;
+
+#if defined(CONFIG_SMP)
+       if (pv_ipi_supported())
+               alloc = true;
+#endif
+
+       if (alloc)
                for_each_possible_cpu(cpu) {
-                       zalloc_cpumask_var_node(per_cpu_ptr(&__pv_tlb_mask, cpu),
+                       zalloc_cpumask_var_node(per_cpu_ptr(&__pv_cpu_mask, cpu),
                                GFP_KERNEL, cpu_to_node(cpu));
                }
-               pr_info("KVM setup pv remote TLB flush\n");
-       }
 
        return 0;
 }
-arch_initcall(kvm_setup_pv_tlb_flush);
+arch_initcall(kvm_alloc_cpumask);
 
 #ifdef CONFIG_PARAVIRT_SPINLOCKS
 
index 904494b..34b18f6 100644 (file)
@@ -159,12 +159,19 @@ bool kvm_check_and_clear_guest_paused(void)
        return ret;
 }
 
+static int kvm_cs_enable(struct clocksource *cs)
+{
+       vclocks_set_used(VDSO_CLOCKMODE_PVCLOCK);
+       return 0;
+}
+
 struct clocksource kvm_clock = {
        .name   = "kvm-clock",
        .read   = kvm_clock_get_cycles,
        .rating = 400,
        .mask   = CLOCKSOURCE_MASK(64),
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .enable = kvm_cs_enable,
 };
 EXPORT_SYMBOL_GPL(kvm_clock);
 
@@ -272,7 +279,7 @@ static int __init kvm_setup_vsyscall_timeinfo(void)
        if (!(flags & PVCLOCK_TSC_STABLE_BIT))
                return 0;
 
-       kvm_clock.archdata.vclock_mode = VCLOCK_PVCLOCK;
+       kvm_clock.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK;
 #endif
 
        kvmclock_init_mem();
index c57e1ca..84c3ba3 100644 (file)
@@ -27,7 +27,6 @@
 #include <asm/tlb.h>
 #include <asm/desc.h>
 #include <asm/mmu_context.h>
-#include <asm/syscalls.h>
 #include <asm/pgtable_areas.h>
 
 /* This is a multiple of PAGE_SIZE. */
index 789f5e4..c131ba4 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/timer.h>
 #include <asm/special_insns.h>
 #include <asm/tlb.h>
+#include <asm/io_bitmap.h>
 
 /*
  * nop stub, which must not clobber anything *including the stack* to
@@ -341,6 +342,10 @@ struct paravirt_patch_template pv_ops = {
        .cpu.iret               = native_iret,
        .cpu.swapgs             = native_swapgs,
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+       .cpu.update_io_bitmap   = native_tss_update_io_bitmap,
+#endif
+
        .cpu.start_context_switch       = paravirt_nop,
        .cpu.end_context_switch         = paravirt_nop,
 
index 839b524..9da70b2 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/hw_breakpoint.h>
 #include <asm/cpu.h>
 #include <asm/apic.h>
-#include <asm/syscalls.h>
 #include <linux/uaccess.h>
 #include <asm/mwait.h>
 #include <asm/fpu/internal.h>
@@ -374,7 +373,7 @@ static void tss_copy_io_bitmap(struct tss_struct *tss, struct io_bitmap *iobm)
 /**
  * tss_update_io_bitmap - Update I/O bitmap before exiting to usermode
  */
-void tss_update_io_bitmap(void)
+void native_tss_update_io_bitmap(void)
 {
        struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw);
        struct thread_struct *t = &current->thread;
@@ -650,6 +649,9 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p)
                /* Enforce MSR update to ensure consistent state */
                __speculation_ctrl_update(~tifn, tifn);
        }
+
+       if ((tifp ^ tifn) & _TIF_SLD)
+               switch_to_sld(tifn);
 }
 
 /*
index 5052ced..954b013 100644 (file)
@@ -49,7 +49,6 @@
 
 #include <asm/tlbflush.h>
 #include <asm/cpu.h>
-#include <asm/syscalls.h>
 #include <asm/debugreg.h>
 #include <asm/switch_to.h>
 #include <asm/vm86.h>
index ffd4978..5ef9d8f 100644 (file)
@@ -48,7 +48,6 @@
 #include <asm/desc.h>
 #include <asm/proto.h>
 #include <asm/ia32.h>
-#include <asm/syscalls.h>
 #include <asm/debugreg.h>
 #include <asm/switch_to.h>
 #include <asm/xen/hypervisor.h>
index 1012535..11065dc 100644 (file)
@@ -145,7 +145,7 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
 
 void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti)
 {
-       WARN_ON(vclock_was_used(VCLOCK_PVCLOCK));
+       WARN_ON(vclock_was_used(VDSO_CLOCKMODE_PVCLOCK));
        pvti_cpu0_va = pvti;
 }
 
index ef3ba99..a4d9a26 100644 (file)
@@ -9,6 +9,8 @@
 #include <asm/kexec.h>
 #include <asm/processor-flags.h>
 #include <asm/pgtable_types.h>
+#include <asm/nospec-branch.h>
+#include <asm/unwind_hints.h>
 
 /*
  * Must be relocatable PIC code callable as a C function
@@ -39,6 +41,7 @@
        .align PAGE_SIZE
        .code64
 SYM_CODE_START_NOALIGN(relocate_kernel)
+       UNWIND_HINT_EMPTY
        /*
         * %rdi indirection_page
         * %rsi page_list
@@ -105,6 +108,7 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
 SYM_CODE_END(relocate_kernel)
 
 SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
+       UNWIND_HINT_EMPTY
        /* set return address to 0 if not preserving context */
        pushq   $0
        /* store the start address on the stack */
@@ -192,14 +196,12 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
 1:
        popq    %rdx
        leaq    PAGE_SIZE(%r10), %rsp
+       ANNOTATE_RETPOLINE_SAFE
        call    *%rdx
 
        /* get the re-entry point of the peer system */
        movq    0(%rsp), %rbp
-       call    1f
-1:
-       popq    %r8
-       subq    $(1b - relocate_kernel), %r8
+       leaq    relocate_kernel(%rip), %r8
        movq    CP_PA_SWAP_PAGE(%r8), %r10
        movq    CP_PA_BACKUP_PAGES_MAP(%r8), %rdi
        movq    CP_PA_TABLE_PAGE(%r8), %rax
@@ -212,6 +214,7 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
 SYM_CODE_END(identity_mapped)
 
 SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
+       UNWIND_HINT_EMPTY
        movq    RSP(%r8), %rsp
        movq    CR4(%r8), %rax
        movq    %rax, %cr4
@@ -233,6 +236,7 @@ SYM_CODE_END(virtual_mapped)
 
        /* Do the copies */
 SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
+       UNWIND_HINT_EMPTY
        movq    %rdi, %rcx      /* Put the page_list in %rcx */
        xorl    %edi, %edi
        xorl    %esi, %esi
index a74262c..e6b5450 100644 (file)
@@ -64,7 +64,6 @@ RESERVE_BRK(dmi_alloc, 65536);
  * at link time, with RESERVE_BRK*() facility reserving additional
  * chunks.
  */
-static __initdata
 unsigned long _brk_start = (unsigned long)__brk_base;
 unsigned long _brk_end   = (unsigned long)__brk_base;
 
index 8a29573..0364f8c 100644 (file)
@@ -42,8 +42,6 @@
 #endif /* CONFIG_X86_64 */
 
 #include <asm/syscall.h>
-#include <asm/syscalls.h>
-
 #include <asm/sigframe.h>
 #include <asm/signal.h>
 
@@ -859,7 +857,7 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
 }
 
 #ifdef CONFIG_X86_X32_ABI
-asmlinkage long sys32_x32_rt_sigreturn(void)
+COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn)
 {
        struct pt_regs *regs = current_pt_regs();
        struct rt_sigframe_x32 __user *frame;
index 69881b2..d59525d 100644 (file)
@@ -147,6 +147,8 @@ static inline void smpboot_restore_warm_reset_vector(void)
        *((volatile u32 *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0;
 }
 
+static void init_freq_invariance(void);
+
 /*
  * Report back to the Boot Processor during boot time or to the caller processor
  * during CPU online.
@@ -183,6 +185,8 @@ static void smp_callin(void)
         */
        set_cpu_sibling_map(raw_smp_processor_id());
 
+       init_freq_invariance();
+
        /*
         * Get our bogomips.
         * Update loops_per_jiffy in cpu_data. Previous call to
@@ -466,7 +470,7 @@ static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
  */
 
 static const struct x86_cpu_id snc_cpu[] = {
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_X },
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL),
        {}
 };
 
@@ -1337,7 +1341,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
        set_sched_topology(x86_topology);
 
        set_cpu_sibling_map(0);
-
+       init_freq_invariance();
        smp_sanity_check();
 
        switch (apic_intr_mode) {
@@ -1764,3 +1768,287 @@ void native_play_dead(void)
 }
 
 #endif
+
+/*
+ * APERF/MPERF frequency ratio computation.
+ *
+ * The scheduler wants to do frequency invariant accounting and needs a <1
+ * ratio to account for the 'current' frequency, corresponding to
+ * freq_curr / freq_max.
+ *
+ * Since the frequency freq_curr on x86 is controlled by micro-controller and
+ * our P-state setting is little more than a request/hint, we need to observe
+ * the effective frequency 'BusyMHz', i.e. the average frequency over a time
+ * interval after discarding idle time. This is given by:
+ *
+ *   BusyMHz = delta_APERF / delta_MPERF * freq_base
+ *
+ * where freq_base is the max non-turbo P-state.
+ *
+ * The freq_max term has to be set to a somewhat arbitrary value, because we
+ * can't know which turbo states will be available at a given point in time:
+ * it all depends on the thermal headroom of the entire package. We set it to
+ * the turbo level with 4 cores active.
+ *
+ * Benchmarks show that's a good compromise between the 1C turbo ratio
+ * (freq_curr/freq_max would rarely reach 1) and something close to freq_base,
+ * which would ignore the entire turbo range (a conspicuous part, making
+ * freq_curr/freq_max always maxed out).
+ *
+ * An exception to the heuristic above is the Atom uarch, where we choose the
+ * highest turbo level for freq_max since Atom's are generally oriented towards
+ * power efficiency.
+ *
+ * Setting freq_max to anything less than the 1C turbo ratio makes the ratio
+ * freq_curr / freq_max to eventually grow >1, in which case we clip it to 1.
+ */
+
+DEFINE_STATIC_KEY_FALSE(arch_scale_freq_key);
+
+static DEFINE_PER_CPU(u64, arch_prev_aperf);
+static DEFINE_PER_CPU(u64, arch_prev_mperf);
+static u64 arch_turbo_freq_ratio = SCHED_CAPACITY_SCALE;
+static u64 arch_max_freq_ratio = SCHED_CAPACITY_SCALE;
+
+void arch_set_max_freq_ratio(bool turbo_disabled)
+{
+       arch_max_freq_ratio = turbo_disabled ? SCHED_CAPACITY_SCALE :
+                                       arch_turbo_freq_ratio;
+}
+
+static bool turbo_disabled(void)
+{
+       u64 misc_en;
+       int err;
+
+       err = rdmsrl_safe(MSR_IA32_MISC_ENABLE, &misc_en);
+       if (err)
+               return false;
+
+       return (misc_en & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
+}
+
+static bool slv_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq)
+{
+       int err;
+
+       err = rdmsrl_safe(MSR_ATOM_CORE_RATIOS, base_freq);
+       if (err)
+               return false;
+
+       err = rdmsrl_safe(MSR_ATOM_CORE_TURBO_RATIOS, turbo_freq);
+       if (err)
+               return false;
+
+       *base_freq = (*base_freq >> 16) & 0x3F;     /* max P state */
+       *turbo_freq = *turbo_freq & 0x3F;           /* 1C turbo    */
+
+       return true;
+}
+
+#include <asm/cpu_device_id.h>
+#include <asm/intel-family.h>
+
+#define ICPU(model) \
+       {X86_VENDOR_INTEL, 6, model, X86_FEATURE_APERFMPERF, 0}
+
+static const struct x86_cpu_id has_knl_turbo_ratio_limits[] = {
+       ICPU(INTEL_FAM6_XEON_PHI_KNL),
+       ICPU(INTEL_FAM6_XEON_PHI_KNM),
+       {}
+};
+
+static const struct x86_cpu_id has_skx_turbo_ratio_limits[] = {
+       ICPU(INTEL_FAM6_SKYLAKE_X),
+       {}
+};
+
+static const struct x86_cpu_id has_glm_turbo_ratio_limits[] = {
+       ICPU(INTEL_FAM6_ATOM_GOLDMONT),
+       ICPU(INTEL_FAM6_ATOM_GOLDMONT_D),
+       ICPU(INTEL_FAM6_ATOM_GOLDMONT_PLUS),
+       {}
+};
+
+static bool knl_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq,
+                               int num_delta_fratio)
+{
+       int fratio, delta_fratio, found;
+       int err, i;
+       u64 msr;
+
+       if (!x86_match_cpu(has_knl_turbo_ratio_limits))
+               return false;
+
+       err = rdmsrl_safe(MSR_PLATFORM_INFO, base_freq);
+       if (err)
+               return false;
+
+       *base_freq = (*base_freq >> 8) & 0xFF;      /* max P state */
+
+       err = rdmsrl_safe(MSR_TURBO_RATIO_LIMIT, &msr);
+       if (err)
+               return false;
+
+       fratio = (msr >> 8) & 0xFF;
+       i = 16;
+       found = 0;
+       do {
+               if (found >= num_delta_fratio) {
+                       *turbo_freq = fratio;
+                       return true;
+               }
+
+               delta_fratio = (msr >> (i + 5)) & 0x7;
+
+               if (delta_fratio) {
+                       found += 1;
+                       fratio -= delta_fratio;
+               }
+
+               i += 8;
+       } while (i < 64);
+
+       return true;
+}
+
+static bool skx_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq, int size)
+{
+       u64 ratios, counts;
+       u32 group_size;
+       int err, i;
+
+       err = rdmsrl_safe(MSR_PLATFORM_INFO, base_freq);
+       if (err)
+               return false;
+
+       *base_freq = (*base_freq >> 8) & 0xFF;      /* max P state */
+
+       err = rdmsrl_safe(MSR_TURBO_RATIO_LIMIT, &ratios);
+       if (err)
+               return false;
+
+       err = rdmsrl_safe(MSR_TURBO_RATIO_LIMIT1, &counts);
+       if (err)
+               return false;
+
+       for (i = 0; i < 64; i += 8) {
+               group_size = (counts >> i) & 0xFF;
+               if (group_size >= size) {
+                       *turbo_freq = (ratios >> i) & 0xFF;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool core_set_max_freq_ratio(u64 *base_freq, u64 *turbo_freq)
+{
+       int err;
+
+       err = rdmsrl_safe(MSR_PLATFORM_INFO, base_freq);
+       if (err)
+               return false;
+
+       err = rdmsrl_safe(MSR_TURBO_RATIO_LIMIT, turbo_freq);
+       if (err)
+               return false;
+
+       *base_freq = (*base_freq >> 8) & 0xFF;      /* max P state */
+       *turbo_freq = (*turbo_freq >> 24) & 0xFF;   /* 4C turbo    */
+
+       return true;
+}
+
+static bool intel_set_max_freq_ratio(void)
+{
+       u64 base_freq, turbo_freq;
+
+       if (slv_set_max_freq_ratio(&base_freq, &turbo_freq))
+               goto out;
+
+       if (x86_match_cpu(has_glm_turbo_ratio_limits) &&
+           skx_set_max_freq_ratio(&base_freq, &turbo_freq, 1))
+               goto out;
+
+       if (knl_set_max_freq_ratio(&base_freq, &turbo_freq, 1))
+               goto out;
+
+       if (x86_match_cpu(has_skx_turbo_ratio_limits) &&
+           skx_set_max_freq_ratio(&base_freq, &turbo_freq, 4))
+               goto out;
+
+       if (core_set_max_freq_ratio(&base_freq, &turbo_freq))
+               goto out;
+
+       return false;
+
+out:
+       arch_turbo_freq_ratio = div_u64(turbo_freq * SCHED_CAPACITY_SCALE,
+                                       base_freq);
+       arch_set_max_freq_ratio(turbo_disabled());
+       return true;
+}
+
+static void init_counter_refs(void *arg)
+{
+       u64 aperf, mperf;
+
+       rdmsrl(MSR_IA32_APERF, aperf);
+       rdmsrl(MSR_IA32_MPERF, mperf);
+
+       this_cpu_write(arch_prev_aperf, aperf);
+       this_cpu_write(arch_prev_mperf, mperf);
+}
+
+static void init_freq_invariance(void)
+{
+       bool ret = false;
+
+       if (smp_processor_id() != 0 || !boot_cpu_has(X86_FEATURE_APERFMPERF))
+               return;
+
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
+               ret = intel_set_max_freq_ratio();
+
+       if (ret) {
+               on_each_cpu(init_counter_refs, NULL, 1);
+               static_branch_enable(&arch_scale_freq_key);
+       } else {
+               pr_debug("Couldn't determine max cpu frequency, necessary for scale-invariant accounting.\n");
+       }
+}
+
+DEFINE_PER_CPU(unsigned long, arch_freq_scale) = SCHED_CAPACITY_SCALE;
+
+void arch_scale_freq_tick(void)
+{
+       u64 freq_scale;
+       u64 aperf, mperf;
+       u64 acnt, mcnt;
+
+       if (!arch_scale_freq_invariant())
+               return;
+
+       rdmsrl(MSR_IA32_APERF, aperf);
+       rdmsrl(MSR_IA32_MPERF, mperf);
+
+       acnt = aperf - this_cpu_read(arch_prev_aperf);
+       mcnt = mperf - this_cpu_read(arch_prev_mperf);
+       if (!mcnt)
+               return;
+
+       this_cpu_write(arch_prev_aperf, aperf);
+       this_cpu_write(arch_prev_mperf, mperf);
+
+       acnt <<= 2*SCHED_CAPACITY_SHIFT;
+       mcnt *= arch_max_freq_ratio;
+
+       freq_scale = div64_u64(acnt, mcnt);
+
+       if (freq_scale > SCHED_CAPACITY_SCALE)
+               freq_scale = SCHED_CAPACITY_SCALE;
+
+       this_cpu_write(arch_freq_scale, freq_scale);
+}
similarity index 78%
rename from arch/x86/ia32/sys_ia32.c
rename to arch/x86/kernel/sys_ia32.c
index 2179030..ab03fed 100644 (file)
 
 #define AA(__x)                ((unsigned long)(__x))
 
-
-COMPAT_SYSCALL_DEFINE3(x86_truncate64, const char __user *, filename,
-                      unsigned long, offset_low, unsigned long, offset_high)
+SYSCALL_DEFINE3(ia32_truncate64, const char __user *, filename,
+               unsigned long, offset_low, unsigned long, offset_high)
 {
        return ksys_truncate(filename,
                            ((loff_t) offset_high << 32) | offset_low);
 }
 
-COMPAT_SYSCALL_DEFINE3(x86_ftruncate64, unsigned int, fd,
-                      unsigned long, offset_low, unsigned long, offset_high)
+SYSCALL_DEFINE3(ia32_ftruncate64, unsigned int, fd,
+               unsigned long, offset_low, unsigned long, offset_high)
 {
        return ksys_ftruncate(fd, ((loff_t) offset_high << 32) | offset_low);
 }
 
+/* warning: next two assume little endian */
+SYSCALL_DEFINE5(ia32_pread64, unsigned int, fd, char __user *, ubuf,
+               u32, count, u32, poslo, u32, poshi)
+{
+       return ksys_pread64(fd, ubuf, count,
+                           ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+SYSCALL_DEFINE5(ia32_pwrite64, unsigned int, fd, const char __user *, ubuf,
+               u32, count, u32, poslo, u32, poshi)
+{
+       return ksys_pwrite64(fd, ubuf, count,
+                            ((loff_t)AA(poshi) << 32) | AA(poslo));
+}
+
+
+/*
+ * Some system calls that need sign extended arguments. This could be
+ * done by a generic wrapper.
+ */
+SYSCALL_DEFINE6(ia32_fadvise64_64, int, fd, __u32, offset_low,
+               __u32, offset_high, __u32, len_low, __u32, len_high,
+               int, advice)
+{
+       return ksys_fadvise64_64(fd,
+                                (((u64)offset_high)<<32) | offset_low,
+                                (((u64)len_high)<<32) | len_low,
+                                advice);
+}
+
+SYSCALL_DEFINE4(ia32_readahead, int, fd, unsigned int, off_lo,
+               unsigned int, off_hi, size_t, count)
+{
+       return ksys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
+}
+
+SYSCALL_DEFINE6(ia32_sync_file_range, int, fd, unsigned int, off_low,
+               unsigned int, off_hi, unsigned int, n_low,
+               unsigned int, n_hi, int, flags)
+{
+       return ksys_sync_file_range(fd,
+                                   ((u64)off_hi << 32) | off_low,
+                                   ((u64)n_hi << 32) | n_low, flags);
+}
+
+SYSCALL_DEFINE5(ia32_fadvise64, int, fd, unsigned int, offset_lo,
+               unsigned int, offset_hi, size_t, len, int, advice)
+{
+       return ksys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
+                                len, advice);
+}
+
+SYSCALL_DEFINE6(ia32_fallocate, int, fd, int, mode,
+               unsigned int, offset_lo, unsigned int, offset_hi,
+               unsigned int, len_lo, unsigned int, len_hi)
+{
+       return ksys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
+                             ((u64)len_hi << 32) | len_lo);
+}
+
+#ifdef CONFIG_IA32_EMULATION
 /*
  * Another set for IA32/LFS -- x86_64 struct stat is different due to
  * support for 64bit inode numbers.
@@ -97,7 +157,7 @@ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
        return 0;
 }
 
-COMPAT_SYSCALL_DEFINE2(x86_stat64, const char __user *, filename,
+COMPAT_SYSCALL_DEFINE2(ia32_stat64, const char __user *, filename,
                       struct stat64 __user *, statbuf)
 {
        struct kstat stat;
@@ -108,7 +168,7 @@ COMPAT_SYSCALL_DEFINE2(x86_stat64, const char __user *, filename,
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE2(x86_lstat64, const char __user *, filename,
+COMPAT_SYSCALL_DEFINE2(ia32_lstat64, const char __user *, filename,
                       struct stat64 __user *, statbuf)
 {
        struct kstat stat;
@@ -118,7 +178,7 @@ COMPAT_SYSCALL_DEFINE2(x86_lstat64, const char __user *, filename,
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE2(x86_fstat64, unsigned int, fd,
+COMPAT_SYSCALL_DEFINE2(ia32_fstat64, unsigned int, fd,
                       struct stat64 __user *, statbuf)
 {
        struct kstat stat;
@@ -128,7 +188,7 @@ COMPAT_SYSCALL_DEFINE2(x86_fstat64, unsigned int, fd,
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE4(x86_fstatat, unsigned int, dfd,
+COMPAT_SYSCALL_DEFINE4(ia32_fstatat64, unsigned int, dfd,
                       const char __user *, filename,
                       struct stat64 __user *, statbuf, int, flag)
 {
@@ -156,7 +216,7 @@ struct mmap_arg_struct32 {
        unsigned int offset;
 };
 
-COMPAT_SYSCALL_DEFINE1(x86_mmap, struct mmap_arg_struct32 __user *, arg)
+COMPAT_SYSCALL_DEFINE1(ia32_mmap, struct mmap_arg_struct32 __user *, arg)
 {
        struct mmap_arg_struct32 a;
 
@@ -170,70 +230,10 @@ COMPAT_SYSCALL_DEFINE1(x86_mmap, struct mmap_arg_struct32 __user *, arg)
                               a.offset>>PAGE_SHIFT);
 }
 
-/* warning: next two assume little endian */
-COMPAT_SYSCALL_DEFINE5(x86_pread, unsigned int, fd, char __user *, ubuf,
-                      u32, count, u32, poslo, u32, poshi)
-{
-       return ksys_pread64(fd, ubuf, count,
-                           ((loff_t)AA(poshi) << 32) | AA(poslo));
-}
-
-COMPAT_SYSCALL_DEFINE5(x86_pwrite, unsigned int, fd, const char __user *, ubuf,
-                      u32, count, u32, poslo, u32, poshi)
-{
-       return ksys_pwrite64(fd, ubuf, count,
-                            ((loff_t)AA(poshi) << 32) | AA(poslo));
-}
-
-
-/*
- * Some system calls that need sign extended arguments. This could be
- * done by a generic wrapper.
- */
-COMPAT_SYSCALL_DEFINE6(x86_fadvise64_64, int, fd, __u32, offset_low,
-                      __u32, offset_high, __u32, len_low, __u32, len_high,
-                      int, advice)
-{
-       return ksys_fadvise64_64(fd,
-                                (((u64)offset_high)<<32) | offset_low,
-                                (((u64)len_high)<<32) | len_low,
-                                advice);
-}
-
-COMPAT_SYSCALL_DEFINE4(x86_readahead, int, fd, unsigned int, off_lo,
-                      unsigned int, off_hi, size_t, count)
-{
-       return ksys_readahead(fd, ((u64)off_hi << 32) | off_lo, count);
-}
-
-COMPAT_SYSCALL_DEFINE6(x86_sync_file_range, int, fd, unsigned int, off_low,
-                      unsigned int, off_hi, unsigned int, n_low,
-                      unsigned int, n_hi, int, flags)
-{
-       return ksys_sync_file_range(fd,
-                                   ((u64)off_hi << 32) | off_low,
-                                   ((u64)n_hi << 32) | n_low, flags);
-}
-
-COMPAT_SYSCALL_DEFINE5(x86_fadvise64, int, fd, unsigned int, offset_lo,
-                      unsigned int, offset_hi, size_t, len, int, advice)
-{
-       return ksys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
-                                len, advice);
-}
-
-COMPAT_SYSCALL_DEFINE6(x86_fallocate, int, fd, int, mode,
-                      unsigned int, offset_lo, unsigned int, offset_hi,
-                      unsigned int, len_lo, unsigned int, len_hi)
-{
-       return ksys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
-                             ((u64)len_hi << 32) | len_lo);
-}
-
 /*
  * The 32-bit clone ABI is CONFIG_CLONE_BACKWARDS
  */
-COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
+COMPAT_SYSCALL_DEFINE5(ia32_clone, unsigned long, clone_flags,
                       unsigned long, newsp, int __user *, parent_tidptr,
                       unsigned long, tls_val, int __user *, child_tidptr)
 {
@@ -252,3 +252,4 @@ COMPAT_SYSCALL_DEFINE5(x86_clone, unsigned long, clone_flags,
 
        return _do_fork(&args);
 }
+#endif /* CONFIG_IA32_EMULATION */
index ca3c11a..504fa54 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <asm/elf.h>
 #include <asm/ia32.h>
-#include <asm/syscalls.h>
 
 /*
  * Align a virtual address to avoid aliasing in the I$ on AMD F15h.
index d8673d8..4d545db 100644 (file)
@@ -122,18 +122,12 @@ void __init time_init(void)
  */
 void clocksource_arch_init(struct clocksource *cs)
 {
-       if (cs->archdata.vclock_mode == VCLOCK_NONE)
+       if (cs->vdso_clock_mode == VDSO_CLOCKMODE_NONE)
                return;
 
-       if (cs->archdata.vclock_mode > VCLOCK_MAX) {
-               pr_warn("clocksource %s registered with invalid vclock_mode %d. Disabling vclock.\n",
-                       cs->name, cs->archdata.vclock_mode);
-               cs->archdata.vclock_mode = VCLOCK_NONE;
-       }
-
        if (cs->mask != CLOCKSOURCE_MASK(64)) {
-               pr_warn("clocksource %s registered with invalid mask %016llx. Disabling vclock.\n",
+               pr_warn("clocksource %s registered with invalid mask %016llx for VDSO. Disabling VDSO support.\n",
                        cs->name, cs->mask);
-               cs->archdata.vclock_mode = VCLOCK_NONE;
+               cs->vdso_clock_mode = VDSO_CLOCKMODE_NONE;
        }
 }
index be5bc2e..b8810eb 100644 (file)
@@ -59,39 +59,29 @@ __setup("cpu0_hotplug", enable_cpu0_hotplug);
  */
 int _debug_hotplug_cpu(int cpu, int action)
 {
-       struct device *dev = get_cpu_device(cpu);
        int ret;
 
        if (!cpu_is_hotpluggable(cpu))
                return -EINVAL;
 
-       lock_device_hotplug();
-
        switch (action) {
        case 0:
-               ret = cpu_down(cpu);
-               if (!ret) {
+               ret = remove_cpu(cpu);
+               if (!ret)
                        pr_info("DEBUG_HOTPLUG_CPU0: CPU %u is now offline\n", cpu);
-                       dev->offline = true;
-                       kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
-               } else
+               else
                        pr_debug("Can't offline CPU%d.\n", cpu);
                break;
        case 1:
-               ret = cpu_up(cpu);
-               if (!ret) {
-                       dev->offline = false;
-                       kobject_uevent(&dev->kobj, KOBJ_ONLINE);
-               } else {
+               ret = add_cpu(cpu);
+               if (ret)
                        pr_debug("Can't online CPU%d.\n", cpu);
-               }
+
                break;
        default:
                ret = -EINVAL;
        }
 
-       unlock_device_hotplug();
-
        return ret;
 }
 
index 6ef00eb..d54cffd 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/traps.h>
 #include <asm/desc.h>
 #include <asm/fpu/internal.h>
+#include <asm/cpu.h>
 #include <asm/cpu_entry_area.h>
 #include <asm/mce.h>
 #include <asm/fixmap.h>
@@ -242,7 +243,6 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
 {
        struct task_struct *tsk = current;
 
-
        if (!do_trap_no_signal(tsk, trapnr, str, regs, error_code))
                return;
 
@@ -288,9 +288,29 @@ DO_ERROR(X86_TRAP_OLD_MF, SIGFPE,           0, NULL, "coprocessor segment overru
 DO_ERROR(X86_TRAP_TS,     SIGSEGV,          0, NULL, "invalid TSS",         invalid_TSS)
 DO_ERROR(X86_TRAP_NP,     SIGBUS,           0, NULL, "segment not present", segment_not_present)
 DO_ERROR(X86_TRAP_SS,     SIGBUS,           0, NULL, "stack segment",       stack_segment)
-DO_ERROR(X86_TRAP_AC,     SIGBUS,  BUS_ADRALN, NULL, "alignment check",     alignment_check)
 #undef IP
 
+dotraplinkage void do_alignment_check(struct pt_regs *regs, long error_code)
+{
+       char *str = "alignment check";
+
+       RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
+
+       if (notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_AC, SIGBUS) == NOTIFY_STOP)
+               return;
+
+       if (!user_mode(regs))
+               die("Split lock detected\n", regs, error_code);
+
+       local_irq_enable();
+
+       if (handle_user_split_lock(regs, error_code))
+               return;
+
+       do_trap(X86_TRAP_AC, SIGBUS, "alignment check", regs,
+               error_code, BUS_ADRALN, NULL);
+}
+
 #ifdef CONFIG_VMAP_STACK
 __visible void __noreturn handle_stack_overflow(const char *message,
                                                struct pt_regs *regs,
@@ -572,14 +592,20 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
                return;
 
        /*
-        * Use ist_enter despite the fact that we don't use an IST stack.
-        * We can be called from a kprobe in non-CONTEXT_KERNEL kernel
-        * mode or even during context tracking state changes.
+        * Unlike any other non-IST entry, we can be called from a kprobe in
+        * non-CONTEXT_KERNEL kernel mode or even during context tracking
+        * state changes.  Make sure that we wake up RCU even if we're coming
+        * from kernel code.
         *
-        * This means that we can't schedule.  That's okay.
+        * This means that we can't schedule even if we came from a
+        * preemptible kernel context.  That's okay.
         */
-       ist_enter(regs);
+       if (!user_mode(regs)) {
+               rcu_nmi_enter();
+               preempt_disable();
+       }
        RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU");
+
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
        if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
                                SIGTRAP) == NOTIFY_STOP)
@@ -600,7 +626,10 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code)
        cond_local_irq_disable(regs);
 
 exit:
-       ist_exit(regs);
+       if (!user_mode(regs)) {
+               preempt_enable_no_resched();
+               rcu_nmi_exit();
+       }
 }
 NOKPROBE_SYMBOL(do_int3);
 
@@ -862,7 +891,25 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
 dotraplinkage void
 do_spurious_interrupt_bug(struct pt_regs *regs, long error_code)
 {
-       cond_local_irq_enable(regs);
+       /*
+        * This addresses a Pentium Pro Erratum:
+        *
+        * PROBLEM: If the APIC subsystem is configured in mixed mode with
+        * Virtual Wire mode implemented through the local APIC, an
+        * interrupt vector of 0Fh (Intel reserved encoding) may be
+        * generated by the local APIC (Int 15).  This vector may be
+        * generated upon receipt of a spurious interrupt (an interrupt
+        * which is removed before the system receives the INTA sequence)
+        * instead of the programmed 8259 spurious interrupt vector.
+        *
+        * IMPLICATION: The spurious interrupt vector programmed in the
+        * 8259 is normally handled by an operating system's spurious
+        * interrupt handler. However, a vector of 0Fh is unknown to some
+        * operating systems, which would crash if this erratum occurred.
+        *
+        * In theory this could be limited to 32bit, but the handler is not
+        * hurting and who knows which other CPUs suffer from this.
+        */
 }
 
 dotraplinkage void
index 7e322e2..971d6f0 100644 (file)
@@ -1108,17 +1108,24 @@ static void tsc_cs_tick_stable(struct clocksource *cs)
                sched_clock_tick_stable();
 }
 
+static int tsc_cs_enable(struct clocksource *cs)
+{
+       vclocks_set_used(VDSO_CLOCKMODE_TSC);
+       return 0;
+}
+
 /*
  * .mask MUST be CLOCKSOURCE_MASK(64). See comment above read_tsc()
  */
 static struct clocksource clocksource_tsc_early = {
-       .name                   = "tsc-early",
-       .rating                 = 299,
-       .read                   = read_tsc,
-       .mask                   = CLOCKSOURCE_MASK(64),
-       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
+       .name                   = "tsc-early",
+       .rating                 = 299,
+       .read                   = read_tsc,
+       .mask                   = CLOCKSOURCE_MASK(64),
+       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
                                  CLOCK_SOURCE_MUST_VERIFY,
-       .archdata               = { .vclock_mode = VCLOCK_TSC },
+       .vdso_clock_mode        = VDSO_CLOCKMODE_TSC,
+       .enable                 = tsc_cs_enable,
        .resume                 = tsc_resume,
        .mark_unstable          = tsc_cs_mark_unstable,
        .tick_stable            = tsc_cs_tick_stable,
@@ -1131,14 +1138,15 @@ static struct clocksource clocksource_tsc_early = {
  * been found good.
  */
 static struct clocksource clocksource_tsc = {
-       .name                   = "tsc",
-       .rating                 = 300,
-       .read                   = read_tsc,
-       .mask                   = CLOCKSOURCE_MASK(64),
-       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
+       .name                   = "tsc",
+       .rating                 = 300,
+       .read                   = read_tsc,
+       .mask                   = CLOCKSOURCE_MASK(64),
+       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS |
                                  CLOCK_SOURCE_VALID_FOR_HRES |
                                  CLOCK_SOURCE_MUST_VERIFY,
-       .archdata               = { .vclock_mode = VCLOCK_TSC },
+       .vdso_clock_mode        = VDSO_CLOCKMODE_TSC,
+       .enable                 = tsc_cs_enable,
        .resume                 = tsc_resume,
        .mark_unstable          = tsc_cs_mark_unstable,
        .tick_stable            = tsc_cs_tick_stable,
index e0cbe4f..4fec6f3 100644 (file)
 #include <asm/param.h>
 #include <asm/tsc.h>
 
-#define MAX_NUM_FREQS  9
+#define MAX_NUM_FREQS  16 /* 4 bits to select the frequency */
+
+/*
+ * The frequency numbers in the SDM are e.g. 83.3 MHz, which does not contain a
+ * lot of accuracy which leads to clock drift. As far as we know Bay Trail SoCs
+ * use a 25 MHz crystal and Cherry Trail uses a 19.2 MHz crystal, the crystal
+ * is the source clk for a root PLL which outputs 1600 and 100 MHz. It is
+ * unclear if the root PLL outputs are used directly by the CPU clock PLL or
+ * if there is another PLL in between.
+ * This does not matter though, we can model the chain of PLLs as a single PLL
+ * with a quotient equal to the quotients of all PLLs in the chain multiplied.
+ * So we can create a simplified model of the CPU clock setup using a reference
+ * clock of 100 MHz plus a quotient which gets us as close to the frequency
+ * from the SDM as possible.
+ * For the 83.3 MHz example from above this would give us 100 MHz * 5 / 6 =
+ * 83 and 1/3 MHz, which matches exactly what has been measured on actual hw.
+ */
+#define TSC_REFERENCE_KHZ 100000
+
+struct muldiv {
+       u32 multiplier;
+       u32 divider;
+};
 
 /*
  * If MSR_PERF_STAT[31] is set, the maximum resolved bus ratio can be
  * read in MSR_PLATFORM_ID[12:8], otherwise in MSR_PERF_STAT[44:40].
  * Unfortunately some Intel Atom SoCs aren't quite compliant to this,
  * so we need manually differentiate SoC families. This is what the
- * field msr_plat does.
+ * field use_msr_plat does.
  */
 struct freq_desc {
-       u8 msr_plat;    /* 1: use MSR_PLATFORM_INFO, 0: MSR_IA32_PERF_STATUS */
+       bool use_msr_plat;
+       struct muldiv muldiv[MAX_NUM_FREQS];
+       /*
+        * Some CPU frequencies in the SDM do not map to known PLL freqs, in
+        * that case the muldiv array is empty and the freqs array is used.
+        */
        u32 freqs[MAX_NUM_FREQS];
+       u32 mask;
 };
 
 /*
@@ -35,41 +63,91 @@ struct freq_desc {
  * by MSR based on SDM.
  */
 static const struct freq_desc freq_desc_pnw = {
-       0, { 0, 0, 0, 0, 0, 99840, 0, 83200 }
+       .use_msr_plat = false,
+       .freqs = { 0, 0, 0, 0, 0, 99840, 0, 83200 },
+       .mask = 0x07,
 };
 
 static const struct freq_desc freq_desc_clv = {
-       0, { 0, 133200, 0, 0, 0, 99840, 0, 83200 }
+       .use_msr_plat = false,
+       .freqs = { 0, 133200, 0, 0, 0, 99840, 0, 83200 },
+       .mask = 0x07,
 };
 
+/*
+ * Bay Trail SDM MSR_FSB_FREQ frequencies simplified PLL model:
+ *  000:   100 *  5 /  6  =  83.3333 MHz
+ *  001:   100 *  1 /  1  = 100.0000 MHz
+ *  010:   100 *  4 /  3  = 133.3333 MHz
+ *  011:   100 *  7 /  6  = 116.6667 MHz
+ *  100:   100 *  4 /  5  =  80.0000 MHz
+ */
 static const struct freq_desc freq_desc_byt = {
-       1, { 83300, 100000, 133300, 116700, 80000, 0, 0, 0 }
+       .use_msr_plat = true,
+       .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 7, 6 },
+                   { 4, 5 } },
+       .mask = 0x07,
 };
 
+/*
+ * Cherry Trail SDM MSR_FSB_FREQ frequencies simplified PLL model:
+ * 0000:   100 *  5 /  6  =  83.3333 MHz
+ * 0001:   100 *  1 /  1  = 100.0000 MHz
+ * 0010:   100 *  4 /  3  = 133.3333 MHz
+ * 0011:   100 *  7 /  6  = 116.6667 MHz
+ * 0100:   100 *  4 /  5  =  80.0000 MHz
+ * 0101:   100 * 14 / 15  =  93.3333 MHz
+ * 0110:   100 *  9 / 10  =  90.0000 MHz
+ * 0111:   100 *  8 /  9  =  88.8889 MHz
+ * 1000:   100 *  7 /  8  =  87.5000 MHz
+ */
 static const struct freq_desc freq_desc_cht = {
-       1, { 83300, 100000, 133300, 116700, 80000, 93300, 90000, 88900, 87500 }
+       .use_msr_plat = true,
+       .muldiv = { { 5, 6 }, {  1,  1 }, { 4,  3 }, { 7, 6 },
+                   { 4, 5 }, { 14, 15 }, { 9, 10 }, { 8, 9 },
+                   { 7, 8 } },
+       .mask = 0x0f,
 };
 
+/*
+ * Merriefield SDM MSR_FSB_FREQ frequencies simplified PLL model:
+ * 0001:   100 *  1 /  1  = 100.0000 MHz
+ * 0010:   100 *  4 /  3  = 133.3333 MHz
+ */
 static const struct freq_desc freq_desc_tng = {
-       1, { 0, 100000, 133300, 0, 0, 0, 0, 0 }
+       .use_msr_plat = true,
+       .muldiv = { { 0, 0 }, { 1, 1 }, { 4, 3 } },
+       .mask = 0x07,
 };
 
+/*
+ * Moorefield SDM MSR_FSB_FREQ frequencies simplified PLL model:
+ * 0000:   100 *  5 /  6  =  83.3333 MHz
+ * 0001:   100 *  1 /  1  = 100.0000 MHz
+ * 0010:   100 *  4 /  3  = 133.3333 MHz
+ * 0011:   100 *  1 /  1  = 100.0000 MHz
+ */
 static const struct freq_desc freq_desc_ann = {
-       1, { 83300, 100000, 133300, 100000, 0, 0, 0, 0 }
+       .use_msr_plat = true,
+       .muldiv = { { 5, 6 }, { 1, 1 }, { 4, 3 }, { 1, 1 } },
+       .mask = 0x0f,
 };
 
+/* 24 MHz crystal? : 24 * 13 / 4 = 78 MHz */
 static const struct freq_desc freq_desc_lgm = {
-       1, { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 }
+       .use_msr_plat = true,
+       .freqs = { 78000, 78000, 78000, 78000, 78000, 78000, 78000, 78000 },
+       .mask = 0x0f,
 };
 
 static const struct x86_cpu_id tsc_msr_cpu_ids[] = {
-       INTEL_CPU_FAM6(ATOM_SALTWELL_MID,       freq_desc_pnw),
-       INTEL_CPU_FAM6(ATOM_SALTWELL_TABLET,    freq_desc_clv),
-       INTEL_CPU_FAM6(ATOM_SILVERMONT,         freq_desc_byt),
-       INTEL_CPU_FAM6(ATOM_SILVERMONT_MID,     freq_desc_tng),
-       INTEL_CPU_FAM6(ATOM_AIRMONT,            freq_desc_cht),
-       INTEL_CPU_FAM6(ATOM_AIRMONT_MID,        freq_desc_ann),
-       INTEL_CPU_FAM6(ATOM_AIRMONT_NP,         freq_desc_lgm),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_MID,   &freq_desc_pnw),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_TABLET,&freq_desc_clv),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,     &freq_desc_byt),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &freq_desc_tng),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        &freq_desc_cht),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_MID,    &freq_desc_ann),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_NP,     &freq_desc_lgm),
        {}
 };
 
@@ -81,17 +159,19 @@ static const struct x86_cpu_id tsc_msr_cpu_ids[] = {
  */
 unsigned long cpu_khz_from_msr(void)
 {
-       u32 lo, hi, ratio, freq;
+       u32 lo, hi, ratio, freq, tscref;
        const struct freq_desc *freq_desc;
        const struct x86_cpu_id *id;
+       const struct muldiv *md;
        unsigned long res;
+       int index;
 
        id = x86_match_cpu(tsc_msr_cpu_ids);
        if (!id)
                return 0;
 
        freq_desc = (struct freq_desc *)id->driver_data;
-       if (freq_desc->msr_plat) {
+       if (freq_desc->use_msr_plat) {
                rdmsr(MSR_PLATFORM_INFO, lo, hi);
                ratio = (lo >> 8) & 0xff;
        } else {
@@ -101,12 +181,28 @@ unsigned long cpu_khz_from_msr(void)
 
        /* Get FSB FREQ ID */
        rdmsr(MSR_FSB_FREQ, lo, hi);
+       index = lo & freq_desc->mask;
+       md = &freq_desc->muldiv[index];
 
-       /* Map CPU reference clock freq ID(0-7) to CPU reference clock freq(KHz) */
-       freq = freq_desc->freqs[lo & 0x7];
+       /*
+        * Note this also catches cases where the index points to an unpopulated
+        * part of muldiv, in that case the else will set freq and res to 0.
+        */
+       if (md->divider) {
+               tscref = TSC_REFERENCE_KHZ * md->multiplier;
+               freq = DIV_ROUND_CLOSEST(tscref, md->divider);
+               /*
+                * Multiplying by ratio before the division has better
+                * accuracy than just calculating freq * ratio.
+                */
+               res = DIV_ROUND_CLOSEST(tscref * ratio, md->divider);
+       } else {
+               freq = freq_desc->freqs[index];
+               res = freq * ratio;
+       }
 
-       /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
-       res = freq * ratio;
+       if (freq == 0)
+               pr_err("Error MSR_FSB_FREQ index %d is unknown\n", index);
 
 #ifdef CONFIG_X86_LOCAL_APIC
        lapic_timer_period = (freq * 1000) / HZ;
index 7206e1a..1bf7e31 100644 (file)
@@ -314,8 +314,8 @@ SECTIONS
 
        . = ALIGN(8);
        /*
-        * .exit.text is discard at runtime, not link time, to deal with
-        *  references from .altinstructions and .eh_frame
+        * .exit.text is discarded at runtime, not link time, to deal with
+        *  references from .altinstructions
         */
        .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) {
                EXIT_TEXT
@@ -413,9 +413,6 @@ SECTIONS
        DWARF_DEBUG
 
        DISCARDS
-       /DISCARD/ : {
-               *(.eh_frame)
-       }
 }
 
 
index 991019d..9fea075 100644 (file)
@@ -59,6 +59,19 @@ config KVM
 
          If unsure, say N.
 
+config KVM_WERROR
+       bool "Compile KVM with -Werror"
+       # KASAN may cause the build to fail due to larger frames
+       default y if X86_64 && !KASAN
+       # We use the dependency on !COMPILE_TEST to not be enabled
+       # blindly in allmodconfig or allyesconfig configurations
+       depends on (X86_64 && !KASAN) || !COMPILE_TEST
+       depends on EXPERT
+       help
+         Add -Werror to the build flags for KVM.
+
+         If in doubt, say "N".
+
 config KVM_INTEL
        tristate "KVM for Intel (and compatible) processors support"
        depends on KVM && IA32_FEAT_CTL
index b19ef42..e553f0f 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 ccflags-y += -Iarch/x86/kvm
+ccflags-$(CONFIG_KVM_WERROR) += -Werror
 
 KVM := ../../../virt/kvm
 
index ddbc619..bc00642 100644 (file)
 #define NR_FASTOP (ilog2(sizeof(ulong)) + 1)
 #define FASTOP_SIZE 8
 
-/*
- * fastop functions have a special calling convention:
- *
- * dst:    rax        (in/out)
- * src:    rdx        (in/out)
- * src2:   rcx        (in)
- * flags:  rflags     (in/out)
- * ex:     rsi        (in:fastop pointer, out:zero if exception)
- *
- * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
- * different operand sizes can be reached by calculation, rather than a jump
- * table (which would be bigger than the code).
- *
- * fastop functions are declared as taking a never-defined fastop parameter,
- * so they can't be called from C directly.
- */
-
-struct fastop;
-
 struct opcode {
        u64 flags : 56;
        u64 intercept : 8;
@@ -311,8 +292,19 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
 #define ON64(x)
 #endif
 
-typedef void (*fastop_t)(struct fastop *);
-
+/*
+ * fastop functions have a special calling convention:
+ *
+ * dst:    rax        (in/out)
+ * src:    rdx        (in/out)
+ * src2:   rcx        (in)
+ * flags:  rflags     (in/out)
+ * ex:     rsi        (in:fastop pointer, out:zero if exception)
+ *
+ * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
+ * different operand sizes can be reached by calculation, rather than a jump
+ * table (which would be bigger than the code).
+ */
 static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 
 #define __FOP_FUNC(name) \
@@ -5181,6 +5173,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
        ctxt->fetch.ptr = ctxt->fetch.data;
        ctxt->fetch.end = ctxt->fetch.data + insn_len;
        ctxt->opcode_len = 1;
+       ctxt->intercept = x86_intercept_none;
        if (insn_len > 0)
                memcpy(ctxt->fetch.data, insn, insn_len);
        else {
@@ -5683,7 +5676,7 @@ special_insn:
 
        if (ctxt->execute) {
                if (ctxt->d & Fastop)
-                       rc = fastop(ctxt, (fastop_t)ctxt->execute);
+                       rc = fastop(ctxt, ctxt->fop);
                else
                        rc = ctxt->execute(ctxt);
                if (rc != X86EMUL_CONTINUE)
index 7668fed..750ff0b 100644 (file)
@@ -378,12 +378,15 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
                if (e->fields.delivery_mode == APIC_DM_FIXED) {
                        struct kvm_lapic_irq irq;
 
-                       irq.shorthand = APIC_DEST_NOSHORT;
                        irq.vector = e->fields.vector;
                        irq.delivery_mode = e->fields.delivery_mode << 8;
-                       irq.dest_id = e->fields.dest_id;
                        irq.dest_mode =
                            kvm_lapic_irq_dest_mode(!!e->fields.dest_mode);
+                       irq.level = false;
+                       irq.trig_mode = e->fields.trig_mode;
+                       irq.shorthand = APIC_DEST_NOSHORT;
+                       irq.dest_id = e->fields.dest_id;
+                       irq.msi_redir_hint = false;
                        bitmap_zero(&vcpu_bitmap, 16);
                        kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
                                                 &vcpu_bitmap);
index 79afa0b..c47d2ac 100644 (file)
@@ -417,7 +417,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
 
                        kvm_set_msi_irq(vcpu->kvm, entry, &irq);
 
-                       if (irq.level &&
+                       if (irq.trig_mode &&
                            kvm_apic_match_dest(vcpu, NULL, APIC_DEST_NOSHORT,
                                                irq.dest_id, irq.dest_mode))
                                __set_bit(irq.vector, ioapic_handled_vectors);
index afcd30d..7356a56 100644 (file)
@@ -627,9 +627,11 @@ static inline bool pv_eoi_enabled(struct kvm_vcpu *vcpu)
 static bool pv_eoi_get_pending(struct kvm_vcpu *vcpu)
 {
        u8 val;
-       if (pv_eoi_get_user(vcpu, &val) < 0)
+       if (pv_eoi_get_user(vcpu, &val) < 0) {
                printk(KERN_WARNING "Can't read EOI MSR value: 0x%llx\n",
                           (unsigned long long)vcpu->arch.pv_eoi.msr_val);
+               return false;
+       }
        return val & 0x1;
 }
 
@@ -1046,11 +1048,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                                                       apic->regs + APIC_TMR);
                }
 
-               if (vcpu->arch.apicv_active)
-                       kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
-               else {
+               if (kvm_x86_ops->deliver_posted_interrupt(vcpu, vector)) {
                        kvm_lapic_set_irr(vector, apic);
-
                        kvm_make_request(KVM_REQ_EVENT, vcpu);
                        kvm_vcpu_kick(vcpu);
                }
@@ -1446,6 +1445,8 @@ static void limit_periodic_timer_frequency(struct kvm_lapic *apic)
        }
 }
 
+static void cancel_hv_timer(struct kvm_lapic *apic);
+
 static void apic_update_lvtt(struct kvm_lapic *apic)
 {
        u32 timer_mode = kvm_lapic_get_reg(apic, APIC_LVTT) &
@@ -1455,6 +1456,10 @@ static void apic_update_lvtt(struct kvm_lapic *apic)
                if (apic_lvtt_tscdeadline(apic) != (timer_mode ==
                                APIC_LVT_TIMER_TSCDEADLINE)) {
                        hrtimer_cancel(&apic->lapic_timer.timer);
+                       preempt_disable();
+                       if (apic->lapic_timer.hv_timer_in_use)
+                               cancel_hv_timer(apic);
+                       preempt_enable();
                        kvm_lapic_set_reg(apic, APIC_TMICT, 0);
                        apic->lapic_timer.period = 0;
                        apic->lapic_timer.tscdeadline = 0;
@@ -1716,7 +1721,7 @@ static void start_sw_period(struct kvm_lapic *apic)
 
        hrtimer_start(&apic->lapic_timer.timer,
                apic->lapic_timer.target_expiration,
-               HRTIMER_MODE_ABS);
+               HRTIMER_MODE_ABS_HARD);
 }
 
 bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu)
index 3c6522b..ffcd96f 100644 (file)
@@ -339,7 +339,7 @@ TRACE_EVENT(
                /* These depend on page entry type, so compute them now.  */
                __field(bool, r)
                __field(bool, x)
-               __field(u8, u)
+               __field(signed char, u)
        ),
 
        TP_fast_assign(
index bef0ba3..216364c 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/kvm_para.h>
 #include <asm/irq_remapping.h>
 #include <asm/spec-ctrl.h>
+#include <asm/cpu_device_id.h>
 
 #include <asm/virtext.h>
 #include "trace.h"
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+#ifdef MODULE
 static const struct x86_cpu_id svm_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_SVM),
+       X86_MATCH_FEATURE(X86_FEATURE_SVM, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
+#endif
 
 #define IOPM_ALLOC_ORDER 2
 #define MSRPM_ALLOC_ORDER 1
@@ -1005,33 +1008,32 @@ static void svm_cpu_uninit(int cpu)
 static int svm_cpu_init(int cpu)
 {
        struct svm_cpu_data *sd;
-       int r;
 
        sd = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL);
        if (!sd)
                return -ENOMEM;
        sd->cpu = cpu;
-       r = -ENOMEM;
        sd->save_area = alloc_page(GFP_KERNEL);
        if (!sd->save_area)
-               goto err_1;
+               goto free_cpu_data;
 
        if (svm_sev_enabled()) {
-               r = -ENOMEM;
                sd->sev_vmcbs = kmalloc_array(max_sev_asid + 1,
                                              sizeof(void *),
                                              GFP_KERNEL);
                if (!sd->sev_vmcbs)
-                       goto err_1;
+                       goto free_save_area;
        }
 
        per_cpu(svm_data, cpu) = sd;
 
        return 0;
 
-err_1:
+free_save_area:
+       __free_page(sd->save_area);
+free_cpu_data:
        kfree(sd);
-       return r;
+       return -ENOMEM;
 
 }
 
@@ -1350,6 +1352,24 @@ static __init void svm_adjust_mmio_mask(void)
        kvm_mmu_set_mmio_spte_mask(mask, mask, PT_WRITABLE_MASK | PT_USER_MASK);
 }
 
+static void svm_hardware_teardown(void)
+{
+       int cpu;
+
+       if (svm_sev_enabled()) {
+               bitmap_free(sev_asid_bitmap);
+               bitmap_free(sev_reclaim_asid_bitmap);
+
+               sev_flush_asids();
+       }
+
+       for_each_possible_cpu(cpu)
+               svm_cpu_uninit(cpu);
+
+       __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
+       iopm_base = 0;
+}
+
 static __init int svm_hardware_setup(void)
 {
        int cpu;
@@ -1463,29 +1483,10 @@ static __init int svm_hardware_setup(void)
        return 0;
 
 err:
-       __free_pages(iopm_pages, IOPM_ALLOC_ORDER);
-       iopm_base = 0;
+       svm_hardware_teardown();
        return r;
 }
 
-static __exit void svm_hardware_unsetup(void)
-{
-       int cpu;
-
-       if (svm_sev_enabled()) {
-               bitmap_free(sev_asid_bitmap);
-               bitmap_free(sev_reclaim_asid_bitmap);
-
-               sev_flush_asids();
-       }
-
-       for_each_possible_cpu(cpu)
-               svm_cpu_uninit(cpu);
-
-       __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER);
-       iopm_base = 0;
-}
-
 static void init_seg(struct vmcb_seg *seg)
 {
        seg->selector = 0;
@@ -1933,14 +1934,6 @@ static void sev_clflush_pages(struct page *pages[], unsigned long npages)
 static void __unregister_enc_region_locked(struct kvm *kvm,
                                           struct enc_region *region)
 {
-       /*
-        * The guest may change the memory encryption attribute from C=0 -> C=1
-        * or vice versa for this memory range. Lets make sure caches are
-        * flushed to ensure that guest data gets written into memory with
-        * correct C-bit.
-        */
-       sev_clflush_pages(region->pages, region->npages);
-
        sev_unpin_memory(kvm, region->pages, region->npages);
        list_del(&region->list);
        kfree(region);
@@ -1971,6 +1964,13 @@ static void sev_vm_destroy(struct kvm *kvm)
        mutex_lock(&kvm->lock);
 
        /*
+        * Ensure that all guest tagged cache entries are flushed before
+        * releasing the pages back to the system for use. CLFLUSH will
+        * not do this, so issue a WBINVD.
+        */
+       wbinvd_on_all_cpus();
+
+       /*
         * if userspace was terminated before unregistering the memory regions
         * then lets unpin all the registered memory.
         */
@@ -2196,8 +2196,9 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 static int avic_init_vcpu(struct vcpu_svm *svm)
 {
        int ret;
+       struct kvm_vcpu *vcpu = &svm->vcpu;
 
-       if (!kvm_vcpu_apicv_active(&svm->vcpu))
+       if (!avic || !irqchip_in_kernel(vcpu->kvm))
                return 0;
 
        ret = avic_init_backing_page(&svm->vcpu);
@@ -5232,6 +5233,9 @@ static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
        struct vmcb *vmcb = svm->vmcb;
        bool activated = kvm_vcpu_apicv_active(vcpu);
 
+       if (!avic)
+               return;
+
        if (activated) {
                /**
                 * During AVIC temporary deactivation, guest could update
@@ -5255,8 +5259,11 @@ static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
        return;
 }
 
-static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
+static int svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
 {
+       if (!vcpu->arch.apicv_active)
+               return -1;
+
        kvm_lapic_set_irr(vec, vcpu->arch.apic);
        smp_mb__after_atomic();
 
@@ -5268,6 +5275,8 @@ static void svm_deliver_avic_intr(struct kvm_vcpu *vcpu, int vec)
                put_cpu();
        } else
                kvm_vcpu_wake_up(vcpu);
+
+       return 0;
 }
 
 static bool svm_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu)
@@ -6303,7 +6312,8 @@ static void svm_handle_exit_irqoff(struct kvm_vcpu *vcpu,
        enum exit_fastpath_completion *exit_fastpath)
 {
        if (!is_guest_mode(vcpu) &&
-               to_svm(vcpu)->vmcb->control.exit_code == EXIT_REASON_MSR_WRITE)
+           to_svm(vcpu)->vmcb->control.exit_code == SVM_EXIT_MSR &&
+           to_svm(vcpu)->vmcb->control.exit_info_1)
                *exit_fastpath = handle_fastpath_set_msr_irqoff(vcpu);
 }
 
@@ -7148,6 +7158,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
        if (!svm_sev_enabled())
                return -ENOTTY;
 
+       if (!argp)
+               return 0;
+
        if (copy_from_user(&sev_cmd, argp, sizeof(struct kvm_sev_cmd)))
                return -EFAULT;
 
@@ -7275,6 +7288,13 @@ static int svm_unregister_enc_region(struct kvm *kvm,
                goto failed;
        }
 
+       /*
+        * Ensure that all guest tagged cache entries are flushed before
+        * releasing the pages back to the system for use. CLFLUSH will
+        * not do this, so issue a WBINVD.
+        */
+       wbinvd_on_all_cpus();
+
        __unregister_enc_region_locked(kvm, region);
 
        mutex_unlock(&kvm->lock);
@@ -7378,7 +7398,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .cpu_has_kvm_support = has_svm,
        .disabled_by_bios = is_disabled,
        .hardware_setup = svm_hardware_setup,
-       .hardware_unsetup = svm_hardware_unsetup,
+       .hardware_unsetup = svm_hardware_teardown,
        .check_processor_compatibility = svm_check_processor_compat,
        .hardware_enable = svm_hardware_enable,
        .hardware_disable = svm_hardware_disable,
@@ -7433,6 +7453,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .run = svm_vcpu_run,
        .handle_exit = handle_exit,
        .skip_emulated_instruction = skip_emulated_instruction,
+       .update_emulated_instruction = NULL,
        .set_interrupt_shadow = svm_set_interrupt_shadow,
        .get_interrupt_shadow = svm_get_interrupt_shadow,
        .patch_hypercall = svm_patch_hypercall,
index f194dd0..cef5a34 100644 (file)
@@ -815,8 +815,8 @@ TRACE_EVENT(kvm_write_tsc_offset,
 #ifdef CONFIG_X86_64
 
 #define host_clocks                                    \
-       {VCLOCK_NONE, "none"},                          \
-       {VCLOCK_TSC,  "tsc"}                            \
+       {VDSO_CLOCKMODE_NONE, "none"},                  \
+       {VDSO_CLOCKMODE_TSC,  "tsc"}                    \
 
 TRACE_EVENT(kvm_update_master_clock,
        TP_PROTO(bool use_master_clock, unsigned int host_clock, bool offset_matched),
index 283bdb7..f486e26 100644 (file)
@@ -12,6 +12,7 @@ extern bool __read_mostly enable_ept;
 extern bool __read_mostly enable_unrestricted_guest;
 extern bool __read_mostly enable_ept_ad_bits;
 extern bool __read_mostly enable_pml;
+extern bool __read_mostly enable_apicv;
 extern int __read_mostly pt_mode;
 
 #define PT_MODE_SYSTEM         0
index 3589cd3..9750e59 100644 (file)
@@ -224,7 +224,7 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu)
                return;
 
        kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true);
-       vmx->nested.hv_evmcs_vmptr = -1ull;
+       vmx->nested.hv_evmcs_vmptr = 0;
        vmx->nested.hv_evmcs = NULL;
 }
 
@@ -1923,7 +1923,8 @@ static int nested_vmx_handle_enlightened_vmptrld(struct kvm_vcpu *vcpu,
        if (!nested_enlightened_vmentry(vcpu, &evmcs_gpa))
                return 1;
 
-       if (unlikely(evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
+       if (unlikely(!vmx->nested.hv_evmcs ||
+                    evmcs_gpa != vmx->nested.hv_evmcs_vmptr)) {
                if (!vmx->nested.hv_evmcs)
                        vmx->nested.current_vmptr = -1ull;
 
@@ -3161,10 +3162,10 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
  * or KVM_SET_NESTED_STATE).  Otherwise it's called from vmlaunch/vmresume.
  *
  * Returns:
- *     NVMX_ENTRY_SUCCESS: Entered VMX non-root mode
- *     NVMX_ENTRY_VMFAIL:  Consistency check VMFail
- *     NVMX_ENTRY_VMEXIT:  Consistency check VMExit
- *     NVMX_ENTRY_KVM_INTERNAL_ERROR: KVM internal error
+ *     NVMX_VMENTRY_SUCCESS: Entered VMX non-root mode
+ *     NVMX_VMENTRY_VMFAIL:  Consistency check VMFail
+ *     NVMX_VMENTRY_VMEXIT:  Consistency check VMExit
+ *     NVMX_VMENTRY_KVM_INTERNAL_ERROR: KVM internal error
  */
 enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu,
                                                        bool from_vmentry)
@@ -3609,8 +3610,15 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
        unsigned long exit_qual;
        bool block_nested_events =
            vmx->nested.nested_run_pending || kvm_event_needs_reinjection(vcpu);
+       bool mtf_pending = vmx->nested.mtf_pending;
        struct kvm_lapic *apic = vcpu->arch.apic;
 
+       /*
+        * Clear the MTF state. If a higher priority VM-exit is delivered first,
+        * this state is discarded.
+        */
+       vmx->nested.mtf_pending = false;
+
        if (lapic_in_kernel(vcpu) &&
                test_bit(KVM_APIC_INIT, &apic->pending_events)) {
                if (block_nested_events)
@@ -3621,8 +3629,28 @@ static int vmx_check_nested_events(struct kvm_vcpu *vcpu, bool external_intr)
                return 0;
        }
 
+       /*
+        * Process any exceptions that are not debug traps before MTF.
+        */
+       if (vcpu->arch.exception.pending &&
+           !vmx_pending_dbg_trap(vcpu) &&
+           nested_vmx_check_exception(vcpu, &exit_qual)) {
+               if (block_nested_events)
+                       return -EBUSY;
+               nested_vmx_inject_exception_vmexit(vcpu, exit_qual);
+               return 0;
+       }
+
+       if (mtf_pending) {
+               if (block_nested_events)
+                       return -EBUSY;
+               nested_vmx_update_pending_dbg(vcpu);
+               nested_vmx_vmexit(vcpu, EXIT_REASON_MONITOR_TRAP_FLAG, 0, 0);
+               return 0;
+       }
+
        if (vcpu->arch.exception.pending &&
-               nested_vmx_check_exception(vcpu, &exit_qual)) {
+           nested_vmx_check_exception(vcpu, &exit_qual)) {
                if (block_nested_events)
                        return -EBUSY;
                nested_vmx_inject_exception_vmexit(vcpu, exit_qual);
@@ -5285,24 +5313,17 @@ fail:
        return 1;
 }
 
-
-static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
-                                      struct vmcs12 *vmcs12)
+/*
+ * Return true if an IO instruction with the specified port and size should cause
+ * a VM-exit into L1.
+ */
+bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
+                                int size)
 {
-       unsigned long exit_qualification;
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
        gpa_t bitmap, last_bitmap;
-       unsigned int port;
-       int size;
        u8 b;
 
-       if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
-               return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING);
-
-       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
-
-       port = exit_qualification >> 16;
-       size = (exit_qualification & 7) + 1;
-
        last_bitmap = (gpa_t)-1;
        b = -1;
 
@@ -5329,8 +5350,26 @@ static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
        return false;
 }
 
+static bool nested_vmx_exit_handled_io(struct kvm_vcpu *vcpu,
+                                      struct vmcs12 *vmcs12)
+{
+       unsigned long exit_qualification;
+       unsigned short port;
+       int size;
+
+       if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
+               return nested_cpu_has(vmcs12, CPU_BASED_UNCOND_IO_EXITING);
+
+       exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
+
+       port = exit_qualification >> 16;
+       size = (exit_qualification & 7) + 1;
+
+       return nested_vmx_check_io_bitmaps(vcpu, port, size);
+}
+
 /*
- * Return 1 if we should exit from L2 to L1 to handle an MSR access access,
+ * Return 1 if we should exit from L2 to L1 to handle an MSR access,
  * rather than handle it ourselves in L0. I.e., check whether L1 expressed
  * disinterest in the current event (read or write a specific MSR) by using an
  * MSR bitmap. This may be the case even when L0 doesn't use MSR bitmaps.
@@ -5712,6 +5751,9 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
 
                        if (vmx->nested.nested_run_pending)
                                kvm_state.flags |= KVM_STATE_NESTED_RUN_PENDING;
+
+                       if (vmx->nested.mtf_pending)
+                               kvm_state.flags |= KVM_STATE_NESTED_MTF_PENDING;
                }
        }
 
@@ -5892,6 +5934,9 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu,
        vmx->nested.nested_run_pending =
                !!(kvm_state->flags & KVM_STATE_NESTED_RUN_PENDING);
 
+       vmx->nested.mtf_pending =
+               !!(kvm_state->flags & KVM_STATE_NESTED_MTF_PENDING);
+
        ret = -EINVAL;
        if (nested_cpu_has_shadow_vmcs(vmcs12) &&
            vmcs12->vmcs_link_pointer != -1ull) {
@@ -5949,8 +5994,7 @@ void nested_vmx_set_vmcs_shadowing_bitmap(void)
  * bit in the high half is on if the corresponding bit in the control field
  * may be on. See also vmx_control_verify().
  */
-void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
-                               bool apicv)
+void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps)
 {
        /*
         * Note that as a general rule, the high half of the MSRs (bits in
@@ -5977,7 +6021,7 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
                PIN_BASED_EXT_INTR_MASK |
                PIN_BASED_NMI_EXITING |
                PIN_BASED_VIRTUAL_NMIS |
-               (apicv ? PIN_BASED_POSTED_INTR : 0);
+               (enable_apicv ? PIN_BASED_POSTED_INTR : 0);
        msrs->pinbased_ctls_high |=
                PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
                PIN_BASED_VMX_PREEMPTION_TIMER;
index fc874d4..9aeda46 100644 (file)
@@ -17,8 +17,7 @@ enum nvmx_vmentry_status {
 };
 
 void vmx_leave_nested(struct kvm_vcpu *vcpu);
-void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps,
-                               bool apicv);
+void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps);
 void nested_vmx_hardware_unsetup(void);
 __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *));
 void nested_vmx_set_vmcs_shadowing_bitmap(void);
@@ -34,6 +33,8 @@ 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, int len, gva_t *ret);
 void nested_vmx_pmu_entry_exit_ctls_update(struct kvm_vcpu *vcpu);
+bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port,
+                                int size);
 
 static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
 {
@@ -175,6 +176,11 @@ static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12)
        return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS;
 }
 
+static inline int nested_cpu_has_mtf(struct vmcs12 *vmcs12)
+{
+       return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_TRAP_FLAG);
+}
+
 static inline int nested_cpu_has_ept(struct vmcs12 *vmcs12)
 {
        return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_EPT);
index 3be25ec..22aac04 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/apic.h>
 #include <asm/asm.h>
 #include <asm/cpu.h>
+#include <asm/cpu_device_id.h>
 #include <asm/debugreg.h>
 #include <asm/desc.h>
 #include <asm/fpu/internal.h>
 MODULE_AUTHOR("Qumranet");
 MODULE_LICENSE("GPL");
 
+#ifdef MODULE
 static const struct x86_cpu_id vmx_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_VMX),
+       X86_MATCH_FEATURE(X86_FEATURE_VMX, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, vmx_cpu_id);
+#endif
 
 bool __read_mostly enable_vpid = 1;
 module_param_named(vpid, enable_vpid, bool, 0444);
@@ -95,7 +98,7 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO);
 static bool __read_mostly fasteoi = 1;
 module_param(fasteoi, bool, S_IRUGO);
 
-static bool __read_mostly enable_apicv = 1;
+bool __read_mostly enable_apicv = 1;
 module_param(enable_apicv, bool, S_IRUGO);
 
 /*
@@ -1175,6 +1178,10 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
                                           vmx->guest_msrs[i].mask);
 
        }
+
+       if (vmx->nested.need_vmcs12_to_shadow_sync)
+               nested_sync_vmcs12_to_shadow(vcpu);
+
        if (vmx->guest_state_loaded)
                return;
 
@@ -1599,6 +1606,40 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
        return 1;
 }
 
+
+/*
+ * Recognizes a pending MTF VM-exit and records the nested state for later
+ * delivery.
+ */
+static void vmx_update_emulated_instruction(struct kvm_vcpu *vcpu)
+{
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       if (!is_guest_mode(vcpu))
+               return;
+
+       /*
+        * Per the SDM, MTF takes priority over debug-trap exceptions besides
+        * T-bit traps. As instruction emulation is completed (i.e. at the
+        * instruction boundary), any #DB exception pending delivery must be a
+        * debug-trap. Record the pending MTF state to be delivered in
+        * vmx_check_nested_events().
+        */
+       if (nested_cpu_has_mtf(vmcs12) &&
+           (!vcpu->arch.exception.pending ||
+            vcpu->arch.exception.nr == DB_VECTOR))
+               vmx->nested.mtf_pending = true;
+       else
+               vmx->nested.mtf_pending = false;
+}
+
+static int vmx_skip_emulated_instruction(struct kvm_vcpu *vcpu)
+{
+       vmx_update_emulated_instruction(vcpu);
+       return skip_emulated_instruction(vcpu);
+}
+
 static void vmx_clear_hlt(struct kvm_vcpu *vcpu)
 {
        /*
@@ -2298,6 +2339,17 @@ static void hardware_disable(void)
        kvm_cpu_vmxoff();
 }
 
+/*
+ * There is no X86_FEATURE for SGX yet, but anyway we need to query CPUID
+ * directly instead of going through cpu_has(), to ensure KVM is trapping
+ * ENCLS whenever it's supported in hardware.  It does not matter whether
+ * the host OS supports or has enabled SGX.
+ */
+static bool cpu_has_sgx(void)
+{
+       return cpuid_eax(0) >= 0x12 && (cpuid_eax(0x12) & BIT(0));
+}
+
 static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
                                      u32 msr, u32 *result)
 {
@@ -2378,8 +2430,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf,
                        SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE |
                        SECONDARY_EXEC_PT_USE_GPA |
                        SECONDARY_EXEC_PT_CONCEAL_VMX |
-                       SECONDARY_EXEC_ENABLE_VMFUNC |
-                       SECONDARY_EXEC_ENCLS_EXITING;
+                       SECONDARY_EXEC_ENABLE_VMFUNC;
+               if (cpu_has_sgx())
+                       opt2 |= SECONDARY_EXEC_ENCLS_EXITING;
                if (adjust_vmx_controls(min2, opt2,
                                        MSR_IA32_VMX_PROCBASED_CTLS2,
                                        &_cpu_based_2nd_exec_control) < 0)
@@ -3818,24 +3871,29 @@ static int vmx_deliver_nested_posted_interrupt(struct kvm_vcpu *vcpu,
  * 2. If target vcpu isn't running(root mode), kick it to pick up the
  * interrupt from PIR in next vmentry.
  */
-static void vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
+static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        int r;
 
        r = vmx_deliver_nested_posted_interrupt(vcpu, vector);
        if (!r)
-               return;
+               return 0;
+
+       if (!vcpu->arch.apicv_active)
+               return -1;
 
        if (pi_test_and_set_pir(vector, &vmx->pi_desc))
-               return;
+               return 0;
 
        /* If a previous notification has sent the IPI, nothing to do.  */
        if (pi_test_and_set_on(&vmx->pi_desc))
-               return;
+               return 0;
 
        if (!kvm_vcpu_trigger_posted_interrupt(vcpu, false))
                kvm_vcpu_kick(vcpu);
+
+       return 0;
 }
 
 /*
@@ -6230,7 +6288,7 @@ static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu)
 #endif
                ASM_CALL_CONSTRAINT
                :
-               THUNK_TARGET(entry),
+               [thunk_target]"r"(entry),
                [ss]"i"(__KERNEL_DS),
                [cs]"i"(__KERNEL_CS)
        );
@@ -6482,8 +6540,11 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
                vmcs_write32(PLE_WINDOW, vmx->ple_window);
        }
 
-       if (vmx->nested.need_vmcs12_to_shadow_sync)
-               nested_sync_vmcs12_to_shadow(vcpu);
+       /*
+        * We did this in prepare_switch_to_guest, because it needs to
+        * be within srcu_read_lock.
+        */
+       WARN_ON_ONCE(vmx->nested.need_vmcs12_to_shadow_sync);
 
        if (kvm_register_is_dirty(vcpu, VCPU_REGS_RSP))
                vmcs_writel(GUEST_RSP, vcpu->arch.regs[VCPU_REGS_RSP]);
@@ -6757,8 +6818,7 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
 
        if (nested)
                nested_vmx_setup_ctls_msrs(&vmx->nested.msrs,
-                                          vmx_capability.ept,
-                                          kvm_vcpu_apicv_active(vcpu));
+                                          vmx_capability.ept);
        else
                memset(&vmx->nested.msrs, 0, sizeof(vmx->nested.msrs));
 
@@ -6839,8 +6899,7 @@ static int __init vmx_check_processor_compat(void)
        if (setup_vmcs_config(&vmcs_conf, &vmx_cap) < 0)
                return -EIO;
        if (nested)
-               nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept,
-                                          enable_apicv);
+               nested_vmx_setup_ctls_msrs(&vmcs_conf.nested, vmx_cap.ept);
        if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) {
                printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n",
                                smp_processor_id());
@@ -7101,6 +7160,40 @@ static void vmx_request_immediate_exit(struct kvm_vcpu *vcpu)
        to_vmx(vcpu)->req_immediate_exit = true;
 }
 
+static int vmx_check_intercept_io(struct kvm_vcpu *vcpu,
+                                 struct x86_instruction_info *info)
+{
+       struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+       unsigned short port;
+       bool intercept;
+       int size;
+
+       if (info->intercept == x86_intercept_in ||
+           info->intercept == x86_intercept_ins) {
+               port = info->src_val;
+               size = info->dst_bytes;
+       } else {
+               port = info->dst_val;
+               size = info->src_bytes;
+       }
+
+       /*
+        * If the 'use IO bitmaps' VM-execution control is 0, IO instruction
+        * VM-exits depend on the 'unconditional IO exiting' VM-execution
+        * control.
+        *
+        * Otherwise, IO instruction VM-exits are controlled by the IO bitmaps.
+        */
+       if (!nested_cpu_has(vmcs12, CPU_BASED_USE_IO_BITMAPS))
+               intercept = nested_cpu_has(vmcs12,
+                                          CPU_BASED_UNCOND_IO_EXITING);
+       else
+               intercept = nested_vmx_check_io_bitmaps(vcpu, port, size);
+
+       /* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED.  */
+       return intercept ? X86EMUL_UNHANDLEABLE : X86EMUL_CONTINUE;
+}
+
 static int vmx_check_intercept(struct kvm_vcpu *vcpu,
                               struct x86_instruction_info *info,
                               enum x86_intercept_stage stage)
@@ -7108,19 +7201,45 @@ static int vmx_check_intercept(struct kvm_vcpu *vcpu,
        struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
        struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt;
 
+       switch (info->intercept) {
        /*
         * RDPID causes #UD if disabled through secondary execution controls.
         * Because it is marked as EmulateOnUD, we need to intercept it here.
         */
-       if (info->intercept == x86_intercept_rdtscp &&
-           !nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
-               ctxt->exception.vector = UD_VECTOR;
-               ctxt->exception.error_code_valid = false;
-               return X86EMUL_PROPAGATE_FAULT;
-       }
+       case x86_intercept_rdtscp:
+               if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_RDTSCP)) {
+                       ctxt->exception.vector = UD_VECTOR;
+                       ctxt->exception.error_code_valid = false;
+                       return X86EMUL_PROPAGATE_FAULT;
+               }
+               break;
+
+       case x86_intercept_in:
+       case x86_intercept_ins:
+       case x86_intercept_out:
+       case x86_intercept_outs:
+               return vmx_check_intercept_io(vcpu, info);
+
+       case x86_intercept_lgdt:
+       case x86_intercept_lidt:
+       case x86_intercept_lldt:
+       case x86_intercept_ltr:
+       case x86_intercept_sgdt:
+       case x86_intercept_sidt:
+       case x86_intercept_sldt:
+       case x86_intercept_str:
+               if (!nested_cpu_has2(vmcs12, SECONDARY_EXEC_DESC))
+                       return X86EMUL_CONTINUE;
+
+               /* FIXME: produce nested vmexit and return X86EMUL_INTERCEPTED.  */
+               break;
 
        /* TODO: check more intercepts... */
-       return X86EMUL_CONTINUE;
+       default:
+               break;
+       }
+
+       return X86EMUL_UNHANDLEABLE;
 }
 
 #ifdef CONFIG_X86_64
@@ -7702,7 +7821,7 @@ static __init int hardware_setup(void)
 
        if (nested) {
                nested_vmx_setup_ctls_msrs(&vmcs_config.nested,
-                                          vmx_capability.ept, enable_apicv);
+                                          vmx_capability.ept);
 
                r = nested_vmx_hardware_setup(kvm_vmx_exit_handlers);
                if (r)
@@ -7786,7 +7905,8 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
 
        .run = vmx_vcpu_run,
        .handle_exit = vmx_handle_exit,
-       .skip_emulated_instruction = skip_emulated_instruction,
+       .skip_emulated_instruction = vmx_skip_emulated_instruction,
+       .update_emulated_instruction = vmx_update_emulated_instruction,
        .set_interrupt_shadow = vmx_set_interrupt_shadow,
        .get_interrupt_shadow = vmx_get_interrupt_shadow,
        .patch_hypercall = vmx_patch_hypercall,
index 7f42cf3..e64da06 100644 (file)
@@ -150,6 +150,9 @@ struct nested_vmx {
        /* L2 must run next, and mustn't decide to exit to L1. */
        bool nested_run_pending;
 
+       /* Pending MTF VM-exit into L1.  */
+       bool mtf_pending;
+
        struct loaded_vmcs vmcs02;
 
        /*
index fb5d64e..bf8564d 100644 (file)
@@ -1554,7 +1554,10 @@ EXPORT_SYMBOL_GPL(kvm_emulate_wrmsr);
  */
 static int handle_fastpath_set_x2apic_icr_irqoff(struct kvm_vcpu *vcpu, u64 data)
 {
-       if (lapic_in_kernel(vcpu) && apic_x2apic_mode(vcpu->arch.apic) &&
+       if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(vcpu->arch.apic))
+               return 1;
+
+       if (((data & APIC_SHORT_MASK) == APIC_DEST_NOSHORT) &&
                ((data & APIC_DEST_MASK) == APIC_DEST_PHYSICAL) &&
                ((data & APIC_MODE_MASK) == APIC_DM_FIXED)) {
 
@@ -1631,7 +1634,7 @@ static void update_pvclock_gtod(struct timekeeper *tk)
        write_seqcount_begin(&vdata->seq);
 
        /* copy pvclock gtod data */
-       vdata->clock.vclock_mode        = tk->tkr_mono.clock->archdata.vclock_mode;
+       vdata->clock.vclock_mode        = tk->tkr_mono.clock->vdso_clock_mode;
        vdata->clock.cycle_last         = tk->tkr_mono.cycle_last;
        vdata->clock.mask               = tk->tkr_mono.mask;
        vdata->clock.mult               = tk->tkr_mono.mult;
@@ -1639,7 +1642,7 @@ static void update_pvclock_gtod(struct timekeeper *tk)
        vdata->clock.base_cycles        = tk->tkr_mono.xtime_nsec;
        vdata->clock.offset             = tk->tkr_mono.base;
 
-       vdata->raw_clock.vclock_mode    = tk->tkr_raw.clock->archdata.vclock_mode;
+       vdata->raw_clock.vclock_mode    = tk->tkr_raw.clock->vdso_clock_mode;
        vdata->raw_clock.cycle_last     = tk->tkr_raw.cycle_last;
        vdata->raw_clock.mask           = tk->tkr_raw.mask;
        vdata->raw_clock.mult           = tk->tkr_raw.mult;
@@ -1840,7 +1843,7 @@ static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
 
 static inline int gtod_is_based_on_tsc(int mode)
 {
-       return mode == VCLOCK_TSC || mode == VCLOCK_HVCLOCK;
+       return mode == VDSO_CLOCKMODE_TSC || mode == VDSO_CLOCKMODE_HVCLOCK;
 }
 
 static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu)
@@ -1933,7 +1936,7 @@ static inline bool kvm_check_tsc_unstable(void)
         * TSC is marked unstable when we're running on Hyper-V,
         * 'TSC page' clocksource is good.
         */
-       if (pvclock_gtod_data.clock.vclock_mode == VCLOCK_HVCLOCK)
+       if (pvclock_gtod_data.clock.vclock_mode == VDSO_CLOCKMODE_HVCLOCK)
                return false;
 #endif
        return check_tsc_unstable();
@@ -2088,30 +2091,30 @@ static inline u64 vgettsc(struct pvclock_clock *clock, u64 *tsc_timestamp,
        u64 tsc_pg_val;
 
        switch (clock->vclock_mode) {
-       case VCLOCK_HVCLOCK:
+       case VDSO_CLOCKMODE_HVCLOCK:
                tsc_pg_val = hv_read_tsc_page_tsc(hv_get_tsc_page(),
                                                  tsc_timestamp);
                if (tsc_pg_val != U64_MAX) {
                        /* TSC page valid */
-                       *mode = VCLOCK_HVCLOCK;
+                       *mode = VDSO_CLOCKMODE_HVCLOCK;
                        v = (tsc_pg_val - clock->cycle_last) &
                                clock->mask;
                } else {
                        /* TSC page invalid */
-                       *mode = VCLOCK_NONE;
+                       *mode = VDSO_CLOCKMODE_NONE;
                }
                break;
-       case VCLOCK_TSC:
-               *mode = VCLOCK_TSC;
+       case VDSO_CLOCKMODE_TSC:
+               *mode = VDSO_CLOCKMODE_TSC;
                *tsc_timestamp = read_tsc();
                v = (*tsc_timestamp - clock->cycle_last) &
                        clock->mask;
                break;
        default:
-               *mode = VCLOCK_NONE;
+               *mode = VDSO_CLOCKMODE_NONE;
        }
 
-       if (*mode == VCLOCK_NONE)
+       if (*mode == VDSO_CLOCKMODE_NONE)
                *tsc_timestamp = v = 0;
 
        return v * clock->mult;
@@ -2444,7 +2447,6 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        vcpu->hv_clock.tsc_timestamp = tsc_timestamp;
        vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
        vcpu->last_guest_tsc = tsc_timestamp;
-       WARN_ON((s64)vcpu->hv_clock.system_time < 0);
 
        /* If the host uses TSC clocksource, then it is stable */
        pvclock_flags = 0;
@@ -6891,6 +6893,8 @@ restart:
                        kvm_rip_write(vcpu, ctxt->eip);
                        if (r && ctxt->tf)
                                r = kvm_vcpu_do_singlestep(vcpu);
+                       if (kvm_x86_ops->update_emulated_instruction)
+                               kvm_x86_ops->update_emulated_instruction(vcpu);
                        __kvm_set_rflags(vcpu, ctxt->eflags);
                }
 
@@ -7188,14 +7192,16 @@ static void kvm_timer_init(void)
 
        if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
 #ifdef CONFIG_CPU_FREQ
-               struct cpufreq_policy policy;
+               struct cpufreq_policy *policy;
                int cpu;
 
-               memset(&policy, 0, sizeof(policy));
                cpu = get_cpu();
-               cpufreq_get_policy(&policy, cpu);
-               if (policy.cpuinfo.max_freq)
-                       max_tsc_khz = policy.cpuinfo.max_freq;
+               policy = cpufreq_cpu_get(cpu);
+               if (policy) {
+                       if (policy->cpuinfo.max_freq)
+                               max_tsc_khz = policy->cpuinfo.max_freq;
+                       cpufreq_cpu_put(policy);
+               }
                put_cpu();
 #endif
                cpufreq_register_notifier(&kvmclock_cpufreq_notifier_block,
@@ -7306,12 +7312,12 @@ int kvm_arch_init(void *opaque)
        }
 
        if (!ops->cpu_has_kvm_support()) {
-               printk(KERN_ERR "kvm: no hardware support\n");
+               pr_err_ratelimited("kvm: no hardware support\n");
                r = -EOPNOTSUPP;
                goto out;
        }
        if (ops->disabled_by_bios()) {
-               printk(KERN_ERR "kvm: disabled by bios\n");
+               pr_err_ratelimited("kvm: disabled by bios\n");
                r = -EOPNOTSUPP;
                goto out;
        }
index 64229da..69309cd 100644 (file)
@@ -363,13 +363,8 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m,
 {
        const struct ptdump_range ptdump_ranges[] = {
 #ifdef CONFIG_X86_64
-
-#define normalize_addr_shift (64 - (__VIRTUAL_MASK_SHIFT + 1))
-#define normalize_addr(u) ((signed long)((u) << normalize_addr_shift) >> \
-                          normalize_addr_shift)
-
        {0, PTRS_PER_PGD * PGD_LEVEL_MULT / 2},
-       {normalize_addr(PTRS_PER_PGD * PGD_LEVEL_MULT / 2), ~0UL},
+       {GUARD_HOLE_END_ADDR, ~0UL},
 #else
        {0, ~0UL},
 #endif
index fa4ea09..629fdf1 100644 (file)
@@ -190,7 +190,7 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
        return pmd_k;
 }
 
-void vmalloc_sync_all(void)
+static void vmalloc_sync(void)
 {
        unsigned long address;
 
@@ -217,6 +217,16 @@ void vmalloc_sync_all(void)
        }
 }
 
+void vmalloc_sync_mappings(void)
+{
+       vmalloc_sync();
+}
+
+void vmalloc_sync_unmappings(void)
+{
+       vmalloc_sync();
+}
+
 /*
  * 32-bit:
  *
@@ -319,11 +329,23 @@ out:
 
 #else /* CONFIG_X86_64: */
 
-void vmalloc_sync_all(void)
+void vmalloc_sync_mappings(void)
 {
+       /*
+        * 64-bit mappings might allocate new p4d/pud pages
+        * that need to be propagated to all tasks' PGDs.
+        */
        sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END);
 }
 
+void vmalloc_sync_unmappings(void)
+{
+       /*
+        * Unmappings never allocate or free p4d/pud pages.
+        * No work is required here.
+        */
+}
+
 /*
  * 64-bit:
  *
index 44e4beb..18c637c 100644 (file)
@@ -106,6 +106,22 @@ static unsigned int __ioremap_check_encrypted(struct resource *res)
        return 0;
 }
 
+/*
+ * The EFI runtime services data area is not covered by walk_mem_res(), but must
+ * be mapped encrypted when SEV is active.
+ */
+static void __ioremap_check_other(resource_size_t addr, struct ioremap_desc *desc)
+{
+       if (!sev_active())
+               return;
+
+       if (!IS_ENABLED(CONFIG_EFI))
+               return;
+
+       if (efi_mem_type(addr) == EFI_RUNTIME_SERVICES_DATA)
+               desc->flags |= IORES_MAP_ENCRYPTED;
+}
+
 static int __ioremap_collect_map_flags(struct resource *res, void *arg)
 {
        struct ioremap_desc *desc = arg;
@@ -124,6 +140,9 @@ static int __ioremap_collect_map_flags(struct resource *res, void *arg)
  * To avoid multiple resource walks, this function walks resources marked as
  * IORESOURCE_MEM and IORESOURCE_BUSY and looking for system RAM and/or a
  * resource described not as IORES_DESC_NONE (e.g. IORES_DESC_ACPI_TABLES).
+ *
+ * After that, deal with misc other ranges in __ioremap_check_other() which do
+ * not fall into the above category.
  */
 static void __ioremap_check_mem(resource_size_t addr, unsigned long size,
                                struct ioremap_desc *desc)
@@ -135,6 +154,8 @@ static void __ioremap_check_mem(resource_size_t addr, unsigned long size,
        memset(desc, 0, sizeof(struct ioremap_desc));
 
        walk_mem_res(start, end, desc, __ioremap_collect_map_flags);
+
+       __ioremap_check_other(addr, desc);
 }
 
 /*
index 673de60..109325d 100644 (file)
@@ -386,7 +386,7 @@ static void enter_uniprocessor(void)
        put_online_cpus();
 
        for_each_cpu(cpu, downed_cpus) {
-               err = cpu_down(cpu);
+               err = remove_cpu(cpu);
                if (!err)
                        pr_info("CPU%d is down.\n", cpu);
                else
@@ -406,7 +406,7 @@ static void leave_uniprocessor(void)
                return;
        pr_notice("Re-enabling CPUs...\n");
        for_each_cpu(cpu, downed_cpus) {
-               err = cpu_up(cpu);
+               err = add_cpu(cpu);
                if (!err)
                        pr_info("enabled CPU%d.\n", cpu);
                else
index 393d251..4d2a7a7 100644 (file)
@@ -2039,10 +2039,12 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
                        }
                        /* and dreg_lo,sreg_lo */
                        EMIT2(0x23, add_2reg(0xC0, sreg_lo, dreg_lo));
-                       /* and dreg_hi,sreg_hi */
-                       EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
-                       /* or dreg_lo,dreg_hi */
-                       EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));
+                       if (is_jmp64) {
+                               /* and dreg_hi,sreg_hi */
+                               EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
+                               /* or dreg_lo,dreg_hi */
+                               EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));
+                       }
                        goto emit_cond_jmp;
                }
                case BPF_JMP | BPF_JSET | BPF_K:
index ee6b078..f8ed5f6 100644 (file)
@@ -117,17 +117,16 @@ static void punit_dbgfs_unregister(void)
        debugfs_remove_recursive(punit_dbg_file);
 }
 
-#define ICPU(model, drv_data) \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT,\
-         (kernel_ulong_t)&drv_data }
+#define X86_MATCH(model, data)                                          \
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_##model, \
+                                          X86_FEATURE_MWAIT, data)
 
 static const struct x86_cpu_id intel_punit_cpu_ids[] = {
-       ICPU(INTEL_FAM6_ATOM_SILVERMONT, punit_device_byt),
-       ICPU(INTEL_FAM6_ATOM_SILVERMONT_MID,  punit_device_tng),
-       ICPU(INTEL_FAM6_ATOM_AIRMONT,     punit_device_cht),
+       X86_MATCH(ATOM_SILVERMONT,              &punit_device_byt),
+       X86_MATCH(ATOM_SILVERMONT_MID,          &punit_device_tng),
+       X86_MATCH(ATOM_AIRMONT,                 &punit_device_cht),
        {}
 };
-
 MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
 
 static int __init punit_atom_debug_init(void)
index ae923ee..1aae530 100644 (file)
 #include <asm/x86_init.h>
 #include <asm/uv/uv.h>
 
-static efi_system_table_t efi_systab __initdata;
-static u64 efi_systab_phys __initdata;
+static unsigned long efi_systab_phys __initdata;
+static unsigned long prop_phys = EFI_INVALID_TABLE_ADDR;
+static unsigned long uga_phys = EFI_INVALID_TABLE_ADDR;
+static unsigned long efi_runtime, efi_nr_tables;
 
-static efi_config_table_type_t arch_tables[] __initdata = {
+unsigned long efi_fw_vendor, efi_config_table;
+
+static const efi_config_table_type_t arch_tables[] __initconst = {
+       {EFI_PROPERTIES_TABLE_GUID, "PROP", &prop_phys},
+       {UGA_IO_PROTOCOL_GUID, "UGA", &uga_phys},
 #ifdef CONFIG_X86_UV
        {UV_SYSTEM_TABLE_GUID, "UVsystab", &uv_systab_phys},
 #endif
@@ -65,26 +71,26 @@ static efi_config_table_type_t arch_tables[] __initdata = {
 };
 
 static const unsigned long * const efi_tables[] = {
-       &efi.mps,
        &efi.acpi,
        &efi.acpi20,
        &efi.smbios,
        &efi.smbios3,
-       &efi.boot_info,
-       &efi.hcdp,
-       &efi.uga,
+       &uga_phys,
 #ifdef CONFIG_X86_UV
        &uv_systab_phys,
 #endif
-       &efi.fw_vendor,
-       &efi.runtime,
-       &efi.config_table,
+       &efi_fw_vendor,
+       &efi_runtime,
+       &efi_config_table,
        &efi.esrt,
-       &efi.properties_table,
-       &efi.mem_attr_table,
+       &prop_phys,
+       &efi_mem_attr_table,
 #ifdef CONFIG_EFI_RCI2_TABLE
        &rci2_table_phys,
 #endif
+       &efi.tpm_log,
+       &efi.tpm_final_log,
+       &efi_rng_seed,
 };
 
 u64 efi_setup;         /* efi setup_data physical address */
@@ -214,16 +220,13 @@ int __init efi_memblock_x86_reserve_range(void)
        if (efi_enabled(EFI_PARAVIRT))
                return 0;
 
-#ifdef CONFIG_X86_32
-       /* Can't handle data above 4GB at this time */
-       if (e->efi_memmap_hi) {
+       /* Can't handle firmware tables above 4GB on i386 */
+       if (IS_ENABLED(CONFIG_X86_32) && e->efi_memmap_hi > 0) {
                pr_err("Memory map is above 4GB, disabling EFI.\n");
                return -EINVAL;
        }
-       pmap =  e->efi_memmap;
-#else
-       pmap = (e->efi_memmap | ((__u64)e->efi_memmap_hi << 32));
-#endif
+       pmap = (phys_addr_t)(e->efi_memmap | ((u64)e->efi_memmap_hi << 32));
+
        data.phys_map           = pmap;
        data.size               = e->efi_memmap_size;
        data.desc_size          = e->efi_memdesc_size;
@@ -243,6 +246,7 @@ int __init efi_memblock_x86_reserve_range(void)
             efi.memmap.desc_version);
 
        memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size);
+       set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags);
 
        return 0;
 }
@@ -305,11 +309,11 @@ static void __init efi_clean_memmap(void)
 
        if (n_removal > 0) {
                struct efi_memory_map_data data = {
-                       .phys_map = efi.memmap.phys_map,
-                       .desc_version = efi.memmap.desc_version,
-                       .desc_size = efi.memmap.desc_size,
-                       .size = efi.memmap.desc_size * (efi.memmap.nr_map - n_removal),
-                       .flags = 0,
+                       .phys_map       = efi.memmap.phys_map,
+                       .desc_version   = efi.memmap.desc_version,
+                       .desc_size      = efi.memmap.desc_size,
+                       .size           = efi.memmap.desc_size * (efi.memmap.nr_map - n_removal),
+                       .flags          = 0,
                };
 
                pr_warn("Removing %d invalid memory map entries.\n", n_removal);
@@ -333,43 +337,32 @@ void __init efi_print_memmap(void)
        }
 }
 
-static int __init efi_systab_init(u64 phys)
+static int __init efi_systab_init(unsigned long phys)
 {
        int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)
                                          : sizeof(efi_system_table_32_t);
+       const efi_table_hdr_t *hdr;
        bool over4g = false;
        void *p;
+       int ret;
 
-       p = early_memremap_ro(phys, size);
+       hdr = p = early_memremap_ro(phys, size);
        if (p == NULL) {
                pr_err("Couldn't map the system table!\n");
                return -ENOMEM;
        }
 
+       ret = efi_systab_check_header(hdr, 1);
+       if (ret) {
+               early_memunmap(p, size);
+               return ret;
+       }
+
        if (efi_enabled(EFI_64BIT)) {
                const efi_system_table_64_t *systab64 = p;
 
-               efi_systab.hdr                  = systab64->hdr;
-               efi_systab.fw_vendor            = systab64->fw_vendor;
-               efi_systab.fw_revision          = systab64->fw_revision;
-               efi_systab.con_in_handle        = systab64->con_in_handle;
-               efi_systab.con_in               = systab64->con_in;
-               efi_systab.con_out_handle       = systab64->con_out_handle;
-               efi_systab.con_out              = (void *)(unsigned long)systab64->con_out;
-               efi_systab.stderr_handle        = systab64->stderr_handle;
-               efi_systab.stderr               = systab64->stderr;
-               efi_systab.runtime              = (void *)(unsigned long)systab64->runtime;
-               efi_systab.boottime             = (void *)(unsigned long)systab64->boottime;
-               efi_systab.nr_tables            = systab64->nr_tables;
-               efi_systab.tables               = systab64->tables;
-
-               over4g = systab64->con_in_handle        > U32_MAX ||
-                        systab64->con_in               > U32_MAX ||
-                        systab64->con_out_handle       > U32_MAX ||
-                        systab64->con_out              > U32_MAX ||
-                        systab64->stderr_handle        > U32_MAX ||
-                        systab64->stderr               > U32_MAX ||
-                        systab64->boottime             > U32_MAX;
+               efi_runtime     = systab64->runtime;
+               over4g          = systab64->runtime > U32_MAX;
 
                if (efi_setup) {
                        struct efi_setup_data *data;
@@ -380,38 +373,33 @@ static int __init efi_systab_init(u64 phys)
                                return -ENOMEM;
                        }
 
-                       efi_systab.fw_vendor    = (unsigned long)data->fw_vendor;
-                       efi_systab.runtime      = (void *)(unsigned long)data->runtime;
-                       efi_systab.tables       = (unsigned long)data->tables;
+                       efi_fw_vendor           = (unsigned long)data->fw_vendor;
+                       efi_config_table        = (unsigned long)data->tables;
 
                        over4g |= data->fw_vendor       > U32_MAX ||
-                                 data->runtime         > U32_MAX ||
                                  data->tables          > U32_MAX;
 
                        early_memunmap(data, sizeof(*data));
                } else {
+                       efi_fw_vendor           = systab64->fw_vendor;
+                       efi_config_table        = systab64->tables;
+
                        over4g |= systab64->fw_vendor   > U32_MAX ||
-                                 systab64->runtime     > U32_MAX ||
                                  systab64->tables      > U32_MAX;
                }
+               efi_nr_tables = systab64->nr_tables;
        } else {
                const efi_system_table_32_t *systab32 = p;
 
-               efi_systab.hdr                  = systab32->hdr;
-               efi_systab.fw_vendor            = systab32->fw_vendor;
-               efi_systab.fw_revision          = systab32->fw_revision;
-               efi_systab.con_in_handle        = systab32->con_in_handle;
-               efi_systab.con_in               = systab32->con_in;
-               efi_systab.con_out_handle       = systab32->con_out_handle;
-               efi_systab.con_out              = (void *)(unsigned long)systab32->con_out;
-               efi_systab.stderr_handle        = systab32->stderr_handle;
-               efi_systab.stderr               = systab32->stderr;
-               efi_systab.runtime              = (void *)(unsigned long)systab32->runtime;
-               efi_systab.boottime             = (void *)(unsigned long)systab32->boottime;
-               efi_systab.nr_tables            = systab32->nr_tables;
-               efi_systab.tables               = systab32->tables;
+               efi_fw_vendor           = systab32->fw_vendor;
+               efi_runtime             = systab32->runtime;
+               efi_config_table        = systab32->tables;
+               efi_nr_tables           = systab32->nr_tables;
        }
 
+       efi.runtime_version = hdr->revision;
+
+       efi_systab_report_header(hdr, efi_fw_vendor);
        early_memunmap(p, size);
 
        if (IS_ENABLED(CONFIG_X86_32) && over4g) {
@@ -419,29 +407,40 @@ static int __init efi_systab_init(u64 phys)
                return -EINVAL;
        }
 
-       efi.systab = &efi_systab;
+       return 0;
+}
+
+static int __init efi_config_init(const efi_config_table_type_t *arch_tables)
+{
+       void *config_tables;
+       int sz, ret;
+
+       if (efi_nr_tables == 0)
+               return 0;
+
+       if (efi_enabled(EFI_64BIT))
+               sz = sizeof(efi_config_table_64_t);
+       else
+               sz = sizeof(efi_config_table_32_t);
 
        /*
-        * Verify the EFI Table
+        * Let's see what config tables the firmware passed to us.
         */
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
-               pr_err("System table signature incorrect!\n");
-               return -EINVAL;
+       config_tables = early_memremap(efi_config_table, efi_nr_tables * sz);
+       if (config_tables == NULL) {
+               pr_err("Could not map Configuration table!\n");
+               return -ENOMEM;
        }
-       if ((efi.systab->hdr.revision >> 16) == 0)
-               pr_err("Warning: System table version %d.%02d, expected 1.00 or greater!\n",
-                      efi.systab->hdr.revision >> 16,
-                      efi.systab->hdr.revision & 0xffff);
 
-       return 0;
+       ret = efi_config_parse_tables(config_tables, efi_nr_tables,
+                                     arch_tables);
+
+       early_memunmap(config_tables, efi_nr_tables * sz);
+       return ret;
 }
 
 void __init efi_init(void)
 {
-       efi_char16_t *c16;
-       char vendor[100] = "unknown";
-       int i = 0;
-
        if (IS_ENABLED(CONFIG_X86_32) &&
            (boot_params.efi_info.efi_systab_hi ||
             boot_params.efi_info.efi_memmap_hi)) {
@@ -455,29 +454,7 @@ void __init efi_init(void)
        if (efi_systab_init(efi_systab_phys))
                return;
 
-       efi.config_table = (unsigned long)efi.systab->tables;
-       efi.fw_vendor    = (unsigned long)efi.systab->fw_vendor;
-       efi.runtime      = (unsigned long)efi.systab->runtime;
-
-       /*
-        * Show what we know for posterity
-        */
-       c16 = early_memremap_ro(efi.systab->fw_vendor,
-                               sizeof(vendor) * sizeof(efi_char16_t));
-       if (c16) {
-               for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
-                       vendor[i] = c16[i];
-               vendor[i] = '\0';
-               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
-       } else {
-               pr_err("Could not map the firmware vendor!\n");
-       }
-
-       pr_info("EFI v%u.%.02u by %s\n",
-               efi.systab->hdr.revision >> 16,
-               efi.systab->hdr.revision & 0xffff, vendor);
-
-       if (efi_reuse_config(efi.systab->tables, efi.systab->nr_tables))
+       if (efi_reuse_config(efi_config_table, efi_nr_tables))
                return;
 
        if (efi_config_init(arch_tables))
@@ -496,6 +473,22 @@ void __init efi_init(void)
                return;
        }
 
+       /* Parse the EFI Properties table if it exists */
+       if (prop_phys != EFI_INVALID_TABLE_ADDR) {
+               efi_properties_table_t *tbl;
+
+               tbl = early_memremap_ro(prop_phys, sizeof(*tbl));
+               if (tbl == NULL) {
+                       pr_err("Could not map Properties table!\n");
+               } else {
+                       if (tbl->memory_protection_attribute &
+                           EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
+                               set_bit(EFI_NX_PE_DATA, &efi.flags);
+
+                       early_memunmap(tbl, sizeof(*tbl));
+               }
+       }
+
        set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
        efi_clean_memmap();
 
@@ -602,20 +595,6 @@ static void __init efi_merge_regions(void)
        }
 }
 
-static void __init get_systab_virt_addr(efi_memory_desc_t *md)
-{
-       unsigned long size;
-       u64 end, systab;
-
-       size = md->num_pages << EFI_PAGE_SHIFT;
-       end = md->phys_addr + size;
-       systab = efi_systab_phys;
-       if (md->phys_addr <= systab && systab < end) {
-               systab += md->virt_addr - md->phys_addr;
-               efi.systab = (efi_system_table_t *)(unsigned long)systab;
-       }
-}
-
 static void *realloc_pages(void *old_memmap, int old_shift)
 {
        void *ret;
@@ -771,7 +750,6 @@ static void * __init efi_map_regions(int *count, int *pg_shift)
                        continue;
 
                efi_map_region(md);
-               get_systab_virt_addr(md);
 
                if (left < desc_size) {
                        new_memmap = realloc_pages(new_memmap, *pg_shift);
@@ -797,8 +775,6 @@ static void __init kexec_enter_virtual_mode(void)
        efi_memory_desc_t *md;
        unsigned int num_pages;
 
-       efi.systab = NULL;
-
        /*
         * We don't do virtual mode, since we don't do runtime services, on
         * non-native EFI. With the UV1 memmap, we don't do runtime services in
@@ -821,10 +797,8 @@ static void __init kexec_enter_virtual_mode(void)
        * Map efi regions which were passed via setup_data. The virt_addr is a
        * fixed addr which was used in first kernel of a kexec boot.
        */
-       for_each_efi_memory_desc(md) {
+       for_each_efi_memory_desc(md)
                efi_map_region_fixed(md); /* FIXME: add error handling */
-               get_systab_virt_addr(md);
-       }
 
        /*
         * Unregister the early EFI memmap from efi_init() and install
@@ -839,8 +813,6 @@ static void __init kexec_enter_virtual_mode(void)
                return;
        }
 
-       BUG_ON(!efi.systab);
-
        num_pages = ALIGN(efi.memmap.nr_map * efi.memmap.desc_size, PAGE_SIZE);
        num_pages >>= PAGE_SHIFT;
 
@@ -850,15 +822,6 @@ static void __init kexec_enter_virtual_mode(void)
        }
 
        efi_sync_low_kernel_mappings();
-
-       /*
-        * Now that EFI is in virtual mode, update the function
-        * pointers in the runtime service table to the new virtual addresses.
-        *
-        * Call EFI services through wrapper functions.
-        */
-       efi.runtime_version = efi_systab.hdr.revision;
-
        efi_native_runtime_setup();
 #endif
 }
@@ -892,8 +855,6 @@ static void __init __efi_enter_virtual_mode(void)
        efi_status_t status;
        unsigned long pa;
 
-       efi.systab = NULL;
-
        if (efi_alloc_page_tables()) {
                pr_err("Failed to allocate EFI page tables\n");
                goto err;
@@ -925,9 +886,6 @@ static void __init __efi_enter_virtual_mode(void)
                efi_print_memmap();
        }
 
-       if (WARN_ON(!efi.systab))
-               goto err;
-
        if (efi_setup_page_tables(pa, 1 << pg_shift))
                goto err;
 
@@ -936,23 +894,17 @@ static void __init __efi_enter_virtual_mode(void)
        status = efi_set_virtual_address_map(efi.memmap.desc_size * count,
                                             efi.memmap.desc_size,
                                             efi.memmap.desc_version,
-                                            (efi_memory_desc_t *)pa);
+                                            (efi_memory_desc_t *)pa,
+                                            efi_systab_phys);
        if (status != EFI_SUCCESS) {
                pr_err("Unable to switch EFI into virtual mode (status=%lx)!\n",
                       status);
                goto err;
        }
 
+       efi_check_for_embedded_firmwares();
        efi_free_boot_services();
 
-       /*
-        * Now that EFI is in virtual mode, update the function
-        * pointers in the runtime service table to the new virtual addresses.
-        *
-        * Call EFI services through wrapper functions.
-        */
-       efi.runtime_version = efi_systab.hdr.revision;
-
        if (!efi_is_mixed())
                efi_native_runtime_setup();
        else
@@ -978,6 +930,8 @@ void __init efi_enter_virtual_mode(void)
        if (efi_enabled(EFI_PARAVIRT))
                return;
 
+       efi.runtime = (efi_runtime_services_t *)efi_runtime;
+
        if (efi_setup)
                kexec_enter_virtual_mode();
        else
@@ -999,3 +953,43 @@ bool efi_is_table_address(unsigned long phys_addr)
 
        return false;
 }
+
+char *efi_systab_show_arch(char *str)
+{
+       if (uga_phys != EFI_INVALID_TABLE_ADDR)
+               str += sprintf(str, "UGA=0x%lx\n", uga_phys);
+       return str;
+}
+
+#define EFI_FIELD(var) efi_ ## var
+
+#define EFI_ATTR_SHOW(name) \
+static ssize_t name##_show(struct kobject *kobj, \
+                               struct kobj_attribute *attr, char *buf) \
+{ \
+       return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
+}
+
+EFI_ATTR_SHOW(fw_vendor);
+EFI_ATTR_SHOW(runtime);
+EFI_ATTR_SHOW(config_table);
+
+struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
+struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
+struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
+
+umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
+{
+       if (attr == &efi_attr_fw_vendor.attr) {
+               if (efi_enabled(EFI_PARAVIRT) ||
+                               efi_fw_vendor == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       } else if (attr == &efi_attr_runtime.attr) {
+               if (efi_runtime == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       } else if (attr == &efi_attr_config_table.attr) {
+               if (efi_config_table == EFI_INVALID_TABLE_ADDR)
+                       return 0;
+       }
+       return attr->mode;
+}
index 081d466..c049c43 100644 (file)
@@ -66,14 +66,16 @@ void __init efi_map_region(efi_memory_desc_t *md)
 void __init efi_map_region_fixed(efi_memory_desc_t *md) {}
 void __init parse_efi_setup(u64 phys_addr, u32 data_len) {}
 
-efi_status_t efi_call_svam(efi_set_virtual_address_map_t *__efiapi *,
-                          u32, u32, u32, void *);
+efi_status_t efi_call_svam(efi_runtime_services_t * const *,
+                          u32, u32, u32, void *, u32);
 
 efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
                                                unsigned long descriptor_size,
                                                u32 descriptor_version,
-                                               efi_memory_desc_t *virtual_map)
+                                               efi_memory_desc_t *virtual_map,
+                                               unsigned long systab_phys)
 {
+       const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
        struct desc_ptr gdt_descr;
        efi_status_t status;
        unsigned long flags;
@@ -90,9 +92,10 @@ efi_status_t __init efi_set_virtual_address_map(unsigned long memory_map_size,
 
        /* Disable interrupts around EFI calls: */
        local_irq_save(flags);
-       status = efi_call_svam(&efi.systab->runtime->set_virtual_address_map,
+       status = efi_call_svam(&systab->runtime,
                               memory_map_size, descriptor_size,
-                              descriptor_version, virtual_map);
+                              descriptor_version, virtual_map,
+                              __pa(&efi.runtime));
        local_irq_restore(flags);
 
        load_fixmap_gdt(0);
index fa8506e..211bb93 100644 (file)
@@ -180,7 +180,7 @@ void efi_sync_low_kernel_mappings(void)
 static inline phys_addr_t
 virt_to_phys_or_null_size(void *va, unsigned long size)
 {
-       bool bad_size;
+       phys_addr_t pa;
 
        if (!va)
                return 0;
@@ -188,16 +188,13 @@ virt_to_phys_or_null_size(void *va, unsigned long size)
        if (virt_addr_valid(va))
                return virt_to_phys(va);
 
-       /*
-        * A fully aligned variable on the stack is guaranteed not to
-        * cross a page bounary. Try to catch strings on the stack by
-        * checking that 'size' is a power of two.
-        */
-       bad_size = size > PAGE_SIZE || !is_power_of_2(size);
+       pa = slow_virt_to_phys(va);
 
-       WARN_ON(!IS_ALIGNED((unsigned long)va, size) || bad_size);
+       /* check if the object crosses a page boundary */
+       if (WARN_ON((pa ^ (pa + size - 1)) & PAGE_MASK))
+               return 0;
 
-       return slow_virt_to_phys(va);
+       return pa;
 }
 
 #define virt_to_phys_or_null(addr)                             \
@@ -500,12 +497,9 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
  */
 #define __efi_thunk(func, ...)                                         \
 ({                                                                     \
-       efi_runtime_services_32_t *__rt;                                \
        unsigned short __ds, __es;                                      \
        efi_status_t ____s;                                             \
                                                                        \
-       __rt = (void *)(unsigned long)efi.systab->mixed_mode.runtime;   \
-                                                                       \
        savesegment(ds, __ds);                                          \
        savesegment(es, __es);                                          \
                                                                        \
@@ -513,7 +507,7 @@ static DEFINE_SPINLOCK(efi_runtime_lock);
        loadsegment(ds, __KERNEL_DS);                                   \
        loadsegment(es, __KERNEL_DS);                                   \
                                                                        \
-       ____s = efi64_thunk(__rt->func, __VA_ARGS__);                   \
+       ____s = efi64_thunk(efi.runtime->mixed_mode.func, __VA_ARGS__); \
                                                                        \
        loadsegment(ds, __ds);                                          \
        loadsegment(es, __es);                                          \
@@ -568,85 +562,25 @@ efi_thunk_set_virtual_address_map(unsigned long memory_map_size,
 
 static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)
 {
-       efi_status_t status;
-       u32 phys_tm, phys_tc;
-       unsigned long flags;
-
-       spin_lock(&rtc_lock);
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_tm = virt_to_phys_or_null(tm);
-       phys_tc = virt_to_phys_or_null(tc);
-
-       status = efi_thunk(get_time, phys_tm, phys_tc);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-       spin_unlock(&rtc_lock);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static efi_status_t efi_thunk_set_time(efi_time_t *tm)
 {
-       efi_status_t status;
-       u32 phys_tm;
-       unsigned long flags;
-
-       spin_lock(&rtc_lock);
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_tm = virt_to_phys_or_null(tm);
-
-       status = efi_thunk(set_time, phys_tm);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-       spin_unlock(&rtc_lock);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static efi_status_t
 efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,
                          efi_time_t *tm)
 {
-       efi_status_t status;
-       u32 phys_enabled, phys_pending, phys_tm;
-       unsigned long flags;
-
-       spin_lock(&rtc_lock);
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_enabled = virt_to_phys_or_null(enabled);
-       phys_pending = virt_to_phys_or_null(pending);
-       phys_tm = virt_to_phys_or_null(tm);
-
-       status = efi_thunk(get_wakeup_time, phys_enabled,
-                            phys_pending, phys_tm);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-       spin_unlock(&rtc_lock);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static efi_status_t
 efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
 {
-       efi_status_t status;
-       u32 phys_tm;
-       unsigned long flags;
-
-       spin_lock(&rtc_lock);
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_tm = virt_to_phys_or_null(tm);
-
-       status = efi_thunk(set_wakeup_time, enabled, phys_tm);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-       spin_unlock(&rtc_lock);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static unsigned long efi_name_size(efi_char16_t *name)
@@ -658,6 +592,8 @@ static efi_status_t
 efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
                       u32 *attr, unsigned long *data_size, void *data)
 {
+       u8 buf[24] __aligned(8);
+       efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
        efi_status_t status;
        u32 phys_name, phys_vendor, phys_attr;
        u32 phys_data_size, phys_data;
@@ -665,14 +601,19 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,
 
        spin_lock_irqsave(&efi_runtime_lock, flags);
 
+       *vnd = *vendor;
+
        phys_data_size = virt_to_phys_or_null(data_size);
-       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_vendor = virt_to_phys_or_null(vnd);
        phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
        phys_attr = virt_to_phys_or_null(attr);
        phys_data = virt_to_phys_or_null_size(data, *data_size);
 
-       status = efi_thunk(get_variable, phys_name, phys_vendor,
-                          phys_attr, phys_data_size, phys_data);
+       if (!phys_name || (data && !phys_data))
+               status = EFI_INVALID_PARAMETER;
+       else
+               status = efi_thunk(get_variable, phys_name, phys_vendor,
+                                  phys_attr, phys_data_size, phys_data);
 
        spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -683,19 +624,25 @@ static efi_status_t
 efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,
                       u32 attr, unsigned long data_size, void *data)
 {
+       u8 buf[24] __aligned(8);
+       efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
        u32 phys_name, phys_vendor, phys_data;
        efi_status_t status;
        unsigned long flags;
 
        spin_lock_irqsave(&efi_runtime_lock, flags);
 
+       *vnd = *vendor;
+
        phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
-       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_vendor = virt_to_phys_or_null(vnd);
        phys_data = virt_to_phys_or_null_size(data, data_size);
 
-       /* If data_size is > sizeof(u32) we've got problems */
-       status = efi_thunk(set_variable, phys_name, phys_vendor,
-                          attr, data_size, phys_data);
+       if (!phys_name || !phys_data)
+               status = EFI_INVALID_PARAMETER;
+       else
+               status = efi_thunk(set_variable, phys_name, phys_vendor,
+                                  attr, data_size, phys_data);
 
        spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -707,6 +654,8 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
                                   u32 attr, unsigned long data_size,
                                   void *data)
 {
+       u8 buf[24] __aligned(8);
+       efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
        u32 phys_name, phys_vendor, phys_data;
        efi_status_t status;
        unsigned long flags;
@@ -714,13 +663,17 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
        if (!spin_trylock_irqsave(&efi_runtime_lock, flags))
                return EFI_NOT_READY;
 
+       *vnd = *vendor;
+
        phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));
-       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_vendor = virt_to_phys_or_null(vnd);
        phys_data = virt_to_phys_or_null_size(data, data_size);
 
-       /* If data_size is > sizeof(u32) we've got problems */
-       status = efi_thunk(set_variable, phys_name, phys_vendor,
-                          attr, data_size, phys_data);
+       if (!phys_name || !phys_data)
+               status = EFI_INVALID_PARAMETER;
+       else
+               status = efi_thunk(set_variable, phys_name, phys_vendor,
+                                  attr, data_size, phys_data);
 
        spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
@@ -732,39 +685,36 @@ efi_thunk_get_next_variable(unsigned long *name_size,
                            efi_char16_t *name,
                            efi_guid_t *vendor)
 {
+       u8 buf[24] __aligned(8);
+       efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));
        efi_status_t status;
        u32 phys_name_size, phys_name, phys_vendor;
        unsigned long flags;
 
        spin_lock_irqsave(&efi_runtime_lock, flags);
 
+       *vnd = *vendor;
+
        phys_name_size = virt_to_phys_or_null(name_size);
-       phys_vendor = virt_to_phys_or_null(vendor);
+       phys_vendor = virt_to_phys_or_null(vnd);
        phys_name = virt_to_phys_or_null_size(name, *name_size);
 
-       status = efi_thunk(get_next_variable, phys_name_size,
-                          phys_name, phys_vendor);
+       if (!phys_name)
+               status = EFI_INVALID_PARAMETER;
+       else
+               status = efi_thunk(get_next_variable, phys_name_size,
+                                  phys_name, phys_vendor);
 
        spin_unlock_irqrestore(&efi_runtime_lock, flags);
 
+       *vendor = *vnd;
        return status;
 }
 
 static efi_status_t
 efi_thunk_get_next_high_mono_count(u32 *count)
 {
-       efi_status_t status;
-       u32 phys_count;
-       unsigned long flags;
-
-       spin_lock_irqsave(&efi_runtime_lock, flags);
-
-       phys_count = virt_to_phys_or_null(count);
-       status = efi_thunk(get_next_high_mono_count, phys_count);
-
-       spin_unlock_irqrestore(&efi_runtime_lock, flags);
-
-       return status;
+       return EFI_UNSUPPORTED;
 }
 
 static void
@@ -886,8 +836,10 @@ efi_status_t __init __no_sanitize_address
 efi_set_virtual_address_map(unsigned long memory_map_size,
                            unsigned long descriptor_size,
                            u32 descriptor_version,
-                           efi_memory_desc_t *virtual_map)
+                           efi_memory_desc_t *virtual_map,
+                           unsigned long systab_phys)
 {
+       const efi_system_table_t *systab = (efi_system_table_t *)systab_phys;
        efi_status_t status;
        unsigned long flags;
        pgd_t *save_pgd = NULL;
@@ -910,13 +862,16 @@ efi_set_virtual_address_map(unsigned long memory_map_size,
 
        /* Disable interrupts around EFI calls: */
        local_irq_save(flags);
-       status = efi_call(efi.systab->runtime->set_virtual_address_map,
+       status = efi_call(efi.runtime->set_virtual_address_map,
                          memory_map_size, descriptor_size,
                          descriptor_version, virtual_map);
        local_irq_restore(flags);
 
        kernel_fpu_end();
 
+       /* grab the virtually remapped EFI runtime services table pointer */
+       efi.runtime = READ_ONCE(systab->runtime);
+
        if (save_pgd)
                efi_uv1_memmap_phys_epilog(save_pgd);
        else
index 75c46e7..09ec84f 100644 (file)
@@ -8,14 +8,20 @@
 
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <asm/asm-offsets.h>
 #include <asm/page_types.h>
 
        __INIT
 SYM_FUNC_START(efi_call_svam)
-       push    8(%esp)
-       push    8(%esp)
+       push    %ebp
+       movl    %esp, %ebp
+       push    %ebx
+
+       push    16(%esp)
+       push    16(%esp)
        push    %ecx
        push    %edx
+       movl    %eax, %ebx              // &systab_phys->runtime
 
        /*
         * Switch to the flat mapped alias of this routine, by jumping to the
@@ -35,15 +41,20 @@ SYM_FUNC_START(efi_call_svam)
        subl    $__PAGE_OFFSET, %esp
 
        /* call the EFI routine */
-       call    *(%eax)
+       movl    (%eax), %eax
+       call    *EFI_svam(%eax)
 
-       /* convert ESP back to a kernel VA, and pop the outgoing args */
-       addl    $__PAGE_OFFSET + 16, %esp
+       /* grab the virtually remapped EFI runtime services table pointer */
+       movl    (%ebx), %ecx
+       movl    36(%esp), %edx          // &efi.runtime
+       movl    %ecx, (%edx)
 
        /* re-enable paging */
        movl    %cr0, %edx
        orl     $0x80000000, %edx
        movl    %edx, %cr0
 
+       movl    16(%esp), %ebx
+       leave
        ret
 SYM_FUNC_END(efi_call_svam)
index 88d32c0..a5a469c 100644 (file)
@@ -410,6 +410,10 @@ void __init efi_free_boot_services(void)
        int num_entries = 0;
        void *new, *new_md;
 
+       /* Keep all regions for /sys/kernel/debug/efi */
+       if (efi_enabled(EFI_DBG))
+               return;
+
        for_each_efi_memory_desc(md) {
                unsigned long long start = md->phys_addr;
                unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -537,7 +541,7 @@ int __init efi_reuse_config(u64 tables, int nr_tables)
                goto out_memremap;
        }
 
-       for (i = 0; i < efi.systab->nr_tables; i++) {
+       for (i = 0; i < nr_tables; i++) {
                efi_guid_t guid;
 
                guid = ((efi_config_table_64_t *)p)->guid;
@@ -659,12 +663,9 @@ static int qrk_capsule_setup_info(struct capsule_info *cap_info, void **pkbuff,
        return 1;
 }
 
-#define ICPU(family, model, quirk_handler) \
-       { X86_VENDOR_INTEL, family, model, X86_FEATURE_ANY, \
-         (unsigned long)&quirk_handler }
-
 static const struct x86_cpu_id efi_capsule_quirk_ids[] = {
-       ICPU(5, 9, qrk_capsule_setup_info),     /* Intel Quark X1000 */
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000,
+                                  &qrk_capsule_setup_info),
        { }
 };
 
index e3f4bfc..31dda18 100644 (file)
@@ -60,11 +60,8 @@ static struct bt_sfi_data tng_bt_sfi_data __initdata = {
        .setup  = tng_bt_sfi_setup,
 };
 
-#define ICPU(model, ddata)     \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata }
-
 static const struct x86_cpu_id bt_sfi_cpu_ids[] = {
-       ICPU(INTEL_FAM6_ATOM_SILVERMONT_MID, tng_bt_sfi_data),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &tng_bt_sfi_data),
        {}
 };
 
index e9d97d5..0286fe1 100644 (file)
@@ -569,7 +569,7 @@ static void __init imr_fixup_memmap(struct imr_device *idev)
 }
 
 static const struct x86_cpu_id imr_ids[] __initconst = {
-       { X86_VENDOR_INTEL, 5, 9 },     /* Intel Quark SoC X1000. */
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL),
        {}
 };
 
index 4307830..570e306 100644 (file)
@@ -105,7 +105,7 @@ static void __init imr_self_test(void)
 }
 
 static const struct x86_cpu_id imr_ids[] __initconst = {
-       { X86_VENDOR_INTEL, 5, 9 },     /* Intel Quark SoC X1000. */
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL),
        {}
 };
 
index 9e24445..526f70f 100644 (file)
@@ -265,7 +265,7 @@ static void iosf_mbi_reset_semaphore(void)
                            iosf_mbi_sem_address, 0, PUNIT_SEMAPHORE_BIT))
                dev_err(&mbi_pdev->dev, "Error P-Unit semaphore reset failed\n");
 
-       pm_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_update_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
 
        blocking_notifier_call_chain(&iosf_mbi_pmic_bus_access_notifier,
                                     MBI_PMIC_BUS_ACCESS_END, NULL);
@@ -301,8 +301,8 @@ static void iosf_mbi_reset_semaphore(void)
  * 4) When CPU cores enter C6 or C7 the P-Unit needs to talk to the PMIC
  *    if this happens while the kernel itself is accessing the PMIC I2C bus
  *    the SoC hangs.
- *    As the third step we call pm_qos_update_request() to disallow the CPU
- *    to enter C6 or C7.
+ *    As the third step we call cpu_latency_qos_update_request() to disallow the
+ *    CPU to enter C6 or C7.
  *
  * 5) The P-Unit has a PMIC bus semaphore which we can request to stop
  *    autonomous P-Unit tasks from accessing the PMIC I2C bus while we hold it.
@@ -338,7 +338,7 @@ int iosf_mbi_block_punit_i2c_access(void)
         * requires the P-Unit to talk to the PMIC and if this happens while
         * we're holding the semaphore, the SoC hangs.
         */
-       pm_qos_update_request(&iosf_mbi_pm_qos, 0);
+       cpu_latency_qos_update_request(&iosf_mbi_pm_qos, 0);
 
        /* host driver writes to side band semaphore register */
        ret = iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE,
@@ -547,8 +547,7 @@ static int __init iosf_mbi_init(void)
 {
        iosf_debugfs_init();
 
-       pm_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_CPU_DMA_LATENCY,
-                          PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_add_request(&iosf_mbi_pm_qos, PM_QOS_DEFAULT_VALUE);
 
        return pci_register_driver(&iosf_mbi_pci_driver);
 }
@@ -561,7 +560,7 @@ static void __exit iosf_mbi_exit(void)
        pci_dev_put(mbi_pdev);
        mbi_pdev = NULL;
 
-       pm_qos_remove_request(&iosf_mbi_pm_qos);
+       cpu_latency_qos_remove_request(&iosf_mbi_pm_qos);
 }
 
 module_init(iosf_mbi_init);
index 915bb16..aaff9ed 100644 (file)
@@ -475,20 +475,8 @@ static int msr_save_cpuid_features(const struct x86_cpu_id *c)
 }
 
 static const struct x86_cpu_id msr_save_cpu_table[] = {
-       {
-               .vendor = X86_VENDOR_AMD,
-               .family = 0x15,
-               .model = X86_MODEL_ANY,
-               .feature = X86_FEATURE_ANY,
-               .driver_data = (kernel_ulong_t)msr_save_cpuid_features,
-       },
-       {
-               .vendor = X86_VENDOR_AMD,
-               .family = 0x16,
-               .model = X86_MODEL_ANY,
-               .feature = X86_FEATURE_ANY,
-               .driver_data = (kernel_ulong_t)msr_save_cpuid_features,
-       },
+       X86_MATCH_VENDOR_FAM(AMD, 0x15, &msr_save_cpuid_features),
+       X86_MATCH_VENDOR_FAM(AMD, 0x16, &msr_save_cpuid_features),
        {}
 };
 
index 99b6332..b11ec5d 100644 (file)
@@ -71,5 +71,6 @@ $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
 KBUILD_CFLAGS  := $(REALMODE_CFLAGS) -D_SETUP -D_WAKEUP \
                   -I$(srctree)/arch/x86/boot
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
+KBUILD_CFLAGS  += -fno-asynchronous-unwind-tables
 GCOV_PROFILE := n
 UBSAN_SANITIZE := n
index 64d135d..63aa518 100644 (file)
@@ -71,7 +71,6 @@ SECTIONS
        /DISCARD/ : {
                *(.note*)
                *(.debug*)
-               *(.eh_frame*)
        }
 
 #include "pasyms.h"
index 33c51c0..77f70b9 100644 (file)
@@ -21,6 +21,7 @@ obj-y += checksum_32.o syscalls_32.o
 obj-$(CONFIG_ELF_CORE) += elfcore.o
 
 subarch-y = ../lib/string_32.o ../lib/atomic64_32.o ../lib/atomic64_cx8_32.o
+subarch-y += ../kernel/sys_ia32.o
 
 else
 
index 9649b5a..2ed81e5 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
-#include <generated/user_constants.h>
+#include <asm/unistd.h>
 #include <asm/syscall.h>
 
 #define __NO_STUBS
 
 #define old_mmap sys_old_mmap
 
-#define __SYSCALL_I386(nr, sym, qual) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ;
+#define __SYSCALL_I386(nr, sym) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ;
 #include <asm/syscalls_32.h>
 
 #undef __SYSCALL_I386
-#define __SYSCALL_I386(nr, sym, qual) [ nr ] = sym,
+#define __SYSCALL_I386(nr, sym) [ nr ] = sym,
 
 extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 
index c8bc7fb..2e8544d 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/linkage.h>
 #include <linux/sys.h>
 #include <linux/cache.h>
-#include <generated/user_constants.h>
+#include <asm/unistd.h>
 #include <asm/syscall.h>
 
 #define __NO_STUBS
 #define stub_execveat sys_execveat
 #define stub_rt_sigreturn sys_rt_sigreturn
 
-#define __SYSCALL_64(nr, sym, qual) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ;
+#define __SYSCALL_X32(nr, sym)
+#define __SYSCALL_COMMON(nr, sym) __SYSCALL_64(nr, sym)
+
+#define __SYSCALL_64(nr, sym) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long) ;
 #include <asm/syscalls_64.h>
 
 #undef __SYSCALL_64
-#define __SYSCALL_64(nr, sym, qual) [ nr ] = sym,
+#define __SYSCALL_64(nr, sym) [ nr ] = sym,
 
 extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
 
index 5b37b7f..c51dd83 100644 (file)
@@ -9,18 +9,6 @@
 #include <linux/ptrace.h>
 #include <asm/types.h>
 
-#ifdef __i386__
-#define __SYSCALL_I386(nr, sym, qual) [nr] = 1,
-static char syscalls[] = {
-#include <asm/syscalls_32.h>
-};
-#else
-#define __SYSCALL_64(nr, sym, qual) [nr] = 1,
-static char syscalls[] = {
-#include <asm/syscalls_64.h>
-};
-#endif
-
 #define DEFINE(sym, val) \
        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
 
@@ -94,7 +82,4 @@ void foo(void)
        DEFINE(UM_PROT_READ, PROT_READ);
        DEFINE(UM_PROT_WRITE, PROT_WRITE);
        DEFINE(UM_PROT_EXEC, PROT_EXEC);
-
-       DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
-       DEFINE(NR_syscalls, sizeof(syscalls));
 }
index 7940912..507f4fb 100644 (file)
@@ -72,6 +72,9 @@
 #include <asm/mwait.h>
 #include <asm/pci_x86.h>
 #include <asm/cpu.h>
+#ifdef CONFIG_X86_IOPL_IOPERM
+#include <asm/io_bitmap.h>
+#endif
 
 #ifdef CONFIG_ACPI
 #include <linux/acpi.h>
@@ -837,6 +840,25 @@ static void xen_load_sp0(unsigned long sp0)
        this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0);
 }
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+static void xen_update_io_bitmap(void)
+{
+       struct physdev_set_iobitmap iobitmap;
+       struct tss_struct *tss = this_cpu_ptr(&cpu_tss_rw);
+
+       native_tss_update_io_bitmap();
+
+       iobitmap.bitmap = (uint8_t *)(&tss->x86_tss) +
+                         tss->x86_tss.io_bitmap_base;
+       if (tss->x86_tss.io_bitmap_base == IO_BITMAP_OFFSET_INVALID)
+               iobitmap.nr_ports = 0;
+       else
+               iobitmap.nr_ports = IO_BITMAP_BITS;
+
+       HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &iobitmap);
+}
+#endif
+
 static void xen_io_delay(void)
 {
 }
@@ -1047,6 +1069,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
        .write_idt_entry = xen_write_idt_entry,
        .load_sp0 = xen_load_sp0,
 
+#ifdef CONFIG_X86_IOPL_IOPERM
+       .update_io_bitmap = xen_update_io_bitmap,
+#endif
        .io_delay = xen_io_delay,
 
        /* Xen takes care of %gs when switching to usermode for us */
index 7a43b2a..2097fa0 100644 (file)
@@ -132,7 +132,7 @@ void __init xen_smp_cpus_done(unsigned int max_cpus)
                if (xen_vcpu_nr(cpu) < MAX_VIRT_CPUS)
                        continue;
 
-               rc = cpu_down(cpu);
+               rc = remove_cpu(cpu);
 
                if (rc == 0) {
                        /*
index befbdd8..c8897aa 100644 (file)
@@ -145,12 +145,19 @@ static struct notifier_block xen_pvclock_gtod_notifier = {
        .notifier_call = xen_pvclock_gtod_notify,
 };
 
+static int xen_cs_enable(struct clocksource *cs)
+{
+       vclocks_set_used(VDSO_CLOCKMODE_PVCLOCK);
+       return 0;
+}
+
 static struct clocksource xen_clocksource __read_mostly = {
-       .name = "xen",
-       .rating = 400,
-       .read = xen_clocksource_get_cycles,
-       .mask = ~0,
-       .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+       .name   = "xen",
+       .rating = 400,
+       .read   = xen_clocksource_get_cycles,
+       .mask   = CLOCKSOURCE_MASK(64),
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .enable = xen_cs_enable,
 };
 
 /*
@@ -412,12 +419,13 @@ void xen_restore_time_memory_area(void)
        ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t);
 
        /*
-        * We don't disable VCLOCK_PVCLOCK entirely if it fails to register the
-        * secondary time info with Xen or if we migrated to a host without the
-        * necessary flags. On both of these cases what happens is either
-        * process seeing a zeroed out pvti or seeing no PVCLOCK_TSC_STABLE_BIT
-        * bit set. Userspace checks the latter and if 0, it discards the data
-        * in pvti and fallbacks to a system call for a reliable timestamp.
+        * We don't disable VDSO_CLOCKMODE_PVCLOCK entirely if it fails to
+        * register the secondary time info with Xen or if we migrated to a
+        * host without the necessary flags. On both of these cases what
+        * happens is either process seeing a zeroed out pvti or seeing no
+        * PVCLOCK_TSC_STABLE_BIT bit set. Userspace checks the latter and
+        * if 0, it discards the data in pvti and fallbacks to a system
+        * call for a reliable timestamp.
         */
        if (ret != 0)
                pr_notice("Cannot restore secondary vcpu_time_info (err %d)",
@@ -443,7 +451,7 @@ static void xen_setup_vsyscall_time_info(void)
 
        ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t);
        if (ret) {
-               pr_notice("xen: VCLOCK_PVCLOCK not supported (err %d)\n", ret);
+               pr_notice("xen: VDSO_CLOCKMODE_PVCLOCK not supported (err %d)\n", ret);
                free_page((unsigned long)ti);
                return;
        }
@@ -460,14 +468,14 @@ static void xen_setup_vsyscall_time_info(void)
                if (!ret)
                        free_page((unsigned long)ti);
 
-               pr_notice("xen: VCLOCK_PVCLOCK not supported (tsc unstable)\n");
+               pr_notice("xen: VDSO_CLOCKMODE_PVCLOCK not supported (tsc unstable)\n");
                return;
        }
 
        xen_clock = ti;
        pvclock_set_pvti_cpu0_va(xen_clock);
 
-       xen_clocksource.archdata.vclock_mode = VCLOCK_PVCLOCK;
+       xen_clocksource.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK;
 }
 
 static void __init xen_time_init(void)
index 9646110..a1a27b2 100644 (file)
@@ -72,7 +72,8 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
 #if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE
        int oldval = 0, ret;
 
-       pagefault_disable();
+       if (!access_ok(uaddr, sizeof(u32)))
+               return -EFAULT;
 
        switch (op) {
        case FUTEX_OP_SET:
@@ -99,8 +100,6 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
                ret = -ENOSYS;
        }
 
-       pagefault_enable();
-
        if (!ret)
                *oval = oldval;
 
index 8331098..49322b6 100644 (file)
@@ -267,13 +267,12 @@ static int __init simdisk_setup(struct simdisk *dev, int which,
        spin_lock_init(&dev->lock);
        dev->users = 0;
 
-       dev->queue = blk_alloc_queue(GFP_KERNEL);
+       dev->queue = blk_alloc_queue(simdisk_make_request, NUMA_NO_NODE);
        if (dev->queue == NULL) {
                pr_err("blk_alloc_queue failed\n");
                goto out_alloc_queue;
        }
 
-       blk_queue_make_request(dev->queue, simdisk_make_request);
        dev->queue->queuedata = dev;
 
        dev->gd = alloc_disk(SIMDISK_MINORS);
index 1a43750..206b96e 100644 (file)
@@ -8,8 +8,7 @@ obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-sysfs.o \
                        blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \
                        blk-lib.o blk-mq.o blk-mq-tag.o blk-stat.o \
                        blk-mq-sysfs.o blk-mq-cpumap.o blk-mq-sched.o ioctl.o \
-                       genhd.o partition-generic.o ioprio.o \
-                       badblocks.o partitions/ blk-rq-qos.o
+                       genhd.o ioprio.o badblocks.o partitions/ blk-rq-qos.o
 
 obj-$(CONFIG_BOUNCE)           += bounce.o
 obj-$(CONFIG_BLK_SCSI_REQUEST) += scsi_ioctl.o
index 09b69a3..68882b9 100644 (file)
@@ -610,12 +610,13 @@ struct bfq_group *bfq_find_set_group(struct bfq_data *bfqd,
         */
        entity = &bfqg->entity;
        for_each_entity(entity) {
-               bfqg = container_of(entity, struct bfq_group, entity);
-               if (bfqg != bfqd->root_group) {
-                       parent = bfqg_parent(bfqg);
+               struct bfq_group *curr_bfqg = container_of(entity,
+                                               struct bfq_group, entity);
+               if (curr_bfqg != bfqd->root_group) {
+                       parent = bfqg_parent(curr_bfqg);
                        if (!parent)
                                parent = bfqd->root_group;
-                       bfq_group_set_parent(bfqg, parent);
+                       bfq_group_set_parent(curr_bfqg, parent);
                }
        }
 
@@ -641,6 +642,12 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
 {
        struct bfq_entity *entity = &bfqq->entity;
 
+       /*
+        * Get extra reference to prevent bfqq from being freed in
+        * next possible expire or deactivate.
+        */
+       bfqq->ref++;
+
        /* If bfqq is empty, then bfq_bfqq_expire also invokes
         * bfq_del_bfqq_busy, thereby removing bfqq and its entity
         * from data structures related to current group. Otherwise we
@@ -651,12 +658,6 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
                bfq_bfqq_expire(bfqd, bfqd->in_service_queue,
                                false, BFQQE_PREEMPTED);
 
-       /*
-        * get extra reference to prevent bfqq from being freed in
-        * next possible deactivate
-        */
-       bfqq->ref++;
-
        if (bfq_bfqq_busy(bfqq))
                bfq_deactivate_bfqq(bfqd, bfqq, false, false);
        else if (entity->on_st_or_in_serv)
@@ -676,7 +677,7 @@ void bfq_bfqq_move(struct bfq_data *bfqd, struct bfq_queue *bfqq,
 
        if (!bfqd->in_service_queue && !bfqd->rq_in_driver)
                bfq_schedule_dispatch(bfqd);
-       /* release extra ref taken above */
+       /* release extra ref taken above, bfqq may happen to be freed now */
        bfq_put_queue(bfqq);
 }
 
@@ -713,10 +714,7 @@ static struct bfq_group *__bfq_bic_change_cgroup(struct bfq_data *bfqd,
 
                if (entity->sched_data != &bfqg->sched_data) {
                        bic_set_bfqq(bic, NULL, 0);
-                       bfq_log_bfqq(bfqd, async_bfqq,
-                                    "bic_change_group: %p %d",
-                                    async_bfqq, async_bfqq->ref);
-                       bfq_put_queue(async_bfqq);
+                       bfq_release_process_ref(bfqd, async_bfqq);
                }
        }
 
@@ -817,39 +815,53 @@ static void bfq_flush_idle_tree(struct bfq_service_tree *st)
 /**
  * bfq_reparent_leaf_entity - move leaf entity to the root_group.
  * @bfqd: the device data structure with the root group.
- * @entity: the entity to move.
+ * @entity: the entity to move, if entity is a leaf; or the parent entity
+ *         of an active leaf entity to move, if entity is not a leaf.
  */
 static void bfq_reparent_leaf_entity(struct bfq_data *bfqd,
-                                    struct bfq_entity *entity)
+                                    struct bfq_entity *entity,
+                                    int ioprio_class)
 {
-       struct bfq_queue *bfqq = bfq_entity_to_bfqq(entity);
+       struct bfq_queue *bfqq;
+       struct bfq_entity *child_entity = entity;
 
+       while (child_entity->my_sched_data) { /* leaf not reached yet */
+               struct bfq_sched_data *child_sd = child_entity->my_sched_data;
+               struct bfq_service_tree *child_st = child_sd->service_tree +
+                       ioprio_class;
+               struct rb_root *child_active = &child_st->active;
+
+               child_entity = bfq_entity_of(rb_first(child_active));
+
+               if (!child_entity)
+                       child_entity = child_sd->in_service_entity;
+       }
+
+       bfqq = bfq_entity_to_bfqq(child_entity);
        bfq_bfqq_move(bfqd, bfqq, bfqd->root_group);
 }
 
 /**
- * bfq_reparent_active_entities - move to the root group all active
- *                                entities.
+ * bfq_reparent_active_queues - move to the root group all active queues.
  * @bfqd: the device data structure with the root group.
  * @bfqg: the group to move from.
- * @st: the service tree with the entities.
+ * @st: the service tree to start the search from.
  */
-static void bfq_reparent_active_entities(struct bfq_data *bfqd,
-                                        struct bfq_group *bfqg,
-                                        struct bfq_service_tree *st)
+static void bfq_reparent_active_queues(struct bfq_data *bfqd,
+                                      struct bfq_group *bfqg,
+                                      struct bfq_service_tree *st,
+                                      int ioprio_class)
 {
        struct rb_root *active = &st->active;
-       struct bfq_entity *entity = NULL;
-
-       if (!RB_EMPTY_ROOT(&st->active))
-               entity = bfq_entity_of(rb_first(active));
+       struct bfq_entity *entity;
 
-       for (; entity ; entity = bfq_entity_of(rb_first(active)))
-               bfq_reparent_leaf_entity(bfqd, entity);
+       while ((entity = bfq_entity_of(rb_first(active))))
+               bfq_reparent_leaf_entity(bfqd, entity, ioprio_class);
 
        if (bfqg->sched_data.in_service_entity)
                bfq_reparent_leaf_entity(bfqd,
-                       bfqg->sched_data.in_service_entity);
+                                        bfqg->sched_data.in_service_entity,
+                                        ioprio_class);
 }
 
 /**
@@ -882,13 +894,6 @@ static void bfq_pd_offline(struct blkg_policy_data *pd)
                st = bfqg->sched_data.service_tree + i;
 
                /*
-                * The idle tree may still contain bfq_queues belonging
-                * to exited task because they never migrated to a different
-                * cgroup from the one being destroyed now.
-                */
-               bfq_flush_idle_tree(st);
-
-               /*
                 * It may happen that some queues are still active
                 * (busy) upon group destruction (if the corresponding
                 * processes have been forced to terminate). We move
@@ -900,7 +905,20 @@ static void bfq_pd_offline(struct blkg_policy_data *pd)
                 * There is no need to put the sync queues, as the
                 * scheduler has taken no reference.
                 */
-               bfq_reparent_active_entities(bfqd, bfqg, st);
+               bfq_reparent_active_queues(bfqd, bfqg, st, i);
+
+               /*
+                * The idle tree may still contain bfq_queues
+                * belonging to exited task because they never
+                * migrated to a different cgroup from the one being
+                * destroyed now. In addition, even
+                * bfq_reparent_active_queues() may happen to add some
+                * entities to the idle tree. It happens if, in some
+                * of the calls to bfq_bfqq_move() performed by
+                * bfq_reparent_active_queues(), the queue to move is
+                * empty and gets expired.
+                */
+               bfq_flush_idle_tree(st);
        }
 
        __bfq_deactivate_entity(entity, false);
index 8c436ab..78ba57e 100644 (file)
@@ -2716,8 +2716,6 @@ static void bfq_bfqq_save_state(struct bfq_queue *bfqq)
        }
 }
 
-
-static
 void bfq_release_process_ref(struct bfq_data *bfqd, struct bfq_queue *bfqq)
 {
        /*
@@ -6215,20 +6213,28 @@ static struct bfq_queue *bfq_init_rq(struct request *rq)
        return bfqq;
 }
 
-static void bfq_idle_slice_timer_body(struct bfq_queue *bfqq)
+static void
+bfq_idle_slice_timer_body(struct bfq_data *bfqd, struct bfq_queue *bfqq)
 {
-       struct bfq_data *bfqd = bfqq->bfqd;
        enum bfqq_expiration reason;
        unsigned long flags;
 
        spin_lock_irqsave(&bfqd->lock, flags);
-       bfq_clear_bfqq_wait_request(bfqq);
 
+       /*
+        * Considering that bfqq may be in race, we should firstly check
+        * whether bfqq is in service before doing something on it. If
+        * the bfqq in race is not in service, it has already been expired
+        * through __bfq_bfqq_expire func and its wait_request flags has
+        * been cleared in __bfq_bfqd_reset_in_service func.
+        */
        if (bfqq != bfqd->in_service_queue) {
                spin_unlock_irqrestore(&bfqd->lock, flags);
                return;
        }
 
+       bfq_clear_bfqq_wait_request(bfqq);
+
        if (bfq_bfqq_budget_timeout(bfqq))
                /*
                 * Also here the queue can be safely expired
@@ -6273,7 +6279,7 @@ static enum hrtimer_restart bfq_idle_slice_timer(struct hrtimer *timer)
         * early.
         */
        if (bfqq)
-               bfq_idle_slice_timer_body(bfqq);
+               bfq_idle_slice_timer_body(bfqd, bfqq);
 
        return HRTIMER_NORESTART;
 }
index d1233af..cd224aa 100644 (file)
@@ -955,6 +955,7 @@ void bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq,
                     bool compensate, enum bfqq_expiration reason);
 void bfq_put_queue(struct bfq_queue *bfqq);
 void bfq_end_wr_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg);
+void bfq_release_process_ref(struct bfq_data *bfqd, struct bfq_queue *bfqq);
 void bfq_schedule_dispatch(struct bfq_data *bfqd);
 void bfq_put_async_queues(struct bfq_data *bfqd, struct bfq_group *bfqg);
 
index 94d6972..21cbaa6 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/cgroup.h>
 #include <linux/blk-cgroup.h>
 #include <linux/highmem.h>
+#include <linux/sched/sysctl.h>
 
 #include <trace/events/block.h>
 #include "blk.h"
@@ -588,6 +589,49 @@ void bio_truncate(struct bio *bio, unsigned new_size)
 }
 
 /**
+ * guard_bio_eod - truncate a BIO to fit the block device
+ * @bio:       bio to truncate
+ *
+ * This allows us to do IO even on the odd last sectors of a device, even if the
+ * block size is some multiple of the physical sector size.
+ *
+ * We'll just truncate the bio to the size of the device, and clear the end of
+ * the buffer head manually.  Truly out-of-range accesses will turn into actual
+ * I/O errors, this only handles the "we need to be able to do I/O at the final
+ * sector" case.
+ */
+void guard_bio_eod(struct bio *bio)
+{
+       sector_t maxsector;
+       struct hd_struct *part;
+
+       rcu_read_lock();
+       part = __disk_get_part(bio->bi_disk, bio->bi_partno);
+       if (part)
+               maxsector = part_nr_sects_read(part);
+       else
+               maxsector = get_capacity(bio->bi_disk);
+       rcu_read_unlock();
+
+       if (!maxsector)
+               return;
+
+       /*
+        * If the *whole* IO is past the end of the device,
+        * let it through, and the IO layer will turn it into
+        * an EIO.
+        */
+       if (unlikely(bio->bi_iter.bi_sector >= maxsector))
+               return;
+
+       maxsector -= bio->bi_iter.bi_sector;
+       if (likely((bio->bi_iter.bi_size >> 9) <= maxsector))
+               return;
+
+       bio_truncate(bio, maxsector << 9);
+}
+
+/**
  * bio_put - release a reference to a bio
  * @bio:   bio to release reference to
  *
@@ -679,6 +723,12 @@ struct bio *bio_clone_fast(struct bio *bio, gfp_t gfp_mask, struct bio_set *bs)
 }
 EXPORT_SYMBOL(bio_clone_fast);
 
+const char *bio_devname(struct bio *bio, char *buf)
+{
+       return disk_name(bio->bi_disk, bio->bi_partno, buf);
+}
+EXPORT_SYMBOL(bio_devname);
+
 static inline bool page_is_mergeable(const struct bio_vec *bv,
                struct page *page, unsigned int len, unsigned int off,
                bool *same_page)
@@ -730,7 +780,7 @@ static bool bio_try_merge_pc_page(struct request_queue *q, struct bio *bio,
  *
  *     This should only be used by passthrough bios.
  */
-static int __bio_add_pc_page(struct request_queue *q, struct bio *bio,
+int __bio_add_pc_page(struct request_queue *q, struct bio *bio,
                struct page *page, unsigned int len, unsigned int offset,
                bool *same_page)
 {
@@ -1019,12 +1069,21 @@ static void submit_bio_wait_endio(struct bio *bio)
 int submit_bio_wait(struct bio *bio)
 {
        DECLARE_COMPLETION_ONSTACK_MAP(done, bio->bi_disk->lockdep_map);
+       unsigned long hang_check;
 
        bio->bi_private = &done;
        bio->bi_end_io = submit_bio_wait_endio;
        bio->bi_opf |= REQ_SYNC;
        submit_bio(bio);
-       wait_for_completion_io(&done);
+
+       /* Prevent hang_check timer from firing at us during very long I/O */
+       hang_check = sysctl_hung_task_timeout_secs;
+       if (hang_check)
+               while (!wait_for_completion_io_timeout(&done,
+                                       hang_check * (HZ/2)))
+                       ;
+       else
+               wait_for_completion_io(&done);
 
        return blk_status_to_errno(bio->bi_status);
 }
@@ -1135,90 +1194,6 @@ void bio_list_copy_data(struct bio *dst, struct bio *src)
 }
 EXPORT_SYMBOL(bio_list_copy_data);
 
-struct bio_map_data {
-       int is_our_pages;
-       struct iov_iter iter;
-       struct iovec iov[];
-};
-
-static struct bio_map_data *bio_alloc_map_data(struct iov_iter *data,
-                                              gfp_t gfp_mask)
-{
-       struct bio_map_data *bmd;
-       if (data->nr_segs > UIO_MAXIOV)
-               return NULL;
-
-       bmd = kmalloc(struct_size(bmd, iov, data->nr_segs), gfp_mask);
-       if (!bmd)
-               return NULL;
-       memcpy(bmd->iov, data->iov, sizeof(struct iovec) * data->nr_segs);
-       bmd->iter = *data;
-       bmd->iter.iov = bmd->iov;
-       return bmd;
-}
-
-/**
- * bio_copy_from_iter - copy all pages from iov_iter to bio
- * @bio: The &struct bio which describes the I/O as destination
- * @iter: iov_iter as source
- *
- * Copy all pages from iov_iter to bio.
- * Returns 0 on success, or error on failure.
- */
-static int bio_copy_from_iter(struct bio *bio, struct iov_iter *iter)
-{
-       struct bio_vec *bvec;
-       struct bvec_iter_all iter_all;
-
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               ssize_t ret;
-
-               ret = copy_page_from_iter(bvec->bv_page,
-                                         bvec->bv_offset,
-                                         bvec->bv_len,
-                                         iter);
-
-               if (!iov_iter_count(iter))
-                       break;
-
-               if (ret < bvec->bv_len)
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
-/**
- * bio_copy_to_iter - copy all pages from bio to iov_iter
- * @bio: The &struct bio which describes the I/O as source
- * @iter: iov_iter as destination
- *
- * Copy all pages from bio to iov_iter.
- * Returns 0 on success, or error on failure.
- */
-static int bio_copy_to_iter(struct bio *bio, struct iov_iter iter)
-{
-       struct bio_vec *bvec;
-       struct bvec_iter_all iter_all;
-
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               ssize_t ret;
-
-               ret = copy_page_to_iter(bvec->bv_page,
-                                       bvec->bv_offset,
-                                       bvec->bv_len,
-                                       &iter);
-
-               if (!iov_iter_count(&iter))
-                       break;
-
-               if (ret < bvec->bv_len)
-                       return -EFAULT;
-       }
-
-       return 0;
-}
-
 void bio_free_pages(struct bio *bio)
 {
        struct bio_vec *bvec;
@@ -1229,430 +1204,6 @@ void bio_free_pages(struct bio *bio)
 }
 EXPORT_SYMBOL(bio_free_pages);
 
-/**
- *     bio_uncopy_user -       finish previously mapped bio
- *     @bio: bio being terminated
- *
- *     Free pages allocated from bio_copy_user_iov() and write back data
- *     to user space in case of a read.
- */
-int bio_uncopy_user(struct bio *bio)
-{
-       struct bio_map_data *bmd = bio->bi_private;
-       int ret = 0;
-
-       if (!bio_flagged(bio, BIO_NULL_MAPPED)) {
-               /*
-                * if we're in a workqueue, the request is orphaned, so
-                * don't copy into a random user address space, just free
-                * and return -EINTR so user space doesn't expect any data.
-                */
-               if (!current->mm)
-                       ret = -EINTR;
-               else if (bio_data_dir(bio) == READ)
-                       ret = bio_copy_to_iter(bio, bmd->iter);
-               if (bmd->is_our_pages)
-                       bio_free_pages(bio);
-       }
-       kfree(bmd);
-       bio_put(bio);
-       return ret;
-}
-
-/**
- *     bio_copy_user_iov       -       copy user data to bio
- *     @q:             destination block queue
- *     @map_data:      pointer to the rq_map_data holding pages (if necessary)
- *     @iter:          iovec iterator
- *     @gfp_mask:      memory allocation flags
- *
- *     Prepares and returns a bio for indirect user io, bouncing data
- *     to/from kernel pages as necessary. Must be paired with
- *     call bio_uncopy_user() on io completion.
- */
-struct bio *bio_copy_user_iov(struct request_queue *q,
-                             struct rq_map_data *map_data,
-                             struct iov_iter *iter,
-                             gfp_t gfp_mask)
-{
-       struct bio_map_data *bmd;
-       struct page *page;
-       struct bio *bio;
-       int i = 0, ret;
-       int nr_pages;
-       unsigned int len = iter->count;
-       unsigned int offset = map_data ? offset_in_page(map_data->offset) : 0;
-
-       bmd = bio_alloc_map_data(iter, gfp_mask);
-       if (!bmd)
-               return ERR_PTR(-ENOMEM);
-
-       /*
-        * We need to do a deep copy of the iov_iter including the iovecs.
-        * The caller provided iov might point to an on-stack or otherwise
-        * shortlived one.
-        */
-       bmd->is_our_pages = map_data ? 0 : 1;
-
-       nr_pages = DIV_ROUND_UP(offset + len, PAGE_SIZE);
-       if (nr_pages > BIO_MAX_PAGES)
-               nr_pages = BIO_MAX_PAGES;
-
-       ret = -ENOMEM;
-       bio = bio_kmalloc(gfp_mask, nr_pages);
-       if (!bio)
-               goto out_bmd;
-
-       ret = 0;
-
-       if (map_data) {
-               nr_pages = 1 << map_data->page_order;
-               i = map_data->offset / PAGE_SIZE;
-       }
-       while (len) {
-               unsigned int bytes = PAGE_SIZE;
-
-               bytes -= offset;
-
-               if (bytes > len)
-                       bytes = len;
-
-               if (map_data) {
-                       if (i == map_data->nr_entries * nr_pages) {
-                               ret = -ENOMEM;
-                               break;
-                       }
-
-                       page = map_data->pages[i / nr_pages];
-                       page += (i % nr_pages);
-
-                       i++;
-               } else {
-                       page = alloc_page(q->bounce_gfp | gfp_mask);
-                       if (!page) {
-                               ret = -ENOMEM;
-                               break;
-                       }
-               }
-
-               if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) {
-                       if (!map_data)
-                               __free_page(page);
-                       break;
-               }
-
-               len -= bytes;
-               offset = 0;
-       }
-
-       if (ret)
-               goto cleanup;
-
-       if (map_data)
-               map_data->offset += bio->bi_iter.bi_size;
-
-       /*
-        * success
-        */
-       if ((iov_iter_rw(iter) == WRITE && (!map_data || !map_data->null_mapped)) ||
-           (map_data && map_data->from_user)) {
-               ret = bio_copy_from_iter(bio, iter);
-               if (ret)
-                       goto cleanup;
-       } else {
-               if (bmd->is_our_pages)
-                       zero_fill_bio(bio);
-               iov_iter_advance(iter, bio->bi_iter.bi_size);
-       }
-
-       bio->bi_private = bmd;
-       if (map_data && map_data->null_mapped)
-               bio_set_flag(bio, BIO_NULL_MAPPED);
-       return bio;
-cleanup:
-       if (!map_data)
-               bio_free_pages(bio);
-       bio_put(bio);
-out_bmd:
-       kfree(bmd);
-       return ERR_PTR(ret);
-}
-
-/**
- *     bio_map_user_iov - map user iovec into bio
- *     @q:             the struct request_queue for the bio
- *     @iter:          iovec iterator
- *     @gfp_mask:      memory allocation flags
- *
- *     Map the user space address into a bio suitable for io to a block
- *     device. Returns an error pointer in case of error.
- */
-struct bio *bio_map_user_iov(struct request_queue *q,
-                            struct iov_iter *iter,
-                            gfp_t gfp_mask)
-{
-       int j;
-       struct bio *bio;
-       int ret;
-
-       if (!iov_iter_count(iter))
-               return ERR_PTR(-EINVAL);
-
-       bio = bio_kmalloc(gfp_mask, iov_iter_npages(iter, BIO_MAX_PAGES));
-       if (!bio)
-               return ERR_PTR(-ENOMEM);
-
-       while (iov_iter_count(iter)) {
-               struct page **pages;
-               ssize_t bytes;
-               size_t offs, added = 0;
-               int npages;
-
-               bytes = iov_iter_get_pages_alloc(iter, &pages, LONG_MAX, &offs);
-               if (unlikely(bytes <= 0)) {
-                       ret = bytes ? bytes : -EFAULT;
-                       goto out_unmap;
-               }
-
-               npages = DIV_ROUND_UP(offs + bytes, PAGE_SIZE);
-
-               if (unlikely(offs & queue_dma_alignment(q))) {
-                       ret = -EINVAL;
-                       j = 0;
-               } else {
-                       for (j = 0; j < npages; j++) {
-                               struct page *page = pages[j];
-                               unsigned int n = PAGE_SIZE - offs;
-                               bool same_page = false;
-
-                               if (n > bytes)
-                                       n = bytes;
-
-                               if (!__bio_add_pc_page(q, bio, page, n, offs,
-                                               &same_page)) {
-                                       if (same_page)
-                                               put_page(page);
-                                       break;
-                               }
-
-                               added += n;
-                               bytes -= n;
-                               offs = 0;
-                       }
-                       iov_iter_advance(iter, added);
-               }
-               /*
-                * release the pages we didn't map into the bio, if any
-                */
-               while (j < npages)
-                       put_page(pages[j++]);
-               kvfree(pages);
-               /* couldn't stuff something into bio? */
-               if (bytes)
-                       break;
-       }
-
-       bio_set_flag(bio, BIO_USER_MAPPED);
-
-       /*
-        * subtle -- if bio_map_user_iov() ended up bouncing a bio,
-        * it would normally disappear when its bi_end_io is run.
-        * however, we need it for the unmap, so grab an extra
-        * reference to it
-        */
-       bio_get(bio);
-       return bio;
-
- out_unmap:
-       bio_release_pages(bio, false);
-       bio_put(bio);
-       return ERR_PTR(ret);
-}
-
-/**
- *     bio_unmap_user  -       unmap a bio
- *     @bio:           the bio being unmapped
- *
- *     Unmap a bio previously mapped by bio_map_user_iov(). Must be called from
- *     process context.
- *
- *     bio_unmap_user() may sleep.
- */
-void bio_unmap_user(struct bio *bio)
-{
-       bio_release_pages(bio, bio_data_dir(bio) == READ);
-       bio_put(bio);
-       bio_put(bio);
-}
-
-static void bio_invalidate_vmalloc_pages(struct bio *bio)
-{
-#ifdef ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
-       if (bio->bi_private && !op_is_write(bio_op(bio))) {
-               unsigned long i, len = 0;
-
-               for (i = 0; i < bio->bi_vcnt; i++)
-                       len += bio->bi_io_vec[i].bv_len;
-               invalidate_kernel_vmap_range(bio->bi_private, len);
-       }
-#endif
-}
-
-static void bio_map_kern_endio(struct bio *bio)
-{
-       bio_invalidate_vmalloc_pages(bio);
-       bio_put(bio);
-}
-
-/**
- *     bio_map_kern    -       map kernel address into bio
- *     @q: the struct request_queue for the bio
- *     @data: pointer to buffer to map
- *     @len: length in bytes
- *     @gfp_mask: allocation flags for bio allocation
- *
- *     Map the kernel address into a bio suitable for io to a block
- *     device. Returns an error pointer in case of error.
- */
-struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len,
-                        gfp_t gfp_mask)
-{
-       unsigned long kaddr = (unsigned long)data;
-       unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       unsigned long start = kaddr >> PAGE_SHIFT;
-       const int nr_pages = end - start;
-       bool is_vmalloc = is_vmalloc_addr(data);
-       struct page *page;
-       int offset, i;
-       struct bio *bio;
-
-       bio = bio_kmalloc(gfp_mask, nr_pages);
-       if (!bio)
-               return ERR_PTR(-ENOMEM);
-
-       if (is_vmalloc) {
-               flush_kernel_vmap_range(data, len);
-               bio->bi_private = data;
-       }
-
-       offset = offset_in_page(kaddr);
-       for (i = 0; i < nr_pages; i++) {
-               unsigned int bytes = PAGE_SIZE - offset;
-
-               if (len <= 0)
-                       break;
-
-               if (bytes > len)
-                       bytes = len;
-
-               if (!is_vmalloc)
-                       page = virt_to_page(data);
-               else
-                       page = vmalloc_to_page(data);
-               if (bio_add_pc_page(q, bio, page, bytes,
-                                   offset) < bytes) {
-                       /* we don't support partial mappings */
-                       bio_put(bio);
-                       return ERR_PTR(-EINVAL);
-               }
-
-               data += bytes;
-               len -= bytes;
-               offset = 0;
-       }
-
-       bio->bi_end_io = bio_map_kern_endio;
-       return bio;
-}
-
-static void bio_copy_kern_endio(struct bio *bio)
-{
-       bio_free_pages(bio);
-       bio_put(bio);
-}
-
-static void bio_copy_kern_endio_read(struct bio *bio)
-{
-       char *p = bio->bi_private;
-       struct bio_vec *bvec;
-       struct bvec_iter_all iter_all;
-
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               memcpy(p, page_address(bvec->bv_page), bvec->bv_len);
-               p += bvec->bv_len;
-       }
-
-       bio_copy_kern_endio(bio);
-}
-
-/**
- *     bio_copy_kern   -       copy kernel address into bio
- *     @q: the struct request_queue for the bio
- *     @data: pointer to buffer to copy
- *     @len: length in bytes
- *     @gfp_mask: allocation flags for bio and page allocation
- *     @reading: data direction is READ
- *
- *     copy the kernel address into a bio suitable for io to a block
- *     device. Returns an error pointer in case of error.
- */
-struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,
-                         gfp_t gfp_mask, int reading)
-{
-       unsigned long kaddr = (unsigned long)data;
-       unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       unsigned long start = kaddr >> PAGE_SHIFT;
-       struct bio *bio;
-       void *p = data;
-       int nr_pages = 0;
-
-       /*
-        * Overflow, abort
-        */
-       if (end < start)
-               return ERR_PTR(-EINVAL);
-
-       nr_pages = end - start;
-       bio = bio_kmalloc(gfp_mask, nr_pages);
-       if (!bio)
-               return ERR_PTR(-ENOMEM);
-
-       while (len) {
-               struct page *page;
-               unsigned int bytes = PAGE_SIZE;
-
-               if (bytes > len)
-                       bytes = len;
-
-               page = alloc_page(q->bounce_gfp | gfp_mask);
-               if (!page)
-                       goto cleanup;
-
-               if (!reading)
-                       memcpy(page_address(page), p, bytes);
-
-               if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes)
-                       break;
-
-               len -= bytes;
-               p += bytes;
-       }
-
-       if (reading) {
-               bio->bi_end_io = bio_copy_kern_endio_read;
-               bio->bi_private = data;
-       } else {
-               bio->bi_end_io = bio_copy_kern_endio;
-       }
-
-       return bio;
-
-cleanup:
-       bio_free_pages(bio);
-       bio_put(bio);
-       return ERR_PTR(-ENOMEM);
-}
-
 /*
  * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions
  * for performing direct-IO in BIOs.
@@ -1752,14 +1303,14 @@ defer:
        schedule_work(&bio_dirty_work);
 }
 
-void update_io_ticks(struct hd_struct *part, unsigned long now)
+void update_io_ticks(struct hd_struct *part, unsigned long now, bool end)
 {
        unsigned long stamp;
 again:
        stamp = READ_ONCE(part->stamp);
        if (unlikely(stamp != now)) {
                if (likely(cmpxchg(&part->stamp, stamp, now) == stamp)) {
-                       __part_stat_add(part, io_ticks, 1);
+                       __part_stat_add(part, io_ticks, end ? now - stamp : 1);
                }
        }
        if (part->partno) {
@@ -1775,7 +1326,7 @@ void generic_start_io_acct(struct request_queue *q, int op,
 
        part_stat_lock();
 
-       update_io_ticks(part, jiffies);
+       update_io_ticks(part, jiffies, false);
        part_stat_inc(part, ios[sgrp]);
        part_stat_add(part, sectors[sgrp], sectors);
        part_inc_in_flight(q, part, op_is_write(op));
@@ -1793,9 +1344,8 @@ void generic_end_io_acct(struct request_queue *q, int req_op,
 
        part_stat_lock();
 
-       update_io_ticks(part, now);
+       update_io_ticks(part, now, true);
        part_stat_add(part, nsecs[sgrp], jiffies_to_nsecs(duration));
-       part_stat_add(part, time_in_queue, duration);
        part_dec_in_flight(q, part, op_is_write(req_op));
 
        part_stat_unlock();
index a229b94..c15a260 100644 (file)
@@ -1010,7 +1010,7 @@ unlock:
  * blkcg_init_queue - initialize blkcg part of request queue
  * @q: request_queue to initialize
  *
- * Called from blk_alloc_queue_node(). Responsible for initializing blkcg
+ * Called from __blk_alloc_queue(). Responsible for initializing blkcg
  * part of new request_queue @q.
  *
  * RETURNS:
index 089e890..7e4a1da 100644 (file)
@@ -346,7 +346,6 @@ void blk_cleanup_queue(struct request_queue *q)
 
        blk_queue_flag_set(QUEUE_FLAG_NOMERGES, q);
        blk_queue_flag_set(QUEUE_FLAG_NOXMERGES, q);
-       blk_queue_flag_set(QUEUE_FLAG_DYING, q);
 
        /*
         * Drain all requests queued before DYING marking. Set DEAD flag to
@@ -389,12 +388,6 @@ void blk_cleanup_queue(struct request_queue *q)
 }
 EXPORT_SYMBOL(blk_cleanup_queue);
 
-struct request_queue *blk_alloc_queue(gfp_t gfp_mask)
-{
-       return blk_alloc_queue_node(gfp_mask, NUMA_NO_NODE);
-}
-EXPORT_SYMBOL(blk_alloc_queue);
-
 /**
  * blk_queue_enter() - try to increase q->q_usage_counter
  * @q: request queue pointer
@@ -471,24 +464,19 @@ static void blk_timeout_work(struct work_struct *work)
 {
 }
 
-/**
- * blk_alloc_queue_node - allocate a request queue
- * @gfp_mask: memory allocation flags
- * @node_id: NUMA node to allocate memory from
- */
-struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
+struct request_queue *__blk_alloc_queue(int node_id)
 {
        struct request_queue *q;
        int ret;
 
        q = kmem_cache_alloc_node(blk_requestq_cachep,
-                               gfp_mask | __GFP_ZERO, node_id);
+                               GFP_KERNEL | __GFP_ZERO, node_id);
        if (!q)
                return NULL;
 
        q->last_merge = NULL;
 
-       q->id = ida_simple_get(&blk_queue_ida, 0, 0, gfp_mask);
+       q->id = ida_simple_get(&blk_queue_ida, 0, 0, GFP_KERNEL);
        if (q->id < 0)
                goto fail_q;
 
@@ -496,7 +484,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
        if (ret)
                goto fail_id;
 
-       q->backing_dev_info = bdi_alloc_node(gfp_mask, node_id);
+       q->backing_dev_info = bdi_alloc_node(GFP_KERNEL, node_id);
        if (!q->backing_dev_info)
                goto fail_split;
 
@@ -542,6 +530,9 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
        if (blkcg_init_queue(q))
                goto fail_ref;
 
+       blk_queue_dma_alignment(q, 511);
+       blk_set_default_limits(&q->limits);
+
        return q;
 
 fail_ref:
@@ -558,7 +549,22 @@ fail_q:
        kmem_cache_free(blk_requestq_cachep, q);
        return NULL;
 }
-EXPORT_SYMBOL(blk_alloc_queue_node);
+
+struct request_queue *blk_alloc_queue(make_request_fn make_request, int node_id)
+{
+       struct request_queue *q;
+
+       if (WARN_ON_ONCE(!make_request))
+               return NULL;
+
+       q = __blk_alloc_queue(node_id);
+       if (!q)
+               return NULL;
+       q->make_request_fn = make_request;
+       q->nr_requests = BLKDEV_MAX_RQ;
+       return q;
+}
+EXPORT_SYMBOL(blk_alloc_queue);
 
 bool blk_get_queue(struct request_queue *q)
 {
@@ -1121,10 +1127,9 @@ blk_qc_t direct_make_request(struct bio *bio)
 
        if (unlikely(blk_queue_enter(q, nowait ? BLK_MQ_REQ_NOWAIT : 0))) {
                if (nowait && !blk_queue_dying(q))
-                       bio->bi_status = BLK_STS_AGAIN;
+                       bio_wouldblock_error(bio);
                else
-                       bio->bi_status = BLK_STS_IOERR;
-               bio_endio(bio);
+                       bio_io_error(bio);
                return BLK_QC_T_NONE;
        }
 
@@ -1203,7 +1208,7 @@ EXPORT_SYMBOL(submit_bio);
 
 /**
  * blk_cloned_rq_check_limits - Helper function to check a cloned request
- *                              for new the queue limits
+ *                              for the new queue limits
  * @q:  the queue
  * @rq: the request being checked
  *
@@ -1339,10 +1344,9 @@ void blk_account_io_done(struct request *req, u64 now)
                part_stat_lock();
                part = req->part;
 
-               update_io_ticks(part, jiffies);
+               update_io_ticks(part, jiffies, true);
                part_stat_inc(part, ios[sgrp]);
                part_stat_add(part, nsecs[sgrp], now - req->start_time_ns);
-               part_stat_add(part, time_in_queue, nsecs_to_jiffies64(now - req->start_time_ns));
                part_dec_in_flight(req->q, part, rq_data_dir(req));
 
                hd_struct_put(part);
@@ -1381,7 +1385,7 @@ void blk_account_io_start(struct request *rq, bool new_io)
                rq->part = part;
        }
 
-       update_io_ticks(part, jiffies);
+       update_io_ticks(part, jiffies, false);
 
        part_stat_unlock();
 }
@@ -1583,23 +1587,6 @@ void blk_rq_unprep_clone(struct request *rq)
 }
 EXPORT_SYMBOL_GPL(blk_rq_unprep_clone);
 
-/*
- * Copy attributes of the original request to the clone request.
- * The actual data parts (e.g. ->cmd, ->sense) are not copied.
- */
-static void __blk_rq_prep_clone(struct request *dst, struct request *src)
-{
-       dst->__sector = blk_rq_pos(src);
-       dst->__data_len = blk_rq_bytes(src);
-       if (src->rq_flags & RQF_SPECIAL_PAYLOAD) {
-               dst->rq_flags |= RQF_SPECIAL_PAYLOAD;
-               dst->special_vec = src->special_vec;
-       }
-       dst->nr_phys_segments = src->nr_phys_segments;
-       dst->ioprio = src->ioprio;
-       dst->extra_len = src->extra_len;
-}
-
 /**
  * blk_rq_prep_clone - Helper function to setup clone request
  * @rq: the request to be setup
@@ -1612,8 +1599,6 @@ static void __blk_rq_prep_clone(struct request *dst, struct request *src)
  *
  * Description:
  *     Clones bios in @rq_src to @rq, and copies attributes of @rq_src to @rq.
- *     The actual data parts of @rq_src (e.g. ->cmd, ->sense)
- *     are not copied, and copying such parts is the caller's responsibility.
  *     Also, pages which the original bios are pointing to are not copied
  *     and the cloned bios just point same pages.
  *     So cloned bios must be completed before original bios, which means
@@ -1644,7 +1629,16 @@ int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
                        rq->bio = rq->biotail = bio;
        }
 
-       __blk_rq_prep_clone(rq, rq_src);
+       /* Copy attributes of the original request to the clone request. */
+       rq->__sector = blk_rq_pos(rq_src);
+       rq->__data_len = blk_rq_bytes(rq_src);
+       if (rq_src->rq_flags & RQF_SPECIAL_PAYLOAD) {
+               rq->rq_flags |= RQF_SPECIAL_PAYLOAD;
+               rq->special_vec = rq_src->special_vec;
+       }
+       rq->nr_phys_segments = rq_src->nr_phys_segments;
+       rq->ioprio = rq_src->ioprio;
+       rq->extra_len = rq_src->extra_len;
 
        return 0;
 
@@ -1663,12 +1657,6 @@ int kblockd_schedule_work(struct work_struct *work)
 }
 EXPORT_SYMBOL(kblockd_schedule_work);
 
-int kblockd_schedule_work_on(int cpu, struct work_struct *work)
-{
-       return queue_work_on(cpu, kblockd_workqueue, work);
-}
-EXPORT_SYMBOL(kblockd_schedule_work_on);
-
 int kblockd_mod_delayed_work_on(int cpu, struct delayed_work *dwork,
                                unsigned long delay)
 {
index 3f977c5..c7f396e 100644 (file)
@@ -160,9 +160,6 @@ static void blk_account_io_flush(struct request *rq)
  *
  * CONTEXT:
  * spin_lock_irq(fq->mq_flush_lock)
- *
- * RETURNS:
- * %true if requests were added to the dispatch queue, %false otherwise.
  */
 static void blk_flush_complete_seq(struct request *rq,
                                   struct blk_flush_queue *fq,
@@ -412,7 +409,7 @@ void blk_insert_flush(struct request *rq)
         */
        if ((policy & REQ_FSEQ_DATA) &&
            !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
-               blk_mq_request_bypass_insert(rq, false);
+               blk_mq_request_bypass_insert(rq, false, false);
                return;
        }
 
@@ -457,15 +454,6 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
        if (!q)
                return -ENXIO;
 
-       /*
-        * some block devices may not have their queue correctly set up here
-        * (e.g. loop device without a backing file) and so issuing a flush
-        * here will panic. Ensure there is a request function before issuing
-        * the flush.
-        */
-       if (!q->make_request_fn)
-               return -ENXIO;
-
        bio = bio_alloc(gfp_mask, 0);
        bio_set_dev(bio, bdev);
        bio->bi_opf = REQ_OP_WRITE | REQ_PREFLUSH;
@@ -485,8 +473,8 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
 }
 EXPORT_SYMBOL(blkdev_issue_flush);
 
-struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q,
-               int node, int cmd_size, gfp_t flags)
+struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
+                                             gfp_t flags)
 {
        struct blk_flush_queue *fq;
        int rq_sz = sizeof(struct request);
index 5ed59ac..9df50fb 100644 (file)
@@ -84,6 +84,7 @@ static void ioc_destroy_icq(struct io_cq *icq)
         * making it impossible to determine icq_cache.  Record it in @icq.
         */
        icq->__rcu_icq_cache = et->icq_cache;
+       icq->flags |= ICQ_DESTROYED;
        call_rcu(&icq->__rcu_head, icq_free_icq_rcu);
 }
 
@@ -212,15 +213,21 @@ static void __ioc_clear_queue(struct list_head *icq_list)
 {
        unsigned long flags;
 
+       rcu_read_lock();
        while (!list_empty(icq_list)) {
                struct io_cq *icq = list_entry(icq_list->next,
                                                struct io_cq, q_node);
                struct io_context *ioc = icq->ioc;
 
                spin_lock_irqsave(&ioc->lock, flags);
+               if (icq->flags & ICQ_DESTROYED) {
+                       spin_unlock_irqrestore(&ioc->lock, flags);
+                       continue;
+               }
                ioc_destroy_icq(icq);
                spin_unlock_irqrestore(&ioc->lock, flags);
        }
+       rcu_read_unlock();
 }
 
 /**
index 27ca686..db35ee6 100644 (file)
@@ -46,9 +46,6 @@
  * If needed, tools/cgroup/iocost_coef_gen.py can be used to generate
  * device-specific coefficients.
  *
- * If needed, tools/cgroup/iocost_coef_gen.py can be used to generate
- * device-specific coefficients.
- *
  * 2. Control Strategy
  *
  * The device virtual time (vtime) is used as the primary control metric.
@@ -1318,7 +1315,7 @@ static bool iocg_is_idle(struct ioc_gq *iocg)
                return false;
 
        /* is something in flight? */
-       if (atomic64_read(&iocg->done_vtime) < atomic64_read(&iocg->vtime))
+       if (atomic64_read(&iocg->done_vtime) != atomic64_read(&iocg->vtime))
                return false;
 
        return true;
index b079026..b72c361 100644 (file)
 
 #include "blk.h"
 
+struct bio_map_data {
+       int is_our_pages;
+       struct iov_iter iter;
+       struct iovec iov[];
+};
+
+static struct bio_map_data *bio_alloc_map_data(struct iov_iter *data,
+                                              gfp_t gfp_mask)
+{
+       struct bio_map_data *bmd;
+
+       if (data->nr_segs > UIO_MAXIOV)
+               return NULL;
+
+       bmd = kmalloc(struct_size(bmd, iov, data->nr_segs), gfp_mask);
+       if (!bmd)
+               return NULL;
+       memcpy(bmd->iov, data->iov, sizeof(struct iovec) * data->nr_segs);
+       bmd->iter = *data;
+       bmd->iter.iov = bmd->iov;
+       return bmd;
+}
+
+/**
+ * bio_copy_from_iter - copy all pages from iov_iter to bio
+ * @bio: The &struct bio which describes the I/O as destination
+ * @iter: iov_iter as source
+ *
+ * Copy all pages from iov_iter to bio.
+ * Returns 0 on success, or error on failure.
+ */
+static int bio_copy_from_iter(struct bio *bio, struct iov_iter *iter)
+{
+       struct bio_vec *bvec;
+       struct bvec_iter_all iter_all;
+
+       bio_for_each_segment_all(bvec, bio, iter_all) {
+               ssize_t ret;
+
+               ret = copy_page_from_iter(bvec->bv_page,
+                                         bvec->bv_offset,
+                                         bvec->bv_len,
+                                         iter);
+
+               if (!iov_iter_count(iter))
+                       break;
+
+               if (ret < bvec->bv_len)
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+/**
+ * bio_copy_to_iter - copy all pages from bio to iov_iter
+ * @bio: The &struct bio which describes the I/O as source
+ * @iter: iov_iter as destination
+ *
+ * Copy all pages from bio to iov_iter.
+ * Returns 0 on success, or error on failure.
+ */
+static int bio_copy_to_iter(struct bio *bio, struct iov_iter iter)
+{
+       struct bio_vec *bvec;
+       struct bvec_iter_all iter_all;
+
+       bio_for_each_segment_all(bvec, bio, iter_all) {
+               ssize_t ret;
+
+               ret = copy_page_to_iter(bvec->bv_page,
+                                       bvec->bv_offset,
+                                       bvec->bv_len,
+                                       &iter);
+
+               if (!iov_iter_count(&iter))
+                       break;
+
+               if (ret < bvec->bv_len)
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+/**
+ *     bio_uncopy_user -       finish previously mapped bio
+ *     @bio: bio being terminated
+ *
+ *     Free pages allocated from bio_copy_user_iov() and write back data
+ *     to user space in case of a read.
+ */
+static int bio_uncopy_user(struct bio *bio)
+{
+       struct bio_map_data *bmd = bio->bi_private;
+       int ret = 0;
+
+       if (!bio_flagged(bio, BIO_NULL_MAPPED)) {
+               /*
+                * if we're in a workqueue, the request is orphaned, so
+                * don't copy into a random user address space, just free
+                * and return -EINTR so user space doesn't expect any data.
+                */
+               if (!current->mm)
+                       ret = -EINTR;
+               else if (bio_data_dir(bio) == READ)
+                       ret = bio_copy_to_iter(bio, bmd->iter);
+               if (bmd->is_our_pages)
+                       bio_free_pages(bio);
+       }
+       kfree(bmd);
+       bio_put(bio);
+       return ret;
+}
+
+/**
+ *     bio_copy_user_iov       -       copy user data to bio
+ *     @q:             destination block queue
+ *     @map_data:      pointer to the rq_map_data holding pages (if necessary)
+ *     @iter:          iovec iterator
+ *     @gfp_mask:      memory allocation flags
+ *
+ *     Prepares and returns a bio for indirect user io, bouncing data
+ *     to/from kernel pages as necessary. Must be paired with
+ *     call bio_uncopy_user() on io completion.
+ */
+static struct bio *bio_copy_user_iov(struct request_queue *q,
+               struct rq_map_data *map_data, struct iov_iter *iter,
+               gfp_t gfp_mask)
+{
+       struct bio_map_data *bmd;
+       struct page *page;
+       struct bio *bio;
+       int i = 0, ret;
+       int nr_pages;
+       unsigned int len = iter->count;
+       unsigned int offset = map_data ? offset_in_page(map_data->offset) : 0;
+
+       bmd = bio_alloc_map_data(iter, gfp_mask);
+       if (!bmd)
+               return ERR_PTR(-ENOMEM);
+
+       /*
+        * We need to do a deep copy of the iov_iter including the iovecs.
+        * The caller provided iov might point to an on-stack or otherwise
+        * shortlived one.
+        */
+       bmd->is_our_pages = map_data ? 0 : 1;
+
+       nr_pages = DIV_ROUND_UP(offset + len, PAGE_SIZE);
+       if (nr_pages > BIO_MAX_PAGES)
+               nr_pages = BIO_MAX_PAGES;
+
+       ret = -ENOMEM;
+       bio = bio_kmalloc(gfp_mask, nr_pages);
+       if (!bio)
+               goto out_bmd;
+
+       ret = 0;
+
+       if (map_data) {
+               nr_pages = 1 << map_data->page_order;
+               i = map_data->offset / PAGE_SIZE;
+       }
+       while (len) {
+               unsigned int bytes = PAGE_SIZE;
+
+               bytes -= offset;
+
+               if (bytes > len)
+                       bytes = len;
+
+               if (map_data) {
+                       if (i == map_data->nr_entries * nr_pages) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+
+                       page = map_data->pages[i / nr_pages];
+                       page += (i % nr_pages);
+
+                       i++;
+               } else {
+                       page = alloc_page(q->bounce_gfp | gfp_mask);
+                       if (!page) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+               }
+
+               if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) {
+                       if (!map_data)
+                               __free_page(page);
+                       break;
+               }
+
+               len -= bytes;
+               offset = 0;
+       }
+
+       if (ret)
+               goto cleanup;
+
+       if (map_data)
+               map_data->offset += bio->bi_iter.bi_size;
+
+       /*
+        * success
+        */
+       if ((iov_iter_rw(iter) == WRITE &&
+            (!map_data || !map_data->null_mapped)) ||
+           (map_data && map_data->from_user)) {
+               ret = bio_copy_from_iter(bio, iter);
+               if (ret)
+                       goto cleanup;
+       } else {
+               if (bmd->is_our_pages)
+                       zero_fill_bio(bio);
+               iov_iter_advance(iter, bio->bi_iter.bi_size);
+       }
+
+       bio->bi_private = bmd;
+       if (map_data && map_data->null_mapped)
+               bio_set_flag(bio, BIO_NULL_MAPPED);
+       return bio;
+cleanup:
+       if (!map_data)
+               bio_free_pages(bio);
+       bio_put(bio);
+out_bmd:
+       kfree(bmd);
+       return ERR_PTR(ret);
+}
+
+/**
+ *     bio_map_user_iov - map user iovec into bio
+ *     @q:             the struct request_queue for the bio
+ *     @iter:          iovec iterator
+ *     @gfp_mask:      memory allocation flags
+ *
+ *     Map the user space address into a bio suitable for io to a block
+ *     device. Returns an error pointer in case of error.
+ */
+static struct bio *bio_map_user_iov(struct request_queue *q,
+               struct iov_iter *iter, gfp_t gfp_mask)
+{
+       int j;
+       struct bio *bio;
+       int ret;
+
+       if (!iov_iter_count(iter))
+               return ERR_PTR(-EINVAL);
+
+       bio = bio_kmalloc(gfp_mask, iov_iter_npages(iter, BIO_MAX_PAGES));
+       if (!bio)
+               return ERR_PTR(-ENOMEM);
+
+       while (iov_iter_count(iter)) {
+               struct page **pages;
+               ssize_t bytes;
+               size_t offs, added = 0;
+               int npages;
+
+               bytes = iov_iter_get_pages_alloc(iter, &pages, LONG_MAX, &offs);
+               if (unlikely(bytes <= 0)) {
+                       ret = bytes ? bytes : -EFAULT;
+                       goto out_unmap;
+               }
+
+               npages = DIV_ROUND_UP(offs + bytes, PAGE_SIZE);
+
+               if (unlikely(offs & queue_dma_alignment(q))) {
+                       ret = -EINVAL;
+                       j = 0;
+               } else {
+                       for (j = 0; j < npages; j++) {
+                               struct page *page = pages[j];
+                               unsigned int n = PAGE_SIZE - offs;
+                               bool same_page = false;
+
+                               if (n > bytes)
+                                       n = bytes;
+
+                               if (!__bio_add_pc_page(q, bio, page, n, offs,
+                                               &same_page)) {
+                                       if (same_page)
+                                               put_page(page);
+                                       break;
+                               }
+
+                               added += n;
+                               bytes -= n;
+                               offs = 0;
+                       }
+                       iov_iter_advance(iter, added);
+               }
+               /*
+                * release the pages we didn't map into the bio, if any
+                */
+               while (j < npages)
+                       put_page(pages[j++]);
+               kvfree(pages);
+               /* couldn't stuff something into bio? */
+               if (bytes)
+                       break;
+       }
+
+       bio_set_flag(bio, BIO_USER_MAPPED);
+
+       /*
+        * subtle -- if bio_map_user_iov() ended up bouncing a bio,
+        * it would normally disappear when its bi_end_io is run.
+        * however, we need it for the unmap, so grab an extra
+        * reference to it
+        */
+       bio_get(bio);
+       return bio;
+
+ out_unmap:
+       bio_release_pages(bio, false);
+       bio_put(bio);
+       return ERR_PTR(ret);
+}
+
+/**
+ *     bio_unmap_user  -       unmap a bio
+ *     @bio:           the bio being unmapped
+ *
+ *     Unmap a bio previously mapped by bio_map_user_iov(). Must be called from
+ *     process context.
+ *
+ *     bio_unmap_user() may sleep.
+ */
+static void bio_unmap_user(struct bio *bio)
+{
+       bio_release_pages(bio, bio_data_dir(bio) == READ);
+       bio_put(bio);
+       bio_put(bio);
+}
+
+static void bio_invalidate_vmalloc_pages(struct bio *bio)
+{
+#ifdef ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+       if (bio->bi_private && !op_is_write(bio_op(bio))) {
+               unsigned long i, len = 0;
+
+               for (i = 0; i < bio->bi_vcnt; i++)
+                       len += bio->bi_io_vec[i].bv_len;
+               invalidate_kernel_vmap_range(bio->bi_private, len);
+       }
+#endif
+}
+
+static void bio_map_kern_endio(struct bio *bio)
+{
+       bio_invalidate_vmalloc_pages(bio);
+       bio_put(bio);
+}
+
+/**
+ *     bio_map_kern    -       map kernel address into bio
+ *     @q: the struct request_queue for the bio
+ *     @data: pointer to buffer to map
+ *     @len: length in bytes
+ *     @gfp_mask: allocation flags for bio allocation
+ *
+ *     Map the kernel address into a bio suitable for io to a block
+ *     device. Returns an error pointer in case of error.
+ */
+static struct bio *bio_map_kern(struct request_queue *q, void *data,
+               unsigned int len, gfp_t gfp_mask)
+{
+       unsigned long kaddr = (unsigned long)data;
+       unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       unsigned long start = kaddr >> PAGE_SHIFT;
+       const int nr_pages = end - start;
+       bool is_vmalloc = is_vmalloc_addr(data);
+       struct page *page;
+       int offset, i;
+       struct bio *bio;
+
+       bio = bio_kmalloc(gfp_mask, nr_pages);
+       if (!bio)
+               return ERR_PTR(-ENOMEM);
+
+       if (is_vmalloc) {
+               flush_kernel_vmap_range(data, len);
+               bio->bi_private = data;
+       }
+
+       offset = offset_in_page(kaddr);
+       for (i = 0; i < nr_pages; i++) {
+               unsigned int bytes = PAGE_SIZE - offset;
+
+               if (len <= 0)
+                       break;
+
+               if (bytes > len)
+                       bytes = len;
+
+               if (!is_vmalloc)
+                       page = virt_to_page(data);
+               else
+                       page = vmalloc_to_page(data);
+               if (bio_add_pc_page(q, bio, page, bytes,
+                                   offset) < bytes) {
+                       /* we don't support partial mappings */
+                       bio_put(bio);
+                       return ERR_PTR(-EINVAL);
+               }
+
+               data += bytes;
+               len -= bytes;
+               offset = 0;
+       }
+
+       bio->bi_end_io = bio_map_kern_endio;
+       return bio;
+}
+
+static void bio_copy_kern_endio(struct bio *bio)
+{
+       bio_free_pages(bio);
+       bio_put(bio);
+}
+
+static void bio_copy_kern_endio_read(struct bio *bio)
+{
+       char *p = bio->bi_private;
+       struct bio_vec *bvec;
+       struct bvec_iter_all iter_all;
+
+       bio_for_each_segment_all(bvec, bio, iter_all) {
+               memcpy(p, page_address(bvec->bv_page), bvec->bv_len);
+               p += bvec->bv_len;
+       }
+
+       bio_copy_kern_endio(bio);
+}
+
+/**
+ *     bio_copy_kern   -       copy kernel address into bio
+ *     @q: the struct request_queue for the bio
+ *     @data: pointer to buffer to copy
+ *     @len: length in bytes
+ *     @gfp_mask: allocation flags for bio and page allocation
+ *     @reading: data direction is READ
+ *
+ *     copy the kernel address into a bio suitable for io to a block
+ *     device. Returns an error pointer in case of error.
+ */
+static struct bio *bio_copy_kern(struct request_queue *q, void *data,
+               unsigned int len, gfp_t gfp_mask, int reading)
+{
+       unsigned long kaddr = (unsigned long)data;
+       unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       unsigned long start = kaddr >> PAGE_SHIFT;
+       struct bio *bio;
+       void *p = data;
+       int nr_pages = 0;
+
+       /*
+        * Overflow, abort
+        */
+       if (end < start)
+               return ERR_PTR(-EINVAL);
+
+       nr_pages = end - start;
+       bio = bio_kmalloc(gfp_mask, nr_pages);
+       if (!bio)
+               return ERR_PTR(-ENOMEM);
+
+       while (len) {
+               struct page *page;
+               unsigned int bytes = PAGE_SIZE;
+
+               if (bytes > len)
+                       bytes = len;
+
+               page = alloc_page(q->bounce_gfp | gfp_mask);
+               if (!page)
+                       goto cleanup;
+
+               if (!reading)
+                       memcpy(page_address(page), p, bytes);
+
+               if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes)
+                       break;
+
+               len -= bytes;
+               p += bytes;
+       }
+
+       if (reading) {
+               bio->bi_end_io = bio_copy_kern_endio_read;
+               bio->bi_private = data;
+       } else {
+               bio->bi_end_io = bio_copy_kern_endio;
+       }
+
+       return bio;
+
+cleanup:
+       bio_free_pages(bio);
+       bio_put(bio);
+       return ERR_PTR(-ENOMEM);
+}
+
 /*
  * Append a bio to a passthrough request.  Only works if the bio can be merged
  * into the request based on the driver constraints.
index ca22afd..74cedea 100644 (file)
@@ -361,13 +361,19 @@ static bool blk_mq_sched_bypass_insert(struct blk_mq_hw_ctx *hctx,
                                       bool has_sched,
                                       struct request *rq)
 {
-       /* dispatch flush rq directly */
-       if (rq->rq_flags & RQF_FLUSH_SEQ) {
-               spin_lock(&hctx->lock);
-               list_add(&rq->queuelist, &hctx->dispatch);
-               spin_unlock(&hctx->lock);
+       /*
+        * dispatch flush and passthrough rq directly
+        *
+        * passthrough request has to be added to hctx->dispatch directly.
+        * For some reason, device may be in one situation which can't
+        * handle FS request, so STS_RESOURCE is always returned and the
+        * FS request will be added to hctx->dispatch. However passthrough
+        * request may be required at that time for fixing the problem. If
+        * passthrough request is added to scheduler queue, there isn't any
+        * chance to dispatch it given we prioritize requests in hctx->dispatch.
+        */
+       if ((rq->rq_flags & RQF_FLUSH_SEQ) || blk_rq_is_passthrough(rq))
                return true;
-       }
 
        if (has_sched)
                rq->rq_flags |= RQF_SORTED;
@@ -391,8 +397,32 @@ void blk_mq_sched_insert_request(struct request *rq, bool at_head,
 
        WARN_ON(e && (rq->tag != -1));
 
-       if (blk_mq_sched_bypass_insert(hctx, !!e, rq))
+       if (blk_mq_sched_bypass_insert(hctx, !!e, rq)) {
+               /*
+                * Firstly normal IO request is inserted to scheduler queue or
+                * sw queue, meantime we add flush request to dispatch queue(
+                * hctx->dispatch) directly and there is at most one in-flight
+                * flush request for each hw queue, so it doesn't matter to add
+                * flush request to tail or front of the dispatch queue.
+                *
+                * Secondly in case of NCQ, flush request belongs to non-NCQ
+                * command, and queueing it will fail when there is any
+                * in-flight normal IO request(NCQ command). When adding flush
+                * rq to the front of hctx->dispatch, it is easier to introduce
+                * extra time to flush rq's latency because of S_SCHED_RESTART
+                * compared with adding to the tail of dispatch queue, then
+                * chance of flush merge is increased, and less flush requests
+                * will be issued to controller. It is observed that ~10% time
+                * is saved in blktests block/004 on disk attached to AHCI/NCQ
+                * drive when adding flush rq to the front of hctx->dispatch.
+                *
+                * Simply queue flush rq to the front of hctx->dispatch so that
+                * intensive flush workloads can benefit in case of NCQ HW.
+                */
+               at_head = (rq->rq_flags & RQF_FLUSH_SEQ) ? true : at_head;
+               blk_mq_request_bypass_insert(rq, at_head, false);
                goto run;
+       }
 
        if (e && e->type->ops.insert_requests) {
                LIST_HEAD(list);
index fbacde4..586c9d6 100644 (file)
@@ -183,8 +183,8 @@ found_tag:
        return tag + tag_offset;
 }
 
-void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_tags *tags,
-                   struct blk_mq_ctx *ctx, unsigned int tag)
+void blk_mq_put_tag(struct blk_mq_tags *tags, struct blk_mq_ctx *ctx,
+                   unsigned int tag)
 {
        if (!blk_mq_tag_is_reserved(tags, tag)) {
                const int real_tag = tag - tags->nr_reserved_tags;
index 15bc74a..2b8321e 100644 (file)
@@ -26,8 +26,8 @@ extern struct blk_mq_tags *blk_mq_init_tags(unsigned int nr_tags, unsigned int r
 extern void blk_mq_free_tags(struct blk_mq_tags *tags);
 
 extern unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data);
-extern void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_tags *tags,
-                          struct blk_mq_ctx *ctx, unsigned int tag);
+extern void blk_mq_put_tag(struct blk_mq_tags *tags, struct blk_mq_ctx *ctx,
+                          unsigned int tag);
 extern int blk_mq_tag_update_depth(struct blk_mq_hw_ctx *hctx,
                                        struct blk_mq_tags **tags,
                                        unsigned int depth, bool can_grow);
index a12b176..f6291ce 100644 (file)
@@ -477,9 +477,9 @@ static void __blk_mq_free_request(struct request *rq)
        blk_pm_mark_last_busy(rq);
        rq->mq_hctx = NULL;
        if (rq->tag != -1)
-               blk_mq_put_tag(hctx, hctx->tags, ctx, rq->tag);
+               blk_mq_put_tag(hctx->tags, ctx, rq->tag);
        if (sched_tag != -1)
-               blk_mq_put_tag(hctx, hctx->sched_tags, ctx, sched_tag);
+               blk_mq_put_tag(hctx->sched_tags, ctx, sched_tag);
        blk_mq_sched_restart(hctx);
        blk_queue_exit(q);
 }
@@ -735,7 +735,7 @@ static void blk_mq_requeue_work(struct work_struct *work)
                 * merge.
                 */
                if (rq->rq_flags & RQF_DONTPREP)
-                       blk_mq_request_bypass_insert(rq, false);
+                       blk_mq_request_bypass_insert(rq, false, false);
                else
                        blk_mq_sched_insert_request(rq, true, false, false);
        }
@@ -1178,6 +1178,23 @@ static void blk_mq_update_dispatch_busy(struct blk_mq_hw_ctx *hctx, bool busy)
 
 #define BLK_MQ_RESOURCE_DELAY  3               /* ms units */
 
+static void blk_mq_handle_dev_resource(struct request *rq,
+                                      struct list_head *list)
+{
+       struct request *next =
+               list_first_entry_or_null(list, struct request, queuelist);
+
+       /*
+        * If an I/O scheduler has been configured and we got a driver tag for
+        * the next request already, free it.
+        */
+       if (next)
+               blk_mq_put_driver_tag(next);
+
+       list_add(&rq->queuelist, list);
+       __blk_mq_requeue_request(rq);
+}
+
 /*
  * Returns true if we did some work AND can potentially do more.
  */
@@ -1245,17 +1262,7 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
 
                ret = q->mq_ops->queue_rq(hctx, &bd);
                if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE) {
-                       /*
-                        * If an I/O scheduler has been configured and we got a
-                        * driver tag for the next request already, free it
-                        * again.
-                        */
-                       if (!list_empty(list)) {
-                               nxt = list_first_entry(list, struct request, queuelist);
-                               blk_mq_put_driver_tag(nxt);
-                       }
-                       list_add(&rq->queuelist, list);
-                       __blk_mq_requeue_request(rq);
+                       blk_mq_handle_dev_resource(rq, list);
                        break;
                }
 
@@ -1286,7 +1293,7 @@ bool blk_mq_dispatch_rq_list(struct request_queue *q, struct list_head *list,
                        q->mq_ops->commit_rqs(hctx);
 
                spin_lock(&hctx->lock);
-               list_splice_init(list, &hctx->dispatch);
+               list_splice_tail_init(list, &hctx->dispatch);
                spin_unlock(&hctx->lock);
 
                /*
@@ -1677,12 +1684,16 @@ void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
  * Should only be used carefully, when the caller knows we want to
  * bypass a potential IO scheduler on the target device.
  */
-void blk_mq_request_bypass_insert(struct request *rq, bool run_queue)
+void blk_mq_request_bypass_insert(struct request *rq, bool at_head,
+                                 bool run_queue)
 {
        struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
 
        spin_lock(&hctx->lock);
-       list_add_tail(&rq->queuelist, &hctx->dispatch);
+       if (at_head)
+               list_add(&rq->queuelist, &hctx->dispatch);
+       else
+               list_add_tail(&rq->queuelist, &hctx->dispatch);
        spin_unlock(&hctx->lock);
 
        if (run_queue)
@@ -1849,7 +1860,7 @@ insert:
        if (bypass_insert)
                return BLK_STS_RESOURCE;
 
-       blk_mq_request_bypass_insert(rq, run_queue);
+       blk_mq_request_bypass_insert(rq, false, run_queue);
        return BLK_STS_OK;
 }
 
@@ -1876,7 +1887,7 @@ static void blk_mq_try_issue_directly(struct blk_mq_hw_ctx *hctx,
 
        ret = __blk_mq_try_issue_directly(hctx, rq, cookie, false, true);
        if (ret == BLK_STS_RESOURCE || ret == BLK_STS_DEV_RESOURCE)
-               blk_mq_request_bypass_insert(rq, true);
+               blk_mq_request_bypass_insert(rq, false, true);
        else if (ret != BLK_STS_OK)
                blk_mq_end_request(rq, ret);
 
@@ -1910,7 +1921,7 @@ void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
                if (ret != BLK_STS_OK) {
                        if (ret == BLK_STS_RESOURCE ||
                                        ret == BLK_STS_DEV_RESOURCE) {
-                               blk_mq_request_bypass_insert(rq,
+                               blk_mq_request_bypass_insert(rq, false,
                                                        list_empty(list));
                                break;
                        }
@@ -2405,8 +2416,7 @@ blk_mq_alloc_hctx(struct request_queue *q, struct blk_mq_tag_set *set,
        init_waitqueue_func_entry(&hctx->dispatch_wait, blk_mq_dispatch_wake);
        INIT_LIST_HEAD(&hctx->dispatch_wait.entry);
 
-       hctx->fq = blk_alloc_flush_queue(q, hctx->numa_node, set->cmd_size,
-                       gfp);
+       hctx->fq = blk_alloc_flush_queue(hctx->numa_node, set->cmd_size, gfp);
        if (!hctx->fq)
                goto free_bitmap;
 
@@ -2714,13 +2724,15 @@ void blk_mq_release(struct request_queue *q)
        blk_mq_sysfs_deinit(q);
 }
 
-struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
+struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set,
+               void *queuedata)
 {
        struct request_queue *uninit_q, *q;
 
-       uninit_q = blk_alloc_queue_node(GFP_KERNEL, set->numa_node);
+       uninit_q = __blk_alloc_queue(set->numa_node);
        if (!uninit_q)
                return ERR_PTR(-ENOMEM);
+       uninit_q->queuedata = queuedata;
 
        /*
         * Initialize the queue without an elevator. device_add_disk() will do
@@ -2732,6 +2744,12 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
 
        return q;
 }
+EXPORT_SYMBOL_GPL(blk_mq_init_queue_data);
+
+struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
+{
+       return blk_mq_init_queue_data(set, NULL);
+}
 EXPORT_SYMBOL(blk_mq_init_queue);
 
 /*
@@ -2820,7 +2838,6 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set,
                        memcpy(new_hctxs, hctxs, q->nr_hw_queues *
                               sizeof(*hctxs));
                q->queue_hw_ctx = new_hctxs;
-               q->nr_hw_queues = set->nr_hw_queues;
                kfree(hctxs);
                hctxs = new_hctxs;
        }
@@ -2922,11 +2939,7 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
        INIT_LIST_HEAD(&q->requeue_list);
        spin_lock_init(&q->requeue_lock);
 
-       blk_queue_make_request(q, blk_mq_make_request);
-
-       /*
-        * Do this after blk_queue_make_request() overrides it...
-        */
+       q->make_request_fn = blk_mq_make_request;
        q->nr_requests = set->queue_depth;
 
        /*
@@ -3019,6 +3032,14 @@ static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
 
 static int blk_mq_update_queue_map(struct blk_mq_tag_set *set)
 {
+       /*
+        * blk_mq_map_queues() and multiple .map_queues() implementations
+        * expect that set->map[HCTX_TYPE_DEFAULT].nr_queues is set to the
+        * number of hardware queues.
+        */
+       if (set->nr_maps == 1)
+               set->map[HCTX_TYPE_DEFAULT].nr_queues = set->nr_hw_queues;
+
        if (set->ops->map_queues && !is_kdump_kernel()) {
                int i;
 
@@ -3398,7 +3419,6 @@ static void blk_mq_poll_stats_fn(struct blk_stat_callback *cb)
 }
 
 static unsigned long blk_mq_poll_nsecs(struct request_queue *q,
-                                      struct blk_mq_hw_ctx *hctx,
                                       struct request *rq)
 {
        unsigned long ret = 0;
@@ -3431,7 +3451,6 @@ static unsigned long blk_mq_poll_nsecs(struct request_queue *q,
 }
 
 static bool blk_mq_poll_hybrid_sleep(struct request_queue *q,
-                                    struct blk_mq_hw_ctx *hctx,
                                     struct request *rq)
 {
        struct hrtimer_sleeper hs;
@@ -3451,7 +3470,7 @@ static bool blk_mq_poll_hybrid_sleep(struct request_queue *q,
        if (q->poll_nsec > 0)
                nsecs = q->poll_nsec;
        else
-               nsecs = blk_mq_poll_nsecs(q, hctx, rq);
+               nsecs = blk_mq_poll_nsecs(q, rq);
 
        if (!nsecs)
                return false;
@@ -3506,7 +3525,7 @@ static bool blk_mq_poll_hybrid(struct request_queue *q,
                        return false;
        }
 
-       return blk_mq_poll_hybrid_sleep(q, hctx, rq);
+       return blk_mq_poll_hybrid_sleep(q, rq);
 }
 
 /**
index eaaca8f..10bfdfb 100644 (file)
@@ -66,7 +66,8 @@ int blk_mq_alloc_rqs(struct blk_mq_tag_set *set, struct blk_mq_tags *tags,
  */
 void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
                                bool at_head);
-void blk_mq_request_bypass_insert(struct request *rq, bool run_queue);
+void blk_mq_request_bypass_insert(struct request *rq, bool at_head,
+                                 bool run_queue);
 void blk_mq_insert_requests(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx,
                                struct list_head *list);
 
@@ -199,7 +200,7 @@ static inline bool blk_mq_get_dispatch_budget(struct blk_mq_hw_ctx *hctx)
 static inline void __blk_mq_put_driver_tag(struct blk_mq_hw_ctx *hctx,
                                           struct request *rq)
 {
-       blk_mq_put_tag(hctx, hctx->tags, rq->mq_ctx, rq->tag);
+       blk_mq_put_tag(hctx->tags, rq->mq_ctx, rq->tag);
        rq->tag = -1;
 
        if (rq->rq_flags & RQF_MQ_INFLIGHT) {
index c8eda2e..14397b4 100644 (file)
@@ -87,42 +87,6 @@ void blk_set_stacking_limits(struct queue_limits *lim)
 EXPORT_SYMBOL(blk_set_stacking_limits);
 
 /**
- * blk_queue_make_request - define an alternate make_request function for a device
- * @q:  the request queue for the device to be affected
- * @mfn: the alternate make_request function
- *
- * Description:
- *    The normal way for &struct bios to be passed to a device
- *    driver is for them to be collected into requests on a request
- *    queue, and then to allow the device driver to select requests
- *    off that queue when it is ready.  This works well for many block
- *    devices. However some block devices (typically virtual devices
- *    such as md or lvm) do not benefit from the processing on the
- *    request queue, and are served best by having the requests passed
- *    directly to them.  This can be achieved by providing a function
- *    to blk_queue_make_request().
- *
- * Caveat:
- *    The driver that does this *must* be able to deal appropriately
- *    with buffers in "highmemory". This can be accomplished by either calling
- *    kmap_atomic() to get a temporary kernel mapping, or by calling
- *    blk_queue_bounce() to create a buffer in normal memory.
- **/
-void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
-{
-       /*
-        * set defaults
-        */
-       q->nr_requests = BLKDEV_MAX_RQ;
-
-       q->make_request_fn = mfn;
-       blk_queue_dma_alignment(q, 511);
-
-       blk_set_default_limits(&q->limits);
-}
-EXPORT_SYMBOL(blk_queue_make_request);
-
-/**
  * blk_queue_bounce_limit - set bounce buffer limit for queue
  * @q: the request queue for the device
  * @max_addr: the maximum address the device can handle
@@ -664,6 +628,9 @@ void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
                printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n",
                       top, bottom);
        }
+
+       t->backing_dev_info->io_pages =
+               t->limits.max_sectors >> (PAGE_SHIFT - 9);
 }
 EXPORT_SYMBOL(disk_stack_limits);
 
index 05741c6..f87956e 100644 (file)
 
 #include "blk.h"
 
+#define ZONE_COND_NAME(name) [BLK_ZONE_COND_##name] = #name
+static const char *const zone_cond_name[] = {
+       ZONE_COND_NAME(NOT_WP),
+       ZONE_COND_NAME(EMPTY),
+       ZONE_COND_NAME(IMP_OPEN),
+       ZONE_COND_NAME(EXP_OPEN),
+       ZONE_COND_NAME(CLOSED),
+       ZONE_COND_NAME(READONLY),
+       ZONE_COND_NAME(FULL),
+       ZONE_COND_NAME(OFFLINE),
+};
+#undef ZONE_COND_NAME
+
+/**
+ * blk_zone_cond_str - Return string XXX in BLK_ZONE_COND_XXX.
+ * @zone_cond: BLK_ZONE_COND_XXX.
+ *
+ * Description: Centralize block layer function to convert BLK_ZONE_COND_XXX
+ * into string format. Useful in the debugging and tracing zone conditions. For
+ * invalid BLK_ZONE_COND_XXX it returns string "UNKNOWN".
+ */
+const char *blk_zone_cond_str(enum blk_zone_cond zone_cond)
+{
+       static const char *zone_cond_str = "UNKNOWN";
+
+       if (zone_cond < ARRAY_SIZE(zone_cond_name) && zone_cond_name[zone_cond])
+               zone_cond_str = zone_cond_name[zone_cond];
+
+       return zone_cond_str;
+}
+EXPORT_SYMBOL_GPL(blk_zone_cond_str);
+
 static inline sector_t blk_zone_start(struct request_queue *q,
                                      sector_t sector)
 {
@@ -173,7 +205,7 @@ int blkdev_zone_mgmt(struct block_device *bdev, enum req_opf op,
        if (!op_is_zone_mgmt(op))
                return -EOPNOTSUPP;
 
-       if (!nr_sectors || end_sector > capacity)
+       if (end_sector <= sector || end_sector > capacity)
                /* Out of range */
                return -EINVAL;
 
index 0b88843..0a94ec6 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/idr.h>
 #include <linux/blk-mq.h>
+#include <linux/part_stat.h>
 #include <xen/xen.h>
 #include "blk-mq.h"
 #include "blk-mq-sched.h"
@@ -55,8 +56,8 @@ is_flush_rq(struct request *req, struct blk_mq_hw_ctx *hctx)
        return hctx->fq->flush_rq == req;
 }
 
-struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q,
-               int node, int cmd_size, gfp_t flags);
+struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
+                                             gfp_t flags);
 void blk_free_flush_queue(struct blk_flush_queue *q);
 
 void blk_freeze_queue(struct request_queue *q);
@@ -149,6 +150,9 @@ static inline bool integrity_req_gap_front_merge(struct request *req,
        return bvec_gap_to_prev(req->q, &bip->bip_vec[bip->bip_vcnt - 1],
                                bip_next->bip_vec[0].bv_offset);
 }
+
+void blk_integrity_add(struct gendisk *);
+void blk_integrity_del(struct gendisk *);
 #else /* CONFIG_BLK_DEV_INTEGRITY */
 static inline bool integrity_req_gap_back_merge(struct request *req,
                struct bio *next)
@@ -171,6 +175,12 @@ static inline bool bio_integrity_endio(struct bio *bio)
 static inline void bio_integrity_free(struct bio *bio)
 {
 }
+static inline void blk_integrity_add(struct gendisk *disk)
+{
+}
+static inline void blk_integrity_del(struct gendisk *disk)
+{
+}
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
 unsigned long blk_rq_timeout(unsigned long timeout);
@@ -214,6 +224,17 @@ static inline void elevator_exit(struct request_queue *q,
 
 struct hd_struct *__disk_get_part(struct gendisk *disk, int partno);
 
+ssize_t part_size_show(struct device *dev, struct device_attribute *attr,
+               char *buf);
+ssize_t part_stat_show(struct device *dev, struct device_attribute *attr,
+               char *buf);
+ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr,
+               char *buf);
+ssize_t part_fail_show(struct device *dev, struct device_attribute *attr,
+               char *buf);
+ssize_t part_fail_store(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count);
+
 #ifdef CONFIG_FAIL_IO_TIMEOUT
 int blk_should_fake_timeout(struct request_queue *);
 ssize_t part_timeout_show(struct device *, struct device_attribute *, char *);
@@ -354,4 +375,117 @@ void blk_queue_free_zone_bitmaps(struct request_queue *q);
 static inline void blk_queue_free_zone_bitmaps(struct request_queue *q) {}
 #endif
 
+void part_dec_in_flight(struct request_queue *q, struct hd_struct *part,
+                       int rw);
+void part_inc_in_flight(struct request_queue *q, struct hd_struct *part,
+                       int rw);
+void update_io_ticks(struct hd_struct *part, unsigned long now, bool end);
+struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector);
+
+int blk_alloc_devt(struct hd_struct *part, dev_t *devt);
+void blk_free_devt(dev_t devt);
+void blk_invalidate_devt(dev_t devt);
+char *disk_name(struct gendisk *hd, int partno, char *buf);
+#define ADDPART_FLAG_NONE      0
+#define ADDPART_FLAG_RAID      1
+#define ADDPART_FLAG_WHOLEDISK 2
+struct hd_struct *__must_check add_partition(struct gendisk *disk, int partno,
+               sector_t start, sector_t len, int flags,
+               struct partition_meta_info *info);
+void __delete_partition(struct percpu_ref *ref);
+void delete_partition(struct gendisk *disk, int partno);
+int disk_expand_part_tbl(struct gendisk *disk, int target);
+
+static inline int hd_ref_init(struct hd_struct *part)
+{
+       if (percpu_ref_init(&part->ref, __delete_partition, 0,
+                               GFP_KERNEL))
+               return -ENOMEM;
+       return 0;
+}
+
+static inline void hd_struct_get(struct hd_struct *part)
+{
+       percpu_ref_get(&part->ref);
+}
+
+static inline int hd_struct_try_get(struct hd_struct *part)
+{
+       return percpu_ref_tryget_live(&part->ref);
+}
+
+static inline void hd_struct_put(struct hd_struct *part)
+{
+       percpu_ref_put(&part->ref);
+}
+
+static inline void hd_struct_kill(struct hd_struct *part)
+{
+       percpu_ref_kill(&part->ref);
+}
+
+static inline void hd_free_part(struct hd_struct *part)
+{
+       free_part_stats(part);
+       kfree(part->info);
+       percpu_ref_exit(&part->ref);
+}
+
+/*
+ * Any access of part->nr_sects which is not protected by partition
+ * bd_mutex or gendisk bdev bd_mutex, should be done using this
+ * accessor function.
+ *
+ * Code written along the lines of i_size_read() and i_size_write().
+ * CONFIG_PREEMPTION case optimizes the case of UP kernel with preemption
+ * on.
+ */
+static inline sector_t part_nr_sects_read(struct hd_struct *part)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+       sector_t nr_sects;
+       unsigned seq;
+       do {
+               seq = read_seqcount_begin(&part->nr_sects_seq);
+               nr_sects = part->nr_sects;
+       } while (read_seqcount_retry(&part->nr_sects_seq, seq));
+       return nr_sects;
+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
+       sector_t nr_sects;
+
+       preempt_disable();
+       nr_sects = part->nr_sects;
+       preempt_enable();
+       return nr_sects;
+#else
+       return part->nr_sects;
+#endif
+}
+
+/*
+ * Should be called with mutex lock held (typically bd_mutex) of partition
+ * to provide mutual exlusion among writers otherwise seqcount might be
+ * left in wrong state leaving the readers spinning infinitely.
+ */
+static inline void part_nr_sects_write(struct hd_struct *part, sector_t size)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+       write_seqcount_begin(&part->nr_sects_seq);
+       part->nr_sects = size;
+       write_seqcount_end(&part->nr_sects_seq);
+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
+       preempt_disable();
+       part->nr_sects = size;
+       preempt_enable();
+#else
+       part->nr_sects = size;
+#endif
+}
+
+struct request_queue *__blk_alloc_queue(int node_id);
+
+int __bio_add_pc_page(struct request_queue *q, struct bio *bio,
+               struct page *page, unsigned int len, unsigned int offset,
+               bool *same_page);
+
 #endif /* BLK_INTERNAL_H */
index ff62689..06b642b 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/ctype.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kdev_t.h>
@@ -26,7 +27,7 @@
 #include "blk.h"
 
 static DEFINE_MUTEX(block_class_lock);
-struct kobject *block_depr;
+static struct kobject *block_depr;
 
 /* for extended dynamic devt allocation, currently only one major is used */
 #define NR_EXT_DEVT            (1 << MINORBITS)
@@ -46,6 +47,78 @@ static void disk_add_events(struct gendisk *disk);
 static void disk_del_events(struct gendisk *disk);
 static void disk_release_events(struct gendisk *disk);
 
+/*
+ * Set disk capacity and notify if the size is not currently
+ * zero and will not be set to zero
+ */
+void set_capacity_revalidate_and_notify(struct gendisk *disk, sector_t size,
+                                       bool revalidate)
+{
+       sector_t capacity = get_capacity(disk);
+
+       set_capacity(disk, size);
+
+       if (revalidate)
+               revalidate_disk(disk);
+
+       if (capacity != size && capacity != 0 && size != 0) {
+               char *envp[] = { "RESIZE=1", NULL };
+
+               kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp);
+       }
+}
+
+EXPORT_SYMBOL_GPL(set_capacity_revalidate_and_notify);
+
+/*
+ * Format the device name of the indicated disk into the supplied buffer and
+ * return a pointer to that same buffer for convenience.
+ */
+char *disk_name(struct gendisk *hd, int partno, char *buf)
+{
+       if (!partno)
+               snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
+       else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
+               snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
+       else
+               snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
+
+       return buf;
+}
+
+const char *bdevname(struct block_device *bdev, char *buf)
+{
+       return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
+}
+EXPORT_SYMBOL(bdevname);
+
+#ifdef CONFIG_SMP
+static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
+{
+       int cpu;
+
+       memset(stat, 0, sizeof(struct disk_stats));
+       for_each_possible_cpu(cpu) {
+               struct disk_stats *ptr = per_cpu_ptr(part->dkstats, cpu);
+               int group;
+
+               for (group = 0; group < NR_STAT_GROUPS; group++) {
+                       stat->nsecs[group] += ptr->nsecs[group];
+                       stat->sectors[group] += ptr->sectors[group];
+                       stat->ios[group] += ptr->ios[group];
+                       stat->merges[group] += ptr->merges[group];
+               }
+
+               stat->io_ticks += ptr->io_ticks;
+       }
+}
+#else /* CONFIG_SMP */
+static void part_stat_read_all(struct hd_struct *part, struct disk_stats *stat)
+{
+       memcpy(stat, &part->dkstats, sizeof(struct disk_stats));
+}
+#endif /* CONFIG_SMP */
+
 void part_inc_in_flight(struct request_queue *q, struct hd_struct *part, int rw)
 {
        if (queue_is_mq(q))
@@ -66,7 +139,8 @@ void part_dec_in_flight(struct request_queue *q, struct hd_struct *part, int rw)
                part_stat_local_dec(&part_to_disk(part)->part0, in_flight[rw]);
 }
 
-unsigned int part_in_flight(struct request_queue *q, struct hd_struct *part)
+static unsigned int part_in_flight(struct request_queue *q,
+               struct hd_struct *part)
 {
        int cpu;
        unsigned int inflight;
@@ -86,8 +160,8 @@ unsigned int part_in_flight(struct request_queue *q, struct hd_struct *part)
        return inflight;
 }
 
-void part_in_flight_rw(struct request_queue *q, struct hd_struct *part,
-                      unsigned int inflight[2])
+static void part_in_flight_rw(struct request_queue *q, struct hd_struct *part,
+               unsigned int inflight[2])
 {
        int cpu;
 
@@ -143,7 +217,6 @@ struct hd_struct *disk_get_part(struct gendisk *disk, int partno)
 
        return part;
 }
-EXPORT_SYMBOL_GPL(disk_get_part);
 
 /**
  * disk_part_iter_init - initialize partition iterator
@@ -299,7 +372,42 @@ struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector)
        }
        return &disk->part0;
 }
-EXPORT_SYMBOL_GPL(disk_map_sector_rcu);
+
+/**
+ * disk_has_partitions
+ * @disk: gendisk of interest
+ *
+ * Walk through the partition table and check if valid partition exists.
+ *
+ * CONTEXT:
+ * Don't care.
+ *
+ * RETURNS:
+ * True if the gendisk has at least one valid non-zero size partition.
+ * Otherwise false.
+ */
+bool disk_has_partitions(struct gendisk *disk)
+{
+       struct disk_part_tbl *ptbl;
+       int i;
+       bool ret = false;
+
+       rcu_read_lock();
+       ptbl = rcu_dereference(disk->part_tbl);
+
+       /* Iterate partitions skipping the whole device at index 0 */
+       for (i = 1; i < ptbl->len; i++) {
+               if (rcu_dereference(ptbl->part[i])) {
+                       ret = true;
+                       break;
+               }
+       }
+
+       rcu_read_unlock();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(disk_has_partitions);
 
 /*
  * Can be deleted altogether. Later.
@@ -908,7 +1016,6 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
        }
        return disk;
 }
-EXPORT_SYMBOL(get_gendisk);
 
 /**
  * bdget_disk - do bdget() by gendisk and partition number
@@ -1154,6 +1261,67 @@ static ssize_t disk_ro_show(struct device *dev,
        return sprintf(buf, "%d\n", get_disk_ro(disk) ? 1 : 0);
 }
 
+ssize_t part_size_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+
+       return sprintf(buf, "%llu\n",
+               (unsigned long long)part_nr_sects_read(p));
+}
+
+ssize_t part_stat_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+       struct request_queue *q = part_to_disk(p)->queue;
+       struct disk_stats stat;
+       unsigned int inflight;
+
+       part_stat_read_all(p, &stat);
+       inflight = part_in_flight(q, p);
+
+       return sprintf(buf,
+               "%8lu %8lu %8llu %8u "
+               "%8lu %8lu %8llu %8u "
+               "%8u %8u %8u "
+               "%8lu %8lu %8llu %8u "
+               "%8lu %8u"
+               "\n",
+               stat.ios[STAT_READ],
+               stat.merges[STAT_READ],
+               (unsigned long long)stat.sectors[STAT_READ],
+               (unsigned int)div_u64(stat.nsecs[STAT_READ], NSEC_PER_MSEC),
+               stat.ios[STAT_WRITE],
+               stat.merges[STAT_WRITE],
+               (unsigned long long)stat.sectors[STAT_WRITE],
+               (unsigned int)div_u64(stat.nsecs[STAT_WRITE], NSEC_PER_MSEC),
+               inflight,
+               jiffies_to_msecs(stat.io_ticks),
+               (unsigned int)div_u64(stat.nsecs[STAT_READ] +
+                                     stat.nsecs[STAT_WRITE] +
+                                     stat.nsecs[STAT_DISCARD] +
+                                     stat.nsecs[STAT_FLUSH],
+                                               NSEC_PER_MSEC),
+               stat.ios[STAT_DISCARD],
+               stat.merges[STAT_DISCARD],
+               (unsigned long long)stat.sectors[STAT_DISCARD],
+               (unsigned int)div_u64(stat.nsecs[STAT_DISCARD], NSEC_PER_MSEC),
+               stat.ios[STAT_FLUSH],
+               (unsigned int)div_u64(stat.nsecs[STAT_FLUSH], NSEC_PER_MSEC));
+}
+
+ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+       struct request_queue *q = part_to_disk(p)->queue;
+       unsigned int inflight[2];
+
+       part_in_flight_rw(q, p, inflight);
+       return sprintf(buf, "%8u %8u\n", inflight[0], inflight[1]);
+}
+
 static ssize_t disk_capability_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
@@ -1192,10 +1360,33 @@ static DEVICE_ATTR(capability, 0444, disk_capability_show, NULL);
 static DEVICE_ATTR(stat, 0444, part_stat_show, NULL);
 static DEVICE_ATTR(inflight, 0444, part_inflight_show, NULL);
 static DEVICE_ATTR(badblocks, 0644, disk_badblocks_show, disk_badblocks_store);
+
 #ifdef CONFIG_FAIL_MAKE_REQUEST
+ssize_t part_fail_show(struct device *dev,
+                      struct device_attribute *attr, char *buf)
+{
+       struct hd_struct *p = dev_to_part(dev);
+
+       return sprintf(buf, "%d\n", p->make_it_fail);
+}
+
+ssize_t part_fail_store(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t count)
+{
+       struct hd_struct *p = dev_to_part(dev);
+       int i;
+
+       if (count > 0 && sscanf(buf, "%d", &i) > 0)
+               p->make_it_fail = (i == 0) ? 0 : 1;
+
+       return count;
+}
+
 static struct device_attribute dev_attr_fail =
        __ATTR(make-it-fail, 0644, part_fail_show, part_fail_store);
-#endif
+#endif /* CONFIG_FAIL_MAKE_REQUEST */
+
 #ifdef CONFIG_FAIL_IO_TIMEOUT
 static struct device_attribute dev_attr_fail_timeout =
        __ATTR(io-timeout-fail, 0644, part_timeout_show, part_timeout_store);
@@ -1342,8 +1533,8 @@ static char *block_devnode(struct device *dev, umode_t *mode,
 {
        struct gendisk *disk = dev_to_disk(dev);
 
-       if (disk->devnode)
-               return disk->devnode(disk, mode);
+       if (disk->fops->devnode)
+               return disk->fops->devnode(disk, mode);
        return NULL;
 }
 
@@ -1369,6 +1560,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)
        struct hd_struct *hd;
        char buf[BDEVNAME_SIZE];
        unsigned int inflight;
+       struct disk_stats stat;
 
        /*
        if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next)
@@ -1380,7 +1572,9 @@ static int diskstats_show(struct seq_file *seqf, void *v)
 
        disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0);
        while ((hd = disk_part_iter_next(&piter))) {
+               part_stat_read_all(hd, &stat);
                inflight = part_in_flight(gp->queue, hd);
+
                seq_printf(seqf, "%4d %7d %s "
                           "%lu %lu %lu %u "
                           "%lu %lu %lu %u "
@@ -1390,23 +1584,31 @@ static int diskstats_show(struct seq_file *seqf, void *v)
                           "\n",
                           MAJOR(part_devt(hd)), MINOR(part_devt(hd)),
                           disk_name(gp, hd->partno, buf),
-                          part_stat_read(hd, ios[STAT_READ]),
-                          part_stat_read(hd, merges[STAT_READ]),
-                          part_stat_read(hd, sectors[STAT_READ]),
-                          (unsigned int)part_stat_read_msecs(hd, STAT_READ),
-                          part_stat_read(hd, ios[STAT_WRITE]),
-                          part_stat_read(hd, merges[STAT_WRITE]),
-                          part_stat_read(hd, sectors[STAT_WRITE]),
-                          (unsigned int)part_stat_read_msecs(hd, STAT_WRITE),
+                          stat.ios[STAT_READ],
+                          stat.merges[STAT_READ],
+                          stat.sectors[STAT_READ],
+                          (unsigned int)div_u64(stat.nsecs[STAT_READ],
+                                                       NSEC_PER_MSEC),
+                          stat.ios[STAT_WRITE],
+                          stat.merges[STAT_WRITE],
+                          stat.sectors[STAT_WRITE],
+                          (unsigned int)div_u64(stat.nsecs[STAT_WRITE],
+                                                       NSEC_PER_MSEC),
                           inflight,
-                          jiffies_to_msecs(part_stat_read(hd, io_ticks)),
-                          jiffies_to_msecs(part_stat_read(hd, time_in_queue)),
-                          part_stat_read(hd, ios[STAT_DISCARD]),
-                          part_stat_read(hd, merges[STAT_DISCARD]),
-                          part_stat_read(hd, sectors[STAT_DISCARD]),
-                          (unsigned int)part_stat_read_msecs(hd, STAT_DISCARD),
-                          part_stat_read(hd, ios[STAT_FLUSH]),
-                          (unsigned int)part_stat_read_msecs(hd, STAT_FLUSH)
+                          jiffies_to_msecs(stat.io_ticks),
+                          (unsigned int)div_u64(stat.nsecs[STAT_READ] +
+                                                stat.nsecs[STAT_WRITE] +
+                                                stat.nsecs[STAT_DISCARD] +
+                                                stat.nsecs[STAT_FLUSH],
+                                                       NSEC_PER_MSEC),
+                          stat.ios[STAT_DISCARD],
+                          stat.merges[STAT_DISCARD],
+                          stat.sectors[STAT_DISCARD],
+                          (unsigned int)div_u64(stat.nsecs[STAT_DISCARD],
+                                                NSEC_PER_MSEC),
+                          stat.ios[STAT_FLUSH],
+                          (unsigned int)div_u64(stat.nsecs[STAT_FLUSH],
+                                                NSEC_PER_MSEC)
                        );
        }
        disk_part_iter_exit(&piter);
@@ -1463,7 +1665,6 @@ dev_t blk_lookup_devt(const char *name, int partno)
        class_dev_iter_exit(&iter);
        return devt;
 }
-EXPORT_SYMBOL(blk_lookup_devt);
 
 struct gendisk *__alloc_disk_node(int minors, int node_id)
 {
index 127194b..6e827de 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/blktrace_api.h>
 #include <linux/pr.h>
 #include <linux/uaccess.h>
+#include "blk.h"
 
 static int blkpg_do_ioctl(struct block_device *bdev,
                          struct blkpg_partition __user *upart, int op)
index 325cbba..b486b3e 100644 (file)
@@ -36,6 +36,7 @@ enum opal_response_token {
 
 #define DTAERROR_NO_METHOD_STATUS 0x89
 #define GENERIC_HOST_SESSION_NUM 0x41
+#define FIRST_TPER_SESSION_NUM 4096
 
 #define TPER_SYNC_SUPPORTED 0x01
 #define MBR_ENABLED_MASK 0x10
index 2f276b6..a7f05cd 100644 (file)
@@ -3,8 +3,7 @@
 # Makefile for the linux kernel.
 #
 
-obj-$(CONFIG_BLOCK) := check.o
-
+obj-$(CONFIG_BLOCK) += core.o
 obj-$(CONFIG_ACORN_PARTITION) += acorn.o
 obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
 obj-$(CONFIG_ATARI_PARTITION) += atari.o
index 7587700..c64c57b 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/adfs_fs.h>
 
 #include "check.h"
-#include "acorn.h"
 
 /*
  * Partition types. (Oh for reusability)
diff --git a/block/partitions/acorn.h b/block/partitions/acorn.h
deleted file mode 100644 (file)
index 67b0660..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * linux/fs/partitions/acorn.h
- *
- * Copyright (C) 1996-2001 Russell King.
- *
- *  I _hate_ this partitioning mess - why can't we have one defined
- *  format, and everyone stick to it?
- */
-
-int adfspart_check_CUMANA(struct parsed_partitions *state);
-int adfspart_check_ADFS(struct parsed_partitions *state);
-int adfspart_check_ICS(struct parsed_partitions *state);
-int adfspart_check_POWERTEC(struct parsed_partitions *state);
-int adfspart_check_EESOX(struct parsed_partitions *state);
index 903f3ed..c7b4fd1 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include "check.h"
-#include "aix.h"
 
 struct lvm_rec {
        char lvm_id[4]; /* "_LVM" */
diff --git a/block/partitions/aix.h b/block/partitions/aix.h
deleted file mode 100644 (file)
index b4449f0..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-extern int aix_partition(struct parsed_partitions *state);
index 5609366..9526491 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/affs_hardblocks.h>
 
 #include "check.h"
-#include "amiga.h"
 
 static __inline__ u32
 checksum_block(__be32 *m, int size)
@@ -42,9 +41,8 @@ int amiga_partition(struct parsed_partitions *state)
                        goto rdb_done;
                data = read_part_sector(state, blk, &sect);
                if (!data) {
-                       if (warn_no_part)
-                               pr_err("Dev %s: unable to read RDB block %d\n",
-                                      bdevname(state->bdev, b), blk);
+                       pr_err("Dev %s: unable to read RDB block %d\n",
+                              bdevname(state->bdev, b), blk);
                        res = -1;
                        goto rdb_done;
                }
@@ -85,9 +83,8 @@ int amiga_partition(struct parsed_partitions *state)
                blk *= blksize; /* Read in terms partition table understands */
                data = read_part_sector(state, blk, &sect);
                if (!data) {
-                       if (warn_no_part)
-                               pr_err("Dev %s: unable to read partition block %d\n",
-                                      bdevname(state->bdev, b), blk);
+                       pr_err("Dev %s: unable to read partition block %d\n",
+                              bdevname(state->bdev, b), blk);
                        res = -1;
                        goto rdb_done;
                }
diff --git a/block/partitions/amiga.h b/block/partitions/amiga.h
deleted file mode 100644 (file)
index 7e63f4d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  fs/partitions/amiga.h
- */
-
-int amiga_partition(struct parsed_partitions *state);
-
index 01c2b94..6782024 100644 (file)
@@ -34,4 +34,3 @@ struct rootsector
   u16 checksum;                        /* checksum for bootable disks */
 } __packed;
 
-int atari_partition(struct parsed_partitions *state);
diff --git a/block/partitions/check.c b/block/partitions/check.c
deleted file mode 100644 (file)
index ffe408f..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- *  fs/partitions/check.c
- *
- *  Code extracted from drivers/block/genhd.c
- *  Copyright (C) 1991-1998  Linus Torvalds
- *  Re-organised Feb 1998 Russell King
- *
- *  We now have independent partition support from the
- *  block drivers, which allows all the partition code to
- *  be grouped in one location, and it to be mostly self
- *  contained.
- *
- *  Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
- */
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/ctype.h>
-#include <linux/genhd.h>
-
-#include "check.h"
-
-#include "acorn.h"
-#include "amiga.h"
-#include "atari.h"
-#include "ldm.h"
-#include "mac.h"
-#include "msdos.h"
-#include "osf.h"
-#include "sgi.h"
-#include "sun.h"
-#include "ibm.h"
-#include "ultrix.h"
-#include "efi.h"
-#include "karma.h"
-#include "sysv68.h"
-#include "cmdline.h"
-
-int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
-
-static int (*check_part[])(struct parsed_partitions *) = {
-       /*
-        * Probe partition formats with tables at disk address 0
-        * that also have an ADFS boot block at 0xdc0.
-        */
-#ifdef CONFIG_ACORN_PARTITION_ICS
-       adfspart_check_ICS,
-#endif
-#ifdef CONFIG_ACORN_PARTITION_POWERTEC
-       adfspart_check_POWERTEC,
-#endif
-#ifdef CONFIG_ACORN_PARTITION_EESOX
-       adfspart_check_EESOX,
-#endif
-
-       /*
-        * Now move on to formats that only have partition info at
-        * disk address 0xdc0.  Since these may also have stale
-        * PC/BIOS partition tables, they need to come before
-        * the msdos entry.
-        */
-#ifdef CONFIG_ACORN_PARTITION_CUMANA
-       adfspart_check_CUMANA,
-#endif
-#ifdef CONFIG_ACORN_PARTITION_ADFS
-       adfspart_check_ADFS,
-#endif
-
-#ifdef CONFIG_CMDLINE_PARTITION
-       cmdline_partition,
-#endif
-#ifdef CONFIG_EFI_PARTITION
-       efi_partition,          /* this must come before msdos */
-#endif
-#ifdef CONFIG_SGI_PARTITION
-       sgi_partition,
-#endif
-#ifdef CONFIG_LDM_PARTITION
-       ldm_partition,          /* this must come before msdos */
-#endif
-#ifdef CONFIG_MSDOS_PARTITION
-       msdos_partition,
-#endif
-#ifdef CONFIG_OSF_PARTITION
-       osf_partition,
-#endif
-#ifdef CONFIG_SUN_PARTITION
-       sun_partition,
-#endif
-#ifdef CONFIG_AMIGA_PARTITION
-       amiga_partition,
-#endif
-#ifdef CONFIG_ATARI_PARTITION
-       atari_partition,
-#endif
-#ifdef CONFIG_MAC_PARTITION
-       mac_partition,
-#endif
-#ifdef CONFIG_ULTRIX_PARTITION
-       ultrix_partition,
-#endif
-#ifdef CONFIG_IBM_PARTITION
-       ibm_partition,
-#endif
-#ifdef CONFIG_KARMA_PARTITION
-       karma_partition,
-#endif
-#ifdef CONFIG_SYSV68_PARTITION
-       sysv68_partition,
-#endif
-       NULL
-};
-
-static struct parsed_partitions *allocate_partitions(struct gendisk *hd)
-{
-       struct parsed_partitions *state;
-       int nr;
-
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (!state)
-               return NULL;
-
-       nr = disk_max_parts(hd);
-       state->parts = vzalloc(array_size(nr, sizeof(state->parts[0])));
-       if (!state->parts) {
-               kfree(state);
-               return NULL;
-       }
-
-       state->limit = nr;
-
-       return state;
-}
-
-void free_partitions(struct parsed_partitions *state)
-{
-       vfree(state->parts);
-       kfree(state);
-}
-
-struct parsed_partitions *
-check_partition(struct gendisk *hd, struct block_device *bdev)
-{
-       struct parsed_partitions *state;
-       int i, res, err;
-
-       state = allocate_partitions(hd);
-       if (!state)
-               return NULL;
-       state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
-       if (!state->pp_buf) {
-               free_partitions(state);
-               return NULL;
-       }
-       state->pp_buf[0] = '\0';
-
-       state->bdev = bdev;
-       disk_name(hd, 0, state->name);
-       snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
-       if (isdigit(state->name[strlen(state->name)-1]))
-               sprintf(state->name, "p");
-
-       i = res = err = 0;
-       while (!res && check_part[i]) {
-               memset(state->parts, 0, state->limit * sizeof(state->parts[0]));
-               res = check_part[i++](state);
-               if (res < 0) {
-                       /* We have hit an I/O error which we don't report now.
-                       * But record it, and let the others do their job.
-                       */
-                       err = res;
-                       res = 0;
-               }
-
-       }
-       if (res > 0) {
-               printk(KERN_INFO "%s", state->pp_buf);
-
-               free_page((unsigned long)state->pp_buf);
-               return state;
-       }
-       if (state->access_beyond_eod)
-               err = -ENOSPC;
-       if (err)
-       /* The partition is unrecognized. So report I/O errors if there were any */
-               res = err;
-       if (res) {
-               if (warn_no_part)
-                       strlcat(state->pp_buf,
-                               " unable to read partition table\n", PAGE_SIZE);
-               printk(KERN_INFO "%s", state->pp_buf);
-       }
-
-       free_page((unsigned long)state->pp_buf);
-       free_partitions(state);
-       return ERR_PTR(res);
-}
index 6042f76..c577e9e 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/pagemap.h>
 #include <linux/blkdev.h>
 #include <linux/genhd.h>
+#include "../blk.h"
 
 /*
  * add_gd_partition adds a partitions details to the devices partition
@@ -23,19 +24,14 @@ struct parsed_partitions {
        char *pp_buf;
 };
 
-void free_partitions(struct parsed_partitions *state);
+typedef struct {
+       struct page *v;
+} Sector;
 
-struct parsed_partitions *
-check_partition(struct gendisk *, struct block_device *);
-
-static inline void *read_part_sector(struct parsed_partitions *state,
-                                    sector_t n, Sector *p)
+void *read_part_sector(struct parsed_partitions *state, sector_t n, Sector *p);
+static inline void put_dev_sector(Sector p)
 {
-       if (n >= get_capacity(state->bdev->bd_disk)) {
-               state->access_beyond_eod = true;
-               return NULL;
-       }
-       return read_dev_sector(state->bdev, n, p);
+       put_page(p.v);
 }
 
 static inline void
@@ -51,5 +47,24 @@ put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
        }
 }
 
-extern int warn_no_part;
-
+/* detection routines go here in alphabetical order: */
+int adfspart_check_ADFS(struct parsed_partitions *state);
+int adfspart_check_CUMANA(struct parsed_partitions *state);
+int adfspart_check_EESOX(struct parsed_partitions *state);
+int adfspart_check_ICS(struct parsed_partitions *state);
+int adfspart_check_POWERTEC(struct parsed_partitions *state);
+int aix_partition(struct parsed_partitions *state);
+int amiga_partition(struct parsed_partitions *state);
+int atari_partition(struct parsed_partitions *state);
+int cmdline_partition(struct parsed_partitions *state);
+int efi_partition(struct parsed_partitions *state);
+int ibm_partition(struct parsed_partitions *);
+int karma_partition(struct parsed_partitions *state);
+int ldm_partition(struct parsed_partitions *state);
+int mac_partition(struct parsed_partitions *state);
+int msdos_partition(struct parsed_partitions *state);
+int osf_partition(struct parsed_partitions *state);
+int sgi_partition(struct parsed_partitions *state);
+int sun_partition(struct parsed_partitions *state);
+int sysv68_partition(struct parsed_partitions *state);
+int ultrix_partition(struct parsed_partitions *state);
index f1edd54..8f545c3 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/cmdline-parser.h>
 
 #include "check.h"
-#include "cmdline.h"
 
 static char *cmdline;
 static struct cmdline_parts *bdev_parts;
diff --git a/block/partitions/cmdline.h b/block/partitions/cmdline.h
deleted file mode 100644 (file)
index e64a316..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-int cmdline_partition(struct parsed_partitions *state);
similarity index 72%
rename from block/partition-generic.c
rename to block/partitions/core.c
index 564fae7..b79c451 100644 (file)
 // SPDX-License-Identifier: GPL-2.0
 /*
- *  Code extracted from drivers/block/genhd.c
- *  Copyright (C) 1991-1998  Linus Torvalds
- *  Re-organised Feb 1998 Russell King
- *
- *  We now have independent partition support from the
- *  block drivers, which allows all the partition code to
- *  be grouped in one location, and it to be mostly self
- *  contained.
+ * Copyright (C) 1991-1998  Linus Torvalds
+ * Re-organised Feb 1998 Russell King
  */
-
-#include <linux/init.h>
-#include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/kmod.h>
 #include <linux/ctype.h>
 #include <linux/genhd.h>
+#include <linux/vmalloc.h>
 #include <linux/blktrace_api.h>
+#include <linux/raid/detect.h>
+#include "check.h"
 
-#include "partitions/check.h"
+static int (*check_part[])(struct parsed_partitions *) = {
+       /*
+        * Probe partition formats with tables at disk address 0
+        * that also have an ADFS boot block at 0xdc0.
+        */
+#ifdef CONFIG_ACORN_PARTITION_ICS
+       adfspart_check_ICS,
+#endif
+#ifdef CONFIG_ACORN_PARTITION_POWERTEC
+       adfspart_check_POWERTEC,
+#endif
+#ifdef CONFIG_ACORN_PARTITION_EESOX
+       adfspart_check_EESOX,
+#endif
 
-#ifdef CONFIG_BLK_DEV_MD
-extern void md_autodetect_dev(dev_t dev);
+       /*
+        * Now move on to formats that only have partition info at
+        * disk address 0xdc0.  Since these may also have stale
+        * PC/BIOS partition tables, they need to come before
+        * the msdos entry.
+        */
+#ifdef CONFIG_ACORN_PARTITION_CUMANA
+       adfspart_check_CUMANA,
+#endif
+#ifdef CONFIG_ACORN_PARTITION_ADFS
+       adfspart_check_ADFS,
 #endif
-/*
- * disk_name() is used by partition check code and the genhd driver.
- * It formats the devicename of the indicated disk into
- * the supplied buffer (of size at least 32), and returns
- * a pointer to that same buffer (for convenience).
- */
 
-char *disk_name(struct gendisk *hd, int partno, char *buf)
+#ifdef CONFIG_CMDLINE_PARTITION
+       cmdline_partition,
+#endif
+#ifdef CONFIG_EFI_PARTITION
+       efi_partition,          /* this must come before msdos */
+#endif
+#ifdef CONFIG_SGI_PARTITION
+       sgi_partition,
+#endif
+#ifdef CONFIG_LDM_PARTITION
+       ldm_partition,          /* this must come before msdos */
+#endif
+#ifdef CONFIG_MSDOS_PARTITION
+       msdos_partition,
+#endif
+#ifdef CONFIG_OSF_PARTITION
+       osf_partition,
+#endif
+#ifdef CONFIG_SUN_PARTITION
+       sun_partition,
+#endif
+#ifdef CONFIG_AMIGA_PARTITION
+       amiga_partition,
+#endif
+#ifdef CONFIG_ATARI_PARTITION
+       atari_partition,
+#endif
+#ifdef CONFIG_MAC_PARTITION
+       mac_partition,
+#endif
+#ifdef CONFIG_ULTRIX_PARTITION
+       ultrix_partition,
+#endif
+#ifdef CONFIG_IBM_PARTITION
+       ibm_partition,
+#endif
+#ifdef CONFIG_KARMA_PARTITION
+       karma_partition,
+#endif
+#ifdef CONFIG_SYSV68_PARTITION
+       sysv68_partition,
+#endif
+       NULL
+};
+
+static struct parsed_partitions *allocate_partitions(struct gendisk *hd)
 {
-       if (!partno)
-               snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
-       else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
-               snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno);
-       else
-               snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno);
+       struct parsed_partitions *state;
+       int nr;
 
-       return buf;
-}
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return NULL;
 
-const char *bdevname(struct block_device *bdev, char *buf)
-{
-       return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf);
-}
+       nr = disk_max_parts(hd);
+       state->parts = vzalloc(array_size(nr, sizeof(state->parts[0])));
+       if (!state->parts) {
+               kfree(state);
+               return NULL;
+       }
 
-EXPORT_SYMBOL(bdevname);
+       state->limit = nr;
 
-const char *bio_devname(struct bio *bio, char *buf)
-{
-       return disk_name(bio->bi_disk, bio->bi_partno, buf);
+       return state;
 }
-EXPORT_SYMBOL(bio_devname);
 
-/*
- * There's very little reason to use this, you should really
- * have a struct block_device just about everywhere and use
- * bdevname() instead.
- */
-const char *__bdevname(dev_t dev, char *buffer)
+static void free_partitions(struct parsed_partitions *state)
 {
-       scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)",
-                               MAJOR(dev), MINOR(dev));
-       return buffer;
+       vfree(state->parts);
+       kfree(state);
 }
 
-EXPORT_SYMBOL(__bdevname);
+static struct parsed_partitions *check_partition(struct gendisk *hd,
+               struct block_device *bdev)
+{
+       struct parsed_partitions *state;
+       int i, res, err;
+
+       state = allocate_partitions(hd);
+       if (!state)
+               return NULL;
+       state->pp_buf = (char *)__get_free_page(GFP_KERNEL);
+       if (!state->pp_buf) {
+               free_partitions(state);
+               return NULL;
+       }
+       state->pp_buf[0] = '\0';
+
+       state->bdev = bdev;
+       disk_name(hd, 0, state->name);
+       snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name);
+       if (isdigit(state->name[strlen(state->name)-1]))
+               sprintf(state->name, "p");
+
+       i = res = err = 0;
+       while (!res && check_part[i]) {
+               memset(state->parts, 0, state->limit * sizeof(state->parts[0]));
+               res = check_part[i++](state);
+               if (res < 0) {
+                       /*
+                        * We have hit an I/O error which we don't report now.
+                        * But record it, and let the others do their job.
+                        */
+                       err = res;
+                       res = 0;
+               }
+
+       }
+       if (res > 0) {
+               printk(KERN_INFO "%s", state->pp_buf);
+
+               free_page((unsigned long)state->pp_buf);
+               return state;
+       }
+       if (state->access_beyond_eod)
+               err = -ENOSPC;
+       /*
+        * The partition is unrecognized. So report I/O errors if there were any
+        */
+       if (err)
+               res = err;
+       if (res) {
+               strlcat(state->pp_buf,
+                       " unable to read partition table\n", PAGE_SIZE);
+               printk(KERN_INFO "%s", state->pp_buf);
+       }
+
+       free_page((unsigned long)state->pp_buf);
+       free_partitions(state);
+       return ERR_PTR(res);
+}
 
 static ssize_t part_partition_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
@@ -87,13 +188,6 @@ static ssize_t part_start_show(struct device *dev,
        return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect);
 }
 
-ssize_t part_size_show(struct device *dev,
-                      struct device_attribute *attr, char *buf)
-{
-       struct hd_struct *p = dev_to_part(dev);
-       return sprintf(buf, "%llu\n",(unsigned long long)part_nr_sects_read(p));
-}
-
 static ssize_t part_ro_show(struct device *dev,
                            struct device_attribute *attr, char *buf)
 {
@@ -115,74 +209,6 @@ static ssize_t part_discard_alignment_show(struct device *dev,
        return sprintf(buf, "%u\n", p->discard_alignment);
 }
 
-ssize_t part_stat_show(struct device *dev,
-                      struct device_attribute *attr, char *buf)
-{
-       struct hd_struct *p = dev_to_part(dev);
-       struct request_queue *q = part_to_disk(p)->queue;
-       unsigned int inflight;
-
-       inflight = part_in_flight(q, p);
-       return sprintf(buf,
-               "%8lu %8lu %8llu %8u "
-               "%8lu %8lu %8llu %8u "
-               "%8u %8u %8u "
-               "%8lu %8lu %8llu %8u "
-               "%8lu %8u"
-               "\n",
-               part_stat_read(p, ios[STAT_READ]),
-               part_stat_read(p, merges[STAT_READ]),
-               (unsigned long long)part_stat_read(p, sectors[STAT_READ]),
-               (unsigned int)part_stat_read_msecs(p, STAT_READ),
-               part_stat_read(p, ios[STAT_WRITE]),
-               part_stat_read(p, merges[STAT_WRITE]),
-               (unsigned long long)part_stat_read(p, sectors[STAT_WRITE]),
-               (unsigned int)part_stat_read_msecs(p, STAT_WRITE),
-               inflight,
-               jiffies_to_msecs(part_stat_read(p, io_ticks)),
-               jiffies_to_msecs(part_stat_read(p, time_in_queue)),
-               part_stat_read(p, ios[STAT_DISCARD]),
-               part_stat_read(p, merges[STAT_DISCARD]),
-               (unsigned long long)part_stat_read(p, sectors[STAT_DISCARD]),
-               (unsigned int)part_stat_read_msecs(p, STAT_DISCARD),
-               part_stat_read(p, ios[STAT_FLUSH]),
-               (unsigned int)part_stat_read_msecs(p, STAT_FLUSH));
-}
-
-ssize_t part_inflight_show(struct device *dev, struct device_attribute *attr,
-                          char *buf)
-{
-       struct hd_struct *p = dev_to_part(dev);
-       struct request_queue *q = part_to_disk(p)->queue;
-       unsigned int inflight[2];
-
-       part_in_flight_rw(q, p, inflight);
-       return sprintf(buf, "%8u %8u\n", inflight[0], inflight[1]);
-}
-
-#ifdef CONFIG_FAIL_MAKE_REQUEST
-ssize_t part_fail_show(struct device *dev,
-                      struct device_attribute *attr, char *buf)
-{
-       struct hd_struct *p = dev_to_part(dev);
-
-       return sprintf(buf, "%d\n", p->make_it_fail);
-}
-
-ssize_t part_fail_store(struct device *dev,
-                       struct device_attribute *attr,
-                       const char *buf, size_t count)
-{
-       struct hd_struct *p = dev_to_part(dev);
-       int i;
-
-       if (count > 0 && sscanf(buf, "%d", &i) > 0)
-               p->make_it_fail = (i == 0) ? 0 : 1;
-
-       return count;
-}
-#endif
-
 static DEVICE_ATTR(partition, 0444, part_partition_show, NULL);
 static DEVICE_ATTR(start, 0444, part_start_show, NULL);
 static DEVICE_ATTR(size, 0444, part_size_show, NULL);
@@ -369,7 +395,9 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        p->policy = get_disk_ro(disk);
 
        if (info) {
-               struct partition_meta_info *pinfo = alloc_part_info(disk);
+               struct partition_meta_info *pinfo;
+
+               pinfo = kzalloc_node(sizeof(*pinfo), GFP_KERNEL, disk->node_id);
                if (!pinfo) {
                        err = -ENOMEM;
                        goto out_free_stats;
@@ -428,7 +456,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        return p;
 
 out_free_info:
-       free_part_info(p);
+       kfree(p->info);
 out_free_stats:
        free_part_stats(p);
 out_free:
@@ -525,10 +553,10 @@ static bool blk_add_partition(struct gendisk *disk, struct block_device *bdev,
                return true;
        }
 
-#ifdef CONFIG_BLK_DEV_MD
-       if (state->parts[p].flags & ADDPART_FLAG_RAID)
+       if (IS_BUILTIN(CONFIG_BLK_DEV_MD) &&
+           (state->parts[p].flags & ADDPART_FLAG_RAID))
                md_autodetect_dev(part_to_dev(part)->devt);
-#endif
+
        return true;
 }
 
@@ -602,22 +630,29 @@ out_free_state:
        return ret;
 }
 
-unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
+void *read_part_sector(struct parsed_partitions *state, sector_t n, Sector *p)
 {
-       struct address_space *mapping = bdev->bd_inode->i_mapping;
+       struct address_space *mapping = state->bdev->bd_inode->i_mapping;
        struct page *page;
 
-       page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_SHIFT-9)), NULL);
-       if (!IS_ERR(page)) {
-               if (PageError(page))
-                       goto fail;
-               p->v = page;
-               return (unsigned char *)page_address(page) +  ((n & ((1 << (PAGE_SHIFT - 9)) - 1)) << 9);
-fail:
-               put_page(page);
+       if (n >= get_capacity(state->bdev->bd_disk)) {
+               state->access_beyond_eod = true;
+               return NULL;
        }
+
+       page = read_mapping_page(mapping,
+                       (pgoff_t)(n >> (PAGE_SHIFT - 9)), NULL);
+       if (IS_ERR(page))
+               goto out;
+       if (PageError(page))
+               goto out_put_page;
+
+       p->v = page;
+       return (unsigned char *)page_address(page) +
+                       ((n & ((1 << (PAGE_SHIFT - 9)) - 1)) << SECTOR_SHIFT);
+out_put_page:
+       put_page(page);
+out:
        p->v = NULL;
        return NULL;
 }
-
-EXPORT_SYMBOL(read_dev_sector);
index db2fef7..b64bfdd 100644 (file)
@@ -657,6 +657,31 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
 }
 
 /**
+ * utf16_le_to_7bit(): Naively converts a UTF-16LE string to 7-bit ASCII characters
+ * @in: input UTF-16LE string
+ * @size: size of the input string
+ * @out: output string ptr, should be capable to store @size+1 characters
+ *
+ * Description: Converts @size UTF16-LE symbols from @in string to 7-bit
+ * ASCII characters and stores them to @out. Adds trailing zero to @out array.
+ */
+static void utf16_le_to_7bit(const __le16 *in, unsigned int size, u8 *out)
+{
+       unsigned int i = 0;
+
+       out[size] = 0;
+
+       while (i < size) {
+               u8 c = le16_to_cpu(in[i]) & 0xff;
+
+               if (c && !isprint(c))
+                       c = '!';
+               out[i] = c;
+               i++;
+       }
+}
+
+/**
  * efi_partition(struct parsed_partitions *state)
  * @state: disk parsed partitions
  *
@@ -692,7 +717,6 @@ int efi_partition(struct parsed_partitions *state)
 
        for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
                struct partition_meta_info *info;
-               unsigned label_count = 0;
                unsigned label_max;
                u64 start = le64_to_cpu(ptes[i].starting_lba);
                u64 size = le64_to_cpu(ptes[i].ending_lba) -
@@ -713,14 +737,7 @@ int efi_partition(struct parsed_partitions *state)
                /* Naively convert UTF16-LE to 7 bits. */
                label_max = min(ARRAY_SIZE(info->volname) - 1,
                                ARRAY_SIZE(ptes[i].partition_name));
-               info->volname[label_max] = 0;
-               while (label_count < label_max) {
-                       u8 c = ptes[i].partition_name[label_count] & 0xff;
-                       if (c && !isprint(c))
-                               c = '!';
-                       info->volname[label_count] = c;
-                       label_count++;
-               }
+               utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname);
                state->parts[i + 1].has_info = true;
        }
        kfree(ptes);
index 3e85761..8cc2b88 100644 (file)
@@ -88,7 +88,7 @@ typedef struct _gpt_entry {
        __le64 starting_lba;
        __le64 ending_lba;
        gpt_entry_attributes attributes;
-       efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
+       __le16 partition_name[72/sizeof(__le16)];
 } __packed gpt_entry;
 
 typedef struct _gpt_mbr_record {
@@ -113,7 +113,4 @@ typedef struct _legacy_mbr {
        __le16 signature;
 } __packed legacy_mbr;
 
-/* Functions */
-extern int efi_partition(struct parsed_partitions *state);
-
 #endif
index a5d480f..073faa6 100644 (file)
@@ -15,7 +15,6 @@
 #include <asm/vtoc.h>
 
 #include "check.h"
-#include "ibm.h"
 
 
 union label_t {
diff --git a/block/partitions/ibm.h b/block/partitions/ibm.h
deleted file mode 100644 (file)
index 8bf13fe..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-int ibm_partition(struct parsed_partitions *);
index 59812d7..4d93512 100644 (file)
@@ -8,9 +8,10 @@
  */
 
 #include "check.h"
-#include "karma.h"
 #include <linux/compiler.h>
 
+#define KARMA_LABEL_MAGIC              0xAB56
+
 int karma_partition(struct parsed_partitions *state)
 {
        int i;
diff --git a/block/partitions/karma.h b/block/partitions/karma.h
deleted file mode 100644 (file)
index 48e074d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  fs/partitions/karma.h
- */
-
-#define KARMA_LABEL_MAGIC              0xAB56
-
-int karma_partition(struct parsed_partitions *state);
-
index a2d97ee..6fdfcb4 100644 (file)
 #include <linux/stringify.h>
 #include <linux/kernel.h>
 #include <linux/uuid.h>
+#include <linux/msdos_partition.h>
 
 #include "ldm.h"
 #include "check.h"
-#include "msdos.h"
 
 /*
  * ldm_debug/info/error/crit - Output an error message
@@ -493,7 +493,7 @@ static bool ldm_validate_partition_table(struct parsed_partitions *state)
 {
        Sector sect;
        u8 *data;
-       struct partition *p;
+       struct msdos_partition *p;
        int i;
        bool result = false;
 
@@ -508,7 +508,7 @@ static bool ldm_validate_partition_table(struct parsed_partitions *state)
        if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC))
                goto out;
 
-       p = (struct partition*)(data + 0x01BE);
+       p = (struct msdos_partition *)(data + 0x01BE);
        for (i = 0; i < 4; i++, p++)
                if (SYS_IND (p) == LDM_PARTITION) {
                        result = true;
index 1ca63e9..841580a 100644 (file)
@@ -193,7 +193,5 @@ struct ldmdb {                              /* Cache of the database */
        struct list_head v_part;
 };
 
-int ldm_partition(struct parsed_partitions *state);
-
 #endif /* _FS_PT_LDM_H_ */
 
index 453ed29..0e41c9d 100644 (file)
@@ -42,4 +42,3 @@ struct mac_driver_desc {
     /* ... more stuff */
 };
 
-int mac_partition(struct parsed_partitions *state);
index 82c44f7..8f2fcc0 100644 (file)
  *  Check partition table on IDE disks for common CHS translations
  *
  *  Re-organised Feb 1998 Russell King
+ *
+ *  BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
+ *  updated by Marc Espie <Marc.Espie@openbsd.org>
+ *
+ *  Unixware slices support by Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
+ *  and Krzysztof G. Baranowski <kgb@knm.org.pl>
  */
 #include <linux/msdos_fs.h>
+#include <linux/msdos_partition.h>
 
 #include "check.h"
-#include "msdos.h"
 #include "efi.h"
-#include "aix.h"
 
 /*
  * Many architectures don't like unaligned accesses, while
 
 #define SYS_IND(p)     get_unaligned(&p->sys_ind)
 
-static inline sector_t nr_sects(struct partition *p)
+static inline sector_t nr_sects(struct msdos_partition *p)
 {
        return (sector_t)get_unaligned_le32(&p->nr_sects);
 }
 
-static inline sector_t start_sect(struct partition *p)
+static inline sector_t start_sect(struct msdos_partition *p)
 {
        return (sector_t)get_unaligned_le32(&p->start_sect);
 }
 
-static inline int is_extended_partition(struct partition *p)
+static inline int is_extended_partition(struct msdos_partition *p)
 {
        return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
                SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
@@ -68,7 +73,7 @@ msdos_magic_present(unsigned char *p)
 #define AIX_LABEL_MAGIC4       0xC1
 static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
 {
-       struct partition *pt = (struct partition *) (p + 0x1be);
+       struct msdos_partition *pt = (struct msdos_partition *) (p + 0x1be);
        Sector sect;
        unsigned char *d;
        int slot, ret = 0;
@@ -78,13 +83,19 @@ static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
                p[2] == AIX_LABEL_MAGIC3 &&
                p[3] == AIX_LABEL_MAGIC4))
                return 0;
-       /* Assume the partition table is valid if Linux partitions exists */
+
+       /*
+        * Assume the partition table is valid if Linux partitions exists.
+        * Note that old Solaris/x86 partitions use the same indicator as
+        * Linux swap partitions, so we consider that a Linux partition as
+        * well.
+        */
        for (slot = 1; slot <= 4; slot++, pt++) {
-               if (pt->sys_ind == LINUX_SWAP_PARTITION ||
-                       pt->sys_ind == LINUX_RAID_PARTITION ||
-                       pt->sys_ind == LINUX_DATA_PARTITION ||
-                       pt->sys_ind == LINUX_LVM_PARTITION ||
-                       is_extended_partition(pt))
+               if (pt->sys_ind == SOLARIS_X86_PARTITION ||
+                   pt->sys_ind == LINUX_RAID_PARTITION ||
+                   pt->sys_ind == LINUX_DATA_PARTITION ||
+                   pt->sys_ind == LINUX_LVM_PARTITION ||
+                   is_extended_partition(pt))
                        return 0;
        }
        d = read_part_sector(state, 7, &sect);
@@ -122,7 +133,7 @@ static void parse_extended(struct parsed_partitions *state,
                           sector_t first_sector, sector_t first_size,
                           u32 disksig)
 {
-       struct partition *p;
+       struct msdos_partition *p;
        Sector sect;
        unsigned char *data;
        sector_t this_sector, this_size;
@@ -146,7 +157,7 @@ static void parse_extended(struct parsed_partitions *state,
                if (!msdos_magic_present(data + 510))
                        goto done;
 
-               p = (struct partition *) (data + 0x1be);
+               p = (struct msdos_partition *) (data + 0x1be);
 
                /*
                 * Usually, the first entry is the real data partition,
@@ -210,6 +221,30 @@ done:
        put_dev_sector(sect);
 }
 
+#define SOLARIS_X86_NUMSLICE   16
+#define SOLARIS_X86_VTOC_SANE  (0x600DDEEEUL)
+
+struct solaris_x86_slice {
+       __le16 s_tag;           /* ID tag of partition */
+       __le16 s_flag;          /* permission flags */
+       __le32 s_start;         /* start sector no of partition */
+       __le32 s_size;          /* # of blocks in partition */
+};
+
+struct solaris_x86_vtoc {
+       unsigned int v_bootinfo[3];     /* info needed by mboot */
+       __le32 v_sanity;                /* to verify vtoc sanity */
+       __le32 v_version;               /* layout version */
+       char    v_volume[8];            /* volume name */
+       __le16  v_sectorsz;             /* sector size in bytes */
+       __le16  v_nparts;               /* number of partitions */
+       unsigned int v_reserved[10];    /* free space */
+       struct solaris_x86_slice
+               v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */
+       unsigned int timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp */
+       char    v_asciilabel[128];      /* for compatibility */
+};
+
 /* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
    indicates linux swap.  Be careful before believing this is Solaris. */
 
@@ -265,6 +300,54 @@ static void parse_solaris_x86(struct parsed_partitions *state,
 #endif
 }
 
+/* check against BSD src/sys/sys/disklabel.h for consistency */
+#define BSD_DISKMAGIC  (0x82564557UL)  /* The disk magic number */
+#define BSD_MAXPARTITIONS      16
+#define OPENBSD_MAXPARTITIONS  16
+#define BSD_FS_UNUSED          0 /* disklabel unused partition entry ID */
+struct bsd_disklabel {
+       __le32  d_magic;                /* the magic number */
+       __s16   d_type;                 /* drive type */
+       __s16   d_subtype;              /* controller/d_type specific */
+       char    d_typename[16];         /* type name, e.g. "eagle" */
+       char    d_packname[16];         /* pack identifier */
+       __u32   d_secsize;              /* # of bytes per sector */
+       __u32   d_nsectors;             /* # of data sectors per track */
+       __u32   d_ntracks;              /* # of tracks per cylinder */
+       __u32   d_ncylinders;           /* # of data cylinders per unit */
+       __u32   d_secpercyl;            /* # of data sectors per cylinder */
+       __u32   d_secperunit;           /* # of data sectors per unit */
+       __u16   d_sparespertrack;       /* # of spare sectors per track */
+       __u16   d_sparespercyl;         /* # of spare sectors per cylinder */
+       __u32   d_acylinders;           /* # of alt. cylinders per unit */
+       __u16   d_rpm;                  /* rotational speed */
+       __u16   d_interleave;           /* hardware sector interleave */
+       __u16   d_trackskew;            /* sector 0 skew, per track */
+       __u16   d_cylskew;              /* sector 0 skew, per cylinder */
+       __u32   d_headswitch;           /* head switch time, usec */
+       __u32   d_trkseek;              /* track-to-track seek, usec */
+       __u32   d_flags;                /* generic flags */
+#define NDDATA 5
+       __u32   d_drivedata[NDDATA];    /* drive-type specific information */
+#define NSPARE 5
+       __u32   d_spare[NSPARE];        /* reserved for future use */
+       __le32  d_magic2;               /* the magic number (again) */
+       __le16  d_checksum;             /* xor of data incl. partitions */
+
+                       /* filesystem and partition information: */
+       __le16  d_npartitions;          /* number of partitions in following */
+       __le32  d_bbsize;               /* size of boot area at sn0, bytes */
+       __le32  d_sbsize;               /* max size of fs superblock, bytes */
+       struct  bsd_partition {         /* the partition table */
+               __le32  p_size;         /* number of sectors in partition */
+               __le32  p_offset;       /* starting sector */
+               __le32  p_fsize;        /* filesystem basic fragment size */
+               __u8    p_fstype;       /* filesystem type, see below */
+               __u8    p_frag;         /* filesystem fragments per block */
+               __le16  p_cpg;          /* filesystem cylinders per group */
+       } d_partitions[BSD_MAXPARTITIONS];      /* actually may be more */
+};
+
 #if defined(CONFIG_BSD_DISKLABEL)
 /*
  * Create devices for BSD partitions listed in a disklabel, under a
@@ -349,6 +432,51 @@ static void parse_openbsd(struct parsed_partitions *state,
 #endif
 }
 
+#define UNIXWARE_DISKMAGIC     (0xCA5E600DUL)  /* The disk magic number */
+#define UNIXWARE_DISKMAGIC2    (0x600DDEEEUL)  /* The slice table magic nr */
+#define UNIXWARE_NUMSLICE      16
+#define UNIXWARE_FS_UNUSED     0               /* Unused slice entry ID */
+
+struct unixware_slice {
+       __le16   s_label;       /* label */
+       __le16   s_flags;       /* permission flags */
+       __le32   start_sect;    /* starting sector */
+       __le32   nr_sects;      /* number of sectors in slice */
+};
+
+struct unixware_disklabel {
+       __le32  d_type;                 /* drive type */
+       __le32  d_magic;                /* the magic number */
+       __le32  d_version;              /* version number */
+       char    d_serial[12];           /* serial number of the device */
+       __le32  d_ncylinders;           /* # of data cylinders per device */
+       __le32  d_ntracks;              /* # of tracks per cylinder */
+       __le32  d_nsectors;             /* # of data sectors per track */
+       __le32  d_secsize;              /* # of bytes per sector */
+       __le32  d_part_start;           /* # of first sector of this partition*/
+       __le32  d_unknown1[12];         /* ? */
+       __le32  d_alt_tbl;              /* byte offset of alternate table */
+       __le32  d_alt_len;              /* byte length of alternate table */
+       __le32  d_phys_cyl;             /* # of physical cylinders per device */
+       __le32  d_phys_trk;             /* # of physical tracks per cylinder */
+       __le32  d_phys_sec;             /* # of physical sectors per track */
+       __le32  d_phys_bytes;           /* # of physical bytes per sector */
+       __le32  d_unknown2;             /* ? */
+       __le32  d_unknown3;             /* ? */
+       __le32  d_pad[8];               /* pad */
+
+       struct unixware_vtoc {
+               __le32  v_magic;                /* the magic number */
+               __le32  v_version;              /* version number */
+               char    v_name[8];              /* volume name */
+               __le16  v_nslices;              /* # of slices */
+               __le16  v_unknown1;             /* ? */
+               __le32  v_reserved[10];         /* reserved */
+               struct unixware_slice
+                       v_slice[UNIXWARE_NUMSLICE];     /* slice headers */
+       } vtoc;
+};  /* 408 */
+
 /*
  * Create devices for Unixware partitions listed in a disklabel, under a
  * dos-like partition. See parse_extended() for more information.
@@ -392,6 +520,8 @@ static void parse_unixware(struct parsed_partitions *state,
 #endif
 }
 
+#define MINIX_NR_SUBPARTITIONS  4
+
 /*
  * Minix 2.0.0/2.0.2 subpartition support.
  * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
@@ -403,14 +533,14 @@ static void parse_minix(struct parsed_partitions *state,
 #ifdef CONFIG_MINIX_SUBPARTITION
        Sector sect;
        unsigned char *data;
-       struct partition *p;
+       struct msdos_partition *p;
        int i;
 
        data = read_part_sector(state, offset, &sect);
        if (!data)
                return;
 
-       p = (struct partition *)(data + 0x1be);
+       p = (struct msdos_partition *)(data + 0x1be);
 
        /* The first sector of a Minix partition can have either
         * a secondary MBR describing its subpartitions, or
@@ -454,7 +584,7 @@ int msdos_partition(struct parsed_partitions *state)
        sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
        Sector sect;
        unsigned char *data;
-       struct partition *p;
+       struct msdos_partition *p;
        struct fat_boot_sector *fb;
        int slot;
        u32 disksig;
@@ -488,7 +618,7 @@ int msdos_partition(struct parsed_partitions *state)
         * partition table. Reject this in case the boot indicator
         * is not 0 or 0x80.
         */
-       p = (struct partition *) (data + 0x1be);
+       p = (struct msdos_partition *) (data + 0x1be);
        for (slot = 1; slot <= 4; slot++, p++) {
                if (p->boot_ind != 0 && p->boot_ind != 0x80) {
                        /*
@@ -510,7 +640,7 @@ int msdos_partition(struct parsed_partitions *state)
        }
 
 #ifdef CONFIG_EFI_PARTITION
-       p = (struct partition *) (data + 0x1be);
+       p = (struct msdos_partition *) (data + 0x1be);
        for (slot = 1 ; slot <= 4 ; slot++, p++) {
                /* If this is an EFI GPT disk, msdos should ignore it. */
                if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
@@ -519,7 +649,7 @@ int msdos_partition(struct parsed_partitions *state)
                }
        }
 #endif
-       p = (struct partition *) (data + 0x1be);
+       p = (struct msdos_partition *) (data + 0x1be);
 
        disksig = le32_to_cpup((__le32 *)(data + 0x1b8));
 
@@ -566,7 +696,7 @@ int msdos_partition(struct parsed_partitions *state)
        strlcat(state->pp_buf, "\n", PAGE_SIZE);
 
        /* second pass - output for each on a separate line */
-       p = (struct partition *) (0x1be + data);
+       p = (struct msdos_partition *) (0x1be + data);
        for (slot = 1 ; slot <= 4 ; slot++, p++) {
                unsigned char id = SYS_IND(p);
                int n;
diff --git a/block/partitions/msdos.h b/block/partitions/msdos.h
deleted file mode 100644 (file)
index fcacfc4..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  fs/partitions/msdos.h
- */
-
-#define MSDOS_LABEL_MAGIC              0xAA55
-
-int msdos_partition(struct parsed_partitions *state);
-
index 4b87397..84560d0 100644 (file)
@@ -9,9 +9,9 @@
  */
 
 #include "check.h"
-#include "osf.h"
 
 #define MAX_OSF_PARTITIONS 18
+#define DISKLABELMAGIC (0x82564557UL)
 
 int osf_partition(struct parsed_partitions *state)
 {
diff --git a/block/partitions/osf.h b/block/partitions/osf.h
deleted file mode 100644 (file)
index 4d8088e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  fs/partitions/osf.h
- */
-
-#define DISKLABELMAGIC (0x82564557UL)
-
-int osf_partition(struct parsed_partitions *state);
index d7b421c..4273f1b 100644 (file)
@@ -6,7 +6,12 @@
  */
 
 #include "check.h"
-#include "sgi.h"
+
+#define SGI_LABEL_MAGIC 0x0be5a941
+
+enum {
+       LINUX_RAID_PARTITION = 0xfd,    /* autodetect RAID partition */
+};
 
 struct sgi_disklabel {
        __be32 magic_mushroom;          /* Big fat spliff... */
diff --git a/block/partitions/sgi.h b/block/partitions/sgi.h
deleted file mode 100644 (file)
index a5b77c3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  fs/partitions/sgi.h
- */
-
-extern int sgi_partition(struct parsed_partitions *state);
-
-#define SGI_LABEL_MAGIC 0x0be5a941
-
index 90f3672..47dc53e 100644 (file)
@@ -9,7 +9,14 @@
  */
 
 #include "check.h"
-#include "sun.h"
+
+#define SUN_LABEL_MAGIC          0xDABE
+#define SUN_VTOC_SANITY          0x600DDEEE
+
+enum {
+       SUN_WHOLE_DISK = 5,
+       LINUX_RAID_PARTITION = 0xfd,    /* autodetect RAID partition */
+};
 
 int sun_partition(struct parsed_partitions *state)
 {
diff --git a/block/partitions/sun.h b/block/partitions/sun.h
deleted file mode 100644 (file)
index ae1b9ee..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  fs/partitions/sun.h
- */
-
-#define SUN_LABEL_MAGIC          0xDABE
-#define SUN_VTOC_SANITY          0x600DDEEE
-
-int sun_partition(struct parsed_partitions *state);
index 92e8108..6f6257f 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include "check.h"
-#include "sysv68.h"
 
 /*
  *     Volume ID structure: on first 256-bytes sector of disk
diff --git a/block/partitions/sysv68.h b/block/partitions/sysv68.h
deleted file mode 100644 (file)
index 4fb6b8e..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-extern int sysv68_partition(struct parsed_partitions *state);
index ecd0d73..4aaa810 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include "check.h"
-#include "ultrix.h"
 
 int ultrix_partition(struct parsed_partitions *state)
 {
diff --git a/block/partitions/ultrix.h b/block/partitions/ultrix.h
deleted file mode 100644 (file)
index 9f676ce..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- *  fs/partitions/ultrix.h
- */
-
-int ultrix_partition(struct parsed_partitions *state);
index 880cc57..daafadb 100644 (file)
@@ -1056,7 +1056,7 @@ static int start_opal_session_cont(struct opal_dev *dev)
        hsn = response_get_u64(&dev->parsed, 4);
        tsn = response_get_u64(&dev->parsed, 5);
 
-       if (hsn == 0 && tsn == 0) {
+       if (hsn != GENERIC_HOST_SESSION_NUM || tsn < FIRST_TPER_SESSION_NUM) {
                pr_debug("Couldn't authenticate session\n");
                return -EPERM;
        }
index 8befa53..c739665 100644 (file)
@@ -228,4 +228,5 @@ source "drivers/interconnect/Kconfig"
 
 source "drivers/counter/Kconfig"
 
+source "drivers/most/Kconfig"
 endmenu
index 31cf17d..7646549 100644 (file)
@@ -186,3 +186,4 @@ obj-$(CONFIG_SIOX)          += siox/
 obj-$(CONFIG_GNSS)             += gnss/
 obj-$(CONFIG_INTERCONNECT)     += interconnect/
 obj-$(CONFIG_COUNTER)          += counter/
+obj-$(CONFIG_MOST)             += most/
index cc57bab..ce2730d 100644 (file)
@@ -190,6 +190,30 @@ config ACPI_BUTTON
          To compile this driver as a module, choose M here:
          the module will be called button.
 
+config ACPI_TINY_POWER_BUTTON
+       tristate "Tiny Power Button Driver"
+       depends on !ACPI_BUTTON
+       help
+         This driver provides a tiny alternative to the ACPI Button driver.
+         The tiny power button driver only handles the power button. Rather
+         than notifying userspace via the input layer or a netlink event, this
+         driver directly signals the init process to shut down.
+
+         This driver is particularly suitable for cloud and VM environments,
+         which use a simulated power button to initiate a controlled poweroff,
+         but which may not want to run a separate userspace daemon to process
+         input events.
+
+config ACPI_TINY_POWER_BUTTON_SIGNAL
+       int "Tiny Power Button Signal"
+       depends on ACPI_TINY_POWER_BUTTON
+       default 38
+       help
+         Default signal to send to init in response to the power button.
+
+         Likely values here include 38 (SIGRTMIN+4) to power off, or 2
+         (SIGINT) to simulate Ctrl+Alt+Del.
+
 config ACPI_VIDEO
        tristate "Video"
        depends on X86 && BACKLIGHT_CLASS_DEVICE
index 33fdaf6..e81e1eb 100644 (file)
@@ -71,6 +71,7 @@ obj-$(CONFIG_ACPI_IPMI)               += acpi_ipmi.o
 
 obj-$(CONFIG_ACPI_AC)          += ac.o
 obj-$(CONFIG_ACPI_BUTTON)      += button.o
+obj-$(CONFIG_ACPI_TINY_POWER_BUTTON)   += tiny-power-button.o
 obj-$(CONFIG_ACPI_FAN)         += fan.o
 obj-$(CONFIG_ACPI_VIDEO)       += video.o
 obj-$(CONFIG_ACPI_TAD)         += acpi_tad.o
index 829f37d..69d2db1 100644 (file)
@@ -293,29 +293,30 @@ static int __init ac_do_not_check_pmic_quirk(const struct dmi_system_id *d)
        return 0;
 }
 
+/* Please keep this list alphabetically sorted */
 static const struct dmi_system_id ac_dmi_table[]  __initconst = {
        {
-       /* Thinkpad e530 */
-       .callback = thinkpad_e530_quirk,
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"),
+               /* ECS EF20EA, AXP288 PMIC but uses separate fuel-gauge */
+               .callback = ac_do_not_check_pmic_quirk,
+               .matches = {
+                       DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
                },
        },
        {
-               /* ECS EF20EA */
+               /* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */
                .callback = ac_do_not_check_pmic_quirk,
                .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "80XF"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
                },
        },
        {
-               /* Lenovo Ideapad Miix 320 */
-               .callback = ac_do_not_check_pmic_quirk,
+               /* Lenovo Thinkpad e530, see comment in acpi_ac_notify() */
+               .callback = thinkpad_e530_quirk,
                .matches = {
-                 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"),
-                 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"),
                },
        },
        {},
index db18df6..dee9999 100644 (file)
@@ -306,11 +306,9 @@ static const struct lpss_device_desc bsw_spi_dev_desc = {
        .setup = lpss_deassert_reset,
 };
 
-#define ICPU(model)    { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
-
 static const struct x86_cpu_id lpss_cpu_ids[] = {
-       ICPU(INTEL_FAM6_ATOM_SILVERMONT),       /* Valleyview, Bay Trail */
-       ICPU(INTEL_FAM6_ATOM_AIRMONT),  /* Braswell, Cherry Trail */
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,     NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        NULL),
        {}
 };
 
index 15c5b27..bc96457 100644 (file)
@@ -943,7 +943,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
        int i, max_level = 0;
        unsigned long long level, level_old;
        struct acpi_video_device_brightness *br = NULL;
-       int result = -EINVAL;
+       int result;
 
        result = acpi_video_get_levels(device->dev, &br, &max_level);
        if (result)
index b5516b0..6e9ec6e 100644 (file)
@@ -55,12 +55,14 @@ static bool acpi_watchdog_uses_rtc(const struct acpi_table_wdat *wdat)
 }
 #endif
 
+static bool acpi_no_watchdog;
+
 static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void)
 {
        const struct acpi_table_wdat *wdat = NULL;
        acpi_status status;
 
-       if (acpi_disabled)
+       if (acpi_disabled || acpi_no_watchdog)
                return NULL;
 
        status = acpi_get_table(ACPI_SIG_WDAT, 0,
@@ -88,6 +90,14 @@ bool acpi_has_watchdog(void)
 }
 EXPORT_SYMBOL_GPL(acpi_has_watchdog);
 
+/* ACPI watchdog can be disabled on boot command line */
+static int __init disable_acpi_watchdog(char *str)
+{
+       acpi_no_watchdog = true;
+       return 1;
+}
+__setup("acpi_no_watchdog", disable_acpi_watchdog);
+
 void __init acpi_watchdog_init(void)
 {
        const struct acpi_wdat_entry *entries;
@@ -126,12 +136,11 @@ void __init acpi_watchdog_init(void)
                gas = &entries[i].register_region;
 
                res.start = gas->address;
+               res.end = res.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1;
                if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
                        res.flags = IORESOURCE_MEM;
-                       res.end = res.start + ALIGN(gas->access_width, 4) - 1;
                } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
                        res.flags = IORESOURCE_IO;
-                       res.end = res.start + gas->access_width - 1;
                } else {
                        pr_warn("Unsupported address space: %u\n",
                                gas->space_id);
index ede4b9c..cf85d66 100644 (file)
@@ -65,9 +65,7 @@ void cg_write_aml_comment(union acpi_parse_object *op);
 /*
  * cvparser
  */
-void
-cv_init_file_tree(struct acpi_table_header *table,
-                 u8 *aml_start, u32 aml_length);
+void cv_init_file_tree(struct acpi_table_header *table, FILE * root_file);
 
 void cv_clear_op_comments(union acpi_parse_object *op);
 
index 6ad0517..ebf6453 100644 (file)
@@ -101,7 +101,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void);
 
 acpi_status acpi_hw_enable_all_wakeup_gpes(void);
 
-u8 acpi_hw_check_all_gpes(void);
+u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number);
 
 acpi_status
 acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
index 2269e10..168904b 100644 (file)
 #define ASL_CV_PRINT_ONE_COMMENT(a,b,c,d) cv_print_one_comment_type (a,b,c,d);
 #define ASL_CV_PRINT_ONE_COMMENT_LIST(a,b) cv_print_one_comment_list (a,b);
 #define ASL_CV_FILE_HAS_SWITCHED(a)       cv_file_has_switched(a)
-#define ASL_CV_INIT_FILETREE(a,b,c)      cv_init_file_tree(a,b,c);
+#define ASL_CV_INIT_FILETREE(a,b)      cv_init_file_tree(a,b);
 
 #else
 
 #define ASL_CV_PRINT_ONE_COMMENT(a,b,c,d)
 #define ASL_CV_PRINT_ONE_COMMENT_LIST(a,b)
 #define ASL_CV_FILE_HAS_SWITCHED(a)       0
-#define ASL_CV_INIT_FILETREE(a,b,c)
+#define ASL_CV_INIT_FILETREE(a,b)
 
 #endif
 
index 789d5e9..9efca54 100644 (file)
@@ -130,7 +130,7 @@ static acpi_status acpi_ev_fixed_event_initialize(void)
 
        /*
         * Initialize the structure that keeps track of fixed event handlers and
-        * enable the fixed events.
+        * disable all of the fixed events.
         */
        for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
                acpi_gbl_fixed_event_handlers[i].handler = NULL;
index f2de66b..3be6067 100644 (file)
@@ -799,17 +799,19 @@ ACPI_EXPORT_SYMBOL(acpi_enable_all_wakeup_gpes)
  *
  * FUNCTION:    acpi_any_gpe_status_set
  *
- * PARAMETERS:  None
+ * PARAMETERS:  gpe_skip_number      - Number of the GPE to skip
  *
  * RETURN:      Whether or not the status bit is set for any GPE
  *
- * DESCRIPTION: Check the status bits of all enabled GPEs and return TRUE if any
- *              of them is set or FALSE otherwise.
+ * DESCRIPTION: Check the status bits of all enabled GPEs, except for the one
+ *              represented by the "skip" argument, and return TRUE if any of
+ *              them is set or FALSE otherwise.
  *
  ******************************************************************************/
-u32 acpi_any_gpe_status_set(void)
+u32 acpi_any_gpe_status_set(u32 gpe_skip_number)
 {
        acpi_status status;
+       acpi_handle gpe_device;
        u8 ret;
 
        ACPI_FUNCTION_TRACE(acpi_any_gpe_status_set);
@@ -819,7 +821,12 @@ u32 acpi_any_gpe_status_set(void)
                return (FALSE);
        }
 
-       ret = acpi_hw_check_all_gpes();
+       status = acpi_get_gpe_device(gpe_skip_number, &gpe_device);
+       if (ACPI_FAILURE(status)) {
+               gpe_device = NULL;
+       }
+
+       ret = acpi_hw_check_all_gpes(gpe_device, gpe_skip_number);
        (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
 
        return (ret);
index f4c285c..49c46d4 100644 (file)
@@ -444,12 +444,19 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
        return (AE_OK);
 }
 
+struct acpi_gpe_block_status_context {
+       struct acpi_gpe_register_info *gpe_skip_register_info;
+       u8 gpe_skip_mask;
+       u8 retval;
+};
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_hw_get_gpe_block_status
  *
  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
  *              gpe_block           - Gpe Block info
+ *              context             - GPE list walk context data
  *
  * RETURN:      Success
  *
@@ -460,12 +467,13 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 static acpi_status
 acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                             struct acpi_gpe_block_info *gpe_block,
-                            void *ret_ptr)
+                            void *context)
 {
+       struct acpi_gpe_block_status_context *c = context;
        struct acpi_gpe_register_info *gpe_register_info;
        u64 in_enable, in_status;
        acpi_status status;
-       u8 *ret = ret_ptr;
+       u8 ret_mask;
        u32 i;
 
        /* Examine each GPE Register within the block */
@@ -485,7 +493,11 @@ acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                        continue;
                }
 
-               *ret |= in_enable & in_status;
+               ret_mask = in_enable & in_status;
+               if (ret_mask && c->gpe_skip_register_info == gpe_register_info) {
+                       ret_mask &= ~c->gpe_skip_mask;
+               }
+               c->retval |= ret_mask;
        }
 
        return (AE_OK);
@@ -561,24 +573,41 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void)
  *
  * FUNCTION:    acpi_hw_check_all_gpes
  *
- * PARAMETERS:  None
+ * PARAMETERS:  gpe_skip_device      - GPE devoce of the GPE to skip
+ *              gpe_skip_number      - Number of the GPE to skip
  *
  * RETURN:      Combined status of all GPEs
  *
- * DESCRIPTION: Check all enabled GPEs in all GPE blocks and return TRUE if the
+ * DESCRIPTION: Check all enabled GPEs in all GPE blocks, except for the one
+ *              represented by the "skip" arguments, and return TRUE if the
  *              status bit is set for at least one of them of FALSE otherwise.
  *
  ******************************************************************************/
 
-u8 acpi_hw_check_all_gpes(void)
+u8 acpi_hw_check_all_gpes(acpi_handle gpe_skip_device, u32 gpe_skip_number)
 {
-       u8 ret = 0;
+       struct acpi_gpe_block_status_context context = {
+               .gpe_skip_register_info = NULL,
+               .retval = 0,
+       };
+       struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_hw_check_all_gpes);
 
-       (void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &ret);
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+       gpe_event_info = acpi_ev_get_gpe_event_info(gpe_skip_device,
+                                                   gpe_skip_number);
+       if (gpe_event_info) {
+               context.gpe_skip_register_info = gpe_event_info->register_info;
+               context.gpe_skip_mask = acpi_hw_get_gpe_register_bit(gpe_event_info);
+       }
+
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
 
-       return (ret != 0);
+       (void)acpi_ev_walk_gpe_list(acpi_hw_get_gpe_block_status, &context);
+       return (context.retval != 0);
 }
 
 #endif                         /* !ACPI_REDUCED_HARDWARE */
index 243a25a..317ae87 100644 (file)
@@ -300,6 +300,18 @@ acpi_status acpi_hw_legacy_wake(u8 sleep_state)
                                    [ACPI_EVENT_POWER_BUTTON].
                                    status_register_id, ACPI_CLEAR_STATUS);
 
+       /* Enable sleep button */
+
+       (void)
+           acpi_write_bit_register(acpi_gbl_fixed_event_info
+                                   [ACPI_EVENT_SLEEP_BUTTON].
+                                   enable_register_id, ACPI_ENABLE_EVENT);
+
+       (void)
+           acpi_write_bit_register(acpi_gbl_fixed_event_info
+                                   [ACPI_EVENT_SLEEP_BUTTON].
+                                   status_register_id, ACPI_CLEAR_STATUS);
+
        acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING);
        return_ACPI_STATUS(status);
 }
index 370bbc8..d4d2614 100644 (file)
@@ -164,7 +164,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle,
        /* Build the path in the caller buffer */
 
        (void)acpi_ns_build_normalized_path(node, buffer->pointer,
-                                           required_size, no_trailing);
+                                           (u32)required_size, no_trailing);
 
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n",
                          (char *)buffer->pointer, (u32) required_size));
@@ -315,7 +315,7 @@ char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node,
 
        /* Build the path in the allocated buffer */
 
-       (void)acpi_ns_build_normalized_path(node, name_buffer, size,
+       (void)acpi_ns_build_normalized_path(node, name_buffer, (u32)size,
                                            no_trailing);
 
        ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, "%s: Path \"%s\"\n",
@@ -346,7 +346,7 @@ char *acpi_ns_build_prefixed_pathname(union acpi_generic_state *prefix_scope,
        char *full_path = NULL;
        char *external_path = NULL;
        char *prefix_path = NULL;
-       u32 prefix_path_length = 0;
+       acpi_size prefix_path_length = 0;
 
        /* If there is a prefix, get the pathname to it */
 
index 984129d..0e6aba8 100644 (file)
@@ -516,7 +516,7 @@ acpi_status acpi_install_method(u8 *buffer)
 
        method_flags = *parser_state.aml++;
        aml_start = parser_state.aml;
-       aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
+       aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
 
        /*
         * Allocate resources up-front. We don't want to have to delete a new
index f8403d4..7490429 100644 (file)
@@ -202,14 +202,14 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_reallocate_root_table)
  *
  * PARAMETERS:  signature           - ACPI signature of needed table
  *              instance            - Which instance (for SSDTs)
- *              out_table_header    - The pointer to the table header to fill
+ *              out_table_header    - The pointer to the where the table header
+ *                                    is returned
  *
- * RETURN:      Status and pointer to mapped table header
+ * RETURN:      Status and a copy of the table header
  *
- * DESCRIPTION: Finds an ACPI table header.
- *
- * NOTE:        Caller is responsible in unmapping the header with
- *              acpi_os_unmap_memory
+ * DESCRIPTION: Finds and returns an ACPI table header. Caller provides the
+ *              memory where a copy of the header is to be returned
+ *              (fixed length).
  *
  ******************************************************************************/
 acpi_status
index 3e60bda..bbec04c 100644 (file)
@@ -44,7 +44,7 @@ acpi_ut_get_element_length(u8 object_type,
  *
  * NOTE:        We always allocate the worst-case object descriptor because
  *              these objects are cached, and we want them to be
- *              one-size-satisifies-any-request. This in itself may not be
+ *              one-size-satisfies-any-request. This in itself may not be
  *              the most memory efficient, but the efficiency of the object
  *              cache should more than make up for this!
  *
index 103acbb..24c9642 100644 (file)
@@ -171,7 +171,7 @@ int ghes_estatus_pool_init(int num_ghes)
         * New allocation must be visible in all pgd before it can be found by
         * an NMI allocating from the pool.
         */
-       vmalloc_sync_all();
+       vmalloc_sync_mappings();
 
        rc = gen_pool_add(ghes_estatus_pool, addr, PAGE_ALIGN(len), -1);
        if (rc)
index 111a407..366c389 100644 (file)
@@ -1365,19 +1365,19 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = {
                },
        },
        {
-               /* ECS EF20EA */
+               /* ECS EF20EA, AXP288 PMIC but uses separate fuel-gauge */
                .callback = battery_do_not_check_pmic_quirk,
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"),
                },
        },
        {
-               /* Lenovo Ideapad Miix 320 */
+               /* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */
                .callback = battery_do_not_check_pmic_quirk,
                .matches = {
-                 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "80XF"),
-                 DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "80XF"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
                },
        },
        {},
index f6925f1..00112cf 100644 (file)
 #define ACPI_BUTTON_NOTIFY_STATUS      0x80
 
 #define ACPI_BUTTON_SUBCLASS_POWER     "power"
-#define ACPI_BUTTON_HID_POWER          "PNP0C0C"
 #define ACPI_BUTTON_DEVICE_NAME_POWER  "Power Button"
 #define ACPI_BUTTON_TYPE_POWER         0x01
 
 #define ACPI_BUTTON_SUBCLASS_SLEEP     "sleep"
-#define ACPI_BUTTON_HID_SLEEP          "PNP0C0E"
 #define ACPI_BUTTON_DEVICE_NAME_SLEEP  "Sleep Button"
 #define ACPI_BUTTON_TYPE_SLEEP         0x03
 
 #define ACPI_BUTTON_SUBCLASS_LID       "lid"
-#define ACPI_BUTTON_HID_LID            "PNP0C0D"
 #define ACPI_BUTTON_DEVICE_NAME_LID    "Lid Switch"
 #define ACPI_BUTTON_TYPE_LID           0x05
 
index d1f1cf5..4816df5 100644 (file)
@@ -182,7 +182,6 @@ static bool boot_ec_is_ecdt = false;
 static struct workqueue_struct *ec_wq;
 static struct workqueue_struct *ec_query_wq;
 
-static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
 static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
 static int EC_FLAGS_IGNORE_DSDT_GPE; /* Needs ECDT GPE as correction setting */
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
@@ -690,21 +689,9 @@ static void advance_transaction(struct acpi_ec *ec)
                        wakeup = true;
                }
                goto out;
-       } else {
-               if (EC_FLAGS_QUERY_HANDSHAKE &&
-                   !(status & ACPI_EC_FLAG_SCI) &&
-                   (t->command == ACPI_EC_COMMAND_QUERY)) {
-                       ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
-                       t->rdata[t->ri++] = 0x00;
-                       ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
-                       ec_dbg_evt("Command(%s) completed by software",
-                                  acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
-                       wakeup = true;
-               } else if ((status & ACPI_EC_FLAG_IBF) == 0) {
-                       acpi_ec_write_cmd(ec, t->command);
-                       ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
-               } else
-                       goto err;
+       } else if (!(status & ACPI_EC_FLAG_IBF)) {
+               acpi_ec_write_cmd(ec, t->command);
+               ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
                goto out;
        }
 err:
@@ -1427,57 +1414,45 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
        return AE_CTRL_TERMINATE;
 }
 
-static void install_gpe_event_handler(struct acpi_ec *ec)
-{
-       acpi_status status =
-               acpi_install_gpe_raw_handler(NULL, ec->gpe,
-                                            ACPI_GPE_EDGE_TRIGGERED,
-                                            &acpi_ec_gpe_handler,
-                                            ec);
-       if (ACPI_SUCCESS(status)) {
-               /* This is not fatal as we can poll EC events */
-               set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
-               acpi_ec_leave_noirq(ec);
-               if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
-                   ec->reference_count >= 1)
-                       acpi_ec_enable_gpe(ec, true);
-       }
-}
-
-/* ACPI reduced hardware platforms use a GpioInt specified in _CRS. */
-static int install_gpio_irq_event_handler(struct acpi_ec *ec,
-                                         struct acpi_device *device)
+static bool install_gpe_event_handler(struct acpi_ec *ec)
 {
-       int irq = acpi_dev_gpio_irq_get(device, 0);
-       int ret;
-
-       if (irq < 0)
-               return irq;
+       acpi_status status;
 
-       ret = request_irq(irq, acpi_ec_irq_handler, IRQF_SHARED,
-                         "ACPI EC", ec);
+       status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
+                                             ACPI_GPE_EDGE_TRIGGERED,
+                                             &acpi_ec_gpe_handler, ec);
+       if (ACPI_FAILURE(status))
+               return false;
 
-       /*
-        * Unlike the GPE case, we treat errors here as fatal, we'll only
-        * implement GPIO polling if we find a case that needs it.
-        */
-       if (ret < 0)
-               return ret;
+       if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1)
+               acpi_ec_enable_gpe(ec, true);
 
-       ec->irq = irq;
-       set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
-       acpi_ec_leave_noirq(ec);
+       return true;
+}
 
-       return 0;
+static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
+{
+       return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED,
+                          "ACPI EC", ec) >= 0;
 }
 
-/*
- * Note: This function returns an error code only when the address space
- *       handler is not installed, which means "not able to handle
- *       transactions".
+/**
+ * ec_install_handlers - Install service callbacks and register query methods.
+ * @ec: Target EC.
+ * @device: ACPI device object corresponding to @ec.
+ *
+ * Install a handler for the EC address space type unless it has been installed
+ * already.  If @device is not NULL, also look for EC query methods in the
+ * namespace and register them, and install an event (either GPE or GPIO IRQ)
+ * handler for the EC, if possible.
+ *
+ * Return:
+ * -ENODEV if the address space handler cannot be installed, which means
+ *  "unable to handle transactions",
+ * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred,
+ * or 0 (success) otherwise.
  */
-static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
-                              bool handle_events)
+static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device)
 {
        acpi_status status;
 
@@ -1490,26 +1465,28 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
                                                            &acpi_ec_space_handler,
                                                            NULL, ec);
                if (ACPI_FAILURE(status)) {
-                       if (status == AE_NOT_FOUND) {
-                               /*
-                                * Maybe OS fails in evaluating the _REG
-                                * object. The AE_NOT_FOUND error will be
-                                * ignored and OS * continue to initialize
-                                * EC.
-                                */
-                               pr_err("Fail in evaluating the _REG object"
-                                       " of EC device. Broken bios is suspected.\n");
-                       } else {
-                               acpi_ec_stop(ec, false);
-                               return -ENODEV;
-                       }
+                       acpi_ec_stop(ec, false);
+                       return -ENODEV;
                }
                set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
        }
 
-       if (!handle_events)
+       if (!device)
                return 0;
 
+       if (ec->gpe < 0) {
+               /* ACPI reduced hardware platforms use a GpioInt from _CRS. */
+               int irq = acpi_dev_gpio_irq_get(device, 0);
+               /*
+                * Bail out right away for deferred probing or complete the
+                * initialization regardless of any other errors.
+                */
+               if (irq == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               else if (irq >= 0)
+                       ec->irq = irq;
+       }
+
        if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
                /* Find and register all query methods */
                acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
@@ -1518,16 +1495,21 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
                set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
        }
        if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
-               if (ec->gpe >= 0) {
-                       install_gpe_event_handler(ec);
-               } else if (device) {
-                       int ret = install_gpio_irq_event_handler(ec, device);
-
-                       if (ret)
-                               return ret;
-               } else { /* No GPE and no GpioInt? */
-                       return -ENODEV;
+               bool ready = false;
+
+               if (ec->gpe >= 0)
+                       ready = install_gpe_event_handler(ec);
+               else if (ec->irq >= 0)
+                       ready = install_gpio_irq_event_handler(ec);
+
+               if (ready) {
+                       set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
+                       acpi_ec_leave_noirq(ec);
                }
+               /*
+                * Failures to install an event handler are not fatal, because
+                * the EC can be polled for events.
+                */
        }
        /* EC is fully operational, allow queries */
        acpi_ec_enable_event(ec);
@@ -1574,61 +1556,46 @@ static void ec_remove_handlers(struct acpi_ec *ec)
        }
 }
 
-static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device,
-                        bool handle_events)
+static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device)
 {
        int ret;
 
-       ret = ec_install_handlers(ec, device, handle_events);
+       ret = ec_install_handlers(ec, device);
        if (ret)
                return ret;
 
        /* First EC capable of handling transactions */
-       if (!first_ec) {
+       if (!first_ec)
                first_ec = ec;
-               acpi_handle_info(first_ec->handle, "Used as first EC\n");
-       }
 
-       acpi_handle_info(ec->handle,
-                        "GPE=0x%x, IRQ=%d, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
-                        ec->gpe, ec->irq, ec->command_addr, ec->data_addr);
-       return ret;
-}
+       pr_info("EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->command_addr,
+               ec->data_addr);
 
-static bool acpi_ec_ecdt_get_handle(acpi_handle *phandle)
-{
-       struct acpi_table_ecdt *ecdt_ptr;
-       acpi_status status;
-       acpi_handle handle;
-
-       status = acpi_get_table(ACPI_SIG_ECDT, 1,
-                               (struct acpi_table_header **)&ecdt_ptr);
-       if (ACPI_FAILURE(status))
-               return false;
-
-       status = acpi_get_handle(NULL, ecdt_ptr->id, &handle);
-       if (ACPI_FAILURE(status))
-               return false;
+       if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
+               if (ec->gpe >= 0)
+                       pr_info("GPE=0x%x\n", ec->gpe);
+               else
+                       pr_info("IRQ=%d\n", ec->irq);
+       }
 
-       *phandle = handle;
-       return true;
+       return ret;
 }
 
 static int acpi_ec_add(struct acpi_device *device)
 {
-       struct acpi_ec *ec = NULL;
-       bool dep_update = true;
-       acpi_status status;
+       struct acpi_ec *ec;
        int ret;
 
        strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
        strcpy(acpi_device_class(device), ACPI_EC_CLASS);
 
-       if (!strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) {
-               boot_ec_is_ecdt = true;
+       if ((boot_ec && boot_ec->handle == device->handle) ||
+           !strcmp(acpi_device_hid(device), ACPI_ECDT_HID)) {
+               /* Fast path: this device corresponds to the boot EC. */
                ec = boot_ec;
-               dep_update = false;
        } else {
+               acpi_status status;
+
                ec = acpi_ec_alloc();
                if (!ec)
                        return -ENOMEM;
@@ -1636,12 +1603,11 @@ static int acpi_ec_add(struct acpi_device *device)
                status = ec_parse_device(device->handle, 0, ec, NULL);
                if (status != AE_CTRL_TERMINATE) {
                        ret = -EINVAL;
-                       goto err_alloc;
+                       goto err;
                }
 
                if (boot_ec && ec->command_addr == boot_ec->command_addr &&
                    ec->data_addr == boot_ec->data_addr) {
-                       boot_ec_is_ecdt = false;
                        /*
                         * Trust PNP0C09 namespace location rather than
                         * ECDT ID. But trust ECDT GPE rather than _GPE
@@ -1655,15 +1621,18 @@ static int acpi_ec_add(struct acpi_device *device)
                }
        }
 
-       ret = acpi_ec_setup(ec, device, true);
+       ret = acpi_ec_setup(ec, device);
        if (ret)
-               goto err_query;
+               goto err;
 
        if (ec == boot_ec)
                acpi_handle_info(boot_ec->handle,
-                                "Boot %s EC used to handle transactions and events\n",
+                                "Boot %s EC initialization complete\n",
                                 boot_ec_is_ecdt ? "ECDT" : "DSDT");
 
+       acpi_handle_info(ec->handle,
+                        "EC: Used to handle transactions and events\n");
+
        device->driver_data = ec;
 
        ret = !!request_region(ec->data_addr, 1, "EC data");
@@ -1671,19 +1640,16 @@ static int acpi_ec_add(struct acpi_device *device)
        ret = !!request_region(ec->command_addr, 1, "EC cmd");
        WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);
 
-       if (dep_update) {
-               /* Reprobe devices depending on the EC */
-               acpi_walk_dep_device_list(ec->handle);
-       }
+       /* Reprobe devices depending on the EC */
+       acpi_walk_dep_device_list(ec->handle);
+
        acpi_handle_debug(ec->handle, "enumerated.\n");
        return 0;
 
-err_query:
-       if (ec != boot_ec)
-               acpi_ec_remove_query_handlers(ec, true, 0);
-err_alloc:
+err:
        if (ec != boot_ec)
                acpi_ec_free(ec);
+
        return ret;
 }
 
@@ -1775,7 +1741,7 @@ void __init acpi_ec_dsdt_probe(void)
         * At this point, the GPE is not fully initialized, so do not to
         * handle the events.
         */
-       ret = acpi_ec_setup(ec, NULL, false);
+       ret = acpi_ec_setup(ec, NULL);
        if (ret) {
                acpi_ec_free(ec);
                return;
@@ -1788,52 +1754,43 @@ void __init acpi_ec_dsdt_probe(void)
 }
 
 /*
- * If the DSDT EC is not functioning, we still need to prepare a fully
- * functioning ECDT EC first in order to handle the events.
- * https://bugzilla.kernel.org/show_bug.cgi?id=115021
+ * acpi_ec_ecdt_start - Finalize the boot ECDT EC initialization.
+ *
+ * First, look for an ACPI handle for the boot ECDT EC if acpi_ec_add() has not
+ * found a matching object in the namespace.
+ *
+ * Next, in case the DSDT EC is not functioning, it is still necessary to
+ * provide a functional ECDT EC to handle events, so add an extra device object
+ * to represent it (see https://bugzilla.kernel.org/show_bug.cgi?id=115021).
+ *
+ * This is useful on platforms with valid ECDT and invalid DSDT EC settings,
+ * like ASUS X550ZE (see https://bugzilla.kernel.org/show_bug.cgi?id=196847).
  */
-static int __init acpi_ec_ecdt_start(void)
+static void __init acpi_ec_ecdt_start(void)
 {
+       struct acpi_table_ecdt *ecdt_ptr;
        acpi_handle handle;
+       acpi_status status;
 
-       if (!boot_ec)
-               return -ENODEV;
-       /* In case acpi_ec_ecdt_start() is called after acpi_ec_add() */
-       if (!boot_ec_is_ecdt)
-               return -ENODEV;
+       /* Bail out if a matching EC has been found in the namespace. */
+       if (!boot_ec || boot_ec->handle != ACPI_ROOT_OBJECT)
+               return;
 
-       /*
-        * At this point, the namespace and the GPE is initialized, so
-        * start to find the namespace objects and handle the events.
-        *
-        * Note: ec->handle can be valid if this function is called after
-        * acpi_ec_add(), hence the fast path.
-        */
-       if (boot_ec->handle == ACPI_ROOT_OBJECT) {
-               if (!acpi_ec_ecdt_get_handle(&handle))
-                       return -ENODEV;
-               boot_ec->handle = handle;
-       }
+       /* Look up the object pointed to from the ECDT in the namespace. */
+       status = acpi_get_table(ACPI_SIG_ECDT, 1,
+                               (struct acpi_table_header **)&ecdt_ptr);
+       if (ACPI_FAILURE(status))
+               return;
 
-       /* Register to ACPI bus with PM ops attached */
-       return acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC);
-}
+       status = acpi_get_handle(NULL, ecdt_ptr->id, &handle);
+       if (ACPI_FAILURE(status))
+               return;
 
-#if 0
-/*
- * Some EC firmware variations refuses to respond QR_EC when SCI_EVT is not
- * set, for which case, we complete the QR_EC without issuing it to the
- * firmware.
- * https://bugzilla.kernel.org/show_bug.cgi?id=82611
- * https://bugzilla.kernel.org/show_bug.cgi?id=97381
- */
-static int ec_flag_query_handshake(const struct dmi_system_id *id)
-{
-       pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n");
-       EC_FLAGS_QUERY_HANDSHAKE = 1;
-       return 0;
+       boot_ec->handle = handle;
+
+       /* Add a special ACPI device object to represent the boot EC. */
+       acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC);
 }
-#endif
 
 /*
  * On some hardware it is necessary to clear events accumulated by the EC during
@@ -1962,7 +1919,7 @@ void __init acpi_ec_ecdt_probe(void)
         * At this point, the namespace is not initialized, so do not find
         * the namespace objects, or handle the events.
         */
-       ret = acpi_ec_setup(ec, NULL, false);
+       ret = acpi_ec_setup(ec, NULL);
        if (ret) {
                acpi_ec_free(ec);
                return;
@@ -2037,6 +1994,11 @@ void acpi_ec_set_gpe_wake_mask(u8 action)
                acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action);
 }
 
+bool acpi_ec_other_gpes_active(void)
+{
+       return acpi_any_gpe_status_set(first_ec ? first_ec->gpe : U32_MAX);
+}
+
 bool acpi_ec_dispatch_gpe(void)
 {
        u32 ret;
@@ -2160,14 +2122,13 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = {
        { },
 };
 
-int __init acpi_ec_init(void)
+void __init acpi_ec_init(void)
 {
        int result;
-       int ecdt_fail, dsdt_fail;
 
        result = acpi_ec_init_workqueues();
        if (result)
-               return result;
+               return;
 
        /*
         * Disable EC wakeup on following systems to prevent periodic
@@ -2178,16 +2139,10 @@ int __init acpi_ec_init(void)
                pr_debug("Disabling EC wakeup on suspend-to-idle\n");
        }
 
-       /* Drivers must be started after acpi_ec_query_init() */
-       dsdt_fail = acpi_bus_register_driver(&acpi_ec_driver);
-       /*
-        * Register ECDT to ACPI bus only when PNP0C09 probe fails. This is
-        * useful for platforms (confirmed on ASUS X550ZE) with valid ECDT
-        * settings but invalid DSDT settings.
-        * https://bugzilla.kernel.org/show_bug.cgi?id=196847
-        */
-       ecdt_fail = acpi_ec_ecdt_start();
-       return ecdt_fail && dsdt_fail ? -ENODEV : 0;
+       /* Driver must be registered after acpi_ec_init_workqueues(). */
+       acpi_bus_register_driver(&acpi_ec_driver);
+
+       acpi_ec_ecdt_start();
 }
 
 /* EC driver currently not unloadable */
index aaf4e8f..873e039 100644 (file)
@@ -276,29 +276,29 @@ static ssize_t show_state(struct device *dev, struct device_attribute *attr, cha
        int count;
 
        if (fps->control == 0xFFFFFFFF || fps->control > 100)
-               count = snprintf(buf, PAGE_SIZE, "not-defined:");
+               count = scnprintf(buf, PAGE_SIZE, "not-defined:");
        else
-               count = snprintf(buf, PAGE_SIZE, "%lld:", fps->control);
+               count = scnprintf(buf, PAGE_SIZE, "%lld:", fps->control);
 
        if (fps->trip_point == 0xFFFFFFFF || fps->trip_point > 9)
-               count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
+               count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
        else
-               count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->trip_point);
+               count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->trip_point);
 
        if (fps->speed == 0xFFFFFFFF)
-               count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
+               count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
        else
-               count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->speed);
+               count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->speed);
 
        if (fps->noise_level == 0xFFFFFFFF)
-               count += snprintf(&buf[count], PAGE_SIZE, "not-defined:");
+               count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined:");
        else
-               count += snprintf(&buf[count], PAGE_SIZE, "%lld:", fps->noise_level * 100);
+               count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld:", fps->noise_level * 100);
 
        if (fps->power == 0xFFFFFFFF)
-               count += snprintf(&buf[count], PAGE_SIZE, "not-defined\n");
+               count += scnprintf(&buf[count], PAGE_SIZE - count, "not-defined\n");
        else
-               count += snprintf(&buf[count], PAGE_SIZE, "%lld\n", fps->power);
+               count += scnprintf(&buf[count], PAGE_SIZE - count, "%lld\n", fps->power);
 
        return count;
 }
index 3616dae..e387517 100644 (file)
@@ -190,7 +190,7 @@ extern struct acpi_ec *first_ec;
 /* External interfaces use first EC only, so remember */
 typedef int (*acpi_ec_query_func) (void *data);
 
-int acpi_ec_init(void);
+void acpi_ec_init(void);
 void acpi_ec_ecdt_probe(void);
 void acpi_ec_dsdt_probe(void);
 void acpi_ec_block_transactions(void);
@@ -202,6 +202,7 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
 
 #ifdef CONFIG_PM_SLEEP
 void acpi_ec_flush_work(void);
+bool acpi_ec_other_gpes_active(void);
 bool acpi_ec_dispatch_gpe(void);
 #endif
 
index 41168c0..762c5d5 100644 (file)
@@ -1598,6 +1598,7 @@ void acpi_os_delete_lock(acpi_spinlock handle)
  */
 
 acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
+       __acquires(lockp)
 {
        acpi_cpu_flags flags;
        spin_lock_irqsave(lockp, flags);
@@ -1609,6 +1610,7 @@ acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
  */
 
 void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
+       __releases(lockp)
 {
        spin_unlock_irqrestore(lockp, flags);
 }
index d1e666e..f92df25 100644 (file)
@@ -153,7 +153,7 @@ static void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word,
        buf[0] = '\0';
        for (i = 0, entry = table; i < size; i++, entry++)
                if (word & entry->bit)
-                       len += snprintf(buf + len, sizeof(buf) - len, "%s%s",
+                       len += scnprintf(buf + len, sizeof(buf) - len, "%s%s",
                                        len ? " " : "", entry->desc);
 
        dev_info(&root->device->dev, "_OSC: %s [%s]\n", msg, buf);
index 0e62ef2..7892980 100644 (file)
@@ -22,14 +22,13 @@ ACPI_MODULE_NAME("sleep")
 static int
 acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
 {
-       struct list_head *node, *next;
+       struct acpi_device *dev, *tmp;
 
        seq_printf(seq, "Device\tS-state\t  Status   Sysfs node\n");
 
        mutex_lock(&acpi_device_lock);
-       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
-               struct acpi_device *dev =
-                   container_of(node, struct acpi_device, wakeup_list);
+       list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
+                                wakeup_list) {
                struct acpi_device_physical_node *entry;
 
                if (!dev->wakeup.flags.valid)
@@ -96,7 +95,7 @@ acpi_system_write_wakeup_device(struct file *file,
                                const char __user * buffer,
                                size_t count, loff_t * ppos)
 {
-       struct list_head *node, *next;
+       struct acpi_device *dev, *tmp;
        char strbuf[5];
        char str[5] = "";
 
@@ -109,9 +108,8 @@ acpi_system_write_wakeup_device(struct file *file,
        sscanf(strbuf, "%s", str);
 
        mutex_lock(&acpi_device_lock);
-       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
-               struct acpi_device *dev =
-                   container_of(node, struct acpi_device, wakeup_list);
+       list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
+                                wakeup_list) {
                if (!dev->wakeup.flags.valid)
                        continue;
 
index e5f9592..bb1ae40 100644 (file)
@@ -982,10 +982,7 @@ static int acpi_s2idle_prepare_late(void)
 
 static void acpi_s2idle_sync(void)
 {
-       /*
-        * The EC driver uses the system workqueue and an additional special
-        * one, so those need to be flushed too.
-        */
+       /* The EC driver uses special workqueues that need to be flushed. */
        acpi_ec_flush_work();
        acpi_os_wait_events_complete(); /* synchronize Notify handling */
 }
@@ -1013,19 +1010,20 @@ static bool acpi_s2idle_wake(void)
                        return true;
 
                /*
-                * If there are no EC events to process and at least one of the
-                * other enabled GPEs is active, the wakeup is regarded as a
-                * genuine one.
-                *
-                * Note that the checks below must be carried out in this order
-                * to avoid returning prematurely due to a change of the EC GPE
-                * status bit from unset to set between the checks with the
-                * status bits of all the other GPEs unset.
+                * If the status bit is set for any enabled GPE other than the
+                * EC one, the wakeup is regarded as a genuine one.
                 */
-               if (acpi_any_gpe_status_set() && !acpi_ec_dispatch_gpe())
+               if (acpi_ec_other_gpes_active())
                        return true;
 
                /*
+                * If the EC GPE status bit has not been set, the wakeup is
+                * regarded as a spurious one.
+                */
+               if (!acpi_ec_dispatch_gpe())
+                       return false;
+
+               /*
                 * Cancel the wakeup and process all pending events in case
                 * there are any wakeup ones in there.
                 *
diff --git a/drivers/acpi/tiny-power-button.c b/drivers/acpi/tiny-power-button.c
new file mode 100644 (file)
index 0000000..6273d73
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/module.h>
+#include <linux/sched/signal.h>
+#include <linux/acpi.h>
+#include <acpi/button.h>
+
+ACPI_MODULE_NAME("tiny-power-button");
+MODULE_AUTHOR("Josh Triplett");
+MODULE_DESCRIPTION("ACPI Tiny Power Button Driver");
+MODULE_LICENSE("GPL");
+
+static int power_signal __read_mostly = CONFIG_ACPI_TINY_POWER_BUTTON_SIGNAL;
+module_param(power_signal, int, 0644);
+MODULE_PARM_DESC(power_signal, "Power button sends this signal to init");
+
+static const struct acpi_device_id tiny_power_button_device_ids[] = {
+       { ACPI_BUTTON_HID_POWER, 0 },
+       { ACPI_BUTTON_HID_POWERF, 0 },
+       { "", 0 },
+};
+MODULE_DEVICE_TABLE(acpi, tiny_power_button_device_ids);
+
+static int acpi_noop_add_remove(struct acpi_device *device)
+{
+       return 0;
+}
+
+static void acpi_tiny_power_button_notify(struct acpi_device *device, u32 event)
+{
+       kill_cad_pid(power_signal, 1);
+}
+
+static struct acpi_driver acpi_tiny_power_button_driver = {
+       .name = "tiny-power-button",
+       .class = "tiny-power-button",
+       .ids = tiny_power_button_device_ids,
+       .ops = {
+               .add = acpi_noop_add_remove,
+               .remove = acpi_noop_add_remove,
+               .notify = acpi_tiny_power_button_notify,
+       },
+};
+
+module_driver(acpi_tiny_power_button_driver,
+               acpi_bus_register_driver,
+               acpi_bus_unregister_driver);
index 9614126..c28244d 100644 (file)
@@ -30,12 +30,10 @@ ACPI_MODULE_NAME("wakeup_devices")
  */
 void acpi_enable_wakeup_devices(u8 sleep_state)
 {
-       struct list_head *node, *next;
-
-       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
-               struct acpi_device *dev =
-                       container_of(node, struct acpi_device, wakeup_list);
+       struct acpi_device *dev, *tmp;
 
+       list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
+                                wakeup_list) {
                if (!dev->wakeup.flags.valid
                    || sleep_state > (u32) dev->wakeup.sleep_state
                    || !(device_may_wakeup(&dev->dev)
@@ -57,12 +55,10 @@ void acpi_enable_wakeup_devices(u8 sleep_state)
  */
 void acpi_disable_wakeup_devices(u8 sleep_state)
 {
-       struct list_head *node, *next;
-
-       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
-               struct acpi_device *dev =
-                       container_of(node, struct acpi_device, wakeup_list);
+       struct acpi_device *dev, *tmp;
 
+       list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
+                                wakeup_list) {
                if (!dev->wakeup.flags.valid
                    || sleep_state > (u32) dev->wakeup.sleep_state
                    || !(device_may_wakeup(&dev->dev)
@@ -79,13 +75,11 @@ void acpi_disable_wakeup_devices(u8 sleep_state)
 
 int __init acpi_wakeup_device_init(void)
 {
-       struct list_head *node, *next;
+       struct acpi_device *dev, *tmp;
 
        mutex_lock(&acpi_device_lock);
-       list_for_each_safe(node, next, &acpi_wakeup_device_list) {
-               struct acpi_device *dev = container_of(node,
-                                                      struct acpi_device,
-                                                      wakeup_list);
+       list_for_each_entry_safe(dev, tmp, &acpi_wakeup_device_list,
+                                wakeup_list) {
                if (device_can_wakeup(&dev->dev)) {
                        /* Button GPEs are supposed to be always enabled. */
                        acpi_enable_gpe(dev->wakeup.gpe_device,
index 697a6b1..bdc1ba0 100644 (file)
@@ -37,7 +37,7 @@ struct always_present_id {
        const char *uid;
 };
 
-#define ICPU(model)    { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
+#define X86_MATCH(model)       X86_MATCH_INTEL_FAM6_MODEL(model, NULL)
 
 #define ENTRY(hid, uid, cpu_models, dmi...) {                          \
        { { hid, }, {} },                                               \
@@ -51,29 +51,29 @@ static const struct always_present_id always_present_ids[] = {
         * Bay / Cherry Trail PWM directly poked by GPU driver in win10,
         * but Linux uses a separate PWM driver, harmless if not used.
         */
-       ENTRY("80860F09", "1", ICPU(INTEL_FAM6_ATOM_SILVERMONT), {}),
-       ENTRY("80862288", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}),
+       ENTRY("80860F09", "1", X86_MATCH(ATOM_SILVERMONT), {}),
+       ENTRY("80862288", "1", X86_MATCH(ATOM_AIRMONT), {}),
 
        /* Lenovo Yoga Book uses PWM2 for keyboard backlight control */
-       ENTRY("80862289", "2", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+       ENTRY("80862289", "2", X86_MATCH(ATOM_AIRMONT), {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"),
                }),
        /*
         * The INT0002 device is necessary to clear wakeup interrupt sources
         * on Cherry Trail devices, without it we get nobody cared IRQ msgs.
         */
-       ENTRY("INT0002", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {}),
+       ENTRY("INT0002", "1", X86_MATCH(ATOM_AIRMONT), {}),
        /*
         * On the Dell Venue 11 Pro 7130 and 7139, the DSDT hides
         * the touchscreen ACPI device until a certain time
         * after _SB.PCI0.GFX0.LCD.LCD1._ON gets called has passed
         * *and* _STA has been called at least 3 times since.
         */
-       ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_L), {
+       ENTRY("SYNA7500", "1", X86_MATCH(HASWELL_L), {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"),
              }),
-       ENTRY("SYNA7500", "1", ICPU(INTEL_FAM6_HASWELL_L), {
+       ENTRY("SYNA7500", "1", X86_MATCH(HASWELL_L), {
                DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
                DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7139"),
              }),
@@ -89,19 +89,19 @@ static const struct always_present_id always_present_ids[] = {
         * was copy-pasted from the GPD win, so it has a disabled KIOX000A
         * node which we should not enable, thus we also check the BIOS date.
         */
-       ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+       ENTRY("KIOX000A", "1", X86_MATCH(ATOM_AIRMONT), {
                DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
                DMI_MATCH(DMI_BOARD_NAME, "Default string"),
                DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
                DMI_MATCH(DMI_BIOS_DATE, "02/21/2017")
              }),
-       ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+       ENTRY("KIOX000A", "1", X86_MATCH(ATOM_AIRMONT), {
                DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
                DMI_MATCH(DMI_BOARD_NAME, "Default string"),
                DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
                DMI_MATCH(DMI_BIOS_DATE, "03/20/2017")
              }),
-       ENTRY("KIOX000A", "1", ICPU(INTEL_FAM6_ATOM_AIRMONT), {
+       ENTRY("KIOX000A", "1", X86_MATCH(ATOM_AIRMONT), {
                DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
                DMI_MATCH(DMI_BOARD_NAME, "Default string"),
                DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
index a6b2082..e47c8a4 100644 (file)
@@ -5228,6 +5228,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
                binder_dev = container_of(filp->private_data,
                                          struct binder_device, miscdev);
        }
+       refcount_inc(&binder_dev->ref);
        proc->context = &binder_dev->context;
        binder_alloc_init(&proc->alloc);
 
@@ -5405,6 +5406,7 @@ static int binder_node_release(struct binder_node *node, int refs)
 static void binder_deferred_release(struct binder_proc *proc)
 {
        struct binder_context *context = proc->context;
+       struct binder_device *device;
        struct rb_node *n;
        int threads, nodes, incoming_refs, outgoing_refs, active_transactions;
 
@@ -5421,6 +5423,12 @@ static void binder_deferred_release(struct binder_proc *proc)
                context->binder_context_mgr_node = NULL;
        }
        mutex_unlock(&context->context_mgr_node_lock);
+       device = container_of(proc->context, struct binder_device, context);
+       if (refcount_dec_and_test(&device->ref)) {
+               kfree(context->name);
+               kfree(device);
+       }
+       proc->context = NULL;
        binder_inner_proc_lock(proc);
        /*
         * Make sure proc stays alive after we
@@ -6077,6 +6085,7 @@ static int __init init_binder_device(const char *name)
        binder_device->miscdev.minor = MISC_DYNAMIC_MINOR;
        binder_device->miscdev.name = name;
 
+       refcount_set(&binder_device->ref, 1);
        binder_device->context.binder_context_mgr_uid = INVALID_UID;
        binder_device->context.name = name;
        mutex_init(&binder_device->context.context_mgr_node_lock);
index ae99109..283d3cb 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/list.h>
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
+#include <linux/refcount.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/uidgid.h>
@@ -33,6 +34,7 @@ struct binder_device {
        struct miscdevice miscdev;
        struct binder_context context;
        struct inode *binderfs_inode;
+       refcount_t ref;
 };
 
 /**
index e2580e5..f303106 100644 (file)
@@ -154,6 +154,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
        if (!name)
                goto err;
 
+       refcount_set(&device->ref, 1);
        device->binderfs_inode = inode;
        device->context.binder_context_mgr_uid = INVALID_UID;
        device->context.name = name;
@@ -257,8 +258,10 @@ static void binderfs_evict_inode(struct inode *inode)
        ida_free(&binderfs_minors, device->miscdev.minor);
        mutex_unlock(&binderfs_minors_mutex);
 
-       kfree(device->context.name);
-       kfree(device);
+       if (refcount_dec_and_test(&device->ref)) {
+               kfree(device->context.name);
+               kfree(device);
+       }
 }
 
 /**
@@ -445,6 +448,7 @@ static int binderfs_binder_ctl_create(struct super_block *sb)
        inode->i_uid = info->root_uid;
        inode->i_gid = info->root_gid;
 
+       refcount_set(&device->ref, 1);
        device->binderfs_inode = inode;
        device->miscdev.minor = minor;
 
index a6beb2c..05ecdce 100644 (file)
@@ -34,6 +34,12 @@ if ATA
 config ATA_NONSTANDARD
        bool
 
+config SATA_HOST
+       bool
+
+config PATA_TIMINGS
+       bool
+
 config ATA_VERBOSE_ERROR
        bool "Verbose ATA error reporting"
        default y
@@ -45,9 +51,26 @@ config ATA_VERBOSE_ERROR
 
          If unsure, say Y.
 
+config ATA_FORCE
+       bool "\"libata.force=\" kernel parameter support" if EXPERT
+       default y
+       help
+         This option adds support for "libata.force=" kernel parameter for
+         forcing configuration settings.
+
+         For further information, please read
+         <file:Documentation/admin-guide/kernel-parameters.txt>.
+
+         This option will enlarge the kernel by approx. 3KB. Disable it if
+         kernel size is more important than ability to override the default
+         configuration settings.
+
+         If unsure, say Y.
+
 config ATA_ACPI
        bool "ATA ACPI Support"
        depends on ACPI
+       select PATA_TIMINGS
        default y
        help
          This option adds support for ATA-related ACPI objects.
@@ -73,6 +96,7 @@ config SATA_ZPODD
 
 config SATA_PMP
        bool "SATA Port Multiplier support"
+       depends on SATA_HOST
        default y
        help
          This option adds support for SATA Port Multipliers
@@ -85,6 +109,7 @@ comment "Controllers with non-SFF native interface"
 config SATA_AHCI
        tristate "AHCI SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for AHCI Serial ATA.
 
@@ -111,6 +136,7 @@ config SATA_MOBILE_LPM_POLICY
 
 config SATA_AHCI_PLATFORM
        tristate "Platform AHCI SATA support"
+       select SATA_HOST
        help
          This option enables support for Platform AHCI Serial ATA
          controllers.
@@ -121,6 +147,7 @@ config AHCI_BRCM
        tristate "Broadcom AHCI SATA support"
        depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP || \
                   ARCH_BCM_63XX
+       select SATA_HOST
        help
          This option enables support for the AHCI SATA3 controller found on
          Broadcom SoC's.
@@ -130,6 +157,7 @@ config AHCI_BRCM
 config AHCI_DA850
        tristate "DaVinci DA850 AHCI SATA support"
        depends on ARCH_DAVINCI_DA850
+       select SATA_HOST
        help
          This option enables support for the DaVinci DA850 SoC's
          onboard AHCI SATA.
@@ -139,6 +167,7 @@ config AHCI_DA850
 config AHCI_DM816
        tristate "DaVinci DM816 AHCI SATA support"
        depends on ARCH_OMAP2PLUS
+       select SATA_HOST
        help
          This option enables support for the DaVinci DM816 SoC's
          onboard AHCI SATA controller.
@@ -148,6 +177,7 @@ config AHCI_DM816
 config AHCI_ST
        tristate "ST AHCI SATA support"
        depends on ARCH_STI
+       select SATA_HOST
        help
          This option enables support for ST AHCI SATA controller.
 
@@ -157,6 +187,7 @@ config AHCI_IMX
        tristate "Freescale i.MX AHCI SATA support"
        depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST)
        depends on (HWMON && (THERMAL || !THERMAL_OF)) || !HWMON
+       select SATA_HOST
        help
          This option enables support for the Freescale i.MX SoC's
          onboard AHCI SATA.
@@ -166,6 +197,7 @@ config AHCI_IMX
 config AHCI_CEVA
        tristate "CEVA AHCI SATA support"
        depends on OF
+       select SATA_HOST
        help
          This option enables support for the CEVA AHCI SATA.
          It can be found on the Xilinx Zynq UltraScale+ MPSoC.
@@ -176,6 +208,7 @@ config AHCI_MTK
        tristate "MediaTek AHCI SATA support"
        depends on ARCH_MEDIATEK
        select MFD_SYSCON
+       select SATA_HOST
        help
          This option enables support for the MediaTek SoC's
          onboard AHCI SATA controller.
@@ -185,6 +218,7 @@ config AHCI_MTK
 config AHCI_MVEBU
        tristate "Marvell EBU AHCI SATA support"
        depends on ARCH_MVEBU
+       select SATA_HOST
        help
          This option enables support for the Marvebu EBU SoC's
          onboard AHCI SATA.
@@ -203,6 +237,7 @@ config AHCI_OCTEON
 config AHCI_SUNXI
        tristate "Allwinner sunxi AHCI SATA support"
        depends on ARCH_SUNXI
+       select SATA_HOST
        help
          This option enables support for the Allwinner sunxi SoC's
          onboard AHCI SATA.
@@ -212,6 +247,7 @@ config AHCI_SUNXI
 config AHCI_TEGRA
        tristate "NVIDIA Tegra AHCI SATA support"
        depends on ARCH_TEGRA
+       select SATA_HOST
        help
          This option enables support for the NVIDIA Tegra SoC's
          onboard AHCI SATA.
@@ -221,12 +257,14 @@ config AHCI_TEGRA
 config AHCI_XGENE
        tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support"
        depends on PHY_XGENE
+       select SATA_HOST
        help
         This option enables support for APM X-Gene SoC SATA host controller.
 
 config AHCI_QORIQ
        tristate "Freescale QorIQ AHCI SATA support"
        depends on OF
+       select SATA_HOST
        help
          This option enables support for the Freescale QorIQ AHCI SoC's
          onboard AHCI SATA.
@@ -236,6 +274,7 @@ config AHCI_QORIQ
 config SATA_FSL
        tristate "Freescale 3.0Gbps SATA support"
        depends on FSL_SOC
+       select SATA_HOST
        help
          This option enables support for Freescale 3.0Gbps SATA controller.
          It can be found on MPC837x and MPC8315.
@@ -245,6 +284,7 @@ config SATA_FSL
 config SATA_GEMINI
        tristate "Gemini SATA bridge support"
        depends on ARCH_GEMINI || COMPILE_TEST
+       select SATA_HOST
        default ARCH_GEMINI
        help
          This enabled support for the FTIDE010 to SATA bridge
@@ -255,6 +295,7 @@ config SATA_GEMINI
 config SATA_AHCI_SEATTLE
        tristate "AMD Seattle 6.0Gbps AHCI SATA host controller support"
        depends on ARCH_SEATTLE
+       select SATA_HOST
        help
         This option enables support for AMD Seattle SATA host controller.
 
@@ -263,12 +304,14 @@ config SATA_AHCI_SEATTLE
 config SATA_INIC162X
        tristate "Initio 162x SATA support (Very Experimental)"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Initio 162x Serial ATA.
 
 config SATA_ACARD_AHCI
        tristate "ACard AHCI variant (ATP 8620)"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Acard.
 
@@ -277,6 +320,7 @@ config SATA_ACARD_AHCI
 config SATA_SIL24
        tristate "Silicon Image 3124/3132 SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Silicon Image 3124/3132 Serial ATA.
 
@@ -317,6 +361,7 @@ config PDC_ADMA
 config PATA_OCTEON_CF
        tristate "OCTEON Boot Bus Compact Flash support"
        depends on CAVIUM_OCTEON_SOC
+       select PATA_TIMINGS
        help
          This option enables a polled compact flash driver for use with
          compact flash cards attached to the OCTEON boot bus.
@@ -326,6 +371,7 @@ config PATA_OCTEON_CF
 config SATA_QSTOR
        tristate "Pacific Digital SATA QStor support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Pacific Digital Serial ATA QStor.
 
@@ -334,6 +380,7 @@ config SATA_QSTOR
 config SATA_SX4
        tristate "Promise SATA SX4 support (Experimental)"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Promise Serial ATA SX4.
 
@@ -357,6 +404,7 @@ comment "SATA SFF controllers with BMDMA"
 config ATA_PIIX
        tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for ICH5/6/7/8 Serial ATA
          and support for PATA on the Intel ESB/ICH/PIIX3/PIIX4 series
@@ -368,6 +416,7 @@ config SATA_DWC
        tristate "DesignWare Cores SATA support"
        depends on DMADEVICES
        select GENERIC_PHY
+       select SATA_HOST
        help
          This option enables support for the on-chip SATA controller of the
          AppliedMicro processor 460EX.
@@ -398,6 +447,7 @@ config SATA_DWC_VDEBUG
 config SATA_HIGHBANK
        tristate "Calxeda Highbank SATA support"
        depends on ARCH_HIGHBANK || COMPILE_TEST
+       select SATA_HOST
        help
          This option enables support for the Calxeda Highbank SoC's
          onboard SATA.
@@ -409,6 +459,7 @@ config SATA_MV
        depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \
                   ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST
        select GENERIC_PHY
+       select SATA_HOST
        help
          This option enables support for the Marvell Serial ATA family.
          Currently supports 88SX[56]0[48][01] PCI(-X) chips,
@@ -419,6 +470,7 @@ config SATA_MV
 config SATA_NV
        tristate "NVIDIA SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for NVIDIA Serial ATA.
 
@@ -427,6 +479,7 @@ config SATA_NV
 config SATA_PROMISE
        tristate "Promise SATA TX2/TX4 support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Promise Serial ATA TX2/TX4.
 
@@ -435,6 +488,7 @@ config SATA_PROMISE
 config SATA_RCAR
        tristate "Renesas R-Car SATA support"
        depends on ARCH_RENESAS || COMPILE_TEST
+       select SATA_HOST
        help
          This option enables support for Renesas R-Car Serial ATA.
 
@@ -443,6 +497,7 @@ config SATA_RCAR
 config SATA_SIL
        tristate "Silicon Image SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Silicon Image Serial ATA.
 
@@ -452,6 +507,7 @@ config SATA_SIS
        tristate "SiS 964/965/966/180 SATA support"
        depends on PCI
        select PATA_SIS
+       select SATA_HOST
        help
          This option enables support for SiS Serial ATA on
          SiS 964/965/966/180 and Parallel ATA on SiS 180.
@@ -462,6 +518,7 @@ config SATA_SIS
 config SATA_SVW
        tristate "ServerWorks Frodo / Apple K2 SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Broadcom/Serverworks/Apple K2
          SATA support.
@@ -471,6 +528,7 @@ config SATA_SVW
 config SATA_ULI
        tristate "ULi Electronics SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for ULi Electronics SATA.
 
@@ -479,6 +537,7 @@ config SATA_ULI
 config SATA_VIA
        tristate "VIA SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for VIA Serial ATA.
 
@@ -487,6 +546,7 @@ config SATA_VIA
 config SATA_VITESSE
        tristate "VITESSE VSC-7174 / INTEL 31244 SATA support"
        depends on PCI
+       select SATA_HOST
        help
          This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA.
 
@@ -497,6 +557,7 @@ comment "PATA SFF controllers with BMDMA"
 config PATA_ALI
        tristate "ALi PATA support"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for the ALi ATA interfaces
          found on the many ALi chipsets.
@@ -506,6 +567,7 @@ config PATA_ALI
 config PATA_AMD
        tristate "AMD/NVidia PATA support"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for the AMD and NVidia PATA
          interfaces found on the chipsets for Athlon/Athlon64.
@@ -540,6 +602,7 @@ config PATA_ATIIXP
 config PATA_ATP867X
        tristate "ARTOP/Acard ATP867X PATA support"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for ARTOP/Acard ATP867X PATA
          controllers.
@@ -549,6 +612,7 @@ config PATA_ATP867X
 config PATA_BK3710
        tristate "Palmchip BK3710 PATA support"
        depends on ARCH_DAVINCI
+       select PATA_TIMINGS
        help
          This option enables support for the integrated IDE controller on
          the TI DaVinci SoC.
@@ -558,6 +622,7 @@ config PATA_BK3710
 config PATA_CMD64X
        tristate "CMD64x PATA support"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for the CMD64x series chips
          except for the CMD640.
@@ -603,6 +668,7 @@ config PATA_CS5536
 config PATA_CYPRESS
        tristate "Cypress CY82C693 PATA support (Very Experimental)"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for the Cypress/Contaq CY82C693
          chipset found in some Alpha systems
@@ -621,6 +687,7 @@ config PATA_EFAR
 config PATA_EP93XX
        tristate "Cirrus Logic EP93xx PATA support"
        depends on ARCH_EP93XX
+       select PATA_TIMINGS
        help
          This option enables support for the PATA controller in
          the Cirrus Logic EP9312 and EP9315 ARM CPU.
@@ -685,6 +752,7 @@ config PATA_HPT3X3_DMA
 config PATA_ICSIDE
        tristate "Acorn ICS PATA support"
        depends on ARM && ARCH_ACORN
+       select PATA_TIMINGS
        help
          On Acorn systems, say Y here if you wish to use the ICS PATA
          interface card.  This is not required for ICS partition support.
@@ -693,6 +761,7 @@ config PATA_ICSIDE
 config PATA_IMX
        tristate "PATA support for Freescale iMX"
        depends on ARCH_MXC
+       select PATA_TIMINGS
        help
          This option enables support for the PATA host available on Freescale
           iMX SoCs.
@@ -778,6 +847,7 @@ config PATA_NINJA32
 config PATA_NS87415
        tristate "Nat Semi NS87415 PATA support"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for the National Semiconductor
          NS87415 PCI-IDE controller.
@@ -902,6 +972,7 @@ config PATA_TRIFLEX
 config PATA_VIA
        tristate "VIA PATA support"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for the VIA PATA interfaces
          found on the many VIA chipsets.
@@ -935,6 +1006,7 @@ comment "PIO-only SFF controllers"
 config PATA_CMD640_PCI
        tristate "CMD640 PCI PATA support (Experimental)"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for the CMD640 PCI IDE
          interface chip. Only the primary channel is currently
@@ -1005,6 +1077,7 @@ config PATA_MPIIX
 config PATA_NS87410
        tristate "Nat Semi NS87410 PATA support"
        depends on PCI
+       select PATA_TIMINGS
        help
          This option enables support for the National Semiconductor
          NS87410 PCI-IDE controller.
@@ -1085,6 +1158,7 @@ config PATA_RZ1000
 config PATA_SAMSUNG_CF
        tristate "Samsung SoC PATA support"
        depends on SAMSUNG_DEV_IDE
+       select PATA_TIMINGS
        help
          This option enables basic support for Samsung's S3C/S5P board
          PATA controllers via the new ATA layer
@@ -1104,6 +1178,7 @@ comment "Generic fallback / legacy drivers"
 config PATA_ACPI
        tristate "ACPI firmware driver for PATA"
        depends on ATA_ACPI && ATA_BMDMA && PCI
+       select PATA_TIMINGS
        help
          This option enables an ACPI method driver which drives
          motherboard PATA controller interfaces through the ACPI
@@ -1113,6 +1188,7 @@ config PATA_ACPI
 config ATA_GENERIC
        tristate "Generic ATA support"
        depends on PCI && ATA_BMDMA
+       select SATA_HOST
        help
          This option enables support for generic BIOS configured
          ATA controllers via the new ATA layer
@@ -1122,6 +1198,7 @@ config ATA_GENERIC
 config PATA_LEGACY
        tristate "Legacy ISA PATA support (Experimental)"
        depends on (ISA || PCI)
+       select PATA_TIMINGS
        help
          This option enables support for ISA/VLB/PCI bus legacy PATA
          ports and allows them to be accessed via the new ATA layer.
index d8cc2e0..b8aebfb 100644 (file)
@@ -123,7 +123,9 @@ obj-$(CONFIG_PATA_LEGACY)   += pata_legacy.o
 
 libata-y       := libata-core.o libata-scsi.o libata-eh.o \
        libata-transport.o libata-trace.o
+libata-$(CONFIG_SATA_HOST)     += libata-sata.o
 libata-$(CONFIG_ATA_SFF)       += libata-sff.o
 libata-$(CONFIG_SATA_PMP)      += libata-pmp.o
 libata-$(CONFIG_ATA_ACPI)      += libata-acpi.o
 libata-$(CONFIG_SATA_ZPODD)    += libata-zpodd.o
+libata-$(CONFIG_PATA_TIMINGS)  += libata-pata-timings.o
index 11ea1af..ad0185c 100644 (file)
@@ -40,6 +40,7 @@
 enum {
        AHCI_PCI_BAR_STA2X11    = 0,
        AHCI_PCI_BAR_CAVIUM     = 0,
+       AHCI_PCI_BAR_LOONGSON   = 0,
        AHCI_PCI_BAR_ENMOTUS    = 2,
        AHCI_PCI_BAR_CAVIUM_GEN5        = 4,
        AHCI_PCI_BAR_STANDARD   = 5,
@@ -245,6 +246,7 @@ static const struct ata_port_info ahci_port_info[] = {
 
 static const struct pci_device_id ahci_pci_tbl[] = {
        /* Intel */
+       { PCI_VDEVICE(INTEL, 0x06d6), board_ahci }, /* Comet Lake PCH-H RAID */
        { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
        { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
        { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
@@ -401,6 +403,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0xa252), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa256), board_ahci }, /* Lewisburg RAID*/
        { PCI_VDEVICE(INTEL, 0xa356), board_ahci }, /* Cannon Lake PCH-H RAID */
+       { PCI_VDEVICE(INTEL, 0x06d7), board_ahci }, /* Comet Lake-H RAID */
+       { PCI_VDEVICE(INTEL, 0xa386), board_ahci }, /* Comet Lake PCH-V RAID */
        { PCI_VDEVICE(INTEL, 0x0f22), board_ahci_mobile }, /* Bay Trail AHCI */
        { PCI_VDEVICE(INTEL, 0x0f23), board_ahci_mobile }, /* Bay Trail AHCI */
        { PCI_VDEVICE(INTEL, 0x22a3), board_ahci_mobile }, /* Cherry Tr. AHCI */
@@ -589,6 +593,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        /* Enmotus */
        { PCI_DEVICE(0x1c44, 0x8000), board_ahci },
 
+       /* Loongson */
+       { PCI_VDEVICE(LOONGSON, 0x7a08), board_ahci },
+
        /* Generic, PCI class code for AHCI */
        { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
          PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci },
@@ -1680,6 +1687,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                        ahci_pci_bar = AHCI_PCI_BAR_CAVIUM;
                if (pdev->device == 0xa084)
                        ahci_pci_bar = AHCI_PCI_BAR_CAVIUM_GEN5;
+       } else if (pdev->vendor == PCI_VENDOR_ID_LOONGSON) {
+               if (pdev->device == 0x7a08)
+                       ahci_pci_bar = AHCI_PCI_BAR_LOONGSON;
        }
 
        /* acquire resources */
index 42c8728..beca5f9 100644 (file)
@@ -2,10 +2,6 @@
 /*
  *  libata-core.c - helper library for ATA
  *
- *  Maintained by:  Tejun Heo <tj@kernel.org>
- *                 Please ALWAYS copy linux-ide@vger.kernel.org
- *                 on emails.
- *
  *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
  *  Copyright 2003-2004 Jeff Garzik
  *
  *     http://www.compactflash.org (CF)
  *     http://www.qic.org (QIC157 - Tape and DSC)
  *     http://www.ce-ata.org (CE-ATA: not supported)
+ *
+ * libata is essentially a library of internal helper functions for
+ * low-level ATA host controller drivers.  As such, the API/ABI is
+ * likely to change as new drivers are added and updated.
+ * Do not depend on ABI/API stability.
  */
 
 #include <linux/kernel.h>
@@ -56,6 +57,7 @@
 #include <linux/leds.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
+#include <asm/setup.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/libata.h>
 #include "libata.h"
 #include "libata-transport.h"
 
-/* debounce timing parameters in msecs { interval, duration, timeout } */
-const unsigned long sata_deb_timing_normal[]           = {   5,  100, 2000 };
-const unsigned long sata_deb_timing_hotplug[]          = {  25,  500, 2000 };
-const unsigned long sata_deb_timing_long[]             = { 100, 2000, 5000 };
-
 const struct ata_port_operations ata_base_port_ops = {
        .prereset               = ata_std_prereset,
        .postreset              = ata_std_postreset,
@@ -82,6 +79,7 @@ const struct ata_port_operations sata_port_ops = {
        .qc_defer               = ata_std_qc_defer,
        .hardreset              = sata_std_hardreset,
 };
+EXPORT_SYMBOL_GPL(sata_port_ops);
 
 static unsigned int ata_dev_init_params(struct ata_device *dev,
                                        u16 heads, u16 sectors);
@@ -91,14 +89,15 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
 
 atomic_t ata_print_id = ATOMIC_INIT(0);
 
+#ifdef CONFIG_ATA_FORCE
 struct ata_force_param {
        const char      *name;
-       unsigned int    cbl;
-       int             spd_limit;
+       u8              cbl;
+       u8              spd_limit;
        unsigned long   xfer_mask;
        unsigned int    horkage_on;
        unsigned int    horkage_off;
-       unsigned int    lflags;
+       u16             lflags;
 };
 
 struct ata_force_ent {
@@ -110,10 +109,11 @@ struct ata_force_ent {
 static struct ata_force_ent *ata_force_tbl;
 static int ata_force_tbl_size;
 
-static char ata_force_param_buf[PAGE_SIZE] __initdata;
+static char ata_force_param_buf[COMMAND_LINE_SIZE] __initdata;
 /* param_buf is thrown away after initialization, disallow read */
 module_param_string(force, ata_force_param_buf, sizeof(ata_force_param_buf), 0);
 MODULE_PARM_DESC(force, "Force ATA configurations including cable type, link speed and transfer mode (see Documentation/admin-guide/kernel-parameters.rst for details)");
+#endif
 
 static int atapi_enabled = 1;
 module_param(atapi_enabled, int, 0444);
@@ -224,6 +224,7 @@ struct ata_link *ata_link_next(struct ata_link *link, struct ata_port *ap,
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(ata_link_next);
 
 /**
  *     ata_dev_next - device iteration helper
@@ -277,6 +278,7 @@ struct ata_device *ata_dev_next(struct ata_device *dev, struct ata_link *link,
                goto next;
        return dev;
 }
+EXPORT_SYMBOL_GPL(ata_dev_next);
 
 /**
  *     ata_dev_phys_link - find physical link for a device
@@ -303,6 +305,7 @@ struct ata_link *ata_dev_phys_link(struct ata_device *dev)
        return ap->slave_link;
 }
 
+#ifdef CONFIG_ATA_FORCE
 /**
  *     ata_force_cbl - force cable type according to libata.force
  *     @ap: ATA port of interest
@@ -483,6 +486,11 @@ static void ata_force_horkage(struct ata_device *dev)
                               fe->param.name);
        }
 }
+#else
+static inline void ata_force_link_limits(struct ata_link *link) { }
+static inline void ata_force_xfermask(struct ata_device *dev) { }
+static inline void ata_force_horkage(struct ata_device *dev) { }
+#endif
 
 /**
  *     atapi_cmd_type - Determine ATAPI command type from SCSI opcode
@@ -521,79 +529,7 @@ int atapi_cmd_type(u8 opcode)
                return ATAPI_MISC;
        }
 }
-
-/**
- *     ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
- *     @tf: Taskfile to convert
- *     @pmp: Port multiplier port
- *     @is_cmd: This FIS is for command
- *     @fis: Buffer into which data will output
- *
- *     Converts a standard ATA taskfile to a Serial ATA
- *     FIS structure (Register - Host to Device).
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
-{
-       fis[0] = 0x27;                  /* Register - Host to Device FIS */
-       fis[1] = pmp & 0xf;             /* Port multiplier number*/
-       if (is_cmd)
-               fis[1] |= (1 << 7);     /* bit 7 indicates Command FIS */
-
-       fis[2] = tf->command;
-       fis[3] = tf->feature;
-
-       fis[4] = tf->lbal;
-       fis[5] = tf->lbam;
-       fis[6] = tf->lbah;
-       fis[7] = tf->device;
-
-       fis[8] = tf->hob_lbal;
-       fis[9] = tf->hob_lbam;
-       fis[10] = tf->hob_lbah;
-       fis[11] = tf->hob_feature;
-
-       fis[12] = tf->nsect;
-       fis[13] = tf->hob_nsect;
-       fis[14] = 0;
-       fis[15] = tf->ctl;
-
-       fis[16] = tf->auxiliary & 0xff;
-       fis[17] = (tf->auxiliary >> 8) & 0xff;
-       fis[18] = (tf->auxiliary >> 16) & 0xff;
-       fis[19] = (tf->auxiliary >> 24) & 0xff;
-}
-
-/**
- *     ata_tf_from_fis - Convert SATA FIS to ATA taskfile
- *     @fis: Buffer from which data will be input
- *     @tf: Taskfile to output
- *
- *     Converts a serial ATA FIS structure to a standard ATA taskfile.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-
-void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
-{
-       tf->command     = fis[2];       /* status */
-       tf->feature     = fis[3];       /* error */
-
-       tf->lbal        = fis[4];
-       tf->lbam        = fis[5];
-       tf->lbah        = fis[6];
-       tf->device      = fis[7];
-
-       tf->hob_lbal    = fis[8];
-       tf->hob_lbam    = fis[9];
-       tf->hob_lbah    = fis[10];
-
-       tf->nsect       = fis[12];
-       tf->hob_nsect   = fis[13];
-}
+EXPORT_SYMBOL_GPL(atapi_cmd_type);
 
 static const u8 ata_rw_cmds[] = {
        /* pio multi */
@@ -868,6 +804,7 @@ unsigned long ata_pack_xfermask(unsigned long pio_mask,
                ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) |
                ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA);
 }
+EXPORT_SYMBOL_GPL(ata_pack_xfermask);
 
 /**
  *     ata_unpack_xfermask - Unpack xfer_mask into pio, mwdma and udma masks
@@ -923,6 +860,7 @@ u8 ata_xfer_mask2mode(unsigned long xfer_mask)
                        return ent->base + highbit - ent->shift;
        return 0xff;
 }
+EXPORT_SYMBOL_GPL(ata_xfer_mask2mode);
 
 /**
  *     ata_xfer_mode2mask - Find matching xfer_mask for XFER_*
@@ -946,6 +884,7 @@ unsigned long ata_xfer_mode2mask(u8 xfer_mode)
                                & ~((1 << ent->shift) - 1);
        return 0;
 }
+EXPORT_SYMBOL_GPL(ata_xfer_mode2mask);
 
 /**
  *     ata_xfer_mode2shift - Find matching xfer_shift for XFER_*
@@ -968,6 +907,7 @@ int ata_xfer_mode2shift(unsigned long xfer_mode)
                        return ent->shift;
        return -1;
 }
+EXPORT_SYMBOL_GPL(ata_xfer_mode2shift);
 
 /**
  *     ata_mode_string - convert xfer_mask to string
@@ -1014,6 +954,7 @@ const char *ata_mode_string(unsigned long xfer_mask)
                return xfer_mode_str[highbit];
        return "<n/a>";
 }
+EXPORT_SYMBOL_GPL(ata_mode_string);
 
 const char *sata_spd_string(unsigned int spd)
 {
@@ -1094,6 +1035,7 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf)
        DPRINTK("unknown device\n");
        return ATA_DEV_UNKNOWN;
 }
+EXPORT_SYMBOL_GPL(ata_dev_classify);
 
 /**
  *     ata_id_string - Convert IDENTIFY DEVICE page into string
@@ -1130,6 +1072,7 @@ void ata_id_string(const u16 *id, unsigned char *s,
                len -= 2;
        }
 }
+EXPORT_SYMBOL_GPL(ata_id_string);
 
 /**
  *     ata_id_c_string - Convert IDENTIFY DEVICE page into C string
@@ -1157,6 +1100,7 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
                p--;
        *p = '\0';
 }
+EXPORT_SYMBOL_GPL(ata_id_c_string);
 
 static u64 ata_id_n_sectors(const u16 *id)
 {
@@ -1514,6 +1458,7 @@ unsigned long ata_id_xfermask(const u16 *id)
 
        return ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask);
 }
+EXPORT_SYMBOL_GPL(ata_id_xfermask);
 
 static void ata_qc_complete_internal(struct ata_queued_cmd *qc)
 {
@@ -1771,6 +1716,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
                return 1;
        return 0;
 }
+EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
 
 /**
  *     ata_pio_mask_no_iordy   -       Return the non IORDY mask
@@ -1811,6 +1757,7 @@ unsigned int ata_do_dev_read_id(struct ata_device *dev,
        return ata_exec_internal(dev, tf, NULL, DMA_FROM_DEVICE,
                                     id, sizeof(id[0]) * ATA_ID_WORDS, 0);
 }
+EXPORT_SYMBOL_GPL(ata_do_dev_read_id);
 
 /**
  *     ata_dev_read_id - Read ID data from the specified device
@@ -2265,6 +2212,8 @@ static int ata_dev_config_ncq(struct ata_device *dev,
                desc[0] = '\0';
                return 0;
        }
+       if (!IS_ENABLED(CONFIG_SATA_HOST))
+               return 0;
        if (dev->horkage & ATA_HORKAGE_NONCQ) {
                snprintf(desc, desc_sz, "NCQ (not used)");
                return 0;
@@ -2783,6 +2732,7 @@ int ata_cable_40wire(struct ata_port *ap)
 {
        return ATA_CBL_PATA40;
 }
+EXPORT_SYMBOL_GPL(ata_cable_40wire);
 
 /**
  *     ata_cable_80wire        -       return 80 wire cable type
@@ -2796,6 +2746,7 @@ int ata_cable_80wire(struct ata_port *ap)
 {
        return ATA_CBL_PATA80;
 }
+EXPORT_SYMBOL_GPL(ata_cable_80wire);
 
 /**
  *     ata_cable_unknown       -       return unknown PATA cable.
@@ -2808,6 +2759,7 @@ int ata_cable_unknown(struct ata_port *ap)
 {
        return ATA_CBL_PATA_UNK;
 }
+EXPORT_SYMBOL_GPL(ata_cable_unknown);
 
 /**
  *     ata_cable_ignore        -       return ignored PATA cable.
@@ -2820,6 +2772,7 @@ int ata_cable_ignore(struct ata_port *ap)
 {
        return ATA_CBL_PATA_IGN;
 }
+EXPORT_SYMBOL_GPL(ata_cable_ignore);
 
 /**
  *     ata_cable_sata  -       return SATA cable type
@@ -2832,6 +2785,7 @@ int ata_cable_sata(struct ata_port *ap)
 {
        return ATA_CBL_SATA;
 }
+EXPORT_SYMBOL_GPL(ata_cable_sata);
 
 /**
  *     ata_bus_probe - Reset and probe ATA bus
@@ -3014,6 +2968,7 @@ struct ata_device *ata_dev_pair(struct ata_device *adev)
                return NULL;
        return pair;
 }
+EXPORT_SYMBOL_GPL(ata_dev_pair);
 
 /**
  *     sata_down_spd_limit - adjust SATA spd limit downward
@@ -3095,252 +3050,7 @@ int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
        return 0;
 }
 
-static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
-{
-       struct ata_link *host_link = &link->ap->link;
-       u32 limit, target, spd;
-
-       limit = link->sata_spd_limit;
-
-       /* Don't configure downstream link faster than upstream link.
-        * It doesn't speed up anything and some PMPs choke on such
-        * configuration.
-        */
-       if (!ata_is_host_link(link) && host_link->sata_spd)
-               limit &= (1 << host_link->sata_spd) - 1;
-
-       if (limit == UINT_MAX)
-               target = 0;
-       else
-               target = fls(limit);
-
-       spd = (*scontrol >> 4) & 0xf;
-       *scontrol = (*scontrol & ~0xf0) | ((target & 0xf) << 4);
-
-       return spd != target;
-}
-
-/**
- *     sata_set_spd_needed - is SATA spd configuration needed
- *     @link: Link in question
- *
- *     Test whether the spd limit in SControl matches
- *     @link->sata_spd_limit.  This function is used to determine
- *     whether hardreset is necessary to apply SATA spd
- *     configuration.
- *
- *     LOCKING:
- *     Inherited from caller.
- *
- *     RETURNS:
- *     1 if SATA spd configuration is needed, 0 otherwise.
- */
-static int sata_set_spd_needed(struct ata_link *link)
-{
-       u32 scontrol;
-
-       if (sata_scr_read(link, SCR_CONTROL, &scontrol))
-               return 1;
-
-       return __sata_set_spd_needed(link, &scontrol);
-}
-
-/**
- *     sata_set_spd - set SATA spd according to spd limit
- *     @link: Link to set SATA spd for
- *
- *     Set SATA spd of @link according to sata_spd_limit.
- *
- *     LOCKING:
- *     Inherited from caller.
- *
- *     RETURNS:
- *     0 if spd doesn't need to be changed, 1 if spd has been
- *     changed.  Negative errno if SCR registers are inaccessible.
- */
-int sata_set_spd(struct ata_link *link)
-{
-       u32 scontrol;
-       int rc;
-
-       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
-               return rc;
-
-       if (!__sata_set_spd_needed(link, &scontrol))
-               return 0;
-
-       if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
-               return rc;
-
-       return 1;
-}
-
-/*
- * This mode timing computation functionality is ported over from
- * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
- */
-/*
- * PIO 0-4, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
- * These were taken from ATA/ATAPI-6 standard, rev 0a, except
- * for UDMA6, which is currently supported only by Maxtor drives.
- *
- * For PIO 5/6 MWDMA 3/4 see the CFA specification 3.0.
- */
-
-static const struct ata_timing ata_timing[] = {
-/*     { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 0,  960,   0 }, */
-       { XFER_PIO_0,     70, 290, 240, 600, 165, 150, 0,  600,   0 },
-       { XFER_PIO_1,     50, 290,  93, 383, 125, 100, 0,  383,   0 },
-       { XFER_PIO_2,     30, 290,  40, 330, 100,  90, 0,  240,   0 },
-       { XFER_PIO_3,     30,  80,  70, 180,  80,  70, 0,  180,   0 },
-       { XFER_PIO_4,     25,  70,  25, 120,  70,  25, 0,  120,   0 },
-       { XFER_PIO_5,     15,  65,  25, 100,  65,  25, 0,  100,   0 },
-       { XFER_PIO_6,     10,  55,  20,  80,  55,  20, 0,   80,   0 },
-
-       { XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 50, 960,   0 },
-       { XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 30, 480,   0 },
-       { XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 20, 240,   0 },
-
-       { XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 20, 480,   0 },
-       { XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 5,  150,   0 },
-       { XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 5,  120,   0 },
-       { XFER_MW_DMA_3,  25,   0,   0,   0,  65,  25, 5,  100,   0 },
-       { XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20, 5,   80,   0 },
-
-/*     { XFER_UDMA_SLOW,  0,   0,   0,   0,   0,   0, 0,    0, 150 }, */
-       { XFER_UDMA_0,     0,   0,   0,   0,   0,   0, 0,    0, 120 },
-       { XFER_UDMA_1,     0,   0,   0,   0,   0,   0, 0,    0,  80 },
-       { XFER_UDMA_2,     0,   0,   0,   0,   0,   0, 0,    0,  60 },
-       { XFER_UDMA_3,     0,   0,   0,   0,   0,   0, 0,    0,  45 },
-       { XFER_UDMA_4,     0,   0,   0,   0,   0,   0, 0,    0,  30 },
-       { XFER_UDMA_5,     0,   0,   0,   0,   0,   0, 0,    0,  20 },
-       { XFER_UDMA_6,     0,   0,   0,   0,   0,   0, 0,    0,  15 },
-
-       { 0xFF }
-};
-
-#define ENOUGH(v, unit)                (((v)-1)/(unit)+1)
-#define EZ(v, unit)            ((v)?ENOUGH(((v) * 1000), unit):0)
-
-static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
-{
-       q->setup        = EZ(t->setup,       T);
-       q->act8b        = EZ(t->act8b,       T);
-       q->rec8b        = EZ(t->rec8b,       T);
-       q->cyc8b        = EZ(t->cyc8b,       T);
-       q->active       = EZ(t->active,      T);
-       q->recover      = EZ(t->recover,     T);
-       q->dmack_hold   = EZ(t->dmack_hold,  T);
-       q->cycle        = EZ(t->cycle,       T);
-       q->udma         = EZ(t->udma,       UT);
-}
-
-void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
-                     struct ata_timing *m, unsigned int what)
-{
-       if (what & ATA_TIMING_SETUP  ) m->setup   = max(a->setup,   b->setup);
-       if (what & ATA_TIMING_ACT8B  ) m->act8b   = max(a->act8b,   b->act8b);
-       if (what & ATA_TIMING_REC8B  ) m->rec8b   = max(a->rec8b,   b->rec8b);
-       if (what & ATA_TIMING_CYC8B  ) m->cyc8b   = max(a->cyc8b,   b->cyc8b);
-       if (what & ATA_TIMING_ACTIVE ) m->active  = max(a->active,  b->active);
-       if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover);
-       if (what & ATA_TIMING_DMACK_HOLD) m->dmack_hold = max(a->dmack_hold, b->dmack_hold);
-       if (what & ATA_TIMING_CYCLE  ) m->cycle   = max(a->cycle,   b->cycle);
-       if (what & ATA_TIMING_UDMA   ) m->udma    = max(a->udma,    b->udma);
-}
-
-const struct ata_timing *ata_timing_find_mode(u8 xfer_mode)
-{
-       const struct ata_timing *t = ata_timing;
-
-       while (xfer_mode > t->mode)
-               t++;
-
-       if (xfer_mode == t->mode)
-               return t;
-
-       WARN_ONCE(true, "%s: unable to find timing for xfer_mode 0x%x\n",
-                       __func__, xfer_mode);
-
-       return NULL;
-}
-
-int ata_timing_compute(struct ata_device *adev, unsigned short speed,
-                      struct ata_timing *t, int T, int UT)
-{
-       const u16 *id = adev->id;
-       const struct ata_timing *s;
-       struct ata_timing p;
-
-       /*
-        * Find the mode.
-        */
-
-       if (!(s = ata_timing_find_mode(speed)))
-               return -EINVAL;
-
-       memcpy(t, s, sizeof(*s));
-
-       /*
-        * If the drive is an EIDE drive, it can tell us it needs extended
-        * PIO/MW_DMA cycle timing.
-        */
-
-       if (id[ATA_ID_FIELD_VALID] & 2) {       /* EIDE drive */
-               memset(&p, 0, sizeof(p));
-
-               if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) {
-                       if (speed <= XFER_PIO_2)
-                               p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
-                       else if ((speed <= XFER_PIO_4) ||
-                                (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
-                               p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
-               } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
-                       p.cycle = id[ATA_ID_EIDE_DMA_MIN];
-
-               ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
-       }
-
-       /*
-        * Convert the timing to bus clock counts.
-        */
-
-       ata_timing_quantize(t, t, T, UT);
-
-       /*
-        * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
-        * S.M.A.R.T * and some other commands. We have to ensure that the
-        * DMA cycle timing is slower/equal than the fastest PIO timing.
-        */
-
-       if (speed > XFER_PIO_6) {
-               ata_timing_compute(adev, adev->pio_mode, &p, T, UT);
-               ata_timing_merge(&p, t, t, ATA_TIMING_ALL);
-       }
-
-       /*
-        * Lengthen active & recovery time so that cycle time is correct.
-        */
-
-       if (t->act8b + t->rec8b < t->cyc8b) {
-               t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
-               t->rec8b = t->cyc8b - t->act8b;
-       }
-
-       if (t->active + t->recover < t->cycle) {
-               t->active += (t->cycle - (t->active + t->recover)) / 2;
-               t->recover = t->cycle - t->active;
-       }
-
-       /* In a few cases quantisation may produce enough errors to
-          leave t->cycle too low for the sum of active and recovery
-          if so we must correct this */
-       if (t->active + t->recover > t->cycle)
-               t->cycle = t->active + t->recover;
-
-       return 0;
-}
-
+#ifdef CONFIG_ATA_ACPI
 /**
  *     ata_timing_cycle2mode - find xfer mode for the specified cycle duration
  *     @xfer_shift: ATA_SHIFT_* value for transfer type to examine.
@@ -3391,6 +3101,7 @@ u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle)
 
        return last_mode;
 }
+#endif
 
 /**
  *     ata_down_xfermask_limit - adjust dev xfer masks downward
@@ -3662,6 +3373,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
                *r_failed_dev = dev;
        return rc;
 }
+EXPORT_SYMBOL_GPL(ata_do_set_mode);
 
 /**
  *     ata_wait_ready - wait for link to become ready
@@ -3771,216 +3483,7 @@ int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
 
        return ata_wait_ready(link, deadline, check_ready);
 }
-
-/**
- *     sata_link_debounce - debounce SATA phy status
- *     @link: ATA link to debounce SATA phy status for
- *     @params: timing parameters { interval, duration, timeout } in msec
- *     @deadline: deadline jiffies for the operation
- *
- *     Make sure SStatus of @link reaches stable state, determined by
- *     holding the same value where DET is not 1 for @duration polled
- *     every @interval, before @timeout.  Timeout constraints the
- *     beginning of the stable state.  Because DET gets stuck at 1 on
- *     some controllers after hot unplugging, this functions waits
- *     until timeout then returns 0 if DET is stable at 1.
- *
- *     @timeout is further limited by @deadline.  The sooner of the
- *     two is used.
- *
- *     LOCKING:
- *     Kernel thread context (may sleep)
- *
- *     RETURNS:
- *     0 on success, -errno on failure.
- */
-int sata_link_debounce(struct ata_link *link, const unsigned long *params,
-                      unsigned long deadline)
-{
-       unsigned long interval = params[0];
-       unsigned long duration = params[1];
-       unsigned long last_jiffies, t;
-       u32 last, cur;
-       int rc;
-
-       t = ata_deadline(jiffies, params[2]);
-       if (time_before(t, deadline))
-               deadline = t;
-
-       if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
-               return rc;
-       cur &= 0xf;
-
-       last = cur;
-       last_jiffies = jiffies;
-
-       while (1) {
-               ata_msleep(link->ap, interval);
-               if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
-                       return rc;
-               cur &= 0xf;
-
-               /* DET stable? */
-               if (cur == last) {
-                       if (cur == 1 && time_before(jiffies, deadline))
-                               continue;
-                       if (time_after(jiffies,
-                                      ata_deadline(last_jiffies, duration)))
-                               return 0;
-                       continue;
-               }
-
-               /* unstable, start over */
-               last = cur;
-               last_jiffies = jiffies;
-
-               /* Check deadline.  If debouncing failed, return
-                * -EPIPE to tell upper layer to lower link speed.
-                */
-               if (time_after(jiffies, deadline))
-                       return -EPIPE;
-       }
-}
-
-/**
- *     sata_link_resume - resume SATA link
- *     @link: ATA link to resume SATA
- *     @params: timing parameters { interval, duration, timeout } in msec
- *     @deadline: deadline jiffies for the operation
- *
- *     Resume SATA phy @link and debounce it.
- *
- *     LOCKING:
- *     Kernel thread context (may sleep)
- *
- *     RETURNS:
- *     0 on success, -errno on failure.
- */
-int sata_link_resume(struct ata_link *link, const unsigned long *params,
-                    unsigned long deadline)
-{
-       int tries = ATA_LINK_RESUME_TRIES;
-       u32 scontrol, serror;
-       int rc;
-
-       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
-               return rc;
-
-       /*
-        * Writes to SControl sometimes get ignored under certain
-        * controllers (ata_piix SIDPR).  Make sure DET actually is
-        * cleared.
-        */
-       do {
-               scontrol = (scontrol & 0x0f0) | 0x300;
-               if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
-                       return rc;
-               /*
-                * Some PHYs react badly if SStatus is pounded
-                * immediately after resuming.  Delay 200ms before
-                * debouncing.
-                */
-               if (!(link->flags & ATA_LFLAG_NO_DB_DELAY))
-                       ata_msleep(link->ap, 200);
-
-               /* is SControl restored correctly? */
-               if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
-                       return rc;
-       } while ((scontrol & 0xf0f) != 0x300 && --tries);
-
-       if ((scontrol & 0xf0f) != 0x300) {
-               ata_link_warn(link, "failed to resume link (SControl %X)\n",
-                            scontrol);
-               return 0;
-       }
-
-       if (tries < ATA_LINK_RESUME_TRIES)
-               ata_link_warn(link, "link resume succeeded after %d retries\n",
-                             ATA_LINK_RESUME_TRIES - tries);
-
-       if ((rc = sata_link_debounce(link, params, deadline)))
-               return rc;
-
-       /* clear SError, some PHYs require this even for SRST to work */
-       if (!(rc = sata_scr_read(link, SCR_ERROR, &serror)))
-               rc = sata_scr_write(link, SCR_ERROR, serror);
-
-       return rc != -EINVAL ? rc : 0;
-}
-
-/**
- *     sata_link_scr_lpm - manipulate SControl IPM and SPM fields
- *     @link: ATA link to manipulate SControl for
- *     @policy: LPM policy to configure
- *     @spm_wakeup: initiate LPM transition to active state
- *
- *     Manipulate the IPM field of the SControl register of @link
- *     according to @policy.  If @policy is ATA_LPM_MAX_POWER and
- *     @spm_wakeup is %true, the SPM field is manipulated to wake up
- *     the link.  This function also clears PHYRDY_CHG before
- *     returning.
- *
- *     LOCKING:
- *     EH context.
- *
- *     RETURNS:
- *     0 on success, -errno otherwise.
- */
-int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
-                     bool spm_wakeup)
-{
-       struct ata_eh_context *ehc = &link->eh_context;
-       bool woken_up = false;
-       u32 scontrol;
-       int rc;
-
-       rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
-       if (rc)
-               return rc;
-
-       switch (policy) {
-       case ATA_LPM_MAX_POWER:
-               /* disable all LPM transitions */
-               scontrol |= (0x7 << 8);
-               /* initiate transition to active state */
-               if (spm_wakeup) {
-                       scontrol |= (0x4 << 12);
-                       woken_up = true;
-               }
-               break;
-       case ATA_LPM_MED_POWER:
-               /* allow LPM to PARTIAL */
-               scontrol &= ~(0x1 << 8);
-               scontrol |= (0x6 << 8);
-               break;
-       case ATA_LPM_MED_POWER_WITH_DIPM:
-       case ATA_LPM_MIN_POWER_WITH_PARTIAL:
-       case ATA_LPM_MIN_POWER:
-               if (ata_link_nr_enabled(link) > 0)
-                       /* no restrictions on LPM transitions */
-                       scontrol &= ~(0x7 << 8);
-               else {
-                       /* empty port, power off */
-                       scontrol &= ~0xf;
-                       scontrol |= (0x1 << 2);
-               }
-               break;
-       default:
-               WARN_ON(1);
-       }
-
-       rc = sata_scr_write(link, SCR_CONTROL, scontrol);
-       if (rc)
-               return rc;
-
-       /* give the link time to transit out of LPM state */
-       if (woken_up)
-               msleep(10);
-
-       /* clear PHYRDY_CHG from SError */
-       ehc->i.serror &= ~SERR_PHYRDY_CHG;
-       return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
-}
+EXPORT_SYMBOL_GPL(ata_wait_after_reset);
 
 /**
  *     ata_std_prereset - prepare for reset
@@ -4026,118 +3529,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline)
 
        return 0;
 }
-
-/**
- *     sata_link_hardreset - reset link via SATA phy reset
- *     @link: link to reset
- *     @timing: timing parameters { interval, duration, timeout } in msec
- *     @deadline: deadline jiffies for the operation
- *     @online: optional out parameter indicating link onlineness
- *     @check_ready: optional callback to check link readiness
- *
- *     SATA phy-reset @link using DET bits of SControl register.
- *     After hardreset, link readiness is waited upon using
- *     ata_wait_ready() if @check_ready is specified.  LLDs are
- *     allowed to not specify @check_ready and wait itself after this
- *     function returns.  Device classification is LLD's
- *     responsibility.
- *
- *     *@online is set to one iff reset succeeded and @link is online
- *     after reset.
- *
- *     LOCKING:
- *     Kernel thread context (may sleep)
- *
- *     RETURNS:
- *     0 on success, -errno otherwise.
- */
-int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
-                       unsigned long deadline,
-                       bool *online, int (*check_ready)(struct ata_link *))
-{
-       u32 scontrol;
-       int rc;
-
-       DPRINTK("ENTER\n");
-
-       if (online)
-               *online = false;
-
-       if (sata_set_spd_needed(link)) {
-               /* SATA spec says nothing about how to reconfigure
-                * spd.  To be on the safe side, turn off phy during
-                * reconfiguration.  This works for at least ICH7 AHCI
-                * and Sil3124.
-                */
-               if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
-                       goto out;
-
-               scontrol = (scontrol & 0x0f0) | 0x304;
-
-               if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
-                       goto out;
-
-               sata_set_spd(link);
-       }
-
-       /* issue phy wake/reset */
-       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
-               goto out;
-
-       scontrol = (scontrol & 0x0f0) | 0x301;
-
-       if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
-               goto out;
-
-       /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
-        * 10.4.2 says at least 1 ms.
-        */
-       ata_msleep(link->ap, 1);
-
-       /* bring link back */
-       rc = sata_link_resume(link, timing, deadline);
-       if (rc)
-               goto out;
-       /* if link is offline nothing more to do */
-       if (ata_phys_link_offline(link))
-               goto out;
-
-       /* Link is online.  From this point, -ENODEV too is an error. */
-       if (online)
-               *online = true;
-
-       if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) {
-               /* If PMP is supported, we have to do follow-up SRST.
-                * Some PMPs don't send D2H Reg FIS after hardreset if
-                * the first port is empty.  Wait only for
-                * ATA_TMOUT_PMP_SRST_WAIT.
-                */
-               if (check_ready) {
-                       unsigned long pmp_deadline;
-
-                       pmp_deadline = ata_deadline(jiffies,
-                                                   ATA_TMOUT_PMP_SRST_WAIT);
-                       if (time_after(pmp_deadline, deadline))
-                               pmp_deadline = deadline;
-                       ata_wait_ready(link, pmp_deadline, check_ready);
-               }
-               rc = -EAGAIN;
-               goto out;
-       }
-
-       rc = 0;
-       if (check_ready)
-               rc = ata_wait_ready(link, deadline, check_ready);
- out:
-       if (rc && rc != -EAGAIN) {
-               /* online is set iff link is online && reset succeeded */
-               if (online)
-                       *online = false;
-               ata_link_err(link, "COMRESET failed (errno=%d)\n", rc);
-       }
-       DPRINTK("EXIT, rc=%d\n", rc);
-       return rc;
-}
+EXPORT_SYMBOL_GPL(ata_std_prereset);
 
 /**
  *     sata_std_hardreset - COMRESET w/o waiting or classification
@@ -4164,6 +3556,7 @@ int sata_std_hardreset(struct ata_link *link, unsigned int *class,
        rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
        return online ? -EAGAIN : rc;
 }
+EXPORT_SYMBOL_GPL(sata_std_hardreset);
 
 /**
  *     ata_std_postreset - standard postreset callback
@@ -4192,6 +3585,7 @@ void ata_std_postreset(struct ata_link *link, unsigned int *classes)
 
        DPRINTK("EXIT\n");
 }
+EXPORT_SYMBOL_GPL(ata_std_postreset);
 
 /**
  *     ata_dev_same_device - Determine whether new ID matches configured device
@@ -4979,11 +4373,13 @@ int ata_std_qc_defer(struct ata_queued_cmd *qc)
 
        return ATA_DEFER_LINK;
 }
+EXPORT_SYMBOL_GPL(ata_std_qc_defer);
 
 enum ata_completion_errors ata_noop_qc_prep(struct ata_queued_cmd *qc)
 {
        return AC_ERR_OK;
 }
+EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
 
 /**
  *     ata_sg_init - Associate command with scatter-gather table.
@@ -5327,6 +4723,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
                __ata_qc_complete(qc);
        }
 }
+EXPORT_SYMBOL_GPL(ata_qc_complete);
 
 /**
  *     ata_qc_get_active - get bitmask of active qcs
@@ -5353,64 +4750,6 @@ u64 ata_qc_get_active(struct ata_port *ap)
 EXPORT_SYMBOL_GPL(ata_qc_get_active);
 
 /**
- *     ata_qc_complete_multiple - Complete multiple qcs successfully
- *     @ap: port in question
- *     @qc_active: new qc_active mask
- *
- *     Complete in-flight commands.  This functions is meant to be
- *     called from low-level driver's interrupt routine to complete
- *     requests normally.  ap->qc_active and @qc_active is compared
- *     and commands are completed accordingly.
- *
- *     Always use this function when completing multiple NCQ commands
- *     from IRQ handlers instead of calling ata_qc_complete()
- *     multiple times to keep IRQ expect status properly in sync.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- *
- *     RETURNS:
- *     Number of completed commands on success, -errno otherwise.
- */
-int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active)
-{
-       u64 done_mask, ap_qc_active = ap->qc_active;
-       int nr_done = 0;
-
-       /*
-        * If the internal tag is set on ap->qc_active, then we care about
-        * bit0 on the passed in qc_active mask. Move that bit up to match
-        * the internal tag.
-        */
-       if (ap_qc_active & (1ULL << ATA_TAG_INTERNAL)) {
-               qc_active |= (qc_active & 0x01) << ATA_TAG_INTERNAL;
-               qc_active ^= qc_active & 0x01;
-       }
-
-       done_mask = ap_qc_active ^ qc_active;
-
-       if (unlikely(done_mask & qc_active)) {
-               ata_port_err(ap, "illegal qc_active transition (%08llx->%08llx)\n",
-                            ap->qc_active, qc_active);
-               return -EINVAL;
-       }
-
-       while (done_mask) {
-               struct ata_queued_cmd *qc;
-               unsigned int tag = __ffs64(done_mask);
-
-               qc = ata_qc_from_tag(ap, tag);
-               if (qc) {
-                       ata_qc_complete(qc);
-                       nr_done++;
-               }
-               done_mask &= ~(1ULL << tag);
-       }
-
-       return nr_done;
-}
-
-/**
  *     ata_qc_issue - issue taskfile to device
  *     @qc: command to issue to device
  *
@@ -5486,111 +4825,6 @@ err:
 }
 
 /**
- *     sata_scr_valid - test whether SCRs are accessible
- *     @link: ATA link to test SCR accessibility for
- *
- *     Test whether SCRs are accessible for @link.
- *
- *     LOCKING:
- *     None.
- *
- *     RETURNS:
- *     1 if SCRs are accessible, 0 otherwise.
- */
-int sata_scr_valid(struct ata_link *link)
-{
-       struct ata_port *ap = link->ap;
-
-       return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read;
-}
-
-/**
- *     sata_scr_read - read SCR register of the specified port
- *     @link: ATA link to read SCR for
- *     @reg: SCR to read
- *     @val: Place to store read value
- *
- *     Read SCR register @reg of @link into *@val.  This function is
- *     guaranteed to succeed if @link is ap->link, the cable type of
- *     the port is SATA and the port implements ->scr_read.
- *
- *     LOCKING:
- *     None if @link is ap->link.  Kernel thread context otherwise.
- *
- *     RETURNS:
- *     0 on success, negative errno on failure.
- */
-int sata_scr_read(struct ata_link *link, int reg, u32 *val)
-{
-       if (ata_is_host_link(link)) {
-               if (sata_scr_valid(link))
-                       return link->ap->ops->scr_read(link, reg, val);
-               return -EOPNOTSUPP;
-       }
-
-       return sata_pmp_scr_read(link, reg, val);
-}
-
-/**
- *     sata_scr_write - write SCR register of the specified port
- *     @link: ATA link to write SCR for
- *     @reg: SCR to write
- *     @val: value to write
- *
- *     Write @val to SCR register @reg of @link.  This function is
- *     guaranteed to succeed if @link is ap->link, the cable type of
- *     the port is SATA and the port implements ->scr_read.
- *
- *     LOCKING:
- *     None if @link is ap->link.  Kernel thread context otherwise.
- *
- *     RETURNS:
- *     0 on success, negative errno on failure.
- */
-int sata_scr_write(struct ata_link *link, int reg, u32 val)
-{
-       if (ata_is_host_link(link)) {
-               if (sata_scr_valid(link))
-                       return link->ap->ops->scr_write(link, reg, val);
-               return -EOPNOTSUPP;
-       }
-
-       return sata_pmp_scr_write(link, reg, val);
-}
-
-/**
- *     sata_scr_write_flush - write SCR register of the specified port and flush
- *     @link: ATA link to write SCR for
- *     @reg: SCR to write
- *     @val: value to write
- *
- *     This function is identical to sata_scr_write() except that this
- *     function performs flush after writing to the register.
- *
- *     LOCKING:
- *     None if @link is ap->link.  Kernel thread context otherwise.
- *
- *     RETURNS:
- *     0 on success, negative errno on failure.
- */
-int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
-{
-       if (ata_is_host_link(link)) {
-               int rc;
-
-               if (sata_scr_valid(link)) {
-                       rc = link->ap->ops->scr_write(link, reg, val);
-                       if (rc == 0)
-                               rc = link->ap->ops->scr_read(link, reg, &val);
-                       return rc;
-               }
-               return -EOPNOTSUPP;
-       }
-
-       return sata_pmp_scr_write(link, reg, val);
-}
-
-/**
  *     ata_phys_link_online - test whether the given link is online
  *     @link: ATA link to test
  *
@@ -5663,6 +4897,7 @@ bool ata_link_online(struct ata_link *link)
        return ata_phys_link_online(link) ||
                (slave && ata_phys_link_online(slave));
 }
+EXPORT_SYMBOL_GPL(ata_link_online);
 
 /**
  *     ata_link_offline - test whether the given link is offline
@@ -5689,6 +4924,7 @@ bool ata_link_offline(struct ata_link *link)
        return ata_phys_link_offline(link) &&
                (!slave || ata_phys_link_offline(slave));
 }
+EXPORT_SYMBOL_GPL(ata_link_offline);
 
 #ifdef CONFIG_PM
 static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
@@ -5875,6 +5111,7 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
        host->dev->power.power_state = mesg;
        return 0;
 }
+EXPORT_SYMBOL_GPL(ata_host_suspend);
 
 /**
  *     ata_host_resume - resume host
@@ -5886,6 +5123,7 @@ void ata_host_resume(struct ata_host *host)
 {
        host->dev->power.power_state = PMSG_ON;
 }
+EXPORT_SYMBOL_GPL(ata_host_resume);
 #endif
 
 const struct device_type ata_port_type = {
@@ -6105,6 +5343,7 @@ void ata_host_put(struct ata_host *host)
 {
        kref_put(&host->kref, ata_host_release);
 }
+EXPORT_SYMBOL_GPL(ata_host_put);
 
 /**
  *     ata_host_alloc - allocate and init basic ATA host resources
@@ -6178,6 +5417,7 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
        kfree(host);
        return NULL;
 }
+EXPORT_SYMBOL_GPL(ata_host_alloc);
 
 /**
  *     ata_host_alloc_pinfo - alloc host and init with port_info array
@@ -6226,68 +5466,7 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
 
        return host;
 }
-
-/**
- *     ata_slave_link_init - initialize slave link
- *     @ap: port to initialize slave link for
- *
- *     Create and initialize slave link for @ap.  This enables slave
- *     link handling on the port.
- *
- *     In libata, a port contains links and a link contains devices.
- *     There is single host link but if a PMP is attached to it,
- *     there can be multiple fan-out links.  On SATA, there's usually
- *     a single device connected to a link but PATA and SATA
- *     controllers emulating TF based interface can have two - master
- *     and slave.
- *
- *     However, there are a few controllers which don't fit into this
- *     abstraction too well - SATA controllers which emulate TF
- *     interface with both master and slave devices but also have
- *     separate SCR register sets for each device.  These controllers
- *     need separate links for physical link handling
- *     (e.g. onlineness, link speed) but should be treated like a
- *     traditional M/S controller for everything else (e.g. command
- *     issue, softreset).
- *
- *     slave_link is libata's way of handling this class of
- *     controllers without impacting core layer too much.  For
- *     anything other than physical link handling, the default host
- *     link is used for both master and slave.  For physical link
- *     handling, separate @ap->slave_link is used.  All dirty details
- *     are implemented inside libata core layer.  From LLD's POV, the
- *     only difference is that prereset, hardreset and postreset are
- *     called once more for the slave link, so the reset sequence
- *     looks like the following.
- *
- *     prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
- *     softreset(M) -> postreset(M) -> postreset(S)
- *
- *     Note that softreset is called only for the master.  Softreset
- *     resets both M/S by definition, so SRST on master should handle
- *     both (the standard method will work just fine).
- *
- *     LOCKING:
- *     Should be called before host is registered.
- *
- *     RETURNS:
- *     0 on success, -errno on failure.
- */
-int ata_slave_link_init(struct ata_port *ap)
-{
-       struct ata_link *link;
-
-       WARN_ON(ap->slave_link);
-       WARN_ON(ap->flags & ATA_FLAG_PMP);
-
-       link = kzalloc(sizeof(*link), GFP_KERNEL);
-       if (!link)
-               return -ENOMEM;
-
-       ata_link_init(ap, link, 1);
-       ap->slave_link = link;
-       return 0;
-}
+EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
 
 static void ata_host_stop(struct device *gendev, void *res)
 {
@@ -6436,6 +5615,7 @@ int ata_host_start(struct ata_host *host)
        devres_free(start_dr);
        return rc;
 }
+EXPORT_SYMBOL_GPL(ata_host_start);
 
 /**
  *     ata_sas_host_init - Initialize a host struct for sas (ipr, libsas)
@@ -6454,6 +5634,7 @@ void ata_host_init(struct ata_host *host, struct device *dev,
        host->ops = ops;
        kref_init(&host->kref);
 }
+EXPORT_SYMBOL_GPL(ata_host_init);
 
 void __ata_port_probe(struct ata_port *ap)
 {
@@ -6609,6 +5790,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        return rc;
 
 }
+EXPORT_SYMBOL_GPL(ata_host_register);
 
 /**
  *     ata_host_activate - start host, request IRQ and register it
@@ -6671,6 +5853,7 @@ int ata_host_activate(struct ata_host *host, int irq,
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(ata_host_activate);
 
 /**
  *     ata_port_detach - Detach ATA port in preparation of device removal
@@ -6746,6 +5929,7 @@ void ata_host_detach(struct ata_host *host)
        /* the host is dead now, dissociate ACPI */
        ata_acpi_dissociate(host);
 }
+EXPORT_SYMBOL_GPL(ata_host_detach);
 
 #ifdef CONFIG_PCI
 
@@ -6766,6 +5950,7 @@ void ata_pci_remove_one(struct pci_dev *pdev)
 
        ata_host_detach(host);
 }
+EXPORT_SYMBOL_GPL(ata_pci_remove_one);
 
 void ata_pci_shutdown_one(struct pci_dev *pdev)
 {
@@ -6786,6 +5971,7 @@ void ata_pci_shutdown_one(struct pci_dev *pdev)
                        ap->ops->port_stop(ap);
        }
 }
+EXPORT_SYMBOL_GPL(ata_pci_shutdown_one);
 
 /* move to PCI subsystem */
 int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
@@ -6820,6 +6006,7 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
 
        return (tmp == bits->val) ? 1 : 0;
 }
+EXPORT_SYMBOL_GPL(pci_test_config_bits);
 
 #ifdef CONFIG_PM
 void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
@@ -6830,6 +6017,7 @@ void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
        if (mesg.event & PM_EVENT_SLEEP)
                pci_set_power_state(pdev, PCI_D3hot);
 }
+EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
 
 int ata_pci_device_do_resume(struct pci_dev *pdev)
 {
@@ -6848,6 +6036,7 @@ int ata_pci_device_do_resume(struct pci_dev *pdev)
        pci_set_master(pdev);
        return 0;
 }
+EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
 
 int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
@@ -6862,6 +6051,7 @@ int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
 
 int ata_pci_device_resume(struct pci_dev *pdev)
 {
@@ -6873,8 +6063,8 @@ int ata_pci_device_resume(struct pci_dev *pdev)
                ata_host_resume(host);
        return rc;
 }
+EXPORT_SYMBOL_GPL(ata_pci_device_resume);
 #endif /* CONFIG_PM */
-
 #endif /* CONFIG_PCI */
 
 /**
@@ -6896,7 +6086,9 @@ int ata_platform_remove_one(struct platform_device *pdev)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ata_platform_remove_one);
 
+#ifdef CONFIG_ATA_FORCE
 static int __init ata_parse_force_one(char **cur,
                                      struct ata_force_ent *force_ent,
                                      const char **reason)
@@ -7076,6 +6268,15 @@ static void __init ata_parse_force_param(void)
        ata_force_tbl_size = idx;
 }
 
+static void ata_free_force_param(void)
+{
+       kfree(ata_force_tbl);
+}
+#else
+static inline void ata_parse_force_param(void) { }
+static inline void ata_free_force_param(void) { }
+#endif
+
 static int __init ata_init(void)
 {
        int rc;
@@ -7084,7 +6285,7 @@ static int __init ata_init(void)
 
        rc = ata_sff_init();
        if (rc) {
-               kfree(ata_force_tbl);
+               ata_free_force_param();
                return rc;
        }
 
@@ -7108,7 +6309,7 @@ static void __exit ata_exit(void)
        ata_release_transport(ata_scsi_transport_template);
        libata_transport_exit();
        ata_sff_exit();
-       kfree(ata_force_tbl);
+       ata_free_force_param();
 }
 
 subsys_initcall(ata_init);
@@ -7120,6 +6321,7 @@ int ata_ratelimit(void)
 {
        return __ratelimit(&ratelimit);
 }
+EXPORT_SYMBOL_GPL(ata_ratelimit);
 
 /**
  *     ata_msleep - ATA EH owner aware msleep
@@ -7152,6 +6354,7 @@ void ata_msleep(struct ata_port *ap, unsigned int msecs)
        if (owns_eh)
                ata_eh_acquire(ap);
 }
+EXPORT_SYMBOL_GPL(ata_msleep);
 
 /**
  *     ata_wait_register - wait until register value changes
@@ -7198,38 +6401,7 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val,
 
        return tmp;
 }
-
-/**
- *     sata_lpm_ignore_phy_events - test if PHY event should be ignored
- *     @link: Link receiving the event
- *
- *     Test whether the received PHY event has to be ignored or not.
- *
- *     LOCKING:
- *     None:
- *
- *     RETURNS:
- *     True if the event has to be ignored.
- */
-bool sata_lpm_ignore_phy_events(struct ata_link *link)
-{
-       unsigned long lpm_timeout = link->last_lpm_change +
-                                   msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY);
-
-       /* if LPM is enabled, PHYRDY doesn't mean anything */
-       if (link->lpm_policy > ATA_LPM_MAX_POWER)
-               return true;
-
-       /* ignore the first PHY event after the LPM policy changed
-        * as it is might be spurious
-        */
-       if ((link->flags & ATA_LFLAG_CHANGED) &&
-           time_before(jiffies, lpm_timeout))
-               return true;
-
-       return false;
-}
-EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events);
+EXPORT_SYMBOL_GPL(ata_wait_register);
 
 /*
  * Dummy port_ops
@@ -7251,10 +6423,12 @@ struct ata_port_operations ata_dummy_port_ops = {
        .sched_eh               = ata_std_sched_eh,
        .end_eh                 = ata_std_end_eh,
 };
+EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
 
 const struct ata_port_info ata_dummy_port_info = {
        .port_ops               = &ata_dummy_port_ops,
 };
+EXPORT_SYMBOL_GPL(ata_dummy_port_info);
 
 /*
  * Utility print functions
@@ -7322,127 +6496,3 @@ void ata_print_version(const struct device *dev, const char *version)
        dev_printk(KERN_DEBUG, dev, "version %s\n", version);
 }
 EXPORT_SYMBOL(ata_print_version);
-
-/*
- * libata is essentially a library of internal helper functions for
- * low-level ATA host controller drivers.  As such, the API/ABI is
- * likely to change as new drivers are added and updated.
- * Do not depend on ABI/API stability.
- */
-EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
-EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
-EXPORT_SYMBOL_GPL(sata_deb_timing_long);
-EXPORT_SYMBOL_GPL(ata_base_port_ops);
-EXPORT_SYMBOL_GPL(sata_port_ops);
-EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
-EXPORT_SYMBOL_GPL(ata_dummy_port_info);
-EXPORT_SYMBOL_GPL(ata_link_next);
-EXPORT_SYMBOL_GPL(ata_dev_next);
-EXPORT_SYMBOL_GPL(ata_std_bios_param);
-EXPORT_SYMBOL_GPL(ata_scsi_unlock_native_capacity);
-EXPORT_SYMBOL_GPL(ata_host_init);
-EXPORT_SYMBOL_GPL(ata_host_alloc);
-EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
-EXPORT_SYMBOL_GPL(ata_slave_link_init);
-EXPORT_SYMBOL_GPL(ata_host_start);
-EXPORT_SYMBOL_GPL(ata_host_register);
-EXPORT_SYMBOL_GPL(ata_host_activate);
-EXPORT_SYMBOL_GPL(ata_host_detach);
-EXPORT_SYMBOL_GPL(ata_sg_init);
-EXPORT_SYMBOL_GPL(ata_qc_complete);
-EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
-EXPORT_SYMBOL_GPL(atapi_cmd_type);
-EXPORT_SYMBOL_GPL(ata_tf_to_fis);
-EXPORT_SYMBOL_GPL(ata_tf_from_fis);
-EXPORT_SYMBOL_GPL(ata_pack_xfermask);
-EXPORT_SYMBOL_GPL(ata_unpack_xfermask);
-EXPORT_SYMBOL_GPL(ata_xfer_mask2mode);
-EXPORT_SYMBOL_GPL(ata_xfer_mode2mask);
-EXPORT_SYMBOL_GPL(ata_xfer_mode2shift);
-EXPORT_SYMBOL_GPL(ata_mode_string);
-EXPORT_SYMBOL_GPL(ata_id_xfermask);
-EXPORT_SYMBOL_GPL(ata_do_set_mode);
-EXPORT_SYMBOL_GPL(ata_std_qc_defer);
-EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
-EXPORT_SYMBOL_GPL(ata_dev_disable);
-EXPORT_SYMBOL_GPL(sata_set_spd);
-EXPORT_SYMBOL_GPL(ata_wait_after_reset);
-EXPORT_SYMBOL_GPL(sata_link_debounce);
-EXPORT_SYMBOL_GPL(sata_link_resume);
-EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
-EXPORT_SYMBOL_GPL(ata_std_prereset);
-EXPORT_SYMBOL_GPL(sata_link_hardreset);
-EXPORT_SYMBOL_GPL(sata_std_hardreset);
-EXPORT_SYMBOL_GPL(ata_std_postreset);
-EXPORT_SYMBOL_GPL(ata_dev_classify);
-EXPORT_SYMBOL_GPL(ata_dev_pair);
-EXPORT_SYMBOL_GPL(ata_ratelimit);
-EXPORT_SYMBOL_GPL(ata_msleep);
-EXPORT_SYMBOL_GPL(ata_wait_register);
-EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
-EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
-EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
-EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
-EXPORT_SYMBOL_GPL(__ata_change_queue_depth);
-EXPORT_SYMBOL_GPL(sata_scr_valid);
-EXPORT_SYMBOL_GPL(sata_scr_read);
-EXPORT_SYMBOL_GPL(sata_scr_write);
-EXPORT_SYMBOL_GPL(sata_scr_write_flush);
-EXPORT_SYMBOL_GPL(ata_link_online);
-EXPORT_SYMBOL_GPL(ata_link_offline);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL_GPL(ata_host_suspend);
-EXPORT_SYMBOL_GPL(ata_host_resume);
-#endif /* CONFIG_PM */
-EXPORT_SYMBOL_GPL(ata_id_string);
-EXPORT_SYMBOL_GPL(ata_id_c_string);
-EXPORT_SYMBOL_GPL(ata_do_dev_read_id);
-EXPORT_SYMBOL_GPL(ata_scsi_simulate);
-
-EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
-EXPORT_SYMBOL_GPL(ata_timing_find_mode);
-EXPORT_SYMBOL_GPL(ata_timing_compute);
-EXPORT_SYMBOL_GPL(ata_timing_merge);
-EXPORT_SYMBOL_GPL(ata_timing_cycle2mode);
-
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL_GPL(pci_test_config_bits);
-EXPORT_SYMBOL_GPL(ata_pci_shutdown_one);
-EXPORT_SYMBOL_GPL(ata_pci_remove_one);
-#ifdef CONFIG_PM
-EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
-EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
-EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
-EXPORT_SYMBOL_GPL(ata_pci_device_resume);
-#endif /* CONFIG_PM */
-#endif /* CONFIG_PCI */
-
-EXPORT_SYMBOL_GPL(ata_platform_remove_one);
-
-EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
-EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
-EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
-EXPORT_SYMBOL_GPL(ata_port_desc);
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL_GPL(ata_port_pbar_desc);
-#endif /* CONFIG_PCI */
-EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
-EXPORT_SYMBOL_GPL(ata_link_abort);
-EXPORT_SYMBOL_GPL(ata_port_abort);
-EXPORT_SYMBOL_GPL(ata_port_freeze);
-EXPORT_SYMBOL_GPL(sata_async_notification);
-EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
-EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
-EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
-EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
-EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error);
-EXPORT_SYMBOL_GPL(ata_do_eh);
-EXPORT_SYMBOL_GPL(ata_std_error_handler);
-
-EXPORT_SYMBOL_GPL(ata_cable_40wire);
-EXPORT_SYMBOL_GPL(ata_cable_80wire);
-EXPORT_SYMBOL_GPL(ata_cable_unknown);
-EXPORT_SYMBOL_GPL(ata_cable_ignore);
-EXPORT_SYMBOL_GPL(ata_cable_sata);
-EXPORT_SYMBOL_GPL(ata_host_get);
-EXPORT_SYMBOL_GPL(ata_host_put);
index 3bfd9da..474c6c3 100644 (file)
@@ -2,10 +2,6 @@
 /*
  *  libata-eh.c - libata error handling
  *
- *  Maintained by:  Tejun Heo <tj@kernel.org>
- *                 Please ALWAYS copy linux-ide@vger.kernel.org
- *                 on emails.
- *
  *  Copyright 2006 Tejun Heo <htejun@gmail.com>
  *
  *  libata documentation is available via 'make {ps|pdf}docs',
@@ -184,6 +180,7 @@ void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
        __ata_ehi_pushv_desc(ehi, fmt, args);
        va_end(args);
 }
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
 
 /**
  *     ata_ehi_push_desc - push error description with separator
@@ -207,6 +204,7 @@ void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
        __ata_ehi_pushv_desc(ehi, fmt, args);
        va_end(args);
 }
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
 
 /**
  *     ata_ehi_clear_desc - clean error description
@@ -222,6 +220,7 @@ void ata_ehi_clear_desc(struct ata_eh_info *ehi)
        ehi->desc[0] = '\0';
        ehi->desc_len = 0;
 }
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
 
 /**
  *     ata_port_desc - append port description
@@ -249,9 +248,9 @@ void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
        __ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args);
        va_end(args);
 }
+EXPORT_SYMBOL_GPL(ata_port_desc);
 
 #ifdef CONFIG_PCI
-
 /**
  *     ata_port_pbar_desc - append PCI BAR description
  *     @ap: target ATA port
@@ -288,7 +287,7 @@ void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
                ata_port_desc(ap, "%s 0x%llx", name,
                                start + (unsigned long long)offset);
 }
-
+EXPORT_SYMBOL_GPL(ata_port_pbar_desc);
 #endif /* CONFIG_PCI */
 
 static int ata_lookup_timeout_table(u8 cmd)
@@ -973,6 +972,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
        /* see: ata_std_sched_eh, unless you know better */
        ap->ops->sched_eh(ap);
 }
+EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
 
 static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
 {
@@ -1015,6 +1015,7 @@ int ata_link_abort(struct ata_link *link)
 {
        return ata_do_link_abort(link->ap, link);
 }
+EXPORT_SYMBOL_GPL(ata_link_abort);
 
 /**
  *     ata_port_abort - abort all qc's on the port
@@ -1032,6 +1033,7 @@ int ata_port_abort(struct ata_port *ap)
 {
        return ata_do_link_abort(ap, NULL);
 }
+EXPORT_SYMBOL_GPL(ata_port_abort);
 
 /**
  *     __ata_port_freeze - freeze port
@@ -1088,79 +1090,7 @@ int ata_port_freeze(struct ata_port *ap)
 
        return nr_aborted;
 }
-
-/**
- *     sata_async_notification - SATA async notification handler
- *     @ap: ATA port where async notification is received
- *
- *     Handler to be called when async notification via SDB FIS is
- *     received.  This function schedules EH if necessary.
- *
- *     LOCKING:
- *     spin_lock_irqsave(host lock)
- *
- *     RETURNS:
- *     1 if EH is scheduled, 0 otherwise.
- */
-int sata_async_notification(struct ata_port *ap)
-{
-       u32 sntf;
-       int rc;
-
-       if (!(ap->flags & ATA_FLAG_AN))
-               return 0;
-
-       rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
-       if (rc == 0)
-               sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
-
-       if (!sata_pmp_attached(ap) || rc) {
-               /* PMP is not attached or SNTF is not available */
-               if (!sata_pmp_attached(ap)) {
-                       /* PMP is not attached.  Check whether ATAPI
-                        * AN is configured.  If so, notify media
-                        * change.
-                        */
-                       struct ata_device *dev = ap->link.device;
-
-                       if ((dev->class == ATA_DEV_ATAPI) &&
-                           (dev->flags & ATA_DFLAG_AN))
-                               ata_scsi_media_change_notify(dev);
-                       return 0;
-               } else {
-                       /* PMP is attached but SNTF is not available.
-                        * ATAPI async media change notification is
-                        * not used.  The PMP must be reporting PHY
-                        * status change, schedule EH.
-                        */
-                       ata_port_schedule_eh(ap);
-                       return 1;
-               }
-       } else {
-               /* PMP is attached and SNTF is available */
-               struct ata_link *link;
-
-               /* check and notify ATAPI AN */
-               ata_for_each_link(link, ap, EDGE) {
-                       if (!(sntf & (1 << link->pmp)))
-                               continue;
-
-                       if ((link->device->class == ATA_DEV_ATAPI) &&
-                           (link->device->flags & ATA_DFLAG_AN))
-                               ata_scsi_media_change_notify(link->device);
-               }
-
-               /* If PMP is reporting that PHY status of some
-                * downstream ports has changed, schedule EH.
-                */
-               if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
-                       ata_port_schedule_eh(ap);
-                       return 1;
-               }
-
-               return 0;
-       }
-}
+EXPORT_SYMBOL_GPL(ata_port_freeze);
 
 /**
  *     ata_eh_freeze_port - EH helper to freeze port
@@ -1182,6 +1112,7 @@ void ata_eh_freeze_port(struct ata_port *ap)
        __ata_port_freeze(ap);
        spin_unlock_irqrestore(ap->lock, flags);
 }
+EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
 
 /**
  *     ata_port_thaw_port - EH helper to thaw port
@@ -1289,6 +1220,7 @@ void ata_dev_disable(struct ata_device *dev)
         */
        ata_ering_clear(&dev->ering);
 }
+EXPORT_SYMBOL_GPL(ata_dev_disable);
 
 /**
  *     ata_eh_detach_dev - detach ATA device
@@ -1420,62 +1352,6 @@ static const char *ata_err_string(unsigned int err_mask)
 }
 
 /**
- *     ata_eh_read_log_10h - Read log page 10h for NCQ error details
- *     @dev: Device to read log page 10h from
- *     @tag: Resulting tag of the failed command
- *     @tf: Resulting taskfile registers of the failed command
- *
- *     Read log page 10h to obtain NCQ error details and clear error
- *     condition.
- *
- *     LOCKING:
- *     Kernel thread context (may sleep).
- *
- *     RETURNS:
- *     0 on success, -errno otherwise.
- */
-static int ata_eh_read_log_10h(struct ata_device *dev,
-                              int *tag, struct ata_taskfile *tf)
-{
-       u8 *buf = dev->link->ap->sector_buf;
-       unsigned int err_mask;
-       u8 csum;
-       int i;
-
-       err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, 0, buf, 1);
-       if (err_mask)
-               return -EIO;
-
-       csum = 0;
-       for (i = 0; i < ATA_SECT_SIZE; i++)
-               csum += buf[i];
-       if (csum)
-               ata_dev_warn(dev, "invalid checksum 0x%x on log page 10h\n",
-                            csum);
-
-       if (buf[0] & 0x80)
-               return -ENOENT;
-
-       *tag = buf[0] & 0x1f;
-
-       tf->command = buf[2];
-       tf->feature = buf[3];
-       tf->lbal = buf[4];
-       tf->lbam = buf[5];
-       tf->lbah = buf[6];
-       tf->device = buf[7];
-       tf->hob_lbal = buf[8];
-       tf->hob_lbam = buf[9];
-       tf->hob_lbah = buf[10];
-       tf->nsect = buf[12];
-       tf->hob_nsect = buf[13];
-       if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id))
-               tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
-
-       return 0;
-}
-
-/**
  *     atapi_eh_tur - perform ATAPI TEST_UNIT_READY
  *     @dev: target ATAPI device
  *     @r_sense_key: out parameter for sense_key
@@ -1659,80 +1535,6 @@ static void ata_eh_analyze_serror(struct ata_link *link)
 }
 
 /**
- *     ata_eh_analyze_ncq_error - analyze NCQ error
- *     @link: ATA link to analyze NCQ error for
- *
- *     Read log page 10h, determine the offending qc and acquire
- *     error status TF.  For NCQ device errors, all LLDDs have to do
- *     is setting AC_ERR_DEV in ehi->err_mask.  This function takes
- *     care of the rest.
- *
- *     LOCKING:
- *     Kernel thread context (may sleep).
- */
-void ata_eh_analyze_ncq_error(struct ata_link *link)
-{
-       struct ata_port *ap = link->ap;
-       struct ata_eh_context *ehc = &link->eh_context;
-       struct ata_device *dev = link->device;
-       struct ata_queued_cmd *qc;
-       struct ata_taskfile tf;
-       int tag, rc;
-
-       /* if frozen, we can't do much */
-       if (ap->pflags & ATA_PFLAG_FROZEN)
-               return;
-
-       /* is it NCQ device error? */
-       if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
-               return;
-
-       /* has LLDD analyzed already? */
-       ata_qc_for_each_raw(ap, qc, tag) {
-               if (!(qc->flags & ATA_QCFLAG_FAILED))
-                       continue;
-
-               if (qc->err_mask)
-                       return;
-       }
-
-       /* okay, this error is ours */
-       memset(&tf, 0, sizeof(tf));
-       rc = ata_eh_read_log_10h(dev, &tag, &tf);
-       if (rc) {
-               ata_link_err(link, "failed to read log page 10h (errno=%d)\n",
-                            rc);
-               return;
-       }
-
-       if (!(link->sactive & (1 << tag))) {
-               ata_link_err(link, "log page 10h reported inactive tag %d\n",
-                            tag);
-               return;
-       }
-
-       /* we've got the perpetrator, condemn it */
-       qc = __ata_qc_from_tag(ap, tag);
-       memcpy(&qc->result_tf, &tf, sizeof(tf));
-       qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
-       qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
-       if (dev->class == ATA_DEV_ZAC &&
-           ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary)) {
-               char sense_key, asc, ascq;
-
-               sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
-               asc = (qc->result_tf.auxiliary >> 8) & 0xff;
-               ascq = qc->result_tf.auxiliary & 0xff;
-               ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq);
-               ata_scsi_set_sense_information(dev, qc->scsicmd,
-                                              &qc->result_tf);
-               qc->flags |= ATA_QCFLAG_SENSE_VALID;
-       }
-
-       ehc->i.err_mask &= ~AC_ERR_DEV;
-}
-
-/**
  *     ata_eh_analyze_tf - analyze taskfile of a failed qc
  *     @qc: qc to analyze
  *     @tf: Taskfile registers to analyze
@@ -3436,7 +3238,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
        int rc;
 
        /* if the link or host doesn't do LPM, noop */
-       if ((link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm))
+       if (!IS_ENABLED(CONFIG_SATA_HOST) ||
+           (link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm))
                return 0;
 
        /*
@@ -4052,6 +3855,7 @@ void ata_std_error_handler(struct ata_port *ap)
 
        ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset);
 }
+EXPORT_SYMBOL_GPL(ata_std_error_handler);
 
 #ifdef CONFIG_PM
 /**
diff --git a/drivers/ata/libata-pata-timings.c b/drivers/ata/libata-pata-timings.c
new file mode 100644 (file)
index 0000000..af34122
--- /dev/null
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Helper library for PATA timings
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/libata.h>
+
+/*
+ * This mode timing computation functionality is ported over from
+ * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
+ */
+/*
+ * PIO 0-4, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
+ * These were taken from ATA/ATAPI-6 standard, rev 0a, except
+ * for UDMA6, which is currently supported only by Maxtor drives.
+ *
+ * For PIO 5/6 MWDMA 3/4 see the CFA specification 3.0.
+ */
+
+static const struct ata_timing ata_timing[] = {
+/*     { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 0,  960,   0 }, */
+       { XFER_PIO_0,     70, 290, 240, 600, 165, 150, 0,  600,   0 },
+       { XFER_PIO_1,     50, 290,  93, 383, 125, 100, 0,  383,   0 },
+       { XFER_PIO_2,     30, 290,  40, 330, 100,  90, 0,  240,   0 },
+       { XFER_PIO_3,     30,  80,  70, 180,  80,  70, 0,  180,   0 },
+       { XFER_PIO_4,     25,  70,  25, 120,  70,  25, 0,  120,   0 },
+       { XFER_PIO_5,     15,  65,  25, 100,  65,  25, 0,  100,   0 },
+       { XFER_PIO_6,     10,  55,  20,  80,  55,  20, 0,   80,   0 },
+
+       { XFER_SW_DMA_0, 120,   0,   0,   0, 480, 480, 50, 960,   0 },
+       { XFER_SW_DMA_1,  90,   0,   0,   0, 240, 240, 30, 480,   0 },
+       { XFER_SW_DMA_2,  60,   0,   0,   0, 120, 120, 20, 240,   0 },
+
+       { XFER_MW_DMA_0,  60,   0,   0,   0, 215, 215, 20, 480,   0 },
+       { XFER_MW_DMA_1,  45,   0,   0,   0,  80,  50, 5,  150,   0 },
+       { XFER_MW_DMA_2,  25,   0,   0,   0,  70,  25, 5,  120,   0 },
+       { XFER_MW_DMA_3,  25,   0,   0,   0,  65,  25, 5,  100,   0 },
+       { XFER_MW_DMA_4,  25,   0,   0,   0,  55,  20, 5,   80,   0 },
+
+/*     { XFER_UDMA_SLOW,  0,   0,   0,   0,   0,   0, 0,    0, 150 }, */
+       { XFER_UDMA_0,     0,   0,   0,   0,   0,   0, 0,    0, 120 },
+       { XFER_UDMA_1,     0,   0,   0,   0,   0,   0, 0,    0,  80 },
+       { XFER_UDMA_2,     0,   0,   0,   0,   0,   0, 0,    0,  60 },
+       { XFER_UDMA_3,     0,   0,   0,   0,   0,   0, 0,    0,  45 },
+       { XFER_UDMA_4,     0,   0,   0,   0,   0,   0, 0,    0,  30 },
+       { XFER_UDMA_5,     0,   0,   0,   0,   0,   0, 0,    0,  20 },
+       { XFER_UDMA_6,     0,   0,   0,   0,   0,   0, 0,    0,  15 },
+
+       { 0xFF }
+};
+
+#define ENOUGH(v, unit)                (((v)-1)/(unit)+1)
+#define EZ(v, unit)            ((v)?ENOUGH(((v) * 1000), unit):0)
+
+static void ata_timing_quantize(const struct ata_timing *t,
+                               struct ata_timing *q, int T, int UT)
+{
+       q->setup        = EZ(t->setup,       T);
+       q->act8b        = EZ(t->act8b,       T);
+       q->rec8b        = EZ(t->rec8b,       T);
+       q->cyc8b        = EZ(t->cyc8b,       T);
+       q->active       = EZ(t->active,      T);
+       q->recover      = EZ(t->recover,     T);
+       q->dmack_hold   = EZ(t->dmack_hold,  T);
+       q->cycle        = EZ(t->cycle,       T);
+       q->udma         = EZ(t->udma,       UT);
+}
+
+void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
+                     struct ata_timing *m, unsigned int what)
+{
+       if (what & ATA_TIMING_SETUP)
+               m->setup = max(a->setup, b->setup);
+       if (what & ATA_TIMING_ACT8B)
+               m->act8b = max(a->act8b, b->act8b);
+       if (what & ATA_TIMING_REC8B)
+               m->rec8b = max(a->rec8b, b->rec8b);
+       if (what & ATA_TIMING_CYC8B)
+               m->cyc8b = max(a->cyc8b, b->cyc8b);
+       if (what & ATA_TIMING_ACTIVE)
+               m->active = max(a->active, b->active);
+       if (what & ATA_TIMING_RECOVER)
+               m->recover = max(a->recover, b->recover);
+       if (what & ATA_TIMING_DMACK_HOLD)
+               m->dmack_hold = max(a->dmack_hold, b->dmack_hold);
+       if (what & ATA_TIMING_CYCLE)
+               m->cycle = max(a->cycle, b->cycle);
+       if (what & ATA_TIMING_UDMA)
+               m->udma = max(a->udma, b->udma);
+}
+EXPORT_SYMBOL_GPL(ata_timing_merge);
+
+const struct ata_timing *ata_timing_find_mode(u8 xfer_mode)
+{
+       const struct ata_timing *t = ata_timing;
+
+       while (xfer_mode > t->mode)
+               t++;
+
+       if (xfer_mode == t->mode)
+               return t;
+
+       WARN_ONCE(true, "%s: unable to find timing for xfer_mode 0x%x\n",
+                       __func__, xfer_mode);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(ata_timing_find_mode);
+
+int ata_timing_compute(struct ata_device *adev, unsigned short speed,
+                      struct ata_timing *t, int T, int UT)
+{
+       const u16 *id = adev->id;
+       const struct ata_timing *s;
+       struct ata_timing p;
+
+       /*
+        * Find the mode.
+        */
+       s = ata_timing_find_mode(speed);
+       if (!s)
+               return -EINVAL;
+
+       memcpy(t, s, sizeof(*s));
+
+       /*
+        * If the drive is an EIDE drive, it can tell us it needs extended
+        * PIO/MW_DMA cycle timing.
+        */
+
+       if (id[ATA_ID_FIELD_VALID] & 2) {       /* EIDE drive */
+               memset(&p, 0, sizeof(p));
+
+               if (speed >= XFER_PIO_0 && speed < XFER_SW_DMA_0) {
+                       if (speed <= XFER_PIO_2)
+                               p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO];
+                       else if ((speed <= XFER_PIO_4) ||
+                                (speed == XFER_PIO_5 && !ata_id_is_cfa(id)))
+                               p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY];
+               } else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
+                       p.cycle = id[ATA_ID_EIDE_DMA_MIN];
+
+               ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B);
+       }
+
+       /*
+        * Convert the timing to bus clock counts.
+        */
+
+       ata_timing_quantize(t, t, T, UT);
+
+       /*
+        * Even in DMA/UDMA modes we still use PIO access for IDENTIFY,
+        * S.M.A.R.T * and some other commands. We have to ensure that the
+        * DMA cycle timing is slower/equal than the fastest PIO timing.
+        */
+
+       if (speed > XFER_PIO_6) {
+               ata_timing_compute(adev, adev->pio_mode, &p, T, UT);
+               ata_timing_merge(&p, t, t, ATA_TIMING_ALL);
+       }
+
+       /*
+        * Lengthen active & recovery time so that cycle time is correct.
+        */
+
+       if (t->act8b + t->rec8b < t->cyc8b) {
+               t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2;
+               t->rec8b = t->cyc8b - t->act8b;
+       }
+
+       if (t->active + t->recover < t->cycle) {
+               t->active += (t->cycle - (t->active + t->recover)) / 2;
+               t->recover = t->cycle - t->active;
+       }
+
+       /*
+        * In a few cases quantisation may produce enough errors to
+        * leave t->cycle too low for the sum of active and recovery
+        * if so we must correct this.
+        */
+       if (t->active + t->recover > t->cycle)
+               t->cycle = t->active + t->recover;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_timing_compute);
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
new file mode 100644 (file)
index 0000000..c16423e
--- /dev/null
@@ -0,0 +1,1483 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  SATA specific part of ATA helper library
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+ *  Copyright 2003-2004 Jeff Garzik
+ *  Copyright 2006 Tejun Heo <htejun@gmail.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <linux/libata.h>
+
+#include "libata.h"
+#include "libata-transport.h"
+
+/* debounce timing parameters in msecs { interval, duration, timeout } */
+const unsigned long sata_deb_timing_normal[]           = {   5,  100, 2000 };
+EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
+const unsigned long sata_deb_timing_hotplug[]          = {  25,  500, 2000 };
+EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
+const unsigned long sata_deb_timing_long[]             = { 100, 2000, 5000 };
+EXPORT_SYMBOL_GPL(sata_deb_timing_long);
+
+/**
+ *     sata_scr_valid - test whether SCRs are accessible
+ *     @link: ATA link to test SCR accessibility for
+ *
+ *     Test whether SCRs are accessible for @link.
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     RETURNS:
+ *     1 if SCRs are accessible, 0 otherwise.
+ */
+int sata_scr_valid(struct ata_link *link)
+{
+       struct ata_port *ap = link->ap;
+
+       return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read;
+}
+EXPORT_SYMBOL_GPL(sata_scr_valid);
+
+/**
+ *     sata_scr_read - read SCR register of the specified port
+ *     @link: ATA link to read SCR for
+ *     @reg: SCR to read
+ *     @val: Place to store read value
+ *
+ *     Read SCR register @reg of @link into *@val.  This function is
+ *     guaranteed to succeed if @link is ap->link, the cable type of
+ *     the port is SATA and the port implements ->scr_read.
+ *
+ *     LOCKING:
+ *     None if @link is ap->link.  Kernel thread context otherwise.
+ *
+ *     RETURNS:
+ *     0 on success, negative errno on failure.
+ */
+int sata_scr_read(struct ata_link *link, int reg, u32 *val)
+{
+       if (ata_is_host_link(link)) {
+               if (sata_scr_valid(link))
+                       return link->ap->ops->scr_read(link, reg, val);
+               return -EOPNOTSUPP;
+       }
+
+       return sata_pmp_scr_read(link, reg, val);
+}
+EXPORT_SYMBOL_GPL(sata_scr_read);
+
+/**
+ *     sata_scr_write - write SCR register of the specified port
+ *     @link: ATA link to write SCR for
+ *     @reg: SCR to write
+ *     @val: value to write
+ *
+ *     Write @val to SCR register @reg of @link.  This function is
+ *     guaranteed to succeed if @link is ap->link, the cable type of
+ *     the port is SATA and the port implements ->scr_read.
+ *
+ *     LOCKING:
+ *     None if @link is ap->link.  Kernel thread context otherwise.
+ *
+ *     RETURNS:
+ *     0 on success, negative errno on failure.
+ */
+int sata_scr_write(struct ata_link *link, int reg, u32 val)
+{
+       if (ata_is_host_link(link)) {
+               if (sata_scr_valid(link))
+                       return link->ap->ops->scr_write(link, reg, val);
+               return -EOPNOTSUPP;
+       }
+
+       return sata_pmp_scr_write(link, reg, val);
+}
+EXPORT_SYMBOL_GPL(sata_scr_write);
+
+/**
+ *     sata_scr_write_flush - write SCR register of the specified port and flush
+ *     @link: ATA link to write SCR for
+ *     @reg: SCR to write
+ *     @val: value to write
+ *
+ *     This function is identical to sata_scr_write() except that this
+ *     function performs flush after writing to the register.
+ *
+ *     LOCKING:
+ *     None if @link is ap->link.  Kernel thread context otherwise.
+ *
+ *     RETURNS:
+ *     0 on success, negative errno on failure.
+ */
+int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
+{
+       if (ata_is_host_link(link)) {
+               int rc;
+
+               if (sata_scr_valid(link)) {
+                       rc = link->ap->ops->scr_write(link, reg, val);
+                       if (rc == 0)
+                               rc = link->ap->ops->scr_read(link, reg, &val);
+                       return rc;
+               }
+               return -EOPNOTSUPP;
+       }
+
+       return sata_pmp_scr_write(link, reg, val);
+}
+EXPORT_SYMBOL_GPL(sata_scr_write_flush);
+
+/**
+ *     ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+ *     @tf: Taskfile to convert
+ *     @pmp: Port multiplier port
+ *     @is_cmd: This FIS is for command
+ *     @fis: Buffer into which data will output
+ *
+ *     Converts a standard ATA taskfile to a Serial ATA
+ *     FIS structure (Register - Host to Device).
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
+{
+       fis[0] = 0x27;                  /* Register - Host to Device FIS */
+       fis[1] = pmp & 0xf;             /* Port multiplier number*/
+       if (is_cmd)
+               fis[1] |= (1 << 7);     /* bit 7 indicates Command FIS */
+
+       fis[2] = tf->command;
+       fis[3] = tf->feature;
+
+       fis[4] = tf->lbal;
+       fis[5] = tf->lbam;
+       fis[6] = tf->lbah;
+       fis[7] = tf->device;
+
+       fis[8] = tf->hob_lbal;
+       fis[9] = tf->hob_lbam;
+       fis[10] = tf->hob_lbah;
+       fis[11] = tf->hob_feature;
+
+       fis[12] = tf->nsect;
+       fis[13] = tf->hob_nsect;
+       fis[14] = 0;
+       fis[15] = tf->ctl;
+
+       fis[16] = tf->auxiliary & 0xff;
+       fis[17] = (tf->auxiliary >> 8) & 0xff;
+       fis[18] = (tf->auxiliary >> 16) & 0xff;
+       fis[19] = (tf->auxiliary >> 24) & 0xff;
+}
+EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+
+/**
+ *     ata_tf_from_fis - Convert SATA FIS to ATA taskfile
+ *     @fis: Buffer from which data will be input
+ *     @tf: Taskfile to output
+ *
+ *     Converts a serial ATA FIS structure to a standard ATA taskfile.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf)
+{
+       tf->command     = fis[2];       /* status */
+       tf->feature     = fis[3];       /* error */
+
+       tf->lbal        = fis[4];
+       tf->lbam        = fis[5];
+       tf->lbah        = fis[6];
+       tf->device      = fis[7];
+
+       tf->hob_lbal    = fis[8];
+       tf->hob_lbam    = fis[9];
+       tf->hob_lbah    = fis[10];
+
+       tf->nsect       = fis[12];
+       tf->hob_nsect   = fis[13];
+}
+EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+
+/**
+ *     sata_link_debounce - debounce SATA phy status
+ *     @link: ATA link to debounce SATA phy status for
+ *     @params: timing parameters { interval, duration, timeout } in msec
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Make sure SStatus of @link reaches stable state, determined by
+ *     holding the same value where DET is not 1 for @duration polled
+ *     every @interval, before @timeout.  Timeout constraints the
+ *     beginning of the stable state.  Because DET gets stuck at 1 on
+ *     some controllers after hot unplugging, this functions waits
+ *     until timeout then returns 0 if DET is stable at 1.
+ *
+ *     @timeout is further limited by @deadline.  The sooner of the
+ *     two is used.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int sata_link_debounce(struct ata_link *link, const unsigned long *params,
+                      unsigned long deadline)
+{
+       unsigned long interval = params[0];
+       unsigned long duration = params[1];
+       unsigned long last_jiffies, t;
+       u32 last, cur;
+       int rc;
+
+       t = ata_deadline(jiffies, params[2]);
+       if (time_before(t, deadline))
+               deadline = t;
+
+       if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
+               return rc;
+       cur &= 0xf;
+
+       last = cur;
+       last_jiffies = jiffies;
+
+       while (1) {
+               ata_msleep(link->ap, interval);
+               if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
+                       return rc;
+               cur &= 0xf;
+
+               /* DET stable? */
+               if (cur == last) {
+                       if (cur == 1 && time_before(jiffies, deadline))
+                               continue;
+                       if (time_after(jiffies,
+                                      ata_deadline(last_jiffies, duration)))
+                               return 0;
+                       continue;
+               }
+
+               /* unstable, start over */
+               last = cur;
+               last_jiffies = jiffies;
+
+               /* Check deadline.  If debouncing failed, return
+                * -EPIPE to tell upper layer to lower link speed.
+                */
+               if (time_after(jiffies, deadline))
+                       return -EPIPE;
+       }
+}
+EXPORT_SYMBOL_GPL(sata_link_debounce);
+
+/**
+ *     sata_link_resume - resume SATA link
+ *     @link: ATA link to resume SATA
+ *     @params: timing parameters { interval, duration, timeout } in msec
+ *     @deadline: deadline jiffies for the operation
+ *
+ *     Resume SATA phy @link and debounce it.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int sata_link_resume(struct ata_link *link, const unsigned long *params,
+                    unsigned long deadline)
+{
+       int tries = ATA_LINK_RESUME_TRIES;
+       u32 scontrol, serror;
+       int rc;
+
+       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
+               return rc;
+
+       /*
+        * Writes to SControl sometimes get ignored under certain
+        * controllers (ata_piix SIDPR).  Make sure DET actually is
+        * cleared.
+        */
+       do {
+               scontrol = (scontrol & 0x0f0) | 0x300;
+               if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
+                       return rc;
+               /*
+                * Some PHYs react badly if SStatus is pounded
+                * immediately after resuming.  Delay 200ms before
+                * debouncing.
+                */
+               if (!(link->flags & ATA_LFLAG_NO_DB_DELAY))
+                       ata_msleep(link->ap, 200);
+
+               /* is SControl restored correctly? */
+               if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
+                       return rc;
+       } while ((scontrol & 0xf0f) != 0x300 && --tries);
+
+       if ((scontrol & 0xf0f) != 0x300) {
+               ata_link_warn(link, "failed to resume link (SControl %X)\n",
+                            scontrol);
+               return 0;
+       }
+
+       if (tries < ATA_LINK_RESUME_TRIES)
+               ata_link_warn(link, "link resume succeeded after %d retries\n",
+                             ATA_LINK_RESUME_TRIES - tries);
+
+       if ((rc = sata_link_debounce(link, params, deadline)))
+               return rc;
+
+       /* clear SError, some PHYs require this even for SRST to work */
+       if (!(rc = sata_scr_read(link, SCR_ERROR, &serror)))
+               rc = sata_scr_write(link, SCR_ERROR, serror);
+
+       return rc != -EINVAL ? rc : 0;
+}
+EXPORT_SYMBOL_GPL(sata_link_resume);
+
+/**
+ *     sata_link_scr_lpm - manipulate SControl IPM and SPM fields
+ *     @link: ATA link to manipulate SControl for
+ *     @policy: LPM policy to configure
+ *     @spm_wakeup: initiate LPM transition to active state
+ *
+ *     Manipulate the IPM field of the SControl register of @link
+ *     according to @policy.  If @policy is ATA_LPM_MAX_POWER and
+ *     @spm_wakeup is %true, the SPM field is manipulated to wake up
+ *     the link.  This function also clears PHYRDY_CHG before
+ *     returning.
+ *
+ *     LOCKING:
+ *     EH context.
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                     bool spm_wakeup)
+{
+       struct ata_eh_context *ehc = &link->eh_context;
+       bool woken_up = false;
+       u32 scontrol;
+       int rc;
+
+       rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+       if (rc)
+               return rc;
+
+       switch (policy) {
+       case ATA_LPM_MAX_POWER:
+               /* disable all LPM transitions */
+               scontrol |= (0x7 << 8);
+               /* initiate transition to active state */
+               if (spm_wakeup) {
+                       scontrol |= (0x4 << 12);
+                       woken_up = true;
+               }
+               break;
+       case ATA_LPM_MED_POWER:
+               /* allow LPM to PARTIAL */
+               scontrol &= ~(0x1 << 8);
+               scontrol |= (0x6 << 8);
+               break;
+       case ATA_LPM_MED_POWER_WITH_DIPM:
+       case ATA_LPM_MIN_POWER_WITH_PARTIAL:
+       case ATA_LPM_MIN_POWER:
+               if (ata_link_nr_enabled(link) > 0)
+                       /* no restrictions on LPM transitions */
+                       scontrol &= ~(0x7 << 8);
+               else {
+                       /* empty port, power off */
+                       scontrol &= ~0xf;
+                       scontrol |= (0x1 << 2);
+               }
+               break;
+       default:
+               WARN_ON(1);
+       }
+
+       rc = sata_scr_write(link, SCR_CONTROL, scontrol);
+       if (rc)
+               return rc;
+
+       /* give the link time to transit out of LPM state */
+       if (woken_up)
+               msleep(10);
+
+       /* clear PHYRDY_CHG from SError */
+       ehc->i.serror &= ~SERR_PHYRDY_CHG;
+       return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+}
+EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
+
+static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
+{
+       struct ata_link *host_link = &link->ap->link;
+       u32 limit, target, spd;
+
+       limit = link->sata_spd_limit;
+
+       /* Don't configure downstream link faster than upstream link.
+        * It doesn't speed up anything and some PMPs choke on such
+        * configuration.
+        */
+       if (!ata_is_host_link(link) && host_link->sata_spd)
+               limit &= (1 << host_link->sata_spd) - 1;
+
+       if (limit == UINT_MAX)
+               target = 0;
+       else
+               target = fls(limit);
+
+       spd = (*scontrol >> 4) & 0xf;
+       *scontrol = (*scontrol & ~0xf0) | ((target & 0xf) << 4);
+
+       return spd != target;
+}
+
+/**
+ *     sata_set_spd_needed - is SATA spd configuration needed
+ *     @link: Link in question
+ *
+ *     Test whether the spd limit in SControl matches
+ *     @link->sata_spd_limit.  This function is used to determine
+ *     whether hardreset is necessary to apply SATA spd
+ *     configuration.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ *
+ *     RETURNS:
+ *     1 if SATA spd configuration is needed, 0 otherwise.
+ */
+static int sata_set_spd_needed(struct ata_link *link)
+{
+       u32 scontrol;
+
+       if (sata_scr_read(link, SCR_CONTROL, &scontrol))
+               return 1;
+
+       return __sata_set_spd_needed(link, &scontrol);
+}
+
+/**
+ *     sata_set_spd - set SATA spd according to spd limit
+ *     @link: Link to set SATA spd for
+ *
+ *     Set SATA spd of @link according to sata_spd_limit.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ *
+ *     RETURNS:
+ *     0 if spd doesn't need to be changed, 1 if spd has been
+ *     changed.  Negative errno if SCR registers are inaccessible.
+ */
+int sata_set_spd(struct ata_link *link)
+{
+       u32 scontrol;
+       int rc;
+
+       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
+               return rc;
+
+       if (!__sata_set_spd_needed(link, &scontrol))
+               return 0;
+
+       if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
+               return rc;
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(sata_set_spd);
+
+/**
+ *     sata_link_hardreset - reset link via SATA phy reset
+ *     @link: link to reset
+ *     @timing: timing parameters { interval, duration, timeout } in msec
+ *     @deadline: deadline jiffies for the operation
+ *     @online: optional out parameter indicating link onlineness
+ *     @check_ready: optional callback to check link readiness
+ *
+ *     SATA phy-reset @link using DET bits of SControl register.
+ *     After hardreset, link readiness is waited upon using
+ *     ata_wait_ready() if @check_ready is specified.  LLDs are
+ *     allowed to not specify @check_ready and wait itself after this
+ *     function returns.  Device classification is LLD's
+ *     responsibility.
+ *
+ *     *@online is set to one iff reset succeeded and @link is online
+ *     after reset.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep)
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
+                       unsigned long deadline,
+                       bool *online, int (*check_ready)(struct ata_link *))
+{
+       u32 scontrol;
+       int rc;
+
+       DPRINTK("ENTER\n");
+
+       if (online)
+               *online = false;
+
+       if (sata_set_spd_needed(link)) {
+               /* SATA spec says nothing about how to reconfigure
+                * spd.  To be on the safe side, turn off phy during
+                * reconfiguration.  This works for at least ICH7 AHCI
+                * and Sil3124.
+                */
+               if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
+                       goto out;
+
+               scontrol = (scontrol & 0x0f0) | 0x304;
+
+               if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
+                       goto out;
+
+               sata_set_spd(link);
+       }
+
+       /* issue phy wake/reset */
+       if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
+               goto out;
+
+       scontrol = (scontrol & 0x0f0) | 0x301;
+
+       if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
+               goto out;
+
+       /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
+        * 10.4.2 says at least 1 ms.
+        */
+       ata_msleep(link->ap, 1);
+
+       /* bring link back */
+       rc = sata_link_resume(link, timing, deadline);
+       if (rc)
+               goto out;
+       /* if link is offline nothing more to do */
+       if (ata_phys_link_offline(link))
+               goto out;
+
+       /* Link is online.  From this point, -ENODEV too is an error. */
+       if (online)
+               *online = true;
+
+       if (sata_pmp_supported(link->ap) && ata_is_host_link(link)) {
+               /* If PMP is supported, we have to do follow-up SRST.
+                * Some PMPs don't send D2H Reg FIS after hardreset if
+                * the first port is empty.  Wait only for
+                * ATA_TMOUT_PMP_SRST_WAIT.
+                */
+               if (check_ready) {
+                       unsigned long pmp_deadline;
+
+                       pmp_deadline = ata_deadline(jiffies,
+                                                   ATA_TMOUT_PMP_SRST_WAIT);
+                       if (time_after(pmp_deadline, deadline))
+                               pmp_deadline = deadline;
+                       ata_wait_ready(link, pmp_deadline, check_ready);
+               }
+               rc = -EAGAIN;
+               goto out;
+       }
+
+       rc = 0;
+       if (check_ready)
+               rc = ata_wait_ready(link, deadline, check_ready);
+ out:
+       if (rc && rc != -EAGAIN) {
+               /* online is set iff link is online && reset succeeded */
+               if (online)
+                       *online = false;
+               ata_link_err(link, "COMRESET failed (errno=%d)\n", rc);
+       }
+       DPRINTK("EXIT, rc=%d\n", rc);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(sata_link_hardreset);
+
+/**
+ *     ata_qc_complete_multiple - Complete multiple qcs successfully
+ *     @ap: port in question
+ *     @qc_active: new qc_active mask
+ *
+ *     Complete in-flight commands.  This functions is meant to be
+ *     called from low-level driver's interrupt routine to complete
+ *     requests normally.  ap->qc_active and @qc_active is compared
+ *     and commands are completed accordingly.
+ *
+ *     Always use this function when completing multiple NCQ commands
+ *     from IRQ handlers instead of calling ata_qc_complete()
+ *     multiple times to keep IRQ expect status properly in sync.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     Number of completed commands on success, -errno otherwise.
+ */
+int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active)
+{
+       u64 done_mask, ap_qc_active = ap->qc_active;
+       int nr_done = 0;
+
+       /*
+        * If the internal tag is set on ap->qc_active, then we care about
+        * bit0 on the passed in qc_active mask. Move that bit up to match
+        * the internal tag.
+        */
+       if (ap_qc_active & (1ULL << ATA_TAG_INTERNAL)) {
+               qc_active |= (qc_active & 0x01) << ATA_TAG_INTERNAL;
+               qc_active ^= qc_active & 0x01;
+       }
+
+       done_mask = ap_qc_active ^ qc_active;
+
+       if (unlikely(done_mask & qc_active)) {
+               ata_port_err(ap, "illegal qc_active transition (%08llx->%08llx)\n",
+                            ap->qc_active, qc_active);
+               return -EINVAL;
+       }
+
+       while (done_mask) {
+               struct ata_queued_cmd *qc;
+               unsigned int tag = __ffs64(done_mask);
+
+               qc = ata_qc_from_tag(ap, tag);
+               if (qc) {
+                       ata_qc_complete(qc);
+                       nr_done++;
+               }
+               done_mask &= ~(1ULL << tag);
+       }
+
+       return nr_done;
+}
+EXPORT_SYMBOL_GPL(ata_qc_complete_multiple);
+
+/**
+ *     ata_slave_link_init - initialize slave link
+ *     @ap: port to initialize slave link for
+ *
+ *     Create and initialize slave link for @ap.  This enables slave
+ *     link handling on the port.
+ *
+ *     In libata, a port contains links and a link contains devices.
+ *     There is single host link but if a PMP is attached to it,
+ *     there can be multiple fan-out links.  On SATA, there's usually
+ *     a single device connected to a link but PATA and SATA
+ *     controllers emulating TF based interface can have two - master
+ *     and slave.
+ *
+ *     However, there are a few controllers which don't fit into this
+ *     abstraction too well - SATA controllers which emulate TF
+ *     interface with both master and slave devices but also have
+ *     separate SCR register sets for each device.  These controllers
+ *     need separate links for physical link handling
+ *     (e.g. onlineness, link speed) but should be treated like a
+ *     traditional M/S controller for everything else (e.g. command
+ *     issue, softreset).
+ *
+ *     slave_link is libata's way of handling this class of
+ *     controllers without impacting core layer too much.  For
+ *     anything other than physical link handling, the default host
+ *     link is used for both master and slave.  For physical link
+ *     handling, separate @ap->slave_link is used.  All dirty details
+ *     are implemented inside libata core layer.  From LLD's POV, the
+ *     only difference is that prereset, hardreset and postreset are
+ *     called once more for the slave link, so the reset sequence
+ *     looks like the following.
+ *
+ *     prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
+ *     softreset(M) -> postreset(M) -> postreset(S)
+ *
+ *     Note that softreset is called only for the master.  Softreset
+ *     resets both M/S by definition, so SRST on master should handle
+ *     both (the standard method will work just fine).
+ *
+ *     LOCKING:
+ *     Should be called before host is registered.
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int ata_slave_link_init(struct ata_port *ap)
+{
+       struct ata_link *link;
+
+       WARN_ON(ap->slave_link);
+       WARN_ON(ap->flags & ATA_FLAG_PMP);
+
+       link = kzalloc(sizeof(*link), GFP_KERNEL);
+       if (!link)
+               return -ENOMEM;
+
+       ata_link_init(ap, link, 1);
+       ap->slave_link = link;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_slave_link_init);
+
+/**
+ *     sata_lpm_ignore_phy_events - test if PHY event should be ignored
+ *     @link: Link receiving the event
+ *
+ *     Test whether the received PHY event has to be ignored or not.
+ *
+ *     LOCKING:
+ *     None:
+ *
+ *     RETURNS:
+ *     True if the event has to be ignored.
+ */
+bool sata_lpm_ignore_phy_events(struct ata_link *link)
+{
+       unsigned long lpm_timeout = link->last_lpm_change +
+                                   msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY);
+
+       /* if LPM is enabled, PHYRDY doesn't mean anything */
+       if (link->lpm_policy > ATA_LPM_MAX_POWER)
+               return true;
+
+       /* ignore the first PHY event after the LPM policy changed
+        * as it is might be spurious
+        */
+       if ((link->flags & ATA_LFLAG_CHANGED) &&
+           time_before(jiffies, lpm_timeout))
+               return true;
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events);
+
+static const char *ata_lpm_policy_names[] = {
+       [ATA_LPM_UNKNOWN]               = "max_performance",
+       [ATA_LPM_MAX_POWER]             = "max_performance",
+       [ATA_LPM_MED_POWER]             = "medium_power",
+       [ATA_LPM_MED_POWER_WITH_DIPM]   = "med_power_with_dipm",
+       [ATA_LPM_MIN_POWER_WITH_PARTIAL] = "min_power_with_partial",
+       [ATA_LPM_MIN_POWER]             = "min_power",
+};
+
+static ssize_t ata_scsi_lpm_store(struct device *device,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       struct Scsi_Host *shost = class_to_shost(device);
+       struct ata_port *ap = ata_shost_to_port(shost);
+       struct ata_link *link;
+       struct ata_device *dev;
+       enum ata_lpm_policy policy;
+       unsigned long flags;
+
+       /* UNKNOWN is internal state, iterate from MAX_POWER */
+       for (policy = ATA_LPM_MAX_POWER;
+            policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) {
+               const char *name = ata_lpm_policy_names[policy];
+
+               if (strncmp(name, buf, strlen(name)) == 0)
+                       break;
+       }
+       if (policy == ARRAY_SIZE(ata_lpm_policy_names))
+               return -EINVAL;
+
+       spin_lock_irqsave(ap->lock, flags);
+
+       ata_for_each_link(link, ap, EDGE) {
+               ata_for_each_dev(dev, &ap->link, ENABLED) {
+                       if (dev->horkage & ATA_HORKAGE_NOLPM) {
+                               count = -EOPNOTSUPP;
+                               goto out_unlock;
+                       }
+               }
+       }
+
+       ap->target_lpm_policy = policy;
+       ata_port_schedule_eh(ap);
+out_unlock:
+       spin_unlock_irqrestore(ap->lock, flags);
+       return count;
+}
+
+static ssize_t ata_scsi_lpm_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ata_port *ap = ata_shost_to_port(shost);
+
+       if (ap->target_lpm_policy >= ARRAY_SIZE(ata_lpm_policy_names))
+               return -EINVAL;
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       ata_lpm_policy_names[ap->target_lpm_policy]);
+}
+DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
+           ata_scsi_lpm_show, ata_scsi_lpm_store);
+EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
+
+static ssize_t ata_ncq_prio_enable_show(struct device *device,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(device);
+       struct ata_port *ap;
+       struct ata_device *dev;
+       bool ncq_prio_enable;
+       int rc = 0;
+
+       ap = ata_shost_to_port(sdev->host);
+
+       spin_lock_irq(ap->lock);
+       dev = ata_scsi_find_dev(ap, sdev);
+       if (!dev) {
+               rc = -ENODEV;
+               goto unlock;
+       }
+
+       ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE;
+
+unlock:
+       spin_unlock_irq(ap->lock);
+
+       return rc ? rc : snprintf(buf, 20, "%u\n", ncq_prio_enable);
+}
+
+static ssize_t ata_ncq_prio_enable_store(struct device *device,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t len)
+{
+       struct scsi_device *sdev = to_scsi_device(device);
+       struct ata_port *ap;
+       struct ata_device *dev;
+       long int input;
+       int rc;
+
+       rc = kstrtol(buf, 10, &input);
+       if (rc)
+               return rc;
+       if ((input < 0) || (input > 1))
+               return -EINVAL;
+
+       ap = ata_shost_to_port(sdev->host);
+       dev = ata_scsi_find_dev(ap, sdev);
+       if (unlikely(!dev))
+               return  -ENODEV;
+
+       spin_lock_irq(ap->lock);
+       if (input)
+               dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLE;
+       else
+               dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE;
+
+       dev->link->eh_info.action |= ATA_EH_REVALIDATE;
+       dev->link->eh_info.flags |= ATA_EHI_QUIET;
+       ata_port_schedule_eh(ap);
+       spin_unlock_irq(ap->lock);
+
+       ata_port_wait_eh(ap);
+
+       if (input) {
+               spin_lock_irq(ap->lock);
+               if (!(dev->flags & ATA_DFLAG_NCQ_PRIO)) {
+                       dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE;
+                       rc = -EIO;
+               }
+               spin_unlock_irq(ap->lock);
+       }
+
+       return rc ? rc : len;
+}
+
+DEVICE_ATTR(ncq_prio_enable, S_IRUGO | S_IWUSR,
+           ata_ncq_prio_enable_show, ata_ncq_prio_enable_store);
+EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_enable);
+
+struct device_attribute *ata_ncq_sdev_attrs[] = {
+       &dev_attr_unload_heads,
+       &dev_attr_ncq_prio_enable,
+       NULL
+};
+EXPORT_SYMBOL_GPL(ata_ncq_sdev_attrs);
+
+static ssize_t
+ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ata_port *ap = ata_shost_to_port(shost);
+       if (ap->ops->em_store && (ap->flags & ATA_FLAG_EM))
+               return ap->ops->em_store(ap, buf, count);
+       return -EINVAL;
+}
+
+static ssize_t
+ata_scsi_em_message_show(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ata_port *ap = ata_shost_to_port(shost);
+
+       if (ap->ops->em_show && (ap->flags & ATA_FLAG_EM))
+               return ap->ops->em_show(ap, buf);
+       return -EINVAL;
+}
+DEVICE_ATTR(em_message, S_IRUGO | S_IWUSR,
+               ata_scsi_em_message_show, ata_scsi_em_message_store);
+EXPORT_SYMBOL_GPL(dev_attr_em_message);
+
+static ssize_t
+ata_scsi_em_message_type_show(struct device *dev, struct device_attribute *attr,
+                             char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(dev);
+       struct ata_port *ap = ata_shost_to_port(shost);
+
+       return snprintf(buf, 23, "%d\n", ap->em_message_type);
+}
+DEVICE_ATTR(em_message_type, S_IRUGO,
+                 ata_scsi_em_message_type_show, NULL);
+EXPORT_SYMBOL_GPL(dev_attr_em_message_type);
+
+static ssize_t
+ata_scsi_activity_show(struct device *dev, struct device_attribute *attr,
+               char *buf)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct ata_port *ap = ata_shost_to_port(sdev->host);
+       struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
+
+       if (atadev && ap->ops->sw_activity_show &&
+           (ap->flags & ATA_FLAG_SW_ACTIVITY))
+               return ap->ops->sw_activity_show(atadev, buf);
+       return -EINVAL;
+}
+
+static ssize_t
+ata_scsi_activity_store(struct device *dev, struct device_attribute *attr,
+       const char *buf, size_t count)
+{
+       struct scsi_device *sdev = to_scsi_device(dev);
+       struct ata_port *ap = ata_shost_to_port(sdev->host);
+       struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
+       enum sw_activity val;
+       int rc;
+
+       if (atadev && ap->ops->sw_activity_store &&
+           (ap->flags & ATA_FLAG_SW_ACTIVITY)) {
+               val = simple_strtoul(buf, NULL, 0);
+               switch (val) {
+               case OFF: case BLINK_ON: case BLINK_OFF:
+                       rc = ap->ops->sw_activity_store(atadev, val);
+                       if (!rc)
+                               return count;
+                       else
+                               return rc;
+               }
+       }
+       return -EINVAL;
+}
+DEVICE_ATTR(sw_activity, S_IWUSR | S_IRUGO, ata_scsi_activity_show,
+                       ata_scsi_activity_store);
+EXPORT_SYMBOL_GPL(dev_attr_sw_activity);
+
+/**
+ *     __ata_change_queue_depth - helper for ata_scsi_change_queue_depth
+ *     @ap: ATA port to which the device change the queue depth
+ *     @sdev: SCSI device to configure queue depth for
+ *     @queue_depth: new queue depth
+ *
+ *     libsas and libata have different approaches for associating a sdev to
+ *     its ata_port.
+ *
+ */
+int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
+                            int queue_depth)
+{
+       struct ata_device *dev;
+       unsigned long flags;
+
+       if (queue_depth < 1 || queue_depth == sdev->queue_depth)
+               return sdev->queue_depth;
+
+       dev = ata_scsi_find_dev(ap, sdev);
+       if (!dev || !ata_dev_enabled(dev))
+               return sdev->queue_depth;
+
+       /* NCQ enabled? */
+       spin_lock_irqsave(ap->lock, flags);
+       dev->flags &= ~ATA_DFLAG_NCQ_OFF;
+       if (queue_depth == 1 || !ata_ncq_enabled(dev)) {
+               dev->flags |= ATA_DFLAG_NCQ_OFF;
+               queue_depth = 1;
+       }
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       /* limit and apply queue depth */
+       queue_depth = min(queue_depth, sdev->host->can_queue);
+       queue_depth = min(queue_depth, ata_id_queue_depth(dev->id));
+       queue_depth = min(queue_depth, ATA_MAX_QUEUE);
+
+       if (sdev->queue_depth == queue_depth)
+               return -EINVAL;
+
+       return scsi_change_queue_depth(sdev, queue_depth);
+}
+EXPORT_SYMBOL_GPL(__ata_change_queue_depth);
+
+/**
+ *     ata_scsi_change_queue_depth - SCSI callback for queue depth config
+ *     @sdev: SCSI device to configure queue depth for
+ *     @queue_depth: new queue depth
+ *
+ *     This is libata standard hostt->change_queue_depth callback.
+ *     SCSI will call into this callback when user tries to set queue
+ *     depth via sysfs.
+ *
+ *     LOCKING:
+ *     SCSI layer (we don't care)
+ *
+ *     RETURNS:
+ *     Newly configured queue depth.
+ */
+int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+       struct ata_port *ap = ata_shost_to_port(sdev->host);
+
+       return __ata_change_queue_depth(ap, sdev, queue_depth);
+}
+EXPORT_SYMBOL_GPL(ata_scsi_change_queue_depth);
+
+/**
+ *     port_alloc - Allocate port for a SAS attached SATA device
+ *     @host: ATA host container for all SAS ports
+ *     @port_info: Information from low-level host driver
+ *     @shost: SCSI host that the scsi device is attached to
+ *
+ *     LOCKING:
+ *     PCI/etc. bus probe sem.
+ *
+ *     RETURNS:
+ *     ata_port pointer on success / NULL on failure.
+ */
+
+struct ata_port *ata_sas_port_alloc(struct ata_host *host,
+                                   struct ata_port_info *port_info,
+                                   struct Scsi_Host *shost)
+{
+       struct ata_port *ap;
+
+       ap = ata_port_alloc(host);
+       if (!ap)
+               return NULL;
+
+       ap->port_no = 0;
+       ap->lock = &host->lock;
+       ap->pio_mask = port_info->pio_mask;
+       ap->mwdma_mask = port_info->mwdma_mask;
+       ap->udma_mask = port_info->udma_mask;
+       ap->flags |= port_info->flags;
+       ap->ops = port_info->port_ops;
+       ap->cbl = ATA_CBL_SATA;
+
+       return ap;
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
+
+/**
+ *     ata_sas_port_start - Set port up for dma.
+ *     @ap: Port to initialize
+ *
+ *     Called just after data structures for each port are
+ *     initialized.
+ *
+ *     May be used as the port_start() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+int ata_sas_port_start(struct ata_port *ap)
+{
+       /*
+        * the port is marked as frozen at allocation time, but if we don't
+        * have new eh, we won't thaw it
+        */
+       if (!ap->ops->error_handler)
+               ap->pflags &= ~ATA_PFLAG_FROZEN;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_start);
+
+/**
+ *     ata_port_stop - Undo ata_sas_port_start()
+ *     @ap: Port to shut down
+ *
+ *     May be used as the port_stop() entry in ata_port_operations.
+ *
+ *     LOCKING:
+ *     Inherited from caller.
+ */
+
+void ata_sas_port_stop(struct ata_port *ap)
+{
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_stop);
+
+/**
+ * ata_sas_async_probe - simply schedule probing and return
+ * @ap: Port to probe
+ *
+ * For batch scheduling of probe for sas attached ata devices, assumes
+ * the port has already been through ata_sas_port_init()
+ */
+void ata_sas_async_probe(struct ata_port *ap)
+{
+       __ata_port_probe(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_async_probe);
+
+int ata_sas_sync_probe(struct ata_port *ap)
+{
+       return ata_port_probe(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_sync_probe);
+
+
+/**
+ *     ata_sas_port_init - Initialize a SATA device
+ *     @ap: SATA port to initialize
+ *
+ *     LOCKING:
+ *     PCI/etc. bus probe sem.
+ *
+ *     RETURNS:
+ *     Zero on success, non-zero on error.
+ */
+
+int ata_sas_port_init(struct ata_port *ap)
+{
+       int rc = ap->ops->port_start(ap);
+
+       if (rc)
+               return rc;
+       ap->print_id = atomic_inc_return(&ata_print_id);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_init);
+
+int ata_sas_tport_add(struct device *parent, struct ata_port *ap)
+{
+       return ata_tport_add(parent, ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_tport_add);
+
+void ata_sas_tport_delete(struct ata_port *ap)
+{
+       ata_tport_delete(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_tport_delete);
+
+/**
+ *     ata_sas_port_destroy - Destroy a SATA port allocated by ata_sas_port_alloc
+ *     @ap: SATA port to destroy
+ *
+ */
+
+void ata_sas_port_destroy(struct ata_port *ap)
+{
+       if (ap->ops->port_stop)
+               ap->ops->port_stop(ap);
+       kfree(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
+
+/**
+ *     ata_sas_slave_configure - Default slave_config routine for libata devices
+ *     @sdev: SCSI device to configure
+ *     @ap: ATA port to which SCSI device is attached
+ *
+ *     RETURNS:
+ *     Zero.
+ */
+
+int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
+{
+       ata_scsi_sdev_config(sdev);
+       ata_scsi_dev_config(sdev, ap->link.device);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
+
+/**
+ *     ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
+ *     @cmd: SCSI command to be sent
+ *     @ap:    ATA port to which the command is being sent
+ *
+ *     RETURNS:
+ *     Return value from __ata_scsi_queuecmd() if @cmd can be queued,
+ *     0 otherwise.
+ */
+
+int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
+{
+       int rc = 0;
+
+       ata_scsi_dump_cdb(ap, cmd);
+
+       if (likely(ata_dev_enabled(ap->link.device)))
+               rc = __ata_scsi_queuecmd(cmd, ap->link.device);
+       else {
+               cmd->result = (DID_BAD_TARGET << 16);
+               cmd->scsi_done(cmd);
+       }
+       return rc;
+}
+EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
+
+int ata_sas_allocate_tag(struct ata_port *ap)
+{
+       unsigned int max_queue = ap->host->n_tags;
+       unsigned int i, tag;
+
+       for (i = 0, tag = ap->sas_last_tag + 1; i < max_queue; i++, tag++) {
+               tag = tag < max_queue ? tag : 0;
+
+               /* the last tag is reserved for internal command. */
+               if (ata_tag_internal(tag))
+                       continue;
+
+               if (!test_and_set_bit(tag, &ap->sas_tag_allocated)) {
+                       ap->sas_last_tag = tag;
+                       return tag;
+               }
+       }
+       return -1;
+}
+
+void ata_sas_free_tag(unsigned int tag, struct ata_port *ap)
+{
+       clear_bit(tag, &ap->sas_tag_allocated);
+}
+
+/**
+ *     sata_async_notification - SATA async notification handler
+ *     @ap: ATA port where async notification is received
+ *
+ *     Handler to be called when async notification via SDB FIS is
+ *     received.  This function schedules EH if necessary.
+ *
+ *     LOCKING:
+ *     spin_lock_irqsave(host lock)
+ *
+ *     RETURNS:
+ *     1 if EH is scheduled, 0 otherwise.
+ */
+int sata_async_notification(struct ata_port *ap)
+{
+       u32 sntf;
+       int rc;
+
+       if (!(ap->flags & ATA_FLAG_AN))
+               return 0;
+
+       rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+       if (rc == 0)
+               sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+       if (!sata_pmp_attached(ap) || rc) {
+               /* PMP is not attached or SNTF is not available */
+               if (!sata_pmp_attached(ap)) {
+                       /* PMP is not attached.  Check whether ATAPI
+                        * AN is configured.  If so, notify media
+                        * change.
+                        */
+                       struct ata_device *dev = ap->link.device;
+
+                       if ((dev->class == ATA_DEV_ATAPI) &&
+                           (dev->flags & ATA_DFLAG_AN))
+                               ata_scsi_media_change_notify(dev);
+                       return 0;
+               } else {
+                       /* PMP is attached but SNTF is not available.
+                        * ATAPI async media change notification is
+                        * not used.  The PMP must be reporting PHY
+                        * status change, schedule EH.
+                        */
+                       ata_port_schedule_eh(ap);
+                       return 1;
+               }
+       } else {
+               /* PMP is attached and SNTF is available */
+               struct ata_link *link;
+
+               /* check and notify ATAPI AN */
+               ata_for_each_link(link, ap, EDGE) {
+                       if (!(sntf & (1 << link->pmp)))
+                               continue;
+
+                       if ((link->device->class == ATA_DEV_ATAPI) &&
+                           (link->device->flags & ATA_DFLAG_AN))
+                               ata_scsi_media_change_notify(link->device);
+               }
+
+               /* If PMP is reporting that PHY status of some
+                * downstream ports has changed, schedule EH.
+                */
+               if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
+                       ata_port_schedule_eh(ap);
+                       return 1;
+               }
+
+               return 0;
+       }
+}
+EXPORT_SYMBOL_GPL(sata_async_notification);
+
+/**
+ *     ata_eh_read_log_10h - Read log page 10h for NCQ error details
+ *     @dev: Device to read log page 10h from
+ *     @tag: Resulting tag of the failed command
+ *     @tf: Resulting taskfile registers of the failed command
+ *
+ *     Read log page 10h to obtain NCQ error details and clear error
+ *     condition.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+static int ata_eh_read_log_10h(struct ata_device *dev,
+                              int *tag, struct ata_taskfile *tf)
+{
+       u8 *buf = dev->link->ap->sector_buf;
+       unsigned int err_mask;
+       u8 csum;
+       int i;
+
+       err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, 0, buf, 1);
+       if (err_mask)
+               return -EIO;
+
+       csum = 0;
+       for (i = 0; i < ATA_SECT_SIZE; i++)
+               csum += buf[i];
+       if (csum)
+               ata_dev_warn(dev, "invalid checksum 0x%x on log page 10h\n",
+                            csum);
+
+       if (buf[0] & 0x80)
+               return -ENOENT;
+
+       *tag = buf[0] & 0x1f;
+
+       tf->command = buf[2];
+       tf->feature = buf[3];
+       tf->lbal = buf[4];
+       tf->lbam = buf[5];
+       tf->lbah = buf[6];
+       tf->device = buf[7];
+       tf->hob_lbal = buf[8];
+       tf->hob_lbam = buf[9];
+       tf->hob_lbah = buf[10];
+       tf->nsect = buf[12];
+       tf->hob_nsect = buf[13];
+       if (dev->class == ATA_DEV_ZAC && ata_id_has_ncq_autosense(dev->id))
+               tf->auxiliary = buf[14] << 16 | buf[15] << 8 | buf[16];
+
+       return 0;
+}
+
+/**
+ *     ata_eh_analyze_ncq_error - analyze NCQ error
+ *     @link: ATA link to analyze NCQ error for
+ *
+ *     Read log page 10h, determine the offending qc and acquire
+ *     error status TF.  For NCQ device errors, all LLDDs have to do
+ *     is setting AC_ERR_DEV in ehi->err_mask.  This function takes
+ *     care of the rest.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+void ata_eh_analyze_ncq_error(struct ata_link *link)
+{
+       struct ata_port *ap = link->ap;
+       struct ata_eh_context *ehc = &link->eh_context;
+       struct ata_device *dev = link->device;
+       struct ata_queued_cmd *qc;
+       struct ata_taskfile tf;
+       int tag, rc;
+
+       /* if frozen, we can't do much */
+       if (ap->pflags & ATA_PFLAG_FROZEN)
+               return;
+
+       /* is it NCQ device error? */
+       if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+               return;
+
+       /* has LLDD analyzed already? */
+       ata_qc_for_each_raw(ap, qc, tag) {
+               if (!(qc->flags & ATA_QCFLAG_FAILED))
+                       continue;
+
+               if (qc->err_mask)
+                       return;
+       }
+
+       /* okay, this error is ours */
+       memset(&tf, 0, sizeof(tf));
+       rc = ata_eh_read_log_10h(dev, &tag, &tf);
+       if (rc) {
+               ata_link_err(link, "failed to read log page 10h (errno=%d)\n",
+                            rc);
+               return;
+       }
+
+       if (!(link->sactive & (1 << tag))) {
+               ata_link_err(link, "log page 10h reported inactive tag %d\n",
+                            tag);
+               return;
+       }
+
+       /* we've got the perpetrator, condemn it */
+       qc = __ata_qc_from_tag(ap, tag);
+       memcpy(&qc->result_tf, &tf, sizeof(tf));
+       qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
+       qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
+       if (dev->class == ATA_DEV_ZAC &&
+           ((qc->result_tf.command & ATA_SENSE) || qc->result_tf.auxiliary)) {
+               char sense_key, asc, ascq;
+
+               sense_key = (qc->result_tf.auxiliary >> 16) & 0xff;
+               asc = (qc->result_tf.auxiliary >> 8) & 0xff;
+               ascq = qc->result_tf.auxiliary & 0xff;
+               ata_scsi_set_sense(dev, qc->scsicmd, sense_key, asc, ascq);
+               ata_scsi_set_sense_information(dev, qc->scsicmd,
+                                              &qc->result_tf);
+               qc->flags |= ATA_QCFLAG_SENSE_VALID;
+       }
+
+       ehc->i.err_mask &= ~AC_ERR_DEV;
+}
+EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error);
index eb2eb59..36e588d 100644 (file)
@@ -2,10 +2,6 @@
 /*
  *  libata-scsi.c - helper library for ATA
  *
- *  Maintained by:  Tejun Heo <tj@kernel.org>
- *                 Please ALWAYS copy linux-ide@vger.kernel.org
- *                 on emails.
- *
  *  Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
  *  Copyright 2003-2004 Jeff Garzik
  *
 #include <linux/suspend.h>
 #include <asm/unaligned.h>
 #include <linux/ioprio.h>
+#include <linux/of.h>
 
 #include "libata.h"
 #include "libata-transport.h"
 
-#define ATA_SCSI_RBUF_SIZE     4096
+#define ATA_SCSI_RBUF_SIZE     576
 
 static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
 static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];
@@ -49,8 +46,6 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
 
 static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
                                        const struct scsi_device *scsidev);
-static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
-                                           const struct scsi_device *scsidev);
 
 #define RW_RECOVERY_MPAGE 0x1
 #define RW_RECOVERY_MPAGE_LEN 12
@@ -90,71 +85,6 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
        0, 30   /* extended self test time, see 05-359r1 */
 };
 
-static const char *ata_lpm_policy_names[] = {
-       [ATA_LPM_UNKNOWN]               = "max_performance",
-       [ATA_LPM_MAX_POWER]             = "max_performance",
-       [ATA_LPM_MED_POWER]             = "medium_power",
-       [ATA_LPM_MED_POWER_WITH_DIPM]   = "med_power_with_dipm",
-       [ATA_LPM_MIN_POWER_WITH_PARTIAL] = "min_power_with_partial",
-       [ATA_LPM_MIN_POWER]             = "min_power",
-};
-
-static ssize_t ata_scsi_lpm_store(struct device *device,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t count)
-{
-       struct Scsi_Host *shost = class_to_shost(device);
-       struct ata_port *ap = ata_shost_to_port(shost);
-       struct ata_link *link;
-       struct ata_device *dev;
-       enum ata_lpm_policy policy;
-       unsigned long flags;
-
-       /* UNKNOWN is internal state, iterate from MAX_POWER */
-       for (policy = ATA_LPM_MAX_POWER;
-            policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) {
-               const char *name = ata_lpm_policy_names[policy];
-
-               if (strncmp(name, buf, strlen(name)) == 0)
-                       break;
-       }
-       if (policy == ARRAY_SIZE(ata_lpm_policy_names))
-               return -EINVAL;
-
-       spin_lock_irqsave(ap->lock, flags);
-
-       ata_for_each_link(link, ap, EDGE) {
-               ata_for_each_dev(dev, &ap->link, ENABLED) {
-                       if (dev->horkage & ATA_HORKAGE_NOLPM) {
-                               count = -EOPNOTSUPP;
-                               goto out_unlock;
-                       }
-               }
-       }
-
-       ap->target_lpm_policy = policy;
-       ata_port_schedule_eh(ap);
-out_unlock:
-       spin_unlock_irqrestore(ap->lock, flags);
-       return count;
-}
-
-static ssize_t ata_scsi_lpm_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct ata_port *ap = ata_shost_to_port(shost);
-
-       if (ap->target_lpm_policy >= ARRAY_SIZE(ata_lpm_policy_names))
-               return -EINVAL;
-
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       ata_lpm_policy_names[ap->target_lpm_policy]);
-}
-DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
-           ata_scsi_lpm_show, ata_scsi_lpm_store);
-EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
-
 static ssize_t ata_scsi_park_show(struct device *device,
                                  struct device_attribute *attr, char *buf)
 {
@@ -258,83 +188,6 @@ DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
            ata_scsi_park_show, ata_scsi_park_store);
 EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
 
-static ssize_t ata_ncq_prio_enable_show(struct device *device,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct scsi_device *sdev = to_scsi_device(device);
-       struct ata_port *ap;
-       struct ata_device *dev;
-       bool ncq_prio_enable;
-       int rc = 0;
-
-       ap = ata_shost_to_port(sdev->host);
-
-       spin_lock_irq(ap->lock);
-       dev = ata_scsi_find_dev(ap, sdev);
-       if (!dev) {
-               rc = -ENODEV;
-               goto unlock;
-       }
-
-       ncq_prio_enable = dev->flags & ATA_DFLAG_NCQ_PRIO_ENABLE;
-
-unlock:
-       spin_unlock_irq(ap->lock);
-
-       return rc ? rc : snprintf(buf, 20, "%u\n", ncq_prio_enable);
-}
-
-static ssize_t ata_ncq_prio_enable_store(struct device *device,
-                                        struct device_attribute *attr,
-                                        const char *buf, size_t len)
-{
-       struct scsi_device *sdev = to_scsi_device(device);
-       struct ata_port *ap;
-       struct ata_device *dev;
-       long int input;
-       int rc;
-
-       rc = kstrtol(buf, 10, &input);
-       if (rc)
-               return rc;
-       if ((input < 0) || (input > 1))
-               return -EINVAL;
-
-       ap = ata_shost_to_port(sdev->host);
-       dev = ata_scsi_find_dev(ap, sdev);
-       if (unlikely(!dev))
-               return  -ENODEV;
-
-       spin_lock_irq(ap->lock);
-       if (input)
-               dev->flags |= ATA_DFLAG_NCQ_PRIO_ENABLE;
-       else
-               dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE;
-
-       dev->link->eh_info.action |= ATA_EH_REVALIDATE;
-       dev->link->eh_info.flags |= ATA_EHI_QUIET;
-       ata_port_schedule_eh(ap);
-       spin_unlock_irq(ap->lock);
-
-       ata_port_wait_eh(ap);
-
-       if (input) {
-               spin_lock_irq(ap->lock);
-               if (!(dev->flags & ATA_DFLAG_NCQ_PRIO)) {
-                       dev->flags &= ~ATA_DFLAG_NCQ_PRIO_ENABLE;
-                       rc = -EIO;
-               }
-               spin_unlock_irq(ap->lock);
-       }
-
-       return rc ? rc : len;
-}
-
-DEVICE_ATTR(ncq_prio_enable, S_IRUGO | S_IWUSR,
-           ata_ncq_prio_enable_show, ata_ncq_prio_enable_store);
-EXPORT_SYMBOL_GPL(dev_attr_ncq_prio_enable);
-
 void ata_scsi_set_sense(struct ata_device *dev, struct scsi_cmnd *cmd,
                        u8 sk, u8 asc, u8 ascq)
 {
@@ -383,90 +236,8 @@ static void ata_scsi_set_invalid_parameter(struct ata_device *dev,
                                     field, 0xff, 0);
 }
 
-static ssize_t
-ata_scsi_em_message_store(struct device *dev, struct device_attribute *attr,
-                         const char *buf, size_t count)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct ata_port *ap = ata_shost_to_port(shost);
-       if (ap->ops->em_store && (ap->flags & ATA_FLAG_EM))
-               return ap->ops->em_store(ap, buf, count);
-       return -EINVAL;
-}
-
-static ssize_t
-ata_scsi_em_message_show(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct ata_port *ap = ata_shost_to_port(shost);
-
-       if (ap->ops->em_show && (ap->flags & ATA_FLAG_EM))
-               return ap->ops->em_show(ap, buf);
-       return -EINVAL;
-}
-DEVICE_ATTR(em_message, S_IRUGO | S_IWUSR,
-               ata_scsi_em_message_show, ata_scsi_em_message_store);
-EXPORT_SYMBOL_GPL(dev_attr_em_message);
-
-static ssize_t
-ata_scsi_em_message_type_show(struct device *dev, struct device_attribute *attr,
-                             char *buf)
-{
-       struct Scsi_Host *shost = class_to_shost(dev);
-       struct ata_port *ap = ata_shost_to_port(shost);
-
-       return snprintf(buf, 23, "%d\n", ap->em_message_type);
-}
-DEVICE_ATTR(em_message_type, S_IRUGO,
-                 ata_scsi_em_message_type_show, NULL);
-EXPORT_SYMBOL_GPL(dev_attr_em_message_type);
-
-static ssize_t
-ata_scsi_activity_show(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct scsi_device *sdev = to_scsi_device(dev);
-       struct ata_port *ap = ata_shost_to_port(sdev->host);
-       struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
-
-       if (atadev && ap->ops->sw_activity_show &&
-           (ap->flags & ATA_FLAG_SW_ACTIVITY))
-               return ap->ops->sw_activity_show(atadev, buf);
-       return -EINVAL;
-}
-
-static ssize_t
-ata_scsi_activity_store(struct device *dev, struct device_attribute *attr,
-       const char *buf, size_t count)
-{
-       struct scsi_device *sdev = to_scsi_device(dev);
-       struct ata_port *ap = ata_shost_to_port(sdev->host);
-       struct ata_device *atadev = ata_scsi_find_dev(ap, sdev);
-       enum sw_activity val;
-       int rc;
-
-       if (atadev && ap->ops->sw_activity_store &&
-           (ap->flags & ATA_FLAG_SW_ACTIVITY)) {
-               val = simple_strtoul(buf, NULL, 0);
-               switch (val) {
-               case OFF: case BLINK_ON: case BLINK_OFF:
-                       rc = ap->ops->sw_activity_store(atadev, val);
-                       if (!rc)
-                               return count;
-                       else
-                               return rc;
-               }
-       }
-       return -EINVAL;
-}
-DEVICE_ATTR(sw_activity, S_IWUSR | S_IRUGO, ata_scsi_activity_show,
-                       ata_scsi_activity_store);
-EXPORT_SYMBOL_GPL(dev_attr_sw_activity);
-
 struct device_attribute *ata_common_sdev_attrs[] = {
        &dev_attr_unload_heads,
-       &dev_attr_ncq_prio_enable,
        NULL
 };
 EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
@@ -499,6 +270,7 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ata_std_bios_param);
 
 /**
  *     ata_scsi_unlock_native_capacity - unlock native capacity
@@ -528,6 +300,7 @@ void ata_scsi_unlock_native_capacity(struct scsi_device *sdev)
        spin_unlock_irqrestore(ap->lock, flags);
        ata_port_wait_eh(ap);
 }
+EXPORT_SYMBOL_GPL(ata_scsi_unlock_native_capacity);
 
 /**
  *     ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl
@@ -1215,7 +988,7 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc)
        scsi_set_sense_information(sb, SCSI_SENSE_BUFFERSIZE, block);
 }
 
-static void ata_scsi_sdev_config(struct scsi_device *sdev)
+void ata_scsi_sdev_config(struct scsi_device *sdev)
 {
        sdev->use_10_for_rw = 1;
        sdev->use_10_for_ms = 1;
@@ -1255,8 +1028,7 @@ static int atapi_drain_needed(struct request *rq)
        return atapi_cmd_type(scsi_req(rq)->cmd[0]) == ATAPI_MISC;
 }
 
-static int ata_scsi_dev_config(struct scsi_device *sdev,
-                              struct ata_device *dev)
+int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev)
 {
        struct request_queue *q = sdev->request_queue;
 
@@ -1344,6 +1116,7 @@ int ata_scsi_slave_config(struct scsi_device *sdev)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
 
 /**
  *     ata_scsi_slave_destroy - SCSI device is about to be destroyed
@@ -1383,71 +1156,7 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
        q->dma_drain_buffer = NULL;
        q->dma_drain_size = 0;
 }
-
-/**
- *     __ata_change_queue_depth - helper for ata_scsi_change_queue_depth
- *     @ap: ATA port to which the device change the queue depth
- *     @sdev: SCSI device to configure queue depth for
- *     @queue_depth: new queue depth
- *
- *     libsas and libata have different approaches for associating a sdev to
- *     its ata_port.
- *
- */
-int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
-                            int queue_depth)
-{
-       struct ata_device *dev;
-       unsigned long flags;
-
-       if (queue_depth < 1 || queue_depth == sdev->queue_depth)
-               return sdev->queue_depth;
-
-       dev = ata_scsi_find_dev(ap, sdev);
-       if (!dev || !ata_dev_enabled(dev))
-               return sdev->queue_depth;
-
-       /* NCQ enabled? */
-       spin_lock_irqsave(ap->lock, flags);
-       dev->flags &= ~ATA_DFLAG_NCQ_OFF;
-       if (queue_depth == 1 || !ata_ncq_enabled(dev)) {
-               dev->flags |= ATA_DFLAG_NCQ_OFF;
-               queue_depth = 1;
-       }
-       spin_unlock_irqrestore(ap->lock, flags);
-
-       /* limit and apply queue depth */
-       queue_depth = min(queue_depth, sdev->host->can_queue);
-       queue_depth = min(queue_depth, ata_id_queue_depth(dev->id));
-       queue_depth = min(queue_depth, ATA_MAX_QUEUE);
-
-       if (sdev->queue_depth == queue_depth)
-               return -EINVAL;
-
-       return scsi_change_queue_depth(sdev, queue_depth);
-}
-
-/**
- *     ata_scsi_change_queue_depth - SCSI callback for queue depth config
- *     @sdev: SCSI device to configure queue depth for
- *     @queue_depth: new queue depth
- *
- *     This is libata standard hostt->change_queue_depth callback.
- *     SCSI will call into this callback when user tries to set queue
- *     depth via sysfs.
- *
- *     LOCKING:
- *     SCSI layer (we don't care)
- *
- *     RETURNS:
- *     Newly configured queue depth.
- */
-int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
-{
-       struct ata_port *ap = ata_shost_to_port(sdev->host);
-
-       return __ata_change_queue_depth(ap, sdev, queue_depth);
-}
+EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
 
 /**
  *     ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
@@ -2354,10 +2063,6 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf)
  */
 static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
 {
-       struct ata_taskfile tf;
-
-       memset(&tf, 0, sizeof(tf));
-
        rbuf[1] = 0x89;                 /* our page code */
        rbuf[2] = (0x238 >> 8);         /* page size fixed at 238h */
        rbuf[3] = (0x238 & 0xff);
@@ -2366,14 +2071,14 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
        memcpy(&rbuf[16], "libata          ", 16);
        memcpy(&rbuf[32], DRV_VERSION, 4);
 
-       /* we don't store the ATA device signature, so we fake it */
-
-       tf.command = ATA_DRDY;          /* really, this is Status reg */
-       tf.lbal = 0x1;
-       tf.nsect = 0x1;
-
-       ata_tf_to_fis(&tf, 0, 1, &rbuf[36]);    /* TODO: PMP? */
        rbuf[36] = 0x34;                /* force D2H Reg FIS (34h) */
+       rbuf[37] = (1 << 7);            /* bit 7 indicates Command FIS */
+                                       /* TODO: PMP? */
+
+       /* we don't store the ATA device signature, so we fake it */
+       rbuf[38] = ATA_DRDY;            /* really, this is Status reg */
+       rbuf[40] = 0x1;
+       rbuf[48] = 0x1;
 
        rbuf[56] = ATA_CMD_ID_ATA;
 
@@ -3089,7 +2794,7 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
  *     RETURNS:
  *     Associated ATA device, or %NULL if not found.
  */
-static struct ata_device *
+struct ata_device *
 ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev)
 {
        struct ata_device *dev = __ata_scsi_find_dev(ap, scsidev);
@@ -4299,8 +4004,7 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
  *     Prints the contents of a SCSI command via printk().
  */
 
-static inline void ata_scsi_dump_cdb(struct ata_port *ap,
-                                    struct scsi_cmnd *cmd)
+void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd)
 {
 #ifdef ATA_VERBOSE_DEBUG
        struct scsi_device *scsidev = cmd->device;
@@ -4312,8 +4016,7 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
 #endif
 }
 
-static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
-                                     struct ata_device *dev)
+int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev)
 {
        u8 scsi_op = scmd->cmnd[0];
        ata_xlat_func_t xlat_func;
@@ -4407,6 +4110,7 @@ int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 
 /**
  *     ata_scsi_simulate - simulate SCSI command on ATA device
@@ -4562,26 +4266,51 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
                 */
                shost->max_host_blocked = 1;
 
-               rc = scsi_add_host_with_dma(ap->scsi_host,
-                                               &ap->tdev, ap->host->dev);
+               rc = scsi_add_host_with_dma(shost, &ap->tdev, ap->host->dev);
                if (rc)
-                       goto err_add;
+                       goto err_alloc;
        }
 
        return 0;
 
- err_add:
-       scsi_host_put(host->ports[i]->scsi_host);
  err_alloc:
        while (--i >= 0) {
                struct Scsi_Host *shost = host->ports[i]->scsi_host;
 
+               /* scsi_host_put() is in ata_devres_release() */
                scsi_remove_host(shost);
-               scsi_host_put(shost);
        }
        return rc;
 }
 
+#ifdef CONFIG_OF
+static void ata_scsi_assign_ofnode(struct ata_device *dev, struct ata_port *ap)
+{
+       struct scsi_device *sdev = dev->sdev;
+       struct device *d = ap->host->dev;
+       struct device_node *np = d->of_node;
+       struct device_node *child;
+
+       for_each_available_child_of_node(np, child) {
+               int ret;
+               u32 val;
+
+               ret = of_property_read_u32(child, "reg", &val);
+               if (ret)
+                       continue;
+               if (val == dev->devno) {
+                       dev_dbg(d, "found matching device node\n");
+                       sdev->sdev_gendev.of_node = child;
+                       return;
+               }
+       }
+}
+#else
+static void ata_scsi_assign_ofnode(struct ata_device *dev, struct ata_port *ap)
+{
+}
+#endif
+
 void ata_scsi_scan_host(struct ata_port *ap, int sync)
 {
        int tries = 5;
@@ -4607,6 +4336,7 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
                                                 NULL);
                        if (!IS_ERR(sdev)) {
                                dev->sdev = sdev;
+                               ata_scsi_assign_ofnode(dev, ap);
                                scsi_device_put(sdev);
                        } else {
                                dev->sdev = NULL;
@@ -4929,214 +4659,3 @@ void ata_scsi_dev_rescan(struct work_struct *work)
        spin_unlock_irqrestore(ap->lock, flags);
        mutex_unlock(&ap->scsi_scan_mutex);
 }
-
-/**
- *     ata_sas_port_alloc - Allocate port for a SAS attached SATA device
- *     @host: ATA host container for all SAS ports
- *     @port_info: Information from low-level host driver
- *     @shost: SCSI host that the scsi device is attached to
- *
- *     LOCKING:
- *     PCI/etc. bus probe sem.
- *
- *     RETURNS:
- *     ata_port pointer on success / NULL on failure.
- */
-
-struct ata_port *ata_sas_port_alloc(struct ata_host *host,
-                                   struct ata_port_info *port_info,
-                                   struct Scsi_Host *shost)
-{
-       struct ata_port *ap;
-
-       ap = ata_port_alloc(host);
-       if (!ap)
-               return NULL;
-
-       ap->port_no = 0;
-       ap->lock = &host->lock;
-       ap->pio_mask = port_info->pio_mask;
-       ap->mwdma_mask = port_info->mwdma_mask;
-       ap->udma_mask = port_info->udma_mask;
-       ap->flags |= port_info->flags;
-       ap->ops = port_info->port_ops;
-       ap->cbl = ATA_CBL_SATA;
-
-       return ap;
-}
-EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
-
-/**
- *     ata_sas_port_start - Set port up for dma.
- *     @ap: Port to initialize
- *
- *     Called just after data structures for each port are
- *     initialized.
- *
- *     May be used as the port_start() entry in ata_port_operations.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-int ata_sas_port_start(struct ata_port *ap)
-{
-       /*
-        * the port is marked as frozen at allocation time, but if we don't
-        * have new eh, we won't thaw it
-        */
-       if (!ap->ops->error_handler)
-               ap->pflags &= ~ATA_PFLAG_FROZEN;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ata_sas_port_start);
-
-/**
- *     ata_port_stop - Undo ata_sas_port_start()
- *     @ap: Port to shut down
- *
- *     May be used as the port_stop() entry in ata_port_operations.
- *
- *     LOCKING:
- *     Inherited from caller.
- */
-
-void ata_sas_port_stop(struct ata_port *ap)
-{
-}
-EXPORT_SYMBOL_GPL(ata_sas_port_stop);
-
-/**
- * ata_sas_async_probe - simply schedule probing and return
- * @ap: Port to probe
- *
- * For batch scheduling of probe for sas attached ata devices, assumes
- * the port has already been through ata_sas_port_init()
- */
-void ata_sas_async_probe(struct ata_port *ap)
-{
-       __ata_port_probe(ap);
-}
-EXPORT_SYMBOL_GPL(ata_sas_async_probe);
-
-int ata_sas_sync_probe(struct ata_port *ap)
-{
-       return ata_port_probe(ap);
-}
-EXPORT_SYMBOL_GPL(ata_sas_sync_probe);
-
-
-/**
- *     ata_sas_port_init - Initialize a SATA device
- *     @ap: SATA port to initialize
- *
- *     LOCKING:
- *     PCI/etc. bus probe sem.
- *
- *     RETURNS:
- *     Zero on success, non-zero on error.
- */
-
-int ata_sas_port_init(struct ata_port *ap)
-{
-       int rc = ap->ops->port_start(ap);
-
-       if (rc)
-               return rc;
-       ap->print_id = atomic_inc_return(&ata_print_id);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ata_sas_port_init);
-
-int ata_sas_tport_add(struct device *parent, struct ata_port *ap)
-{
-       return ata_tport_add(parent, ap);
-}
-EXPORT_SYMBOL_GPL(ata_sas_tport_add);
-
-void ata_sas_tport_delete(struct ata_port *ap)
-{
-       ata_tport_delete(ap);
-}
-EXPORT_SYMBOL_GPL(ata_sas_tport_delete);
-
-/**
- *     ata_sas_port_destroy - Destroy a SATA port allocated by ata_sas_port_alloc
- *     @ap: SATA port to destroy
- *
- */
-
-void ata_sas_port_destroy(struct ata_port *ap)
-{
-       if (ap->ops->port_stop)
-               ap->ops->port_stop(ap);
-       kfree(ap);
-}
-EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
-
-/**
- *     ata_sas_slave_configure - Default slave_config routine for libata devices
- *     @sdev: SCSI device to configure
- *     @ap: ATA port to which SCSI device is attached
- *
- *     RETURNS:
- *     Zero.
- */
-
-int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
-{
-       ata_scsi_sdev_config(sdev);
-       ata_scsi_dev_config(sdev, ap->link.device);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
-
-/**
- *     ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
- *     @cmd: SCSI command to be sent
- *     @ap:    ATA port to which the command is being sent
- *
- *     RETURNS:
- *     Return value from __ata_scsi_queuecmd() if @cmd can be queued,
- *     0 otherwise.
- */
-
-int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
-{
-       int rc = 0;
-
-       ata_scsi_dump_cdb(ap, cmd);
-
-       if (likely(ata_dev_enabled(ap->link.device)))
-               rc = __ata_scsi_queuecmd(cmd, ap->link.device);
-       else {
-               cmd->result = (DID_BAD_TARGET << 16);
-               cmd->scsi_done(cmd);
-       }
-       return rc;
-}
-EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
-
-int ata_sas_allocate_tag(struct ata_port *ap)
-{
-       unsigned int max_queue = ap->host->n_tags;
-       unsigned int i, tag;
-
-       for (i = 0, tag = ap->sas_last_tag + 1; i < max_queue; i++, tag++) {
-               tag = tag < max_queue ? tag : 0;
-
-               /* the last tag is reserved for internal command. */
-               if (ata_tag_internal(tag))
-                       continue;
-
-               if (!test_and_set_bit(tag, &ap->sas_tag_allocated)) {
-                       ap->sas_last_tag = tag;
-                       return tag;
-               }
-       }
-       return -1;
-}
-
-void ata_sas_free_tag(unsigned int tag, struct ata_port *ap)
-{
-       clear_bit(tag, &ap->sas_tag_allocated);
-}
index 038db94..ae7189d 100644 (file)
@@ -2,10 +2,6 @@
 /*
  *  libata-sff.c - helper library for PCI IDE BMDMA
  *
- *  Maintained by:  Tejun Heo <tj@kernel.org>
- *                 Please ALWAYS copy linux-ide@vger.kernel.org
- *                 on emails.
- *
  *  Copyright 2003-2006 Red Hat, Inc.  All rights reserved.
  *  Copyright 2003-2006 Jeff Garzik
  *
index 12a505b..6a40e3c 100644 (file)
@@ -208,7 +208,7 @@ show_ata_port_##name(struct device *dev,                            \
 {                                                                      \
        struct ata_port *ap = transport_class_to_port(dev);             \
                                                                        \
-       return snprintf(buf, 20, format_string, cast ap->field);        \
+       return scnprintf(buf, 20, format_string, cast ap->field);       \
 }
 
 #define ata_port_simple_attr(field, name, format_string, type)         \
@@ -479,7 +479,7 @@ show_ata_dev_##field(struct device *dev,                            \
 {                                                                      \
        struct ata_device *ata_dev = transport_class_to_dev(dev);       \
                                                                        \
-       return snprintf(buf, 20, format_string, cast ata_dev->field);   \
+       return scnprintf(buf, 20, format_string, cast ata_dev->field);  \
 }
 
 #define ata_dev_simple_attr(field, format_string, type)        \
@@ -533,7 +533,7 @@ show_ata_dev_id(struct device *dev,
        if (ata_dev->class == ATA_DEV_PMP)
                return 0;
        for(i=0;i<ATA_ID_WORDS;i++)  {
-               written += snprintf(buf+written, 20, "%04x%c",
+               written += scnprintf(buf+written, 20, "%04x%c",
                                    ata_dev->id[i],
                                    ((i+1) & 7) ? ' ' : '\n');
        }
@@ -552,7 +552,7 @@ show_ata_dev_gscr(struct device *dev,
        if (ata_dev->class != ATA_DEV_PMP)
                return 0;
        for(i=0;i<SATA_PMP_GSCR_DWORDS;i++)  {
-               written += snprintf(buf+written, 20, "%08x%c",
+               written += scnprintf(buf+written, 20, "%08x%c",
                                    ata_dev->gscr[i],
                                    ((i+1) & 3) ? ' ' : '\n');
        }
@@ -581,7 +581,7 @@ show_ata_dev_trim(struct device *dev,
        else
                mode = "unqueued";
 
-       return snprintf(buf, 20, "%s\n", mode);
+       return scnprintf(buf, 20, "%s\n", mode);
 }
 
 static DEVICE_ATTR(trim, S_IRUGO, show_ata_dev_trim, NULL);
index cd8090a..68cdd81 100644 (file)
@@ -37,7 +37,11 @@ extern int libata_noacpi;
 extern int libata_allow_tpm;
 extern const struct device_type ata_port_type;
 extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
+#ifdef CONFIG_ATA_FORCE
 extern void ata_force_cbl(struct ata_port *ap);
+#else
+static inline void ata_force_cbl(struct ata_port *ap) { }
+#endif
 extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
 extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
@@ -87,6 +91,18 @@ extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
 
 #define to_ata_port(d) container_of(d, struct ata_port, tdev)
 
+/* libata-sata.c */
+#ifdef CONFIG_SATA_HOST
+int ata_sas_allocate_tag(struct ata_port *ap);
+void ata_sas_free_tag(unsigned int tag, struct ata_port *ap);
+#else
+static inline int ata_sas_allocate_tag(struct ata_port *ap)
+{
+       return -EOPNOTSUPP;
+}
+static inline void ata_sas_free_tag(unsigned int tag, struct ata_port *ap) { }
+#endif
+
 /* libata-acpi.c */
 #ifdef CONFIG_ATA_ACPI
 extern unsigned int ata_acpi_gtf_filter;
@@ -112,6 +128,8 @@ static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
 #endif
 
 /* libata-scsi.c */
+extern struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
+                                           const struct scsi_device *scsidev);
 extern int ata_scsi_add_hosts(struct ata_host *host,
                              struct scsi_host_template *sht);
 extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
@@ -128,9 +146,10 @@ extern void ata_scsi_dev_rescan(struct work_struct *work);
 extern int ata_bus_probe(struct ata_port *ap);
 extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
                              unsigned int id, u64 lun);
-int ata_sas_allocate_tag(struct ata_port *ap);
-void ata_sas_free_tag(unsigned int tag, struct ata_port *ap);
-
+void ata_scsi_sdev_config(struct scsi_device *sdev);
+int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev);
+void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd);
+int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev);
 
 /* libata-eh.c */
 extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
index c451d7d..8729f78 100644 (file)
@@ -157,7 +157,6 @@ static int pdc_sata_hardreset(struct ata_link *link, unsigned int *class,
 static void pdc_error_handler(struct ata_port *ap);
 static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
 static int pdc_pata_cable_detect(struct ata_port *ap);
-static int pdc_sata_cable_detect(struct ata_port *ap);
 
 static struct scsi_host_template pdc_ata_sht = {
        ATA_BASE_SHT(DRV_NAME),
@@ -183,7 +182,7 @@ static const struct ata_port_operations pdc_common_ops = {
 
 static struct ata_port_operations pdc_sata_ops = {
        .inherits               = &pdc_common_ops,
-       .cable_detect           = pdc_sata_cable_detect,
+       .cable_detect           = ata_cable_sata,
        .freeze                 = pdc_sata_freeze,
        .thaw                   = pdc_sata_thaw,
        .scr_read               = pdc_sata_scr_read,
@@ -459,11 +458,6 @@ static int pdc_pata_cable_detect(struct ata_port *ap)
        return ATA_CBL_PATA80;
 }
 
-static int pdc_sata_cable_detect(struct ata_port *ap)
-{
-       return ATA_CBL_SATA;
-}
-
 static int pdc_sata_scr_read(struct ata_link *link,
                             unsigned int sc_reg, u32 *val)
 {
index 8db8c0f..7af74fb 100644 (file)
@@ -91,7 +91,7 @@
 #ifdef GENERAL_DEBUG
 #define PRINTK(args...) printk(args)
 #else
-#define PRINTK(args...)
+#define PRINTK(args...) do {} while (0)
 #endif /* GENERAL_DEBUG */
 
 #ifdef EXTRA_DEBUG
index b8313a0..48efa7a 100644 (file)
@@ -111,7 +111,7 @@ config CFAG12864B
          If unsure, say N.
 
 config CFAG12864B_RATE
-       int "Refresh rate (hertz)"
+       int "Refresh rate (hertz)"
        depends on CFAG12864B
        default "20"
        ---help---
@@ -329,7 +329,7 @@ config PANEL_LCD_PROTO
 
 config PANEL_LCD_PIN_E
        depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
-        int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) "
+       int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) "
        range -17 17
        default 14
        ---help---
@@ -344,7 +344,7 @@ config PANEL_LCD_PIN_E
 
 config PANEL_LCD_PIN_RS
        depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
-        int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) "
+       int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) "
        range -17 17
        default 17
        ---help---
@@ -359,7 +359,7 @@ config PANEL_LCD_PIN_RS
 
 config PANEL_LCD_PIN_RW
        depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
-        int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) "
+       int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) "
        range -17 17
        default 16
        ---help---
@@ -374,7 +374,7 @@ config PANEL_LCD_PIN_RW
 
 config PANEL_LCD_PIN_SCL
        depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0"
-        int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) "
+       int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) "
        range -17 17
        default 1
        ---help---
@@ -389,7 +389,7 @@ config PANEL_LCD_PIN_SCL
 
 config PANEL_LCD_PIN_SDA
        depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0"
-        int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) "
+       int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) "
        range -17 17
        default 2
        ---help---
@@ -404,12 +404,12 @@ config PANEL_LCD_PIN_SDA
 
 config PANEL_LCD_PIN_BL
        depends on PANEL_PROFILE="0" && PANEL_LCD="1"
-        int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) "
+       int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) "
        range -17 17
        default 0
        ---help---
          This describes the number of the parallel port pin to which the LCD 'BL' signal
-          has been connected. It can be :
+         has been connected. It can be :
 
                  0 : no connection (eg: connected to ground)
              1..17 : directly connected to any of these pins on the DB25 plug
index 874c259..c0da382 100644 (file)
@@ -88,7 +88,7 @@ struct charlcd_priv {
                int len;
        } esc_seq;
 
-       unsigned long long drvdata[0];
+       unsigned long long drvdata[];
 };
 
 #define charlcd_to_priv(p)     container_of(p, struct charlcd_priv, lcd)
index efb928e..1cce409 100644 (file)
@@ -356,7 +356,6 @@ static int img_ascii_lcd_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        const struct img_ascii_lcd_config *cfg;
        struct img_ascii_lcd_ctx *ctx;
-       struct resource *res;
        int err;
 
        match = of_match_device(img_ascii_lcd_matches, &pdev->dev);
@@ -378,8 +377,7 @@ static int img_ascii_lcd_probe(struct platform_device *pdev)
                                         &ctx->offset))
                        return -EINVAL;
        } else {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               ctx->base = devm_ioremap_resource(&pdev->dev, res);
+               ctx->base = devm_platform_ioremap_resource(pdev, 0);
                if (IS_ERR(ctx->base))
                        return PTR_ERR(ctx->base);
        }
index 6119e11..4d0a003 100644 (file)
 #include <linux/sched.h>
 #include <linux/smp.h>
 
+__weak bool arch_freq_counters_available(struct cpumask *cpus)
+{
+       return false;
+}
 DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
 
 void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
@@ -29,6 +33,14 @@ void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
        unsigned long scale;
        int i;
 
+       /*
+        * If the use of counters for FIE is enabled, just return as we don't
+        * want to update the scale factor with information from CPUFREQ.
+        * Instead the scale factor will be updated from arch_scale_freq_tick.
+        */
+       if (arch_freq_counters_available(cpus))
+               return;
+
        scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq;
 
        for_each_cpu(i, cpus)
@@ -94,7 +106,7 @@ static void update_topology_flags_workfn(struct work_struct *work)
        update_topology = 0;
 }
 
-static u32 capacity_scale;
+static DEFINE_PER_CPU(u32, freq_factor) = 1;
 static u32 *raw_capacity;
 
 static int free_raw_capacity(void)
@@ -108,17 +120,23 @@ static int free_raw_capacity(void)
 void topology_normalize_cpu_scale(void)
 {
        u64 capacity;
+       u64 capacity_scale;
        int cpu;
 
        if (!raw_capacity)
                return;
 
-       pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
+       capacity_scale = 1;
        for_each_possible_cpu(cpu) {
-               pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
-                        cpu, raw_capacity[cpu]);
-               capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
-                       / capacity_scale;
+               capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
+               capacity_scale = max(capacity, capacity_scale);
+       }
+
+       pr_debug("cpu_capacity: capacity_scale=%llu\n", capacity_scale);
+       for_each_possible_cpu(cpu) {
+               capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
+               capacity = div64_u64(capacity << SCHED_CAPACITY_SHIFT,
+                       capacity_scale);
                topology_set_cpu_scale(cpu, capacity);
                pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
                        cpu, topology_get_cpu_scale(cpu));
@@ -127,6 +145,7 @@ void topology_normalize_cpu_scale(void)
 
 bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
 {
+       struct clk *cpu_clk;
        static bool cap_parsing_failed;
        int ret;
        u32 cpu_capacity;
@@ -146,10 +165,22 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
                                return false;
                        }
                }
-               capacity_scale = max(cpu_capacity, capacity_scale);
                raw_capacity[cpu] = cpu_capacity;
                pr_debug("cpu_capacity: %pOF cpu_capacity=%u (raw)\n",
                        cpu_node, raw_capacity[cpu]);
+
+               /*
+                * Update freq_factor for calculating early boot cpu capacities.
+                * For non-clk CPU DVFS mechanism, there's no way to get the
+                * frequency value now, assuming they are running at the same
+                * frequency (by keeping the initial freq_factor value).
+                */
+               cpu_clk = of_clk_get(cpu_node, 0);
+               if (!PTR_ERR_OR_ZERO(cpu_clk)) {
+                       per_cpu(freq_factor, cpu) =
+                               clk_get_rate(cpu_clk) / 1000;
+                       clk_put(cpu_clk);
+               }
        } else {
                if (raw_capacity) {
                        pr_err("cpu_capacity: missing %pOF raw capacity\n",
@@ -188,11 +219,8 @@ init_cpu_capacity_callback(struct notifier_block *nb,
 
        cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus);
 
-       for_each_cpu(cpu, policy->related_cpus) {
-               raw_capacity[cpu] = topology_get_cpu_scale(cpu) *
-                                   policy->cpuinfo.max_freq / 1000UL;
-               capacity_scale = max(raw_capacity[cpu], capacity_scale);
-       }
+       for_each_cpu(cpu, policy->related_cpus)
+               per_cpu(freq_factor, cpu) = policy->cpuinfo.max_freq / 1000;
 
        if (cpumask_empty(cpus_to_visit)) {
                topology_normalize_cpu_scale();
@@ -281,7 +309,7 @@ static int __init get_cpu_for_node(struct device_node *node)
 static int __init parse_core(struct device_node *core, int package_id,
                             int core_id)
 {
-       char name[10];
+       char name[20];
        bool leaf = true;
        int i = 0;
        int cpu;
@@ -327,7 +355,7 @@ static int __init parse_core(struct device_node *core, int package_id,
 
 static int __init parse_cluster(struct device_node *cluster, int depth)
 {
-       char name[10];
+       char name[20];
        bool leaf = true;
        bool has_cores = false;
        struct device_node *c;
index c7879f5..e977041 100644 (file)
@@ -528,7 +528,8 @@ static void component_unbind(struct component *component,
 {
        WARN_ON(!component->bound);
 
-       component->ops->unbind(component->dev, master->dev, data);
+       if (component->ops && component->ops->unbind)
+               component->ops->unbind(component->dev, master->dev, data);
        component->bound = false;
 
        /* Release all resources claimed in the binding of this component */
index 42a6724..5e3cc16 100644 (file)
@@ -64,12 +64,12 @@ static inline void device_links_write_unlock(void)
        mutex_unlock(&device_links_lock);
 }
 
-int device_links_read_lock(void)
+int device_links_read_lock(void) __acquires(&device_links_srcu)
 {
        return srcu_read_lock(&device_links_srcu);
 }
 
-void device_links_read_unlock(int idx)
+void device_links_read_unlock(int idx) __releases(&device_links_srcu)
 {
        srcu_read_unlock(&device_links_srcu, idx);
 }
@@ -523,9 +523,13 @@ static void device_link_add_missing_supplier_links(void)
 
        mutex_lock(&wfs_lock);
        list_for_each_entry_safe(dev, tmp, &wait_for_suppliers,
-                                links.needs_suppliers)
-               if (!fwnode_call_int_op(dev->fwnode, add_links, dev))
+                                links.needs_suppliers) {
+               int ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
+               if (!ret)
                        list_del_init(&dev->links.needs_suppliers);
+               else if (ret != -ENODEV)
+                       dev->links.need_for_probe = false;
+       }
        mutex_unlock(&wfs_lock);
 }
 
@@ -718,6 +722,8 @@ static void __device_links_queue_sync_state(struct device *dev,
 {
        struct device_link *link;
 
+       if (!dev_has_sync_state(dev))
+               return;
        if (dev->state_synced)
                return;
 
@@ -745,25 +751,31 @@ static void __device_links_queue_sync_state(struct device *dev,
 /**
  * device_links_flush_sync_list - Call sync_state() on a list of devices
  * @list: List of devices to call sync_state() on
+ * @dont_lock_dev: Device for which lock is already held by the caller
  *
  * Calls sync_state() on all the devices that have been queued for it. This
- * function is used in conjunction with __device_links_queue_sync_state().
+ * function is used in conjunction with __device_links_queue_sync_state(). The
+ * @dont_lock_dev parameter is useful when this function is called from a
+ * context where a device lock is already held.
  */
-static void device_links_flush_sync_list(struct list_head *list)
+static void device_links_flush_sync_list(struct list_head *list,
+                                        struct device *dont_lock_dev)
 {
        struct device *dev, *tmp;
 
        list_for_each_entry_safe(dev, tmp, list, links.defer_sync) {
                list_del_init(&dev->links.defer_sync);
 
-               device_lock(dev);
+               if (dev != dont_lock_dev)
+                       device_lock(dev);
 
                if (dev->bus->sync_state)
                        dev->bus->sync_state(dev);
                else if (dev->driver && dev->driver->sync_state)
                        dev->driver->sync_state(dev);
 
-               device_unlock(dev);
+               if (dev != dont_lock_dev)
+                       device_unlock(dev);
 
                put_device(dev);
        }
@@ -801,7 +813,7 @@ void device_links_supplier_sync_state_resume(void)
 out:
        device_links_write_unlock();
 
-       device_links_flush_sync_list(&sync_list);
+       device_links_flush_sync_list(&sync_list, NULL);
 }
 
 static int sync_state_resume_initcall(void)
@@ -813,7 +825,7 @@ late_initcall(sync_state_resume_initcall);
 
 static void __device_links_supplier_defer_sync(struct device *sup)
 {
-       if (list_empty(&sup->links.defer_sync))
+       if (list_empty(&sup->links.defer_sync) && dev_has_sync_state(sup))
                list_add_tail(&sup->links.defer_sync, &deferred_sync);
 }
 
@@ -865,6 +877,11 @@ void device_links_driver_bound(struct device *dev)
                        driver_deferred_probe_add(link->consumer);
        }
 
+       if (defer_sync_state_count)
+               __device_links_supplier_defer_sync(dev);
+       else
+               __device_links_queue_sync_state(dev, &sync_list);
+
        list_for_each_entry(link, &dev->links.suppliers, c_node) {
                if (!(link->flags & DL_FLAG_MANAGED))
                        continue;
@@ -883,7 +900,7 @@ void device_links_driver_bound(struct device *dev)
 
        device_links_write_unlock();
 
-       device_links_flush_sync_list(&sync_list);
+       device_links_flush_sync_list(&sync_list, dev);
 }
 
 static void device_link_drop_managed(struct device_link *link)
@@ -2328,6 +2345,31 @@ static int device_private_init(struct device *dev)
        return 0;
 }
 
+static u32 fw_devlink_flags;
+static int __init fw_devlink_setup(char *arg)
+{
+       if (!arg)
+               return -EINVAL;
+
+       if (strcmp(arg, "off") == 0) {
+               fw_devlink_flags = 0;
+       } else if (strcmp(arg, "permissive") == 0) {
+               fw_devlink_flags = DL_FLAG_SYNC_STATE_ONLY;
+       } else if (strcmp(arg, "on") == 0) {
+               fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER;
+       } else if (strcmp(arg, "rpm") == 0) {
+               fw_devlink_flags = DL_FLAG_AUTOPROBE_CONSUMER |
+                                  DL_FLAG_PM_RUNTIME;
+       }
+       return 0;
+}
+early_param("fw_devlink", fw_devlink_setup);
+
+u32 fw_devlink_get_flags(void)
+{
+       return fw_devlink_flags;
+}
+
 /**
  * device_add - add device to device hierarchy.
  * @dev: device.
@@ -2362,6 +2404,7 @@ int device_add(struct device *dev)
        struct class_interface *class_intf;
        int error = -EINVAL, fw_ret;
        struct kobject *glue_dir = NULL;
+       bool is_fwnode_dev = false;
 
        dev = get_device(dev);
        if (!dev)
@@ -2459,8 +2502,10 @@ int device_add(struct device *dev)
 
        kobject_uevent(&dev->kobj, KOBJ_ADD);
 
-       if (dev->fwnode && !dev->fwnode->dev)
+       if (dev->fwnode && !dev->fwnode->dev) {
                dev->fwnode->dev = dev;
+               is_fwnode_dev = true;
+       }
 
        /*
         * Check if any of the other devices (consumers) have been waiting for
@@ -2476,7 +2521,8 @@ int device_add(struct device *dev)
         */
        device_link_add_missing_supplier_links();
 
-       if (fwnode_has_op(dev->fwnode, add_links)) {
+       if (fw_devlink_flags && is_fwnode_dev &&
+           fwnode_has_op(dev->fwnode, add_links)) {
                fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
                if (fw_ret == -ENODEV)
                        device_link_wait_for_mandatory_supplier(dev);
index 6265871..9a1c00f 100644 (file)
@@ -55,7 +55,7 @@ static int cpu_subsys_online(struct device *dev)
        if (from_nid == NUMA_NO_NODE)
                return -ENODEV;
 
-       ret = cpu_up(cpuid);
+       ret = cpu_device_up(dev);
        /*
         * When hot adding memory to memoryless node and enabling a cpu
         * on the node, node number of the cpu may internally change.
@@ -69,7 +69,7 @@ static int cpu_subsys_online(struct device *dev)
 
 static int cpu_subsys_offline(struct device *dev)
 {
-       return cpu_down(dev->id);
+       return cpu_device_down(dev);
 }
 
 void unregister_cpu(struct cpu *cpu)
@@ -231,8 +231,7 @@ static struct cpu_attr cpu_attrs[] = {
 static ssize_t print_cpus_kernel_max(struct device *dev,
                                     struct device_attribute *attr, char *buf)
 {
-       int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1);
-       return n;
+       return sprintf(buf, "%d\n", NR_CPUS - 1);
 }
 static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
 
@@ -258,13 +257,13 @@ static ssize_t print_cpus_offline(struct device *dev,
                        buf[n++] = ',';
 
                if (nr_cpu_ids == total_cpus-1)
-                       n += snprintf(&buf[n], len - n, "%u", nr_cpu_ids);
+                       n += scnprintf(&buf[n], len - n, "%u", nr_cpu_ids);
                else
-                       n += snprintf(&buf[n], len - n, "%u-%d",
+                       n += scnprintf(&buf[n], len - n, "%u-%d",
                                                      nr_cpu_ids, total_cpus-1);
        }
 
-       n += snprintf(&buf[n], len - n, "\n");
+       n += scnprintf(&buf[n], len - n, "\n");
        return n;
 }
 static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
@@ -272,7 +271,7 @@ static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
 static ssize_t print_cpus_isolated(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
-       int n = 0, len = PAGE_SIZE-2;
+       int n;
        cpumask_var_t isolated;
 
        if (!alloc_cpumask_var(&isolated, GFP_KERNEL))
@@ -280,7 +279,7 @@ static ssize_t print_cpus_isolated(struct device *dev,
 
        cpumask_andnot(isolated, cpu_possible_mask,
                       housekeeping_cpumask(HK_FLAG_DOMAIN));
-       n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(isolated));
+       n = sprintf(buf, "%*pbl\n", cpumask_pr_args(isolated));
 
        free_cpumask_var(isolated);
 
@@ -292,11 +291,7 @@ static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL);
 static ssize_t print_cpus_nohz_full(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
-       int n = 0, len = PAGE_SIZE-2;
-
-       n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
-
-       return n;
+       return sprintf(buf, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
 }
 static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
 #endif
index b25bcab..06ec0e8 100644 (file)
@@ -224,76 +224,52 @@ static int deferred_devs_show(struct seq_file *s, void *data)
 }
 DEFINE_SHOW_ATTRIBUTE(deferred_devs);
 
-static int deferred_probe_timeout = -1;
+#ifdef CONFIG_MODULES
+/*
+ * In the case of modules, set the default probe timeout to
+ * 30 seconds to give userland some time to load needed modules
+ */
+int driver_deferred_probe_timeout = 30;
+#else
+/* In the case of !modules, no probe timeout needed */
+int driver_deferred_probe_timeout = -1;
+#endif
+EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout);
+
 static int __init deferred_probe_timeout_setup(char *str)
 {
        int timeout;
 
        if (!kstrtoint(str, 10, &timeout))
-               deferred_probe_timeout = timeout;
+               driver_deferred_probe_timeout = timeout;
        return 1;
 }
 __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
  *
- * Returns -ENODEV if init is done and all built-in drivers have had a chance
- * to probe (i.e. initcalls are done), -ETIMEDOUT if deferred probe debug
- * timeout has expired, or -EPROBE_DEFER if none of those conditions are met.
+ * Return:
+ * -ENODEV if initcalls have completed and modules are disabled.
+ * -ETIMEDOUT if the deferred probe timeout was set and has expired
+ *  and modules are enabled.
+ * -EPROBE_DEFER in other cases.
  *
  * Drivers or subsystems can opt-in to calling this function instead of directly
  * returning -EPROBE_DEFER.
  */
 int driver_deferred_probe_check_state(struct device *dev)
 {
-       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;
+       if (!IS_ENABLED(CONFIG_MODULES) && initcalls_done) {
+               dev_warn(dev, "ignoring dependency for device, assuming no driver");
+               return -ENODEV;
+       }
 
-       ret = __driver_deferred_probe_check_state(dev);
-       if (ret < 0)
-               return ret;
+       if (!driver_deferred_probe_timeout) {
+               dev_WARN(dev, "deferred probe timeout, ignoring dependency");
+               return -ETIMEDOUT;
+       }
 
        return -EPROBE_DEFER;
 }
@@ -302,7 +278,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work)
 {
        struct device_private *private, *p;
 
-       deferred_probe_timeout = 0;
+       driver_deferred_probe_timeout = 0;
        driver_deferred_probe_trigger();
        flush_work(&deferred_probe_work);
 
@@ -336,9 +312,9 @@ static int deferred_probe_initcall(void)
        driver_deferred_probe_trigger();
        flush_work(&deferred_probe_work);
 
-       if (deferred_probe_timeout > 0) {
+       if (driver_deferred_probe_timeout > 0) {
                schedule_delayed_work(&deferred_probe_timeout_work,
-                       deferred_probe_timeout * HZ);
+                       driver_deferred_probe_timeout * HZ);
        }
        return 0;
 }
@@ -668,9 +644,10 @@ static int really_probe_debug(struct device *dev, struct device_driver *drv)
  */
 int driver_probe_done(void)
 {
-       pr_debug("%s: probe_count = %d\n", __func__,
-                atomic_read(&probe_count));
-       if (atomic_read(&probe_count))
+       int local_probe_count = atomic_read(&probe_count);
+
+       pr_debug("%s: probe_count = %d\n", __func__, local_probe_count);
+       if (local_probe_count)
                return -EBUSY;
        return 0;
 }
@@ -1222,7 +1199,7 @@ void driver_detach(struct device_driver *drv)
                        spin_unlock(&drv->p->klist_devices.k_lock);
                        break;
                }
-               dev_prv = list_entry(drv->p->klist_devices.k_list.prev,
+               dev_prv = list_last_entry(&drv->p->klist_devices.k_list,
                                     struct device_private,
                                     knode_driver.n_node);
                dev = dev_prv->device;
index 0b2dfa6..e878434 100644 (file)
@@ -5,5 +5,6 @@ obj-$(CONFIG_FW_LOADER_USER_HELPER) += fallback_table.o
 obj-$(CONFIG_FW_LOADER)        += firmware_class.o
 firmware_class-objs := main.o
 firmware_class-$(CONFIG_FW_LOADER_USER_HELPER) += fallback.o
+firmware_class-$(CONFIG_EFI_EMBEDDED_FIRMWARE) += fallback_platform.o
 
 obj-y += builtin/
index 8704e1b..1e9c96e 100644 (file)
@@ -525,7 +525,7 @@ static int fw_load_sysfs_fallback(struct fw_sysfs *fw_sysfs,
        }
 
        retval = fw_sysfs_wait_timeout(fw_priv, timeout);
-       if (retval < 0) {
+       if (retval < 0 && retval != -ENOENT) {
                mutex_lock(&fw_lock);
                fw_load_abort(fw_sysfs);
                mutex_unlock(&fw_lock);
index 2106350..06f4577 100644 (file)
@@ -66,4 +66,14 @@ static inline void unregister_sysfs_loader(void)
 }
 #endif /* CONFIG_FW_LOADER_USER_HELPER */
 
+#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
+int firmware_fallback_platform(struct fw_priv *fw_priv, enum fw_opt opt_flags);
+#else
+static inline int firmware_fallback_platform(struct fw_priv *fw_priv,
+                                            enum fw_opt opt_flags)
+{
+       return -ENOENT;
+}
+#endif
+
 #endif /* __FIRMWARE_FALLBACK_H */
diff --git a/drivers/base/firmware_loader/fallback_platform.c b/drivers/base/firmware_loader/fallback_platform.c
new file mode 100644 (file)
index 0000000..c88c745
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi_embedded_fw.h>
+#include <linux/property.h>
+#include <linux/security.h>
+#include <linux/vmalloc.h>
+
+#include "fallback.h"
+#include "firmware.h"
+
+int firmware_fallback_platform(struct fw_priv *fw_priv, enum fw_opt opt_flags)
+{
+       const u8 *data;
+       size_t size;
+       int rc;
+
+       if (!(opt_flags & FW_OPT_FALLBACK_PLATFORM))
+               return -ENOENT;
+
+       rc = security_kernel_load_data(LOADING_FIRMWARE_EFI_EMBEDDED);
+       if (rc)
+               return rc;
+
+       rc = efi_get_embedded_fw(fw_priv->fw_name, &data, &size);
+       if (rc)
+               return rc; /* rc == -ENOENT when the fw was not found */
+
+       fw_priv->data = vmalloc(size);
+       if (!fw_priv->data)
+               return -ENOMEM;
+
+       memcpy(fw_priv->data, data, size);
+       fw_priv->size = size;
+       fw_state_done(fw_priv);
+       return 0;
+}
index 8656e52..25836a6 100644 (file)
@@ -29,6 +29,9 @@
  *     firmware caching mechanism.
  * @FW_OPT_NOFALLBACK_SYSFS: Disable the sysfs fallback mechanism. Takes
  *     precedence over &FW_OPT_UEVENT and &FW_OPT_USERHELPER.
+ * @FW_OPT_FALLBACK_PLATFORM: Enable fallback to device fw copy embedded in
+ *     the platform's main firmware. If both this fallback and the sysfs
+ *      fallback are enabled, then this fallback will be tried first.
  */
 enum fw_opt {
        FW_OPT_UEVENT                   = BIT(0),
@@ -37,6 +40,7 @@ enum fw_opt {
        FW_OPT_NO_WARN                  = BIT(3),
        FW_OPT_NOCACHE                  = BIT(4),
        FW_OPT_NOFALLBACK_SYSFS         = BIT(5),
+       FW_OPT_FALLBACK_PLATFORM        = BIT(6),
 };
 
 enum fw_status {
index 57133a9..76f7991 100644 (file)
@@ -493,8 +493,10 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
                }
 
                fw_priv->size = 0;
-               rc = kernel_read_file_from_path(path, &buffer, &size,
-                                               msize, id);
+
+               /* load firmware files from the mount namespace of init */
+               rc = kernel_read_file_from_path_initns(path, &buffer,
+                                                      &size, msize, id);
                if (rc) {
                        if (rc != -ENOENT)
                                dev_warn(device, "loading %s failed with error %d\n",
@@ -776,6 +778,9 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
                                                 fw_decompress_xz);
 #endif
 
+       if (ret == -ENOENT)
+               ret = firmware_fallback_platform(fw->priv, opt_flags);
+
        if (ret) {
                if (!(opt_flags & FW_OPT_NO_WARN))
                        dev_warn(device,
@@ -884,6 +889,30 @@ int request_firmware_direct(const struct firmware **firmware_p,
 EXPORT_SYMBOL_GPL(request_firmware_direct);
 
 /**
+ * firmware_request_platform() - request firmware with platform-fw fallback
+ * @firmware: pointer to firmware image
+ * @name: name of firmware file
+ * @device: device for which firmware is being loaded
+ *
+ * This function is similar in behaviour to request_firmware, except that if
+ * direct filesystem lookup fails, it will fallback to looking for a copy of the
+ * requested firmware embedded in the platform's main (e.g. UEFI) firmware.
+ **/
+int firmware_request_platform(const struct firmware **firmware,
+                             const char *name, struct device *device)
+{
+       int ret;
+
+       /* Need to pin this module until return */
+       __module_get(THIS_MODULE);
+       ret = _request_firmware(firmware, name, device, NULL, 0,
+                               FW_OPT_UEVENT | FW_OPT_FALLBACK_PLATFORM);
+       module_put(THIS_MODULE);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(firmware_request_platform);
+
+/**
  * firmware_request_cache() - cache firmware for suspend so resume can use it
  * @name: name of firmware file
  * @device: device for which firmware should be cached for
index b9f474c..4086718 100644 (file)
@@ -97,30 +97,13 @@ static ssize_t phys_index_show(struct device *dev,
 }
 
 /*
- * Show whether the memory block is likely to be offlineable (or is already
- * offline). Once offline, the memory block could be removed. The return
- * value does, however, not indicate that there is a way to remove the
- * memory block.
+ * Legacy interface that we cannot remove. Always indicate "removable"
+ * with CONFIG_MEMORY_HOTREMOVE - bad heuristic.
  */
 static ssize_t removable_show(struct device *dev, struct device_attribute *attr,
                              char *buf)
 {
-       struct memory_block *mem = to_memory_block(dev);
-       unsigned long pfn;
-       int ret = 1, i;
-
-       if (mem->state != MEM_ONLINE)
-               goto out;
-
-       for (i = 0; i < sections_per_block; i++) {
-               if (!present_section_nr(mem->start_section_nr + i))
-                       continue;
-               pfn = section_nr_to_pfn(mem->start_section_nr + i);
-               ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
-       }
-
-out:
-       return sprintf(buf, "%d\n", ret);
+       return sprintf(buf, "%d\n", (int)IS_ENABLED(CONFIG_MEMORY_HOTREMOVE));
 }
 
 /*
index 7fa654f..5255550 100644 (file)
@@ -63,6 +63,28 @@ EXPORT_SYMBOL_GPL(platform_get_resource);
 
 #ifdef CONFIG_HAS_IOMEM
 /**
+ * devm_platform_get_and_ioremap_resource - call devm_ioremap_resource() for a
+ *                                         platform device and get resource
+ *
+ * @pdev: platform device to use both for memory resource lookup as well as
+ *        resource management
+ * @index: resource index
+ * @res: optional output parameter to store a pointer to the obtained resource.
+ */
+void __iomem *
+devm_platform_get_and_ioremap_resource(struct platform_device *pdev,
+                               unsigned int index, struct resource **res)
+{
+       struct resource *r;
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, index);
+       if (res)
+               *res = r;
+       return devm_ioremap_resource(&pdev->dev, r);
+}
+EXPORT_SYMBOL_GPL(devm_platform_get_and_ioremap_resource);
+
+/**
  * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform
  *                                 device
  *
@@ -73,10 +95,7 @@ EXPORT_SYMBOL_GPL(platform_get_resource);
 void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
                                             unsigned int index)
 {
-       struct resource *res;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, index);
-       return devm_ioremap_resource(&pdev->dev, res);
+       return devm_platform_get_and_ioremap_resource(pdev, index, NULL);
 }
 EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
 
@@ -363,10 +382,10 @@ static void setup_pdev_dma_masks(struct platform_device *pdev)
 {
        if (!pdev->dev.coherent_dma_mask)
                pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-       if (!pdev->dma_mask)
-               pdev->dma_mask = DMA_BIT_MASK(32);
-       if (!pdev->dev.dma_mask)
-               pdev->dev.dma_mask = &pdev->dma_mask;
+       if (!pdev->dev.dma_mask) {
+               pdev->platform_dma_mask = DMA_BIT_MASK(32);
+               pdev->dev.dma_mask = &pdev->platform_dma_mask;
+       }
 };
 
 /**
@@ -662,20 +681,8 @@ struct platform_device *platform_device_register_full(
        pdev->dev.of_node_reused = pdevinfo->of_node_reused;
 
        if (pdevinfo->dma_mask) {
-               /*
-                * This memory isn't freed when the device is put,
-                * I don't have a nice idea for that though.  Conceptually
-                * dma_mask in struct device should not be a pointer.
-                * See http://thread.gmane.org/gmane.linux.kernel.pci/9081
-                */
-               pdev->dev.dma_mask =
-                       kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
-               if (!pdev->dev.dma_mask)
-                       goto err;
-
-               kmemleak_ignore(pdev->dev.dma_mask);
-
-               *pdev->dev.dma_mask = pdevinfo->dma_mask;
+               pdev->platform_dma_mask = pdevinfo->dma_mask;
+               pdev->dev.dma_mask = &pdev->platform_dma_mask;
                pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
        }
 
@@ -700,7 +707,6 @@ struct platform_device *platform_device_register_full(
        if (ret) {
 err:
                ACPI_COMPANION_SET(&pdev->dev, NULL);
-               kfree(pdev->dev.dma_mask);
                platform_device_put(pdev);
                return ERR_PTR(ret);
        }
index 959d6d5..0a01df6 100644 (file)
@@ -2653,7 +2653,7 @@ static int genpd_iterate_idle_states(struct device_node *dn,
 
        ret = of_count_phandle_with_args(dn, "domain-idle-states", NULL);
        if (ret <= 0)
-               return ret;
+               return ret == -ENOENT ? 0 : ret;
 
        /* Loop over the phandles until all the requested entry is found */
        of_for_each_phandle(&it, ret, dn, "domain-idle-states", NULL, 0) {
index 0e99a76..6d1dee7 100644 (file)
 
 typedef int (*pm_callback_t)(struct device *);
 
+#define list_for_each_entry_rcu_locked(pos, head, member) \
+       list_for_each_entry_rcu(pos, head, member, \
+                       device_links_read_lock_held())
+
 /*
  * The entries in the dpm_list list are in a depth first order, simply
  * because children are guaranteed to be discovered after parents, and
@@ -266,7 +270,7 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async)
         * callbacks freeing the link objects for the links in the list we're
         * walking.
         */
-       list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
+       list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node)
                if (READ_ONCE(link->status) != DL_STATE_DORMANT)
                        dpm_wait(link->supplier, async);
 
@@ -323,7 +327,7 @@ static void dpm_wait_for_consumers(struct device *dev, bool async)
         * continue instead of trying to continue in parallel with its
         * unregistration).
         */
-       list_for_each_entry_rcu(link, &dev->links.consumers, s_node)
+       list_for_each_entry_rcu_locked(link, &dev->links.consumers, s_node)
                if (READ_ONCE(link->status) != DL_STATE_DORMANT)
                        dpm_wait(link->consumer, async);
 
@@ -1235,7 +1239,7 @@ static void dpm_superior_set_must_resume(struct device *dev)
 
        idx = device_links_read_lock();
 
-       list_for_each_entry_rcu(link, &dev->links.suppliers, c_node)
+       list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node)
                link->supplier->power.must_resume = true;
 
        device_links_read_unlock(idx);
@@ -1695,7 +1699,7 @@ static void dpm_clear_superiors_direct_complete(struct device *dev)
 
        idx = device_links_read_lock();
 
-       list_for_each_entry_rcu(link, &dev->links.suppliers, c_node) {
+       list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
                spin_lock_irq(&link->supplier->power.lock);
                link->supplier->power.direct_complete = false;
                spin_unlock_irq(&link->supplier->power.lock);
index 16134a6..99c7da1 100644 (file)
@@ -1087,29 +1087,47 @@ int __pm_runtime_resume(struct device *dev, int rpmflags)
 EXPORT_SYMBOL_GPL(__pm_runtime_resume);
 
 /**
- * pm_runtime_get_if_in_use - Conditionally bump up the device's usage counter.
+ * pm_runtime_get_if_active - Conditionally bump up the device's usage counter.
  * @dev: Device to handle.
  *
  * Return -EINVAL if runtime PM is disabled for the device.
  *
- * If that's not the case and if the device's runtime PM status is RPM_ACTIVE
- * and the runtime PM usage counter is nonzero, increment the counter and
- * return 1.  Otherwise return 0 without changing the counter.
+ * Otherwise, if the device's runtime PM status is RPM_ACTIVE and either
+ * ign_usage_count is true or the device's usage_count is non-zero, increment
+ * the counter and return 1. Otherwise return 0 without changing the counter.
+ *
+ * If ign_usage_count is true, the function can be used to prevent suspending
+ * the device when its runtime PM status is RPM_ACTIVE.
+ *
+ * If ign_usage_count is false, the function can be used to prevent suspending
+ * the device when both its runtime PM status is RPM_ACTIVE and its usage_count
+ * is non-zero.
+ *
+ * The caller is resposible for putting the device's usage count when ther
+ * return value is greater than zero.
  */
-int pm_runtime_get_if_in_use(struct device *dev)
+int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count)
 {
        unsigned long flags;
        int retval;
 
        spin_lock_irqsave(&dev->power.lock, flags);
-       retval = dev->power.disable_depth > 0 ? -EINVAL :
-               dev->power.runtime_status == RPM_ACTIVE
-                       && atomic_inc_not_zero(&dev->power.usage_count);
+       if (dev->power.disable_depth > 0) {
+               retval = -EINVAL;
+       } else if (dev->power.runtime_status != RPM_ACTIVE) {
+               retval = 0;
+       } else if (ign_usage_count) {
+               retval = 1;
+               atomic_inc(&dev->power.usage_count);
+       } else {
+               retval = atomic_inc_not_zero(&dev->power.usage_count);
+       }
        trace_rpm_usage_rcuidle(dev, 0);
        spin_unlock_irqrestore(&dev->power.lock, flags);
+
        return retval;
 }
-EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use);
+EXPORT_SYMBOL_GPL(pm_runtime_get_if_active);
 
 /**
  * __pm_runtime_set_status - Set runtime PM status of a device.
index 27f3e60..92073ac 100644 (file)
@@ -24,6 +24,9 @@ suspend_state_t pm_suspend_target_state;
 #define pm_suspend_target_state        (PM_SUSPEND_ON)
 #endif
 
+#define list_for_each_entry_rcu_locked(pos, head, member) \
+       list_for_each_entry_rcu(pos, head, member, \
+               srcu_read_lock_held(&wakeup_srcu))
 /*
  * If set, the suspend/hibernate code will abort transitions to a sleep state
  * if wakeup events are registered during or immediately before the transition.
@@ -241,7 +244,9 @@ void wakeup_source_unregister(struct wakeup_source *ws)
 {
        if (ws) {
                wakeup_source_remove(ws);
-               wakeup_source_sysfs_remove(ws);
+               if (ws->dev)
+                       wakeup_source_sysfs_remove(ws);
+
                wakeup_source_destroy(ws);
        }
 }
@@ -405,7 +410,7 @@ void device_wakeup_arm_wake_irqs(void)
        int srcuidx;
 
        srcuidx = srcu_read_lock(&wakeup_srcu);
-       list_for_each_entry_rcu(ws, &wakeup_sources, entry)
+       list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry)
                dev_pm_arm_wake_irq(ws->wakeirq);
        srcu_read_unlock(&wakeup_srcu, srcuidx);
 }
@@ -421,7 +426,7 @@ void device_wakeup_disarm_wake_irqs(void)
        int srcuidx;
 
        srcuidx = srcu_read_lock(&wakeup_srcu);
-       list_for_each_entry_rcu(ws, &wakeup_sources, entry)
+       list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry)
                dev_pm_disarm_wake_irq(ws->wakeirq);
        srcu_read_unlock(&wakeup_srcu, srcuidx);
 }
@@ -874,7 +879,7 @@ void pm_print_active_wakeup_sources(void)
        struct wakeup_source *last_activity_ws = NULL;
 
        srcuidx = srcu_read_lock(&wakeup_srcu);
-       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+       list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry) {
                if (ws->active) {
                        pm_pr_dbg("active wakeup source: %s\n", ws->name);
                        active = 1;
@@ -1025,7 +1030,7 @@ void pm_wakep_autosleep_enabled(bool set)
        int srcuidx;
 
        srcuidx = srcu_read_lock(&wakeup_srcu);
-       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+       list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry) {
                spin_lock_irq(&ws->lock);
                if (ws->autosleep_enabled != set) {
                        ws->autosleep_enabled = set;
@@ -1104,7 +1109,7 @@ static void *wakeup_sources_stats_seq_start(struct seq_file *m,
        }
 
        *srcuidx = srcu_read_lock(&wakeup_srcu);
-       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+       list_for_each_entry_rcu_locked(ws, &wakeup_sources, entry) {
                if (n-- <= 0)
                        return ws;
        }
index 511f6d7..5f35c0c 100644 (file)
@@ -566,6 +566,7 @@ const char *fwnode_get_name(const struct fwnode_handle *fwnode)
 {
        return fwnode_call_ptr_op(fwnode, get_name);
 }
+EXPORT_SYMBOL_GPL(fwnode_get_name);
 
 /**
  * fwnode_get_name_prefix - Return the prefix of node for printing purposes
index 0b081de..de8d354 100644 (file)
@@ -608,6 +608,13 @@ static void software_node_release(struct kobject *kobj)
 {
        struct swnode *swnode = kobj_to_swnode(kobj);
 
+       if (swnode->parent) {
+               ida_simple_remove(&swnode->parent->child_ids, swnode->id);
+               list_del(&swnode->entry);
+       } else {
+               ida_simple_remove(&swnode_root_ids, swnode->id);
+       }
+
        if (swnode->allocated) {
                property_entries_free(swnode->node->properties);
                kfree(swnode->node);
@@ -773,13 +780,6 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode)
        if (!swnode)
                return;
 
-       if (swnode->parent) {
-               ida_simple_remove(&swnode->parent->child_ids, swnode->id);
-               list_del(&swnode->entry);
-       } else {
-               ida_simple_remove(&swnode_root_ids, swnode->id);
-       }
-
        kobject_put(&swnode->kobj);
 }
 EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
index a53cc1e..795facd 100644 (file)
@@ -6,6 +6,9 @@
 # Rewritten to use lists instead of if-statements.
 # 
 
+# needed for trace events
+ccflags-y                              += -I$(src)
+
 obj-$(CONFIG_MAC_FLOPPY)       += swim3.o
 obj-$(CONFIG_BLK_DEV_SWIM)     += swim_mod.o
 obj-$(CONFIG_BLK_DEV_FD)       += floppy.o
@@ -39,6 +42,9 @@ obj-$(CONFIG_ZRAM) += zram/
 
 obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_blk.o
 null_blk-objs  := null_blk_main.o
+ifeq ($(CONFIG_BLK_DEV_ZONED), y)
+null_blk-$(CONFIG_TRACING) += null_blk_trace.o
+endif
 null_blk-$(CONFIG_BLK_DEV_ZONED) += null_blk_zoned.o
 
 skd-y          := skd_main.o
index 7b32fb6..a27804d 100644 (file)
@@ -87,9 +87,9 @@ static ssize_t aoedisk_show_netif(struct device *dev,
        if (*nd == NULL)
                return snprintf(page, PAGE_SIZE, "none\n");
        for (p = page; nd < ne; nd++)
-               p += snprintf(p, PAGE_SIZE - (p-page), "%s%s",
+               p += scnprintf(p, PAGE_SIZE - (p-page), "%s%s",
                        p == page ? "" : ",", (*nd)->name);
-       p += snprintf(p, PAGE_SIZE - (p-page), "\n");
+       p += scnprintf(p, PAGE_SIZE - (p-page), "\n");
        return p-page;
 }
 /* firmware version */
index 220c5e1..2fb25c3 100644 (file)
@@ -381,12 +381,10 @@ static struct brd_device *brd_alloc(int i)
        spin_lock_init(&brd->brd_lock);
        INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
 
-       brd->brd_queue = blk_alloc_queue(GFP_KERNEL);
+       brd->brd_queue = blk_alloc_queue(brd_make_request, NUMA_NO_NODE);
        if (!brd->brd_queue)
                goto out_free_dev;
 
-       blk_queue_make_request(brd->brd_queue, brd_make_request);
-
        /* This is so fdisk will align partitions on 4k, because of
         * direct_access API needing 4k alignment, returning a PFN
         * (This is only a problem on very small devices <= 4M,
index a18155c..c094c3c 100644 (file)
@@ -2801,7 +2801,7 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
 
        drbd_init_set_defaults(device);
 
-       q = blk_alloc_queue_node(GFP_KERNEL, NUMA_NO_NODE);
+       q = blk_alloc_queue(drbd_make_request, NUMA_NO_NODE);
        if (!q)
                goto out_no_q;
        device->rq_queue = q;
@@ -2828,7 +2828,6 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig
        q->backing_dev_info->congested_fn = drbd_congested;
        q->backing_dev_info->congested_data = device;
 
-       blk_queue_make_request(q, drbd_make_request);
        blk_queue_write_cache(q, true, true);
        /* Setting the max_hw_sectors to an odd value of 8kibyte here
           This triggers a max_bio_size message upon first attach or connect */
@@ -3414,22 +3413,11 @@ int drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev)
  * the meta-data super block. This function sets MD_DIRTY, and starts a
  * timer that ensures that within five seconds you have to call drbd_md_sync().
  */
-#ifdef DEBUG
-void drbd_md_mark_dirty_(struct drbd_device *device, unsigned int line, const char *func)
-{
-       if (!test_and_set_bit(MD_DIRTY, &device->flags)) {
-               mod_timer(&device->md_sync_timer, jiffies + HZ);
-               device->last_md_mark_dirty.line = line;
-               device->last_md_mark_dirty.func = func;
-       }
-}
-#else
 void drbd_md_mark_dirty(struct drbd_device *device)
 {
        if (!test_and_set_bit(MD_DIRTY, &device->flags))
                mod_timer(&device->md_sync_timer, jiffies + 5*HZ);
 }
-#endif
 
 void drbd_uuid_move_history(struct drbd_device *device) __must_hold(local)
 {
index 79e2164..c15e708 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/random.h>
 #include <linux/string.h>
 #include <linux/scatterlist.h>
+#include <linux/part_stat.h>
 #include "drbd_int.h"
 #include "drbd_protocol.h"
 #include "drbd_req.h"
index b7f605c..0dc019d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/random.h>
 #include <linux/string.h>
 #include <linux/scatterlist.h>
+#include <linux/part_stat.h>
 
 #include "drbd_int.h"
 #include "drbd_protocol.h"
index cd3612e..c3daa64 100644 (file)
@@ -171,7 +171,6 @@ static int print_unex = 1;
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/workqueue.h>
-#define FDPATCHES
 #include <linux/fdreg.h>
 #include <linux/fd.h>
 #include <linux/hdreg.h>
@@ -306,36 +305,26 @@ static bool initialized;
        /* reverse mapping from unit and fdc to drive */
 #define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))
 
-#define DP     (&drive_params[current_drive])
-#define DRS    (&drive_state[current_drive])
-#define DRWE   (&write_errors[current_drive])
-#define FDCS   (&fdc_state[fdc])
-
-#define UDP    (&drive_params[drive])
-#define UDRS   (&drive_state[drive])
-#define UDRWE  (&write_errors[drive])
-#define UFDCS  (&fdc_state[FDC(drive)])
-
 #define PH_HEAD(floppy, head) (((((floppy)->stretch & 2) >> 1) ^ head) << 2)
 #define STRETCH(floppy)        ((floppy)->stretch & FD_STRETCH)
 
-/* read/write */
-#define COMMAND                (raw_cmd->cmd[0])
-#define DR_SELECT      (raw_cmd->cmd[1])
-#define TRACK          (raw_cmd->cmd[2])
-#define HEAD           (raw_cmd->cmd[3])
-#define SECTOR         (raw_cmd->cmd[4])
-#define SIZECODE       (raw_cmd->cmd[5])
-#define SECT_PER_TRACK (raw_cmd->cmd[6])
-#define GAP            (raw_cmd->cmd[7])
-#define SIZECODE2      (raw_cmd->cmd[8])
+/* read/write commands */
+#define COMMAND                        0
+#define DR_SELECT              1
+#define TRACK                  2
+#define HEAD                   3
+#define SECTOR                 4
+#define SIZECODE               5
+#define SECT_PER_TRACK         6
+#define GAP                    7
+#define SIZECODE2              8
 #define NR_RW 9
 
-/* format */
-#define F_SIZECODE     (raw_cmd->cmd[2])
-#define F_SECT_PER_TRACK (raw_cmd->cmd[3])
-#define F_GAP          (raw_cmd->cmd[4])
-#define F_FILL         (raw_cmd->cmd[5])
+/* format commands */
+#define F_SIZECODE             2
+#define F_SECT_PER_TRACK       3
+#define F_GAP                  4
+#define F_FILL                 5
 #define NR_F 6
 
 /*
@@ -351,14 +340,14 @@ static bool initialized;
 #define MAX_REPLIES 16
 static unsigned char reply_buffer[MAX_REPLIES];
 static int inr;                /* size of reply buffer, when called from interrupt */
-#define ST0            (reply_buffer[0])
-#define ST1            (reply_buffer[1])
-#define ST2            (reply_buffer[2])
-#define ST3            (reply_buffer[0])       /* result of GETSTATUS */
-#define R_TRACK                (reply_buffer[3])
-#define R_HEAD         (reply_buffer[4])
-#define R_SECTOR       (reply_buffer[5])
-#define R_SIZECODE     (reply_buffer[6])
+#define ST0            0
+#define ST1            1
+#define ST2            2
+#define ST3            0       /* result of GETSTATUS */
+#define R_TRACK                3
+#define R_HEAD         4
+#define R_SECTOR       5
+#define R_SIZECODE     6
 
 #define SEL_DLY                (2 * HZ / 100)
 
@@ -593,7 +582,7 @@ static int buffer_max = -1;
 
 /* fdc related variables, should end up in a struct */
 static struct floppy_fdc_state fdc_state[N_FDC];
-static int fdc;                        /* current fdc */
+static int current_fdc;                        /* current fdc */
 
 static struct workqueue_struct *floppy_wq;
 
@@ -604,9 +593,19 @@ static unsigned char fsector_t;    /* sector in track */
 static unsigned char in_sector_offset; /* offset within physical sector,
                                         * expressed in units of 512 bytes */
 
+static inline unsigned char fdc_inb(int fdc, int reg)
+{
+       return fd_inb(fdc_state[fdc].address + reg);
+}
+
+static inline void fdc_outb(unsigned char value, int fdc, int reg)
+{
+       fd_outb(value, fdc_state[fdc].address + reg);
+}
+
 static inline bool drive_no_geom(int drive)
 {
-       return !current_type[drive] && !ITYPE(UDRS->fd_device);
+       return !current_type[drive] && !ITYPE(drive_state[drive].fd_device);
 }
 
 #ifndef fd_eject
@@ -630,7 +629,7 @@ static inline void set_debugt(void)
 
 static inline void debugt(const char *func, const char *msg)
 {
-       if (DP->flags & DEBUGT)
+       if (drive_params[current_drive].flags & DEBUGT)
                pr_info("%s:%s dtime=%lu\n", func, msg, jiffies - debugtimer);
 }
 #else
@@ -683,10 +682,10 @@ static void __reschedule_timeout(int drive, const char *message)
                delay = 20UL * HZ;
                drive = 0;
        } else
-               delay = UDP->timeout;
+               delay = drive_params[drive].timeout;
 
        mod_delayed_work(floppy_wq, &fd_timeout, delay);
-       if (UDP->flags & FD_DEBUG)
+       if (drive_params[drive].flags & FD_DEBUG)
                DPRINT("reschedule timeout %s\n", message);
        timeout_message = message;
 }
@@ -740,33 +739,37 @@ static int disk_change(int drive)
 {
        int fdc = FDC(drive);
 
-       if (time_before(jiffies, UDRS->select_date + UDP->select_delay))
+       if (time_before(jiffies, drive_state[drive].select_date + drive_params[drive].select_delay))
                DPRINT("WARNING disk change called early\n");
-       if (!(FDCS->dor & (0x10 << UNIT(drive))) ||
-           (FDCS->dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
+       if (!(fdc_state[fdc].dor & (0x10 << UNIT(drive))) ||
+           (fdc_state[fdc].dor & 3) != UNIT(drive) || fdc != FDC(drive)) {
                DPRINT("probing disk change on unselected drive\n");
                DPRINT("drive=%d fdc=%d dor=%x\n", drive, FDC(drive),
-                      (unsigned int)FDCS->dor);
+                      (unsigned int)fdc_state[fdc].dor);
        }
 
-       debug_dcl(UDP->flags,
+       debug_dcl(drive_params[drive].flags,
                  "checking disk change line for drive %d\n", drive);
-       debug_dcl(UDP->flags, "jiffies=%lu\n", jiffies);
-       debug_dcl(UDP->flags, "disk change line=%x\n", fd_inb(FD_DIR) & 0x80);
-       debug_dcl(UDP->flags, "flags=%lx\n", UDRS->flags);
-
-       if (UDP->flags & FD_BROKEN_DCL)
-               return test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
-       if ((fd_inb(FD_DIR) ^ UDP->flags) & 0x80) {
-               set_bit(FD_VERIFY_BIT, &UDRS->flags);
+       debug_dcl(drive_params[drive].flags, "jiffies=%lu\n", jiffies);
+       debug_dcl(drive_params[drive].flags, "disk change line=%x\n",
+                 fdc_inb(fdc, FD_DIR) & 0x80);
+       debug_dcl(drive_params[drive].flags, "flags=%lx\n",
+                 drive_state[drive].flags);
+
+       if (drive_params[drive].flags & FD_BROKEN_DCL)
+               return test_bit(FD_DISK_CHANGED_BIT,
+                               &drive_state[drive].flags);
+       if ((fdc_inb(fdc, FD_DIR) ^ drive_params[drive].flags) & 0x80) {
+               set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
                                        /* verify write protection */
 
-               if (UDRS->maxblock)     /* mark it changed */
-                       set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
+               if (drive_state[drive].maxblock)        /* mark it changed */
+                       set_bit(FD_DISK_CHANGED_BIT,
+                               &drive_state[drive].flags);
 
                /* invalidate its geometry */
-               if (UDRS->keep_data >= 0) {
-                       if ((UDP->flags & FTD_MSG) &&
+               if (drive_state[drive].keep_data >= 0) {
+                       if ((drive_params[drive].flags & FTD_MSG) &&
                            current_type[drive] != NULL)
                                DPRINT("Disk type is undefined after disk change\n");
                        current_type[drive] = NULL;
@@ -775,8 +778,8 @@ static int disk_change(int drive)
 
                return 1;
        } else {
-               UDRS->last_checked = jiffies;
-               clear_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
+               drive_state[drive].last_checked = jiffies;
+               clear_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[drive].flags);
        }
        return 0;
 }
@@ -799,26 +802,26 @@ static int set_dor(int fdc, char mask, char data)
        unsigned char newdor;
        unsigned char olddor;
 
-       if (FDCS->address == -1)
+       if (fdc_state[fdc].address == -1)
                return -1;
 
-       olddor = FDCS->dor;
+       olddor = fdc_state[fdc].dor;
        newdor = (olddor & mask) | data;
        if (newdor != olddor) {
                unit = olddor & 0x3;
                if (is_selected(olddor, unit) && !is_selected(newdor, unit)) {
                        drive = REVDRIVE(fdc, unit);
-                       debug_dcl(UDP->flags,
+                       debug_dcl(drive_params[drive].flags,
                                  "calling disk change from set_dor\n");
                        disk_change(drive);
                }
-               FDCS->dor = newdor;
-               fd_outb(newdor, FD_DOR);
+               fdc_state[fdc].dor = newdor;
+               fdc_outb(newdor, fdc, FD_DOR);
 
                unit = newdor & 0x3;
                if (!is_selected(olddor, unit) && is_selected(newdor, unit)) {
                        drive = REVDRIVE(fdc, unit);
-                       UDRS->select_date = jiffies;
+                       drive_state[drive].select_date = jiffies;
                }
        }
        return olddor;
@@ -826,11 +829,12 @@ static int set_dor(int fdc, char mask, char data)
 
 static void twaddle(void)
 {
-       if (DP->select_delay)
+       if (drive_params[current_drive].select_delay)
                return;
-       fd_outb(FDCS->dor & ~(0x10 << UNIT(current_drive)), FD_DOR);
-       fd_outb(FDCS->dor, FD_DOR);
-       DRS->select_date = jiffies;
+       fdc_outb(fdc_state[current_fdc].dor & ~(0x10 << UNIT(current_drive)),
+                current_fdc, FD_DOR);
+       fdc_outb(fdc_state[current_fdc].dor, current_fdc, FD_DOR);
+       drive_state[current_drive].select_date = jiffies;
 }
 
 /*
@@ -841,34 +845,38 @@ static void reset_fdc_info(int mode)
 {
        int drive;
 
-       FDCS->spec1 = FDCS->spec2 = -1;
-       FDCS->need_configure = 1;
-       FDCS->perp_mode = 1;
-       FDCS->rawcmd = 0;
+       fdc_state[current_fdc].spec1 = fdc_state[current_fdc].spec2 = -1;
+       fdc_state[current_fdc].need_configure = 1;
+       fdc_state[current_fdc].perp_mode = 1;
+       fdc_state[current_fdc].rawcmd = 0;
        for (drive = 0; drive < N_DRIVE; drive++)
-               if (FDC(drive) == fdc && (mode || UDRS->track != NEED_1_RECAL))
-                       UDRS->track = NEED_2_RECAL;
+               if (FDC(drive) == current_fdc &&
+                   (mode || drive_state[drive].track != NEED_1_RECAL))
+                       drive_state[drive].track = NEED_2_RECAL;
 }
 
 /* selects the fdc and drive, and enables the fdc's input/dma. */
 static void set_fdc(int drive)
 {
+       unsigned int new_fdc = current_fdc;
+
        if (drive >= 0 && drive < N_DRIVE) {
-               fdc = FDC(drive);
+               new_fdc = FDC(drive);
                current_drive = drive;
        }
-       if (fdc != 1 && fdc != 0) {
+       if (new_fdc >= N_FDC) {
                pr_info("bad fdc value\n");
                return;
        }
-       set_dor(fdc, ~0, 8);
+       current_fdc = new_fdc;
+       set_dor(current_fdc, ~0, 8);
 #if N_FDC > 1
-       set_dor(1 - fdc, ~8, 0);
+       set_dor(1 - current_fdc, ~8, 0);
 #endif
-       if (FDCS->rawcmd == 2)
+       if (fdc_state[current_fdc].rawcmd == 2)
                reset_fdc_info(1);
-       if (fd_inb(FD_STATUS) != STATUS_READY)
-               FDCS->reset = 1;
+       if (fdc_inb(current_fdc, FD_STATUS) != STATUS_READY)
+               fdc_state[current_fdc].reset = 1;
 }
 
 /* locks the driver */
@@ -921,19 +929,19 @@ static void floppy_off(unsigned int drive)
        unsigned long volatile delta;
        int fdc = FDC(drive);
 
-       if (!(FDCS->dor & (0x10 << UNIT(drive))))
+       if (!(fdc_state[fdc].dor & (0x10 << UNIT(drive))))
                return;
 
        del_timer(motor_off_timer + drive);
 
        /* make spindle stop in a position which minimizes spinup time
         * next time */
-       if (UDP->rps) {
-               delta = jiffies - UDRS->first_read_date + HZ -
-                   UDP->spindown_offset;
-               delta = ((delta * UDP->rps) % HZ) / UDP->rps;
+       if (drive_params[drive].rps) {
+               delta = jiffies - drive_state[drive].first_read_date + HZ -
+                   drive_params[drive].spindown_offset;
+               delta = ((delta * drive_params[drive].rps) % HZ) / drive_params[drive].rps;
                motor_off_timer[drive].expires =
-                   jiffies + UDP->spindown - delta;
+                   jiffies + drive_params[drive].spindown - delta;
        }
        add_timer(motor_off_timer + drive);
 }
@@ -949,20 +957,20 @@ static void scandrives(void)
        int drive;
        int saved_drive;
 
-       if (DP->select_delay)
+       if (drive_params[current_drive].select_delay)
                return;
 
        saved_drive = current_drive;
        for (i = 0; i < N_DRIVE; i++) {
                drive = (saved_drive + i + 1) % N_DRIVE;
-               if (UDRS->fd_ref == 0 || UDP->select_delay != 0)
+               if (drive_state[drive].fd_ref == 0 || drive_params[drive].select_delay != 0)
                        continue;       /* skip closed drives */
                set_fdc(drive);
-               if (!(set_dor(fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
+               if (!(set_dor(current_fdc, ~3, UNIT(drive) | (0x10 << UNIT(drive))) &
                      (0x10 << UNIT(drive))))
                        /* switch the motor off again, if it was off to
                         * begin with */
-                       set_dor(fdc, ~(0x10 << UNIT(drive)), 0);
+                       set_dor(current_fdc, ~(0x10 << UNIT(drive)), 0);
        }
        set_fdc(saved_drive);
 }
@@ -1008,7 +1016,8 @@ static void cancel_activity(void)
  * transfer */
 static void fd_watchdog(void)
 {
-       debug_dcl(DP->flags, "calling disk change from watchdog\n");
+       debug_dcl(drive_params[current_drive].flags,
+                 "calling disk change from watchdog\n");
 
        if (disk_change(current_drive)) {
                DPRINT("disk removed during i/o\n");
@@ -1032,7 +1041,7 @@ static void main_command_interrupt(void)
 static int fd_wait_for_completion(unsigned long expires,
                                  void (*function)(void))
 {
-       if (FDCS->reset) {
+       if (fdc_state[current_fdc].reset) {
                reset_fdc();    /* do the reset during sleep to win time
                                 * if we don't need to sleep, it's a good
                                 * occasion anyways */
@@ -1060,13 +1069,13 @@ static void setup_DMA(void)
                        pr_cont("%x,", raw_cmd->cmd[i]);
                pr_cont("\n");
                cont->done(0);
-               FDCS->reset = 1;
+               fdc_state[current_fdc].reset = 1;
                return;
        }
        if (((unsigned long)raw_cmd->kernel_data) % 512) {
                pr_info("non aligned address: %p\n", raw_cmd->kernel_data);
                cont->done(0);
-               FDCS->reset = 1;
+               fdc_state[current_fdc].reset = 1;
                return;
        }
        f = claim_dma_lock();
@@ -1074,10 +1083,11 @@ static void setup_DMA(void)
 #ifdef fd_dma_setup
        if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length,
                         (raw_cmd->flags & FD_RAW_READ) ?
-                        DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) {
+                        DMA_MODE_READ : DMA_MODE_WRITE,
+                        fdc_state[current_fdc].address) < 0) {
                release_dma_lock(f);
                cont->done(0);
-               FDCS->reset = 1;
+               fdc_state[current_fdc].reset = 1;
                return;
        }
        release_dma_lock(f);
@@ -1088,7 +1098,7 @@ static void setup_DMA(void)
                        DMA_MODE_READ : DMA_MODE_WRITE);
        fd_set_dma_addr(raw_cmd->kernel_data);
        fd_set_dma_count(raw_cmd->length);
-       virtual_dma_port = FDCS->address;
+       virtual_dma_port = fdc_state[current_fdc].address;
        fd_enable_dma();
        release_dma_lock(f);
 #endif
@@ -1102,18 +1112,18 @@ static int wait_til_ready(void)
        int status;
        int counter;
 
-       if (FDCS->reset)
+       if (fdc_state[current_fdc].reset)
                return -1;
        for (counter = 0; counter < 10000; counter++) {
-               status = fd_inb(FD_STATUS);
+               status = fdc_inb(current_fdc, FD_STATUS);
                if (status & STATUS_READY)
                        return status;
        }
        if (initialized) {
-               DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
+               DPRINT("Getstatus times out (%x) on fdc %d\n", status, current_fdc);
                show_floppy();
        }
-       FDCS->reset = 1;
+       fdc_state[current_fdc].reset = 1;
        return -1;
 }
 
@@ -1126,17 +1136,17 @@ static int output_byte(char byte)
                return -1;
 
        if (is_ready_state(status)) {
-               fd_outb(byte, FD_DATA);
+               fdc_outb(byte, current_fdc, FD_DATA);
                output_log[output_log_pos].data = byte;
                output_log[output_log_pos].status = status;
                output_log[output_log_pos].jiffies = jiffies;
                output_log_pos = (output_log_pos + 1) % OLOGSIZE;
                return 0;
        }
-       FDCS->reset = 1;
+       fdc_state[current_fdc].reset = 1;
        if (initialized) {
                DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
-                      byte, fdc, status);
+                      byte, current_fdc, status);
                show_floppy();
        }
        return -1;
@@ -1159,16 +1169,16 @@ static int result(void)
                        return i;
                }
                if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
-                       reply_buffer[i] = fd_inb(FD_DATA);
+                       reply_buffer[i] = fdc_inb(current_fdc, FD_DATA);
                else
                        break;
        }
        if (initialized) {
                DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
-                      fdc, status, i);
+                      current_fdc, status, i);
                show_floppy();
        }
-       FDCS->reset = 1;
+       fdc_state[current_fdc].reset = 1;
        return -1;
 }
 
@@ -1205,7 +1215,7 @@ static void perpendicular_mode(void)
                default:
                        DPRINT("Invalid data rate for perpendicular mode!\n");
                        cont->done(0);
-                       FDCS->reset = 1;
+                       fdc_state[current_fdc].reset = 1;
                                        /*
                                         * convenient way to return to
                                         * redo without too much hassle
@@ -1216,12 +1226,12 @@ static void perpendicular_mode(void)
        } else
                perp_mode = 0;
 
-       if (FDCS->perp_mode == perp_mode)
+       if (fdc_state[current_fdc].perp_mode == perp_mode)
                return;
-       if (FDCS->version >= FDC_82077_ORIG) {
+       if (fdc_state[current_fdc].version >= FDC_82077_ORIG) {
                output_byte(FD_PERPENDICULAR);
                output_byte(perp_mode);
-               FDCS->perp_mode = perp_mode;
+               fdc_state[current_fdc].perp_mode = perp_mode;
        } else if (perp_mode) {
                DPRINT("perpendicular mode not supported by this FDC.\n");
        }
@@ -1276,9 +1286,10 @@ static void fdc_specify(void)
        int hlt_max_code = 0x7f;
        int hut_max_code = 0xf;
 
-       if (FDCS->need_configure && FDCS->version >= FDC_82072A) {
+       if (fdc_state[current_fdc].need_configure &&
+           fdc_state[current_fdc].version >= FDC_82072A) {
                fdc_configure();
-               FDCS->need_configure = 0;
+               fdc_state[current_fdc].need_configure = 0;
        }
 
        switch (raw_cmd->rate & 0x03) {
@@ -1287,7 +1298,7 @@ static void fdc_specify(void)
                break;
        case 1:
                dtr = 300;
-               if (FDCS->version >= FDC_82078) {
+               if (fdc_state[current_fdc].version >= FDC_82078) {
                        /* chose the default rate table, not the one
                         * where 1 = 2 Mbps */
                        output_byte(FD_DRIVESPEC);
@@ -1302,27 +1313,30 @@ static void fdc_specify(void)
                break;
        }
 
-       if (FDCS->version >= FDC_82072) {
+       if (fdc_state[current_fdc].version >= FDC_82072) {
                scale_dtr = dtr;
                hlt_max_code = 0x00;    /* 0==256msec*dtr0/dtr (not linear!) */
                hut_max_code = 0x0;     /* 0==256msec*dtr0/dtr (not linear!) */
        }
 
        /* Convert step rate from microseconds to milliseconds and 4 bits */
-       srt = 16 - DIV_ROUND_UP(DP->srt * scale_dtr / 1000, NOMINAL_DTR);
+       srt = 16 - DIV_ROUND_UP(drive_params[current_drive].srt * scale_dtr / 1000,
+                               NOMINAL_DTR);
        if (slow_floppy)
                srt = srt / 4;
 
        SUPBOUND(srt, 0xf);
        INFBOUND(srt, 0);
 
-       hlt = DIV_ROUND_UP(DP->hlt * scale_dtr / 2, NOMINAL_DTR);
+       hlt = DIV_ROUND_UP(drive_params[current_drive].hlt * scale_dtr / 2,
+                          NOMINAL_DTR);
        if (hlt < 0x01)
                hlt = 0x01;
        else if (hlt > 0x7f)
                hlt = hlt_max_code;
 
-       hut = DIV_ROUND_UP(DP->hut * scale_dtr / 16, NOMINAL_DTR);
+       hut = DIV_ROUND_UP(drive_params[current_drive].hut * scale_dtr / 16,
+                          NOMINAL_DTR);
        if (hut < 0x1)
                hut = 0x1;
        else if (hut > 0xf)
@@ -1332,11 +1346,12 @@ static void fdc_specify(void)
        spec2 = (hlt << 1) | (use_virtual_dma & 1);
 
        /* If these parameters did not change, just return with success */
-       if (FDCS->spec1 != spec1 || FDCS->spec2 != spec2) {
+       if (fdc_state[current_fdc].spec1 != spec1 ||
+           fdc_state[current_fdc].spec2 != spec2) {
                /* Go ahead and set spec1 and spec2 */
                output_byte(FD_SPECIFY);
-               output_byte(FDCS->spec1 = spec1);
-               output_byte(FDCS->spec2 = spec2);
+               output_byte(fdc_state[current_fdc].spec1 = spec1);
+               output_byte(fdc_state[current_fdc].spec2 = spec2);
        }
 }                              /* fdc_specify */
 
@@ -1347,52 +1362,55 @@ static void fdc_specify(void)
 static int fdc_dtr(void)
 {
        /* If data rate not already set to desired value, set it. */
-       if ((raw_cmd->rate & 3) == FDCS->dtr)
+       if ((raw_cmd->rate & 3) == fdc_state[current_fdc].dtr)
                return 0;
 
        /* Set dtr */
-       fd_outb(raw_cmd->rate & 3, FD_DCR);
+       fdc_outb(raw_cmd->rate & 3, current_fdc, FD_DCR);
 
        /* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
         * need a stabilization period of several milliseconds to be
         * enforced after data rate changes before R/W operations.
         * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
         */
-       FDCS->dtr = raw_cmd->rate & 3;
+       fdc_state[current_fdc].dtr = raw_cmd->rate & 3;
        return fd_wait_for_completion(jiffies + 2UL * HZ / 100, floppy_ready);
 }                              /* fdc_dtr */
 
 static void tell_sector(void)
 {
        pr_cont(": track %d, head %d, sector %d, size %d",
-               R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE);
+               reply_buffer[R_TRACK], reply_buffer[R_HEAD],
+               reply_buffer[R_SECTOR],
+               reply_buffer[R_SIZECODE]);
 }                              /* tell_sector */
 
 static void print_errors(void)
 {
        DPRINT("");
-       if (ST0 & ST0_ECE) {
+       if (reply_buffer[ST0] & ST0_ECE) {
                pr_cont("Recalibrate failed!");
-       } else if (ST2 & ST2_CRC) {
+       } else if (reply_buffer[ST2] & ST2_CRC) {
                pr_cont("data CRC error");
                tell_sector();
-       } else if (ST1 & ST1_CRC) {
+       } else if (reply_buffer[ST1] & ST1_CRC) {
                pr_cont("CRC error");
                tell_sector();
-       } else if ((ST1 & (ST1_MAM | ST1_ND)) ||
-                  (ST2 & ST2_MAM)) {
+       } else if ((reply_buffer[ST1] & (ST1_MAM | ST1_ND)) ||
+                  (reply_buffer[ST2] & ST2_MAM)) {
                if (!probing) {
                        pr_cont("sector not found");
                        tell_sector();
                } else
                        pr_cont("probe failed...");
-       } else if (ST2 & ST2_WC) {      /* seek error */
+       } else if (reply_buffer[ST2] & ST2_WC) {        /* seek error */
                pr_cont("wrong cylinder");
-       } else if (ST2 & ST2_BC) {      /* cylinder marked as bad */
+       } else if (reply_buffer[ST2] & ST2_BC) {        /* cylinder marked as bad */
                pr_cont("bad cylinder");
        } else {
                pr_cont("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x",
-                       ST0, ST1, ST2);
+                       reply_buffer[ST0], reply_buffer[ST1],
+                       reply_buffer[ST2]);
                tell_sector();
        }
        pr_cont("\n");
@@ -1411,33 +1429,35 @@ static int interpret_errors(void)
 
        if (inr != 7) {
                DPRINT("-- FDC reply error\n");
-               FDCS->reset = 1;
+               fdc_state[current_fdc].reset = 1;
                return 1;
        }
 
        /* check IC to find cause of interrupt */
-       switch (ST0 & ST0_INTR) {
+       switch (reply_buffer[ST0] & ST0_INTR) {
        case 0x40:              /* error occurred during command execution */
-               if (ST1 & ST1_EOC)
+               if (reply_buffer[ST1] & ST1_EOC)
                        return 0;       /* occurs with pseudo-DMA */
                bad = 1;
-               if (ST1 & ST1_WP) {
+               if (reply_buffer[ST1] & ST1_WP) {
                        DPRINT("Drive is write protected\n");
-                       clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
+                       clear_bit(FD_DISK_WRITABLE_BIT,
+                                 &drive_state[current_drive].flags);
                        cont->done(0);
                        bad = 2;
-               } else if (ST1 & ST1_ND) {
-                       set_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
-               } else if (ST1 & ST1_OR) {
-                       if (DP->flags & FTD_MSG)
+               } else if (reply_buffer[ST1] & ST1_ND) {
+                       set_bit(FD_NEED_TWADDLE_BIT,
+                               &drive_state[current_drive].flags);
+               } else if (reply_buffer[ST1] & ST1_OR) {
+                       if (drive_params[current_drive].flags & FTD_MSG)
                                DPRINT("Over/Underrun - retrying\n");
                        bad = 0;
-               } else if (*errors >= DP->max_errors.reporting) {
+               } else if (*errors >= drive_params[current_drive].max_errors.reporting) {
                        print_errors();
                }
-               if (ST2 & ST2_WC || ST2 & ST2_BC)
+               if (reply_buffer[ST2] & ST2_WC || reply_buffer[ST2] & ST2_BC)
                        /* wrong cylinder => recal */
-                       DRS->track = NEED_2_RECAL;
+                       drive_state[current_drive].track = NEED_2_RECAL;
                return bad;
        case 0x80:              /* invalid command given */
                DPRINT("Invalid FDC command given!\n");
@@ -1470,13 +1490,13 @@ static void setup_rw_floppy(void)
                flags |= FD_RAW_INTR;
 
        if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)) {
-               ready_date = DRS->spinup_date + DP->spinup;
+               ready_date = drive_state[current_drive].spinup_date + drive_params[current_drive].spinup;
                /* If spinup will take a long time, rerun scandrives
                 * again just before spinup completion. Beware that
                 * after scandrives, we must again wait for selection.
                 */
-               if (time_after(ready_date, jiffies + DP->select_delay)) {
-                       ready_date -= DP->select_delay;
+               if (time_after(ready_date, jiffies + drive_params[current_drive].select_delay)) {
+                       ready_date -= drive_params[current_drive].select_delay;
                        function = floppy_start;
                } else
                        function = setup_rw_floppy;
@@ -1519,44 +1539,52 @@ static int blind_seek;
 static void seek_interrupt(void)
 {
        debugt(__func__, "");
-       if (inr != 2 || (ST0 & 0xF8) != 0x20) {
+       if (inr != 2 || (reply_buffer[ST0] & 0xF8) != 0x20) {
                DPRINT("seek failed\n");
-               DRS->track = NEED_2_RECAL;
+               drive_state[current_drive].track = NEED_2_RECAL;
                cont->error();
                cont->redo();
                return;
        }
-       if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek) {
-               debug_dcl(DP->flags,
+       if (drive_state[current_drive].track >= 0 &&
+           drive_state[current_drive].track != reply_buffer[ST1] &&
+           !blind_seek) {
+               debug_dcl(drive_params[current_drive].flags,
                          "clearing NEWCHANGE flag because of effective seek\n");
-               debug_dcl(DP->flags, "jiffies=%lu\n", jiffies);
-               clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
+               debug_dcl(drive_params[current_drive].flags, "jiffies=%lu\n",
+                         jiffies);
+               clear_bit(FD_DISK_NEWCHANGE_BIT,
+                         &drive_state[current_drive].flags);
                                        /* effective seek */
-               DRS->select_date = jiffies;
+               drive_state[current_drive].select_date = jiffies;
        }
-       DRS->track = ST1;
+       drive_state[current_drive].track = reply_buffer[ST1];
        floppy_ready();
 }
 
 static void check_wp(void)
 {
-       if (test_bit(FD_VERIFY_BIT, &DRS->flags)) {
+       if (test_bit(FD_VERIFY_BIT, &drive_state[current_drive].flags)) {
                                        /* check write protection */
                output_byte(FD_GETSTATUS);
                output_byte(UNIT(current_drive));
                if (result() != 1) {
-                       FDCS->reset = 1;
+                       fdc_state[current_fdc].reset = 1;
                        return;
                }
-               clear_bit(FD_VERIFY_BIT, &DRS->flags);
-               clear_bit(FD_NEED_TWADDLE_BIT, &DRS->flags);
-               debug_dcl(DP->flags,
+               clear_bit(FD_VERIFY_BIT, &drive_state[current_drive].flags);
+               clear_bit(FD_NEED_TWADDLE_BIT,
+                         &drive_state[current_drive].flags);
+               debug_dcl(drive_params[current_drive].flags,
                          "checking whether disk is write protected\n");
-               debug_dcl(DP->flags, "wp=%x\n", ST3 & 0x40);
-               if (!(ST3 & 0x40))
-                       set_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
+               debug_dcl(drive_params[current_drive].flags, "wp=%x\n",
+                         reply_buffer[ST3] & 0x40);
+               if (!(reply_buffer[ST3] & 0x40))
+                       set_bit(FD_DISK_WRITABLE_BIT,
+                               &drive_state[current_drive].flags);
                else
-                       clear_bit(FD_DISK_WRITABLE_BIT, &DRS->flags);
+                       clear_bit(FD_DISK_WRITABLE_BIT,
+                                 &drive_state[current_drive].flags);
        }
 }
 
@@ -1566,32 +1594,34 @@ static void seek_floppy(void)
 
        blind_seek = 0;
 
-       debug_dcl(DP->flags, "calling disk change from %s\n", __func__);
+       debug_dcl(drive_params[current_drive].flags,
+                 "calling disk change from %s\n", __func__);
 
-       if (!test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
+       if (!test_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags) &&
            disk_change(current_drive) && (raw_cmd->flags & FD_RAW_NEED_DISK)) {
                /* the media changed flag should be cleared after the seek.
                 * If it isn't, this means that there is really no disk in
                 * the drive.
                 */
-               set_bit(FD_DISK_CHANGED_BIT, &DRS->flags);
+               set_bit(FD_DISK_CHANGED_BIT,
+                       &drive_state[current_drive].flags);
                cont->done(0);
                cont->redo();
                return;
        }
-       if (DRS->track <= NEED_1_RECAL) {
+       if (drive_state[current_drive].track <= NEED_1_RECAL) {
                recalibrate_floppy();
                return;
-       } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags) &&
+       } else if (test_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags) &&
                   (raw_cmd->flags & FD_RAW_NEED_DISK) &&
-                  (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) {
+                  (drive_state[current_drive].track <= NO_TRACK || drive_state[current_drive].track == raw_cmd->track)) {
                /* we seek to clear the media-changed condition. Does anybody
                 * know a more elegant way, which works on all drives? */
                if (raw_cmd->track)
                        track = raw_cmd->track - 1;
                else {
-                       if (DP->flags & FD_SILENT_DCL_CLEAR) {
-                               set_dor(fdc, ~(0x10 << UNIT(current_drive)), 0);
+                       if (drive_params[current_drive].flags & FD_SILENT_DCL_CLEAR) {
+                               set_dor(current_fdc, ~(0x10 << UNIT(current_drive)), 0);
                                blind_seek = 1;
                                raw_cmd->flags |= FD_RAW_NEED_SEEK;
                        }
@@ -1599,7 +1629,7 @@ static void seek_floppy(void)
                }
        } else {
                check_wp();
-               if (raw_cmd->track != DRS->track &&
+               if (raw_cmd->track != drive_state[current_drive].track &&
                    (raw_cmd->flags & FD_RAW_NEED_SEEK))
                        track = raw_cmd->track;
                else {
@@ -1622,9 +1652,9 @@ static void recal_interrupt(void)
 {
        debugt(__func__, "");
        if (inr != 2)
-               FDCS->reset = 1;
-       else if (ST0 & ST0_ECE) {
-               switch (DRS->track) {
+               fdc_state[current_fdc].reset = 1;
+       else if (reply_buffer[ST0] & ST0_ECE) {
+               switch (drive_state[current_drive].track) {
                case NEED_1_RECAL:
                        debugt(__func__, "need 1 recal");
                        /* after a second recalibrate, we still haven't
@@ -1642,11 +1672,12 @@ static void recal_interrupt(void)
                         * not to move at recalibration is to
                         * be already at track 0.) Clear the
                         * new change flag */
-                       debug_dcl(DP->flags,
+                       debug_dcl(drive_params[current_drive].flags,
                                  "clearing NEWCHANGE flag because of second recalibrate\n");
 
-                       clear_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
-                       DRS->select_date = jiffies;
+                       clear_bit(FD_DISK_NEWCHANGE_BIT,
+                                 &drive_state[current_drive].flags);
+                       drive_state[current_drive].select_date = jiffies;
                        /* fall through */
                default:
                        debugt(__func__, "default");
@@ -1656,11 +1687,11 @@ static void recal_interrupt(void)
                         * track 0, this might mean that we
                         * started beyond track 80.  Try
                         * again.  */
-                       DRS->track = NEED_1_RECAL;
+                       drive_state[current_drive].track = NEED_1_RECAL;
                        break;
                }
        } else
-               DRS->track = ST1;
+               drive_state[current_drive].track = reply_buffer[ST1];
        floppy_ready();
 }
 
@@ -1690,20 +1721,20 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
        release_dma_lock(f);
 
        do_floppy = NULL;
-       if (fdc >= N_FDC || FDCS->address == -1) {
+       if (current_fdc >= N_FDC || fdc_state[current_fdc].address == -1) {
                /* we don't even know which FDC is the culprit */
                pr_info("DOR0=%x\n", fdc_state[0].dor);
-               pr_info("floppy interrupt on bizarre fdc %d\n", fdc);
+               pr_info("floppy interrupt on bizarre fdc %d\n", current_fdc);
                pr_info("handler=%ps\n", handler);
                is_alive(__func__, "bizarre fdc");
                return IRQ_NONE;
        }
 
-       FDCS->reset = 0;
+       fdc_state[current_fdc].reset = 0;
        /* We have to clear the reset flag here, because apparently on boxes
         * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
-        * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
-        * emission of the SENSEI's.
+        * emit SENSEI's to clear the interrupt line. And fdc_state[fdc].reset
+        * blocks the emission of the SENSEI's.
         * It is OK to emit floppy commands because we are in an interrupt
         * handler here, and thus we have to fear no interference of other
         * activity.
@@ -1722,11 +1753,11 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
                        if (do_print)
                                print_result("sensei", inr);
                        max_sensei--;
-               } while ((ST0 & 0x83) != UNIT(current_drive) &&
+               } while ((reply_buffer[ST0] & 0x83) != UNIT(current_drive) &&
                         inr == 2 && max_sensei);
        }
        if (!handler) {
-               FDCS->reset = 1;
+               fdc_state[current_fdc].reset = 1;
                return IRQ_NONE;
        }
        schedule_bh(handler);
@@ -1752,7 +1783,7 @@ static void reset_interrupt(void)
 {
        debugt(__func__, "");
        result();               /* get the status ready for set_fdc */
-       if (FDCS->reset) {
+       if (fdc_state[current_fdc].reset) {
                pr_info("reset set in interrupt, calling %ps\n", cont->error);
                cont->error();  /* a reset just after a reset. BAD! */
        }
@@ -1768,7 +1799,7 @@ static void reset_fdc(void)
        unsigned long flags;
 
        do_floppy = reset_interrupt;
-       FDCS->reset = 0;
+       fdc_state[current_fdc].reset = 0;
        reset_fdc_info(0);
 
        /* Pseudo-DMA may intercept 'reset finished' interrupt.  */
@@ -1778,12 +1809,13 @@ static void reset_fdc(void)
        fd_disable_dma();
        release_dma_lock(flags);
 
-       if (FDCS->version >= FDC_82072A)
-               fd_outb(0x80 | (FDCS->dtr & 3), FD_STATUS);
+       if (fdc_state[current_fdc].version >= FDC_82072A)
+               fdc_outb(0x80 | (fdc_state[current_fdc].dtr & 3),
+                        current_fdc, FD_STATUS);
        else {
-               fd_outb(FDCS->dor & ~0x04, FD_DOR);
+               fdc_outb(fdc_state[current_fdc].dor & ~0x04, current_fdc, FD_DOR);
                udelay(FD_RESET_DELAY);
-               fd_outb(FDCS->dor, FD_DOR);
+               fdc_outb(fdc_state[current_fdc].dor, current_fdc, FD_DOR);
        }
 }
 
@@ -1810,7 +1842,7 @@ static void show_floppy(void)
        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
                       reply_buffer, resultsize, true);
 
-       pr_info("status=%x\n", fd_inb(FD_STATUS));
+       pr_info("status=%x\n", fdc_inb(current_fdc, FD_STATUS));
        pr_info("fdc_busy=%lu\n", fdc_busy);
        if (do_floppy)
                pr_info("do_floppy=%ps\n", do_floppy);
@@ -1847,7 +1879,7 @@ static void floppy_shutdown(struct work_struct *arg)
 
        if (initialized)
                DPRINT("floppy timeout called\n");
-       FDCS->reset = 1;
+       fdc_state[current_fdc].reset = 1;
        if (cont) {
                cont->done(0);
                cont->redo();   /* this will recall reset when needed */
@@ -1867,29 +1899,29 @@ static int start_motor(void (*function)(void))
        mask = 0xfc;
        data = UNIT(current_drive);
        if (!(raw_cmd->flags & FD_RAW_NO_MOTOR)) {
-               if (!(FDCS->dor & (0x10 << UNIT(current_drive)))) {
+               if (!(fdc_state[current_fdc].dor & (0x10 << UNIT(current_drive)))) {
                        set_debugt();
                        /* no read since this drive is running */
-                       DRS->first_read_date = 0;
+                       drive_state[current_drive].first_read_date = 0;
                        /* note motor start time if motor is not yet running */
-                       DRS->spinup_date = jiffies;
+                       drive_state[current_drive].spinup_date = jiffies;
                        data |= (0x10 << UNIT(current_drive));
                }
-       } else if (FDCS->dor & (0x10 << UNIT(current_drive)))
+       } else if (fdc_state[current_fdc].dor & (0x10 << UNIT(current_drive)))
                mask &= ~(0x10 << UNIT(current_drive));
 
        /* starts motor and selects floppy */
        del_timer(motor_off_timer + current_drive);
-       set_dor(fdc, mask, data);
+       set_dor(current_fdc, mask, data);
 
        /* wait_for_completion also schedules reset if needed. */
-       return fd_wait_for_completion(DRS->select_date + DP->select_delay,
+       return fd_wait_for_completion(drive_state[current_drive].select_date + drive_params[current_drive].select_delay,
                                      function);
 }
 
 static void floppy_ready(void)
 {
-       if (FDCS->reset) {
+       if (fdc_state[current_fdc].reset) {
                reset_fdc();
                return;
        }
@@ -1898,9 +1930,10 @@ static void floppy_ready(void)
        if (fdc_dtr())
                return;
 
-       debug_dcl(DP->flags, "calling disk change from floppy_ready\n");
+       debug_dcl(drive_params[current_drive].flags,
+                 "calling disk change from floppy_ready\n");
        if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
-           disk_change(current_drive) && !DP->select_delay)
+           disk_change(current_drive) && !drive_params[current_drive].select_delay)
                twaddle();      /* this clears the dcl on certain
                                 * drive/controller combinations */
 
@@ -1929,8 +1962,9 @@ static void floppy_start(void)
        reschedule_timeout(current_reqD, "floppy start");
 
        scandrives();
-       debug_dcl(DP->flags, "setting NEWCHANGE in floppy_start\n");
-       set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
+       debug_dcl(drive_params[current_drive].flags,
+                 "setting NEWCHANGE in floppy_start\n");
+       set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags);
        floppy_ready();
 }
 
@@ -1988,7 +2022,7 @@ static int wait_til_done(void (*handler)(void), bool interruptible)
                return -EINTR;
        }
 
-       if (FDCS->reset)
+       if (fdc_state[current_fdc].reset)
                command_status = FD_COMMAND_ERROR;
        if (command_status == FD_COMMAND_OKAY)
                ret = 0;
@@ -2029,14 +2063,14 @@ static int next_valid_format(void)
 {
        int probed_format;
 
-       probed_format = DRS->probed_format;
+       probed_format = drive_state[current_drive].probed_format;
        while (1) {
-               if (probed_format >= 8 || !DP->autodetect[probed_format]) {
-                       DRS->probed_format = 0;
+               if (probed_format >= 8 || !drive_params[current_drive].autodetect[probed_format]) {
+                       drive_state[current_drive].probed_format = 0;
                        return 1;
                }
-               if (floppy_type[DP->autodetect[probed_format]].sect) {
-                       DRS->probed_format = probed_format;
+               if (floppy_type[drive_params[current_drive].autodetect[probed_format]].sect) {
+                       drive_state[current_drive].probed_format = probed_format;
                        return 0;
                }
                probed_format++;
@@ -2048,23 +2082,23 @@ static void bad_flp_intr(void)
        int err_count;
 
        if (probing) {
-               DRS->probed_format++;
+               drive_state[current_drive].probed_format++;
                if (!next_valid_format())
                        return;
        }
        err_count = ++(*errors);
-       INFBOUND(DRWE->badness, err_count);
-       if (err_count > DP->max_errors.abort)
+       INFBOUND(write_errors[current_drive].badness, err_count);
+       if (err_count > drive_params[current_drive].max_errors.abort)
                cont->done(0);
-       if (err_count > DP->max_errors.reset)
-               FDCS->reset = 1;
-       else if (err_count > DP->max_errors.recal)
-               DRS->track = NEED_2_RECAL;
+       if (err_count > drive_params[current_drive].max_errors.reset)
+               fdc_state[current_fdc].reset = 1;
+       else if (err_count > drive_params[current_drive].max_errors.recal)
+               drive_state[current_drive].track = NEED_2_RECAL;
 }
 
 static void set_floppy(int drive)
 {
-       int type = ITYPE(UDRS->fd_device);
+       int type = ITYPE(drive_state[drive].fd_device);
 
        if (type)
                _floppy = floppy_type + type;
@@ -2110,28 +2144,28 @@ static void setup_format_params(int track)
                          FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK);
        raw_cmd->rate = _floppy->rate & 0x43;
        raw_cmd->cmd_count = NR_F;
-       COMMAND = FM_MODE(_floppy, FD_FORMAT);
-       DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
-       F_SIZECODE = FD_SIZECODE(_floppy);
-       F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE;
-       F_GAP = _floppy->fmt_gap;
-       F_FILL = FD_FILL_BYTE;
+       raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_FORMAT);
+       raw_cmd->cmd[DR_SELECT] = UNIT(current_drive) + PH_HEAD(_floppy, format_req.head);
+       raw_cmd->cmd[F_SIZECODE] = FD_SIZECODE(_floppy);
+       raw_cmd->cmd[F_SECT_PER_TRACK] = _floppy->sect << 2 >> raw_cmd->cmd[F_SIZECODE];
+       raw_cmd->cmd[F_GAP] = _floppy->fmt_gap;
+       raw_cmd->cmd[F_FILL] = FD_FILL_BYTE;
 
        raw_cmd->kernel_data = floppy_track_buffer;
-       raw_cmd->length = 4 * F_SECT_PER_TRACK;
+       raw_cmd->length = 4 * raw_cmd->cmd[F_SECT_PER_TRACK];
 
-       if (!F_SECT_PER_TRACK)
+       if (!raw_cmd->cmd[F_SECT_PER_TRACK])
                return;
 
        /* allow for about 30ms for data transport per track */
-       head_shift = (F_SECT_PER_TRACK + 5) / 6;
+       head_shift = (raw_cmd->cmd[F_SECT_PER_TRACK] + 5) / 6;
 
        /* a ``cylinder'' is two tracks plus a little stepping time */
        track_shift = 2 * head_shift + 3;
 
        /* position of logical sector 1 on this track */
        n = (track_shift * format_req.track + head_shift * format_req.head)
-           % F_SECT_PER_TRACK;
+           % raw_cmd->cmd[F_SECT_PER_TRACK];
 
        /* determine interleave */
        il = 1;
@@ -2139,27 +2173,27 @@ static void setup_format_params(int track)
                il++;
 
        /* initialize field */
-       for (count = 0; count < F_SECT_PER_TRACK; ++count) {
+       for (count = 0; count < raw_cmd->cmd[F_SECT_PER_TRACK]; ++count) {
                here[count].track = format_req.track;
                here[count].head = format_req.head;
                here[count].sect = 0;
-               here[count].size = F_SIZECODE;
+               here[count].size = raw_cmd->cmd[F_SIZECODE];
        }
        /* place logical sectors */
-       for (count = 1; count <= F_SECT_PER_TRACK; ++count) {
+       for (count = 1; count <= raw_cmd->cmd[F_SECT_PER_TRACK]; ++count) {
                here[n].sect = count;
-               n = (n + il) % F_SECT_PER_TRACK;
+               n = (n + il) % raw_cmd->cmd[F_SECT_PER_TRACK];
                if (here[n].sect) {     /* sector busy, find next free sector */
                        ++n;
-                       if (n >= F_SECT_PER_TRACK) {
-                               n -= F_SECT_PER_TRACK;
+                       if (n >= raw_cmd->cmd[F_SECT_PER_TRACK]) {
+                               n -= raw_cmd->cmd[F_SECT_PER_TRACK];
                                while (here[n].sect)
                                        ++n;
                        }
                }
        }
        if (_floppy->stretch & FD_SECTBASEMASK) {
-               for (count = 0; count < F_SECT_PER_TRACK; count++)
+               for (count = 0; count < raw_cmd->cmd[F_SECT_PER_TRACK]; count++)
                        here[count].sect += FD_SECTBASE(_floppy) - 1;
        }
 }
@@ -2188,7 +2222,7 @@ static int do_format(int drive, struct format_descr *tmp_format_req)
 
        set_floppy(drive);
        if (!_floppy ||
-           _floppy->track > DP->tracks ||
+           _floppy->track > drive_params[current_drive].tracks ||
            tmp_format_req->track >= _floppy->track ||
            tmp_format_req->head >= _floppy->head ||
            (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) ||
@@ -2250,21 +2284,21 @@ static void request_done(int uptodate)
                /* maintain values for invalidation on geometry
                 * change */
                block = current_count_sectors + blk_rq_pos(req);
-               INFBOUND(DRS->maxblock, block);
+               INFBOUND(drive_state[current_drive].maxblock, block);
                if (block > _floppy->sect)
-                       DRS->maxtrack = 1;
+                       drive_state[current_drive].maxtrack = 1;
 
                floppy_end_request(req, 0);
        } else {
                if (rq_data_dir(req) == WRITE) {
                        /* record write error information */
-                       DRWE->write_errors++;
-                       if (DRWE->write_errors == 1) {
-                               DRWE->first_error_sector = blk_rq_pos(req);
-                               DRWE->first_error_generation = DRS->generation;
+                       write_errors[current_drive].write_errors++;
+                       if (write_errors[current_drive].write_errors == 1) {
+                               write_errors[current_drive].first_error_sector = blk_rq_pos(req);
+                               write_errors[current_drive].first_error_generation = drive_state[current_drive].generation;
                        }
-                       DRWE->last_error_sector = blk_rq_pos(req);
-                       DRWE->last_error_generation = DRS->generation;
+                       write_errors[current_drive].last_error_sector = blk_rq_pos(req);
+                       write_errors[current_drive].last_error_generation = drive_state[current_drive].generation;
                }
                floppy_end_request(req, BLK_STS_IOERR);
        }
@@ -2278,43 +2312,46 @@ static void rw_interrupt(void)
        int heads;
        int nr_sectors;
 
-       if (R_HEAD >= 2) {
+       if (reply_buffer[R_HEAD] >= 2) {
                /* some Toshiba floppy controllers occasionnally seem to
                 * return bogus interrupts after read/write operations, which
                 * can be recognized by a bad head number (>= 2) */
                return;
        }
 
-       if (!DRS->first_read_date)
-               DRS->first_read_date = jiffies;
+       if (!drive_state[current_drive].first_read_date)
+               drive_state[current_drive].first_read_date = jiffies;
 
        nr_sectors = 0;
-       ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
+       ssize = DIV_ROUND_UP(1 << raw_cmd->cmd[SIZECODE], 4);
 
-       if (ST1 & ST1_EOC)
+       if (reply_buffer[ST1] & ST1_EOC)
                eoc = 1;
        else
                eoc = 0;
 
-       if (COMMAND & 0x80)
+       if (raw_cmd->cmd[COMMAND] & 0x80)
                heads = 2;
        else
                heads = 1;
 
-       nr_sectors = (((R_TRACK - TRACK) * heads +
-                      R_HEAD - HEAD) * SECT_PER_TRACK +
-                     R_SECTOR - SECTOR + eoc) << SIZECODE >> 2;
+       nr_sectors = (((reply_buffer[R_TRACK] - raw_cmd->cmd[TRACK]) * heads +
+                      reply_buffer[R_HEAD] - raw_cmd->cmd[HEAD]) * raw_cmd->cmd[SECT_PER_TRACK] +
+                     reply_buffer[R_SECTOR] - raw_cmd->cmd[SECTOR] + eoc) << raw_cmd->cmd[SIZECODE] >> 2;
 
        if (nr_sectors / ssize >
            DIV_ROUND_UP(in_sector_offset + current_count_sectors, ssize)) {
                DPRINT("long rw: %x instead of %lx\n",
                       nr_sectors, current_count_sectors);
-               pr_info("rs=%d s=%d\n", R_SECTOR, SECTOR);
-               pr_info("rh=%d h=%d\n", R_HEAD, HEAD);
-               pr_info("rt=%d t=%d\n", R_TRACK, TRACK);
+               pr_info("rs=%d s=%d\n", reply_buffer[R_SECTOR],
+                       raw_cmd->cmd[SECTOR]);
+               pr_info("rh=%d h=%d\n", reply_buffer[R_HEAD],
+                       raw_cmd->cmd[HEAD]);
+               pr_info("rt=%d t=%d\n", reply_buffer[R_TRACK],
+                       raw_cmd->cmd[TRACK]);
                pr_info("heads=%d eoc=%d\n", heads, eoc);
                pr_info("spt=%d st=%d ss=%d\n",
-                       SECT_PER_TRACK, fsector_t, ssize);
+                       raw_cmd->cmd[SECT_PER_TRACK], fsector_t, ssize);
                pr_info("in_sector_offset=%d\n", in_sector_offset);
        }
 
@@ -2344,7 +2381,7 @@ static void rw_interrupt(void)
        }
 
        if (probing) {
-               if (DP->flags & FTD_MSG)
+               if (drive_params[current_drive].flags & FTD_MSG)
                        DPRINT("Auto-detected floppy type %s in fd%d\n",
                               _floppy->name, current_drive);
                current_type[current_drive] = _floppy;
@@ -2352,11 +2389,11 @@ static void rw_interrupt(void)
                probing = 0;
        }
 
-       if (CT(COMMAND) != FD_READ ||
+       if (CT(raw_cmd->cmd[COMMAND]) != FD_READ ||
            raw_cmd->kernel_data == bio_data(current_req->bio)) {
                /* transfer directly from buffer */
                cont->done(1);
-       } else if (CT(COMMAND) == FD_READ) {
+       } else if (CT(raw_cmd->cmd[COMMAND]) == FD_READ) {
                buffer_track = raw_cmd->track;
                buffer_drive = current_drive;
                INFBOUND(buffer_max, nr_sectors + fsector_t);
@@ -2415,13 +2452,13 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
                                   min(max_sector, max_sector_2),
                                   blk_rq_sectors(current_req));
 
-       if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
+       if (current_count_sectors <= 0 && CT(raw_cmd->cmd[COMMAND]) == FD_WRITE &&
            buffer_max > fsector_t + blk_rq_sectors(current_req))
                current_count_sectors = min_t(int, buffer_max - fsector_t,
                                              blk_rq_sectors(current_req));
 
        remaining = current_count_sectors << 9;
-       if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
+       if (remaining > blk_rq_bytes(current_req) && CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
                DPRINT("in copy buffer\n");
                pr_info("current_count_sectors=%ld\n", current_count_sectors);
                pr_info("remaining=%d\n", remaining >> 9);
@@ -2456,16 +2493,16 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
                                fsector_t, buffer_min);
                        pr_info("current_count_sectors=%ld\n",
                                current_count_sectors);
-                       if (CT(COMMAND) == FD_READ)
+                       if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
                                pr_info("read\n");
-                       if (CT(COMMAND) == FD_WRITE)
+                       if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE)
                                pr_info("write\n");
                        break;
                }
                if (((unsigned long)buffer) % 512)
                        DPRINT("%p buffer not aligned\n", buffer);
 
-               if (CT(COMMAND) == FD_READ)
+               if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
                        memcpy(buffer, dma_buffer, size);
                else
                        memcpy(dma_buffer, buffer, size);
@@ -2483,7 +2520,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
 /* work around a bug in pseudo DMA
  * (on some FDCs) pseudo DMA does not stop when the CPU stops
  * sending data.  Hence we need a different way to signal the
- * transfer length:  We use SECT_PER_TRACK.  Unfortunately, this
+ * transfer length:  We use raw_cmd->cmd[SECT_PER_TRACK].  Unfortunately, this
  * does not work with MT, hence we can only transfer one head at
  * a time
  */
@@ -2492,18 +2529,18 @@ static void virtualdmabug_workaround(void)
        int hard_sectors;
        int end_sector;
 
-       if (CT(COMMAND) == FD_WRITE) {
-               COMMAND &= ~0x80;       /* switch off multiple track mode */
+       if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
+               raw_cmd->cmd[COMMAND] &= ~0x80; /* switch off multiple track mode */
 
-               hard_sectors = raw_cmd->length >> (7 + SIZECODE);
-               end_sector = SECTOR + hard_sectors - 1;
-               if (end_sector > SECT_PER_TRACK) {
+               hard_sectors = raw_cmd->length >> (7 + raw_cmd->cmd[SIZECODE]);
+               end_sector = raw_cmd->cmd[SECTOR] + hard_sectors - 1;
+               if (end_sector > raw_cmd->cmd[SECT_PER_TRACK]) {
                        pr_info("too many sectors %d > %d\n",
-                               end_sector, SECT_PER_TRACK);
+                               end_sector, raw_cmd->cmd[SECT_PER_TRACK]);
                        return;
                }
-               SECT_PER_TRACK = end_sector;
-                                       /* make sure SECT_PER_TRACK
+               raw_cmd->cmd[SECT_PER_TRACK] = end_sector;
+                                       /* make sure raw_cmd->cmd[SECT_PER_TRACK]
                                         * points to end of transfer */
        }
 }
@@ -2536,10 +2573,10 @@ static int make_raw_rw_request(void)
        raw_cmd->cmd_count = NR_RW;
        if (rq_data_dir(current_req) == READ) {
                raw_cmd->flags |= FD_RAW_READ;
-               COMMAND = FM_MODE(_floppy, FD_READ);
+               raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_READ);
        } else if (rq_data_dir(current_req) == WRITE) {
                raw_cmd->flags |= FD_RAW_WRITE;
-               COMMAND = FM_MODE(_floppy, FD_WRITE);
+               raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_WRITE);
        } else {
                DPRINT("%s: unknown command\n", __func__);
                return 0;
@@ -2547,24 +2584,24 @@ static int make_raw_rw_request(void)
 
        max_sector = _floppy->sect * _floppy->head;
 
-       TRACK = (int)blk_rq_pos(current_req) / max_sector;
+       raw_cmd->cmd[TRACK] = (int)blk_rq_pos(current_req) / max_sector;
        fsector_t = (int)blk_rq_pos(current_req) % max_sector;
-       if (_floppy->track && TRACK >= _floppy->track) {
+       if (_floppy->track && raw_cmd->cmd[TRACK] >= _floppy->track) {
                if (blk_rq_cur_sectors(current_req) & 1) {
                        current_count_sectors = 1;
                        return 1;
                } else
                        return 0;
        }
-       HEAD = fsector_t / _floppy->sect;
+       raw_cmd->cmd[HEAD] = fsector_t / _floppy->sect;
 
        if (((_floppy->stretch & (FD_SWAPSIDES | FD_SECTBASEMASK)) ||
-            test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags)) &&
+            test_bit(FD_NEED_TWADDLE_BIT, &drive_state[current_drive].flags)) &&
            fsector_t < _floppy->sect)
                max_sector = _floppy->sect;
 
        /* 2M disks have phantom sectors on the first track */
-       if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)) {
+       if ((_floppy->rate & FD_2M) && (!raw_cmd->cmd[TRACK]) && (!raw_cmd->cmd[HEAD])) {
                max_sector = 2 * _floppy->sect / 3;
                if (fsector_t >= max_sector) {
                        current_count_sectors =
@@ -2572,23 +2609,24 @@ static int make_raw_rw_request(void)
                                  blk_rq_sectors(current_req));
                        return 1;
                }
-               SIZECODE = 2;
+               raw_cmd->cmd[SIZECODE] = 2;
        } else
-               SIZECODE = FD_SIZECODE(_floppy);
+               raw_cmd->cmd[SIZECODE] = FD_SIZECODE(_floppy);
        raw_cmd->rate = _floppy->rate & 0x43;
-       if ((_floppy->rate & FD_2M) && (TRACK || HEAD) && raw_cmd->rate == 2)
+       if ((_floppy->rate & FD_2M) &&
+           (raw_cmd->cmd[TRACK] || raw_cmd->cmd[HEAD]) && raw_cmd->rate == 2)
                raw_cmd->rate = 1;
 
-       if (SIZECODE)
-               SIZECODE2 = 0xff;
+       if (raw_cmd->cmd[SIZECODE])
+               raw_cmd->cmd[SIZECODE2] = 0xff;
        else
-               SIZECODE2 = 0x80;
-       raw_cmd->track = TRACK << STRETCH(_floppy);
-       DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy, HEAD);
-       GAP = _floppy->gap;
-       ssize = DIV_ROUND_UP(1 << SIZECODE, 4);
-       SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE;
-       SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) +
+               raw_cmd->cmd[SIZECODE2] = 0x80;
+       raw_cmd->track = raw_cmd->cmd[TRACK] << STRETCH(_floppy);
+       raw_cmd->cmd[DR_SELECT] = UNIT(current_drive) + PH_HEAD(_floppy, raw_cmd->cmd[HEAD]);
+       raw_cmd->cmd[GAP] = _floppy->gap;
+       ssize = DIV_ROUND_UP(1 << raw_cmd->cmd[SIZECODE], 4);
+       raw_cmd->cmd[SECT_PER_TRACK] = _floppy->sect << 2 >> raw_cmd->cmd[SIZECODE];
+       raw_cmd->cmd[SECTOR] = ((fsector_t % _floppy->sect) << 2 >> raw_cmd->cmd[SIZECODE]) +
            FD_SECTBASE(_floppy);
 
        /* tracksize describes the size which can be filled up with sectors
@@ -2596,24 +2634,24 @@ static int make_raw_rw_request(void)
         */
        tracksize = _floppy->sect - _floppy->sect % ssize;
        if (tracksize < _floppy->sect) {
-               SECT_PER_TRACK++;
+               raw_cmd->cmd[SECT_PER_TRACK]++;
                if (tracksize <= fsector_t % _floppy->sect)
-                       SECTOR--;
+                       raw_cmd->cmd[SECTOR]--;
 
                /* if we are beyond tracksize, fill up using smaller sectors */
                while (tracksize <= fsector_t % _floppy->sect) {
                        while (tracksize + ssize > _floppy->sect) {
-                               SIZECODE--;
+                               raw_cmd->cmd[SIZECODE]--;
                                ssize >>= 1;
                        }
-                       SECTOR++;
-                       SECT_PER_TRACK++;
+                       raw_cmd->cmd[SECTOR]++;
+                       raw_cmd->cmd[SECT_PER_TRACK]++;
                        tracksize += ssize;
                }
-               max_sector = HEAD * _floppy->sect + tracksize;
-       } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) {
+               max_sector = raw_cmd->cmd[HEAD] * _floppy->sect + tracksize;
+       } else if (!raw_cmd->cmd[TRACK] && !raw_cmd->cmd[HEAD] && !(_floppy->rate & FD_2M) && probing) {
                max_sector = _floppy->sect;
-       } else if (!HEAD && CT(COMMAND) == FD_WRITE) {
+       } else if (!raw_cmd->cmd[HEAD] && CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
                /* for virtual DMA bug workaround */
                max_sector = _floppy->sect;
        }
@@ -2625,12 +2663,12 @@ static int make_raw_rw_request(void)
            (current_drive == buffer_drive) &&
            (fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
                /* data already in track buffer */
-               if (CT(COMMAND) == FD_READ) {
+               if (CT(raw_cmd->cmd[COMMAND]) == FD_READ) {
                        copy_buffer(1, max_sector, buffer_max);
                        return 1;
                }
        } else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
-               if (CT(COMMAND) == FD_WRITE) {
+               if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
                        unsigned int sectors;
 
                        sectors = fsector_t + blk_rq_sectors(current_req);
@@ -2641,7 +2679,7 @@ static int make_raw_rw_request(void)
                }
                raw_cmd->flags &= ~FD_RAW_WRITE;
                raw_cmd->flags |= FD_RAW_READ;
-               COMMAND = FM_MODE(_floppy, FD_READ);
+               raw_cmd->cmd[COMMAND] = FM_MODE(_floppy, FD_READ);
        } else if ((unsigned long)bio_data(current_req->bio) < MAX_DMA_ADDRESS) {
                unsigned long dma_limit;
                int direct, indirect;
@@ -2674,9 +2712,9 @@ static int make_raw_rw_request(void)
                 */
                if (!direct ||
                    (indirect * 2 > direct * 3 &&
-                    *errors < DP->max_errors.read_track &&
+                    *errors < drive_params[current_drive].max_errors.read_track &&
                     ((!probing ||
-                      (DP->read_track & (1 << DRS->probed_format)))))) {
+                      (drive_params[current_drive].read_track & (1 << drive_state[current_drive].probed_format)))))) {
                        max_size = blk_rq_sectors(current_req);
                } else {
                        raw_cmd->kernel_data = bio_data(current_req->bio);
@@ -2692,7 +2730,7 @@ static int make_raw_rw_request(void)
                }
        }
 
-       if (CT(COMMAND) == FD_READ)
+       if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
                max_size = max_sector;  /* unbounded */
 
        /* claim buffer track if needed */
@@ -2700,7 +2738,7 @@ static int make_raw_rw_request(void)
            buffer_drive != current_drive ||    /* bad drive */
            fsector_t > buffer_max ||
            fsector_t < buffer_min ||
-           ((CT(COMMAND) == FD_READ ||
+           ((CT(raw_cmd->cmd[COMMAND]) == FD_READ ||
              (!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
             max_sector > 2 * max_buffer_sectors + buffer_min &&
             max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)) {
@@ -2712,7 +2750,7 @@ static int make_raw_rw_request(void)
        raw_cmd->kernel_data = floppy_track_buffer +
                ((aligned_sector_t - buffer_min) << 9);
 
-       if (CT(COMMAND) == FD_WRITE) {
+       if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE) {
                /* copy write buffer to track buffer.
                 * if we get here, we know that the write
                 * is either aligned or the data already in the buffer
@@ -2734,10 +2772,10 @@ static int make_raw_rw_request(void)
        raw_cmd->length <<= 9;
        if ((raw_cmd->length < current_count_sectors << 9) ||
            (raw_cmd->kernel_data != bio_data(current_req->bio) &&
-            CT(COMMAND) == FD_WRITE &&
+            CT(raw_cmd->cmd[COMMAND]) == FD_WRITE &&
             (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max ||
              aligned_sector_t < buffer_min)) ||
-           raw_cmd->length % (128 << SIZECODE) ||
+           raw_cmd->length % (128 << raw_cmd->cmd[SIZECODE]) ||
            raw_cmd->length <= 0 || current_count_sectors <= 0) {
                DPRINT("fractionary current count b=%lx s=%lx\n",
                       raw_cmd->length, current_count_sectors);
@@ -2748,9 +2786,10 @@ static int make_raw_rw_request(void)
                                current_count_sectors);
                pr_info("st=%d ast=%d mse=%d msi=%d\n",
                        fsector_t, aligned_sector_t, max_sector, max_size);
-               pr_info("ssize=%x SIZECODE=%d\n", ssize, SIZECODE);
+               pr_info("ssize=%x SIZECODE=%d\n", ssize, raw_cmd->cmd[SIZECODE]);
                pr_info("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n",
-                       COMMAND, SECTOR, HEAD, TRACK);
+                       raw_cmd->cmd[COMMAND], raw_cmd->cmd[SECTOR],
+                       raw_cmd->cmd[HEAD], raw_cmd->cmd[TRACK]);
                pr_info("buffer drive=%d\n", buffer_drive);
                pr_info("buffer track=%d\n", buffer_track);
                pr_info("buffer_min=%d\n", buffer_min);
@@ -2769,9 +2808,9 @@ static int make_raw_rw_request(void)
                                fsector_t, buffer_min, raw_cmd->length >> 9);
                        pr_info("current_count_sectors=%ld\n",
                                current_count_sectors);
-                       if (CT(COMMAND) == FD_READ)
+                       if (CT(raw_cmd->cmd[COMMAND]) == FD_READ)
                                pr_info("read\n");
-                       if (CT(COMMAND) == FD_WRITE)
+                       if (CT(raw_cmd->cmd[COMMAND]) == FD_WRITE)
                                pr_info("write\n");
                        return 0;
                }
@@ -2838,14 +2877,14 @@ do_request:
 
        disk_change(current_drive);
        if (test_bit(current_drive, &fake_change) ||
-           test_bit(FD_DISK_CHANGED_BIT, &DRS->flags)) {
+           test_bit(FD_DISK_CHANGED_BIT, &drive_state[current_drive].flags)) {
                DPRINT("disk absent or changed during operation\n");
                request_done(0);
                goto do_request;
        }
        if (!_floppy) { /* Autodetection */
                if (!probing) {
-                       DRS->probed_format = 0;
+                       drive_state[current_drive].probed_format = 0;
                        if (next_valid_format()) {
                                DPRINT("no autodetectable formats\n");
                                _floppy = NULL;
@@ -2854,7 +2893,7 @@ do_request:
                        }
                }
                probing = 1;
-               _floppy = floppy_type + DP->autodetect[DRS->probed_format];
+               _floppy = floppy_type + drive_params[current_drive].autodetect[drive_state[current_drive].probed_format];
        } else
                probing = 0;
        errors = &(current_req->error_count);
@@ -2864,7 +2903,7 @@ do_request:
                goto do_request;
        }
 
-       if (test_bit(FD_NEED_TWADDLE_BIT, &DRS->flags))
+       if (test_bit(FD_NEED_TWADDLE_BIT, &drive_state[current_drive].flags))
                twaddle();
        schedule_bh(floppy_start);
        debugt(__func__, "queue fd request");
@@ -2933,8 +2972,9 @@ static int poll_drive(bool interruptible, int flag)
        raw_cmd->track = 0;
        raw_cmd->cmd_count = 0;
        cont = &poll_cont;
-       debug_dcl(DP->flags, "setting NEWCHANGE in poll_drive\n");
-       set_bit(FD_DISK_NEWCHANGE_BIT, &DRS->flags);
+       debug_dcl(drive_params[current_drive].flags,
+                 "setting NEWCHANGE in poll_drive\n");
+       set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[current_drive].flags);
 
        return wait_til_done(floppy_ready, interruptible);
 }
@@ -2964,8 +3004,8 @@ static int user_reset_fdc(int drive, int arg, bool interruptible)
                return -EINTR;
 
        if (arg == FD_RESET_ALWAYS)
-               FDCS->reset = 1;
-       if (FDCS->reset) {
+               fdc_state[current_fdc].reset = 1;
+       if (fdc_state[current_fdc].reset) {
                cont = &reset_cont;
                ret = wait_til_done(reset_fdc, interruptible);
                if (ret == -EINTR)
@@ -2998,8 +3038,8 @@ static const char *drive_name(int type, int drive)
        if (type)
                floppy = floppy_type + type;
        else {
-               if (UDP->native_format)
-                       floppy = floppy_type + UDP->native_format;
+               if (drive_params[drive].native_format)
+                       floppy = floppy_type + drive_params[drive].native_format;
                else
                        return "(null)";
        }
@@ -3176,23 +3216,23 @@ static int raw_cmd_ioctl(int cmd, void __user *param)
        int ret2;
        int ret;
 
-       if (FDCS->rawcmd <= 1)
-               FDCS->rawcmd = 1;
+       if (fdc_state[current_fdc].rawcmd <= 1)
+               fdc_state[current_fdc].rawcmd = 1;
        for (drive = 0; drive < N_DRIVE; drive++) {
-               if (FDC(drive) != fdc)
+               if (FDC(drive) != current_fdc)
                        continue;
                if (drive == current_drive) {
-                       if (UDRS->fd_ref > 1) {
-                               FDCS->rawcmd = 2;
+                       if (drive_state[drive].fd_ref > 1) {
+                               fdc_state[current_fdc].rawcmd = 2;
                                break;
                        }
-               } else if (UDRS->fd_ref) {
-                       FDCS->rawcmd = 2;
+               } else if (drive_state[drive].fd_ref) {
+                       fdc_state[current_fdc].rawcmd = 2;
                        break;
                }
        }
 
-       if (FDCS->reset)
+       if (fdc_state[current_fdc].reset)
                return -EIO;
 
        ret = raw_cmd_copyin(cmd, param, &my_raw_cmd);
@@ -3204,12 +3244,13 @@ static int raw_cmd_ioctl(int cmd, void __user *param)
        raw_cmd = my_raw_cmd;
        cont = &raw_cmd_cont;
        ret = wait_til_done(floppy_start, true);
-       debug_dcl(DP->flags, "calling disk change from raw_cmd ioctl\n");
+       debug_dcl(drive_params[current_drive].flags,
+                 "calling disk change from raw_cmd ioctl\n");
 
-       if (ret != -EINTR && FDCS->reset)
+       if (ret != -EINTR && fdc_state[current_fdc].reset)
                ret = -EIO;
 
-       DRS->track = NO_TRACK;
+       drive_state[current_drive].track = NO_TRACK;
 
        ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd);
        if (!ret)
@@ -3237,9 +3278,9 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
            (int)g->head <= 0 ||
            /* check for overflow in max_sector */
            (int)(g->sect * g->head) <= 0 ||
-           /* check for zero in F_SECT_PER_TRACK */
+           /* check for zero in raw_cmd->cmd[F_SECT_PER_TRACK] */
            (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 ||
-           g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) ||
+           g->track <= 0 || g->track > drive_params[drive].tracks >> STRETCH(g) ||
            /* check if reserved bits are set */
            (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0)
                return -EINVAL;
@@ -3282,16 +3323,16 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
                current_type[drive] = &user_params[drive];
                floppy_sizes[drive] = user_params[drive].size;
                if (cmd == FDDEFPRM)
-                       DRS->keep_data = -1;
+                       drive_state[current_drive].keep_data = -1;
                else
-                       DRS->keep_data = 1;
+                       drive_state[current_drive].keep_data = 1;
                /* invalidation. Invalidate only when needed, i.e.
                 * when there are already sectors in the buffer cache
                 * whose number will change. This is useful, because
                 * mtools often changes the geometry of the disk after
                 * looking at the boot block */
-               if (DRS->maxblock > user_params[drive].sect ||
-                   DRS->maxtrack ||
+               if (drive_state[current_drive].maxblock > user_params[drive].sect ||
+                   drive_state[current_drive].maxtrack ||
                    ((user_params[drive].sect ^ oldStretch) &
                     (FD_SWAPSIDES | FD_SECTBASEMASK)))
                        invalidate_drive(bdev);
@@ -3404,7 +3445,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                    unsigned long param)
 {
        int drive = (long)bdev->bd_disk->private_data;
-       int type = ITYPE(UDRS->fd_device);
+       int type = ITYPE(drive_state[drive].fd_device);
        int i;
        int ret;
        int size;
@@ -3452,7 +3493,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
 
        switch (cmd) {
        case FDEJECT:
-               if (UDRS->fd_ref != 1)
+               if (drive_state[drive].fd_ref != 1)
                        /* somebody else has this drive open */
                        return -EBUSY;
                if (lock_fdc(drive))
@@ -3462,8 +3503,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                 * non-Sparc architectures */
                ret = fd_eject(UNIT(drive));
 
-               set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
-               set_bit(FD_VERIFY_BIT, &UDRS->flags);
+               set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
+               set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
                process_fd_request();
                return ret;
        case FDCLRPRM:
@@ -3471,7 +3512,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                        return -EINTR;
                current_type[drive] = NULL;
                floppy_sizes[drive] = MAX_DISK_SIZE << 1;
-               UDRS->keep_data = 0;
+               drive_state[drive].keep_data = 0;
                return invalidate_drive(bdev);
        case FDSETPRM:
        case FDDEFPRM:
@@ -3486,17 +3527,17 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                outparam = &inparam.g;
                break;
        case FDMSGON:
-               UDP->flags |= FTD_MSG;
+               drive_params[drive].flags |= FTD_MSG;
                return 0;
        case FDMSGOFF:
-               UDP->flags &= ~FTD_MSG;
+               drive_params[drive].flags &= ~FTD_MSG;
                return 0;
        case FDFMTBEG:
                if (lock_fdc(drive))
                        return -EINTR;
                if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR)
                        return -EINTR;
-               ret = UDRS->flags;
+               ret = drive_state[drive].flags;
                process_fd_request();
                if (ret & FD_VERIFY)
                        return -ENODEV;
@@ -3504,7 +3545,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                        return -EROFS;
                return 0;
        case FDFMTTRK:
-               if (UDRS->fd_ref != 1)
+               if (drive_state[drive].fd_ref != 1)
                        return -EBUSY;
                return do_format(drive, &inparam.f);
        case FDFMTEND:
@@ -3513,13 +3554,13 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                        return -EINTR;
                return invalidate_drive(bdev);
        case FDSETEMSGTRESH:
-               UDP->max_errors.reporting = (unsigned short)(param & 0x0f);
+               drive_params[drive].max_errors.reporting = (unsigned short)(param & 0x0f);
                return 0;
        case FDGETMAXERRS:
-               outparam = &UDP->max_errors;
+               outparam = &drive_params[drive].max_errors;
                break;
        case FDSETMAXERRS:
-               UDP->max_errors = inparam.max_errors;
+               drive_params[drive].max_errors = inparam.max_errors;
                break;
        case FDGETDRVTYP:
                outparam = drive_name(type, drive);
@@ -3529,10 +3570,10 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                if (!valid_floppy_drive_params(inparam.dp.autodetect,
                                inparam.dp.native_format))
                        return -EINVAL;
-               *UDP = inparam.dp;
+               drive_params[drive] = inparam.dp;
                break;
        case FDGETDRVPRM:
-               outparam = UDP;
+               outparam = &drive_params[drive];
                break;
        case FDPOLLDRVSTAT:
                if (lock_fdc(drive))
@@ -3542,18 +3583,18 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
                process_fd_request();
                /* fall through */
        case FDGETDRVSTAT:
-               outparam = UDRS;
+               outparam = &drive_state[drive];
                break;
        case FDRESET:
                return user_reset_fdc(drive, (int)param, true);
        case FDGETFDCSTAT:
-               outparam = UFDCS;
+               outparam = &fdc_state[FDC(drive)];
                break;
        case FDWERRORCLR:
-               memset(UDRWE, 0, sizeof(*UDRWE));
+               memset(&write_errors[drive], 0, sizeof(write_errors[drive]));
                return 0;
        case FDWERRORGET:
-               outparam = UDRWE;
+               outparam = &write_errors[drive];
                break;
        case FDRAWCMD:
                if (type)
@@ -3689,7 +3730,7 @@ static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned
 
        mutex_lock(&floppy_mutex);
        drive = (long)bdev->bd_disk->private_data;
-       type = ITYPE(UDRS->fd_device);
+       type = ITYPE(drive_state[drive].fd_device);
        err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM,
                        &v, drive, type, bdev);
        mutex_unlock(&floppy_mutex);
@@ -3705,7 +3746,8 @@ static int compat_get_prm(int drive,
 
        memset(&v, 0, sizeof(v));
        mutex_lock(&floppy_mutex);
-       err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p);
+       err = get_floppy_geometry(drive, ITYPE(drive_state[drive].fd_device),
+                                 &p);
        if (err) {
                mutex_unlock(&floppy_mutex);
                return err;
@@ -3729,25 +3771,26 @@ static int compat_setdrvprm(int drive,
        if (!valid_floppy_drive_params(v.autodetect, v.native_format))
                return -EINVAL;
        mutex_lock(&floppy_mutex);
-       UDP->cmos = v.cmos;
-       UDP->max_dtr = v.max_dtr;
-       UDP->hlt = v.hlt;
-       UDP->hut = v.hut;
-       UDP->srt = v.srt;
-       UDP->spinup = v.spinup;
-       UDP->spindown = v.spindown;
-       UDP->spindown_offset = v.spindown_offset;
-       UDP->select_delay = v.select_delay;
-       UDP->rps = v.rps;
-       UDP->tracks = v.tracks;
-       UDP->timeout = v.timeout;
-       UDP->interleave_sect = v.interleave_sect;
-       UDP->max_errors = v.max_errors;
-       UDP->flags = v.flags;
-       UDP->read_track = v.read_track;
-       memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect));
-       UDP->checkfreq = v.checkfreq;
-       UDP->native_format = v.native_format;
+       drive_params[drive].cmos = v.cmos;
+       drive_params[drive].max_dtr = v.max_dtr;
+       drive_params[drive].hlt = v.hlt;
+       drive_params[drive].hut = v.hut;
+       drive_params[drive].srt = v.srt;
+       drive_params[drive].spinup = v.spinup;
+       drive_params[drive].spindown = v.spindown;
+       drive_params[drive].spindown_offset = v.spindown_offset;
+       drive_params[drive].select_delay = v.select_delay;
+       drive_params[drive].rps = v.rps;
+       drive_params[drive].tracks = v.tracks;
+       drive_params[drive].timeout = v.timeout;
+       drive_params[drive].interleave_sect = v.interleave_sect;
+       drive_params[drive].max_errors = v.max_errors;
+       drive_params[drive].flags = v.flags;
+       drive_params[drive].read_track = v.read_track;
+       memcpy(drive_params[drive].autodetect, v.autodetect,
+              sizeof(v.autodetect));
+       drive_params[drive].checkfreq = v.checkfreq;
+       drive_params[drive].native_format = v.native_format;
        mutex_unlock(&floppy_mutex);
        return 0;
 }
@@ -3759,25 +3802,26 @@ static int compat_getdrvprm(int drive,
 
        memset(&v, 0, sizeof(struct compat_floppy_drive_params));
        mutex_lock(&floppy_mutex);
-       v.cmos = UDP->cmos;
-       v.max_dtr = UDP->max_dtr;
-       v.hlt = UDP->hlt;
-       v.hut = UDP->hut;
-       v.srt = UDP->srt;
-       v.spinup = UDP->spinup;
-       v.spindown = UDP->spindown;
-       v.spindown_offset = UDP->spindown_offset;
-       v.select_delay = UDP->select_delay;
-       v.rps = UDP->rps;
-       v.tracks = UDP->tracks;
-       v.timeout = UDP->timeout;
-       v.interleave_sect = UDP->interleave_sect;
-       v.max_errors = UDP->max_errors;
-       v.flags = UDP->flags;
-       v.read_track = UDP->read_track;
-       memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect));
-       v.checkfreq = UDP->checkfreq;
-       v.native_format = UDP->native_format;
+       v.cmos = drive_params[drive].cmos;
+       v.max_dtr = drive_params[drive].max_dtr;
+       v.hlt = drive_params[drive].hlt;
+       v.hut = drive_params[drive].hut;
+       v.srt = drive_params[drive].srt;
+       v.spinup = drive_params[drive].spinup;
+       v.spindown = drive_params[drive].spindown;
+       v.spindown_offset = drive_params[drive].spindown_offset;
+       v.select_delay = drive_params[drive].select_delay;
+       v.rps = drive_params[drive].rps;
+       v.tracks = drive_params[drive].tracks;
+       v.timeout = drive_params[drive].timeout;
+       v.interleave_sect = drive_params[drive].interleave_sect;
+       v.max_errors = drive_params[drive].max_errors;
+       v.flags = drive_params[drive].flags;
+       v.read_track = drive_params[drive].read_track;
+       memcpy(v.autodetect, drive_params[drive].autodetect,
+              sizeof(v.autodetect));
+       v.checkfreq = drive_params[drive].checkfreq;
+       v.native_format = drive_params[drive].native_format;
        mutex_unlock(&floppy_mutex);
 
        if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_params)))
@@ -3800,20 +3844,20 @@ static int compat_getdrvstat(int drive, bool poll,
                        goto Eintr;
                process_fd_request();
        }
-       v.spinup_date = UDRS->spinup_date;
-       v.select_date = UDRS->select_date;
-       v.first_read_date = UDRS->first_read_date;
-       v.probed_format = UDRS->probed_format;
-       v.track = UDRS->track;
-       v.maxblock = UDRS->maxblock;
-       v.maxtrack = UDRS->maxtrack;
-       v.generation = UDRS->generation;
-       v.keep_data = UDRS->keep_data;
-       v.fd_ref = UDRS->fd_ref;
-       v.fd_device = UDRS->fd_device;
-       v.last_checked = UDRS->last_checked;
-       v.dmabuf = (uintptr_t)UDRS->dmabuf;
-       v.bufblocks = UDRS->bufblocks;
+       v.spinup_date = drive_state[drive].spinup_date;
+       v.select_date = drive_state[drive].select_date;
+       v.first_read_date = drive_state[drive].first_read_date;
+       v.probed_format = drive_state[drive].probed_format;
+       v.track = drive_state[drive].track;
+       v.maxblock = drive_state[drive].maxblock;
+       v.maxtrack = drive_state[drive].maxtrack;
+       v.generation = drive_state[drive].generation;
+       v.keep_data = drive_state[drive].keep_data;
+       v.fd_ref = drive_state[drive].fd_ref;
+       v.fd_device = drive_state[drive].fd_device;
+       v.last_checked = drive_state[drive].last_checked;
+       v.dmabuf = (uintptr_t) drive_state[drive].dmabuf;
+       v.bufblocks = drive_state[drive].bufblocks;
        mutex_unlock(&floppy_mutex);
 
        if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_struct)))
@@ -3831,7 +3875,7 @@ static int compat_getfdcstat(int drive,
        struct floppy_fdc_state v;
 
        mutex_lock(&floppy_mutex);
-       v = *UFDCS;
+       v = fdc_state[FDC(drive)];
        mutex_unlock(&floppy_mutex);
 
        memset(&v32, 0, sizeof(struct compat_floppy_fdc_state));
@@ -3861,7 +3905,7 @@ static int compat_werrorget(int drive,
 
        memset(&v32, 0, sizeof(struct compat_floppy_write_errors));
        mutex_lock(&floppy_mutex);
-       v = *UDRWE;
+       v = write_errors[drive];
        mutex_unlock(&floppy_mutex);
        v32.write_errors = v.write_errors;
        v32.first_error_sector = v.first_error_sector;
@@ -3930,16 +3974,16 @@ static void __init config_types(void)
 
        /* read drive info out of physical CMOS */
        drive = 0;
-       if (!UDP->cmos)
-               UDP->cmos = FLOPPY0_TYPE;
+       if (!drive_params[drive].cmos)
+               drive_params[drive].cmos = FLOPPY0_TYPE;
        drive = 1;
-       if (!UDP->cmos)
-               UDP->cmos = FLOPPY1_TYPE;
+       if (!drive_params[drive].cmos)
+               drive_params[drive].cmos = FLOPPY1_TYPE;
 
        /* FIXME: additional physical CMOS drive detection should go here */
 
        for (drive = 0; drive < N_DRIVE; drive++) {
-               unsigned int type = UDP->cmos;
+               unsigned int type = drive_params[drive].cmos;
                struct floppy_drive_params *params;
                const char *name = NULL;
                char temparea[32];
@@ -3969,7 +4013,7 @@ static void __init config_types(void)
 
                        pr_cont("%s fd%d is %s", prepend, drive, name);
                }
-               *UDP = *params;
+               drive_params[drive] = *params;
        }
 
        if (has_drive)
@@ -3982,11 +4026,11 @@ static void floppy_release(struct gendisk *disk, fmode_t mode)
 
        mutex_lock(&floppy_mutex);
        mutex_lock(&open_lock);
-       if (!UDRS->fd_ref--) {
+       if (!drive_state[drive].fd_ref--) {
                DPRINT("floppy_release with fd_ref == 0");
-               UDRS->fd_ref = 0;
+               drive_state[drive].fd_ref = 0;
        }
-       if (!UDRS->fd_ref)
+       if (!drive_state[drive].fd_ref)
                opened_bdev[drive] = NULL;
        mutex_unlock(&open_lock);
        mutex_unlock(&floppy_mutex);
@@ -4007,16 +4051,16 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
 
        mutex_lock(&floppy_mutex);
        mutex_lock(&open_lock);
-       old_dev = UDRS->fd_device;
+       old_dev = drive_state[drive].fd_device;
        if (opened_bdev[drive] && opened_bdev[drive] != bdev)
                goto out2;
 
-       if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)) {
-               set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
-               set_bit(FD_VERIFY_BIT, &UDRS->flags);
+       if (!drive_state[drive].fd_ref && (drive_params[drive].flags & FD_BROKEN_DCL)) {
+               set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
+               set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
        }
 
-       UDRS->fd_ref++;
+       drive_state[drive].fd_ref++;
 
        opened_bdev[drive] = bdev;
 
@@ -4025,7 +4069,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
        if (!floppy_track_buffer) {
                /* if opening an ED drive, reserve a big buffer,
                 * else reserve a small one */
-               if ((UDP->cmos == 6) || (UDP->cmos == 5))
+               if ((drive_params[drive].cmos == 6) || (drive_params[drive].cmos == 5))
                        try = 64;       /* Only 48 actually useful */
                else
                        try = 32;       /* Only 24 actually useful */
@@ -4053,38 +4097,39 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
        }
 
        new_dev = MINOR(bdev->bd_dev);
-       UDRS->fd_device = new_dev;
+       drive_state[drive].fd_device = new_dev;
        set_capacity(disks[drive], floppy_sizes[new_dev]);
        if (old_dev != -1 && old_dev != new_dev) {
                if (buffer_drive == drive)
                        buffer_track = -1;
        }
 
-       if (UFDCS->rawcmd == 1)
-               UFDCS->rawcmd = 2;
+       if (fdc_state[FDC(drive)].rawcmd == 1)
+               fdc_state[FDC(drive)].rawcmd = 2;
 
        if (!(mode & FMODE_NDELAY)) {
                if (mode & (FMODE_READ|FMODE_WRITE)) {
-                       UDRS->last_checked = 0;
-                       clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
+                       drive_state[drive].last_checked = 0;
+                       clear_bit(FD_OPEN_SHOULD_FAIL_BIT,
+                                 &drive_state[drive].flags);
                        check_disk_change(bdev);
-                       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
+                       if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags))
                                goto out;
-                       if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
+                       if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &drive_state[drive].flags))
                                goto out;
                }
                res = -EROFS;
                if ((mode & FMODE_WRITE) &&
-                   !test_bit(FD_DISK_WRITABLE_BIT, &UDRS->flags))
+                   !test_bit(FD_DISK_WRITABLE_BIT, &drive_state[drive].flags))
                        goto out;
        }
        mutex_unlock(&open_lock);
        mutex_unlock(&floppy_mutex);
        return 0;
 out:
-       UDRS->fd_ref--;
+       drive_state[drive].fd_ref--;
 
-       if (!UDRS->fd_ref)
+       if (!drive_state[drive].fd_ref)
                opened_bdev[drive] = NULL;
 out2:
        mutex_unlock(&open_lock);
@@ -4100,19 +4145,19 @@ static unsigned int floppy_check_events(struct gendisk *disk,
 {
        int drive = (long)disk->private_data;
 
-       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
-           test_bit(FD_VERIFY_BIT, &UDRS->flags))
+       if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
+           test_bit(FD_VERIFY_BIT, &drive_state[drive].flags))
                return DISK_EVENT_MEDIA_CHANGE;
 
-       if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
+       if (time_after(jiffies, drive_state[drive].last_checked + drive_params[drive].checkfreq)) {
                if (lock_fdc(drive))
                        return 0;
                poll_drive(false, 0);
                process_fd_request();
        }
 
-       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
-           test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
+       if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
+           test_bit(FD_VERIFY_BIT, &drive_state[drive].flags) ||
            test_bit(drive, &fake_change) ||
            drive_no_geom(drive))
                return DISK_EVENT_MEDIA_CHANGE;
@@ -4138,7 +4183,7 @@ static void floppy_rb0_cb(struct bio *bio)
        if (bio->bi_status) {
                pr_info("floppy: error %d while reading block 0\n",
                        bio->bi_status);
-               set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
+               set_bit(FD_OPEN_SHOULD_FAIL_BIT, &drive_state[drive].flags);
        }
        complete(&cbdata->complete);
 }
@@ -4195,8 +4240,8 @@ static int floppy_revalidate(struct gendisk *disk)
        int cf;
        int res = 0;
 
-       if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
-           test_bit(FD_VERIFY_BIT, &UDRS->flags) ||
+       if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
+           test_bit(FD_VERIFY_BIT, &drive_state[drive].flags) ||
            test_bit(drive, &fake_change) ||
            drive_no_geom(drive)) {
                if (WARN(atomic_read(&usage_count) == 0,
@@ -4206,20 +4251,20 @@ static int floppy_revalidate(struct gendisk *disk)
                res = lock_fdc(drive);
                if (res)
                        return res;
-               cf = (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) ||
-                     test_bit(FD_VERIFY_BIT, &UDRS->flags));
+               cf = (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags) ||
+                     test_bit(FD_VERIFY_BIT, &drive_state[drive].flags));
                if (!(cf || test_bit(drive, &fake_change) || drive_no_geom(drive))) {
                        process_fd_request();   /*already done by another thread */
                        return 0;
                }
-               UDRS->maxblock = 0;
-               UDRS->maxtrack = 0;
+               drive_state[drive].maxblock = 0;
+               drive_state[drive].maxtrack = 0;
                if (buffer_drive == drive)
                        buffer_track = -1;
                clear_bit(drive, &fake_change);
-               clear_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
+               clear_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
                if (cf)
-                       UDRS->generation++;
+                       drive_state[drive].generation++;
                if (drive_no_geom(drive)) {
                        /* auto-sensing */
                        res = __floppy_read_block_0(opened_bdev[drive], drive);
@@ -4229,7 +4274,7 @@ static int floppy_revalidate(struct gendisk *disk)
                        process_fd_request();
                }
        }
-       set_capacity(disk, floppy_sizes[UDRS->fd_device]);
+       set_capacity(disk, floppy_sizes[drive_state[drive].fd_device]);
        return res;
 }
 
@@ -4258,23 +4303,23 @@ static char __init get_fdc_version(void)
        int r;
 
        output_byte(FD_DUMPREGS);       /* 82072 and better know DUMPREGS */
-       if (FDCS->reset)
+       if (fdc_state[current_fdc].reset)
                return FDC_NONE;
        r = result();
        if (r <= 0x00)
                return FDC_NONE;        /* No FDC present ??? */
        if ((r == 1) && (reply_buffer[0] == 0x80)) {
-               pr_info("FDC %d is an 8272A\n", fdc);
+               pr_info("FDC %d is an 8272A\n", current_fdc);
                return FDC_8272A;       /* 8272a/765 don't know DUMPREGS */
        }
        if (r != 10) {
                pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
-                       fdc, r);
+                       current_fdc, r);
                return FDC_UNKNOWN;
        }
 
        if (!fdc_configure()) {
-               pr_info("FDC %d is an 82072\n", fdc);
+               pr_info("FDC %d is an 82072\n", current_fdc);
                return FDC_82072;       /* 82072 doesn't know CONFIGURE */
        }
 
@@ -4282,50 +4327,50 @@ static char __init get_fdc_version(void)
        if (need_more_output() == MORE_OUTPUT) {
                output_byte(0);
        } else {
-               pr_info("FDC %d is an 82072A\n", fdc);
+               pr_info("FDC %d is an 82072A\n", current_fdc);
                return FDC_82072A;      /* 82072A as found on Sparcs. */
        }
 
        output_byte(FD_UNLOCK);
        r = result();
        if ((r == 1) && (reply_buffer[0] == 0x80)) {
-               pr_info("FDC %d is a pre-1991 82077\n", fdc);
+               pr_info("FDC %d is a pre-1991 82077\n", current_fdc);
                return FDC_82077_ORIG;  /* Pre-1991 82077, doesn't know
                                         * LOCK/UNLOCK */
        }
        if ((r != 1) || (reply_buffer[0] != 0x00)) {
                pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
-                       fdc, r);
+                       current_fdc, r);
                return FDC_UNKNOWN;
        }
        output_byte(FD_PARTID);
        r = result();
        if (r != 1) {
                pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
-                       fdc, r);
+                       current_fdc, r);
                return FDC_UNKNOWN;
        }
        if (reply_buffer[0] == 0x80) {
-               pr_info("FDC %d is a post-1991 82077\n", fdc);
+               pr_info("FDC %d is a post-1991 82077\n", current_fdc);
                return FDC_82077;       /* Revised 82077AA passes all the tests */
        }
        switch (reply_buffer[0] >> 5) {
        case 0x0:
                /* Either a 82078-1 or a 82078SL running at 5Volt */
-               pr_info("FDC %d is an 82078.\n", fdc);
+               pr_info("FDC %d is an 82078.\n", current_fdc);
                return FDC_82078;
        case 0x1:
-               pr_info("FDC %d is a 44pin 82078\n", fdc);
+               pr_info("FDC %d is a 44pin 82078\n", current_fdc);
                return FDC_82078;
        case 0x2:
-               pr_info("FDC %d is a S82078B\n", fdc);
+               pr_info("FDC %d is a S82078B\n", current_fdc);
                return FDC_S82078B;
        case 0x3:
-               pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
+               pr_info("FDC %d is a National Semiconductor PC87306\n", current_fdc);
                return FDC_87306;
        default:
                pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
-                       fdc, reply_buffer[0] >> 5);
+                       current_fdc, reply_buffer[0] >> 5);
                return FDC_82078_UNKN;
        }
 }                              /* get_fdc_version */
@@ -4381,7 +4426,7 @@ static void __init set_cmos(int *ints, int dummy, int dummy2)
        if (current_drive >= 4 && !FDC2)
                FDC2 = 0x370;
 #endif
-       DP->cmos = ints[2];
+       drive_params[current_drive].cmos = ints[2];
        DPRINT("setting CMOS code to %d\n", ints[2]);
 }
 
@@ -4470,7 +4515,7 @@ static ssize_t floppy_cmos_show(struct device *dev,
        int drive;
 
        drive = p->id;
-       return sprintf(buf, "%X\n", UDP->cmos);
+       return sprintf(buf, "%X\n", drive_params[drive].cmos);
 }
 
 static DEVICE_ATTR(cmos, 0444, floppy_cmos_show, NULL);
@@ -4491,7 +4536,7 @@ static int floppy_resume(struct device *dev)
        int fdc;
 
        for (fdc = 0; fdc < N_FDC; fdc++)
-               if (FDCS->address != -1)
+               if (fdc_state[fdc].address != -1)
                        user_reset_fdc(-1, FD_RESET_ALWAYS, false);
 
        return 0;
@@ -4601,16 +4646,16 @@ static int __init do_floppy_init(void)
        config_types();
 
        for (i = 0; i < N_FDC; i++) {
-               fdc = i;
-               memset(FDCS, 0, sizeof(*FDCS));
-               FDCS->dtr = -1;
-               FDCS->dor = 0x4;
+               current_fdc = i;
+               memset(&fdc_state[current_fdc], 0, sizeof(*fdc_state));
+               fdc_state[current_fdc].dtr = -1;
+               fdc_state[current_fdc].dor = 0x4;
 #if defined(__sparc__) || defined(__mc68000__)
        /*sparcs/sun3x don't have a DOR reset which we can fall back on to */
 #ifdef __mc68000__
                if (MACH_IS_SUN3X)
 #endif
-                       FDCS->version = FDC_82072A;
+                       fdc_state[current_fdc].version = FDC_82072A;
 #endif
        }
 
@@ -4625,7 +4670,7 @@ static int __init do_floppy_init(void)
        fdc_state[1].address = FDC2;
 #endif
 
-       fdc = 0;                /* reset fdc in case of unexpected interrupt */
+       current_fdc = 0;        /* reset fdc in case of unexpected interrupt */
        err = floppy_grab_irq_and_dma();
        if (err) {
                cancel_delayed_work(&fd_timeout);
@@ -4635,12 +4680,12 @@ static int __init do_floppy_init(void)
 
        /* initialise drive state */
        for (drive = 0; drive < N_DRIVE; drive++) {
-               memset(UDRS, 0, sizeof(*UDRS));
-               memset(UDRWE, 0, sizeof(*UDRWE));
-               set_bit(FD_DISK_NEWCHANGE_BIT, &UDRS->flags);
-               set_bit(FD_DISK_CHANGED_BIT, &UDRS->flags);
-               set_bit(FD_VERIFY_BIT, &UDRS->flags);
-               UDRS->fd_device = -1;
+               memset(&drive_state[drive], 0, sizeof(drive_state[drive]));
+               memset(&write_errors[drive], 0, sizeof(write_errors[drive]));
+               set_bit(FD_DISK_NEWCHANGE_BIT, &drive_state[drive].flags);
+               set_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags);
+               set_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
+               drive_state[drive].fd_device = -1;
                floppy_track_buffer = NULL;
                max_buffer_sectors = 0;
        }
@@ -4652,29 +4697,30 @@ static int __init do_floppy_init(void)
        msleep(10);
 
        for (i = 0; i < N_FDC; i++) {
-               fdc = i;
-               FDCS->driver_version = FD_DRIVER_VERSION;
+               current_fdc = i;
+               fdc_state[current_fdc].driver_version = FD_DRIVER_VERSION;
                for (unit = 0; unit < 4; unit++)
-                       FDCS->track[unit] = 0;
-               if (FDCS->address == -1)
+                       fdc_state[current_fdc].track[unit] = 0;
+               if (fdc_state[current_fdc].address == -1)
                        continue;
-               FDCS->rawcmd = 2;
+               fdc_state[current_fdc].rawcmd = 2;
                if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
                        /* free ioports reserved by floppy_grab_irq_and_dma() */
-                       floppy_release_regions(fdc);
-                       FDCS->address = -1;
-                       FDCS->version = FDC_NONE;
+                       floppy_release_regions(current_fdc);
+                       fdc_state[current_fdc].address = -1;
+                       fdc_state[current_fdc].version = FDC_NONE;
                        continue;
                }
                /* Try to determine the floppy controller type */
-               FDCS->version = get_fdc_version();
-               if (FDCS->version == FDC_NONE) {
+               fdc_state[current_fdc].version = get_fdc_version();
+               if (fdc_state[current_fdc].version == FDC_NONE) {
                        /* free ioports reserved by floppy_grab_irq_and_dma() */
-                       floppy_release_regions(fdc);
-                       FDCS->address = -1;
+                       floppy_release_regions(current_fdc);
+                       fdc_state[current_fdc].address = -1;
                        continue;
                }
-               if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A)
+               if (can_use_virtual_dma == 2 &&
+                   fdc_state[current_fdc].version < FDC_82072A)
                        can_use_virtual_dma = 0;
 
                have_no_fdc = 0;
@@ -4684,7 +4730,7 @@ static int __init do_floppy_init(void)
                 */
                user_reset_fdc(-1, FD_RESET_ALWAYS, false);
        }
-       fdc = 0;
+       current_fdc = 0;
        cancel_delayed_work(&fd_timeout);
        current_drive = 0;
        initialized = true;
@@ -4780,7 +4826,7 @@ static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
 {
        while (p != io_regions) {
                p--;
-               release_region(FDCS->address + p->offset, p->size);
+               release_region(fdc_state[fdc].address + p->offset, p->size);
        }
 }
 
@@ -4791,10 +4837,10 @@ static int floppy_request_regions(int fdc)
        const struct io_region *p;
 
        for (p = io_regions; p < ARRAY_END(io_regions); p++) {
-               if (!request_region(FDCS->address + p->offset,
+               if (!request_region(fdc_state[fdc].address + p->offset,
                                    p->size, "floppy")) {
                        DPRINT("Floppy io-port 0x%04lx in use\n",
-                              FDCS->address + p->offset);
+                              fdc_state[fdc].address + p->offset);
                        floppy_release_allocated_regions(fdc, p);
                        return -EBUSY;
                }
@@ -4836,36 +4882,36 @@ static int floppy_grab_irq_and_dma(void)
                }
        }
 
-       for (fdc = 0; fdc < N_FDC; fdc++) {
-               if (FDCS->address != -1) {
-                       if (floppy_request_regions(fdc))
+       for (current_fdc = 0; current_fdc < N_FDC; current_fdc++) {
+               if (fdc_state[current_fdc].address != -1) {
+                       if (floppy_request_regions(current_fdc))
                                goto cleanup;
                }
        }
-       for (fdc = 0; fdc < N_FDC; fdc++) {
-               if (FDCS->address != -1) {
+       for (current_fdc = 0; current_fdc < N_FDC; current_fdc++) {
+               if (fdc_state[current_fdc].address != -1) {
                        reset_fdc_info(1);
-                       fd_outb(FDCS->dor, FD_DOR);
+                       fdc_outb(fdc_state[current_fdc].dor, current_fdc, FD_DOR);
                }
        }
-       fdc = 0;
+       current_fdc = 0;
        set_dor(0, ~0, 8);      /* avoid immediate interrupt */
 
-       for (fdc = 0; fdc < N_FDC; fdc++)
-               if (FDCS->address != -1)
-                       fd_outb(FDCS->dor, FD_DOR);
+       for (current_fdc = 0; current_fdc < N_FDC; current_fdc++)
+               if (fdc_state[current_fdc].address != -1)
+                       fdc_outb(fdc_state[current_fdc].dor, current_fdc, FD_DOR);
        /*
         * The driver will try and free resources and relies on us
         * to know if they were allocated or not.
         */
-       fdc = 0;
+       current_fdc = 0;
        irqdma_allocated = 1;
        return 0;
 cleanup:
        fd_free_irq();
        fd_free_dma();
-       while (--fdc >= 0)
-               floppy_release_regions(fdc);
+       while (--current_fdc >= 0)
+               floppy_release_regions(current_fdc);
        atomic_dec(&usage_count);
        return -1;
 }
@@ -4913,11 +4959,11 @@ static void floppy_release_irq_and_dma(void)
                pr_info("auxiliary floppy timer still active\n");
        if (work_pending(&floppy_work))
                pr_info("work still pending\n");
-       old_fdc = fdc;
-       for (fdc = 0; fdc < N_FDC; fdc++)
-               if (FDCS->address != -1)
-                       floppy_release_regions(fdc);
-       fdc = old_fdc;
+       old_fdc = current_fdc;
+       for (current_fdc = 0; current_fdc < N_FDC; current_fdc++)
+               if (fdc_state[current_fdc].address != -1)
+                       floppy_release_regions(current_fdc);
+       current_fdc = old_fdc;
 }
 
 #ifdef MODULE
index 739b372..a42c49e 100644 (file)
@@ -214,7 +214,8 @@ static void __loop_update_dio(struct loop_device *lo, bool dio)
         * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup
         * will get updated by ioctl(LOOP_GET_STATUS)
         */
-       blk_mq_freeze_queue(lo->lo_queue);
+       if (lo->lo_state == Lo_bound)
+               blk_mq_freeze_queue(lo->lo_queue);
        lo->use_dio = use_dio;
        if (use_dio) {
                blk_queue_flag_clear(QUEUE_FLAG_NOMERGES, lo->lo_queue);
@@ -223,7 +224,8 @@ static void __loop_update_dio(struct loop_device *lo, bool dio)
                blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue);
                lo->lo_flags &= ~LO_FLAGS_DIRECT_IO;
        }
-       blk_mq_unfreeze_queue(lo->lo_queue);
+       if (lo->lo_state == Lo_bound)
+               blk_mq_unfreeze_queue(lo->lo_queue);
 }
 
 static int
@@ -1539,16 +1541,16 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
        if (arg < 512 || arg > PAGE_SIZE || !is_power_of_2(arg))
                return -EINVAL;
 
-       if (lo->lo_queue->limits.logical_block_size != arg) {
-               sync_blockdev(lo->lo_device);
-               kill_bdev(lo->lo_device);
-       }
+       if (lo->lo_queue->limits.logical_block_size == arg)
+               return 0;
+
+       sync_blockdev(lo->lo_device);
+       kill_bdev(lo->lo_device);
 
        blk_mq_freeze_queue(lo->lo_queue);
 
        /* kill_bdev should have truncated all the pages */
-       if (lo->lo_queue->limits.logical_block_size != arg &&
-                       lo->lo_device->bd_inode->i_mapping->nrpages) {
+       if (lo->lo_device->bd_inode->i_mapping->nrpages) {
                err = -EAGAIN;
                pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n",
                        __func__, lo->lo_number, lo->lo_file_name,
index 7818190..43cff01 100644 (file)
@@ -395,16 +395,19 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req,
        }
        config = nbd->config;
 
-       if (config->num_connections > 1) {
+       if (config->num_connections > 1 ||
+           (config->num_connections == 1 && nbd->tag_set.timeout)) {
                dev_err_ratelimited(nbd_to_dev(nbd),
                                    "Connection timed out, retrying (%d/%d alive)\n",
                                    atomic_read(&config->live_connections),
                                    config->num_connections);
                /*
                 * Hooray we have more connections, requeue this IO, the submit
-                * path will put it on a real connection.
+                * path will put it on a real connection. Or if only one
+                * connection is configured, the submit path will wait util
+                * a new connection is reconfigured or util dead timeout.
                 */
-               if (config->socks && config->num_connections > 1) {
+               if (config->socks) {
                        if (cmd->index < config->num_connections) {
                                struct nbd_sock *nsock =
                                        config->socks[cmd->index];
@@ -431,12 +434,22 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req,
                 * Userspace sets timeout=0 to disable socket disconnection,
                 * so just warn and reset the timer.
                 */
+               struct nbd_sock *nsock = config->socks[cmd->index];
                cmd->retries++;
                dev_info(nbd_to_dev(nbd), "Possible stuck request %p: control (%s@%llu,%uB). Runtime %u seconds\n",
                        req, nbdcmd_to_ascii(req_to_nbd_cmd_type(req)),
                        (unsigned long long)blk_rq_pos(req) << 9,
                        blk_rq_bytes(req), (req->timeout / HZ) * cmd->retries);
 
+               mutex_lock(&nsock->tx_lock);
+               if (cmd->cookie != nsock->cookie) {
+                       nbd_requeue_cmd(cmd);
+                       mutex_unlock(&nsock->tx_lock);
+                       mutex_unlock(&cmd->lock);
+                       nbd_config_put(nbd);
+                       return BLK_EH_DONE;
+               }
+               mutex_unlock(&nsock->tx_lock);
                mutex_unlock(&cmd->lock);
                nbd_config_put(nbd);
                return BLK_EH_RESET_TIMER;
@@ -741,14 +754,12 @@ static struct nbd_cmd *nbd_read_stat(struct nbd_device *nbd, int index)
                                dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
                                        result);
                                /*
-                                * If we've disconnected or we only have 1
-                                * connection then we need to make sure we
+                                * If we've disconnected, we need to make sure we
                                 * complete this request, otherwise error out
                                 * and let the timeout stuff handle resubmitting
                                 * this request onto another connection.
                                 */
-                               if (nbd_disconnected(config) ||
-                                   config->num_connections <= 1) {
+                               if (nbd_disconnected(config)) {
                                        cmd->status = BLK_STS_IOERR;
                                        goto out;
                                }
@@ -825,7 +836,7 @@ static int find_fallback(struct nbd_device *nbd, int index)
 
        if (config->num_connections <= 1) {
                dev_err_ratelimited(disk_to_dev(nbd->disk),
-                                   "Attempted send on invalid socket\n");
+                                   "Dead connection, failed to find a fallback\n");
                return new_index;
        }
 
index bc83786..62b6608 100644 (file)
@@ -14,9 +14,6 @@
 #include <linux/fault-inject.h>
 
 struct nullb_cmd {
-       struct list_head list;
-       struct llist_node ll_list;
-       struct __call_single_data csd;
        struct request *rq;
        struct bio *bio;
        unsigned int tag;
index 1651079..4e1c071 100644 (file)
@@ -23,6 +23,7 @@
 #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
 static DECLARE_FAULT_ATTR(null_timeout_attr);
 static DECLARE_FAULT_ATTR(null_requeue_attr);
+static DECLARE_FAULT_ATTR(null_init_hctx_attr);
 #endif
 
 static inline u64 mb_per_tick(int mbps)
@@ -96,11 +97,21 @@ module_param_named(home_node, g_home_node, int, 0444);
 MODULE_PARM_DESC(home_node, "Home node for the device");
 
 #ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
+/*
+ * For more details about fault injection, please refer to
+ * Documentation/fault-injection/fault-injection.rst.
+ */
 static char g_timeout_str[80];
 module_param_string(timeout, g_timeout_str, sizeof(g_timeout_str), 0444);
+MODULE_PARM_DESC(timeout, "Fault injection. timeout=<interval>,<probability>,<space>,<times>");
 
 static char g_requeue_str[80];
 module_param_string(requeue, g_requeue_str, sizeof(g_requeue_str), 0444);
+MODULE_PARM_DESC(requeue, "Fault injection. requeue=<interval>,<probability>,<space>,<times>");
+
+static char g_init_hctx_str[80];
+module_param_string(init_hctx, g_init_hctx_str, sizeof(g_init_hctx_str), 0444);
+MODULE_PARM_DESC(init_hctx, "Fault injection to fail hctx init. init_hctx=<interval>,<probability>,<space>,<times>");
 #endif
 
 static int g_queue_mode = NULL_Q_MQ;
@@ -276,7 +287,7 @@ nullb_device_##NAME##_store(struct config_item *item, const char *page,     \
 {                                                                      \
        int (*apply_fn)(struct nullb_device *dev, TYPE new_value) = APPLY;\
        struct nullb_device *dev = to_nullb_device(item);               \
-       TYPE uninitialized_var(new_value);                              \
+       TYPE new_value = 0;                                             \
        int ret;                                                        \
                                                                        \
        ret = nullb_device_##TYPE##_attr_store(&new_value, page, count);\
@@ -302,6 +313,12 @@ static int nullb_apply_submit_queues(struct nullb_device *dev,
        if (!nullb)
                return 0;
 
+       /*
+        * Make sure that null_init_hctx() does not access nullb->queues[] past
+        * the end of that array.
+        */
+       if (submit_queues > nr_cpu_ids)
+               return -EINVAL;
        set = nullb->tag_set;
        blk_mq_update_nr_hw_queues(set, submit_queues);
        return set->nr_hw_queues == submit_queues ? 0 : -ENOMEM;
@@ -605,6 +622,7 @@ static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq)
        if (tag != -1U) {
                cmd = &nq->cmds[tag];
                cmd->tag = tag;
+               cmd->error = BLK_STS_OK;
                cmd->nq = nq;
                if (nq->dev->irqmode == NULL_IRQ_TIMER) {
                        hrtimer_init(&cmd->timer, CLOCK_MONOTONIC,
@@ -1385,6 +1403,7 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx,
                cmd->timer.function = null_cmd_timer_expired;
        }
        cmd->rq = bd->rq;
+       cmd->error = BLK_STS_OK;
        cmd->nq = nq;
 
        blk_mq_start_request(bd->rq);
@@ -1408,12 +1427,6 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx,
        return null_handle_cmd(cmd, sector, nr_sectors, req_op(bd->rq));
 }
 
-static const struct blk_mq_ops null_mq_ops = {
-       .queue_rq       = null_queue_rq,
-       .complete       = null_complete_rq,
-       .timeout        = null_timeout_rq,
-};
-
 static void cleanup_queue(struct nullb_queue *nq)
 {
        kfree(nq->tag_map);
@@ -1430,9 +1443,56 @@ static void cleanup_queues(struct nullb *nullb)
        kfree(nullb->queues);
 }
 
+static void null_exit_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx)
+{
+       struct nullb_queue *nq = hctx->driver_data;
+       struct nullb *nullb = nq->dev->nullb;
+
+       nullb->nr_queues--;
+}
+
+static void null_init_queue(struct nullb *nullb, struct nullb_queue *nq)
+{
+       init_waitqueue_head(&nq->wait);
+       nq->queue_depth = nullb->queue_depth;
+       nq->dev = nullb->dev;
+}
+
+static int null_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
+                         unsigned int hctx_idx)
+{
+       struct nullb *nullb = hctx->queue->queuedata;
+       struct nullb_queue *nq;
+
+#ifdef CONFIG_BLK_DEV_NULL_BLK_FAULT_INJECTION
+       if (g_init_hctx_str[0] && should_fail(&null_init_hctx_attr, 1))
+               return -EFAULT;
+#endif
+
+       nq = &nullb->queues[hctx_idx];
+       hctx->driver_data = nq;
+       null_init_queue(nullb, nq);
+       nullb->nr_queues++;
+
+       return 0;
+}
+
+static const struct blk_mq_ops null_mq_ops = {
+       .queue_rq       = null_queue_rq,
+       .complete       = null_complete_rq,
+       .timeout        = null_timeout_rq,
+       .init_hctx      = null_init_hctx,
+       .exit_hctx      = null_exit_hctx,
+};
+
 static void null_del_dev(struct nullb *nullb)
 {
-       struct nullb_device *dev = nullb->dev;
+       struct nullb_device *dev;
+
+       if (!nullb)
+               return;
+
+       dev = nullb->dev;
 
        ida_simple_remove(&nullb_indexes, nullb->index);
 
@@ -1473,33 +1533,6 @@ static const struct block_device_operations null_ops = {
        .report_zones   = null_report_zones,
 };
 
-static void null_init_queue(struct nullb *nullb, struct nullb_queue *nq)
-{
-       BUG_ON(!nullb);
-       BUG_ON(!nq);
-
-       init_waitqueue_head(&nq->wait);
-       nq->queue_depth = nullb->queue_depth;
-       nq->dev = nullb->dev;
-}
-
-static void null_init_queues(struct nullb *nullb)
-{
-       struct request_queue *q = nullb->q;
-       struct blk_mq_hw_ctx *hctx;
-       struct nullb_queue *nq;
-       int i;
-
-       queue_for_each_hw_ctx(q, hctx, i) {
-               if (!hctx->nr_ctx || !hctx->tags)
-                       continue;
-               nq = &nullb->queues[i];
-               hctx->driver_data = nq;
-               null_init_queue(nullb, nq);
-               nullb->nr_queues++;
-       }
-}
-
 static int setup_commands(struct nullb_queue *nq)
 {
        struct nullb_cmd *cmd;
@@ -1518,8 +1551,6 @@ static int setup_commands(struct nullb_queue *nq)
 
        for (i = 0; i < nq->queue_depth; i++) {
                cmd = &nq->cmds[i];
-               INIT_LIST_HEAD(&cmd->list);
-               cmd->ll_list.next = NULL;
                cmd->tag = -1U;
        }
 
@@ -1528,8 +1559,7 @@ static int setup_commands(struct nullb_queue *nq)
 
 static int setup_queues(struct nullb *nullb)
 {
-       nullb->queues = kcalloc(nullb->dev->submit_queues,
-                               sizeof(struct nullb_queue),
+       nullb->queues = kcalloc(nr_cpu_ids, sizeof(struct nullb_queue),
                                GFP_KERNEL);
        if (!nullb->queues)
                return -ENOMEM;
@@ -1671,6 +1701,8 @@ static bool null_setup_fault(void)
                return false;
        if (!__null_setup_fault(&null_requeue_attr, g_requeue_str))
                return false;
+       if (!__null_setup_fault(&null_init_hctx_attr, g_init_hctx_str))
+               return false;
 #endif
        return true;
 }
@@ -1714,19 +1746,17 @@ static int null_add_dev(struct nullb_device *dev)
                        goto out_cleanup_queues;
 
                nullb->tag_set->timeout = 5 * HZ;
-               nullb->q = blk_mq_init_queue(nullb->tag_set);
+               nullb->q = blk_mq_init_queue_data(nullb->tag_set, nullb);
                if (IS_ERR(nullb->q)) {
                        rv = -ENOMEM;
                        goto out_cleanup_tags;
                }
-               null_init_queues(nullb);
        } else if (dev->queue_mode == NULL_Q_BIO) {
-               nullb->q = blk_alloc_queue_node(GFP_KERNEL, dev->home_node);
+               nullb->q = blk_alloc_queue(null_queue_bio, dev->home_node);
                if (!nullb->q) {
                        rv = -ENOMEM;
                        goto out_cleanup_queues;
                }
-               blk_queue_make_request(nullb->q, null_queue_bio);
                rv = init_driver_queues(nullb);
                if (rv)
                        goto out_cleanup_blk_queue;
@@ -1790,6 +1820,7 @@ out_cleanup_queues:
        cleanup_queues(nullb);
 out_free_nullb:
        kfree(nullb);
+       dev->nullb = NULL;
 out:
        return rv;
 }
diff --git a/drivers/block/null_blk_trace.c b/drivers/block/null_blk_trace.c
new file mode 100644 (file)
index 0000000..f246e7b
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * null_blk trace related helpers.
+ *
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+#include "null_blk_trace.h"
+
+/*
+ * Helper to use for all null_blk traces to extract disk name.
+ */
+const char *nullb_trace_disk_name(struct trace_seq *p, char *name)
+{
+       const char *ret = trace_seq_buffer_ptr(p);
+
+       if (name && *name)
+               trace_seq_printf(p, "disk=%s, ", name);
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
diff --git a/drivers/block/null_blk_trace.h b/drivers/block/null_blk_trace.h
new file mode 100644 (file)
index 0000000..4f83032
--- /dev/null
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * null_blk device driver tracepoints.
+ *
+ * Copyright (C) 2020 Western Digital Corporation or its affiliates.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM nullb
+
+#if !defined(_TRACE_NULLB_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_NULLB_H
+
+#include <linux/tracepoint.h>
+#include <linux/trace_seq.h>
+
+#include "null_blk.h"
+
+const char *nullb_trace_disk_name(struct trace_seq *p, char *name);
+
+#define __print_disk_name(name) nullb_trace_disk_name(p, name)
+
+#ifndef TRACE_HEADER_MULTI_READ
+static inline void __assign_disk_name(char *name, struct gendisk *disk)
+{
+       if (disk)
+               memcpy(name, disk->disk_name, DISK_NAME_LEN);
+       else
+               memset(name, 0, DISK_NAME_LEN);
+}
+#endif
+
+TRACE_EVENT(nullb_zone_op,
+           TP_PROTO(struct nullb_cmd *cmd, unsigned int zone_no,
+                    unsigned int zone_cond),
+           TP_ARGS(cmd, zone_no, zone_cond),
+           TP_STRUCT__entry(
+               __array(char, disk, DISK_NAME_LEN)
+               __field(enum req_opf, op)
+               __field(unsigned int, zone_no)
+               __field(unsigned int, zone_cond)
+           ),
+           TP_fast_assign(
+               __entry->op = req_op(cmd->rq);
+               __entry->zone_no = zone_no;
+               __entry->zone_cond = zone_cond;
+               __assign_disk_name(__entry->disk, cmd->rq->rq_disk);
+           ),
+           TP_printk("%s req=%-15s zone_no=%u zone_cond=%-10s",
+                     __print_disk_name(__entry->disk),
+                     blk_op_str(__entry->op),
+                     __entry->zone_no,
+                     blk_zone_cond_str(__entry->zone_cond))
+);
+
+TRACE_EVENT(nullb_report_zones,
+           TP_PROTO(struct nullb *nullb, unsigned int nr_zones),
+           TP_ARGS(nullb, nr_zones),
+           TP_STRUCT__entry(
+               __array(char, disk, DISK_NAME_LEN)
+               __field(unsigned int, nr_zones)
+           ),
+           TP_fast_assign(
+               __entry->nr_zones = nr_zones;
+               __assign_disk_name(__entry->disk, nullb->disk);
+           ),
+           TP_printk("%s nr_zones=%u",
+                     __print_disk_name(__entry->disk), __entry->nr_zones)
+);
+
+#endif /* _TRACE_NULLB_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE null_blk_trace
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index ed34785..673618d 100644 (file)
@@ -2,6 +2,9 @@
 #include <linux/vmalloc.h>
 #include "null_blk.h"
 
+#define CREATE_TRACE_POINTS
+#include "null_blk_trace.h"
+
 /* zone_size in MBs to sectors. */
 #define ZONE_SIZE_SHIFT                11
 
@@ -80,6 +83,8 @@ int null_report_zones(struct gendisk *disk, sector_t sector,
                return 0;
 
        nr_zones = min(nr_zones, dev->nr_zones - first_zone);
+       trace_nullb_report_zones(nullb, nr_zones);
+
        for (i = 0; i < nr_zones; i++) {
                /*
                 * Stacked DM target drivers will remap the zone information by
@@ -148,6 +153,8 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
                /* Invalid zone condition */
                return BLK_STS_IOERR;
        }
+
+       trace_nullb_zone_op(cmd, zno, zone->cond);
        return BLK_STS_OK;
 }
 
@@ -155,7 +162,8 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_opf op,
                                   sector_t sector)
 {
        struct nullb_device *dev = cmd->nq->dev;
-       struct blk_zone *zone = &dev->zones[null_zone_no(dev, sector)];
+       unsigned int zone_no = null_zone_no(dev, sector);
+       struct blk_zone *zone = &dev->zones[zone_no];
        size_t i;
 
        switch (op) {
@@ -203,6 +211,8 @@ static blk_status_t null_zone_mgmt(struct nullb_cmd *cmd, enum req_opf op,
        default:
                return BLK_STS_NOTSUPP;
        }
+
+       trace_nullb_zone_op(cmd, zone_no, zone->cond);
        return BLK_STS_OK;
 }
 
index 117cfc8..cda5cf9 100644 (file)
@@ -276,7 +276,7 @@ static const struct block_device_operations pcd_bdops = {
        .release        = pcd_block_release,
        .ioctl          = pcd_block_ioctl,
 #ifdef CONFIG_COMPAT
-       .ioctl          = blkdev_compat_ptr_ioctl,
+       .compat_ioctl   = blkdev_compat_ptr_ioctl,
 #endif
        .check_events   = pcd_block_check_events,
 };
index 5f970a7..0b944ac 100644 (file)
@@ -2493,7 +2493,6 @@ static void pkt_init_queue(struct pktcdvd_device *pd)
 {
        struct request_queue *q = pd->disk->queue;
 
-       blk_queue_make_request(q, pkt_make_request);
        blk_queue_logical_block_size(q, CD_FRAMESIZE);
        blk_queue_max_hw_sectors(q, PACKET_MAX_SECTORS);
        q->queuedata = pd;
@@ -2679,6 +2678,11 @@ static unsigned int pkt_check_events(struct gendisk *disk,
        return attached_disk->fops->check_events(attached_disk, clearing);
 }
 
+static char *pkt_devnode(struct gendisk *disk, umode_t *mode)
+{
+       return kasprintf(GFP_KERNEL, "pktcdvd/%s", disk->disk_name);
+}
+
 static const struct block_device_operations pktcdvd_ops = {
        .owner =                THIS_MODULE,
        .open =                 pkt_open,
@@ -2686,13 +2690,9 @@ static const struct block_device_operations pktcdvd_ops = {
        .ioctl =                pkt_ioctl,
        .compat_ioctl =         blkdev_compat_ptr_ioctl,
        .check_events =         pkt_check_events,
+       .devnode =              pkt_devnode,
 };
 
-static char *pktcdvd_devnode(struct gendisk *gd, umode_t *mode)
-{
-       return kasprintf(GFP_KERNEL, "pktcdvd/%s", gd->disk_name);
-}
-
 /*
  * Set up mapping from pktcdvd device to CD-ROM device.
  */
@@ -2748,9 +2748,8 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        disk->fops = &pktcdvd_ops;
        disk->flags = GENHD_FL_REMOVABLE;
        strcpy(disk->disk_name, pd->name);
-       disk->devnode = pktcdvd_devnode;
        disk->private_data = pd;
-       disk->queue = blk_alloc_queue(GFP_KERNEL);
+       disk->queue = blk_alloc_queue(pkt_make_request, NUMA_NO_NODE);
        if (!disk->queue)
                goto out_mem2;
 
index 4628e1a..821d4d8 100644 (file)
@@ -737,7 +737,7 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
 
        ps3vram_proc_init(dev);
 
-       queue = blk_alloc_queue(GFP_KERNEL);
+       queue = blk_alloc_queue(ps3vram_make_request, NUMA_NO_NODE);
        if (!queue) {
                dev_err(&dev->core, "blk_alloc_queue failed\n");
                error = -ENOMEM;
@@ -746,7 +746,6 @@ static int ps3vram_probe(struct ps3_system_bus_device *dev)
 
        priv->queue = queue;
        queue->queuedata = dev;
-       blk_queue_make_request(queue, ps3vram_make_request);
        blk_queue_max_segments(queue, BLK_MAX_SEGMENTS);
        blk_queue_max_segment_size(queue, BLK_MAX_SEGMENT_SIZE);
        blk_queue_max_hw_sectors(queue, BLK_SAFE_MAX_SECTORS);
index c47d28b..8ffa826 100644 (file)
@@ -248,7 +248,7 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card)
                return -ENOMEM;
        }
 
-       card->queue = blk_alloc_queue(GFP_KERNEL);
+       card->queue = blk_alloc_queue(rsxx_make_request, NUMA_NO_NODE);
        if (!card->queue) {
                dev_err(CARD_TO_DEV(card), "Failed queue alloc\n");
                unregister_blkdev(card->major, DRIVER_NAME);
@@ -269,7 +269,6 @@ int rsxx_setup_dev(struct rsxx_cardinfo *card)
                blk_queue_logical_block_size(card->queue, blk_size);
        }
 
-       blk_queue_make_request(card->queue, rsxx_make_request);
        blk_queue_max_hw_sectors(card->queue, blkdev_max_hw_sectors);
        blk_queue_physical_block_size(card->queue, RSXX_HW_BLK_SIZE);
 
index 111eb65..1914f54 100644 (file)
@@ -80,7 +80,7 @@ struct dma_tracker {
 struct dma_tracker_list {
        spinlock_t              lock;
        int                     head;
-       struct dma_tracker      list[0];
+       struct dma_tracker      list[];
 };
 
 
index 4eaf97d..d84e8a8 100644 (file)
@@ -885,11 +885,9 @@ static int mm_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
        card->biotail = &card->bio;
        spin_lock_init(&card->lock);
 
-       card->queue = blk_alloc_queue_node(GFP_KERNEL, NUMA_NO_NODE);
+       card->queue = blk_alloc_queue(mm_make_request, NUMA_NO_NODE);
        if (!card->queue)
                goto failed_alloc;
-
-       blk_queue_make_request(card->queue, mm_make_request);
        card->queue->queuedata = card;
 
        tasklet_init(&card->tasklet, process_page, (unsigned long)card);
index 5415876..f9b1e70 100644 (file)
@@ -245,13 +245,20 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
        err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num);
        if (err) {
                virtqueue_kick(vblk->vqs[qid].vq);
-               blk_mq_stop_hw_queue(hctx);
+               /* Don't stop the queue if -ENOMEM: we may have failed to
+                * bounce the buffer due to global resource outage.
+                */
+               if (err == -ENOSPC)
+                       blk_mq_stop_hw_queue(hctx);
                spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags);
-               /* Out of mem doesn't actually happen, since we fall back
-                * to direct descriptors */
-               if (err == -ENOMEM || err == -ENOSPC)
+               switch (err) {
+               case -ENOSPC:
                        return BLK_STS_DEV_RESOURCE;
-               return BLK_STS_IOERR;
+               case -ENOMEM:
+                       return BLK_STS_RESOURCE;
+               default:
+                       return BLK_STS_IOERR;
+               }
        }
 
        if (bd->last && virtqueue_kick_prepare(vblk->vqs[qid].vq))
@@ -381,18 +388,15 @@ static void virtblk_update_capacity(struct virtio_blk *vblk, bool resize)
                   cap_str_10,
                   cap_str_2);
 
-       set_capacity(vblk->disk, capacity);
+       set_capacity_revalidate_and_notify(vblk->disk, capacity, true);
 }
 
 static void virtblk_config_changed_work(struct work_struct *work)
 {
        struct virtio_blk *vblk =
                container_of(work, struct virtio_blk, config_work);
-       char *envp[] = { "RESIZE=1", NULL };
 
        virtblk_update_capacity(vblk, true);
-       revalidate_disk(vblk->disk);
-       kobject_uevent_env(&disk_to_dev(vblk->disk)->kobj, KOBJ_CHANGE, envp);
 }
 
 static void virtblk_config_changed(struct virtio_device *vdev)
index e2ad6bb..915cf5b 100644 (file)
@@ -213,6 +213,7 @@ struct blkfront_info
        struct blk_mq_tag_set tag_set;
        struct blkfront_ring_info *rinfo;
        unsigned int nr_rings;
+       unsigned int rinfo_size;
        /* Save uncomplete reqs and bios for migration. */
        struct list_head requests;
        struct bio_list bio_list;
@@ -259,6 +260,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo);
 static void blkfront_gather_backend_features(struct blkfront_info *info);
 static int negotiate_mq(struct blkfront_info *info);
 
+#define for_each_rinfo(info, ptr, idx)                         \
+       for ((ptr) = (info)->rinfo, (idx) = 0;                  \
+            (idx) < (info)->nr_rings;                          \
+            (idx)++, (ptr) = (void *)(ptr) + (info)->rinfo_size)
+
+static inline struct blkfront_ring_info *
+get_rinfo(const struct blkfront_info *info, unsigned int i)
+{
+       BUG_ON(i >= info->nr_rings);
+       return (void *)info->rinfo + i * info->rinfo_size;
+}
+
 static int get_id_from_freelist(struct blkfront_ring_info *rinfo)
 {
        unsigned long free = rinfo->shadow_free;
@@ -883,8 +896,7 @@ static blk_status_t blkif_queue_rq(struct blk_mq_hw_ctx *hctx,
        struct blkfront_info *info = hctx->queue->queuedata;
        struct blkfront_ring_info *rinfo = NULL;
 
-       BUG_ON(info->nr_rings <= qid);
-       rinfo = &info->rinfo[qid];
+       rinfo = get_rinfo(info, qid);
        blk_mq_start_request(qd->rq);
        spin_lock_irqsave(&rinfo->ring_lock, flags);
        if (RING_FULL(&rinfo->ring))
@@ -1181,6 +1193,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity,
 static void xlvbd_release_gendisk(struct blkfront_info *info)
 {
        unsigned int minor, nr_minors, i;
+       struct blkfront_ring_info *rinfo;
 
        if (info->rq == NULL)
                return;
@@ -1188,9 +1201,7 @@ static void xlvbd_release_gendisk(struct blkfront_info *info)
        /* No more blkif_request(). */
        blk_mq_stop_hw_queues(info->rq);
 
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
-
+       for_each_rinfo(info, rinfo, i) {
                /* No more gnttab callback work. */
                gnttab_cancel_free_callback(&rinfo->callback);
 
@@ -1339,6 +1350,7 @@ free_shadow:
 static void blkif_free(struct blkfront_info *info, int suspend)
 {
        unsigned int i;
+       struct blkfront_ring_info *rinfo;
 
        /* Prevent new requests being issued until we fix things up. */
        info->connected = suspend ?
@@ -1347,8 +1359,8 @@ static void blkif_free(struct blkfront_info *info, int suspend)
        if (info->rq)
                blk_mq_stop_hw_queues(info->rq);
 
-       for (i = 0; i < info->nr_rings; i++)
-               blkif_free_ring(&info->rinfo[i]);
+       for_each_rinfo(info, rinfo, i)
+               blkif_free_ring(rinfo);
 
        kvfree(info->rinfo);
        info->rinfo = NULL;
@@ -1775,6 +1787,7 @@ static int talk_to_blkback(struct xenbus_device *dev,
        int err;
        unsigned int i, max_page_order;
        unsigned int ring_page_order;
+       struct blkfront_ring_info *rinfo;
 
        if (!info)
                return -ENODEV;
@@ -1788,9 +1801,7 @@ static int talk_to_blkback(struct xenbus_device *dev,
        if (err)
                goto destroy_blkring;
 
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
-
+       for_each_rinfo(info, rinfo, i) {
                /* Create shared ring, alloc event channel. */
                err = setup_blkring(dev, rinfo);
                if (err)
@@ -1815,7 +1826,7 @@ again:
 
        /* We already got the number of queues/rings in _probe */
        if (info->nr_rings == 1) {
-               err = write_per_ring_nodes(xbt, &info->rinfo[0], dev->nodename);
+               err = write_per_ring_nodes(xbt, info->rinfo, dev->nodename);
                if (err)
                        goto destroy_blkring;
        } else {
@@ -1837,10 +1848,10 @@ again:
                        goto abort_transaction;
                }
 
-               for (i = 0; i < info->nr_rings; i++) {
+               for_each_rinfo(info, rinfo, i) {
                        memset(path, 0, pathsize);
                        snprintf(path, pathsize, "%s/queue-%u", dev->nodename, i);
-                       err = write_per_ring_nodes(xbt, &info->rinfo[i], path);
+                       err = write_per_ring_nodes(xbt, rinfo, path);
                        if (err) {
                                kfree(path);
                                goto destroy_blkring;
@@ -1868,9 +1879,8 @@ again:
                goto destroy_blkring;
        }
 
-       for (i = 0; i < info->nr_rings; i++) {
+       for_each_rinfo(info, rinfo, i) {
                unsigned int j;
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
 
                for (j = 0; j < BLK_RING_SIZE(info); j++)
                        rinfo->shadow[j].req.u.rw.id = j + 1;
@@ -1900,6 +1910,7 @@ static int negotiate_mq(struct blkfront_info *info)
 {
        unsigned int backend_max_queues;
        unsigned int i;
+       struct blkfront_ring_info *rinfo;
 
        BUG_ON(info->nr_rings);
 
@@ -1911,20 +1922,16 @@ static int negotiate_mq(struct blkfront_info *info)
        if (!info->nr_rings)
                info->nr_rings = 1;
 
-       info->rinfo = kvcalloc(info->nr_rings,
-                              struct_size(info->rinfo, shadow,
-                                          BLK_RING_SIZE(info)),
-                              GFP_KERNEL);
+       info->rinfo_size = struct_size(info->rinfo, shadow,
+                                      BLK_RING_SIZE(info));
+       info->rinfo = kvcalloc(info->nr_rings, info->rinfo_size, GFP_KERNEL);
        if (!info->rinfo) {
                xenbus_dev_fatal(info->xbdev, -ENOMEM, "allocating ring_info structure");
                info->nr_rings = 0;
                return -ENOMEM;
        }
 
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo;
-
-               rinfo = &info->rinfo[i];
+       for_each_rinfo(info, rinfo, i) {
                INIT_LIST_HEAD(&rinfo->indirect_pages);
                INIT_LIST_HEAD(&rinfo->grants);
                rinfo->dev_info = info;
@@ -2017,6 +2024,7 @@ static int blkif_recover(struct blkfront_info *info)
        int rc;
        struct bio *bio;
        unsigned int segs;
+       struct blkfront_ring_info *rinfo;
 
        blkfront_gather_backend_features(info);
        /* Reset limits changed by blk_mq_update_nr_hw_queues(). */
@@ -2024,9 +2032,7 @@ static int blkif_recover(struct blkfront_info *info)
        segs = info->max_indirect_segments ? : BLKIF_MAX_SEGMENTS_PER_REQUEST;
        blk_queue_max_segments(info->rq, segs / GRANTS_PER_PSEG);
 
-       for (r_index = 0; r_index < info->nr_rings; r_index++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[r_index];
-
+       for_each_rinfo(info, rinfo, r_index) {
                rc = blkfront_setup_indirect(rinfo);
                if (rc)
                        return rc;
@@ -2036,10 +2042,7 @@ static int blkif_recover(struct blkfront_info *info)
        /* Now safe for us to use the shared ring */
        info->connected = BLKIF_STATE_CONNECTED;
 
-       for (r_index = 0; r_index < info->nr_rings; r_index++) {
-               struct blkfront_ring_info *rinfo;
-
-               rinfo = &info->rinfo[r_index];
+       for_each_rinfo(info, rinfo, r_index) {
                /* Kick any other new requests queued since we resumed */
                kick_pending_request_queues(rinfo);
        }
@@ -2072,13 +2075,13 @@ static int blkfront_resume(struct xenbus_device *dev)
        struct blkfront_info *info = dev_get_drvdata(&dev->dev);
        int err = 0;
        unsigned int i, j;
+       struct blkfront_ring_info *rinfo;
 
        dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
 
        bio_list_init(&info->bio_list);
        INIT_LIST_HEAD(&info->requests);
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
+       for_each_rinfo(info, rinfo, i) {
                struct bio_list merge_bio;
                struct blk_shadow *shadow = rinfo->shadow;
 
@@ -2335,8 +2338,8 @@ static void blkfront_connect(struct blkfront_info *info)
        unsigned long sector_size;
        unsigned int physical_sector_size;
        unsigned int binfo;
-       char *envp[] = { "RESIZE=1", NULL };
        int err, i;
+       struct blkfront_ring_info *rinfo;
 
        switch (info->connected) {
        case BLKIF_STATE_CONNECTED:
@@ -2350,10 +2353,7 @@ static void blkfront_connect(struct blkfront_info *info)
                        return;
                printk(KERN_INFO "Setting capacity to %Lu\n",
                       sectors);
-               set_capacity(info->gd, sectors);
-               revalidate_disk(info->gd);
-               kobject_uevent_env(&disk_to_dev(info->gd)->kobj,
-                                  KOBJ_CHANGE, envp);
+               set_capacity_revalidate_and_notify(info->gd, sectors, true);
 
                return;
        case BLKIF_STATE_SUSPENDED:
@@ -2394,8 +2394,8 @@ static void blkfront_connect(struct blkfront_info *info)
                                                    "physical-sector-size",
                                                    sector_size);
        blkfront_gather_backend_features(info);
-       for (i = 0; i < info->nr_rings; i++) {
-               err = blkfront_setup_indirect(&info->rinfo[i]);
+       for_each_rinfo(info, rinfo, i) {
+               err = blkfront_setup_indirect(rinfo);
                if (err) {
                        xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
                                         info->xbdev->otherend);
@@ -2416,8 +2416,8 @@ static void blkfront_connect(struct blkfront_info *info)
 
        /* Kick pending requests. */
        info->connected = BLKIF_STATE_CONNECTED;
-       for (i = 0; i < info->nr_rings; i++)
-               kick_pending_request_queues(&info->rinfo[i]);
+       for_each_rinfo(info, rinfo, i)
+               kick_pending_request_queues(rinfo);
 
        device_add_disk(&info->xbdev->dev, info->gd, NULL);
 
@@ -2652,9 +2652,9 @@ static void purge_persistent_grants(struct blkfront_info *info)
 {
        unsigned int i;
        unsigned long flags;
+       struct blkfront_ring_info *rinfo;
 
-       for (i = 0; i < info->nr_rings; i++) {
-               struct blkfront_ring_info *rinfo = &info->rinfo[i];
+       for_each_rinfo(info, rinfo, i) {
                struct grant *gnt_list_entry, *tmp;
 
                spin_lock_irqsave(&rinfo->ring_lock, flags);
index 1bdb579..ebb234f 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/sysfs.h>
 #include <linux/debugfs.h>
 #include <linux/cpuhotplug.h>
+#include <linux/part_stat.h>
 
 #include "zram_drv.h"
 
@@ -1894,7 +1895,7 @@ static int zram_add(void)
 #ifdef CONFIG_ZRAM_WRITEBACK
        spin_lock_init(&zram->wb_limit_lock);
 #endif
-       queue = blk_alloc_queue(GFP_KERNEL);
+       queue = blk_alloc_queue(zram_make_request, NUMA_NO_NODE);
        if (!queue) {
                pr_err("Error allocating disk queue for device %d\n",
                        device_id);
@@ -1902,8 +1903,6 @@ static int zram_add(void)
                goto out_free_idr;
        }
 
-       blk_queue_make_request(queue, zram_make_request);
-
        /* gendisk structure */
        zram->disk = alloc_disk(1);
        if (!zram->disk) {
index be79d6c..1bb00a9 100644 (file)
@@ -345,7 +345,7 @@ static int sunxi_rsb_read(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr,
        if (ret)
                goto unlock;
 
-       *buf = readl(rsb->regs + RSB_DATA);
+       *buf = readl(rsb->regs + RSB_DATA) & GENMASK(len * 8 - 1, 0);
 
 unlock:
        mutex_unlock(&rsb->lock);
index f702c85..4400196 100644 (file)
@@ -1266,6 +1266,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("gpu", 0x50000000, 0x14, -1, -1, 0x00010201, 0xffffffff, 0),
        SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff,
                   SYSC_MODULE_QUIRK_SGX),
+       SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff,
+                  SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
        SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
                   0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
        SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -1, 0x4ea2080d, 0xffffffff,
@@ -1294,7 +1296,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
        SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff, 0),
        SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
        SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
-       SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0),
        SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
        SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0),
        SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0),
@@ -1400,7 +1401,7 @@ static void sysc_init_revision_quirks(struct sysc *ddata)
 }
 
 /* 1-wire needs module's internal clocks enabled for reset */
-static void sysc_clk_enable_quirk_hdq1w(struct sysc *ddata)
+static void sysc_pre_reset_quirk_hdq1w(struct sysc *ddata)
 {
        int offset = 0x0c;      /* HDQ_CTRL_STATUS */
        u16 val;
@@ -1488,7 +1489,7 @@ static void sysc_init_module_quirks(struct sysc *ddata)
                return;
 
        if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) {
-               ddata->clk_enable_quirk = sysc_clk_enable_quirk_hdq1w;
+               ddata->clk_disable_quirk = sysc_pre_reset_quirk_hdq1w;
 
                return;
        }
index 886b263..c51292c 100644 (file)
@@ -519,7 +519,7 @@ static const struct block_device_operations gdrom_bdops = {
        .check_events           = gdrom_bdops_check_events,
        .ioctl                  = gdrom_bdops_ioctl,
 #ifdef CONFIG_COMPAT
-       .ioctl                  = blkdev_compat_ptr_ioctl,
+       .compat_ioctl           = blkdev_compat_ptr_ioctl,
 #endif
 };
 
index 594aee2..b40edae 100644 (file)
@@ -775,7 +775,7 @@ int __init agp_amd64_init(void)
                }
 
                /* First check that we have at least one AMD64 NB */
-               if (!pci_dev_present(amd_nb_misc_ids)) {
+               if (!amd_nb_num()) {
                        pci_unregister_driver(&agp_amd64_pci_driver);
                        return -ENODEV;
                }
index ffe9b0c..39943bc 100644 (file)
@@ -209,20 +209,19 @@ static int __init mod_init(void)
 out:
        return err;
 }
+module_init(mod_init);
 
 static void __exit mod_exit(void)
 {
        hwrng_unregister(&via_rng);
 }
-
-module_init(mod_init);
 module_exit(mod_exit);
 
 static struct x86_cpu_id __maybe_unused via_rng_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_XSTORE),
+       X86_MATCH_FEATURE(X86_FEATURE_XSTORE, NULL),
        {}
 };
+MODULE_DEVICE_TABLE(x86cpu, via_rng_cpu_id);
 
 MODULE_DESCRIPTION("H/W RNG driver for VIA CPU with PadLock");
 MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(x86cpu, via_rng_cpu_id);
index c78127c..638c693 100644 (file)
@@ -194,7 +194,7 @@ static int platform_ipmi_probe(struct platform_device *pdev)
        else
                io.slave_addr = slave_addr;
 
-       io.irq = platform_get_irq(pdev, 0);
+       io.irq = platform_get_irq_optional(pdev, 0);
        if (io.irq > 0)
                io.irq_setup = ipmi_std_irq_setup;
        else
@@ -378,7 +378,7 @@ static int acpi_ipmi_probe(struct platform_device *pdev)
                io.irq = tmp;
                io.irq_setup = acpi_gpe_irq_setup;
        } else {
-               int irq = platform_get_irq(pdev, 0);
+               int irq = platform_get_irq_optional(pdev, 0);
 
                if (irq > 0) {
                        io.irq = irq;
index 7a0fca6..7460f23 100644 (file)
@@ -99,11 +99,8 @@ static int tpm_read_log(struct tpm_chip *chip)
  *
  * If an event log is found then the securityfs files are setup to
  * export it to userspace, otherwise nothing is done.
- *
- * Returns -ENODEV if the firmware has no event log or securityfs is not
- * supported.
  */
-int tpm_bios_log_setup(struct tpm_chip *chip)
+void tpm_bios_log_setup(struct tpm_chip *chip)
 {
        const char *name = dev_name(&chip->dev);
        unsigned int cnt;
@@ -112,7 +109,7 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
 
        rc = tpm_read_log(chip);
        if (rc < 0)
-               return rc;
+               return;
        log_version = rc;
 
        cnt = 0;
@@ -158,13 +155,12 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
                cnt++;
        }
 
-       return 0;
+       return;
 
 err:
-       rc = PTR_ERR(chip->bios_dir[cnt]);
        chip->bios_dir[cnt] = NULL;
        tpm_bios_log_teardown(chip);
-       return rc;
+       return;
 }
 
 void tpm_bios_log_teardown(struct tpm_chip *chip)
index af347c1..a9ce66d 100644 (file)
@@ -51,7 +51,8 @@ int tpm_read_log_of(struct tpm_chip *chip)
         * endian format. For this reason, vtpm doesn't need conversion
         * but physical tpm needs the conversion.
         */
-       if (of_property_match_string(np, "compatible", "IBM,vtpm") < 0) {
+       if (of_property_match_string(np, "compatible", "IBM,vtpm") < 0 &&
+           of_property_match_string(np, "compatible", "IBM,vtpm20") < 0) {
                size = be32_to_cpup((__force __be32 *)sizep);
                base = be64_to_cpup((__force __be64 *)basep);
        } else {
index 739b1d9..2c96977 100644 (file)
@@ -115,6 +115,7 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
        u32 converted_event_size;
        u32 converted_event_type;
 
+       (*pos)++;
        converted_event_size = do_endian_conversion(event->event_size);
 
        v += sizeof(struct tcpa_event) + converted_event_size;
@@ -132,7 +133,6 @@ static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
            ((v + sizeof(struct tcpa_event) + converted_event_size) > limit))
                return NULL;
 
-       (*pos)++;
        return v;
 }
 
index b9aeda1..e741b11 100644 (file)
@@ -94,6 +94,7 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
        size_t event_size;
        void *marker;
 
+       (*pos)++;
        event_header = log->bios_event_log;
 
        if (v == SEQ_START_TOKEN) {
@@ -118,7 +119,6 @@ static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
        if (((v + event_size) >= limit) || (event_size == 0))
                return NULL;
 
-       (*pos)++;
        return v;
 }
 
index 3d6d394..5807383 100644 (file)
@@ -596,9 +596,7 @@ int tpm_chip_register(struct tpm_chip *chip)
 
        tpm_sysfs_add_device(chip);
 
-       rc = tpm_bios_log_setup(chip);
-       if (rc != 0 && rc != -ENODEV)
-               return rc;
+       tpm_bios_log_setup(chip);
 
        tpm_add_ppi(chip);
 
index 5620747..0fbcede 100644 (file)
@@ -226,6 +226,7 @@ int tpm2_auto_startup(struct tpm_chip *chip);
 void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
 unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
 int tpm2_probe(struct tpm_chip *chip);
+int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip);
 int tpm2_find_cc(struct tpm_chip *chip, u32 cc);
 int tpm2_init_space(struct tpm_space *space);
 void tpm2_del_space(struct tpm_chip *chip, struct tpm_space *space);
@@ -235,7 +236,7 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u8 *cmd,
 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space, void *buf,
                      size_t *bufsiz);
 
-int tpm_bios_log_setup(struct tpm_chip *chip);
+void tpm_bios_log_setup(struct tpm_chip *chip);
 void tpm_bios_log_teardown(struct tpm_chip *chip);
 int tpm_dev_common_init(void);
 void tpm_dev_common_exit(void);
index 7603295..76f67b1 100644 (file)
@@ -615,7 +615,7 @@ out:
        return rc;
 }
 
-static int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
+int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip)
 {
        struct tpm_buf buf;
        u32 nr_commands;
index 78cc526..1a49db9 100644 (file)
@@ -29,6 +29,7 @@ static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm";
 
 static const struct vio_device_id tpm_ibmvtpm_device_table[] = {
        { "IBM,vtpm", "IBM,vtpm"},
+       { "IBM,vtpm", "IBM,vtpm20"},
        { "", "" }
 };
 MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table);
@@ -571,6 +572,7 @@ static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance)
         */
        while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) {
                ibmvtpm_crq_process(crq, ibmvtpm);
+               wake_up_interruptible(&ibmvtpm->crq_queue.wq);
                crq->valid = 0;
                smp_wmb();
        }
@@ -618,6 +620,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
        }
 
        crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr);
+       init_waitqueue_head(&crq_q->wq);
        ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr,
                                                 CRQ_RES_BUF_SIZE,
                                                 DMA_BIDIRECTIONAL);
@@ -670,6 +673,20 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
        if (rc)
                goto init_irq_cleanup;
 
+       if (!strcmp(id->compat, "IBM,vtpm20")) {
+               chip->flags |= TPM_CHIP_FLAG_TPM2;
+               rc = tpm2_get_cc_attrs_tbl(chip);
+               if (rc)
+                       goto init_irq_cleanup;
+       }
+
+       if (!wait_event_timeout(ibmvtpm->crq_queue.wq,
+                               ibmvtpm->rtce_buf != NULL,
+                               HZ)) {
+               dev_err(dev, "CRQ response timed out\n");
+               goto init_irq_cleanup;
+       }
+
        return tpm_chip_register(chip);
 init_irq_cleanup:
        do {
index 7983f1a..b92aa7d 100644 (file)
@@ -26,6 +26,7 @@ struct ibmvtpm_crq_queue {
        struct ibmvtpm_crq *crq_addr;
        u32 index;
        u32 num_entry;
+       wait_queue_head_t wq;
 };
 
 struct ibmvtpm_dev {
index 37d72e8..ea759af 100644 (file)
@@ -132,7 +132,12 @@ static void cr50_wake_if_needed(struct cr50_spi_phy *cr50_phy)
 
        if (cr50_needs_waking(cr50_phy)) {
                /* Assert CS, wait 1 msec, deassert CS */
-               struct spi_transfer spi_cs_wake = { .delay_usecs = 1000 };
+               struct spi_transfer spi_cs_wake = {
+                       .delay = {
+                               .value = 1000,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       }
+               };
 
                spi_sync_transfer(phy->spi_device, &spi_cs_wake, 1);
                /* Wait for it to fully wake */
index d1754fd..d967559 100644 (file)
@@ -110,7 +110,8 @@ int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
 
                spi_xfer.cs_change = 0;
                spi_xfer.len = transfer_len;
-               spi_xfer.delay_usecs = 5;
+               spi_xfer.delay.value = 5;
+               spi_xfer.delay.unit = SPI_DELAY_UNIT_USECS;
 
                if (in) {
                        spi_xfer.tx_buf = NULL;
index f0f2b59..95adf6c 100644 (file)
@@ -4713,7 +4713,7 @@ EXPORT_SYMBOL(of_clk_get_by_name);
  *
  * Returns: The number of clocks that are possible parents of this node
  */
-unsigned int of_clk_get_parent_count(struct device_node *np)
+unsigned int of_clk_get_parent_count(const struct device_node *np)
 {
        int count;
 
@@ -4725,7 +4725,7 @@ unsigned int of_clk_get_parent_count(struct device_node *np)
 }
 EXPORT_SYMBOL_GPL(of_clk_get_parent_count);
 
-const char *of_clk_get_parent_name(struct device_node *np, int index)
+const char *of_clk_get_parent_name(const struct device_node *np, int index)
 {
        struct of_phandle_args clkspec;
        struct property *prop;
index f6c120c..cf19290 100644 (file)
@@ -560,7 +560,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
        hws[IMX8MP_CLK_MEDIA_AXI] = imx8m_clk_hw_composite("media_axi", imx8mp_media_axi_sels, ccm_base + 0x8a00);
        hws[IMX8MP_CLK_MEDIA_APB] = imx8m_clk_hw_composite("media_apb", imx8mp_media_apb_sels, ccm_base + 0x8a80);
        hws[IMX8MP_CLK_HDMI_APB] = imx8m_clk_hw_composite("hdmi_apb", imx8mp_media_apb_sels, ccm_base + 0x8b00);
-       hws[IMX8MP_CLK_HDMI_AXI] = imx8m_clk_hw_composite("hdmi_axi", imx8mp_media_apb_sels, ccm_base + 0x8b80);
+       hws[IMX8MP_CLK_HDMI_AXI] = imx8m_clk_hw_composite("hdmi_axi", imx8mp_media_axi_sels, ccm_base + 0x8b80);
        hws[IMX8MP_CLK_GPU_AXI] = imx8m_clk_hw_composite("gpu_axi", imx8mp_gpu_axi_sels, ccm_base + 0x8c00);
        hws[IMX8MP_CLK_GPU_AHB] = imx8m_clk_hw_composite("gpu_ahb", imx8mp_gpu_ahb_sels, ccm_base + 0x8c80);
        hws[IMX8MP_CLK_NOC] = imx8m_clk_hw_composite_critical("noc", imx8mp_noc_sels, ccm_base + 0x8d00);
@@ -686,7 +686,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev)
        hws[IMX8MP_CLK_CAN1_ROOT] = imx_clk_hw_gate2("can1_root_clk", "can1", ccm_base + 0x4350, 0);
        hws[IMX8MP_CLK_CAN2_ROOT] = imx_clk_hw_gate2("can2_root_clk", "can2", ccm_base + 0x4360, 0);
        hws[IMX8MP_CLK_SDMA1_ROOT] = imx_clk_hw_gate4("sdma1_root_clk", "ipg_root", ccm_base + 0x43a0, 0);
-       hws[IMX8MP_CLK_ENET_QOS_ROOT] = imx_clk_hw_gate4("enet_qos_root_clk", "enet_axi", ccm_base + 0x43b0, 0);
+       hws[IMX8MP_CLK_ENET_QOS_ROOT] = imx_clk_hw_gate4("enet_qos_root_clk", "sim_enet_root_clk", ccm_base + 0x43b0, 0);
        hws[IMX8MP_CLK_SIM_ENET_ROOT] = imx_clk_hw_gate4("sim_enet_root_clk", "enet_axi", ccm_base + 0x4400, 0);
        hws[IMX8MP_CLK_GPU2D_ROOT] = imx_clk_hw_gate4("gpu2d_root_clk", "gpu2d_div", ccm_base + 0x4450, 0);
        hws[IMX8MP_CLK_GPU3D_ROOT] = imx_clk_hw_gate4("gpu3d_root_clk", "gpu3d_core_div", ccm_base + 0x4460, 0);
index fbef740..b8b2072 100644 (file)
@@ -43,12 +43,12 @@ struct imx_sc_msg_req_set_clock_rate {
        __le32 rate;
        __le16 resource;
        u8 clk;
-} __packed;
+} __packed __aligned(4);
 
 struct req_get_clock_rate {
        __le16 resource;
        u8 clk;
-} __packed;
+} __packed __aligned(4);
 
 struct resp_get_clock_rate {
        __le32 rate;
@@ -84,7 +84,7 @@ struct imx_sc_msg_get_clock_parent {
                struct req_get_clock_parent {
                        __le16 resource;
                        u8 clk;
-               } __packed req;
+               } __packed __aligned(4) req;
                struct resp_get_clock_parent {
                        u8 parent;
                } resp;
@@ -121,7 +121,7 @@ struct imx_sc_msg_req_clock_enable {
        u8 clk;
        u8 enable;
        u8 autog;
-} __packed;
+} __packed __aligned(4);
 
 static inline struct clk_scu *to_clk_scu(struct clk_hw *hw)
 {
index dd7af41..0a5d395 100644 (file)
@@ -592,24 +592,6 @@ static struct clk_branch disp_cc_mdss_rot_clk = {
        },
 };
 
-static struct clk_branch disp_cc_mdss_rscc_ahb_clk = {
-       .halt_reg = 0x400c,
-       .halt_check = BRANCH_HALT,
-       .clkr = {
-               .enable_reg = 0x400c,
-               .enable_mask = BIT(0),
-               .hw.init = &(struct clk_init_data){
-                       .name = "disp_cc_mdss_rscc_ahb_clk",
-                       .parent_data = &(const struct clk_parent_data){
-                               .hw = &disp_cc_mdss_ahb_clk_src.clkr.hw,
-                       },
-                       .num_parents = 1,
-                       .flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
-                       .ops = &clk_branch2_ops,
-               },
-       },
-};
-
 static struct clk_branch disp_cc_mdss_rscc_vsync_clk = {
        .halt_reg = 0x4008,
        .halt_check = BRANCH_HALT,
@@ -687,7 +669,6 @@ static struct clk_regmap *disp_cc_sc7180_clocks[] = {
        [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr,
        [DISP_CC_MDSS_ROT_CLK] = &disp_cc_mdss_rot_clk.clkr,
        [DISP_CC_MDSS_ROT_CLK_SRC] = &disp_cc_mdss_rot_clk_src.clkr,
-       [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr,
        [DISP_CC_MDSS_RSCC_VSYNC_CLK] = &disp_cc_mdss_rscc_vsync_clk.clkr,
        [DISP_CC_MDSS_VSYNC_CLK] = &disp_cc_mdss_vsync_clk.clkr,
        [DISP_CC_MDSS_VSYNC_CLK_SRC] = &disp_cc_mdss_vsync_clk_src.clkr,
index c363c3c..276e5ec 100644 (file)
@@ -97,7 +97,7 @@ static struct clk_branch video_cc_vcodec0_axi_clk = {
 
 static struct clk_branch video_cc_vcodec0_core_clk = {
        .halt_reg = 0x890,
-       .halt_check = BRANCH_HALT,
+       .halt_check = BRANCH_HALT_VOTED,
        .clkr = {
                .enable_reg = 0x890,
                .enable_mask = BIT(0),
index af3e780..e5538d5 100644 (file)
@@ -78,7 +78,7 @@ static const struct omap_clkctrl_reg_data am4_gfx_l3_clkctrl_regs[] __initconst
 };
 
 static const struct omap_clkctrl_reg_data am4_l4_rtc_clkctrl_regs[] __initconst = {
-       { AM4_L4_RTC_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clk_32768_ck" },
+       { AM4_L4_RTC_RTC_CLKCTRL, NULL, CLKF_SW_SUP, "clkdiv32k_ick" },
        { 0 },
 };
 
index cc909e4..f2142e6 100644 (file)
@@ -697,6 +697,14 @@ config INGENIC_TIMER
        help
          Support for the timer/counter unit of the Ingenic JZ SoCs.
 
+config INGENIC_OST
+       bool "Clocksource for Ingenic OS Timer"
+       depends on MIPS || COMPILE_TEST
+       depends on COMMON_CLK
+       select MFD_SYSCON
+       help
+         Support for the Operating System Timer of the Ingenic JZ SoCs.
+
 config MICROCHIP_PIT64B
        bool "Microchip PIT64B support"
        depends on OF || COMPILE_TEST
index 713686f..641ba53 100644 (file)
@@ -80,6 +80,7 @@ obj-$(CONFIG_ASM9260_TIMER)           += asm9260_timer.o
 obj-$(CONFIG_H8300_TMR8)               += h8300_timer8.o
 obj-$(CONFIG_H8300_TMR16)              += h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)                        += h8300_tpu.o
+obj-$(CONFIG_INGENIC_OST)              += ingenic-ost.o
 obj-$(CONFIG_INGENIC_TIMER)            += ingenic-timer.o
 obj-$(CONFIG_CLKSRC_ST_LPC)            += clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP)             += numachip.o
index 9a5464c..2204a44 100644 (file)
@@ -69,7 +69,11 @@ static enum arch_timer_ppi_nr arch_timer_uses_ppi = ARCH_TIMER_VIRT_PPI;
 static bool arch_timer_c3stop;
 static bool arch_timer_mem_use_virtual;
 static bool arch_counter_suspend_stop;
-static bool vdso_default = true;
+#ifdef CONFIG_GENERIC_GETTIMEOFDAY
+static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_ARCHTIMER;
+#else
+static enum vdso_clock_mode vdso_default = VDSO_CLOCKMODE_NONE;
+#endif /* CONFIG_GENERIC_GETTIMEOFDAY */
 
 static cpumask_t evtstrm_available = CPU_MASK_NONE;
 static bool evtstrm_enable = IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM);
@@ -560,8 +564,8 @@ void arch_timer_enable_workaround(const struct arch_timer_erratum_workaround *wa
         * change both the default value and the vdso itself.
         */
        if (wa->read_cntvct_el0) {
-               clocksource_counter.archdata.vdso_direct = false;
-               vdso_default = false;
+               clocksource_counter.vdso_clock_mode = VDSO_CLOCKMODE_NONE;
+               vdso_default = VDSO_CLOCKMODE_NONE;
        }
 }
 
@@ -885,6 +889,17 @@ static int arch_timer_starting_cpu(unsigned int cpu)
        return 0;
 }
 
+static int validate_timer_rate(void)
+{
+       if (!arch_timer_rate)
+               return -EINVAL;
+
+       /* Arch timer frequency < 1MHz can cause trouble */
+       WARN_ON(arch_timer_rate < 1000000);
+
+       return 0;
+}
+
 /*
  * For historical reasons, when probing with DT we use whichever (non-zero)
  * rate was probed first, and don't verify that others match. If the first node
@@ -900,7 +915,7 @@ static void arch_timer_of_configure_rate(u32 rate, struct device_node *np)
                arch_timer_rate = rate;
 
        /* Check the timer frequency. */
-       if (arch_timer_rate == 0)
+       if (validate_timer_rate())
                pr_warn("frequency not available\n");
 }
 
@@ -979,7 +994,7 @@ static void __init arch_counter_register(unsigned type)
                }
 
                arch_timer_read_counter = rd;
-               clocksource_counter.archdata.vdso_direct = vdso_default;
+               clocksource_counter.vdso_clock_mode = vdso_default;
        } else {
                arch_timer_read_counter = arch_counter_get_cntvct_mem;
        }
@@ -1594,9 +1609,10 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
         * CNTFRQ value. This *must* be correct.
         */
        arch_timer_rate = arch_timer_get_cntfrq();
-       if (!arch_timer_rate) {
+       ret = validate_timer_rate();
+       if (ret) {
                pr_err(FW_BUG "frequency not available.\n");
-               return -EINVAL;
+               return ret;
        }
 
        arch_timer_uses_ppi = arch_timer_select_ppi();
index b235f44..1592650 100644 (file)
@@ -31,7 +31,6 @@ struct bcm2835_timer {
        void __iomem *compare;
        int match_mask;
        struct clock_event_device evt;
-       struct irqaction act;
 };
 
 static void __iomem *system_clock __read_mostly;
@@ -113,12 +112,9 @@ static int __init bcm2835_timer_init(struct device_node *node)
        timer->evt.features = CLOCK_EVT_FEAT_ONESHOT;
        timer->evt.set_next_event = bcm2835_time_set_next_event;
        timer->evt.cpumask = cpumask_of(0);
-       timer->act.name = node->name;
-       timer->act.flags = IRQF_TIMER | IRQF_SHARED;
-       timer->act.dev_id = timer;
-       timer->act.handler = bcm2835_time_interrupt;
 
-       ret = setup_irq(irq, &timer->act);
+       ret = request_irq(irq, bcm2835_time_interrupt, IRQF_TIMER | IRQF_SHARED,
+                         node->name, timer);
        if (ret) {
                pr_err("Can't set up timer IRQ\n");
                goto err_timer_free;
index 5c40be9..a50ab5c 100644 (file)
@@ -160,12 +160,6 @@ static irqreturn_t kona_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction kona_timer_irq = {
-       .name = "Kona Timer Tick",
-       .flags = IRQF_TIMER,
-       .handler = kona_timer_interrupt,
-};
-
 static int __init kona_timer_init(struct device_node *node)
 {
        u32 freq;
@@ -192,7 +186,9 @@ static int __init kona_timer_init(struct device_node *node)
        kona_timer_disable_and_clear(timers.tmr_regs);
 
        kona_timer_clockevents_init();
-       setup_irq(timers.tmr_irq, &kona_timer_irq);
+       if (request_irq(timers.tmr_irq, kona_timer_interrupt, IRQF_TIMER,
+                       "Kona Timer Tick", NULL))
+               pr_err("%s: request_irq() failed\n", "Kona Timer Tick");
        kona_timer_set_next_event((arch_timer_rate / HZ), NULL);
 
        return 0;
index 6547665..b207a77 100644 (file)
@@ -270,15 +270,10 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating,
        dw_ced->ced.rating = rating;
        dw_ced->ced.name = name;
 
-       dw_ced->irqaction.name          = dw_ced->ced.name;
-       dw_ced->irqaction.handler       = dw_apb_clockevent_irq;
-       dw_ced->irqaction.dev_id        = &dw_ced->ced;
-       dw_ced->irqaction.irq           = irq;
-       dw_ced->irqaction.flags         = IRQF_TIMER | IRQF_IRQPOLL |
-                                         IRQF_NOBALANCING;
-
        dw_ced->eoi = apbt_eoi;
-       err = setup_irq(irq, &dw_ced->irqaction);
+       err = request_irq(irq, dw_apb_clockevent_irq,
+                         IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
+                         dw_ced->ced.name, &dw_ced->ced);
        if (err) {
                pr_err("failed to request timer irq\n");
                kfree(dw_ced);
index a267fe3..fabad79 100644 (file)
@@ -329,19 +329,15 @@ static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction mct_comp_event_irq = {
-       .name           = "mct_comp_irq",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = exynos4_mct_comp_isr,
-       .dev_id         = &mct_comp_device,
-};
-
 static int exynos4_clockevent_init(void)
 {
        mct_comp_device.cpumask = cpumask_of(0);
        clockevents_config_and_register(&mct_comp_device, clk_rate,
                                        0xf, 0xffffffff);
-       setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq);
+       if (request_irq(mct_irqs[MCT_G0_IRQ], exynos4_mct_comp_isr,
+                       IRQF_TIMER | IRQF_IRQPOLL, "mct_comp_irq",
+                       &mct_comp_device))
+               pr_err("%s: request_irq() failed\n", "mct_comp_irq");
 
        return 0;
 }
index 9d808d5..09aa44c 100644 (file)
@@ -343,7 +343,8 @@ static u64 notrace read_hv_clock_tsc_cs(struct clocksource *arg)
 
 static u64 read_hv_sched_clock_tsc(void)
 {
-       return read_hv_clock_tsc() - hv_sched_clock_offset;
+       return (read_hv_clock_tsc() - hv_sched_clock_offset) *
+               (NSEC_PER_SEC / HV_CLOCK_HZ);
 }
 
 static void suspend_hv_clock_tsc(struct clocksource *arg)
@@ -369,6 +370,12 @@ static void resume_hv_clock_tsc(struct clocksource *arg)
        hv_set_reference_tsc(tsc_msr);
 }
 
+static int hv_cs_enable(struct clocksource *cs)
+{
+       hv_enable_vdso_clocksource();
+       return 0;
+}
+
 static struct clocksource hyperv_cs_tsc = {
        .name   = "hyperv_clocksource_tsc_page",
        .rating = 250,
@@ -377,6 +384,7 @@ static struct clocksource hyperv_cs_tsc = {
        .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
        .suspend= suspend_hv_clock_tsc,
        .resume = resume_hv_clock_tsc,
+       .enable = hv_cs_enable,
 };
 
 static u64 notrace read_hv_clock_msr(void)
@@ -398,7 +406,8 @@ static u64 notrace read_hv_clock_msr_cs(struct clocksource *arg)
 
 static u64 read_hv_sched_clock_msr(void)
 {
-       return read_hv_clock_msr() - hv_sched_clock_offset;
+       return (read_hv_clock_msr() - hv_sched_clock_offset) *
+               (NSEC_PER_SEC / HV_CLOCK_HZ);
 }
 
 static struct clocksource hyperv_cs_msr = {
diff --git a/drivers/clocksource/ingenic-ost.c b/drivers/clocksource/ingenic-ost.c
new file mode 100644 (file)
index 0000000..029efc2
--- /dev/null
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ47xx SoCs TCU Operating System Timer driver
+ *
+ * Copyright (C) 2016 Maarten ter Huurne <maarten@treewalker.org>
+ * Copyright (C) 2020 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/mfd/ingenic-tcu.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/regmap.h>
+#include <linux/sched_clock.h>
+
+#define TCU_OST_TCSR_MASK      0xffc0
+#define TCU_OST_TCSR_CNT_MD    BIT(15)
+
+#define TCU_OST_CHANNEL                15
+
+/*
+ * The TCU_REG_OST_CNT{L,R} from <linux/mfd/ingenic-tcu.h> are only for the
+ * regmap; these are for use with the __iomem pointer.
+ */
+#define OST_REG_CNTL           0x4
+#define OST_REG_CNTH           0x8
+
+struct ingenic_ost_soc_info {
+       bool is64bit;
+};
+
+struct ingenic_ost {
+       void __iomem *regs;
+       struct clk *clk;
+
+       struct clocksource cs;
+};
+
+static struct ingenic_ost *ingenic_ost;
+
+static u64 notrace ingenic_ost_read_cntl(void)
+{
+       /* Read using __iomem pointer instead of regmap to avoid locking */
+       return readl(ingenic_ost->regs + OST_REG_CNTL);
+}
+
+static u64 notrace ingenic_ost_read_cnth(void)
+{
+       /* Read using __iomem pointer instead of regmap to avoid locking */
+       return readl(ingenic_ost->regs + OST_REG_CNTH);
+}
+
+static u64 notrace ingenic_ost_clocksource_readl(struct clocksource *cs)
+{
+       return ingenic_ost_read_cntl();
+}
+
+static u64 notrace ingenic_ost_clocksource_readh(struct clocksource *cs)
+{
+       return ingenic_ost_read_cnth();
+}
+
+static int __init ingenic_ost_probe(struct platform_device *pdev)
+{
+       const struct ingenic_ost_soc_info *soc_info;
+       struct device *dev = &pdev->dev;
+       struct ingenic_ost *ost;
+       struct clocksource *cs;
+       struct regmap *map;
+       unsigned long rate;
+       int err;
+
+       soc_info = device_get_match_data(dev);
+       if (!soc_info)
+               return -EINVAL;
+
+       ost = devm_kzalloc(dev, sizeof(*ost), GFP_KERNEL);
+       if (!ost)
+               return -ENOMEM;
+
+       ingenic_ost = ost;
+
+       ost->regs = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(ost->regs))
+               return PTR_ERR(ost->regs);
+
+       map = device_node_to_regmap(dev->parent->of_node);
+       if (!map) {
+               dev_err(dev, "regmap not found");
+               return -EINVAL;
+       }
+
+       ost->clk = devm_clk_get(dev, "ost");
+       if (IS_ERR(ost->clk))
+               return PTR_ERR(ost->clk);
+
+       err = clk_prepare_enable(ost->clk);
+       if (err)
+               return err;
+
+       /* Clear counter high/low registers */
+       if (soc_info->is64bit)
+               regmap_write(map, TCU_REG_OST_CNTL, 0);
+       regmap_write(map, TCU_REG_OST_CNTH, 0);
+
+       /* Don't reset counter at compare value. */
+       regmap_update_bits(map, TCU_REG_OST_TCSR,
+                          TCU_OST_TCSR_MASK, TCU_OST_TCSR_CNT_MD);
+
+       rate = clk_get_rate(ost->clk);
+
+       /* Enable OST TCU channel */
+       regmap_write(map, TCU_REG_TESR, BIT(TCU_OST_CHANNEL));
+
+       cs = &ost->cs;
+       cs->name        = "ingenic-ost";
+       cs->rating      = 320;
+       cs->flags       = CLOCK_SOURCE_IS_CONTINUOUS;
+       cs->mask        = CLOCKSOURCE_MASK(32);
+
+       if (soc_info->is64bit)
+               cs->read = ingenic_ost_clocksource_readl;
+       else
+               cs->read = ingenic_ost_clocksource_readh;
+
+       err = clocksource_register_hz(cs, rate);
+       if (err) {
+               dev_err(dev, "clocksource registration failed");
+               clk_disable_unprepare(ost->clk);
+               return err;
+       }
+
+       if (soc_info->is64bit)
+               sched_clock_register(ingenic_ost_read_cntl, 32, rate);
+       else
+               sched_clock_register(ingenic_ost_read_cnth, 32, rate);
+
+       return 0;
+}
+
+static int __maybe_unused ingenic_ost_suspend(struct device *dev)
+{
+       struct ingenic_ost *ost = dev_get_drvdata(dev);
+
+       clk_disable(ost->clk);
+
+       return 0;
+}
+
+static int __maybe_unused ingenic_ost_resume(struct device *dev)
+{
+       struct ingenic_ost *ost = dev_get_drvdata(dev);
+
+       return clk_enable(ost->clk);
+}
+
+static const struct dev_pm_ops __maybe_unused ingenic_ost_pm_ops = {
+       /* _noirq: We want the OST clock to be gated last / ungated first */
+       .suspend_noirq = ingenic_ost_suspend,
+       .resume_noirq  = ingenic_ost_resume,
+};
+
+static const struct ingenic_ost_soc_info jz4725b_ost_soc_info = {
+       .is64bit = false,
+};
+
+static const struct ingenic_ost_soc_info jz4770_ost_soc_info = {
+       .is64bit = true,
+};
+
+static const struct of_device_id ingenic_ost_of_match[] = {
+       { .compatible = "ingenic,jz4725b-ost", .data = &jz4725b_ost_soc_info, },
+       { .compatible = "ingenic,jz4770-ost", .data = &jz4770_ost_soc_info, },
+       { }
+};
+
+static struct platform_driver ingenic_ost_driver = {
+       .driver = {
+               .name = "ingenic-ost",
+#ifdef CONFIG_PM_SUSPEND
+               .pm = &ingenic_ost_pm_ops,
+#endif
+               .of_match_table = ingenic_ost_of_match,
+       },
+};
+builtin_platform_driver_probe(ingenic_ost_driver, ingenic_ost_probe);
index 4bbdb3d..4963336 100644 (file)
@@ -230,6 +230,7 @@ static const struct of_device_id ingenic_tcu_of_match[] = {
        { .compatible = "ingenic,jz4740-tcu", .data = &jz4740_soc_info, },
        { .compatible = "ingenic,jz4725b-tcu", .data = &jz4725b_soc_info, },
        { .compatible = "ingenic,jz4770-tcu", .data = &jz4740_soc_info, },
+       { .compatible = "ingenic,x1000-tcu", .data = &jz4740_soc_info, },
        { /* sentinel */ }
 };
 
@@ -302,7 +303,7 @@ err_free_ingenic_tcu:
 TIMER_OF_DECLARE(jz4740_tcu_intc,  "ingenic,jz4740-tcu",  ingenic_tcu_init);
 TIMER_OF_DECLARE(jz4725b_tcu_intc, "ingenic,jz4725b-tcu", ingenic_tcu_init);
 TIMER_OF_DECLARE(jz4770_tcu_intc,  "ingenic,jz4770-tcu",  ingenic_tcu_init);
-
+TIMER_OF_DECLARE(x1000_tcu_intc,  "ingenic,x1000-tcu",  ingenic_tcu_init);
 
 static int __init ingenic_tcu_probe(struct platform_device *pdev)
 {
index 37671a5..8b5f8ae 100644 (file)
@@ -155,10 +155,10 @@ static u64 gic_hpt_read(struct clocksource *cs)
 }
 
 static struct clocksource gic_clocksource = {
-       .name           = "GIC",
-       .read           = gic_hpt_read,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-       .archdata       = { .vdso_clock_mode = VDSO_CLOCK_GIC },
+       .name                   = "GIC",
+       .read                   = gic_hpt_read,
+       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .vdso_clock_mode        = VDSO_CLOCKMODE_GIC,
 };
 
 static int __init __gic_clocksource_init(void)
index f6ddae3..bc96a4c 100644 (file)
@@ -117,13 +117,6 @@ static irqreturn_t mxs_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction mxs_timer_irq = {
-       .name           = "MXS Timer Tick",
-       .dev_id         = &mxs_clockevent_device,
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = mxs_timer_interrupt,
-};
-
 static void mxs_irq_clear(char *state)
 {
        /* Disable interrupt in timer module */
@@ -277,6 +270,7 @@ static int __init mxs_timer_init(struct device_node *np)
        if (irq <= 0)
                return -EINVAL;
 
-       return setup_irq(irq, &mxs_timer_irq);
+       return request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
+                          "MXS Timer Tick", &mxs_clockevent_device);
 }
 TIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
index 3f7fa8c..f49a631 100644 (file)
@@ -181,13 +181,6 @@ static irqreturn_t nmdk_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction nmdk_timer_irq = {
-       .name           = "Nomadik Timer Tick",
-       .flags          = IRQF_TIMER,
-       .handler        = nmdk_timer_interrupt,
-       .dev_id         = &nmdk_clkevt,
-};
-
 static int __init nmdk_timer_init(void __iomem *base, int irq,
                                   struct clk *pclk, struct clk *clk)
 {
@@ -232,7 +225,9 @@ static int __init nmdk_timer_init(void __iomem *base, int irq,
        sched_clock_register(nomadik_read_sched_clock, 32, rate);
 
        /* Timer 1 is used for events, register irq and clockevents */
-       setup_irq(irq, &nmdk_timer_irq);
+       if (request_irq(irq, nmdk_timer_interrupt, IRQF_TIMER,
+                       "Nomadik Timer Tick", &nmdk_clkevt))
+               pr_err("%s: request_irq() failed\n", "Nomadik Timer Tick");
        nmdk_clkevt.cpumask = cpumask_of(0);
        nmdk_clkevt.irq = irq;
        clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU);
index dae1b2b..f760229 100644 (file)
@@ -256,13 +256,6 @@ static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction samsung_clock_event_irq = {
-       .name           = "samsung_time_irq",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = samsung_clock_event_isr,
-       .dev_id         = &time_event_device,
-};
-
 static void __init samsung_clockevent_init(void)
 {
        unsigned long pclk;
@@ -282,7 +275,10 @@ static void __init samsung_clockevent_init(void)
                                                clock_rate, 1, pwm.tcnt_max);
 
        irq_number = pwm.irq[pwm.event_id];
-       setup_irq(irq_number, &samsung_clock_event_irq);
+       if (request_irq(irq_number, samsung_clock_event_isr,
+                       IRQF_TIMER | IRQF_IRQPOLL, "samsung_time_irq",
+                       &time_event_device))
+               pr_err("%s: request_irq() failed\n", "samsung_time_irq");
 
        if (pwm.variant.has_tint_cstat) {
                u32 mask = (1 << pwm.event_id);
index 93c3ac6..c21c91c 100644 (file)
@@ -159,29 +159,23 @@ static struct clocksource sirfsoc_clocksource = {
        .resume = sirfsoc_clocksource_resume,
 };
 
-static struct irqaction sirfsoc_timer_irq = {
-       .name = "sirfsoc_timer0",
-       .flags = IRQF_TIMER | IRQF_NOBALANCING,
-       .handler = sirfsoc_timer_interrupt,
-};
-
-static struct irqaction sirfsoc_timer1_irq = {
-       .name = "sirfsoc_timer1",
-       .flags = IRQF_TIMER | IRQF_NOBALANCING,
-       .handler = sirfsoc_timer_interrupt,
-};
+static unsigned int sirfsoc_timer_irq, sirfsoc_timer1_irq;
 
 static int sirfsoc_local_timer_starting_cpu(unsigned int cpu)
 {
        struct clock_event_device *ce = per_cpu_ptr(sirfsoc_clockevent, cpu);
-       struct irqaction *action;
-
-       if (cpu == 0)
-               action = &sirfsoc_timer_irq;
-       else
-               action = &sirfsoc_timer1_irq;
+       unsigned int irq;
+       const char *name;
+
+       if (cpu == 0) {
+               irq = sirfsoc_timer_irq;
+               name = "sirfsoc_timer0";
+       } else {
+               irq = sirfsoc_timer1_irq;
+               name = "sirfsoc_timer1";
+       }
 
-       ce->irq = action->irq;
+       ce->irq = irq;
        ce->name = "local_timer";
        ce->features = CLOCK_EVT_FEAT_ONESHOT;
        ce->rating = 200;
@@ -196,9 +190,9 @@ static int sirfsoc_local_timer_starting_cpu(unsigned int cpu)
        ce->min_delta_ticks = 2;
        ce->cpumask = cpumask_of(cpu);
 
-       action->dev_id = ce;
-       BUG_ON(setup_irq(ce->irq, action));
-       irq_force_affinity(action->irq, cpumask_of(cpu));
+       BUG_ON(request_irq(ce->irq, sirfsoc_timer_interrupt,
+                          IRQF_TIMER | IRQF_NOBALANCING, name, ce));
+       irq_force_affinity(ce->irq, cpumask_of(cpu));
 
        clockevents_register_device(ce);
        return 0;
@@ -206,12 +200,14 @@ static int sirfsoc_local_timer_starting_cpu(unsigned int cpu)
 
 static int sirfsoc_local_timer_dying_cpu(unsigned int cpu)
 {
+       struct clock_event_device *ce = per_cpu_ptr(sirfsoc_clockevent, cpu);
+
        sirfsoc_timer_count_disable(1);
 
        if (cpu == 0)
-               remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
+               free_irq(sirfsoc_timer_irq, ce);
        else
-               remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+               free_irq(sirfsoc_timer1_irq, ce);
        return 0;
 }
 
@@ -268,14 +264,14 @@ static int __init sirfsoc_of_timer_init(struct device_node *np)
                return -ENXIO;
        }
 
-       sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
-       if (!sirfsoc_timer_irq.irq) {
+       sirfsoc_timer_irq = irq_of_parse_and_map(np, 0);
+       if (!sirfsoc_timer_irq) {
                pr_err("No irq passed for timer0 via DT\n");
                return -EINVAL;
        }
 
-       sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
-       if (!sirfsoc_timer1_irq.irq) {
+       sirfsoc_timer1_irq = irq_of_parse_and_map(np, 1);
+       if (!sirfsoc_timer1_irq) {
                pr_err("No irq passed for timer1 via DT\n");
                return -EINVAL;
        }
index 8f6bc53..d47acfe 100644 (file)
@@ -131,14 +131,9 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction mfgptirq  = {
-       .handler = mfgpt_tick,
-       .flags = IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED,
-       .name = DRV_NAME,
-};
-
 static int __init cs5535_mfgpt_init(void)
 {
+       unsigned long flags = IRQF_NOBALANCING | IRQF_TIMER | IRQF_SHARED;
        struct cs5535_mfgpt_timer *timer;
        int ret;
        uint16_t val;
@@ -158,7 +153,7 @@ static int __init cs5535_mfgpt_init(void)
        }
 
        /* And register it with the kernel */
-       ret = setup_irq(timer_irq, &mfgptirq);
+       ret = request_irq(timer_irq, mfgpt_tick, flags, DRV_NAME, timer);
        if (ret) {
                printk(KERN_ERR DRV_NAME ": Unable to set up the interrupt.\n");
                goto err_irq;
index 5a22cb0..441a4b9 100644 (file)
@@ -119,13 +119,6 @@ static struct efm32_clock_event_ddata clock_event_ddata = {
        },
 };
 
-static struct irqaction efm32_clock_event_irq = {
-       .name = "efm32 clockevent",
-       .flags = IRQF_TIMER,
-       .handler = efm32_clock_event_handler,
-       .dev_id = &clock_event_ddata,
-};
-
 static int __init efm32_clocksource_init(struct device_node *np)
 {
        struct clk *clk;
@@ -230,7 +223,8 @@ static int __init efm32_clockevent_init(struct device_node *np)
                                        DIV_ROUND_CLOSEST(rate, 1024),
                                        0xf, 0xffff);
 
-       ret = setup_irq(irq, &efm32_clock_event_irq);
+       ret = request_irq(irq, efm32_clock_event_handler, IRQF_TIMER,
+                         "efm32 clockevent", &clock_event_ddata);
        if (ret) {
                pr_err("Failed setup irq\n");
                goto err_setup_irq;
index a9d9a3c..12a2ed7 100644 (file)
@@ -176,13 +176,6 @@ static struct clock_event_device ftm_clockevent = {
        .rating                 = 300,
 };
 
-static struct irqaction ftm_timer_irq = {
-       .name           = "Freescale ftm timer",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = ftm_evt_interrupt,
-       .dev_id         = &ftm_clockevent,
-};
-
 static int __init ftm_clockevent_init(unsigned long freq, int irq)
 {
        int err;
@@ -192,7 +185,8 @@ static int __init ftm_clockevent_init(unsigned long freq, int irq)
 
        ftm_reset_counter(priv->clkevt_base);
 
-       err = setup_irq(irq, &ftm_timer_irq);
+       err = request_irq(irq, ftm_evt_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
+                         "Freescale ftm timer", &ftm_clockevent);
        if (err) {
                pr_err("ftm: setup irq failed: %d\n", err);
                return err;
index fadff79..edb1d5f 100644 (file)
 #define TIMER_CR               (0x30)
 
 /*
+ * Control register set to clear for ast2600 only.
+ */
+#define AST2600_TIMER_CR_CLR   (0x3c)
+
+/*
  * Control register (TMC30) bit fields for fttmr010/gemini/moxart timers.
  */
 #define TIMER_1_CR_ENABLE      BIT(0)
@@ -97,6 +102,7 @@ struct fttmr010 {
        bool is_aspeed;
        u32 t1_enable_val;
        struct clock_event_device clkevt;
+       int (*timer_shutdown)(struct clock_event_device *evt);
 #ifdef CONFIG_ARM
        struct delay_timer delay_timer;
 #endif
@@ -140,9 +146,7 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
        u32 cr;
 
        /* Stop */
-       cr = readl(fttmr010->base + TIMER_CR);
-       cr &= ~fttmr010->t1_enable_val;
-       writel(cr, fttmr010->base + TIMER_CR);
+       fttmr010->timer_shutdown(evt);
 
        if (fttmr010->is_aspeed) {
                /*
@@ -164,6 +168,16 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
        return 0;
 }
 
+static int ast2600_timer_shutdown(struct clock_event_device *evt)
+{
+       struct fttmr010 *fttmr010 = to_fttmr010(evt);
+
+       /* Stop */
+       writel(fttmr010->t1_enable_val, fttmr010->base + AST2600_TIMER_CR_CLR);
+
+       return 0;
+}
+
 static int fttmr010_timer_shutdown(struct clock_event_device *evt)
 {
        struct fttmr010 *fttmr010 = to_fttmr010(evt);
@@ -183,9 +197,7 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
        u32 cr;
 
        /* Stop */
-       cr = readl(fttmr010->base + TIMER_CR);
-       cr &= ~fttmr010->t1_enable_val;
-       writel(cr, fttmr010->base + TIMER_CR);
+       fttmr010->timer_shutdown(evt);
 
        /* Setup counter start from 0 or ~0 */
        writel(0, fttmr010->base + TIMER1_COUNT);
@@ -211,9 +223,7 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
        u32 cr;
 
        /* Stop */
-       cr = readl(fttmr010->base + TIMER_CR);
-       cr &= ~fttmr010->t1_enable_val;
-       writel(cr, fttmr010->base + TIMER_CR);
+       fttmr010->timer_shutdown(evt);
 
        /* Setup timer to fire at 1/HZ intervals. */
        if (fttmr010->is_aspeed) {
@@ -249,7 +259,21 @@ static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
+static irqreturn_t ast2600_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = dev_id;
+       struct fttmr010 *fttmr010 = to_fttmr010(evt);
+
+       writel(0x1, fttmr010->base + TIMER_INTR_STATE);
+
+       evt->event_handler(evt);
+       return IRQ_HANDLED;
+}
+
+static int __init fttmr010_common_init(struct device_node *np,
+               bool is_aspeed,
+               int (*timer_shutdown)(struct clock_event_device *),
+               irq_handler_t irq_handler)
 {
        struct fttmr010 *fttmr010;
        int irq;
@@ -350,6 +374,8 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
                                     fttmr010->tick_rate);
        }
 
+       fttmr010->timer_shutdown = timer_shutdown;
+
        /*
         * Setup clockevent timer (interrupt-driven) on timer 1.
         */
@@ -357,7 +383,7 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
        writel(0, fttmr010->base + TIMER1_LOAD);
        writel(0, fttmr010->base + TIMER1_MATCH1);
        writel(0, fttmr010->base + TIMER1_MATCH2);
-       ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER,
+       ret = request_irq(irq, irq_handler, IRQF_TIMER,
                          "FTTMR010-TIMER1", &fttmr010->clkevt);
        if (ret) {
                pr_err("FTTMR010-TIMER1 no IRQ\n");
@@ -370,10 +396,10 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
        fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
                CLOCK_EVT_FEAT_ONESHOT;
        fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event;
-       fttmr010->clkevt.set_state_shutdown = fttmr010_timer_shutdown;
+       fttmr010->clkevt.set_state_shutdown = fttmr010->timer_shutdown;
        fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic;
        fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot;
-       fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown;
+       fttmr010->clkevt.tick_resume = fttmr010->timer_shutdown;
        fttmr010->clkevt.cpumask = cpumask_of(0);
        fttmr010->clkevt.irq = irq;
        clockevents_config_and_register(&fttmr010->clkevt,
@@ -404,14 +430,25 @@ out_disable_clock:
        return ret;
 }
 
+static __init int ast2600_timer_init(struct device_node *np)
+{
+       return fttmr010_common_init(np, true,
+                       ast2600_timer_shutdown,
+                       ast2600_timer_interrupt);
+}
+
 static __init int aspeed_timer_init(struct device_node *np)
 {
-       return fttmr010_common_init(np, true);
+       return fttmr010_common_init(np, true,
+                       fttmr010_timer_shutdown,
+                       fttmr010_timer_interrupt);
 }
 
 static __init int fttmr010_timer_init(struct device_node *np)
 {
-       return fttmr010_common_init(np, false);
+       return fttmr010_common_init(np, false,
+                       fttmr010_timer_shutdown,
+                       fttmr010_timer_interrupt);
 }
 
 TIMER_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init);
@@ -419,3 +456,4 @@ TIMER_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init);
 TIMER_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init);
 TIMER_OF_DECLARE(ast2400, "aspeed,ast2400-timer", aspeed_timer_init);
 TIMER_OF_DECLARE(ast2500, "aspeed,ast2500-timer", aspeed_timer_init);
+TIMER_OF_DECLARE(ast2600, "aspeed,ast2600-timer", ast2600_timer_init);
index 706c0d0..7b2c70f 100644 (file)
@@ -67,7 +67,6 @@ struct imx_timer {
        struct clk *clk_ipg;
        const struct imx_gpt_data *gpt;
        struct clock_event_device ced;
-       struct irqaction act;
 };
 
 struct imx_gpt_data {
@@ -273,7 +272,6 @@ static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
 static int __init mxc_clockevent_init(struct imx_timer *imxtm)
 {
        struct clock_event_device *ced = &imxtm->ced;
-       struct irqaction *act = &imxtm->act;
 
        ced->name = "mxc_timer1";
        ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
@@ -287,12 +285,8 @@ static int __init mxc_clockevent_init(struct imx_timer *imxtm)
        clockevents_config_and_register(ced, clk_get_rate(imxtm->clk_per),
                                        0xff, 0xfffffffe);
 
-       act->name = "i.MX Timer Tick";
-       act->flags = IRQF_TIMER | IRQF_IRQPOLL;
-       act->handler = mxc_timer_interrupt;
-       act->dev_id = ced;
-
-       return setup_irq(imxtm->irq, act);
+       return request_irq(imxtm->irq, mxc_timer_interrupt,
+                          IRQF_TIMER | IRQF_IRQPOLL, "i.MX Timer Tick", ced);
 }
 
 static void imx1_gpt_setup_tctl(struct imx_timer *imxtm)
index b7c80a3..18b90fc 100644 (file)
@@ -4,8 +4,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/clockchips.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
 
 #include "timer-of.h"
 
index c1d52d5..6334a35 100644 (file)
@@ -8,8 +8,6 @@
 #include <linux/clocksource.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
 #include <linux/sched_clock.h>
 
 #include "timer-of.h"
index c90a69c..b0fcbaa 100644 (file)
@@ -123,13 +123,6 @@ static struct clock_event_device integrator_clockevent = {
        .rating                 = 300,
 };
 
-static struct irqaction integrator_timer_irq = {
-       .name           = "timer",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = integrator_timer_interrupt,
-       .dev_id         = &integrator_clockevent,
-};
-
 static int integrator_clockevent_init(unsigned long inrate,
                                      void __iomem *base, int irq)
 {
@@ -149,7 +142,9 @@ static int integrator_clockevent_init(unsigned long inrate,
        timer_reload = rate / HZ;
        writel(ctrl, clkevt_base + TIMER_CTRL);
 
-       ret = setup_irq(irq, &integrator_timer_irq);
+       ret = request_irq(irq, integrator_timer_interrupt,
+                         IRQF_TIMER | IRQF_IRQPOLL, "timer",
+                         &integrator_clockevent);
        if (ret)
                return ret;
 
index 9e8b467..99f5510 100644 (file)
@@ -150,13 +150,6 @@ static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction meson6_timer_irq = {
-       .name           = "meson6_timer",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = meson6_timer_interrupt,
-       .dev_id         = &meson6_clockevent,
-};
-
 static int __init meson6_timer_init(struct device_node *node)
 {
        u32 val;
@@ -194,7 +187,9 @@ static int __init meson6_timer_init(struct device_node *node)
        /* Stop the timer A */
        meson6_clkevt_time_stop();
 
-       ret = setup_irq(irq, &meson6_timer_irq);
+       ret = request_irq(irq, meson6_timer_interrupt,
+                         IRQF_TIMER | IRQF_IRQPOLL, "meson6_timer",
+                         &meson6_clockevent);
        if (ret) {
                pr_warn("failed to setup irq %d\n", irq);
                return ret;
index bd63d34..59e11ca 100644 (file)
@@ -264,6 +264,7 @@ static int __init mchp_pit64b_init_mode(struct mchp_pit64b_timer *timer,
 
        if (!best_diff) {
                timer->mode |= MCHP_PIT64B_MR_SGCLK;
+               clk_set_rate(timer->gclk, gclk_round);
                goto done;
        }
 
index 7d48710..d01ff41 100644 (file)
@@ -114,12 +114,6 @@ static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction orion_clkevt_irq = {
-       .name           = "orion_event",
-       .flags          = IRQF_TIMER,
-       .handler        = orion_clkevt_irq_handler,
-};
-
 static int __init orion_timer_init(struct device_node *np)
 {
        unsigned long rate;
@@ -172,7 +166,8 @@ static int __init orion_timer_init(struct device_node *np)
        sched_clock_register(orion_read_sched_clock, 32, rate);
 
        /* setup timer1 as clockevent timer */
-       ret = setup_irq(irq, &orion_clkevt_irq);
+       ret = request_irq(irq, orion_clkevt_irq_handler, IRQF_TIMER,
+                         "orion_event", NULL);
        if (ret) {
                pr_err("%pOFn: unable to setup irq\n", np);
                return ret;
index 900fe73..ac97420 100644 (file)
@@ -135,8 +135,11 @@ static int __init owl_timer_init(struct device_node *node)
        }
 
        clk = of_clk_get(node, 0);
-       if (IS_ERR(clk))
-               return PTR_ERR(clk);
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               pr_err("Failed to get clock for clocksource (%d)\n", ret);
+               return ret;
+       }
 
        rate = clk_get_rate(clk);
 
@@ -144,8 +147,12 @@ static int __init owl_timer_init(struct device_node *node)
        owl_timer_set_enabled(owl_clksrc_base, true);
 
        sched_clock_register(owl_timer_sched_read, 32, rate);
-       clocksource_mmio_init(owl_clksrc_base + OWL_Tx_VAL, node->name,
-                             rate, 200, 32, clocksource_mmio_readl_up);
+       ret = clocksource_mmio_init(owl_clksrc_base + OWL_Tx_VAL, node->name,
+                                   rate, 200, 32, clocksource_mmio_readl_up);
+       if (ret) {
+               pr_err("Failed to register clocksource (%d)\n", ret);
+               return ret;
+       }
 
        owl_timer_reset(owl_clkevt_base);
 
index d4a9dcf..c5d4693 100644 (file)
@@ -165,14 +165,6 @@ static struct clocksource sirfsoc_clocksource = {
        .resume = sirfsoc_clocksource_resume,
 };
 
-static struct irqaction sirfsoc_timer_irq = {
-       .name = "sirfsoc_timer0",
-       .flags = IRQF_TIMER,
-       .irq = 0,
-       .handler = sirfsoc_timer_interrupt,
-       .dev_id = &sirfsoc_clockevent,
-};
-
 /* Overwrite weak default sched_clock with more precise one */
 static u64 notrace sirfsoc_read_sched_clock(void)
 {
@@ -190,6 +182,7 @@ static void __init sirfsoc_clockevent_init(void)
 static int __init sirfsoc_prima2_timer_init(struct device_node *np)
 {
        unsigned long rate;
+       unsigned int irq;
        struct clk *clk;
        int ret;
 
@@ -218,7 +211,7 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np)
                return -ENXIO;
        }
 
-       sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
+       irq = irq_of_parse_and_map(np, 0);
 
        writel_relaxed(rate / PRIMA2_CLOCK_FREQ / 2 - 1,
                sirfsoc_timer_base + SIRFSOC_TIMER_DIV);
@@ -234,7 +227,8 @@ static int __init sirfsoc_prima2_timer_init(struct device_node *np)
 
        sched_clock_register(sirfsoc_read_sched_clock, 64, PRIMA2_CLOCK_FREQ);
 
-       ret = setup_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
+       ret = request_irq(irq, sirfsoc_timer_interrupt, IRQF_TIMER,
+                         "sirfsoc_timer0", &sirfsoc_clockevent);
        if (ret) {
                pr_err("Failed to setup irq\n");
                return ret;
index 913a5d3..7ad0e5a 100644 (file)
@@ -143,13 +143,6 @@ static struct clock_event_device ckevt_pxa_osmr0 = {
        .resume                 = pxa_timer_resume,
 };
 
-static struct irqaction pxa_ost0_irq = {
-       .name           = "ost0",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = pxa_ost0_interrupt,
-       .dev_id         = &ckevt_pxa_osmr0,
-};
-
 static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
 {
        int ret;
@@ -161,7 +154,8 @@ static int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
 
        ckevt_pxa_osmr0.cpumask = cpumask_of(0);
 
-       ret = setup_irq(irq, &pxa_ost0_irq);
+       ret = request_irq(irq, pxa_ost0_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
+                         "ost0", &ckevt_pxa_osmr0);
        if (ret) {
                pr_err("Failed to setup irq\n");
                return ret;
index 9c84198..5cd0abf 100644 (file)
@@ -168,13 +168,6 @@ static struct clock_event_device sp804_clockevent = {
        .rating                 = 300,
 };
 
-static struct irqaction sp804_timer_irq = {
-       .name           = "timer",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = sp804_timer_interrupt,
-       .dev_id         = &sp804_clockevent,
-};
-
 int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name)
 {
        struct clock_event_device *evt = &sp804_clockevent;
@@ -200,7 +193,9 @@ int __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct
 
        writel(0, base + TIMER_CTRL);
 
-       setup_irq(irq, &sp804_timer_irq);
+       if (request_irq(irq, sp804_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
+                       "timer", &sp804_clockevent))
+               pr_err("%s: request_irq() failed\n", "timer");
        clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
 
        return 0;
index 269a994..2531eab 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * linux/arch/arm/plat-omap/dmtimer.c
  *
  *
  * Copyright (C) 2009 Texas Instruments
  * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * 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.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/cpu_pm.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/device.h>
@@ -109,6 +93,47 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
                                timer->context.tclr);
 }
 
+static void omap_timer_save_context(struct omap_dm_timer *timer)
+{
+       timer->context.tclr =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       timer->context.twer =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG);
+       timer->context.tldr =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_LOAD_REG);
+       timer->context.tmar =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG);
+       timer->context.tier = readl_relaxed(timer->irq_ena);
+       timer->context.tsicr =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_IF_CTRL_REG);
+}
+
+static int omap_timer_context_notifier(struct notifier_block *nb,
+                                      unsigned long cmd, void *v)
+{
+       struct omap_dm_timer *timer;
+
+       timer = container_of(nb, struct omap_dm_timer, nb);
+
+       switch (cmd) {
+       case CPU_CLUSTER_PM_ENTER:
+               if ((timer->capability & OMAP_TIMER_ALWON) ||
+                   !atomic_read(&timer->enabled))
+                       break;
+               omap_timer_save_context(timer);
+               break;
+       case CPU_CLUSTER_PM_ENTER_FAILED:
+       case CPU_CLUSTER_PM_EXIT:
+               if ((timer->capability & OMAP_TIMER_ALWON) ||
+                   !atomic_read(&timer->enabled))
+                       break;
+               omap_timer_restore_context(timer);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
 static int omap_dm_timer_reset(struct omap_dm_timer *timer)
 {
        u32 l, timeout = 100000;
@@ -138,35 +163,6 @@ static int omap_dm_timer_reset(struct omap_dm_timer *timer)
        return 0;
 }
 
-static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer)
-{
-       int ret;
-       struct clk *parent;
-
-       /*
-        * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
-        * do not call clk_get() for these devices.
-        */
-       if (!timer->fclk)
-               return -ENODEV;
-
-       parent = clk_get(&timer->pdev->dev, NULL);
-       if (IS_ERR(parent))
-               return -ENODEV;
-
-       /* Bail out if both clocks point to fck */
-       if (clk_is_match(parent, timer->fclk))
-               return 0;
-
-       ret = clk_set_parent(timer->fclk, parent);
-       if (ret < 0)
-               pr_err("%s: failed to set parent\n", __func__);
-
-       clk_put(parent);
-
-       return ret;
-}
-
 static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
        int ret;
@@ -225,21 +221,7 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 
 static void omap_dm_timer_enable(struct omap_dm_timer *timer)
 {
-       int c;
-
        pm_runtime_get_sync(&timer->pdev->dev);
-
-       if (!(timer->capability & OMAP_TIMER_ALWON)) {
-               if (timer->get_context_loss_count) {
-                       c = timer->get_context_loss_count(&timer->pdev->dev);
-                       if (c != timer->ctx_loss_count) {
-                               omap_timer_restore_context(timer);
-                               timer->ctx_loss_count = c;
-                       }
-               } else {
-                       omap_timer_restore_context(timer);
-               }
-       }
 }
 
 static void omap_dm_timer_disable(struct omap_dm_timer *timer)
@@ -276,9 +258,7 @@ static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
        __omap_dm_timer_enable_posted(timer);
        omap_dm_timer_disable(timer);
 
-       rc = omap_dm_timer_of_set_source(timer);
-       if (rc == -ENODEV)
-               return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
+       rc = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
 
        return rc;
 }
@@ -508,7 +488,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 
 int omap_dm_timer_trigger(struct omap_dm_timer *timer)
 {
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+       if (unlikely(!timer || !atomic_read(&timer->enabled))) {
                pr_err("%s: timer not available or enabled.\n", __func__);
                return -EINVAL;
        }
@@ -532,8 +512,6 @@ static int omap_dm_timer_start(struct omap_dm_timer *timer)
                omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
        }
 
-       /* Save the context */
-       timer->context.tclr = l;
        return 0;
 }
 
@@ -549,38 +527,19 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer)
 
        __omap_dm_timer_stop(timer, timer->posted, rate);
 
-       /*
-        * Since the register values are computed and written within
-        * __omap_dm_timer_stop, we need to use read to retrieve the
-        * context.
-        */
-       timer->context.tclr =
-                       omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        omap_dm_timer_disable(timer);
        return 0;
 }
 
-static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
+static int omap_dm_timer_set_load(struct omap_dm_timer *timer,
                                  unsigned int load)
 {
-       u32 l;
-
        if (unlikely(!timer))
                return -EINVAL;
 
        omap_dm_timer_enable(timer);
-       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       if (autoreload)
-               l |= OMAP_TIMER_CTRL_AR;
-       else
-               l &= ~OMAP_TIMER_CTRL_AR;
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
-       /* Save the context */
-       timer->context.tclr = l;
-       timer->context.tldr = load;
        omap_dm_timer_disable(timer);
        return 0;
 }
@@ -602,15 +561,12 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
        omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 
-       /* Save the context */
-       timer->context.tclr = l;
-       timer->context.tmar = match;
        omap_dm_timer_disable(timer);
        return 0;
 }
 
 static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
-                                int toggle, int trigger)
+                                int toggle, int trigger, int autoreload)
 {
        u32 l;
 
@@ -620,20 +576,34 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
        omap_dm_timer_enable(timer);
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
-              OMAP_TIMER_CTRL_PT | (0x03 << 10));
+              OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR);
        if (def_on)
                l |= OMAP_TIMER_CTRL_SCPWM;
        if (toggle)
                l |= OMAP_TIMER_CTRL_PT;
        l |= trigger << 10;
+       if (autoreload)
+               l |= OMAP_TIMER_CTRL_AR;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 
-       /* Save the context */
-       timer->context.tclr = l;
        omap_dm_timer_disable(timer);
        return 0;
 }
 
+static int omap_dm_timer_get_pwm_status(struct omap_dm_timer *timer)
+{
+       u32 l;
+
+       if (unlikely(!timer))
+               return -EINVAL;
+
+       omap_dm_timer_enable(timer);
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       omap_dm_timer_disable(timer);
+
+       return l;
+}
+
 static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
                                        int prescaler)
 {
@@ -651,8 +621,6 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
        }
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
 
-       /* Save the context */
-       timer->context.tclr = l;
        omap_dm_timer_disable(timer);
        return 0;
 }
@@ -666,9 +634,6 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
        omap_dm_timer_enable(timer);
        __omap_dm_timer_int_enable(timer, value);
 
-       /* Save the context */
-       timer->context.tier = value;
-       timer->context.twer = value;
        omap_dm_timer_disable(timer);
        return 0;
 }
@@ -696,9 +661,6 @@ static int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
 
-       /* Save the context */
-       timer->context.tier &= ~mask;
-       timer->context.twer &= ~mask;
        omap_dm_timer_disable(timer);
        return 0;
 }
@@ -707,7 +669,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 {
        unsigned int l;
 
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+       if (unlikely(!timer || !atomic_read(&timer->enabled))) {
                pr_err("%s: timer not available or enabled.\n", __func__);
                return 0;
        }
@@ -719,7 +681,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 
 static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
+       if (unlikely(!timer || !atomic_read(&timer->enabled)))
                return -EINVAL;
 
        __omap_dm_timer_write_status(timer, value);
@@ -729,7 +691,7 @@ static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int
 
 static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+       if (unlikely(!timer || !atomic_read(&timer->enabled))) {
                pr_err("%s: timer not iavailable or enabled.\n", __func__);
                return 0;
        }
@@ -739,7 +701,7 @@ static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 
 static int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 {
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+       if (unlikely(!timer || !atomic_read(&timer->enabled))) {
                pr_err("%s: timer not available or enabled.\n", __func__);
                return -EINVAL;
        }
@@ -767,6 +729,37 @@ int omap_dm_timers_active(void)
        return 0;
 }
 
+static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev)
+{
+       struct omap_dm_timer *timer = dev_get_drvdata(dev);
+
+       atomic_set(&timer->enabled, 0);
+
+       if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base)
+               return 0;
+
+       omap_timer_save_context(timer);
+
+       return 0;
+}
+
+static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev)
+{
+       struct omap_dm_timer *timer = dev_get_drvdata(dev);
+
+       if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base)
+               omap_timer_restore_context(timer);
+
+       atomic_set(&timer->enabled, 1);
+
+       return 0;
+}
+
+static const struct dev_pm_ops omap_dm_timer_pm_ops = {
+       SET_RUNTIME_PM_OPS(omap_dm_timer_runtime_suspend,
+                          omap_dm_timer_runtime_resume, NULL)
+};
+
 static const struct of_device_id omap_timer_match[];
 
 /**
@@ -808,6 +801,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        if (IS_ERR(timer->io_base))
                return PTR_ERR(timer->io_base);
 
+       platform_set_drvdata(pdev, timer);
+
        if (dev->of_node) {
                if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
                        timer->capability |= OMAP_TIMER_ALWON;
@@ -821,7 +816,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
                timer->id = pdev->id;
                timer->capability = pdata->timer_capability;
                timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
-               timer->get_context_loss_count = pdata->get_context_loss_count;
+       }
+
+       if (!(timer->capability & OMAP_TIMER_ALWON)) {
+               timer->nb.notifier_call = omap_timer_context_notifier;
+               cpu_pm_register_notifier(&timer->nb);
        }
 
        if (pdata)
@@ -875,6 +874,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
        list_for_each_entry(timer, &omap_timer_list, node)
                if (!strcmp(dev_name(&timer->pdev->dev),
                            dev_name(&pdev->dev))) {
+                       if (!(timer->capability & OMAP_TIMER_ALWON))
+                               cpu_pm_unregister_notifier(&timer->nb);
                        list_del(&timer->node);
                        ret = 0;
                        break;
@@ -903,6 +904,7 @@ static const struct omap_dm_timer_ops dmtimer_ops = {
        .set_load = omap_dm_timer_set_load,
        .set_match = omap_dm_timer_set_match,
        .set_pwm = omap_dm_timer_set_pwm,
+       .get_pwm_status = omap_dm_timer_get_pwm_status,
        .set_prescaler = omap_dm_timer_set_prescaler,
        .read_counter = omap_dm_timer_read_counter,
        .write_counter = omap_dm_timer_write_counter,
@@ -953,6 +955,7 @@ static struct platform_driver omap_dm_timer_driver = {
        .driver = {
                .name   = "omap_timer",
                .of_match_table = of_match_ptr(omap_timer_match),
+               .pm = &omap_dm_timer_pm_ops,
        },
 };
 
index 32adc30..37cba8d 100644 (file)
@@ -330,12 +330,6 @@ static irqreturn_t u300_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction u300_timer_irq = {
-       .name           = "U300 Timer Tick",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = u300_timer_interrupt,
-};
-
 /*
  * Override the global weak sched_clock symbol with this
  * local implementation which uses the clocksource to get some
@@ -420,7 +414,8 @@ static int __init u300_timer_init_of(struct device_node *np)
                u300_timer_base + U300_TIMER_APP_RGPT1);
 
        /* Set up the IRQ handler */
-       ret = setup_irq(irq, &u300_timer_irq);
+       ret = request_irq(irq, u300_timer_interrupt,
+                         IRQF_TIMER | IRQF_IRQPOLL, "U300 Timer Tick", NULL);
        if (ret)
                return ret;
 
index fef0bb4..7ad4a8b 100644 (file)
@@ -123,19 +123,13 @@ static struct clock_event_device clockevent_pit = {
        .rating         = 300,
 };
 
-static struct irqaction pit_timer_irq = {
-       .name           = "VF pit timer",
-       .flags          = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = pit_timer_interrupt,
-       .dev_id         = &clockevent_pit,
-};
-
 static int __init pit_clockevent_init(unsigned long rate, int irq)
 {
        __raw_writel(0, clkevt_base + PITTCTRL);
        __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG);
 
-       BUG_ON(setup_irq(irq, &pit_timer_irq));
+       BUG_ON(request_irq(irq, pit_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
+                          "VF pit timer", &clockevent_pit);
 
        clockevent_pit.cpumask = cpumask_of(0);
        clockevent_pit.irq = irq;
index bb424bc..a469b1b 100644 (file)
@@ -101,13 +101,6 @@ static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct irqaction irq = {
-       .name    = "vt8500_timer",
-       .flags   = IRQF_TIMER | IRQF_IRQPOLL,
-       .handler = vt8500_timer_interrupt,
-       .dev_id  = &clockevent,
-};
-
 static int __init vt8500_timer_init(struct device_node *np)
 {
        int timer_irq, ret;
@@ -139,7 +132,9 @@ static int __init vt8500_timer_init(struct device_node *np)
 
        clockevent.cpumask = cpumask_of(0);
 
-       ret = setup_irq(timer_irq, &irq);
+       ret = request_irq(timer_irq, vt8500_timer_interrupt,
+                         IRQF_TIMER | IRQF_IRQPOLL, "vt8500_timer",
+                         &clockevent);
        if (ret) {
                pr_err("%s: setup_irq failed for %s\n", __func__,
                                                        clockevent.name);
index c004156..ecaa356 100644 (file)
@@ -53,7 +53,6 @@ struct zevio_timer {
 
        struct clk *clk;
        struct clock_event_device clkevt;
-       struct irqaction clkevt_irq;
 
        char clocksource_name[64];
        char clockevent_name[64];
@@ -172,12 +171,12 @@ static int __init zevio_timer_add(struct device_node *node)
                /* Interrupt to occur when timer value matches 0 */
                writel(0, timer->base + IO_MATCH(TIMER_MATCH));
 
-               timer->clkevt_irq.name          = timer->clockevent_name;
-               timer->clkevt_irq.handler       = zevio_timer_interrupt;
-               timer->clkevt_irq.dev_id        = timer;
-               timer->clkevt_irq.flags         = IRQF_TIMER | IRQF_IRQPOLL;
-
-               setup_irq(irqnr, &timer->clkevt_irq);
+               if (request_irq(irqnr, zevio_timer_interrupt,
+                               IRQF_TIMER | IRQF_IRQPOLL,
+                               timer->clockevent_name, timer)) {
+                       pr_err("%s: request_irq() failed\n",
+                              timer->clockevent_name);
+               }
 
                clockevents_config_and_register(&timer->clkevt,
                                clk_get_rate(timer->clk), 0x0001, 0xffff);
index 17e67a8..9dab190 100644 (file)
@@ -31,6 +31,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
 /**
  * struct quad8_iio - IIO device private data structure
  * @counter:           instance of the counter_device
+ * @fck_prescaler:     array of filter clock prescaler configurations
  * @preset:            array of preset values
  * @count_mode:                array of count mode configurations
  * @quadrature_mode:   array of quadrature mode configurations
@@ -39,10 +40,12 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
  * @preset_enable:     array of set_to_preset_on_index attribute configurations
  * @synchronous_mode:  array of index function synchronous mode configurations
  * @index_polarity:    array of index function polarity configurations
+ * @cable_fault_enable:        differential encoder cable status enable configurations
  * @base:              base port address of the IIO device
  */
 struct quad8_iio {
        struct counter_device counter;
+       unsigned int fck_prescaler[QUAD8_NUM_COUNTERS];
        unsigned int preset[QUAD8_NUM_COUNTERS];
        unsigned int count_mode[QUAD8_NUM_COUNTERS];
        unsigned int quadrature_mode[QUAD8_NUM_COUNTERS];
@@ -51,11 +54,13 @@ struct quad8_iio {
        unsigned int preset_enable[QUAD8_NUM_COUNTERS];
        unsigned int synchronous_mode[QUAD8_NUM_COUNTERS];
        unsigned int index_polarity[QUAD8_NUM_COUNTERS];
+       unsigned int cable_fault_enable;
        unsigned int base;
 };
 
 #define QUAD8_REG_CHAN_OP 0x11
 #define QUAD8_REG_INDEX_INPUT_LEVELS 0x16
+#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17
 /* Borrow Toggle flip-flop */
 #define QUAD8_FLAG_BT BIT(0)
 /* Carry Toggle flip-flop */
@@ -84,6 +89,8 @@ struct quad8_iio {
 #define QUAD8_RLD_PRESET_CNTR 0x08
 /* Transfer Counter to Output Latch */
 #define QUAD8_RLD_CNTR_OUT 0x10
+/* Transfer Preset Register LSB to FCK Prescaler */
+#define QUAD8_RLD_PRESET_PSC 0x18
 #define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00
 #define QUAD8_CHAN_OP_RESET_COUNTERS 0x01
 #define QUAD8_CMR_QUADRATURE_X1 0x08
@@ -1140,6 +1147,119 @@ static ssize_t quad8_count_preset_enable_write(struct counter_device *counter,
        return len;
 }
 
+static ssize_t quad8_signal_cable_fault_read(struct counter_device *counter,
+                                            struct counter_signal *signal,
+                                            void *private, char *buf)
+{
+       const struct quad8_iio *const priv = counter->priv;
+       const size_t channel_id = signal->id / 2;
+       const bool disabled = !(priv->cable_fault_enable & BIT(channel_id));
+       unsigned int status;
+       unsigned int fault;
+
+       if (disabled)
+               return -EINVAL;
+
+       /* Logic 0 = cable fault */
+       status = inb(priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS);
+
+       /* Mask respective channel and invert logic */
+       fault = !(status & BIT(channel_id));
+
+       return sprintf(buf, "%u\n", fault);
+}
+
+static ssize_t quad8_signal_cable_fault_enable_read(
+       struct counter_device *counter, struct counter_signal *signal,
+       void *private, char *buf)
+{
+       const struct quad8_iio *const priv = counter->priv;
+       const size_t channel_id = signal->id / 2;
+       const unsigned int enb = !!(priv->cable_fault_enable & BIT(channel_id));
+
+       return sprintf(buf, "%u\n", enb);
+}
+
+static ssize_t quad8_signal_cable_fault_enable_write(
+       struct counter_device *counter, struct counter_signal *signal,
+       void *private, const char *buf, size_t len)
+{
+       struct quad8_iio *const priv = counter->priv;
+       const size_t channel_id = signal->id / 2;
+       bool enable;
+       int ret;
+       unsigned int cable_fault_enable;
+
+       ret = kstrtobool(buf, &enable);
+       if (ret)
+               return ret;
+
+       if (enable)
+               priv->cable_fault_enable |= BIT(channel_id);
+       else
+               priv->cable_fault_enable &= ~BIT(channel_id);
+
+       /* Enable is active low in Differential Encoder Cable Status register */
+       cable_fault_enable = ~priv->cable_fault_enable;
+
+       outb(cable_fault_enable, priv->base + QUAD8_DIFF_ENCODER_CABLE_STATUS);
+
+       return len;
+}
+
+static ssize_t quad8_signal_fck_prescaler_read(struct counter_device *counter,
+       struct counter_signal *signal, void *private, char *buf)
+{
+       const struct quad8_iio *const priv = counter->priv;
+       const size_t channel_id = signal->id / 2;
+
+       return sprintf(buf, "%u\n", priv->fck_prescaler[channel_id]);
+}
+
+static ssize_t quad8_signal_fck_prescaler_write(struct counter_device *counter,
+       struct counter_signal *signal, void *private, const char *buf,
+       size_t len)
+{
+       struct quad8_iio *const priv = counter->priv;
+       const size_t channel_id = signal->id / 2;
+       const int base_offset = priv->base + 2 * channel_id;
+       u8 prescaler;
+       int ret;
+
+       ret = kstrtou8(buf, 0, &prescaler);
+       if (ret)
+               return ret;
+
+       priv->fck_prescaler[channel_id] = prescaler;
+
+       /* Reset Byte Pointer */
+       outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
+
+       /* Set filter clock factor */
+       outb(prescaler, base_offset);
+       outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
+            base_offset + 1);
+
+       return len;
+}
+
+static const struct counter_signal_ext quad8_signal_ext[] = {
+       {
+               .name = "cable_fault",
+               .read = quad8_signal_cable_fault_read
+       },
+       {
+               .name = "cable_fault_enable",
+               .read = quad8_signal_cable_fault_enable_read,
+               .write = quad8_signal_cable_fault_enable_write
+       },
+       {
+               .name = "filter_clock_prescaler",
+               .read = quad8_signal_fck_prescaler_read,
+               .write = quad8_signal_fck_prescaler_write
+       }
+};
+
 static const struct counter_signal_ext quad8_index_ext[] = {
        COUNTER_SIGNAL_ENUM("index_polarity", &quad8_index_pol_enum),
        COUNTER_SIGNAL_ENUM_AVAILABLE("index_polarity", &quad8_index_pol_enum),
@@ -1147,9 +1267,11 @@ static const struct counter_signal_ext quad8_index_ext[] = {
        COUNTER_SIGNAL_ENUM_AVAILABLE("synchronous_mode", &quad8_syn_mode_enum)
 };
 
-#define        QUAD8_QUAD_SIGNAL(_id, _name) { \
-       .id = (_id),                    \
-       .name = (_name)                 \
+#define QUAD8_QUAD_SIGNAL(_id, _name) {                \
+       .id = (_id),                            \
+       .name = (_name),                        \
+       .ext = quad8_signal_ext,                \
+       .num_ext = ARRAY_SIZE(quad8_signal_ext) \
 }
 
 #define        QUAD8_INDEX_SIGNAL(_id, _name) {        \
@@ -1314,6 +1436,12 @@ static int quad8_probe(struct device *dev, unsigned int id)
                base_offset = base[id] + 2 * i;
                /* Reset Byte Pointer */
                outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
+               /* Reset filter clock factor */
+               outb(0, base_offset);
+               outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_PRESET_PSC,
+                    base_offset + 1);
+               /* Reset Byte Pointer */
+               outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1);
                /* Reset Preset Register */
                for (j = 0; j < 3; j++)
                        outb(0x00, base_offset);
@@ -1328,6 +1456,8 @@ static int quad8_probe(struct device *dev, unsigned int id)
                /* Disable index function; negative index polarity */
                outb(QUAD8_CTR_IDR, base_offset + 1);
        }
+       /* Disable Differential Encoder Cable Status for all channels */
+       outb(0xFF, base[id] + QUAD8_DIFF_ENCODER_CABLE_STATUS);
        /* Enable all counters */
        outb(QUAD8_CHAN_OP_ENABLE_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);
 
index 3eafcce..ef2a974 100644 (file)
@@ -8,10 +8,10 @@
  *
  */
 #include <linux/counter.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/types.h>
 #include <linux/mfd/stm32-timers.h>
+#include <linux/mod_devicetable.h>
 #include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 
 #define TIM_CCMR_CCXS  (BIT(8) | BIT(0))
 #define TIM_CCER_MASK  (TIM_CCER_CC1P | TIM_CCER_CC1NP | \
                         TIM_CCER_CC2P | TIM_CCER_CC2NP)
 
+struct stm32_timer_regs {
+       u32 cr1;
+       u32 cnt;
+       u32 smcr;
+       u32 arr;
+};
+
 struct stm32_timer_cnt {
        struct counter_device counter;
        struct regmap *regmap;
        struct clk *clk;
        u32 ceiling;
+       bool enabled;
+       struct stm32_timer_regs bak;
 };
 
 /**
@@ -224,6 +233,9 @@ static ssize_t stm32_count_enable_write(struct counter_device *counter,
                        clk_disable(priv->clk);
        }
 
+       /* Keep enabled state to properly handle low power states */
+       priv->enabled = enable;
+
        return len;
 }
 
@@ -358,10 +370,59 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev)
        priv->counter.num_signals = ARRAY_SIZE(stm32_signals);
        priv->counter.priv = priv;
 
+       platform_set_drvdata(pdev, priv);
+
        /* Register Counter device */
        return devm_counter_register(dev, &priv->counter);
 }
 
+static int __maybe_unused stm32_timer_cnt_suspend(struct device *dev)
+{
+       struct stm32_timer_cnt *priv = dev_get_drvdata(dev);
+
+       /* Only take care of enabled counter: don't disturb other MFD child */
+       if (priv->enabled) {
+               /* Backup registers that may get lost in low power mode */
+               regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr);
+               regmap_read(priv->regmap, TIM_ARR, &priv->bak.arr);
+               regmap_read(priv->regmap, TIM_CNT, &priv->bak.cnt);
+               regmap_read(priv->regmap, TIM_CR1, &priv->bak.cr1);
+
+               /* Disable the counter */
+               regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+               clk_disable(priv->clk);
+       }
+
+       return pinctrl_pm_select_sleep_state(dev);
+}
+
+static int __maybe_unused stm32_timer_cnt_resume(struct device *dev)
+{
+       struct stm32_timer_cnt *priv = dev_get_drvdata(dev);
+       int ret;
+
+       ret = pinctrl_pm_select_default_state(dev);
+       if (ret)
+               return ret;
+
+       if (priv->enabled) {
+               clk_enable(priv->clk);
+
+               /* Restore registers that may have been lost */
+               regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr);
+               regmap_write(priv->regmap, TIM_ARR, priv->bak.arr);
+               regmap_write(priv->regmap, TIM_CNT, priv->bak.cnt);
+
+               /* Also re-enables the counter */
+               regmap_write(priv->regmap, TIM_CR1, priv->bak.cr1);
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(stm32_timer_cnt_pm_ops, stm32_timer_cnt_suspend,
+                        stm32_timer_cnt_resume);
+
 static const struct of_device_id stm32_timer_cnt_of_match[] = {
        { .compatible = "st,stm32-timer-counter", },
        {},
@@ -373,6 +434,7 @@ static struct platform_driver stm32_timer_cnt_driver = {
        .driver = {
                .name = "stm32-timer-counter",
                .of_match_table = stm32_timer_cnt_of_match,
+               .pm = &stm32_timer_cnt_pm_ops,
        },
 };
 module_platform_driver(stm32_timer_cnt_driver);
index 3858d86..15c1a12 100644 (file)
@@ -128,7 +128,7 @@ config ARM_OMAP2PLUS_CPUFREQ
 
 config ARM_QCOM_CPUFREQ_NVMEM
        tristate "Qualcomm nvmem based CPUFreq"
-       depends on ARM64
+       depends on ARCH_QCOM
        depends on QCOM_QFPROM
        depends on QCOM_SMEM
        select PM_OPP
index a652838..62502d0 100644 (file)
@@ -25,7 +25,7 @@ config X86_PCC_CPUFREQ
          This driver adds support for the PCC interface.
 
          For details, take a look at:
-         <file:Documentation/cpu-freq/pcc-cpufreq.txt>.
+         <file:Documentation/admin-guide/pm/cpufreq_drivers.rst>.
 
          To compile this driver as a module, choose M here: the
          module will be called pcc-cpufreq.
index d6f7df3..289e8ce 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/msr.h>
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
 MODULE_DESCRIPTION("ACPI Processor P-States Driver");
@@ -991,8 +992,8 @@ late_initcall(acpi_cpufreq_init);
 module_exit(acpi_cpufreq_exit);
 
 static const struct x86_cpu_id acpi_cpufreq_ids[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_ACPI),
-       X86_FEATURE_MATCH(X86_FEATURE_HW_PSTATE),
+       X86_MATCH_FEATURE(X86_FEATURE_ACPI, NULL),
+       X86_MATCH_FEATURE(X86_FEATURE_HW_PSTATE, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, acpi_cpufreq_ids);
index e2df9d1..f7c4206 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/msr.h>
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 #include "cpufreq_ondemand.h"
 
@@ -144,7 +145,7 @@ static void __exit amd_freq_sensitivity_exit(void)
 module_exit(amd_freq_sensitivity_exit);
 
 static const struct x86_cpu_id amd_freq_sensitivity_ids[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_PROC_FEEDBACK),
+       X86_MATCH_FEATURE(X86_FEATURE_PROC_FEEDBACK, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, amd_freq_sensitivity_ids);
index f2ae9cd..cb9db16 100644 (file)
@@ -141,6 +141,11 @@ static const struct of_device_id blacklist[] __initconst = {
        { .compatible = "ti,dra7", },
        { .compatible = "ti,omap3", },
 
+       { .compatible = "qcom,ipq8064", },
+       { .compatible = "qcom,apq8064", },
+       { .compatible = "qcom,msm8974", },
+       { .compatible = "qcom,msm8960", },
+
        { }
 };
 
index d2b5f06..26fe8df 100644 (file)
@@ -363,6 +363,10 @@ static int dt_cpufreq_probe(struct platform_device *pdev)
                dt_cpufreq_driver.resume = data->resume;
                if (data->suspend)
                        dt_cpufreq_driver.suspend = data->suspend;
+               if (data->get_intermediate) {
+                       dt_cpufreq_driver.target_intermediate = data->target_intermediate;
+                       dt_cpufreq_driver.get_intermediate = data->get_intermediate;
+               }
        }
 
        ret = cpufreq_register_driver(&dt_cpufreq_driver);
index a5a45b5..28c8af7 100644 (file)
@@ -14,6 +14,10 @@ struct cpufreq_policy;
 struct cpufreq_dt_platform_data {
        bool have_governor_per_policy;
 
+       unsigned int    (*get_intermediate)(struct cpufreq_policy *policy,
+                                           unsigned int index);
+       int             (*target_intermediate)(struct cpufreq_policy *policy,
+                                              unsigned int index);
        int (*suspend)(struct cpufreq_policy *policy);
        int (*resume)(struct cpufreq_policy *policy);
 };
index cbe6c94..045f9fe 100644 (file)
@@ -1076,9 +1076,17 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
                        pol = policy->last_policy;
                } else if (def_gov) {
                        pol = cpufreq_parse_policy(def_gov->name);
-               } else {
-                       return -ENODATA;
+                       /*
+                        * In case the default governor is neiter "performance"
+                        * nor "powersave", fall back to the initial policy
+                        * value set by the driver.
+                        */
+                       if (pol == CPUFREQ_POLICY_UNKNOWN)
+                               pol = policy->policy;
                }
+               if (pol != CPUFREQ_POLICY_PERFORMANCE &&
+                   pol != CPUFREQ_POLICY_POWERSAVE)
+                       return -ENODATA;
        }
 
        return cpufreq_set_policy(policy, gov, pol);
@@ -1725,6 +1733,26 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu)
 }
 EXPORT_SYMBOL(cpufreq_quick_get_max);
 
+/**
+ * cpufreq_get_hw_max_freq - get the max hardware frequency of the CPU
+ * @cpu: CPU number
+ *
+ * The default return value is the max_freq field of cpuinfo.
+ */
+__weak unsigned int cpufreq_get_hw_max_freq(unsigned int cpu)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+       unsigned int ret_freq = 0;
+
+       if (policy) {
+               ret_freq = policy->cpuinfo.max_freq;
+               cpufreq_cpu_put(policy);
+       }
+
+       return ret_freq;
+}
+EXPORT_SYMBOL(cpufreq_get_hw_max_freq);
+
 static unsigned int __cpufreq_get(struct cpufreq_policy *policy)
 {
        if (unlikely(policy_is_inactive(policy)))
index f9bcf0f..94d959a 100644 (file)
@@ -90,35 +90,35 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
        if (policy->fast_switch_enabled)
                return 0;
 
-       len += snprintf(buf + len, PAGE_SIZE - len, "   From  :    To\n");
-       len += snprintf(buf + len, PAGE_SIZE - len, "         : ");
+       len += scnprintf(buf + len, PAGE_SIZE - len, "   From  :    To\n");
+       len += scnprintf(buf + len, PAGE_SIZE - len, "         : ");
        for (i = 0; i < stats->state_num; i++) {
                if (len >= PAGE_SIZE)
                        break;
-               len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
+               len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ",
                                stats->freq_table[i]);
        }
        if (len >= PAGE_SIZE)
                return PAGE_SIZE;
 
-       len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+       len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
 
        for (i = 0; i < stats->state_num; i++) {
                if (len >= PAGE_SIZE)
                        break;
 
-               len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
+               len += scnprintf(buf + len, PAGE_SIZE - len, "%9u: ",
                                stats->freq_table[i]);
 
                for (j = 0; j < stats->state_num; j++) {
                        if (len >= PAGE_SIZE)
                                break;
-                       len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
+                       len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ",
                                        stats->trans_table[i*stats->max_state+j]);
                }
                if (len >= PAGE_SIZE)
                        break;
-               len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+               len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
        }
 
        if (len >= PAGE_SIZE) {
index 45c18c6..776a58b 100644 (file)
@@ -385,7 +385,7 @@ static struct cpufreq_driver eps_driver = {
 /* This driver will work only on Centaur C7 processors with
  * Enhanced SpeedStep/PowerSaver registers */
 static const struct x86_cpu_id eps_cpu_id[] = {
-       { X86_VENDOR_CENTAUR, 6, X86_MODEL_ANY, X86_FEATURE_EST },
+       X86_MATCH_VENDOR_FAM_FEATURE(CENTAUR, 6, X86_FEATURE_EST, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, eps_cpu_id);
index 2242541..4ce5eb3 100644 (file)
@@ -198,7 +198,7 @@ static struct cpufreq_driver elanfreq_driver = {
 };
 
 static const struct x86_cpu_id elan_id[] = {
-       { X86_VENDOR_AMD, 4, 10, },
+       X86_MATCH_VENDOR_FAM_MODEL(AMD, 4, 10, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, elan_id);
index 6cb8193..de206d2 100644 (file)
@@ -19,6 +19,8 @@
 #define IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK     (0xf << 8)
 #define OCOTP_CFG3_MKT_SEGMENT_SHIFT    6
 #define OCOTP_CFG3_MKT_SEGMENT_MASK     (0x3 << 6)
+#define IMX8MP_OCOTP_CFG3_MKT_SEGMENT_SHIFT    5
+#define IMX8MP_OCOTP_CFG3_MKT_SEGMENT_MASK     (0x3 << 5)
 
 /* cpufreq-dt device registered by imx-cpufreq-dt */
 static struct platform_device *cpufreq_dt_pdev;
@@ -31,6 +33,9 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
        int speed_grade, mkt_segment;
        int ret;
 
+       if (!of_find_property(cpu_dev->of_node, "cpu-supply", NULL))
+               return -ENODEV;
+
        ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value);
        if (ret)
                return ret;
@@ -42,7 +47,13 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
        else
                speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK)
                              >> OCOTP_CFG3_SPEED_GRADE_SHIFT;
-       mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
+
+       if (of_machine_is_compatible("fsl,imx8mp"))
+               mkt_segment = (cell_value & IMX8MP_OCOTP_CFG3_MKT_SEGMENT_MASK)
+                              >> IMX8MP_OCOTP_CFG3_MKT_SEGMENT_SHIFT;
+       else
+               mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK)
+                              >> OCOTP_CFG3_MKT_SEGMENT_SHIFT;
 
        /*
         * Early samples without fuses written report "0 0" which may NOT
index 648a09a..fdb2fff 100644 (file)
@@ -216,31 +216,41 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
 #define OCOTP_CFG3_SPEED_996MHZ                0x2
 #define OCOTP_CFG3_SPEED_852MHZ                0x1
 
-static void imx6q_opp_check_speed_grading(struct device *dev)
+static int imx6q_opp_check_speed_grading(struct device *dev)
 {
        struct device_node *np;
        void __iomem *base;
        u32 val;
+       int ret;
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
-       if (!np)
-               return;
+       if (of_find_property(dev->of_node, "nvmem-cells", NULL)) {
+               ret = nvmem_cell_read_u32(dev, "speed_grade", &val);
+               if (ret)
+                       return ret;
+       } else {
+               np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
+               if (!np)
+                       return -ENOENT;
 
-       base = of_iomap(np, 0);
-       if (!base) {
-               dev_err(dev, "failed to map ocotp\n");
-               goto put_node;
+               base = of_iomap(np, 0);
+               of_node_put(np);
+               if (!base) {
+                       dev_err(dev, "failed to map ocotp\n");
+                       return -EFAULT;
+               }
+
+               /*
+                * SPEED_GRADING[1:0] defines the max speed of ARM:
+                * 2b'11: 1200000000Hz;
+                * 2b'10: 996000000Hz;
+                * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
+                * 2b'00: 792000000Hz;
+                * We need to set the max speed of ARM according to fuse map.
+                */
+               val = readl_relaxed(base + OCOTP_CFG3);
+               iounmap(base);
        }
 
-       /*
-        * SPEED_GRADING[1:0] defines the max speed of ARM:
-        * 2b'11: 1200000000Hz;
-        * 2b'10: 996000000Hz;
-        * 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
-        * 2b'00: 792000000Hz;
-        * We need to set the max speed of ARM according to fuse map.
-        */
-       val = readl_relaxed(base + OCOTP_CFG3);
        val >>= OCOTP_CFG3_SPEED_SHIFT;
        val &= 0x3;
 
@@ -257,9 +267,8 @@ static void imx6q_opp_check_speed_grading(struct device *dev)
                        if (dev_pm_opp_disable(dev, 1200000000))
                                dev_warn(dev, "failed to disable 1.2GHz OPP\n");
        }
-       iounmap(base);
-put_node:
-       of_node_put(np);
+
+       return 0;
 }
 
 #define OCOTP_CFG3_6UL_SPEED_696MHZ    0x2
@@ -281,6 +290,9 @@ static int imx6ul_opp_check_speed_grading(struct device *dev)
 
                np = of_find_compatible_node(NULL, NULL, "fsl,imx6ul-ocotp");
                if (!np)
+                       np = of_find_compatible_node(NULL, NULL,
+                                                    "fsl,imx6ull-ocotp");
+               if (!np)
                        return -ENOENT;
 
                base = of_iomap(np, 0);
@@ -378,23 +390,22 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
                goto put_reg;
        }
 
+       /* Because we have added the OPPs here, we must free them */
+       free_opp = true;
+
        if (of_machine_is_compatible("fsl,imx6ul") ||
            of_machine_is_compatible("fsl,imx6ull")) {
                ret = imx6ul_opp_check_speed_grading(cpu_dev);
-               if (ret) {
-                       if (ret == -EPROBE_DEFER)
-                               goto put_node;
-
+       } else {
+               ret = imx6q_opp_check_speed_grading(cpu_dev);
+       }
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
                        dev_err(cpu_dev, "failed to read ocotp: %d\n",
                                ret);
-                       goto put_node;
-               }
-       } else {
-               imx6q_opp_check_speed_grading(cpu_dev);
+               goto out_free_opp;
        }
 
-       /* Because we have added the OPPs here, we must free them */
-       free_opp = true;
        num = dev_pm_opp_get_opp_count(cpu_dev);
        if (num < 0) {
                ret = num;
index c81e1ff..4d1e25d 100644 (file)
@@ -922,6 +922,7 @@ static void intel_pstate_update_limits(unsigned int cpu)
         */
        if (global.turbo_disabled_mf != global.turbo_disabled) {
                global.turbo_disabled_mf = global.turbo_disabled;
+               arch_set_max_freq_ratio(global.turbo_disabled);
                for_each_possible_cpu(cpu)
                        intel_pstate_update_max_freq(cpu);
        } else {
@@ -1908,51 +1909,51 @@ static const struct pstate_funcs knl_funcs = {
        .get_val = core_get_val,
 };
 
-#define ICPU(model, policy) \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_APERFMPERF,\
-                       (unsigned long)&policy }
+#define X86_MATCH(model, policy)                                        \
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_##model, \
+                                          X86_FEATURE_APERFMPERF, &policy)
 
 static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
-       ICPU(INTEL_FAM6_SANDYBRIDGE,            core_funcs),
-       ICPU(INTEL_FAM6_SANDYBRIDGE_X,          core_funcs),
-       ICPU(INTEL_FAM6_ATOM_SILVERMONT,        silvermont_funcs),
-       ICPU(INTEL_FAM6_IVYBRIDGE,              core_funcs),
-       ICPU(INTEL_FAM6_HASWELL,                core_funcs),
-       ICPU(INTEL_FAM6_BROADWELL,              core_funcs),
-       ICPU(INTEL_FAM6_IVYBRIDGE_X,            core_funcs),
-       ICPU(INTEL_FAM6_HASWELL_X,              core_funcs),
-       ICPU(INTEL_FAM6_HASWELL_L,              core_funcs),
-       ICPU(INTEL_FAM6_HASWELL_G,              core_funcs),
-       ICPU(INTEL_FAM6_BROADWELL_G,            core_funcs),
-       ICPU(INTEL_FAM6_ATOM_AIRMONT,           airmont_funcs),
-       ICPU(INTEL_FAM6_SKYLAKE_L,              core_funcs),
-       ICPU(INTEL_FAM6_BROADWELL_X,            core_funcs),
-       ICPU(INTEL_FAM6_SKYLAKE,                core_funcs),
-       ICPU(INTEL_FAM6_BROADWELL_D,            core_funcs),
-       ICPU(INTEL_FAM6_XEON_PHI_KNL,           knl_funcs),
-       ICPU(INTEL_FAM6_XEON_PHI_KNM,           knl_funcs),
-       ICPU(INTEL_FAM6_ATOM_GOLDMONT,          core_funcs),
-       ICPU(INTEL_FAM6_ATOM_GOLDMONT_PLUS,     core_funcs),
-       ICPU(INTEL_FAM6_SKYLAKE_X,              core_funcs),
+       X86_MATCH(SANDYBRIDGE,          core_funcs),
+       X86_MATCH(SANDYBRIDGE_X,        core_funcs),
+       X86_MATCH(ATOM_SILVERMONT,      silvermont_funcs),
+       X86_MATCH(IVYBRIDGE,            core_funcs),
+       X86_MATCH(HASWELL,              core_funcs),
+       X86_MATCH(BROADWELL,            core_funcs),
+       X86_MATCH(IVYBRIDGE_X,          core_funcs),
+       X86_MATCH(HASWELL_X,            core_funcs),
+       X86_MATCH(HASWELL_L,            core_funcs),
+       X86_MATCH(HASWELL_G,            core_funcs),
+       X86_MATCH(BROADWELL_G,          core_funcs),
+       X86_MATCH(ATOM_AIRMONT,         airmont_funcs),
+       X86_MATCH(SKYLAKE_L,            core_funcs),
+       X86_MATCH(BROADWELL_X,          core_funcs),
+       X86_MATCH(SKYLAKE,              core_funcs),
+       X86_MATCH(BROADWELL_D,          core_funcs),
+       X86_MATCH(XEON_PHI_KNL,         knl_funcs),
+       X86_MATCH(XEON_PHI_KNM,         knl_funcs),
+       X86_MATCH(ATOM_GOLDMONT,        core_funcs),
+       X86_MATCH(ATOM_GOLDMONT_PLUS,   core_funcs),
+       X86_MATCH(SKYLAKE_X,            core_funcs),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
 
 static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] __initconst = {
-       ICPU(INTEL_FAM6_BROADWELL_D, core_funcs),
-       ICPU(INTEL_FAM6_BROADWELL_X, core_funcs),
-       ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs),
+       X86_MATCH(BROADWELL_D,          core_funcs),
+       X86_MATCH(BROADWELL_X,          core_funcs),
+       X86_MATCH(SKYLAKE_X,            core_funcs),
        {}
 };
 
 static const struct x86_cpu_id intel_pstate_cpu_ee_disable_ids[] = {
-       ICPU(INTEL_FAM6_KABYLAKE, core_funcs),
+       X86_MATCH(KABYLAKE,             core_funcs),
        {}
 };
 
 static const struct x86_cpu_id intel_pstate_hwp_boost_ids[] = {
-       ICPU(INTEL_FAM6_SKYLAKE_X, core_funcs),
-       ICPU(INTEL_FAM6_SKYLAKE, core_funcs),
+       X86_MATCH(SKYLAKE_X,            core_funcs),
+       X86_MATCH(SKYLAKE,              core_funcs),
        {}
 };
 
@@ -2155,15 +2156,19 @@ static void intel_pstate_adjust_policy_max(struct cpudata *cpu,
        }
 }
 
-static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy)
+static void intel_pstate_verify_cpu_policy(struct cpudata *cpu,
+                                          struct cpufreq_policy_data *policy)
 {
-       struct cpudata *cpu = all_cpu_data[policy->cpu];
-
        update_turbo_state();
        cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
                                     intel_pstate_get_max_freq(cpu));
 
        intel_pstate_adjust_policy_max(cpu, policy);
+}
+
+static int intel_pstate_verify_policy(struct cpufreq_policy_data *policy)
+{
+       intel_pstate_verify_cpu_policy(all_cpu_data[policy->cpu], policy);
 
        return 0;
 }
@@ -2243,10 +2248,11 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
        if (ret)
                return ret;
 
-       if (IS_ENABLED(CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE))
-               policy->policy = CPUFREQ_POLICY_PERFORMANCE;
-       else
-               policy->policy = CPUFREQ_POLICY_POWERSAVE;
+       /*
+        * Set the policy to powersave to provide a valid fallback value in case
+        * the default cpufreq governor is neither powersave nor performance.
+        */
+       policy->policy = CPUFREQ_POLICY_POWERSAVE;
 
        return 0;
 }
@@ -2268,12 +2274,7 @@ static int intel_cpufreq_verify_policy(struct cpufreq_policy_data *policy)
 {
        struct cpudata *cpu = all_cpu_data[policy->cpu];
 
-       update_turbo_state();
-       cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
-                                    intel_pstate_get_max_freq(cpu));
-
-       intel_pstate_adjust_policy_max(cpu, policy);
-
+       intel_pstate_verify_cpu_policy(cpu, policy);
        intel_pstate_update_perf_limits(cpu, policy->min, policy->max);
 
        return 0;
@@ -2725,13 +2726,14 @@ static inline void intel_pstate_request_control_from_smm(void) {}
 
 #define INTEL_PSTATE_HWP_BROADWELL     0x01
 
-#define ICPU_HWP(model, hwp_mode) \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_HWP, hwp_mode }
+#define X86_MATCH_HWP(model, hwp_mode)                                 \
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_##model, \
+                                          X86_FEATURE_HWP, hwp_mode)
 
 static const struct x86_cpu_id hwp_support_ids[] __initconst = {
-       ICPU_HWP(INTEL_FAM6_BROADWELL_X, INTEL_PSTATE_HWP_BROADWELL),
-       ICPU_HWP(INTEL_FAM6_BROADWELL_D, INTEL_PSTATE_HWP_BROADWELL),
-       ICPU_HWP(X86_MODEL_ANY, 0),
+       X86_MATCH_HWP(BROADWELL_X,      INTEL_PSTATE_HWP_BROADWELL),
+       X86_MATCH_HWP(BROADWELL_D,      INTEL_PSTATE_HWP_BROADWELL),
+       X86_MATCH_HWP(ANY,              0),
        {}
 };
 
index 92d92e6..123fb00 100644 (file)
@@ -910,7 +910,7 @@ static struct cpufreq_driver longhaul_driver = {
 };
 
 static const struct x86_cpu_id longhaul_id[] = {
-       { X86_VENDOR_CENTAUR, 6 },
+       X86_MATCH_VENDOR_FAM(CENTAUR, 6, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, longhaul_id);
index 0b08be8..1caaec7 100644 (file)
@@ -281,8 +281,7 @@ static struct cpufreq_driver longrun_driver = {
 };
 
 static const struct x86_cpu_id longrun_ids[] = {
-       { X86_VENDOR_TRANSMETA, X86_FAMILY_ANY, X86_MODEL_ANY,
-         X86_FEATURE_LONGRUN },
+       X86_MATCH_VENDOR_FEATURE(TRANSMETA, X86_FEATURE_LONGRUN, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, longrun_ids);
index efc0b46..bb61677 100644 (file)
@@ -231,7 +231,7 @@ static struct cpufreq_driver p4clockmod_driver = {
 };
 
 static const struct x86_cpu_id cpufreq_p4_id[] = {
-       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_ACC },
+       X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_ACC, NULL),
        {}
 };
 
index 0196f81..41eefef 100644 (file)
@@ -258,8 +258,8 @@ static struct cpufreq_driver powernow_k6_driver = {
 };
 
 static const struct x86_cpu_id powernow_k6_ids[] = {
-       { X86_VENDOR_AMD, 5, 12 },
-       { X86_VENDOR_AMD, 5, 13 },
+       X86_MATCH_VENDOR_FAM_MODEL(AMD, 5, 12, NULL),
+       X86_MATCH_VENDOR_FAM_MODEL(AMD, 5, 13, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, powernow_k6_ids);
index 5e5171d..5d515fc 100644 (file)
@@ -109,7 +109,7 @@ static int check_fsb(unsigned int fsbspeed)
 }
 
 static const struct x86_cpu_id powernow_k7_cpuids[] = {
-       { X86_VENDOR_AMD, 6, },
+       X86_MATCH_VENDOR_FAM(AMD, 6, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);
index 2db2f17..3984959 100644 (file)
@@ -452,7 +452,7 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
 
 static const struct x86_cpu_id powernow_k8_ids[] = {
        /* IO based frequency switching */
-       { X86_VENDOR_AMD, 0xf },
+       X86_MATCH_VENDOR_FAM(AMD, 0xf, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, powernow_k8_ids);
index f0d2d50..a1b8238 100644 (file)
@@ -49,12 +49,14 @@ struct qcom_cpufreq_drv;
 struct qcom_cpufreq_match_data {
        int (*get_version)(struct device *cpu_dev,
                           struct nvmem_cell *speedbin_nvmem,
+                          char **pvs_name,
                           struct qcom_cpufreq_drv *drv);
        const char **genpd_names;
 };
 
 struct qcom_cpufreq_drv {
-       struct opp_table **opp_tables;
+       struct opp_table **names_opp_tables;
+       struct opp_table **hw_opp_tables;
        struct opp_table **genpd_opp_tables;
        u32 versions;
        const struct qcom_cpufreq_match_data *data;
@@ -62,6 +64,84 @@ struct qcom_cpufreq_drv {
 
 static struct platform_device *cpufreq_dt_pdev, *cpufreq_pdev;
 
+static void get_krait_bin_format_a(struct device *cpu_dev,
+                                         int *speed, int *pvs, int *pvs_ver,
+                                         struct nvmem_cell *pvs_nvmem, u8 *buf)
+{
+       u32 pte_efuse;
+
+       pte_efuse = *((u32 *)buf);
+
+       *speed = pte_efuse & 0xf;
+       if (*speed == 0xf)
+               *speed = (pte_efuse >> 4) & 0xf;
+
+       if (*speed == 0xf) {
+               *speed = 0;
+               dev_warn(cpu_dev, "Speed bin: Defaulting to %d\n", *speed);
+       } else {
+               dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
+       }
+
+       *pvs = (pte_efuse >> 10) & 0x7;
+       if (*pvs == 0x7)
+               *pvs = (pte_efuse >> 13) & 0x7;
+
+       if (*pvs == 0x7) {
+               *pvs = 0;
+               dev_warn(cpu_dev, "PVS bin: Defaulting to %d\n", *pvs);
+       } else {
+               dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
+       }
+}
+
+static void get_krait_bin_format_b(struct device *cpu_dev,
+                                         int *speed, int *pvs, int *pvs_ver,
+                                         struct nvmem_cell *pvs_nvmem, u8 *buf)
+{
+       u32 pte_efuse, redundant_sel;
+
+       pte_efuse = *((u32 *)buf);
+       redundant_sel = (pte_efuse >> 24) & 0x7;
+
+       *pvs_ver = (pte_efuse >> 4) & 0x3;
+
+       switch (redundant_sel) {
+       case 1:
+               *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
+               *speed = (pte_efuse >> 27) & 0xf;
+               break;
+       case 2:
+               *pvs = (pte_efuse >> 27) & 0xf;
+               *speed = pte_efuse & 0x7;
+               break;
+       default:
+               /* 4 bits of PVS are in efuse register bits 31, 8-6. */
+               *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
+               *speed = pte_efuse & 0x7;
+       }
+
+       /* Check SPEED_BIN_BLOW_STATUS */
+       if (pte_efuse & BIT(3)) {
+               dev_dbg(cpu_dev, "Speed bin: %d\n", *speed);
+       } else {
+               dev_warn(cpu_dev, "Speed bin not set. Defaulting to 0!\n");
+               *speed = 0;
+       }
+
+       /* Check PVS_BLOW_STATUS */
+       pte_efuse = *(((u32 *)buf) + 4);
+       pte_efuse &= BIT(21);
+       if (pte_efuse) {
+               dev_dbg(cpu_dev, "PVS bin: %d\n", *pvs);
+       } else {
+               dev_warn(cpu_dev, "PVS bin not set. Defaulting to 0!\n");
+               *pvs = 0;
+       }
+
+       dev_dbg(cpu_dev, "PVS version: %d\n", *pvs_ver);
+}
+
 static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
 {
        size_t len;
@@ -93,11 +173,13 @@ static enum _msm8996_version qcom_cpufreq_get_msm_id(void)
 
 static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
                                          struct nvmem_cell *speedbin_nvmem,
+                                         char **pvs_name,
                                          struct qcom_cpufreq_drv *drv)
 {
        size_t len;
        u8 *speedbin;
        enum _msm8996_version msm8996_version;
+       *pvs_name = NULL;
 
        msm8996_version = qcom_cpufreq_get_msm_id();
        if (NUM_OF_MSM8996_VERSIONS == msm8996_version) {
@@ -125,10 +207,51 @@ static int qcom_cpufreq_kryo_name_version(struct device *cpu_dev,
        return 0;
 }
 
+static int qcom_cpufreq_krait_name_version(struct device *cpu_dev,
+                                          struct nvmem_cell *speedbin_nvmem,
+                                          char **pvs_name,
+                                          struct qcom_cpufreq_drv *drv)
+{
+       int speed = 0, pvs = 0, pvs_ver = 0;
+       u8 *speedbin;
+       size_t len;
+
+       speedbin = nvmem_cell_read(speedbin_nvmem, &len);
+
+       if (IS_ERR(speedbin))
+               return PTR_ERR(speedbin);
+
+       switch (len) {
+       case 4:
+               get_krait_bin_format_a(cpu_dev, &speed, &pvs, &pvs_ver,
+                                      speedbin_nvmem, speedbin);
+               break;
+       case 8:
+               get_krait_bin_format_b(cpu_dev, &speed, &pvs, &pvs_ver,
+                                      speedbin_nvmem, speedbin);
+               break;
+       default:
+               dev_err(cpu_dev, "Unable to read nvmem data. Defaulting to 0!\n");
+               return -ENODEV;
+       }
+
+       snprintf(*pvs_name, sizeof("speedXX-pvsXX-vXX"), "speed%d-pvs%d-v%d",
+                speed, pvs, pvs_ver);
+
+       drv->versions = (1 << speed);
+
+       kfree(speedbin);
+       return 0;
+}
+
 static const struct qcom_cpufreq_match_data match_data_kryo = {
        .get_version = qcom_cpufreq_kryo_name_version,
 };
 
+static const struct qcom_cpufreq_match_data match_data_krait = {
+       .get_version = qcom_cpufreq_krait_name_version,
+};
+
 static const char *qcs404_genpd_names[] = { "cpr", NULL };
 
 static const struct qcom_cpufreq_match_data match_data_qcs404 = {
@@ -141,6 +264,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
        struct nvmem_cell *speedbin_nvmem;
        struct device_node *np;
        struct device *cpu_dev;
+       char *pvs_name = "speedXX-pvsXX-vXX";
        unsigned cpu;
        const struct of_device_id *match;
        int ret;
@@ -153,7 +277,7 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
        if (!np)
                return -ENOENT;
 
-       ret = of_device_is_compatible(np, "operating-points-v2-kryo-cpu");
+       ret = of_device_is_compatible(np, "operating-points-v2-qcom-cpu");
        if (!ret) {
                of_node_put(np);
                return -ENOENT;
@@ -181,7 +305,8 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
                        goto free_drv;
                }
 
-               ret = drv->data->get_version(cpu_dev, speedbin_nvmem, drv);
+               ret = drv->data->get_version(cpu_dev,
+                                                       speedbin_nvmem, &pvs_name, drv);
                if (ret) {
                        nvmem_cell_put(speedbin_nvmem);
                        goto free_drv;
@@ -190,12 +315,20 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
        }
        of_node_put(np);
 
-       drv->opp_tables = kcalloc(num_possible_cpus(), sizeof(*drv->opp_tables),
+       drv->names_opp_tables = kcalloc(num_possible_cpus(),
+                                 sizeof(*drv->names_opp_tables),
                                  GFP_KERNEL);
-       if (!drv->opp_tables) {
+       if (!drv->names_opp_tables) {
                ret = -ENOMEM;
                goto free_drv;
        }
+       drv->hw_opp_tables = kcalloc(num_possible_cpus(),
+                                 sizeof(*drv->hw_opp_tables),
+                                 GFP_KERNEL);
+       if (!drv->hw_opp_tables) {
+               ret = -ENOMEM;
+               goto free_opp_names;
+       }
 
        drv->genpd_opp_tables = kcalloc(num_possible_cpus(),
                                        sizeof(*drv->genpd_opp_tables),
@@ -213,11 +346,23 @@ static int qcom_cpufreq_probe(struct platform_device *pdev)
                }
 
                if (drv->data->get_version) {
-                       drv->opp_tables[cpu] =
-                               dev_pm_opp_set_supported_hw(cpu_dev,
-                                                           &drv->versions, 1);
-                       if (IS_ERR(drv->opp_tables[cpu])) {
-                               ret = PTR_ERR(drv->opp_tables[cpu]);
+
+                       if (pvs_name) {
+                               drv->names_opp_tables[cpu] = dev_pm_opp_set_prop_name(
+                                                                    cpu_dev,
+                                                                    pvs_name);
+                               if (IS_ERR(drv->names_opp_tables[cpu])) {
+                                       ret = PTR_ERR(drv->names_opp_tables[cpu]);
+                                       dev_err(cpu_dev, "Failed to add OPP name %s\n",
+                                               pvs_name);
+                                       goto free_opp;
+                               }
+                       }
+
+                       drv->hw_opp_tables[cpu] = dev_pm_opp_set_supported_hw(
+                                                                        cpu_dev, &drv->versions, 1);
+                       if (IS_ERR(drv->hw_opp_tables[cpu])) {
+                               ret = PTR_ERR(drv->hw_opp_tables[cpu]);
                                dev_err(cpu_dev,
                                        "Failed to set supported hardware\n");
                                goto free_genpd_opp;
@@ -259,11 +404,18 @@ free_genpd_opp:
        kfree(drv->genpd_opp_tables);
 free_opp:
        for_each_possible_cpu(cpu) {
-               if (IS_ERR_OR_NULL(drv->opp_tables[cpu]))
+               if (IS_ERR_OR_NULL(drv->names_opp_tables[cpu]))
+                       break;
+               dev_pm_opp_put_prop_name(drv->names_opp_tables[cpu]);
+       }
+       for_each_possible_cpu(cpu) {
+               if (IS_ERR_OR_NULL(drv->hw_opp_tables[cpu]))
                        break;
-               dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
+               dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
        }
-       kfree(drv->opp_tables);
+       kfree(drv->hw_opp_tables);
+free_opp_names:
+       kfree(drv->names_opp_tables);
 free_drv:
        kfree(drv);
 
@@ -278,13 +430,16 @@ static int qcom_cpufreq_remove(struct platform_device *pdev)
        platform_device_unregister(cpufreq_dt_pdev);
 
        for_each_possible_cpu(cpu) {
-               if (drv->opp_tables[cpu])
-                       dev_pm_opp_put_supported_hw(drv->opp_tables[cpu]);
+               if (drv->names_opp_tables[cpu])
+                       dev_pm_opp_put_supported_hw(drv->names_opp_tables[cpu]);
+               if (drv->hw_opp_tables[cpu])
+                       dev_pm_opp_put_supported_hw(drv->hw_opp_tables[cpu]);
                if (drv->genpd_opp_tables[cpu])
                        dev_pm_opp_detach_genpd(drv->genpd_opp_tables[cpu]);
        }
 
-       kfree(drv->opp_tables);
+       kfree(drv->names_opp_tables);
+       kfree(drv->hw_opp_tables);
        kfree(drv->genpd_opp_tables);
        kfree(drv);
 
@@ -303,6 +458,10 @@ static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
        { .compatible = "qcom,apq8096", .data = &match_data_kryo },
        { .compatible = "qcom,msm8996", .data = &match_data_kryo },
        { .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
+       { .compatible = "qcom,ipq8064", .data = &match_data_krait },
+       { .compatible = "qcom,apq8064", .data = &match_data_krait },
+       { .compatible = "qcom,msm8974", .data = &match_data_krait },
+       { .compatible = "qcom,msm8960", .data = &match_data_krait },
        {},
 };
 
index c6f647b..73a2085 100644 (file)
@@ -95,7 +95,7 @@ static struct cpufreq_driver sc520_freq_driver = {
 };
 
 static const struct x86_cpu_id sc520_ids[] = {
-       { X86_VENDOR_AMD, 4, 9 },
+       X86_MATCH_VENDOR_FAM_MODEL(AMD, 4, 9, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, sc520_ids);
index b49f494..75b10ec 100644 (file)
@@ -520,18 +520,12 @@ static struct cpufreq_driver centrino_driver = {
  * or ASCII model IDs.
  */
 static const struct x86_cpu_id centrino_ids[] = {
-       { X86_VENDOR_INTEL, 6, 9, X86_FEATURE_EST },
-       { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
-       { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
-       { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
-       { X86_VENDOR_INTEL, 15, 3, X86_FEATURE_EST },
-       { X86_VENDOR_INTEL, 15, 4, X86_FEATURE_EST },
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL,  6,  9, X86_FEATURE_EST, NULL),
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL,  6, 13, X86_FEATURE_EST, NULL),
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 15,  3, X86_FEATURE_EST, NULL),
+       X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 15,  4, X86_FEATURE_EST, NULL),
        {}
 };
-#if 0
-/* Autoload or not? Do not for now. */
-MODULE_DEVICE_TABLE(x86cpu, centrino_ids);
-#endif
 
 /**
  * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver
index 547fd7a..f2076d7 100644 (file)
@@ -319,15 +319,11 @@ static struct cpufreq_driver speedstep_driver = {
 };
 
 static const struct x86_cpu_id ss_smi_ids[] = {
-       { X86_VENDOR_INTEL, 6, 0xb, },
-       { X86_VENDOR_INTEL, 6, 0x8, },
-       { X86_VENDOR_INTEL, 15, 2 },
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL,  6, 0x8, 0),
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL,  6, 0xb, 0),
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL, 15, 0x2, 0),
        {}
 };
-#if 0
-/* Autoload or not? Do not for now. */
-MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
-#endif
 
 /**
  * speedstep_init - initializes the SpeedStep CPUFreq driver
index eeb31bc..0ce9d4b 100644 (file)
@@ -299,15 +299,11 @@ static struct cpufreq_driver speedstep_driver = {
 };
 
 static const struct x86_cpu_id ss_smi_ids[] = {
-       { X86_VENDOR_INTEL, 6, 0xb, },
-       { X86_VENDOR_INTEL, 6, 0x8, },
-       { X86_VENDOR_INTEL, 15, 2 },
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL,  6, 0x8, 0),
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL,  6, 0xb, 0),
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL, 15, 0x2, 0),
        {}
 };
-#if 0
-/* Not auto loaded currently */
-MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
-#endif
 
 /**
  * speedstep_init - initializes the SpeedStep CPUFreq driver
index 557cb51..ab0de27 100644 (file)
 
 #define DRA7_EFUSE_HAS_OD_MPU_OPP              11
 #define DRA7_EFUSE_HAS_HIGH_MPU_OPP            15
+#define DRA76_EFUSE_HAS_PLUS_MPU_OPP           18
 #define DRA7_EFUSE_HAS_ALL_MPU_OPP             23
+#define DRA76_EFUSE_HAS_ALL_MPU_OPP            24
 
 #define DRA7_EFUSE_NOM_MPU_OPP                 BIT(0)
 #define DRA7_EFUSE_OD_MPU_OPP                  BIT(1)
 #define DRA7_EFUSE_HIGH_MPU_OPP                        BIT(2)
+#define DRA76_EFUSE_PLUS_MPU_OPP               BIT(3)
 
 #define OMAP3_CONTROL_DEVICE_STATUS            0x4800244C
 #define OMAP3_CONTROL_IDCODE                   0x4830A204
@@ -80,6 +83,10 @@ static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data,
         */
 
        switch (efuse) {
+       case DRA76_EFUSE_HAS_PLUS_MPU_OPP:
+       case DRA76_EFUSE_HAS_ALL_MPU_OPP:
+               calculated_efuse |= DRA76_EFUSE_PLUS_MPU_OPP;
+               /* Fall through */
        case DRA7_EFUSE_HAS_ALL_MPU_OPP:
        case DRA7_EFUSE_HAS_HIGH_MPU_OPP:
                calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP;
index b0ce9bc..db124bc 100644 (file)
 #include <linux/kvm_para.h>
 #include <linux/cpuidle_haltpoll.h>
 
+static bool force __read_mostly;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Load unconditionally");
+
 static struct cpuidle_device __percpu *haltpoll_cpuidle_devices;
 static enum cpuhp_state haltpoll_hp_state;
 
@@ -90,6 +94,11 @@ static void haltpoll_uninit(void)
        haltpoll_cpuidle_devices = NULL;
 }
 
+static bool haltpool_want(void)
+{
+       return kvm_para_has_hint(KVM_HINTS_REALTIME) || force;
+}
+
 static int __init haltpoll_init(void)
 {
        int ret;
@@ -101,8 +110,7 @@ static int __init haltpoll_init(void)
 
        cpuidle_poll_state_init(drv);
 
-       if (!kvm_para_available() ||
-               !kvm_para_has_hint(KVM_HINTS_REALTIME))
+       if (!kvm_para_available() || !haltpool_want())
                return -ENODEV;
 
        ret = cpuidle_register_driver(drv);
index edd7a54..bae9140 100644 (file)
@@ -160,6 +160,29 @@ int __init psci_dt_parse_state_node(struct device_node *np, u32 *state)
        return 0;
 }
 
+static int __init psci_dt_cpu_init_topology(struct cpuidle_driver *drv,
+                                           struct psci_cpuidle_data *data,
+                                           unsigned int state_count, int cpu)
+{
+       /* Currently limit the hierarchical topology to be used in OSI mode. */
+       if (!psci_has_osi_support())
+               return 0;
+
+       data->dev = psci_dt_attach_cpu(cpu);
+       if (IS_ERR_OR_NULL(data->dev))
+               return PTR_ERR_OR_ZERO(data->dev);
+
+       /*
+        * Using the deepest state for the CPU to trigger a potential selection
+        * of a shared state for the domain, assumes the domain states are all
+        * deeper states.
+        */
+       drv->states[state_count - 1].enter = psci_enter_domain_idle_state;
+       psci_cpuidle_use_cpuhp = true;
+
+       return 0;
+}
+
 static int __init psci_dt_cpu_init_idle(struct cpuidle_driver *drv,
                                        struct device_node *cpu_node,
                                        unsigned int state_count, int cpu)
@@ -193,25 +216,10 @@ static int __init psci_dt_cpu_init_idle(struct cpuidle_driver *drv,
                goto free_mem;
        }
 
-       /* Currently limit the hierarchical topology to be used in OSI mode. */
-       if (psci_has_osi_support()) {
-               data->dev = psci_dt_attach_cpu(cpu);
-               if (IS_ERR(data->dev)) {
-                       ret = PTR_ERR(data->dev);
-                       goto free_mem;
-               }
-
-               /*
-                * Using the deepest state for the CPU to trigger a potential
-                * selection of a shared state for the domain, assumes the
-                * domain states are all deeper states.
-                */
-               if (data->dev) {
-                       drv->states[state_count - 1].enter =
-                               psci_enter_domain_idle_state;
-                       psci_cpuidle_use_cpuhp = true;
-               }
-       }
+       /* Initialize optional data, used for the hierarchical topology. */
+       ret = psci_dt_cpu_init_topology(drv, data, state_count, cpu);
+       if (ret < 0)
+               goto free_mem;
 
        /* Idle states parsed correctly, store them in the per-cpu struct. */
        data->psci_states = psci_states;
index de81298..c149d9e 100644 (file)
@@ -736,53 +736,15 @@ int cpuidle_register(struct cpuidle_driver *drv,
 }
 EXPORT_SYMBOL_GPL(cpuidle_register);
 
-#ifdef CONFIG_SMP
-
-/*
- * This function gets called when a part of the kernel has a new latency
- * requirement.  This means we need to get all processors out of their C-state,
- * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
- * wakes them all right up.
- */
-static int cpuidle_latency_notify(struct notifier_block *b,
-               unsigned long l, void *v)
-{
-       wake_up_all_idle_cpus();
-       return NOTIFY_OK;
-}
-
-static struct notifier_block cpuidle_latency_notifier = {
-       .notifier_call = cpuidle_latency_notify,
-};
-
-static inline void latency_notifier_init(struct notifier_block *n)
-{
-       pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n);
-}
-
-#else /* CONFIG_SMP */
-
-#define latency_notifier_init(x) do { } while (0)
-
-#endif /* CONFIG_SMP */
-
 /**
  * cpuidle_init - core initializer
  */
 static int __init cpuidle_init(void)
 {
-       int ret;
-
        if (cpuidle_disabled())
                return -ENODEV;
 
-       ret = cpuidle_add_interface(cpu_subsys.dev_root);
-       if (ret)
-               return ret;
-
-       latency_notifier_init(&cpuidle_latency_notifier);
-
-       return 0;
+       return cpuidle_add_interface(cpu_subsys.dev_root);
 }
 
 module_param(off, int, 0444);
index e48271e..29acaf4 100644 (file)
@@ -109,9 +109,9 @@ int cpuidle_register_governor(struct cpuidle_governor *gov)
  */
 s64 cpuidle_governor_latency_req(unsigned int cpu)
 {
-       int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
        struct device *device = get_cpu_device(cpu);
        int device_req = dev_pm_qos_raw_resume_latency(device);
+       int global_req = cpu_latency_qos_limit();
 
        if (device_req > global_req)
                device_req = global_req;
index 594d6b1..62c6fe8 100644 (file)
@@ -474,7 +474,7 @@ static struct skcipher_alg cbc_aes_alg = {
 };
 
 static const struct x86_cpu_id padlock_cpu_id[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_XCRYPT),
+       X86_MATCH_FEATURE(X86_FEATURE_XCRYPT, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, padlock_cpu_id);
index c826abe..a697a4a 100644 (file)
@@ -490,7 +490,7 @@ static struct shash_alg sha256_alg_nano = {
 };
 
 static const struct x86_cpu_id padlock_sha_ids[] = {
-       X86_FEATURE_MATCH(X86_FEATURE_PHE),
+       X86_MATCH_FEATURE(X86_FEATURE_PHE, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, padlock_sha_ids);
index cceee8b..6fecd11 100644 (file)
@@ -550,14 +550,14 @@ out:
 EXPORT_SYMBOL(devfreq_monitor_resume);
 
 /**
- * devfreq_interval_update() - Update device devfreq monitoring interval
+ * devfreq_update_interval() - Update device devfreq monitoring interval
  * @devfreq:    the devfreq instance.
  * @delay:      new polling interval to be set.
  *
  * Helper function to set new load monitoring polling interval. Function
- * to be called from governor in response to DEVFREQ_GOV_INTERVAL event.
+ * to be called from governor in response to DEVFREQ_GOV_UPDATE_INTERVAL event.
  */
-void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay)
+void devfreq_update_interval(struct devfreq *devfreq, unsigned int *delay)
 {
        unsigned int cur_delay = devfreq->profile->polling_ms;
        unsigned int new_delay = *delay;
@@ -597,7 +597,7 @@ void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay)
 out:
        mutex_unlock(&devfreq->lock);
 }
-EXPORT_SYMBOL(devfreq_interval_update);
+EXPORT_SYMBOL(devfreq_update_interval);
 
 /**
  * devfreq_notifier_call() - Notify that the device frequency requirements
@@ -705,13 +705,13 @@ static void devfreq_dev_release(struct device *dev)
 
        if (dev_pm_qos_request_active(&devfreq->user_max_freq_req)) {
                err = dev_pm_qos_remove_request(&devfreq->user_max_freq_req);
-               if (err)
+               if (err < 0)
                        dev_warn(dev->parent,
                                "Failed to remove max_freq request: %d\n", err);
        }
        if (dev_pm_qos_request_active(&devfreq->user_min_freq_req)) {
                err = dev_pm_qos_remove_request(&devfreq->user_min_freq_req);
-               if (err)
+               if (err < 0)
                        dev_warn(dev->parent,
                                "Failed to remove min_freq request: %d\n", err);
        }
@@ -738,7 +738,6 @@ struct devfreq *devfreq_add_device(struct device *dev,
 {
        struct devfreq *devfreq;
        struct devfreq_governor *governor;
-       static atomic_t devfreq_no = ATOMIC_INIT(-1);
        int err = 0;
 
        if (!dev || !profile || !governor_name) {
@@ -800,8 +799,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
        devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
        atomic_set(&devfreq->suspend_count, 0);
 
-       dev_set_name(&devfreq->dev, "devfreq%d",
-                               atomic_inc_return(&devfreq_no));
+       dev_set_name(&devfreq->dev, "%s", dev_name(dev));
        err = device_register(&devfreq->dev);
        if (err) {
                mutex_unlock(&devfreq->lock);
@@ -1426,7 +1424,7 @@ static ssize_t polling_interval_store(struct device *dev,
        if (ret != 1)
                return -EINVAL;
 
-       df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value);
+       df->governor->event_handler(df, DEVFREQ_GOV_UPDATE_INTERVAL, &value);
        ret = count;
 
        return ret;
index dc7533c..ae4d0cc 100644 (file)
@@ -18,7 +18,7 @@
 /* Devfreq events */
 #define DEVFREQ_GOV_START                      0x1
 #define DEVFREQ_GOV_STOP                       0x2
-#define DEVFREQ_GOV_INTERVAL                   0x3
+#define DEVFREQ_GOV_UPDATE_INTERVAL            0x3
 #define DEVFREQ_GOV_SUSPEND                    0x4
 #define DEVFREQ_GOV_RESUME                     0x5
 
@@ -30,7 +30,7 @@
  * @node:              list node - contains registered devfreq governors
  * @name:              Governor's name
  * @immutable:         Immutable flag for governor. If the value is 1,
- *                     this govenror is never changeable to other governor.
+ *                     this governor is never changeable to other governor.
  * @interrupt_driven:  Devfreq core won't schedule polling work for this
  *                     governor if value is set to 1.
  * @get_target_freq:   Returns desired operating frequency for the device.
@@ -57,17 +57,16 @@ struct devfreq_governor {
                                unsigned int event, void *data);
 };
 
-extern void devfreq_monitor_start(struct devfreq *devfreq);
-extern void devfreq_monitor_stop(struct devfreq *devfreq);
-extern void devfreq_monitor_suspend(struct devfreq *devfreq);
-extern void devfreq_monitor_resume(struct devfreq *devfreq);
-extern void devfreq_interval_update(struct devfreq *devfreq,
-                                       unsigned int *delay);
+void devfreq_monitor_start(struct devfreq *devfreq);
+void devfreq_monitor_stop(struct devfreq *devfreq);
+void devfreq_monitor_suspend(struct devfreq *devfreq);
+void devfreq_monitor_resume(struct devfreq *devfreq);
+void devfreq_update_interval(struct devfreq *devfreq, unsigned int *delay);
 
-extern int devfreq_add_governor(struct devfreq_governor *governor);
-extern int devfreq_remove_governor(struct devfreq_governor *governor);
+int devfreq_add_governor(struct devfreq_governor *governor);
+int devfreq_remove_governor(struct devfreq_governor *governor);
 
-extern int devfreq_update_status(struct devfreq *devfreq, unsigned long freq);
+int devfreq_update_status(struct devfreq *devfreq, unsigned long freq);
 
 static inline int devfreq_update_stats(struct devfreq *df)
 {
index 3d809f2..1b314e1 100644 (file)
@@ -96,8 +96,8 @@ static int devfreq_simple_ondemand_handler(struct devfreq *devfreq,
                devfreq_monitor_stop(devfreq);
                break;
 
-       case DEVFREQ_GOV_INTERVAL:
-               devfreq_interval_update(devfreq, (unsigned int *)data);
+       case DEVFREQ_GOV_UPDATE_INTERVAL:
+               devfreq_update_interval(devfreq, (unsigned int *)data);
                break;
 
        case DEVFREQ_GOV_SUSPEND:
index af94942..0fd6c48 100644 (file)
@@ -131,7 +131,7 @@ static int devfreq_userspace_handler(struct devfreq *devfreq,
 }
 
 static struct devfreq_governor devfreq_userspace = {
-       .name = "userspace",
+       .name = DEVFREQ_GOV_USERSPACE,
        .get_target_freq = devfreq_userspace_func,
        .event_handler = devfreq_userspace_handler,
 };
index 0b65f89..28b2c7c 100644 (file)
@@ -734,7 +734,7 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
                devfreq_monitor_stop(devfreq);
                break;
 
-       case DEVFREQ_GOV_INTERVAL:
+       case DEVFREQ_GOV_UPDATE_INTERVAL:
                /*
                 * ACTMON hardware supports up to 256 milliseconds for the
                 * sampling period.
@@ -745,7 +745,7 @@ static int tegra_governor_event_handler(struct devfreq *devfreq,
                }
 
                tegra_actmon_pause(tegra);
-               devfreq_interval_update(devfreq, new_delay);
+               devfreq_update_interval(devfreq, new_delay);
                ret = tegra_actmon_resume(tegra);
                break;
 
index a7b174e..69c4693 100644 (file)
@@ -25,7 +25,7 @@
  *  dio_device_id structure or %NULL if there is no match.
  */
 
-const struct dio_device_id *
+static const struct dio_device_id *
 dio_match_device(const struct dio_device_id *ids,
                   const struct dio_dev *d)
 {
@@ -105,9 +105,9 @@ void dio_unregister_driver(struct dio_driver *drv)
  *  @dev: the DIO device structure to match against
  *  @drv: the &device_driver that points to the array of DIO device id structures to search
  *
- *  Used by a driver to check whether a DIO device present in the
- *  system is in its list of supported devices. Returns the matching
- *  dio_device_id structure or %NULL if there is no match.
+ *  Used by the driver core to check whether a DIO device present in the
+ *  system is in a driver's list of supported devices. Returns 1 if supported,
+ *  and 0 if there is no match.
  */
 
 static int dio_bus_match(struct device *dev, struct device_driver *drv)
@@ -137,7 +137,6 @@ static int __init dio_driver_init(void)
 
 postcore_initcall(dio_driver_init);
 
-EXPORT_SYMBOL(dio_match_device);
 EXPORT_SYMBOL(dio_register_driver);
 EXPORT_SYMBOL(dio_unregister_driver);
 EXPORT_SYMBOL(dio_bus_type);
index d409785..c343c7c 100644 (file)
@@ -108,6 +108,7 @@ static int dma_buf_release(struct inode *inode, struct file *file)
                dma_resv_fini(dmabuf->resv);
 
        module_put(dmabuf->owner);
+       kfree(dmabuf->name);
        kfree(dmabuf);
        return 0;
 }
index e51d836..1092d4c 100644 (file)
@@ -1947,8 +1947,6 @@ static void dma_tc_handle(struct coh901318_chan *cohc)
                return;
        }
 
-       spin_lock(&cohc->lock);
-
        /*
         * When we reach this point, at least one queue item
         * should have been moved over from cohc->queue to
@@ -1969,8 +1967,6 @@ static void dma_tc_handle(struct coh901318_chan *cohc)
        if (coh901318_queue_start(cohc) == NULL)
                cohc->busy = 0;
 
-       spin_unlock(&cohc->lock);
-
        /*
         * This tasklet will remove items from cohc->active
         * and thus terminates them.
index c3b1283..17909fd 100644 (file)
@@ -1151,7 +1151,7 @@ int dma_async_device_register(struct dma_device *device)
        }
 
        if (!device->device_release)
-               dev_warn(device->dev,
+               dev_dbg(device->dev,
                         "WARN: Device release is not defined so it is not safe to unbind this driver while in use\n");
 
        kref_init(&device->ref);
index 1d73478..989b7a2 100644 (file)
@@ -81,9 +81,9 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
        dev = &idxd->pdev->dev;
        idxd_cdev = &wq->idxd_cdev;
 
-       dev_dbg(dev, "%s called\n", __func__);
+       dev_dbg(dev, "%s called: %d\n", __func__, idxd_wq_refcount(wq));
 
-       if (idxd_wq_refcount(wq) > 1 && wq_dedicated(wq))
+       if (idxd_wq_refcount(wq) > 0 && wq_dedicated(wq))
                return -EBUSY;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -204,6 +204,7 @@ static int idxd_wq_cdev_dev_setup(struct idxd_wq *wq)
        minor = ida_simple_get(&cdev_ctx->minor_ida, 0, MINORMASK, GFP_KERNEL);
        if (minor < 0) {
                rc = minor;
+               kfree(dev);
                goto ida_err;
        }
 
@@ -212,7 +213,6 @@ static int idxd_wq_cdev_dev_setup(struct idxd_wq *wq)
        rc = device_register(dev);
        if (rc < 0) {
                dev_err(&idxd->pdev->dev, "device register failed\n");
-               put_device(dev);
                goto dev_reg_err;
        }
        idxd_cdev->minor = minor;
@@ -221,8 +221,8 @@ static int idxd_wq_cdev_dev_setup(struct idxd_wq *wq)
 
  dev_reg_err:
        ida_simple_remove(&cdev_ctx->minor_ida, MINOR(dev->devt));
+       put_device(dev);
  ida_err:
-       kfree(dev);
        idxd_cdev->dev = NULL;
        return rc;
 }
index 6d907fe..6ca6e52 100644 (file)
@@ -124,6 +124,7 @@ static int idxd_config_bus_probe(struct device *dev)
                rc = idxd_device_config(idxd);
                if (rc < 0) {
                        spin_unlock_irqrestore(&idxd->dev_lock, flags);
+                       module_put(THIS_MODULE);
                        dev_warn(dev, "Device config failed: %d\n", rc);
                        return rc;
                }
@@ -132,6 +133,7 @@ static int idxd_config_bus_probe(struct device *dev)
                rc = idxd_device_enable(idxd);
                if (rc < 0) {
                        spin_unlock_irqrestore(&idxd->dev_lock, flags);
+                       module_put(THIS_MODULE);
                        dev_warn(dev, "Device enable failed: %d\n", rc);
                        return rc;
                }
@@ -142,6 +144,7 @@ static int idxd_config_bus_probe(struct device *dev)
                rc = idxd_register_dma_device(idxd);
                if (rc < 0) {
                        spin_unlock_irqrestore(&idxd->dev_lock, flags);
+                       module_put(THIS_MODULE);
                        dev_dbg(dev, "Failed to register dmaengine device\n");
                        return rc;
                }
@@ -516,7 +519,7 @@ static ssize_t group_tokens_reserved_store(struct device *dev,
        if (val > idxd->max_tokens)
                return -EINVAL;
 
-       if (val > idxd->nr_tokens)
+       if (val > idxd->nr_tokens + group->tokens_reserved)
                return -EINVAL;
 
        group->tokens_reserved = val;
@@ -901,6 +904,20 @@ static ssize_t wq_size_show(struct device *dev, struct device_attribute *attr,
        return sprintf(buf, "%u\n", wq->size);
 }
 
+static int total_claimed_wq_size(struct idxd_device *idxd)
+{
+       int i;
+       int wq_size = 0;
+
+       for (i = 0; i < idxd->max_wqs; i++) {
+               struct idxd_wq *wq = &idxd->wqs[i];
+
+               wq_size += wq->size;
+       }
+
+       return wq_size;
+}
+
 static ssize_t wq_size_store(struct device *dev,
                             struct device_attribute *attr, const char *buf,
                             size_t count)
@@ -920,7 +937,7 @@ static ssize_t wq_size_store(struct device *dev,
        if (wq->state != IDXD_WQ_DISABLED)
                return -EPERM;
 
-       if (size > idxd->max_wq_size)
+       if (size + total_claimed_wq_size(idxd) - wq->size > idxd->max_wq_size)
                return -EINVAL;
 
        wq->size = size;
@@ -999,12 +1016,14 @@ static ssize_t wq_type_store(struct device *dev,
                return -EPERM;
 
        old_type = wq->type;
-       if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_KERNEL]))
+       if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_NONE]))
+               wq->type = IDXD_WQT_NONE;
+       else if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_KERNEL]))
                wq->type = IDXD_WQT_KERNEL;
        else if (sysfs_streq(buf, idxd_wq_type_names[IDXD_WQT_USER]))
                wq->type = IDXD_WQT_USER;
        else
-               wq->type = IDXD_WQT_NONE;
+               return -EINVAL;
 
        /* If we are changing queue type, clear the name */
        if (wq->type != old_type)
index 066b21a..4d4477d 100644 (file)
@@ -1331,13 +1331,14 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 
        sdma_channel_synchronize(chan);
 
-       if (sdmac->event_id0)
+       if (sdmac->event_id0 >= 0)
                sdma_event_disable(sdmac, sdmac->event_id0);
        if (sdmac->event_id1)
                sdma_event_disable(sdmac, sdmac->event_id1);
 
        sdmac->event_id0 = 0;
        sdmac->event_id1 = 0;
+       sdmac->context_loaded = false;
 
        sdma_set_channel_priority(sdmac, 0);
 
@@ -1631,7 +1632,7 @@ static int sdma_config(struct dma_chan *chan,
        memcpy(&sdmac->slave_config, dmaengine_cfg, sizeof(*dmaengine_cfg));
 
        /* Set ENBLn earlier to make sure dma request triggered after that */
-       if (sdmac->event_id0) {
+       if (sdmac->event_id0 >= 0) {
                if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
                        return -EINVAL;
                sdma_event_enable(sdmac, sdmac->event_id0);
index 3a45079..4a750e2 100644 (file)
@@ -281,7 +281,7 @@ static struct tegra_dma_desc *tegra_dma_desc_get(
 
        /* Do not allocate if desc are waiting for ack */
        list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) {
-               if (async_tx_test_ack(&dma_desc->txd)) {
+               if (async_tx_test_ack(&dma_desc->txd) && !dma_desc->cb_count) {
                        list_del(&dma_desc->node);
                        spin_unlock_irqrestore(&tdc->lock, flags);
                        dma_desc->txd.flags = 0;
@@ -756,10 +756,6 @@ static int tegra_dma_terminate_all(struct dma_chan *dc)
        bool was_busy;
 
        spin_lock_irqsave(&tdc->lock, flags);
-       if (list_empty(&tdc->pending_sg_req)) {
-               spin_unlock_irqrestore(&tdc->lock, flags);
-               return 0;
-       }
 
        if (!tdc->busy)
                goto skip_dma_stop;
index c151129..4d7561a 100644 (file)
@@ -564,12 +564,12 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
        if (IS_ERR(flow->udma_rflow)) {
                ret = PTR_ERR(flow->udma_rflow);
                dev_err(dev, "UDMAX rflow get err %d\n", ret);
-               goto err;
+               return ret;
        }
 
        if (flow->udma_rflow_id != xudma_rflow_get_id(flow->udma_rflow)) {
-               xudma_rflow_put(rx_chn->common.udmax, flow->udma_rflow);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto err_rflow_put;
        }
 
        /* request and cfg rings */
@@ -578,7 +578,7 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
        if (!flow->ringrx) {
                ret = -ENODEV;
                dev_err(dev, "Failed to get RX ring\n");
-               goto err;
+               goto err_rflow_put;
        }
 
        flow->ringrxfdq = k3_ringacc_request_ring(rx_chn->common.ringacc,
@@ -586,19 +586,19 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
        if (!flow->ringrxfdq) {
                ret = -ENODEV;
                dev_err(dev, "Failed to get RXFDQ ring\n");
-               goto err;
+               goto err_ringrx_free;
        }
 
        ret = k3_ringacc_ring_cfg(flow->ringrx, &flow_cfg->rx_cfg);
        if (ret) {
                dev_err(dev, "Failed to cfg ringrx %d\n", ret);
-               goto err;
+               goto err_ringrxfdq_free;
        }
 
        ret = k3_ringacc_ring_cfg(flow->ringrxfdq, &flow_cfg->rxfdq_cfg);
        if (ret) {
                dev_err(dev, "Failed to cfg ringrxfdq %d\n", ret);
-               goto err;
+               goto err_ringrxfdq_free;
        }
 
        if (rx_chn->remote) {
@@ -648,7 +648,7 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
        if (ret) {
                dev_err(dev, "flow%d config failed: %d\n", flow->udma_rflow_id,
                        ret);
-               goto err;
+               goto err_ringrxfdq_free;
        }
 
        rx_chn->flows_ready++;
@@ -656,8 +656,17 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
                flow->udma_rflow_id, rx_chn->flows_ready);
 
        return 0;
-err:
-       k3_udma_glue_release_rx_flow(rx_chn, flow_idx);
+
+err_ringrxfdq_free:
+       k3_ringacc_ring_free(flow->ringrxfdq);
+
+err_ringrx_free:
+       k3_ringacc_ring_free(flow->ringrx);
+
+err_rflow_put:
+       xudma_rflow_put(rx_chn->common.udmax, flow->udma_rflow);
+       flow->udma_rflow = NULL;
+
        return ret;
 }
 
index ea79c2d..0536866 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
@@ -96,6 +97,24 @@ struct udma_match_data {
        u32 level_start_idx[];
 };
 
+struct udma_hwdesc {
+       size_t cppi5_desc_size;
+       void *cppi5_desc_vaddr;
+       dma_addr_t cppi5_desc_paddr;
+
+       /* TR descriptor internal pointers */
+       void *tr_req_base;
+       struct cppi5_tr_resp_t *tr_resp_base;
+};
+
+struct udma_rx_flush {
+       struct udma_hwdesc hwdescs[2];
+
+       size_t buffer_size;
+       void *buffer_vaddr;
+       dma_addr_t buffer_paddr;
+};
+
 struct udma_dev {
        struct dma_device ddev;
        struct device *dev;
@@ -112,6 +131,8 @@ struct udma_dev {
        struct list_head desc_to_purge;
        spinlock_t lock;
 
+       struct udma_rx_flush rx_flush;
+
        int tchan_cnt;
        int echan_cnt;
        int rchan_cnt;
@@ -130,16 +151,6 @@ struct udma_dev {
        u32 psil_base;
 };
 
-struct udma_hwdesc {
-       size_t cppi5_desc_size;
-       void *cppi5_desc_vaddr;
-       dma_addr_t cppi5_desc_paddr;
-
-       /* TR descriptor internal pointers */
-       void *tr_req_base;
-       struct cppi5_tr_resp_t *tr_resp_base;
-};
-
 struct udma_desc {
        struct virt_dma_desc vd;
 
@@ -169,7 +180,7 @@ enum udma_chan_state {
 
 struct udma_tx_drain {
        struct delayed_work work;
-       unsigned long jiffie;
+       ktime_t tstamp;
        u32 residue;
 };
 
@@ -502,7 +513,7 @@ static bool udma_is_chan_paused(struct udma_chan *uc)
 {
        u32 val, pause_mask;
 
-       switch (uc->desc->dir) {
+       switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
                val = udma_rchanrt_read(uc->rchan,
                                        UDMA_RCHAN_RT_PEER_RT_EN_REG);
@@ -551,12 +562,17 @@ static void udma_sync_for_device(struct udma_chan *uc, int idx)
        }
 }
 
+static inline dma_addr_t udma_get_rx_flush_hwdesc_paddr(struct udma_chan *uc)
+{
+       return uc->ud->rx_flush.hwdescs[uc->config.pkt_mode].cppi5_desc_paddr;
+}
+
 static int udma_push_to_ring(struct udma_chan *uc, int idx)
 {
        struct udma_desc *d = uc->desc;
-
        struct k3_ring *ring = NULL;
-       int ret = -EINVAL;
+       dma_addr_t paddr;
+       int ret;
 
        switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
@@ -567,21 +583,37 @@ static int udma_push_to_ring(struct udma_chan *uc, int idx)
                ring = uc->tchan->t_ring;
                break;
        default:
-               break;
+               return -EINVAL;
        }
 
-       if (ring) {
-               dma_addr_t desc_addr = udma_curr_cppi5_desc_paddr(d, idx);
+       /* RX flush packet: idx == -1 is only passed in case of DEV_TO_MEM */
+       if (idx == -1) {
+               paddr = udma_get_rx_flush_hwdesc_paddr(uc);
+       } else {
+               paddr = udma_curr_cppi5_desc_paddr(d, idx);
 
                wmb(); /* Ensure that writes are not moved over this point */
                udma_sync_for_device(uc, idx);
-               ret = k3_ringacc_ring_push(ring, &desc_addr);
-               uc->in_ring_cnt++;
        }
 
+       ret = k3_ringacc_ring_push(ring, &paddr);
+       if (!ret)
+               uc->in_ring_cnt++;
+
        return ret;
 }
 
+static bool udma_desc_is_rx_flush(struct udma_chan *uc, dma_addr_t addr)
+{
+       if (uc->config.dir != DMA_DEV_TO_MEM)
+               return false;
+
+       if (addr == udma_get_rx_flush_hwdesc_paddr(uc))
+               return true;
+
+       return false;
+}
+
 static int udma_pop_from_ring(struct udma_chan *uc, dma_addr_t *addr)
 {
        struct k3_ring *ring = NULL;
@@ -610,6 +642,10 @@ static int udma_pop_from_ring(struct udma_chan *uc, dma_addr_t *addr)
                if (cppi5_desc_is_tdcm(*addr))
                        return ret;
 
+               /* Check for flush descriptor */
+               if (udma_desc_is_rx_flush(uc, *addr))
+                       return -ENOENT;
+
                d = udma_udma_desc_from_paddr(uc, *addr);
 
                if (d)
@@ -890,6 +926,9 @@ static int udma_stop(struct udma_chan *uc)
 
        switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
+               if (!uc->cyclic && !uc->desc)
+                       udma_push_to_ring(uc, -1);
+
                udma_rchanrt_write(uc->rchan, UDMA_RCHAN_RT_PEER_RT_EN_REG,
                                   UDMA_PEER_RT_EN_ENABLE |
                                   UDMA_PEER_RT_EN_TEARDOWN);
@@ -946,9 +985,10 @@ static bool udma_is_desc_really_done(struct udma_chan *uc, struct udma_desc *d)
        peer_bcnt = udma_tchanrt_read(uc->tchan, UDMA_TCHAN_RT_PEER_BCNT_REG);
        bcnt = udma_tchanrt_read(uc->tchan, UDMA_TCHAN_RT_BCNT_REG);
 
+       /* Transfer is incomplete, store current residue and time stamp */
        if (peer_bcnt < bcnt) {
                uc->tx_drain.residue = bcnt - peer_bcnt;
-               uc->tx_drain.jiffie = jiffies;
+               uc->tx_drain.tstamp = ktime_get();
                return false;
        }
 
@@ -961,35 +1001,59 @@ static void udma_check_tx_completion(struct work_struct *work)
                                            tx_drain.work.work);
        bool desc_done = true;
        u32 residue_diff;
-       unsigned long jiffie_diff, delay;
+       ktime_t time_diff;
+       unsigned long delay;
+
+       while (1) {
+               if (uc->desc) {
+                       /* Get previous residue and time stamp */
+                       residue_diff = uc->tx_drain.residue;
+                       time_diff = uc->tx_drain.tstamp;
+                       /*
+                        * Get current residue and time stamp or see if
+                        * transfer is complete
+                        */
+                       desc_done = udma_is_desc_really_done(uc, uc->desc);
+               }
 
-       if (uc->desc) {
-               residue_diff = uc->tx_drain.residue;
-               jiffie_diff = uc->tx_drain.jiffie;
-               desc_done = udma_is_desc_really_done(uc, uc->desc);
-       }
-
-       if (!desc_done) {
-               jiffie_diff = uc->tx_drain.jiffie - jiffie_diff;
-               residue_diff -= uc->tx_drain.residue;
-               if (residue_diff) {
-                       /* Try to guess when we should check next time */
-                       residue_diff /= jiffie_diff;
-                       delay = uc->tx_drain.residue / residue_diff / 3;
-                       if (jiffies_to_msecs(delay) < 5)
-                               delay = 0;
-               } else {
-                       /* No progress, check again in 1 second  */
-                       delay = HZ;
+               if (!desc_done) {
+                       /*
+                        * Find the time delta and residue delta w.r.t
+                        * previous poll
+                        */
+                       time_diff = ktime_sub(uc->tx_drain.tstamp,
+                                             time_diff) + 1;
+                       residue_diff -= uc->tx_drain.residue;
+                       if (residue_diff) {
+                               /*
+                                * Try to guess when we should check
+                                * next time by calculating rate at
+                                * which data is being drained at the
+                                * peer device
+                                */
+                               delay = (time_diff / residue_diff) *
+                                       uc->tx_drain.residue;
+                       } else {
+                               /* No progress, check again in 1 second  */
+                               schedule_delayed_work(&uc->tx_drain.work, HZ);
+                               break;
+                       }
+
+                       usleep_range(ktime_to_us(delay),
+                                    ktime_to_us(delay) + 10);
+                       continue;
                }
 
-               schedule_delayed_work(&uc->tx_drain.work, delay);
-       } else if (uc->desc) {
-               struct udma_desc *d = uc->desc;
+               if (uc->desc) {
+                       struct udma_desc *d = uc->desc;
 
-               uc->bcnt += d->residue;
-               udma_start(uc);
-               vchan_cookie_complete(&d->vd);
+                       uc->bcnt += d->residue;
+                       udma_start(uc);
+                       vchan_cookie_complete(&d->vd);
+                       break;
+               }
+
+               break;
        }
 }
 
@@ -1033,29 +1097,27 @@ static irqreturn_t udma_ring_irq_handler(int irq, void *data)
                        goto out;
                }
 
-               if (uc->cyclic) {
-                       /* push the descriptor back to the ring */
-                       if (d == uc->desc) {
+               if (d == uc->desc) {
+                       /* active descriptor */
+                       if (uc->cyclic) {
                                udma_cyclic_packet_elapsed(uc);
                                vchan_cyclic_callback(&d->vd);
-                       }
-               } else {
-                       bool desc_done = false;
-
-                       if (d == uc->desc) {
-                               desc_done = udma_is_desc_really_done(uc, d);
-
-                               if (desc_done) {
+                       } else {
+                               if (udma_is_desc_really_done(uc, d)) {
                                        uc->bcnt += d->residue;
                                        udma_start(uc);
+                                       vchan_cookie_complete(&d->vd);
                                } else {
                                        schedule_delayed_work(&uc->tx_drain.work,
                                                              0);
                                }
                        }
-
-                       if (desc_done)
-                               vchan_cookie_complete(&d->vd);
+               } else {
+                       /*
+                        * terminated descriptor, mark the descriptor as
+                        * completed to update the channel's cookie marker
+                        */
+                       dma_cookie_complete(&d->vd.tx);
                }
        }
 out:
@@ -1965,36 +2027,81 @@ static struct udma_desc *udma_alloc_tr_desc(struct udma_chan *uc,
        return d;
 }
 
+/**
+ * udma_get_tr_counters - calculate TR counters for a given length
+ * @len: Length of the trasnfer
+ * @align_to: Preferred alignment
+ * @tr0_cnt0: First TR icnt0
+ * @tr0_cnt1: First TR icnt1
+ * @tr1_cnt0: Second (if used) TR icnt0
+ *
+ * For len < SZ_64K only one TR is enough, tr1_cnt0 is not updated
+ * For len >= SZ_64K two TRs are used in a simple way:
+ * First TR: SZ_64K-alignment blocks (tr0_cnt0, tr0_cnt1)
+ * Second TR: the remaining length (tr1_cnt0)
+ *
+ * Returns the number of TRs the length needs (1 or 2)
+ * -EINVAL if the length can not be supported
+ */
+static int udma_get_tr_counters(size_t len, unsigned long align_to,
+                               u16 *tr0_cnt0, u16 *tr0_cnt1, u16 *tr1_cnt0)
+{
+       if (len < SZ_64K) {
+               *tr0_cnt0 = len;
+               *tr0_cnt1 = 1;
+
+               return 1;
+       }
+
+       if (align_to > 3)
+               align_to = 3;
+
+realign:
+       *tr0_cnt0 = SZ_64K - BIT(align_to);
+       if (len / *tr0_cnt0 >= SZ_64K) {
+               if (align_to) {
+                       align_to--;
+                       goto realign;
+               }
+               return -EINVAL;
+       }
+
+       *tr0_cnt1 = len / *tr0_cnt0;
+       *tr1_cnt0 = len % *tr0_cnt0;
+
+       return 2;
+}
+
 static struct udma_desc *
 udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl,
                      unsigned int sglen, enum dma_transfer_direction dir,
                      unsigned long tx_flags, void *context)
 {
-       enum dma_slave_buswidth dev_width;
        struct scatterlist *sgent;
        struct udma_desc *d;
-       size_t tr_size;
        struct cppi5_tr_type1_t *tr_req = NULL;
+       u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
        unsigned int i;
-       u32 burst;
+       size_t tr_size;
+       int num_tr = 0;
+       int tr_idx = 0;
 
-       if (dir == DMA_DEV_TO_MEM) {
-               dev_width = uc->cfg.src_addr_width;
-               burst = uc->cfg.src_maxburst;
-       } else if (dir == DMA_MEM_TO_DEV) {
-               dev_width = uc->cfg.dst_addr_width;
-               burst = uc->cfg.dst_maxburst;
-       } else {
-               dev_err(uc->ud->dev, "%s: bad direction?\n", __func__);
+       if (!is_slave_direction(dir)) {
+               dev_err(uc->ud->dev, "Only slave cyclic is supported\n");
                return NULL;
        }
 
-       if (!burst)
-               burst = 1;
+       /* estimate the number of TRs we will need */
+       for_each_sg(sgl, sgent, sglen, i) {
+               if (sg_dma_len(sgent) < SZ_64K)
+                       num_tr++;
+               else
+                       num_tr += 2;
+       }
 
        /* Now allocate and setup the descriptor. */
        tr_size = sizeof(struct cppi5_tr_type1_t);
-       d = udma_alloc_tr_desc(uc, tr_size, sglen, dir);
+       d = udma_alloc_tr_desc(uc, tr_size, num_tr, dir);
        if (!d)
                return NULL;
 
@@ -2002,19 +2109,46 @@ udma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl,
 
        tr_req = d->hwdesc[0].tr_req_base;
        for_each_sg(sgl, sgent, sglen, i) {
-               d->residue += sg_dma_len(sgent);
+               dma_addr_t sg_addr = sg_dma_address(sgent);
+
+               num_tr = udma_get_tr_counters(sg_dma_len(sgent), __ffs(sg_addr),
+                                             &tr0_cnt0, &tr0_cnt1, &tr1_cnt0);
+               if (num_tr < 0) {
+                       dev_err(uc->ud->dev, "size %u is not supported\n",
+                               sg_dma_len(sgent));
+                       udma_free_hwdesc(uc, d);
+                       kfree(d);
+                       return NULL;
+               }
 
                cppi5_tr_init(&tr_req[i].flags, CPPI5_TR_TYPE1, false, false,
                              CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
                cppi5_tr_csf_set(&tr_req[i].flags, CPPI5_TR_CSF_SUPR_EVT);
 
-               tr_req[i].addr = sg_dma_address(sgent);
-               tr_req[i].icnt0 = burst * dev_width;
-               tr_req[i].dim1 = burst * dev_width;
-               tr_req[i].icnt1 = sg_dma_len(sgent) / tr_req[i].icnt0;
+               tr_req[tr_idx].addr = sg_addr;
+               tr_req[tr_idx].icnt0 = tr0_cnt0;
+               tr_req[tr_idx].icnt1 = tr0_cnt1;
+               tr_req[tr_idx].dim1 = tr0_cnt0;
+               tr_idx++;
+
+               if (num_tr == 2) {
+                       cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1,
+                                     false, false,
+                                     CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+                       cppi5_tr_csf_set(&tr_req[tr_idx].flags,
+                                        CPPI5_TR_CSF_SUPR_EVT);
+
+                       tr_req[tr_idx].addr = sg_addr + tr0_cnt1 * tr0_cnt0;
+                       tr_req[tr_idx].icnt0 = tr1_cnt0;
+                       tr_req[tr_idx].icnt1 = 1;
+                       tr_req[tr_idx].dim1 = tr1_cnt0;
+                       tr_idx++;
+               }
+
+               d->residue += sg_dma_len(sgent);
        }
 
-       cppi5_tr_csf_set(&tr_req[i - 1].flags, CPPI5_TR_CSF_EOP);
+       cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, CPPI5_TR_CSF_EOP);
 
        return d;
 }
@@ -2319,47 +2453,66 @@ udma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
                        size_t buf_len, size_t period_len,
                        enum dma_transfer_direction dir, unsigned long flags)
 {
-       enum dma_slave_buswidth dev_width;
        struct udma_desc *d;
-       size_t tr_size;
+       size_t tr_size, period_addr;
        struct cppi5_tr_type1_t *tr_req;
-       unsigned int i;
        unsigned int periods = buf_len / period_len;
-       u32 burst;
+       u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
+       unsigned int i;
+       int num_tr;
 
-       if (dir == DMA_DEV_TO_MEM) {
-               dev_width = uc->cfg.src_addr_width;
-               burst = uc->cfg.src_maxburst;
-       } else if (dir == DMA_MEM_TO_DEV) {
-               dev_width = uc->cfg.dst_addr_width;
-               burst = uc->cfg.dst_maxburst;
-       } else {
-               dev_err(uc->ud->dev, "%s: bad direction?\n", __func__);
+       if (!is_slave_direction(dir)) {
+               dev_err(uc->ud->dev, "Only slave cyclic is supported\n");
                return NULL;
        }
 
-       if (!burst)
-               burst = 1;
+       num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0,
+                                     &tr0_cnt1, &tr1_cnt0);
+       if (num_tr < 0) {
+               dev_err(uc->ud->dev, "size %zu is not supported\n",
+                       period_len);
+               return NULL;
+       }
 
        /* Now allocate and setup the descriptor. */
        tr_size = sizeof(struct cppi5_tr_type1_t);
-       d = udma_alloc_tr_desc(uc, tr_size, periods, dir);
+       d = udma_alloc_tr_desc(uc, tr_size, periods * num_tr, dir);
        if (!d)
                return NULL;
 
        tr_req = d->hwdesc[0].tr_req_base;
+       period_addr = buf_addr;
        for (i = 0; i < periods; i++) {
-               cppi5_tr_init(&tr_req[i].flags, CPPI5_TR_TYPE1, false, false,
-                             CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+               int tr_idx = i * num_tr;
 
-               tr_req[i].addr = buf_addr + period_len * i;
-               tr_req[i].icnt0 = dev_width;
-               tr_req[i].icnt1 = period_len / dev_width;
-               tr_req[i].dim1 = dev_width;
+               cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false,
+                             false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+
+               tr_req[tr_idx].addr = period_addr;
+               tr_req[tr_idx].icnt0 = tr0_cnt0;
+               tr_req[tr_idx].icnt1 = tr0_cnt1;
+               tr_req[tr_idx].dim1 = tr0_cnt0;
+
+               if (num_tr == 2) {
+                       cppi5_tr_csf_set(&tr_req[tr_idx].flags,
+                                        CPPI5_TR_CSF_SUPR_EVT);
+                       tr_idx++;
+
+                       cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1,
+                                     false, false,
+                                     CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+
+                       tr_req[tr_idx].addr = period_addr + tr0_cnt1 * tr0_cnt0;
+                       tr_req[tr_idx].icnt0 = tr1_cnt0;
+                       tr_req[tr_idx].icnt1 = 1;
+                       tr_req[tr_idx].dim1 = tr1_cnt0;
+               }
 
                if (!(flags & DMA_PREP_INTERRUPT))
-                       cppi5_tr_csf_set(&tr_req[i].flags,
+                       cppi5_tr_csf_set(&tr_req[tr_idx].flags,
                                         CPPI5_TR_CSF_SUPR_EVT);
+
+               period_addr += period_len;
        }
 
        return d;
@@ -2517,29 +2670,12 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
                return NULL;
        }
 
-       if (len < SZ_64K) {
-               num_tr = 1;
-               tr0_cnt0 = len;
-               tr0_cnt1 = 1;
-       } else {
-               unsigned long align_to = __ffs(src | dest);
-
-               if (align_to > 3)
-                       align_to = 3;
-               /*
-                * Keep simple: tr0: SZ_64K-alignment blocks,
-                *              tr1: the remaining
-                */
-               num_tr = 2;
-               tr0_cnt0 = (SZ_64K - BIT(align_to));
-               if (len / tr0_cnt0 >= SZ_64K) {
-                       dev_err(uc->ud->dev, "size %zu is not supported\n",
-                               len);
-                       return NULL;
-               }
-
-               tr0_cnt1 = len / tr0_cnt0;
-               tr1_cnt0 = len % tr0_cnt0;
+       num_tr = udma_get_tr_counters(len, __ffs(src | dest), &tr0_cnt0,
+                                     &tr0_cnt1, &tr1_cnt0);
+       if (num_tr < 0) {
+               dev_err(uc->ud->dev, "size %zu is not supported\n",
+                       len);
+               return NULL;
        }
 
        d = udma_alloc_tr_desc(uc, tr_size, num_tr, DMA_MEM_TO_MEM);
@@ -2631,6 +2767,9 @@ static enum dma_status udma_tx_status(struct dma_chan *chan,
 
        ret = dma_cookie_status(chan, cookie, txstate);
 
+       if (!udma_is_chan_running(uc))
+               ret = DMA_COMPLETE;
+
        if (ret == DMA_IN_PROGRESS && udma_is_chan_paused(uc))
                ret = DMA_PAUSED;
 
@@ -2697,11 +2836,8 @@ static int udma_pause(struct dma_chan *chan)
 {
        struct udma_chan *uc = to_udma_chan(chan);
 
-       if (!uc->desc)
-               return -EINVAL;
-
        /* pause the channel */
-       switch (uc->desc->dir) {
+       switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
                udma_rchanrt_update_bits(uc->rchan,
                                         UDMA_RCHAN_RT_PEER_RT_EN_REG,
@@ -2730,11 +2866,8 @@ static int udma_resume(struct dma_chan *chan)
 {
        struct udma_chan *uc = to_udma_chan(chan);
 
-       if (!uc->desc)
-               return -EINVAL;
-
        /* resume the channel */
-       switch (uc->desc->dir) {
+       switch (uc->config.dir) {
        case DMA_DEV_TO_MEM:
                udma_rchanrt_update_bits(uc->rchan,
                                         UDMA_RCHAN_RT_PEER_RT_EN_REG,
@@ -3248,6 +3381,98 @@ static int udma_setup_resources(struct udma_dev *ud)
        return ch_count;
 }
 
+static int udma_setup_rx_flush(struct udma_dev *ud)
+{
+       struct udma_rx_flush *rx_flush = &ud->rx_flush;
+       struct cppi5_desc_hdr_t *tr_desc;
+       struct cppi5_tr_type1_t *tr_req;
+       struct cppi5_host_desc_t *desc;
+       struct device *dev = ud->dev;
+       struct udma_hwdesc *hwdesc;
+       size_t tr_size;
+
+       /* Allocate 1K buffer for discarded data on RX channel teardown */
+       rx_flush->buffer_size = SZ_1K;
+       rx_flush->buffer_vaddr = devm_kzalloc(dev, rx_flush->buffer_size,
+                                             GFP_KERNEL);
+       if (!rx_flush->buffer_vaddr)
+               return -ENOMEM;
+
+       rx_flush->buffer_paddr = dma_map_single(dev, rx_flush->buffer_vaddr,
+                                               rx_flush->buffer_size,
+                                               DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, rx_flush->buffer_paddr))
+               return -ENOMEM;
+
+       /* Set up descriptor to be used for TR mode */
+       hwdesc = &rx_flush->hwdescs[0];
+       tr_size = sizeof(struct cppi5_tr_type1_t);
+       hwdesc->cppi5_desc_size = cppi5_trdesc_calc_size(tr_size, 1);
+       hwdesc->cppi5_desc_size = ALIGN(hwdesc->cppi5_desc_size,
+                                       ud->desc_align);
+
+       hwdesc->cppi5_desc_vaddr = devm_kzalloc(dev, hwdesc->cppi5_desc_size,
+                                               GFP_KERNEL);
+       if (!hwdesc->cppi5_desc_vaddr)
+               return -ENOMEM;
+
+       hwdesc->cppi5_desc_paddr = dma_map_single(dev, hwdesc->cppi5_desc_vaddr,
+                                                 hwdesc->cppi5_desc_size,
+                                                 DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, hwdesc->cppi5_desc_paddr))
+               return -ENOMEM;
+
+       /* Start of the TR req records */
+       hwdesc->tr_req_base = hwdesc->cppi5_desc_vaddr + tr_size;
+       /* Start address of the TR response array */
+       hwdesc->tr_resp_base = hwdesc->tr_req_base + tr_size;
+
+       tr_desc = hwdesc->cppi5_desc_vaddr;
+       cppi5_trdesc_init(tr_desc, 1, tr_size, 0, 0);
+       cppi5_desc_set_pktids(tr_desc, 0, CPPI5_INFO1_DESC_FLOWID_DEFAULT);
+       cppi5_desc_set_retpolicy(tr_desc, 0, 0);
+
+       tr_req = hwdesc->tr_req_base;
+       cppi5_tr_init(&tr_req->flags, CPPI5_TR_TYPE1, false, false,
+                     CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
+       cppi5_tr_csf_set(&tr_req->flags, CPPI5_TR_CSF_SUPR_EVT);
+
+       tr_req->addr = rx_flush->buffer_paddr;
+       tr_req->icnt0 = rx_flush->buffer_size;
+       tr_req->icnt1 = 1;
+
+       /* Set up descriptor to be used for packet mode */
+       hwdesc = &rx_flush->hwdescs[1];
+       hwdesc->cppi5_desc_size = ALIGN(sizeof(struct cppi5_host_desc_t) +
+                                       CPPI5_INFO0_HDESC_EPIB_SIZE +
+                                       CPPI5_INFO0_HDESC_PSDATA_MAX_SIZE,
+                                       ud->desc_align);
+
+       hwdesc->cppi5_desc_vaddr = devm_kzalloc(dev, hwdesc->cppi5_desc_size,
+                                               GFP_KERNEL);
+       if (!hwdesc->cppi5_desc_vaddr)
+               return -ENOMEM;
+
+       hwdesc->cppi5_desc_paddr = dma_map_single(dev, hwdesc->cppi5_desc_vaddr,
+                                                 hwdesc->cppi5_desc_size,
+                                                 DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, hwdesc->cppi5_desc_paddr))
+               return -ENOMEM;
+
+       desc = hwdesc->cppi5_desc_vaddr;
+       cppi5_hdesc_init(desc, 0, 0);
+       cppi5_desc_set_pktids(&desc->hdr, 0, CPPI5_INFO1_DESC_FLOWID_DEFAULT);
+       cppi5_desc_set_retpolicy(&desc->hdr, 0, 0);
+
+       cppi5_hdesc_attach_buf(desc,
+                              rx_flush->buffer_paddr, rx_flush->buffer_size,
+                              rx_flush->buffer_paddr, rx_flush->buffer_size);
+
+       dma_sync_single_for_device(dev, hwdesc->cppi5_desc_paddr,
+                                  hwdesc->cppi5_desc_size, DMA_TO_DEVICE);
+       return 0;
+}
+
 #define TI_UDMAC_BUSWIDTHS     (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
                                 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
                                 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
@@ -3361,6 +3586,10 @@ static int udma_probe(struct platform_device *pdev)
        if (ud->desc_align < dma_get_cache_alignment())
                ud->desc_align = dma_get_cache_alignment();
 
+       ret = udma_setup_rx_flush(ud);
+       if (ret)
+               return ret;
+
        for (i = 0; i < ud->tchan_cnt; i++) {
                struct udma_tchan *tchan = &ud->tchans[i];
 
index b3c99bb..fe2eb89 100644 (file)
@@ -523,4 +523,11 @@ config EDAC_BLUEFIELD
          Support for error detection and correction on the
          Mellanox BlueField SoCs.
 
+config EDAC_DMC520
+       tristate "ARM DMC-520 ECC"
+       depends on ARM64
+       help
+         Support for error detection and correction on the
+         SoCs with ARM DMC-520 DRAM controller.
+
 endif # EDAC
index d77200c..269e151 100644 (file)
@@ -87,3 +87,4 @@ obj-$(CONFIG_EDAC_TI)                 += ti_edac.o
 obj-$(CONFIG_EDAC_QCOM)                        += qcom_edac.o
 obj-$(CONFIG_EDAC_ASPEED)              += aspeed_edac.o
 obj-$(CONFIG_EDAC_BLUEFIELD)           += bluefield_edac.o
+obj-$(CONFIG_EDAC_DMC520)              += dmc520_edac.o
index 9fbad90..f91f3bc 100644 (file)
@@ -3626,13 +3626,13 @@ static void setup_pci_device(void)
 }
 
 static const struct x86_cpu_id amd64_cpuids[] = {
-       { X86_VENDOR_AMD, 0xF,  X86_MODEL_ANY,  X86_FEATURE_ANY, 0 },
-       { X86_VENDOR_AMD, 0x10, X86_MODEL_ANY,  X86_FEATURE_ANY, 0 },
-       { X86_VENDOR_AMD, 0x15, X86_MODEL_ANY,  X86_FEATURE_ANY, 0 },
-       { X86_VENDOR_AMD, 0x16, X86_MODEL_ANY,  X86_FEATURE_ANY, 0 },
-       { X86_VENDOR_AMD, 0x17, X86_MODEL_ANY,  X86_FEATURE_ANY, 0 },
-       { X86_VENDOR_HYGON, 0x18, X86_MODEL_ANY, X86_FEATURE_ANY, 0 },
-       { X86_VENDOR_AMD, 0x19, X86_MODEL_ANY,  X86_FEATURE_ANY, 0 },
+       X86_MATCH_VENDOR_FAM(AMD,       0x0F, NULL),
+       X86_MATCH_VENDOR_FAM(AMD,       0x10, NULL),
+       X86_MATCH_VENDOR_FAM(AMD,       0x15, NULL),
+       X86_MATCH_VENDOR_FAM(AMD,       0x16, NULL),
+       X86_MATCH_VENDOR_FAM(AMD,       0x17, NULL),
+       X86_MATCH_VENDOR_FAM(HYGON,     0x18, NULL),
+       X86_MATCH_VENDOR_FAM(AMD,       0x19, NULL),
        { }
 };
 MODULE_DEVICE_TABLE(x86cpu, amd64_cpuids);
index 7f227bd..a7502eb 100644 (file)
@@ -429,26 +429,26 @@ static void aurora_l2_check(struct edac_device_ctl_info *dci)
 
        src = (attr_cap & AURORA_ERR_ATTR_SRC_MSK) >> AURORA_ERR_ATTR_SRC_OFF;
        if (src <= 3)
-               len += snprintf(msg+len, size-len, "src=CPU%d ", src);
+               len += scnprintf(msg+len, size-len, "src=CPU%d ", src);
        else
-               len += snprintf(msg+len, size-len, "src=IO ");
+               len += scnprintf(msg+len, size-len, "src=IO ");
 
        txn =  (attr_cap & AURORA_ERR_ATTR_TXN_MSK) >> AURORA_ERR_ATTR_TXN_OFF;
        switch (txn) {
        case 0:
-               len += snprintf(msg+len, size-len, "txn=Data-Read ");
+               len += scnprintf(msg+len, size-len, "txn=Data-Read ");
                break;
        case 1:
-               len += snprintf(msg+len, size-len, "txn=Isn-Read ");
+               len += scnprintf(msg+len, size-len, "txn=Isn-Read ");
                break;
        case 2:
-               len += snprintf(msg+len, size-len, "txn=Clean-Flush ");
+               len += scnprintf(msg+len, size-len, "txn=Clean-Flush ");
                break;
        case 3:
-               len += snprintf(msg+len, size-len, "txn=Eviction ");
+               len += scnprintf(msg+len, size-len, "txn=Eviction ");
                break;
        case 4:
-               len += snprintf(msg+len, size-len,
+               len += scnprintf(msg+len, size-len,
                                "txn=Read-Modify-Write ");
                break;
        }
@@ -456,19 +456,19 @@ static void aurora_l2_check(struct edac_device_ctl_info *dci)
        err = (attr_cap & AURORA_ERR_ATTR_ERR_MSK) >> AURORA_ERR_ATTR_ERR_OFF;
        switch (err) {
        case 0:
-               len += snprintf(msg+len, size-len, "err=CorrECC ");
+               len += scnprintf(msg+len, size-len, "err=CorrECC ");
                break;
        case 1:
-               len += snprintf(msg+len, size-len, "err=UnCorrECC ");
+               len += scnprintf(msg+len, size-len, "err=UnCorrECC ");
                break;
        case 2:
-               len += snprintf(msg+len, size-len, "err=TagParity ");
+               len += scnprintf(msg+len, size-len, "err=TagParity ");
                break;
        }
 
-       len += snprintf(msg+len, size-len, "addr=0x%x ", addr_cap & AURORA_ERR_ADDR_CAP_ADDR_MASK);
-       len += snprintf(msg+len, size-len, "index=0x%x ", (way_cap & AURORA_ERR_WAY_IDX_MSK) >> AURORA_ERR_WAY_IDX_OFF);
-       len += snprintf(msg+len, size-len, "way=0x%x", (way_cap & AURORA_ERR_WAY_CAP_WAY_MASK) >> AURORA_ERR_WAY_CAP_WAY_OFFSET);
+       len += scnprintf(msg+len, size-len, "addr=0x%x ", addr_cap & AURORA_ERR_ADDR_CAP_ADDR_MASK);
+       len += scnprintf(msg+len, size-len, "index=0x%x ", (way_cap & AURORA_ERR_WAY_IDX_MSK) >> AURORA_ERR_WAY_IDX_OFF);
+       len += scnprintf(msg+len, size-len, "way=0x%x", (way_cap & AURORA_ERR_WAY_CAP_WAY_MASK) >> AURORA_ERR_WAY_CAP_WAY_OFFSET);
 
        /* clear error capture registers */
        writel(AURORA_ERR_ATTR_CAP_VALID, drvdata->base + AURORA_ERR_ATTR_CAP_REG);
diff --git a/drivers/edac/dmc520_edac.c b/drivers/edac/dmc520_edac.c
new file mode 100644 (file)
index 0000000..fc1153a
--- /dev/null
@@ -0,0 +1,656 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * EDAC driver for DMC-520 memory controller.
+ *
+ * The driver supports 10 interrupt lines,
+ * though only dram_ecc_errc and dram_ecc_errd are currently handled.
+ *
+ * Authors:    Rui Zhao <ruizhao@microsoft.com>
+ *             Lei Wang <lewan@microsoft.com>
+ *             Shiping Ji <shji@microsoft.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include "edac_mc.h"
+
+/* DMC-520 registers */
+#define REG_OFFSET_FEATURE_CONFIG                      0x130
+#define REG_OFFSET_ECC_ERRC_COUNT_31_00                0x158
+#define REG_OFFSET_ECC_ERRC_COUNT_63_32                0x15C
+#define REG_OFFSET_ECC_ERRD_COUNT_31_00                0x160
+#define REG_OFFSET_ECC_ERRD_COUNT_63_32                0x164
+#define REG_OFFSET_INTERRUPT_CONTROL                   0x500
+#define REG_OFFSET_INTERRUPT_CLR                       0x508
+#define REG_OFFSET_INTERRUPT_STATUS                    0x510
+#define REG_OFFSET_DRAM_ECC_ERRC_INT_INFO_31_00        0x528
+#define REG_OFFSET_DRAM_ECC_ERRC_INT_INFO_63_32        0x52C
+#define REG_OFFSET_DRAM_ECC_ERRD_INT_INFO_31_00        0x530
+#define REG_OFFSET_DRAM_ECC_ERRD_INT_INFO_63_32        0x534
+#define REG_OFFSET_ADDRESS_CONTROL_NOW                 0x1010
+#define REG_OFFSET_MEMORY_TYPE_NOW                     0x1128
+#define REG_OFFSET_SCRUB_CONTROL0_NOW                  0x1170
+#define REG_OFFSET_FORMAT_CONTROL                      0x18
+
+/* DMC-520 types, masks and bitfields */
+#define RAM_ECC_INT_CE_BIT                     BIT(0)
+#define RAM_ECC_INT_UE_BIT                     BIT(1)
+#define DRAM_ECC_INT_CE_BIT                    BIT(2)
+#define DRAM_ECC_INT_UE_BIT                    BIT(3)
+#define FAILED_ACCESS_INT_BIT                  BIT(4)
+#define FAILED_PROG_INT_BIT                    BIT(5)
+#define LINK_ERR_INT_BIT                       BIT(6)
+#define TEMPERATURE_EVENT_INT_BIT              BIT(7)
+#define ARCH_FSM_INT_BIT                       BIT(8)
+#define PHY_REQUEST_INT_BIT                    BIT(9)
+#define MEMORY_WIDTH_MASK                      GENMASK(1, 0)
+#define SCRUB_TRIGGER0_NEXT_MASK               GENMASK(1, 0)
+#define REG_FIELD_DRAM_ECC_ENABLED             GENMASK(1, 0)
+#define REG_FIELD_MEMORY_TYPE                  GENMASK(2, 0)
+#define REG_FIELD_DEVICE_WIDTH                 GENMASK(9, 8)
+#define REG_FIELD_ADDRESS_CONTROL_COL          GENMASK(2,  0)
+#define REG_FIELD_ADDRESS_CONTROL_ROW          GENMASK(10, 8)
+#define REG_FIELD_ADDRESS_CONTROL_BANK         GENMASK(18, 16)
+#define REG_FIELD_ADDRESS_CONTROL_RANK         GENMASK(25, 24)
+#define REG_FIELD_ERR_INFO_LOW_VALID           BIT(0)
+#define REG_FIELD_ERR_INFO_LOW_COL             GENMASK(10, 1)
+#define REG_FIELD_ERR_INFO_LOW_ROW             GENMASK(28, 11)
+#define REG_FIELD_ERR_INFO_LOW_RANK            GENMASK(31, 29)
+#define REG_FIELD_ERR_INFO_HIGH_BANK           GENMASK(3, 0)
+#define REG_FIELD_ERR_INFO_HIGH_VALID          BIT(31)
+
+#define DRAM_ADDRESS_CONTROL_MIN_COL_BITS      8
+#define DRAM_ADDRESS_CONTROL_MIN_ROW_BITS      11
+
+#define DMC520_SCRUB_TRIGGER_ERR_DETECT        2
+#define DMC520_SCRUB_TRIGGER_IDLE              3
+
+/* Driver settings */
+/*
+ * The max-length message would be: "rank:7 bank:15 row:262143 col:1023".
+ * Max length is 34. Using a 40-size buffer is enough.
+ */
+#define DMC520_MSG_BUF_SIZE                    40
+#define EDAC_MOD_NAME                          "dmc520-edac"
+#define EDAC_CTL_NAME                          "dmc520"
+
+/* the data bus width for the attached memory chips. */
+enum dmc520_mem_width {
+       MEM_WIDTH_X32 = 2,
+       MEM_WIDTH_X64 = 3
+};
+
+/* memory type */
+enum dmc520_mem_type {
+       MEM_TYPE_DDR3 = 1,
+       MEM_TYPE_DDR4 = 2
+};
+
+/* memory device width */
+enum dmc520_dev_width {
+       DEV_WIDTH_X4 = 0,
+       DEV_WIDTH_X8 = 1,
+       DEV_WIDTH_X16 = 2
+};
+
+struct ecc_error_info {
+       u32 col;
+       u32 row;
+       u32 bank;
+       u32 rank;
+};
+
+/* The interrupt config */
+struct dmc520_irq_config {
+       char *name;
+       int mask;
+};
+
+/* The interrupt mappings */
+static struct dmc520_irq_config dmc520_irq_configs[] = {
+       {
+               .name = "ram_ecc_errc",
+               .mask = RAM_ECC_INT_CE_BIT
+       },
+       {
+               .name = "ram_ecc_errd",
+               .mask = RAM_ECC_INT_UE_BIT
+       },
+       {
+               .name = "dram_ecc_errc",
+               .mask = DRAM_ECC_INT_CE_BIT
+       },
+       {
+               .name = "dram_ecc_errd",
+               .mask = DRAM_ECC_INT_UE_BIT
+       },
+       {
+               .name = "failed_access",
+               .mask = FAILED_ACCESS_INT_BIT
+       },
+       {
+               .name = "failed_prog",
+               .mask = FAILED_PROG_INT_BIT
+       },
+       {
+               .name = "link_err",
+               .mask = LINK_ERR_INT_BIT
+       },
+       {
+               .name = "temperature_event",
+               .mask = TEMPERATURE_EVENT_INT_BIT
+       },
+       {
+               .name = "arch_fsm",
+               .mask = ARCH_FSM_INT_BIT
+       },
+       {
+               .name = "phy_request",
+               .mask = PHY_REQUEST_INT_BIT
+       }
+};
+
+#define NUMBER_OF_IRQS                         ARRAY_SIZE(dmc520_irq_configs)
+
+/*
+ * The EDAC driver private data.
+ * error_lock is to protect concurrent writes to the mci->error_desc through
+ * edac_mc_handle_error().
+ */
+struct dmc520_edac {
+       void __iomem *reg_base;
+       spinlock_t error_lock;
+       u32 mem_width_in_bytes;
+       int irqs[NUMBER_OF_IRQS];
+       int masks[NUMBER_OF_IRQS];
+};
+
+static int dmc520_mc_idx;
+
+static u32 dmc520_read_reg(struct dmc520_edac *pvt, u32 offset)
+{
+       return readl(pvt->reg_base + offset);
+}
+
+static void dmc520_write_reg(struct dmc520_edac *pvt, u32 val, u32 offset)
+{
+       writel(val, pvt->reg_base + offset);
+}
+
+static u32 dmc520_calc_dram_ecc_error(u32 value)
+{
+       u32 total = 0;
+
+       /* Each rank's error counter takes one byte. */
+       while (value > 0) {
+               total += (value & 0xFF);
+               value >>= 8;
+       }
+       return total;
+}
+
+static u32 dmc520_get_dram_ecc_error_count(struct dmc520_edac *pvt,
+                                           bool is_ce)
+{
+       u32 reg_offset_low, reg_offset_high;
+       u32 err_low, err_high;
+       u32 err_count;
+
+       reg_offset_low = is_ce ? REG_OFFSET_ECC_ERRC_COUNT_31_00 :
+                                REG_OFFSET_ECC_ERRD_COUNT_31_00;
+       reg_offset_high = is_ce ? REG_OFFSET_ECC_ERRC_COUNT_63_32 :
+                                 REG_OFFSET_ECC_ERRD_COUNT_63_32;
+
+       err_low = dmc520_read_reg(pvt, reg_offset_low);
+       err_high = dmc520_read_reg(pvt, reg_offset_high);
+       /* Reset error counters */
+       dmc520_write_reg(pvt, 0, reg_offset_low);
+       dmc520_write_reg(pvt, 0, reg_offset_high);
+
+       err_count = dmc520_calc_dram_ecc_error(err_low) +
+                  dmc520_calc_dram_ecc_error(err_high);
+
+       return err_count;
+}
+
+static void dmc520_get_dram_ecc_error_info(struct dmc520_edac *pvt,
+                                           bool is_ce,
+                                           struct ecc_error_info *info)
+{
+       u32 reg_offset_low, reg_offset_high;
+       u32 reg_val_low, reg_val_high;
+       bool valid;
+
+       reg_offset_low = is_ce ? REG_OFFSET_DRAM_ECC_ERRC_INT_INFO_31_00 :
+                                REG_OFFSET_DRAM_ECC_ERRD_INT_INFO_31_00;
+       reg_offset_high = is_ce ? REG_OFFSET_DRAM_ECC_ERRC_INT_INFO_63_32 :
+                                 REG_OFFSET_DRAM_ECC_ERRD_INT_INFO_63_32;
+
+       reg_val_low = dmc520_read_reg(pvt, reg_offset_low);
+       reg_val_high = dmc520_read_reg(pvt, reg_offset_high);
+
+       valid = (FIELD_GET(REG_FIELD_ERR_INFO_LOW_VALID, reg_val_low) != 0) &&
+               (FIELD_GET(REG_FIELD_ERR_INFO_HIGH_VALID, reg_val_high) != 0);
+
+       if (valid) {
+               info->col = FIELD_GET(REG_FIELD_ERR_INFO_LOW_COL, reg_val_low);
+               info->row = FIELD_GET(REG_FIELD_ERR_INFO_LOW_ROW, reg_val_low);
+               info->rank = FIELD_GET(REG_FIELD_ERR_INFO_LOW_RANK, reg_val_low);
+               info->bank = FIELD_GET(REG_FIELD_ERR_INFO_HIGH_BANK, reg_val_high);
+       } else {
+               memset(info, 0, sizeof(*info));
+       }
+}
+
+static bool dmc520_is_ecc_enabled(void __iomem *reg_base)
+{
+       u32 reg_val = readl(reg_base + REG_OFFSET_FEATURE_CONFIG);
+
+       return FIELD_GET(REG_FIELD_DRAM_ECC_ENABLED, reg_val);
+}
+
+static enum scrub_type dmc520_get_scrub_type(struct dmc520_edac *pvt)
+{
+       enum scrub_type type = SCRUB_NONE;
+       u32 reg_val, scrub_cfg;
+
+       reg_val = dmc520_read_reg(pvt, REG_OFFSET_SCRUB_CONTROL0_NOW);
+       scrub_cfg = FIELD_GET(SCRUB_TRIGGER0_NEXT_MASK, reg_val);
+
+       if (scrub_cfg == DMC520_SCRUB_TRIGGER_ERR_DETECT ||
+           scrub_cfg == DMC520_SCRUB_TRIGGER_IDLE)
+               type = SCRUB_HW_PROG;
+
+       return type;
+}
+
+/* Get the memory data bus width, in number of bytes. */
+static u32 dmc520_get_memory_width(struct dmc520_edac *pvt)
+{
+       enum dmc520_mem_width mem_width_field;
+       u32 mem_width_in_bytes = 0;
+       u32 reg_val;
+
+       reg_val = dmc520_read_reg(pvt, REG_OFFSET_FORMAT_CONTROL);
+       mem_width_field = FIELD_GET(MEMORY_WIDTH_MASK, reg_val);
+
+       if (mem_width_field == MEM_WIDTH_X32)
+               mem_width_in_bytes = 4;
+       else if (mem_width_field == MEM_WIDTH_X64)
+               mem_width_in_bytes = 8;
+       return mem_width_in_bytes;
+}
+
+static enum mem_type dmc520_get_mtype(struct dmc520_edac *pvt)
+{
+       enum mem_type mt = MEM_UNKNOWN;
+       enum dmc520_mem_type type;
+       u32 reg_val;
+
+       reg_val = dmc520_read_reg(pvt, REG_OFFSET_MEMORY_TYPE_NOW);
+       type = FIELD_GET(REG_FIELD_MEMORY_TYPE, reg_val);
+
+       switch (type) {
+       case MEM_TYPE_DDR3:
+               mt = MEM_DDR3;
+               break;
+
+       case MEM_TYPE_DDR4:
+               mt = MEM_DDR4;
+               break;
+       }
+
+       return mt;
+}
+
+static enum dev_type dmc520_get_dtype(struct dmc520_edac *pvt)
+{
+       enum dmc520_dev_width device_width;
+       enum dev_type dt = DEV_UNKNOWN;
+       u32 reg_val;
+
+       reg_val = dmc520_read_reg(pvt, REG_OFFSET_MEMORY_TYPE_NOW);
+       device_width = FIELD_GET(REG_FIELD_DEVICE_WIDTH, reg_val);
+
+       switch (device_width) {
+       case DEV_WIDTH_X4:
+               dt = DEV_X4;
+               break;
+
+       case DEV_WIDTH_X8:
+               dt = DEV_X8;
+               break;
+
+       case DEV_WIDTH_X16:
+               dt = DEV_X16;
+               break;
+       }
+
+       return dt;
+}
+
+static u32 dmc520_get_rank_count(void __iomem *reg_base)
+{
+       u32 reg_val, rank_bits;
+
+       reg_val = readl(reg_base + REG_OFFSET_ADDRESS_CONTROL_NOW);
+       rank_bits = FIELD_GET(REG_FIELD_ADDRESS_CONTROL_RANK, reg_val);
+
+       return BIT(rank_bits);
+}
+
+static u64 dmc520_get_rank_size(struct dmc520_edac *pvt)
+{
+       u32 reg_val, col_bits, row_bits, bank_bits;
+
+       reg_val = dmc520_read_reg(pvt, REG_OFFSET_ADDRESS_CONTROL_NOW);
+
+       col_bits = FIELD_GET(REG_FIELD_ADDRESS_CONTROL_COL, reg_val) +
+                  DRAM_ADDRESS_CONTROL_MIN_COL_BITS;
+       row_bits = FIELD_GET(REG_FIELD_ADDRESS_CONTROL_ROW, reg_val) +
+                  DRAM_ADDRESS_CONTROL_MIN_ROW_BITS;
+       bank_bits = FIELD_GET(REG_FIELD_ADDRESS_CONTROL_BANK, reg_val);
+
+       return (u64)pvt->mem_width_in_bytes << (col_bits + row_bits + bank_bits);
+}
+
+static void dmc520_handle_dram_ecc_errors(struct mem_ctl_info *mci,
+                                          bool is_ce)
+{
+       struct dmc520_edac *pvt = mci->pvt_info;
+       char message[DMC520_MSG_BUF_SIZE];
+       struct ecc_error_info info;
+       u32 cnt;
+
+       dmc520_get_dram_ecc_error_info(pvt, is_ce, &info);
+
+       cnt = dmc520_get_dram_ecc_error_count(pvt, is_ce);
+       if (!cnt)
+               return;
+
+       snprintf(message, ARRAY_SIZE(message),
+                "rank:%d bank:%d row:%d col:%d",
+                info.rank, info.bank,
+                info.row, info.col);
+
+       spin_lock(&pvt->error_lock);
+       edac_mc_handle_error((is_ce ? HW_EVENT_ERR_CORRECTED :
+                            HW_EVENT_ERR_UNCORRECTED),
+                            mci, cnt, 0, 0, 0, info.rank, -1, -1,
+                            message, "");
+       spin_unlock(&pvt->error_lock);
+}
+
+static irqreturn_t dmc520_edac_dram_ecc_isr(int irq, struct mem_ctl_info *mci,
+                                            bool is_ce)
+{
+       struct dmc520_edac *pvt = mci->pvt_info;
+       u32 i_mask;
+
+       i_mask = is_ce ? DRAM_ECC_INT_CE_BIT : DRAM_ECC_INT_UE_BIT;
+
+       dmc520_handle_dram_ecc_errors(mci, is_ce);
+
+       dmc520_write_reg(pvt, i_mask, REG_OFFSET_INTERRUPT_CLR);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t dmc520_edac_dram_all_isr(int irq, struct mem_ctl_info *mci,
+                                            u32 irq_mask)
+{
+       struct dmc520_edac *pvt = mci->pvt_info;
+       irqreturn_t irq_ret = IRQ_NONE;
+       u32 status;
+
+       status = dmc520_read_reg(pvt, REG_OFFSET_INTERRUPT_STATUS);
+
+       if ((irq_mask & DRAM_ECC_INT_CE_BIT) &&
+               (status & DRAM_ECC_INT_CE_BIT))
+               irq_ret = dmc520_edac_dram_ecc_isr(irq, mci, true);
+
+       if ((irq_mask & DRAM_ECC_INT_UE_BIT) &&
+               (status & DRAM_ECC_INT_UE_BIT))
+               irq_ret = dmc520_edac_dram_ecc_isr(irq, mci, false);
+
+       return irq_ret;
+}
+
+static irqreturn_t dmc520_isr(int irq, void *data)
+{
+       struct mem_ctl_info *mci = data;
+       struct dmc520_edac *pvt = mci->pvt_info;
+       u32 mask = 0;
+       int idx;
+
+       for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
+               if (pvt->irqs[idx] == irq) {
+                       mask = pvt->masks[idx];
+                       break;
+               }
+       }
+       return dmc520_edac_dram_all_isr(irq, mci, mask);
+}
+
+static void dmc520_init_csrow(struct mem_ctl_info *mci)
+{
+       struct dmc520_edac *pvt = mci->pvt_info;
+       struct csrow_info *csi;
+       struct dimm_info *dimm;
+       u32 pages_per_rank;
+       enum dev_type dt;
+       enum mem_type mt;
+       int row, ch;
+       u64 rs;
+
+       dt = dmc520_get_dtype(pvt);
+       mt = dmc520_get_mtype(pvt);
+       rs = dmc520_get_rank_size(pvt);
+       pages_per_rank = rs >> PAGE_SHIFT;
+
+       for (row = 0; row < mci->nr_csrows; row++) {
+               csi = mci->csrows[row];
+
+               for (ch = 0; ch < csi->nr_channels; ch++) {
+                       dimm            = csi->channels[ch]->dimm;
+                       dimm->grain     = pvt->mem_width_in_bytes;
+                       dimm->dtype     = dt;
+                       dimm->mtype     = mt;
+                       dimm->edac_mode = EDAC_FLAG_SECDED;
+                       dimm->nr_pages  = pages_per_rank / csi->nr_channels;
+               }
+       }
+}
+
+static int dmc520_edac_probe(struct platform_device *pdev)
+{
+       bool registered[NUMBER_OF_IRQS] = { false };
+       int irqs[NUMBER_OF_IRQS] = { -ENXIO };
+       int masks[NUMBER_OF_IRQS] = { 0 };
+       struct edac_mc_layer layers[1];
+       struct dmc520_edac *pvt = NULL;
+       struct mem_ctl_info *mci;
+       void __iomem *reg_base;
+       u32 irq_mask_all = 0;
+       struct resource *res;
+       struct device *dev;
+       int ret, idx, irq;
+       u32 reg_val;
+
+       /* Parse the device node */
+       dev = &pdev->dev;
+
+       for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
+               irq = platform_get_irq_byname(pdev, dmc520_irq_configs[idx].name);
+               irqs[idx] = irq;
+               masks[idx] = dmc520_irq_configs[idx].mask;
+               if (irq >= 0) {
+                       irq_mask_all |= dmc520_irq_configs[idx].mask;
+                       edac_dbg(0, "Discovered %s, irq: %d.\n", dmc520_irq_configs[idx].name, irq);
+               }
+       }
+
+       if (!irq_mask_all) {
+               edac_printk(KERN_ERR, EDAC_MOD_NAME,
+                           "At least one valid interrupt line is expected.\n");
+               return -EINVAL;
+       }
+
+       /* Initialize dmc520 edac */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       reg_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(reg_base))
+               return PTR_ERR(reg_base);
+
+       if (!dmc520_is_ecc_enabled(reg_base))
+               return -ENXIO;
+
+       layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+       layers[0].size = dmc520_get_rank_count(reg_base);
+       layers[0].is_virt_csrow = true;
+
+       mci = edac_mc_alloc(dmc520_mc_idx++, ARRAY_SIZE(layers), layers, sizeof(*pvt));
+       if (!mci) {
+               edac_printk(KERN_ERR, EDAC_MOD_NAME,
+                           "Failed to allocate memory for mc instance\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       pvt = mci->pvt_info;
+
+       pvt->reg_base = reg_base;
+       spin_lock_init(&pvt->error_lock);
+       memcpy(pvt->irqs, irqs, sizeof(irqs));
+       memcpy(pvt->masks, masks, sizeof(masks));
+
+       platform_set_drvdata(pdev, mci);
+
+       mci->pdev = dev;
+       mci->mtype_cap          = MEM_FLAG_DDR3 | MEM_FLAG_DDR4;
+       mci->edac_ctl_cap       = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+       mci->edac_cap           = EDAC_FLAG_SECDED;
+       mci->scrub_cap          = SCRUB_FLAG_HW_SRC;
+       mci->scrub_mode         = dmc520_get_scrub_type(pvt);
+       mci->ctl_name           = EDAC_CTL_NAME;
+       mci->dev_name           = dev_name(mci->pdev);
+       mci->mod_name           = EDAC_MOD_NAME;
+
+       edac_op_state = EDAC_OPSTATE_INT;
+
+       pvt->mem_width_in_bytes = dmc520_get_memory_width(pvt);
+
+       dmc520_init_csrow(mci);
+
+       /* Clear interrupts, not affecting other unrelated interrupts */
+       reg_val = dmc520_read_reg(pvt, REG_OFFSET_INTERRUPT_CONTROL);
+       dmc520_write_reg(pvt, reg_val & (~irq_mask_all),
+                        REG_OFFSET_INTERRUPT_CONTROL);
+       dmc520_write_reg(pvt, irq_mask_all, REG_OFFSET_INTERRUPT_CLR);
+
+       for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
+               irq = irqs[idx];
+               if (irq >= 0) {
+                       ret = devm_request_irq(&pdev->dev, irq,
+                                              dmc520_isr, IRQF_SHARED,
+                                              dev_name(&pdev->dev), mci);
+                       if (ret < 0) {
+                               edac_printk(KERN_ERR, EDAC_MC,
+                                           "Failed to request irq %d\n", irq);
+                               goto err;
+                       }
+                       registered[idx] = true;
+               }
+       }
+
+       /* Reset DRAM CE/UE counters */
+       if (irq_mask_all & DRAM_ECC_INT_CE_BIT)
+               dmc520_get_dram_ecc_error_count(pvt, true);
+
+       if (irq_mask_all & DRAM_ECC_INT_UE_BIT)
+               dmc520_get_dram_ecc_error_count(pvt, false);
+
+       ret = edac_mc_add_mc(mci);
+       if (ret) {
+               edac_printk(KERN_ERR, EDAC_MOD_NAME,
+                           "Failed to register with EDAC core\n");
+               goto err;
+       }
+
+       /* Enable interrupts, not affecting other unrelated interrupts */
+       dmc520_write_reg(pvt, reg_val | irq_mask_all,
+                        REG_OFFSET_INTERRUPT_CONTROL);
+
+       return 0;
+
+err:
+       for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
+               if (registered[idx])
+                       devm_free_irq(&pdev->dev, pvt->irqs[idx], mci);
+       }
+       if (mci)
+               edac_mc_free(mci);
+
+       return ret;
+}
+
+static int dmc520_edac_remove(struct platform_device *pdev)
+{
+       u32 reg_val, idx, irq_mask_all = 0;
+       struct mem_ctl_info *mci;
+       struct dmc520_edac *pvt;
+
+       mci = platform_get_drvdata(pdev);
+       pvt = mci->pvt_info;
+
+       /* Disable interrupts */
+       reg_val = dmc520_read_reg(pvt, REG_OFFSET_INTERRUPT_CONTROL);
+       dmc520_write_reg(pvt, reg_val & (~irq_mask_all),
+                        REG_OFFSET_INTERRUPT_CONTROL);
+
+       /* free irq's */
+       for (idx = 0; idx < NUMBER_OF_IRQS; idx++) {
+               if (pvt->irqs[idx] >= 0) {
+                       irq_mask_all |= pvt->masks[idx];
+                       devm_free_irq(&pdev->dev, pvt->irqs[idx], mci);
+               }
+       }
+
+       edac_mc_del_mc(&pdev->dev);
+       edac_mc_free(mci);
+
+       return 0;
+}
+
+static const struct of_device_id dmc520_edac_driver_id[] = {
+       { .compatible = "arm,dmc-520", },
+       { /* end of table */ }
+};
+
+MODULE_DEVICE_TABLE(of, dmc520_edac_driver_id);
+
+static struct platform_driver dmc520_edac_driver = {
+       .driver = {
+               .name = "dmc520",
+               .of_match_table = dmc520_edac_driver_id,
+       },
+
+       .probe = dmc520_edac_probe,
+       .remove = dmc520_edac_remove
+};
+
+module_platform_driver(dmc520_edac_driver);
+
+MODULE_AUTHOR("Rui Zhao <ruizhao@microsoft.com>");
+MODULE_AUTHOR("Lei Wang <lewan@microsoft.com>");
+MODULE_AUTHOR("Shiping Ji <shji@microsoft.com>");
+MODULE_DESCRIPTION("DMC-520 ECC driver");
+MODULE_LICENSE("GPL v2");
index 69e0d90..75ede27 100644 (file)
@@ -55,6 +55,11 @@ static LIST_HEAD(mc_devices);
  */
 static const char *edac_mc_owner;
 
+static struct mem_ctl_info *error_desc_to_mci(struct edac_raw_error_desc *e)
+{
+       return container_of(e, struct mem_ctl_info, error_desc);
+}
+
 int edac_get_report_status(void)
 {
        return edac_report;
@@ -278,6 +283,12 @@ void *edac_align_ptr(void **p, unsigned int size, int n_elems)
 
 static void _edac_mc_free(struct mem_ctl_info *mci)
 {
+       put_device(&mci->dev);
+}
+
+static void mci_release(struct device *dev)
+{
+       struct mem_ctl_info *mci = container_of(dev, struct mem_ctl_info, dev);
        struct csrow_info *csr;
        int i, chn, row;
 
@@ -305,103 +316,26 @@ static void _edac_mc_free(struct mem_ctl_info *mci)
        kfree(mci);
 }
 
-struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
-                                  unsigned int n_layers,
-                                  struct edac_mc_layer *layers,
-                                  unsigned int sz_pvt)
+static int edac_mc_alloc_csrows(struct mem_ctl_info *mci)
 {
-       struct mem_ctl_info *mci;
-       struct edac_mc_layer *layer;
-       struct csrow_info *csr;
-       struct rank_info *chan;
-       struct dimm_info *dimm;
-       u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
-       unsigned int pos[EDAC_MAX_LAYERS];
-       unsigned int idx, size, tot_dimms = 1, count = 1;
-       unsigned int tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
-       void *pvt, *p, *ptr = NULL;
-       int i, j, row, chn, n, len;
-       bool per_rank = false;
-
-       if (WARN_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0))
-               return NULL;
-
-       /*
-        * Calculate the total amount of dimms and csrows/cschannels while
-        * in the old API emulation mode
-        */
-       for (idx = 0; idx < n_layers; idx++) {
-               tot_dimms *= layers[idx].size;
-
-               if (layers[idx].is_virt_csrow)
-                       tot_csrows *= layers[idx].size;
-               else
-                       tot_channels *= layers[idx].size;
-
-               if (layers[idx].type == EDAC_MC_LAYER_CHIP_SELECT)
-                       per_rank = true;
-       }
-
-       /* Figure out the offsets of the various items from the start of an mc
-        * structure.  We want the alignment of each item to be at least as
-        * stringent as what the compiler would provide if we could simply
-        * hardcode everything into a single struct.
-        */
-       mci = edac_align_ptr(&ptr, sizeof(*mci), 1);
-       layer = edac_align_ptr(&ptr, sizeof(*layer), n_layers);
-       for (i = 0; i < n_layers; i++) {
-               count *= layers[i].size;
-               edac_dbg(4, "errcount layer %d size %d\n", i, count);
-               ce_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count);
-               ue_per_layer[i] = edac_align_ptr(&ptr, sizeof(u32), count);
-               tot_errcount += 2 * count;
-       }
-
-       edac_dbg(4, "allocating %d error counters\n", tot_errcount);
-       pvt = edac_align_ptr(&ptr, sz_pvt, 1);
-       size = ((unsigned long)pvt) + sz_pvt;
-
-       edac_dbg(1, "allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
-                size,
-                tot_dimms,
-                per_rank ? "ranks" : "dimms",
-                tot_csrows * tot_channels);
-
-       mci = kzalloc(size, GFP_KERNEL);
-       if (mci == NULL)
-               return NULL;
-
-       /* Adjust pointers so they point within the memory we just allocated
-        * rather than an imaginary chunk of memory located at address 0.
-        */
-       layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
-       for (i = 0; i < n_layers; i++) {
-               mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i]));
-               mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i]));
-       }
-       pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
-
-       /* setup index and various internal pointers */
-       mci->mc_idx = mc_num;
-       mci->tot_dimms = tot_dimms;
-       mci->pvt_info = pvt;
-       mci->n_layers = n_layers;
-       mci->layers = layer;
-       memcpy(mci->layers, layers, sizeof(*layer) * n_layers);
-       mci->nr_csrows = tot_csrows;
-       mci->num_cschannel = tot_channels;
-       mci->csbased = per_rank;
+       unsigned int tot_channels = mci->num_cschannel;
+       unsigned int tot_csrows = mci->nr_csrows;
+       unsigned int row, chn;
 
        /*
         * Alocate and fill the csrow/channels structs
         */
        mci->csrows = kcalloc(tot_csrows, sizeof(*mci->csrows), GFP_KERNEL);
        if (!mci->csrows)
-               goto error;
+               return -ENOMEM;
+
        for (row = 0; row < tot_csrows; row++) {
+               struct csrow_info *csr;
+
                csr = kzalloc(sizeof(**mci->csrows), GFP_KERNEL);
                if (!csr)
-                       goto error;
+                       return -ENOMEM;
+
                mci->csrows[row] = csr;
                csr->csrow_idx = row;
                csr->mci = mci;
@@ -409,34 +343,51 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
                csr->channels = kcalloc(tot_channels, sizeof(*csr->channels),
                                        GFP_KERNEL);
                if (!csr->channels)
-                       goto error;
+                       return -ENOMEM;
 
                for (chn = 0; chn < tot_channels; chn++) {
+                       struct rank_info *chan;
+
                        chan = kzalloc(sizeof(**csr->channels), GFP_KERNEL);
                        if (!chan)
-                               goto error;
+                               return -ENOMEM;
+
                        csr->channels[chn] = chan;
                        chan->chan_idx = chn;
                        chan->csrow = csr;
                }
        }
 
+       return 0;
+}
+
+static int edac_mc_alloc_dimms(struct mem_ctl_info *mci)
+{
+       unsigned int pos[EDAC_MAX_LAYERS];
+       unsigned int row, chn, idx;
+       int layer;
+       void *p;
+
        /*
         * Allocate and fill the dimm structs
         */
-       mci->dimms  = kcalloc(tot_dimms, sizeof(*mci->dimms), GFP_KERNEL);
+       mci->dimms  = kcalloc(mci->tot_dimms, sizeof(*mci->dimms), GFP_KERNEL);
        if (!mci->dimms)
-               goto error;
+               return -ENOMEM;
 
        memset(&pos, 0, sizeof(pos));
        row = 0;
        chn = 0;
-       for (idx = 0; idx < tot_dimms; idx++) {
+       for (idx = 0; idx < mci->tot_dimms; idx++) {
+               struct dimm_info *dimm;
+               struct rank_info *chan;
+               int n, len;
+
                chan = mci->csrows[row]->channels[chn];
 
                dimm = kzalloc(sizeof(**mci->dimms), GFP_KERNEL);
                if (!dimm)
-                       goto error;
+                       return -ENOMEM;
                mci->dimms[idx] = dimm;
                dimm->mci = mci;
                dimm->idx = idx;
@@ -446,16 +397,16 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
                 */
                len = sizeof(dimm->label);
                p = dimm->label;
-               n = snprintf(p, len, "mc#%u", mc_num);
+               n = snprintf(p, len, "mc#%u", mci->mc_idx);
                p += n;
                len -= n;
-               for (j = 0; j < n_layers; j++) {
+               for (layer = 0; layer < mci->n_layers; layer++) {
                        n = snprintf(p, len, "%s#%u",
-                                    edac_layer_name[layers[j].type],
-                                    pos[j]);
+                                    edac_layer_name[mci->layers[layer].type],
+                                    pos[layer]);
                        p += n;
                        len -= n;
-                       dimm->location[j] = pos[j];
+                       dimm->location[layer] = pos[layer];
 
                        if (len <= 0)
                                break;
@@ -467,29 +418,109 @@ struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
                dimm->cschannel = chn;
 
                /* Increment csrow location */
-               if (layers[0].is_virt_csrow) {
+               if (mci->layers[0].is_virt_csrow) {
                        chn++;
-                       if (chn == tot_channels) {
+                       if (chn == mci->num_cschannel) {
                                chn = 0;
                                row++;
                        }
                } else {
                        row++;
-                       if (row == tot_csrows) {
+                       if (row == mci->nr_csrows) {
                                row = 0;
                                chn++;
                        }
                }
 
                /* Increment dimm location */
-               for (j = n_layers - 1; j >= 0; j--) {
-                       pos[j]++;
-                       if (pos[j] < layers[j].size)
+               for (layer = mci->n_layers - 1; layer >= 0; layer--) {
+                       pos[layer]++;
+                       if (pos[layer] < mci->layers[layer].size)
                                break;
-                       pos[j] = 0;
+                       pos[layer] = 0;
                }
        }
 
+       return 0;
+}
+
+struct mem_ctl_info *edac_mc_alloc(unsigned int mc_num,
+                                  unsigned int n_layers,
+                                  struct edac_mc_layer *layers,
+                                  unsigned int sz_pvt)
+{
+       struct mem_ctl_info *mci;
+       struct edac_mc_layer *layer;
+       unsigned int idx, size, tot_dimms = 1;
+       unsigned int tot_csrows = 1, tot_channels = 1;
+       void *pvt, *ptr = NULL;
+       bool per_rank = false;
+
+       if (WARN_ON(n_layers > EDAC_MAX_LAYERS || n_layers == 0))
+               return NULL;
+
+       /*
+        * Calculate the total amount of dimms and csrows/cschannels while
+        * in the old API emulation mode
+        */
+       for (idx = 0; idx < n_layers; idx++) {
+               tot_dimms *= layers[idx].size;
+
+               if (layers[idx].is_virt_csrow)
+                       tot_csrows *= layers[idx].size;
+               else
+                       tot_channels *= layers[idx].size;
+
+               if (layers[idx].type == EDAC_MC_LAYER_CHIP_SELECT)
+                       per_rank = true;
+       }
+
+       /* Figure out the offsets of the various items from the start of an mc
+        * structure.  We want the alignment of each item to be at least as
+        * stringent as what the compiler would provide if we could simply
+        * hardcode everything into a single struct.
+        */
+       mci     = edac_align_ptr(&ptr, sizeof(*mci), 1);
+       layer   = edac_align_ptr(&ptr, sizeof(*layer), n_layers);
+       pvt     = edac_align_ptr(&ptr, sz_pvt, 1);
+       size    = ((unsigned long)pvt) + sz_pvt;
+
+       edac_dbg(1, "allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
+                size,
+                tot_dimms,
+                per_rank ? "ranks" : "dimms",
+                tot_csrows * tot_channels);
+
+       mci = kzalloc(size, GFP_KERNEL);
+       if (mci == NULL)
+               return NULL;
+
+       mci->dev.release = mci_release;
+       device_initialize(&mci->dev);
+
+       /* Adjust pointers so they point within the memory we just allocated
+        * rather than an imaginary chunk of memory located at address 0.
+        */
+       layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
+       pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
+
+       /* setup index and various internal pointers */
+       mci->mc_idx = mc_num;
+       mci->tot_dimms = tot_dimms;
+       mci->pvt_info = pvt;
+       mci->n_layers = n_layers;
+       mci->layers = layer;
+       memcpy(mci->layers, layers, sizeof(*layer) * n_layers);
+       mci->nr_csrows = tot_csrows;
+       mci->num_cschannel = tot_channels;
+       mci->csbased = per_rank;
+
+       if (edac_mc_alloc_csrows(mci))
+               goto error;
+
+       if (edac_mc_alloc_dimms(mci))
+               goto error;
+
        mci->op_state = OP_ALLOC;
 
        return mci;
@@ -505,9 +536,6 @@ void edac_mc_free(struct mem_ctl_info *mci)
 {
        edac_dbg(1, "\n");
 
-       if (device_is_registered(&mci->dev))
-               edac_unregister_sysfs(mci);
-
        _edac_mc_free(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
@@ -902,88 +930,51 @@ const char *edac_layer_name[] = {
 };
 EXPORT_SYMBOL_GPL(edac_layer_name);
 
-static void edac_inc_ce_error(struct mem_ctl_info *mci,
-                             bool enable_per_layer_report,
-                             const int pos[EDAC_MAX_LAYERS],
-                             const u16 count)
+static void edac_inc_ce_error(struct edac_raw_error_desc *e)
 {
-       int i, index = 0;
-
-       mci->ce_mc += count;
-
-       if (!enable_per_layer_report) {
-               mci->ce_noinfo_count += count;
-               return;
-       }
+       int pos[EDAC_MAX_LAYERS] = { e->top_layer, e->mid_layer, e->low_layer };
+       struct mem_ctl_info *mci = error_desc_to_mci(e);
+       struct dimm_info *dimm = edac_get_dimm(mci, pos[0], pos[1], pos[2]);
 
-       for (i = 0; i < mci->n_layers; i++) {
-               if (pos[i] < 0)
-                       break;
-               index += pos[i];
-               mci->ce_per_layer[i][index] += count;
+       mci->ce_mc += e->error_count;
 
-               if (i < mci->n_layers - 1)
-                       index *= mci->layers[i + 1].size;
-       }
+       if (dimm)
+               dimm->ce_count += e->error_count;
+       else
+               mci->ce_noinfo_count += e->error_count;
 }
 
-static void edac_inc_ue_error(struct mem_ctl_info *mci,
-                                   bool enable_per_layer_report,
-                                   const int pos[EDAC_MAX_LAYERS],
-                                   const u16 count)
+static void edac_inc_ue_error(struct edac_raw_error_desc *e)
 {
-       int i, index = 0;
-
-       mci->ue_mc += count;
-
-       if (!enable_per_layer_report) {
-               mci->ue_noinfo_count += count;
-               return;
-       }
+       int pos[EDAC_MAX_LAYERS] = { e->top_layer, e->mid_layer, e->low_layer };
+       struct mem_ctl_info *mci = error_desc_to_mci(e);
+       struct dimm_info *dimm = edac_get_dimm(mci, pos[0], pos[1], pos[2]);
 
-       for (i = 0; i < mci->n_layers; i++) {
-               if (pos[i] < 0)
-                       break;
-               index += pos[i];
-               mci->ue_per_layer[i][index] += count;
+       mci->ue_mc += e->error_count;
 
-               if (i < mci->n_layers - 1)
-                       index *= mci->layers[i + 1].size;
-       }
+       if (dimm)
+               dimm->ue_count += e->error_count;
+       else
+               mci->ue_noinfo_count += e->error_count;
 }
 
-static void edac_ce_error(struct mem_ctl_info *mci,
-                         const u16 error_count,
-                         const int pos[EDAC_MAX_LAYERS],
-                         const char *msg,
-                         const char *location,
-                         const char *label,
-                         const char *detail,
-                         const char *other_detail,
-                         const bool enable_per_layer_report,
-                         const unsigned long page_frame_number,
-                         const unsigned long offset_in_page,
-                         long grain)
+static void edac_ce_error(struct edac_raw_error_desc *e)
 {
+       struct mem_ctl_info *mci = error_desc_to_mci(e);
        unsigned long remapped_page;
-       char *msg_aux = "";
-
-       if (*msg)
-               msg_aux = " ";
 
        if (edac_mc_get_log_ce()) {
-               if (other_detail && *other_detail)
-                       edac_mc_printk(mci, KERN_WARNING,
-                                      "%d CE %s%son %s (%s %s - %s)\n",
-                                      error_count, msg, msg_aux, label,
-                                      location, detail, other_detail);
-               else
-                       edac_mc_printk(mci, KERN_WARNING,
-                                      "%d CE %s%son %s (%s %s)\n",
-                                      error_count, msg, msg_aux, label,
-                                      location, detail);
+               edac_mc_printk(mci, KERN_WARNING,
+                       "%d CE %s%son %s (%s page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx%s%s)\n",
+                       e->error_count, e->msg,
+                       *e->msg ? " " : "",
+                       e->label, e->location, e->page_frame_number, e->offset_in_page,
+                       e->grain, e->syndrome,
+                       *e->other_detail ? " - " : "",
+                       e->other_detail);
        }
-       edac_inc_ce_error(mci, enable_per_layer_report, pos, error_count);
+
+       edac_inc_ce_error(e);
 
        if (mci->scrub_mode == SCRUB_SW_SRC) {
                /*
@@ -998,60 +989,64 @@ static void edac_ce_error(struct mem_ctl_info *mci,
                        * be scrubbed.
                        */
                remapped_page = mci->ctl_page_to_phys ?
-                       mci->ctl_page_to_phys(mci, page_frame_number) :
-                       page_frame_number;
+                       mci->ctl_page_to_phys(mci, e->page_frame_number) :
+                       e->page_frame_number;
 
-               edac_mc_scrub_block(remapped_page,
-                                       offset_in_page, grain);
+               edac_mc_scrub_block(remapped_page, e->offset_in_page, e->grain);
        }
 }
 
-static void edac_ue_error(struct mem_ctl_info *mci,
-                         const u16 error_count,
-                         const int pos[EDAC_MAX_LAYERS],
-                         const char *msg,
-                         const char *location,
-                         const char *label,
-                         const char *detail,
-                         const char *other_detail,
-                         const bool enable_per_layer_report)
+static void edac_ue_error(struct edac_raw_error_desc *e)
 {
-       char *msg_aux = "";
-
-       if (*msg)
-               msg_aux = " ";
+       struct mem_ctl_info *mci = error_desc_to_mci(e);
 
        if (edac_mc_get_log_ue()) {
-               if (other_detail && *other_detail)
-                       edac_mc_printk(mci, KERN_WARNING,
-                                      "%d UE %s%son %s (%s %s - %s)\n",
-                                      error_count, msg, msg_aux, label,
-                                      location, detail, other_detail);
-               else
-                       edac_mc_printk(mci, KERN_WARNING,
-                                      "%d UE %s%son %s (%s %s)\n",
-                                      error_count, msg, msg_aux, label,
-                                      location, detail);
+               edac_mc_printk(mci, KERN_WARNING,
+                       "%d UE %s%son %s (%s page:0x%lx offset:0x%lx grain:%ld%s%s)\n",
+                       e->error_count, e->msg,
+                       *e->msg ? " " : "",
+                       e->label, e->location, e->page_frame_number, e->offset_in_page,
+                       e->grain,
+                       *e->other_detail ? " - " : "",
+                       e->other_detail);
        }
 
        if (edac_mc_get_panic_on_ue()) {
-               if (other_detail && *other_detail)
-                       panic("UE %s%son %s (%s%s - %s)\n",
-                             msg, msg_aux, label, location, detail, other_detail);
-               else
-                       panic("UE %s%son %s (%s%s)\n",
-                             msg, msg_aux, label, location, detail);
+               panic("UE %s%son %s (%s page:0x%lx offset:0x%lx grain:%ld%s%s)\n",
+                       e->msg,
+                       *e->msg ? " " : "",
+                       e->label, e->location, e->page_frame_number, e->offset_in_page,
+                       e->grain,
+                       *e->other_detail ? " - " : "",
+                       e->other_detail);
        }
 
-       edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count);
+       edac_inc_ue_error(e);
 }
 
-void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type,
-                             struct mem_ctl_info *mci,
-                             struct edac_raw_error_desc *e)
+static void edac_inc_csrow(struct edac_raw_error_desc *e, int row, int chan)
 {
-       char detail[80];
-       int pos[EDAC_MAX_LAYERS] = { e->top_layer, e->mid_layer, e->low_layer };
+       struct mem_ctl_info *mci = error_desc_to_mci(e);
+       enum hw_event_mc_err_type type = e->type;
+       u16 count = e->error_count;
+
+       if (row < 0)
+               return;
+
+       edac_dbg(4, "csrow/channel to increment: (%d,%d)\n", row, chan);
+
+       if (type == HW_EVENT_ERR_CORRECTED) {
+               mci->csrows[row]->ce_count += count;
+               if (chan >= 0)
+                       mci->csrows[row]->channels[chan]->ce_count += count;
+       } else {
+               mci->csrows[row]->ue_count += count;
+       }
+}
+
+void edac_raw_mc_handle_error(struct edac_raw_error_desc *e)
+{
+       struct mem_ctl_info *mci = error_desc_to_mci(e);
        u8 grain_bits;
 
        /* Sanity-check driver-supplied grain value. */
@@ -1062,31 +1057,16 @@ void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type,
 
        /* Report the error via the trace interface */
        if (IS_ENABLED(CONFIG_RAS))
-               trace_mc_event(type, e->msg, e->label, e->error_count,
+               trace_mc_event(e->type, e->msg, e->label, e->error_count,
                               mci->mc_idx, e->top_layer, e->mid_layer,
                               e->low_layer,
                               (e->page_frame_number << PAGE_SHIFT) | e->offset_in_page,
                               grain_bits, e->syndrome, e->other_detail);
 
-       /* Memory type dependent details about the error */
-       if (type == HW_EVENT_ERR_CORRECTED) {
-               snprintf(detail, sizeof(detail),
-                       "page:0x%lx offset:0x%lx grain:%ld syndrome:0x%lx",
-                       e->page_frame_number, e->offset_in_page,
-                       e->grain, e->syndrome);
-               edac_ce_error(mci, e->error_count, pos, e->msg, e->location, e->label,
-                             detail, e->other_detail, e->enable_per_layer_report,
-                             e->page_frame_number, e->offset_in_page, e->grain);
-       } else {
-               snprintf(detail, sizeof(detail),
-                       "page:0x%lx offset:0x%lx grain:%ld",
-                       e->page_frame_number, e->offset_in_page, e->grain);
-
-               edac_ue_error(mci, e->error_count, pos, e->msg, e->location, e->label,
-                             detail, e->other_detail, e->enable_per_layer_report);
-       }
-
-
+       if (e->type == HW_EVENT_ERR_CORRECTED)
+               edac_ce_error(e);
+       else
+               edac_ue_error(e);
 }
 EXPORT_SYMBOL_GPL(edac_raw_mc_handle_error);
 
@@ -1108,25 +1088,27 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
        int pos[EDAC_MAX_LAYERS] = { top_layer, mid_layer, low_layer };
        int i, n_labels = 0;
        struct edac_raw_error_desc *e = &mci->error_desc;
+       bool any_memory = true;
 
        edac_dbg(3, "MC%d\n", mci->mc_idx);
 
        /* Fills the error report buffer */
        memset(e, 0, sizeof (*e));
        e->error_count = error_count;
+       e->type = type;
        e->top_layer = top_layer;
        e->mid_layer = mid_layer;
        e->low_layer = low_layer;
        e->page_frame_number = page_frame_number;
        e->offset_in_page = offset_in_page;
        e->syndrome = syndrome;
-       e->msg = msg;
-       e->other_detail = other_detail;
+       /* need valid strings here for both: */
+       e->msg = msg ?: "";
+       e->other_detail = other_detail ?: "";
 
        /*
-        * Check if the event report is consistent and if the memory
-        * location is known. If it is known, enable_per_layer_report will be
-        * true, the DIMM(s) label info will be filled and the per-layer
+        * Check if the event report is consistent and if the memory location is
+        * known. If it is, the DIMM(s) label info will be filled and the DIMM's
         * error counters will be incremented.
         */
        for (i = 0; i < mci->n_layers; i++) {
@@ -1145,7 +1127,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
                        pos[i] = -1;
                }
                if (pos[i] >= 0)
-                       e->enable_per_layer_report = true;
+                       any_memory = false;
        }
 
        /*
@@ -1176,24 +1158,25 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 
                /*
                 * If the error is memory-controller wide, there's no need to
-                * seek for the affected DIMMs because the whole
-                * channel/memory controller/...  may be affected.
-                * Also, don't show errors for empty DIMM slots.
+                * seek for the affected DIMMs because the whole channel/memory
+                * controller/... may be affected. Also, don't show errors for
+                * empty DIMM slots.
                 */
-               if (!e->enable_per_layer_report || !dimm->nr_pages)
+               if (!dimm->nr_pages)
                        continue;
 
-               if (n_labels >= EDAC_MAX_LABELS) {
-                       e->enable_per_layer_report = false;
-                       break;
-               }
                n_labels++;
-               if (p != e->label) {
-                       strcpy(p, OTHER_LABEL);
-                       p += strlen(OTHER_LABEL);
+               if (n_labels > EDAC_MAX_LABELS) {
+                       p = e->label;
+                       *p = '\0';
+               } else {
+                       if (p != e->label) {
+                               strcpy(p, OTHER_LABEL);
+                               p += strlen(OTHER_LABEL);
+                       }
+                       strcpy(p, dimm->label);
+                       p += strlen(p);
                }
-               strcpy(p, dimm->label);
-               p += strlen(p);
 
                /*
                 * get csrow/channel of the DIMM, in order to allow
@@ -1213,22 +1196,12 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
                        chan = -2;
        }
 
-       if (!e->enable_per_layer_report) {
+       if (any_memory)
                strcpy(e->label, "any memory");
-       } else {
-               edac_dbg(4, "csrow/channel to increment: (%d,%d)\n", row, chan);
-               if (p == e->label)
-                       strcpy(e->label, "unknown memory");
-               if (type == HW_EVENT_ERR_CORRECTED) {
-                       if (row >= 0) {
-                               mci->csrows[row]->ce_count += error_count;
-                               if (chan >= 0)
-                                       mci->csrows[row]->channels[chan]->ce_count += error_count;
-                       }
-               } else
-                       if (row >= 0)
-                               mci->csrows[row]->ue_count += error_count;
-       }
+       else if (!*e->label)
+               strcpy(e->label, "unknown memory");
+
+       edac_inc_csrow(e, row, chan);
 
        /* Fill the RAM location data */
        p = e->location;
@@ -1244,6 +1217,6 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
        if (p > e->location)
                *(p - 1) = '\0';
 
-       edac_raw_mc_handle_error(type, mci, e);
+       edac_raw_mc_handle_error(e);
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
index 02aac5c..881b00e 100644 (file)
@@ -212,17 +212,13 @@ extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
  * edac_raw_mc_handle_error() - Reports a memory event to userspace without
  *     doing anything to discover the error location.
  *
- * @type:              severity of the error (CE/UE/Fatal)
- * @mci:               a struct mem_ctl_info pointer
  * @e:                 error description
  *
  * This raw function is used internally by edac_mc_handle_error(). It should
  * only be called directly when the hardware error come directly from BIOS,
  * like in the case of APEI GHES driver.
  */
-void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type,
-                             struct mem_ctl_info *mci,
-                             struct edac_raw_error_desc *e);
+void edac_raw_mc_handle_error(struct edac_raw_error_desc *e);
 
 /**
  * edac_mc_handle_error() - Reports a memory event to userspace.
index c70ec0a..4e6aca5 100644 (file)
@@ -274,14 +274,8 @@ static const struct attribute_group *csrow_attr_groups[] = {
        NULL
 };
 
-static void csrow_attr_release(struct device *dev)
-{
-       /* release device with _edac_mc_free() */
-}
-
 static const struct device_type csrow_attr_type = {
        .groups         = csrow_attr_groups,
-       .release        = csrow_attr_release,
 };
 
 /*
@@ -387,6 +381,14 @@ static const struct attribute_group *csrow_dev_groups[] = {
        NULL
 };
 
+static void csrow_release(struct device *dev)
+{
+       /*
+        * Nothing to do, just unregister sysfs here. The mci
+        * device owns the data and will also release it.
+        */
+}
+
 static inline int nr_pages_per_csrow(struct csrow_info *csrow)
 {
        int chan, nr_pages = 0;
@@ -405,6 +407,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
 
        csrow->dev.type = &csrow_attr_type;
        csrow->dev.groups = csrow_dev_groups;
+       csrow->dev.release = csrow_release;
        device_initialize(&csrow->dev);
        csrow->dev.parent = &mci->dev;
        csrow->mci = mci;
@@ -441,10 +444,8 @@ static int edac_create_csrow_objects(struct mem_ctl_info *mci)
 
 error:
        for (--i; i >= 0; i--) {
-               csrow = mci->csrows[i];
-               if (!nr_pages_per_csrow(csrow))
-                       continue;
-               device_unregister(&mci->csrows[i]->dev);
+               if (device_is_registered(&mci->csrows[i]->dev))
+                       device_unregister(&mci->csrows[i]->dev);
        }
 
        return err;
@@ -453,15 +454,13 @@ error:
 static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
 {
        int i;
-       struct csrow_info *csrow;
 
-       for (i = mci->nr_csrows - 1; i >= 0; i--) {
-               csrow = mci->csrows[i];
-               if (!nr_pages_per_csrow(csrow))
-                       continue;
-               device_unregister(&mci->csrows[i]->dev);
+       for (i = 0; i < mci->nr_csrows; i++) {
+               if (device_is_registered(&mci->csrows[i]->dev))
+                       device_unregister(&mci->csrows[i]->dev);
        }
 }
+
 #endif
 
 /*
@@ -552,10 +551,8 @@ static ssize_t dimmdev_ce_count_show(struct device *dev,
                                      char *data)
 {
        struct dimm_info *dimm = to_dimm(dev);
-       u32 count;
 
-       count = dimm->mci->ce_per_layer[dimm->mci->n_layers-1][dimm->idx];
-       return sprintf(data, "%u\n", count);
+       return sprintf(data, "%u\n", dimm->ce_count);
 }
 
 static ssize_t dimmdev_ue_count_show(struct device *dev,
@@ -563,10 +560,8 @@ static ssize_t dimmdev_ue_count_show(struct device *dev,
                                      char *data)
 {
        struct dimm_info *dimm = to_dimm(dev);
-       u32 count;
 
-       count = dimm->mci->ue_per_layer[dimm->mci->n_layers-1][dimm->idx];
-       return sprintf(data, "%u\n", count);
+       return sprintf(data, "%u\n", dimm->ue_count);
 }
 
 /* dimm/rank attribute files */
@@ -602,16 +597,18 @@ static const struct attribute_group *dimm_attr_groups[] = {
        NULL
 };
 
-static void dimm_attr_release(struct device *dev)
-{
-       /* release device with _edac_mc_free() */
-}
-
 static const struct device_type dimm_attr_type = {
        .groups         = dimm_attr_groups,
-       .release        = dimm_attr_release,
 };
 
+static void dimm_release(struct device *dev)
+{
+       /*
+        * Nothing to do, just unregister sysfs here. The mci
+        * device owns the data and will also release it.
+        */
+}
+
 /* Create a DIMM object under specifed memory controller device */
 static int edac_create_dimm_object(struct mem_ctl_info *mci,
                                   struct dimm_info *dimm)
@@ -620,6 +617,7 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
        dimm->mci = mci;
 
        dimm->dev.type = &dimm_attr_type;
+       dimm->dev.release = dimm_release;
        device_initialize(&dimm->dev);
 
        dimm->dev.parent = &mci->dev;
@@ -659,7 +657,9 @@ static ssize_t mci_reset_counters_store(struct device *dev,
                                        const char *data, size_t count)
 {
        struct mem_ctl_info *mci = to_mci(dev);
-       int cnt, row, chan, i;
+       struct dimm_info *dimm;
+       int row, chan;
+
        mci->ue_mc = 0;
        mci->ce_mc = 0;
        mci->ue_noinfo_count = 0;
@@ -675,11 +675,9 @@ static ssize_t mci_reset_counters_store(struct device *dev,
                        ri->channels[chan]->ce_count = 0;
        }
 
-       cnt = 1;
-       for (i = 0; i < mci->n_layers; i++) {
-               cnt *= mci->layers[i].size;
-               memset(mci->ce_per_layer[i], 0, cnt * sizeof(u32));
-               memset(mci->ue_per_layer[i], 0, cnt * sizeof(u32));
+       mci_for_each_dimm(mci, dimm) {
+               dimm->ue_count = 0;
+               dimm->ce_count = 0;
        }
 
        mci->start_time = jiffies;
@@ -884,14 +882,8 @@ static const struct attribute_group *mci_attr_groups[] = {
        NULL
 };
 
-static void mci_attr_release(struct device *dev)
-{
-       /* release device with _edac_mc_free() */
-}
-
 static const struct device_type mci_attr_type = {
        .groups         = mci_attr_groups,
-       .release        = mci_attr_release,
 };
 
 /*
@@ -910,8 +902,6 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
 
        /* get the /sys/devices/system/edac subsys reference */
        mci->dev.type = &mci_attr_type;
-       device_initialize(&mci->dev);
-
        mci->dev.parent = mci_pdev;
        mci->dev.groups = groups;
        dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
@@ -921,7 +911,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
        err = device_add(&mci->dev);
        if (err < 0) {
                edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
-               put_device(&mci->dev);
+               /* no put_device() here, free mci with _edac_mc_free() */
                return err;
        }
 
@@ -937,24 +927,20 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
 
                err = edac_create_dimm_object(mci, dimm);
                if (err)
-                       goto fail_unregister_dimm;
+                       goto fail;
        }
 
 #ifdef CONFIG_EDAC_LEGACY_SYSFS
        err = edac_create_csrow_objects(mci);
        if (err < 0)
-               goto fail_unregister_dimm;
+               goto fail;
 #endif
 
        edac_create_debugfs_nodes(mci);
        return 0;
 
-fail_unregister_dimm:
-       mci_for_each_dimm(mci, dimm) {
-               if (device_is_registered(&dimm->dev))
-                       device_unregister(&dimm->dev);
-       }
-       device_unregister(&mci->dev);
+fail:
+       edac_remove_sysfs_mci_device(mci);
 
        return err;
 }
@@ -966,6 +952,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 {
        struct dimm_info *dimm;
 
+       if (!device_is_registered(&mci->dev))
+               return;
+
        edac_dbg(0, "\n");
 
 #ifdef CONFIG_EDAC_DEBUG
@@ -976,17 +965,14 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
 #endif
 
        mci_for_each_dimm(mci, dimm) {
-               if (dimm->nr_pages == 0)
+               if (!device_is_registered(&dimm->dev))
                        continue;
                edac_dbg(1, "unregistering device %s\n", dev_name(&dimm->dev));
                device_unregister(&dimm->dev);
        }
-}
 
-void edac_unregister_sysfs(struct mem_ctl_info *mci)
-{
-       edac_dbg(1, "unregistering device %s\n", dev_name(&mci->dev));
-       device_unregister(&mci->dev);
+       /* only remove the device, but keep mci */
+       device_del(&mci->dev);
 }
 
 static void mc_attr_release(struct device *dev)
@@ -1000,9 +986,6 @@ static void mc_attr_release(struct device *dev)
        kfree(dev);
 }
 
-static const struct device_type mc_attr_type = {
-       .release        = mc_attr_release,
-};
 /*
  * Init/exit code for the module. Basically, creates/removes /sys/class/rc
  */
@@ -1015,11 +998,10 @@ int __init edac_mc_sysfs_init(void)
                return -ENOMEM;
 
        mci_pdev->bus = edac_get_sysfs_subsys();
-       mci_pdev->type = &mc_attr_type;
-       device_initialize(mci_pdev);
-       dev_set_name(mci_pdev, "mc");
+       mci_pdev->release = mc_attr_release;
+       mci_pdev->init_name = "mc";
 
-       err = device_add(mci_pdev);
+       err = device_register(mci_pdev);
        if (err < 0) {
                edac_dbg(1, "failure: create device %s\n", dev_name(mci_pdev));
                put_device(mci_pdev);
index 388427d..aa1f916 100644 (file)
@@ -28,7 +28,6 @@ void edac_mc_sysfs_exit(void);
 extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
                                        const struct attribute_group **groups);
 extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
-void edac_unregister_sysfs(struct mem_ctl_info *mci);
 extern int edac_get_log_ue(void);
 extern int edac_get_log_ce(void);
 extern int edac_get_panic_on_ue(void);
index b99080d..cb3dab5 100644 (file)
@@ -201,7 +201,6 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg)
 
 void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
 {
-       enum hw_event_mc_err_type type;
        struct edac_raw_error_desc *e;
        struct mem_ctl_info *mci;
        struct ghes_edac_pvt *pvt;
@@ -240,17 +239,17 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
 
        switch (sev) {
        case GHES_SEV_CORRECTED:
-               type = HW_EVENT_ERR_CORRECTED;
+               e->type = HW_EVENT_ERR_CORRECTED;
                break;
        case GHES_SEV_RECOVERABLE:
-               type = HW_EVENT_ERR_UNCORRECTED;
+               e->type = HW_EVENT_ERR_UNCORRECTED;
                break;
        case GHES_SEV_PANIC:
-               type = HW_EVENT_ERR_FATAL;
+               e->type = HW_EVENT_ERR_FATAL;
                break;
        default:
        case GHES_SEV_NO:
-               type = HW_EVENT_ERR_INFO;
+               e->type = HW_EVENT_ERR_INFO;
        }
 
        edac_dbg(1, "error validation_bits: 0x%08llx\n",
@@ -356,11 +355,8 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
                                     mem_err->mem_dev_handle);
 
                index = get_dimm_smbios_index(mci, mem_err->mem_dev_handle);
-               if (index >= 0) {
+               if (index >= 0)
                        e->top_layer = index;
-                       e->enable_per_layer_report = true;
-               }
-
        }
        if (p > e->location)
                *(p - 1) = '\0';
@@ -442,7 +438,7 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
        if (p > pvt->other_detail)
                *(p - 1) = '\0';
 
-       edac_raw_mc_handle_error(type, mci, e);
+       edac_raw_mc_handle_error(e);
 
 unlock:
        spin_unlock_irqrestore(&ghes_lock, flags);
index 059eccf..df08de9 100644 (file)
@@ -123,10 +123,10 @@ static int i10nm_get_all_munits(void)
 }
 
 static const struct x86_cpu_id i10nm_cpuids[] = {
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_TREMONT_D, 0, 0 },
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_X, 0, 0 },
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ICELAKE_D, 0, 0 },
-       { }
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,      NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X,           NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D,           NULL),
+       {}
 };
 MODULE_DEVICE_TABLE(x86cpu, i10nm_cpuids);
 
index ea980c5..8874b77 100644 (file)
@@ -1239,7 +1239,7 @@ static int __init mce_amd_init(void)
 
        case 0x17:
        case 0x18:
-               pr_warn("Decoding supported only on Scalable MCA processors.\n");
+               pr_warn_once("Decoding supported only on Scalable MCA processors.\n");
                return -EINVAL;
 
        default:
index 933f772..bc47328 100644 (file)
@@ -1537,8 +1537,8 @@ static struct dunit_ops dnv_ops = {
 };
 
 static const struct x86_cpu_id pnd2_cpuids[] = {
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT, 0, (kernel_ulong_t)&apl_ops },
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_GOLDMONT_D, 0, (kernel_ulong_t)&dnv_ops },
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,       &apl_ops),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D,     &dnv_ops),
        { }
 };
 MODULE_DEVICE_TABLE(x86cpu, pnd2_cpuids);
index 4957e8e..7d51c82 100644 (file)
@@ -3420,13 +3420,13 @@ fail0:
 }
 
 static const struct x86_cpu_id sbridge_cpuids[] = {
-       INTEL_CPU_FAM6(SANDYBRIDGE_X,     pci_dev_descr_sbridge_table),
-       INTEL_CPU_FAM6(IVYBRIDGE_X,       pci_dev_descr_ibridge_table),
-       INTEL_CPU_FAM6(HASWELL_X,         pci_dev_descr_haswell_table),
-       INTEL_CPU_FAM6(BROADWELL_X,       pci_dev_descr_broadwell_table),
-       INTEL_CPU_FAM6(BROADWELL_D,       pci_dev_descr_broadwell_table),
-       INTEL_CPU_FAM6(XEON_PHI_KNL,      pci_dev_descr_knl_table),
-       INTEL_CPU_FAM6(XEON_PHI_KNM,      pci_dev_descr_knl_table),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X, &pci_dev_descr_sbridge_table),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,   &pci_dev_descr_ibridge_table),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,     &pci_dev_descr_haswell_table),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,   &pci_dev_descr_broadwell_table),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,   &pci_dev_descr_broadwell_table),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,  &pci_dev_descr_knl_table),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,  &pci_dev_descr_knl_table),
        { }
 };
 MODULE_DEVICE_TABLE(x86cpu, sbridge_cpuids);
index 83545b4..46a3a34 100644 (file)
@@ -158,7 +158,7 @@ fail:
 }
 
 static const struct x86_cpu_id skx_cpuids[] = {
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_X, 0, 0 },
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,   NULL),
        { }
 };
 MODULE_DEVICE_TABLE(x86cpu, skx_cpuids);
index 2d26338..12211dc 100644 (file)
@@ -477,22 +477,16 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
 
        if (p->ce_cnt) {
                pinf = &p->ceinfo;
-               if (!priv->p_data->quirks) {
+               if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT) {
                        snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                                "DDR ECC error type:%s Row %d Bank %d Col %d ",
-                                 "CE", pinf->row, pinf->bank, pinf->col);
-                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                                "Bit Position: %d Data: 0x%08x\n",
+                                "DDR ECC error type:%s Row %d Bank %d BankGroup Number %d Block Number %d Bit Position: %d Data: 0x%08x",
+                                "CE", pinf->row, pinf->bank,
+                                pinf->bankgrpnr, pinf->blknr,
                                 pinf->bitpos, pinf->data);
                } else {
                        snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                                "DDR ECC error type:%s Row %d Bank %d Col %d ",
-                                 "CE", pinf->row, pinf->bank, pinf->col);
-                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                                "BankGroup Number %d Block Number %d ",
-                                pinf->bankgrpnr, pinf->blknr);
-                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                                "Bit Position: %d Data: 0x%08x\n",
+                                "DDR ECC error type:%s Row %d Bank %d Col %d Bit Position: %d Data: 0x%08x",
+                                "CE", pinf->row, pinf->bank, pinf->col,
                                 pinf->bitpos, pinf->data);
                }
 
@@ -503,17 +497,15 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p)
 
        if (p->ue_cnt) {
                pinf = &p->ueinfo;
-               if (!priv->p_data->quirks) {
+               if (priv->p_data->quirks & DDR_ECC_INTR_SUPPORT) {
                        snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                                "DDR ECC error type :%s Row %d Bank %d Col %d ",
-                               "UE", pinf->row, pinf->bank, pinf->col);
+                                "DDR ECC error type :%s Row %d Bank %d BankGroup Number %d Block Number %d",
+                                "UE", pinf->row, pinf->bank,
+                                pinf->bankgrpnr, pinf->blknr);
                } else {
                        snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
                                 "DDR ECC error type :%s Row %d Bank %d Col %d ",
                                 "UE", pinf->row, pinf->bank, pinf->col);
-                       snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
-                                "BankGroup Number %d Block Number %d",
-                                pinf->bankgrpnr, pinf->blknr);
                }
 
                edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
index a7f2161..34b7aff 100644 (file)
@@ -107,7 +107,7 @@ struct axp288_extcon_info {
 };
 
 static const struct x86_cpu_id cherry_trail_cpu_ids[] = {
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT, X86_FEATURE_ANY },
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        NULL),
        {}
 };
 
index a479023..334c8be 100644 (file)
@@ -267,26 +267,19 @@ static struct sdei_event *sdei_event_create(u32 event_num,
                event->private_registered = regs;
        }
 
-       if (sdei_event_find(event_num)) {
-               kfree(event->registered);
-               kfree(event);
-               event = ERR_PTR(-EBUSY);
-       } else {
-               spin_lock(&sdei_list_lock);
-               list_add(&event->list, &sdei_list);
-               spin_unlock(&sdei_list_lock);
-       }
+       spin_lock(&sdei_list_lock);
+       list_add(&event->list, &sdei_list);
+       spin_unlock(&sdei_list_lock);
 
        return event;
 }
 
-static void sdei_event_destroy(struct sdei_event *event)
+static void sdei_event_destroy_llocked(struct sdei_event *event)
 {
        lockdep_assert_held(&sdei_events_lock);
+       lockdep_assert_held(&sdei_list_lock);
 
-       spin_lock(&sdei_list_lock);
        list_del(&event->list);
-       spin_unlock(&sdei_list_lock);
 
        if (event->type == SDEI_EVENT_TYPE_SHARED)
                kfree(event->registered);
@@ -296,6 +289,13 @@ static void sdei_event_destroy(struct sdei_event *event)
        kfree(event);
 }
 
+static void sdei_event_destroy(struct sdei_event *event)
+{
+       spin_lock(&sdei_list_lock);
+       sdei_event_destroy_llocked(event);
+       spin_unlock(&sdei_list_lock);
+}
+
 static int sdei_api_get_version(u64 *version)
 {
        return invoke_sdei_fn(SDEI_1_0_FN_SDEI_VERSION, 0, 0, 0, 0, 0, version);
@@ -412,14 +412,19 @@ int sdei_event_enable(u32 event_num)
                return -ENOENT;
        }
 
-       spin_lock(&sdei_list_lock);
-       event->reenable = true;
-       spin_unlock(&sdei_list_lock);
 
+       cpus_read_lock();
        if (event->type == SDEI_EVENT_TYPE_SHARED)
                err = sdei_api_event_enable(event->event_num);
        else
                err = sdei_do_cross_call(_local_event_enable, event);
+
+       if (!err) {
+               spin_lock(&sdei_list_lock);
+               event->reenable = true;
+               spin_unlock(&sdei_list_lock);
+       }
+       cpus_read_unlock();
        mutex_unlock(&sdei_events_lock);
 
        return err;
@@ -491,11 +496,6 @@ static int _sdei_event_unregister(struct sdei_event *event)
 {
        lockdep_assert_held(&sdei_events_lock);
 
-       spin_lock(&sdei_list_lock);
-       event->reregister = false;
-       event->reenable = false;
-       spin_unlock(&sdei_list_lock);
-
        if (event->type == SDEI_EVENT_TYPE_SHARED)
                return sdei_api_event_unregister(event->event_num);
 
@@ -518,6 +518,11 @@ int sdei_event_unregister(u32 event_num)
                        break;
                }
 
+               spin_lock(&sdei_list_lock);
+               event->reregister = false;
+               event->reenable = false;
+               spin_unlock(&sdei_list_lock);
+
                err = _sdei_event_unregister(event);
                if (err)
                        break;
@@ -585,26 +590,15 @@ static int _sdei_event_register(struct sdei_event *event)
 
        lockdep_assert_held(&sdei_events_lock);
 
-       spin_lock(&sdei_list_lock);
-       event->reregister = true;
-       spin_unlock(&sdei_list_lock);
-
        if (event->type == SDEI_EVENT_TYPE_SHARED)
                return sdei_api_event_register(event->event_num,
                                               sdei_entry_point,
                                               event->registered,
                                               SDEI_EVENT_REGISTER_RM_ANY, 0);
 
-
        err = sdei_do_cross_call(_local_event_register, event);
-       if (err) {
-               spin_lock(&sdei_list_lock);
-               event->reregister = false;
-               event->reenable = false;
-               spin_unlock(&sdei_list_lock);
-
+       if (err)
                sdei_do_cross_call(_local_event_unregister, event);
-       }
 
        return err;
 }
@@ -632,12 +626,18 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
                        break;
                }
 
+               cpus_read_lock();
                err = _sdei_event_register(event);
                if (err) {
                        sdei_event_destroy(event);
                        pr_warn("Failed to register event %u: %d\n", event_num,
                                err);
+               } else {
+                       spin_lock(&sdei_list_lock);
+                       event->reregister = true;
+                       spin_unlock(&sdei_list_lock);
                }
+               cpus_read_unlock();
        } while (0);
        mutex_unlock(&sdei_events_lock);
 
@@ -645,16 +645,17 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
 }
 EXPORT_SYMBOL(sdei_event_register);
 
-static int sdei_reregister_event(struct sdei_event *event)
+static int sdei_reregister_event_llocked(struct sdei_event *event)
 {
        int err;
 
        lockdep_assert_held(&sdei_events_lock);
+       lockdep_assert_held(&sdei_list_lock);
 
        err = _sdei_event_register(event);
        if (err) {
                pr_err("Failed to re-register event %u\n", event->event_num);
-               sdei_event_destroy(event);
+               sdei_event_destroy_llocked(event);
                return err;
        }
 
@@ -683,7 +684,7 @@ static int sdei_reregister_shared(void)
                        continue;
 
                if (event->reregister) {
-                       err = sdei_reregister_event(event);
+                       err = sdei_reregister_event_llocked(event);
                        if (err)
                                break;
                }
index 2045566..f59163c 100644 (file)
 #include <asm/dmi.h>
 #include <asm/unaligned.h>
 
+#ifndef SMBIOS_ENTRY_POINT_SCAN_START
+#define SMBIOS_ENTRY_POINT_SCAN_START 0xF0000
+#endif
+
 struct kobject *dmi_kobj;
 EXPORT_SYMBOL_GPL(dmi_kobj);
 
@@ -663,7 +667,7 @@ static void __init dmi_scan_machine(void)
                        return;
                }
        } else if (IS_ENABLED(CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK)) {
-               p = dmi_early_remap(0xF0000, 0x10000);
+               p = dmi_early_remap(SMBIOS_ENTRY_POINT_SCAN_START, 0x10000);
                if (p == NULL)
                        goto error;
 
index ecc83e2..613828d 100644 (file)
@@ -239,6 +239,11 @@ config EFI_DISABLE_PCI_DMA
 
 endmenu
 
+config EFI_EMBEDDED_FIRMWARE
+       bool
+       depends on EFI
+       select CRYPTO_LIB_SHA256
+
 config UEFI_CPER
        bool
 
index 554d795..7a21698 100644 (file)
@@ -13,19 +13,21 @@ KASAN_SANITIZE_runtime-wrappers.o   := n
 obj-$(CONFIG_ACPI_BGRT)                += efi-bgrt.o
 obj-$(CONFIG_EFI)                      += efi.o vars.o reboot.o memattr.o tpm.o
 obj-$(CONFIG_EFI)                      += capsule.o memmap.o
+obj-$(CONFIG_EFI_PARAMS_FROM_FDT)      += fdtparams.o
 obj-$(CONFIG_EFI_VARS)                 += efivars.o
 obj-$(CONFIG_EFI_ESRT)                 += esrt.o
 obj-$(CONFIG_EFI_VARS_PSTORE)          += efi-pstore.o
 obj-$(CONFIG_UEFI_CPER)                        += cper.o
 obj-$(CONFIG_EFI_RUNTIME_MAP)          += runtime-map.o
 obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)     += runtime-wrappers.o
-obj-$(CONFIG_EFI_STUB)                 += libstub/
+subdir-$(CONFIG_EFI_STUB)              += libstub
 obj-$(CONFIG_EFI_FAKE_MEMMAP)          += fake_map.o
 obj-$(CONFIG_EFI_BOOTLOADER_CONTROL)   += efibc.o
 obj-$(CONFIG_EFI_TEST)                 += test/
 obj-$(CONFIG_EFI_DEV_PATH_PARSER)      += dev-path-parser.o
 obj-$(CONFIG_APPLE_PROPERTIES)         += apple-properties.o
 obj-$(CONFIG_EFI_RCI2_TABLE)           += rci2-table.o
+obj-$(CONFIG_EFI_EMBEDDED_FIRMWARE)    += embedded-firmware.o
 
 fake_map-y                             += fake_mem.o
 fake_map-$(CONFIG_X86)                 += x86_fake_mem.o
index 5ccf399..34f53d8 100644 (file)
@@ -31,7 +31,7 @@ __setup("dump_apple_properties", dump_properties_enable);
 struct dev_header {
        u32 len;
        u32 prop_count;
-       struct efi_dev_path path[0];
+       struct efi_dev_path path[];
        /*
         * followed by key/value pairs, each key and value preceded by u32 len,
         * len includes itself, value may be empty (in which case its len is 4)
@@ -42,11 +42,11 @@ struct properties_header {
        u32 len;
        u32 version;
        u32 dev_count;
-       struct dev_header dev_header[0];
+       struct dev_header dev_header[];
 };
 
 static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
-                                            struct device *dev, void *ptr,
+                                            struct device *dev, const void *ptr,
                                             struct property_entry entry[])
 {
        int i;
@@ -117,10 +117,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
        while (offset + sizeof(struct dev_header) < properties->len) {
                struct dev_header *dev_header = (void *)properties + offset;
                struct property_entry *entry = NULL;
+               const struct efi_dev_path *ptr;
                struct device *dev;
                size_t len;
                int ret, i;
-               void *ptr;
 
                if (offset + dev_header->len > properties->len ||
                    dev_header->len <= sizeof(*dev_header)) {
@@ -131,10 +131,10 @@ static int __init unmarshal_devices(struct properties_header *properties)
                ptr = dev_header->path;
                len = dev_header->len - sizeof(*dev_header);
 
-               dev = efi_get_device_by_path((struct efi_dev_path **)&ptr, &len);
+               dev = efi_get_device_by_path(&ptr, &len);
                if (IS_ERR(dev)) {
                        pr_err("device path parse error %ld at %#zx:\n",
-                              PTR_ERR(dev), ptr - (void *)dev_header);
+                              PTR_ERR(dev), (void *)ptr - (void *)dev_header);
                        print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
                               16, 1, dev_header, dev_header->len, true);
                        dev = NULL;
index d99f5b0..9e5e62f 100644 (file)
@@ -22,8 +22,6 @@
 
 #include <asm/efi.h>
 
-u64 efi_system_table;
-
 static int __init is_memory(efi_memory_desc_t *md)
 {
        if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC))
@@ -36,7 +34,7 @@ static int __init is_memory(efi_memory_desc_t *md)
  * as some data members of the EFI system table are virtually remapped after
  * SetVirtualAddressMap() has been called.
  */
-static phys_addr_t efi_to_phys(unsigned long addr)
+static phys_addr_t __init efi_to_phys(unsigned long addr)
 {
        efi_memory_desc_t *md;
 
@@ -55,7 +53,7 @@ static phys_addr_t efi_to_phys(unsigned long addr)
 
 static __initdata unsigned long screen_info_table = EFI_INVALID_TABLE_ADDR;
 
-static __initdata efi_config_table_type_t arch_tables[] = {
+static const efi_config_table_type_t arch_tables[] __initconst = {
        {LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, NULL, &screen_info_table},
        {NULL_GUID, NULL, NULL}
 };
@@ -83,17 +81,15 @@ static void __init init_screen_info(void)
                memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size);
 }
 
-static int __init uefi_init(void)
+static int __init uefi_init(u64 efi_system_table)
 {
-       efi_char16_t *c16;
-       void *config_tables;
+       efi_config_table_t *config_tables;
+       efi_system_table_t *systab;
        size_t table_size;
-       char vendor[100] = "unknown";
-       int i, retval;
+       int retval;
 
-       efi.systab = early_memremap_ro(efi_system_table,
-                                      sizeof(efi_system_table_t));
-       if (efi.systab == NULL) {
+       systab = early_memremap_ro(efi_system_table, sizeof(efi_system_table_t));
+       if (systab == NULL) {
                pr_warn("Unable to map EFI system table.\n");
                return -ENOMEM;
        }
@@ -102,53 +98,29 @@ static int __init uefi_init(void)
        if (IS_ENABLED(CONFIG_64BIT))
                set_bit(EFI_64BIT, &efi.flags);
 
-       /*
-        * Verify the EFI Table
-        */
-       if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
-               pr_err("System table signature incorrect\n");
-               retval = -EINVAL;
+       retval = efi_systab_check_header(&systab->hdr, 2);
+       if (retval)
                goto out;
-       }
-       if ((efi.systab->hdr.revision >> 16) < 2)
-               pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
-                       efi.systab->hdr.revision >> 16,
-                       efi.systab->hdr.revision & 0xffff);
-
-       efi.runtime_version = efi.systab->hdr.revision;
-
-       /* Show what we know for posterity */
-       c16 = early_memremap_ro(efi_to_phys(efi.systab->fw_vendor),
-                               sizeof(vendor) * sizeof(efi_char16_t));
-       if (c16) {
-               for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
-                       vendor[i] = c16[i];
-               vendor[i] = '\0';
-               early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
-       }
 
-       pr_info("EFI v%u.%.02u by %s\n",
-               efi.systab->hdr.revision >> 16,
-               efi.systab->hdr.revision & 0xffff, vendor);
+       efi.runtime = systab->runtime;
+       efi.runtime_version = systab->hdr.revision;
 
-       table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
-       config_tables = early_memremap_ro(efi_to_phys(efi.systab->tables),
+       efi_systab_report_header(&systab->hdr, efi_to_phys(systab->fw_vendor));
+
+       table_size = sizeof(efi_config_table_t) * systab->nr_tables;
+       config_tables = early_memremap_ro(efi_to_phys(systab->tables),
                                          table_size);
        if (config_tables == NULL) {
                pr_warn("Unable to map EFI config table array.\n");
                retval = -ENOMEM;
                goto out;
        }
-       retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
-                                        sizeof(efi_config_table_t),
+       retval = efi_config_parse_tables(config_tables, systab->nr_tables,
                                         arch_tables);
 
-       if (!retval)
-               efi.config_table = (unsigned long)efi.systab->tables;
-
        early_memunmap(config_tables, table_size);
 out:
-       early_memunmap(efi.systab,  sizeof(efi_system_table_t));
+       early_memunmap(systab, sizeof(efi_system_table_t));
        return retval;
 }
 
@@ -233,19 +205,13 @@ static __init void reserve_regions(void)
 void __init efi_init(void)
 {
        struct efi_memory_map_data data;
-       struct efi_fdt_params params;
+       u64 efi_system_table;
 
        /* Grab UEFI information placed in FDT by stub */
-       if (!efi_get_fdt_params(&params))
+       efi_system_table = efi_get_fdt_params(&data);
+       if (!efi_system_table)
                return;
 
-       efi_system_table = params.system_table;
-
-       data.desc_version = params.desc_ver;
-       data.desc_size = params.desc_size;
-       data.size = params.mmap_size;
-       data.phys_map = params.mmap;
-
        if (efi_memmap_init_early(&data) < 0) {
                /*
                * If we are booting via UEFI, the UEFI memory map is the only
@@ -259,7 +225,7 @@ void __init efi_init(void)
             "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
              efi.memmap.desc_version);
 
-       if (uefi_init() < 0) {
+       if (uefi_init(efi_system_table) < 0) {
                efi_memmap_unmap();
                return;
        }
@@ -267,9 +233,8 @@ void __init efi_init(void)
        reserve_regions();
        efi_esrt_init();
 
-       memblock_reserve(params.mmap & PAGE_MASK,
-                        PAGE_ALIGN(params.mmap_size +
-                                   (params.mmap & ~PAGE_MASK)));
+       memblock_reserve(data.phys_map & PAGE_MASK,
+                        PAGE_ALIGN(data.size + (data.phys_map & ~PAGE_MASK)));
 
        init_screen_info();
 
@@ -349,7 +314,7 @@ static int efifb_add_links(const struct fwnode_handle *fwnode,
         * If this fails, retrying this function at a later point won't
         * change anything. So, don't return an error after this.
         */
-       if (!device_link_add(dev, sup_dev, 0))
+       if (!device_link_add(dev, sup_dev, fw_devlink_get_flags()))
                dev_warn(dev, "device_link_add() failed\n");
 
        put_device(sup_dev);
index 9dda260..b876373 100644 (file)
@@ -25,8 +25,6 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 
-extern u64 efi_system_table;
-
 #if defined(CONFIG_PTDUMP_DEBUGFS) && defined(CONFIG_ARM64)
 #include <asm/ptdump.h>
 
@@ -54,13 +52,11 @@ device_initcall(ptdump_init);
 static bool __init efi_virtmap_init(void)
 {
        efi_memory_desc_t *md;
-       bool systab_found;
 
        efi_mm.pgd = pgd_alloc(&efi_mm);
        mm_init_cpumask(&efi_mm);
        init_new_context(NULL, &efi_mm);
 
-       systab_found = false;
        for_each_efi_memory_desc(md) {
                phys_addr_t phys = md->phys_addr;
                int ret;
@@ -76,20 +72,6 @@ static bool __init efi_virtmap_init(void)
                                &phys, ret);
                        return false;
                }
-               /*
-                * If this entry covers the address of the UEFI system table,
-                * calculate and record its virtual address.
-                */
-               if (efi_system_table >= phys &&
-                   efi_system_table < phys + (md->num_pages * EFI_PAGE_SIZE)) {
-                       efi.systab = (void *)(unsigned long)(efi_system_table -
-                                                            phys + md->virt_addr);
-                       systab_found = true;
-               }
-       }
-       if (!systab_found) {
-               pr_err("No virtual mapping found for the UEFI System Table\n");
-               return false;
        }
 
        if (efi_memattr_apply_permissions(&efi_mm, efi_set_mapping_permissions))
index d3067cb..4dde8ed 100644 (file)
@@ -168,7 +168,7 @@ static ssize_t efi_capsule_submit_update(struct capsule_info *cap_info)
 static ssize_t efi_capsule_write(struct file *file, const char __user *buff,
                                 size_t count, loff_t *offp)
 {
-       int ret = 0;
+       int ret;
        struct capsule_info *cap_info = file->private_data;
        struct page *page;
        void *kbuff = NULL;
index 2012338..5c9625e 100644 (file)
@@ -31,13 +31,13 @@ static int __init match_acpi_dev(struct device *dev, const void *data)
                return !strcmp("0", hid_uid.uid);
 }
 
-static long __init parse_acpi_path(struct efi_dev_path *node,
+static long __init parse_acpi_path(const struct efi_dev_path *node,
                                   struct device *parent, struct device **child)
 {
        struct acpi_hid_uid hid_uid = {};
        struct device *phys_dev;
 
-       if (node->length != 12)
+       if (node->header.length != 12)
                return -EINVAL;
 
        sprintf(hid_uid.hid[0].id, "%c%c%c%04X",
@@ -69,12 +69,12 @@ static int __init match_pci_dev(struct device *dev, void *data)
        return dev_is_pci(dev) && to_pci_dev(dev)->devfn == devfn;
 }
 
-static long __init parse_pci_path(struct efi_dev_path *node,
+static long __init parse_pci_path(const struct efi_dev_path *node,
                                  struct device *parent, struct device **child)
 {
        unsigned int devfn;
 
-       if (node->length != 6)
+       if (node->header.length != 6)
                return -EINVAL;
        if (!parent)
                return -EINVAL;
@@ -105,19 +105,19 @@ static long __init parse_pci_path(struct efi_dev_path *node,
  * search for a device.
  */
 
-static long __init parse_end_path(struct efi_dev_path *node,
+static long __init parse_end_path(const struct efi_dev_path *node,
                                  struct device *parent, struct device **child)
 {
-       if (node->length != 4)
+       if (node->header.length != 4)
                return -EINVAL;
-       if (node->sub_type != EFI_DEV_END_INSTANCE &&
-           node->sub_type != EFI_DEV_END_ENTIRE)
+       if (node->header.sub_type != EFI_DEV_END_INSTANCE &&
+           node->header.sub_type != EFI_DEV_END_ENTIRE)
                return -EINVAL;
        if (!parent)
                return -ENODEV;
 
        *child = get_device(parent);
-       return node->sub_type;
+       return node->header.sub_type;
 }
 
 /**
@@ -156,7 +156,7 @@ static long __init parse_end_path(struct efi_dev_path *node,
  *     %ERR_PTR(-EINVAL) if a node is malformed or exceeds @len,
  *     %ERR_PTR(-ENOTSUPP) if support for a node type is not yet implemented.
  */
-struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
+struct device * __init efi_get_device_by_path(const struct efi_dev_path **node,
                                              size_t *len)
 {
        struct device *parent = NULL, *child;
@@ -166,16 +166,16 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
                return NULL;
 
        while (!ret) {
-               if (*len < 4 || *len < (*node)->length)
+               if (*len < 4 || *len < (*node)->header.length)
                        ret = -EINVAL;
-               else if ((*node)->type     == EFI_DEV_ACPI &&
-                        (*node)->sub_type == EFI_DEV_BASIC_ACPI)
+               else if ((*node)->header.type           == EFI_DEV_ACPI &&
+                        (*node)->header.sub_type       == EFI_DEV_BASIC_ACPI)
                        ret = parse_acpi_path(*node, parent, &child);
-               else if ((*node)->type     == EFI_DEV_HW &&
-                        (*node)->sub_type == EFI_DEV_PCI)
+               else if ((*node)->header.type           == EFI_DEV_HW &&
+                        (*node)->header.sub_type       == EFI_DEV_PCI)
                        ret = parse_pci_path(*node, parent, &child);
-               else if (((*node)->type    == EFI_DEV_END_PATH ||
-                         (*node)->type    == EFI_DEV_END_PATH2))
+               else if (((*node)->header.type          == EFI_DEV_END_PATH ||
+                         (*node)->header.type          == EFI_DEV_END_PATH2))
                        ret = parse_end_path(*node, parent, &child);
                else
                        ret = -ENOTSUPP;
@@ -185,8 +185,8 @@ struct device * __init efi_get_device_by_path(struct efi_dev_path **node,
                        return ERR_PTR(ret);
 
                parent = child;
-               *node  = (void *)*node + (*node)->length;
-               *len  -= (*node)->length;
+               *node  = (void *)*node + (*node)->header.length;
+               *len  -= (*node)->header.length;
        }
 
        if (ret == EFI_DEV_END_ENTIRE)
index b07c176..6aafdb6 100644 (file)
@@ -42,7 +42,12 @@ void __init efi_bgrt_init(struct acpi_table_header *table)
                return;
        }
        *bgrt = *(struct acpi_table_bgrt *)table;
-       if (bgrt->version != 1) {
+       /*
+        * Only version 1 is defined but some older laptops (seen on Lenovo
+        * Ivy Bridge models) have a correct version 1 BGRT table with the
+        * version set to 0, so we accept version 0 and 1.
+        */
+       if (bgrt->version > 1) {
                pr_notice("Ignoring BGRT: invalid version %u (expected 1)\n",
                       bgrt->version);
                goto out;
index 9ea13e8..c2f1d4e 100644 (file)
@@ -161,7 +161,7 @@ static int efi_pstore_scan_sysfs_exit(struct efivar_entry *pos,
  *
  * @record: pstore record to pass to callback
  *
- * You MUST call efivar_enter_iter_begin() before this function, and
+ * You MUST call efivar_entry_iter_begin() before this function, and
  * efivar_entry_iter_end() afterwards.
  *
  */
@@ -356,7 +356,7 @@ static struct pstore_info efi_pstore_info = {
 
 static __init int efivars_pstore_init(void)
 {
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
                return 0;
 
        if (!efivars_kobject())
index 621220a..911a2bd 100644 (file)
 #include <linux/kobject.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/efi.h>
 #include <linux/of.h>
-#include <linux/of_fdt.h>
 #include <linux/io.h>
 #include <linux/kexec.h>
 #include <linux/platform_device.h>
 #include <asm/early_ioremap.h>
 
 struct efi __read_mostly efi = {
-       .mps                    = EFI_INVALID_TABLE_ADDR,
+       .runtime_supported_mask = EFI_RT_SUPPORTED_ALL,
        .acpi                   = EFI_INVALID_TABLE_ADDR,
        .acpi20                 = EFI_INVALID_TABLE_ADDR,
        .smbios                 = EFI_INVALID_TABLE_ADDR,
        .smbios3                = EFI_INVALID_TABLE_ADDR,
-       .boot_info              = EFI_INVALID_TABLE_ADDR,
-       .hcdp                   = EFI_INVALID_TABLE_ADDR,
-       .uga                    = EFI_INVALID_TABLE_ADDR,
-       .fw_vendor              = EFI_INVALID_TABLE_ADDR,
-       .runtime                = EFI_INVALID_TABLE_ADDR,
-       .config_table           = EFI_INVALID_TABLE_ADDR,
        .esrt                   = EFI_INVALID_TABLE_ADDR,
-       .properties_table       = EFI_INVALID_TABLE_ADDR,
-       .mem_attr_table         = EFI_INVALID_TABLE_ADDR,
-       .rng_seed               = EFI_INVALID_TABLE_ADDR,
        .tpm_log                = EFI_INVALID_TABLE_ADDR,
        .tpm_final_log          = EFI_INVALID_TABLE_ADDR,
-       .mem_reserve            = EFI_INVALID_TABLE_ADDR,
 };
 EXPORT_SYMBOL(efi);
 
+unsigned long __ro_after_init efi_rng_seed = EFI_INVALID_TABLE_ADDR;
+static unsigned long __initdata mem_reserve = EFI_INVALID_TABLE_ADDR;
+static unsigned long __initdata rt_prop = EFI_INVALID_TABLE_ADDR;
+
 struct mm_struct efi_mm = {
        .mm_rb                  = RB_ROOT,
        .mm_users               = ATOMIC_INIT(2),
@@ -122,8 +116,6 @@ static ssize_t systab_show(struct kobject *kobj,
        if (!kobj || !buf)
                return -EINVAL;
 
-       if (efi.mps != EFI_INVALID_TABLE_ADDR)
-               str += sprintf(str, "MPS=0x%lx\n", efi.mps);
        if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
                str += sprintf(str, "ACPI20=0x%lx\n", efi.acpi20);
        if (efi.acpi != EFI_INVALID_TABLE_ADDR)
@@ -137,30 +129,17 @@ static ssize_t systab_show(struct kobject *kobj,
                str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
        if (efi.smbios != EFI_INVALID_TABLE_ADDR)
                str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
-       if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
-               str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
-       if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
-               str += sprintf(str, "BOOTINFO=0x%lx\n", efi.boot_info);
-       if (efi.uga != EFI_INVALID_TABLE_ADDR)
-               str += sprintf(str, "UGA=0x%lx\n", efi.uga);
-
-       return str - buf;
-}
 
-static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
+       if (IS_ENABLED(CONFIG_IA64) || IS_ENABLED(CONFIG_X86)) {
+               extern char *efi_systab_show_arch(char *str);
 
-#define EFI_FIELD(var) efi.var
+               str = efi_systab_show_arch(str);
+       }
 
-#define EFI_ATTR_SHOW(name) \
-static ssize_t name##_show(struct kobject *kobj, \
-                               struct kobj_attribute *attr, char *buf) \
-{ \
-       return sprintf(buf, "0x%lx\n", EFI_FIELD(name)); \
+       return str - buf;
 }
 
-EFI_ATTR_SHOW(fw_vendor);
-EFI_ATTR_SHOW(runtime);
-EFI_ATTR_SHOW(config_table);
+static struct kobj_attribute efi_attr_systab = __ATTR_RO_MODE(systab, 0400);
 
 static ssize_t fw_platform_size_show(struct kobject *kobj,
                                     struct kobj_attribute *attr, char *buf)
@@ -168,36 +147,24 @@ static ssize_t fw_platform_size_show(struct kobject *kobj,
        return sprintf(buf, "%d\n", efi_enabled(EFI_64BIT) ? 64 : 32);
 }
 
-static struct kobj_attribute efi_attr_fw_vendor = __ATTR_RO(fw_vendor);
-static struct kobj_attribute efi_attr_runtime = __ATTR_RO(runtime);
-static struct kobj_attribute efi_attr_config_table = __ATTR_RO(config_table);
+extern __weak struct kobj_attribute efi_attr_fw_vendor;
+extern __weak struct kobj_attribute efi_attr_runtime;
+extern __weak struct kobj_attribute efi_attr_config_table;
 static struct kobj_attribute efi_attr_fw_platform_size =
        __ATTR_RO(fw_platform_size);
 
 static struct attribute *efi_subsys_attrs[] = {
        &efi_attr_systab.attr,
+       &efi_attr_fw_platform_size.attr,
        &efi_attr_fw_vendor.attr,
        &efi_attr_runtime.attr,
        &efi_attr_config_table.attr,
-       &efi_attr_fw_platform_size.attr,
        NULL,
 };
 
-static umode_t efi_attr_is_visible(struct kobject *kobj,
-                                  struct attribute *attr, int n)
+umode_t __weak efi_attr_is_visible(struct kobject *kobj, struct attribute *attr,
+                                  int n)
 {
-       if (attr == &efi_attr_fw_vendor.attr) {
-               if (efi_enabled(EFI_PARAVIRT) ||
-                               efi.fw_vendor == EFI_INVALID_TABLE_ADDR)
-                       return 0;
-       } else if (attr == &efi_attr_runtime.attr) {
-               if (efi.runtime == EFI_INVALID_TABLE_ADDR)
-                       return 0;
-       } else if (attr == &efi_attr_config_table.attr) {
-               if (efi.config_table == EFI_INVALID_TABLE_ADDR)
-                       return 0;
-       }
-
        return attr->mode;
 }
 
@@ -325,6 +292,59 @@ free_entry:
 static inline int efivar_ssdt_load(void) { return 0; }
 #endif
 
+#ifdef CONFIG_DEBUG_FS
+
+#define EFI_DEBUGFS_MAX_BLOBS 32
+
+static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS];
+
+static void __init efi_debugfs_init(void)
+{
+       struct dentry *efi_debugfs;
+       efi_memory_desc_t *md;
+       char name[32];
+       int type_count[EFI_BOOT_SERVICES_DATA + 1] = {};
+       int i = 0;
+
+       efi_debugfs = debugfs_create_dir("efi", NULL);
+       if (IS_ERR_OR_NULL(efi_debugfs))
+               return;
+
+       for_each_efi_memory_desc(md) {
+               switch (md->type) {
+               case EFI_BOOT_SERVICES_CODE:
+                       snprintf(name, sizeof(name), "boot_services_code%d",
+                                type_count[md->type]++);
+                       break;
+               case EFI_BOOT_SERVICES_DATA:
+                       snprintf(name, sizeof(name), "boot_services_data%d",
+                                type_count[md->type]++);
+                       break;
+               default:
+                       continue;
+               }
+
+               if (i >= EFI_DEBUGFS_MAX_BLOBS) {
+                       pr_warn("More then %d EFI boot service segments, only showing first %d in debugfs\n",
+                               EFI_DEBUGFS_MAX_BLOBS, EFI_DEBUGFS_MAX_BLOBS);
+                       break;
+               }
+
+               debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT;
+               debugfs_blob[i].data = memremap(md->phys_addr,
+                                               debugfs_blob[i].size,
+                                               MEMREMAP_WB);
+               if (!debugfs_blob[i].data)
+                       continue;
+
+               debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]);
+               i++;
+       }
+}
+#else
+static inline void efi_debugfs_init(void) {}
+#endif
+
 /*
  * We register the efi subsystem with the firmware subsystem and the
  * efivars subsystem with the efi subsystem, if the system was booted with
@@ -334,21 +354,30 @@ static int __init efisubsys_init(void)
 {
        int error;
 
+       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+               efi.runtime_supported_mask = 0;
+
        if (!efi_enabled(EFI_BOOT))
                return 0;
 
-       /*
-        * Since we process only one efi_runtime_service() at a time, an
-        * ordered workqueue (which creates only one execution context)
-        * should suffice all our needs.
-        */
-       efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
-       if (!efi_rts_wq) {
-               pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
-               clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-               return 0;
+       if (efi.runtime_supported_mask) {
+               /*
+                * Since we process only one efi_runtime_service() at a time, an
+                * ordered workqueue (which creates only one execution context)
+                * should suffice for all our needs.
+                */
+               efi_rts_wq = alloc_ordered_workqueue("efi_rts_wq", 0);
+               if (!efi_rts_wq) {
+                       pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
+                       clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+                       efi.runtime_supported_mask = 0;
+                       return 0;
+               }
        }
 
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_TIME_SERVICES))
+               platform_device_register_simple("rtc-efi", 0, NULL, 0);
+
        /* We register the efi directory at /sys/firmware/efi */
        efi_kobj = kobject_create_and_add("efi", firmware_kobj);
        if (!efi_kobj) {
@@ -356,12 +385,13 @@ static int __init efisubsys_init(void)
                return -ENOMEM;
        }
 
-       error = generic_ops_register();
-       if (error)
-               goto err_put;
-
-       if (efi_enabled(EFI_RUNTIME_SERVICES))
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES)) {
                efivar_ssdt_load();
+               error = generic_ops_register();
+               if (error)
+                       goto err_put;
+               platform_device_register_simple("efivars", 0, NULL, 0);
+       }
 
        error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
        if (error) {
@@ -381,12 +411,16 @@ static int __init efisubsys_init(void)
                goto err_remove_group;
        }
 
+       if (efi_enabled(EFI_DBG) && efi_enabled(EFI_PRESERVE_BS_REGIONS))
+               efi_debugfs_init();
+
        return 0;
 
 err_remove_group:
        sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
 err_unregister:
-       generic_ops_unregister();
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
+               generic_ops_unregister();
 err_put:
        kobject_put(efi_kobj);
        return error;
@@ -467,30 +501,27 @@ void __init efi_mem_reserve(phys_addr_t addr, u64 size)
        efi_arch_mem_reserve(addr, size);
 }
 
-static __initdata efi_config_table_type_t common_tables[] = {
+static const efi_config_table_type_t common_tables[] __initconst = {
        {ACPI_20_TABLE_GUID, "ACPI 2.0", &efi.acpi20},
        {ACPI_TABLE_GUID, "ACPI", &efi.acpi},
-       {HCDP_TABLE_GUID, "HCDP", &efi.hcdp},
-       {MPS_TABLE_GUID, "MPS", &efi.mps},
        {SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
        {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
-       {UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
        {EFI_SYSTEM_RESOURCE_TABLE_GUID, "ESRT", &efi.esrt},
-       {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
-       {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
-       {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
+       {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi_mem_attr_table},
+       {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi_rng_seed},
        {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
        {LINUX_EFI_TPM_FINAL_LOG_GUID, "TPMFinalLog", &efi.tpm_final_log},
-       {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &efi.mem_reserve},
+       {LINUX_EFI_MEMRESERVE_TABLE_GUID, "MEMRESERVE", &mem_reserve},
+       {EFI_RT_PROPERTIES_TABLE_GUID, "RTPROP", &rt_prop},
 #ifdef CONFIG_EFI_RCI2_TABLE
        {DELLEMC_EFI_RCI2_TABLE_GUID, NULL, &rci2_table_phys},
 #endif
        {NULL_GUID, NULL, NULL},
 };
 
-static __init int match_config_table(efi_guid_t *guid,
+static __init int match_config_table(const efi_guid_t *guid,
                                     unsigned long table,
-                                    efi_config_table_type_t *table_types)
+                                    const efi_config_table_type_t *table_types)
 {
        int i;
 
@@ -509,60 +540,59 @@ static __init int match_config_table(efi_guid_t *guid,
        return 0;
 }
 
-int __init efi_config_parse_tables(void *config_tables, int count, int sz,
-                                  efi_config_table_type_t *arch_tables)
+int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
+                                  int count,
+                                  const efi_config_table_type_t *arch_tables)
 {
-       void *tablep;
+       const efi_config_table_64_t *tbl64 = (void *)config_tables;
+       const efi_config_table_32_t *tbl32 = (void *)config_tables;
+       const efi_guid_t *guid;
+       unsigned long table;
        int i;
 
-       tablep = config_tables;
        pr_info("");
        for (i = 0; i < count; i++) {
-               efi_guid_t guid;
-               unsigned long table;
-
-               if (efi_enabled(EFI_64BIT)) {
-                       u64 table64;
-                       guid = ((efi_config_table_64_t *)tablep)->guid;
-                       table64 = ((efi_config_table_64_t *)tablep)->table;
-                       table = table64;
-#ifndef CONFIG_64BIT
-                       if (table64 >> 32) {
+               if (!IS_ENABLED(CONFIG_X86)) {
+                       guid = &config_tables[i].guid;
+                       table = (unsigned long)config_tables[i].table;
+               } else if (efi_enabled(EFI_64BIT)) {
+                       guid = &tbl64[i].guid;
+                       table = tbl64[i].table;
+
+                       if (IS_ENABLED(CONFIG_X86_32) &&
+                           tbl64[i].table > U32_MAX) {
                                pr_cont("\n");
                                pr_err("Table located above 4GB, disabling EFI.\n");
                                return -EINVAL;
                        }
-#endif
                } else {
-                       guid = ((efi_config_table_32_t *)tablep)->guid;
-                       table = ((efi_config_table_32_t *)tablep)->table;
+                       guid = &tbl32[i].guid;
+                       table = tbl32[i].table;
                }
 
-               if (!match_config_table(&guid, table, common_tables))
-                       match_config_table(&guid, table, arch_tables);
-
-               tablep += sz;
+               if (!match_config_table(guid, table, common_tables))
+                       match_config_table(guid, table, arch_tables);
        }
        pr_cont("\n");
        set_bit(EFI_CONFIG_TABLES, &efi.flags);
 
-       if (efi.rng_seed != EFI_INVALID_TABLE_ADDR) {
+       if (efi_rng_seed != EFI_INVALID_TABLE_ADDR) {
                struct linux_efi_random_seed *seed;
                u32 size = 0;
 
-               seed = early_memremap(efi.rng_seed, sizeof(*seed));
+               seed = early_memremap(efi_rng_seed, sizeof(*seed));
                if (seed != NULL) {
-                       size = seed->size;
+                       size = READ_ONCE(seed->size);
                        early_memunmap(seed, sizeof(*seed));
                } else {
                        pr_err("Could not map UEFI random seed!\n");
                }
                if (size > 0) {
-                       seed = early_memremap(efi.rng_seed,
+                       seed = early_memremap(efi_rng_seed,
                                              sizeof(*seed) + size);
                        if (seed != NULL) {
                                pr_notice("seeding entropy pool\n");
-                               add_bootloader_randomness(seed->bits, seed->size);
+                               add_bootloader_randomness(seed->bits, size);
                                early_memunmap(seed, sizeof(*seed) + size);
                        } else {
                                pr_err("Could not map UEFI random seed!\n");
@@ -570,35 +600,17 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
                }
        }
 
-       if (efi_enabled(EFI_MEMMAP))
+       if (!IS_ENABLED(CONFIG_X86_32) && efi_enabled(EFI_MEMMAP))
                efi_memattr_init();
 
        efi_tpm_eventlog_init();
 
-       /* Parse the EFI Properties table if it exists */
-       if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
-               efi_properties_table_t *tbl;
-
-               tbl = early_memremap(efi.properties_table, sizeof(*tbl));
-               if (tbl == NULL) {
-                       pr_err("Could not map Properties table!\n");
-                       return -ENOMEM;
-               }
-
-               if (tbl->memory_protection_attribute &
-                   EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA)
-                       set_bit(EFI_NX_PE_DATA, &efi.flags);
-
-               early_memunmap(tbl, sizeof(*tbl));
-       }
-
-       if (efi.mem_reserve != EFI_INVALID_TABLE_ADDR) {
-               unsigned long prsv = efi.mem_reserve;
+       if (mem_reserve != EFI_INVALID_TABLE_ADDR) {
+               unsigned long prsv = mem_reserve;
 
                while (prsv) {
                        struct linux_efi_memreserve *rsv;
                        u8 *p;
-                       int i;
 
                        /*
                         * Just map a full page: that is what we will get
@@ -627,186 +639,78 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
                }
        }
 
-       return 0;
-}
-
-int __init efi_config_init(efi_config_table_type_t *arch_tables)
-{
-       void *config_tables;
-       int sz, ret;
-
-       if (efi.systab->nr_tables == 0)
-               return 0;
-
-       if (efi_enabled(EFI_64BIT))
-               sz = sizeof(efi_config_table_64_t);
-       else
-               sz = sizeof(efi_config_table_32_t);
+       if (rt_prop != EFI_INVALID_TABLE_ADDR) {
+               efi_rt_properties_table_t *tbl;
 
-       /*
-        * Let's see what config tables the firmware passed to us.
-        */
-       config_tables = early_memremap(efi.systab->tables,
-                                      efi.systab->nr_tables * sz);
-       if (config_tables == NULL) {
-               pr_err("Could not map Configuration table!\n");
-               return -ENOMEM;
+               tbl = early_memremap(rt_prop, sizeof(*tbl));
+               if (tbl) {
+                       efi.runtime_supported_mask &= tbl->runtime_services_supported;
+                       early_memunmap(tbl, sizeof(*tbl));
+               }
        }
 
-       ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
-                                     arch_tables);
-
-       early_memunmap(config_tables, efi.systab->nr_tables * sz);
-       return ret;
+       return 0;
 }
 
-#ifdef CONFIG_EFI_VARS_MODULE
-static int __init efi_load_efivars(void)
+int __init efi_systab_check_header(const efi_table_hdr_t *systab_hdr,
+                                  int min_major_version)
 {
-       struct platform_device *pdev;
-
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
-               return 0;
-
-       pdev = platform_device_register_simple("efivars", 0, NULL, 0);
-       return PTR_ERR_OR_ZERO(pdev);
-}
-device_initcall(efi_load_efivars);
-#endif
-
-#ifdef CONFIG_EFI_PARAMS_FROM_FDT
-
-#define UEFI_PARAM(name, prop, field)                     \
-       {                                                  \
-               { name },                                  \
-               { prop },                                  \
-               offsetof(struct efi_fdt_params, field),    \
-               sizeof_field(struct efi_fdt_params, field) \
+       if (systab_hdr->signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+               pr_err("System table signature incorrect!\n");
+               return -EINVAL;
        }
 
-struct params {
-       const char name[32];
-       const char propname[32];
-       int offset;
-       int size;
-};
-
-static __initdata struct params fdt_params[] = {
-       UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
-       UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
-       UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
-       UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
-       UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
-};
+       if ((systab_hdr->revision >> 16) < min_major_version)
+               pr_err("Warning: System table version %d.%02d, expected %d.00 or greater!\n",
+                      systab_hdr->revision >> 16,
+                      systab_hdr->revision & 0xffff,
+                      min_major_version);
 
-static __initdata struct params xen_fdt_params[] = {
-       UEFI_PARAM("System Table", "xen,uefi-system-table", system_table),
-       UEFI_PARAM("MemMap Address", "xen,uefi-mmap-start", mmap),
-       UEFI_PARAM("MemMap Size", "xen,uefi-mmap-size", mmap_size),
-       UEFI_PARAM("MemMap Desc. Size", "xen,uefi-mmap-desc-size", desc_size),
-       UEFI_PARAM("MemMap Desc. Version", "xen,uefi-mmap-desc-ver", desc_ver)
-};
-
-#define EFI_FDT_PARAMS_SIZE    ARRAY_SIZE(fdt_params)
-
-static __initdata struct {
-       const char *uname;
-       const char *subnode;
-       struct params *params;
-} dt_params[] = {
-       { "hypervisor", "uefi", xen_fdt_params },
-       { "chosen", NULL, fdt_params },
-};
-
-struct param_info {
-       int found;
-       void *params;
-       const char *missing;
-};
+       return 0;
+}
 
-static int __init __find_uefi_params(unsigned long node,
-                                    struct param_info *info,
-                                    struct params *params)
+#ifndef CONFIG_IA64
+static const efi_char16_t *__init map_fw_vendor(unsigned long fw_vendor,
+                                               size_t size)
 {
-       const void *prop;
-       void *dest;
-       u64 val;
-       int i, len;
-
-       for (i = 0; i < EFI_FDT_PARAMS_SIZE; i++) {
-               prop = of_get_flat_dt_prop(node, params[i].propname, &len);
-               if (!prop) {
-                       info->missing = params[i].name;
-                       return 0;
-               }
+       const efi_char16_t *ret;
 
-               dest = info->params + params[i].offset;
-               info->found++;
-
-               val = of_read_number(prop, len / sizeof(u32));
-
-               if (params[i].size == sizeof(u32))
-                       *(u32 *)dest = val;
-               else
-                       *(u64 *)dest = val;
-
-               if (efi_enabled(EFI_DBG))
-                       pr_info("  %s: 0x%0*llx\n", params[i].name,
-                               params[i].size * 2, val);
-       }
-
-       return 1;
+       ret = early_memremap_ro(fw_vendor, size);
+       if (!ret)
+               pr_err("Could not map the firmware vendor!\n");
+       return ret;
 }
 
-static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
-                                      int depth, void *data)
+static void __init unmap_fw_vendor(const void *fw_vendor, size_t size)
 {
-       struct param_info *info = data;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
-               const char *subnode = dt_params[i].subnode;
-
-               if (depth != 1 || strcmp(uname, dt_params[i].uname) != 0) {
-                       info->missing = dt_params[i].params[0].name;
-                       continue;
-               }
-
-               if (subnode) {
-                       int err = of_get_flat_dt_subnode_by_name(node, subnode);
-
-                       if (err < 0)
-                               return 0;
-
-                       node = err;
-               }
-
-               return __find_uefi_params(node, info, dt_params[i].params);
-       }
-
-       return 0;
+       early_memunmap((void *)fw_vendor, size);
 }
+#else
+#define map_fw_vendor(p, s)    __va(p)
+#define unmap_fw_vendor(v, s)
+#endif
 
-int __init efi_get_fdt_params(struct efi_fdt_params *params)
+void __init efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
+                                    unsigned long fw_vendor)
 {
-       struct param_info info;
-       int ret;
+       char vendor[100] = "unknown";
+       const efi_char16_t *c16;
+       size_t i;
 
-       pr_info("Getting EFI parameters from FDT:\n");
+       c16 = map_fw_vendor(fw_vendor, sizeof(vendor) * sizeof(efi_char16_t));
+       if (c16) {
+               for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
+                       vendor[i] = c16[i];
+               vendor[i] = '\0';
 
-       info.found = 0;
-       info.params = params;
-
-       ret = of_scan_flat_dt(fdt_find_uefi_params, &info);
-       if (!info.found)
-               pr_info("UEFI not found.\n");
-       else if (!ret)
-               pr_err("Can't find '%s' in device tree!\n",
-                      info.missing);
+               unmap_fw_vendor(c16, sizeof(vendor) * sizeof(efi_char16_t));
+       }
 
-       return ret;
+       pr_info("EFI v%u.%.02u by %s\n",
+               systab_hdr->revision >> 16,
+               systab_hdr->revision & 0xffff,
+               vendor);
 }
-#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
 
 static __initdata char memory_type_name[][20] = {
        "Reserved",
@@ -968,10 +872,10 @@ static struct linux_efi_memreserve *efi_memreserve_root __ro_after_init;
 
 static int __init efi_memreserve_map_root(void)
 {
-       if (efi.mem_reserve == EFI_INVALID_TABLE_ADDR)
+       if (mem_reserve == EFI_INVALID_TABLE_ADDR)
                return -ENODEV;
 
-       efi_memreserve_root = memremap(efi.mem_reserve,
+       efi_memreserve_root = memremap(mem_reserve,
                                       sizeof(*efi_memreserve_root),
                                       MEMREMAP_WB);
        if (WARN_ON_ONCE(!efi_memreserve_root))
@@ -1076,7 +980,7 @@ static int update_efi_random_seed(struct notifier_block *nb,
        if (!kexec_in_progress)
                return NOTIFY_DONE;
 
-       seed = memremap(efi.rng_seed, sizeof(*seed), MEMREMAP_WB);
+       seed = memremap(efi_rng_seed, sizeof(*seed), MEMREMAP_WB);
        if (seed != NULL) {
                size = min(seed->size, EFI_RANDOM_SEED_SIZE);
                memunmap(seed);
@@ -1084,7 +988,7 @@ static int update_efi_random_seed(struct notifier_block *nb,
                pr_err("Could not map UEFI random seed!\n");
        }
        if (size > 0) {
-               seed = memremap(efi.rng_seed, sizeof(*seed) + size,
+               seed = memremap(efi_rng_seed, sizeof(*seed) + size,
                                MEMREMAP_WB);
                if (seed != NULL) {
                        seed->size = size;
@@ -1101,9 +1005,9 @@ static struct notifier_block efi_random_seed_nb = {
        .notifier_call = update_efi_random_seed,
 };
 
-static int register_update_efi_random_seed(void)
+static int __init register_update_efi_random_seed(void)
 {
-       if (efi.rng_seed == EFI_INVALID_TABLE_ADDR)
+       if (efi_rng_seed == EFI_INVALID_TABLE_ADDR)
                return 0;
        return register_reboot_notifier(&efi_random_seed_nb);
 }
index 7576450..78ad1ba 100644 (file)
@@ -83,13 +83,16 @@ static ssize_t
 efivar_attr_read(struct efivar_entry *entry, char *buf)
 {
        struct efi_variable *var = &entry->var;
+       unsigned long size = sizeof(var->Data);
        char *str = buf;
+       int ret;
 
        if (!entry || !buf)
                return -EINVAL;
 
-       var->DataSize = 1024;
-       if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+       ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+       var->DataSize = size;
+       if (ret)
                return -EIO;
 
        if (var->Attributes & EFI_VARIABLE_NON_VOLATILE)
@@ -116,13 +119,16 @@ static ssize_t
 efivar_size_read(struct efivar_entry *entry, char *buf)
 {
        struct efi_variable *var = &entry->var;
+       unsigned long size = sizeof(var->Data);
        char *str = buf;
+       int ret;
 
        if (!entry || !buf)
                return -EINVAL;
 
-       var->DataSize = 1024;
-       if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+       ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+       var->DataSize = size;
+       if (ret)
                return -EIO;
 
        str += sprintf(str, "0x%lx\n", var->DataSize);
@@ -133,12 +139,15 @@ static ssize_t
 efivar_data_read(struct efivar_entry *entry, char *buf)
 {
        struct efi_variable *var = &entry->var;
+       unsigned long size = sizeof(var->Data);
+       int ret;
 
        if (!entry || !buf)
                return -EINVAL;
 
-       var->DataSize = 1024;
-       if (efivar_entry_get(entry, &var->Attributes, &var->DataSize, var->Data))
+       ret = efivar_entry_get(entry, &var->Attributes, &size, var->Data);
+       var->DataSize = size;
+       if (ret)
                return -EIO;
 
        memcpy(buf, var->Data, var->DataSize);
@@ -199,6 +208,9 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
        u8 *data;
        int err;
 
+       if (!entry || !buf)
+               return -EINVAL;
+
        if (in_compat_syscall()) {
                struct compat_efi_variable *compat;
 
@@ -250,14 +262,16 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
 {
        struct efi_variable *var = &entry->var;
        struct compat_efi_variable *compat;
+       unsigned long datasize = sizeof(var->Data);
        size_t size;
+       int ret;
 
        if (!entry || !buf)
                return 0;
 
-       var->DataSize = 1024;
-       if (efivar_entry_get(entry, &entry->var.Attributes,
-                            &entry->var.DataSize, entry->var.Data))
+       ret = efivar_entry_get(entry, &var->Attributes, &datasize, var->Data);
+       var->DataSize = datasize;
+       if (ret)
                return -EIO;
 
        if (in_compat_syscall()) {
@@ -664,7 +678,7 @@ int efivars_sysfs_init(void)
        struct kobject *parent_kobj = efivars_kobject();
        int error = 0;
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
                return -ENODEV;
 
        /* No efivars has been registered yet */
diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c
new file mode 100644 (file)
index 0000000..a1b199d
--- /dev/null
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for extracting embedded firmware for peripherals from EFI code,
+ *
+ * Copyright (c) 2018 Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/dmi.h>
+#include <linux/efi.h>
+#include <linux/efi_embedded_fw.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <crypto/sha.h>
+
+/* Exported for use by lib/test_firmware.c only */
+LIST_HEAD(efi_embedded_fw_list);
+EXPORT_SYMBOL_GPL(efi_embedded_fw_list);
+
+static bool checked_for_fw;
+
+static const struct dmi_system_id * const embedded_fw_table[] = {
+#ifdef CONFIG_TOUCHSCREEN_DMI
+       touchscreen_dmi_table,
+#endif
+       NULL
+};
+
+/*
+ * Note the efi_check_for_embedded_firmwares() code currently makes the
+ * following 2 assumptions. This may needs to be revisited if embedded firmware
+ * is found where this is not true:
+ * 1) The firmware is only found in EFI_BOOT_SERVICES_CODE memory segments
+ * 2) The firmware always starts at an offset which is a multiple of 8 bytes
+ */
+static int __init efi_check_md_for_embedded_firmware(
+       efi_memory_desc_t *md, const struct efi_embedded_fw_desc *desc)
+{
+       struct sha256_state sctx;
+       struct efi_embedded_fw *fw;
+       u8 sha256[32];
+       u64 i, size;
+       u8 *map;
+
+       size = md->num_pages << EFI_PAGE_SHIFT;
+       map = memremap(md->phys_addr, size, MEMREMAP_WB);
+       if (!map) {
+               pr_err("Error mapping EFI mem at %#llx\n", md->phys_addr);
+               return -ENOMEM;
+       }
+
+       for (i = 0; (i + desc->length) <= size; i += 8) {
+               if (memcmp(map + i, desc->prefix, EFI_EMBEDDED_FW_PREFIX_LEN))
+                       continue;
+
+               sha256_init(&sctx);
+               sha256_update(&sctx, map + i, desc->length);
+               sha256_final(&sctx, sha256);
+               if (memcmp(sha256, desc->sha256, 32) == 0)
+                       break;
+       }
+       if ((i + desc->length) > size) {
+               memunmap(map);
+               return -ENOENT;
+       }
+
+       pr_info("Found EFI embedded fw '%s'\n", desc->name);
+
+       fw = kmalloc(sizeof(*fw), GFP_KERNEL);
+       if (!fw) {
+               memunmap(map);
+               return -ENOMEM;
+       }
+
+       fw->data = kmemdup(map + i, desc->length, GFP_KERNEL);
+       memunmap(map);
+       if (!fw->data) {
+               kfree(fw);
+               return -ENOMEM;
+       }
+
+       fw->name = desc->name;
+       fw->length = desc->length;
+       list_add(&fw->list, &efi_embedded_fw_list);
+
+       return 0;
+}
+
+void __init efi_check_for_embedded_firmwares(void)
+{
+       const struct efi_embedded_fw_desc *fw_desc;
+       const struct dmi_system_id *dmi_id;
+       efi_memory_desc_t *md;
+       int i, r;
+
+       for (i = 0; embedded_fw_table[i]; i++) {
+               dmi_id = dmi_first_match(embedded_fw_table[i]);
+               if (!dmi_id)
+                       continue;
+
+               fw_desc = dmi_id->driver_data;
+
+               /*
+                * In some drivers the struct driver_data contains may contain
+                * other driver specific data after the fw_desc struct; and
+                * the fw_desc struct itself may be empty, skip these.
+                */
+               if (!fw_desc->name)
+                       continue;
+
+               for_each_efi_memory_desc(md) {
+                       if (md->type != EFI_BOOT_SERVICES_CODE)
+                               continue;
+
+                       r = efi_check_md_for_embedded_firmware(md, fw_desc);
+                       if (r == 0)
+                               break;
+               }
+       }
+
+       checked_for_fw = true;
+}
+
+int efi_get_embedded_fw(const char *name, const u8 **data, size_t *size)
+{
+       struct efi_embedded_fw *iter, *fw = NULL;
+
+       if (!checked_for_fw) {
+               pr_warn("Warning %s called while we did not check for embedded fw\n",
+                       __func__);
+               return -ENOENT;
+       }
+
+       list_for_each_entry(iter, &efi_embedded_fw_list, list) {
+               if (strcmp(name, iter->name) == 0) {
+                       fw = iter;
+                       break;
+               }
+       }
+
+       if (!fw)
+               return -ENOENT;
+
+       *data = fw->data;
+       *size = fw->length;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(efi_get_embedded_fw);
index 2762e06..e3d6926 100644 (file)
@@ -240,7 +240,6 @@ void __init efi_esrt_init(void)
 {
        void *va;
        struct efi_system_resource_table tmpesrt;
-       struct efi_system_resource_entry_v1 *v1_entries;
        size_t size, max, entry_size, entries_size;
        efi_memory_desc_t md;
        int rc;
@@ -288,14 +287,13 @@ void __init efi_esrt_init(void)
        memcpy(&tmpesrt, va, sizeof(tmpesrt));
        early_memunmap(va, size);
 
-       if (tmpesrt.fw_resource_version == 1) {
-               entry_size = sizeof (*v1_entries);
-       } else {
+       if (tmpesrt.fw_resource_version != 1) {
                pr_err("Unsupported ESRT version %lld.\n",
                       tmpesrt.fw_resource_version);
                return;
        }
 
+       entry_size = sizeof(struct efi_system_resource_entry_v1);
        if (tmpesrt.fw_resource_count > 0 && max - size < entry_size) {
                pr_err("ESRT memory map entry can only hold the header. (max: %zu size: %zu)\n",
                       max - size, entry_size);
diff --git a/drivers/firmware/efi/fdtparams.c b/drivers/firmware/efi/fdtparams.c
new file mode 100644 (file)
index 0000000..bb042ab
--- /dev/null
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "efi: " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/efi.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+
+#include <asm/unaligned.h>
+
+enum {
+       SYSTAB,
+       MMBASE,
+       MMSIZE,
+       DCSIZE,
+       DCVERS,
+
+       PARAMCOUNT
+};
+
+static __initconst const char name[][22] = {
+       [SYSTAB] = "System Table         ",
+       [MMBASE] = "MemMap Address       ",
+       [MMSIZE] = "MemMap Size          ",
+       [DCSIZE] = "MemMap Desc. Size    ",
+       [DCVERS] = "MemMap Desc. Version ",
+};
+
+static __initconst const struct {
+       const char      path[17];
+       const char      params[PARAMCOUNT][26];
+} dt_params[] = {
+       {
+#ifdef CONFIG_XEN    //  <-------17------>
+               .path = "/hypervisor/uefi",
+               .params = {
+                       [SYSTAB] = "xen,uefi-system-table",
+                       [MMBASE] = "xen,uefi-mmap-start",
+                       [MMSIZE] = "xen,uefi-mmap-size",
+                       [DCSIZE] = "xen,uefi-mmap-desc-size",
+                       [DCVERS] = "xen,uefi-mmap-desc-ver",
+               }
+       }, {
+#endif
+               .path = "/chosen",
+               .params = {     //  <-----------26----------->
+                       [SYSTAB] = "linux,uefi-system-table",
+                       [MMBASE] = "linux,uefi-mmap-start",
+                       [MMSIZE] = "linux,uefi-mmap-size",
+                       [DCSIZE] = "linux,uefi-mmap-desc-size",
+                       [DCVERS] = "linux,uefi-mmap-desc-ver",
+               }
+       }
+};
+
+static int __init efi_get_fdt_prop(const void *fdt, int node, const char *pname,
+                                  const char *rname, void *var, int size)
+{
+       const void *prop;
+       int len;
+       u64 val;
+
+       prop = fdt_getprop(fdt, node, pname, &len);
+       if (!prop)
+               return 1;
+
+       val = (len == 4) ? (u64)be32_to_cpup(prop) : get_unaligned_be64(prop);
+
+       if (size == 8)
+               *(u64 *)var = val;
+       else
+               *(u32 *)var = (val < U32_MAX) ? val : U32_MAX; // saturate
+
+       if (efi_enabled(EFI_DBG))
+               pr_info("  %s: 0x%0*llx\n", rname, size * 2, val);
+
+       return 0;
+}
+
+u64 __init efi_get_fdt_params(struct efi_memory_map_data *mm)
+{
+       const void *fdt = initial_boot_params;
+       unsigned long systab;
+       int i, j, node;
+       struct {
+               void    *var;
+               int     size;
+       } target[] = {
+               [SYSTAB] = { &systab,           sizeof(systab) },
+               [MMBASE] = { &mm->phys_map,     sizeof(mm->phys_map) },
+               [MMSIZE] = { &mm->size,         sizeof(mm->size) },
+               [DCSIZE] = { &mm->desc_size,    sizeof(mm->desc_size) },
+               [DCVERS] = { &mm->desc_version, sizeof(mm->desc_version) },
+       };
+
+       BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(name));
+       BUILD_BUG_ON(ARRAY_SIZE(target) != ARRAY_SIZE(dt_params[0].params));
+
+       for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
+               node = fdt_path_offset(fdt, dt_params[i].path);
+               if (node < 0)
+                       continue;
+
+               if (efi_enabled(EFI_DBG))
+                       pr_info("Getting UEFI parameters from %s in DT:\n",
+                               dt_params[i].path);
+
+               for (j = 0; j < ARRAY_SIZE(target); j++) {
+                       const char *pname = dt_params[i].params[j];
+
+                       if (!efi_get_fdt_prop(fdt, node, pname, name[j],
+                                             target[j].var, target[j].size))
+                               continue;
+                       if (!j)
+                               goto notfound;
+                       pr_err("Can't find property '%s' in DT!\n", pname);
+                       return 0;
+               }
+               return systab;
+       }
+notfound:
+       pr_info("UEFI not found.\n");
+       return 0;
+}
index 98a8157..094eabd 100644 (file)
@@ -12,7 +12,8 @@ cflags-$(CONFIG_X86)          += -m$(BITS) -D__KERNEL__ -O2 \
                                   -mno-mmx -mno-sse -fshort-wchar \
                                   -Wno-pointer-sign \
                                   $(call cc-disable-warning, address-of-packed-member) \
-                                  $(call cc-disable-warning, gnu)
+                                  $(call cc-disable-warning, gnu) \
+                                  -fno-asynchronous-unwind-tables
 
 # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly
 # disable the stackleak plugin
@@ -25,6 +26,7 @@ cflags-$(CONFIG_ARM)          := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) \
 cflags-$(CONFIG_EFI_ARMSTUB)   += -I$(srctree)/scripts/dtc/libfdt
 
 KBUILD_CFLAGS                  := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
+                                  -include $(srctree)/drivers/firmware/efi/libstub/hidden.h \
                                   -D__NO_FORTIFY \
                                   $(call cc-option,-ffreestanding) \
                                   $(call cc-option,-fno-stack-protector) \
@@ -39,11 +41,11 @@ OBJECT_FILES_NON_STANDARD   := y
 KCOV_INSTRUMENT                        := n
 
 lib-y                          := efi-stub-helper.o gop.o secureboot.o tpm.o \
-                                  random.o pci.o
+                                  file.o mem.o random.o randomalloc.o pci.o \
+                                  skip_spaces.o lib-cmdline.o lib-ctype.o
 
 # include the stub's generic dependencies from lib/ when building for ARM/arm64
 arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
-arm-deps-$(CONFIG_ARM64) += sort.c
 
 $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
        $(call if_changed_rule,cc_o_c)
@@ -53,6 +55,7 @@ lib-$(CONFIG_EFI_ARMSTUB)     += arm-stub.o fdt.o string.o \
 
 lib-$(CONFIG_ARM)              += arm32-stub.o
 lib-$(CONFIG_ARM64)            += arm64-stub.o
+lib-$(CONFIG_X86)              += x86-stub.o
 CFLAGS_arm32-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
 CFLAGS_arm64-stub.o            := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
index 7bbef4a..99a5cde 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/efi.h>
-#include <linux/sort.h>
+#include <linux/libfdt.h>
 #include <asm/efi.h>
 
 #include "efistub.h"
@@ -36,6 +36,7 @@
 #endif
 
 static u64 virtmap_base = EFI_RT_VIRTUAL_BASE;
+static bool __efistub_global flat_va_mapping;
 
 static efi_system_table_t *__efistub_global sys_table;
 
@@ -87,6 +88,39 @@ void install_memreserve_table(void)
                pr_efi_err("Failed to install memreserve config table!\n");
 }
 
+static unsigned long get_dram_base(void)
+{
+       efi_status_t status;
+       unsigned long map_size, buff_size;
+       unsigned long membase  = EFI_ERROR;
+       struct efi_memory_map map;
+       efi_memory_desc_t *md;
+       struct efi_boot_memmap boot_map;
+
+       boot_map.map            = (efi_memory_desc_t **)&map.map;
+       boot_map.map_size       = &map_size;
+       boot_map.desc_size      = &map.desc_size;
+       boot_map.desc_ver       = NULL;
+       boot_map.key_ptr        = NULL;
+       boot_map.buff_size      = &buff_size;
+
+       status = efi_get_memory_map(&boot_map);
+       if (status != EFI_SUCCESS)
+               return membase;
+
+       map.map_end = map.map + map_size;
+
+       for_each_efi_memory_desc_in_map(&map, md) {
+               if (md->attribute & EFI_MEMORY_WB) {
+                       if (membase > md->phys_addr)
+                               membase = md->phys_addr;
+               }
+       }
+
+       efi_bs_call(free_pool, map.map);
+
+       return membase;
+}
 
 /*
  * This function handles the architcture specific differences between arm and
@@ -100,38 +134,46 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                                 unsigned long *reserve_size,
                                 unsigned long dram_base,
                                 efi_loaded_image_t *image);
+
+asmlinkage void __noreturn efi_enter_kernel(unsigned long entrypoint,
+                                           unsigned long fdt_addr,
+                                           unsigned long fdt_size);
+
 /*
  * EFI entry point for the arm/arm64 EFI stubs.  This is the entrypoint
  * that is described in the PE/COFF header.  Most of the code is the same
  * for both archictectures, with the arch-specific code provided in the
  * handle_kernel_image() function.
  */
-unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
-                              unsigned long *image_addr)
+efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
 {
        efi_loaded_image_t *image;
        efi_status_t status;
+       unsigned long image_addr;
        unsigned long image_size = 0;
        unsigned long dram_base;
        /* addr/point and size pairs for memory management*/
-       unsigned long initrd_addr;
-       u64 initrd_size = 0;
+       unsigned long initrd_addr = 0;
+       unsigned long initrd_size = 0;
        unsigned long fdt_addr = 0;  /* Original DTB */
        unsigned long fdt_size = 0;
        char *cmdline_ptr = NULL;
        int cmdline_size = 0;
-       unsigned long new_fdt_addr;
        efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
        unsigned long reserve_addr = 0;
        unsigned long reserve_size = 0;
        enum efi_secureboot_mode secure_boot;
        struct screen_info *si;
+       efi_properties_table_t *prop_tbl;
+       unsigned long max_addr;
 
        sys_table = sys_table_arg;
 
        /* Check if we were booted by the EFI firmware */
-       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+       if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+               status = EFI_INVALID_PARAMETER;
                goto fail;
+       }
 
        status = check_platform_features();
        if (status != EFI_SUCCESS)
@@ -152,6 +194,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
        dram_base = get_dram_base();
        if (dram_base == EFI_ERROR) {
                pr_efi_err("Failed to find DRAM base\n");
+               status = EFI_LOAD_ERROR;
                goto fail;
        }
 
@@ -160,9 +203,10 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
         * protocol. We are going to copy the command line into the
         * device tree, so this can be allocated anywhere.
         */
-       cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
+       cmdline_ptr = efi_convert_cmdline(image, &cmdline_size, ULONG_MAX);
        if (!cmdline_ptr) {
                pr_efi_err("getting command line via LOADED_IMAGE_PROTOCOL\n");
+               status = EFI_OUT_OF_RESOURCES;
                goto fail;
        }
 
@@ -178,7 +222,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
 
        si = setup_graphics();
 
-       status = handle_kernel_image(image_addr, &image_size,
+       status = handle_kernel_image(&image_addr, &image_size,
                                     &reserve_addr,
                                     &reserve_size,
                                     dram_base, image);
@@ -204,8 +248,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
                if (strstr(cmdline_ptr, "dtb="))
                        pr_efi("Ignoring DTB from command line.\n");
        } else {
-               status = handle_cmdline_files(image, cmdline_ptr, "dtb=",
-                                             ~0UL, &fdt_addr, &fdt_size);
+               status = efi_load_dtb(image, &fdt_addr, &fdt_size);
 
                if (status != EFI_SUCCESS) {
                        pr_efi_err("Failed to load device tree!\n");
@@ -225,18 +268,38 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
        if (!fdt_addr)
                pr_efi("Generating empty DTB\n");
 
-       status = handle_cmdline_files(image, cmdline_ptr, "initrd=",
-                                     efi_get_max_initrd_addr(dram_base,
-                                                             *image_addr),
-                                     (unsigned long *)&initrd_addr,
-                                     (unsigned long *)&initrd_size);
-       if (status != EFI_SUCCESS)
-               pr_efi_err("Failed initrd from command line!\n");
+       if (!noinitrd()) {
+               max_addr = efi_get_max_initrd_addr(dram_base, image_addr);
+               status = efi_load_initrd_dev_path(&initrd_addr, &initrd_size,
+                                                 max_addr);
+               if (status == EFI_SUCCESS) {
+                       pr_efi("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
+               } else if (status == EFI_NOT_FOUND) {
+                       status = efi_load_initrd(image, &initrd_addr, &initrd_size,
+                                                ULONG_MAX, max_addr);
+                       if (status == EFI_SUCCESS && initrd_size > 0)
+                               pr_efi("Loaded initrd from command line option\n");
+               }
+               if (status != EFI_SUCCESS)
+                       pr_efi_err("Failed to load initrd!\n");
+       }
 
        efi_random_get_seed();
 
+       /*
+        * If the NX PE data feature is enabled in the properties table, we
+        * should take care not to create a virtual mapping that changes the
+        * relative placement of runtime services code and data regions, as
+        * they may belong to the same PE/COFF executable image in memory.
+        * The easiest way to achieve that is to simply use a 1:1 mapping.
+        */
+       prop_tbl = get_efi_config_table(EFI_PROPERTIES_TABLE_GUID);
+       flat_va_mapping = prop_tbl &&
+                         (prop_tbl->memory_protection_attribute &
+                          EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA);
+
        /* hibernation expects the runtime regions to stay in the same place */
-       if (!IS_ENABLED(CONFIG_HIBERNATION) && !nokaslr()) {
+       if (!IS_ENABLED(CONFIG_HIBERNATION) && !nokaslr() && !flat_va_mapping) {
                /*
                 * Randomize the base of the UEFI runtime services region.
                 * Preserve the 2 MB alignment of the region by taking a
@@ -257,71 +320,30 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table_arg,
 
        install_memreserve_table();
 
-       new_fdt_addr = fdt_addr;
-       status = allocate_new_fdt_and_exit_boot(handle,
-                               &new_fdt_addr, efi_get_max_fdt_addr(dram_base),
-                               initrd_addr, initrd_size, cmdline_ptr,
-                               fdt_addr, fdt_size);
+       status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr,
+                                               efi_get_max_fdt_addr(dram_base),
+                                               initrd_addr, initrd_size,
+                                               cmdline_ptr, fdt_addr, fdt_size);
+       if (status != EFI_SUCCESS)
+               goto fail_free_initrd;
 
-       /*
-        * If all went well, we need to return the FDT address to the
-        * calling function so it can be passed to kernel as part of
-        * the kernel boot protocol.
-        */
-       if (status == EFI_SUCCESS)
-               return new_fdt_addr;
+       efi_enter_kernel(image_addr, fdt_addr, fdt_totalsize((void *)fdt_addr));
+       /* not reached */
 
+fail_free_initrd:
        pr_efi_err("Failed to update FDT and exit boot services\n");
 
        efi_free(initrd_size, initrd_addr);
        efi_free(fdt_size, fdt_addr);
 
 fail_free_image:
-       efi_free(image_size, *image_addr);
+       efi_free(image_size, image_addr);
        efi_free(reserve_size, reserve_addr);
 fail_free_cmdline:
        free_screen_info(si);
        efi_free(cmdline_size, (unsigned long)cmdline_ptr);
 fail:
-       return EFI_ERROR;
-}
-
-static int cmp_mem_desc(const void *l, const void *r)
-{
-       const efi_memory_desc_t *left = l, *right = r;
-
-       return (left->phys_addr > right->phys_addr) ? 1 : -1;
-}
-
-/*
- * Returns whether region @left ends exactly where region @right starts,
- * or false if either argument is NULL.
- */
-static bool regions_are_adjacent(efi_memory_desc_t *left,
-                                efi_memory_desc_t *right)
-{
-       u64 left_end;
-
-       if (left == NULL || right == NULL)
-               return false;
-
-       left_end = left->phys_addr + left->num_pages * EFI_PAGE_SIZE;
-
-       return left_end == right->phys_addr;
-}
-
-/*
- * Returns whether region @left and region @right have compatible memory type
- * mapping attributes, and are both EFI_MEMORY_RUNTIME regions.
- */
-static bool regions_have_compatible_memory_type_attrs(efi_memory_desc_t *left,
-                                                     efi_memory_desc_t *right)
-{
-       static const u64 mem_type_mask = EFI_MEMORY_WB | EFI_MEMORY_WT |
-                                        EFI_MEMORY_WC | EFI_MEMORY_UC |
-                                        EFI_MEMORY_RUNTIME;
-
-       return ((left->attribute ^ right->attribute) & mem_type_mask) == 0;
+       return status;
 }
 
 /*
@@ -336,23 +358,10 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                     int *count)
 {
        u64 efi_virt_base = virtmap_base;
-       efi_memory_desc_t *in, *prev = NULL, *out = runtime_map;
+       efi_memory_desc_t *in, *out = runtime_map;
        int l;
 
-       /*
-        * To work around potential issues with the Properties Table feature
-        * introduced in UEFI 2.5, which may split PE/COFF executable images
-        * in memory into several RuntimeServicesCode and RuntimeServicesData
-        * regions, we need to preserve the relative offsets between adjacent
-        * EFI_MEMORY_RUNTIME regions with the same memory type attributes.
-        * The easiest way to find adjacent regions is to sort the memory map
-        * before traversing it.
-        */
-       if (IS_ENABLED(CONFIG_ARM64))
-               sort(memory_map, map_size / desc_size, desc_size, cmp_mem_desc,
-                    NULL);
-
-       for (l = 0; l < map_size; l += desc_size, prev = in) {
+       for (l = 0; l < map_size; l += desc_size) {
                u64 paddr, size;
 
                in = (void *)memory_map + l;
@@ -362,8 +371,8 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                paddr = in->phys_addr;
                size = in->num_pages * EFI_PAGE_SIZE;
 
+               in->virt_addr = in->phys_addr;
                if (novamap()) {
-                       in->virt_addr = in->phys_addr;
                        continue;
                }
 
@@ -372,9 +381,7 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                 * a 4k page size kernel to kexec a 64k page size kernel and
                 * vice versa.
                 */
-               if ((IS_ENABLED(CONFIG_ARM64) &&
-                    !regions_are_adjacent(prev, in)) ||
-                   !regions_have_compatible_memory_type_attrs(prev, in)) {
+               if (!flat_va_mapping) {
 
                        paddr = round_down(in->phys_addr, SZ_64K);
                        size += in->phys_addr - paddr;
@@ -389,10 +396,10 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
                                efi_virt_base = round_up(efi_virt_base, SZ_2M);
                        else
                                efi_virt_base = round_up(efi_virt_base, SZ_64K);
-               }
 
-               in->virt_addr = efi_virt_base + in->phys_addr - paddr;
-               efi_virt_base += size;
+                       in->virt_addr += efi_virt_base - paddr;
+                       efi_virt_base += size;
+               }
 
                memcpy(out, in, desc_size);
                out = (void *)out + desc_size;
index 7b2a638..7826553 100644 (file)
@@ -227,6 +227,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
         * Relocate the zImage, so that it appears in the lowest 128 MB
         * memory window.
         */
+       *image_addr = (unsigned long)image->image_base;
        *image_size = image->image_size;
        status = efi_relocate_kernel(image_addr, *image_size, *image_size,
                                     kernel_base + MAX_UNCOMP_KERNEL_SIZE, 0, 0);
index 2915b44..db0c1a9 100644 (file)
@@ -6,17 +6,11 @@
  * Adapted from ARM version by Mark Salter <msalter@redhat.com>
  */
 
-/*
- * To prevent the compiler from emitting GOT-indirected (and thus absolute)
- * references to the section markers, override their visibility as 'hidden'
- */
-#pragma GCC visibility push(hidden)
-#include <asm/sections.h>
-#pragma GCC visibility pop
 
 #include <linux/efi.h>
 #include <asm/efi.h>
 #include <asm/memory.h>
+#include <asm/sections.h>
 #include <asm/sysreg.h>
 
 #include "efistub.h"
@@ -49,7 +43,6 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
 {
        efi_status_t status;
        unsigned long kernel_size, kernel_memsize = 0;
-       void *old_image_addr = (void *)*image_addr;
        unsigned long preferred_offset;
        u64 phys_seed = 0;
 
@@ -123,6 +116,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                 * Mustang), we can still place the kernel at the address
                 * 'dram_base + TEXT_OFFSET'.
                 */
+               *image_addr = (unsigned long)_text;
                if (*image_addr == preferred_offset)
                        return EFI_SUCCESS;
 
@@ -147,7 +141,11 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
                }
                *image_addr = *reserve_addr + TEXT_OFFSET;
        }
-       memcpy((void *)*image_addr, old_image_addr, kernel_size);
+
+       if (image->image_base != _text)
+               pr_efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
+
+       memcpy((void *)*image_addr, _text, kernel_size);
 
        return EFI_SUCCESS;
 }
index 74ddfb4..9f34c72 100644 (file)
 
 #include "efistub.h"
 
-/*
- * Some firmware implementations have problems reading files in one go.
- * A read chunk size of 1MB seems to work for most platforms.
- *
- * Unfortunately, reading files in chunks triggers *other* bugs on some
- * platforms, so we provide a way to disable this workaround, which can
- * be done by passing "efi=nochunk" on the EFI boot stub command line.
- *
- * If you experience issues with initrd images being corrupt it's worth
- * trying efi=nochunk, but chunking is enabled by default because there
- * are far more machines that require the workaround than those that
- * break with it enabled.
- */
-#define EFI_READ_CHUNK_SIZE    (1024 * 1024)
-
-static unsigned long efi_chunk_size = EFI_READ_CHUNK_SIZE;
-
+static bool __efistub_global efi_nochunk;
 static bool __efistub_global efi_nokaslr;
+static bool __efistub_global efi_noinitrd;
 static bool __efistub_global efi_quiet;
 static bool __efistub_global efi_novamap;
 static bool __efistub_global efi_nosoftreserve;
 static bool __efistub_global efi_disable_pci_dma =
                                        IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
 
+bool __pure nochunk(void)
+{
+       return efi_nochunk;
+}
 bool __pure nokaslr(void)
 {
        return efi_nokaslr;
 }
+bool __pure noinitrd(void)
+{
+       return efi_noinitrd;
+}
 bool __pure is_quiet(void)
 {
        return efi_quiet;
@@ -53,13 +46,6 @@ bool __pure __efi_soft_reserve_enabled(void)
        return !efi_nosoftreserve;
 }
 
-#define EFI_MMAP_NR_SLACK_SLOTS        8
-
-struct file_info {
-       efi_file_handle_t *handle;
-       u64 size;
-};
-
 void efi_printk(char *str)
 {
        char *s8;
@@ -77,369 +63,6 @@ void efi_printk(char *str)
        }
 }
 
-static inline bool mmap_has_headroom(unsigned long buff_size,
-                                    unsigned long map_size,
-                                    unsigned long desc_size)
-{
-       unsigned long slack = buff_size - map_size;
-
-       return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS;
-}
-
-efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
-{
-       efi_memory_desc_t *m = NULL;
-       efi_status_t status;
-       unsigned long key;
-       u32 desc_version;
-
-       *map->desc_size =       sizeof(*m);
-       *map->map_size =        *map->desc_size * 32;
-       *map->buff_size =       *map->map_size;
-again:
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
-                            *map->map_size, (void **)&m);
-       if (status != EFI_SUCCESS)
-               goto fail;
-
-       *map->desc_size = 0;
-       key = 0;
-       status = efi_bs_call(get_memory_map, map->map_size, m,
-                            &key, map->desc_size, &desc_version);
-       if (status == EFI_BUFFER_TOO_SMALL ||
-           !mmap_has_headroom(*map->buff_size, *map->map_size,
-                              *map->desc_size)) {
-               efi_bs_call(free_pool, m);
-               /*
-                * Make sure there is some entries of headroom so that the
-                * buffer can be reused for a new map after allocations are
-                * no longer permitted.  Its unlikely that the map will grow to
-                * exceed this headroom once we are ready to trigger
-                * ExitBootServices()
-                */
-               *map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS;
-               *map->buff_size = *map->map_size;
-               goto again;
-       }
-
-       if (status != EFI_SUCCESS)
-               efi_bs_call(free_pool, m);
-
-       if (map->key_ptr && status == EFI_SUCCESS)
-               *map->key_ptr = key;
-       if (map->desc_ver && status == EFI_SUCCESS)
-               *map->desc_ver = desc_version;
-
-fail:
-       *map->map = m;
-       return status;
-}
-
-
-unsigned long get_dram_base(void)
-{
-       efi_status_t status;
-       unsigned long map_size, buff_size;
-       unsigned long membase  = EFI_ERROR;
-       struct efi_memory_map map;
-       efi_memory_desc_t *md;
-       struct efi_boot_memmap boot_map;
-
-       boot_map.map =          (efi_memory_desc_t **)&map.map;
-       boot_map.map_size =     &map_size;
-       boot_map.desc_size =    &map.desc_size;
-       boot_map.desc_ver =     NULL;
-       boot_map.key_ptr =      NULL;
-       boot_map.buff_size =    &buff_size;
-
-       status = efi_get_memory_map(&boot_map);
-       if (status != EFI_SUCCESS)
-               return membase;
-
-       map.map_end = map.map + map_size;
-
-       for_each_efi_memory_desc_in_map(&map, md) {
-               if (md->attribute & EFI_MEMORY_WB) {
-                       if (membase > md->phys_addr)
-                               membase = md->phys_addr;
-               }
-       }
-
-       efi_bs_call(free_pool, map.map);
-
-       return membase;
-}
-
-/*
- * Allocate at the highest possible address that is not above 'max'.
- */
-efi_status_t efi_high_alloc(unsigned long size, unsigned long align,
-                           unsigned long *addr, unsigned long max)
-{
-       unsigned long map_size, desc_size, buff_size;
-       efi_memory_desc_t *map;
-       efi_status_t status;
-       unsigned long nr_pages;
-       u64 max_addr = 0;
-       int i;
-       struct efi_boot_memmap boot_map;
-
-       boot_map.map =          &map;
-       boot_map.map_size =     &map_size;
-       boot_map.desc_size =    &desc_size;
-       boot_map.desc_ver =     NULL;
-       boot_map.key_ptr =      NULL;
-       boot_map.buff_size =    &buff_size;
-
-       status = efi_get_memory_map(&boot_map);
-       if (status != EFI_SUCCESS)
-               goto fail;
-
-       /*
-        * Enforce minimum alignment that EFI or Linux requires when
-        * requesting a specific address.  We are doing page-based (or
-        * larger) allocations, and both the address and size must meet
-        * alignment constraints.
-        */
-       if (align < EFI_ALLOC_ALIGN)
-               align = EFI_ALLOC_ALIGN;
-
-       size = round_up(size, EFI_ALLOC_ALIGN);
-       nr_pages = size / EFI_PAGE_SIZE;
-again:
-       for (i = 0; i < map_size / desc_size; i++) {
-               efi_memory_desc_t *desc;
-               unsigned long m = (unsigned long)map;
-               u64 start, end;
-
-               desc = efi_early_memdesc_ptr(m, desc_size, i);
-               if (desc->type != EFI_CONVENTIONAL_MEMORY)
-                       continue;
-
-               if (efi_soft_reserve_enabled() &&
-                   (desc->attribute & EFI_MEMORY_SP))
-                       continue;
-
-               if (desc->num_pages < nr_pages)
-                       continue;
-
-               start = desc->phys_addr;
-               end = start + desc->num_pages * EFI_PAGE_SIZE;
-
-               if (end > max)
-                       end = max;
-
-               if ((start + size) > end)
-                       continue;
-
-               if (round_down(end - size, align) < start)
-                       continue;
-
-               start = round_down(end - size, align);
-
-               /*
-                * Don't allocate at 0x0. It will confuse code that
-                * checks pointers against NULL.
-                */
-               if (start == 0x0)
-                       continue;
-
-               if (start > max_addr)
-                       max_addr = start;
-       }
-
-       if (!max_addr)
-               status = EFI_NOT_FOUND;
-       else {
-               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                                    EFI_LOADER_DATA, nr_pages, &max_addr);
-               if (status != EFI_SUCCESS) {
-                       max = max_addr;
-                       max_addr = 0;
-                       goto again;
-               }
-
-               *addr = max_addr;
-       }
-
-       efi_bs_call(free_pool, map);
-fail:
-       return status;
-}
-
-/*
- * Allocate at the lowest possible address that is not below 'min'.
- */
-efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
-                                unsigned long *addr, unsigned long min)
-{
-       unsigned long map_size, desc_size, buff_size;
-       efi_memory_desc_t *map;
-       efi_status_t status;
-       unsigned long nr_pages;
-       int i;
-       struct efi_boot_memmap boot_map;
-
-       boot_map.map =          &map;
-       boot_map.map_size =     &map_size;
-       boot_map.desc_size =    &desc_size;
-       boot_map.desc_ver =     NULL;
-       boot_map.key_ptr =      NULL;
-       boot_map.buff_size =    &buff_size;
-
-       status = efi_get_memory_map(&boot_map);
-       if (status != EFI_SUCCESS)
-               goto fail;
-
-       /*
-        * Enforce minimum alignment that EFI or Linux requires when
-        * requesting a specific address.  We are doing page-based (or
-        * larger) allocations, and both the address and size must meet
-        * alignment constraints.
-        */
-       if (align < EFI_ALLOC_ALIGN)
-               align = EFI_ALLOC_ALIGN;
-
-       size = round_up(size, EFI_ALLOC_ALIGN);
-       nr_pages = size / EFI_PAGE_SIZE;
-       for (i = 0; i < map_size / desc_size; i++) {
-               efi_memory_desc_t *desc;
-               unsigned long m = (unsigned long)map;
-               u64 start, end;
-
-               desc = efi_early_memdesc_ptr(m, desc_size, i);
-
-               if (desc->type != EFI_CONVENTIONAL_MEMORY)
-                       continue;
-
-               if (efi_soft_reserve_enabled() &&
-                   (desc->attribute & EFI_MEMORY_SP))
-                       continue;
-
-               if (desc->num_pages < nr_pages)
-                       continue;
-
-               start = desc->phys_addr;
-               end = start + desc->num_pages * EFI_PAGE_SIZE;
-
-               if (start < min)
-                       start = min;
-
-               start = round_up(start, align);
-               if ((start + size) > end)
-                       continue;
-
-               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                                    EFI_LOADER_DATA, nr_pages, &start);
-               if (status == EFI_SUCCESS) {
-                       *addr = start;
-                       break;
-               }
-       }
-
-       if (i == map_size / desc_size)
-               status = EFI_NOT_FOUND;
-
-       efi_bs_call(free_pool, map);
-fail:
-       return status;
-}
-
-void efi_free(unsigned long size, unsigned long addr)
-{
-       unsigned long nr_pages;
-
-       if (!size)
-               return;
-
-       nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
-       efi_bs_call(free_pages, addr, nr_pages);
-}
-
-static efi_status_t efi_file_size(void *__fh, efi_char16_t *filename_16,
-                                 void **handle, u64 *file_sz)
-{
-       efi_file_handle_t *h, *fh = __fh;
-       efi_file_info_t *info;
-       efi_status_t status;
-       efi_guid_t info_guid = EFI_FILE_INFO_ID;
-       unsigned long info_sz;
-
-       status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, 0);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to open file: ");
-               efi_char16_printk(filename_16);
-               efi_printk("\n");
-               return status;
-       }
-
-       *handle = h;
-
-       info_sz = 0;
-       status = h->get_info(h, &info_guid, &info_sz, NULL);
-       if (status != EFI_BUFFER_TOO_SMALL) {
-               efi_printk("Failed to get file info size\n");
-               return status;
-       }
-
-grow:
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, info_sz,
-                            (void **)&info);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to alloc mem for file info\n");
-               return status;
-       }
-
-       status = h->get_info(h, &info_guid, &info_sz, info);
-       if (status == EFI_BUFFER_TOO_SMALL) {
-               efi_bs_call(free_pool, info);
-               goto grow;
-       }
-
-       *file_sz = info->file_size;
-       efi_bs_call(free_pool, info);
-
-       if (status != EFI_SUCCESS)
-               efi_printk("Failed to get initrd info\n");
-
-       return status;
-}
-
-static efi_status_t efi_file_read(efi_file_handle_t *handle,
-                                 unsigned long *size, void *addr)
-{
-       return handle->read(handle, size, addr);
-}
-
-static efi_status_t efi_file_close(efi_file_handle_t *handle)
-{
-       return handle->close(handle);
-}
-
-static efi_status_t efi_open_volume(efi_loaded_image_t *image,
-                                   efi_file_handle_t **__fh)
-{
-       efi_file_io_interface_t *io;
-       efi_file_handle_t *fh;
-       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
-       efi_status_t status;
-       efi_handle_t handle = image->device_handle;
-
-       status = efi_bs_call(handle_protocol, handle, &fs_proto, (void **)&io);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to handle fs_proto\n");
-               return status;
-       }
-
-       status = io->open_volume(io, &fh);
-       if (status != EFI_SUCCESS)
-               efi_printk("Failed to open volume\n");
-       else
-               *__fh = fh;
-
-       return status;
-}
-
 /*
  * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi=
  * option, e.g. efi=nochunk.
@@ -450,316 +73,42 @@ static efi_status_t efi_open_volume(efi_loaded_image_t *image,
  */
 efi_status_t efi_parse_options(char const *cmdline)
 {
-       char *str;
-
-       str = strstr(cmdline, "nokaslr");
-       if (str == cmdline || (str && str > cmdline && *(str - 1) == ' '))
-               efi_nokaslr = true;
-
-       str = strstr(cmdline, "quiet");
-       if (str == cmdline || (str && str > cmdline && *(str - 1) == ' '))
-               efi_quiet = true;
-
-       /*
-        * If no EFI parameters were specified on the cmdline we've got
-        * nothing to do.
-        */
-       str = strstr(cmdline, "efi=");
-       if (!str)
-               return EFI_SUCCESS;
-
-       /* Skip ahead to first argument */
-       str += strlen("efi=");
-
-       /*
-        * Remember, because efi= is also used by the kernel we need to
-        * skip over arguments we don't understand.
-        */
-       while (*str && *str != ' ') {
-               if (!strncmp(str, "nochunk", 7)) {
-                       str += strlen("nochunk");
-                       efi_chunk_size = -1UL;
-               }
-
-               if (!strncmp(str, "novamap", 7)) {
-                       str += strlen("novamap");
-                       efi_novamap = true;
-               }
-
-               if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
-                   !strncmp(str, "nosoftreserve", 7)) {
-                       str += strlen("nosoftreserve");
-                       efi_nosoftreserve = true;
-               }
-
-               if (!strncmp(str, "disable_early_pci_dma", 21)) {
-                       str += strlen("disable_early_pci_dma");
-                       efi_disable_pci_dma = true;
-               }
-
-               if (!strncmp(str, "no_disable_early_pci_dma", 24)) {
-                       str += strlen("no_disable_early_pci_dma");
-                       efi_disable_pci_dma = false;
-               }
-
-               /* Group words together, delimited by "," */
-               while (*str && *str != ' ' && *str != ',')
-                       str++;
-
-               if (*str == ',')
-                       str++;
-       }
-
-       return EFI_SUCCESS;
-}
-
-/*
- * Check the cmdline for a LILO-style file= arguments.
- *
- * We only support loading a file from the same filesystem as
- * the kernel image.
- */
-efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
-                                 char *cmd_line, char *option_string,
-                                 unsigned long max_addr,
-                                 unsigned long *load_addr,
-                                 unsigned long *load_size)
-{
-       struct file_info *files;
-       unsigned long file_addr;
-       u64 file_size_total;
-       efi_file_handle_t *fh = NULL;
+       size_t len = strlen(cmdline) + 1;
        efi_status_t status;
-       int nr_files;
-       char *str;
-       int i, j, k;
-
-       file_addr = 0;
-       file_size_total = 0;
-
-       str = cmd_line;
-
-       j = 0;                  /* See close_handles */
-
-       if (!load_addr || !load_size)
-               return EFI_INVALID_PARAMETER;
-
-       *load_addr = 0;
-       *load_size = 0;
-
-       if (!str || !*str)
-               return EFI_SUCCESS;
-
-       for (nr_files = 0; *str; nr_files++) {
-               str = strstr(str, option_string);
-               if (!str)
-                       break;
-
-               str += strlen(option_string);
-
-               /* Skip any leading slashes */
-               while (*str == '/' || *str == '\\')
-                       str++;
-
-               while (*str && *str != ' ' && *str != '\n')
-                       str++;
-       }
-
-       if (!nr_files)
-               return EFI_SUCCESS;
-
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
-                            nr_files * sizeof(*files), (void **)&files);
-       if (status != EFI_SUCCESS) {
-               pr_efi_err("Failed to alloc mem for file handle list\n");
-               goto fail;
-       }
-
-       str = cmd_line;
-       for (i = 0; i < nr_files; i++) {
-               struct file_info *file;
-               efi_char16_t filename_16[256];
-               efi_char16_t *p;
-
-               str = strstr(str, option_string);
-               if (!str)
-                       break;
-
-               str += strlen(option_string);
-
-               file = &files[i];
-               p = filename_16;
-
-               /* Skip any leading slashes */
-               while (*str == '/' || *str == '\\')
-                       str++;
-
-               while (*str && *str != ' ' && *str != '\n') {
-                       if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
-                               break;
-
-                       if (*str == '/') {
-                               *p++ = '\\';
-                               str++;
-                       } else {
-                               *p++ = *str++;
-                       }
-               }
-
-               *p = '\0';
+       char *str, *buf;
 
-               /* Only open the volume once. */
-               if (!i) {
-                       status = efi_open_volume(image, &fh);
-                       if (status != EFI_SUCCESS)
-                               goto free_files;
-               }
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, len, (void **)&buf);
+       if (status != EFI_SUCCESS)
+               return status;
 
-               status = efi_file_size(fh, filename_16, (void **)&file->handle,
-                                      &file->size);
-               if (status != EFI_SUCCESS)
-                       goto close_handles;
+       str = skip_spaces(memcpy(buf, cmdline, len));
 
-               file_size_total += file->size;
-       }
+       while (*str) {
+               char *param, *val;
 
-       if (file_size_total) {
-               unsigned long addr;
+               str = next_arg(str, &param, &val);
 
-               /*
-                * Multiple files need to be at consecutive addresses in memory,
-                * so allocate enough memory for all the files.  This is used
-                * for loading multiple files.
-                */
-               status = efi_high_alloc(file_size_total, 0x1000, &file_addr,
-                                       max_addr);
-               if (status != EFI_SUCCESS) {
-                       pr_efi_err("Failed to alloc highmem for files\n");
-                       goto close_handles;
-               }
+               if (!strcmp(param, "nokaslr")) {
+                       efi_nokaslr = true;
+               } else if (!strcmp(param, "quiet")) {
+                       efi_quiet = true;
+               } else if (!strcmp(param, "noinitrd")) {
+                       efi_noinitrd = true;
+               } else if (!strcmp(param, "efi") && val) {
+                       efi_nochunk = parse_option_str(val, "nochunk");
+                       efi_novamap = parse_option_str(val, "novamap");
 
-               /* We've run out of free low memory. */
-               if (file_addr > max_addr) {
-                       pr_efi_err("We've run out of free low memory\n");
-                       status = EFI_INVALID_PARAMETER;
-                       goto free_file_total;
-               }
+                       efi_nosoftreserve = IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
+                                           parse_option_str(val, "nosoftreserve");
 
-               addr = file_addr;
-               for (j = 0; j < nr_files; j++) {
-                       unsigned long size;
-
-                       size = files[j].size;
-                       while (size) {
-                               unsigned long chunksize;
-
-                               if (IS_ENABLED(CONFIG_X86) && size > efi_chunk_size)
-                                       chunksize = efi_chunk_size;
-                               else
-                                       chunksize = size;
-
-                               status = efi_file_read(files[j].handle,
-                                                      &chunksize,
-                                                      (void *)addr);
-                               if (status != EFI_SUCCESS) {
-                                       pr_efi_err("Failed to read file\n");
-                                       goto free_file_total;
-                               }
-                               addr += chunksize;
-                               size -= chunksize;
-                       }
-
-                       efi_file_close(files[j].handle);
+                       if (parse_option_str(val, "disable_early_pci_dma"))
+                               efi_disable_pci_dma = true;
+                       if (parse_option_str(val, "no_disable_early_pci_dma"))
+                               efi_disable_pci_dma = false;
                }
-
-       }
-
-       efi_bs_call(free_pool, files);
-
-       *load_addr = file_addr;
-       *load_size = file_size_total;
-
-       return status;
-
-free_file_total:
-       efi_free(file_size_total, file_addr);
-
-close_handles:
-       for (k = j; k < i; k++)
-               efi_file_close(files[k].handle);
-free_files:
-       efi_bs_call(free_pool, files);
-fail:
-       *load_addr = 0;
-       *load_size = 0;
-
-       return status;
-}
-/*
- * Relocate a kernel image, either compressed or uncompressed.
- * In the ARM64 case, all kernel images are currently
- * uncompressed, and as such when we relocate it we need to
- * allocate additional space for the BSS segment. Any low
- * memory that this function should avoid needs to be
- * unavailable in the EFI memory map, as if the preferred
- * address is not available the lowest available address will
- * be used.
- */
-efi_status_t efi_relocate_kernel(unsigned long *image_addr,
-                                unsigned long image_size,
-                                unsigned long alloc_size,
-                                unsigned long preferred_addr,
-                                unsigned long alignment,
-                                unsigned long min_addr)
-{
-       unsigned long cur_image_addr;
-       unsigned long new_addr = 0;
-       efi_status_t status;
-       unsigned long nr_pages;
-       efi_physical_addr_t efi_addr = preferred_addr;
-
-       if (!image_addr || !image_size || !alloc_size)
-               return EFI_INVALID_PARAMETER;
-       if (alloc_size < image_size)
-               return EFI_INVALID_PARAMETER;
-
-       cur_image_addr = *image_addr;
-
-       /*
-        * The EFI firmware loader could have placed the kernel image
-        * anywhere in memory, but the kernel has restrictions on the
-        * max physical address it can run at.  Some architectures
-        * also have a prefered address, so first try to relocate
-        * to the preferred address.  If that fails, allocate as low
-        * as possible while respecting the required alignment.
-        */
-       nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
-       status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                            EFI_LOADER_DATA, nr_pages, &efi_addr);
-       new_addr = efi_addr;
-       /*
-        * If preferred address allocation failed allocate as low as
-        * possible.
-        */
-       if (status != EFI_SUCCESS) {
-               status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
-                                            min_addr);
        }
-       if (status != EFI_SUCCESS) {
-               pr_efi_err("Failed to allocate usable memory for kernel.\n");
-               return status;
-       }
-
-       /*
-        * We know source/dest won't overlap since both memory ranges
-        * have been allocated by UEFI, so we can safely use memcpy.
-        */
-       memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
-
-       /* Return the new address of the relocated image. */
-       *image_addr = new_addr;
-
-       return status;
+       efi_bs_call(free_pool, buf);
+       return EFI_SUCCESS;
 }
 
 /*
@@ -811,23 +160,19 @@ static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
        return dst;
 }
 
-#ifndef MAX_CMDLINE_ADDRESS
-#define MAX_CMDLINE_ADDRESS    ULONG_MAX
-#endif
-
 /*
  * Convert the unicode UEFI command line to ASCII to pass to kernel.
  * Size of memory allocated return in *cmd_line_len.
  * Returns NULL on error.
  */
 char *efi_convert_cmdline(efi_loaded_image_t *image,
-                         int *cmd_line_len)
+                         int *cmd_line_len, unsigned long max_addr)
 {
        const u16 *s2;
        u8 *s1 = NULL;
        unsigned long cmdline_addr = 0;
-       int load_options_chars = image->load_options_size / 2; /* UTF-16 */
-       const u16 *options = image->load_options;
+       int load_options_chars = efi_table_attr(image, load_options_size) / 2;
+       const u16 *options = efi_table_attr(image, load_options);
        int options_bytes = 0;  /* UTF-8 bytes */
        int options_chars = 0;  /* UTF-16 chars */
        efi_status_t status;
@@ -849,8 +194,7 @@ char *efi_convert_cmdline(efi_loaded_image_t *image,
 
        options_bytes++;        /* NUL termination */
 
-       status = efi_high_alloc(options_bytes, 0, &cmdline_addr,
-                               MAX_CMDLINE_ADDRESS);
+       status = efi_allocate_pages(options_bytes, &cmdline_addr, max_addr);
        if (status != EFI_SUCCESS)
                return NULL;
 
@@ -962,3 +306,89 @@ void efi_char16_printk(efi_char16_t *str)
        efi_call_proto(efi_table_attr(efi_system_table(), con_out),
                       output_string, str);
 }
+
+/*
+ * The LINUX_EFI_INITRD_MEDIA_GUID vendor media device path below provides a way
+ * for the firmware or bootloader to expose the initrd data directly to the stub
+ * via the trivial LoadFile2 protocol, which is defined in the UEFI spec, and is
+ * very easy to implement. It is a simple Linux initrd specific conduit between
+ * kernel and firmware, allowing us to put the EFI stub (being part of the
+ * kernel) in charge of where and when to load the initrd, while leaving it up
+ * to the firmware to decide whether it needs to expose its filesystem hierarchy
+ * via EFI protocols.
+ */
+static const struct {
+       struct efi_vendor_dev_path      vendor;
+       struct efi_generic_dev_path     end;
+} __packed initrd_dev_path = {
+       {
+               {
+                       EFI_DEV_MEDIA,
+                       EFI_DEV_MEDIA_VENDOR,
+                       sizeof(struct efi_vendor_dev_path),
+               },
+               LINUX_EFI_INITRD_MEDIA_GUID
+       }, {
+               EFI_DEV_END_PATH,
+               EFI_DEV_END_ENTIRE,
+               sizeof(struct efi_generic_dev_path)
+       }
+};
+
+/**
+ * efi_load_initrd_dev_path - load the initrd from the Linux initrd device path
+ * @load_addr: pointer to store the address where the initrd was loaded
+ * @load_size: pointer to store the size of the loaded initrd
+ * @max:       upper limit for the initrd memory allocation
+ * @return:    %EFI_SUCCESS if the initrd was loaded successfully, in which
+ *             case @load_addr and @load_size are assigned accordingly
+ *             %EFI_NOT_FOUND if no LoadFile2 protocol exists on the initrd
+ *             device path
+ *             %EFI_INVALID_PARAMETER if load_addr == NULL or load_size == NULL
+ *             %EFI_OUT_OF_RESOURCES if memory allocation failed
+ *             %EFI_LOAD_ERROR in all other cases
+ */
+efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
+                                     unsigned long *load_size,
+                                     unsigned long max)
+{
+       efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
+       efi_device_path_protocol_t *dp;
+       efi_load_file2_protocol_t *lf2;
+       unsigned long initrd_addr;
+       unsigned long initrd_size;
+       efi_handle_t handle;
+       efi_status_t status;
+
+       if (!load_addr || !load_size)
+               return EFI_INVALID_PARAMETER;
+
+       dp = (efi_device_path_protocol_t *)&initrd_dev_path;
+       status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid,
+                            (void **)&lf2);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_call_proto(lf2, load_file, dp, false, &initrd_size, NULL);
+       if (status != EFI_BUFFER_TOO_SMALL)
+               return EFI_LOAD_ERROR;
+
+       status = efi_allocate_pages(initrd_size, &initrd_addr, max);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       status = efi_call_proto(lf2, load_file, dp, false, &initrd_size,
+                               (void *)initrd_addr);
+       if (status != EFI_SUCCESS) {
+               efi_free(initrd_size, initrd_addr);
+               return EFI_LOAD_ERROR;
+       }
+
+       *load_addr = initrd_addr;
+       *load_size = initrd_size;
+       return EFI_SUCCESS;
+}
index c244b16..cc90a74 100644 (file)
@@ -31,7 +31,9 @@
 #define __efistub_global
 #endif
 
+extern bool __pure nochunk(void);
 extern bool __pure nokaslr(void);
+extern bool __pure noinitrd(void);
 extern bool __pure is_quiet(void);
 extern bool __pure novamap(void);
 
@@ -43,10 +45,549 @@ extern __pure efi_system_table_t  *efi_system_table(void);
 
 #define pr_efi_err(msg) efi_printk("EFI stub: ERROR: "msg)
 
-void efi_char16_printk(efi_char16_t *);
-void efi_char16_printk(efi_char16_t *);
+/* Helper macros for the usual case of using simple C variables: */
+#ifndef fdt_setprop_inplace_var
+#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
+       fdt_setprop_inplace((fdt), (node_offset), (name), &(var), sizeof(var))
+#endif
+
+#ifndef fdt_setprop_var
+#define fdt_setprop_var(fdt, node_offset, name, var) \
+       fdt_setprop((fdt), (node_offset), (name), &(var), sizeof(var))
+#endif
+
+#define get_efi_var(name, vendor, ...)                         \
+       efi_rt_call(get_variable, (efi_char16_t *)(name),       \
+                   (efi_guid_t *)(vendor), __VA_ARGS__)
+
+#define set_efi_var(name, vendor, ...)                         \
+       efi_rt_call(set_variable, (efi_char16_t *)(name),       \
+                   (efi_guid_t *)(vendor), __VA_ARGS__)
+
+#define efi_get_handle_at(array, idx)                                  \
+       (efi_is_native() ? (array)[idx]                                 \
+               : (efi_handle_t)(unsigned long)((u32 *)(array))[idx])
+
+#define efi_get_handle_num(size)                                       \
+       ((size) / (efi_is_native() ? sizeof(efi_handle_t) : sizeof(u32)))
+
+#define for_each_efi_handle(handle, array, size, i)                    \
+       for (i = 0;                                                     \
+            i < efi_get_handle_num(size) &&                            \
+               ((handle = efi_get_handle_at((array), i)) || true);     \
+            i++)
+
+/*
+ * Allocation types for calls to boottime->allocate_pages.
+ */
+#define EFI_ALLOCATE_ANY_PAGES         0
+#define EFI_ALLOCATE_MAX_ADDRESS       1
+#define EFI_ALLOCATE_ADDRESS           2
+#define EFI_MAX_ALLOCATE_TYPE          3
+
+/*
+ * The type of search to perform when calling boottime->locate_handle
+ */
+#define EFI_LOCATE_ALL_HANDLES                 0
+#define EFI_LOCATE_BY_REGISTER_NOTIFY          1
+#define EFI_LOCATE_BY_PROTOCOL                 2
+
+struct efi_boot_memmap {
+       efi_memory_desc_t       **map;
+       unsigned long           *map_size;
+       unsigned long           *desc_size;
+       u32                     *desc_ver;
+       unsigned long           *key_ptr;
+       unsigned long           *buff_size;
+};
+
+typedef struct efi_generic_dev_path efi_device_path_protocol_t;
+
+/*
+ * EFI Boot Services table
+ */
+union efi_boot_services {
+       struct {
+               efi_table_hdr_t hdr;
+               void *raise_tpl;
+               void *restore_tpl;
+               efi_status_t (__efiapi *allocate_pages)(int, int, unsigned long,
+                                                       efi_physical_addr_t *);
+               efi_status_t (__efiapi *free_pages)(efi_physical_addr_t,
+                                                   unsigned long);
+               efi_status_t (__efiapi *get_memory_map)(unsigned long *, void *,
+                                                       unsigned long *,
+                                                       unsigned long *, u32 *);
+               efi_status_t (__efiapi *allocate_pool)(int, unsigned long,
+                                                      void **);
+               efi_status_t (__efiapi *free_pool)(void *);
+               void *create_event;
+               void *set_timer;
+               void *wait_for_event;
+               void *signal_event;
+               void *close_event;
+               void *check_event;
+               void *install_protocol_interface;
+               void *reinstall_protocol_interface;
+               void *uninstall_protocol_interface;
+               efi_status_t (__efiapi *handle_protocol)(efi_handle_t,
+                                                        efi_guid_t *, void **);
+               void *__reserved;
+               void *register_protocol_notify;
+               efi_status_t (__efiapi *locate_handle)(int, efi_guid_t *,
+                                                      void *, unsigned long *,
+                                                      efi_handle_t *);
+               efi_status_t (__efiapi *locate_device_path)(efi_guid_t *,
+                                                           efi_device_path_protocol_t **,
+                                                           efi_handle_t *);
+               efi_status_t (__efiapi *install_configuration_table)(efi_guid_t *,
+                                                                    void *);
+               void *load_image;
+               void *start_image;
+               efi_status_t __noreturn (__efiapi *exit)(efi_handle_t,
+                                                        efi_status_t,
+                                                        unsigned long,
+                                                        efi_char16_t *);
+               void *unload_image;
+               efi_status_t (__efiapi *exit_boot_services)(efi_handle_t,
+                                                           unsigned long);
+               void *get_next_monotonic_count;
+               void *stall;
+               void *set_watchdog_timer;
+               void *connect_controller;
+               efi_status_t (__efiapi *disconnect_controller)(efi_handle_t,
+                                                              efi_handle_t,
+                                                              efi_handle_t);
+               void *open_protocol;
+               void *close_protocol;
+               void *open_protocol_information;
+               void *protocols_per_handle;
+               void *locate_handle_buffer;
+               efi_status_t (__efiapi *locate_protocol)(efi_guid_t *, void *,
+                                                        void **);
+               void *install_multiple_protocol_interfaces;
+               void *uninstall_multiple_protocol_interfaces;
+               void *calculate_crc32;
+               void *copy_mem;
+               void *set_mem;
+               void *create_event_ex;
+       };
+       struct {
+               efi_table_hdr_t hdr;
+               u32 raise_tpl;
+               u32 restore_tpl;
+               u32 allocate_pages;
+               u32 free_pages;
+               u32 get_memory_map;
+               u32 allocate_pool;
+               u32 free_pool;
+               u32 create_event;
+               u32 set_timer;
+               u32 wait_for_event;
+               u32 signal_event;
+               u32 close_event;
+               u32 check_event;
+               u32 install_protocol_interface;
+               u32 reinstall_protocol_interface;
+               u32 uninstall_protocol_interface;
+               u32 handle_protocol;
+               u32 __reserved;
+               u32 register_protocol_notify;
+               u32 locate_handle;
+               u32 locate_device_path;
+               u32 install_configuration_table;
+               u32 load_image;
+               u32 start_image;
+               u32 exit;
+               u32 unload_image;
+               u32 exit_boot_services;
+               u32 get_next_monotonic_count;
+               u32 stall;
+               u32 set_watchdog_timer;
+               u32 connect_controller;
+               u32 disconnect_controller;
+               u32 open_protocol;
+               u32 close_protocol;
+               u32 open_protocol_information;
+               u32 protocols_per_handle;
+               u32 locate_handle_buffer;
+               u32 locate_protocol;
+               u32 install_multiple_protocol_interfaces;
+               u32 uninstall_multiple_protocol_interfaces;
+               u32 calculate_crc32;
+               u32 copy_mem;
+               u32 set_mem;
+               u32 create_event_ex;
+       } mixed_mode;
+};
+
+typedef union efi_uga_draw_protocol efi_uga_draw_protocol_t;
+
+union efi_uga_draw_protocol {
+       struct {
+               efi_status_t (__efiapi *get_mode)(efi_uga_draw_protocol_t *,
+                                                 u32*, u32*, u32*, u32*);
+               void *set_mode;
+               void *blt;
+       };
+       struct {
+               u32 get_mode;
+               u32 set_mode;
+               u32 blt;
+       } mixed_mode;
+};
+
+union efi_simple_text_output_protocol {
+       struct {
+               void *reset;
+               efi_status_t (__efiapi *output_string)(efi_simple_text_output_protocol_t *,
+                                                      efi_char16_t *);
+               void *test_string;
+       };
+       struct {
+               u32 reset;
+               u32 output_string;
+               u32 test_string;
+       } mixed_mode;
+};
+
+#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR              0
+#define PIXEL_BGR_RESERVED_8BIT_PER_COLOR              1
+#define PIXEL_BIT_MASK                                 2
+#define PIXEL_BLT_ONLY                                 3
+#define PIXEL_FORMAT_MAX                               4
+
+typedef struct {
+       u32 red_mask;
+       u32 green_mask;
+       u32 blue_mask;
+       u32 reserved_mask;
+} efi_pixel_bitmask_t;
+
+typedef struct {
+       u32 version;
+       u32 horizontal_resolution;
+       u32 vertical_resolution;
+       int pixel_format;
+       efi_pixel_bitmask_t pixel_information;
+       u32 pixels_per_scan_line;
+} efi_graphics_output_mode_info_t;
+
+typedef union efi_graphics_output_protocol_mode efi_graphics_output_protocol_mode_t;
+
+union efi_graphics_output_protocol_mode {
+       struct {
+               u32 max_mode;
+               u32 mode;
+               efi_graphics_output_mode_info_t *info;
+               unsigned long size_of_info;
+               efi_physical_addr_t frame_buffer_base;
+               unsigned long frame_buffer_size;
+       };
+       struct {
+               u32 max_mode;
+               u32 mode;
+               u32 info;
+               u32 size_of_info;
+               u64 frame_buffer_base;
+               u32 frame_buffer_size;
+       } mixed_mode;
+};
+
+typedef union efi_graphics_output_protocol efi_graphics_output_protocol_t;
+
+union efi_graphics_output_protocol {
+       struct {
+               void *query_mode;
+               void *set_mode;
+               void *blt;
+               efi_graphics_output_protocol_mode_t *mode;
+       };
+       struct {
+               u32 query_mode;
+               u32 set_mode;
+               u32 blt;
+               u32 mode;
+       } mixed_mode;
+};
+
+typedef union {
+       struct {
+               u32                     revision;
+               efi_handle_t            parent_handle;
+               efi_system_table_t      *system_table;
+               efi_handle_t            device_handle;
+               void                    *file_path;
+               void                    *reserved;
+               u32                     load_options_size;
+               void                    *load_options;
+               void                    *image_base;
+               __aligned_u64           image_size;
+               unsigned int            image_code_type;
+               unsigned int            image_data_type;
+               efi_status_t            (__efiapi *unload)(efi_handle_t image_handle);
+       };
+       struct {
+               u32             revision;
+               u32             parent_handle;
+               u32             system_table;
+               u32             device_handle;
+               u32             file_path;
+               u32             reserved;
+               u32             load_options_size;
+               u32             load_options;
+               u32             image_base;
+               __aligned_u64   image_size;
+               u32             image_code_type;
+               u32             image_data_type;
+               u32             unload;
+       } mixed_mode;
+} efi_loaded_image_t;
+
+typedef struct {
+       u64                     size;
+       u64                     file_size;
+       u64                     phys_size;
+       efi_time_t              create_time;
+       efi_time_t              last_access_time;
+       efi_time_t              modification_time;
+       __aligned_u64           attribute;
+       efi_char16_t            filename[];
+} efi_file_info_t;
+
+typedef struct efi_file_protocol efi_file_protocol_t;
+
+struct efi_file_protocol {
+       u64             revision;
+       efi_status_t    (__efiapi *open)        (efi_file_protocol_t *,
+                                                efi_file_protocol_t **,
+                                                efi_char16_t *, u64, u64);
+       efi_status_t    (__efiapi *close)       (efi_file_protocol_t *);
+       efi_status_t    (__efiapi *delete)      (efi_file_protocol_t *);
+       efi_status_t    (__efiapi *read)        (efi_file_protocol_t *,
+                                                unsigned long *, void *);
+       efi_status_t    (__efiapi *write)       (efi_file_protocol_t *,
+                                                unsigned long, void *);
+       efi_status_t    (__efiapi *get_position)(efi_file_protocol_t *, u64 *);
+       efi_status_t    (__efiapi *set_position)(efi_file_protocol_t *, u64);
+       efi_status_t    (__efiapi *get_info)    (efi_file_protocol_t *,
+                                                efi_guid_t *, unsigned long *,
+                                                void *);
+       efi_status_t    (__efiapi *set_info)    (efi_file_protocol_t *,
+                                                efi_guid_t *, unsigned long,
+                                                void *);
+       efi_status_t    (__efiapi *flush)       (efi_file_protocol_t *);
+};
 
-unsigned long get_dram_base(void);
+typedef struct efi_simple_file_system_protocol efi_simple_file_system_protocol_t;
+
+struct efi_simple_file_system_protocol {
+       u64     revision;
+       int     (__efiapi *open_volume)(efi_simple_file_system_protocol_t *,
+                                       efi_file_protocol_t **);
+};
+
+#define EFI_FILE_MODE_READ     0x0000000000000001
+#define EFI_FILE_MODE_WRITE    0x0000000000000002
+#define EFI_FILE_MODE_CREATE   0x8000000000000000
+
+typedef enum {
+       EfiPciIoWidthUint8,
+       EfiPciIoWidthUint16,
+       EfiPciIoWidthUint32,
+       EfiPciIoWidthUint64,
+       EfiPciIoWidthFifoUint8,
+       EfiPciIoWidthFifoUint16,
+       EfiPciIoWidthFifoUint32,
+       EfiPciIoWidthFifoUint64,
+       EfiPciIoWidthFillUint8,
+       EfiPciIoWidthFillUint16,
+       EfiPciIoWidthFillUint32,
+       EfiPciIoWidthFillUint64,
+       EfiPciIoWidthMaximum
+} EFI_PCI_IO_PROTOCOL_WIDTH;
+
+typedef enum {
+       EfiPciIoAttributeOperationGet,
+       EfiPciIoAttributeOperationSet,
+       EfiPciIoAttributeOperationEnable,
+       EfiPciIoAttributeOperationDisable,
+       EfiPciIoAttributeOperationSupported,
+    EfiPciIoAttributeOperationMaximum
+} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
+
+typedef struct {
+       u32 read;
+       u32 write;
+} efi_pci_io_protocol_access_32_t;
+
+typedef union efi_pci_io_protocol efi_pci_io_protocol_t;
+
+typedef
+efi_status_t (__efiapi *efi_pci_io_protocol_cfg_t)(efi_pci_io_protocol_t *,
+                                                  EFI_PCI_IO_PROTOCOL_WIDTH,
+                                                  u32 offset,
+                                                  unsigned long count,
+                                                  void *buffer);
+
+typedef struct {
+       void *read;
+       void *write;
+} efi_pci_io_protocol_access_t;
+
+typedef struct {
+       efi_pci_io_protocol_cfg_t read;
+       efi_pci_io_protocol_cfg_t write;
+} efi_pci_io_protocol_config_access_t;
+
+union efi_pci_io_protocol {
+       struct {
+               void *poll_mem;
+               void *poll_io;
+               efi_pci_io_protocol_access_t mem;
+               efi_pci_io_protocol_access_t io;
+               efi_pci_io_protocol_config_access_t pci;
+               void *copy_mem;
+               void *map;
+               void *unmap;
+               void *allocate_buffer;
+               void *free_buffer;
+               void *flush;
+               efi_status_t (__efiapi *get_location)(efi_pci_io_protocol_t *,
+                                                     unsigned long *segment_nr,
+                                                     unsigned long *bus_nr,
+                                                     unsigned long *device_nr,
+                                                     unsigned long *func_nr);
+               void *attributes;
+               void *get_bar_attributes;
+               void *set_bar_attributes;
+               uint64_t romsize;
+               void *romimage;
+       };
+       struct {
+               u32 poll_mem;
+               u32 poll_io;
+               efi_pci_io_protocol_access_32_t mem;
+               efi_pci_io_protocol_access_32_t io;
+               efi_pci_io_protocol_access_32_t pci;
+               u32 copy_mem;
+               u32 map;
+               u32 unmap;
+               u32 allocate_buffer;
+               u32 free_buffer;
+               u32 flush;
+               u32 get_location;
+               u32 attributes;
+               u32 get_bar_attributes;
+               u32 set_bar_attributes;
+               u64 romsize;
+               u32 romimage;
+       } mixed_mode;
+};
+
+#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004
+#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010
+#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
+#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
+#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200
+#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800
+#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000
+#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000
+#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
+#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000
+#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000
+#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000
+
+struct efi_dev_path;
+
+typedef union apple_properties_protocol apple_properties_protocol_t;
+
+union apple_properties_protocol {
+       struct {
+               unsigned long version;
+               efi_status_t (__efiapi *get)(apple_properties_protocol_t *,
+                                            struct efi_dev_path *,
+                                            efi_char16_t *, void *, u32 *);
+               efi_status_t (__efiapi *set)(apple_properties_protocol_t *,
+                                            struct efi_dev_path *,
+                                            efi_char16_t *, void *, u32);
+               efi_status_t (__efiapi *del)(apple_properties_protocol_t *,
+                                            struct efi_dev_path *,
+                                            efi_char16_t *);
+               efi_status_t (__efiapi *get_all)(apple_properties_protocol_t *,
+                                                void *buffer, u32 *);
+       };
+       struct {
+               u32 version;
+               u32 get;
+               u32 set;
+               u32 del;
+               u32 get_all;
+       } mixed_mode;
+};
+
+typedef u32 efi_tcg2_event_log_format;
+
+typedef union efi_tcg2_protocol efi_tcg2_protocol_t;
+
+union efi_tcg2_protocol {
+       struct {
+               void *get_capability;
+               efi_status_t (__efiapi *get_event_log)(efi_handle_t,
+                                                      efi_tcg2_event_log_format,
+                                                      efi_physical_addr_t *,
+                                                      efi_physical_addr_t *,
+                                                      efi_bool_t *);
+               void *hash_log_extend_event;
+               void *submit_command;
+               void *get_active_pcr_banks;
+               void *set_active_pcr_banks;
+               void *get_result_of_set_active_pcr_banks;
+       };
+       struct {
+               u32 get_capability;
+               u32 get_event_log;
+               u32 hash_log_extend_event;
+               u32 submit_command;
+               u32 get_active_pcr_banks;
+               u32 set_active_pcr_banks;
+               u32 get_result_of_set_active_pcr_banks;
+       } mixed_mode;
+};
+
+typedef union efi_load_file_protocol efi_load_file_protocol_t;
+typedef union efi_load_file_protocol efi_load_file2_protocol_t;
+
+union efi_load_file_protocol {
+       struct {
+               efi_status_t (__efiapi *load_file)(efi_load_file_protocol_t *,
+                                                  efi_device_path_protocol_t *,
+                                                  bool, unsigned long *, void *);
+       };
+       struct {
+               u32 load_file;
+       } mixed_mode;
+};
+
+void efi_pci_disable_bridge_busmaster(void);
+
+typedef efi_status_t (*efi_exit_boot_map_processing)(
+       struct efi_boot_memmap *map,
+       void *priv);
+
+efi_status_t efi_exit_boot_services(void *handle,
+                                   struct efi_boot_memmap *map,
+                                   void *priv,
+                                   efi_exit_boot_map_processing priv_func);
+
+void efi_char16_printk(efi_char16_t *);
 
 efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
                                            unsigned long *new_fdt_addr,
@@ -71,23 +612,57 @@ efi_status_t check_platform_features(void);
 
 void *get_efi_config_table(efi_guid_t guid);
 
-/* Helper macros for the usual case of using simple C variables: */
-#ifndef fdt_setprop_inplace_var
-#define fdt_setprop_inplace_var(fdt, node_offset, name, var) \
-       fdt_setprop_inplace((fdt), (node_offset), (name), &(var), sizeof(var))
-#endif
+void efi_printk(char *str);
 
-#ifndef fdt_setprop_var
-#define fdt_setprop_var(fdt, node_offset, name, var) \
-       fdt_setprop((fdt), (node_offset), (name), &(var), sizeof(var))
-#endif
+void efi_free(unsigned long size, unsigned long addr);
 
-#define get_efi_var(name, vendor, ...)                         \
-       efi_rt_call(get_variable, (efi_char16_t *)(name),       \
-                   (efi_guid_t *)(vendor), __VA_ARGS__)
+char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len,
+                         unsigned long max_addr);
 
-#define set_efi_var(name, vendor, ...)                         \
-       efi_rt_call(set_variable, (efi_char16_t *)(name),       \
-                   (efi_guid_t *)(vendor), __VA_ARGS__)
+efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
+
+efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
+                                unsigned long *addr, unsigned long min);
+
+static inline
+efi_status_t efi_low_alloc(unsigned long size, unsigned long align,
+                          unsigned long *addr)
+{
+       /*
+        * Don't allocate at 0x0. It will confuse code that
+        * checks pointers against NULL. Skip the first 8
+        * bytes so we start at a nice even number.
+        */
+       return efi_low_alloc_above(size, align, addr, 0x8);
+}
+
+efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
+                               unsigned long max);
+
+efi_status_t efi_relocate_kernel(unsigned long *image_addr,
+                                unsigned long image_size,
+                                unsigned long alloc_size,
+                                unsigned long preferred_addr,
+                                unsigned long alignment,
+                                unsigned long min_addr);
+
+efi_status_t efi_parse_options(char const *cmdline);
+
+efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
+                          unsigned long size);
+
+efi_status_t efi_load_dtb(efi_loaded_image_t *image,
+                         unsigned long *load_addr,
+                         unsigned long *load_size);
+
+efi_status_t efi_load_initrd(efi_loaded_image_t *image,
+                            unsigned long *load_addr,
+                            unsigned long *load_size,
+                            unsigned long soft_limit,
+                            unsigned long hard_limit);
+
+efi_status_t efi_load_initrd_dev_path(unsigned long *load_addr,
+                                     unsigned long *load_size,
+                                     unsigned long max);
 
 #endif
index 0a91e52..46cffac 100644 (file)
@@ -199,10 +199,6 @@ static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
        return EFI_SUCCESS;
 }
 
-#ifndef EFI_FDT_ALIGN
-# define EFI_FDT_ALIGN EFI_PAGE_SIZE
-#endif
-
 struct exit_boot_struct {
        efi_memory_desc_t       *runtime_map;
        int                     *runtime_entry_count;
@@ -281,8 +277,7 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
        pr_efi("Exiting boot services and installing virtual address map...\n");
 
        map.map = &memory_map;
-       status = efi_high_alloc(MAX_FDT_SIZE, EFI_FDT_ALIGN,
-                               new_fdt_addr, max_addr);
+       status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, max_addr);
        if (status != EFI_SUCCESS) {
                pr_efi_err("Unable to allocate memory for new device tree.\n");
                goto fail;
diff --git a/drivers/firmware/efi/libstub/file.c b/drivers/firmware/efi/libstub/file.c
new file mode 100644 (file)
index 0000000..d4c7e5f
--- /dev/null
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Helper functions used by the EFI stub on multiple
+ * architectures. This should be #included by the EFI stub
+ * implementation files.
+ *
+ * Copyright 2011 Intel Corporation; author Matt Fleming
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+#define MAX_FILENAME_SIZE      256
+
+/*
+ * Some firmware implementations have problems reading files in one go.
+ * A read chunk size of 1MB seems to work for most platforms.
+ *
+ * Unfortunately, reading files in chunks triggers *other* bugs on some
+ * platforms, so we provide a way to disable this workaround, which can
+ * be done by passing "efi=nochunk" on the EFI boot stub command line.
+ *
+ * If you experience issues with initrd images being corrupt it's worth
+ * trying efi=nochunk, but chunking is enabled by default on x86 because
+ * there are far more machines that require the workaround than those that
+ * break with it enabled.
+ */
+#define EFI_READ_CHUNK_SIZE    SZ_1M
+
+static efi_status_t efi_open_file(efi_file_protocol_t *volume,
+                                 efi_char16_t *filename_16,
+                                 efi_file_protocol_t **handle,
+                                 unsigned long *file_size)
+{
+       struct {
+               efi_file_info_t info;
+               efi_char16_t    filename[MAX_FILENAME_SIZE];
+       } finfo;
+       efi_guid_t info_guid = EFI_FILE_INFO_ID;
+       efi_file_protocol_t *fh;
+       unsigned long info_sz;
+       efi_status_t status;
+
+       status = volume->open(volume, &fh, filename_16, EFI_FILE_MODE_READ, 0);
+       if (status != EFI_SUCCESS) {
+               pr_efi_err("Failed to open file: ");
+               efi_char16_printk(filename_16);
+               efi_printk("\n");
+               return status;
+       }
+
+       info_sz = sizeof(finfo);
+       status = fh->get_info(fh, &info_guid, &info_sz, &finfo);
+       if (status != EFI_SUCCESS) {
+               pr_efi_err("Failed to get file info\n");
+               fh->close(fh);
+               return status;
+       }
+
+       *handle = fh;
+       *file_size = finfo.info.file_size;
+       return EFI_SUCCESS;
+}
+
+static efi_status_t efi_open_volume(efi_loaded_image_t *image,
+                                   efi_file_protocol_t **fh)
+{
+       efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
+       efi_simple_file_system_protocol_t *io;
+       efi_status_t status;
+
+       status = efi_bs_call(handle_protocol, image->device_handle, &fs_proto,
+                            (void **)&io);
+       if (status != EFI_SUCCESS) {
+               pr_efi_err("Failed to handle fs_proto\n");
+               return status;
+       }
+
+       status = io->open_volume(io, fh);
+       if (status != EFI_SUCCESS)
+               pr_efi_err("Failed to open volume\n");
+
+       return status;
+}
+
+static int find_file_option(const efi_char16_t *cmdline, int cmdline_len,
+                           const efi_char16_t *prefix, int prefix_size,
+                           efi_char16_t *result, int result_len)
+{
+       int prefix_len = prefix_size / 2;
+       bool found = false;
+       int i;
+
+       for (i = prefix_len; i < cmdline_len; i++) {
+               if (!memcmp(&cmdline[i - prefix_len], prefix, prefix_size)) {
+                       found = true;
+                       break;
+               }
+       }
+
+       if (!found)
+               return 0;
+
+       while (--result_len > 0 && i < cmdline_len) {
+               if (cmdline[i] == L'\0' ||
+                   cmdline[i] == L'\n' ||
+                   cmdline[i] == L' ')
+                       break;
+               *result++ = cmdline[i++];
+       }
+       *result = L'\0';
+       return i;
+}
+
+/*
+ * Check the cmdline for a LILO-style file= arguments.
+ *
+ * We only support loading a file from the same filesystem as
+ * the kernel image.
+ */
+static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
+                                        const efi_char16_t *optstr,
+                                        int optstr_size,
+                                        unsigned long soft_limit,
+                                        unsigned long hard_limit,
+                                        unsigned long *load_addr,
+                                        unsigned long *load_size)
+{
+       const efi_char16_t *cmdline = image->load_options;
+       int cmdline_len = image->load_options_size / 2;
+       unsigned long efi_chunk_size = ULONG_MAX;
+       efi_file_protocol_t *volume = NULL;
+       efi_file_protocol_t *file;
+       unsigned long alloc_addr;
+       unsigned long alloc_size;
+       efi_status_t status;
+       int offset;
+
+       if (!load_addr || !load_size)
+               return EFI_INVALID_PARAMETER;
+
+       if (IS_ENABLED(CONFIG_X86) && !nochunk())
+               efi_chunk_size = EFI_READ_CHUNK_SIZE;
+
+       alloc_addr = alloc_size = 0;
+       do {
+               efi_char16_t filename[MAX_FILENAME_SIZE];
+               unsigned long size;
+               void *addr;
+
+               offset = find_file_option(cmdline, cmdline_len,
+                                         optstr, optstr_size,
+                                         filename, ARRAY_SIZE(filename));
+
+               if (!offset)
+                       break;
+
+               cmdline += offset;
+               cmdline_len -= offset;
+
+               if (!volume) {
+                       status = efi_open_volume(image, &volume);
+                       if (status != EFI_SUCCESS)
+                               return status;
+               }
+
+               status = efi_open_file(volume, filename, &file, &size);
+               if (status != EFI_SUCCESS)
+                       goto err_close_volume;
+
+               /*
+                * Check whether the existing allocation can contain the next
+                * file. This condition will also trigger naturally during the
+                * first (and typically only) iteration of the loop, given that
+                * alloc_size == 0 in that case.
+                */
+               if (round_up(alloc_size + size, EFI_ALLOC_ALIGN) >
+                   round_up(alloc_size, EFI_ALLOC_ALIGN)) {
+                       unsigned long old_addr = alloc_addr;
+
+                       status = EFI_OUT_OF_RESOURCES;
+                       if (soft_limit < hard_limit)
+                               status = efi_allocate_pages(alloc_size + size,
+                                                           &alloc_addr,
+                                                           soft_limit);
+                       if (status == EFI_OUT_OF_RESOURCES)
+                               status = efi_allocate_pages(alloc_size + size,
+                                                           &alloc_addr,
+                                                           hard_limit);
+                       if (status != EFI_SUCCESS) {
+                               pr_efi_err("Failed to allocate memory for files\n");
+                               goto err_close_file;
+                       }
+
+                       if (old_addr != 0) {
+                               /*
+                                * This is not the first time we've gone
+                                * around this loop, and so we are loading
+                                * multiple files that need to be concatenated
+                                * and returned in a single buffer.
+                                */
+                               memcpy((void *)alloc_addr, (void *)old_addr, alloc_size);
+                               efi_free(alloc_size, old_addr);
+                       }
+               }
+
+               addr = (void *)alloc_addr + alloc_size;
+               alloc_size += size;
+
+               while (size) {
+                       unsigned long chunksize = min(size, efi_chunk_size);
+
+                       status = file->read(file, &chunksize, addr);
+                       if (status != EFI_SUCCESS) {
+                               pr_efi_err("Failed to read file\n");
+                               goto err_close_file;
+                       }
+                       addr += chunksize;
+                       size -= chunksize;
+               }
+               file->close(file);
+       } while (offset > 0);
+
+       *load_addr = alloc_addr;
+       *load_size = alloc_size;
+
+       if (volume)
+               volume->close(volume);
+       return EFI_SUCCESS;
+
+err_close_file:
+       file->close(file);
+
+err_close_volume:
+       volume->close(volume);
+       efi_free(alloc_size, alloc_addr);
+       return status;
+}
+
+efi_status_t efi_load_dtb(efi_loaded_image_t *image,
+                         unsigned long *load_addr,
+                         unsigned long *load_size)
+{
+       return handle_cmdline_files(image, L"dtb=", sizeof(L"dtb=") - 2,
+                                   ULONG_MAX, ULONG_MAX, load_addr, load_size);
+}
+
+efi_status_t efi_load_initrd(efi_loaded_image_t *image,
+                            unsigned long *load_addr,
+                            unsigned long *load_size,
+                            unsigned long soft_limit,
+                            unsigned long hard_limit)
+{
+       return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
+                                   soft_limit, hard_limit, load_addr, load_size);
+}
diff --git a/drivers/firmware/efi/libstub/hidden.h b/drivers/firmware/efi/libstub/hidden.h
new file mode 100644 (file)
index 0000000..3493b04
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * To prevent the compiler from emitting GOT-indirected (and thus absolute)
+ * references to any global symbols, override their visibility as 'hidden'
+ */
+#pragma GCC visibility push(hidden)
diff --git a/drivers/firmware/efi/libstub/mem.c b/drivers/firmware/efi/libstub/mem.c
new file mode 100644 (file)
index 0000000..869a79c
--- /dev/null
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+#define EFI_MMAP_NR_SLACK_SLOTS        8
+
+static inline bool mmap_has_headroom(unsigned long buff_size,
+                                    unsigned long map_size,
+                                    unsigned long desc_size)
+{
+       unsigned long slack = buff_size - map_size;
+
+       return slack / desc_size >= EFI_MMAP_NR_SLACK_SLOTS;
+}
+
+/**
+ * efi_get_memory_map() - get memory map
+ * @map:       on return pointer to memory map
+ *
+ * Retrieve the UEFI memory map. The allocated memory leaves room for
+ * up to EFI_MMAP_NR_SLACK_SLOTS additional memory map entries.
+ *
+ * Return:     status code
+ */
+efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
+{
+       efi_memory_desc_t *m = NULL;
+       efi_status_t status;
+       unsigned long key;
+       u32 desc_version;
+
+       *map->desc_size =       sizeof(*m);
+       *map->map_size =        *map->desc_size * 32;
+       *map->buff_size =       *map->map_size;
+again:
+       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
+                            *map->map_size, (void **)&m);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       *map->desc_size = 0;
+       key = 0;
+       status = efi_bs_call(get_memory_map, map->map_size, m,
+                            &key, map->desc_size, &desc_version);
+       if (status == EFI_BUFFER_TOO_SMALL ||
+           !mmap_has_headroom(*map->buff_size, *map->map_size,
+                              *map->desc_size)) {
+               efi_bs_call(free_pool, m);
+               /*
+                * Make sure there is some entries of headroom so that the
+                * buffer can be reused for a new map after allocations are
+                * no longer permitted.  Its unlikely that the map will grow to
+                * exceed this headroom once we are ready to trigger
+                * ExitBootServices()
+                */
+               *map->map_size += *map->desc_size * EFI_MMAP_NR_SLACK_SLOTS;
+               *map->buff_size = *map->map_size;
+               goto again;
+       }
+
+       if (status == EFI_SUCCESS) {
+               if (map->key_ptr)
+                       *map->key_ptr = key;
+               if (map->desc_ver)
+                       *map->desc_ver = desc_version;
+       } else {
+               efi_bs_call(free_pool, m);
+       }
+
+fail:
+       *map->map = m;
+       return status;
+}
+
+/**
+ * efi_allocate_pages() - Allocate memory pages
+ * @size:      minimum number of bytes to allocate
+ * @addr:      On return the address of the first allocated page. The first
+ *             allocated page has alignment EFI_ALLOC_ALIGN which is an
+ *             architecture dependent multiple of the page size.
+ * @max:       the address that the last allocated memory page shall not
+ *             exceed
+ *
+ * Allocate pages as EFI_LOADER_DATA. The allocated pages are aligned according
+ * to EFI_ALLOC_ALIGN. The last allocated page will not exceed the address
+ * given by @max.
+ *
+ * Return:     status code
+ */
+efi_status_t efi_allocate_pages(unsigned long size, unsigned long *addr,
+                               unsigned long max)
+{
+       efi_physical_addr_t alloc_addr = ALIGN_DOWN(max + 1, EFI_ALLOC_ALIGN) - 1;
+       int slack = EFI_ALLOC_ALIGN / EFI_PAGE_SIZE - 1;
+       efi_status_t status;
+
+       size = round_up(size, EFI_ALLOC_ALIGN);
+       status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS,
+                            EFI_LOADER_DATA, size / EFI_PAGE_SIZE + slack,
+                            &alloc_addr);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       *addr = ALIGN((unsigned long)alloc_addr, EFI_ALLOC_ALIGN);
+
+       if (slack > 0) {
+               int l = (alloc_addr % EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
+
+               if (l) {
+                       efi_bs_call(free_pages, alloc_addr, slack - l + 1);
+                       slack = l - 1;
+               }
+               if (slack)
+                       efi_bs_call(free_pages, *addr + size, slack);
+       }
+       return EFI_SUCCESS;
+}
+/**
+ * efi_low_alloc_above() - allocate pages at or above given address
+ * @size:      size of the memory area to allocate
+ * @align:     minimum alignment of the allocated memory area. It should
+ *             a power of two.
+ * @addr:      on exit the address of the allocated memory
+ * @min:       minimum address to used for the memory allocation
+ *
+ * Allocate at the lowest possible address that is not below @min as
+ * EFI_LOADER_DATA. The allocated pages are aligned according to @align but at
+ * least EFI_ALLOC_ALIGN. The first allocated page will not below the address
+ * given by @min.
+ *
+ * Return:     status code
+ */
+efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
+                                unsigned long *addr, unsigned long min)
+{
+       unsigned long map_size, desc_size, buff_size;
+       efi_memory_desc_t *map;
+       efi_status_t status;
+       unsigned long nr_pages;
+       int i;
+       struct efi_boot_memmap boot_map;
+
+       boot_map.map            = &map;
+       boot_map.map_size       = &map_size;
+       boot_map.desc_size      = &desc_size;
+       boot_map.desc_ver       = NULL;
+       boot_map.key_ptr        = NULL;
+       boot_map.buff_size      = &buff_size;
+
+       status = efi_get_memory_map(&boot_map);
+       if (status != EFI_SUCCESS)
+               goto fail;
+
+       /*
+        * Enforce minimum alignment that EFI or Linux requires when
+        * requesting a specific address.  We are doing page-based (or
+        * larger) allocations, and both the address and size must meet
+        * alignment constraints.
+        */
+       if (align < EFI_ALLOC_ALIGN)
+               align = EFI_ALLOC_ALIGN;
+
+       size = round_up(size, EFI_ALLOC_ALIGN);
+       nr_pages = size / EFI_PAGE_SIZE;
+       for (i = 0; i < map_size / desc_size; i++) {
+               efi_memory_desc_t *desc;
+               unsigned long m = (unsigned long)map;
+               u64 start, end;
+
+               desc = efi_early_memdesc_ptr(m, desc_size, i);
+
+               if (desc->type != EFI_CONVENTIONAL_MEMORY)
+                       continue;
+
+               if (efi_soft_reserve_enabled() &&
+                   (desc->attribute & EFI_MEMORY_SP))
+                       continue;
+
+               if (desc->num_pages < nr_pages)
+                       continue;
+
+               start = desc->phys_addr;
+               end = start + desc->num_pages * EFI_PAGE_SIZE;
+
+               if (start < min)
+                       start = min;
+
+               start = round_up(start, align);
+               if ((start + size) > end)
+                       continue;
+
+               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
+                                    EFI_LOADER_DATA, nr_pages, &start);
+               if (status == EFI_SUCCESS) {
+                       *addr = start;
+                       break;
+               }
+       }
+
+       if (i == map_size / desc_size)
+               status = EFI_NOT_FOUND;
+
+       efi_bs_call(free_pool, map);
+fail:
+       return status;
+}
+
+/**
+ * efi_free() - free memory pages
+ * @size:      size of the memory area to free in bytes
+ * @addr:      start of the memory area to free (must be EFI_PAGE_SIZE
+ *             aligned)
+ *
+ * @size is rounded up to a multiple of EFI_ALLOC_ALIGN which is an
+ * architecture specific multiple of EFI_PAGE_SIZE. So this function should
+ * only be used to return pages allocated with efi_allocate_pages() or
+ * efi_low_alloc_above().
+ */
+void efi_free(unsigned long size, unsigned long addr)
+{
+       unsigned long nr_pages;
+
+       if (!size)
+               return;
+
+       nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
+       efi_bs_call(free_pages, addr, nr_pages);
+}
+
+/**
+ * efi_relocate_kernel() - copy memory area
+ * @image_addr:                pointer to address of memory area to copy
+ * @image_size:                size of memory area to copy
+ * @alloc_size:                minimum size of memory to allocate, must be greater or
+ *                     equal to image_size
+ * @preferred_addr:    preferred target address
+ * @alignment:         minimum alignment of the allocated memory area. It
+ *                     should be a power of two.
+ * @min_addr:          minimum target address
+ *
+ * Copy a memory area to a newly allocated memory area aligned according
+ * to @alignment but at least EFI_ALLOC_ALIGN. If the preferred address
+ * is not available, the allocated address will not be below @min_addr.
+ * On exit, @image_addr is updated to the target copy address that was used.
+ *
+ * This function is used to copy the Linux kernel verbatim. It does not apply
+ * any relocation changes.
+ *
+ * Return:             status code
+ */
+efi_status_t efi_relocate_kernel(unsigned long *image_addr,
+                                unsigned long image_size,
+                                unsigned long alloc_size,
+                                unsigned long preferred_addr,
+                                unsigned long alignment,
+                                unsigned long min_addr)
+{
+       unsigned long cur_image_addr;
+       unsigned long new_addr = 0;
+       efi_status_t status;
+       unsigned long nr_pages;
+       efi_physical_addr_t efi_addr = preferred_addr;
+
+       if (!image_addr || !image_size || !alloc_size)
+               return EFI_INVALID_PARAMETER;
+       if (alloc_size < image_size)
+               return EFI_INVALID_PARAMETER;
+
+       cur_image_addr = *image_addr;
+
+       /*
+        * The EFI firmware loader could have placed the kernel image
+        * anywhere in memory, but the kernel has restrictions on the
+        * max physical address it can run at.  Some architectures
+        * also have a prefered address, so first try to relocate
+        * to the preferred address.  If that fails, allocate as low
+        * as possible while respecting the required alignment.
+        */
+       nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
+       status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
+                            EFI_LOADER_DATA, nr_pages, &efi_addr);
+       new_addr = efi_addr;
+       /*
+        * If preferred address allocation failed allocate as low as
+        * possible.
+        */
+       if (status != EFI_SUCCESS) {
+               status = efi_low_alloc_above(alloc_size, alignment, &new_addr,
+                                            min_addr);
+       }
+       if (status != EFI_SUCCESS) {
+               pr_efi_err("Failed to allocate usable memory for kernel.\n");
+               return status;
+       }
+
+       /*
+        * We know source/dest won't overlap since both memory ranges
+        * have been allocated by UEFI, so we can safely use memcpy.
+        */
+       memcpy((void *)new_addr, (void *)cur_image_addr, image_size);
+
+       /* Return the new address of the relocated image. */
+       *image_addr = new_addr;
+
+       return status;
+}
index 316ce9f..24aa375 100644 (file)
@@ -4,7 +4,6 @@
  */
 
 #include <linux/efi.h>
-#include <linux/log2.h>
 #include <asm/efi.h>
 
 #include "efistub.h"
@@ -26,6 +25,17 @@ union efi_rng_protocol {
        } mixed_mode;
 };
 
+/**
+ * efi_get_random_bytes() - fill a buffer with random bytes
+ * @size:      size of the buffer
+ * @out:       caller allocated buffer to receive the random bytes
+ *
+ * The call will fail if either the firmware does not implement the
+ * EFI_RNG_PROTOCOL or there are not enough random bytes available to fill
+ * the buffer.
+ *
+ * Return:     status code
+ */
 efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
 {
        efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
@@ -39,119 +49,19 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out)
        return efi_call_proto(rng, get_rng, NULL, size, out);
 }
 
-/*
- * Return the number of slots covered by this entry, i.e., the number of
- * addresses it covers that are suitably aligned and supply enough room
- * for the allocation.
+/**
+ * efi_random_get_seed() - provide random seed as configuration table
+ *
+ * The EFI_RNG_PROTOCOL is used to read random bytes. These random bytes are
+ * saved as a configuration table which can be used as entropy by the kernel
+ * for the initialization of its pseudo random number generator.
+ *
+ * If the EFI_RNG_PROTOCOL is not available or there are not enough random bytes
+ * available, the configuration table will not be installed and an error code
+ * will be returned.
+ *
+ * Return:     status code
  */
-static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
-                                        unsigned long size,
-                                        unsigned long align_shift)
-{
-       unsigned long align = 1UL << align_shift;
-       u64 first_slot, last_slot, region_end;
-
-       if (md->type != EFI_CONVENTIONAL_MEMORY)
-               return 0;
-
-       if (efi_soft_reserve_enabled() &&
-           (md->attribute & EFI_MEMORY_SP))
-               return 0;
-
-       region_end = min((u64)ULONG_MAX, md->phys_addr + md->num_pages*EFI_PAGE_SIZE - 1);
-
-       first_slot = round_up(md->phys_addr, align);
-       last_slot = round_down(region_end - size + 1, align);
-
-       if (first_slot > last_slot)
-               return 0;
-
-       return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1;
-}
-
-/*
- * The UEFI memory descriptors have a virtual address field that is only used
- * when installing the virtual mapping using SetVirtualAddressMap(). Since it
- * is unused here, we can reuse it to keep track of each descriptor's slot
- * count.
- */
-#define MD_NUM_SLOTS(md)       ((md)->virt_addr)
-
-efi_status_t efi_random_alloc(unsigned long size,
-                             unsigned long align,
-                             unsigned long *addr,
-                             unsigned long random_seed)
-{
-       unsigned long map_size, desc_size, total_slots = 0, target_slot;
-       unsigned long buff_size;
-       efi_status_t status;
-       efi_memory_desc_t *memory_map;
-       int map_offset;
-       struct efi_boot_memmap map;
-
-       map.map =       &memory_map;
-       map.map_size =  &map_size;
-       map.desc_size = &desc_size;
-       map.desc_ver =  NULL;
-       map.key_ptr =   NULL;
-       map.buff_size = &buff_size;
-
-       status = efi_get_memory_map(&map);
-       if (status != EFI_SUCCESS)
-               return status;
-
-       if (align < EFI_ALLOC_ALIGN)
-               align = EFI_ALLOC_ALIGN;
-
-       /* count the suitable slots in each memory map entry */
-       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
-               efi_memory_desc_t *md = (void *)memory_map + map_offset;
-               unsigned long slots;
-
-               slots = get_entry_num_slots(md, size, ilog2(align));
-               MD_NUM_SLOTS(md) = slots;
-               total_slots += slots;
-       }
-
-       /* find a random number between 0 and total_slots */
-       target_slot = (total_slots * (u16)random_seed) >> 16;
-
-       /*
-        * target_slot is now a value in the range [0, total_slots), and so
-        * it corresponds with exactly one of the suitable slots we recorded
-        * when iterating over the memory map the first time around.
-        *
-        * So iterate over the memory map again, subtracting the number of
-        * slots of each entry at each iteration, until we have found the entry
-        * that covers our chosen slot. Use the residual value of target_slot
-        * to calculate the randomly chosen address, and allocate it directly
-        * using EFI_ALLOCATE_ADDRESS.
-        */
-       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
-               efi_memory_desc_t *md = (void *)memory_map + map_offset;
-               efi_physical_addr_t target;
-               unsigned long pages;
-
-               if (target_slot >= MD_NUM_SLOTS(md)) {
-                       target_slot -= MD_NUM_SLOTS(md);
-                       continue;
-               }
-
-               target = round_up(md->phys_addr, align) + target_slot * align;
-               pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
-
-               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
-                                    EFI_LOADER_DATA, pages, &target);
-               if (status == EFI_SUCCESS)
-                       *addr = target;
-               break;
-       }
-
-       efi_bs_call(free_pool, memory_map);
-
-       return status;
-}
-
 efi_status_t efi_random_get_seed(void)
 {
        efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c
new file mode 100644 (file)
index 0000000..4578f59
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016 Linaro Ltd;  <ard.biesheuvel@linaro.org>
+ */
+
+#include <linux/efi.h>
+#include <linux/log2.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+/*
+ * Return the number of slots covered by this entry, i.e., the number of
+ * addresses it covers that are suitably aligned and supply enough room
+ * for the allocation.
+ */
+static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
+                                        unsigned long size,
+                                        unsigned long align_shift)
+{
+       unsigned long align = 1UL << align_shift;
+       u64 first_slot, last_slot, region_end;
+
+       if (md->type != EFI_CONVENTIONAL_MEMORY)
+               return 0;
+
+       if (efi_soft_reserve_enabled() &&
+           (md->attribute & EFI_MEMORY_SP))
+               return 0;
+
+       region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1,
+                        (u64)ULONG_MAX);
+
+       first_slot = round_up(md->phys_addr, align);
+       last_slot = round_down(region_end - size + 1, align);
+
+       if (first_slot > last_slot)
+               return 0;
+
+       return ((unsigned long)(last_slot - first_slot) >> align_shift) + 1;
+}
+
+/*
+ * The UEFI memory descriptors have a virtual address field that is only used
+ * when installing the virtual mapping using SetVirtualAddressMap(). Since it
+ * is unused here, we can reuse it to keep track of each descriptor's slot
+ * count.
+ */
+#define MD_NUM_SLOTS(md)       ((md)->virt_addr)
+
+efi_status_t efi_random_alloc(unsigned long size,
+                             unsigned long align,
+                             unsigned long *addr,
+                             unsigned long random_seed)
+{
+       unsigned long map_size, desc_size, total_slots = 0, target_slot;
+       unsigned long buff_size;
+       efi_status_t status;
+       efi_memory_desc_t *memory_map;
+       int map_offset;
+       struct efi_boot_memmap map;
+
+       map.map =       &memory_map;
+       map.map_size =  &map_size;
+       map.desc_size = &desc_size;
+       map.desc_ver =  NULL;
+       map.key_ptr =   NULL;
+       map.buff_size = &buff_size;
+
+       status = efi_get_memory_map(&map);
+       if (status != EFI_SUCCESS)
+               return status;
+
+       if (align < EFI_ALLOC_ALIGN)
+               align = EFI_ALLOC_ALIGN;
+
+       /* count the suitable slots in each memory map entry */
+       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+               efi_memory_desc_t *md = (void *)memory_map + map_offset;
+               unsigned long slots;
+
+               slots = get_entry_num_slots(md, size, ilog2(align));
+               MD_NUM_SLOTS(md) = slots;
+               total_slots += slots;
+       }
+
+       /* find a random number between 0 and total_slots */
+       target_slot = (total_slots * (u16)random_seed) >> 16;
+
+       /*
+        * target_slot is now a value in the range [0, total_slots), and so
+        * it corresponds with exactly one of the suitable slots we recorded
+        * when iterating over the memory map the first time around.
+        *
+        * So iterate over the memory map again, subtracting the number of
+        * slots of each entry at each iteration, until we have found the entry
+        * that covers our chosen slot. Use the residual value of target_slot
+        * to calculate the randomly chosen address, and allocate it directly
+        * using EFI_ALLOCATE_ADDRESS.
+        */
+       for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+               efi_memory_desc_t *md = (void *)memory_map + map_offset;
+               efi_physical_addr_t target;
+               unsigned long pages;
+
+               if (target_slot >= MD_NUM_SLOTS(md)) {
+                       target_slot -= MD_NUM_SLOTS(md);
+                       continue;
+               }
+
+               target = round_up(md->phys_addr, align) + target_slot * align;
+               pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+
+               status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
+                                    EFI_LOADER_DATA, pages, &target);
+               if (status == EFI_SUCCESS)
+                       *addr = target;
+               break;
+       }
+
+       efi_bs_call(free_pool, memory_map);
+
+       return status;
+}
diff --git a/drivers/firmware/efi/libstub/skip_spaces.c b/drivers/firmware/efi/libstub/skip_spaces.c
new file mode 100644 (file)
index 0000000..a700b3c
--- /dev/null
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/ctype.h>
+#include <linux/types.h>
+
+char *skip_spaces(const char *str)
+{
+       while (isspace(*str))
+               ++str;
+       return (char *)str;
+}
index ed10e3f..1ac2f87 100644 (file)
@@ -6,6 +6,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/ctype.h>
 #include <linux/types.h>
 #include <linux/string.h>
 
@@ -56,3 +57,58 @@ int strncmp(const char *cs, const char *ct, size_t count)
        return 0;
 }
 #endif
+
+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
+static unsigned int simple_guess_base(const char *cp)
+{
+       if (cp[0] == '0') {
+               if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2]))
+                       return 16;
+               else
+                       return 8;
+       } else {
+               return 10;
+       }
+}
+
+/**
+ * simple_strtoull - convert a string to an unsigned long long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+
+unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
+{
+       unsigned long long result = 0;
+
+       if (!base)
+               base = simple_guess_base(cp);
+
+       if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')
+               cp += 2;
+
+       while (isxdigit(*cp)) {
+               unsigned int value;
+
+               value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;
+               if (value >= base)
+                       break;
+               result = result * base + value;
+               cp++;
+       }
+       if (endp)
+               *endp = (char *)cp;
+
+       return result;
+}
+
+long simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+       if (*cp == '-')
+               return -simple_strtoull(cp + 1, endp, base);
+
+       return simple_strtoull(cp, endp, base);
+}
similarity index 80%
rename from arch/x86/boot/compressed/eboot.c
rename to drivers/firmware/efi/libstub/x86-stub.c
index 287393d..8d3a707 100644 (file)
@@ -6,8 +6,6 @@
  *
  * ----------------------------------------------------------------------- */
 
-#pragma GCC visibility push(hidden)
-
 #include <linux/efi.h>
 #include <linux/pci.h>
 
 #include <asm/desc.h>
 #include <asm/boot.h>
 
-#include "../string.h"
-#include "eboot.h"
+#include "efistub.h"
+
+/* Maximum physical address for 64-bit kernel with 4-level paging */
+#define MAXMEM_X86_64_4LEVEL (1ull << 46)
 
 static efi_system_table_t *sys_table;
 extern const bool efi_is64;
+extern u32 image_offset;
 
 __pure efi_system_table_t *efi_system_table(void)
 {
@@ -315,7 +316,7 @@ free_handle:
        return status;
 }
 
-void setup_graphics(struct boot_params *boot_params)
+static void setup_graphics(struct boot_params *boot_params)
 {
        efi_guid_t graphics_proto = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
        struct screen_info *si;
@@ -343,6 +344,14 @@ void setup_graphics(struct boot_params *boot_params)
        }
 }
 
+
+static void __noreturn efi_exit(efi_handle_t handle, efi_status_t status)
+{
+       efi_bs_call(exit, handle, status, 0, NULL);
+       for(;;)
+               asm("hlt");
+}
+
 void startup_32(struct boot_params *boot_params);
 
 void __noreturn efi_stub_entry(efi_handle_t handle,
@@ -358,9 +367,9 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
                                   efi_system_table_t *sys_table_arg)
 {
        struct boot_params *boot_params;
-       struct apm_bios_info *bi;
        struct setup_header *hdr;
        efi_loaded_image_t *image;
+       void *image_base;
        efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID;
        int options_size = 0;
        efi_status_t status;
@@ -372,27 +381,31 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
 
        /* Check if we were booted by the EFI firmware */
        if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
-               return EFI_INVALID_PARAMETER;
+               efi_exit(handle, EFI_INVALID_PARAMETER);
 
-       status = efi_bs_call(handle_protocol, handle, &proto, (void *)&image);
+       status = efi_bs_call(handle_protocol, handle, &proto, (void **)&image);
        if (status != EFI_SUCCESS) {
                efi_printk("Failed to get handle for LOADED_IMAGE_PROTOCOL\n");
-               return status;
+               efi_exit(handle, status);
        }
 
-       status = efi_low_alloc(0x4000, 1, (unsigned long *)&boot_params);
+       image_base = efi_table_attr(image, image_base);
+       image_offset = (void *)startup_32 - image_base;
+
+       hdr = &((struct boot_params *)image_base)->hdr;
+
+       status = efi_allocate_pages(0x4000, (unsigned long *)&boot_params, ULONG_MAX);
        if (status != EFI_SUCCESS) {
                efi_printk("Failed to allocate lowmem for boot params\n");
-               return status;
+               efi_exit(handle, status);
        }
 
        memset(boot_params, 0x0, 0x4000);
 
        hdr = &boot_params->hdr;
-       bi = &boot_params->apm_bios_info;
 
        /* Copy the second sector to boot_params */
-       memcpy(&hdr->jump, image->image_base + 512, 512);
+       memcpy(&hdr->jump, image_base + 512, 512);
 
        /*
         * Fill out some of the header fields ourselves because the
@@ -405,7 +418,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        hdr->type_of_loader = 0x21;
 
        /* Convert unicode cmdline to ascii */
-       cmdline_ptr = efi_convert_cmdline(image, &options_size);
+       cmdline_ptr = efi_convert_cmdline(image, &options_size, ULONG_MAX);
        if (!cmdline_ptr)
                goto fail;
 
@@ -416,45 +429,34 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        hdr->ramdisk_image = 0;
        hdr->ramdisk_size = 0;
 
-       /* Clear APM BIOS info */
-       memset(bi, 0, sizeof(*bi));
-
-       status = efi_parse_options(cmdline_ptr);
-       if (status != EFI_SUCCESS)
-               goto fail2;
-
-       status = handle_cmdline_files(image,
-                                     (char *)(unsigned long)hdr->cmd_line_ptr,
-                                     "initrd=", hdr->initrd_addr_max,
-                                     &ramdisk_addr, &ramdisk_size);
-
-       if (status != EFI_SUCCESS &&
-           hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) {
-               efi_printk("Trying to load files to higher address\n");
-               status = handle_cmdline_files(image,
-                                     (char *)(unsigned long)hdr->cmd_line_ptr,
-                                     "initrd=", -1UL,
-                                     &ramdisk_addr, &ramdisk_size);
+       if (efi_is_native()) {
+               status = efi_parse_options(cmdline_ptr);
+               if (status != EFI_SUCCESS)
+                       goto fail2;
+
+               if (!noinitrd()) {
+                       status = efi_load_initrd(image, &ramdisk_addr,
+                                                &ramdisk_size,
+                                                hdr->initrd_addr_max,
+                                                ULONG_MAX);
+                       if (status != EFI_SUCCESS)
+                               goto fail2;
+                       hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
+                       hdr->ramdisk_size  = ramdisk_size & 0xffffffff;
+                       boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
+                       boot_params->ext_ramdisk_size  = (u64)ramdisk_size >> 32;
+               }
        }
 
-       if (status != EFI_SUCCESS)
-               goto fail2;
-       hdr->ramdisk_image = ramdisk_addr & 0xffffffff;
-       hdr->ramdisk_size  = ramdisk_size & 0xffffffff;
-       boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32;
-       boot_params->ext_ramdisk_size  = (u64)ramdisk_size >> 32;
-
-       hdr->code32_start = (u32)(unsigned long)startup_32;
-
        efi_stub_entry(handle, sys_table, boot_params);
        /* not reached */
 
 fail2:
-       efi_free(options_size, hdr->cmd_line_ptr);
+       efi_free(options_size, (unsigned long)cmdline_ptr);
 fail:
        efi_free(0x4000, (unsigned long)boot_params);
 
-       return status;
+       efi_exit(handle, status);
 }
 
 static void add_e820ext(struct boot_params *params,
@@ -705,27 +707,73 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)
 }
 
 /*
- * On success we return a pointer to a boot_params structure, and NULL
- * on failure.
+ * On success, we return the address of startup_32, which has potentially been
+ * relocated by efi_relocate_kernel.
+ * On failure, we exit to the firmware via efi_exit instead of returning.
  */
-struct boot_params *efi_main(efi_handle_t handle,
+unsigned long efi_main(efi_handle_t handle,
                             efi_system_table_t *sys_table_arg,
                             struct boot_params *boot_params)
 {
-       struct desc_ptr *gdt = NULL;
+       unsigned long bzimage_addr = (unsigned long)startup_32;
+       unsigned long buffer_start, buffer_end;
        struct setup_header *hdr = &boot_params->hdr;
        efi_status_t status;
-       struct desc_struct *desc;
        unsigned long cmdline_paddr;
 
        sys_table = sys_table_arg;
 
        /* Check if we were booted by the EFI firmware */
        if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
-               goto fail;
+               efi_exit(handle, EFI_INVALID_PARAMETER);
+
+       /*
+        * If the kernel isn't already loaded at a suitable address,
+        * relocate it.
+        *
+        * It must be loaded above LOAD_PHYSICAL_ADDR.
+        *
+        * The maximum address for 64-bit is 1 << 46 for 4-level paging. This
+        * is defined as the macro MAXMEM, but unfortunately that is not a
+        * compile-time constant if 5-level paging is configured, so we instead
+        * define our own macro for use here.
+        *
+        * For 32-bit, the maximum address is complicated to figure out, for
+        * now use KERNEL_IMAGE_SIZE, which will be 512MiB, the same as what
+        * KASLR uses.
+        *
+        * Also relocate it if image_offset is zero, i.e. we weren't loaded by
+        * LoadImage, but we are not aligned correctly.
+        */
+
+       buffer_start = ALIGN(bzimage_addr - image_offset,
+                            hdr->kernel_alignment);
+       buffer_end = buffer_start + hdr->init_size;
+
+       if ((buffer_start < LOAD_PHYSICAL_ADDR)                              ||
+           (IS_ENABLED(CONFIG_X86_32) && buffer_end > KERNEL_IMAGE_SIZE)    ||
+           (IS_ENABLED(CONFIG_X86_64) && buffer_end > MAXMEM_X86_64_4LEVEL) ||
+           (image_offset == 0 && !IS_ALIGNED(bzimage_addr,
+                                             hdr->kernel_alignment))) {
+               status = efi_relocate_kernel(&bzimage_addr,
+                                            hdr->init_size, hdr->init_size,
+                                            hdr->pref_address,
+                                            hdr->kernel_alignment,
+                                            LOAD_PHYSICAL_ADDR);
+               if (status != EFI_SUCCESS) {
+                       efi_printk("efi_relocate_kernel() failed!\n");
+                       goto fail;
+               }
+               /*
+                * Now that we've copied the kernel elsewhere, we no longer
+                * have a set up block before startup_32(), so reset image_offset
+                * to zero in case it was set earlier.
+                */
+               image_offset = 0;
+       }
 
        /*
-        * make_boot_params() may have been called before efi_main(), in which
+        * efi_pe_entry() may have been called before efi_main(), in which
         * case this is the second time we parse the cmdline. This is ok,
         * parsing the cmdline multiple times does not have side-effects.
         */
@@ -734,6 +782,28 @@ struct boot_params *efi_main(efi_handle_t handle,
        efi_parse_options((char *)cmdline_paddr);
 
        /*
+        * At this point, an initrd may already have been loaded, either by
+        * the bootloader and passed via bootparams, or loaded from a initrd=
+        * command line option by efi_pe_entry() above. In either case, we
+        * permit an initrd loaded from the LINUX_EFI_INITRD_MEDIA_GUID device
+        * path to supersede it.
+        */
+       if (!noinitrd()) {
+               unsigned long addr, size;
+
+               status = efi_load_initrd_dev_path(&addr, &size, ULONG_MAX);
+               if (status == EFI_SUCCESS) {
+                       hdr->ramdisk_image              = (u32)addr;
+                       hdr->ramdisk_size               = (u32)size;
+                       boot_params->ext_ramdisk_image  = (u64)addr >> 32;
+                       boot_params->ext_ramdisk_size   = (u64)size >> 32;
+               } else if (status != EFI_NOT_FOUND) {
+                       efi_printk("efi_load_initrd_dev_path() failed!\n");
+                       goto fail;
+               }
+       }
+
+       /*
         * If the boot loader gave us a value for secure_boot then we use that,
         * otherwise we ask the BIOS.
         */
@@ -753,137 +823,15 @@ struct boot_params *efi_main(efi_handle_t handle,
 
        setup_quirks(boot_params);
 
-       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, sizeof(*gdt),
-                            (void **)&gdt);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to allocate memory for 'gdt' structure\n");
-               goto fail;
-       }
-
-       gdt->size = 0x800;
-       status = efi_low_alloc(gdt->size, 8, (unsigned long *)&gdt->address);
-       if (status != EFI_SUCCESS) {
-               efi_printk("Failed to allocate memory for 'gdt'\n");
-               goto fail;
-       }
-
-       /*
-        * If the kernel isn't already loaded at the preferred load
-        * address, relocate it.
-        */
-       if (hdr->pref_address != hdr->code32_start) {
-               unsigned long bzimage_addr = hdr->code32_start;
-               status = efi_relocate_kernel(&bzimage_addr,
-                                            hdr->init_size, hdr->init_size,
-                                            hdr->pref_address,
-                                            hdr->kernel_alignment,
-                                            LOAD_PHYSICAL_ADDR);
-               if (status != EFI_SUCCESS) {
-                       efi_printk("efi_relocate_kernel() failed!\n");
-                       goto fail;
-               }
-
-               hdr->pref_address = hdr->code32_start;
-               hdr->code32_start = bzimage_addr;
-       }
-
        status = exit_boot(boot_params, handle);
        if (status != EFI_SUCCESS) {
                efi_printk("exit_boot() failed!\n");
                goto fail;
        }
 
-       memset((char *)gdt->address, 0x0, gdt->size);
-       desc = (struct desc_struct *)gdt->address;
-
-       /* The first GDT is a dummy. */
-       desc++;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               /* __KERNEL32_CS */
-               desc->limit0    = 0xffff;
-               desc->base0     = 0x0000;
-               desc->base1     = 0x0000;
-               desc->type      = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
-               desc->s         = DESC_TYPE_CODE_DATA;
-               desc->dpl       = 0;
-               desc->p         = 1;
-               desc->limit1    = 0xf;
-               desc->avl       = 0;
-               desc->l         = 0;
-               desc->d         = SEG_OP_SIZE_32BIT;
-               desc->g         = SEG_GRANULARITY_4KB;
-               desc->base2     = 0x00;
-
-               desc++;
-       } else {
-               /* Second entry is unused on 32-bit */
-               desc++;
-       }
-
-       /* __KERNEL_CS */
-       desc->limit0    = 0xffff;
-       desc->base0     = 0x0000;
-       desc->base1     = 0x0000;
-       desc->type      = SEG_TYPE_CODE | SEG_TYPE_EXEC_READ;
-       desc->s         = DESC_TYPE_CODE_DATA;
-       desc->dpl       = 0;
-       desc->p         = 1;
-       desc->limit1    = 0xf;
-       desc->avl       = 0;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               desc->l = 1;
-               desc->d = 0;
-       } else {
-               desc->l = 0;
-               desc->d = SEG_OP_SIZE_32BIT;
-       }
-       desc->g         = SEG_GRANULARITY_4KB;
-       desc->base2     = 0x00;
-       desc++;
-
-       /* __KERNEL_DS */
-       desc->limit0    = 0xffff;
-       desc->base0     = 0x0000;
-       desc->base1     = 0x0000;
-       desc->type      = SEG_TYPE_DATA | SEG_TYPE_READ_WRITE;
-       desc->s         = DESC_TYPE_CODE_DATA;
-       desc->dpl       = 0;
-       desc->p         = 1;
-       desc->limit1    = 0xf;
-       desc->avl       = 0;
-       desc->l         = 0;
-       desc->d         = SEG_OP_SIZE_32BIT;
-       desc->g         = SEG_GRANULARITY_4KB;
-       desc->base2     = 0x00;
-       desc++;
-
-       if (IS_ENABLED(CONFIG_X86_64)) {
-               /* Task segment value */
-               desc->limit0    = 0x0000;
-               desc->base0     = 0x0000;
-               desc->base1     = 0x0000;
-               desc->type      = SEG_TYPE_TSS;
-               desc->s         = 0;
-               desc->dpl       = 0;
-               desc->p         = 1;
-               desc->limit1    = 0x0;
-               desc->avl       = 0;
-               desc->l         = 0;
-               desc->d         = 0;
-               desc->g         = SEG_GRANULARITY_4KB;
-               desc->base2     = 0x00;
-               desc++;
-       }
-
-       asm volatile("cli");
-       asm volatile ("lgdt %0" : : "m" (*gdt));
-
-       return boot_params;
+       return bzimage_addr;
 fail:
        efi_printk("efi_main() failed!\n");
 
-       for (;;)
-               asm("hlt");
+       efi_exit(handle, status);
 }
index 58452fd..5737cb0 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/early_ioremap.h>
 
 static int __initdata tbl_size;
+unsigned long __ro_after_init efi_mem_attr_table = EFI_INVALID_TABLE_ADDR;
 
 /*
  * Reserve the memory associated with the Memory Attributes configuration
@@ -22,13 +23,13 @@ int __init efi_memattr_init(void)
 {
        efi_memory_attributes_table_t *tbl;
 
-       if (efi.mem_attr_table == EFI_INVALID_TABLE_ADDR)
+       if (efi_mem_attr_table == EFI_INVALID_TABLE_ADDR)
                return 0;
 
-       tbl = early_memremap(efi.mem_attr_table, sizeof(*tbl));
+       tbl = early_memremap(efi_mem_attr_table, sizeof(*tbl));
        if (!tbl) {
                pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
-                      efi.mem_attr_table);
+                      efi_mem_attr_table);
                return -ENOMEM;
        }
 
@@ -39,7 +40,7 @@ int __init efi_memattr_init(void)
        }
 
        tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size;
-       memblock_reserve(efi.mem_attr_table, tbl_size);
+       memblock_reserve(efi_mem_attr_table, tbl_size);
        set_bit(EFI_MEM_ATTR, &efi.flags);
 
 unmap:
@@ -147,10 +148,10 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm,
        if (WARN_ON(!efi_enabled(EFI_MEMMAP)))
                return 0;
 
-       tbl = memremap(efi.mem_attr_table, tbl_size, MEMREMAP_WB);
+       tbl = memremap(efi_mem_attr_table, tbl_size, MEMREMAP_WB);
        if (!tbl) {
                pr_err("Failed to map EFI Memory Attributes table @ 0x%lx\n",
-                      efi.mem_attr_table);
+                      efi_mem_attr_table);
                return -ENOMEM;
        }
 
index 7effff9..73089a2 100644 (file)
@@ -15,7 +15,7 @@ void efi_reboot(enum reboot_mode reboot_mode, const char *__unused)
        const char *str[] = { "cold", "warm", "shutdown", "platform" };
        int efi_mode, cap_reset_mode;
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM))
                return;
 
        switch (reboot_mode) {
@@ -64,7 +64,7 @@ static void efi_power_off(void)
 
 static int __init efi_shutdown_init(void)
 {
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_RESET_SYSTEM))
                return -ENODEV;
 
        if (efi_poweroff_required()) {
index 65fffaa..1410bea 100644 (file)
@@ -40,9 +40,9 @@
  * code doesn't get too cluttered:
  */
 #define efi_call_virt(f, args...)   \
-       efi_call_virt_pointer(efi.systab->runtime, f, args)
+       efi_call_virt_pointer(efi.runtime, f, args)
 #define __efi_call_virt(f, args...) \
-       __efi_call_virt_pointer(efi.systab->runtime, f, args)
+       __efi_call_virt_pointer(efi.runtime, f, args)
 
 struct efi_runtime_work efi_rts_work;
 
index 436d177..5f2a4d1 100644 (file)
@@ -1071,7 +1071,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
  * entry on the list. It is safe for @func to remove entries in the
  * list via efivar_entry_delete().
  *
- * You MUST call efivar_enter_iter_begin() before this function, and
+ * You MUST call efivar_entry_iter_begin() before this function, and
  * efivar_entry_iter_end() afterwards.
  *
  * It is possible to begin iteration from an arbitrary entry within
index 03b43b7..f71eaa5 100644 (file)
@@ -29,6 +29,7 @@ struct imx_sc_chan {
        struct mbox_client cl;
        struct mbox_chan *ch;
        int idx;
+       struct completion tx_done;
 };
 
 struct imx_sc_ipc {
@@ -100,6 +101,14 @@ int imx_scu_get_handle(struct imx_sc_ipc **ipc)
 }
 EXPORT_SYMBOL(imx_scu_get_handle);
 
+/* Callback called when the word of a message is ack-ed, eg read by SCU */
+static void imx_scu_tx_done(struct mbox_client *cl, void *mssg, int r)
+{
+       struct imx_sc_chan *sc_chan = container_of(cl, struct imx_sc_chan, cl);
+
+       complete(&sc_chan->tx_done);
+}
+
 static void imx_scu_rx_callback(struct mbox_client *c, void *msg)
 {
        struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl);
@@ -149,6 +158,19 @@ static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)
 
        for (i = 0; i < hdr->size; i++) {
                sc_chan = &sc_ipc->chans[i % 4];
+
+               /*
+                * SCU requires that all messages words are written
+                * sequentially but linux MU driver implements multiple
+                * independent channels for each register so ordering between
+                * different channels must be ensured by SCU API interface.
+                *
+                * Wait for tx_done before every send to ensure that no
+                * queueing happens at the mailbox channel level.
+                */
+               wait_for_completion(&sc_chan->tx_done);
+               reinit_completion(&sc_chan->tx_done);
+
                ret = mbox_send_message(sc_chan->ch, &data[i]);
                if (ret < 0)
                        return ret;
@@ -247,6 +269,11 @@ static int imx_scu_probe(struct platform_device *pdev)
                cl->knows_txdone = true;
                cl->rx_callback = imx_scu_rx_callback;
 
+               /* Initial tx_done completion as "done" */
+               cl->tx_done = imx_scu_tx_done;
+               init_completion(&sc_chan->tx_done);
+               complete(&sc_chan->tx_done);
+
                sc_chan->sc_ipc = sc_ipc;
                sc_chan->idx = i % 4;
                sc_chan->ch = mbox_request_channel_byname(cl, chan_name);
index 4b56a58..d073cb3 100644 (file)
@@ -16,7 +16,7 @@ struct imx_sc_msg_req_misc_set_ctrl {
        u32 ctrl;
        u32 val;
        u16 resource;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_req_cpu_start {
        struct imx_sc_rpc_msg hdr;
@@ -24,18 +24,18 @@ struct imx_sc_msg_req_cpu_start {
        u32 address_lo;
        u16 resource;
        u8 enable;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_req_misc_get_ctrl {
        struct imx_sc_rpc_msg hdr;
        u32 ctrl;
        u16 resource;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_resp_misc_get_ctrl {
        struct imx_sc_rpc_msg hdr;
        u32 val;
-} __packed;
+} __packed __aligned(4);
 
 /*
  * This function sets a miscellaneous control value.
index b556612..af3ae00 100644 (file)
@@ -61,7 +61,7 @@ struct imx_sc_msg_req_set_resource_power_mode {
        struct imx_sc_rpc_msg hdr;
        u16 resource;
        u8 mode;
-} __packed;
+} __packed __aligned(4);
 
 #define IMX_SCU_PD_NAME_SIZE 20
 struct imx_sc_pm_domain {
index 4adeb7a..715a454 100644 (file)
@@ -80,6 +80,8 @@ setup_vga_console(struct pcdp_device *dev)
 #endif
 }
 
+extern unsigned long hcdp_phys;
+
 int __init
 efi_setup_pcdp_console(char *cmdline)
 {
@@ -89,11 +91,11 @@ efi_setup_pcdp_console(char *cmdline)
        int i, serial = 0;
        int rc = -ENODEV;
 
-       if (efi.hcdp == EFI_INVALID_TABLE_ADDR)
+       if (hcdp_phys == EFI_INVALID_TABLE_ADDR)
                return -ENODEV;
 
-       pcdp = early_memremap(efi.hcdp, 4096);
-       printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, efi.hcdp);
+       pcdp = early_memremap(hcdp_phys, 4096);
+       printk(KERN_INFO "PCDP: v%d at 0x%lx\n", pcdp->rev, hcdp_phys);
 
        if (strstr(cmdline, "console=hcdp")) {
                if (pcdp->rev < 3)
index 6a44539..873841a 100644 (file)
@@ -84,7 +84,7 @@ static unsigned int down_and_up_cpus(const struct cpumask *cpus,
 
        /* Try to power down all CPUs in the mask. */
        for_each_cpu(cpu, cpus) {
-               int ret = cpu_down(cpu);
+               int ret = remove_cpu(cpu);
 
                /*
                 * cpu_down() checks the number of online CPUs before the TOS
@@ -116,7 +116,7 @@ static unsigned int down_and_up_cpus(const struct cpumask *cpus,
 
        /* Try to power up all the CPUs that have been offlined. */
        for_each_cpu(cpu, offlined_cpus) {
-               int ret = cpu_up(cpu);
+               int ret = add_cpu(cpu);
 
                if (ret != 0) {
                        pr_err("Error occurred (%d) while trying "
index 31fee5e..0017367 100644 (file)
 #include "gpiolib.h"
 #include "gpiolib-acpi.h"
 
-#define QUIRK_NO_EDGE_EVENTS_ON_BOOT           0x01l
-#define QUIRK_NO_WAKEUP                                0x02l
-
 static int run_edge_events_on_boot = -1;
 module_param(run_edge_events_on_boot, int, 0444);
 MODULE_PARM_DESC(run_edge_events_on_boot,
                 "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
 
-static int honor_wakeup = -1;
-module_param(honor_wakeup, int, 0444);
-MODULE_PARM_DESC(honor_wakeup,
-                "Honor the ACPI wake-capable flag: 0=no, 1=yes, -1=auto");
+static char *ignore_wake;
+module_param(ignore_wake, charp, 0444);
+MODULE_PARM_DESC(ignore_wake,
+                "controller@pin combos on which to ignore the ACPI wake flag "
+                "ignore_wake=controller@pin[,controller@pin[,...]]");
+
+struct acpi_gpiolib_dmi_quirk {
+       bool no_edge_events_on_boot;
+       char *ignore_wake;
+};
 
 /**
  * struct acpi_gpio_event - ACPI GPIO event handler data
@@ -202,6 +205,57 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
                acpi_gpiochip_request_irq(acpi_gpio, event);
 }
 
+static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in)
+{
+       const char *controller, *pin_str;
+       int len, pin;
+       char *endp;
+
+       controller = ignore_wake;
+       while (controller) {
+               pin_str = strchr(controller, '@');
+               if (!pin_str)
+                       goto err;
+
+               len = pin_str - controller;
+               if (len == strlen(controller_in) &&
+                   strncmp(controller, controller_in, len) == 0) {
+                       pin = simple_strtoul(pin_str + 1, &endp, 10);
+                       if (*endp != 0 && *endp != ',')
+                               goto err;
+
+                       if (pin == pin_in)
+                               return true;
+               }
+
+               controller = strchr(controller, ',');
+               if (controller)
+                       controller++;
+       }
+
+       return false;
+err:
+       pr_err_once("Error invalid value for gpiolib_acpi.ignore_wake: %s\n",
+                   ignore_wake);
+       return false;
+}
+
+static bool acpi_gpio_irq_is_wake(struct device *parent,
+                                 struct acpi_resource_gpio *agpio)
+{
+       int pin = agpio->pin_table[0];
+
+       if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
+               return false;
+
+       if (acpi_gpio_in_ignore_list(dev_name(parent), pin)) {
+               dev_info(parent, "Ignoring wakeup on pin %d\n", pin);
+               return false;
+       }
+
+       return true;
+}
+
 /* Always returns AE_OK so that we keep looping over the resources */
 static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
                                             void *context)
@@ -289,7 +343,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
        event->handle = evt_handle;
        event->handler = handler;
        event->irq = irq;
-       event->irq_is_wake = honor_wakeup && agpio->wake_capable == ACPI_WAKE_CAPABLE;
+       event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
        event->pin = pin;
        event->desc = desc;
 
@@ -1328,7 +1382,9 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
                },
-               .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT,
+               .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+                       .no_edge_events_on_boot = true,
+               },
        },
        {
                /*
@@ -1341,16 +1397,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"),
                },
-               .driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT,
+               .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+                       .no_edge_events_on_boot = true,
+               },
        },
        {
                /*
-                * Various HP X2 10 Cherry Trail models use an external
-                * embedded-controller connected via I2C + an ACPI GPIO
-                * event handler. The embedded controller generates various
-                * spurious wakeup events when suspended. So disable wakeup
-                * for its handler (it uses the only ACPI GPIO event handler).
-                * This breaks wakeup when opening the lid, the user needs
+                * HP X2 10 models with Cherry Trail SoC + TI PMIC use an
+                * external embedded-controller connected via I2C + an ACPI GPIO
+                * event handler on INT33FF:01 pin 0, causing spurious wakeups.
+                * When suspending by closing the LID, the power to the USB
+                * keyboard is turned off, causing INT0002 ACPI events to
+                * trigger once the XHCI controller notices the keyboard is
+                * gone. So INT0002 events cause spurious wakeups too. Ignoring
+                * EC wakes breaks wakeup when opening the lid, the user needs
                 * to press the power-button to wakeup the system. The
                 * alternative is suspend simply not working, which is worse.
                 */
@@ -1358,33 +1418,61 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
                        DMI_MATCH(DMI_SYS_VENDOR, "HP"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"),
                },
-               .driver_data = (void *)QUIRK_NO_WAKEUP,
+               .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+                       .ignore_wake = "INT33FF:01@0,INT0002:00@2",
+               },
+       },
+       {
+               /*
+                * HP X2 10 models with Bay Trail SoC + AXP288 PMIC use an
+                * external embedded-controller connected via I2C + an ACPI GPIO
+                * event handler on INT33FC:02 pin 28, causing spurious wakeups.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
+                       DMI_MATCH(DMI_BOARD_NAME, "815D"),
+               },
+               .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+                       .ignore_wake = "INT33FC:02@28",
+               },
+       },
+       {
+               /*
+                * HP X2 10 models with Cherry Trail SoC + AXP288 PMIC use an
+                * external embedded-controller connected via I2C + an ACPI GPIO
+                * event handler on INT33FF:01 pin 0, causing spurious wakeups.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
+                       DMI_MATCH(DMI_BOARD_NAME, "813E"),
+               },
+               .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
+                       .ignore_wake = "INT33FF:01@0",
+               },
        },
        {} /* Terminating entry */
 };
 
 static int acpi_gpio_setup_params(void)
 {
+       const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
        const struct dmi_system_id *id;
-       long quirks = 0;
 
        id = dmi_first_match(gpiolib_acpi_quirks);
        if (id)
-               quirks = (long)id->driver_data;
+               quirk = id->driver_data;
 
        if (run_edge_events_on_boot < 0) {
-               if (quirks & QUIRK_NO_EDGE_EVENTS_ON_BOOT)
+               if (quirk && quirk->no_edge_events_on_boot)
                        run_edge_events_on_boot = 0;
                else
                        run_edge_events_on_boot = 1;
        }
 
-       if (honor_wakeup < 0) {
-               if (quirks & QUIRK_NO_WAKEUP)
-                       honor_wakeup = 0;
-               else
-                       honor_wakeup = 1;
-       }
+       if (ignore_wake == NULL && quirk && quirk->ignore_wake)
+               ignore_wake = quirk->ignore_wake;
 
        return 0;
 }
index 4d0106c..00fb91f 100644 (file)
@@ -2306,9 +2306,16 @@ static void gpiochip_irq_disable(struct irq_data *d)
 {
        struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
 
+       /*
+        * Since we override .irq_disable() we need to mimic the
+        * behaviour of __irq_disable() in irq/chip.c.
+        * First call .irq_disable() if it exists, else mimic the
+        * behaviour of mask_irq() which calls .irq_mask() if
+        * it exists.
+        */
        if (chip->irq.irq_disable)
                chip->irq.irq_disable(d);
-       else
+       else if (chip->irq.chip->irq_mask)
                chip->irq.chip->irq_mask(d);
        gpiochip_disable_irq(chip, d->hwirq);
 }
index f24ed9a..337d7cd 100644 (file)
@@ -781,11 +781,11 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
        ssize_t result = 0;
        uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data;
 
-       if (size & 3 || *pos & 3)
+       if (size > 4096 || size & 3 || *pos & 3)
                return -EINVAL;
 
        /* decode offset */
-       offset = *pos & GENMASK_ULL(11, 0);
+       offset = (*pos & GENMASK_ULL(11, 0)) >> 2;
        se = (*pos & GENMASK_ULL(19, 12)) >> 12;
        sh = (*pos & GENMASK_ULL(27, 20)) >> 20;
        cu = (*pos & GENMASK_ULL(35, 28)) >> 28;
@@ -823,7 +823,7 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
        while (size) {
                uint32_t value;
 
-               value = data[offset++];
+               value = data[result >> 2];
                r = put_user(value, (uint32_t *)buf);
                if (r) {
                        result = r;
index 39cd545..b897585 100644 (file)
@@ -3913,6 +3913,8 @@ static int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive,
                                if (r)
                                        goto out;
 
+                               amdgpu_fbdev_set_suspend(tmp_adev, 0);
+
                                /* must succeed. */
                                amdgpu_ras_resume(tmp_adev);
 
@@ -4086,6 +4088,8 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
                 */
                amdgpu_unregister_gpu_instance(tmp_adev);
 
+               amdgpu_fbdev_set_suspend(adev, 1);
+
                /* disable ras on ALL IPs */
                if (!(in_ras_intr && !use_baco) &&
                      amdgpu_device_ip_need_full_reset(tmp_adev))
index 94e2fd7..42f4feb 100644 (file)
@@ -1389,7 +1389,7 @@ amdgpu_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
 
 static struct drm_driver kms_driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_ATOMIC |
+           DRIVER_ATOMIC |
            DRIVER_GEM |
            DRIVER_RENDER | DRIVER_MODESET | DRIVER_SYNCOBJ |
            DRIVER_SYNCOBJ_TIMELINE,
index d3c27a3..7546da0 100644 (file)
@@ -195,6 +195,7 @@ struct amdgpu_gmc {
        uint32_t                srbm_soft_reset;
        bool                    prt_warning;
        uint64_t                stolen_size;
+       uint32_t                sdpif_register;
        /* apertures */
        u64                     shared_aperture_start;
        u64                     shared_aperture_end;
index dee4462..c6e9885 100644 (file)
@@ -974,7 +974,7 @@ static int amdgpu_ttm_tt_pin_userptr(struct ttm_tt *ttm)
        /* Map SG to device */
        r = -ENOMEM;
        nents = dma_map_sg(adev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
-       if (nents != ttm->sg->nents)
+       if (nents == 0)
                goto release_sg;
 
        /* convert SG to linear array of pages and dma addresses */
index 22bbb36..0270259 100644 (file)
@@ -52,7 +52,7 @@
  * 1. Primary ring
  * 2. Async ring
  */
-#define GFX10_NUM_GFX_RINGS    2
+#define GFX10_NUM_GFX_RINGS_NV1X       1
 #define GFX10_MEC_HPD_SIZE     2048
 
 #define F32_CE_PROGRAM_RAM_SIZE                65536
@@ -1304,7 +1304,7 @@ static int gfx_v10_0_sw_init(void *handle)
        case CHIP_NAVI14:
        case CHIP_NAVI12:
                adev->gfx.me.num_me = 1;
-               adev->gfx.me.num_pipe_per_me = 2;
+               adev->gfx.me.num_pipe_per_me = 1;
                adev->gfx.me.num_queue_per_pipe = 1;
                adev->gfx.mec.num_mec = 2;
                adev->gfx.mec.num_pipe_per_mec = 4;
@@ -2710,18 +2710,20 @@ static int gfx_v10_0_cp_gfx_start(struct amdgpu_device *adev)
        amdgpu_ring_commit(ring);
 
        /* submit cs packet to copy state 0 to next available state */
-       ring = &adev->gfx.gfx_ring[1];
-       r = amdgpu_ring_alloc(ring, 2);
-       if (r) {
-               DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r);
-               return r;
-       }
-
-       amdgpu_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0));
-       amdgpu_ring_write(ring, 0);
+       if (adev->gfx.num_gfx_rings > 1) {
+               /* maximum supported gfx ring is 2 */
+               ring = &adev->gfx.gfx_ring[1];
+               r = amdgpu_ring_alloc(ring, 2);
+               if (r) {
+                       DRM_ERROR("amdgpu: cp failed to lock ring (%d).\n", r);
+                       return r;
+               }
 
-       amdgpu_ring_commit(ring);
+               amdgpu_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0));
+               amdgpu_ring_write(ring, 0);
 
+               amdgpu_ring_commit(ring);
+       }
        return 0;
 }
 
@@ -2818,39 +2820,41 @@ static int gfx_v10_0_cp_gfx_resume(struct amdgpu_device *adev)
        mutex_unlock(&adev->srbm_mutex);
 
        /* Init gfx ring 1 for pipe 1 */
-       mutex_lock(&adev->srbm_mutex);
-       gfx_v10_0_cp_gfx_switch_pipe(adev, PIPE_ID1);
-       ring = &adev->gfx.gfx_ring[1];
-       rb_bufsz = order_base_2(ring->ring_size / 8);
-       tmp = REG_SET_FIELD(0, CP_RB1_CNTL, RB_BUFSZ, rb_bufsz);
-       tmp = REG_SET_FIELD(tmp, CP_RB1_CNTL, RB_BLKSZ, rb_bufsz - 2);
-       WREG32_SOC15(GC, 0, mmCP_RB1_CNTL, tmp);
-       /* Initialize the ring buffer's write pointers */
-       ring->wptr = 0;
-       WREG32_SOC15(GC, 0, mmCP_RB1_WPTR, lower_32_bits(ring->wptr));
-       WREG32_SOC15(GC, 0, mmCP_RB1_WPTR_HI, upper_32_bits(ring->wptr));
-       /* Set the wb address wether it's enabled or not */
-       rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
-       WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
-       WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) &
-               CP_RB1_RPTR_ADDR_HI__RB_RPTR_ADDR_HI_MASK);
-       wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
-       WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_LO,
-               lower_32_bits(wptr_gpu_addr));
-       WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_HI,
-               upper_32_bits(wptr_gpu_addr));
-
-       mdelay(1);
-       WREG32_SOC15(GC, 0, mmCP_RB1_CNTL, tmp);
-
-       rb_addr = ring->gpu_addr >> 8;
-       WREG32_SOC15(GC, 0, mmCP_RB1_BASE, rb_addr);
-       WREG32_SOC15(GC, 0, mmCP_RB1_BASE_HI, upper_32_bits(rb_addr));
-       WREG32_SOC15(GC, 0, mmCP_RB1_ACTIVE, 1);
-
-       gfx_v10_0_cp_gfx_set_doorbell(adev, ring);
-       mutex_unlock(&adev->srbm_mutex);
-
+       if (adev->gfx.num_gfx_rings > 1) {
+               mutex_lock(&adev->srbm_mutex);
+               gfx_v10_0_cp_gfx_switch_pipe(adev, PIPE_ID1);
+               /* maximum supported gfx ring is 2 */
+               ring = &adev->gfx.gfx_ring[1];
+               rb_bufsz = order_base_2(ring->ring_size / 8);
+               tmp = REG_SET_FIELD(0, CP_RB1_CNTL, RB_BUFSZ, rb_bufsz);
+               tmp = REG_SET_FIELD(tmp, CP_RB1_CNTL, RB_BLKSZ, rb_bufsz - 2);
+               WREG32_SOC15(GC, 0, mmCP_RB1_CNTL, tmp);
+               /* Initialize the ring buffer's write pointers */
+               ring->wptr = 0;
+               WREG32_SOC15(GC, 0, mmCP_RB1_WPTR, lower_32_bits(ring->wptr));
+               WREG32_SOC15(GC, 0, mmCP_RB1_WPTR_HI, upper_32_bits(ring->wptr));
+               /* Set the wb address wether it's enabled or not */
+               rptr_addr = adev->wb.gpu_addr + (ring->rptr_offs * 4);
+               WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR, lower_32_bits(rptr_addr));
+               WREG32_SOC15(GC, 0, mmCP_RB1_RPTR_ADDR_HI, upper_32_bits(rptr_addr) &
+                            CP_RB1_RPTR_ADDR_HI__RB_RPTR_ADDR_HI_MASK);
+               wptr_gpu_addr = adev->wb.gpu_addr + (ring->wptr_offs * 4);
+               WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_LO,
+                            lower_32_bits(wptr_gpu_addr));
+               WREG32_SOC15(GC, 0, mmCP_RB_WPTR_POLL_ADDR_HI,
+                            upper_32_bits(wptr_gpu_addr));
+
+               mdelay(1);
+               WREG32_SOC15(GC, 0, mmCP_RB1_CNTL, tmp);
+
+               rb_addr = ring->gpu_addr >> 8;
+               WREG32_SOC15(GC, 0, mmCP_RB1_BASE, rb_addr);
+               WREG32_SOC15(GC, 0, mmCP_RB1_BASE_HI, upper_32_bits(rb_addr));
+               WREG32_SOC15(GC, 0, mmCP_RB1_ACTIVE, 1);
+
+               gfx_v10_0_cp_gfx_set_doorbell(adev, ring);
+               mutex_unlock(&adev->srbm_mutex);
+       }
        /* Switch to pipe 0 */
        mutex_lock(&adev->srbm_mutex);
        gfx_v10_0_cp_gfx_switch_pipe(adev, PIPE_ID0);
@@ -3513,6 +3517,7 @@ static int gfx_v10_0_kcq_init_queue(struct amdgpu_ring *ring)
 
                /* reset ring buffer */
                ring->wptr = 0;
+               atomic64_set((atomic64_t *)&adev->wb.wb[ring->wptr_offs], 0);
                amdgpu_ring_clear_ring(ring);
        } else {
                amdgpu_ring_clear_ring(ring);
@@ -3966,7 +3971,8 @@ static int gfx_v10_0_early_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       adev->gfx.num_gfx_rings = GFX10_NUM_GFX_RINGS;
+       adev->gfx.num_gfx_rings = GFX10_NUM_GFX_RINGS_NV1X;
+
        adev->gfx.num_compute_rings = AMDGPU_MAX_COMPUTE_RINGS;
 
        gfx_v10_0_set_kiq_pm4_funcs(adev);
index 3afdbbd..889154a 100644 (file)
@@ -3663,6 +3663,7 @@ static int gfx_v9_0_kcq_init_queue(struct amdgpu_ring *ring)
 
                /* reset ring buffer */
                ring->wptr = 0;
+               atomic64_set((atomic64_t *)&adev->wb.wb[ring->wptr_offs], 0);
                amdgpu_ring_clear_ring(ring);
        } else {
                amdgpu_ring_clear_ring(ring);
index 90216ab..cc0c273 100644 (file)
@@ -1272,6 +1272,19 @@ static void gmc_v9_0_init_golden_registers(struct amdgpu_device *adev)
 }
 
 /**
+ * gmc_v9_0_restore_registers - restores regs
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * This restores register values, saved at suspend.
+ */
+static void gmc_v9_0_restore_registers(struct amdgpu_device *adev)
+{
+       if (adev->asic_type == CHIP_RAVEN)
+               WREG32(mmDCHUBBUB_SDPIF_MMIO_CNTRL_0, adev->gmc.sdpif_register);
+}
+
+/**
  * gmc_v9_0_gart_enable - gart enable
  *
  * @adev: amdgpu_device pointer
@@ -1377,6 +1390,20 @@ static int gmc_v9_0_hw_init(void *handle)
 }
 
 /**
+ * gmc_v9_0_save_registers - saves regs
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * This saves potential register values that should be
+ * restored upon resume
+ */
+static void gmc_v9_0_save_registers(struct amdgpu_device *adev)
+{
+       if (adev->asic_type == CHIP_RAVEN)
+               adev->gmc.sdpif_register = RREG32(mmDCHUBBUB_SDPIF_MMIO_CNTRL_0);
+}
+
+/**
  * gmc_v9_0_gart_disable - gart disable
  *
  * @adev: amdgpu_device pointer
@@ -1412,9 +1439,16 @@ static int gmc_v9_0_hw_fini(void *handle)
 
 static int gmc_v9_0_suspend(void *handle)
 {
+       int r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
-       return gmc_v9_0_hw_fini(adev);
+       r = gmc_v9_0_hw_fini(adev);
+       if (r)
+               return r;
+
+       gmc_v9_0_save_registers(adev);
+
+       return 0;
 }
 
 static int gmc_v9_0_resume(void *handle)
@@ -1422,6 +1456,7 @@ static int gmc_v9_0_resume(void *handle)
        int r;
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
+       gmc_v9_0_restore_registers(adev);
        r = gmc_v9_0_hw_init(adev);
        if (r)
                return r;
index ff2e6e1..6173951 100644 (file)
@@ -693,7 +693,7 @@ static int jpeg_v2_0_set_clockgating_state(void *handle,
        bool enable = (state == AMD_CG_STATE_GATE);
 
        if (enable) {
-               if (jpeg_v2_0_is_idle(handle))
+               if (!jpeg_v2_0_is_idle(handle))
                        return -EBUSY;
                jpeg_v2_0_enable_clock_gating(adev);
        } else {
index c6d046d..c04c207 100644 (file)
@@ -477,7 +477,7 @@ static int jpeg_v2_5_set_clockgating_state(void *handle,
                        continue;
 
                if (enable) {
-                       if (jpeg_v2_5_is_idle(handle))
+                       if (!jpeg_v2_5_is_idle(handle))
                                return -EBUSY;
                        jpeg_v2_5_enable_clock_gating(adev, i);
                } else {
index 2b488df..d8945c3 100644 (file)
 #define HDP_MEM_POWER_CTRL__RC_MEM_POWER_CTRL_EN_MASK  0x00010000L
 #define HDP_MEM_POWER_CTRL__RC_MEM_POWER_LS_EN_MASK            0x00020000L
 #define mmHDP_MEM_POWER_CTRL_BASE_IDX  0
+
+/* for Vega20/arcturus regiter offset change */
+#define        mmROM_INDEX_VG20                                0x00e4
+#define        mmROM_INDEX_VG20_BASE_IDX                       0
+#define        mmROM_DATA_VG20                                 0x00e5
+#define        mmROM_DATA_VG20_BASE_IDX                        0
+
 /*
  * Indirect registers accessor
  */
@@ -309,6 +316,8 @@ static bool soc15_read_bios_from_rom(struct amdgpu_device *adev,
 {
        u32 *dw_ptr;
        u32 i, length_dw;
+       uint32_t rom_index_offset;
+       uint32_t rom_data_offset;
 
        if (bios == NULL)
                return false;
@@ -321,11 +330,23 @@ static bool soc15_read_bios_from_rom(struct amdgpu_device *adev,
        dw_ptr = (u32 *)bios;
        length_dw = ALIGN(length_bytes, 4) / 4;
 
+       switch (adev->asic_type) {
+       case CHIP_VEGA20:
+       case CHIP_ARCTURUS:
+               rom_index_offset = SOC15_REG_OFFSET(SMUIO, 0, mmROM_INDEX_VG20);
+               rom_data_offset = SOC15_REG_OFFSET(SMUIO, 0, mmROM_DATA_VG20);
+               break;
+       default:
+               rom_index_offset = SOC15_REG_OFFSET(SMUIO, 0, mmROM_INDEX);
+               rom_data_offset = SOC15_REG_OFFSET(SMUIO, 0, mmROM_DATA);
+               break;
+       }
+
        /* set rom index to 0 */
-       WREG32(SOC15_REG_OFFSET(SMUIO, 0, mmROM_INDEX), 0);
+       WREG32(rom_index_offset, 0);
        /* read out the rom data */
        for (i = 0; i < length_dw; i++)
-               dw_ptr[i] = RREG32(SOC15_REG_OFFSET(SMUIO, 0, mmROM_DATA));
+               dw_ptr[i] = RREG32(rom_data_offset);
 
        return true;
 }
index 71f61af..09b0572 100644 (file)
@@ -1352,7 +1352,7 @@ static int vcn_v1_0_set_clockgating_state(void *handle,
 
        if (enable) {
                /* wait for STATUS to clear */
-               if (vcn_v1_0_is_idle(handle))
+               if (!vcn_v1_0_is_idle(handle))
                        return -EBUSY;
                vcn_v1_0_enable_clock_gating(adev);
        } else {
index c387c81..b7f1734 100644 (file)
@@ -1217,7 +1217,7 @@ static int vcn_v2_0_set_clockgating_state(void *handle,
 
        if (enable) {
                /* wait for STATUS to clear */
-               if (vcn_v2_0_is_idle(handle))
+               if (!vcn_v2_0_is_idle(handle))
                        return -EBUSY;
                vcn_v2_0_enable_clock_gating(adev);
        } else {
index 2d64ba1..678253d 100644 (file)
@@ -1672,7 +1672,7 @@ static int vcn_v2_5_set_clockgating_state(void *handle,
                return 0;
 
        if (enable) {
-               if (vcn_v2_5_is_idle(handle))
+               if (!vcn_v2_5_is_idle(handle))
                        return -EBUSY;
                vcn_v2_5_enable_clock_gating(adev);
        } else {
index e8f66fb..6240259 100644 (file)
@@ -522,8 +522,9 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)
 
        acrtc_state = to_dm_crtc_state(acrtc->base.state);
 
-       DRM_DEBUG_DRIVER("crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id,
-                               amdgpu_dm_vrr_active(acrtc_state));
+       DRM_DEBUG_DRIVER("crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id,
+                        amdgpu_dm_vrr_active(acrtc_state),
+                        acrtc_state->active_planes);
 
        amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
        drm_crtc_handle_vblank(&acrtc->base);
@@ -543,7 +544,18 @@ static void dm_dcn_crtc_high_irq(void *interrupt_params)
                        &acrtc_state->vrr_params.adjust);
        }
 
-       if (acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED) {
+       /*
+        * If there aren't any active_planes then DCH HUBP may be clock-gated.
+        * In that case, pageflip completion interrupts won't fire and pageflip
+        * completion events won't get delivered. Prevent this by sending
+        * pending pageflip events from here if a flip is still pending.
+        *
+        * If any planes are enabled, use dm_pflip_high_irq() instead, to
+        * avoid race conditions between flip programming and completion,
+        * which could cause too early flip completion events.
+        */
+       if (acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED &&
+           acrtc_state->active_planes == 0) {
                if (acrtc->event) {
                        drm_crtc_send_vblank_event(&acrtc->base, acrtc->event);
                        acrtc->event = NULL;
@@ -1422,6 +1434,73 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
                drm_kms_helper_hotplug_event(dev);
 }
 
+static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
+{
+       struct smu_context *smu = &adev->smu;
+       int ret = 0;
+
+       if (!is_support_sw_smu(adev))
+               return 0;
+
+       /* This interface is for dGPU Navi1x.Linux dc-pplib interface depends
+        * on window driver dc implementation.
+        * For Navi1x, clock settings of dcn watermarks are fixed. the settings
+        * should be passed to smu during boot up and resume from s3.
+        * boot up: dc calculate dcn watermark clock settings within dc_create,
+        * dcn20_resource_construct
+        * then call pplib functions below to pass the settings to smu:
+        * smu_set_watermarks_for_clock_ranges
+        * smu_set_watermarks_table
+        * navi10_set_watermarks_table
+        * smu_write_watermarks_table
+        *
+        * For Renoir, clock settings of dcn watermark are also fixed values.
+        * dc has implemented different flow for window driver:
+        * dc_hardware_init / dc_set_power_state
+        * dcn10_init_hw
+        * notify_wm_ranges
+        * set_wm_ranges
+        * -- Linux
+        * smu_set_watermarks_for_clock_ranges
+        * renoir_set_watermarks_table
+        * smu_write_watermarks_table
+        *
+        * For Linux,
+        * dc_hardware_init -> amdgpu_dm_init
+        * dc_set_power_state --> dm_resume
+        *
+        * therefore, this function apply to navi10/12/14 but not Renoir
+        * *
+        */
+       switch(adev->asic_type) {
+       case CHIP_NAVI10:
+       case CHIP_NAVI14:
+       case CHIP_NAVI12:
+               break;
+       default:
+               return 0;
+       }
+
+       mutex_lock(&smu->mutex);
+
+       /* pass data to smu controller */
+       if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
+                       !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
+               ret = smu_write_watermarks_table(smu);
+
+               if (ret) {
+                       mutex_unlock(&smu->mutex);
+                       DRM_ERROR("Failed to update WMTABLE!\n");
+                       return ret;
+               }
+               smu->watermarks_bitmap |= WATERMARKS_LOADED;
+       }
+
+       mutex_unlock(&smu->mutex);
+
+       return 0;
+}
+
 /**
  * dm_hw_init() - Initialize DC device
  * @handle: The base driver device containing the amdgpu_dm device.
@@ -1700,6 +1779,8 @@ static int dm_resume(void *handle)
 
        amdgpu_dm_irq_resume_late(adev);
 
+       amdgpu_dm_smu_write_watermarks_table(adev);
+
        return 0;
 }
 
index 5672f77..da73161 100644 (file)
@@ -451,6 +451,7 @@ static void dm_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr,
                                           aconnector->dc_sink);
                dc_sink_release(aconnector->dc_sink);
                aconnector->dc_sink = NULL;
+               aconnector->dc_link->cur_link_settings.lane_count = 0;
        }
 
        drm_connector_unregister(connector);
index cb731c1..fd9e696 100644 (file)
@@ -3401,6 +3401,17 @@ static bool retrieve_link_cap(struct dc_link *link)
                sink_id.ieee_device_id,
                sizeof(sink_id.ieee_device_id));
 
+       /* Quirk Apple MBP 2017 15" Retina panel: Wrong DP_MAX_LINK_RATE */
+       {
+               uint8_t str_mbp_2017[] = { 101, 68, 21, 101, 98, 97 };
+
+               if ((link->dpcd_caps.sink_dev_id == 0x0010fa) &&
+                   !memcmp(link->dpcd_caps.sink_dev_id_str, str_mbp_2017,
+                           sizeof(str_mbp_2017))) {
+                       link->reported_link_cap.link_rate = 0x0c;
+               }
+       }
+
        core_link_read_dpcd(
                link,
                DP_SINK_HW_REVISION_START,
index f36a0d8..446ba0a 100644 (file)
@@ -840,8 +840,8 @@ static void hubbub1_det_request_size(
 
        hubbub1_get_blk256_size(&blk256_width, &blk256_height, bpe);
 
-       swath_bytes_horz_wc = height * blk256_height * bpe;
-       swath_bytes_vert_wc = width * blk256_width * bpe;
+       swath_bytes_horz_wc = width * blk256_height * bpe;
+       swath_bytes_vert_wc = height * blk256_width * bpe;
 
        *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ?
                        false : /* full 256B request */
index d51e02f..5e640f1 100644 (file)
@@ -108,7 +108,6 @@ static const struct hwseq_private_funcs dcn20_private_funcs = {
        .enable_power_gating_plane = dcn20_enable_power_gating_plane,
        .dpp_pg_control = dcn20_dpp_pg_control,
        .hubp_pg_control = dcn20_hubp_pg_control,
-       .dsc_pg_control = NULL,
        .update_odm = dcn20_update_odm,
        .dsc_pg_control = dcn20_dsc_pg_control,
        .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color,
index 85f90f3..e310d67 100644 (file)
@@ -335,6 +335,117 @@ struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = {
        .use_urgent_burst_bw = 0
 };
 
+struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc = {
+       .clock_limits = {
+                       {
+                               .state = 0,
+                               .dcfclk_mhz = 560.0,
+                               .fabricclk_mhz = 560.0,
+                               .dispclk_mhz = 513.0,
+                               .dppclk_mhz = 513.0,
+                               .phyclk_mhz = 540.0,
+                               .socclk_mhz = 560.0,
+                               .dscclk_mhz = 171.0,
+                               .dram_speed_mts = 8960.0,
+                       },
+                       {
+                               .state = 1,
+                               .dcfclk_mhz = 694.0,
+                               .fabricclk_mhz = 694.0,
+                               .dispclk_mhz = 642.0,
+                               .dppclk_mhz = 642.0,
+                               .phyclk_mhz = 600.0,
+                               .socclk_mhz = 694.0,
+                               .dscclk_mhz = 214.0,
+                               .dram_speed_mts = 11104.0,
+                       },
+                       {
+                               .state = 2,
+                               .dcfclk_mhz = 875.0,
+                               .fabricclk_mhz = 875.0,
+                               .dispclk_mhz = 734.0,
+                               .dppclk_mhz = 734.0,
+                               .phyclk_mhz = 810.0,
+                               .socclk_mhz = 875.0,
+                               .dscclk_mhz = 245.0,
+                               .dram_speed_mts = 14000.0,
+                       },
+                       {
+                               .state = 3,
+                               .dcfclk_mhz = 1000.0,
+                               .fabricclk_mhz = 1000.0,
+                               .dispclk_mhz = 1100.0,
+                               .dppclk_mhz = 1100.0,
+                               .phyclk_mhz = 810.0,
+                               .socclk_mhz = 1000.0,
+                               .dscclk_mhz = 367.0,
+                               .dram_speed_mts = 16000.0,
+                       },
+                       {
+                               .state = 4,
+                               .dcfclk_mhz = 1200.0,
+                               .fabricclk_mhz = 1200.0,
+                               .dispclk_mhz = 1284.0,
+                               .dppclk_mhz = 1284.0,
+                               .phyclk_mhz = 810.0,
+                               .socclk_mhz = 1200.0,
+                               .dscclk_mhz = 428.0,
+                               .dram_speed_mts = 16000.0,
+                       },
+                       /*Extra state, no dispclk ramping*/
+                       {
+                               .state = 5,
+                               .dcfclk_mhz = 1200.0,
+                               .fabricclk_mhz = 1200.0,
+                               .dispclk_mhz = 1284.0,
+                               .dppclk_mhz = 1284.0,
+                               .phyclk_mhz = 810.0,
+                               .socclk_mhz = 1200.0,
+                               .dscclk_mhz = 428.0,
+                               .dram_speed_mts = 16000.0,
+                       },
+               },
+       .num_states = 5,
+       .sr_exit_time_us = 8.6,
+       .sr_enter_plus_exit_time_us = 10.9,
+       .urgent_latency_us = 4.0,
+       .urgent_latency_pixel_data_only_us = 4.0,
+       .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+       .urgent_latency_vm_data_only_us = 4.0,
+       .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+       .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+       .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+       .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0,
+       .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0,
+       .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
+       .max_avg_sdp_bw_use_normal_percent = 40.0,
+       .max_avg_dram_bw_use_normal_percent = 40.0,
+       .writeback_latency_us = 12.0,
+       .ideal_dram_bw_after_urgent_percent = 40.0,
+       .max_request_size_bytes = 256,
+       .dram_channel_width_bytes = 2,
+       .fabric_datapath_to_dcn_data_return_bytes = 64,
+       .dcn_downspread_percent = 0.5,
+       .downspread_percent = 0.38,
+       .dram_page_open_time_ns = 50.0,
+       .dram_rw_turnaround_time_ns = 17.5,
+       .dram_return_buffer_per_channel_bytes = 8192,
+       .round_trip_ping_latency_dcfclk_cycles = 131,
+       .urgent_out_of_order_return_per_channel_bytes = 256,
+       .channel_interleave_bytes = 256,
+       .num_banks = 8,
+       .num_chans = 8,
+       .vmm_page_size_bytes = 4096,
+       .dram_clock_change_latency_us = 404.0,
+       .dummy_pstate_latency_us = 5.0,
+       .writeback_dram_clock_change_latency_us = 23.0,
+       .return_bus_width_bytes = 64,
+       .dispclk_dppclk_vco_speed_mhz = 3850,
+       .xfc_bus_transport_time_us = 20,
+       .xfc_xbuf_latency_tolerance_us = 4,
+       .use_urgent_burst_bw = 0
+};
+
 struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc = { 0 };
 
 #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL
@@ -3291,6 +3402,9 @@ void dcn20_patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st
 static struct _vcs_dpi_soc_bounding_box_st *get_asic_rev_soc_bb(
        uint32_t hw_internal_rev)
 {
+       if (ASICREV_IS_NAVI14_M(hw_internal_rev))
+               return &dcn2_0_nv14_soc;
+
        if (ASICREV_IS_NAVI12_P(hw_internal_rev))
                return &dcn2_0_nv12_soc;
 
index 4861aa5..fddbd59 100644 (file)
@@ -116,7 +116,6 @@ static const struct hwseq_private_funcs dcn21_private_funcs = {
        .enable_power_gating_plane = dcn20_enable_power_gating_plane,
        .dpp_pg_control = dcn20_dpp_pg_control,
        .hubp_pg_control = dcn20_hubp_pg_control,
-       .dsc_pg_control = NULL,
        .update_odm = dcn20_update_odm,
        .dsc_pg_control = dcn20_dsc_pg_control,
        .get_surface_visual_confirm_color = dcn10_get_surface_visual_confirm_color,
index b6f74bf..27bb8c1 100644 (file)
 #define mmCRTC4_CRTC_DRR_CONTROL                                                                       0x0f3e
 #define mmCRTC4_CRTC_DRR_CONTROL_BASE_IDX                                                              2
 
+#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0                                                                  0x395d
+#define mmDCHUBBUB_SDPIF_MMIO_CNTRL_0_BASE_IDX                                                         2
 
 // addressBlock: dce_dc_fmt4_dispdec
 // base address: 0x2000
index 99ad4dd..96e81c7 100644 (file)
@@ -222,7 +222,7 @@ int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type,
 {
        int ret = 0;
 
-       if (min <= 0 && max <= 0)
+       if (min < 0 && max < 0)
                return -EINVAL;
 
        if (!smu_clk_dpm_is_enabled(smu, clk_type))
@@ -2006,8 +2006,11 @@ int smu_set_watermarks_for_clock_ranges(struct smu_context *smu,
                        smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
                        smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
                smu_set_watermarks_table(smu, table, clock_ranges);
-               smu->watermarks_bitmap |= WATERMARKS_EXIST;
-               smu->watermarks_bitmap &= ~WATERMARKS_LOADED;
+
+               if (!(smu->watermarks_bitmap & WATERMARKS_EXIST)) {
+                       smu->watermarks_bitmap |= WATERMARKS_EXIST;
+                       smu->watermarks_bitmap &= ~WATERMARKS_LOADED;
+               }
        }
 
        mutex_unlock(&smu->mutex);
index 0d73a49..aed4d6e 100644 (file)
@@ -1063,15 +1063,6 @@ static int navi10_display_config_changed(struct smu_context *smu)
        int ret = 0;
 
        if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
-           !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
-               ret = smu_write_watermarks_table(smu);
-               if (ret)
-                       return ret;
-
-               smu->watermarks_bitmap |= WATERMARKS_LOADED;
-       }
-
-       if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
            smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
            smu_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
                ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays,
@@ -1493,6 +1484,7 @@ static int navi10_set_watermarks_table(struct smu_context *smu,
                                       *clock_ranges)
 {
        int i;
+       int ret = 0;
        Watermarks_t *table = watermarks;
 
        if (!table || !clock_ranges)
@@ -1544,6 +1536,18 @@ static int navi10_set_watermarks_table(struct smu_context *smu,
                                clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
        }
 
+       smu->watermarks_bitmap |= WATERMARKS_EXIST;
+
+       /* pass data to smu controller */
+       if (!(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
+               ret = smu_write_watermarks_table(smu);
+               if (ret) {
+                       pr_err("Failed to update WMTABLE!");
+                       return ret;
+               }
+               smu->watermarks_bitmap |= WATERMARKS_LOADED;
+       }
+
        return 0;
 }
 
index 861e641..3ad0f4a 100644 (file)
@@ -111,8 +111,8 @@ static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = {
        CLK_MAP(GFXCLK, CLOCK_GFXCLK),
        CLK_MAP(SCLK,   CLOCK_GFXCLK),
        CLK_MAP(SOCCLK, CLOCK_SOCCLK),
-       CLK_MAP(UCLK, CLOCK_UMCCLK),
-       CLK_MAP(MCLK, CLOCK_UMCCLK),
+       CLK_MAP(UCLK, CLOCK_FCLK),
+       CLK_MAP(MCLK, CLOCK_FCLK),
 };
 
 static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = {
@@ -280,7 +280,7 @@ static int renoir_print_clk_levels(struct smu_context *smu,
                break;
        case SMU_MCLK:
                count = NUM_MEMCLK_DPM_LEVELS;
-               cur_value = metrics.ClockFrequency[CLOCK_UMCCLK];
+               cur_value = metrics.ClockFrequency[CLOCK_FCLK];
                break;
        case SMU_DCEFCLK:
                count = NUM_DCFCLK_DPM_LEVELS;
@@ -806,9 +806,10 @@ static int renoir_set_watermarks_table(
                                clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
        }
 
+       smu->watermarks_bitmap |= WATERMARKS_EXIST;
+
        /* pass data to smu controller */
-       if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
-                       !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
+       if (!(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
                ret = smu_write_watermarks_table(smu);
                if (ret) {
                        pr_err("Failed to update WMTABLE!");
index b06c057..c9e5ce1 100644 (file)
@@ -978,8 +978,12 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu)
        struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks;
        int ret = 0;
 
-       max_sustainable_clocks = kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks),
+       if (!smu->smu_table.max_sustainable_clocks)
+               max_sustainable_clocks = kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks),
                                         GFP_KERNEL);
+       else
+               max_sustainable_clocks = smu->smu_table.max_sustainable_clocks;
+
        smu->smu_table.max_sustainable_clocks = (void *)max_sustainable_clocks;
 
        max_sustainable_clocks->uclock = smu->smu_table.boot_values.uclk / 100;
index 870e6db..518e659 100644 (file)
@@ -458,9 +458,6 @@ int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_
 {
        int ret = 0;
 
-       if (max < min)
-               return -EINVAL;
-
        switch (clk_type) {
        case SMU_GFXCLK:
        case SMU_SCLK:
index ea5cd1e..e793393 100644 (file)
@@ -146,14 +146,14 @@ static const struct of_device_id komeda_of_match[] = {
 
 MODULE_DEVICE_TABLE(of, komeda_of_match);
 
-static int komeda_rt_pm_suspend(struct device *dev)
+static int __maybe_unused komeda_rt_pm_suspend(struct device *dev)
 {
        struct komeda_drv *mdrv = dev_get_drvdata(dev);
 
        return komeda_dev_suspend(mdrv->mdev);
 }
 
-static int komeda_rt_pm_resume(struct device *dev)
+static int __maybe_unused komeda_rt_pm_resume(struct device *dev)
 {
        struct komeda_drv *mdrv = dev_get_drvdata(dev);
 
index b615b7d..a4fc4e6 100644 (file)
@@ -156,10 +156,8 @@ int bochs_hw_init(struct drm_device *dev)
                size = min(size, mem);
        }
 
-       if (pci_request_region(pdev, 0, "bochs-drm") != 0) {
-               DRM_ERROR("Cannot request framebuffer\n");
-               return -EBUSY;
-       }
+       if (pci_request_region(pdev, 0, "bochs-drm") != 0)
+               DRM_WARN("Cannot request framebuffer, boot fb still active?\n");
 
        bochs->fb_map = ioremap(addr, size);
        if (bochs->fb_map == NULL) {
index 56f55c5..2dfa2fd 100644 (file)
@@ -210,8 +210,7 @@ static int anx6345_dp_link_training(struct anx6345 *anx6345)
        if (err)
                return err;
 
-       dpcd[0] = drm_dp_max_link_rate(anx6345->dpcd);
-       dpcd[0] = drm_dp_link_rate_to_bw_code(dpcd[0]);
+       dpcd[0] = dp_bw;
        err = regmap_write(anx6345->map[I2C_IDX_DPTX],
                           SP_DP_MAIN_LINK_BW_SET_REG, dpcd[0]);
        if (err)
index 67fca43..24965e5 100644 (file)
@@ -1624,28 +1624,34 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
                frame.colorspace = HDMI_COLORSPACE_RGB;
 
        /* Set up colorimetry */
-       switch (hdmi->hdmi_data.enc_out_encoding) {
-       case V4L2_YCBCR_ENC_601:
-               if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
-                       frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
-               else
+       if (!hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
+               switch (hdmi->hdmi_data.enc_out_encoding) {
+               case V4L2_YCBCR_ENC_601:
+                       if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
+                               frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
+                       else
+                               frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
+                       frame.extended_colorimetry =
+                                       HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+                       break;
+               case V4L2_YCBCR_ENC_709:
+                       if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
+                               frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
+                       else
+                               frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
+                       frame.extended_colorimetry =
+                                       HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
+                       break;
+               default: /* Carries no data */
                        frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
+                       frame.extended_colorimetry =
+                                       HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+                       break;
+               }
+       } else {
+               frame.colorimetry = HDMI_COLORIMETRY_NONE;
                frame.extended_colorimetry =
-                               HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
-               break;
-       case V4L2_YCBCR_ENC_709:
-               if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
-                       frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
-               else
-                       frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
-               frame.extended_colorimetry =
-                               HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
-               break;
-       default: /* Carries no data */
-               frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
-               frame.extended_colorimetry =
-                               HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
-               break;
+                       HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
        }
 
        frame.scan_mode = HDMI_SCAN_MODE_NONE;
index cce0b1b..ed0fea2 100644 (file)
@@ -1935,7 +1935,7 @@ static u8 drm_dp_calculate_rad(struct drm_dp_mst_port *port,
        return parent_lct + 1;
 }
 
-static bool drm_dp_mst_is_dp_mst_end_device(u8 pdt, bool mcs)
+static bool drm_dp_mst_is_end_device(u8 pdt, bool mcs)
 {
        switch (pdt) {
        case DP_PEER_DEVICE_DP_LEGACY_CONV:
@@ -1965,13 +1965,13 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt,
 
        /* Teardown the old pdt, if there is one */
        if (port->pdt != DP_PEER_DEVICE_NONE) {
-               if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
+               if (drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
                        /*
                         * If the new PDT would also have an i2c bus,
                         * don't bother with reregistering it
                         */
                        if (new_pdt != DP_PEER_DEVICE_NONE &&
-                           drm_dp_mst_is_dp_mst_end_device(new_pdt, new_mcs)) {
+                           drm_dp_mst_is_end_device(new_pdt, new_mcs)) {
                                port->pdt = new_pdt;
                                port->mcs = new_mcs;
                                return 0;
@@ -1991,7 +1991,7 @@ drm_dp_port_set_pdt(struct drm_dp_mst_port *port, u8 new_pdt,
        port->mcs = new_mcs;
 
        if (port->pdt != DP_PEER_DEVICE_NONE) {
-               if (drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
+               if (drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
                        /* add i2c over sideband */
                        ret = drm_dp_mst_register_i2c_bus(&port->aux);
                } else {
@@ -2172,7 +2172,7 @@ drm_dp_mst_port_add_connector(struct drm_dp_mst_branch *mstb,
        }
 
        if (port->pdt != DP_PEER_DEVICE_NONE &&
-           drm_dp_mst_is_dp_mst_end_device(port->pdt, port->mcs)) {
+           drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
                port->cached_edid = drm_get_edid(port->connector,
                                                 &port->aux.ddc);
                drm_connector_set_tile_property(port->connector);
@@ -2302,14 +2302,18 @@ drm_dp_mst_handle_link_address_port(struct drm_dp_mst_branch *mstb,
                mutex_unlock(&mgr->lock);
        }
 
-       if (old_ddps != port->ddps) {
-               if (port->ddps) {
-                       if (!port->input) {
-                               drm_dp_send_enum_path_resources(mgr, mstb,
-                                                               port);
-                       }
+       /*
+        * Reprobe PBN caps on both hotplug, and when re-probing the link
+        * for our parent mstb
+        */
+       if (old_ddps != port->ddps || !created) {
+               if (port->ddps && !port->input) {
+                       ret = drm_dp_send_enum_path_resources(mgr, mstb,
+                                                             port);
+                       if (ret == 1)
+                               changed = true;
                } else {
-                       port->available_pbn = 0;
+                       port->full_pbn = 0;
                }
        }
 
@@ -2401,11 +2405,10 @@ drm_dp_mst_handle_conn_stat(struct drm_dp_mst_branch *mstb,
        port->ddps = conn_stat->displayport_device_plug_status;
 
        if (old_ddps != port->ddps) {
-               if (port->ddps) {
-                       dowork = true;
-               } else {
-                       port->available_pbn = 0;
-               }
+               if (port->ddps && !port->input)
+                       drm_dp_send_enum_path_resources(mgr, mstb, port);
+               else
+                       port->full_pbn = 0;
        }
 
        new_pdt = port->input ? DP_PEER_DEVICE_NONE : conn_stat->peer_device_type;
@@ -2556,13 +2559,6 @@ static int drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *mg
                if (port->input || !port->ddps)
                        continue;
 
-               if (!port->available_pbn) {
-                       drm_modeset_lock(&mgr->base.lock, NULL);
-                       drm_dp_send_enum_path_resources(mgr, mstb, port);
-                       drm_modeset_unlock(&mgr->base.lock);
-                       changed = true;
-               }
-
                if (port->mstb)
                        mstb_child = drm_dp_mst_topology_get_mstb_validated(
                            mgr, port->mstb);
@@ -2990,6 +2986,7 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
 
        ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
        if (ret > 0) {
+               ret = 0;
                path_res = &txmsg->reply.u.path_resources;
 
                if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
@@ -3002,14 +2999,22 @@ drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
                                      path_res->port_number,
                                      path_res->full_payload_bw_number,
                                      path_res->avail_payload_bw_number);
-                       port->available_pbn =
-                               path_res->avail_payload_bw_number;
+
+                       /*
+                        * If something changed, make sure we send a
+                        * hotplug
+                        */
+                       if (port->full_pbn != path_res->full_payload_bw_number ||
+                           port->fec_capable != path_res->fec_capable)
+                               ret = 1;
+
+                       port->full_pbn = path_res->full_payload_bw_number;
                        port->fec_capable = path_res->fec_capable;
                }
        }
 
        kfree(txmsg);
-       return 0;
+       return ret;
 }
 
 static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb)
@@ -3596,13 +3601,9 @@ drm_dp_mst_topology_mgr_invalidate_mstb(struct drm_dp_mst_branch *mstb)
        /* The link address will need to be re-sent on resume */
        mstb->link_address_sent = false;
 
-       list_for_each_entry(port, &mstb->ports, next) {
-               /* The PBN for each port will also need to be re-probed */
-               port->available_pbn = 0;
-
+       list_for_each_entry(port, &mstb->ports, next)
                if (port->mstb)
                        drm_dp_mst_topology_mgr_invalidate_mstb(port->mstb);
-       }
 }
 
 /**
@@ -4829,41 +4830,102 @@ static bool drm_dp_mst_port_downstream_of_branch(struct drm_dp_mst_port *port,
        return false;
 }
 
-static inline
-int drm_dp_mst_atomic_check_bw_limit(struct drm_dp_mst_branch *branch,
-                                    struct drm_dp_mst_topology_state *mst_state)
+static int
+drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port,
+                                     struct drm_dp_mst_topology_state *state);
+
+static int
+drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb,
+                                     struct drm_dp_mst_topology_state *state)
 {
-       struct drm_dp_mst_port *port;
        struct drm_dp_vcpi_allocation *vcpi;
-       int pbn_limit = 0, pbn_used = 0;
+       struct drm_dp_mst_port *port;
+       int pbn_used = 0, ret;
+       bool found = false;
 
-       list_for_each_entry(port, &branch->ports, next) {
-               if (port->mstb)
-                       if (drm_dp_mst_atomic_check_bw_limit(port->mstb, mst_state))
-                               return -ENOSPC;
+       /* Check that we have at least one port in our state that's downstream
+        * of this branch, otherwise we can skip this branch
+        */
+       list_for_each_entry(vcpi, &state->vcpis, next) {
+               if (!vcpi->pbn ||
+                   !drm_dp_mst_port_downstream_of_branch(vcpi->port, mstb))
+                       continue;
 
-               if (port->available_pbn > 0)
-                       pbn_limit = port->available_pbn;
+               found = true;
+               break;
        }
-       DRM_DEBUG_ATOMIC("[MST BRANCH:%p] branch has %d PBN available\n",
-                        branch, pbn_limit);
+       if (!found)
+               return 0;
 
-       list_for_each_entry(vcpi, &mst_state->vcpis, next) {
-               if (!vcpi->pbn)
-                       continue;
+       if (mstb->port_parent)
+               DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] Checking bandwidth limits on [MSTB:%p]\n",
+                                mstb->port_parent->parent, mstb->port_parent,
+                                mstb);
+       else
+               DRM_DEBUG_ATOMIC("[MSTB:%p] Checking bandwidth limits\n",
+                                mstb);
+
+       list_for_each_entry(port, &mstb->ports, next) {
+               ret = drm_dp_mst_atomic_check_port_bw_limit(port, state);
+               if (ret < 0)
+                       return ret;
 
-               if (drm_dp_mst_port_downstream_of_branch(vcpi->port, branch))
-                       pbn_used += vcpi->pbn;
+               pbn_used += ret;
        }
-       DRM_DEBUG_ATOMIC("[MST BRANCH:%p] branch used %d PBN\n",
-                        branch, pbn_used);
 
-       if (pbn_used > pbn_limit) {
-               DRM_DEBUG_ATOMIC("[MST BRANCH:%p] No available bandwidth\n",
-                                branch);
+       return pbn_used;
+}
+
+static int
+drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port,
+                                     struct drm_dp_mst_topology_state *state)
+{
+       struct drm_dp_vcpi_allocation *vcpi;
+       int pbn_used = 0;
+
+       if (port->pdt == DP_PEER_DEVICE_NONE)
+               return 0;
+
+       if (drm_dp_mst_is_end_device(port->pdt, port->mcs)) {
+               bool found = false;
+
+               list_for_each_entry(vcpi, &state->vcpis, next) {
+                       if (vcpi->port != port)
+                               continue;
+                       if (!vcpi->pbn)
+                               return 0;
+
+                       found = true;
+                       break;
+               }
+               if (!found)
+                       return 0;
+
+               /* This should never happen, as it means we tried to
+                * set a mode before querying the full_pbn
+                */
+               if (WARN_ON(!port->full_pbn))
+                       return -EINVAL;
+
+               pbn_used = vcpi->pbn;
+       } else {
+               pbn_used = drm_dp_mst_atomic_check_mstb_bw_limit(port->mstb,
+                                                                state);
+               if (pbn_used <= 0)
+                       return pbn_used;
+       }
+
+       if (pbn_used > port->full_pbn) {
+               DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] required PBN of %d exceeds port limit of %d\n",
+                                port->parent, port, pbn_used,
+                                port->full_pbn);
                return -ENOSPC;
        }
-       return 0;
+
+       DRM_DEBUG_ATOMIC("[MSTB:%p] [MST PORT:%p] uses %d out of %d PBN\n",
+                        port->parent, port, pbn_used, port->full_pbn);
+
+       return pbn_used;
 }
 
 static inline int
@@ -5061,9 +5123,15 @@ int drm_dp_mst_atomic_check(struct drm_atomic_state *state)
                ret = drm_dp_mst_atomic_check_vcpi_alloc_limit(mgr, mst_state);
                if (ret)
                        break;
-               ret = drm_dp_mst_atomic_check_bw_limit(mgr->mst_primary, mst_state);
-               if (ret)
+
+               mutex_lock(&mgr->lock);
+               ret = drm_dp_mst_atomic_check_mstb_bw_limit(mgr->mst_primary,
+                                                           mst_state);
+               mutex_unlock(&mgr->lock);
+               if (ret < 0)
                        break;
+               else
+                       ret = 0;
        }
 
        return ret;
index a421a2e..df31e57 100644 (file)
@@ -254,11 +254,16 @@ static void *drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem)
        if (ret)
                goto err_zero_use;
 
-       if (obj->import_attach)
+       if (obj->import_attach) {
                shmem->vaddr = dma_buf_vmap(obj->import_attach->dmabuf);
-       else
+       } else {
+               pgprot_t prot = PAGE_KERNEL;
+
+               if (!shmem->map_cached)
+                       prot = pgprot_writecombine(prot);
                shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT,
-                                   VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+                                   VM_MAP, prot);
+       }
 
        if (!shmem->vaddr) {
                DRM_DEBUG_KMS("Failed to vmap pages\n");
@@ -540,8 +545,9 @@ int drm_gem_shmem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
        }
 
        vma->vm_flags |= VM_MIXEDMAP | VM_DONTEXPAND;
-       vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
-       vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
+       vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+       if (!shmem->map_cached)
+               vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
        vma->vm_ops = &drm_gem_shmem_vm_ops;
 
        return 0;
index b481caf..825abe3 100644 (file)
@@ -542,10 +542,12 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
        }
 
        DRM_DEBUG_LEASE("Creating lease\n");
+       /* lessee will take the ownership of leases */
        lessee = drm_lease_create(lessor, &leases);
 
        if (IS_ERR(lessee)) {
                ret = PTR_ERR(lessee);
+               idr_destroy(&leases);
                goto out_leases;
        }
 
@@ -580,7 +582,6 @@ out_lessee:
 
 out_leases:
        put_unused_fd(fd);
-       idr_destroy(&leases);
 
        DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret);
        return ret;
index 86d9b0e..1de2cde 100644 (file)
@@ -967,7 +967,7 @@ int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
 
        index = 0;
        for_each_sg(sgt->sgl, sg, sgt->nents, count) {
-               len = sg->length;
+               len = sg_dma_len(sg);
                page = sg_page(sg);
                addr = sg_dma_address(sg);
 
index 8428ae1..1f79bc2 100644 (file)
@@ -55,6 +55,7 @@ static const char * const decon_clks_name[] = {
 struct decon_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
+       void                            *dma_priv;
        struct exynos_drm_crtc          *crtc;
        struct exynos_drm_plane         planes[WINDOWS_NR];
        struct exynos_drm_plane_config  configs[WINDOWS_NR];
@@ -644,7 +645,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data)
 
        decon_clear_channels(ctx->crtc);
 
-       return exynos_drm_register_dma(drm_dev, dev);
+       return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
 }
 
 static void decon_unbind(struct device *dev, struct device *master, void *data)
@@ -654,7 +655,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data)
        decon_atomic_disable(ctx->crtc);
 
        /* detach this sub driver from iommu mapping if supported. */
-       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
+       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
 }
 
 static const struct component_ops decon_component_ops = {
index ff59c64..1eed332 100644 (file)
@@ -40,6 +40,7 @@
 struct decon_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
+       void                            *dma_priv;
        struct exynos_drm_crtc          *crtc;
        struct exynos_drm_plane         planes[WINDOWS_NR];
        struct exynos_drm_plane_config  configs[WINDOWS_NR];
@@ -127,13 +128,13 @@ static int decon_ctx_initialize(struct decon_context *ctx,
 
        decon_clear_channels(ctx->crtc);
 
-       return exynos_drm_register_dma(drm_dev, ctx->dev);
+       return exynos_drm_register_dma(drm_dev, ctx->dev, &ctx->dma_priv);
 }
 
 static void decon_ctx_remove(struct decon_context *ctx)
 {
        /* detach this sub driver from iommu mapping if supported. */
-       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
+       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
 }
 
 static u32 decon_calc_clkdiv(struct decon_context *ctx,
index 9ebc027..619f814 100644 (file)
@@ -58,7 +58,7 @@ static inline void clear_dma_max_seg_size(struct device *dev)
  * mapping.
  */
 static int drm_iommu_attach_device(struct drm_device *drm_dev,
-                               struct device *subdrv_dev)
+                               struct device *subdrv_dev, void **dma_priv)
 {
        struct exynos_drm_private *priv = drm_dev->dev_private;
        int ret;
@@ -74,7 +74,14 @@ static int drm_iommu_attach_device(struct drm_device *drm_dev,
                return ret;
 
        if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
-               if (to_dma_iommu_mapping(subdrv_dev))
+               /*
+                * Keep the original DMA mapping of the sub-device and
+                * restore it on Exynos DRM detach, otherwise the DMA
+                * framework considers it as IOMMU-less during the next
+                * probe (in case of deferred probe or modular build)
+                */
+               *dma_priv = to_dma_iommu_mapping(subdrv_dev);
+               if (*dma_priv)
                        arm_iommu_detach_device(subdrv_dev);
 
                ret = arm_iommu_attach_device(subdrv_dev, priv->mapping);
@@ -98,19 +105,21 @@ static int drm_iommu_attach_device(struct drm_device *drm_dev,
  * mapping
  */
 static void drm_iommu_detach_device(struct drm_device *drm_dev,
-                               struct device *subdrv_dev)
+                                   struct device *subdrv_dev, void **dma_priv)
 {
        struct exynos_drm_private *priv = drm_dev->dev_private;
 
-       if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
+       if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
                arm_iommu_detach_device(subdrv_dev);
-       else if (IS_ENABLED(CONFIG_IOMMU_DMA))
+               arm_iommu_attach_device(subdrv_dev, *dma_priv);
+       } else if (IS_ENABLED(CONFIG_IOMMU_DMA))
                iommu_detach_device(priv->mapping, subdrv_dev);
 
        clear_dma_max_seg_size(subdrv_dev);
 }
 
-int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
+int exynos_drm_register_dma(struct drm_device *drm, struct device *dev,
+                           void **dma_priv)
 {
        struct exynos_drm_private *priv = drm->dev_private;
 
@@ -137,13 +146,14 @@ int exynos_drm_register_dma(struct drm_device *drm, struct device *dev)
                priv->mapping = mapping;
        }
 
-       return drm_iommu_attach_device(drm, dev);
+       return drm_iommu_attach_device(drm, dev, dma_priv);
 }
 
-void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev)
+void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev,
+                              void **dma_priv)
 {
        if (IS_ENABLED(CONFIG_EXYNOS_IOMMU))
-               drm_iommu_detach_device(drm, dev);
+               drm_iommu_detach_device(drm, dev, dma_priv);
 }
 
 void exynos_drm_cleanup_dma(struct drm_device *drm)
index d4d21d8..6ae9056 100644 (file)
@@ -223,8 +223,10 @@ static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
        return priv->mapping ? true : false;
 }
 
-int exynos_drm_register_dma(struct drm_device *drm, struct device *dev);
-void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev);
+int exynos_drm_register_dma(struct drm_device *drm, struct device *dev,
+                           void **dma_priv);
+void exynos_drm_unregister_dma(struct drm_device *drm, struct device *dev,
+                              void **dma_priv);
 void exynos_drm_cleanup_dma(struct drm_device *drm);
 
 #ifdef CONFIG_DRM_EXYNOS_DPI
index 33628d8..a85365c 100644 (file)
@@ -1773,8 +1773,9 @@ static int exynos_dsi_probe(struct platform_device *pdev)
        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dsi->supplies),
                                      dsi->supplies);
        if (ret) {
-               dev_info(dev, "failed to get regulators: %d\n", ret);
-               return -EPROBE_DEFER;
+               if (ret != -EPROBE_DEFER)
+                       dev_info(dev, "failed to get regulators: %d\n", ret);
+               return ret;
        }
 
        dsi->clks = devm_kcalloc(dev,
@@ -1787,9 +1788,10 @@ static int exynos_dsi_probe(struct platform_device *pdev)
                dsi->clks[i] = devm_clk_get(dev, clk_names[i]);
                if (IS_ERR(dsi->clks[i])) {
                        if (strcmp(clk_names[i], "sclk_mipi") == 0) {
-                               strcpy(clk_names[i], OLD_SCLK_MIPI_CLK_NAME);
-                               i--;
-                               continue;
+                               dsi->clks[i] = devm_clk_get(dev,
+                                                       OLD_SCLK_MIPI_CLK_NAME);
+                               if (!IS_ERR(dsi->clks[i]))
+                                       continue;
                        }
 
                        dev_info(dev, "failed to get the clock: %s\n",
index 8ea2e1d..29ab8be 100644 (file)
@@ -97,6 +97,7 @@ struct fimc_scaler {
 struct fimc_context {
        struct exynos_drm_ipp ipp;
        struct drm_device *drm_dev;
+       void            *dma_priv;
        struct device   *dev;
        struct exynos_drm_ipp_task      *task;
        struct exynos_drm_ipp_formats   *formats;
@@ -1133,7 +1134,7 @@ static int fimc_bind(struct device *dev, struct device *master, void *data)
 
        ctx->drm_dev = drm_dev;
        ipp->drm_dev = drm_dev;
-       exynos_drm_register_dma(drm_dev, dev);
+       exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
 
        exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
                        DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1153,7 +1154,7 @@ static void fimc_unbind(struct device *dev, struct device *master,
        struct exynos_drm_ipp *ipp = &ctx->ipp;
 
        exynos_drm_ipp_unregister(dev, ipp);
-       exynos_drm_unregister_dma(drm_dev, dev);
+       exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
 }
 
 static const struct component_ops fimc_component_ops = {
index 21aec38..bb67cad 100644 (file)
@@ -167,6 +167,7 @@ static struct fimd_driver_data exynos5420_fimd_driver_data = {
 struct fimd_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
+       void                            *dma_priv;
        struct exynos_drm_crtc          *crtc;
        struct exynos_drm_plane         planes[WINDOWS_NR];
        struct exynos_drm_plane_config  configs[WINDOWS_NR];
@@ -1090,7 +1091,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
        if (is_drm_iommu_supported(drm_dev))
                fimd_clear_channels(ctx->crtc);
 
-       return exynos_drm_register_dma(drm_dev, dev);
+       return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
 }
 
 static void fimd_unbind(struct device *dev, struct device *master,
@@ -1100,7 +1101,7 @@ static void fimd_unbind(struct device *dev, struct device *master,
 
        fimd_atomic_disable(ctx->crtc);
 
-       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
+       exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
 
        if (ctx->encoder)
                exynos_dpi_remove(ctx->encoder);
index 2a3382d..fcee33a 100644 (file)
@@ -232,6 +232,7 @@ struct g2d_runqueue_node {
 
 struct g2d_data {
        struct device                   *dev;
+       void                            *dma_priv;
        struct clk                      *gate_clk;
        void __iomem                    *regs;
        int                             irq;
@@ -1409,7 +1410,7 @@ static int g2d_bind(struct device *dev, struct device *master, void *data)
                return ret;
        }
 
-       ret = exynos_drm_register_dma(drm_dev, dev);
+       ret = exynos_drm_register_dma(drm_dev, dev, &g2d->dma_priv);
        if (ret < 0) {
                dev_err(dev, "failed to enable iommu.\n");
                g2d_fini_cmdlist(g2d);
@@ -1434,7 +1435,7 @@ static void g2d_unbind(struct device *dev, struct device *master, void *data)
        priv->g2d_dev = NULL;
 
        cancel_work_sync(&g2d->runqueue_work);
-       exynos_drm_unregister_dma(g2d->drm_dev, dev);
+       exynos_drm_unregister_dma(g2d->drm_dev, dev, &g2d->dma_priv);
 }
 
 static const struct component_ops g2d_component_ops = {
index 88b6fca..45e9aee 100644 (file)
@@ -97,6 +97,7 @@ struct gsc_scaler {
 struct gsc_context {
        struct exynos_drm_ipp ipp;
        struct drm_device *drm_dev;
+       void            *dma_priv;
        struct device   *dev;
        struct exynos_drm_ipp_task      *task;
        struct exynos_drm_ipp_formats   *formats;
@@ -1169,7 +1170,7 @@ static int gsc_bind(struct device *dev, struct device *master, void *data)
 
        ctx->drm_dev = drm_dev;
        ctx->drm_dev = drm_dev;
-       exynos_drm_register_dma(drm_dev, dev);
+       exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
 
        exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
                        DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -1189,7 +1190,7 @@ static void gsc_unbind(struct device *dev, struct device *master,
        struct exynos_drm_ipp *ipp = &ctx->ipp;
 
        exynos_drm_ipp_unregister(dev, ipp);
-       exynos_drm_unregister_dma(drm_dev, dev);
+       exynos_drm_unregister_dma(drm_dev, dev, &ctx->dma_priv);
 }
 
 static const struct component_ops gsc_component_ops = {
index b984829..dafa87b 100644 (file)
@@ -56,6 +56,7 @@ struct rot_variant {
 struct rot_context {
        struct exynos_drm_ipp ipp;
        struct drm_device *drm_dev;
+       void            *dma_priv;
        struct device   *dev;
        void __iomem    *regs;
        struct clk      *clock;
@@ -243,7 +244,7 @@ static int rotator_bind(struct device *dev, struct device *master, void *data)
 
        rot->drm_dev = drm_dev;
        ipp->drm_dev = drm_dev;
-       exynos_drm_register_dma(drm_dev, dev);
+       exynos_drm_register_dma(drm_dev, dev, &rot->dma_priv);
 
        exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
                           DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE,
@@ -261,7 +262,7 @@ static void rotator_unbind(struct device *dev, struct device *master,
        struct exynos_drm_ipp *ipp = &rot->ipp;
 
        exynos_drm_ipp_unregister(dev, ipp);
-       exynos_drm_unregister_dma(rot->drm_dev, rot->dev);
+       exynos_drm_unregister_dma(rot->drm_dev, rot->dev, &rot->dma_priv);
 }
 
 static const struct component_ops rotator_component_ops = {
index 497973e..93c43c8 100644 (file)
@@ -39,6 +39,7 @@ struct scaler_data {
 struct scaler_context {
        struct exynos_drm_ipp           ipp;
        struct drm_device               *drm_dev;
+       void                            *dma_priv;
        struct device                   *dev;
        void __iomem                    *regs;
        struct clk                      *clock[SCALER_MAX_CLK];
@@ -450,7 +451,7 @@ static int scaler_bind(struct device *dev, struct device *master, void *data)
 
        scaler->drm_dev = drm_dev;
        ipp->drm_dev = drm_dev;
-       exynos_drm_register_dma(drm_dev, dev);
+       exynos_drm_register_dma(drm_dev, dev, &scaler->dma_priv);
 
        exynos_drm_ipp_register(dev, ipp, &ipp_funcs,
                        DRM_EXYNOS_IPP_CAP_CROP | DRM_EXYNOS_IPP_CAP_ROTATE |
@@ -470,7 +471,8 @@ static void scaler_unbind(struct device *dev, struct device *master,
        struct exynos_drm_ipp *ipp = &scaler->ipp;
 
        exynos_drm_ipp_unregister(dev, ipp);
-       exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev);
+       exynos_drm_unregister_dma(scaler->drm_dev, scaler->dev,
+                                 &scaler->dma_priv);
 }
 
 static const struct component_ops scaler_component_ops = {
index 9ff921f..f141916 100644 (file)
@@ -1805,18 +1805,10 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
 
        hdata->reg_hdmi_en = devm_regulator_get_optional(dev, "hdmi-en");
 
-       if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV) {
+       if (PTR_ERR(hdata->reg_hdmi_en) != -ENODEV)
                if (IS_ERR(hdata->reg_hdmi_en))
                        return PTR_ERR(hdata->reg_hdmi_en);
 
-               ret = regulator_enable(hdata->reg_hdmi_en);
-               if (ret) {
-                       DRM_DEV_ERROR(dev,
-                                     "failed to enable hdmi-en regulator\n");
-                       return ret;
-               }
-       }
-
        return hdmi_bridge_init(hdata);
 }
 
@@ -2023,6 +2015,15 @@ static int hdmi_probe(struct platform_device *pdev)
                }
        }
 
+       if (!IS_ERR(hdata->reg_hdmi_en)) {
+               ret = regulator_enable(hdata->reg_hdmi_en);
+               if (ret) {
+                       DRM_DEV_ERROR(dev,
+                             "failed to enable hdmi-en regulator\n");
+                       goto err_hdmiphy;
+               }
+       }
+
        pm_runtime_enable(dev);
 
        audio_infoframe = &hdata->audio.infoframe;
@@ -2047,7 +2048,8 @@ err_unregister_audio:
 
 err_rpm_disable:
        pm_runtime_disable(dev);
-
+       if (!IS_ERR(hdata->reg_hdmi_en))
+               regulator_disable(hdata->reg_hdmi_en);
 err_hdmiphy:
        if (hdata->hdmiphy_port)
                put_device(&hdata->hdmiphy_port->dev);
index 38ae9c3..21b726b 100644 (file)
@@ -94,6 +94,7 @@ struct mixer_context {
        struct platform_device *pdev;
        struct device           *dev;
        struct drm_device       *drm_dev;
+       void                    *dma_priv;
        struct exynos_drm_crtc  *crtc;
        struct exynos_drm_plane planes[MIXER_WIN_NR];
        unsigned long           flags;
@@ -894,12 +895,14 @@ static int mixer_initialize(struct mixer_context *mixer_ctx,
                }
        }
 
-       return exynos_drm_register_dma(drm_dev, mixer_ctx->dev);
+       return exynos_drm_register_dma(drm_dev, mixer_ctx->dev,
+                                      &mixer_ctx->dma_priv);
 }
 
 static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
 {
-       exynos_drm_unregister_dma(mixer_ctx->drm_dev, mixer_ctx->dev);
+       exynos_drm_unregister_dma(mixer_ctx->drm_dev, mixer_ctx->dev,
+                                 &mixer_ctx->dma_priv);
 }
 
 static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
index 0da8602..e2ac098 100644 (file)
@@ -83,7 +83,6 @@
 #define VSIZE_OFST                     20
 #define LDI_INT_EN                     0x741C
 #define FRAME_END_INT_EN_OFST          1
-#define UNDERFLOW_INT_EN_OFST          2
 #define LDI_CTRL                       0x7420
 #define BPP_OFST                       3
 #define DATA_GATE_EN                   BIT(2)
index 73cd28a..8600012 100644 (file)
@@ -46,7 +46,6 @@ struct ade_hw_ctx {
        struct clk *media_noc_clk;
        struct clk *ade_pix_clk;
        struct reset_control *reset;
-       struct work_struct display_reset_wq;
        bool power_on;
        int irq;
 
@@ -136,7 +135,6 @@ static void ade_init(struct ade_hw_ctx *ctx)
         */
        ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST,
                        FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND);
-       ade_update_bits(base + LDI_INT_EN, UNDERFLOW_INT_EN_OFST, MASK(1), 1);
 }
 
 static bool ade_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -304,17 +302,6 @@ static void ade_crtc_disable_vblank(struct drm_crtc *crtc)
                        MASK(1), 0);
 }
 
-static void drm_underflow_wq(struct work_struct *work)
-{
-       struct ade_hw_ctx *ctx = container_of(work, struct ade_hw_ctx,
-                                             display_reset_wq);
-       struct drm_device *drm_dev = ctx->crtc->dev;
-       struct drm_atomic_state *state;
-
-       state = drm_atomic_helper_suspend(drm_dev);
-       drm_atomic_helper_resume(drm_dev, state);
-}
-
 static irqreturn_t ade_irq_handler(int irq, void *data)
 {
        struct ade_hw_ctx *ctx = data;
@@ -331,12 +318,6 @@ static irqreturn_t ade_irq_handler(int irq, void *data)
                                MASK(1), 1);
                drm_crtc_handle_vblank(crtc);
        }
-       if (status & BIT(UNDERFLOW_INT_EN_OFST)) {
-               ade_update_bits(base + LDI_INT_CLR, UNDERFLOW_INT_EN_OFST,
-                               MASK(1), 1);
-               DRM_ERROR("LDI underflow!");
-               schedule_work(&ctx->display_reset_wq);
-       }
 
        return IRQ_HANDLED;
 }
@@ -919,7 +900,6 @@ static void *ade_hw_ctx_alloc(struct platform_device *pdev,
        if (ret)
                return ERR_PTR(-EIO);
 
-       INIT_WORK(&ctx->display_reset_wq, drm_underflow_wq);
        ctx->crtc = crtc;
 
        return ctx;
index b8c5f89..a1f2411 100644 (file)
@@ -294,7 +294,7 @@ extra-$(CONFIG_DRM_I915_WERROR) += \
                $(shell cd $(srctree)/$(src) && find * -name '*.h')))
 
 quiet_cmd_hdrtest = HDRTEST $(patsubst %.hdrtest,%.h,$@)
-      cmd_hdrtest = $(CC) $(c_flags) -S -o /dev/null -x c /dev/null -include $<; touch $@
+      cmd_hdrtest = $(CC) $(filter-out $(CFLAGS_GCOV), $(c_flags)) -S -o /dev/null -x c /dev/null -include $<; touch $@
 
 $(obj)/%.hdrtest: $(src)/%.h FORCE
        $(call if_changed_dep,hdrtest)
index 21561ac..46c40db 100644 (file)
@@ -4466,13 +4466,19 @@ static void icl_dbuf_disable(struct drm_i915_private *dev_priv)
 
 static void icl_mbus_init(struct drm_i915_private *dev_priv)
 {
-       u32 val;
+       u32 mask, val;
 
-       val = MBUS_ABOX_BT_CREDIT_POOL1(16) |
-             MBUS_ABOX_BT_CREDIT_POOL2(16) |
-             MBUS_ABOX_B_CREDIT(1) |
-             MBUS_ABOX_BW_CREDIT(1);
+       mask = MBUS_ABOX_BT_CREDIT_POOL1_MASK |
+               MBUS_ABOX_BT_CREDIT_POOL2_MASK |
+               MBUS_ABOX_B_CREDIT_MASK |
+               MBUS_ABOX_BW_CREDIT_MASK;
 
+       val = I915_READ(MBUS_ABOX_CTL);
+       val &= ~mask;
+       val |= MBUS_ABOX_BT_CREDIT_POOL1(16) |
+               MBUS_ABOX_BT_CREDIT_POOL2(16) |
+               MBUS_ABOX_B_CREDIT(1) |
+               MBUS_ABOX_BW_CREDIT(1);
        I915_WRITE(MBUS_ABOX_CTL, val);
 }
 
@@ -4968,8 +4974,21 @@ static void tgl_bw_buddy_init(struct drm_i915_private *dev_priv)
                I915_WRITE(BW_BUDDY1_CTL, BW_BUDDY_DISABLE);
                I915_WRITE(BW_BUDDY2_CTL, BW_BUDDY_DISABLE);
        } else {
+               u32 val;
+
                I915_WRITE(BW_BUDDY1_PAGE_MASK, table[i].page_mask);
                I915_WRITE(BW_BUDDY2_PAGE_MASK, table[i].page_mask);
+
+               /* Wa_22010178259:tgl */
+               val = I915_READ(BW_BUDDY1_CTL);
+               val &= ~BW_BUDDY_TLB_REQ_TIMER_MASK;
+               val |= REG_FIELD_PREP(BW_BUDDY_TLB_REQ_TIMER_MASK, 0x8);
+               I915_WRITE(BW_BUDDY1_CTL, val);
+
+               val = I915_READ(BW_BUDDY2_CTL);
+               val &= ~BW_BUDDY_TLB_REQ_TIMER_MASK;
+               val |= REG_FIELD_PREP(BW_BUDDY_TLB_REQ_TIMER_MASK, 0x8);
+               I915_WRITE(BW_BUDDY2_CTL, val);
        }
 }
 
index c7424e2..2084570 100644 (file)
@@ -1360,7 +1360,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp,
         * lowest possible wakeup latency and so prevent the cpu from going into
         * deep sleep states.
         */
-       pm_qos_update_request(&i915->pm_qos, 0);
+       cpu_latency_qos_update_request(&i915->pm_qos, 0);
 
        intel_dp_check_edp(intel_dp);
 
@@ -1488,7 +1488,7 @@ done:
 
        ret = recv_bytes;
 out:
-       pm_qos_update_request(&i915->pm_qos, PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_update_request(&i915->pm_qos, PM_QOS_DEFAULT_VALUE);
 
        if (vdd)
                edp_panel_vdd_off(intel_dp, false);
index 89c9cf5..8302505 100644 (file)
@@ -852,10 +852,12 @@ void intel_psr_enable(struct intel_dp *intel_dp,
 {
        struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
 
-       if (!crtc_state->has_psr)
+       if (!CAN_PSR(dev_priv) || dev_priv->psr.dp != intel_dp)
                return;
 
-       if (WARN_ON(!CAN_PSR(dev_priv)))
+       dev_priv->psr.force_mode_changed = false;
+
+       if (!crtc_state->has_psr)
                return;
 
        WARN_ON(dev_priv->drrs.dp);
@@ -1009,6 +1011,8 @@ void intel_psr_update(struct intel_dp *intel_dp,
        if (!CAN_PSR(dev_priv) || READ_ONCE(psr->dp) != intel_dp)
                return;
 
+       dev_priv->psr.force_mode_changed = false;
+
        mutex_lock(&dev_priv->psr.lock);
 
        enable = crtc_state->has_psr && psr_global_enabled(psr->debug);
@@ -1534,7 +1538,7 @@ void intel_psr_atomic_check(struct drm_connector *connector,
        struct drm_crtc_state *crtc_state;
 
        if (!CAN_PSR(dev_priv) || !new_state->crtc ||
-           dev_priv->psr.initially_probed)
+           !dev_priv->psr.force_mode_changed)
                return;
 
        intel_connector = to_intel_connector(connector);
@@ -1545,5 +1549,18 @@ void intel_psr_atomic_check(struct drm_connector *connector,
        crtc_state = drm_atomic_get_new_crtc_state(new_state->state,
                                                   new_state->crtc);
        crtc_state->mode_changed = true;
-       dev_priv->psr.initially_probed = true;
+}
+
+void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp)
+{
+       struct drm_i915_private *dev_priv;
+
+       if (!intel_dp)
+               return;
+
+       dev_priv = dp_to_i915(intel_dp);
+       if (!CAN_PSR(dev_priv) || intel_dp != dev_priv->psr.dp)
+               return;
+
+       dev_priv->psr.force_mode_changed = true;
 }
index c58a1d4..274fc6b 100644 (file)
@@ -40,5 +40,6 @@ bool intel_psr_enabled(struct intel_dp *intel_dp);
 void intel_psr_atomic_check(struct drm_connector *connector,
                            struct drm_connector_state *old_state,
                            struct drm_connector_state *new_state);
+void intel_psr_set_force_mode_changed(struct intel_dp *intel_dp);
 
 #endif /* __INTEL_PSR_H__ */
index 60c984e..7643a30 100644 (file)
@@ -423,7 +423,8 @@ eb_validate_vma(struct i915_execbuffer *eb,
        if (unlikely(entry->flags & eb->invalid_flags))
                return -EINVAL;
 
-       if (unlikely(entry->alignment && !is_power_of_2(entry->alignment)))
+       if (unlikely(entry->alignment &&
+                    !is_power_of_2_u64(entry->alignment)))
                return -EINVAL;
 
        /*
index 3598521..5da9f9e 100644 (file)
@@ -225,6 +225,7 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
 
                /* But keep the pointer alive for RCU-protected lookups */
                call_rcu(&obj->rcu, __i915_gem_free_object_rcu);
+               cond_resched();
        }
        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 }
index f7e4b39..59b387a 100644 (file)
@@ -256,8 +256,7 @@ unsigned long i915_gem_shrink_all(struct drm_i915_private *i915)
        with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
                freed = i915_gem_shrink(i915, -1UL, NULL,
                                        I915_SHRINK_BOUND |
-                                       I915_SHRINK_UNBOUND |
-                                       I915_SHRINK_ACTIVE);
+                                       I915_SHRINK_UNBOUND);
        }
 
        return freed;
@@ -336,7 +335,6 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
        freed_pages = 0;
        with_intel_runtime_pm(&i915->runtime_pm, wakeref)
                freed_pages += i915_gem_shrink(i915, -1UL, NULL,
-                                              I915_SHRINK_ACTIVE |
                                               I915_SHRINK_BOUND |
                                               I915_SHRINK_UNBOUND |
                                               I915_SHRINK_WRITEBACK);
index ef7c74c..43912e9 100644 (file)
@@ -570,7 +570,7 @@ static bool assert_mmap_offset(struct drm_i915_private *i915,
 
        obj = i915_gem_object_create_internal(i915, size);
        if (IS_ERR(obj))
-               return PTR_ERR(obj);
+               return false;
 
        mmo = mmap_offset_attach(obj, I915_MMAP_OFFSET_GTT, NULL);
        i915_gem_object_put(obj);
index 8a5054f..24c99d0 100644 (file)
@@ -147,24 +147,32 @@ long intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout)
 
                        fence = i915_active_fence_get(&tl->last_request);
                        if (fence) {
+                               mutex_unlock(&tl->mutex);
+
                                timeout = dma_fence_wait_timeout(fence,
                                                                 interruptible,
                                                                 timeout);
                                dma_fence_put(fence);
+
+                               /* Retirement is best effort */
+                               if (!mutex_trylock(&tl->mutex)) {
+                                       active_count++;
+                                       goto out_active;
+                               }
                        }
                }
 
                if (!retire_requests(tl) || flush_submission(gt))
                        active_count++;
+               mutex_unlock(&tl->mutex);
 
-               spin_lock(&timelines->lock);
+out_active:    spin_lock(&timelines->lock);
 
-               /* Resume iteration after dropping lock */
+               /* Resume list iteration after reacquiring spinlock */
                list_safe_reset_next(tl, tn, link);
                if (atomic_dec_and_test(&tl->active_count))
                        list_del(&tl->link);
 
-               mutex_unlock(&tl->mutex);
 
                /* Defer the final release to after the spinlock */
                if (refcount_dec_and_test(&tl->kref.refcount)) {
index fe8a59a..31455ec 100644 (file)
@@ -1600,17 +1600,6 @@ static void virtual_xfer_breadcrumbs(struct virtual_engine *ve,
        spin_unlock(&old->breadcrumbs.irq_lock);
 }
 
-static struct i915_request *
-last_active(const struct intel_engine_execlists *execlists)
-{
-       struct i915_request * const *last = READ_ONCE(execlists->active);
-
-       while (*last && i915_request_completed(*last))
-               last++;
-
-       return *last;
-}
-
 #define for_each_waiter(p__, rq__) \
        list_for_each_entry_lockless(p__, \
                                     &(rq__)->sched.waiters_list, \
@@ -1679,11 +1668,9 @@ need_timeslice(struct intel_engine_cs *engine, const struct i915_request *rq)
        if (!intel_engine_has_timeslices(engine))
                return false;
 
-       if (list_is_last(&rq->sched.link, &engine->active.requests))
-               return false;
-
-       hint = max(rq_prio(list_next_entry(rq, sched.link)),
-                  engine->execlists.queue_priority_hint);
+       hint = engine->execlists.queue_priority_hint;
+       if (!list_is_last(&rq->sched.link, &engine->active.requests))
+               hint = max(hint, rq_prio(list_next_entry(rq, sched.link)));
 
        return hint >= effective_prio(rq);
 }
@@ -1725,16 +1712,26 @@ static void set_timeslice(struct intel_engine_cs *engine)
        set_timer_ms(&engine->execlists.timer, active_timeslice(engine));
 }
 
+static void start_timeslice(struct intel_engine_cs *engine)
+{
+       struct intel_engine_execlists *execlists = &engine->execlists;
+
+       execlists->switch_priority_hint = execlists->queue_priority_hint;
+
+       if (timer_pending(&execlists->timer))
+               return;
+
+       set_timer_ms(&execlists->timer, timeslice(engine));
+}
+
 static void record_preemption(struct intel_engine_execlists *execlists)
 {
        (void)I915_SELFTEST_ONLY(execlists->preempt_hang.count++);
 }
 
-static unsigned long active_preempt_timeout(struct intel_engine_cs *engine)
+static unsigned long active_preempt_timeout(struct intel_engine_cs *engine,
+                                           const struct i915_request *rq)
 {
-       struct i915_request *rq;
-
-       rq = last_active(&engine->execlists);
        if (!rq)
                return 0;
 
@@ -1745,13 +1742,14 @@ static unsigned long active_preempt_timeout(struct intel_engine_cs *engine)
        return READ_ONCE(engine->props.preempt_timeout_ms);
 }
 
-static void set_preempt_timeout(struct intel_engine_cs *engine)
+static void set_preempt_timeout(struct intel_engine_cs *engine,
+                               const struct i915_request *rq)
 {
        if (!intel_engine_has_preempt_reset(engine))
                return;
 
        set_timer_ms(&engine->execlists.preempt,
-                    active_preempt_timeout(engine));
+                    active_preempt_timeout(engine, rq));
 }
 
 static inline void clear_ports(struct i915_request **ports, int count)
@@ -1764,6 +1762,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
        struct intel_engine_execlists * const execlists = &engine->execlists;
        struct i915_request **port = execlists->pending;
        struct i915_request ** const last_port = port + execlists->port_mask;
+       struct i915_request * const *active;
        struct i915_request *last;
        struct rb_node *rb;
        bool submit = false;
@@ -1818,7 +1817,10 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
         * i.e. we will retrigger preemption following the ack in case
         * of trouble.
         */
-       last = last_active(execlists);
+       active = READ_ONCE(execlists->active);
+       while ((last = *active) && i915_request_completed(last))
+               active++;
+
        if (last) {
                if (need_preempt(engine, last, rb)) {
                        ENGINE_TRACE(engine,
@@ -1888,11 +1890,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
                                 * Even if ELSP[1] is occupied and not worthy
                                 * of timeslices, our queue might be.
                                 */
-                               if (!execlists->timer.expires &&
-                                   need_timeslice(engine, last))
-                                       set_timer_ms(&execlists->timer,
-                                                    timeslice(engine));
-
+                               start_timeslice(engine);
                                return;
                        }
                }
@@ -1927,7 +1925,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 
                        if (last && !can_merge_rq(last, rq)) {
                                spin_unlock(&ve->base.active.lock);
-                               return; /* leave this for another */
+                               start_timeslice(engine);
+                               return; /* leave this for another sibling */
                        }
 
                        ENGINE_TRACE(engine,
@@ -2103,7 +2102,7 @@ done:
                 * Skip if we ended up with exactly the same set of requests,
                 * e.g. trying to timeslice a pair of ordered contexts
                 */
-               if (!memcmp(execlists->active, execlists->pending,
+               if (!memcmp(active, execlists->pending,
                            (port - execlists->pending + 1) * sizeof(*port))) {
                        do
                                execlists_schedule_out(fetch_and_zero(port));
@@ -2114,7 +2113,7 @@ done:
                clear_ports(port + 1, last_port - port);
 
                execlists_submit_ports(engine);
-               set_preempt_timeout(engine);
+               set_preempt_timeout(engine, *active);
        } else {
 skip_submit:
                ring_set_paused(engine, 0);
@@ -4001,26 +4000,6 @@ static int gen12_emit_flush_render(struct i915_request *request,
 
                *cs++ = preparser_disable(false);
                intel_ring_advance(request, cs);
-
-               /*
-                * Wa_1604544889:tgl
-                */
-               if (IS_TGL_REVID(request->i915, TGL_REVID_A0, TGL_REVID_A0)) {
-                       flags = 0;
-                       flags |= PIPE_CONTROL_CS_STALL;
-                       flags |= PIPE_CONTROL_HDC_PIPELINE_FLUSH;
-
-                       flags |= PIPE_CONTROL_STORE_DATA_INDEX;
-                       flags |= PIPE_CONTROL_QW_WRITE;
-
-                       cs = intel_ring_begin(request, 6);
-                       if (IS_ERR(cs))
-                               return PTR_ERR(cs);
-
-                       cs = gen8_emit_pipe_control(cs, flags,
-                                                   LRC_PPHWSP_SCRATCH_ADDR);
-                       intel_ring_advance(request, cs);
-               }
        }
 
        return 0;
index 8771652..d8d9f11 100644 (file)
@@ -192,11 +192,15 @@ static void cacheline_release(struct intel_timeline_cacheline *cl)
 
 static void cacheline_free(struct intel_timeline_cacheline *cl)
 {
+       if (!i915_active_acquire_if_busy(&cl->active)) {
+               __idle_cacheline_free(cl);
+               return;
+       }
+
        GEM_BUG_ON(ptr_test_bit(cl->vaddr, CACHELINE_FREE));
        cl->vaddr = ptr_set_bit(cl->vaddr, CACHELINE_FREE);
 
-       if (i915_active_is_idle(&cl->active))
-               __idle_cacheline_free(cl);
+       i915_active_release(&cl->active);
 }
 
 int intel_timeline_init(struct intel_timeline *timeline,
index 4e292d4..6c2f846 100644 (file)
@@ -575,24 +575,19 @@ static void icl_ctx_workarounds_init(struct intel_engine_cs *engine,
 static void tgl_ctx_workarounds_init(struct intel_engine_cs *engine,
                                     struct i915_wa_list *wal)
 {
-       u32 val;
-
        /* Wa_1409142259:tgl */
        WA_SET_BIT_MASKED(GEN11_COMMON_SLICE_CHICKEN3,
                          GEN12_DISABLE_CPS_AWARE_COLOR_PIPE);
 
-       /* Wa_1604555607:tgl */
-       val = intel_uncore_read(engine->uncore, FF_MODE2);
-       val &= ~FF_MODE2_TDS_TIMER_MASK;
-       val |= FF_MODE2_TDS_TIMER_128;
        /*
-        * FIXME: FF_MODE2 register is not readable till TGL B0. We can
-        * enable verification of WA from the later steppings, which enables
-        * the read of FF_MODE2.
+        * Wa_1604555607:gen12 and Wa_1608008084:gen12
+        * FF_MODE2 register will return the wrong value when read. The default
+        * value for this register is zero for all fields and there are no bit
+        * masks. So instead of doing a RMW we should just write the TDS timer
+        * value for Wa_1604555607.
         */
-       wa_add(wal, FF_MODE2, FF_MODE2_TDS_TIMER_MASK, val,
-              IS_TGL_REVID(engine->i915, TGL_REVID_A0, TGL_REVID_A0) ? 0 :
-                           FF_MODE2_TDS_TIMER_MASK);
+       wa_add(wal, FF_MODE2, FF_MODE2_TDS_TIMER_MASK,
+              FF_MODE2_TDS_TIMER_128, 0);
 }
 
 static void
@@ -1534,15 +1529,34 @@ err_obj:
        return ERR_PTR(err);
 }
 
+static const struct {
+       u32 start;
+       u32 end;
+} mcr_ranges_gen8[] = {
+       { .start = 0x5500, .end = 0x55ff },
+       { .start = 0x7000, .end = 0x7fff },
+       { .start = 0x9400, .end = 0x97ff },
+       { .start = 0xb000, .end = 0xb3ff },
+       { .start = 0xe000, .end = 0xe7ff },
+       {},
+};
+
 static bool mcr_range(struct drm_i915_private *i915, u32 offset)
 {
+       int i;
+
+       if (INTEL_GEN(i915) < 8)
+               return false;
+
        /*
-        * Registers in this range are affected by the MCR selector
+        * Registers in these ranges are affected by the MCR selector
         * which only controls CPU initiated MMIO. Routing does not
         * work for CS access so we cannot verify them on this path.
         */
-       if (INTEL_GEN(i915) >= 8 && (offset >= 0xb000 && offset <= 0xb4ff))
-               return true;
+       for (i = 0; mcr_ranges_gen8[i].start; i++)
+               if (offset >= mcr_ranges_gen8[i].start &&
+                   offset <= mcr_ranges_gen8[i].end)
+                       return true;
 
        return false;
 }
index e1c313d..a62bdf9 100644 (file)
@@ -457,7 +457,8 @@ void intel_vgpu_emulate_hotplug(struct intel_vgpu *vgpu, bool connected)
        struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
 
        /* TODO: add more platforms support */
-       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+       if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) ||
+               IS_COFFEELAKE(dev_priv)) {
                if (connected) {
                        vgpu_vreg_t(vgpu, SFUSE_STRAP) |=
                                SFUSE_STRAP_DDID_DETECTED;
index 2477a1e..ae139f0 100644 (file)
@@ -151,12 +151,12 @@ static void dmabuf_gem_object_free(struct kref *kref)
                        dmabuf_obj = container_of(pos,
                                        struct intel_vgpu_dmabuf_obj, list);
                        if (dmabuf_obj == obj) {
+                               list_del(pos);
                                intel_gvt_hypervisor_put_vfio_device(vgpu);
                                idr_remove(&vgpu->object_idr,
                                           dmabuf_obj->dmabuf_id);
                                kfree(dmabuf_obj->info);
                                kfree(dmabuf_obj);
-                               list_del(pos);
                                break;
                        }
                }
index 867e762..33569b9 100644 (file)
@@ -147,15 +147,14 @@ static void virt_vbt_generation(struct vbt *v)
        /* there's features depending on version! */
        v->header.version = 155;
        v->header.header_size = sizeof(v->header);
-       v->header.vbt_size = sizeof(struct vbt) - sizeof(v->header);
+       v->header.vbt_size = sizeof(struct vbt);
        v->header.bdb_offset = offsetof(struct vbt, bdb_header);
 
        strcpy(&v->bdb_header.signature[0], "BIOS_DATA_BLOCK");
        v->bdb_header.version = 186; /* child_dev_size = 33 */
        v->bdb_header.header_size = sizeof(v->bdb_header);
 
-       v->bdb_header.bdb_size = sizeof(struct vbt) - sizeof(struct vbt_header)
-               - sizeof(struct bdb_header);
+       v->bdb_header.bdb_size = sizeof(struct vbt) - sizeof(struct vbt_header);
 
        /* general features */
        v->general_features_header.id = BDB_GENERAL_FEATURES;
index 85bd9bf..345c2aa 100644 (file)
@@ -272,10 +272,17 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu)
 {
        struct intel_gvt *gvt = vgpu->gvt;
 
-       mutex_lock(&vgpu->vgpu_lock);
-
        WARN(vgpu->active, "vGPU is still active!\n");
 
+       /*
+        * remove idr first so later clean can judge if need to stop
+        * service if no active vgpu.
+        */
+       mutex_lock(&gvt->lock);
+       idr_remove(&gvt->vgpu_idr, vgpu->id);
+       mutex_unlock(&gvt->lock);
+
+       mutex_lock(&vgpu->vgpu_lock);
        intel_gvt_debugfs_remove_vgpu(vgpu);
        intel_vgpu_clean_sched_policy(vgpu);
        intel_vgpu_clean_submission(vgpu);
@@ -290,7 +297,6 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu)
        mutex_unlock(&vgpu->vgpu_lock);
 
        mutex_lock(&gvt->lock);
-       idr_remove(&gvt->vgpu_idr, vgpu->id);
        if (idr_is_empty(&gvt->vgpu_idr))
                intel_gvt_clean_irq(gvt);
        intel_gvt_update_vgpu_types(gvt);
@@ -560,9 +566,9 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
 
                intel_vgpu_reset_mmio(vgpu, dmlr);
                populate_pvinfo_page(vgpu);
-               intel_vgpu_reset_display(vgpu);
 
                if (dmlr) {
+                       intel_vgpu_reset_display(vgpu);
                        intel_vgpu_reset_cfg_space(vgpu);
                        /* only reset the failsafe mode when dmlr reset */
                        vgpu->failsafe = false;
index f7385ab..eec1d6a 100644 (file)
@@ -56,6 +56,7 @@
 #include "display/intel_hotplug.h"
 #include "display/intel_overlay.h"
 #include "display/intel_pipe_crc.h"
+#include "display/intel_psr.h"
 #include "display/intel_sprite.h"
 #include "display/intel_vga.h"
 
@@ -330,6 +331,8 @@ static int i915_driver_modeset_probe(struct drm_i915_private *i915)
 
        intel_init_ipc(i915);
 
+       intel_psr_set_force_mode_changed(i915->psr.dp);
+
        return 0;
 
 cleanup_gem:
@@ -502,8 +505,7 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv)
        mutex_init(&dev_priv->backlight_lock);
 
        mutex_init(&dev_priv->sb_lock);
-       pm_qos_add_request(&dev_priv->sb_qos,
-                          PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_add_request(&dev_priv->sb_qos, PM_QOS_DEFAULT_VALUE);
 
        mutex_init(&dev_priv->av_mutex);
        mutex_init(&dev_priv->wm.wm_mutex);
@@ -568,7 +570,7 @@ static void i915_driver_late_release(struct drm_i915_private *dev_priv)
        vlv_free_s0ix_state(dev_priv);
        i915_workqueues_cleanup(dev_priv);
 
-       pm_qos_remove_request(&dev_priv->sb_qos);
+       cpu_latency_qos_remove_request(&dev_priv->sb_qos);
        mutex_destroy(&dev_priv->sb_lock);
 }
 
@@ -1226,8 +1228,7 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
                }
        }
 
-       pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY,
-                          PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_add_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
 
        intel_gt_init_workarounds(dev_priv);
 
@@ -1273,7 +1274,7 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv)
 err_msi:
        if (pdev->msi_enabled)
                pci_disable_msi(pdev);
-       pm_qos_remove_request(&dev_priv->pm_qos);
+       cpu_latency_qos_remove_request(&dev_priv->pm_qos);
 err_mem_regions:
        intel_memory_regions_driver_release(dev_priv);
 err_ggtt:
@@ -1296,7 +1297,7 @@ static void i915_driver_hw_remove(struct drm_i915_private *dev_priv)
        if (pdev->msi_enabled)
                pci_disable_msi(pdev);
 
-       pm_qos_remove_request(&dev_priv->pm_qos);
+       cpu_latency_qos_remove_request(&dev_priv->pm_qos);
 }
 
 /**
index 077af22..810e3cc 100644 (file)
@@ -505,7 +505,7 @@ struct i915_psr {
        bool dc3co_enabled;
        u32 dc3co_exit_delay;
        struct delayed_work idle_work;
-       bool initially_probed;
+       bool force_mode_changed;
 };
 
 #define QUIRK_LVDS_SSC_DISABLE (1<<1)
index 83f0140..f631f6d 100644 (file)
@@ -437,7 +437,7 @@ static const struct intel_device_info snb_m_gt2_info = {
        .has_rc6 = 1, \
        .has_rc6p = 1, \
        .has_rps = true, \
-       .ppgtt_type = INTEL_PPGTT_FULL, \
+       .ppgtt_type = INTEL_PPGTT_ALIASING, \
        .ppgtt_size = 31, \
        IVB_PIPE_OFFSETS, \
        IVB_CURSOR_OFFSETS, \
@@ -494,7 +494,7 @@ static const struct intel_device_info vlv_info = {
        .has_rps = true,
        .display.has_gmch = 1,
        .display.has_hotplug = 1,
-       .ppgtt_type = INTEL_PPGTT_FULL,
+       .ppgtt_type = INTEL_PPGTT_ALIASING,
        .ppgtt_size = 31,
        .has_snoop = true,
        .has_coherent_ggtt = false,
index 0f556d8..3b6b913 100644 (file)
@@ -1954,9 +1954,10 @@ out:
        return i915_vma_get(oa_bo->vma);
 }
 
-static int emit_oa_config(struct i915_perf_stream *stream,
-                         struct i915_oa_config *oa_config,
-                         struct intel_context *ce)
+static struct i915_request *
+emit_oa_config(struct i915_perf_stream *stream,
+              struct i915_oa_config *oa_config,
+              struct intel_context *ce)
 {
        struct i915_request *rq;
        struct i915_vma *vma;
@@ -1964,7 +1965,7 @@ static int emit_oa_config(struct i915_perf_stream *stream,
 
        vma = get_oa_vma(stream, oa_config);
        if (IS_ERR(vma))
-               return PTR_ERR(vma);
+               return ERR_CAST(vma);
 
        err = i915_vma_pin(vma, 0, 0, PIN_GLOBAL | PIN_HIGH);
        if (err)
@@ -1989,13 +1990,17 @@ static int emit_oa_config(struct i915_perf_stream *stream,
        err = rq->engine->emit_bb_start(rq,
                                        vma->node.start, 0,
                                        I915_DISPATCH_SECURE);
+       if (err)
+               goto err_add_request;
+
+       i915_request_get(rq);
 err_add_request:
        i915_request_add(rq);
 err_vma_unpin:
        i915_vma_unpin(vma);
 err_vma_put:
        i915_vma_put(vma);
-       return err;
+       return err ? ERR_PTR(err) : rq;
 }
 
 static struct intel_context *oa_context(struct i915_perf_stream *stream)
@@ -2003,7 +2008,8 @@ static struct intel_context *oa_context(struct i915_perf_stream *stream)
        return stream->pinned_ctx ?: stream->engine->kernel_context;
 }
 
-static int hsw_enable_metric_set(struct i915_perf_stream *stream)
+static struct i915_request *
+hsw_enable_metric_set(struct i915_perf_stream *stream)
 {
        struct intel_uncore *uncore = stream->uncore;
 
@@ -2406,7 +2412,8 @@ static int lrc_configure_all_contexts(struct i915_perf_stream *stream,
        return oa_configure_all_contexts(stream, regs, ARRAY_SIZE(regs));
 }
 
-static int gen8_enable_metric_set(struct i915_perf_stream *stream)
+static struct i915_request *
+gen8_enable_metric_set(struct i915_perf_stream *stream)
 {
        struct intel_uncore *uncore = stream->uncore;
        struct i915_oa_config *oa_config = stream->oa_config;
@@ -2448,7 +2455,7 @@ static int gen8_enable_metric_set(struct i915_perf_stream *stream)
         */
        ret = lrc_configure_all_contexts(stream, oa_config);
        if (ret)
-               return ret;
+               return ERR_PTR(ret);
 
        return emit_oa_config(stream, oa_config, oa_context(stream));
 }
@@ -2460,7 +2467,8 @@ static u32 oag_report_ctx_switches(const struct i915_perf_stream *stream)
                             0 : GEN12_OAG_OA_DEBUG_DISABLE_CTX_SWITCH_REPORTS);
 }
 
-static int gen12_enable_metric_set(struct i915_perf_stream *stream)
+static struct i915_request *
+gen12_enable_metric_set(struct i915_perf_stream *stream)
 {
        struct intel_uncore *uncore = stream->uncore;
        struct i915_oa_config *oa_config = stream->oa_config;
@@ -2491,7 +2499,7 @@ static int gen12_enable_metric_set(struct i915_perf_stream *stream)
         */
        ret = gen12_configure_all_contexts(stream, oa_config);
        if (ret)
-               return ret;
+               return ERR_PTR(ret);
 
        /*
         * For Gen12, performance counters are context
@@ -2501,7 +2509,7 @@ static int gen12_enable_metric_set(struct i915_perf_stream *stream)
        if (stream->ctx) {
                ret = gen12_configure_oar_context(stream, true);
                if (ret)
-                       return ret;
+                       return ERR_PTR(ret);
        }
 
        return emit_oa_config(stream, oa_config, oa_context(stream));
@@ -2696,6 +2704,20 @@ static const struct i915_perf_stream_ops i915_oa_stream_ops = {
        .read = i915_oa_read,
 };
 
+static int i915_perf_stream_enable_sync(struct i915_perf_stream *stream)
+{
+       struct i915_request *rq;
+
+       rq = stream->perf->ops.enable_metric_set(stream);
+       if (IS_ERR(rq))
+               return PTR_ERR(rq);
+
+       i915_request_wait(rq, 0, MAX_SCHEDULE_TIMEOUT);
+       i915_request_put(rq);
+
+       return 0;
+}
+
 /**
  * i915_oa_stream_init - validate combined props for OA stream and init
  * @stream: An i915 perf stream
@@ -2829,7 +2851,7 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
        stream->ops = &i915_oa_stream_ops;
        perf->exclusive_stream = stream;
 
-       ret = perf->ops.enable_metric_set(stream);
+       ret = i915_perf_stream_enable_sync(stream);
        if (ret) {
                DRM_DEBUG("Unable to enable metric set\n");
                goto err_enable;
@@ -3147,7 +3169,7 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream,
                return -EINVAL;
 
        if (config != stream->oa_config) {
-               int err;
+               struct i915_request *rq;
 
                /*
                 * If OA is bound to a specific context, emit the
@@ -3158,11 +3180,13 @@ static long i915_perf_config_locked(struct i915_perf_stream *stream,
                 * When set globally, we use a low priority kernel context,
                 * so it will effectively take effect when idle.
                 */
-               err = emit_oa_config(stream, config, oa_context(stream));
-               if (err == 0)
+               rq = emit_oa_config(stream, config, oa_context(stream));
+               if (!IS_ERR(rq)) {
                        config = xchg(&stream->oa_config, config);
-               else
-                       ret = err;
+                       i915_request_put(rq);
+               } else {
+                       ret = PTR_ERR(rq);
+               }
        }
 
        i915_oa_config_put(config);
index 45e5814..a0e22f0 100644 (file)
@@ -339,7 +339,8 @@ struct i915_oa_ops {
         * counter reports being sampled. May apply system constraints such as
         * disabling EU clock gating as required.
         */
-       int (*enable_metric_set)(struct i915_perf_stream *stream);
+       struct i915_request *
+               (*enable_metric_set)(struct i915_perf_stream *stream);
 
        /**
         * @disable_metric_set: Remove system constraints associated with using
index ec02994..aa729d0 100644 (file)
@@ -822,11 +822,6 @@ static ssize_t i915_pmu_event_show(struct device *dev,
        return sprintf(buf, "config=0x%lx\n", eattr->val);
 }
 
-static struct attribute_group i915_pmu_events_attr_group = {
-       .name = "events",
-       /* Patch in attrs at runtime. */
-};
-
 static ssize_t
 i915_pmu_get_attr_cpumask(struct device *dev,
                          struct device_attribute *attr,
@@ -846,13 +841,6 @@ static const struct attribute_group i915_pmu_cpumask_attr_group = {
        .attrs = i915_cpumask_attrs,
 };
 
-static const struct attribute_group *i915_pmu_attr_groups[] = {
-       &i915_pmu_format_attr_group,
-       &i915_pmu_events_attr_group,
-       &i915_pmu_cpumask_attr_group,
-       NULL
-};
-
 #define __event(__config, __name, __unit) \
 { \
        .config = (__config), \
@@ -1026,23 +1014,23 @@ err_alloc:
 
 static void free_event_attributes(struct i915_pmu *pmu)
 {
-       struct attribute **attr_iter = i915_pmu_events_attr_group.attrs;
+       struct attribute **attr_iter = pmu->events_attr_group.attrs;
 
        for (; *attr_iter; attr_iter++)
                kfree((*attr_iter)->name);
 
-       kfree(i915_pmu_events_attr_group.attrs);
+       kfree(pmu->events_attr_group.attrs);
        kfree(pmu->i915_attr);
        kfree(pmu->pmu_attr);
 
-       i915_pmu_events_attr_group.attrs = NULL;
+       pmu->events_attr_group.attrs = NULL;
        pmu->i915_attr = NULL;
        pmu->pmu_attr = NULL;
 }
 
 static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
 {
-       struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), node);
+       struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), cpuhp.node);
 
        GEM_BUG_ON(!pmu->base.event_init);
 
@@ -1055,7 +1043,7 @@ static int i915_pmu_cpu_online(unsigned int cpu, struct hlist_node *node)
 
 static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
 {
-       struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), node);
+       struct i915_pmu *pmu = hlist_entry_safe(node, typeof(*pmu), cpuhp.node);
        unsigned int target;
 
        GEM_BUG_ON(!pmu->base.event_init);
@@ -1072,8 +1060,6 @@ static int i915_pmu_cpu_offline(unsigned int cpu, struct hlist_node *node)
        return 0;
 }
 
-static enum cpuhp_state cpuhp_slot = CPUHP_INVALID;
-
 static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
 {
        enum cpuhp_state slot;
@@ -1087,21 +1073,22 @@ static int i915_pmu_register_cpuhp_state(struct i915_pmu *pmu)
                return ret;
 
        slot = ret;
-       ret = cpuhp_state_add_instance(slot, &pmu->node);
+       ret = cpuhp_state_add_instance(slot, &pmu->cpuhp.node);
        if (ret) {
                cpuhp_remove_multi_state(slot);
                return ret;
        }
 
-       cpuhp_slot = slot;
+       pmu->cpuhp.slot = slot;
        return 0;
 }
 
 static void i915_pmu_unregister_cpuhp_state(struct i915_pmu *pmu)
 {
-       WARN_ON(cpuhp_slot == CPUHP_INVALID);
-       WARN_ON(cpuhp_state_remove_instance(cpuhp_slot, &pmu->node));
-       cpuhp_remove_multi_state(cpuhp_slot);
+       WARN_ON(pmu->cpuhp.slot == CPUHP_INVALID);
+       WARN_ON(cpuhp_state_remove_instance(pmu->cpuhp.slot, &pmu->cpuhp.node));
+       cpuhp_remove_multi_state(pmu->cpuhp.slot);
+       pmu->cpuhp.slot = CPUHP_INVALID;
 }
 
 static bool is_igp(struct drm_i915_private *i915)
@@ -1118,6 +1105,13 @@ static bool is_igp(struct drm_i915_private *i915)
 void i915_pmu_register(struct drm_i915_private *i915)
 {
        struct i915_pmu *pmu = &i915->pmu;
+       const struct attribute_group *attr_groups[] = {
+               &i915_pmu_format_attr_group,
+               &pmu->events_attr_group,
+               &i915_pmu_cpumask_attr_group,
+               NULL
+       };
+
        int ret = -ENOMEM;
 
        if (INTEL_GEN(i915) <= 2) {
@@ -1128,6 +1122,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
        spin_lock_init(&pmu->lock);
        hrtimer_init(&pmu->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        pmu->timer.function = i915_sample;
+       pmu->cpuhp.slot = CPUHP_INVALID;
 
        if (!is_igp(i915)) {
                pmu->name = kasprintf(GFP_KERNEL,
@@ -1143,11 +1138,16 @@ void i915_pmu_register(struct drm_i915_private *i915)
        if (!pmu->name)
                goto err;
 
-       i915_pmu_events_attr_group.attrs = create_event_attributes(pmu);
-       if (!i915_pmu_events_attr_group.attrs)
+       pmu->events_attr_group.name = "events";
+       pmu->events_attr_group.attrs = create_event_attributes(pmu);
+       if (!pmu->events_attr_group.attrs)
                goto err_name;
 
-       pmu->base.attr_groups   = i915_pmu_attr_groups;
+       pmu->base.attr_groups = kmemdup(attr_groups, sizeof(attr_groups),
+                                       GFP_KERNEL);
+       if (!pmu->base.attr_groups)
+               goto err_attr;
+
        pmu->base.task_ctx_nr   = perf_invalid_context;
        pmu->base.event_init    = i915_pmu_event_init;
        pmu->base.add           = i915_pmu_event_add;
@@ -1159,7 +1159,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
 
        ret = perf_pmu_register(&pmu->base, pmu->name, -1);
        if (ret)
-               goto err_attr;
+               goto err_groups;
 
        ret = i915_pmu_register_cpuhp_state(pmu);
        if (ret)
@@ -1169,6 +1169,8 @@ void i915_pmu_register(struct drm_i915_private *i915)
 
 err_unreg:
        perf_pmu_unregister(&pmu->base);
+err_groups:
+       kfree(pmu->base.attr_groups);
 err_attr:
        pmu->base.event_init = NULL;
        free_event_attributes(pmu);
@@ -1194,6 +1196,7 @@ void i915_pmu_unregister(struct drm_i915_private *i915)
 
        perf_pmu_unregister(&pmu->base);
        pmu->base.event_init = NULL;
+       kfree(pmu->base.attr_groups);
        if (!is_igp(i915))
                kfree(pmu->name);
        free_event_attributes(pmu);
index 6c1647c..f1d6cad 100644 (file)
@@ -39,9 +39,12 @@ struct i915_pmu_sample {
 
 struct i915_pmu {
        /**
-        * @node: List node for CPU hotplug handling.
+        * @cpuhp: Struct used for CPU hotplug handling.
         */
-       struct hlist_node node;
+       struct {
+               struct hlist_node node;
+               enum cpuhp_state slot;
+       } cpuhp;
        /**
         * @base: PMU base.
         */
@@ -105,6 +108,10 @@ struct i915_pmu {
         */
        ktime_t sleep_last;
        /**
+        * @events_attr_group: Device events attribute group.
+        */
+       struct attribute_group events_attr_group;
+       /**
         * @i915_attr: Memory block holding device attributes.
         */
        void *i915_attr;
index 6cc55c1..3575fd3 100644 (file)
@@ -7757,6 +7757,7 @@ enum {
 #define BW_BUDDY1_CTL                  _MMIO(0x45140)
 #define BW_BUDDY2_CTL                  _MMIO(0x45150)
 #define   BW_BUDDY_DISABLE             REG_BIT(31)
+#define   BW_BUDDY_TLB_REQ_TIMER_MASK  REG_GENMASK(21, 16)
 
 #define BW_BUDDY1_PAGE_MASK            _MMIO(0x45144)
 #define BW_BUDDY2_PAGE_MASK            _MMIO(0x45154)
index f56b046..a18b2a2 100644 (file)
@@ -275,7 +275,7 @@ bool i915_request_retire(struct i915_request *rq)
        spin_unlock_irq(&rq->lock);
 
        remove_from_client(rq);
-       list_del(&rq->link);
+       list_del_rcu(&rq->link);
 
        intel_context_exit(rq->context);
        intel_context_unpin(rq->context);
@@ -527,19 +527,31 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
        return NOTIFY_DONE;
 }
 
+static void irq_semaphore_cb(struct irq_work *wrk)
+{
+       struct i915_request *rq =
+               container_of(wrk, typeof(*rq), semaphore_work);
+
+       i915_schedule_bump_priority(rq, I915_PRIORITY_NOSEMAPHORE);
+       i915_request_put(rq);
+}
+
 static int __i915_sw_fence_call
 semaphore_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
 {
-       struct i915_request *request =
-               container_of(fence, typeof(*request), semaphore);
+       struct i915_request *rq = container_of(fence, typeof(*rq), semaphore);
 
        switch (state) {
        case FENCE_COMPLETE:
-               i915_schedule_bump_priority(request, I915_PRIORITY_NOSEMAPHORE);
+               if (!(READ_ONCE(rq->sched.attr.priority) & I915_PRIORITY_NOSEMAPHORE)) {
+                       i915_request_get(rq);
+                       init_irq_work(&rq->semaphore_work, irq_semaphore_cb);
+                       irq_work_queue(&rq->semaphore_work);
+               }
                break;
 
        case FENCE_FREE:
-               i915_request_put(request);
+               i915_request_put(rq);
                break;
        }
 
@@ -721,6 +733,8 @@ __i915_request_create(struct intel_context *ce, gfp_t gfp)
        rq->infix = rq->ring->emit; /* end of header; start of user payload */
 
        intel_context_mark_active(ce);
+       list_add_tail_rcu(&rq->link, &tl->requests);
+
        return rq;
 
 err_unwind:
@@ -774,16 +788,26 @@ i915_request_await_start(struct i915_request *rq, struct i915_request *signal)
        struct dma_fence *fence;
        int err;
 
-       GEM_BUG_ON(i915_request_timeline(rq) ==
-                  rcu_access_pointer(signal->timeline));
+       if (i915_request_timeline(rq) == rcu_access_pointer(signal->timeline))
+               return 0;
+
+       if (i915_request_started(signal))
+               return 0;
 
        fence = NULL;
        rcu_read_lock();
        spin_lock_irq(&signal->lock);
-       if (!i915_request_started(signal) &&
-           !list_is_first(&signal->link,
-                          &rcu_dereference(signal->timeline)->requests)) {
-               struct i915_request *prev = list_prev_entry(signal, link);
+       do {
+               struct list_head *pos = READ_ONCE(signal->link.prev);
+               struct i915_request *prev;
+
+               /* Confirm signal has not been retired, the link is valid */
+               if (unlikely(i915_request_started(signal)))
+                       break;
+
+               /* Is signal the earliest request on its timeline? */
+               if (pos == &rcu_dereference(signal->timeline)->requests)
+                       break;
 
                /*
                 * Peek at the request before us in the timeline. That
@@ -791,20 +815,25 @@ i915_request_await_start(struct i915_request *rq, struct i915_request *signal)
                 * after acquiring a reference to it, confirm that it is
                 * still part of the signaler's timeline.
                 */
-               if (i915_request_get_rcu(prev)) {
-                       if (list_next_entry(prev, link) == signal)
-                               fence = &prev->fence;
-                       else
-                               i915_request_put(prev);
+               prev = list_entry(pos, typeof(*prev), link);
+               if (!i915_request_get_rcu(prev))
+                       break;
+
+               /* After the strong barrier, confirm prev is still attached */
+               if (unlikely(READ_ONCE(prev->link.next) != &signal->link)) {
+                       i915_request_put(prev);
+                       break;
                }
-       }
+
+               fence = &prev->fence;
+       } while (0);
        spin_unlock_irq(&signal->lock);
        rcu_read_unlock();
        if (!fence)
                return 0;
 
        err = 0;
-       if (intel_timeline_sync_is_later(i915_request_timeline(rq), fence))
+       if (!intel_timeline_sync_is_later(i915_request_timeline(rq), fence))
                err = i915_sw_fence_await_dma_fence(&rq->submit,
                                                    fence, 0,
                                                    I915_FENCE_GFP);
@@ -1242,8 +1271,6 @@ __i915_request_add_to_timeline(struct i915_request *rq)
                                                         0);
        }
 
-       list_add_tail(&rq->link, &timeline->requests);
-
        /*
         * Make sure that no request gazumped us - if it was allocated after
         * our i915_request_alloc() and called __i915_request_add() before
@@ -1303,9 +1330,9 @@ void __i915_request_queue(struct i915_request *rq,
         * decide whether to preempt the entire chain so that it is ready to
         * run at the earliest possible convenience.
         */
-       i915_sw_fence_commit(&rq->semaphore);
        if (attr && rq->engine->schedule)
                rq->engine->schedule(rq, attr);
+       i915_sw_fence_commit(&rq->semaphore);
        i915_sw_fence_commit(&rq->submit);
 }
 
index f57eadc..fccc339 100644 (file)
@@ -26,6 +26,7 @@
 #define I915_REQUEST_H
 
 #include <linux/dma-fence.h>
+#include <linux/irq_work.h>
 #include <linux/lockdep.h>
 
 #include "gem/i915_gem_context_types.h"
@@ -208,6 +209,7 @@ struct i915_request {
        };
        struct list_head execute_cb;
        struct i915_sw_fence semaphore;
+       struct irq_work semaphore_work;
 
        /*
         * A list of everyone we wait upon, and everyone who waits upon us.
index b0ade76..d34141f 100644 (file)
@@ -234,6 +234,11 @@ static inline u64 ptr_to_u64(const void *ptr)
        __idx;                                                          \
 })
 
+static inline bool is_power_of_2_u64(u64 n)
+{
+       return (n != 0 && ((n & (n - 1)) == 0));
+}
+
 static inline void __list_del_many(struct list_head *head,
                                   struct list_head *first)
 {
index cbfb717..0648eda 100644 (file)
@@ -60,7 +60,7 @@ static void __vlv_punit_get(struct drm_i915_private *i915)
         * to the Valleyview P-unit and not all sideband communications.
         */
        if (IS_VALLEYVIEW(i915)) {
-               pm_qos_update_request(&i915->sb_qos, 0);
+               cpu_latency_qos_update_request(&i915->sb_qos, 0);
                on_each_cpu(ping, NULL, 1);
        }
 }
@@ -68,7 +68,8 @@ static void __vlv_punit_get(struct drm_i915_private *i915)
 static void __vlv_punit_put(struct drm_i915_private *i915)
 {
        if (IS_VALLEYVIEW(i915))
-               pm_qos_update_request(&i915->sb_qos, PM_QOS_DEFAULT_VALUE);
+               cpu_latency_qos_update_request(&i915->sb_qos,
+                                              PM_QOS_DEFAULT_VALUE);
 
        iosf_mbi_punit_release();
 }
index 0dfcd17..fe85e48 100644 (file)
@@ -486,6 +486,7 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc)
        }
 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
        if (mtk_crtc->cmdq_client) {
+               mbox_flush(mtk_crtc->cmdq_client->chan, 2000);
                cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE);
                cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event);
                cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event);
@@ -636,10 +637,18 @@ static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
 
 static int mtk_drm_crtc_init(struct drm_device *drm,
                             struct mtk_drm_crtc *mtk_crtc,
-                            struct drm_plane *primary,
-                            struct drm_plane *cursor, unsigned int pipe)
+                            unsigned int pipe)
 {
-       int ret;
+       struct drm_plane *primary = NULL;
+       struct drm_plane *cursor = NULL;
+       int i, ret;
+
+       for (i = 0; i < mtk_crtc->layer_nr; i++) {
+               if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_PRIMARY)
+                       primary = &mtk_crtc->planes[i];
+               else if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR)
+                       cursor = &mtk_crtc->planes[i];
+       }
 
        ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor,
                                        &mtk_crtc_funcs, NULL);
@@ -689,11 +698,12 @@ static int mtk_drm_crtc_num_comp_planes(struct mtk_drm_crtc *mtk_crtc,
 }
 
 static inline
-enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx)
+enum drm_plane_type mtk_drm_crtc_plane_type(unsigned int plane_idx,
+                                           unsigned int num_planes)
 {
        if (plane_idx == 0)
                return DRM_PLANE_TYPE_PRIMARY;
-       else if (plane_idx == 1)
+       else if (plane_idx == (num_planes - 1))
                return DRM_PLANE_TYPE_CURSOR;
        else
                return DRM_PLANE_TYPE_OVERLAY;
@@ -712,7 +722,8 @@ static int mtk_drm_crtc_init_comp_planes(struct drm_device *drm_dev,
                ret = mtk_plane_init(drm_dev,
                                &mtk_crtc->planes[mtk_crtc->layer_nr],
                                BIT(pipe),
-                               mtk_drm_crtc_plane_type(mtk_crtc->layer_nr),
+                               mtk_drm_crtc_plane_type(mtk_crtc->layer_nr,
+                                                       num_planes),
                                mtk_ddp_comp_supported_rotations(comp));
                if (ret)
                        return ret;
@@ -807,9 +818,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
                        return ret;
        }
 
-       ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, &mtk_crtc->planes[0],
-                               mtk_crtc->layer_nr > 1 ? &mtk_crtc->planes[1] :
-                               NULL, pipe);
+       ret = mtk_drm_crtc_init(drm_dev, mtk_crtc, pipe);
        if (ret < 0)
                return ret;
 
@@ -828,7 +837,8 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev,
                        drm_crtc_index(&mtk_crtc->base));
                mtk_crtc->cmdq_client = NULL;
        }
-       ret = of_property_read_u32_index(dev->of_node, "mediatek,gce-events",
+       ret = of_property_read_u32_index(priv->mutex_node,
+                                        "mediatek,gce-events",
                                         drm_crtc_index(&mtk_crtc->base),
                                         &mtk_crtc->cmdq_event);
        if (ret)
index 1f5a112..57c88de 100644 (file)
@@ -471,6 +471,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
        /* Only DMA capable components need the LARB property */
        comp->larb_dev = NULL;
        if (type != MTK_DISP_OVL &&
+           type != MTK_DISP_OVL_2L &&
            type != MTK_DISP_RDMA &&
            type != MTK_DISP_WDMA)
                return 0;
index 914cc76..c2bd683 100644 (file)
@@ -80,6 +80,7 @@ static int mtk_plane_atomic_async_check(struct drm_plane *plane,
                                        struct drm_plane_state *state)
 {
        struct drm_crtc_state *crtc_state;
+       int ret;
 
        if (plane != state->crtc->cursor)
                return -EINVAL;
@@ -90,6 +91,11 @@ static int mtk_plane_atomic_async_check(struct drm_plane *plane,
        if (!plane->state->fb)
                return -EINVAL;
 
+       ret = mtk_drm_crtc_plane_check(state->crtc, plane,
+                                      to_mtk_plane_state(state));
+       if (ret)
+               return ret;
+
        if (state->state)
                crtc_state = drm_atomic_get_existing_crtc_state(state->state,
                                                                state->crtc);
@@ -115,6 +121,7 @@ static void mtk_plane_atomic_async_update(struct drm_plane *plane,
        plane->state->src_y = new_state->src_y;
        plane->state->src_h = new_state->src_h;
        plane->state->src_w = new_state->src_w;
+       swap(plane->state->fb, new_state->fb);
        state->pending.async_dirty = true;
 
        mtk_drm_crtc_async_update(new_state->crtc, plane, new_state);
index 3107b07..5d75f8c 100644 (file)
@@ -601,33 +601,27 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
                source_id = (fault_status >> 16);
 
                /* Page fault only */
-               if ((status & mask) == BIT(i)) {
-                       WARN_ON(exception_type < 0xC1 || exception_type > 0xC4);
-
+               ret = -1;
+               if ((status & mask) == BIT(i) && (exception_type & 0xF8) == 0xC0)
                        ret = panfrost_mmu_map_fault_addr(pfdev, i, addr);
-                       if (!ret) {
-                               mmu_write(pfdev, MMU_INT_CLEAR, BIT(i));
-                               status &= ~mask;
-                               continue;
-                       }
-               }
 
-               /* terminal fault, print info about the fault */
-               dev_err(pfdev->dev,
-                       "Unhandled Page fault in AS%d at VA 0x%016llX\n"
-                       "Reason: %s\n"
-                       "raw fault status: 0x%X\n"
-                       "decoded fault status: %s\n"
-                       "exception type 0x%X: %s\n"
-                       "access type 0x%X: %s\n"
-                       "source id 0x%X\n",
-                       i, addr,
-                       "TODO",
-                       fault_status,
-                       (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
-                       exception_type, panfrost_exception_name(pfdev, exception_type),
-                       access_type, access_type_name(pfdev, fault_status),
-                       source_id);
+               if (ret)
+                       /* terminal fault, print info about the fault */
+                       dev_err(pfdev->dev,
+                               "Unhandled Page fault in AS%d at VA 0x%016llX\n"
+                               "Reason: %s\n"
+                               "raw fault status: 0x%X\n"
+                               "decoded fault status: %s\n"
+                               "exception type 0x%X: %s\n"
+                               "access type 0x%X: %s\n"
+                               "source id 0x%X\n",
+                               i, addr,
+                               "TODO",
+                               fault_status,
+                               (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"),
+                               exception_type, panfrost_exception_name(pfdev, exception_type),
+                               access_type, access_type_name(pfdev, fault_status),
+                               source_id);
 
                mmu_write(pfdev, MMU_INT_CLEAR, mask);
 
index fd74e26..8696af1 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/vga_switcheroo.h>
 #include <linux/mmu_notifier.h>
 
+#include <drm/drm_agpsupport.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_drv.h>
 #include <drm/drm_fb_helper.h>
@@ -325,6 +326,7 @@ static int radeon_pci_probe(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
 {
        unsigned long flags = 0;
+       struct drm_device *dev;
        int ret;
 
        if (!ent)
@@ -365,7 +367,44 @@ static int radeon_pci_probe(struct pci_dev *pdev,
        if (ret)
                return ret;
 
-       return drm_get_pci_dev(pdev, ent, &kms_driver);
+       dev = drm_dev_alloc(&kms_driver, &pdev->dev);
+       if (IS_ERR(dev))
+               return PTR_ERR(dev);
+
+       ret = pci_enable_device(pdev);
+       if (ret)
+               goto err_free;
+
+       dev->pdev = pdev;
+#ifdef __alpha__
+       dev->hose = pdev->sysdata;
+#endif
+
+       pci_set_drvdata(pdev, dev);
+
+       if (pci_find_capability(dev->pdev, PCI_CAP_ID_AGP))
+               dev->agp = drm_agp_init(dev);
+       if (dev->agp) {
+               dev->agp->agp_mtrr = arch_phys_wc_add(
+                       dev->agp->agp_info.aper_base,
+                       dev->agp->agp_info.aper_size *
+                       1024 * 1024);
+       }
+
+       ret = drm_dev_register(dev, ent->driver_data);
+       if (ret)
+               goto err_agp;
+
+       return 0;
+
+err_agp:
+       if (dev->agp)
+               arch_phys_wc_del(dev->agp->agp_mtrr);
+       kfree(dev->agp);
+       pci_disable_device(pdev);
+err_free:
+       drm_dev_put(dev);
+       return ret;
 }
 
 static void
@@ -575,7 +614,7 @@ radeon_get_crtc_scanout_position(struct drm_device *dev, unsigned int pipe,
 
 static struct drm_driver kms_driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_GEM | DRIVER_RENDER,
+           DRIVER_GEM | DRIVER_RENDER,
        .load = radeon_driver_load_kms,
        .open = radeon_driver_open_kms,
        .postclose = radeon_driver_postclose_kms,
index d24f23a..dd2f19b 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/uaccess.h>
 #include <linux/vga_switcheroo.h>
 
+#include <drm/drm_agpsupport.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_file.h>
 #include <drm/drm_ioctl.h>
@@ -77,6 +78,11 @@ void radeon_driver_unload_kms(struct drm_device *dev)
        radeon_modeset_fini(rdev);
        radeon_device_fini(rdev);
 
+       if (dev->agp)
+               arch_phys_wc_del(dev->agp->agp_mtrr);
+       kfree(dev->agp);
+       dev->agp = NULL;
+
 done_free:
        kfree(rdev);
        dev->dev_private = NULL;
index 3b92311..b3380ff 100644 (file)
@@ -528,7 +528,7 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
 
        r = -ENOMEM;
        nents = dma_map_sg(rdev->dev, ttm->sg->sgl, ttm->sg->nents, direction);
-       if (nents != ttm->sg->nents)
+       if (nents == 0)
                goto release_sg;
 
        drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
index 71ce621..60c4c6a 100644 (file)
@@ -661,7 +661,9 @@ static void drm_sched_process_job(struct dma_fence *f, struct dma_fence_cb *cb)
 
        trace_drm_sched_process_job(s_fence);
 
+       dma_fence_get(&s_fence->finished);
        drm_sched_fence_finished(s_fence);
+       dma_fence_put(&s_fence->finished);
        wake_up_interruptible(&sched->wake_up_worker);
 }
 
index 7c24f8f..4a64f7a 100644 (file)
@@ -107,48 +107,128 @@ static const struct de2_fmt_info de2_formats[] = {
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_XRGB4444,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ARGB4444,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_ABGR4444,
                .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_XBGR4444,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ABGR4444,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_RGBA4444,
                .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_RGBX4444,
+               .de2_fmt = SUN8I_MIXER_FBFMT_RGBA4444,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_BGRA4444,
                .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_BGRX4444,
+               .de2_fmt = SUN8I_MIXER_FBFMT_BGRA4444,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_ARGB1555,
                .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_XRGB1555,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ARGB1555,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_ABGR1555,
                .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_XBGR1555,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ABGR1555,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_RGBA5551,
                .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_RGBX5551,
+               .de2_fmt = SUN8I_MIXER_FBFMT_RGBA5551,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_BGRA5551,
                .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
                .rgb = true,
                .csc = SUN8I_CSC_MODE_OFF,
        },
        {
+               /* for DE2 VI layer which ignores alpha */
+               .drm_fmt = DRM_FORMAT_BGRX5551,
+               .de2_fmt = SUN8I_MIXER_FBFMT_BGRA5551,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_ARGB2101010,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ARGB2101010,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_ABGR2101010,
+               .de2_fmt = SUN8I_MIXER_FBFMT_ABGR2101010,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_RGBA1010102,
+               .de2_fmt = SUN8I_MIXER_FBFMT_RGBA1010102,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_BGRA1010102,
+               .de2_fmt = SUN8I_MIXER_FBFMT_BGRA1010102,
+               .rgb = true,
+               .csc = SUN8I_CSC_MODE_OFF,
+       },
+       {
                .drm_fmt = DRM_FORMAT_UYVY,
                .de2_fmt = SUN8I_MIXER_FBFMT_UYVY,
                .rgb = false,
@@ -197,12 +277,6 @@ static const struct de2_fmt_info de2_formats[] = {
                .csc = SUN8I_CSC_MODE_YUV2RGB,
        },
        {
-               .drm_fmt = DRM_FORMAT_YUV444,
-               .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
-               .rgb = true,
-               .csc = SUN8I_CSC_MODE_YUV2RGB,
-       },
-       {
                .drm_fmt = DRM_FORMAT_YUV422,
                .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
                .rgb = false,
@@ -221,12 +295,6 @@ static const struct de2_fmt_info de2_formats[] = {
                .csc = SUN8I_CSC_MODE_YUV2RGB,
        },
        {
-               .drm_fmt = DRM_FORMAT_YVU444,
-               .de2_fmt = SUN8I_MIXER_FBFMT_RGB888,
-               .rgb = true,
-               .csc = SUN8I_CSC_MODE_YVU2RGB,
-       },
-       {
                .drm_fmt = DRM_FORMAT_YVU422,
                .de2_fmt = SUN8I_MIXER_FBFMT_YUV422,
                .rgb = false,
@@ -244,6 +312,18 @@ static const struct de2_fmt_info de2_formats[] = {
                .rgb = false,
                .csc = SUN8I_CSC_MODE_YVU2RGB,
        },
+       {
+               .drm_fmt = DRM_FORMAT_P010,
+               .de2_fmt = SUN8I_MIXER_FBFMT_P010_YUV,
+               .rgb = false,
+               .csc = SUN8I_CSC_MODE_YUV2RGB,
+       },
+       {
+               .drm_fmt = DRM_FORMAT_P210,
+               .de2_fmt = SUN8I_MIXER_FBFMT_P210_YUV,
+               .rgb = false,
+               .csc = SUN8I_CSC_MODE_YUV2RGB,
+       },
 };
 
 const struct de2_fmt_info *sun8i_mixer_format_info(u32 format)
index c6cc940..345b28b 100644 (file)
 #define SUN8I_MIXER_FBFMT_ABGR1555     17
 #define SUN8I_MIXER_FBFMT_RGBA5551     18
 #define SUN8I_MIXER_FBFMT_BGRA5551     19
+#define SUN8I_MIXER_FBFMT_ARGB2101010  20
+#define SUN8I_MIXER_FBFMT_ABGR2101010  21
+#define SUN8I_MIXER_FBFMT_RGBA1010102  22
+#define SUN8I_MIXER_FBFMT_BGRA1010102  23
 
 #define SUN8I_MIXER_FBFMT_YUYV         0
 #define SUN8I_MIXER_FBFMT_UYVY         1
 /* format 12 is semi-planar YUV411 UVUV */
 /* format 13 is semi-planar YUV411 VUVU */
 #define SUN8I_MIXER_FBFMT_YUV411       14
+/* format 15 doesn't exist */
+/* format 16 is P010 YVU */
+#define SUN8I_MIXER_FBFMT_P010_YUV     17
+/* format 18 is P210 YVU */
+#define SUN8I_MIXER_FBFMT_P210_YUV     19
+/* format 20 is packed YVU444 10-bit */
+/* format 21 is packed YUV444 10-bit */
 
 /*
  * Sub-engines listed bellow are unused for now. The EN registers are here only
index 42d445d..b8398ca 100644 (file)
@@ -398,24 +398,66 @@ static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
 };
 
 /*
- * While all RGB formats are supported, VI planes don't support
- * alpha blending, so there is no point having formats with alpha
- * channel if their opaque analog exist.
+ * While DE2 VI layer supports same RGB formats as UI layer, alpha
+ * channel is ignored. This structure lists all unique variants
+ * where alpha channel is replaced with "don't care" (X) channel.
  */
 static const u32 sun8i_vi_layer_formats[] = {
+       DRM_FORMAT_BGR565,
+       DRM_FORMAT_BGR888,
+       DRM_FORMAT_BGRX4444,
+       DRM_FORMAT_BGRX5551,
+       DRM_FORMAT_BGRX8888,
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_RGB888,
+       DRM_FORMAT_RGBX4444,
+       DRM_FORMAT_RGBX5551,
+       DRM_FORMAT_RGBX8888,
+       DRM_FORMAT_XBGR1555,
+       DRM_FORMAT_XBGR4444,
+       DRM_FORMAT_XBGR8888,
+       DRM_FORMAT_XRGB1555,
+       DRM_FORMAT_XRGB4444,
+       DRM_FORMAT_XRGB8888,
+
+       DRM_FORMAT_NV16,
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_NV21,
+       DRM_FORMAT_NV61,
+       DRM_FORMAT_UYVY,
+       DRM_FORMAT_VYUY,
+       DRM_FORMAT_YUYV,
+       DRM_FORMAT_YVYU,
+       DRM_FORMAT_YUV411,
+       DRM_FORMAT_YUV420,
+       DRM_FORMAT_YUV422,
+       DRM_FORMAT_YVU411,
+       DRM_FORMAT_YVU420,
+       DRM_FORMAT_YVU422,
+};
+
+static const u32 sun8i_vi_layer_de3_formats[] = {
        DRM_FORMAT_ABGR1555,
+       DRM_FORMAT_ABGR2101010,
        DRM_FORMAT_ABGR4444,
+       DRM_FORMAT_ABGR8888,
        DRM_FORMAT_ARGB1555,
+       DRM_FORMAT_ARGB2101010,
        DRM_FORMAT_ARGB4444,
+       DRM_FORMAT_ARGB8888,
        DRM_FORMAT_BGR565,
        DRM_FORMAT_BGR888,
+       DRM_FORMAT_BGRA1010102,
        DRM_FORMAT_BGRA5551,
        DRM_FORMAT_BGRA4444,
+       DRM_FORMAT_BGRA8888,
        DRM_FORMAT_BGRX8888,
        DRM_FORMAT_RGB565,
        DRM_FORMAT_RGB888,
+       DRM_FORMAT_RGBA1010102,
        DRM_FORMAT_RGBA4444,
        DRM_FORMAT_RGBA5551,
+       DRM_FORMAT_RGBA8888,
        DRM_FORMAT_RGBX8888,
        DRM_FORMAT_XBGR8888,
        DRM_FORMAT_XRGB8888,
@@ -424,6 +466,8 @@ static const u32 sun8i_vi_layer_formats[] = {
        DRM_FORMAT_NV12,
        DRM_FORMAT_NV21,
        DRM_FORMAT_NV61,
+       DRM_FORMAT_P010,
+       DRM_FORMAT_P210,
        DRM_FORMAT_UYVY,
        DRM_FORMAT_VYUY,
        DRM_FORMAT_YUYV,
@@ -431,11 +475,9 @@ static const u32 sun8i_vi_layer_formats[] = {
        DRM_FORMAT_YUV411,
        DRM_FORMAT_YUV420,
        DRM_FORMAT_YUV422,
-       DRM_FORMAT_YUV444,
        DRM_FORMAT_YVU411,
        DRM_FORMAT_YVU420,
        DRM_FORMAT_YVU422,
-       DRM_FORMAT_YVU444,
 };
 
 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
@@ -443,19 +485,27 @@ struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
                                               int index)
 {
        u32 supported_encodings, supported_ranges;
+       unsigned int plane_cnt, format_count;
        struct sun8i_vi_layer *layer;
-       unsigned int plane_cnt;
+       const u32 *formats;
        int ret;
 
        layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
        if (!layer)
                return ERR_PTR(-ENOMEM);
 
+       if (mixer->cfg->is_de3) {
+               formats = sun8i_vi_layer_de3_formats;
+               format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
+       } else {
+               formats = sun8i_vi_layer_formats;
+               format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
+       }
+
        /* possible crtcs are set later */
        ret = drm_universal_plane_init(drm, &layer->plane, 0,
                                       &sun8i_vi_layer_funcs,
-                                      sun8i_vi_layer_formats,
-                                      ARRAY_SIZE(sun8i_vi_layer_formats),
+                                      formats, format_count,
                                       NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
        if (ret) {
                dev_err(drm->dev, "Couldn't initialize layer\n");
index 49ed557..953c82a 100644 (file)
@@ -515,6 +515,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
                fbo->base.base.resv = &fbo->base.base._resv;
 
        dma_resv_init(&fbo->base.base._resv);
+       fbo->base.base.dev = NULL;
        ret = dma_resv_trylock(&fbo->base.base._resv);
        WARN_ON(!ret);
 
index 017a9e0..3af7ec8 100644 (file)
@@ -42,8 +42,8 @@ static int virtio_gpu_resource_id_get(struct virtio_gpu_device *vgdev,
                 * "f91a9dd35715 Fix unlinking resources from hash
                 * table." (Feb 2019) fixes the bug.
                 */
-               static int handle;
-               handle++;
+               static atomic_t seqno = ATOMIC_INIT(0);
+               int handle = atomic_inc_return(&seqno);
                *resid = handle + 1;
        } else {
                int handle = ida_alloc(&vgdev->resource_ida, GFP_KERNEL);
@@ -99,6 +99,7 @@ struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
                return NULL;
 
        bo->base.base.funcs = &virtio_gpu_gem_funcs;
+       bo->base.map_cached = true;
        return &bo->base.base;
 }
 
index ae79a7c..fa70415 100644 (file)
@@ -730,7 +730,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
        if (data->has_sp) {
                input2 = input_allocate_device();
                if (!input2) {
-                       input_free_device(input2);
+                       ret = -ENOMEM;
                        goto exit;
                }
 
index 6ac8bec..d732d1d 100644 (file)
@@ -340,7 +340,8 @@ static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                unsigned long **bit, int *max)
 {
        if (usage->hid == (HID_UP_CUSTOM | 0x0003) ||
-                       usage->hid == (HID_UP_MSVENDOR | 0x0003)) {
+                       usage->hid == (HID_UP_MSVENDOR | 0x0003) ||
+                       usage->hid == (HID_UP_HPVENDOR2 | 0x0003)) {
                /* The fn key on Apple USB keyboards */
                set_bit(EV_REP, hi->input->evbit);
                hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
index 3f6abd1..db6da21 100644 (file)
@@ -174,6 +174,7 @@ static __u8 pid0902_rdesc_fixed[] = {
 struct bigben_device {
        struct hid_device *hid;
        struct hid_report *report;
+       bool removed;
        u8 led_state;         /* LED1 = 1 .. LED4 = 8 */
        u8 right_motor_on;    /* right motor off/on 0/1 */
        u8 left_motor_force;  /* left motor force 0-255 */
@@ -190,6 +191,9 @@ static void bigben_worker(struct work_struct *work)
                struct bigben_device, worker);
        struct hid_field *report_field = bigben->report->field[0];
 
+       if (bigben->removed)
+               return;
+
        if (bigben->work_led) {
                bigben->work_led = false;
                report_field->value[0] = 0x01; /* 1 = led message */
@@ -220,10 +224,16 @@ static void bigben_worker(struct work_struct *work)
 static int hid_bigben_play_effect(struct input_dev *dev, void *data,
                         struct ff_effect *effect)
 {
-       struct bigben_device *bigben = data;
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct bigben_device *bigben = hid_get_drvdata(hid);
        u8 right_motor_on;
        u8 left_motor_force;
 
+       if (!bigben) {
+               hid_err(hid, "no device data\n");
+               return 0;
+       }
+
        if (effect->type != FF_RUMBLE)
                return 0;
 
@@ -298,8 +308,8 @@ static void bigben_remove(struct hid_device *hid)
 {
        struct bigben_device *bigben = hid_get_drvdata(hid);
 
+       bigben->removed = true;
        cancel_work_sync(&bigben->worker);
-       hid_hw_close(hid);
        hid_hw_stop(hid);
 }
 
@@ -319,6 +329,7 @@ static int bigben_probe(struct hid_device *hid,
                return -ENOMEM;
        hid_set_drvdata(hid, bigben);
        bigben->hid = hid;
+       bigben->removed = false;
 
        error = hid_parse(hid);
        if (error) {
@@ -341,10 +352,10 @@ static int bigben_probe(struct hid_device *hid,
 
        INIT_WORK(&bigben->worker, bigben_worker);
 
-       error = input_ff_create_memless(hidinput->input, bigben,
+       error = input_ff_create_memless(hidinput->input, NULL,
                hid_bigben_play_effect);
        if (error)
-               return error;
+               goto error_hw_stop;
 
        name_sz = strlen(dev_name(&hid->dev)) + strlen(":red:bigben#") + 1;
 
@@ -354,8 +365,10 @@ static int bigben_probe(struct hid_device *hid,
                        sizeof(struct led_classdev) + name_sz,
                        GFP_KERNEL
                );
-               if (!led)
-                       return -ENOMEM;
+               if (!led) {
+                       error = -ENOMEM;
+                       goto error_hw_stop;
+               }
                name = (void *)(&led[1]);
                snprintf(name, name_sz,
                        "%s:red:bigben%d",
@@ -369,7 +382,7 @@ static int bigben_probe(struct hid_device *hid,
                bigben->leds[n] = led;
                error = devm_led_classdev_register(&hid->dev, led);
                if (error)
-                       return error;
+                       goto error_hw_stop;
        }
 
        /* initial state: LED1 is on, no rumble effect */
@@ -383,6 +396,10 @@ static int bigben_probe(struct hid_device *hid,
        hid_info(hid, "LED and force feedback support for BigBen gamepad\n");
 
        return 0;
+
+error_hw_stop:
+       hid_hw_stop(hid);
+       return error;
 }
 
 static __u8 *bigben_report_fixup(struct hid_device *hid, __u8 *rdesc,
index 851fe54..359616e 100644 (file)
@@ -1741,7 +1741,9 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
 
        rsize = ((report->size - 1) >> 3) + 1;
 
-       if (rsize > HID_MAX_BUFFER_SIZE)
+       if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
+               rsize = HID_MAX_BUFFER_SIZE - 1;
+       else if (rsize > HID_MAX_BUFFER_SIZE)
                rsize = HID_MAX_BUFFER_SIZE;
 
        if (csize < rsize) {
index 2aa4ed1..85a054f 100644 (file)
@@ -533,6 +533,8 @@ static const struct hid_device_id hammer_devices[] = {
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MASTERBALL) },
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+                    USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MOONBALL) },
+       { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STAFF) },
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_WAND) },
index dddfca5..0b6ee1d 100644 (file)
@@ -193,8 +193,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
                goto cleanup;
 
        /* The pointer is not NULL when we resume from hibernation */
-       if (input_device->hid_desc != NULL)
-               kfree(input_device->hid_desc);
+       kfree(input_device->hid_desc);
        input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
 
        if (!input_device->hid_desc)
@@ -207,8 +206,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
        }
 
        /* The pointer is not NULL when we resume from hibernation */
-       if (input_device->report_desc != NULL)
-               kfree(input_device->report_desc);
+       kfree(input_device->report_desc);
        input_device->report_desc = kzalloc(input_device->report_desc_size,
                                          GFP_ATOMIC);
 
index 3a400ce..9f22134 100644 (file)
 #define USB_DEVICE_ID_GOOGLE_WHISKERS  0x5030
 #define USB_DEVICE_ID_GOOGLE_MASTERBALL        0x503c
 #define USB_DEVICE_ID_GOOGLE_MAGNEMITE 0x503d
+#define USB_DEVICE_ID_GOOGLE_MOONBALL  0x5044
 
 #define USB_VENDOR_ID_GOTOP            0x08f2
 #define USB_DEVICE_ID_SUPER_Q2         0x007f
 #define USB_DEVICE_ID_LENOVO_X1_COVER  0x6085
 #define USB_DEVICE_ID_LENOVO_X1_TAB    0x60a3
 #define USB_DEVICE_ID_LENOVO_X1_TAB3   0x60b5
+#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D     0x608d
 
 #define USB_VENDOR_ID_LG               0x1fd2
 #define USB_DEVICE_ID_LG_MULTITOUCH    0x0064
index c436e12..6c55682 100644 (file)
@@ -41,8 +41,9 @@ static const struct hid_device_id ite_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) },
        { HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) },
        /* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */
-       { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS,
-                        USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) },
+       { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+                    USB_VENDOR_ID_SYNAPTICS,
+                    USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012) },
        { }
 };
 MODULE_DEVICE_TABLE(hid, ite_devices);
index 70e1cb9..094f4f1 100644 (file)
@@ -1256,36 +1256,35 @@ static int hidpp20_battery_map_status_voltage(u8 data[3], int *voltage,
 {
        int status;
 
-       long charge_sts = (long)data[2];
+       long flags = (long) data[2];
 
-       *level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN;
-       switch (data[2] & 0xe0) {
-       case 0x00:
-               status = POWER_SUPPLY_STATUS_CHARGING;
-               break;
-       case 0x20:
-               status = POWER_SUPPLY_STATUS_FULL;
-               *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
-               break;
-       case 0x40:
+       if (flags & 0x80)
+               switch (flags & 0x07) {
+               case 0:
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               case 1:
+                       status = POWER_SUPPLY_STATUS_FULL;
+                       *level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+                       break;
+               case 2:
+                       status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       break;
+               default:
+                       status = POWER_SUPPLY_STATUS_UNKNOWN;
+                       break;
+               }
+       else
                status = POWER_SUPPLY_STATUS_DISCHARGING;
-               break;
-       case 0xe0:
-               status = POWER_SUPPLY_STATUS_NOT_CHARGING;
-               break;
-       default:
-               status = POWER_SUPPLY_STATUS_UNKNOWN;
-       }
 
        *charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
-       if (test_bit(3, &charge_sts)) {
+       if (test_bit(3, &flags)) {
                *charge_type = POWER_SUPPLY_CHARGE_TYPE_FAST;
        }
-       if (test_bit(4, &charge_sts)) {
+       if (test_bit(4, &flags)) {
                *charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
        }
-
-       if (test_bit(5, &charge_sts)) {
+       if (test_bit(5, &flags)) {
                *level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
        }
 
index a549c42..33c102a 100644 (file)
@@ -458,9 +458,9 @@ static ssize_t picolcd_fb_update_rate_show(struct device *dev,
                if (ret >= PAGE_SIZE)
                        break;
                else if (i == fb_update_rate)
-                       ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
+                       ret += scnprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
                else
-                       ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
+                       ret += scnprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
        if (ret > 0)
                buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
        return ret;
index 0e7b2d9..3735546 100644 (file)
@@ -103,6 +103,7 @@ static const struct hid_device_id hid_quirks[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET },
index fb827c2..4d25577 100644 (file)
@@ -313,7 +313,7 @@ static ssize_t show_value(struct device *dev, struct device_attribute *attr,
 
                        while (i < ret) {
                                if (i + attribute->size > ret) {
-                                       len += snprintf(&buf[len],
+                                       len += scnprintf(&buf[len],
                                                        PAGE_SIZE - len,
                                                        "%d ", values[i]);
                                        break;
@@ -336,10 +336,10 @@ static ssize_t show_value(struct device *dev, struct device_attribute *attr,
                                        ++i;
                                        break;
                                }
-                               len += snprintf(&buf[len], PAGE_SIZE - len,
+                               len += scnprintf(&buf[len], PAGE_SIZE - len,
                                                "%lld ", value);
                        }
-                       len += snprintf(&buf[len], PAGE_SIZE - len, "\n");
+                       len += scnprintf(&buf[len], PAGE_SIZE - len, "\n");
 
                        return len;
                } else if (input)
index d31ea82..a66f080 100644 (file)
@@ -342,6 +342,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
                .driver_data = (void *)&sipodev_desc
        },
        {
+               .ident = "Trekstor SURFBOOK E11B",
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "TREKSTOR"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SURFBOOK E11B"),
+               },
+               .driver_data = (void *)&sipodev_desc
+       },
+       {
                .ident = "Direkt-Tek DTLAPY116-2",
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Direkt-Tek"),
index a970b80..4140dea 100644 (file)
@@ -932,9 +932,9 @@ void hiddev_disconnect(struct hid_device *hid)
        hiddev->exist = 0;
 
        if (hiddev->open) {
-               mutex_unlock(&hiddev->existancelock);
                hid_hw_close(hiddev->hid);
                wake_up_interruptible(&hiddev->wait);
+               mutex_unlock(&hiddev->existancelock);
        } else {
                mutex_unlock(&hiddev->existancelock);
                kfree(hiddev);
index 9eec970..89869c6 100644 (file)
@@ -965,14 +965,13 @@ static int cs_hsi_buf_config(struct cs_hsi_iface *hi,
 
        if (old_state != hi->iface_state) {
                if (hi->iface_state == CS_STATE_CONFIGURED) {
-                       pm_qos_add_request(&hi->pm_qos_req,
-                               PM_QOS_CPU_DMA_LATENCY,
+                       cpu_latency_qos_add_request(&hi->pm_qos_req,
                                CS_QOS_LATENCY_FOR_DATA_USEC);
                        local_bh_disable();
                        cs_hsi_read_on_data(hi);
                        local_bh_enable();
                } else if (old_state == CS_STATE_CONFIGURED) {
-                       pm_qos_remove_request(&hi->pm_qos_req);
+                       cpu_latency_qos_remove_request(&hi->pm_qos_req);
                }
        }
        return r;
@@ -1075,8 +1074,8 @@ static void cs_hsi_stop(struct cs_hsi_iface *hi)
        WARN_ON(!cs_state_idle(hi->control_state));
        WARN_ON(!cs_state_idle(hi->data_state));
 
-       if (pm_qos_request_active(&hi->pm_qos_req))
-               pm_qos_remove_request(&hi->pm_qos_req);
+       if (cpu_latency_qos_request_active(&hi->pm_qos_req))
+               cpu_latency_qos_remove_request(&hi->pm_qos_req);
 
        spin_lock_bh(&hi->lock);
        cs_hsi_free_data(hi);
index 47ac20a..05a3083 100644 (file)
@@ -280,6 +280,15 @@ config SENSORS_ASC7621
          This driver can also be built as a module. If so, the module
          will be called asc7621.
 
+config SENSORS_AXI_FAN_CONTROL
+       tristate "Analog Devices FAN Control HDL Core driver"
+       help
+         If you say yes here you get support for the Analog Devices
+         AXI HDL FAN monitoring core.
+
+         This driver can also be built as a module. If so, the module
+         will be called axi-fan-control
+
 config SENSORS_K8TEMP
        tristate "AMD Athlon64/FX or Opteron temperature sensor"
        depends on X86 && PCI
index 613f509..b0b9c8e 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_SENSORS_AS370)   += as370-hwmon.o
 obj-$(CONFIG_SENSORS_ASC7621)  += asc7621.o
 obj-$(CONFIG_SENSORS_ASPEED)   += aspeed-pwm-tacho.o
 obj-$(CONFIG_SENSORS_ATXP1)    += atxp1.o
+obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o
 obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
 obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
 obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
index 9632e2e..319a051 100644 (file)
@@ -413,7 +413,7 @@ static int ADT7462_REG_VOLT(struct adt7462_data *data, int which)
                        return 0x95;
                break;
        }
-       return -ENODEV;
+       return 0;
 }
 
 /* Provide labels for sysfs */
index 01c2eeb..0540804 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/jiffies.h>
+#include <linux/of.h>
 #include <linux/util_macros.h>
 
 /* Indexes for the sysfs hooks */
@@ -193,6 +194,7 @@ struct adt7475_data {
        unsigned long measure_updated;
        bool valid;
 
+       u8 config2;
        u8 config4;
        u8 config5;
        u8 has_voltage;
@@ -1458,6 +1460,85 @@ static int adt7475_update_limits(struct i2c_client *client)
        return 0;
 }
 
+static int set_property_bit(const struct i2c_client *client, char *property,
+                           u8 *config, u8 bit_index)
+{
+       u32 prop_value = 0;
+       int ret = of_property_read_u32(client->dev.of_node, property,
+                                       &prop_value);
+
+       if (!ret) {
+               if (prop_value)
+                       *config |= (1 << bit_index);
+               else
+                       *config &= ~(1 << bit_index);
+       }
+
+       return ret;
+}
+
+static int load_attenuators(const struct i2c_client *client, int chip,
+                           struct adt7475_data *data)
+{
+       int ret;
+
+       if (chip == adt7476 || chip == adt7490) {
+               set_property_bit(client, "adi,bypass-attenuator-in0",
+                                &data->config4, 4);
+               set_property_bit(client, "adi,bypass-attenuator-in1",
+                                &data->config4, 5);
+               set_property_bit(client, "adi,bypass-attenuator-in3",
+                                &data->config4, 6);
+               set_property_bit(client, "adi,bypass-attenuator-in4",
+                                &data->config4, 7);
+
+               ret = i2c_smbus_write_byte_data(client, REG_CONFIG4,
+                                               data->config4);
+               if (ret < 0)
+                       return ret;
+       } else if (chip == adt7473 || chip == adt7475) {
+               set_property_bit(client, "adi,bypass-attenuator-in1",
+                                &data->config2, 5);
+
+               ret = i2c_smbus_write_byte_data(client, REG_CONFIG2,
+                                               data->config2);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int adt7475_set_pwm_polarity(struct i2c_client *client)
+{
+       u32 states[ADT7475_PWM_COUNT];
+       int ret, i;
+       u8 val;
+
+       ret = of_property_read_u32_array(client->dev.of_node,
+                                        "adi,pwm-active-state", states,
+                                        ARRAY_SIZE(states));
+       if (ret)
+               return ret;
+
+       for (i = 0; i < ADT7475_PWM_COUNT; i++) {
+               ret = adt7475_read(PWM_CONFIG_REG(i));
+               if (ret < 0)
+                       return ret;
+               val = ret;
+               if (states[i])
+                       val &= ~BIT(4);
+               else
+                       val |= BIT(4);
+
+               ret = i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(i), val);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int adt7475_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
@@ -1472,7 +1553,7 @@ static int adt7475_probe(struct i2c_client *client,
        struct adt7475_data *data;
        struct device *hwmon_dev;
        int i, ret = 0, revision, group_num = 0;
-       u8 config2, config3;
+       u8 config3;
 
        data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
        if (data == NULL)
@@ -1546,8 +1627,12 @@ static int adt7475_probe(struct i2c_client *client,
        }
 
        /* Voltage attenuators can be bypassed, globally or individually */
-       config2 = adt7475_read(REG_CONFIG2);
-       if (config2 & CONFIG2_ATTN) {
+       data->config2 = adt7475_read(REG_CONFIG2);
+       ret = load_attenuators(client, chip, data);
+       if (ret)
+               dev_warn(&client->dev, "Error configuring attenuator bypass\n");
+
+       if (data->config2 & CONFIG2_ATTN) {
                data->bypass_attn = (0x3 << 3) | 0x3;
        } else {
                data->bypass_attn = ((data->config4 & CONFIG4_ATTN_IN10) >> 4) |
@@ -1562,6 +1647,10 @@ static int adt7475_probe(struct i2c_client *client,
        for (i = 0; i < ADT7475_PWM_COUNT; i++)
                adt7475_read_pwm(client, i);
 
+       ret = adt7475_set_pwm_polarity(client);
+       if (ret && ret != -EINVAL)
+               dev_warn(&client->dev, "Error configuring pwm polarity\n");
+
        /* Start monitoring */
        switch (chip) {
        case adt7475:
diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c
new file mode 100644 (file)
index 0000000..38d9cdb
--- /dev/null
@@ -0,0 +1,469 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Fan Control HDL CORE driver
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/fpga/adi-axi-common.h>
+#include <linux/hwmon.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define ADI_AXI_PCORE_VER_MAJOR(version)       (((version) >> 16) & 0xff)
+#define ADI_AXI_PCORE_VER_MINOR(version)       (((version) >> 8) & 0xff)
+#define ADI_AXI_PCORE_VER_PATCH(version)       ((version) & 0xff)
+
+/* register map */
+#define ADI_REG_RSTN           0x0080
+#define ADI_REG_PWM_WIDTH      0x0084
+#define ADI_REG_TACH_PERIOD    0x0088
+#define ADI_REG_TACH_TOLERANCE 0x008c
+#define ADI_REG_PWM_PERIOD     0x00c0
+#define ADI_REG_TACH_MEASUR    0x00c4
+#define ADI_REG_TEMPERATURE    0x00c8
+
+#define ADI_REG_IRQ_MASK       0x0040
+#define ADI_REG_IRQ_PENDING    0x0044
+#define ADI_REG_IRQ_SRC                0x0048
+
+/* IRQ sources */
+#define ADI_IRQ_SRC_PWM_CHANGED                BIT(0)
+#define ADI_IRQ_SRC_TACH_ERR           BIT(1)
+#define ADI_IRQ_SRC_TEMP_INCREASE      BIT(2)
+#define ADI_IRQ_SRC_NEW_MEASUR         BIT(3)
+#define ADI_IRQ_SRC_MASK               GENMASK(3, 0)
+#define ADI_IRQ_MASK_OUT_ALL           0xFFFFFFFFU
+
+#define SYSFS_PWM_MAX                  255
+
+struct axi_fan_control_data {
+       void __iomem *base;
+       struct device *hdev;
+       unsigned long clk_rate;
+       int irq;
+       /* pulses per revolution */
+       u32 ppr;
+       bool hw_pwm_req;
+       bool update_tacho_params;
+       u8 fan_fault;
+};
+
+static inline void axi_iowrite(const u32 val, const u32 reg,
+                              const struct axi_fan_control_data *ctl)
+{
+       iowrite32(val, ctl->base + reg);
+}
+
+static inline u32 axi_ioread(const u32 reg,
+                            const struct axi_fan_control_data *ctl)
+{
+       return ioread32(ctl->base + reg);
+}
+
+static long axi_fan_control_get_pwm_duty(const struct axi_fan_control_data *ctl)
+{
+       u32 pwm_width = axi_ioread(ADI_REG_PWM_WIDTH, ctl);
+       u32 pwm_period = axi_ioread(ADI_REG_PWM_PERIOD, ctl);
+       /*
+        * PWM_PERIOD is a RO register set by the core. It should never be 0.
+        * For now we are trusting the HW...
+        */
+       return DIV_ROUND_CLOSEST(pwm_width * SYSFS_PWM_MAX, pwm_period);
+}
+
+static int axi_fan_control_set_pwm_duty(const long val,
+                                       struct axi_fan_control_data *ctl)
+{
+       u32 pwm_period = axi_ioread(ADI_REG_PWM_PERIOD, ctl);
+       u32 new_width;
+       long __val = clamp_val(val, 0, SYSFS_PWM_MAX);
+
+       new_width = DIV_ROUND_CLOSEST(__val * pwm_period, SYSFS_PWM_MAX);
+
+       axi_iowrite(new_width, ADI_REG_PWM_WIDTH, ctl);
+
+       return 0;
+}
+
+static long axi_fan_control_get_fan_rpm(const struct axi_fan_control_data *ctl)
+{
+       const u32 tach = axi_ioread(ADI_REG_TACH_MEASUR, ctl);
+
+       if (tach == 0)
+               /* should we return error, EAGAIN maybe? */
+               return 0;
+       /*
+        * The tacho period should be:
+        *      TACH = 60/(ppr * rpm), where rpm is revolutions per second
+        *      and ppr is pulses per revolution.
+        * Given the tacho period, we can multiply it by the input clock
+        * so that we know how many clocks we need to have this period.
+        * From this, we can derive the RPM value.
+        */
+       return DIV_ROUND_CLOSEST(60 * ctl->clk_rate, ctl->ppr * tach);
+}
+
+static int axi_fan_control_read_temp(struct device *dev, u32 attr, long *val)
+{
+       struct axi_fan_control_data *ctl = dev_get_drvdata(dev);
+       long raw_temp;
+
+       switch (attr) {
+       case hwmon_temp_input:
+               raw_temp = axi_ioread(ADI_REG_TEMPERATURE, ctl);
+               /*
+                * The formula for the temperature is:
+                *      T = (ADC * 501.3743 / 2^bits) - 273.6777
+                * It's multiplied by 1000 to have millidegrees as
+                * specified by the hwmon sysfs interface.
+                */
+               *val = ((raw_temp * 501374) >> 16) - 273677;
+               return 0;
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int axi_fan_control_read_fan(struct device *dev, u32 attr, long *val)
+{
+       struct axi_fan_control_data *ctl = dev_get_drvdata(dev);
+
+       switch (attr) {
+       case hwmon_fan_fault:
+               *val = ctl->fan_fault;
+               /* clear it now */
+               ctl->fan_fault = 0;
+               return 0;
+       case hwmon_fan_input:
+               *val = axi_fan_control_get_fan_rpm(ctl);
+               return 0;
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int axi_fan_control_read_pwm(struct device *dev, u32 attr, long *val)
+{
+       struct axi_fan_control_data *ctl = dev_get_drvdata(dev);
+
+       switch (attr) {
+       case hwmon_pwm_input:
+               *val = axi_fan_control_get_pwm_duty(ctl);
+               return 0;
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int axi_fan_control_write_pwm(struct device *dev, u32 attr, long val)
+{
+       struct axi_fan_control_data *ctl = dev_get_drvdata(dev);
+
+       switch (attr) {
+       case hwmon_pwm_input:
+               return axi_fan_control_set_pwm_duty(val, ctl);
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int axi_fan_control_read_labels(struct device *dev,
+                                      enum hwmon_sensor_types type,
+                                      u32 attr, int channel, const char **str)
+{
+       switch (type) {
+       case hwmon_fan:
+               *str = "FAN";
+               return 0;
+       case hwmon_temp:
+               *str = "SYSMON4";
+               return 0;
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int axi_fan_control_read(struct device *dev,
+                               enum hwmon_sensor_types type,
+                               u32 attr, int channel, long *val)
+{
+       switch (type) {
+       case hwmon_fan:
+               return axi_fan_control_read_fan(dev, attr, val);
+       case hwmon_pwm:
+               return axi_fan_control_read_pwm(dev, attr, val);
+       case hwmon_temp:
+               return axi_fan_control_read_temp(dev, attr, val);
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static int axi_fan_control_write(struct device *dev,
+                                enum hwmon_sensor_types type,
+                                u32 attr, int channel, long val)
+{
+       switch (type) {
+       case hwmon_pwm:
+               return axi_fan_control_write_pwm(dev, attr, val);
+       default:
+               return -ENOTSUPP;
+       }
+}
+
+static umode_t axi_fan_control_fan_is_visible(const u32 attr)
+{
+       switch (attr) {
+       case hwmon_fan_input:
+       case hwmon_fan_fault:
+       case hwmon_fan_label:
+               return 0444;
+       default:
+               return 0;
+       }
+}
+
+static umode_t axi_fan_control_pwm_is_visible(const u32 attr)
+{
+       switch (attr) {
+       case hwmon_pwm_input:
+               return 0644;
+       default:
+               return 0;
+       }
+}
+
+static umode_t axi_fan_control_temp_is_visible(const u32 attr)
+{
+       switch (attr) {
+       case hwmon_temp_input:
+       case hwmon_temp_label:
+               return 0444;
+       default:
+               return 0;
+       }
+}
+
+static umode_t axi_fan_control_is_visible(const void *data,
+                                         enum hwmon_sensor_types type,
+                                         u32 attr, int channel)
+{
+       switch (type) {
+       case hwmon_fan:
+               return axi_fan_control_fan_is_visible(attr);
+       case hwmon_pwm:
+               return axi_fan_control_pwm_is_visible(attr);
+       case hwmon_temp:
+               return axi_fan_control_temp_is_visible(attr);
+       default:
+               return 0;
+       }
+}
+
+/*
+ * This core has two main ways of changing the PWM duty cycle. It is done,
+ * either by a request from userspace (writing on pwm1_input) or by the
+ * core itself. When the change is done by the core, it will use predefined
+ * parameters to evaluate the tach signal and, on that case we cannot set them.
+ * On the other hand, when the request is done by the user, with some arbitrary
+ * value that the core does not now about, we have to provide the tach
+ * parameters so that, the core can evaluate the signal. On the IRQ handler we
+ * distinguish this by using the ADI_IRQ_SRC_TEMP_INCREASE interrupt. This tell
+ * us that the CORE requested a new duty cycle. After this, there is 5s delay
+ * on which the core waits for the fan rotation speed to stabilize. After this
+ * we get ADI_IRQ_SRC_PWM_CHANGED irq where we will decide if we need to set
+ * the tach parameters or not on the next tach measurement cycle (corresponding
+ * already to the ney duty cycle) based on the %ctl->hw_pwm_req flag.
+ */
+static irqreturn_t axi_fan_control_irq_handler(int irq, void *data)
+{
+       struct axi_fan_control_data *ctl = (struct axi_fan_control_data *)data;
+       u32 irq_pending = axi_ioread(ADI_REG_IRQ_PENDING, ctl);
+       u32 clear_mask;
+
+       if (irq_pending & ADI_IRQ_SRC_NEW_MEASUR) {
+               if (ctl->update_tacho_params) {
+                       u32 new_tach = axi_ioread(ADI_REG_TACH_MEASUR, ctl);
+
+                       /* get 25% tolerance */
+                       u32 tach_tol = DIV_ROUND_CLOSEST(new_tach * 25, 100);
+                       /* set new tacho parameters */
+                       axi_iowrite(new_tach, ADI_REG_TACH_PERIOD, ctl);
+                       axi_iowrite(tach_tol, ADI_REG_TACH_TOLERANCE, ctl);
+                       ctl->update_tacho_params = false;
+               }
+       }
+
+       if (irq_pending & ADI_IRQ_SRC_PWM_CHANGED) {
+               /*
+                * if the pwm changes on behalf of software,
+                * we need to provide new tacho parameters to the core.
+                * Wait for the next measurement for that...
+                */
+               if (!ctl->hw_pwm_req) {
+                       ctl->update_tacho_params = true;
+               } else {
+                       ctl->hw_pwm_req = false;
+                       sysfs_notify(&ctl->hdev->kobj, NULL, "pwm1");
+               }
+       }
+
+       if (irq_pending & ADI_IRQ_SRC_TEMP_INCREASE)
+               /* hardware requested a new pwm */
+               ctl->hw_pwm_req = true;
+
+       if (irq_pending & ADI_IRQ_SRC_TACH_ERR)
+               ctl->fan_fault = 1;
+
+       /* clear all interrupts */
+       clear_mask = irq_pending & ADI_IRQ_SRC_MASK;
+       axi_iowrite(clear_mask, ADI_REG_IRQ_PENDING, ctl);
+
+       return IRQ_HANDLED;
+}
+
+static int axi_fan_control_init(struct axi_fan_control_data *ctl,
+                               const struct device_node *np)
+{
+       int ret;
+
+       /* get fan pulses per revolution */
+       ret = of_property_read_u32(np, "pulses-per-revolution", &ctl->ppr);
+       if (ret)
+               return ret;
+
+       /* 1, 2 and 4 are the typical and accepted values */
+       if (ctl->ppr != 1 && ctl->ppr != 2 && ctl->ppr != 4)
+               return -EINVAL;
+       /*
+        * Enable all IRQs
+        */
+       axi_iowrite(ADI_IRQ_MASK_OUT_ALL &
+                   ~(ADI_IRQ_SRC_NEW_MEASUR | ADI_IRQ_SRC_TACH_ERR |
+                     ADI_IRQ_SRC_PWM_CHANGED | ADI_IRQ_SRC_TEMP_INCREASE),
+                   ADI_REG_IRQ_MASK, ctl);
+
+       /* bring the device out of reset */
+       axi_iowrite(0x01, ADI_REG_RSTN, ctl);
+
+       return ret;
+}
+
+static const struct hwmon_channel_info *axi_fan_control_info[] = {
+       HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT),
+       HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_FAULT | HWMON_F_LABEL),
+       HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_LABEL),
+       NULL
+};
+
+static const struct hwmon_ops axi_fan_control_hwmon_ops = {
+       .is_visible = axi_fan_control_is_visible,
+       .read = axi_fan_control_read,
+       .write = axi_fan_control_write,
+       .read_string = axi_fan_control_read_labels,
+};
+
+static const struct hwmon_chip_info axi_chip_info = {
+       .ops = &axi_fan_control_hwmon_ops,
+       .info = axi_fan_control_info,
+};
+
+static const u32 version_1_0_0 = ADI_AXI_PCORE_VER(1, 0, 'a');
+
+static const struct of_device_id axi_fan_control_of_match[] = {
+       { .compatible = "adi,axi-fan-control-1.00.a",
+               .data = (void *)&version_1_0_0},
+       {},
+};
+MODULE_DEVICE_TABLE(of, axi_fan_control_of_match);
+
+static int axi_fan_control_probe(struct platform_device *pdev)
+{
+       struct axi_fan_control_data *ctl;
+       struct clk *clk;
+       const struct of_device_id *id;
+       const char *name = "axi_fan_control";
+       u32 version;
+       int ret;
+
+       id = of_match_node(axi_fan_control_of_match, pdev->dev.of_node);
+       if (!id)
+               return -EINVAL;
+
+       ctl = devm_kzalloc(&pdev->dev, sizeof(*ctl), GFP_KERNEL);
+       if (!ctl)
+               return -ENOMEM;
+
+       ctl->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(ctl->base))
+               return PTR_ERR(ctl->base);
+
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "clk_get failed with %ld\n", PTR_ERR(clk));
+               return PTR_ERR(clk);
+       }
+
+       ctl->clk_rate = clk_get_rate(clk);
+       if (!ctl->clk_rate)
+               return -EINVAL;
+
+       version = axi_ioread(ADI_AXI_REG_VERSION, ctl);
+       if (ADI_AXI_PCORE_VER_MAJOR(version) !=
+           ADI_AXI_PCORE_VER_MAJOR((*(u32 *)id->data))) {
+               dev_err(&pdev->dev, "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
+                       ADI_AXI_PCORE_VER_MAJOR((*(u32 *)id->data)),
+                       ADI_AXI_PCORE_VER_MINOR((*(u32 *)id->data)),
+                       ADI_AXI_PCORE_VER_PATCH((*(u32 *)id->data)),
+                       ADI_AXI_PCORE_VER_MAJOR(version),
+                       ADI_AXI_PCORE_VER_MINOR(version),
+                       ADI_AXI_PCORE_VER_PATCH(version));
+               return -ENODEV;
+       }
+
+       ctl->irq = platform_get_irq(pdev, 0);
+       if (ctl->irq < 0)
+               return ctl->irq;
+
+       ret = devm_request_threaded_irq(&pdev->dev, ctl->irq, NULL,
+                                       axi_fan_control_irq_handler,
+                                       IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+                                       pdev->driver_override, ctl);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request an irq, %d", ret);
+               return ret;
+       }
+
+       ret = axi_fan_control_init(ctl, pdev->dev.of_node);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to initialize device\n");
+               return ret;
+       }
+
+       ctl->hdev = devm_hwmon_device_register_with_info(&pdev->dev,
+                                                        name,
+                                                        ctl,
+                                                        &axi_chip_info,
+                                                        NULL);
+
+       return PTR_ERR_OR_ZERO(ctl->hdev);
+}
+
+static struct platform_driver axi_fan_control_driver = {
+       .driver = {
+               .name = "axi_fan_control_driver",
+               .of_match_table = axi_fan_control_of_match,
+       },
+       .probe = axi_fan_control_probe,
+};
+module_platform_driver(axi_fan_control_driver);
+
+MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices Fan Control HDL CORE driver");
+MODULE_LICENSE("GPL");
index d855c78..bb92112 100644 (file)
@@ -709,7 +709,7 @@ static int coretemp_cpu_offline(unsigned int cpu)
        return 0;
 }
 static const struct x86_cpu_id __initconst coretemp_ids[] = {
-       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTHERM },
+       X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_DTHERM, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, coretemp_ids);
index d05ab71..a4ec852 100644 (file)
@@ -219,7 +219,7 @@ struct aem_read_sensor_req {
 
 struct aem_read_sensor_resp {
        struct aem_iana_id      id;
-       u8                      bytes[0];
+       u8                      bytes[];
 } __packed;
 
 /* Data structures to talk to the IPMI layer */
index 0e525cf..a750647 100644 (file)
@@ -186,7 +186,7 @@ static void make_sensor_label(struct device_node *np,
        u32 id;
        size_t n;
 
-       n = snprintf(sdata->label, sizeof(sdata->label), "%s", label);
+       n = scnprintf(sdata->label, sizeof(sdata->label), "%s", label);
 
        /*
         * Core temp pretty print
@@ -199,11 +199,11 @@ static void make_sensor_label(struct device_node *np,
                         * The digital thermal sensors are associated
                         * with a core.
                         */
-                       n += snprintf(sdata->label + n,
+                       n += scnprintf(sdata->label + n,
                                      sizeof(sdata->label) - n, " %d",
                                      cpuid);
                else
-                       n += snprintf(sdata->label + n,
+                       n += scnprintf(sdata->label + n,
                                      sizeof(sdata->label) - n, " phy%d", id);
        }
 
@@ -211,7 +211,7 @@ static void make_sensor_label(struct device_node *np,
         * Membuffer pretty print
         */
        if (!of_property_read_u32(np, "ibm,chip-id", &id))
-               n += snprintf(sdata->label + n, sizeof(sdata->label) - n,
+               n += scnprintf(sdata->label + n, sizeof(sdata->label) - n,
                              " %d", id & 0xffff);
 }
 
index e39354f..3f37d5d 100644 (file)
@@ -96,13 +96,20 @@ struct k10temp_data {
        void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
        int temp_offset;
        u32 temp_adjust_mask;
-       bool show_tdie;
-       u32 show_tccd;
+       u32 show_temp;
        u32 svi_addr[2];
+       bool is_zen;
        bool show_current;
        int cfactor[2];
 };
 
+#define TCTL_BIT       0
+#define TDIE_BIT       1
+#define TCCD_BIT(x)    ((x) + 2)
+
+#define HAVE_TEMP(d, channel)  ((d)->show_temp & BIT(channel))
+#define HAVE_TDIE(d)           HAVE_TEMP(d, TDIE_BIT)
+
 struct tctl_offset {
        u8 model;
        char const *id;
@@ -180,8 +187,8 @@ static long get_raw_temp(struct k10temp_data *data)
 }
 
 const char *k10temp_temp_label[] = {
-       "Tdie",
        "Tctl",
+       "Tdie",
        "Tccd1",
        "Tccd2",
        "Tccd3",
@@ -269,13 +276,13 @@ static int k10temp_read_temp(struct device *dev, u32 attr, int channel,
        switch (attr) {
        case hwmon_temp_input:
                switch (channel) {
-               case 0:         /* Tdie */
-                       *val = get_raw_temp(data) - data->temp_offset;
+               case 0:         /* Tctl */
+                       *val = get_raw_temp(data);
                        if (*val < 0)
                                *val = 0;
                        break;
-               case 1:         /* Tctl */
-                       *val = get_raw_temp(data);
+               case 1:         /* Tdie */
+                       *val = get_raw_temp(data) - data->temp_offset;
                        if (*val < 0)
                                *val = 0;
                        break;
@@ -333,23 +340,11 @@ static umode_t k10temp_is_visible(const void *_data,
        case hwmon_temp:
                switch (attr) {
                case hwmon_temp_input:
-                       switch (channel) {
-                       case 0:         /* Tdie, or Tctl if we don't show it */
-                               break;
-                       case 1:         /* Tctl */
-                               if (!data->show_tdie)
-                                       return 0;
-                               break;
-                       case 2 ... 9:           /* Tccd{1-8} */
-                               if (!(data->show_tccd & BIT(channel - 2)))
-                                       return 0;
-                               break;
-                       default:
+                       if (!HAVE_TEMP(data, channel))
                                return 0;
-                       }
                        break;
                case hwmon_temp_max:
-                       if (channel || data->show_tdie)
+                       if (channel || data->is_zen)
                                return 0;
                        break;
                case hwmon_temp_crit:
@@ -368,20 +363,9 @@ static umode_t k10temp_is_visible(const void *_data,
                                return 0;
                        break;
                case hwmon_temp_label:
-                       /* No labels if we don't show the die temperature */
-                       if (!data->show_tdie)
-                               return 0;
-                       switch (channel) {
-                       case 0:         /* Tdie */
-                       case 1:         /* Tctl */
-                               break;
-                       case 2 ... 9:           /* Tccd{1-8} */
-                               if (!(data->show_tccd & BIT(channel - 2)))
-                                       return 0;
-                               break;
-                       default:
+                       /* Show temperature labels only on Zen CPUs */
+                       if (!data->is_zen || !HAVE_TEMP(data, channel))
                                return 0;
-                       }
                        break;
                default:
                        return 0;
@@ -480,7 +464,7 @@ static void k10temp_init_debugfs(struct k10temp_data *data)
        char name[32];
 
        /* Only show debugfs data for Family 17h/18h CPUs */
-       if (!data->show_tdie)
+       if (!data->is_zen)
                return;
 
        scnprintf(name, sizeof(name), "k10temp-%s", pci_name(data->pdev));
@@ -546,7 +530,7 @@ static void k10temp_get_ccd_support(struct pci_dev *pdev,
                amd_smn_read(amd_pci_dev_to_node_id(pdev),
                             F17H_M70H_CCD_TEMP(i), &regval);
                if (regval & F17H_M70H_CCD_TEMP_VALID)
-                       data->show_tccd |= BIT(i);
+                       data->show_temp |= BIT(TCCD_BIT(i));
        }
 }
 
@@ -573,6 +557,7 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return -ENOMEM;
 
        data->pdev = pdev;
+       data->show_temp |= BIT(TCTL_BIT);       /* Always show Tctl */
 
        if (boot_cpu_data.x86 == 0x15 &&
            ((boot_cpu_data.x86_model & 0xf0) == 0x60 ||
@@ -582,7 +567,8 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        } else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) {
                data->temp_adjust_mask = CUR_TEMP_RANGE_SEL_MASK;
                data->read_tempreg = read_tempreg_nb_f17;
-               data->show_tdie = true;
+               data->show_temp |= BIT(TDIE_BIT);       /* show Tdie */
+               data->is_zen = true;
 
                switch (boot_cpu_data.x86_model) {
                case 0x1:       /* Zen */
index 1eeb9d7..733c48b 100644 (file)
@@ -262,10 +262,20 @@ static int lm73_detect(struct i2c_client *new_client,
        return 0;
 }
 
+static const struct of_device_id lm73_of_match[] = {
+       {
+               .compatible = "ti,lm73",
+       },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, lm73_of_match);
+
 static struct i2c_driver lm73_driver = {
        .class          = I2C_CLASS_HWMON,
        .driver = {
                .name   = "lm73",
+               .of_match_table = lm73_of_match,
        },
        .probe          = lm73_probe,
        .id_table       = lm73_ids,
index 281c81e..1f5743d 100644 (file)
@@ -7,6 +7,11 @@
  *
  * Copyright (c) 2019 Advantech
  * Author: Amy.Shih <amy.shih@advantech.com.tw>
+ *
+ * Supports the following chips:
+ *
+ * Chip        #vin  #fan  #pwm  #temp  #dts  chip ID
+ * nct7904d     20    12    4     5      8    0xc5
  */
 
 #include <linux/module.h>
@@ -820,6 +825,10 @@ static const struct hwmon_channel_info *nct7904_info[] = {
                           HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
                           HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
                           HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
+                          HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM,
                           HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM),
        HWMON_CHANNEL_INFO(pwm,
                           HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
@@ -853,6 +862,18 @@ static const struct hwmon_channel_info *nct7904_info[] = {
                           HWMON_T_CRIT_HYST,
                           HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
                           HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
+                          HWMON_T_CRIT_HYST,
+                          HWMON_T_INPUT | HWMON_T_ALARM | HWMON_T_MAX |
+                          HWMON_T_MAX_HYST | HWMON_T_TYPE | HWMON_T_CRIT |
                           HWMON_T_CRIT_HYST),
        NULL
 };
index a9ea062..de12a56 100644 (file)
@@ -92,10 +92,10 @@ config SENSORS_IRPS5401
          be called irps5401.
 
 config SENSORS_ISL68137
-       tristate "Intersil ISL68137"
+       tristate "Renesas Digital Multiphase Voltage Regulators"
        help
-         If you say yes here you get hardware monitoring support for Intersil
-         ISL68137.
+         If you say yes here you get hardware monitoring support for Renesas
+         digital multiphase voltage regulators.
 
          This driver can also be built as a module. If so, the module will
          be called isl68137.
@@ -113,8 +113,8 @@ config SENSORS_LTC2978
        tristate "Linear Technologies LTC2978 and compatibles"
        help
          If you say yes here you get hardware monitoring support for Linear
-         Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880,
-         LTC3883, LTC3886, LTC3887, LTCM2987, LTM4675, and LTM4676.
+         Technology LTC2972, LTC2974, LTC2975, LTC2977, LTC2978, LTC2979,
+         LTC2980, and LTM2987.
 
          This driver can also be built as a module. If so, the module will
          be called ltc2978.
@@ -123,9 +123,10 @@ config SENSORS_LTC2978_REGULATOR
        bool "Regulator support for LTC2978 and compatibles"
        depends on SENSORS_LTC2978 && REGULATOR
        help
-         If you say yes here you get regulator support for Linear
-         Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, LTM4676
-         and LTM4686.
+         If you say yes here you get regulator support for Linear Technology
+         LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7880, 
+         LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4686, 
+         and LTM4700.
 
 config SENSORS_LTC3815
        tristate "Linear Technologies LTC3815"
@@ -209,10 +210,10 @@ config SENSORS_TPS40422
          be called tps40422.
 
 config SENSORS_TPS53679
-       tristate "TI TPS53679, TPS53688"
+       tristate "TI TPS53647, TPS53667, TPS53679, TPS53681, TPS53688"
        help
          If you say yes here you get hardware monitoring support for TI
-         TPS53679, TPS53688
+         TPS53647, TPS53667, TPS53679, TPS53681, and TPS53688.
 
          This driver can also be built as a module. If so, the module will
          be called tps53679.
index 5caa37f..e25f541 100644 (file)
@@ -226,7 +226,8 @@ static int adm1275_write_pmon_config(const struct adm1275_data *data,
        return ret;
 }
 
-static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
+static int adm1275_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        const struct adm1275_data *data = to_adm1275_data(info);
@@ -239,58 +240,68 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
        case PMBUS_IOUT_UC_FAULT_LIMIT:
                if (!data->have_uc_fault)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1275_IOUT_WARN2_LIMIT);
                break;
        case PMBUS_IOUT_OC_FAULT_LIMIT:
                if (!data->have_oc_fault)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1275_IOUT_WARN2_LIMIT);
                break;
        case PMBUS_VOUT_OV_WARN_LIMIT:
                if (data->have_vout)
                        return -ENODATA;
-               ret = pmbus_read_word_data(client, 0,
+               ret = pmbus_read_word_data(client, 0, 0xff,
                                           ADM1075_VAUX_OV_WARN_LIMIT);
                break;
        case PMBUS_VOUT_UV_WARN_LIMIT:
                if (data->have_vout)
                        return -ENODATA;
-               ret = pmbus_read_word_data(client, 0,
+               ret = pmbus_read_word_data(client, 0, 0xff,
                                           ADM1075_VAUX_UV_WARN_LIMIT);
                break;
        case PMBUS_READ_VOUT:
                if (data->have_vout)
                        return -ENODATA;
-               ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1075_READ_VAUX);
                break;
        case PMBUS_VIRT_READ_IOUT_MIN:
                if (!data->have_iout_min)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, 0, ADM1293_IOUT_MIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1293_IOUT_MIN);
                break;
        case PMBUS_VIRT_READ_IOUT_MAX:
-               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1275_PEAK_IOUT);
                break;
        case PMBUS_VIRT_READ_VOUT_MAX:
-               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1275_PEAK_VOUT);
                break;
        case PMBUS_VIRT_READ_VIN_MAX:
-               ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1275_PEAK_VIN);
                break;
        case PMBUS_VIRT_READ_PIN_MIN:
                if (!data->have_pin_min)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, 0, ADM1293_PIN_MIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1293_PIN_MIN);
                break;
        case PMBUS_VIRT_READ_PIN_MAX:
                if (!data->have_pin_max)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1276_PEAK_PIN);
                break;
        case PMBUS_VIRT_READ_TEMP_MAX:
                if (!data->have_temp_max)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, 0, ADM1278_PEAK_TEMP);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          ADM1278_PEAK_TEMP);
                break;
        case PMBUS_VIRT_RESET_IOUT_HISTORY:
        case PMBUS_VIRT_RESET_VOUT_HISTORY:
index 3795fe5..7d300f2 100644 (file)
 #define CFFPS_INPUT_HISTORY_CMD                        0xD6
 #define CFFPS_INPUT_HISTORY_SIZE               100
 
+#define CFFPS_CCIN_REVISION                    GENMASK(7, 0)
+#define  CFFPS_CCIN_REVISION_LEGACY             0xde
 #define CFFPS_CCIN_VERSION                     GENMASK(15, 8)
 #define CFFPS_CCIN_VERSION_1                    0x2b
 #define CFFPS_CCIN_VERSION_2                    0x2e
+#define CFFPS_CCIN_VERSION_3                    0x51
 
 /* STATUS_MFR_SPECIFIC bits */
 #define CFFPS_MFR_FAN_FAULT                    BIT(0)
@@ -148,7 +151,7 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
        struct ibm_cffps *psu = to_psu(idxp, idx);
        char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
 
-       pmbus_set_page(psu->client, 0);
+       pmbus_set_page(psu->client, 0, 0xff);
 
        switch (idx) {
        case CFFPS_DEBUGFS_INPUT_HISTORY:
@@ -247,7 +250,7 @@ static ssize_t ibm_cffps_debugfs_write(struct file *file,
 
        switch (idx) {
        case CFFPS_DEBUGFS_ON_OFF_CONFIG:
-               pmbus_set_page(psu->client, 0);
+               pmbus_set_page(psu->client, 0, 0xff);
 
                rc = simple_write_to_buffer(&data, 1, ppos, buf, count);
                if (rc <= 0)
@@ -325,13 +328,13 @@ static int ibm_cffps_read_byte_data(struct i2c_client *client, int page,
 }
 
 static int ibm_cffps_read_word_data(struct i2c_client *client, int page,
-                                   int reg)
+                                   int phase, int reg)
 {
        int rc, mfr;
 
        switch (reg) {
        case PMBUS_STATUS_WORD:
-               rc = pmbus_read_word_data(client, page, reg);
+               rc = pmbus_read_word_data(client, page, phase, reg);
                if (rc < 0)
                        return rc;
 
@@ -348,7 +351,8 @@ static int ibm_cffps_read_word_data(struct i2c_client *client, int page,
                        rc |= PB_STATUS_OFF;
                break;
        case PMBUS_VIRT_READ_VMON:
-               rc = pmbus_read_word_data(client, page, CFFPS_12VCS_VOUT_CMD);
+               rc = pmbus_read_word_data(client, page, phase,
+                                         CFFPS_12VCS_VOUT_CMD);
                break;
        default:
                rc = -ENODATA;
@@ -379,7 +383,7 @@ static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,
        dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n",
                brightness, next_led_state);
 
-       pmbus_set_page(psu->client, 0);
+       pmbus_set_page(psu->client, 0, 0xff);
 
        rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
                                       next_led_state);
@@ -401,7 +405,7 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,
 
        dev_dbg(&psu->client->dev, "LED blink set.\n");
 
-       pmbus_set_page(psu->client, 0);
+       pmbus_set_page(psu->client, 0, 0xff);
 
        rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,
                                       CFFPS_LED_BLINK);
@@ -485,11 +489,14 @@ static int ibm_cffps_probe(struct i2c_client *client,
                vs = (enum versions)id->driver_data;
 
        if (vs == cffps_unknown) {
+               u16 ccin_revision = 0;
                u16 ccin_version = CFFPS_CCIN_VERSION_1;
                int ccin = i2c_smbus_read_word_swapped(client, CFFPS_CCIN_CMD);
 
-               if (ccin > 0)
+               if (ccin > 0) {
+                       ccin_revision = FIELD_GET(CFFPS_CCIN_REVISION, ccin);
                        ccin_version = FIELD_GET(CFFPS_CCIN_VERSION, ccin);
+               }
 
                switch (ccin_version) {
                default:
@@ -499,6 +506,12 @@ static int ibm_cffps_probe(struct i2c_client *client,
                case CFFPS_CCIN_VERSION_2:
                        vs = cffps2;
                        break;
+               case CFFPS_CCIN_VERSION_3:
+                       if (ccin_revision == CFFPS_CCIN_REVISION_LEGACY)
+                               vs = cffps1;
+                       else
+                               vs = cffps2;
+                       break;
                }
 
                /* Set the client name to include the version number. */
index 0d878bc..3eea3e0 100644 (file)
 #define IR35221_MFR_IOUT_VALLEY                0xcb
 #define IR35221_MFR_TEMP_VALLEY                0xcc
 
-static int ir35221_read_word_data(struct i2c_client *client, int page, int reg)
+static int ir35221_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        int ret;
 
        switch (reg) {
        case PMBUS_VIRT_READ_VIN_MAX:
-               ret = pmbus_read_word_data(client, page, IR35221_MFR_VIN_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          IR35221_MFR_VIN_PEAK);
                break;
        case PMBUS_VIRT_READ_VOUT_MAX:
-               ret = pmbus_read_word_data(client, page, IR35221_MFR_VOUT_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          IR35221_MFR_VOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_IOUT_MAX:
-               ret = pmbus_read_word_data(client, page, IR35221_MFR_IOUT_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          IR35221_MFR_IOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_TEMP_MAX:
-               ret = pmbus_read_word_data(client, page, IR35221_MFR_TEMP_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          IR35221_MFR_TEMP_PEAK);
                break;
        case PMBUS_VIRT_READ_VIN_MIN:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           IR35221_MFR_VIN_VALLEY);
                break;
        case PMBUS_VIRT_READ_VOUT_MIN:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           IR35221_MFR_VOUT_VALLEY);
                break;
        case PMBUS_VIRT_READ_IOUT_MIN:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           IR35221_MFR_IOUT_VALLEY);
                break;
        case PMBUS_VIRT_READ_TEMP_MIN:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           IR35221_MFR_TEMP_VALLEY);
                break;
        default:
index 515596c..4d23152 100644 (file)
@@ -1,8 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Hardware monitoring driver for Intersil ISL68137
+ * Hardware monitoring driver for Renesas Digital Multiphase Voltage Regulators
  *
  * Copyright (c) 2017 Google Inc
+ * Copyright (c) 2020 Renesas Electronics America
  *
  */
 
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/sysfs.h>
+
 #include "pmbus.h"
 
 #define ISL68137_VOUT_AVS      0x30
+#define RAA_DMPVR2_READ_VMON   0xc8
+
+enum versions {
+       isl68137,
+       raa_dmpvr2_1rail,
+       raa_dmpvr2_2rail,
+       raa_dmpvr2_3rail,
+       raa_dmpvr2_hv,
+};
 
 static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client,
                                             int page,
@@ -49,7 +60,8 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client,
         * enabling AVS control is the workaround.
         */
        if (op_val == ISL68137_VOUT_AVS) {
-               rc = pmbus_read_word_data(client, page, PMBUS_VOUT_COMMAND);
+               rc = pmbus_read_word_data(client, page, 0xff,
+                                         PMBUS_VOUT_COMMAND);
                if (rc < 0)
                        return rc;
 
@@ -98,13 +110,31 @@ static const struct attribute_group enable_group = {
        .attrs = enable_attrs,
 };
 
-static const struct attribute_group *attribute_groups[] = {
+static const struct attribute_group *isl68137_attribute_groups[] = {
        &enable_group,
        NULL,
 };
 
-static struct pmbus_driver_info isl68137_info = {
-       .pages = 2,
+static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page,
+                                    int phase, int reg)
+{
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VIRT_READ_VMON:
+               ret = pmbus_read_word_data(client, page, phase,
+                                          RAA_DMPVR2_READ_VMON);
+               break;
+       default:
+               ret = -ENODATA;
+               break;
+       }
+
+       return ret;
+}
+
+static struct pmbus_driver_info raa_dmpvr_info = {
+       .pages = 3,
        .format[PSC_VOLTAGE_IN] = direct,
        .format[PSC_VOLTAGE_OUT] = direct,
        .format[PSC_CURRENT_IN] = direct,
@@ -113,7 +143,7 @@ static struct pmbus_driver_info isl68137_info = {
        .format[PSC_TEMPERATURE] = direct,
        .m[PSC_VOLTAGE_IN] = 1,
        .b[PSC_VOLTAGE_IN] = 0,
-       .R[PSC_VOLTAGE_IN] = 3,
+       .R[PSC_VOLTAGE_IN] = 2,
        .m[PSC_VOLTAGE_OUT] = 1,
        .b[PSC_VOLTAGE_OUT] = 0,
        .R[PSC_VOLTAGE_OUT] = 3,
@@ -133,24 +163,76 @@ static struct pmbus_driver_info isl68137_info = {
            | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2
            | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP
            | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-           | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
-       .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
-           | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
-       .groups = attribute_groups,
+           | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT
+               | PMBUS_HAVE_VMON,
+       .func[1] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT
+           | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP
+           | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT
+           | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
+       .func[2] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT
+           | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP
+           | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_IOUT
+           | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT,
 };
 
 static int isl68137_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
-       return pmbus_do_probe(client, id, &isl68137_info);
+       struct pmbus_driver_info *info;
+
+       info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+       memcpy(info, &raa_dmpvr_info, sizeof(*info));
+
+       switch (id->driver_data) {
+       case isl68137:
+               info->pages = 2;
+               info->R[PSC_VOLTAGE_IN] = 3;
+               info->func[0] &= ~PMBUS_HAVE_VMON;
+               info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
+                   | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
+                   | PMBUS_HAVE_POUT;
+               info->groups = isl68137_attribute_groups;
+               break;
+       case raa_dmpvr2_1rail:
+               info->pages = 1;
+               info->read_word_data = raa_dmpvr2_read_word_data;
+               break;
+       case raa_dmpvr2_2rail:
+               info->pages = 2;
+               info->read_word_data = raa_dmpvr2_read_word_data;
+               break;
+       case raa_dmpvr2_3rail:
+               info->read_word_data = raa_dmpvr2_read_word_data;
+               break;
+       case raa_dmpvr2_hv:
+               info->pages = 1;
+               info->R[PSC_VOLTAGE_IN] = 1;
+               info->m[PSC_VOLTAGE_OUT] = 2;
+               info->R[PSC_VOLTAGE_OUT] = 2;
+               info->m[PSC_CURRENT_IN] = 2;
+               info->m[PSC_POWER] = 2;
+               info->R[PSC_POWER] = -1;
+               info->read_word_data = raa_dmpvr2_read_word_data;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       return pmbus_do_probe(client, id, info);
 }
 
-static const struct i2c_device_id isl68137_id[] = {
-       {"isl68137", 0},
+static const struct i2c_device_id raa_dmpvr_id[] = {
+       {"isl68137", isl68137},
+       {"raa_dmpvr2_1rail", raa_dmpvr2_1rail},
+       {"raa_dmpvr2_2rail", raa_dmpvr2_2rail},
+       {"raa_dmpvr2_3rail", raa_dmpvr2_3rail},
+       {"raa_dmpvr2_hv", raa_dmpvr2_hv},
        {}
 };
 
-MODULE_DEVICE_TABLE(i2c, isl68137_id);
+MODULE_DEVICE_TABLE(i2c, raa_dmpvr_id);
 
 /* This is the driver that will be inserted */
 static struct i2c_driver isl68137_driver = {
@@ -159,11 +241,11 @@ static struct i2c_driver isl68137_driver = {
                   },
        .probe = isl68137_probe,
        .remove = pmbus_do_remove,
-       .id_table = isl68137_id,
+       .id_table = raa_dmpvr_id,
 };
 
 module_i2c_driver(isl68137_driver);
 
 MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>");
-MODULE_DESCRIPTION("PMBus driver for Intersil ISL68137");
+MODULE_DESCRIPTION("PMBus driver for Renesas digital multiphase voltage regulators");
 MODULE_LICENSE("GPL");
index 05fce86..9e4cf08 100644 (file)
@@ -211,7 +211,8 @@ struct lm25066_data {
 
 #define to_lm25066_data(x)  container_of(x, struct lm25066_data, info)
 
-static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
+static int lm25066_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        const struct lm25066_data *data = to_lm25066_data(info);
@@ -219,7 +220,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
 
        switch (reg) {
        case PMBUS_VIRT_READ_VMON:
-               ret = pmbus_read_word_data(client, 0, LM25066_READ_VAUX);
+               ret = pmbus_read_word_data(client, 0, 0xff, LM25066_READ_VAUX);
                if (ret < 0)
                        break;
                /* Adjust returned value to match VIN coefficients */
@@ -244,33 +245,40 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
                }
                break;
        case PMBUS_READ_IIN:
-               ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_IIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          LM25066_MFR_READ_IIN);
                break;
        case PMBUS_READ_PIN:
-               ret = pmbus_read_word_data(client, 0, LM25066_MFR_READ_PIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          LM25066_MFR_READ_PIN);
                break;
        case PMBUS_IIN_OC_WARN_LIMIT:
-               ret = pmbus_read_word_data(client, 0,
+               ret = pmbus_read_word_data(client, 0, 0xff,
                                           LM25066_MFR_IIN_OC_WARN_LIMIT);
                break;
        case PMBUS_PIN_OP_WARN_LIMIT:
-               ret = pmbus_read_word_data(client, 0,
+               ret = pmbus_read_word_data(client, 0, 0xff,
                                           LM25066_MFR_PIN_OP_WARN_LIMIT);
                break;
        case PMBUS_VIRT_READ_VIN_AVG:
-               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          LM25066_READ_AVG_VIN);
                break;
        case PMBUS_VIRT_READ_VOUT_AVG:
-               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_VOUT);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          LM25066_READ_AVG_VOUT);
                break;
        case PMBUS_VIRT_READ_IIN_AVG:
-               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_IIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          LM25066_READ_AVG_IIN);
                break;
        case PMBUS_VIRT_READ_PIN_AVG:
-               ret = pmbus_read_word_data(client, 0, LM25066_READ_AVG_PIN);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          LM25066_READ_AVG_PIN);
                break;
        case PMBUS_VIRT_READ_PIN_MAX:
-               ret = pmbus_read_word_data(client, 0, LM25066_READ_PIN_PEAK);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          LM25066_READ_PIN_PEAK);
                break;
        case PMBUS_VIRT_RESET_PIN_HISTORY:
                ret = 0;
@@ -288,13 +296,14 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg)
        return ret;
 }
 
-static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
+static int lm25056_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        int ret;
 
        switch (reg) {
        case PMBUS_VIRT_VMON_UV_WARN_LIMIT:
-               ret = pmbus_read_word_data(client, 0,
+               ret = pmbus_read_word_data(client, 0, 0xff,
                                           LM25056_VAUX_UV_WARN_LIMIT);
                if (ret < 0)
                        break;
@@ -302,7 +311,7 @@ static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
                ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
                break;
        case PMBUS_VIRT_VMON_OV_WARN_LIMIT:
-               ret = pmbus_read_word_data(client, 0,
+               ret = pmbus_read_word_data(client, 0, 0xff,
                                           LM25056_VAUX_OV_WARN_LIMIT);
                if (ret < 0)
                        break;
@@ -310,7 +319,7 @@ static int lm25056_read_word_data(struct i2c_client *client, int page, int reg)
                ret = DIV_ROUND_CLOSEST(ret * 293, 6140);
                break;
        default:
-               ret = lm25066_read_word_data(client, page, reg);
+               ret = lm25066_read_word_data(client, page, phase, reg);
                break;
        }
        return ret;
index a91ed01..7b0e6b3 100644 (file)
 #include <linux/regulator/driver.h>
 #include "pmbus.h"
 
-enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
-       ltc3883, ltc3886, ltc3887, ltm2987, ltm4675, ltm4676, ltm4686 };
+enum chips {
+       /* Managers */
+       ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980,
+       /* Controllers */
+       ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7880,
+       /* Modules */
+       ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686,
+       ltm4700,
+};
 
 /* Common for all chips */
 #define LTC2978_MFR_VOUT_PEAK          0xdd
@@ -43,9 +50,10 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
 #define LTC3880_MFR_CLEAR_PEAKS                0xe3
 #define LTC3880_MFR_TEMPERATURE2_PEAK  0xf4
 
-/* LTC3883 and LTC3886 only */
+/* LTC3883, LTC3884, LTC3886, LTC3889 and LTC7880 only */
 #define LTC3883_MFR_IIN_PEAK           0xe1
 
+
 /* LTC2975 only */
 #define LTC2975_MFR_IIN_PEAK           0xc4
 #define LTC2975_MFR_IIN_MIN            0xc5
@@ -54,27 +62,41 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
 
 #define LTC2978_ID_MASK                        0xfff0
 
+#define LTC2972_ID                     0x0310
 #define LTC2974_ID                     0x0210
 #define LTC2975_ID                     0x0220
 #define LTC2977_ID                     0x0130
 #define LTC2978_ID_REV1                        0x0110  /* Early revision */
 #define LTC2978_ID_REV2                        0x0120
+#define LTC2979_ID_A                   0x8060
+#define LTC2979_ID_B                   0x8070
 #define LTC2980_ID_A                   0x8030  /* A/B for two die IDs */
 #define LTC2980_ID_B                   0x8040
 #define LTC3880_ID                     0x4020
 #define LTC3882_ID                     0x4200
 #define LTC3882_ID_D1                  0x4240  /* Dash 1 */
 #define LTC3883_ID                     0x4300
+#define LTC3884_ID                     0x4C00
 #define LTC3886_ID                     0x4600
 #define LTC3887_ID                     0x4700
 #define LTM2987_ID_A                   0x8010  /* A/B for two die IDs */
 #define LTM2987_ID_B                   0x8020
+#define LTC3889_ID                     0x4900
+#define LTC7880_ID                     0x49E0
+#define LTM4664_ID                     0x4120
 #define LTM4675_ID                     0x47a0
 #define LTM4676_ID_REV1                        0x4400
 #define LTM4676_ID_REV2                        0x4480
 #define LTM4676A_ID                    0x47e0
+#define LTM4677_ID_REV1                        0x47B0
+#define LTM4677_ID_REV2                        0x47D0
+#define LTM4678_ID_REV1                        0x4100
+#define LTM4678_ID_REV2                        0x4110
+#define LTM4680_ID                     0x4140
 #define LTM4686_ID                     0x4770
+#define LTM4700_ID                     0x4130
 
+#define LTC2972_NUM_PAGES              2
 #define LTC2974_NUM_PAGES              4
 #define LTC2978_NUM_PAGES              8
 #define LTC3880_NUM_PAGES              2
@@ -151,7 +173,8 @@ static int ltc_wait_ready(struct i2c_client *client)
        return -ETIMEDOUT;
 }
 
-static int ltc_read_word_data(struct i2c_client *client, int page, int reg)
+static int ltc_read_word_data(struct i2c_client *client, int page, int phase,
+                             int reg)
 {
        int ret;
 
@@ -159,7 +182,7 @@ static int ltc_read_word_data(struct i2c_client *client, int page, int reg)
        if (ret < 0)
                return ret;
 
-       return pmbus_read_word_data(client, page, reg);
+       return pmbus_read_word_data(client, page, 0xff, reg);
 }
 
 static int ltc_read_byte_data(struct i2c_client *client, int page, int reg)
@@ -202,7 +225,7 @@ static int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client,
 {
        int ret;
 
-       ret = ltc_read_word_data(client, page, reg);
+       ret = ltc_read_word_data(client, page, 0xff, reg);
        if (ret >= 0) {
                if (lin11_to_val(ret) > lin11_to_val(*pmax))
                        *pmax = ret;
@@ -216,7 +239,7 @@ static int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client,
 {
        int ret;
 
-       ret = ltc_read_word_data(client, page, reg);
+       ret = ltc_read_word_data(client, page, 0xff, reg);
        if (ret >= 0) {
                if (lin11_to_val(ret) < lin11_to_val(*pmin))
                        *pmin = ret;
@@ -238,7 +261,8 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
                                  &data->vin_max);
                break;
        case PMBUS_VIRT_READ_VOUT_MAX:
-               ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK);
+               ret = ltc_read_word_data(client, page, 0xff,
+                                        LTC2978_MFR_VOUT_PEAK);
                if (ret >= 0) {
                        /*
                         * VOUT is 16 bit unsigned with fixed exponent,
@@ -269,7 +293,8 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
        return ret;
 }
 
-static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
+static int ltc2978_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct ltc2978_data *data = to_ltc2978_data(info);
@@ -281,7 +306,8 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
                                  &data->vin_min);
                break;
        case PMBUS_VIRT_READ_VOUT_MIN:
-               ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_MIN);
+               ret = ltc_read_word_data(client, page, phase,
+                                        LTC2978_MFR_VOUT_MIN);
                if (ret >= 0) {
                        /*
                         * VOUT_MIN is known to not be supported on some lots
@@ -314,7 +340,8 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
        return ret;
 }
 
-static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
+static int ltc2974_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct ltc2978_data *data = to_ltc2978_data(info);
@@ -333,13 +360,14 @@ static int ltc2974_read_word_data(struct i2c_client *client, int page, int reg)
                ret = 0;
                break;
        default:
-               ret = ltc2978_read_word_data(client, page, reg);
+               ret = ltc2978_read_word_data(client, page, phase, reg);
                break;
        }
        return ret;
 }
 
-static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg)
+static int ltc2975_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct ltc2978_data *data = to_ltc2978_data(info);
@@ -367,13 +395,14 @@ static int ltc2975_read_word_data(struct i2c_client *client, int page, int reg)
                ret = 0;
                break;
        default:
-               ret = ltc2978_read_word_data(client, page, reg);
+               ret = ltc2978_read_word_data(client, page, phase, reg);
                break;
        }
        return ret;
 }
 
-static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
+static int ltc3880_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct ltc2978_data *data = to_ltc2978_data(info);
@@ -405,7 +434,8 @@ static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg)
        return ret;
 }
 
-static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
+static int ltc3883_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct ltc2978_data *data = to_ltc2978_data(info);
@@ -420,7 +450,7 @@ static int ltc3883_read_word_data(struct i2c_client *client, int page, int reg)
                ret = 0;
                break;
        default:
-               ret = ltc3880_read_word_data(client, page, reg);
+               ret = ltc3880_read_word_data(client, page, phase, reg);
                break;
        }
        return ret;
@@ -492,20 +522,30 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
 }
 
 static const struct i2c_device_id ltc2978_id[] = {
+       {"ltc2972", ltc2972},
        {"ltc2974", ltc2974},
        {"ltc2975", ltc2975},
        {"ltc2977", ltc2977},
        {"ltc2978", ltc2978},
+       {"ltc2979", ltc2979},
        {"ltc2980", ltc2980},
        {"ltc3880", ltc3880},
        {"ltc3882", ltc3882},
        {"ltc3883", ltc3883},
+       {"ltc3884", ltc3884},
        {"ltc3886", ltc3886},
        {"ltc3887", ltc3887},
+       {"ltc3889", ltc3889},
+       {"ltc7880", ltc7880},
        {"ltm2987", ltm2987},
+       {"ltm4664", ltm4664},
        {"ltm4675", ltm4675},
        {"ltm4676", ltm4676},
+       {"ltm4677", ltm4677},
+       {"ltm4678", ltm4678},
+       {"ltm4680", ltm4680},
        {"ltm4686", ltm4686},
+       {"ltm4700", ltm4700},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ltc2978_id);
@@ -555,7 +595,9 @@ static int ltc2978_get_id(struct i2c_client *client)
 
        chip_id &= LTC2978_ID_MASK;
 
-       if (chip_id == LTC2974_ID)
+       if (chip_id == LTC2972_ID)
+               return ltc2972;
+       else if (chip_id == LTC2974_ID)
                return ltc2974;
        else if (chip_id == LTC2975_ID)
                return ltc2975;
@@ -563,6 +605,8 @@ static int ltc2978_get_id(struct i2c_client *client)
                return ltc2977;
        else if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2)
                return ltc2978;
+       else if (chip_id == LTC2979_ID_A || chip_id == LTC2979_ID_B)
+               return ltc2979;
        else if (chip_id == LTC2980_ID_A || chip_id == LTC2980_ID_B)
                return ltc2980;
        else if (chip_id == LTC3880_ID)
@@ -571,19 +615,35 @@ static int ltc2978_get_id(struct i2c_client *client)
                return ltc3882;
        else if (chip_id == LTC3883_ID)
                return ltc3883;
+       else if (chip_id == LTC3884_ID)
+               return ltc3884;
        else if (chip_id == LTC3886_ID)
                return ltc3886;
        else if (chip_id == LTC3887_ID)
                return ltc3887;
+       else if (chip_id == LTC3889_ID)
+               return ltc3889;
+       else if (chip_id == LTC7880_ID)
+               return ltc7880;
        else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B)
                return ltm2987;
+       else if (chip_id == LTM4664_ID)
+               return ltm4664;
        else if (chip_id == LTM4675_ID)
                return ltm4675;
        else if (chip_id == LTM4676_ID_REV1 || chip_id == LTM4676_ID_REV2 ||
                 chip_id == LTM4676A_ID)
                return ltm4676;
+       else if (chip_id == LTM4677_ID_REV1 || chip_id == LTM4677_ID_REV2)
+               return ltm4677;
+       else if (chip_id == LTM4678_ID_REV1 || chip_id == LTM4678_ID_REV2)
+               return ltm4678;
+       else if (chip_id == LTM4680_ID)
+               return ltm4680;
        else if (chip_id == LTM4686_ID)
                return ltm4686;
+       else if (chip_id == LTM4700_ID)
+               return ltm4700;
 
        dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id);
        return -ENODEV;
@@ -637,6 +697,19 @@ static int ltc2978_probe(struct i2c_client *client,
        data->temp2_max = 0x7c00;
 
        switch (data->id) {
+       case ltc2972:
+               info->read_word_data = ltc2975_read_word_data;
+               info->pages = LTC2972_NUM_PAGES;
+               info->func[0] = PMBUS_HAVE_IIN | PMBUS_HAVE_PIN
+                 | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT
+                 | PMBUS_HAVE_TEMP2;
+               for (i = 0; i < info->pages; i++) {
+                       info->func[i] |= PMBUS_HAVE_VOUT
+                         | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_POUT
+                         | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP
+                         | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+               }
+               break;
        case ltc2974:
                info->read_word_data = ltc2974_read_word_data;
                info->pages = LTC2974_NUM_PAGES;
@@ -662,8 +735,10 @@ static int ltc2978_probe(struct i2c_client *client,
                          | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
                }
                break;
+
        case ltc2977:
        case ltc2978:
+       case ltc2979:
        case ltc2980:
        case ltm2987:
                info->read_word_data = ltc2978_read_word_data;
@@ -680,6 +755,7 @@ static int ltc2978_probe(struct i2c_client *client,
        case ltc3887:
        case ltm4675:
        case ltm4676:
+       case ltm4677:
        case ltm4686:
                data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
                info->read_word_data = ltc3880_read_word_data;
@@ -721,7 +797,14 @@ static int ltc2978_probe(struct i2c_client *client,
                  | PMBUS_HAVE_PIN | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
                  | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
                break;
+       case ltc3884:
        case ltc3886:
+       case ltc3889:
+       case ltc7880:
+       case ltm4664:
+       case ltm4678:
+       case ltm4680:
+       case ltm4700:
                data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
                info->read_word_data = ltc3883_read_word_data;
                info->pages = LTC3880_NUM_PAGES;
@@ -752,22 +835,33 @@ static int ltc2978_probe(struct i2c_client *client,
        return pmbus_do_probe(client, id, info);
 }
 
+
 #ifdef CONFIG_OF
 static const struct of_device_id ltc2978_of_match[] = {
+       { .compatible = "lltc,ltc2972" },
        { .compatible = "lltc,ltc2974" },
        { .compatible = "lltc,ltc2975" },
        { .compatible = "lltc,ltc2977" },
        { .compatible = "lltc,ltc2978" },
+       { .compatible = "lltc,ltc2979" },
        { .compatible = "lltc,ltc2980" },
        { .compatible = "lltc,ltc3880" },
        { .compatible = "lltc,ltc3882" },
        { .compatible = "lltc,ltc3883" },
+       { .compatible = "lltc,ltc3884" },
        { .compatible = "lltc,ltc3886" },
        { .compatible = "lltc,ltc3887" },
+       { .compatible = "lltc,ltc3889" },
+       { .compatible = "lltc,ltc7880" },
        { .compatible = "lltc,ltm2987" },
+       { .compatible = "lltc,ltm4664" },
        { .compatible = "lltc,ltm4675" },
        { .compatible = "lltc,ltm4676" },
+       { .compatible = "lltc,ltm4677" },
+       { .compatible = "lltc,ltm4678" },
+       { .compatible = "lltc,ltm4680" },
        { .compatible = "lltc,ltm4686" },
+       { .compatible = "lltc,ltm4700" },
        { }
 };
 MODULE_DEVICE_TABLE(of, ltc2978_of_match);
index b83a18a..3036263 100644 (file)
@@ -55,7 +55,7 @@ static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
                 * LTC3815 does not support the CLEAR_FAULTS command.
                 * Emulate it by clearing the status register.
                 */
-               ret = pmbus_read_word_data(client, 0, PMBUS_STATUS_WORD);
+               ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_STATUS_WORD);
                if (ret > 0) {
                        pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
                                              ret);
@@ -69,25 +69,31 @@ static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
        return ret;
 }
 
-static int ltc3815_read_word_data(struct i2c_client *client, int page, int reg)
+static int ltc3815_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        int ret;
 
        switch (reg) {
        case PMBUS_VIRT_READ_VIN_MAX:
-               ret = pmbus_read_word_data(client, page, LTC3815_MFR_VIN_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          LTC3815_MFR_VIN_PEAK);
                break;
        case PMBUS_VIRT_READ_VOUT_MAX:
-               ret = pmbus_read_word_data(client, page, LTC3815_MFR_VOUT_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          LTC3815_MFR_VOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_TEMP_MAX:
-               ret = pmbus_read_word_data(client, page, LTC3815_MFR_TEMP_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          LTC3815_MFR_TEMP_PEAK);
                break;
        case PMBUS_VIRT_READ_IOUT_MAX:
-               ret = pmbus_read_word_data(client, page, LTC3815_MFR_IOUT_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          LTC3815_MFR_IOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_IIN_MAX:
-               ret = pmbus_read_word_data(client, page, LTC3815_MFR_IIN_PEAK);
+               ret = pmbus_read_word_data(client, page, phase,
+                                          LTC3815_MFR_IIN_PEAK);
                break;
        case PMBUS_VIRT_RESET_VOUT_HISTORY:
        case PMBUS_VIRT_RESET_VIN_HISTORY:
index b3e7b8d..288e93f 100644 (file)
 #define MAX16064_MFR_VOUT_PEAK         0xd4
 #define MAX16064_MFR_TEMPERATURE_PEAK  0xd6
 
-static int max16064_read_word_data(struct i2c_client *client, int page, int reg)
+static int max16064_read_word_data(struct i2c_client *client, int page,
+                                  int phase, int reg)
 {
        int ret;
 
        switch (reg) {
        case PMBUS_VIRT_READ_VOUT_MAX:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX16064_MFR_VOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_TEMP_MAX:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX16064_MFR_TEMPERATURE_PEAK);
                break;
        case PMBUS_VIRT_RESET_VOUT_HISTORY:
index 294e221..c0bb054 100644 (file)
@@ -85,7 +85,8 @@ static u32 max_current[][5] = {
        [max20743] = { 18900, 24100, 29200, 34100 },
 };
 
-static int max20730_read_word_data(struct i2c_client *client, int page, int reg)
+static int max20730_read_word_data(struct i2c_client *client, int page,
+                                  int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        const struct max20730_data *data = to_max20730_data(info);
index 254b0f9..d9aa5c8 100644 (file)
@@ -72,7 +72,7 @@ static int max31785_read_long_data(struct i2c_client *client, int page,
 
        cmdbuf[0] = reg;
 
-       rc = pmbus_set_page(client, page);
+       rc = pmbus_set_page(client, page, 0xff);
        if (rc < 0)
                return rc;
 
@@ -110,7 +110,7 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page)
        if (config < 0)
                return config;
 
-       command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1);
+       command = pmbus_read_word_data(client, page, 0xff, PMBUS_FAN_COMMAND_1);
        if (command < 0)
                return command;
 
@@ -126,7 +126,7 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page)
 }
 
 static int max31785_read_word_data(struct i2c_client *client, int page,
-                                  int reg)
+                                  int phase, int reg)
 {
        u32 val;
        int rv;
index 5c63a66..18b4e07 100644 (file)
@@ -41,7 +41,8 @@ struct max34440_data {
 
 #define to_max34440_data(x)  container_of(x, struct max34440_data, info)
 
-static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
+static int max34440_read_word_data(struct i2c_client *client, int page,
+                                  int phase, int reg)
 {
        int ret;
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
@@ -49,44 +50,44 @@ static int max34440_read_word_data(struct i2c_client *client, int page, int reg)
 
        switch (reg) {
        case PMBUS_VIRT_READ_VOUT_MIN:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX34440_MFR_VOUT_MIN);
                break;
        case PMBUS_VIRT_READ_VOUT_MAX:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX34440_MFR_VOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_IOUT_AVG:
                if (data->id != max34446 && data->id != max34451)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX34446_MFR_IOUT_AVG);
                break;
        case PMBUS_VIRT_READ_IOUT_MAX:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX34440_MFR_IOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_POUT_AVG:
                if (data->id != max34446)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX34446_MFR_POUT_AVG);
                break;
        case PMBUS_VIRT_READ_POUT_MAX:
                if (data->id != max34446)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX34446_MFR_POUT_PEAK);
                break;
        case PMBUS_VIRT_READ_TEMP_AVG:
                if (data->id != max34446 && data->id != max34460 &&
                    data->id != max34461)
                        return -ENXIO;
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX34446_MFR_TEMPERATURE_AVG);
                break;
        case PMBUS_VIRT_READ_TEMP_MAX:
-               ret = pmbus_read_word_data(client, page,
+               ret = pmbus_read_word_data(client, page, phase,
                                           MAX34440_MFR_TEMPERATURE_PEAK);
                break;
        case PMBUS_VIRT_RESET_POUT_HISTORY:
@@ -159,14 +160,14 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
        int mfg_status;
 
        if (page >= 0) {
-               ret = pmbus_set_page(client, page);
+               ret = pmbus_set_page(client, page, 0xff);
                if (ret < 0)
                        return ret;
        }
 
        switch (reg) {
        case PMBUS_STATUS_IOUT:
-               mfg_status = pmbus_read_word_data(client, 0,
+               mfg_status = pmbus_read_word_data(client, 0, 0xff,
                                                  PMBUS_STATUS_MFR_SPECIFIC);
                if (mfg_status < 0)
                        return mfg_status;
@@ -176,7 +177,7 @@ static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
                        ret |= PB_IOUT_OC_FAULT;
                break;
        case PMBUS_STATUS_TEMPERATURE:
-               mfg_status = pmbus_read_word_data(client, 0,
+               mfg_status = pmbus_read_word_data(client, 0, 0xff,
                                                  PMBUS_STATUS_MFR_SPECIFIC);
                if (mfg_status < 0)
                        return mfg_status;
index bc5f4cb..643ccfc 100644 (file)
@@ -28,7 +28,8 @@
 #define MAX8688_STATUS_OT_FAULT                BIT(13)
 #define MAX8688_STATUS_OT_WARNING      BIT(14)
 
-static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
+static int max8688_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
 {
        int ret;
 
@@ -37,13 +38,15 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
 
        switch (reg) {
        case PMBUS_VIRT_READ_VOUT_MAX:
-               ret = pmbus_read_word_data(client, 0, MAX8688_MFR_VOUT_PEAK);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          MAX8688_MFR_VOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_IOUT_MAX:
-               ret = pmbus_read_word_data(client, 0, MAX8688_MFR_IOUT_PEAK);
+               ret = pmbus_read_word_data(client, 0, 0xff,
+                                          MAX8688_MFR_IOUT_PEAK);
                break;
        case PMBUS_VIRT_READ_TEMP_MAX:
-               ret = pmbus_read_word_data(client, 0,
+               ret = pmbus_read_word_data(client, 0, 0xff,
                                           MAX8688_MFR_TEMPERATURE_PEAK);
                break;
        case PMBUS_VIRT_RESET_VOUT_HISTORY:
@@ -94,7 +97,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
 
        switch (reg) {
        case PMBUS_STATUS_VOUT:
-               mfg_status = pmbus_read_word_data(client, 0,
+               mfg_status = pmbus_read_word_data(client, 0, 0xff,
                                                  MAX8688_MFG_STATUS);
                if (mfg_status < 0)
                        return mfg_status;
@@ -108,7 +111,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
                        ret |= PB_VOLTAGE_OV_FAULT;
                break;
        case PMBUS_STATUS_IOUT:
-               mfg_status = pmbus_read_word_data(client, 0,
+               mfg_status = pmbus_read_word_data(client, 0, 0xff,
                                                  MAX8688_MFG_STATUS);
                if (mfg_status < 0)
                        return mfg_status;
@@ -120,7 +123,7 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
                        ret |= PB_IOUT_OC_FAULT;
                break;
        case PMBUS_STATUS_TEMPERATURE:
-               mfg_status = pmbus_read_word_data(client, 0,
+               mfg_status = pmbus_read_word_data(client, 0, 0xff,
                                                  MAX8688_MFG_STATUS);
                if (mfg_status < 0)
                        return mfg_status;
index 51e8312..6d384e8 100644 (file)
@@ -102,10 +102,10 @@ static int pmbus_identify(struct i2c_client *client,
                        int page;
 
                        for (page = 1; page < PMBUS_PAGES; page++) {
-                               if (pmbus_set_page(client, page) < 0)
+                               if (pmbus_set_page(client, page, 0xff) < 0)
                                        break;
                        }
-                       pmbus_set_page(client, 0);
+                       pmbus_set_page(client, 0, 0xff);
                        info->pages = page;
                } else {
                        info->pages = 1;
index 13b34bd..18e06fc 100644 (file)
@@ -119,6 +119,9 @@ enum pmbus_regs {
        PMBUS_MFR_DATE                  = 0x9D,
        PMBUS_MFR_SERIAL                = 0x9E,
 
+       PMBUS_IC_DEVICE_ID              = 0xAD,
+       PMBUS_IC_DEVICE_REV             = 0xAE,
+
 /*
  * Virtual registers.
  * Useful to support attributes which are not supported by standard PMBus
@@ -359,6 +362,7 @@ enum pmbus_sensor_classes {
 };
 
 #define PMBUS_PAGES    32      /* Per PMBus specification */
+#define PMBUS_PHASES   8       /* Maximum number of phases per page */
 
 /* Functionality bit mask */
 #define PMBUS_HAVE_VIN         BIT(0)
@@ -385,13 +389,15 @@ enum pmbus_sensor_classes {
 #define PMBUS_HAVE_PWM34       BIT(21)
 #define PMBUS_HAVE_SAMPLES     BIT(22)
 
-#define PMBUS_PAGE_VIRTUAL     BIT(31)
+#define PMBUS_PHASE_VIRTUAL    BIT(30) /* Phases on this page are virtual */
+#define PMBUS_PAGE_VIRTUAL     BIT(31) /* Page is virtual */
 
 enum pmbus_data_format { linear = 0, direct, vid };
 enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv };
 
 struct pmbus_driver_info {
        int pages;              /* Total number of pages */
+       u8 phases[PMBUS_PAGES]; /* Number of phases per page */
        enum pmbus_data_format format[PSC_NUM_CLASSES];
        enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */
        /*
@@ -403,6 +409,7 @@ struct pmbus_driver_info {
        int R[PSC_NUM_CLASSES]; /* exponent */
 
        u32 func[PMBUS_PAGES];  /* Functionality, per page */
+       u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */
        /*
         * The following functions map manufacturing specific register values
         * to PMBus standard register values. Specify only if mapping is
@@ -415,7 +422,8 @@ struct pmbus_driver_info {
         * the standard register.
         */
        int (*read_byte_data)(struct i2c_client *client, int page, int reg);
-       int (*read_word_data)(struct i2c_client *client, int page, int reg);
+       int (*read_word_data)(struct i2c_client *client, int page, int phase,
+                             int reg);
        int (*write_word_data)(struct i2c_client *client, int page, int reg,
                               u16 word);
        int (*write_byte)(struct i2c_client *client, int page, u8 value);
@@ -454,9 +462,11 @@ extern const struct regulator_ops pmbus_regulator_ops;
 /* Function declarations */
 
 void pmbus_clear_cache(struct i2c_client *client);
-int pmbus_set_page(struct i2c_client *client, int page);
-int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg);
-int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, u16 word);
+int pmbus_set_page(struct i2c_client *client, int page, int phase);
+int pmbus_read_word_data(struct i2c_client *client, int page, int phase,
+                        u8 reg);
+int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg,
+                         u16 word);
 int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
 int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
 int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg,
index d9c17fe..8d321bf 100644 (file)
@@ -49,6 +49,7 @@ struct pmbus_sensor {
        char name[PMBUS_NAME_SIZE];     /* sysfs sensor name */
        struct device_attribute attribute;
        u8 page;                /* page number */
+       u8 phase;               /* phase number, 0xff for all phases */
        u16 reg;                /* register */
        enum pmbus_sensor_classes class;        /* sensor class */
        bool update;            /* runtime sensor update needed */
@@ -109,6 +110,7 @@ struct pmbus_data {
        int (*read_status)(struct i2c_client *client, int page);
 
        u8 currpage;
+       u8 currphase;   /* current phase, 0xff for all */
 };
 
 struct pmbus_debugfs_entry {
@@ -146,15 +148,16 @@ void pmbus_clear_cache(struct i2c_client *client)
 }
 EXPORT_SYMBOL_GPL(pmbus_clear_cache);
 
-int pmbus_set_page(struct i2c_client *client, int page)
+int pmbus_set_page(struct i2c_client *client, int page, int phase)
 {
        struct pmbus_data *data = i2c_get_clientdata(client);
        int rv;
 
-       if (page < 0 || page == data->currpage)
+       if (page < 0)
                return 0;
 
-       if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL)) {
+       if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL) &&
+           data->info->pages > 1 && page != data->currpage) {
                rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
                if (rv < 0)
                        return rv;
@@ -166,9 +169,17 @@ int pmbus_set_page(struct i2c_client *client, int page)
                if (rv != page)
                        return -EIO;
        }
-
        data->currpage = page;
 
+       if (data->info->phases[page] && data->currphase != phase &&
+           !(data->info->func[page] & PMBUS_PHASE_VIRTUAL)) {
+               rv = i2c_smbus_write_byte_data(client, PMBUS_PHASE,
+                                              phase);
+               if (rv)
+                       return rv;
+       }
+       data->currphase = phase;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(pmbus_set_page);
@@ -177,7 +188,7 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
 {
        int rv;
 
-       rv = pmbus_set_page(client, page);
+       rv = pmbus_set_page(client, page, 0xff);
        if (rv < 0)
                return rv;
 
@@ -208,7 +219,7 @@ int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg,
 {
        int rv;
 
-       rv = pmbus_set_page(client, page);
+       rv = pmbus_set_page(client, page, 0xff);
        if (rv < 0)
                return rv;
 
@@ -286,11 +297,11 @@ int pmbus_update_fan(struct i2c_client *client, int page, int id,
 }
 EXPORT_SYMBOL_GPL(pmbus_update_fan);
 
-int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg)
+int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg)
 {
        int rv;
 
-       rv = pmbus_set_page(client, page);
+       rv = pmbus_set_page(client, page, phase);
        if (rv < 0)
                return rv;
 
@@ -320,14 +331,15 @@ static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg)
  * _pmbus_read_word_data() is similar to pmbus_read_word_data(), but checks if
  * a device specific mapping function exists and calls it if necessary.
  */
-static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg)
+static int _pmbus_read_word_data(struct i2c_client *client, int page,
+                                int phase, int reg)
 {
        struct pmbus_data *data = i2c_get_clientdata(client);
        const struct pmbus_driver_info *info = data->info;
        int status;
 
        if (info->read_word_data) {
-               status = info->read_word_data(client, page, reg);
+               status = info->read_word_data(client, page, phase, reg);
                if (status != -ENODATA)
                        return status;
        }
@@ -335,14 +347,20 @@ static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg)
        if (reg >= PMBUS_VIRT_BASE)
                return pmbus_read_virt_reg(client, page, reg);
 
-       return pmbus_read_word_data(client, page, reg);
+       return pmbus_read_word_data(client, page, phase, reg);
+}
+
+/* Same as above, but without phase parameter, for use in check functions */
+static int __pmbus_read_word_data(struct i2c_client *client, int page, int reg)
+{
+       return _pmbus_read_word_data(client, page, 0xff, reg);
 }
 
 int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
 {
        int rv;
 
-       rv = pmbus_set_page(client, page);
+       rv = pmbus_set_page(client, page, 0xff);
        if (rv < 0)
                return rv;
 
@@ -354,7 +372,7 @@ int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value)
 {
        int rv;
 
-       rv = pmbus_set_page(client, page);
+       rv = pmbus_set_page(client, page, 0xff);
        if (rv < 0)
                return rv;
 
@@ -440,7 +458,7 @@ static int pmbus_get_fan_rate(struct i2c_client *client, int page, int id,
 
        have_rpm = !!(config & pmbus_fan_rpm_mask[id]);
        if (want_rpm == have_rpm)
-               return pmbus_read_word_data(client, page,
+               return pmbus_read_word_data(client, page, 0xff,
                                            pmbus_fan_command_registers[id]);
 
        /* Can't sensibly map between RPM and PWM, just return zero */
@@ -530,7 +548,7 @@ EXPORT_SYMBOL_GPL(pmbus_check_byte_register);
 
 bool pmbus_check_word_register(struct i2c_client *client, int page, int reg)
 {
-       return pmbus_check_register(client, _pmbus_read_word_data, page, reg);
+       return pmbus_check_register(client, __pmbus_read_word_data, page, reg);
 }
 EXPORT_SYMBOL_GPL(pmbus_check_word_register);
 
@@ -595,6 +613,7 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
                                sensor->data
                                    = _pmbus_read_word_data(client,
                                                            sensor->page,
+                                                           sensor->phase,
                                                            sensor->reg);
                }
                pmbus_clear_faults(client);
@@ -1076,7 +1095,8 @@ static int pmbus_add_boolean(struct pmbus_data *data,
 
 static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
                                             const char *name, const char *type,
-                                            int seq, int page, int reg,
+                                            int seq, int page, int phase,
+                                            int reg,
                                             enum pmbus_sensor_classes class,
                                             bool update, bool readonly,
                                             bool convert)
@@ -1100,6 +1120,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
                readonly = true;
 
        sensor->page = page;
+       sensor->phase = phase;
        sensor->reg = reg;
        sensor->class = class;
        sensor->update = update;
@@ -1119,7 +1140,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data,
 
 static int pmbus_add_label(struct pmbus_data *data,
                           const char *name, int seq,
-                          const char *lstring, int index)
+                          const char *lstring, int index, int phase)
 {
        struct pmbus_label *label;
        struct device_attribute *a;
@@ -1131,11 +1152,21 @@ static int pmbus_add_label(struct pmbus_data *data,
        a = &label->attribute;
 
        snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq);
-       if (!index)
-               strncpy(label->label, lstring, sizeof(label->label) - 1);
-       else
-               snprintf(label->label, sizeof(label->label), "%s%d", lstring,
-                        index);
+       if (!index) {
+               if (phase == 0xff)
+                       strncpy(label->label, lstring,
+                               sizeof(label->label) - 1);
+               else
+                       snprintf(label->label, sizeof(label->label), "%s.%d",
+                                lstring, phase);
+       } else {
+               if (phase == 0xff)
+                       snprintf(label->label, sizeof(label->label), "%s%d",
+                                lstring, index);
+               else
+                       snprintf(label->label, sizeof(label->label), "%s%d.%d",
+                                lstring, index, phase);
+       }
 
        pmbus_dev_attr_init(a, label->name, 0444, pmbus_show_label, NULL);
        return pmbus_add_attribute(data, &a->attr);
@@ -1200,7 +1231,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client,
        for (i = 0; i < nlimit; i++) {
                if (pmbus_check_word_register(client, page, l->reg)) {
                        curr = pmbus_add_sensor(data, name, l->attr, index,
-                                               page, l->reg, attr->class,
+                                               page, 0xff, l->reg, attr->class,
                                                attr->update || l->update,
                                                false, true);
                        if (!curr)
@@ -1227,7 +1258,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
                                      struct pmbus_data *data,
                                      const struct pmbus_driver_info *info,
                                      const char *name,
-                                     int index, int page,
+                                     int index, int page, int phase,
                                      const struct pmbus_sensor_attr *attr,
                                      bool paged)
 {
@@ -1237,15 +1268,16 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
 
        if (attr->label) {
                ret = pmbus_add_label(data, name, index, attr->label,
-                                     paged ? page + 1 : 0);
+                                     paged ? page + 1 : 0, phase);
                if (ret)
                        return ret;
        }
-       base = pmbus_add_sensor(data, name, "input", index, page, attr->reg,
-                               attr->class, true, true, true);
+       base = pmbus_add_sensor(data, name, "input", index, page, phase,
+                               attr->reg, attr->class, true, true, true);
        if (!base)
                return -ENOMEM;
-       if (attr->sfunc) {
+       /* No limit and alarm attributes for phase specific sensors */
+       if (attr->sfunc && phase == 0xff) {
                ret = pmbus_add_limit_attrs(client, data, info, name,
                                            index, page, base, attr);
                if (ret < 0)
@@ -1315,10 +1347,25 @@ static int pmbus_add_sensor_attrs(struct i2c_client *client,
                                continue;
                        ret = pmbus_add_sensor_attrs_one(client, data, info,
                                                         name, index, page,
-                                                        attrs, paged);
+                                                        0xff, attrs, paged);
                        if (ret)
                                return ret;
                        index++;
+                       if (info->phases[page]) {
+                               int phase;
+
+                               for (phase = 0; phase < info->phases[page];
+                                    phase++) {
+                                       if (!(info->pfunc[phase] & attrs->func))
+                                               continue;
+                                       ret = pmbus_add_sensor_attrs_one(client,
+                                               data, info, name, index, page,
+                                               phase, attrs, paged);
+                                       if (ret)
+                                               return ret;
+                                       index++;
+                               }
+                       }
                }
                attrs++;
        }
@@ -1822,7 +1869,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
        struct pmbus_sensor *sensor;
 
        sensor = pmbus_add_sensor(data, "fan", "target", index, page,
-                                 PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN,
+                                 PMBUS_VIRT_FAN_TARGET_1 + id, 0xff, PSC_FAN,
                                  false, false, true);
 
        if (!sensor)
@@ -1833,14 +1880,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client,
                return 0;
 
        sensor = pmbus_add_sensor(data, "pwm", NULL, index, page,
-                                 PMBUS_VIRT_PWM_1 + id, PSC_PWM,
+                                 PMBUS_VIRT_PWM_1 + id, 0xff, PSC_PWM,
                                  false, false, true);
 
        if (!sensor)
                return -ENOMEM;
 
        sensor = pmbus_add_sensor(data, "pwm", "enable", index, page,
-                                 PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM,
+                                 PMBUS_VIRT_PWM_ENABLE_1 + id, 0xff, PSC_PWM,
                                  true, false, false);
 
        if (!sensor)
@@ -1882,7 +1929,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client,
                                continue;
 
                        if (pmbus_add_sensor(data, "fan", "input", index,
-                                            page, pmbus_fan_registers[f],
+                                            page, pmbus_fan_registers[f], 0xff,
                                             PSC_FAN, true, true, true) == NULL)
                                return -ENOMEM;
 
@@ -1964,7 +2011,7 @@ static ssize_t pmbus_show_samples(struct device *dev,
        struct i2c_client *client = to_i2c_client(dev->parent);
        struct pmbus_samples_reg *reg = to_samples_reg(devattr);
 
-       val = _pmbus_read_word_data(client, reg->page, reg->attr->reg);
+       val = _pmbus_read_word_data(client, reg->page, 0xff, reg->attr->reg);
        if (val < 0)
                return val;
 
@@ -2120,7 +2167,7 @@ static int pmbus_read_status_byte(struct i2c_client *client, int page)
 
 static int pmbus_read_status_word(struct i2c_client *client, int page)
 {
-       return _pmbus_read_word_data(client, page, PMBUS_STATUS_WORD);
+       return _pmbus_read_word_data(client, page, 0xff, PMBUS_STATUS_WORD);
 }
 
 static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
@@ -2482,6 +2529,8 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
        if (pdata)
                data->flags = pdata->flags;
        data->info = info;
+       data->currpage = 0xff;
+       data->currphase = 0xfe;
 
        ret = pmbus_init_common(client, data, info);
        if (ret < 0)
index 9c22e90..157c99f 100644 (file)
@@ -6,13 +6,21 @@
  * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
  */
 
+#include <linux/bits.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include "pmbus.h"
 
+enum chips {
+       tps53647, tps53667, tps53679, tps53681, tps53688
+};
+
+#define TPS53647_PAGE_NUM              1
+
 #define TPS53679_PROT_VR12_5MV         0x01 /* VR12.0 mode, 5-mV DAC */
 #define TPS53679_PROT_VR12_5_10MV      0x02 /* VR12.5 mode, 10-mV DAC */
 #define TPS53679_PROT_VR13_10MV                0x04 /* VR13.0 mode, 10-mV DAC */
 #define TPS53679_PROT_VR13_5MV         0x07 /* VR13.0 mode, 5-mV DAC */
 #define TPS53679_PAGE_NUM              2
 
-static int tps53679_identify(struct i2c_client *client,
-                            struct pmbus_driver_info *info)
+#define TPS53681_DEVICE_ID             0x81
+
+#define TPS53681_PMBUS_REVISION                0x33
+
+#define TPS53681_MFR_SPECIFIC_20       0xe4    /* Number of phases, per page */
+
+static int tps53679_identify_mode(struct i2c_client *client,
+                                 struct pmbus_driver_info *info)
 {
        u8 vout_params;
        int i, ret;
 
-       for (i = 0; i < TPS53679_PAGE_NUM; i++) {
+       for (i = 0; i < info->pages; i++) {
                /* Read the register with VOUT scaling value.*/
                ret = pmbus_read_byte_data(client, i, PMBUS_VOUT_MODE);
                if (ret < 0)
@@ -52,48 +66,180 @@ static int tps53679_identify(struct i2c_client *client,
        return 0;
 }
 
+static int tps53679_identify_phases(struct i2c_client *client,
+                                   struct pmbus_driver_info *info)
+{
+       int ret;
+
+       /* On TPS53681, only channel A provides per-phase output current */
+       ret = pmbus_read_byte_data(client, 0, TPS53681_MFR_SPECIFIC_20);
+       if (ret < 0)
+               return ret;
+       info->phases[0] = (ret & 0x07) + 1;
+
+       return 0;
+}
+
+static int tps53679_identify_chip(struct i2c_client *client,
+                                 u8 revision, u16 id)
+{
+       u8 buf[I2C_SMBUS_BLOCK_MAX];
+       int ret;
+
+       ret = pmbus_read_byte_data(client, 0, PMBUS_REVISION);
+       if (ret < 0)
+               return ret;
+       if (ret != revision) {
+               dev_err(&client->dev, "Unexpected PMBus revision 0x%x\n", ret);
+               return -ENODEV;
+       }
+
+       ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf);
+       if (ret < 0)
+               return ret;
+       if (ret != 1 || buf[0] != id) {
+               dev_err(&client->dev, "Unexpected device ID 0x%x\n", buf[0]);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+/*
+ * Common identification function for chips with multi-phase support.
+ * Since those chips have special configuration registers, we want to have
+ * some level of reassurance that we are really talking with the chip
+ * being probed. Check PMBus revision and chip ID.
+ */
+static int tps53679_identify_multiphase(struct i2c_client *client,
+                                       struct pmbus_driver_info *info,
+                                       int pmbus_rev, int device_id)
+{
+       int ret;
+
+       ret = tps53679_identify_chip(client, pmbus_rev, device_id);
+       if (ret < 0)
+               return ret;
+
+       ret = tps53679_identify_mode(client, info);
+       if (ret < 0)
+               return ret;
+
+       return tps53679_identify_phases(client, info);
+}
+
+static int tps53679_identify(struct i2c_client *client,
+                            struct pmbus_driver_info *info)
+{
+       return tps53679_identify_mode(client, info);
+}
+
+static int tps53681_identify(struct i2c_client *client,
+                            struct pmbus_driver_info *info)
+{
+       return tps53679_identify_multiphase(client, info,
+                                           TPS53681_PMBUS_REVISION,
+                                           TPS53681_DEVICE_ID);
+}
+
+static int tps53681_read_word_data(struct i2c_client *client, int page,
+                                  int phase, int reg)
+{
+       /*
+        * For reading the total output current (READ_IOUT) for all phases,
+        * the chip datasheet is a bit vague. It says "PHASE must be set to
+        * FFh to access all phases simultaneously. PHASE may also be set to
+        * 80h readack (!) the total phase current".
+        * Experiments show that the command does _not_ report the total
+        * current for all phases if the phase is set to 0xff. Instead, it
+        * appears to report the current of one of the phases. Override phase
+        * parameter with 0x80 when reading the total output current on page 0.
+        */
+       if (reg == PMBUS_READ_IOUT && page == 0 && phase == 0xff)
+               return pmbus_read_word_data(client, page, 0x80, reg);
+       return -ENODATA;
+}
+
 static struct pmbus_driver_info tps53679_info = {
-       .pages = TPS53679_PAGE_NUM,
        .format[PSC_VOLTAGE_IN] = linear,
        .format[PSC_VOLTAGE_OUT] = vid,
        .format[PSC_TEMPERATURE] = linear,
        .format[PSC_CURRENT_OUT] = linear,
        .format[PSC_POWER] = linear,
-       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+       .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
+               PMBUS_HAVE_STATUS_INPUT |
+               PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
                PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
                PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
                PMBUS_HAVE_POUT,
-       .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+       .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
                PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
                PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
                PMBUS_HAVE_POUT,
-       .identify = tps53679_identify,
+       .pfunc[0] = PMBUS_HAVE_IOUT,
+       .pfunc[1] = PMBUS_HAVE_IOUT,
+       .pfunc[2] = PMBUS_HAVE_IOUT,
+       .pfunc[3] = PMBUS_HAVE_IOUT,
+       .pfunc[4] = PMBUS_HAVE_IOUT,
+       .pfunc[5] = PMBUS_HAVE_IOUT,
 };
 
 static int tps53679_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
        struct pmbus_driver_info *info;
+       enum chips chip_id;
+
+       if (dev->of_node)
+               chip_id = (enum chips)of_device_get_match_data(dev);
+       else
+               chip_id = id->driver_data;
 
-       info = devm_kmemdup(&client->dev, &tps53679_info, sizeof(*info),
-                           GFP_KERNEL);
+       info = devm_kmemdup(dev, &tps53679_info, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
+       switch (chip_id) {
+       case tps53647:
+       case tps53667:
+               info->pages = TPS53647_PAGE_NUM;
+               info->identify = tps53679_identify;
+               break;
+       case tps53679:
+       case tps53688:
+               info->pages = TPS53679_PAGE_NUM;
+               info->identify = tps53679_identify;
+               break;
+       case tps53681:
+               info->pages = TPS53679_PAGE_NUM;
+               info->phases[0] = 6;
+               info->identify = tps53681_identify;
+               info->read_word_data = tps53681_read_word_data;
+               break;
+       default:
+               return -ENODEV;
+       }
+
        return pmbus_do_probe(client, id, info);
 }
 
 static const struct i2c_device_id tps53679_id[] = {
-       {"tps53679", 0},
-       {"tps53688", 0},
+       {"tps53647", tps53647},
+       {"tps53667", tps53667},
+       {"tps53679", tps53679},
+       {"tps53681", tps53681},
+       {"tps53688", tps53688},
        {}
 };
 
 MODULE_DEVICE_TABLE(i2c, tps53679_id);
 
 static const struct of_device_id __maybe_unused tps53679_of_match[] = {
-       {.compatible = "ti,tps53679"},
-       {.compatible = "ti,tps53688"},
+       {.compatible = "ti,tps53647", .data = (void *)tps53647},
+       {.compatible = "ti,tps53667", .data = (void *)tps53667},
+       {.compatible = "ti,tps53679", .data = (void *)tps53679},
+       {.compatible = "ti,tps53681", .data = (void *)tps53681},
+       {.compatible = "ti,tps53688", .data = (void *)tps53688},
        {}
 };
 MODULE_DEVICE_TABLE(of, tps53679_of_match);
index 23ea341..81f4c4f 100644 (file)
@@ -370,7 +370,7 @@ static void ucd9000_probe_gpio(struct i2c_client *client,
 #ifdef CONFIG_DEBUG_FS
 static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer)
 {
-       int ret = pmbus_set_page(client, 0);
+       int ret = pmbus_set_page(client, 0, 0xff);
 
        if (ret < 0)
                return ret;
index ecd9b65..d5103fc 100644 (file)
 #define XDPE122_AMD_625MV              0x10 /* AMD mode 6.25mV */
 #define XDPE122_PAGE_NUM               2
 
+static int xdpe122_read_word_data(struct i2c_client *client, int page,
+                                 int phase, int reg)
+{
+       const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+       long val;
+       s16 exponent;
+       s32 mantissa;
+       int ret;
+
+       switch (reg) {
+       case PMBUS_VOUT_OV_FAULT_LIMIT:
+       case PMBUS_VOUT_UV_FAULT_LIMIT:
+               ret = pmbus_read_word_data(client, page, phase, reg);
+               if (ret < 0)
+                       return ret;
+
+               /* Convert register value to LINEAR11 data. */
+               exponent = ((s16)ret) >> 11;
+               mantissa = ((s16)((ret & GENMASK(10, 0)) << 5)) >> 5;
+               val = mantissa * 1000L;
+               if (exponent >= 0)
+                       val <<= exponent;
+               else
+                       val >>= -exponent;
+
+               /* Convert data to VID register. */
+               switch (info->vrm_version[page]) {
+               case vr13:
+                       if (val >= 500)
+                               return 1 + DIV_ROUND_CLOSEST(val - 500, 10);
+                       return 0;
+               case vr12:
+                       if (val >= 250)
+                               return 1 + DIV_ROUND_CLOSEST(val - 250, 5);
+                       return 0;
+               case imvp9:
+                       if (val >= 200)
+                               return 1 + DIV_ROUND_CLOSEST(val - 200, 10);
+                       return 0;
+               case amd625mv:
+                       if (val >= 200 && val <= 1550)
+                               return DIV_ROUND_CLOSEST((1550 - val) * 100,
+                                                        625);
+                       return 0;
+               default:
+                       return -EINVAL;
+               }
+       default:
+               return -ENODATA;
+       }
+
+       return 0;
+}
+
 static int xdpe122_identify(struct i2c_client *client,
                            struct pmbus_driver_info *info)
 {
@@ -70,6 +124,7 @@ static struct pmbus_driver_info xdpe122_info = {
                PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
                PMBUS_HAVE_POUT | PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT,
        .identify = xdpe122_identify,
+       .read_word_data = xdpe122_read_word_data,
 };
 
 static int xdpe122_probe(struct i2c_client *client,
index 190b898..3a827d0 100644 (file)
@@ -125,7 +125,8 @@ static inline void zl6100_wait(const struct zl6100_data *data)
        }
 }
 
-static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
+static int zl6100_read_word_data(struct i2c_client *client, int page,
+                                int phase, int reg)
 {
        const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
        struct zl6100_data *data = to_zl6100_data(info);
@@ -167,7 +168,7 @@ static int zl6100_read_word_data(struct i2c_client *client, int page, int reg)
        }
 
        zl6100_wait(data);
-       ret = pmbus_read_word_data(client, page, vreg);
+       ret = pmbus_read_word_data(client, page, phase, vreg);
        data->access = ktime_get();
        if (ret < 0)
                return ret;
index 8264e84..e5d18da 100644 (file)
@@ -270,10 +270,10 @@ static int via_cputemp_down_prep(unsigned int cpu)
 }
 
 static const struct x86_cpu_id __initconst cputemp_ids[] = {
-       { X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */
-       { X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */
-       { X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */
-       { X86_VENDOR_CENTAUR, 7, X86_MODEL_ANY, },
+       X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 6, X86_CENTAUR_FAM6_C7_A,   NULL),
+       X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 6, X86_CENTAUR_FAM6_C7_D,   NULL),
+       X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 6, X86_CENTAUR_FAM6_NANO,   NULL),
+       X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, X86_MODEL_ANY,           NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, cputemp_ids);
index 8e48c74..255f8f4 100644 (file)
@@ -718,9 +718,6 @@ static int msc_win_set_lockout(struct msc_window *win,
 
        if (old != expect) {
                ret = -EINVAL;
-               dev_warn_ratelimited(msc_dev(win->msc),
-                                    "expected lockout state %d, got %d\n",
-                                    expect, old);
                goto unlock;
        }
 
@@ -741,6 +738,10 @@ unlock:
                /* from intel_th_msc_window_unlock(), don't warn if not locked */
                if (expect == WIN_LOCKED && old == new)
                        return 0;
+
+               dev_warn_ratelimited(msc_dev(win->msc),
+                                    "expected lockout state %d, got %d\n",
+                                    expect, old);
        }
 
        return ret;
@@ -760,7 +761,7 @@ static int msc_configure(struct msc *msc)
        lockdep_assert_held(&msc->buf_mutex);
 
        if (msc->mode > MSC_MODE_MULTI)
-               return -ENOTSUPP;
+               return -EINVAL;
 
        if (msc->mode == MSC_MODE_MULTI) {
                if (msc_win_set_lockout(msc->cur_win, WIN_READY, WIN_INUSE))
@@ -1294,7 +1295,7 @@ static int msc_buffer_alloc(struct msc *msc, unsigned long *nr_pages,
        } else if (msc->mode == MSC_MODE_MULTI) {
                ret = msc_buffer_multi_alloc(msc, nr_pages, nr_wins);
        } else {
-               ret = -ENOTSUPP;
+               ret = -EINVAL;
        }
 
        if (!ret) {
@@ -1530,7 +1531,7 @@ static ssize_t intel_th_msc_read(struct file *file, char __user *buf,
                if (ret >= 0)
                        *ppos = iter->offset;
        } else {
-               ret = -ENOTSUPP;
+               ret = -EINVAL;
        }
 
 put_count:
index e9d90b5..86aa6a4 100644 (file)
@@ -235,6 +235,11 @@ static const struct pci_device_id intel_th_pci_id_table[] = {
                .driver_data = (kernel_ulong_t)&intel_th_2x,
        },
        {
+               /* Elkhart Lake CPU */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4529),
+               .driver_data = (kernel_ulong_t)&intel_th_2x,
+       },
+       {
                /* Elkhart Lake */
                PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4b26),
                .driver_data = (kernel_ulong_t)&intel_th_2x,
index b178a54..360b5c0 100644 (file)
@@ -238,7 +238,7 @@ static struct configfs_attribute *sys_t_policy_attrs[] = {
 static inline bool sys_t_need_ts(struct sys_t_output *op)
 {
        if (op->node.ts_interval &&
-           time_after(op->ts_jiffies + op->node.ts_interval, jiffies)) {
+           time_after(jiffies, op->ts_jiffies + op->node.ts_interval)) {
                op->ts_jiffies = jiffies;
 
                return true;
@@ -250,8 +250,8 @@ static inline bool sys_t_need_ts(struct sys_t_output *op)
 static bool sys_t_need_clock_sync(struct sys_t_output *op)
 {
        if (op->node.clocksync_interval &&
-           time_after(op->clocksync_jiffies + op->node.clocksync_interval,
-                      jiffies)) {
+           time_after(jiffies,
+                      op->clocksync_jiffies + op->node.clocksync_interval)) {
                op->clocksync_jiffies = jiffies;
 
                return true;
index 5255d37..1de23b4 100644 (file)
@@ -171,7 +171,7 @@ static void altr_i2c_init(struct altr_i2c_dev *idev)
        /* SCL Low Time */
        writel(t_low, idev->base + ALTR_I2C_SCL_LOW);
        /* SDA Hold Time, 300ns */
-       writel(div_u64(300 * clk_mhz, 1000), idev->base + ALTR_I2C_SDA_HOLD);
+       writel(3 * clk_mhz / 10, idev->base + ALTR_I2C_SDA_HOLD);
 
        /* Mask all master interrupt bits */
        altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, false);
index 050adda..05b35ac 100644 (file)
@@ -313,6 +313,7 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
        pm_runtime_get_noresume(&pdev->dev);
 
        i2c_del_adapter(&dev->adapter);
+       devm_free_irq(&pdev->dev, dev->irq, dev);
        pci_free_irq_vectors(pdev);
 }
 
index 3a9e840..a4a6825 100644 (file)
@@ -348,7 +348,7 @@ static struct gpio_desc *i2c_gpio_get_desc(struct device *dev,
        if (ret == -ENOENT)
                retdesc = ERR_PTR(-EPROBE_DEFER);
 
-       if (ret != -EPROBE_DEFER)
+       if (PTR_ERR(retdesc) != -EPROBE_DEFER)
                dev_err(dev, "error trying to get descriptor: %d\n", ret);
 
        return retdesc;
index 8497c7a..224f830 100644 (file)
@@ -477,6 +477,7 @@ static int hix5hd2_i2c_remove(struct platform_device *pdev)
        i2c_del_adapter(&priv->adap);
        pm_runtime_disable(priv->dev);
        pm_runtime_set_suspended(priv->dev);
+       clk_disable_unprepare(priv->clk);
 
        return 0;
 }
index ca4f096..a9c03f5 100644 (file)
 #define TCOBASE                0x050
 #define TCOCTL         0x054
 
-#define ACPIBASE               0x040
-#define ACPIBASE_SMI_OFF       0x030
-#define ACPICTRL               0x044
-#define ACPICTRL_EN            0x080
-
 #define SBREG_BAR              0x10
 #define SBREG_SMBCTRL          0xc6000c
 #define SBREG_SMBCTRL_DNV      0xcf000c
@@ -1553,7 +1548,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
                pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden);
        spin_unlock(&p2sb_spinlock);
 
-       res = &tco_res[ICH_RES_MEM_OFF];
+       res = &tco_res[1];
        if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS)
                res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV;
        else
@@ -1563,7 +1558,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev,
        res->flags = IORESOURCE_MEM;
 
        return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
-                                       tco_res, 3, &spt_tco_platform_data,
+                                       tco_res, 2, &spt_tco_platform_data,
                                        sizeof(spt_tco_platform_data));
 }
 
@@ -1576,17 +1571,16 @@ static struct platform_device *
 i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev,
                 struct resource *tco_res)
 {
-       return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1,
-                                       tco_res, 2, &cnl_tco_platform_data,
-                                       sizeof(cnl_tco_platform_data));
+       return platform_device_register_resndata(&pci_dev->dev,
+                       "iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data,
+                       sizeof(cnl_tco_platform_data));
 }
 
 static void i801_add_tco(struct i801_priv *priv)
 {
-       u32 base_addr, tco_base, tco_ctl, ctrl_val;
        struct pci_dev *pci_dev = priv->pci_dev;
-       struct resource tco_res[3], *res;
-       unsigned int devfn;
+       struct resource tco_res[2], *res;
+       u32 tco_base, tco_ctl;
 
        /* If we have ACPI based watchdog use that instead */
        if (acpi_has_watchdog())
@@ -1601,30 +1595,15 @@ static void i801_add_tco(struct i801_priv *priv)
                return;
 
        memset(tco_res, 0, sizeof(tco_res));
-
-       res = &tco_res[ICH_RES_IO_TCO];
-       res->start = tco_base & ~1;
-       res->end = res->start + 32 - 1;
-       res->flags = IORESOURCE_IO;
-
        /*
-        * Power Management registers.
+        * Always populate the main iTCO IO resource here. The second entry
+        * for NO_REBOOT MMIO is filled by the SPT specific function.
         */
-       devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 2);
-       pci_bus_read_config_dword(pci_dev->bus, devfn, ACPIBASE, &base_addr);
-
-       res = &tco_res[ICH_RES_IO_SMI];
-       res->start = (base_addr & ~1) + ACPIBASE_SMI_OFF;
-       res->end = res->start + 3;
+       res = &tco_res[0];
+       res->start = tco_base & ~1;
+       res->end = res->start + 32 - 1;
        res->flags = IORESOURCE_IO;
 
-       /*
-        * Enable the ACPI I/O space.
-        */
-       pci_bus_read_config_dword(pci_dev->bus, devfn, ACPICTRL, &ctrl_val);
-       ctrl_val |= ACPICTRL_EN;
-       pci_bus_write_config_dword(pci_dev->bus, devfn, ACPICTRL, ctrl_val);
-
        if (priv->features & FEATURE_TCO_CNL)
                priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res);
        else
index 16a67a6..b426fc9 100644 (file)
 
 #define X1000_I2C_DC_STOP              BIT(9)
 
-static const char * const jz4780_i2c_abrt_src[] = {
-       "ABRT_7B_ADDR_NOACK",
-       "ABRT_10ADDR1_NOACK",
-       "ABRT_10ADDR2_NOACK",
-       "ABRT_XDATA_NOACK",
-       "ABRT_GCALL_NOACK",
-       "ABRT_GCALL_READ",
-       "ABRT_HS_ACKD",
-       "SBYTE_ACKDET",
-       "ABRT_HS_NORSTRT",
-       "SBYTE_NORSTRT",
-       "ABRT_10B_RD_NORSTRT",
-       "ABRT_MASTER_DIS",
-       "ARB_LOST",
-       "SLVFLUSH_TXFIFO",
-       "SLV_ARBLOST",
-       "SLVRD_INTX",
-};
-
 #define JZ4780_I2C_INTST_IGC           BIT(11)
 #define JZ4780_I2C_INTST_ISTT          BIT(10)
 #define JZ4780_I2C_INTST_ISTP          BIT(9)
@@ -576,21 +557,8 @@ done:
 
 static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src)
 {
-       int i;
-
-       dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src);
-       dev_err(&i2c->adap.dev, "device addr=%x\n",
-               jz4780_i2c_readw(i2c, JZ4780_I2C_TAR));
-       dev_err(&i2c->adap.dev, "send cmd count:%d  %d\n",
-               i2c->cmd, i2c->cmd_buf[i2c->cmd]);
-       dev_err(&i2c->adap.dev, "receive data count:%d  %d\n",
-               i2c->cmd, i2c->data_buf[i2c->cmd]);
-
-       for (i = 0; i < 16; i++) {
-               if (src & BIT(i))
-                       dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n",
-                               i, jz4780_i2c_abrt_src[i]);
-       }
+       dev_dbg(&i2c->adap.dev, "txabrt: 0x%08x, cmd: %d, send: %d, recv: %d\n",
+               src, i2c->cmd, i2c->cmd_buf[i2c->cmd], i2c->data_buf[i2c->cmd]);
 }
 
 static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
index 62e18b4..f5d25ce 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
@@ -75,20 +76,15 @@ static void gpu_enable_i2c_bus(struct gpu_i2c_dev *i2cd)
 
 static int gpu_i2c_check_status(struct gpu_i2c_dev *i2cd)
 {
-       unsigned long target = jiffies + msecs_to_jiffies(1000);
        u32 val;
+       int ret;
 
-       do {
-               val = readl(i2cd->regs + I2C_MST_CNTL);
-               if (!(val & I2C_MST_CNTL_CYCLE_TRIGGER))
-                       break;
-               if ((val & I2C_MST_CNTL_STATUS) !=
-                               I2C_MST_CNTL_STATUS_BUS_BUSY)
-                       break;
-               usleep_range(500, 600);
-       } while (time_is_after_jiffies(target));
-
-       if (time_is_before_jiffies(target)) {
+       ret = readl_poll_timeout(i2cd->regs + I2C_MST_CNTL, val,
+                                !(val & I2C_MST_CNTL_CYCLE_TRIGGER) ||
+                                (val & I2C_MST_CNTL_STATUS) != I2C_MST_CNTL_STATUS_BUS_BUSY,
+                                500, 1000 * USEC_PER_MSEC);
+
+       if (ret) {
                dev_err(i2cd->dev, "i2c timeout error %x\n", val);
                return -ETIMEDOUT;
        }
index a7a8184..635dd69 100644 (file)
@@ -140,7 +140,7 @@ static int i2c_pca_pf_probe(struct platform_device *pdev)
        int ret = 0;
        int irq;
 
-       irq = platform_get_irq(pdev, 0);
+       irq = platform_get_irq_optional(pdev, 0);
        /* If irq is 0, we do polling. */
        if (irq < 0)
                irq = 0;
index 54e1fc8..f7f7b5b 100644 (file)
@@ -434,6 +434,7 @@ static void st_i2c_wr_fill_tx_fifo(struct st_i2c_dev *i2c_dev)
 /**
  * st_i2c_rd_fill_tx_fifo() - Fill the Tx FIFO in read mode
  * @i2c_dev: Controller's private data
+ * @max: Maximum amount of data to fill into the Tx FIFO
  *
  * This functions fills the Tx FIFO with fixed pattern when
  * in read mode to trigger clock.
index 8f3dbc9..8b0ff78 100644 (file)
@@ -394,9 +394,17 @@ EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle);
 static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev)
 {
        struct device *dev;
+       struct i2c_client *client;
 
        dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev);
-       return dev ? i2c_verify_client(dev) : NULL;
+       if (!dev)
+               return NULL;
+
+       client = i2c_verify_client(dev);
+       if (!client)
+               put_device(dev);
+
+       return client;
 }
 
 static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
index 9e2e140..bb8e60d 100644 (file)
@@ -213,40 +213,34 @@ i3c_device_match_id(struct i3c_device *i3cdev,
 {
        struct i3c_device_info devinfo;
        const struct i3c_device_id *id;
+       u16 manuf, part, ext_info;
+       bool rndpid;
 
        i3c_device_get_info(i3cdev, &devinfo);
 
-       /*
-        * The lower 32bits of the provisional ID is just filled with a random
-        * value, try to match using DCR info.
-        */
-       if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
-               u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
-               u16 part = I3C_PID_PART_ID(devinfo.pid);
-               u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
-
-               /* First try to match by manufacturer/part ID. */
-               for (id = id_table; id->match_flags != 0; id++) {
-                       if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
-                           I3C_MATCH_MANUF_AND_PART)
-                               continue;
-
-                       if (manuf != id->manuf_id || part != id->part_id)
-                               continue;
-
-                       if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
-                           ext_info != id->extra_info)
-                               continue;
-
-                       return id;
-               }
-       }
+       manuf = I3C_PID_MANUF_ID(devinfo.pid);
+       part = I3C_PID_PART_ID(devinfo.pid);
+       ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
+       rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid);
 
-       /* Fallback to DCR match. */
        for (id = id_table; id->match_flags != 0; id++) {
                if ((id->match_flags & I3C_MATCH_DCR) &&
-                   id->dcr == devinfo.dcr)
-                       return id;
+                   id->dcr != devinfo.dcr)
+                       continue;
+
+               if ((id->match_flags & I3C_MATCH_MANUF) &&
+                   id->manuf_id != manuf)
+                       continue;
+
+               if ((id->match_flags & I3C_MATCH_PART) &&
+                   (rndpid || id->part_id != part))
+                       continue;
+
+               if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
+                   (rndpid || id->extra_info != ext_info))
+                       continue;
+
+               return id;
        }
 
        return NULL;
index 7f8f896..d79cd6d 100644 (file)
@@ -241,12 +241,34 @@ out:
 }
 static DEVICE_ATTR_RO(hdrcap);
 
+static ssize_t modalias_show(struct device *dev,
+                            struct device_attribute *da, char *buf)
+{
+       struct i3c_device *i3c = dev_to_i3cdev(dev);
+       struct i3c_device_info devinfo;
+       u16 manuf, part, ext;
+
+       i3c_device_get_info(i3c, &devinfo);
+       manuf = I3C_PID_MANUF_ID(devinfo.pid);
+       part = I3C_PID_PART_ID(devinfo.pid);
+       ext = I3C_PID_EXTRA_INFO(devinfo.pid);
+
+       if (I3C_PID_RND_LOWER_32BITS(devinfo.pid))
+               return sprintf(buf, "i3c:dcr%02Xmanuf%04X", devinfo.dcr,
+                              manuf);
+
+       return sprintf(buf, "i3c:dcr%02Xmanuf%04Xpart%04Xext%04X",
+                      devinfo.dcr, manuf, part, ext);
+}
+static DEVICE_ATTR_RO(modalias);
+
 static struct attribute *i3c_device_attrs[] = {
        &dev_attr_bcr.attr,
        &dev_attr_dcr.attr,
        &dev_attr_pid.attr,
        &dev_attr_dynamic_address.attr,
        &dev_attr_hdrcap.attr,
+       &dev_attr_modalias.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(i3c_device);
@@ -267,7 +289,7 @@ static int i3c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
                                      devinfo.dcr, manuf);
 
        return add_uevent_var(env,
-                             "MODALIAS=i3c:dcr%02Xmanuf%04Xpart%04xext%04x",
+                             "MODALIAS=i3c:dcr%02Xmanuf%04Xpart%04Xext%04X",
                              devinfo.dcr, manuf, part, ext);
 }
 
@@ -1953,7 +1975,7 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
         * DEFSLVS command.
         */
        if (boardinfo->base.flags & I2C_CLIENT_TEN) {
-               dev_err(&master->dev, "I2C device with 10 bit address not supported.");
+               dev_err(dev, "I2C device with 10 bit address not supported.");
                return -ENOTSUPP;
        }
 
@@ -2138,7 +2160,7 @@ static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
         * correctly even if one or more i2c devices are not registered.
         */
        i3c_bus_for_each_i2cdev(&master->bus, i2cdev)
-               i2cdev->dev = i2c_new_device(adap, &i2cdev->boardinfo->base);
+               i2cdev->dev = i2c_new_client_device(adap, &i2cdev->boardinfo->base);
 
        return 0;
 }
index bd26c3b..5c5306c 100644 (file)
@@ -221,7 +221,7 @@ struct dw_i3c_xfer {
        struct completion comp;
        int ret;
        unsigned int ncmds;
-       struct dw_i3c_cmd cmds[0];
+       struct dw_i3c_cmd cmds[];
 };
 
 struct dw_i3c_master {
index 5471279..3fee8bd 100644 (file)
@@ -388,7 +388,7 @@ struct cdns_i3c_xfer {
        struct completion comp;
        int ret;
        unsigned int ncmds;
-       struct cdns_i3c_cmd cmds[0];
+       struct cdns_i3c_cmd cmds[];
 };
 
 struct cdns_i3c_data {
index 1c227ea..593f149 100644 (file)
@@ -662,23 +662,6 @@ config BLK_DEV_IDE_PMAC_ATA100FIRST
          CD-ROM on hda. This option changes this to more natural hda for
          hard disk and hdc for CD-ROM.
 
-config BLK_DEV_IDE_AU1XXX
-       bool "IDE for AMD Alchemy Au1200"
-       depends on MIPS_ALCHEMY
-       select IDE_XFER_MODE
-choice
-       prompt "IDE Mode for AMD Alchemy Au1200"
-       default BLK_DEV_IDE_AU1XXX_PIO_DBDMA
-       depends on BLK_DEV_IDE_AU1XXX
-
-config BLK_DEV_IDE_AU1XXX_PIO_DBDMA
-       bool "PIO+DbDMA IDE for AMD Alchemy Au1200"
-
-config BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-       bool "MDMA2+DbDMA IDE for AMD Alchemy Au1200"
-       depends on BLK_DEV_IDE_AU1XXX
-endchoice
-
 config BLK_DEV_IDE_TX4938
        tristate "TX4938 internal IDE support"
        depends on SOC_TX4938
@@ -859,8 +842,7 @@ config BLK_DEV_UMC8672
 endif
 
 config BLK_DEV_IDEDMA
-       def_bool BLK_DEV_IDEDMA_SFF || \
-                BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
+       def_bool BLK_DEV_IDEDMA_SFF || BLK_DEV_IDEDMA_ICS
        select IDE_XFER_MODE
 
 endif # IDE
index d4f4409..2605b3c 100644 (file)
@@ -107,7 +107,5 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)    += icside.o
 obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)       += rapide.o
 obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710)  += palm_bk3710.o
 
-obj-$(CONFIG_BLK_DEV_IDE_AU1XXX)       += au1xxx-ide.o
-
 obj-$(CONFIG_BLK_DEV_IDE_TX4938)       += tx4938ide.o
 obj-$(CONFIG_BLK_DEV_IDE_TX4939)       += tx4939ide.o
diff --git a/drivers/ide/au1xxx-ide.c b/drivers/ide/au1xxx-ide.c
deleted file mode 100644 (file)
index 4d181a9..0000000
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * AMD Alchemy Au1xxx IDE interface routines over the Static Bus
- *
- * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE
- *       Interface and Linux Device Driver" Application Note.
- */
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/ide.h>
-#include <linux/scatterlist.h>
-
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-au1x00/au1xxx_ide.h>
-
-#define DRV_NAME       "au1200-ide"
-#define DRV_AUTHOR     "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>"
-
-#ifndef IDE_REG_SHIFT
-#define IDE_REG_SHIFT 5
-#endif
-
-/* enable the burstmode in the dbdma */
-#define IDE_AU1XXX_BURSTMODE   1
-
-static _auide_hwif auide_hwif;
-
-#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
-
-static inline void auide_insw(unsigned long port, void *addr, u32 count)
-{
-       _auide_hwif *ahwif = &auide_hwif;
-       chan_tab_t *ctp;
-       au1x_ddma_desc_t *dp;
-
-       if (!au1xxx_dbdma_put_dest(ahwif->rx_chan, virt_to_phys(addr),
-                                  count << 1, DDMA_FLAGS_NOIE)) {
-               printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
-               return;
-       }
-       ctp = *((chan_tab_t **)ahwif->rx_chan);
-       dp = ctp->cur_ptr;
-       while (dp->dscr_cmd0 & DSCR_CMD0_V)
-               ;
-       ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
-}
-
-static inline void auide_outsw(unsigned long port, void *addr, u32 count)
-{
-       _auide_hwif *ahwif = &auide_hwif;
-       chan_tab_t *ctp;
-       au1x_ddma_desc_t *dp;
-
-       if (!au1xxx_dbdma_put_source(ahwif->tx_chan, virt_to_phys(addr),
-                                    count << 1, DDMA_FLAGS_NOIE)) {
-               printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
-               return;
-       }
-       ctp = *((chan_tab_t **)ahwif->tx_chan);
-       dp = ctp->cur_ptr;
-       while (dp->dscr_cmd0 & DSCR_CMD0_V)
-               ;
-       ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
-}
-
-static void au1xxx_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
-                             void *buf, unsigned int len)
-{
-       auide_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
-}
-
-static void au1xxx_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
-                              void *buf, unsigned int len)
-{
-       auide_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
-}
-#endif
-
-static void au1xxx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
-
-       switch (drive->pio_mode - XFER_PIO_0) {
-       case 0:
-               mem_sttime = SBC_IDE_TIMING(PIO0);
-
-               /* set configuration for RCS2# */
-               mem_stcfg |= TS_MASK;
-               mem_stcfg &= ~TCSOE_MASK;
-               mem_stcfg &= ~TOECS_MASK;
-               mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS;
-               break;
-
-       case 1:
-               mem_sttime = SBC_IDE_TIMING(PIO1);
-
-               /* set configuration for RCS2# */
-               mem_stcfg |= TS_MASK;
-               mem_stcfg &= ~TCSOE_MASK;
-               mem_stcfg &= ~TOECS_MASK;
-               mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS;
-               break;
-
-       case 2:
-               mem_sttime = SBC_IDE_TIMING(PIO2);
-
-               /* set configuration for RCS2# */
-               mem_stcfg &= ~TS_MASK;
-               mem_stcfg &= ~TCSOE_MASK;
-               mem_stcfg &= ~TOECS_MASK;
-               mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS;
-               break;
-
-       case 3:
-               mem_sttime = SBC_IDE_TIMING(PIO3);
-
-               /* set configuration for RCS2# */
-               mem_stcfg &= ~TS_MASK;
-               mem_stcfg &= ~TCSOE_MASK;
-               mem_stcfg &= ~TOECS_MASK;
-               mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS;
-
-               break;
-
-       case 4:
-               mem_sttime = SBC_IDE_TIMING(PIO4);
-
-               /* set configuration for RCS2# */
-               mem_stcfg &= ~TS_MASK;
-               mem_stcfg &= ~TCSOE_MASK;
-               mem_stcfg &= ~TOECS_MASK;
-               mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS;
-               break;
-       }
-
-       au_writel(mem_sttime,MEM_STTIME2);
-       au_writel(mem_stcfg,MEM_STCFG2);
-}
-
-static void auide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
-{
-       int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
-
-       switch (drive->dma_mode) {
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-       case XFER_MW_DMA_2:
-               mem_sttime = SBC_IDE_TIMING(MDMA2);
-
-               /* set configuration for RCS2# */
-               mem_stcfg &= ~TS_MASK;
-               mem_stcfg &= ~TCSOE_MASK;
-               mem_stcfg &= ~TOECS_MASK;
-               mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS;
-
-               break;
-       case XFER_MW_DMA_1:
-               mem_sttime = SBC_IDE_TIMING(MDMA1);
-
-               /* set configuration for RCS2# */
-               mem_stcfg &= ~TS_MASK;
-               mem_stcfg &= ~TCSOE_MASK;
-               mem_stcfg &= ~TOECS_MASK;
-               mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS;
-
-               break;
-       case XFER_MW_DMA_0:
-               mem_sttime = SBC_IDE_TIMING(MDMA0);
-
-               /* set configuration for RCS2# */
-               mem_stcfg |= TS_MASK;
-               mem_stcfg &= ~TCSOE_MASK;
-               mem_stcfg &= ~TOECS_MASK;
-               mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS;
-
-               break;
-#endif
-       }
-
-       au_writel(mem_sttime,MEM_STTIME2);
-       au_writel(mem_stcfg,MEM_STCFG2);
-}
-
-/*
- * Multi-Word DMA + DbDMA functions
- */
-
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       ide_hwif_t *hwif = drive->hwif;
-       _auide_hwif *ahwif = &auide_hwif;
-       struct scatterlist *sg;
-       int i = cmd->sg_nents, count = 0;
-       int iswrite = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
-
-       /* Save for interrupt context */
-       ahwif->drive = drive;
-
-       /* fill the descriptors */
-       sg = hwif->sg_table;
-       while (i && sg_dma_len(sg)) {
-               u32 cur_addr;
-               u32 cur_len;
-
-               cur_addr = sg_dma_address(sg);
-               cur_len = sg_dma_len(sg);
-
-               while (cur_len) {
-                       u32 flags = DDMA_FLAGS_NOIE;
-                       unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
-
-                       if (++count >= PRD_ENTRIES) {
-                               printk(KERN_WARNING "%s: DMA table too small\n",
-                                      drive->name);
-                               return 0;
-                       }
-
-                       /* Lets enable intr for the last descriptor only */
-                       if (1==i)
-                               flags = DDMA_FLAGS_IE;
-                       else
-                               flags = DDMA_FLAGS_NOIE;
-
-                       if (iswrite) {
-                               if (!au1xxx_dbdma_put_source(ahwif->tx_chan,
-                                       sg_phys(sg), tc, flags)) {
-                                       printk(KERN_ERR "%s failed %d\n", 
-                                              __func__, __LINE__);
-                               }
-                       } else  {
-                               if (!au1xxx_dbdma_put_dest(ahwif->rx_chan,
-                                       sg_phys(sg), tc, flags)) {
-                                       printk(KERN_ERR "%s failed %d\n", 
-                                              __func__, __LINE__);
-                               }
-                       }
-
-                       cur_addr += tc;
-                       cur_len -= tc;
-               }
-               sg = sg_next(sg);
-               i--;
-       }
-
-       if (count)
-               return 1;
-
-       return 0; /* revert to PIO for this request */
-}
-
-static int auide_dma_end(ide_drive_t *drive)
-{
-       return 0;
-}
-
-static void auide_dma_start(ide_drive_t *drive )
-{
-}
-
-
-static int auide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
-{
-       if (auide_build_dmatable(drive, cmd) == 0)
-               return 1;
-
-       return 0;
-}
-
-static int auide_dma_test_irq(ide_drive_t *drive)
-{
-       /* If dbdma didn't execute the STOP command yet, the
-        * active bit is still set
-        */
-       drive->waiting_for_dma++;
-       if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
-               printk(KERN_WARNING "%s: timeout waiting for ddma to complete\n",
-                      drive->name);
-               return 1;
-       }
-       udelay(10);
-       return 0;
-}
-
-static void auide_dma_host_set(ide_drive_t *drive, int on)
-{
-}
-
-static void auide_ddma_tx_callback(int irq, void *param)
-{
-}
-
-static void auide_ddma_rx_callback(int irq, void *param)
-{
-}
-#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
-
-static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize,
-                                u32 devwidth, u32 flags, u32 regbase)
-{
-       dev->dev_id          = dev_id;
-       dev->dev_physaddr    = CPHYSADDR(regbase);
-       dev->dev_intlevel    = 0;
-       dev->dev_intpolarity = 0;
-       dev->dev_tsize       = tsize;
-       dev->dev_devwidth    = devwidth;
-       dev->dev_flags       = flags;
-}
-
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-static const struct ide_dma_ops au1xxx_dma_ops = {
-       .dma_host_set           = auide_dma_host_set,
-       .dma_setup              = auide_dma_setup,
-       .dma_start              = auide_dma_start,
-       .dma_end                = auide_dma_end,
-       .dma_test_irq           = auide_dma_test_irq,
-       .dma_lost_irq           = ide_dma_lost_irq,
-};
-
-static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       _auide_hwif *auide = &auide_hwif;
-       dbdev_tab_t source_dev_tab, target_dev_tab;
-       u32 dev_id, tsize, devwidth, flags;
-
-       dev_id   = hwif->ddma_id;
-
-       tsize    =  8; /*  1 */
-       devwidth = 32; /* 16 */
-
-#ifdef IDE_AU1XXX_BURSTMODE 
-       flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
-#else
-       flags = DEV_FLAGS_SYNC;
-#endif
-
-       /* setup dev_tab for tx channel */
-       auide_init_dbdma_dev(&source_dev_tab, dev_id, tsize, devwidth,
-                            DEV_FLAGS_OUT | flags, auide->regbase);
-       auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
-
-       auide_init_dbdma_dev(&source_dev_tab, dev_id, tsize, devwidth,
-                            DEV_FLAGS_IN | flags, auide->regbase);
-       auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
-       
-       /* We also need to add a target device for the DMA */
-       auide_init_dbdma_dev(&target_dev_tab, (u32)DSCR_CMD0_ALWAYS, tsize,
-                            devwidth, DEV_FLAGS_ANYUSE, auide->regbase);
-       auide->target_dev_id = au1xxx_ddma_add_device(&target_dev_tab); 
-       /* Get a channel for TX */
-       auide->tx_chan = au1xxx_dbdma_chan_alloc(auide->target_dev_id,
-                                                auide->tx_dev_id,
-                                                auide_ddma_tx_callback,
-                                                (void*)auide);
-       /* Get a channel for RX */
-       auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id,
-                                                auide->target_dev_id,
-                                                auide_ddma_rx_callback,
-                                                (void*)auide);
-
-       auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan,
-                                                            NUM_DESCRIPTORS);
-       auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
-                                                            NUM_DESCRIPTORS);
-
-       /* FIXME: check return value */
-       (void)ide_allocate_dma_engine(hwif);
-       
-       au1xxx_dbdma_start( auide->tx_chan );
-       au1xxx_dbdma_start( auide->rx_chan );
-       return 0;
-} 
-#else
-static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
-{
-       _auide_hwif *auide = &auide_hwif;
-       dbdev_tab_t source_dev_tab;
-       int flags;
-
-#ifdef IDE_AU1XXX_BURSTMODE 
-       flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
-#else
-       flags = DEV_FLAGS_SYNC;
-#endif
-
-       /* setup dev_tab for tx channel */
-       auide_init_dbdma_dev(&source_dev_tab, (u32)DSCR_CMD0_ALWAYS, 8, 32,
-                            DEV_FLAGS_OUT | flags, auide->regbase);
-       auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
-
-       auide_init_dbdma_dev(&source_dev_tab, (u32)DSCR_CMD0_ALWAYS, 8, 32,
-                            DEV_FLAGS_IN | flags, auide->regbase);
-       auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
-       
-       /* Get a channel for TX */
-       auide->tx_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS,
-                                                auide->tx_dev_id,
-                                                NULL,
-                                                (void*)auide);
-       /* Get a channel for RX */
-       auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id,
-                                                DSCR_CMD0_ALWAYS,
-                                                NULL,
-                                                (void*)auide);
-       auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan,
-                                                            NUM_DESCRIPTORS);
-       auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
-                                                            NUM_DESCRIPTORS);
-       au1xxx_dbdma_start( auide->tx_chan );
-       au1xxx_dbdma_start( auide->rx_chan );
-       
-       return 0;
-}
-#endif
-
-static void auide_setup_ports(struct ide_hw *hw, _auide_hwif *ahwif)
-{
-       int i;
-       unsigned long *ata_regs = hw->io_ports_array;
-
-       /* FIXME? */
-       for (i = 0; i < 8; i++)
-               *ata_regs++ = ahwif->regbase + (i << IDE_REG_SHIFT);
-
-       /* set the Alternative Status register */
-       *ata_regs = ahwif->regbase + (14 << IDE_REG_SHIFT);
-}
-
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
-static const struct ide_tp_ops au1xxx_tp_ops = {
-       .exec_command           = ide_exec_command,
-       .read_status            = ide_read_status,
-       .read_altstatus         = ide_read_altstatus,
-       .write_devctl           = ide_write_devctl,
-
-       .dev_select             = ide_dev_select,
-       .tf_load                = ide_tf_load,
-       .tf_read                = ide_tf_read,
-
-       .input_data             = au1xxx_input_data,
-       .output_data            = au1xxx_output_data,
-};
-#endif
-
-static const struct ide_port_ops au1xxx_port_ops = {
-       .set_pio_mode           = au1xxx_set_pio_mode,
-       .set_dma_mode           = auide_set_dma_mode,
-};
-
-static const struct ide_port_info au1xxx_port_info = {
-       .init_dma               = auide_ddma_init,
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
-       .tp_ops                 = &au1xxx_tp_ops,
-#endif
-       .port_ops               = &au1xxx_port_ops,
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-       .dma_ops                = &au1xxx_dma_ops,
-#endif
-       .host_flags             = IDE_HFLAG_POST_SET_MODE |
-                                 IDE_HFLAG_NO_IO_32BIT |
-                                 IDE_HFLAG_UNMASK_IRQS,
-       .pio_mask               = ATA_PIO4,
-#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
-       .mwdma_mask             = ATA_MWDMA2,
-#endif
-       .chipset                = ide_au1xxx,
-};
-
-static int au_ide_probe(struct platform_device *dev)
-{
-       _auide_hwif *ahwif = &auide_hwif;
-       struct resource *res;
-       struct ide_host *host;
-       int ret = 0;
-       struct ide_hw hw, *hws[] = { &hw };
-
-#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
-       char *mode = "MWDMA2";
-#elif defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
-       char *mode = "PIO+DDMA(offload)";
-#endif
-
-       memset(&auide_hwif, 0, sizeof(_auide_hwif));
-       ahwif->irq = platform_get_irq(dev, 0);
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-
-       if (res == NULL) {
-               pr_debug("%s %d: no base address\n", DRV_NAME, dev->id);
-               ret = -ENODEV;
-               goto out;
-       }
-       if (ahwif->irq < 0) {
-               pr_debug("%s %d: no IRQ\n", DRV_NAME, dev->id);
-               ret = -ENODEV;
-               goto out;
-       }
-
-       if (!request_mem_region(res->start, resource_size(res), dev->name)) {
-               pr_debug("%s: request_mem_region failed\n", DRV_NAME);
-               ret =  -EBUSY;
-               goto out;
-       }
-
-       ahwif->regbase = (u32)ioremap(res->start, resource_size(res));
-       if (ahwif->regbase == 0) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       res = platform_get_resource(dev, IORESOURCE_DMA, 0);
-       if (!res) {
-               pr_debug("%s: no DDMA ID resource\n", DRV_NAME);
-               ret = -ENODEV;
-               goto out;
-       }
-       ahwif->ddma_id = res->start;
-
-       memset(&hw, 0, sizeof(hw));
-       auide_setup_ports(&hw, ahwif);
-       hw.irq = ahwif->irq;
-       hw.dev = &dev->dev;
-
-       ret = ide_host_add(&au1xxx_port_info, hws, 1, &host);
-       if (ret)
-               goto out;
-
-       auide_hwif.hwif = host->ports[0];
-
-       platform_set_drvdata(dev, host);
-
-       printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode );
-
- out:
-       return ret;
-}
-
-static int au_ide_remove(struct platform_device *dev)
-{
-       struct resource *res;
-       struct ide_host *host = platform_get_drvdata(dev);
-       _auide_hwif *ahwif = &auide_hwif;
-
-       ide_host_remove(host);
-
-       iounmap((void *)ahwif->regbase);
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
-       return 0;
-}
-
-static struct platform_driver au1200_ide_driver = {
-       .driver = {
-               .name           = "au1200-ide",
-       },
-       .probe          = au_ide_probe,
-       .remove         = au_ide_remove,
-};
-
-module_platform_driver(au1200_ide_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("AU1200 IDE driver");
index 1bb99b5..05c2698 100644 (file)
@@ -361,7 +361,7 @@ static const struct block_device_operations ide_gd_ops = {
        .release                = ide_gd_release,
        .ioctl                  = ide_gd_ioctl,
 #ifdef CONFIG_COMPAT
-       .ioctl                  = ide_gd_compat_ioctl,
+       .compat_ioctl           = ide_gd_compat_ioctl,
 #endif
        .getgeo                 = ide_gd_getgeo,
        .check_events           = ide_gd_check_events,
index d556066..f449584 100644 (file)
@@ -2,8 +2,9 @@
 /*
  * intel_idle.c - native hardware idle loop for modern Intel processors
  *
- * Copyright (c) 2013, Intel Corporation.
+ * Copyright (c) 2013 - 2020, Intel Corporation.
  * Len Brown <len.brown@intel.com>
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  */
 
 /*
 /*
  * Known limitations
  *
- * The driver currently initializes for_each_online_cpu() upon modprobe.
- * It it unaware of subsequent processors hot-added to the system.
- * This means that if you boot with maxcpus=n and later online
- * processors above n, those processors will use C1 only.
- *
  * ACPI has a .suspend hack to turn off deep c-statees during suspend
  * to avoid complications with the lapic timer workaround.
  * Have not seen issues with suspend, but may need same workaround here.
@@ -55,7 +51,7 @@
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
-#define INTEL_IDLE_VERSION "0.4.1"
+#define INTEL_IDLE_VERSION "0.5.1"
 
 static struct cpuidle_driver intel_idle_driver = {
        .name = "intel_idle",
@@ -65,11 +61,12 @@ static struct cpuidle_driver intel_idle_driver = {
 static int max_cstate = CPUIDLE_STATE_MAX - 1;
 static unsigned int disabled_states_mask;
 
-static unsigned int mwait_substates;
+static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
+
+static unsigned long auto_demotion_disable_flags;
+static bool disable_promotion_to_c1e;
 
-#define LAPIC_TIMER_ALWAYS_RELIABLE 0xFFFFFFFF
-/* Reliable LAPIC Timer States, bit 1 for C1 etc.  */
-static unsigned int lapic_timer_reliable_states = (1 << 1);     /* Default to only C1 */
+static bool lapic_timer_always_reliable;
 
 struct idle_cpu {
        struct cpuidle_state *state_table;
@@ -84,13 +81,10 @@ struct idle_cpu {
        bool use_acpi;
 };
 
-static const struct idle_cpu *icpu;
-static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
-static int intel_idle(struct cpuidle_device *dev,
-                       struct cpuidle_driver *drv, int index);
-static void intel_idle_s2idle(struct cpuidle_device *dev,
-                             struct cpuidle_driver *drv, int index);
-static struct cpuidle_state *cpuidle_state_table;
+static const struct idle_cpu *icpu __initdata;
+static struct cpuidle_state *cpuidle_state_table __initdata;
+
+static unsigned int mwait_substates __initdata;
 
 /*
  * Enable this state by default even if the ACPI _CST does not list it.
@@ -103,7 +97,7 @@ static struct cpuidle_state *cpuidle_state_table;
  * If this flag is set, SW flushes the TLB, so even if the
  * HW doesn't do the flushing, this flag is safe to use.
  */
-#define CPUIDLE_FLAG_TLB_FLUSHED       0x10000
+#define CPUIDLE_FLAG_TLB_FLUSHED       BIT(16)
 
 /*
  * MWAIT takes an 8-bit "hint" in EAX "suggesting"
@@ -115,12 +109,87 @@ static struct cpuidle_state *cpuidle_state_table;
 #define flg2MWAIT(flags) (((flags) >> 24) & 0xFF)
 #define MWAIT2flg(eax) ((eax & 0xFF) << 24)
 
+/**
+ * intel_idle - Ask the processor to enter the given idle state.
+ * @dev: cpuidle device of the target CPU.
+ * @drv: cpuidle driver (assumed to point to intel_idle_driver).
+ * @index: Target idle state index.
+ *
+ * Use the MWAIT instruction to notify the processor that the CPU represented by
+ * @dev is idle and it can try to enter the idle state corresponding to @index.
+ *
+ * If the local APIC timer is not known to be reliable in the target idle state,
+ * enable one-shot tick broadcasting for the target CPU before executing MWAIT.
+ *
+ * Optionally call leave_mm() for the target CPU upfront to avoid wakeups due to
+ * flushing user TLBs.
+ *
+ * Must be called under local_irq_disable().
+ */
+static __cpuidle int intel_idle(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv, int index)
+{
+       struct cpuidle_state *state = &drv->states[index];
+       unsigned long eax = flg2MWAIT(state->flags);
+       unsigned long ecx = 1; /* break on interrupt flag */
+       bool uninitialized_var(tick);
+       int cpu = smp_processor_id();
+
+       /*
+        * leave_mm() to avoid costly and often unnecessary wakeups
+        * for flushing the user TLB's associated with the active mm.
+        */
+       if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
+               leave_mm(cpu);
+
+       if (!static_cpu_has(X86_FEATURE_ARAT) && !lapic_timer_always_reliable) {
+               /*
+                * Switch over to one-shot tick broadcast if the target C-state
+                * is deeper than C1.
+                */
+               if ((eax >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) {
+                       tick = true;
+                       tick_broadcast_enter();
+               } else {
+                       tick = false;
+               }
+       }
+
+       mwait_idle_with_hints(eax, ecx);
+
+       if (!static_cpu_has(X86_FEATURE_ARAT) && tick)
+               tick_broadcast_exit();
+
+       return index;
+}
+
+/**
+ * intel_idle_s2idle - Ask the processor to enter the given idle state.
+ * @dev: cpuidle device of the target CPU.
+ * @drv: cpuidle driver (assumed to point to intel_idle_driver).
+ * @index: Target idle state index.
+ *
+ * Use the MWAIT instruction to notify the processor that the CPU represented by
+ * @dev is idle and it can try to enter the idle state corresponding to @index.
+ *
+ * Invoked as a suspend-to-idle callback routine with frozen user space, frozen
+ * scheduler tick and suspended scheduler clock on the target CPU.
+ */
+static __cpuidle void intel_idle_s2idle(struct cpuidle_device *dev,
+                                       struct cpuidle_driver *drv, int index)
+{
+       unsigned long eax = flg2MWAIT(drv->states[index].flags);
+       unsigned long ecx = 1; /* break on interrupt flag */
+
+       mwait_idle_with_hints(eax, ecx);
+}
+
 /*
  * States are indexed by the cstate number,
  * which is also the index into the MWAIT hint array.
  * Thus C0 is a dummy.
  */
-static struct cpuidle_state nehalem_cstates[] = {
+static struct cpuidle_state nehalem_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -157,7 +226,7 @@ static struct cpuidle_state nehalem_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state snb_cstates[] = {
+static struct cpuidle_state snb_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -202,7 +271,7 @@ static struct cpuidle_state snb_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state byt_cstates[] = {
+static struct cpuidle_state byt_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -247,7 +316,7 @@ static struct cpuidle_state byt_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state cht_cstates[] = {
+static struct cpuidle_state cht_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -292,7 +361,7 @@ static struct cpuidle_state cht_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state ivb_cstates[] = {
+static struct cpuidle_state ivb_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -337,7 +406,7 @@ static struct cpuidle_state ivb_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state ivt_cstates[] = {
+static struct cpuidle_state ivt_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -374,7 +443,7 @@ static struct cpuidle_state ivt_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state ivt_cstates_4s[] = {
+static struct cpuidle_state ivt_cstates_4s[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -411,7 +480,7 @@ static struct cpuidle_state ivt_cstates_4s[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state ivt_cstates_8s[] = {
+static struct cpuidle_state ivt_cstates_8s[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -448,7 +517,7 @@ static struct cpuidle_state ivt_cstates_8s[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state hsw_cstates[] = {
+static struct cpuidle_state hsw_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -516,7 +585,7 @@ static struct cpuidle_state hsw_cstates[] = {
        {
                .enter = NULL }
 };
-static struct cpuidle_state bdw_cstates[] = {
+static struct cpuidle_state bdw_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -585,7 +654,7 @@ static struct cpuidle_state bdw_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state skl_cstates[] = {
+static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -654,7 +723,7 @@ static struct cpuidle_state skl_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state skx_cstates[] = {
+static struct cpuidle_state skx_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -683,7 +752,7 @@ static struct cpuidle_state skx_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state atom_cstates[] = {
+static struct cpuidle_state atom_cstates[] __initdata = {
        {
                .name = "C1E",
                .desc = "MWAIT 0x00",
@@ -719,7 +788,7 @@ static struct cpuidle_state atom_cstates[] = {
        {
                .enter = NULL }
 };
-static struct cpuidle_state tangier_cstates[] = {
+static struct cpuidle_state tangier_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -763,7 +832,7 @@ static struct cpuidle_state tangier_cstates[] = {
        {
                .enter = NULL }
 };
-static struct cpuidle_state avn_cstates[] = {
+static struct cpuidle_state avn_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -783,7 +852,7 @@ static struct cpuidle_state avn_cstates[] = {
        {
                .enter = NULL }
 };
-static struct cpuidle_state knl_cstates[] = {
+static struct cpuidle_state knl_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -804,7 +873,7 @@ static struct cpuidle_state knl_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state bxt_cstates[] = {
+static struct cpuidle_state bxt_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -865,7 +934,7 @@ static struct cpuidle_state bxt_cstates[] = {
                .enter = NULL }
 };
 
-static struct cpuidle_state dnv_cstates[] = {
+static struct cpuidle_state dnv_cstates[] __initdata = {
        {
                .name = "C1",
                .desc = "MWAIT 0x00",
@@ -894,225 +963,164 @@ static struct cpuidle_state dnv_cstates[] = {
                .enter = NULL }
 };
 
-/**
- * intel_idle
- * @dev: cpuidle_device
- * @drv: cpuidle driver
- * @index: index of cpuidle state
- *
- * Must be called under local_irq_disable().
- */
-static __cpuidle int intel_idle(struct cpuidle_device *dev,
-                               struct cpuidle_driver *drv, int index)
-{
-       unsigned long ecx = 1; /* break on interrupt flag */
-       struct cpuidle_state *state = &drv->states[index];
-       unsigned long eax = flg2MWAIT(state->flags);
-       unsigned int cstate;
-       bool uninitialized_var(tick);
-       int cpu = smp_processor_id();
-
-       /*
-        * leave_mm() to avoid costly and often unnecessary wakeups
-        * for flushing the user TLB's associated with the active mm.
-        */
-       if (state->flags & CPUIDLE_FLAG_TLB_FLUSHED)
-               leave_mm(cpu);
-
-       if (!static_cpu_has(X86_FEATURE_ARAT)) {
-               cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) &
-                               MWAIT_CSTATE_MASK) + 1;
-               tick = false;
-               if (!(lapic_timer_reliable_states & (1 << (cstate)))) {
-                       tick = true;
-                       tick_broadcast_enter();
-               }
-       }
-
-       mwait_idle_with_hints(eax, ecx);
-
-       if (!static_cpu_has(X86_FEATURE_ARAT) && tick)
-               tick_broadcast_exit();
-
-       return index;
-}
-
-/**
- * intel_idle_s2idle - simplified "enter" callback routine for suspend-to-idle
- * @dev: cpuidle_device
- * @drv: cpuidle driver
- * @index: state index
- */
-static void intel_idle_s2idle(struct cpuidle_device *dev,
-                            struct cpuidle_driver *drv, int index)
-{
-       unsigned long ecx = 1; /* break on interrupt flag */
-       unsigned long eax = flg2MWAIT(drv->states[index].flags);
-
-       mwait_idle_with_hints(eax, ecx);
-}
-
-static const struct idle_cpu idle_cpu_nehalem = {
+static const struct idle_cpu idle_cpu_nehalem __initconst = {
        .state_table = nehalem_cstates,
        .auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
        .disable_promotion_to_c1e = true,
 };
 
-static const struct idle_cpu idle_cpu_nhx = {
+static const struct idle_cpu idle_cpu_nhx __initconst = {
        .state_table = nehalem_cstates,
        .auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
        .disable_promotion_to_c1e = true,
        .use_acpi = true,
 };
 
-static const struct idle_cpu idle_cpu_atom = {
+static const struct idle_cpu idle_cpu_atom __initconst = {
        .state_table = atom_cstates,
 };
 
-static const struct idle_cpu idle_cpu_tangier = {
+static const struct idle_cpu idle_cpu_tangier __initconst = {
        .state_table = tangier_cstates,
 };
 
-static const struct idle_cpu idle_cpu_lincroft = {
+static const struct idle_cpu idle_cpu_lincroft __initconst = {
        .state_table = atom_cstates,
        .auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE,
 };
 
-static const struct idle_cpu idle_cpu_snb = {
+static const struct idle_cpu idle_cpu_snb __initconst = {
        .state_table = snb_cstates,
        .disable_promotion_to_c1e = true,
 };
 
-static const struct idle_cpu idle_cpu_snx = {
+static const struct idle_cpu idle_cpu_snx __initconst = {
        .state_table = snb_cstates,
        .disable_promotion_to_c1e = true,
        .use_acpi = true,
 };
 
-static const struct idle_cpu idle_cpu_byt = {
+static const struct idle_cpu idle_cpu_byt __initconst = {
        .state_table = byt_cstates,
        .disable_promotion_to_c1e = true,
        .byt_auto_demotion_disable_flag = true,
 };
 
-static const struct idle_cpu idle_cpu_cht = {
+static const struct idle_cpu idle_cpu_cht __initconst = {
        .state_table = cht_cstates,
        .disable_promotion_to_c1e = true,
        .byt_auto_demotion_disable_flag = true,
 };
 
-static const struct idle_cpu idle_cpu_ivb = {
+static const struct idle_cpu idle_cpu_ivb __initconst = {
        .state_table = ivb_cstates,
        .disable_promotion_to_c1e = true,
 };
 
-static const struct idle_cpu idle_cpu_ivt = {
+static const struct idle_cpu idle_cpu_ivt __initconst = {
        .state_table = ivt_cstates,
        .disable_promotion_to_c1e = true,
        .use_acpi = true,
 };
 
-static const struct idle_cpu idle_cpu_hsw = {
+static const struct idle_cpu idle_cpu_hsw __initconst = {
        .state_table = hsw_cstates,
        .disable_promotion_to_c1e = true,
 };
 
-static const struct idle_cpu idle_cpu_hsx = {
+static const struct idle_cpu idle_cpu_hsx __initconst = {
        .state_table = hsw_cstates,
        .disable_promotion_to_c1e = true,
        .use_acpi = true,
 };
 
-static const struct idle_cpu idle_cpu_bdw = {
+static const struct idle_cpu idle_cpu_bdw __initconst = {
        .state_table = bdw_cstates,
        .disable_promotion_to_c1e = true,
 };
 
-static const struct idle_cpu idle_cpu_bdx = {
+static const struct idle_cpu idle_cpu_bdx __initconst = {
        .state_table = bdw_cstates,
        .disable_promotion_to_c1e = true,
        .use_acpi = true,
 };
 
-static const struct idle_cpu idle_cpu_skl = {
+static const struct idle_cpu idle_cpu_skl __initconst = {
        .state_table = skl_cstates,
        .disable_promotion_to_c1e = true,
 };
 
-static const struct idle_cpu idle_cpu_skx = {
+static const struct idle_cpu idle_cpu_skx __initconst = {
        .state_table = skx_cstates,
        .disable_promotion_to_c1e = true,
        .use_acpi = true,
 };
 
-static const struct idle_cpu idle_cpu_avn = {
+static const struct idle_cpu idle_cpu_avn __initconst = {
        .state_table = avn_cstates,
        .disable_promotion_to_c1e = true,
        .use_acpi = true,
 };
 
-static const struct idle_cpu idle_cpu_knl = {
+static const struct idle_cpu idle_cpu_knl __initconst = {
        .state_table = knl_cstates,
        .use_acpi = true,
 };
 
-static const struct idle_cpu idle_cpu_bxt = {
+static const struct idle_cpu idle_cpu_bxt __initconst = {
        .state_table = bxt_cstates,
        .disable_promotion_to_c1e = true,
 };
 
-static const struct idle_cpu idle_cpu_dnv = {
+static const struct idle_cpu idle_cpu_dnv __initconst = {
        .state_table = dnv_cstates,
        .disable_promotion_to_c1e = true,
        .use_acpi = true,
 };
 
 static const struct x86_cpu_id intel_idle_ids[] __initconst = {
-       INTEL_CPU_FAM6(NEHALEM_EP,              idle_cpu_nhx),
-       INTEL_CPU_FAM6(NEHALEM,                 idle_cpu_nehalem),
-       INTEL_CPU_FAM6(NEHALEM_G,               idle_cpu_nehalem),
-       INTEL_CPU_FAM6(WESTMERE,                idle_cpu_nehalem),
-       INTEL_CPU_FAM6(WESTMERE_EP,             idle_cpu_nhx),
-       INTEL_CPU_FAM6(NEHALEM_EX,              idle_cpu_nhx),
-       INTEL_CPU_FAM6(ATOM_BONNELL,            idle_cpu_atom),
-       INTEL_CPU_FAM6(ATOM_BONNELL_MID,        idle_cpu_lincroft),
-       INTEL_CPU_FAM6(WESTMERE_EX,             idle_cpu_nhx),
-       INTEL_CPU_FAM6(SANDYBRIDGE,             idle_cpu_snb),
-       INTEL_CPU_FAM6(SANDYBRIDGE_X,           idle_cpu_snx),
-       INTEL_CPU_FAM6(ATOM_SALTWELL,           idle_cpu_atom),
-       INTEL_CPU_FAM6(ATOM_SILVERMONT,         idle_cpu_byt),
-       INTEL_CPU_FAM6(ATOM_SILVERMONT_MID,     idle_cpu_tangier),
-       INTEL_CPU_FAM6(ATOM_AIRMONT,            idle_cpu_cht),
-       INTEL_CPU_FAM6(IVYBRIDGE,               idle_cpu_ivb),
-       INTEL_CPU_FAM6(IVYBRIDGE_X,             idle_cpu_ivt),
-       INTEL_CPU_FAM6(HASWELL,                 idle_cpu_hsw),
-       INTEL_CPU_FAM6(HASWELL_X,               idle_cpu_hsx),
-       INTEL_CPU_FAM6(HASWELL_L,               idle_cpu_hsw),
-       INTEL_CPU_FAM6(HASWELL_G,               idle_cpu_hsw),
-       INTEL_CPU_FAM6(ATOM_SILVERMONT_D,       idle_cpu_avn),
-       INTEL_CPU_FAM6(BROADWELL,               idle_cpu_bdw),
-       INTEL_CPU_FAM6(BROADWELL_G,             idle_cpu_bdw),
-       INTEL_CPU_FAM6(BROADWELL_X,             idle_cpu_bdx),
-       INTEL_CPU_FAM6(BROADWELL_D,             idle_cpu_bdx),
-       INTEL_CPU_FAM6(SKYLAKE_L,               idle_cpu_skl),
-       INTEL_CPU_FAM6(SKYLAKE,                 idle_cpu_skl),
-       INTEL_CPU_FAM6(KABYLAKE_L,              idle_cpu_skl),
-       INTEL_CPU_FAM6(KABYLAKE,                idle_cpu_skl),
-       INTEL_CPU_FAM6(SKYLAKE_X,               idle_cpu_skx),
-       INTEL_CPU_FAM6(XEON_PHI_KNL,            idle_cpu_knl),
-       INTEL_CPU_FAM6(XEON_PHI_KNM,            idle_cpu_knl),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT,           idle_cpu_bxt),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS,      idle_cpu_bxt),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT_D,         idle_cpu_dnv),
-       INTEL_CPU_FAM6(ATOM_TREMONT_D,          idle_cpu_dnv),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EP,          &idle_cpu_nhx),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM,             &idle_cpu_nehalem),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_G,           &idle_cpu_nehalem),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE,            &idle_cpu_nehalem),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EP,         &idle_cpu_nhx),
+       X86_MATCH_INTEL_FAM6_MODEL(NEHALEM_EX,          &idle_cpu_nhx),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_BONNELL,        &idle_cpu_atom),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_BONNELL_MID,    &idle_cpu_lincroft),
+       X86_MATCH_INTEL_FAM6_MODEL(WESTMERE_EX,         &idle_cpu_nhx),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE,         &idle_cpu_snb),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X,       &idle_cpu_snx),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL,       &idle_cpu_atom),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,     &idle_cpu_byt),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &idle_cpu_tangier),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        &idle_cpu_cht),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE,           &idle_cpu_ivb),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,         &idle_cpu_ivt),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL,             &idle_cpu_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,           &idle_cpu_hsx),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L,           &idle_cpu_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G,           &idle_cpu_hsw),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D,   &idle_cpu_avn),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL,           &idle_cpu_bdw),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G,         &idle_cpu_bdw),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,         &idle_cpu_bdx),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,         &idle_cpu_bdx),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,           &idle_cpu_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,             &idle_cpu_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,          &idle_cpu_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,            &idle_cpu_skl),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,           &idle_cpu_skx),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,        &idle_cpu_knl),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,        &idle_cpu_knl),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,       &idle_cpu_bxt),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS,  &idle_cpu_bxt),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D,     &idle_cpu_dnv),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,      &idle_cpu_dnv),
        {}
 };
 
-#define INTEL_CPU_FAM6_MWAIT \
-       { X86_VENDOR_INTEL, 6, X86_MODEL_ANY, X86_FEATURE_MWAIT, 0 }
-
 static const struct x86_cpu_id intel_mwait_ids[] __initconst = {
-       INTEL_CPU_FAM6_MWAIT,
+       X86_MATCH_VENDOR_FAM_FEATURE(INTEL, 6, X86_FEATURE_MWAIT, NULL),
        {}
 };
 
@@ -1273,11 +1281,11 @@ static inline void intel_idle_init_cstates_acpi(struct cpuidle_driver *drv) { }
 static inline bool intel_idle_off_by_default(u32 mwait_hint) { return false; }
 #endif /* !CONFIG_ACPI_PROCESSOR_CSTATE */
 
-/*
- * ivt_idle_state_table_update(void)
+/**
+ * ivt_idle_state_table_update - Tune the idle states table for Ivy Town.
  *
- * Tune IVT multi-socket targets
- * Assumption: num_sockets == (max_package_num + 1)
+ * Tune IVT multi-socket targets.
+ * Assumption: num_sockets == (max_package_num + 1).
  */
 static void __init ivt_idle_state_table_update(void)
 {
@@ -1323,11 +1331,11 @@ static unsigned long long __init irtl_2_usec(unsigned long long irtl)
        return div_u64((irtl & 0x3FF) * ns, NSEC_PER_USEC);
 }
 
-/*
- * bxt_idle_state_table_update(void)
+/**
+ * bxt_idle_state_table_update - Fix up the Broxton idle states table.
  *
- * On BXT, we trust the IRTL to show the definitive maximum latency
- * We use the same value for target_residency.
+ * On BXT, trust the IRTL (Interrupt Response Time Limit) MSR to show the
+ * definitive maximum latency and use the same value for target_residency.
  */
 static void __init bxt_idle_state_table_update(void)
 {
@@ -1370,11 +1378,11 @@ static void __init bxt_idle_state_table_update(void)
        }
 
 }
-/*
- * sklh_idle_state_table_update(void)
+
+/**
+ * sklh_idle_state_table_update - Fix up the Sky Lake idle states table.
  *
- * On SKL-H (model 0x5e) disable C8 and C9 if:
- * C10 is enabled and SGX disabled
+ * On SKL-H (model 0x5e) skip C8 and C9 if C10 is enabled and SGX disabled.
  */
 static void __init sklh_idle_state_table_update(void)
 {
@@ -1485,9 +1493,9 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
        }
 }
 
-/*
- * intel_idle_cpuidle_driver_init()
- * allocate, initialize cpuidle_states
+/**
+ * intel_idle_cpuidle_driver_init - Create the list of available idle states.
+ * @drv: cpuidle driver structure to initialize.
  */
 static void __init intel_idle_cpuidle_driver_init(struct cpuidle_driver *drv)
 {
@@ -1509,7 +1517,7 @@ static void auto_demotion_disable(void)
        unsigned long long msr_bits;
 
        rdmsrl(MSR_PKG_CST_CONFIG_CONTROL, msr_bits);
-       msr_bits &= ~(icpu->auto_demotion_disable_flags);
+       msr_bits &= ~auto_demotion_disable_flags;
        wrmsrl(MSR_PKG_CST_CONFIG_CONTROL, msr_bits);
 }
 
@@ -1522,10 +1530,12 @@ static void c1e_promotion_disable(void)
        wrmsrl(MSR_IA32_POWER_CTL, msr_bits);
 }
 
-/*
- * intel_idle_cpu_init()
- * allocate, initialize, register cpuidle_devices
- * @cpu: cpu/core to initialize
+/**
+ * intel_idle_cpu_init - Register the target CPU with the cpuidle core.
+ * @cpu: CPU to initialize.
+ *
+ * Register a cpuidle device object for @cpu and update its MSRs in accordance
+ * with the processor model flags.
  */
 static int intel_idle_cpu_init(unsigned int cpu)
 {
@@ -1539,13 +1549,10 @@ static int intel_idle_cpu_init(unsigned int cpu)
                return -EIO;
        }
 
-       if (!icpu)
-               return 0;
-
-       if (icpu->auto_demotion_disable_flags)
+       if (auto_demotion_disable_flags)
                auto_demotion_disable();
 
-       if (icpu->disable_promotion_to_c1e)
+       if (disable_promotion_to_c1e)
                c1e_promotion_disable();
 
        return 0;
@@ -1555,7 +1562,7 @@ static int intel_idle_cpu_online(unsigned int cpu)
 {
        struct cpuidle_device *dev;
 
-       if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
+       if (!lapic_timer_always_reliable)
                tick_broadcast_enable();
 
        /*
@@ -1623,6 +1630,8 @@ static int __init intel_idle_init(void)
        icpu = (const struct idle_cpu *)id->driver_data;
        if (icpu) {
                cpuidle_state_table = icpu->state_table;
+               auto_demotion_disable_flags = icpu->auto_demotion_disable_flags;
+               disable_promotion_to_c1e = icpu->disable_promotion_to_c1e;
                if (icpu->use_acpi || force_use_acpi)
                        intel_idle_acpi_cst_extract();
        } else if (!intel_idle_acpi_cst_extract()) {
@@ -1647,15 +1656,15 @@ static int __init intel_idle_init(void)
        }
 
        if (boot_cpu_has(X86_FEATURE_ARAT))     /* Always Reliable APIC Timer */
-               lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
+               lapic_timer_always_reliable = true;
 
        retval = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "idle/intel:online",
                                   intel_idle_cpu_online, NULL);
        if (retval < 0)
                goto hp_setup_fail;
 
-       pr_debug("lapic_timer_reliable_states 0x%x\n",
-                lapic_timer_reliable_states);
+       pr_debug("Local APIC timer is reliable in %s\n",
+                lapic_timer_always_reliable ? "all C-states" : "C1");
 
        return 0;
 
diff --git a/drivers/iio/TODO b/drivers/iio/TODO
new file mode 100644 (file)
index 0000000..7d7326b
--- /dev/null
@@ -0,0 +1,19 @@
+2020-02-29
+
+Documentation
+  - Binding docs for devices that are obviously used via device
+tree
+  - Yaml conversions for abandoned drivers
+  - ABI Documentation
+  - Audit driviers/iio/staging/Documentation
+
+- Replace iio_dev->mlock by either a local lock or use
+iio_claim_direct.(Requires analysis of the purpose of the lock.)
+
+- Converting drivers from device tree centric to more generic
+property handlers.
+
+- Refactor old platform_data constructs from drivers and convert it
+to state struct and using property handlers and readers.
+
+Mailing list: linux-iio@vger.kernel.org
index 0f0f27a..4154e73 100644 (file)
@@ -246,6 +246,7 @@ static const struct adis_data adis16201_data = {
        .diag_stat_reg = ADIS16201_DIAG_STAT_REG,
 
        .self_test_mask = ADIS16201_MSC_CTRL_SELF_TEST_EN,
+       .self_test_reg = ADIS16201_MSC_CTRL_REG,
        .self_test_no_autoclear = true,
        .timeouts = &adis16201_timeouts,
 
index c6dbd24..31d45e7 100644 (file)
@@ -256,6 +256,7 @@ static const struct adis_data adis16209_data = {
        .diag_stat_reg = ADIS16209_STAT_REG,
 
        .self_test_mask = ADIS16209_MSC_CTRL_SELF_TEST_EN,
+       .self_test_reg = ADIS16209_MSC_CTRL_REG,
        .self_test_no_autoclear = true,
        .timeouts = &adis16209_timeouts,
 
index 67b8817..60daf04 100644 (file)
@@ -237,6 +237,7 @@ static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = {
                .realbits = 12,                                         \
                .storagebits = 16,                                      \
                .shift = 4,                                             \
+               .endianness = IIO_BE,                                   \
        },                                                              \
 }
 
index 633955d..6b283be 100644 (file)
@@ -110,7 +110,7 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match);
 
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id st_accel_acpi_match[] = {
-       {"SMO8840", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
+       {"SMO8840", (kernel_ulong_t)LIS2DH12_ACCEL_DEV_NAME},
        {"SMO8A90", (kernel_ulong_t)LNG2DM_ACCEL_DEV_NAME},
        { },
 };
@@ -147,12 +147,9 @@ static int st_accel_i2c_probe(struct i2c_client *client)
        const struct st_sensor_settings *settings;
        struct st_sensor_data *adata;
        struct iio_dev *indio_dev;
-       const char *match;
        int ret;
 
-       match = device_get_match_data(&client->dev);
-       if (match)
-               strlcpy(client->name, match, sizeof(client->name));
+       st_sensors_dev_name_probe(&client->dev, client->name, sizeof(client->name));
 
        settings = st_accel_get_settings(client->name);
        if (!settings) {
index 82e3308..f4da821 100644 (file)
@@ -39,6 +39,18 @@ config AD7124
          To compile this driver as a module, choose M here: the module will be
          called ad7124.
 
+config AD7192
+       tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver"
+       depends on SPI
+       select AD_SIGMA_DELTA
+       help
+         Say yes here to build support for Analog Devices AD7190,
+         AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC).
+         If unsure, say N (but it's safe to say "Y").
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad7192.
+
 config AD7266
        tristate "Analog Devices AD7265/AD7266 ADC driver"
        depends on SPI_MASTER
index 9192289..8462455 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
 obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
 obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o
 obj-$(CONFIG_AD7124) += ad7124.o
+obj-$(CONFIG_AD7192) += ad7192.o
 obj-$(CONFIG_AD7266) += ad7266.o
 obj-$(CONFIG_AD7291) += ad7291.o
 obj-$(CONFIG_AD7292) += ad7292.o
index d9915dc..a3c0647 100644 (file)
 /* AD7124_FILTER_X */
 #define AD7124_FILTER_FS_MSK           GENMASK(10, 0)
 #define AD7124_FILTER_FS(x)            FIELD_PREP(AD7124_FILTER_FS_MSK, x)
+#define AD7124_FILTER_TYPE_MSK         GENMASK(23, 21)
+#define AD7124_FILTER_TYPE_SEL(x)      FIELD_PREP(AD7124_FILTER_TYPE_MSK, x)
+
+#define AD7124_SINC3_FILTER 2
+#define AD7124_SINC4_FILTER 0
 
 enum ad7124_ids {
        ID_AD7124_4,
@@ -93,6 +98,14 @@ static const unsigned int ad7124_gain[8] = {
        1, 2, 4, 8, 16, 32, 64, 128
 };
 
+static const unsigned int ad7124_reg_size[] = {
+       1, 2, 3, 3, 2, 1, 3, 3, 1, 2, 2, 2, 2,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       3, 3, 3, 3, 3
+};
+
 static const int ad7124_master_clk_freq_hz[3] = {
        [AD7124_LOW_POWER] = 76800,
        [AD7124_MID_POWER] = 153600,
@@ -119,6 +132,7 @@ struct ad7124_channel_config {
        unsigned int vref_mv;
        unsigned int pga_bits;
        unsigned int odr;
+       unsigned int filter_type;
 };
 
 struct ad7124_state {
@@ -138,7 +152,8 @@ static const struct iio_chan_spec ad7124_channel_template = {
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                BIT(IIO_CHAN_INFO_SCALE) |
                BIT(IIO_CHAN_INFO_OFFSET) |
-               BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+               BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
        .scan_type = {
                .sign = 'u',
                .realbits = 24,
@@ -281,6 +296,58 @@ static int ad7124_set_channel_gain(struct ad7124_state *st,
        return 0;
 }
 
+static int ad7124_get_3db_filter_freq(struct ad7124_state *st,
+                                     unsigned int channel)
+{
+       unsigned int fadc;
+
+       fadc = st->channel_config[channel].odr;
+
+       switch (st->channel_config[channel].filter_type) {
+       case AD7124_SINC3_FILTER:
+               return DIV_ROUND_CLOSEST(fadc * 230, 1000);
+       case AD7124_SINC4_FILTER:
+               return DIV_ROUND_CLOSEST(fadc * 262, 1000);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad7124_set_3db_filter_freq(struct ad7124_state *st,
+                                     unsigned int channel,
+                                     unsigned int freq)
+{
+       unsigned int sinc4_3db_odr;
+       unsigned int sinc3_3db_odr;
+       unsigned int new_filter;
+       unsigned int new_odr;
+
+       sinc4_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 230);
+       sinc3_3db_odr = DIV_ROUND_CLOSEST(freq * 1000, 262);
+
+       if (sinc4_3db_odr > sinc3_3db_odr) {
+               new_filter = AD7124_SINC3_FILTER;
+               new_odr = sinc4_3db_odr;
+       } else {
+               new_filter = AD7124_SINC4_FILTER;
+               new_odr = sinc3_3db_odr;
+       }
+
+       if (st->channel_config[channel].filter_type != new_filter) {
+               int ret;
+
+               st->channel_config[channel].filter_type = new_filter;
+               ret = ad7124_spi_write_mask(st, AD7124_FILTER(channel),
+                                           AD7124_FILTER_TYPE_MSK,
+                                           AD7124_FILTER_TYPE_SEL(new_filter),
+                                           3);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ad7124_set_channel_odr(st, channel, new_odr);
+}
+
 static int ad7124_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val, int *val2, long info)
@@ -323,6 +390,9 @@ static int ad7124_read_raw(struct iio_dev *indio_dev,
                *val = st->channel_config[chan->address].odr;
 
                return IIO_VAL_INT;
+       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+               *val = ad7124_get_3db_filter_freq(st, chan->scan_index);
+               return IIO_VAL_INT;
        default:
                return -EINVAL;
        }
@@ -355,11 +425,37 @@ static int ad7124_write_raw(struct iio_dev *indio_dev,
                gain = DIV_ROUND_CLOSEST(res, val2);
 
                return ad7124_set_channel_gain(st, chan->address, gain);
+       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+               if (val2 != 0)
+                       return -EINVAL;
+
+               return ad7124_set_3db_filter_freq(st, chan->address, val);
        default:
                return -EINVAL;
        }
 }
 
+static int ad7124_reg_access(struct iio_dev *indio_dev,
+                            unsigned int reg,
+                            unsigned int writeval,
+                            unsigned int *readval)
+{
+       struct ad7124_state *st = iio_priv(indio_dev);
+       int ret;
+
+       if (reg >= ARRAY_SIZE(ad7124_reg_size))
+               return -EINVAL;
+
+       if (readval)
+               ret = ad_sd_read_reg(&st->sd, reg, ad7124_reg_size[reg],
+                                    readval);
+       else
+               ret = ad_sd_write_reg(&st->sd, reg, ad7124_reg_size[reg],
+                                     writeval);
+
+       return ret;
+}
+
 static IIO_CONST_ATTR(in_voltage_scale_available,
        "0.000001164 0.000002328 0.000004656 0.000009313 0.000018626 0.000037252 0.000074505 0.000149011 0.000298023");
 
@@ -375,6 +471,7 @@ static const struct attribute_group ad7124_attrs_group = {
 static const struct iio_info ad7124_info = {
        .read_raw = ad7124_read_raw,
        .write_raw = ad7124_write_raw,
+       .debugfs_reg_access = &ad7124_reg_access,
        .validate_trigger = ad_sd_validate_trigger,
        .attrs = &ad7124_attrs_group,
 };
similarity index 89%
rename from drivers/staging/iio/adc/ad7192.c
rename to drivers/iio/adc/ad7192.c
index bf3e2a9..02981f3 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
+#include <linux/of_device.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
  */
 
 enum {
-   AD7192_SYSCALIB_ZERO_SCALE,
-   AD7192_SYSCALIB_FULL_SCALE,
+       AD7192_SYSCALIB_ZERO_SCALE,
+       AD7192_SYSCALIB_FULL_SCALE,
 };
 
 struct ad7192_state {
@@ -786,76 +787,105 @@ static const struct iio_info ad7195_info = {
        .validate_trigger = ad_sd_validate_trigger,
 };
 
+#define __AD719x_CHANNEL(_si, _channel1, _channel2, _address, _extend_name, \
+       _type, _mask_type_av, _ext_info) \
+       { \
+               .type = (_type), \
+               .differential = ((_channel2) == -1 ? 0 : 1), \
+               .indexed = 1, \
+               .channel = (_channel1), \
+               .channel2 = (_channel2), \
+               .address = (_address), \
+               .extend_name = (_extend_name), \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+                       BIT(IIO_CHAN_INFO_OFFSET), \
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+                       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
+               .info_mask_shared_by_type_available = (_mask_type_av), \
+               .ext_info = (_ext_info), \
+               .scan_index = (_si), \
+               .scan_type = { \
+                       .sign = 'u', \
+                       .realbits = 24, \
+                       .storagebits = 32, \
+                       .endianness = IIO_BE, \
+               }, \
+       }
+
+#define AD719x_DIFF_CHANNEL(_si, _channel1, _channel2, _address) \
+       __AD719x_CHANNEL(_si, _channel1, _channel2, _address, NULL, \
+               IIO_VOLTAGE, BIT(IIO_CHAN_INFO_SCALE), \
+               ad7192_calibsys_ext_info)
+
+#define AD719x_CHANNEL(_si, _channel1, _address) \
+       __AD719x_CHANNEL(_si, _channel1, -1, _address, NULL, IIO_VOLTAGE, \
+               BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info)
+
+#define AD719x_SHORTED_CHANNEL(_si, _channel1, _address) \
+       __AD719x_CHANNEL(_si, _channel1, -1, _address, "shorted", IIO_VOLTAGE, \
+               BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info)
+
+#define AD719x_TEMP_CHANNEL(_si, _address) \
+       __AD719x_CHANNEL(_si, 0, -1, _address, NULL, IIO_TEMP, 0, NULL)
+
 static const struct iio_chan_spec ad7192_channels[] = {
-       AD_SD_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M, 24, 32, 0),
-       AD_SD_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M, 24, 32, 0),
-       AD_SD_TEMP_CHANNEL(2, AD7192_CH_TEMP, 24, 32, 0),
-       AD_SD_SHORTED_CHANNEL(3, 2, AD7192_CH_AIN2P_AIN2M, 24, 32, 0),
-       AD_SD_CHANNEL(4, 1, AD7192_CH_AIN1, 24, 32, 0),
-       AD_SD_CHANNEL(5, 2, AD7192_CH_AIN2, 24, 32, 0),
-       AD_SD_CHANNEL(6, 3, AD7192_CH_AIN3, 24, 32, 0),
-       AD_SD_CHANNEL(7, 4, AD7192_CH_AIN4, 24, 32, 0),
+       AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M),
+       AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M),
+       AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP),
+       AD719x_SHORTED_CHANNEL(3, 2, AD7192_CH_AIN2P_AIN2M),
+       AD719x_CHANNEL(4, 1, AD7192_CH_AIN1),
+       AD719x_CHANNEL(5, 2, AD7192_CH_AIN2),
+       AD719x_CHANNEL(6, 3, AD7192_CH_AIN3),
+       AD719x_CHANNEL(7, 4, AD7192_CH_AIN4),
        IIO_CHAN_SOFT_TIMESTAMP(8),
 };
 
 static const struct iio_chan_spec ad7193_channels[] = {
-       AD_SD_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M, 24, 32, 0),
-       AD_SD_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M, 24, 32, 0),
-       AD_SD_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M, 24, 32, 0),
-       AD_SD_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M, 24, 32, 0),
-       AD_SD_TEMP_CHANNEL(4, AD7193_CH_TEMP, 24, 32, 0),
-       AD_SD_SHORTED_CHANNEL(5, 2, AD7193_CH_AIN2P_AIN2M, 24, 32, 0),
-       AD_SD_CHANNEL(6, 1, AD7193_CH_AIN1, 24, 32, 0),
-       AD_SD_CHANNEL(7, 2, AD7193_CH_AIN2, 24, 32, 0),
-       AD_SD_CHANNEL(8, 3, AD7193_CH_AIN3, 24, 32, 0),
-       AD_SD_CHANNEL(9, 4, AD7193_CH_AIN4, 24, 32, 0),
-       AD_SD_CHANNEL(10, 5, AD7193_CH_AIN5, 24, 32, 0),
-       AD_SD_CHANNEL(11, 6, AD7193_CH_AIN6, 24, 32, 0),
-       AD_SD_CHANNEL(12, 7, AD7193_CH_AIN7, 24, 32, 0),
-       AD_SD_CHANNEL(13, 8, AD7193_CH_AIN8, 24, 32, 0),
+       AD719x_DIFF_CHANNEL(0, 1, 2, AD7193_CH_AIN1P_AIN2M),
+       AD719x_DIFF_CHANNEL(1, 3, 4, AD7193_CH_AIN3P_AIN4M),
+       AD719x_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M),
+       AD719x_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M),
+       AD719x_TEMP_CHANNEL(4, AD7193_CH_TEMP),
+       AD719x_SHORTED_CHANNEL(5, 2, AD7193_CH_AIN2P_AIN2M),
+       AD719x_CHANNEL(6, 1, AD7193_CH_AIN1),
+       AD719x_CHANNEL(7, 2, AD7193_CH_AIN2),
+       AD719x_CHANNEL(8, 3, AD7193_CH_AIN3),
+       AD719x_CHANNEL(9, 4, AD7193_CH_AIN4),
+       AD719x_CHANNEL(10, 5, AD7193_CH_AIN5),
+       AD719x_CHANNEL(11, 6, AD7193_CH_AIN6),
+       AD719x_CHANNEL(12, 7, AD7193_CH_AIN7),
+       AD719x_CHANNEL(13, 8, AD7193_CH_AIN8),
        IIO_CHAN_SOFT_TIMESTAMP(14),
 };
 
 static int ad7192_channels_config(struct iio_dev *indio_dev)
 {
        struct ad7192_state *st = iio_priv(indio_dev);
-       const struct iio_chan_spec *channels;
-       struct iio_chan_spec *chan;
-       int i;
 
        switch (st->devid) {
        case ID_AD7193:
-               channels = ad7193_channels;
+               indio_dev->channels = ad7193_channels;
                indio_dev->num_channels = ARRAY_SIZE(ad7193_channels);
                break;
        default:
-               channels = ad7192_channels;
+               indio_dev->channels = ad7192_channels;
                indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
                break;
        }
 
-       chan = devm_kcalloc(indio_dev->dev.parent, indio_dev->num_channels,
-                           sizeof(*chan), GFP_KERNEL);
-       if (!chan)
-               return -ENOMEM;
-
-       indio_dev->channels = chan;
-
-       for (i = 0; i < indio_dev->num_channels; i++) {
-               *chan = channels[i];
-               chan->info_mask_shared_by_all |=
-                       BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY);
-               if (chan->type != IIO_TEMP) {
-                       chan->info_mask_shared_by_type_available |=
-                               BIT(IIO_CHAN_INFO_SCALE);
-                       chan->ext_info = ad7192_calibsys_ext_info;
-               }
-               chan++;
-       }
-
        return 0;
 }
 
+static const struct of_device_id ad7192_of_match[] = {
+       { .compatible = "adi,ad7190", .data = (void *)ID_AD7190 },
+       { .compatible = "adi,ad7192", .data = (void *)ID_AD7192 },
+       { .compatible = "adi,ad7193", .data = (void *)ID_AD7193 },
+       { .compatible = "adi,ad7195", .data = (void *)ID_AD7195 },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ad7192_of_match);
+
 static int ad7192_probe(struct spi_device *spi)
 {
        struct ad7192_state *st;
@@ -899,13 +929,16 @@ static int ad7192_probe(struct spi_device *spi)
 
        voltage_uv = regulator_get_voltage(st->avdd);
 
-       if (voltage_uv)
+       if (voltage_uv > 0) {
                st->int_vref_mv = voltage_uv / 1000;
-       else
+       } else {
+               ret = voltage_uv;
                dev_err(&spi->dev, "Device tree error, reference voltage undefined\n");
+               goto error_disable_avdd;
+       }
 
        spi_set_drvdata(spi, indio_dev);
-       st->devid = spi_get_device_id(spi)->driver_data;
+       st->devid = (unsigned long)of_device_get_match_data(&spi->dev);
        indio_dev->dev.parent = &spi->dev;
        indio_dev->name = spi_get_device_id(spi)->name;
        indio_dev->modes = INDIO_DIRECT_MODE;
@@ -986,26 +1019,6 @@ static int ad7192_remove(struct spi_device *spi)
        return 0;
 }
 
-static const struct spi_device_id ad7192_id[] = {
-       {"ad7190", ID_AD7190},
-       {"ad7192", ID_AD7192},
-       {"ad7193", ID_AD7193},
-       {"ad7195", ID_AD7195},
-       {}
-};
-
-MODULE_DEVICE_TABLE(spi, ad7192_id);
-
-static const struct of_device_id ad7192_of_match[] = {
-       { .compatible = "adi,ad7190" },
-       { .compatible = "adi,ad7192" },
-       { .compatible = "adi,ad7193" },
-       { .compatible = "adi,ad7195" },
-       {}
-};
-
-MODULE_DEVICE_TABLE(of, ad7192_of_match);
-
 static struct spi_driver ad7192_driver = {
        .driver = {
                .name   = "ad7192",
@@ -1013,7 +1026,6 @@ static struct spi_driver ad7192_driver = {
        },
        .probe          = ad7192_probe,
        .remove         = ad7192_remove,
-       .id_table       = ad7192_id,
 };
 module_spi_driver(ad7192_driver);
 
index a6798f7..6595fd1 100644 (file)
@@ -122,7 +122,10 @@ static int ad7292_single_conversion(struct ad7292_state *st,
                {
                        .tx_buf = &st->d8,
                        .len = 4,
-                       .delay_usecs = 6,
+                       .delay = {
+                               .value = 6,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
                }, {
                        .rx_buf = &st->d16,
                        .len = 2,
index a5c7771..9d96f7d 100644 (file)
@@ -723,6 +723,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
 
        for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
                struct iio_chan_spec const *chan = at91_adc_chan_get(indio, bit);
+               u32 cor;
 
                if (!chan)
                        continue;
@@ -732,6 +733,20 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
                        continue;
 
                if (state) {
+                       cor = at91_adc_readl(st, AT91_SAMA5D2_COR);
+
+                       if (chan->differential)
+                               cor |= (BIT(chan->channel) |
+                                       BIT(chan->channel2)) <<
+                                       AT91_SAMA5D2_COR_DIFF_OFFSET;
+                       else
+                               cor &= ~(BIT(chan->channel) <<
+                                      AT91_SAMA5D2_COR_DIFF_OFFSET);
+
+                       at91_adc_writel(st, AT91_SAMA5D2_COR, cor);
+               }
+
+               if (state) {
                        at91_adc_writel(st, AT91_SAMA5D2_CHER,
                                        BIT(chan->channel));
                        /* enable irq only if not using DMA */
index 2df7d05..22131a6 100644 (file)
@@ -836,8 +836,10 @@ static int exynos_adc_probe(struct platform_device *pdev)
 
        info->vdd = devm_regulator_get(&pdev->dev, "vdd");
        if (IS_ERR(info->vdd)) {
-               dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
-                                                       PTR_ERR(info->vdd));
+               if (PTR_ERR(info->vdd) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                               "failed getting regulator, err = %ld\n",
+                               PTR_ERR(info->vdd));
                return PTR_ERR(info->vdd);
        }
 
index 3b6f3b9..0c5d7aa 100644 (file)
@@ -71,7 +71,10 @@ static int max1118_read(struct spi_device *spi, int channel)
                 */
                {
                        .len = 0,
-                       .delay_usecs = 1,       /* > CNVST Low Time 100 ns */
+                       .delay = {      /* > CNVST Low Time 100 ns */
+                               .value = 1,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
                        .cs_change = 1,
                },
                /*
@@ -81,7 +84,10 @@ static int max1118_read(struct spi_device *spi, int channel)
                 */
                {
                        .len = 0,
-                       .delay_usecs = 8,
+                       .delay = {
+                               .value = 8,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
                },
                {
                        .rx_buf = &adc->data,
index 465c762..2c0eb5d 100644 (file)
@@ -421,7 +421,8 @@ static int mcp320x_probe(struct spi_device *spi)
                        adc->transfer[1].len++;
 
                /* conversions are started by asserting CS pin for 8 usec */
-               adc->start_conv_transfer.delay_usecs = 8;
+               adc->start_conv_transfer.delay.value = 8;
+               adc->start_conv_transfer.delay.unit = SPI_DELAY_UNIT_USECS;
                spi_message_init_with_transfers(&adc->start_conv_msg,
                                                &adc->start_conv_transfer, 1);
 
index a6170a3..83bad2d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
+#include <linux/reset.h>
 
 struct npcm_adc {
        bool int_status;
@@ -23,13 +24,9 @@ struct npcm_adc {
        struct clk *adc_clk;
        wait_queue_head_t wq;
        struct regulator *vref;
-       struct regmap *rst_regmap;
+       struct reset_control *reset;
 };
 
-/* NPCM7xx reset module */
-#define NPCM7XX_IPSRST1_OFFSET         0x020
-#define NPCM7XX_IPSRST1_ADC_RST                BIT(27)
-
 /* ADC registers */
 #define NPCM_ADCCON     0x00
 #define NPCM_ADCDATA    0x04
@@ -106,13 +103,11 @@ static int npcm_adc_read(struct npcm_adc *info, int *val, u8 channel)
                                               msecs_to_jiffies(10));
        if (ret == 0) {
                regtemp = ioread32(info->regs + NPCM_ADCCON);
-               if ((regtemp & NPCM_ADCCON_ADC_CONV) && info->rst_regmap) {
+               if (regtemp & NPCM_ADCCON_ADC_CONV) {
                        /* if conversion failed - reset ADC module */
-                       regmap_write(info->rst_regmap, NPCM7XX_IPSRST1_OFFSET,
-                                    NPCM7XX_IPSRST1_ADC_RST);
+                       reset_control_assert(info->reset);
                        msleep(100);
-                       regmap_write(info->rst_regmap, NPCM7XX_IPSRST1_OFFSET,
-                                    0x0);
+                       reset_control_deassert(info->reset);
                        msleep(100);
 
                        /* Enable ADC and start conversion module */
@@ -186,7 +181,6 @@ static int npcm_adc_probe(struct platform_device *pdev)
        struct npcm_adc *info;
        struct iio_dev *indio_dev;
        struct device *dev = &pdev->dev;
-       struct device_node *np = pdev->dev.of_node;
 
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
        if (!indio_dev)
@@ -199,6 +193,10 @@ static int npcm_adc_probe(struct platform_device *pdev)
        if (IS_ERR(info->regs))
                return PTR_ERR(info->regs);
 
+       info->reset = devm_reset_control_get(&pdev->dev, NULL);
+       if (IS_ERR(info->reset))
+               return PTR_ERR(info->reset);
+
        info->adc_clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(info->adc_clk)) {
                dev_warn(&pdev->dev, "ADC clock failed: can't read clk\n");
@@ -211,16 +209,6 @@ static int npcm_adc_probe(struct platform_device *pdev)
        div = div >> NPCM_ADCCON_DIV_SHIFT;
        info->adc_sample_hz = clk_get_rate(info->adc_clk) / ((div + 1) * 2);
 
-       if (of_device_is_compatible(np, "nuvoton,npcm750-adc")) {
-               info->rst_regmap = syscon_regmap_lookup_by_compatible
-                       ("nuvoton,npcm750-rst");
-               if (IS_ERR(info->rst_regmap)) {
-                       dev_err(&pdev->dev, "Failed to find nuvoton,npcm750-rst\n");
-                       ret = PTR_ERR(info->rst_regmap);
-                       goto err_disable_clk;
-               }
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq <= 0) {
                ret = -EINVAL;
index 2aad2cd..76a60d9 100644 (file)
@@ -842,31 +842,6 @@ static inline void stm32_dfsdm_process_data(struct stm32_dfsdm_adc *adc,
        }
 }
 
-static irqreturn_t stm32_dfsdm_adc_trigger_handler(int irq, void *p)
-{
-       struct iio_poll_func *pf = p;
-       struct iio_dev *indio_dev = pf->indio_dev;
-       struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
-       int available = stm32_dfsdm_adc_dma_residue(adc);
-
-       while (available >= indio_dev->scan_bytes) {
-               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);
-               available -= indio_dev->scan_bytes;
-               adc->bufi += indio_dev->scan_bytes;
-               if (adc->bufi >= adc->buf_sz)
-                       adc->bufi = 0;
-       }
-
-       iio_trigger_notify_done(indio_dev->trig);
-
-       return IRQ_HANDLED;
-}
-
 static void stm32_dfsdm_dma_buffer_done(void *data)
 {
        struct iio_dev *indio_dev = data;
@@ -874,11 +849,6 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
        int available = stm32_dfsdm_adc_dma_residue(adc);
        size_t old_pos;
 
-       if (indio_dev->currentmode & INDIO_BUFFER_TRIGGERED) {
-               iio_trigger_poll_chained(indio_dev->trig);
-               return;
-       }
-
        /*
         * FIXME: In Kernel interface does not support cyclic DMA buffer,and
         * offers only an interface to push data samples per samples.
@@ -906,7 +876,15 @@ static void stm32_dfsdm_dma_buffer_done(void *data)
                        adc->bufi = 0;
                        old_pos = 0;
                }
-               /* regular iio buffer without trigger */
+               /*
+                * In DMA mode the trigger services of IIO are not used
+                * (e.g. no call to iio_trigger_poll).
+                * Calling irq handler associated to the hardware trigger is not
+                * relevant as the conversions have already been done. Data
+                * transfers are performed directly in DMA callback instead.
+                * This implementation avoids to call trigger irq handler that
+                * may sleep, in an atomic context (DMA irq handler context).
+                */
                if (adc->dev_data->type == DFSDM_IIO)
                        iio_push_to_buffers(indio_dev, buffer);
        }
@@ -1536,8 +1514,7 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
        }
 
        ret = iio_triggered_buffer_setup(indio_dev,
-                                        &iio_pollfunc_store_time,
-                                        &stm32_dfsdm_adc_trigger_handler,
+                                        &iio_pollfunc_store_time, NULL,
                                         &stm32_dfsdm_buffer_setup_ops);
        if (ret) {
                stm32_dfsdm_dma_release(indio_dev);
index 4965246..7762035 100644 (file)
@@ -189,7 +189,8 @@ static int tlc4541_probe(struct spi_device *spi)
        /* Setup default message */
        st->scan_single_xfer[0].rx_buf = &st->rx_buf[0];
        st->scan_single_xfer[0].len = 3;
-       st->scan_single_xfer[1].delay_usecs = 3;
+       st->scan_single_xfer[1].delay.value = 3;
+       st->scan_single_xfer[1].delay.unit = SPI_DELAY_UNIT_NSECS;
        st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
        st->scan_single_xfer[2].len = 2;
 
index da7f126..9b02c9a 100644 (file)
@@ -22,4 +22,14 @@ config AD8366
          To compile this driver as a module, choose M here: the
          module will be called ad8366.
 
+config HMC425
+       tristate "Analog Devices HMC425A and similar GPIO Gain Amplifiers"
+       depends on GPIOLIB
+       help
+         Say yes here to build support for Analog Devices HMC425A and similar
+         gain amplifiers or step attenuators.
+
+         To compile this driver as a module, choose M here: the
+         module will be called hmc425a.
+
 endmenu
index 9abef2e..cb551d8 100644 (file)
@@ -5,3 +5,4 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD8366) += ad8366.o
+obj-$(CONFIG_HMC425) += hmc425a.o
index 0176d3d..62167b8 100644 (file)
@@ -5,6 +5,7 @@
  *   AD8366 Dual-Digital Variable Gain Amplifier (VGA)
  *   ADA4961 BiCMOS RF Digital Gain Amplifier (DGA)
  *   ADL5240 Digitally controlled variable gain amplifier (VGA)
+ *   HMC1119 0.25 dB LSB, 7-Bit, Silicon Digital Attenuator
  *
  * Copyright 2012-2019 Analog Devices Inc.
  */
@@ -27,6 +28,7 @@ enum ad8366_type {
        ID_AD8366,
        ID_ADA4961,
        ID_ADL5240,
+       ID_HMC1119,
 };
 
 struct ad8366_info {
@@ -62,6 +64,10 @@ static struct ad8366_info ad8366_infos[] = {
                .gain_min = -11500,
                .gain_max = 20000,
        },
+       [ID_HMC1119] = {
+               .gain_min = -31750,
+               .gain_max = 0,
+       },
 };
 
 static int ad8366_write(struct iio_dev *indio_dev,
@@ -84,6 +90,9 @@ static int ad8366_write(struct iio_dev *indio_dev,
        case ID_ADL5240:
                st->data[0] = (ch_a & 0x3F);
                break;
+       case ID_HMC1119:
+               st->data[0] = ch_a;
+               break;
        }
 
        ret = spi_write(st->spi, st->data, indio_dev->num_channels);
@@ -118,6 +127,9 @@ static int ad8366_read_raw(struct iio_dev *indio_dev,
                case ID_ADL5240:
                        gain = 20000 - 31500 + code * 500;
                        break;
+               case ID_HMC1119:
+                       gain = -1 * code * 250;
+                       break;
                }
 
                /* Values in dB */
@@ -164,6 +176,9 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
        case ID_ADL5240:
                code = ((gain - 500 - 20000) / 500) & 0x3F;
                break;
+       case ID_HMC1119:
+               code = (abs(gain) / 250) & 0x7F;
+               break;
        }
 
        mutex_lock(&st->lock);
@@ -180,9 +195,22 @@ static int ad8366_write_raw(struct iio_dev *indio_dev,
        return ret;
 }
 
+static int ad8366_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                   struct iio_chan_spec const *chan,
+                                   long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               return IIO_VAL_INT_PLUS_MICRO_DB;
+       default:
+               return -EINVAL;
+       }
+}
+
 static const struct iio_info ad8366_info = {
        .read_raw = &ad8366_read_raw,
        .write_raw = &ad8366_write_raw,
+       .write_raw_get_fmt = &ad8366_write_raw_get_fmt,
 };
 
 #define AD8366_CHAN(_channel) {                                \
@@ -233,6 +261,7 @@ static int ad8366_probe(struct spi_device *spi)
                break;
        case ID_ADA4961:
        case ID_ADL5240:
+       case ID_HMC1119:
                st->reset_gpio = devm_gpiod_get(&spi->dev, "reset",
                        GPIOD_OUT_HIGH);
                indio_dev->channels = ada4961_channels;
@@ -285,6 +314,7 @@ static const struct spi_device_id ad8366_id[] = {
        {"ad8366",  ID_AD8366},
        {"ada4961", ID_ADA4961},
        {"adl5240", ID_ADL5240},
+       {"hmc1119", ID_HMC1119},
        {}
 };
 MODULE_DEVICE_TABLE(spi, ad8366_id);
diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c
new file mode 100644 (file)
index 0000000..d9e6e96
--- /dev/null
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * HMC425A and similar Gain Amplifiers
+ *
+ * Copyright 2020 Analog Devices Inc.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sysfs.h>
+
+enum hmc425a_type {
+       ID_HMC425A,
+};
+
+struct hmc425a_chip_info {
+       const char                      *name;
+       const struct iio_chan_spec      *channels;
+       unsigned int                    num_channels;
+       unsigned int                    num_gpios;
+       int                             gain_min;
+       int                             gain_max;
+       int                             default_gain;
+};
+
+struct hmc425a_state {
+       struct  regulator *reg;
+       struct  mutex lock; /* protect sensor state */
+       struct  hmc425a_chip_info *chip_info;
+       struct  gpio_descs *gpios;
+       enum    hmc425a_type type;
+       u32     gain;
+};
+
+static int hmc425a_write(struct iio_dev *indio_dev, u32 value)
+{
+       struct hmc425a_state *st = iio_priv(indio_dev);
+       DECLARE_BITMAP(values, BITS_PER_TYPE(value));
+
+       values[0] = value;
+
+       gpiod_set_array_value_cansleep(st->gpios->ndescs, st->gpios->desc,
+                                      NULL, values);
+       return 0;
+}
+
+static int hmc425a_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan, int *val,
+                           int *val2, long m)
+{
+       struct hmc425a_state *st = iio_priv(indio_dev);
+       int code, gain = 0;
+       int ret;
+
+       mutex_lock(&st->lock);
+       switch (m) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               code = st->gain;
+
+               switch (st->type) {
+               case ID_HMC425A:
+                       gain = ~code * -500;
+                       break;
+               }
+
+               *val = gain / 1000;
+               *val2 = (gain % 1000) * 1000;
+
+               ret = IIO_VAL_INT_PLUS_MICRO_DB;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       mutex_unlock(&st->lock);
+
+       return ret;
+};
+
+static int hmc425a_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan, int val,
+                            int val2, long mask)
+{
+       struct hmc425a_state *st = iio_priv(indio_dev);
+       struct hmc425a_chip_info *inf = st->chip_info;
+       int code = 0, gain;
+       int ret;
+
+       if (val < 0)
+               gain = (val * 1000) - (val2 / 1000);
+       else
+               gain = (val * 1000) + (val2 / 1000);
+
+       if (gain > inf->gain_max || gain < inf->gain_min)
+               return -EINVAL;
+
+       switch (st->type) {
+       case ID_HMC425A:
+               code = ~((abs(gain) / 500) & 0x3F);
+               break;
+       }
+
+       mutex_lock(&st->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               st->gain = code;
+
+               ret = hmc425a_write(indio_dev, st->gain);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int hmc425a_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                    struct iio_chan_spec const *chan,
+                                    long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_HARDWAREGAIN:
+               return IIO_VAL_INT_PLUS_MICRO_DB;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info hmc425a_info = {
+       .read_raw = &hmc425a_read_raw,
+       .write_raw = &hmc425a_write_raw,
+       .write_raw_get_fmt = &hmc425a_write_raw_get_fmt,
+};
+
+#define HMC425A_CHAN(_channel)                                         \
+{                                                                      \
+       .type = IIO_VOLTAGE,                                            \
+       .output = 1,                                                    \
+       .indexed = 1,                                                   \
+       .channel = _channel,                                            \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN),          \
+}
+
+static const struct iio_chan_spec hmc425a_channels[] = {
+       HMC425A_CHAN(0),
+};
+
+/* Match table for of_platform binding */
+static const struct of_device_id hmc425a_of_match[] = {
+       { .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A },
+       {},
+};
+MODULE_DEVICE_TABLE(of, hmc425a_of_match);
+
+static void hmc425a_reg_disable(void *data)
+{
+       struct hmc425a_state *st = data;
+
+       regulator_disable(st->reg);
+}
+
+static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
+       [ID_HMC425A] = {
+               .name = "hmc425a",
+               .channels = hmc425a_channels,
+               .num_channels = ARRAY_SIZE(hmc425a_channels),
+               .num_gpios = 6,
+               .gain_min = -31500,
+               .gain_max = 0,
+               .default_gain = -0x40, /* set default gain -31.5db*/
+       },
+};
+
+static int hmc425a_probe(struct platform_device *pdev)
+{
+       struct iio_dev *indio_dev;
+       struct hmc425a_state *st;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+       st->type = (enum hmc425a_type)of_device_get_match_data(&pdev->dev);
+
+       st->chip_info = &hmc425a_chip_info_tbl[st->type];
+       indio_dev->num_channels = st->chip_info->num_channels;
+       indio_dev->channels = st->chip_info->channels;
+       indio_dev->name = st->chip_info->name;
+       st->gain = st->chip_info->default_gain;
+
+       st->gpios = devm_gpiod_get_array(&pdev->dev, "ctrl", GPIOD_OUT_LOW);
+       if (IS_ERR(st->gpios)) {
+               ret = PTR_ERR(st->gpios);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "failed to get gpios\n");
+               return ret;
+       }
+
+       if (st->gpios->ndescs != st->chip_info->num_gpios) {
+               dev_err(&pdev->dev, "%d GPIOs needed to operate\n",
+                       st->chip_info->num_gpios);
+               return -ENODEV;
+       }
+
+       st->reg = devm_regulator_get(&pdev->dev, "vcc-supply");
+       if (IS_ERR(st->reg))
+               return PTR_ERR(st->reg);
+
+       ret = regulator_enable(st->reg);
+       if (ret)
+               return ret;
+       ret = devm_add_action_or_reset(&pdev->dev, hmc425a_reg_disable, st);
+       if (ret)
+               return ret;
+
+       mutex_init(&st->lock);
+
+       indio_dev->dev.parent = &pdev->dev;
+       indio_dev->info = &hmc425a_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static struct platform_driver hmc425a_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .of_match_table = hmc425a_of_match,
+       },
+       .probe = hmc425a_probe,
+};
+module_platform_driver(hmc425a_driver);
+
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
+MODULE_DESCRIPTION("Analog Devices HMC425A and similar GPIO control Gain Amplifiers");
+MODULE_LICENSE("GPL v2");
index 0b91de4..a7e65a5 100644 (file)
@@ -91,6 +91,8 @@ config SPS30
        tristate "SPS30 particulate matter sensor"
        depends on I2C
        select CRC8
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
        help
          Say Y here to build support for the Sensirion SPS30 particulate
          matter sensor.
index 2f0a6fe..82d4705 100644 (file)
 #define ATLAS_REG_EC_CALIB_STATUS_LOW          BIT(2)
 #define ATLAS_REG_EC_CALIB_STATUS_HIGH         BIT(3)
 
+#define ATLAS_REG_DO_CALIB_STATUS              0x09
+#define ATLAS_REG_DO_CALIB_STATUS_MASK         0x03
+#define ATLAS_REG_DO_CALIB_STATUS_PRESSURE     BIT(0)
+#define ATLAS_REG_DO_CALIB_STATUS_DO           BIT(1)
+
 #define ATLAS_REG_PH_TEMP_DATA         0x0e
 #define ATLAS_REG_PH_DATA              0x16
 
 #define ATLAS_REG_ORP_CALIB_STATUS     0x0d
 #define ATLAS_REG_ORP_DATA             0x0e
 
+#define ATLAS_REG_DO_TEMP_DATA         0x12
+#define ATLAS_REG_DO_DATA              0x22
+
 #define ATLAS_PH_INT_TIME_IN_MS                450
 #define ATLAS_EC_INT_TIME_IN_MS                650
 #define ATLAS_ORP_INT_TIME_IN_MS       450
+#define ATLAS_DO_INT_TIME_IN_MS                450
 
 enum {
        ATLAS_PH_SM,
        ATLAS_EC_SM,
        ATLAS_ORP_SM,
+       ATLAS_DO_SM,
 };
 
 struct atlas_data {
@@ -76,6 +86,7 @@ struct atlas_data {
        struct atlas_device *chip;
        struct regmap *regmap;
        struct irq_work work;
+       unsigned int interrupt_enabled;
 
        __be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */
 };
@@ -121,7 +132,7 @@ static const struct iio_chan_spec atlas_ph_channels[] = {
        },
 };
 
-#define ATLAS_EC_CHANNEL(_idx, _addr) \
+#define ATLAS_CONCENTRATION_CHANNEL(_idx, _addr) \
        {\
                .type = IIO_CONCENTRATION, \
                .indexed = 1, \
@@ -152,8 +163,8 @@ static const struct iio_chan_spec atlas_ec_channels[] = {
                        .endianness = IIO_BE,
                },
        },
-       ATLAS_EC_CHANNEL(0, ATLAS_REG_TDS_DATA),
-       ATLAS_EC_CHANNEL(1, ATLAS_REG_PSS_DATA),
+       ATLAS_CONCENTRATION_CHANNEL(0, ATLAS_REG_TDS_DATA),
+       ATLAS_CONCENTRATION_CHANNEL(1, ATLAS_REG_PSS_DATA),
        IIO_CHAN_SOFT_TIMESTAMP(3),
        {
                .type = IIO_TEMP,
@@ -182,6 +193,19 @@ static const struct iio_chan_spec atlas_orp_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(1),
 };
 
+static const struct iio_chan_spec atlas_do_channels[] = {
+       ATLAS_CONCENTRATION_CHANNEL(0, ATLAS_REG_DO_DATA),
+       IIO_CHAN_SOFT_TIMESTAMP(1),
+       {
+               .type = IIO_TEMP,
+               .address = ATLAS_REG_DO_TEMP_DATA,
+               .info_mask_separate =
+                       BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+               .output = 1,
+               .scan_index = -1
+       },
+};
+
 static int atlas_check_ph_calibration(struct atlas_data *data)
 {
        struct device *dev = &data->client->dev;
@@ -262,7 +286,31 @@ static int atlas_check_orp_calibration(struct atlas_data *data)
                dev_warn(dev, "device has not been calibrated\n");
 
        return 0;
-};
+}
+
+static int atlas_check_do_calibration(struct atlas_data *data)
+{
+       struct device *dev = &data->client->dev;
+       int ret;
+       unsigned int val;
+
+       ret = regmap_read(data->regmap, ATLAS_REG_DO_CALIB_STATUS, &val);
+       if (ret)
+               return ret;
+
+       if (!(val & ATLAS_REG_DO_CALIB_STATUS_MASK)) {
+               dev_warn(dev, "device has not been calibrated\n");
+               return 0;
+       }
+
+       if (!(val & ATLAS_REG_DO_CALIB_STATUS_PRESSURE))
+               dev_warn(dev, "device missing atmospheric pressure calibration\n");
+
+       if (!(val & ATLAS_REG_DO_CALIB_STATUS_DO))
+               dev_warn(dev, "device missing dissolved oxygen calibration\n");
+
+       return 0;
+}
 
 struct atlas_device {
        const struct iio_chan_spec *channels;
@@ -295,6 +343,13 @@ static struct atlas_device atlas_devices[] = {
                                .calibration = &atlas_check_orp_calibration,
                                .delay = ATLAS_ORP_INT_TIME_IN_MS,
        },
+       [ATLAS_DO_SM] = {
+                               .channels = atlas_do_channels,
+                               .num_channels = 3,
+                               .data_reg = ATLAS_REG_DO_DATA,
+                               .calibration = &atlas_check_do_calibration,
+                               .delay = ATLAS_DO_INT_TIME_IN_MS,
+       },
 };
 
 static int atlas_set_powermode(struct atlas_data *data, int on)
@@ -304,6 +359,9 @@ static int atlas_set_powermode(struct atlas_data *data, int on)
 
 static int atlas_set_interrupt(struct atlas_data *data, bool state)
 {
+       if (!data->interrupt_enabled)
+               return 0;
+
        return regmap_update_bits(data->regmap, ATLAS_REG_INT_CONTROL,
                                  ATLAS_REG_INT_CONTROL_EN,
                                  state ? ATLAS_REG_INT_CONTROL_EN : 0);
@@ -507,6 +565,7 @@ static const struct i2c_device_id atlas_id[] = {
        { "atlas-ph-sm", ATLAS_PH_SM},
        { "atlas-ec-sm", ATLAS_EC_SM},
        { "atlas-orp-sm", ATLAS_ORP_SM},
+       { "atlas-do-sm", ATLAS_DO_SM},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, atlas_id);
@@ -515,6 +574,7 @@ static const struct of_device_id atlas_dt_ids[] = {
        { .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
        { .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
        { .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, },
+       { .compatible = "atlas,do-sm", .data = (void *)ATLAS_DO_SM, },
        { }
 };
 MODULE_DEVICE_TABLE(of, atlas_dt_ids);
@@ -572,11 +632,6 @@ static int atlas_probe(struct i2c_client *client,
        if (ret)
                return ret;
 
-       if (client->irq <= 0) {
-               dev_err(&client->dev, "no valid irq defined\n");
-               return -EINVAL;
-       }
-
        ret = chip->calibration(data);
        if (ret)
                return ret;
@@ -596,16 +651,20 @@ static int atlas_probe(struct i2c_client *client,
 
        init_irq_work(&data->work, atlas_work_handler);
 
-       /* interrupt pin toggles on new conversion */
-       ret = devm_request_threaded_irq(&client->dev, client->irq,
-                                       NULL, atlas_interrupt_handler,
-                                       IRQF_TRIGGER_RISING |
-                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                                       "atlas_irq",
-                                       indio_dev);
-       if (ret) {
-               dev_err(&client->dev, "request irq (%d) failed\n", client->irq);
-               goto unregister_buffer;
+       if (client->irq > 0) {
+               /* interrupt pin toggles on new conversion */
+               ret = devm_request_threaded_irq(&client->dev, client->irq,
+                               NULL, atlas_interrupt_handler,
+                               IRQF_TRIGGER_RISING |
+                               IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                               "atlas_irq",
+                               indio_dev);
+
+               if (ret)
+                       dev_warn(&client->dev,
+                               "request irq (%d) failed\n", client->irq);
+               else
+                       data->interrupt_enabled = 1;
        }
 
        ret = atlas_set_powermode(data, 1);
index e051edb..0e35ff0 100644 (file)
@@ -328,6 +328,8 @@ static struct st_sensors_platform_data *st_sensors_dev_probe(struct device *dev,
                return NULL;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
        if (!device_property_read_u32(dev, "st,drdy-int-pin", &val) && (val <= 2))
                pdata->drdy_int_pin = (u8) val;
        else
@@ -371,6 +373,8 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
 
        /* If OF/DT pdata exists, it will take precedence of anything else */
        of_pdata = st_sensors_dev_probe(indio_dev->dev.parent, pdata);
+       if (IS_ERR(of_pdata))
+               return PTR_ERR(of_pdata);
        if (of_pdata)
                pdata = of_pdata;
 
index 9790701..9374401 100644 (file)
@@ -121,26 +121,6 @@ config AD5624R_SPI
          Say yes here to build support for Analog Devices AD5624R, AD5644R and
          AD5664R converters (DAC). This driver uses the common SPI interface.
 
-config LTC1660
-       tristate "Linear Technology LTC1660/LTC1665 DAC SPI driver"
-       depends on SPI
-       help
-         Say yes here to build support for Linear Technology
-         LTC1660 and LTC1665 Digital to Analog Converters.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ltc1660.
-
-config LTC2632
-       tristate "Linear Technology LTC2632-12/10/8 DAC spi driver"
-       depends on SPI
-       help
-         Say yes here to build support for Linear Technology
-         LTC2632-12, LTC2632-10, LTC2632-8 converters (DAC).
-
-         To compile this driver as a module, choose M here: the
-         module will be called ltc2632.
-
 config AD5686
        tristate
 
@@ -208,6 +188,16 @@ config AD5764
          To compile this driver as a module, choose M here: the
          module will be called ad5764.
 
+config AD5770R
+       tristate "Analog Devices AD5770R IDAC driver"
+       depends on SPI_MASTER
+       help
+         Say yes here to build support for Analog Devices AD5770R Digital to
+         Analog Converter.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad5770r.
+
 config AD5791
        tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver"
        depends on SPI
@@ -229,16 +219,6 @@ config AD7303
          To compile this driver as module choose M here: the module will be called
          ad7303.
 
-config CIO_DAC
-       tristate "Measurement Computing CIO-DAC IIO driver"
-       depends on X86 && (ISA_BUS || PC104)
-       select ISA_BUS_API
-       help
-         Say yes here to build support for the Measurement Computing CIO-DAC
-         analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The
-         base port addresses for the devices may be configured via the base
-         array module parameter.
-
 config AD8801
        tristate "Analog Devices AD8801/AD8803 DAC driver"
        depends on SPI_MASTER
@@ -249,6 +229,16 @@ config AD8801
          To compile this driver as a module choose M here: the module will be called
          ad8801.
 
+config CIO_DAC
+       tristate "Measurement Computing CIO-DAC IIO driver"
+       depends on X86 && (ISA_BUS || PC104)
+       select ISA_BUS_API
+       help
+         Say yes here to build support for the Measurement Computing CIO-DAC
+         analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The
+         base port addresses for the devices may be configured via the base
+         array module parameter.
+
 config DPOT_DAC
        tristate "DAC emulation using a DPOT"
        depends on OF
@@ -278,6 +268,27 @@ config LPC18XX_DAC
          To compile this driver as a module, choose M here: the module will be
          called lpc18xx_dac.
 
+config LTC1660
+       tristate "Linear Technology LTC1660/LTC1665 DAC SPI driver"
+       depends on SPI
+       help
+         Say yes here to build support for Linear Technology
+         LTC1660 and LTC1665 Digital to Analog Converters.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ltc1660.
+
+config LTC2632
+       tristate "Linear Technology LTC2632-12/10/8 and LTC2636-12/10/8 DAC spi driver"
+       depends on SPI
+       help
+         Say yes here to build support for Linear Technology
+         LTC2632-12, LTC2632-10, LTC2632-8, LTC2636-12, LTC2636-10 and
+         LTC2636-8 converters (DAC).
+
+         To compile this driver as a module, choose M here: the
+         module will be called ltc2632.
+
 config M62332
        tristate "Mitsubishi M62332 DAC driver"
        depends on I2C
index 1369fa1..2fc4811 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_AD5755) += ad5755.o
 obj-$(CONFIG_AD5755) += ad5758.o
 obj-$(CONFIG_AD5761) += ad5761.o
 obj-$(CONFIG_AD5764) += ad5764.o
+obj-$(CONFIG_AD5770R) += ad5770r.o
 obj-$(CONFIG_AD5791) += ad5791.o
 obj-$(CONFIG_AD5686) += ad5686.o
 obj-$(CONFIG_AD5686_SPI) += ad5686-spi.o
index b9175fb..388ddd1 100644 (file)
@@ -631,10 +631,9 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
                        }
                }
 
-               if (i == ARRAY_SIZE(ad5755_dcdc_freq_table)) {
+               if (i == ARRAY_SIZE(ad5755_dcdc_freq_table))
                        dev_err(dev,
-                               "adi,dc-dc-freq out of range selecting 410kHz");
-               }
+                               "adi,dc-dc-freq out of range selecting 410kHz\n");
        }
 
        pdata->dc_dc_maxv = AD5755_DC_DC_MAXV_23V;
@@ -645,17 +644,16 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
                                break;
                        }
                }
-               if (i == ARRAY_SIZE(ad5755_dcdc_maxv_table)) {
+               if (i == ARRAY_SIZE(ad5755_dcdc_maxv_table))
                                dev_err(dev,
-                                       "adi,dc-dc-maxv out of range selecting 23V");
-               }
+                                       "adi,dc-dc-maxv out of range selecting 23V\n");
        }
 
        devnr = 0;
        for_each_child_of_node(np, pp) {
                if (devnr >= AD5755_NUM_CHANNELS) {
                        dev_err(dev,
-                               "There is to many channels defined in DT\n");
+                               "There are too many channels defined in DT\n");
                        goto error_out;
                }
 
@@ -681,11 +679,10 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
                                        break;
                                }
                        }
-                       if (i == ARRAY_SIZE(ad5755_slew_rate_table)) {
+                       if (i == ARRAY_SIZE(ad5755_slew_rate_table))
                                dev_err(dev,
-                                       "channel %d slew rate out of range selecting 64kHz",
+                                       "channel %d slew rate out of range selecting 64kHz\n",
                                        devnr);
-                       }
 
                        pdata->dac[devnr].slew.step_size = AD5755_SLEW_STEP_SIZE_1;
                        for (i = 0; i < ARRAY_SIZE(ad5755_slew_step_table); i++) {
@@ -695,11 +692,10 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
                                        break;
                                }
                        }
-                       if (i == ARRAY_SIZE(ad5755_slew_step_table)) {
+                       if (i == ARRAY_SIZE(ad5755_slew_step_table))
                                dev_err(dev,
-                                       "channel %d slew step size out of range selecting 1 LSB",
+                                       "channel %d slew step size out of range selecting 1 LSB\n",
                                        devnr);
-                       }
                } else {
                        pdata->dac[devnr].slew.enable = false;
                        pdata->dac[devnr].slew.rate = AD5755_SLEW_RATE_64k;
diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c
new file mode 100644 (file)
index 0000000..a98ea76
--- /dev/null
@@ -0,0 +1,695 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AD5770R Digital to analog converters driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#define ADI_SPI_IF_CONFIG_A            0x00
+#define ADI_SPI_IF_CONFIG_B            0x01
+#define ADI_SPI_IF_DEVICE_CONFIG       0x02
+#define ADI_SPI_IF_CHIP_TYPE           0x03
+#define ADI_SPI_IF_PRODUCT_ID_L                0x04
+#define ADI_SPI_IF_PRODUCT_ID_H                0x05
+#define ADI_SPI_IF_CHIP_GRADE          0x06
+#define ADI_SPI_IF_SCRACTH_PAD         0x0A
+#define ADI_SPI_IF_SPI_REVISION                0x0B
+#define ADI_SPI_IF_SPI_VENDOR_L                0x0C
+#define ADI_SPI_IF_SPI_VENDOR_H                0x0D
+#define ADI_SPI_IF_SPI_STREAM_MODE     0x0E
+#define ADI_SPI_IF_CONFIG_C            0x10
+#define ADI_SPI_IF_STATUS_A            0x11
+
+/* ADI_SPI_IF_CONFIG_A */
+#define ADI_SPI_IF_SW_RESET_MSK                (BIT(0) | BIT(7))
+#define ADI_SPI_IF_SW_RESET_SEL(x)     ((x) & ADI_SPI_IF_SW_RESET_MSK)
+#define ADI_SPI_IF_ADDR_ASC_MSK                (BIT(2) | BIT(5))
+#define ADI_SPI_IF_ADDR_ASC_SEL(x)     (((x) << 2) & ADI_SPI_IF_ADDR_ASC_MSK)
+
+/* ADI_SPI_IF_CONFIG_B */
+#define ADI_SPI_IF_SINGLE_INS_MSK      BIT(7)
+#define ADI_SPI_IF_SINGLE_INS_SEL(x)   FIELD_PREP(ADI_SPI_IF_SINGLE_INS_MSK, x)
+#define ADI_SPI_IF_SHORT_INS_MSK       BIT(7)
+#define ADI_SPI_IF_SHORT_INS_SEL(x)    FIELD_PREP(ADI_SPI_IF_SINGLE_INS_MSK, x)
+
+/* ADI_SPI_IF_CONFIG_C */
+#define ADI_SPI_IF_STRICT_REG_MSK      BIT(5)
+#define ADI_SPI_IF_STRICT_REG_GET(x)   FIELD_GET(ADI_SPI_IF_STRICT_REG_MSK, x)
+
+/* AD5770R configuration registers */
+#define AD5770R_CHANNEL_CONFIG         0x14
+#define AD5770R_OUTPUT_RANGE(ch)       (0x15 + (ch))
+#define AD5770R_FILTER_RESISTOR(ch)    (0x1D + (ch))
+#define AD5770R_REFERENCE              0x1B
+#define AD5770R_DAC_LSB(ch)            (0x26 + 2 * (ch))
+#define AD5770R_DAC_MSB(ch)            (0x27 + 2 * (ch))
+#define AD5770R_CH_SELECT              0x34
+#define AD5770R_CH_ENABLE              0x44
+
+/* AD5770R_CHANNEL_CONFIG */
+#define AD5770R_CFG_CH0_SINK_EN(x)             (((x) & 0x1) << 7)
+#define AD5770R_CFG_SHUTDOWN_B(x, ch)          (((x) & 0x1) << (ch))
+
+/* AD5770R_OUTPUT_RANGE */
+#define AD5770R_RANGE_OUTPUT_SCALING(x)                (((x) & GENMASK(5, 0)) << 2)
+#define AD5770R_RANGE_MODE(x)                  ((x) & GENMASK(1, 0))
+
+/* AD5770R_REFERENCE */
+#define AD5770R_REF_RESISTOR_SEL(x)            (((x) & 0x1) << 2)
+#define AD5770R_REF_SEL(x)                     ((x) & GENMASK(1, 0))
+
+/* AD5770R_CH_ENABLE */
+#define AD5770R_CH_SET(x, ch)          (((x) & 0x1) << (ch))
+
+#define AD5770R_MAX_CHANNELS   6
+#define AD5770R_MAX_CH_MODES   14
+#define AD5770R_LOW_VREF_mV    1250
+#define AD5770R_HIGH_VREF_mV   2500
+
+enum ad5770r_ch0_modes {
+       AD5770R_CH0_0_300 = 0,
+       AD5770R_CH0_NEG_60_0,
+       AD5770R_CH0_NEG_60_300
+};
+
+enum ad5770r_ch1_modes {
+       AD5770R_CH1_0_140_LOW_HEAD = 1,
+       AD5770R_CH1_0_140_LOW_NOISE,
+       AD5770R_CH1_0_250
+};
+
+enum ad5770r_ch2_5_modes {
+       AD5770R_CH_LOW_RANGE = 0,
+       AD5770R_CH_HIGH_RANGE
+};
+
+enum ad5770r_ref_v {
+       AD5770R_EXT_2_5_V = 0,
+       AD5770R_INT_1_25_V_OUT_ON,
+       AD5770R_EXT_1_25_V,
+       AD5770R_INT_1_25_V_OUT_OFF
+};
+
+enum ad5770r_output_filter_resistor {
+       AD5770R_FILTER_60_OHM = 0x0,
+       AD5770R_FILTER_5_6_KOHM = 0x5,
+       AD5770R_FILTER_11_2_KOHM,
+       AD5770R_FILTER_22_2_KOHM,
+       AD5770R_FILTER_44_4_KOHM,
+       AD5770R_FILTER_104_KOHM,
+};
+
+struct ad5770r_out_range {
+       u8      out_scale;
+       u8      out_range_mode;
+};
+
+/**
+ * struct ad5770R_state - driver instance specific data
+ * @spi:               spi_device
+ * @regmap:            regmap
+ * @vref_reg:          fixed regulator for reference configuration
+ * @gpio_reset:                gpio descriptor
+ * @output_mode:       array contains channels output ranges
+ * @vref:              reference value
+ * @ch_pwr_down:       powerdown flags
+ * @internal_ref:      internal reference flag
+ * @external_res:      external 2.5k resistor flag
+ * @transf_buf:                cache aligned buffer for spi read/write
+ */
+struct ad5770r_state {
+       struct spi_device               *spi;
+       struct regmap                   *regmap;
+       struct regulator                *vref_reg;
+       struct gpio_desc                *gpio_reset;
+       struct ad5770r_out_range        output_mode[AD5770R_MAX_CHANNELS];
+       int                             vref;
+       bool                            ch_pwr_down[AD5770R_MAX_CHANNELS];
+       bool                            internal_ref;
+       bool                            external_res;
+       u8                              transf_buf[2] ____cacheline_aligned;
+};
+
+static const struct regmap_config ad5770r_spi_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .read_flag_mask = BIT(7),
+};
+
+struct ad5770r_output_modes {
+       unsigned int ch;
+       u8 mode;
+       int min;
+       int max;
+};
+
+static struct ad5770r_output_modes ad5770r_rng_tbl[] = {
+       { 0, AD5770R_CH0_0_300, 0, 300 },
+       { 0, AD5770R_CH0_NEG_60_0, -60, 0 },
+       { 0, AD5770R_CH0_NEG_60_300, -60, 300 },
+       { 1, AD5770R_CH1_0_140_LOW_HEAD, 0, 140 },
+       { 1, AD5770R_CH1_0_140_LOW_NOISE, 0, 140 },
+       { 1, AD5770R_CH1_0_250, 0, 250 },
+       { 2, AD5770R_CH_LOW_RANGE, 0, 55 },
+       { 2, AD5770R_CH_HIGH_RANGE, 0, 150 },
+       { 3, AD5770R_CH_LOW_RANGE, 0, 45 },
+       { 3, AD5770R_CH_HIGH_RANGE, 0, 100 },
+       { 4, AD5770R_CH_LOW_RANGE, 0, 45 },
+       { 4, AD5770R_CH_HIGH_RANGE, 0, 100 },
+       { 5, AD5770R_CH_LOW_RANGE, 0, 45 },
+       { 5, AD5770R_CH_HIGH_RANGE, 0, 100 },
+};
+
+static const unsigned int ad5770r_filter_freqs[] = {
+       153, 357, 715, 1400, 2800, 262000,
+};
+
+static const unsigned int ad5770r_filter_reg_vals[] = {
+       AD5770R_FILTER_104_KOHM,
+       AD5770R_FILTER_44_4_KOHM,
+       AD5770R_FILTER_22_2_KOHM,
+       AD5770R_FILTER_11_2_KOHM,
+       AD5770R_FILTER_5_6_KOHM,
+       AD5770R_FILTER_60_OHM
+};
+
+static int ad5770r_set_output_mode(struct ad5770r_state *st,
+                                  const struct ad5770r_out_range *out_mode,
+                                  int channel)
+{
+       unsigned int regval;
+
+       regval = AD5770R_RANGE_OUTPUT_SCALING(out_mode->out_scale) |
+                AD5770R_RANGE_MODE(out_mode->out_range_mode);
+
+       return regmap_write(st->regmap,
+                           AD5770R_OUTPUT_RANGE(channel), regval);
+}
+
+static int ad5770r_set_reference(struct ad5770r_state *st)
+{
+       unsigned int regval;
+
+       regval = AD5770R_REF_RESISTOR_SEL(st->external_res);
+
+       if (st->internal_ref) {
+               regval |= AD5770R_REF_SEL(AD5770R_INT_1_25_V_OUT_OFF);
+       } else {
+               switch (st->vref) {
+               case AD5770R_LOW_VREF_mV:
+                       regval |= AD5770R_REF_SEL(AD5770R_EXT_1_25_V);
+                       break;
+               case AD5770R_HIGH_VREF_mV:
+                       regval |= AD5770R_REF_SEL(AD5770R_EXT_2_5_V);
+                       break;
+               default:
+                       regval = AD5770R_REF_SEL(AD5770R_INT_1_25_V_OUT_OFF);
+                       break;
+               }
+       }
+
+       return regmap_write(st->regmap, AD5770R_REFERENCE, regval);
+}
+
+static int ad5770r_soft_reset(struct ad5770r_state *st)
+{
+       return regmap_write(st->regmap, ADI_SPI_IF_CONFIG_A,
+                           ADI_SPI_IF_SW_RESET_SEL(1));
+}
+
+static int ad5770r_reset(struct ad5770r_state *st)
+{
+       /* Perform software reset if no GPIO provided */
+       if (!st->gpio_reset)
+               return ad5770r_soft_reset(st);
+
+       gpiod_set_value_cansleep(st->gpio_reset, 0);
+       usleep_range(10, 20);
+       gpiod_set_value_cansleep(st->gpio_reset, 1);
+
+       /* data must not be written during reset timeframe */
+       usleep_range(100, 200);
+
+       return 0;
+}
+
+static int ad5770r_get_range(struct ad5770r_state *st,
+                            int ch, int *min, int *max)
+{
+       int i;
+       u8 tbl_ch, tbl_mode, out_range;
+
+       out_range = st->output_mode[ch].out_range_mode;
+
+       for (i = 0; i < AD5770R_MAX_CH_MODES; i++) {
+               tbl_ch = ad5770r_rng_tbl[i].ch;
+               tbl_mode = ad5770r_rng_tbl[i].mode;
+               if (tbl_ch == ch && tbl_mode == out_range) {
+                       *min = ad5770r_rng_tbl[i].min;
+                       *max = ad5770r_rng_tbl[i].max;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int ad5770r_get_filter_freq(struct iio_dev *indio_dev,
+                                  const struct iio_chan_spec *chan, int *freq)
+{
+       struct ad5770r_state *st = iio_priv(indio_dev);
+       int ret;
+       unsigned int regval, i;
+
+       ret = regmap_read(st->regmap,
+                         AD5770R_FILTER_RESISTOR(chan->channel), &regval);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(ad5770r_filter_reg_vals); i++)
+               if (regval == ad5770r_filter_reg_vals[i])
+                       break;
+       if (i == ARRAY_SIZE(ad5770r_filter_reg_vals))
+               return -EINVAL;
+
+       *freq = ad5770r_filter_freqs[i];
+
+       return IIO_VAL_INT;
+}
+
+static int ad5770r_set_filter_freq(struct iio_dev *indio_dev,
+                                  const struct iio_chan_spec *chan,
+                                  unsigned int freq)
+{
+       struct ad5770r_state *st = iio_priv(indio_dev);
+       unsigned int regval, i;
+
+       for (i = 0; i < ARRAY_SIZE(ad5770r_filter_freqs); i++)
+               if (ad5770r_filter_freqs[i] >= freq)
+                       break;
+       if (i == ARRAY_SIZE(ad5770r_filter_freqs))
+               return -EINVAL;
+
+       regval = ad5770r_filter_reg_vals[i];
+
+       return regmap_write(st->regmap, AD5770R_FILTER_RESISTOR(chan->channel),
+                           regval);
+}
+
+static int ad5770r_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long info)
+{
+       struct ad5770r_state *st = iio_priv(indio_dev);
+       int max, min, ret;
+       u16 buf16;
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               ret = regmap_bulk_read(st->regmap,
+                                      chan->address,
+                                      st->transf_buf, 2);
+               if (ret)
+                       return 0;
+
+               buf16 = st->transf_buf[0] + (st->transf_buf[1] << 8);
+               *val = buf16 >> 2;
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               ret = ad5770r_get_range(st, chan->channel, &min, &max);
+               if (ret < 0)
+                       return ret;
+               *val = max - min;
+               /* There is no sign bit. (negative current is mapped from 0)
+                * (sourced/sinked) current = raw * scale + offset
+                * where offset in case of CH0 can be negative.
+                */
+               *val2 = 14;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+               return ad5770r_get_filter_freq(indio_dev, chan, val);
+       case IIO_CHAN_INFO_OFFSET:
+               ret = ad5770r_get_range(st, chan->channel, &min, &max);
+               if (ret < 0)
+                       return ret;
+               *val = min;
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad5770r_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long info)
+{
+       struct ad5770r_state *st = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               st->transf_buf[0] = ((u16)val >> 6);
+               st->transf_buf[1] = (val & GENMASK(5, 0)) << 2;
+               return regmap_bulk_write(st->regmap, chan->address,
+                                        st->transf_buf, 2);
+       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+               return ad5770r_set_filter_freq(indio_dev, chan, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad5770r_read_freq_avail(struct iio_dev *indio_dev,
+                                  struct iio_chan_spec const *chan,
+                                  const int **vals, int *type, int *length,
+                                  long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+               *type = IIO_VAL_INT;
+               *vals = ad5770r_filter_freqs;
+               *length = ARRAY_SIZE(ad5770r_filter_freqs);
+               return IIO_AVAIL_LIST;
+       }
+
+       return -EINVAL;
+}
+
+static int ad5770r_reg_access(struct iio_dev *indio_dev,
+                             unsigned int reg,
+                             unsigned int writeval,
+                             unsigned int *readval)
+{
+       struct ad5770r_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 ad5770r_info = {
+       .read_raw = ad5770r_read_raw,
+       .write_raw = ad5770r_write_raw,
+       .read_avail = ad5770r_read_freq_avail,
+       .debugfs_reg_access = &ad5770r_reg_access,
+};
+
+static int ad5770r_store_output_range(struct ad5770r_state *st,
+                                     int min, int max, int index)
+{
+       int i;
+
+       for (i = 0; i < AD5770R_MAX_CH_MODES; i++) {
+               if (ad5770r_rng_tbl[i].ch != index)
+                       continue;
+               if (ad5770r_rng_tbl[i].min != min ||
+                   ad5770r_rng_tbl[i].max != max)
+                       continue;
+               st->output_mode[index].out_range_mode = ad5770r_rng_tbl[i].mode;
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static ssize_t ad5770r_read_dac_powerdown(struct iio_dev *indio_dev,
+                                         uintptr_t private,
+                                         const struct iio_chan_spec *chan,
+                                         char *buf)
+{
+       struct ad5770r_state *st = iio_priv(indio_dev);
+
+       return sprintf(buf, "%d\n", st->ch_pwr_down[chan->channel]);
+}
+
+static ssize_t ad5770r_write_dac_powerdown(struct iio_dev *indio_dev,
+                                          uintptr_t private,
+                                          const struct iio_chan_spec *chan,
+                                          const char *buf, size_t len)
+{
+       struct ad5770r_state *st = iio_priv(indio_dev);
+       unsigned int regval;
+       unsigned int mask;
+       bool readin;
+       int ret;
+
+       ret = kstrtobool(buf, &readin);
+       if (ret)
+               return ret;
+
+       readin = !readin;
+
+       regval = AD5770R_CFG_SHUTDOWN_B(readin, chan->channel);
+       if (chan->channel == 0 &&
+           st->output_mode[0].out_range_mode > AD5770R_CH0_0_300) {
+               regval |= AD5770R_CFG_CH0_SINK_EN(readin);
+               mask = BIT(chan->channel) + BIT(7);
+       } else {
+               mask = BIT(chan->channel);
+       }
+       ret = regmap_update_bits(st->regmap, AD5770R_CHANNEL_CONFIG, mask,
+                                regval);
+       if (ret)
+               return ret;
+
+       regval = AD5770R_CH_SET(readin, chan->channel);
+       ret = regmap_update_bits(st->regmap, AD5770R_CH_ENABLE,
+                                BIT(chan->channel), regval);
+       if (ret)
+               return ret;
+
+       st->ch_pwr_down[chan->channel] = !readin;
+
+       return len;
+}
+
+static const struct iio_chan_spec_ext_info ad5770r_ext_info[] = {
+       {
+               .name = "powerdown",
+               .read = ad5770r_read_dac_powerdown,
+               .write = ad5770r_write_dac_powerdown,
+               .shared = IIO_SEPARATE,
+       },
+       { }
+};
+
+#define AD5770R_IDAC_CHANNEL(index, reg) {                             \
+       .type = IIO_CURRENT,                                            \
+       .address = reg,                                                 \
+       .indexed = 1,                                                   \
+       .channel = index,                                               \
+       .output = 1,                                                    \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
+               BIT(IIO_CHAN_INFO_SCALE) |                              \
+               BIT(IIO_CHAN_INFO_OFFSET) |                             \
+               BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),       \
+       .info_mask_shared_by_type_available =                           \
+               BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),       \
+       .ext_info = ad5770r_ext_info,                                   \
+}
+
+static const struct iio_chan_spec ad5770r_channels[] = {
+       AD5770R_IDAC_CHANNEL(0, AD5770R_DAC_MSB(0)),
+       AD5770R_IDAC_CHANNEL(1, AD5770R_DAC_MSB(1)),
+       AD5770R_IDAC_CHANNEL(2, AD5770R_DAC_MSB(2)),
+       AD5770R_IDAC_CHANNEL(3, AD5770R_DAC_MSB(3)),
+       AD5770R_IDAC_CHANNEL(4, AD5770R_DAC_MSB(4)),
+       AD5770R_IDAC_CHANNEL(5, AD5770R_DAC_MSB(5)),
+};
+
+static int ad5770r_channel_config(struct ad5770r_state *st)
+{
+       int ret, tmp[2], min, max;
+       unsigned int num;
+       struct fwnode_handle *child;
+
+       num = device_get_child_node_count(&st->spi->dev);
+       if (num != AD5770R_MAX_CHANNELS)
+               return -EINVAL;
+
+       device_for_each_child_node(&st->spi->dev, child) {
+               ret = fwnode_property_read_u32(child, "num", &num);
+               if (ret)
+                       return ret;
+               if (num > AD5770R_MAX_CHANNELS)
+                       return -EINVAL;
+
+               ret = fwnode_property_read_u32_array(child,
+                                                    "adi,range-microamp",
+                                                    tmp, 2);
+               if (ret)
+                       return ret;
+
+               min = tmp[0] / 1000;
+               max = tmp[1] / 1000;
+               ret = ad5770r_store_output_range(st, min, max, num);
+               if (ret)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static int ad5770r_init(struct ad5770r_state *st)
+{
+       int ret, i;
+
+       st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
+                                                GPIOD_OUT_HIGH);
+       if (IS_ERR(st->gpio_reset))
+               return PTR_ERR(st->gpio_reset);
+
+       /* Perform a reset */
+       ret = ad5770r_reset(st);
+       if (ret)
+               return ret;
+
+       /* Set output range */
+       ret = ad5770r_channel_config(st);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < AD5770R_MAX_CHANNELS; i++) {
+               ret = ad5770r_set_output_mode(st,  &st->output_mode[i], i);
+               if (ret)
+                       return ret;
+       }
+
+       st->external_res = fwnode_property_read_bool(st->spi->dev.fwnode,
+                                                    "adi,external-resistor");
+
+       ret = ad5770r_set_reference(st);
+       if (ret)
+               return ret;
+
+       /* Set outputs off */
+       ret = regmap_write(st->regmap, AD5770R_CHANNEL_CONFIG, 0x00);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(st->regmap, AD5770R_CH_ENABLE, 0x00);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < AD5770R_MAX_CHANNELS; i++)
+               st->ch_pwr_down[i] = true;
+
+       return ret;
+}
+
+static void ad5770r_disable_regulator(void *data)
+{
+       struct ad5770r_state *st = data;
+
+       regulator_disable(st->vref_reg);
+}
+
+static int ad5770r_probe(struct spi_device *spi)
+{
+       struct ad5770r_state *st;
+       struct iio_dev *indio_dev;
+       struct regmap *regmap;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+       spi_set_drvdata(spi, indio_dev);
+
+       st->spi = spi;
+
+       regmap = devm_regmap_init_spi(spi, &ad5770r_spi_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
+                       PTR_ERR(regmap));
+               return PTR_ERR(regmap);
+       }
+       st->regmap = regmap;
+
+       st->vref_reg = devm_regulator_get_optional(&spi->dev, "vref");
+       if (!IS_ERR(st->vref_reg)) {
+               ret = regulator_enable(st->vref_reg);
+               if (ret) {
+                       dev_err(&spi->dev,
+                               "Failed to enable vref regulators: %d\n", ret);
+                       return ret;
+               }
+
+               ret = devm_add_action_or_reset(&spi->dev,
+                                              ad5770r_disable_regulator,
+                                              st);
+               if (ret < 0)
+                       return ret;
+
+               ret = regulator_get_voltage(st->vref_reg);
+               if (ret < 0)
+                       return ret;
+
+               st->vref = ret / 1000;
+       } else {
+               if (PTR_ERR(st->vref_reg) == -ENODEV) {
+                       st->vref = AD5770R_LOW_VREF_mV;
+                       st->internal_ref = true;
+               } else {
+                       return PTR_ERR(st->vref_reg);
+               }
+       }
+
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->info = &ad5770r_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = ad5770r_channels;
+       indio_dev->num_channels = ARRAY_SIZE(ad5770r_channels);
+
+       ret = ad5770r_init(st);
+       if (ret < 0) {
+               dev_err(&spi->dev, "AD5770R init failed\n");
+               return ret;
+       }
+
+       return devm_iio_device_register(&st->spi->dev, indio_dev);
+}
+
+static const struct of_device_id ad5770r_of_id[] = {
+       { .compatible = "adi,ad5770r", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ad5770r_of_id);
+
+static const struct spi_device_id ad5770r_id[] = {
+       { "ad5770r", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(spi, ad5770r_id);
+
+static struct spi_driver ad5770r_driver = {
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .of_match_table = ad5770r_of_id,
+       },
+       .probe = ad5770r_probe,
+       .id_table = ad5770r_id,
+};
+
+module_spi_driver(ad5770r_driver);
+
+MODULE_AUTHOR("Mircea Caprioru <mircea.caprioru@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD5770R IDAC");
+MODULE_LICENSE("GPL v2");
index 643d1ce..7adc910 100644 (file)
 #include <linux/iio/iio.h>
 #include <linux/regulator/consumer.h>
 
-#define LTC2632_DAC_CHANNELS                    2
-
-#define LTC2632_ADDR_DAC0                       0x0
-#define LTC2632_ADDR_DAC1                       0x1
-
 #define LTC2632_CMD_WRITE_INPUT_N               0x0
 #define LTC2632_CMD_UPDATE_DAC_N                0x1
 #define LTC2632_CMD_WRITE_INPUT_N_UPDATE_ALL    0x2
@@ -33,6 +28,7 @@
  */
 struct ltc2632_chip_info {
        const struct iio_chan_spec *channels;
+       const size_t num_channels;
        const int vref_mv;
 };
 
@@ -57,6 +53,12 @@ enum ltc2632_supported_device_ids {
        ID_LTC2632H12,
        ID_LTC2632H10,
        ID_LTC2632H8,
+       ID_LTC2636L12,
+       ID_LTC2636L10,
+       ID_LTC2636L8,
+       ID_LTC2636H12,
+       ID_LTC2636H10,
+       ID_LTC2636H8,
 };
 
 static int ltc2632_spi_write(struct spi_device *spi,
@@ -190,39 +192,77 @@ static const struct iio_chan_spec_ext_info ltc2632_ext_info[] = {
        const struct iio_chan_spec _name ## _channels[] = { \
                LTC2632_CHANNEL(0, _bits), \
                LTC2632_CHANNEL(1, _bits), \
+               LTC2632_CHANNEL(2, _bits), \
+               LTC2632_CHANNEL(3, _bits), \
+               LTC2632_CHANNEL(4, _bits), \
+               LTC2632_CHANNEL(5, _bits), \
+               LTC2632_CHANNEL(6, _bits), \
+               LTC2632_CHANNEL(7, _bits), \
        }
 
-static DECLARE_LTC2632_CHANNELS(ltc2632l12, 12);
-static DECLARE_LTC2632_CHANNELS(ltc2632l10, 10);
-static DECLARE_LTC2632_CHANNELS(ltc2632l8, 8);
-
-static DECLARE_LTC2632_CHANNELS(ltc2632h12, 12);
-static DECLARE_LTC2632_CHANNELS(ltc2632h10, 10);
-static DECLARE_LTC2632_CHANNELS(ltc2632h8, 8);
+static DECLARE_LTC2632_CHANNELS(ltc2632x12, 12);
+static DECLARE_LTC2632_CHANNELS(ltc2632x10, 10);
+static DECLARE_LTC2632_CHANNELS(ltc2632x8, 8);
 
 static const struct ltc2632_chip_info ltc2632_chip_info_tbl[] = {
        [ID_LTC2632L12] = {
-               .channels       = ltc2632l12_channels,
+               .channels       = ltc2632x12_channels,
+               .num_channels   = 2,
                .vref_mv        = 2500,
        },
        [ID_LTC2632L10] = {
-               .channels       = ltc2632l10_channels,
+               .channels       = ltc2632x10_channels,
+               .num_channels   = 2,
                .vref_mv        = 2500,
        },
        [ID_LTC2632L8] =  {
-               .channels       = ltc2632l8_channels,
+               .channels       = ltc2632x8_channels,
+               .num_channels   = 2,
                .vref_mv        = 2500,
        },
        [ID_LTC2632H12] = {
-               .channels       = ltc2632h12_channels,
+               .channels       = ltc2632x12_channels,
+               .num_channels   = 2,
                .vref_mv        = 4096,
        },
        [ID_LTC2632H10] = {
-               .channels       = ltc2632h10_channels,
+               .channels       = ltc2632x10_channels,
+               .num_channels   = 2,
                .vref_mv        = 4096,
        },
        [ID_LTC2632H8] =  {
-               .channels       = ltc2632h8_channels,
+               .channels       = ltc2632x8_channels,
+               .num_channels   = 2,
+               .vref_mv        = 4096,
+       },
+       [ID_LTC2636L12] = {
+               .channels       = ltc2632x12_channels,
+               .num_channels   = 8,
+               .vref_mv        = 2500,
+       },
+       [ID_LTC2636L10] = {
+               .channels       = ltc2632x10_channels,
+               .num_channels   = 8,
+               .vref_mv        = 2500,
+       },
+       [ID_LTC2636L8] =  {
+               .channels       = ltc2632x8_channels,
+               .num_channels   = 8,
+               .vref_mv        = 2500,
+       },
+       [ID_LTC2636H12] = {
+               .channels       = ltc2632x12_channels,
+               .num_channels   = 8,
+               .vref_mv        = 4096,
+       },
+       [ID_LTC2636H10] = {
+               .channels       = ltc2632x10_channels,
+               .num_channels   = 8,
+               .vref_mv        = 4096,
+       },
+       [ID_LTC2636H8] =  {
+               .channels       = ltc2632x8_channels,
+               .num_channels   = 8,
                .vref_mv        = 4096,
        },
 };
@@ -291,7 +331,7 @@ static int ltc2632_probe(struct spi_device *spi)
        indio_dev->info = &ltc2632_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = chip_info->channels;
-       indio_dev->num_channels = LTC2632_DAC_CHANNELS;
+       indio_dev->num_channels = chip_info->num_channels;
 
        return iio_device_register(indio_dev);
 }
@@ -316,6 +356,12 @@ static const struct spi_device_id ltc2632_id[] = {
        { "ltc2632-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H12] },
        { "ltc2632-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H10] },
        { "ltc2632-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2632H8] },
+       { "ltc2636-l12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L12] },
+       { "ltc2636-l10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L10] },
+       { "ltc2636-l8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636L8] },
+       { "ltc2636-h12", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H12] },
+       { "ltc2636-h10", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H10] },
+       { "ltc2636-h8", (kernel_ulong_t)&ltc2632_chip_info_tbl[ID_LTC2636H8] },
        {}
 };
 MODULE_DEVICE_TABLE(spi, ltc2632_id);
@@ -339,6 +385,24 @@ static const struct of_device_id ltc2632_of_match[] = {
        }, {
                .compatible = "lltc,ltc2632-h8",
                .data = &ltc2632_chip_info_tbl[ID_LTC2632H8]
+       }, {
+               .compatible = "lltc,ltc2636-l12",
+               .data = &ltc2632_chip_info_tbl[ID_LTC2636L12]
+       }, {
+               .compatible = "lltc,ltc2636-l10",
+               .data = &ltc2632_chip_info_tbl[ID_LTC2636L10]
+       }, {
+               .compatible = "lltc,ltc2636-l8",
+               .data = &ltc2632_chip_info_tbl[ID_LTC2636L8]
+       }, {
+               .compatible = "lltc,ltc2636-h12",
+               .data = &ltc2632_chip_info_tbl[ID_LTC2636H12]
+       }, {
+               .compatible = "lltc,ltc2636-h10",
+               .data = &ltc2632_chip_info_tbl[ID_LTC2636H10]
+       }, {
+               .compatible = "lltc,ltc2636-h8",
+               .data = &ltc2632_chip_info_tbl[ID_LTC2636H8]
        },
        {}
 };
index d5e03a4..a4c967a 100644 (file)
@@ -59,7 +59,7 @@
 struct adis16136_chip_info {
        unsigned int precision;
        unsigned int fullscale;
-       const struct adis_timeout *timeouts;
+       const struct adis_data adis_data;
 };
 
 struct adis16136 {
@@ -466,22 +466,22 @@ static const char * const adis16136_status_error_msgs[] = {
        [ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error",
 };
 
-static const struct adis_data adis16136_data = {
-       .diag_stat_reg = ADIS16136_REG_DIAG_STAT,
-       .glob_cmd_reg = ADIS16136_REG_GLOB_CMD,
-       .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,
-
-       .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,
-
-       .read_delay = 10,
-       .write_delay = 10,
-
-       .status_error_msgs = adis16136_status_error_msgs,
-       .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) |
-               BIT(ADIS16136_DIAG_STAT_SPI_FAIL) |
-               BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) |
-               BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL),
-};
+#define ADIS16136_DATA(_timeouts)                                      \
+{                                                                      \
+       .diag_stat_reg = ADIS16136_REG_DIAG_STAT,                       \
+       .glob_cmd_reg = ADIS16136_REG_GLOB_CMD,                         \
+       .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL,                         \
+       .self_test_reg = ADIS16136_REG_MSC_CTRL,                        \
+       .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST,                 \
+       .read_delay = 10,                                               \
+       .write_delay = 10,                                              \
+       .status_error_msgs = adis16136_status_error_msgs,               \
+       .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) |       \
+               BIT(ADIS16136_DIAG_STAT_SPI_FAIL) |                     \
+               BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) |               \
+               BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL),             \
+       .timeouts = (_timeouts),                                        \
+}
 
 enum adis16136_id {
        ID_ADIS16133,
@@ -506,41 +506,25 @@ static const struct adis16136_chip_info adis16136_chip_info[] = {
        [ID_ADIS16133] = {
                .precision = IIO_DEGREE_TO_RAD(1200),
                .fullscale = 24000,
-               .timeouts = &adis16133_timeouts,
+               .adis_data = ADIS16136_DATA(&adis16133_timeouts),
        },
        [ID_ADIS16135] = {
                .precision = IIO_DEGREE_TO_RAD(300),
                .fullscale = 24000,
-               .timeouts = &adis16133_timeouts,
+               .adis_data = ADIS16136_DATA(&adis16133_timeouts),
        },
        [ID_ADIS16136] = {
                .precision = IIO_DEGREE_TO_RAD(450),
                .fullscale = 24623,
-               .timeouts = &adis16136_timeouts,
+               .adis_data = ADIS16136_DATA(&adis16136_timeouts),
        },
        [ID_ADIS16137] = {
                .precision = IIO_DEGREE_TO_RAD(1000),
                .fullscale = 24609,
-               .timeouts = &adis16136_timeouts,
+               .adis_data = ADIS16136_DATA(&adis16136_timeouts),
        },
 };
 
-static struct adis_data *adis16136_adis_data_alloc(struct adis16136 *st,
-                                                  struct device *dev)
-{
-       struct adis_data *data;
-
-       data = devm_kmalloc(dev, sizeof(struct adis_data), GFP_KERNEL);
-       if (!data)
-               return ERR_PTR(-ENOMEM);
-
-       memcpy(data, &adis16136_data, sizeof(*data));
-
-       data->timeouts = st->chip_info->timeouts;
-
-       return data;
-}
-
 static int adis16136_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
@@ -565,9 +549,7 @@ static int adis16136_probe(struct spi_device *spi)
        indio_dev->info = &adis16136_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       adis16136_data = adis16136_adis_data_alloc(adis16136, &spi->dev);
-       if (IS_ERR(adis16136_data))
-               return PTR_ERR(adis16136_data);
+       adis16136_data = &adis16136->chip_info->adis_data;
 
        ret = adis_init(&adis16136->adis, indio_dev, spi, adis16136_data);
        if (ret)
index be09b3e..9823573 100644 (file)
@@ -346,6 +346,7 @@ static const struct adis_data adis16260_data = {
        .diag_stat_reg = ADIS16260_DIAG_STAT,
 
        .self_test_mask = ADIS16260_MSC_CTRL_MEM_TEST,
+       .self_test_reg = ADIS16260_MSC_CTRL,
        .timeouts = &adis16260_timeouts,
 
        .status_error_msgs = adis1620_status_error_msgs,
index 022bb54..a8afd01 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/mutex.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
@@ -346,8 +347,8 @@ static int adis_self_test(struct adis *adis)
        int ret;
        const struct adis_timeout *timeouts = adis->data->timeouts;
 
-       ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
-                       adis->data->self_test_mask);
+       ret = __adis_write_reg_16(adis, adis->data->self_test_reg,
+                                 adis->data->self_test_mask);
        if (ret) {
                dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
                        ret);
@@ -359,42 +360,71 @@ static int adis_self_test(struct adis *adis)
        ret = __adis_check_status(adis);
 
        if (adis->data->self_test_no_autoclear)
-               __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
+               __adis_write_reg_16(adis, adis->data->self_test_reg, 0x00);
 
        return ret;
 }
 
 /**
- * adis_inital_startup() - Performs device self-test
+ * __adis_initial_startup() - Device initial setup
  * @adis: The adis device
  *
+ * The function performs a HW reset via a reset pin that should be specified
+ * via GPIOLIB. If no pin is configured a SW reset will be performed.
+ * The RST pin for the ADIS devices should be configured as ACTIVE_LOW.
+ *
+ * After the self-test operation is performed, the function will also check
+ * that the product ID is as expected. This assumes that drivers providing
+ * 'prod_id_reg' will also provide the 'prod_id'.
+ *
  * Returns 0 if the device is operational, a negative error code otherwise.
  *
  * This function should be called early on in the device initialization sequence
  * to ensure that the device is in a sane and known state and that it is usable.
  */
-int adis_initial_startup(struct adis *adis)
+int __adis_initial_startup(struct adis *adis)
 {
+       const struct adis_timeout *timeouts = adis->data->timeouts;
+       struct gpio_desc *gpio;
+       uint16_t prod_id;
        int ret;
 
-       mutex_lock(&adis->state_lock);
+       /* check if the device has rst pin low */
+       gpio = devm_gpiod_get_optional(&adis->spi->dev, "reset", GPIOD_ASIS);
+       if (IS_ERR(gpio))
+               return PTR_ERR(gpio);
+
+       if (gpio) {
+               gpiod_set_value_cansleep(gpio, 1);
+               msleep(10);
+               /* bring device out of reset */
+               gpiod_set_value_cansleep(gpio, 0);
+               msleep(timeouts->reset_ms);
+       } else {
+               ret = __adis_reset(adis);
+               if (ret)
+                       return ret;
+       }
 
        ret = adis_self_test(adis);
-       if (ret) {
-               dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
-               __adis_reset(adis);
-               ret = adis_self_test(adis);
-               if (ret) {
-                       dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
-                       goto out_unlock;
-               }
-       }
+       if (ret)
+               return ret;
 
-out_unlock:
-       mutex_unlock(&adis->state_lock);
-       return ret;
+       if (!adis->data->prod_id_reg)
+               return 0;
+
+       ret = adis_read_reg_16(adis, adis->data->prod_id_reg, &prod_id);
+       if (ret)
+               return ret;
+
+       if (prod_id != adis->data->prod_id)
+               dev_warn(&adis->spi->dev,
+                        "Device ID(%u) and product ID(%u) do not match.",
+                        adis->data->prod_id, prod_id);
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(adis_initial_startup);
+EXPORT_SYMBOL_GPL(__adis_initial_startup);
 
 /**
  * adis_single_conversion() - Performs a single sample conversion
index cfb1c19..05e70c1 100644 (file)
@@ -156,7 +156,7 @@ struct adis16400_state;
 
 struct adis16400_chip_info {
        const struct iio_chan_spec *channels;
-       const struct adis_timeout *timeouts;
+       const struct adis_data adis_data;
        const int num_channels;
        const long flags;
        unsigned int gyro_scale_micro;
@@ -930,12 +930,64 @@ static const struct iio_chan_spec adis16334_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
 };
 
+static const char * const adis16400_status_error_msgs[] = {
+       [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
+       [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
+       [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
+       [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
+       [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
+       [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
+       [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active",
+       [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active",
+       [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error",
+       [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error",
+       [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange",
+       [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure",
+       [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed",
+       [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V",
+       [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V",
+};
+
+#define ADIS16400_DATA(_timeouts)                                      \
+{                                                                      \
+       .msc_ctrl_reg = ADIS16400_MSC_CTRL,                             \
+       .glob_cmd_reg = ADIS16400_GLOB_CMD,                             \
+       .diag_stat_reg = ADIS16400_DIAG_STAT,                           \
+       .read_delay = 50,                                               \
+       .write_delay = 50,                                              \
+       .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST,                  \
+       .self_test_reg = ADIS16400_MSC_CTRL,                            \
+       .status_error_msgs = adis16400_status_error_msgs,               \
+       .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) |      \
+               BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) |                   \
+               BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) |                   \
+               BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) |                   \
+               BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) |                   \
+               BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) |                   \
+               BIT(ADIS16400_DIAG_STAT_ALARM2) |                       \
+               BIT(ADIS16400_DIAG_STAT_ALARM1) |                       \
+               BIT(ADIS16400_DIAG_STAT_FLASH_CHK) |                    \
+               BIT(ADIS16400_DIAG_STAT_SELF_TEST) |                    \
+               BIT(ADIS16400_DIAG_STAT_OVERFLOW) |                     \
+               BIT(ADIS16400_DIAG_STAT_SPI_FAIL) |                     \
+               BIT(ADIS16400_DIAG_STAT_FLASH_UPT) |                    \
+               BIT(ADIS16400_DIAG_STAT_POWER_HIGH) |                   \
+               BIT(ADIS16400_DIAG_STAT_POWER_LOW),                     \
+       .timeouts = (_timeouts),                                        \
+}
+
 static const struct adis_timeout adis16300_timeouts = {
        .reset_ms = ADIS16400_STARTUP_DELAY,
        .sw_reset_ms = ADIS16400_STARTUP_DELAY,
        .self_test_ms = ADIS16400_STARTUP_DELAY,
 };
 
+static const struct adis_timeout adis16334_timeouts = {
+       .reset_ms = 60,
+       .sw_reset_ms = 60,
+       .self_test_ms = 14,
+};
+
 static const struct adis_timeout adis16362_timeouts = {
        .reset_ms = 130,
        .sw_reset_ms = 130,
@@ -972,7 +1024,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
-               .timeouts = &adis16300_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16300_timeouts),
        },
        [ADIS16334] = {
                .channels = adis16334_channels,
@@ -985,6 +1037,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 67850, /* 25 C = 0x00 */
                .set_freq = adis16334_set_freq,
                .get_freq = adis16334_get_freq,
+               .adis_data = ADIS16400_DATA(&adis16334_timeouts),
        },
        [ADIS16350] = {
                .channels = adis16350_channels,
@@ -996,7 +1049,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .flags = ADIS16400_NO_BURST | ADIS16400_HAS_SLOW_MODE,
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
-               .timeouts = &adis16300_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16300_timeouts),
        },
        [ADIS16360] = {
                .channels = adis16350_channels,
@@ -1009,7 +1062,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
-               .timeouts = &adis16300_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16300_timeouts),
        },
        [ADIS16362] = {
                .channels = adis16350_channels,
@@ -1022,7 +1075,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
-               .timeouts = &adis16362_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16362_timeouts),
        },
        [ADIS16364] = {
                .channels = adis16350_channels,
@@ -1035,7 +1088,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
-               .timeouts = &adis16362_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16362_timeouts),
        },
        [ADIS16367] = {
                .channels = adis16350_channels,
@@ -1048,7 +1101,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
-               .timeouts = &adis16300_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16300_timeouts),
        },
        [ADIS16400] = {
                .channels = adis16400_channels,
@@ -1060,7 +1113,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
                .set_freq = adis16400_set_freq,
                .get_freq = adis16400_get_freq,
-               .timeouts = &adis16400_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16400_timeouts),
        },
        [ADIS16445] = {
                .channels = adis16445_channels,
@@ -1074,7 +1127,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
                .set_freq = adis16334_set_freq,
                .get_freq = adis16334_get_freq,
-               .timeouts = &adis16445_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16445_timeouts),
        },
        [ADIS16448] = {
                .channels = adis16448_channels,
@@ -1088,7 +1141,7 @@ static struct adis16400_chip_info adis16400_chips[] = {
                .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */
                .set_freq = adis16334_set_freq,
                .get_freq = adis16334_get_freq,
-               .timeouts = &adis16448_timeouts,
+               .adis_data = ADIS16400_DATA(&adis16448_timeouts),
        }
 };
 
@@ -1099,52 +1152,6 @@ static const struct iio_info adis16400_info = {
        .debugfs_reg_access = adis_debugfs_reg_access,
 };
 
-static const char * const adis16400_status_error_msgs[] = {
-       [ADIS16400_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
-       [ADIS16400_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
-       [ADIS16400_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
-       [ADIS16400_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
-       [ADIS16400_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
-       [ADIS16400_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
-       [ADIS16400_DIAG_STAT_ALARM2] = "Alarm 2 active",
-       [ADIS16400_DIAG_STAT_ALARM1] = "Alarm 1 active",
-       [ADIS16400_DIAG_STAT_FLASH_CHK] = "Flash checksum error",
-       [ADIS16400_DIAG_STAT_SELF_TEST] = "Self test error",
-       [ADIS16400_DIAG_STAT_OVERFLOW] = "Sensor overrange",
-       [ADIS16400_DIAG_STAT_SPI_FAIL] = "SPI failure",
-       [ADIS16400_DIAG_STAT_FLASH_UPT] = "Flash update failed",
-       [ADIS16400_DIAG_STAT_POWER_HIGH] = "Power supply above 5.25V",
-       [ADIS16400_DIAG_STAT_POWER_LOW] = "Power supply below 4.75V",
-};
-
-static const struct adis_data adis16400_data = {
-       .msc_ctrl_reg = ADIS16400_MSC_CTRL,
-       .glob_cmd_reg = ADIS16400_GLOB_CMD,
-       .diag_stat_reg = ADIS16400_DIAG_STAT,
-
-       .read_delay = 50,
-       .write_delay = 50,
-
-       .self_test_mask = ADIS16400_MSC_CTRL_MEM_TEST,
-
-       .status_error_msgs = adis16400_status_error_msgs,
-       .status_error_mask = BIT(ADIS16400_DIAG_STAT_ZACCL_FAIL) |
-               BIT(ADIS16400_DIAG_STAT_YACCL_FAIL) |
-               BIT(ADIS16400_DIAG_STAT_XACCL_FAIL) |
-               BIT(ADIS16400_DIAG_STAT_XGYRO_FAIL) |
-               BIT(ADIS16400_DIAG_STAT_YGYRO_FAIL) |
-               BIT(ADIS16400_DIAG_STAT_ZGYRO_FAIL) |
-               BIT(ADIS16400_DIAG_STAT_ALARM2) |
-               BIT(ADIS16400_DIAG_STAT_ALARM1) |
-               BIT(ADIS16400_DIAG_STAT_FLASH_CHK) |
-               BIT(ADIS16400_DIAG_STAT_SELF_TEST) |
-               BIT(ADIS16400_DIAG_STAT_OVERFLOW) |
-               BIT(ADIS16400_DIAG_STAT_SPI_FAIL) |
-               BIT(ADIS16400_DIAG_STAT_FLASH_UPT) |
-               BIT(ADIS16400_DIAG_STAT_POWER_HIGH) |
-               BIT(ADIS16400_DIAG_STAT_POWER_LOW),
-};
-
 static void adis16400_setup_chan_mask(struct adis16400_state *st)
 {
        const struct adis16400_chip_info *chip_info = st->variant;
@@ -1158,23 +1165,6 @@ static void adis16400_setup_chan_mask(struct adis16400_state *st)
                        st->avail_scan_mask[0] |= BIT(ch->scan_index);
        }
 }
-
-static struct adis_data *adis16400_adis_data_alloc(struct adis16400_state *st,
-                                                  struct device *dev)
-{
-       struct adis_data *data;
-
-       data = devm_kmalloc(dev, sizeof(struct adis_data), GFP_KERNEL);
-       if (!data)
-               return ERR_PTR(-ENOMEM);
-
-       memcpy(data, &adis16400_data, sizeof(*data));
-
-       data->timeouts = st->variant->timeouts;
-
-       return data;
-}
-
 static int adis16400_probe(struct spi_device *spi)
 {
        struct adis16400_state *st;
@@ -1207,9 +1197,7 @@ static int adis16400_probe(struct spi_device *spi)
                        st->adis.burst->extra_len = sizeof(u16);
        }
 
-       adis16400_data = adis16400_adis_data_alloc(st, &spi->dev);
-       if (IS_ERR(adis16400_data))
-               return PTR_ERR(adis16400_data);
+       adis16400_data = &st->variant->adis_data;
 
        ret = adis_init(&st->adis, indio_dev, spi, adis16400_data);
        if (ret)
index 9539cfe..0027683 100644 (file)
@@ -333,40 +333,6 @@ static int adis16460_enable_irq(struct adis *adis, bool enable)
        return 0;
 }
 
-static int adis16460_initial_setup(struct iio_dev *indio_dev)
-{
-       struct adis16460 *st = iio_priv(indio_dev);
-       uint16_t prod_id;
-       unsigned int device_id;
-       int ret;
-
-       adis_reset(&st->adis);
-       msleep(222);
-
-       ret = adis_write_reg_16(&st->adis, ADIS16460_REG_GLOB_CMD, BIT(1));
-       if (ret)
-               return ret;
-       msleep(75);
-
-       ret = adis_check_status(&st->adis);
-       if (ret)
-               return ret;
-
-       ret = adis_read_reg_16(&st->adis, ADIS16460_REG_PROD_ID, &prod_id);
-       if (ret)
-               return ret;
-
-       ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
-       if (ret != 1)
-               return -EINVAL;
-
-       if (prod_id != device_id)
-               dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
-                               device_id, prod_id);
-
-       return 0;
-}
-
 #define ADIS16460_DIAG_STAT_IN_CLK_OOS 7
 #define ADIS16460_DIAG_STAT_FLASH_MEM  6
 #define ADIS16460_DIAG_STAT_SELF_TEST  5
@@ -392,6 +358,10 @@ static const struct adis_timeout adis16460_timeouts = {
 static const struct adis_data adis16460_data = {
        .diag_stat_reg = ADIS16460_REG_DIAG_STAT,
        .glob_cmd_reg = ADIS16460_REG_GLOB_CMD,
+       .prod_id_reg = ADIS16460_REG_PROD_ID,
+       .prod_id = 16460,
+       .self_test_mask = BIT(2),
+       .self_test_reg = ADIS16460_REG_GLOB_CMD,
        .has_paging = false,
        .read_delay = 5,
        .write_delay = 5,
@@ -439,7 +409,7 @@ static int adis16460_probe(struct spi_device *spi)
 
        adis16460_enable_irq(&st->adis, 0);
 
-       ret = adis16460_initial_setup(indio_dev);
+       ret = __adis_initial_startup(&st->adis);
        if (ret)
                goto error_cleanup_buffer;
 
index dac87f1..cfae0e4 100644 (file)
@@ -138,7 +138,7 @@ struct adis16480_chip_info {
        unsigned int max_dec_rate;
        const unsigned int *filter_freqs;
        bool has_pps_clk_mode;
-       const struct adis_timeout *timeouts;
+       const struct adis_data adis_data;
 };
 
 enum adis16480_int_pin {
@@ -796,6 +796,58 @@ enum adis16480_variant {
        ADIS16497_3,
 };
 
+#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
+#define ADIS16480_DIAG_STAT_YGYRO_FAIL 1
+#define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2
+#define ADIS16480_DIAG_STAT_XACCL_FAIL 3
+#define ADIS16480_DIAG_STAT_YACCL_FAIL 4
+#define ADIS16480_DIAG_STAT_ZACCL_FAIL 5
+#define ADIS16480_DIAG_STAT_XMAGN_FAIL 8
+#define ADIS16480_DIAG_STAT_YMAGN_FAIL 9
+#define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10
+#define ADIS16480_DIAG_STAT_BARO_FAIL 11
+
+static const char * const adis16480_status_error_msgs[] = {
+       [ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
+       [ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
+       [ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
+       [ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
+       [ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
+       [ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
+       [ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure",
+       [ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure",
+       [ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure",
+       [ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure",
+};
+
+static int adis16480_enable_irq(struct adis *adis, bool enable);
+
+#define ADIS16480_DATA(_prod_id, _timeouts)                            \
+{                                                                      \
+       .diag_stat_reg = ADIS16480_REG_DIAG_STS,                        \
+       .glob_cmd_reg = ADIS16480_REG_GLOB_CMD,                         \
+       .prod_id_reg = ADIS16480_REG_PROD_ID,                           \
+       .prod_id = (_prod_id),                                          \
+       .has_paging = true,                                             \
+       .read_delay = 5,                                                \
+       .write_delay = 5,                                               \
+       .self_test_mask = BIT(1),                                       \
+       .self_test_reg = ADIS16480_REG_GLOB_CMD,                        \
+       .status_error_msgs = adis16480_status_error_msgs,               \
+       .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) |      \
+               BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) |                   \
+               BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) |                   \
+               BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) |                   \
+               BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) |                   \
+               BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) |                   \
+               BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) |                   \
+               BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) |                   \
+               BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) |                   \
+               BIT(ADIS16480_DIAG_STAT_BARO_FAIL),                     \
+       .enable_irq = adis16480_enable_irq,                             \
+       .timeouts = (_timeouts),                                        \
+}
+
 static const struct adis_timeout adis16485_timeouts = {
        .reset_ms = 560,
        .sw_reset_ms = 120,
@@ -838,7 +890,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .int_clk = 2460000,
                .max_dec_rate = 2048,
                .filter_freqs = adis16480_def_filter_freqs,
-               .timeouts = &adis16485_timeouts,
+               .adis_data = ADIS16480_DATA(16375, &adis16485_timeouts),
        },
        [ADIS16480] = {
                .channels = adis16480_channels,
@@ -851,7 +903,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .int_clk = 2460000,
                .max_dec_rate = 2048,
                .filter_freqs = adis16480_def_filter_freqs,
-               .timeouts = &adis16480_timeouts,
+               .adis_data = ADIS16480_DATA(16480, &adis16480_timeouts),
        },
        [ADIS16485] = {
                .channels = adis16485_channels,
@@ -864,7 +916,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .int_clk = 2460000,
                .max_dec_rate = 2048,
                .filter_freqs = adis16480_def_filter_freqs,
-               .timeouts = &adis16485_timeouts,
+               .adis_data = ADIS16480_DATA(16485, &adis16485_timeouts),
        },
        [ADIS16488] = {
                .channels = adis16480_channels,
@@ -877,7 +929,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .int_clk = 2460000,
                .max_dec_rate = 2048,
                .filter_freqs = adis16480_def_filter_freqs,
-               .timeouts = &adis16485_timeouts,
+               .adis_data = ADIS16480_DATA(16488, &adis16485_timeouts),
        },
        [ADIS16490] = {
                .channels = adis16485_channels,
@@ -891,7 +943,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .max_dec_rate = 4250,
                .filter_freqs = adis16495_def_filter_freqs,
                .has_pps_clk_mode = true,
-               .timeouts = &adis16495_timeouts,
+               .adis_data = ADIS16480_DATA(16490, &adis16495_timeouts),
        },
        [ADIS16495_1] = {
                .channels = adis16485_channels,
@@ -905,7 +957,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .max_dec_rate = 4250,
                .filter_freqs = adis16495_def_filter_freqs,
                .has_pps_clk_mode = true,
-               .timeouts = &adis16495_1_timeouts,
+               .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts),
        },
        [ADIS16495_2] = {
                .channels = adis16485_channels,
@@ -919,7 +971,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .max_dec_rate = 4250,
                .filter_freqs = adis16495_def_filter_freqs,
                .has_pps_clk_mode = true,
-               .timeouts = &adis16495_1_timeouts,
+               .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts),
        },
        [ADIS16495_3] = {
                .channels = adis16485_channels,
@@ -933,7 +985,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .max_dec_rate = 4250,
                .filter_freqs = adis16495_def_filter_freqs,
                .has_pps_clk_mode = true,
-               .timeouts = &adis16495_1_timeouts,
+               .adis_data = ADIS16480_DATA(16495, &adis16495_1_timeouts),
        },
        [ADIS16497_1] = {
                .channels = adis16485_channels,
@@ -947,7 +999,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .max_dec_rate = 4250,
                .filter_freqs = adis16495_def_filter_freqs,
                .has_pps_clk_mode = true,
-               .timeouts = &adis16495_1_timeouts,
+               .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts),
        },
        [ADIS16497_2] = {
                .channels = adis16485_channels,
@@ -961,7 +1013,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .max_dec_rate = 4250,
                .filter_freqs = adis16495_def_filter_freqs,
                .has_pps_clk_mode = true,
-               .timeouts = &adis16495_1_timeouts,
+               .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts),
        },
        [ADIS16497_3] = {
                .channels = adis16485_channels,
@@ -975,7 +1027,7 @@ static const struct adis16480_chip_info adis16480_chip_info[] = {
                .max_dec_rate = 4250,
                .filter_freqs = adis16495_def_filter_freqs,
                .has_pps_clk_mode = true,
-               .timeouts = &adis16495_1_timeouts,
+               .adis_data = ADIS16480_DATA(16497, &adis16495_1_timeouts),
        },
 };
 
@@ -1014,87 +1066,6 @@ static int adis16480_enable_irq(struct adis *adis, bool enable)
        return __adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val);
 }
 
-static int adis16480_initial_setup(struct iio_dev *indio_dev)
-{
-       struct adis16480 *st = iio_priv(indio_dev);
-       uint16_t prod_id;
-       unsigned int device_id;
-       int ret;
-
-       adis_reset(&st->adis);
-       msleep(70);
-
-       ret = adis_write_reg_16(&st->adis, ADIS16480_REG_GLOB_CMD, BIT(1));
-       if (ret)
-               return ret;
-       msleep(30);
-
-       ret = adis_check_status(&st->adis);
-       if (ret)
-               return ret;
-
-       ret = adis_read_reg_16(&st->adis, ADIS16480_REG_PROD_ID, &prod_id);
-       if (ret)
-               return ret;
-
-       ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
-       if (ret != 1)
-               return -EINVAL;
-
-       if (prod_id != device_id)
-               dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
-                               device_id, prod_id);
-
-       return 0;
-}
-
-#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
-#define ADIS16480_DIAG_STAT_YGYRO_FAIL 1
-#define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2
-#define ADIS16480_DIAG_STAT_XACCL_FAIL 3
-#define ADIS16480_DIAG_STAT_YACCL_FAIL 4
-#define ADIS16480_DIAG_STAT_ZACCL_FAIL 5
-#define ADIS16480_DIAG_STAT_XMAGN_FAIL 8
-#define ADIS16480_DIAG_STAT_YMAGN_FAIL 9
-#define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10
-#define ADIS16480_DIAG_STAT_BARO_FAIL 11
-
-static const char * const adis16480_status_error_msgs[] = {
-       [ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
-       [ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
-       [ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
-       [ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
-       [ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
-       [ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
-       [ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure",
-       [ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure",
-       [ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure",
-       [ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure",
-};
-
-static const struct adis_data adis16480_data = {
-       .diag_stat_reg = ADIS16480_REG_DIAG_STS,
-       .glob_cmd_reg = ADIS16480_REG_GLOB_CMD,
-       .has_paging = true,
-
-       .read_delay = 5,
-       .write_delay = 5,
-
-       .status_error_msgs = adis16480_status_error_msgs,
-       .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) |
-               BIT(ADIS16480_DIAG_STAT_BARO_FAIL),
-
-       .enable_irq = adis16480_enable_irq,
-};
-
 static int adis16480_config_irq_pin(struct device_node *of_node,
                                    struct adis16480 *st)
 {
@@ -1245,22 +1216,6 @@ static int adis16480_get_ext_clocks(struct adis16480 *st)
        return 0;
 }
 
-static struct adis_data *adis16480_adis_data_alloc(struct adis16480 *st,
-                                                  struct device *dev)
-{
-       struct adis_data *data;
-
-       data = devm_kmalloc(dev, sizeof(struct adis_data), GFP_KERNEL);
-       if (!data)
-               return ERR_PTR(-ENOMEM);
-
-       memcpy(data, &adis16480_data, sizeof(*data));
-
-       data->timeouts = st->chip_info->timeouts;
-
-       return data;
-}
-
 static int adis16480_probe(struct spi_device *spi)
 {
        const struct spi_device_id *id = spi_get_device_id(spi);
@@ -1285,26 +1240,28 @@ static int adis16480_probe(struct spi_device *spi)
        indio_dev->info = &adis16480_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       adis16480_data = adis16480_adis_data_alloc(st, &spi->dev);
-       if (IS_ERR(adis16480_data))
-               return PTR_ERR(adis16480_data);
+       adis16480_data = &st->chip_info->adis_data;
 
        ret = adis_init(&st->adis, indio_dev, spi, adis16480_data);
        if (ret)
                return ret;
 
-       ret = adis16480_config_irq_pin(spi->dev.of_node, st);
+       ret = __adis_initial_startup(&st->adis);
        if (ret)
                return ret;
 
+       ret = adis16480_config_irq_pin(spi->dev.of_node, st);
+       if (ret)
+               goto error_stop_device;
+
        ret = adis16480_get_ext_clocks(st);
        if (ret)
-               return ret;
+               goto error_stop_device;
 
        if (!IS_ERR_OR_NULL(st->ext_clk)) {
                ret = adis16480_ext_clk_config(st, spi->dev.of_node, true);
                if (ret)
-                       return ret;
+                       goto error_stop_device;
 
                st->clk_freq = clk_get_rate(st->ext_clk);
                st->clk_freq *= 1000; /* micro */
@@ -1316,24 +1273,20 @@ static int adis16480_probe(struct spi_device *spi)
        if (ret)
                goto error_clk_disable_unprepare;
 
-       ret = adis16480_initial_setup(indio_dev);
-       if (ret)
-               goto error_cleanup_buffer;
-
        ret = iio_device_register(indio_dev);
        if (ret)
-               goto error_stop_device;
+               goto error_cleanup_buffer;
 
        adis16480_debugfs_init(indio_dev);
 
        return 0;
 
-error_stop_device:
-       adis16480_stop_device(indio_dev);
 error_cleanup_buffer:
        adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
 error_clk_disable_unprepare:
        clk_disable_unprepare(st->ext_clk);
+error_stop_device:
+       adis16480_stop_device(indio_dev);
        return ret;
 }
 
index 3f4dd5c..04e5e2a 100644 (file)
@@ -97,7 +97,8 @@ int adis_update_scan_mode(struct iio_dev *indio_dev,
                if (j != scan_count)
                        adis->xfer[j].cs_change = 1;
                adis->xfer[j].len = 2;
-               adis->xfer[j].delay_usecs = adis->data->read_delay;
+               adis->xfer[j].delay.value = adis->data->read_delay;
+               adis->xfer[j].delay.unit = SPI_DELAY_UNIT_USECS;
                if (j < scan_count)
                        adis->xfer[j].tx_buf = &tx[j];
                if (j >= 1)
index 017bc0f..7137ea6 100644 (file)
@@ -15,9 +15,9 @@ config INV_MPU6050_I2C
        select INV_MPU6050_IIO
        select REGMAP_I2C
        help
-         This driver supports the Invensense MPU6050/6500/6515,
-         MPU9150/9250/9255 and ICM20608/20602 motion tracking devices
-         over I2C.
+         This driver supports the Invensense MPU6050/9150,
+         MPU6500/6515/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690 and
+         IAM20680 motion tracking devices over I2C.
          This driver can be built as a module. The module will be called
          inv-mpu6050-i2c.
 
@@ -27,8 +27,8 @@ config INV_MPU6050_SPI
        select INV_MPU6050_IIO
        select REGMAP_SPI
        help
-         This driver supports the Invensense MPU6000/6500/6515,
-         MPU9250/9255 and ICM20608/20602 motion tracking devices
-         over SPI.
+         This driver supports the Invensense MPU6000,
+         MPU6500/6515/9250/9255, ICM20608/20609/20689, ICM20602/ICM20690 and
+         IAM20680 motion tracking devices over SPI.
          This driver can be built as a module. The module will be called
          inv-mpu6050-spi.
index 5096fc4..7cb9ff3 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include "inv_mpu_iio.h"
 #include "inv_mpu_magn.h"
 
@@ -99,9 +101,31 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
 };
 
 static const struct inv_mpu6050_chip_config chip_config_6050 = {
+       .clk = INV_CLK_INTERNAL,
        .fsr = INV_MPU6050_FSR_2000DPS,
        .lpf = INV_MPU6050_FILTER_20HZ,
-       .divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE),
+       .divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(50),
+       .gyro_en = true,
+       .accl_en = true,
+       .temp_en = true,
+       .magn_en = false,
+       .gyro_fifo_enable = false,
+       .accl_fifo_enable = false,
+       .temp_fifo_enable = false,
+       .magn_fifo_enable = false,
+       .accl_fs = INV_MPU6050_FS_02G,
+       .user_ctrl = 0,
+};
+
+static const struct inv_mpu6050_chip_config chip_config_6500 = {
+       .clk = INV_CLK_PLL,
+       .fsr = INV_MPU6050_FSR_2000DPS,
+       .lpf = INV_MPU6050_FILTER_20HZ,
+       .divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(50),
+       .gyro_en = true,
+       .accl_en = true,
+       .temp_en = true,
+       .magn_en = false,
        .gyro_fifo_enable = false,
        .accl_fifo_enable = false,
        .temp_fifo_enable = false,
@@ -124,7 +148,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
                .whoami = INV_MPU6500_WHOAMI_VALUE,
                .name = "MPU6500",
                .reg = &reg_set_6500,
-               .config = &chip_config_6050,
+               .config = &chip_config_6500,
                .fifo_size = 512,
                .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
        },
@@ -132,7 +156,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
                .whoami = INV_MPU6515_WHOAMI_VALUE,
                .name = "MPU6515",
                .reg = &reg_set_6500,
-               .config = &chip_config_6050,
+               .config = &chip_config_6500,
                .fifo_size = 512,
                .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
        },
@@ -156,7 +180,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
                .whoami = INV_MPU9250_WHOAMI_VALUE,
                .name = "MPU9250",
                .reg = &reg_set_6500,
-               .config = &chip_config_6050,
+               .config = &chip_config_6500,
                .fifo_size = 512,
                .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
        },
@@ -164,7 +188,7 @@ static const struct inv_mpu6050_hw hw_info[] = {
                .whoami = INV_MPU9255_WHOAMI_VALUE,
                .name = "MPU9255",
                .reg = &reg_set_6500,
-               .config = &chip_config_6050,
+               .config = &chip_config_6500,
                .fifo_size = 512,
                .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE},
        },
@@ -172,104 +196,242 @@ static const struct inv_mpu6050_hw hw_info[] = {
                .whoami = INV_ICM20608_WHOAMI_VALUE,
                .name = "ICM20608",
                .reg = &reg_set_6500,
-               .config = &chip_config_6050,
+               .config = &chip_config_6500,
                .fifo_size = 512,
                .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
        },
        {
+               .whoami = INV_ICM20609_WHOAMI_VALUE,
+               .name = "ICM20609",
+               .reg = &reg_set_6500,
+               .config = &chip_config_6500,
+               .fifo_size = 4 * 1024,
+               .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+       },
+       {
+               .whoami = INV_ICM20689_WHOAMI_VALUE,
+               .name = "ICM20689",
+               .reg = &reg_set_6500,
+               .config = &chip_config_6500,
+               .fifo_size = 4 * 1024,
+               .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+       },
+       {
                .whoami = INV_ICM20602_WHOAMI_VALUE,
                .name = "ICM20602",
                .reg = &reg_set_icm20602,
-               .config = &chip_config_6050,
+               .config = &chip_config_6500,
                .fifo_size = 1008,
                .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
        },
+       {
+               .whoami = INV_ICM20690_WHOAMI_VALUE,
+               .name = "ICM20690",
+               .reg = &reg_set_6500,
+               .config = &chip_config_6500,
+               .fifo_size = 1024,
+               .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+       },
+       {
+               .whoami = INV_IAM20680_WHOAMI_VALUE,
+               .name = "IAM20680",
+               .reg = &reg_set_6500,
+               .config = &chip_config_6500,
+               .fifo_size = 512,
+               .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE},
+       },
 };
 
-int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
+static int inv_mpu6050_pwr_mgmt_1_write(struct inv_mpu6050_state *st, bool sleep,
+                                       int clock, int temp_dis)
 {
-       unsigned int d, mgmt_1;
-       int result;
-       /*
-        * switch clock needs to be careful. Only when gyro is on, can
-        * clock source be switched to gyro. Otherwise, it must be set to
-        * internal clock
-        */
-       if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) {
-               result = regmap_read(st->map, st->reg->pwr_mgmt_1, &mgmt_1);
-               if (result)
-                       return result;
+       u8 val;
+
+       if (clock < 0)
+               clock = st->chip_config.clk;
+       if (temp_dis < 0)
+               temp_dis = !st->chip_config.temp_en;
 
-               mgmt_1 &= ~INV_MPU6050_BIT_CLK_MASK;
+       val = clock & INV_MPU6050_BIT_CLK_MASK;
+       if (temp_dis)
+               val |= INV_MPU6050_BIT_TEMP_DIS;
+       if (sleep)
+               val |= INV_MPU6050_BIT_SLEEP;
+
+       dev_dbg(regmap_get_device(st->map), "pwr_mgmt_1: 0x%x\n", val);
+       return regmap_write(st->map, st->reg->pwr_mgmt_1, val);
+}
+
+static int inv_mpu6050_clock_switch(struct inv_mpu6050_state *st,
+                                   unsigned int clock)
+{
+       int ret;
+
+       switch (st->chip_type) {
+       case INV_MPU6050:
+       case INV_MPU6000:
+       case INV_MPU9150:
+               /* old chips: switch clock manually */
+               ret = inv_mpu6050_pwr_mgmt_1_write(st, false, clock, -1);
+               if (ret)
+                       return ret;
+               st->chip_config.clk = clock;
+               break;
+       default:
+               /* automatic clock switching, nothing to do */
+               break;
        }
 
-       if ((mask == INV_MPU6050_BIT_PWR_GYRO_STBY) && (!en)) {
-               /*
-                * turning off gyro requires switch to internal clock first.
-                * Then turn off gyro engine
-                */
-               mgmt_1 |= INV_CLK_INTERNAL;
-               result = regmap_write(st->map, st->reg->pwr_mgmt_1, mgmt_1);
-               if (result)
-                       return result;
+       return 0;
+}
+
+int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
+                             unsigned int mask)
+{
+       unsigned int sleep;
+       u8 pwr_mgmt2, user_ctrl;
+       int ret;
+
+       /* delete useless requests */
+       if (mask & INV_MPU6050_SENSOR_ACCL && en == st->chip_config.accl_en)
+               mask &= ~INV_MPU6050_SENSOR_ACCL;
+       if (mask & INV_MPU6050_SENSOR_GYRO && en == st->chip_config.gyro_en)
+               mask &= ~INV_MPU6050_SENSOR_GYRO;
+       if (mask & INV_MPU6050_SENSOR_TEMP && en == st->chip_config.temp_en)
+               mask &= ~INV_MPU6050_SENSOR_TEMP;
+       if (mask & INV_MPU6050_SENSOR_MAGN && en == st->chip_config.magn_en)
+               mask &= ~INV_MPU6050_SENSOR_MAGN;
+       if (mask == 0)
+               return 0;
+
+       /* turn on/off temperature sensor */
+       if (mask & INV_MPU6050_SENSOR_TEMP) {
+               ret = inv_mpu6050_pwr_mgmt_1_write(st, false, -1, !en);
+               if (ret)
+                       return ret;
+               st->chip_config.temp_en = en;
        }
 
-       result = regmap_read(st->map, st->reg->pwr_mgmt_2, &d);
-       if (result)
-               return result;
-       if (en)
-               d &= ~mask;
-       else
-               d |= mask;
-       result = regmap_write(st->map, st->reg->pwr_mgmt_2, d);
-       if (result)
-               return result;
+       /* update user_crtl for driving magnetometer */
+       if (mask & INV_MPU6050_SENSOR_MAGN) {
+               user_ctrl = st->chip_config.user_ctrl;
+               if (en)
+                       user_ctrl |= INV_MPU6050_BIT_I2C_MST_EN;
+               else
+                       user_ctrl &= ~INV_MPU6050_BIT_I2C_MST_EN;
+               ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
+               if (ret)
+                       return ret;
+               st->chip_config.user_ctrl = user_ctrl;
+               st->chip_config.magn_en = en;
+       }
 
-       if (en) {
-               /* Wait for output to stabilize */
-               msleep(INV_MPU6050_TEMP_UP_TIME);
-               if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) {
-                       /* switch internal clock to PLL */
-                       mgmt_1 |= INV_CLK_PLL;
-                       result = regmap_write(st->map,
-                                             st->reg->pwr_mgmt_1, mgmt_1);
-                       if (result)
-                               return result;
+       /* manage accel & gyro engines */
+       if (mask & (INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO)) {
+               /* compute power management 2 current value */
+               pwr_mgmt2 = 0;
+               if (!st->chip_config.accl_en)
+                       pwr_mgmt2 |= INV_MPU6050_BIT_PWR_ACCL_STBY;
+               if (!st->chip_config.gyro_en)
+                       pwr_mgmt2 |= INV_MPU6050_BIT_PWR_GYRO_STBY;
+
+               /* update to new requested value */
+               if (mask & INV_MPU6050_SENSOR_ACCL) {
+                       if (en)
+                               pwr_mgmt2 &= ~INV_MPU6050_BIT_PWR_ACCL_STBY;
+                       else
+                               pwr_mgmt2 |= INV_MPU6050_BIT_PWR_ACCL_STBY;
+               }
+               if (mask & INV_MPU6050_SENSOR_GYRO) {
+                       if (en)
+                               pwr_mgmt2 &= ~INV_MPU6050_BIT_PWR_GYRO_STBY;
+                       else
+                               pwr_mgmt2 |= INV_MPU6050_BIT_PWR_GYRO_STBY;
+               }
+
+               /* switch clock to internal when turning gyro off */
+               if (mask & INV_MPU6050_SENSOR_GYRO && !en) {
+                       ret = inv_mpu6050_clock_switch(st, INV_CLK_INTERNAL);
+                       if (ret)
+                               return ret;
+               }
+
+               /* update sensors engine */
+               dev_dbg(regmap_get_device(st->map), "pwr_mgmt_2: 0x%x\n",
+                       pwr_mgmt2);
+               ret = regmap_write(st->map, st->reg->pwr_mgmt_2, pwr_mgmt2);
+               if (ret)
+                       return ret;
+               if (mask & INV_MPU6050_SENSOR_ACCL)
+                       st->chip_config.accl_en = en;
+               if (mask & INV_MPU6050_SENSOR_GYRO)
+                       st->chip_config.gyro_en = en;
+
+               /* compute required time to have sensors stabilized */
+               sleep = 0;
+               if (en) {
+                       if (mask & INV_MPU6050_SENSOR_ACCL) {
+                               if (sleep < INV_MPU6050_ACCEL_UP_TIME)
+                                       sleep = INV_MPU6050_ACCEL_UP_TIME;
+                       }
+                       if (mask & INV_MPU6050_SENSOR_GYRO) {
+                               if (sleep < INV_MPU6050_GYRO_UP_TIME)
+                                       sleep = INV_MPU6050_GYRO_UP_TIME;
+                       }
+               } else {
+                       if (mask & INV_MPU6050_SENSOR_GYRO) {
+                               if (sleep < INV_MPU6050_GYRO_DOWN_TIME)
+                                       sleep = INV_MPU6050_GYRO_DOWN_TIME;
+                       }
+               }
+               if (sleep)
+                       msleep(sleep);
+
+               /* switch clock to PLL when turning gyro on */
+               if (mask & INV_MPU6050_SENSOR_GYRO && en) {
+                       ret = inv_mpu6050_clock_switch(st, INV_CLK_PLL);
+                       if (ret)
+                               return ret;
                }
        }
 
        return 0;
 }
 
-int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
+static int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st,
+                                    bool power_on)
 {
        int result;
 
-       if (power_on) {
-               if (!st->powerup_count) {
-                       result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0);
-                       if (result)
-                               return result;
-                       usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
-                                    INV_MPU6050_REG_UP_TIME_MAX);
-               }
-               st->powerup_count++;
-       } else {
-               if (st->powerup_count == 1) {
-                       result = regmap_write(st->map, st->reg->pwr_mgmt_1,
-                                             INV_MPU6050_BIT_SLEEP);
-                       if (result)
-                               return result;
-               }
-               st->powerup_count--;
-       }
+       result = inv_mpu6050_pwr_mgmt_1_write(st, !power_on, -1, -1);
+       if (result)
+               return result;
 
-       dev_dbg(regmap_get_device(st->map), "set power %d, count=%u\n",
-               power_on, st->powerup_count);
+       if (power_on)
+               usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
+                            INV_MPU6050_REG_UP_TIME_MAX);
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(inv_mpu6050_set_power_itg);
+
+static int inv_mpu6050_set_gyro_fsr(struct inv_mpu6050_state *st,
+                                   enum inv_mpu6050_fsr_e val)
+{
+       unsigned int gyro_shift;
+       u8 data;
+
+       switch (st->chip_type) {
+       case INV_ICM20690:
+               gyro_shift = INV_ICM20690_GYRO_CONFIG_FSR_SHIFT;
+               break;
+       default:
+               gyro_shift = INV_MPU6050_GYRO_CONFIG_FSR_SHIFT;
+               break;
+       }
+
+       data = val << gyro_shift;
+       return regmap_write(st->map, st->reg->gyro_config, data);
+}
 
 /**
  *  inv_mpu6050_set_lpf_regs() - set low pass filter registers, chip dependent
@@ -286,20 +448,23 @@ static int inv_mpu6050_set_lpf_regs(struct inv_mpu6050_state *st,
        if (result)
                return result;
 
+       /* set accel lpf */
        switch (st->chip_type) {
        case INV_MPU6050:
        case INV_MPU6000:
        case INV_MPU9150:
                /* old chips, nothing to do */
-               result = 0;
+               return 0;
+       case INV_ICM20689:
+       case INV_ICM20690:
+               /* set FIFO size to maximum value */
+               val |= INV_ICM20689_BITS_FIFO_SIZE_MAX;
                break;
        default:
-               /* set accel lpf */
-               result = regmap_write(st->map, st->reg->accel_lpf, val);
                break;
        }
 
-       return result;
+       return regmap_write(st->map, st->reg->accel_lpf, val);
 }
 
 /**
@@ -317,35 +482,28 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
        u8 d;
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
-       result = inv_mpu6050_set_power_itg(st, true);
+       result = inv_mpu6050_set_gyro_fsr(st, st->chip_config.fsr);
        if (result)
                return result;
-       d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
-       result = regmap_write(st->map, st->reg->gyro_config, d);
-       if (result)
-               goto error_power_off;
 
-       result = inv_mpu6050_set_lpf_regs(st, INV_MPU6050_FILTER_20HZ);
+       result = inv_mpu6050_set_lpf_regs(st, st->chip_config.lpf);
        if (result)
-               goto error_power_off;
+               return result;
 
-       d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE);
+       d = st->chip_config.divider;
        result = regmap_write(st->map, st->reg->sample_rate_div, d);
        if (result)
-               goto error_power_off;
+               return result;
 
-       d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
+       d = (st->chip_config.accl_fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
        result = regmap_write(st->map, st->reg->accl_config, d);
        if (result)
-               goto error_power_off;
+               return result;
 
        result = regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask);
        if (result)
                return result;
 
-       memcpy(&st->chip_config, hw_info[st->chip_type].config,
-              sizeof(struct inv_mpu6050_chip_config));
-
        /*
         * Internal chip period is 1ms (1kHz).
         * Let's use at the beginning the theorical value before measuring
@@ -356,13 +514,9 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
        /* magn chip init, noop if not present in the chip */
        result = inv_mpu_magn_probe(st);
        if (result)
-               goto error_power_off;
-
-       return inv_mpu6050_set_power_itg(st, false);
+               return result;
 
-error_power_off:
-       inv_mpu6050_set_power_itg(st, false);
-       return result;
+       return 0;
 }
 
 static int inv_mpu6050_sensor_set(struct inv_mpu6050_state  *st, int reg,
@@ -399,45 +553,85 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
                                         int *val)
 {
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
+       struct device *pdev = regmap_get_device(st->map);
+       unsigned int freq_hz, period_us, min_sleep_us, max_sleep_us;
        int result;
        int ret;
 
-       result = inv_mpu6050_set_power_itg(st, true);
-       if (result)
+       /* compute sample period */
+       freq_hz = INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
+       period_us = 1000000 / freq_hz;
+
+       result = pm_runtime_get_sync(pdev);
+       if (result < 0) {
+               pm_runtime_put_noidle(pdev);
                return result;
+       }
 
        switch (chan->type) {
        case IIO_ANGL_VEL:
-               result = inv_mpu6050_switch_engine(st, true,
-                               INV_MPU6050_BIT_PWR_GYRO_STBY);
-               if (result)
-                       goto error_power_off;
+               if (!st->chip_config.gyro_en) {
+                       result = inv_mpu6050_switch_engine(st, true,
+                                       INV_MPU6050_SENSOR_GYRO);
+                       if (result)
+                               goto error_power_off;
+                       /* need to wait 2 periods to have first valid sample */
+                       min_sleep_us = 2 * period_us;
+                       max_sleep_us = 2 * (period_us + period_us / 2);
+                       usleep_range(min_sleep_us, max_sleep_us);
+               }
                ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
                                              chan->channel2, val);
-               result = inv_mpu6050_switch_engine(st, false,
-                               INV_MPU6050_BIT_PWR_GYRO_STBY);
-               if (result)
-                       goto error_power_off;
                break;
        case IIO_ACCEL:
-               result = inv_mpu6050_switch_engine(st, true,
-                               INV_MPU6050_BIT_PWR_ACCL_STBY);
-               if (result)
-                       goto error_power_off;
+               if (!st->chip_config.accl_en) {
+                       result = inv_mpu6050_switch_engine(st, true,
+                                       INV_MPU6050_SENSOR_ACCL);
+                       if (result)
+                               goto error_power_off;
+                       /* wait 1 period for first sample availability */
+                       min_sleep_us = period_us;
+                       max_sleep_us = period_us + period_us / 2;
+                       usleep_range(min_sleep_us, max_sleep_us);
+               }
                ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
                                              chan->channel2, val);
-               result = inv_mpu6050_switch_engine(st, false,
-                               INV_MPU6050_BIT_PWR_ACCL_STBY);
-               if (result)
-                       goto error_power_off;
                break;
        case IIO_TEMP:
-               /* wait for stablization */
-               msleep(INV_MPU6050_SENSOR_UP_TIME);
+               /* temperature sensor work only with accel and/or gyro */
+               if (!st->chip_config.accl_en && !st->chip_config.gyro_en) {
+                       result = -EBUSY;
+                       goto error_power_off;
+               }
+               if (!st->chip_config.temp_en) {
+                       result = inv_mpu6050_switch_engine(st, true,
+                                       INV_MPU6050_SENSOR_TEMP);
+                       if (result)
+                               goto error_power_off;
+                       /* wait 1 period for first sample availability */
+                       min_sleep_us = period_us;
+                       max_sleep_us = period_us + period_us / 2;
+                       usleep_range(min_sleep_us, max_sleep_us);
+               }
                ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
                                              IIO_MOD_X, val);
                break;
        case IIO_MAGN:
+               if (!st->chip_config.magn_en) {
+                       result = inv_mpu6050_switch_engine(st, true,
+                                       INV_MPU6050_SENSOR_MAGN);
+                       if (result)
+                               goto error_power_off;
+                       /* frequency is limited for magnetometer */
+                       if (freq_hz > INV_MPU_MAGN_FREQ_HZ_MAX) {
+                               freq_hz = INV_MPU_MAGN_FREQ_HZ_MAX;
+                               period_us = 1000000 / freq_hz;
+                       }
+                       /* need to wait 2 periods to have first valid sample */
+                       min_sleep_us = 2 * period_us;
+                       max_sleep_us = 2 * (period_us + period_us / 2);
+                       usleep_range(min_sleep_us, max_sleep_us);
+               }
                ret = inv_mpu_magn_read(st, chan->channel2, val);
                break;
        default:
@@ -445,14 +639,13 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
                break;
        }
 
-       result = inv_mpu6050_set_power_itg(st, false);
-       if (result)
-               goto error_power_off;
+       pm_runtime_mark_last_busy(pdev);
+       pm_runtime_put_autosuspend(pdev);
 
        return ret;
 
 error_power_off:
-       inv_mpu6050_set_power_itg(st, false);
+       pm_runtime_put_autosuspend(pdev);
        return result;
 }
 
@@ -533,12 +726,10 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
 static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val)
 {
        int result, i;
-       u8 d;
 
        for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) {
                if (gyro_scale_6050[i] == val) {
-                       d = (i << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
-                       result = regmap_write(st->map, st->reg->gyro_config, d);
+                       result = inv_mpu6050_set_gyro_fsr(st, i);
                        if (result)
                                return result;
 
@@ -593,6 +784,7 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
                                 int val, int val2, long mask)
 {
        struct inv_mpu6050_state  *st = iio_priv(indio_dev);
+       struct device *pdev = regmap_get_device(st->map);
        int result;
 
        /*
@@ -604,9 +796,11 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
                return result;
 
        mutex_lock(&st->lock);
-       result = inv_mpu6050_set_power_itg(st, true);
-       if (result)
+       result = pm_runtime_get_sync(pdev);
+       if (result < 0) {
+               pm_runtime_put_noidle(pdev);
                goto error_write_raw_unlock;
+       }
 
        switch (mask) {
        case IIO_CHAN_INFO_SCALE:
@@ -644,7 +838,8 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
                break;
        }
 
-       result |= inv_mpu6050_set_power_itg(st, false);
+       pm_runtime_mark_last_busy(pdev);
+       pm_runtime_put_autosuspend(pdev);
 error_write_raw_unlock:
        mutex_unlock(&st->lock);
        iio_device_release_direct_mode(indio_dev);
@@ -655,30 +850,32 @@ error_write_raw_unlock:
 /**
  *  inv_mpu6050_set_lpf() - set low pass filer based on fifo rate.
  *
- *                  Based on the Nyquist principle, the sampling rate must
- *                  exceed twice of the bandwidth of the signal, or there
- *                  would be alising. This function basically search for the
- *                  correct low pass parameters based on the fifo rate, e.g,
- *                  sampling frequency.
+ *                  Based on the Nyquist principle, the bandwidth of the low
+ *                  pass filter must not exceed the signal sampling rate divided
+ *                  by 2, or there would be aliasing.
+ *                  This function basically search for the correct low pass
+ *                  parameters based on the fifo rate, e.g, sampling frequency.
  *
  *  lpf is set automatically when setting sampling rate to avoid any aliases.
  */
 static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate)
 {
-       static const int hz[] = {188, 98, 42, 20, 10, 5};
+       static const int hz[] = {400, 200, 90, 40, 20, 10};
        static const int d[] = {
-               INV_MPU6050_FILTER_188HZ, INV_MPU6050_FILTER_98HZ,
-               INV_MPU6050_FILTER_42HZ, INV_MPU6050_FILTER_20HZ,
+               INV_MPU6050_FILTER_200HZ, INV_MPU6050_FILTER_100HZ,
+               INV_MPU6050_FILTER_45HZ, INV_MPU6050_FILTER_20HZ,
                INV_MPU6050_FILTER_10HZ, INV_MPU6050_FILTER_5HZ
        };
-       int i, h, result;
+       int i, result;
        u8 data;
 
-       h = (rate >> 1);
-       i = 0;
-       while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1))
-               i++;
-       data = d[i];
+       data = INV_MPU6050_FILTER_5HZ;
+       for (i = 0; i < ARRAY_SIZE(hz); ++i) {
+               if (rate >= hz[i]) {
+                       data = d[i];
+                       break;
+               }
+       }
        result = inv_mpu6050_set_lpf_regs(st, data);
        if (result)
                return result;
@@ -699,6 +896,7 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
        int result;
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
+       struct device *pdev = regmap_get_device(st->map);
 
        if (kstrtoint(buf, 10, &fifo_rate))
                return -EINVAL;
@@ -706,10 +904,6 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
            fifo_rate > INV_MPU6050_MAX_FIFO_RATE)
                return -EINVAL;
 
-       result = iio_device_claim_direct_mode(indio_dev);
-       if (result)
-               return result;
-
        /* compute the chip sample rate divider */
        d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(fifo_rate);
        /* compute back the fifo rate to handle truncation cases */
@@ -720,9 +914,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
                result = 0;
                goto fifo_rate_fail_unlock;
        }
-       result = inv_mpu6050_set_power_itg(st, true);
-       if (result)
+       result = pm_runtime_get_sync(pdev);
+       if (result < 0) {
+               pm_runtime_put_noidle(pdev);
                goto fifo_rate_fail_unlock;
+       }
 
        result = regmap_write(st->map, st->reg->sample_rate_div, d);
        if (result)
@@ -738,11 +934,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
        if (result)
                goto fifo_rate_fail_power_off;
 
+       pm_runtime_mark_last_busy(pdev);
 fifo_rate_fail_power_off:
-       result |= inv_mpu6050_set_power_itg(st, false);
+       pm_runtime_put_autosuspend(pdev);
 fifo_rate_fail_unlock:
        mutex_unlock(&st->lock);
-       iio_device_release_direct_mode(indio_dev);
        if (result)
                return result;
 
@@ -1066,11 +1262,13 @@ static const struct iio_info mpu_info = {
 static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
 {
        int result;
-       unsigned int regval;
+       unsigned int regval, mask;
        int i;
 
        st->hw  = &hw_info[st->chip_type];
        st->reg = hw_info[st->chip_type].reg;
+       memcpy(&st->chip_config, hw_info[st->chip_type].config,
+              sizeof(st->chip_config));
 
        /* check chip self-identification */
        result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, &regval);
@@ -1102,6 +1300,24 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
        if (result)
                return result;
        msleep(INV_MPU6050_POWER_UP_TIME);
+       switch (st->chip_type) {
+       case INV_MPU6000:
+       case INV_MPU6500:
+       case INV_MPU6515:
+       case INV_MPU9250:
+       case INV_MPU9255:
+               /* reset signal path (required for spi connection) */
+               regval = INV_MPU6050_BIT_TEMP_RST | INV_MPU6050_BIT_ACCEL_RST |
+                        INV_MPU6050_BIT_GYRO_RST;
+               result = regmap_write(st->map, INV_MPU6050_REG_SIGNAL_PATH_RESET,
+                                     regval);
+               if (result)
+                       return result;
+               msleep(INV_MPU6050_POWER_UP_TIME);
+               break;
+       default:
+               break;
+       }
 
        /*
         * Turn power on. After reset, the sleep bit could be on
@@ -1112,17 +1328,13 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
        result = inv_mpu6050_set_power_itg(st, true);
        if (result)
                return result;
-
-       result = inv_mpu6050_switch_engine(st, false,
-                                          INV_MPU6050_BIT_PWR_ACCL_STBY);
-       if (result)
-               goto error_power_off;
-       result = inv_mpu6050_switch_engine(st, false,
-                                          INV_MPU6050_BIT_PWR_GYRO_STBY);
+       mask = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO |
+                       INV_MPU6050_SENSOR_TEMP | INV_MPU6050_SENSOR_MAGN;
+       result = inv_mpu6050_switch_engine(st, false, mask);
        if (result)
                goto error_power_off;
 
-       return inv_mpu6050_set_power_itg(st, false);
+       return 0;
 
 error_power_off:
        inv_mpu6050_set_power_itg(st, false);
@@ -1139,7 +1351,7 @@ static int inv_mpu_core_enable_regulator_vddio(struct inv_mpu6050_state *st)
                        "Failed to enable vddio regulator: %d\n", result);
        } else {
                /* Give the device a little bit of time to start up. */
-               usleep_range(35000, 70000);
+               usleep_range(3000, 5000);
        }
 
        return result;
@@ -1170,6 +1382,14 @@ static void inv_mpu_core_disable_regulator_action(void *_data)
        inv_mpu_core_disable_regulator_vddio(st);
 }
 
+static void inv_mpu_pm_disable(void *data)
+{
+       struct device *dev = data;
+
+       pm_runtime_put_sync_suspend(dev);
+       pm_runtime_disable(dev);
+}
+
 int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
                int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
 {
@@ -1194,7 +1414,6 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
        st = iio_priv(indio_dev);
        mutex_init(&st->lock);
        st->chip_type = chip_type;
-       st->powerup_count = 0;
        st->irq = irq;
        st->map = regmap;
 
@@ -1259,6 +1478,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
                dev_err(dev, "Failed to enable vdd regulator: %d\n", result);
                return result;
        }
+       msleep(INV_MPU6050_POWER_UP_TIME);
 
        result = inv_mpu_core_enable_regulator_vddio(st);
        if (result) {
@@ -1287,7 +1507,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
        result = inv_mpu6050_init_config(indio_dev);
        if (result) {
                dev_err(dev, "Could not initialize device.\n");
-               return result;
+               goto error_power_off;
        }
 
        dev_set_drvdata(dev, indio_dev);
@@ -1299,8 +1519,24 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
                indio_dev->name = dev_name(dev);
 
        /* requires parent device set in indio_dev */
-       if (inv_mpu_bus_setup)
-               inv_mpu_bus_setup(indio_dev);
+       if (inv_mpu_bus_setup) {
+               result = inv_mpu_bus_setup(indio_dev);
+               if (result)
+                       goto error_power_off;
+       }
+
+       /* chip init is done, turning on runtime power management */
+       result = pm_runtime_set_active(dev);
+       if (result)
+               goto error_power_off;
+       pm_runtime_get_noresume(dev);
+       pm_runtime_enable(dev);
+       pm_runtime_set_autosuspend_delay(dev, INV_MPU6050_SUSPEND_DELAY_MS);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_put(dev);
+       result = devm_add_action_or_reset(dev, inv_mpu_pm_disable, dev);
+       if (result)
+               return result;
 
        switch (chip_type) {
        case INV_MPU9150:
@@ -1359,14 +1595,17 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
        }
 
        return 0;
+
+error_power_off:
+       inv_mpu6050_set_power_itg(st, false);
+       return result;
 }
 EXPORT_SYMBOL_GPL(inv_mpu_core_probe);
 
-#ifdef CONFIG_PM_SLEEP
-
-static int inv_mpu_resume(struct device *dev)
+static int __maybe_unused inv_mpu_resume(struct device *dev)
 {
-       struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct inv_mpu6050_state *st = iio_priv(indio_dev);
        int result;
 
        mutex_lock(&st->lock);
@@ -1375,27 +1614,101 @@ static int inv_mpu_resume(struct device *dev)
                goto out_unlock;
 
        result = inv_mpu6050_set_power_itg(st, true);
+       if (result)
+               goto out_unlock;
+
+       result = inv_mpu6050_switch_engine(st, true, st->suspended_sensors);
+       if (result)
+               goto out_unlock;
+
+       if (iio_buffer_enabled(indio_dev))
+               result = inv_mpu6050_prepare_fifo(st, true);
+
 out_unlock:
        mutex_unlock(&st->lock);
 
        return result;
 }
 
-static int inv_mpu_suspend(struct device *dev)
+static int __maybe_unused inv_mpu_suspend(struct device *dev)
 {
-       struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct inv_mpu6050_state *st = iio_priv(indio_dev);
        int result;
 
        mutex_lock(&st->lock);
+
+       if (iio_buffer_enabled(indio_dev)) {
+               result = inv_mpu6050_prepare_fifo(st, false);
+               if (result)
+                       goto out_unlock;
+       }
+
+       st->suspended_sensors = 0;
+       if (st->chip_config.accl_en)
+               st->suspended_sensors |= INV_MPU6050_SENSOR_ACCL;
+       if (st->chip_config.gyro_en)
+               st->suspended_sensors |= INV_MPU6050_SENSOR_GYRO;
+       if (st->chip_config.temp_en)
+               st->suspended_sensors |= INV_MPU6050_SENSOR_TEMP;
+       if (st->chip_config.magn_en)
+               st->suspended_sensors |= INV_MPU6050_SENSOR_MAGN;
+       result = inv_mpu6050_switch_engine(st, false, st->suspended_sensors);
+       if (result)
+               goto out_unlock;
+
        result = inv_mpu6050_set_power_itg(st, false);
+       if (result)
+               goto out_unlock;
+
        inv_mpu_core_disable_regulator_vddio(st);
+out_unlock:
        mutex_unlock(&st->lock);
 
        return result;
 }
-#endif /* CONFIG_PM_SLEEP */
 
-SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume);
+static int __maybe_unused inv_mpu_runtime_suspend(struct device *dev)
+{
+       struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
+       unsigned int sensors;
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       sensors = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO |
+                       INV_MPU6050_SENSOR_TEMP | INV_MPU6050_SENSOR_MAGN;
+       ret = inv_mpu6050_switch_engine(st, false, sensors);
+       if (ret)
+               goto out_unlock;
+
+       ret = inv_mpu6050_set_power_itg(st, false);
+       if (ret)
+               goto out_unlock;
+
+       inv_mpu_core_disable_regulator_vddio(st);
+
+out_unlock:
+       mutex_unlock(&st->lock);
+       return ret;
+}
+
+static int __maybe_unused inv_mpu_runtime_resume(struct device *dev)
+{
+       struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
+       int ret;
+
+       ret = inv_mpu_core_enable_regulator_vddio(st);
+       if (ret)
+               return ret;
+
+       return inv_mpu6050_set_power_itg(st, true);
+}
+
+const struct dev_pm_ops inv_mpu_pmops = {
+       SET_SYSTEM_SLEEP_PM_OPS(inv_mpu_suspend, inv_mpu_resume)
+       SET_RUNTIME_PM_OPS(inv_mpu_runtime_suspend, inv_mpu_runtime_resume, NULL)
+};
 EXPORT_SYMBOL_GPL(inv_mpu_pmops);
 
 MODULE_AUTHOR("Invensense Corporation");
index f47a28b..6993d3b 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/iio/iio.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/property.h>
 #include "inv_mpu_iio.h"
 
 static const struct regmap_config inv_mpu_regmap_config = {
@@ -19,62 +20,19 @@ static const struct regmap_config inv_mpu_regmap_config = {
 
 static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
 {
-       struct iio_dev *indio_dev = i2c_mux_priv(muxc);
-       struct inv_mpu6050_state *st = iio_priv(indio_dev);
-       int ret;
-
-       mutex_lock(&st->lock);
-
-       ret = inv_mpu6050_set_power_itg(st, true);
-       if (ret)
-               goto error_unlock;
-
-       ret = regmap_write(st->map, st->reg->int_pin_cfg,
-                          st->irq_mask | INV_MPU6050_BIT_BYPASS_EN);
-
-error_unlock:
-       mutex_unlock(&st->lock);
-
-       return ret;
-}
-
-static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
-{
-       struct iio_dev *indio_dev = i2c_mux_priv(muxc);
-       struct inv_mpu6050_state *st = iio_priv(indio_dev);
-
-       mutex_lock(&st->lock);
-
-       /* It doesn't really matter if any of the calls fail */
-       regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask);
-       inv_mpu6050_set_power_itg(st, false);
-
-       mutex_unlock(&st->lock);
-
        return 0;
 }
 
-static const char *inv_mpu_match_acpi_device(struct device *dev,
-                                            enum inv_devices *chip_id)
-{
-       const struct acpi_device_id *id;
-
-       id = acpi_match_device(dev->driver->acpi_match_table, dev);
-       if (!id)
-               return NULL;
-
-       *chip_id = (int)id->driver_data;
-
-       return dev_name(dev);
-}
-
 static bool inv_mpu_i2c_aux_bus(struct device *dev)
 {
        struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
 
        switch (st->chip_type) {
        case INV_ICM20608:
+       case INV_ICM20609:
+       case INV_ICM20689:
        case INV_ICM20602:
+       case INV_IAM20680:
                /* no i2c auxiliary bus on the chip */
                return false;
        case INV_MPU9150:
@@ -89,19 +47,20 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev)
        }
 }
 
-/*
- * MPU9xxx magnetometer support requires to disable i2c auxiliary bus support.
- * To ensure backward compatibility with existing setups, do not disable
- * i2c auxiliary bus if it used.
- * Check for i2c-gate node in devicetree and set magnetometer disabled.
- * Only MPU6500 is supported by ACPI, no need to check.
- */
-static int inv_mpu_magn_disable(struct iio_dev *indio_dev)
+static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev)
 {
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
        struct device *dev = indio_dev->dev.parent;
        struct device_node *mux_node;
+       int ret;
 
+       /*
+        * MPU9xxx magnetometer support requires to disable i2c auxiliary bus.
+        * To ensure backward compatibility with existing setups, do not disable
+        * i2c auxiliary bus if it used.
+        * Check for i2c-gate node in devicetree and set magnetometer disabled.
+        * Only MPU6500 is supported by ACPI, no need to check.
+        */
        switch (st->chip_type) {
        case INV_MPU9150:
        case INV_MPU9250:
@@ -117,6 +76,14 @@ static int inv_mpu_magn_disable(struct iio_dev *indio_dev)
                break;
        }
 
+       /* enable i2c bypass when using i2c auxiliary bus */
+       if (inv_mpu_i2c_aux_bus(dev)) {
+               ret = regmap_write(st->map, st->reg->int_pin_cfg,
+                                  st->irq_mask | INV_MPU6050_BIT_BYPASS_EN);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -130,6 +97,7 @@ static int inv_mpu_magn_disable(struct iio_dev *indio_dev)
 static int inv_mpu_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
+       const void *match;
        struct inv_mpu6050_state *st;
        int result;
        enum inv_devices chip_type;
@@ -140,18 +108,14 @@ static int inv_mpu_probe(struct i2c_client *client,
                                     I2C_FUNC_SMBUS_I2C_BLOCK))
                return -EOPNOTSUPP;
 
-       if (client->dev.of_node) {
-               chip_type = (enum inv_devices)
-                       of_device_get_match_data(&client->dev);
+       match = device_get_match_data(&client->dev);
+       if (match) {
+               chip_type = (enum inv_devices)match;
                name = client->name;
        } else if (id) {
                chip_type = (enum inv_devices)
                        id->driver_data;
                name = id->name;
-       } else if (ACPI_HANDLE(&client->dev)) {
-               name = inv_mpu_match_acpi_device(&client->dev, &chip_type);
-               if (!name)
-                       return -ENODEV;
        } else {
                return -ENOSYS;
        }
@@ -164,7 +128,7 @@ static int inv_mpu_probe(struct i2c_client *client,
        }
 
        result = inv_mpu_core_probe(regmap, client->irq, name,
-                                   inv_mpu_magn_disable, chip_type);
+                                   inv_mpu_i2c_aux_setup, chip_type);
        if (result < 0)
                return result;
 
@@ -173,8 +137,7 @@ static int inv_mpu_probe(struct i2c_client *client,
                /* declare i2c auxiliary bus */
                st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
                                         1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
-                                        inv_mpu6050_select_bypass,
-                                        inv_mpu6050_deselect_bypass);
+                                        inv_mpu6050_select_bypass, NULL);
                if (!st->muxc)
                        return -ENOMEM;
                st->muxc->priv = dev_get_drvdata(&client->dev);
@@ -218,7 +181,11 @@ static const struct i2c_device_id inv_mpu_id[] = {
        {"mpu9250", INV_MPU9250},
        {"mpu9255", INV_MPU9255},
        {"icm20608", INV_ICM20608},
+       {"icm20609", INV_ICM20609},
+       {"icm20689", INV_ICM20689},
        {"icm20602", INV_ICM20602},
+       {"icm20690", INV_ICM20690},
+       {"iam20680", INV_IAM20680},
        {}
 };
 
@@ -254,9 +221,25 @@ static const struct of_device_id inv_of_match[] = {
                .data = (void *)INV_ICM20608
        },
        {
+               .compatible = "invensense,icm20609",
+               .data = (void *)INV_ICM20609
+       },
+       {
+               .compatible = "invensense,icm20689",
+               .data = (void *)INV_ICM20689
+       },
+       {
                .compatible = "invensense,icm20602",
                .data = (void *)INV_ICM20602
        },
+       {
+               .compatible = "invensense,icm20690",
+               .data = (void *)INV_ICM20690
+       },
+       {
+               .compatible = "invensense,iam20680",
+               .data = (void *)INV_IAM20680
+       },
        { }
 };
 MODULE_DEVICE_TABLE(of, inv_of_match);
index 6158fca..cd38b3f 100644 (file)
@@ -75,15 +75,30 @@ enum inv_devices {
        INV_MPU9250,
        INV_MPU9255,
        INV_ICM20608,
+       INV_ICM20609,
+       INV_ICM20689,
        INV_ICM20602,
+       INV_ICM20690,
+       INV_IAM20680,
        INV_NUM_PARTS
 };
 
+/* chip sensors mask: accelerometer, gyroscope, temperature, magnetometer */
+#define INV_MPU6050_SENSOR_ACCL                BIT(0)
+#define INV_MPU6050_SENSOR_GYRO                BIT(1)
+#define INV_MPU6050_SENSOR_TEMP                BIT(2)
+#define INV_MPU6050_SENSOR_MAGN                BIT(3)
+
 /**
  *  struct inv_mpu6050_chip_config - Cached chip configuration data.
+ *  @clk:              selected chip clock
  *  @fsr:              Full scale range.
  *  @lpf:              Digital low pass filter frequency.
  *  @accl_fs:          accel full scale range.
+ *  @accl_en:          accel engine enabled
+ *  @gyro_en:          gyro engine enabled
+ *  @temp_en:          temperature sensor enabled
+ *  @magn_en:          magn engine (i2c master) enabled
  *  @accl_fifo_enable: enable accel data output
  *  @gyro_fifo_enable: enable gyro data output
  *  @temp_fifo_enable: enable temp data output
@@ -91,9 +106,14 @@ enum inv_devices {
  *  @divider:          chip sample rate divider (sample rate divider - 1)
  */
 struct inv_mpu6050_chip_config {
+       unsigned int clk:3;
        unsigned int fsr:2;
        unsigned int lpf:3;
        unsigned int accl_fs:2;
+       unsigned int accl_en:1;
+       unsigned int gyro_en:1;
+       unsigned int temp_en:1;
+       unsigned int magn_en:1;
        unsigned int accl_fifo_enable:1;
        unsigned int gyro_fifo_enable:1;
        unsigned int temp_fifo_enable:1;
@@ -144,6 +164,7 @@ struct inv_mpu6050_hw {
  *  @magn_disabled:     magnetometer disabled for backward compatibility reason.
  *  @magn_raw_to_gauss:        coefficient to convert mag raw value to Gauss.
  *  @magn_orient:       magnetometer sensor chip orientation if available.
+ *  @suspended_sensors:        sensors mask of sensors turned off for suspend
  */
 struct inv_mpu6050_state {
        struct mutex lock;
@@ -154,7 +175,6 @@ struct inv_mpu6050_state {
        enum   inv_devices chip_type;
        struct i2c_mux_core *muxc;
        struct i2c_client *mux_client;
-       unsigned int powerup_count;
        struct inv_mpu6050_platform_data plat_data;
        struct iio_mount_matrix orientation;
        struct regmap *map;
@@ -169,6 +189,7 @@ struct inv_mpu6050_state {
        bool magn_disabled;
        s32 magn_raw_to_gauss[3];
        struct iio_mount_matrix magn_orient;
+       unsigned int suspended_sensors;
 };
 
 /*register and associated bit definition*/
@@ -241,7 +262,13 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_BIT_I2C_SLV3_DLY_EN     0x08
 #define INV_MPU6050_BIT_DELAY_ES_SHADOW     0x80
 
+#define INV_MPU6050_REG_SIGNAL_PATH_RESET   0x68
+#define INV_MPU6050_BIT_TEMP_RST            BIT(0)
+#define INV_MPU6050_BIT_ACCEL_RST           BIT(1)
+#define INV_MPU6050_BIT_GYRO_RST            BIT(2)
+
 #define INV_MPU6050_REG_USER_CTRL           0x6A
+#define INV_MPU6050_BIT_SIG_COND_RST        0x01
 #define INV_MPU6050_BIT_FIFO_RST            0x04
 #define INV_MPU6050_BIT_DMP_RST             0x08
 #define INV_MPU6050_BIT_I2C_MST_EN          0x20
@@ -252,6 +279,7 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_REG_PWR_MGMT_1          0x6B
 #define INV_MPU6050_BIT_H_RESET             0x80
 #define INV_MPU6050_BIT_SLEEP               0x40
+#define INV_MPU6050_BIT_TEMP_DIS            0x08
 #define INV_MPU6050_BIT_CLK_MASK            0x7
 
 #define INV_MPU6050_REG_PWR_MGMT_2          0x6C
@@ -276,12 +304,16 @@ struct inv_mpu6050_state {
 
 /* mpu6500 registers */
 #define INV_MPU6500_REG_ACCEL_CONFIG_2      0x1D
+#define INV_ICM20689_BITS_FIFO_SIZE_MAX     0xC0
 #define INV_MPU6500_REG_ACCEL_OFFSET        0x77
 
 /* delay time in milliseconds */
 #define INV_MPU6050_POWER_UP_TIME            100
 #define INV_MPU6050_TEMP_UP_TIME             100
-#define INV_MPU6050_SENSOR_UP_TIME           30
+#define INV_MPU6050_ACCEL_UP_TIME            20
+#define INV_MPU6050_GYRO_UP_TIME             35
+#define INV_MPU6050_GYRO_DOWN_TIME           150
+#define INV_MPU6050_SUSPEND_DELAY_MS         2000
 
 /* delay time in microseconds */
 #define INV_MPU6050_REG_UP_TIME_MIN          5000
@@ -293,6 +325,7 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_MAX_ACCL_FS_PARAM        3
 #define INV_MPU6050_THREE_AXIS               3
 #define INV_MPU6050_GYRO_CONFIG_FSR_SHIFT    3
+#define INV_ICM20690_GYRO_CONFIG_FSR_SHIFT   2
 #define INV_MPU6050_ACCL_CONFIG_FSR_SHIFT    3
 
 #define INV_MPU6500_TEMP_OFFSET              7011
@@ -315,7 +348,6 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_TS_PERIOD_JITTER   4
 
 /* init parameters */
-#define INV_MPU6050_INIT_FIFO_RATE           50
 #define INV_MPU6050_MAX_FIFO_RATE            1000
 #define INV_MPU6050_MIN_FIFO_RATE            4
 
@@ -340,7 +372,11 @@ struct inv_mpu6050_state {
 #define INV_MPU9255_WHOAMI_VALUE               0x73
 #define INV_MPU6515_WHOAMI_VALUE               0x74
 #define INV_ICM20608_WHOAMI_VALUE              0xAF
+#define INV_ICM20609_WHOAMI_VALUE              0xA6
+#define INV_ICM20689_WHOAMI_VALUE              0x98
 #define INV_ICM20602_WHOAMI_VALUE              0x12
+#define INV_ICM20690_WHOAMI_VALUE              0x20
+#define INV_IAM20680_WHOAMI_VALUE              0xA9
 
 /* scan element definition for generic MPU6xxx devices */
 enum inv_mpu6050_scan {
@@ -360,14 +396,14 @@ enum inv_mpu6050_scan {
 };
 
 enum inv_mpu6050_filter_e {
-       INV_MPU6050_FILTER_256HZ_NOLPF2 = 0,
-       INV_MPU6050_FILTER_188HZ,
-       INV_MPU6050_FILTER_98HZ,
-       INV_MPU6050_FILTER_42HZ,
+       INV_MPU6050_FILTER_NOLPF2 = 0,
+       INV_MPU6050_FILTER_200HZ,
+       INV_MPU6050_FILTER_100HZ,
+       INV_MPU6050_FILTER_45HZ,
        INV_MPU6050_FILTER_20HZ,
        INV_MPU6050_FILTER_10HZ,
        INV_MPU6050_FILTER_5HZ,
-       INV_MPU6050_FILTER_2100HZ_NOLPF,
+       INV_MPU6050_FILTER_NOLPF,
        NUM_MPU6050_FILTER
 };
 
@@ -401,10 +437,10 @@ enum inv_mpu6050_clock_sel_e {
 
 irqreturn_t inv_mpu6050_read_fifo(int irq, void *p);
 int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev, int irq_type);
-int inv_reset_fifo(struct iio_dev *indio_dev);
-int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask);
+int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable);
+int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
+                             unsigned int mask);
 int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
-int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
 int inv_mpu_acpi_create_mux_client(struct i2c_client *client);
 void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
 int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
index 4f19235..f282e9c 100644 (file)
@@ -44,9 +44,6 @@
 #define INV_MPU_MAGN_REG_ASAY          0x11
 #define INV_MPU_MAGN_REG_ASAZ          0x12
 
-/* Magnetometer maximum frequency */
-#define INV_MPU_MAGN_FREQ_HZ_MAX       50
-
 static bool inv_magn_supported(const struct inv_mpu6050_state *st)
 {
        switch (st->chip_type) {
@@ -316,59 +313,32 @@ int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
  *
  * Returns 0 on success, a negative error code otherwise
  */
-int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val)
+int inv_mpu_magn_read(struct inv_mpu6050_state *st, int axis, int *val)
 {
-       unsigned int user_ctrl, status;
-       __be16 data[3];
+       unsigned int status;
+       __be16 data;
        uint8_t addr;
-       uint8_t d;
-       unsigned int period_ms;
        int ret;
 
        /* quit if chip is not supported */
        if (!inv_magn_supported(st))
                return -ENODEV;
 
-       /* Mag data: X - Y - Z */
+       /* Mag data: XH,XL,YH,YL,ZH,ZL */
        switch (axis) {
        case IIO_MOD_X:
                addr = 0;
                break;
        case IIO_MOD_Y:
-               addr = 1;
+               addr = 2;
                break;
        case IIO_MOD_Z:
-               addr = 2;
+               addr = 4;
                break;
        default:
                return -EINVAL;
        }
-
-       /* set sample rate to max mag freq */
-       d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU_MAGN_FREQ_HZ_MAX);
-       ret = regmap_write(st->map, st->reg->sample_rate_div, d);
-       if (ret)
-               return ret;
-
-       /* start i2c master, wait for xfer, stop */
-       user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
-       ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
-       if (ret)
-               return ret;
-
-       /* need to wait 2 periods + half-period margin */
-       period_ms = 1000 / INV_MPU_MAGN_FREQ_HZ_MAX;
-       msleep(period_ms * 2 + period_ms / 2);
-       user_ctrl = st->chip_config.user_ctrl;
-       ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
-       if (ret)
-               return ret;
-
-       /* restore sample rate */
-       d = st->chip_config.divider;
-       ret = regmap_write(st->map, st->reg->sample_rate_div, d);
-       if (ret)
-               return ret;
+       addr += INV_MPU6050_REG_EXT_SENS_DATA;
 
        /* check i2c status and read raw data */
        ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
@@ -379,12 +349,11 @@ int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val)
                        status & INV_MPU6050_BIT_I2C_SLV1_NACK)
                return -EIO;
 
-       ret = regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
-                              data, sizeof(data));
+       ret = regmap_bulk_read(st->map, addr, &data, sizeof(data));
        if (ret)
                return ret;
 
-       *val = (int16_t)be16_to_cpu(data[addr]);
+       *val = (int16_t)be16_to_cpu(data);
 
        return IIO_VAL_INT;
 }
index b41bd05..185c000 100644 (file)
@@ -10,6 +10,9 @@
 
 #include "inv_mpu_iio.h"
 
+/* Magnetometer maximum frequency */
+#define INV_MPU_MAGN_FREQ_HZ_MAX       50
+
 int inv_mpu_magn_probe(struct inv_mpu6050_state *st);
 
 /**
@@ -31,6 +34,6 @@ int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate);
 
 int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st);
 
-int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val);
+int inv_mpu_magn_read(struct inv_mpu6050_state *st, int axis, int *val);
 
 #endif         /* INV_MPU_MAGN_H_ */
index f9fdf43..9511e47 100644 (file)
@@ -90,63 +90,14 @@ static s64 inv_mpu6050_get_timestamp(struct inv_mpu6050_state *st)
        return ts;
 }
 
-int inv_reset_fifo(struct iio_dev *indio_dev)
+static int inv_reset_fifo(struct iio_dev *indio_dev)
 {
        int result;
-       u8 d;
        struct inv_mpu6050_state  *st = iio_priv(indio_dev);
 
-       /* reset it timestamp validation */
-       st->it_timestamp = 0;
-
-       /* disable interrupt */
-       result = regmap_write(st->map, st->reg->int_enable, 0);
-       if (result) {
-               dev_err(regmap_get_device(st->map), "int_enable failed %d\n",
-                       result);
-               return result;
-       }
-       /* disable the sensor output to FIFO */
-       result = regmap_write(st->map, st->reg->fifo_en, 0);
-       if (result)
-               goto reset_fifo_fail;
-       /* disable fifo reading */
-       result = regmap_write(st->map, st->reg->user_ctrl,
-                             st->chip_config.user_ctrl);
-       if (result)
-               goto reset_fifo_fail;
-
-       /* reset FIFO*/
-       d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_RST;
-       result = regmap_write(st->map, st->reg->user_ctrl, d);
-       if (result)
-               goto reset_fifo_fail;
-
-       /* enable interrupt */
-       if (st->chip_config.accl_fifo_enable ||
-           st->chip_config.gyro_fifo_enable ||
-           st->chip_config.magn_fifo_enable) {
-               result = regmap_write(st->map, st->reg->int_enable,
-                                     INV_MPU6050_BIT_DATA_RDY_EN);
-               if (result)
-                       return result;
-       }
-       /* enable FIFO reading */
-       d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_EN;
-       result = regmap_write(st->map, st->reg->user_ctrl, d);
-       if (result)
-               goto reset_fifo_fail;
-       /* enable sensor output to FIFO */
-       d = 0;
-       if (st->chip_config.gyro_fifo_enable)
-               d |= INV_MPU6050_BITS_GYRO_OUT;
-       if (st->chip_config.accl_fifo_enable)
-               d |= INV_MPU6050_BIT_ACCEL_OUT;
-       if (st->chip_config.temp_fifo_enable)
-               d |= INV_MPU6050_BIT_TEMP_OUT;
-       if (st->chip_config.magn_fifo_enable)
-               d |= INV_MPU6050_BIT_SLAVE_0;
-       result = regmap_write(st->map, st->reg->fifo_en, d);
+       /* disable fifo and reenable it */
+       inv_mpu6050_prepare_fifo(st, false);
+       result = inv_mpu6050_prepare_fifo(st, true);
        if (result)
                goto reset_fifo_fail;
 
index ec102d5..673b198 100644 (file)
@@ -4,6 +4,8 @@
 */
 #include <linux/module.h>
 #include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/property.h>
 #include <linux/spi/spi.h>
 #include <linux/regmap.h>
 #include <linux/iio/iio.h>
@@ -19,10 +21,6 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev)
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
        int ret = 0;
 
-       ret = inv_mpu6050_set_power_itg(st, true);
-       if (ret)
-               return ret;
-
        if (st->reg->i2c_if) {
                ret = regmap_write(st->map, st->reg->i2c_if,
                                   INV_ICM20602_BIT_I2C_IF_DIS);
@@ -31,27 +29,24 @@ static int inv_mpu_i2c_disable(struct iio_dev *indio_dev)
                ret = regmap_write(st->map, st->reg->user_ctrl,
                                   st->chip_config.user_ctrl);
        }
-       if (ret) {
-               inv_mpu6050_set_power_itg(st, false);
-               return ret;
-       }
 
-       return inv_mpu6050_set_power_itg(st, false);
+       return ret;
 }
 
 static int inv_mpu_probe(struct spi_device *spi)
 {
+       const void *match;
        struct regmap *regmap;
        const struct spi_device_id *spi_id;
-       const struct acpi_device_id *acpi_id;
        const char *name = NULL;
        enum inv_devices chip_type;
 
        if ((spi_id = spi_get_device_id(spi))) {
                chip_type = (enum inv_devices)spi_id->driver_data;
                name = spi_id->name;
-       } else if ((acpi_id = acpi_match_device(spi->dev.driver->acpi_match_table, &spi->dev))) {
-               chip_type = (enum inv_devices)acpi_id->driver_data;
+       } else if ((match = device_get_match_data(&spi->dev))) {
+               chip_type = (enum inv_devices)match;
+               name = dev_name(&spi->dev);
        } else {
                return -ENODEV;
        }
@@ -74,15 +69,69 @@ static int inv_mpu_probe(struct spi_device *spi)
 static const struct spi_device_id inv_mpu_id[] = {
        {"mpu6000", INV_MPU6000},
        {"mpu6500", INV_MPU6500},
+       {"mpu6515", INV_MPU6515},
        {"mpu9250", INV_MPU9250},
        {"mpu9255", INV_MPU9255},
        {"icm20608", INV_ICM20608},
+       {"icm20609", INV_ICM20609},
+       {"icm20689", INV_ICM20689},
        {"icm20602", INV_ICM20602},
+       {"icm20690", INV_ICM20690},
+       {"iam20680", INV_IAM20680},
        {}
 };
 
 MODULE_DEVICE_TABLE(spi, inv_mpu_id);
 
+static const struct of_device_id inv_of_match[] = {
+       {
+               .compatible = "invensense,mpu6000",
+               .data = (void *)INV_MPU6000
+       },
+       {
+               .compatible = "invensense,mpu6500",
+               .data = (void *)INV_MPU6500
+       },
+       {
+               .compatible = "invensense,mpu6515",
+               .data = (void *)INV_MPU6515
+       },
+       {
+               .compatible = "invensense,mpu9250",
+               .data = (void *)INV_MPU9250
+       },
+       {
+               .compatible = "invensense,mpu9255",
+               .data = (void *)INV_MPU9255
+       },
+       {
+               .compatible = "invensense,icm20608",
+               .data = (void *)INV_ICM20608
+       },
+       {
+               .compatible = "invensense,icm20609",
+               .data = (void *)INV_ICM20609
+       },
+       {
+               .compatible = "invensense,icm20689",
+               .data = (void *)INV_ICM20689
+       },
+       {
+               .compatible = "invensense,icm20602",
+               .data = (void *)INV_ICM20602
+       },
+       {
+               .compatible = "invensense,icm20690",
+               .data = (void *)INV_ICM20690
+       },
+       {
+               .compatible = "invensense,iam20680",
+               .data = (void *)INV_IAM20680
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, inv_of_match);
+
 static const struct acpi_device_id inv_acpi_match[] = {
        {"INVN6000", INV_MPU6000},
        { },
@@ -93,6 +142,7 @@ static struct spi_driver inv_mpu_driver = {
        .probe          =       inv_mpu_probe,
        .id_table       =       inv_mpu_id,
        .driver = {
+               .of_match_table = inv_of_match,
                .acpi_match_table = ACPI_PTR(inv_acpi_match),
                .name   =       "inv-mpu6000-spi",
                .pm     =       &inv_mpu_pmops,
index 5199fe7..f7b5a70 100644 (file)
@@ -3,11 +3,13 @@
 * Copyright (C) 2012 Invensense, Inc.
 */
 
+#include <linux/pm_runtime.h>
 #include "inv_mpu_iio.h"
 
-static void inv_scan_query_mpu6050(struct iio_dev *indio_dev)
+static unsigned int inv_scan_query_mpu6050(struct iio_dev *indio_dev)
 {
        struct inv_mpu6050_state  *st = iio_priv(indio_dev);
+       unsigned int mask;
 
        st->chip_config.gyro_fifo_enable =
                test_bit(INV_MPU6050_SCAN_GYRO_X,
@@ -27,17 +29,28 @@ static void inv_scan_query_mpu6050(struct iio_dev *indio_dev)
 
        st->chip_config.temp_fifo_enable =
                test_bit(INV_MPU6050_SCAN_TEMP, indio_dev->active_scan_mask);
+
+       mask = 0;
+       if (st->chip_config.gyro_fifo_enable)
+               mask |= INV_MPU6050_SENSOR_GYRO;
+       if (st->chip_config.accl_fifo_enable)
+               mask |= INV_MPU6050_SENSOR_ACCL;
+       if (st->chip_config.temp_fifo_enable)
+               mask |= INV_MPU6050_SENSOR_TEMP;
+
+       return mask;
 }
 
-static void inv_scan_query_mpu9x50(struct iio_dev *indio_dev)
+static unsigned int inv_scan_query_mpu9x50(struct iio_dev *indio_dev)
 {
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
+       unsigned int mask;
 
-       inv_scan_query_mpu6050(indio_dev);
+       mask = inv_scan_query_mpu6050(indio_dev);
 
        /* no magnetometer if i2c auxiliary bus is used */
        if (st->magn_disabled)
-               return;
+               return mask;
 
        st->chip_config.magn_fifo_enable =
                test_bit(INV_MPU9X50_SCAN_MAGN_X,
@@ -46,9 +59,13 @@ static void inv_scan_query_mpu9x50(struct iio_dev *indio_dev)
                         indio_dev->active_scan_mask) ||
                test_bit(INV_MPU9X50_SCAN_MAGN_Z,
                         indio_dev->active_scan_mask);
+       if (st->chip_config.magn_fifo_enable)
+               mask |= INV_MPU6050_SENSOR_MAGN;
+
+       return mask;
 }
 
-static void inv_scan_query(struct iio_dev *indio_dev)
+static unsigned int inv_scan_query(struct iio_dev *indio_dev)
 {
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
 
@@ -84,6 +101,54 @@ static unsigned int inv_compute_skip_samples(const struct inv_mpu6050_state *st)
        return skip_samples;
 }
 
+int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable)
+{
+       uint8_t d;
+       int ret;
+
+       if (enable) {
+               st->it_timestamp = 0;
+               /* reset FIFO */
+               d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_RST;
+               ret = regmap_write(st->map, st->reg->user_ctrl, d);
+               if (ret)
+                       return ret;
+               /* enable sensor output to FIFO */
+               d = 0;
+               if (st->chip_config.gyro_fifo_enable)
+                       d |= INV_MPU6050_BITS_GYRO_OUT;
+               if (st->chip_config.accl_fifo_enable)
+                       d |= INV_MPU6050_BIT_ACCEL_OUT;
+               if (st->chip_config.temp_fifo_enable)
+                       d |= INV_MPU6050_BIT_TEMP_OUT;
+               if (st->chip_config.magn_fifo_enable)
+                       d |= INV_MPU6050_BIT_SLAVE_0;
+               ret = regmap_write(st->map, st->reg->fifo_en, d);
+               if (ret)
+                       return ret;
+               /* enable FIFO reading */
+               d = st->chip_config.user_ctrl | INV_MPU6050_BIT_FIFO_EN;
+               ret = regmap_write(st->map, st->reg->user_ctrl, d);
+               if (ret)
+                       return ret;
+               /* enable interrupt */
+               ret = regmap_write(st->map, st->reg->int_enable,
+                                  INV_MPU6050_BIT_DATA_RDY_EN);
+       } else {
+               ret = regmap_write(st->map, st->reg->int_enable, 0);
+               if (ret)
+                       return ret;
+               ret = regmap_write(st->map, st->reg->fifo_en, 0);
+               if (ret)
+                       return ret;
+               /* restore user_ctrl for disabling FIFO reading */
+               ret = regmap_write(st->map, st->reg->user_ctrl,
+                                  st->chip_config.user_ctrl);
+       }
+
+       return ret;
+}
+
 /**
  *  inv_mpu6050_set_enable() - enable chip functions.
  *  @indio_dev:        Device driver instance.
@@ -92,84 +157,43 @@ static unsigned int inv_compute_skip_samples(const struct inv_mpu6050_state *st)
 static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
 {
        struct inv_mpu6050_state *st = iio_priv(indio_dev);
-       uint8_t d;
+       struct device *pdev = regmap_get_device(st->map);
+       unsigned int scan;
        int result;
 
        if (enable) {
-               result = inv_mpu6050_set_power_itg(st, true);
-               if (result)
+               scan = inv_scan_query(indio_dev);
+               result = pm_runtime_get_sync(pdev);
+               if (result < 0) {
+                       pm_runtime_put_noidle(pdev);
                        return result;
-               inv_scan_query(indio_dev);
-               if (st->chip_config.gyro_fifo_enable) {
-                       result = inv_mpu6050_switch_engine(st, true,
-                                       INV_MPU6050_BIT_PWR_GYRO_STBY);
-                       if (result)
-                               goto error_power_off;
-               }
-               if (st->chip_config.accl_fifo_enable) {
-                       result = inv_mpu6050_switch_engine(st, true,
-                                       INV_MPU6050_BIT_PWR_ACCL_STBY);
-                       if (result)
-                               goto error_gyro_off;
                }
-               if (st->chip_config.magn_fifo_enable) {
-                       d = st->chip_config.user_ctrl |
-                                       INV_MPU6050_BIT_I2C_MST_EN;
-                       result = regmap_write(st->map, st->reg->user_ctrl, d);
-                       if (result)
-                               goto error_accl_off;
-                       st->chip_config.user_ctrl = d;
-               }
-               st->skip_samples = inv_compute_skip_samples(st);
-               result = inv_reset_fifo(indio_dev);
+               /*
+                * In case autosuspend didn't trigger, turn off first not
+                * required sensors.
+                */
+               result = inv_mpu6050_switch_engine(st, false, ~scan);
                if (result)
-                       goto error_magn_off;
-       } else {
-               result = regmap_write(st->map, st->reg->fifo_en, 0);
-               if (result)
-                       goto error_magn_off;
-
-               result = regmap_write(st->map, st->reg->int_enable, 0);
-               if (result)
-                       goto error_magn_off;
-
-               d = st->chip_config.user_ctrl & ~INV_MPU6050_BIT_I2C_MST_EN;
-               result = regmap_write(st->map, st->reg->user_ctrl, d);
-               if (result)
-                       goto error_magn_off;
-               st->chip_config.user_ctrl = d;
-
-               result = inv_mpu6050_switch_engine(st, false,
-                                       INV_MPU6050_BIT_PWR_ACCL_STBY);
+                       goto error_power_off;
+               result = inv_mpu6050_switch_engine(st, true, scan);
                if (result)
-                       goto error_accl_off;
-
-               result = inv_mpu6050_switch_engine(st, false,
-                                       INV_MPU6050_BIT_PWR_GYRO_STBY);
+                       goto error_power_off;
+               st->skip_samples = inv_compute_skip_samples(st);
+               result = inv_mpu6050_prepare_fifo(st, true);
                if (result)
-                       goto error_gyro_off;
-
-               result = inv_mpu6050_set_power_itg(st, false);
+                       goto error_power_off;
+       } else {
+               result = inv_mpu6050_prepare_fifo(st, false);
                if (result)
                        goto error_power_off;
+               pm_runtime_mark_last_busy(pdev);
+               pm_runtime_put_autosuspend(pdev);
        }
 
        return 0;
 
-error_magn_off:
-       /* always restore user_ctrl to disable fifo properly */
-       st->chip_config.user_ctrl &= ~INV_MPU6050_BIT_I2C_MST_EN;
-       regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl);
-error_accl_off:
-       if (st->chip_config.accl_fifo_enable)
-               inv_mpu6050_switch_engine(st, false,
-                                         INV_MPU6050_BIT_PWR_ACCL_STBY);
-error_gyro_off:
-       if (st->chip_config.gyro_fifo_enable)
-               inv_mpu6050_switch_engine(st, false,
-                                         INV_MPU6050_BIT_PWR_GYRO_STBY);
 error_power_off:
-       inv_mpu6050_set_power_itg(st, false);
+       pm_runtime_put_autosuspend(pdev);
        return result;
 }
 
index 9c3486a..f2113a6 100644 (file)
@@ -230,8 +230,8 @@ enum st_lsm6dsx_ext_sensor_id {
  * @i2c_addr: I2c slave address list.
  * @wai: Wai address info.
  * @id: external sensor id.
- * @odr: Output data rate of the sensor [Hz].
- * @gain: Configured sensor sensitivity.
+ * @odr_table: Output data rate of the sensor [Hz].
+ * @fs_table: Configured sensor sensitivity table depending on full scale.
  * @temp_comp: Temperature compensation register info (addr + mask).
  * @pwr_table: Power on register info (addr + mask).
  * @off_canc: Offset cancellation register info (addr + mask).
index eea5556..95ddd19 100644 (file)
@@ -464,9 +464,10 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor,
 
        len = min_t(int, sizeof(data), ch->scan_type.realbits >> 3);
        err = st_lsm6dsx_shub_read(sensor, ch->address, data, len);
+       if (err < 0)
+               return err;
 
-       st_lsm6dsx_shub_set_enable(sensor, false);
-
+       err = st_lsm6dsx_shub_set_enable(sensor, false);
        if (err < 0)
                return err;
 
index 65ff0d0..eac63c1 100644 (file)
@@ -301,11 +301,14 @@ static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf,
                              size_t count, loff_t *ppos)
 {
        struct iio_dev *indio_dev = file->private_data;
-       char buf[20];
        unsigned val = 0;
-       ssize_t len;
        int ret;
 
+       if (*ppos > 0)
+               return simple_read_from_buffer(userbuf, count, ppos,
+                                              indio_dev->read_buf,
+                                              indio_dev->read_buf_len);
+
        ret = indio_dev->info->debugfs_reg_access(indio_dev,
                                                  indio_dev->cached_reg_addr,
                                                  0, &val);
@@ -314,9 +317,13 @@ static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf,
                return ret;
        }
 
-       len = snprintf(buf, sizeof(buf), "0x%X\n", val);
+       indio_dev->read_buf_len = snprintf(indio_dev->read_buf,
+                                          sizeof(indio_dev->read_buf),
+                                          "0x%X\n", val);
 
-       return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+       return simple_read_from_buffer(userbuf, count, ppos,
+                                      indio_dev->read_buf,
+                                      indio_dev->read_buf_len);
 }
 
 static ssize_t iio_debugfs_write_reg(struct file *file,
@@ -769,17 +776,18 @@ static ssize_t iio_read_channel_info_avail(struct device *dev,
 }
 
 /**
- * iio_str_to_fixpoint() - Parse a fixed-point number from a string
+ * __iio_str_to_fixpoint() - Parse a fixed-point number from a string
  * @str: The string to parse
  * @fract_mult: Multiplier for the first decimal place, should be a power of 10
  * @integer: The integer part of the number
  * @fract: The fractional part of the number
+ * @scale_db: True if this should parse as dB
  *
  * Returns 0 on success, or a negative error code if the string could not be
  * parsed.
  */
-int iio_str_to_fixpoint(const char *str, int fract_mult,
-       int *integer, int *fract)
+static int __iio_str_to_fixpoint(const char *str, int fract_mult,
+                                int *integer, int *fract, bool scale_db)
 {
        int i = 0, f = 0;
        bool integer_part = true, negative = false;
@@ -810,6 +818,14 @@ int iio_str_to_fixpoint(const char *str, int fract_mult,
                                break;
                        else
                                return -EINVAL;
+               } else if (!strncmp(str, " dB", sizeof(" dB") - 1) && scale_db) {
+                       /* Ignore the dB suffix */
+                       str += sizeof(" dB") - 1;
+                       continue;
+               } else if (!strncmp(str, "dB", sizeof("dB") - 1) && scale_db) {
+                       /* Ignore the dB suffix */
+                       str += sizeof("dB") - 1;
+                       continue;
                } else if (*str == '.' && integer_part) {
                        integer_part = false;
                } else {
@@ -830,6 +846,22 @@ int iio_str_to_fixpoint(const char *str, int fract_mult,
 
        return 0;
 }
+
+/**
+ * iio_str_to_fixpoint() - Parse a fixed-point number from a string
+ * @str: The string to parse
+ * @fract_mult: Multiplier for the first decimal place, should be a power of 10
+ * @integer: The integer part of the number
+ * @fract: The fractional part of the number
+ *
+ * Returns 0 on success, or a negative error code if the string could not be
+ * parsed.
+ */
+int iio_str_to_fixpoint(const char *str, int fract_mult,
+                       int *integer, int *fract)
+{
+       return __iio_str_to_fixpoint(str, fract_mult, integer, fract, false);
+}
 EXPORT_SYMBOL_GPL(iio_str_to_fixpoint);
 
 static ssize_t iio_write_channel_info(struct device *dev,
@@ -842,6 +874,7 @@ static ssize_t iio_write_channel_info(struct device *dev,
        int ret, fract_mult = 100000;
        int integer, fract = 0;
        bool is_char = false;
+       bool scale_db = false;
 
        /* Assumes decimal - precision based on number of digits */
        if (!indio_dev->info->write_raw)
@@ -853,6 +886,9 @@ static ssize_t iio_write_channel_info(struct device *dev,
                case IIO_VAL_INT:
                        fract_mult = 0;
                        break;
+               case IIO_VAL_INT_PLUS_MICRO_DB:
+                       scale_db = true;
+                       /* fall through */
                case IIO_VAL_INT_PLUS_MICRO:
                        fract_mult = 100000;
                        break;
@@ -877,6 +913,10 @@ static ssize_t iio_write_channel_info(struct device *dev,
                if (ret)
                        return ret;
        }
+       ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract,
+                                   scale_db);
+       if (ret)
+               return ret;
 
        ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
                                         integer, fract, this_attr->address);
index 9968f98..74970f1 100644 (file)
@@ -43,6 +43,16 @@ config ADUX1020
         To compile this driver as a module, choose M here: the
         module will be called adux1020.
 
+config AL3010
+       tristate "AL3010 ambient light sensor"
+       depends on I2C
+       help
+         Say Y here if you want to build a driver for the Dyna Image AL3010
+         ambient light sensor.
+
+         To compile this driver as a module, choose M here: the
+         module will be called al3010.
+
 config AL3320A
        tristate "AL3320A ambient light sensor"
        depends on I2C
@@ -159,6 +169,17 @@ config IIO_CROS_EC_LIGHT_PROX
          To compile this driver as a module, choose M here:
          the module will be called cros_ec_light_prox.
 
+config GP2AP002
+       tristate "Sharp GP2AP002 Proximity/ALS sensor"
+       depends on I2C
+       select REGMAP
+       help
+         Say Y here if you have a Sharp GP2AP002 proximity/ALS combo-chip
+         hooked to an I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gp2ap002.
+
 config GP2AP020A00F
        tristate "Sharp GP2AP020A00F Proximity/ALS sensor"
        depends on I2C
index c98d1ce..5c1ebaf 100644 (file)
@@ -7,6 +7,7 @@
 obj-$(CONFIG_ACPI_ALS)         += acpi-als.o
 obj-$(CONFIG_ADJD_S311)                += adjd_s311.o
 obj-$(CONFIG_ADUX1020)         += adux1020.o
+obj-$(CONFIG_AL3010)           += al3010.o
 obj-$(CONFIG_AL3320A)          += al3320a.o
 obj-$(CONFIG_APDS9300)         += apds9300.o
 obj-$(CONFIG_APDS9960)         += apds9960.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_CM3323)          += cm3323.o
 obj-$(CONFIG_CM3605)           += cm3605.o
 obj-$(CONFIG_CM36651)          += cm36651.o
 obj-$(CONFIG_IIO_CROS_EC_LIGHT_PROX) += cros_ec_light_prox.o
+obj-$(CONFIG_GP2AP002)         += gp2ap002.o
 obj-$(CONFIG_GP2AP020A00F)     += gp2ap020a00f.o
 obj-$(CONFIG_HID_SENSOR_ALS)   += hid-sensor-als.o
 obj-$(CONFIG_HID_SENSOR_PROX)  += hid-sensor-prox.o
diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c
new file mode 100644 (file)
index 0000000..b1ed765
--- /dev/null
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AL3010 - Dyna Image Ambient Light Sensor
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ * Copyright (c) 2016, Dyna-Image Corp.
+ * Copyright (c) 2020, David Heidelberg, Michał Mirosław, Dmitry Osipenko
+ *
+ * IIO driver for AL3010 (7-bit I2C slave address 0x1C).
+ *
+ * TODO: interrupt support, thresholds
+ * When the driver will get support for interrupt handling, then interrupt
+ * will need to be disabled before turning sensor OFF in order to avoid
+ * potential races with the interrupt handling.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define AL3010_DRV_NAME "al3010"
+
+#define AL3010_REG_SYSTEM              0x00
+#define AL3010_REG_DATA_LOW            0x0c
+#define AL3010_REG_CONFIG              0x10
+
+#define AL3010_CONFIG_DISABLE          0x00
+#define AL3010_CONFIG_ENABLE           0x01
+
+#define AL3010_GAIN_MASK               GENMASK(6,4)
+
+#define AL3010_SCALE_AVAILABLE "1.1872 0.2968 0.0742 0.018"
+
+enum al3xxxx_range {
+       AL3XXX_RANGE_1, /* 77806 lx */
+       AL3XXX_RANGE_2, /* 19542 lx */
+       AL3XXX_RANGE_3, /*  4863 lx */
+       AL3XXX_RANGE_4  /*  1216 lx */
+};
+
+static const int al3010_scales[][2] = {
+       {0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600}
+};
+
+struct al3010_data {
+       struct i2c_client *client;
+};
+
+static const struct iio_chan_spec al3010_channels[] = {
+       {
+               .type   = IIO_LIGHT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE),
+       }
+};
+
+static IIO_CONST_ATTR(in_illuminance_scale_available, AL3010_SCALE_AVAILABLE);
+
+static struct attribute *al3010_attributes[] = {
+       &iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group al3010_attribute_group = {
+       .attrs = al3010_attributes,
+};
+
+static int al3010_set_pwr(struct i2c_client *client, bool pwr)
+{
+       u8 val = pwr ? AL3010_CONFIG_ENABLE : AL3010_CONFIG_DISABLE;
+       return i2c_smbus_write_byte_data(client, AL3010_REG_SYSTEM, val);
+}
+
+static void al3010_set_pwr_off(void *_data)
+{
+       struct al3010_data *data = _data;
+
+       al3010_set_pwr(data->client, false);
+}
+
+static int al3010_init(struct al3010_data *data)
+{
+       int ret;
+
+       ret = al3010_set_pwr(data->client, true);
+
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(data->client, AL3010_REG_CONFIG,
+                                       FIELD_PREP(AL3010_GAIN_MASK,
+                                                  AL3XXX_RANGE_3));
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int al3010_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan, int *val,
+                          int *val2, long mask)
+{
+       struct al3010_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               /*
+                * ALS ADC value is stored in two adjacent registers:
+                * - low byte of output is stored at AL3010_REG_DATA_LOW
+                * - high byte of output is stored at AL3010_REG_DATA_LOW + 1
+                */
+               ret = i2c_smbus_read_word_data(data->client,
+                                              AL3010_REG_DATA_LOW);
+               if (ret < 0)
+                       return ret;
+               *val = ret;
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               ret = i2c_smbus_read_byte_data(data->client,
+                                              AL3010_REG_CONFIG);
+               if (ret < 0)
+                       return ret;
+
+               ret = FIELD_GET(AL3010_GAIN_MASK, ret);
+               *val = al3010_scales[ret][0];
+               *val2 = al3010_scales[ret][1];
+
+               return IIO_VAL_INT_PLUS_MICRO;
+       }
+       return -EINVAL;
+}
+
+static int al3010_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan, int val,
+                           int val2, long mask)
+{
+       struct al3010_data *data = iio_priv(indio_dev);
+       int i;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               for (i = 0; i < ARRAY_SIZE(al3010_scales); i++) {
+                       if (val != al3010_scales[i][0] ||
+                           val2 != al3010_scales[i][1])
+                               continue;
+
+                       return i2c_smbus_write_byte_data(data->client,
+                                       AL3010_REG_CONFIG,
+                                       FIELD_PREP(AL3010_GAIN_MASK, i));
+               }
+               break;
+       }
+       return -EINVAL;
+}
+
+static const struct iio_info al3010_info = {
+       .read_raw       = al3010_read_raw,
+       .write_raw      = al3010_write_raw,
+       .attrs          = &al3010_attribute_group,
+};
+
+static int al3010_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct al3010_data *data;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       data = iio_priv(indio_dev);
+       i2c_set_clientdata(client, indio_dev);
+       data->client = client;
+
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->info = &al3010_info;
+       indio_dev->name = AL3010_DRV_NAME;
+       indio_dev->channels = al3010_channels;
+       indio_dev->num_channels = ARRAY_SIZE(al3010_channels);
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = al3010_init(data);
+       if (ret < 0) {
+               dev_err(&client->dev, "al3010 chip init failed\n");
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(&client->dev,
+                                       al3010_set_pwr_off,
+                                       data);
+       if (ret < 0)
+               return ret;
+
+       return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static int __maybe_unused al3010_suspend(struct device *dev)
+{
+       return al3010_set_pwr(to_i2c_client(dev), false);
+}
+
+static int __maybe_unused al3010_resume(struct device *dev)
+{
+       return al3010_set_pwr(to_i2c_client(dev), true);
+}
+
+static SIMPLE_DEV_PM_OPS(al3010_pm_ops, al3010_suspend, al3010_resume);
+
+static const struct i2c_device_id al3010_id[] = {
+       {"al3010", },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, al3010_id);
+
+static const struct of_device_id al3010_of_match[] = {
+       { .compatible = "dynaimage,al3010", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, al3010_of_match);
+
+static struct i2c_driver al3010_driver = {
+       .driver = {
+               .name = AL3010_DRV_NAME,
+               .of_match_table = al3010_of_match,
+               .pm = &al3010_pm_ops,
+       },
+       .probe          = al3010_probe,
+       .id_table       = al3010_id,
+};
+module_i2c_driver(al3010_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
+MODULE_AUTHOR("David Heidelberg <david@ixit.cz>");
+MODULE_DESCRIPTION("AL3010 Ambient Light Sensor driver");
+MODULE_LICENSE("GPL v2");
index a21aa99..20ed0a7 100644 (file)
@@ -7,11 +7,15 @@
  * IIO driver for AL3320A (7-bit I2C slave address 0x1C).
  *
  * TODO: interrupt support, thresholds
+ * When the driver will get support for interrupt handling, then interrupt
+ * will need to be disabled before turning sensor OFF in order to avoid
+ * potential races with the interrupt handling.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
+#include <linux/bitfield.h>
 #include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -36,8 +40,7 @@
 #define AL3320A_CONFIG_DISABLE         0x00
 #define AL3320A_CONFIG_ENABLE          0x01
 
-#define AL3320A_GAIN_SHIFT             1
-#define AL3320A_GAIN_MASK              (BIT(2) | BIT(1))
+#define AL3320A_GAIN_MASK              GENMASK(2, 1)
 
 /* chip params default values */
 #define AL3320A_DEFAULT_MEAN_TIME      4
@@ -79,18 +82,31 @@ static const struct attribute_group al3320a_attribute_group = {
        .attrs = al3320a_attributes,
 };
 
+static int al3320a_set_pwr(struct i2c_client *client, bool pwr)
+{
+       u8 val = pwr ? AL3320A_CONFIG_ENABLE : AL3320A_CONFIG_DISABLE;
+       return i2c_smbus_write_byte_data(client, AL3320A_REG_CONFIG, val);
+}
+
+static void al3320a_set_pwr_off(void *_data)
+{
+       struct al3320a_data *data = _data;
+
+       al3320a_set_pwr(data->client, false);
+}
+
 static int al3320a_init(struct al3320a_data *data)
 {
        int ret;
 
-       /* power on */
-       ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG,
-                                       AL3320A_CONFIG_ENABLE);
+       ret = al3320a_set_pwr(data->client, true);
+
        if (ret < 0)
                return ret;
 
        ret = i2c_smbus_write_byte_data(data->client, AL3320A_REG_CONFIG_RANGE,
-                                       AL3320A_RANGE_3 << AL3320A_GAIN_SHIFT);
+                                       FIELD_PREP(AL3320A_GAIN_MASK,
+                                                  AL3320A_RANGE_3));
        if (ret < 0)
                return ret;
 
@@ -133,7 +149,7 @@ static int al3320a_read_raw(struct iio_dev *indio_dev,
                if (ret < 0)
                        return ret;
 
-               ret = (ret & AL3320A_GAIN_MASK) >> AL3320A_GAIN_SHIFT;
+               ret = FIELD_GET(AL3320A_GAIN_MASK, ret);
                *val = al3320a_scales[ret][0];
                *val2 = al3320a_scales[ret][1];
 
@@ -152,11 +168,13 @@ static int al3320a_write_raw(struct iio_dev *indio_dev,
        switch (mask) {
        case IIO_CHAN_INFO_SCALE:
                for (i = 0; i < ARRAY_SIZE(al3320a_scales); i++) {
-                       if (val == al3320a_scales[i][0] &&
-                           val2 == al3320a_scales[i][1])
-                               return i2c_smbus_write_byte_data(data->client,
+                       if (val != al3320a_scales[i][0] ||
+                           val2 != al3320a_scales[i][1])
+                               continue;
+
+                       return i2c_smbus_write_byte_data(data->client,
                                        AL3320A_REG_CONFIG_RANGE,
-                                       i << AL3320A_GAIN_SHIFT);
+                                       FIELD_PREP(AL3320A_GAIN_MASK, i));
                }
                break;
        }
@@ -196,27 +214,47 @@ static int al3320a_probe(struct i2c_client *client,
                dev_err(&client->dev, "al3320a chip init failed\n");
                return ret;
        }
+
+       ret = devm_add_action_or_reset(&client->dev,
+                                       al3320a_set_pwr_off,
+                                       data);
+       if (ret < 0)
+               return ret;
+
        return devm_iio_device_register(&client->dev, indio_dev);
 }
 
-static int al3320a_remove(struct i2c_client *client)
+static int __maybe_unused al3320a_suspend(struct device *dev)
+{
+       return al3320a_set_pwr(to_i2c_client(dev), false);
+}
+
+static int __maybe_unused al3320a_resume(struct device *dev)
 {
-       return i2c_smbus_write_byte_data(client, AL3320A_REG_CONFIG,
-                                        AL3320A_CONFIG_DISABLE);
+       return al3320a_set_pwr(to_i2c_client(dev), true);
 }
 
+static SIMPLE_DEV_PM_OPS(al3320a_pm_ops, al3320a_suspend, al3320a_resume);
+
 static const struct i2c_device_id al3320a_id[] = {
        {"al3320a", 0},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, al3320a_id);
 
+static const struct of_device_id al3320a_of_match[] = {
+       { .compatible = "dynaimage,al3320a", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, al3320a_of_match);
+
 static struct i2c_driver al3320a_driver = {
        .driver = {
                .name = AL3320A_DRV_NAME,
+               .of_match_table = al3320a_of_match,
+               .pm = &al3320a_pm_ops,
        },
        .probe          = al3320a_probe,
-       .remove         = al3320a_remove,
        .id_table       = al3320a_id,
 };
 
diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
new file mode 100644 (file)
index 0000000..b7ef16b
--- /dev/null
@@ -0,0 +1,720 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * These are the two Sharp GP2AP002 variants supported by this driver:
+ * GP2AP002A00F Ambient Light and Proximity Sensor
+ * GP2AP002S00F Proximity Sensor
+ *
+ * Copyright (C) 2020 Linaro Ltd.
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Based partly on the code in Sony Ericssons GP2AP00200F driver by
+ * Courtney Cavin and Oskar Andero in drivers/input/misc/gp2ap002a00f.c
+ * Based partly on a Samsung misc driver submitted by
+ * Donggeun Kim & Minkyu Kang in 2011:
+ * https://lore.kernel.org/lkml/1315556546-7445-1-git-send-email-dg77.kim@samsung.com/
+ * Based partly on a submission by
+ * Jonathan Bakker and Paweł Chmiel in january 2019:
+ * https://lore.kernel.org/linux-input/20190125175045.22576-1-pawel.mikolaj.chmiel@gmail.com/
+ * Based partly on code from the Samsung GT-S7710 by <mjchen@sta.samsung.com>
+ * Based partly on the code in LG Electronics GP2AP00200F driver by
+ * Kenobi Lee <sungyoung.lee@lge.com> and EunYoung Cho <ey.cho@lge.com>
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/consumer.h> /* To get our ADC channel */
+#include <linux/iio/types.h> /* To deal with our ADC channel */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/bits.h>
+#include <linux/math64.h>
+#include <linux/pm.h>
+
+#define GP2AP002_PROX_CHANNEL 0
+#define GP2AP002_ALS_CHANNEL 1
+
+/* ------------------------------------------------------------------------ */
+/* ADDRESS SYMBOL             DATA                                 Init R/W */
+/*                   D7    D6    D5    D4    D3    D2    D1    D0           */
+/* ------------------------------------------------------------------------ */
+/*    0      PROX     X     X     X     X     X     X     X    VO  H'00   R */
+/*    1      GAIN     X     X     X     X  LED0     X     X     X  H'00   W */
+/*    2       HYS  HYSD HYSC1 HYSC0     X HYSF3 HYSF2 HYSF1 HYSF0  H'00   W */
+/*    3     CYCLE     X     X CYCL2 CYCL1 CYCL0  OSC2     X     X  H'00   W */
+/*    4     OPMOD     X     X     X   ASD     X     X  VCON   SSD  H'00   W */
+/*    6       CON     X     X     X OCON1 OCON0     X     X     X  H'00   W */
+/* ------------------------------------------------------------------------ */
+/* VO   :Proximity sensing result(0: no detection, 1: detection)            */
+/* LED0 :Select switch for LED driver's On-registence(0:2x higher, 1:normal)*/
+/* HYSD/HYSF :Adjusts the receiver sensitivity                              */
+/* OSC  :Select switch internal clocl frequency hoppling(0:effective)       */
+/* CYCL :Determine the detection cycle(typically 8ms, up to 128x)           */
+/* SSD  :Software Shutdown function(0:shutdown, 1:operating)                */
+/* VCON :VOUT output method control(0:normal, 1:interrupt)                  */
+/* ASD  :Select switch for analog sleep function(0:ineffective, 1:effective)*/
+/* OCON :Select switch for enabling/disabling VOUT (00:enable, 11:disable)  */
+
+#define GP2AP002_PROX                          0x00
+#define GP2AP002_GAIN                          0x01
+#define GP2AP002_HYS                           0x02
+#define GP2AP002_CYCLE                         0x03
+#define GP2AP002_OPMOD                         0x04
+#define GP2AP002_CON                           0x06
+
+#define GP2AP002_PROX_VO_DETECT                        BIT(0)
+
+/* Setting this bit to 0 means 2x higher LED resistance */
+#define GP2AP002_GAIN_LED_NORMAL               BIT(3)
+
+/*
+ * These bits adjusts the proximity sensitivity, determining characteristics
+ * of the detection distance and its hysteresis.
+ */
+#define GP2AP002_HYS_HYSD_SHIFT                7
+#define GP2AP002_HYS_HYSD_MASK         BIT(7)
+#define GP2AP002_HYS_HYSC_SHIFT                5
+#define GP2AP002_HYS_HYSC_MASK         GENMASK(6, 5)
+#define GP2AP002_HYS_HYSF_SHIFT                0
+#define GP2AP002_HYS_HYSF_MASK         GENMASK(3, 0)
+#define GP2AP002_HYS_MASK              (GP2AP002_HYS_HYSD_MASK | \
+                                        GP2AP002_HYS_HYSC_MASK | \
+                                        GP2AP002_HYS_HYSF_MASK)
+
+/*
+ * These values determine the detection cycle response time
+ * 0: 8ms, 1: 16ms, 2: 32ms, 3: 64ms, 4: 128ms,
+ * 5: 256ms, 6: 512ms, 7: 1024ms
+ */
+#define GP2AP002_CYCLE_CYCL_SHIFT      3
+#define GP2AP002_CYCLE_CYCL_MASK       GENMASK(5, 3)
+
+/*
+ * Select switch for internal clock frequency hopping
+ *     0: effective,
+ *     1: ineffective
+ */
+#define GP2AP002_CYCLE_OSC_EFFECTIVE   0
+#define GP2AP002_CYCLE_OSC_INEFFECTIVE BIT(2)
+#define GP2AP002_CYCLE_OSC_MASK                BIT(2)
+
+/* Analog sleep effective */
+#define GP2AP002_OPMOD_ASD             BIT(4)
+/* Enable chip */
+#define GP2AP002_OPMOD_SSD_OPERATING   BIT(0)
+/* IRQ mode */
+#define GP2AP002_OPMOD_VCON_IRQ                BIT(1)
+#define GP2AP002_OPMOD_MASK            (BIT(0) | BIT(1) | BIT(4))
+
+/*
+ * Select switch for enabling/disabling Vout pin
+ * 0: enable
+ * 2: force to go Low
+ * 3: force to go High
+ */
+#define GP2AP002_CON_OCON_SHIFT                3
+#define GP2AP002_CON_OCON_ENABLE       (0x0 << GP2AP002_CON_OCON_SHIFT)
+#define GP2AP002_CON_OCON_LOW          (0x2 << GP2AP002_CON_OCON_SHIFT)
+#define GP2AP002_CON_OCON_HIGH         (0x3 << GP2AP002_CON_OCON_SHIFT)
+#define GP2AP002_CON_OCON_MASK         (0x3 << GP2AP002_CON_OCON_SHIFT)
+
+/**
+ * struct gp2ap002 - GP2AP002 state
+ * @map: regmap pointer for the i2c regmap
+ * @dev: pointer to parent device
+ * @vdd: regulator controlling VDD
+ * @vio: regulator controlling VIO
+ * @alsout: IIO ADC channel to convert the ALSOUT signal
+ * @hys_far: hysteresis control from device tree
+ * @hys_close: hysteresis control from device tree
+ * @is_gp2ap002s00f: this is the GP2AP002F variant of the chip
+ * @irq: the IRQ line used by this device
+ * @enabled: we cannot read the status of the hardware so we need to
+ * keep track of whether the event is enabled using this state variable
+ */
+struct gp2ap002 {
+       struct regmap *map;
+       struct device *dev;
+       struct regulator *vdd;
+       struct regulator *vio;
+       struct iio_channel *alsout;
+       u8 hys_far;
+       u8 hys_close;
+       bool is_gp2ap002s00f;
+       int irq;
+       bool enabled;
+};
+
+static irqreturn_t gp2ap002_prox_irq(int irq, void *d)
+{
+       struct iio_dev *indio_dev = d;
+       struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+       u64 ev;
+       int val;
+       int ret;
+
+       ret = regmap_read(gp2ap002->map, GP2AP002_PROX, &val);
+       if (ret) {
+               dev_err(gp2ap002->dev, "error reading proximity\n");
+               goto err_retrig;
+       }
+
+       if (val & GP2AP002_PROX_VO_DETECT) {
+               /* Close */
+               dev_dbg(gp2ap002->dev, "close\n");
+               ret = regmap_write(gp2ap002->map, GP2AP002_HYS,
+                                  gp2ap002->hys_far);
+               if (ret)
+                       dev_err(gp2ap002->dev,
+                               "error setting up proximity hysteresis\n");
+               ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, GP2AP002_PROX_CHANNEL,
+                                       IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING);
+       } else {
+               /* Far */
+               dev_dbg(gp2ap002->dev, "far\n");
+               ret = regmap_write(gp2ap002->map, GP2AP002_HYS,
+                                  gp2ap002->hys_close);
+               if (ret)
+                       dev_err(gp2ap002->dev,
+                               "error setting up proximity hysteresis\n");
+               ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, GP2AP002_PROX_CHANNEL,
+                                       IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING);
+       }
+       iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
+
+       /*
+        * After changing hysteresis, we need to wait for one detection
+        * cycle to see if anything changed, or we will just trigger the
+        * previous interrupt again. A detection cycle depends on the CYCLE
+        * register, we are hard-coding ~8 ms in probe() so wait some more
+        * than this, 20-30 ms.
+        */
+       usleep_range(20000, 30000);
+
+err_retrig:
+       ret = regmap_write(gp2ap002->map, GP2AP002_CON,
+                          GP2AP002_CON_OCON_ENABLE);
+       if (ret)
+               dev_err(gp2ap002->dev, "error setting up VOUT control\n");
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * This array maps current and lux.
+ *
+ * Ambient light sensing range is 3 to 55000 lux.
+ *
+ * This mapping is based on the following formula.
+ * illuminance = 10 ^ (current[mA] / 10)
+ *
+ * When the ADC measures 0, return 0 lux.
+ */
+static const u16 gp2ap002_illuminance_table[] = {
+       0, 1, 1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 25, 32, 40, 50, 63, 79,
+       100, 126, 158, 200, 251, 316, 398, 501, 631, 794, 1000, 1259, 1585,
+       1995, 2512, 3162, 3981, 5012, 6310, 7943, 10000, 12589, 15849, 19953,
+       25119, 31623, 39811, 50119,
+};
+
+static int gp2ap002_get_lux(struct gp2ap002 *gp2ap002)
+{
+       int ret, res;
+       u16 lux;
+
+       ret = iio_read_channel_processed(gp2ap002->alsout, &res);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(gp2ap002->dev, "read %d mA from ADC\n", res);
+
+       /* ensure we don't under/overflow */
+       res = clamp(res, 0, (int)ARRAY_SIZE(gp2ap002_illuminance_table) - 1);
+       lux = gp2ap002_illuminance_table[res];
+
+       return (int)lux;
+}
+
+static int gp2ap002_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               switch (chan->type) {
+               case IIO_LIGHT:
+                       ret = gp2ap002_get_lux(gp2ap002);
+                       if (ret < 0)
+                               return ret;
+                       *val = ret;
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+       default:
+               return -EINVAL;
+       }
+}
+
+static int gp2ap002_init(struct gp2ap002 *gp2ap002)
+{
+       int ret;
+
+       /* Set up the IR LED resistance */
+       ret = regmap_write(gp2ap002->map, GP2AP002_GAIN,
+                          GP2AP002_GAIN_LED_NORMAL);
+       if (ret) {
+               dev_err(gp2ap002->dev, "error setting up LED gain\n");
+               return ret;
+       }
+       ret = regmap_write(gp2ap002->map, GP2AP002_HYS, gp2ap002->hys_far);
+       if (ret) {
+               dev_err(gp2ap002->dev,
+                       "error setting up proximity hysteresis\n");
+               return ret;
+       }
+
+       /* Disable internal frequency hopping */
+       ret = regmap_write(gp2ap002->map, GP2AP002_CYCLE,
+                          GP2AP002_CYCLE_OSC_INEFFECTIVE);
+       if (ret) {
+               dev_err(gp2ap002->dev,
+                       "error setting up internal frequency hopping\n");
+               return ret;
+       }
+
+       /* Enable chip and IRQ, disable analog sleep */
+       ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD,
+                          GP2AP002_OPMOD_SSD_OPERATING |
+                          GP2AP002_OPMOD_VCON_IRQ);
+       if (ret) {
+               dev_err(gp2ap002->dev, "error setting up operation mode\n");
+               return ret;
+       }
+
+       /* Interrupt on VOUT enabled */
+       ret = regmap_write(gp2ap002->map, GP2AP002_CON,
+                          GP2AP002_CON_OCON_ENABLE);
+       if (ret)
+               dev_err(gp2ap002->dev, "error setting up VOUT control\n");
+
+       return ret;
+}
+
+static int gp2ap002_read_event_config(struct iio_dev *indio_dev,
+                                     const struct iio_chan_spec *chan,
+                                     enum iio_event_type type,
+                                     enum iio_event_direction dir)
+{
+       struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+
+       /*
+        * We just keep track of this internally, as it is not possible to
+        * query the hardware.
+        */
+       return gp2ap002->enabled;
+}
+
+static int gp2ap002_write_event_config(struct iio_dev *indio_dev,
+                                      const struct iio_chan_spec *chan,
+                                      enum iio_event_type type,
+                                      enum iio_event_direction dir,
+                                      int state)
+{
+       struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+
+       if (state) {
+               /*
+                * This will bring the regulators up (unless they are on
+                * already) and reintialize the sensor by using runtime_pm
+                * callbacks.
+                */
+               pm_runtime_get_sync(gp2ap002->dev);
+               gp2ap002->enabled = true;
+       } else {
+               pm_runtime_mark_last_busy(gp2ap002->dev);
+               pm_runtime_put_autosuspend(gp2ap002->dev);
+               gp2ap002->enabled = false;
+       }
+
+       return 0;
+}
+
+static const struct iio_info gp2ap002_info = {
+       .read_raw = gp2ap002_read_raw,
+       .read_event_config = gp2ap002_read_event_config,
+       .write_event_config = gp2ap002_write_event_config,
+};
+
+static const struct iio_event_spec gp2ap002_events[] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_EITHER,
+               .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+       },
+};
+
+static const struct iio_chan_spec gp2ap002_channels[] = {
+       {
+               .type = IIO_PROXIMITY,
+               .event_spec = gp2ap002_events,
+               .num_event_specs = ARRAY_SIZE(gp2ap002_events),
+       },
+       {
+               .type = IIO_LIGHT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .channel = GP2AP002_ALS_CHANNEL,
+       },
+};
+
+/*
+ * We need a special regmap because this hardware expects to
+ * write single bytes to registers but read a 16bit word on some
+ * variants and discard the lower 8 bits so combine
+ * i2c_smbus_read_word_data() with i2c_smbus_write_byte_data()
+ * selectively like this.
+ */
+static int gp2ap002_regmap_i2c_read(void *context, unsigned int reg,
+                                   unsigned int *val)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+       int ret;
+
+       ret = i2c_smbus_read_word_data(i2c, reg);
+       if (ret < 0)
+               return ret;
+
+       *val = (ret >> 8) & 0xFF;
+
+       return 0;
+}
+
+static int gp2ap002_regmap_i2c_write(void *context, unsigned int reg,
+                                    unsigned int val)
+{
+       struct device *dev = context;
+       struct i2c_client *i2c = to_i2c_client(dev);
+
+       return i2c_smbus_write_byte_data(i2c, reg, val);
+}
+
+static struct regmap_bus gp2ap002_regmap_bus = {
+       .reg_read = gp2ap002_regmap_i2c_read,
+       .reg_write = gp2ap002_regmap_i2c_write,
+};
+
+static int gp2ap002_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct gp2ap002 *gp2ap002;
+       struct iio_dev *indio_dev;
+       struct device *dev = &client->dev;
+       enum iio_chan_type ch_type;
+       static const struct regmap_config config = {
+               .reg_bits = 8,
+               .val_bits = 8,
+               .max_register = GP2AP002_CON,
+       };
+       struct regmap *regmap;
+       int num_chan;
+       const char *compat;
+       u8 val;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*gp2ap002));
+       if (!indio_dev)
+               return -ENOMEM;
+       i2c_set_clientdata(client, indio_dev);
+
+       gp2ap002 = iio_priv(indio_dev);
+       gp2ap002->dev = dev;
+
+       /*
+        * Check the device compatible like this makes it possible to use
+        * ACPI PRP0001 for registering the sensor using device tree
+        * properties.
+        */
+       ret = device_property_read_string(dev, "compatible", &compat);
+       if (ret) {
+               dev_err(dev, "cannot check compatible\n");
+               return ret;
+       }
+       gp2ap002->is_gp2ap002s00f = !strcmp(compat, "sharp,gp2ap002s00f");
+
+       regmap = devm_regmap_init(dev, &gp2ap002_regmap_bus, dev, &config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to register i2c regmap %d\n",
+                       (int)PTR_ERR(regmap));
+               return PTR_ERR(regmap);
+       }
+       gp2ap002->map = regmap;
+
+       /*
+        * The hysteresis settings are coded into the device tree as values
+        * to be written into the hysteresis register. The datasheet defines
+        * modes "A", "B1" and "B2" with fixed values to be use but vendor
+        * code trees for actual devices are tweaking these values and refer to
+        * modes named things like "B1.5". To be able to support any devices,
+        * we allow passing an arbitrary hysteresis setting for "near" and
+        * "far".
+        */
+
+       /* Check the device tree for the IR LED hysteresis */
+       ret = device_property_read_u8(dev, "sharp,proximity-far-hysteresis",
+                                     &val);
+       if (ret) {
+               dev_err(dev, "failed to obtain proximity far setting\n");
+               return ret;
+       }
+       dev_dbg(dev, "proximity far setting %02x\n", val);
+       gp2ap002->hys_far = val;
+
+       ret = device_property_read_u8(dev, "sharp,proximity-close-hysteresis",
+                                     &val);
+       if (ret) {
+               dev_err(dev, "failed to obtain proximity close setting\n");
+               return ret;
+       }
+       dev_dbg(dev, "proximity close setting %02x\n", val);
+       gp2ap002->hys_close = val;
+
+       /* The GP2AP002A00F has a light sensor too */
+       if (!gp2ap002->is_gp2ap002s00f) {
+               gp2ap002->alsout = devm_iio_channel_get(dev, "alsout");
+               if (IS_ERR(gp2ap002->alsout)) {
+                       if (PTR_ERR(gp2ap002->alsout) == -ENODEV) {
+                               dev_err(dev, "no ADC, deferring...\n");
+                               return -EPROBE_DEFER;
+                       }
+                       dev_err(dev, "failed to get ALSOUT ADC channel\n");
+                       return PTR_ERR(gp2ap002->alsout);
+               }
+               ret = iio_get_channel_type(gp2ap002->alsout, &ch_type);
+               if (ret < 0)
+                       return ret;
+               if (ch_type != IIO_CURRENT) {
+                       dev_err(dev,
+                               "wrong type of IIO channel specified for ALSOUT\n");
+                       return -EINVAL;
+               }
+       }
+
+       gp2ap002->vdd = devm_regulator_get(dev, "vdd");
+       if (IS_ERR(gp2ap002->vdd)) {
+               dev_err(dev, "failed to get VDD regulator\n");
+               return PTR_ERR(gp2ap002->vdd);
+       }
+       gp2ap002->vio = devm_regulator_get(dev, "vio");
+       if (IS_ERR(gp2ap002->vio)) {
+               dev_err(dev, "failed to get VIO regulator\n");
+               return PTR_ERR(gp2ap002->vio);
+       }
+
+       /* Operating voltage 2.4V .. 3.6V according to datasheet */
+       ret = regulator_set_voltage(gp2ap002->vdd, 2400000, 3600000);
+       if (ret) {
+               dev_err(dev, "failed to sett VDD voltage\n");
+               return ret;
+       }
+
+       /* VIO should be between 1.65V and VDD */
+       ret = regulator_get_voltage(gp2ap002->vdd);
+       if (ret < 0) {
+               dev_err(dev, "failed to get VDD voltage\n");
+               return ret;
+       }
+       ret = regulator_set_voltage(gp2ap002->vio, 1650000, ret);
+       if (ret) {
+               dev_err(dev, "failed to set VIO voltage\n");
+               return ret;
+       }
+
+       ret = regulator_enable(gp2ap002->vdd);
+       if (ret) {
+               dev_err(dev, "failed to enable VDD regulator\n");
+               return ret;
+       }
+       ret = regulator_enable(gp2ap002->vio);
+       if (ret) {
+               dev_err(dev, "failed to enable VIO regulator\n");
+               goto out_disable_vdd;
+       }
+
+       msleep(20);
+
+       /*
+        * Initialize the device and signal to runtime PM that now we are
+        * definately up and using power.
+        */
+       ret = gp2ap002_init(gp2ap002);
+       if (ret) {
+               dev_err(dev, "initialization failed\n");
+               goto out_disable_vio;
+       }
+       pm_runtime_get_noresume(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       gp2ap002->enabled = false;
+
+       ret = devm_request_threaded_irq(dev, client->irq, NULL,
+                                       gp2ap002_prox_irq, IRQF_ONESHOT,
+                                       "gp2ap002", indio_dev);
+       if (ret) {
+               dev_err(dev, "unable to request IRQ\n");
+               goto out_disable_vio;
+       }
+       gp2ap002->irq = client->irq;
+
+       /*
+        * As the device takes 20 ms + regulator delay to come up with a fresh
+        * measurement after power-on, do not shut it down unnecessarily.
+        * Set autosuspend to a one second.
+        */
+       pm_runtime_set_autosuspend_delay(dev, 1000);
+       pm_runtime_use_autosuspend(dev);
+       pm_runtime_put(dev);
+
+       indio_dev->dev.parent = dev;
+       indio_dev->info = &gp2ap002_info;
+       indio_dev->name = "gp2ap002";
+       indio_dev->channels = gp2ap002_channels;
+       /* Skip light channel for the proximity-only sensor */
+       num_chan = ARRAY_SIZE(gp2ap002_channels);
+       if (gp2ap002->is_gp2ap002s00f)
+               num_chan--;
+       indio_dev->num_channels = num_chan;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(indio_dev);
+       if (ret)
+               goto out_disable_pm;
+       dev_dbg(dev, "Sharp GP2AP002 probed successfully\n");
+
+       return 0;
+
+out_disable_pm:
+       pm_runtime_put_noidle(dev);
+       pm_runtime_disable(dev);
+out_disable_vio:
+       regulator_disable(gp2ap002->vio);
+out_disable_vdd:
+       regulator_disable(gp2ap002->vdd);
+       return ret;
+}
+
+static int gp2ap002_remove(struct i2c_client *client)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+       struct device *dev = &client->dev;
+
+       pm_runtime_get_sync(dev);
+       pm_runtime_put_noidle(dev);
+       pm_runtime_disable(dev);
+       iio_device_unregister(indio_dev);
+       regulator_disable(gp2ap002->vio);
+       regulator_disable(gp2ap002->vdd);
+
+       return 0;
+}
+
+static int __maybe_unused gp2ap002_runtime_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+       int ret;
+
+       /* Deactivate the IRQ */
+       disable_irq(gp2ap002->irq);
+
+       /* Disable chip and IRQ, everything off */
+       ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD, 0x00);
+       if (ret) {
+               dev_err(gp2ap002->dev, "error setting up operation mode\n");
+               return ret;
+       }
+       /*
+        * As these regulators may be shared, at least we are now in
+        * sleep even if the regulators aren't really turned off.
+        */
+       regulator_disable(gp2ap002->vio);
+       regulator_disable(gp2ap002->vdd);
+
+       return 0;
+}
+
+static int __maybe_unused gp2ap002_runtime_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
+       int ret;
+
+       ret = regulator_enable(gp2ap002->vdd);
+       if (ret) {
+               dev_err(dev, "failed to enable VDD regulator in resume path\n");
+               return ret;
+       }
+       ret = regulator_enable(gp2ap002->vio);
+       if (ret) {
+               dev_err(dev, "failed to enable VIO regulator in resume path\n");
+               return ret;
+       }
+
+       msleep(20);
+
+       ret = gp2ap002_init(gp2ap002);
+       if (ret) {
+               dev_err(dev, "re-initialization failed\n");
+               return ret;
+       }
+
+       /* Re-activate the IRQ */
+       enable_irq(gp2ap002->irq);
+
+       return 0;
+}
+
+static const struct dev_pm_ops gp2ap002_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(gp2ap002_runtime_suspend,
+                          gp2ap002_runtime_resume, NULL)
+};
+
+static const struct i2c_device_id gp2ap002_id_table[] = {
+       { "gp2ap002", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table);
+
+static const struct of_device_id gp2ap002_of_match[] = {
+       { .compatible = "sharp,gp2ap002a00f" },
+       { .compatible = "sharp,gp2ap002s00f" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, gp2ap002_of_match);
+
+static struct i2c_driver gp2ap002_driver = {
+       .driver = {
+               .name = "gp2ap002",
+               .of_match_table = gp2ap002_of_match,
+               .pm = &gp2ap002_dev_pm_ops,
+       },
+       .probe = gp2ap002_probe,
+       .remove = gp2ap002_remove,
+       .id_table = gp2ap002_id_table,
+};
+module_i2c_driver(gp2ap002_driver);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("GP2AP002 ambient light and proximity sensor driver");
+MODULE_LICENSE("GPL v2");
index 4d70c5b..7fbbce0 100644 (file)
@@ -1390,6 +1390,12 @@ static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev)
 
        mutex_lock(&data->lock);
 
+       err = iio_triggered_buffer_postenable(indio_dev);
+       if (err < 0) {
+               mutex_unlock(&data->lock);
+               return err;
+       }
+
        /*
         * Enable triggers according to the scan_mask. Enabling either
         * LIGHT_CLEAR or LIGHT_IR scan mode results in enabling ALS
@@ -1420,14 +1426,12 @@ static int gp2ap020a00f_buffer_postenable(struct iio_dev *indio_dev)
                goto error_unlock;
 
        data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
-       if (!data->buffer) {
+       if (!data->buffer)
                err = -ENOMEM;
-               goto error_unlock;
-       }
-
-       err = iio_triggered_buffer_postenable(indio_dev);
 
 error_unlock:
+       if (err < 0)
+               iio_triggered_buffer_predisable(indio_dev);
        mutex_unlock(&data->lock);
 
        return err;
@@ -1436,14 +1440,10 @@ error_unlock:
 static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev)
 {
        struct gp2ap020a00f_data *data = iio_priv(indio_dev);
-       int i, err;
+       int i, err = 0;
 
        mutex_lock(&data->lock);
 
-       err = iio_triggered_buffer_predisable(indio_dev);
-       if (err < 0)
-               goto error_unlock;
-
        for_each_set_bit(i, indio_dev->active_scan_mask,
                indio_dev->masklength) {
                switch (i) {
@@ -1465,7 +1465,8 @@ static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev)
        if (err == 0)
                kfree(data->buffer);
 
-error_unlock:
+       iio_triggered_buffer_predisable(indio_dev);
+
        mutex_unlock(&data->lock);
 
        return err;
index 015a21f..9174ab9 100644 (file)
 #define SI1133_INPUT_FRACTION_LOW      15
 #define SI1133_LUX_OUTPUT_FRACTION     12
 #define SI1133_LUX_BUFFER_SIZE         9
+#define SI1133_MEASURE_BUFFER_SIZE     3
+
+#define SI1133_SIGN_BIT_INDEX 23
 
 static const int si1133_scale_available[] = {
        1, 2, 4, 8, 16, 32, 64, 128};
@@ -234,13 +237,13 @@ static const struct si1133_lux_coeff lux_coeff = {
        }
 };
 
-static int si1133_calculate_polynomial_inner(u32 input, u8 fraction, u16 mag,
+static int si1133_calculate_polynomial_inner(s32 input, u8 fraction, u16 mag,
                                             s8 shift)
 {
        return ((input << fraction) / mag) << shift;
 }
 
-static int si1133_calculate_output(u32 x, u32 y, u8 x_order, u8 y_order,
+static int si1133_calculate_output(s32 x, s32 y, u8 x_order, u8 y_order,
                                   u8 input_fraction, s8 sign,
                                   const struct si1133_coeff *coeffs)
 {
@@ -276,7 +279,7 @@ static int si1133_calculate_output(u32 x, u32 y, u8 x_order, u8 y_order,
  * The algorithm is from:
  * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00716
  */
-static int si1133_calc_polynomial(u32 x, u32 y, u8 input_fraction, u8 num_coeff,
+static int si1133_calc_polynomial(s32 x, s32 y, u8 input_fraction, u8 num_coeff,
                                  const struct si1133_coeff *coeffs)
 {
        u8 x_order, y_order;
@@ -614,7 +617,7 @@ static int si1133_measure(struct si1133_data *data,
 {
        int err;
 
-       __be16 resp;
+       u8 buffer[SI1133_MEASURE_BUFFER_SIZE];
 
        err = si1133_set_adcmux(data, 0, chan->channel);
        if (err)
@@ -625,12 +628,13 @@ static int si1133_measure(struct si1133_data *data,
        if (err)
                return err;
 
-       err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(resp),
-                              (u8 *)&resp);
+       err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(buffer),
+                              buffer);
        if (err)
                return err;
 
-       *val = be16_to_cpu(resp);
+       *val = sign_extend32((buffer[0] << 16) | (buffer[1] << 8) | buffer[2],
+                            SI1133_SIGN_BIT_INDEX);
 
        return err;
 }
@@ -704,9 +708,9 @@ static int si1133_get_lux(struct si1133_data *data, int *val)
 {
        int err;
        int lux;
-       u32 high_vis;
-       u32 low_vis;
-       u32 ir;
+       s32 high_vis;
+       s32 low_vis;
+       s32 ir;
        u8 buffer[SI1133_LUX_BUFFER_SIZE];
 
        /* Activate lux channels */
@@ -719,9 +723,16 @@ static int si1133_get_lux(struct si1133_data *data, int *val)
        if (err)
                return err;
 
-       high_vis = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
-       low_vis = (buffer[3] << 16) | (buffer[4] << 8) | buffer[5];
-       ir = (buffer[6] << 16) | (buffer[7] << 8) | buffer[8];
+       high_vis =
+               sign_extend32((buffer[0] << 16) | (buffer[1] << 8) | buffer[2],
+                             SI1133_SIGN_BIT_INDEX);
+
+       low_vis =
+               sign_extend32((buffer[3] << 16) | (buffer[4] << 8) | buffer[5],
+                             SI1133_SIGN_BIT_INDEX);
+
+       ir = sign_extend32((buffer[6] << 16) | (buffer[7] << 8) | buffer[8],
+                          SI1133_SIGN_BIT_INDEX);
 
        if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD)
                lux = si1133_calc_polynomial(high_vis, ir,
index b0e241a..ec803c1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/i2c.h>
 #include <linux/err.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -57,6 +58,8 @@
 #define VCNL4000_AL_OD         BIT(4) /* start on-demand ALS measurement */
 #define VCNL4000_PS_OD         BIT(3) /* start on-demand proximity measurement */
 
+#define VCNL4000_SLEEP_DELAY_MS        2000 /* before we enter pm_runtime_suspend */
+
 enum vcnl4000_device_ids {
        VCNL4000,
        VCNL4010,
@@ -87,6 +90,7 @@ struct vcnl4000_chip_spec {
        int (*init)(struct vcnl4000_data *data);
        int (*measure_light)(struct vcnl4000_data *data, int *val);
        int (*measure_proximity)(struct vcnl4000_data *data, int *val);
+       int (*set_power_state)(struct vcnl4000_data *data, bool on);
 };
 
 static const struct i2c_device_id vcnl4000_id[] = {
@@ -99,6 +103,12 @@ static const struct i2c_device_id vcnl4000_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
 
+static int vcnl4000_set_power_state(struct vcnl4000_data *data, bool on)
+{
+       /* no suspend op */
+       return 0;
+}
+
 static int vcnl4000_init(struct vcnl4000_data *data)
 {
        int ret, prod_id;
@@ -127,9 +137,31 @@ static int vcnl4000_init(struct vcnl4000_data *data)
        data->al_scale = 250000;
        mutex_init(&data->vcnl4000_lock);
 
-       return 0;
+       return data->chip_spec->set_power_state(data, true);
 };
 
+static int vcnl4200_set_power_state(struct vcnl4000_data *data, bool on)
+{
+       u16 val = on ? 0 /* power on */ : 1 /* shut down */;
+       int ret;
+
+       ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, val);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, val);
+       if (ret < 0)
+               return ret;
+
+       if (on) {
+               /* Wait at least one integration cycle before fetching data */
+               data->vcnl4200_al.last_measurement = ktime_get();
+               data->vcnl4200_ps.last_measurement = ktime_get();
+       }
+
+       return 0;
+}
+
 static int vcnl4200_init(struct vcnl4000_data *data)
 {
        int ret, id;
@@ -155,36 +187,31 @@ static int vcnl4200_init(struct vcnl4000_data *data)
 
        data->rev = (ret >> 8) & 0xf;
 
-       /* Set defaults and enable both channels */
-       ret = i2c_smbus_write_word_data(data->client, VCNL4200_AL_CONF, 0);
-       if (ret < 0)
-               return ret;
-       ret = i2c_smbus_write_word_data(data->client, VCNL4200_PS_CONF1, 0);
-       if (ret < 0)
-               return ret;
-
        data->vcnl4200_al.reg = VCNL4200_AL_DATA;
        data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
        switch (id) {
        case VCNL4200_PROD_ID:
-               /* Integration time is 50ms, but the experiments */
-               /* show 54ms in total. */
-               data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
-               data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
+               /* Default wait time is 50ms, add 20% tolerance. */
+               data->vcnl4200_al.sampling_rate = ktime_set(0, 60000 * 1000);
+               /* Default wait time is 4.8ms, add 20% tolerance. */
+               data->vcnl4200_ps.sampling_rate = ktime_set(0, 5760 * 1000);
                data->al_scale = 24000;
                break;
        case VCNL4040_PROD_ID:
-               /* Integration time is 80ms, add 10ms. */
-               data->vcnl4200_al.sampling_rate = ktime_set(0, 100000 * 1000);
-               data->vcnl4200_ps.sampling_rate = ktime_set(0, 100000 * 1000);
+               /* Default wait time is 80ms, add 20% tolerance. */
+               data->vcnl4200_al.sampling_rate = ktime_set(0, 96000 * 1000);
+               /* Default wait time is 5ms, add 20% tolerance. */
+               data->vcnl4200_ps.sampling_rate = ktime_set(0, 6000 * 1000);
                data->al_scale = 120000;
                break;
        }
-       data->vcnl4200_al.last_measurement = ktime_set(0, 0);
-       data->vcnl4200_ps.last_measurement = ktime_set(0, 0);
        mutex_init(&data->vcnl4200_al.lock);
        mutex_init(&data->vcnl4200_ps.lock);
 
+       ret = data->chip_spec->set_power_state(data, true);
+       if (ret < 0)
+               return ret;
+
        return 0;
 };
 
@@ -291,24 +318,28 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
                .init = vcnl4000_init,
                .measure_light = vcnl4000_measure_light,
                .measure_proximity = vcnl4000_measure_proximity,
+               .set_power_state = vcnl4000_set_power_state,
        },
        [VCNL4010] = {
                .prod = "VCNL4010/4020",
                .init = vcnl4000_init,
                .measure_light = vcnl4000_measure_light,
                .measure_proximity = vcnl4000_measure_proximity,
+               .set_power_state = vcnl4000_set_power_state,
        },
        [VCNL4040] = {
                .prod = "VCNL4040",
                .init = vcnl4200_init,
                .measure_light = vcnl4200_measure_light,
                .measure_proximity = vcnl4200_measure_proximity,
+               .set_power_state = vcnl4200_set_power_state,
        },
        [VCNL4200] = {
                .prod = "VCNL4200",
                .init = vcnl4200_init,
                .measure_light = vcnl4200_measure_light,
                .measure_proximity = vcnl4200_measure_proximity,
+               .set_power_state = vcnl4200_set_power_state,
        },
 };
 
@@ -323,6 +354,23 @@ static const struct iio_chan_spec vcnl4000_channels[] = {
        }
 };
 
+static int vcnl4000_set_pm_runtime_state(struct vcnl4000_data *data, bool on)
+{
+       struct device *dev = &data->client->dev;
+       int ret;
+
+       if (on) {
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0)
+                       pm_runtime_put_noidle(dev);
+       } else {
+               pm_runtime_mark_last_busy(dev);
+               ret = pm_runtime_put_autosuspend(dev);
+       }
+
+       return ret;
+}
+
 static int vcnl4000_read_raw(struct iio_dev *indio_dev,
                                struct iio_chan_spec const *chan,
                                int *val, int *val2, long mask)
@@ -332,20 +380,26 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
+               ret = vcnl4000_set_pm_runtime_state(data, true);
+               if  (ret < 0)
+                       return ret;
+
                switch (chan->type) {
                case IIO_LIGHT:
                        ret = data->chip_spec->measure_light(data, val);
-                       if (ret < 0)
-                               return ret;
-                       return IIO_VAL_INT;
+                       if (!ret)
+                               ret = IIO_VAL_INT;
+                       break;
                case IIO_PROXIMITY:
                        ret = data->chip_spec->measure_proximity(data, val);
-                       if (ret < 0)
-                               return ret;
-                       return IIO_VAL_INT;
+                       if (!ret)
+                               ret = IIO_VAL_INT;
+                       break;
                default:
-                       return -EINVAL;
+                       ret = -EINVAL;
                }
+               vcnl4000_set_pm_runtime_state(data, false);
+               return ret;
        case IIO_CHAN_INFO_SCALE:
                if (chan->type != IIO_LIGHT)
                        return -EINVAL;
@@ -393,7 +447,22 @@ static int vcnl4000_probe(struct i2c_client *client,
        indio_dev->name = VCNL4000_DRV_NAME;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       return devm_iio_device_register(&client->dev, indio_dev);
+       ret = pm_runtime_set_active(&client->dev);
+       if (ret < 0)
+               goto fail_poweroff;
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0)
+               goto fail_poweroff;
+
+       pm_runtime_enable(&client->dev);
+       pm_runtime_set_autosuspend_delay(&client->dev, VCNL4000_SLEEP_DELAY_MS);
+       pm_runtime_use_autosuspend(&client->dev);
+
+       return 0;
+fail_poweroff:
+       data->chip_spec->set_power_state(data, false);
+       return ret;
 }
 
 static const struct of_device_id vcnl_4000_of_match[] = {
@@ -421,13 +490,51 @@ static const struct of_device_id vcnl_4000_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, vcnl_4000_of_match);
 
+static int vcnl4000_remove(struct i2c_client *client)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct vcnl4000_data *data = iio_priv(indio_dev);
+
+       pm_runtime_dont_use_autosuspend(&client->dev);
+       pm_runtime_disable(&client->dev);
+       iio_device_unregister(indio_dev);
+       pm_runtime_set_suspended(&client->dev);
+
+       return data->chip_spec->set_power_state(data, false);
+}
+
+static int __maybe_unused vcnl4000_runtime_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct vcnl4000_data *data = iio_priv(indio_dev);
+
+       return data->chip_spec->set_power_state(data, false);
+}
+
+static int __maybe_unused vcnl4000_runtime_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct vcnl4000_data *data = iio_priv(indio_dev);
+
+       return data->chip_spec->set_power_state(data, true);
+}
+
+static const struct dev_pm_ops vcnl4000_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(vcnl4000_runtime_suspend,
+                          vcnl4000_runtime_resume, NULL)
+};
+
 static struct i2c_driver vcnl4000_driver = {
        .driver = {
                .name   = VCNL4000_DRV_NAME,
+               .pm     = &vcnl4000_pm_ops,
                .of_match_table = vcnl_4000_of_match,
        },
        .probe  = vcnl4000_probe,
        .id_table = vcnl4000_id,
+       .remove = vcnl4000_remove,
 };
 
 module_i2c_driver(vcnl4000_driver);
index fc7e910..d329967 100644 (file)
@@ -564,7 +564,7 @@ static int ak8974_read_raw(struct iio_dev *indio_dev,
                 * We read all axes and discard all but one, for optimized
                 * reading, use the triggered buffer.
                 */
-               *val = le16_to_cpu(hw_values[chan->address]);
+               *val = (s16)le16_to_cpu(hw_values[chan->address]);
 
                ret = IIO_VAL_INT;
        }
index a0e5f53..2cb11da 100644 (file)
@@ -275,11 +275,20 @@ static int lmp91000_buffer_cb(const void *val, void *private)
 static const struct iio_trigger_ops lmp91000_trigger_ops = {
 };
 
-static int lmp91000_buffer_preenable(struct iio_dev *indio_dev)
+static int lmp91000_buffer_postenable(struct iio_dev *indio_dev)
 {
        struct lmp91000_data *data = iio_priv(indio_dev);
+       int err;
 
-       return iio_channel_start_all_cb(data->cb_buffer);
+       err = iio_triggered_buffer_postenable(indio_dev);
+       if (err)
+               return err;
+
+       err = iio_channel_start_all_cb(data->cb_buffer);
+       if (err)
+               iio_triggered_buffer_predisable(indio_dev);
+
+       return err;
 }
 
 static int lmp91000_buffer_predisable(struct iio_dev *indio_dev)
@@ -288,12 +297,11 @@ static int lmp91000_buffer_predisable(struct iio_dev *indio_dev)
 
        iio_channel_stop_all_cb(data->cb_buffer);
 
-       return 0;
+       return iio_triggered_buffer_predisable(indio_dev);
 }
 
 static const struct iio_buffer_setup_ops lmp91000_buffer_setup_ops = {
-       .preenable = lmp91000_buffer_preenable,
-       .postenable = iio_triggered_buffer_postenable,
+       .postenable = lmp91000_buffer_postenable,
        .predisable = lmp91000_buffer_predisable,
 };
 
index 9c2d9bf..689b978 100644 (file)
@@ -101,6 +101,17 @@ config HP03
          To compile this driver as a module, choose M here: the module
          will be called hp03.
 
+config ICP10100
+       tristate "InvenSense ICP-101xx pressure and temperature sensor"
+       depends on I2C
+       select CRC8
+       help
+         Say yes here to build support for InvenSense ICP-101xx barometric
+         pressure and temperature sensor.
+
+         To compile this driver as a module, choose M here: the module
+         will be called icp10100.
+
 config MPL115
        tristate
 
index 5a79192..083ae87 100644 (file)
@@ -14,6 +14,7 @@ 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
+obj-$(CONFIG_ICP10100) += icp10100.o
 obj-$(CONFIG_MPL115) += mpl115.o
 obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o
 obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o
diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c
new file mode 100644 (file)
index 0000000..06cb5b6
--- /dev/null
@@ -0,0 +1,658 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 InvenSense, Inc.
+ *
+ * Driver for InvenSense ICP-1010xx barometric pressure and temperature sensor.
+ *
+ * Datasheet:
+ * http://www.invensense.com/wp-content/uploads/2018/01/DS-000186-ICP-101xx-v1.2.pdf
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <linux/crc8.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/math64.h>
+#include <linux/regulator/consumer.h>
+#include <linux/iio/iio.h>
+
+#define ICP10100_ID_REG_GET(_reg)      ((_reg) & 0x003F)
+#define ICP10100_ID_REG                        0x08
+#define ICP10100_RESPONSE_WORD_LENGTH  3
+#define ICP10100_CRC8_WORD_LENGTH      2
+#define ICP10100_CRC8_POLYNOMIAL       0x31
+#define ICP10100_CRC8_INIT             0xFF
+
+enum icp10100_mode {
+       ICP10100_MODE_LP,       /* Low power mode: 1x sampling */
+       ICP10100_MODE_N,        /* Normal mode: 2x sampling */
+       ICP10100_MODE_LN,       /* Low noise mode: 4x sampling */
+       ICP10100_MODE_ULN,      /* Ultra low noise mode: 8x sampling */
+       ICP10100_MODE_NB,
+};
+
+struct icp10100_state {
+       struct mutex lock;
+       struct i2c_client *client;
+       struct regulator *vdd;
+       enum icp10100_mode mode;
+       int16_t cal[4];
+};
+
+struct icp10100_command {
+       __be16 cmd;
+       unsigned long wait_us;
+       unsigned long wait_max_us;
+       size_t response_word_nb;
+};
+
+static const struct icp10100_command icp10100_cmd_soft_reset = {
+       .cmd = cpu_to_be16(0x805D),
+       .wait_us = 170,
+       .wait_max_us = 200,
+       .response_word_nb = 0,
+};
+
+static const struct icp10100_command icp10100_cmd_read_id = {
+       .cmd = cpu_to_be16(0xEFC8),
+       .wait_us = 0,
+       .response_word_nb = 1,
+};
+
+static const struct icp10100_command icp10100_cmd_read_otp = {
+       .cmd = cpu_to_be16(0xC7F7),
+       .wait_us = 0,
+       .response_word_nb = 1,
+};
+
+static const struct icp10100_command icp10100_cmd_measure[] = {
+       [ICP10100_MODE_LP] = {
+               .cmd = cpu_to_be16(0x401A),
+               .wait_us = 1800,
+               .wait_max_us = 2000,
+               .response_word_nb = 3,
+       },
+       [ICP10100_MODE_N] = {
+               .cmd = cpu_to_be16(0x48A3),
+               .wait_us = 6300,
+               .wait_max_us = 6500,
+               .response_word_nb = 3,
+       },
+       [ICP10100_MODE_LN] = {
+               .cmd = cpu_to_be16(0x5059),
+               .wait_us = 23800,
+               .wait_max_us = 24000,
+               .response_word_nb = 3,
+       },
+       [ICP10100_MODE_ULN] = {
+               .cmd = cpu_to_be16(0x58E0),
+               .wait_us = 94500,
+               .wait_max_us = 94700,
+               .response_word_nb = 3,
+       },
+};
+
+static const uint8_t icp10100_switch_mode_otp[] =
+       {0xC5, 0x95, 0x00, 0x66, 0x9c};
+
+DECLARE_CRC8_TABLE(icp10100_crc8_table);
+
+static inline int icp10100_i2c_xfer(struct i2c_adapter *adap,
+                                   struct i2c_msg *msgs, int num)
+{
+       int ret;
+
+       ret = i2c_transfer(adap, msgs, num);
+       if (ret < 0)
+               return ret;
+
+       if (ret != num)
+               return -EIO;
+
+       return 0;
+}
+
+static int icp10100_send_cmd(struct icp10100_state *st,
+                            const struct icp10100_command *cmd,
+                            __be16 *buf, size_t buf_len)
+{
+       size_t size = cmd->response_word_nb * ICP10100_RESPONSE_WORD_LENGTH;
+       uint8_t data[16];
+       uint8_t *ptr;
+       uint8_t *buf_ptr = (uint8_t *)buf;
+       struct i2c_msg msgs[2] = {
+               {
+                       .addr = st->client->addr,
+                       .flags = 0,
+                       .len = 2,
+                       .buf = (uint8_t *)&cmd->cmd,
+               }, {
+                       .addr = st->client->addr,
+                       .flags = I2C_M_RD,
+                       .len = size,
+                       .buf = data,
+               },
+       };
+       uint8_t crc;
+       unsigned int i;
+       int ret;
+
+       if (size > sizeof(data))
+               return -EINVAL;
+
+       if (cmd->response_word_nb > 0 &&
+                       (buf == NULL || buf_len < (cmd->response_word_nb * 2)))
+               return -EINVAL;
+
+       dev_dbg(&st->client->dev, "sending cmd %#x\n", be16_to_cpu(cmd->cmd));
+
+       if (cmd->response_word_nb > 0 && cmd->wait_us == 0) {
+               /* direct command-response without waiting */
+               ret = icp10100_i2c_xfer(st->client->adapter, msgs,
+                                       ARRAY_SIZE(msgs));
+               if (ret)
+                       return ret;
+       } else {
+               /* transfer command write */
+               ret = icp10100_i2c_xfer(st->client->adapter, &msgs[0], 1);
+               if (ret)
+                       return ret;
+               if (cmd->wait_us > 0)
+                       usleep_range(cmd->wait_us, cmd->wait_max_us);
+               /* transfer response read if needed */
+               if (cmd->response_word_nb > 0) {
+                       ret = icp10100_i2c_xfer(st->client->adapter, &msgs[1], 1);
+                       if (ret)
+                               return ret;
+               } else {
+                       return 0;
+               }
+       }
+
+       /* process read words with crc checking */
+       for (i = 0; i < cmd->response_word_nb; ++i) {
+               ptr = &data[i * ICP10100_RESPONSE_WORD_LENGTH];
+               crc = crc8(icp10100_crc8_table, ptr, ICP10100_CRC8_WORD_LENGTH,
+                          ICP10100_CRC8_INIT);
+               if (crc != ptr[ICP10100_CRC8_WORD_LENGTH]) {
+                       dev_err(&st->client->dev, "crc error recv=%#x calc=%#x\n",
+                               ptr[ICP10100_CRC8_WORD_LENGTH], crc);
+                       return -EIO;
+               }
+               *buf_ptr++ = ptr[0];
+               *buf_ptr++ = ptr[1];
+       }
+
+       return 0;
+}
+
+static int icp10100_read_cal_otp(struct icp10100_state *st)
+{
+       __be16 val;
+       int i;
+       int ret;
+
+       /* switch into OTP read mode */
+       ret = i2c_master_send(st->client, icp10100_switch_mode_otp,
+                             ARRAY_SIZE(icp10100_switch_mode_otp));
+       if (ret < 0)
+               return ret;
+       if (ret != ARRAY_SIZE(icp10100_switch_mode_otp))
+               return -EIO;
+
+       /* read 4 calibration values */
+       for (i = 0; i < 4; ++i) {
+               ret = icp10100_send_cmd(st, &icp10100_cmd_read_otp,
+                                       &val, sizeof(val));
+               if (ret)
+                       return ret;
+               st->cal[i] = be16_to_cpu(val);
+               dev_dbg(&st->client->dev, "cal[%d] = %d\n", i, st->cal[i]);
+       }
+
+       return 0;
+}
+
+static int icp10100_init_chip(struct icp10100_state *st)
+{
+       __be16 val;
+       uint16_t id;
+       int ret;
+
+       /* read and check id */
+       ret = icp10100_send_cmd(st, &icp10100_cmd_read_id, &val, sizeof(val));
+       if (ret)
+               return ret;
+       id = ICP10100_ID_REG_GET(be16_to_cpu(val));
+       if (id != ICP10100_ID_REG) {
+               dev_err(&st->client->dev, "invalid id %#x\n", id);
+               return -ENODEV;
+       }
+
+       /* read calibration data from OTP */
+       ret = icp10100_read_cal_otp(st);
+       if (ret)
+               return ret;
+
+       /* reset chip */
+       return icp10100_send_cmd(st, &icp10100_cmd_soft_reset, NULL, 0);
+}
+
+static int icp10100_get_measures(struct icp10100_state *st,
+                               uint32_t *pressure, uint16_t *temperature)
+{
+       const struct icp10100_command *cmd;
+       __be16 measures[3];
+       int ret;
+
+       pm_runtime_get_sync(&st->client->dev);
+
+       mutex_lock(&st->lock);
+       cmd = &icp10100_cmd_measure[st->mode];
+       ret = icp10100_send_cmd(st, cmd, measures, sizeof(measures));
+       mutex_unlock(&st->lock);
+       if (ret)
+               goto error_measure;
+
+       *pressure = (be16_to_cpu(measures[0]) << 8) |
+                       (be16_to_cpu(measures[1]) >> 8);
+       *temperature = be16_to_cpu(measures[2]);
+
+       pm_runtime_mark_last_busy(&st->client->dev);
+error_measure:
+       pm_runtime_put_autosuspend(&st->client->dev);
+       return ret;
+}
+
+static uint32_t icp10100_get_pressure(struct icp10100_state *st,
+                                     uint32_t raw_pressure, uint16_t raw_temp)
+{
+       static int32_t p_calib[] = {45000, 80000, 105000};
+       static int32_t lut_lower = 3670016;
+       static int32_t lut_upper = 12058624;
+       static int32_t inv_quadr_factor = 16777216;
+       static int32_t offset_factor = 2048;
+       int64_t val1, val2;
+       int32_t p_lut[3];
+       int32_t t, t_square;
+       int64_t a, b, c;
+       uint32_t pressure_mPa;
+
+       dev_dbg(&st->client->dev, "raw: pressure = %u, temp = %u\n",
+               raw_pressure, raw_temp);
+
+       /* compute p_lut values */
+       t = (int32_t)raw_temp - 32768;
+       t_square = t * t;
+       val1 = (int64_t)st->cal[0] * (int64_t)t_square;
+       p_lut[0] = lut_lower + (int32_t)div_s64(val1, inv_quadr_factor);
+       val1 = (int64_t)st->cal[1] * (int64_t)t_square;
+       p_lut[1] = offset_factor * st->cal[3] +
+                       (int32_t)div_s64(val1, inv_quadr_factor);
+       val1 = (int64_t)st->cal[2] * (int64_t)t_square;
+       p_lut[2] = lut_upper + (int32_t)div_s64(val1, inv_quadr_factor);
+       dev_dbg(&st->client->dev, "p_lut = [%d, %d, %d]\n",
+               p_lut[0], p_lut[1], p_lut[2]);
+
+       /* compute a, b, c factors */
+       val1 = (int64_t)p_lut[0] * (int64_t)p_lut[1] *
+                       (int64_t)(p_calib[0] - p_calib[1]) +
+               (int64_t)p_lut[1] * (int64_t)p_lut[2] *
+                       (int64_t)(p_calib[1] - p_calib[2]) +
+               (int64_t)p_lut[2] * (int64_t)p_lut[0] *
+                       (int64_t)(p_calib[2] - p_calib[0]);
+       val2 = (int64_t)p_lut[2] * (int64_t)(p_calib[0] - p_calib[1]) +
+               (int64_t)p_lut[0] * (int64_t)(p_calib[1] - p_calib[2]) +
+               (int64_t)p_lut[1] * (int64_t)(p_calib[2] - p_calib[0]);
+       c = div64_s64(val1, val2);
+       dev_dbg(&st->client->dev, "val1 = %lld, val2 = %lld, c = %lld\n",
+               val1, val2, c);
+       val1 = (int64_t)p_calib[0] * (int64_t)p_lut[0] -
+               (int64_t)p_calib[1] * (int64_t)p_lut[1] -
+               (int64_t)(p_calib[1] - p_calib[0]) * c;
+       val2 = (int64_t)p_lut[0] - (int64_t)p_lut[1];
+       a = div64_s64(val1, val2);
+       dev_dbg(&st->client->dev, "val1 = %lld, val2 = %lld, a = %lld\n",
+               val1, val2, a);
+       b = ((int64_t)p_calib[0] - a) * ((int64_t)p_lut[0] + c);
+       dev_dbg(&st->client->dev, "b = %lld\n", b);
+
+       /*
+        * pressure_Pa = a + (b / (c + raw_pressure))
+        * pressure_mPa = 1000 * pressure_Pa
+        */
+       pressure_mPa = 1000LL * a + div64_s64(1000LL * b, c + raw_pressure);
+
+       return pressure_mPa;
+}
+
+static int icp10100_read_raw_measures(struct iio_dev *indio_dev,
+                                     struct iio_chan_spec const *chan,
+                                     int *val, int *val2)
+{
+       struct icp10100_state *st = iio_priv(indio_dev);
+       uint32_t raw_pressure;
+       uint16_t raw_temp;
+       uint32_t pressure_mPa;
+       int ret;
+
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
+
+       ret = icp10100_get_measures(st, &raw_pressure, &raw_temp);
+       if (ret)
+               goto error_release;
+
+       switch (chan->type) {
+       case IIO_PRESSURE:
+               pressure_mPa = icp10100_get_pressure(st, raw_pressure,
+                                                    raw_temp);
+               /* mPa to kPa */
+               *val = pressure_mPa / 1000000;
+               *val2 = pressure_mPa % 1000000;
+               ret = IIO_VAL_INT_PLUS_MICRO;
+               break;
+       case IIO_TEMP:
+               *val = raw_temp;
+               ret = IIO_VAL_INT;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+error_release:
+       iio_device_release_direct_mode(indio_dev);
+       return ret;
+}
+
+static int icp10100_read_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int *val, int *val2, long mask)
+{
+       struct icp10100_state *st = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+       case IIO_CHAN_INFO_PROCESSED:
+               return icp10100_read_raw_measures(indio_dev, chan, val, val2);
+       case IIO_CHAN_INFO_SCALE:
+               switch (chan->type) {
+               case IIO_TEMP:
+                       /* 1000 * 175°C / 65536 in m°C */
+                       *val = 2;
+                       *val2 = 670288;
+                       return IIO_VAL_INT_PLUS_MICRO;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IIO_CHAN_INFO_OFFSET:
+               switch (chan->type) {
+               case IIO_TEMP:
+                       /* 1000 * -45°C in m°C */
+                       *val = -45000;
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               mutex_lock(&st->lock);
+               *val = 1 << st->mode;
+               mutex_unlock(&st->lock);
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int icp10100_read_avail(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              const int **vals, int *type, int *length,
+                              long mask)
+{
+       static int oversamplings[] = {1, 2, 4, 8};
+
+       switch (mask) {
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               *vals = oversamplings;
+               *type = IIO_VAL_INT;
+               *length = ARRAY_SIZE(oversamplings);
+               return IIO_AVAIL_LIST;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int icp10100_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val, int val2, long mask)
+{
+       struct icp10100_state *st = iio_priv(indio_dev);
+       unsigned int mode;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               /* oversampling is always positive and a power of 2 */
+               if (val <= 0 || !is_power_of_2(val))
+                       return -EINVAL;
+               mode = ilog2(val);
+               if (mode >= ICP10100_MODE_NB)
+                       return -EINVAL;
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+               mutex_lock(&st->lock);
+               st->mode = mode;
+               mutex_unlock(&st->lock);
+               iio_device_release_direct_mode(indio_dev);
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int icp10100_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                     struct iio_chan_spec const *chan,
+                                     long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info icp10100_info = {
+       .read_raw = icp10100_read_raw,
+       .read_avail = icp10100_read_avail,
+       .write_raw = icp10100_write_raw,
+       .write_raw_get_fmt = icp10100_write_raw_get_fmt,
+};
+
+static const struct iio_chan_spec icp10100_channels[] = {
+       {
+               .type = IIO_PRESSURE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .info_mask_shared_by_all =
+                       BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .info_mask_shared_by_all_available =
+                       BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+       }, {
+               .type = IIO_TEMP,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                       BIT(IIO_CHAN_INFO_SCALE) |
+                       BIT(IIO_CHAN_INFO_OFFSET),
+               .info_mask_shared_by_all =
+                       BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+               .info_mask_shared_by_all_available =
+                       BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+       },
+};
+
+static int icp10100_enable_regulator(struct icp10100_state *st)
+{
+       int ret;
+
+       ret = regulator_enable(st->vdd);
+       if (ret)
+               return ret;
+       msleep(100);
+
+       return 0;
+}
+
+static void icp10100_disable_regulator_action(void *data)
+{
+       struct icp10100_state *st = data;
+       int ret;
+
+       ret = regulator_disable(st->vdd);
+       if (ret)
+               dev_err(&st->client->dev, "error %d disabling vdd\n", ret);
+}
+
+static void icp10100_pm_disable(void *data)
+{
+       struct device *dev = data;
+
+       pm_runtime_put_sync_suspend(dev);
+       pm_runtime_disable(dev);
+}
+
+static int icp10100_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct iio_dev *indio_dev;
+       struct icp10100_state *st;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "plain i2c transactions not supported\n");
+               return -ENODEV;
+       }
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, indio_dev);
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->name = client->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = icp10100_channels;
+       indio_dev->num_channels = ARRAY_SIZE(icp10100_channels);
+       indio_dev->info = &icp10100_info;
+
+       st = iio_priv(indio_dev);
+       mutex_init(&st->lock);
+       st->client = client;
+       st->mode = ICP10100_MODE_N;
+
+       st->vdd = devm_regulator_get(&client->dev, "vdd");
+       if (IS_ERR(st->vdd))
+               return PTR_ERR(st->vdd);
+
+       ret = icp10100_enable_regulator(st);
+       if (ret)
+               return ret;
+
+       ret = devm_add_action_or_reset(&client->dev,
+                                      icp10100_disable_regulator_action, st);
+       if (ret)
+               return ret;
+
+       /* has to be done before the first i2c communication */
+       crc8_populate_msb(icp10100_crc8_table, ICP10100_CRC8_POLYNOMIAL);
+
+       ret = icp10100_init_chip(st);
+       if (ret) {
+               dev_err(&client->dev, "init chip error %d\n", ret);
+               return ret;
+       }
+
+       /* enable runtime pm with autosuspend delay of 2s */
+       pm_runtime_get_noresume(&client->dev);
+       pm_runtime_set_active(&client->dev);
+       pm_runtime_enable(&client->dev);
+       pm_runtime_set_autosuspend_delay(&client->dev, 2000);
+       pm_runtime_use_autosuspend(&client->dev);
+       pm_runtime_put(&client->dev);
+       ret = devm_add_action_or_reset(&client->dev, icp10100_pm_disable,
+                                      &client->dev);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static int __maybe_unused icp10100_suspend(struct device *dev)
+{
+       struct icp10100_state *st = iio_priv(dev_get_drvdata(dev));
+       int ret;
+
+       mutex_lock(&st->lock);
+       ret = regulator_disable(st->vdd);
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int __maybe_unused icp10100_resume(struct device *dev)
+{
+       struct icp10100_state *st = iio_priv(dev_get_drvdata(dev));
+       int ret;
+
+       mutex_lock(&st->lock);
+
+       ret = icp10100_enable_regulator(st);
+       if (ret)
+               goto out_unlock;
+
+       /* reset chip */
+       ret = icp10100_send_cmd(st, &icp10100_cmd_soft_reset, NULL, 0);
+
+out_unlock:
+       mutex_unlock(&st->lock);
+       return ret;
+}
+
+static UNIVERSAL_DEV_PM_OPS(icp10100_pm, icp10100_suspend, icp10100_resume,
+                           NULL);
+
+static const struct of_device_id icp10100_of_match[] = {
+       {
+               .compatible = "invensense,icp10100",
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, icp10100_of_match);
+
+static const struct i2c_device_id icp10100_id[] = {
+       { "icp10100", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, icp10100_id);
+
+static struct i2c_driver icp10100_driver = {
+       .driver = {
+               .name = "icp10100",
+               .pm = &icp10100_pm,
+               .of_match_table = of_match_ptr(icp10100_of_match),
+       },
+       .probe = icp10100_probe,
+       .id_table = icp10100_id,
+};
+module_i2c_driver(icp10100_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense icp10100 driver");
+MODULE_LICENSE("GPL");
index 34aff10..12b893c 100644 (file)
@@ -269,7 +269,7 @@ static const struct iio_chan_spec ping_chan_spec[] = {
 
 static const struct of_device_id of_ping_match[] = {
        { .compatible = "parallax,ping", .data = &pa_ping_cfg},
-       { .compatible = "parallax,laserping", .data = &pa_ping_cfg},
+       { .compatible = "parallax,laserping", .data = &pa_laser_ping_cfg},
        {},
 };
 
index 01eb8cc..568b76e 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 
@@ -56,6 +57,7 @@ struct srf04_data {
        struct device           *dev;
        struct gpio_desc        *gpiod_trig;
        struct gpio_desc        *gpiod_echo;
+       struct gpio_desc        *gpiod_power;
        struct mutex            lock;
        int                     irqnr;
        ktime_t                 ts_rising;
@@ -63,6 +65,7 @@ struct srf04_data {
        struct completion       rising;
        struct completion       falling;
        const struct srf04_cfg  *cfg;
+       int                     startup_time_ms;
 };
 
 static const struct srf04_cfg srf04_cfg = {
@@ -97,6 +100,9 @@ static int srf04_read(struct srf04_data *data)
        u64 dt_ns;
        u32 time_ns, distance_mm;
 
+       if (data->gpiod_power)
+               pm_runtime_get_sync(data->dev);
+
        /*
         * just one read-echo-cycle can take place at a time
         * ==> lock against concurrent reading calls
@@ -110,6 +116,11 @@ static int srf04_read(struct srf04_data *data)
        udelay(data->cfg->trigger_pulse_us);
        gpiod_set_value(data->gpiod_trig, 0);
 
+       if (data->gpiod_power) {
+               pm_runtime_mark_last_busy(data->dev);
+               pm_runtime_put_autosuspend(data->dev);
+       }
+
        /* it should not take more than 20 ms until echo is rising */
        ret = wait_for_completion_killable_timeout(&data->rising, HZ/50);
        if (ret < 0) {
@@ -268,6 +279,22 @@ static int srf04_probe(struct platform_device *pdev)
                return PTR_ERR(data->gpiod_echo);
        }
 
+       data->gpiod_power = devm_gpiod_get_optional(dev, "power",
+                                                               GPIOD_OUT_LOW);
+       if (IS_ERR(data->gpiod_power)) {
+               dev_err(dev, "failed to get power-gpios: err=%ld\n",
+                                               PTR_ERR(data->gpiod_power));
+               return PTR_ERR(data->gpiod_power);
+       }
+       if (data->gpiod_power) {
+
+               if (of_property_read_u32(dev->of_node, "startup-time-ms",
+                                               &data->startup_time_ms))
+                       data->startup_time_ms = 100;
+               dev_dbg(dev, "using power gpio: startup-time-ms=%d\n",
+                                                       data->startup_time_ms);
+       }
+
        if (gpiod_cansleep(data->gpiod_echo)) {
                dev_err(data->dev, "cansleep-GPIOs not supported\n");
                return -ENODEV;
@@ -296,14 +323,81 @@ static int srf04_probe(struct platform_device *pdev)
        indio_dev->channels = srf04_chan_spec;
        indio_dev->num_channels = ARRAY_SIZE(srf04_chan_spec);
 
-       return devm_iio_device_register(dev, indio_dev);
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(data->dev, "iio_device_register: %d\n", ret);
+               return ret;
+       }
+
+       if (data->gpiod_power) {
+               pm_runtime_set_autosuspend_delay(data->dev, 1000);
+               pm_runtime_use_autosuspend(data->dev);
+
+               ret = pm_runtime_set_active(data->dev);
+               if (ret) {
+                       dev_err(data->dev, "pm_runtime_set_active: %d\n", ret);
+                       iio_device_unregister(indio_dev);
+               }
+
+               pm_runtime_enable(data->dev);
+               pm_runtime_idle(data->dev);
+       }
+
+       return ret;
 }
 
+static int srf04_remove(struct platform_device *pdev)
+{
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct srf04_data *data = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+
+       if (data->gpiod_power) {
+               pm_runtime_disable(data->dev);
+               pm_runtime_set_suspended(data->dev);
+       }
+
+       return 0;
+}
+
+static int __maybe_unused srf04_pm_runtime_suspend(struct device *dev)
+{
+       struct platform_device *pdev = container_of(dev,
+                                               struct platform_device, dev);
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct srf04_data *data = iio_priv(indio_dev);
+
+       gpiod_set_value(data->gpiod_power, 0);
+
+       return 0;
+}
+
+static int __maybe_unused srf04_pm_runtime_resume(struct device *dev)
+{
+       struct platform_device *pdev = container_of(dev,
+                                               struct platform_device, dev);
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct srf04_data *data = iio_priv(indio_dev);
+
+       gpiod_set_value(data->gpiod_power, 1);
+       msleep(data->startup_time_ms);
+
+       return 0;
+}
+
+static const struct dev_pm_ops srf04_pm_ops = {
+       SET_RUNTIME_PM_OPS(srf04_pm_runtime_suspend,
+                               srf04_pm_runtime_resume, NULL)
+};
+
 static struct platform_driver srf04_driver = {
        .probe          = srf04_probe,
+       .remove         = srf04_remove,
        .driver         = {
                .name           = "srf04-gpio",
                .of_match_table = of_srf04_match,
+               .pm             = &srf04_pm_ops,
        },
 };
 
index 2e0d32a..7d8962d 100644 (file)
@@ -75,14 +75,27 @@ static const void *stm32h7_valids_table[][MAX_VALIDS] = {
        { }, /* timer 17 */
 };
 
+struct stm32_timer_trigger_regs {
+       u32 cr1;
+       u32 cr2;
+       u32 psc;
+       u32 arr;
+       u32 cnt;
+       u32 smcr;
+};
+
 struct stm32_timer_trigger {
        struct device *dev;
        struct regmap *regmap;
        struct clk *clk;
+       bool enabled;
        u32 max_arr;
        const void *triggers;
        const void *valids;
        bool has_trgo2;
+       struct mutex lock; /* concurrent sysfs configuration */
+       struct list_head tr_list;
+       struct stm32_timer_trigger_regs bak;
 };
 
 struct stm32_timer_trigger_cfg {
@@ -106,7 +119,7 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 {
        unsigned long long prd, div;
        int prescaler = 0;
-       u32 ccer, cr1;
+       u32 ccer;
 
        /* Period and prescaler values depends of clock rate */
        div = (unsigned long long)clk_get_rate(priv->clk);
@@ -136,9 +149,11 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
        if (ccer & TIM_CCER_CCXE)
                return -EBUSY;
 
-       regmap_read(priv->regmap, TIM_CR1, &cr1);
-       if (!(cr1 & TIM_CR1_CEN))
+       mutex_lock(&priv->lock);
+       if (!priv->enabled) {
+               priv->enabled = true;
                clk_enable(priv->clk);
+       }
 
        regmap_write(priv->regmap, TIM_PSC, prescaler);
        regmap_write(priv->regmap, TIM_ARR, prd - 1);
@@ -157,30 +172,41 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
 
        /* Enable controller */
        regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+       mutex_unlock(&priv->lock);
 
        return 0;
 }
 
-static void stm32_timer_stop(struct stm32_timer_trigger *priv)
+static void stm32_timer_stop(struct stm32_timer_trigger *priv,
+                            struct iio_trigger *trig)
 {
-       u32 ccer, cr1;
+       u32 ccer;
 
        regmap_read(priv->regmap, TIM_CCER, &ccer);
        if (ccer & TIM_CCER_CCXE)
                return;
 
-       regmap_read(priv->regmap, TIM_CR1, &cr1);
-       if (cr1 & TIM_CR1_CEN)
-               clk_disable(priv->clk);
-
+       mutex_lock(&priv->lock);
        /* Stop timer */
        regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, 0);
        regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
        regmap_write(priv->regmap, TIM_PSC, 0);
        regmap_write(priv->regmap, TIM_ARR, 0);
 
+       /* Force disable master mode */
+       if (stm32_timer_is_trgo2_name(trig->name))
+               regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0);
+       else
+               regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0);
+
        /* Make sure that registers are updated */
        regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+       if (priv->enabled) {
+               priv->enabled = false;
+               clk_disable(priv->clk);
+       }
+       mutex_unlock(&priv->lock);
 }
 
 static ssize_t stm32_tt_store_frequency(struct device *dev,
@@ -197,7 +223,7 @@ static ssize_t stm32_tt_store_frequency(struct device *dev,
                return ret;
 
        if (freq == 0) {
-               stm32_timer_stop(priv);
+               stm32_timer_stop(priv, trig);
        } else {
                ret = stm32_timer_start(priv, trig, freq);
                if (ret)
@@ -295,8 +321,15 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
        for (i = 0; i <= master_mode_max; i++) {
                if (!strncmp(master_mode_table[i], buf,
                             strlen(master_mode_table[i]))) {
+                       mutex_lock(&priv->lock);
+                       if (!priv->enabled) {
+                               /* Clock should be enabled first */
+                               priv->enabled = true;
+                               clk_enable(priv->clk);
+                       }
                        regmap_update_bits(priv->regmap, TIM_CR2, mask,
                                           i << shift);
+                       mutex_unlock(&priv->lock);
                        return len;
                }
        }
@@ -354,11 +387,21 @@ static const struct attribute_group *stm32_trigger_attr_groups[] = {
 static const struct iio_trigger_ops timer_trigger_ops = {
 };
 
-static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
+static void stm32_unregister_iio_triggers(struct stm32_timer_trigger *priv)
+{
+       struct iio_trigger *tr;
+
+       list_for_each_entry(tr, &priv->tr_list, alloc_list)
+               iio_trigger_unregister(tr);
+}
+
+static int stm32_register_iio_triggers(struct stm32_timer_trigger *priv)
 {
        int ret;
        const char * const *cur = priv->triggers;
 
+       INIT_LIST_HEAD(&priv->tr_list);
+
        while (cur && *cur) {
                struct iio_trigger *trig;
                bool cur_is_trgo = stm32_timer_is_trgo_name(*cur);
@@ -385,9 +428,13 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
 
                iio_trigger_set_drvdata(trig, priv);
 
-               ret = devm_iio_trigger_register(priv->dev, trig);
-               if (ret)
+               ret = iio_trigger_register(trig);
+               if (ret) {
+                       stm32_unregister_iio_triggers(priv);
                        return ret;
+               }
+
+               list_add_tail(&trig->alloc_list, &priv->tr_list);
                cur++;
        }
 
@@ -434,7 +481,6 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
                                   int val, int val2, long mask)
 {
        struct stm32_timer_trigger *priv = iio_priv(indio_dev);
-       u32 dat;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
@@ -445,19 +491,23 @@ static int stm32_counter_write_raw(struct iio_dev *indio_dev,
                return -EINVAL;
 
        case IIO_CHAN_INFO_ENABLE:
+               mutex_lock(&priv->lock);
                if (val) {
-                       regmap_read(priv->regmap, TIM_CR1, &dat);
-                       if (!(dat & TIM_CR1_CEN))
+                       if (!priv->enabled) {
+                               priv->enabled = true;
                                clk_enable(priv->clk);
+                       }
                        regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
                                           TIM_CR1_CEN);
                } else {
-                       regmap_read(priv->regmap, TIM_CR1, &dat);
                        regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN,
                                           0);
-                       if (dat & TIM_CR1_CEN)
+                       if (priv->enabled) {
+                               priv->enabled = false;
                                clk_disable(priv->clk);
+                       }
                }
+               mutex_unlock(&priv->lock);
                return 0;
        }
 
@@ -553,7 +603,6 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
 {
        struct stm32_timer_trigger *priv = iio_priv(indio_dev);
        int sms = stm32_enable_mode2sms(mode);
-       u32 val;
 
        if (sms < 0)
                return sms;
@@ -561,11 +610,12 @@ static int stm32_set_enable_mode(struct iio_dev *indio_dev,
         * Triggered mode sets CEN bit automatically by hardware. So, first
         * enable counter clock, so it can use it. Keeps it in sync with CEN.
         */
-       if (sms == 6) {
-               regmap_read(priv->regmap, TIM_CR1, &val);
-               if (!(val & TIM_CR1_CEN))
-                       clk_enable(priv->clk);
+       mutex_lock(&priv->lock);
+       if (sms == 6 && !priv->enabled) {
+               clk_enable(priv->clk);
+               priv->enabled = true;
        }
+       mutex_unlock(&priv->lock);
 
        regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);
 
@@ -749,8 +799,9 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
        priv->triggers = triggers_table[index];
        priv->valids = cfg->valids_table[index];
        stm32_timer_detect_trgo2(priv);
+       mutex_init(&priv->lock);
 
-       ret = stm32_setup_iio_triggers(priv);
+       ret = stm32_register_iio_triggers(priv);
        if (ret)
                return ret;
 
@@ -759,6 +810,77 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
        return 0;
 }
 
+static int stm32_timer_trigger_remove(struct platform_device *pdev)
+{
+       struct stm32_timer_trigger *priv = platform_get_drvdata(pdev);
+       u32 val;
+
+       /* Unregister triggers before everything can be safely turned off */
+       stm32_unregister_iio_triggers(priv);
+
+       /* Check if nobody else use the timer, then disable it */
+       regmap_read(priv->regmap, TIM_CCER, &val);
+       if (!(val & TIM_CCER_CCXE))
+               regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+       if (priv->enabled)
+               clk_disable(priv->clk);
+
+       return 0;
+}
+
+static int __maybe_unused stm32_timer_trigger_suspend(struct device *dev)
+{
+       struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
+
+       /* Only take care of enabled timer: don't disturb other MFD child */
+       if (priv->enabled) {
+               /* Backup registers that may get lost in low power mode */
+               regmap_read(priv->regmap, TIM_CR1, &priv->bak.cr1);
+               regmap_read(priv->regmap, TIM_CR2, &priv->bak.cr2);
+               regmap_read(priv->regmap, TIM_PSC, &priv->bak.psc);
+               regmap_read(priv->regmap, TIM_ARR, &priv->bak.arr);
+               regmap_read(priv->regmap, TIM_CNT, &priv->bak.cnt);
+               regmap_read(priv->regmap, TIM_SMCR, &priv->bak.smcr);
+
+               /* Disable the timer */
+               regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+               clk_disable(priv->clk);
+       }
+
+       return 0;
+}
+
+static int __maybe_unused stm32_timer_trigger_resume(struct device *dev)
+{
+       struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
+       int ret;
+
+       if (priv->enabled) {
+               ret = clk_enable(priv->clk);
+               if (ret)
+                       return ret;
+
+               /* restore master/slave modes */
+               regmap_write(priv->regmap, TIM_SMCR, priv->bak.smcr);
+               regmap_write(priv->regmap, TIM_CR2, priv->bak.cr2);
+
+               /* restore sampling_frequency (trgo / trgo2 triggers) */
+               regmap_write(priv->regmap, TIM_PSC, priv->bak.psc);
+               regmap_write(priv->regmap, TIM_ARR, priv->bak.arr);
+               regmap_write(priv->regmap, TIM_CNT, priv->bak.cnt);
+
+               /* Also re-enables the timer */
+               regmap_write(priv->regmap, TIM_CR1, priv->bak.cr1);
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(stm32_timer_trigger_pm_ops,
+                        stm32_timer_trigger_suspend,
+                        stm32_timer_trigger_resume);
+
 static const struct stm32_timer_trigger_cfg stm32_timer_trg_cfg = {
        .valids_table = valids_table,
        .num_valids_table = ARRAY_SIZE(valids_table),
@@ -783,9 +905,11 @@ MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
 
 static struct platform_driver stm32_timer_trigger_driver = {
        .probe = stm32_timer_trigger_probe,
+       .remove = stm32_timer_trigger_remove,
        .driver = {
                .name = "stm32-timer-trigger",
                .of_match_table = stm32_trig_of_match,
+               .pm = &stm32_timer_trigger_pm_ops,
        },
 };
 module_platform_driver(stm32_timer_trigger_driver);
index 68cc1b2..15e99a8 100644 (file)
@@ -1191,6 +1191,7 @@ struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device,
                        /* Sharing an ib_cm_id with different handlers is not
                         * supported */
                        spin_unlock_irqrestore(&cm.lock, flags);
+                       ib_destroy_cm_id(cm_id);
                        return ERR_PTR(-EINVAL);
                }
                refcount_inc(&cm_id_priv->refcount);
index 72f0321..2dec3a0 100644 (file)
@@ -3212,19 +3212,26 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
        int ret;
 
        id_priv = container_of(id, struct rdma_id_private, id);
+       memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
        if (id_priv->state == RDMA_CM_IDLE) {
                ret = cma_bind_addr(id, src_addr, dst_addr);
-               if (ret)
+               if (ret) {
+                       memset(cma_dst_addr(id_priv), 0,
+                              rdma_addr_size(dst_addr));
                        return ret;
+               }
        }
 
-       if (cma_family(id_priv) != dst_addr->sa_family)
+       if (cma_family(id_priv) != dst_addr->sa_family) {
+               memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
                return -EINVAL;
+       }
 
-       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
+       if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY)) {
+               memset(cma_dst_addr(id_priv), 0, rdma_addr_size(dst_addr));
                return -EINVAL;
+       }
 
-       memcpy(cma_dst_addr(id_priv), dst_addr, rdma_addr_size(dst_addr));
        if (cma_any_addr(dst_addr)) {
                ret = cma_resolve_loopback(id_priv);
        } else {
index b1457b3..cf42acc 100644 (file)
@@ -338,6 +338,20 @@ static inline struct ib_qp *_ib_create_qp(struct ib_device *dev,
        qp->pd = pd;
        qp->uobject = uobj;
        qp->real_qp = qp;
+
+       qp->qp_type = attr->qp_type;
+       qp->rwq_ind_tbl = attr->rwq_ind_tbl;
+       qp->send_cq = attr->send_cq;
+       qp->recv_cq = attr->recv_cq;
+       qp->srq = attr->srq;
+       qp->rwq_ind_tbl = attr->rwq_ind_tbl;
+       qp->event_handler = attr->event_handler;
+
+       atomic_set(&qp->usecnt, 0);
+       spin_lock_init(&qp->mr_lock);
+       INIT_LIST_HEAD(&qp->rdma_mrs);
+       INIT_LIST_HEAD(&qp->sig_mrs);
+
        /*
         * We don't track XRC QPs for now, because they don't have PD
         * and more importantly they are created internaly by driver,
index f6c2552..d0b3d35 100644 (file)
@@ -896,7 +896,9 @@ static int add_one_compat_dev(struct ib_device *device,
        cdev->dev.parent = device->dev.parent;
        rdma_init_coredev(cdev, device, read_pnet(&rnet->net));
        cdev->dev.release = compatdev_release;
-       dev_set_name(&cdev->dev, "%s", dev_name(&device->dev));
+       ret = dev_set_name(&cdev->dev, "%s", dev_name(&device->dev));
+       if (ret)
+               goto add_err;
 
        ret = device_add(&cdev->dev);
        if (ret)
index ade7182..da8adad 100644 (file)
@@ -159,8 +159,10 @@ static void dealloc_work_entries(struct iwcm_id_private *cm_id_priv)
 {
        struct list_head *e, *tmp;
 
-       list_for_each_safe(e, tmp, &cm_id_priv->work_free_list)
+       list_for_each_safe(e, tmp, &cm_id_priv->work_free_list) {
+               list_del(e);
                kfree(list_entry(e, struct iwcm_work, free_list));
+       }
 }
 
 static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count)
index 37b433a..9eec26d 100644 (file)
@@ -918,6 +918,10 @@ static int nldev_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
 
                nla_strlcpy(name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
                            IB_DEVICE_NAME_MAX);
+               if (strlen(name) == 0) {
+                       err = -EINVAL;
+                       goto done;
+               }
                err = ib_device_rename(device, name);
                goto done;
        }
@@ -1514,7 +1518,7 @@ static int nldev_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
 
        nla_strlcpy(ibdev_name, tb[RDMA_NLDEV_ATTR_DEV_NAME],
                    sizeof(ibdev_name));
-       if (strchr(ibdev_name, '%'))
+       if (strchr(ibdev_name, '%') || strlen(ibdev_name) == 0)
                return -EINVAL;
 
        nla_strlcpy(type, tb[RDMA_NLDEV_ATTR_LINK_TYPE], sizeof(type));
@@ -1757,6 +1761,8 @@ static int nldev_stat_set_doit(struct sk_buff *skb, struct nlmsghdr *nlh,
                if (ret)
                        goto err_msg;
        } else {
+               if (!tb[RDMA_NLDEV_ATTR_RES_LQPN])
+                       goto err_msg;
                qpn = nla_get_u32(tb[RDMA_NLDEV_ATTR_RES_LQPN]);
                if (tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]) {
                        cntn = nla_get_u32(tb[RDMA_NLDEV_ATTR_STAT_COUNTER_ID]);
index 4fad732..06e5b67 100644 (file)
@@ -273,6 +273,23 @@ static int rdma_rw_init_single_wr(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
        return 1;
 }
 
+static void rdma_rw_unmap_sg(struct ib_device *dev, struct scatterlist *sg,
+                            u32 sg_cnt, enum dma_data_direction dir)
+{
+       if (is_pci_p2pdma_page(sg_page(sg)))
+               pci_p2pdma_unmap_sg(dev->dma_device, sg, sg_cnt, dir);
+       else
+               ib_dma_unmap_sg(dev, sg, sg_cnt, dir);
+}
+
+static int rdma_rw_map_sg(struct ib_device *dev, struct scatterlist *sg,
+                         u32 sg_cnt, enum dma_data_direction dir)
+{
+       if (is_pci_p2pdma_page(sg_page(sg)))
+               return pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir);
+       return ib_dma_map_sg(dev, sg, sg_cnt, dir);
+}
+
 /**
  * rdma_rw_ctx_init - initialize a RDMA READ/WRITE context
  * @ctx:       context to initialize
@@ -295,11 +312,7 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
        struct ib_device *dev = qp->pd->device;
        int ret;
 
-       if (is_pci_p2pdma_page(sg_page(sg)))
-               ret = pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir);
-       else
-               ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
-
+       ret = rdma_rw_map_sg(dev, sg, sg_cnt, dir);
        if (!ret)
                return -ENOMEM;
        sg_cnt = ret;
@@ -338,7 +351,7 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
        return ret;
 
 out_unmap_sg:
-       ib_dma_unmap_sg(dev, sg, sg_cnt, dir);
+       rdma_rw_unmap_sg(dev, sg, sg_cnt, dir);
        return ret;
 }
 EXPORT_SYMBOL(rdma_rw_ctx_init);
@@ -588,11 +601,7 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
                break;
        }
 
-       if (is_pci_p2pdma_page(sg_page(sg)))
-               pci_p2pdma_unmap_sg(qp->pd->device->dma_device, sg,
-                                   sg_cnt, dir);
-       else
-               ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
+       rdma_rw_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
 }
 EXPORT_SYMBOL(rdma_rw_ctx_destroy);
 
index 2b4d803..75e7ec0 100644 (file)
@@ -340,20 +340,19 @@ static struct ib_ports_pkeys *get_new_pps(const struct ib_qp *qp,
                return NULL;
 
        if (qp_attr_mask & IB_QP_PORT)
-               new_pps->main.port_num =
-                       (qp_pps) ? qp_pps->main.port_num : qp_attr->port_num;
-       if (qp_attr_mask & IB_QP_PKEY_INDEX)
-               new_pps->main.pkey_index = (qp_pps) ? qp_pps->main.pkey_index :
-                                                     qp_attr->pkey_index;
-       if ((qp_attr_mask & IB_QP_PKEY_INDEX) && (qp_attr_mask & IB_QP_PORT))
-               new_pps->main.state = IB_PORT_PKEY_VALID;
-
-       if (!(qp_attr_mask & (IB_QP_PKEY_INDEX || IB_QP_PORT)) && qp_pps) {
+               new_pps->main.port_num = qp_attr->port_num;
+       else if (qp_pps)
                new_pps->main.port_num = qp_pps->main.port_num;
+
+       if (qp_attr_mask & IB_QP_PKEY_INDEX)
+               new_pps->main.pkey_index = qp_attr->pkey_index;
+       else if (qp_pps)
                new_pps->main.pkey_index = qp_pps->main.pkey_index;
-               if (qp_pps->main.state != IB_PORT_PKEY_NOT_VALID)
-                       new_pps->main.state = IB_PORT_PKEY_VALID;
-       }
+
+       if (((qp_attr_mask & IB_QP_PKEY_INDEX) &&
+            (qp_attr_mask & IB_QP_PORT)) ||
+           (qp_pps && qp_pps->main.state != IB_PORT_PKEY_NOT_VALID))
+               new_pps->main.state = IB_PORT_PKEY_VALID;
 
        if (qp_attr_mask & IB_QP_ALT_PATH) {
                new_pps->alt.port_num = qp_attr->alt_port_num;
index b8c657b..3b1e627 100644 (file)
@@ -181,14 +181,28 @@ ib_umem_odp_alloc_child(struct ib_umem_odp *root, unsigned long addr,
        odp_data->page_shift = PAGE_SHIFT;
        odp_data->notifier.ops = ops;
 
+       /*
+        * A mmget must be held when registering a notifier, the owming_mm only
+        * has a mm_grab at this point.
+        */
+       if (!mmget_not_zero(umem->owning_mm)) {
+               ret = -EFAULT;
+               goto out_free;
+       }
+
        odp_data->tgid = get_pid(root->tgid);
        ret = ib_init_umem_odp(odp_data, ops);
-       if (ret) {
-               put_pid(odp_data->tgid);
-               kfree(odp_data);
-               return ERR_PTR(ret);
-       }
+       if (ret)
+               goto out_tgid;
+       mmput(umem->owning_mm);
        return odp_data;
+
+out_tgid:
+       put_pid(odp_data->tgid);
+       mmput(umem->owning_mm);
+out_free:
+       kfree(odp_data);
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL(ib_umem_odp_alloc_child);
 
@@ -261,8 +275,8 @@ void ib_umem_odp_release(struct ib_umem_odp *umem_odp)
                mmu_interval_notifier_remove(&umem_odp->notifier);
                kvfree(umem_odp->dma_list);
                kvfree(umem_odp->page_list);
-               put_pid(umem_odp->tgid);
        }
+       put_pid(umem_odp->tgid);
        kfree(umem_odp);
 }
 EXPORT_SYMBOL(ib_umem_odp_release);
index 1235ffb..da229ea 100644 (file)
@@ -1129,17 +1129,30 @@ static const struct file_operations umad_sm_fops = {
        .llseek  = no_llseek,
 };
 
+static struct ib_umad_port *get_port(struct ib_device *ibdev,
+                                    struct ib_umad_device *umad_dev,
+                                    unsigned int port)
+{
+       if (!umad_dev)
+               return ERR_PTR(-EOPNOTSUPP);
+       if (!rdma_is_port_valid(ibdev, port))
+               return ERR_PTR(-EINVAL);
+       if (!rdma_cap_ib_mad(ibdev, port))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       return &umad_dev->ports[port - rdma_start_port(ibdev)];
+}
+
 static int ib_umad_get_nl_info(struct ib_device *ibdev, void *client_data,
                               struct ib_client_nl_info *res)
 {
-       struct ib_umad_device *umad_dev = client_data;
+       struct ib_umad_port *port = get_port(ibdev, client_data, res->port);
 
-       if (!rdma_is_port_valid(ibdev, res->port))
-               return -EINVAL;
+       if (IS_ERR(port))
+               return PTR_ERR(port);
 
        res->abi = IB_USER_MAD_ABI_VERSION;
-       res->cdev = &umad_dev->ports[res->port - rdma_start_port(ibdev)].dev;
-
+       res->cdev = &port->dev;
        return 0;
 }
 
@@ -1154,15 +1167,13 @@ MODULE_ALIAS_RDMA_CLIENT("umad");
 static int ib_issm_get_nl_info(struct ib_device *ibdev, void *client_data,
                               struct ib_client_nl_info *res)
 {
-       struct ib_umad_device *umad_dev =
-               ib_get_client_data(ibdev, &umad_client);
+       struct ib_umad_port *port = get_port(ibdev, client_data, res->port);
 
-       if (!rdma_is_port_valid(ibdev, res->port))
-               return -EINVAL;
+       if (IS_ERR(port))
+               return PTR_ERR(port);
 
        res->abi = IB_USER_MAD_ABI_VERSION;
-       res->cdev = &umad_dev->ports[res->port - rdma_start_port(ibdev)].sm_dev;
-
+       res->cdev = &port->sm_dev;
        return 0;
 }
 
index 0259337..060b4eb 100644 (file)
@@ -1445,16 +1445,7 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
                if (ret)
                        goto err_cb;
 
-               qp->pd            = pd;
-               qp->send_cq       = attr.send_cq;
-               qp->recv_cq       = attr.recv_cq;
-               qp->srq           = attr.srq;
-               qp->rwq_ind_tbl   = ind_tbl;
-               qp->event_handler = attr.event_handler;
-               qp->qp_type       = attr.qp_type;
-               atomic_set(&qp->usecnt, 0);
                atomic_inc(&pd->usecnt);
-               qp->port = 0;
                if (attr.send_cq)
                        atomic_inc(&attr.send_cq->usecnt);
                if (attr.recv_cq)
index 3ebae3b..e62c9df 100644 (file)
@@ -1185,16 +1185,6 @@ struct ib_qp *ib_create_qp_user(struct ib_pd *pd,
        if (ret)
                goto err;
 
-       qp->qp_type    = qp_init_attr->qp_type;
-       qp->rwq_ind_tbl = qp_init_attr->rwq_ind_tbl;
-
-       atomic_set(&qp->usecnt, 0);
-       qp->mrs_used = 0;
-       spin_lock_init(&qp->mr_lock);
-       INIT_LIST_HEAD(&qp->rdma_mrs);
-       INIT_LIST_HEAD(&qp->sig_mrs);
-       qp->port = 0;
-
        if (qp_init_attr->qp_type == IB_QPT_XRC_TGT) {
                struct ib_qp *xrc_qp =
                        create_xrc_qp_user(qp, qp_init_attr, udata);
index d106d23..c22ab7b 100644 (file)
@@ -78,7 +78,7 @@ static int read_efi_var(const char *name, unsigned long *size,
        *size = 0;
        *return_data = NULL;
 
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                return -EOPNOTSUPP;
 
        uni_name = kcalloc(strlen(name) + 1, sizeof(efi_char16_t), GFP_KERNEL);
index c2f0d9b..13e4203 100644 (file)
@@ -141,6 +141,7 @@ static int defer_packet_queue(
         */
        xchg(&pq->state, SDMA_PKT_Q_DEFERRED);
        if (list_empty(&pq->busy.list)) {
+               pq->busy.lock = &sde->waitlock;
                iowait_get_priority(&pq->busy);
                iowait_queue(pkts_sent, &pq->busy, &sde->dmawait);
        }
@@ -155,6 +156,7 @@ static void activate_packet_queue(struct iowait *wait, int reason)
 {
        struct hfi1_user_sdma_pkt_q *pq =
                container_of(wait, struct hfi1_user_sdma_pkt_q, busy);
+       pq->busy.lock = NULL;
        xchg(&pq->state, SDMA_PKT_Q_ACTIVE);
        wake_up(&wait->wait_dma);
 };
@@ -256,6 +258,21 @@ pq_reqs_nomem:
        return ret;
 }
 
+static void flush_pq_iowait(struct hfi1_user_sdma_pkt_q *pq)
+{
+       unsigned long flags;
+       seqlock_t *lock = pq->busy.lock;
+
+       if (!lock)
+               return;
+       write_seqlock_irqsave(lock, flags);
+       if (!list_empty(&pq->busy.list)) {
+               list_del_init(&pq->busy.list);
+               pq->busy.lock = NULL;
+       }
+       write_sequnlock_irqrestore(lock, flags);
+}
+
 int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd,
                               struct hfi1_ctxtdata *uctxt)
 {
@@ -281,6 +298,7 @@ int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd,
                kfree(pq->reqs);
                kfree(pq->req_in_use);
                kmem_cache_destroy(pq->txreq_cache);
+               flush_pq_iowait(pq);
                kfree(pq);
        } else {
                spin_unlock(&fd->pq_rcu_lock);
@@ -587,11 +605,12 @@ int hfi1_user_sdma_process_request(struct hfi1_filedata *fd,
                if (ret < 0) {
                        if (ret != -EBUSY)
                                goto free_req;
-                       wait_event_interruptible_timeout(
+                       if (wait_event_interruptible_timeout(
                                pq->busy.wait_dma,
-                               (pq->state == SDMA_PKT_Q_ACTIVE),
+                               pq->state == SDMA_PKT_Q_ACTIVE,
                                msecs_to_jiffies(
-                                       SDMA_IOWAIT_TIMEOUT));
+                                       SDMA_IOWAIT_TIMEOUT)) <= 0)
+                               flush_pq_iowait(pq);
                }
        }
        *count += idx;
index 089e201..2f6323a 100644 (file)
@@ -515,10 +515,11 @@ static inline void hfi1_handle_packet(struct hfi1_packet *packet,
                                       opa_get_lid(packet->dlid, 9B));
                if (!mcast)
                        goto drop;
+               rcu_read_lock();
                list_for_each_entry_rcu(p, &mcast->qp_list, list) {
                        packet->qp = p->qp;
                        if (hfi1_do_pkey_check(packet))
-                               goto drop;
+                               goto unlock_drop;
                        spin_lock_irqsave(&packet->qp->r_lock, flags);
                        packet_handler = qp_ok(packet);
                        if (likely(packet_handler))
@@ -527,6 +528,7 @@ static inline void hfi1_handle_packet(struct hfi1_packet *packet,
                                ibp->rvp.n_pkt_drops++;
                        spin_unlock_irqrestore(&packet->qp->r_lock, flags);
                }
+               rcu_read_unlock();
                /*
                 * Notify rvt_multicast_detach() if it is waiting for us
                 * to finish.
index 367a71b..3dec3de 100644 (file)
@@ -330,6 +330,22 @@ static void mlx5_handle_error_cqe(struct mlx5_ib_dev *dev,
                dump_cqe(dev, cqe);
 }
 
+static void handle_atomics(struct mlx5_ib_qp *qp, struct mlx5_cqe64 *cqe64,
+                          u16 tail, u16 head)
+{
+       u16 idx;
+
+       do {
+               idx = tail & (qp->sq.wqe_cnt - 1);
+               if (idx == head)
+                       break;
+
+               tail = qp->sq.w_list[idx].next;
+       } while (1);
+       tail = qp->sq.w_list[idx].next;
+       qp->sq.last_poll = tail;
+}
+
 static void free_cq_buf(struct mlx5_ib_dev *dev, struct mlx5_ib_cq_buf *buf)
 {
        mlx5_frag_buf_free(dev->mdev, &buf->frag_buf);
@@ -368,7 +384,7 @@ static void get_sig_err_item(struct mlx5_sig_err_cqe *cqe,
 }
 
 static void sw_comp(struct mlx5_ib_qp *qp, int num_entries, struct ib_wc *wc,
-                   int *npolled, int is_send)
+                   int *npolled, bool is_send)
 {
        struct mlx5_ib_wq *wq;
        unsigned int cur;
@@ -383,10 +399,16 @@ static void sw_comp(struct mlx5_ib_qp *qp, int num_entries, struct ib_wc *wc,
                return;
 
        for (i = 0;  i < cur && np < num_entries; i++) {
-               wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+               unsigned int idx;
+
+               idx = (is_send) ? wq->last_poll : wq->tail;
+               idx &= (wq->wqe_cnt - 1);
+               wc->wr_id = wq->wrid[idx];
                wc->status = IB_WC_WR_FLUSH_ERR;
                wc->vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR;
                wq->tail++;
+               if (is_send)
+                       wq->last_poll = wq->w_list[idx].next;
                np++;
                wc->qp = &qp->ibqp;
                wc++;
@@ -473,6 +495,7 @@ repoll:
                wqe_ctr = be16_to_cpu(cqe64->wqe_counter);
                idx = wqe_ctr & (wq->wqe_cnt - 1);
                handle_good_req(wc, cqe64, wq, idx);
+               handle_atomics(*cur_qp, cqe64, wq->last_poll, idx);
                wc->wr_id = wq->wrid[idx];
                wq->tail = wq->wqe_head[idx] + 1;
                wc->status = IB_WC_SUCCESS;
index e4bcfa8..ffa7c21 100644 (file)
@@ -5722,9 +5722,10 @@ mlx5_ib_counter_alloc_stats(struct rdma_counter *counter)
        const struct mlx5_ib_counters *cnts =
                get_counters(dev, counter->port - 1);
 
-       /* Q counters are in the beginning of all counters */
        return rdma_alloc_hw_stats_struct(cnts->names,
-                                         cnts->num_q_counters,
+                                         cnts->num_q_counters +
+                                         cnts->num_cong_counters +
+                                         cnts->num_ext_ppcnt_counters,
                                          RDMA_HW_STATS_DEFAULT_LIFESPAN);
 }
 
index d9bffcc..f3bdbd5 100644 (file)
@@ -288,6 +288,7 @@ struct mlx5_ib_wq {
        unsigned                head;
        unsigned                tail;
        u16                     cur_post;
+       u16                     last_poll;
        void                    *cur_edge;
 };
 
@@ -636,6 +637,7 @@ struct mlx5_ib_mr {
 
        /* For ODP and implicit */
        atomic_t                num_deferred_work;
+       wait_queue_head_t       q_deferred_work;
        struct xarray           implicit_children;
        union {
                struct rcu_head rcu;
index 4216814..bf50cd9 100644 (file)
@@ -235,7 +235,8 @@ static void free_implicit_child_mr(struct mlx5_ib_mr *mr, bool need_imr_xlt)
        mr->parent = NULL;
        mlx5_mr_cache_free(mr->dev, mr);
        ib_umem_odp_release(odp);
-       atomic_dec(&imr->num_deferred_work);
+       if (atomic_dec_and_test(&imr->num_deferred_work))
+               wake_up(&imr->q_deferred_work);
 }
 
 static void free_implicit_child_mr_work(struct work_struct *work)
@@ -554,6 +555,7 @@ struct mlx5_ib_mr *mlx5_ib_alloc_implicit_mr(struct mlx5_ib_pd *pd,
        imr->umem = &umem_odp->umem;
        imr->is_odp_implicit = true;
        atomic_set(&imr->num_deferred_work, 0);
+       init_waitqueue_head(&imr->q_deferred_work);
        xa_init(&imr->implicit_children);
 
        err = mlx5_ib_update_xlt(imr, 0,
@@ -611,10 +613,7 @@ void mlx5_ib_free_implicit_mr(struct mlx5_ib_mr *imr)
         * under xa_lock while the child is in the xarray. Thus at this point
         * it is only decreasing, and all work holding it is now on the wq.
         */
-       if (atomic_read(&imr->num_deferred_work)) {
-               flush_workqueue(system_unbound_wq);
-               WARN_ON(atomic_read(&imr->num_deferred_work));
-       }
+       wait_event(imr->q_deferred_work, !atomic_read(&imr->num_deferred_work));
 
        /*
         * Fence the imr before we destroy the children. This allows us to
@@ -645,10 +644,7 @@ void mlx5_ib_fence_odp_mr(struct mlx5_ib_mr *mr)
        /* Wait for all running page-fault handlers to finish. */
        synchronize_srcu(&mr->dev->odp_srcu);
 
-       if (atomic_read(&mr->num_deferred_work)) {
-               flush_workqueue(system_unbound_wq);
-               WARN_ON(atomic_read(&mr->num_deferred_work));
-       }
+       wait_event(mr->q_deferred_work, !atomic_read(&mr->num_deferred_work));
 
        dma_fence_odp_mr(mr);
 }
@@ -1720,7 +1716,8 @@ static void destroy_prefetch_work(struct prefetch_mr_work *work)
        u32 i;
 
        for (i = 0; i < work->num_sge; ++i)
-               atomic_dec(&work->frags[i].mr->num_deferred_work);
+               if (atomic_dec_and_test(&work->frags[i].mr->num_deferred_work))
+                       wake_up(&work->frags[i].mr->q_deferred_work);
        kvfree(work);
 }
 
index 957f3a5..8fe149e 100644 (file)
@@ -3775,6 +3775,7 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
                qp->sq.cur_post = 0;
                if (qp->sq.wqe_cnt)
                        qp->sq.cur_edge = get_sq_edge(&qp->sq, 0);
+               qp->sq.last_poll = 0;
                qp->db.db[MLX5_RCV_DBR] = 0;
                qp->db.db[MLX5_SND_DBR] = 0;
        }
@@ -6204,6 +6205,10 @@ struct ib_wq *mlx5_ib_create_wq(struct ib_pd *pd,
        if (udata->outlen && udata->outlen < min_resp_len)
                return ERR_PTR(-EINVAL);
 
+       if (!capable(CAP_SYS_RAWIO) &&
+           init_attr->create_flags & IB_WQ_FLAGS_DELAY_DROP)
+               return ERR_PTR(-EPERM);
+
        dev = to_mdev(pd->device);
        switch (init_attr->wq_type) {
        case IB_WQT_RQ:
index 33778d4..5ef93f8 100644 (file)
@@ -329,8 +329,10 @@ void qib_ib_rcv(struct qib_ctxtdata *rcd, void *rhdr, void *data, u32 tlen)
                if (mcast == NULL)
                        goto drop;
                this_cpu_inc(ibp->pmastats->n_multicast_rcv);
+               rcu_read_lock();
                list_for_each_entry_rcu(p, &mcast->qp_list, list)
                        qib_qp_rcv(rcd, hdr, 1, data, tlen, p->qp);
+               rcu_read_unlock();
                /*
                 * Notify rvt_multicast_detach() if it is waiting for us
                 * to finish.
index 13d7f66..5724cbb 100644 (file)
@@ -327,7 +327,7 @@ void rvt_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
        if (cq->ip)
                kref_put(&cq->ip->ref, rvt_release_mmap_info);
        else
-               vfree(cq->queue);
+               vfree(cq->kqueue);
 }
 
 /**
index 96ed349..5cd40fb 100644 (file)
@@ -388,6 +388,9 @@ static struct siw_device *siw_device_create(struct net_device *netdev)
                { .max_segment_size = SZ_2G };
        base_dev->num_comp_vectors = num_possible_cpus();
 
+       xa_init_flags(&sdev->qp_xa, XA_FLAGS_ALLOC1);
+       xa_init_flags(&sdev->mem_xa, XA_FLAGS_ALLOC1);
+
        ib_set_device_ops(base_dev, &siw_device_ops);
        rv = ib_device_set_netdev(base_dev, netdev, 1);
        if (rv)
@@ -415,9 +418,6 @@ static struct siw_device *siw_device_create(struct net_device *netdev)
        sdev->attrs.max_srq_wr = SIW_MAX_SRQ_WR;
        sdev->attrs.max_srq_sge = SIW_MAX_SGE;
 
-       xa_init_flags(&sdev->qp_xa, XA_FLAGS_ALLOC1);
-       xa_init_flags(&sdev->mem_xa, XA_FLAGS_ALLOC1);
-
        INIT_LIST_HEAD(&sdev->cep_list);
        INIT_LIST_HEAD(&sdev->qp_list);
 
index fce43e6..3cfd2c1 100644 (file)
@@ -190,6 +190,7 @@ static void input_repeat_key(struct timer_list *t)
                        input_value_sync
                };
 
+               input_set_timestamp(dev, ktime_get());
                input_pass_values(dev, vals, ARRAY_SIZE(vals));
 
                if (dev->rep[REP_PERIOD])
index 14b55ba..fb078e0 100644 (file)
@@ -75,6 +75,14 @@ static struct touchkey_variant aries_touchkey_variant = {
        .cmd_led_off = ARIES_TOUCHKEY_CMD_LED_OFF,
 };
 
+static const struct touchkey_variant tc360_touchkey_variant = {
+       .keycode_reg = 0x00,
+       .base_reg = 0x00,
+       .fixed_regulator = true,
+       .cmd_led_on = TM2_TOUCHKEY_CMD_LED_ON,
+       .cmd_led_off = TM2_TOUCHKEY_CMD_LED_OFF,
+};
+
 static int tm2_touchkey_led_brightness_set(struct led_classdev *led_dev,
                                            enum led_brightness brightness)
 {
@@ -327,6 +335,9 @@ static const struct of_device_id tm2_touchkey_of_match[] = {
        }, {
                .compatible = "cypress,aries-touchkey",
                .data = &aries_touchkey_variant,
+       }, {
+               .compatible = "coreriver,tc360-touchkey",
+               .data = &tc360_touchkey_variant,
        },
        { },
 };
index 2c666fb..4d20362 100644 (file)
@@ -186,6 +186,7 @@ static const char * const smbus_pnp_ids[] = {
        "SYN3052", /* HP EliteBook 840 G4 */
        "SYN3221", /* HP 15-ay000 */
        "SYN323d", /* HP Spectre X360 13-w013dx */
+       "SYN3257", /* HP Envy 13-ad105ng */
        NULL
 };
 
index 6adea8a..ffa39ab 100644 (file)
@@ -1203,8 +1203,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
         * If distance threshold values are set, switch to reduced reporting
         * mode so they actually get used by the controller.
         */
-       if (ctrl->ctrl0_11[RMI_F11_DELTA_X_THRESHOLD] ||
-           ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD]) {
+       if (sensor->axis_align.delta_x_threshold ||
+           sensor->axis_align.delta_y_threshold) {
                ctrl->ctrl0_11[0] &= ~RMI_F11_REPORT_MODE_MASK;
                ctrl->ctrl0_11[0] |= RMI_F11_REPORT_MODE_REDUCED;
        }
index c768186..f9ca550 100644 (file)
@@ -288,7 +288,7 @@ static int icn8505_upload_fw(struct icn8505_data *icn8505)
         * we may need it at resume. Having loaded it once will make the
         * firmware class code cache it at suspend/resume.
         */
-       error = request_firmware(&fw, icn8505->firmware_name, dev);
+       error = firmware_request_platform(&fw, icn8505->firmware_name, dev);
        if (error) {
                dev_err(dev, "Firmware request error %d\n", error);
                return error;
index 6ed9f22..fe24543 100644 (file)
@@ -432,7 +432,7 @@ static int raydium_i2c_write_object(struct i2c_client *client,
        return 0;
 }
 
-static bool raydium_i2c_boot_trigger(struct i2c_client *client)
+static int raydium_i2c_boot_trigger(struct i2c_client *client)
 {
        static const u8 cmd[7][6] = {
                { 0x08, 0x0C, 0x09, 0x00, 0x50, 0xD7 },
@@ -457,10 +457,10 @@ static bool raydium_i2c_boot_trigger(struct i2c_client *client)
                }
        }
 
-       return false;
+       return 0;
 }
 
-static bool raydium_i2c_fw_trigger(struct i2c_client *client)
+static int raydium_i2c_fw_trigger(struct i2c_client *client)
 {
        static const u8 cmd[5][11] = {
                { 0, 0x09, 0x71, 0x0C, 0x09, 0x00, 0x50, 0xD7, 0, 0, 0 },
@@ -483,7 +483,7 @@ static bool raydium_i2c_fw_trigger(struct i2c_client *client)
                }
        }
 
-       return false;
+       return 0;
 }
 
 static int raydium_i2c_check_path(struct i2c_client *client)
index ad8b6a2..8fa2f3b 100644 (file)
@@ -288,7 +288,7 @@ static int silead_ts_load_fw(struct i2c_client *client)
 
        dev_dbg(dev, "Firmware file name: %s", data->fw_name);
 
-       error = request_firmware(&fw, data->fw_name, dev);
+       error = firmware_request_platform(&fw, data->fw_name, dev);
        if (error) {
                dev_err(dev, "Firmware request error %d\n", error);
                return error;
index f277e46..2c6515e 100644 (file)
@@ -445,6 +445,11 @@ struct icc_path *of_icc_get(struct device *dev, const char *name)
                path->name = kasprintf(GFP_KERNEL, "%s-%s",
                                       src_node->name, dst_node->name);
 
+       if (!path->name) {
+               kfree(path);
+               return ERR_PTR(-ENOMEM);
+       }
+
        return path;
 }
 EXPORT_SYMBOL_GPL(of_icc_get);
@@ -579,6 +584,10 @@ struct icc_path *icc_get(struct device *dev, const int src_id, const int dst_id)
        }
 
        path->name = kasprintf(GFP_KERNEL, "%s-%s", src->name, dst->name);
+       if (!path->name) {
+               kfree(path);
+               path = ERR_PTR(-ENOMEM);
+       }
 out:
        mutex_unlock(&icc_lock);
        return path;
index aac132b..20cce36 100644 (file)
@@ -3826,7 +3826,7 @@ int amd_iommu_activate_guest_mode(void *data)
        entry->lo.fields_vapic.ga_tag      = ir_data->ga_tag;
 
        return modify_irte_ga(ir_data->irq_2_irte.devid,
-                             ir_data->irq_2_irte.index, entry, NULL);
+                             ir_data->irq_2_irte.index, entry, ir_data);
 }
 EXPORT_SYMBOL(amd_iommu_activate_guest_mode);
 
@@ -3852,7 +3852,7 @@ int amd_iommu_deactivate_guest_mode(void *data)
                                APICID_TO_IRTE_DEST_HI(cfg->dest_apicid);
 
        return modify_irte_ga(ir_data->irq_2_irte.devid,
-                             ir_data->irq_2_irte.index, entry, NULL);
+                             ir_data->irq_2_irte.index, entry, ir_data);
 }
 EXPORT_SYMBOL(amd_iommu_deactivate_guest_mode);
 
index a2e96a5..ba128d1 100644 (file)
@@ -177,15 +177,15 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
        start -= iova_offset(iovad, start);
        num_pages = iova_align(iovad, end - start) >> iova_shift(iovad);
 
-       msi_page = kcalloc(num_pages, sizeof(*msi_page), GFP_KERNEL);
-       if (!msi_page)
-               return -ENOMEM;
-
        for (i = 0; i < num_pages; i++) {
-               msi_page[i].phys = start;
-               msi_page[i].iova = start;
-               INIT_LIST_HEAD(&msi_page[i].list);
-               list_add(&msi_page[i].list, &cookie->msi_page_list);
+               msi_page = kmalloc(sizeof(*msi_page), GFP_KERNEL);
+               if (!msi_page)
+                       return -ENOMEM;
+
+               msi_page->phys = start;
+               msi_page->iova = start;
+               INIT_LIST_HEAD(&msi_page->list);
+               list_add(&msi_page->list, &cookie->msi_page_list);
                start += iovad->granule;
        }
 
index 071bb42..f77dae7 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/iommu.h>
 #include <linux/numa.h>
+#include <linux/limits.h>
 #include <asm/irq_remapping.h>
 #include <asm/iommu_table.h>
 
@@ -128,6 +129,13 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event)
 
        BUG_ON(dev->is_virtfn);
 
+       /*
+        * Ignore devices that have a domain number higher than what can
+        * be looked up in DMAR, e.g. VMD subdevices with domain 0x10000
+        */
+       if (pci_domain_nr(dev->bus) > U16_MAX)
+               return NULL;
+
        /* Only generate path[] for device addition event */
        if (event == BUS_NOTIFY_ADD_DEVICE)
                for (tmp = dev; tmp; tmp = tmp->bus->self)
@@ -363,7 +371,8 @@ dmar_find_dmaru(struct acpi_dmar_hardware_unit *drhd)
 {
        struct dmar_drhd_unit *dmaru;
 
-       list_for_each_entry_rcu(dmaru, &dmar_drhd_units, list)
+       list_for_each_entry_rcu(dmaru, &dmar_drhd_units, list,
+                               dmar_rcu_check())
                if (dmaru->segment == drhd->segment &&
                    dmaru->reg_base_addr == drhd->address)
                        return dmaru;
@@ -440,12 +449,13 @@ static int __init dmar_parse_one_andd(struct acpi_dmar_header *header,
 
        /* Check for NUL termination within the designated length */
        if (strnlen(andd->device_name, header->length - 8) == header->length - 8) {
-               WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND,
+               pr_warn(FW_BUG
                           "Your BIOS is broken; ANDD object name is not NUL-terminated\n"
                           "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
                           dmi_get_system_info(DMI_BIOS_VENDOR),
                           dmi_get_system_info(DMI_BIOS_VERSION),
                           dmi_get_system_info(DMI_PRODUCT_VERSION));
+               add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
                return -EINVAL;
        }
        pr_info("ANDD device: %x name: %s\n", andd->device_number,
@@ -471,14 +481,14 @@ static int dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg)
                        return 0;
                }
        }
-       WARN_TAINT(
-               1, TAINT_FIRMWARE_WORKAROUND,
+       pr_warn(FW_BUG
                "Your BIOS is broken; RHSA refers to non-existent DMAR unit at %llx\n"
                "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
-               drhd->reg_base_addr,
+               rhsa->base_address,
                dmi_get_system_info(DMI_BIOS_VENDOR),
                dmi_get_system_info(DMI_BIOS_VERSION),
                dmi_get_system_info(DMI_PRODUCT_VERSION));
+       add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
 
        return 0;
 }
@@ -827,14 +837,14 @@ int __init dmar_table_init(void)
 
 static void warn_invalid_dmar(u64 addr, const char *message)
 {
-       WARN_TAINT_ONCE(
-               1, TAINT_FIRMWARE_WORKAROUND,
+       pr_warn_once(FW_BUG
                "Your BIOS is broken; DMAR reported at address %llx%s!\n"
                "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
                addr, message,
                dmi_get_system_info(DMI_BIOS_VENDOR),
                dmi_get_system_info(DMI_BIOS_VERSION),
                dmi_get_system_info(DMI_PRODUCT_VERSION));
+       add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
 }
 
 static int __ref
index c1257be..3eb1fe2 100644 (file)
@@ -33,38 +33,42 @@ struct iommu_regset {
 
 #define IOMMU_REGSET_ENTRY(_reg_)                                      \
        { DMAR_##_reg_##_REG, __stringify(_reg_) }
-static const struct iommu_regset iommu_regs[] = {
+
+static const struct iommu_regset iommu_regs_32[] = {
        IOMMU_REGSET_ENTRY(VER),
-       IOMMU_REGSET_ENTRY(CAP),
-       IOMMU_REGSET_ENTRY(ECAP),
        IOMMU_REGSET_ENTRY(GCMD),
        IOMMU_REGSET_ENTRY(GSTS),
-       IOMMU_REGSET_ENTRY(RTADDR),
-       IOMMU_REGSET_ENTRY(CCMD),
        IOMMU_REGSET_ENTRY(FSTS),
        IOMMU_REGSET_ENTRY(FECTL),
        IOMMU_REGSET_ENTRY(FEDATA),
        IOMMU_REGSET_ENTRY(FEADDR),
        IOMMU_REGSET_ENTRY(FEUADDR),
-       IOMMU_REGSET_ENTRY(AFLOG),
        IOMMU_REGSET_ENTRY(PMEN),
        IOMMU_REGSET_ENTRY(PLMBASE),
        IOMMU_REGSET_ENTRY(PLMLIMIT),
+       IOMMU_REGSET_ENTRY(ICS),
+       IOMMU_REGSET_ENTRY(PRS),
+       IOMMU_REGSET_ENTRY(PECTL),
+       IOMMU_REGSET_ENTRY(PEDATA),
+       IOMMU_REGSET_ENTRY(PEADDR),
+       IOMMU_REGSET_ENTRY(PEUADDR),
+};
+
+static const struct iommu_regset iommu_regs_64[] = {
+       IOMMU_REGSET_ENTRY(CAP),
+       IOMMU_REGSET_ENTRY(ECAP),
+       IOMMU_REGSET_ENTRY(RTADDR),
+       IOMMU_REGSET_ENTRY(CCMD),
+       IOMMU_REGSET_ENTRY(AFLOG),
        IOMMU_REGSET_ENTRY(PHMBASE),
        IOMMU_REGSET_ENTRY(PHMLIMIT),
        IOMMU_REGSET_ENTRY(IQH),
        IOMMU_REGSET_ENTRY(IQT),
        IOMMU_REGSET_ENTRY(IQA),
-       IOMMU_REGSET_ENTRY(ICS),
        IOMMU_REGSET_ENTRY(IRTA),
        IOMMU_REGSET_ENTRY(PQH),
        IOMMU_REGSET_ENTRY(PQT),
        IOMMU_REGSET_ENTRY(PQA),
-       IOMMU_REGSET_ENTRY(PRS),
-       IOMMU_REGSET_ENTRY(PECTL),
-       IOMMU_REGSET_ENTRY(PEDATA),
-       IOMMU_REGSET_ENTRY(PEADDR),
-       IOMMU_REGSET_ENTRY(PEUADDR),
        IOMMU_REGSET_ENTRY(MTRRCAP),
        IOMMU_REGSET_ENTRY(MTRRDEF),
        IOMMU_REGSET_ENTRY(MTRR_FIX64K_00000),
@@ -127,10 +131,16 @@ static int iommu_regset_show(struct seq_file *m, void *unused)
                 * by adding the offset to the pointer (virtual address).
                 */
                raw_spin_lock_irqsave(&iommu->register_lock, flag);
-               for (i = 0 ; i < ARRAY_SIZE(iommu_regs); i++) {
-                       value = dmar_readq(iommu->reg + iommu_regs[i].offset);
+               for (i = 0 ; i < ARRAY_SIZE(iommu_regs_32); i++) {
+                       value = dmar_readl(iommu->reg + iommu_regs_32[i].offset);
+                       seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
+                                  iommu_regs_32[i].regs, iommu_regs_32[i].offset,
+                                  value);
+               }
+               for (i = 0 ; i < ARRAY_SIZE(iommu_regs_64); i++) {
+                       value = dmar_readq(iommu->reg + iommu_regs_64[i].offset);
                        seq_printf(m, "%-16s\t0x%02x\t\t0x%016llx\n",
-                                  iommu_regs[i].regs, iommu_regs[i].offset,
+                                  iommu_regs_64[i].regs, iommu_regs_64[i].offset,
                                   value);
                }
                raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
@@ -272,9 +282,16 @@ static int dmar_translation_struct_show(struct seq_file *m, void *unused)
 {
        struct dmar_drhd_unit *drhd;
        struct intel_iommu *iommu;
+       u32 sts;
 
        rcu_read_lock();
        for_each_active_iommu(iommu, drhd) {
+               sts = dmar_readl(iommu->reg + DMAR_GSTS_REG);
+               if (!(sts & DMA_GSTS_TES)) {
+                       seq_printf(m, "DMA Remapping is not enabled on %s\n",
+                                  iommu->name);
+                       continue;
+               }
                root_tbl_walk(m, iommu);
                seq_putc(m, '\n');
        }
@@ -415,6 +432,7 @@ static int ir_translation_struct_show(struct seq_file *m, void *unused)
        struct dmar_drhd_unit *drhd;
        struct intel_iommu *iommu;
        u64 irta;
+       u32 sts;
 
        rcu_read_lock();
        for_each_active_iommu(iommu, drhd) {
@@ -424,7 +442,8 @@ static int ir_translation_struct_show(struct seq_file *m, void *unused)
                seq_printf(m, "Remapped Interrupt supported on IOMMU: %s\n",
                           iommu->name);
 
-               if (iommu->ir_table) {
+               sts = dmar_readl(iommu->reg + DMAR_GSTS_REG);
+               if (iommu->ir_table && (sts & DMA_GSTS_IRES)) {
                        irta = virt_to_phys(iommu->ir_table->base);
                        seq_printf(m, " IR table address:%llx\n", irta);
                        ir_tbl_remap_entry_show(m, iommu);
index 6fa6de2..4be5494 100644 (file)
@@ -4261,10 +4261,11 @@ static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
 
        /* we know that the this iommu should be at offset 0xa000 from vtbar */
        drhd = dmar_find_matched_drhd_unit(pdev);
-       if (WARN_TAINT_ONCE(!drhd || drhd->reg_base_addr - vtbar != 0xa000,
-                           TAINT_FIRMWARE_WORKAROUND,
-                           "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n"))
+       if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
+               pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
+               add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
                pdev->dev.archdata.iommu = DUMMY_DEVICE_DOMAIN_INFO;
+       }
 }
 DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB, quirk_ioat_snb_local_iommu);
 
@@ -4460,14 +4461,16 @@ int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
        struct dmar_rmrr_unit *rmrru;
 
        rmrr = (struct acpi_dmar_reserved_memory *)header;
-       if (rmrr_sanity_check(rmrr))
-               WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND,
+       if (rmrr_sanity_check(rmrr)) {
+               pr_warn(FW_BUG
                           "Your BIOS is broken; bad RMRR [%#018Lx-%#018Lx]\n"
                           "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
                           rmrr->base_address, rmrr->end_address,
                           dmi_get_system_info(DMI_BIOS_VENDOR),
                           dmi_get_system_info(DMI_BIOS_VERSION),
                           dmi_get_system_info(DMI_PRODUCT_VERSION));
+               add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
+       }
 
        rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
        if (!rmrru)
@@ -5130,6 +5133,9 @@ int __init intel_iommu_init(void)
 
        down_write(&dmar_global_lock);
 
+       if (!no_iommu)
+               intel_iommu_debugfs_init();
+
        if (no_iommu || dmar_disabled) {
                /*
                 * We exit the function here to ensure IOMMU's remapping and
@@ -5193,6 +5199,7 @@ int __init intel_iommu_init(void)
 
        init_iommu_pm_ops();
 
+       down_read(&dmar_global_lock);
        for_each_active_iommu(iommu, drhd) {
                iommu_device_sysfs_add(&iommu->iommu, NULL,
                                       intel_iommu_groups,
@@ -5200,6 +5207,7 @@ int __init intel_iommu_init(void)
                iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
                iommu_device_register(&iommu->iommu);
        }
+       up_read(&dmar_global_lock);
 
        bus_set_iommu(&pci_bus_type, &intel_iommu_ops);
        if (si_domain && !hw_pass_through)
@@ -5210,7 +5218,6 @@ int __init intel_iommu_init(void)
        down_read(&dmar_global_lock);
        if (probe_acpi_namespace_devices())
                pr_warn("ACPI name space devices didn't probe correctly\n");
-       up_read(&dmar_global_lock);
 
        /* Finally, we enable the DMA remapping hardware. */
        for_each_iommu(iommu, drhd) {
@@ -5219,10 +5226,11 @@ int __init intel_iommu_init(void)
 
                iommu_disable_protect_mem_regions(iommu);
        }
+       up_read(&dmar_global_lock);
+
        pr_info("Intel(R) Virtualization Technology for Directed I/O\n");
 
        intel_iommu_enabled = 1;
-       intel_iommu_debugfs_init();
 
        return 0;
 
@@ -5700,8 +5708,10 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
        u64 phys = 0;
 
        pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, &level);
-       if (pte)
-               phys = dma_pte_addr(pte);
+       if (pte && dma_pte_present(pte))
+               phys = dma_pte_addr(pte) +
+                       (iova & (BIT_MASK(level_to_offset_bits(level) +
+                                               VTD_PAGE_SHIFT) - 1));
 
        return phys;
 }
index 983b084..04fbd4b 100644 (file)
@@ -468,7 +468,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
        arm_lpae_iopte *ptep = data->pgd;
        int ret, lvl = data->start_level;
        arm_lpae_iopte prot;
-       long iaext = (long)iova >> cfg->ias;
+       long iaext = (s64)iova >> cfg->ias;
 
        /* If no access, then nothing to do */
        if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
@@ -645,7 +645,7 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
        struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
        struct io_pgtable_cfg *cfg = &data->iop.cfg;
        arm_lpae_iopte *ptep = data->pgd;
-       long iaext = (long)iova >> cfg->ias;
+       long iaext = (s64)iova >> cfg->ias;
 
        if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
                return 0;
index 6d39773..a85aada 100644 (file)
@@ -458,7 +458,7 @@ config IMX_IRQSTEER
          Support for the i.MX IRQSTEER interrupt multiplexer/remapper.
 
 config IMX_INTMUX
-       def_bool y if ARCH_MXC
+       def_bool y if ARCH_MXC || COMPILE_TEST
        select IRQ_DOMAIN
        help
          Support for the i.MX INTMUX interrupt multiplexer.
@@ -513,4 +513,23 @@ config EXYNOS_IRQ_COMBINER
          Say yes here to add support for the IRQ combiner devices embedded
          in Samsung Exynos chips.
 
+config LOONGSON_LIOINTC
+       bool "Loongson Local I/O Interrupt Controller"
+       depends on MACH_LOONGSON64
+       default y
+       select IRQ_DOMAIN
+       select GENERIC_IRQ_CHIP
+       help
+         Support for the Loongson Local I/O Interrupt Controller.
+
+config LOONGSON_HTPIC
+       bool "Loongson3 HyperTransport PIC Controller"
+       depends on MACH_LOONGSON64
+       default y
+       select IRQ_DOMAIN
+       select GENERIC_IRQ_CHIP
+       select I8259
+       help
+         Support for the Loongson-3 HyperTransport PIC Controller.
+
 endmenu
index eae0d78..37bbe39 100644 (file)
@@ -105,3 +105,5 @@ obj-$(CONFIG_MADERA_IRQ)            += irq-madera.o
 obj-$(CONFIG_LS1X_IRQ)                 += irq-ls1x.o
 obj-$(CONFIG_TI_SCI_INTR_IRQCHIP)      += irq-ti-sci-intr.o
 obj-$(CONFIG_TI_SCI_INTA_IRQCHIP)      += irq-ti-sci-inta.o
+obj-$(CONFIG_LOONGSON_LIOINTC)         += irq-loongson-liointc.o
+obj-$(CONFIG_LOONGSON_HTPIC)           += irq-loongson-htpic.o
index bb1ad45..2c999dc 100644 (file)
@@ -83,7 +83,7 @@ static int aic_retrigger(struct irq_data *d)
        irq_reg_writel(gc, d->mask, AT91_AIC_ISCR);
        irq_gc_unlock(gc);
 
-       return 0;
+       return 1;
 }
 
 static int aic_set_type(struct irq_data *d, unsigned type)
index 2933349..fc1b3a9 100644 (file)
@@ -128,7 +128,7 @@ static int aic5_retrigger(struct irq_data *d)
        irq_reg_writel(bgc, 1, AT91_AIC5_ISCR);
        irq_gc_unlock(bgc);
 
-       return 0;
+       return 1;
 }
 
 static int aic5_set_type(struct irq_data *d, unsigned type)
index 418245d..a1e004a 100644 (file)
@@ -61,6 +61,7 @@
                                        | SHORTCUT1_MASK | SHORTCUT2_MASK)
 
 #define REG_FIQ_CONTROL                0x0c
+#define FIQ_CONTROL_ENABLE     BIT(7)
 
 #define NR_BANKS               3
 #define IRQS_PER_BANK          32
@@ -135,6 +136,7 @@ static int __init armctrl_of_init(struct device_node *node,
 {
        void __iomem *base;
        int irq, b, i;
+       u32 reg;
 
        base = of_iomap(node, 0);
        if (!base)
@@ -157,6 +159,19 @@ static int __init armctrl_of_init(struct device_node *node,
                                handle_level_irq);
                        irq_set_probe(irq);
                }
+
+               reg = readl_relaxed(intc.enable[b]);
+               if (reg) {
+                       writel_relaxed(reg, intc.disable[b]);
+                       pr_err(FW_BUG "Bootloader left irq enabled: "
+                              "bank %d irq %*pbl\n", b, IRQS_PER_BANK, &reg);
+               }
+       }
+
+       reg = readl_relaxed(base + REG_FIQ_CONTROL);
+       if (reg & FIQ_CONTROL_ENABLE) {
+               writel_relaxed(0, base + REG_FIQ_CONTROL);
+               pr_err(FW_BUG "Bootloader left fiq enabled\n");
        }
 
        if (is_2836) {
index cbf01af..eb9bce9 100644 (file)
@@ -50,7 +50,7 @@ struct bcm7038_l1_chip {
 
 struct bcm7038_l1_cpu {
        void __iomem            *map_base;
-       u32                     mask_cache[0];
+       u32                     mask_cache[];
 };
 
 /*
index 83b1186..54d142c 100644 (file)
@@ -96,6 +96,7 @@ struct its_node {
        struct mutex            dev_alloc_lock;
        struct list_head        entry;
        void __iomem            *base;
+       void __iomem            *sgir_base;
        phys_addr_t             phys_base;
        struct its_cmd_block    *cmd_base;
        struct its_cmd_block    *cmd_write;
@@ -188,6 +189,15 @@ static DEFINE_IDA(its_vpeid_ida);
 #define gic_data_rdist_rd_base()       (gic_data_rdist()->rd_base)
 #define gic_data_rdist_vlpi_base()     (gic_data_rdist_rd_base() + SZ_128K)
 
+/*
+ * Skip ITSs that have no vLPIs mapped, unless we're on GICv4.1, as we
+ * always have vSGIs mapped.
+ */
+static bool require_its_list_vmovp(struct its_vm *vm, struct its_node *its)
+{
+       return (gic_rdists->has_rvpeid || vm->vlpi_count[its->list_nr]);
+}
+
 static u16 get_its_list(struct its_vm *vm)
 {
        struct its_node *its;
@@ -197,7 +207,7 @@ static u16 get_its_list(struct its_vm *vm)
                if (!is_v4(its))
                        continue;
 
-               if (vm->vlpi_count[its->list_nr])
+               if (require_its_list_vmovp(vm, its))
                        __set_bit(its->list_nr, &its_list);
        }
 
@@ -239,15 +249,41 @@ static struct its_vlpi_map *get_vlpi_map(struct irq_data *d)
        return NULL;
 }
 
-static int irq_to_cpuid(struct irq_data *d)
+static int vpe_to_cpuid_lock(struct its_vpe *vpe, unsigned long *flags)
+{
+       raw_spin_lock_irqsave(&vpe->vpe_lock, *flags);
+       return vpe->col_idx;
+}
+
+static void vpe_to_cpuid_unlock(struct its_vpe *vpe, unsigned long flags)
+{
+       raw_spin_unlock_irqrestore(&vpe->vpe_lock, flags);
+}
+
+static int irq_to_cpuid_lock(struct irq_data *d, unsigned long *flags)
 {
-       struct its_device *its_dev = irq_data_get_irq_chip_data(d);
        struct its_vlpi_map *map = get_vlpi_map(d);
+       int cpu;
 
-       if (map)
-               return map->vpe->col_idx;
+       if (map) {
+               cpu = vpe_to_cpuid_lock(map->vpe, flags);
+       } else {
+               /* Physical LPIs are already locked via the irq_desc lock */
+               struct its_device *its_dev = irq_data_get_irq_chip_data(d);
+               cpu = its_dev->event_map.col_map[its_get_event_id(d)];
+               /* Keep GCC quiet... */
+               *flags = 0;
+       }
+
+       return cpu;
+}
+
+static void irq_to_cpuid_unlock(struct irq_data *d, unsigned long flags)
+{
+       struct its_vlpi_map *map = get_vlpi_map(d);
 
-       return its_dev->event_map.col_map[its_get_event_id(d)];
+       if (map)
+               vpe_to_cpuid_unlock(map->vpe, flags);
 }
 
 static struct its_collection *valid_col(struct its_collection *col)
@@ -353,6 +389,15 @@ struct its_cmd_desc {
                struct {
                        struct its_vpe *vpe;
                } its_invdb_cmd;
+
+               struct {
+                       struct its_vpe *vpe;
+                       u8 sgi;
+                       u8 priority;
+                       bool enable;
+                       bool group;
+                       bool clear;
+               } its_vsgi_cmd;
        };
 };
 
@@ -501,6 +546,31 @@ static void its_encode_db(struct its_cmd_block *cmd, bool db)
        its_mask_encode(&cmd->raw_cmd[2], db, 63, 63);
 }
 
+static void its_encode_sgi_intid(struct its_cmd_block *cmd, u8 sgi)
+{
+       its_mask_encode(&cmd->raw_cmd[0], sgi, 35, 32);
+}
+
+static void its_encode_sgi_priority(struct its_cmd_block *cmd, u8 prio)
+{
+       its_mask_encode(&cmd->raw_cmd[0], prio >> 4, 23, 20);
+}
+
+static void its_encode_sgi_group(struct its_cmd_block *cmd, bool grp)
+{
+       its_mask_encode(&cmd->raw_cmd[0], grp, 10, 10);
+}
+
+static void its_encode_sgi_clear(struct its_cmd_block *cmd, bool clr)
+{
+       its_mask_encode(&cmd->raw_cmd[0], clr, 9, 9);
+}
+
+static void its_encode_sgi_enable(struct its_cmd_block *cmd, bool en)
+{
+       its_mask_encode(&cmd->raw_cmd[0], en, 8, 8);
+}
+
 static inline void its_fixup_cmd(struct its_cmd_block *cmd)
 {
        /* Let's fixup BE commands */
@@ -866,6 +936,26 @@ static struct its_vpe *its_build_invdb_cmd(struct its_node *its,
        return valid_vpe(its, desc->its_invdb_cmd.vpe);
 }
 
+static struct its_vpe *its_build_vsgi_cmd(struct its_node *its,
+                                         struct its_cmd_block *cmd,
+                                         struct its_cmd_desc *desc)
+{
+       if (WARN_ON(!is_v4_1(its)))
+               return NULL;
+
+       its_encode_cmd(cmd, GITS_CMD_VSGI);
+       its_encode_vpeid(cmd, desc->its_vsgi_cmd.vpe->vpe_id);
+       its_encode_sgi_intid(cmd, desc->its_vsgi_cmd.sgi);
+       its_encode_sgi_priority(cmd, desc->its_vsgi_cmd.priority);
+       its_encode_sgi_group(cmd, desc->its_vsgi_cmd.group);
+       its_encode_sgi_clear(cmd, desc->its_vsgi_cmd.clear);
+       its_encode_sgi_enable(cmd, desc->its_vsgi_cmd.enable);
+
+       its_fixup_cmd(cmd);
+
+       return valid_vpe(its, desc->its_vsgi_cmd.vpe);
+}
+
 static u64 its_cmd_ptr_to_offset(struct its_node *its,
                                 struct its_cmd_block *ptr)
 {
@@ -1214,7 +1304,7 @@ static void its_send_vmovp(struct its_vpe *vpe)
                if (!is_v4(its))
                        continue;
 
-               if (!vpe->its_vm->vlpi_count[its->list_nr])
+               if (!require_its_list_vmovp(vpe->its_vm, its))
                        continue;
 
                desc.its_vmovp_cmd.col = &its->collections[col_id];
@@ -1321,7 +1411,7 @@ static void lpi_write_config(struct irq_data *d, u8 clr, u8 set)
 
 static void wait_for_syncr(void __iomem *rdbase)
 {
-       while (gic_read_lpir(rdbase + GICR_SYNCR) & 1)
+       while (readl_relaxed(rdbase + GICR_SYNCR) & 1)
                cpu_relax();
 }
 
@@ -1329,7 +1419,9 @@ static void direct_lpi_inv(struct irq_data *d)
 {
        struct its_vlpi_map *map = get_vlpi_map(d);
        void __iomem *rdbase;
+       unsigned long flags;
        u64 val;
+       int cpu;
 
        if (map) {
                struct its_device *its_dev = irq_data_get_irq_chip_data(d);
@@ -1344,10 +1436,14 @@ static void direct_lpi_inv(struct irq_data *d)
        }
 
        /* Target the redistributor this LPI is currently routed to */
-       rdbase = per_cpu_ptr(gic_rdists->rdist, irq_to_cpuid(d))->rd_base;
+       cpu = irq_to_cpuid_lock(d, &flags);
+       raw_spin_lock(&gic_data_rdist_cpu(cpu)->rd_lock);
+       rdbase = per_cpu_ptr(gic_rdists->rdist, cpu)->rd_base;
        gic_write_lpir(val, rdbase + GICR_INVLPIR);
 
        wait_for_syncr(rdbase);
+       raw_spin_unlock(&gic_data_rdist_cpu(cpu)->rd_lock);
+       irq_to_cpuid_unlock(d, flags);
 }
 
 static void lpi_update_config(struct irq_data *d, u8 clr, u8 set)
@@ -1499,12 +1595,31 @@ static int its_irq_set_irqchip_state(struct irq_data *d,
        return 0;
 }
 
+/*
+ * Two favourable cases:
+ *
+ * (a) Either we have a GICv4.1, and all vPEs have to be mapped at all times
+ *     for vSGI delivery
+ *
+ * (b) Or the ITSs do not use a list map, meaning that VMOVP is cheap enough
+ *     and we're better off mapping all VPEs always
+ *
+ * If neither (a) nor (b) is true, then we map vPEs on demand.
+ *
+ */
+static bool gic_requires_eager_mapping(void)
+{
+       if (!its_list_map || gic_rdists->has_rvpeid)
+               return true;
+
+       return false;
+}
+
 static void its_map_vm(struct its_node *its, struct its_vm *vm)
 {
        unsigned long flags;
 
-       /* Not using the ITS list? Everything is always mapped. */
-       if (!its_list_map)
+       if (gic_requires_eager_mapping())
                return;
 
        raw_spin_lock_irqsave(&vmovp_lock, flags);
@@ -1538,7 +1653,7 @@ static void its_unmap_vm(struct its_node *its, struct its_vm *vm)
        unsigned long flags;
 
        /* Not using the ITS list? Everything is always mapped. */
-       if (!its_list_map)
+       if (gic_requires_eager_mapping())
                return;
 
        raw_spin_lock_irqsave(&vmovp_lock, flags);
@@ -2036,18 +2151,17 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser,
 }
 
 static int its_setup_baser(struct its_node *its, struct its_baser *baser,
-                          u64 cache, u64 shr, u32 psz, u32 order,
-                          bool indirect)
+                          u64 cache, u64 shr, u32 order, bool indirect)
 {
        u64 val = its_read_baser(its, baser);
        u64 esz = GITS_BASER_ENTRY_SIZE(val);
        u64 type = GITS_BASER_TYPE(val);
        u64 baser_phys, tmp;
-       u32 alloc_pages;
+       u32 alloc_pages, psz;
        struct page *page;
        void *base;
 
-retry_alloc_baser:
+       psz = baser->psz;
        alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz);
        if (alloc_pages > GITS_BASER_PAGES_MAX) {
                pr_warn("ITS@%pa: %s too large, reduce ITS pages %u->%u\n",
@@ -2120,25 +2234,6 @@ retry_baser:
                goto retry_baser;
        }
 
-       if ((val ^ tmp) & GITS_BASER_PAGE_SIZE_MASK) {
-               /*
-                * Page size didn't stick. Let's try a smaller
-                * size and retry. If we reach 4K, then
-                * something is horribly wrong...
-                */
-               free_pages((unsigned long)base, order);
-               baser->base = NULL;
-
-               switch (psz) {
-               case SZ_16K:
-                       psz = SZ_4K;
-                       goto retry_alloc_baser;
-               case SZ_64K:
-                       psz = SZ_16K;
-                       goto retry_alloc_baser;
-               }
-       }
-
        if (val != tmp) {
                pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n",
                       &its->phys_base, its_base_type_string[type],
@@ -2164,13 +2259,14 @@ retry_baser:
 
 static bool its_parse_indirect_baser(struct its_node *its,
                                     struct its_baser *baser,
-                                    u32 psz, u32 *order, u32 ids)
+                                    u32 *order, u32 ids)
 {
        u64 tmp = its_read_baser(its, baser);
        u64 type = GITS_BASER_TYPE(tmp);
        u64 esz = GITS_BASER_ENTRY_SIZE(tmp);
        u64 val = GITS_BASER_InnerShareable | GITS_BASER_RaWaWb;
        u32 new_order = *order;
+       u32 psz = baser->psz;
        bool indirect = false;
 
        /* No need to enable Indirection if memory requirement < (psz*2)bytes */
@@ -2288,11 +2384,58 @@ static void its_free_tables(struct its_node *its)
        }
 }
 
+static int its_probe_baser_psz(struct its_node *its, struct its_baser *baser)
+{
+       u64 psz = SZ_64K;
+
+       while (psz) {
+               u64 val, gpsz;
+
+               val = its_read_baser(its, baser);
+               val &= ~GITS_BASER_PAGE_SIZE_MASK;
+
+               switch (psz) {
+               case SZ_64K:
+                       gpsz = GITS_BASER_PAGE_SIZE_64K;
+                       break;
+               case SZ_16K:
+                       gpsz = GITS_BASER_PAGE_SIZE_16K;
+                       break;
+               case SZ_4K:
+               default:
+                       gpsz = GITS_BASER_PAGE_SIZE_4K;
+                       break;
+               }
+
+               gpsz >>= GITS_BASER_PAGE_SIZE_SHIFT;
+
+               val |= FIELD_PREP(GITS_BASER_PAGE_SIZE_MASK, gpsz);
+               its_write_baser(its, baser, val);
+
+               if (FIELD_GET(GITS_BASER_PAGE_SIZE_MASK, baser->val) == gpsz)
+                       break;
+
+               switch (psz) {
+               case SZ_64K:
+                       psz = SZ_16K;
+                       break;
+               case SZ_16K:
+                       psz = SZ_4K;
+                       break;
+               case SZ_4K:
+               default:
+                       return -1;
+               }
+       }
+
+       baser->psz = psz;
+       return 0;
+}
+
 static int its_alloc_tables(struct its_node *its)
 {
        u64 shr = GITS_BASER_InnerShareable;
        u64 cache = GITS_BASER_RaWaWb;
-       u32 psz = SZ_64K;
        int err, i;
 
        if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_22375)
@@ -2303,16 +2446,22 @@ static int its_alloc_tables(struct its_node *its)
                struct its_baser *baser = its->tables + i;
                u64 val = its_read_baser(its, baser);
                u64 type = GITS_BASER_TYPE(val);
-               u32 order = get_order(psz);
                bool indirect = false;
+               u32 order;
 
-               switch (type) {
-               case GITS_BASER_TYPE_NONE:
+               if (type == GITS_BASER_TYPE_NONE)
                        continue;
 
+               if (its_probe_baser_psz(its, baser)) {
+                       its_free_tables(its);
+                       return -ENXIO;
+               }
+
+               order = get_order(baser->psz);
+
+               switch (type) {
                case GITS_BASER_TYPE_DEVICE:
-                       indirect = its_parse_indirect_baser(its, baser,
-                                                           psz, &order,
+                       indirect = its_parse_indirect_baser(its, baser, &order,
                                                            device_ids(its));
                        break;
 
@@ -2328,20 +2477,18 @@ static int its_alloc_tables(struct its_node *its)
                                }
                        }
 
-                       indirect = its_parse_indirect_baser(its, baser,
-                                                           psz, &order,
+                       indirect = its_parse_indirect_baser(its, baser, &order,
                                                            ITS_MAX_VPEID_BITS);
                        break;
                }
 
-               err = its_setup_baser(its, baser, cache, shr, psz, order, indirect);
+               err = its_setup_baser(its, baser, cache, shr, order, indirect);
                if (err < 0) {
                        its_free_tables(its);
                        return err;
                }
 
                /* Update settings which will be used for next BASERn */
-               psz = baser->psz;
                cache = baser->val & GITS_BASER_CACHEABILITY_MASK;
                shr = baser->val & GITS_BASER_SHAREABILITY_MASK;
        }
@@ -2452,6 +2599,10 @@ static bool allocate_vpe_l2_table(int cpu, u32 id)
        if (!gic_rdists->has_rvpeid)
                return true;
 
+       /* Skip non-present CPUs */
+       if (!base)
+               return true;
+
        val  = gicr_read_vpropbaser(base + SZ_128K + GICR_VPROPBASER);
 
        esz  = FIELD_GET(GICR_VPROPBASER_4_1_ENTRY_SIZE, val) + 1;
@@ -3482,17 +3633,25 @@ static int its_vpe_set_affinity(struct irq_data *d,
 {
        struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
        int from, cpu = cpumask_first(mask_val);
+       unsigned long flags;
 
        /*
         * Changing affinity is mega expensive, so let's be as lazy as
         * we can and only do it if we really have to. Also, if mapped
         * into the proxy device, we need to move the doorbell
         * interrupt to its new location.
+        *
+        * Another thing is that changing the affinity of a vPE affects
+        * *other interrupts* such as all the vLPIs that are routed to
+        * this vPE. This means that the irq_desc lock is not enough to
+        * protect us, and that we must ensure nobody samples vpe->col_idx
+        * during the update, hence the lock below which must also be
+        * taken on any vLPI handling path that evaluates vpe->col_idx.
         */
-       if (vpe->col_idx == cpu)
+       from = vpe_to_cpuid_lock(vpe, &flags);
+       if (from == cpu)
                goto out;
 
-       from = vpe->col_idx;
        vpe->col_idx = cpu;
 
        /*
@@ -3508,6 +3667,7 @@ static int its_vpe_set_affinity(struct irq_data *d,
 
 out:
        irq_data_update_effective_affinity(d, cpumask_of(cpu));
+       vpe_to_cpuid_unlock(vpe, flags);
 
        return IRQ_SET_MASK_OK_DONE;
 }
@@ -3528,7 +3688,7 @@ static void its_vpe_schedule(struct its_vpe *vpe)
        val  = virt_to_phys(page_address(vpe->vpt_page)) &
                GENMASK_ULL(51, 16);
        val |= GICR_VPENDBASER_RaWaWb;
-       val |= GICR_VPENDBASER_NonShareable;
+       val |= GICR_VPENDBASER_InnerShareable;
        /*
         * There is no good way of finding out if the pending table is
         * empty as we can race against the doorbell interrupt very
@@ -3619,9 +3779,11 @@ static void its_vpe_send_inv(struct irq_data *d)
                void __iomem *rdbase;
 
                /* Target the redistributor this VPE is currently known on */
+               raw_spin_lock(&gic_data_rdist_cpu(vpe->col_idx)->rd_lock);
                rdbase = per_cpu_ptr(gic_rdists->rdist, vpe->col_idx)->rd_base;
                gic_write_lpir(d->parent_data->hwirq, rdbase + GICR_INVLPIR);
                wait_for_syncr(rdbase);
+               raw_spin_unlock(&gic_data_rdist_cpu(vpe->col_idx)->rd_lock);
        } else {
                its_vpe_send_cmd(vpe, its_send_inv);
        }
@@ -3675,12 +3837,18 @@ static int its_vpe_set_irqchip_state(struct irq_data *d,
        return 0;
 }
 
+static int its_vpe_retrigger(struct irq_data *d)
+{
+       return !its_vpe_set_irqchip_state(d, IRQCHIP_STATE_PENDING, true);
+}
+
 static struct irq_chip its_vpe_irq_chip = {
        .name                   = "GICv4-vpe",
        .irq_mask               = its_vpe_mask_irq,
        .irq_unmask             = its_vpe_unmask_irq,
        .irq_eoi                = irq_chip_eoi_parent,
        .irq_set_affinity       = its_vpe_set_affinity,
+       .irq_retrigger          = its_vpe_retrigger,
        .irq_set_irqchip_state  = its_vpe_set_irqchip_state,
        .irq_set_vcpu_affinity  = its_vpe_set_vcpu_affinity,
 };
@@ -3782,8 +3950,12 @@ static void its_vpe_4_1_invall(struct its_vpe *vpe)
        val |= FIELD_PREP(GICR_INVALLR_VPEID, vpe->vpe_id);
 
        /* Target the redistributor this vPE is currently known on */
+       raw_spin_lock(&gic_data_rdist_cpu(vpe->col_idx)->rd_lock);
        rdbase = per_cpu_ptr(gic_rdists->rdist, vpe->col_idx)->rd_base;
        gic_write_lpir(val, rdbase + GICR_INVALLR);
+
+       wait_for_syncr(rdbase);
+       raw_spin_unlock(&gic_data_rdist_cpu(vpe->col_idx)->rd_lock);
 }
 
 static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
@@ -3818,6 +3990,221 @@ static struct irq_chip its_vpe_4_1_irq_chip = {
        .irq_set_vcpu_affinity  = its_vpe_4_1_set_vcpu_affinity,
 };
 
+static void its_configure_sgi(struct irq_data *d, bool clear)
+{
+       struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+       struct its_cmd_desc desc;
+
+       desc.its_vsgi_cmd.vpe = vpe;
+       desc.its_vsgi_cmd.sgi = d->hwirq;
+       desc.its_vsgi_cmd.priority = vpe->sgi_config[d->hwirq].priority;
+       desc.its_vsgi_cmd.enable = vpe->sgi_config[d->hwirq].enabled;
+       desc.its_vsgi_cmd.group = vpe->sgi_config[d->hwirq].group;
+       desc.its_vsgi_cmd.clear = clear;
+
+       /*
+        * GICv4.1 allows us to send VSGI commands to any ITS as long as the
+        * destination VPE is mapped there. Since we map them eagerly at
+        * activation time, we're pretty sure the first GICv4.1 ITS will do.
+        */
+       its_send_single_vcommand(find_4_1_its(), its_build_vsgi_cmd, &desc);
+}
+
+static void its_sgi_mask_irq(struct irq_data *d)
+{
+       struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+
+       vpe->sgi_config[d->hwirq].enabled = false;
+       its_configure_sgi(d, false);
+}
+
+static void its_sgi_unmask_irq(struct irq_data *d)
+{
+       struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+
+       vpe->sgi_config[d->hwirq].enabled = true;
+       its_configure_sgi(d, false);
+}
+
+static int its_sgi_set_affinity(struct irq_data *d,
+                               const struct cpumask *mask_val,
+                               bool force)
+{
+       /*
+        * There is no notion of affinity for virtual SGIs, at least
+        * not on the host (since they can only be targetting a vPE).
+        * Tell the kernel we've done whatever it asked for.
+        */
+       return IRQ_SET_MASK_OK;
+}
+
+static int its_sgi_set_irqchip_state(struct irq_data *d,
+                                    enum irqchip_irq_state which,
+                                    bool state)
+{
+       if (which != IRQCHIP_STATE_PENDING)
+               return -EINVAL;
+
+       if (state) {
+               struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+               struct its_node *its = find_4_1_its();
+               u64 val;
+
+               val  = FIELD_PREP(GITS_SGIR_VPEID, vpe->vpe_id);
+               val |= FIELD_PREP(GITS_SGIR_VINTID, d->hwirq);
+               writeq_relaxed(val, its->sgir_base + GITS_SGIR - SZ_128K);
+       } else {
+               its_configure_sgi(d, true);
+       }
+
+       return 0;
+}
+
+static int its_sgi_get_irqchip_state(struct irq_data *d,
+                                    enum irqchip_irq_state which, bool *val)
+{
+       struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+       void __iomem *base;
+       unsigned long flags;
+       u32 count = 1000000;    /* 1s! */
+       u32 status;
+       int cpu;
+
+       if (which != IRQCHIP_STATE_PENDING)
+               return -EINVAL;
+
+       /*
+        * Locking galore! We can race against two different events:
+        *
+        * - Concurent vPE affinity change: we must make sure it cannot
+        *   happen, or we'll talk to the wrong redistributor. This is
+        *   identical to what happens with vLPIs.
+        *
+        * - Concurrent VSGIPENDR access: As it involves accessing two
+        *   MMIO registers, this must be made atomic one way or another.
+        */
+       cpu = vpe_to_cpuid_lock(vpe, &flags);
+       raw_spin_lock(&gic_data_rdist_cpu(cpu)->rd_lock);
+       base = gic_data_rdist_cpu(cpu)->rd_base + SZ_128K;
+       writel_relaxed(vpe->vpe_id, base + GICR_VSGIR);
+       do {
+               status = readl_relaxed(base + GICR_VSGIPENDR);
+               if (!(status & GICR_VSGIPENDR_BUSY))
+                       goto out;
+
+               count--;
+               if (!count) {
+                       pr_err_ratelimited("Unable to get SGI status\n");
+                       goto out;
+               }
+               cpu_relax();
+               udelay(1);
+       } while (count);
+
+out:
+       raw_spin_unlock(&gic_data_rdist_cpu(cpu)->rd_lock);
+       vpe_to_cpuid_unlock(vpe, flags);
+
+       if (!count)
+               return -ENXIO;
+
+       *val = !!(status & (1 << d->hwirq));
+
+       return 0;
+}
+
+static int its_sgi_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
+{
+       struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+       struct its_cmd_info *info = vcpu_info;
+
+       switch (info->cmd_type) {
+       case PROP_UPDATE_VSGI:
+               vpe->sgi_config[d->hwirq].priority = info->priority;
+               vpe->sgi_config[d->hwirq].group = info->group;
+               its_configure_sgi(d, false);
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static struct irq_chip its_sgi_irq_chip = {
+       .name                   = "GICv4.1-sgi",
+       .irq_mask               = its_sgi_mask_irq,
+       .irq_unmask             = its_sgi_unmask_irq,
+       .irq_set_affinity       = its_sgi_set_affinity,
+       .irq_set_irqchip_state  = its_sgi_set_irqchip_state,
+       .irq_get_irqchip_state  = its_sgi_get_irqchip_state,
+       .irq_set_vcpu_affinity  = its_sgi_set_vcpu_affinity,
+};
+
+static int its_sgi_irq_domain_alloc(struct irq_domain *domain,
+                                   unsigned int virq, unsigned int nr_irqs,
+                                   void *args)
+{
+       struct its_vpe *vpe = args;
+       int i;
+
+       /* Yes, we do want 16 SGIs */
+       WARN_ON(nr_irqs != 16);
+
+       for (i = 0; i < 16; i++) {
+               vpe->sgi_config[i].priority = 0;
+               vpe->sgi_config[i].enabled = false;
+               vpe->sgi_config[i].group = false;
+
+               irq_domain_set_hwirq_and_chip(domain, virq + i, i,
+                                             &its_sgi_irq_chip, vpe);
+               irq_set_status_flags(virq + i, IRQ_DISABLE_UNLAZY);
+       }
+
+       return 0;
+}
+
+static void its_sgi_irq_domain_free(struct irq_domain *domain,
+                                   unsigned int virq,
+                                   unsigned int nr_irqs)
+{
+       /* Nothing to do */
+}
+
+static int its_sgi_irq_domain_activate(struct irq_domain *domain,
+                                      struct irq_data *d, bool reserve)
+{
+       /* Write out the initial SGI configuration */
+       its_configure_sgi(d, false);
+       return 0;
+}
+
+static void its_sgi_irq_domain_deactivate(struct irq_domain *domain,
+                                         struct irq_data *d)
+{
+       struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
+
+       /*
+        * The VSGI command is awkward:
+        *
+        * - To change the configuration, CLEAR must be set to false,
+        *   leaving the pending bit unchanged.
+        * - To clear the pending bit, CLEAR must be set to true, leaving
+        *   the configuration unchanged.
+        *
+        * You just can't do both at once, hence the two commands below.
+        */
+       vpe->sgi_config[d->hwirq].enabled = false;
+       its_configure_sgi(d, false);
+       its_configure_sgi(d, true);
+}
+
+static const struct irq_domain_ops its_sgi_domain_ops = {
+       .alloc          = its_sgi_irq_domain_alloc,
+       .free           = its_sgi_irq_domain_free,
+       .activate       = its_sgi_irq_domain_activate,
+       .deactivate     = its_sgi_irq_domain_deactivate,
+};
+
 static int its_vpe_id_alloc(void)
 {
        return ida_simple_get(&its_vpeid_ida, 0, ITS_MAX_VPEID, GFP_KERNEL);
@@ -3851,6 +4238,7 @@ static int its_vpe_init(struct its_vpe *vpe)
                return -ENOMEM;
        }
 
+       raw_spin_lock_init(&vpe->vpe_lock);
        vpe->vpe_id = vpe_id;
        vpe->vpt_page = vpt_page;
        if (gic_rdists->has_rvpeid)
@@ -3960,8 +4348,12 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain,
        struct its_vpe *vpe = irq_data_get_irq_chip_data(d);
        struct its_node *its;
 
-       /* If we use the list map, we issue VMAPP on demand... */
-       if (its_list_map)
+       /*
+        * If we use the list map, we issue VMAPP on demand... Unless
+        * we're on a GICv4.1 and we eagerly map the VPE on all ITSs
+        * so that VSGIs can work.
+        */
+       if (!gic_requires_eager_mapping())
                return 0;
 
        /* Map the VPE to the first possible CPU */
@@ -3987,10 +4379,10 @@ static void its_vpe_irq_domain_deactivate(struct irq_domain *domain,
        struct its_node *its;
 
        /*
-        * If we use the list map, we unmap the VPE once no VLPIs are
-        * associated with the VM.
+        * If we use the list map on GICv4.0, we unmap the VPE once no
+        * VLPIs are associated with the VM.
         */
-       if (its_list_map)
+       if (!gic_requires_eager_mapping())
                return;
 
        list_for_each_entry(its, &its_nodes, entry) {
@@ -4404,7 +4796,7 @@ static int __init its_probe_one(struct resource *res,
        struct page *page;
        int err;
 
-       its_base = ioremap(res->start, resource_size(res));
+       its_base = ioremap(res->start, SZ_64K);
        if (!its_base) {
                pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
                return -ENOMEM;
@@ -4455,6 +4847,13 @@ static int __init its_probe_one(struct resource *res,
 
                if (is_v4_1(its)) {
                        u32 svpet = FIELD_GET(GITS_TYPER_SVPET, typer);
+
+                       its->sgir_base = ioremap(res->start + SZ_128K, SZ_64K);
+                       if (!its->sgir_base) {
+                               err = -ENOMEM;
+                               goto out_free_its;
+                       }
+
                        its->mpidr = readl_relaxed(its_base + GITS_MPIDR);
 
                        pr_info("ITS@%pa: Using GICv4.1 mode %08x %08x\n",
@@ -4468,7 +4867,7 @@ static int __init its_probe_one(struct resource *res,
                                get_order(ITS_CMD_QUEUE_SZ));
        if (!page) {
                err = -ENOMEM;
-               goto out_free_its;
+               goto out_unmap_sgir;
        }
        its->cmd_base = (void *)page_address(page);
        its->cmd_write = its->cmd_base;
@@ -4535,6 +4934,9 @@ out_free_tables:
        its_free_tables(its);
 out_free_cmd:
        free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ));
+out_unmap_sgir:
+       if (its->sgir_base)
+               iounmap(its->sgir_base);
 out_free_its:
        kfree(its);
 out_unmap:
@@ -4818,6 +5220,7 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
        struct device_node *of_node;
        struct its_node *its;
        bool has_v4 = false;
+       bool has_v4_1 = false;
        int err;
 
        gic_rdists = rdists;
@@ -4838,12 +5241,25 @@ int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
        if (err)
                return err;
 
-       list_for_each_entry(its, &its_nodes, entry)
+       list_for_each_entry(its, &its_nodes, entry) {
                has_v4 |= is_v4(its);
+               has_v4_1 |= is_v4_1(its);
+       }
+
+       /* Don't bother with inconsistent systems */
+       if (WARN_ON(!has_v4_1 && rdists->has_rvpeid))
+               rdists->has_rvpeid = false;
 
        if (has_v4 & rdists->has_vlpis) {
+               const struct irq_domain_ops *sgi_ops;
+
+               if (has_v4_1)
+                       sgi_ops = &its_sgi_domain_ops;
+               else
+                       sgi_ops = NULL;
+
                if (its_init_vpe_domain() ||
-                   its_init_v4(parent_domain, &its_vpe_domain_ops)) {
+                   its_init_v4(parent_domain, &its_vpe_domain_ops, sgi_ops)) {
                        rdists->has_vlpis = false;
                        pr_err("ITS: Disabling GICv4 support\n");
                }
index c1f7af9..9dbc81b 100644 (file)
@@ -34,6 +34,7 @@
 #define GICD_INT_NMI_PRI       (GICD_INT_DEF_PRI & ~0x80)
 
 #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996    (1ULL << 0)
+#define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539  (1ULL << 1)
 
 struct redist_region {
        void __iomem            *redist_base;
@@ -723,6 +724,7 @@ static void __init gic_dist_init(void)
        unsigned int i;
        u64 affinity;
        void __iomem *base = gic_data.dist_base;
+       u32 val;
 
        /* Disable the distributor */
        writel_relaxed(0, base + GICD_CTLR);
@@ -755,9 +757,14 @@ static void __init gic_dist_init(void)
        /* Now do the common stuff, and wait for the distributor to drain */
        gic_dist_config(base, GIC_LINE_NR, gic_dist_wait_for_rwp);
 
+       val = GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1;
+       if (gic_data.rdists.gicd_typer2 & GICD_TYPER2_nASSGIcap) {
+               pr_info("Enabling SGIs without active state\n");
+               val |= GICD_CTLR_nASSGIreq;
+       }
+
        /* Enable distributor with ARE, Group1 */
-       writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
-                      base + GICD_CTLR);
+       writel_relaxed(val, base + GICD_CTLR);
 
        /*
         * Set all global interrupts to the boot CPU only. ARE must be
@@ -828,6 +835,7 @@ static int __gic_populate_rdist(struct redist_region *region, void __iomem *ptr)
        typer = gic_read_typer(ptr + GICR_TYPER);
        if ((typer >> 32) == aff) {
                u64 offset = ptr - region->redist_base;
+               raw_spin_lock_init(&gic_data_rdist()->rd_lock);
                gic_data_rdist_rd_base() = ptr;
                gic_data_rdist()->phys_base = region->phys_base + offset;
 
@@ -1464,6 +1472,15 @@ static bool gic_enable_quirk_msm8996(void *data)
        return true;
 }
 
+static bool gic_enable_quirk_cavium_38539(void *data)
+{
+       struct gic_chip_data *d = data;
+
+       d->flags |= FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539;
+
+       return true;
+}
+
 static bool gic_enable_quirk_hip06_07(void *data)
 {
        struct gic_chip_data *d = data;
@@ -1503,6 +1520,19 @@ static const struct gic_quirk gic_quirks[] = {
                .init   = gic_enable_quirk_hip06_07,
        },
        {
+               /*
+                * Reserved register accesses generate a Synchronous
+                * External Abort. This erratum applies to:
+                * - ThunderX: CN88xx
+                * - OCTEON TX: CN83xx, CN81xx
+                * - OCTEON TX2: CN93xx, CN96xx, CN98xx, CNF95xx*
+                */
+               .desc   = "GICv3: Cavium erratum 38539",
+               .iidr   = 0xa000034c,
+               .mask   = 0xe8f00fff,
+               .init   = gic_enable_quirk_cavium_38539,
+       },
+       {
        }
 };
 
@@ -1577,11 +1607,15 @@ static int __init gic_init_bases(void __iomem *dist_base,
        pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);
        pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);
 
-       gic_data.rdists.gicd_typer2 = readl_relaxed(gic_data.dist_base + GICD_TYPER2);
+       /*
+        * ThunderX1 explodes on reading GICD_TYPER2, in violation of the
+        * architecture spec (which says that reserved registers are RES0).
+        */
+       if (!(gic_data.flags & FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539))
+               gic_data.rdists.gicd_typer2 = readl_relaxed(gic_data.dist_base + GICD_TYPER2);
 
        gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
                                                 &gic_data);
-       irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);
        gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
        gic_data.rdists.has_rvpeid = true;
        gic_data.rdists.has_vlpis = true;
@@ -1592,6 +1626,8 @@ static int __init gic_init_bases(void __iomem *dist_base,
                goto out_free;
        }
 
+       irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);
+
        gic_data.has_rss = !!(typer & GICD_TYPER_RSS);
        pr_info("Distributor has %sRange Selector support\n",
                gic_data.has_rss ? "" : "no ");
@@ -1757,6 +1793,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
                gic_v3_kvm_info.vcpu = r;
 
        gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
+       gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
        gic_set_kvm_info(&gic_v3_kvm_info);
 }
 
@@ -2072,6 +2109,7 @@ static void __init gic_acpi_setup_kvm_info(void)
        }
 
        gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis;
+       gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid;
        gic_set_kvm_info(&gic_v3_kvm_info);
 }
 
index 4596992..0c18714 100644 (file)
 
 static struct irq_domain *gic_domain;
 static const struct irq_domain_ops *vpe_domain_ops;
+static const struct irq_domain_ops *sgi_domain_ops;
+
+static bool has_v4_1(void)
+{
+       return !!sgi_domain_ops;
+}
+
+static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
+{
+       char *name;
+       int sgi_base;
+
+       if (!has_v4_1())
+               return 0;
+
+       name = kasprintf(GFP_KERNEL, "GICv4-sgi-%d", task_pid_nr(current));
+       if (!name)
+               goto err;
+
+       vpe->fwnode = irq_domain_alloc_named_id_fwnode(name, idx);
+       if (!vpe->fwnode)
+               goto err;
+
+       kfree(name);
+       name = NULL;
+
+       vpe->sgi_domain = irq_domain_create_linear(vpe->fwnode, 16,
+                                                  sgi_domain_ops, vpe);
+       if (!vpe->sgi_domain)
+               goto err;
+
+       sgi_base = __irq_domain_alloc_irqs(vpe->sgi_domain, -1, 16,
+                                              NUMA_NO_NODE, vpe,
+                                              false, NULL);
+       if (sgi_base <= 0)
+               goto err;
+
+       return 0;
+
+err:
+       if (vpe->sgi_domain)
+               irq_domain_remove(vpe->sgi_domain);
+       if (vpe->fwnode)
+               irq_domain_free_fwnode(vpe->fwnode);
+       kfree(name);
+       return -ENOMEM;
+}
 
 int its_alloc_vcpu_irqs(struct its_vm *vm)
 {
@@ -112,8 +159,13 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
        if (vpe_base_irq <= 0)
                goto err;
 
-       for (i = 0; i < vm->nr_vpes; i++)
+       for (i = 0; i < vm->nr_vpes; i++) {
+               int ret;
                vm->vpes[i]->irq = vpe_base_irq + i;
+               ret = its_alloc_vcpu_sgis(vm->vpes[i], i);
+               if (ret)
+                       goto err;
+       }
 
        return 0;
 
@@ -126,8 +178,28 @@ err:
        return -ENOMEM;
 }
 
+static void its_free_sgi_irqs(struct its_vm *vm)
+{
+       int i;
+
+       if (!has_v4_1())
+               return;
+
+       for (i = 0; i < vm->nr_vpes; i++) {
+               unsigned int irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0);
+
+               if (WARN_ON(!irq))
+                       continue;
+
+               irq_domain_free_irqs(irq, 16);
+               irq_domain_remove(vm->vpes[i]->sgi_domain);
+               irq_domain_free_fwnode(vm->vpes[i]->fwnode);
+       }
+}
+
 void its_free_vcpu_irqs(struct its_vm *vm)
 {
+       its_free_sgi_irqs(vm);
        irq_domain_free_irqs(vm->vpes[0]->irq, vm->nr_vpes);
        irq_domain_remove(vm->domain);
        irq_domain_free_fwnode(vm->fwnode);
@@ -138,18 +210,50 @@ static int its_send_vpe_cmd(struct its_vpe *vpe, struct its_cmd_info *info)
        return irq_set_vcpu_affinity(vpe->irq, info);
 }
 
-int its_schedule_vpe(struct its_vpe *vpe, bool on)
+int its_make_vpe_non_resident(struct its_vpe *vpe, bool db)
+{
+       struct irq_desc *desc = irq_to_desc(vpe->irq);
+       struct its_cmd_info info = { };
+       int ret;
+
+       WARN_ON(preemptible());
+
+       info.cmd_type = DESCHEDULE_VPE;
+       if (has_v4_1()) {
+               /* GICv4.1 can directly deal with doorbells */
+               info.req_db = db;
+       } else {
+               /* Undo the nested disable_irq() calls... */
+               while (db && irqd_irq_disabled(&desc->irq_data))
+                       enable_irq(vpe->irq);
+       }
+
+       ret = its_send_vpe_cmd(vpe, &info);
+       if (!ret)
+               vpe->resident = false;
+
+       return ret;
+}
+
+int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en)
 {
-       struct its_cmd_info info;
+       struct its_cmd_info info = { };
        int ret;
 
        WARN_ON(preemptible());
 
-       info.cmd_type = on ? SCHEDULE_VPE : DESCHEDULE_VPE;
+       info.cmd_type = SCHEDULE_VPE;
+       if (has_v4_1()) {
+               info.g0en = g0en;
+               info.g1en = g1en;
+       } else {
+               /* Disabled the doorbell, as we're about to enter the guest */
+               disable_irq_nosync(vpe->irq);
+       }
 
        ret = its_send_vpe_cmd(vpe, &info);
        if (!ret)
-               vpe->resident = on;
+               vpe->resident = true;
 
        return ret;
 }
@@ -216,12 +320,28 @@ int its_prop_update_vlpi(int irq, u8 config, bool inv)
        return irq_set_vcpu_affinity(irq, &info);
 }
 
-int its_init_v4(struct irq_domain *domain, const struct irq_domain_ops *ops)
+int its_prop_update_vsgi(int irq, u8 priority, bool group)
+{
+       struct its_cmd_info info = {
+               .cmd_type = PROP_UPDATE_VSGI,
+               {
+                       .priority       = priority,
+                       .group          = group,
+               },
+       };
+
+       return irq_set_vcpu_affinity(irq, &info);
+}
+
+int its_init_v4(struct irq_domain *domain,
+               const struct irq_domain_ops *vpe_ops,
+               const struct irq_domain_ops *sgi_ops)
 {
        if (domain) {
                pr_info("ITS: Enabling GICv4 support\n");
                gic_domain = domain;
-               vpe_domain_ops = ops;
+               vpe_domain_ops = vpe_ops;
+               sgi_domain_ops = sgi_ops;
                return 0;
        }
 
index d000870..b6f6aa7 100644 (file)
@@ -268,15 +268,6 @@ static void init_8259A(int auto_eoi)
        raw_spin_unlock_irqrestore(&i8259A_lock, flags);
 }
 
-/*
- * IRQ2 is cascade interrupt to second interrupt controller
- */
-static struct irqaction irq2 = {
-       .handler = no_action,
-       .name = "cascade",
-       .flags = IRQF_NO_THREAD,
-};
-
 static struct resource pic1_io_resource = {
        .name = "pic1",
        .start = PIC_MASTER_CMD,
@@ -311,6 +302,10 @@ static const struct irq_domain_ops i8259A_ops = {
  */
 struct irq_domain * __init __init_i8259_irqs(struct device_node *node)
 {
+       /*
+        * PIC_CASCADE_IR is cascade interrupt to second interrupt controller
+        */
+       int irq = I8259A_IRQ_BASE + PIC_CASCADE_IR;
        struct irq_domain *domain;
 
        insert_resource(&ioport_resource, &pic1_io_resource);
@@ -323,7 +318,8 @@ struct irq_domain * __init __init_i8259_irqs(struct device_node *node)
        if (!domain)
                panic("Failed to add i8259 IRQ domain");
 
-       setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
+       if (request_irq(irq, no_action, IRQF_NO_THREAD, "cascade", NULL))
+               pr_err("Failed to register cascade interrupt\n");
        register_syscore_ops(&i8259_syscore_ops);
        return domain;
 }
index 6d05cef..7a7222d 100644 (file)
@@ -180,3 +180,4 @@ err_free_tcu:
 IRQCHIP_DECLARE(jz4740_tcu_irq, "ingenic,jz4740-tcu", ingenic_tcu_irq_init);
 IRQCHIP_DECLARE(jz4725b_tcu_irq, "ingenic,jz4725b-tcu", ingenic_tcu_irq_init);
 IRQCHIP_DECLARE(jz4770_tcu_irq, "ingenic,jz4770-tcu", ingenic_tcu_irq_init);
+IRQCHIP_DECLARE(x1000_tcu_irq, "ingenic,x1000-tcu", ingenic_tcu_irq_init);
index c5589ee..9f3da42 100644 (file)
@@ -58,11 +58,6 @@ static irqreturn_t intc_cascade(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static struct irqaction intc_cascade_action = {
-       .handler = intc_cascade,
-       .name = "SoC intc cascade interrupt",
-};
-
 static int __init ingenic_intc_of_init(struct device_node *node,
                                       unsigned num_chips)
 {
@@ -130,7 +125,9 @@ static int __init ingenic_intc_of_init(struct device_node *node,
                irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK);
        }
 
-       setup_irq(parent_irq, &intc_cascade_action);
+       if (request_irq(parent_irq, intc_cascade, 0,
+                       "SoC intc cascade interrupt", NULL))
+               pr_err("Failed to register SoC intc cascade interrupt\n");
        return 0;
 
 out_domain_remove:
diff --git a/drivers/irqchip/irq-loongson-htpic.c b/drivers/irqchip/irq-loongson-htpic.c
new file mode 100644 (file)
index 0000000..dd018c2
--- /dev/null
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *  Loongson HTPIC IRQ support
+ */
+
+#include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/syscore_ops.h>
+
+#include <asm/i8259.h>
+
+#define HTPIC_MAX_PARENT_IRQ   4
+#define HTINT_NUM_VECTORS      8
+#define HTINT_EN_OFF           0x20
+
+struct loongson_htpic {
+       void __iomem *base;
+       struct irq_domain *domain;
+};
+
+static struct loongson_htpic *htpic;
+
+static void htpic_irq_dispatch(struct irq_desc *desc)
+{
+       struct loongson_htpic *priv = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       uint32_t pending;
+
+       chained_irq_enter(chip, desc);
+       pending = readl(priv->base);
+       /* Ack all IRQs at once, otherwise IRQ flood might happen */
+       writel(pending, priv->base);
+
+       if (!pending)
+               spurious_interrupt();
+
+       while (pending) {
+               int bit = __ffs(pending);
+
+               if (unlikely(bit > 15)) {
+                       spurious_interrupt();
+                       break;
+               }
+
+               generic_handle_irq(irq_linear_revmap(priv->domain, bit));
+               pending &= ~BIT(bit);
+       }
+       chained_irq_exit(chip, desc);
+}
+
+static void htpic_reg_init(void)
+{
+       int i;
+
+       for (i = 0; i < HTINT_NUM_VECTORS; i++) {
+               uint32_t val;
+
+               /* Disable all HT Vectors */
+               writel(0x0, htpic->base + HTINT_EN_OFF + i * 0x4);
+               val = readl(htpic->base + i * 0x4);
+               /* Ack all possible pending IRQs */
+               writel(GENMASK(31, 0), htpic->base + i * 0x4);
+       }
+
+       /* Enable 16 vectors for PIC */
+       writel(0xffff, htpic->base + HTINT_EN_OFF);
+}
+
+static void htpic_resume(void)
+{
+       htpic_reg_init();
+}
+
+struct syscore_ops htpic_syscore_ops = {
+       .resume         = htpic_resume,
+};
+
+int __init htpic_of_init(struct device_node *node, struct device_node *parent)
+{
+       unsigned int parent_irq[4];
+       int i, err;
+       int num_parents = 0;
+
+       if (htpic) {
+               pr_err("loongson-htpic: Only one HTPIC is allowed in the system\n");
+               return -ENODEV;
+       }
+
+       htpic = kzalloc(sizeof(*htpic), GFP_KERNEL);
+       if (!htpic) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+
+       htpic->base = of_iomap(node, 0);
+       if (!htpic->base) {
+               err = -ENODEV;
+               goto out_free;
+       }
+
+       htpic->domain = __init_i8259_irqs(node);
+       if (!htpic->domain) {
+               pr_err("loongson-htpic: Failed to initialize i8259 IRQs\n");
+               err = -ENOMEM;
+               goto out_iounmap;
+       }
+
+       /* Interrupt may come from any of the 4 interrupt line */
+       for (i = 0; i < HTPIC_MAX_PARENT_IRQ; i++) {
+               parent_irq[i] = irq_of_parse_and_map(node, i);
+               if (parent_irq[i] <= 0)
+                       break;
+
+               num_parents++;
+       }
+
+       if (!num_parents) {
+               pr_err("loongson-htpic: Failed to get parent irqs\n");
+               err = -ENODEV;
+               goto out_remove_domain;
+       }
+
+       htpic_reg_init();
+
+       for (i = 0; i < num_parents; i++) {
+               irq_set_chained_handler_and_data(parent_irq[i],
+                                               htpic_irq_dispatch, htpic);
+       }
+
+       register_syscore_ops(&htpic_syscore_ops);
+
+       return 0;
+
+out_remove_domain:
+       irq_domain_remove(htpic->domain);
+out_iounmap:
+       iounmap(htpic->base);
+out_free:
+       kfree(htpic);
+       return err;
+}
+
+IRQCHIP_DECLARE(loongson_htpic, "loongson,htpic-1.0", htpic_of_init);
diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c
new file mode 100644 (file)
index 0000000..63b6147
--- /dev/null
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *  Loongson Local IO Interrupt Controller support
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/irqchip.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+#include <linux/irqchip/chained_irq.h>
+
+#include <boot_param.h>
+
+#define LIOINTC_CHIP_IRQ       32
+#define LIOINTC_NUM_PARENT 4
+
+#define LIOINTC_INTC_CHIP_START        0x20
+
+#define LIOINTC_REG_INTC_STATUS        (LIOINTC_INTC_CHIP_START + 0x20)
+#define LIOINTC_REG_INTC_EN_STATUS     (LIOINTC_INTC_CHIP_START + 0x04)
+#define LIOINTC_REG_INTC_ENABLE        (LIOINTC_INTC_CHIP_START + 0x08)
+#define LIOINTC_REG_INTC_DISABLE       (LIOINTC_INTC_CHIP_START + 0x0c)
+#define LIOINTC_REG_INTC_POL   (LIOINTC_INTC_CHIP_START + 0x10)
+#define LIOINTC_REG_INTC_EDGE  (LIOINTC_INTC_CHIP_START + 0x14)
+
+#define LIOINTC_SHIFT_INTx     4
+
+#define LIOINTC_ERRATA_IRQ     10
+
+struct liointc_handler_data {
+       struct liointc_priv     *priv;
+       u32                     parent_int_map;
+};
+
+struct liointc_priv {
+       struct irq_chip_generic         *gc;
+       struct liointc_handler_data     handler[LIOINTC_NUM_PARENT];
+       u8                              map_cache[LIOINTC_CHIP_IRQ];
+       bool                            has_lpc_irq_errata;
+};
+
+static void liointc_chained_handle_irq(struct irq_desc *desc)
+{
+       struct liointc_handler_data *handler = irq_desc_get_handler_data(desc);
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct irq_chip_generic *gc = handler->priv->gc;
+       u32 pending;
+
+       chained_irq_enter(chip, desc);
+
+       pending = readl(gc->reg_base + LIOINTC_REG_INTC_STATUS);
+
+       if (!pending) {
+               /* Always blame LPC IRQ if we have that bug */
+               if (handler->priv->has_lpc_irq_errata &&
+                       (handler->parent_int_map & ~gc->mask_cache &
+                       BIT(LIOINTC_ERRATA_IRQ)))
+                       pending = BIT(LIOINTC_ERRATA_IRQ);
+               else
+                       spurious_interrupt();
+       }
+
+       while (pending) {
+               int bit = __ffs(pending);
+
+               generic_handle_irq(irq_find_mapping(gc->domain, bit));
+               pending &= ~BIT(bit);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static void liointc_set_bit(struct irq_chip_generic *gc,
+                               unsigned int offset,
+                               u32 mask, bool set)
+{
+       if (set)
+               writel(readl(gc->reg_base + offset) | mask,
+                               gc->reg_base + offset);
+       else
+               writel(readl(gc->reg_base + offset) & ~mask,
+                               gc->reg_base + offset);
+}
+
+static int liointc_set_type(struct irq_data *data, unsigned int type)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
+       u32 mask = data->mask;
+       unsigned long flags;
+
+       irq_gc_lock_irqsave(gc, flags);
+       switch (type) {
+       case IRQ_TYPE_LEVEL_HIGH:
+               liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false);
+               liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false);
+               liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false);
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true);
+               liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true);
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true);
+               liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false);
+               break;
+       default:
+               return -EINVAL;
+       }
+       irq_gc_unlock_irqrestore(gc, flags);
+
+       irqd_set_trigger_type(data, type);
+       return 0;
+}
+
+static void liointc_resume(struct irq_chip_generic *gc)
+{
+       struct liointc_priv *priv = gc->private;
+       unsigned long flags;
+       int i;
+
+       irq_gc_lock_irqsave(gc, flags);
+       /* Disable all at first */
+       writel(0xffffffff, gc->reg_base + LIOINTC_REG_INTC_DISABLE);
+       /* Revert map cache */
+       for (i = 0; i < LIOINTC_CHIP_IRQ; i++)
+               writeb(priv->map_cache[i], gc->reg_base + i);
+       /* Revert mask cache */
+       writel(~gc->mask_cache, gc->reg_base + LIOINTC_REG_INTC_ENABLE);
+       irq_gc_unlock_irqrestore(gc, flags);
+}
+
+static const char * const parent_names[] = {"int0", "int1", "int2", "int3"};
+
+int __init liointc_of_init(struct device_node *node,
+                               struct device_node *parent)
+{
+       struct irq_chip_generic *gc;
+       struct irq_domain *domain;
+       struct irq_chip_type *ct;
+       struct liointc_priv *priv;
+       void __iomem *base;
+       u32 of_parent_int_map[LIOINTC_NUM_PARENT];
+       int parent_irq[LIOINTC_NUM_PARENT];
+       bool have_parent = FALSE;
+       int sz, i, err = 0;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       base = of_iomap(node, 0);
+       if (!base) {
+               err = -ENODEV;
+               goto out_free_priv;
+       }
+
+       for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
+               parent_irq[i] = of_irq_get_byname(node, parent_names[i]);
+               if (parent_irq[i] > 0)
+                       have_parent = TRUE;
+       }
+       if (!have_parent) {
+               err = -ENODEV;
+               goto out_iounmap;
+       }
+
+       sz = of_property_read_variable_u32_array(node,
+                                               "loongson,parent_int_map",
+                                               &of_parent_int_map[0],
+                                               LIOINTC_NUM_PARENT,
+                                               LIOINTC_NUM_PARENT);
+       if (sz < 4) {
+               pr_err("loongson-liointc: No parent_int_map\n");
+               err = -ENODEV;
+               goto out_iounmap;
+       }
+
+       for (i = 0; i < LIOINTC_NUM_PARENT; i++)
+               priv->handler[i].parent_int_map = of_parent_int_map[i];
+
+       /* Setup IRQ domain */
+       domain = irq_domain_add_linear(node, 32,
+                                       &irq_generic_chip_ops, priv);
+       if (!domain) {
+               pr_err("loongson-liointc: cannot add IRQ domain\n");
+               err = -EINVAL;
+               goto out_iounmap;
+       }
+
+       err = irq_alloc_domain_generic_chips(domain, 32, 1,
+                                       node->full_name, handle_level_irq,
+                                       IRQ_NOPROBE, 0, 0);
+       if (err) {
+               pr_err("loongson-liointc: unable to register IRQ domain\n");
+               goto out_free_domain;
+       }
+
+
+       /* Disable all IRQs */
+       writel(0xffffffff, base + LIOINTC_REG_INTC_DISABLE);
+       /* Set to level triggered */
+       writel(0x0, base + LIOINTC_REG_INTC_EDGE);
+
+       /* Generate parent INT part of map cache */
+       for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
+               u32 pending = priv->handler[i].parent_int_map;
+
+               while (pending) {
+                       int bit = __ffs(pending);
+
+                       priv->map_cache[bit] = BIT(i) << LIOINTC_SHIFT_INTx;
+                       pending &= ~BIT(bit);
+               }
+       }
+
+       for (i = 0; i < LIOINTC_CHIP_IRQ; i++) {
+               /* Generate core part of map cache */
+               priv->map_cache[i] |= BIT(loongson_sysconf.boot_cpu_id);
+               writeb(priv->map_cache[i], base + i);
+       }
+
+       gc = irq_get_domain_generic_chip(domain, 0);
+       gc->private = priv;
+       gc->reg_base = base;
+       gc->domain = domain;
+       gc->resume = liointc_resume;
+
+       ct = gc->chip_types;
+       ct->regs.enable = LIOINTC_REG_INTC_ENABLE;
+       ct->regs.disable = LIOINTC_REG_INTC_DISABLE;
+       ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+       ct->chip.irq_mask = irq_gc_mask_disable_reg;
+       ct->chip.irq_mask_ack = irq_gc_mask_disable_reg;
+       ct->chip.irq_set_type = liointc_set_type;
+
+       gc->mask_cache = 0xffffffff;
+       priv->gc = gc;
+
+       for (i = 0; i < LIOINTC_NUM_PARENT; i++) {
+               if (parent_irq[i] <= 0)
+                       continue;
+
+               priv->handler[i].priv = priv;
+               irq_set_chained_handler_and_data(parent_irq[i],
+                               liointc_chained_handle_irq, &priv->handler[i]);
+       }
+
+       return 0;
+
+out_free_domain:
+       irq_domain_remove(domain);
+out_iounmap:
+       iounmap(base);
+out_free_priv:
+       kfree(priv);
+
+       return err;
+}
+
+IRQCHIP_DECLARE(loongson_liointc_1_0, "loongson,liointc-1.0", liointc_of_init);
+IRQCHIP_DECLARE(loongson_liointc_1_0a, "loongson,liointc-1.0a", liointc_of_init);
index 6e5e317..3819185 100644 (file)
@@ -461,7 +461,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
                }
 
                i->iomem = devm_ioremap(dev, io[k]->start,
-                                               resource_size(io[k]));
+                                       resource_size(io[k]));
                if (!i->iomem) {
                        dev_err(dev, "failed to remap IOMEM\n");
                        ret = -ENXIO;
index aa4af88..c34fb3a 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2018 Christoph Hellwig
  */
 #define pr_fmt(fmt) "plic: " fmt
+#include <linux/cpu.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #define     CONTEXT_THRESHOLD          0x00
 #define     CONTEXT_CLAIM              0x04
 
-static void __iomem *plic_regs;
+#define        PLIC_DISABLE_THRESHOLD          0xf
+#define        PLIC_ENABLE_THRESHOLD           0
+
+struct plic_priv {
+       struct cpumask lmask;
+       struct irq_domain *irqdomain;
+       void __iomem *regs;
+};
 
 struct plic_handler {
        bool                    present;
@@ -66,6 +74,7 @@ struct plic_handler {
         */
        raw_spinlock_t          enable_lock;
        void __iomem            *enable_base;
+       struct plic_priv        *priv;
 };
 static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
 
@@ -84,31 +93,40 @@ static inline void plic_toggle(struct plic_handler *handler,
 }
 
 static inline void plic_irq_toggle(const struct cpumask *mask,
-                                  int hwirq, int enable)
+                                  struct irq_data *d, int enable)
 {
        int cpu;
+       struct plic_priv *priv = irq_get_chip_data(d->irq);
 
-       writel(enable, plic_regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
+       writel(enable, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
        for_each_cpu(cpu, mask) {
                struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
 
-               if (handler->present)
-                       plic_toggle(handler, hwirq, enable);
+               if (handler->present &&
+                   cpumask_test_cpu(cpu, &handler->priv->lmask))
+                       plic_toggle(handler, d->hwirq, enable);
        }
 }
 
 static void plic_irq_unmask(struct irq_data *d)
 {
-       unsigned int cpu = cpumask_any_and(irq_data_get_affinity_mask(d),
-                                          cpu_online_mask);
+       struct cpumask amask;
+       unsigned int cpu;
+       struct plic_priv *priv = irq_get_chip_data(d->irq);
+
+       cpumask_and(&amask, &priv->lmask, cpu_online_mask);
+       cpu = cpumask_any_and(irq_data_get_affinity_mask(d),
+                                          &amask);
        if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
                return;
-       plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1);
+       plic_irq_toggle(cpumask_of(cpu), d, 1);
 }
 
 static void plic_irq_mask(struct irq_data *d)
 {
-       plic_irq_toggle(cpu_possible_mask, d->hwirq, 0);
+       struct plic_priv *priv = irq_get_chip_data(d->irq);
+
+       plic_irq_toggle(&priv->lmask, d, 0);
 }
 
 #ifdef CONFIG_SMP
@@ -116,17 +134,21 @@ static int plic_set_affinity(struct irq_data *d,
                             const struct cpumask *mask_val, bool force)
 {
        unsigned int cpu;
+       struct cpumask amask;
+       struct plic_priv *priv = irq_get_chip_data(d->irq);
+
+       cpumask_and(&amask, &priv->lmask, mask_val);
 
        if (force)
-               cpu = cpumask_first(mask_val);
+               cpu = cpumask_first(&amask);
        else
-               cpu = cpumask_any_and(mask_val, cpu_online_mask);
+               cpu = cpumask_any_and(&amask, cpu_online_mask);
 
        if (cpu >= nr_cpu_ids)
                return -EINVAL;
 
-       plic_irq_toggle(cpu_possible_mask, d->hwirq, 0);
-       plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1);
+       plic_irq_toggle(&priv->lmask, d, 0);
+       plic_irq_toggle(cpumask_of(cpu), d, 1);
 
        irq_data_update_effective_affinity(d, cpumask_of(cpu));
 
@@ -187,8 +209,6 @@ static const struct irq_domain_ops plic_irqdomain_ops = {
        .free           = irq_domain_free_irqs_top,
 };
 
-static struct irq_domain *plic_irqdomain;
-
 /*
  * Handling an interrupt is a two-step process: first you claim the interrupt
  * by reading the claim register, then you complete the interrupt by writing
@@ -205,7 +225,7 @@ static void plic_handle_irq(struct pt_regs *regs)
 
        csr_clear(CSR_IE, IE_EIE);
        while ((hwirq = readl(claim))) {
-               int irq = irq_find_mapping(plic_irqdomain, hwirq);
+               int irq = irq_find_mapping(handler->priv->irqdomain, hwirq);
 
                if (unlikely(irq <= 0))
                        pr_warn_ratelimited("can't find mapping for hwirq %lu\n",
@@ -230,20 +250,48 @@ static int plic_find_hart_id(struct device_node *node)
        return -1;
 }
 
+static void plic_set_threshold(struct plic_handler *handler, u32 threshold)
+{
+       /* priority must be > threshold to trigger an interrupt */
+       writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
+}
+
+static int plic_dying_cpu(unsigned int cpu)
+{
+       struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
+
+       csr_clear(CSR_IE, IE_EIE);
+       plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD);
+
+       return 0;
+}
+
+static int plic_starting_cpu(unsigned int cpu)
+{
+       struct plic_handler *handler = this_cpu_ptr(&plic_handlers);
+
+       csr_set(CSR_IE, IE_EIE);
+       plic_set_threshold(handler, PLIC_ENABLE_THRESHOLD);
+
+       return 0;
+}
+
 static int __init plic_init(struct device_node *node,
                struct device_node *parent)
 {
        int error = 0, nr_contexts, nr_handlers = 0, i;
        u32 nr_irqs;
+       struct plic_priv *priv;
 
-       if (plic_regs) {
-               pr_warn("PLIC already present.\n");
-               return -ENXIO;
-       }
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
 
-       plic_regs = of_iomap(node, 0);
-       if (WARN_ON(!plic_regs))
-               return -EIO;
+       priv->regs = of_iomap(node, 0);
+       if (WARN_ON(!priv->regs)) {
+               error = -EIO;
+               goto out_free_priv;
+       }
 
        error = -EINVAL;
        of_property_read_u32(node, "riscv,ndev", &nr_irqs);
@@ -257,9 +305,9 @@ static int __init plic_init(struct device_node *node,
                goto out_iounmap;
 
        error = -ENOMEM;
-       plic_irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
-                       &plic_irqdomain_ops, NULL);
-       if (WARN_ON(!plic_irqdomain))
+       priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
+                       &plic_irqdomain_ops, priv);
+       if (WARN_ON(!priv->irqdomain))
                goto out_iounmap;
 
        for (i = 0; i < nr_contexts; i++) {
@@ -267,7 +315,6 @@ static int __init plic_init(struct device_node *node,
                struct plic_handler *handler;
                irq_hw_number_t hwirq;
                int cpu, hartid;
-               u32 threshold = 0;
 
                if (of_irq_parse_one(node, i, &parent)) {
                        pr_err("failed to parse parent for context %d.\n", i);
@@ -301,32 +348,36 @@ static int __init plic_init(struct device_node *node,
                handler = per_cpu_ptr(&plic_handlers, cpu);
                if (handler->present) {
                        pr_warn("handler already present for context %d.\n", i);
-                       threshold = 0xffffffff;
+                       plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD);
                        goto done;
                }
 
+               cpumask_set_cpu(cpu, &priv->lmask);
                handler->present = true;
                handler->hart_base =
-                       plic_regs + CONTEXT_BASE + i * CONTEXT_PER_HART;
+                       priv->regs + CONTEXT_BASE + i * CONTEXT_PER_HART;
                raw_spin_lock_init(&handler->enable_lock);
                handler->enable_base =
-                       plic_regs + ENABLE_BASE + i * ENABLE_PER_HART;
-
+                       priv->regs + ENABLE_BASE + i * ENABLE_PER_HART;
+               handler->priv = priv;
 done:
-               /* priority must be > threshold to trigger an interrupt */
-               writel(threshold, handler->hart_base + CONTEXT_THRESHOLD);
                for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
                        plic_toggle(handler, hwirq, 0);
                nr_handlers++;
        }
 
+       cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
+                                 "irqchip/sifive/plic:starting",
+                                 plic_starting_cpu, plic_dying_cpu);
        pr_info("mapped %d interrupts with %d handlers for %d contexts.\n",
                nr_irqs, nr_handlers, nr_contexts);
        set_handle_irq(plic_handle_irq);
        return 0;
 
 out_iounmap:
-       iounmap(plic_regs);
+       iounmap(priv->regs);
+out_free_priv:
+       kfree(priv);
        return error;
 }
 
index e00f2fa..faa8482 100644 (file)
@@ -604,12 +604,24 @@ static void stm32_exti_h_syscore_deinit(void)
        unregister_syscore_ops(&stm32_exti_h_syscore_ops);
 }
 
+static int stm32_exti_h_retrigger(struct irq_data *d)
+{
+       struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
+       const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
+       void __iomem *base = chip_data->host_data->base;
+       u32 mask = BIT(d->hwirq % IRQS_PER_BANK);
+
+       writel_relaxed(mask, base + stm32_bank->swier_ofst);
+
+       return 0;
+}
+
 static struct irq_chip stm32_exti_h_chip = {
        .name                   = "stm32-exti-h",
        .irq_eoi                = stm32_exti_h_eoi,
        .irq_mask               = stm32_exti_h_mask,
        .irq_unmask             = stm32_exti_h_unmask,
-       .irq_retrigger          = irq_chip_retrigger_hierarchy,
+       .irq_retrigger          = stm32_exti_h_retrigger,
        .irq_set_type           = stm32_exti_h_set_type,
        .irq_set_wake           = stm32_exti_h_set_wake,
        .flags                  = IRQCHIP_MASK_ON_SUSPEND,
index 928858d..f138673 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/versatile-fpga.h>
 #include <linux/irqdomain.h>
 #include <linux/module.h>
@@ -68,12 +69,16 @@ static void fpga_irq_unmask(struct irq_data *d)
 
 static void fpga_irq_handle(struct irq_desc *desc)
 {
+       struct irq_chip *chip = irq_desc_get_chip(desc);
        struct fpga_irq_data *f = irq_desc_get_handler_data(desc);
-       u32 status = readl(f->base + IRQ_STATUS);
+       u32 status;
+
+       chained_irq_enter(chip, desc);
 
+       status = readl(f->base + IRQ_STATUS);
        if (status == 0) {
                do_bad_IRQ(desc);
-               return;
+               goto out;
        }
 
        do {
@@ -82,6 +87,9 @@ static void fpga_irq_handle(struct irq_desc *desc)
                status &= ~(1 << irq);
                generic_handle_irq(irq_find_mapping(f->domain, irq));
        } while (status);
+
+out:
+       chained_irq_exit(chip, desc);
 }
 
 /*
@@ -204,6 +212,9 @@ int __init fpga_irq_of_init(struct device_node *node,
        if (of_property_read_u32(node, "valid-mask", &valid_mask))
                valid_mask = 0;
 
+       writel(clear_mask, base + IRQ_ENABLE_CLEAR);
+       writel(clear_mask, base + FIQ_ENABLE_CLEAR);
+
        /* Some chips are cascaded from a parent IRQ */
        parent_irq = irq_of_parse_and_map(node, 0);
        if (!parent_irq) {
@@ -213,9 +224,6 @@ int __init fpga_irq_of_init(struct device_node *node,
 
        fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node);
 
-       writel(clear_mask, base + IRQ_ENABLE_CLEAR);
-       writel(clear_mask, base + FIQ_ENABLE_CLEAR);
-
        /*
         * On Versatile AB/PB, some secondary interrupts have a direct
         * pass-thru to the primary controller for IRQs 20 and 22-31 which need
index f3f20a3..3c87d92 100644 (file)
@@ -509,9 +509,7 @@ static int __init vic_of_init(struct device_node *node,
        void __iomem *regs;
        u32 interrupt_mask = ~0;
        u32 wakeup_mask = ~0;
-
-       if (WARN(parent, "non-root VICs are not supported"))
-               return -EINVAL;
+       int parent_irq;
 
        regs = of_iomap(node, 0);
        if (WARN_ON(!regs))
@@ -519,11 +517,14 @@ static int __init vic_of_init(struct device_node *node,
 
        of_property_read_u32(node, "valid-mask", &interrupt_mask);
        of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask);
+       parent_irq = of_irq_get(node, 0);
+       if (parent_irq < 0)
+               parent_irq = 0;
 
        /*
         * Passing 0 as first IRQ makes the simple domain allocate descriptors
         */
-       __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node);
+       __vic_init(regs, parent_irq, 0, interrupt_mask, wakeup_mask, node);
 
        return 0;
 }
index e3043de..7f811fe 100644 (file)
@@ -38,29 +38,31 @@ struct xintc_irq_chip {
        void            __iomem *base;
        struct          irq_domain *root_domain;
        u32             intr_mask;
+       u32             nr_irq;
 };
 
-static struct xintc_irq_chip *xintc_irqc;
+static struct xintc_irq_chip *primary_intc;
 
-static void xintc_write(int reg, u32 data)
+static void xintc_write(struct xintc_irq_chip *irqc, int reg, u32 data)
 {
        if (static_branch_unlikely(&xintc_is_be))
-               iowrite32be(data, xintc_irqc->base + reg);
+               iowrite32be(data, irqc->base + reg);
        else
-               iowrite32(data, xintc_irqc->base + reg);
+               iowrite32(data, irqc->base + reg);
 }
 
-static unsigned int xintc_read(int reg)
+static u32 xintc_read(struct xintc_irq_chip *irqc, int reg)
 {
        if (static_branch_unlikely(&xintc_is_be))
-               return ioread32be(xintc_irqc->base + reg);
+               return ioread32be(irqc->base + reg);
        else
-               return ioread32(xintc_irqc->base + reg);
+               return ioread32(irqc->base + reg);
 }
 
 static void intc_enable_or_unmask(struct irq_data *d)
 {
-       unsigned long mask = 1 << d->hwirq;
+       struct xintc_irq_chip *irqc = irq_data_get_irq_chip_data(d);
+       unsigned long mask = BIT(d->hwirq);
 
        pr_debug("irq-xilinx: enable_or_unmask: %ld\n", d->hwirq);
 
@@ -69,30 +71,35 @@ static void intc_enable_or_unmask(struct irq_data *d)
         * acks the irq before calling the interrupt handler
         */
        if (irqd_is_level_type(d))
-               xintc_write(IAR, mask);
+               xintc_write(irqc, IAR, mask);
 
-       xintc_write(SIE, mask);
+       xintc_write(irqc, SIE, mask);
 }
 
 static void intc_disable_or_mask(struct irq_data *d)
 {
+       struct xintc_irq_chip *irqc = irq_data_get_irq_chip_data(d);
+
        pr_debug("irq-xilinx: disable: %ld\n", d->hwirq);
-       xintc_write(CIE, 1 << d->hwirq);
+       xintc_write(irqc, CIE, BIT(d->hwirq));
 }
 
 static void intc_ack(struct irq_data *d)
 {
+       struct xintc_irq_chip *irqc = irq_data_get_irq_chip_data(d);
+
        pr_debug("irq-xilinx: ack: %ld\n", d->hwirq);
-       xintc_write(IAR, 1 << d->hwirq);
+       xintc_write(irqc, IAR, BIT(d->hwirq));
 }
 
 static void intc_mask_ack(struct irq_data *d)
 {
-       unsigned long mask = 1 << d->hwirq;
+       struct xintc_irq_chip *irqc = irq_data_get_irq_chip_data(d);
+       unsigned long mask = BIT(d->hwirq);
 
        pr_debug("irq-xilinx: disable_and_ack: %ld\n", d->hwirq);
-       xintc_write(CIE, mask);
-       xintc_write(IAR, mask);
+       xintc_write(irqc, CIE, mask);
+       xintc_write(irqc, IAR, mask);
 }
 
 static struct irq_chip intc_dev = {
@@ -103,13 +110,14 @@ static struct irq_chip intc_dev = {
        .irq_mask_ack = intc_mask_ack,
 };
 
-unsigned int xintc_get_irq(void)
+static unsigned int xintc_get_irq_local(struct xintc_irq_chip *irqc)
 {
-       unsigned int hwirq, irq = -1;
+       unsigned int irq = 0;
+       u32 hwirq;
 
-       hwirq = xintc_read(IVR);
+       hwirq = xintc_read(irqc, IVR);
        if (hwirq != -1U)
-               irq = irq_find_mapping(xintc_irqc->root_domain, hwirq);
+               irq = irq_find_mapping(irqc->root_domain, hwirq);
 
        pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq);
 
@@ -118,15 +126,18 @@ unsigned int xintc_get_irq(void)
 
 static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
 {
-       if (xintc_irqc->intr_mask & (1 << hw)) {
+       struct xintc_irq_chip *irqc = d->host_data;
+
+       if (irqc->intr_mask & BIT(hw)) {
                irq_set_chip_and_handler_name(irq, &intc_dev,
-                                               handle_edge_irq, "edge");
+                                             handle_edge_irq, "edge");
                irq_clear_status_flags(irq, IRQ_LEVEL);
        } else {
                irq_set_chip_and_handler_name(irq, &intc_dev,
-                                               handle_level_irq, "level");
+                                             handle_level_irq, "level");
                irq_set_status_flags(irq, IRQ_LEVEL);
        }
+       irq_set_chip_data(irq, irqc);
        return 0;
 }
 
@@ -138,43 +149,55 @@ static const struct irq_domain_ops xintc_irq_domain_ops = {
 static void xil_intc_irq_handler(struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct xintc_irq_chip *irqc;
        u32 pending;
 
+       irqc = irq_data_get_irq_handler_data(&desc->irq_data);
        chained_irq_enter(chip, desc);
        do {
-               pending = xintc_get_irq();
-               if (pending == -1U)
+               pending = xintc_get_irq_local(irqc);
+               if (pending == 0)
                        break;
                generic_handle_irq(pending);
        } while (true);
        chained_irq_exit(chip, desc);
 }
 
+static void xil_intc_handle_irq(struct pt_regs *regs)
+{
+       u32 hwirq;
+       struct xintc_irq_chip *irqc = primary_intc;
+
+       do {
+               hwirq = xintc_read(irqc, IVR);
+               if (likely(hwirq != -1U)) {
+                       int ret;
+
+                       ret = handle_domain_irq(irqc->root_domain, hwirq, regs);
+                       WARN_ONCE(ret, "Unhandled HWIRQ %d\n", hwirq);
+                       continue;
+               }
+
+               break;
+       } while (1);
+}
+
 static int __init xilinx_intc_of_init(struct device_node *intc,
                                             struct device_node *parent)
 {
-       u32 nr_irq;
-       int ret, irq;
        struct xintc_irq_chip *irqc;
-
-       if (xintc_irqc) {
-               pr_err("irq-xilinx: Multiple instances aren't supported\n");
-               return -EINVAL;
-       }
+       int ret, irq;
 
        irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
        if (!irqc)
                return -ENOMEM;
-
-       xintc_irqc = irqc;
-
        irqc->base = of_iomap(intc, 0);
        BUG_ON(!irqc->base);
 
-       ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq);
+       ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &irqc->nr_irq);
        if (ret < 0) {
                pr_err("irq-xilinx: unable to read xlnx,num-intr-inputs\n");
-               goto err_alloc;
+               goto error;
        }
 
        ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &irqc->intr_mask);
@@ -183,34 +206,35 @@ static int __init xilinx_intc_of_init(struct device_node *intc,
                irqc->intr_mask = 0;
        }
 
-       if (irqc->intr_mask >> nr_irq)
+       if (irqc->intr_mask >> irqc->nr_irq)
                pr_warn("irq-xilinx: mismatch in kind-of-intr param\n");
 
        pr_info("irq-xilinx: %pOF: num_irq=%d, edge=0x%x\n",
-               intc, nr_irq, irqc->intr_mask);
+               intc, irqc->nr_irq, irqc->intr_mask);
 
 
        /*
         * Disable all external interrupts until they are
         * explicity requested.
         */
-       xintc_write(IER, 0);
+       xintc_write(irqc, IER, 0);
 
        /* Acknowledge any pending interrupts just in case. */
-       xintc_write(IAR, 0xffffffff);
+       xintc_write(irqc, IAR, 0xffffffff);
 
        /* Turn on the Master Enable. */
-       xintc_write(MER, MER_HIE | MER_ME);
-       if (!(xintc_read(MER) & (MER_HIE | MER_ME))) {
+       xintc_write(irqc, MER, MER_HIE | MER_ME);
+       if (xintc_read(irqc, MER) != (MER_HIE | MER_ME)) {
                static_branch_enable(&xintc_is_be);
-               xintc_write(MER, MER_HIE | MER_ME);
+               xintc_write(irqc, MER, MER_HIE | MER_ME);
        }
 
-       irqc->root_domain = irq_domain_add_linear(intc, nr_irq,
+       irqc->root_domain = irq_domain_add_linear(intc, irqc->nr_irq,
                                                  &xintc_irq_domain_ops, irqc);
        if (!irqc->root_domain) {
                pr_err("irq-xilinx: Unable to create IRQ domain\n");
-               goto err_alloc;
+               ret = -EINVAL;
+               goto error;
        }
 
        if (parent) {
@@ -222,16 +246,17 @@ static int __init xilinx_intc_of_init(struct device_node *intc,
                } else {
                        pr_err("irq-xilinx: interrupts property not in DT\n");
                        ret = -EINVAL;
-                       goto err_alloc;
+                       goto error;
                }
        } else {
-               irq_set_default_host(irqc->root_domain);
+               primary_intc = irqc;
+               set_handle_irq(xil_intc_handle_irq);
        }
 
        return 0;
 
-err_alloc:
-       xintc_irqc = NULL;
+error:
+       iounmap(irqc->base);
        kfree(irqc);
        return ret;
 
index abfe592..aa54bfc 100644 (file)
@@ -33,7 +33,7 @@ struct combiner {
        int                 parent_irq;
        u32                 nirqs;
        u32                 nregs;
-       struct combiner_reg regs[0];
+       struct combiner_reg regs[];
 };
 
 static inline int irq_nr(u32 reg, u32 bit)
index 7543e39..db38a68 100644 (file)
@@ -380,12 +380,11 @@ static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create)
                goto err_dev;
        }
 
-       tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node);
+       tqueue = blk_alloc_queue(tt->make_rq, dev->q->node);
        if (!tqueue) {
                ret = -ENOMEM;
                goto err_disk;
        }
-       blk_queue_make_request(tqueue, tt->make_rq);
 
        strlcpy(tdisk->disk_name, create->tgtname, sizeof(tdisk->disk_name));
        tdisk->flags = GENHD_FL_EXT_DEVT;
index 7d8958d..6387302 100644 (file)
@@ -37,7 +37,7 @@ static ssize_t pblk_sysfs_luns_show(struct pblk *pblk, char *page)
                        active = 0;
                        up(&rlun->wr_sem);
                }
-               sz += snprintf(page + sz, PAGE_SIZE - sz,
+               sz += scnprintf(page + sz, PAGE_SIZE - sz,
                                "pblk: pos:%d, ch:%d, lun:%d - %d\n",
                                        i,
                                        rlun->bppa.a.ch,
@@ -120,7 +120,7 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
                struct nvm_addrf_12 *ppaf = (struct nvm_addrf_12 *)&pblk->addrf;
                struct nvm_addrf_12 *gppaf = (struct nvm_addrf_12 *)&geo->addrf;
 
-               sz = snprintf(page, PAGE_SIZE,
+               sz = scnprintf(page, PAGE_SIZE,
                        "g:(b:%d)blk:%d/%d,pg:%d/%d,lun:%d/%d,ch:%d/%d,pl:%d/%d,sec:%d/%d\n",
                        pblk->addrf_len,
                        ppaf->blk_offset, ppaf->blk_len,
@@ -130,7 +130,7 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
                        ppaf->pln_offset, ppaf->pln_len,
                        ppaf->sec_offset, ppaf->sec_len);
 
-               sz += snprintf(page + sz, PAGE_SIZE - sz,
+               sz += scnprintf(page + sz, PAGE_SIZE - sz,
                        "d:blk:%d/%d,pg:%d/%d,lun:%d/%d,ch:%d/%d,pl:%d/%d,sec:%d/%d\n",
                        gppaf->blk_offset, gppaf->blk_len,
                        gppaf->pg_offset, gppaf->pg_len,
@@ -142,7 +142,7 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
                struct nvm_addrf *ppaf = &pblk->addrf;
                struct nvm_addrf *gppaf = &geo->addrf;
 
-               sz = snprintf(page, PAGE_SIZE,
+               sz = scnprintf(page, PAGE_SIZE,
                        "pblk:(s:%d)ch:%d/%d,lun:%d/%d,chk:%d/%d/sec:%d/%d\n",
                        pblk->addrf_len,
                        ppaf->ch_offset, ppaf->ch_len,
@@ -150,7 +150,7 @@ static ssize_t pblk_sysfs_ppaf(struct pblk *pblk, char *page)
                        ppaf->chk_offset, ppaf->chk_len,
                        ppaf->sec_offset, ppaf->sec_len);
 
-               sz += snprintf(page + sz, PAGE_SIZE - sz,
+               sz += scnprintf(page + sz, PAGE_SIZE - sz,
                        "device:ch:%d/%d,lun:%d/%d,chk:%d/%d,sec:%d/%d\n",
                        gppaf->ch_offset, gppaf->ch_len,
                        gppaf->lun_offset, gppaf->lun_len,
@@ -278,11 +278,11 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page)
                pblk_err(pblk, "corrupted free line list:%d/%d\n",
                                                nr_free_lines, free_line_cnt);
 
-       sz = snprintf(page, PAGE_SIZE - sz,
+       sz = scnprintf(page, PAGE_SIZE - sz,
                "line: nluns:%d, nblks:%d, nsecs:%d\n",
                geo->all_luns, lm->blk_per_line, lm->sec_per_line);
 
-       sz += snprintf(page + sz, PAGE_SIZE - sz,
+       sz += scnprintf(page + sz, PAGE_SIZE - sz,
                "lines:d:%d,l:%d-f:%d,m:%d/%d,c:%d,b:%d,co:%d(d:%d,l:%d)t:%d\n",
                                        cur_data, cur_log,
                                        nr_free_lines,
@@ -292,12 +292,12 @@ static ssize_t pblk_sysfs_lines(struct pblk *pblk, char *page)
                                        d_line_cnt, l_line_cnt,
                                        l_mg->nr_lines);
 
-       sz += snprintf(page + sz, PAGE_SIZE - sz,
+       sz += scnprintf(page + sz, PAGE_SIZE - sz,
                "GC: full:%d, high:%d, mid:%d, low:%d, empty:%d, werr: %d, queue:%d\n",
                        gc_full, gc_high, gc_mid, gc_low, gc_empty, gc_werr,
                        atomic_read(&pblk->gc.read_inflight_gc));
 
-       sz += snprintf(page + sz, PAGE_SIZE - sz,
+       sz += scnprintf(page + sz, PAGE_SIZE - sz,
                "data (%d) cur:%d, left:%d, vsc:%d, s:%d, map:%d/%d (%d)\n",
                        cur_data, cur_sec, msecs, vsc, sec_in_line,
                        map_weight, lm->sec_per_line,
@@ -313,19 +313,19 @@ static ssize_t pblk_sysfs_lines_info(struct pblk *pblk, char *page)
        struct pblk_line_meta *lm = &pblk->lm;
        ssize_t sz = 0;
 
-       sz = snprintf(page, PAGE_SIZE - sz,
+       sz = scnprintf(page, PAGE_SIZE - sz,
                                "smeta - len:%d, secs:%d\n",
                                        lm->smeta_len, lm->smeta_sec);
-       sz += snprintf(page + sz, PAGE_SIZE - sz,
+       sz += scnprintf(page + sz, PAGE_SIZE - sz,
                                "emeta - len:%d, sec:%d, bb_start:%d\n",
                                        lm->emeta_len[0], lm->emeta_sec[0],
                                        lm->emeta_bb);
-       sz += snprintf(page + sz, PAGE_SIZE - sz,
+       sz += scnprintf(page + sz, PAGE_SIZE - sz,
                                "bitmap lengths: sec:%d, blk:%d, lun:%d\n",
                                        lm->sec_bitmap_len,
                                        lm->blk_bitmap_len,
                                        lm->lun_bitmap_len);
-       sz += snprintf(page + sz, PAGE_SIZE - sz,
+       sz += scnprintf(page + sz, PAGE_SIZE - sz,
                                "blk_line:%d, sec_line:%d, sec_blk:%d\n",
                                        lm->blk_per_line,
                                        lm->sec_per_line,
@@ -344,12 +344,12 @@ static ssize_t pblk_get_write_amp(u64 user, u64 gc, u64 pad,
 {
        int sz;
 
-       sz = snprintf(page, PAGE_SIZE,
+       sz = scnprintf(page, PAGE_SIZE,
                        "user:%lld gc:%lld pad:%lld WA:",
                        user, gc, pad);
 
        if (!user) {
-               sz += snprintf(page + sz, PAGE_SIZE - sz, "NaN\n");
+               sz += scnprintf(page + sz, PAGE_SIZE - sz, "NaN\n");
        } else {
                u64 wa_int;
                u32 wa_frac;
@@ -358,7 +358,7 @@ static ssize_t pblk_get_write_amp(u64 user, u64 gc, u64 pad,
                wa_int = div64_u64(wa_int, user);
                wa_int = div_u64_rem(wa_int, 100000, &wa_frac);
 
-               sz += snprintf(page + sz, PAGE_SIZE - sz, "%llu.%05u\n",
+               sz += scnprintf(page + sz, PAGE_SIZE - sz, "%llu.%05u\n",
                                                        wa_int, wa_frac);
        }
 
@@ -401,9 +401,9 @@ static ssize_t pblk_sysfs_get_padding_dist(struct pblk *pblk, char *page)
        total = atomic64_read(&pblk->nr_flush) - pblk->nr_flush_rst;
        if (!total) {
                for (i = 0; i < (buckets + 1); i++)
-                       sz += snprintf(page + sz, PAGE_SIZE - sz,
+                       sz += scnprintf(page + sz, PAGE_SIZE - sz,
                                "%d:0 ", i);
-               sz += snprintf(page + sz, PAGE_SIZE - sz, "\n");
+               sz += scnprintf(page + sz, PAGE_SIZE - sz, "\n");
 
                return sz;
        }
@@ -411,7 +411,7 @@ static ssize_t pblk_sysfs_get_padding_dist(struct pblk *pblk, char *page)
        for (i = 0; i < buckets; i++)
                total_buckets += atomic64_read(&pblk->pad_dist[i]);
 
-       sz += snprintf(page + sz, PAGE_SIZE - sz, "0:%lld%% ",
+       sz += scnprintf(page + sz, PAGE_SIZE - sz, "0:%lld%% ",
                bucket_percentage(total - total_buckets, total));
 
        for (i = 0; i < buckets; i++) {
@@ -419,10 +419,10 @@ static ssize_t pblk_sysfs_get_padding_dist(struct pblk *pblk, char *page)
 
                p = bucket_percentage(atomic64_read(&pblk->pad_dist[i]),
                                          total);
-               sz += snprintf(page + sz, PAGE_SIZE - sz, "%d:%lld%% ",
+               sz += scnprintf(page + sz, PAGE_SIZE - sz, "%d:%lld%% ",
                                i + 1, p);
        }
-       sz += snprintf(page + sz, PAGE_SIZE - sz, "\n");
+       sz += scnprintf(page + sz, PAGE_SIZE - sz, "\n");
 
        return sz;
 }
index 8c74457..a0d87ed 100644 (file)
@@ -300,9 +300,11 @@ static int control_loop(void *dummy)
 /*     i2c probing and setup                                           */
 /************************************************************************/
 
-static int
-do_attach( struct i2c_adapter *adapter )
+static void do_attach(struct i2c_adapter *adapter)
 {
+       struct i2c_board_info info = { };
+       struct device_node *np;
+
        /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
        static const unsigned short scan_ds1775[] = {
                0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
@@ -313,25 +315,24 @@ do_attach( struct i2c_adapter *adapter )
                I2C_CLIENT_END
        };
 
-       if( strncmp(adapter->name, "uni-n", 5) )
-               return 0;
-
-       if( !x.running ) {
-               struct i2c_board_info info;
+       if (x.running || strncmp(adapter->name, "uni-n", 5))
+               return;
 
-               memset(&info, 0, sizeof(struct i2c_board_info));
-               strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE);
+       np = of_find_compatible_node(adapter->dev.of_node, NULL, "MAC,ds1775");
+       if (np) {
+               of_node_put(np);
+       } else {
+               strlcpy(info.type, "MAC,ds1775", I2C_NAME_SIZE);
                i2c_new_probed_device(adapter, &info, scan_ds1775, NULL);
+       }
 
-               strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE);
+       np = of_find_compatible_node(adapter->dev.of_node, NULL, "MAC,adm1030");
+       if (np) {
+               of_node_put(np);
+       } else {
+               strlcpy(info.type, "MAC,adm1030", I2C_NAME_SIZE);
                i2c_new_probed_device(adapter, &info, scan_adm1030, NULL);
-
-               if( x.thermostat && x.fan ) {
-                       x.running = 1;
-                       x.poll_task = kthread_run(control_loop, NULL, "g4fand");
-               }
        }
-       return 0;
 }
 
 static int
@@ -404,8 +405,8 @@ out:
 enum chip { ds1775, adm1030 };
 
 static const struct i2c_device_id therm_windtunnel_id[] = {
-       { "therm_ds1775", ds1775 },
-       { "therm_adm1030", adm1030 },
+       { "MAC,ds1775", ds1775 },
+       { "MAC,adm1030", adm1030 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, therm_windtunnel_id);
@@ -414,6 +415,7 @@ static int
 do_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
        struct i2c_adapter *adapter = cl->adapter;
+       int ret = 0;
 
        if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA
                                     | I2C_FUNC_SMBUS_WRITE_BYTE) )
@@ -421,11 +423,19 @@ do_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 
        switch (id->driver_data) {
        case adm1030:
-               return attach_fan( cl );
+               ret = attach_fan(cl);
+               break;
        case ds1775:
-               return attach_thermostat(cl);
+               ret = attach_thermostat(cl);
+               break;
        }
-       return 0;
+
+       if (!x.running && x.thermostat && x.fan) {
+               x.running = 1;
+               x.poll_task = kthread_run(control_loop, NULL, "g4fand");
+       }
+
+       return ret;
 }
 
 static struct i2c_driver g4fan_driver = {
index 1256059..e7dec32 100644 (file)
@@ -312,9 +312,16 @@ static const struct i2c_device_id wf_ad7417_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
 
+static const struct of_device_id wf_ad7417_of_id[] = {
+       { .compatible = "ad7417", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wf_ad7417_of_id);
+
 static struct i2c_driver wf_ad7417_driver = {
        .driver = {
                .name   = "wf_ad7417",
+               .of_match_table = wf_ad7417_of_id,
        },
        .probe          = wf_ad7417_probe,
        .remove         = wf_ad7417_remove,
index 67daeec..2470e5a 100644 (file)
@@ -580,9 +580,16 @@ static const struct i2c_device_id wf_fcu_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wf_fcu_id);
 
+static const struct of_device_id wf_fcu_of_id[] = {
+       { .compatible = "fcu", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wf_fcu_of_id);
+
 static struct i2c_driver wf_fcu_driver = {
        .driver = {
                .name   = "wf_fcu",
+               .of_match_table = wf_fcu_of_id,
        },
        .probe          = wf_fcu_probe,
        .remove         = wf_fcu_remove,
index 282c28a..1e5fa09 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
+#include <linux/of_device.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
@@ -91,9 +92,14 @@ static int wf_lm75_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {      
        struct wf_lm75_sensor *lm;
-       int rc, ds1775 = id->driver_data;
+       int rc, ds1775;
        const char *name, *loc;
 
+       if (id)
+               ds1775 = id->driver_data;
+       else
+               ds1775 = !!of_device_get_match_data(&client->dev);
+
        DBG("wf_lm75: creating  %s device at address 0x%02x\n",
            ds1775 ? "ds1775" : "lm75", client->addr);
 
@@ -164,9 +170,17 @@ static const struct i2c_device_id wf_lm75_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
 
+static const struct of_device_id wf_lm75_of_id[] = {
+       { .compatible = "lm75", .data = (void *)0},
+       { .compatible = "ds1775", .data = (void *)1 },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wf_lm75_of_id);
+
 static struct i2c_driver wf_lm75_driver = {
        .driver = {
                .name   = "wf_lm75",
+               .of_match_table = wf_lm75_of_id,
        },
        .probe          = wf_lm75_probe,
        .remove         = wf_lm75_remove,
index b03a33b..d011899 100644 (file)
@@ -166,9 +166,16 @@ static const struct i2c_device_id wf_lm87_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
 
+static const struct of_device_id wf_lm87_of_id[] = {
+       { .compatible = "lm87cimt", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wf_lm87_of_id);
+
 static struct i2c_driver wf_lm87_driver = {
        .driver = {
                .name   = "wf_lm87",
+               .of_match_table = wf_lm87_of_id,
        },
        .probe          = wf_lm87_probe,
        .remove         = wf_lm87_remove,
index e666cc0..1e7b03d 100644 (file)
@@ -120,9 +120,16 @@ static const struct i2c_device_id wf_max6690_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wf_max6690_id);
 
+static const struct of_device_id wf_max6690_of_id[] = {
+       { .compatible = "max6690", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wf_max6690_of_id);
+
 static struct i2c_driver wf_max6690_driver = {
        .driver = {
                .name           = "wf_max6690",
+               .of_match_table = wf_max6690_of_id,
        },
        .probe          = wf_max6690_probe,
        .remove         = wf_max6690_remove,
index c84ec49..cb75dc0 100644 (file)
@@ -341,9 +341,16 @@ static const struct i2c_device_id wf_sat_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, wf_sat_id);
 
+static const struct of_device_id wf_sat_of_id[] = {
+       { .compatible = "smu-sat", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wf_sat_of_id);
+
 static struct i2c_driver wf_sat_driver = {
        .driver = {
                .name           = "wf_smu_sat",
+               .of_match_table = wf_sat_of_id,
        },
        .probe          = wf_sat_probe,
        .remove         = wf_sat_remove,
index 8bc1faf..a1df0d9 100644 (file)
@@ -67,7 +67,6 @@
 #include <linux/blkdev.h>
 #include <linux/kthread.h>
 #include <linux/random.h>
-#include <linux/sched/signal.h>
 #include <trace/events/bcache.h>
 
 #define MAX_OPEN_BUCKETS 128
@@ -734,21 +733,8 @@ int bch_open_buckets_alloc(struct cache_set *c)
 
 int bch_cache_allocator_start(struct cache *ca)
 {
-       struct task_struct *k;
-
-       /*
-        * In case previous btree check operation occupies too many
-        * system memory for bcache btree node cache, and the
-        * registering process is selected by OOM killer. Here just
-        * ignore the SIGKILL sent by OOM killer if there is, to
-        * avoid kthread_run() being failed by pending signals. The
-        * bcache registering process will exit after the registration
-        * done.
-        */
-       if (signal_pending(current))
-               flush_signals(current);
-
-       k = kthread_run(bch_allocator_thread, ca, "bcache_allocator");
+       struct task_struct *k = kthread_run(bch_allocator_thread,
+                                           ca, "bcache_allocator");
        if (IS_ERR(k))
                return PTR_ERR(k);
 
index b12186c..72856e5 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/random.h>
 #include <linux/rcupdate.h>
 #include <linux/sched/clock.h>
-#include <linux/sched/signal.h>
 #include <linux/rculist.h>
 #include <linux/delay.h>
 #include <trace/events/bcache.h>
 
 #define insert_lock(s, b)      ((b)->level <= (s)->lock)
 
-/*
- * These macros are for recursing down the btree - they handle the details of
- * locking and looking up nodes in the cache for you. They're best treated as
- * mere syntax when reading code that uses them.
- *
- * op->lock determines whether we take a read or a write lock at a given depth.
- * If you've got a read lock and find that you need a write lock (i.e. you're
- * going to have to split), set op->lock and return -EINTR; btree_root() will
- * call you again and you'll have the correct lock.
- */
-
-/**
- * btree - recurse down the btree on a specified key
- * @fn:                function to call, which will be passed the child node
- * @key:       key to recurse on
- * @b:         parent btree node
- * @op:                pointer to struct btree_op
- */
-#define btree(fn, key, b, op, ...)                                     \
-({                                                                     \
-       int _r, l = (b)->level - 1;                                     \
-       bool _w = l <= (op)->lock;                                      \
-       struct btree *_child = bch_btree_node_get((b)->c, op, key, l,   \
-                                                 _w, b);               \
-       if (!IS_ERR(_child)) {                                          \
-               _r = bch_btree_ ## fn(_child, op, ##__VA_ARGS__);       \
-               rw_unlock(_w, _child);                                  \
-       } else                                                          \
-               _r = PTR_ERR(_child);                                   \
-       _r;                                                             \
-})
-
-/**
- * btree_root - call a function on the root of the btree
- * @fn:                function to call, which will be passed the child node
- * @c:         cache set
- * @op:                pointer to struct btree_op
- */
-#define btree_root(fn, c, op, ...)                                     \
-({                                                                     \
-       int _r = -EINTR;                                                \
-       do {                                                            \
-               struct btree *_b = (c)->root;                           \
-               bool _w = insert_lock(op, _b);                          \
-               rw_lock(_w, _b, _b->level);                             \
-               if (_b == (c)->root &&                                  \
-                   _w == insert_lock(op, _b)) {                        \
-                       _r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__);   \
-               }                                                       \
-               rw_unlock(_w, _b);                                      \
-               bch_cannibalize_unlock(c);                              \
-               if (_r == -EINTR)                                       \
-                       schedule();                                     \
-       } while (_r == -EINTR);                                         \
-                                                                       \
-       finish_wait(&(c)->btree_cache_wait, &(op)->wait);               \
-       _r;                                                             \
-})
 
 static inline struct bset *write_block(struct btree *b)
 {
@@ -1849,7 +1790,7 @@ static void bch_btree_gc(struct cache_set *c)
 
        /* if CACHE_SET_IO_DISABLE set, gc thread should stop too */
        do {
-               ret = btree_root(gc_root, c, &op, &writes, &stats);
+               ret = bcache_btree_root(gc_root, c, &op, &writes, &stats);
                closure_sync(&writes);
                cond_resched();
 
@@ -1914,18 +1855,6 @@ static int bch_gc_thread(void *arg)
 
 int bch_gc_thread_start(struct cache_set *c)
 {
-       /*
-        * In case previous btree check operation occupies too many
-        * system memory for bcache btree node cache, and the
-        * registering process is selected by OOM killer. Here just
-        * ignore the SIGKILL sent by OOM killer if there is, to
-        * avoid kthread_run() being failed by pending signals. The
-        * bcache registering process will exit after the registration
-        * done.
-        */
-       if (signal_pending(current))
-               flush_signals(current);
-
        c->gc_thread = kthread_run(bch_gc_thread, c, "bcache_gc");
        return PTR_ERR_OR_ZERO(c->gc_thread);
 }
@@ -1959,7 +1888,7 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op)
                        }
 
                        if (p)
-                               ret = btree(check_recurse, p, b, op);
+                               ret = bcache_btree(check_recurse, p, b, op);
 
                        p = k;
                } while (p && !ret);
@@ -1968,13 +1897,176 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op)
        return ret;
 }
 
+
+static int bch_btree_check_thread(void *arg)
+{
+       int ret;
+       struct btree_check_info *info = arg;
+       struct btree_check_state *check_state = info->state;
+       struct cache_set *c = check_state->c;
+       struct btree_iter iter;
+       struct bkey *k, *p;
+       int cur_idx, prev_idx, skip_nr;
+       int i, n;
+
+       k = p = NULL;
+       i = n = 0;
+       cur_idx = prev_idx = 0;
+       ret = 0;
+
+       /* root node keys are checked before thread created */
+       bch_btree_iter_init(&c->root->keys, &iter, NULL);
+       k = bch_btree_iter_next_filter(&iter, &c->root->keys, bch_ptr_bad);
+       BUG_ON(!k);
+
+       p = k;
+       while (k) {
+               /*
+                * Fetch a root node key index, skip the keys which
+                * should be fetched by other threads, then check the
+                * sub-tree indexed by the fetched key.
+                */
+               spin_lock(&check_state->idx_lock);
+               cur_idx = check_state->key_idx;
+               check_state->key_idx++;
+               spin_unlock(&check_state->idx_lock);
+
+               skip_nr = cur_idx - prev_idx;
+
+               while (skip_nr) {
+                       k = bch_btree_iter_next_filter(&iter,
+                                                      &c->root->keys,
+                                                      bch_ptr_bad);
+                       if (k)
+                               p = k;
+                       else {
+                               /*
+                                * No more keys to check in root node,
+                                * current checking threads are enough,
+                                * stop creating more.
+                                */
+                               atomic_set(&check_state->enough, 1);
+                               /* Update check_state->enough earlier */
+                               smp_mb__after_atomic();
+                               goto out;
+                       }
+                       skip_nr--;
+                       cond_resched();
+               }
+
+               if (p) {
+                       struct btree_op op;
+
+                       btree_node_prefetch(c->root, p);
+                       c->gc_stats.nodes++;
+                       bch_btree_op_init(&op, 0);
+                       ret = bcache_btree(check_recurse, p, c->root, &op);
+                       if (ret)
+                               goto out;
+               }
+               p = NULL;
+               prev_idx = cur_idx;
+               cond_resched();
+       }
+
+out:
+       info->result = ret;
+       /* update check_state->started among all CPUs */
+       smp_mb__before_atomic();
+       if (atomic_dec_and_test(&check_state->started))
+               wake_up(&check_state->wait);
+
+       return ret;
+}
+
+
+
+static int bch_btree_chkthread_nr(void)
+{
+       int n = num_online_cpus()/2;
+
+       if (n == 0)
+               n = 1;
+       else if (n > BCH_BTR_CHKTHREAD_MAX)
+               n = BCH_BTR_CHKTHREAD_MAX;
+
+       return n;
+}
+
 int bch_btree_check(struct cache_set *c)
 {
-       struct btree_op op;
+       int ret = 0;
+       int i;
+       struct bkey *k = NULL;
+       struct btree_iter iter;
+       struct btree_check_state *check_state;
+       char name[32];
 
-       bch_btree_op_init(&op, SHRT_MAX);
+       /* check and mark root node keys */
+       for_each_key_filter(&c->root->keys, k, &iter, bch_ptr_invalid)
+               bch_initial_mark_key(c, c->root->level, k);
+
+       bch_initial_mark_key(c, c->root->level + 1, &c->root->key);
+
+       if (c->root->level == 0)
+               return 0;
+
+       check_state = kzalloc(sizeof(struct btree_check_state), GFP_KERNEL);
+       if (!check_state)
+               return -ENOMEM;
+
+       check_state->c = c;
+       check_state->total_threads = bch_btree_chkthread_nr();
+       check_state->key_idx = 0;
+       spin_lock_init(&check_state->idx_lock);
+       atomic_set(&check_state->started, 0);
+       atomic_set(&check_state->enough, 0);
+       init_waitqueue_head(&check_state->wait);
 
-       return btree_root(check_recurse, c, &op);
+       /*
+        * Run multiple threads to check btree nodes in parallel,
+        * if check_state->enough is non-zero, it means current
+        * running check threads are enough, unncessary to create
+        * more.
+        */
+       for (i = 0; i < check_state->total_threads; i++) {
+               /* fetch latest check_state->enough earlier */
+               smp_mb__before_atomic();
+               if (atomic_read(&check_state->enough))
+                       break;
+
+               check_state->infos[i].result = 0;
+               check_state->infos[i].state = check_state;
+               snprintf(name, sizeof(name), "bch_btrchk[%u]", i);
+               atomic_inc(&check_state->started);
+
+               check_state->infos[i].thread =
+                       kthread_run(bch_btree_check_thread,
+                                   &check_state->infos[i],
+                                   name);
+               if (IS_ERR(check_state->infos[i].thread)) {
+                       pr_err("fails to run thread bch_btrchk[%d]", i);
+                       for (--i; i >= 0; i--)
+                               kthread_stop(check_state->infos[i].thread);
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       wait_event_interruptible(check_state->wait,
+                                atomic_read(&check_state->started) == 0 ||
+                                 test_bit(CACHE_SET_IO_DISABLE, &c->flags));
+
+       for (i = 0; i < check_state->total_threads; i++) {
+               if (check_state->infos[i].result) {
+                       ret = check_state->infos[i].result;
+                       goto out;
+               }
+       }
+
+out:
+       kfree(check_state);
+       return ret;
 }
 
 void bch_initial_gc_finish(struct cache_set *c)
@@ -2414,7 +2506,7 @@ static int bch_btree_map_nodes_recurse(struct btree *b, struct btree_op *op,
 
                while ((k = bch_btree_iter_next_filter(&iter, &b->keys,
                                                       bch_ptr_bad))) {
-                       ret = btree(map_nodes_recurse, k, b,
+                       ret = bcache_btree(map_nodes_recurse, k, b,
                                    op, from, fn, flags);
                        from = NULL;
 
@@ -2432,10 +2524,10 @@ static int bch_btree_map_nodes_recurse(struct btree *b, struct btree_op *op,
 int __bch_btree_map_nodes(struct btree_op *op, struct cache_set *c,
                          struct bkey *from, btree_map_nodes_fn *fn, int flags)
 {
-       return btree_root(map_nodes_recurse, c, op, from, fn, flags);
+       return bcache_btree_root(map_nodes_recurse, c, op, from, fn, flags);
 }
 
-static int bch_btree_map_keys_recurse(struct btree *b, struct btree_op *op,
+int bch_btree_map_keys_recurse(struct btree *b, struct btree_op *op,
                                      struct bkey *from, btree_map_keys_fn *fn,
                                      int flags)
 {
@@ -2448,7 +2540,8 @@ static int bch_btree_map_keys_recurse(struct btree *b, struct btree_op *op,
        while ((k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad))) {
                ret = !b->level
                        ? fn(op, b, k)
-                       : btree(map_keys_recurse, k, b, op, from, fn, flags);
+                       : bcache_btree(map_keys_recurse, k,
+                                      b, op, from, fn, flags);
                from = NULL;
 
                if (ret != MAP_CONTINUE)
@@ -2465,7 +2558,7 @@ static int bch_btree_map_keys_recurse(struct btree *b, struct btree_op *op,
 int bch_btree_map_keys(struct btree_op *op, struct cache_set *c,
                       struct bkey *from, btree_map_keys_fn *fn, int flags)
 {
-       return btree_root(map_keys_recurse, c, op, from, fn, flags);
+       return bcache_btree_root(map_keys_recurse, c, op, from, fn, flags);
 }
 
 /* Keybuf code */
index f4dcca4..2579699 100644 (file)
@@ -145,6 +145,9 @@ struct btree {
        struct bio              *bio;
 };
 
+
+
+
 #define BTREE_FLAG(flag)                                               \
 static inline bool btree_node_ ## flag(struct btree *b)                        \
 {      return test_bit(BTREE_NODE_ ## flag, &b->flags); }              \
@@ -216,6 +219,25 @@ struct btree_op {
        unsigned int            insert_collision:1;
 };
 
+struct btree_check_state;
+struct btree_check_info {
+       struct btree_check_state        *state;
+       struct task_struct              *thread;
+       int                             result;
+};
+
+#define BCH_BTR_CHKTHREAD_MAX  64
+struct btree_check_state {
+       struct cache_set                *c;
+       int                             total_threads;
+       int                             key_idx;
+       spinlock_t                      idx_lock;
+       atomic_t                        started;
+       atomic_t                        enough;
+       wait_queue_head_t               wait;
+       struct btree_check_info         infos[BCH_BTR_CHKTHREAD_MAX];
+};
+
 static inline void bch_btree_op_init(struct btree_op *op, int write_lock_level)
 {
        memset(op, 0, sizeof(struct btree_op));
@@ -284,6 +306,65 @@ static inline void force_wake_up_gc(struct cache_set *c)
        wake_up_gc(c);
 }
 
+/*
+ * These macros are for recursing down the btree - they handle the details of
+ * locking and looking up nodes in the cache for you. They're best treated as
+ * mere syntax when reading code that uses them.
+ *
+ * op->lock determines whether we take a read or a write lock at a given depth.
+ * If you've got a read lock and find that you need a write lock (i.e. you're
+ * going to have to split), set op->lock and return -EINTR; btree_root() will
+ * call you again and you'll have the correct lock.
+ */
+
+/**
+ * btree - recurse down the btree on a specified key
+ * @fn:                function to call, which will be passed the child node
+ * @key:       key to recurse on
+ * @b:         parent btree node
+ * @op:                pointer to struct btree_op
+ */
+#define bcache_btree(fn, key, b, op, ...)                              \
+({                                                                     \
+       int _r, l = (b)->level - 1;                                     \
+       bool _w = l <= (op)->lock;                                      \
+       struct btree *_child = bch_btree_node_get((b)->c, op, key, l,   \
+                                                 _w, b);               \
+       if (!IS_ERR(_child)) {                                          \
+               _r = bch_btree_ ## fn(_child, op, ##__VA_ARGS__);       \
+               rw_unlock(_w, _child);                                  \
+       } else                                                          \
+               _r = PTR_ERR(_child);                                   \
+       _r;                                                             \
+})
+
+/**
+ * btree_root - call a function on the root of the btree
+ * @fn:                function to call, which will be passed the child node
+ * @c:         cache set
+ * @op:                pointer to struct btree_op
+ */
+#define bcache_btree_root(fn, c, op, ...)                              \
+({                                                                     \
+       int _r = -EINTR;                                                \
+       do {                                                            \
+               struct btree *_b = (c)->root;                           \
+               bool _w = insert_lock(op, _b);                          \
+               rw_lock(_w, _b, _b->level);                             \
+               if (_b == (c)->root &&                                  \
+                   _w == insert_lock(op, _b)) {                        \
+                       _r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__);   \
+               }                                                       \
+               rw_unlock(_w, _b);                                      \
+               bch_cannibalize_unlock(c);                              \
+               if (_r == -EINTR)                                       \
+                       schedule();                                     \
+       } while (_r == -EINTR);                                         \
+                                                                       \
+       finish_wait(&(c)->btree_cache_wait, &(op)->wait);               \
+       _r;                                                             \
+})
+
 #define MAP_DONE       0
 #define MAP_CONTINUE   1
 
@@ -314,6 +395,9 @@ typedef int (btree_map_keys_fn)(struct btree_op *op, struct btree *b,
                                struct bkey *k);
 int bch_btree_map_keys(struct btree_op *op, struct cache_set *c,
                       struct bkey *from, btree_map_keys_fn *fn, int flags);
+int bch_btree_map_keys_recurse(struct btree *b, struct btree_op *op,
+                              struct bkey *from, btree_map_keys_fn *fn,
+                              int flags);
 
 typedef bool (keybuf_pred_fn)(struct keybuf *buf, struct bkey *k);
 
index 820d840..71a90fb 100644 (file)
@@ -1161,8 +1161,7 @@ static void quit_max_writeback_rate(struct cache_set *c,
 
 /* Cached devices - read & write stuff */
 
-static blk_qc_t cached_dev_make_request(struct request_queue *q,
-                                       struct bio *bio)
+blk_qc_t cached_dev_make_request(struct request_queue *q, struct bio *bio)
 {
        struct search *s;
        struct bcache_device *d = bio->bi_disk->private_data;
@@ -1266,7 +1265,6 @@ void bch_cached_dev_request_init(struct cached_dev *dc)
 {
        struct gendisk *g = dc->disk.disk;
 
-       g->queue->make_request_fn               = cached_dev_make_request;
        g->queue->backing_dev_info->congested_fn = cached_dev_congested;
        dc->disk.cache_miss                     = cached_dev_cache_miss;
        dc->disk.ioctl                          = cached_dev_ioctl;
@@ -1301,8 +1299,7 @@ static void flash_dev_nodata(struct closure *cl)
        continue_at(cl, search_free, NULL);
 }
 
-static blk_qc_t flash_dev_make_request(struct request_queue *q,
-                                            struct bio *bio)
+blk_qc_t flash_dev_make_request(struct request_queue *q, struct bio *bio)
 {
        struct search *s;
        struct closure *cl;
index c64dbd7..bb005c9 100644 (file)
@@ -37,7 +37,10 @@ unsigned int bch_get_congested(const struct cache_set *c);
 void bch_data_insert(struct closure *cl);
 
 void bch_cached_dev_request_init(struct cached_dev *dc);
+blk_qc_t cached_dev_make_request(struct request_queue *q, struct bio *bio);
+
 void bch_flash_dev_request_init(struct bcache_device *d);
+blk_qc_t flash_dev_make_request(struct request_queue *q, struct bio *bio);
 
 extern struct kmem_cache *bch_search_cache;
 
index 0c3c541..d98354f 100644 (file)
@@ -816,7 +816,7 @@ static void bcache_device_free(struct bcache_device *d)
 }
 
 static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
-                             sector_t sectors)
+                             sector_t sectors, make_request_fn make_request_fn)
 {
        struct request_queue *q;
        const size_t max_stripes = min_t(size_t, INT_MAX,
@@ -866,11 +866,10 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
        d->disk->fops           = &bcache_ops;
        d->disk->private_data   = d;
 
-       q = blk_alloc_queue(GFP_KERNEL);
+       q = blk_alloc_queue(make_request_fn, NUMA_NO_NODE);
        if (!q)
                return -ENOMEM;
 
-       blk_queue_make_request(q, NULL);
        d->disk->queue                  = q;
        q->queuedata                    = d;
        q->backing_dev_info->congested_data = d;
@@ -1339,7 +1338,8 @@ static int cached_dev_init(struct cached_dev *dc, unsigned int block_size)
                        q->limits.raid_partial_stripes_expensive;
 
        ret = bcache_device_init(&dc->disk, block_size,
-                        dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
+                        dc->bdev->bd_part->nr_sects - dc->sb.data_offset,
+                        cached_dev_make_request);
        if (ret)
                return ret;
 
@@ -1451,7 +1451,8 @@ static int flash_dev_run(struct cache_set *c, struct uuid_entry *u)
 
        kobject_init(&d->kobj, &bch_flash_dev_ktype);
 
-       if (bcache_device_init(d, block_bytes(c), u->sectors))
+       if (bcache_device_init(d, block_bytes(c), u->sectors,
+                       flash_dev_make_request))
                goto err;
 
        bcache_device_attach(d, c, u - c->uuids);
index 3470fae..3232769 100644 (file)
@@ -154,7 +154,7 @@ static ssize_t bch_snprint_string_list(char *buf,
        size_t i;
 
        for (i = 0; list[i]; i++)
-               out += snprintf(out, buf + size - out,
+               out += scnprintf(out, buf + size - out,
                                i == selected ? "[%s] " : "%s ", list[i]);
 
        out[-1] = '\n';
index 4a40f9e..3f7641f 100644 (file)
@@ -183,7 +183,7 @@ static void update_writeback_rate(struct work_struct *work)
         */
        set_bit(BCACHE_DEV_RATE_DW_RUNNING, &dc->disk.flags);
        /* paired with where BCACHE_DEV_RATE_DW_RUNNING is tested */
-       smp_mb();
+       smp_mb__after_atomic();
 
        /*
         * CACHE_SET_IO_DISABLE might be set via sysfs interface,
@@ -193,7 +193,7 @@ static void update_writeback_rate(struct work_struct *work)
            test_bit(CACHE_SET_IO_DISABLE, &c->flags)) {
                clear_bit(BCACHE_DEV_RATE_DW_RUNNING, &dc->disk.flags);
                /* paired with where BCACHE_DEV_RATE_DW_RUNNING is tested */
-               smp_mb();
+               smp_mb__after_atomic();
                return;
        }
 
@@ -229,7 +229,7 @@ static void update_writeback_rate(struct work_struct *work)
         */
        clear_bit(BCACHE_DEV_RATE_DW_RUNNING, &dc->disk.flags);
        /* paired with where BCACHE_DEV_RATE_DW_RUNNING is tested */
-       smp_mb();
+       smp_mb__after_atomic();
 }
 
 static unsigned int writeback_delay(struct cached_dev *dc,
@@ -785,7 +785,9 @@ static int sectors_dirty_init_fn(struct btree_op *_op, struct btree *b,
        return MAP_CONTINUE;
 }
 
-void bch_sectors_dirty_init(struct bcache_device *d)
+static int bch_root_node_dirty_init(struct cache_set *c,
+                                    struct bcache_device *d,
+                                    struct bkey *k)
 {
        struct sectors_dirty_init op;
        int ret;
@@ -796,8 +798,13 @@ void bch_sectors_dirty_init(struct bcache_device *d)
        op.start = KEY(op.inode, 0, 0);
 
        do {
-               ret = bch_btree_map_keys(&op.op, d->c, &op.start,
-                                        sectors_dirty_init_fn, 0);
+               ret = bcache_btree(map_keys_recurse,
+                                  k,
+                                  c->root,
+                                  &op.op,
+                                  &op.start,
+                                  sectors_dirty_init_fn,
+                                  0);
                if (ret == -EAGAIN)
                        schedule_timeout_interruptible(
                                msecs_to_jiffies(INIT_KEYS_SLEEP_MS));
@@ -806,6 +813,151 @@ void bch_sectors_dirty_init(struct bcache_device *d)
                        break;
                }
        } while (ret == -EAGAIN);
+
+       return ret;
+}
+
+static int bch_dirty_init_thread(void *arg)
+{
+       struct dirty_init_thrd_info *info = arg;
+       struct bch_dirty_init_state *state = info->state;
+       struct cache_set *c = state->c;
+       struct btree_iter iter;
+       struct bkey *k, *p;
+       int cur_idx, prev_idx, skip_nr;
+       int i;
+
+       k = p = NULL;
+       i = 0;
+       cur_idx = prev_idx = 0;
+
+       bch_btree_iter_init(&c->root->keys, &iter, NULL);
+       k = bch_btree_iter_next_filter(&iter, &c->root->keys, bch_ptr_bad);
+       BUG_ON(!k);
+
+       p = k;
+
+       while (k) {
+               spin_lock(&state->idx_lock);
+               cur_idx = state->key_idx;
+               state->key_idx++;
+               spin_unlock(&state->idx_lock);
+
+               skip_nr = cur_idx - prev_idx;
+
+               while (skip_nr) {
+                       k = bch_btree_iter_next_filter(&iter,
+                                                      &c->root->keys,
+                                                      bch_ptr_bad);
+                       if (k)
+                               p = k;
+                       else {
+                               atomic_set(&state->enough, 1);
+                               /* Update state->enough earlier */
+                               smp_mb__after_atomic();
+                               goto out;
+                       }
+                       skip_nr--;
+                       cond_resched();
+               }
+
+               if (p) {
+                       if (bch_root_node_dirty_init(c, state->d, p) < 0)
+                               goto out;
+               }
+
+               p = NULL;
+               prev_idx = cur_idx;
+               cond_resched();
+       }
+
+out:
+       /* In order to wake up state->wait in time */
+       smp_mb__before_atomic();
+       if (atomic_dec_and_test(&state->started))
+               wake_up(&state->wait);
+
+       return 0;
+}
+
+static int bch_btre_dirty_init_thread_nr(void)
+{
+       int n = num_online_cpus()/2;
+
+       if (n == 0)
+               n = 1;
+       else if (n > BCH_DIRTY_INIT_THRD_MAX)
+               n = BCH_DIRTY_INIT_THRD_MAX;
+
+       return n;
+}
+
+void bch_sectors_dirty_init(struct bcache_device *d)
+{
+       int i;
+       struct bkey *k = NULL;
+       struct btree_iter iter;
+       struct sectors_dirty_init op;
+       struct cache_set *c = d->c;
+       struct bch_dirty_init_state *state;
+       char name[32];
+
+       /* Just count root keys if no leaf node */
+       if (c->root->level == 0) {
+               bch_btree_op_init(&op.op, -1);
+               op.inode = d->id;
+               op.count = 0;
+               op.start = KEY(op.inode, 0, 0);
+
+               for_each_key_filter(&c->root->keys,
+                                   k, &iter, bch_ptr_invalid)
+                       sectors_dirty_init_fn(&op.op, c->root, k);
+               return;
+       }
+
+       state = kzalloc(sizeof(struct bch_dirty_init_state), GFP_KERNEL);
+       if (!state) {
+               pr_warn("sectors dirty init failed: cannot allocate memory");
+               return;
+       }
+
+       state->c = c;
+       state->d = d;
+       state->total_threads = bch_btre_dirty_init_thread_nr();
+       state->key_idx = 0;
+       spin_lock_init(&state->idx_lock);
+       atomic_set(&state->started, 0);
+       atomic_set(&state->enough, 0);
+       init_waitqueue_head(&state->wait);
+
+       for (i = 0; i < state->total_threads; i++) {
+               /* Fetch latest state->enough earlier */
+               smp_mb__before_atomic();
+               if (atomic_read(&state->enough))
+                       break;
+
+               state->infos[i].state = state;
+               atomic_inc(&state->started);
+               snprintf(name, sizeof(name), "bch_dirty_init[%d]", i);
+
+               state->infos[i].thread =
+                       kthread_run(bch_dirty_init_thread,
+                                   &state->infos[i],
+                                   name);
+               if (IS_ERR(state->infos[i].thread)) {
+                       pr_err("fails to run thread bch_dirty_init[%d]", i);
+                       for (--i; i >= 0; i--)
+                               kthread_stop(state->infos[i].thread);
+                       goto out;
+               }
+       }
+
+       wait_event_interruptible(state->wait,
+                atomic_read(&state->started) == 0 ||
+                test_bit(CACHE_SET_IO_DISABLE, &c->flags));
+
+out:
+       kfree(state);
 }
 
 void bch_cached_dev_writeback_init(struct cached_dev *dc)
index 4e4c681..b029843 100644 (file)
@@ -16,6 +16,7 @@
 
 #define BCH_AUTO_GC_DIRTY_THRESHOLD    50
 
+#define BCH_DIRTY_INIT_THRD_MAX        64
 /*
  * 14 (16384ths) is chosen here as something that each backing device
  * should be a reasonable fraction of the share, and not to blow up
  */
 #define WRITEBACK_SHARE_SHIFT   14
 
+struct bch_dirty_init_state;
+struct dirty_init_thrd_info {
+       struct bch_dirty_init_state     *state;
+       struct task_struct              *thread;
+};
+
+struct bch_dirty_init_state {
+       struct cache_set                *c;
+       struct bcache_device            *d;
+       int                             total_threads;
+       int                             key_idx;
+       spinlock_t                      idx_lock;
+       atomic_t                        started;
+       atomic_t                        enough;
+       wait_queue_head_t               wait;
+       struct dirty_init_thrd_info     infos[BCH_DIRTY_INIT_THRD_MAX];
+};
+
 static inline uint64_t bcache_dev_sectors_dirty(struct bcache_device *d)
 {
        uint64_t i, ret = 0;
index c82578a..2ea0360 100644 (file)
 struct dm_bio_details {
        struct gendisk *bi_disk;
        u8 bi_partno;
+       int __bi_remaining;
        unsigned long bi_flags;
        struct bvec_iter bi_iter;
+       bio_end_io_t *bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       struct bio_integrity_payload *bi_integrity;
+#endif
 };
 
 static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
@@ -30,6 +35,11 @@ static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
        bd->bi_partno = bio->bi_partno;
        bd->bi_flags = bio->bi_flags;
        bd->bi_iter = bio->bi_iter;
+       bd->__bi_remaining = atomic_read(&bio->__bi_remaining);
+       bd->bi_end_io = bio->bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       bd->bi_integrity = bio_integrity(bio);
+#endif
 }
 
 static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
@@ -38,6 +48,11 @@ static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
        bio->bi_partno = bd->bi_partno;
        bio->bi_flags = bd->bi_flags;
        bio->bi_iter = bd->bi_iter;
+       atomic_set(&bio->__bi_remaining, bd->__bi_remaining);
+       bio->bi_end_io = bd->bi_end_io;
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+       bio->bi_integrity = bd->bi_integrity;
+#endif
 }
 
 #endif
index 2d32821..d3bb355 100644 (file)
@@ -2846,8 +2846,8 @@ static void cache_postsuspend(struct dm_target *ti)
        prevent_background_work(cache);
        BUG_ON(atomic_read(&cache->nr_io_migrations));
 
-       cancel_delayed_work(&cache->waker);
-       flush_workqueue(cache->wq);
+       cancel_delayed_work_sync(&cache->waker);
+       drain_workqueue(cache->wq);
        WARN_ON(cache->tracker.in_flight);
 
        /*
@@ -3492,7 +3492,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type cache_target = {
        .name = "cache",
-       .version = {2, 1, 0},
+       .version = {2, 2, 0},
        .module = THIS_MODULE,
        .ctr = cache_ctr,
        .dtr = cache_dtr,
index b225b3e..2f03fec 100644 (file)
@@ -6,6 +6,8 @@
  * This file is released under the GPL.
  */
 
+#include "dm-bio-record.h"
+
 #include <linux/compiler.h>
 #include <linux/module.h>
 #include <linux/device-mapper.h>
@@ -201,17 +203,19 @@ struct dm_integrity_c {
        __u8 log2_blocks_per_bitmap_bit;
 
        unsigned char mode;
-       int suspending;
 
        int failed;
 
        struct crypto_shash *internal_hash;
 
+       struct dm_target *ti;
+
        /* these variables are locked with endio_wait.lock */
        struct rb_root in_progress;
        struct list_head wait_list;
        wait_queue_head_t endio_wait;
        struct workqueue_struct *wait_wq;
+       struct workqueue_struct *offload_wq;
 
        unsigned char commit_seq;
        commit_id_t commit_ids[N_COMMIT_IDS];
@@ -293,11 +297,7 @@ struct dm_integrity_io {
 
        struct completion *completion;
 
-       struct gendisk *orig_bi_disk;
-       u8 orig_bi_partno;
-       bio_end_io_t *orig_bi_end_io;
-       struct bio_integrity_payload *orig_bi_integrity;
-       struct bvec_iter orig_bi_iter;
+       struct dm_bio_details bio_details;
 };
 
 struct journal_completion {
@@ -1439,7 +1439,7 @@ static void dec_in_flight(struct dm_integrity_io *dio)
                        dio->range.logical_sector += dio->range.n_sectors;
                        bio_advance(bio, dio->range.n_sectors << SECTOR_SHIFT);
                        INIT_WORK(&dio->work, integrity_bio_wait);
-                       queue_work(ic->wait_wq, &dio->work);
+                       queue_work(ic->offload_wq, &dio->work);
                        return;
                }
                do_endio_flush(ic, dio);
@@ -1450,14 +1450,9 @@ static void integrity_end_io(struct bio *bio)
 {
        struct dm_integrity_io *dio = dm_per_bio_data(bio, sizeof(struct dm_integrity_io));
 
-       bio->bi_iter = dio->orig_bi_iter;
-       bio->bi_disk = dio->orig_bi_disk;
-       bio->bi_partno = dio->orig_bi_partno;
-       if (dio->orig_bi_integrity) {
-               bio->bi_integrity = dio->orig_bi_integrity;
+       dm_bio_restore(&dio->bio_details, bio);
+       if (bio->bi_integrity)
                bio->bi_opf |= REQ_INTEGRITY;
-       }
-       bio->bi_end_io = dio->orig_bi_end_io;
 
        if (dio->completion)
                complete(dio->completion);
@@ -1542,7 +1537,7 @@ static void integrity_metadata(struct work_struct *w)
                        }
                }
 
-               __bio_for_each_segment(bv, bio, iter, dio->orig_bi_iter) {
+               __bio_for_each_segment(bv, bio, iter, dio->bio_details.bi_iter) {
                        unsigned pos;
                        char *mem, *checksums_ptr;
 
@@ -1586,7 +1581,7 @@ again:
                if (likely(checksums != checksums_onstack))
                        kfree(checksums);
        } else {
-               struct bio_integrity_payload *bip = dio->orig_bi_integrity;
+               struct bio_integrity_payload *bip = dio->bio_details.bi_integrity;
 
                if (bip) {
                        struct bio_vec biv;
@@ -1865,7 +1860,7 @@ static void dm_integrity_map_continue(struct dm_integrity_io *dio, bool from_map
 
        if (need_sync_io && from_map) {
                INIT_WORK(&dio->work, integrity_bio_wait);
-               queue_work(ic->metadata_wq, &dio->work);
+               queue_work(ic->offload_wq, &dio->work);
                return;
        }
 
@@ -2005,20 +2000,13 @@ offload_to_thread:
        } else
                dio->completion = NULL;
 
-       dio->orig_bi_iter = bio->bi_iter;
-
-       dio->orig_bi_disk = bio->bi_disk;
-       dio->orig_bi_partno = bio->bi_partno;
+       dm_bio_record(&dio->bio_details, bio);
        bio_set_dev(bio, ic->dev->bdev);
-
-       dio->orig_bi_integrity = bio_integrity(bio);
        bio->bi_integrity = NULL;
        bio->bi_opf &= ~REQ_INTEGRITY;
-
-       dio->orig_bi_end_io = bio->bi_end_io;
        bio->bi_end_io = integrity_end_io;
-
        bio->bi_iter.bi_size = dio->range.n_sectors << SECTOR_SHIFT;
+
        generic_make_request(bio);
 
        if (need_sync_io) {
@@ -2315,7 +2303,7 @@ static void integrity_writer(struct work_struct *w)
        unsigned prev_free_sectors;
 
        /* the following test is not needed, but it tests the replay code */
-       if (READ_ONCE(ic->suspending) && !ic->meta_dev)
+       if (unlikely(dm_suspended(ic->ti)) && !ic->meta_dev)
                return;
 
        spin_lock_irq(&ic->endio_wait.lock);
@@ -2376,7 +2364,7 @@ static void integrity_recalc(struct work_struct *w)
 
 next_chunk:
 
-       if (unlikely(READ_ONCE(ic->suspending)))
+       if (unlikely(dm_suspended(ic->ti)))
                goto unlock_ret;
 
        range.logical_sector = le64_to_cpu(ic->sb->recalc_sector);
@@ -2501,7 +2489,7 @@ static void bitmap_block_work(struct work_struct *w)
                                    dio->range.n_sectors, BITMAP_OP_TEST_ALL_SET)) {
                        remove_range(ic, &dio->range);
                        INIT_WORK(&dio->work, integrity_bio_wait);
-                       queue_work(ic->wait_wq, &dio->work);
+                       queue_work(ic->offload_wq, &dio->work);
                } else {
                        block_bitmap_op(ic, ic->journal, dio->range.logical_sector,
                                        dio->range.n_sectors, BITMAP_OP_SET);
@@ -2524,7 +2512,7 @@ static void bitmap_block_work(struct work_struct *w)
 
                remove_range(ic, &dio->range);
                INIT_WORK(&dio->work, integrity_bio_wait);
-               queue_work(ic->wait_wq, &dio->work);
+               queue_work(ic->offload_wq, &dio->work);
        }
 
        queue_delayed_work(ic->commit_wq, &ic->bitmap_flush_work, ic->bitmap_flush_interval);
@@ -2804,8 +2792,6 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
 
        del_timer_sync(&ic->autocommit_timer);
 
-       WRITE_ONCE(ic->suspending, 1);
-
        if (ic->recalc_wq)
                drain_workqueue(ic->recalc_wq);
 
@@ -2834,8 +2820,6 @@ static void dm_integrity_postsuspend(struct dm_target *ti)
 #endif
        }
 
-       WRITE_ONCE(ic->suspending, 0);
-
        BUG_ON(!RB_EMPTY_ROOT(&ic->in_progress));
 
        ic->journal_uptodate = true;
@@ -2888,17 +2872,24 @@ static void dm_integrity_resume(struct dm_target *ti)
        } else {
                replay_journal(ic);
                if (ic->mode == 'B') {
-                       int mode;
                        ic->sb->flags |= cpu_to_le32(SB_FLAG_DIRTY_BITMAP);
                        ic->sb->log2_blocks_per_bitmap_bit = ic->log2_blocks_per_bitmap_bit;
                        r = sync_rw_sb(ic, REQ_OP_WRITE, REQ_FUA);
                        if (unlikely(r))
                                dm_integrity_io_error(ic, "writing superblock", r);
 
-                       mode = ic->recalculate_flag ? BITMAP_OP_SET : BITMAP_OP_CLEAR;
-                       block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, mode);
-                       block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, mode);
-                       block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, mode);
+                       block_bitmap_op(ic, ic->journal, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       block_bitmap_op(ic, ic->recalc_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       block_bitmap_op(ic, ic->may_write_bitmap, 0, ic->provided_data_sectors, BITMAP_OP_CLEAR);
+                       if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING) &&
+                           le64_to_cpu(ic->sb->recalc_sector) < ic->provided_data_sectors) {
+                               block_bitmap_op(ic, ic->journal, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                               block_bitmap_op(ic, ic->recalc_bitmap, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                               block_bitmap_op(ic, ic->may_write_bitmap, le64_to_cpu(ic->sb->recalc_sector),
+                                               ic->provided_data_sectors - le64_to_cpu(ic->sb->recalc_sector), BITMAP_OP_SET);
+                       }
                        rw_journal_sectors(ic, REQ_OP_WRITE, REQ_FUA | REQ_SYNC, 0,
                                           ic->n_bitmap_blocks * (BITMAP_BLOCK_SIZE >> SECTOR_SHIFT), NULL);
                }
@@ -2967,7 +2958,7 @@ static void dm_integrity_status(struct dm_target *ti, status_type_t type,
                        DMEMIT(" meta_device:%s", ic->meta_dev->name);
                if (ic->sectors_per_block != 1)
                        DMEMIT(" block_size:%u", ic->sectors_per_block << SECTOR_SHIFT);
-               if (ic->recalculate_flag)
+               if (ic->sb->flags & cpu_to_le32(SB_FLAG_RECALCULATING))
                        DMEMIT(" recalculate");
                DMEMIT(" journal_sectors:%u", ic->initial_sectors - SB_SECTORS);
                DMEMIT(" interleave_sectors:%u", 1U << ic->sb->log2_interleave_sectors);
@@ -3623,6 +3614,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
        }
        ti->private = ic;
        ti->per_io_data_size = sizeof(struct dm_integrity_io);
+       ic->ti = ti;
 
        ic->in_progress = RB_ROOT;
        INIT_LIST_HEAD(&ic->wait_list);
@@ -3836,6 +3828,14 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
                goto bad;
        }
 
+       ic->offload_wq = alloc_workqueue("dm-integrity-offload", WQ_MEM_RECLAIM,
+                                         METADATA_WORKQUEUE_MAX_ACTIVE);
+       if (!ic->offload_wq) {
+               ti->error = "Cannot allocate workqueue";
+               r = -ENOMEM;
+               goto bad;
+       }
+
        ic->commit_wq = alloc_workqueue("dm-integrity-commit", WQ_MEM_RECLAIM, 1);
        if (!ic->commit_wq) {
                ti->error = "Cannot allocate workqueue";
@@ -4140,6 +4140,8 @@ static void dm_integrity_dtr(struct dm_target *ti)
                destroy_workqueue(ic->metadata_wq);
        if (ic->wait_wq)
                destroy_workqueue(ic->wait_wq);
+       if (ic->offload_wq)
+               destroy_workqueue(ic->offload_wq);
        if (ic->commit_wq)
                destroy_workqueue(ic->commit_wq);
        if (ic->writer_wq)
@@ -4200,7 +4202,7 @@ static void dm_integrity_dtr(struct dm_target *ti)
 
 static struct target_type integrity_target = {
        .name                   = "integrity",
-       .version                = {1, 4, 0},
+       .version                = {1, 5, 0},
        .module                 = THIS_MODULE,
        .features               = DM_TARGET_SINGLETON | DM_TARGET_INTEGRITY,
        .ctr                    = dm_integrity_ctr,
index 2bc18c9..58fd137 100644 (file)
@@ -2053,7 +2053,7 @@ static int multipath_busy(struct dm_target *ti)
  *---------------------------------------------------------------*/
 static struct target_type multipath_target = {
        .name = "multipath",
-       .version = {1, 13, 0},
+       .version = {1, 14, 0},
        .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE |
                    DM_TARGET_PASSES_INTEGRITY,
        .module = THIS_MODULE,
index fc9947d..76b6b32 100644 (file)
@@ -960,9 +960,9 @@ int dm_pool_metadata_close(struct dm_pool_metadata *pmd)
                        DMWARN("%s: __commit_transaction() failed, error = %d",
                               __func__, r);
        }
+       pmd_write_unlock(pmd);
        if (!pmd->fail_io)
                __destroy_persistent_data_objects(pmd);
-       pmd_write_unlock(pmd);
 
        kfree(pmd);
        return 0;
index 0d61e9c..eec9f25 100644 (file)
@@ -1221,7 +1221,7 @@ bad:
 
 static struct target_type verity_target = {
        .name           = "verity",
-       .version        = {1, 5, 0},
+       .version        = {1, 6, 0},
        .module         = THIS_MODULE,
        .ctr            = verity_ctr,
        .dtr            = verity_dtr,
index b9e27e3..a09bdc0 100644 (file)
@@ -625,6 +625,12 @@ static void writecache_add_to_freelist(struct dm_writecache *wc, struct wc_entry
        wc->freelist_size++;
 }
 
+static inline void writecache_verify_watermark(struct dm_writecache *wc)
+{
+       if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark))
+               queue_work(wc->writeback_wq, &wc->writeback_work);
+}
+
 static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc, sector_t expected_sector)
 {
        struct wc_entry *e;
@@ -650,8 +656,8 @@ static struct wc_entry *writecache_pop_from_freelist(struct dm_writecache *wc, s
                list_del(&e->lru);
        }
        wc->freelist_size--;
-       if (unlikely(wc->freelist_size + wc->writeback_size <= wc->freelist_high_watermark))
-               queue_work(wc->writeback_wq, &wc->writeback_work);
+
+       writecache_verify_watermark(wc);
 
        return e;
 }
@@ -842,7 +848,7 @@ static void writecache_suspend(struct dm_target *ti)
        }
        wc_unlock(wc);
 
-       flush_workqueue(wc->writeback_wq);
+       drain_workqueue(wc->writeback_wq);
 
        wc_lock(wc);
        if (flush_on_suspend)
@@ -965,6 +971,8 @@ erase_this:
                writecache_commit_flushed(wc, false);
        }
 
+       writecache_verify_watermark(wc);
+
        wc_unlock(wc);
 }
 
@@ -2312,7 +2320,7 @@ static void writecache_status(struct dm_target *ti, status_type_t type,
 
 static struct target_type writecache_target = {
        .name                   = "writecache",
-       .version                = {1, 1, 1},
+       .version                = {1, 2, 0},
        .module                 = THIS_MODULE,
        .ctr                    = writecache_ctr,
        .dtr                    = writecache_dtr,
index 70a1063..f4f83d3 100644 (file)
@@ -533,8 +533,9 @@ static int dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
 
        /* Get the BIO chunk work. If one is not active yet, create one */
        cw = radix_tree_lookup(&dmz->chunk_rxtree, chunk);
-       if (!cw) {
-
+       if (cw) {
+               dmz_get_chunk_work(cw);
+       } else {
                /* Create a new chunk work */
                cw = kmalloc(sizeof(struct dm_chunk_work), GFP_NOIO);
                if (unlikely(!cw)) {
@@ -543,7 +544,7 @@ static int dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
                }
 
                INIT_WORK(&cw->work, dmz_chunk_work);
-               refcount_set(&cw->refcount, 0);
+               refcount_set(&cw->refcount, 1);
                cw->target = dmz;
                cw->chunk = chunk;
                bio_list_init(&cw->bio_list);
@@ -556,7 +557,6 @@ static int dmz_queue_chunk_work(struct dmz_target *dmz, struct bio *bio)
        }
 
        bio_list_add(&cw->bio_list, bio);
-       dmz_get_chunk_work(cw);
 
        dmz_reclaim_bio_acc(dmz->reclaim);
        if (queue_work(dmz->chunk_wq, &cw->work))
@@ -967,7 +967,7 @@ static int dmz_iterate_devices(struct dm_target *ti,
 
 static struct target_type dmz_type = {
        .name            = "zoned",
-       .version         = {1, 0, 0},
+       .version         = {1, 1, 0},
        .features        = DM_TARGET_SINGLETON | DM_TARGET_ZONED_HM,
        .module          = THIS_MODULE,
        .ctr             = dmz_ctr,
index b89f07e..753302e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/wait.h>
 #include <linux/pr.h>
 #include <linux/refcount.h>
+#include <linux/part_stat.h>
 
 #define DM_MSG_PREFIX "core"
 
@@ -1788,7 +1789,8 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
                         * With request-based DM we only need to check the
                         * top-level queue for congestion.
                         */
-                       r = md->queue->backing_dev_info->wb.state & bdi_bits;
+                       struct backing_dev_info *bdi = md->queue->backing_dev_info;
+                       r = bdi->wb.congested->state & bdi_bits;
                } else {
                        map = dm_get_live_table_fast(md);
                        if (map)
@@ -1854,15 +1856,6 @@ static const struct dax_operations dm_dax_ops;
 
 static void dm_wq_work(struct work_struct *work);
 
-static void dm_init_normal_md_queue(struct mapped_device *md)
-{
-       /*
-        * Initialize aspects of queue that aren't relevant for blk-mq
-        */
-       md->queue->backing_dev_info->congested_data = md;
-       md->queue->backing_dev_info->congested_fn = dm_any_congested;
-}
-
 static void cleanup_mapped_device(struct mapped_device *md)
 {
        if (md->wq)
@@ -1946,16 +1939,15 @@ static struct mapped_device *alloc_dev(int minor)
        INIT_LIST_HEAD(&md->table_devices);
        spin_lock_init(&md->uevent_lock);
 
-       md->queue = blk_alloc_queue_node(GFP_KERNEL, numa_node_id);
-       if (!md->queue)
-               goto bad;
-       md->queue->queuedata = md;
        /*
         * default to bio-based required ->make_request_fn until DM
         * table is loaded and md->type established. If request-based
         * table is loaded: blk-mq will override accordingly.
         */
-       blk_queue_make_request(md->queue, dm_make_request);
+       md->queue = blk_alloc_queue(dm_make_request, numa_node_id);
+       if (!md->queue)
+               goto bad;
+       md->queue->queuedata = md;
 
        md->disk = alloc_disk_node(1, md->numa_node_id);
        if (!md->disk)
@@ -2249,6 +2241,12 @@ struct queue_limits *dm_get_queue_limits(struct mapped_device *md)
 }
 EXPORT_SYMBOL_GPL(dm_get_queue_limits);
 
+static void dm_init_congested_fn(struct mapped_device *md)
+{
+       md->queue->backing_dev_info->congested_data = md;
+       md->queue->backing_dev_info->congested_fn = dm_any_congested;
+}
+
 /*
  * Setup the DM device's queue based on md's type
  */
@@ -2265,11 +2263,12 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t)
                        DMERR("Cannot initialize queue for request-based dm-mq mapped device");
                        return r;
                }
+               dm_init_congested_fn(md);
                break;
        case DM_TYPE_BIO_BASED:
        case DM_TYPE_DAX_BIO_BASED:
        case DM_TYPE_NVME_BIO_BASED:
-               dm_init_normal_md_queue(md);
+               dm_init_congested_fn(md);
                break;
        case DM_TYPE_NONE:
                WARN_ON_ONCE(true);
@@ -2368,6 +2367,7 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
        map = dm_get_live_table(md, &srcu_idx);
        if (!dm_suspended_md(md)) {
                dm_table_presuspend_targets(map);
+               set_bit(DMF_SUSPENDED, &md->flags);
                dm_table_postsuspend_targets(map);
        }
        /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
index 469f551..271e8a5 100644 (file)
 #include <linux/delay.h>
 #include <linux/raid/md_p.h>
 #include <linux/raid/md_u.h>
+#include <linux/raid/detect.h>
 #include <linux/slab.h>
 #include <linux/percpu-refcount.h>
+#include <linux/part_stat.h>
 
 #include <trace/events/block.h>
 #include "md.h"
@@ -2491,12 +2493,12 @@ static int lock_rdev(struct md_rdev *rdev, dev_t dev, int shared)
 {
        int err = 0;
        struct block_device *bdev;
-       char b[BDEVNAME_SIZE];
 
        bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL,
                                 shared ? (struct md_rdev *)lock_rdev : rdev);
        if (IS_ERR(bdev)) {
-               pr_warn("md: could not open %s.\n", __bdevname(dev, b));
+               pr_warn("md: could not open device unknown-block(%u,%u).\n",
+                       MAJOR(dev), MINOR(dev));
                return PTR_ERR(bdev);
        }
        rdev->bdev = bdev;
@@ -5621,12 +5623,11 @@ static int md_alloc(dev_t dev, char *name)
                mddev->hold_active = UNTIL_STOP;
 
        error = -ENOMEM;
-       mddev->queue = blk_alloc_queue(GFP_KERNEL);
+       mddev->queue = blk_alloc_queue(md_make_request, NUMA_NO_NODE);
        if (!mddev->queue)
                goto abort;
        mddev->queue->queuedata = mddev;
 
-       blk_queue_make_request(mddev->queue, md_make_request);
        blk_set_stacking_limits(&mddev->queue->limits);
 
        disk = alloc_disk(1 << shift);
@@ -6184,7 +6185,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes);
 static void mddev_detach(struct mddev *mddev)
 {
        md_bitmap_wait_behind_writes(mddev);
-       if (mddev->pers && mddev->pers->quiesce) {
+       if (mddev->pers && mddev->pers->quiesce && !mddev->suspended) {
                mddev->pers->quiesce(mddev, 1);
                mddev->pers->quiesce(mddev, 0);
        }
index b36a413..9dfea5c 100644 (file)
@@ -208,9 +208,9 @@ config MEDIA_SUBDRV_AUTOSELECT
          If unsure say Y.
 
 config MEDIA_HIDE_ANCILLARY_SUBDRV
-        bool
-        depends on MEDIA_SUBDRV_AUTOSELECT && !COMPILE_TEST && !EXPERT
-        default y
+       bool
+       depends on MEDIA_SUBDRV_AUTOSELECT && !COMPILE_TEST && !EXPERT
+       default y
 
 config MEDIA_ATTACH
        bool
index 4a841be..e748cd5 100644 (file)
@@ -23,7 +23,7 @@ struct cec_notifier {
        struct kref kref;
        struct device *hdmi_dev;
        struct cec_connector_info conn_info;
-       const char *conn_name;
+       const char *port_name;
        struct cec_adapter *cec_adap;
 
        u16 phys_addr;
@@ -32,16 +32,30 @@ struct cec_notifier {
 static LIST_HEAD(cec_notifiers);
 static DEFINE_MUTEX(cec_notifiers_lock);
 
-struct cec_notifier *
-cec_notifier_get_conn(struct device *hdmi_dev, const char *conn_name)
+/**
+ * cec_notifier_get_conn - find or create a new cec_notifier for the given
+ * device and connector tuple.
+ * @hdmi_dev: device that sends the events.
+ * @port_name: the connector name from which the event occurs
+ *
+ * If a notifier for device @dev already exists, then increase the refcount
+ * and return that notifier.
+ *
+ * If it doesn't exist, then allocate a new notifier struct and return a
+ * pointer to that new struct.
+ *
+ * Return NULL if the memory could not be allocated.
+ */
+static struct cec_notifier *
+cec_notifier_get_conn(struct device *hdmi_dev, const char *port_name)
 {
        struct cec_notifier *n;
 
        mutex_lock(&cec_notifiers_lock);
        list_for_each_entry(n, &cec_notifiers, head) {
                if (n->hdmi_dev == hdmi_dev &&
-                   (!conn_name ||
-                    (n->conn_name && !strcmp(n->conn_name, conn_name)))) {
+                   (!port_name ||
+                    (n->port_name && !strcmp(n->port_name, port_name)))) {
                        kref_get(&n->kref);
                        mutex_unlock(&cec_notifiers_lock);
                        return n;
@@ -51,9 +65,9 @@ cec_notifier_get_conn(struct device *hdmi_dev, const char *conn_name)
        if (!n)
                goto unlock;
        n->hdmi_dev = hdmi_dev;
-       if (conn_name) {
-               n->conn_name = kstrdup(conn_name, GFP_KERNEL);
-               if (!n->conn_name) {
+       if (port_name) {
+               n->port_name = kstrdup(port_name, GFP_KERNEL);
+               if (!n->port_name) {
                        kfree(n);
                        n = NULL;
                        goto unlock;
@@ -68,7 +82,6 @@ unlock:
        mutex_unlock(&cec_notifiers_lock);
        return n;
 }
-EXPORT_SYMBOL_GPL(cec_notifier_get_conn);
 
 static void cec_notifier_release(struct kref *kref)
 {
@@ -76,7 +89,7 @@ static void cec_notifier_release(struct kref *kref)
                container_of(kref, struct cec_notifier, kref);
 
        list_del(&n->head);
-       kfree(n->conn_name);
+       kfree(n->port_name);
        kfree(n);
 }
 
@@ -88,10 +101,10 @@ static void cec_notifier_put(struct cec_notifier *n)
 }
 
 struct cec_notifier *
-cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name,
+cec_notifier_conn_register(struct device *hdmi_dev, const char *port_name,
                           const struct cec_connector_info *conn_info)
 {
-       struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, conn_name);
+       struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, port_name);
 
        if (!n)
                return n;
@@ -129,7 +142,7 @@ void cec_notifier_conn_unregister(struct cec_notifier *n)
 EXPORT_SYMBOL_GPL(cec_notifier_conn_unregister);
 
 struct cec_notifier *
-cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name,
+cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *port_name,
                               struct cec_adapter *adap)
 {
        struct cec_notifier *n;
@@ -137,7 +150,7 @@ cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name,
        if (WARN_ON(!adap))
                return NULL;
 
-       n = cec_notifier_get_conn(hdmi_dev, conn_name);
+       n = cec_notifier_get_conn(hdmi_dev, port_name);
        if (!n)
                return n;
 
index aabb830..d653187 100644 (file)
@@ -97,8 +97,6 @@ void saa7146_buffer_finish(struct saa7146_dev *dev,
        DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state);
        DEB_EE("q->curr:%p\n", q->curr);
 
-       BUG_ON(!q->curr);
-
        /* finish current buffer */
        if (NULL == q->curr) {
                DEB_D("aiii. no current buffer\n");
@@ -296,7 +294,7 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
        int res;
 
        switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER: {
+       case VFL_TYPE_VIDEO: {
                DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
                       file, vma);
                q = &fh->video_q;
@@ -378,7 +376,7 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
        int ret;
 
        switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
 /*
                DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
                       file, data, (unsigned long)count);
@@ -409,7 +407,7 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou
        int ret;
 
        switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                return -EINVAL;
        case VFL_TYPE_VBI:
                if (fh->dev->ext_vv_data->vbi_fops.write) {
@@ -597,7 +595,7 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
        DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type);
 
        vfd->fops = &video_fops;
-       if (type == VFL_TYPE_GRABBER)
+       if (type == VFL_TYPE_VIDEO)
                vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
        else
                vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
@@ -611,7 +609,7 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev,
        vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
                           V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
        vfd->device_caps |= dev->ext_vv_data->capabilities;
-       if (type == VFL_TYPE_GRABBER)
+       if (type == VFL_TYPE_VIDEO)
                vfd->device_caps &=
                        ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
        else
index c95d458..8916bb6 100644 (file)
@@ -45,88 +45,88 @@ static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data,
 
        buf = debug_data->stats_data;
 
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_rf_locked = %d\n", p->is_rf_locked);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_demod_locked = %d\n", p->is_demod_locked);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_external_lna_on = %d\n", p->is_external_lna_on);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "SNR = %d\n", p->SNR);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "ber = %d\n", p->ber);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "FIB_CRC = %d\n", p->FIB_CRC);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "ts_per = %d\n", p->ts_per);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "MFER = %d\n", p->MFER);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "RSSI = %d\n", p->RSSI);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "in_band_pwr = %d\n", p->in_band_pwr);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "carrier_offset = %d\n", p->carrier_offset);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "modem_state = %d\n", p->modem_state);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "frequency = %d\n", p->frequency);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "bandwidth = %d\n", p->bandwidth);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "transmission_mode = %d\n", p->transmission_mode);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "modem_state = %d\n", p->modem_state);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "guard_interval = %d\n", p->guard_interval);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "code_rate = %d\n", p->code_rate);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "lp_code_rate = %d\n", p->lp_code_rate);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "hierarchy = %d\n", p->hierarchy);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "constellation = %d\n", p->constellation);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "burst_size = %d\n", p->burst_size);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "burst_duration = %d\n", p->burst_duration);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "burst_cycle_time = %d\n", p->burst_cycle_time);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "calc_burst_cycle_time = %d\n",
                      p->calc_burst_cycle_time);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_of_rows = %d\n", p->num_of_rows);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_of_padd_cols = %d\n", p->num_of_padd_cols);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_of_punct_cols = %d\n", p->num_of_punct_cols);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "error_ts_packets = %d\n", p->error_ts_packets);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "total_ts_packets = %d\n", p->total_ts_packets);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "ber_error_count = %d\n", p->ber_error_count);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "ber_bit_count = %d\n", p->ber_bit_count);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "pre_ber = %d\n", p->pre_ber);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "cell_id = %d\n", p->cell_id);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_mpe_received = %d\n", p->num_mpe_received);
 
        debug_data->stats_count = n;
@@ -148,42 +148,42 @@ static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data,
 
        buf = debug_data->stats_data;
 
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "statistics_type = %d\t", p->statistics_type);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "full_size = %d\n", p->full_size);
 
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_rf_locked = %d\t\t", p->is_rf_locked);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_demod_locked = %d\t", p->is_demod_locked);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_external_lna_on = %d\n", p->is_external_lna_on);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "SNR = %d dB\t\t", p->SNR);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "RSSI = %d dBm\t\t", p->RSSI);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "in_band_pwr = %d dBm\n", p->in_band_pwr);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "carrier_offset = %d\t", p->carrier_offset);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "bandwidth = %d\t\t", p->bandwidth);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "frequency = %d Hz\n", p->frequency);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "transmission_mode = %d\t", p->transmission_mode);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "modem_state = %d\t\t", p->modem_state);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "guard_interval = %d\n", p->guard_interval);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "system_type = %d\t\t", p->system_type);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "partial_reception = %d\t", p->partial_reception);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_of_layers = %d\n", p->num_of_layers);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors);
 
        for (i = 0; i < 3; i++) {
@@ -191,31 +191,34 @@ static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data,
                    p->layer_info[i].number_of_segments > 13)
                        continue;
 
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
                              p->layer_info[i].code_rate);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
                              p->layer_info[i].constellation);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
                              p->layer_info[i].ber);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n,
+                             "\tber_error_count = %-5d\t",
                              p->layer_info[i].ber_error_count);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
                              p->layer_info[i].ber_bit_count);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
                              p->layer_info[i].pre_ber);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
                              p->layer_info[i].ts_per);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n,
+                             "\terror_ts_packets = %-5d\t",
                              p->layer_info[i].error_ts_packets);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n,
+                             "total_ts_packets = %-5d\t",
                              p->layer_info[i].total_ts_packets);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
                              p->layer_info[i].ti_ldepth_i);
-               n += snprintf(&buf[n], PAGE_SIZE - n,
+               n += scnprintf(&buf[n], PAGE_SIZE - n,
                              "\tnumber_of_segments = %d\t",
                              p->layer_info[i].number_of_segments);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
                              p->layer_info[i].tmcc_errors);
        }
 
@@ -238,44 +241,44 @@ static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data,
 
        buf = debug_data->stats_data;
 
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "statistics_type = %d\t", p->statistics_type);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "full_size = %d\n", p->full_size);
 
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_rf_locked = %d\t\t", p->is_rf_locked);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_demod_locked = %d\t", p->is_demod_locked);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "is_external_lna_on = %d\n", p->is_external_lna_on);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "SNR = %d dB\t\t", p->SNR);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "RSSI = %d dBm\t\t", p->RSSI);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "in_band_pwr = %d dBm\n", p->in_band_pwr);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "carrier_offset = %d\t", p->carrier_offset);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "bandwidth = %d\t\t", p->bandwidth);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "frequency = %d Hz\n", p->frequency);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "transmission_mode = %d\t", p->transmission_mode);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "modem_state = %d\t\t", p->modem_state);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "guard_interval = %d\n", p->guard_interval);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "system_type = %d\t\t", p->system_type);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "partial_reception = %d\t", p->partial_reception);
-       n += snprintf(&buf[n], PAGE_SIZE - n,
+       n += scnprintf(&buf[n], PAGE_SIZE - n,
                      "num_of_layers = %d\n", p->num_of_layers);
-       n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t",
+       n += scnprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t",
                      p->segment_number);
-       n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n",
+       n += scnprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n",
                      p->tune_bw);
 
        for (i = 0; i < 3; i++) {
@@ -283,31 +286,34 @@ static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data,
                    p->layer_info[i].number_of_segments > 13)
                        continue;
 
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i);
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t",
                              p->layer_info[i].code_rate);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n",
                              p->layer_info[i].constellation);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t",
                              p->layer_info[i].ber);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n,
+                             "\tber_error_count = %-5d\t",
                              p->layer_info[i].ber_error_count);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n",
                              p->layer_info[i].ber_bit_count);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t",
                              p->layer_info[i].pre_ber);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n",
                              p->layer_info[i].ts_per);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n,
+                             "\terror_ts_packets = %-5d\t",
                              p->layer_info[i].error_ts_packets);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t",
+               n += scnprintf(&buf[n], PAGE_SIZE - n,
+                             "total_ts_packets = %-5d\t",
                              p->layer_info[i].total_ts_packets);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n",
                              p->layer_info[i].ti_ldepth_i);
-               n += snprintf(&buf[n], PAGE_SIZE - n,
+               n += scnprintf(&buf[n], PAGE_SIZE - n,
                              "\tnumber_of_segments = %d\t",
                              p->layer_info[i].number_of_segments);
-               n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
+               n += scnprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n",
                              p->layer_info[i].tmcc_errors);
        }
 
index 4489744..44d65f5 100644 (file)
@@ -393,8 +393,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
                }
        }
 
-       dprintk(1, "allocated %d buffers, %d plane(s) each\n",
-                       buffer, num_planes);
+       dprintk(3, "allocated %d buffers, %d plane(s) each\n",
+               buffer, num_planes);
 
        return buffer;
 }
index d0c9dff..d3a3ee5 100644 (file)
@@ -593,8 +593,8 @@ static int vb2_dc_map_dmabuf(void *mem_priv)
        /* checking if dmabuf is big enough to store contiguous chunk */
        contig_size = vb2_dc_get_contiguous_size(sgt);
        if (contig_size < buf->size) {
-               pr_err("contiguous chunk is too small %lu/%lu b\n",
-                       contig_size, buf->size);
+               pr_err("contiguous chunk is too small %lu/%lu\n",
+                      contig_size, buf->size);
                dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir);
                return -EFAULT;
        }
index ac7be87..5de0164 100644 (file)
@@ -2182,7 +2182,7 @@ int drxj_dap_atomic_read_reg32(struct i2c_device_addr *dev_addr,
                                     u32 *data, u32 flags)
 {
        u8 buf[sizeof(*data)] = { 0 };
-       int rc = -EIO;
+       int rc;
        u32 word = 0;
 
        if (!data)
@@ -4229,7 +4229,7 @@ int drxj_dap_scu_atomic_write_reg16(struct i2c_device_addr *dev_addr,
                                          u16 data, u32 flags)
 {
        u8 buf[2];
-       int rc = -EIO;
+       int rc;
 
        buf[0] = (u8) (data & 0xff);
        buf[1] = (u8) ((data >> 8) & 0xff);
index c96f05f..d2c28dc 100644 (file)
@@ -65,6 +65,92 @@ err:
 }
 
 /*
+ * m88ds3103b demod has an internal device related to clocking. First the i2c
+ * gate must be opened, for one transaction, then writes will be allowed.
+ */
+static int m88ds3103b_dt_write(struct m88ds3103_dev *dev, int reg, int data)
+{
+       struct i2c_client *client = dev->client;
+       u8 buf[] = {reg, data};
+       u8 val;
+       int ret;
+       struct i2c_msg msg = {
+               .addr = dev->dt_addr, .flags = 0, .buf = buf, .len = 2
+       };
+
+       m88ds3103_update_bits(dev, 0x11, 0x01, 0x00);
+
+       val = 0x11;
+       ret = regmap_write(dev->regmap, 0x03, val);
+       if (ret)
+               dev_dbg(&client->dev, "fail=%d\n", ret);
+
+       ret = i2c_transfer(dev->dt_client->adapter, &msg, 1);
+       if (ret != 1) {
+               dev_err(&client->dev, "0x%02x (ret=%i, reg=0x%02x, value=0x%02x)\n",
+                       dev->dt_addr, ret, reg, data);
+
+               m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+               return -EREMOTEIO;
+       }
+       m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+
+       dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n",
+               dev->dt_addr, reg, data);
+
+       return 0;
+}
+
+/*
+ * m88ds3103b demod has an internal device related to clocking. First the i2c
+ * gate must be opened, for two transactions, then reads will be allowed.
+ */
+static int m88ds3103b_dt_read(struct m88ds3103_dev *dev, u8 reg)
+{
+       struct i2c_client *client = dev->client;
+       int ret;
+       u8 val;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               {
+                       .addr = dev->dt_addr,
+                       .flags = 0,
+                       .buf = b0,
+                       .len = 1
+               },
+               {
+                       .addr = dev->dt_addr,
+                       .flags = I2C_M_RD,
+                       .buf = b1,
+                       .len = 1
+               }
+       };
+
+       m88ds3103_update_bits(dev, 0x11, 0x01, 0x00);
+
+       val = 0x12;
+       ret = regmap_write(dev->regmap, 0x03, val);
+       if (ret)
+               dev_dbg(&client->dev, "fail=%d\n", ret);
+
+       ret = i2c_transfer(dev->dt_client->adapter, msg, 2);
+       if (ret != 2) {
+               dev_err(&client->dev, "0x%02x (ret=%d, reg=0x%02x)\n",
+                       dev->dt_addr, ret, reg);
+
+               m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+               return -EREMOTEIO;
+       }
+       m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+
+       dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n",
+               dev->dt_addr, reg, b1[0]);
+
+       return b1[0];
+}
+
+/*
  * Get the demodulator AGC PWM voltage setting supplied to the tuner.
  */
 int m88ds3103_get_agc_pwm(struct dvb_frontend *fe, u8 *_agc_pwm)
@@ -288,6 +374,251 @@ err:
        return ret;
 }
 
+static int m88ds3103b_select_mclk(struct m88ds3103_dev *dev)
+{
+       struct i2c_client *client = dev->client;
+       struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+       u32 adc_Freq_MHz[3] = {96, 93, 99};
+       u8  reg16_list[3] = {96, 92, 100}, reg16, reg15;
+       u32 offset_MHz[3];
+       u32 max_offset = 0;
+       u32 old_setting = dev->mclk;
+       u32 tuner_freq_MHz = c->frequency / 1000;
+       u8 i;
+       char big_symbol = 0;
+
+       big_symbol = (c->symbol_rate > 45010000) ? 1 : 0;
+
+       if (big_symbol) {
+               reg16 = 115;
+       } else {
+               reg16 = 96;
+
+               /* TODO: IS THIS NECESSARY ? */
+               for (i = 0; i < 3; i++) {
+                       offset_MHz[i] = tuner_freq_MHz % adc_Freq_MHz[i];
+
+                       if (offset_MHz[i] > (adc_Freq_MHz[i] / 2))
+                               offset_MHz[i] = adc_Freq_MHz[i] - offset_MHz[i];
+
+                       if (offset_MHz[i] > max_offset) {
+                               max_offset = offset_MHz[i];
+                               reg16 = reg16_list[i];
+                               dev->mclk = adc_Freq_MHz[i] * 1000 * 1000;
+
+                               if (big_symbol)
+                                       dev->mclk /= 2;
+
+                               dev_dbg(&client->dev, "modifying mclk %u -> %u\n",
+                                       old_setting, dev->mclk);
+                       }
+               }
+       }
+
+       if (dev->mclk == 93000000)
+               regmap_write(dev->regmap, 0xA0, 0x42);
+       else if (dev->mclk == 96000000)
+               regmap_write(dev->regmap, 0xA0, 0x44);
+       else if (dev->mclk == 99000000)
+               regmap_write(dev->regmap, 0xA0, 0x46);
+       else if (dev->mclk == 110250000)
+               regmap_write(dev->regmap, 0xA0, 0x4E);
+       else
+               regmap_write(dev->regmap, 0xA0, 0x44);
+
+       reg15 = m88ds3103b_dt_read(dev, 0x15);
+
+       m88ds3103b_dt_write(dev, 0x05, 0x40);
+       m88ds3103b_dt_write(dev, 0x11, 0x08);
+
+       if (big_symbol)
+               reg15 |= 0x02;
+       else
+               reg15 &= ~0x02;
+
+       m88ds3103b_dt_write(dev, 0x15, reg15);
+       m88ds3103b_dt_write(dev, 0x16, reg16);
+
+       usleep_range(5000, 5500);
+
+       m88ds3103b_dt_write(dev, 0x05, 0x00);
+       m88ds3103b_dt_write(dev, 0x11, (u8)(big_symbol ? 0x0E : 0x0A));
+
+       usleep_range(5000, 5500);
+
+       return 0;
+}
+
+static int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz)
+{
+       u8 reg11 = 0x0A, reg15, reg16, reg1D, reg1E, reg1F, tmp;
+       u8 sm, f0 = 0, f1 = 0, f2 = 0, f3 = 0;
+       u16 pll_div_fb, N;
+       u32 div;
+
+       reg15 = m88ds3103b_dt_read(dev, 0x15);
+       reg16 = m88ds3103b_dt_read(dev, 0x16);
+       reg1D = m88ds3103b_dt_read(dev, 0x1D);
+
+       if (dev->cfg->ts_mode != M88DS3103_TS_SERIAL) {
+               if (reg16 == 92)
+                       tmp = 93;
+               else if (reg16 == 100)
+                       tmp = 99;
+               else
+                       tmp = 96;
+
+               mclk_khz *= tmp;
+               mclk_khz /= 96;
+       }
+
+       pll_div_fb = (reg15 & 0x01) << 8;
+       pll_div_fb += reg16;
+       pll_div_fb += 32;
+
+       div = 9000 * pll_div_fb * 4;
+       div /= mclk_khz;
+
+       if (dev->cfg->ts_mode == M88DS3103_TS_SERIAL) {
+               reg11 |= 0x02;
+
+               if (div <= 32) {
+                       N = 2;
+
+                       f0 = 0;
+                       f1 = div / N;
+                       f2 = div - f1;
+                       f3 = 0;
+               } else if (div <= 34) {
+                       N = 3;
+
+                       f0 = div / N;
+                       f1 = (div - f0) / (N - 1);
+                       f2 = div - f0 - f1;
+                       f3 = 0;
+               } else if (div <= 64) {
+                       N = 4;
+
+                       f0 = div / N;
+                       f1 = (div - f0) / (N - 1);
+                       f2 = (div - f0 - f1) / (N - 2);
+                       f3 = div - f0 - f1 - f2;
+               } else {
+                       N = 4;
+
+                       f0 = 16;
+                       f1 = 16;
+                       f2 = 16;
+                       f3 = 16;
+               }
+
+               if (f0 == 16)
+                       f0 = 0;
+               else if ((f0 < 8) && (f0 != 0))
+                       f0 = 8;
+
+               if (f1 == 16)
+                       f1 = 0;
+               else if ((f1 < 8) && (f1 != 0))
+                       f1 = 8;
+
+               if (f2 == 16)
+                       f2 = 0;
+               else if ((f2 < 8) && (f2 != 0))
+                       f2 = 8;
+
+               if (f3 == 16)
+                       f3 = 0;
+               else if ((f3 < 8) && (f3 != 0))
+                       f3 = 8;
+       } else {
+               reg11 &= ~0x02;
+
+               if (div <= 32) {
+                       N = 2;
+
+                       f0 = 0;
+                       f1 = div / N;
+                       f2 = div - f1;
+                       f3 = 0;
+               } else if (div <= 48) {
+                       N = 3;
+
+                       f0 = div / N;
+                       f1 = (div - f0) / (N - 1);
+                       f2 = div - f0 - f1;
+                       f3 = 0;
+               } else if (div <= 64) {
+                       N = 4;
+
+                       f0 = div / N;
+                       f1 = (div - f0) / (N - 1);
+                       f2 = (div - f0 - f1) / (N - 2);
+                       f3 = div - f0 - f1 - f2;
+               } else {
+                       N = 4;
+
+                       f0 = 16;
+                       f1 = 16;
+                       f2 = 16;
+                       f3 = 16;
+               }
+
+               if (f0 == 16)
+                       f0 = 0;
+               else if ((f0 < 9) && (f0 != 0))
+                       f0 = 9;
+
+               if (f1 == 16)
+                       f1 = 0;
+               else if ((f1 < 9) && (f1 != 0))
+                       f1 = 9;
+
+               if (f2 == 16)
+                       f2 = 0;
+               else if ((f2 < 9) && (f2 != 0))
+                       f2 = 9;
+
+               if (f3 == 16)
+                       f3 = 0;
+               else if ((f3 < 9) && (f3 != 0))
+                       f3 = 9;
+       }
+
+       sm = N - 1;
+
+       /* Write to registers */
+       //reg15 &= 0x01;
+       //reg15 |= (pll_div_fb >> 8) & 0x01;
+
+       //reg16 = pll_div_fb & 0xFF;
+
+       reg1D &= ~0x03;
+       reg1D |= sm;
+       reg1D |= 0x80;
+
+       reg1E = ((f3 << 4) + f2) & 0xFF;
+       reg1F = ((f1 << 4) + f0) & 0xFF;
+
+       m88ds3103b_dt_write(dev, 0x05, 0x40);
+       m88ds3103b_dt_write(dev, 0x11, 0x08);
+       m88ds3103b_dt_write(dev, 0x1D, reg1D);
+       m88ds3103b_dt_write(dev, 0x1E, reg1E);
+       m88ds3103b_dt_write(dev, 0x1F, reg1F);
+
+       m88ds3103b_dt_write(dev, 0x17, 0xc1);
+       m88ds3103b_dt_write(dev, 0x17, 0x81);
+
+       usleep_range(5000, 5500);
+
+       m88ds3103b_dt_write(dev, 0x05, 0x00);
+       m88ds3103b_dt_write(dev, 0x11, 0x0A);
+
+       usleep_range(5000, 5500);
+
+       return 0;
+}
+
 static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 {
        struct m88ds3103_dev *dev = fe->demodulator_priv;
@@ -298,7 +629,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
        u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */
        u8 buf[3];
        u16 u16tmp;
-       u32 tuner_frequency_khz, target_mclk;
+       u32 tuner_frequency_khz, target_mclk, u32tmp;
        s32 s32tmp;
        static const struct reg_sequence reset_buf[] = {
                {0x07, 0x80}, {0x07, 0x00}
@@ -321,6 +652,20 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
 
        /* Disable demod clock path */
        if (dev->chip_id == M88RS6000_CHIP_ID) {
+               if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+                       ret = regmap_read(dev->regmap, 0xb2, &u32tmp);
+                       if (ret)
+                               goto err;
+                       if (u32tmp == 0x01) {
+                               ret = regmap_write(dev->regmap, 0x00, 0x00);
+                               if (ret)
+                                       goto err;
+                               ret = regmap_write(dev->regmap, 0xb2, 0x00);
+                               if (ret)
+                                       goto err;
+                       }
+               }
+
                ret = regmap_write(dev->regmap, 0x06, 0xe0);
                if (ret)
                        goto err;
@@ -346,7 +691,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                tuner_frequency_khz = c->frequency;
        }
 
-       /* select M88RS6000 demod main mclk and ts mclk from tuner die. */
+       /* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */
        if (dev->chip_id == M88RS6000_CHIP_ID) {
                if (c->symbol_rate > 45010000)
                        dev->mclk = 110250000;
@@ -358,6 +703,11 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                else
                        target_mclk = 144000000;
 
+               if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+                       m88ds3103b_select_mclk(dev);
+                       m88ds3103b_set_mclk(dev, target_mclk / 1000);
+               }
+
                /* Enable demod clock path */
                ret = regmap_write(dev->regmap, 0x06, 0x00);
                if (ret)
@@ -469,12 +819,42 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08);
                if (ret)
                        goto err;
+
+               if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+                       buf[0] = m88ds3103b_dt_read(dev, 0x15);
+                       buf[1] = m88ds3103b_dt_read(dev, 0x16);
+
+                       if (c->symbol_rate > 45010000) {
+                               buf[0] &= ~0x03;
+                               buf[0] |= 0x02;
+                               buf[0] |= ((147 - 32) >> 8) & 0x01;
+                               buf[1] = (147 - 32) & 0xFF;
+
+                               dev->mclk = 110250 * 1000;
+                       } else {
+                               buf[0] &= ~0x03;
+                               buf[0] |= ((128 - 32) >> 8) & 0x01;
+                               buf[1] = (128 - 32) & 0xFF;
+
+                               dev->mclk = 96000 * 1000;
+                       }
+                       m88ds3103b_dt_write(dev, 0x15, buf[0]);
+                       m88ds3103b_dt_write(dev, 0x16, buf[1]);
+
+                       regmap_read(dev->regmap, 0x30, &u32tmp);
+                       u32tmp &= ~0x80;
+                       regmap_write(dev->regmap, 0x30, u32tmp & 0xff);
+               }
+
                ret = regmap_write(dev->regmap, 0xf1, 0x01);
                if (ret)
                        goto err;
-               ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
-               if (ret)
-                       goto err;
+
+               if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) {
+                       ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80);
+                       if (ret)
+                               goto err;
+               }
        }
 
        switch (dev->cfg->ts_mode) {
@@ -488,6 +868,10 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                break;
        case M88DS3103_TS_PARALLEL:
                u8tmp = 0x02;
+               if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+                       u8tmp = 0x01;
+                       u8tmp1 = 0x01;
+               }
                break;
        case M88DS3103_TS_CI:
                u8tmp = 0x03;
@@ -516,6 +900,13 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
                u8tmp1 = 0x3f;
                u8tmp2 = 0x3f;
                break;
+       case M88DS3103_TS_PARALLEL:
+               if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+                       ret = m88ds3103_update_bits(dev, 0x29, 0x01, u8tmp1);
+                       if (ret)
+                               goto err;
+               }
+               /* fall through */
        default:
                u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk);
                u8tmp1 = u16tmp / 2 - 1;
@@ -543,6 +934,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
        else
                u8tmp = 0x06;
 
+       if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
+               m88ds3103b_set_mclk(dev, target_mclk / 1000);
+
        ret = regmap_write(dev->regmap, 0xc3, 0x08);
        if (ret)
                goto err;
@@ -578,6 +972,16 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
        if (ret)
                goto err;
 
+       if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+               /* enable/disable 192M LDPC clock */
+               ret = m88ds3103_update_bits(dev, 0x29, 0x10,
+                               (c->delivery_system == SYS_DVBS) ? 0x10 : 0x0);
+               if (ret)
+                       goto err;
+
+               ret = m88ds3103_update_bits(dev, 0xc9, 0x08, 0x08);
+       }
+
        dev_dbg(&client->dev, "carrier offset=%d\n",
                (tuner_frequency_khz - c->frequency));
 
@@ -642,7 +1046,7 @@ static int m88ds3103_init(struct dvb_frontend *fe)
        if (utmp)
                goto warm;
 
-       /* global reset, global diseqc reset, golbal fec reset */
+       /* global reset, global diseqc reset, global fec reset */
        ret = regmap_write(dev->regmap, 0x07, 0xe0);
        if (ret)
                goto err;
@@ -652,12 +1056,15 @@ static int m88ds3103_init(struct dvb_frontend *fe)
 
        /* cold state - try to download firmware */
        dev_info(&client->dev, "found a '%s' in cold state\n",
-                m88ds3103_ops.info.name);
+                dev->fe.ops.info.name);
 
-       if (dev->chip_id == M88RS6000_CHIP_ID)
+       if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
+               name = M88DS3103B_FIRMWARE;
+       else if (dev->chip_id == M88RS6000_CHIP_ID)
                name = M88RS6000_FIRMWARE;
        else
                name = M88DS3103_FIRMWARE;
+
        /* request the firmware, this will block and timeout */
        ret = request_firmware(&firmware, name, &client->dev);
        if (ret) {
@@ -700,10 +1107,16 @@ static int m88ds3103_init(struct dvb_frontend *fe)
        }
 
        dev_info(&client->dev, "found a '%s' in warm state\n",
-                m88ds3103_ops.info.name);
+                dev->fe.ops.info.name);
        dev_info(&client->dev, "firmware version: %X.%X\n",
                 (utmp >> 4) & 0xf, (utmp >> 0 & 0xf));
 
+       if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+               m88ds3103b_dt_write(dev, 0x21, 0x92);
+               m88ds3103b_dt_write(dev, 0x15, 0x6C);
+               m88ds3103b_dt_write(dev, 0x17, 0xC1);
+               m88ds3103b_dt_write(dev, 0x17, 0x81);
+       }
 warm:
        /* warm state */
        dev->warm = true;
@@ -1393,6 +1806,8 @@ static int m88ds3103_probe(struct i2c_client *client,
                goto err_kfree;
 
        dev->chip_id = utmp >> 1;
+       dev->chiptype = (u8)id->driver_data;
+
        dev_dbg(&client->dev, "chip_id=%02x\n", dev->chip_id);
 
        switch (dev->chip_id) {
@@ -1459,7 +1874,10 @@ static int m88ds3103_probe(struct i2c_client *client,
 
        /* create dvb_frontend */
        memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
-       if (dev->chip_id == M88RS6000_CHIP_ID)
+       if (dev->chiptype == M88DS3103_CHIPTYPE_3103B)
+               strscpy(dev->fe.ops.info.name, "Montage Technology M88DS3103B",
+                       sizeof(dev->fe.ops.info.name));
+       else if (dev->chip_id == M88RS6000_CHIP_ID)
                strscpy(dev->fe.ops.info.name, "Montage Technology M88RS6000",
                        sizeof(dev->fe.ops.info.name));
        if (!pdata->attach_in_use)
@@ -1470,6 +1888,26 @@ static int m88ds3103_probe(struct i2c_client *client,
        /* setup callbacks */
        pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend;
        pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter;
+
+       if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) {
+               /* enable i2c repeater for tuner */
+               m88ds3103_update_bits(dev, 0x11, 0x01, 0x01);
+
+               /* get frontend address */
+               ret = regmap_read(dev->regmap, 0x29, &utmp);
+               if (ret)
+                       goto err_kfree;
+               dev->dt_addr = ((utmp & 0x80) == 0) ? 0x42 >> 1 : 0x40 >> 1;
+               dev_err(&client->dev, "dt addr is 0x%02x", dev->dt_addr);
+
+               dev->dt_client = i2c_new_dummy_device(client->adapter,
+                                                     dev->dt_addr);
+               if (!dev->dt_client) {
+                       ret = -ENODEV;
+                       goto err_kfree;
+               }
+       }
+
        return 0;
 err_kfree:
        kfree(dev);
@@ -1484,6 +1922,9 @@ static int m88ds3103_remove(struct i2c_client *client)
 
        dev_dbg(&client->dev, "\n");
 
+       if (dev->dt_client)
+               i2c_unregister_device(dev->dt_client);
+
        i2c_mux_del_adapters(dev->muxc);
 
        kfree(dev);
@@ -1491,7 +1932,9 @@ static int m88ds3103_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id m88ds3103_id_table[] = {
-       {"m88ds3103", 0},
+       {"m88ds3103",  M88DS3103_CHIPTYPE_3103},
+       {"m88rs6000",  M88DS3103_CHIPTYPE_RS6000},
+       {"m88ds3103b", M88DS3103_CHIPTYPE_3103B},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table);
@@ -1513,3 +1956,4 @@ MODULE_DESCRIPTION("Montage Technology M88DS3103 DVB-S/S2 demodulator driver");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(M88DS3103_FIRMWARE);
 MODULE_FIRMWARE(M88RS6000_FIRMWARE);
+MODULE_FIRMWARE(M88DS3103B_FIRMWARE);
index c825032..aa5306f 100644 (file)
 #include <linux/regmap.h>
 #include <linux/math64.h>
 
-#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
-#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw"
+#define M88DS3103B_FIRMWARE "dvb-demod-m88ds3103b.fw"
+#define M88DS3103_FIRMWARE  "dvb-demod-m88ds3103.fw"
+#define M88RS6000_FIRMWARE  "dvb-demod-m88rs6000.fw"
+
 #define M88RS6000_CHIP_ID 0x74
 #define M88DS3103_CHIP_ID 0x70
 
+#define M88DS3103_CHIPTYPE_3103   0
+#define M88DS3103_CHIPTYPE_RS6000 1
+#define M88DS3103_CHIPTYPE_3103B  2
+
 struct m88ds3103_dev {
        struct i2c_client *client;
+       struct i2c_client *dt_client;
        struct regmap_config regmap_config;
        struct regmap *regmap;
        struct m88ds3103_config config;
@@ -35,10 +42,13 @@ struct m88ds3103_dev {
        struct i2c_mux_core *muxc;
        /* auto detect chip id to do different config */
        u8 chip_id;
+       /* chip type to differentiate m88rs6000 from m88ds3103b */
+       u8 chiptype;
        /* main mclk is calculated for M88RS6000 dynamically */
        s32 mclk;
        u64 post_bit_error;
        u64 post_bit_count;
+       u8 dt_addr;
 };
 
 struct m88ds3103_reg_val {
index 1953b00..685c0ac 100644 (file)
@@ -470,10 +470,11 @@ static int tda10071_read_status(struct dvb_frontend *fe, enum fe_status *status)
                        goto error;
 
                if (dev->delivery_system == SYS_DVBS) {
-                       dev->dvbv3_ber = buf[0] << 24 | buf[1] << 16 |
-                                        buf[2] << 8 | buf[3] << 0;
-                       dev->post_bit_error += buf[0] << 24 | buf[1] << 16 |
-                                              buf[2] << 8 | buf[3] << 0;
+                       u32 bit_error = buf[0] << 24 | buf[1] << 16 |
+                                       buf[2] << 8 | buf[3] << 0;
+
+                       dev->dvbv3_ber = bit_error;
+                       dev->post_bit_error += bit_error;
                        c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
                        c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
                        dev->block_error += buf[4] << 8 | buf[5] << 0;
index c68e002..125d596 100644 (file)
@@ -238,6 +238,7 @@ config VIDEO_ADV7604
        tristate "Analog Devices ADV7604 decoder"
        depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
        depends on GPIOLIB || COMPILE_TEST
+       select REGMAP_I2C
        select HDMI
        select V4L2_FWNODE
        help
@@ -379,6 +380,7 @@ config VIDEO_TVP5150
        tristate "Texas Instruments TVP5150 video decoder"
        depends on VIDEO_V4L2 && I2C
        select V4L2_FWNODE
+       select REGMAP_I2C
        help
          Support for the Texas Instruments TVP5150 video decoder.
 
@@ -584,6 +586,7 @@ config VIDEO_IMX214
        tristate "Sony IMX214 sensor support"
        depends on GPIOLIB && I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
        depends on V4L2_FWNODE
+       select REGMAP_I2C
        help
          This is a Video4Linux2 sensor driver for the Sony
          IMX214 camera.
@@ -591,6 +594,17 @@ config VIDEO_IMX214
          To compile this driver as a module, choose M here: the
          module will be called imx214.
 
+config VIDEO_IMX219
+       tristate "Sony IMX219 sensor support"
+       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       select V4L2_FWNODE
+       help
+         This is a Video4Linux2 sensor driver for the Sony
+         IMX219 camera.
+
+         To compile this driver as a module, choose M here: the
+         module will be called imx219.
+
 config VIDEO_IMX258
        tristate "Sony IMX258 sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
@@ -612,6 +626,7 @@ config VIDEO_IMX274
 config VIDEO_IMX290
        tristate "Sony IMX290 sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       select REGMAP_I2C
        select V4L2_FWNODE
        help
          This is a Video4Linux2 sensor driver for the Sony
@@ -804,6 +819,7 @@ config VIDEO_OV7670
 config VIDEO_OV7740
        tristate "OmniVision OV7740 sensor support"
        depends on I2C && VIDEO_V4L2
+       select REGMAP_I2C
        help
          This is a Video4Linux2 sensor driver for the OmniVision
          OV7740 VGA camera sensor.
index c147bb9..77bf7d0 100644 (file)
@@ -111,6 +111,7 @@ obj-$(CONFIG_VIDEO_OV2659)  += ov2659.o
 obj-$(CONFIG_VIDEO_TC358743)   += tc358743.o
 obj-$(CONFIG_VIDEO_HI556)      += hi556.o
 obj-$(CONFIG_VIDEO_IMX214)     += imx214.o
+obj-$(CONFIG_VIDEO_IMX219)     += imx219.o
 obj-$(CONFIG_VIDEO_IMX258)     += imx258.o
 obj-$(CONFIG_VIDEO_IMX274)     += imx274.o
 obj-$(CONFIG_VIDEO_IMX290)     += imx290.o
index 6528e23..00159da 100644 (file)
@@ -749,6 +749,17 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
        return ret;
 }
 
+static int adv7180_init_cfg(struct v4l2_subdev *sd,
+                           struct v4l2_subdev_pad_config *cfg)
+{
+       struct v4l2_subdev_format fmt = {
+               .which = cfg ? V4L2_SUBDEV_FORMAT_TRY
+                       : V4L2_SUBDEV_FORMAT_ACTIVE,
+       };
+
+       return adv7180_set_pad_format(sd, cfg, &fmt);
+}
+
 static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
                                 struct v4l2_mbus_config *cfg)
 {
@@ -854,6 +865,7 @@ static const struct v4l2_subdev_core_ops adv7180_core_ops = {
 };
 
 static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
+       .init_cfg = adv7180_init_cfg,
        .enum_mbus_code = adv7180_enum_mbus_code,
        .set_fmt = adv7180_set_pad_format,
        .get_fmt = adv7180_get_pad_format,
index adcaaa8..4175d06 100644 (file)
@@ -803,7 +803,6 @@ err_rpm_put:
 static int imx214_g_frame_interval(struct v4l2_subdev *subdev,
                                   struct v4l2_subdev_frame_interval *fival)
 {
-       fival->pad = 0;
        fival->interval.numerator = 1;
        fival->interval.denominator = IMX214_FPS;
 
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
new file mode 100644 (file)
index 0000000..cb03bde
--- /dev/null
@@ -0,0 +1,1481 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A V4L2 driver for Sony IMX219 cameras.
+ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd
+ *
+ * Based on Sony imx258 camera driver
+ * Copyright (C) 2018 Intel Corporation
+ *
+ * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver
+ * Copyright 2018 Qtechnology A/S
+ *
+ * Flip handling taken from the Sony IMX319 driver.
+ * Copyright (C) 2018 Intel Corporation
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+#include <asm/unaligned.h>
+
+#define IMX219_REG_VALUE_08BIT         1
+#define IMX219_REG_VALUE_16BIT         2
+
+#define IMX219_REG_MODE_SELECT         0x0100
+#define IMX219_MODE_STANDBY            0x00
+#define IMX219_MODE_STREAMING          0x01
+
+/* Chip ID */
+#define IMX219_REG_CHIP_ID             0x0000
+#define IMX219_CHIP_ID                 0x0219
+
+/* External clock frequency is 24.0M */
+#define IMX219_XCLK_FREQ               24000000
+
+/* Pixel rate is fixed at 182.4M for all the modes */
+#define IMX219_PIXEL_RATE              182400000
+
+#define IMX219_DEFAULT_LINK_FREQ       456000000
+
+/* V_TIMING internal */
+#define IMX219_REG_VTS                 0x0160
+#define IMX219_VTS_15FPS               0x0dc6
+#define IMX219_VTS_30FPS_1080P         0x06e3
+#define IMX219_VTS_30FPS_BINNED                0x06e3
+#define IMX219_VTS_30FPS_640x480       0x06e3
+#define IMX219_VTS_MAX                 0xffff
+
+#define IMX219_VBLANK_MIN              4
+
+/*Frame Length Line*/
+#define IMX219_FLL_MIN                 0x08a6
+#define IMX219_FLL_MAX                 0xffff
+#define IMX219_FLL_STEP                        1
+#define IMX219_FLL_DEFAULT             0x0c98
+
+/* HBLANK control - read only */
+#define IMX219_PPL_DEFAULT             3448
+
+/* Exposure control */
+#define IMX219_REG_EXPOSURE            0x015a
+#define IMX219_EXPOSURE_MIN            4
+#define IMX219_EXPOSURE_STEP           1
+#define IMX219_EXPOSURE_DEFAULT                0x640
+#define IMX219_EXPOSURE_MAX            65535
+
+/* Analog gain control */
+#define IMX219_REG_ANALOG_GAIN         0x0157
+#define IMX219_ANA_GAIN_MIN            0
+#define IMX219_ANA_GAIN_MAX            232
+#define IMX219_ANA_GAIN_STEP           1
+#define IMX219_ANA_GAIN_DEFAULT                0x0
+
+/* Digital gain control */
+#define IMX219_REG_DIGITAL_GAIN                0x0158
+#define IMX219_DGTL_GAIN_MIN           0x0100
+#define IMX219_DGTL_GAIN_MAX           0x0fff
+#define IMX219_DGTL_GAIN_DEFAULT       0x0100
+#define IMX219_DGTL_GAIN_STEP          1
+
+#define IMX219_REG_ORIENTATION         0x0172
+
+/* Test Pattern Control */
+#define IMX219_REG_TEST_PATTERN                0x0600
+#define IMX219_TEST_PATTERN_DISABLE    0
+#define IMX219_TEST_PATTERN_SOLID_COLOR        1
+#define IMX219_TEST_PATTERN_COLOR_BARS 2
+#define IMX219_TEST_PATTERN_GREY_COLOR 3
+#define IMX219_TEST_PATTERN_PN9                4
+
+/* Test pattern colour components */
+#define IMX219_REG_TESTP_RED           0x0602
+#define IMX219_REG_TESTP_GREENR                0x0604
+#define IMX219_REG_TESTP_BLUE          0x0606
+#define IMX219_REG_TESTP_GREENB                0x0608
+#define IMX219_TESTP_COLOUR_MIN                0
+#define IMX219_TESTP_COLOUR_MAX                0x03ff
+#define IMX219_TESTP_COLOUR_STEP       1
+#define IMX219_TESTP_RED_DEFAULT       IMX219_TESTP_COLOUR_MAX
+#define IMX219_TESTP_GREENR_DEFAULT    0
+#define IMX219_TESTP_BLUE_DEFAULT      0
+#define IMX219_TESTP_GREENB_DEFAULT    0
+
+struct imx219_reg {
+       u16 address;
+       u8 val;
+};
+
+struct imx219_reg_list {
+       unsigned int num_of_regs;
+       const struct imx219_reg *regs;
+};
+
+/* Mode : resolution and related config&values */
+struct imx219_mode {
+       /* Frame width */
+       unsigned int width;
+       /* Frame height */
+       unsigned int height;
+
+       /* V-timing */
+       unsigned int vts_def;
+
+       /* Default register values */
+       struct imx219_reg_list reg_list;
+};
+
+/*
+ * Register sets lifted off the i2C interface from the Raspberry Pi firmware
+ * driver.
+ * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7.
+ */
+static const struct imx219_reg mode_3280x2464_regs[] = {
+       {0x0100, 0x00},
+       {0x30eb, 0x0c},
+       {0x30eb, 0x05},
+       {0x300a, 0xff},
+       {0x300b, 0xff},
+       {0x30eb, 0x05},
+       {0x30eb, 0x09},
+       {0x0114, 0x01},
+       {0x0128, 0x00},
+       {0x012a, 0x18},
+       {0x012b, 0x00},
+       {0x0164, 0x00},
+       {0x0165, 0x00},
+       {0x0166, 0x0c},
+       {0x0167, 0xcf},
+       {0x0168, 0x00},
+       {0x0169, 0x00},
+       {0x016a, 0x09},
+       {0x016b, 0x9f},
+       {0x016c, 0x0c},
+       {0x016d, 0xd0},
+       {0x016e, 0x09},
+       {0x016f, 0xa0},
+       {0x0170, 0x01},
+       {0x0171, 0x01},
+       {0x0174, 0x00},
+       {0x0175, 0x00},
+       {0x0301, 0x05},
+       {0x0303, 0x01},
+       {0x0304, 0x03},
+       {0x0305, 0x03},
+       {0x0306, 0x00},
+       {0x0307, 0x39},
+       {0x030b, 0x01},
+       {0x030c, 0x00},
+       {0x030d, 0x72},
+       {0x0624, 0x0c},
+       {0x0625, 0xd0},
+       {0x0626, 0x09},
+       {0x0627, 0xa0},
+       {0x455e, 0x00},
+       {0x471e, 0x4b},
+       {0x4767, 0x0f},
+       {0x4750, 0x14},
+       {0x4540, 0x00},
+       {0x47b4, 0x14},
+       {0x4713, 0x30},
+       {0x478b, 0x10},
+       {0x478f, 0x10},
+       {0x4793, 0x10},
+       {0x4797, 0x0e},
+       {0x479b, 0x0e},
+       {0x0162, 0x0d},
+       {0x0163, 0x78},
+};
+
+static const struct imx219_reg mode_1920_1080_regs[] = {
+       {0x0100, 0x00},
+       {0x30eb, 0x05},
+       {0x30eb, 0x0c},
+       {0x300a, 0xff},
+       {0x300b, 0xff},
+       {0x30eb, 0x05},
+       {0x30eb, 0x09},
+       {0x0114, 0x01},
+       {0x0128, 0x00},
+       {0x012a, 0x18},
+       {0x012b, 0x00},
+       {0x0162, 0x0d},
+       {0x0163, 0x78},
+       {0x0164, 0x02},
+       {0x0165, 0xa8},
+       {0x0166, 0x0a},
+       {0x0167, 0x27},
+       {0x0168, 0x02},
+       {0x0169, 0xb4},
+       {0x016a, 0x06},
+       {0x016b, 0xeb},
+       {0x016c, 0x07},
+       {0x016d, 0x80},
+       {0x016e, 0x04},
+       {0x016f, 0x38},
+       {0x0170, 0x01},
+       {0x0171, 0x01},
+       {0x0174, 0x00},
+       {0x0175, 0x00},
+       {0x0301, 0x05},
+       {0x0303, 0x01},
+       {0x0304, 0x03},
+       {0x0305, 0x03},
+       {0x0306, 0x00},
+       {0x0307, 0x39},
+       {0x030b, 0x01},
+       {0x030c, 0x00},
+       {0x030d, 0x72},
+       {0x0624, 0x07},
+       {0x0625, 0x80},
+       {0x0626, 0x04},
+       {0x0627, 0x38},
+       {0x455e, 0x00},
+       {0x471e, 0x4b},
+       {0x4767, 0x0f},
+       {0x4750, 0x14},
+       {0x4540, 0x00},
+       {0x47b4, 0x14},
+       {0x4713, 0x30},
+       {0x478b, 0x10},
+       {0x478f, 0x10},
+       {0x4793, 0x10},
+       {0x4797, 0x0e},
+       {0x479b, 0x0e},
+       {0x0162, 0x0d},
+       {0x0163, 0x78},
+};
+
+static const struct imx219_reg mode_1640_1232_regs[] = {
+       {0x0100, 0x00},
+       {0x30eb, 0x0c},
+       {0x30eb, 0x05},
+       {0x300a, 0xff},
+       {0x300b, 0xff},
+       {0x30eb, 0x05},
+       {0x30eb, 0x09},
+       {0x0114, 0x01},
+       {0x0128, 0x00},
+       {0x012a, 0x18},
+       {0x012b, 0x00},
+       {0x0164, 0x00},
+       {0x0165, 0x00},
+       {0x0166, 0x0c},
+       {0x0167, 0xcf},
+       {0x0168, 0x00},
+       {0x0169, 0x00},
+       {0x016a, 0x09},
+       {0x016b, 0x9f},
+       {0x016c, 0x06},
+       {0x016d, 0x68},
+       {0x016e, 0x04},
+       {0x016f, 0xd0},
+       {0x0170, 0x01},
+       {0x0171, 0x01},
+       {0x0174, 0x01},
+       {0x0175, 0x01},
+       {0x0301, 0x05},
+       {0x0303, 0x01},
+       {0x0304, 0x03},
+       {0x0305, 0x03},
+       {0x0306, 0x00},
+       {0x0307, 0x39},
+       {0x030b, 0x01},
+       {0x030c, 0x00},
+       {0x030d, 0x72},
+       {0x0624, 0x06},
+       {0x0625, 0x68},
+       {0x0626, 0x04},
+       {0x0627, 0xd0},
+       {0x455e, 0x00},
+       {0x471e, 0x4b},
+       {0x4767, 0x0f},
+       {0x4750, 0x14},
+       {0x4540, 0x00},
+       {0x47b4, 0x14},
+       {0x4713, 0x30},
+       {0x478b, 0x10},
+       {0x478f, 0x10},
+       {0x4793, 0x10},
+       {0x4797, 0x0e},
+       {0x479b, 0x0e},
+       {0x0162, 0x0d},
+       {0x0163, 0x78},
+};
+
+static const struct imx219_reg mode_640_480_regs[] = {
+       {0x0100, 0x00},
+       {0x30eb, 0x05},
+       {0x30eb, 0x0c},
+       {0x300a, 0xff},
+       {0x300b, 0xff},
+       {0x30eb, 0x05},
+       {0x30eb, 0x09},
+       {0x0114, 0x01},
+       {0x0128, 0x00},
+       {0x012a, 0x18},
+       {0x012b, 0x00},
+       {0x0162, 0x0d},
+       {0x0163, 0x78},
+       {0x0164, 0x03},
+       {0x0165, 0xe8},
+       {0x0166, 0x08},
+       {0x0167, 0xe7},
+       {0x0168, 0x02},
+       {0x0169, 0xf0},
+       {0x016a, 0x06},
+       {0x016b, 0xaf},
+       {0x016c, 0x02},
+       {0x016d, 0x80},
+       {0x016e, 0x01},
+       {0x016f, 0xe0},
+       {0x0170, 0x01},
+       {0x0171, 0x01},
+       {0x0174, 0x03},
+       {0x0175, 0x03},
+       {0x0301, 0x05},
+       {0x0303, 0x01},
+       {0x0304, 0x03},
+       {0x0305, 0x03},
+       {0x0306, 0x00},
+       {0x0307, 0x39},
+       {0x030b, 0x01},
+       {0x030c, 0x00},
+       {0x030d, 0x72},
+       {0x0624, 0x06},
+       {0x0625, 0x68},
+       {0x0626, 0x04},
+       {0x0627, 0xd0},
+       {0x455e, 0x00},
+       {0x471e, 0x4b},
+       {0x4767, 0x0f},
+       {0x4750, 0x14},
+       {0x4540, 0x00},
+       {0x47b4, 0x14},
+       {0x4713, 0x30},
+       {0x478b, 0x10},
+       {0x478f, 0x10},
+       {0x4793, 0x10},
+       {0x4797, 0x0e},
+       {0x479b, 0x0e},
+};
+
+static const struct imx219_reg raw8_framefmt_regs[] = {
+       {0x018c, 0x08},
+       {0x018d, 0x08},
+       {0x0309, 0x08},
+};
+
+static const struct imx219_reg raw10_framefmt_regs[] = {
+       {0x018c, 0x0a},
+       {0x018d, 0x0a},
+       {0x0309, 0x0a},
+};
+
+static const char * const imx219_test_pattern_menu[] = {
+       "Disabled",
+       "Color Bars",
+       "Solid Color",
+       "Grey Color Bars",
+       "PN9"
+};
+
+static const int imx219_test_pattern_val[] = {
+       IMX219_TEST_PATTERN_DISABLE,
+       IMX219_TEST_PATTERN_COLOR_BARS,
+       IMX219_TEST_PATTERN_SOLID_COLOR,
+       IMX219_TEST_PATTERN_GREY_COLOR,
+       IMX219_TEST_PATTERN_PN9,
+};
+
+/* regulator supplies */
+static const char * const imx219_supply_name[] = {
+       /* Supplies can be enabled in any order */
+       "VANA",  /* Analog (2.8V) supply */
+       "VDIG",  /* Digital Core (1.8V) supply */
+       "VDDL",  /* IF (1.2V) supply */
+};
+
+#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name)
+
+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 codes[] = {
+       MEDIA_BUS_FMT_SRGGB10_1X10,
+       MEDIA_BUS_FMT_SGRBG10_1X10,
+       MEDIA_BUS_FMT_SGBRG10_1X10,
+       MEDIA_BUS_FMT_SBGGR10_1X10,
+
+       MEDIA_BUS_FMT_SRGGB8_1X8,
+       MEDIA_BUS_FMT_SGRBG8_1X8,
+       MEDIA_BUS_FMT_SGBRG8_1X8,
+       MEDIA_BUS_FMT_SBGGR8_1X8,
+};
+
+/*
+ * Initialisation delay between XCLR low->high and the moment when the sensor
+ * can start capture (i.e. can leave software stanby) must be not less than:
+ *   t4 + max(t5, t6 + <time to initialize the sensor register over I2C>)
+ * where
+ *   t4 is fixed, and is max 200uS,
+ *   t5 is fixed, and is 6000uS,
+ *   t6 depends on the sensor external clock, and is max 32000 clock periods.
+ * As per sensor datasheet, the external clock must be from 6MHz to 27MHz.
+ * So for any acceptable external clock t6 is always within the range of
+ * 1185 to 5333 uS, and is always less than t5.
+ * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then
+ * initialize the sensor over I2C, and then exit the software standby.
+ *
+ * This start-up time can be optimized a bit more, if we start the writes
+ * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor
+ * initialization over I2C may complete before (t4+t5) expires, and we must
+ * ensure that capture is not started before (t4+t5).
+ *
+ * This delay doesn't account for the power supply startup time. If needed,
+ * this should be taken care of via the regulator framework. E.g. in the
+ * case of DT for regulator-fixed one should define the startup-delay-us
+ * property.
+ */
+#define IMX219_XCLR_MIN_DELAY_US       6200
+#define IMX219_XCLR_DELAY_RANGE_US     1000
+
+/* Mode configs */
+static const struct imx219_mode supported_modes[] = {
+       {
+               /* 8MPix 15fps mode */
+               .width = 3280,
+               .height = 2464,
+               .vts_def = IMX219_VTS_15FPS,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),
+                       .regs = mode_3280x2464_regs,
+               },
+       },
+       {
+               /* 1080P 30fps cropped */
+               .width = 1920,
+               .height = 1080,
+               .vts_def = IMX219_VTS_30FPS_1080P,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs),
+                       .regs = mode_1920_1080_regs,
+               },
+       },
+       {
+               /* 2x2 binned 30fps mode */
+               .width = 1640,
+               .height = 1232,
+               .vts_def = IMX219_VTS_30FPS_BINNED,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs),
+                       .regs = mode_1640_1232_regs,
+               },
+       },
+       {
+               /* 640x480 30fps mode */
+               .width = 640,
+               .height = 480,
+               .vts_def = IMX219_VTS_30FPS_640x480,
+               .reg_list = {
+                       .num_of_regs = ARRAY_SIZE(mode_640_480_regs),
+                       .regs = mode_640_480_regs,
+               },
+       },
+};
+
+struct imx219 {
+       struct v4l2_subdev sd;
+       struct media_pad pad;
+
+       struct v4l2_mbus_framefmt fmt;
+
+       struct clk *xclk; /* system clock to IMX219 */
+       u32 xclk_freq;
+
+       struct gpio_desc *reset_gpio;
+       struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES];
+
+       struct v4l2_ctrl_handler ctrl_handler;
+       /* V4L2 Controls */
+       struct v4l2_ctrl *pixel_rate;
+       struct v4l2_ctrl *exposure;
+       struct v4l2_ctrl *vflip;
+       struct v4l2_ctrl *hflip;
+       struct v4l2_ctrl *vblank;
+       struct v4l2_ctrl *hblank;
+
+       /* Current mode */
+       const struct imx219_mode *mode;
+
+       /*
+        * Mutex for serialized access:
+        * Protect sensor module set pad format and start/stop streaming safely.
+        */
+       struct mutex mutex;
+
+       /* Streaming on/off */
+       bool streaming;
+};
+
+static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd)
+{
+       return container_of(_sd, struct imx219, sd);
+}
+
+/* Read registers up to 2 at a time */
+static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       struct i2c_msg msgs[2];
+       u8 addr_buf[2] = { reg >> 8, reg & 0xff };
+       u8 data_buf[4] = { 0, };
+       int ret;
+
+       if (len > 4)
+               return -EINVAL;
+
+       /* Write register address */
+       msgs[0].addr = client->addr;
+       msgs[0].flags = 0;
+       msgs[0].len = ARRAY_SIZE(addr_buf);
+       msgs[0].buf = addr_buf;
+
+       /* Read data from register */
+       msgs[1].addr = client->addr;
+       msgs[1].flags = I2C_M_RD;
+       msgs[1].len = len;
+       msgs[1].buf = &data_buf[4 - len];
+
+       ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+       if (ret != ARRAY_SIZE(msgs))
+               return -EIO;
+
+       *val = get_unaligned_be32(data_buf);
+
+       return 0;
+}
+
+/* Write registers up to 2 at a time */
+static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       u8 buf[6];
+
+       if (len > 4)
+               return -EINVAL;
+
+       put_unaligned_be16(reg, buf);
+       put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
+       if (i2c_master_send(client, buf, len + 2) != len + 2)
+               return -EIO;
+
+       return 0;
+}
+
+/* Write a list of registers */
+static int imx219_write_regs(struct imx219 *imx219,
+                            const struct imx219_reg *regs, u32 len)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < len; i++) {
+               ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val);
+               if (ret) {
+                       dev_err_ratelimited(&client->dev,
+                                           "Failed to write reg 0x%4.4x. error = %d\n",
+                                           regs[i].address, ret);
+
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/* Get bayer order based on flip setting. */
+static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
+{
+       unsigned int i;
+
+       lockdep_assert_held(&imx219->mutex);
+
+       for (i = 0; i < ARRAY_SIZE(codes); i++)
+               if (codes[i] == code)
+                       break;
+
+       if (i >= ARRAY_SIZE(codes))
+               i = 0;
+
+       i = (i & ~3) | (imx219->vflip->val ? 2 : 0) |
+           (imx219->hflip->val ? 1 : 0);
+
+       return codes[i];
+}
+
+static void imx219_set_default_format(struct imx219 *imx219)
+{
+       struct v4l2_mbus_framefmt *fmt;
+
+       fmt = &imx219->fmt;
+       fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10;
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;
+       fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+       fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+                                                         fmt->colorspace,
+                                                         fmt->ycbcr_enc);
+       fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+       fmt->width = supported_modes[0].width;
+       fmt->height = supported_modes[0].height;
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct imx219 *imx219 = to_imx219(sd);
+       struct v4l2_mbus_framefmt *try_fmt =
+               v4l2_subdev_get_try_format(sd, fh->pad, 0);
+
+       mutex_lock(&imx219->mutex);
+
+       /* Initialize try_fmt */
+       try_fmt->width = supported_modes[0].width;
+       try_fmt->height = supported_modes[0].height;
+       try_fmt->code = imx219_get_format_code(imx219,
+                                              MEDIA_BUS_FMT_SRGGB10_1X10);
+       try_fmt->field = V4L2_FIELD_NONE;
+
+       mutex_unlock(&imx219->mutex);
+
+       return 0;
+}
+
+static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct imx219 *imx219 =
+               container_of(ctrl->handler, struct imx219, ctrl_handler);
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       int ret;
+
+       if (ctrl->id == V4L2_CID_VBLANK) {
+               int exposure_max, exposure_def;
+
+               /* Update max exposure while meeting expected vblanking */
+               exposure_max = imx219->mode->height + ctrl->val - 4;
+               exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+                       exposure_max : IMX219_EXPOSURE_DEFAULT;
+               __v4l2_ctrl_modify_range(imx219->exposure,
+                                        imx219->exposure->minimum,
+                                        exposure_max, imx219->exposure->step,
+                                        exposure_def);
+       }
+
+       /*
+        * Applying V4L2 control value only happens
+        * when power is up for streaming
+        */
+       if (pm_runtime_get_if_in_use(&client->dev) == 0)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_ANALOGUE_GAIN:
+               ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN,
+                                      IMX219_REG_VALUE_08BIT, ctrl->val);
+               break;
+       case V4L2_CID_EXPOSURE:
+               ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE,
+                                      IMX219_REG_VALUE_16BIT, ctrl->val);
+               break;
+       case V4L2_CID_DIGITAL_GAIN:
+               ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN,
+                                      IMX219_REG_VALUE_16BIT, ctrl->val);
+               break;
+       case V4L2_CID_TEST_PATTERN:
+               ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN,
+                                      IMX219_REG_VALUE_16BIT,
+                                      imx219_test_pattern_val[ctrl->val]);
+               break;
+       case V4L2_CID_HFLIP:
+       case V4L2_CID_VFLIP:
+               ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1,
+                                      imx219->hflip->val |
+                                      imx219->vflip->val << 1);
+               break;
+       case V4L2_CID_VBLANK:
+               ret = imx219_write_reg(imx219, IMX219_REG_VTS,
+                                      IMX219_REG_VALUE_16BIT,
+                                      imx219->mode->height + ctrl->val);
+               break;
+       case V4L2_CID_TEST_PATTERN_RED:
+               ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED,
+                                      IMX219_REG_VALUE_16BIT, ctrl->val);
+               break;
+       case V4L2_CID_TEST_PATTERN_GREENR:
+               ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR,
+                                      IMX219_REG_VALUE_16BIT, ctrl->val);
+               break;
+       case V4L2_CID_TEST_PATTERN_BLUE:
+               ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE,
+                                      IMX219_REG_VALUE_16BIT, ctrl->val);
+               break;
+       case V4L2_CID_TEST_PATTERN_GREENB:
+               ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB,
+                                      IMX219_REG_VALUE_16BIT, ctrl->val);
+               break;
+       default:
+               dev_info(&client->dev,
+                        "ctrl(id:0x%x,val:0x%x) is not handled\n",
+                        ctrl->id, ctrl->val);
+               ret = -EINVAL;
+               break;
+       }
+
+       pm_runtime_put(&client->dev);
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
+       .s_ctrl = imx219_set_ctrl,
+};
+
+static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct imx219 *imx219 = to_imx219(sd);
+
+       if (code->index >= (ARRAY_SIZE(codes) / 4))
+               return -EINVAL;
+
+       code->code = imx219_get_format_code(imx219, codes[code->index * 4]);
+
+       return 0;
+}
+
+static int imx219_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct imx219 *imx219 = to_imx219(sd);
+
+       if (fse->index >= ARRAY_SIZE(supported_modes))
+               return -EINVAL;
+
+       if (fse->code != imx219_get_format_code(imx219, imx219->fmt.code))
+               return -EINVAL;
+
+       fse->min_width = supported_modes[fse->index].width;
+       fse->max_width = fse->min_width;
+       fse->min_height = supported_modes[fse->index].height;
+       fse->max_height = fse->min_height;
+
+       return 0;
+}
+
+static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt)
+{
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;
+       fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+       fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+                                                         fmt->colorspace,
+                                                         fmt->ycbcr_enc);
+       fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+}
+
+static void imx219_update_pad_format(struct imx219 *imx219,
+                                    const struct imx219_mode *mode,
+                                    struct v4l2_subdev_format *fmt)
+{
+       fmt->format.width = mode->width;
+       fmt->format.height = mode->height;
+       fmt->format.field = V4L2_FIELD_NONE;
+       imx219_reset_colorspace(&fmt->format);
+}
+
+static int __imx219_get_pad_format(struct imx219 *imx219,
+                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_format *fmt)
+{
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               struct v4l2_mbus_framefmt *try_fmt =
+                       v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad);
+               /* update the code which could change due to vflip or hflip: */
+               try_fmt->code = imx219_get_format_code(imx219, try_fmt->code);
+               fmt->format = *try_fmt;
+       } else {
+               imx219_update_pad_format(imx219, imx219->mode, fmt);
+               fmt->format.code = imx219_get_format_code(imx219,
+                                                         imx219->fmt.code);
+       }
+
+       return 0;
+}
+
+static int imx219_get_pad_format(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_format *fmt)
+{
+       struct imx219 *imx219 = to_imx219(sd);
+       int ret;
+
+       mutex_lock(&imx219->mutex);
+       ret = __imx219_get_pad_format(imx219, cfg, fmt);
+       mutex_unlock(&imx219->mutex);
+
+       return ret;
+}
+
+static int imx219_set_pad_format(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_format *fmt)
+{
+       struct imx219 *imx219 = to_imx219(sd);
+       const struct imx219_mode *mode;
+       struct v4l2_mbus_framefmt *framefmt;
+       int exposure_max, exposure_def, hblank;
+       unsigned int i;
+
+       mutex_lock(&imx219->mutex);
+
+       for (i = 0; i < ARRAY_SIZE(codes); i++)
+               if (codes[i] == fmt->format.code)
+                       break;
+       if (i >= ARRAY_SIZE(codes))
+               i = 0;
+
+       /* Bayer order varies with flips */
+       fmt->format.code = imx219_get_format_code(imx219, codes[i]);
+
+       mode = v4l2_find_nearest_size(supported_modes,
+                                     ARRAY_SIZE(supported_modes),
+                                     width, height,
+                                     fmt->format.width, fmt->format.height);
+       imx219_update_pad_format(imx219, mode, fmt);
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
+               *framefmt = fmt->format;
+       } else if (imx219->mode != mode ||
+                  imx219->fmt.code != fmt->format.code) {
+               imx219->fmt = fmt->format;
+               imx219->mode = mode;
+               /* Update limits and set FPS to default */
+               __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
+                                        IMX219_VTS_MAX - mode->height, 1,
+                                        mode->vts_def - mode->height);
+               __v4l2_ctrl_s_ctrl(imx219->vblank,
+                                  mode->vts_def - mode->height);
+               /* Update max exposure while meeting expected vblanking */
+               exposure_max = mode->vts_def - 4;
+               exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+                       exposure_max : IMX219_EXPOSURE_DEFAULT;
+               __v4l2_ctrl_modify_range(imx219->exposure,
+                                        imx219->exposure->minimum,
+                                        exposure_max, imx219->exposure->step,
+                                        exposure_def);
+               /*
+                * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
+                * depends on mode->width only, and is not changeble in any
+                * way other than changing the mode.
+                */
+               hblank = IMX219_PPL_DEFAULT - mode->width;
+               __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
+                                        hblank);
+       }
+
+       mutex_unlock(&imx219->mutex);
+
+       return 0;
+}
+
+static int imx219_set_framefmt(struct imx219 *imx219)
+{
+       switch (imx219->fmt.code) {
+       case MEDIA_BUS_FMT_SRGGB8_1X8:
+       case MEDIA_BUS_FMT_SGRBG8_1X8:
+       case MEDIA_BUS_FMT_SGBRG8_1X8:
+       case MEDIA_BUS_FMT_SBGGR8_1X8:
+               return imx219_write_regs(imx219, raw8_framefmt_regs,
+                                       ARRAY_SIZE(raw8_framefmt_regs));
+
+       case MEDIA_BUS_FMT_SRGGB10_1X10:
+       case MEDIA_BUS_FMT_SGRBG10_1X10:
+       case MEDIA_BUS_FMT_SGBRG10_1X10:
+       case MEDIA_BUS_FMT_SBGGR10_1X10:
+               return imx219_write_regs(imx219, raw10_framefmt_regs,
+                                       ARRAY_SIZE(raw10_framefmt_regs));
+       }
+
+       return -EINVAL;
+}
+
+static int imx219_start_streaming(struct imx219 *imx219)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       const struct imx219_reg_list *reg_list;
+       int ret;
+
+       /* Apply default values of current mode */
+       reg_list = &imx219->mode->reg_list;
+       ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs);
+       if (ret) {
+               dev_err(&client->dev, "%s failed to set mode\n", __func__);
+               return ret;
+       }
+
+       ret = imx219_set_framefmt(imx219);
+       if (ret) {
+               dev_err(&client->dev, "%s failed to set frame format: %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       /* Apply customized values from user */
+       ret =  __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler);
+       if (ret)
+               return ret;
+
+       /* set stream on register */
+       return imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+                               IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
+}
+
+static void imx219_stop_streaming(struct imx219 *imx219)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       int ret;
+
+       /* set stream off register */
+       ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+                              IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
+       if (ret)
+               dev_err(&client->dev, "%s failed to set stream\n", __func__);
+}
+
+static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct imx219 *imx219 = to_imx219(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       mutex_lock(&imx219->mutex);
+       if (imx219->streaming == enable) {
+               mutex_unlock(&imx219->mutex);
+               return 0;
+       }
+
+       if (enable) {
+               ret = pm_runtime_get_sync(&client->dev);
+               if (ret < 0) {
+                       pm_runtime_put_noidle(&client->dev);
+                       goto err_unlock;
+               }
+
+               /*
+                * Apply default & customized values
+                * and then start streaming.
+                */
+               ret = imx219_start_streaming(imx219);
+               if (ret)
+                       goto err_rpm_put;
+       } else {
+               imx219_stop_streaming(imx219);
+               pm_runtime_put(&client->dev);
+       }
+
+       imx219->streaming = enable;
+
+       /* vflip and hflip cannot change during streaming */
+       __v4l2_ctrl_grab(imx219->vflip, enable);
+       __v4l2_ctrl_grab(imx219->hflip, enable);
+
+       mutex_unlock(&imx219->mutex);
+
+       return ret;
+
+err_rpm_put:
+       pm_runtime_put(&client->dev);
+err_unlock:
+       mutex_unlock(&imx219->mutex);
+
+       return ret;
+}
+
+/* Power/clock management functions */
+static int imx219_power_on(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx219 *imx219 = to_imx219(sd);
+       int ret;
+
+       ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
+                                   imx219->supplies);
+       if (ret) {
+               dev_err(&client->dev, "%s: failed to enable regulators\n",
+                       __func__);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(imx219->xclk);
+       if (ret) {
+               dev_err(&client->dev, "%s: failed to enable clock\n",
+                       __func__);
+               goto reg_off;
+       }
+
+       gpiod_set_value_cansleep(imx219->reset_gpio, 1);
+       usleep_range(IMX219_XCLR_MIN_DELAY_US,
+                    IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
+
+       return 0;
+
+reg_off:
+       regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
+
+       return ret;
+}
+
+static int imx219_power_off(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx219 *imx219 = to_imx219(sd);
+
+       gpiod_set_value_cansleep(imx219->reset_gpio, 0);
+       regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
+       clk_disable_unprepare(imx219->xclk);
+
+       return 0;
+}
+
+static int __maybe_unused imx219_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx219 *imx219 = to_imx219(sd);
+
+       if (imx219->streaming)
+               imx219_stop_streaming(imx219);
+
+       return 0;
+}
+
+static int __maybe_unused imx219_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx219 *imx219 = to_imx219(sd);
+       int ret;
+
+       if (imx219->streaming) {
+               ret = imx219_start_streaming(imx219);
+               if (ret)
+                       goto error;
+       }
+
+       return 0;
+
+error:
+       imx219_stop_streaming(imx219);
+       imx219->streaming = 0;
+
+       return ret;
+}
+
+static int imx219_get_regulators(struct imx219 *imx219)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       unsigned int i;
+
+       for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
+               imx219->supplies[i].supply = imx219_supply_name[i];
+
+       return devm_regulator_bulk_get(&client->dev,
+                                      IMX219_NUM_SUPPLIES,
+                                      imx219->supplies);
+}
+
+/* Verify chip ID */
+static int imx219_identify_module(struct imx219 *imx219)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       int ret;
+       u32 val;
+
+       ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID,
+                             IMX219_REG_VALUE_16BIT, &val);
+       if (ret) {
+               dev_err(&client->dev, "failed to read chip id %x\n",
+                       IMX219_CHIP_ID);
+               return ret;
+       }
+
+       if (val != IMX219_CHIP_ID) {
+               dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+                       IMX219_CHIP_ID, val);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_subdev_core_ops imx219_core_ops = {
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops imx219_video_ops = {
+       .s_stream = imx219_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
+       .enum_mbus_code = imx219_enum_mbus_code,
+       .get_fmt = imx219_get_pad_format,
+       .set_fmt = imx219_set_pad_format,
+       .enum_frame_size = imx219_enum_frame_size,
+};
+
+static const struct v4l2_subdev_ops imx219_subdev_ops = {
+       .core = &imx219_core_ops,
+       .video = &imx219_video_ops,
+       .pad = &imx219_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops imx219_internal_ops = {
+       .open = imx219_open,
+};
+
+/* Initialize control handlers */
+static int imx219_init_controls(struct imx219 *imx219)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
+       struct v4l2_ctrl_handler *ctrl_hdlr;
+       unsigned int height = imx219->mode->height;
+       int exposure_max, exposure_def, hblank;
+       int i, ret;
+
+       ctrl_hdlr = &imx219->ctrl_handler;
+       ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
+       if (ret)
+               return ret;
+
+       mutex_init(&imx219->mutex);
+       ctrl_hdlr->lock = &imx219->mutex;
+
+       /* By default, PIXEL_RATE is read only */
+       imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+                                              V4L2_CID_PIXEL_RATE,
+                                              IMX219_PIXEL_RATE,
+                                              IMX219_PIXEL_RATE, 1,
+                                              IMX219_PIXEL_RATE);
+
+       /* Initial vblank/hblank/exposure parameters based on current mode */
+       imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+                                          V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
+                                          IMX219_VTS_MAX - height, 1,
+                                          imx219->mode->vts_def - height);
+       hblank = IMX219_PPL_DEFAULT - imx219->mode->width;
+       imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+                                          V4L2_CID_HBLANK, hblank, hblank,
+                                          1, hblank);
+       if (imx219->hblank)
+               imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+       exposure_max = imx219->mode->vts_def - 4;
+       exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
+               exposure_max : IMX219_EXPOSURE_DEFAULT;
+       imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+                                            V4L2_CID_EXPOSURE,
+                                            IMX219_EXPOSURE_MIN, exposure_max,
+                                            IMX219_EXPOSURE_STEP,
+                                            exposure_def);
+
+       v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+                         IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
+                         IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
+
+       v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+                         IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
+                         IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
+
+       imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+                                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+       if (imx219->hflip)
+               imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+       imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+                                         V4L2_CID_VFLIP, 0, 1, 1, 0);
+       if (imx219->vflip)
+               imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+       v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
+                                    V4L2_CID_TEST_PATTERN,
+                                    ARRAY_SIZE(imx219_test_pattern_menu) - 1,
+                                    0, 0, imx219_test_pattern_menu);
+       for (i = 0; i < 4; i++) {
+               /*
+                * The assumption is that
+                * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
+                * V4L2_CID_TEST_PATTERN_BLUE   == V4L2_CID_TEST_PATTERN_RED + 2
+                * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
+                */
+               v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
+                                 V4L2_CID_TEST_PATTERN_RED + i,
+                                 IMX219_TESTP_COLOUR_MIN,
+                                 IMX219_TESTP_COLOUR_MAX,
+                                 IMX219_TESTP_COLOUR_STEP,
+                                 IMX219_TESTP_COLOUR_MAX);
+               /* The "Solid color" pattern is white by default */
+       }
+
+       if (ctrl_hdlr->error) {
+               ret = ctrl_hdlr->error;
+               dev_err(&client->dev, "%s control init failed (%d)\n",
+                       __func__, ret);
+               goto error;
+       }
+
+       imx219->sd.ctrl_handler = ctrl_hdlr;
+
+       return 0;
+
+error:
+       v4l2_ctrl_handler_free(ctrl_hdlr);
+       mutex_destroy(&imx219->mutex);
+
+       return ret;
+}
+
+static void imx219_free_controls(struct imx219 *imx219)
+{
+       v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
+       mutex_destroy(&imx219->mutex);
+}
+
+static int imx219_check_hwcfg(struct device *dev)
+{
+       struct fwnode_handle *endpoint;
+       struct v4l2_fwnode_endpoint ep_cfg = {
+               .bus_type = V4L2_MBUS_CSI2_DPHY
+       };
+       int ret = -EINVAL;
+
+       endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
+       if (!endpoint) {
+               dev_err(dev, "endpoint node not found\n");
+               return -EINVAL;
+       }
+
+       if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) {
+               dev_err(dev, "could not parse endpoint\n");
+               goto error_out;
+       }
+
+       /* Check the number of MIPI CSI2 data lanes */
+       if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) {
+               dev_err(dev, "only 2 data lanes are currently supported\n");
+               goto error_out;
+       }
+
+       /* Check the link frequency set in device tree */
+       if (!ep_cfg.nr_of_link_frequencies) {
+               dev_err(dev, "link-frequency property not found in DT\n");
+               goto error_out;
+       }
+
+       if (ep_cfg.nr_of_link_frequencies != 1 ||
+           ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) {
+               dev_err(dev, "Link frequency not supported: %lld\n",
+                       ep_cfg.link_frequencies[0]);
+               goto error_out;
+       }
+
+       ret = 0;
+
+error_out:
+       v4l2_fwnode_endpoint_free(&ep_cfg);
+       fwnode_handle_put(endpoint);
+
+       return ret;
+}
+
+static int imx219_probe(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       struct imx219 *imx219;
+       int ret;
+
+       imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL);
+       if (!imx219)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops);
+
+       /* Check the hardware configuration in device tree */
+       if (imx219_check_hwcfg(dev))
+               return -EINVAL;
+
+       /* Get system clock (xclk) */
+       imx219->xclk = devm_clk_get(dev, NULL);
+       if (IS_ERR(imx219->xclk)) {
+               dev_err(dev, "failed to get xclk\n");
+               return PTR_ERR(imx219->xclk);
+       }
+
+       imx219->xclk_freq = clk_get_rate(imx219->xclk);
+       if (imx219->xclk_freq != IMX219_XCLK_FREQ) {
+               dev_err(dev, "xclk frequency not supported: %d Hz\n",
+                       imx219->xclk_freq);
+               return -EINVAL;
+       }
+
+       ret = imx219_get_regulators(imx219);
+       if (ret) {
+               dev_err(dev, "failed to get regulators\n");
+               return ret;
+       }
+
+       /* Request optional enable pin */
+       imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+                                                    GPIOD_OUT_HIGH);
+
+       /*
+        * The sensor must be powered for imx219_identify_module()
+        * to be able to read the CHIP_ID register
+        */
+       ret = imx219_power_on(dev);
+       if (ret)
+               return ret;
+
+       ret = imx219_identify_module(imx219);
+       if (ret)
+               goto error_power_off;
+
+       /* Set default mode to max resolution */
+       imx219->mode = &supported_modes[0];
+
+       /* sensor doesn't enter LP-11 state upon power up until and unless
+        * streaming is started, so upon power up switch the modes to:
+        * streaming -> standby
+        */
+       ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+                              IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING);
+       if (ret < 0)
+               goto error_power_off;
+       usleep_range(100, 110);
+
+       /* put sensor back to standby mode */
+       ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT,
+                              IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY);
+       if (ret < 0)
+               goto error_power_off;
+       usleep_range(100, 110);
+
+       ret = imx219_init_controls(imx219);
+       if (ret)
+               goto error_power_off;
+
+       /* Initialize subdev */
+       imx219->sd.internal_ops = &imx219_internal_ops;
+       imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+       /* Initialize source pad */
+       imx219->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+       /* Initialize default format */
+       imx219_set_default_format(imx219);
+
+       ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad);
+       if (ret) {
+               dev_err(dev, "failed to init entity pads: %d\n", ret);
+               goto error_handler_free;
+       }
+
+       ret = v4l2_async_register_subdev_sensor_common(&imx219->sd);
+       if (ret < 0) {
+               dev_err(dev, "failed to register sensor sub-device: %d\n", ret);
+               goto error_media_entity;
+       }
+
+       /* Enable runtime PM and turn off the device */
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+       pm_runtime_idle(dev);
+
+       return 0;
+
+error_media_entity:
+       media_entity_cleanup(&imx219->sd.entity);
+
+error_handler_free:
+       imx219_free_controls(imx219);
+
+error_power_off:
+       imx219_power_off(dev);
+
+       return ret;
+}
+
+static int imx219_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct imx219 *imx219 = to_imx219(sd);
+
+       v4l2_async_unregister_subdev(sd);
+       media_entity_cleanup(&sd->entity);
+       imx219_free_controls(imx219);
+
+       pm_runtime_disable(&client->dev);
+       if (!pm_runtime_status_suspended(&client->dev))
+               imx219_power_off(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
+       return 0;
+}
+
+static const struct of_device_id imx219_dt_ids[] = {
+       { .compatible = "sony,imx219" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx219_dt_ids);
+
+static const struct dev_pm_ops imx219_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume)
+       SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL)
+};
+
+static struct i2c_driver imx219_i2c_driver = {
+       .driver = {
+               .name = "imx219",
+               .of_match_table = imx219_dt_ids,
+               .pm = &imx219_pm_ops,
+       },
+       .probe_new = imx219_probe,
+       .remove = imx219_remove,
+};
+
+module_i2c_driver(imx219_i2c_driver);
+
+MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com");
+MODULE_DESCRIPTION("Sony IMX219 sensor driver");
+MODULE_LICENSE("GPL v2");
index 1ae2523..8537cc4 100644 (file)
 #define OV5675_TEST_PATTERN_ENABLE     BIT(7)
 #define OV5675_TEST_PATTERN_BAR_SHIFT  2
 
+/* Flip Mirror Controls from sensor */
+#define OV5675_REG_FORMAT1             0x3820
+#define OV5675_REG_FORMAT2             0x373d
+
 #define to_ov5675(_sd)                 container_of(_sd, struct ov5675, sd)
 
 enum {
@@ -314,21 +318,21 @@ static const struct ov5675_reg mode_1296x972_regs[] = {
        {0x3800, 0x00},
        {0x3801, 0x00},
        {0x3802, 0x00},
-       {0x3803, 0xf4},
+       {0x3803, 0x00},
        {0x3804, 0x0a},
        {0x3805, 0x3f},
-       {0x3806, 0x06},
-       {0x3807, 0xb3},
+       {0x3806, 0x07},
+       {0x3807, 0xb7},
        {0x3808, 0x05},
-       {0x3809, 0x00},
-       {0x380a, 0x02},
-       {0x380b, 0xd0},
+       {0x3809, 0x10},
+       {0x380a, 0x03},
+       {0x380b, 0xcc},
        {0x380c, 0x02},
        {0x380d, 0xee},
        {0x380e, 0x07},
-       {0x380f, 0xe4},
-       {0x3811, 0x10},
-       {0x3813, 0x09},
+       {0x380f, 0xd0},
+       {0x3811, 0x08},
+       {0x3813, 0x0d},
        {0x3814, 0x03},
        {0x3815, 0x01},
        {0x3816, 0x03},
@@ -604,6 +608,53 @@ static int ov5675_test_pattern(struct ov5675 *ov5675, u32 pattern)
                                OV5675_REG_VALUE_08BIT, pattern);
 }
 
+/*
+ * OV5675 supports keeping the pixel order by mirror and flip function
+ * The Bayer order isn't affected by the flip controls
+ */
+static int ov5675_set_ctrl_hflip(struct ov5675 *ov5675, u32 ctrl_val)
+{
+       int ret;
+       u32 val;
+
+       ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT1,
+                             OV5675_REG_VALUE_08BIT, &val);
+       if (ret)
+               return ret;
+
+       return ov5675_write_reg(ov5675, OV5675_REG_FORMAT1,
+                               OV5675_REG_VALUE_08BIT,
+                               ctrl_val ? val & ~BIT(3) : val);
+}
+
+static int ov5675_set_ctrl_vflip(struct ov5675 *ov5675, u8 ctrl_val)
+{
+       int ret;
+       u32 val;
+
+       ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT1,
+                             OV5675_REG_VALUE_08BIT, &val);
+       if (ret)
+               return ret;
+
+       ret = ov5675_write_reg(ov5675, OV5675_REG_FORMAT1,
+                              OV5675_REG_VALUE_08BIT,
+                              ctrl_val ? val | BIT(4) | BIT(5)  : val);
+
+       if (ret)
+               return ret;
+
+       ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT2,
+                             OV5675_REG_VALUE_08BIT, &val);
+
+       if (ret)
+               return ret;
+
+       return ov5675_write_reg(ov5675, OV5675_REG_FORMAT2,
+                               OV5675_REG_VALUE_08BIT,
+                               ctrl_val ? val | BIT(1) : val);
+}
+
 static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct ov5675 *ov5675 = container_of(ctrl->handler,
@@ -654,6 +705,14 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl)
                ret = ov5675_test_pattern(ov5675, ctrl->val);
                break;
 
+       case V4L2_CID_HFLIP:
+               ov5675_set_ctrl_hflip(ov5675, ctrl->val);
+               break;
+
+       case V4L2_CID_VFLIP:
+               ov5675_set_ctrl_vflip(ov5675, ctrl->val);
+               break;
+
        default:
                ret = -EINVAL;
                break;
@@ -722,6 +781,11 @@ static int ov5675_init_controls(struct ov5675 *ov5675)
                                     V4L2_CID_TEST_PATTERN,
                                     ARRAY_SIZE(ov5675_test_pattern_menu) - 1,
                                     0, 0, ov5675_test_pattern_menu);
+       v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
+                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
+                         V4L2_CID_VFLIP, 0, 1, 1, 0);
+
        if (ctrl_hdlr->error)
                return ctrl_hdlr->error;
 
index d6cd15b..cc678d9 100644 (file)
@@ -971,16 +971,9 @@ unlock_and_return:
        return ret;
 }
 
-/* Calculate the delay in us by clock rate and clock cycles */
-static inline u32 ov5695_cal_delay(u32 cycles)
-{
-       return DIV_ROUND_UP(cycles, OV5695_XVCLK_FREQ / 1000 / 1000);
-}
-
 static int __ov5695_power_on(struct ov5695 *ov5695)
 {
-       int ret;
-       u32 delay_us;
+       int i, ret;
        struct device *dev = &ov5695->client->dev;
 
        ret = clk_prepare_enable(ov5695->xvclk);
@@ -991,21 +984,28 @@ static int __ov5695_power_on(struct ov5695 *ov5695)
 
        gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
 
-       ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies);
-       if (ret < 0) {
-               dev_err(dev, "Failed to enable regulators\n");
-               goto disable_clk;
+       /*
+        * The hardware requires the regulators to be powered on in order,
+        * so enable them one by one.
+        */
+       for (i = 0; i < OV5695_NUM_SUPPLIES; i++) {
+               ret = regulator_enable(ov5695->supplies[i].consumer);
+               if (ret) {
+                       dev_err(dev, "Failed to enable %s: %d\n",
+                               ov5695->supplies[i].supply, ret);
+                       goto disable_reg_clk;
+               }
        }
 
        gpiod_set_value_cansleep(ov5695->reset_gpio, 0);
 
-       /* 8192 cycles prior to first SCCB transaction */
-       delay_us = ov5695_cal_delay(8192);
-       usleep_range(delay_us, delay_us * 2);
+       usleep_range(1000, 1200);
 
        return 0;
 
-disable_clk:
+disable_reg_clk:
+       for (--i; i >= 0; i--)
+               regulator_disable(ov5695->supplies[i].consumer);
        clk_disable_unprepare(ov5695->xvclk);
 
        return ret;
@@ -1013,9 +1013,22 @@ disable_clk:
 
 static void __ov5695_power_off(struct ov5695 *ov5695)
 {
+       struct device *dev = &ov5695->client->dev;
+       int i, ret;
+
        clk_disable_unprepare(ov5695->xvclk);
        gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
-       regulator_bulk_disable(OV5695_NUM_SUPPLIES, ov5695->supplies);
+
+       /*
+        * The hardware requires the regulators to be powered off in order,
+        * so disable them one by one.
+        */
+       for (i = OV5695_NUM_SUPPLIES - 1; i >= 0; i--) {
+               ret = regulator_disable(ov5695->supplies[i].consumer);
+               if (ret)
+                       dev_err(dev, "Failed to disable %s: %d\n",
+                               ov5695->supplies[i].supply, ret);
+       }
 }
 
 static int __maybe_unused ov5695_runtime_resume(struct device *dev)
@@ -1285,7 +1298,7 @@ static int ov5695_probe(struct i2c_client *client,
        if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ)
                dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
 
-       ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+       ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
        if (IS_ERR(ov5695->reset_gpio)) {
                dev_err(dev, "Failed to get reset-gpios\n");
                return -EINVAL;
index 8911660..71cf68a 100644 (file)
@@ -547,7 +547,7 @@ int s5c73m3_init_controls(struct s5c73m3 *state)
                                V4L2_CTRL_FLAG_UPDATE;
        v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 0, false);
        ctrls->af_status->flags |= V4L2_CTRL_FLAG_VOLATILE;
-       v4l2_ctrl_cluster(6, &ctrls->focus_auto);
+       v4l2_ctrl_cluster(5, &ctrls->focus_auto);
 
        state->sensor_sd.ctrl_handler = hdl;
 
index a80d770..5e4f6a2 100644 (file)
@@ -57,6 +57,45 @@ static const struct smiapp_module_ident smiapp_module_idents[] = {
  *
  */
 
+static u32 smiapp_get_limit(struct smiapp_sensor *sensor,
+                                unsigned int limit)
+{
+       if (WARN_ON(limit >= SMIAPP_LIMIT_LAST))
+               return 1;
+
+       return sensor->limits[limit];
+}
+
+#define SMIA_LIM(sensor, limit) \
+       smiapp_get_limit(sensor, SMIAPP_LIMIT_##limit)
+
+static int smiapp_read_all_smia_limits(struct smiapp_sensor *sensor)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+       unsigned int i;
+       int rval;
+
+       for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
+               u32 val;
+
+               rval = smiapp_read(
+                       sensor, smiapp_reg_limits[i].addr, &val);
+               if (rval)
+                       return rval;
+
+               sensor->limits[i] = val;
+
+               dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n",
+                       smiapp_reg_limits[i].addr,
+                       smiapp_reg_limits[i].what, val, val);
+       }
+
+       if (SMIA_LIM(sensor, SCALER_N_MIN) == 0)
+               smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
+
+       return 0;
+}
+
 static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
@@ -240,35 +279,35 @@ static int smiapp_pll_try(struct smiapp_sensor *sensor,
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
        struct smiapp_pll_limits lim = {
-               .min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
-               .max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
-               .min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ],
-               .max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ],
-               .min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER],
-               .max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER],
-               .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ],
-               .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ],
-
-               .op.min_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV],
-               .op.max_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV],
-               .op.min_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV],
-               .op.max_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV],
-               .op.min_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ],
-               .op.max_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ],
-               .op.min_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ],
-               .op.max_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ],
-
-               .vt.min_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV],
-               .vt.max_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV],
-               .vt.min_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV],
-               .vt.max_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV],
-               .vt.min_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ],
-               .vt.max_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ],
-               .vt.min_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ],
-               .vt.max_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ],
-
-               .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN],
-               .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK],
+               .min_pre_pll_clk_div = SMIA_LIM(sensor, MIN_PRE_PLL_CLK_DIV),
+               .max_pre_pll_clk_div = SMIA_LIM(sensor, MAX_PRE_PLL_CLK_DIV),
+               .min_pll_ip_freq_hz = SMIA_LIM(sensor, MIN_PLL_IP_FREQ_HZ),
+               .max_pll_ip_freq_hz = SMIA_LIM(sensor, MAX_PLL_IP_FREQ_HZ),
+               .min_pll_multiplier = SMIA_LIM(sensor, MIN_PLL_MULTIPLIER),
+               .max_pll_multiplier = SMIA_LIM(sensor, MAX_PLL_MULTIPLIER),
+               .min_pll_op_freq_hz = SMIA_LIM(sensor, MIN_PLL_OP_FREQ_HZ),
+               .max_pll_op_freq_hz = SMIA_LIM(sensor, MAX_PLL_OP_FREQ_HZ),
+
+               .op.min_sys_clk_div = SMIA_LIM(sensor, MIN_OP_SYS_CLK_DIV),
+               .op.max_sys_clk_div = SMIA_LIM(sensor, MAX_OP_SYS_CLK_DIV),
+               .op.min_pix_clk_div = SMIA_LIM(sensor, MIN_OP_PIX_CLK_DIV),
+               .op.max_pix_clk_div = SMIA_LIM(sensor, MAX_OP_PIX_CLK_DIV),
+               .op.min_sys_clk_freq_hz = SMIA_LIM(sensor, MIN_OP_SYS_CLK_FREQ_HZ),
+               .op.max_sys_clk_freq_hz = SMIA_LIM(sensor, MAX_OP_SYS_CLK_FREQ_HZ),
+               .op.min_pix_clk_freq_hz = SMIA_LIM(sensor, MIN_OP_PIX_CLK_FREQ_HZ),
+               .op.max_pix_clk_freq_hz = SMIA_LIM(sensor, MAX_OP_PIX_CLK_FREQ_HZ),
+
+               .vt.min_sys_clk_div = SMIA_LIM(sensor, MIN_VT_SYS_CLK_DIV),
+               .vt.max_sys_clk_div = SMIA_LIM(sensor, MAX_VT_SYS_CLK_DIV),
+               .vt.min_pix_clk_div = SMIA_LIM(sensor, MIN_VT_PIX_CLK_DIV),
+               .vt.max_pix_clk_div = SMIA_LIM(sensor, MAX_VT_PIX_CLK_DIV),
+               .vt.min_sys_clk_freq_hz = SMIA_LIM(sensor, MIN_VT_SYS_CLK_FREQ_HZ),
+               .vt.max_sys_clk_freq_hz = SMIA_LIM(sensor, MAX_VT_SYS_CLK_FREQ_HZ),
+               .vt.min_pix_clk_freq_hz = SMIA_LIM(sensor, MIN_VT_PIX_CLK_FREQ_HZ),
+               .vt.max_pix_clk_freq_hz = SMIA_LIM(sensor, MAX_VT_PIX_CLK_FREQ_HZ),
+
+               .min_line_length_pck_bin = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN),
+               .min_line_length_pck = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK),
        };
 
        return smiapp_pll_calculate(&client->dev, &lim, pll);
@@ -311,7 +350,7 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
 
        max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
                + sensor->vblank->val
-               - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
+               - SMIA_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN);
 
        __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max);
 }
@@ -568,10 +607,10 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
        sensor->analog_gain = v4l2_ctrl_new_std(
                &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
                V4L2_CID_ANALOGUE_GAIN,
-               sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN],
-               sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX],
-               max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U),
-               sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]);
+               SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MIN),
+               SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MAX),
+               max(SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_STEP), 1U),
+               SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MIN));
 
        /* Exposure limits will be updated soon, use just something here. */
        sensor->exposure = v4l2_ctrl_new_std(
@@ -677,45 +716,6 @@ static void smiapp_free_controls(struct smiapp_sensor *sensor)
                v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler);
 }
 
-static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
-                            unsigned int n)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-       unsigned int i;
-       u32 val;
-       int rval;
-
-       for (i = 0; i < n; i++) {
-               rval = smiapp_read(
-                       sensor, smiapp_reg_limits[limit[i]].addr, &val);
-               if (rval)
-                       return rval;
-               sensor->limits[limit[i]] = val;
-               dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n",
-                       smiapp_reg_limits[limit[i]].addr,
-                       smiapp_reg_limits[limit[i]].what, val, val);
-       }
-
-       return 0;
-}
-
-static int smiapp_get_all_limits(struct smiapp_sensor *sensor)
-{
-       unsigned int i;
-       int rval;
-
-       for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
-               rval = smiapp_get_limits(sensor, &i, 1);
-               if (rval < 0)
-                       return rval;
-       }
-
-       if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0)
-               smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
-
-       return 0;
-}
-
 static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
@@ -869,21 +869,21 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor)
        int min, max;
 
        if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) {
-               min_fll = sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN];
-               max_fll = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN];
-               min_llp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN];
-               max_llp = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN];
-               min_lbp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN];
+               min_fll = SMIA_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN);
+               max_fll = SMIA_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN);
+               min_llp = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN);
+               max_llp = SMIA_LIM(sensor, MAX_LINE_LENGTH_PCK_BIN);
+               min_lbp = SMIA_LIM(sensor, MIN_LINE_BLANKING_PCK_BIN);
        } else {
-               min_fll = sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES];
-               max_fll = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES];
-               min_llp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK];
-               max_llp = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK];
-               min_lbp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK];
+               min_fll = SMIA_LIM(sensor, MIN_FRAME_LENGTH_LINES);
+               max_fll = SMIA_LIM(sensor, MAX_FRAME_LENGTH_LINES);
+               min_llp = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK);
+               max_llp = SMIA_LIM(sensor, MAX_LINE_LENGTH_PCK);
+               min_lbp = SMIA_LIM(sensor, MIN_LINE_BLANKING_PCK);
        }
 
        min = max_t(int,
-                   sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+                   SMIA_LIM(sensor, MIN_FRAME_BLANKING_LINES),
                    min_fll -
                    sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
        max = max_fll - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
@@ -961,7 +961,7 @@ static int smiapp_read_nvm_page(struct smiapp_sensor *sensor, u32 p, u8 *nvm,
                return -ENODATA;
        }
 
-       if (sensor->limits[SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY] &
+       if (SMIA_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) &
            SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL) {
                for (i = 1000; i > 0; i--) {
                        if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
@@ -1416,7 +1416,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor)
         */
 
        /* Digital crop */
-       if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+       if (SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY)
            == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
                rval = smiapp_write(
                        sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET,
@@ -1444,7 +1444,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor)
        }
 
        /* Scaling */
-       if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+       if (SMIA_LIM(sensor, SCALING_CAPABILITY)
            != SMIAPP_SCALING_CAPABILITY_NONE) {
                rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE,
                                    sensor->scaling_mode);
@@ -1467,7 +1467,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor)
        if (rval < 0)
                goto out;
 
-       if ((sensor->limits[SMIAPP_LIMIT_FLASH_MODE_CAPABILITY] &
+       if ((SMIA_LIM(sensor, FLASH_MODE_CAPABILITY) &
             (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
              SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
            sensor->hwcfg->strobe_setup != NULL &&
@@ -1715,8 +1715,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev,
                if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
                        if (ssd == sensor->scaler) {
                                sensor->scale_m =
-                                       sensor->limits[
-                                               SMIAPP_LIMIT_SCALER_N_MIN];
+                                       SMIA_LIM(sensor, SCALER_N_MIN);
                                sensor->scaling_mode =
                                        SMIAPP_SCALING_MODE_NONE;
                        } else if (ssd == sensor->binner) {
@@ -1828,12 +1827,12 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
 
        fmt->format.width =
                clamp(fmt->format.width,
-                     sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
-                     sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]);
+                     SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE),
+                     SMIA_LIM(sensor, MAX_X_OUTPUT_SIZE));
        fmt->format.height =
                clamp(fmt->format.height,
-                     sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
-                     sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]);
+                     SMIA_LIM(sensor, MIN_Y_OUTPUT_SIZE),
+                     SMIA_LIM(sensor, MAX_Y_OUTPUT_SIZE));
 
        smiapp_get_crop_compose(subdev, cfg, crops, NULL, fmt->which);
 
@@ -1886,7 +1885,7 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
        val -= abs(w - ask_w);
        val -= abs(h - ask_h);
 
-       if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
+       if (w < SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE))
                val -= SCALING_GOODNESS_EXTREME;
 
        dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
@@ -1952,7 +1951,7 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
        struct i2c_client *client = v4l2_get_subdevdata(subdev);
        struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
        u32 min, max, a, b, max_m;
-       u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+       u32 scale_m = SMIA_LIM(sensor, SCALER_N_MIN);
        int mode = SMIAPP_SCALING_MODE_HORIZONTAL;
        u32 try[4];
        u32 ntry = 0;
@@ -1965,19 +1964,19 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
                              crops[SMIAPP_PAD_SINK]->height);
 
        a = crops[SMIAPP_PAD_SINK]->width
-               * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width;
+               * SMIA_LIM(sensor, SCALER_N_MIN) / sel->r.width;
        b = crops[SMIAPP_PAD_SINK]->height
-               * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height;
+               * SMIA_LIM(sensor, SCALER_N_MIN) / sel->r.height;
        max_m = crops[SMIAPP_PAD_SINK]->width
-               * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
-               / sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
+               * SMIA_LIM(sensor, SCALER_N_MIN)
+               / SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE);
 
-       a = clamp(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN],
-                 sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]);
-       b = clamp(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN],
-                 sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]);
-       max_m = clamp(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN],
-                     sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]);
+       a = clamp(a, SMIA_LIM(sensor, SCALER_M_MIN),
+                 SMIA_LIM(sensor, SCALER_M_MAX));
+       b = clamp(b, SMIA_LIM(sensor, SCALER_M_MIN),
+                 SMIA_LIM(sensor, SCALER_M_MAX));
+       max_m = clamp(max_m, SMIA_LIM(sensor, SCALER_M_MIN),
+                     SMIA_LIM(sensor, SCALER_M_MAX));
 
        dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
 
@@ -2004,7 +2003,7 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
                        subdev,
                        crops[SMIAPP_PAD_SINK]->width
                        / try[i]
-                       * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+                       * SMIA_LIM(sensor, SCALER_N_MIN),
                        sel->r.width,
                        crops[SMIAPP_PAD_SINK]->height,
                        sel->r.height,
@@ -2018,18 +2017,18 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
                        best = this;
                }
 
-               if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+               if (SMIA_LIM(sensor, SCALING_CAPABILITY)
                    == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
                        continue;
 
                this = scaling_goodness(
                        subdev, crops[SMIAPP_PAD_SINK]->width
                        / try[i]
-                       * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+                       * SMIA_LIM(sensor, SCALER_N_MIN),
                        sel->r.width,
                        crops[SMIAPP_PAD_SINK]->height
                        / try[i]
-                       * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+                       * SMIA_LIM(sensor, SCALER_N_MIN),
                        sel->r.height,
                        sel->flags);
 
@@ -2043,12 +2042,12 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
        sel->r.width =
                (crops[SMIAPP_PAD_SINK]->width
                 / scale_m
-                * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1;
+                * SMIA_LIM(sensor, SCALER_N_MIN)) & ~1;
        if (mode == SMIAPP_SCALING_MODE_BOTH)
                sel->r.height =
                        (crops[SMIAPP_PAD_SINK]->height
                         / scale_m
-                        * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN])
+                        * SMIA_LIM(sensor, SCALER_N_MIN))
                        & ~1;
        else
                sel->r.height = crops[SMIAPP_PAD_SINK]->height;
@@ -2104,7 +2103,7 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
                        return 0;
                if (ssd == sensor->scaler
                    && sel->pad == SMIAPP_PAD_SINK
-                   && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+                   && SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY)
                    == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
                        return 0;
                return -EINVAL;
@@ -2120,7 +2119,7 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
                if (ssd == sensor->binner)
                        return 0;
                if (ssd == sensor->scaler
-                   && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+                   && SMIA_LIM(sensor, SCALING_CAPABILITY)
                    != SMIAPP_SCALING_CAPABILITY_NONE)
                        return 0;
                /* Fall through */
@@ -2185,8 +2184,8 @@ static void smiapp_get_native_size(struct smiapp_subdev *ssd,
 {
        r->top = 0;
        r->left = 0;
-       r->width = ssd->sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
-       r->height = ssd->sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+       r->width = SMIA_LIM(ssd->sensor, X_ADDR_MAX) + 1;
+       r->height = SMIA_LIM(ssd->sensor, Y_ADDR_MAX) + 1;
 }
 
 static int __smiapp_get_selection(struct v4l2_subdev *subdev,
@@ -2271,10 +2270,10 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev,
        sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags);
 
        sel->r.width = max_t(unsigned int,
-                            sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+                            SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE),
                             sel->r.width);
        sel->r.height = max_t(unsigned int,
-                             sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+                             SMIA_LIM(sensor, MIN_Y_OUTPUT_SIZE),
                              sel->r.height);
 
        switch (sel->target) {
@@ -2927,7 +2926,7 @@ static int smiapp_probe(struct i2c_client *client)
                goto out_power_off;
        }
 
-       rval = smiapp_get_all_limits(sensor);
+       rval = smiapp_read_all_smia_limits(sensor);
        if (rval) {
                rval = -ENODEV;
                goto out_power_off;
@@ -2963,7 +2962,7 @@ static int smiapp_probe(struct i2c_client *client)
                goto out_power_off;
        }
 
-       if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
+       if (SMIA_LIM(sensor, BINNING_CAPABILITY)) {
                u32 val;
 
                rval = smiapp_read(sensor,
@@ -3000,7 +2999,7 @@ static int smiapp_probe(struct i2c_client *client)
        }
 
        if (sensor->minfo.smiapp_version &&
-           sensor->limits[SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY] &
+           SMIA_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) &
            SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) {
                if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
                        dev_err(&client->dev, "sysfs nvm entry failed\n");
@@ -3010,21 +3009,21 @@ static int smiapp_probe(struct i2c_client *client)
        }
 
        /* We consider this as profile 0 sensor if any of these are zero. */
-       if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
-           !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
-           !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
-           !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
+       if (!SMIA_LIM(sensor, MIN_OP_SYS_CLK_DIV) ||
+           !SMIA_LIM(sensor, MAX_OP_SYS_CLK_DIV) ||
+           !SMIA_LIM(sensor, MIN_OP_PIX_CLK_DIV) ||
+           !SMIA_LIM(sensor, MAX_OP_PIX_CLK_DIV)) {
                sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
-       } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+       } else if (SMIA_LIM(sensor, SCALING_CAPABILITY)
                   != SMIAPP_SCALING_CAPABILITY_NONE) {
-               if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+               if (SMIA_LIM(sensor, SCALING_CAPABILITY)
                    == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
                        sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
                else
                        sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
                sensor->scaler = &sensor->ssds[sensor->ssds_used];
                sensor->ssds_used++;
-       } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+       } else if (SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY)
                   == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
                sensor->scaler = &sensor->ssds[sensor->ssds_used];
                sensor->ssds_used++;
@@ -3034,13 +3033,13 @@ static int smiapp_probe(struct i2c_client *client)
        sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
        sensor->ssds_used++;
 
-       sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+       sensor->scale_m = SMIA_LIM(sensor, SCALER_N_MIN);
 
        /* prepare PLL configuration input values */
        sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
        sensor->pll.csi2.lanes = sensor->hwcfg->lanes;
        sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk;
-       sensor->pll.scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+       sensor->pll.scale_n = SMIA_LIM(sensor, SCALER_N_MIN);
        /* Profile 0 sensors have no separate OP clock branch. */
        if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
                sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
index 43505cd..e6f9630 100644 (file)
 #define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE     BIT(0)
 #define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE   BIT(1)
 
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK     0
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE    1
+#define SMIAPP_CSI_SIGNALLING_MODE_CSI2                        2
+
 #define SMIAPP_DPHY_CTRL_AUTOMATIC                     0
 /* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */
 #define SMIAPP_DPHY_CTRL_UI                            1
index ce8c1d4..1b58b7c 100644 (file)
@@ -8,6 +8,8 @@
  * Contact: Sakari Ailus <sakari.ailus@iki.fi>
  */
 
+#include <asm/unaligned.h>
+
 #include <linux/delay.h>
 #include <linux/i2c.h>
 
@@ -69,18 +71,19 @@ static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
        struct i2c_msg msg;
-       unsigned char data[4];
-       u16 offset = reg;
+       unsigned char data_buf[sizeof(u32)] = { 0 };
+       unsigned char offset_buf[sizeof(u16)];
        int r;
 
+       if (len > sizeof(data_buf))
+               return -EINVAL;
+
        msg.addr = client->addr;
        msg.flags = 0;
-       msg.len = 2;
-       msg.buf = data;
+       msg.len = sizeof(offset_buf);
+       msg.buf = offset_buf;
+       put_unaligned_be16(reg, offset_buf);
 
-       /* high byte goes out first */
-       data[0] = (u8) (offset >> 8);
-       data[1] = (u8) offset;
        r = i2c_transfer(client->adapter, &msg, 1);
        if (r != 1) {
                if (r >= 0)
@@ -90,6 +93,8 @@ static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
 
        msg.len = len;
        msg.flags = I2C_M_RD;
+       msg.buf = &data_buf[sizeof(data_buf) - len];
+
        r = i2c_transfer(client->adapter, &msg, 1);
        if (r != 1) {
                if (r >= 0)
@@ -97,27 +102,12 @@ static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
                goto err;
        }
 
-       *val = 0;
-       /* high byte comes first */
-       switch (len) {
-       case SMIAPP_REG_32BIT:
-               *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
-                       data[3];
-               break;
-       case SMIAPP_REG_16BIT:
-               *val = (data[0] << 8) + data[1];
-               break;
-       case SMIAPP_REG_8BIT:
-               *val = data[0];
-               break;
-       default:
-               BUG();
-       }
+       *val = get_unaligned_be32(data_buf);
 
        return 0;
 
 err:
-       dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
+       dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r);
 
        return r;
 }
@@ -158,7 +148,7 @@ static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val,
            && len != SMIAPP_REG_32BIT)
                return -EINVAL;
 
-       if (len == SMIAPP_REG_8BIT || !only8)
+       if (!only8)
                rval = ____smiapp_read(sensor, SMIAPP_REG_ADDR(reg), len, val);
        else
                rval = ____smiapp_read_8only(sensor, SMIAPP_REG_ADDR(reg), len,
@@ -214,13 +204,10 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val)
        struct i2c_msg msg;
        unsigned char data[6];
        unsigned int retries;
-       u8 flags = SMIAPP_REG_FLAGS(reg);
        u8 len = SMIAPP_REG_WIDTH(reg);
-       u16 offset = SMIAPP_REG_ADDR(reg);
        int r;
 
-       if ((len != SMIAPP_REG_8BIT && len != SMIAPP_REG_16BIT &&
-            len != SMIAPP_REG_32BIT) || flags)
+       if (len > sizeof(data) - 2)
                return -EINVAL;
 
        msg.addr = client->addr;
@@ -228,27 +215,8 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val)
        msg.len = 2 + len;
        msg.buf = data;
 
-       /* high byte goes out first */
-       data[0] = (u8) (reg >> 8);
-       data[1] = (u8) (reg & 0xff);
-
-       switch (len) {
-       case SMIAPP_REG_8BIT:
-               data[2] = val;
-               break;
-       case SMIAPP_REG_16BIT:
-               data[2] = val >> 8;
-               data[3] = val;
-               break;
-       case SMIAPP_REG_32BIT:
-               data[2] = val >> 24;
-               data[3] = val >> 16;
-               data[4] = val >> 8;
-               data[5] = val;
-               break;
-       default:
-               BUG();
-       }
+       put_unaligned_be16(SMIAPP_REG_ADDR(reg), data);
+       put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2);
 
        for (retries = 0; retries < 5; retries++) {
                /*
@@ -269,7 +237,8 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val)
        }
 
        dev_err(&client->dev,
-               "wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
+               "wrote 0x%x to offset 0x%x error %d\n", val,
+               SMIAPP_REG_ADDR(reg), r);
 
        return r;
 }
index 4837d80..6f46993 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/mutex.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
-#include <media/i2c/smiapp.h>
 
 #include "smiapp-pll.h"
 #include "smiapp-reg.h"
 
 #define SMIAPP_COLOUR_COMPONENTS       4
 
+#define SMIAPP_NAME            "smiapp"
+
+#define SMIAPP_DFL_I2C_ADDR    (0x20 >> 1) /* Default I2C Address */
+#define SMIAPP_ALT_I2C_ADDR    (0x6e >> 1) /* Alternate I2C Address */
+
+/*
+ * Sometimes due to board layout considerations the camera module can be
+ * mounted rotated. The typical rotation used is 180 degrees which can be
+ * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
+ * FIXME: rotation also changes the bayer pattern.
+ */
+enum smiapp_module_board_orient {
+       SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
+       SMIAPP_MODULE_BOARD_ORIENT_180,
+};
+
+struct smiapp_flash_strobe_parms {
+       u8 mode;
+       u32 strobe_width_high_us;
+       u16 strobe_delay;
+       u16 stobe_start_point;
+       u8 trigger;
+};
+
+struct smiapp_hwconfig {
+       /*
+        * Change the cci address if i2c_addr_alt is set.
+        * Both default and alternate cci addr need to be present
+        */
+       unsigned short i2c_addr_dfl;    /* Default i2c addr */
+       unsigned short i2c_addr_alt;    /* Alternate i2c addr */
+
+       uint32_t ext_clk;               /* sensor external clk */
+
+       unsigned int lanes;             /* Number of CSI-2 lanes */
+       uint32_t csi_signalling_mode;   /* SMIAPP_CSI_SIGNALLING_MODE_* */
+       uint64_t *op_sys_clock;
+
+       enum smiapp_module_board_orient module_board_orient;
+
+       struct smiapp_flash_strobe_parms *strobe_setup;
+};
+
 #include "smiapp-limits.h"
 
 struct smiapp_quirk;
index edad49c..eb39cf5 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-mc.h>
+#include <media/v4l2-rect.h>
 
 #include "tvp5150_reg.h"
 
 #define TVP5150_MBUS_FMT       MEDIA_BUS_FMT_UYVY8_2X8
 #define TVP5150_FIELD          V4L2_FIELD_ALTERNATE
 #define TVP5150_COLORSPACE     V4L2_COLORSPACE_SMPTE170M
+#define TVP5150_STD_MASK       (V4L2_STD_NTSC     | \
+                                V4L2_STD_NTSC_443 | \
+                                V4L2_STD_PAL      | \
+                                V4L2_STD_PAL_M    | \
+                                V4L2_STD_PAL_N    | \
+                                V4L2_STD_PAL_Nc   | \
+                                V4L2_STD_SECAM)
+
+#define TVP5150_MAX_CONNECTORS 3 /* Check dt-bindings for more information */
 
 MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver");
 MODULE_AUTHOR("Mauro Carvalho Chehab");
@@ -44,18 +56,26 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg)
 
 enum tvp5150_pads {
-       TVP5150_PAD_IF_INPUT,
+       TVP5150_PAD_AIP1A,
+       TVP5150_PAD_AIP1B,
        TVP5150_PAD_VID_OUT,
        TVP5150_NUM_PADS
 };
 
+struct tvp5150_connector {
+       struct v4l2_fwnode_connector base;
+       struct media_entity ent;
+       struct media_pad pad;
+};
+
 struct tvp5150 {
        struct v4l2_subdev sd;
-#ifdef CONFIG_MEDIA_CONTROLLER
+
        struct media_pad pads[TVP5150_NUM_PADS];
-       struct media_entity input_ent[TVP5150_INPUT_NUM];
-       struct media_pad input_pad[TVP5150_INPUT_NUM];
-#endif
+       struct tvp5150_connector connectors[TVP5150_MAX_CONNECTORS];
+       struct tvp5150_connector *cur_connector;
+       unsigned int connectors_num;
+
        struct v4l2_ctrl_handler hdl;
        struct v4l2_rect rect;
        struct regmap *regmap;
@@ -282,9 +302,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
                break;
        }
 
-       dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n",
-                       decoder->input, decoder->output,
-                       input, opmode);
+       dev_dbg_lvl(sd->dev, 1, debug,
+                   "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n",
+                   decoder->input == 0 ? "aip1a" :
+                   decoder->input == 2 ? "aip1b" : "svideo",
+                   decoder->output == 0 ? "normal" : "black-frame-gen",
+                   input, opmode);
 
        regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode);
        regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input);
@@ -773,17 +796,33 @@ static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
 static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
+       struct tvp5150_connector *cur_con = decoder->cur_connector;
+       v4l2_std_id supported_stds;
 
        if (decoder->norm == std)
                return 0;
 
+       /* In case of no of-connectors are available no limitations are made */
+       if (!decoder->connectors_num)
+               supported_stds = V4L2_STD_ALL;
+       else
+               supported_stds = cur_con->base.connector.analog.sdtv_stds;
+
+       /*
+        * Check if requested std or group of std's is/are supported by the
+        * connector.
+        */
+       if ((supported_stds & std) == 0)
+               return -EINVAL;
+
        /* Change cropping height limits */
        if (std & V4L2_STD_525_60)
                decoder->rect.height = TVP5150_V_MAX_525_60;
        else
                decoder->rect.height = TVP5150_V_MAX_OTHERS;
 
-       decoder->norm = std;
+       /* Set only the specific supported std in case of group of std's. */
+       decoder->norm = supported_stds & std;
 
        return tvp5150_set_std(sd, std);
 }
@@ -986,6 +1025,25 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop)
                crop->height = TVP5150_V_MAX_OTHERS;
 }
 
+static struct v4l2_rect *
+tvp5150_get_pad_crop(struct tvp5150 *decoder,
+                    struct v4l2_subdev_pad_config *cfg, unsigned int pad,
+                    enum v4l2_subdev_format_whence which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &decoder->rect;
+       case V4L2_SUBDEV_FORMAT_TRY:
+#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+               return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad);
+#else
+               return ERR_PTR(-EINVAL);
+#endif
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+}
+
 static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
                            struct v4l2_subdev_pad_config *cfg,
                            struct v4l2_subdev_format *format)
@@ -1010,25 +1068,10 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int tvp5150_set_selection(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
-                                struct v4l2_subdev_selection *sel)
+static unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
-       struct v4l2_rect rect = sel->r;
        v4l2_std_id std;
-       int hmax;
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
-           sel->target != V4L2_SEL_TGT_CROP)
-               return -EINVAL;
-
-       dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
-               __func__, rect.left, rect.top, rect.width, rect.height);
-
-       /* tvp5150 has some special limits */
-       rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
-       rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
 
        /* Calculate height based on current standard */
        if (decoder->norm == V4L2_STD_ALL)
@@ -1036,36 +1079,78 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd,
        else
                std = decoder->norm;
 
-       if (std & V4L2_STD_525_60)
-               hmax = TVP5150_V_MAX_525_60;
-       else
-               hmax = TVP5150_V_MAX_OTHERS;
+       return (std & V4L2_STD_525_60) ?
+               TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS;
+}
 
-       /*
-        * alignments:
-        *  - width = 2 due to UYVY colorspace
-        *  - height, image = no special alignment
-        */
-       v4l_bound_align_image(&rect.width,
-                             TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
-                             TVP5150_H_MAX - rect.left, 1, &rect.height,
-                             hmax - TVP5150_MAX_CROP_TOP - rect.top,
-                             hmax - rect.top, 0, 0);
+static void tvp5150_set_hw_selection(struct v4l2_subdev *sd,
+                                    struct v4l2_rect *rect)
+{
+       struct tvp5150 *decoder = to_tvp5150(sd);
+       unsigned int hmax = tvp5150_get_hmax(sd);
 
-       regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top);
+       regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect->top);
        regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP,
-                    rect.top + rect.height - hmax);
+                    rect->top + rect->height - hmax);
        regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB,
-                    rect.left >> TVP5150_CROP_SHIFT);
+                    rect->left >> TVP5150_CROP_SHIFT);
        regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB,
-                    rect.left | (1 << TVP5150_CROP_SHIFT));
+                    rect->left | (1 << TVP5150_CROP_SHIFT));
        regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB,
-                    (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >>
+                    (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >>
                     TVP5150_CROP_SHIFT);
        regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB,
-                    rect.left + rect.width - TVP5150_MAX_CROP_LEFT);
+                    rect->left + rect->width - TVP5150_MAX_CROP_LEFT);
+}
+
+static int tvp5150_set_selection(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_selection *sel)
+{
+       struct tvp5150 *decoder = to_tvp5150(sd);
+       struct v4l2_rect *rect = &sel->r;
+       struct v4l2_rect *crop;
+       unsigned int hmax;
+
+       if (sel->target != V4L2_SEL_TGT_CROP)
+               return -EINVAL;
+
+       dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n",
+               __func__, rect->left, rect->top, rect->width, rect->height);
+
+       /* tvp5150 has some special limits */
+       rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT);
+       rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP);
+       hmax = tvp5150_get_hmax(sd);
+
+       /*
+        * alignments:
+        *  - width = 2 due to UYVY colorspace
+        *  - height, image = no special alignment
+        */
+       v4l_bound_align_image(&rect->width,
+                             TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left,
+                             TVP5150_H_MAX - rect->left, 1, &rect->height,
+                             hmax - TVP5150_MAX_CROP_TOP - rect->top,
+                             hmax - rect->top, 0, 0);
+
+       if (!IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API) &&
+           sel->which == V4L2_SUBDEV_FORMAT_TRY)
+               return 0;
+
+       crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which);
+       if (IS_ERR(crop))
+               return PTR_ERR(crop);
+
+       /*
+        * Update output image size if the selection (crop) rectangle size or
+        * position has been modified.
+        */
+       if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+           !v4l2_rect_equal(rect, crop))
+               tvp5150_set_hw_selection(sd, rect);
 
-       decoder->rect = rect;
+       *crop = *rect;
 
        return 0;
 }
@@ -1075,11 +1160,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
                                 struct v4l2_subdev_selection *sel)
 {
        struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+       struct v4l2_rect *crop;
        v4l2_std_id std;
 
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP_BOUNDS:
                sel->r.left = 0;
@@ -1097,7 +1180,11 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
                        sel->r.height = TVP5150_V_MAX_OTHERS;
                return 0;
        case V4L2_SEL_TGT_CROP:
-               sel->r = decoder->rect;
+               crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad,
+                                           sel->which);
+               if (IS_ERR(crop))
+                       return PTR_ERR(crop);
+               sel->r = *crop;
                return 0;
        default:
                return -EINVAL;
@@ -1170,30 +1257,148 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd,
 }
 
 /****************************************************************************
                      Media entity ops
*                     Media entity ops
  ****************************************************************************/
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static int tvp5150_set_link(struct media_pad *connector_pad,
+                           struct media_pad *tvp5150_pad, u32 flags)
+{
+       struct media_link *link;
+
+       link = media_entity_find_link(connector_pad, tvp5150_pad);
+       if (!link)
+               return -EINVAL;
+
+       link->flags = flags;
+       link->reverse->flags = link->flags;
+
+       return 0;
+}
+
+static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
+{
+       struct media_pad *connector_pad;
+       unsigned int i;
+       int err;
+
+       for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
+               connector_pad = media_entity_remote_pad(&decoder->pads[i]);
+               if (!connector_pad)
+                       continue;
+
+               err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output,
+                            u32 config);
 
-#ifdef CONFIG_MEDIA_CONTROLLER
 static int tvp5150_link_setup(struct media_entity *entity,
-                             const struct media_pad *local,
+                             const struct media_pad *tvp5150_pad,
                              const struct media_pad *remote, u32 flags)
 {
        struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
        struct tvp5150 *decoder = to_tvp5150(sd);
-       int i;
+       struct media_pad *other_tvp5150_pad =
+               &decoder->pads[tvp5150_pad->index ^ 1];
+       struct v4l2_fwnode_connector *v4l2c;
+       bool is_svideo = false;
+       unsigned int i;
+       int err;
+
+       /*
+        * The TVP5150 state is determined by the enabled sink pad link(s).
+        * Enabling or disabling the source pad link has no effect.
+        */
+       if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE)
+               return 0;
 
-       for (i = 0; i < TVP5150_INPUT_NUM; i++) {
-               if (remote->entity == &decoder->input_ent[i])
+       /* Check if the svideo connector should be enabled */
+       for (i = 0; i < decoder->connectors_num; i++) {
+               if (remote->entity == &decoder->connectors[i].ent) {
+                       v4l2c = &decoder->connectors[i].base;
+                       is_svideo = v4l2c->type == V4L2_CONN_SVIDEO;
                        break;
+               }
        }
 
-       /* Do nothing for entities that are not input connectors */
-       if (i == TVP5150_INPUT_NUM)
-               return 0;
+       dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]",
+                   remote->entity->name, remote->index,
+                   tvp5150_pad->entity->name, tvp5150_pad->index,
+                   flags & MEDIA_LNK_FL_ENABLED);
+       if (is_svideo)
+               dev_dbg_lvl(sd->dev, 1, debug,
+                           "link setup '%s':%d->'%s':%d[%d]",
+                           remote->entity->name, remote->index,
+                           other_tvp5150_pad->entity->name,
+                           other_tvp5150_pad->index,
+                           flags & MEDIA_LNK_FL_ENABLED);
 
-       decoder->input = i;
+       /*
+        * The TVP5150 has an internal mux which allows the following setup:
+        *
+        * comp-connector1  --\
+        *                     |---> AIP1A
+        *                    /
+        * svideo-connector -|
+        *                    \
+        *                     |---> AIP1B
+        * comp-connector2  --/
+        *
+        * We can't rely on user space that the current connector gets disabled
+        * first before enabling the new connector. Disable all active
+        * connector links to be on the safe side.
+        */
+       err = tvp5150_disable_all_input_links(decoder);
+       if (err)
+               return err;
+
+       tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index,
+                         flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL :
+                         TVP5150_BLACK_SCREEN, 0);
+
+       if (flags & MEDIA_LNK_FL_ENABLED) {
+               struct v4l2_fwnode_connector_analog *v4l2ca;
+               u32 new_norm;
+
+               /*
+                * S-Video connector is conneted to both ports AIP1A and AIP1B.
+                * Both links must be enabled in one-shot regardless which link
+                * the user requests.
+                */
+               if (is_svideo) {
+                       err = tvp5150_set_link((struct media_pad *)remote,
+                                              other_tvp5150_pad, flags);
+                       if (err)
+                               return err;
+               }
 
-       tvp5150_selmux(sd);
+               if (!decoder->connectors_num)
+                       return 0;
+
+               /* Update the current connector */
+               decoder->cur_connector =
+                       container_of(remote, struct tvp5150_connector, pad);
+
+               /*
+                * Do nothing if the new connector supports the same tv-norms as
+                * the old one.
+                */
+               v4l2ca = &decoder->cur_connector->base.connector.analog;
+               new_norm = decoder->norm & v4l2ca->sdtv_stds;
+               if (decoder->norm == new_norm)
+                       return 0;
+
+               /*
+                * Fallback to the new connector tv-norms if we can't find any
+                * common between the current tv-norm and the new one.
+                */
+               tvp5150_s_std(sd, new_norm ? new_norm : v4l2ca->sdtv_stds);
+       }
 
        return 0;
 }
@@ -1202,20 +1407,54 @@ static const struct media_entity_operations tvp5150_sd_media_ops = {
        .link_setup = tvp5150_link_setup,
 };
 #endif
-
 /****************************************************************************
                        I2C Command
  ****************************************************************************/
+static int __maybe_unused tvp5150_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct tvp5150 *decoder = to_tvp5150(sd);
+
+       if (decoder->irq)
+               /* Disable lock interrupt */
+               return regmap_update_bits(decoder->regmap,
+                                         TVP5150_INT_ENABLE_REG_A,
+                                         TVP5150_INT_A_LOCK, 0);
+       return 0;
+}
+
+static int __maybe_unused tvp5150_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct tvp5150 *decoder = to_tvp5150(sd);
+
+       if (decoder->irq)
+               /* Enable lock interrupt */
+               return regmap_update_bits(decoder->regmap,
+                                         TVP5150_INT_ENABLE_REG_A,
+                                         TVP5150_INT_A_LOCK,
+                                         TVP5150_INT_A_LOCK);
+       return 0;
+}
 
 static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
-       unsigned int mask, val = 0, int_val = 0;
+       unsigned int mask, val = 0;
+       int ret;
 
        mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
               TVP5150_MISC_CTL_CLOCK_OE;
 
        if (enable) {
+               ret = pm_runtime_get_sync(sd->dev);
+               if (ret < 0) {
+                       pm_runtime_put_noidle(sd->dev);
+                       return ret;
+               }
+
                tvp5150_enable(sd);
 
                /* Enable outputs if decoder is locked */
@@ -1223,15 +1462,13 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
                        val = decoder->lock ? decoder->oe : 0;
                else
                        val = decoder->oe;
-               int_val = TVP5150_INT_A_LOCK;
+
                v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt);
+       } else {
+               pm_runtime_put(sd->dev);
        }
 
        regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val);
-       if (decoder->irq)
-               /* Enable / Disable lock interrupt */
-               regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A,
-                                  TVP5150_INT_A_LOCK, int_val);
 
        return 0;
 }
@@ -1342,6 +1579,19 @@ static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi
 }
 #endif
 
+static int tvp5150_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+                                  struct v4l2_event_subscription *sub)
+{
+       switch (sub->type) {
+       case V4L2_EVENT_SOURCE_CHANGE:
+               return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
+       case V4L2_EVENT_CTRL:
+               return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
+       default:
+               return -EINVAL;
+       }
+}
+
 static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 {
        int status = tvp5150_read(sd, 0x88);
@@ -1352,40 +1602,96 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 
 static int tvp5150_registered(struct v4l2_subdev *sd)
 {
-#ifdef CONFIG_MEDIA_CONTROLLER
+#if defined(CONFIG_MEDIA_CONTROLLER)
        struct tvp5150 *decoder = to_tvp5150(sd);
-       int ret = 0;
-       int i;
-
-       for (i = 0; i < TVP5150_INPUT_NUM; i++) {
-               struct media_entity *input = &decoder->input_ent[i];
-               struct media_pad *pad = &decoder->input_pad[i];
-
-               if (!input->name)
-                       continue;
+       unsigned int i;
+       int ret;
 
-               decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
+       /*
+        * Setup connector pads and links. Enable the link to the first
+        * available connector per default.
+        */
+       for (i = 0; i < decoder->connectors_num; i++) {
+               struct media_entity *con = &decoder->connectors[i].ent;
+               struct media_pad *pad = &decoder->connectors[i].pad;
+               struct v4l2_fwnode_connector *v4l2c =
+                       &decoder->connectors[i].base;
+               struct v4l2_connector_link *link =
+                       v4l2_connector_first_link(v4l2c);
+               unsigned int port = link->fwnode_link.remote_port;
+               unsigned int flags = i ? 0 : MEDIA_LNK_FL_ENABLED;
+               bool is_svideo = v4l2c->type == V4L2_CONN_SVIDEO;
+
+               pad->flags = MEDIA_PAD_FL_SOURCE;
+               ret = media_entity_pads_init(con, 1, pad);
+               if (ret < 0)
+                       goto err;
 
-               ret = media_entity_pads_init(input, 1, pad);
+               ret = media_device_register_entity(sd->v4l2_dev->mdev, con);
                if (ret < 0)
-                       return ret;
+                       goto err;
 
-               ret = media_device_register_entity(sd->v4l2_dev->mdev, input);
+               ret = media_create_pad_link(con, 0, &sd->entity, port, flags);
                if (ret < 0)
-                       return ret;
+                       goto err;
 
-               ret = media_create_pad_link(input, 0, &sd->entity,
-                                           TVP5150_PAD_IF_INPUT, 0);
-               if (ret < 0) {
-                       media_device_unregister_entity(input);
-                       return ret;
+               if (is_svideo) {
+                       /*
+                        * Check tvp5150_link_setup() comments for more
+                        * information.
+                        */
+                       link = v4l2_connector_last_link(v4l2c);
+                       port = link->fwnode_link.remote_port;
+                       ret = media_create_pad_link(con, 0, &sd->entity, port,
+                                                   flags);
+                       if (ret < 0)
+                               goto err;
+               }
+
+               /* Enable default input. */
+               if (flags == MEDIA_LNK_FL_ENABLED) {
+                       decoder->input =
+                               is_svideo ? TVP5150_SVIDEO :
+                               port == 0 ? TVP5150_COMPOSITE0 :
+                               TVP5150_COMPOSITE1;
+
+                       tvp5150_selmux(sd);
+                       decoder->cur_connector = &decoder->connectors[i];
+                       tvp5150_s_std(sd, v4l2c->connector.analog.sdtv_stds);
                }
        }
+
+       return 0;
+
+err:
+       for (i = 0; i < decoder->connectors_num; i++)
+               media_device_unregister_entity(&decoder->connectors[i].ent);
+       return ret;
 #endif
 
        return 0;
 }
 
+static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       int ret;
+
+       ret = pm_runtime_get_sync(sd->dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(sd->dev);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int tvp5150_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       pm_runtime_put(sd->dev);
+
+       return 0;
+}
+
 /* ----------------------------------------------------------------------- */
 
 static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
@@ -1399,6 +1705,8 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
        .g_register = tvp5150_g_register,
        .s_register = tvp5150_s_register,
 #endif
+       .subscribe_event = tvp5150_subscribe_event,
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,
 };
 
 static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
@@ -1441,6 +1749,8 @@ static const struct v4l2_subdev_ops tvp5150_ops = {
 
 static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = {
        .registered = tvp5150_registered,
+       .open = tvp5150_open,
+       .close = tvp5150_close,
 };
 
 /****************************************************************************
@@ -1591,102 +1901,211 @@ static int tvp5150_init(struct i2c_client *c)
        return 0;
 }
 
-static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static int tvp5150_mc_init(struct tvp5150 *decoder)
 {
-       struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
-       struct device_node *ep;
-#ifdef CONFIG_MEDIA_CONTROLLER
-       struct device_node *connectors, *child;
-       struct media_entity *input;
-       const char *name;
-       u32 input_type;
-#endif
-       unsigned int flags;
-       int ret = 0;
+       struct v4l2_subdev *sd = &decoder->sd;
+       unsigned int i;
 
-       ep = of_graph_get_next_endpoint(np, NULL);
-       if (!ep)
-               return -EINVAL;
+       sd->entity.ops = &tvp5150_sd_media_ops;
+       sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
 
-       ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
-       if (ret)
-               goto err;
+       for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
+               decoder->pads[i].flags = MEDIA_PAD_FL_SINK;
+               decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG;
+       }
 
-       flags = bus_cfg.bus.parallel.flags;
+       decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE;
+       decoder->pads[i].sig_type = PAD_SIGNAL_DV;
 
-       if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
-           !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
-             flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
-             flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
-               ret = -EINVAL;
-               goto err;
-       }
+       return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS,
+                                     decoder->pads);
+}
 
-       decoder->mbus_type = bus_cfg.bus_type;
+#else /* !defined(CONFIG_MEDIA_CONTROLLER) */
 
-#ifdef CONFIG_MEDIA_CONTROLLER
-       connectors = of_get_child_by_name(np, "connectors");
+static inline int tvp5150_mc_init(struct tvp5150 *decoder)
+{
+       return 0;
+}
+#endif /* defined(CONFIG_MEDIA_CONTROLLER) */
 
-       if (!connectors)
-               goto err;
+static int tvp5150_validate_connectors(struct tvp5150 *decoder)
+{
+       struct device *dev = decoder->sd.dev;
+       struct tvp5150_connector *tvpc;
+       struct v4l2_fwnode_connector *v4l2c;
+       unsigned int i;
+
+       if (!decoder->connectors_num) {
+               dev_err(dev, "No valid connector found\n");
+               return -ENODEV;
+       }
 
-       for_each_available_child_of_node(connectors, child) {
-               ret = of_property_read_u32(child, "input", &input_type);
-               if (ret) {
-                       dev_err(decoder->sd.dev,
-                                "missing type property in node %pOFn\n",
-                                child);
-                       of_node_put(child);
-                       goto err_connector;
+       for (i = 0; i < decoder->connectors_num; i++) {
+               struct v4l2_connector_link *link0 = NULL;
+               struct v4l2_connector_link *link1;
+
+               tvpc = &decoder->connectors[i];
+               v4l2c = &tvpc->base;
+
+               if (v4l2c->type == V4L2_CONN_COMPOSITE) {
+                       if (v4l2c->nr_of_links != 1) {
+                               dev_err(dev, "Composite: connector needs 1 link\n");
+                               return -EINVAL;
+                       }
+                       link0 = v4l2_connector_first_link(v4l2c);
+                       if (!link0) {
+                               dev_err(dev, "Composite: invalid first link\n");
+                               return -EINVAL;
+                       }
+                       if (link0->fwnode_link.remote_id == 1) {
+                               dev_err(dev, "Composite: invalid endpoint id\n");
+                               return -EINVAL;
+                       }
                }
 
-               if (input_type >= TVP5150_INPUT_NUM) {
-                       ret = -EINVAL;
-                       of_node_put(child);
-                       goto err_connector;
+               if (v4l2c->type == V4L2_CONN_SVIDEO) {
+                       if (v4l2c->nr_of_links != 2) {
+                               dev_err(dev, "SVideo: connector needs 2 links\n");
+                               return -EINVAL;
+                       }
+                       link0 = v4l2_connector_first_link(v4l2c);
+                       if (!link0) {
+                               dev_err(dev, "SVideo: invalid first link\n");
+                               return -EINVAL;
+                       }
+                       link1 = v4l2_connector_last_link(v4l2c);
+                       if (link0->fwnode_link.remote_port ==
+                           link1->fwnode_link.remote_port) {
+                               dev_err(dev, "SVideo: invalid link setup\n");
+                               return -EINVAL;
+                       }
                }
 
-               input = &decoder->input_ent[input_type];
+               if (!(v4l2c->connector.analog.sdtv_stds & TVP5150_STD_MASK)) {
+                       dev_err(dev, "Unsupported tv-norm on connector %s\n",
+                               v4l2c->name);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np)
+{
+       struct device *dev = decoder->sd.dev;
+       struct v4l2_fwnode_endpoint bus_cfg = {
+               .bus_type = V4L2_MBUS_UNKNOWN
+       };
+       struct device_node *ep_np;
+       struct tvp5150_connector *tvpc;
+       struct v4l2_fwnode_connector *v4l2c;
+       unsigned int flags, ep_num;
+       unsigned int i;
+       int ret;
+
+       /* At least 1 output and 1 input */
+       ep_num = of_graph_get_endpoint_count(np);
+       if (ep_num < 2 || ep_num > 5) {
+               dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n");
+               return -EINVAL;
+       }
 
-               /* Each input connector can only be defined once */
-               if (input->name) {
-                       dev_err(decoder->sd.dev,
-                                "input %s with same type already exists\n",
-                                input->name);
-                       of_node_put(child);
-                       ret = -EINVAL;
-                       goto err_connector;
+       /* Layout if all connectors are used:
+        *
+        * tvp-5150 port@0 (AIP1A)
+        *      endpoint@0 -----------> Comp0-Con  port
+        *      endpoint@1 --------+--> Svideo-Con port
+        * tvp-5150 port@1 (AIP1B) |
+        *      endpoint@1 --------+
+        *      endpoint@0 -----------> Comp1-Con  port
+        * tvp-5150 port@2
+        *      endpoint (video bitstream output at YOUT[0-7] parallel bus)
+        */
+       for_each_endpoint_of_node(np, ep_np) {
+               struct fwnode_handle *ep_fwnode = of_fwnode_handle(ep_np);
+               unsigned int next_connector = decoder->connectors_num;
+               struct of_endpoint ep;
+
+               of_graph_parse_endpoint(ep_np, &ep);
+               if (ep.port > 1 || ep.id > 1) {
+                       dev_dbg(dev, "Ignore connector on port@%u/ep@%u\n",
+                               ep.port, ep.id);
+                       continue;
                }
 
-               switch (input_type) {
-               case TVP5150_COMPOSITE0:
-               case TVP5150_COMPOSITE1:
-                       input->function = MEDIA_ENT_F_CONN_COMPOSITE;
-                       break;
-               case TVP5150_SVIDEO:
-                       input->function = MEDIA_ENT_F_CONN_SVIDEO;
-                       break;
+               tvpc = &decoder->connectors[next_connector];
+               v4l2c = &tvpc->base;
+
+               if (ep.port == 0 || (ep.port == 1 && ep.id == 0)) {
+                       ret = v4l2_fwnode_connector_parse(ep_fwnode, v4l2c);
+                       if (ret)
+                               goto err_put;
+                       ret = v4l2_fwnode_connector_add_link(ep_fwnode, v4l2c);
+                       if (ret)
+                               goto err_put;
+                       decoder->connectors_num++;
+               } else {
+                       /* Adding the 2nd svideo link */
+                       for (i = 0; i < TVP5150_MAX_CONNECTORS; i++) {
+                               tvpc = &decoder->connectors[i];
+                               v4l2c = &tvpc->base;
+                               if (v4l2c->type == V4L2_CONN_SVIDEO)
+                                       break;
+                       }
+
+                       ret = v4l2_fwnode_connector_add_link(ep_fwnode, v4l2c);
+                       if (ret)
+                               goto err_put;
                }
+       }
 
-               input->flags = MEDIA_ENT_FL_CONNECTOR;
+       ret = tvp5150_validate_connectors(decoder);
+       if (ret)
+               goto err_free;
+
+       for (i = 0; i < decoder->connectors_num; i++) {
+               tvpc = &decoder->connectors[i];
+               v4l2c = &tvpc->base;
+               tvpc->ent.flags = MEDIA_ENT_FL_CONNECTOR;
+               tvpc->ent.function = v4l2c->type == V4L2_CONN_SVIDEO ?
+                       MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE;
+               tvpc->ent.name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
+                                               v4l2c->name, v4l2c->label ?
+                                               v4l2c->label : "");
+       }
 
-               ret = of_property_read_string(child, "label", &name);
-               if (ret < 0) {
-                       dev_err(decoder->sd.dev,
-                                "missing label property in node %pOFn\n",
-                                child);
-                       of_node_put(child);
-                       goto err_connector;
-               }
+       ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0);
+       if (!ep_np) {
+               dev_err(dev, "Error no output endpoint available\n");
+               goto err_free;
+       }
+       ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np), &bus_cfg);
+       of_node_put(ep_np);
+       if (ret)
+               goto err_free;
 
-               input->name = name;
+       flags = bus_cfg.bus.parallel.flags;
+       if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL &&
+           !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH &&
+             flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH &&
+             flags & V4L2_MBUS_FIELD_EVEN_LOW)) {
+               ret = -EINVAL;
+               goto err_free;
        }
 
-err_connector:
-       of_node_put(connectors);
-#endif
-err:
-       of_node_put(ep);
+       decoder->mbus_type = bus_cfg.bus_type;
+
+       return 0;
+
+err_put:
+       of_node_put(ep_np);
+err_free:
+       for (i = 0; i < TVP5150_MAX_CONNECTORS; i++)
+               v4l2_fwnode_connector_free(&decoder->connectors[i].base);
+
        return ret;
 }
 
@@ -1701,6 +2120,7 @@ static int tvp5150_probe(struct i2c_client *c)
        struct v4l2_subdev *sd;
        struct device_node *np = c->dev.of_node;
        struct regmap *map;
+       unsigned int i;
        int res;
 
        /* Check if the adapter supports the needed features */
@@ -1722,6 +2142,9 @@ static int tvp5150_probe(struct i2c_client *c)
 
        core->regmap = map;
        sd = &core->sd;
+       v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
+       sd->internal_ops = &tvp5150_internal_ops;
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
 
        if (IS_ENABLED(CONFIG_OF) && np) {
                res = tvp5150_parse_dt(core, np);
@@ -1734,30 +2157,29 @@ static int tvp5150_probe(struct i2c_client *c)
                core->mbus_type = V4L2_MBUS_BT656;
        }
 
-       v4l2_i2c_subdev_init(sd, c, &tvp5150_ops);
-       sd->internal_ops = &tvp5150_internal_ops;
-       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-
-#if defined(CONFIG_MEDIA_CONTROLLER)
-       core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK;
-       core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG;
-       core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
-       core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
-
-       sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
-
-       res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads);
-       if (res < 0)
+       res = tvp5150_mc_init(core);
+       if (res)
                return res;
 
-       sd->entity.ops = &tvp5150_sd_media_ops;
-#endif
-
        res = tvp5150_detect_version(core);
        if (res < 0)
                return res;
 
-       core->norm = V4L2_STD_ALL;      /* Default is autodetect */
+       /*
+        * Iterate over all available connectors in case they are supported and
+        * successfully parsed. Fallback to default autodetect in case they
+        * aren't supported.
+        */
+       for (i = 0; i < core->connectors_num; i++) {
+               struct v4l2_fwnode_connector *v4l2c;
+
+               v4l2c = &core->connectors[i].base;
+               core->norm |= v4l2c->connector.analog.sdtv_stds;
+       }
+
+       if (!core->connectors_num)
+               core->norm = V4L2_STD_ALL;
+
        core->detected_norm = V4L2_STD_UNKNOWN;
        core->input = TVP5150_COMPOSITE1;
        core->enable = true;
@@ -1802,6 +2224,11 @@ static int tvp5150_probe(struct i2c_client *c)
 
        if (debug > 1)
                tvp5150_log_status(sd);
+
+       pm_runtime_set_active(&c->dev);
+       pm_runtime_enable(&c->dev);
+       pm_runtime_idle(&c->dev);
+
        return 0;
 
 err:
@@ -1813,18 +2240,32 @@ static int tvp5150_remove(struct i2c_client *c)
 {
        struct v4l2_subdev *sd = i2c_get_clientdata(c);
        struct tvp5150 *decoder = to_tvp5150(sd);
+       unsigned int i;
 
        dev_dbg_lvl(sd->dev, 1, debug,
                "tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
                c->addr << 1);
 
+       for (i = 0; i < decoder->connectors_num; i++)
+               v4l2_fwnode_connector_free(&decoder->connectors[i].base);
+       for (i = 0; i < decoder->connectors_num; i++)
+               media_device_unregister_entity(&decoder->connectors[i].ent);
        v4l2_async_unregister_subdev(sd);
        v4l2_ctrl_handler_free(&decoder->hdl);
+       pm_runtime_disable(&c->dev);
+       pm_runtime_set_suspended(&c->dev);
+
        return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
+static const struct dev_pm_ops tvp5150_pm_ops = {
+       SET_RUNTIME_PM_OPS(tvp5150_runtime_suspend,
+                          tvp5150_runtime_resume,
+                          NULL)
+};
+
 static const struct i2c_device_id tvp5150_id[] = {
        { "tvp5150", 0 },
        { }
@@ -1843,6 +2284,7 @@ static struct i2c_driver tvp5150_driver = {
        .driver = {
                .of_match_table = of_match_ptr(tvp5150_of_match),
                .name   = "tvp5150",
+               .pm     = &tvp5150_pm_ops,
        },
        .probe_new      = tvp5150_probe,
        .remove         = tvp5150_remove,
index 0781417..0465832 100644 (file)
@@ -255,7 +255,7 @@ static int amg88xx_set_power(struct video_i2c_data *data, bool on)
        return amg88xx_set_power_off(data);
 }
 
-#if IS_ENABLED(CONFIG_HWMON)
+#if IS_REACHABLE(CONFIG_HWMON)
 
 static const u32 amg88xx_temp_config[] = {
        HWMON_T_INPUT,
@@ -858,7 +858,7 @@ static int video_i2c_probe(struct i2c_client *client,
                }
        }
 
-       ret = video_register_device(&data->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&data->vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0)
                goto error_pm_disable;
 
index 7c429ce..211279c 100644 (file)
@@ -639,9 +639,9 @@ int media_get_pad_index(struct media_entity *entity, bool is_sink,
                return -EINVAL;
 
        for (i = 0; i < entity->num_pads; i++) {
-               if (entity->pads[i].flags == MEDIA_PAD_FL_SINK)
+               if (entity->pads[i].flags & MEDIA_PAD_FL_SINK)
                        pad_is_sink = true;
-               else if (entity->pads[i].flags == MEDIA_PAD_FL_SOURCE)
+               else if (entity->pads[i].flags & MEDIA_PAD_FL_SOURCE)
                        pad_is_sink = false;
                else
                        continue;       /* This is an error! */
@@ -662,9 +662,14 @@ media_create_pad_link(struct media_entity *source, u16 source_pad,
        struct media_link *link;
        struct media_link *backlink;
 
-       BUG_ON(source == NULL || sink == NULL);
-       BUG_ON(source_pad >= source->num_pads);
-       BUG_ON(sink_pad >= sink->num_pads);
+       if (WARN_ON(!source || !sink) ||
+           WARN_ON(source_pad >= source->num_pads) ||
+           WARN_ON(sink_pad >= sink->num_pads))
+               return -EINVAL;
+       if (WARN_ON(!(source->pads[source_pad].flags & MEDIA_PAD_FL_SOURCE)))
+               return -EINVAL;
+       if (WARN_ON(!(sink->pads[sink_pad].flags & MEDIA_PAD_FL_SINK)))
+               return -EINVAL;
 
        link = media_add_link(&source->links);
        if (link == NULL)
index a359da7..9144f79 100644 (file)
@@ -2964,7 +2964,7 @@ static int bttv_open(struct file *file)
 
        dprintk("open dev=%s\n", video_device_node_name(vdev));
 
-       if (vdev->vfl_type == VFL_TYPE_GRABBER) {
+       if (vdev->vfl_type == VFL_TYPE_VIDEO) {
                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        } else if (vdev->vfl_type == VFL_TYPE_VBI) {
                type = V4L2_BUF_TYPE_VBI_CAPTURE;
@@ -3905,7 +3905,7 @@ static int bttv_register_video(struct bttv *btv)
        if (no_overlay <= 0)
                btv->video_dev.device_caps |= V4L2_CAP_VIDEO_OVERLAY;
 
-       if (video_register_device(&btv->video_dev, VFL_TYPE_GRABBER,
+       if (video_register_device(&btv->video_dev, VFL_TYPE_VIDEO,
                                  video_nr[btv->c.nr]) < 0)
                goto err;
        pr_info("%d: registered device %s\n",
index c520750..0ff3749 100644 (file)
@@ -1272,7 +1272,7 @@ static int cobalt_node_register(struct cobalt *cobalt, int node)
        video_set_drvdata(vdev, s);
        ret = vb2_queue_init(q);
        if (!s->is_audio && ret == 0)
-               ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+               ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        else if (!s->is_dummy)
                ret = cobalt_alsa_init(s);
 
index b797185..3178df3 100644 (file)
@@ -48,19 +48,19 @@ static struct {
 } cx18_stream_info[] = {
        {       /* CX18_ENC_STREAM_TYPE_MPG */
                "encoder MPEG",
-               VFL_TYPE_GRABBER, 0,
+               VFL_TYPE_VIDEO, 0,
                PCI_DMA_FROMDEVICE,
                V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
                V4L2_CAP_AUDIO | V4L2_CAP_TUNER
        },
        {       /* CX18_ENC_STREAM_TYPE_TS */
                "TS",
-               VFL_TYPE_GRABBER, -1,
+               VFL_TYPE_VIDEO, -1,
                PCI_DMA_FROMDEVICE,
        },
        {       /* CX18_ENC_STREAM_TYPE_YUV */
                "encoder YUV",
-               VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET,
+               VFL_TYPE_VIDEO, CX18_V4L2_ENC_YUV_OFFSET,
                PCI_DMA_FROMDEVICE,
                V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
                V4L2_CAP_STREAMING | V4L2_CAP_AUDIO | V4L2_CAP_TUNER
@@ -74,13 +74,13 @@ static struct {
        },
        {       /* CX18_ENC_STREAM_TYPE_PCM */
                "encoder PCM audio",
-               VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET,
+               VFL_TYPE_VIDEO, CX18_V4L2_ENC_PCM_OFFSET,
                PCI_DMA_FROMDEVICE,
                V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
        },
        {       /* CX18_ENC_STREAM_TYPE_IDX */
                "encoder IDX",
-               VFL_TYPE_GRABBER, -1,
+               VFL_TYPE_VIDEO, -1,
                PCI_DMA_FROMDEVICE,
        },
        {       /* CX18_ENC_STREAM_TYPE_RAD */
@@ -434,7 +434,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
        name = video_device_node_name(&s->video_dev);
 
        switch (vfl_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n",
                          name, s->name, cx->stream_buffers[type],
                          cx->stream_buf_size[type] / 1024,
index 2327fe6..434677b 100644 (file)
@@ -1545,7 +1545,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
        if (dev->tuner_type != TUNER_ABSENT)
                dev->v4l_device->device_caps |= V4L2_CAP_TUNER;
        err = video_register_device(dev->v4l_device,
-               VFL_TYPE_GRABBER, -1);
+               VFL_TYPE_VIDEO, -1);
        if (err < 0) {
                pr_info("%s: can't register mpeg device\n", dev->name);
                return err;
index 7fc408e..000c108 100644 (file)
@@ -1304,7 +1304,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
                                      V4L2_CAP_AUDIO | V4L2_CAP_VIDEO_CAPTURE;
        if (dev->tuner_type != TUNER_ABSENT)
                dev->video_dev->device_caps |= V4L2_CAP_TUNER;
-       err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER,
+       err = video_register_device(dev->video_dev, VFL_TYPE_VIDEO,
                                    video_nr[dev->nr]);
        if (err < 0) {
                pr_info("%s: can't register video device\n",
index a10261d..1b80c99 100644 (file)
@@ -757,7 +757,7 @@ int cx25821_video_register(struct cx25821_dev *dev)
                snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
                video_set_drvdata(vdev, chan);
 
-               err = video_register_device(vdev, VFL_TYPE_GRABBER,
+               err = video_register_device(vdev, VFL_TYPE_VIDEO,
                                            video_nr[dev->nr]);
 
                if (err < 0)
index d3da7f4..fa4ca00 100644 (file)
@@ -1138,7 +1138,7 @@ static int blackbird_register_video(struct cx8802_dev *dev)
                                    V4L2_CAP_VIDEO_CAPTURE;
        if (dev->core->board.tuner_type != UNSET)
                dev->mpeg_dev.device_caps |= V4L2_CAP_TUNER;
-       err = video_register_device(&dev->mpeg_dev, VFL_TYPE_GRABBER, -1);
+       err = video_register_device(&dev->mpeg_dev, VFL_TYPE_VIDEO, -1);
        if (err < 0) {
                pr_info("can't register mpeg device\n");
                return err;
index b8abcd5..6aabc45 100644 (file)
@@ -1451,7 +1451,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
                                     V4L2_CAP_VIDEO_CAPTURE;
        if (core->board.tuner_type != UNSET)
                dev->video_dev.device_caps |= V4L2_CAP_TUNER;
-       err = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER,
+       err = video_register_device(&dev->video_dev, VFL_TYPE_VIDEO,
                                    video_nr[core->nr]);
        if (err < 0) {
                pr_err("can't register video device\n");
index 7480f0d..82581aa 100644 (file)
@@ -550,7 +550,7 @@ static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                                        IRQF_SHARED, DT3155_NAME, pd);
        if (err)
                goto err_iounmap;
-       err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1);
+       err = video_register_device(&pd->vdev, VFL_TYPE_VIDEO, -1);
        if (err)
                goto err_free_irq;
        dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor);
index 1adfdc7..92f5ead 100644 (file)
@@ -1647,7 +1647,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
        vdev->queue = &q->vbq;
        vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING;
        video_set_drvdata(vdev, cio2);
-       r = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       r = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (r) {
                dev_err(&cio2->pci_dev->dev,
                        "failed to register video device (%d)\n", r);
index f7de911..f04ee84 100644 (file)
@@ -99,7 +99,7 @@ static struct {
 } ivtv_stream_info[] = {
        {       /* IVTV_ENC_STREAM_TYPE_MPG */
                "encoder MPG",
-               VFL_TYPE_GRABBER, 0,
+               VFL_TYPE_VIDEO, 0,
                PCI_DMA_FROMDEVICE, 0,
                V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
                        V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
@@ -107,7 +107,7 @@ static struct {
        },
        {       /* IVTV_ENC_STREAM_TYPE_YUV */
                "encoder YUV",
-               VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET,
+               VFL_TYPE_VIDEO, IVTV_V4L2_ENC_YUV_OFFSET,
                PCI_DMA_FROMDEVICE, 0,
                V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
                        V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
@@ -123,7 +123,7 @@ static struct {
        },
        {       /* IVTV_ENC_STREAM_TYPE_PCM */
                "encoder PCM",
-               VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
+               VFL_TYPE_VIDEO, IVTV_V4L2_ENC_PCM_OFFSET,
                PCI_DMA_FROMDEVICE, 0,
                V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_enc_fops
@@ -137,7 +137,7 @@ static struct {
        },
        {       /* IVTV_DEC_STREAM_TYPE_MPG */
                "decoder MPG",
-               VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
+               VFL_TYPE_VIDEO, IVTV_V4L2_DEC_MPG_OFFSET,
                PCI_DMA_TODEVICE, 0,
                V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_dec_fops
@@ -158,7 +158,7 @@ static struct {
        },
        {       /* IVTV_DEC_STREAM_TYPE_YUV */
                "decoder YUV",
-               VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET,
+               VFL_TYPE_VIDEO, IVTV_V4L2_DEC_YUV_OFFSET,
                PCI_DMA_TODEVICE, 0,
                V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE,
                &ivtv_v4l2_dec_fops
@@ -318,7 +318,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
        name = video_device_node_name(&s->vdev);
 
        switch (vfl_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                IVTV_INFO("Registered device %s for %s (%d kB)\n",
                        name, s->name, itv->options.kilobytes[type]);
                break;
index 3a4c29b..73e064e 100644 (file)
@@ -1711,7 +1711,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
        v4l2_ctrl_handler_setup(&meye.hdl);
        meye.vdev.ctrl_handler = &meye.hdl;
 
-       if (video_register_device(&meye.vdev, VFL_TYPE_GRABBER,
+       if (video_register_device(&meye.vdev, VFL_TYPE_VIDEO,
                                  video_nr) < 0) {
                v4l2_err(v4l2_dev, "video_register_device failed\n");
                goto outvideoreg;
index 2d582c0..e4623ed 100644 (file)
@@ -1214,7 +1214,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
        if (saa7134_no_overlay <= 0)
                dev->video_dev->device_caps |= V4L2_CAP_VIDEO_OVERLAY;
 
-       err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
+       err = video_register_device(dev->video_dev,VFL_TYPE_VIDEO,
                                    video_nr[dev->nr]);
        if (err < 0) {
                pr_info("%s: can't register video device\n",
index cb65d34..8ad7879 100644 (file)
@@ -291,7 +291,7 @@ static int empress_init(struct saa7134_dev *dev)
                dev->empress_dev->device_caps |= V4L2_CAP_TUNER;
 
        video_set_drvdata(dev->empress_dev, dev);
-       err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
+       err = video_register_device(dev->empress_dev,VFL_TYPE_VIDEO,
                                    empress_nr[dev->nr]);
        if (err < 0) {
                pr_info("%s: can't register video device\n",
index 342cabf..a8ac94f 100644 (file)
@@ -1008,8 +1008,7 @@ int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
         */
        if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
            (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
-               pm_qos_add_request(&dev->qos_request,
-                       PM_QOS_CPU_DMA_LATENCY, 20);
+               cpu_latency_qos_add_request(&dev->qos_request, 20);
        dmaq->seq_nr = 0;
 
        return 0;
@@ -1024,7 +1023,7 @@ void saa7134_vb2_stop_streaming(struct vb2_queue *vq)
 
        if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
            (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
-               pm_qos_remove_request(&dev->qos_request);
+               cpu_latency_qos_remove_request(&dev->qos_request);
 }
 
 static const struct vb2_ops vb2_qops = {
index f962269..2214c74 100644 (file)
@@ -289,7 +289,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
        vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
        vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
        vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
-       ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
+       ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_VIDEO);
        if (ret < 0) {
                pr_err("cannot register capture v4l2 device. skipping.\n");
                saa7146_vv_release(dev);
index bf5e553..39d14c1 100644 (file)
@@ -362,7 +362,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
        vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
        vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
        vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
-       if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
+       if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_VIDEO)) {
                pr_err("cannot register capture v4l2 device. skipping.\n");
                return -1;
        }
index e6a71c1..129a1f8 100644 (file)
@@ -707,7 +707,7 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
        vv_data.vid_ops.vidioc_g_register = vidioc_g_register;
        vv_data.vid_ops.vidioc_s_register = vidioc_s_register;
 #endif
-       if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
+       if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_VIDEO)) {
                ERR("cannot register capture v4l2 device. skipping.\n");
                saa7146_vv_release(dev);
                return -1;
index 3fca725..11e1eb6 100644 (file)
@@ -1087,7 +1087,7 @@ int saa7164_encoder_register(struct saa7164_port *port)
        v4l2_ctrl_handler_setup(hdl);
        video_set_drvdata(port->v4l_device, port);
        result = video_register_device(port->v4l_device,
-               VFL_TYPE_GRABBER, -1);
+               VFL_TYPE_VIDEO, -1);
        if (result < 0) {
                printk(KERN_INFO "%s: can't register mpeg device\n",
                        dev->name);
index 476d7f3..cbf8523 100644 (file)
@@ -1304,7 +1304,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
        solo_enc->vfd->queue = &solo_enc->vidq;
        solo_enc->vfd->lock = &solo_enc->lock;
        video_set_drvdata(solo_enc->vfd, solo_enc);
-       ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
+       ret = video_register_device(solo_enc->vfd, VFL_TYPE_VIDEO, nr);
        if (ret < 0)
                goto vdev_release;
 
index 7879206..54434f3 100644 (file)
@@ -692,7 +692,7 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
        while (erase_off(solo_dev))
                /* Do nothing */;
 
-       ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr);
+       ret = video_register_device(solo_dev->vfd, VFL_TYPE_VIDEO, nr);
        if (ret < 0)
                goto fail;
 
index fd3de3b..798574c 100644 (file)
@@ -1069,7 +1069,7 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
        vip->video_dev.lock = &vip->v4l_lock;
        video_set_drvdata(&vip->video_dev, vip);
 
-       ret = video_register_device(&vip->video_dev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&vip->video_dev, VFL_TYPE_VIDEO, -1);
        if (ret)
                goto vrelease;
 
index f3d6c3c..cabe006 100644 (file)
@@ -831,7 +831,7 @@ int av7110_init_v4l(struct av7110 *av7110)
        if (FW_VERSION(av7110->arm_app) < 0x2623)
                vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT;
 
-       if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
+       if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_VIDEO)) {
                ERR("cannot register capture device. skipping\n");
                saa7146_vv_release(dev);
                return -ENODEV;
index e2d482a..38cac50 100644 (file)
@@ -1470,7 +1470,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
                vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
                vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
 
-               if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
+               if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_VIDEO))) {
                        /* fixme: proper cleanup here */
                        ERR("cannot register capture v4l2 device\n");
                        saa7146_vv_release(dev);
index 09732ee..ec1e06d 100644 (file)
@@ -1156,7 +1156,7 @@ static int tw5864_video_input_init(struct tw5864_input *input, int video_nr)
        input->gop = GOP_SIZE;
        input->frame_interval = 1;
 
-       ret = video_register_device(&input->vdev, VFL_TYPE_GRABBER, video_nr);
+       ret = video_register_device(&input->vdev, VFL_TYPE_VIDEO, video_nr);
        if (ret)
                goto free_v4l2_hdl;
 
index 2fb82d5..10986fc 100644 (file)
@@ -962,7 +962,7 @@ int tw68_video_init2(struct tw68_dev *dev, int video_nr)
        dev->vdev.lock = &dev->lock;
        dev->vdev.queue = &dev->vidq;
        video_set_drvdata(&dev->vdev, dev);
-       return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
+       return video_register_device(&dev->vdev, VFL_TYPE_VIDEO, video_nr);
 }
 
 /*
index 9be8c6e..1ced2b0 100644 (file)
@@ -1282,7 +1282,7 @@ int tw686x_video_init(struct tw686x_dev *dev)
                vc->device = vdev;
                video_set_drvdata(vdev, vc);
 
-               err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+               err = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
                if (err < 0)
                        goto error;
                vc->num = vdev->num;
index f65e98d..e01bbb9 100644 (file)
@@ -507,6 +507,18 @@ config VIDEO_SUN8I_DEINTERLACE
           capability found on some SoCs, like H3.
           To compile this driver as a module choose m here.
 
+config VIDEO_SUN8I_ROTATE
+       tristate "Allwinner DE2 rotation driver"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on ARCH_SUNXI || COMPILE_TEST
+       depends on COMMON_CLK && OF
+       depends on PM
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       help
+          Support for the Allwinner DE2 rotation unit.
+          To compile this driver as a module choose m here.
+
 endif # V4L_MEM2MEM_DRIVERS
 
 # TI VIDEO PORT Helper Modules
@@ -610,49 +622,49 @@ config CEC_GPIO
          between compatible devices.
 
 config VIDEO_SAMSUNG_S5P_CEC
-       tristate "Samsung S5P CEC driver"
-       depends on ARCH_EXYNOS || COMPILE_TEST
-       select CEC_CORE
-       select CEC_NOTIFIER
-       help
-        This is a driver for Samsung S5P HDMI CEC interface. It uses the
-        generic CEC framework interface.
-        CEC bus is present in the HDMI connector and enables communication
-        between compatible devices.
+       tristate "Samsung S5P CEC driver"
+       depends on ARCH_EXYNOS || COMPILE_TEST
+       select CEC_CORE
+       select CEC_NOTIFIER
+       help
+         This is a driver for Samsung S5P HDMI CEC interface. It uses the
+         generic CEC framework interface.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
 
 config VIDEO_STI_HDMI_CEC
-       tristate "STMicroelectronics STiH4xx HDMI CEC driver"
-       depends on ARCH_STI || COMPILE_TEST
-       select CEC_CORE
-       select CEC_NOTIFIER
-       help
-        This is a driver for STIH4xx HDMI CEC interface. It uses the
-        generic CEC framework interface.
-        CEC bus is present in the HDMI connector and enables communication
-        between compatible devices.
+       tristate "STMicroelectronics STiH4xx HDMI CEC driver"
+       depends on ARCH_STI || COMPILE_TEST
+       select CEC_CORE
+       select CEC_NOTIFIER
+       help
+         This is a driver for STIH4xx HDMI CEC interface. It uses the
+         generic CEC framework interface.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
 
 config VIDEO_STM32_HDMI_CEC
-       tristate "STMicroelectronics STM32 HDMI CEC driver"
-       depends on ARCH_STM32 || COMPILE_TEST
-       select REGMAP
-       select REGMAP_MMIO
-       select CEC_CORE
-       help
-        This is a driver for STM32 interface. It uses the
-        generic CEC framework interface.
-        CEC bus is present in the HDMI connector and enables communication
-        between compatible devices.
+       tristate "STMicroelectronics STM32 HDMI CEC driver"
+       depends on ARCH_STM32 || COMPILE_TEST
+       select REGMAP
+       select REGMAP_MMIO
+       select CEC_CORE
+       help
+         This is a driver for STM32 interface. It uses the
+         generic CEC framework interface.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
 
 config VIDEO_TEGRA_HDMI_CEC
-       tristate "Tegra HDMI CEC driver"
-       depends on ARCH_TEGRA || COMPILE_TEST
-       select CEC_CORE
-       select CEC_NOTIFIER
-       help
-        This is a driver for the Tegra HDMI CEC interface. It uses the
-        generic CEC framework interface.
-        The CEC bus is present in the HDMI connector and enables communication
-        between compatible devices.
+       tristate "Tegra HDMI CEC driver"
+       depends on ARCH_TEGRA || COMPILE_TEST
+       select CEC_CORE
+       select CEC_NOTIFIER
+       help
+         This is a driver for the Tegra HDMI CEC interface. It uses the
+         generic CEC framework interface.
+         The CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
 
 config VIDEO_SECO_CEC
        tristate "SECO Boards HDMI CEC driver"
index 0910430..66079cc 100644 (file)
@@ -285,6 +285,7 @@ vpfe_ccdc_validate_param(struct vpfe_ccdc *ccdc,
        max_data = ccdc_data_size_max_bit(ccdcparam->data_sz);
 
        if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 ||
+           ccdcparam->data_sz > VPFE_CCDC_DATA_8BITS ||
            max_gamma > max_data) {
                vpfe_dbg(1, vpfe, "Invalid data line select\n");
                return -EINVAL;
@@ -324,7 +325,7 @@ static void vpfe_ccdc_restore_defaults(struct vpfe_ccdc *ccdc)
 
 static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev)
 {
-       struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+       struct vpfe_device *vpfe = to_vpfe(ccdc);
        u32 dma_cntl, pcr;
 
        pcr = vpfe_reg_read(ccdc, VPFE_PCR);
@@ -348,7 +349,7 @@ static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev)
 
 static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params)
 {
-       struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+       struct vpfe_device *vpfe = to_vpfe(ccdc);
        struct vpfe_ccdc_config_params_raw raw_params;
        int x;
 
@@ -504,7 +505,7 @@ vpfe_ccdc_config_black_compense(struct vpfe_ccdc *ccdc,
  */
 static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc)
 {
-       struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+       struct vpfe_device *vpfe = to_vpfe(ccdc);
        struct vpfe_ccdc_config_params_raw *config_params =
                                &ccdc->ccdc_cfg.bayer.config_params;
        struct ccdc_params_raw *params = &ccdc->ccdc_cfg.bayer;
@@ -609,7 +610,7 @@ static inline enum ccdc_buftype vpfe_ccdc_get_buftype(struct vpfe_ccdc *ccdc)
 
 static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt)
 {
-       struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+       struct vpfe_device *vpfe = to_vpfe(ccdc);
 
        vpfe_dbg(1, vpfe, "%s: if_type: %d, pixfmt:%s\n",
                 __func__, ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt));
@@ -741,7 +742,7 @@ static inline void vpfe_set_sdr_addr(struct vpfe_ccdc *ccdc, unsigned long addr)
 static int vpfe_ccdc_set_hw_if_params(struct vpfe_ccdc *ccdc,
                                      struct vpfe_hw_if_param *params)
 {
-       struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+       struct vpfe_device *vpfe = to_vpfe(ccdc);
 
        ccdc->ccdc_cfg.if_type = params->if_type;
 
@@ -2267,7 +2268,7 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe)
        vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
                            V4L2_CAP_READWRITE;
        video_set_drvdata(vdev, vpfe);
-       err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1);
+       err = video_register_device(&vpfe->video_dev, VFL_TYPE_VIDEO, -1);
        if (err) {
                vpfe_err(vpfe,
                        "Unable to register video device.\n");
index d8593cb..7d98db1 100644 (file)
@@ -1,4 +1,6 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2020 IBM Corp.
+// Copyright (c) 2019-2020 Intel Corporation
 
 #include <linux/atomic.h>
 #include <linux/bitfield.h>
 #define  VE_SEQ_CTRL_CAP_BUSY          BIT(16)
 #define  VE_SEQ_CTRL_COMP_BUSY         BIT(18)
 
-#ifdef CONFIG_MACH_ASPEED_G5
-#define  VE_SEQ_CTRL_JPEG_MODE         BIT(13) /* AST2500 */
-#else
-#define  VE_SEQ_CTRL_JPEG_MODE         BIT(8)  /* AST2400 */
-#endif /* CONFIG_MACH_ASPEED_G5 */
+#define AST2500_VE_SEQ_CTRL_JPEG_MODE  BIT(13)
+#define AST2400_VE_SEQ_CTRL_JPEG_MODE  BIT(8)
 
 #define VE_CTRL                                0x008
 #define  VE_CTRL_HSYNC_POL             BIT(0)
 #define  VE_COMP_CTRL_HQ_DCT_CHR       GENMASK(26, 22)
 #define  VE_COMP_CTRL_HQ_DCT_LUM       GENMASK(31, 27)
 
-#define VE_OFFSET_COMP_STREAM          0x078
+#define AST2400_VE_COMP_SIZE_READ_BACK 0x078
+#define AST2600_VE_COMP_SIZE_READ_BACK 0x084
 
 #define VE_SRC_LR_EDGE_DET             0x090
 #define  VE_SRC_LR_EDGE_DET_LEFT       GENMASK(11, 0)
@@ -220,6 +220,9 @@ struct aspeed_video {
        struct video_device vdev;
        struct mutex video_lock;        /* v4l2 and videobuf2 lock */
 
+       u32 jpeg_mode;
+       u32 comp_size_read;
+
        wait_queue_head_t wait;
        spinlock_t lock;                /* buffer list lock */
        struct delayed_work res_work;
@@ -243,6 +246,26 @@ struct aspeed_video {
 
 #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev)
 
+struct aspeed_video_config {
+       u32 jpeg_mode;
+       u32 comp_size_read;
+};
+
+static const struct aspeed_video_config ast2400_config = {
+       .jpeg_mode = AST2400_VE_SEQ_CTRL_JPEG_MODE,
+       .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK,
+};
+
+static const struct aspeed_video_config ast2500_config = {
+       .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE,
+       .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK,
+};
+
+static const struct aspeed_video_config ast2600_config = {
+       .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE,
+       .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK,
+};
+
 static const u32 aspeed_video_jpeg_header[ASPEED_VIDEO_JPEG_HEADER_SIZE] = {
        0xe0ffd8ff, 0x464a1000, 0x01004649, 0x60000101, 0x00006000, 0x0f00feff,
        0x00002d05, 0x00000000, 0x00000000, 0x00dbff00
@@ -572,7 +595,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
        if (sts & VE_INTERRUPT_COMP_COMPLETE) {
                struct aspeed_video_buffer *buf;
                u32 frame_size = aspeed_video_read(video,
-                                                  VE_OFFSET_COMP_STREAM);
+                                                  video->comp_size_read);
 
                spin_lock(&video->lock);
                clear_bit(VIDEO_FRAME_INPRG, &video->flags);
@@ -907,7 +930,7 @@ static void aspeed_video_init_regs(struct aspeed_video *video)
                FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) |
                FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10);
        u32 ctrl = VE_CTRL_AUTO_OR_CURSOR;
-       u32 seq_ctrl = VE_SEQ_CTRL_JPEG_MODE;
+       u32 seq_ctrl = video->jpeg_mode;
 
        if (video->frame_rate)
                ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate);
@@ -1565,14 +1588,14 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
                V4L2_CAP_STREAMING;
        vdev->v4l2_dev = v4l2_dev;
        strscpy(vdev->name, DEVICE_NAME, sizeof(vdev->name));
-       vdev->vfl_type = VFL_TYPE_GRABBER;
+       vdev->vfl_type = VFL_TYPE_VIDEO;
        vdev->vfl_dir = VFL_DIR_RX;
        vdev->release = video_device_release_empty;
        vdev->ioctl_ops = &aspeed_video_ioctl_ops;
        vdev->lock = &video->video_lock;
 
        video_set_drvdata(vdev, video);
-       rc = video_register_device(vdev, VFL_TYPE_GRABBER, 0);
+       rc = video_register_device(vdev, VFL_TYPE_VIDEO, 0);
        if (rc) {
                vb2_queue_release(vbq);
                v4l2_ctrl_handler_free(&video->ctrl_handler);
@@ -1653,16 +1676,37 @@ err_unprepare_eclk:
        return rc;
 }
 
+static const struct of_device_id aspeed_video_of_match[] = {
+       { .compatible = "aspeed,ast2400-video-engine", .data = &ast2400_config },
+       { .compatible = "aspeed,ast2500-video-engine", .data = &ast2500_config },
+       { .compatible = "aspeed,ast2600-video-engine", .data = &ast2600_config },
+       {}
+};
+MODULE_DEVICE_TABLE(of, aspeed_video_of_match);
+
 static int aspeed_video_probe(struct platform_device *pdev)
 {
+       const struct aspeed_video_config *config;
+       const struct of_device_id *match;
+       struct aspeed_video *video;
        int rc;
-       struct resource *res;
-       struct aspeed_video *video =
-               devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL);
 
+       video = devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL);
        if (!video)
                return -ENOMEM;
 
+       video->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(video->base))
+               return PTR_ERR(video->base);
+
+       match = of_match_node(aspeed_video_of_match, pdev->dev.of_node);
+       if (!match)
+               return -EINVAL;
+
+       config = match->data;
+       video->jpeg_mode = config->jpeg_mode;
+       video->comp_size_read = config->comp_size_read;
+
        video->frame_rate = 30;
        video->dev = &pdev->dev;
        spin_lock_init(&video->lock);
@@ -1671,13 +1715,6 @@ static int aspeed_video_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work);
        INIT_LIST_HEAD(&video->buffers);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       video->base = devm_ioremap_resource(video->dev, res);
-
-       if (IS_ERR(video->base))
-               return PTR_ERR(video->base);
-
        rc = aspeed_video_init(video);
        if (rc)
                return rc;
@@ -1716,13 +1753,6 @@ static int aspeed_video_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id aspeed_video_of_match[] = {
-       { .compatible = "aspeed,ast2400-video-engine" },
-       { .compatible = "aspeed,ast2500-video-engine" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, aspeed_video_of_match);
-
 static struct platform_driver aspeed_video_driver = {
        .driver = {
                .name = DEVICE_NAME,
index d7669a0..a6e9797 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/videodev2.h>
+#include <linux/atmel-isc-media.h>
 
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
@@ -224,10 +225,35 @@ const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
        (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \
        (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8)))
 
+#define ISC_CTRL_ISC_TO_V4L2(x) ((x) == ISC_WB_O_ZERO_VAL ? 0 : (x))
+#define ISC_CTRL_V4L2_TO_ISC(x) ((x) ? (x) : ISC_WB_O_ZERO_VAL)
+
+static inline void isc_update_v4l2_ctrls(struct isc_device *isc)
+{
+       struct isc_ctrls *ctrls = &isc->ctrls;
+
+       /* In here we set the v4l2 controls w.r.t. our pipeline config */
+       v4l2_ctrl_s_ctrl(isc->r_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_R]);
+       v4l2_ctrl_s_ctrl(isc->b_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_B]);
+       v4l2_ctrl_s_ctrl(isc->gr_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GR]);
+       v4l2_ctrl_s_ctrl(isc->gb_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GB]);
+
+       v4l2_ctrl_s_ctrl(isc->r_off_ctrl,
+                        ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_R]));
+       v4l2_ctrl_s_ctrl(isc->b_off_ctrl,
+                        ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_B]));
+       v4l2_ctrl_s_ctrl(isc->gr_off_ctrl,
+                        ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GR]));
+       v4l2_ctrl_s_ctrl(isc->gb_off_ctrl,
+                        ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GB]));
+}
+
 static inline void isc_update_awb_ctrls(struct isc_device *isc)
 {
        struct isc_ctrls *ctrls = &isc->ctrls;
 
+       /* In here we set our actual hw pipeline config */
+
        regmap_write(isc->regmap, ISC_WB_O_RGR,
                     (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) |
                     ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16));
@@ -662,11 +688,9 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
 
        bay_cfg = isc->config.sd_format->cfa_baycfg;
 
-       if (ctrls->awb == ISC_WB_NONE)
-               isc_reset_awb_ctrls(isc);
-
        regmap_write(regmap, ISC_WB_CFG, bay_cfg);
        isc_update_awb_ctrls(isc);
+       isc_update_v4l2_ctrls(isc);
 
        regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
 
@@ -1396,6 +1420,7 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
            isc->try_config.sd_format != isc->config.sd_format) {
                isc->ctrls.hist_stat = HIST_INIT;
                isc_reset_awb_ctrls(isc);
+               isc_update_v4l2_ctrls(isc);
        }
        /* make the try configuration active */
        isc->config = isc->try_config;
@@ -1814,10 +1839,6 @@ static void isc_awb_work(struct work_struct *w)
        ctrls->hist_id = hist_id;
        baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
 
-       /* if no more auto white balance, reset controls. */
-       if (ctrls->awb == ISC_WB_NONE)
-               isc_reset_awb_ctrls(isc);
-
        pm_runtime_get_sync(isc->dev);
 
        /*
@@ -1842,6 +1863,8 @@ static void isc_awb_work(struct work_struct *w)
                if (ctrls->awb == ISC_WB_ONETIME) {
                        v4l2_info(&isc->v4l2_dev,
                                  "Completed one time white-balance adjustment.\n");
+                       /* update the v4l2 controls values */
+                       isc_update_v4l2_ctrls(isc);
                        ctrls->awb = ISC_WB_NONE;
                }
        }
@@ -1873,6 +1896,27 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_GAMMA:
                ctrls->gamma_index = ctrl->val;
                break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops isc_ctrl_ops = {
+       .s_ctrl = isc_s_ctrl,
+};
+
+static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct isc_device *isc = container_of(ctrl->handler,
+                                            struct isc_device, ctrls.handler);
+       struct isc_ctrls *ctrls = &isc->ctrls;
+
+       if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+               return 0;
+
+       switch (ctrl->id) {
        case V4L2_CID_AUTO_WHITE_BALANCE:
                if (ctrl->val == 1)
                        ctrls->awb = ISC_WB_AUTO;
@@ -1883,36 +1927,142 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
                if (!isc->config.sd_format)
                        break;
 
-               if (ctrls->hist_stat != HIST_ENABLED)
-                       isc_reset_awb_ctrls(isc);
+               /* configure the controls with new values from v4l2 */
+               if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new)
+                       ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val;
+               if (ctrl->cluster[ISC_CTRL_B_GAIN]->is_new)
+                       ctrls->gain[ISC_HIS_CFG_MODE_B] = isc->b_gain_ctrl->val;
+               if (ctrl->cluster[ISC_CTRL_GR_GAIN]->is_new)
+                       ctrls->gain[ISC_HIS_CFG_MODE_GR] = isc->gr_gain_ctrl->val;
+               if (ctrl->cluster[ISC_CTRL_GB_GAIN]->is_new)
+                       ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val;
+
+               if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new)
+                       ctrls->offset[ISC_HIS_CFG_MODE_R] =
+                               ISC_CTRL_V4L2_TO_ISC(isc->r_off_ctrl->val);
+               if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new)
+                       ctrls->offset[ISC_HIS_CFG_MODE_B] =
+                               ISC_CTRL_V4L2_TO_ISC(isc->b_off_ctrl->val);
+               if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new)
+                       ctrls->offset[ISC_HIS_CFG_MODE_GR] =
+                               ISC_CTRL_V4L2_TO_ISC(isc->gr_off_ctrl->val);
+               if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new)
+                       ctrls->offset[ISC_HIS_CFG_MODE_GB] =
+                               ISC_CTRL_V4L2_TO_ISC(isc->gb_off_ctrl->val);
 
-               if (isc->ctrls.awb == ISC_WB_AUTO &&
+               isc_update_awb_ctrls(isc);
+
+               if (vb2_is_streaming(&isc->vb2_vidq)) {
+                       /*
+                        * If we are streaming, we can update profile to
+                        * have the new settings in place.
+                        */
+                       isc_update_profile(isc);
+               } else {
+                       /*
+                        * The auto cluster will activate automatically this
+                        * control. This has to be deactivated when not
+                        * streaming.
+                        */
+                       v4l2_ctrl_activate(isc->do_wb_ctrl, false);
+               }
+
+               /* if we have autowhitebalance on, start histogram procedure */
+               if (ctrls->awb == ISC_WB_AUTO &&
                    vb2_is_streaming(&isc->vb2_vidq) &&
                    ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
                        isc_set_histogram(isc, true);
 
-               break;
-       case V4L2_CID_DO_WHITE_BALANCE:
-               /* if AWB is enabled, do nothing */
-               if (ctrls->awb == ISC_WB_AUTO)
-                       return 0;
+               /*
+                * for one time whitebalance adjustment, check the button,
+                * if it's pressed, perform the one time operation.
+                */
+               if (ctrls->awb == ISC_WB_NONE &&
+                   ctrl->cluster[ISC_CTRL_DO_WB]->is_new &&
+                   !(ctrl->cluster[ISC_CTRL_DO_WB]->flags &
+                   V4L2_CTRL_FLAG_INACTIVE)) {
+                       ctrls->awb = ISC_WB_ONETIME;
+                       isc_set_histogram(isc, true);
+                       v4l2_dbg(1, debug, &isc->v4l2_dev,
+                                "One time white-balance started.\n");
+               }
+               return 0;
+       }
+       return 0;
+}
 
-               ctrls->awb = ISC_WB_ONETIME;
-               isc_set_histogram(isc, true);
-               v4l2_dbg(1, debug, &isc->v4l2_dev,
-                        "One time white-balance started.\n");
+static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct isc_device *isc = container_of(ctrl->handler,
+                                            struct isc_device, ctrls.handler);
+       struct isc_ctrls *ctrls = &isc->ctrls;
+
+       switch (ctrl->id) {
+       /* being a cluster, this id will be called for every control */
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               ctrl->cluster[ISC_CTRL_R_GAIN]->val =
+                                       ctrls->gain[ISC_HIS_CFG_MODE_R];
+               ctrl->cluster[ISC_CTRL_B_GAIN]->val =
+                                       ctrls->gain[ISC_HIS_CFG_MODE_B];
+               ctrl->cluster[ISC_CTRL_GR_GAIN]->val =
+                                       ctrls->gain[ISC_HIS_CFG_MODE_GR];
+               ctrl->cluster[ISC_CTRL_GB_GAIN]->val =
+                                       ctrls->gain[ISC_HIS_CFG_MODE_GB];
+
+               ctrl->cluster[ISC_CTRL_R_OFF]->val =
+                       ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_R]);
+               ctrl->cluster[ISC_CTRL_B_OFF]->val =
+                       ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_B]);
+               ctrl->cluster[ISC_CTRL_GR_OFF]->val =
+                       ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GR]);
+               ctrl->cluster[ISC_CTRL_GB_OFF]->val =
+                       ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GB]);
                break;
-       default:
-               return -EINVAL;
        }
-
        return 0;
 }
 
-static const struct v4l2_ctrl_ops isc_ctrl_ops = {
-       .s_ctrl = isc_s_ctrl,
+static const struct v4l2_ctrl_ops isc_awb_ops = {
+       .s_ctrl = isc_s_awb_ctrl,
+       .g_volatile_ctrl = isc_g_volatile_awb_ctrl,
 };
 
+#define ISC_CTRL_OFF(_name, _id, _name_str) \
+       static const struct v4l2_ctrl_config _name = { \
+               .ops = &isc_awb_ops, \
+               .id = _id, \
+               .name = _name_str, \
+               .type = V4L2_CTRL_TYPE_INTEGER, \
+               .flags = V4L2_CTRL_FLAG_SLIDER, \
+               .min = -4095, \
+               .max = 4095, \
+               .step = 1, \
+               .def = 0, \
+       }
+
+ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset");
+ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset");
+ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset");
+ISC_CTRL_OFF(isc_gb_off_ctrl, ISC_CID_GB_OFFSET, "Green Blue Component Offset");
+
+#define ISC_CTRL_GAIN(_name, _id, _name_str) \
+       static const struct v4l2_ctrl_config _name = { \
+               .ops = &isc_awb_ops, \
+               .id = _id, \
+               .name = _name_str, \
+               .type = V4L2_CTRL_TYPE_INTEGER, \
+               .flags = V4L2_CTRL_FLAG_SLIDER, \
+               .min = 0, \
+               .max = 8191, \
+               .step = 1, \
+               .def = 512, \
+       }
+
+ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain");
+ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain");
+ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain");
+ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain");
+
 static int isc_ctrl_init(struct isc_device *isc)
 {
        const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
@@ -1923,7 +2073,7 @@ static int isc_ctrl_init(struct isc_device *isc)
        ctrls->hist_stat = HIST_INIT;
        isc_reset_awb_ctrls(isc);
 
-       ret = v4l2_ctrl_handler_init(hdl, 5);
+       ret = v4l2_ctrl_handler_init(hdl, 13);
        if (ret < 0)
                return ret;
 
@@ -1933,10 +2083,13 @@ static int isc_ctrl_init(struct isc_device *isc)
        v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
        v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
        v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2);
-       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+       isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
+                                         V4L2_CID_AUTO_WHITE_BALANCE,
+                                         0, 1, 1, 1);
 
        /* do_white_balance is a button, so min,max,step,default are ignored */
-       isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE,
+       isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops,
+                                           V4L2_CID_DO_WHITE_BALANCE,
                                            0, 0, 0, 0);
 
        if (!isc->do_wb_ctrl) {
@@ -1947,6 +2100,21 @@ static int isc_ctrl_init(struct isc_device *isc)
 
        v4l2_ctrl_activate(isc->do_wb_ctrl, false);
 
+       isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL);
+       isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL);
+       isc->gr_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_gain_ctrl, NULL);
+       isc->gb_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_gain_ctrl, NULL);
+       isc->r_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_off_ctrl, NULL);
+       isc->b_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_off_ctrl, NULL);
+       isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL);
+       isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL);
+
+       /*
+        * The cluster is in auto mode with autowhitebalance enabled
+        * and manual mode otherwise.
+        */
+       v4l2_ctrl_auto_cluster(10, &isc->awb_ctrl, 0, true);
+
        v4l2_ctrl_handler_setup(hdl);
 
        return 0;
@@ -2143,7 +2311,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
        vdev->device_caps       = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
        video_set_drvdata(vdev, isc);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                v4l2_err(&isc->v4l2_dev,
                         "video_register_device failed: %d\n", ret);
index bfaed2f..fc56a74 100644 (file)
@@ -213,7 +213,6 @@ struct isc_device {
        struct fmt_config       try_config;
 
        struct isc_ctrls        ctrls;
-       struct v4l2_ctrl        *do_wb_ctrl;
        struct work_struct      awb_work;
 
        struct mutex            lock; /* serialize access to file operations */
@@ -223,6 +222,28 @@ struct isc_device {
 
        struct isc_subdev_entity        *current_subdev;
        struct list_head                subdev_entities;
+
+       struct {
+#define ISC_CTRL_DO_WB 1
+#define ISC_CTRL_R_GAIN 2
+#define ISC_CTRL_B_GAIN 3
+#define ISC_CTRL_GR_GAIN 4
+#define ISC_CTRL_GB_GAIN 5
+#define ISC_CTRL_R_OFF 6
+#define ISC_CTRL_B_OFF 7
+#define ISC_CTRL_GR_OFF 8
+#define ISC_CTRL_GB_OFF 9
+               struct v4l2_ctrl        *awb_ctrl;
+               struct v4l2_ctrl        *do_wb_ctrl;
+               struct v4l2_ctrl        *r_gain_ctrl;
+               struct v4l2_ctrl        *b_gain_ctrl;
+               struct v4l2_ctrl        *gr_gain_ctrl;
+               struct v4l2_ctrl        *gb_gain_ctrl;
+               struct v4l2_ctrl        *r_off_ctrl;
+               struct v4l2_ctrl        *b_off_ctrl;
+               struct v4l2_ctrl        *gr_off_ctrl;
+               struct v4l2_ctrl        *gb_off_ctrl;
+       };
 };
 
 #define GAMMA_MAX      2
index 963dfd6..d74aa73 100644 (file)
@@ -1094,7 +1094,7 @@ static int isi_graph_notify_complete(struct v4l2_async_notifier *notifier)
                return ret;
        }
 
-       ret = video_register_device(isi->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(isi->vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(isi->dev, "Failed to register video device\n");
                return ret;
index acff10a..d0d093d 100644 (file)
@@ -2726,7 +2726,7 @@ static int coda_register_device(struct coda_dev *dev, int i)
        v4l2_disable_ioctl(vfd, VIDIOC_G_CROP);
        v4l2_disable_ioctl(vfd, VIDIOC_S_CROP);
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (!ret)
                v4l2_info(&dev->v4l2_dev, "%s registered as %s\n",
                          type == CODA_INST_ENCODER ? "encoder" : "decoder",
index b49378b..c98edb6 100644 (file)
@@ -29,7 +29,7 @@
 #include "ccdc_hw_device.h"
 
 /* Defaults for module configuration parameters */
-static struct isif_config_params_raw isif_config_defaults = {
+static const struct isif_config_params_raw isif_config_defaults = {
        .linearize = {
                .en = 0,
                .corr_shft = ISIF_NO_SHIFT,
index ae41995..38d3088 100644 (file)
@@ -1339,7 +1339,7 @@ static int register_device(struct vpbe_layer *vpbe_display_layer,
 
        vpbe_display_layer->video_dev.queue = &vpbe_display_layer->buffer_queue;
        err = video_register_device(&vpbe_display_layer->video_dev,
-                                   VFL_TYPE_GRABBER,
+                                   VFL_TYPE_VIDEO,
                                    -1);
        if (err)
                return -ENODEV;
index 9b1d964..f9f7dd1 100644 (file)
@@ -880,7 +880,7 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void  *priv,
        /* Fill in the information about format */
        pix_fmt = vpfe_lookup_pix_format(pix);
        if (pix_fmt) {
-               fmt->pixelformat = fmt->pixelformat;
+               fmt->pixelformat = pix_fmt->pixelformat;
                return 0;
        }
        return -EINVAL;
@@ -1780,7 +1780,7 @@ static int vpfe_probe(struct platform_device *pdev)
                "video_dev=%p\n", &vpfe_dev->video_dev);
        vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ret = video_register_device(&vpfe_dev->video_dev,
-                                   VFL_TYPE_GRABBER, -1);
+                                   VFL_TYPE_VIDEO, -1);
 
        if (ret) {
                v4l2_err(pdev->dev.driver,
index 71f4fe8..d9ec439 100644 (file)
@@ -1466,7 +1466,7 @@ static int vpif_probe_complete(void)
                vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
                video_set_drvdata(&ch->video_dev, ch);
                err = video_register_device(vdev,
-                                           VFL_TYPE_GRABBER, (j ? 1 : 0));
+                                           VFL_TYPE_VIDEO, (j ? 1 : 0));
                if (err)
                        goto probe_out;
        }
index abbdbac..ead14c4 100644 (file)
@@ -1214,7 +1214,7 @@ static int vpif_probe_complete(void)
                vdev->lock = &common->lock;
                vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
                video_set_drvdata(&ch->video_dev, ch);
-               err = video_register_device(vdev, VFL_TYPE_GRABBER,
+               err = video_register_device(vdev, VFL_TYPE_VIDEO,
                                            (j ? 3 : 2));
                if (err < 0)
                        goto probe_out;
index 35a1d0d..e2c1626 100644 (file)
@@ -771,7 +771,7 @@ int gsc_register_m2m_device(struct gsc_dev *gsc)
                return PTR_ERR(gsc->m2m.m2m_dev);
        }
 
-       ret = video_register_device(&gsc->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&gsc->vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(&pdev->dev,
                         "%s(): failed to register video device\n", __func__);
index 989cb34..be4effc 100644 (file)
@@ -13,7 +13,7 @@ config VIDEO_SAMSUNG_EXYNOS4_IS
 if VIDEO_SAMSUNG_EXYNOS4_IS
 
 config VIDEO_EXYNOS4_IS_COMMON
-       tristate
+       tristate
 
 config VIDEO_S5P_FIMC
        tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
index 121d609..705f182 100644 (file)
@@ -1808,7 +1808,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
        if (ret)
                goto err_me_cleanup;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret)
                goto err_ctrl_free;
 
index d2cbcdc..15f443f 100644 (file)
@@ -619,7 +619,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp,
 
        video_set_drvdata(vdev, isp);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                media_entity_cleanup(&vdev->entity);
                return ret;
index e87c6a0..394e081 100644 (file)
@@ -1297,7 +1297,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
        video_set_drvdata(vfd, fimc);
        fimc->ve.pipe = v4l2_get_subdev_hostdata(sd);
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                media_entity_cleanup(&vfd->entity);
                fimc->ve.pipe = NULL;
@@ -1614,6 +1614,9 @@ static int fimc_lite_remove(struct platform_device *pdev)
        struct fimc_lite *fimc = platform_get_drvdata(pdev);
        struct device *dev = &pdev->dev;
 
+       if (!pm_runtime_enabled(dev))
+               clk_disable_unprepare(fimc->clock);
+
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
        fimc_lite_unregister_capture_subdev(fimc);
index c70c2cb..4acb179 100644 (file)
@@ -746,7 +746,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc,
        if (ret)
                goto err_me;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret)
                goto err_vd;
 
index 81a8fae..84633a3 100644 (file)
@@ -1486,7 +1486,7 @@ static int viu_of_probe(struct platform_device *op)
 
        mutex_lock(&viu_dev->lock);
 
-       ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(viu_dev->vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                video_device_release(viu_dev->vdev);
                goto err_unlock;
index 38d9423..08d76eb 100644 (file)
@@ -1709,7 +1709,7 @@ static int pxp_probe(struct platform_device *pdev)
                goto err_v4l2;
        }
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
                goto err_m2m;
index 9ad24c8..1f89e71 100644 (file)
@@ -953,7 +953,7 @@ static int deinterlace_probe(struct platform_device *pdev)
        vfd->lock = &pcdev->dev_mutex;
        vfd->v4l2_dev = &pcdev->v4l2_dev;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
                goto unreg_dev;
index 803baf9..09775b6 100644 (file)
@@ -1802,7 +1802,7 @@ static int mccic_notify_bound(struct v4l2_async_notifier *notifier,
        cam->vdev.lock = &cam->s_mutex;
        cam->vdev.queue = &cam->vb_queue;
        video_set_drvdata(&cam->vdev, cam);
-       ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                cam->sensor = NULL;
                goto out;
index ee802fc..f82a81a 100644 (file)
@@ -1150,7 +1150,7 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
        jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
                                      V4L2_CAP_VIDEO_M2M_MPLANE;
 
-       ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, 3);
+       ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_VIDEO, 3);
        if (ret) {
                v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
                goto err_dec_vdev_register;
index 9afe816..1499168 100644 (file)
@@ -110,6 +110,12 @@ int mtk_mdp_comp_init(struct device *dev, struct device_node *node,
 
        for (i = 0; i < ARRAY_SIZE(comp->clk); i++) {
                comp->clk[i] = of_clk_get(node, i);
+               if (IS_ERR(comp->clk[i])) {
+                       if (PTR_ERR(comp->clk[i]) != -EPROBE_DEFER)
+                               dev_err(dev, "Failed to get clock\n");
+
+                       return PTR_ERR(comp->clk[i]);
+               }
 
                /* Only RDMA needs two clocks */
                if (comp->type != MTK_MDP_RDMA)
index 7c9e2d6..821f2cf 100644 (file)
@@ -1229,7 +1229,7 @@ int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp)
                goto err_m2m_init;
        }
 
-       ret = video_register_device(mdp->vdev, VFL_TYPE_GRABBER, 2);
+       ret = video_register_device(mdp->vdev, VFL_TYPE_VIDEO, 2);
        if (ret) {
                dev_err(dev, "failed to register video device\n");
                goto err_vdev_register;
index 6720d11..b065ccd 100644 (file)
@@ -15,7 +15,7 @@ static inline struct mtk_mdp_ctx *vpu_to_ctx(struct mtk_mdp_vpu *vpu)
        return container_of(vpu, struct mtk_mdp_ctx, vpu);
 }
 
-static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg)
+static void mtk_mdp_vpu_handle_init_ack(const struct mdp_ipi_comm_ack *msg)
 {
        struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)
                                        (unsigned long)msg->ap_inst;
@@ -26,10 +26,11 @@ static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg)
        vpu->inst_addr = msg->vpu_inst_addr;
 }
 
-static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, void *priv)
+static void mtk_mdp_vpu_ipi_handler(const void *data, unsigned int len,
+                                   void *priv)
 {
-       unsigned int msg_id = *(unsigned int *)data;
-       struct mdp_ipi_comm_ack *msg = (struct mdp_ipi_comm_ack *)data;
+       const struct mdp_ipi_comm_ack *msg = data;
+       unsigned int msg_id = msg->msg_id;
        struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)
                                        (unsigned long)msg->ap_inst;
        struct mtk_mdp_ctx *ctx;
index 100ae8c..97a1b66 100644 (file)
@@ -331,7 +331,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
                goto err_event_workq;
        }
 
-       ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, 0);
        if (ret) {
                mtk_v4l2_err("Failed to register video device");
                goto err_dec_reg;
index 1d82aa2..4d31f1e 100644 (file)
@@ -356,7 +356,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
                goto err_event_workq;
        }
 
-       ret = video_register_device(vfd_enc, VFL_TYPE_GRABBER, 1);
+       ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, 1);
        if (ret) {
                mtk_v4l2_err("Failed to register video device");
                goto err_enc_reg;
index 24c1f0b..257a5b5 100644 (file)
@@ -110,7 +110,11 @@ struct vp9_sf_ref_fb {
  * @buf_len_sz_c : size used to store cbcr plane ufo info (AP-R, VPU-W)
 
  * @profile : profile sparsed from vpu (AP-R, VPU-W)
- * @show_frame : display this frame or not (AP-R, VPU-W)
+ * @show_frame : [BIT(0)] display this frame or not (AP-R, VPU-W)
+ *     [BIT(1)] reset segment data or not (AP-R, VPU-W)
+ *     [BIT(2)] trig decoder hardware or not (AP-R, VPU-W)
+ *     [BIT(3)] ask VPU to set bits(0~4) accordingly (AP-W, VPU-R)
+ *     [BIT(4)] do not reset segment data before every frame (AP-R, VPU-W)
  * @show_existing_frame : inform this frame is show existing frame
  *     (AP-R, VPU-W)
  * @frm_to_show_idx : index to show frame (AP-R, VPU-W)
@@ -494,12 +498,12 @@ static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst)
                                        frm_to_show->fb->base_y.size);
                }
                if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) {
-                       if (vsi->show_frame)
+                       if (vsi->show_frame & BIT(0))
                                vp9_add_to_fb_disp_list(inst, inst->cur_fb);
                }
        } else {
                if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) {
-                       if (vsi->show_frame)
+                       if (vsi->show_frame & BIT(0))
                                vp9_add_to_fb_disp_list(inst, frm_to_show->fb);
                }
        }
@@ -800,6 +804,9 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx)
        }
 
        inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi;
+
+       inst->vsi->show_frame |= BIT(3);
+
        init_all_fb_lists(inst);
 
        ctx->drv_handle = inst;
@@ -870,13 +877,27 @@ static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
                                        vsi->sf_frm_sz[idx]);
                        }
                }
-               memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size);
+
+               if (!(vsi->show_frame & BIT(4)))
+                       memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size);
+
                ret = vpu_dec_start(&inst->vpu, data, 3);
                if (ret) {
                        mtk_vcodec_err(inst, "vpu_dec_start failed");
                        goto DECODE_ERROR;
                }
 
+               if (vsi->show_frame & BIT(1)) {
+                       memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size);
+
+                       if (vsi->show_frame & BIT(2)) {
+                               if (vpu_dec_start(&inst->vpu, NULL, 0)) {
+                                       mtk_vcodec_err(inst, "vpu trig decoder failed");
+                                       goto DECODE_ERROR;
+                               }
+                       }
+               }
+
                ret = validate_vsi_array_indexes(inst, vsi);
                if (ret) {
                        mtk_vcodec_err(inst, "Invalid values from VPU.");
index 70abfd4..948a12f 100644 (file)
@@ -9,7 +9,7 @@
 #include "vdec_ipi_msg.h"
 #include "vdec_vpu_if.h"
 
-static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg)
+static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg)
 {
        struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
                                        (unsigned long)msg->ap_inst_addr;
@@ -34,9 +34,9 @@ static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg)
  * This function runs in interrupt context and it means there's an IPI MSG
  * from VPU.
  */
-static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
+static void vpu_dec_ipi_handler(const void *data, unsigned int len, void *priv)
 {
-       struct vdec_vpu_ipi_ack *msg = data;
+       const struct vdec_vpu_ipi_ack *msg = data;
        struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
                                        (unsigned long)msg->ap_inst_addr;
 
index 3e931b0..9540709 100644 (file)
@@ -8,26 +8,26 @@
 #include "venc_ipi_msg.h"
 #include "venc_vpu_if.h"
 
-static void handle_enc_init_msg(struct venc_vpu_inst *vpu, void *data)
+static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data)
 {
-       struct venc_vpu_ipi_msg_init *msg = data;
+       const struct venc_vpu_ipi_msg_init *msg = data;
 
        vpu->inst_addr = msg->vpu_inst_addr;
        vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr);
 }
 
-static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, void *data)
+static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data)
 {
-       struct venc_vpu_ipi_msg_enc *msg = data;
+       const struct venc_vpu_ipi_msg_enc *msg = data;
 
        vpu->state = msg->state;
        vpu->bs_size = msg->bs_size;
        vpu->is_key_frm = msg->is_key_frm;
 }
 
-static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)
+static void vpu_enc_ipi_handler(const void *data, unsigned int len, void *priv)
 {
-       struct venc_vpu_ipi_msg_common *msg = data;
+       const struct venc_vpu_ipi_msg_common *msg = data;
        struct venc_vpu_inst *vpu =
                (struct venc_vpu_inst *)(unsigned long)msg->venc_inst;
 
index a768707..d30c089 100644 (file)
@@ -46,6 +46,8 @@
 /* binary firmware name */
 #define VPU_P_FW               "vpu_p.bin"
 #define VPU_D_FW               "vpu_d.bin"
+#define VPU_P_FW_NEW           "mediatek/mt8173/vpu_p.bin"
+#define VPU_D_FW_NEW           "mediatek/mt8173/vpu_d.bin"
 
 #define VPU_RESET              0x0
 #define VPU_TCM_CFG            0x0008
@@ -203,8 +205,8 @@ struct mtk_vpu {
        struct vpu_run run;
        struct vpu_wdt wdt;
        struct vpu_ipi_desc ipi_desc[IPI_MAX];
-       struct share_obj *recv_buf;
-       struct share_obj *send_buf;
+       struct share_obj __iomem *recv_buf;
+       struct share_obj __iomem *send_buf;
        struct device *dev;
        struct clk *clk;
        bool fw_loaded;
@@ -292,7 +294,7 @@ int vpu_ipi_send(struct platform_device *pdev,
                 unsigned int len)
 {
        struct mtk_vpu *vpu = platform_get_drvdata(pdev);
-       struct share_obj *send_obj = vpu->send_buf;
+       struct share_obj __iomem *send_obj = vpu->send_buf;
        unsigned long timeout;
        int ret = 0;
 
@@ -325,9 +327,9 @@ int vpu_ipi_send(struct platform_device *pdev,
                }
        } while (vpu_cfg_readl(vpu, HOST_TO_VPU));
 
-       memcpy((void *)send_obj->share_buf, buf, len);
-       send_obj->len = len;
-       send_obj->id = id;
+       memcpy_toio(send_obj->share_buf, buf, len);
+       writel(len, &send_obj->len);
+       writel(id, &send_obj->id);
 
        vpu->ipi_id_ack[id] = false;
        /* send the command to VPU */
@@ -477,16 +479,24 @@ static int load_requested_vpu(struct mtk_vpu *vpu,
        size_t tcm_size = fw_type ? VPU_DTCM_SIZE : VPU_PTCM_SIZE;
        size_t fw_size = fw_type ? VPU_D_FW_SIZE : VPU_P_FW_SIZE;
        char *fw_name = fw_type ? VPU_D_FW : VPU_P_FW;
+       char *fw_new_name = fw_type ? VPU_D_FW_NEW : VPU_P_FW_NEW;
        const struct firmware *vpu_fw;
        size_t dl_size = 0;
        size_t extra_fw_size = 0;
        void *dest;
        int ret;
 
-       ret = request_firmware(&vpu_fw, fw_name, vpu->dev);
+       ret = request_firmware(&vpu_fw, fw_new_name, vpu->dev);
        if (ret < 0) {
-               dev_err(vpu->dev, "Failed to load %s, %d\n", fw_name, ret);
-               return ret;
+               dev_info(vpu->dev, "Failed to load %s, %d, retry\n",
+                        fw_new_name, ret);
+
+               ret = request_firmware(&vpu_fw, fw_name, vpu->dev);
+               if (ret < 0) {
+                       dev_err(vpu->dev, "Failed to load %s, %d\n", fw_name,
+                               ret);
+                       return ret;
+               }
        }
        dl_size = vpu_fw->size;
        if (dl_size > fw_size) {
@@ -600,10 +610,10 @@ OUT_LOAD_FW:
 }
 EXPORT_SYMBOL_GPL(vpu_load_firmware);
 
-static void vpu_init_ipi_handler(void *data, unsigned int len, void *priv)
+static void vpu_init_ipi_handler(const void *data, unsigned int len, void *priv)
 {
-       struct mtk_vpu *vpu = (struct mtk_vpu *)priv;
-       struct vpu_run *run = (struct vpu_run *)data;
+       struct mtk_vpu *vpu = priv;
+       const struct vpu_run *run = data;
 
        vpu->run.signaled = run->signaled;
        strscpy(vpu->run.fw_ver, run->fw_ver, sizeof(vpu->run.fw_ver));
@@ -700,19 +710,21 @@ static int vpu_alloc_ext_mem(struct mtk_vpu *vpu, u32 fw_type)
 
 static void vpu_ipi_handler(struct mtk_vpu *vpu)
 {
-       struct share_obj *rcv_obj = vpu->recv_buf;
+       struct share_obj __iomem *rcv_obj = vpu->recv_buf;
        struct vpu_ipi_desc *ipi_desc = vpu->ipi_desc;
-
-       if (rcv_obj->id < IPI_MAX && ipi_desc[rcv_obj->id].handler) {
-               ipi_desc[rcv_obj->id].handler(rcv_obj->share_buf,
-                                             rcv_obj->len,
-                                             ipi_desc[rcv_obj->id].priv);
-               if (rcv_obj->id > IPI_VPU_INIT) {
-                       vpu->ipi_id_ack[rcv_obj->id] = true;
+       unsigned char data[SHARE_BUF_SIZE];
+       s32 id = readl(&rcv_obj->id);
+
+       memcpy_fromio(data, rcv_obj->share_buf, sizeof(data));
+       if (id < IPI_MAX && ipi_desc[id].handler) {
+               ipi_desc[id].handler(data, readl(&rcv_obj->len),
+                                    ipi_desc[id].priv);
+               if (id > IPI_VPU_INIT) {
+                       vpu->ipi_id_ack[id] = true;
                        wake_up(&vpu->ack_wq);
                }
        } else {
-               dev_err(vpu->dev, "No such ipi id = %d\n", rcv_obj->id);
+               dev_err(vpu->dev, "No such ipi id = %d\n", id);
        }
 }
 
@@ -722,11 +734,10 @@ static int vpu_ipi_init(struct mtk_vpu *vpu)
        vpu_cfg_writel(vpu, 0x0, VPU_TO_HOST);
 
        /* shared buffer initialization */
-       vpu->recv_buf = (__force struct share_obj *)(vpu->reg.tcm +
-                                                    VPU_DTCM_OFFSET);
+       vpu->recv_buf = vpu->reg.tcm + VPU_DTCM_OFFSET;
        vpu->send_buf = vpu->recv_buf + 1;
-       memset(vpu->recv_buf, 0, sizeof(struct share_obj));
-       memset(vpu->send_buf, 0, sizeof(struct share_obj));
+       memset_io(vpu->recv_buf, 0, sizeof(struct share_obj));
+       memset_io(vpu->send_buf, 0, sizeof(struct share_obj));
 
        return 0;
 }
index d4453b4..ee7c552 100644 (file)
@@ -15,7 +15,7 @@
  * VPU interfaces with other blocks by share memory and interrupt.
  **/
 
-typedef void (*ipi_handler_t) (void *data,
+typedef void (*ipi_handler_t) (const void *data,
                               unsigned int len,
                               void *priv);
 
index 27779b7..df78df5 100644 (file)
@@ -866,7 +866,7 @@ static int emmaprp_probe(struct platform_device *pdev)
                goto rel_vdev;
        }
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
                goto rel_m2m;
index 513b99b..21193f0 100644 (file)
@@ -1500,7 +1500,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
                /* Register the Video device with V4L2
                 */
                vfd = vout->vfd;
-               if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) {
+               if (video_register_device(vfd, VFL_TYPE_VIDEO, -1) < 0) {
                        dev_err(&pdev->dev,
                                ": Could not register Video for Linux device\n");
                        vfd->minor = -1;
index 471ae7c..0fbb2aa 100644 (file)
@@ -1312,6 +1312,10 @@ static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)
 {
        struct isp_device *isp = to_isp_device(ccdc);
 
+       /* Avoid restarting the CCDC when streaming is stopping. */
+       if (enable && ccdc->stopping & CCDC_STOP_REQUEST)
+               return;
+
        isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
                        ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
 
index ee183c3..6f769c5 100644 (file)
@@ -1311,7 +1311,7 @@ static int isp_video_open(struct file *file)
                goto done;
        }
 
-       ret = v4l2_pipeline_pm_use(&video->video.entity, 1);
+       ret = v4l2_pipeline_pm_get(&video->video.entity);
        if (ret < 0) {
                omap3isp_put(video->isp);
                goto done;
@@ -1363,7 +1363,7 @@ static int isp_video_release(struct file *file)
        vb2_queue_release(&handle->queue);
        mutex_unlock(&video->queue_lock);
 
-       v4l2_pipeline_pm_use(&video->video.entity, 0);
+       v4l2_pipeline_pm_put(&video->video.entity);
 
        /* Release the file handle. */
        v4l2_fh_del(vfh);
@@ -1453,7 +1453,7 @@ int omap3isp_video_init(struct isp_video *video, const char *name)
        video->video.fops = &isp_video_fops;
        snprintf(video->video.name, sizeof(video->video.name),
                 "OMAP3 ISP %s %s", name, direction);
-       video->video.vfl_type = VFL_TYPE_GRABBER;
+       video->video.vfl_type = VFL_TYPE_VIDEO;
        video->video.release = video_device_release_empty;
        video->video.ioctl_ops = &isp_video_ioctl_ops;
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -1484,7 +1484,7 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev)
 
        video->video.v4l2_dev = vdev;
 
-       ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1);
        if (ret < 0)
                dev_err(video->isp->dev,
                        "%s: could not register video device (%d)\n",
index 43ae645..70c85a2 100644 (file)
@@ -2191,7 +2191,7 @@ static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier,
        if (err)
                goto out_sensor_poweroff;
 
-       err = video_register_device(&pcdev->vdev, VFL_TYPE_GRABBER, -1);
+       err = video_register_device(&pcdev->vdev, VFL_TYPE_VIDEO, -1);
        if (err) {
                v4l2_err(v4l2_dev, "register video device failed: %d\n", err);
                pcdev->sensor = NULL;
@@ -2440,23 +2440,23 @@ static int pxa_camera_probe(struct platform_device *pdev)
        pcdev->base = base;
 
        /* request dma */
-       pcdev->dma_chans[0] = dma_request_slave_channel(&pdev->dev, "CI_Y");
-       if (!pcdev->dma_chans[0]) {
+       pcdev->dma_chans[0] = dma_request_chan(&pdev->dev, "CI_Y");
+       if (IS_ERR(pcdev->dma_chans[0])) {
                dev_err(&pdev->dev, "Can't request DMA for Y\n");
-               return -ENODEV;
+               return PTR_ERR(pcdev->dma_chans[0]);
        }
 
-       pcdev->dma_chans[1] = dma_request_slave_channel(&pdev->dev, "CI_U");
-       if (!pcdev->dma_chans[1]) {
-               dev_err(&pdev->dev, "Can't request DMA for Y\n");
-               err = -ENODEV;
+       pcdev->dma_chans[1] = dma_request_chan(&pdev->dev, "CI_U");
+       if (IS_ERR(pcdev->dma_chans[1])) {
+               dev_err(&pdev->dev, "Can't request DMA for U\n");
+               err = PTR_ERR(pcdev->dma_chans[1]);
                goto exit_free_dma_y;
        }
 
-       pcdev->dma_chans[2] = dma_request_slave_channel(&pdev->dev, "CI_V");
-       if (!pcdev->dma_chans[2]) {
+       pcdev->dma_chans[2] = dma_request_chan(&pdev->dev, "CI_V");
+       if (IS_ERR(pcdev->dma_chans[2])) {
                dev_err(&pdev->dev, "Can't request DMA for V\n");
-               err = -ENODEV;
+               err = PTR_ERR(pcdev->dma_chans[2]);
                goto exit_free_dma_u;
        }
 
index 1d50dfb..cdbd6db 100644 (file)
@@ -745,7 +745,7 @@ static int video_open(struct file *file)
 
        file->private_data = vfh;
 
-       ret = v4l2_pipeline_pm_use(&vdev->entity, 1);
+       ret = v4l2_pipeline_pm_get(&vdev->entity);
        if (ret < 0) {
                dev_err(video->camss->dev, "Failed to power up pipeline: %d\n",
                        ret);
@@ -771,7 +771,7 @@ static int video_release(struct file *file)
 
        vb2_fop_release(file);
 
-       v4l2_pipeline_pm_use(&vdev->entity, 0);
+       v4l2_pipeline_pm_put(&vdev->entity);
 
        file->private_data = NULL;
 
@@ -921,7 +921,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
        vdev->lock = &video->lock;
        strscpy(vdev->name, name, sizeof(vdev->name));
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                dev_err(v4l2_dev->dev, "Failed to register video device: %d\n",
                        ret);
index b44b11b..64af0bc 100644 (file)
@@ -3,7 +3,7 @@
 
 venus-core-objs += core.o helpers.o firmware.o \
                   hfi_venus.o hfi_msgs.o hfi_cmds.o hfi.o \
-                  hfi_parser.o
+                  hfi_parser.o pm_helpers.o
 
 venus-dec-objs += vdec.o vdec_ctrls.o
 venus-enc-objs += venc.o venc_ctrls.o
index 07312a2..194b10b 100644 (file)
@@ -3,7 +3,6 @@
  * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
  * Copyright (C) 2017 Linaro Ltd.
  */
-#include <linux/clk.h>
 #include <linux/init.h>
 #include <linux/interconnect.h>
 #include <linux/ioctl.h>
@@ -19,9 +18,8 @@
 #include <media/v4l2-ioctl.h>
 
 #include "core.h"
-#include "vdec.h"
-#include "venc.h"
 #include "firmware.h"
+#include "pm_helpers.h"
 
 static void venus_event_notify(struct venus_core *core, u32 event)
 {
@@ -100,50 +98,6 @@ static void venus_sys_error_handler(struct work_struct *work)
        mutex_unlock(&core->lock);
 }
 
-static int venus_clks_get(struct venus_core *core)
-{
-       const struct venus_resources *res = core->res;
-       struct device *dev = core->dev;
-       unsigned int i;
-
-       for (i = 0; i < res->clks_num; i++) {
-               core->clks[i] = devm_clk_get(dev, res->clks[i]);
-               if (IS_ERR(core->clks[i]))
-                       return PTR_ERR(core->clks[i]);
-       }
-
-       return 0;
-}
-
-static int venus_clks_enable(struct venus_core *core)
-{
-       const struct venus_resources *res = core->res;
-       unsigned int i;
-       int ret;
-
-       for (i = 0; i < res->clks_num; i++) {
-               ret = clk_prepare_enable(core->clks[i]);
-               if (ret)
-                       goto err;
-       }
-
-       return 0;
-err:
-       while (i--)
-               clk_disable_unprepare(core->clks[i]);
-
-       return ret;
-}
-
-static void venus_clks_disable(struct venus_core *core)
-{
-       const struct venus_resources *res = core->res;
-       unsigned int i = res->clks_num;
-
-       while (i--)
-               clk_disable_unprepare(core->clks[i]);
-}
-
 static u32 to_v4l2_codec_type(u32 codec)
 {
        switch (codec) {
@@ -256,9 +210,15 @@ static int venus_probe(struct platform_device *pdev)
        if (!core->res)
                return -ENODEV;
 
-       ret = venus_clks_get(core);
-       if (ret)
-               return ret;
+       core->pm_ops = venus_pm_get(core->res->hfi_version);
+       if (!core->pm_ops)
+               return -ENODEV;
+
+       if (core->pm_ops->core_get) {
+               ret = core->pm_ops->core_get(dev);
+               if (ret)
+                       return ret;
+       }
 
        ret = dma_set_mask_and_coherent(dev, core->res->dma_mask);
        if (ret)
@@ -350,6 +310,7 @@ err_runtime_disable:
 static int venus_remove(struct platform_device *pdev)
 {
        struct venus_core *core = platform_get_drvdata(pdev);
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
        struct device *dev = core->dev;
        int ret;
 
@@ -368,6 +329,9 @@ static int venus_remove(struct platform_device *pdev)
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
 
+       if (pm_ops->core_put)
+               pm_ops->core_put(dev);
+
        icc_put(core->video_path);
        icc_put(core->cpucfg_path);
 
@@ -379,11 +343,15 @@ static int venus_remove(struct platform_device *pdev)
 static __maybe_unused int venus_runtime_suspend(struct device *dev)
 {
        struct venus_core *core = dev_get_drvdata(dev);
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
        int ret;
 
        ret = hfi_core_suspend(core);
+       if (ret)
+               return ret;
 
-       venus_clks_disable(core);
+       if (pm_ops->core_power)
+               ret = pm_ops->core_power(dev, POWER_OFF);
 
        return ret;
 }
@@ -391,21 +359,16 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev)
 static __maybe_unused int venus_runtime_resume(struct device *dev)
 {
        struct venus_core *core = dev_get_drvdata(dev);
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
        int ret;
 
-       ret = venus_clks_enable(core);
-       if (ret)
-               return ret;
-
-       ret = hfi_core_resume(core, false);
-       if (ret)
-               goto err_clks_disable;
-
-       return 0;
+       if (pm_ops->core_power) {
+               ret = pm_ops->core_power(dev, POWER_ON);
+               if (ret)
+                       return ret;
+       }
 
-err_clks_disable:
-       venus_clks_disable(core);
-       return ret;
+       return hfi_core_resume(core, false);
 }
 
 static const struct dev_pm_ops venus_pm_ops = {
@@ -463,6 +426,9 @@ static const struct venus_resources msm8996_res = {
        .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset),
        .clks = {"core", "iface", "bus", "mbus" },
        .clks_num = 4,
+       .vcodec0_clks = { "core" },
+       .vcodec1_clks = { "core" },
+       .vcodec_clks_num = 1,
        .max_load = 2563200,
        .hfi_version = HFI_VERSION_3XX,
        .vmem_id = VIDC_RESOURCE_NONE,
@@ -517,6 +483,35 @@ static const struct venus_resources sdm845_res = {
        .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data),
        .clks = {"core", "iface", "bus" },
        .clks_num = 3,
+       .vcodec0_clks = { "core", "bus" },
+       .vcodec1_clks = { "core", "bus" },
+       .vcodec_clks_num = 2,
+       .max_load = 3110400,    /* 4096x2160@90 */
+       .hfi_version = HFI_VERSION_4XX,
+       .vmem_id = VIDC_RESOURCE_NONE,
+       .vmem_size = 0,
+       .vmem_addr = 0,
+       .dma_mask = 0xe0000000 - 1,
+       .fwname = "qcom/venus-5.2/venus.mdt",
+};
+
+static const struct venus_resources sdm845_res_v2 = {
+       .freq_tbl = sdm845_freq_table,
+       .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table),
+       .bw_tbl_enc = sdm845_bw_table_enc,
+       .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc),
+       .bw_tbl_dec = sdm845_bw_table_dec,
+       .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec),
+       .codec_freq_data = sdm845_codec_freq_data,
+       .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data),
+       .clks = {"core", "iface", "bus" },
+       .clks_num = 3,
+       .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" },
+       .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" },
+       .vcodec_clks_num = 2,
+       .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" },
+       .vcodec_pmdomains_num = 3,
+       .vcodec_num = 2,
        .max_load = 3110400,    /* 4096x2160@90 */
        .hfi_version = HFI_VERSION_4XX,
        .vmem_id = VIDC_RESOURCE_NONE,
@@ -526,10 +521,56 @@ static const struct venus_resources sdm845_res = {
        .fwname = "qcom/venus-5.2/venus.mdt",
 };
 
+static const struct freq_tbl sc7180_freq_table[] = {
+       {  0, 500000000 },
+       {  0, 434000000 },
+       {  0, 340000000 },
+       {  0, 270000000 },
+       {  0, 150000000 },
+};
+
+static const struct bw_tbl sc7180_bw_table_enc[] = {
+       {  972000,  750000, 0, 0, 0 },  /* 3840x2160@30 */
+       {  489600,  451000, 0, 0, 0 },  /* 1920x1080@60 */
+       {  244800,  234000, 0, 0, 0 },  /* 1920x1080@30 */
+};
+
+static const struct bw_tbl sc7180_bw_table_dec[] = {
+       { 1036800, 1386000, 0, 1875000, 0 },    /* 4096x2160@30 */
+       {  489600,  865000, 0, 1146000, 0 },    /* 1920x1080@60 */
+       {  244800,  530000, 0,  583000, 0 },    /* 1920x1080@30 */
+};
+
+static const struct venus_resources sc7180_res = {
+       .freq_tbl = sc7180_freq_table,
+       .freq_tbl_size = ARRAY_SIZE(sc7180_freq_table),
+       .bw_tbl_enc = sc7180_bw_table_enc,
+       .bw_tbl_enc_size = ARRAY_SIZE(sc7180_bw_table_enc),
+       .bw_tbl_dec = sc7180_bw_table_dec,
+       .bw_tbl_dec_size = ARRAY_SIZE(sc7180_bw_table_dec),
+       .codec_freq_data = sdm845_codec_freq_data,
+       .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data),
+       .clks = {"core", "iface", "bus" },
+       .clks_num = 3,
+       .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" },
+       .vcodec_clks_num = 2,
+       .vcodec_pmdomains = { "venus", "vcodec0" },
+       .vcodec_pmdomains_num = 2,
+       .vcodec_num = 1,
+       .hfi_version = HFI_VERSION_4XX,
+       .vmem_id = VIDC_RESOURCE_NONE,
+       .vmem_size = 0,
+       .vmem_addr = 0,
+       .dma_mask = 0xe0000000 - 1,
+       .fwname = "qcom/venus-5.4/venus.mdt",
+};
+
 static const struct of_device_id venus_dt_match[] = {
        { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, },
        { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, },
        { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, },
+       { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, },
+       { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, },
        { }
 };
 MODULE_DEVICE_TABLE(of, venus_dt_match);
index 11585fb..bd3ac6a 100644 (file)
@@ -14,7 +14,9 @@
 
 #include "hfi.h"
 
-#define VIDC_CLKS_NUM_MAX      4
+#define VIDC_CLKS_NUM_MAX              4
+#define VIDC_VCODEC_CLKS_NUM_MAX       2
+#define VIDC_PMDOMAINS_NUM_MAX         3
 
 struct freq_tbl {
        unsigned int load;
@@ -55,6 +57,12 @@ struct venus_resources {
        unsigned int codec_freq_data_size;
        const char * const clks[VIDC_CLKS_NUM_MAX];
        unsigned int clks_num;
+       const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX];
+       const char * const vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
+       unsigned int vcodec_clks_num;
+       const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX];
+       unsigned int vcodec_pmdomains_num;
+       unsigned int vcodec_num;
        enum hfi_version hfi_version;
        u32 max_load;
        unsigned int vmem_id;
@@ -100,10 +108,10 @@ struct venus_caps {
  * @base:      IO memory base address
  * @irq:               Venus irq
  * @clks:      an array of struct clk pointers
- * @core0_clk: a struct clk pointer for core0
- * @core1_clk: a struct clk pointer for core1
- * @core0_bus_clk: a struct clk pointer for core0 bus clock
- * @core1_bus_clk: a struct clk pointer for core1 bus clock
+ * @vcodec0_clks: an array of vcodec0 struct clk pointers
+ * @vcodec1_clks: an array of vcodec1 struct clk pointers
+ * @pd_dl_venus: pmdomain device-link for venus domain
+ * @pmdomains: an array of pmdomains struct device pointers
  * @vdev_dec:  a reference to video device structure for decoder instances
  * @vdev_enc:  a reference to video device structure for encoder instances
  * @v4l2_dev:  a holder for v4l2 device structure
@@ -132,12 +140,12 @@ struct venus_core {
        void __iomem *base;
        int irq;
        struct clk *clks[VIDC_CLKS_NUM_MAX];
-       struct clk *core0_clk;
-       struct clk *core1_clk;
-       struct clk *core0_bus_clk;
-       struct clk *core1_bus_clk;
+       struct clk *vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX];
+       struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
        struct icc_path *video_path;
        struct icc_path *cpucfg_path;
+       struct device_link *pd_dl_venus;
+       struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX];
        struct video_device *vdev_dec;
        struct video_device *vdev_enc;
        struct v4l2_device v4l2_dev;
@@ -159,6 +167,7 @@ struct venus_core {
        unsigned int error;
        bool sys_error;
        const struct hfi_core_ops *core_ops;
+       const struct venus_pm_ops *pm_ops;
        unsigned long enc_codecs;
        unsigned long dec_codecs;
        unsigned int max_sessions_supported;
@@ -172,6 +181,8 @@ struct venus_core {
        struct delayed_work work;
        struct venus_caps caps[MAX_CODEC_NUM];
        unsigned int codecs_count;
+       unsigned int core0_usage_count;
+       unsigned int core1_usage_count;
 };
 
 struct vdec_controls {
@@ -187,6 +198,7 @@ struct venc_controls {
        u32 bitrate_mode;
        u32 bitrate;
        u32 bitrate_peak;
+       u32 rc_enable;
 
        u32 h264_i_period;
        u32 h264_entropy_mode;
@@ -344,6 +356,7 @@ struct venus_inst {
        unsigned int subscriptions;
        int buf_count;
        struct venus_ts_metadata tss[VIDEO_MAX_FRAME];
+       unsigned long payloads[VIDEO_MAX_FRAME];
        u64 fps;
        struct v4l2_fract timeperframe;
        const struct venus_format *fmt_out;
@@ -370,6 +383,8 @@ struct venus_inst {
        const struct hfi_inst_ops *ops;
        u32 session_type;
        union hfi_get_property hprop;
+       unsigned int core_acquired: 1;
+       unsigned int bit_depth;
 };
 
 #define IS_V1(core)    ((core)->res->hfi_version == HFI_VERSION_1XX)
index d3d1748..8801a6a 100644 (file)
@@ -44,8 +44,14 @@ static void venus_reset_cpu(struct venus_core *core)
 
 int venus_set_hw_state(struct venus_core *core, bool resume)
 {
-       if (core->use_tz)
-               return qcom_scm_set_remote_state(resume, 0);
+       int ret;
+
+       if (core->use_tz) {
+               ret = qcom_scm_set_remote_state(resume, 0);
+               if (resume && ret == -EINVAL)
+                       ret = 0;
+               return ret;
+       }
 
        if (resume)
                venus_reset_cpu(core);
@@ -100,8 +106,7 @@ static int venus_load_fw(struct venus_core *core, const char *fwname,
 
        mem_va = memremap(r.start, *mem_size, MEMREMAP_WC);
        if (!mem_va) {
-               dev_err(dev, "unable to map memory region: %pa+%zx\n",
-                       &r.start, *mem_size);
+               dev_err(dev, "unable to map memory region: %pR\n", &r);
                ret = -ENOMEM;
                goto err_release_fw;
        }
index a172f1a..bcc6038 100644 (file)
@@ -3,12 +3,8 @@
  * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
  * Copyright (C) 2017 Linaro Ltd.
  */
-#include <linux/clk.h>
-#include <linux/iopoll.h>
-#include <linux/interconnect.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
-#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <media/videobuf2-dma-sg.h>
 #include <media/v4l2-mem2mem.h>
@@ -17,7 +13,7 @@
 #include "core.h"
 #include "helpers.h"
 #include "hfi_helper.h"
-#include "hfi_venus_io.h"
+#include "pm_helpers.h"
 
 struct intbuf {
        struct list_head list;
@@ -360,266 +356,6 @@ err:
 }
 EXPORT_SYMBOL_GPL(venus_helper_intbufs_realloc);
 
-static u32 load_per_instance(struct venus_inst *inst)
-{
-       u32 mbs;
-
-       if (!inst || !(inst->state >= INST_INIT && inst->state < INST_STOP))
-               return 0;
-
-       mbs = (ALIGN(inst->width, 16) / 16) * (ALIGN(inst->height, 16) / 16);
-
-       return mbs * inst->fps;
-}
-
-static u32 load_per_type(struct venus_core *core, u32 session_type)
-{
-       struct venus_inst *inst = NULL;
-       u32 mbs_per_sec = 0;
-
-       mutex_lock(&core->lock);
-       list_for_each_entry(inst, &core->instances, list) {
-               if (inst->session_type != session_type)
-                       continue;
-
-               mbs_per_sec += load_per_instance(inst);
-       }
-       mutex_unlock(&core->lock);
-
-       return mbs_per_sec;
-}
-
-static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak)
-{
-       const struct venus_resources *res = inst->core->res;
-       const struct bw_tbl *bw_tbl;
-       unsigned int num_rows, i;
-
-       *avg = 0;
-       *peak = 0;
-
-       if (mbs == 0)
-               return;
-
-       if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
-               num_rows = res->bw_tbl_enc_size;
-               bw_tbl = res->bw_tbl_enc;
-       } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
-               num_rows = res->bw_tbl_dec_size;
-               bw_tbl = res->bw_tbl_dec;
-       } else {
-               return;
-       }
-
-       if (!bw_tbl || num_rows == 0)
-               return;
-
-       for (i = 0; i < num_rows; i++) {
-               if (mbs > bw_tbl[i].mbs_per_sec)
-                       break;
-
-               if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) {
-                       *avg = bw_tbl[i].avg_10bit;
-                       *peak = bw_tbl[i].peak_10bit;
-               } else {
-                       *avg = bw_tbl[i].avg;
-                       *peak = bw_tbl[i].peak;
-               }
-       }
-}
-
-static int load_scale_bw(struct venus_core *core)
-{
-       struct venus_inst *inst = NULL;
-       u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0;
-
-       mutex_lock(&core->lock);
-       list_for_each_entry(inst, &core->instances, list) {
-               mbs_per_sec = load_per_instance(inst);
-               mbs_to_bw(inst, mbs_per_sec, &avg, &peak);
-               total_avg += avg;
-               total_peak += peak;
-       }
-       mutex_unlock(&core->lock);
-
-       dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n",
-               total_avg, total_peak);
-
-       return icc_set_bw(core->video_path, total_avg, total_peak);
-}
-
-static int set_clk_freq(struct venus_core *core, unsigned long freq)
-{
-       struct clk *clk = core->clks[0];
-       int ret;
-
-       ret = clk_set_rate(clk, freq);
-       if (ret)
-               return ret;
-
-       ret = clk_set_rate(core->core0_clk, freq);
-       if (ret)
-               return ret;
-
-       ret = clk_set_rate(core->core1_clk, freq);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int scale_clocks(struct venus_inst *inst)
-{
-       struct venus_core *core = inst->core;
-       const struct freq_tbl *table = core->res->freq_tbl;
-       unsigned int num_rows = core->res->freq_tbl_size;
-       unsigned long freq = table[0].freq;
-       struct device *dev = core->dev;
-       u32 mbs_per_sec;
-       unsigned int i;
-       int ret;
-
-       mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) +
-                     load_per_type(core, VIDC_SESSION_TYPE_DEC);
-
-       if (mbs_per_sec > core->res->max_load)
-               dev_warn(dev, "HW is overloaded, needed: %d max: %d\n",
-                        mbs_per_sec, core->res->max_load);
-
-       if (!mbs_per_sec && num_rows > 1) {
-               freq = table[num_rows - 1].freq;
-               goto set_freq;
-       }
-
-       for (i = 0; i < num_rows; i++) {
-               if (mbs_per_sec > table[i].load)
-                       break;
-               freq = table[i].freq;
-       }
-
-set_freq:
-
-       ret = set_clk_freq(core, freq);
-       if (ret) {
-               dev_err(dev, "failed to set clock rate %lu (%d)\n",
-                       freq, ret);
-               return ret;
-       }
-
-       ret = load_scale_bw(core);
-       if (ret) {
-               dev_err(dev, "failed to set bandwidth (%d)\n",
-                       ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static unsigned long calculate_inst_freq(struct venus_inst *inst,
-                                        unsigned long filled_len)
-{
-       unsigned long vpp_freq = 0, vsp_freq = 0;
-       u32 fps = (u32)inst->fps;
-       u32 mbs_per_sec;
-
-       mbs_per_sec = load_per_instance(inst) / fps;
-
-       vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
-       /* 21 / 20 is overhead factor */
-       vpp_freq += vpp_freq / 20;
-       vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq;
-
-       /* 10 / 7 is overhead factor */
-       if (inst->session_type == VIDC_SESSION_TYPE_ENC)
-               vsp_freq += (inst->controls.enc.bitrate * 10) / 7;
-       else
-               vsp_freq += ((fps * filled_len * 8) * 10) / 7;
-
-       return max(vpp_freq, vsp_freq);
-}
-
-static int scale_clocks_v4(struct venus_inst *inst)
-{
-       struct venus_core *core = inst->core;
-       const struct freq_tbl *table = core->res->freq_tbl;
-       unsigned int num_rows = core->res->freq_tbl_size;
-       struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
-       struct device *dev = core->dev;
-       unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
-       unsigned long filled_len = 0;
-       struct venus_buffer *buf, *n;
-       struct vb2_buffer *vb;
-       int i, ret;
-
-       v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
-               vb = &buf->vb.vb2_buf;
-               filled_len = max(filled_len, vb2_get_plane_payload(vb, 0));
-       }
-
-       if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
-               return 0;
-
-       freq = calculate_inst_freq(inst, filled_len);
-       inst->clk_data.freq = freq;
-
-       mutex_lock(&core->lock);
-       list_for_each_entry(inst, &core->instances, list) {
-               if (inst->clk_data.core_id == VIDC_CORE_ID_1) {
-                       freq_core1 += inst->clk_data.freq;
-               } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) {
-                       freq_core2 += inst->clk_data.freq;
-               } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
-                       freq_core1 += inst->clk_data.freq;
-                       freq_core2 += inst->clk_data.freq;
-               }
-       }
-       mutex_unlock(&core->lock);
-
-       freq = max(freq_core1, freq_core2);
-
-       if (freq >= table[0].freq) {
-               freq = table[0].freq;
-               dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n",
-                        freq, table[0].freq);
-               goto set_freq;
-       }
-
-       for (i = num_rows - 1 ; i >= 0; i--) {
-               if (freq <= table[i].freq) {
-                       freq = table[i].freq;
-                       break;
-               }
-       }
-
-set_freq:
-
-       ret = set_clk_freq(core, freq);
-       if (ret) {
-               dev_err(dev, "failed to set clock rate %lu (%d)\n",
-                       freq, ret);
-               return ret;
-       }
-
-       ret = load_scale_bw(core);
-       if (ret) {
-               dev_err(dev, "failed to set bandwidth (%d)\n",
-                       ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-int venus_helper_load_scale_clocks(struct venus_inst *inst)
-{
-       if (IS_V4(inst->core))
-               return scale_clocks_v4(inst);
-
-       return scale_clocks(inst);
-}
-EXPORT_SYMBOL_GPL(venus_helper_load_scale_clocks);
-
 static void fill_buffer_desc(const struct venus_buffer *buf,
                             struct hfi_buffer_desc *bd, bool response)
 {
@@ -723,7 +459,7 @@ session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
                if (inst->session_type == VIDC_SESSION_TYPE_DEC)
                        put_ts_metadata(inst, vbuf);
 
-               venus_helper_load_scale_clocks(inst);
+               venus_pm_load_scale(inst);
        } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                if (inst->session_type == VIDC_SESSION_TYPE_ENC)
                        fdata.buffer_type = HFI_BUFFER_OUTPUT;
@@ -890,6 +626,78 @@ static u32 get_framesize_raw_nv12_ubwc(u32 width, u32 height)
                     max(extradata, y_stride * 48), SZ_4K);
 }
 
+static u32 get_framesize_raw_p010(u32 width, u32 height)
+{
+       u32 y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines;
+
+       y_stride = ALIGN(width * 2, 256);
+       uv_stride = ALIGN(width * 2, 256);
+       y_sclines = ALIGN(height, 32);
+       uv_sclines = ALIGN((height + 1) >> 1, 16);
+       y_plane = y_stride * y_sclines;
+       uv_plane = uv_stride * uv_sclines;
+
+       return ALIGN((y_plane + uv_plane), SZ_4K);
+}
+
+static u32 get_framesize_raw_p010_ubwc(u32 width, u32 height)
+{
+       u32 y_stride, uv_stride, y_sclines, uv_sclines;
+       u32 y_ubwc_plane, uv_ubwc_plane;
+       u32 y_meta_stride, y_meta_scanlines;
+       u32 uv_meta_stride, uv_meta_scanlines;
+       u32 y_meta_plane, uv_meta_plane;
+       u32 size;
+
+       y_stride = ALIGN(width * 2, 256);
+       uv_stride = ALIGN(width * 2, 256);
+       y_sclines = ALIGN(height, 16);
+       uv_sclines = ALIGN((height + 1) >> 1, 16);
+
+       y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
+       uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
+       y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64);
+       y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
+       y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
+       uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 16), 64);
+       uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
+       uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
+
+       size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
+
+       return ALIGN(size, SZ_4K);
+}
+
+static u32 get_framesize_raw_yuv420_tp10_ubwc(u32 width, u32 height)
+{
+       u32 y_stride, uv_stride, y_sclines, uv_sclines;
+       u32 y_ubwc_plane, uv_ubwc_plane;
+       u32 y_meta_stride, y_meta_scanlines;
+       u32 uv_meta_stride, uv_meta_scanlines;
+       u32 y_meta_plane, uv_meta_plane;
+       u32 extradata = SZ_16K;
+       u32 size;
+
+       y_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256);
+       uv_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256);
+       y_sclines = ALIGN(height, 16);
+       uv_sclines = ALIGN((height + 1) >> 1, 16);
+
+       y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K);
+       uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K);
+       y_meta_stride = ALIGN(DIV_ROUND_UP(width, 48), 64);
+       y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16);
+       y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K);
+       uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 24), 64);
+       uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16);
+       uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K);
+
+       size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane;
+       size += max(extradata + SZ_8K, y_stride * 48);
+
+       return ALIGN(size, SZ_4K);
+}
+
 u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height)
 {
        switch (hfi_fmt) {
@@ -898,6 +706,12 @@ u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height)
                return get_framesize_raw_nv12(width, height);
        case HFI_COLOR_FORMAT_NV12_UBWC:
                return get_framesize_raw_nv12_ubwc(width, height);
+       case HFI_COLOR_FORMAT_P010:
+               return get_framesize_raw_p010(width, height);
+       case HFI_COLOR_FORMAT_P010_UBWC:
+               return get_framesize_raw_p010_ubwc(width, height);
+       case HFI_COLOR_FORMAT_YUV420_TP10_UBWC:
+               return get_framesize_raw_yuv420_tp10_ubwc(width, height);
        default:
                return 0;
        }
@@ -987,21 +801,6 @@ int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode)
 }
 EXPORT_SYMBOL_GPL(venus_helper_set_work_mode);
 
-int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage)
-{
-       const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
-       struct hfi_videocores_usage_type cu;
-
-       inst->clk_data.core_id = usage;
-       if (!IS_V4(inst->core))
-               return 0;
-
-       cu.video_core_enable_mask = usage;
-
-       return hfi_session_set_property(inst, ptype, &cu);
-}
-EXPORT_SYMBOL_GPL(venus_helper_set_core_usage);
-
 int venus_helper_init_codec_freq_data(struct venus_inst *inst)
 {
        const struct codec_freq_data *data;
@@ -1289,6 +1088,15 @@ int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb)
 }
 EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_prepare);
 
+static void cache_payload(struct venus_inst *inst, struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       unsigned int idx = vbuf->vb2_buf.index;
+
+       if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+               inst->payloads[idx] = vb2_get_plane_payload(vb, 0);
+}
+
 void venus_helper_vb2_buf_queue(struct vb2_buffer *vb)
 {
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -1300,6 +1108,8 @@ void venus_helper_vb2_buf_queue(struct vb2_buffer *vb)
 
        v4l2_m2m_buf_queue(m2m_ctx, vbuf);
 
+       cache_payload(inst, vb);
+
        if (inst->session_type == VIDC_SESSION_TYPE_ENC &&
            !(inst->streamon_out && inst->streamon_cap))
                goto unlock;
@@ -1354,7 +1164,7 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
 
                venus_helper_free_dpb_bufs(inst);
 
-               venus_helper_load_scale_clocks(inst);
+               venus_pm_load_scale(inst);
                INIT_LIST_HEAD(&inst->registeredbufs);
        }
 
@@ -1365,6 +1175,8 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
        else
                inst->streamon_cap = 0;
 
+       venus_pm_release_core(inst);
+
        mutex_unlock(&inst->lock);
 }
 EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
@@ -1417,7 +1229,7 @@ int venus_helper_vb2_start_streaming(struct venus_inst *inst)
        if (ret)
                goto err_bufs_free;
 
-       venus_helper_load_scale_clocks(inst);
+       venus_pm_load_scale(inst);
 
        ret = hfi_session_load_res(inst);
        if (ret)
@@ -1512,6 +1324,27 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt,
        if (!caps)
                return -EINVAL;
 
+       if (inst->bit_depth == VIDC_BITDEPTH_10 &&
+           inst->session_type == VIDC_SESSION_TYPE_DEC) {
+               found_ubwc =
+                       find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
+                                          HFI_COLOR_FORMAT_YUV420_TP10_UBWC);
+               found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2,
+                                          HFI_COLOR_FORMAT_NV12);
+               if (found_ubwc && found) {
+                       /*
+                        * Hard-code DPB buffers to be 10bit UBWC and decoder
+                        * output buffers in 8bit NV12 until V4L2 is able to
+                        * expose compressed/tiled formats to applications.
+                        */
+                       *out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC;
+                       *out2_fmt = HFI_COLOR_FORMAT_NV12;
+                       return 0;
+               }
+
+               return -EINVAL;
+       }
+
        if (ubwc) {
                ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE;
                found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT,
@@ -1542,52 +1375,3 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt,
        return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts);
-
-int venus_helper_power_enable(struct venus_core *core, u32 session_type,
-                             bool enable)
-{
-       void __iomem *ctrl, *stat;
-       u32 val;
-       int ret;
-
-       if (!IS_V3(core) && !IS_V4(core))
-               return 0;
-
-       if (IS_V3(core)) {
-               if (session_type == VIDC_SESSION_TYPE_DEC)
-                       ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL;
-               else
-                       ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL;
-               if (enable)
-                       writel(0, ctrl);
-               else
-                       writel(1, ctrl);
-
-               return 0;
-       }
-
-       if (session_type == VIDC_SESSION_TYPE_DEC) {
-               ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
-               stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
-       } else {
-               ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
-               stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
-       }
-
-       if (enable) {
-               writel(0, ctrl);
-
-               ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100);
-               if (ret)
-                       return ret;
-       } else {
-               writel(1, ctrl);
-
-               ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(venus_helper_power_enable);
index 34dcd0c..b648755 100644 (file)
@@ -34,7 +34,6 @@ int venus_helper_set_output_resolution(struct venus_inst *inst,
                                       u32 buftype);
 int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode);
 int venus_helper_init_codec_freq_data(struct venus_inst *inst);
-int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage);
 int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
                              unsigned int output_bufs,
                              unsigned int output2_bufs);
@@ -53,14 +52,11 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 fmt, u32 *out_fmt,
                              u32 *out2_fmt, bool ubwc);
 int venus_helper_alloc_dpb_bufs(struct venus_inst *inst);
 int venus_helper_free_dpb_bufs(struct venus_inst *inst);
-int venus_helper_power_enable(struct venus_core *core, u32 session_type,
-                             bool enable);
 int venus_helper_intbufs_alloc(struct venus_inst *inst);
 int venus_helper_intbufs_free(struct venus_inst *inst);
 int venus_helper_intbufs_realloc(struct venus_inst *inst);
 int venus_helper_queue_dpb_bufs(struct venus_inst *inst);
 int venus_helper_unregister_bufs(struct venus_inst *inst);
-int venus_helper_load_scale_clocks(struct venus_inst *inst);
 int venus_helper_process_initial_cap_bufs(struct venus_inst *inst);
 int venus_helper_process_initial_out_bufs(struct venus_inst *inst);
 void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
index 4f64507..c67e412 100644 (file)
@@ -1207,6 +1207,8 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
        case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
        case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
        case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE:
+       case HFI_PROPERTY_PARAM_VENC_SESSION_QP:
+       case HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE:
                /* not implemented on Venus 4xx */
                return -ENOTSUPP;
        default:
index b70551e..f6613df 100644 (file)
@@ -550,6 +550,7 @@ struct hfi_bitrate {
 #define HFI_CAPABILITY_LCU_SIZE                                0x14
 #define HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS    0x15
 #define HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE                0x16
+#define HFI_CAPABILITY_MAX_VIDEOCORES                  0x2b
 
 struct hfi_capability {
        u32 capability_type;
@@ -792,6 +793,9 @@ struct hfi_h264_vui_timing_info {
        u32 time_scale;
 };
 
+#define VIDC_BITDEPTH_8                0x00000
+#define VIDC_BITDEPTH_10       0x20002
+
 struct hfi_bit_depth {
        u32 buffer_type;
        u32 bit_depth;
@@ -840,8 +844,10 @@ struct hfi_extradata_input_crop {
 #define HFI_COLOR_FORMAT_10_BIT_BASE           0x4000
 
 #define HFI_COLOR_FORMAT_YUV420_TP10           0x4002
+#define HFI_COLOR_FORMAT_P010                  0x4003
 #define HFI_COLOR_FORMAT_NV12_UBWC             0x8002
 #define HFI_COLOR_FORMAT_YUV420_TP10_UBWC      0xc002
+#define HFI_COLOR_FORMAT_P010_UBWC             0xc003
 #define HFI_COLOR_FORMAT_RGBA8888_UBWC         0x8010
 
 struct hfi_uncompressed_format_select {
index 2293d93..7f515a4 100644 (file)
@@ -181,6 +181,7 @@ static void parse_codecs(struct venus_core *core, void *data)
        if (IS_V1(core)) {
                core->dec_codecs &= ~HFI_VIDEO_CODEC_HEVC;
                core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK;
+               core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC;
        }
 }
 
index 3e931c7..264e6dd 100644 (file)
@@ -107,4 +107,9 @@ static inline u32 frate_step(struct venus_inst *inst)
        return cap_step(inst, HFI_CAPABILITY_FRAMERATE);
 }
 
+static inline u32 core_num_max(struct venus_inst *inst)
+{
+       return cap_max(inst, HFI_CAPABILITY_MAX_VIDEOCORES);
+}
+
 #endif
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
new file mode 100644 (file)
index 0000000..abf9315
--- /dev/null
@@ -0,0 +1,959 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Linaro Ltd.
+ *
+ * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+ */
+#include <linux/clk.h>
+#include <linux/interconnect.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/types.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "core.h"
+#include "hfi_parser.h"
+#include "hfi_venus_io.h"
+#include "pm_helpers.h"
+
+static bool legacy_binding;
+
+static int core_clks_get(struct venus_core *core)
+{
+       const struct venus_resources *res = core->res;
+       struct device *dev = core->dev;
+       unsigned int i;
+
+       for (i = 0; i < res->clks_num; i++) {
+               core->clks[i] = devm_clk_get(dev, res->clks[i]);
+               if (IS_ERR(core->clks[i]))
+                       return PTR_ERR(core->clks[i]);
+       }
+
+       return 0;
+}
+
+static int core_clks_enable(struct venus_core *core)
+{
+       const struct venus_resources *res = core->res;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < res->clks_num; i++) {
+               ret = clk_prepare_enable(core->clks[i]);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+err:
+       while (i--)
+               clk_disable_unprepare(core->clks[i]);
+
+       return ret;
+}
+
+static void core_clks_disable(struct venus_core *core)
+{
+       const struct venus_resources *res = core->res;
+       unsigned int i = res->clks_num;
+
+       while (i--)
+               clk_disable_unprepare(core->clks[i]);
+}
+
+static int core_clks_set_rate(struct venus_core *core, unsigned long freq)
+{
+       struct clk *clk = core->clks[0];
+       int ret;
+
+       ret = clk_set_rate(clk, freq);
+       if (ret)
+               return ret;
+
+       ret = clk_set_rate(core->vcodec0_clks[0], freq);
+       if (ret)
+               return ret;
+
+       ret = clk_set_rate(core->vcodec1_clks[0], freq);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int vcodec_clks_get(struct venus_core *core, struct device *dev,
+                          struct clk **clks, const char * const *id)
+{
+       const struct venus_resources *res = core->res;
+       unsigned int i;
+
+       for (i = 0; i < res->vcodec_clks_num; i++) {
+               if (!id[i])
+                       continue;
+               clks[i] = devm_clk_get(dev, id[i]);
+               if (IS_ERR(clks[i]))
+                       return PTR_ERR(clks[i]);
+       }
+
+       return 0;
+}
+
+static int vcodec_clks_enable(struct venus_core *core, struct clk **clks)
+{
+       const struct venus_resources *res = core->res;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < res->vcodec_clks_num; i++) {
+               ret = clk_prepare_enable(clks[i]);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+err:
+       while (i--)
+               clk_disable_unprepare(clks[i]);
+
+       return ret;
+}
+
+static void vcodec_clks_disable(struct venus_core *core, struct clk **clks)
+{
+       const struct venus_resources *res = core->res;
+       unsigned int i = res->vcodec_clks_num;
+
+       while (i--)
+               clk_disable_unprepare(clks[i]);
+}
+
+static u32 load_per_instance(struct venus_inst *inst)
+{
+       u32 mbs;
+
+       if (!inst || !(inst->state >= INST_INIT && inst->state < INST_STOP))
+               return 0;
+
+       mbs = (ALIGN(inst->width, 16) / 16) * (ALIGN(inst->height, 16) / 16);
+
+       return mbs * inst->fps;
+}
+
+static u32 load_per_type(struct venus_core *core, u32 session_type)
+{
+       struct venus_inst *inst = NULL;
+       u32 mbs_per_sec = 0;
+
+       mutex_lock(&core->lock);
+       list_for_each_entry(inst, &core->instances, list) {
+               if (inst->session_type != session_type)
+                       continue;
+
+               mbs_per_sec += load_per_instance(inst);
+       }
+       mutex_unlock(&core->lock);
+
+       return mbs_per_sec;
+}
+
+static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak)
+{
+       const struct venus_resources *res = inst->core->res;
+       const struct bw_tbl *bw_tbl;
+       unsigned int num_rows, i;
+
+       *avg = 0;
+       *peak = 0;
+
+       if (mbs == 0)
+               return;
+
+       if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
+               num_rows = res->bw_tbl_enc_size;
+               bw_tbl = res->bw_tbl_enc;
+       } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
+               num_rows = res->bw_tbl_dec_size;
+               bw_tbl = res->bw_tbl_dec;
+       } else {
+               return;
+       }
+
+       if (!bw_tbl || num_rows == 0)
+               return;
+
+       for (i = 0; i < num_rows; i++) {
+               if (mbs > bw_tbl[i].mbs_per_sec)
+                       break;
+
+               if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) {
+                       *avg = bw_tbl[i].avg_10bit;
+                       *peak = bw_tbl[i].peak_10bit;
+               } else {
+                       *avg = bw_tbl[i].avg;
+                       *peak = bw_tbl[i].peak;
+               }
+       }
+}
+
+static int load_scale_bw(struct venus_core *core)
+{
+       struct venus_inst *inst = NULL;
+       u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0;
+
+       mutex_lock(&core->lock);
+       list_for_each_entry(inst, &core->instances, list) {
+               mbs_per_sec = load_per_instance(inst);
+               mbs_to_bw(inst, mbs_per_sec, &avg, &peak);
+               total_avg += avg;
+               total_peak += peak;
+       }
+       mutex_unlock(&core->lock);
+
+       dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n",
+               total_avg, total_peak);
+
+       return icc_set_bw(core->video_path, total_avg, total_peak);
+}
+
+static int load_scale_v1(struct venus_inst *inst)
+{
+       struct venus_core *core = inst->core;
+       const struct freq_tbl *table = core->res->freq_tbl;
+       unsigned int num_rows = core->res->freq_tbl_size;
+       unsigned long freq = table[0].freq;
+       struct device *dev = core->dev;
+       u32 mbs_per_sec;
+       unsigned int i;
+       int ret;
+
+       mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) +
+                     load_per_type(core, VIDC_SESSION_TYPE_DEC);
+
+       if (mbs_per_sec > core->res->max_load)
+               dev_warn(dev, "HW is overloaded, needed: %d max: %d\n",
+                        mbs_per_sec, core->res->max_load);
+
+       if (!mbs_per_sec && num_rows > 1) {
+               freq = table[num_rows - 1].freq;
+               goto set_freq;
+       }
+
+       for (i = 0; i < num_rows; i++) {
+               if (mbs_per_sec > table[i].load)
+                       break;
+               freq = table[i].freq;
+       }
+
+set_freq:
+
+       ret = core_clks_set_rate(core, freq);
+       if (ret) {
+               dev_err(dev, "failed to set clock rate %lu (%d)\n",
+                       freq, ret);
+               return ret;
+       }
+
+       ret = load_scale_bw(core);
+       if (ret) {
+               dev_err(dev, "failed to set bandwidth (%d)\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int core_get_v1(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+
+       return core_clks_get(core);
+}
+
+static int core_power_v1(struct device *dev, int on)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (on == POWER_ON)
+               ret = core_clks_enable(core);
+       else
+               core_clks_disable(core);
+
+       return ret;
+}
+
+static const struct venus_pm_ops pm_ops_v1 = {
+       .core_get = core_get_v1,
+       .core_power = core_power_v1,
+       .load_scale = load_scale_v1,
+};
+
+static void
+vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable)
+{
+       void __iomem *ctrl;
+
+       if (session_type == VIDC_SESSION_TYPE_DEC)
+               ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL;
+       else
+               ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL;
+
+       if (enable)
+               writel(0, ctrl);
+       else
+               writel(1, ctrl);
+}
+
+static int vdec_get_v3(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+
+       return vcodec_clks_get(core, dev, core->vcodec0_clks,
+                              core->res->vcodec0_clks);
+}
+
+static int vdec_power_v3(struct device *dev, int on)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       int ret = 0;
+
+       vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, true);
+
+       if (on == POWER_ON)
+               ret = vcodec_clks_enable(core, core->vcodec0_clks);
+       else
+               vcodec_clks_disable(core, core->vcodec0_clks);
+
+       vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, false);
+
+       return ret;
+}
+
+static int venc_get_v3(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+
+       return vcodec_clks_get(core, dev, core->vcodec1_clks,
+                              core->res->vcodec1_clks);
+}
+
+static int venc_power_v3(struct device *dev, int on)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       int ret = 0;
+
+       vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, true);
+
+       if (on == POWER_ON)
+               ret = vcodec_clks_enable(core, core->vcodec1_clks);
+       else
+               vcodec_clks_disable(core, core->vcodec1_clks);
+
+       vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, false);
+
+       return ret;
+}
+
+static const struct venus_pm_ops pm_ops_v3 = {
+       .core_get = core_get_v1,
+       .core_power = core_power_v1,
+       .vdec_get = vdec_get_v3,
+       .vdec_power = vdec_power_v3,
+       .venc_get = venc_get_v3,
+       .venc_power = venc_power_v3,
+       .load_scale = load_scale_v1,
+};
+
+static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable)
+{
+       void __iomem *ctrl, *stat;
+       u32 val;
+       int ret;
+
+       if (coreid == VIDC_CORE_ID_1) {
+               ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL;
+               stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS;
+       } else {
+               ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL;
+               stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS;
+       }
+
+       if (enable) {
+               writel(0, ctrl);
+
+               ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100);
+               if (ret)
+                       return ret;
+       } else {
+               writel(1, ctrl);
+
+               ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask)
+{
+       int ret;
+
+       if (coreid_mask & VIDC_CORE_ID_1) {
+               ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
+               if (ret)
+                       return ret;
+
+               vcodec_clks_disable(core, core->vcodec0_clks);
+
+               ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
+               if (ret)
+                       return ret;
+
+               ret = pm_runtime_put_sync(core->pmdomains[1]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (coreid_mask & VIDC_CORE_ID_2) {
+               ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
+               if (ret)
+                       return ret;
+
+               vcodec_clks_disable(core, core->vcodec1_clks);
+
+               ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
+               if (ret)
+                       return ret;
+
+               ret = pm_runtime_put_sync(core->pmdomains[2]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask)
+{
+       int ret;
+
+       if (coreid_mask & VIDC_CORE_ID_1) {
+               ret = pm_runtime_get_sync(core->pmdomains[1]);
+               if (ret < 0)
+                       return ret;
+
+               ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
+               if (ret)
+                       return ret;
+
+               ret = vcodec_clks_enable(core, core->vcodec0_clks);
+               if (ret)
+                       return ret;
+
+               ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (coreid_mask & VIDC_CORE_ID_2) {
+               ret = pm_runtime_get_sync(core->pmdomains[2]);
+               if (ret < 0)
+                       return ret;
+
+               ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
+               if (ret)
+                       return ret;
+
+               ret = vcodec_clks_enable(core, core->vcodec1_clks);
+               if (ret)
+                       return ret;
+
+               ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void
+min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
+{
+       u32 mbs_per_sec, load, core1_load = 0, core2_load = 0;
+       u32 cores_max = core_num_max(inst);
+       struct venus_core *core = inst->core;
+       struct venus_inst *inst_pos;
+       unsigned long vpp_freq;
+       u32 coreid;
+
+       mutex_lock(&core->lock);
+
+       list_for_each_entry(inst_pos, &core->instances, list) {
+               if (inst_pos == inst)
+                       continue;
+               vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq;
+               coreid = inst_pos->clk_data.core_id;
+
+               mbs_per_sec = load_per_instance(inst_pos);
+               load = mbs_per_sec * vpp_freq;
+
+               if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) {
+                       core1_load += load / 2;
+                       core2_load += load / 2;
+               } else if (coreid & VIDC_CORE_ID_1) {
+                       core1_load += load;
+               } else if (coreid & VIDC_CORE_ID_2) {
+                       core2_load += load;
+               }
+       }
+
+       *min_coreid = core1_load <= core2_load ?
+                       VIDC_CORE_ID_1 : VIDC_CORE_ID_2;
+       *min_load = min(core1_load, core2_load);
+
+       if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) {
+               *min_coreid = VIDC_CORE_ID_1;
+               *min_load = core1_load;
+       }
+
+       mutex_unlock(&core->lock);
+}
+
+static int decide_core(struct venus_inst *inst)
+{
+       const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
+       struct venus_core *core = inst->core;
+       u32 min_coreid, min_load, inst_load;
+       struct hfi_videocores_usage_type cu;
+       unsigned long max_freq;
+
+       if (legacy_binding) {
+               if (inst->session_type == VIDC_SESSION_TYPE_DEC)
+                       cu.video_core_enable_mask = VIDC_CORE_ID_1;
+               else
+                       cu.video_core_enable_mask = VIDC_CORE_ID_2;
+
+               goto done;
+       }
+
+       if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT)
+               return 0;
+
+       inst_load = load_per_instance(inst);
+       inst_load *= inst->clk_data.codec_freq_data->vpp_freq;
+       max_freq = core->res->freq_tbl[0].freq;
+
+       min_loaded_core(inst, &min_coreid, &min_load);
+
+       if ((inst_load + min_load) > max_freq) {
+               dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n",
+                        inst_load, max_freq);
+               return -EINVAL;
+       }
+
+       inst->clk_data.core_id = min_coreid;
+       cu.video_core_enable_mask = min_coreid;
+
+done:
+       return hfi_session_set_property(inst, ptype, &cu);
+}
+
+static int acquire_core(struct venus_inst *inst)
+{
+       struct venus_core *core = inst->core;
+       unsigned int coreid_mask = 0;
+
+       if (inst->core_acquired)
+               return 0;
+
+       inst->core_acquired = true;
+
+       if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
+               if (core->core0_usage_count++)
+                       return 0;
+
+               coreid_mask = VIDC_CORE_ID_1;
+       }
+
+       if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
+               if (core->core1_usage_count++)
+                       return 0;
+
+               coreid_mask |= VIDC_CORE_ID_2;
+       }
+
+       return poweron_coreid(core, coreid_mask);
+}
+
+static int release_core(struct venus_inst *inst)
+{
+       struct venus_core *core = inst->core;
+       unsigned int coreid_mask = 0;
+       int ret;
+
+       if (!inst->core_acquired)
+               return 0;
+
+       if (inst->clk_data.core_id & VIDC_CORE_ID_1) {
+               if (--core->core0_usage_count)
+                       goto done;
+
+               coreid_mask = VIDC_CORE_ID_1;
+       }
+
+       if (inst->clk_data.core_id & VIDC_CORE_ID_2) {
+               if (--core->core1_usage_count)
+                       goto done;
+
+               coreid_mask |= VIDC_CORE_ID_2;
+       }
+
+       ret = poweroff_coreid(core, coreid_mask);
+       if (ret)
+               return ret;
+
+done:
+       inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
+       inst->core_acquired = false;
+       return 0;
+}
+
+static int coreid_power_v4(struct venus_inst *inst, int on)
+{
+       struct venus_core *core = inst->core;
+       int ret;
+
+       if (legacy_binding)
+               return 0;
+
+       if (on == POWER_ON) {
+               ret = decide_core(inst);
+               if (ret)
+                       return ret;
+
+               mutex_lock(&core->lock);
+               ret = acquire_core(inst);
+               mutex_unlock(&core->lock);
+       } else {
+               mutex_lock(&core->lock);
+               ret = release_core(inst);
+               mutex_unlock(&core->lock);
+       }
+
+       return ret;
+}
+
+static int vdec_get_v4(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+
+       if (!legacy_binding)
+               return 0;
+
+       return vcodec_clks_get(core, dev, core->vcodec0_clks,
+                              core->res->vcodec0_clks);
+}
+
+static void vdec_put_v4(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       unsigned int i;
+
+       if (!legacy_binding)
+               return;
+
+       for (i = 0; i < core->res->vcodec_clks_num; i++)
+               core->vcodec0_clks[i] = NULL;
+}
+
+static int vdec_power_v4(struct device *dev, int on)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       int ret;
+
+       if (!legacy_binding)
+               return 0;
+
+       ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true);
+       if (ret)
+               return ret;
+
+       if (on == POWER_ON)
+               ret = vcodec_clks_enable(core, core->vcodec0_clks);
+       else
+               vcodec_clks_disable(core, core->vcodec0_clks);
+
+       vcodec_control_v4(core, VIDC_CORE_ID_1, false);
+
+       return ret;
+}
+
+static int venc_get_v4(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+
+       if (!legacy_binding)
+               return 0;
+
+       return vcodec_clks_get(core, dev, core->vcodec1_clks,
+                              core->res->vcodec1_clks);
+}
+
+static void venc_put_v4(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       unsigned int i;
+
+       if (!legacy_binding)
+               return;
+
+       for (i = 0; i < core->res->vcodec_clks_num; i++)
+               core->vcodec1_clks[i] = NULL;
+}
+
+static int venc_power_v4(struct device *dev, int on)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       int ret;
+
+       if (!legacy_binding)
+               return 0;
+
+       ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true);
+       if (ret)
+               return ret;
+
+       if (on == POWER_ON)
+               ret = vcodec_clks_enable(core, core->vcodec1_clks);
+       else
+               vcodec_clks_disable(core, core->vcodec1_clks);
+
+       vcodec_control_v4(core, VIDC_CORE_ID_2, false);
+
+       return ret;
+}
+
+static int vcodec_domains_get(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       const struct venus_resources *res = core->res;
+       struct device *pd;
+       unsigned int i;
+
+       if (!res->vcodec_pmdomains_num)
+               return -ENODEV;
+
+       for (i = 0; i < res->vcodec_pmdomains_num; i++) {
+               pd = dev_pm_domain_attach_by_name(dev,
+                                                 res->vcodec_pmdomains[i]);
+               if (IS_ERR(pd))
+                       return PTR_ERR(pd);
+               core->pmdomains[i] = pd;
+       }
+
+       core->pd_dl_venus = device_link_add(dev, core->pmdomains[0],
+                                           DL_FLAG_PM_RUNTIME |
+                                           DL_FLAG_STATELESS |
+                                           DL_FLAG_RPM_ACTIVE);
+       if (!core->pd_dl_venus)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void vcodec_domains_put(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       const struct venus_resources *res = core->res;
+       unsigned int i;
+
+       if (!res->vcodec_pmdomains_num)
+               return;
+
+       if (core->pd_dl_venus)
+               device_link_del(core->pd_dl_venus);
+
+       for (i = 0; i < res->vcodec_pmdomains_num; i++) {
+               if (IS_ERR_OR_NULL(core->pmdomains[i]))
+                       continue;
+               dev_pm_domain_detach(core->pmdomains[i], true);
+       }
+}
+
+static int core_get_v4(struct device *dev)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       const struct venus_resources *res = core->res;
+       int ret;
+
+       ret = core_clks_get(core);
+       if (ret)
+               return ret;
+
+       if (!res->vcodec_pmdomains_num)
+               legacy_binding = true;
+
+       dev_info(dev, "%s legacy binding\n", legacy_binding ? "" : "non");
+
+       ret = vcodec_clks_get(core, dev, core->vcodec0_clks, res->vcodec0_clks);
+       if (ret)
+               return ret;
+
+       ret = vcodec_clks_get(core, dev, core->vcodec1_clks, res->vcodec1_clks);
+       if (ret)
+               return ret;
+
+       if (legacy_binding)
+               return 0;
+
+       ret = vcodec_domains_get(dev);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void core_put_v4(struct device *dev)
+{
+       if (legacy_binding)
+               return;
+
+       vcodec_domains_put(dev);
+}
+
+static int core_power_v4(struct device *dev, int on)
+{
+       struct venus_core *core = dev_get_drvdata(dev);
+       int ret = 0;
+
+       if (on == POWER_ON)
+               ret = core_clks_enable(core);
+       else
+               core_clks_disable(core);
+
+       return ret;
+}
+
+static unsigned long calculate_inst_freq(struct venus_inst *inst,
+                                        unsigned long filled_len)
+{
+       unsigned long vpp_freq = 0, vsp_freq = 0;
+       u32 fps = (u32)inst->fps;
+       u32 mbs_per_sec;
+
+       mbs_per_sec = load_per_instance(inst) / fps;
+
+       vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
+       /* 21 / 20 is overhead factor */
+       vpp_freq += vpp_freq / 20;
+       vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq;
+
+       /* 10 / 7 is overhead factor */
+       if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+               vsp_freq += (inst->controls.enc.bitrate * 10) / 7;
+       else
+               vsp_freq += ((fps * filled_len * 8) * 10) / 7;
+
+       return max(vpp_freq, vsp_freq);
+}
+
+static int load_scale_v4(struct venus_inst *inst)
+{
+       struct venus_core *core = inst->core;
+       const struct freq_tbl *table = core->res->freq_tbl;
+       unsigned int num_rows = core->res->freq_tbl_size;
+       struct device *dev = core->dev;
+       unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
+       unsigned long filled_len = 0;
+       int i, ret;
+
+       for (i = 0; i < inst->num_input_bufs; i++)
+               filled_len = max(filled_len, inst->payloads[i]);
+
+       if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
+               return 0;
+
+       freq = calculate_inst_freq(inst, filled_len);
+       inst->clk_data.freq = freq;
+
+       mutex_lock(&core->lock);
+       list_for_each_entry(inst, &core->instances, list) {
+               if (inst->clk_data.core_id == VIDC_CORE_ID_1) {
+                       freq_core1 += inst->clk_data.freq;
+               } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) {
+                       freq_core2 += inst->clk_data.freq;
+               } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
+                       freq_core1 += inst->clk_data.freq;
+                       freq_core2 += inst->clk_data.freq;
+               }
+       }
+       mutex_unlock(&core->lock);
+
+       freq = max(freq_core1, freq_core2);
+
+       if (freq >= table[0].freq) {
+               freq = table[0].freq;
+               dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n",
+                        freq, table[0].freq);
+               goto set_freq;
+       }
+
+       for (i = num_rows - 1 ; i >= 0; i--) {
+               if (freq <= table[i].freq) {
+                       freq = table[i].freq;
+                       break;
+               }
+       }
+
+set_freq:
+
+       ret = core_clks_set_rate(core, freq);
+       if (ret) {
+               dev_err(dev, "failed to set clock rate %lu (%d)\n",
+                       freq, ret);
+               return ret;
+       }
+
+       ret = load_scale_bw(core);
+       if (ret) {
+               dev_err(dev, "failed to set bandwidth (%d)\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct venus_pm_ops pm_ops_v4 = {
+       .core_get = core_get_v4,
+       .core_put = core_put_v4,
+       .core_power = core_power_v4,
+       .vdec_get = vdec_get_v4,
+       .vdec_put = vdec_put_v4,
+       .vdec_power = vdec_power_v4,
+       .venc_get = venc_get_v4,
+       .venc_put = venc_put_v4,
+       .venc_power = venc_power_v4,
+       .coreid_power = coreid_power_v4,
+       .load_scale = load_scale_v4,
+};
+
+const struct venus_pm_ops *venus_pm_get(enum hfi_version version)
+{
+       switch (version) {
+       case HFI_VERSION_1XX:
+       default:
+               return &pm_ops_v1;
+       case HFI_VERSION_3XX:
+               return &pm_ops_v3;
+       case HFI_VERSION_4XX:
+               return &pm_ops_v4;
+       }
+
+       return NULL;
+}
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.h b/drivers/media/platform/qcom/venus/pm_helpers.h
new file mode 100644 (file)
index 0000000..aa2f6af
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2019 Linaro Ltd. */
+#ifndef __VENUS_PM_HELPERS_H__
+#define __VENUS_PM_HELPERS_H__
+
+struct device;
+
+#define POWER_ON       1
+#define POWER_OFF      0
+
+struct venus_pm_ops {
+       int (*core_get)(struct device *dev);
+       void (*core_put)(struct device *dev);
+       int (*core_power)(struct device *dev, int on);
+
+       int (*vdec_get)(struct device *dev);
+       void (*vdec_put)(struct device *dev);
+       int (*vdec_power)(struct device *dev, int on);
+
+       int (*venc_get)(struct device *dev);
+       void (*venc_put)(struct device *dev);
+       int (*venc_power)(struct device *dev, int on);
+
+       int (*coreid_power)(struct venus_inst *inst, int on);
+
+       int (*load_scale)(struct venus_inst *inst);
+};
+
+const struct venus_pm_ops *venus_pm_get(enum hfi_version version);
+
+static inline int venus_pm_load_scale(struct venus_inst *inst)
+{
+       struct venus_core *core = inst->core;
+
+       if (!core->pm_ops || !core->pm_ops->load_scale)
+               return 0;
+
+       return core->pm_ops->load_scale(inst);
+}
+
+static inline int venus_pm_acquire_core(struct venus_inst *inst)
+{
+       struct venus_core *core = inst->core;
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
+       int ret = 0;
+
+       if (pm_ops && pm_ops->coreid_power)
+               ret = pm_ops->coreid_power(inst, POWER_ON);
+
+       return ret;
+}
+
+static inline int venus_pm_release_core(struct venus_inst *inst)
+{
+       struct venus_core *core = inst->core;
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
+       int ret = 0;
+
+       if (pm_ops && pm_ops->coreid_power)
+               ret = pm_ops->coreid_power(inst, POWER_OFF);
+
+       return ret;
+}
+
+#endif
index 8feaf5d..4ed2628 100644 (file)
@@ -20,6 +20,7 @@
 #include "core.h"
 #include "helpers.h"
 #include "vdec.h"
+#include "pm_helpers.h"
 
 /*
  * Three resons to keep MPLANE formats (despite that the number of planes
@@ -578,10 +579,6 @@ static int vdec_output_conf(struct venus_inst *inst)
        if (ret)
                return ret;
 
-       ret = venus_helper_set_core_usage(inst, VIDC_CORE_ID_1);
-       if (ret)
-               return ret;
-
        if (core->res->hfi_version == HFI_VERSION_1XX) {
                ptype = HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
                ret = hfi_session_set_property(inst, ptype, &en);
@@ -868,7 +865,7 @@ reconfigure:
        if (ret)
                goto free_dpb_bufs;
 
-       venus_helper_load_scale_clocks(inst);
+       venus_pm_load_scale(inst);
 
        ret = hfi_session_continue(inst);
        if (ret)
@@ -950,6 +947,10 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
 
        mutex_lock(&inst->lock);
 
+       ret = venus_pm_acquire_core(inst);
+       if (ret)
+               goto error;
+
        if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
                ret = vdec_start_capture(inst);
        else
@@ -1076,7 +1077,8 @@ static void vdec_session_release(struct venus_inst *inst)
                hfi_session_abort(inst);
 
        venus_helper_free_dpb_bufs(inst);
-       venus_helper_load_scale_clocks(inst);
+       venus_pm_load_scale(inst);
+       venus_pm_release_core(inst);
        INIT_LIST_HEAD(&inst->registeredbufs);
 
        mutex_unlock(&inst->lock);
@@ -1191,6 +1193,9 @@ static void vdec_event_change(struct venus_inst *inst,
        inst->out_width = ev_data->width;
        inst->out_height = ev_data->height;
 
+       if (inst->bit_depth != ev_data->bit_depth)
+               inst->bit_depth = ev_data->bit_depth;
+
        dev_dbg(dev, "event %s sufficient resources (%ux%u)\n",
                sufficient ? "" : "not", ev_data->width, ev_data->height);
 
@@ -1336,6 +1341,9 @@ static int vdec_open(struct file *file)
        inst->num_output_bufs = 1;
        inst->codec_state = VENUS_DEC_STATE_DEINIT;
        inst->buf_count = 0;
+       inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
+       inst->core_acquired = false;
+       inst->bit_depth = VIDC_BITDEPTH_8;
        init_waitqueue_head(&inst->reconf_wait);
        venus_helper_init_instance(inst);
 
@@ -1432,20 +1440,14 @@ static int vdec_probe(struct platform_device *pdev)
        if (!core)
                return -EPROBE_DEFER;
 
-       if (IS_V3(core) || IS_V4(core)) {
-               core->core0_clk = devm_clk_get(dev, "core");
-               if (IS_ERR(core->core0_clk))
-                       return PTR_ERR(core->core0_clk);
-       }
+       platform_set_drvdata(pdev, core);
 
-       if (IS_V4(core)) {
-               core->core0_bus_clk = devm_clk_get(dev, "bus");
-               if (IS_ERR(core->core0_bus_clk))
-                       return PTR_ERR(core->core0_bus_clk);
+       if (core->pm_ops->vdec_get) {
+               ret = core->pm_ops->vdec_get(dev);
+               if (ret)
+                       return ret;
        }
 
-       platform_set_drvdata(pdev, core);
-
        vdev = video_device_alloc();
        if (!vdev)
                return -ENOMEM;
@@ -1458,7 +1460,7 @@ static int vdec_probe(struct platform_device *pdev)
        vdev->v4l2_dev = &core->v4l2_dev;
        vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret)
                goto err_vdev_release;
 
@@ -1482,57 +1484,33 @@ static int vdec_remove(struct platform_device *pdev)
        video_unregister_device(core->vdev_dec);
        pm_runtime_disable(core->dev_dec);
 
+       if (core->pm_ops->vdec_put)
+               core->pm_ops->vdec_put(core->dev_dec);
+
        return 0;
 }
 
 static __maybe_unused int vdec_runtime_suspend(struct device *dev)
 {
        struct venus_core *core = dev_get_drvdata(dev);
-       int ret;
-
-       if (IS_V1(core))
-               return 0;
-
-       ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, true);
-       if (ret)
-               return ret;
-
-       if (IS_V4(core))
-               clk_disable_unprepare(core->core0_bus_clk);
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
+       int ret = 0;
 
-       clk_disable_unprepare(core->core0_clk);
+       if (pm_ops->vdec_power)
+               ret = pm_ops->vdec_power(dev, POWER_OFF);
 
-       return venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, false);
+       return ret;
 }
 
 static __maybe_unused int vdec_runtime_resume(struct device *dev)
 {
        struct venus_core *core = dev_get_drvdata(dev);
-       int ret;
-
-       if (IS_V1(core))
-               return 0;
-
-       ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, true);
-       if (ret)
-               return ret;
-
-       ret = clk_prepare_enable(core->core0_clk);
-       if (ret)
-               goto err_power_disable;
-
-       if (IS_V4(core))
-               ret = clk_prepare_enable(core->core0_bus_clk);
-
-       if (ret)
-               goto err_unprepare_core0;
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
+       int ret = 0;
 
-       return venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, false);
+       if (pm_ops->vdec_power)
+               ret = pm_ops->vdec_power(dev, POWER_ON);
 
-err_unprepare_core0:
-       clk_disable_unprepare(core->core0_clk);
-err_power_disable:
-       venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, false);
        return ret;
 }
 
index 453edf9..9981a2a 100644 (file)
@@ -20,6 +20,7 @@
 #include "core.h"
 #include "helpers.h"
 #include "venc.h"
+#include "pm_helpers.h"
 
 #define NUM_B_FRAMES_MAX       4
 
@@ -655,10 +656,6 @@ static int venc_set_properties(struct venus_inst *inst)
        if (ret)
                return ret;
 
-       ret = venus_helper_set_core_usage(inst, VIDC_CORE_ID_2);
-       if (ret)
-               return ret;
-
        ptype = HFI_PROPERTY_CONFIG_FRAME_RATE;
        frate.buffer_type = HFI_BUFFER_OUTPUT;
        frate.framerate = inst->fps * (1 << 16);
@@ -731,7 +728,9 @@ static int venc_set_properties(struct venus_inst *inst)
        if (ret)
                return ret;
 
-       if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
+       if (!ctr->rc_enable)
+               rate_control = HFI_RATE_CONTROL_OFF;
+       else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
                rate_control = HFI_RATE_CONTROL_VBR_CFR;
        else
                rate_control = HFI_RATE_CONTROL_CBR_CFR;
@@ -991,6 +990,10 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count)
        if (ret)
                goto bufs_done;
 
+       ret = venus_pm_acquire_core(inst);
+       if (ret)
+               goto deinit_sess;
+
        ret = venc_set_properties(inst);
        if (ret)
                goto deinit_sess;
@@ -1159,6 +1162,8 @@ static int venc_open(struct file *file)
 
        inst->core = core;
        inst->session_type = VIDC_SESSION_TYPE_ENC;
+       inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
+       inst->core_acquired = false;
 
        venus_helper_init_instance(inst);
 
@@ -1255,20 +1260,14 @@ static int venc_probe(struct platform_device *pdev)
        if (!core)
                return -EPROBE_DEFER;
 
-       if (IS_V3(core) || IS_V4(core)) {
-               core->core1_clk = devm_clk_get(dev, "core");
-               if (IS_ERR(core->core1_clk))
-                       return PTR_ERR(core->core1_clk);
-       }
+       platform_set_drvdata(pdev, core);
 
-       if (IS_V4(core)) {
-               core->core1_bus_clk = devm_clk_get(dev, "bus");
-               if (IS_ERR(core->core1_bus_clk))
-                       return PTR_ERR(core->core1_bus_clk);
+       if (core->pm_ops->venc_get) {
+               ret = core->pm_ops->venc_get(dev);
+               if (ret)
+                       return ret;
        }
 
-       platform_set_drvdata(pdev, core);
-
        vdev = video_device_alloc();
        if (!vdev)
                return -ENOMEM;
@@ -1281,7 +1280,7 @@ static int venc_probe(struct platform_device *pdev)
        vdev->v4l2_dev = &core->v4l2_dev;
        vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret)
                goto err_vdev_release;
 
@@ -1305,57 +1304,33 @@ static int venc_remove(struct platform_device *pdev)
        video_unregister_device(core->vdev_enc);
        pm_runtime_disable(core->dev_enc);
 
+       if (core->pm_ops->venc_put)
+               core->pm_ops->venc_put(core->dev_enc);
+
        return 0;
 }
 
 static __maybe_unused int venc_runtime_suspend(struct device *dev)
 {
        struct venus_core *core = dev_get_drvdata(dev);
-       int ret;
-
-       if (IS_V1(core))
-               return 0;
-
-       ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, true);
-       if (ret)
-               return ret;
-
-       if (IS_V4(core))
-               clk_disable_unprepare(core->core1_bus_clk);
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
+       int ret = 0;
 
-       clk_disable_unprepare(core->core1_clk);
+       if (pm_ops->venc_power)
+               ret = pm_ops->venc_power(dev, POWER_OFF);
 
-       return venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false);
+       return ret;
 }
 
 static __maybe_unused int venc_runtime_resume(struct device *dev)
 {
        struct venus_core *core = dev_get_drvdata(dev);
-       int ret;
-
-       if (IS_V1(core))
-               return 0;
-
-       ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, true);
-       if (ret)
-               return ret;
-
-       ret = clk_prepare_enable(core->core1_clk);
-       if (ret)
-               goto err_power_disable;
-
-       if (IS_V4(core))
-               ret = clk_prepare_enable(core->core1_bus_clk);
-
-       if (ret)
-               goto err_unprepare_core1;
+       const struct venus_pm_ops *pm_ops = core->pm_ops;
+       int ret = 0;
 
-       return venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false);
+       if (pm_ops->venc_power)
+               ret = pm_ops->venc_power(dev, POWER_ON);
 
-err_unprepare_core1:
-       clk_disable_unprepare(core->core1_clk);
-err_power_disable:
-       venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false);
        return ret;
 }
 
index 877c0b3..8362dde 100644 (file)
@@ -199,6 +199,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
                }
                mutex_unlock(&inst->lock);
                break;
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+               ctr->rc_enable = ctrl->val;
+               break;
        default:
                return -EINVAL;
        }
@@ -214,7 +217,7 @@ int venc_ctrl_init(struct venus_inst *inst)
 {
        int ret;
 
-       ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 30);
+       ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 31);
        if (ret)
                return ret;
 
@@ -351,6 +354,9 @@ int venc_ctrl_init(struct venus_inst *inst)
        v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
                          V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0, 0, 0, 0);
 
+       v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+                         V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1);
+
        ret = inst->ctrl_handler.error;
        if (ret)
                goto err;
index cf9029e..1a30cd0 100644 (file)
@@ -535,7 +535,7 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin)
 
        /* Set scaling coefficient */
        crop_height = vin->crop.height;
-       if (V4L2_FIELD_IS_INTERLACED(vin->format.field))
+       if (V4L2_FIELD_HAS_BOTH(vin->format.field))
                crop_height *= 2;
 
        ys = 0;
@@ -564,7 +564,7 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin)
        rvin_write(vin, 0, VNSLPOC_REG);
        rvin_write(vin, vin->format.width - 1, VNEPPOC_REG);
 
-       if (V4L2_FIELD_IS_INTERLACED(vin->format.field))
+       if (V4L2_FIELD_HAS_BOTH(vin->format.field))
                rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG);
        else
                rvin_write(vin, vin->format.height - 1, VNELPOC_REG);
@@ -626,6 +626,8 @@ static int rvin_setup(struct rvin_dev *vin)
        case V4L2_FIELD_INTERLACED_BT:
                vnmc = VNMC_IM_FULL | VNMC_FOC;
                break;
+       case V4L2_FIELD_SEQ_TB:
+       case V4L2_FIELD_SEQ_BT:
        case V4L2_FIELD_NONE:
                vnmc = VNMC_IM_ODD_EVEN;
                progressive = true;
@@ -842,27 +844,52 @@ static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot)
        struct rvin_buffer *buf;
        struct vb2_v4l2_buffer *vbuf;
        dma_addr_t phys_addr;
+       int prev;
 
        /* A already populated slot shall never be overwritten. */
-       if (WARN_ON(vin->queue_buf[slot] != NULL))
+       if (WARN_ON(vin->buf_hw[slot].buffer))
                return;
 
-       vin_dbg(vin, "Filling HW slot: %d\n", slot);
-
-       if (list_empty(&vin->buf_list)) {
-               vin->queue_buf[slot] = NULL;
+       prev = (slot == 0 ? HW_BUFFER_NUM : slot) - 1;
+
+       if (vin->buf_hw[prev].type == HALF_TOP) {
+               vbuf = vin->buf_hw[prev].buffer;
+               vin->buf_hw[slot].buffer = vbuf;
+               vin->buf_hw[slot].type = HALF_BOTTOM;
+               switch (vin->format.pixelformat) {
+               case V4L2_PIX_FMT_NV12:
+               case V4L2_PIX_FMT_NV16:
+                       phys_addr = vin->buf_hw[prev].phys +
+                               vin->format.sizeimage / 4;
+                       break;
+               default:
+                       phys_addr = vin->buf_hw[prev].phys +
+                               vin->format.sizeimage / 2;
+                       break;
+               }
+       } else if (list_empty(&vin->buf_list)) {
+               vin->buf_hw[slot].buffer = NULL;
+               vin->buf_hw[slot].type = FULL;
                phys_addr = vin->scratch_phys;
        } else {
                /* Keep track of buffer we give to HW */
                buf = list_entry(vin->buf_list.next, struct rvin_buffer, list);
                vbuf = &buf->vb;
                list_del_init(to_buf_list(vbuf));
-               vin->queue_buf[slot] = vbuf;
+               vin->buf_hw[slot].buffer = vbuf;
+
+               vin->buf_hw[slot].type =
+                       V4L2_FIELD_IS_SEQUENTIAL(vin->format.field) ?
+                       HALF_TOP : FULL;
 
                /* Setup DMA */
                phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
        }
 
+       vin_dbg(vin, "Filling HW slot: %d type: %d buffer: %p\n",
+               slot, vin->buf_hw[slot].type, vin->buf_hw[slot].buffer);
+
+       vin->buf_hw[slot].phys = phys_addr;
        rvin_set_slot_addr(vin, slot, phys_addr);
 }
 
@@ -870,6 +897,11 @@ static int rvin_capture_start(struct rvin_dev *vin)
 {
        int slot, ret;
 
+       for (slot = 0; slot < HW_BUFFER_NUM; slot++) {
+               vin->buf_hw[slot].buffer = NULL;
+               vin->buf_hw[slot].type = FULL;
+       }
+
        for (slot = 0; slot < HW_BUFFER_NUM; slot++)
                rvin_fill_hw_slot(vin, slot);
 
@@ -953,13 +985,24 @@ static irqreturn_t rvin_irq(int irq, void *data)
        }
 
        /* Capture frame */
-       if (vin->queue_buf[slot]) {
-               vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms);
-               vin->queue_buf[slot]->sequence = vin->sequence;
-               vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
-               vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf,
+       if (vin->buf_hw[slot].buffer) {
+               /*
+                * Nothing to do but refill the hardware slot if
+                * capture only filled first half of vb2 buffer.
+                */
+               if (vin->buf_hw[slot].type == HALF_TOP) {
+                       vin->buf_hw[slot].buffer = NULL;
+                       rvin_fill_hw_slot(vin, slot);
+                       goto done;
+               }
+
+               vin->buf_hw[slot].buffer->field =
+                       rvin_get_active_field(vin, vnms);
+               vin->buf_hw[slot].buffer->sequence = vin->sequence;
+               vin->buf_hw[slot].buffer->vb2_buf.timestamp = ktime_get_ns();
+               vb2_buffer_done(&vin->buf_hw[slot].buffer->vb2_buf,
                                VB2_BUF_STATE_DONE);
-               vin->queue_buf[slot] = NULL;
+               vin->buf_hw[slot].buffer = NULL;
        } else {
                /* Scratch buffer was used, dropping frame. */
                vin_dbg(vin, "Dropping frame %u\n", vin->sequence);
@@ -980,14 +1023,22 @@ static void return_all_buffers(struct rvin_dev *vin,
                               enum vb2_buffer_state state)
 {
        struct rvin_buffer *buf, *node;
-       int i;
+       struct vb2_v4l2_buffer *freed[HW_BUFFER_NUM];
+       unsigned int i, n;
 
        for (i = 0; i < HW_BUFFER_NUM; i++) {
-               if (vin->queue_buf[i]) {
-                       vb2_buffer_done(&vin->queue_buf[i]->vb2_buf,
-                                       state);
-                       vin->queue_buf[i] = NULL;
+               freed[i] = vin->buf_hw[i].buffer;
+               vin->buf_hw[i].buffer = NULL;
+
+               for (n = 0; n < i; n++) {
+                       if (freed[i] == freed[n]) {
+                               freed[i] = NULL;
+                               break;
+                       }
                }
+
+               if (freed[i])
+                       vb2_buffer_done(&freed[i]->vb2_buf, state);
        }
 
        list_for_each_entry_safe(buf, node, &vin->buf_list, list) {
@@ -1291,7 +1342,7 @@ int rvin_dma_register(struct rvin_dev *vin, int irq)
        vin->state = STOPPED;
 
        for (i = 0; i < HW_BUFFER_NUM; i++)
-               vin->queue_buf[i] = NULL;
+               vin->buf_hw[i].buffer = NULL;
 
        /* buffer queue */
        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
index 5ff565e..5151a3c 100644 (file)
@@ -73,11 +73,22 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
 {
        int i;
 
-       if (vin->info->model == RCAR_M1 && pixelformat == V4L2_PIX_FMT_XBGR32)
-               return NULL;
-
-       if (pixelformat == V4L2_PIX_FMT_NV12 && !vin->info->nv12)
-               return NULL;
+       switch (pixelformat) {
+       case V4L2_PIX_FMT_XBGR32:
+               if (vin->info->model == RCAR_M1)
+                       return NULL;
+               break;
+       case V4L2_PIX_FMT_NV12:
+               /*
+                * If NV12 is supported it's only supported on channels 0, 1, 4,
+                * 5, 8, 9, 12 and 13.
+                */
+               if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333))
+                       return NULL;
+               break;
+       default:
+               break;
+       }
 
        for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
                if (rvin_formats[i].fourcc == pixelformat)
@@ -107,6 +118,9 @@ static u32 rvin_format_bytesperline(struct rvin_dev *vin,
                break;
        }
 
+       if (V4L2_FIELD_IS_SEQUENTIAL(pix->field))
+               align = 0x80;
+
        return ALIGN(pix->width, align) * fmt->bpp;
 }
 
@@ -137,6 +151,8 @@ static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
        case V4L2_FIELD_INTERLACED_BT:
        case V4L2_FIELD_INTERLACED:
        case V4L2_FIELD_ALTERNATE:
+       case V4L2_FIELD_SEQ_TB:
+       case V4L2_FIELD_SEQ_BT:
                break;
        default:
                pix->field = RVIN_DEFAULT_FIELD;
@@ -826,7 +842,7 @@ static int rvin_open(struct file *file)
                goto err_unlock;
 
        if (vin->info->use_mc)
-               ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
+               ret = v4l2_pipeline_pm_get(&vin->vdev.entity);
        else if (v4l2_fh_is_singular_file(file))
                ret = rvin_power_parallel(vin, true);
 
@@ -842,7 +858,7 @@ static int rvin_open(struct file *file)
        return 0;
 err_power:
        if (vin->info->use_mc)
-               v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
+               v4l2_pipeline_pm_put(&vin->vdev.entity);
        else if (v4l2_fh_is_singular_file(file))
                rvin_power_parallel(vin, false);
 err_open:
@@ -870,7 +886,7 @@ static int rvin_release(struct file *file)
        ret = _vb2_fop_release(file, NULL);
 
        if (vin->info->use_mc) {
-               v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
+               v4l2_pipeline_pm_put(&vin->vdev.entity);
        } else {
                if (fh_singular)
                        rvin_power_parallel(vin, false);
@@ -953,7 +969,7 @@ int rvin_v4l2_register(struct rvin_dev *vin)
 
        rvin_format_align(vin, &vin->format);
 
-       ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                vin_err(vin, "Failed to register video device\n");
                return ret;
index a36b082..c19d077 100644 (file)
@@ -61,6 +61,23 @@ enum rvin_dma_state {
 };
 
 /**
+ * enum rvin_buffer_type
+ *
+ * Describes how a buffer is given to the hardware. To be able
+ * to capture SEQ_TB/BT it's needed to capture to the same vb2
+ * buffer twice so the type of buffer needs to be kept.
+ *
+ * FULL - One capture fills the whole vb2 buffer
+ * HALF_TOP - One capture fills the top half of the vb2 buffer
+ * HALF_BOTTOM - One capture fills the bottom half of the vb2 buffer
+ */
+enum rvin_buffer_type {
+       FULL,
+       HALF_TOP,
+       HALF_BOTTOM,
+};
+
+/**
  * struct rvin_video_format - Data format stored in memory
  * @fourcc:    Pixelformat
  * @bpp:       Bytes per pixel
@@ -164,9 +181,8 @@ struct rvin_info {
  * @scratch:           cpu address for scratch buffer
  * @scratch_phys:      physical address of the scratch buffer
  *
- * @qlock:             protects @queue_buf, @buf_list, @sequence
- *                     @state
- * @queue_buf:         Keeps track of buffers given to HW slot
+ * @qlock:             protects @buf_hw, @buf_list, @sequence and @state
+ * @buf_hw:            Keeps track of buffers given to HW slot
  * @buf_list:          list of queued buffers
  * @sequence:          V4L2 buffers sequence number
  * @state:             keeps track of operation state
@@ -205,7 +221,11 @@ struct rvin_dev {
        dma_addr_t scratch_phys;
 
        spinlock_t qlock;
-       struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM];
+       struct {
+               struct vb2_v4l2_buffer *buffer;
+               enum rvin_buffer_type type;
+               dma_addr_t phys;
+       } buf_hw[HW_BUFFER_NUM];
        struct list_head buf_list;
        unsigned int sequence;
        enum rvin_dma_state state;
index 0f267a2..3d2451a 100644 (file)
@@ -275,10 +275,14 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr)
        for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) {
                struct rcar_drif *ch = sdr->ch[i];
 
-               ch->dmach = dma_request_slave_channel(&ch->pdev->dev, "rx");
-               if (!ch->dmach) {
-                       rdrif_err(sdr, "ch%u: dma channel req failed\n", i);
-                       ret = -ENODEV;
+               ch->dmach = dma_request_chan(&ch->pdev->dev, "rx");
+               if (IS_ERR(ch->dmach)) {
+                       ret = PTR_ERR(ch->dmach);
+                       if (ret != -EPROBE_DEFER)
+                               rdrif_err(sdr,
+                                         "ch%u: dma channel req failed: %pe\n",
+                                         i, ch->dmach);
+                       ch->dmach = NULL;
                        goto dmach_error;
                }
 
index 97bed45..c9448de 100644 (file)
@@ -2344,7 +2344,7 @@ static int fdp1_probe(struct platform_device *pdev)
        video_set_drvdata(vfd, fdp1);
        strscpy(vfd->name, fdp1_videodev.name, sizeof(vfd->name));
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&fdp1->v4l2_dev, "Failed to register video device\n");
                goto release_m2m;
index 1c3f507..5250a14 100644 (file)
@@ -1663,7 +1663,7 @@ static int jpu_probe(struct platform_device *pdev)
        jpu->vfd_encoder.device_caps    = V4L2_CAP_STREAMING |
                                          V4L2_CAP_VIDEO_M2M_MPLANE;
 
-       ret = video_register_device(&jpu->vfd_encoder, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&jpu->vfd_encoder, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(&jpu->v4l2_dev, "Failed to register video device\n");
                goto m2m_init_rollback;
@@ -1682,7 +1682,7 @@ static int jpu_probe(struct platform_device *pdev)
        jpu->vfd_decoder.device_caps    = V4L2_CAP_STREAMING |
                                          V4L2_CAP_VIDEO_M2M_MPLANE;
 
-       ret = video_register_device(&jpu->vfd_decoder, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&jpu->vfd_decoder, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(&jpu->v4l2_dev, "Failed to register video device\n");
                goto enc_vdev_register_rollback;
index 197b399..f7d71a6 100644 (file)
@@ -1450,7 +1450,7 @@ static int ceu_notify_complete(struct v4l2_async_notifier *notifier)
                                  V4L2_CAP_STREAMING;
        video_set_drvdata(vdev, ceudev);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                v4l2_err(vdev->v4l2_dev,
                         "video_register_device failed: %d\n", ret);
index e9ff12b..9d12242 100644 (file)
@@ -889,7 +889,7 @@ static int rga_probe(struct platform_device *pdev)
        def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
        def_frame.size = def_frame.stride * def_frame.height;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(&rga->v4l2_dev, "Failed to register video device\n");
                goto rel_vdev;
index 2fb45db..9ca49af 100644 (file)
@@ -1158,7 +1158,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx)
        vfd->ctrl_handler = &vp->ctrl_handler;
        vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret)
                goto err_ctrlh_free;
 
index f5f05ea..6932fd4 100644 (file)
@@ -695,7 +695,7 @@ static int g2d_probe(struct platform_device *pdev)
        vfd->lock = &dev->mutex;
        vfd->v4l2_dev = &dev->v4l2_dev;
        vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
                goto rel_vdev;
index ac21622..86bda39 100644 (file)
@@ -2946,7 +2946,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
        jpeg->vfd_encoder->vfl_dir      = VFL_DIR_M2M;
        jpeg->vfd_encoder->device_caps  = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
 
-       ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
                video_device_release(jpeg->vfd_encoder);
@@ -2976,7 +2976,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
        jpeg->vfd_decoder->vfl_dir      = VFL_DIR_M2M;
        jpeg->vfd_decoder->device_caps  = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
 
-       ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
                video_device_release(jpeg->vfd_decoder);
index b776f83..5c2a23b 100644 (file)
@@ -1376,7 +1376,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
        s5p_mfc_init_regs(dev);
 
        /* Register decoder and encoder */
-       ret = video_register_device(dev->vfd_dec, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(dev->vfd_dec, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
                goto err_dec_reg;
@@ -1384,7 +1384,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
        v4l2_info(&dev->v4l2_dev,
                  "decoder registered as /dev/video%d\n", dev->vfd_dec->num);
 
-       ret = video_register_device(dev->vfd_enc, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(dev->vfd_enc, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
                goto err_enc_reg;
index 2b4c0d9..f08b8fc 100644 (file)
@@ -1160,7 +1160,7 @@ static int sh_veu_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        pm_runtime_suspend(&pdev->dev);
        if (ret < 0)
                goto evidreg;
index 2236702..36e5f2f 100644 (file)
@@ -1323,7 +1323,7 @@ static int sh_vou_probe(struct platform_device *pdev)
                goto ei2cnd;
        }
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0)
                goto evregdev;
 
index d1025a5..af2d5eb 100644 (file)
@@ -1066,7 +1066,7 @@ static int bdisp_register_device(struct bdisp_dev *bdisp)
                return PTR_ERR(bdisp->m2m.m2m_dev);
        }
 
-       ret = video_register_device(&bdisp->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&bdisp->vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(bdisp->dev,
                        "%s(): failed to register video device\n", __func__);
index 91369fb..2503224 100644 (file)
@@ -1781,7 +1781,7 @@ static int delta_register_device(struct delta_dev *delta)
        snprintf(vdev->name, sizeof(vdev->name), "%s-%s",
                 DELTA_NAME, DELTA_FW_VERSION);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(delta->dev, "%s failed to register video device\n",
                        DELTA_PREFIX);
index 64004d1..197b99d 100644 (file)
@@ -1316,7 +1316,7 @@ static int hva_register_device(struct hva_dev *hva)
        snprintf(vdev->name, sizeof(vdev->name), "%s%lx", HVA_NAME,
                 hva->ip_version);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(dev, "%s failed to register video device\n",
                        HVA_PREFIX);
index 8a86b2c..ea4b1eb 100644 (file)
@@ -291,7 +291,9 @@ static int stm32_cec_probe(struct platform_device *pdev)
 
        cec->clk_cec = devm_clk_get(&pdev->dev, "cec");
        if (IS_ERR(cec->clk_cec)) {
-               dev_err(&pdev->dev, "Cannot get cec clock\n");
+               if (PTR_ERR(cec->clk_cec) != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Cannot get cec clock\n");
+
                return PTR_ERR(cec->clk_cec);
        }
 
@@ -302,10 +304,14 @@ static int stm32_cec_probe(struct platform_device *pdev)
        }
 
        cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec");
+       if (IS_ERR(cec->clk_hdmi_cec) &&
+           PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
        if (!IS_ERR(cec->clk_hdmi_cec)) {
                ret = clk_prepare(cec->clk_hdmi_cec);
                if (ret) {
-                       dev_err(&pdev->dev, "Unable to prepare hdmi-cec clock\n");
+                       dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n");
                        return ret;
                }
        }
index 9392e34..b893149 100644 (file)
@@ -1910,10 +1910,13 @@ static int dcmi_probe(struct platform_device *pdev)
                return PTR_ERR(mclk);
        }
 
-       chan = dma_request_slave_channel(&pdev->dev, "tx");
-       if (!chan) {
-               dev_info(&pdev->dev, "Unable to request DMA channel, defer probing\n");
-               return -EPROBE_DEFER;
+       chan = dma_request_chan(&pdev->dev, "tx");
+       if (IS_ERR(chan)) {
+               ret = PTR_ERR(chan);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                               "Failed to request DMA channel: %d\n", ret);
+               return ret;
        }
 
        spin_lock_init(&dcmi->irqlock);
@@ -1971,7 +1974,7 @@ static int dcmi_probe(struct platform_device *pdev)
        }
        dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
 
-       ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(dcmi->vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(dcmi->dev, "Failed to register video device\n");
                goto err_media_entity_cleanup;
index 3878cb4..ff0993f 100644 (file)
@@ -1,3 +1,4 @@
 obj-y          += sun4i-csi/
 obj-y          += sun6i-csi/
 obj-y          += sun8i-di/
+obj-y          += sun8i-rotate/
index 83a3a02..1721e5a 100644 (file)
@@ -214,7 +214,7 @@ static int sun4i_csi_open(struct file *file)
        if (ret < 0)
                goto err_pm_put;
 
-       ret = v4l2_pipeline_pm_use(&csi->vdev.entity, 1);
+       ret = v4l2_pipeline_pm_get(&csi->vdev.entity);
        if (ret)
                goto err_pm_put;
 
@@ -227,7 +227,7 @@ static int sun4i_csi_open(struct file *file)
        return 0;
 
 err_pipeline_pm_put:
-       v4l2_pipeline_pm_use(&csi->vdev.entity, 0);
+       v4l2_pipeline_pm_put(&csi->vdev.entity);
 
 err_pm_put:
        pm_runtime_put(csi->dev);
@@ -243,7 +243,7 @@ static int sun4i_csi_release(struct file *file)
        mutex_lock(&csi->lock);
 
        v4l2_fh_release(file);
-       v4l2_pipeline_pm_use(&csi->vdev.entity, 0);
+       v4l2_pipeline_pm_put(&csi->vdev.entity);
        pm_runtime_put(csi->dev);
 
        mutex_unlock(&csi->lock);
@@ -374,7 +374,7 @@ int sun4i_csi_v4l2_register(struct sun4i_csi *csi)
        vdev->ioctl_ops = &sun4i_csi_ioctl_ops;
        video_set_drvdata(vdev, csi);
 
-       ret = video_register_device(&csi->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&csi->vdev, VFL_TYPE_VIDEO, -1);
        if (ret)
                return ret;
 
index f0dfe68..d9648b2 100644 (file)
@@ -474,7 +474,7 @@ static int sun6i_video_open(struct file *file)
        if (ret < 0)
                goto unlock;
 
-       ret = v4l2_pipeline_pm_use(&video->vdev.entity, 1);
+       ret = v4l2_pipeline_pm_get(&video->vdev.entity);
        if (ret < 0)
                goto fh_release;
 
@@ -507,7 +507,7 @@ static int sun6i_video_close(struct file *file)
 
        _vb2_fop_release(file, NULL);
 
-       v4l2_pipeline_pm_use(&video->vdev.entity, 0);
+       v4l2_pipeline_pm_put(&video->vdev.entity);
 
        if (last_fh)
                sun6i_csi_set_power(video->csi, false);
@@ -648,7 +648,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
        vdev->release           = video_device_release_empty;
        vdev->fops              = &sun6i_video_fops;
        vdev->ioctl_ops         = &sun6i_video_ioctl_ops;
-       vdev->vfl_type          = VFL_TYPE_GRABBER;
+       vdev->vfl_type          = VFL_TYPE_VIDEO;
        vdev->vfl_dir           = VFL_DIR_RX;
        vdev->v4l2_dev          = &csi->v4l2_dev;
        vdev->queue             = vidq;
@@ -656,7 +656,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
        vdev->device_caps       = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
        video_set_drvdata(vdev, video);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                v4l2_err(&csi->v4l2_dev,
                         "video_register_device failed: %d\n", ret);
index b61f3de..d78f659 100644 (file)
@@ -814,11 +814,8 @@ static int deinterlace_probe(struct platform_device *pdev)
        dev->dev = &pdev->dev;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(dev->dev, "Failed to get IRQ\n");
-
+       if (irq <= 0)
                return irq;
-       }
 
        ret = devm_request_irq(dev->dev, irq, deinterlace_irq,
                               0, dev_name(dev->dev), dev);
@@ -882,7 +879,7 @@ static int deinterlace_probe(struct platform_device *pdev)
                 deinterlace_video_device.name);
        video_set_drvdata(vfd, dev);
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
 
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/Makefile b/drivers/media/platform/sunxi/sun8i-rotate/Makefile
new file mode 100644 (file)
index 0000000..40f9cf3
--- /dev/null
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+sun8i-rotate-y += sun8i_rotate.o
+sun8i-rotate-y += sun8i_formats.o
+
+obj-$(CONFIG_VIDEO_SUN8I_ROTATE) += sun8i-rotate.o
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h
new file mode 100644 (file)
index 0000000..697cd5f
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> */
+
+#ifndef _SUN8I_FORMATS_H_
+#define _SUN8I_FORMATS_H_
+
+#include <linux/videodev2.h>
+
+#define ROTATE_FLAG_YUV    BIT(0)
+#define ROTATE_FLAG_OUTPUT BIT(1)
+
+struct rotate_format {
+       u32 fourcc;
+       u32 hw_format;
+       int planes;
+       int bpp[3];
+       int hsub;
+       int vsub;
+       unsigned int flags;
+};
+
+const struct rotate_format *rotate_find_format(u32 pixelformat);
+int rotate_enum_fmt(struct v4l2_fmtdesc *f, bool dst);
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h
new file mode 100644 (file)
index 0000000..32ade97
--- /dev/null
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Allwinner DE2 rotation driver
+ *
+ * Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#ifndef _SUN8I_ROTATE_H_
+#define _SUN8I_ROTATE_H_
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <linux/platform_device.h>
+
+#define ROTATE_NAME            "sun8i-rotate"
+
+#define ROTATE_GLB_CTL                 0x00
+#define ROTATE_GLB_CTL_START                   BIT(31)
+#define ROTATE_GLB_CTL_RESET                   BIT(30)
+#define ROTATE_GLB_CTL_BURST_LEN(x)            ((x) << 16)
+#define ROTATE_GLB_CTL_HFLIP                   BIT(7)
+#define ROTATE_GLB_CTL_VFLIP                   BIT(6)
+#define ROTATE_GLB_CTL_ROTATION(x)             ((x) << 4)
+#define ROTATE_GLB_CTL_MODE(x)                 ((x) << 0)
+
+#define ROTATE_INT                     0x04
+#define ROTATE_INT_FINISH_IRQ_EN               BIT(16)
+#define ROTATE_INT_FINISH_IRQ                  BIT(0)
+
+#define ROTATE_IN_FMT                  0x20
+#define ROTATE_IN_FMT_FORMAT(x)                        ((x) << 0)
+
+#define ROTATE_IN_SIZE                 0x24
+#define ROTATE_IN_PITCH0               0x30
+#define ROTATE_IN_PITCH1               0x34
+#define ROTATE_IN_PITCH2               0x38
+#define ROTATE_IN_ADDRL0               0x40
+#define ROTATE_IN_ADDRH0               0x44
+#define ROTATE_IN_ADDRL1               0x48
+#define ROTATE_IN_ADDRH1               0x4c
+#define ROTATE_IN_ADDRL2               0x50
+#define ROTATE_IN_ADDRH2               0x54
+#define ROTATE_OUT_SIZE                        0x84
+#define ROTATE_OUT_PITCH0              0x90
+#define ROTATE_OUT_PITCH1              0x94
+#define ROTATE_OUT_PITCH2              0x98
+#define ROTATE_OUT_ADDRL0              0xA0
+#define ROTATE_OUT_ADDRH0              0xA4
+#define ROTATE_OUT_ADDRL1              0xA8
+#define ROTATE_OUT_ADDRH1              0xAC
+#define ROTATE_OUT_ADDRL2              0xB0
+#define ROTATE_OUT_ADDRH2              0xB4
+
+#define ROTATE_BURST_8                 0x07
+#define ROTATE_BURST_16                        0x0f
+#define ROTATE_BURST_32                        0x1f
+#define ROTATE_BURST_64                        0x3f
+
+#define ROTATE_MODE_COPY_ROTATE                0x01
+
+#define ROTATE_FORMAT_ARGB32           0x00
+#define ROTATE_FORMAT_ABGR32           0x01
+#define ROTATE_FORMAT_RGBA32           0x02
+#define ROTATE_FORMAT_BGRA32           0x03
+#define ROTATE_FORMAT_XRGB32           0x04
+#define ROTATE_FORMAT_XBGR32           0x05
+#define ROTATE_FORMAT_RGBX32           0x06
+#define ROTATE_FORMAT_BGRX32           0x07
+#define ROTATE_FORMAT_RGB24            0x08
+#define ROTATE_FORMAT_BGR24            0x09
+#define ROTATE_FORMAT_RGB565           0x0a
+#define ROTATE_FORMAT_BGR565           0x0b
+#define ROTATE_FORMAT_ARGB4444         0x0c
+#define ROTATE_FORMAT_ABGR4444         0x0d
+#define ROTATE_FORMAT_RGBA4444         0x0e
+#define ROTATE_FORMAT_BGRA4444         0x0f
+#define ROTATE_FORMAT_ARGB1555         0x10
+#define ROTATE_FORMAT_ABGR1555         0x11
+#define ROTATE_FORMAT_RGBA5551         0x12
+#define ROTATE_FORMAT_BGRA5551         0x13
+
+#define ROTATE_FORMAT_YUYV             0x20
+#define ROTATE_FORMAT_UYVY             0x21
+#define ROTATE_FORMAT_YVYU             0x22
+#define ROTATE_FORMAT_VYUV             0x23
+#define ROTATE_FORMAT_NV61             0x24
+#define ROTATE_FORMAT_NV16             0x25
+#define ROTATE_FORMAT_YUV422P          0x26
+#define ROTATE_FORMAT_NV21             0x28
+#define ROTATE_FORMAT_NV12             0x29
+#define ROTATE_FORMAT_YUV420P          0x2A
+
+#define ROTATE_SIZE(w, h)      (((h) - 1) << 16 | ((w) - 1))
+
+#define ROTATE_MIN_WIDTH       8U
+#define ROTATE_MIN_HEIGHT      8U
+#define ROTATE_MAX_WIDTH       4096U
+#define ROTATE_MAX_HEIGHT      4096U
+
+struct rotate_ctx {
+       struct v4l2_fh          fh;
+       struct rotate_dev       *dev;
+
+       struct v4l2_pix_format  src_fmt;
+       struct v4l2_pix_format  dst_fmt;
+
+       struct v4l2_ctrl_handler ctrl_handler;
+
+       u32 hflip;
+       u32 vflip;
+       u32 rotate;
+};
+
+struct rotate_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     vfd;
+       struct device           *dev;
+       struct v4l2_m2m_dev     *m2m_dev;
+
+       /* Device file mutex */
+       struct mutex            dev_mutex;
+
+       void __iomem            *base;
+
+       struct clk              *bus_clk;
+       struct clk              *mod_clk;
+
+       struct reset_control    *rstc;
+};
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_formats.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_formats.c
new file mode 100644 (file)
index 0000000..cebfbc5
--- /dev/null
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> */
+
+#include "sun8i-formats.h"
+#include "sun8i-rotate.h"
+
+/*
+ * Formats not included in array:
+ * ROTATE_FORMAT_BGR565
+ * ROTATE_FORMAT_VYUV
+ */
+
+static const struct rotate_format rotate_formats[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_ARGB32,
+               .hw_format = ROTATE_FORMAT_ARGB32,
+               .planes = 1,
+               .bpp = { 4, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_ABGR32,
+               .hw_format = ROTATE_FORMAT_ABGR32,
+               .planes = 1,
+               .bpp = { 4, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGBA32,
+               .hw_format = ROTATE_FORMAT_RGBA32,
+               .planes = 1,
+               .bpp = { 4, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_BGRA32,
+               .hw_format = ROTATE_FORMAT_BGRA32,
+               .planes = 1,
+               .bpp = { 4, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_XRGB32,
+               .hw_format = ROTATE_FORMAT_XRGB32,
+               .planes = 1,
+               .bpp = { 4, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_XBGR32,
+               .hw_format = ROTATE_FORMAT_XBGR32,
+               .planes = 1,
+               .bpp = { 4, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGB32,
+               .hw_format = ROTATE_FORMAT_RGBX32,
+               .planes = 1,
+               .bpp = { 4, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_BGR32,
+               .hw_format = ROTATE_FORMAT_BGRX32,
+               .planes = 1,
+               .bpp = { 4, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGB24,
+               .hw_format = ROTATE_FORMAT_RGB24,
+               .planes = 1,
+               .bpp = { 3, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_BGR24,
+               .hw_format = ROTATE_FORMAT_BGR24,
+               .planes = 1,
+               .bpp = { 3, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGB565,
+               .hw_format = ROTATE_FORMAT_RGB565,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_ARGB444,
+               .hw_format = ROTATE_FORMAT_ARGB4444,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_ABGR444,
+               .hw_format = ROTATE_FORMAT_ABGR4444,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGBA444,
+               .hw_format = ROTATE_FORMAT_RGBA4444,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_BGRA444,
+               .hw_format = ROTATE_FORMAT_BGRA4444,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_ARGB555,
+               .hw_format = ROTATE_FORMAT_ARGB1555,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_ABGR555,
+               .hw_format = ROTATE_FORMAT_ABGR1555,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_RGBA555,
+               .hw_format = ROTATE_FORMAT_RGBA5551,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_BGRA555,
+               .hw_format = ROTATE_FORMAT_BGRA5551,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 1,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_OUTPUT
+       }, {
+               .fourcc = V4L2_PIX_FMT_YVYU,
+               .hw_format = ROTATE_FORMAT_YVYU,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 2,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_YUV
+       }, {
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .hw_format = ROTATE_FORMAT_UYVY,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 2,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_YUV
+       }, {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .hw_format = ROTATE_FORMAT_YUYV,
+               .planes = 1,
+               .bpp = { 2, 0, 0 },
+               .hsub = 2,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_YUV
+       }, {
+               .fourcc = V4L2_PIX_FMT_NV61,
+               .hw_format = ROTATE_FORMAT_NV61,
+               .planes = 2,
+               .bpp = { 1, 2, 0 },
+               .hsub = 2,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_YUV
+       }, {
+               .fourcc = V4L2_PIX_FMT_NV16,
+               .hw_format = ROTATE_FORMAT_NV16,
+               .planes = 2,
+               .bpp = { 1, 2, 0 },
+               .hsub = 2,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_YUV
+       }, {
+               .fourcc = V4L2_PIX_FMT_YUV422P,
+               .hw_format = ROTATE_FORMAT_YUV422P,
+               .planes = 3,
+               .bpp = { 1, 1, 1 },
+               .hsub = 2,
+               .vsub = 1,
+               .flags = ROTATE_FLAG_YUV
+       }, {
+               .fourcc = V4L2_PIX_FMT_NV21,
+               .hw_format = ROTATE_FORMAT_NV21,
+               .planes = 2,
+               .bpp = { 1, 2, 0 },
+               .hsub = 2,
+               .vsub = 2,
+               .flags = ROTATE_FLAG_YUV
+       }, {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .hw_format = ROTATE_FORMAT_NV12,
+               .planes = 2,
+               .bpp = { 1, 2, 0 },
+               .hsub = 2,
+               .vsub = 2,
+               .flags = ROTATE_FLAG_YUV
+       }, {
+               .fourcc = V4L2_PIX_FMT_YUV420,
+               .hw_format = ROTATE_FORMAT_YUV420P,
+               .planes = 3,
+               .bpp = { 1, 1, 1 },
+               .hsub = 2,
+               .vsub = 2,
+               .flags = ROTATE_FLAG_YUV | ROTATE_FLAG_OUTPUT
+       },
+};
+
+const struct rotate_format *rotate_find_format(u32 pixelformat)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(rotate_formats); i++)
+               if (rotate_formats[i].fourcc == pixelformat)
+                       return &rotate_formats[i];
+
+       return NULL;
+}
+
+int rotate_enum_fmt(struct v4l2_fmtdesc *f, bool dst)
+{
+       int i, index;
+
+       index = 0;
+
+       for (i = 0; i < ARRAY_SIZE(rotate_formats); i++) {
+               /* not all formats can be used for capture buffers */
+               if (dst && !(rotate_formats[i].flags & ROTATE_FLAG_OUTPUT))
+                       continue;
+
+               if (index == f->index) {
+                       f->pixelformat = rotate_formats[i].fourcc;
+
+                       return 0;
+               }
+
+               index++;
+       }
+
+       return -EINVAL;
+}
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
new file mode 100644 (file)
index 0000000..94f505d
--- /dev/null
@@ -0,0 +1,924 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner sun8i DE2 rotation driver
+ *
+ * Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "sun8i-formats.h"
+#include "sun8i-rotate.h"
+
+static inline u32 rotate_read(struct rotate_dev *dev, u32 reg)
+{
+       return readl(dev->base + reg);
+}
+
+static inline void rotate_write(struct rotate_dev *dev, u32 reg, u32 value)
+{
+       writel(value, dev->base + reg);
+}
+
+static inline void rotate_set_bits(struct rotate_dev *dev, u32 reg, u32 bits)
+{
+       writel(readl(dev->base + reg) | bits, dev->base + reg);
+}
+
+static void rotate_calc_addr_pitch(dma_addr_t buffer,
+                                  u32 bytesperline, u32 height,
+                                  const struct rotate_format *fmt,
+                                  dma_addr_t *addr, u32 *pitch)
+{
+       u32 size;
+       int i;
+
+       for (i = 0; i < fmt->planes; i++) {
+               pitch[i] = bytesperline;
+               addr[i] = buffer;
+               if (i > 0)
+                       pitch[i] /= fmt->hsub / fmt->bpp[i];
+               size = pitch[i] * height;
+               if (i > 0)
+                       size /= fmt->vsub;
+               buffer += size;
+       }
+}
+
+static void rotate_device_run(void *priv)
+{
+       struct rotate_ctx *ctx = priv;
+       struct rotate_dev *dev = ctx->dev;
+       struct vb2_v4l2_buffer *src, *dst;
+       const struct rotate_format *fmt;
+       dma_addr_t addr[3];
+       u32 val, pitch[3];
+
+       src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+       v4l2_m2m_buf_copy_metadata(src, dst, true);
+
+       val = ROTATE_GLB_CTL_MODE(ROTATE_MODE_COPY_ROTATE);
+       if (ctx->hflip)
+               val |= ROTATE_GLB_CTL_HFLIP;
+       if (ctx->vflip)
+               val |= ROTATE_GLB_CTL_VFLIP;
+       val |= ROTATE_GLB_CTL_ROTATION(ctx->rotate / 90);
+       if (ctx->rotate != 90 && ctx->rotate != 270)
+               val |= ROTATE_GLB_CTL_BURST_LEN(ROTATE_BURST_64);
+       else
+               val |= ROTATE_GLB_CTL_BURST_LEN(ROTATE_BURST_8);
+       rotate_write(dev, ROTATE_GLB_CTL, val);
+
+       fmt = rotate_find_format(ctx->src_fmt.pixelformat);
+       if (!fmt)
+               return;
+
+       rotate_write(dev, ROTATE_IN_FMT, ROTATE_IN_FMT_FORMAT(fmt->hw_format));
+
+       rotate_calc_addr_pitch(vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0),
+                              ctx->src_fmt.bytesperline, ctx->src_fmt.height,
+                              fmt, addr, pitch);
+
+       rotate_write(dev, ROTATE_IN_SIZE,
+                    ROTATE_SIZE(ctx->src_fmt.width, ctx->src_fmt.height));
+
+       rotate_write(dev, ROTATE_IN_PITCH0, pitch[0]);
+       rotate_write(dev, ROTATE_IN_PITCH1, pitch[1]);
+       rotate_write(dev, ROTATE_IN_PITCH2, pitch[2]);
+
+       rotate_write(dev, ROTATE_IN_ADDRL0, addr[0]);
+       rotate_write(dev, ROTATE_IN_ADDRL1, addr[1]);
+       rotate_write(dev, ROTATE_IN_ADDRL2, addr[2]);
+
+       rotate_write(dev, ROTATE_IN_ADDRH0, 0);
+       rotate_write(dev, ROTATE_IN_ADDRH1, 0);
+       rotate_write(dev, ROTATE_IN_ADDRH2, 0);
+
+       fmt = rotate_find_format(ctx->dst_fmt.pixelformat);
+       if (!fmt)
+               return;
+
+       rotate_calc_addr_pitch(vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0),
+                              ctx->dst_fmt.bytesperline, ctx->dst_fmt.height,
+                              fmt, addr, pitch);
+
+       rotate_write(dev, ROTATE_OUT_SIZE,
+                    ROTATE_SIZE(ctx->dst_fmt.width, ctx->dst_fmt.height));
+
+       rotate_write(dev, ROTATE_OUT_PITCH0, pitch[0]);
+       rotate_write(dev, ROTATE_OUT_PITCH1, pitch[1]);
+       rotate_write(dev, ROTATE_OUT_PITCH2, pitch[2]);
+
+       rotate_write(dev, ROTATE_OUT_ADDRL0, addr[0]);
+       rotate_write(dev, ROTATE_OUT_ADDRL1, addr[1]);
+       rotate_write(dev, ROTATE_OUT_ADDRL2, addr[2]);
+
+       rotate_write(dev, ROTATE_OUT_ADDRH0, 0);
+       rotate_write(dev, ROTATE_OUT_ADDRH1, 0);
+       rotate_write(dev, ROTATE_OUT_ADDRH2, 0);
+
+       rotate_set_bits(dev, ROTATE_INT, ROTATE_INT_FINISH_IRQ_EN);
+       rotate_set_bits(dev, ROTATE_GLB_CTL, ROTATE_GLB_CTL_START);
+}
+
+static irqreturn_t rotate_irq(int irq, void *data)
+{
+       struct vb2_v4l2_buffer *buffer;
+       struct rotate_dev *dev = data;
+       struct rotate_ctx *ctx;
+       unsigned int val;
+
+       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+       if (!ctx) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Instance released before the end of transaction\n");
+               return IRQ_NONE;
+       }
+
+       val = rotate_read(dev, ROTATE_INT);
+       if (!(val & ROTATE_INT_FINISH_IRQ))
+               return IRQ_NONE;
+
+       /* clear flag and disable irq */
+       rotate_write(dev, ROTATE_INT, ROTATE_INT_FINISH_IRQ);
+
+       buffer = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_DONE);
+
+       buffer = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_DONE);
+
+       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+
+       return IRQ_HANDLED;
+}
+
+static inline struct rotate_ctx *rotate_file2ctx(struct file *file)
+{
+       return container_of(file->private_data, struct rotate_ctx, fh);
+}
+
+static void rotate_prepare_format(struct v4l2_pix_format *pix_fmt)
+{
+       unsigned int height, width, alignment, sizeimage, size, bpl;
+       const struct rotate_format *fmt;
+       int i;
+
+       fmt = rotate_find_format(pix_fmt->pixelformat);
+       if (!fmt)
+               return;
+
+       width = ALIGN(pix_fmt->width, fmt->hsub);
+       height = ALIGN(pix_fmt->height, fmt->vsub);
+
+       /* all pitches have to be 16 byte aligned */
+       alignment = 16;
+       if (fmt->planes > 1)
+               alignment *= fmt->hsub / fmt->bpp[1];
+       bpl = ALIGN(width * fmt->bpp[0], alignment);
+
+       sizeimage = 0;
+       for (i = 0; i < fmt->planes; i++) {
+               size = bpl * height;
+               if (i > 0) {
+                       size *= fmt->bpp[i];
+                       size /= fmt->hsub;
+                       size /= fmt->vsub;
+               }
+               sizeimage += size;
+       }
+
+       pix_fmt->width = width;
+       pix_fmt->height = height;
+       pix_fmt->bytesperline = bpl;
+       pix_fmt->sizeimage = sizeimage;
+}
+
+static int rotate_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       strscpy(cap->driver, ROTATE_NAME, sizeof(cap->driver));
+       strscpy(cap->card, ROTATE_NAME, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info),
+                "platform:%s", ROTATE_NAME);
+
+       return 0;
+}
+
+static int rotate_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return rotate_enum_fmt(f, true);
+}
+
+static int rotate_enum_fmt_vid_out(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return rotate_enum_fmt(f, false);
+}
+
+static int rotate_enum_framesizes(struct file *file, void *priv,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       const struct rotate_format *fmt;
+
+       if (fsize->index != 0)
+               return -EINVAL;
+
+       fmt = rotate_find_format(fsize->pixel_format);
+       if (!fmt)
+               return -EINVAL;
+
+       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       fsize->stepwise.min_width = ROTATE_MIN_WIDTH;
+       fsize->stepwise.min_height = ROTATE_MIN_HEIGHT;
+       fsize->stepwise.max_width = ROTATE_MAX_WIDTH;
+       fsize->stepwise.max_height = ROTATE_MAX_HEIGHT;
+       fsize->stepwise.step_width = fmt->hsub;
+       fsize->stepwise.step_height = fmt->vsub;
+
+       return 0;
+}
+
+static int rotate_set_cap_format(struct rotate_ctx *ctx,
+                                struct v4l2_pix_format *f,
+                                u32 rotate)
+{
+       const struct rotate_format *fmt;
+
+       fmt = rotate_find_format(ctx->src_fmt.pixelformat);
+       if (!fmt)
+               return -EINVAL;
+
+       if (fmt->flags & ROTATE_FLAG_YUV)
+               f->pixelformat = V4L2_PIX_FMT_YUV420;
+       else
+               f->pixelformat = ctx->src_fmt.pixelformat;
+
+       f->field = V4L2_FIELD_NONE;
+
+       if (rotate == 90 || rotate == 270) {
+               f->width = ctx->src_fmt.height;
+               f->height = ctx->src_fmt.width;
+       } else {
+               f->width = ctx->src_fmt.width;
+               f->height = ctx->src_fmt.height;
+       }
+
+       rotate_prepare_format(f);
+
+       return 0;
+}
+
+static int rotate_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct rotate_ctx *ctx = rotate_file2ctx(file);
+
+       f->fmt.pix = ctx->dst_fmt;
+
+       return 0;
+}
+
+static int rotate_g_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct rotate_ctx *ctx = rotate_file2ctx(file);
+
+       f->fmt.pix = ctx->src_fmt;
+
+       return 0;
+}
+
+static int rotate_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct rotate_ctx *ctx = rotate_file2ctx(file);
+
+       return rotate_set_cap_format(ctx, &f->fmt.pix, ctx->rotate);
+}
+
+static int rotate_try_fmt_vid_out(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       if (!rotate_find_format(f->fmt.pix.pixelformat))
+               f->fmt.pix.pixelformat = V4L2_PIX_FMT_ARGB32;
+
+       if (f->fmt.pix.width < ROTATE_MIN_WIDTH)
+               f->fmt.pix.width = ROTATE_MIN_WIDTH;
+       if (f->fmt.pix.height < ROTATE_MIN_HEIGHT)
+               f->fmt.pix.height = ROTATE_MIN_HEIGHT;
+
+       if (f->fmt.pix.width > ROTATE_MAX_WIDTH)
+               f->fmt.pix.width = ROTATE_MAX_WIDTH;
+       if (f->fmt.pix.height > ROTATE_MAX_HEIGHT)
+               f->fmt.pix.height = ROTATE_MAX_HEIGHT;
+
+       f->fmt.pix.field = V4L2_FIELD_NONE;
+
+       rotate_prepare_format(&f->fmt.pix);
+
+       return 0;
+}
+
+static int rotate_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct rotate_ctx *ctx = rotate_file2ctx(file);
+       struct vb2_queue *vq;
+       int ret;
+
+       ret = rotate_try_fmt_vid_cap(file, priv, f);
+       if (ret)
+               return ret;
+
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (vb2_is_busy(vq))
+               return -EBUSY;
+
+       ctx->dst_fmt = f->fmt.pix;
+
+       return 0;
+}
+
+static int rotate_s_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct rotate_ctx *ctx = rotate_file2ctx(file);
+       struct vb2_queue *vq;
+       int ret;
+
+       ret = rotate_try_fmt_vid_out(file, priv, f);
+       if (ret)
+               return ret;
+
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+       if (vb2_is_busy(vq))
+               return -EBUSY;
+
+       /*
+        * Capture queue has to be also checked, because format and size
+        * depends on output format and size.
+        */
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       if (vb2_is_busy(vq))
+               return -EBUSY;
+
+       ctx->src_fmt = f->fmt.pix;
+
+       /* Propagate colorspace information to capture. */
+       ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
+       ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
+       ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
+       ctx->dst_fmt.quantization = f->fmt.pix.quantization;
+
+       return rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate);
+}
+
+static const struct v4l2_ioctl_ops rotate_ioctl_ops = {
+       .vidioc_querycap                = rotate_querycap,
+
+       .vidioc_enum_framesizes         = rotate_enum_framesizes,
+
+       .vidioc_enum_fmt_vid_cap        = rotate_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap           = rotate_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = rotate_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = rotate_s_fmt_vid_cap,
+
+       .vidioc_enum_fmt_vid_out        = rotate_enum_fmt_vid_out,
+       .vidioc_g_fmt_vid_out           = rotate_g_fmt_vid_out,
+       .vidioc_try_fmt_vid_out         = rotate_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out           = rotate_s_fmt_vid_out,
+
+       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
+       .vidioc_qbuf                    = v4l2_m2m_ioctl_qbuf,
+       .vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
+       .vidioc_prepare_buf             = v4l2_m2m_ioctl_prepare_buf,
+       .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
+       .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
+
+       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
+
+       .vidioc_log_status              = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
+};
+
+static int rotate_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+                             unsigned int *nplanes, unsigned int sizes[],
+                             struct device *alloc_devs[])
+{
+       struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+       struct v4l2_pix_format *pix_fmt;
+
+       if (V4L2_TYPE_IS_OUTPUT(vq->type))
+               pix_fmt = &ctx->src_fmt;
+       else
+               pix_fmt = &ctx->dst_fmt;
+
+       if (*nplanes) {
+               if (sizes[0] < pix_fmt->sizeimage)
+                       return -EINVAL;
+       } else {
+               sizes[0] = pix_fmt->sizeimage;
+               *nplanes = 1;
+       }
+
+       return 0;
+}
+
+static int rotate_buf_prepare(struct vb2_buffer *vb)
+{
+       struct vb2_queue *vq = vb->vb2_queue;
+       struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+       struct v4l2_pix_format *pix_fmt;
+
+       if (V4L2_TYPE_IS_OUTPUT(vq->type))
+               pix_fmt = &ctx->src_fmt;
+       else
+               pix_fmt = &ctx->dst_fmt;
+
+       if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
+               return -EINVAL;
+
+       vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
+
+       return 0;
+}
+
+static void rotate_buf_queue(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+       struct rotate_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static void rotate_queue_cleanup(struct vb2_queue *vq, u32 state)
+{
+       struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+       struct vb2_v4l2_buffer *vbuf;
+
+       do {
+               if (V4L2_TYPE_IS_OUTPUT(vq->type))
+                       vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+               else
+                       vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+               if (vbuf)
+                       v4l2_m2m_buf_done(vbuf, state);
+       } while (vbuf);
+}
+
+static int rotate_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+               struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+               struct device *dev = ctx->dev->dev;
+               int ret;
+
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0) {
+                       dev_err(dev, "Failed to enable module\n");
+
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void rotate_stop_streaming(struct vb2_queue *vq)
+{
+       if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+               struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+
+               pm_runtime_put(ctx->dev->dev);
+       }
+
+       rotate_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops rotate_qops = {
+       .queue_setup            = rotate_queue_setup,
+       .buf_prepare            = rotate_buf_prepare,
+       .buf_queue              = rotate_buf_queue,
+       .start_streaming        = rotate_start_streaming,
+       .stop_streaming         = rotate_stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+static int rotate_queue_init(void *priv, struct vb2_queue *src_vq,
+                            struct vb2_queue *dst_vq)
+{
+       struct rotate_ctx *ctx = priv;
+       int ret;
+
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+       src_vq->drv_priv = ctx;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       src_vq->min_buffers_needed = 1;
+       src_vq->ops = &rotate_qops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock = &ctx->dev->dev_mutex;
+       src_vq->dev = ctx->dev->dev;
+
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+       dst_vq->drv_priv = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->min_buffers_needed = 2;
+       dst_vq->ops = &rotate_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock = &ctx->dev->dev_mutex;
+       dst_vq->dev = ctx->dev->dev;
+
+       ret = vb2_queue_init(dst_vq);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int rotate_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct rotate_ctx *ctx = container_of(ctrl->handler,
+                                             struct rotate_ctx,
+                                             ctrl_handler);
+       struct v4l2_pix_format fmt;
+
+       switch (ctrl->id) {
+       case V4L2_CID_HFLIP:
+               ctx->hflip = ctrl->val;
+               break;
+       case V4L2_CID_VFLIP:
+               ctx->vflip = ctrl->val;
+               break;
+       case V4L2_CID_ROTATE:
+               rotate_set_cap_format(ctx, &fmt, ctrl->val);
+
+               /* Check if capture format needs to be changed */
+               if (fmt.width != ctx->dst_fmt.width ||
+                   fmt.height != ctx->dst_fmt.height ||
+                   fmt.bytesperline != ctx->dst_fmt.bytesperline ||
+                   fmt.sizeimage != ctx->dst_fmt.sizeimage) {
+                       struct vb2_queue *vq;
+
+                       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+                                            V4L2_BUF_TYPE_VIDEO_CAPTURE);
+                       if (vb2_is_busy(vq))
+                               return -EBUSY;
+
+                       rotate_set_cap_format(ctx, &ctx->dst_fmt, ctrl->val);
+               }
+
+               ctx->rotate = ctrl->val;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops rotate_ctrl_ops = {
+       .s_ctrl = rotate_s_ctrl,
+};
+
+static int rotate_setup_ctrls(struct rotate_ctx *ctx)
+{
+       v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+       v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops,
+                         V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+       v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops,
+                         V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+       v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops,
+                         V4L2_CID_ROTATE, 0, 270, 90, 0);
+
+       if (ctx->ctrl_handler.error) {
+               int err = ctx->ctrl_handler.error;
+
+               v4l2_err(&ctx->dev->v4l2_dev, "control setup failed!\n");
+               v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+
+               return err;
+       }
+
+       return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+}
+
+static int rotate_open(struct file *file)
+{
+       struct rotate_dev *dev = video_drvdata(file);
+       struct rotate_ctx *ctx = NULL;
+       int ret;
+
+       if (mutex_lock_interruptible(&dev->dev_mutex))
+               return -ERESTARTSYS;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               mutex_unlock(&dev->dev_mutex);
+               return -ENOMEM;
+       }
+
+       /* default output format */
+       ctx->src_fmt.pixelformat = V4L2_PIX_FMT_ARGB32;
+       ctx->src_fmt.field = V4L2_FIELD_NONE;
+       ctx->src_fmt.width = 640;
+       ctx->src_fmt.height = 480;
+       rotate_prepare_format(&ctx->src_fmt);
+
+       /* default capture format */
+       rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate);
+
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       ctx->dev = dev;
+
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+                                           &rotate_queue_init);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
+               goto err_free;
+       }
+
+       v4l2_fh_add(&ctx->fh);
+
+       ret = rotate_setup_ctrls(ctx);
+       if (ret)
+               goto err_free;
+
+       ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+       mutex_unlock(&dev->dev_mutex);
+
+       return 0;
+
+err_free:
+       kfree(ctx);
+       mutex_unlock(&dev->dev_mutex);
+
+       return ret;
+}
+
+static int rotate_release(struct file *file)
+{
+       struct rotate_dev *dev = video_drvdata(file);
+       struct rotate_ctx *ctx = container_of(file->private_data,
+                                                  struct rotate_ctx, fh);
+
+       mutex_lock(&dev->dev_mutex);
+
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+       kfree(ctx);
+
+       mutex_unlock(&dev->dev_mutex);
+
+       return 0;
+}
+
+static const struct v4l2_file_operations rotate_fops = {
+       .owner          = THIS_MODULE,
+       .open           = rotate_open,
+       .release        = rotate_release,
+       .poll           = v4l2_m2m_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = v4l2_m2m_fop_mmap,
+};
+
+static const struct video_device rotate_video_device = {
+       .name           = ROTATE_NAME,
+       .vfl_dir        = VFL_DIR_M2M,
+       .fops           = &rotate_fops,
+       .ioctl_ops      = &rotate_ioctl_ops,
+       .minor          = -1,
+       .release        = video_device_release_empty,
+       .device_caps    = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static const struct v4l2_m2m_ops rotate_m2m_ops = {
+       .device_run     = rotate_device_run,
+};
+
+static int rotate_probe(struct platform_device *pdev)
+{
+       struct rotate_dev *dev;
+       struct video_device *vfd;
+       int irq, ret;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->vfd = rotate_video_device;
+       dev->dev = &pdev->dev;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq <= 0) {
+               dev_err(dev->dev, "Failed to get IRQ\n");
+
+               return irq;
+       }
+
+       ret = devm_request_irq(dev->dev, irq, rotate_irq,
+                              0, dev_name(dev->dev), dev);
+       if (ret) {
+               dev_err(dev->dev, "Failed to request IRQ\n");
+
+               return ret;
+       }
+
+       dev->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(dev->base))
+               return PTR_ERR(dev->base);
+
+       dev->bus_clk = devm_clk_get(dev->dev, "bus");
+       if (IS_ERR(dev->bus_clk)) {
+               dev_err(dev->dev, "Failed to get bus clock\n");
+
+               return PTR_ERR(dev->bus_clk);
+       }
+
+       dev->mod_clk = devm_clk_get(dev->dev, "mod");
+       if (IS_ERR(dev->mod_clk)) {
+               dev_err(dev->dev, "Failed to get mod clock\n");
+
+               return PTR_ERR(dev->mod_clk);
+       }
+
+       dev->rstc = devm_reset_control_get(dev->dev, NULL);
+       if (IS_ERR(dev->rstc)) {
+               dev_err(dev->dev, "Failed to get reset control\n");
+
+               return PTR_ERR(dev->rstc);
+       }
+
+       mutex_init(&dev->dev_mutex);
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret) {
+               dev_err(dev->dev, "Failed to register V4L2 device\n");
+
+               return ret;
+       }
+
+       vfd = &dev->vfd;
+       vfd->lock = &dev->dev_mutex;
+       vfd->v4l2_dev = &dev->v4l2_dev;
+
+       snprintf(vfd->name, sizeof(vfd->name), "%s",
+                rotate_video_device.name);
+       video_set_drvdata(vfd, dev);
+
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+
+               goto err_v4l2;
+       }
+
+       v4l2_info(&dev->v4l2_dev,
+                 "Device registered as /dev/video%d\n", vfd->num);
+
+       dev->m2m_dev = v4l2_m2m_init(&rotate_m2m_ops);
+       if (IS_ERR(dev->m2m_dev)) {
+               v4l2_err(&dev->v4l2_dev,
+                        "Failed to initialize V4L2 M2M device\n");
+               ret = PTR_ERR(dev->m2m_dev);
+
+               goto err_video;
+       }
+
+       platform_set_drvdata(pdev, dev);
+
+       pm_runtime_enable(dev->dev);
+
+       return 0;
+
+err_video:
+       video_unregister_device(&dev->vfd);
+err_v4l2:
+       v4l2_device_unregister(&dev->v4l2_dev);
+
+       return ret;
+}
+
+static int rotate_remove(struct platform_device *pdev)
+{
+       struct rotate_dev *dev = platform_get_drvdata(pdev);
+
+       v4l2_m2m_release(dev->m2m_dev);
+       video_unregister_device(&dev->vfd);
+       v4l2_device_unregister(&dev->v4l2_dev);
+
+       pm_runtime_force_suspend(&pdev->dev);
+
+       return 0;
+}
+
+static int rotate_runtime_resume(struct device *device)
+{
+       struct rotate_dev *dev = dev_get_drvdata(device);
+       int ret;
+
+       ret = clk_prepare_enable(dev->bus_clk);
+       if (ret) {
+               dev_err(dev->dev, "Failed to enable bus clock\n");
+
+               return ret;
+       }
+
+       ret = clk_prepare_enable(dev->mod_clk);
+       if (ret) {
+               dev_err(dev->dev, "Failed to enable mod clock\n");
+
+               goto err_bus_clk;
+       }
+
+       ret = reset_control_deassert(dev->rstc);
+       if (ret) {
+               dev_err(dev->dev, "Failed to apply reset\n");
+
+               goto err_mod_clk;
+       }
+
+       return 0;
+
+err_mod_clk:
+       clk_disable_unprepare(dev->mod_clk);
+err_bus_clk:
+       clk_disable_unprepare(dev->bus_clk);
+
+       return ret;
+}
+
+static int rotate_runtime_suspend(struct device *device)
+{
+       struct rotate_dev *dev = dev_get_drvdata(device);
+
+       reset_control_assert(dev->rstc);
+
+       clk_disable_unprepare(dev->mod_clk);
+       clk_disable_unprepare(dev->bus_clk);
+
+       return 0;
+}
+
+static const struct of_device_id rotate_dt_match[] = {
+       { .compatible = "allwinner,sun8i-a83t-de2-rotate" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rotate_dt_match);
+
+static const struct dev_pm_ops rotate_pm_ops = {
+       .runtime_resume         = rotate_runtime_resume,
+       .runtime_suspend        = rotate_runtime_suspend,
+};
+
+static struct platform_driver rotate_driver = {
+       .probe          = rotate_probe,
+       .remove         = rotate_remove,
+       .driver         = {
+               .name           = ROTATE_NAME,
+               .of_match_table = rotate_dt_match,
+               .pm             = &rotate_pm_ops,
+       },
+};
+module_platform_driver(rotate_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("Allwinner DE2 rotate driver");
index be54806..6c8f370 100644 (file)
@@ -372,8 +372,6 @@ struct cal_ctx {
        struct v4l2_subdev      *sensor;
        struct v4l2_fwnode_endpoint     endpoint;
 
-       struct v4l2_async_subdev asd;
-
        struct v4l2_fh          fh;
        struct cal_dev          *dev;
        struct cc_data          *cc;
@@ -722,16 +720,16 @@ static void enable_irqs(struct cal_ctx *ctx)
 
 static void disable_irqs(struct cal_ctx *ctx)
 {
+       u32 val;
+
        /* Disable IRQ_WDMA_END 0/1 */
-       reg_write_field(ctx->dev,
-                       CAL_HL_IRQENABLE_CLR(2),
-                       CAL_HL_IRQ_CLEAR,
-                       CAL_HL_IRQ_MASK(ctx->csi2_port));
+       val = 0;
+       set_field(&val, CAL_HL_IRQ_CLEAR, CAL_HL_IRQ_MASK(ctx->csi2_port));
+       reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(2), val);
        /* Disable IRQ_WDMA_START 0/1 */
-       reg_write_field(ctx->dev,
-                       CAL_HL_IRQENABLE_CLR(3),
-                       CAL_HL_IRQ_CLEAR,
-                       CAL_HL_IRQ_MASK(ctx->csi2_port));
+       val = 0;
+       set_field(&val, CAL_HL_IRQ_CLEAR, CAL_HL_IRQ_MASK(ctx->csi2_port));
+       reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(3), val);
        /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */
        reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0);
 }
@@ -1948,7 +1946,7 @@ static int cal_complete_ctx(struct cal_ctx *ctx)
        vfd->lock = &ctx->mutex;
        video_set_drvdata(vfd, ctx);
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr);
        if (ret < 0)
                return ret;
 
@@ -2032,7 +2030,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
 
        parent = pdev->dev.of_node;
 
-       asd = &ctx->asd;
        endpoint = &ctx->endpoint;
 
        ep_node = NULL;
@@ -2079,8 +2076,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
                ctx_dbg(3, ctx, "can't get remote parent\n");
                goto cleanup_exit;
        }
-       asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
-       asd->match.fwnode = of_fwnode_handle(sensor_node);
 
        v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint);
 
@@ -2110,9 +2105,17 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
 
        v4l2_async_notifier_init(&ctx->notifier);
 
+       asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+       if (!asd)
+               goto cleanup_exit;
+
+       asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+       asd->match.fwnode = of_fwnode_handle(sensor_node);
+
        ret = v4l2_async_notifier_add_subdev(&ctx->notifier, asd);
        if (ret) {
                ctx_err(ctx, "Error adding asd\n");
+               kfree(asd);
                goto cleanup_exit;
        }
 
index 65c2c04..cff2fcd 100644 (file)
@@ -2500,7 +2500,7 @@ static void vpe_fw_cb(struct platform_device *pdev)
        vfd->lock = &dev->dev_mutex;
        vfd->v4l2_dev = &dev->v4l2_dev;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                vpe_err(dev, "Failed to register video device\n");
 
index 78841b9..ed0ad68 100644 (file)
@@ -646,7 +646,7 @@ static int viacam_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
         * requirement which will keep the CPU out of the deeper sleep
         * states.
         */
-       pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50);
+       cpu_latency_qos_add_request(&cam->qos_request, 50);
        viacam_start_engine(cam);
        return 0;
 out:
@@ -662,7 +662,7 @@ static void viacam_vb2_stop_streaming(struct vb2_queue *vq)
        struct via_camera *cam = vb2_get_drv_priv(vq);
        struct via_buffer *buf, *tmp;
 
-       pm_qos_remove_request(&cam->qos_request);
+       cpu_latency_qos_remove_request(&cam->qos_request);
        viacam_stop_engine(cam);
 
        list_for_each_entry_safe(buf, tmp, &cam->buffer_queue, queue) {
@@ -1262,7 +1262,7 @@ static int viacam_probe(struct platform_device *pdev)
        cam->vdev.lock = &cam->lock;
        cam->vdev.queue = vq;
        video_set_drvdata(&cam->vdev, cam);
-       ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1);
        if (ret)
                goto out_irq;
 
index 3c93d92..b6e39fb 100644 (file)
@@ -27,17 +27,17 @@ static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
        { V4L2_PIX_FMT_BGR24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_RGB24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_HSV24,   3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
-       { V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_BGR32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_XBGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_ABGR32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_RGB32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_XRGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_ARGB32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_BGRX32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_BGRX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_BGRA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_RGBX32,  4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+       { V4L2_PIX_FMT_RGBX32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
        { V4L2_PIX_FMT_RGBA32,  4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
-       { V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
+       { V4L2_PIX_FMT_HSV32,   4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_HSV},
        { V4L2_PIX_FMT_GREY,    1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB},
 };
 
@@ -175,22 +175,14 @@ static int prepare_raw_frame(struct fwht_raw_frame *rf,
        case V4L2_PIX_FMT_RGB32:
        case V4L2_PIX_FMT_XRGB32:
        case V4L2_PIX_FMT_HSV32:
-               rf->cr = rf->luma + 1;
-               rf->cb = rf->cr + 2;
-               rf->luma += 2;
-               break;
-       case V4L2_PIX_FMT_BGR32:
-       case V4L2_PIX_FMT_XBGR32:
-               rf->cb = rf->luma;
-               rf->cr = rf->cb + 2;
-               rf->luma++;
-               break;
        case V4L2_PIX_FMT_ARGB32:
                rf->alpha = rf->luma;
                rf->cr = rf->luma + 1;
                rf->cb = rf->cr + 2;
                rf->luma += 2;
                break;
+       case V4L2_PIX_FMT_BGR32:
+       case V4L2_PIX_FMT_XBGR32:
        case V4L2_PIX_FMT_ABGR32:
                rf->cb = rf->luma;
                rf->cr = rf->cb + 2;
@@ -198,10 +190,6 @@ static int prepare_raw_frame(struct fwht_raw_frame *rf,
                rf->alpha = rf->cr + 1;
                break;
        case V4L2_PIX_FMT_BGRX32:
-               rf->cb = rf->luma + 1;
-               rf->cr = rf->cb + 2;
-               rf->luma += 2;
-               break;
        case V4L2_PIX_FMT_BGRA32:
                rf->alpha = rf->luma;
                rf->cb = rf->luma + 1;
@@ -209,10 +197,6 @@ static int prepare_raw_frame(struct fwht_raw_frame *rf,
                rf->luma += 2;
                break;
        case V4L2_PIX_FMT_RGBX32:
-               rf->cr = rf->luma;
-               rf->cb = rf->cr + 2;
-               rf->luma++;
-               break;
        case V4L2_PIX_FMT_RGBA32:
                rf->alpha = rf->luma + 3;
                rf->cr = rf->luma;
index 8235009..30ced1c 100644 (file)
@@ -117,15 +117,10 @@ struct vicodec_ctx {
        struct vicodec_dev      *dev;
        bool                    is_enc;
        bool                    is_stateless;
-       bool                    is_draining;
-       bool                    next_is_last;
-       bool                    has_stopped;
        spinlock_t              *lock;
 
        struct v4l2_ctrl_handler hdl;
 
-       struct vb2_v4l2_buffer *last_src_buf;
-
        /* Source and destination queue data */
        struct vicodec_q_data   q_data[2];
        struct v4l2_fwht_state  state;
@@ -431,11 +426,11 @@ static void device_run(void *priv)
        v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
 
        spin_lock(ctx->lock);
-       if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
+       if (!ctx->comp_has_next_frame &&
+           v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) {
                dst_buf->flags |= V4L2_BUF_FLAG_LAST;
                v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
-               ctx->is_draining = false;
-               ctx->has_stopped = true;
+               v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
        }
        if (ctx->is_enc || ctx->is_stateless) {
                src_buf->sequence = q_src->sequence++;
@@ -586,8 +581,6 @@ static int job_ready(void *priv)
        unsigned int max_to_copy;
        unsigned int comp_frame_size;
 
-       if (ctx->has_stopped)
-               return 0;
        if (ctx->source_changed)
                return 0;
        if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame)
@@ -607,7 +600,8 @@ restart:
        if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
                state = get_next_header(ctx, &p, p_src + sz - p);
                if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
-                       if (ctx->is_draining && src_buf == ctx->last_src_buf)
+                       if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
+                                                             src_buf))
                                return 1;
                        job_remove_src_buf(ctx, state);
                        goto restart;
@@ -636,7 +630,8 @@ restart:
                p += copy;
                ctx->comp_size += copy;
                if (ctx->comp_size < max_to_copy) {
-                       if (ctx->is_draining && src_buf == ctx->last_src_buf)
+                       if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
+                                                             src_buf))
                                return 1;
                        job_remove_src_buf(ctx, state);
                        goto restart;
@@ -1219,41 +1214,6 @@ static int vidioc_s_selection(struct file *file, void *priv,
        return 0;
 }
 
-static int vicodec_mark_last_buf(struct vicodec_ctx *ctx)
-{
-       struct vb2_v4l2_buffer *next_dst_buf;
-       int ret = 0;
-
-       spin_lock(ctx->lock);
-       if (ctx->is_draining) {
-               ret = -EBUSY;
-               goto unlock;
-       }
-       if (ctx->has_stopped)
-               goto unlock;
-
-       ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
-       ctx->is_draining = true;
-       if (ctx->last_src_buf)
-               goto unlock;
-
-       next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-       if (!next_dst_buf) {
-               ctx->next_is_last = true;
-               goto unlock;
-       }
-
-       next_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
-       vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE);
-       ctx->is_draining = false;
-       ctx->has_stopped = true;
-       v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
-
-unlock:
-       spin_unlock(ctx->lock);
-       return ret;
-}
-
 static int vicodec_encoder_cmd(struct file *file, void *fh,
                            struct v4l2_encoder_cmd *ec)
 {
@@ -1268,18 +1228,19 @@ static int vicodec_encoder_cmd(struct file *file, void *fh,
            !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
                return 0;
 
-       if (ec->cmd == V4L2_ENC_CMD_STOP)
-               return vicodec_mark_last_buf(ctx);
-       ret = 0;
-       spin_lock(ctx->lock);
-       if (ctx->is_draining) {
-               ret = -EBUSY;
-       } else if (ctx->has_stopped) {
-               ctx->has_stopped = false;
+       ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec);
+       if (ret < 0)
+               return ret;
+
+       if (ec->cmd == V4L2_ENC_CMD_STOP &&
+           v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
+               v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
+
+       if (ec->cmd == V4L2_ENC_CMD_START &&
+           v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
                vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
-       }
-       spin_unlock(ctx->lock);
-       return ret;
+
+       return 0;
 }
 
 static int vicodec_decoder_cmd(struct file *file, void *fh,
@@ -1296,18 +1257,19 @@ static int vicodec_decoder_cmd(struct file *file, void *fh,
            !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
                return 0;
 
-       if (dc->cmd == V4L2_DEC_CMD_STOP)
-               return vicodec_mark_last_buf(ctx);
-       ret = 0;
-       spin_lock(ctx->lock);
-       if (ctx->is_draining) {
-               ret = -EBUSY;
-       } else if (ctx->has_stopped) {
-               ctx->has_stopped = false;
+       ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc);
+       if (ret < 0)
+               return ret;
+
+       if (dc->cmd == V4L2_DEC_CMD_STOP &&
+           v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
+               v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
+
+       if (dc->cmd == V4L2_DEC_CMD_START &&
+           v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
                vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
-       }
-       spin_unlock(ctx->lock);
-       return ret;
+
+       return 0;
 }
 
 static int vicodec_enum_framesizes(struct file *file, void *fh,
@@ -1480,23 +1442,21 @@ static void vicodec_buf_queue(struct vb2_buffer *vb)
                .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
        };
 
-       if (vb2_is_streaming(vq_cap)) {
-               if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) &&
-                   ctx->next_is_last) {
-                       unsigned int i;
+       if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) &&
+           vb2_is_streaming(vb->vb2_queue) &&
+           v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) {
+               unsigned int i;
 
-                       for (i = 0; i < vb->num_planes; i++)
-                               vb->planes[i].bytesused = 0;
-                       vbuf->flags = V4L2_BUF_FLAG_LAST;
-                       vbuf->field = V4L2_FIELD_NONE;
-                       vbuf->sequence = get_q_data(ctx, vb->vb2_queue->type)->sequence++;
-                       vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-                       ctx->is_draining = false;
-                       ctx->has_stopped = true;
-                       ctx->next_is_last = false;
-                       v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
-                       return;
-               }
+               for (i = 0; i < vb->num_planes; i++)
+                       vb->planes[i].bytesused = 0;
+
+               vbuf->field = V4L2_FIELD_NONE;
+               vbuf->sequence =
+                       get_q_data(ctx, vb->vb2_queue->type)->sequence++;
+
+               v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);
+               v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
+               return;
        }
 
        /* buf_queue handles only the first source change event */
@@ -1609,8 +1569,7 @@ static int vicodec_start_streaming(struct vb2_queue *q,
        chroma_div = info->width_div * info->height_div;
        q_data->sequence = 0;
 
-       if (V4L2_TYPE_IS_OUTPUT(q->type))
-               ctx->last_src_buf = NULL;
+       v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
 
        state->gop_cnt = 0;
 
@@ -1689,29 +1648,12 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
 
        vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
 
-       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
-               if (ctx->is_draining) {
-                       struct vb2_v4l2_buffer *next_dst_buf;
-
-                       spin_lock(ctx->lock);
-                       ctx->last_src_buf = NULL;
-                       next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
-                       if (!next_dst_buf) {
-                               ctx->next_is_last = true;
-                       } else {
-                               next_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
-                               vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE);
-                               ctx->is_draining = false;
-                               ctx->has_stopped = true;
-                               v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
-                       }
-                       spin_unlock(ctx->lock);
-               }
-       } else {
-               ctx->is_draining = false;
-               ctx->has_stopped = false;
-               ctx->next_is_last = false;
-       }
+       v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
+
+       if (V4L2_TYPE_IS_OUTPUT(q->type) &&
+           v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
+               v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
+
        if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type))
                ctx->first_source_change_sent = false;
 
@@ -2120,7 +2062,7 @@ static int register_instance(struct vicodec_dev *dev,
        }
        video_set_drvdata(vfd, dev);
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name);
                v4l2_m2m_release(dev_instance->m2m_dev);
index 8d6b096..ac6717f 100644 (file)
@@ -1333,7 +1333,7 @@ static int vim2m_probe(struct platform_device *pdev)
        vfd->lock = &dev->dev_mutex;
        vfd->v4l2_dev = &dev->v4l2_dev;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
                goto error_v4l2;
index 76c0158..23e740c 100644 (file)
@@ -325,20 +325,20 @@ static const struct media_entity_operations vimc_cap_mops = {
        .link_validate          = vimc_vdev_link_validate,
 };
 
-static void vimc_cap_release(struct video_device *vdev)
+void vimc_cap_release(struct vimc_ent_device *ved)
 {
        struct vimc_cap_device *vcap =
-               container_of(vdev, struct vimc_cap_device, vdev);
+               container_of(ved, struct vimc_cap_device, ved);
 
        media_entity_cleanup(vcap->ved.ent);
        kfree(vcap);
 }
 
-void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
+void vimc_cap_unregister(struct vimc_ent_device *ved)
 {
-       struct vimc_cap_device *vcap;
+       struct vimc_cap_device *vcap =
+               container_of(ved, struct vimc_cap_device, ved);
 
-       vcap = container_of(ved, struct vimc_cap_device, ved);
        vb2_queue_release(&vcap->queue);
        video_unregister_device(&vcap->vdev);
 }
@@ -423,7 +423,7 @@ struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
 
        ret = vb2_queue_init(q);
        if (ret) {
-               dev_err(&vimc->pdev.dev, "%s: vb2 queue init failed (err=%d)\n",
+               dev_err(vimc->mdev.dev, "%s: vb2 queue init failed (err=%d)\n",
                        vcfg_name, ret);
                goto err_clean_m_ent;
        }
@@ -443,13 +443,13 @@ struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
        vcap->ved.ent = &vcap->vdev.entity;
        vcap->ved.process_frame = vimc_cap_process_frame;
        vcap->ved.vdev_get_format = vimc_cap_get_format;
-       vcap->ved.dev = &vimc->pdev.dev;
+       vcap->ved.dev = vimc->mdev.dev;
 
        /* Initialize the video_device struct */
        vdev = &vcap->vdev;
        vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        vdev->entity.ops = &vimc_cap_mops;
-       vdev->release = vimc_cap_release;
+       vdev->release = video_device_release_empty;
        vdev->fops = &vimc_cap_fops;
        vdev->ioctl_ops = &vimc_cap_ioctl_ops;
        vdev->lock = &vcap->lock;
@@ -460,9 +460,9 @@ struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
        video_set_drvdata(vdev, &vcap->ved);
 
        /* Register the video_device with the v4l2 and the media framework */
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
-               dev_err(&vimc->pdev.dev, "%s: video register failed (err=%d)\n",
+               dev_err(vimc->mdev.dev, "%s: video register failed (err=%d)\n",
                        vcap->vdev.name, ret);
                goto err_release_queue;
        }
index 16ce9f3..c95c17c 100644 (file)
@@ -327,7 +327,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
                         u32 function,
                         u16 num_pads,
                         struct media_pad *pads,
-                        const struct v4l2_subdev_internal_ops *sd_int_ops,
                         const struct v4l2_subdev_ops *sd_ops)
 {
        int ret;
@@ -337,7 +336,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
 
        /* Initialize the subdev */
        v4l2_subdev_init(sd, sd_ops);
-       sd->internal_ops = sd_int_ops;
        sd->entity.function = function;
        sd->entity.ops = &vimc_ent_sd_mops;
        sd->owner = THIS_MODULE;
index 87eb825..616d5a6 100644 (file)
@@ -106,14 +106,12 @@ struct vimc_ent_device {
 /**
  * struct vimc_device - main device for vimc driver
  *
- * @pdev       pointer to the platform device
  * @pipe_cfg   pointer to the vimc pipeline configuration structure
  * @ent_devs   array of vimc_ent_device pointers
  * @mdev       the associated media_device parent
  * @v4l2_dev   Internal v4l2 parent device
  */
 struct vimc_device {
-       struct platform_device pdev;
        const struct vimc_pipeline_config *pipe_cfg;
        struct vimc_ent_device **ent_devs;
        struct media_device mdev;
@@ -127,16 +125,18 @@ struct vimc_device {
  * @name                       entity name
  * @ved                                pointer to vimc_ent_device (a node in the
  *                                     topology)
- * @add                                subdev add hook - initializes and registers
- *                                     subdev called from vimc-core
- * @rm                         subdev rm hook - unregisters and frees
- *                                     subdev called from vimc-core
+ * @add                                initializes and registers
+ *                                     vim entity - called from vimc-core
+ * @unregister                 unregisters vimc entity - called from vimc-core
+ * @release                    releases vimc entity - called from the v4l2_dev
+ *                                     release callback
  */
 struct vimc_ent_config {
        const char *name;
        struct vimc_ent_device *(*add)(struct vimc_device *vimc,
                                       const char *vcfg_name);
-       void (*rm)(struct vimc_device *vimc, struct vimc_ent_device *ved);
+       void (*unregister)(struct vimc_ent_device *ved);
+       void (*release)(struct vimc_ent_device *ved);
 };
 
 /**
@@ -147,22 +147,23 @@ struct vimc_ent_config {
  */
 bool vimc_is_source(struct media_entity *ent);
 
-/* prototypes for vimc_ent_config add and rm hooks */
+/* prototypes for vimc_ent_config hooks */
 struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
                                     const char *vcfg_name);
-void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);
+void vimc_cap_unregister(struct vimc_ent_device *ved);
+void vimc_cap_release(struct vimc_ent_device *ved);
 
 struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc,
                                     const char *vcfg_name);
-void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);
+void vimc_deb_release(struct vimc_ent_device *ved);
 
 struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
                                     const char *vcfg_name);
-void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);
+void vimc_sca_release(struct vimc_ent_device *ved);
 
 struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc,
                                     const char *vcfg_name);
-void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);
+void vimc_sen_release(struct vimc_ent_device *ved);
 
 /**
  * vimc_pix_map_by_index - get vimc_pix_map struct by its index
@@ -197,7 +198,6 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat);
  * @num_pads:  number of pads to initialize
  * @pads:      the array of pads of the entity, the caller should set the
                flags of the pads
- * @sd_int_ops:        pointer to &struct v4l2_subdev_internal_ops
  * @sd_ops:    pointer to &struct v4l2_subdev_ops.
  *
  * Helper function initialize and register the struct vimc_ent_device and struct
@@ -210,7 +210,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
                         u32 function,
                         u16 num_pads,
                         struct media_pad *pads,
-                        const struct v4l2_subdev_internal_ops *sd_int_ops,
                         const struct v4l2_subdev_ops *sd_ops);
 
 /**
index 97a272f..339126e 100644 (file)
@@ -48,48 +48,51 @@ static struct vimc_ent_config ent_config[] = {
        {
                .name = "Sensor A",
                .add = vimc_sen_add,
-               .rm = vimc_sen_rm,
+               .release = vimc_sen_release,
        },
        {
                .name = "Sensor B",
                .add = vimc_sen_add,
-               .rm = vimc_sen_rm,
+               .release = vimc_sen_release,
        },
        {
                .name = "Debayer A",
                .add = vimc_deb_add,
-               .rm = vimc_deb_rm,
+               .release = vimc_deb_release,
        },
        {
                .name = "Debayer B",
                .add = vimc_deb_add,
-               .rm = vimc_deb_rm,
+               .release = vimc_deb_release,
        },
        {
                .name = "Raw Capture 0",
                .add = vimc_cap_add,
-               .rm = vimc_cap_rm,
+               .unregister = vimc_cap_unregister,
+               .release = vimc_cap_release,
        },
        {
                .name = "Raw Capture 1",
                .add = vimc_cap_add,
-               .rm = vimc_cap_rm,
+               .unregister = vimc_cap_unregister,
+               .release = vimc_cap_release,
        },
        {
                /* TODO: change this to vimc-input when it is implemented */
                .name = "RGB/YUV Input",
                .add = vimc_sen_add,
-               .rm = vimc_sen_rm,
+               .release = vimc_sen_release,
        },
        {
                .name = "Scaler",
                .add = vimc_sca_add,
-               .rm = vimc_sca_rm,
+               .release = vimc_sca_release,
        },
        {
                .name = "RGB/YUV Capture",
                .add = vimc_cap_add,
-               .rm = vimc_cap_rm,
+               .unregister = vimc_cap_unregister,
+               .release = vimc_cap_release,
        },
 };
 
@@ -162,12 +165,12 @@ static int vimc_add_subdevs(struct vimc_device *vimc)
        unsigned int i;
 
        for (i = 0; i < vimc->pipe_cfg->num_ents; i++) {
-               dev_dbg(&vimc->pdev.dev, "new entity for %s\n",
+               dev_dbg(vimc->mdev.dev, "new entity for %s\n",
                        vimc->pipe_cfg->ents[i].name);
                vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].add(vimc,
                                        vimc->pipe_cfg->ents[i].name);
                if (!vimc->ent_devs[i]) {
-                       dev_err(&vimc->pdev.dev, "add new entity for %s\n",
+                       dev_err(vimc->mdev.dev, "add new entity for %s\n",
                                vimc->pipe_cfg->ents[i].name);
                        return -EINVAL;
                }
@@ -175,13 +178,33 @@ static int vimc_add_subdevs(struct vimc_device *vimc)
        return 0;
 }
 
-static void vimc_rm_subdevs(struct vimc_device *vimc)
+static void vimc_release_subdevs(struct vimc_device *vimc)
 {
        unsigned int i;
 
        for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
                if (vimc->ent_devs[i])
-                       vimc->pipe_cfg->ents[i].rm(vimc, vimc->ent_devs[i]);
+                       vimc->pipe_cfg->ents[i].release(vimc->ent_devs[i]);
+}
+
+static void vimc_unregister_subdevs(struct vimc_device *vimc)
+{
+       unsigned int i;
+
+       for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
+               if (vimc->ent_devs[i] && vimc->pipe_cfg->ents[i].unregister)
+                       vimc->pipe_cfg->ents[i].unregister(vimc->ent_devs[i]);
+}
+
+static void vimc_v4l2_dev_release(struct v4l2_device *v4l2_dev)
+{
+       struct vimc_device *vimc =
+               container_of(v4l2_dev, struct vimc_device, v4l2_dev);
+
+       vimc_release_subdevs(vimc);
+       media_device_cleanup(&vimc->mdev);
+       kfree(vimc->ent_devs);
+       kfree(vimc);
 }
 
 static int vimc_register_devices(struct vimc_device *vimc)
@@ -195,7 +218,6 @@ static int vimc_register_devices(struct vimc_device *vimc)
                        "v4l2 device register failed (err=%d)\n", ret);
                return ret;
        }
-
        /* allocate ent_devs */
        vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents,
                                 sizeof(*vimc->ent_devs), GFP_KERNEL);
@@ -236,9 +258,9 @@ static int vimc_register_devices(struct vimc_device *vimc)
 
 err_mdev_unregister:
        media_device_unregister(&vimc->mdev);
-       media_device_cleanup(&vimc->mdev);
 err_rm_subdevs:
-       vimc_rm_subdevs(vimc);
+       vimc_unregister_subdevs(vimc);
+       vimc_release_subdevs(vimc);
        kfree(vimc->ent_devs);
 err_v4l2_unregister:
        v4l2_device_unregister(&vimc->v4l2_dev);
@@ -248,20 +270,23 @@ err_v4l2_unregister:
 
 static void vimc_unregister(struct vimc_device *vimc)
 {
+       vimc_unregister_subdevs(vimc);
        media_device_unregister(&vimc->mdev);
-       media_device_cleanup(&vimc->mdev);
        v4l2_device_unregister(&vimc->v4l2_dev);
-       kfree(vimc->ent_devs);
 }
 
 static int vimc_probe(struct platform_device *pdev)
 {
-       struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev);
+       struct vimc_device *vimc;
        int ret;
 
        dev_dbg(&pdev->dev, "probe");
 
-       memset(&vimc->mdev, 0, sizeof(vimc->mdev));
+       vimc = kzalloc(sizeof(*vimc), GFP_KERNEL);
+       if (!vimc)
+               return -ENOMEM;
+
+       vimc->pipe_cfg = &pipe_cfg;
 
        /* Link the media device within the v4l2_device */
        vimc->v4l2_dev.mdev = &vimc->mdev;
@@ -277,20 +302,27 @@ static int vimc_probe(struct platform_device *pdev)
        ret = vimc_register_devices(vimc);
        if (ret) {
                media_device_cleanup(&vimc->mdev);
+               kfree(vimc);
                return ret;
        }
+       /*
+        * the release cb is set only after successful registration.
+        * if the registration fails, we release directly from probe
+        */
 
+       vimc->v4l2_dev.release = vimc_v4l2_dev_release;
+       platform_set_drvdata(pdev, vimc);
        return 0;
 }
 
 static int vimc_remove(struct platform_device *pdev)
 {
-       struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev);
+       struct vimc_device *vimc = platform_get_drvdata(pdev);
 
        dev_dbg(&pdev->dev, "remove");
 
-       vimc_rm_subdevs(vimc);
        vimc_unregister(vimc);
+       v4l2_device_put(&vimc->v4l2_dev);
 
        return 0;
 }
@@ -299,12 +331,9 @@ static void vimc_dev_release(struct device *dev)
 {
 }
 
-static struct vimc_device vimc_dev = {
-       .pipe_cfg = &pipe_cfg,
-       .pdev = {
-               .name = VIMC_PDEV_NAME,
-               .dev.release = vimc_dev_release,
-       }
+static struct platform_device vimc_pdev = {
+       .name = VIMC_PDEV_NAME,
+       .dev.release = vimc_dev_release,
 };
 
 static struct platform_driver vimc_pdrv = {
@@ -319,16 +348,16 @@ static int __init vimc_init(void)
 {
        int ret;
 
-       ret = platform_device_register(&vimc_dev.pdev);
+       ret = platform_device_register(&vimc_pdev);
        if (ret) {
-               dev_err(&vimc_dev.pdev.dev,
+               dev_err(&vimc_pdev.dev,
                        "platform device registration failed (err=%d)\n", ret);
                return ret;
        }
 
        ret = platform_driver_register(&vimc_pdrv);
        if (ret) {
-               dev_err(&vimc_dev.pdev.dev,
+               dev_err(&vimc_pdev.dev,
                        "platform driver registration failed (err=%d)\n", ret);
                platform_driver_unregister(&vimc_pdrv);
                return ret;
@@ -341,7 +370,7 @@ static void __exit vimc_exit(void)
 {
        platform_driver_unregister(&vimc_pdrv);
 
-       platform_device_unregister(&vimc_dev.pdev);
+       platform_device_unregister(&vimc_pdev);
 }
 
 module_init(vimc_init);
index 5d1b67d..baf6bf9 100644 (file)
@@ -494,28 +494,16 @@ static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = {
        .s_ctrl = vimc_deb_s_ctrl,
 };
 
-static void vimc_deb_release(struct v4l2_subdev *sd)
+void vimc_deb_release(struct vimc_ent_device *ved)
 {
        struct vimc_deb_device *vdeb =
-                               container_of(sd, struct vimc_deb_device, sd);
+               container_of(ved, struct vimc_deb_device, ved);
 
        v4l2_ctrl_handler_free(&vdeb->hdl);
        media_entity_cleanup(vdeb->ved.ent);
        kfree(vdeb);
 }
 
-static const struct v4l2_subdev_internal_ops vimc_deb_int_ops = {
-       .release = vimc_deb_release,
-};
-
-void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
-{
-       struct vimc_deb_device *vdeb;
-
-       vdeb = container_of(ved, struct vimc_deb_device, ved);
-       v4l2_device_unregister_subdev(&vdeb->sd);
-}
-
 static const struct v4l2_ctrl_config vimc_deb_ctrl_class = {
        .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
        .id = VIMC_CID_VIMC_CLASS,
@@ -563,13 +551,12 @@ struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc,
        ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev,
                                   vcfg_name,
                                   MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2,
-                                  vdeb->pads,
-                                  &vimc_deb_int_ops, &vimc_deb_ops);
+                                  vdeb->pads, &vimc_deb_ops);
        if (ret)
                goto err_free_hdl;
 
        vdeb->ved.process_frame = vimc_deb_process_frame;
-       vdeb->ved.dev = &vimc->pdev.dev;
+       vdeb->ved.dev = vimc->mdev.dev;
        vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def;
 
        /* Initialize the frame format */
index e2e551b..7521439 100644 (file)
@@ -464,27 +464,15 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
        return vsca->src_frame;
 };
 
-static void vimc_sca_release(struct v4l2_subdev *sd)
+void vimc_sca_release(struct vimc_ent_device *ved)
 {
        struct vimc_sca_device *vsca =
-                               container_of(sd, struct vimc_sca_device, sd);
+               container_of(ved, struct vimc_sca_device, ved);
 
        media_entity_cleanup(vsca->ved.ent);
        kfree(vsca);
 }
 
-static const struct v4l2_subdev_internal_ops vimc_sca_int_ops = {
-       .release = vimc_sca_release,
-};
-
-void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
-{
-       struct vimc_sca_device *vsca;
-
-       vsca = container_of(ved, struct vimc_sca_device, ved);
-       v4l2_device_unregister_subdev(&vsca->sd);
-}
-
 struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
                                     const char *vcfg_name)
 {
@@ -504,15 +492,14 @@ struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
        ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev,
                                   vcfg_name,
                                   MEDIA_ENT_F_PROC_VIDEO_SCALER, 2,
-                                  vsca->pads,
-                                  &vimc_sca_int_ops, &vimc_sca_ops);
+                                  vsca->pads, &vimc_sca_ops);
        if (ret) {
                kfree(vsca);
                return NULL;
        }
 
        vsca->ved.process_frame = vimc_sca_process_frame;
-       vsca->ved.dev = &vimc->pdev.dev;
+       vsca->ved.dev = vimc->mdev.dev;
 
        /* Initialize the frame format */
        vsca->sink_fmt = sink_fmt_default;
index 32380f5..92daee5 100644 (file)
@@ -279,10 +279,10 @@ static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = {
        .s_ctrl = vimc_sen_s_ctrl,
 };
 
-static void vimc_sen_release(struct v4l2_subdev *sd)
+void vimc_sen_release(struct vimc_ent_device *ved)
 {
        struct vimc_sen_device *vsen =
-                               container_of(sd, struct vimc_sen_device, sd);
+               container_of(ved, struct vimc_sen_device, ved);
 
        v4l2_ctrl_handler_free(&vsen->hdl);
        tpg_free(&vsen->tpg);
@@ -290,18 +290,6 @@ static void vimc_sen_release(struct v4l2_subdev *sd)
        kfree(vsen);
 }
 
-static const struct v4l2_subdev_internal_ops vimc_sen_int_ops = {
-       .release = vimc_sen_release,
-};
-
-void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
-{
-       struct vimc_sen_device *vsen;
-
-       vsen = container_of(ved, struct vimc_sen_device, ved);
-       v4l2_device_unregister_subdev(&vsen->sd);
-}
-
 /* Image Processing Controls */
 static const struct v4l2_ctrl_config vimc_sen_ctrl_class = {
        .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
@@ -365,12 +353,12 @@ struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc,
        ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev,
                                   vcfg_name,
                                   MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad,
-                                  &vimc_sen_int_ops, &vimc_sen_ops);
+                                  &vimc_sen_ops);
        if (ret)
                goto err_free_tpg;
 
        vsen->ved.process_frame = vimc_sen_process_frame;
-       vsen->ved.dev = &vimc->pdev.dev;
+       vsen->ved.dev = vimc->mdev.dev;
 
        /* Initialize the frame format */
        vsen->mbus_format = fmt_default;
index cd6b554..65feb3c 100644 (file)
@@ -207,16 +207,27 @@ int vimc_streamer_s_stream(struct vimc_stream *stream,
                stream->kthread = kthread_run(vimc_streamer_thread, stream,
                                              "vimc-streamer thread");
 
-               if (IS_ERR(stream->kthread))
-                       return PTR_ERR(stream->kthread);
+               if (IS_ERR(stream->kthread)) {
+                       ret = PTR_ERR(stream->kthread);
+                       dev_err(ved->dev, "kthread_run failed with %d\n", ret);
+                       vimc_streamer_pipeline_terminate(stream);
+                       stream->kthread = NULL;
+                       return ret;
+               }
 
        } else {
                if (!stream->kthread)
                        return 0;
 
                ret = kthread_stop(stream->kthread);
+               /*
+                * kthread_stop returns -EINTR in cases when streamon was
+                * immediately followed by streamoff, and the thread didn't had
+                * a chance to run. Ignore errors to stop the stream in the
+                * pipeline.
+                */
                if (ret)
-                       return ret;
+                       dev_dbg(ved->dev, "kthread_stop returned '%d'\n", ret);
 
                stream->kthread = NULL;
 
index 15091cb..6c740e3 100644 (file)
@@ -407,7 +407,7 @@ static int vidioc_log_status(struct file *file, void *fh)
        struct video_device *vdev = video_devdata(file);
 
        v4l2_ctrl_log_status(file, fh);
-       if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_GRABBER)
+       if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_VIDEO)
                tpg_log_status(&dev->tpg);
        return 0;
 }
@@ -1525,7 +1525,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                }
 #endif
 
-               ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]);
+               ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_cap_nr[inst]);
                if (ret < 0)
                        goto unreg_dev;
                v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
@@ -1571,14 +1571,14 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                        }
                        v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n",
                                  dev_name(&dev->cec_tx_adap[i]->devnode.dev), i);
-                       if (i <= out_type_counter[HDMI])
-                               cec_s_phys_addr(dev->cec_tx_adap[i], i << 12, false);
+                       if (i < out_type_counter[HDMI])
+                               cec_s_phys_addr(dev->cec_tx_adap[i], (i + 1) << 12, false);
                        else
                                cec_s_phys_addr(dev->cec_tx_adap[i], 0x1000, false);
                }
 #endif
 
-               ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]);
+               ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_out_nr[inst]);
                if (ret < 0)
                        goto unreg_dev;
                v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n",
@@ -1734,7 +1734,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                if (ret)
                        goto unreg_dev;
 #endif
-               ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+               ret = video_register_device(vfd, VFL_TYPE_VIDEO,
                                            meta_cap_nr[inst]);
                if (ret < 0)
                        goto unreg_dev;
@@ -1764,7 +1764,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
                if (ret)
                        goto unreg_dev;
 #endif
-               ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+               ret = video_register_device(vfd, VFL_TYPE_VIDEO,
                                            meta_out_nr[inst]);
                if (ret < 0)
                        goto unreg_dev;
index 30d751f..a91e142 100644 (file)
@@ -551,7 +551,7 @@ int vsp1_histogram_init(struct vsp1_device *vsp1, struct vsp1_histogram *histo,
        histo->video.fops = &histo_v4l2_fops;
        snprintf(histo->video.name, sizeof(histo->video.name),
                 "%s histo", histo->entity.subdev.name);
-       histo->video.vfl_type = VFL_TYPE_GRABBER;
+       histo->video.vfl_type = VFL_TYPE_VIDEO;
        histo->video.release = video_device_release_empty;
        histo->video.ioctl_ops = &histo_v4l2_ioctl_ops;
        histo->video.device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
@@ -576,7 +576,7 @@ int vsp1_histogram_init(struct vsp1_device *vsp1, struct vsp1_histogram *histo,
 
        /* ... and register the video device. */
        histo->video.queue = &histo->queue;
-       ret = video_register_device(&histo->video, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&histo->video, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                dev_err(vsp1->dev, "failed to register video device\n");
                goto error;
index 5c67ff9..fe3130d 100644 (file)
 #define VI6_HGT_HUE_AREA_LOWER_SHIFT   16
 #define VI6_HGT_HUE_AREA_UPPER_SHIFT   0
 #define VI6_HGT_LB_TH                  0x3424
-#define VI6_HGT_LBn_H(n)               (0x3438 + (n) * 8)
+#define VI6_HGT_LBn_H(n)               (0x3428 + (n) * 8)
 #define VI6_HGT_LBn_V(n)               (0x342c + (n) * 8)
 #define VI6_HGT_HISTO(m, n)            (0x3450 + (m) * 128 + (n) * 4)
 #define VI6_HGT_MAXMIN                 0x3750
index 5e59ed2..044eb57 100644 (file)
@@ -1293,7 +1293,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
        video->video.fops = &vsp1_video_fops;
        snprintf(video->video.name, sizeof(video->video.name), "%s %s",
                 rwpf->entity.subdev.name, direction);
-       video->video.vfl_type = VFL_TYPE_GRABBER;
+       video->video.vfl_type = VFL_TYPE_VIDEO;
        video->video.release = video_device_release_empty;
        video->video.ioctl_ops = &vsp1_video_ioctl_ops;
 
@@ -1316,7 +1316,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
 
        /* ... and register the video device. */
        video->video.queue = &video->queue;
-       ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                dev_err(video->vsp1->dev, "failed to register video device\n");
                goto error;
index b211380..2a56201 100644 (file)
@@ -685,7 +685,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
                 xdev->dev->of_node,
                 type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input",
                 port);
-       dma->video.vfl_type = VFL_TYPE_GRABBER;
+       dma->video.vfl_type = VFL_TYPE_VIDEO;
        dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE
                           ? VFL_DIR_RX : VFL_DIR_TX;
        dma->video.release = video_device_release_empty;
@@ -725,16 +725,17 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
 
        /* ... and the DMA channel. */
        snprintf(name, sizeof(name), "port%u", port);
-       dma->dma = dma_request_slave_channel(dma->xdev->dev, name);
-       if (dma->dma == NULL) {
-               dev_err(dma->xdev->dev, "no VDMA channel found\n");
-               ret = -ENODEV;
+       dma->dma = dma_request_chan(dma->xdev->dev, name);
+       if (IS_ERR(dma->dma)) {
+               ret = PTR_ERR(dma->dma);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dma->xdev->dev, "no VDMA channel found\n");
                goto error;
        }
 
        dma->align = 1 << dma->dma->device->copy_align;
 
-       ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&dma->video, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                dev_err(dma->xdev->dev, "failed to register video device\n");
                goto error;
@@ -752,7 +753,7 @@ void xvip_dma_cleanup(struct xvip_dma *dma)
        if (video_is_registered(&dma->video))
                video_unregister_device(&dma->video);
 
-       if (dma->dma)
+       if (!IS_ERR_OR_NULL(dma->dma))
                dma_release_channel(dma->dma);
 
        media_entity_cleanup(&dma->video.entity);
index 537f8e1..a1ba8bc 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config RADIO_SI470X
-        tristate "Silicon Labs Si470x FM Radio Receiver support"
-        depends on VIDEO_V4L2
+       tristate "Silicon Labs Si470x FM Radio Receiver support"
+       depends on VIDEO_V4L2
        help
          This is a driver for devices with the Silicon Labs SI470x
          chip (either via USB or I2C buses).
index 0a0ce62..0f3417d 100644 (file)
@@ -35,11 +35,6 @@ static const struct bpf_func_proto rc_repeat_proto = {
        .arg1_type = ARG_PTR_TO_CTX,
 };
 
-/*
- * Currently rc-core does not support 64-bit scancodes, but there are many
- * known protocols with more than 32 bits. So, define the interface as u64
- * as a future-proof.
- */
 BPF_CALL_4(bpf_rc_keydown, u32*, sample, u32, protocol, u64, scancode,
           u32, toggle)
 {
index a7deca1..3c8bd13 100644 (file)
@@ -76,7 +76,7 @@ struct send_packet {
        uint8_t channels;
        uint8_t busy7;
        uint8_t busy4;
-       uint8_t payload[0];
+       uint8_t payload[];
 };
 
 static void process_ir_data(struct iguanair *ir, unsigned len)
index 74a1d30..4c3d038 100644 (file)
@@ -166,7 +166,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
                } else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) {
                        /* store nibble raw data, decode after trailer */
                        if (data->count == 16) {
-                               dev_dbg(&dev->dev, "to many pulses (%d) ignoring: %u\n",
+                               dev_dbg(&dev->dev, "too many pulses (%d) ignoring: %u\n",
                                        data->count, ev.duration);
                                data->state = STATE_INACTIVE;
                                return -EINVAL;
index 63261ef..aaa1bf8 100644 (file)
@@ -119,6 +119,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-videomate-m1f.o \
                        rc-videomate-s350.o \
                        rc-videomate-tv-pvr.o \
+                       rc-videostrong-kii-pro.o \
                        rc-wetek-hub.o \
                        rc-wetek-play2.o \
                        rc-winfast.o \
diff --git a/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c b/drivers/media/rc/keymaps/rc-videostrong-kii-pro.c
new file mode 100644 (file)
index 0000000..414d4d2
--- /dev/null
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright (C) 2019 Mohammad Rasim <mohammad.rasim96@gmail.com>
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+//
+// Keytable for the Videostrong KII Pro STB remote control
+//
+
+static struct rc_map_table kii_pro[] = {
+       { 0x59, KEY_POWER },
+       { 0x19, KEY_MUTE },
+       { 0x42, KEY_RED },
+       { 0x40, KEY_GREEN },
+       { 0x00, KEY_YELLOW },
+       { 0x03, KEY_BLUE },
+       { 0x4a, KEY_BACK },
+       { 0x48, KEY_FORWARD },
+       { 0x08, KEY_PREVIOUSSONG},
+       { 0x0b, KEY_NEXTSONG},
+       { 0x46, KEY_PLAYPAUSE },
+       { 0x44, KEY_STOP },
+       { 0x1f, KEY_FAVORITES}, //KEY_F5?
+       { 0x04, KEY_PVR },
+       { 0x4d, KEY_EPG },
+       { 0x02, KEY_INFO },
+       { 0x09, KEY_SUBTITLE },
+       { 0x01, KEY_AUDIO },
+       { 0x0d, KEY_HOMEPAGE },
+       { 0x11, KEY_TV },       // DTV ?
+       { 0x06, KEY_UP },
+       { 0x5a, KEY_LEFT },
+       { 0x1a, KEY_ENTER },    // KEY_OK ?
+       { 0x1b, KEY_RIGHT },
+       { 0x16, KEY_DOWN },
+       { 0x45, KEY_MENU },
+       { 0x05, KEY_ESC },
+       { 0x13, KEY_VOLUMEUP },
+       { 0x17, KEY_VOLUMEDOWN },
+       { 0x58, KEY_APPSELECT },
+       { 0x12, KEY_VENDOR },   // mouse
+       { 0x55, KEY_PAGEUP },   // KEY_CHANNELUP ?
+       { 0x15, KEY_PAGEDOWN }, // KEY_CHANNELDOWN ?
+       { 0x52, KEY_1 },
+       { 0x50, KEY_2 },
+       { 0x10, KEY_3 },
+       { 0x56, KEY_4 },
+       { 0x54, KEY_5 },
+       { 0x14, KEY_6 },
+       { 0x4e, KEY_7 },
+       { 0x4c, KEY_8 },
+       { 0x0c, KEY_9 },
+       { 0x18, KEY_WWW },      // KEY_F7
+       { 0x0f, KEY_0 },
+       { 0x51, KEY_BACKSPACE },
+};
+
+static struct rc_map_list kii_pro_map = {
+       .map = {
+               .scan     = kii_pro,
+               .size     = ARRAY_SIZE(kii_pro),
+               .rc_proto = RC_PROTO_NEC,
+               .name     = RC_MAP_KII_PRO,
+       }
+};
+
+static int __init init_rc_map_kii_pro(void)
+{
+       return rc_map_register(&kii_pro_map);
+}
+
+static void __exit exit_rc_map_kii_pro(void)
+{
+       rc_map_unregister(&kii_pro_map);
+}
+
+module_init(init_rc_map_kii_pro)
+module_exit(exit_rc_map_kii_pro)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mohammad Rasim <mohammad.rasim96@gmail.com>");
index 9a8c1cf..583e4f3 100644 (file)
@@ -269,12 +269,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
                        goto out_unlock;
                }
 
-               /*
-                * The scancode field in lirc_scancode is 64-bit simply
-                * to future-proof it, since there are IR protocols encode
-                * use more than 32 bits. For now only 32-bit protocols
-                * are supported.
-                */
+               /* We only have encoders for 32-bit protocols. */
                if (scan.scancode > U32_MAX ||
                    !rc_validate_scancode(scan.rc_proto, scan.scancode)) {
                        ret = -EINVAL;
index 5c2cd8d..48a69bf 100644 (file)
@@ -230,10 +230,10 @@ static ssize_t wakeup_data_show(struct device *dev,
        for (i = 0; i < fifo_len; i++) {
                duration = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
                duration = (duration & BUF_LEN_MASK) * SAMPLE_PERIOD;
-               buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len,
+               buf_len += scnprintf(buf + buf_len, PAGE_SIZE - buf_len,
                                    "%d ", duration);
        }
-       buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n");
+       buf_len += scnprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n");
 
        spin_unlock_irqrestore(&nvt->lock, flags);
 
index 6f80c25..d7064d6 100644 (file)
@@ -164,6 +164,41 @@ static struct rc_map_list empty_map = {
 };
 
 /**
+ * scancode_to_u64() - converts scancode in &struct input_keymap_entry
+ * @ke: keymap entry containing scancode to be converted.
+ * @scancode: pointer to the location where converted scancode should
+ *     be stored.
+ *
+ * This function is a version of input_scancode_to_scalar specialized for
+ * rc-core.
+ */
+static int scancode_to_u64(const struct input_keymap_entry *ke, u64 *scancode)
+{
+       switch (ke->len) {
+       case 1:
+               *scancode = *((u8 *)ke->scancode);
+               break;
+
+       case 2:
+               *scancode = *((u16 *)ke->scancode);
+               break;
+
+       case 4:
+               *scancode = *((u32 *)ke->scancode);
+               break;
+
+       case 8:
+               *scancode = *((u64 *)ke->scancode);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
  * ir_create_table() - initializes a scancode table
  * @dev:       the rc_dev device
  * @rc_map:    the rc_map to initialize
@@ -285,13 +320,13 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
 
        /* Did the user wish to remove the mapping? */
        if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
-               dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04x\n",
+               dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04llx\n",
                        index, rc_map->scan[index].scancode);
                rc_map->len--;
                memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
                        (rc_map->len - index) * sizeof(struct rc_map_table));
        } else {
-               dev_dbg(&dev->dev, "#%d: %s scan 0x%04x with key 0x%04x\n",
+               dev_dbg(&dev->dev, "#%d: %s scan 0x%04llx with key 0x%04x\n",
                        index,
                        old_keycode == KEY_RESERVED ? "New" : "Replacing",
                        rc_map->scan[index].scancode, new_keycode);
@@ -334,8 +369,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev,
  */
 static unsigned int ir_establish_scancode(struct rc_dev *dev,
                                          struct rc_map *rc_map,
-                                         unsigned int scancode,
-                                         bool resize)
+                                         u64 scancode, bool resize)
 {
        unsigned int i;
 
@@ -394,7 +428,7 @@ static int ir_setkeycode(struct input_dev *idev,
        struct rc_dev *rdev = input_get_drvdata(idev);
        struct rc_map *rc_map = &rdev->rc_map;
        unsigned int index;
-       unsigned int scancode;
+       u64 scancode;
        int retval = 0;
        unsigned long flags;
 
@@ -407,7 +441,7 @@ static int ir_setkeycode(struct input_dev *idev,
                        goto out;
                }
        } else {
-               retval = input_scancode_to_scalar(ke, &scancode);
+               retval = scancode_to_u64(ke, &scancode);
                if (retval)
                        goto out;
 
@@ -434,8 +468,7 @@ out:
  *
  * return:     -ENOMEM if all keycodes could not be inserted, otherwise zero.
  */
-static int ir_setkeytable(struct rc_dev *dev,
-                         const struct rc_map *from)
+static int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from)
 {
        struct rc_map *rc_map = &dev->rc_map;
        unsigned int i, index;
@@ -466,7 +499,7 @@ static int ir_setkeytable(struct rc_dev *dev,
 
 static int rc_map_cmp(const void *key, const void *elt)
 {
-       const unsigned int *scancode = key;
+       const u64 *scancode = key;
        const struct rc_map_table *e = elt;
 
        if (*scancode < e->scancode)
@@ -487,7 +520,7 @@ static int rc_map_cmp(const void *key, const void *elt)
  * return:     index in the table, -1U if not found
  */
 static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
-                                         unsigned int scancode)
+                                         u64 scancode)
 {
        struct rc_map_table *res;
 
@@ -516,7 +549,7 @@ static int ir_getkeycode(struct input_dev *idev,
        struct rc_map_table *entry;
        unsigned long flags;
        unsigned int index;
-       unsigned int scancode;
+       u64 scancode;
        int retval;
 
        spin_lock_irqsave(&rc_map->lock, flags);
@@ -524,7 +557,7 @@ static int ir_getkeycode(struct input_dev *idev,
        if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
                index = ke->index;
        } else {
-               retval = input_scancode_to_scalar(ke, &scancode);
+               retval = scancode_to_u64(ke, &scancode);
                if (retval)
                        goto out;
 
@@ -538,7 +571,6 @@ static int ir_getkeycode(struct input_dev *idev,
                ke->keycode = entry->keycode;
                ke->len = sizeof(entry->scancode);
                memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
-
        } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) {
                /*
                 * We do not really know the valid range of scancodes
@@ -570,7 +602,7 @@ out:
  *
  * return:     the corresponding keycode, or KEY_RESERVED
  */
-u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
+u32 rc_g_keycode_from_table(struct rc_dev *dev, u64 scancode)
 {
        struct rc_map *rc_map = &dev->rc_map;
        unsigned int keycode;
@@ -586,7 +618,7 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
        spin_unlock_irqrestore(&rc_map->lock, flags);
 
        if (keycode != KEY_RESERVED)
-               dev_dbg(&dev->dev, "%s: scancode 0x%04x keycode 0x%02x\n",
+               dev_dbg(&dev->dev, "%s: scancode 0x%04llx keycode 0x%02x\n",
                        dev->device_name, scancode, keycode);
 
        return keycode;
@@ -719,8 +751,11 @@ void rc_repeat(struct rc_dev *dev)
 
        spin_lock_irqsave(&dev->keylock, flags);
 
-       input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
-       input_sync(dev->input_dev);
+       if (dev->last_scancode <= U32_MAX) {
+               input_event(dev->input_dev, EV_MSC, MSC_SCAN,
+                           dev->last_scancode);
+               input_sync(dev->input_dev);
+       }
 
        if (dev->keypressed) {
                dev->keyup_jiffies = jiffies + timeout;
@@ -743,7 +778,7 @@ EXPORT_SYMBOL_GPL(rc_repeat);
  * called with keylock held.
  */
 static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
-                         u32 scancode, u32 keycode, u8 toggle)
+                         u64 scancode, u32 keycode, u8 toggle)
 {
        bool new_event = (!dev->keypressed               ||
                          dev->last_protocol != protocol ||
@@ -761,7 +796,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
        if (new_event && dev->keypressed)
                ir_do_keyup(dev, false);
 
-       input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
+       if (scancode <= U32_MAX)
+               input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
 
        dev->last_protocol = protocol;
        dev->last_scancode = scancode;
@@ -772,7 +808,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
                /* Register a keypress */
                dev->keypressed = true;
 
-               dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
+               dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08llx\n",
                        dev->device_name, keycode, protocol, scancode);
                input_report_key(dev->input_dev, keycode, 1);
 
@@ -809,7 +845,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
  * This routine is used to signal that a key has been pressed on the
  * remote control.
  */
-void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode,
+void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u64 scancode,
                u8 toggle)
 {
        unsigned long flags;
@@ -840,7 +876,7 @@ EXPORT_SYMBOL_GPL(rc_keydown);
  * remote control. The driver must manually call rc_keyup() at a later stage.
  */
 void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol,
-                         u32 scancode, u8 toggle)
+                         u64 scancode, u8 toggle)
 {
        unsigned long flags;
        u32 keycode = rc_g_keycode_from_table(dev, scancode);
index d789d82..f86ef1c 100644 (file)
@@ -147,11 +147,17 @@ static int gs_read_register(struct spi_device *spi, u16 addr, u16 *value)
                {
                        .tx_buf = &buf_addr,
                        .len = 2,
-                       .delay_usecs = 1,
+                       .delay = {
+                               .value = 1,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
                }, {
                        .rx_buf = &buf_value,
                        .len = 2,
-                       .delay_usecs = 1,
+                       .delay = {
+                               .value = 1,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
                },
        };
 
@@ -175,11 +181,17 @@ static int gs_write_register(struct spi_device *spi, u16 addr, u16 value)
                {
                        .tx_buf = &buf_addr,
                        .len = 2,
-                       .delay_usecs = 1,
+                       .delay = {
+                               .value = 1,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
                }, {
                        .tx_buf = &buf_value,
                        .len = 2,
-                       .delay_usecs = 1,
+                       .delay = {
+                               .value = 1,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
                },
        };
 
index 03c2944..e678d3d 100644 (file)
@@ -25,7 +25,6 @@ if MEDIA_ANALOG_TV_SUPPORT
        comment "Analog TV USB devices"
 source "drivers/media/usb/pvrusb2/Kconfig"
 source "drivers/media/usb/hdpvr/Kconfig"
-source "drivers/media/usb/usbvision/Kconfig"
 source "drivers/media/usb/stk1160/Kconfig"
 source "drivers/media/usb/go7007/Kconfig"
 endif
index 21e46b1..169aa07 100644 (file)
@@ -17,7 +17,6 @@ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 obj-$(CONFIG_VIDEO_HDPVR)      += hdpvr/
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_STK1160) += stk1160/
 obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_TM6000) += tm6000/
index d189533..51b8d14 100644 (file)
@@ -1042,7 +1042,7 @@ static int au0828_v4l2_close(struct file *filp)
                dev->streaming_users, dev->users);
 
        mutex_lock(&dev->lock);
-       if (vdev->vfl_type == VFL_TYPE_GRABBER && dev->vid_timeout_running) {
+       if (vdev->vfl_type == VFL_TYPE_VIDEO && dev->vid_timeout_running) {
                /* Cancel timeout thread in case they didn't call streamoff */
                dev->vid_timeout_running = 0;
                del_timer_sync(&dev->vid_timeout);
@@ -2007,7 +2007,7 @@ int au0828_analog_register(struct au0828_dev *dev,
 
        /* Register the v4l2 device */
        video_set_drvdata(&dev->vdev, dev);
-       retval = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
+       retval = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1);
        if (retval != 0) {
                dprintk(1, "unable to register video device (error = %d).\n",
                        retval);
index 039963a..198ddfb 100644 (file)
@@ -511,6 +511,9 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb)
                return ret;
        }
 
+       if (fc_usb->uintf->cur_altsetting->desc.bNumEndpoints < 1)
+               return -ENODEV;
+
        switch (fc_usb->udev->speed) {
        case USB_SPEED_LOW:
                err("cannot handle USB speed because it is too slow.");
@@ -544,9 +547,6 @@ static int flexcop_usb_probe(struct usb_interface *intf,
        struct flexcop_device *fc = NULL;
        int ret;
 
-       if (intf->cur_altsetting->desc.bNumEndpoints < 1)
-               return -ENODEV;
-
        if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) {
                err("out of memory\n");
                return -ENOMEM;
index 9d3d051..e488e78 100644 (file)
@@ -1134,7 +1134,7 @@ int cpia2_register_camera(struct camera_data *cam)
        reset_camera_struct_v4l(cam);
 
        /* register v4l device */
-       if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+       if (video_register_device(&cam->vdev, VFL_TYPE_VIDEO, video_nr) < 0) {
                ERR("video_register_device failed\n");
                return -ENODEV;
        }
index 1aec445..b0cd511 100644 (file)
@@ -1790,7 +1790,7 @@ int cx231xx_417_register(struct cx231xx *dev)
        dev->v4l_device.queue = q;
 
        err = video_register_device(&dev->v4l_device,
-               VFL_TYPE_GRABBER, -1);
+               VFL_TYPE_VIDEO, -1);
        if (err < 0) {
                dprintk(3, "%s: can't register mpeg device\n", dev->name);
                v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl);
index e205f7f..0037b4b 100644 (file)
@@ -147,7 +147,7 @@ static struct tda18271_config pv_tda18271_config = {
        .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
 };
 
-static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = {
+static const struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = {
        .qam_if_khz         = 4000,
        .vsb_if_khz         = 3250,
        .spectral_inversion = 1,
index 69abafa..8bff7d8 100644 (file)
@@ -1785,7 +1785,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
                dev->vdev.device_caps |= V4L2_CAP_TUNER;
 
        /* register v4l2 video video_device */
-       ret = video_register_device(&dev->vdev, VFL_TYPE_GRABBER,
+       ret = video_register_device(&dev->vdev, VFL_TYPE_VIDEO,
                                    video_nr[dev->devno]);
        if (ret) {
                dev_err(dev->dev,
index 0514e87..89a1b20 100644 (file)
@@ -318,14 +318,14 @@ static struct tda10023_config anysee_tda10023_tda18212_config = {
        .deltaf = 0xba02,
 };
 
-static struct tda18212_config anysee_tda18212_config = {
+static const struct tda18212_config anysee_tda18212_config = {
        .if_dvbt_6 = 4150,
        .if_dvbt_7 = 4150,
        .if_dvbt_8 = 4150,
        .if_dvbc = 5000,
 };
 
-static struct tda18212_config anysee_tda18212_config2 = {
+static const struct tda18212_config anysee_tda18212_config2 = {
        .if_dvbt_6 = 3550,
        .if_dvbt_7 = 3700,
        .if_dvbt_8 = 4150,
index 62d3566..fd8b42b 100644 (file)
@@ -486,13 +486,10 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        static u8 obuf[64], ibuf[64];
        int i, read, read_o;
        u16 len;
-       u8 gate = st->i2c_gate;
+       u8 gate;
 
        mutex_lock(&d->i2c_mutex);
 
-       if (gate == 0)
-               gate = 5;
-
        for (i = 0; i < num; i++) {
                read_o = msg[i].flags & I2C_M_RD;
                read = i + 1 < num && msg[i + 1].flags & I2C_M_RD;
index c6881a1..2080f6e 100644 (file)
@@ -552,6 +552,9 @@ tuner_found:
                if (ret)
                        goto err;
 
+               /* slave demod needs some time to wake up */
+               msleep(20);
+
                /* check slave answers */
                ret = rtl28xxu_ctrl_msg(d, &req_mn88472);
                if (ret == 0 && buf[0] == 0x02) {
index 0699f71..001cae6 100644 (file)
@@ -1223,7 +1223,7 @@ static int cxusb_medion_g_tuner(struct file *file, void *fh,
        if (tuner->index != 0)
                return -EINVAL;
 
-       if (vdev->vfl_type == VFL_TYPE_GRABBER)
+       if (vdev->vfl_type == VFL_TYPE_VIDEO)
                tuner->type = V4L2_TUNER_ANALOG_TV;
        else
                tuner->type = V4L2_TUNER_RADIO;
@@ -1259,7 +1259,7 @@ static int cxusb_medion_g_tuner(struct file *file, void *fh,
        if (ret != 0)
                return ret;
 
-       if (vdev->vfl_type == VFL_TYPE_GRABBER)
+       if (vdev->vfl_type == VFL_TYPE_VIDEO)
                strscpy(tuner->name, "TV tuner", sizeof(tuner->name));
        else
                strscpy(tuner->name, "Radio tuner", sizeof(tuner->name));
@@ -1292,7 +1292,7 @@ static int cxusb_medion_s_tuner(struct file *file, void *fh,
         * make sure that cx25840 is in a correct TV / radio mode,
         * since calls above may have changed it for tuner / IF demod
         */
-       if (vdev->vfl_type == VFL_TYPE_GRABBER)
+       if (vdev->vfl_type == VFL_TYPE_VIDEO)
                v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm);
        else
                v4l2_subdev_call(cxdev->cx25840, tuner, s_radio);
@@ -1335,7 +1335,7 @@ static int cxusb_medion_s_frequency(struct file *file, void *fh,
         * make sure that cx25840 is in a correct TV / radio mode,
         * since calls above may have changed it for tuner / IF demod
         */
-       if (vdev->vfl_type == VFL_TYPE_GRABBER)
+       if (vdev->vfl_type == VFL_TYPE_VIDEO)
                v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm);
        else
                v4l2_subdev_call(cxdev->cx25840, tuner, s_radio);
@@ -1564,7 +1564,7 @@ static int cxusb_videoradio_release(struct file *f)
 
        cxusb_vprintk(dvbdev, OPS, "got release\n");
 
-       if (vdev->vfl_type == VFL_TYPE_GRABBER)
+       if (vdev->vfl_type == VFL_TYPE_VIDEO)
                ret = vb2_fop_release(f);
        else
                ret = v4l2_fh_release(f);
@@ -1663,7 +1663,7 @@ static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev)
        cxdev->videodev->lock = &cxdev->dev_lock;
        video_set_drvdata(cxdev->videodev, dvbdev);
 
-       ret = video_register_device(cxdev->videodev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(cxdev->videodev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(&dvbdev->udev->dev,
                        "video device register failed, ret = %d\n", ret);
index e53c58a..ef62dd6 100644 (file)
@@ -818,7 +818,7 @@ int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf)
 
        /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
 
-       if (intf->altsetting[0].desc.bNumEndpoints < rc_ep + 1)
+       if (intf->cur_altsetting->desc.bNumEndpoints < rc_ep + 1)
                return -ENODEV;
 
        purb = usb_alloc_urb(0, GFP_KERNEL);
@@ -838,7 +838,7 @@ int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf)
         * Some devices like the Hauppauge NovaTD model 52009 use an interrupt
         * endpoint, while others use a bulk one.
         */
-       e = &intf->altsetting[0].endpoint[rc_ep].desc;
+       e = &intf->cur_altsetting->endpoint[rc_ep].desc;
        if (usb_endpoint_dir_in(e)) {
                if (usb_endpoint_xfer_bulk(e)) {
                        pipe = usb_rcvbulkpipe(d->udev, rc_ep);
index 8b58450..1007366 100644 (file)
@@ -1524,6 +1524,29 @@ static int m88rs2000_frontend_attach(struct dvb_usb_adapter *adap)
        return -EIO;
 }
 
+static int tt_s2_4600_frontend_attach_probe_demod(struct dvb_usb_device *d,
+                                                 const int probe_addr)
+{
+       struct dw2102_state *state = d->priv;
+
+       state->data[0] = 0x9;
+       state->data[1] = 0x1;
+       state->data[2] = 0x1;
+       state->data[3] = probe_addr;
+       state->data[4] = 0x0;
+
+       if (dvb_usb_generic_rw(d, state->data, 5, state->data, 2, 0) < 0) {
+               err("i2c probe for address 0x%x failed.", probe_addr);
+               return 0;
+       }
+
+       if (state->data[0] != 8) /* fail(7) or error, no device at address */
+               return 0;
+
+       /* probing successful */
+       return 1;
+}
+
 static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
 {
        struct dvb_usb_device *d = adap->dev;
@@ -1533,6 +1556,7 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
        struct i2c_board_info board_info;
        struct m88ds3103_platform_data m88ds3103_pdata = {};
        struct ts2020_config ts2020_config = {};
+       int demod_addr;
 
        mutex_lock(&d->data_mutex);
 
@@ -1570,8 +1594,22 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
        if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
                err("command 0x51 transfer failed.");
 
+       /* probe for demodulator i2c address */
+       demod_addr = -1;
+       if (tt_s2_4600_frontend_attach_probe_demod(d, 0x68))
+               demod_addr = 0x68;
+       else if (tt_s2_4600_frontend_attach_probe_demod(d, 0x69))
+               demod_addr = 0x69;
+       else if (tt_s2_4600_frontend_attach_probe_demod(d, 0x6a))
+               demod_addr = 0x6a;
+
        mutex_unlock(&d->data_mutex);
 
+       if (demod_addr < 0) {
+               err("probing for demodulator failed. Is the external power switched on?");
+               return -ENODEV;
+       }
+
        /* attach demod */
        m88ds3103_pdata.clk = 27000000;
        m88ds3103_pdata.i2c_wr_max = 33;
@@ -1586,8 +1624,11 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
        m88ds3103_pdata.lnb_hv_pol = 1;
        m88ds3103_pdata.lnb_en_pol = 0;
        memset(&board_info, 0, sizeof(board_info));
-       strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
-       board_info.addr = 0x68;
+       if (demod_addr == 0x6a)
+               strscpy(board_info.type, "m88ds3103b", I2C_NAME_SIZE);
+       else
+               strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
+       board_info.addr = demod_addr;
        board_info.platform_data = &m88ds3103_pdata;
        request_module("m88ds3103");
        client = i2c_new_client_device(&d->i2c_adap, &board_info);
index def9cdd..a8c321d 100644 (file)
@@ -2398,6 +2398,20 @@ const struct em28xx_board em28xx_boards[] = {
                .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
        },
        /*
+        * 2013:0259 PCTV DVB-S2 Stick (461e_v2)
+        * Empia EM28178, Montage M88DS3103b, Montage M88TS2022, Allegro A8293
+        */
+       [EM28178_BOARD_PCTV_461E_V2] = {
+               .def_i2c_bus   = 1,
+               .i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE |
+                                EM28XX_I2C_FREQ_400_KHZ,
+               .name          = "PCTV DVB-S2 Stick (461e v2)",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = pctv_461e,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+       },
+       /*
         * 2013:025f PCTV tripleStick (292e).
         * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157
         */
@@ -2696,6 +2710,10 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
        { USB_DEVICE(0x2013, 0x0258),
                        .driver_info = EM28178_BOARD_PCTV_461E },
+       { USB_DEVICE(0x2013, 0x0461),
+                       .driver_info = EM28178_BOARD_PCTV_461E_V2 },
+       { USB_DEVICE(0x2013, 0x0259),
+                       .driver_info = EM28178_BOARD_PCTV_461E_V2 },
        { USB_DEVICE(0x2013, 0x025f),
                        .driver_info = EM28178_BOARD_PCTV_292E },
        { USB_DEVICE(0x2013, 0x0264), /* Hauppauge WinTV-soloHD 292e SE */
index 0ab6c49..fb9cbfa 100644 (file)
@@ -1219,6 +1219,61 @@ static int em28178_dvb_init_pctv_461e(struct em28xx *dev)
        return 0;
 }
 
+static int em28178_dvb_init_pctv_461e_v2(struct em28xx *dev)
+{
+       struct em28xx_dvb *dvb = dev->dvb;
+       struct i2c_adapter *i2c_adapter;
+       struct m88ds3103_platform_data m88ds3103_pdata = {};
+       struct ts2020_config ts2020_config = {};
+       struct a8293_platform_data a8293_pdata = {};
+
+       /* attach demod */
+       m88ds3103_pdata.clk = 27000000;
+       m88ds3103_pdata.i2c_wr_max = 33;
+       m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
+       m88ds3103_pdata.ts_clk = 16000;
+       m88ds3103_pdata.ts_clk_pol = 0;
+       m88ds3103_pdata.agc = 0x99;
+       m88ds3103_pdata.agc_inv = 0;
+       m88ds3103_pdata.spec_inv = 0;
+       dvb->i2c_client_demod = dvb_module_probe("m88ds3103", "m88ds3103b",
+                                                &dev->i2c_adap[dev->def_i2c_bus],
+                                                0x6a, &m88ds3103_pdata);
+
+       if (!dvb->i2c_client_demod)
+               return -ENODEV;
+
+       dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod);
+       i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod);
+
+       /* attach tuner */
+       ts2020_config.fe = dvb->fe[0];
+       dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022",
+                                                i2c_adapter,
+                                                0x60, &ts2020_config);
+       if (!dvb->i2c_client_tuner) {
+               dvb_module_release(dvb->i2c_client_demod);
+               return -ENODEV;
+       }
+
+       /* delegate signal strength measurement to tuner */
+       dvb->fe[0]->ops.read_signal_strength =
+                       dvb->fe[0]->ops.tuner_ops.get_rf_strength;
+
+       /* attach SEC */
+       a8293_pdata.dvb_frontend = dvb->fe[0];
+       dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
+                                              &dev->i2c_adap[dev->def_i2c_bus],
+                                              0x08, &a8293_pdata);
+       if (!dvb->i2c_client_sec) {
+               dvb_module_release(dvb->i2c_client_tuner);
+               dvb_module_release(dvb->i2c_client_demod);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
 static int em28178_dvb_init_pctv_292e(struct em28xx *dev)
 {
        struct em28xx_dvb *dvb = dev->dvb;
@@ -1860,6 +1915,11 @@ static int em28xx_dvb_init(struct em28xx *dev)
                if (result)
                        goto out_free;
                break;
+       case EM28178_BOARD_PCTV_461E_V2:
+               result = em28178_dvb_init_pctv_461e_v2(dev);
+               if (result)
+                       goto out_free;
+               break;
        case EM28178_BOARD_PCTV_292E:
                result = em28178_dvb_init_pctv_292e(dev);
                if (result)
index b0f7390..6b84c34 100644 (file)
@@ -2141,7 +2141,7 @@ static int em28xx_v4l2_open(struct file *filp)
        int ret;
 
        switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                break;
        case VFL_TYPE_VBI:
@@ -2789,7 +2789,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
        }
 
        /* register v4l2 video video_device */
-       ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER,
+       ret = video_register_device(&v4l2->vdev, VFL_TYPE_VIDEO,
                                    video_nr[dev->devno]);
        if (ret) {
                dev_err(&dev->intf->dev,
index 4ecadd5..acbb623 100644 (file)
 #define EM2884_BOARD_TERRATEC_H6                 101
 #define EM2882_BOARD_ZOLID_HYBRID_TV_STICK             102
 #define EM2861_BOARD_MAGIX_VIDEOWANDLER2          103
+#define EM28178_BOARD_PCTV_461E_V2                104
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
index ff2aa05..f889c9d 100644 (file)
@@ -1044,6 +1044,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
        struct go7007_usb *usb;
        const struct go7007_usb_board *board;
        struct usb_device *usbdev = interface_to_usbdev(intf);
+       struct usb_host_endpoint *ep;
        unsigned num_i2c_devs;
        char *name;
        int video_pipe, i, v_urb_len;
@@ -1140,7 +1141,8 @@ static int go7007_usb_probe(struct usb_interface *intf,
        if (usb->intr_urb->transfer_buffer == NULL)
                goto allocfail;
 
-       if (go->board_id == GO7007_BOARDID_SENSORAY_2250)
+       ep = usb->usbdev->ep_in[4];
+       if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)
                usb_fill_bulk_urb(usb->intr_urb, usb->usbdev,
                        usb_rcvbulkpipe(usb->usbdev, 4),
                        usb->intr_urb->transfer_buffer, 2*sizeof(u16),
index 0b3d185..b2edc4d 100644 (file)
@@ -1138,7 +1138,7 @@ int go7007_v4l2_init(struct go7007 *go)
        go7007_s_input(go);
        if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
                go7007_s_std(go);
-       rv = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       rv = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (rv < 0)
                return rv;
        dev_info(go->dev, "registered device %s [v4l2]\n",
index c1b307b..0566e00 100644 (file)
@@ -1555,7 +1555,7 @@ int gspca_dev_probe2(struct usb_interface *intf,
 
        /* init video stuff */
        ret = video_register_device(&gspca_dev->vdev,
-                                 VFL_TYPE_GRABBER,
+                                 VFL_TYPE_VIDEO,
                                  -1);
        if (ret < 0) {
                pr_err("video_register_device err %d\n", ret);
index f417dfc..0afe70a 100644 (file)
@@ -3477,6 +3477,11 @@ static void ov511_mode_init_regs(struct sd *sd)
                return;
        }
 
+       if (alt->desc.bNumEndpoints < 1) {
+               sd->gspca_dev.usb_err = -ENODEV;
+               return;
+       }
+
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
        reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5);
 
@@ -3603,6 +3608,11 @@ static void ov518_mode_init_regs(struct sd *sd)
                return;
        }
 
+       if (alt->desc.bNumEndpoints < 1) {
+               sd->gspca_dev.usb_err = -ENODEV;
+               return;
+       }
+
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
        ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);
 
index 79653d4..95673fc 100644 (file)
@@ -282,6 +282,9 @@ static int stv06xx_start(struct gspca_dev *gspca_dev)
                return -EIO;
        }
 
+       if (alt->desc.bNumEndpoints < 1)
+               return -ENODEV;
+
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
        err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size);
        if (err < 0)
@@ -306,11 +309,21 @@ out:
 
 static int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
 {
+       struct usb_interface_cache *intfc;
        struct usb_host_interface *alt;
        struct sd *sd = (struct sd *) gspca_dev;
 
+       intfc = gspca_dev->dev->actconfig->intf_cache[0];
+
+       if (intfc->num_altsetting < 2)
+               return -ENODEV;
+
+       alt = &intfc->altsetting[1];
+
+       if (alt->desc.bNumEndpoints < 1)
+               return -ENODEV;
+
        /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
-       alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
        alt->endpoint[0].desc.wMaxPacketSize =
                cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
 
@@ -323,6 +336,10 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
        struct usb_host_interface *alt;
        struct sd *sd = (struct sd *) gspca_dev;
 
+       /*
+        * Existence of altsetting and endpoint was verified in
+        * stv06xx_isoc_init()
+        */
        alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
        min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
index 6d10077..ae382b3 100644 (file)
@@ -185,6 +185,10 @@ static int pb0100_start(struct sd *sd)
        alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
        if (!alt)
                return -ENODEV;
+
+       if (alt->desc.bNumEndpoints < 1)
+               return -ENODEV;
+
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 
        /* If we don't have enough bandwidth use a lower framerate */
index 934a90b..c579b10 100644 (file)
@@ -1442,6 +1442,9 @@ static int cit_get_packet_size(struct gspca_dev *gspca_dev)
                return -EIO;
        }
 
+       if (alt->desc.bNumEndpoints < 1)
+               return -ENODEV;
+
        return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
 }
 
@@ -2626,6 +2629,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
 static int sd_isoc_init(struct gspca_dev *gspca_dev)
 {
+       struct usb_interface_cache *intfc;
        struct usb_host_interface *alt;
        int max_packet_size;
 
@@ -2641,8 +2645,17 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
                break;
        }
 
+       intfc = gspca_dev->dev->actconfig->intf_cache[0];
+
+       if (intfc->num_altsetting < 2)
+               return -ENODEV;
+
+       alt = &intfc->altsetting[1];
+
+       if (alt->desc.bNumEndpoints < 1)
+               return -ENODEV;
+
        /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
-       alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
        alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
 
        return 0;
@@ -2665,6 +2678,9 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev)
                break;
        }
 
+       /*
+        * Existence of altsetting and endpoint was verified in sd_isoc_init()
+        */
        alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
        packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
        if (packet_size <= min_packet_size)
index bad71d8..563128d 100644 (file)
@@ -1238,7 +1238,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent,
        dev->video_dev.v4l2_dev = &dev->v4l2_dev;
        video_set_drvdata(&dev->video_dev, dev);
 
-       res = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, devnum);
+       res = video_register_device(&dev->video_dev, VFL_TYPE_VIDEO, devnum);
        if (res < 0) {
                v4l2_err(&dev->v4l2_dev, "video_device registration failed\n");
                goto error;
index afda438..0655aa9 100644 (file)
@@ -635,8 +635,6 @@ static void pulse8_cec_adap_free(struct cec_adapter *adap)
        cancel_delayed_work_sync(&pulse8->ping_eeprom_work);
        cancel_work_sync(&pulse8->irq_work);
        cancel_work_sync(&pulse8->tx_work);
-       serio_close(pulse8->serio);
-       serio_set_drvdata(pulse8->serio, NULL);
        kfree(pulse8);
 }
 
@@ -652,6 +650,9 @@ static void pulse8_disconnect(struct serio *serio)
        struct pulse8 *pulse8 = serio_get_drvdata(serio);
 
        cec_unregister_adapter(pulse8->adap);
+       pulse8->serio = NULL;
+       serio_set_drvdata(serio, NULL);
+       serio_close(serio);
 }
 
 static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
@@ -840,6 +841,8 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv)
        serio_set_drvdata(serio, pulse8);
        INIT_WORK(&pulse8->irq_work, pulse8_irq_work_handler);
        INIT_WORK(&pulse8->tx_work, pulse8_tx_work_handler);
+       INIT_DELAYED_WORK(&pulse8->ping_eeprom_work,
+                         pulse8_ping_eeprom_work_handler);
        mutex_init(&pulse8->lock);
        spin_lock_init(&pulse8->msg_lock);
        pulse8->config_pending = false;
@@ -865,17 +868,16 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv)
                pulse8->restoring_config = true;
        }
 
-       INIT_DELAYED_WORK(&pulse8->ping_eeprom_work,
-                         pulse8_ping_eeprom_work_handler);
        schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD);
 
        return 0;
 
 close_serio:
+       pulse8->serio = NULL;
+       serio_set_drvdata(serio, NULL);
        serio_close(serio);
 delete_adap:
        cec_delete_adapter(pulse8->adap);
-       serio_set_drvdata(serio, NULL);
 free_device:
        kfree(pulse8);
        return err;
index eaa08c7..9657c18 100644 (file)
@@ -1196,7 +1196,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
        hdw = vp->channel.mc_head->hdw;
        dip->v4l_type = v4l_type;
        switch (v4l_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                dip->stream = &vp->channel.mc_head->video_stream;
                dip->config = pvr2_config_mpeg;
                dip->minor_type = pvr2_v4l_type_video;
@@ -1276,7 +1276,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
        /* register streams */
        vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
        if (!vp->dev_video) goto fail;
-       pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
+       pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_VIDEO);
        if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
            (1 << PVR2_CVAL_INPUT_RADIO)) {
                vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
index 9b76cf1..d57b8b7 100644 (file)
@@ -1116,7 +1116,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        pdev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
                                 V4L2_CAP_READWRITE;
 
-       rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1);
+       rc = video_register_device(&pdev->vdev, VFL_TYPE_VIDEO, -1);
        if (rc < 0) {
                PWC_ERROR("Failed to register as video device (%d).\n", rc);
                goto err_unregister_v4l2_dev;
index 329ec80..4af55e2 100644 (file)
@@ -1649,11 +1649,11 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                video_set_drvdata(&vc->vdev, vc);
                if (video_nr == -1)
                        ret = video_register_device(&vc->vdev,
-                                                   VFL_TYPE_GRABBER,
+                                                   VFL_TYPE_VIDEO,
                                                    video_nr);
                else
                        ret = video_register_device(&vc->vdev,
-                                                   VFL_TYPE_GRABBER,
+                                                   VFL_TYPE_VIDEO,
                                                    cur_nr + i);
 
                if (ret) {
index bcd14c6..6a4eb61 100644 (file)
@@ -830,7 +830,7 @@ int stk1160_video_register(struct stk1160 *dev)
                        dev->norm);
 
        video_set_drvdata(&dev->vdev, dev);
-       rc = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
+       rc = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1);
        if (rc < 0) {
                stk1160_err("video_register_device failed (%d)\n", rc);
                return rc;
index b22501f..a45d464 100644 (file)
@@ -1254,7 +1254,7 @@ static int stk_register_video_device(struct stk_camera *dev)
        dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
                                V4L2_CAP_STREAMING;
        video_set_drvdata(&dev->vdev, dev);
-       err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
+       err = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1);
        if (err)
                pr_err("v4l registration failed\n");
        else
index c07a81a..bfba06e 100644 (file)
@@ -1300,7 +1300,7 @@ static int __tm6000_open(struct file *file)
                video_device_node_name(vdev));
 
        switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                break;
        case VFL_TYPE_VBI:
@@ -1639,7 +1639,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev)
        INIT_LIST_HEAD(&dev->vidq.active);
        INIT_LIST_HEAD(&dev->vidq.queued);
 
-       ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, video_nr);
+       ret = video_register_device(&dev->vfd, VFL_TYPE_VIDEO, video_nr);
 
        if (ret < 0) {
                printk(KERN_INFO "%s: can't register video device\n",
index 5095c38..ee9c656 100644 (file)
@@ -56,7 +56,7 @@ int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
 
                ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       value, index, NULL, 0, 0);
+                       value, index, NULL, 0, USB_CTRL_GET_TIMEOUT);
                if (ret < 0)
                        return ret;
        }
index 3d9284a..c89efcd 100644 (file)
@@ -800,7 +800,8 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl)
                ret = usb_control_msg(usbtv->udev,
                        usb_rcvctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0, USBTV_BASE + 0x0244, (void *)data, 3, 0);
+                       0, USBTV_BASE + 0x0244, (void *)data, 3,
+                       USB_CTRL_GET_TIMEOUT);
                if (ret < 0)
                        goto error;
        }
@@ -851,7 +852,7 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl)
        ret = usb_control_msg(usbtv->udev, usb_sndctrlpipe(usbtv->udev, 0),
                        USBTV_CONTROL_REG,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0, index, (void *)data, size, 0);
+                       0, index, (void *)data, size, USB_CTRL_SET_TIMEOUT);
 
 error:
        if (ret < 0)
@@ -940,7 +941,7 @@ int usbtv_video_init(struct usbtv *usbtv)
        usbtv->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
                                  V4L2_CAP_STREAMING;
        video_set_drvdata(&usbtv->vdev, usbtv);
-       ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&usbtv->vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                dev_warn(usbtv->dev, "Could not register video device\n");
                goto vdev_fail;
index 9988355..431d86e 100644 (file)
@@ -2014,7 +2014,7 @@ int uvc_register_video_device(struct uvc_device *dev,
         */
        video_set_drvdata(vdev, stream);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                uvc_printk(KERN_ERR, "Failed to register %s device (%d).\n",
                           v4l2_type_names[type], ret);
index 57dbcc8..8c67093 100644 (file)
@@ -1516,7 +1516,7 @@ static int zr364xx_probe(struct usb_interface *intf,
                                    V4L2_FIELD_NONE,
                                    sizeof(struct zr364xx_buffer), cam, &cam->lock);
 
-       err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+       err = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1);
        if (err) {
                dev_err(&udev->dev, "video_register_device failed\n");
                goto fail;
index 2928c5e..93d33d1 100644 (file)
@@ -4296,10 +4296,17 @@ void v4l2_ctrl_request_complete(struct media_request *req,
                        continue;
 
                v4l2_ctrl_lock(ctrl);
-               if (ref->req)
+               if (ref->req) {
                        ptr_to_ptr(ctrl, ref->req->p_req, ref->p_req);
-               else
+               } else {
                        ptr_to_ptr(ctrl, ctrl->p_cur, ref->p_req);
+                       /*
+                        * Set ref->req to ensure that when userspace wants to
+                        * obtain the controls of this request it will take
+                        * this value and not the current value of the control.
+                        */
+                       ref->req = ref;
+               }
                v4l2_ctrl_unlock(ctrl);
        }
 
index da42d17..97b6a3a 100644 (file)
@@ -542,13 +542,13 @@ static void determine_valid_ioctls(struct video_device *vdev)
                              V4L2_CAP_META_OUTPUT;
        DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
        const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
-       bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER &&
+       bool is_vid = vdev->vfl_type == VFL_TYPE_VIDEO &&
                      (vdev->device_caps & vid_caps);
        bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI;
        bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO;
        bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR;
        bool is_tch = vdev->vfl_type == VFL_TYPE_TOUCH;
-       bool is_meta = vdev->vfl_type == VFL_TYPE_GRABBER &&
+       bool is_meta = vdev->vfl_type == VFL_TYPE_VIDEO &&
                       (vdev->device_caps & meta_caps);
        bool is_rx = vdev->vfl_dir != VFL_DIR_TX;
        bool is_tx = vdev->vfl_dir != VFL_DIR_RX;
@@ -783,7 +783,7 @@ static int video_register_media_controller(struct video_device *vdev)
        vdev->entity.function = MEDIA_ENT_F_UNKNOWN;
 
        switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                intf_type = MEDIA_INTF_T_V4L_VIDEO;
                vdev->entity.function = MEDIA_ENT_F_IO_V4L;
                break;
@@ -891,7 +891,7 @@ int __video_register_device(struct video_device *vdev,
 
        /* Part 1: check device type */
        switch (type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                name_base = "video";
                break;
        case VFL_TYPE_VBI:
@@ -935,7 +935,7 @@ int __video_register_device(struct video_device *vdev,
         * of 128-191 and just pick the first free minor there
         * (new style). */
        switch (type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                minor_offset = 0;
                minor_cnt = 64;
                break;
index 63d6b14..c699412 100644 (file)
@@ -111,9 +111,6 @@ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
                                struct v4l2_subdev *sd)
 {
-#if defined(CONFIG_MEDIA_CONTROLLER)
-       struct media_entity *entity = &sd->entity;
-#endif
        int err;
 
        /* Check for valid input */
@@ -143,7 +140,7 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
 #if defined(CONFIG_MEDIA_CONTROLLER)
        /* Register the entity. */
        if (v4l2_dev->mdev) {
-               err = media_device_register_entity(v4l2_dev->mdev, entity);
+               err = media_device_register_entity(v4l2_dev->mdev, &sd->entity);
                if (err < 0)
                        goto error_module;
        }
@@ -163,7 +160,7 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
 
 error_unregister:
 #if defined(CONFIG_MEDIA_CONTROLLER)
-       media_device_unregister_entity(entity);
+       media_device_unregister_entity(&sd->entity);
 #endif
 error_module:
        if (!sd->owner_v4l2_dev)
@@ -179,6 +176,7 @@ static void v4l2_subdev_release(struct v4l2_subdev *sd)
 
        if (sd->internal_ops && sd->internal_ops->release)
                sd->internal_ops->release(sd);
+       sd->devnode = NULL;
        module_put(owner);
 }
 
index 6ece432..97f0f8b 100644 (file)
@@ -557,33 +557,28 @@ int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
 
-int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
+int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
                           struct v4l2_fwnode_link *link)
 {
-       const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
-       struct fwnode_handle *fwnode;
+       struct fwnode_endpoint fwep;
 
        memset(link, 0, sizeof(*link));
 
-       fwnode = fwnode_get_parent(__fwnode);
-       fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
-       fwnode = fwnode_get_next_parent(fwnode);
-       if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
-               fwnode = fwnode_get_next_parent(fwnode);
-       link->local_node = fwnode;
+       fwnode_graph_parse_endpoint(fwnode, &fwep);
+       link->local_id = fwep.id;
+       link->local_port = fwep.port;
+       link->local_node = fwnode_graph_get_port_parent(fwnode);
 
-       fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
+       fwnode = fwnode_graph_get_remote_endpoint(fwnode);
        if (!fwnode) {
                fwnode_handle_put(fwnode);
                return -ENOLINK;
        }
 
-       fwnode = fwnode_get_parent(fwnode);
-       fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
-       fwnode = fwnode_get_next_parent(fwnode);
-       if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
-               fwnode = fwnode_get_next_parent(fwnode);
-       link->remote_node = fwnode;
+       fwnode_graph_parse_endpoint(fwnode, &fwep);
+       link->remote_id = fwep.id;
+       link->remote_port = fwep.port;
+       link->remote_node = fwnode_graph_get_port_parent(fwnode);
 
        return 0;
 }
@@ -596,6 +591,171 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
 
+static const struct v4l2_fwnode_connector_conv {
+       enum v4l2_connector_type type;
+       const char *compatible;
+} connectors[] = {
+       {
+               .type = V4L2_CONN_COMPOSITE,
+               .compatible = "composite-video-connector",
+       }, {
+               .type = V4L2_CONN_SVIDEO,
+               .compatible = "svideo-connector",
+       },
+};
+
+static enum v4l2_connector_type
+v4l2_fwnode_string_to_connector_type(const char *con_str)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(connectors); i++)
+               if (!strcmp(con_str, connectors[i].compatible))
+                       return connectors[i].type;
+
+       return V4L2_CONN_UNKNOWN;
+}
+
+static void
+v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
+                                  struct v4l2_fwnode_connector *vc)
+{
+       u32 stds;
+       int ret;
+
+       ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
+
+       /* The property is optional. */
+       vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
+}
+
+void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
+{
+       struct v4l2_connector_link *link, *tmp;
+
+       if (IS_ERR_OR_NULL(connector) || connector->type == V4L2_CONN_UNKNOWN)
+               return;
+
+       list_for_each_entry_safe(link, tmp, &connector->links, head) {
+               v4l2_fwnode_put_link(&link->fwnode_link);
+               list_del(&link->head);
+               kfree(link);
+       }
+
+       kfree(connector->label);
+       connector->label = NULL;
+       connector->type = V4L2_CONN_UNKNOWN;
+}
+EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
+
+static enum v4l2_connector_type
+v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode)
+{
+       const char *type_name;
+       int err;
+
+       if (!fwnode)
+               return V4L2_CONN_UNKNOWN;
+
+       /* The connector-type is stored within the compatible string. */
+       err = fwnode_property_read_string(fwnode, "compatible", &type_name);
+       if (err)
+               return V4L2_CONN_UNKNOWN;
+
+       return v4l2_fwnode_string_to_connector_type(type_name);
+}
+
+int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode,
+                               struct v4l2_fwnode_connector *connector)
+{
+       struct fwnode_handle *connector_node;
+       enum v4l2_connector_type connector_type;
+       const char *label;
+       int err;
+
+       if (!fwnode)
+               return -EINVAL;
+
+       memset(connector, 0, sizeof(*connector));
+
+       INIT_LIST_HEAD(&connector->links);
+
+       connector_node = fwnode_graph_get_port_parent(fwnode);
+       connector_type = v4l2_fwnode_get_connector_type(connector_node);
+       if (connector_type == V4L2_CONN_UNKNOWN) {
+               fwnode_handle_put(connector_node);
+               connector_node = fwnode_graph_get_remote_port_parent(fwnode);
+               connector_type = v4l2_fwnode_get_connector_type(connector_node);
+       }
+
+       if (connector_type == V4L2_CONN_UNKNOWN) {
+               pr_err("Unknown connector type\n");
+               err = -ENOTCONN;
+               goto out;
+       }
+
+       connector->type = connector_type;
+       connector->name = fwnode_get_name(connector_node);
+       err = fwnode_property_read_string(connector_node, "label", &label);
+       connector->label = err ? NULL : kstrdup_const(label, GFP_KERNEL);
+
+       /* Parse the connector specific properties. */
+       switch (connector->type) {
+       case V4L2_CONN_COMPOSITE:
+       case V4L2_CONN_SVIDEO:
+               v4l2_fwnode_connector_parse_analog(connector_node, connector);
+               break;
+       /* Avoid compiler warnings */
+       case V4L2_CONN_UNKNOWN:
+               break;
+       }
+
+out:
+       fwnode_handle_put(connector_node);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse);
+
+int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
+                                  struct v4l2_fwnode_connector *connector)
+{
+       struct fwnode_handle *connector_ep;
+       struct v4l2_connector_link *link;
+       int err;
+
+       if (!fwnode || !connector || connector->type == V4L2_CONN_UNKNOWN)
+               return -EINVAL;
+
+       connector_ep = fwnode_graph_get_remote_endpoint(fwnode);
+       if (!connector_ep)
+               return -ENOTCONN;
+
+       link = kzalloc(sizeof(*link), GFP_KERNEL);
+       if (!link) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       err = v4l2_fwnode_parse_link(connector_ep, &link->fwnode_link);
+       if (err)
+               goto err;
+
+       fwnode_handle_put(connector_ep);
+
+       list_add(&link->head, &connector->links);
+       connector->nr_of_links++;
+
+       return 0;
+
+err:
+       kfree(link);
+       fwnode_handle_put(connector_ep);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
+
 static int
 v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
                                          struct v4l2_async_notifier *notifier,
index 5bf99e7..b4acca7 100644 (file)
@@ -74,10 +74,10 @@ struct v4l2_subdev
 
        /* Create the i2c client */
        if (info->addr == 0 && probe_addrs)
-               client = i2c_new_probed_device(adapter, info, probe_addrs,
-                                              NULL);
+               client = i2c_new_scanned_device(adapter, info, probe_addrs,
+                                               NULL);
        else
-               client = i2c_new_device(adapter, info);
+               client = i2c_new_client_device(adapter, info);
 
        /*
         * Note: by loading the module first we are certain that c->driver
@@ -88,7 +88,7 @@ struct v4l2_subdev
         * want to use the i2c device, so explicitly loading the module
         * is the best alternative.
         */
-       if (!client || !client->dev.driver)
+       if (!i2c_client_has_driver(client))
                goto error;
 
        /* Lock the module so we can safely get the v4l2_subdev pointer */
@@ -110,7 +110,7 @@ error:
         * If we have a client but no subdev, then something went wrong and
         * we must unregister the client.
         */
-       if (client && !sd)
+       if (!IS_ERR(client) && !sd)
                i2c_unregister_device(client);
        return sd;
 }
index aaf83e2..b2ef8e6 100644 (file)
@@ -941,12 +941,12 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
                              V4L2_CAP_META_OUTPUT;
        struct video_device *vfd = video_devdata(file);
        const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
-       bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER &&
+       bool is_vid = vfd->vfl_type == VFL_TYPE_VIDEO &&
                      (vfd->device_caps & vid_caps);
        bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI;
        bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR;
        bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH;
-       bool is_meta = vfd->vfl_type == VFL_TYPE_GRABBER &&
+       bool is_meta = vfd->vfl_type == VFL_TYPE_VIDEO &&
                       (vfd->device_caps & meta_caps);
        bool is_rx = vfd->vfl_dir != VFL_DIR_TX;
        bool is_tx = vfd->vfl_dir != VFL_DIR_RX;
@@ -1222,6 +1222,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
        case V4L2_PIX_FMT_Y6:           descr = "6-bit Greyscale"; break;
        case V4L2_PIX_FMT_Y10:          descr = "10-bit Greyscale"; break;
        case V4L2_PIX_FMT_Y12:          descr = "12-bit Greyscale"; break;
+       case V4L2_PIX_FMT_Y14:          descr = "14-bit Greyscale"; break;
        case V4L2_PIX_FMT_Y16:          descr = "16-bit Greyscale"; break;
        case V4L2_PIX_FMT_Y16_BE:       descr = "16-bit Greyscale BE"; break;
        case V4L2_PIX_FMT_Y10BPACK:     descr = "10-bit Greyscale (Packed)"; break;
@@ -1306,6 +1307,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
        case V4L2_PIX_FMT_SGBRG12P:     descr = "12-bit Bayer GBGB/RGRG Packed"; break;
        case V4L2_PIX_FMT_SGRBG12P:     descr = "12-bit Bayer GRGR/BGBG Packed"; break;
        case V4L2_PIX_FMT_SRGGB12P:     descr = "12-bit Bayer RGRG/GBGB Packed"; break;
+       case V4L2_PIX_FMT_SBGGR14:      descr = "14-bit Bayer BGBG/GRGR"; break;
+       case V4L2_PIX_FMT_SGBRG14:      descr = "14-bit Bayer GBGB/RGRG"; break;
+       case V4L2_PIX_FMT_SGRBG14:      descr = "14-bit Bayer GRGR/BGBG"; break;
+       case V4L2_PIX_FMT_SRGGB14:      descr = "14-bit Bayer RGRG/GBGB"; break;
        case V4L2_PIX_FMT_SBGGR14P:     descr = "14-bit Bayer BGBG/GRGR Packed"; break;
        case V4L2_PIX_FMT_SGBRG14P:     descr = "14-bit Bayer GBGB/RGRG Packed"; break;
        case V4L2_PIX_FMT_SGRBG14P:     descr = "14-bit Bayer GRGR/BGBG Packed"; break;
index 014a2a9..0fffdd3 100644 (file)
@@ -321,7 +321,7 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source);
  * use_count field stores the total number of users of all video device nodes
  * in the pipeline.
  *
- * The v4l2_pipeline_pm_use() function must be called in the open() and
+ * The v4l2_pipeline_pm_{get, put}() functions must be called in the open() and
  * close() handlers of video device nodes. It increments or decrements the use
  * count of all subdev entities in the pipeline.
  *
@@ -423,7 +423,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change,
        return ret;
 }
 
-int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
+static int v4l2_pipeline_pm_use(struct media_entity *entity, unsigned int use)
 {
        struct media_device *mdev = entity->graph_obj.mdev;
        int change = use ? 1 : -1;
@@ -444,7 +444,19 @@ int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use);
+
+int v4l2_pipeline_pm_get(struct media_entity *entity)
+{
+       return v4l2_pipeline_pm_use(entity, 1);
+}
+EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_get);
+
+void v4l2_pipeline_pm_put(struct media_entity *entity)
+{
+       /* Powering off entities shouldn't fail. */
+       WARN_ON(v4l2_pipeline_pm_use(entity, 0));
+}
+EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_put);
 
 int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
                              unsigned int notification)
index 1afd9c6..8986c31 100644 (file)
@@ -340,6 +340,11 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev,
                m2m_ctx->new_frame = !dst->vb2_buf.copied_timestamp ||
                        dst->vb2_buf.timestamp != src->vb2_buf.timestamp;
 
+       if (m2m_ctx->has_stopped) {
+               dprintk("Device has stopped\n");
+               goto job_unlock;
+       }
+
        if (m2m_dev->m2m_ops->job_ready
                && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) {
                dprintk("Driver not ready\n");
@@ -556,6 +561,140 @@ int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf);
 
+/*
+ * This will add the LAST flag and mark the buffer management
+ * state as stopped.
+ * This is called when the last capture buffer must be flagged as LAST
+ * in draining mode from the encoder/decoder driver buf_queue() callback
+ * or from v4l2_update_last_buf_state() when a capture buffer is available.
+ */
+void v4l2_m2m_last_buffer_done(struct v4l2_m2m_ctx *m2m_ctx,
+                              struct vb2_v4l2_buffer *vbuf)
+{
+       vbuf->flags |= V4L2_BUF_FLAG_LAST;
+       vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
+
+       v4l2_m2m_mark_stopped(m2m_ctx);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_last_buffer_done);
+
+/* When stop command is issued, update buffer management state */
+static int v4l2_update_last_buf_state(struct v4l2_m2m_ctx *m2m_ctx)
+{
+       struct vb2_v4l2_buffer *next_dst_buf;
+
+       if (m2m_ctx->is_draining)
+               return -EBUSY;
+
+       if (m2m_ctx->has_stopped)
+               return 0;
+
+       m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx);
+       m2m_ctx->is_draining = true;
+
+       /*
+        * The processing of the last output buffer queued before
+        * the STOP command is expected to mark the buffer management
+        * state as stopped with v4l2_m2m_mark_stopped().
+        */
+       if (m2m_ctx->last_src_buf)
+               return 0;
+
+       /*
+        * In case the output queue is empty, try to mark the last capture
+        * buffer as LAST.
+        */
+       next_dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx);
+       if (!next_dst_buf) {
+               /*
+                * Wait for the next queued one in encoder/decoder driver
+                * buf_queue() callback using the v4l2_m2m_dst_buf_is_last()
+                * helper or in v4l2_m2m_qbuf() if encoder/decoder is not yet
+                * streaming.
+                */
+               m2m_ctx->next_buf_last = true;
+               return 0;
+       }
+
+       v4l2_m2m_last_buffer_done(m2m_ctx, next_dst_buf);
+
+       return 0;
+}
+
+/*
+ * Updates the encoding/decoding buffer management state, should
+ * be called from encoder/decoder drivers start_streaming()
+ */
+void v4l2_m2m_update_start_streaming_state(struct v4l2_m2m_ctx *m2m_ctx,
+                                          struct vb2_queue *q)
+{
+       /* If start streaming again, untag the last output buffer */
+       if (V4L2_TYPE_IS_OUTPUT(q->type))
+               m2m_ctx->last_src_buf = NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_update_start_streaming_state);
+
+/*
+ * Updates the encoding/decoding buffer management state, should
+ * be called from encoder/decoder driver stop_streaming()
+ */
+void v4l2_m2m_update_stop_streaming_state(struct v4l2_m2m_ctx *m2m_ctx,
+                                         struct vb2_queue *q)
+{
+       if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               /*
+                * If in draining state, either mark next dst buffer as
+                * done or flag next one to be marked as done either
+                * in encoder/decoder driver buf_queue() callback using
+                * the v4l2_m2m_dst_buf_is_last() helper or in v4l2_m2m_qbuf()
+                * if encoder/decoder is not yet streaming
+                */
+               if (m2m_ctx->is_draining) {
+                       struct vb2_v4l2_buffer *next_dst_buf;
+
+                       m2m_ctx->last_src_buf = NULL;
+                       next_dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx);
+                       if (!next_dst_buf)
+                               m2m_ctx->next_buf_last = true;
+                       else
+                               v4l2_m2m_last_buffer_done(m2m_ctx,
+                                                         next_dst_buf);
+               }
+       } else {
+               v4l2_m2m_clear_state(m2m_ctx);
+       }
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_update_stop_streaming_state);
+
+static void v4l2_m2m_force_last_buf_done(struct v4l2_m2m_ctx *m2m_ctx,
+                                        struct vb2_queue *q)
+{
+       struct vb2_buffer *vb;
+       struct vb2_v4l2_buffer *vbuf;
+       unsigned int i;
+
+       if (WARN_ON(q->is_output))
+               return;
+       if (list_empty(&q->queued_list))
+               return;
+
+       vb = list_first_entry(&q->queued_list, struct vb2_buffer, queued_entry);
+       for (i = 0; i < vb->num_planes; i++)
+               vb2_set_plane_payload(vb, i, 0);
+
+       /*
+        * Since the buffer hasn't been queued to the ready queue,
+        * mark is active and owned before marking it LAST and DONE
+        */
+       vb->state = VB2_BUF_STATE_ACTIVE;
+       atomic_inc(&q->owned_by_drv_count);
+
+       vbuf = to_vb2_v4l2_buffer(vb);
+       vbuf->field = V4L2_FIELD_NONE;
+
+       v4l2_m2m_last_buffer_done(m2m_ctx, vbuf);
+}
+
 int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                  struct v4l2_buffer *buf)
 {
@@ -570,11 +709,25 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                        __func__);
                return -EPERM;
        }
+
        ret = vb2_qbuf(vq, vdev->v4l2_dev->mdev, buf);
-       if (!ret && !(buf->flags & V4L2_BUF_FLAG_IN_REQUEST))
+       if (ret)
+               return ret;
+
+       /*
+        * If the capture queue is streaming, but streaming hasn't started
+        * on the device, but was asked to stop, mark the previously queued
+        * buffer as DONE with LAST flag since it won't be queued on the
+        * device.
+        */
+       if (!V4L2_TYPE_IS_OUTPUT(vq->type) &&
+           vb2_is_streaming(vq) && !vb2_start_streaming_called(vq) &&
+          (v4l2_m2m_has_stopped(m2m_ctx) || v4l2_m2m_dst_buf_is_last(m2m_ctx)))
+               v4l2_m2m_force_last_buf_done(m2m_ctx, vq);
+       else if (!(buf->flags & V4L2_BUF_FLAG_IN_REQUEST))
                v4l2_m2m_try_schedule(m2m_ctx);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf);
 
@@ -880,12 +1033,12 @@ int v4l2_m2m_register_media_controller(struct v4l2_m2m_dev *m2m_dev,
                goto err_rel_entity1;
 
        /* Connect the three entities */
-       ret = media_create_pad_link(m2m_dev->source, 0, &m2m_dev->proc, 1,
+       ret = media_create_pad_link(m2m_dev->source, 0, &m2m_dev->proc, 0,
                        MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
        if (ret)
                goto err_rel_entity2;
 
-       ret = media_create_pad_link(&m2m_dev->proc, 0, &m2m_dev->sink, 0,
+       ret = media_create_pad_link(&m2m_dev->proc, 1, &m2m_dev->sink, 0,
                        MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
        if (ret)
                goto err_rm_links0;
@@ -1225,6 +1378,70 @@ int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh,
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_decoder_cmd);
 
+/*
+ * Updates the encoding state on ENC_CMD_STOP/ENC_CMD_START
+ * Should be called from the encoder driver encoder_cmd() callback
+ */
+int v4l2_m2m_encoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+                        struct v4l2_encoder_cmd *ec)
+{
+       if (ec->cmd != V4L2_ENC_CMD_STOP && ec->cmd != V4L2_ENC_CMD_START)
+               return -EINVAL;
+
+       if (ec->cmd == V4L2_ENC_CMD_STOP)
+               return v4l2_update_last_buf_state(m2m_ctx);
+
+       if (m2m_ctx->is_draining)
+               return -EBUSY;
+
+       if (m2m_ctx->has_stopped)
+               m2m_ctx->has_stopped = false;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_encoder_cmd);
+
+/*
+ * Updates the decoding state on DEC_CMD_STOP/DEC_CMD_START
+ * Should be called from the decoder driver decoder_cmd() callback
+ */
+int v4l2_m2m_decoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+                        struct v4l2_decoder_cmd *dc)
+{
+       if (dc->cmd != V4L2_DEC_CMD_STOP && dc->cmd != V4L2_DEC_CMD_START)
+               return -EINVAL;
+
+       if (dc->cmd == V4L2_DEC_CMD_STOP)
+               return v4l2_update_last_buf_state(m2m_ctx);
+
+       if (m2m_ctx->is_draining)
+               return -EBUSY;
+
+       if (m2m_ctx->has_stopped)
+               m2m_ctx->has_stopped = false;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_decoder_cmd);
+
+int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *priv,
+                              struct v4l2_encoder_cmd *ec)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_encoder_cmd(file, fh->m2m_ctx, ec);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_encoder_cmd);
+
+int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *priv,
+                              struct v4l2_decoder_cmd *dc)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_decoder_cmd(file, fh->m2m_ctx, dc);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_decoder_cmd);
+
 int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *fh,
                                             struct v4l2_decoder_cmd *dc)
 {
index 25e5f24..5bdf574 100644 (file)
@@ -2112,8 +2112,8 @@ exit_done:
        return status;
 }
 
-static int altera_get_note(u8 *p, s32 program_size,
-                       s32 *offset, char *key, char *value, int length)
+static int altera_get_note(u8 *p, s32 program_size, s32 *offset,
+                          char *key, char *value, int keylen, int vallen)
 /*
  * Gets key and value of NOTE fields in the JBC file.
  * Can be called in two modes:  if offset pointer is NULL,
@@ -2170,7 +2170,7 @@ static int altera_get_note(u8 *p, s32 program_size,
                                                &p[note_table + (8 * i) + 4])];
 
                                if (value != NULL)
-                                       strlcpy(value, value_ptr, length);
+                                       strlcpy(value, value_ptr, vallen);
 
                        }
                }
@@ -2189,13 +2189,13 @@ static int altera_get_note(u8 *p, s32 program_size,
                                strlcpy(key, &p[note_strings +
                                                get_unaligned_be32(
                                                &p[note_table + (8 * i)])],
-                                       length);
+                                       keylen);
 
                        if (value != NULL)
                                strlcpy(value, &p[note_strings +
                                                get_unaligned_be32(
                                                &p[note_table + (8 * i) + 4])],
-                                       length);
+                                       vallen);
 
                        *offset = i + 1;
                }
@@ -2449,7 +2449,7 @@ int altera_init(struct altera_config *config, const struct firmware *fw)
                        __func__, (format_version == 2) ? "Jam STAPL" :
                                                "pre-standardized Jam 1.1");
                while (altera_get_note((u8 *)fw->data, fw->size,
-                                       &offset, key, value, 256) == 0)
+                                       &offset, key, value, 32, 256) == 0)
                        printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n",
                                        __func__, key, value);
        }
index 4feed29..423fecc 100644 (file)
@@ -394,7 +394,7 @@ static const struct pcr_ops rts522a_pcr_ops = {
 void rts522a_init_params(struct rtsx_pcr *pcr)
 {
        rts5227_init_params(pcr);
-
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(20, 20, 11);
        pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3;
 
        pcr->option.ocp_en = 1;
index db936e4..1a81cda 100644 (file)
@@ -618,6 +618,7 @@ static const struct pcr_ops rts524a_pcr_ops = {
 void rts524a_init_params(struct rtsx_pcr *pcr)
 {
        rts5249_init_params(pcr);
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 29, 11);
        pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
        pcr->option.ltr_l1off_snooze_sspwrgate =
                LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
@@ -733,6 +734,7 @@ static const struct pcr_ops rts525a_pcr_ops = {
 void rts525a_init_params(struct rtsx_pcr *pcr)
 {
        rts5249_init_params(pcr);
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(25, 29, 11);
        pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
        pcr->option.ltr_l1off_snooze_sspwrgate =
                LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
index 4214f02..711054e 100644 (file)
@@ -662,7 +662,7 @@ void rts5260_init_params(struct rtsx_pcr *pcr)
        pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
        pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
        pcr->aspm_en = ASPM_L1_EN;
-       pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16);
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 29, 11);
        pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
 
        pcr->ic_version = rts5260_get_ic_version(pcr);
index bc4967a..78c3b1d 100644 (file)
@@ -764,7 +764,7 @@ void rts5261_init_params(struct rtsx_pcr *pcr)
        pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
        pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
        pcr->aspm_en = ASPM_L1_EN;
-       pcr->tx_initial_phase = SET_CLOCK_PHASE(20, 27, 16);
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 11);
        pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
 
        pcr->ic_version = rts5261_get_ic_version(pcr);
index 031eb64..282c9ef 100644 (file)
@@ -712,13 +712,14 @@ static int at24_probe(struct i2c_client *client)
         * chip is functional.
         */
        err = at24_read(at24, 0, &test_byte, 1);
-       pm_runtime_idle(dev);
        if (err) {
                pm_runtime_disable(dev);
                regulator_disable(at24->vcc_reg);
                return -ENODEV;
        }
 
+       pm_runtime_idle(dev);
+
        if (writable)
                dev_info(dev, "%u byte %s EEPROM, writable, %u bytes/write\n",
                         byte_len, client->name, at24->write_max);
index de87693..cc92bc3 100644 (file)
@@ -378,3 +378,39 @@ void lkdtm_DOUBLE_FAULT(void)
        pr_err("XFAIL: this test is ia32-only\n");
 #endif
 }
+
+#ifdef CONFIG_ARM64_PTR_AUTH
+static noinline void change_pac_parameters(void)
+{
+       /* Reset the keys of current task */
+       ptrauth_thread_init_kernel(current);
+       ptrauth_thread_switch_kernel(current);
+}
+
+#define CORRUPT_PAC_ITERATE    10
+noinline void lkdtm_CORRUPT_PAC(void)
+{
+       int i;
+
+       if (!system_supports_address_auth()) {
+               pr_err("FAIL: arm64 pointer authentication feature not present\n");
+               return;
+       }
+
+       pr_info("Change the PAC parameters to force function return failure\n");
+       /*
+        * Pac is a hash value computed from input keys, return address and
+        * stack pointer. As pac has fewer bits so there is a chance of
+        * collision, so iterate few times to reduce the collision probability.
+        */
+       for (i = 0; i < CORRUPT_PAC_ITERATE; i++)
+               change_pac_parameters();
+
+       pr_err("FAIL: %s test failed. Kernel may be unstable from here\n", __func__);
+}
+#else /* !CONFIG_ARM64_PTR_AUTH */
+noinline void lkdtm_CORRUPT_PAC(void)
+{
+       pr_err("FAIL: arm64 pointer authentication config disabled\n");
+}
+#endif
index ee0d6e7..5ce4ac8 100644 (file)
@@ -116,6 +116,7 @@ static const struct crashtype crashtypes[] = {
        CRASHTYPE(STACK_GUARD_PAGE_LEADING),
        CRASHTYPE(STACK_GUARD_PAGE_TRAILING),
        CRASHTYPE(UNSET_SMEP),
+       CRASHTYPE(CORRUPT_PAC),
        CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
        CRASHTYPE(OVERWRITE_ALLOCATION),
        CRASHTYPE(WRITE_AFTER_FREE),
index c56d23e..8d13d01 100644 (file)
@@ -31,6 +31,7 @@ void lkdtm_UNSET_SMEP(void);
 #ifdef CONFIG_X86_32
 void lkdtm_DOUBLE_FAULT(void);
 #endif
+void lkdtm_CORRUPT_PAC(void);
 
 /* lkdtm_heap.c */
 void __init lkdtm_heap_init(void);
index aa54d35..a971c4b 100644 (file)
@@ -1732,8 +1732,11 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
         * the erase operation does not exceed the max_busy_timeout, we should
         * use R1B response. Or we need to prevent the host from doing hw busy
         * detection, which is done by converting to a R1 response instead.
+        * Note, some hosts requires R1B, which also means they are on their own
+        * when it comes to deal with the busy timeout.
         */
-       if (card->host->max_busy_timeout &&
+       if (!(card->host->caps & MMC_CAP_NEED_RSP_BUSY) &&
+           card->host->max_busy_timeout &&
            busy_timeout > card->host->max_busy_timeout) {
                cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
        } else {
index f6912de..de14b58 100644 (file)
@@ -1910,9 +1910,12 @@ static int mmc_sleep(struct mmc_host *host)
         * If the max_busy_timeout of the host is specified, validate it against
         * the sleep cmd timeout. A failure means we need to prevent the host
         * from doing hw busy detection, which is done by converting to a R1
-        * response instead of a R1B.
+        * response instead of a R1B. Note, some hosts requires R1B, which also
+        * means they are on their own when it comes to deal with the busy
+        * timeout.
         */
-       if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) {
+       if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
+           (timeout_ms > host->max_busy_timeout)) {
                cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
        } else {
                cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
index da425ee..e025604 100644 (file)
@@ -542,9 +542,11 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
         * If the max_busy_timeout of the host is specified, make sure it's
         * enough to fit the used timeout_ms. In case it's not, let's instruct
         * the host to avoid HW busy detection, by converting to a R1 response
-        * instead of a R1B.
+        * instead of a R1B. Note, some hosts requires R1B, which also means
+        * they are on their own when it comes to deal with the busy timeout.
         */
-       if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout))
+       if (!(host->caps & MMC_CAP_NEED_RSP_BUSY) && host->max_busy_timeout &&
+           (timeout_ms > host->max_busy_timeout))
                use_r1b_resp = false;
 
        cmd.opcode = MMC_SWITCH;
index bd50935..1108797 100644 (file)
@@ -606,19 +606,22 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
                u8 sample_point, bool rx)
 {
        struct rtsx_pcr *pcr = host->pcr;
-
+       u16 SD_VP_CTL = 0;
        dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n",
                        __func__, rx ? "RX" : "TX", sample_point);
 
        rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, CHANGE_CLK);
-       if (rx)
+       if (rx) {
+               SD_VP_CTL = SD_VPRX_CTL;
                rtsx_pci_write_register(pcr, SD_VPRX_CTL,
                        PHASE_SELECT_MASK, sample_point);
-       else
+       } else {
+               SD_VP_CTL = SD_VPTX_CTL;
                rtsx_pci_write_register(pcr, SD_VPTX_CTL,
                        PHASE_SELECT_MASK, sample_point);
-       rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
-       rtsx_pci_write_register(pcr, SD_VPCLK0_CTL, PHASE_NOT_RESET,
+       }
+       rtsx_pci_write_register(pcr, SD_VP_CTL, PHASE_NOT_RESET, 0);
+       rtsx_pci_write_register(pcr, SD_VP_CTL, PHASE_NOT_RESET,
                                PHASE_NOT_RESET);
        rtsx_pci_write_register(pcr, CLK_CTL, CHANGE_CLK, 0);
        rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
index 9651dca..7e7d0d1 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
+#include <linux/dmi.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/pm.h>
@@ -72,9 +73,16 @@ struct sdhci_acpi_host {
        const struct sdhci_acpi_slot    *slot;
        struct platform_device          *pdev;
        bool                            use_runtime_pm;
+       bool                            is_intel;
+       bool                            reset_signal_volt_on_suspend;
        unsigned long                   private[0] ____cacheline_aligned;
 };
 
+enum {
+       DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP                  = BIT(0),
+       DMI_QUIRK_SD_NO_WRITE_PROTECT                           = BIT(1),
+};
+
 static inline void *sdhci_acpi_priv(struct sdhci_acpi_host *c)
 {
        return (void *)c->private;
@@ -234,7 +242,7 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
 static bool sdhci_acpi_byt(void)
 {
        static const struct x86_cpu_id byt[] = {
-               { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT },
+               X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, NULL),
                {}
        };
 
@@ -244,7 +252,7 @@ static bool sdhci_acpi_byt(void)
 static bool sdhci_acpi_cht(void)
 {
        static const struct x86_cpu_id cht[] = {
-               { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },
+               X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL),
                {}
        };
 
@@ -391,6 +399,8 @@ static int intel_probe_slot(struct platform_device *pdev, struct acpi_device *ad
        host->mmc_host_ops.start_signal_voltage_switch =
                                        intel_start_signal_voltage_switch;
 
+       c->is_intel = true;
+
        return 0;
 }
 
@@ -647,6 +657,36 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
 
+static const struct dmi_system_id sdhci_acpi_quirks[] = {
+       {
+               /*
+                * The Lenovo Miix 320-10ICR has a bug in the _PS0 method of
+                * the SHC1 ACPI device, this bug causes it to reprogram the
+                * wrong LDO (DLDO3) to 1.8V if 1.8V modes are used and the
+                * card is (runtime) suspended + resumed. DLDO3 is used for
+                * the LCD and setting it to 1.8V causes the LCD to go black.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"),
+               },
+               .driver_data = (void *)DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP,
+       },
+       {
+               /*
+                * The Acer Aspire Switch 10 (SW5-012) microSD slot always
+                * reports the card being write-protected even though microSD
+                * cards do not have a write-protect switch at all.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
+               },
+               .driver_data = (void *)DMI_QUIRK_SD_NO_WRITE_PROTECT,
+       },
+       {} /* Terminating entry */
+};
+
 static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(struct acpi_device *adev)
 {
        const struct sdhci_acpi_uid_slot *u;
@@ -663,17 +703,23 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        const struct sdhci_acpi_slot *slot;
        struct acpi_device *device, *child;
+       const struct dmi_system_id *id;
        struct sdhci_acpi_host *c;
        struct sdhci_host *host;
        struct resource *iomem;
        resource_size_t len;
        size_t priv_size;
+       int quirks = 0;
        int err;
 
        device = ACPI_COMPANION(dev);
        if (!device)
                return -ENODEV;
 
+       id = dmi_first_match(sdhci_acpi_quirks);
+       if (id)
+               quirks = (long)id->driver_data;
+
        slot = sdhci_acpi_get_slot(device);
 
        /* Power on the SDHCI controller and its children */
@@ -759,6 +805,12 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
                        dev_warn(dev, "failed to setup card detect gpio\n");
                        c->use_runtime_pm = false;
                }
+
+               if (quirks & DMI_QUIRK_RESET_SD_SIGNAL_VOLT_ON_SUSP)
+                       c->reset_signal_volt_on_suspend = true;
+
+               if (quirks & DMI_QUIRK_SD_NO_WRITE_PROTECT)
+                       host->mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
        }
 
        err = sdhci_setup_host(host);
@@ -823,17 +875,39 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
        return 0;
 }
 
+static void __maybe_unused sdhci_acpi_reset_signal_voltage_if_needed(
+       struct device *dev)
+{
+       struct sdhci_acpi_host *c = dev_get_drvdata(dev);
+       struct sdhci_host *host = c->host;
+
+       if (c->is_intel && c->reset_signal_volt_on_suspend &&
+           host->mmc->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_330) {
+               struct intel_host *intel_host = sdhci_acpi_priv(c);
+               unsigned int fn = INTEL_DSM_V33_SWITCH;
+               u32 result = 0;
+
+               intel_dsm(intel_host, dev, fn, &result);
+       }
+}
+
 #ifdef CONFIG_PM_SLEEP
 
 static int sdhci_acpi_suspend(struct device *dev)
 {
        struct sdhci_acpi_host *c = dev_get_drvdata(dev);
        struct sdhci_host *host = c->host;
+       int ret;
 
        if (host->tuning_mode != SDHCI_TUNING_MODE_3)
                mmc_retune_needed(host->mmc);
 
-       return sdhci_suspend_host(host);
+       ret = sdhci_suspend_host(host);
+       if (ret)
+               return ret;
+
+       sdhci_acpi_reset_signal_voltage_if_needed(dev);
+       return 0;
 }
 
 static int sdhci_acpi_resume(struct device *dev)
@@ -853,11 +927,17 @@ static int sdhci_acpi_runtime_suspend(struct device *dev)
 {
        struct sdhci_acpi_host *c = dev_get_drvdata(dev);
        struct sdhci_host *host = c->host;
+       int ret;
 
        if (host->tuning_mode != SDHCI_TUNING_MODE_3)
                mmc_retune_needed(host->mmc);
 
-       return sdhci_runtime_suspend_host(host);
+       ret = sdhci_runtime_suspend_host(host);
+       if (ret)
+               return ret;
+
+       sdhci_acpi_reset_signal_voltage_if_needed(dev);
+       return 0;
 }
 
 static int sdhci_acpi_runtime_resume(struct device *dev)
index 5827d37..e573495 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
 #include "sdhci-pltfm.h"
 
@@ -235,6 +236,11 @@ static const struct sdhci_ops sdhci_cdns_ops = {
        .set_uhs_signaling = sdhci_cdns_set_uhs_signaling,
 };
 
+static const struct sdhci_pltfm_data sdhci_cdns_uniphier_pltfm_data = {
+       .ops = &sdhci_cdns_ops,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+};
+
 static const struct sdhci_pltfm_data sdhci_cdns_pltfm_data = {
        .ops = &sdhci_cdns_ops,
 };
@@ -334,6 +340,7 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc,
 static int sdhci_cdns_probe(struct platform_device *pdev)
 {
        struct sdhci_host *host;
+       const struct sdhci_pltfm_data *data;
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_cdns_priv *priv;
        struct clk *clk;
@@ -350,8 +357,12 @@ static int sdhci_cdns_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       data = of_device_get_match_data(dev);
+       if (!data)
+               data = &sdhci_cdns_pltfm_data;
+
        nr_phy_params = sdhci_cdns_phy_param_count(dev->of_node);
-       host = sdhci_pltfm_init(pdev, &sdhci_cdns_pltfm_data,
+       host = sdhci_pltfm_init(pdev, data,
                                struct_size(priv, phy_params, nr_phy_params));
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
@@ -431,7 +442,10 @@ static const struct dev_pm_ops sdhci_cdns_pm_ops = {
 };
 
 static const struct of_device_id sdhci_cdns_match[] = {
-       { .compatible = "socionext,uniphier-sd4hc" },
+       {
+               .compatible = "socionext,uniphier-sd4hc",
+               .data = &sdhci_cdns_uniphier_pltfm_data,
+       },
        { .compatible = "cdns,sd4hc" },
        { /* sentinel */ }
 };
index 382f25b..b2bdf50 100644 (file)
@@ -1452,8 +1452,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
                                                  pdev->id_entry->driver_data;
 
        if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
-               pm_qos_add_request(&imx_data->pm_qos_req,
-                       PM_QOS_CPU_DMA_LATENCY, 0);
+               cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
 
        imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(imx_data->clk_ipg)) {
@@ -1572,7 +1571,7 @@ disable_per_clk:
        clk_disable_unprepare(imx_data->clk_per);
 free_sdhci:
        if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
-               pm_qos_remove_request(&imx_data->pm_qos_req);
+               cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
        sdhci_pltfm_free(pdev);
        return err;
 }
@@ -1595,7 +1594,7 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
        clk_disable_unprepare(imx_data->clk_ahb);
 
        if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
-               pm_qos_remove_request(&imx_data->pm_qos_req);
+               cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
 
        sdhci_pltfm_free(pdev);
 
@@ -1667,7 +1666,7 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
        clk_disable_unprepare(imx_data->clk_ahb);
 
        if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
-               pm_qos_remove_request(&imx_data->pm_qos_req);
+               cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
 
        return ret;
 }
@@ -1680,8 +1679,7 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
        int err;
 
        if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
-               pm_qos_add_request(&imx_data->pm_qos_req,
-                       PM_QOS_CPU_DMA_LATENCY, 0);
+               cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
 
        err = clk_prepare_enable(imx_data->clk_ahb);
        if (err)
@@ -1714,7 +1712,7 @@ disable_ahb_clk:
        clk_disable_unprepare(imx_data->clk_ahb);
 remove_pm_qos_request:
        if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
-               pm_qos_remove_request(&imx_data->pm_qos_req);
+               cpu_latency_qos_remove_request(&imx_data->pm_qos_req);
        return err;
 }
 #endif
index c3a160c..3955fa5 100644 (file)
@@ -1590,7 +1590,7 @@ static u32 sdhci_msm_cqe_irq(struct sdhci_host *host, u32 intmask)
        return 0;
 }
 
-void sdhci_msm_cqe_disable(struct mmc_host *mmc, bool recovery)
+static void sdhci_msm_cqe_disable(struct mmc_host *mmc, bool recovery)
 {
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
index ab2bd31..fcef5c0 100644 (file)
@@ -132,7 +132,8 @@ static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)
 
        sdhci_reset(host, mask);
 
-       if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+       if ((host->mmc->caps & MMC_CAP_NONREMOVABLE)
+           || mmc_gpio_get_cd(host->mmc) >= 0)
                sdhci_at91_set_force_card_detect(host);
 
        if (priv->cal_always_on && (mask & SDHCI_RESET_ALL))
@@ -427,8 +428,11 @@ static int sdhci_at91_probe(struct platform_device *pdev)
         * detection procedure using the SDMCC_CD signal is bypassed.
         * This bit is reset when a software reset for all command is performed
         * so we need to implement our own reset function to set back this bit.
+        *
+        * WA: SAMA5D2 doesn't drive CMD if using CD GPIO line.
         */
-       if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
+       if ((host->mmc->caps & MMC_CAP_NONREMOVABLE)
+           || mmc_gpio_get_cd(host->mmc) >= 0)
                sdhci_at91_set_force_card_detect(host);
 
        pm_runtime_put_autosuspend(&pdev->dev);
index 8820531..c497817 100644 (file)
@@ -1192,6 +1192,9 @@ static int sdhci_omap_probe(struct platform_device *pdev)
        if (of_find_property(dev->of_node, "dmas", NULL))
                sdhci_switch_external_dma(host, true);
 
+       /* R1B responses is required to properly manage HW busy detection. */
+       mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
+
        ret = sdhci_setup_host(host);
        if (ret)
                goto err_put_sync;
index 5eea8d7..ce15a05 100644 (file)
@@ -262,10 +262,26 @@ static int gl9750_execute_tuning(struct sdhci_host *host, u32 opcode)
        return 0;
 }
 
+static void gli_pcie_enable_msi(struct sdhci_pci_slot *slot)
+{
+       int ret;
+
+       ret = pci_alloc_irq_vectors(slot->chip->pdev, 1, 1,
+                                   PCI_IRQ_MSI | PCI_IRQ_MSIX);
+       if (ret < 0) {
+               pr_warn("%s: enable PCI MSI failed, error=%d\n",
+                      mmc_hostname(slot->host->mmc), ret);
+               return;
+       }
+
+       slot->host->irq = pci_irq_vector(slot->chip->pdev, 0);
+}
+
 static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
 {
        struct sdhci_host *host = slot->host;
 
+       gli_pcie_enable_msi(slot);
        slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
        sdhci_enable_v4_mode(host);
 
@@ -276,6 +292,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
 {
        struct sdhci_host *host = slot->host;
 
+       gli_pcie_enable_msi(slot);
        slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
        sdhci_enable_v4_mode(host);
 
index 403ac44..a25c3a4 100644 (file)
@@ -1552,6 +1552,9 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
        if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
                host->mmc->caps |= MMC_CAP_1_8V_DDR;
 
+       /* R1B responses is required to properly manage HW busy detection. */
+       host->mmc->caps |= MMC_CAP_NEED_RSP_BUSY;
+
        tegra_sdhci_parse_dt(host);
 
        tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
diff --git a/drivers/most/Kconfig b/drivers/most/Kconfig
new file mode 100644 (file)
index 0000000..58d7999
--- /dev/null
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+menuconfig MOST
+       tristate "MOST support"
+       depends on HAS_DMA && CONFIGFS_FS
+       default n
+       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
+         matches the network controller's hardware interface (e.g. USB).
+
+         To compile this driver as a module, choose M here: the
+         module will be called most_core.
+
+         If in doubt, say N here.
diff --git a/drivers/most/Makefile b/drivers/most/Makefile
new file mode 100644 (file)
index 0000000..e810cd3
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_MOST) += most_core.o
+most_core-y := core.o \
+               configfs.o
similarity index 99%
rename from drivers/staging/most/configfs.c
rename to drivers/most/configfs.c
index 9a96122..27b0c92 100644 (file)
@@ -10,8 +10,7 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/configfs.h>
-
-#include "most.h"
+#include <linux/most.h>
 
 #define MAX_STRING_SIZE 80
 
similarity index 99%
rename from drivers/staging/most/core.c
rename to drivers/most/core.c
index 0c4ae69..06426fc 100644 (file)
@@ -20,8 +20,7 @@
 #include <linux/kthread.h>
 #include <linux/dma-mapping.h>
 #include <linux/idr.h>
-
-#include "most.h"
+#include <linux/most.h>
 
 #define MAX_CHANNELS   64
 #define STRING_SIZE    80
@@ -472,7 +471,7 @@ static int print_links(struct device *dev, void *data)
 
        list_for_each_entry(c, &iface->p->channel_list, list) {
                if (c->pipe0.comp) {
-                       offs += snprintf(buf + offs,
+                       offs += scnprintf(buf + offs,
                                         PAGE_SIZE - offs,
                                         "%s:%s:%s\n",
                                         c->pipe0.comp->name,
@@ -480,7 +479,7 @@ static int print_links(struct device *dev, void *data)
                                         dev_name(&c->dev));
                }
                if (c->pipe1.comp) {
-                       offs += snprintf(buf + offs,
+                       offs += scnprintf(buf + offs,
                                         PAGE_SIZE - offs,
                                         "%s:%s:%s\n",
                                         c->pipe1.comp->name,
@@ -519,7 +518,7 @@ static ssize_t components_show(struct device_driver *drv, char *buf)
        int offs = 0;
 
        list_for_each_entry(comp, &comp_list, list) {
-               offs += snprintf(buf + offs, PAGE_SIZE - offs, "%s\n",
+               offs += scnprintf(buf + offs, PAGE_SIZE - offs, "%s\n",
                                 comp->name);
        }
        return offs;
index c1eda67..267b900 100644 (file)
@@ -52,14 +52,6 @@ config SPI_HISI_SFC
        help
          This enables support for HiSilicon FMC SPI-NOR flash controller.
 
-config SPI_MTK_QUADSPI
-       tristate "MediaTek Quad SPI controller"
-       depends on HAS_IOMEM
-       help
-         This enables support for the Quad SPI controller in master mode.
-         This controller does not support generic SPI. It only supports
-         SPI NOR.
-
 config SPI_NXP_SPIFI
        tristate "NXP SPI Flash Interface (SPIFI)"
        depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
index 9c5ed03..738dfd7 100644 (file)
@@ -3,7 +3,6 @@ obj-$(CONFIG_MTD_SPI_NOR)       += spi-nor.o
 obj-$(CONFIG_SPI_ASPEED_SMC)   += aspeed-smc.o
 obj-$(CONFIG_SPI_CADENCE_QUADSPI)      += cadence-quadspi.o
 obj-$(CONFIG_SPI_HISI_SFC)     += hisi-sfc.o
-obj-$(CONFIG_SPI_MTK_QUADSPI)    += mtk-quadspi.o
 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
diff --git a/drivers/mtd/spi-nor/mtk-quadspi.c b/drivers/mtd/spi-nor/mtk-quadspi.c
deleted file mode 100644 (file)
index b169168..0000000
+++ /dev/null
@@ -1,565 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2015 MediaTek Inc.
- * Author: Bayi Cheng <bayi.cheng@mediatek.com>
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/ioport.h>
-#include <linux/math64.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/spi-nor.h>
-
-#define MTK_NOR_CMD_REG                        0x00
-#define MTK_NOR_CNT_REG                        0x04
-#define MTK_NOR_RDSR_REG               0x08
-#define MTK_NOR_RDATA_REG              0x0c
-#define MTK_NOR_RADR0_REG              0x10
-#define MTK_NOR_RADR1_REG              0x14
-#define MTK_NOR_RADR2_REG              0x18
-#define MTK_NOR_WDATA_REG              0x1c
-#define MTK_NOR_PRGDATA0_REG           0x20
-#define MTK_NOR_PRGDATA1_REG           0x24
-#define MTK_NOR_PRGDATA2_REG           0x28
-#define MTK_NOR_PRGDATA3_REG           0x2c
-#define MTK_NOR_PRGDATA4_REG           0x30
-#define MTK_NOR_PRGDATA5_REG           0x34
-#define MTK_NOR_SHREG0_REG             0x38
-#define MTK_NOR_SHREG1_REG             0x3c
-#define MTK_NOR_SHREG2_REG             0x40
-#define MTK_NOR_SHREG3_REG             0x44
-#define MTK_NOR_SHREG4_REG             0x48
-#define MTK_NOR_SHREG5_REG             0x4c
-#define MTK_NOR_SHREG6_REG             0x50
-#define MTK_NOR_SHREG7_REG             0x54
-#define MTK_NOR_SHREG8_REG             0x58
-#define MTK_NOR_SHREG9_REG             0x5c
-#define MTK_NOR_CFG1_REG               0x60
-#define MTK_NOR_CFG2_REG               0x64
-#define MTK_NOR_CFG3_REG               0x68
-#define MTK_NOR_STATUS0_REG            0x70
-#define MTK_NOR_STATUS1_REG            0x74
-#define MTK_NOR_STATUS2_REG            0x78
-#define MTK_NOR_STATUS3_REG            0x7c
-#define MTK_NOR_FLHCFG_REG             0x84
-#define MTK_NOR_TIME_REG               0x94
-#define MTK_NOR_PP_DATA_REG            0x98
-#define MTK_NOR_PREBUF_STUS_REG                0x9c
-#define MTK_NOR_DELSEL0_REG            0xa0
-#define MTK_NOR_DELSEL1_REG            0xa4
-#define MTK_NOR_INTRSTUS_REG           0xa8
-#define MTK_NOR_INTREN_REG             0xac
-#define MTK_NOR_CHKSUM_CTL_REG         0xb8
-#define MTK_NOR_CHKSUM_REG             0xbc
-#define MTK_NOR_CMD2_REG               0xc0
-#define MTK_NOR_WRPROT_REG             0xc4
-#define MTK_NOR_RADR3_REG              0xc8
-#define MTK_NOR_DUAL_REG               0xcc
-#define MTK_NOR_DELSEL2_REG            0xd0
-#define MTK_NOR_DELSEL3_REG            0xd4
-#define MTK_NOR_DELSEL4_REG            0xd8
-
-/* commands for mtk nor controller */
-#define MTK_NOR_READ_CMD               0x0
-#define MTK_NOR_RDSR_CMD               0x2
-#define MTK_NOR_PRG_CMD                        0x4
-#define MTK_NOR_WR_CMD                 0x10
-#define MTK_NOR_PIO_WR_CMD             0x90
-#define MTK_NOR_WRSR_CMD               0x20
-#define MTK_NOR_PIO_READ_CMD           0x81
-#define MTK_NOR_WR_BUF_ENABLE          0x1
-#define MTK_NOR_WR_BUF_DISABLE         0x0
-#define MTK_NOR_ENABLE_SF_CMD          0x30
-#define MTK_NOR_DUAD_ADDR_EN           0x8
-#define MTK_NOR_QUAD_READ_EN           0x4
-#define MTK_NOR_DUAL_ADDR_EN           0x2
-#define MTK_NOR_DUAL_READ_EN           0x1
-#define MTK_NOR_DUAL_DISABLE           0x0
-#define MTK_NOR_FAST_READ              0x1
-
-#define SFLASH_WRBUF_SIZE              128
-
-/* Can shift up to 48 bits (6 bytes) of TX/RX */
-#define MTK_NOR_MAX_RX_TX_SHIFT                6
-/* can shift up to 56 bits (7 bytes) transfer by MTK_NOR_PRG_CMD */
-#define MTK_NOR_MAX_SHIFT              7
-/* nor controller 4-byte address mode enable bit */
-#define MTK_NOR_4B_ADDR_EN             BIT(4)
-
-/* Helpers for accessing the program data / shift data registers */
-#define MTK_NOR_PRG_REG(n)             (MTK_NOR_PRGDATA0_REG + 4 * (n))
-#define MTK_NOR_SHREG(n)               (MTK_NOR_SHREG0_REG + 4 * (n))
-
-struct mtk_nor {
-       struct spi_nor nor;
-       struct device *dev;
-       void __iomem *base;     /* nor flash base address */
-       struct clk *spi_clk;
-       struct clk *nor_clk;
-};
-
-static void mtk_nor_set_read_mode(struct mtk_nor *mtk_nor)
-{
-       struct spi_nor *nor = &mtk_nor->nor;
-
-       switch (nor->read_proto) {
-       case SNOR_PROTO_1_1_1:
-               writeb(nor->read_opcode, mtk_nor->base +
-                      MTK_NOR_PRGDATA3_REG);
-               writeb(MTK_NOR_FAST_READ, mtk_nor->base +
-                      MTK_NOR_CFG1_REG);
-               break;
-       case SNOR_PROTO_1_1_2:
-               writeb(nor->read_opcode, mtk_nor->base +
-                      MTK_NOR_PRGDATA3_REG);
-               writeb(MTK_NOR_DUAL_READ_EN, mtk_nor->base +
-                      MTK_NOR_DUAL_REG);
-               break;
-       case SNOR_PROTO_1_1_4:
-               writeb(nor->read_opcode, mtk_nor->base +
-                      MTK_NOR_PRGDATA4_REG);
-               writeb(MTK_NOR_QUAD_READ_EN, mtk_nor->base +
-                      MTK_NOR_DUAL_REG);
-               break;
-       default:
-               writeb(MTK_NOR_DUAL_DISABLE, mtk_nor->base +
-                      MTK_NOR_DUAL_REG);
-               break;
-       }
-}
-
-static int mtk_nor_execute_cmd(struct mtk_nor *mtk_nor, u8 cmdval)
-{
-       int reg;
-       u8 val = cmdval & 0x1f;
-
-       writeb(cmdval, mtk_nor->base + MTK_NOR_CMD_REG);
-       return readl_poll_timeout(mtk_nor->base + MTK_NOR_CMD_REG, reg,
-                                 !(reg & val), 100, 10000);
-}
-
-static int mtk_nor_do_tx_rx(struct mtk_nor *mtk_nor, u8 op,
-                           const u8 *tx, size_t txlen, u8 *rx, size_t rxlen)
-{
-       size_t len = 1 + txlen + rxlen;
-       int i, ret, idx;
-
-       if (len > MTK_NOR_MAX_SHIFT)
-               return -EINVAL;
-
-       writeb(len * 8, mtk_nor->base + MTK_NOR_CNT_REG);
-
-       /* start at PRGDATA5, go down to PRGDATA0 */
-       idx = MTK_NOR_MAX_RX_TX_SHIFT - 1;
-
-       /* opcode */
-       writeb(op, mtk_nor->base + MTK_NOR_PRG_REG(idx));
-       idx--;
-
-       /* program TX data */
-       for (i = 0; i < txlen; i++, idx--)
-               writeb(tx[i], mtk_nor->base + MTK_NOR_PRG_REG(idx));
-
-       /* clear out rest of TX registers */
-       while (idx >= 0) {
-               writeb(0, mtk_nor->base + MTK_NOR_PRG_REG(idx));
-               idx--;
-       }
-
-       ret = mtk_nor_execute_cmd(mtk_nor, MTK_NOR_PRG_CMD);
-       if (ret)
-               return ret;
-
-       /* restart at first RX byte */
-       idx = rxlen - 1;
-
-       /* read out RX data */
-       for (i = 0; i < rxlen; i++, idx--)
-               rx[i] = readb(mtk_nor->base + MTK_NOR_SHREG(idx));
-
-       return 0;
-}
-
-/* Do a WRSR (Write Status Register) command */
-static int mtk_nor_wr_sr(struct mtk_nor *mtk_nor, const u8 sr)
-{
-       writeb(sr, mtk_nor->base + MTK_NOR_PRGDATA5_REG);
-       writeb(8, mtk_nor->base + MTK_NOR_CNT_REG);
-       return mtk_nor_execute_cmd(mtk_nor, MTK_NOR_WRSR_CMD);
-}
-
-static int mtk_nor_write_buffer_enable(struct mtk_nor *mtk_nor)
-{
-       u8 reg;
-
-       /* the bit0 of MTK_NOR_CFG2_REG is pre-fetch buffer
-        * 0: pre-fetch buffer use for read
-        * 1: pre-fetch buffer use for page program
-        */
-       writel(MTK_NOR_WR_BUF_ENABLE, mtk_nor->base + MTK_NOR_CFG2_REG);
-       return readb_poll_timeout(mtk_nor->base + MTK_NOR_CFG2_REG, reg,
-                                 0x01 == (reg & 0x01), 100, 10000);
-}
-
-static int mtk_nor_write_buffer_disable(struct mtk_nor *mtk_nor)
-{
-       u8 reg;
-
-       writel(MTK_NOR_WR_BUF_DISABLE, mtk_nor->base + MTK_NOR_CFG2_REG);
-       return readb_poll_timeout(mtk_nor->base + MTK_NOR_CFG2_REG, reg,
-                                 MTK_NOR_WR_BUF_DISABLE == (reg & 0x1), 100,
-                                 10000);
-}
-
-static void mtk_nor_set_addr_width(struct mtk_nor *mtk_nor)
-{
-       u8 val;
-       struct spi_nor *nor = &mtk_nor->nor;
-
-       val = readb(mtk_nor->base + MTK_NOR_DUAL_REG);
-
-       switch (nor->addr_width) {
-       case 3:
-               val &= ~MTK_NOR_4B_ADDR_EN;
-               break;
-       case 4:
-               val |= MTK_NOR_4B_ADDR_EN;
-               break;
-       default:
-               dev_warn(mtk_nor->dev, "Unexpected address width %u.\n",
-                        nor->addr_width);
-               break;
-       }
-
-       writeb(val, mtk_nor->base + MTK_NOR_DUAL_REG);
-}
-
-static void mtk_nor_set_addr(struct mtk_nor *mtk_nor, u32 addr)
-{
-       int i;
-
-       mtk_nor_set_addr_width(mtk_nor);
-
-       for (i = 0; i < 3; i++) {
-               writeb(addr & 0xff, mtk_nor->base + MTK_NOR_RADR0_REG + i * 4);
-               addr >>= 8;
-       }
-       /* Last register is non-contiguous */
-       writeb(addr & 0xff, mtk_nor->base + MTK_NOR_RADR3_REG);
-}
-
-static ssize_t mtk_nor_read(struct spi_nor *nor, loff_t from, size_t length,
-                           u_char *buffer)
-{
-       int i, ret;
-       int addr = (int)from;
-       u8 *buf = (u8 *)buffer;
-       struct mtk_nor *mtk_nor = nor->priv;
-
-       /* set mode for fast read mode ,dual mode or quad mode */
-       mtk_nor_set_read_mode(mtk_nor);
-       mtk_nor_set_addr(mtk_nor, addr);
-
-       for (i = 0; i < length; i++) {
-               ret = mtk_nor_execute_cmd(mtk_nor, MTK_NOR_PIO_READ_CMD);
-               if (ret < 0)
-                       return ret;
-               buf[i] = readb(mtk_nor->base + MTK_NOR_RDATA_REG);
-       }
-       return length;
-}
-
-static int mtk_nor_write_single_byte(struct mtk_nor *mtk_nor,
-                                    int addr, int length, u8 *data)
-{
-       int i, ret;
-
-       mtk_nor_set_addr(mtk_nor, addr);
-
-       for (i = 0; i < length; i++) {
-               writeb(*data++, mtk_nor->base + MTK_NOR_WDATA_REG);
-               ret = mtk_nor_execute_cmd(mtk_nor, MTK_NOR_PIO_WR_CMD);
-               if (ret < 0)
-                       return ret;
-       }
-       return 0;
-}
-
-static int mtk_nor_write_buffer(struct mtk_nor *mtk_nor, int addr,
-                               const u8 *buf)
-{
-       int i, bufidx, data;
-
-       mtk_nor_set_addr(mtk_nor, addr);
-
-       bufidx = 0;
-       for (i = 0; i < SFLASH_WRBUF_SIZE; i += 4) {
-               data = buf[bufidx + 3]<<24 | buf[bufidx + 2]<<16 |
-                      buf[bufidx + 1]<<8 | buf[bufidx];
-               bufidx += 4;
-               writel(data, mtk_nor->base + MTK_NOR_PP_DATA_REG);
-       }
-       return mtk_nor_execute_cmd(mtk_nor, MTK_NOR_WR_CMD);
-}
-
-static ssize_t mtk_nor_write(struct spi_nor *nor, loff_t to, size_t len,
-                            const u_char *buf)
-{
-       int ret;
-       struct mtk_nor *mtk_nor = nor->priv;
-       size_t i;
-
-       ret = mtk_nor_write_buffer_enable(mtk_nor);
-       if (ret < 0) {
-               dev_warn(mtk_nor->dev, "write buffer enable failed!\n");
-               return ret;
-       }
-
-       for (i = 0; i + SFLASH_WRBUF_SIZE <= len; i += SFLASH_WRBUF_SIZE) {
-               ret = mtk_nor_write_buffer(mtk_nor, to, buf);
-               if (ret < 0) {
-                       dev_err(mtk_nor->dev, "write buffer failed!\n");
-                       return ret;
-               }
-               to += SFLASH_WRBUF_SIZE;
-               buf += SFLASH_WRBUF_SIZE;
-       }
-       ret = mtk_nor_write_buffer_disable(mtk_nor);
-       if (ret < 0) {
-               dev_warn(mtk_nor->dev, "write buffer disable failed!\n");
-               return ret;
-       }
-
-       if (i < len) {
-               ret = mtk_nor_write_single_byte(mtk_nor, to,
-                                               (int)(len - i), (u8 *)buf);
-               if (ret < 0) {
-                       dev_err(mtk_nor->dev, "write single byte failed!\n");
-                       return ret;
-               }
-       }
-
-       return len;
-}
-
-static int mtk_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, size_t len)
-{
-       int ret;
-       struct mtk_nor *mtk_nor = nor->priv;
-
-       switch (opcode) {
-       case SPINOR_OP_RDSR:
-               ret = mtk_nor_execute_cmd(mtk_nor, MTK_NOR_RDSR_CMD);
-               if (ret < 0)
-                       return ret;
-               if (len == 1)
-                       *buf = readb(mtk_nor->base + MTK_NOR_RDSR_REG);
-               else
-                       dev_err(mtk_nor->dev, "len should be 1 for read status!\n");
-               break;
-       default:
-               ret = mtk_nor_do_tx_rx(mtk_nor, opcode, NULL, 0, buf, len);
-               break;
-       }
-       return ret;
-}
-
-static int mtk_nor_write_reg(struct spi_nor *nor, u8 opcode, const u8 *buf,
-                            size_t len)
-{
-       int ret;
-       struct mtk_nor *mtk_nor = nor->priv;
-
-       switch (opcode) {
-       case SPINOR_OP_WRSR:
-               /* We only handle 1 byte */
-               ret = mtk_nor_wr_sr(mtk_nor, *buf);
-               break;
-       default:
-               ret = mtk_nor_do_tx_rx(mtk_nor, opcode, buf, len, NULL, 0);
-               if (ret)
-                       dev_warn(mtk_nor->dev, "write reg failure!\n");
-               break;
-       }
-       return ret;
-}
-
-static void mtk_nor_disable_clk(struct mtk_nor *mtk_nor)
-{
-       clk_disable_unprepare(mtk_nor->spi_clk);
-       clk_disable_unprepare(mtk_nor->nor_clk);
-}
-
-static int mtk_nor_enable_clk(struct mtk_nor *mtk_nor)
-{
-       int ret;
-
-       ret = clk_prepare_enable(mtk_nor->spi_clk);
-       if (ret)
-               return ret;
-
-       ret = clk_prepare_enable(mtk_nor->nor_clk);
-       if (ret) {
-               clk_disable_unprepare(mtk_nor->spi_clk);
-               return ret;
-       }
-
-       return 0;
-}
-
-static const struct spi_nor_controller_ops mtk_controller_ops = {
-       .read_reg = mtk_nor_read_reg,
-       .write_reg = mtk_nor_write_reg,
-       .read = mtk_nor_read,
-       .write = mtk_nor_write,
-};
-
-static int mtk_nor_init(struct mtk_nor *mtk_nor,
-                       struct device_node *flash_node)
-{
-       const struct spi_nor_hwcaps hwcaps = {
-               .mask = SNOR_HWCAPS_READ |
-                       SNOR_HWCAPS_READ_FAST |
-                       SNOR_HWCAPS_READ_1_1_2 |
-                       SNOR_HWCAPS_PP,
-       };
-       int ret;
-       struct spi_nor *nor;
-
-       /* initialize controller to accept commands */
-       writel(MTK_NOR_ENABLE_SF_CMD, mtk_nor->base + MTK_NOR_WRPROT_REG);
-
-       nor = &mtk_nor->nor;
-       nor->dev = mtk_nor->dev;
-       nor->priv = mtk_nor;
-       spi_nor_set_flash_node(nor, flash_node);
-       nor->controller_ops = &mtk_controller_ops;
-
-       nor->mtd.name = "mtk_nor";
-       /* initialized with NULL */
-       ret = spi_nor_scan(nor, NULL, &hwcaps);
-       if (ret)
-               return ret;
-
-       return mtd_device_register(&nor->mtd, NULL, 0);
-}
-
-static int mtk_nor_drv_probe(struct platform_device *pdev)
-{
-       struct device_node *flash_np;
-       struct resource *res;
-       int ret;
-       struct mtk_nor *mtk_nor;
-
-       if (!pdev->dev.of_node) {
-               dev_err(&pdev->dev, "No DT found\n");
-               return -EINVAL;
-       }
-
-       mtk_nor = devm_kzalloc(&pdev->dev, sizeof(*mtk_nor), GFP_KERNEL);
-       if (!mtk_nor)
-               return -ENOMEM;
-       platform_set_drvdata(pdev, mtk_nor);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mtk_nor->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mtk_nor->base))
-               return PTR_ERR(mtk_nor->base);
-
-       mtk_nor->spi_clk = devm_clk_get(&pdev->dev, "spi");
-       if (IS_ERR(mtk_nor->spi_clk))
-               return PTR_ERR(mtk_nor->spi_clk);
-
-       mtk_nor->nor_clk = devm_clk_get(&pdev->dev, "sf");
-       if (IS_ERR(mtk_nor->nor_clk))
-               return PTR_ERR(mtk_nor->nor_clk);
-
-       mtk_nor->dev = &pdev->dev;
-
-       ret = mtk_nor_enable_clk(mtk_nor);
-       if (ret)
-               return ret;
-
-       /* only support one attached flash */
-       flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
-       if (!flash_np) {
-               dev_err(&pdev->dev, "no SPI flash device to configure\n");
-               ret = -ENODEV;
-               goto nor_free;
-       }
-       ret = mtk_nor_init(mtk_nor, flash_np);
-
-nor_free:
-       if (ret)
-               mtk_nor_disable_clk(mtk_nor);
-
-       return ret;
-}
-
-static int mtk_nor_drv_remove(struct platform_device *pdev)
-{
-       struct mtk_nor *mtk_nor = platform_get_drvdata(pdev);
-
-       mtk_nor_disable_clk(mtk_nor);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int mtk_nor_suspend(struct device *dev)
-{
-       struct mtk_nor *mtk_nor = dev_get_drvdata(dev);
-
-       mtk_nor_disable_clk(mtk_nor);
-
-       return 0;
-}
-
-static int mtk_nor_resume(struct device *dev)
-{
-       struct mtk_nor *mtk_nor = dev_get_drvdata(dev);
-
-       return mtk_nor_enable_clk(mtk_nor);
-}
-
-static const struct dev_pm_ops mtk_nor_dev_pm_ops = {
-       .suspend = mtk_nor_suspend,
-       .resume = mtk_nor_resume,
-};
-
-#define MTK_NOR_DEV_PM_OPS     (&mtk_nor_dev_pm_ops)
-#else
-#define MTK_NOR_DEV_PM_OPS     NULL
-#endif
-
-static const struct of_device_id mtk_nor_of_ids[] = {
-       { .compatible = "mediatek,mt8173-nor"},
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, mtk_nor_of_ids);
-
-static struct platform_driver mtk_nor_driver = {
-       .probe = mtk_nor_drv_probe,
-       .remove = mtk_nor_drv_remove,
-       .driver = {
-               .name = "mtk-nor",
-               .pm = MTK_NOR_DEV_PM_OPS,
-               .of_match_table = mtk_nor_of_ids,
-       },
-};
-
-module_platform_driver(mtk_nor_driver);
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("MediaTek SPI NOR Flash Driver");
index 25a8f93..db8884a 100644 (file)
@@ -149,6 +149,7 @@ config NET_FC
 config IFB
        tristate "Intermediate Functional Block support"
        depends on NET_CLS_ACT
+       select NET_REDIRECT
        ---help---
          This is an intermediate driver that allows sharing of
          resources.
index 1cc2cd8..c816985 100644 (file)
@@ -50,11 +50,6 @@ struct arp_pkt {
 };
 #pragma pack()
 
-static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb)
-{
-       return (struct arp_pkt *)skb_network_header(skb);
-}
-
 /* Forward declaration */
 static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
                                      bool strict_match);
@@ -553,10 +548,11 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip)
        spin_unlock(&bond->mode_lock);
 }
 
-static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond)
+static struct slave *rlb_choose_channel(struct sk_buff *skb,
+                                       struct bonding *bond,
+                                       const struct arp_pkt *arp)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
-       struct arp_pkt *arp = arp_pkt(skb);
        struct slave *assigned_slave, *curr_active_slave;
        struct rlb_client_info *client_info;
        u32 hash_index = 0;
@@ -653,8 +649,12 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
  */
 static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
 {
-       struct arp_pkt *arp = arp_pkt(skb);
        struct slave *tx_slave = NULL;
+       struct arp_pkt *arp;
+
+       if (!pskb_network_may_pull(skb, sizeof(*arp)))
+               return NULL;
+       arp = (struct arp_pkt *)skb_network_header(skb);
 
        /* Don't modify or load balance ARPs that do not originate locally
         * (e.g.,arrive via a bridge).
@@ -664,7 +664,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
 
        if (arp->op_code == htons(ARPOP_REPLY)) {
                /* the arp must be sent on the selected rx channel */
-               tx_slave = rlb_choose_channel(skb, bond);
+               tx_slave = rlb_choose_channel(skb, bond, arp);
                if (tx_slave)
                        bond_hw_addr_copy(arp->mac_src, tx_slave->dev->dev_addr,
                                          tx_slave->dev->addr_len);
@@ -676,7 +676,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
                 * When the arp reply is received the entry will be updated
                 * with the correct unicast address of the client.
                 */
-               tx_slave = rlb_choose_channel(skb, bond);
+               tx_slave = rlb_choose_channel(skb, bond, arp);
 
                /* The ARP reply packets must be delayed so that
                 * they can cancel out the influence of the ARP request.
index 8e81bdf..63f2548 100644 (file)
@@ -141,29 +141,29 @@ static ssize_t dbgfs_state(struct file *file, char __user *user_buf,
                return 0;
 
        /* Print out debug information. */
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "CAIF SPI debug information:\n");
-
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR);
-
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "STATE: %d\n", cfspi->dbg_state);
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Previous CMD: 0x%x\n", cfspi->pcmd);
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Current CMD: 0x%x\n", cfspi->cmd);
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Previous TX len: %d\n", cfspi->tx_ppck_len);
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Previous RX len: %d\n", cfspi->rx_ppck_len);
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Current TX len: %d\n", cfspi->tx_cpck_len);
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Current RX len: %d\n", cfspi->rx_cpck_len);
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Next TX len: %d\n", cfspi->tx_npck_len);
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Next RX len: %d\n", cfspi->rx_npck_len);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "CAIF SPI debug information:\n");
+
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), FLAVOR);
+
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "STATE: %d\n", cfspi->dbg_state);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Previous CMD: 0x%x\n", cfspi->pcmd);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Current CMD: 0x%x\n", cfspi->cmd);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Previous TX len: %d\n", cfspi->tx_ppck_len);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Previous RX len: %d\n", cfspi->rx_ppck_len);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Current TX len: %d\n", cfspi->tx_cpck_len);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Current RX len: %d\n", cfspi->rx_cpck_len);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Next TX len: %d\n", cfspi->tx_npck_len);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Next RX len: %d\n", cfspi->rx_npck_len);
 
        if (len > DEBUGFS_BUF_SIZE)
                len = DEBUGFS_BUF_SIZE;
@@ -180,23 +180,23 @@ static ssize_t print_frame(char *buf, size_t size, char *frm,
        int len = 0;
        int i;
        for (i = 0; i < count; i++) {
-               len += snprintf((buf + len), (size - len),
+               len += scnprintf((buf + len), (size - len),
                                        "[0x" BYTE_HEX_FMT "]",
                                        frm[i]);
                if ((i == cut) && (count > (cut * 2))) {
                        /* Fast forward. */
                        i = count - cut;
-                       len += snprintf((buf + len), (size - len),
-                                       "--- %zu bytes skipped ---\n",
-                                       count - (cut * 2));
+                       len += scnprintf((buf + len), (size - len),
+                                        "--- %zu bytes skipped ---\n",
+                                        count - (cut * 2));
                }
 
                if ((!(i % 10)) && i) {
-                       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                                       "\n");
+                       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                                        "\n");
                }
        }
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n");
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len), "\n");
        return len;
 }
 
@@ -214,18 +214,18 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
                return 0;
 
        /* Print out debug information. */
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Current frame:\n");
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Current frame:\n");
 
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Tx data (Len: %d):\n", cfspi->tx_cpck_len);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Tx data (Len: %d):\n", cfspi->tx_cpck_len);
 
        len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
                           cfspi->xfer.va_tx[0],
                           (cfspi->tx_cpck_len + SPI_CMD_SZ), 100);
 
-       len += snprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
-                       "Rx data (Len: %d):\n", cfspi->rx_cpck_len);
+       len += scnprintf((buf + len), (DEBUGFS_BUF_SIZE - len),
+                        "Rx data (Len: %d):\n", cfspi->rx_cpck_len);
 
        len += print_frame((buf + len), (DEBUGFS_BUF_SIZE - len),
                           cfspi->xfer.va_rx,
index 6ee06a4..68834a2 100644 (file)
@@ -883,6 +883,7 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
                                = { .len = sizeof(struct can_bittiming) },
        [IFLA_CAN_DATA_BITTIMING_CONST]
                                = { .len = sizeof(struct can_bittiming_const) },
+       [IFLA_CAN_TERMINATION]  = { .type = NLA_U16 },
 };
 
 static int can_validate(struct nlattr *tb[], struct nlattr *data[],
index 2f5c287..a366428 100644 (file)
@@ -625,7 +625,10 @@ err_free_chan:
        tty->disc_data = NULL;
        clear_bit(SLF_INUSE, &sl->flags);
        slc_free_netdev(sl->dev);
+       /* do not call free_netdev before rtnl_unlock */
+       rtnl_unlock();
        free_netdev(sl->dev);
+       return err;
 
 err_exit:
        rtnl_unlock();
index d195554..b0f5280 100644 (file)
@@ -69,8 +69,7 @@ static void bcm_sf2_imp_setup(struct dsa_switch *ds, int port)
                /* Force link status for IMP port */
                reg = core_readl(priv, offset);
                reg |= (MII_SW_OR | LINK_STS);
-               if (priv->type == BCM7278_DEVICE_ID)
-                       reg |= GMII_SPEED_UP_2G;
+               reg &= ~GMII_SPEED_UP_2G;
                core_writel(priv, reg, offset);
 
                /* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
index 022466c..7cbd1bd 100644 (file)
@@ -566,7 +566,7 @@ mt7530_mib_reset(struct dsa_switch *ds)
 static void
 mt7530_port_set_status(struct mt7530_priv *priv, int port, int enable)
 {
-       u32 mask = PMCR_TX_EN | PMCR_RX_EN;
+       u32 mask = PMCR_TX_EN | PMCR_RX_EN | PMCR_FORCE_LNK;
 
        if (enable)
                mt7530_set(priv, MT7530_PMCR_P(port), mask);
@@ -1444,7 +1444,7 @@ static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,
        mcr_new &= ~(PMCR_FORCE_SPEED_1000 | PMCR_FORCE_SPEED_100 |
                     PMCR_FORCE_FDX | PMCR_TX_FC_EN | PMCR_RX_FC_EN);
        mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
-                  PMCR_BACKPR_EN | PMCR_FORCE_MODE | PMCR_FORCE_LNK;
+                  PMCR_BACKPR_EN | PMCR_FORCE_MODE;
 
        /* Are we connected to external phy */
        if (port == 5 && dsa_is_user_port(ds, 5))
index 8c92895..2f993e6 100644 (file)
@@ -2769,6 +2769,8 @@ static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
                goto unlock;
        }
 
+       occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
+
 unlock:
        mv88e6xxx_reg_unlock(chip);
 
index b016cc2..ca3a7a7 100644 (file)
@@ -278,13 +278,13 @@ int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip,
        switch (direction) {
        case MV88E6XXX_EGRESS_DIR_INGRESS:
                dest_port_chip = &chip->ingress_dest_port;
-               reg &= MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
+               reg &= ~MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK;
                reg |= port <<
                       __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK);
                break;
        case MV88E6XXX_EGRESS_DIR_EGRESS:
                dest_port_chip = &chip->egress_dest_port;
-               reg &= MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
+               reg &= ~MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK;
                reg |= port <<
                       __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK);
                break;
index 0150301..8fd4830 100644 (file)
@@ -1099,6 +1099,13 @@ int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
 {
        int err, irq, virq;
 
+       chip->g2_irq.masked = ~0;
+       mv88e6xxx_reg_lock(chip);
+       err = mv88e6xxx_g2_int_mask(chip, ~chip->g2_irq.masked);
+       mv88e6xxx_reg_unlock(chip);
+       if (err)
+               return err;
+
        chip->g2_irq.domain = irq_domain_add_simple(
                chip->dev->of_node, 16, 0, &mv88e6xxx_g2_irq_domain_ops, chip);
        if (!chip->g2_irq.domain)
@@ -1108,7 +1115,6 @@ int mv88e6xxx_g2_irq_setup(struct mv88e6xxx_chip *chip)
                irq_create_mapping(chip->g2_irq.domain, irq);
 
        chip->g2_irq.chip = mv88e6xxx_g2_irq_chip;
-       chip->g2_irq.masked = ~0;
 
        chip->device_irq = irq_find_mapping(chip->g1_irq.domain,
                                            MV88E6XXX_G1_STS_IRQ_DEVICE);
index 03ba6d2..7edea57 100644 (file)
@@ -1741,7 +1741,8 @@ static void sja1105_teardown(struct dsa_switch *ds)
                if (!dsa_is_user_port(ds, port))
                        continue;
 
-               kthread_destroy_worker(sp->xmit_worker);
+               if (sp->xmit_worker)
+                       kthread_destroy_worker(sp->xmit_worker);
        }
 
        sja1105_tas_teardown(ds);
index 0b2fd96..cada6e7 100644 (file)
@@ -1018,13 +1018,9 @@ static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num)
                struct ena_rx_buffer *rx_info;
 
                req_id = rx_ring->free_ids[next_to_use];
-               rc = validate_rx_req_id(rx_ring, req_id);
-               if (unlikely(rc < 0))
-                       break;
 
                rx_info = &rx_ring->rx_buffer_info[req_id];
 
-
                rc = ena_alloc_rx_page(rx_ring, rx_info,
                                       GFP_ATOMIC | __GFP_COMP);
                if (unlikely(rc < 0)) {
@@ -1379,9 +1375,15 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
        struct ena_rx_buffer *rx_info;
        u16 len, req_id, buf = 0;
        void *va;
+       int rc;
 
        len = ena_bufs[buf].len;
        req_id = ena_bufs[buf].req_id;
+
+       rc = validate_rx_req_id(rx_ring, req_id);
+       if (unlikely(rc < 0))
+               return NULL;
+
        rx_info = &rx_ring->rx_buffer_info[req_id];
 
        if (unlikely(!rx_info->page)) {
@@ -1454,6 +1456,11 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
                buf++;
                len = ena_bufs[buf].len;
                req_id = ena_bufs[buf].req_id;
+
+               rc = validate_rx_req_id(rx_ring, req_id);
+               if (unlikely(rc < 0))
+                       return NULL;
+
                rx_info = &rx_ring->rx_buffer_info[req_id];
        } while (1);
 
@@ -1968,7 +1975,7 @@ static int ena_enable_msix(struct ena_adapter *adapter)
        }
 
        /* Reserved the max msix vectors we might need */
-       msix_vecs = ENA_MAX_MSIX_VEC(adapter->num_io_queues);
+       msix_vecs = ENA_MAX_MSIX_VEC(adapter->max_num_io_queues);
        netif_dbg(adapter, probe, adapter->netdev,
                  "trying to enable MSI-X, vectors %d\n", msix_vecs);
 
@@ -2068,6 +2075,7 @@ static int ena_request_mgmnt_irq(struct ena_adapter *adapter)
 
 static int ena_request_io_irq(struct ena_adapter *adapter)
 {
+       u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
        unsigned long flags = 0;
        struct ena_irq *irq;
        int rc = 0, i, k;
@@ -2078,7 +2086,7 @@ static int ena_request_io_irq(struct ena_adapter *adapter)
                return -EINVAL;
        }
 
-       for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
+       for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
                irq = &adapter->irq_tbl[i];
                rc = request_irq(irq->vector, irq->handler, flags, irq->name,
                                 irq->data);
@@ -2119,6 +2127,7 @@ static void ena_free_mgmnt_irq(struct ena_adapter *adapter)
 
 static void ena_free_io_irq(struct ena_adapter *adapter)
 {
+       u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
        struct ena_irq *irq;
        int i;
 
@@ -2129,7 +2138,7 @@ static void ena_free_io_irq(struct ena_adapter *adapter)
        }
 #endif /* CONFIG_RFS_ACCEL */
 
-       for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++) {
+       for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++) {
                irq = &adapter->irq_tbl[i];
                irq_set_affinity_hint(irq->vector, NULL);
                free_irq(irq->vector, irq->data);
@@ -2144,12 +2153,13 @@ static void ena_disable_msix(struct ena_adapter *adapter)
 
 static void ena_disable_io_intr_sync(struct ena_adapter *adapter)
 {
+       u32 io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues;
        int i;
 
        if (!netif_running(adapter->netdev))
                return;
 
-       for (i = ENA_IO_IRQ_FIRST_IDX; i < adapter->msix_vecs; i++)
+       for (i = ENA_IO_IRQ_FIRST_IDX; i < ENA_MAX_MSIX_VEC(io_queue_count); i++)
                synchronize_irq(adapter->irq_tbl[i].vector);
 }
 
@@ -3476,6 +3486,7 @@ static int ena_restore_device(struct ena_adapter *adapter)
                netif_carrier_on(adapter->netdev);
 
        mod_timer(&adapter->timer_service, round_jiffies(jiffies + HZ));
+       adapter->last_keep_alive_jiffies = jiffies;
        dev_err(&pdev->dev,
                "Device reset completed successfully, Driver info: %s\n",
                version);
@@ -4325,13 +4336,15 @@ err_disable_device:
 
 /*****************************************************************************/
 
-/* ena_remove - Device Removal Routine
+/* __ena_shutoff - Helper used in both PCI remove/shutdown routines
  * @pdev: PCI device information struct
+ * @shutdown: Is it a shutdown operation? If false, means it is a removal
  *
- * ena_remove is called by the PCI subsystem to alert the driver
- * that it should release a PCI device.
+ * __ena_shutoff is a helper routine that does the real work on shutdown and
+ * removal paths; the difference between those paths is with regards to whether
+ * dettach or unregister the netdevice.
  */
-static void ena_remove(struct pci_dev *pdev)
+static void __ena_shutoff(struct pci_dev *pdev, bool shutdown)
 {
        struct ena_adapter *adapter = pci_get_drvdata(pdev);
        struct ena_com_dev *ena_dev;
@@ -4350,13 +4363,17 @@ static void ena_remove(struct pci_dev *pdev)
 
        cancel_work_sync(&adapter->reset_task);
 
-       rtnl_lock();
+       rtnl_lock(); /* lock released inside the below if-else block */
        ena_destroy_device(adapter, true);
-       rtnl_unlock();
-
-       unregister_netdev(netdev);
-
-       free_netdev(netdev);
+       if (shutdown) {
+               netif_device_detach(netdev);
+               dev_close(netdev);
+               rtnl_unlock();
+       } else {
+               rtnl_unlock();
+               unregister_netdev(netdev);
+               free_netdev(netdev);
+       }
 
        ena_com_rss_destroy(ena_dev);
 
@@ -4371,6 +4388,30 @@ static void ena_remove(struct pci_dev *pdev)
        vfree(ena_dev);
 }
 
+/* ena_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * ena_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.
+ */
+
+static void ena_remove(struct pci_dev *pdev)
+{
+       __ena_shutoff(pdev, false);
+}
+
+/* ena_shutdown - Device Shutdown Routine
+ * @pdev: PCI device information struct
+ *
+ * ena_shutdown is called by the PCI subsystem to alert the driver that
+ * a shutdown/reboot (or kexec) is happening and device must be disabled.
+ */
+
+static void ena_shutdown(struct pci_dev *pdev)
+{
+       __ena_shutoff(pdev, true);
+}
+
 #ifdef CONFIG_PM
 /* ena_suspend - PM suspend callback
  * @pdev: PCI device information struct
@@ -4420,6 +4461,7 @@ static struct pci_driver ena_pci_driver = {
        .id_table       = ena_pci_tbl,
        .probe          = ena_probe,
        .remove         = ena_remove,
+       .shutdown       = ena_shutdown,
 #ifdef CONFIG_PM
        .suspend    = ena_suspend,
        .resume     = ena_resume,
index e0611cb..15b31cd 100644 (file)
@@ -2135,7 +2135,7 @@ static int bcm_sysport_rule_set(struct bcm_sysport_priv *priv,
                return -ENOSPC;
 
        index = find_first_zero_bit(priv->filters, RXCHK_BRCM_TAG_MAX);
-       if (index > RXCHK_BRCM_TAG_MAX)
+       if (index >= RXCHK_BRCM_TAG_MAX)
                return -ENOSPC;
 
        /* Location is the classification ID, and index is the position
index fd6e0e4..d28b406 100644 (file)
@@ -6880,12 +6880,12 @@ skip_rdma:
        }
        ena |= FUNC_BACKING_STORE_CFG_REQ_DFLT_ENABLES;
        rc = bnxt_hwrm_func_backing_store_cfg(bp, ena);
-       if (rc)
+       if (rc) {
                netdev_err(bp->dev, "Failed configuring context mem, rc = %d.\n",
                           rc);
-       else
-               ctx->flags |= BNXT_CTX_FLAG_INITED;
-
+               return rc;
+       }
+       ctx->flags |= BNXT_CTX_FLAG_INITED;
        return 0;
 }
 
@@ -7406,14 +7406,22 @@ static int bnxt_hwrm_port_qstats_ext(struct bnxt *bp)
                pri2cos = &resp2->pri0_cos_queue_id;
                for (i = 0; i < 8; i++) {
                        u8 queue_id = pri2cos[i];
+                       u8 queue_idx;
 
+                       /* Per port queue IDs start from 0, 10, 20, etc */
+                       queue_idx = queue_id % 10;
+                       if (queue_idx > BNXT_MAX_QUEUE) {
+                               bp->pri2cos_valid = false;
+                               goto qstats_done;
+                       }
                        for (j = 0; j < bp->max_q; j++) {
                                if (bp->q_ids[j] == queue_id)
-                                       bp->pri2cos[i] = j;
+                                       bp->pri2cos_idx[i] = queue_idx;
                        }
                }
                bp->pri2cos_valid = 1;
        }
+qstats_done:
        mutex_unlock(&bp->hwrm_cmd_lock);
        return rc;
 }
@@ -10982,13 +10990,13 @@ static int bnxt_change_mtu(struct net_device *dev, int new_mtu)
        struct bnxt *bp = netdev_priv(dev);
 
        if (netif_running(dev))
-               bnxt_close_nic(bp, false, false);
+               bnxt_close_nic(bp, true, false);
 
        dev->mtu = new_mtu;
        bnxt_set_ring_params(bp);
 
        if (netif_running(dev))
-               return bnxt_open_nic(bp, false, false);
+               return bnxt_open_nic(bp, true, false);
 
        return 0;
 }
@@ -11252,7 +11260,7 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp)
                }
        }
        if (test_and_clear_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event))
-               netdev_info(bp->dev, "Receive PF driver unload event!");
+               netdev_info(bp->dev, "Receive PF driver unload event!\n");
 }
 
 #else
@@ -11669,6 +11677,10 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh)
                bp->rx_nr_rings++;
                bp->cp_nr_rings++;
        }
+       if (rc) {
+               bp->tx_nr_rings = 0;
+               bp->rx_nr_rings = 0;
+       }
        return rc;
 }
 
@@ -11759,7 +11771,7 @@ static int bnxt_pcie_dsn_get(struct bnxt *bp, u8 dsn[])
        u32 dw;
 
        if (!pos) {
-               netdev_info(bp->dev, "Unable do read adapter's DSN");
+               netdev_info(bp->dev, "Unable do read adapter's DSN\n");
                return -EOPNOTSUPP;
        }
 
@@ -11962,12 +11974,12 @@ init_err_pci_clean:
        bnxt_hwrm_func_drv_unrgtr(bp);
        bnxt_free_hwrm_short_cmd_req(bp);
        bnxt_free_hwrm_resources(bp);
-       bnxt_free_ctx_mem(bp);
-       kfree(bp->ctx);
-       bp->ctx = NULL;
        kfree(bp->fw_health);
        bp->fw_health = NULL;
        bnxt_cleanup_pci(bp);
+       bnxt_free_ctx_mem(bp);
+       kfree(bp->ctx);
+       bp->ctx = NULL;
 
 init_err_free:
        free_netdev(dev);
index cabef0b..63b1706 100644 (file)
@@ -1716,7 +1716,7 @@ struct bnxt {
        u16                     fw_rx_stats_ext_size;
        u16                     fw_tx_stats_ext_size;
        u16                     hw_ring_stats_size;
-       u8                      pri2cos[8];
+       u8                      pri2cos_idx[8];
        u8                      pri2cos_valid;
 
        u16                     hwrm_max_req_len;
index fb6f30d..b1511bc 100644 (file)
@@ -479,24 +479,26 @@ static int bnxt_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets)
 {
        struct bnxt *bp = netdev_priv(dev);
        struct ieee_ets *my_ets = bp->ieee_ets;
+       int rc;
 
        ets->ets_cap = bp->max_tc;
 
        if (!my_ets) {
-               int rc;
-
                if (bp->dcbx_cap & DCB_CAP_DCBX_HOST)
                        return 0;
 
                my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL);
                if (!my_ets)
-                       return 0;
+                       return -ENOMEM;
                rc = bnxt_hwrm_queue_cos2bw_qcfg(bp, my_ets);
                if (rc)
-                       return 0;
+                       goto error;
                rc = bnxt_hwrm_queue_pri2cos_qcfg(bp, my_ets);
                if (rc)
-                       return 0;
+                       goto error;
+
+               /* cache result */
+               bp->ieee_ets = my_ets;
        }
 
        ets->cbs = my_ets->cbs;
@@ -505,6 +507,9 @@ static int bnxt_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets)
        memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
        memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
        return 0;
+error:
+       kfree(my_ets);
+       return rc;
 }
 
 static int bnxt_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets)
index eec0168..d3c93cc 100644 (file)
@@ -641,14 +641,14 @@ static int bnxt_dl_params_register(struct bnxt *bp)
        rc = devlink_params_register(bp->dl, bnxt_dl_params,
                                     ARRAY_SIZE(bnxt_dl_params));
        if (rc) {
-               netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
+               netdev_warn(bp->dev, "devlink_params_register failed. rc=%d\n",
                            rc);
                return rc;
        }
        rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
                                          ARRAY_SIZE(bnxt_dl_port_params));
        if (rc) {
-               netdev_err(bp->dev, "devlink_port_params_register failed");
+               netdev_err(bp->dev, "devlink_port_params_register failed\n");
                devlink_params_unregister(bp->dl, bnxt_dl_params,
                                          ARRAY_SIZE(bnxt_dl_params));
                return rc;
@@ -679,7 +679,7 @@ int bnxt_dl_register(struct bnxt *bp)
        else
                dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl));
        if (!dl) {
-               netdev_warn(bp->dev, "devlink_alloc failed");
+               netdev_warn(bp->dev, "devlink_alloc failed\n");
                return -ENOMEM;
        }
 
@@ -692,7 +692,7 @@ int bnxt_dl_register(struct bnxt *bp)
 
        rc = devlink_register(dl, &bp->pdev->dev);
        if (rc) {
-               netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
+               netdev_warn(bp->dev, "devlink_register failed. rc=%d\n", rc);
                goto err_dl_free;
        }
 
@@ -704,7 +704,7 @@ int bnxt_dl_register(struct bnxt *bp)
                               sizeof(bp->dsn));
        rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
        if (rc) {
-               netdev_err(bp->dev, "devlink_port_register failed");
+               netdev_err(bp->dev, "devlink_port_register failed\n");
                goto err_dl_unreg;
        }
 
index 6171fa8..3f8a1de 100644 (file)
@@ -589,25 +589,25 @@ skip_ring_stats:
                if (bp->pri2cos_valid) {
                        for (i = 0; i < 8; i++, j++) {
                                long n = bnxt_rx_bytes_pri_arr[i].base_off +
-                                        bp->pri2cos[i];
+                                        bp->pri2cos_idx[i];
 
                                buf[j] = le64_to_cpu(*(rx_port_stats_ext + n));
                        }
                        for (i = 0; i < 8; i++, j++) {
                                long n = bnxt_rx_pkts_pri_arr[i].base_off +
-                                        bp->pri2cos[i];
+                                        bp->pri2cos_idx[i];
 
                                buf[j] = le64_to_cpu(*(rx_port_stats_ext + n));
                        }
                        for (i = 0; i < 8; i++, j++) {
                                long n = bnxt_tx_bytes_pri_arr[i].base_off +
-                                        bp->pri2cos[i];
+                                        bp->pri2cos_idx[i];
 
                                buf[j] = le64_to_cpu(*(tx_port_stats_ext + n));
                        }
                        for (i = 0; i < 8; i++, j++) {
                                long n = bnxt_tx_pkts_pri_arr[i].base_off +
-                                        bp->pri2cos[i];
+                                        bp->pri2cos_idx[i];
 
                                buf[j] = le64_to_cpu(*(tx_port_stats_ext + n));
                        }
@@ -2007,8 +2007,8 @@ int bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
        struct hwrm_nvm_install_update_output *resp = bp->hwrm_cmd_resp_addr;
        struct hwrm_nvm_install_update_input install = {0};
        const struct firmware *fw;
-       int rc, hwrm_err = 0;
        u32 item_len;
+       int rc = 0;
        u16 index;
 
        bnxt_hwrm_fw_set_time(bp);
@@ -2028,7 +2028,7 @@ int bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
        }
 
        if (fw->size > item_len) {
-               netdev_err(dev, "PKG insufficient update area in nvram: %lu",
+               netdev_err(dev, "PKG insufficient update area in nvram: %lu\n",
                           (unsigned long)fw->size);
                rc = -EFBIG;
        } else {
@@ -2052,15 +2052,14 @@ int bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
                        memcpy(kmem, fw->data, fw->size);
                        modify.host_src_addr = cpu_to_le64(dma_handle);
 
-                       hwrm_err = hwrm_send_message(bp, &modify,
-                                                    sizeof(modify),
-                                                    FLASH_PACKAGE_TIMEOUT);
+                       rc = hwrm_send_message(bp, &modify, sizeof(modify),
+                                              FLASH_PACKAGE_TIMEOUT);
                        dma_free_coherent(&bp->pdev->dev, fw->size, kmem,
                                          dma_handle);
                }
        }
        release_firmware(fw);
-       if (rc || hwrm_err)
+       if (rc)
                goto err_exit;
 
        if ((install_type & 0xffff) == 0)
@@ -2069,20 +2068,19 @@ int bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
        install.install_type = cpu_to_le32(install_type);
 
        mutex_lock(&bp->hwrm_cmd_lock);
-       hwrm_err = _hwrm_send_message(bp, &install, sizeof(install),
-                                     INSTALL_PACKAGE_TIMEOUT);
-       if (hwrm_err) {
+       rc = _hwrm_send_message(bp, &install, sizeof(install),
+                               INSTALL_PACKAGE_TIMEOUT);
+       if (rc) {
                u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err;
 
                if (resp->error_code && error_code ==
                    NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
                        install.flags |= cpu_to_le16(
                               NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
-                       hwrm_err = _hwrm_send_message(bp, &install,
-                                                     sizeof(install),
-                                                     INSTALL_PACKAGE_TIMEOUT);
+                       rc = _hwrm_send_message(bp, &install, sizeof(install),
+                                               INSTALL_PACKAGE_TIMEOUT);
                }
-               if (hwrm_err)
+               if (rc)
                        goto flash_pkg_exit;
        }
 
@@ -2094,7 +2092,7 @@ int bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
 flash_pkg_exit:
        mutex_unlock(&bp->hwrm_cmd_lock);
 err_exit:
-       if (hwrm_err == -EACCES)
+       if (rc == -EACCES)
                bnxt_print_admin_err(bp);
        return rc;
 }
@@ -3338,7 +3336,7 @@ err:
        kfree(coredump.data);
        *dump_len += sizeof(struct bnxt_coredump_record);
        if (rc == -ENOBUFS)
-               netdev_err(bp->dev, "Firmware returned large coredump buffer");
+               netdev_err(bp->dev, "Firmware returned large coredump buffer\n");
        return rc;
 }
 
index 0cc6ec5..9bec256 100644 (file)
@@ -50,7 +50,7 @@ static u16 bnxt_flow_get_dst_fid(struct bnxt *pf_bp, struct net_device *dev)
 
        /* check if dev belongs to the same switch */
        if (!netdev_port_same_parent_id(pf_bp->dev, dev)) {
-               netdev_info(pf_bp->dev, "dev(ifindex=%d) not on same switch",
+               netdev_info(pf_bp->dev, "dev(ifindex=%d) not on same switch\n",
                            dev->ifindex);
                return BNXT_FID_INVALID;
        }
@@ -70,7 +70,7 @@ static int bnxt_tc_parse_redir(struct bnxt *bp,
        struct net_device *dev = act->dev;
 
        if (!dev) {
-               netdev_info(bp->dev, "no dev in mirred action");
+               netdev_info(bp->dev, "no dev in mirred action\n");
                return -EINVAL;
        }
 
@@ -106,7 +106,7 @@ static int bnxt_tc_parse_tunnel_set(struct bnxt *bp,
        const struct ip_tunnel_key *tun_key = &tun_info->key;
 
        if (ip_tunnel_info_af(tun_info) != AF_INET) {
-               netdev_info(bp->dev, "only IPv4 tunnel-encap is supported");
+               netdev_info(bp->dev, "only IPv4 tunnel-encap is supported\n");
                return -EOPNOTSUPP;
        }
 
@@ -295,7 +295,7 @@ static int bnxt_tc_parse_actions(struct bnxt *bp,
        int i, rc;
 
        if (!flow_action_has_entries(flow_action)) {
-               netdev_info(bp->dev, "no actions");
+               netdev_info(bp->dev, "no actions\n");
                return -EINVAL;
        }
 
@@ -370,7 +370,7 @@ static int bnxt_tc_parse_flow(struct bnxt *bp,
        /* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */
        if ((dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) == 0 ||
            (dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_BASIC)) == 0) {
-               netdev_info(bp->dev, "cannot form TC key: used_keys = 0x%x",
+               netdev_info(bp->dev, "cannot form TC key: used_keys = 0x%x\n",
                            dissector->used_keys);
                return -EOPNOTSUPP;
        }
@@ -508,7 +508,7 @@ static int bnxt_hwrm_cfa_flow_free(struct bnxt *bp,
 
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
 
        return rc;
 }
@@ -841,7 +841,7 @@ static int hwrm_cfa_decap_filter_alloc(struct bnxt *bp,
                resp = bnxt_get_hwrm_resp_addr(bp, &req);
                *decap_filter_handle = resp->decap_filter_id;
        } else {
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
        }
        mutex_unlock(&bp->hwrm_cmd_lock);
 
@@ -859,7 +859,7 @@ static int hwrm_cfa_decap_filter_free(struct bnxt *bp,
 
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
 
        return rc;
 }
@@ -906,7 +906,7 @@ static int hwrm_cfa_encap_record_alloc(struct bnxt *bp,
                resp = bnxt_get_hwrm_resp_addr(bp, &req);
                *encap_record_handle = resp->encap_record_id;
        } else {
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
        }
        mutex_unlock(&bp->hwrm_cmd_lock);
 
@@ -924,7 +924,7 @@ static int hwrm_cfa_encap_record_free(struct bnxt *bp,
 
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
-               netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s: Error rc=%d\n", __func__, rc);
 
        return rc;
 }
@@ -943,7 +943,7 @@ static int bnxt_tc_put_l2_node(struct bnxt *bp,
                                             tc_info->l2_ht_params);
                if (rc)
                        netdev_err(bp->dev,
-                                  "Error: %s: rhashtable_remove_fast: %d",
+                                  "Error: %s: rhashtable_remove_fast: %d\n",
                                   __func__, rc);
                kfree_rcu(l2_node, rcu);
        }
@@ -972,7 +972,7 @@ bnxt_tc_get_l2_node(struct bnxt *bp, struct rhashtable *l2_table,
                if (rc) {
                        kfree_rcu(l2_node, rcu);
                        netdev_err(bp->dev,
-                                  "Error: %s: rhashtable_insert_fast: %d",
+                                  "Error: %s: rhashtable_insert_fast: %d\n",
                                   __func__, rc);
                        return NULL;
                }
@@ -1031,7 +1031,7 @@ static bool bnxt_tc_can_offload(struct bnxt *bp, struct bnxt_tc_flow *flow)
        if ((flow->flags & BNXT_TC_FLOW_FLAGS_PORTS) &&
            (flow->l4_key.ip_proto != IPPROTO_TCP &&
             flow->l4_key.ip_proto != IPPROTO_UDP)) {
-               netdev_info(bp->dev, "Cannot offload non-TCP/UDP (%d) ports",
+               netdev_info(bp->dev, "Cannot offload non-TCP/UDP (%d) ports\n",
                            flow->l4_key.ip_proto);
                return false;
        }
@@ -1088,7 +1088,7 @@ static int bnxt_tc_put_tunnel_node(struct bnxt *bp,
                rc =  rhashtable_remove_fast(tunnel_table, &tunnel_node->node,
                                             *ht_params);
                if (rc) {
-                       netdev_err(bp->dev, "rhashtable_remove_fast rc=%d", rc);
+                       netdev_err(bp->dev, "rhashtable_remove_fast rc=%d\n", rc);
                        rc = -1;
                }
                kfree_rcu(tunnel_node, rcu);
@@ -1129,7 +1129,7 @@ bnxt_tc_get_tunnel_node(struct bnxt *bp, struct rhashtable *tunnel_table,
        tunnel_node->refcount++;
        return tunnel_node;
 err:
-       netdev_info(bp->dev, "error rc=%d", rc);
+       netdev_info(bp->dev, "error rc=%d\n", rc);
        return NULL;
 }
 
@@ -1187,7 +1187,7 @@ static void bnxt_tc_put_decap_l2_node(struct bnxt *bp,
                                             &decap_l2_node->node,
                                             tc_info->decap_l2_ht_params);
                if (rc)
-                       netdev_err(bp->dev, "rhashtable_remove_fast rc=%d", rc);
+                       netdev_err(bp->dev, "rhashtable_remove_fast rc=%d\n", rc);
                kfree_rcu(decap_l2_node, rcu);
        }
 }
@@ -1227,7 +1227,7 @@ static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
 
        rt = ip_route_output_key(dev_net(real_dst_dev), &flow);
        if (IS_ERR(rt)) {
-               netdev_info(bp->dev, "no route to %pI4b", &flow.daddr);
+               netdev_info(bp->dev, "no route to %pI4b\n", &flow.daddr);
                return -EOPNOTSUPP;
        }
 
@@ -1241,7 +1241,7 @@ static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
 
                if (vlan->real_dev != real_dst_dev) {
                        netdev_info(bp->dev,
-                                   "dst_dev(%s) doesn't use PF-if(%s)",
+                                   "dst_dev(%s) doesn't use PF-if(%s)\n",
                                    netdev_name(dst_dev),
                                    netdev_name(real_dst_dev));
                        rc = -EOPNOTSUPP;
@@ -1253,7 +1253,7 @@ static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
 #endif
        } else if (dst_dev != real_dst_dev) {
                netdev_info(bp->dev,
-                           "dst_dev(%s) for %pI4b is not PF-if(%s)",
+                           "dst_dev(%s) for %pI4b is not PF-if(%s)\n",
                            netdev_name(dst_dev), &flow.daddr,
                            netdev_name(real_dst_dev));
                rc = -EOPNOTSUPP;
@@ -1262,7 +1262,7 @@ static int bnxt_tc_resolve_tunnel_hdrs(struct bnxt *bp,
 
        nbr = dst_neigh_lookup(&rt->dst, &flow.daddr);
        if (!nbr) {
-               netdev_info(bp->dev, "can't lookup neighbor for %pI4b",
+               netdev_info(bp->dev, "can't lookup neighbor for %pI4b\n",
                            &flow.daddr);
                rc = -EOPNOTSUPP;
                goto put_rt;
@@ -1472,7 +1472,7 @@ static int __bnxt_tc_del_flow(struct bnxt *bp,
        rc = rhashtable_remove_fast(&tc_info->flow_table, &flow_node->node,
                                    tc_info->flow_ht_params);
        if (rc)
-               netdev_err(bp->dev, "Error: %s: rhashtable_remove_fast rc=%d",
+               netdev_err(bp->dev, "Error: %s: rhashtable_remove_fast rc=%d\n",
                           __func__, rc);
 
        kfree_rcu(flow_node, rcu);
@@ -1587,7 +1587,7 @@ unlock:
 free_node:
        kfree_rcu(new_node, rcu);
 done:
-       netdev_err(bp->dev, "Error: %s: cookie=0x%lx error=%d",
+       netdev_err(bp->dev, "Error: %s: cookie=0x%lx error=%d\n",
                   __func__, tc_flow_cmd->cookie, rc);
        return rc;
 }
@@ -1700,7 +1700,7 @@ bnxt_hwrm_cfa_flow_stats_get(struct bnxt *bp, int num_flows,
                                                le64_to_cpu(resp_bytes[i]);
                }
        } else {
-               netdev_info(bp->dev, "error rc=%d", rc);
+               netdev_info(bp->dev, "error rc=%d\n", rc);
        }
        mutex_unlock(&bp->hwrm_cmd_lock);
 
@@ -1970,7 +1970,7 @@ static int bnxt_tc_indr_block_event(struct notifier_block *nb,
                                                   bp);
                if (rc)
                        netdev_info(bp->dev,
-                                   "Failed to register indirect blk: dev: %s",
+                                   "Failed to register indirect blk: dev: %s\n",
                                    netdev->name);
                break;
        case NETDEV_UNREGISTER:
index b010b34..6f2faf8 100644 (file)
@@ -43,7 +43,7 @@ static int hwrm_cfa_vfr_alloc(struct bnxt *bp, u16 vf_idx,
                netdev_dbg(bp->dev, "tx_cfa_action=0x%x, rx_cfa_code=0x%x",
                           *tx_cfa_action, *rx_cfa_code);
        } else {
-               netdev_info(bp->dev, "%s error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s error rc=%d\n", __func__, rc);
        }
 
        mutex_unlock(&bp->hwrm_cmd_lock);
@@ -60,7 +60,7 @@ static int hwrm_cfa_vfr_free(struct bnxt *bp, u16 vf_idx)
 
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
-               netdev_info(bp->dev, "%s error rc=%d", __func__, rc);
+               netdev_info(bp->dev, "%s error rc=%d\n", __func__, rc);
        return rc;
 }
 
@@ -465,7 +465,7 @@ static int bnxt_vf_reps_create(struct bnxt *bp)
        return 0;
 
 err:
-       netdev_info(bp->dev, "%s error=%d", __func__, rc);
+       netdev_info(bp->dev, "%s error=%d\n", __func__, rc);
        kfree(cfa_code_map);
        __bnxt_vf_reps_destroy(bp);
        return rc;
@@ -488,7 +488,7 @@ int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
 
        mutex_lock(&bp->sriov_lock);
        if (bp->eswitch_mode == mode) {
-               netdev_info(bp->dev, "already in %s eswitch mode",
+               netdev_info(bp->dev, "already in %s eswitch mode\n",
                            mode == DEVLINK_ESWITCH_MODE_LEGACY ?
                            "legacy" : "switchdev");
                rc = -EINVAL;
@@ -508,7 +508,7 @@ int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
                }
 
                if (pci_num_vf(bp->pdev) == 0) {
-                       netdev_info(bp->dev, "Enable VFs before setting switchdev mode");
+                       netdev_info(bp->dev, "Enable VFs before setting switchdev mode\n");
                        rc = -EPERM;
                        goto done;
                }
index e50a153..1d678be 100644 (file)
@@ -94,12 +94,6 @@ static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv,
        bcmgenet_writel(value, d + DMA_DESC_LENGTH_STATUS);
 }
 
-static inline u32 dmadesc_get_length_status(struct bcmgenet_priv *priv,
-                                           void __iomem *d)
-{
-       return bcmgenet_readl(d + DMA_DESC_LENGTH_STATUS);
-}
-
 static inline void dmadesc_set_addr(struct bcmgenet_priv *priv,
                                    void __iomem *d,
                                    dma_addr_t addr)
@@ -508,61 +502,6 @@ static int bcmgenet_set_link_ksettings(struct net_device *dev,
        return phy_ethtool_ksettings_set(dev->phydev, cmd);
 }
 
-static void bcmgenet_set_rx_csum(struct net_device *dev,
-                                netdev_features_t wanted)
-{
-       struct bcmgenet_priv *priv = netdev_priv(dev);
-       u32 rbuf_chk_ctrl;
-       bool rx_csum_en;
-
-       rx_csum_en = !!(wanted & NETIF_F_RXCSUM);
-
-       rbuf_chk_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL);
-
-       /* enable rx checksumming */
-       if (rx_csum_en)
-               rbuf_chk_ctrl |= RBUF_RXCHK_EN | RBUF_L3_PARSE_DIS;
-       else
-               rbuf_chk_ctrl &= ~RBUF_RXCHK_EN;
-       priv->desc_rxchk_en = rx_csum_en;
-
-       /* If UniMAC forwards CRC, we need to skip over it to get
-        * a valid CHK bit to be set in the per-packet status word
-       */
-       if (rx_csum_en && priv->crc_fwd_en)
-               rbuf_chk_ctrl |= RBUF_SKIP_FCS;
-       else
-               rbuf_chk_ctrl &= ~RBUF_SKIP_FCS;
-
-       bcmgenet_rbuf_writel(priv, rbuf_chk_ctrl, RBUF_CHK_CTRL);
-}
-
-static void bcmgenet_set_tx_csum(struct net_device *dev,
-                                netdev_features_t wanted)
-{
-       struct bcmgenet_priv *priv = netdev_priv(dev);
-       bool desc_64b_en;
-       u32 tbuf_ctrl, rbuf_ctrl;
-
-       tbuf_ctrl = bcmgenet_tbuf_ctrl_get(priv);
-       rbuf_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CTRL);
-
-       desc_64b_en = !!(wanted & NETIF_F_HW_CSUM);
-
-       /* enable 64 bytes descriptor in both directions (RBUF and TBUF) */
-       if (desc_64b_en) {
-               tbuf_ctrl |= RBUF_64B_EN;
-               rbuf_ctrl |= RBUF_64B_EN;
-       } else {
-               tbuf_ctrl &= ~RBUF_64B_EN;
-               rbuf_ctrl &= ~RBUF_64B_EN;
-       }
-       priv->desc_64b_en = desc_64b_en;
-
-       bcmgenet_tbuf_ctrl_set(priv, tbuf_ctrl);
-       bcmgenet_rbuf_writel(priv, rbuf_ctrl, RBUF_CTRL);
-}
-
 static int bcmgenet_set_features(struct net_device *dev,
                                 netdev_features_t features)
 {
@@ -578,9 +517,6 @@ static int bcmgenet_set_features(struct net_device *dev,
        reg = bcmgenet_umac_readl(priv, UMAC_CMD);
        priv->crc_fwd_en = !!(reg & CMD_CRC_FWD);
 
-       bcmgenet_set_tx_csum(dev, features);
-       bcmgenet_set_rx_csum(dev, features);
-
        clk_disable_unprepare(priv->clk);
 
        return ret;
@@ -1475,8 +1411,8 @@ static void bcmgenet_tx_reclaim_all(struct net_device *dev)
 /* Reallocate the SKB to put enough headroom in front of it and insert
  * the transmit checksum offsets in the descriptors
  */
-static struct sk_buff *bcmgenet_put_tx_csum(struct net_device *dev,
-                                           struct sk_buff *skb)
+static struct sk_buff *bcmgenet_add_tsb(struct net_device *dev,
+                                       struct sk_buff *skb)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        struct status_64 *status = NULL;
@@ -1590,13 +1526,11 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        GENET_CB(skb)->bytes_sent = skb->len;
 
-       /* set the SKB transmit checksum */
-       if (priv->desc_64b_en) {
-               skb = bcmgenet_put_tx_csum(dev, skb);
-               if (!skb) {
-                       ret = NETDEV_TX_OK;
-                       goto out;
-               }
+       /* add the Transmit Status Block */
+       skb = bcmgenet_add_tsb(dev, skb);
+       if (!skb) {
+               ret = NETDEV_TX_OK;
+               goto out;
        }
 
        for (i = 0; i <= nr_frags; i++) {
@@ -1775,6 +1709,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
 
        while ((rxpktprocessed < rxpkttoprocess) &&
               (rxpktprocessed < budget)) {
+               struct status_64 *status;
+               __be16 rx_csum;
+
                cb = &priv->rx_cbs[ring->read_ptr];
                skb = bcmgenet_rx_refill(priv, cb);
 
@@ -1783,20 +1720,12 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
                        goto next;
                }
 
-               if (!priv->desc_64b_en) {
-                       dma_length_status =
-                               dmadesc_get_length_status(priv, cb->bd_addr);
-               } else {
-                       struct status_64 *status;
-                       __be16 rx_csum;
-
-                       status = (struct status_64 *)skb->data;
-                       dma_length_status = status->length_status;
+               status = (struct status_64 *)skb->data;
+               dma_length_status = status->length_status;
+               if (dev->features & NETIF_F_RXCSUM) {
                        rx_csum = (__force __be16)(status->rx_csum & 0xffff);
-                       if (priv->desc_rxchk_en) {
-                               skb->csum = (__force __wsum)ntohs(rx_csum);
-                               skb->ip_summed = CHECKSUM_COMPLETE;
-                       }
+                       skb->csum = (__force __wsum)ntohs(rx_csum);
+                       skb->ip_summed = CHECKSUM_COMPLETE;
                }
 
                /* DMA flags and length are still valid no matter how
@@ -1840,14 +1769,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring,
                } /* error packet */
 
                skb_put(skb, len);
-               if (priv->desc_64b_en) {
-                       skb_pull(skb, 64);
-                       len -= 64;
-               }
 
-               /* remove hardware 2bytes added for IP alignment */
-               skb_pull(skb, 2);
-               len -= 2;
+               /* remove RSB and hardware 2bytes added for IP alignment */
+               skb_pull(skb, 66);
+               len -= 66;
 
                if (priv->crc_fwd_en) {
                        skb_trim(skb, len - ETH_FCS_LEN);
@@ -1965,6 +1890,8 @@ static void umac_enable_set(struct bcmgenet_priv *priv, u32 mask, bool enable)
        u32 reg;
 
        reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       if (reg & CMD_SW_RESET)
+               return;
        if (enable)
                reg |= mask;
        else
@@ -1984,11 +1911,9 @@ static void reset_umac(struct bcmgenet_priv *priv)
        bcmgenet_rbuf_ctrl_set(priv, 0);
        udelay(10);
 
-       /* disable MAC while updating its registers */
-       bcmgenet_umac_writel(priv, 0, UMAC_CMD);
-
-       /* issue soft reset with (rg)mii loopback to ensure a stable rxclk */
-       bcmgenet_umac_writel(priv, CMD_SW_RESET | CMD_LCL_LOOP_EN, UMAC_CMD);
+       /* issue soft reset and disable MAC while updating its registers */
+       bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD);
+       udelay(2);
 }
 
 static void bcmgenet_intr_disable(struct bcmgenet_priv *priv)
@@ -2038,11 +1963,28 @@ static void init_umac(struct bcmgenet_priv *priv)
 
        bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
 
-       /* init rx registers, enable ip header optimization */
+       /* init tx registers, enable TSB */
+       reg = bcmgenet_tbuf_ctrl_get(priv);
+       reg |= TBUF_64B_EN;
+       bcmgenet_tbuf_ctrl_set(priv, reg);
+
+       /* init rx registers, enable ip header optimization and RSB */
        reg = bcmgenet_rbuf_readl(priv, RBUF_CTRL);
-       reg |= RBUF_ALIGN_2B;
+       reg |= RBUF_ALIGN_2B | RBUF_64B_EN;
        bcmgenet_rbuf_writel(priv, reg, RBUF_CTRL);
 
+       /* enable rx checksumming */
+       reg = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL);
+       reg |= RBUF_RXCHK_EN | RBUF_L3_PARSE_DIS;
+       /* If UniMAC forwards CRC, we need to skip over it to get
+        * a valid CHK bit to be set in the per-packet status word
+        */
+       if (priv->crc_fwd_en)
+               reg |= RBUF_SKIP_FCS;
+       else
+               reg &= ~RBUF_SKIP_FCS;
+       bcmgenet_rbuf_writel(priv, reg, RBUF_CHK_CTRL);
+
        if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv))
                bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL);
 
index 61a6fe9..daf8fb2 100644 (file)
@@ -273,6 +273,7 @@ struct bcmgenet_mib_counters {
 #define  RBUF_FLTR_LEN_SHIFT           8
 
 #define TBUF_CTRL                      0x00
+#define  TBUF_64B_EN                   (1 << 0)
 #define TBUF_BP_MC                     0x0C
 #define TBUF_ENERGY_CTRL               0x14
 #define  TBUF_EEE_EN                   (1 << 0)
@@ -662,8 +663,6 @@ struct bcmgenet_priv {
        unsigned int irq0_stat;
 
        /* HW descriptors/checksum variables */
-       bool desc_64b_en;
-       bool desc_rxchk_en;
        bool crc_fwd_en;
 
        u32 dma_max_burst_length;
index ea20d94..c9a4369 100644 (file)
@@ -132,8 +132,12 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
                return -EINVAL;
        }
 
-       /* disable RX */
+       /* Can't suspend with WoL if MAC is still in reset */
        reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       if (reg & CMD_SW_RESET)
+               reg &= ~CMD_SW_RESET;
+
+       /* disable RX */
        reg &= ~CMD_RX_EN;
        bcmgenet_umac_writel(priv, reg, UMAC_CMD);
        mdelay(10);
index 6392a25..b5930f8 100644 (file)
@@ -95,6 +95,12 @@ void bcmgenet_mii_setup(struct net_device *dev)
                               CMD_HD_EN |
                               CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE);
                reg |= cmd_bits;
+               if (reg & CMD_SW_RESET) {
+                       reg &= ~CMD_SW_RESET;
+                       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+                       udelay(2);
+                       reg |= CMD_TX_EN | CMD_RX_EN;
+               }
                bcmgenet_umac_writel(priv, reg, UMAC_CMD);
        } else {
                /* done if nothing has changed */
@@ -181,38 +187,8 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
        const char *phy_name = NULL;
        u32 id_mode_dis = 0;
        u32 port_ctrl;
-       int bmcr = -1;
-       int ret;
        u32 reg;
 
-       /* MAC clocking workaround during reset of umac state machines */
-       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
-       if (reg & CMD_SW_RESET) {
-               /* An MII PHY must be isolated to prevent TXC contention */
-               if (priv->phy_interface == PHY_INTERFACE_MODE_MII) {
-                       ret = phy_read(phydev, MII_BMCR);
-                       if (ret >= 0) {
-                               bmcr = ret;
-                               ret = phy_write(phydev, MII_BMCR,
-                                               bmcr | BMCR_ISOLATE);
-                       }
-                       if (ret) {
-                               netdev_err(dev, "failed to isolate PHY\n");
-                               return ret;
-                       }
-               }
-               /* Switch MAC clocking to RGMII generated clock */
-               bcmgenet_sys_writel(priv, PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
-               /* Ensure 5 clks with Rx disabled
-                * followed by 5 clks with Reset asserted
-                */
-               udelay(4);
-               reg &= ~(CMD_SW_RESET | CMD_LCL_LOOP_EN);
-               bcmgenet_umac_writel(priv, reg, UMAC_CMD);
-               /* Ensure 5 more clocks before Rx is enabled */
-               udelay(2);
-       }
-
        switch (priv->phy_interface) {
        case PHY_INTERFACE_MODE_INTERNAL:
                phy_name = "internal PHY";
@@ -282,10 +258,6 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
 
        bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
 
-       /* Restore the MII PHY after isolation */
-       if (bmcr >= 0)
-               phy_write(phydev, MII_BMCR, bmcr);
-
        priv->ext_phy = !priv->internal_phy &&
                        (priv->phy_interface != PHY_INTERFACE_MODE_MOCA);
 
@@ -294,6 +266,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init)
         */
        if (priv->ext_phy) {
                reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
+               reg &= ~ID_MODE_DIS;
                reg |= id_mode_dis;
                if (GENET_IS_V1(priv) || GENET_IS_V2(priv) || GENET_IS_V3(priv))
                        reg |= RGMII_MODE_EN_V123;
index 2a2938b..fc05248 100644 (file)
@@ -902,7 +902,7 @@ void clear_all_filters(struct adapter *adapter)
                                adapter->tids.tid_tab[i];
 
                        if (f && (f->valid || f->pending))
-                               cxgb4_del_filter(dev, i, &f->fs);
+                               cxgb4_del_filter(dev, f->tid, &f->fs);
                }
 
                sb = t4_read_reg(adapter, LE_DB_SRVR_START_INDEX_A);
@@ -910,7 +910,7 @@ void clear_all_filters(struct adapter *adapter)
                        f = (struct filter_entry *)adapter->tids.tid_tab[i];
 
                        if (f && (f->valid || f->pending))
-                               cxgb4_del_filter(dev, i, &f->fs);
+                               cxgb4_del_filter(dev, f->tid, &f->fs);
                }
        }
 }
index 649842a..97f90ed 100644 (file)
@@ -5381,12 +5381,11 @@ static inline bool is_x_10g_port(const struct link_config *lc)
 static int cfg_queues(struct adapter *adap)
 {
        u32 avail_qsets, avail_eth_qsets, avail_uld_qsets;
+       u32 i, n10g = 0, qidx = 0, n1g = 0;
+       u32 ncpus = num_online_cpus();
        u32 niqflint, neq, num_ulds;
        struct sge *s = &adap->sge;
-       u32 i, n10g = 0, qidx = 0;
-#ifndef CONFIG_CHELSIO_T4_DCB
-       int q10g = 0;
-#endif
+       u32 q10g = 0, q1g;
 
        /* Reduce memory usage in kdump environment, disable all offload. */
        if (is_kdump_kernel() || (is_uld(adap) && t4_uld_mem_alloc(adap))) {
@@ -5424,44 +5423,50 @@ static int cfg_queues(struct adapter *adap)
                n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg);
 
        avail_eth_qsets = min_t(u32, avail_qsets, MAX_ETH_QSETS);
+
+       /* We default to 1 queue per non-10G port and up to # of cores queues
+        * per 10G port.
+        */
+       if (n10g)
+               q10g = (avail_eth_qsets - (adap->params.nports - n10g)) / n10g;
+
+       n1g = adap->params.nports - n10g;
 #ifdef CONFIG_CHELSIO_T4_DCB
        /* For Data Center Bridging support we need to be able to support up
         * to 8 Traffic Priorities; each of which will be assigned to its
         * own TX Queue in order to prevent Head-Of-Line Blocking.
         */
+       q1g = 8;
        if (adap->params.nports * 8 > avail_eth_qsets) {
                dev_err(adap->pdev_dev, "DCB avail_eth_qsets=%d < %d!\n",
                        avail_eth_qsets, adap->params.nports * 8);
                return -ENOMEM;
        }
 
-       for_each_port(adap, i) {
-               struct port_info *pi = adap2pinfo(adap, i);
+       if (adap->params.nports * ncpus < avail_eth_qsets)
+               q10g = max(8U, ncpus);
+       else
+               q10g = max(8U, q10g);
 
-               pi->first_qset = qidx;
-               pi->nqsets = is_kdump_kernel() ? 1 : 8;
-               qidx += pi->nqsets;
-       }
-#else /* !CONFIG_CHELSIO_T4_DCB */
-       /* We default to 1 queue per non-10G port and up to # of cores queues
-        * per 10G port.
-        */
-       if (n10g)
-               q10g = (avail_eth_qsets - (adap->params.nports - n10g)) / n10g;
-       if (q10g > netif_get_num_default_rss_queues())
-               q10g = netif_get_num_default_rss_queues();
+       while ((q10g * n10g) > (avail_eth_qsets - n1g * q1g))
+               q10g--;
 
-       if (is_kdump_kernel())
+#else /* !CONFIG_CHELSIO_T4_DCB */
+       q1g = 1;
+       q10g = min(q10g, ncpus);
+#endif /* !CONFIG_CHELSIO_T4_DCB */
+       if (is_kdump_kernel()) {
                q10g = 1;
+               q1g = 1;
+       }
 
        for_each_port(adap, i) {
                struct port_info *pi = adap2pinfo(adap, i);
 
                pi->first_qset = qidx;
-               pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : 1;
+               pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : q1g;
                qidx += pi->nqsets;
        }
-#endif /* !CONFIG_CHELSIO_T4_DCB */
 
        s->ethqsets = qidx;
        s->max_ethqsets = qidx;   /* MSI-X may lower it later */
@@ -5473,7 +5478,7 @@ static int cfg_queues(struct adapter *adap)
                 * capped by the number of available cores.
                 */
                num_ulds = adap->num_uld + adap->num_ofld_uld;
-               i = min_t(u32, MAX_OFLD_QSETS, num_online_cpus());
+               i = min_t(u32, MAX_OFLD_QSETS, ncpus);
                avail_uld_qsets = roundup(i, adap->params.nports);
                if (avail_qsets < num_ulds * adap->params.nports) {
                        adap->params.offload = 0;
index 58a039c..af1f40c 100644 (file)
@@ -246,6 +246,9 @@ static int  cxgb4_ptp_fineadjtime(struct adapter *adapter, s64 delta)
                             FW_PTP_CMD_PORTID_V(0));
        c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
        c.u.ts.sc = FW_PTP_SC_ADJ_FTIME;
+       c.u.ts.sign = (delta < 0) ? 1 : 0;
+       if (delta < 0)
+               delta = -delta;
        c.u.ts.tm = cpu_to_be64(delta);
 
        err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
index 97cda50..cab3d17 100644 (file)
@@ -1307,8 +1307,9 @@ static inline void *write_tso_wr(struct adapter *adap, struct sk_buff *skb,
 int t4_sge_eth_txq_egress_update(struct adapter *adap, struct sge_eth_txq *eq,
                                 int maxreclaim)
 {
+       unsigned int reclaimed, hw_cidx;
        struct sge_txq *q = &eq->q;
-       unsigned int reclaimed;
+       int hw_in_use;
 
        if (!q->in_use || !__netif_tx_trylock(eq->txq))
                return 0;
@@ -1316,12 +1317,17 @@ int t4_sge_eth_txq_egress_update(struct adapter *adap, struct sge_eth_txq *eq,
        /* Reclaim pending completed TX Descriptors. */
        reclaimed = reclaim_completed_tx(adap, &eq->q, maxreclaim, true);
 
+       hw_cidx = ntohs(READ_ONCE(q->stat->cidx));
+       hw_in_use = q->pidx - hw_cidx;
+       if (hw_in_use < 0)
+               hw_in_use += q->size;
+
        /* If the TX Queue is currently stopped and there's now more than half
         * the queue available, restart it.  Otherwise bail out since the rest
         * of what we want do here is with the possibility of shipping any
         * currently buffered Coalesced TX Work Request.
         */
-       if (netif_tx_queue_stopped(eq->txq) && txq_avail(q) > (q->size / 2)) {
+       if (netif_tx_queue_stopped(eq->txq) && hw_in_use < (q->size / 2)) {
                netif_tx_wake_queue(eq->txq);
                eq->q.restarts++;
        }
@@ -1486,16 +1492,7 @@ static netdev_tx_t cxgb4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                 * has opened up.
                 */
                eth_txq_stop(q);
-
-               /* If we're using the SGE Doorbell Queue Timer facility, we
-                * don't need to ask the Firmware to send us Egress Queue CIDX
-                * Updates: the Hardware will do this automatically.  And
-                * since we send the Ingress Queue CIDX Updates to the
-                * corresponding Ethernet Response Queue, we'll get them very
-                * quickly.
-                */
-               if (!q->dbqt)
-                       wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
+               wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
        }
 
        wr = (void *)&q->q.desc[q->q.pidx];
@@ -1805,16 +1802,7 @@ static netdev_tx_t cxgb4_vf_eth_xmit(struct sk_buff *skb,
                 * has opened up.
                 */
                eth_txq_stop(txq);
-
-               /* If we're using the SGE Doorbell Queue Timer facility, we
-                * don't need to ask the Firmware to send us Egress Queue CIDX
-                * Updates: the Hardware will do this automatically.  And
-                * since we send the Ingress Queue CIDX Updates to the
-                * corresponding Ethernet Response Queue, we'll get them very
-                * quickly.
-                */
-               if (!txq->dbqt)
-                       wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
+               wr_mid |= FW_WR_EQUEQ_F | FW_WR_EQUIQ_F;
        }
 
        /* Start filling in our Work Request.  Note that we do _not_ handle
@@ -3370,26 +3358,6 @@ static void t4_tx_completion_handler(struct sge_rspq *rspq,
        }
 
        txq = &s->ethtxq[pi->first_qset + rspq->idx];
-
-       /* We've got the Hardware Consumer Index Update in the Egress Update
-        * message.  If we're using the SGE Doorbell Queue Timer mechanism,
-        * these Egress Update messages will be our sole CIDX Updates we get
-        * since we don't want to chew up PCIe bandwidth for both Ingress
-        * Messages and Status Page writes.  However, The code which manages
-        * reclaiming successfully DMA'ed TX Work Requests uses the CIDX value
-        * stored in the Status Page at the end of the TX Queue.  It's easiest
-        * to simply copy the CIDX Update value from the Egress Update message
-        * to the Status Page.  Also note that no Endian issues need to be
-        * considered here since both are Big Endian and we're just copying
-        * bytes consistently ...
-        */
-       if (txq->dbqt) {
-               struct cpl_sge_egr_update *egr;
-
-               egr = (struct cpl_sge_egr_update *)rsp;
-               WRITE_ONCE(txq->q.stat->cidx, egr->cidx);
-       }
-
        t4_sge_eth_txq_egress_update(adapter, txq, -1);
 }
 
index fd93d54..ca74a68 100644 (file)
@@ -1,4 +1,5 @@
 /* Copyright 2008 - 2016 Freescale Semiconductor Inc.
+ * Copyright 2020 NXP
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -123,7 +124,22 @@ MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
 #define FSL_QMAN_MAX_OAL       127
 
 /* Default alignment for start of data in an Rx FD */
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+/* aligning data start to 64 avoids DMA transaction splits, unless the buffer
+ * is crossing a 4k page boundary
+ */
+#define DPAA_FD_DATA_ALIGNMENT  (fman_has_errata_a050385() ? 64 : 16)
+/* aligning to 256 avoids DMA transaction splits caused by 4k page boundary
+ * crossings; also, all SG fragments except the last must have a size multiple
+ * of 256 to avoid DMA transaction splits
+ */
+#define DPAA_A050385_ALIGN 256
+#define DPAA_FD_RX_DATA_ALIGNMENT (fman_has_errata_a050385() ? \
+                                  DPAA_A050385_ALIGN : 16)
+#else
 #define DPAA_FD_DATA_ALIGNMENT  16
+#define DPAA_FD_RX_DATA_ALIGNMENT DPAA_FD_DATA_ALIGNMENT
+#endif
 
 /* The DPAA requires 256 bytes reserved and mapped for the SGT */
 #define DPAA_SGT_SIZE 256
@@ -158,8 +174,13 @@ MODULE_PARM_DESC(tx_timeout, "The Tx timeout in ms");
 #define DPAA_PARSE_RESULTS_SIZE sizeof(struct fman_prs_result)
 #define DPAA_TIME_STAMP_SIZE 8
 #define DPAA_HASH_RESULTS_SIZE 8
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+#define DPAA_RX_PRIV_DATA_SIZE (DPAA_A050385_ALIGN - (DPAA_PARSE_RESULTS_SIZE\
+        + DPAA_TIME_STAMP_SIZE + DPAA_HASH_RESULTS_SIZE))
+#else
 #define DPAA_RX_PRIV_DATA_SIZE (u16)(DPAA_TX_PRIV_DATA_SIZE + \
                                        dpaa_rx_extra_headroom)
+#endif
 
 #define DPAA_ETH_PCD_RXQ_NUM   128
 
@@ -180,7 +201,12 @@ static struct dpaa_bp *dpaa_bp_array[BM_MAX_NUM_OF_POOLS];
 
 #define DPAA_BP_RAW_SIZE 4096
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+#define dpaa_bp_size(raw_size) (SKB_WITH_OVERHEAD(raw_size) & \
+                               ~(DPAA_A050385_ALIGN - 1))
+#else
 #define dpaa_bp_size(raw_size) SKB_WITH_OVERHEAD(raw_size)
+#endif
 
 static int dpaa_max_frm;
 
@@ -1192,7 +1218,7 @@ static int dpaa_eth_init_rx_port(struct fman_port *port, struct dpaa_bp *bp,
        buf_prefix_content.pass_prs_result = true;
        buf_prefix_content.pass_hash_result = true;
        buf_prefix_content.pass_time_stamp = true;
-       buf_prefix_content.data_align = DPAA_FD_DATA_ALIGNMENT;
+       buf_prefix_content.data_align = DPAA_FD_RX_DATA_ALIGNMENT;
 
        rx_p = &params.specific_params.rx_params;
        rx_p->err_fqid = errq->fqid;
@@ -1662,6 +1688,8 @@ static u8 rx_csum_offload(const struct dpaa_priv *priv, const struct qm_fd *fd)
        return CHECKSUM_NONE;
 }
 
+#define PTR_IS_ALIGNED(x, a) (IS_ALIGNED((unsigned long)(x), (a)))
+
 /* Build a linear skb around the received buffer.
  * We are guaranteed there is enough room at the end of the data buffer to
  * accommodate the shared info area of the skb.
@@ -1733,8 +1761,7 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv,
 
                sg_addr = qm_sg_addr(&sgt[i]);
                sg_vaddr = phys_to_virt(sg_addr);
-               WARN_ON(!IS_ALIGNED((unsigned long)sg_vaddr,
-                                   SMP_CACHE_BYTES));
+               WARN_ON(!PTR_IS_ALIGNED(sg_vaddr, SMP_CACHE_BYTES));
 
                dma_unmap_page(priv->rx_dma_dev, sg_addr,
                               DPAA_BP_RAW_SIZE, DMA_FROM_DEVICE);
@@ -2022,6 +2049,75 @@ static inline int dpaa_xmit(struct dpaa_priv *priv,
        return 0;
 }
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+int dpaa_a050385_wa(struct net_device *net_dev, struct sk_buff **s)
+{
+       struct dpaa_priv *priv = netdev_priv(net_dev);
+       struct sk_buff *new_skb, *skb = *s;
+       unsigned char *start, i;
+
+       /* check linear buffer alignment */
+       if (!PTR_IS_ALIGNED(skb->data, DPAA_A050385_ALIGN))
+               goto workaround;
+
+       /* linear buffers just need to have an aligned start */
+       if (!skb_is_nonlinear(skb))
+               return 0;
+
+       /* linear data size for nonlinear skbs needs to be aligned */
+       if (!IS_ALIGNED(skb_headlen(skb), DPAA_A050385_ALIGN))
+               goto workaround;
+
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+               /* all fragments need to have aligned start addresses */
+               if (!IS_ALIGNED(skb_frag_off(frag), DPAA_A050385_ALIGN))
+                       goto workaround;
+
+               /* all but last fragment need to have aligned sizes */
+               if (!IS_ALIGNED(skb_frag_size(frag), DPAA_A050385_ALIGN) &&
+                   (i < skb_shinfo(skb)->nr_frags - 1))
+                       goto workaround;
+       }
+
+       return 0;
+
+workaround:
+       /* copy all the skb content into a new linear buffer */
+       new_skb = netdev_alloc_skb(net_dev, skb->len + DPAA_A050385_ALIGN - 1 +
+                                               priv->tx_headroom);
+       if (!new_skb)
+               return -ENOMEM;
+
+       /* NET_SKB_PAD bytes already reserved, adding up to tx_headroom */
+       skb_reserve(new_skb, priv->tx_headroom - NET_SKB_PAD);
+
+       /* Workaround for DPAA_A050385 requires data start to be aligned */
+       start = PTR_ALIGN(new_skb->data, DPAA_A050385_ALIGN);
+       if (start - new_skb->data != 0)
+               skb_reserve(new_skb, start - new_skb->data);
+
+       skb_put(new_skb, skb->len);
+       skb_copy_bits(skb, 0, new_skb->data, skb->len);
+       skb_copy_header(new_skb, skb);
+       new_skb->dev = skb->dev;
+
+       /* We move the headroom when we align it so we have to reset the
+        * network and transport header offsets relative to the new data
+        * pointer. The checksum offload relies on these offsets.
+        */
+       skb_set_network_header(new_skb, skb_network_offset(skb));
+       skb_set_transport_header(new_skb, skb_transport_offset(skb));
+
+       /* TODO: does timestamping need the result in the old skb? */
+       dev_kfree_skb(skb);
+       *s = new_skb;
+
+       return 0;
+}
+#endif
+
 static netdev_tx_t
 dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
 {
@@ -2068,6 +2164,14 @@ dpaa_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
                nonlinear = skb_is_nonlinear(skb);
        }
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+       if (unlikely(fman_has_errata_a050385())) {
+               if (dpaa_a050385_wa(net_dev, &skb))
+                       goto enomem;
+               nonlinear = skb_is_nonlinear(skb);
+       }
+#endif
+
        if (nonlinear) {
                /* Just create a S/G fd based on the skb */
                err = skb_to_sg_fd(priv, skb, &fd);
@@ -2741,9 +2845,7 @@ static inline u16 dpaa_get_headroom(struct dpaa_buffer_layout *bl)
        headroom = (u16)(bl->priv_data_size + DPAA_PARSE_RESULTS_SIZE +
                DPAA_TIME_STAMP_SIZE + DPAA_HASH_RESULTS_SIZE);
 
-       return DPAA_FD_DATA_ALIGNMENT ? ALIGN(headroom,
-                                             DPAA_FD_DATA_ALIGNMENT) :
-                                       headroom;
+       return ALIGN(headroom, DPAA_FD_DATA_ALIGNMENT);
 }
 
 static int dpaa_eth_probe(struct platform_device *pdev)
index 4432a59..23c5fef 100644 (file)
@@ -2529,15 +2529,15 @@ fec_enet_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *ec)
                return -EINVAL;
        }
 
-       cycle = fec_enet_us_to_itr_clock(ndev, fep->rx_time_itr);
+       cycle = fec_enet_us_to_itr_clock(ndev, ec->rx_coalesce_usecs);
        if (cycle > 0xFFFF) {
                dev_err(dev, "Rx coalesced usec exceed hardware limitation\n");
                return -EINVAL;
        }
 
-       cycle = fec_enet_us_to_itr_clock(ndev, fep->tx_time_itr);
+       cycle = fec_enet_us_to_itr_clock(ndev, ec->tx_coalesce_usecs);
        if (cycle > 0xFFFF) {
-               dev_err(dev, "Rx coalesced usec exceed hardware limitation\n");
+               dev_err(dev, "Tx coalesced usec exceed hardware limitation\n");
                return -EINVAL;
        }
 
index 0139cb9..3415018 100644 (file)
@@ -8,3 +8,31 @@ config FSL_FMAN
        help
                Freescale Data-Path Acceleration Architecture Frame Manager
                (FMan) support
+
+config DPAA_ERRATUM_A050385
+       bool
+       depends on ARM64 && FSL_DPAA
+       default y
+       help
+               DPAA FMan erratum A050385 software workaround implementation:
+               align buffers, data start, SG fragment length to avoid FMan DMA
+               splits.
+               FMAN DMA read or writes under heavy traffic load may cause FMAN
+               internal resource leak thus stopping further packet processing.
+               The FMAN internal queue can overflow when FMAN splits single
+               read or write transactions into multiple smaller transactions
+               such that more than 17 AXI transactions are in flight from FMAN
+               to interconnect. When the FMAN internal queue overflows, it can
+               stall further packet processing. The issue can occur with any
+               one of the following three conditions:
+               1. FMAN AXI transaction crosses 4K address boundary (Errata
+               A010022)
+               2. FMAN DMA address for an AXI transaction is not 16 byte
+               aligned, i.e. the last 4 bits of an address are non-zero
+               3. Scatter Gather (SG) frames have more than one SG buffer in
+               the SG list and any one of the buffers, except the last
+               buffer in the SG list has data size that is not a multiple
+               of 16 bytes, i.e., other than 16, 32, 48, 64, etc.
+               With any one of the above three conditions present, there is
+               likelihood of stalled FMAN packet processing, especially under
+               stress with multiple ports injecting line-rate traffic.
index 934111d..f151d6e 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2008-2015 Freescale Semiconductor Inc.
+ * Copyright 2020 NXP
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -566,6 +567,10 @@ struct fman_cfg {
        u32 qmi_def_tnums_thresh;
 };
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+static bool fman_has_err_a050385;
+#endif
+
 static irqreturn_t fman_exceptions(struct fman *fman,
                                   enum fman_exceptions exception)
 {
@@ -2518,6 +2523,14 @@ struct fman *fman_bind(struct device *fm_dev)
 }
 EXPORT_SYMBOL(fman_bind);
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+bool fman_has_errata_a050385(void)
+{
+       return fman_has_err_a050385;
+}
+EXPORT_SYMBOL(fman_has_errata_a050385);
+#endif
+
 static irqreturn_t fman_err_irq(int irq, void *handle)
 {
        struct fman *fman = (struct fman *)handle;
@@ -2845,6 +2858,11 @@ static struct fman *read_dts_node(struct platform_device *of_dev)
                goto fman_free;
        }
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+       fman_has_err_a050385 =
+               of_property_read_bool(fm_node, "fsl,erratum-a050385");
+#endif
+
        return fman;
 
 fman_node_put:
index 935c317..f2ede13 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2008-2015 Freescale Semiconductor Inc.
+ * Copyright 2020 NXP
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -398,6 +399,10 @@ u16 fman_get_max_frm(void);
 
 int fman_get_rx_extra_headroom(void);
 
+#ifdef CONFIG_DPAA_ERRATUM_A050385
+bool fman_has_errata_a050385(void);
+#endif
+
 struct fman *fman_bind(struct device *dev);
 
 #endif /* __FM_H */
index e190187..0d2b4ab 100644 (file)
@@ -782,7 +782,7 @@ int memac_adjust_link(struct fman_mac *memac, u16 speed)
        /* Set full duplex */
        tmp &= ~IF_MODE_HD;
 
-       if (memac->phy_if == PHY_INTERFACE_MODE_RGMII) {
+       if (phy_interface_mode_is_rgmii(memac->phy_if)) {
                /* Configure RGMII in manual mode */
                tmp &= ~IF_MODE_RGMII_AUTO;
                tmp &= ~IF_MODE_RGMII_SP_MASK;
index 1b03139..d87158a 100644 (file)
@@ -46,6 +46,7 @@ enum HCLGE_MBX_OPCODE {
        HCLGE_MBX_PUSH_VLAN_INFO,       /* (PF -> VF) push port base vlan */
        HCLGE_MBX_GET_MEDIA_TYPE,       /* (VF -> PF) get media type */
        HCLGE_MBX_PUSH_PROMISC_INFO,    /* (PF -> VF) push vf promisc info */
+       HCLGE_MBX_VF_UNINIT,            /* (VF -> PF) vf is unintializing */
 
        HCLGE_MBX_GET_VF_FLR_STATUS = 200, /* (M7 -> PF) get vf flr status */
        HCLGE_MBX_PUSH_LINK_STATUS,     /* (M7 -> PF) get port link status */
index acb796c..a7f40aa 100644 (file)
@@ -1711,7 +1711,7 @@ static int hns3_setup_tc(struct net_device *netdev, void *type_data)
        netif_dbg(h, drv, netdev, "setup tc: num_tc=%u\n", tc);
 
        return (kinfo->dcb_ops && kinfo->dcb_ops->setup_tc) ?
-               kinfo->dcb_ops->setup_tc(h, tc, prio_tc) : -EOPNOTSUPP;
+               kinfo->dcb_ops->setup_tc(h, tc ? tc : 1, prio_tc) : -EOPNOTSUPP;
 }
 
 static int hns3_nic_setup_tc(struct net_device *dev, enum tc_setup_type type,
index 492bc94..d3b0cd7 100644 (file)
@@ -2446,10 +2446,12 @@ static int hclge_cfg_mac_speed_dup_hw(struct hclge_dev *hdev, int speed,
 
 int hclge_cfg_mac_speed_dup(struct hclge_dev *hdev, int speed, u8 duplex)
 {
+       struct hclge_mac *mac = &hdev->hw.mac;
        int ret;
 
        duplex = hclge_check_speed_dup(duplex, speed);
-       if (hdev->hw.mac.speed == speed && hdev->hw.mac.duplex == duplex)
+       if (!mac->support_autoneg && mac->speed == speed &&
+           mac->duplex == duplex)
                return 0;
 
        ret = hclge_cfg_mac_speed_dup_hw(hdev, speed, duplex);
@@ -7743,16 +7745,27 @@ static int hclge_set_vlan_filter_ctrl(struct hclge_dev *hdev, u8 vlan_type,
        struct hclge_desc desc;
        int ret;
 
-       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_FILTER_CTRL, false);
-
+       /* read current vlan filter parameter */
+       hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_VLAN_FILTER_CTRL, true);
        req = (struct hclge_vlan_filter_ctrl_cmd *)desc.data;
        req->vlan_type = vlan_type;
-       req->vlan_fe = filter_en ? fe_type : 0;
        req->vf_id = vf_id;
 
        ret = hclge_cmd_send(&hdev->hw, &desc, 1);
+       if (ret) {
+               dev_err(&hdev->pdev->dev,
+                       "failed to get vlan filter config, ret = %d.\n", ret);
+               return ret;
+       }
+
+       /* modify and write new config parameter */
+       hclge_cmd_reuse_desc(&desc, false);
+       req->vlan_fe = filter_en ?
+                       (req->vlan_fe | fe_type) : (req->vlan_fe & ~fe_type);
+
+       ret = hclge_cmd_send(&hdev->hw, &desc, 1);
        if (ret)
-               dev_err(&hdev->pdev->dev, "set vlan filter fail, ret =%d.\n",
+               dev_err(&hdev->pdev->dev, "failed to set vlan filter, ret = %d.\n",
                        ret);
 
        return ret;
@@ -8270,6 +8283,7 @@ void hclge_rm_vport_all_vlan_table(struct hclge_vport *vport, bool is_del_list)
                        kfree(vlan);
                }
        }
+       clear_bit(vport->vport_id, hdev->vf_vlan_full);
 }
 
 void hclge_uninit_vport_vlan_table(struct hclge_dev *hdev)
@@ -8486,6 +8500,28 @@ static int hclge_set_vf_vlan_filter(struct hnae3_handle *handle, int vfid,
        }
 }
 
+static void hclge_clear_vf_vlan(struct hclge_dev *hdev)
+{
+       struct hclge_vlan_info *vlan_info;
+       struct hclge_vport *vport;
+       int ret;
+       int vf;
+
+       /* clear port base vlan for all vf */
+       for (vf = HCLGE_VF_VPORT_START_NUM; vf < hdev->num_alloc_vport; vf++) {
+               vport = &hdev->vport[vf];
+               vlan_info = &vport->port_base_vlan_cfg.vlan_info;
+
+               ret = hclge_set_vlan_filter_hw(hdev, htons(ETH_P_8021Q),
+                                              vport->vport_id,
+                                              vlan_info->vlan_tag, true);
+               if (ret)
+                       dev_err(&hdev->pdev->dev,
+                               "failed to clear vf vlan for vf%d, ret = %d\n",
+                               vf - HCLGE_VF_VPORT_START_NUM, ret);
+       }
+}
+
 int hclge_set_vlan_filter(struct hnae3_handle *handle, __be16 proto,
                          u16 vlan_id, bool is_kill)
 {
@@ -9895,6 +9931,7 @@ static void hclge_uninit_ae_dev(struct hnae3_ae_dev *ae_dev)
        struct hclge_mac *mac = &hdev->hw.mac;
 
        hclge_reset_vf_rate(hdev);
+       hclge_clear_vf_vlan(hdev);
        hclge_misc_affinity_teardown(hdev);
        hclge_state_uninit(hdev);
 
index a3c0822..3d850f6 100644 (file)
@@ -799,6 +799,7 @@ void hclge_mbx_handler(struct hclge_dev *hdev)
                        hclge_get_link_mode(vport, req);
                        break;
                case HCLGE_MBX_GET_VF_FLR_STATUS:
+               case HCLGE_MBX_VF_UNINIT:
                        hclge_rm_vport_all_mac_table(vport, true,
                                                     HCLGE_MAC_ADDR_UC);
                        hclge_rm_vport_all_mac_table(vport, true,
index d659720..0510d85 100644 (file)
@@ -2803,6 +2803,9 @@ static void hclgevf_uninit_hdev(struct hclgevf_dev *hdev)
 {
        hclgevf_state_uninit(hdev);
 
+       hclgevf_send_mbx_msg(hdev, HCLGE_MBX_VF_UNINIT, 0, NULL, 0,
+                            false, NULL, 0);
+
        if (test_bit(HCLGEVF_STATE_IRQ_INITED, &hdev->state)) {
                hclgevf_misc_irq_uninit(hdev);
                hclgevf_uninit_msi(hdev);
index eb53c15..5f2d57d 100644 (file)
@@ -389,7 +389,8 @@ static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq,
 
        spin_unlock_bh(&cmdq->cmdq_lock);
 
-       if (!wait_for_completion_timeout(&done, CMDQ_TIMEOUT)) {
+       if (!wait_for_completion_timeout(&done,
+                                        msecs_to_jiffies(CMDQ_TIMEOUT))) {
                spin_lock_bh(&cmdq->cmdq_lock);
 
                if (cmdq->errcode[curr_prod_idx] == &errcode)
@@ -623,6 +624,8 @@ static int cmdq_cmd_ceq_handler(struct hinic_cmdq *cmdq, u16 ci,
        if (!CMDQ_WQE_COMPLETED(be32_to_cpu(ctrl->ctrl_info)))
                return -EBUSY;
 
+       dma_rmb();
+
        errcode = CMDQ_WQE_ERRCODE_GET(be32_to_cpu(status->status_info), VAL);
 
        cmdq_sync_cmd_handler(cmdq, ci, errcode);
index 6f2cf56..c7c75b7 100644 (file)
@@ -297,6 +297,7 @@ static int set_hw_ioctxt(struct hinic_hwdev *hwdev, unsigned int rq_depth,
        }
 
        hw_ioctxt.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
+       hw_ioctxt.ppf_idx = HINIC_HWIF_PPF_IDX(hwif);
 
        hw_ioctxt.set_cmdq_depth = HW_IOCTXT_SET_CMDQ_DEPTH_DEFAULT;
        hw_ioctxt.cmdq_depth = 0;
@@ -359,50 +360,6 @@ static int wait_for_db_state(struct hinic_hwdev *hwdev)
        return -EFAULT;
 }
 
-static int wait_for_io_stopped(struct hinic_hwdev *hwdev)
-{
-       struct hinic_cmd_io_status cmd_io_status;
-       struct hinic_hwif *hwif = hwdev->hwif;
-       struct pci_dev *pdev = hwif->pdev;
-       struct hinic_pfhwdev *pfhwdev;
-       unsigned long end;
-       u16 out_size;
-       int err;
-
-       if (!HINIC_IS_PF(hwif) && !HINIC_IS_PPF(hwif)) {
-               dev_err(&pdev->dev, "Unsupported PCI Function type\n");
-               return -EINVAL;
-       }
-
-       pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev);
-
-       cmd_io_status.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
-
-       end = jiffies + msecs_to_jiffies(IO_STATUS_TIMEOUT);
-       do {
-               err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM,
-                                       HINIC_COMM_CMD_IO_STATUS_GET,
-                                       &cmd_io_status, sizeof(cmd_io_status),
-                                       &cmd_io_status, &out_size,
-                                       HINIC_MGMT_MSG_SYNC);
-               if ((err) || (out_size != sizeof(cmd_io_status))) {
-                       dev_err(&pdev->dev, "Failed to get IO status, ret = %d\n",
-                               err);
-                       return err;
-               }
-
-               if (cmd_io_status.status == IO_STOPPED) {
-                       dev_info(&pdev->dev, "IO stopped\n");
-                       return 0;
-               }
-
-               msleep(20);
-       } while (time_before(jiffies, end));
-
-       dev_err(&pdev->dev, "Wait for IO stopped - Timeout\n");
-       return -ETIMEDOUT;
-}
-
 /**
  * clear_io_resource - set the IO resources as not active in the NIC
  * @hwdev: the NIC HW device
@@ -422,11 +379,8 @@ static int clear_io_resources(struct hinic_hwdev *hwdev)
                return -EINVAL;
        }
 
-       err = wait_for_io_stopped(hwdev);
-       if (err) {
-               dev_err(&pdev->dev, "IO has not stopped yet\n");
-               return err;
-       }
+       /* sleep 100ms to wait for firmware stopping I/O */
+       msleep(100);
 
        cmd_clear_io_res.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
 
index b069045..66fd234 100644 (file)
@@ -151,8 +151,8 @@ struct hinic_cmd_hw_ioctxt {
 
        u8      lro_en;
        u8      rsvd3;
+       u8      ppf_idx;
        u8      rsvd4;
-       u8      rsvd5;
 
        u16     rq_depth;
        u16     rx_buf_sz_idx;
index 79243b6..c0b6bcb 100644 (file)
@@ -188,7 +188,7 @@ static u8 eq_cons_idx_checksum_set(u32 val)
  * eq_update_ci - update the HW cons idx of event queue
  * @eq: the event queue to update the cons idx for
  **/
-static void eq_update_ci(struct hinic_eq *eq)
+static void eq_update_ci(struct hinic_eq *eq, u32 arm_state)
 {
        u32 val, addr = EQ_CONS_IDX_REG_ADDR(eq);
 
@@ -202,7 +202,7 @@ static void eq_update_ci(struct hinic_eq *eq)
 
        val |= HINIC_EQ_CI_SET(eq->cons_idx, IDX)    |
               HINIC_EQ_CI_SET(eq->wrapped, WRAPPED) |
-              HINIC_EQ_CI_SET(EQ_ARMED, INT_ARMED);
+              HINIC_EQ_CI_SET(arm_state, INT_ARMED);
 
        val |= HINIC_EQ_CI_SET(eq_cons_idx_checksum_set(val), XOR_CHKSUM);
 
@@ -235,6 +235,8 @@ static void aeq_irq_handler(struct hinic_eq *eq)
                if (HINIC_EQ_ELEM_DESC_GET(aeqe_desc, WRAPPED) == eq->wrapped)
                        break;
 
+               dma_rmb();
+
                event = HINIC_EQ_ELEM_DESC_GET(aeqe_desc, TYPE);
                if (event >= HINIC_MAX_AEQ_EVENTS) {
                        dev_err(&pdev->dev, "Unknown AEQ Event %d\n", event);
@@ -347,7 +349,7 @@ static void eq_irq_handler(void *data)
        else if (eq->type == HINIC_CEQ)
                ceq_irq_handler(eq);
 
-       eq_update_ci(eq);
+       eq_update_ci(eq, EQ_ARMED);
 }
 
 /**
@@ -702,7 +704,7 @@ static int init_eq(struct hinic_eq *eq, struct hinic_hwif *hwif,
        }
 
        set_eq_ctrls(eq);
-       eq_update_ci(eq);
+       eq_update_ci(eq, EQ_ARMED);
 
        err = alloc_eq_pages(eq);
        if (err) {
@@ -752,18 +754,28 @@ err_req_irq:
  **/
 static void remove_eq(struct hinic_eq *eq)
 {
-       struct msix_entry *entry = &eq->msix_entry;
-
-       free_irq(entry->vector, eq);
+       hinic_set_msix_state(eq->hwif, eq->msix_entry.entry,
+                            HINIC_MSIX_DISABLE);
+       free_irq(eq->msix_entry.vector, eq);
 
        if (eq->type == HINIC_AEQ) {
                struct hinic_eq_work *aeq_work = &eq->aeq_work;
 
                cancel_work_sync(&aeq_work->work);
+               /* clear aeq_len to avoid hw access host memory */
+               hinic_hwif_write_reg(eq->hwif,
+                                    HINIC_CSR_AEQ_CTRL_1_ADDR(eq->q_id), 0);
        } else if (eq->type == HINIC_CEQ) {
                tasklet_kill(&eq->ceq_tasklet);
+               /* clear ceq_len to avoid hw access host memory */
+               hinic_hwif_write_reg(eq->hwif,
+                                    HINIC_CSR_CEQ_CTRL_1_ADDR(eq->q_id), 0);
        }
 
+       /* update cons_idx to avoid invalid interrupt */
+       eq->cons_idx = hinic_hwif_read_reg(eq->hwif, EQ_PROD_IDX_REG_ADDR(eq));
+       eq_update_ci(eq, EQ_NOT_ARMED);
+
        free_eq_pages(eq);
 }
 
index 5177945..c7bb9ce 100644 (file)
 #define HINIC_HWIF_FUNC_IDX(hwif)       ((hwif)->attr.func_idx)
 #define HINIC_HWIF_PCI_INTF(hwif)       ((hwif)->attr.pci_intf_idx)
 #define HINIC_HWIF_PF_IDX(hwif)         ((hwif)->attr.pf_idx)
+#define HINIC_HWIF_PPF_IDX(hwif)        ((hwif)->attr.ppf_idx)
 
 #define HINIC_FUNC_TYPE(hwif)           ((hwif)->attr.func_type)
 #define HINIC_IS_PF(hwif)               (HINIC_FUNC_TYPE(hwif) == HINIC_PF)
index c1a6be6..8995e32 100644 (file)
@@ -43,7 +43,7 @@
 
 #define MSG_NOT_RESP                    0xFFFF
 
-#define MGMT_MSG_TIMEOUT                1000
+#define MGMT_MSG_TIMEOUT                5000
 
 #define mgmt_to_pfhwdev(pf_mgmt)        \
                container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt)
@@ -267,7 +267,8 @@ static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt,
                goto unlock_sync_msg;
        }
 
-       if (!wait_for_completion_timeout(recv_done, MGMT_MSG_TIMEOUT)) {
+       if (!wait_for_completion_timeout(recv_done,
+                                        msecs_to_jiffies(MGMT_MSG_TIMEOUT))) {
                dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id);
                err = -ETIMEDOUT;
                goto unlock_sync_msg;
index f4a339b..79091e1 100644 (file)
@@ -94,6 +94,7 @@ struct hinic_rq {
 
        struct hinic_wq         *wq;
 
+       struct cpumask          affinity_mask;
        u32                     irq;
        u16                     msix_entry;
 
index 02a14f5..1356097 100644 (file)
@@ -356,7 +356,8 @@ static void hinic_enable_rss(struct hinic_dev *nic_dev)
        if (!num_cpus)
                num_cpus = num_online_cpus();
 
-       nic_dev->num_qps = min_t(u16, nic_dev->max_qps, num_cpus);
+       nic_dev->num_qps = hinic_hwdev_num_qps(hwdev);
+       nic_dev->num_qps = min_t(u16, nic_dev->num_qps, num_cpus);
 
        nic_dev->rss_limit = nic_dev->num_qps;
        nic_dev->num_rss = nic_dev->num_qps;
index 56ea6d6..815649e 100644 (file)
@@ -350,6 +350,9 @@ static int rxq_recv(struct hinic_rxq *rxq, int budget)
                if (!rq_wqe)
                        break;
 
+               /* make sure we read rx_done before packet length */
+               dma_rmb();
+
                cqe = rq->cqe[ci];
                status =  be32_to_cpu(cqe->status);
                hinic_rq_get_sge(rxq->rq, rq_wqe, ci, &sge);
@@ -475,7 +478,6 @@ static int rx_request_irq(struct hinic_rxq *rxq)
        struct hinic_hwdev *hwdev = nic_dev->hwdev;
        struct hinic_rq *rq = rxq->rq;
        struct hinic_qp *qp;
-       struct cpumask mask;
        int err;
 
        rx_add_napi(rxq);
@@ -492,8 +494,8 @@ static int rx_request_irq(struct hinic_rxq *rxq)
        }
 
        qp = container_of(rq, struct hinic_qp, rq);
-       cpumask_set_cpu(qp->q_id % num_online_cpus(), &mask);
-       return irq_set_affinity_hint(rq->irq, &mask);
+       cpumask_set_cpu(qp->q_id % num_online_cpus(), &rq->affinity_mask);
+       return irq_set_affinity_hint(rq->irq, &rq->affinity_mask);
 }
 
 static void rx_free_irq(struct hinic_rxq *rxq)
index 0e13d1c..3650164 100644 (file)
@@ -45,7 +45,7 @@
 
 #define HW_CONS_IDX(sq)                 be16_to_cpu(*(u16 *)((sq)->hw_ci_addr))
 
-#define MIN_SKB_LEN                     17
+#define MIN_SKB_LEN                    32
 
 #define        MAX_PAYLOAD_OFFSET              221
 #define TRANSPORT_OFFSET(l4_hdr, skb)  ((u32)((l4_hdr) - (skb)->data))
@@ -622,6 +622,8 @@ static int free_tx_poll(struct napi_struct *napi, int budget)
        do {
                hw_ci = HW_CONS_IDX(sq) & wq->mask;
 
+               dma_rmb();
+
                /* Reading a WQEBB to get real WQE size and consumer index. */
                sq_wqe = hinic_sq_read_wqebb(sq, &skb, &wqe_size, &sw_ci);
                if ((!sq_wqe) ||
index c75239d..4bd3324 100644 (file)
@@ -2142,6 +2142,8 @@ static void __ibmvnic_reset(struct work_struct *work)
 {
        struct ibmvnic_rwi *rwi;
        struct ibmvnic_adapter *adapter;
+       bool saved_state = false;
+       unsigned long flags;
        u32 reset_state;
        int rc = 0;
 
@@ -2153,17 +2155,25 @@ static void __ibmvnic_reset(struct work_struct *work)
                return;
        }
 
-       reset_state = adapter->state;
-
        rwi = get_next_rwi(adapter);
        while (rwi) {
+               spin_lock_irqsave(&adapter->state_lock, flags);
+
                if (adapter->state == VNIC_REMOVING ||
                    adapter->state == VNIC_REMOVED) {
+                       spin_unlock_irqrestore(&adapter->state_lock, flags);
                        kfree(rwi);
                        rc = EBUSY;
                        break;
                }
 
+               if (!saved_state) {
+                       reset_state = adapter->state;
+                       adapter->state = VNIC_RESETTING;
+                       saved_state = true;
+               }
+               spin_unlock_irqrestore(&adapter->state_lock, flags);
+
                if (rwi->reset_reason == VNIC_RESET_CHANGE_PARAM) {
                        /* CHANGE_PARAM requestor holds rtnl_lock */
                        rc = do_change_param_reset(adapter, rwi, reset_state);
@@ -5091,6 +5101,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
                          __ibmvnic_delayed_reset);
        INIT_LIST_HEAD(&adapter->rwi_list);
        spin_lock_init(&adapter->rwi_lock);
+       spin_lock_init(&adapter->state_lock);
        mutex_init(&adapter->fw_lock);
        init_completion(&adapter->init_done);
        init_completion(&adapter->fw_done);
@@ -5163,8 +5174,17 @@ static int ibmvnic_remove(struct vio_dev *dev)
 {
        struct net_device *netdev = dev_get_drvdata(&dev->dev);
        struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+       unsigned long flags;
+
+       spin_lock_irqsave(&adapter->state_lock, flags);
+       if (adapter->state == VNIC_RESETTING) {
+               spin_unlock_irqrestore(&adapter->state_lock, flags);
+               return -EBUSY;
+       }
 
        adapter->state = VNIC_REMOVING;
+       spin_unlock_irqrestore(&adapter->state_lock, flags);
+
        rtnl_lock();
        unregister_netdevice(netdev);
 
index 60eccaf..f8416e1 100644 (file)
@@ -941,7 +941,8 @@ enum vnic_state {VNIC_PROBING = 1,
                 VNIC_CLOSING,
                 VNIC_CLOSED,
                 VNIC_REMOVING,
-                VNIC_REMOVED};
+                VNIC_REMOVED,
+                VNIC_RESETTING};
 
 enum ibmvnic_reset_reason {VNIC_RESET_FAILOVER = 1,
                           VNIC_RESET_MOBILITY,
@@ -1090,4 +1091,7 @@ struct ibmvnic_adapter {
 
        struct ibmvnic_tunables desired;
        struct ibmvnic_tunables fallback;
+
+       /* Used for serializatin of state field */
+       spinlock_t state_lock;
 };
index db4ea58..0f02c7a 100644 (file)
@@ -3280,10 +3280,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
 
                dev_info(&adapter->pdev->dev,
                         "Some CPU C-states have been disabled in order to enable jumbo frames\n");
-               pm_qos_update_request(&adapter->pm_qos_req, lat);
+               cpu_latency_qos_update_request(&adapter->pm_qos_req, lat);
        } else {
-               pm_qos_update_request(&adapter->pm_qos_req,
-                                     PM_QOS_DEFAULT_VALUE);
+               cpu_latency_qos_update_request(&adapter->pm_qos_req,
+                                              PM_QOS_DEFAULT_VALUE);
        }
 
        /* Enable Receives */
@@ -4636,8 +4636,7 @@ int e1000e_open(struct net_device *netdev)
                e1000_update_mng_vlan(adapter);
 
        /* DMA latency requirement to workaround jumbo issue */
-       pm_qos_add_request(&adapter->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-                          PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_add_request(&adapter->pm_qos_req, PM_QOS_DEFAULT_VALUE);
 
        /* before we allocate an interrupt, we must be ready to handle it.
         * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
@@ -4679,7 +4678,7 @@ int e1000e_open(struct net_device *netdev)
        return 0;
 
 err_req_irq:
-       pm_qos_remove_request(&adapter->pm_qos_req);
+       cpu_latency_qos_remove_request(&adapter->pm_qos_req);
        e1000e_release_hw_control(adapter);
        e1000_power_down_phy(adapter);
        e1000e_free_rx_resources(adapter->rx_ring);
@@ -4743,7 +4742,7 @@ int e1000e_close(struct net_device *netdev)
            !test_bit(__E1000_TESTING, &adapter->state))
                e1000e_release_hw_control(adapter);
 
-       pm_qos_remove_request(&adapter->pm_qos_req);
+       cpu_latency_qos_remove_request(&adapter->pm_qos_req);
 
        pm_runtime_put_sync(&pdev->dev);
 
index 0b9e851..d14762d 100644 (file)
@@ -347,7 +347,7 @@ static int orion_mdio_probe(struct platform_device *pdev)
        }
 
 
-       dev->err_interrupt = platform_get_irq(pdev, 0);
+       dev->err_interrupt = platform_get_irq_optional(pdev, 0);
        if (dev->err_interrupt > 0 &&
            resource_size(r) < MVMDIO_ERR_INT_MASK + 4) {
                dev_err(&pdev->dev,
index 98017e7..11babc7 100644 (file)
@@ -3036,11 +3036,10 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
        /* For the case where the last mvneta_poll did not process all
         * RX packets
         */
-       rx_queue = fls(((cause_rx_tx >> 8) & 0xff));
-
        cause_rx_tx |= pp->neta_armada3700 ? pp->cause_rx_tx :
                port->cause_rx_tx;
 
+       rx_queue = fls(((cause_rx_tx >> 8) & 0xff));
        if (rx_queue) {
                rx_queue = rx_queue - 1;
                if (pp->bm_priv)
index 9c48182..9486cae 100644 (file)
@@ -906,59 +906,59 @@ static void mlx4_err_rule(struct mlx4_dev *dev, char *str,
        int len = 0;
 
        mlx4_err(dev, "%s", str);
-       len += snprintf(buf + len, BUF_SIZE - len,
-                       "port = %d prio = 0x%x qp = 0x%x ",
-                       rule->port, rule->priority, rule->qpn);
+       len += scnprintf(buf + len, BUF_SIZE - len,
+                        "port = %d prio = 0x%x qp = 0x%x ",
+                        rule->port, rule->priority, rule->qpn);
 
        list_for_each_entry(cur, &rule->list, list) {
                switch (cur->id) {
                case MLX4_NET_TRANS_RULE_ID_ETH:
-                       len += snprintf(buf + len, BUF_SIZE - len,
-                                       "dmac = %pM ", &cur->eth.dst_mac);
+                       len += scnprintf(buf + len, BUF_SIZE - len,
+                                        "dmac = %pM ", &cur->eth.dst_mac);
                        if (cur->eth.ether_type)
-                               len += snprintf(buf + len, BUF_SIZE - len,
-                                               "ethertype = 0x%x ",
-                                               be16_to_cpu(cur->eth.ether_type));
+                               len += scnprintf(buf + len, BUF_SIZE - len,
+                                                "ethertype = 0x%x ",
+                                                be16_to_cpu(cur->eth.ether_type));
                        if (cur->eth.vlan_id)
-                               len += snprintf(buf + len, BUF_SIZE - len,
-                                               "vlan-id = %d ",
-                                               be16_to_cpu(cur->eth.vlan_id));
+                               len += scnprintf(buf + len, BUF_SIZE - len,
+                                                "vlan-id = %d ",
+                                                be16_to_cpu(cur->eth.vlan_id));
                        break;
 
                case MLX4_NET_TRANS_RULE_ID_IPV4:
                        if (cur->ipv4.src_ip)
-                               len += snprintf(buf + len, BUF_SIZE - len,
-                                               "src-ip = %pI4 ",
-                                               &cur->ipv4.src_ip);
+                               len += scnprintf(buf + len, BUF_SIZE - len,
+                                                "src-ip = %pI4 ",
+                                                &cur->ipv4.src_ip);
                        if (cur->ipv4.dst_ip)
-                               len += snprintf(buf + len, BUF_SIZE - len,
-                                               "dst-ip = %pI4 ",
-                                               &cur->ipv4.dst_ip);
+                               len += scnprintf(buf + len, BUF_SIZE - len,
+                                                "dst-ip = %pI4 ",
+                                                &cur->ipv4.dst_ip);
                        break;
 
                case MLX4_NET_TRANS_RULE_ID_TCP:
                case MLX4_NET_TRANS_RULE_ID_UDP:
                        if (cur->tcp_udp.src_port)
-                               len += snprintf(buf + len, BUF_SIZE - len,
-                                               "src-port = %d ",
-                                               be16_to_cpu(cur->tcp_udp.src_port));
+                               len += scnprintf(buf + len, BUF_SIZE - len,
+                                                "src-port = %d ",
+                                                be16_to_cpu(cur->tcp_udp.src_port));
                        if (cur->tcp_udp.dst_port)
-                               len += snprintf(buf + len, BUF_SIZE - len,
-                                               "dst-port = %d ",
-                                               be16_to_cpu(cur->tcp_udp.dst_port));
+                               len += scnprintf(buf + len, BUF_SIZE - len,
+                                                "dst-port = %d ",
+                                                be16_to_cpu(cur->tcp_udp.dst_port));
                        break;
 
                case MLX4_NET_TRANS_RULE_ID_IB:
-                       len += snprintf(buf + len, BUF_SIZE - len,
-                                       "dst-gid = %pI6\n", cur->ib.dst_gid);
-                       len += snprintf(buf + len, BUF_SIZE - len,
-                                       "dst-gid-mask = %pI6\n",
-                                       cur->ib.dst_gid_msk);
+                       len += scnprintf(buf + len, BUF_SIZE - len,
+                                        "dst-gid = %pI6\n", cur->ib.dst_gid);
+                       len += scnprintf(buf + len, BUF_SIZE - len,
+                                        "dst-gid-mask = %pI6\n",
+                                        cur->ib.dst_gid_msk);
                        break;
 
                case MLX4_NET_TRANS_RULE_ID_VXLAN:
-                       len += snprintf(buf + len, BUF_SIZE - len,
-                                       "VNID = %d ", be32_to_cpu(cur->vxlan.vni));
+                       len += scnprintf(buf + len, BUF_SIZE - len,
+                                        "VNID = %d ", be32_to_cpu(cur->vxlan.vni));
                        break;
                case MLX4_NET_TRANS_RULE_ID_IPV6:
                        break;
@@ -967,7 +967,7 @@ static void mlx4_err_rule(struct mlx4_dev *dev, char *str,
                        break;
                }
        }
-       len += snprintf(buf + len, BUF_SIZE - len, "\n");
+       len += scnprintf(buf + len, BUF_SIZE - len, "\n");
        mlx4_err(dev, "%s", buf);
 
        if (len >= BUF_SIZE)
index 220ef9f..c9606b8 100644 (file)
@@ -371,6 +371,7 @@ enum {
 
 struct mlx5e_sq_wqe_info {
        u8  opcode;
+       u8 num_wqebbs;
 
        /* Auxiliary data for different opcodes. */
        union {
@@ -1059,6 +1060,7 @@ int mlx5e_modify_rq_state(struct mlx5e_rq *rq, int curr_state, int next_state);
 void mlx5e_activate_rq(struct mlx5e_rq *rq);
 void mlx5e_deactivate_rq(struct mlx5e_rq *rq);
 void mlx5e_free_rx_descs(struct mlx5e_rq *rq);
+void mlx5e_free_rx_in_progress_descs(struct mlx5e_rq *rq);
 void mlx5e_activate_icosq(struct mlx5e_icosq *icosq);
 void mlx5e_deactivate_icosq(struct mlx5e_icosq *icosq);
 
index d3693fa..e54f70d 100644 (file)
@@ -10,8 +10,7 @@
 
 static inline bool cqe_syndrome_needs_recover(u8 syndrome)
 {
-       return syndrome == MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR ||
-              syndrome == MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR ||
+       return syndrome == MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR ||
               syndrome == MLX5_CQE_SYNDROME_LOCAL_PROT_ERR ||
               syndrome == MLX5_CQE_SYNDROME_WR_FLUSH_ERR;
 }
index 6c72b59..a01e2de 100644 (file)
@@ -90,7 +90,7 @@ static int mlx5e_rx_reporter_err_icosq_cqe_recover(void *ctx)
                goto out;
 
        mlx5e_reset_icosq_cc_pc(icosq);
-       mlx5e_free_rx_descs(rq);
+       mlx5e_free_rx_in_progress_descs(rq);
        clear_bit(MLX5E_SQ_STATE_RECOVERING, &icosq->state);
        mlx5e_activate_icosq(icosq);
        mlx5e_activate_rq(rq);
index a226277..f07b139 100644 (file)
@@ -181,10 +181,12 @@ mlx5e_tx_dma_unmap(struct device *pdev, struct mlx5e_sq_dma *dma)
 
 static inline void mlx5e_rqwq_reset(struct mlx5e_rq *rq)
 {
-       if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ)
+       if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
                mlx5_wq_ll_reset(&rq->mpwqe.wq);
-       else
+               rq->mpwqe.actual_wq_head = 0;
+       } else {
                mlx5_wq_cyc_reset(&rq->wqe.wq);
+       }
 }
 
 /* SW parser related functions */
index a3efa29..63116be 100644 (file)
@@ -38,8 +38,8 @@ enum {
 
 enum {
        MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_START     = 0,
-       MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING = 1,
-       MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING  = 2,
+       MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_TRACKING  = 1,
+       MLX5E_TLS_PROGRESS_PARAMS_RECORD_TRACKER_STATE_SEARCHING = 2,
 };
 
 struct mlx5e_ktls_offload_context_tx {
index f260dd9..52a5662 100644 (file)
@@ -218,7 +218,7 @@ tx_sync_info_get(struct mlx5e_ktls_offload_context_tx *priv_tx,
         *    this packet was already acknowledged and its record info
         *    was released.
         */
-       ends_before = before(tcp_seq + datalen, tls_record_start_seq(record));
+       ends_before = before(tcp_seq + datalen - 1, tls_record_start_seq(record));
 
        if (unlikely(tls_record_is_start_marker(record))) {
                ret = ends_before ? MLX5E_KTLS_SYNC_SKIP_NO_DATA : MLX5E_KTLS_SYNC_FAIL;
index 9669836..4ef3dc7 100644 (file)
@@ -813,6 +813,29 @@ int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
        return -ETIMEDOUT;
 }
 
+void mlx5e_free_rx_in_progress_descs(struct mlx5e_rq *rq)
+{
+       struct mlx5_wq_ll *wq;
+       u16 head;
+       int i;
+
+       if (rq->wq_type != MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ)
+               return;
+
+       wq = &rq->mpwqe.wq;
+       head = wq->head;
+
+       /* Outstanding UMR WQEs (in progress) start at wq->head */
+       for (i = 0; i < rq->mpwqe.umr_in_progress; i++) {
+               rq->dealloc_wqe(rq, head);
+               head = mlx5_wq_ll_get_wqe_next_ix(wq, head);
+       }
+
+       rq->mpwqe.actual_wq_head = wq->head;
+       rq->mpwqe.umr_in_progress = 0;
+       rq->mpwqe.umr_completed = 0;
+}
+
 void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
 {
        __be16 wqe_ix_be;
@@ -820,14 +843,8 @@ void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
 
        if (rq->wq_type == MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ) {
                struct mlx5_wq_ll *wq = &rq->mpwqe.wq;
-               u16 head = wq->head;
-               int i;
 
-               /* Outstanding UMR WQEs (in progress) start at wq->head */
-               for (i = 0; i < rq->mpwqe.umr_in_progress; i++) {
-                       rq->dealloc_wqe(rq, head);
-                       head = mlx5_wq_ll_get_wqe_next_ix(wq, head);
-               }
+               mlx5e_free_rx_in_progress_descs(rq);
 
                while (!mlx5_wq_ll_is_empty(wq)) {
                        struct mlx5e_rx_wqe_ll *wqe;
@@ -5147,7 +5164,6 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
 
 static void mlx5e_nic_disable(struct mlx5e_priv *priv)
 {
-       struct net_device *netdev = priv->netdev;
        struct mlx5_core_dev *mdev = priv->mdev;
 
 #ifdef CONFIG_MLX5_CORE_EN_DCB
@@ -5168,7 +5184,7 @@ static void mlx5e_nic_disable(struct mlx5e_priv *priv)
                mlx5e_monitor_counter_cleanup(priv);
 
        mlx5e_disable_async_events(priv);
-       mlx5_lag_remove(mdev, netdev);
+       mlx5_lag_remove(mdev);
 }
 
 int mlx5e_update_nic_rx(struct mlx5e_priv *priv)
index 7b48cca..6ed307d 100644 (file)
@@ -1861,7 +1861,6 @@ static void mlx5e_uplink_rep_enable(struct mlx5e_priv *priv)
 
 static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
 {
-       struct net_device *netdev = priv->netdev;
        struct mlx5_core_dev *mdev = priv->mdev;
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
 
@@ -1870,7 +1869,7 @@ static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
 #endif
        mlx5_notifier_unregister(mdev, &priv->events_nb);
        cancel_work_sync(&rpriv->uplink_priv.reoffload_flows_work);
-       mlx5_lag_remove(mdev, netdev);
+       mlx5_lag_remove(mdev);
 }
 
 static MLX5E_DEFINE_STATS_GRP(sw_rep, 0);
index 1c3ab69..312d469 100644 (file)
@@ -477,6 +477,7 @@ static inline void mlx5e_fill_icosq_frag_edge(struct mlx5e_icosq *sq,
        /* fill sq frag edge with nops to avoid wqe wrapping two pages */
        for (; wi < edge_wi; wi++) {
                wi->opcode = MLX5_OPCODE_NOP;
+               wi->num_wqebbs = 1;
                mlx5e_post_nop(wq, sq->sqn, &sq->pc);
        }
 }
@@ -525,6 +526,7 @@ static int mlx5e_alloc_rx_mpwqe(struct mlx5e_rq *rq, u16 ix)
        umr_wqe->uctrl.xlt_offset = cpu_to_be16(xlt_offset);
 
        sq->db.ico_wqe[pi].opcode = MLX5_OPCODE_UMR;
+       sq->db.ico_wqe[pi].num_wqebbs = MLX5E_UMR_WQEBBS;
        sq->db.ico_wqe[pi].umr.rq = rq;
        sq->pc += MLX5E_UMR_WQEBBS;
 
@@ -621,6 +623,7 @@ void mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
 
                        ci = mlx5_wq_cyc_ctr2ix(&sq->wq, sqcc);
                        wi = &sq->db.ico_wqe[ci];
+                       sqcc += wi->num_wqebbs;
 
                        if (last_wqe && unlikely(get_cqe_opcode(cqe) != MLX5_CQE_REQ)) {
                                netdev_WARN_ONCE(cq->channel->netdev,
@@ -631,16 +634,12 @@ void mlx5e_poll_ico_cq(struct mlx5e_cq *cq)
                                break;
                        }
 
-                       if (likely(wi->opcode == MLX5_OPCODE_UMR)) {
-                               sqcc += MLX5E_UMR_WQEBBS;
+                       if (likely(wi->opcode == MLX5_OPCODE_UMR))
                                wi->umr.rq->mpwqe.umr_completed++;
-                       } else if (likely(wi->opcode == MLX5_OPCODE_NOP)) {
-                               sqcc++;
-                       } else {
+                       else if (unlikely(wi->opcode != MLX5_OPCODE_NOP))
                                netdev_WARN_ONCE(cq->channel->netdev,
                                                 "Bad OPCODE in ICOSQ WQE info: 0x%x\n",
                                                 wi->opcode);
-                       }
 
                } while (!last_wqe);
 
index 74091f7..ec5fc52 100644 (file)
@@ -2476,10 +2476,11 @@ static int offload_pedit_fields(struct pedit_headers_action *hdrs,
                        continue;
 
                if (f->field_bsize == 32) {
-                       mask_be32 = *(__be32 *)&mask;
+                       mask_be32 = (__be32)mask;
                        mask = (__force unsigned long)cpu_to_le32(be32_to_cpu(mask_be32));
                } else if (f->field_bsize == 16) {
-                       mask_be16 = *(__be16 *)&mask;
+                       mask_be32 = (__be32)mask;
+                       mask_be16 = *(__be16 *)&mask_be32;
                        mask = (__force unsigned long)cpu_to_le16(be16_to_cpu(mask_be16));
                }
 
index 257a7c9..800d34e 100644 (file)
@@ -78,6 +78,7 @@ void mlx5e_trigger_irq(struct mlx5e_icosq *sq)
        u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
 
        sq->db.ico_wqe[pi].opcode = MLX5_OPCODE_NOP;
+       sq->db.ico_wqe[pi].num_wqebbs = 1;
        nopwqe = mlx5e_post_nop(wq, sq->sqn, &sq->pc);
        mlx5e_notify_hw(wq, sq->pc, sq->uar_map, &nopwqe->ctrl);
 }
index b91eabc..93052b0 100644 (file)
@@ -464,9 +464,6 @@ static int mlx5_lag_netdev_event(struct notifier_block *this,
        struct mlx5_lag *ldev;
        int changed = 0;
 
-       if (!net_eq(dev_net(ndev), &init_net))
-               return NOTIFY_DONE;
-
        if ((event != NETDEV_CHANGEUPPER) && (event != NETDEV_CHANGELOWERSTATE))
                return NOTIFY_DONE;
 
@@ -586,8 +583,7 @@ void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev)
 
        if (!ldev->nb.notifier_call) {
                ldev->nb.notifier_call = mlx5_lag_netdev_event;
-               if (register_netdevice_notifier_dev_net(netdev, &ldev->nb,
-                                                       &ldev->nn)) {
+               if (register_netdevice_notifier_net(&init_net, &ldev->nb)) {
                        ldev->nb.notifier_call = NULL;
                        mlx5_core_err(dev, "Failed to register LAG netdev notifier\n");
                }
@@ -600,7 +596,7 @@ void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev)
 }
 
 /* Must be called with intf_mutex held */
-void mlx5_lag_remove(struct mlx5_core_dev *dev, struct net_device *netdev)
+void mlx5_lag_remove(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev;
        int i;
@@ -619,9 +615,10 @@ void mlx5_lag_remove(struct mlx5_core_dev *dev, struct net_device *netdev)
                        break;
 
        if (i == MLX5_MAX_PORTS) {
-               if (ldev->nb.notifier_call)
-                       unregister_netdevice_notifier_dev_net(netdev, &ldev->nb,
-                                                             &ldev->nn);
+               if (ldev->nb.notifier_call) {
+                       unregister_netdevice_notifier_net(&init_net, &ldev->nb);
+                       ldev->nb.notifier_call = NULL;
+               }
                mlx5_lag_mp_cleanup(ldev);
                cancel_delayed_work_sync(&ldev->bond_work);
                mlx5_lag_dev_free(ldev);
index 316ab09..f1068aa 100644 (file)
@@ -44,7 +44,6 @@ struct mlx5_lag {
        struct workqueue_struct   *wq;
        struct delayed_work       bond_work;
        struct notifier_block     nb;
-       struct netdev_net_notifier      nn;
        struct lag_mp             lag_mp;
 };
 
index fcce9e0..da67b28 100644 (file)
@@ -157,7 +157,7 @@ int mlx5_query_qcam_reg(struct mlx5_core_dev *mdev, u32 *qcam,
                        u8 feature_group, u8 access_reg_group);
 
 void mlx5_lag_add(struct mlx5_core_dev *dev, struct net_device *netdev);
-void mlx5_lag_remove(struct mlx5_core_dev *dev, struct net_device *netdev);
+void mlx5_lag_remove(struct mlx5_core_dev *dev);
 
 int mlx5_irq_table_init(struct mlx5_core_dev *dev);
 void mlx5_irq_table_cleanup(struct mlx5_core_dev *dev);
index 6dec2a5..2d93228 100644 (file)
@@ -933,7 +933,6 @@ static int dr_actions_l2_rewrite(struct mlx5dr_domain *dmn,
 
        action->rewrite.data = (void *)ops;
        action->rewrite.num_of_actions = i;
-       action->rewrite.chunk->byte_size = i * sizeof(*ops);
 
        ret = mlx5dr_send_postsend_action(dmn, action);
        if (ret) {
index c7f10d4..095ec7b 100644 (file)
@@ -558,7 +558,8 @@ int mlx5dr_send_postsend_action(struct mlx5dr_domain *dmn,
        int ret;
 
        send_info.write.addr = (uintptr_t)action->rewrite.data;
-       send_info.write.length = action->rewrite.chunk->byte_size;
+       send_info.write.length = action->rewrite.num_of_actions *
+                                DR_MODIFY_ACTION_SIZE;
        send_info.write.lkey = 0;
        send_info.remote_addr = action->rewrite.chunk->mr_addr;
        send_info.rkey = action->rewrite.chunk->rkey;
index 1faac31..23f879d 100644 (file)
@@ -1071,6 +1071,9 @@ int mlx5_core_modify_hca_vport_context(struct mlx5_core_dev *dev,
                MLX5_SET64(hca_vport_context, ctx, port_guid, req->port_guid);
        if (req->field_select & MLX5_HCA_VPORT_SEL_NODE_GUID)
                MLX5_SET64(hca_vport_context, ctx, node_guid, req->node_guid);
+       MLX5_SET(hca_vport_context, ctx, cap_mask1, req->cap_mask1);
+       MLX5_SET(hca_vport_context, ctx, cap_mask1_field_select,
+                req->cap_mask1_perm);
        err = mlx5_cmd_exec(dev, in, in_sz, out, sizeof(out));
 ex:
        kfree(in);
index 914c33e..e9ded1a 100644 (file)
@@ -1322,36 +1322,64 @@ static void mlxsw_pci_mbox_free(struct mlxsw_pci *mlxsw_pci,
                            mbox->mapaddr);
 }
 
-static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
-                             const struct pci_device_id *id)
+static int mlxsw_pci_sys_ready_wait(struct mlxsw_pci *mlxsw_pci,
+                                   const struct pci_device_id *id,
+                                   u32 *p_sys_status)
 {
        unsigned long end;
-       char mrsr_pl[MLXSW_REG_MRSR_LEN];
-       int err;
+       u32 val;
 
-       mlxsw_reg_mrsr_pack(mrsr_pl);
-       err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl);
-       if (err)
-               return err;
        if (id->device == PCI_DEVICE_ID_MELLANOX_SWITCHX2) {
                msleep(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
                return 0;
        }
 
-       /* We must wait for the HW to become responsive once again. */
+       /* We must wait for the HW to become responsive. */
        msleep(MLXSW_PCI_SW_RESET_WAIT_MSECS);
 
        end = jiffies + msecs_to_jiffies(MLXSW_PCI_SW_RESET_TIMEOUT_MSECS);
        do {
-               u32 val = mlxsw_pci_read32(mlxsw_pci, FW_READY);
-
+               val = mlxsw_pci_read32(mlxsw_pci, FW_READY);
                if ((val & MLXSW_PCI_FW_READY_MASK) == MLXSW_PCI_FW_READY_MAGIC)
                        return 0;
                cond_resched();
        } while (time_before(jiffies, end));
+
+       *p_sys_status = val & MLXSW_PCI_FW_READY_MASK;
+
        return -EBUSY;
 }
 
+static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci,
+                             const struct pci_device_id *id)
+{
+       struct pci_dev *pdev = mlxsw_pci->pdev;
+       char mrsr_pl[MLXSW_REG_MRSR_LEN];
+       u32 sys_status;
+       int err;
+
+       err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to reach system ready status before reset. Status is 0x%x\n",
+                       sys_status);
+               return err;
+       }
+
+       mlxsw_reg_mrsr_pack(mrsr_pl);
+       err = mlxsw_reg_write(mlxsw_pci->core, MLXSW_REG(mrsr), mrsr_pl);
+       if (err)
+               return err;
+
+       err = mlxsw_pci_sys_ready_wait(mlxsw_pci, id, &sys_status);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to reach system ready status after reset. Status is 0x%x\n",
+                       sys_status);
+               return err;
+       }
+
+       return 0;
+}
+
 static int mlxsw_pci_alloc_irq_vectors(struct mlxsw_pci *mlxsw_pci)
 {
        int err;
index e0d7d2d..43fa8c8 100644 (file)
@@ -28,7 +28,7 @@
 #define MLXSW_PCI_SW_RESET                     0xF0010
 #define MLXSW_PCI_SW_RESET_RST_BIT             BIT(0)
 #define MLXSW_PCI_SW_RESET_TIMEOUT_MSECS       900000
-#define MLXSW_PCI_SW_RESET_WAIT_MSECS          100
+#define MLXSW_PCI_SW_RESET_WAIT_MSECS          200
 #define MLXSW_PCI_FW_READY                     0xA1844
 #define MLXSW_PCI_FW_READY_MASK                        0xFFFF
 #define MLXSW_PCI_FW_READY_MAGIC               0x5E
index dd66851..e05d1d1 100644 (file)
@@ -3572,7 +3572,7 @@ MLXSW_ITEM32(reg, qeec, mase, 0x10, 31, 1);
  * When in bytes mode, value is specified in units of 1000bps.
  * Access: RW
  */
-MLXSW_ITEM32(reg, qeec, max_shaper_rate, 0x10, 0, 28);
+MLXSW_ITEM32(reg, qeec, max_shaper_rate, 0x10, 0, 31);
 
 /* reg_qeec_de
  * DWRR configuration enable. Enables configuration of the dwrr and
index 5427562..336e5ec 100644 (file)
@@ -637,12 +637,12 @@ static int mlxsw_sp_mr_vif_resolve(struct mlxsw_sp_mr_table *mr_table,
        return 0;
 
 err_erif_unresolve:
-       list_for_each_entry_from_reverse(erve, &mr_vif->route_evif_list,
-                                        vif_node)
+       list_for_each_entry_continue_reverse(erve, &mr_vif->route_evif_list,
+                                            vif_node)
                mlxsw_sp_mr_route_evif_unresolve(mr_table, erve);
 err_irif_unresolve:
-       list_for_each_entry_from_reverse(irve, &mr_vif->route_ivif_list,
-                                        vif_node)
+       list_for_each_entry_continue_reverse(irve, &mr_vif->route_ivif_list,
+                                            vif_node)
                mlxsw_sp_mr_route_ivif_unresolve(mr_table, irve);
        mr_vif->rif = NULL;
        return err;
index 1c9e70c..45cc840 100644 (file)
@@ -157,6 +157,50 @@ static int msg_enable;
  */
 
 /**
+ * ks_check_endian - Check whether endianness of the bus is correct
+ * @ks   : The chip information
+ *
+ * The KS8851-16MLL EESK pin allows selecting the endianness of the 16bit
+ * bus. To maintain optimum performance, the bus endianness should be set
+ * such that it matches the endianness of the CPU.
+ */
+
+static int ks_check_endian(struct ks_net *ks)
+{
+       u16 cider;
+
+       /*
+        * Read CIDER register first, however read it the "wrong" way around.
+        * If the endian strap on the KS8851-16MLL in incorrect and the chip
+        * is operating in different endianness than the CPU, then the meaning
+        * of BE[3:0] byte-enable bits is also swapped such that:
+        *    BE[3,2,1,0] becomes BE[1,0,3,2]
+        *
+        * Luckily for us, the byte-enable bits are the top four MSbits of
+        * the address register and the CIDER register is at offset 0xc0.
+        * Hence, by reading address 0xc0c0, which is not impacted by endian
+        * swapping, we assert either BE[3:2] or BE[1:0] while reading the
+        * CIDER register.
+        *
+        * If the bus configuration is correct, reading 0xc0c0 asserts
+        * BE[3:2] and this read returns 0x0000, because to read register
+        * with bottom two LSbits of address set to 0, BE[1:0] must be
+        * asserted.
+        *
+        * If the bus configuration is NOT correct, reading 0xc0c0 asserts
+        * BE[1:0] and this read returns non-zero 0x8872 value.
+        */
+       iowrite16(BE3 | BE2 | KS_CIDER, ks->hw_addr_cmd);
+       cider = ioread16(ks->hw_addr);
+       if (!cider)
+               return 0;
+
+       netdev_err(ks->netdev, "incorrect EESK endian strap setting\n");
+
+       return -EINVAL;
+}
+
+/**
  * ks_rdreg16 - read 16 bit register from device
  * @ks   : The chip information
  * @offset: The register address
@@ -166,7 +210,7 @@ static int msg_enable;
 
 static u16 ks_rdreg16(struct ks_net *ks, int offset)
 {
-       ks->cmd_reg_cache = (u16)offset | ((BE3 | BE2) >> (offset & 0x02));
+       ks->cmd_reg_cache = (u16)offset | ((BE1 | BE0) << (offset & 0x02));
        iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd);
        return ioread16(ks->hw_addr);
 }
@@ -181,7 +225,7 @@ static u16 ks_rdreg16(struct ks_net *ks, int offset)
 
 static void ks_wrreg16(struct ks_net *ks, int offset, u16 value)
 {
-       ks->cmd_reg_cache = (u16)offset | ((BE3 | BE2) >> (offset & 0x02));
+       ks->cmd_reg_cache = (u16)offset | ((BE1 | BE0) << (offset & 0x02));
        iowrite16(ks->cmd_reg_cache, ks->hw_addr_cmd);
        iowrite16(value, ks->hw_addr);
 }
@@ -197,7 +241,7 @@ static inline void ks_inblk(struct ks_net *ks, u16 *wptr, u32 len)
 {
        len >>= 1;
        while (len--)
-               *wptr++ = be16_to_cpu(ioread16(ks->hw_addr));
+               *wptr++ = (u16)ioread16(ks->hw_addr);
 }
 
 /**
@@ -211,7 +255,7 @@ static inline void ks_outblk(struct ks_net *ks, u16 *wptr, u32 len)
 {
        len >>= 1;
        while (len--)
-               iowrite16(cpu_to_be16(*wptr++), ks->hw_addr);
+               iowrite16(*wptr++, ks->hw_addr);
 }
 
 static void ks_disable_int(struct ks_net *ks)
@@ -513,14 +557,17 @@ static irqreturn_t ks_irq(int irq, void *pw)
 {
        struct net_device *netdev = pw;
        struct ks_net *ks = netdev_priv(netdev);
+       unsigned long flags;
        u16 status;
 
+       spin_lock_irqsave(&ks->statelock, flags);
        /*this should be the first in IRQ handler */
        ks_save_cmd_reg(ks);
 
        status = ks_rdreg16(ks, KS_ISR);
        if (unlikely(!status)) {
                ks_restore_cmd_reg(ks);
+               spin_unlock_irqrestore(&ks->statelock, flags);
                return IRQ_NONE;
        }
 
@@ -546,6 +593,7 @@ static irqreturn_t ks_irq(int irq, void *pw)
                ks->netdev->stats.rx_over_errors++;
        /* this should be the last in IRQ handler*/
        ks_restore_cmd_reg(ks);
+       spin_unlock_irqrestore(&ks->statelock, flags);
        return IRQ_HANDLED;
 }
 
@@ -615,6 +663,7 @@ static int ks_net_stop(struct net_device *netdev)
 
        /* shutdown RX/TX QMU */
        ks_disable_qmu(ks);
+       ks_disable_int(ks);
 
        /* set powermode to soft power down to save power */
        ks_set_powermode(ks, PMECR_PM_SOFTDOWN);
@@ -671,10 +720,9 @@ static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        netdev_tx_t retv = NETDEV_TX_OK;
        struct ks_net *ks = netdev_priv(netdev);
+       unsigned long flags;
 
-       disable_irq(netdev->irq);
-       ks_disable_int(ks);
-       spin_lock(&ks->statelock);
+       spin_lock_irqsave(&ks->statelock, flags);
 
        /* Extra space are required:
        *  4 byte for alignment, 4 for status/length, 4 for CRC
@@ -688,9 +736,7 @@ static netdev_tx_t ks_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                dev_kfree_skb(skb);
        } else
                retv = NETDEV_TX_BUSY;
-       spin_unlock(&ks->statelock);
-       ks_enable_int(ks);
-       enable_irq(netdev->irq);
+       spin_unlock_irqrestore(&ks->statelock, flags);
        return retv;
 }
 
@@ -1216,6 +1262,10 @@ static int ks8851_probe(struct platform_device *pdev)
                goto err_free;
        }
 
+       err = ks_check_endian(ks);
+       if (err)
+               goto err_free;
+
        netdev->irq = platform_get_irq(pdev, 0);
 
        if ((int)netdev->irq < 0) {
index 86d543a..d3b7373 100644 (file)
@@ -2176,24 +2176,29 @@ static int ocelot_init_timestamp(struct ocelot *ocelot)
        return 0;
 }
 
-static void ocelot_port_set_mtu(struct ocelot *ocelot, int port, size_t mtu)
+/* Configure the maximum SDU (L2 payload) on RX to the value specified in @sdu.
+ * The length of VLAN tags is accounted for automatically via DEV_MAC_TAGS_CFG.
+ */
+static void ocelot_port_set_maxlen(struct ocelot *ocelot, int port, size_t sdu)
 {
        struct ocelot_port *ocelot_port = ocelot->ports[port];
+       int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;
        int atop_wm;
 
-       ocelot_port_writel(ocelot_port, mtu, DEV_MAC_MAXLEN_CFG);
+       ocelot_port_writel(ocelot_port, maxlen, DEV_MAC_MAXLEN_CFG);
 
        /* Set Pause WM hysteresis
-        * 152 = 6 * mtu / OCELOT_BUFFER_CELL_SZ
-        * 101 = 4 * mtu / OCELOT_BUFFER_CELL_SZ
+        * 152 = 6 * maxlen / OCELOT_BUFFER_CELL_SZ
+        * 101 = 4 * maxlen / OCELOT_BUFFER_CELL_SZ
         */
        ocelot_write_rix(ocelot, SYS_PAUSE_CFG_PAUSE_ENA |
                         SYS_PAUSE_CFG_PAUSE_STOP(101) |
                         SYS_PAUSE_CFG_PAUSE_START(152), SYS_PAUSE_CFG, port);
 
        /* Tail dropping watermark */
-       atop_wm = (ocelot->shared_queue_sz - 9 * mtu) / OCELOT_BUFFER_CELL_SZ;
-       ocelot_write_rix(ocelot, ocelot_wm_enc(9 * mtu),
+       atop_wm = (ocelot->shared_queue_sz - 9 * maxlen) /
+                  OCELOT_BUFFER_CELL_SZ;
+       ocelot_write_rix(ocelot, ocelot_wm_enc(9 * maxlen),
                         SYS_ATOP, port);
        ocelot_write(ocelot, ocelot_wm_enc(atop_wm), SYS_ATOP_TOT_CFG);
 }
@@ -2222,9 +2227,10 @@ void ocelot_init_port(struct ocelot *ocelot, int port)
                           DEV_MAC_HDX_CFG);
 
        /* Set Max Length and maximum tags allowed */
-       ocelot_port_set_mtu(ocelot, port, VLAN_ETH_FRAME_LEN);
+       ocelot_port_set_maxlen(ocelot, port, ETH_DATA_LEN);
        ocelot_port_writel(ocelot_port, DEV_MAC_TAGS_CFG_TAG_ID(ETH_P_8021AD) |
                           DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
+                          DEV_MAC_TAGS_CFG_VLAN_DBL_AWR_ENA |
                           DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA,
                           DEV_MAC_TAGS_CFG);
 
@@ -2310,18 +2316,18 @@ void ocelot_set_cpu_port(struct ocelot *ocelot, int cpu,
         * Only one port can be an NPI at the same time.
         */
        if (cpu < ocelot->num_phys_ports) {
-               int mtu = VLAN_ETH_FRAME_LEN + OCELOT_TAG_LEN;
+               int sdu = ETH_DATA_LEN + OCELOT_TAG_LEN;
 
                ocelot_write(ocelot, QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_M |
                             QSYS_EXT_CPU_CFG_EXT_CPU_PORT(cpu),
                             QSYS_EXT_CPU_CFG);
 
                if (injection == OCELOT_TAG_PREFIX_SHORT)
-                       mtu += OCELOT_SHORT_PREFIX_LEN;
+                       sdu += OCELOT_SHORT_PREFIX_LEN;
                else if (injection == OCELOT_TAG_PREFIX_LONG)
-                       mtu += OCELOT_LONG_PREFIX_LEN;
+                       sdu += OCELOT_LONG_PREFIX_LEN;
 
-               ocelot_port_set_mtu(ocelot, cpu, mtu);
+               ocelot_port_set_maxlen(ocelot, cpu, sdu);
        }
 
        /* CPU port Injection/Extraction configuration */
index e678ba3..628fa9b 100644 (file)
@@ -2045,7 +2045,7 @@ vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask);
        if ((level >= VXGE_ERR && VXGE_COMPONENT_LL & VXGE_DEBUG_ERR_MASK) ||  \
            (level >= VXGE_TRACE && VXGE_COMPONENT_LL & VXGE_DEBUG_TRACE_MASK))\
                if ((mask & VXGE_DEBUG_MASK) == mask)                          \
-                       printk(fmt "\n", __VA_ARGS__);                         \
+                       printk(fmt "\n", ##__VA_ARGS__);                       \
 } while (0)
 #else
 #define vxge_debug_ll(level, mask, fmt, ...)
index 59a57ff..9c86f4f 100644 (file)
@@ -452,49 +452,49 @@ int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override);
 
 #if (VXGE_DEBUG_LL_CONFIG & VXGE_DEBUG_MASK)
 #define vxge_debug_ll_config(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, __VA_ARGS__)
+       vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_ll_config(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_INIT & VXGE_DEBUG_MASK)
 #define vxge_debug_init(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, __VA_ARGS__)
+       vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_init(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_TX & VXGE_DEBUG_MASK)
 #define vxge_debug_tx(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, __VA_ARGS__)
+       vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_tx(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_RX & VXGE_DEBUG_MASK)
 #define vxge_debug_rx(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, __VA_ARGS__)
+       vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_rx(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_MEM & VXGE_DEBUG_MASK)
 #define vxge_debug_mem(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, __VA_ARGS__)
+       vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_mem(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)
 #define vxge_debug_entryexit(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, __VA_ARGS__)
+       vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_entryexit(level, fmt, ...)
 #endif
 
 #if (VXGE_DEBUG_INTR & VXGE_DEBUG_MASK)
 #define vxge_debug_intr(level, fmt, ...) \
-       vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, __VA_ARGS__)
+       vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, ##__VA_ARGS__)
 #else
 #define vxge_debug_intr(level, fmt, ...)
 #endif
index b454db2..684e4e0 100644 (file)
@@ -616,7 +616,7 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
        if (bar->iomem) {
                int pf;
 
-               msg += snprintf(msg, end - msg, "0.0: General/MSI-X SRAM, ");
+               msg += scnprintf(msg, end - msg, "0.0: General/MSI-X SRAM, ");
                atomic_inc(&bar->refcnt);
                bars_free--;
 
@@ -661,7 +661,7 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
 
        /* Configure, and lock, BAR0.1 for PCIe XPB (MSI-X PBA) */
        bar = &nfp->bar[1];
-       msg += snprintf(msg, end - msg, "0.1: PCIe XPB/MSI-X PBA, ");
+       msg += scnprintf(msg, end - msg, "0.1: PCIe XPB/MSI-X PBA, ");
        atomic_inc(&bar->refcnt);
        bars_free--;
 
@@ -680,8 +680,8 @@ static int enable_bars(struct nfp6000_pcie *nfp, u16 interface)
                bar->iomem = ioremap(nfp_bar_resource_start(bar),
                                             nfp_bar_resource_len(bar));
                if (bar->iomem) {
-                       msg += snprintf(msg, end - msg,
-                                       "0.%d: Explicit%d, ", 4 + i, i);
+                       msg += scnprintf(msg, end - msg,
+                                        "0.%d: Explicit%d, ", 4 + i, i);
                        atomic_inc(&bar->refcnt);
                        bars_free--;
 
index 54547d5..51adf50 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB OR BSD-2-Clause */
+/* SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) OR BSD-2-Clause */
 /* Copyright (c) 2017-2019 Pensando Systems, Inc.  All rights reserved. */
 
 #ifndef _IONIC_IF_H_
index 191271f..938e19e 100644 (file)
@@ -948,18 +948,18 @@ static void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode)
        int i;
 #define REMAIN(__x) (sizeof(buf) - (__x))
 
-       i = snprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:",
-                    lif->rx_mode, rx_mode);
+       i = scnprintf(buf, sizeof(buf), "rx_mode 0x%04x -> 0x%04x:",
+                     lif->rx_mode, rx_mode);
        if (rx_mode & IONIC_RX_MODE_F_UNICAST)
-               i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST");
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_UNICAST");
        if (rx_mode & IONIC_RX_MODE_F_MULTICAST)
-               i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST");
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_MULTICAST");
        if (rx_mode & IONIC_RX_MODE_F_BROADCAST)
-               i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST");
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_BROADCAST");
        if (rx_mode & IONIC_RX_MODE_F_PROMISC)
-               i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC");
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_PROMISC");
        if (rx_mode & IONIC_RX_MODE_F_ALLMULTI)
-               i += snprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI");
+               i += scnprintf(&buf[i], REMAIN(i), " RX_MODE_F_ALLMULTI");
        netdev_dbg(lif->netdev, "lif%d %s\n", lif->index, buf);
 
        err = ionic_adminq_post_wait(lif, &ctx);
@@ -1688,7 +1688,7 @@ static int ionic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
        if (!(is_zero_ether_addr(mac) || is_valid_ether_addr(mac)))
                return -EINVAL;
 
-       down_read(&ionic->vf_op_lock);
+       down_write(&ionic->vf_op_lock);
 
        if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
                ret = -EINVAL;
@@ -1698,7 +1698,7 @@ static int ionic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
                        ether_addr_copy(ionic->vfs[vf].macaddr, mac);
        }
 
-       up_read(&ionic->vf_op_lock);
+       up_write(&ionic->vf_op_lock);
        return ret;
 }
 
@@ -1719,7 +1719,7 @@ static int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
        if (proto != htons(ETH_P_8021Q))
                return -EPROTONOSUPPORT;
 
-       down_read(&ionic->vf_op_lock);
+       down_write(&ionic->vf_op_lock);
 
        if (vf >= pci_num_vf(ionic->pdev) || !ionic->vfs) {
                ret = -EINVAL;
@@ -1730,7 +1730,7 @@ static int ionic_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan,
                        ionic->vfs[vf].vlanid = vlan;
        }
 
-       up_read(&ionic->vf_op_lock);
+       up_write(&ionic->vf_op_lock);
        return ret;
 }
 
index 03ee5a3..2e174f4 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB OR BSD-2-Clause */
+/* SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) OR BSD-2-Clause */
 /* Copyright (c) 2018-2019 Pensando Systems, Inc.  All rights reserved. */
 
 #ifndef IONIC_REGS_H
index 07f9067..cda5b0a 100644 (file)
@@ -1720,7 +1720,7 @@ static int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_d
 
        ahw->reset.seq_error = 0;
        ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
-       if (p_dev->ahw->reset.buff == NULL)
+       if (ahw->reset.buff == NULL)
                return -ENOMEM;
 
        p_buff = p_dev->ahw->reset.buff;
index 06de595..fbf4cbc 100644 (file)
 #include "rmnet_vnd.h"
 #include "rmnet_private.h"
 
-/* Locking scheme -
- * The shared resource which needs to be protected is realdev->rx_handler_data.
- * For the writer path, this is using rtnl_lock(). The writer paths are
- * rmnet_newlink(), rmnet_dellink() and rmnet_force_unassociate_device(). These
- * paths are already called with rtnl_lock() acquired in. There is also an
- * ASSERT_RTNL() to ensure that we are calling with rtnl acquired. For
- * dereference here, we will need to use rtnl_dereference(). Dev list writing
- * needs to happen with rtnl_lock() acquired for netdev_master_upper_dev_link().
- * For the reader path, the real_dev->rx_handler_data is called in the TX / RX
- * path. We only need rcu_read_lock() for these scenarios. In these cases,
- * the rcu_read_lock() is held in __dev_queue_xmit() and
- * netif_receive_skb_internal(), so readers need to use rcu_dereference_rtnl()
- * to get the relevant information. For dev list reading, we again acquire
- * rcu_read_lock() in rmnet_dellink() for netdev_master_upper_dev_get_rcu().
- * We also use unregister_netdevice_many() to free all rmnet devices in
- * rmnet_force_unassociate_device() so we dont lose the rtnl_lock() and free in
- * same context.
- */
-
 /* Local Definitions and Declarations */
 
 static const struct nla_policy rmnet_policy[IFLA_RMNET_MAX + 1] = {
@@ -51,9 +32,10 @@ rmnet_get_port_rtnl(const struct net_device *real_dev)
        return rtnl_dereference(real_dev->rx_handler_data);
 }
 
-static int rmnet_unregister_real_device(struct net_device *real_dev,
-                                       struct rmnet_port *port)
+static int rmnet_unregister_real_device(struct net_device *real_dev)
 {
+       struct rmnet_port *port = rmnet_get_port_rtnl(real_dev);
+
        if (port->nr_rmnet_devs)
                return -EINVAL;
 
@@ -61,9 +43,6 @@ static int rmnet_unregister_real_device(struct net_device *real_dev,
 
        kfree(port);
 
-       /* release reference on real_dev */
-       dev_put(real_dev);
-
        netdev_dbg(real_dev, "Removed from rmnet\n");
        return 0;
 }
@@ -89,9 +68,6 @@ static int rmnet_register_real_device(struct net_device *real_dev)
                return -EBUSY;
        }
 
-       /* hold on to real dev for MAP data */
-       dev_hold(real_dev);
-
        for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++)
                INIT_HLIST_HEAD(&port->muxed_ep[entry]);
 
@@ -99,28 +75,33 @@ static int rmnet_register_real_device(struct net_device *real_dev)
        return 0;
 }
 
-static void rmnet_unregister_bridge(struct net_device *dev,
-                                   struct rmnet_port *port)
+static void rmnet_unregister_bridge(struct rmnet_port *port)
 {
-       struct rmnet_port *bridge_port;
-       struct net_device *bridge_dev;
+       struct net_device *bridge_dev, *real_dev, *rmnet_dev;
+       struct rmnet_port *real_port;
 
        if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
                return;
 
-       /* bridge slave handling */
+       rmnet_dev = port->rmnet_dev;
        if (!port->nr_rmnet_devs) {
-               bridge_dev = port->bridge_ep;
+               /* bridge device */
+               real_dev = port->bridge_ep;
+               bridge_dev = port->dev;
 
-               bridge_port = rmnet_get_port_rtnl(bridge_dev);
-               bridge_port->bridge_ep = NULL;
-               bridge_port->rmnet_mode = RMNET_EPMODE_VND;
+               real_port = rmnet_get_port_rtnl(real_dev);
+               real_port->bridge_ep = NULL;
+               real_port->rmnet_mode = RMNET_EPMODE_VND;
        } else {
+               /* real device */
                bridge_dev = port->bridge_ep;
 
-               bridge_port = rmnet_get_port_rtnl(bridge_dev);
-               rmnet_unregister_real_device(bridge_dev, bridge_port);
+               port->bridge_ep = NULL;
+               port->rmnet_mode = RMNET_EPMODE_VND;
        }
+
+       netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
+       rmnet_unregister_real_device(bridge_dev);
 }
 
 static int rmnet_newlink(struct net *src_net, struct net_device *dev,
@@ -135,6 +116,11 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
        int err = 0;
        u16 mux_id;
 
+       if (!tb[IFLA_LINK]) {
+               NL_SET_ERR_MSG_MOD(extack, "link not specified");
+               return -EINVAL;
+       }
+
        real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
        if (!real_dev || !dev)
                return -ENODEV;
@@ -157,7 +143,12 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
        if (err)
                goto err1;
 
+       err = netdev_upper_dev_link(real_dev, dev, extack);
+       if (err < 0)
+               goto err2;
+
        port->rmnet_mode = mode;
+       port->rmnet_dev = dev;
 
        hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
 
@@ -173,8 +164,11 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 
        return 0;
 
+err2:
+       unregister_netdevice(dev);
+       rmnet_vnd_dellink(mux_id, port, ep);
 err1:
-       rmnet_unregister_real_device(real_dev, port);
+       rmnet_unregister_real_device(real_dev);
 err0:
        kfree(ep);
        return err;
@@ -183,77 +177,74 @@ err0:
 static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 {
        struct rmnet_priv *priv = netdev_priv(dev);
-       struct net_device *real_dev;
+       struct net_device *real_dev, *bridge_dev;
+       struct rmnet_port *real_port, *bridge_port;
        struct rmnet_endpoint *ep;
-       struct rmnet_port *port;
-       u8 mux_id;
+       u8 mux_id = priv->mux_id;
 
        real_dev = priv->real_dev;
 
-       if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
+       if (!rmnet_is_real_dev_registered(real_dev))
                return;
 
-       port = rmnet_get_port_rtnl(real_dev);
-
-       mux_id = rmnet_vnd_get_mux(dev);
+       real_port = rmnet_get_port_rtnl(real_dev);
+       bridge_dev = real_port->bridge_ep;
+       if (bridge_dev) {
+               bridge_port = rmnet_get_port_rtnl(bridge_dev);
+               rmnet_unregister_bridge(bridge_port);
+       }
 
-       ep = rmnet_get_endpoint(port, mux_id);
+       ep = rmnet_get_endpoint(real_port, mux_id);
        if (ep) {
                hlist_del_init_rcu(&ep->hlnode);
-               rmnet_unregister_bridge(dev, port);
-               rmnet_vnd_dellink(mux_id, port, ep);
+               rmnet_vnd_dellink(mux_id, real_port, ep);
                kfree(ep);
        }
-       rmnet_unregister_real_device(real_dev, port);
 
+       netdev_upper_dev_unlink(real_dev, dev);
+       rmnet_unregister_real_device(real_dev);
        unregister_netdevice_queue(dev, head);
 }
 
-static void rmnet_force_unassociate_device(struct net_device *dev)
+static void rmnet_force_unassociate_device(struct net_device *real_dev)
 {
-       struct net_device *real_dev = dev;
        struct hlist_node *tmp_ep;
        struct rmnet_endpoint *ep;
        struct rmnet_port *port;
        unsigned long bkt_ep;
        LIST_HEAD(list);
 
-       if (!rmnet_is_real_dev_registered(real_dev))
-               return;
-
-       ASSERT_RTNL();
-
-       port = rmnet_get_port_rtnl(dev);
-
-       rcu_read_lock();
-       rmnet_unregister_bridge(dev, port);
-
-       hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
-               unregister_netdevice_queue(ep->egress_dev, &list);
-               rmnet_vnd_dellink(ep->mux_id, port, ep);
+       port = rmnet_get_port_rtnl(real_dev);
 
-               hlist_del_init_rcu(&ep->hlnode);
-               kfree(ep);
+       if (port->nr_rmnet_devs) {
+               /* real device */
+               rmnet_unregister_bridge(port);
+               hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
+                       unregister_netdevice_queue(ep->egress_dev, &list);
+                       netdev_upper_dev_unlink(real_dev, ep->egress_dev);
+                       rmnet_vnd_dellink(ep->mux_id, port, ep);
+                       hlist_del_init_rcu(&ep->hlnode);
+                       kfree(ep);
+               }
+               rmnet_unregister_real_device(real_dev);
+               unregister_netdevice_many(&list);
+       } else {
+               rmnet_unregister_bridge(port);
        }
-
-       rcu_read_unlock();
-       unregister_netdevice_many(&list);
-
-       rmnet_unregister_real_device(real_dev, port);
 }
 
 static int rmnet_config_notify_cb(struct notifier_block *nb,
                                  unsigned long event, void *data)
 {
-       struct net_device *dev = netdev_notifier_info_to_dev(data);
+       struct net_device *real_dev = netdev_notifier_info_to_dev(data);
 
-       if (!dev)
+       if (!rmnet_is_real_dev_registered(real_dev))
                return NOTIFY_DONE;
 
        switch (event) {
        case NETDEV_UNREGISTER:
-               netdev_dbg(dev, "Kernel unregister\n");
-               rmnet_force_unassociate_device(dev);
+               netdev_dbg(real_dev, "Kernel unregister\n");
+               rmnet_force_unassociate_device(real_dev);
                break;
 
        default:
@@ -295,16 +286,18 @@ static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
        if (!dev)
                return -ENODEV;
 
-       real_dev = __dev_get_by_index(dev_net(dev),
-                                     nla_get_u32(tb[IFLA_LINK]));
-
-       if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
+       real_dev = priv->real_dev;
+       if (!rmnet_is_real_dev_registered(real_dev))
                return -ENODEV;
 
        port = rmnet_get_port_rtnl(real_dev);
 
        if (data[IFLA_RMNET_MUX_ID]) {
                mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]);
+               if (rmnet_get_endpoint(port, mux_id)) {
+                       NL_SET_ERR_MSG_MOD(extack, "MUX ID already exists");
+                       return -EINVAL;
+               }
                ep = rmnet_get_endpoint(port, priv->mux_id);
                if (!ep)
                        return -ENODEV;
@@ -379,11 +372,10 @@ struct rtnl_link_ops rmnet_link_ops __read_mostly = {
        .fill_info      = rmnet_fill_info,
 };
 
-/* Needs either rcu_read_lock() or rtnl lock */
-struct rmnet_port *rmnet_get_port(struct net_device *real_dev)
+struct rmnet_port *rmnet_get_port_rcu(struct net_device *real_dev)
 {
        if (rmnet_is_real_dev_registered(real_dev))
-               return rcu_dereference_rtnl(real_dev->rx_handler_data);
+               return rcu_dereference_bh(real_dev->rx_handler_data);
        else
                return NULL;
 }
@@ -409,7 +401,7 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
        struct rmnet_port *port, *slave_port;
        int err;
 
-       port = rmnet_get_port(real_dev);
+       port = rmnet_get_port_rtnl(real_dev);
 
        /* If there is more than one rmnet dev attached, its probably being
         * used for muxing. Skip the briding in that case
@@ -417,6 +409,9 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
        if (port->nr_rmnet_devs > 1)
                return -EINVAL;
 
+       if (port->rmnet_mode != RMNET_EPMODE_VND)
+               return -EINVAL;
+
        if (rmnet_is_real_dev_registered(slave_dev))
                return -EBUSY;
 
@@ -424,9 +419,17 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
        if (err)
                return -EBUSY;
 
-       slave_port = rmnet_get_port(slave_dev);
+       err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
+                                          extack);
+       if (err) {
+               rmnet_unregister_real_device(slave_dev);
+               return err;
+       }
+
+       slave_port = rmnet_get_port_rtnl(slave_dev);
        slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
        slave_port->bridge_ep = real_dev;
+       slave_port->rmnet_dev = rmnet_dev;
 
        port->rmnet_mode = RMNET_EPMODE_BRIDGE;
        port->bridge_ep = slave_dev;
@@ -438,16 +441,9 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
 int rmnet_del_bridge(struct net_device *rmnet_dev,
                     struct net_device *slave_dev)
 {
-       struct rmnet_priv *priv = netdev_priv(rmnet_dev);
-       struct net_device *real_dev = priv->real_dev;
-       struct rmnet_port *port, *slave_port;
+       struct rmnet_port *port = rmnet_get_port_rtnl(slave_dev);
 
-       port = rmnet_get_port(real_dev);
-       port->rmnet_mode = RMNET_EPMODE_VND;
-       port->bridge_ep = NULL;
-
-       slave_port = rmnet_get_port(slave_dev);
-       rmnet_unregister_real_device(slave_dev, slave_port);
+       rmnet_unregister_bridge(port);
 
        netdev_dbg(slave_dev, "removed from rmnet as slave\n");
        return 0;
@@ -473,8 +469,8 @@ static int __init rmnet_init(void)
 
 static void __exit rmnet_exit(void)
 {
-       unregister_netdevice_notifier(&rmnet_dev_notifier);
        rtnl_link_unregister(&rmnet_link_ops);
+       unregister_netdevice_notifier(&rmnet_dev_notifier);
 }
 
 module_init(rmnet_init)
index cd0a6bc..be51598 100644 (file)
@@ -28,6 +28,7 @@ struct rmnet_port {
        u8 rmnet_mode;
        struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
        struct net_device *bridge_ep;
+       struct net_device *rmnet_dev;
 };
 
 extern struct rtnl_link_ops rmnet_link_ops;
@@ -65,7 +66,7 @@ struct rmnet_priv {
        struct rmnet_priv_stats stats;
 };
 
-struct rmnet_port *rmnet_get_port(struct net_device *real_dev);
+struct rmnet_port *rmnet_get_port_rcu(struct net_device *real_dev);
 struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id);
 int rmnet_add_bridge(struct net_device *rmnet_dev,
                     struct net_device *slave_dev,
index 1b74bc1..29a7bfa 100644 (file)
@@ -159,6 +159,9 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
 static void
 rmnet_bridge_handler(struct sk_buff *skb, struct net_device *bridge_dev)
 {
+       if (skb_mac_header_was_set(skb))
+               skb_push(skb, skb->mac_len);
+
        if (bridge_dev) {
                skb->dev = bridge_dev;
                dev_queue_xmit(skb);
@@ -184,7 +187,7 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
                return RX_HANDLER_PASS;
 
        dev = skb->dev;
-       port = rmnet_get_port(dev);
+       port = rmnet_get_port_rcu(dev);
 
        switch (port->rmnet_mode) {
        case RMNET_EPMODE_VND:
@@ -217,7 +220,7 @@ void rmnet_egress_handler(struct sk_buff *skb)
        skb->dev = priv->real_dev;
        mux_id = priv->mux_id;
 
-       port = rmnet_get_port(skb->dev);
+       port = rmnet_get_port_rcu(skb->dev);
        if (!port)
                goto drop;
 
index 509dfc8..26ad40f 100644 (file)
@@ -266,14 +266,6 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
        return 0;
 }
 
-u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev)
-{
-       struct rmnet_priv *priv;
-
-       priv = netdev_priv(rmnet_dev);
-       return priv->mux_id;
-}
-
 int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
 {
        netdev_dbg(rmnet_dev, "Setting VND TX queue state to %d\n", enable);
index 54cbaf3..14d77c7 100644 (file)
@@ -16,6 +16,5 @@ int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
                      struct rmnet_endpoint *ep);
 void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev);
 void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev);
-u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev);
 void rmnet_vnd_setup(struct net_device *dev);
 #endif /* _RMNET_VND_H_ */
index a2168a1..791d99b 100644 (file)
@@ -5194,7 +5194,7 @@ static int rtl_alloc_irq(struct rtl8169_private *tp)
                RTL_W8(tp, Config2, RTL_R8(tp, Config2) & ~MSIEnable);
                rtl_lock_config_regs(tp);
                /* fall through */
-       case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_24:
+       case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_17:
                flags = PCI_IRQ_LEGACY;
                break;
        default:
@@ -5285,6 +5285,13 @@ static int r8169_mdio_register(struct rtl8169_private *tp)
        if (!tp->phydev) {
                mdiobus_unregister(new_bus);
                return -ENODEV;
+       } else if (!tp->phydev->drv) {
+               /* Most chip versions fail with the genphy driver.
+                * Therefore ensure that the dedicated PHY driver is loaded.
+                */
+               dev_err(&pdev->dev, "realtek.ko not loaded, maybe it needs to be added to initramfs?\n");
+               mdiobus_unregister(new_bus);
+               return -EUNATCH;
        }
 
        /* PHY will be woken up in rtl_open() */
@@ -5446,15 +5453,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        int chipset, region;
        int jumbo_max, rc;
 
-       /* Some tools for creating an initramfs don't consider softdeps, then
-        * r8169.ko may be in initramfs, but realtek.ko not. Then the generic
-        * PHY driver is used that doesn't work with most chip versions.
-        */
-       if (!driver_find("RTL8201CP Ethernet", &mdio_bus_type)) {
-               dev_err(&pdev->dev, "realtek.ko not loaded, maybe it needs to be added to initramfs?\n");
-               return -ENOENT;
-       }
-
        dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp));
        if (!dev)
                return -ENOMEM;
index c705743..2cc8184 100644 (file)
@@ -2277,7 +2277,7 @@ static int __init sxgbe_cmdline_opt(char *str)
        if (!str || !*str)
                return -EINVAL;
        while ((opt = strsep(&str, ",")) != NULL) {
-               if (!strncmp(opt, "eee_timer:", 6)) {
+               if (!strncmp(opt, "eee_timer:", 10)) {
                        if (kstrtoint(opt + 10, 0, &eee_timer))
                                goto err;
                }
index 52113b7..3f16bd8 100644 (file)
@@ -2853,11 +2853,24 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
        }
 
        /* Transmit timestamps are only available for 8XXX series. They result
-        * in three events per packet. These occur in order, and are:
-        *  - the normal completion event
+        * in up to three events per packet. These occur in order, and are:
+        *  - the normal completion event (may be omitted)
         *  - the low part of the timestamp
         *  - the high part of the timestamp
         *
+        * It's possible for multiple completion events to appear before the
+        * corresponding timestamps. So we can for example get:
+        *  COMP N
+        *  COMP N+1
+        *  TS_LO N
+        *  TS_HI N
+        *  TS_LO N+1
+        *  TS_HI N+1
+        *
+        * In addition it's also possible for the adjacent completions to be
+        * merged, so we may not see COMP N above. As such, the completion
+        * events are not very useful here.
+        *
         * Each part of the timestamp is itself split across two 16 bit
         * fields in the event.
         */
@@ -2865,17 +2878,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
 
        switch (tx_ev_type) {
        case TX_TIMESTAMP_EVENT_TX_EV_COMPLETION:
-               /* In case of Queue flush or FLR, we might have received
-                * the previous TX completion event but not the Timestamp
-                * events.
-                */
-               if (tx_queue->completed_desc_ptr != tx_queue->ptr_mask)
-                       efx_xmit_done(tx_queue, tx_queue->completed_desc_ptr);
-
-               tx_ev_desc_ptr = EFX_QWORD_FIELD(*event,
-                                                ESF_DZ_TX_DESCR_INDX);
-               tx_queue->completed_desc_ptr =
-                                       tx_ev_desc_ptr & tx_queue->ptr_mask;
+               /* Ignore this event - see above. */
                break;
 
        case TX_TIMESTAMP_EVENT_TX_EV_TSTAMP_LO:
@@ -2887,8 +2890,7 @@ efx_ef10_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
                ts_part = efx_ef10_extract_event_ts(event);
                tx_queue->completed_timestamp_major = ts_part;
 
-               efx_xmit_done(tx_queue, tx_queue->completed_desc_ptr);
-               tx_queue->completed_desc_ptr = tx_queue->ptr_mask;
+               efx_xmit_done_single(tx_queue);
                break;
 
        default:
index f1bdb04..95395d6 100644 (file)
@@ -20,6 +20,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
                                struct net_device *net_dev);
 netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
 void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
+void efx_xmit_done_single(struct efx_tx_queue *tx_queue);
 int efx_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
                 void *type_data);
 extern unsigned int efx_piobuf_size;
index aeb5e8a..73d4e39 100644 (file)
@@ -583,6 +583,7 @@ struct efx_channel *efx_copy_channel(const struct efx_channel *old_channel)
                if (tx_queue->channel)
                        tx_queue->channel = channel;
                tx_queue->buffer = NULL;
+               tx_queue->cb_page = NULL;
                memset(&tx_queue->txd, 0, sizeof(tx_queue->txd));
        }
 
index 2713300..15c731d 100644 (file)
@@ -212,12 +212,14 @@ static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd,
                 * progress on a NIC at any one time.  So no need for locking.
                 */
                for (i = 0; i < hdr_len / 4 && bytes < PAGE_SIZE; i++)
-                       bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
-                                         " %08x", le32_to_cpu(hdr[i].u32[0]));
+                       bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes,
+                                          " %08x",
+                                          le32_to_cpu(hdr[i].u32[0]));
 
                for (i = 0; i < inlen / 4 && bytes < PAGE_SIZE; i++)
-                       bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
-                                         " %08x", le32_to_cpu(inbuf[i].u32[0]));
+                       bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes,
+                                          " %08x",
+                                          le32_to_cpu(inbuf[i].u32[0]));
 
                netif_info(efx, hw, efx->net_dev, "MCDI RPC REQ:%s\n", buf);
        }
@@ -302,15 +304,15 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx)
                 */
                for (i = 0; i < hdr_len && bytes < PAGE_SIZE; i++) {
                        efx->type->mcdi_read_response(efx, &hdr, (i * 4), 4);
-                       bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
-                                         " %08x", le32_to_cpu(hdr.u32[0]));
+                       bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes,
+                                          " %08x", le32_to_cpu(hdr.u32[0]));
                }
 
                for (i = 0; i < data_len && bytes < PAGE_SIZE; i++) {
                        efx->type->mcdi_read_response(efx, &hdr,
                                        mcdi->resp_hdr_len + (i * 4), 4);
-                       bytes += snprintf(buf + bytes, PAGE_SIZE - bytes,
-                                         " %08x", le32_to_cpu(hdr.u32[0]));
+                       bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes,
+                                          " %08x", le32_to_cpu(hdr.u32[0]));
                }
 
                netif_info(efx, hw, efx->net_dev, "MCDI RPC RESP:%s\n", buf);
@@ -1417,9 +1419,11 @@ void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
        }
 
        ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION);
-       offset = snprintf(buf, len, "%u.%u.%u.%u",
-                         le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]),
-                         le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3]));
+       offset = scnprintf(buf, len, "%u.%u.%u.%u",
+                          le16_to_cpu(ver_words[0]),
+                          le16_to_cpu(ver_words[1]),
+                          le16_to_cpu(ver_words[2]),
+                          le16_to_cpu(ver_words[3]));
 
        /* EF10 may have multiple datapath firmware variants within a
         * single version.  Report which variants are running.
@@ -1427,9 +1431,9 @@ void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len)
        if (efx_nic_rev(efx) >= EFX_REV_HUNT_A0) {
                struct efx_ef10_nic_data *nic_data = efx->nic_data;
 
-               offset += snprintf(buf + offset, len - offset, " rx%x tx%x",
-                                  nic_data->rx_dpcpu_fw_id,
-                                  nic_data->tx_dpcpu_fw_id);
+               offset += scnprintf(buf + offset, len - offset, " rx%x tx%x",
+                                   nic_data->rx_dpcpu_fw_id,
+                                   nic_data->tx_dpcpu_fw_id);
 
                /* It's theoretically possible for the string to exceed 31
                 * characters, though in practice the first three version
index 9f9886f..8164f0e 100644 (file)
@@ -208,8 +208,6 @@ struct efx_tx_buffer {
  *     avoid cache-line ping-pong between the xmit path and the
  *     completion path.
  * @merge_events: Number of TX merged completion events
- * @completed_desc_ptr: Most recent completed pointer - only used with
- *      timestamping.
  * @completed_timestamp_major: Top part of the most recent tx timestamp.
  * @completed_timestamp_minor: Low part of the most recent tx timestamp.
  * @insert_count: Current insert pointer
@@ -269,7 +267,6 @@ struct efx_tx_queue {
        unsigned int merge_events;
        unsigned int bytes_compl;
        unsigned int pkts_compl;
-       unsigned int completed_desc_ptr;
        u32 completed_timestamp_major;
        u32 completed_timestamp_minor;
 
index af15a73..59b4f16 100644 (file)
@@ -560,13 +560,45 @@ efx_ptp_mac_nic_to_ktime_correction(struct efx_nic *efx,
                                    u32 nic_major, u32 nic_minor,
                                    s32 correction)
 {
+       u32 sync_timestamp;
        ktime_t kt = { 0 };
+       s16 delta;
 
        if (!(nic_major & 0x80000000)) {
                WARN_ON_ONCE(nic_major >> 16);
-               /* Use the top bits from the latest sync event. */
-               nic_major &= 0xffff;
-               nic_major |= (last_sync_timestamp_major(efx) & 0xffff0000);
+
+               /* Medford provides 48 bits of timestamp, so we must get the top
+                * 16 bits from the timesync event state.
+                *
+                * We only have the lower 16 bits of the time now, but we do
+                * have a full resolution timestamp at some point in past. As
+                * long as the difference between the (real) now and the sync
+                * is less than 2^15, then we can reconstruct the difference
+                * between those two numbers using only the lower 16 bits of
+                * each.
+                *
+                * Put another way
+                *
+                * a - b = ((a mod k) - b) mod k
+                *
+                * when -k/2 < (a-b) < k/2. In our case k is 2^16. We know
+                * (a mod k) and b, so can calculate the delta, a - b.
+                *
+                */
+               sync_timestamp = last_sync_timestamp_major(efx);
+
+               /* Because delta is s16 this does an implicit mask down to
+                * 16 bits which is what we need, assuming
+                * MEDFORD_TX_SECS_EVENT_BITS is 16. delta is signed so that
+                * we can deal with the (unlikely) case of sync timestamps
+                * arriving from the future.
+                */
+               delta = nic_major - sync_timestamp;
+
+               /* Recover the fully specified time now, by applying the offset
+                * to the (fully specified) sync time.
+                */
+               nic_major = sync_timestamp + delta;
 
                kt = ptp->nic_to_kernel_time(nic_major, nic_minor,
                                             correction);
index 04d7f41..8aafc54 100644 (file)
@@ -535,6 +535,44 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
        return efx_enqueue_skb(tx_queue, skb);
 }
 
+void efx_xmit_done_single(struct efx_tx_queue *tx_queue)
+{
+       unsigned int pkts_compl = 0, bytes_compl = 0;
+       unsigned int read_ptr;
+       bool finished = false;
+
+       read_ptr = tx_queue->read_count & tx_queue->ptr_mask;
+
+       while (!finished) {
+               struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
+
+               if (!efx_tx_buffer_in_use(buffer)) {
+                       struct efx_nic *efx = tx_queue->efx;
+
+                       netif_err(efx, hw, efx->net_dev,
+                                 "TX queue %d spurious single TX completion\n",
+                                 tx_queue->queue);
+                       efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
+                       return;
+               }
+
+               /* Need to check the flag before dequeueing. */
+               if (buffer->flags & EFX_TX_BUF_SKB)
+                       finished = true;
+               efx_dequeue_buffer(tx_queue, buffer, &pkts_compl, &bytes_compl);
+
+               ++tx_queue->read_count;
+               read_ptr = tx_queue->read_count & tx_queue->ptr_mask;
+       }
+
+       tx_queue->pkts_compl += pkts_compl;
+       tx_queue->bytes_compl += bytes_compl;
+
+       EFX_WARN_ON_PARANOID(pkts_compl != 1);
+
+       efx_xmit_done_check_empty(tx_queue);
+}
+
 void efx_init_tx_queue_core_txq(struct efx_tx_queue *tx_queue)
 {
        struct efx_nic *efx = tx_queue->efx;
index b1571e9..70876df 100644 (file)
@@ -80,7 +80,6 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue)
        tx_queue->xmit_more_available = false;
        tx_queue->timestamping = (efx_ptp_use_mac_tx_timestamps(efx) &&
                                  tx_queue->channel == efx_ptp_channel(efx));
-       tx_queue->completed_desc_ptr = tx_queue->ptr_mask;
        tx_queue->completed_timestamp_major = 0;
        tx_queue->completed_timestamp_minor = 0;
 
@@ -210,10 +209,9 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
        while (read_ptr != stop_index) {
                struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
 
-               if (!(buffer->flags & EFX_TX_BUF_OPTION) &&
-                   unlikely(buffer->len == 0)) {
+               if (!efx_tx_buffer_in_use(buffer)) {
                        netif_err(efx, tx_err, efx->net_dev,
-                                 "TX queue %d spurious TX completion id %x\n",
+                                 "TX queue %d spurious TX completion id %d\n",
                                  tx_queue->queue, read_ptr);
                        efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
                        return;
@@ -226,6 +224,19 @@ static void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
        }
 }
 
+void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue)
+{
+       if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
+               tx_queue->old_write_count = READ_ONCE(tx_queue->write_count);
+               if (tx_queue->read_count == tx_queue->old_write_count) {
+                       /* Ensure that read_count is flushed. */
+                       smp_mb();
+                       tx_queue->empty_read_count =
+                               tx_queue->read_count | EFX_EMPTY_COUNT_VALID;
+               }
+       }
+}
+
 void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
 {
        unsigned int fill_level, pkts_compl = 0, bytes_compl = 0;
@@ -256,15 +267,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
                        netif_tx_wake_queue(tx_queue->core_txq);
        }
 
-       /* Check whether the hardware queue is now empty */
-       if ((int)(tx_queue->read_count - tx_queue->old_write_count) >= 0) {
-               tx_queue->old_write_count = READ_ONCE(tx_queue->write_count);
-               if (tx_queue->read_count == tx_queue->old_write_count) {
-                       smp_mb();
-                       tx_queue->empty_read_count =
-                               tx_queue->read_count | EFX_EMPTY_COUNT_VALID;
-               }
-       }
+       efx_xmit_done_check_empty(tx_queue);
 }
 
 /* Remove buffers put into a tx_queue for the current packet.
index f92f1fe..99cf7ce 100644 (file)
@@ -21,6 +21,12 @@ void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
                        unsigned int *pkts_compl,
                        unsigned int *bytes_compl);
 
+static inline bool efx_tx_buffer_in_use(struct efx_tx_buffer *buffer)
+{
+       return buffer->len || (buffer->flags & EFX_TX_BUF_OPTION);
+}
+
+void efx_xmit_done_check_empty(struct efx_tx_queue *tx_queue);
 void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
 
 void efx_enqueue_unwind(struct efx_tx_queue *tx_queue,
index dc50ba1..2d5573b 100644 (file)
@@ -1411,7 +1411,7 @@ static int rk_gmac_probe(struct platform_device *pdev)
 
        ret = rk_gmac_clk_init(plat_dat);
        if (ret)
-               return ret;
+               goto err_remove_config_dt;
 
        ret = rk_gmac_powerup(plat_dat->bsp_priv);
        if (ret)
index d0356fb..5427843 100644 (file)
@@ -24,6 +24,7 @@
 static void dwmac1000_core_init(struct mac_device_info *hw,
                                struct net_device *dev)
 {
+       struct stmmac_priv *priv = netdev_priv(dev);
        void __iomem *ioaddr = hw->pcsr;
        u32 value = readl(ioaddr + GMAC_CONTROL);
        int mtu = dev->mtu;
@@ -35,7 +36,7 @@ static void dwmac1000_core_init(struct mac_device_info *hw,
         * Broadcom tags can look like invalid LLC/SNAP packets and cause the
         * hardware to truncate packets on reception.
         */
-       if (netdev_uses_dsa(dev))
+       if (netdev_uses_dsa(dev) || !priv->plat->enh_desc)
                value &= ~GMAC_CONTROL_ACS;
 
        if (mtu > 1500)
index 5836b21..7da18c9 100644 (file)
@@ -4405,6 +4405,8 @@ static void stmmac_init_fs(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
+       rtnl_lock();
+
        /* Create per netdev entries */
        priv->dbgfs_dir = debugfs_create_dir(dev->name, stmmac_fs_dir);
 
@@ -4416,14 +4418,13 @@ static void stmmac_init_fs(struct net_device *dev)
        debugfs_create_file("dma_cap", 0444, priv->dbgfs_dir, dev,
                            &stmmac_dma_cap_fops);
 
-       register_netdevice_notifier(&stmmac_notifier);
+       rtnl_unlock();
 }
 
 static void stmmac_exit_fs(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
 
-       unregister_netdevice_notifier(&stmmac_notifier);
        debugfs_remove_recursive(priv->dbgfs_dir);
 }
 #endif /* CONFIG_DEBUG_FS */
@@ -4940,14 +4941,14 @@ int stmmac_dvr_remove(struct device *dev)
 
        netdev_info(priv->dev, "%s: removing driver", __func__);
 
-#ifdef CONFIG_DEBUG_FS
-       stmmac_exit_fs(ndev);
-#endif
        stmmac_stop_all_dma(priv);
 
        stmmac_mac_set(priv, priv->ioaddr, false);
        netif_carrier_off(ndev);
        unregister_netdev(ndev);
+#ifdef CONFIG_DEBUG_FS
+       stmmac_exit_fs(ndev);
+#endif
        phylink_destroy(priv->phylink);
        if (priv->plat->stmmac_rst)
                reset_control_assert(priv->plat->stmmac_rst);
@@ -5166,6 +5167,7 @@ static int __init stmmac_init(void)
        /* Create debugfs main directory if it doesn't exist yet */
        if (!stmmac_fs_dir)
                stmmac_fs_dir = debugfs_create_dir(STMMAC_RESOURCE_NAME, NULL);
+       register_netdevice_notifier(&stmmac_notifier);
 #endif
 
        return 0;
@@ -5174,6 +5176,7 @@ static int __init stmmac_init(void)
 static void __exit stmmac_exit(void)
 {
 #ifdef CONFIG_DEBUG_FS
+       unregister_netdevice_notifier(&stmmac_notifier);
        debugfs_remove_recursive(stmmac_fs_dir);
 #endif
 }
index d10ac54..13fafd9 100644 (file)
@@ -663,16 +663,22 @@ int stmmac_get_platform_resources(struct platform_device *pdev,
         * In case the wake up interrupt is not passed from the platform
         * so the driver will continue to use the mac irq (ndev->irq)
         */
-       stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
+       stmmac_res->wol_irq =
+               platform_get_irq_byname_optional(pdev, "eth_wake_irq");
        if (stmmac_res->wol_irq < 0) {
                if (stmmac_res->wol_irq == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
+               dev_info(&pdev->dev, "IRQ eth_wake_irq not found\n");
                stmmac_res->wol_irq = stmmac_res->irq;
        }
 
-       stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
-       if (stmmac_res->lpi_irq == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
+       stmmac_res->lpi_irq =
+               platform_get_irq_byname_optional(pdev, "eth_lpi");
+       if (stmmac_res->lpi_irq < 0) {
+               if (stmmac_res->lpi_irq == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+               dev_info(&pdev->dev, "IRQ eth_lpi not found\n");
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);
index 276292b..53fb814 100644 (file)
@@ -375,10 +375,14 @@ struct temac_local {
        int tx_bd_next;
        int tx_bd_tail;
        int rx_bd_ci;
+       int rx_bd_tail;
 
        /* DMA channel control setup */
        u32 tx_chnl_ctrl;
        u32 rx_chnl_ctrl;
+       u8 coalesce_count_rx;
+
+       struct delayed_work restart_work;
 };
 
 /* Wrappers for temac_ior()/temac_iow() function pointers above */
index 6f11f52..9461ace 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/ip.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include <linux/dma-mapping.h>
 #include <linux/processor.h>
 #include <linux/platform_data/xilinx-ll-temac.h>
@@ -367,6 +368,8 @@ static int temac_dma_bd_init(struct net_device *ndev)
                skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
                                              XTE_MAX_JUMBO_FRAME_SIZE,
                                              DMA_FROM_DEVICE);
+               if (dma_mapping_error(ndev->dev.parent, skb_dma_addr))
+                       goto out;
                lp->rx_bd_v[i].phys = cpu_to_be32(skb_dma_addr);
                lp->rx_bd_v[i].len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
                lp->rx_bd_v[i].app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
@@ -387,12 +390,13 @@ static int temac_dma_bd_init(struct net_device *ndev)
        lp->tx_bd_next = 0;
        lp->tx_bd_tail = 0;
        lp->rx_bd_ci = 0;
+       lp->rx_bd_tail = RX_BD_NUM - 1;
 
        /* Enable RX DMA transfers */
        wmb();
        lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
        lp->dma_out(lp, RX_TAILDESC_PTR,
-                      lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+                      lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * lp->rx_bd_tail));
 
        /* Prepare for TX DMA transfer */
        lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
@@ -788,6 +792,9 @@ static void temac_start_xmit_done(struct net_device *ndev)
                stat = be32_to_cpu(cur_p->app0);
        }
 
+       /* Matches barrier in temac_start_xmit */
+       smp_mb();
+
        netif_wake_queue(ndev);
 }
 
@@ -830,9 +837,19 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
 
        if (temac_check_tx_bd_space(lp, num_frag + 1)) {
-               if (!netif_queue_stopped(ndev))
-                       netif_stop_queue(ndev);
-               return NETDEV_TX_BUSY;
+               if (netif_queue_stopped(ndev))
+                       return NETDEV_TX_BUSY;
+
+               netif_stop_queue(ndev);
+
+               /* Matches barrier in temac_start_xmit_done */
+               smp_mb();
+
+               /* Space might have just been freed - check again */
+               if (temac_check_tx_bd_space(lp, num_frag))
+                       return NETDEV_TX_BUSY;
+
+               netif_wake_queue(ndev);
        }
 
        cur_p->app0 = 0;
@@ -850,12 +867,16 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
                                      skb_headlen(skb), DMA_TO_DEVICE);
        cur_p->len = cpu_to_be32(skb_headlen(skb));
+       if (WARN_ON_ONCE(dma_mapping_error(ndev->dev.parent, skb_dma_addr))) {
+               dev_kfree_skb_any(skb);
+               ndev->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
        cur_p->phys = cpu_to_be32(skb_dma_addr);
        ptr_to_txbd((void *)skb, cur_p);
 
        for (ii = 0; ii < num_frag; ii++) {
-               lp->tx_bd_tail++;
-               if (lp->tx_bd_tail >= TX_BD_NUM)
+               if (++lp->tx_bd_tail >= TX_BD_NUM)
                        lp->tx_bd_tail = 0;
 
                cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
@@ -863,6 +884,27 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                              skb_frag_address(frag),
                                              skb_frag_size(frag),
                                              DMA_TO_DEVICE);
+               if (dma_mapping_error(ndev->dev.parent, skb_dma_addr)) {
+                       if (--lp->tx_bd_tail < 0)
+                               lp->tx_bd_tail = TX_BD_NUM - 1;
+                       cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+                       while (--ii >= 0) {
+                               --frag;
+                               dma_unmap_single(ndev->dev.parent,
+                                                be32_to_cpu(cur_p->phys),
+                                                skb_frag_size(frag),
+                                                DMA_TO_DEVICE);
+                               if (--lp->tx_bd_tail < 0)
+                                       lp->tx_bd_tail = TX_BD_NUM - 1;
+                               cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
+                       }
+                       dma_unmap_single(ndev->dev.parent,
+                                        be32_to_cpu(cur_p->phys),
+                                        skb_headlen(skb), DMA_TO_DEVICE);
+                       dev_kfree_skb_any(skb);
+                       ndev->stats.tx_dropped++;
+                       return NETDEV_TX_OK;
+               }
                cur_p->phys = cpu_to_be32(skb_dma_addr);
                cur_p->len = cpu_to_be32(skb_frag_size(frag));
                cur_p->app0 = 0;
@@ -884,31 +926,56 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        return NETDEV_TX_OK;
 }
 
+static int ll_temac_recv_buffers_available(struct temac_local *lp)
+{
+       int available;
+
+       if (!lp->rx_skb[lp->rx_bd_ci])
+               return 0;
+       available = 1 + lp->rx_bd_tail - lp->rx_bd_ci;
+       if (available <= 0)
+               available += RX_BD_NUM;
+       return available;
+}
 
 static void ll_temac_recv(struct net_device *ndev)
 {
        struct temac_local *lp = netdev_priv(ndev);
-       struct sk_buff *skb, *new_skb;
-       unsigned int bdstat;
-       struct cdmac_bd *cur_p;
-       dma_addr_t tail_p, skb_dma_addr;
-       int length;
        unsigned long flags;
+       int rx_bd;
+       bool update_tail = false;
 
        spin_lock_irqsave(&lp->rx_lock, flags);
 
-       tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
-       cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-
-       bdstat = be32_to_cpu(cur_p->app0);
-       while ((bdstat & STS_CTRL_APP0_CMPLT)) {
+       /* Process all received buffers, passing them on network
+        * stack.  After this, the buffer descriptors will be in an
+        * un-allocated stage, where no skb is allocated for it, and
+        * they are therefore not available for TEMAC/DMA.
+        */
+       do {
+               struct cdmac_bd *bd = &lp->rx_bd_v[lp->rx_bd_ci];
+               struct sk_buff *skb = lp->rx_skb[lp->rx_bd_ci];
+               unsigned int bdstat = be32_to_cpu(bd->app0);
+               int length;
+
+               /* While this should not normally happen, we can end
+                * here when GFP_ATOMIC allocations fail, and we
+                * therefore have un-allocated buffers.
+                */
+               if (!skb)
+                       break;
 
-               skb = lp->rx_skb[lp->rx_bd_ci];
-               length = be32_to_cpu(cur_p->app4) & 0x3FFF;
+               /* Loop over all completed buffer descriptors */
+               if (!(bdstat & STS_CTRL_APP0_CMPLT))
+                       break;
 
-               dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+               dma_unmap_single(ndev->dev.parent, be32_to_cpu(bd->phys),
                                 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
+               /* The buffer is not valid for DMA anymore */
+               bd->phys = 0;
+               bd->len = 0;
 
+               length = be32_to_cpu(bd->app4) & 0x3FFF;
                skb_put(skb, length);
                skb->protocol = eth_type_trans(skb, ndev);
                skb_checksum_none_assert(skb);
@@ -923,43 +990,102 @@ static void ll_temac_recv(struct net_device *ndev)
                         * (back) for proper IP checksum byte order
                         * (be16).
                         */
-                       skb->csum = htons(be32_to_cpu(cur_p->app3) & 0xFFFF);
+                       skb->csum = htons(be32_to_cpu(bd->app3) & 0xFFFF);
                        skb->ip_summed = CHECKSUM_COMPLETE;
                }
 
                if (!skb_defer_rx_timestamp(skb))
                        netif_rx(skb);
+               /* The skb buffer is now owned by network stack above */
+               lp->rx_skb[lp->rx_bd_ci] = NULL;
 
                ndev->stats.rx_packets++;
                ndev->stats.rx_bytes += length;
 
-               new_skb = netdev_alloc_skb_ip_align(ndev,
-                                               XTE_MAX_JUMBO_FRAME_SIZE);
-               if (!new_skb) {
-                       spin_unlock_irqrestore(&lp->rx_lock, flags);
-                       return;
+               rx_bd = lp->rx_bd_ci;
+               if (++lp->rx_bd_ci >= RX_BD_NUM)
+                       lp->rx_bd_ci = 0;
+       } while (rx_bd != lp->rx_bd_tail);
+
+       /* DMA operations will halt when the last buffer descriptor is
+        * processed (ie. the one pointed to by RX_TAILDESC_PTR).
+        * When that happens, no more interrupt events will be
+        * generated.  No IRQ_COAL or IRQ_DLY, and not even an
+        * IRQ_ERR.  To avoid stalling, we schedule a delayed work
+        * when there is a potential risk of that happening.  The work
+        * will call this function, and thus re-schedule itself until
+        * enough buffers are available again.
+        */
+       if (ll_temac_recv_buffers_available(lp) < lp->coalesce_count_rx)
+               schedule_delayed_work(&lp->restart_work, HZ / 1000);
+
+       /* Allocate new buffers for those buffer descriptors that were
+        * passed to network stack.  Note that GFP_ATOMIC allocations
+        * can fail (e.g. when a larger burst of GFP_ATOMIC
+        * allocations occurs), so while we try to allocate all
+        * buffers in the same interrupt where they were processed, we
+        * continue with what we could get in case of allocation
+        * failure.  Allocation of remaining buffers will be retried
+        * in following calls.
+        */
+       while (1) {
+               struct sk_buff *skb;
+               struct cdmac_bd *bd;
+               dma_addr_t skb_dma_addr;
+
+               rx_bd = lp->rx_bd_tail + 1;
+               if (rx_bd >= RX_BD_NUM)
+                       rx_bd = 0;
+               bd = &lp->rx_bd_v[rx_bd];
+
+               if (bd->phys)
+                       break;  /* All skb's allocated */
+
+               skb = netdev_alloc_skb_ip_align(ndev, XTE_MAX_JUMBO_FRAME_SIZE);
+               if (!skb) {
+                       dev_warn(&ndev->dev, "skb alloc failed\n");
+                       break;
                }
 
-               cur_p->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
-               skb_dma_addr = dma_map_single(ndev->dev.parent, new_skb->data,
+               skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
                                              XTE_MAX_JUMBO_FRAME_SIZE,
                                              DMA_FROM_DEVICE);
-               cur_p->phys = cpu_to_be32(skb_dma_addr);
-               cur_p->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
-               lp->rx_skb[lp->rx_bd_ci] = new_skb;
+               if (WARN_ON_ONCE(dma_mapping_error(ndev->dev.parent,
+                                                  skb_dma_addr))) {
+                       dev_kfree_skb_any(skb);
+                       break;
+               }
 
-               lp->rx_bd_ci++;
-               if (lp->rx_bd_ci >= RX_BD_NUM)
-                       lp->rx_bd_ci = 0;
+               bd->phys = cpu_to_be32(skb_dma_addr);
+               bd->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
+               bd->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
+               lp->rx_skb[rx_bd] = skb;
 
-               cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-               bdstat = be32_to_cpu(cur_p->app0);
+               lp->rx_bd_tail = rx_bd;
+               update_tail = true;
+       }
+
+       /* Move tail pointer when buffers have been allocated */
+       if (update_tail) {
+               lp->dma_out(lp, RX_TAILDESC_PTR,
+                       lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_tail);
        }
-       lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
 
        spin_unlock_irqrestore(&lp->rx_lock, flags);
 }
 
+/* Function scheduled to ensure a restart in case of DMA halt
+ * condition caused by running out of buffer descriptors.
+ */
+static void ll_temac_restart_work_func(struct work_struct *work)
+{
+       struct temac_local *lp = container_of(work, struct temac_local,
+                                             restart_work.work);
+       struct net_device *ndev = lp->ndev;
+
+       ll_temac_recv(ndev);
+}
+
 static irqreturn_t ll_temac_tx_irq(int irq, void *_ndev)
 {
        struct net_device *ndev = _ndev;
@@ -1052,6 +1178,8 @@ static int temac_stop(struct net_device *ndev)
 
        dev_dbg(&ndev->dev, "temac_close()\n");
 
+       cancel_delayed_work_sync(&lp->restart_work);
+
        free_irq(lp->tx_irq, ndev);
        free_irq(lp->rx_irq, ndev);
 
@@ -1173,6 +1301,7 @@ static int temac_probe(struct platform_device *pdev)
        lp->dev = &pdev->dev;
        lp->options = XTE_OPTION_DEFAULTS;
        spin_lock_init(&lp->rx_lock);
+       INIT_DELAYED_WORK(&lp->restart_work, ll_temac_restart_work_func);
 
        /* Setup mutex for synchronization of indirect register access */
        if (pdata) {
@@ -1279,6 +1408,7 @@ static int temac_probe(struct platform_device *pdev)
                 */
                lp->tx_chnl_ctrl = 0x10220000;
                lp->rx_chnl_ctrl = 0xff070000;
+               lp->coalesce_count_rx = 0x07;
 
                /* Finished with the DMA node; drop the reference */
                of_node_put(dma_np);
@@ -1310,11 +1440,14 @@ static int temac_probe(struct platform_device *pdev)
                                (pdata->tx_irq_count << 16);
                else
                        lp->tx_chnl_ctrl = 0x10220000;
-               if (pdata->rx_irq_timeout || pdata->rx_irq_count)
+               if (pdata->rx_irq_timeout || pdata->rx_irq_count) {
                        lp->rx_chnl_ctrl = (pdata->rx_irq_timeout << 24) |
                                (pdata->rx_irq_count << 16);
-               else
+                       lp->coalesce_count_rx = pdata->rx_irq_count;
+               } else {
                        lp->rx_chnl_ctrl = 0xff070000;
+                       lp->coalesce_count_rx = 0x07;
+               }
        }
 
        /* Error handle returned DMA RX and TX interrupts */
index 75757e9..09f279c 100644 (file)
@@ -1845,8 +1845,6 @@ static void geneve_destroy_tunnels(struct net *net, struct list_head *head)
                if (!net_eq(dev_net(geneve->dev), net))
                        unregister_netdevice_queue(geneve->dev, head);
        }
-
-       WARN_ON_ONCE(!list_empty(&gn->sock_list));
 }
 
 static void __net_exit geneve_exit_batch_net(struct list_head *net_list)
@@ -1861,6 +1859,12 @@ static void __net_exit geneve_exit_batch_net(struct list_head *net_list)
        /* unregister the devices gathered above */
        unregister_netdevice_many(&list);
        rtnl_unlock();
+
+       list_for_each_entry(net, net_list, exit_list) {
+               const struct geneve_net *gn = net_generic(net, geneve_net_id);
+
+               WARN_ON_ONCE(!list_empty(&gn->sock_list));
+       }
 }
 
 static struct pernet_operations geneve_net_ops = {
index ae3f308..1b320bc 100644 (file)
@@ -99,7 +99,7 @@ static struct netvsc_device *alloc_net_device(void)
 
        init_waitqueue_head(&net_device->wait_drain);
        net_device->destroy = false;
-       net_device->tx_disable = false;
+       net_device->tx_disable = true;
 
        net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
        net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
index 65e12cb..2c0a24c 100644 (file)
@@ -1068,6 +1068,7 @@ static int netvsc_attach(struct net_device *ndev,
        }
 
        /* In any case device is now ready */
+       nvdev->tx_disable = false;
        netif_device_attach(ndev);
 
        /* Note: enable and attach happen when sub-channels setup */
@@ -2476,6 +2477,8 @@ static int netvsc_probe(struct hv_device *dev,
        else
                net->max_mtu = ETH_DATA_LEN;
 
+       nvdev->tx_disable = false;
+
        ret = register_netdevice(net);
        if (ret != 0) {
                pr_err("Unable to register netdev.\n");
index 242b9b0..7fe306e 100644 (file)
@@ -75,7 +75,7 @@ static void ifb_ri_tasklet(unsigned long _txp)
        }
 
        while ((skb = __skb_dequeue(&txp->tq)) != NULL) {
-               skb->tc_redirected = 0;
+               skb->redirected = 0;
                skb->tc_skip_classify = 1;
 
                u64_stats_update_begin(&txp->tsync);
@@ -96,7 +96,7 @@ static void ifb_ri_tasklet(unsigned long _txp)
                rcu_read_unlock();
                skb->skb_iif = txp->dev->ifindex;
 
-               if (!skb->tc_from_ingress) {
+               if (!skb->from_ingress) {
                        dev_queue_xmit(skb);
                } else {
                        skb_pull_rcsum(skb, skb->mac_len);
@@ -243,7 +243,7 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)
        txp->rx_bytes += skb->len;
        u64_stats_update_end(&txp->rsync);
 
-       if (!skb->tc_redirected || !skb->skb_iif) {
+       if (!skb->redirected || !skb->skb_iif) {
                dev_kfree_skb(skb);
                dev->stats.rx_dropped++;
                return NETDEV_TX_OK;
index 30cd0c4..8801d09 100644 (file)
@@ -293,6 +293,7 @@ void ipvlan_process_multicast(struct work_struct *work)
                }
                if (dev)
                        dev_put(dev);
+               cond_resched();
        }
 }
 
@@ -498,19 +499,21 @@ static int ipvlan_process_outbound(struct sk_buff *skb)
        struct ethhdr *ethh = eth_hdr(skb);
        int ret = NET_XMIT_DROP;
 
-       /* In this mode we dont care about multicast and broadcast traffic */
-       if (is_multicast_ether_addr(ethh->h_dest)) {
-               pr_debug_ratelimited("Dropped {multi|broad}cast of type=[%x]\n",
-                                    ntohs(skb->protocol));
-               kfree_skb(skb);
-               goto out;
-       }
-
        /* The ipvlan is a pseudo-L2 device, so the packets that we receive
         * will have L2; which need to discarded and processed further
         * in the net-ns of the main-device.
         */
        if (skb_mac_header_was_set(skb)) {
+               /* In this mode we dont care about
+                * multicast and broadcast traffic */
+               if (is_multicast_ether_addr(ethh->h_dest)) {
+                       pr_debug_ratelimited(
+                               "Dropped {multi|broad}cast of type=[%x]\n",
+                               ntohs(skb->protocol));
+                       kfree_skb(skb);
+                       goto out;
+               }
+
                skb_pull(skb, sizeof(*ethh));
                skb->mac_header = (typeof(skb->mac_header))~0U;
                skb_reset_network_header(skb);
index a706622..f195f27 100644 (file)
@@ -164,7 +164,6 @@ static void ipvlan_uninit(struct net_device *dev)
 static int ipvlan_open(struct net_device *dev)
 {
        struct ipvl_dev *ipvlan = netdev_priv(dev);
-       struct net_device *phy_dev = ipvlan->phy_dev;
        struct ipvl_addr *addr;
 
        if (ipvlan->port->mode == IPVLAN_MODE_L3 ||
@@ -178,7 +177,7 @@ static int ipvlan_open(struct net_device *dev)
                ipvlan_ht_addr_add(ipvlan, addr);
        rcu_read_unlock();
 
-       return dev_uc_add(phy_dev, phy_dev->dev_addr);
+       return 0;
 }
 
 static int ipvlan_stop(struct net_device *dev)
@@ -190,8 +189,6 @@ static int ipvlan_stop(struct net_device *dev)
        dev_uc_unsync(phy_dev, dev);
        dev_mc_unsync(phy_dev, dev);
 
-       dev_uc_del(phy_dev, phy_dev->dev_addr);
-
        rcu_read_lock();
        list_for_each_entry_rcu(addr, &ipvlan->addrs, anode)
                ipvlan_ht_addr_del(addr);
index 45bfd99..92bc2b2 100644 (file)
@@ -19,6 +19,7 @@
 #include <net/gro_cells.h>
 #include <net/macsec.h>
 #include <linux/phy.h>
+#include <linux/if_arp.h>
 
 #include <uapi/linux/if_macsec.h>
 
@@ -424,6 +425,11 @@ static struct macsec_eth_header *macsec_ethhdr(struct sk_buff *skb)
        return (struct macsec_eth_header *)skb_mac_header(skb);
 }
 
+static sci_t dev_to_sci(struct net_device *dev, __be16 port)
+{
+       return make_sci(dev->dev_addr, port);
+}
+
 static void __macsec_pn_wrapped(struct macsec_secy *secy,
                                struct macsec_tx_sa *tx_sa)
 {
@@ -3268,6 +3274,20 @@ static int macsec_set_mac_address(struct net_device *dev, void *p)
 
 out:
        ether_addr_copy(dev->dev_addr, addr->sa_data);
+       macsec->secy.sci = dev_to_sci(dev, MACSEC_PORT_ES);
+
+       /* If h/w offloading is available, propagate to the device */
+       if (macsec_is_offloaded(macsec)) {
+               const struct macsec_ops *ops;
+               struct macsec_context ctx;
+
+               ops = macsec_get_ops(macsec, &ctx);
+               if (ops) {
+                       ctx.secy = &macsec->secy;
+                       macsec_offload(ops->mdo_upd_secy, &ctx);
+               }
+       }
+
        return 0;
 }
 
@@ -3342,6 +3362,7 @@ static const struct device_type macsec_type = {
 
 static const struct nla_policy macsec_rtnl_policy[IFLA_MACSEC_MAX + 1] = {
        [IFLA_MACSEC_SCI] = { .type = NLA_U64 },
+       [IFLA_MACSEC_PORT] = { .type = NLA_U16 },
        [IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 },
        [IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 },
        [IFLA_MACSEC_WINDOW] = { .type = NLA_U32 },
@@ -3592,11 +3613,6 @@ static bool sci_exists(struct net_device *dev, sci_t sci)
        return false;
 }
 
-static sci_t dev_to_sci(struct net_device *dev, __be16 port)
-{
-       return make_sci(dev->dev_addr, port);
-}
-
 static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
 {
        struct macsec_dev *macsec = macsec_priv(dev);
@@ -3650,6 +3666,8 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
        real_dev = __dev_get_by_index(net, nla_get_u32(tb[IFLA_LINK]));
        if (!real_dev)
                return -ENODEV;
+       if (real_dev->type != ARPHRD_ETHER)
+               return -EINVAL;
 
        dev->priv_flags |= IFF_MACSEC;
 
index 81aa7ad..e7289d6 100644 (file)
@@ -334,6 +334,8 @@ static void macvlan_process_broadcast(struct work_struct *w)
                if (src)
                        dev_put(src->dev);
                consume_skb(skb);
+
+               cond_resched();
        }
 }
 
index e27fc1a..3811f1b 100644 (file)
@@ -29,9 +29,9 @@ static ssize_t nsim_dbg_netdev_ops_read(struct file *filp,
                return -ENOMEM;
 
        p = buf;
-       p += snprintf(p, bufsize - (p - buf),
-                     "SA count=%u tx=%u\n",
-                     ipsec->count, ipsec->tx);
+       p += scnprintf(p, bufsize - (p - buf),
+                      "SA count=%u tx=%u\n",
+                      ipsec->count, ipsec->tx);
 
        for (i = 0; i < NSIM_IPSEC_MAX_SA_COUNT; i++) {
                struct nsim_sa *sap = &ipsec->sa[i];
@@ -39,18 +39,18 @@ static ssize_t nsim_dbg_netdev_ops_read(struct file *filp,
                if (!sap->used)
                        continue;
 
-               p += snprintf(p, bufsize - (p - buf),
-                             "sa[%i] %cx ipaddr=0x%08x %08x %08x %08x\n",
-                             i, (sap->rx ? 'r' : 't'), sap->ipaddr[0],
-                             sap->ipaddr[1], sap->ipaddr[2], sap->ipaddr[3]);
-               p += snprintf(p, bufsize - (p - buf),
-                             "sa[%i]    spi=0x%08x proto=0x%x salt=0x%08x crypt=%d\n",
-                             i, be32_to_cpu(sap->xs->id.spi),
-                             sap->xs->id.proto, sap->salt, sap->crypt);
-               p += snprintf(p, bufsize - (p - buf),
-                             "sa[%i]    key=0x%08x %08x %08x %08x\n",
-                             i, sap->key[0], sap->key[1],
-                             sap->key[2], sap->key[3]);
+               p += scnprintf(p, bufsize - (p - buf),
+                              "sa[%i] %cx ipaddr=0x%08x %08x %08x %08x\n",
+                              i, (sap->rx ? 'r' : 't'), sap->ipaddr[0],
+                              sap->ipaddr[1], sap->ipaddr[2], sap->ipaddr[3]);
+               p += scnprintf(p, bufsize - (p - buf),
+                              "sa[%i]    spi=0x%08x proto=0x%x salt=0x%08x crypt=%d\n",
+                              i, be32_to_cpu(sap->xs->id.spi),
+                              sap->xs->id.proto, sap->salt, sap->crypt);
+               p += scnprintf(p, bufsize - (p - buf),
+                              "sa[%i]    key=0x%08x %08x %08x %08x\n",
+                              i, sap->key[0], sap->key[1],
+                              sap->key[2], sap->key[3]);
        }
 
        len = simple_read_from_buffer(buffer, count, ppos, buf, p - buf);
index 23f1958..459fb20 100644 (file)
@@ -73,6 +73,7 @@ static struct phy_driver bcm63xx_driver[] = {
        /* same phy as above, with just a different OUI */
        .phy_id         = 0x002bdc00,
        .phy_id_mask    = 0xfffffc00,
+       .name           = "Broadcom BCM63XX (2)",
        /* PHY_BASIC_FEATURES */
        .flags          = PHY_IS_INTERNAL,
        .config_init    = bcm63xx_config_init,
index 967f57e..9a07ad1 100644 (file)
@@ -28,7 +28,8 @@
 #define DP83867_CTRL           0x1f
 
 /* Extended Registers */
-#define DP83867_CFG4            0x0031
+#define DP83867_FLD_THR_CFG    0x002e
+#define DP83867_CFG4           0x0031
 #define DP83867_CFG4_SGMII_ANEG_MASK (BIT(5) | BIT(6))
 #define DP83867_CFG4_SGMII_ANEG_TIMER_11MS   (3 << 5)
 #define DP83867_CFG4_SGMII_ANEG_TIMER_800US  (2 << 5)
@@ -91,6 +92,7 @@
 #define DP83867_STRAP_STS2_CLK_SKEW_RX_MASK    GENMASK(2, 0)
 #define DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT   0
 #define DP83867_STRAP_STS2_CLK_SKEW_NONE       BIT(2)
+#define DP83867_STRAP_STS2_STRAP_FLD           BIT(10)
 
 /* PHY CTRL bits */
 #define DP83867_PHYCR_TX_FIFO_DEPTH_SHIFT      14
 /* CFG4 bits */
 #define DP83867_CFG4_PORT_MIRROR_EN              BIT(0)
 
+/* FLD_THR_CFG */
+#define DP83867_FLD_THR_CFG_ENERGY_LOST_THR_MASK       0x7
+
 enum {
        DP83867_PORT_MIRROING_KEEP,
        DP83867_PORT_MIRROING_EN,
@@ -476,6 +481,20 @@ static int dp83867_config_init(struct phy_device *phydev)
                phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
                                   BIT(7));
 
+       bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS2);
+       if (bs & DP83867_STRAP_STS2_STRAP_FLD) {
+               /* When using strap to enable FLD, the ENERGY_LOST_FLD_THR will
+                * be set to 0x2. This may causes the PHY link to be unstable -
+                * the default value 0x1 need to be restored.
+                */
+               ret = phy_modify_mmd(phydev, DP83867_DEVADDR,
+                                    DP83867_FLD_THR_CFG,
+                                    DP83867_FLD_THR_CFG_ENERGY_LOST_THR_MASK,
+                                    0x1);
+               if (ret)
+                       return ret;
+       }
+
        if (phy_interface_is_rgmii(phydev) ||
            phydev->interface == PHY_INTERFACE_MODE_SGMII) {
                val = phy_read(phydev, MII_DP83867_PHYCTRL);
index 28e33ec..9a8bada 100644 (file)
@@ -1306,6 +1306,9 @@ static int marvell_read_status_page_an(struct phy_device *phydev,
                }
        }
 
+       if (!(status & MII_M1011_PHY_STATUS_RESOLVED))
+               return 0;
+
        if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
                phydev->duplex = DUPLEX_FULL;
        else
@@ -1365,6 +1368,8 @@ static int marvell_read_status_page(struct phy_device *phydev, int page)
        linkmode_zero(phydev->lp_advertising);
        phydev->pause = 0;
        phydev->asym_pause = 0;
+       phydev->speed = SPEED_UNKNOWN;
+       phydev->duplex = DUPLEX_UNKNOWN;
 
        if (phydev->autoneg == AUTONEG_ENABLE)
                err = marvell_read_status_page_an(phydev, fiber, status);
index 4a28fb2..fbd3689 100644 (file)
@@ -242,11 +242,9 @@ static int unimac_mdio_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       priv->clk = devm_clk_get(&pdev->dev, NULL);
-       if (PTR_ERR(priv->clk) == -EPROBE_DEFER)
+       priv->clk = devm_clk_get_optional(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk))
                return PTR_ERR(priv->clk);
-       else
-               priv->clk = NULL;
 
        ret = clk_prepare_enable(priv->clk);
        if (ret)
index 88d409e..aad6809 100644 (file)
@@ -288,8 +288,13 @@ static int mdio_mux_iproc_suspend(struct device *dev)
 static int mdio_mux_iproc_resume(struct device *dev)
 {
        struct iproc_mdiomux_desc *md = dev_get_drvdata(dev);
+       int rc;
 
-       clk_prepare_enable(md->core_clk);
+       rc = clk_prepare_enable(md->core_clk);
+       if (rc) {
+               dev_err(md->dev, "failed to enable core clk\n");
+               return rc;
+       }
        mdio_mux_iproc_config(md);
 
        return 0;
index 937ac7d..f686f40 100644 (file)
@@ -345,11 +345,11 @@ enum macsec_bank {
                                BIT(VSC8531_FORCE_LED_OFF) | \
                                BIT(VSC8531_FORCE_LED_ON))
 
-#define MSCC_VSC8584_REVB_INT8051_FW           "mscc_vsc8584_revb_int8051_fb48.bin"
+#define MSCC_VSC8584_REVB_INT8051_FW           "microchip/mscc_vsc8584_revb_int8051_fb48.bin"
 #define MSCC_VSC8584_REVB_INT8051_FW_START_ADDR        0xe800
 #define MSCC_VSC8584_REVB_INT8051_FW_CRC       0xfb48
 
-#define MSCC_VSC8574_REVB_INT8051_FW           "mscc_vsc8574_revb_int8051_29e8.bin"
+#define MSCC_VSC8574_REVB_INT8051_FW           "microchip/mscc_vsc8574_revb_int8051_29e8.bin"
 #define MSCC_VSC8574_REVB_INT8051_FW_START_ADDR        0x4000
 #define MSCC_VSC8574_REVB_INT8051_FW_CRC       0x29e8
 
index a1caeee..dd2e23f 100644 (file)
@@ -167,7 +167,7 @@ EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
  */
 int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
 {
-       int ret = 0;
+       int ret;
 
        if (!restart) {
                /* Configure and restart aneg if it wasn't set before */
@@ -180,9 +180,9 @@ int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
        }
 
        if (restart)
-               ret = genphy_c45_restart_aneg(phydev);
+               return genphy_c45_restart_aneg(phydev);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
 
index d76e038..355bfde 100644 (file)
@@ -727,7 +727,8 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
                phy_trigger_machine(phydev);
        }
 
-       if (phy_clear_interrupt(phydev))
+       /* did_interrupt() may have cleared the interrupt already */
+       if (!phydev->drv->did_interrupt && phy_clear_interrupt(phydev))
                goto phy_err;
        return IRQ_HANDLED;
 
index 6a5056e..28e3c5c 100644 (file)
@@ -247,7 +247,7 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
         * MDIO bus driver and clock gated at this point.
         */
        if (!netdev)
-               return !phydev->suspended;
+               goto out;
 
        if (netdev->wol_enabled)
                return false;
@@ -267,7 +267,8 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
        if (device_may_wakeup(&netdev->dev))
                return false;
 
-       return true;
+out:
+       return !phydev->suspended;
 }
 
 static int mdio_bus_phy_suspend(struct device *dev)
@@ -285,6 +286,8 @@ static int mdio_bus_phy_suspend(struct device *dev)
        if (!mdio_bus_phy_may_suspend(phydev))
                return 0;
 
+       phydev->suspended_by_mdio_bus = 1;
+
        return phy_suspend(phydev);
 }
 
@@ -293,9 +296,11 @@ static int mdio_bus_phy_resume(struct device *dev)
        struct phy_device *phydev = to_phy_device(dev);
        int ret;
 
-       if (!mdio_bus_phy_may_suspend(phydev))
+       if (!phydev->suspended_by_mdio_bus)
                goto no_resume;
 
+       phydev->suspended_by_mdio_bus = 0;
+
        ret = phy_resume(phydev);
        if (ret < 0)
                return ret;
@@ -1792,7 +1797,7 @@ EXPORT_SYMBOL(genphy_restart_aneg);
  */
 int genphy_check_and_restart_aneg(struct phy_device *phydev, bool restart)
 {
-       int ret = 0;
+       int ret;
 
        if (!restart) {
                /* Advertisement hasn't changed, but maybe aneg was never on to
@@ -1807,9 +1812,9 @@ int genphy_check_and_restart_aneg(struct phy_device *phydev, bool restart)
        }
 
        if (restart)
-               ret = genphy_restart_aneg(phydev);
+               return genphy_restart_aneg(phydev);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(genphy_check_and_restart_aneg);
 
index 70b9a14..6e66b8e 100644 (file)
@@ -761,8 +761,14 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
                config.interface = interface;
 
        ret = phylink_validate(pl, supported, &config);
-       if (ret)
+       if (ret) {
+               phylink_warn(pl, "validation of %s with support %*pb and advertisement %*pb failed: %d\n",
+                            phy_modes(config.interface),
+                            __ETHTOOL_LINK_MODE_MASK_NBITS, phy->supported,
+                            __ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising,
+                            ret);
                return ret;
+       }
 
        phy->phylink = pl;
        phy->phy_link_change = phylink_phy_change;
index d949ea7..6900c68 100644 (file)
@@ -572,13 +572,15 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
  * the sfp_bus structure, incrementing its reference count.  This must
  * be put via sfp_bus_put() when done.
  *
- * Returns: on success, a pointer to the sfp_bus structure,
- *         %NULL if no SFP is specified,
- *         on failure, an error pointer value:
- *             corresponding to the errors detailed for
- *             fwnode_property_get_reference_args().
- *             %-ENOMEM if we failed to allocate the bus.
- *             an error from the upstream's connect_phy() method.
+ * Returns:
+ *         - on success, a pointer to the sfp_bus structure,
+ *         - %NULL if no SFP is specified,
+ *         - on failure, an error pointer value:
+ *
+ *           - corresponding to the errors detailed for
+ *             fwnode_property_get_reference_args().
+ *           - %-ENOMEM if we failed to allocate the bus.
+ *           - an error from the upstream's connect_phy() method.
  */
 struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
 {
@@ -612,13 +614,15 @@ EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode);
  * the SFP bus using sfp_register_upstream().  This takes a reference on the
  * bus, so it is safe to put the bus after this call.
  *
- * Returns: on success, a pointer to the sfp_bus structure,
- *         %NULL if no SFP is specified,
- *         on failure, an error pointer value:
- *             corresponding to the errors detailed for
- *             fwnode_property_get_reference_args().
- *             %-ENOMEM if we failed to allocate the bus.
- *             an error from the upstream's connect_phy() method.
+ * Returns:
+ *         - on success, a pointer to the sfp_bus structure,
+ *         - %NULL if no SFP is specified,
+ *         - on failure, an error pointer value:
+ *
+ *           - corresponding to the errors detailed for
+ *             fwnode_property_get_reference_args().
+ *           - %-ENOMEM if we failed to allocate the bus.
+ *           - an error from the upstream's connect_phy() method.
  */
 int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
                         const struct sfp_upstream_ops *ops)
index 58a69f8..f78ceba 100644 (file)
@@ -232,7 +232,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
        struct cstate *cs = lcs->next;
        unsigned long deltaS, deltaA;
        short changes = 0;
-       int hlen;
+       int nlen, hlen;
        unsigned char new_seq[16];
        unsigned char *cp = new_seq;
        struct iphdr *ip;
@@ -248,6 +248,8 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
                return isize;
 
        ip = (struct iphdr *) icp;
+       if (ip->version != 4 || ip->ihl < 5)
+               return isize;
 
        /* Bail if this packet isn't TCP, or is an IP fragment */
        if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
@@ -258,10 +260,14 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
                        comp->sls_o_tcp++;
                return isize;
        }
-       /* Extract TCP header */
+       nlen = ip->ihl * 4;
+       if (isize < nlen + sizeof(*th))
+               return isize;
 
-       th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
-       hlen = ip->ihl*4 + th->doff*4;
+       th = (struct tcphdr *)(icp + nlen);
+       if (th->doff < sizeof(struct tcphdr) / 4)
+               return isize;
+       hlen = nlen + th->doff * 4;
 
        /*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
         *  some other control bit is set). Also uncompressible if
index 6f4d7ba..babb018 100644 (file)
@@ -863,7 +863,10 @@ err_free_chan:
        tty->disc_data = NULL;
        clear_bit(SLF_INUSE, &sl->flags);
        sl_free_netdev(sl->dev);
+       /* do not call free_netdev before rtnl_unlock */
+       rtnl_unlock();
        free_netdev(sl->dev);
+       return err;
 
 err_exit:
        rtnl_unlock();
index ca70a1d..4004f98 100644 (file)
@@ -2240,6 +2240,8 @@ team_nl_option_policy[TEAM_ATTR_OPTION_MAX + 1] = {
        [TEAM_ATTR_OPTION_CHANGED]              = { .type = NLA_FLAG },
        [TEAM_ATTR_OPTION_TYPE]                 = { .type = NLA_U8 },
        [TEAM_ATTR_OPTION_DATA]                 = { .type = NLA_BINARY },
+       [TEAM_ATTR_OPTION_PORT_IFINDEX]         = { .type = NLA_U32 },
+       [TEAM_ATTR_OPTION_ARRAY_INDEX]          = { .type = NLA_U32 },
 };
 
 static int team_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info)
index 3b7a3b8..6c738a2 100644 (file)
@@ -337,6 +337,9 @@ static void qmi_wwan_netdev_setup(struct net_device *net)
                netdev_dbg(net, "mode: raw IP\n");
        } else if (!net->header_ops) { /* don't bother if already set */
                ether_setup(net);
+               /* Restoring min/max mtu values set originally by usbnet */
+               net->min_mtu = 0;
+               net->max_mtu = ETH_MAX_MTU;
                clear_bit(EVENT_NO_IP_ALIGN, &dev->flags);
                netdev_dbg(net, "mode: Ethernet\n");
        }
@@ -1207,6 +1210,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1435, 0xd182, 5)},    /* Wistron NeWeb D18 */
        {QMI_FIXED_INTF(0x1435, 0xd191, 4)},    /* Wistron NeWeb D19Q1 */
        {QMI_QUIRK_SET_DTR(0x1508, 0x1001, 4)}, /* Fibocom NL668 series */
+       {QMI_FIXED_INTF(0x1690, 0x7588, 4)},    /* ASKEY WWHC050 */
        {QMI_FIXED_INTF(0x16d8, 0x6003, 0)},    /* CMOTech 6003 */
        {QMI_FIXED_INTF(0x16d8, 0x6007, 0)},    /* CMOTech CHE-628S */
        {QMI_FIXED_INTF(0x16d8, 0x6008, 0)},    /* CMOTech CMU-301 */
index 78ddbaf..95b19ce 100644 (file)
@@ -3221,6 +3221,8 @@ static u16 r8153_phy_status(struct r8152 *tp, u16 desired)
                }
 
                msleep(20);
+               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+                       break;
        }
 
        return data;
@@ -5402,7 +5404,10 @@ static void r8153_init(struct r8152 *tp)
                if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
                    AUTOLOAD_DONE)
                        break;
+
                msleep(20);
+               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+                       break;
        }
 
        data = r8153_phy_status(tp, 0);
@@ -5539,7 +5544,10 @@ static void r8153b_init(struct r8152 *tp)
                if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
                    AUTOLOAD_DONE)
                        break;
+
                msleep(20);
+               if (test_bit(RTL8152_UNPLUG, &tp->flags))
+                       break;
        }
 
        data = r8153_phy_status(tp, 0);
index 8cdc441..d4cbb9e 100644 (file)
@@ -328,7 +328,7 @@ static void veth_get_stats64(struct net_device *dev,
        rcu_read_lock();
        peer = rcu_dereference(priv->peer);
        if (peer) {
-               tot->rx_dropped += veth_stats_tx(peer, &packets, &bytes);
+               veth_stats_tx(peer, &packets, &bytes);
                tot->rx_bytes += bytes;
                tot->rx_packets += packets;
 
index d3b08b7..45308b3 100644 (file)
@@ -2779,10 +2779,19 @@ static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan,
 /* Setup stats when device is created */
 static int vxlan_init(struct net_device *dev)
 {
+       struct vxlan_dev *vxlan = netdev_priv(dev);
+       int err;
+
        dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
 
+       err = gro_cells_init(&vxlan->gro_cells, dev);
+       if (err) {
+               free_percpu(dev->tstats);
+               return err;
+       }
+
        return 0;
 }
 
@@ -3043,8 +3052,6 @@ static void vxlan_setup(struct net_device *dev)
 
        vxlan->dev = dev;
 
-       gro_cells_init(&vxlan->gro_cells, dev);
-
        for (h = 0; h < FDB_HASH_SIZE; ++h) {
                spin_lock_init(&vxlan->hash_lock[h]);
                INIT_HLIST_HEAD(&vxlan->fdb_head[h]);
index cdc9696..3ac3f85 100644 (file)
@@ -122,7 +122,7 @@ static netdev_tx_t wg_xmit(struct sk_buff *skb, struct net_device *dev)
        u32 mtu;
        int ret;
 
-       if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol)) {
+       if (unlikely(!wg_check_packet_protocol(skb))) {
                ret = -EPROTONOSUPPORT;
                net_dbg_ratelimited("%s: Invalid IP packet\n", dev->name);
                goto err;
index bda2640..802099c 100644 (file)
@@ -411,11 +411,7 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs)
 
                peer = wg_peer_create(wg, public_key, preshared_key);
                if (IS_ERR(peer)) {
-                       /* Similar to the above, if the key is invalid, we skip
-                        * it without fanfare, so that services don't need to
-                        * worry about doing key validation themselves.
-                        */
-                       ret = PTR_ERR(peer) == -EKEYREJECTED ? 0 : PTR_ERR(peer);
+                       ret = PTR_ERR(peer);
                        peer = NULL;
                        goto out;
                }
@@ -569,7 +565,7 @@ static int wg_set_device(struct sk_buff *skb, struct genl_info *info)
                                                         private_key);
                list_for_each_entry_safe(peer, temp, &wg->peer_list,
                                         peer_list) {
-                       BUG_ON(!wg_noise_precompute_static_static(peer));
+                       wg_noise_precompute_static_static(peer);
                        wg_noise_expire_current_peer_keypairs(peer);
                }
                wg_cookie_checker_precompute_device_keys(&wg->cookie_checker);
index 919d9d8..708dc61 100644 (file)
@@ -44,32 +44,23 @@ void __init wg_noise_init(void)
 }
 
 /* Must hold peer->handshake.static_identity->lock */
-bool wg_noise_precompute_static_static(struct wg_peer *peer)
+void wg_noise_precompute_static_static(struct wg_peer *peer)
 {
-       bool ret;
-
        down_write(&peer->handshake.lock);
-       if (peer->handshake.static_identity->has_identity) {
-               ret = curve25519(
-                       peer->handshake.precomputed_static_static,
+       if (!peer->handshake.static_identity->has_identity ||
+           !curve25519(peer->handshake.precomputed_static_static,
                        peer->handshake.static_identity->static_private,
-                       peer->handshake.remote_static);
-       } else {
-               u8 empty[NOISE_PUBLIC_KEY_LEN] = { 0 };
-
-               ret = curve25519(empty, empty, peer->handshake.remote_static);
+                       peer->handshake.remote_static))
                memset(peer->handshake.precomputed_static_static, 0,
                       NOISE_PUBLIC_KEY_LEN);
-       }
        up_write(&peer->handshake.lock);
-       return ret;
 }
 
-bool wg_noise_handshake_init(struct noise_handshake *handshake,
-                          struct noise_static_identity *static_identity,
-                          const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
-                          const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
-                          struct wg_peer *peer)
+void wg_noise_handshake_init(struct noise_handshake *handshake,
+                            struct noise_static_identity *static_identity,
+                            const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
+                            const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
+                            struct wg_peer *peer)
 {
        memset(handshake, 0, sizeof(*handshake));
        init_rwsem(&handshake->lock);
@@ -81,7 +72,7 @@ bool wg_noise_handshake_init(struct noise_handshake *handshake,
                       NOISE_SYMMETRIC_KEY_LEN);
        handshake->static_identity = static_identity;
        handshake->state = HANDSHAKE_ZEROED;
-       return wg_noise_precompute_static_static(peer);
+       wg_noise_precompute_static_static(peer);
 }
 
 static void handshake_zero(struct noise_handshake *handshake)
@@ -403,6 +394,19 @@ static bool __must_check mix_dh(u8 chaining_key[NOISE_HASH_LEN],
        return true;
 }
 
+static bool __must_check mix_precomputed_dh(u8 chaining_key[NOISE_HASH_LEN],
+                                           u8 key[NOISE_SYMMETRIC_KEY_LEN],
+                                           const u8 precomputed[NOISE_PUBLIC_KEY_LEN])
+{
+       static u8 zero_point[NOISE_PUBLIC_KEY_LEN];
+       if (unlikely(!crypto_memneq(precomputed, zero_point, NOISE_PUBLIC_KEY_LEN)))
+               return false;
+       kdf(chaining_key, key, NULL, precomputed, NOISE_HASH_LEN,
+           NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
+           chaining_key);
+       return true;
+}
+
 static void mix_hash(u8 hash[NOISE_HASH_LEN], const u8 *src, size_t src_len)
 {
        struct blake2s_state blake;
@@ -531,10 +535,9 @@ wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
                        NOISE_PUBLIC_KEY_LEN, key, handshake->hash);
 
        /* ss */
-       kdf(handshake->chaining_key, key, NULL,
-           handshake->precomputed_static_static, NOISE_HASH_LEN,
-           NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
-           handshake->chaining_key);
+       if (!mix_precomputed_dh(handshake->chaining_key, key,
+                               handshake->precomputed_static_static))
+               goto out;
 
        /* {t} */
        tai64n_now(timestamp);
@@ -595,9 +598,9 @@ wg_noise_handshake_consume_initiation(struct message_handshake_initiation *src,
        handshake = &peer->handshake;
 
        /* ss */
-       kdf(chaining_key, key, NULL, handshake->precomputed_static_static,
-           NOISE_HASH_LEN, NOISE_SYMMETRIC_KEY_LEN, 0, NOISE_PUBLIC_KEY_LEN,
-           chaining_key);
+       if (!mix_precomputed_dh(chaining_key, key,
+                               handshake->precomputed_static_static))
+           goto out;
 
        /* {t} */
        if (!message_decrypt(t, src->encrypted_timestamp,
index 138a07b..f532d59 100644 (file)
@@ -94,11 +94,11 @@ struct noise_handshake {
 struct wg_device;
 
 void wg_noise_init(void);
-bool wg_noise_handshake_init(struct noise_handshake *handshake,
-                          struct noise_static_identity *static_identity,
-                          const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
-                          const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
-                          struct wg_peer *peer);
+void wg_noise_handshake_init(struct noise_handshake *handshake,
+                            struct noise_static_identity *static_identity,
+                            const u8 peer_public_key[NOISE_PUBLIC_KEY_LEN],
+                            const u8 peer_preshared_key[NOISE_SYMMETRIC_KEY_LEN],
+                            struct wg_peer *peer);
 void wg_noise_handshake_clear(struct noise_handshake *handshake);
 static inline void wg_noise_reset_last_sent_handshake(atomic64_t *handshake_ns)
 {
@@ -116,7 +116,7 @@ void wg_noise_expire_current_peer_keypairs(struct wg_peer *peer);
 void wg_noise_set_static_identity_private_key(
        struct noise_static_identity *static_identity,
        const u8 private_key[NOISE_PUBLIC_KEY_LEN]);
-bool wg_noise_precompute_static_static(struct wg_peer *peer);
+void wg_noise_precompute_static_static(struct wg_peer *peer);
 
 bool
 wg_noise_handshake_create_initiation(struct message_handshake_initiation *dst,
index 071eedf..1d634bd 100644 (file)
@@ -34,11 +34,8 @@ struct wg_peer *wg_peer_create(struct wg_device *wg,
                return ERR_PTR(ret);
        peer->device = wg;
 
-       if (!wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
-                                    public_key, preshared_key, peer)) {
-               ret = -EKEYREJECTED;
-               goto err_1;
-       }
+       wg_noise_handshake_init(&peer->handshake, &wg->static_identity,
+                               public_key, preshared_key, peer);
        if (dst_cache_init(&peer->endpoint_cache, GFP_KERNEL))
                goto err_1;
        if (wg_packet_queue_init(&peer->tx_queue, wg_packet_tx_worker, false,
index fecb559..3432232 100644 (file)
@@ -66,7 +66,7 @@ struct packet_cb {
 #define PACKET_PEER(skb) (PACKET_CB(skb)->keypair->entry.peer)
 
 /* Returns either the correct skb->protocol value, or 0 if invalid. */
-static inline __be16 wg_skb_examine_untrusted_ip_hdr(struct sk_buff *skb)
+static inline __be16 wg_examine_packet_protocol(struct sk_buff *skb)
 {
        if (skb_network_header(skb) >= skb->head &&
            (skb_network_header(skb) + sizeof(struct iphdr)) <=
@@ -81,6 +81,12 @@ static inline __be16 wg_skb_examine_untrusted_ip_hdr(struct sk_buff *skb)
        return 0;
 }
 
+static inline bool wg_check_packet_protocol(struct sk_buff *skb)
+{
+       __be16 real_protocol = wg_examine_packet_protocol(skb);
+       return real_protocol && skb->protocol == real_protocol;
+}
+
 static inline void wg_reset_packet(struct sk_buff *skb)
 {
        skb_scrub_packet(skb, true);
@@ -94,8 +100,8 @@ static inline void wg_reset_packet(struct sk_buff *skb)
        skb->dev = NULL;
 #ifdef CONFIG_NET_SCHED
        skb->tc_index = 0;
-       skb_reset_tc(skb);
 #endif
+       skb_reset_redirect(skb);
        skb->hdr_len = skb_headroom(skb);
        skb_reset_mac_header(skb);
        skb_reset_network_header(skb);
index 4a15389..da3b782 100644 (file)
@@ -56,7 +56,7 @@ static int prepare_skb_header(struct sk_buff *skb, struct wg_device *wg)
        size_t data_offset, data_len, header_len;
        struct udphdr *udp;
 
-       if (unlikely(wg_skb_examine_untrusted_ip_hdr(skb) != skb->protocol ||
+       if (unlikely(!wg_check_packet_protocol(skb) ||
                     skb_transport_header(skb) < skb->head ||
                     (skb_transport_header(skb) + sizeof(struct udphdr)) >
                             skb_tail_pointer(skb)))
@@ -388,7 +388,7 @@ static void wg_packet_consume_data_done(struct wg_peer *peer,
         */
        skb->ip_summed = CHECKSUM_UNNECESSARY;
        skb->csum_level = ~0; /* All levels */
-       skb->protocol = wg_skb_examine_untrusted_ip_hdr(skb);
+       skb->protocol = wg_examine_packet_protocol(skb);
        if (skb->protocol == htons(ETH_P_IP)) {
                len = ntohs(ip_hdr(skb)->tot_len);
                if (unlikely(len < sizeof(struct iphdr)))
@@ -587,8 +587,7 @@ void wg_packet_receive(struct wg_device *wg, struct sk_buff *skb)
                wg_packet_consume_data(wg, skb);
                break;
        default:
-               net_dbg_skb_ratelimited("%s: Invalid packet from %pISpfsc\n",
-                                       wg->dev->name, skb);
+               WARN(1, "Non-exhaustive parsing of packet header lead to unknown packet type!\n");
                goto err;
        }
        return;
index 5ec16ce..a202a4e 100644 (file)
@@ -1052,11 +1052,11 @@ static int ath10k_download_fw(struct ath10k *ar)
        }
 
        memset(&latency_qos, 0, sizeof(latency_qos));
-       pm_qos_add_request(&latency_qos, PM_QOS_CPU_DMA_LATENCY, 0);
+       cpu_latency_qos_add_request(&latency_qos, 0);
 
        ret = ath10k_bmi_fast_download(ar, address, data, data_len);
 
-       pm_qos_remove_request(&latency_qos);
+       cpu_latency_qos_remove_request(&latency_qos);
 
        return ret;
 }
index 536cd72..5dfcce7 100644 (file)
@@ -1730,7 +1730,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
        /* the ipw2100 hardware really doesn't want power management delays
         * longer than 175usec
         */
-       pm_qos_update_request(&ipw2100_pm_qos_req, 175);
+       cpu_latency_qos_update_request(&ipw2100_pm_qos_req, 175);
 
        /* If the interrupt is enabled, turn it off... */
        spin_lock_irqsave(&priv->low_lock, flags);
@@ -1875,7 +1875,8 @@ static void ipw2100_down(struct ipw2100_priv *priv)
        ipw2100_disable_interrupts(priv);
        spin_unlock_irqrestore(&priv->low_lock, flags);
 
-       pm_qos_update_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_update_request(&ipw2100_pm_qos_req,
+                                      PM_QOS_DEFAULT_VALUE);
 
        /* We have to signal any supplicant if we are disassociating */
        if (associated)
@@ -6566,8 +6567,7 @@ static int __init ipw2100_init(void)
        printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
        printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
 
-       pm_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
-                          PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
 
        ret = pci_register_driver(&ipw2100_pci_driver);
        if (ret)
@@ -6594,7 +6594,7 @@ static void __exit ipw2100_exit(void)
                           &driver_attr_debug_level);
 #endif
        pci_unregister_driver(&ipw2100_pci_driver);
-       pm_qos_remove_request(&ipw2100_pm_qos_req);
+       cpu_latency_qos_remove_request(&ipw2100_pm_qos_req);
 }
 
 module_init(ipw2100_init);
index a22a830..355af47 100644 (file)
@@ -283,6 +283,7 @@ const struct iwl_cfg iwl_ax101_cfg_qu_c0_hr_b0 = {
         * HT size; mac80211 would otherwise pick the HE max (256) by default.
         */
        .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+       .tx_with_siso_diversity = true,
        .num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
@@ -309,6 +310,7 @@ const struct iwl_cfg iwl_ax101_cfg_quz_hr = {
         * HT size; mac80211 would otherwise pick the HE max (256) by default.
         */
        .max_tx_agg_size = IEEE80211_MAX_AMPDU_BUF_HT,
+       .tx_with_siso_diversity = true,
        .num_rbds = IWL_NUM_RBDS_22000_HE,
 };
 
index 48d375a..ba2aff3 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2017        Intel Deutschland GmbH
- * Copyright (C) 2019 Intel Corporation
+ * Copyright (C) 2019 - 2020 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -27,7 +27,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2017        Intel Deutschland GmbH
- * Copyright (C) 2019 Intel Corporation
+ * Copyright (C) 2019 - 2020 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -491,13 +491,13 @@ int iwl_validate_sar_geo_profile(struct iwl_fw_runtime *fwrt,
 }
 IWL_EXPORT_SYMBOL(iwl_validate_sar_geo_profile);
 
-void iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
-                     struct iwl_per_chain_offset_group *table)
+int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
+                    struct iwl_per_chain_offset_group *table)
 {
        int ret, i, j;
 
        if (!iwl_sar_geo_support(fwrt))
-               return;
+               return -EOPNOTSUPP;
 
        ret = iwl_sar_get_wgds_table(fwrt);
        if (ret < 0) {
@@ -505,7 +505,7 @@ void iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
                                "Geo SAR BIOS table invalid or unavailable. (%d)\n",
                                ret);
                /* we don't fail if the table is not available */
-               return;
+               return -ENOENT;
        }
 
        BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES * ACPI_WGDS_NUM_BANDS *
@@ -530,5 +530,7 @@ void iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
                                        i, j, value[1], value[2], value[0]);
                }
        }
+
+       return 0;
 }
 IWL_EXPORT_SYMBOL(iwl_sar_geo_init);
index 4a6e826..5590e5c 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2017        Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019        Intel Corporation
+ * Copyright(c) 2018 - 2020        Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -27,7 +27,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2017        Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019       Intel Corporation
+ * Copyright(c) 2018 - 2020       Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -171,8 +171,9 @@ bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt);
 int iwl_validate_sar_geo_profile(struct iwl_fw_runtime *fwrt,
                                 struct iwl_host_cmd *cmd);
 
-void iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
-                     struct iwl_per_chain_offset_group *table);
+int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
+                    struct iwl_per_chain_offset_group *table);
+
 #else /* CONFIG_ACPI */
 
 static inline void *iwl_acpi_get_object(struct device *dev, acpi_string method)
@@ -243,9 +244,10 @@ static inline int iwl_validate_sar_geo_profile(struct iwl_fw_runtime *fwrt,
        return -ENOENT;
 }
 
-static inline void iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
-                                   struct iwl_per_chain_offset_group *table)
+static inline int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
+                                  struct iwl_per_chain_offset_group *table)
 {
+       return -ENOENT;
 }
 
 #endif /* CONFIG_ACPI */
index 91df1ee..8796ab8 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
+ * Copyright(c) 2018 - 2020 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
+ * Copyright(c) 2018 - 2020 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1409,11 +1409,7 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt,
                goto out;
        }
 
-       /*
-        * region register have absolute value so apply rxf offset after
-        * reading the registers
-        */
-       offs += rxf_data.offset;
+       offs = rxf_data.offset;
 
        /* Lock fence */
        iwl_write_prph_no_grab(fwrt->trans, RXF_SET_FENCE_MODE + offs, 0x1);
@@ -2494,10 +2490,7 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx)
                goto out;
        }
 
-       if (iwl_fw_dbg_stop_restart_recording(fwrt, &params, true)) {
-               IWL_ERR(fwrt, "Failed to stop DBGC recording, aborting dump\n");
-               goto out;
-       }
+       iwl_fw_dbg_stop_restart_recording(fwrt, &params, true);
 
        IWL_DEBUG_FW_INFO(fwrt, "WRT: Data collection start\n");
        if (iwl_trans_dbg_ini_valid(fwrt->trans))
@@ -2662,14 +2655,14 @@ static int iwl_fw_dbg_restart_recording(struct iwl_trans *trans,
        return 0;
 }
 
-int iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
-                                     struct iwl_fw_dbg_params *params,
-                                     bool stop)
+void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
+                                      struct iwl_fw_dbg_params *params,
+                                      bool stop)
 {
        int ret = 0;
 
        if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status))
-               return 0;
+               return;
 
        if (fw_has_capa(&fwrt->fw->ucode_capa,
                        IWL_UCODE_TLV_CAPA_DBG_SUSPEND_RESUME_CMD_SUPP))
@@ -2686,7 +2679,5 @@ int iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
                        iwl_fw_set_dbg_rec_on(fwrt);
        }
 #endif
-
-       return ret;
 }
 IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_restart_recording);
index 179f290..9d35132 100644 (file)
@@ -239,9 +239,9 @@ _iwl_fw_dbg_trigger_simple_stop(struct iwl_fw_runtime *fwrt,
        _iwl_fw_dbg_trigger_simple_stop((fwrt), (wdev),         \
                                        iwl_fw_dbg_get_trigger((fwrt)->fw,\
                                                               (trig)))
-int iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
-                                     struct iwl_fw_dbg_params *params,
-                                     bool stop);
+void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,
+                                      struct iwl_fw_dbg_params *params,
+                                      bool stop);
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 static inline void iwl_fw_set_dbg_rec_on(struct iwl_fw_runtime *fwrt)
index 2d1cb46..0481796 100644 (file)
@@ -1467,7 +1467,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
                                kmemdup(pieces->dbg_conf_tlv[i],
                                        pieces->dbg_conf_tlv_len[i],
                                        GFP_KERNEL);
-                       if (!pieces->dbg_conf_tlv_len[i])
+                       if (!pieces->dbg_conf_tlv[i])
                                goto out_free_fw;
                }
        }
index 54c094e..98263cd 100644 (file)
@@ -762,10 +762,17 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
        u16 cmd_wide_id =  WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT);
        union geo_tx_power_profiles_cmd cmd;
        u16 len;
+       int ret;
 
        cmd.geo_cmd.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES);
 
-       iwl_sar_geo_init(&mvm->fwrt, cmd.geo_cmd.table);
+       ret = iwl_sar_geo_init(&mvm->fwrt, cmd.geo_cmd.table);
+       /*
+        * It is a valid scenario to not support SAR, or miss wgds table,
+        * but in that case there is no need to send the command.
+        */
+       if (ret)
+               return 0;
 
        cmd.geo_cmd.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
 
index 70b29bf..60296a7 100644 (file)
@@ -308,7 +308,8 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
                }
 
                /* PHY_SKU section is mandatory in B0 */
-               if (!mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) {
+               if (mvm->trans->cfg->nvm_type == IWL_NVM_EXT &&
+                   !mvm->nvm_sections[NVM_SECTION_TYPE_PHY_SKU].data) {
                        IWL_ERR(mvm,
                                "Can't parse phy_sku in B0, empty sections\n");
                        return NULL;
index e2cf9e0..ca99a9c 100644 (file)
@@ -6,7 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2017        Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
+ * Copyright(c) 2018 - 2020 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -27,7 +27,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2017        Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
+ * Copyright(c) 2018 - 2020 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -147,7 +147,11 @@ static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
             (vht_ena && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))))
                flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
 
-       /* consider our LDPC support in case of HE */
+       /* consider LDPC support in case of HE */
+       if (he_cap->has_he && (he_cap->he_cap_elem.phy_cap_info[1] &
+           IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
+               flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK;
+
        if (sband->iftype_data && sband->iftype_data->he_cap.has_he &&
            !(sband->iftype_data->he_cap.he_cap_elem.phy_cap_info[1] &
             IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
@@ -191,11 +195,13 @@ rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
 {
        u16 supp;
        int i, highest_mcs;
+       u8 nss = sta->rx_nss;
 
-       for (i = 0; i < sta->rx_nss; i++) {
-               if (i == IWL_TLC_NSS_MAX)
-                       break;
+       /* the station support only a single receive chain */
+       if (sta->smps_mode == IEEE80211_SMPS_STATIC)
+               nss = 1;
 
+       for (i = 0; i < nss && i < IWL_TLC_NSS_MAX; i++) {
                highest_mcs = rs_fw_vht_highest_rx_mcs_index(vht_cap, i + 1);
                if (!highest_mcs)
                        continue;
@@ -241,8 +247,13 @@ rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta,
        u16 tx_mcs_160 =
                le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160);
        int i;
+       u8 nss = sta->rx_nss;
+
+       /* the station support only a single receive chain */
+       if (sta->smps_mode == IEEE80211_SMPS_STATIC)
+               nss = 1;
 
-       for (i = 0; i < sta->rx_nss && i < IWL_TLC_NSS_MAX; i++) {
+       for (i = 0; i < nss && i < IWL_TLC_NSS_MAX; i++) {
                u16 _mcs_160 = (mcs_160 >> (2 * i)) & 0x3;
                u16 _mcs_80 = (mcs_80 >> (2 * i)) & 0x3;
                u16 _tx_mcs_160 = (tx_mcs_160 >> (2 * i)) & 0x3;
@@ -303,8 +314,14 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
                cmd->mode = IWL_TLC_MNG_MODE_HT;
                cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_HT_BW_NONE_160] =
                        cpu_to_le16(ht_cap->mcs.rx_mask[0]);
-               cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_HT_BW_NONE_160] =
-                       cpu_to_le16(ht_cap->mcs.rx_mask[1]);
+
+               /* the station support only a single receive chain */
+               if (sta->smps_mode == IEEE80211_SMPS_STATIC)
+                       cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_HT_BW_NONE_160] =
+                               0;
+               else
+                       cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_HT_BW_NONE_160] =
+                               cpu_to_le16(ht_cap->mcs.rx_mask[1]);
        }
 }
 
index c0b420f..1babc4b 100644 (file)
@@ -785,7 +785,9 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
                if (!le32_to_cpu(notif->status)) {
                        iwl_mvm_te_check_disconnect(mvm, vif,
                                                    "Session protection failure");
+                       spin_lock_bh(&mvm->time_event_lock);
                        iwl_mvm_te_clear_data(mvm, te_data);
+                       spin_unlock_bh(&mvm->time_event_lock);
                }
 
                if (le32_to_cpu(notif->start)) {
@@ -801,7 +803,9 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
                         */
                        iwl_mvm_te_check_disconnect(mvm, vif,
                                                    "No beacon heard and the session protection is over already...");
+                       spin_lock_bh(&mvm->time_event_lock);
                        iwl_mvm_te_clear_data(mvm, te_data);
+                       spin_unlock_bh(&mvm->time_event_lock);
                }
 
                goto out_unlock;
index 97f227f..f441b20 100644 (file)
@@ -981,6 +981,9 @@ static const struct iwl_dev_info iwl_dev_info_table[] = {
        IWL_DEV_INFO(0x2526, 0x0014, iwl9260_2ac_160_cfg, iwl9260_160_name),
        IWL_DEV_INFO(0x2526, 0x0018, iwl9260_2ac_160_cfg, iwl9260_160_name),
        IWL_DEV_INFO(0x2526, 0x001C, iwl9260_2ac_160_cfg, iwl9260_160_name),
+       IWL_DEV_INFO(0x2526, 0x4010, iwl9260_2ac_160_cfg, iwl9260_160_name),
+       IWL_DEV_INFO(0x2526, 0x4018, iwl9260_2ac_160_cfg, iwl9260_160_name),
+       IWL_DEV_INFO(0x2526, 0x401C, iwl9260_2ac_160_cfg, iwl9260_160_name),
        IWL_DEV_INFO(0x2526, 0x6010, iwl9260_2ac_160_cfg, iwl9260_160_name),
        IWL_DEV_INFO(0x2526, 0x6014, iwl9260_2ac_160_cfg, iwl9260_160_name),
        IWL_DEV_INFO(0x2526, 0x8014, iwl9260_2ac_160_cfg, iwl9260_160_name),
index e753f43..0e42de2 100644 (file)
@@ -365,17 +365,6 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
        return ctx;
 }
 
-
-/* Hopefully the real complete_all will soon be exported, in the mean
- * while this should work. */
-static inline void ezusb_complete_all(struct completion *comp)
-{
-       complete(comp);
-       complete(comp);
-       complete(comp);
-       complete(comp);
-}
-
 static void ezusb_ctx_complete(struct request_context *ctx)
 {
        struct ezusb_priv *upriv = ctx->upriv;
@@ -409,7 +398,7 @@ static void ezusb_ctx_complete(struct request_context *ctx)
 
                        netif_wake_queue(dev);
                }
-               ezusb_complete_all(&ctx->done);
+               complete_all(&ctx->done);
                ezusb_request_context_put(ctx);
                break;
 
@@ -419,7 +408,7 @@ static void ezusb_ctx_complete(struct request_context *ctx)
                        /* This is normal, as all request contexts get flushed
                         * when the device is disconnected */
                        err("Called, CTX not terminating, but device gone");
-                       ezusb_complete_all(&ctx->done);
+                       complete_all(&ctx->done);
                        ezusb_request_context_put(ctx);
                        break;
                }
@@ -690,11 +679,11 @@ static void ezusb_req_ctx_wait(struct ezusb_priv *upriv,
                         * get the chance to run themselves. So we make sure
                         * that we don't sleep for ever */
                        int msecs = DEF_TIMEOUT * (1000 / HZ);
-                       while (!ctx->done.done && msecs--)
+
+                       while (!try_wait_for_completion(&ctx->done) && msecs--)
                                udelay(1000);
                } else {
-                       wait_event_interruptible(ctx->done.wait,
-                                                ctx->done.done);
+                       wait_for_completion(&ctx->done);
                }
                break;
        default:
index 6173c80..1847f55 100644 (file)
@@ -447,10 +447,13 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
        struct page *page = virt_to_head_page(data);
        int offset = data - page_address(page);
        struct sk_buff *skb = q->rx_head;
+       struct skb_shared_info *shinfo = skb_shinfo(skb);
 
-       offset += q->buf_offset;
-       skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset, len,
-                       q->buf_size);
+       if (shinfo->nr_frags < ARRAY_SIZE(shinfo->frags)) {
+               offset += q->buf_offset;
+               skb_add_rx_frag(skb, shinfo->nr_frags, page, offset, len,
+                               q->buf_size);
+       }
 
        if (more)
                return;
index 9177298..e17f70b 100644 (file)
@@ -561,6 +561,7 @@ static inline void clear_pci_tx_desc_content(__le32 *__pdesc, int _size)
         rxmcs == DESC92C_RATE11M)
 
 struct phy_status_rpt {
+       u8      padding[2];
        u8      ch_corr[2];
        u8      cck_sig_qual_ofdm_pwdb_all;
        u8      cck_agc_rpt_ofdm_cfosho_a;
index ed049c9..f140f7d 100644 (file)
@@ -6274,7 +6274,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
        wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
                                WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
                                WIPHY_FLAG_HAS_CHANNEL_SWITCH |
-+                              WIPHY_FLAG_IBSS_RSN;
+                               WIPHY_FLAG_IBSS_RSN;
 
        wl->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN;
 
index 0cc9ac8..ed21231 100644 (file)
@@ -184,7 +184,7 @@ static int fdp_nci_send_patch(struct nci_dev *ndev, u8 conn_id, u8 type)
        const struct firmware *fw;
        struct sk_buff *skb;
        unsigned long len;
-       u8 max_size, payload_size;
+       int max_size, payload_size;
        int rc = 0;
 
        if ((type == NCI_PATCH_TYPE_OTP && !info->otp_patch) ||
@@ -207,8 +207,7 @@ static int fdp_nci_send_patch(struct nci_dev *ndev, u8 conn_id, u8 type)
 
        while (len) {
 
-               payload_size = min_t(unsigned long, (unsigned long) max_size,
-                                    len);
+               payload_size = min_t(unsigned long, max_size, len);
 
                skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + payload_size),
                                    GFP_KERNEL);
index 677d6f4..43751fa 100644 (file)
@@ -249,13 +249,12 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        internal_nlba = div_u64(nsblk->size, nsblk_internal_lbasize(nsblk));
        available_disk_size = internal_nlba * nsblk_sector_size(nsblk);
 
-       q = blk_alloc_queue(GFP_KERNEL);
+       q = blk_alloc_queue(nd_blk_make_request, NUMA_NO_NODE);
        if (!q)
                return -ENOMEM;
        if (devm_add_action_or_reset(dev, nd_blk_release_queue, q))
                return -ENOMEM;
 
-       blk_queue_make_request(q, nd_blk_make_request);
        blk_queue_max_hw_sectors(q, UINT_MAX);
        blk_queue_logical_block_size(q, nsblk_sector_size(nsblk));
        blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
index 0d04ea3..3b09419 100644 (file)
@@ -1521,7 +1521,7 @@ static int btt_blk_init(struct btt *btt)
        struct nd_namespace_common *ndns = nd_btt->ndns;
 
        /* create a new disk and request queue for btt */
-       btt->btt_queue = blk_alloc_queue(GFP_KERNEL);
+       btt->btt_queue = blk_alloc_queue(btt_make_request, NUMA_NO_NODE);
        if (!btt->btt_queue)
                return -ENOMEM;
 
@@ -1540,7 +1540,6 @@ static int btt_blk_init(struct btt *btt)
        btt->btt_disk->queue->backing_dev_info->capabilities |=
                        BDI_CAP_SYNCHRONOUS_IO;
 
-       blk_queue_make_request(btt->btt_queue, btt_make_request);
        blk_queue_logical_block_size(btt->btt_queue, btt->sector_size);
        blk_queue_max_hw_sectors(btt->btt_queue, UINT_MAX);
        blk_queue_flag_set(QUEUE_FLAG_NONROT, btt->btt_queue);
index 4eae441..4ffc6f7 100644 (file)
@@ -395,7 +395,7 @@ static int pmem_attach_disk(struct device *dev,
                return -EBUSY;
        }
 
-       q = blk_alloc_queue_node(GFP_KERNEL, dev_to_node(dev));
+       q = blk_alloc_queue(pmem_make_request, dev_to_node(dev));
        if (!q)
                return -ENOMEM;
 
@@ -433,7 +433,6 @@ static int pmem_attach_disk(struct device *dev,
        pmem->virt_addr = addr;
 
        blk_queue_write_cache(q, true, fua);
-       blk_queue_make_request(q, pmem_make_request);
        blk_queue_physical_block_size(q, PAGE_SIZE);
        blk_queue_logical_block_size(q, pmem_sector_size(ndns));
        blk_queue_max_hw_sectors(q, UINT_MAX);
index b9358db..9c17ed3 100644 (file)
@@ -32,8 +32,6 @@ config NVME_HWMON
          a hardware monitoring device will be created for each NVMe drive
          in the system.
 
-         If unsure, say N.
-
 config NVME_FABRICS
        tristate
 
index a4d8c90..4f907e3 100644 (file)
@@ -171,7 +171,6 @@ static void nvme_do_delete_ctrl(struct nvme_ctrl *ctrl)
        nvme_remove_namespaces(ctrl);
        ctrl->ops->delete_ctrl(ctrl);
        nvme_uninit_ctrl(ctrl);
-       nvme_put_ctrl(ctrl);
 }
 
 static void nvme_delete_ctrl_work(struct work_struct *work)
@@ -192,21 +191,16 @@ int nvme_delete_ctrl(struct nvme_ctrl *ctrl)
 }
 EXPORT_SYMBOL_GPL(nvme_delete_ctrl);
 
-static int nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl)
+static void nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl)
 {
-       int ret = 0;
-
        /*
         * Keep a reference until nvme_do_delete_ctrl() complete,
         * since ->delete_ctrl can free the controller.
         */
        nvme_get_ctrl(ctrl);
-       if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_DELETING))
-               ret = -EBUSY;
-       if (!ret)
+       if (nvme_change_ctrl_state(ctrl, NVME_CTRL_DELETING))
                nvme_do_delete_ctrl(ctrl);
        nvme_put_ctrl(ctrl);
-       return ret;
 }
 
 static inline bool nvme_ns_has_pi(struct nvme_ns *ns)
@@ -291,11 +285,8 @@ void nvme_complete_rq(struct request *req)
                nvme_req(req)->ctrl->comp_seen = true;
 
        if (unlikely(status != BLK_STS_OK && nvme_req_needs_retry(req))) {
-               if ((req->cmd_flags & REQ_NVME_MPATH) &&
-                   blk_path_error(status)) {
-                       nvme_failover_req(req);
+               if ((req->cmd_flags & REQ_NVME_MPATH) && nvme_failover_req(req))
                        return;
-               }
 
                if (!blk_queue_dying(req->q)) {
                        nvme_retry_req(req);
@@ -1055,6 +1046,43 @@ static int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
        return error;
 }
 
+static int nvme_process_ns_desc(struct nvme_ctrl *ctrl, struct nvme_ns_ids *ids,
+               struct nvme_ns_id_desc *cur)
+{
+       const char *warn_str = "ctrl returned bogus length:";
+       void *data = cur;
+
+       switch (cur->nidt) {
+       case NVME_NIDT_EUI64:
+               if (cur->nidl != NVME_NIDT_EUI64_LEN) {
+                       dev_warn(ctrl->device, "%s %d for NVME_NIDT_EUI64\n",
+                                warn_str, cur->nidl);
+                       return -1;
+               }
+               memcpy(ids->eui64, data + sizeof(*cur), NVME_NIDT_EUI64_LEN);
+               return NVME_NIDT_EUI64_LEN;
+       case NVME_NIDT_NGUID:
+               if (cur->nidl != NVME_NIDT_NGUID_LEN) {
+                       dev_warn(ctrl->device, "%s %d for NVME_NIDT_NGUID\n",
+                                warn_str, cur->nidl);
+                       return -1;
+               }
+               memcpy(ids->nguid, data + sizeof(*cur), NVME_NIDT_NGUID_LEN);
+               return NVME_NIDT_NGUID_LEN;
+       case NVME_NIDT_UUID:
+               if (cur->nidl != NVME_NIDT_UUID_LEN) {
+                       dev_warn(ctrl->device, "%s %d for NVME_NIDT_UUID\n",
+                                warn_str, cur->nidl);
+                       return -1;
+               }
+               uuid_copy(&ids->uuid, data + sizeof(*cur));
+               return NVME_NIDT_UUID_LEN;
+       default:
+               /* Skip unknown types */
+               return cur->nidl;
+       }
+}
+
 static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid,
                struct nvme_ns_ids *ids)
 {
@@ -1074,8 +1102,17 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid,
 
        status = nvme_submit_sync_cmd(ctrl->admin_q, &c, data,
                                      NVME_IDENTIFY_DATA_SIZE);
-       if (status)
+       if (status) {
+               dev_warn(ctrl->device,
+                       "Identify Descriptors failed (%d)\n", status);
+                /*
+                 * Don't treat an error as fatal, as we potentially already
+                 * have a NGUID or EUI-64.
+                 */
+               if (status > 0)
+                       status = 0;
                goto free_data;
+       }
 
        for (pos = 0; pos < NVME_IDENTIFY_DATA_SIZE; pos += len) {
                struct nvme_ns_id_desc *cur = data + pos;
@@ -1083,42 +1120,9 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid,
                if (cur->nidl == 0)
                        break;
 
-               switch (cur->nidt) {
-               case NVME_NIDT_EUI64:
-                       if (cur->nidl != NVME_NIDT_EUI64_LEN) {
-                               dev_warn(ctrl->device,
-                                        "ctrl returned bogus length: %d for NVME_NIDT_EUI64\n",
-                                        cur->nidl);
-                               goto free_data;
-                       }
-                       len = NVME_NIDT_EUI64_LEN;
-                       memcpy(ids->eui64, data + pos + sizeof(*cur), len);
-                       break;
-               case NVME_NIDT_NGUID:
-                       if (cur->nidl != NVME_NIDT_NGUID_LEN) {
-                               dev_warn(ctrl->device,
-                                        "ctrl returned bogus length: %d for NVME_NIDT_NGUID\n",
-                                        cur->nidl);
-                               goto free_data;
-                       }
-                       len = NVME_NIDT_NGUID_LEN;
-                       memcpy(ids->nguid, data + pos + sizeof(*cur), len);
-                       break;
-               case NVME_NIDT_UUID:
-                       if (cur->nidl != NVME_NIDT_UUID_LEN) {
-                               dev_warn(ctrl->device,
-                                        "ctrl returned bogus length: %d for NVME_NIDT_UUID\n",
-                                        cur->nidl);
-                               goto free_data;
-                       }
-                       len = NVME_NIDT_UUID_LEN;
-                       uuid_copy(&ids->uuid, data + pos + sizeof(*cur));
-                       break;
-               default:
-                       /* Skip unknown types */
-                       len = cur->nidl;
-                       break;
-               }
+               len = nvme_process_ns_desc(ctrl, ids, cur);
+               if (len < 0)
+                       goto free_data;
 
                len += sizeof(*cur);
        }
@@ -1584,6 +1588,47 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
        return ret;
 }
 
+#ifdef CONFIG_COMPAT
+struct nvme_user_io32 {
+       __u8    opcode;
+       __u8    flags;
+       __u16   control;
+       __u16   nblocks;
+       __u16   rsvd;
+       __u64   metadata;
+       __u64   addr;
+       __u64   slba;
+       __u32   dsmgmt;
+       __u32   reftag;
+       __u16   apptag;
+       __u16   appmask;
+} __attribute__((__packed__));
+
+#define NVME_IOCTL_SUBMIT_IO32 _IOW('N', 0x42, struct nvme_user_io32)
+
+static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
+               unsigned int cmd, unsigned long arg)
+{
+       /*
+        * Corresponds to the difference of NVME_IOCTL_SUBMIT_IO
+        * between 32 bit programs and 64 bit kernel.
+        * The cause is that the results of sizeof(struct nvme_user_io),
+        * which is used to define NVME_IOCTL_SUBMIT_IO,
+        * are not same between 32 bit compiler and 64 bit compiler.
+        * NVME_IOCTL_SUBMIT_IO32 is for 64 bit kernel handling
+        * NVME_IOCTL_SUBMIT_IO issued from 32 bit programs.
+        * Other IOCTL numbers are same between 32 bit and 64 bit.
+        * So there is nothing to do regarding to other IOCTL numbers.
+        */
+       if (cmd == NVME_IOCTL_SUBMIT_IO32)
+               return nvme_ioctl(bdev, mode, NVME_IOCTL_SUBMIT_IO, arg);
+
+       return nvme_ioctl(bdev, mode, cmd, arg);
+}
+#else
+#define nvme_compat_ioctl      NULL
+#endif /* CONFIG_COMPAT */
+
 static int nvme_open(struct block_device *bdev, fmode_t mode)
 {
        struct nvme_ns *ns = bdev->bd_disk->private_data;
@@ -1721,26 +1766,15 @@ static void nvme_config_write_zeroes(struct gendisk *disk, struct nvme_ns *ns)
 static int nvme_report_ns_ids(struct nvme_ctrl *ctrl, unsigned int nsid,
                struct nvme_id_ns *id, struct nvme_ns_ids *ids)
 {
-       int ret = 0;
-
        memset(ids, 0, sizeof(*ids));
 
        if (ctrl->vs >= NVME_VS(1, 1, 0))
                memcpy(ids->eui64, id->eui64, sizeof(id->eui64));
        if (ctrl->vs >= NVME_VS(1, 2, 0))
                memcpy(ids->nguid, id->nguid, sizeof(id->nguid));
-       if (ctrl->vs >= NVME_VS(1, 3, 0)) {
-                /* Don't treat error as fatal we potentially
-                 * already have a NGUID or EUI-64
-                 */
-               ret = nvme_identify_ns_descs(ctrl, nsid, ids);
-               if (ret)
-                       dev_warn(ctrl->device,
-                                "Identify Descriptors failed (%d)\n", ret);
-               if (ret > 0)
-                       ret = 0;
-       }
-       return ret;
+       if (ctrl->vs >= NVME_VS(1, 3, 0))
+               return nvme_identify_ns_descs(ctrl, nsid, ids);
+       return 0;
 }
 
 static bool nvme_ns_ids_valid(struct nvme_ns_ids *ids)
@@ -1810,7 +1844,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
            ns->lba_shift > PAGE_SHIFT)
                capacity = 0;
 
-       set_capacity(disk, capacity);
+       set_capacity_revalidate_and_notify(disk, capacity, false);
 
        nvme_config_discard(disk, ns);
        nvme_config_write_zeroes(disk, ns);
@@ -2027,7 +2061,7 @@ EXPORT_SYMBOL_GPL(nvme_sec_submit);
 static const struct block_device_operations nvme_fops = {
        .owner          = THIS_MODULE,
        .ioctl          = nvme_ioctl,
-       .compat_ioctl   = nvme_ioctl,
+       .compat_ioctl   = nvme_compat_ioctl,
        .open           = nvme_open,
        .release        = nvme_release,
        .getgeo         = nvme_getgeo,
@@ -2055,7 +2089,7 @@ const struct block_device_operations nvme_ns_head_ops = {
        .open           = nvme_ns_head_open,
        .release        = nvme_ns_head_release,
        .ioctl          = nvme_ioctl,
-       .compat_ioctl   = nvme_ioctl,
+       .compat_ioctl   = nvme_compat_ioctl,
        .getgeo         = nvme_getgeo,
        .pr_ops         = &nvme_pr_ops,
 };
@@ -2074,13 +2108,13 @@ static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled)
                if ((csts & NVME_CSTS_RDY) == bit)
                        break;
 
-               msleep(100);
+               usleep_range(1000, 2000);
                if (fatal_signal_pending(current))
                        return -EINTR;
                if (time_after(jiffies, timeout)) {
                        dev_err(ctrl->device,
-                               "Device not ready; aborting %s\n", enabled ?
-                                               "initialisation" : "reset");
+                               "Device not ready; aborting %s, CSTS=0x%x\n",
+                               enabled ? "initialisation" : "reset", csts);
                        return -ENODEV;
                }
        }
@@ -2591,8 +2625,7 @@ static bool nvme_validate_cntlid(struct nvme_subsystem *subsys,
        lockdep_assert_held(&nvme_subsystems_lock);
 
        list_for_each_entry(tmp, &subsys->ctrls, subsys_entry) {
-               if (tmp->state == NVME_CTRL_DELETING ||
-                   tmp->state == NVME_CTRL_DEAD)
+               if (nvme_state_terminal(tmp))
                        continue;
 
                if (tmp->cntlid == ctrl->cntlid) {
@@ -3193,6 +3226,10 @@ static ssize_t nvme_sysfs_delete(struct device *dev,
 {
        struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
 
+       /* Can't delete non-created controllers */
+       if (!ctrl->created)
+               return -EBUSY;
+
        if (device_remove_file_self(dev, attr))
                nvme_delete_ctrl_sync(ctrl);
        return count;
@@ -3242,6 +3279,26 @@ static ssize_t nvme_sysfs_show_subsysnqn(struct device *dev,
 }
 static DEVICE_ATTR(subsysnqn, S_IRUGO, nvme_sysfs_show_subsysnqn, NULL);
 
+static ssize_t nvme_sysfs_show_hostnqn(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", ctrl->opts->host->nqn);
+}
+static DEVICE_ATTR(hostnqn, S_IRUGO, nvme_sysfs_show_hostnqn, NULL);
+
+static ssize_t nvme_sysfs_show_hostid(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%pU\n", &ctrl->opts->host->id);
+}
+static DEVICE_ATTR(hostid, S_IRUGO, nvme_sysfs_show_hostid, NULL);
+
 static ssize_t nvme_sysfs_show_address(struct device *dev,
                                         struct device_attribute *attr,
                                         char *buf)
@@ -3267,6 +3324,8 @@ static struct attribute *nvme_dev_attrs[] = {
        &dev_attr_numa_node.attr,
        &dev_attr_queue_count.attr,
        &dev_attr_sqsize.attr,
+       &dev_attr_hostnqn.attr,
+       &dev_attr_hostid.attr,
        NULL
 };
 
@@ -3280,6 +3339,10 @@ static umode_t nvme_dev_attrs_are_visible(struct kobject *kobj,
                return 0;
        if (a == &dev_attr_address.attr && !ctrl->ops->get_address)
                return 0;
+       if (a == &dev_attr_hostnqn.attr && !ctrl->opts)
+               return 0;
+       if (a == &dev_attr_hostid.attr && !ctrl->opts)
+               return 0;
 
        return a->mode;
 }
@@ -3294,7 +3357,7 @@ static const struct attribute_group *nvme_dev_attr_groups[] = {
        NULL,
 };
 
-static struct nvme_ns_head *__nvme_find_ns_head(struct nvme_subsystem *subsys,
+static struct nvme_ns_head *nvme_find_ns_head(struct nvme_subsystem *subsys,
                unsigned nsid)
 {
        struct nvme_ns_head *h;
@@ -3327,7 +3390,8 @@ static int __nvme_check_ids(struct nvme_subsystem *subsys,
 }
 
 static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
-               unsigned nsid, struct nvme_id_ns *id)
+               unsigned nsid, struct nvme_id_ns *id,
+               struct nvme_ns_ids *ids)
 {
        struct nvme_ns_head *head;
        size_t size = sizeof(*head);
@@ -3350,12 +3414,9 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
                goto out_ida_remove;
        head->subsys = ctrl->subsys;
        head->ns_id = nsid;
+       head->ids = *ids;
        kref_init(&head->ref);
 
-       ret = nvme_report_ns_ids(ctrl, nsid, id, &head->ids);
-       if (ret)
-               goto out_cleanup_srcu;
-
        ret = __nvme_check_ids(ctrl->subsys, head);
        if (ret) {
                dev_err(ctrl->device,
@@ -3390,24 +3451,23 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
        struct nvme_ctrl *ctrl = ns->ctrl;
        bool is_shared = id->nmic & (1 << 0);
        struct nvme_ns_head *head = NULL;
+       struct nvme_ns_ids ids;
        int ret = 0;
 
+       ret = nvme_report_ns_ids(ctrl, nsid, id, &ids);
+       if (ret)
+               goto out;
+
        mutex_lock(&ctrl->subsys->lock);
        if (is_shared)
-               head = __nvme_find_ns_head(ctrl->subsys, nsid);
+               head = nvme_find_ns_head(ctrl->subsys, nsid);
        if (!head) {
-               head = nvme_alloc_ns_head(ctrl, nsid, id);
+               head = nvme_alloc_ns_head(ctrl, nsid, id, &ids);
                if (IS_ERR(head)) {
                        ret = PTR_ERR(head);
                        goto out_unlock;
                }
        } else {
-               struct nvme_ns_ids ids;
-
-               ret = nvme_report_ns_ids(ctrl, nsid, id, &ids);
-               if (ret)
-                       goto out_unlock;
-
                if (!nvme_ns_ids_equal(&head->ids, &ids)) {
                        dev_err(ctrl->device,
                                "IDs don't match for shared namespace %d\n",
@@ -3422,6 +3482,7 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
 
 out_unlock:
        mutex_unlock(&ctrl->subsys->lock);
+out:
        if (ret > 0)
                ret = blk_status_to_errno(nvme_error_status(ret));
        return ret;
@@ -3480,7 +3541,7 @@ static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns)
        return 0;
 }
 
-static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
+static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
 {
        struct nvme_ns *ns;
        struct gendisk *disk;
@@ -3490,13 +3551,11 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
 
        ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
        if (!ns)
-               return -ENOMEM;
+               return;
 
        ns->queue = blk_mq_init_queue(ctrl->tagset);
-       if (IS_ERR(ns->queue)) {
-               ret = PTR_ERR(ns->queue);
+       if (IS_ERR(ns->queue))
                goto out_free_ns;
-       }
 
        if (ctrl->opts && ctrl->opts->data_digest)
                ns->queue->backing_dev_info->capabilities
@@ -3519,10 +3578,8 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        if (ret)
                goto out_free_queue;
 
-       if (id->ncap == 0) {
-               ret = -EINVAL;
+       if (id->ncap == 0)      /* no namespace (legacy quirk) */
                goto out_free_id;
-       }
 
        ret = nvme_init_ns_head(ns, nsid, id);
        if (ret)
@@ -3531,10 +3588,8 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        nvme_set_disk_name(disk_name, ns, ctrl, &flags);
 
        disk = alloc_disk_node(0, node);
-       if (!disk) {
-               ret = -ENOMEM;
+       if (!disk)
                goto out_unlink_ns;
-       }
 
        disk->fops = &nvme_fops;
        disk->private_data = ns;
@@ -3565,7 +3620,7 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name);
        kfree(id);
 
-       return 0;
+       return;
  out_put_disk:
        put_disk(ns->disk);
  out_unlink_ns:
@@ -3579,9 +3634,6 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        blk_cleanup_queue(ns->queue);
  out_free_ns:
        kfree(ns);
-       if (ret > 0)
-               ret = blk_status_to_errno(nvme_error_status(ret));
-       return ret;
 }
 
 static void nvme_ns_remove(struct nvme_ns *ns)
@@ -3987,6 +4039,7 @@ void nvme_start_ctrl(struct nvme_ctrl *ctrl)
                nvme_queue_scan(ctrl);
                nvme_start_queues(ctrl);
        }
+       ctrl->created = true;
 }
 EXPORT_SYMBOL_GPL(nvme_start_ctrl);
 
@@ -3995,6 +4048,7 @@ void nvme_uninit_ctrl(struct nvme_ctrl *ctrl)
        nvme_fault_inject_fini(&ctrl->fault_inject);
        dev_pm_qos_hide_latency_tolerance(ctrl->device);
        cdev_device_del(&ctrl->cdev, ctrl->device);
+       nvme_put_ctrl(ctrl);
 }
 EXPORT_SYMBOL_GPL(nvme_uninit_ctrl);
 
@@ -4077,6 +4131,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
        if (ret)
                goto out_release_instance;
 
+       nvme_get_ctrl(ctrl);
        cdev_init(&ctrl->cdev, &nvme_dev_fops);
        ctrl->cdev.owner = ops->module;
        ret = cdev_device_add(&ctrl->cdev, ctrl->device);
@@ -4095,6 +4150,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
 
        return 0;
 out_free_name:
+       nvme_put_ctrl(ctrl);
        kfree_const(ctrl->device->kobj.name);
 out_release_instance:
        ida_simple_remove(&nvme_instance_ida, ctrl->instance);
@@ -4299,6 +4355,7 @@ static void __exit nvme_core_exit(void)
        destroy_workqueue(nvme_delete_wq);
        destroy_workqueue(nvme_reset_wq);
        destroy_workqueue(nvme_wq);
+       ida_destroy(&nvme_instance_ida);
 }
 
 MODULE_LICENSE("GPL");
index 74b8818..2a6c819 100644 (file)
@@ -105,14 +105,14 @@ int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
        int len = 0;
 
        if (ctrl->opts->mask & NVMF_OPT_TRADDR)
-               len += snprintf(buf, size, "traddr=%s", ctrl->opts->traddr);
+               len += scnprintf(buf, size, "traddr=%s", ctrl->opts->traddr);
        if (ctrl->opts->mask & NVMF_OPT_TRSVCID)
-               len += snprintf(buf + len, size - len, "%strsvcid=%s",
+               len += scnprintf(buf + len, size - len, "%strsvcid=%s",
                                (len) ? "," : "", ctrl->opts->trsvcid);
        if (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR)
-               len += snprintf(buf + len, size - len, "%shost_traddr=%s",
+               len += scnprintf(buf + len, size - len, "%shost_traddr=%s",
                                (len) ? "," : "", ctrl->opts->host_traddr);
-       len += snprintf(buf + len, size - len, "\n");
+       len += scnprintf(buf + len, size - len, "\n");
 
        return len;
 }
index 5a70ac3..a8bf2fb 100644 (file)
@@ -3181,10 +3181,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
                goto fail_ctrl;
        }
 
-       nvme_get_ctrl(&ctrl->ctrl);
-
        if (!queue_delayed_work(nvme_wq, &ctrl->connect_work, 0)) {
-               nvme_put_ctrl(&ctrl->ctrl);
                dev_err(ctrl->ctrl.device,
                        "NVME-FC{%d}: failed to schedule initial connect\n",
                        ctrl->cnum);
index a11900c..61bf875 100644 (file)
@@ -64,17 +64,12 @@ void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
        }
 }
 
-void nvme_failover_req(struct request *req)
+bool nvme_failover_req(struct request *req)
 {
        struct nvme_ns *ns = req->q->queuedata;
        u16 status = nvme_req(req)->status;
        unsigned long flags;
 
-       spin_lock_irqsave(&ns->head->requeue_lock, flags);
-       blk_steal_bios(&ns->head->requeue_list, req);
-       spin_unlock_irqrestore(&ns->head->requeue_lock, flags);
-       blk_mq_end_request(req, 0);
-
        switch (status & 0x7ff) {
        case NVME_SC_ANA_TRANSITION:
        case NVME_SC_ANA_INACCESSIBLE:
@@ -103,15 +98,17 @@ void nvme_failover_req(struct request *req)
                nvme_mpath_clear_current_path(ns);
                break;
        default:
-               /*
-                * Reset the controller for any non-ANA error as we don't know
-                * what caused the error.
-                */
-               nvme_reset_ctrl(ns->ctrl);
-               break;
+               /* This was a non-ANA error so follow the normal error path. */
+               return false;
        }
 
+       spin_lock_irqsave(&ns->head->requeue_lock, flags);
+       blk_steal_bios(&ns->head->requeue_list, req);
+       spin_unlock_irqrestore(&ns->head->requeue_lock, flags);
+       blk_mq_end_request(req, 0);
+
        kblockd_schedule_work(&ns->head->requeue_work);
+       return true;
 }
 
 void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
@@ -377,11 +374,10 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head)
        if (!(ctrl->subsys->cmic & (1 << 1)) || !multipath)
                return 0;
 
-       q = blk_alloc_queue_node(GFP_KERNEL, ctrl->numa_node);
+       q = blk_alloc_queue(nvme_ns_head_make_request, ctrl->numa_node);
        if (!q)
                goto out;
        q->queuedata = head;
-       blk_queue_make_request(q, nvme_ns_head_make_request);
        blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
        /* set to a default value for 512 until disk is validated */
        blk_queue_logical_block_size(q, 512);
index 1024fec..2e04a36 100644 (file)
@@ -259,6 +259,7 @@ struct nvme_ctrl {
        struct nvme_command ka_cmd;
        struct work_struct fw_act_work;
        unsigned long events;
+       bool created;
 
 #ifdef CONFIG_NVME_MULTIPATH
        /* asymmetric namespace access: */
@@ -550,7 +551,7 @@ void nvme_mpath_wait_freeze(struct nvme_subsystem *subsys);
 void nvme_mpath_start_freeze(struct nvme_subsystem *subsys);
 void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
                        struct nvme_ctrl *ctrl, int *flags);
-void nvme_failover_req(struct request *req);
+bool nvme_failover_req(struct request *req);
 void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl);
 int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head);
 void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id);
@@ -599,8 +600,9 @@ static inline void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
        sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->head->instance);
 }
 
-static inline void nvme_failover_req(struct request *req)
+static inline bool nvme_failover_req(struct request *req)
 {
+       return false;
 }
 static inline void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl)
 {
index ace4dd9..4e79e41 100644 (file)
@@ -971,39 +971,25 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx)
        nvme_end_request(req, cqe->status, cqe->result);
 }
 
-static void nvme_complete_cqes(struct nvme_queue *nvmeq, u16 start, u16 end)
-{
-       while (start != end) {
-               nvme_handle_cqe(nvmeq, start);
-               if (++start == nvmeq->q_depth)
-                       start = 0;
-       }
-}
-
 static inline void nvme_update_cq_head(struct nvme_queue *nvmeq)
 {
-       if (nvmeq->cq_head == nvmeq->q_depth - 1) {
+       if (++nvmeq->cq_head == nvmeq->q_depth) {
                nvmeq->cq_head = 0;
-               nvmeq->cq_phase = !nvmeq->cq_phase;
-       } else {
-               nvmeq->cq_head++;
+               nvmeq->cq_phase ^= 1;
        }
 }
 
-static inline int nvme_process_cq(struct nvme_queue *nvmeq, u16 *start,
-                                 u16 *end, unsigned int tag)
+static inline int nvme_process_cq(struct nvme_queue *nvmeq)
 {
        int found = 0;
 
-       *start = nvmeq->cq_head;
        while (nvme_cqe_pending(nvmeq)) {
-               if (tag == -1U || nvmeq->cqes[nvmeq->cq_head].command_id == tag)
-                       found++;
+               found++;
+               nvme_handle_cqe(nvmeq, nvmeq->cq_head);
                nvme_update_cq_head(nvmeq);
        }
-       *end = nvmeq->cq_head;
 
-       if (*start != *end)
+       if (found)
                nvme_ring_cq_doorbell(nvmeq);
        return found;
 }
@@ -1012,21 +998,16 @@ static irqreturn_t nvme_irq(int irq, void *data)
 {
        struct nvme_queue *nvmeq = data;
        irqreturn_t ret = IRQ_NONE;
-       u16 start, end;
 
        /*
         * The rmb/wmb pair ensures we see all updates from a previous run of
         * the irq handler, even if that was on another CPU.
         */
        rmb();
-       nvme_process_cq(nvmeq, &start, &end, -1);
+       if (nvme_process_cq(nvmeq))
+               ret = IRQ_HANDLED;
        wmb();
 
-       if (start != end) {
-               nvme_complete_cqes(nvmeq, start, end);
-               return IRQ_HANDLED;
-       }
-
        return ret;
 }
 
@@ -1039,48 +1020,32 @@ static irqreturn_t nvme_irq_check(int irq, void *data)
 }
 
 /*
- * Poll for completions any queue, including those not dedicated to polling.
+ * Poll for completions for any interrupt driven queue
  * Can be called from any context.
  */
-static int nvme_poll_irqdisable(struct nvme_queue *nvmeq, unsigned int tag)
+static void nvme_poll_irqdisable(struct nvme_queue *nvmeq)
 {
        struct pci_dev *pdev = to_pci_dev(nvmeq->dev->dev);
-       u16 start, end;
-       int found;
 
-       /*
-        * For a poll queue we need to protect against the polling thread
-        * using the CQ lock.  For normal interrupt driven threads we have
-        * to disable the interrupt to avoid racing with it.
-        */
-       if (test_bit(NVMEQ_POLLED, &nvmeq->flags)) {
-               spin_lock(&nvmeq->cq_poll_lock);
-               found = nvme_process_cq(nvmeq, &start, &end, tag);
-               spin_unlock(&nvmeq->cq_poll_lock);
-       } else {
-               disable_irq(pci_irq_vector(pdev, nvmeq->cq_vector));
-               found = nvme_process_cq(nvmeq, &start, &end, tag);
-               enable_irq(pci_irq_vector(pdev, nvmeq->cq_vector));
-       }
+       WARN_ON_ONCE(test_bit(NVMEQ_POLLED, &nvmeq->flags));
 
-       nvme_complete_cqes(nvmeq, start, end);
-       return found;
+       disable_irq(pci_irq_vector(pdev, nvmeq->cq_vector));
+       nvme_process_cq(nvmeq);
+       enable_irq(pci_irq_vector(pdev, nvmeq->cq_vector));
 }
 
 static int nvme_poll(struct blk_mq_hw_ctx *hctx)
 {
        struct nvme_queue *nvmeq = hctx->driver_data;
-       u16 start, end;
        bool found;
 
        if (!nvme_cqe_pending(nvmeq))
                return 0;
 
        spin_lock(&nvmeq->cq_poll_lock);
-       found = nvme_process_cq(nvmeq, &start, &end, -1);
+       found = nvme_process_cq(nvmeq);
        spin_unlock(&nvmeq->cq_poll_lock);
 
-       nvme_complete_cqes(nvmeq, start, end);
        return found;
 }
 
@@ -1255,7 +1220,12 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
        /*
         * Did we miss an interrupt?
         */
-       if (nvme_poll_irqdisable(nvmeq, req->tag)) {
+       if (test_bit(NVMEQ_POLLED, &nvmeq->flags))
+               nvme_poll(req->mq_hctx);
+       else
+               nvme_poll_irqdisable(nvmeq);
+
+       if (blk_mq_request_completed(req)) {
                dev_warn(dev->ctrl.device,
                         "I/O %d QID %d timeout, completion polled\n",
                         req->tag, nvmeq->qid);
@@ -1398,7 +1368,7 @@ static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown)
        else
                nvme_disable_ctrl(&dev->ctrl);
 
-       nvme_poll_irqdisable(nvmeq, -1);
+       nvme_poll_irqdisable(nvmeq);
 }
 
 /*
@@ -1409,13 +1379,10 @@ static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown)
  */
 static void nvme_reap_pending_cqes(struct nvme_dev *dev)
 {
-       u16 start, end;
        int i;
 
-       for (i = dev->ctrl.queue_count - 1; i > 0; i--) {
-               nvme_process_cq(&dev->queues[i], &start, &end, -1);
-               nvme_complete_cqes(&dev->queues[i], start, end);
-       }
+       for (i = dev->ctrl.queue_count - 1; i > 0; i--)
+               nvme_process_cq(&dev->queues[i]);
 }
 
 static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues,
@@ -2503,13 +2470,13 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl)
        struct nvme_dev *dev = to_nvme_dev(ctrl);
 
        nvme_dbbuf_dma_free(dev);
-       put_device(dev->dev);
        nvme_free_tagset(dev);
        if (dev->ctrl.admin_q)
                blk_put_queue(dev->ctrl.admin_q);
-       kfree(dev->queues);
        free_opal_dev(dev->ctrl.opal_dev);
        mempool_destroy(dev->iod_mempool);
+       put_device(dev->dev);
+       kfree(dev->queues);
        kfree(dev);
 }
 
@@ -2689,7 +2656,7 @@ static int nvme_pci_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
 {
        struct pci_dev *pdev = to_pci_dev(to_nvme_dev(ctrl)->dev);
 
-       return snprintf(buf, size, "%s", dev_name(&pdev->dev));
+       return snprintf(buf, size, "%s\n", dev_name(&pdev->dev));
 }
 
 static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
@@ -2835,7 +2802,6 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev));
 
        nvme_reset_ctrl(&dev->ctrl);
-       nvme_get_ctrl(&dev->ctrl);
        async_schedule(nvme_async_probe, dev);
 
        return 0;
@@ -2907,10 +2873,9 @@ static void nvme_remove(struct pci_dev *pdev)
        nvme_free_host_mem(dev);
        nvme_dev_remove_admin(dev);
        nvme_free_queues(dev, 0);
-       nvme_uninit_ctrl(&dev->ctrl);
        nvme_release_prp_pools(dev);
        nvme_dev_unmap(dev);
-       nvme_put_ctrl(&dev->ctrl);
+       nvme_uninit_ctrl(&dev->ctrl);
 }
 
 #ifdef CONFIG_PM_SLEEP
index 3e85c5c..86603d9 100644 (file)
@@ -850,9 +850,11 @@ out_free_tagset:
        if (new)
                blk_mq_free_tag_set(ctrl->ctrl.admin_tagset);
 out_free_async_qe:
-       nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe,
-               sizeof(struct nvme_command), DMA_TO_DEVICE);
-       ctrl->async_event_sqe.data = NULL;
+       if (ctrl->async_event_sqe.data) {
+               nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe,
+                       sizeof(struct nvme_command), DMA_TO_DEVICE);
+               ctrl->async_event_sqe.data = NULL;
+       }
 out_free_queue:
        nvme_rdma_free_queue(&ctrl->queues[0]);
        return error;
@@ -1022,8 +1024,13 @@ static int nvme_rdma_setup_ctrl(struct nvme_rdma_ctrl *ctrl, bool new)
 
        changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE);
        if (!changed) {
-               /* state change failure is ok if we're in DELETING state */
+               /*
+                * state change failure is ok if we're in DELETING state,
+                * unless we're during creation of a new controller to
+                * avoid races with teardown flow.
+                */
                WARN_ON_ONCE(ctrl->ctrl.state != NVME_CTRL_DELETING);
+               WARN_ON_ONCE(new);
                ret = -EINVAL;
                goto destroy_io;
        }
@@ -2043,8 +2050,6 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
        dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISpcs\n",
                ctrl->ctrl.opts->subsysnqn, &ctrl->addr);
 
-       nvme_get_ctrl(&ctrl->ctrl);
-
        mutex_lock(&nvme_rdma_ctrl_mutex);
        list_add_tail(&ctrl->list, &nvme_rdma_ctrl_list);
        mutex_unlock(&nvme_rdma_ctrl_mutex);
index 49d4373..0ef14f0 100644 (file)
 
 struct nvme_tcp_queue;
 
+/* Define the socket priority to use for connections were it is desirable
+ * that the NIC consider performing optimized packet processing or filtering.
+ * A non-zero value being sufficient to indicate general consideration of any
+ * possible optimization.  Making it a module param allows for alternative
+ * values that may be unique for some NIC implementations.
+ */
+static int so_priority;
+module_param(so_priority, int, 0644);
+MODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority");
+
 enum nvme_tcp_send_state {
        NVME_TCP_SEND_CMD_PDU = 0,
        NVME_TCP_SEND_H2C_PDU,
@@ -1017,8 +1027,15 @@ static int nvme_tcp_try_send(struct nvme_tcp_queue *queue)
        if (req->state == NVME_TCP_SEND_DDGST)
                ret = nvme_tcp_try_send_ddgst(req);
 done:
-       if (ret == -EAGAIN)
+       if (ret == -EAGAIN) {
                ret = 0;
+       } else if (ret < 0) {
+               dev_err(queue->ctrl->ctrl.device,
+                       "failed to send request %d\n", ret);
+               if (ret != -EPIPE && ret != -ECONNRESET)
+                       nvme_tcp_fail_request(queue->request);
+               nvme_tcp_done_send_req(queue);
+       }
        return ret;
 }
 
@@ -1049,25 +1066,16 @@ static void nvme_tcp_io_work(struct work_struct *w)
                int result;
 
                result = nvme_tcp_try_send(queue);
-               if (result > 0) {
+               if (result > 0)
                        pending = true;
-               } else if (unlikely(result < 0)) {
-                       dev_err(queue->ctrl->ctrl.device,
-                               "failed to send request %d\n", result);
-
-                       /*
-                        * Fail the request unless peer closed the connection,
-                        * in which case error recovery flow will complete all.
-                        */
-                       if ((result != -EPIPE) && (result != -ECONNRESET))
-                               nvme_tcp_fail_request(queue->request);
-                       nvme_tcp_done_send_req(queue);
-                       return;
-               }
+               else if (unlikely(result < 0))
+                       break;
 
                result = nvme_tcp_try_recv(queue);
                if (result > 0)
                        pending = true;
+               else if (unlikely(result < 0))
+                       break;
 
                if (!pending)
                        return;
@@ -1248,13 +1256,67 @@ free_icreq:
        return ret;
 }
 
+static bool nvme_tcp_admin_queue(struct nvme_tcp_queue *queue)
+{
+       return nvme_tcp_queue_id(queue) == 0;
+}
+
+static bool nvme_tcp_default_queue(struct nvme_tcp_queue *queue)
+{
+       struct nvme_tcp_ctrl *ctrl = queue->ctrl;
+       int qid = nvme_tcp_queue_id(queue);
+
+       return !nvme_tcp_admin_queue(queue) &&
+               qid < 1 + ctrl->io_queues[HCTX_TYPE_DEFAULT];
+}
+
+static bool nvme_tcp_read_queue(struct nvme_tcp_queue *queue)
+{
+       struct nvme_tcp_ctrl *ctrl = queue->ctrl;
+       int qid = nvme_tcp_queue_id(queue);
+
+       return !nvme_tcp_admin_queue(queue) &&
+               !nvme_tcp_default_queue(queue) &&
+               qid < 1 + ctrl->io_queues[HCTX_TYPE_DEFAULT] +
+                         ctrl->io_queues[HCTX_TYPE_READ];
+}
+
+static bool nvme_tcp_poll_queue(struct nvme_tcp_queue *queue)
+{
+       struct nvme_tcp_ctrl *ctrl = queue->ctrl;
+       int qid = nvme_tcp_queue_id(queue);
+
+       return !nvme_tcp_admin_queue(queue) &&
+               !nvme_tcp_default_queue(queue) &&
+               !nvme_tcp_read_queue(queue) &&
+               qid < 1 + ctrl->io_queues[HCTX_TYPE_DEFAULT] +
+                         ctrl->io_queues[HCTX_TYPE_READ] +
+                         ctrl->io_queues[HCTX_TYPE_POLL];
+}
+
+static void nvme_tcp_set_queue_io_cpu(struct nvme_tcp_queue *queue)
+{
+       struct nvme_tcp_ctrl *ctrl = queue->ctrl;
+       int qid = nvme_tcp_queue_id(queue);
+       int n = 0;
+
+       if (nvme_tcp_default_queue(queue))
+               n = qid - 1;
+       else if (nvme_tcp_read_queue(queue))
+               n = qid - ctrl->io_queues[HCTX_TYPE_DEFAULT] - 1;
+       else if (nvme_tcp_poll_queue(queue))
+               n = qid - ctrl->io_queues[HCTX_TYPE_DEFAULT] -
+                               ctrl->io_queues[HCTX_TYPE_READ] - 1;
+       queue->io_cpu = cpumask_next_wrap(n - 1, cpu_online_mask, -1, false);
+}
+
 static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
                int qid, size_t queue_size)
 {
        struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
        struct nvme_tcp_queue *queue = &ctrl->queues[qid];
        struct linger sol = { .l_onoff = 1, .l_linger = 0 };
-       int ret, opt, rcv_pdu_size, n;
+       int ret, opt, rcv_pdu_size;
 
        queue->ctrl = ctrl;
        INIT_LIST_HEAD(&queue->send_list);
@@ -1309,6 +1371,17 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
                goto err_sock;
        }
 
+       if (so_priority > 0) {
+               ret = kernel_setsockopt(queue->sock, SOL_SOCKET, SO_PRIORITY,
+                               (char *)&so_priority, sizeof(so_priority));
+               if (ret) {
+                       dev_err(ctrl->ctrl.device,
+                               "failed to set SO_PRIORITY sock opt, ret %d\n",
+                               ret);
+                       goto err_sock;
+               }
+       }
+
        /* Set socket type of service */
        if (nctrl->opts->tos >= 0) {
                opt = nctrl->opts->tos;
@@ -1322,11 +1395,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
        }
 
        queue->sock->sk->sk_allocation = GFP_ATOMIC;
-       if (!qid)
-               n = 0;
-       else
-               n = (qid - 1) % num_online_cpus();
-       queue->io_cpu = cpumask_next_wrap(n - 1, cpu_online_mask, -1, false);
+       nvme_tcp_set_queue_io_cpu(queue);
        queue->request = NULL;
        queue->data_remaining = 0;
        queue->ddgst_remaining = 0;
@@ -1861,8 +1930,13 @@ static int nvme_tcp_setup_ctrl(struct nvme_ctrl *ctrl, bool new)
        }
 
        if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) {
-               /* state change failure is ok if we're in DELETING state */
+               /*
+                * state change failure is ok if we're in DELETING state,
+                * unless we're during creation of a new controller to
+                * avoid races with teardown flow.
+                */
                WARN_ON_ONCE(ctrl->state != NVME_CTRL_DELETING);
+               WARN_ON_ONCE(new);
                ret = -EINVAL;
                goto destroy_io;
        }
@@ -2359,8 +2433,6 @@ static struct nvme_ctrl *nvme_tcp_create_ctrl(struct device *dev,
        dev_info(ctrl->ctrl.device, "new ctrl: NQN \"%s\", addr %pISp\n",
                ctrl->ctrl.opts->subsysnqn, &ctrl->addr);
 
-       nvme_get_ctrl(&ctrl->ctrl);
-
        mutex_lock(&nvme_tcp_ctrl_mutex);
        list_add_tail(&ctrl->list, &nvme_tcp_ctrl_list);
        mutex_unlock(&nvme_tcp_ctrl_mutex);
index 72a7e41..9d6f75c 100644 (file)
@@ -6,6 +6,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
 #include <linux/rculist.h>
+#include <linux/part_stat.h>
 
 #include <generated/utsrelease.h>
 #include <asm/unaligned.h>
@@ -322,12 +323,25 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
        nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR);
 }
 
+static void nvmet_id_set_model_number(struct nvme_id_ctrl *id,
+                                     struct nvmet_subsys *subsys)
+{
+       const char *model = NVMET_DEFAULT_CTRL_MODEL;
+       struct nvmet_subsys_model *subsys_model;
+
+       rcu_read_lock();
+       subsys_model = rcu_dereference(subsys->model);
+       if (subsys_model)
+               model = subsys_model->number;
+       memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
+       rcu_read_unlock();
+}
+
 static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 {
        struct nvmet_ctrl *ctrl = req->sq->ctrl;
        struct nvme_id_ctrl *id;
        u16 status = 0;
-       const char model[] = "Linux";
 
        id = kzalloc(sizeof(*id), GFP_KERNEL);
        if (!id) {
@@ -342,7 +356,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
        memset(id->sn, ' ', sizeof(id->sn));
        bin2hex(id->sn, &ctrl->subsys->serial,
                min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
-       memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
+       nvmet_id_set_model_number(id, ctrl->subsys);
        memcpy_and_pad(id->fr, sizeof(id->fr),
                       UTS_RELEASE, strlen(UTS_RELEASE), ' ');
 
@@ -356,8 +370,12 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
        /* we support multiple ports, multiples hosts and ANA: */
        id->cmic = (1 << 0) | (1 << 1) | (1 << 3);
 
-       /* no limit on data transfer sizes for now */
-       id->mdts = 0;
+       /* Limit MDTS according to transport capability */
+       if (ctrl->ops->get_mdts)
+               id->mdts = ctrl->ops->get_mdts(ctrl);
+       else
+               id->mdts = 0;
+
        id->cntlid = cpu_to_le16(ctrl->cntlid);
        id->ver = cpu_to_le32(ctrl->subsys->ver);
 
@@ -720,13 +738,22 @@ static void nvmet_execute_set_features(struct nvmet_req *req)
 {
        struct nvmet_subsys *subsys = req->sq->ctrl->subsys;
        u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10);
+       u32 cdw11 = le32_to_cpu(req->cmd->common.cdw11);
        u16 status = 0;
+       u16 nsqr;
+       u16 ncqr;
 
        if (!nvmet_check_data_len(req, 0))
                return;
 
        switch (cdw10 & 0xff) {
        case NVME_FEAT_NUM_QUEUES:
+               ncqr = (cdw11 >> 16) & 0xffff;
+               nsqr = cdw11 & 0xffff;
+               if (ncqr == 0xffff || nsqr == 0xffff) {
+                       status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
+                       break;
+               }
                nvmet_set_result(req,
                        (subsys->max_qid - 1) | ((subsys->max_qid - 1) << 16));
                break;
index 98613a4..7aa1078 100644 (file)
@@ -395,14 +395,12 @@ static ssize_t nvmet_ns_device_uuid_store(struct config_item *item,
        struct nvmet_subsys *subsys = ns->subsys;
        int ret = 0;
 
-
        mutex_lock(&subsys->lock);
        if (ns->enabled) {
                ret = -EBUSY;
                goto out_unlock;
        }
 
-
        if (uuid_parse(page, &ns->uuid))
                ret = -EINVAL;
 
@@ -815,10 +813,10 @@ static ssize_t nvmet_subsys_attr_version_show(struct config_item *item,
                                (int)NVME_MAJOR(subsys->ver),
                                (int)NVME_MINOR(subsys->ver),
                                (int)NVME_TERTIARY(subsys->ver));
-       else
-               return snprintf(page, PAGE_SIZE, "%d.%d\n",
-                               (int)NVME_MAJOR(subsys->ver),
-                               (int)NVME_MINOR(subsys->ver));
+
+       return snprintf(page, PAGE_SIZE, "%d.%d\n",
+                       (int)NVME_MAJOR(subsys->ver),
+                       (int)NVME_MINOR(subsys->ver));
 }
 
 static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
@@ -828,7 +826,6 @@ static ssize_t nvmet_subsys_attr_version_store(struct config_item *item,
        int major, minor, tertiary = 0;
        int ret;
 
-
        ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary);
        if (ret != 2 && ret != 3)
                return -EINVAL;
@@ -852,20 +849,151 @@ static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item,
 static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
                                              const char *page, size_t count)
 {
-       struct nvmet_subsys *subsys = to_subsys(item);
+       u64 serial;
+
+       if (sscanf(page, "%llx\n", &serial) != 1)
+               return -EINVAL;
 
        down_write(&nvmet_config_sem);
-       sscanf(page, "%llx\n", &subsys->serial);
+       to_subsys(item)->serial = serial;
        up_write(&nvmet_config_sem);
 
        return count;
 }
 CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
 
+static ssize_t nvmet_subsys_attr_cntlid_min_show(struct config_item *item,
+                                                char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->cntlid_min);
+}
+
+static ssize_t nvmet_subsys_attr_cntlid_min_store(struct config_item *item,
+                                                 const char *page, size_t cnt)
+{
+       u16 cntlid_min;
+
+       if (sscanf(page, "%hu\n", &cntlid_min) != 1)
+               return -EINVAL;
+
+       if (cntlid_min == 0)
+               return -EINVAL;
+
+       down_write(&nvmet_config_sem);
+       if (cntlid_min >= to_subsys(item)->cntlid_max)
+               goto out_unlock;
+       to_subsys(item)->cntlid_min = cntlid_min;
+       up_write(&nvmet_config_sem);
+       return cnt;
+
+out_unlock:
+       up_write(&nvmet_config_sem);
+       return -EINVAL;
+}
+CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_min);
+
+static ssize_t nvmet_subsys_attr_cntlid_max_show(struct config_item *item,
+                                                char *page)
+{
+       return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->cntlid_max);
+}
+
+static ssize_t nvmet_subsys_attr_cntlid_max_store(struct config_item *item,
+                                                 const char *page, size_t cnt)
+{
+       u16 cntlid_max;
+
+       if (sscanf(page, "%hu\n", &cntlid_max) != 1)
+               return -EINVAL;
+
+       if (cntlid_max == 0)
+               return -EINVAL;
+
+       down_write(&nvmet_config_sem);
+       if (cntlid_max <= to_subsys(item)->cntlid_min)
+               goto out_unlock;
+       to_subsys(item)->cntlid_max = cntlid_max;
+       up_write(&nvmet_config_sem);
+       return cnt;
+
+out_unlock:
+       up_write(&nvmet_config_sem);
+       return -EINVAL;
+}
+CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_max);
+
+static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
+                                           char *page)
+{
+       struct nvmet_subsys *subsys = to_subsys(item);
+       struct nvmet_subsys_model *subsys_model;
+       char *model = NVMET_DEFAULT_CTRL_MODEL;
+       int ret;
+
+       rcu_read_lock();
+       subsys_model = rcu_dereference(subsys->model);
+       if (subsys_model)
+               model = subsys_model->number;
+       ret = snprintf(page, PAGE_SIZE, "%s\n", model);
+       rcu_read_unlock();
+
+       return ret;
+}
+
+/* See Section 1.5 of NVMe 1.4 */
+static bool nvmet_is_ascii(const char c)
+{
+       return c >= 0x20 && c <= 0x7e;
+}
+
+static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
+                                            const char *page, size_t count)
+{
+       struct nvmet_subsys *subsys = to_subsys(item);
+       struct nvmet_subsys_model *new_model;
+       char *new_model_number;
+       int pos = 0, len;
+
+       len = strcspn(page, "\n");
+       if (!len)
+               return -EINVAL;
+
+       for (pos = 0; pos < len; pos++) {
+               if (!nvmet_is_ascii(page[pos]))
+                       return -EINVAL;
+       }
+
+       new_model_number = kstrndup(page, len, GFP_KERNEL);
+       if (!new_model_number)
+               return -ENOMEM;
+
+       new_model = kzalloc(sizeof(*new_model) + len + 1, GFP_KERNEL);
+       if (!new_model) {
+               kfree(new_model_number);
+               return -ENOMEM;
+       }
+       memcpy(new_model->number, new_model_number, len);
+
+       down_write(&nvmet_config_sem);
+       mutex_lock(&subsys->lock);
+       new_model = rcu_replace_pointer(subsys->model, new_model,
+                                       mutex_is_locked(&subsys->lock));
+       mutex_unlock(&subsys->lock);
+       up_write(&nvmet_config_sem);
+
+       kfree_rcu(new_model, rcuhead);
+
+       return count;
+}
+CONFIGFS_ATTR(nvmet_subsys_, attr_model);
+
 static struct configfs_attribute *nvmet_subsys_attrs[] = {
        &nvmet_subsys_attr_attr_allow_any_host,
        &nvmet_subsys_attr_attr_version,
        &nvmet_subsys_attr_attr_serial,
+       &nvmet_subsys_attr_attr_cntlid_min,
+       &nvmet_subsys_attr_attr_cntlid_max,
+       &nvmet_subsys_attr_attr_model,
        NULL,
 };
 
index 576de77..b685f99 100644 (file)
@@ -1289,8 +1289,11 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
        if (!ctrl->sqs)
                goto out_free_cqs;
 
+       if (subsys->cntlid_min > subsys->cntlid_max)
+               goto out_free_cqs;
+
        ret = ida_simple_get(&cntlid_ida,
-                            NVME_CNTLID_MIN, NVME_CNTLID_MAX,
+                            subsys->cntlid_min, subsys->cntlid_max,
                             GFP_KERNEL);
        if (ret < 0) {
                status = NVME_SC_CONNECT_CTRL_BUSY | NVME_SC_DNR;
@@ -1438,7 +1441,8 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
                kfree(subsys);
                return ERR_PTR(-ENOMEM);
        }
-
+       subsys->cntlid_min = NVME_CNTLID_MIN;
+       subsys->cntlid_max = NVME_CNTLID_MAX;
        kref_init(&subsys->ref);
 
        mutex_init(&subsys->lock);
@@ -1457,6 +1461,7 @@ static void nvmet_subsys_free(struct kref *ref)
        WARN_ON_ONCE(!list_empty(&subsys->namespaces));
 
        kfree(subsys->subsysnqn);
+       kfree_rcu(subsys->model, rcuhead);
        kfree(subsys);
 }
 
index 4df4ebd..0d54e73 100644 (file)
@@ -485,7 +485,6 @@ out_destroy_admin:
 out_disable:
        dev_warn(ctrl->ctrl.device, "Removing after reset failure\n");
        nvme_uninit_ctrl(&ctrl->ctrl);
-       nvme_put_ctrl(&ctrl->ctrl);
 }
 
 static const struct nvme_ctrl_ops nvme_loop_ctrl_ops = {
@@ -618,8 +617,6 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
        dev_info(ctrl->ctrl.device,
                 "new ctrl: \"%s\"\n", ctrl->ctrl.opts->subsysnqn);
 
-       nvme_get_ctrl(&ctrl->ctrl);
-
        changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE);
        WARN_ON_ONCE(!changed);
 
index eda28b2..421dff3 100644 (file)
@@ -23,6 +23,7 @@
 #define NVMET_ASYNC_EVENTS             4
 #define NVMET_ERROR_LOG_SLOTS          128
 #define NVMET_NO_ERROR_LOC             ((u16)-1)
+#define NVMET_DEFAULT_CTRL_MODEL       "Linux"
 
 /*
  * Supported optional AENs:
@@ -202,6 +203,11 @@ struct nvmet_ctrl {
        struct nvme_error_slot  slots[NVMET_ERROR_LOG_SLOTS];
 };
 
+struct nvmet_subsys_model {
+       struct rcu_head         rcuhead;
+       char                    number[];
+};
+
 struct nvmet_subsys {
        enum nvme_subsys_type   type;
 
@@ -211,6 +217,8 @@ struct nvmet_subsys {
        struct list_head        namespaces;
        unsigned int            nr_namespaces;
        unsigned int            max_nsid;
+       u16                     cntlid_min;
+       u16                     cntlid_max;
 
        struct list_head        ctrls;
 
@@ -227,6 +235,8 @@ struct nvmet_subsys {
 
        struct config_group     namespaces_group;
        struct config_group     allowed_hosts_group;
+
+       struct nvmet_subsys_model       __rcu *model;
 };
 
 static inline struct nvmet_subsys *to_subsys(struct config_item *item)
@@ -279,6 +289,7 @@ struct nvmet_fabrics_ops {
                        struct nvmet_port *port, char *traddr);
        u16 (*install_queue)(struct nvmet_sq *nvme_sq);
        void (*discovery_chg)(struct nvmet_port *port);
+       u8 (*get_mdts)(const struct nvmet_ctrl *ctrl);
 };
 
 #define NVMET_MAX_INLINE_BIOVEC        8
index 37d262a..9e1b8c6 100644 (file)
@@ -31,6 +31,9 @@
 #define NVMET_RDMA_MAX_INLINE_SGE              4
 #define NVMET_RDMA_MAX_INLINE_DATA_SIZE                max_t(int, SZ_16K, PAGE_SIZE)
 
+/* Assume mpsmin == device_page_size == 4KB */
+#define NVMET_RDMA_MAX_MDTS                    8
+
 struct nvmet_rdma_cmd {
        struct ib_sge           sge[NVMET_RDMA_MAX_INLINE_SGE + 1];
        struct ib_cqe           cqe;
@@ -975,7 +978,7 @@ static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue)
 {
        struct ib_qp_init_attr qp_attr;
        struct nvmet_rdma_device *ndev = queue->dev;
-       int comp_vector, nr_cqe, ret, i;
+       int comp_vector, nr_cqe, ret, i, factor;
 
        /*
         * Spread the io queues across completion vectors,
@@ -1008,7 +1011,9 @@ static int nvmet_rdma_create_queue_ib(struct nvmet_rdma_queue *queue)
        qp_attr.qp_type = IB_QPT_RC;
        /* +1 for drain */
        qp_attr.cap.max_send_wr = queue->send_queue_size + 1;
-       qp_attr.cap.max_rdma_ctxs = queue->send_queue_size;
+       factor = rdma_rw_mr_factor(ndev->device, queue->cm_id->port_num,
+                                  1 << NVMET_RDMA_MAX_MDTS);
+       qp_attr.cap.max_rdma_ctxs = queue->send_queue_size * factor;
        qp_attr.cap.max_send_sge = max(ndev->device->attrs.max_sge_rd,
                                        ndev->device->attrs.max_send_sge);
 
@@ -1602,6 +1607,11 @@ static void nvmet_rdma_disc_port_addr(struct nvmet_req *req,
        }
 }
 
+static u8 nvmet_rdma_get_mdts(const struct nvmet_ctrl *ctrl)
+{
+       return NVMET_RDMA_MAX_MDTS;
+}
+
 static const struct nvmet_fabrics_ops nvmet_rdma_ops = {
        .owner                  = THIS_MODULE,
        .type                   = NVMF_TRTYPE_RDMA,
@@ -1612,6 +1622,7 @@ static const struct nvmet_fabrics_ops nvmet_rdma_ops = {
        .queue_response         = nvmet_rdma_queue_response,
        .delete_ctrl            = nvmet_rdma_delete_ctrl,
        .disc_traddr            = nvmet_rdma_disc_port_addr,
+       .get_mdts               = nvmet_rdma_get_mdts,
 };
 
 static void nvmet_rdma_remove_one(struct ib_device *ib_device, void *client_data)
index af674fc..f0da04e 100644 (file)
 
 #define NVMET_TCP_DEF_INLINE_DATA_SIZE (4 * PAGE_SIZE)
 
+/* Define the socket priority to use for connections were it is desirable
+ * that the NIC consider performing optimized packet processing or filtering.
+ * A non-zero value being sufficient to indicate general consideration of any
+ * possible optimization.  Making it a module param allows for alternative
+ * values that may be unique for some NIC implementations.
+ */
+static int so_priority;
+module_param(so_priority, int, 0644);
+MODULE_PARM_DESC(so_priority, "nvmet tcp socket optimize priority");
+
 #define NVMET_TCP_RECV_BUDGET          8
 #define NVMET_TCP_SEND_BUDGET          8
 #define NVMET_TCP_IO_WORK_BUDGET       64
@@ -515,7 +525,7 @@ static int nvmet_try_send_data_pdu(struct nvmet_tcp_cmd *cmd)
        return 1;
 }
 
-static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd)
+static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd, bool last_in_batch)
 {
        struct nvmet_tcp_queue *queue = cmd->queue;
        int ret;
@@ -523,9 +533,15 @@ static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd)
        while (cmd->cur_sg) {
                struct page *page = sg_page(cmd->cur_sg);
                u32 left = cmd->cur_sg->length - cmd->offset;
+               int flags = MSG_DONTWAIT;
+
+               if ((!last_in_batch && cmd->queue->send_list_len) ||
+                   cmd->wbytes_done + left < cmd->req.transfer_len ||
+                   queue->data_digest || !queue->nvme_sq.sqhd_disabled)
+                       flags |= MSG_MORE;
 
                ret = kernel_sendpage(cmd->queue->sock, page, cmd->offset,
-                                       left, MSG_DONTWAIT | MSG_MORE);
+                                       left, flags);
                if (ret <= 0)
                        return ret;
 
@@ -616,7 +632,7 @@ static int nvmet_try_send_r2t(struct nvmet_tcp_cmd *cmd, bool last_in_batch)
        return 1;
 }
 
-static int nvmet_try_send_ddgst(struct nvmet_tcp_cmd *cmd)
+static int nvmet_try_send_ddgst(struct nvmet_tcp_cmd *cmd, bool last_in_batch)
 {
        struct nvmet_tcp_queue *queue = cmd->queue;
        struct msghdr msg = { .msg_flags = MSG_DONTWAIT };
@@ -626,6 +642,9 @@ static int nvmet_try_send_ddgst(struct nvmet_tcp_cmd *cmd)
        };
        int ret;
 
+       if (!last_in_batch && cmd->queue->send_list_len)
+               msg.msg_flags |= MSG_MORE;
+
        ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
        if (unlikely(ret <= 0))
                return ret;
@@ -660,13 +679,13 @@ static int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue,
        }
 
        if (cmd->state == NVMET_TCP_SEND_DATA) {
-               ret = nvmet_try_send_data(cmd);
+               ret = nvmet_try_send_data(cmd, last_in_batch);
                if (ret <= 0)
                        goto done_send;
        }
 
        if (cmd->state == NVMET_TCP_SEND_DDGST) {
-               ret = nvmet_try_send_ddgst(cmd);
+               ret = nvmet_try_send_ddgst(cmd, last_in_batch);
                if (ret <= 0)
                        goto done_send;
        }
@@ -788,7 +807,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)
        icresp->hdr.pdo = 0;
        icresp->hdr.plen = cpu_to_le32(icresp->hdr.hlen);
        icresp->pfv = cpu_to_le16(NVME_TCP_PFV_1_0);
-       icresp->maxdata = cpu_to_le32(0xffff); /* FIXME: support r2t */
+       icresp->maxdata = cpu_to_le32(0x400000); /* 16M arbitrary limit */
        icresp->cpda = 0;
        if (queue->hdr_digest)
                icresp->digest |= NVME_TCP_HDR_DIGEST_ENABLE;
@@ -1433,6 +1452,13 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
        if (ret)
                return ret;
 
+       if (so_priority > 0) {
+               ret = kernel_setsockopt(sock, SOL_SOCKET, SO_PRIORITY,
+                               (char *)&so_priority, sizeof(so_priority));
+               if (ret)
+                       return ret;
+       }
+
        /* Set socket type of service */
        if (inet->rcv_tos > 0) {
                int tos = inet->rcv_tos;
@@ -1622,6 +1648,15 @@ static int nvmet_tcp_add_port(struct nvmet_port *nport)
                goto err_sock;
        }
 
+       if (so_priority > 0) {
+               ret = kernel_setsockopt(port->sock, SOL_SOCKET, SO_PRIORITY,
+                               (char *)&so_priority, sizeof(so_priority));
+               if (ret) {
+                       pr_err("failed to set SO_PRIORITY sock opt %d\n", ret);
+                       goto err_sock;
+               }
+       }
+
        ret = kernel_bind(port->sock, (struct sockaddr *)&port->addr,
                        sizeof(port->addr));
        if (ret) {
index 8270bbf..9f982c0 100644 (file)
@@ -306,6 +306,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
                                rc = of_mdiobus_register_phy(mdio, child, addr);
                                if (rc && rc != -ENODEV)
                                        goto unregister;
+                               break;
                        }
                }
        }
index e851c57..f104f15 100644 (file)
@@ -1262,7 +1262,7 @@ static int of_link_property(struct device *dev, struct device_node *con_np,
        u32 dl_flags;
 
        if (dev->of_node == con_np)
-               dl_flags = DL_FLAG_AUTOPROBE_CONSUMER;
+               dl_flags = fw_devlink_get_flags();
        else
                dl_flags = DL_FLAG_SYNC_STATE_ONLY;
 
@@ -1299,15 +1299,9 @@ static int of_link_to_suppliers(struct device *dev,
        return ret;
 }
 
-static bool of_devlink;
-core_param(of_devlink, of_devlink, bool, 0);
-
 static int of_fwnode_add_links(const struct fwnode_handle *fwnode,
                               struct device *dev)
 {
-       if (!of_devlink)
-               return 0;
-
        if (unlikely(!is_of_node(fwnode)))
                return 0;
 
index d20aabc..3a10e67 100644 (file)
@@ -670,7 +670,7 @@ static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie,
         *   outbound memory @ 3GB). So instead it will  start at the 1x
         *   multiple of its size
         */
-       if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size ||
+       if (!*rc_bar2_size || (*rc_bar2_offset & (*rc_bar2_size - 1)) ||
            (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) {
                dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n",
                        *rc_bar2_size, *rc_bar2_offset);
index 30fbe2e..aafd58d 100644 (file)
@@ -55,15 +55,13 @@ static const struct pci_platform_pm_ops mid_pci_platform_pm = {
        .need_resume    = mid_pci_need_resume,
 };
 
-#define ICPU(model)    { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
-
 /*
  * This table should be in sync with the one in
  * arch/x86/platform/intel-mid/pwr.c.
  */
 static const struct x86_cpu_id lpss_cpu_ids[] = {
-       ICPU(INTEL_FAM6_ATOM_SALTWELL_MID),
-       ICPU(INTEL_FAM6_ATOM_SILVERMONT_MID),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_MID, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, NULL),
        {}
 };
 
index 6e3c04b..7876dc4 100644 (file)
@@ -34,6 +34,7 @@ config PCIEAER
 config PCIEAER_INJECT
        tristate "PCI Express error injection support"
        depends on PCIEAER
+       select GENERIC_IRQ_INJECTION
        help
          This enables PCI Express Root Port Advanced Error Reporting
          (AER) software error injector.
index 6988fe7..21cc3d3 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
 #include <linux/miscdevice.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
@@ -468,9 +468,7 @@ static int aer_inject(struct aer_error_inj *einj)
                }
                pci_info(edev->port, "Injecting errors %08x/%08x into device %s\n",
                         einj->cor_status, einj->uncor_status, pci_name(dev));
-               local_irq_disable();
-               generic_handle_irq(edev->irq);
-               local_irq_enable();
+               ret = irq_inject_interrupt(edev->irq);
        } else {
                pci_err(rpdev, "AER device not found\n");
                ret = -ENODEV;
index a823b4b..e69cac8 100644 (file)
@@ -52,10 +52,11 @@ struct switchtec_user {
 
        enum mrpc_state state;
 
-       struct completion comp;
+       wait_queue_head_t cmd_comp;
        struct kref kref;
        struct list_head list;
 
+       bool cmd_done;
        u32 cmd;
        u32 status;
        u32 return_code;
@@ -77,7 +78,7 @@ static struct switchtec_user *stuser_create(struct switchtec_dev *stdev)
        stuser->stdev = stdev;
        kref_init(&stuser->kref);
        INIT_LIST_HEAD(&stuser->list);
-       init_completion(&stuser->comp);
+       init_waitqueue_head(&stuser->cmd_comp);
        stuser->event_cnt = atomic_read(&stdev->event_cnt);
 
        dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser);
@@ -175,7 +176,7 @@ static int mrpc_queue_cmd(struct switchtec_user *stuser)
        kref_get(&stuser->kref);
        stuser->read_len = sizeof(stuser->data);
        stuser_set_state(stuser, MRPC_QUEUED);
-       init_completion(&stuser->comp);
+       stuser->cmd_done = false;
        list_add_tail(&stuser->list, &stdev->mrpc_queue);
 
        mrpc_cmd_submit(stdev);
@@ -222,7 +223,8 @@ static void mrpc_complete_cmd(struct switchtec_dev *stdev)
                memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data,
                              stuser->read_len);
 out:
-       complete_all(&stuser->comp);
+       stuser->cmd_done = true;
+       wake_up_interruptible(&stuser->cmd_comp);
        list_del_init(&stuser->list);
        stuser_put(stuser);
        stdev->mrpc_busy = 0;
@@ -529,10 +531,11 @@ static ssize_t switchtec_dev_read(struct file *filp, char __user *data,
        mutex_unlock(&stdev->mrpc_mutex);
 
        if (filp->f_flags & O_NONBLOCK) {
-               if (!try_wait_for_completion(&stuser->comp))
+               if (!stuser->cmd_done)
                        return -EAGAIN;
        } else {
-               rc = wait_for_completion_interruptible(&stuser->comp);
+               rc = wait_event_interruptible(stuser->cmd_comp,
+                                             stuser->cmd_done);
                if (rc < 0)
                        return rc;
        }
@@ -580,7 +583,7 @@ static __poll_t switchtec_dev_poll(struct file *filp, poll_table *wait)
        struct switchtec_dev *stdev = stuser->stdev;
        __poll_t ret = 0;
 
-       poll_wait(filp, &stuser->comp.wait, wait);
+       poll_wait(filp, &stuser->cmd_comp, wait);
        poll_wait(filp, &stdev->event_wq, wait);
 
        if (lock_mutex_and_test_alive(stdev))
@@ -588,7 +591,7 @@ static __poll_t switchtec_dev_poll(struct file *filp, poll_table *wait)
 
        mutex_unlock(&stdev->mrpc_mutex);
 
-       if (try_wait_for_completion(&stuser->comp))
+       if (stuser->cmd_done)
                ret |= EPOLLIN | EPOLLRDNORM;
 
        if (stuser->event_cnt != atomic_read(&stdev->event_cnt))
@@ -1272,7 +1275,8 @@ static void stdev_kill(struct switchtec_dev *stdev)
 
        /* Wake up and kill any users waiting on an MRPC request */
        list_for_each_entry_safe(stuser, tmpuser, &stdev->mrpc_queue, list) {
-               complete_all(&stuser->comp);
+               stuser->cmd_done = true;
+               wake_up_interruptible(&stuser->cmd_comp);
                list_del_init(&stuser->list);
                stuser_put(stuser);
        }
index fea354d..d50edef 100644 (file)
@@ -328,15 +328,15 @@ static ssize_t arm_ccn_pmu_event_show(struct device *dev,
                        struct arm_ccn_pmu_event, attr);
        ssize_t res;
 
-       res = snprintf(buf, PAGE_SIZE, "type=0x%x", event->type);
+       res = scnprintf(buf, PAGE_SIZE, "type=0x%x", event->type);
        if (event->event)
-               res += snprintf(buf + res, PAGE_SIZE - res, ",event=0x%x",
+               res += scnprintf(buf + res, PAGE_SIZE - res, ",event=0x%x",
                                event->event);
        if (event->def)
-               res += snprintf(buf + res, PAGE_SIZE - res, ",%s",
+               res += scnprintf(buf + res, PAGE_SIZE - res, ",%s",
                                event->def);
        if (event->mask)
-               res += snprintf(buf + res, PAGE_SIZE - res, ",mask=0x%x",
+               res += scnprintf(buf + res, PAGE_SIZE - res, ",mask=0x%x",
                                event->mask);
 
        /* Arguments required by an event */
@@ -344,25 +344,25 @@ static ssize_t arm_ccn_pmu_event_show(struct device *dev,
        case CCN_TYPE_CYCLES:
                break;
        case CCN_TYPE_XP:
-               res += snprintf(buf + res, PAGE_SIZE - res,
+               res += scnprintf(buf + res, PAGE_SIZE - res,
                                ",xp=?,vc=?");
                if (event->event == CCN_EVENT_WATCHPOINT)
-                       res += snprintf(buf + res, PAGE_SIZE - res,
+                       res += scnprintf(buf + res, PAGE_SIZE - res,
                                        ",port=?,dir=?,cmp_l=?,cmp_h=?,mask=?");
                else
-                       res += snprintf(buf + res, PAGE_SIZE - res,
+                       res += scnprintf(buf + res, PAGE_SIZE - res,
                                        ",bus=?");
 
                break;
        case CCN_TYPE_MN:
-               res += snprintf(buf + res, PAGE_SIZE - res, ",node=%d", ccn->mn_id);
+               res += scnprintf(buf + res, PAGE_SIZE - res, ",node=%d", ccn->mn_id);
                break;
        default:
-               res += snprintf(buf + res, PAGE_SIZE - res, ",node=?");
+               res += scnprintf(buf + res, PAGE_SIZE - res, ",node=?");
                break;
        }
 
-       res += snprintf(buf + res, PAGE_SIZE - res, "\n");
+       res += scnprintf(buf + res, PAGE_SIZE - res, "\n");
 
        return res;
 }
index acce878..f5c7a84 100644 (file)
@@ -24,8 +24,6 @@ static int arm_pmu_acpi_register_irq(int cpu)
        int gsi, trigger;
 
        gicc = acpi_cpu_get_madt_gicc(cpu);
-       if (WARN_ON(!gicc))
-               return -EINVAL;
 
        gsi = gicc->performance_interrupt;
 
@@ -64,11 +62,10 @@ static void arm_pmu_acpi_unregister_irq(int cpu)
        int gsi;
 
        gicc = acpi_cpu_get_madt_gicc(cpu);
-       if (!gicc)
-               return;
 
        gsi = gicc->performance_interrupt;
-       acpi_unregister_gsi(gsi);
+       if (gsi)
+               acpi_unregister_gsi(gsi);
 }
 
 #if IS_ENABLED(CONFIG_ARM_SPE_PMU)
index 4e4984a..b72c048 100644 (file)
@@ -831,7 +831,7 @@ static void *arm_spe_pmu_setup_aux(struct perf_event *event, void **pages,
         * parts and give userspace a fighting chance of getting some
         * useful data out of it.
         */
-       if (!nr_pages || (snapshot && (nr_pages & 1)))
+       if (snapshot && (nr_pages & 1))
                return NULL;
 
        if (cpu == -1)
index 95dca2c..90884d1 100644 (file)
@@ -388,9 +388,10 @@ static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config,
 
        if (enable) {
                /*
-                * must disable first, then enable again
-                * otherwise, cycle counter will not work
-                * if previous state is enabled.
+                * cycle counter is special which should firstly write 0 then
+                * write 1 into CLEAR bit to clear it. Other counters only
+                * need write 0 into CLEAR bit and it turns out to be 1 by
+                * hardware. Below enable flow is harmless for all counters.
                 */
                writel(0, pmu->base + reg);
                val = CNTL_EN | CNTL_CLEAR;
@@ -398,7 +399,8 @@ static void ddr_perf_counter_enable(struct ddr_pmu *pmu, int config,
                writel(val, pmu->base + reg);
        } else {
                /* Disable counter */
-               writel(0, pmu->base + reg);
+               val = readl_relaxed(pmu->base + reg) & CNTL_EN_MASK;
+               writel(val, pmu->base + reg);
        }
 }
 
index 1169f3e..b1c04f7 100644 (file)
@@ -49,7 +49,7 @@
 #define SUNXI_LOS_BIAS(n)              ((n) << 3)
 #define SUNXI_LOS_BIAS_MASK            GENMASK(5, 3)
 #define SUNXI_TXVBOOSTLVL(n)           ((n) << 0)
-#define SUNXI_TXVBOOSTLVL_MASK         GENMASK(0, 2)
+#define SUNXI_TXVBOOSTLVL_MASK         GENMASK(2, 0)
 
 struct sun50i_usb3_phy {
        struct phy *phy;
index 9065ffc..b26e30e 100644 (file)
@@ -66,7 +66,7 @@
 #define PHY_CTRL_R14                                           0x38
        #define PHY_CTRL_R14_I_RDP_EN                           BIT(0)
        #define PHY_CTRL_R14_I_RPU_SW1_EN                       BIT(1)
-       #define PHY_CTRL_R14_I_RPU_SW2_EN                       GENMASK(2, 3)
+       #define PHY_CTRL_R14_I_RPU_SW2_EN                       GENMASK(3, 2)
        #define PHY_CTRL_R14_PG_RSTN                            BIT(4)
        #define PHY_CTRL_R14_I_C2L_DATA_16_8                    BIT(5)
        #define PHY_CTRL_R14_I_C2L_ASSERT_SINGLE_EN_ZERO        BIT(6)
 #define RESET_COMPLETE_TIME                                    1000
 #define PLL_RESET_COMPLETE_TIME                                        100
 
+enum meson_soc_id {
+       MESON_SOC_G12A  = 0,
+       MESON_SOC_A1,
+};
+
 struct phy_meson_g12a_usb2_priv {
        struct device           *dev;
        struct regmap           *regmap;
        struct clk              *clk;
        struct reset_control    *reset;
+       int                     soc_id;
 };
 
 static const struct regmap_config phy_meson_g12a_usb2_regmap_conf = {
@@ -164,6 +170,7 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
 {
        struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy);
        int ret;
+       unsigned int value;
 
        ret = reset_control_reset(priv->reset);
        if (ret)
@@ -192,18 +199,22 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
                     FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) |
                     FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9));
 
-       regmap_write(priv->regmap, PHY_CTRL_R18,
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) |
-                    FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) |
-                    PHY_CTRL_R18_MPLL_ACG_RANGE);
+       value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) |
+               FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) |
+               PHY_CTRL_R18_MPLL_ACG_RANGE;
+
+       if (priv->soc_id == MESON_SOC_A1)
+               value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL;
+
+       regmap_write(priv->regmap, PHY_CTRL_R18, value);
 
        udelay(PLL_RESET_COMPLETE_TIME);
 
@@ -227,13 +238,24 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
                     FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) |
                     FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0));
 
-       regmap_write(priv->regmap, PHY_CTRL_R4,
-                    FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) |
-                    FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) |
-                    FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) |
-                    PHY_CTRL_R4_TEST_BYPASS_MODE_EN |
-                    FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) |
-                    FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
+       if (priv->soc_id == MESON_SOC_G12A)
+               regmap_write(priv->regmap, PHY_CTRL_R4,
+                            FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) |
+                            FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) |
+                            FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) |
+                            PHY_CTRL_R4_TEST_BYPASS_MODE_EN |
+                            FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) |
+                            FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
+       else if (priv->soc_id == MESON_SOC_A1) {
+               regmap_write(priv->regmap, PHY_CTRL_R21,
+                            PHY_CTRL_R21_USB2_CAL_ACK_EN |
+                            PHY_CTRL_R21_USB2_TX_STRG_PD |
+                            FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2));
+
+               /* Analog Settings */
+               regmap_write(priv->regmap, PHY_CTRL_R13,
+                            FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
+       }
 
        /* Tuning Disconnect Threshold */
        regmap_write(priv->regmap, PHY_CTRL_R3,
@@ -241,11 +263,13 @@ static int phy_meson_g12a_usb2_init(struct phy *phy)
                     FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) |
                     FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3));
 
-       /* Analog Settings */
-       regmap_write(priv->regmap, PHY_CTRL_R14, 0);
-       regmap_write(priv->regmap, PHY_CTRL_R13,
-                    PHY_CTRL_R13_UPDATE_PMA_SIGNALS |
-                    FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
+       if (priv->soc_id == MESON_SOC_G12A) {
+               /* Analog Settings */
+               regmap_write(priv->regmap, PHY_CTRL_R14, 0);
+               regmap_write(priv->regmap, PHY_CTRL_R13,
+                            PHY_CTRL_R13_UPDATE_PMA_SIGNALS |
+                            FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
+       }
 
        return 0;
 }
@@ -286,6 +310,8 @@ static int phy_meson_g12a_usb2_probe(struct platform_device *pdev)
        if (IS_ERR(base))
                return PTR_ERR(base);
 
+       priv->soc_id = (enum meson_soc_id)of_device_get_match_data(&pdev->dev);
+
        priv->regmap = devm_regmap_init_mmio(dev, base,
                                             &phy_meson_g12a_usb2_regmap_conf);
        if (IS_ERR(priv->regmap))
@@ -321,8 +347,15 @@ static int phy_meson_g12a_usb2_probe(struct platform_device *pdev)
 }
 
 static const struct of_device_id phy_meson_g12a_usb2_of_match[] = {
-       { .compatible = "amlogic,g12a-usb2-phy", },
-       { },
+       {
+               .compatible = "amlogic,g12a-usb2-phy",
+               .data = (void *)MESON_SOC_G12A,
+       },
+       {
+               .compatible = "amlogic,a1-usb2-phy",
+               .data = (void *)MESON_SOC_A1,
+       },
+       { /* Sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, phy_meson_g12a_usb2_of_match);
 
index 4710cfc..18251f2 100644 (file)
@@ -186,29 +186,6 @@ enum sata_phy_ctrl_regs {
        PHY_CTRL_1_RESET                        = BIT(0),
 };
 
-static inline void __iomem *brcm_sata_pcb_base(struct brcm_sata_port *port)
-{
-       struct brcm_sata_phy *priv = port->phy_priv;
-       u32 size = 0;
-
-       switch (priv->version) {
-       case BRCM_SATA_PHY_STB_16NM:
-       case BRCM_SATA_PHY_STB_28NM:
-       case BRCM_SATA_PHY_IPROC_NS2:
-       case BRCM_SATA_PHY_DSL_28NM:
-               size = SATA_PCB_REG_28NM_SPACE_SIZE;
-               break;
-       case BRCM_SATA_PHY_STB_40NM:
-               size = SATA_PCB_REG_40NM_SPACE_SIZE;
-               break;
-       default:
-               dev_err(priv->dev, "invalid phy version\n");
-               break;
-       }
-
-       return priv->phy_base + (port->portnum * size);
-}
-
 static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port)
 {
        struct brcm_sata_phy *priv = port->phy_priv;
@@ -226,19 +203,34 @@ static inline void __iomem *brcm_sata_ctrl_base(struct brcm_sata_port *port)
        return priv->ctrl_base + (port->portnum * size);
 }
 
-static void brcm_sata_phy_wr(void __iomem *pcb_base, u32 bank,
+static void brcm_sata_phy_wr(struct brcm_sata_port *port, u32 bank,
                             u32 ofs, u32 msk, u32 value)
 {
+       struct brcm_sata_phy *priv = port->phy_priv;
+       void __iomem *pcb_base = priv->phy_base;
        u32 tmp;
 
+       if (priv->version == BRCM_SATA_PHY_STB_40NM)
+               bank += (port->portnum * SATA_PCB_REG_40NM_SPACE_SIZE);
+       else
+               pcb_base += (port->portnum * SATA_PCB_REG_28NM_SPACE_SIZE);
+
        writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
        tmp = readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
        tmp = (tmp & msk) | value;
        writel(tmp, pcb_base + SATA_PCB_REG_OFFSET(ofs));
 }
 
-static u32 brcm_sata_phy_rd(void __iomem *pcb_base, u32 bank, u32 ofs)
+static u32 brcm_sata_phy_rd(struct brcm_sata_port *port, u32 bank, u32 ofs)
 {
+       struct brcm_sata_phy *priv = port->phy_priv;
+       void __iomem *pcb_base = priv->phy_base;
+
+       if (priv->version == BRCM_SATA_PHY_STB_40NM)
+               bank += (port->portnum * SATA_PCB_REG_40NM_SPACE_SIZE);
+       else
+               pcb_base += (port->portnum * SATA_PCB_REG_28NM_SPACE_SIZE);
+
        writel(bank, pcb_base + SATA_PCB_BANK_OFFSET);
        return readl(pcb_base + SATA_PCB_REG_OFFSET(ofs));
 }
@@ -250,16 +242,15 @@ static u32 brcm_sata_phy_rd(void __iomem *pcb_base, u32 bank, u32 ofs)
 
 static void brcm_stb_sata_ssc_init(struct brcm_sata_port *port)
 {
-       void __iomem *base = brcm_sata_pcb_base(port);
        struct brcm_sata_phy *priv = port->phy_priv;
        u32 tmp;
 
        /* override the TX spread spectrum setting */
        tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
-       brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
+       brcm_sata_phy_wr(port, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
 
        /* set fixed min freq */
-       brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
+       brcm_sata_phy_wr(port, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
                         ~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
                         STB_FMIN_VAL_DEFAULT);
 
@@ -271,7 +262,7 @@ static void brcm_stb_sata_ssc_init(struct brcm_sata_port *port)
                tmp = STB_FMAX_VAL_DEFAULT;
        }
 
-       brcm_sata_phy_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
+       brcm_sata_phy_wr(port, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
                          ~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
 }
 
@@ -280,7 +271,6 @@ static void brcm_stb_sata_ssc_init(struct brcm_sata_port *port)
 
 static int brcm_stb_sata_rxaeq_init(struct brcm_sata_port *port)
 {
-       void __iomem *base = brcm_sata_pcb_base(port);
        u32 tmp = 0, reg = 0;
 
        switch (port->rxaeq_mode) {
@@ -301,8 +291,8 @@ static int brcm_stb_sata_rxaeq_init(struct brcm_sata_port *port)
                break;
        }
 
-       brcm_sata_phy_wr(base, AEQRX_REG_BANK_0, reg, ~tmp, tmp);
-       brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, reg, ~tmp, tmp);
+       brcm_sata_phy_wr(port, AEQRX_REG_BANK_0, reg, ~tmp, tmp);
+       brcm_sata_phy_wr(port, AEQRX_REG_BANK_1, reg, ~tmp, tmp);
 
        return 0;
 }
@@ -316,18 +306,17 @@ static int brcm_stb_sata_init(struct brcm_sata_port *port)
 
 static int brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port *port)
 {
-       void __iomem *base = brcm_sata_pcb_base(port);
        u32 tmp, value;
 
        /* Reduce CP tail current to 1/16th of its default value */
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0x141);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0x141);
 
        /* Turn off CP tail current boost */
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL8, 0, 0xc006);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL8, 0, 0xc006);
 
        /* Set a specific AEQ equalizer value */
        tmp = AEQ_FRC_EQ_FORCE_VAL | AEQ_FRC_EQ_FORCE;
-       brcm_sata_phy_wr(base, AEQRX_REG_BANK_0, AEQ_FRC_EQ,
+       brcm_sata_phy_wr(port, AEQRX_REG_BANK_0, AEQ_FRC_EQ,
                         ~(tmp | AEQ_RFZ_FRC_VAL |
                           AEQ_FRC_EQ_VAL_MASK << AEQ_FRC_EQ_VAL_SHIFT),
                         tmp | 32 << AEQ_FRC_EQ_VAL_SHIFT);
@@ -337,7 +326,7 @@ static int brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port *port)
                value = 0x52;
        else
                value = 0;
-       brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_CDR_CONTROL1,
+       brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_CDR_CONTROL1,
                         ~RXPMD_RX_PPM_VAL_MASK, value);
 
        /* Set proportional loop bandwith Gen1/2/3 */
@@ -352,7 +341,7 @@ static int brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port *port)
                value = 1 << RXPMD_G1_CDR_PROP_BW_SHIFT |
                        1 << RXPMD_G2_CDR_PROP_BW_SHIFT |
                        1 << RXPMD_G3_CDR_PROB_BW_SHIFT;
-       brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_PROP_BW, ~tmp,
+       brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_PROP_BW, ~tmp,
                         value);
 
        /* Set CDR integral loop acquisition bandwidth for Gen1/2/3 */
@@ -365,7 +354,7 @@ static int brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port *port)
                        1 << RXPMD_G3_CDR_ACQ_INT_BW_SHIFT;
        else
                value = 0;
-       brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_ACQ_INTEG_BW,
+       brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_ACQ_INTEG_BW,
                         ~tmp, value);
 
        /* Set CDR integral loop locking bandwidth to 1 for Gen 1/2/3 */
@@ -378,7 +367,7 @@ static int brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port *port)
                        1 << RXPMD_G3_CDR_LOCK_INT_BW_SHIFT;
        else
                value = 0;
-       brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_LOCK_INTEG_BW,
+       brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_CDR_CDR_LOCK_INTEG_BW,
                         ~tmp, value);
 
        /* Set no guard band and clamp CDR */
@@ -387,11 +376,11 @@ static int brcm_stb_sata_16nm_ssc_init(struct brcm_sata_port *port)
                value = 0x51;
        else
                value = 0;
-       brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_FREQ_MON_CONTROL1,
+       brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_FREQ_MON_CONTROL1,
                         ~tmp, RXPMD_MON_CORRECT_EN | value);
 
        /* Turn on/off SSC */
-       brcm_sata_phy_wr(base, TX_REG_BANK, TX_ACTRL5, ~TX_ACTRL5_SSC_EN,
+       brcm_sata_phy_wr(port, TX_REG_BANK, TX_ACTRL5, ~TX_ACTRL5_SSC_EN,
                         port->ssc_en ? TX_ACTRL5_SSC_EN : 0);
 
        return 0;
@@ -411,7 +400,6 @@ static int brcm_ns2_sata_init(struct brcm_sata_port *port)
 {
        int try;
        unsigned int val;
-       void __iomem *base = brcm_sata_pcb_base(port);
        void __iomem *ctrl_base = brcm_sata_ctrl_base(port);
        struct device *dev = port->phy_priv->dev;
 
@@ -421,24 +409,24 @@ static int brcm_ns2_sata_init(struct brcm_sata_port *port)
        val |= (0x4 << OOB_CTRL1_BURST_MIN_SHIFT);
        val |= (0x9 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT);
        val |= (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT);
-       brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
+       brcm_sata_phy_wr(port, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
        val = 0x0;
        val |= (0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT);
        val |= (0x2 << OOB_CTRL2_BURST_CNT_SHIFT);
        val |= (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT);
-       brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
+       brcm_sata_phy_wr(port, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
 
        /* Configure PHY PLL register bank 1 */
        val = NS2_PLL1_ACTRL2_MAGIC;
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
        val = NS2_PLL1_ACTRL3_MAGIC;
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
        val = NS2_PLL1_ACTRL4_MAGIC;
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
 
        /* Configure PHY BLOCK0 register bank */
        /* Set oob_clk_sel to refclk/2 */
-       brcm_sata_phy_wr(base, BLOCK0_REG_BANK, BLOCK0_SPARE,
+       brcm_sata_phy_wr(port, BLOCK0_REG_BANK, BLOCK0_SPARE,
                         ~BLOCK0_SPARE_OOB_CLK_SEL_MASK,
                         BLOCK0_SPARE_OOB_CLK_SEL_REFBY2);
 
@@ -451,7 +439,7 @@ static int brcm_ns2_sata_init(struct brcm_sata_port *port)
        /* Wait for PHY PLL lock by polling pll_lock bit */
        try = 50;
        while (try) {
-               val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
+               val = brcm_sata_phy_rd(port, BLOCK0_REG_BANK,
                                        BLOCK0_XGXSSTATUS);
                if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
                        break;
@@ -471,9 +459,7 @@ static int brcm_ns2_sata_init(struct brcm_sata_port *port)
 
 static int brcm_nsp_sata_init(struct brcm_sata_port *port)
 {
-       struct brcm_sata_phy *priv = port->phy_priv;
        struct device *dev = port->phy_priv->dev;
-       void __iomem *base = priv->phy_base;
        unsigned int oob_bank;
        unsigned int val, try;
 
@@ -490,36 +476,36 @@ static int brcm_nsp_sata_init(struct brcm_sata_port *port)
        val |= (0x06 << OOB_CTRL1_BURST_MIN_SHIFT);
        val |= (0x0f << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT);
        val |= (0x06 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT);
-       brcm_sata_phy_wr(base, oob_bank, OOB_CTRL1, 0x0, val);
+       brcm_sata_phy_wr(port, oob_bank, OOB_CTRL1, 0x0, val);
 
        val = 0x0;
        val |= (0x2e << OOB_CTRL2_RESET_IDLE_MAX_SHIFT);
        val |= (0x02 << OOB_CTRL2_BURST_CNT_SHIFT);
        val |= (0x16 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT);
-       brcm_sata_phy_wr(base, oob_bank, OOB_CTRL2, 0x0, val);
+       brcm_sata_phy_wr(port, oob_bank, OOB_CTRL2, 0x0, val);
 
 
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_ACTRL2,
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_ACTRL2,
                ~(PLL_ACTRL2_SELDIV_MASK << PLL_ACTRL2_SELDIV_SHIFT),
                0x0c << PLL_ACTRL2_SELDIV_SHIFT);
 
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_CAP_CONTROL,
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_CAP_CONTROL,
                                                0xff0, 0x4f0);
 
        val = PLLCONTROL_0_FREQ_DET_RESTART | PLLCONTROL_0_FREQ_MONITOR;
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
                                                                ~val, val);
        val = PLLCONTROL_0_SEQ_START;
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
                                                                ~val, 0);
        mdelay(10);
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
                                                                ~val, val);
 
        /* Wait for pll_seq_done bit */
        try = 50;
        while (--try) {
-               val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
+               val = brcm_sata_phy_rd(port, BLOCK0_REG_BANK,
                                        BLOCK0_XGXSSTATUS);
                if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
                        break;
@@ -546,27 +532,25 @@ static int brcm_nsp_sata_init(struct brcm_sata_port *port)
 
 static int brcm_sr_sata_init(struct brcm_sata_port *port)
 {
-       struct brcm_sata_phy *priv = port->phy_priv;
        struct device *dev = port->phy_priv->dev;
-       void __iomem *base = priv->phy_base;
        unsigned int val, try;
 
        /* Configure PHY PLL register bank 1 */
        val = SR_PLL1_ACTRL2_MAGIC;
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val);
        val = SR_PLL1_ACTRL3_MAGIC;
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val);
        val = SR_PLL1_ACTRL4_MAGIC;
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val);
 
        /* Configure PHY PLL register bank 0 */
        val = SR_PLL0_ACTRL6_MAGIC;
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_ACTRL6, 0x0, val);
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_ACTRL6, 0x0, val);
 
        /* Wait for PHY PLL lock by polling pll_lock bit */
        try = 50;
        do {
-               val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
+               val = brcm_sata_phy_rd(port, BLOCK0_REG_BANK,
                                        BLOCK0_XGXSSTATUS);
                if (val & BLOCK0_XGXSSTATUS_PLL_LOCK)
                        break;
@@ -581,7 +565,7 @@ static int brcm_sr_sata_init(struct brcm_sata_port *port)
        }
 
        /* Invert Tx polarity */
-       brcm_sata_phy_wr(base, TX_REG_BANK, TX_ACTRL0,
+       brcm_sata_phy_wr(port, TX_REG_BANK, TX_ACTRL0,
                         ~TX_ACTRL0_TXPOL_FLIP, TX_ACTRL0_TXPOL_FLIP);
 
        /* Configure OOB control to handle 100MHz reference clock */
@@ -589,52 +573,51 @@ static int brcm_sr_sata_init(struct brcm_sata_port *port)
                (0x4 << OOB_CTRL1_BURST_MIN_SHIFT) |
                (0x8 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT) |
                (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT));
-       brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
+       brcm_sata_phy_wr(port, OOB_REG_BANK, OOB_CTRL1, 0x0, val);
        val = ((0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT) |
                (0x2 << OOB_CTRL2_BURST_CNT_SHIFT) |
                (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT));
-       brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
+       brcm_sata_phy_wr(port, OOB_REG_BANK, OOB_CTRL2, 0x0, val);
 
        return 0;
 }
 
 static int brcm_dsl_sata_init(struct brcm_sata_port *port)
 {
-       void __iomem *base = brcm_sata_pcb_base(port);
        struct device *dev = port->phy_priv->dev;
        unsigned int try;
        u32 tmp;
 
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL7, 0, 0x873);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL7, 0, 0x873);
 
-       brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0xc000);
+       brcm_sata_phy_wr(port, PLL1_REG_BANK, PLL1_ACTRL6, 0, 0xc000);
 
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
                         0, 0x3089);
        usleep_range(1000, 2000);
 
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_REG_BANK_0_PLLCONTROL_0,
                         0, 0x3088);
        usleep_range(1000, 2000);
 
-       brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL0_CTRL0,
+       brcm_sata_phy_wr(port, AEQRX_REG_BANK_1, AEQRX_SLCAL0_CTRL0,
                         0, 0x3000);
 
-       brcm_sata_phy_wr(base, AEQRX_REG_BANK_1, AEQRX_SLCAL1_CTRL0,
+       brcm_sata_phy_wr(port, AEQRX_REG_BANK_1, AEQRX_SLCAL1_CTRL0,
                         0, 0x3000);
        usleep_range(1000, 2000);
 
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_CAP_CHARGE_TIME, 0, 0x32);
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_CAP_CHARGE_TIME, 0, 0x32);
 
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_VCO_CAL_THRESH, 0, 0xa);
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_VCO_CAL_THRESH, 0, 0xa);
 
-       brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_FREQ_DET_TIME, 0, 0x64);
+       brcm_sata_phy_wr(port, PLL_REG_BANK_0, PLL_FREQ_DET_TIME, 0, 0x64);
        usleep_range(1000, 2000);
 
        /* Acquire PLL lock */
        try = 50;
        while (try) {
-               tmp = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,
+               tmp = brcm_sata_phy_rd(port, BLOCK0_REG_BANK,
                                       BLOCK0_XGXSSTATUS);
                if (tmp & BLOCK0_XGXSSTATUS_PLL_LOCK)
                        break;
@@ -687,10 +670,9 @@ static int brcm_sata_phy_init(struct phy *phy)
 
 static void brcm_stb_sata_calibrate(struct brcm_sata_port *port)
 {
-       void __iomem *base = brcm_sata_pcb_base(port);
        u32 tmp = BIT(8);
 
-       brcm_sata_phy_wr(base, RXPMD_REG_BANK, RXPMD_RX_FREQ_MON_CONTROL1,
+       brcm_sata_phy_wr(port, RXPMD_REG_BANK, RXPMD_RX_FREQ_MON_CONTROL1,
                         ~tmp, tmp);
 }
 
index b2db916..4595458 100644 (file)
@@ -3,13 +3,13 @@
 # Phy drivers for Cadence PHYs
 #
 
-config PHY_CADENCE_DP
-       tristate "Cadence MHDP DisplayPort PHY driver"
+config PHY_CADENCE_TORRENT
+       tristate "Cadence Torrent PHY driver"
        depends on OF
        depends on HAS_IOMEM
        select GENERIC_PHY
        help
-         Support for Cadence MHDP DisplayPort PHY.
+         Support for Cadence Torrent PHY.
 
 config PHY_CADENCE_DPHY
        tristate "Cadence D-PHY Support"
index 8f89560..6a7ffc6 100644 (file)
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_PHY_CADENCE_DP)   += phy-cadence-dp.o
+obj-$(CONFIG_PHY_CADENCE_TORRENT)      += phy-cadence-torrent.o
 obj-$(CONFIG_PHY_CADENCE_DPHY) += cdns-dphy.o
 obj-$(CONFIG_PHY_CADENCE_SIERRA)       += phy-cadence-sierra.o
diff --git a/drivers/phy/cadence/phy-cadence-dp.c b/drivers/phy/cadence/phy-cadence-dp.c
deleted file mode 100644 (file)
index bc10cb2..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Cadence MHDP DisplayPort SD0801 PHY driver.
- *
- * Copyright 2018 Cadence Design Systems, Inc.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_device.h>
-#include <linux/phy/phy.h>
-#include <linux/platform_device.h>
-
-#define DEFAULT_NUM_LANES      2
-#define MAX_NUM_LANES          4
-#define DEFAULT_MAX_BIT_RATE   8100 /* in Mbps */
-
-#define POLL_TIMEOUT_US                2000
-#define LANE_MASK              0x7
-
-/*
- * register offsets from DPTX PHY register block base (i.e MHDP
- * register base + 0x30a00)
- */
-#define PHY_AUX_CONFIG                 0x00
-#define PHY_AUX_CTRL                   0x04
-#define PHY_RESET                      0x20
-#define PHY_PMA_XCVR_PLLCLK_EN         0x24
-#define PHY_PMA_XCVR_PLLCLK_EN_ACK     0x28
-#define PHY_PMA_XCVR_POWER_STATE_REQ   0x2c
-#define PHY_POWER_STATE_LN_0   0x0000
-#define PHY_POWER_STATE_LN_1   0x0008
-#define PHY_POWER_STATE_LN_2   0x0010
-#define PHY_POWER_STATE_LN_3   0x0018
-#define PHY_PMA_XCVR_POWER_STATE_ACK   0x30
-#define PHY_PMA_CMN_READY              0x34
-#define PHY_PMA_XCVR_TX_VMARGIN                0x38
-#define PHY_PMA_XCVR_TX_DEEMPH         0x3c
-
-/*
- * register offsets from SD0801 PHY register block base (i.e MHDP
- * register base + 0x500000)
- */
-#define CMN_SSM_BANDGAP_TMR            0x00084
-#define CMN_SSM_BIAS_TMR               0x00088
-#define CMN_PLLSM0_PLLPRE_TMR          0x000a8
-#define CMN_PLLSM0_PLLLOCK_TMR         0x000b0
-#define CMN_PLLSM1_PLLPRE_TMR          0x000c8
-#define CMN_PLLSM1_PLLLOCK_TMR         0x000d0
-#define CMN_BGCAL_INIT_TMR             0x00190
-#define CMN_BGCAL_ITER_TMR             0x00194
-#define CMN_IBCAL_INIT_TMR             0x001d0
-#define CMN_PLL0_VCOCAL_INIT_TMR       0x00210
-#define CMN_PLL0_VCOCAL_ITER_TMR       0x00214
-#define CMN_PLL0_VCOCAL_REFTIM_START   0x00218
-#define CMN_PLL0_VCOCAL_PLLCNT_START   0x00220
-#define CMN_PLL0_INTDIV_M0             0x00240
-#define CMN_PLL0_FRACDIVL_M0           0x00244
-#define CMN_PLL0_FRACDIVH_M0           0x00248
-#define CMN_PLL0_HIGH_THR_M0           0x0024c
-#define CMN_PLL0_DSM_DIAG_M0           0x00250
-#define CMN_PLL0_LOCK_PLLCNT_START     0x00278
-#define CMN_PLL1_VCOCAL_INIT_TMR       0x00310
-#define CMN_PLL1_VCOCAL_ITER_TMR       0x00314
-#define CMN_PLL1_DSM_DIAG_M0           0x00350
-#define CMN_TXPUCAL_INIT_TMR           0x00410
-#define CMN_TXPUCAL_ITER_TMR           0x00414
-#define CMN_TXPDCAL_INIT_TMR           0x00430
-#define CMN_TXPDCAL_ITER_TMR           0x00434
-#define CMN_RXCAL_INIT_TMR             0x00450
-#define CMN_RXCAL_ITER_TMR             0x00454
-#define CMN_SD_CAL_INIT_TMR            0x00490
-#define CMN_SD_CAL_ITER_TMR            0x00494
-#define CMN_SD_CAL_REFTIM_START                0x00498
-#define CMN_SD_CAL_PLLCNT_START                0x004a0
-#define CMN_PDIAG_PLL0_CTRL_M0         0x00680
-#define CMN_PDIAG_PLL0_CLK_SEL_M0      0x00684
-#define CMN_PDIAG_PLL0_CP_PADJ_M0      0x00690
-#define CMN_PDIAG_PLL0_CP_IADJ_M0      0x00694
-#define CMN_PDIAG_PLL0_FILT_PADJ_M0    0x00698
-#define CMN_PDIAG_PLL0_CP_PADJ_M1      0x006d0
-#define CMN_PDIAG_PLL0_CP_IADJ_M1      0x006d4
-#define CMN_PDIAG_PLL1_CLK_SEL_M0      0x00704
-#define XCVR_DIAG_PLLDRC_CTRL          0x10394
-#define XCVR_DIAG_HSCLK_SEL            0x10398
-#define XCVR_DIAG_HSCLK_DIV            0x1039c
-#define TX_PSC_A0                      0x10400
-#define TX_PSC_A1                      0x10404
-#define TX_PSC_A2                      0x10408
-#define TX_PSC_A3                      0x1040c
-#define RX_PSC_A0                      0x20000
-#define RX_PSC_A1                      0x20004
-#define RX_PSC_A2                      0x20008
-#define RX_PSC_A3                      0x2000c
-#define PHY_PLL_CFG                    0x30038
-
-struct cdns_dp_phy {
-       void __iomem *base;     /* DPTX registers base */
-       void __iomem *sd_base; /* SD0801 registers base */
-       u32 num_lanes; /* Number of lanes to use */
-       u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */
-       struct device *dev;
-};
-
-static int cdns_dp_phy_init(struct phy *phy);
-static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy);
-static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy);
-static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy);
-static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy);
-static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy,
-                                        unsigned int lane);
-static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy);
-static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy);
-static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy,
-                                       unsigned int offset,
-                                       unsigned char start_bit,
-                                       unsigned char num_bits,
-                                       unsigned int val);
-
-static const struct phy_ops cdns_dp_phy_ops = {
-       .init           = cdns_dp_phy_init,
-       .owner          = THIS_MODULE,
-};
-
-static int cdns_dp_phy_init(struct phy *phy)
-{
-       unsigned char lane_bits;
-
-       struct cdns_dp_phy *cdns_phy = phy_get_drvdata(phy);
-
-       writel(0x0003, cdns_phy->base + PHY_AUX_CTRL); /* enable AUX */
-
-       /* PHY PMA registers configuration function */
-       cdns_dp_phy_pma_cfg(cdns_phy);
-
-       /*
-        * Set lines power state to A0
-        * Set lines pll clk enable to 0
-        */
-
-       cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_POWER_STATE_REQ,
-                               PHY_POWER_STATE_LN_0, 6, 0x0000);
-
-       if (cdns_phy->num_lanes >= 2) {
-               cdns_dp_phy_write_field(cdns_phy,
-                                       PHY_PMA_XCVR_POWER_STATE_REQ,
-                                       PHY_POWER_STATE_LN_1, 6, 0x0000);
-
-               if (cdns_phy->num_lanes == 4) {
-                       cdns_dp_phy_write_field(cdns_phy,
-                                               PHY_PMA_XCVR_POWER_STATE_REQ,
-                                               PHY_POWER_STATE_LN_2, 6, 0);
-                       cdns_dp_phy_write_field(cdns_phy,
-                                               PHY_PMA_XCVR_POWER_STATE_REQ,
-                                               PHY_POWER_STATE_LN_3, 6, 0);
-               }
-       }
-
-       cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN,
-                               0, 1, 0x0000);
-
-       if (cdns_phy->num_lanes >= 2) {
-               cdns_dp_phy_write_field(cdns_phy, PHY_PMA_XCVR_PLLCLK_EN,
-                                       1, 1, 0x0000);
-               if (cdns_phy->num_lanes == 4) {
-                       cdns_dp_phy_write_field(cdns_phy,
-                                               PHY_PMA_XCVR_PLLCLK_EN,
-                                               2, 1, 0x0000);
-                       cdns_dp_phy_write_field(cdns_phy,
-                                               PHY_PMA_XCVR_PLLCLK_EN,
-                                               3, 1, 0x0000);
-               }
-       }
-
-       /*
-        * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on
-        * used lanes
-        */
-       lane_bits = (1 << cdns_phy->num_lanes) - 1;
-       writel(((0xF & ~lane_bits) << 4) | (0xF & lane_bits),
-                  cdns_phy->base + PHY_RESET);
-
-       /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
-       writel(0x0001, cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN);
-
-       /* PHY PMA registers configuration functions */
-       cdns_dp_phy_pma_cmn_vco_cfg_25mhz(cdns_phy);
-       cdns_dp_phy_pma_cmn_rate(cdns_phy);
-
-       /* take out of reset */
-       cdns_dp_phy_write_field(cdns_phy, PHY_RESET, 8, 1, 1);
-       cdns_dp_phy_wait_pma_cmn_ready(cdns_phy);
-       cdns_dp_phy_run(cdns_phy);
-
-       return 0;
-}
-
-static void cdns_dp_phy_wait_pma_cmn_ready(struct cdns_dp_phy *cdns_phy)
-{
-       unsigned int reg;
-       int ret;
-
-       ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_CMN_READY, reg,
-                                reg & 1, 0, 500);
-       if (ret == -ETIMEDOUT)
-               dev_err(cdns_phy->dev,
-                       "timeout waiting for PMA common ready\n");
-}
-
-static void cdns_dp_phy_pma_cfg(struct cdns_dp_phy *cdns_phy)
-{
-       unsigned int i;
-
-       /* PMA common configuration */
-       cdns_dp_phy_pma_cmn_cfg_25mhz(cdns_phy);
-
-       /* PMA lane configuration to deal with multi-link operation */
-       for (i = 0; i < cdns_phy->num_lanes; i++)
-               cdns_dp_phy_pma_lane_cfg(cdns_phy, i);
-}
-
-static void cdns_dp_phy_pma_cmn_cfg_25mhz(struct cdns_dp_phy *cdns_phy)
-{
-       /* refclock registers - assumes 25 MHz refclock */
-       writel(0x0019, cdns_phy->sd_base + CMN_SSM_BIAS_TMR);
-       writel(0x0032, cdns_phy->sd_base + CMN_PLLSM0_PLLPRE_TMR);
-       writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM0_PLLLOCK_TMR);
-       writel(0x0032, cdns_phy->sd_base + CMN_PLLSM1_PLLPRE_TMR);
-       writel(0x00D1, cdns_phy->sd_base + CMN_PLLSM1_PLLLOCK_TMR);
-       writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_INIT_TMR);
-       writel(0x007D, cdns_phy->sd_base + CMN_BGCAL_ITER_TMR);
-       writel(0x0019, cdns_phy->sd_base + CMN_IBCAL_INIT_TMR);
-       writel(0x001E, cdns_phy->sd_base + CMN_TXPUCAL_INIT_TMR);
-       writel(0x0006, cdns_phy->sd_base + CMN_TXPUCAL_ITER_TMR);
-       writel(0x001E, cdns_phy->sd_base + CMN_TXPDCAL_INIT_TMR);
-       writel(0x0006, cdns_phy->sd_base + CMN_TXPDCAL_ITER_TMR);
-       writel(0x02EE, cdns_phy->sd_base + CMN_RXCAL_INIT_TMR);
-       writel(0x0006, cdns_phy->sd_base + CMN_RXCAL_ITER_TMR);
-       writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_INIT_TMR);
-       writel(0x0002, cdns_phy->sd_base + CMN_SD_CAL_ITER_TMR);
-       writel(0x000E, cdns_phy->sd_base + CMN_SD_CAL_REFTIM_START);
-       writel(0x012B, cdns_phy->sd_base + CMN_SD_CAL_PLLCNT_START);
-       /* PLL registers */
-       writel(0x0409, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_PADJ_M0);
-       writel(0x1001, cdns_phy->sd_base + CMN_PDIAG_PLL0_CP_IADJ_M0);
-       writel(0x0F08, cdns_phy->sd_base + CMN_PDIAG_PLL0_FILT_PADJ_M0);
-       writel(0x0004, cdns_phy->sd_base + CMN_PLL0_DSM_DIAG_M0);
-       writel(0x00FA, cdns_phy->sd_base + CMN_PLL0_VCOCAL_INIT_TMR);
-       writel(0x0004, cdns_phy->sd_base + CMN_PLL0_VCOCAL_ITER_TMR);
-       writel(0x00FA, cdns_phy->sd_base + CMN_PLL1_VCOCAL_INIT_TMR);
-       writel(0x0004, cdns_phy->sd_base + CMN_PLL1_VCOCAL_ITER_TMR);
-       writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_REFTIM_START);
-}
-
-static void cdns_dp_phy_pma_cmn_vco_cfg_25mhz(struct cdns_dp_phy *cdns_phy)
-{
-       /* Assumes 25 MHz refclock */
-       switch (cdns_phy->max_bit_rate) {
-               /* Setting VCO for 10.8GHz */
-       case 2700:
-       case 5400:
-               writel(0x01B0, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
-               writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
-               writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
-               writel(0x0120, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
-               break;
-               /* Setting VCO for 9.72GHz */
-       case 2430:
-       case 3240:
-               writel(0x0184, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
-               writel(0xCCCD, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
-               writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
-               writel(0x0104, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
-               break;
-               /* Setting VCO for 8.64GHz */
-       case 2160:
-       case 4320:
-               writel(0x0159, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
-               writel(0x999A, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
-               writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
-               writel(0x00E7, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
-               break;
-               /* Setting VCO for 8.1GHz */
-       case 8100:
-               writel(0x0144, cdns_phy->sd_base + CMN_PLL0_INTDIV_M0);
-               writel(0x0000, cdns_phy->sd_base + CMN_PLL0_FRACDIVL_M0);
-               writel(0x0002, cdns_phy->sd_base + CMN_PLL0_FRACDIVH_M0);
-               writel(0x00D8, cdns_phy->sd_base + CMN_PLL0_HIGH_THR_M0);
-               break;
-       }
-
-       writel(0x0002, cdns_phy->sd_base + CMN_PDIAG_PLL0_CTRL_M0);
-       writel(0x0318, cdns_phy->sd_base + CMN_PLL0_VCOCAL_PLLCNT_START);
-}
-
-static void cdns_dp_phy_pma_cmn_rate(struct cdns_dp_phy *cdns_phy)
-{
-       unsigned int clk_sel_val = 0;
-       unsigned int hsclk_div_val = 0;
-       unsigned int i;
-
-       /* 16'h0000 for single DP link configuration */
-       writel(0x0000, cdns_phy->sd_base + PHY_PLL_CFG);
-
-       switch (cdns_phy->max_bit_rate) {
-       case 1620:
-               clk_sel_val = 0x0f01;
-               hsclk_div_val = 2;
-               break;
-       case 2160:
-       case 2430:
-       case 2700:
-               clk_sel_val = 0x0701;
-                hsclk_div_val = 1;
-               break;
-       case 3240:
-               clk_sel_val = 0x0b00;
-               hsclk_div_val = 2;
-               break;
-       case 4320:
-       case 5400:
-               clk_sel_val = 0x0301;
-               hsclk_div_val = 0;
-               break;
-       case 8100:
-               clk_sel_val = 0x0200;
-               hsclk_div_val = 0;
-               break;
-       }
-
-       writel(clk_sel_val, cdns_phy->sd_base + CMN_PDIAG_PLL0_CLK_SEL_M0);
-
-       /* PMA lane configuration to deal with multi-link operation */
-       for (i = 0; i < cdns_phy->num_lanes; i++) {
-               writel(hsclk_div_val,
-                      cdns_phy->sd_base + (XCVR_DIAG_HSCLK_DIV | (i<<11)));
-       }
-}
-
-static void cdns_dp_phy_pma_lane_cfg(struct cdns_dp_phy *cdns_phy,
-                                    unsigned int lane)
-{
-       unsigned int lane_bits = (lane & LANE_MASK) << 11;
-
-       /* Writing Tx/Rx Power State Controllers registers */
-       writel(0x00FB, cdns_phy->sd_base + (TX_PSC_A0 | lane_bits));
-       writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A2 | lane_bits));
-       writel(0x04AA, cdns_phy->sd_base + (TX_PSC_A3 | lane_bits));
-       writel(0x0000, cdns_phy->sd_base + (RX_PSC_A0 | lane_bits));
-       writel(0x0000, cdns_phy->sd_base + (RX_PSC_A2 | lane_bits));
-       writel(0x0000, cdns_phy->sd_base + (RX_PSC_A3 | lane_bits));
-
-       writel(0x0001, cdns_phy->sd_base + (XCVR_DIAG_PLLDRC_CTRL | lane_bits));
-       writel(0x0000, cdns_phy->sd_base + (XCVR_DIAG_HSCLK_SEL | lane_bits));
-}
-
-static void cdns_dp_phy_run(struct cdns_dp_phy *cdns_phy)
-{
-       unsigned int read_val;
-       u32 write_val1 = 0;
-       u32 write_val2 = 0;
-       u32 mask = 0;
-       int ret;
-
-       /*
-        * waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the
-        * master lane
-        */
-       ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_PLLCLK_EN_ACK,
-                                read_val, read_val & 1, 0, POLL_TIMEOUT_US);
-       if (ret == -ETIMEDOUT)
-               dev_err(cdns_phy->dev,
-                       "timeout waiting for link PLL clock enable ack\n");
-
-       ndelay(100);
-
-       switch (cdns_phy->num_lanes) {
-
-       case 1: /* lane 0 */
-               write_val1 = 0x00000004;
-               write_val2 = 0x00000001;
-               mask = 0x0000003f;
-               break;
-       case 2: /* lane 0-1 */
-               write_val1 = 0x00000404;
-               write_val2 = 0x00000101;
-               mask = 0x00003f3f;
-               break;
-       case 4: /* lane 0-3 */
-               write_val1 = 0x04040404;
-               write_val2 = 0x01010101;
-               mask = 0x3f3f3f3f;
-               break;
-       }
-
-       writel(write_val1, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
-
-       ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK,
-                                read_val, (read_val & mask) == write_val1, 0,
-                                POLL_TIMEOUT_US);
-       if (ret == -ETIMEDOUT)
-               dev_err(cdns_phy->dev,
-                       "timeout waiting for link power state ack\n");
-
-       writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
-       ndelay(100);
-
-       writel(write_val2, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
-
-       ret = readl_poll_timeout(cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_ACK,
-                                read_val, (read_val & mask) == write_val2, 0,
-                                POLL_TIMEOUT_US);
-       if (ret == -ETIMEDOUT)
-               dev_err(cdns_phy->dev,
-                       "timeout waiting for link power state ack\n");
-
-       writel(0, cdns_phy->base + PHY_PMA_XCVR_POWER_STATE_REQ);
-       ndelay(100);
-}
-
-static void cdns_dp_phy_write_field(struct cdns_dp_phy *cdns_phy,
-                                   unsigned int offset,
-                                   unsigned char start_bit,
-                                   unsigned char num_bits,
-                                   unsigned int val)
-{
-       unsigned int read_val;
-
-       read_val = readl(cdns_phy->base + offset);
-       writel(((val << start_bit) | (read_val & ~(((1 << num_bits) - 1) <<
-               start_bit))), cdns_phy->base + offset);
-}
-
-static int cdns_dp_phy_probe(struct platform_device *pdev)
-{
-       struct resource *regs;
-       struct cdns_dp_phy *cdns_phy;
-       struct device *dev = &pdev->dev;
-       struct phy_provider *phy_provider;
-       struct phy *phy;
-       int err;
-
-       cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL);
-       if (!cdns_phy)
-               return -ENOMEM;
-
-       cdns_phy->dev = &pdev->dev;
-
-       phy = devm_phy_create(dev, NULL, &cdns_dp_phy_ops);
-       if (IS_ERR(phy)) {
-               dev_err(dev, "failed to create DisplayPort PHY\n");
-               return PTR_ERR(phy);
-       }
-
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       cdns_phy->base = devm_ioremap_resource(&pdev->dev, regs);
-       if (IS_ERR(cdns_phy->base))
-               return PTR_ERR(cdns_phy->base);
-
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       cdns_phy->sd_base = devm_ioremap_resource(&pdev->dev, regs);
-       if (IS_ERR(cdns_phy->sd_base))
-               return PTR_ERR(cdns_phy->sd_base);
-
-       err = device_property_read_u32(dev, "num_lanes",
-                                      &(cdns_phy->num_lanes));
-       if (err)
-               cdns_phy->num_lanes = DEFAULT_NUM_LANES;
-
-       switch (cdns_phy->num_lanes) {
-       case 1:
-       case 2:
-       case 4:
-               /* valid number of lanes */
-               break;
-       default:
-               dev_err(dev, "unsupported number of lanes: %d\n",
-                       cdns_phy->num_lanes);
-               return -EINVAL;
-       }
-
-       err = device_property_read_u32(dev, "max_bit_rate",
-                  &(cdns_phy->max_bit_rate));
-       if (err)
-               cdns_phy->max_bit_rate = DEFAULT_MAX_BIT_RATE;
-
-       switch (cdns_phy->max_bit_rate) {
-       case 2160:
-       case 2430:
-       case 2700:
-       case 3240:
-       case 4320:
-       case 5400:
-       case 8100:
-               /* valid bit rate */
-               break;
-       default:
-               dev_err(dev, "unsupported max bit rate: %dMbps\n",
-                       cdns_phy->max_bit_rate);
-               return -EINVAL;
-       }
-
-       phy_set_drvdata(phy, cdns_phy);
-
-       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-
-       dev_info(dev, "%d lanes, max bit rate %d.%03d Gbps\n",
-                cdns_phy->num_lanes,
-                cdns_phy->max_bit_rate / 1000,
-                cdns_phy->max_bit_rate % 1000);
-
-       return PTR_ERR_OR_ZERO(phy_provider);
-}
-
-static const struct of_device_id cdns_dp_phy_of_match[] = {
-       {
-               .compatible = "cdns,dp-phy"
-       },
-       {}
-};
-MODULE_DEVICE_TABLE(of, cdns_dp_phy_of_match);
-
-static struct platform_driver cdns_dp_phy_driver = {
-       .probe  = cdns_dp_phy_probe,
-       .driver = {
-               .name   = "cdns-dp-phy",
-               .of_match_table = cdns_dp_phy_of_match,
-       }
-};
-module_platform_driver(cdns_dp_phy_driver);
-
-MODULE_AUTHOR("Cadence Design Systems, Inc.");
-MODULE_DESCRIPTION("Cadence MHDP PHY driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
new file mode 100644 (file)
index 0000000..7116127
--- /dev/null
@@ -0,0 +1,1944 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cadence Torrent SD0801 PHY driver.
+ *
+ * Copyright 2018 Cadence Design Systems, Inc.
+ *
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+#define REF_CLK_19_2MHz                19200000
+#define REF_CLK_25MHz          25000000
+
+#define DEFAULT_NUM_LANES      4
+#define MAX_NUM_LANES          4
+#define DEFAULT_MAX_BIT_RATE   8100 /* in Mbps */
+
+#define POLL_TIMEOUT_US                5000
+
+#define TORRENT_COMMON_CDB_OFFSET      0x0
+
+#define TORRENT_TX_LANE_CDB_OFFSET(ln, block_offset, reg_offset)       \
+                               ((0x4000 << (block_offset)) +           \
+                               (((ln) << 9) << (reg_offset)))
+
+#define TORRENT_RX_LANE_CDB_OFFSET(ln, block_offset, reg_offset)       \
+                               ((0x8000 << (block_offset)) +           \
+                               (((ln) << 9) << (reg_offset)))
+
+#define TORRENT_PHY_PCS_COMMON_OFFSET(block_offset)    \
+                               (0xC000 << (block_offset))
+
+#define TORRENT_PHY_PMA_COMMON_OFFSET(block_offset)    \
+                               (0xE000 << (block_offset))
+
+#define TORRENT_DPTX_PHY_OFFSET                0x0
+
+/*
+ * register offsets from DPTX PHY register block base (i.e MHDP
+ * register base + 0x30a00)
+ */
+#define PHY_AUX_CTRL                   0x04
+#define PHY_RESET                      0x20
+#define PMA_TX_ELEC_IDLE_MASK          0xF0U
+#define PMA_TX_ELEC_IDLE_SHIFT         4
+#define PHY_L00_RESET_N_MASK           0x01U
+#define PHY_PMA_XCVR_PLLCLK_EN         0x24
+#define PHY_PMA_XCVR_PLLCLK_EN_ACK     0x28
+#define PHY_PMA_XCVR_POWER_STATE_REQ   0x2c
+#define PHY_POWER_STATE_LN_0   0x0000
+#define PHY_POWER_STATE_LN_1   0x0008
+#define PHY_POWER_STATE_LN_2   0x0010
+#define PHY_POWER_STATE_LN_3   0x0018
+#define PMA_XCVR_POWER_STATE_REQ_LN_MASK       0x3FU
+#define PHY_PMA_XCVR_POWER_STATE_ACK   0x30
+#define PHY_PMA_CMN_READY              0x34
+
+/*
+ * register offsets from SD0801 PHY register block base (i.e MHDP
+ * register base + 0x500000)
+ */
+#define CMN_SSM_BANDGAP_TMR            0x0021U
+#define CMN_SSM_BIAS_TMR               0x0022U
+#define CMN_PLLSM0_PLLPRE_TMR          0x002AU
+#define CMN_PLLSM0_PLLLOCK_TMR         0x002CU
+#define CMN_PLLSM1_PLLPRE_TMR          0x0032U
+#define CMN_PLLSM1_PLLLOCK_TMR         0x0034U
+#define CMN_BGCAL_INIT_TMR             0x0064U
+#define CMN_BGCAL_ITER_TMR             0x0065U
+#define CMN_IBCAL_INIT_TMR             0x0074U
+#define CMN_PLL0_VCOCAL_TCTRL          0x0082U
+#define CMN_PLL0_VCOCAL_INIT_TMR       0x0084U
+#define CMN_PLL0_VCOCAL_ITER_TMR       0x0085U
+#define CMN_PLL0_VCOCAL_REFTIM_START   0x0086U
+#define CMN_PLL0_VCOCAL_PLLCNT_START   0x0088U
+#define CMN_PLL0_INTDIV_M0             0x0090U
+#define CMN_PLL0_FRACDIVL_M0           0x0091U
+#define CMN_PLL0_FRACDIVH_M0           0x0092U
+#define CMN_PLL0_HIGH_THR_M0           0x0093U
+#define CMN_PLL0_DSM_DIAG_M0           0x0094U
+#define CMN_PLL0_SS_CTRL1_M0           0x0098U
+#define CMN_PLL0_SS_CTRL2_M0            0x0099U
+#define CMN_PLL0_SS_CTRL3_M0            0x009AU
+#define CMN_PLL0_SS_CTRL4_M0            0x009BU
+#define CMN_PLL0_LOCK_REFCNT_START      0x009CU
+#define CMN_PLL0_LOCK_PLLCNT_START     0x009EU
+#define CMN_PLL0_LOCK_PLLCNT_THR        0x009FU
+#define CMN_PLL1_VCOCAL_TCTRL          0x00C2U
+#define CMN_PLL1_VCOCAL_INIT_TMR       0x00C4U
+#define CMN_PLL1_VCOCAL_ITER_TMR       0x00C5U
+#define CMN_PLL1_VCOCAL_REFTIM_START   0x00C6U
+#define CMN_PLL1_VCOCAL_PLLCNT_START   0x00C8U
+#define CMN_PLL1_INTDIV_M0             0x00D0U
+#define CMN_PLL1_FRACDIVL_M0           0x00D1U
+#define CMN_PLL1_FRACDIVH_M0           0x00D2U
+#define CMN_PLL1_HIGH_THR_M0           0x00D3U
+#define CMN_PLL1_DSM_DIAG_M0           0x00D4U
+#define CMN_PLL1_SS_CTRL1_M0           0x00D8U
+#define CMN_PLL1_SS_CTRL2_M0            0x00D9U
+#define CMN_PLL1_SS_CTRL3_M0            0x00DAU
+#define CMN_PLL1_SS_CTRL4_M0            0x00DBU
+#define CMN_PLL1_LOCK_REFCNT_START      0x00DCU
+#define CMN_PLL1_LOCK_PLLCNT_START     0x00DEU
+#define CMN_PLL1_LOCK_PLLCNT_THR        0x00DFU
+#define CMN_TXPUCAL_INIT_TMR           0x0104U
+#define CMN_TXPUCAL_ITER_TMR           0x0105U
+#define CMN_TXPDCAL_INIT_TMR           0x010CU
+#define CMN_TXPDCAL_ITER_TMR           0x010DU
+#define CMN_RXCAL_INIT_TMR             0x0114U
+#define CMN_RXCAL_ITER_TMR             0x0115U
+#define CMN_SD_CAL_INIT_TMR            0x0124U
+#define CMN_SD_CAL_ITER_TMR            0x0125U
+#define CMN_SD_CAL_REFTIM_START                0x0126U
+#define CMN_SD_CAL_PLLCNT_START                0x0128U
+#define CMN_PDIAG_PLL0_CTRL_M0         0x01A0U
+#define CMN_PDIAG_PLL0_CLK_SEL_M0      0x01A1U
+#define CMN_PDIAG_PLL0_CP_PADJ_M0      0x01A4U
+#define CMN_PDIAG_PLL0_CP_IADJ_M0      0x01A5U
+#define CMN_PDIAG_PLL0_FILT_PADJ_M0    0x01A6U
+#define CMN_PDIAG_PLL0_CP_PADJ_M1      0x01B4U
+#define CMN_PDIAG_PLL0_CP_IADJ_M1      0x01B5U
+#define CMN_PDIAG_PLL1_CTRL_M0         0x01C0U
+#define CMN_PDIAG_PLL1_CLK_SEL_M0      0x01C1U
+#define CMN_PDIAG_PLL1_CP_PADJ_M0      0x01C4U
+#define CMN_PDIAG_PLL1_CP_IADJ_M0      0x01C5U
+#define CMN_PDIAG_PLL1_FILT_PADJ_M0    0x01C6U
+
+/* PMA TX Lane registers */
+#define TX_TXCC_CTRL                   0x0040U
+#define TX_TXCC_CPOST_MULT_00          0x004CU
+#define TX_TXCC_MGNFS_MULT_000         0x0050U
+#define DRV_DIAG_TX_DRV                        0x00C6U
+#define XCVR_DIAG_PLLDRC_CTRL          0x00E5U
+#define XCVR_DIAG_HSCLK_SEL            0x00E6U
+#define XCVR_DIAG_HSCLK_DIV            0x00E7U
+#define XCVR_DIAG_BIDI_CTRL            0x00EAU
+#define TX_PSC_A0                      0x0100U
+#define TX_PSC_A2                      0x0102U
+#define TX_PSC_A3                      0x0103U
+#define TX_RCVDET_ST_TMR               0x0123U
+#define TX_DIAG_ACYA                   0x01E7U
+#define TX_DIAG_ACYA_HBDC_MASK         0x0001U
+
+/* PMA RX Lane registers */
+#define RX_PSC_A0                      0x0000U
+#define RX_PSC_A2                      0x0002U
+#define RX_PSC_A3                      0x0003U
+#define RX_PSC_CAL                     0x0006U
+#define RX_REE_GCSM1_CTRL              0x0108U
+#define RX_REE_GCSM2_CTRL              0x0110U
+#define RX_REE_PERGCSM_CTRL            0x0118U
+
+/* PHY PCS common registers */
+#define PHY_PLL_CFG                    0x000EU
+
+/* PHY PMA common registers */
+#define PHY_PMA_CMN_CTRL2              0x0001U
+#define PHY_PMA_PLL_RAW_CTRL           0x0003U
+
+static const struct reg_field phy_pll_cfg =
+                               REG_FIELD(PHY_PLL_CFG, 0, 1);
+
+static const struct reg_field phy_pma_cmn_ctrl_2 =
+                               REG_FIELD(PHY_PMA_CMN_CTRL2, 0, 7);
+
+static const struct reg_field phy_pma_pll_raw_ctrl =
+                               REG_FIELD(PHY_PMA_PLL_RAW_CTRL, 0, 1);
+
+static const struct reg_field phy_reset_ctrl =
+                               REG_FIELD(PHY_RESET, 8, 8);
+
+static const struct of_device_id cdns_torrent_phy_of_match[];
+
+struct cdns_torrent_inst {
+       struct phy *phy;
+       u32 mlane;
+       u32 phy_type;
+       u32 num_lanes;
+       struct reset_control *lnk_rst;
+};
+
+struct cdns_torrent_phy {
+       void __iomem *base;     /* DPTX registers base */
+       void __iomem *sd_base; /* SD0801 registers base */
+       u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */
+       struct reset_control *phy_rst;
+       struct device *dev;
+       struct clk *clk;
+       unsigned long ref_clk_rate;
+       struct cdns_torrent_inst phys[MAX_NUM_LANES];
+       int nsubnodes;
+       struct regmap *regmap;
+       struct regmap *regmap_common_cdb;
+       struct regmap *regmap_phy_pcs_common_cdb;
+       struct regmap *regmap_phy_pma_common_cdb;
+       struct regmap *regmap_tx_lane_cdb[MAX_NUM_LANES];
+       struct regmap *regmap_rx_lane_cdb[MAX_NUM_LANES];
+       struct regmap *regmap_dptx_phy_reg;
+       struct regmap_field *phy_pll_cfg;
+       struct regmap_field *phy_pma_cmn_ctrl_2;
+       struct regmap_field *phy_pma_pll_raw_ctrl;
+       struct regmap_field *phy_reset_ctrl;
+};
+
+enum phy_powerstate {
+       POWERSTATE_A0 = 0,
+       /* Powerstate A1 is unused */
+       POWERSTATE_A2 = 2,
+       POWERSTATE_A3 = 3,
+};
+
+static int cdns_torrent_dp_init(struct phy *phy);
+static int cdns_torrent_dp_exit(struct phy *phy);
+static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy,
+                              u32 num_lanes);
+static
+int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy);
+static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy,
+                                   struct cdns_torrent_inst *inst);
+static
+void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy);
+static
+void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy,
+                                            u32 rate, bool ssc);
+static
+void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy);
+static
+void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy,
+                                          u32 rate, bool ssc);
+static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy,
+                                        unsigned int lane);
+static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy,
+                                        u32 rate, u32 num_lanes);
+static int cdns_torrent_dp_configure(struct phy *phy,
+                                    union phy_configure_opts *opts);
+static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
+                                          u32 num_lanes,
+                                          enum phy_powerstate powerstate);
+static int cdns_torrent_phy_on(struct phy *phy);
+static int cdns_torrent_phy_off(struct phy *phy);
+
+static const struct phy_ops cdns_torrent_phy_ops = {
+       .init           = cdns_torrent_dp_init,
+       .exit           = cdns_torrent_dp_exit,
+       .configure      = cdns_torrent_dp_configure,
+       .power_on       = cdns_torrent_phy_on,
+       .power_off      = cdns_torrent_phy_off,
+       .owner          = THIS_MODULE,
+};
+
+struct cdns_torrent_data {
+               u8 block_offset_shift;
+               u8 reg_offset_shift;
+};
+
+struct cdns_regmap_cdb_context {
+       struct device *dev;
+       void __iomem *base;
+       u8 reg_offset_shift;
+};
+
+static int cdns_regmap_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct cdns_regmap_cdb_context *ctx = context;
+       u32 offset = reg << ctx->reg_offset_shift;
+
+       writew(val, ctx->base + offset);
+
+       return 0;
+}
+
+static int cdns_regmap_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct cdns_regmap_cdb_context *ctx = context;
+       u32 offset = reg << ctx->reg_offset_shift;
+
+       *val = readw(ctx->base + offset);
+       return 0;
+}
+
+static int cdns_regmap_dptx_write(void *context, unsigned int reg,
+                                 unsigned int val)
+{
+       struct cdns_regmap_cdb_context *ctx = context;
+       u32 offset = reg;
+
+       writel(val, ctx->base + offset);
+
+       return 0;
+}
+
+static int cdns_regmap_dptx_read(void *context, unsigned int reg,
+                                unsigned int *val)
+{
+       struct cdns_regmap_cdb_context *ctx = context;
+       u32 offset = reg;
+
+       *val = readl(ctx->base + offset);
+       return 0;
+}
+
+#define TORRENT_TX_LANE_CDB_REGMAP_CONF(n) \
+{ \
+       .name = "torrent_tx_lane" n "_cdb", \
+       .reg_stride = 1, \
+       .fast_io = true, \
+       .reg_write = cdns_regmap_write, \
+       .reg_read = cdns_regmap_read, \
+}
+
+#define TORRENT_RX_LANE_CDB_REGMAP_CONF(n) \
+{ \
+       .name = "torrent_rx_lane" n "_cdb", \
+       .reg_stride = 1, \
+       .fast_io = true, \
+       .reg_write = cdns_regmap_write, \
+       .reg_read = cdns_regmap_read, \
+}
+
+static struct regmap_config cdns_torrent_tx_lane_cdb_config[] = {
+       TORRENT_TX_LANE_CDB_REGMAP_CONF("0"),
+       TORRENT_TX_LANE_CDB_REGMAP_CONF("1"),
+       TORRENT_TX_LANE_CDB_REGMAP_CONF("2"),
+       TORRENT_TX_LANE_CDB_REGMAP_CONF("3"),
+};
+
+static struct regmap_config cdns_torrent_rx_lane_cdb_config[] = {
+       TORRENT_RX_LANE_CDB_REGMAP_CONF("0"),
+       TORRENT_RX_LANE_CDB_REGMAP_CONF("1"),
+       TORRENT_RX_LANE_CDB_REGMAP_CONF("2"),
+       TORRENT_RX_LANE_CDB_REGMAP_CONF("3"),
+};
+
+static struct regmap_config cdns_torrent_common_cdb_config = {
+       .name = "torrent_common_cdb",
+       .reg_stride = 1,
+       .fast_io = true,
+       .reg_write = cdns_regmap_write,
+       .reg_read = cdns_regmap_read,
+};
+
+static struct regmap_config cdns_torrent_phy_pcs_cmn_cdb_config = {
+       .name = "torrent_phy_pcs_cmn_cdb",
+       .reg_stride = 1,
+       .fast_io = true,
+       .reg_write = cdns_regmap_write,
+       .reg_read = cdns_regmap_read,
+};
+
+static struct regmap_config cdns_torrent_phy_pma_cmn_cdb_config = {
+       .name = "torrent_phy_pma_cmn_cdb",
+       .reg_stride = 1,
+       .fast_io = true,
+       .reg_write = cdns_regmap_write,
+       .reg_read = cdns_regmap_read,
+};
+
+static struct regmap_config cdns_torrent_dptx_phy_config = {
+       .name = "torrent_dptx_phy",
+       .reg_stride = 1,
+       .fast_io = true,
+       .reg_write = cdns_regmap_dptx_write,
+       .reg_read = cdns_regmap_dptx_read,
+};
+
+/* PHY mmr access functions */
+
+static void cdns_torrent_phy_write(struct regmap *regmap, u32 offset, u32 val)
+{
+       regmap_write(regmap, offset, val);
+}
+
+static u32 cdns_torrent_phy_read(struct regmap *regmap, u32 offset)
+{
+       unsigned int val;
+
+       regmap_read(regmap, offset, &val);
+       return val;
+}
+
+/* DPTX mmr access functions */
+
+static void cdns_torrent_dp_write(struct regmap *regmap, u32 offset, u32 val)
+{
+       regmap_write(regmap, offset, val);
+}
+
+static u32 cdns_torrent_dp_read(struct regmap *regmap, u32 offset)
+{
+       u32 val;
+
+       regmap_read(regmap, offset, &val);
+       return val;
+}
+
+/*
+ * Structure used to store values of PHY registers for voltage-related
+ * coefficients, for particular voltage swing and pre-emphasis level. Values
+ * are shared across all physical lanes.
+ */
+struct coefficients {
+       /* Value of DRV_DIAG_TX_DRV register to use */
+       u16 diag_tx_drv;
+       /* Value of TX_TXCC_MGNFS_MULT_000 register to use */
+       u16 mgnfs_mult;
+       /* Value of TX_TXCC_CPOST_MULT_00 register to use */
+       u16 cpost_mult;
+};
+
+/*
+ * Array consists of values of voltage-related registers for sd0801 PHY. A value
+ * of 0xFFFF is a placeholder for invalid combination, and will never be used.
+ */
+static const struct coefficients vltg_coeff[4][4] = {
+       /* voltage swing 0, pre-emphasis 0->3 */
+       {       {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x002A,
+                .cpost_mult = 0x0000},
+               {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x001F,
+                .cpost_mult = 0x0014},
+               {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0012,
+                .cpost_mult = 0x0020},
+               {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0000,
+                .cpost_mult = 0x002A}
+       },
+
+       /* voltage swing 1, pre-emphasis 0->3 */
+       {       {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x001F,
+                .cpost_mult = 0x0000},
+               {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0013,
+                .cpost_mult = 0x0012},
+               {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0000,
+                .cpost_mult = 0x001F},
+               {.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
+                .cpost_mult = 0xFFFF}
+       },
+
+       /* voltage swing 2, pre-emphasis 0->3 */
+       {       {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0013,
+                .cpost_mult = 0x0000},
+               {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0000,
+                .cpost_mult = 0x0013},
+               {.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
+                .cpost_mult = 0xFFFF},
+               {.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
+                .cpost_mult = 0xFFFF}
+       },
+
+       /* voltage swing 3, pre-emphasis 0->3 */
+       {       {.diag_tx_drv = 0x0003, .mgnfs_mult = 0x0000,
+                .cpost_mult = 0x0000},
+               {.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
+                .cpost_mult = 0xFFFF},
+               {.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
+                .cpost_mult = 0xFFFF},
+               {.diag_tx_drv = 0xFFFF, .mgnfs_mult = 0xFFFF,
+                .cpost_mult = 0xFFFF}
+       }
+};
+
+/*
+ * Enable or disable PLL for selected lanes.
+ */
+static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy,
+                                     struct phy_configure_opts_dp *dp,
+                                     bool enable)
+{
+       u32 rd_val;
+       u32 ret;
+       struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
+
+       /*
+        * Used to determine, which bits to check for or enable in
+        * PHY_PMA_XCVR_PLLCLK_EN register.
+        */
+       u32 pll_bits;
+       /* Used to enable or disable lanes. */
+       u32 pll_val;
+
+       /* Select values of registers and mask, depending on enabled lane
+        * count.
+        */
+       switch (dp->lanes) {
+       /* lane 0 */
+       case (1):
+               pll_bits = 0x00000001;
+               break;
+       /* lanes 0-1 */
+       case (2):
+               pll_bits = 0x00000003;
+               break;
+       /* lanes 0-3, all */
+       default:
+               pll_bits = 0x0000000F;
+               break;
+       }
+
+       if (enable)
+               pll_val = pll_bits;
+       else
+               pll_val = 0x00000000;
+
+       cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val);
+
+       /* Wait for acknowledgment from PHY. */
+       ret = regmap_read_poll_timeout(regmap,
+                                      PHY_PMA_XCVR_PLLCLK_EN_ACK,
+                                      rd_val,
+                                      (rd_val & pll_bits) == pll_val,
+                                      0, POLL_TIMEOUT_US);
+       ndelay(100);
+       return ret;
+}
+
+/*
+ * Perform register operations related to setting link rate, once powerstate is
+ * set and PLL disable request was processed.
+ */
+static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy,
+                                         struct phy_configure_opts_dp *dp)
+{
+       u32 ret;
+       u32 read_val;
+
+       /* Disable the cmn_pll0_en before re-programming the new data rate. */
+       regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0);
+
+       /*
+        * Wait for PLL ready de-assertion.
+        * For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1
+        */
+       ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
+                                            read_val,
+                                            ((read_val >> 2) & 0x01) != 0,
+                                            0, POLL_TIMEOUT_US);
+       if (ret)
+               return ret;
+       ndelay(200);
+
+       /* DP Rate Change - VCO Output settings. */
+       if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz) {
+               /* PMA common configuration 19.2MHz */
+               cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate,
+                                                       dp->ssc);
+               cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy);
+       } else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz) {
+               /* PMA common configuration 25MHz */
+               cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate,
+                                                     dp->ssc);
+               cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy);
+       }
+       cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes);
+
+       /* Enable the cmn_pll0_en. */
+       regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x3);
+
+       /*
+        * Wait for PLL ready assertion.
+        * For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1
+        */
+       ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2,
+                                            read_val,
+                                            (read_val & 0x01) != 0,
+                                            0, POLL_TIMEOUT_US);
+       return ret;
+}
+
+/*
+ * Verify, that parameters to configure PHY with are correct.
+ */
+static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst,
+                                        struct phy_configure_opts_dp *dp)
+{
+       u8 i;
+
+       /* If changing link rate was required, verify it's supported. */
+       if (dp->set_rate) {
+               switch (dp->link_rate) {
+               case 1620:
+               case 2160:
+               case 2430:
+               case 2700:
+               case 3240:
+               case 4320:
+               case 5400:
+               case 8100:
+                       /* valid bit rate */
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       /* Verify lane count. */
+       switch (dp->lanes) {
+       case 1:
+       case 2:
+       case 4:
+               /* valid lane count. */
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Check against actual number of PHY's lanes. */
+       if (dp->lanes > inst->num_lanes)
+               return -EINVAL;
+
+       /*
+        * If changing voltages is required, check swing and pre-emphasis
+        * levels, per-lane.
+        */
+       if (dp->set_voltages) {
+               /* Lane count verified previously. */
+               for (i = 0; i < dp->lanes; i++) {
+                       if (dp->voltage[i] > 3 || dp->pre[i] > 3)
+                               return -EINVAL;
+
+                       /* Sum of voltage swing and pre-emphasis levels cannot
+                        * exceed 3.
+                        */
+                       if (dp->voltage[i] + dp->pre[i] > 3)
+                               return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */
+static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy,
+                                      u32 num_lanes)
+{
+       struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
+       u32 pwr_state = cdns_torrent_dp_read(regmap,
+                                            PHY_PMA_XCVR_POWER_STATE_REQ);
+       u32 pll_clk_en = cdns_torrent_dp_read(regmap,
+                                             PHY_PMA_XCVR_PLLCLK_EN);
+
+       /* Lane 0 is always enabled. */
+       pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
+                      PHY_POWER_STATE_LN_0);
+       pll_clk_en &= ~0x01U;
+
+       if (num_lanes > 1) {
+               /* lane 1 */
+               pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
+                              PHY_POWER_STATE_LN_1);
+               pll_clk_en &= ~(0x01U << 1);
+       }
+
+       if (num_lanes > 2) {
+               /* lanes 2 and 3 */
+               pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
+                              PHY_POWER_STATE_LN_2);
+               pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK <<
+                              PHY_POWER_STATE_LN_3);
+               pll_clk_en &= ~(0x01U << 2);
+               pll_clk_en &= ~(0x01U << 3);
+       }
+
+       cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state);
+       cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en);
+}
+
+/* Configure lane count as required. */
+static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy,
+                                    struct phy_configure_opts_dp *dp)
+{
+       u32 value;
+       u32 ret;
+       struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
+       u8 lane_mask = (1 << dp->lanes) - 1;
+
+       value = cdns_torrent_dp_read(regmap, PHY_RESET);
+       /* clear pma_tx_elec_idle_ln_* bits. */
+       value &= ~PMA_TX_ELEC_IDLE_MASK;
+       /* Assert pma_tx_elec_idle_ln_* for disabled lanes. */
+       value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) &
+                PMA_TX_ELEC_IDLE_MASK;
+       cdns_torrent_dp_write(regmap, PHY_RESET, value);
+
+       /* reset the link by asserting phy_l00_reset_n low */
+       cdns_torrent_dp_write(regmap, PHY_RESET,
+                             value & (~PHY_L00_RESET_N_MASK));
+
+       /*
+        * Assert lane reset on unused lanes and lane 0 so they remain in reset
+        * and powered down when re-enabling the link
+        */
+       value = (value & 0x0000FFF0) | (0x0000000E & lane_mask);
+       cdns_torrent_dp_write(regmap, PHY_RESET, value);
+
+       cdns_torrent_dp_set_a0_pll(cdns_phy, dp->lanes);
+
+       /* release phy_l0*_reset_n based on used laneCount */
+       value = (value & 0x0000FFF0) | (0x0000000F & lane_mask);
+       cdns_torrent_dp_write(regmap, PHY_RESET, value);
+
+       /* Wait, until PHY gets ready after releasing PHY reset signal. */
+       ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy);
+       if (ret)
+               return ret;
+
+       ndelay(100);
+
+       /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
+       cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001);
+
+       ret = cdns_torrent_dp_run(cdns_phy, dp->lanes);
+
+       return ret;
+}
+
+/* Configure link rate as required. */
+static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy,
+                                   struct phy_configure_opts_dp *dp)
+{
+       u32 ret;
+
+       ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
+                                             POWERSTATE_A3);
+       if (ret)
+               return ret;
+       ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, false);
+       if (ret)
+               return ret;
+       ndelay(200);
+
+       ret = cdns_torrent_dp_configure_rate(cdns_phy, dp);
+       if (ret)
+               return ret;
+       ndelay(200);
+
+       ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, true);
+       if (ret)
+               return ret;
+       ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
+                                             POWERSTATE_A2);
+       if (ret)
+               return ret;
+       ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes,
+                                             POWERSTATE_A0);
+       if (ret)
+               return ret;
+       ndelay(900);
+
+       return ret;
+}
+
+/* Configure voltage swing and pre-emphasis for all enabled lanes. */
+static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy,
+                                        struct phy_configure_opts_dp *dp)
+{
+       u8 lane;
+       u16 val;
+
+       for (lane = 0; lane < dp->lanes; lane++) {
+               val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane],
+                                           TX_DIAG_ACYA);
+               /*
+                * Write 1 to register bit TX_DIAG_ACYA[0] to freeze the
+                * current state of the analog TX driver.
+                */
+               val |= TX_DIAG_ACYA_HBDC_MASK;
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                                      TX_DIAG_ACYA, val);
+
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                                      TX_TXCC_CTRL, 0x08A4);
+               val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv;
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                                      DRV_DIAG_TX_DRV, val);
+               val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult;
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                                      TX_TXCC_MGNFS_MULT_000,
+                                      val);
+               val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult;
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                                      TX_TXCC_CPOST_MULT_00,
+                                      val);
+
+               val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane],
+                                           TX_DIAG_ACYA);
+               /*
+                * Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of
+                * analog TX driver to reflect the new programmed one.
+                */
+               val &= ~TX_DIAG_ACYA_HBDC_MASK;
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                                      TX_DIAG_ACYA, val);
+       }
+};
+
+static int cdns_torrent_dp_configure(struct phy *phy,
+                                    union phy_configure_opts *opts)
+{
+       struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
+       struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
+       int ret;
+
+       ret = cdns_torrent_dp_verify_config(inst, &opts->dp);
+       if (ret) {
+               dev_err(&phy->dev, "invalid params for phy configure\n");
+               return ret;
+       }
+
+       if (opts->dp.set_lanes) {
+               ret = cdns_torrent_dp_set_lanes(cdns_phy, &opts->dp);
+               if (ret) {
+                       dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n");
+                       return ret;
+               }
+       }
+
+       if (opts->dp.set_rate) {
+               ret = cdns_torrent_dp_set_rate(cdns_phy, &opts->dp);
+               if (ret) {
+                       dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n");
+                       return ret;
+               }
+       }
+
+       if (opts->dp.set_voltages)
+               cdns_torrent_dp_set_voltages(cdns_phy, &opts->dp);
+
+       return ret;
+}
+
+static int cdns_torrent_dp_init(struct phy *phy)
+{
+       unsigned char lane_bits;
+       int ret;
+       struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
+       struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
+       struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
+
+       ret = clk_prepare_enable(cdns_phy->clk);
+       if (ret) {
+               dev_err(cdns_phy->dev, "Failed to prepare ref clock\n");
+               return ret;
+       }
+
+       cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk);
+       if (!(cdns_phy->ref_clk_rate)) {
+               dev_err(cdns_phy->dev, "Failed to get ref clock rate\n");
+               clk_disable_unprepare(cdns_phy->clk);
+               return -EINVAL;
+       }
+
+       switch (cdns_phy->ref_clk_rate) {
+       case REF_CLK_19_2MHz:
+       case REF_CLK_25MHz:
+               /* Valid Ref Clock Rate */
+               break;
+       default:
+               dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n");
+               return -EINVAL;
+       }
+
+       cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */
+
+       /* PHY PMA registers configuration function */
+       cdns_torrent_dp_pma_cfg(cdns_phy, inst);
+
+       /*
+        * Set lines power state to A0
+        * Set lines pll clk enable to 0
+        */
+       cdns_torrent_dp_set_a0_pll(cdns_phy, inst->num_lanes);
+
+       /*
+        * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on
+        * used lanes
+        */
+       lane_bits = (1 << inst->num_lanes) - 1;
+       cdns_torrent_dp_write(regmap, PHY_RESET,
+                             ((0xF & ~lane_bits) << 4) | (0xF & lane_bits));
+
+       /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */
+       cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001);
+
+       /* PHY PMA registers configuration functions */
+       /* Initialize PHY with max supported link rate, without SSC. */
+       if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz)
+               cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy,
+                                                       cdns_phy->max_bit_rate,
+                                                       false);
+       else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz)
+               cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy,
+                                                     cdns_phy->max_bit_rate,
+                                                     false);
+       cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate,
+                                    inst->num_lanes);
+
+       /* take out of reset */
+       regmap_field_write(cdns_phy->phy_reset_ctrl, 0x1);
+
+       cdns_torrent_phy_on(phy);
+
+       ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy);
+       if (ret)
+               return ret;
+
+       ret = cdns_torrent_dp_run(cdns_phy, inst->num_lanes);
+
+       return ret;
+}
+
+static int cdns_torrent_dp_exit(struct phy *phy)
+{
+       struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
+
+       clk_disable_unprepare(cdns_phy->clk);
+       return 0;
+}
+
+static
+int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy)
+{
+       unsigned int reg;
+       int ret;
+       struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
+
+       ret = regmap_read_poll_timeout(regmap, PHY_PMA_CMN_READY, reg,
+                                      reg & 1, 0, POLL_TIMEOUT_US);
+       if (ret == -ETIMEDOUT) {
+               dev_err(cdns_phy->dev,
+                       "timeout waiting for PMA common ready\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy,
+                                   struct cdns_torrent_inst *inst)
+{
+       unsigned int i;
+
+       if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz)
+               /* PMA common configuration 19.2MHz */
+               cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy);
+       else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz)
+               /* PMA common configuration 25MHz */
+               cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy);
+
+       /* PMA lane configuration to deal with multi-link operation */
+       for (i = 0; i < inst->num_lanes; i++)
+               cdns_torrent_dp_pma_lane_cfg(cdns_phy, i);
+}
+
+static
+void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy)
+{
+       struct regmap *regmap = cdns_phy->regmap_common_cdb;
+
+       /* refclock registers - assumes 19.2 MHz refclock */
+       cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0014);
+       cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0027);
+       cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00A1);
+       cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0027);
+       cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00A1);
+       cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x0060);
+       cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x0060);
+       cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0014);
+       cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x0018);
+       cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0005);
+       cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x0018);
+       cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0005);
+       cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x0240);
+       cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0005);
+       cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002);
+       cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002);
+       cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000B);
+       cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x0137);
+
+       /* PLL registers */
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00C0);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00C0);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0260);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0260);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003);
+}
+
+/*
+ * Set registers responsible for enabling and configuring SSC, with second and
+ * third register values provided by parameters.
+ */
+static
+void cdns_torrent_dp_enable_ssc_19_2mhz(struct cdns_torrent_phy *cdns_phy,
+                                       u32 ctrl2_val, u32 ctrl3_val)
+{
+       struct regmap *regmap = cdns_phy->regmap_common_cdb;
+
+       cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl3_val);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl3_val);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003);
+}
+
+static
+void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy,
+                                            u32 rate, bool ssc)
+{
+       struct regmap *regmap = cdns_phy->regmap_common_cdb;
+
+       /* Assumes 19.2 MHz refclock */
+       switch (rate) {
+       /* Setting VCO for 10.8GHz */
+       case 2700:
+       case 5400:
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_INTDIV_M0, 0x0119);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_FRACDIVL_M0, 0x4000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_HIGH_THR_M0, 0x00BC);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PDIAG_PLL0_CTRL_M0, 0x0012);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_INTDIV_M0, 0x0119);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_FRACDIVL_M0, 0x4000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_HIGH_THR_M0, 0x00BC);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PDIAG_PLL1_CTRL_M0, 0x0012);
+               if (ssc)
+                       cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x033A,
+                                                          0x006A);
+               break;
+       /* Setting VCO for 9.72GHz */
+       case 1620:
+       case 2430:
+       case 3240:
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_INTDIV_M0, 0x01FA);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_FRACDIVL_M0, 0x4000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_HIGH_THR_M0, 0x0152);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_INTDIV_M0, 0x01FA);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_FRACDIVL_M0, 0x4000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_HIGH_THR_M0, 0x0152);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
+               if (ssc)
+                       cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x05DD,
+                                                          0x0069);
+               break;
+       /* Setting VCO for 8.64GHz */
+       case 2160:
+       case 4320:
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_INTDIV_M0, 0x01C2);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_FRACDIVL_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_HIGH_THR_M0, 0x012C);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_INTDIV_M0, 0x01C2);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_FRACDIVL_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_HIGH_THR_M0, 0x012C);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
+               if (ssc)
+                       cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x0536,
+                                                          0x0069);
+               break;
+       /* Setting VCO for 8.1GHz */
+       case 8100:
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_INTDIV_M0, 0x01A5);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_FRACDIVL_M0, 0xE000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_HIGH_THR_M0, 0x011A);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_INTDIV_M0, 0x01A5);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_FRACDIVL_M0, 0xE000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_HIGH_THR_M0, 0x011A);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
+               if (ssc)
+                       cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x04D7,
+                                                          0x006A);
+               break;
+       }
+
+       if (ssc) {
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_VCOCAL_PLLCNT_START, 0x025E);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_LOCK_PLLCNT_THR, 0x0005);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_VCOCAL_PLLCNT_START, 0x025E);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_LOCK_PLLCNT_THR, 0x0005);
+       } else {
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_VCOCAL_PLLCNT_START, 0x0260);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_VCOCAL_PLLCNT_START, 0x0260);
+               /* Set reset register values to disable SSC */
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_SS_CTRL1_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_SS_CTRL2_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_SS_CTRL3_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_SS_CTRL4_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_LOCK_PLLCNT_THR, 0x0003);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_SS_CTRL1_M0, 0x0002);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_SS_CTRL2_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_SS_CTRL3_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_SS_CTRL4_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_LOCK_PLLCNT_THR, 0x0003);
+       }
+
+       cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x0099);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x0099);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x0099);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x0099);
+}
+
+static
+void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy)
+{
+       struct regmap *regmap = cdns_phy->regmap_common_cdb;
+
+       /* refclock registers - assumes 25 MHz refclock */
+       cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0019);
+       cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0032);
+       cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00D1);
+       cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0032);
+       cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00D1);
+       cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x007D);
+       cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x007D);
+       cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0019);
+       cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x001E);
+       cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0006);
+       cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x001E);
+       cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0006);
+       cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x02EE);
+       cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0006);
+       cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002);
+       cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002);
+       cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000E);
+       cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x012B);
+
+       /* PLL registers */
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00FA);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00FA);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0317);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0317);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003);
+}
+
+/*
+ * Set registers responsible for enabling and configuring SSC, with second
+ * register value provided by a parameter.
+ */
+static void cdns_torrent_dp_enable_ssc_25mhz(struct cdns_torrent_phy *cdns_phy,
+                                            u32 ctrl2_val)
+{
+       struct regmap *regmap = cdns_phy->regmap_common_cdb;
+
+       cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x007F);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x007F);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003);
+}
+
+static
+void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy,
+                                          u32 rate, bool ssc)
+{
+       struct regmap *regmap = cdns_phy->regmap_common_cdb;
+
+       /* Assumes 25 MHz refclock */
+       switch (rate) {
+       /* Setting VCO for 10.8GHz */
+       case 2700:
+       case 5400:
+               cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01B0);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0120);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01B0);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0120);
+               if (ssc)
+                       cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x0423);
+               break;
+       /* Setting VCO for 9.72GHz */
+       case 1620:
+       case 2430:
+       case 3240:
+               cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0184);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0xCCCD);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0104);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0184);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0xCCCD);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0104);
+               if (ssc)
+                       cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x03B9);
+               break;
+       /* Setting VCO for 8.64GHz */
+       case 2160:
+       case 4320:
+               cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0159);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x999A);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00E7);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0159);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x999A);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00E7);
+               if (ssc)
+                       cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x034F);
+               break;
+       /* Setting VCO for 8.1GHz */
+       case 8100:
+               cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0144);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00D8);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0144);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00D8);
+               if (ssc)
+                       cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x031A);
+               break;
+       }
+
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002);
+       cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002);
+
+       if (ssc) {
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_VCOCAL_PLLCNT_START, 0x0315);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_LOCK_PLLCNT_THR, 0x0005);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_VCOCAL_PLLCNT_START, 0x0315);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_LOCK_PLLCNT_THR, 0x0005);
+       } else {
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_VCOCAL_PLLCNT_START, 0x0317);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_VCOCAL_PLLCNT_START, 0x0317);
+               /* Set reset register values to disable SSC */
+               cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL2_M0, 0x0000);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL3_M0, 0x0000);
+               cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL0_LOCK_PLLCNT_THR, 0x0003);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0002);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL2_M0, 0x0000);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL3_M0, 0x0000);
+               cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0000);
+               cdns_torrent_phy_write(regmap,
+                                      CMN_PLL1_LOCK_PLLCNT_THR, 0x0003);
+       }
+
+       cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x00C7);
+       cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x00C7);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x00C7);
+       cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x00C7);
+}
+
+static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy,
+                                        u32 rate, u32 num_lanes)
+{
+       unsigned int clk_sel_val = 0;
+       unsigned int hsclk_div_val = 0;
+       unsigned int i;
+
+       /* 16'h0000 for single DP link configuration */
+       regmap_field_write(cdns_phy->phy_pll_cfg, 0x0);
+
+       switch (rate) {
+       case 1620:
+               clk_sel_val = 0x0f01;
+               hsclk_div_val = 2;
+               break;
+       case 2160:
+       case 2430:
+       case 2700:
+               clk_sel_val = 0x0701;
+               hsclk_div_val = 1;
+               break;
+       case 3240:
+               clk_sel_val = 0x0b00;
+               hsclk_div_val = 2;
+               break;
+       case 4320:
+       case 5400:
+               clk_sel_val = 0x0301;
+               hsclk_div_val = 0;
+               break;
+       case 8100:
+               clk_sel_val = 0x0200;
+               hsclk_div_val = 0;
+               break;
+       }
+
+       cdns_torrent_phy_write(cdns_phy->regmap_common_cdb,
+                              CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val);
+       cdns_torrent_phy_write(cdns_phy->regmap_common_cdb,
+                              CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val);
+
+       /* PMA lane configuration to deal with multi-link operation */
+       for (i = 0; i < num_lanes; i++)
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[i],
+                                      XCVR_DIAG_HSCLK_DIV, hsclk_div_val);
+}
+
+static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy,
+                                        unsigned int lane)
+{
+       /* Per lane, refclock-dependent receiver detection setting */
+       if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz)
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                                      TX_RCVDET_ST_TMR, 0x0780);
+       else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz)
+               cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                                      TX_RCVDET_ST_TMR, 0x09C4);
+
+       /* Writing Tx/Rx Power State Controllers registers */
+       cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                              TX_PSC_A0, 0x00FB);
+       cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                              TX_PSC_A2, 0x04AA);
+       cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                              TX_PSC_A3, 0x04AA);
+       cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
+                              RX_PSC_A0, 0x0000);
+       cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
+                              RX_PSC_A2, 0x0000);
+       cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
+                              RX_PSC_A3, 0x0000);
+
+       cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
+                              RX_PSC_CAL, 0x0000);
+
+       cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
+                              RX_REE_GCSM1_CTRL, 0x0000);
+       cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
+                              RX_REE_GCSM2_CTRL, 0x0000);
+       cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane],
+                              RX_REE_PERGCSM_CTRL, 0x0000);
+
+       cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                              XCVR_DIAG_BIDI_CTRL, 0x000F);
+       cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                              XCVR_DIAG_PLLDRC_CTRL, 0x0001);
+       cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane],
+                              XCVR_DIAG_HSCLK_SEL, 0x0000);
+}
+
+static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy,
+                                          u32 num_lanes,
+                                          enum phy_powerstate powerstate)
+{
+       /* Register value for power state for a single byte. */
+       u32 value_part;
+       u32 value;
+       u32 mask;
+       u32 read_val;
+       u32 ret;
+       struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
+
+       switch (powerstate) {
+       case (POWERSTATE_A0):
+               value_part = 0x01U;
+               break;
+       case (POWERSTATE_A2):
+               value_part = 0x04U;
+               break;
+       default:
+               /* Powerstate A3 */
+               value_part = 0x08U;
+               break;
+       }
+
+       /* Select values of registers and mask, depending on enabled
+        * lane count.
+        */
+       switch (num_lanes) {
+       /* lane 0 */
+       case (1):
+               value = value_part;
+               mask = 0x0000003FU;
+               break;
+       /* lanes 0-1 */
+       case (2):
+               value = (value_part
+                        | (value_part << 8));
+               mask = 0x00003F3FU;
+               break;
+       /* lanes 0-3, all */
+       default:
+               value = (value_part
+                        | (value_part << 8)
+                        | (value_part << 16)
+                        | (value_part << 24));
+               mask = 0x3F3F3F3FU;
+               break;
+       }
+
+       /* Set power state A<n>. */
+       cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, value);
+       /* Wait, until PHY acknowledges power state completion. */
+       ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_POWER_STATE_ACK,
+                                      read_val, (read_val & mask) == value, 0,
+                                      POLL_TIMEOUT_US);
+       cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, 0x00000000);
+       ndelay(100);
+
+       return ret;
+}
+
+static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes)
+{
+       unsigned int read_val;
+       int ret;
+       struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg;
+
+       /*
+        * waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the
+        * master lane
+        */
+       ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_PLLCLK_EN_ACK,
+                                      read_val, read_val & 1,
+                                      0, POLL_TIMEOUT_US);
+       if (ret == -ETIMEDOUT) {
+               dev_err(cdns_phy->dev,
+                       "timeout waiting for link PLL clock enable ack\n");
+               return ret;
+       }
+
+       ndelay(100);
+
+       ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes,
+                                             POWERSTATE_A2);
+       if (ret)
+               return ret;
+
+       ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes,
+                                             POWERSTATE_A0);
+
+       return ret;
+}
+
+static int cdns_torrent_phy_on(struct phy *phy)
+{
+       struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
+       struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
+       int ret;
+
+       /* Take the PHY out of reset */
+       ret = reset_control_deassert(cdns_phy->phy_rst);
+       if (ret)
+               return ret;
+
+       /* Take the PHY lane group out of reset */
+       return reset_control_deassert(inst->lnk_rst);
+}
+
+static int cdns_torrent_phy_off(struct phy *phy)
+{
+       struct cdns_torrent_inst *inst = phy_get_drvdata(phy);
+       struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent);
+       int ret;
+
+       ret = reset_control_assert(cdns_phy->phy_rst);
+       if (ret)
+               return ret;
+
+       return reset_control_assert(inst->lnk_rst);
+}
+
+static struct regmap *cdns_regmap_init(struct device *dev, void __iomem *base,
+                                      u32 block_offset,
+                                      u8 reg_offset_shift,
+                                      const struct regmap_config *config)
+{
+       struct cdns_regmap_cdb_context *ctx;
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return ERR_PTR(-ENOMEM);
+
+       ctx->dev = dev;
+       ctx->base = base + block_offset;
+       ctx->reg_offset_shift = reg_offset_shift;
+
+       return devm_regmap_init(dev, NULL, ctx, config);
+}
+
+static int cdns_regfield_init(struct cdns_torrent_phy *cdns_phy)
+{
+       struct device *dev = cdns_phy->dev;
+       struct regmap_field *field;
+       struct regmap *regmap;
+
+       regmap = cdns_phy->regmap_phy_pcs_common_cdb;
+       field = devm_regmap_field_alloc(dev, regmap, phy_pll_cfg);
+       if (IS_ERR(field)) {
+               dev_err(dev, "PHY_PLL_CFG reg field init failed\n");
+               return PTR_ERR(field);
+       }
+       cdns_phy->phy_pll_cfg = field;
+
+       regmap = cdns_phy->regmap_phy_pma_common_cdb;
+       field = devm_regmap_field_alloc(dev, regmap, phy_pma_cmn_ctrl_2);
+       if (IS_ERR(field)) {
+               dev_err(dev, "PHY_PMA_CMN_CTRL2 reg field init failed\n");
+               return PTR_ERR(field);
+       }
+       cdns_phy->phy_pma_cmn_ctrl_2 = field;
+
+       regmap = cdns_phy->regmap_phy_pma_common_cdb;
+       field = devm_regmap_field_alloc(dev, regmap, phy_pma_pll_raw_ctrl);
+       if (IS_ERR(field)) {
+               dev_err(dev, "PHY_PMA_PLL_RAW_CTRL reg field init failed\n");
+               return PTR_ERR(field);
+       }
+       cdns_phy->phy_pma_pll_raw_ctrl = field;
+
+       regmap = cdns_phy->regmap_dptx_phy_reg;
+       field = devm_regmap_field_alloc(dev, regmap, phy_reset_ctrl);
+       if (IS_ERR(field)) {
+               dev_err(dev, "PHY_RESET reg field init failed\n");
+               return PTR_ERR(field);
+       }
+       cdns_phy->phy_reset_ctrl = field;
+
+       return 0;
+}
+
+static int cdns_regmap_init_torrent_dp(struct cdns_torrent_phy *cdns_phy,
+                                      void __iomem *sd_base,
+                                      void __iomem *base,
+                                      u8 block_offset_shift,
+                                      u8 reg_offset_shift)
+{
+       struct device *dev = cdns_phy->dev;
+       struct regmap *regmap;
+       u32 block_offset;
+       int i;
+
+       for (i = 0; i < MAX_NUM_LANES; i++) {
+               block_offset = TORRENT_TX_LANE_CDB_OFFSET(i, block_offset_shift,
+                                                         reg_offset_shift);
+               regmap = cdns_regmap_init(dev, sd_base, block_offset,
+                                         reg_offset_shift,
+                                         &cdns_torrent_tx_lane_cdb_config[i]);
+               if (IS_ERR(regmap)) {
+                       dev_err(dev, "Failed to init tx lane CDB regmap\n");
+                       return PTR_ERR(regmap);
+               }
+               cdns_phy->regmap_tx_lane_cdb[i] = regmap;
+
+               block_offset = TORRENT_RX_LANE_CDB_OFFSET(i, block_offset_shift,
+                                                         reg_offset_shift);
+               regmap = cdns_regmap_init(dev, sd_base, block_offset,
+                                         reg_offset_shift,
+                                         &cdns_torrent_rx_lane_cdb_config[i]);
+               if (IS_ERR(regmap)) {
+                       dev_err(dev, "Failed to init rx lane CDB regmap\n");
+                       return PTR_ERR(regmap);
+               }
+               cdns_phy->regmap_rx_lane_cdb[i] = regmap;
+       }
+
+       block_offset = TORRENT_COMMON_CDB_OFFSET;
+       regmap = cdns_regmap_init(dev, sd_base, block_offset,
+                                 reg_offset_shift,
+                                 &cdns_torrent_common_cdb_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to init common CDB regmap\n");
+               return PTR_ERR(regmap);
+       }
+       cdns_phy->regmap_common_cdb = regmap;
+
+       block_offset = TORRENT_PHY_PCS_COMMON_OFFSET(block_offset_shift);
+       regmap = cdns_regmap_init(dev, sd_base, block_offset,
+                                 reg_offset_shift,
+                                 &cdns_torrent_phy_pcs_cmn_cdb_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to init PHY PCS common CDB regmap\n");
+               return PTR_ERR(regmap);
+       }
+       cdns_phy->regmap_phy_pcs_common_cdb = regmap;
+
+       block_offset = TORRENT_PHY_PMA_COMMON_OFFSET(block_offset_shift);
+       regmap = cdns_regmap_init(dev, sd_base, block_offset,
+                                 reg_offset_shift,
+                                 &cdns_torrent_phy_pma_cmn_cdb_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to init PHY PMA common CDB regmap\n");
+               return PTR_ERR(regmap);
+       }
+       cdns_phy->regmap_phy_pma_common_cdb = regmap;
+
+       block_offset = TORRENT_DPTX_PHY_OFFSET;
+       regmap = cdns_regmap_init(dev, base, block_offset,
+                                 reg_offset_shift,
+                                 &cdns_torrent_dptx_phy_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to init DPTX PHY regmap\n");
+               return PTR_ERR(regmap);
+       }
+       cdns_phy->regmap_dptx_phy_reg = regmap;
+
+       return 0;
+}
+
+static int cdns_torrent_phy_probe(struct platform_device *pdev)
+{
+       struct resource *regs;
+       struct cdns_torrent_phy *cdns_phy;
+       struct device *dev = &pdev->dev;
+       struct phy_provider *phy_provider;
+       const struct of_device_id *match;
+       struct cdns_torrent_data *data;
+       struct device_node *child;
+       int ret, subnodes, node = 0, i;
+
+       /* Get init data for this PHY */
+       match = of_match_device(cdns_torrent_phy_of_match, dev);
+       if (!match)
+               return -EINVAL;
+
+       data = (struct cdns_torrent_data *)match->data;
+
+       cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL);
+       if (!cdns_phy)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, cdns_phy);
+       cdns_phy->dev = dev;
+
+       cdns_phy->phy_rst = devm_reset_control_get_exclusive_by_index(dev, 0);
+       if (IS_ERR(cdns_phy->phy_rst)) {
+               dev_err(dev, "%s: failed to get reset\n",
+                       dev->of_node->full_name);
+               return PTR_ERR(cdns_phy->phy_rst);
+       }
+
+       cdns_phy->clk = devm_clk_get(dev, "refclk");
+       if (IS_ERR(cdns_phy->clk)) {
+               dev_err(dev, "phy ref clock not found\n");
+               return PTR_ERR(cdns_phy->clk);
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       cdns_phy->sd_base = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(cdns_phy->sd_base))
+               return PTR_ERR(cdns_phy->sd_base);
+
+       subnodes = of_get_available_child_count(dev->of_node);
+       if (subnodes == 0) {
+               dev_err(dev, "No available link subnodes found\n");
+               return -EINVAL;
+       } else if (subnodes != 1) {
+               dev_err(dev, "Driver supports only one link subnode.\n");
+               return -EINVAL;
+       }
+
+       for_each_available_child_of_node(dev->of_node, child) {
+               struct phy *gphy;
+
+               cdns_phy->phys[node].lnk_rst =
+                               of_reset_control_array_get_exclusive(child);
+               if (IS_ERR(cdns_phy->phys[node].lnk_rst)) {
+                       dev_err(dev, "%s: failed to get reset\n",
+                               child->full_name);
+                       ret = PTR_ERR(cdns_phy->phys[node].lnk_rst);
+                       goto put_lnk_rst;
+               }
+
+               if (of_property_read_u32(child, "reg",
+                                        &cdns_phy->phys[node].mlane)) {
+                       dev_err(dev, "%s: No \"reg\"-property.\n",
+                               child->full_name);
+                       ret = -EINVAL;
+                       goto put_child;
+               }
+
+               if (cdns_phy->phys[node].mlane != 0) {
+                       dev_err(dev,
+                               "%s: Driver supports only lane-0 as master lane.\n",
+                               child->full_name);
+                       ret = -EINVAL;
+                       goto put_child;
+               }
+
+               if (of_property_read_u32(child, "cdns,phy-type",
+                                        &cdns_phy->phys[node].phy_type)) {
+                       dev_err(dev, "%s: No \"cdns,phy-type\"-property.\n",
+                               child->full_name);
+                       ret = -EINVAL;
+                       goto put_child;
+               }
+
+               cdns_phy->phys[node].num_lanes = DEFAULT_NUM_LANES;
+               of_property_read_u32(child, "cdns,num-lanes",
+                                    &cdns_phy->phys[node].num_lanes);
+
+               if (cdns_phy->phys[node].phy_type == PHY_TYPE_DP) {
+                       switch (cdns_phy->phys[node].num_lanes) {
+                       case 1:
+                       case 2:
+                       case 4:
+                       /* valid number of lanes */
+                               break;
+                       default:
+                               dev_err(dev, "unsupported number of lanes: %d\n",
+                                       cdns_phy->phys[node].num_lanes);
+                               ret = -EINVAL;
+                               goto put_child;
+                       }
+
+                       cdns_phy->max_bit_rate = DEFAULT_MAX_BIT_RATE;
+                       of_property_read_u32(child, "cdns,max-bit-rate",
+                                            &cdns_phy->max_bit_rate);
+
+                       switch (cdns_phy->max_bit_rate) {
+                       case 1620:
+                       case 2160:
+                       case 2430:
+                       case 2700:
+                       case 3240:
+                       case 4320:
+                       case 5400:
+                       case 8100:
+                       /* valid bit rate */
+                               break;
+                       default:
+                               dev_err(dev, "unsupported max bit rate: %dMbps\n",
+                                       cdns_phy->max_bit_rate);
+                               ret = -EINVAL;
+                               goto put_child;
+                       }
+
+                       /* DPTX registers */
+                       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+                       cdns_phy->base = devm_ioremap_resource(&pdev->dev,
+                                                              regs);
+                       if (IS_ERR(cdns_phy->base)) {
+                               ret = PTR_ERR(cdns_phy->base);
+                               goto put_child;
+                       }
+
+                       gphy = devm_phy_create(dev, child,
+                                              &cdns_torrent_phy_ops);
+                       if (IS_ERR(gphy)) {
+                               ret = PTR_ERR(gphy);
+                               goto put_child;
+                       }
+
+                       dev_info(dev, "%d lanes, max bit rate %d.%03d Gbps\n",
+                                cdns_phy->phys[node].num_lanes,
+                                cdns_phy->max_bit_rate / 1000,
+                                cdns_phy->max_bit_rate % 1000);
+               } else {
+                       dev_err(dev, "Driver supports only PHY_TYPE_DP\n");
+                       ret = -ENOTSUPP;
+                       goto put_child;
+               }
+               cdns_phy->phys[node].phy = gphy;
+               phy_set_drvdata(gphy, &cdns_phy->phys[node]);
+
+               node++;
+       }
+       cdns_phy->nsubnodes = node;
+
+       ret = cdns_regmap_init_torrent_dp(cdns_phy, cdns_phy->sd_base,
+                                         cdns_phy->base,
+                                         data->block_offset_shift,
+                                         data->reg_offset_shift);
+       if (ret)
+               goto put_lnk_rst;
+
+       ret = cdns_regfield_init(cdns_phy);
+       if (ret)
+               goto put_lnk_rst;
+
+       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(phy_provider)) {
+               ret = PTR_ERR(phy_provider);
+               goto put_lnk_rst;
+       }
+
+       return 0;
+
+put_child:
+       node++;
+put_lnk_rst:
+       for (i = 0; i < node; i++)
+               reset_control_put(cdns_phy->phys[i].lnk_rst);
+       of_node_put(child);
+       return ret;
+}
+
+static int cdns_torrent_phy_remove(struct platform_device *pdev)
+{
+       struct cdns_torrent_phy *cdns_phy = platform_get_drvdata(pdev);
+       int i;
+
+       reset_control_assert(cdns_phy->phy_rst);
+       for (i = 0; i < cdns_phy->nsubnodes; i++) {
+               reset_control_assert(cdns_phy->phys[i].lnk_rst);
+               reset_control_put(cdns_phy->phys[i].lnk_rst);
+       }
+
+       return 0;
+}
+
+static const struct cdns_torrent_data cdns_map_torrent = {
+       .block_offset_shift = 0x2,
+       .reg_offset_shift = 0x2,
+};
+
+static const struct cdns_torrent_data ti_j721e_map_torrent = {
+       .block_offset_shift = 0x0,
+       .reg_offset_shift = 0x1,
+};
+
+static const struct of_device_id cdns_torrent_phy_of_match[] = {
+       {
+               .compatible = "cdns,torrent-phy",
+               .data = &cdns_map_torrent,
+       },
+       {
+               .compatible = "ti,j721e-serdes-10g",
+               .data = &ti_j721e_map_torrent,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, cdns_torrent_phy_of_match);
+
+static struct platform_driver cdns_torrent_phy_driver = {
+       .probe  = cdns_torrent_phy_probe,
+       .remove = cdns_torrent_phy_remove,
+       .driver = {
+               .name   = "cdns-torrent-phy",
+               .of_match_table = cdns_torrent_phy_of_match,
+       }
+};
+module_platform_driver(cdns_torrent_phy_driver);
+
+MODULE_AUTHOR("Cadence Design Systems, Inc.");
+MODULE_DESCRIPTION("Cadence Torrent PHY driver");
+MODULE_LICENSE("GPL v2");
index cb2ed3b..cdbcc49 100644 (file)
@@ -43,6 +43,8 @@
 #define PA0_RG_USB20_INTR_EN           BIT(5)
 
 #define U3P_USBPHYACR1         0x004
+#define PA1_RG_INTR_CAL                GENMASK(23, 19)
+#define PA1_RG_INTR_CAL_VAL(x) ((0x1f & (x)) << 19)
 #define PA1_RG_VRT_SEL                 GENMASK(14, 12)
 #define PA1_RG_VRT_SEL_VAL(x)  ((0x7 & (x)) << 12)
 #define PA1_RG_TERM_SEL                GENMASK(10, 8)
@@ -60,6 +62,8 @@
 #define U3P_USBPHYACR6         0x018
 #define PA6_RG_U2_BC11_SW_EN           BIT(23)
 #define PA6_RG_U2_OTG_VBUSCMP_EN       BIT(20)
+#define PA6_RG_U2_DISCTH               GENMASK(7, 4)
+#define PA6_RG_U2_DISCTH_VAL(x)        ((0xf & (x)) << 4)
 #define PA6_RG_U2_SQTH         GENMASK(3, 0)
 #define PA6_RG_U2_SQTH_VAL(x)  (0xf & (x))
 
@@ -294,20 +298,21 @@ struct mtk_phy_instance {
                struct u2phy_banks u2_banks;
                struct u3phy_banks u3_banks;
        };
-       struct clk *ref_clk;    /* reference clock of anolog phy */
+       struct clk *ref_clk;    /* reference clock of (digital) phy */
+       struct clk *da_ref_clk; /* reference clock of analog phy */
        u32 index;
        u8 type;
        int eye_src;
        int eye_vrt;
        int eye_term;
+       int intr;
+       int discth;
        bool bc12_en;
 };
 
 struct mtk_tphy {
        struct device *dev;
        void __iomem *sif_base; /* only shared sif */
-       /* deprecated, use @ref_clk instead in phy instance */
-       struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
        const struct mtk_phy_pdata *pdata;
        struct mtk_phy_instance **phys;
        int nphys;
@@ -850,9 +855,14 @@ static void phy_parse_property(struct mtk_tphy *tphy,
                                 &instance->eye_vrt);
        device_property_read_u32(dev, "mediatek,eye-term",
                                 &instance->eye_term);
-       dev_dbg(dev, "bc12:%d, src:%d, vrt:%d, term:%d\n",
+       device_property_read_u32(dev, "mediatek,intr",
+                                &instance->intr);
+       device_property_read_u32(dev, "mediatek,discth",
+                                &instance->discth);
+       dev_dbg(dev, "bc12:%d, src:%d, vrt:%d, term:%d, intr:%d, disc:%d\n",
                instance->bc12_en, instance->eye_src,
-               instance->eye_vrt, instance->eye_term);
+               instance->eye_vrt, instance->eye_term,
+               instance->intr, instance->discth);
 }
 
 static void u2_phy_props_set(struct mtk_tphy *tphy,
@@ -888,6 +898,20 @@ static void u2_phy_props_set(struct mtk_tphy *tphy,
                tmp |= PA1_RG_TERM_SEL_VAL(instance->eye_term);
                writel(tmp, com + U3P_USBPHYACR1);
        }
+
+       if (instance->intr) {
+               tmp = readl(com + U3P_USBPHYACR1);
+               tmp &= ~PA1_RG_INTR_CAL;
+               tmp |= PA1_RG_INTR_CAL_VAL(instance->intr);
+               writel(tmp, com + U3P_USBPHYACR1);
+       }
+
+       if (instance->discth) {
+               tmp = readl(com + U3P_USBPHYACR6);
+               tmp &= ~PA6_RG_U2_DISCTH;
+               tmp |= PA6_RG_U2_DISCTH_VAL(instance->discth);
+               writel(tmp, com + U3P_USBPHYACR6);
+       }
 }
 
 static int mtk_phy_init(struct phy *phy)
@@ -896,15 +920,16 @@ static int mtk_phy_init(struct phy *phy)
        struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);
        int ret;
 
-       ret = clk_prepare_enable(tphy->u3phya_ref);
+       ret = clk_prepare_enable(instance->ref_clk);
        if (ret) {
-               dev_err(tphy->dev, "failed to enable u3phya_ref\n");
+               dev_err(tphy->dev, "failed to enable ref_clk\n");
                return ret;
        }
 
-       ret = clk_prepare_enable(instance->ref_clk);
+       ret = clk_prepare_enable(instance->da_ref_clk);
        if (ret) {
-               dev_err(tphy->dev, "failed to enable ref_clk\n");
+               dev_err(tphy->dev, "failed to enable da_ref\n");
+               clk_disable_unprepare(instance->ref_clk);
                return ret;
        }
 
@@ -967,7 +992,7 @@ static int mtk_phy_exit(struct phy *phy)
                u2_phy_instance_exit(tphy, instance);
 
        clk_disable_unprepare(instance->ref_clk);
-       clk_disable_unprepare(tphy->u3phya_ref);
+       clk_disable_unprepare(instance->da_ref_clk);
        return 0;
 }
 
@@ -1102,11 +1127,6 @@ static int mtk_tphy_probe(struct platform_device *pdev)
                }
        }
 
-       /* it's deprecated, make it optional for backward compatibility */
-       tphy->u3phya_ref = devm_clk_get_optional(dev, "u3phya_ref");
-       if (IS_ERR(tphy->u3phya_ref))
-               return PTR_ERR(tphy->u3phya_ref);
-
        tphy->src_ref_clk = U3P_REF_CLK;
        tphy->src_coef = U3P_SLEW_RATE_COEF;
        /* update parameters of slew rate calibrate if exist */
@@ -1153,16 +1173,20 @@ static int mtk_tphy_probe(struct platform_device *pdev)
                phy_set_drvdata(phy, instance);
                port++;
 
-               /* if deprecated clock is provided, ignore instance's one */
-               if (tphy->u3phya_ref)
-                       continue;
-
-               instance->ref_clk = devm_clk_get(&phy->dev, "ref");
+               instance->ref_clk = devm_clk_get_optional(&phy->dev, "ref");
                if (IS_ERR(instance->ref_clk)) {
                        dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
                        retval = PTR_ERR(instance->ref_clk);
                        goto put_child;
                }
+
+               instance->da_ref_clk =
+                       devm_clk_get_optional(&phy->dev, "da_ref");
+               if (IS_ERR(instance->da_ref_clk)) {
+                       dev_err(dev, "failed to get da_ref_clk(id-%d)\n", port);
+                       retval = PTR_ERR(instance->da_ref_clk);
+                       goto put_child;
+               }
        }
 
        provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);
index f20524f..94a34cf 100644 (file)
@@ -20,6 +20,7 @@
 
 #define PHY_MDM6600_PHY_DELAY_MS       4000    /* PHY enable 2.2s to 3.5s */
 #define PHY_MDM6600_ENABLED_DELAY_MS   8000    /* 8s more total for MDM6600 */
+#define PHY_MDM6600_WAKE_KICK_MS       600     /* time on after GPIO toggle */
 #define MDM6600_MODEM_IDLE_DELAY_MS    1000    /* modem after USB suspend */
 #define MDM6600_MODEM_WAKE_DELAY_MS    200     /* modem response after idle */
 
@@ -243,10 +244,24 @@ static irqreturn_t phy_mdm6600_wakeirq_thread(int irq, void *data)
 {
        struct phy_mdm6600 *ddata = data;
        struct gpio_desc *mode_gpio1;
+       int error, wakeup;
 
        mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
-       dev_dbg(ddata->dev, "OOB wake on mode_gpio1: %i\n",
-               gpiod_get_value(mode_gpio1));
+       wakeup = gpiod_get_value(mode_gpio1);
+       if (!wakeup)
+               return IRQ_NONE;
+
+       dev_dbg(ddata->dev, "OOB wake on mode_gpio1: %i\n", wakeup);
+       error = pm_runtime_get_sync(ddata->dev);
+       if (error < 0) {
+               pm_runtime_put_noidle(ddata->dev);
+
+               return IRQ_NONE;
+       }
+
+       /* Just wake-up and kick the autosuspend timer */
+       pm_runtime_mark_last_busy(ddata->dev);
+       pm_runtime_put_autosuspend(ddata->dev);
 
        return IRQ_HANDLED;
 }
@@ -496,8 +511,14 @@ static void phy_mdm6600_modem_wake(struct work_struct *work)
 
        ddata = container_of(work, struct phy_mdm6600, modem_wake_work.work);
        phy_mdm6600_wake_modem(ddata);
+
+       /*
+        * The modem does not always stay awake 1.2 seconds after toggling
+        * the wake GPIO, and sometimes it idles after about some 600 ms
+        * making writes time out.
+        */
        schedule_delayed_work(&ddata->modem_wake_work,
-                             msecs_to_jiffies(MDM6600_MODEM_IDLE_DELAY_MS));
+                             msecs_to_jiffies(PHY_MDM6600_WAKE_KICK_MS));
 }
 
 static int __maybe_unused phy_mdm6600_runtime_suspend(struct device *dev)
index cd5a6c9..a27b8d5 100644 (file)
@@ -688,11 +688,9 @@ struct phy *phy_get(struct device *dev, const char *string)
        get_device(&phy->dev);
 
        link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
-       if (!link) {
-               dev_err(dev, "failed to create device link to %s\n",
+       if (!link)
+               dev_dbg(dev, "failed to create device link to %s\n",
                        dev_name(phy->dev.parent));
-               return ERR_PTR(-EINVAL);
-       }
 
        return phy;
 }
@@ -803,11 +801,9 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
        }
 
        link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
-       if (!link) {
-               dev_err(dev, "failed to create device link to %s\n",
+       if (!link)
+               dev_dbg(dev, "failed to create device link to %s\n",
                        dev_name(phy->dev.parent));
-               return ERR_PTR(-EINVAL);
-       }
 
        return phy;
 }
@@ -852,11 +848,9 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
        devres_add(dev, ptr);
 
        link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
-       if (!link) {
-               dev_err(dev, "failed to create device link to %s\n",
+       if (!link)
+               dev_dbg(dev, "failed to create device link to %s\n",
                        dev_name(phy->dev.parent));
-               return ERR_PTR(-EINVAL);
-       }
 
        return phy;
 }
index e46824d..98674ed 100644 (file)
@@ -91,3 +91,23 @@ config PHY_QCOM_USB_HSIC
        select GENERIC_PHY
        help
          Support for the USB HSIC ULPI compliant PHY on QCOM chipsets.
+
+config PHY_QCOM_USB_HS_28NM
+       tristate "Qualcomm 28nm High-Speed PHY"
+       depends on ARCH_QCOM || COMPILE_TEST
+       depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in
+       select GENERIC_PHY
+       help
+         Enable this to support the Qualcomm Synopsys DesignWare Core 28nm
+         High-Speed PHY driver. This driver supports the Hi-Speed PHY which
+         is usually paired with either the ChipIdea or Synopsys DWC3 USB
+         IPs on MSM SOCs.
+
+config PHY_QCOM_USB_SS
+       tristate "Qualcomm USB Super-Speed PHY driver"
+       depends on ARCH_QCOM || COMPILE_TEST
+       depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in
+       select GENERIC_PHY
+       help
+         Enable this to support the Super-Speed USB transceiver on various
+         Qualcomm chipsets.
index 283251d..1f14aea 100644 (file)
@@ -10,3 +10,5 @@ obj-$(CONFIG_PHY_QCOM_UFS_14NM)               += phy-qcom-ufs-qmp-14nm.o
 obj-$(CONFIG_PHY_QCOM_UFS_20NM)                += phy-qcom-ufs-qmp-20nm.o
 obj-$(CONFIG_PHY_QCOM_USB_HS)          += phy-qcom-usb-hs.o
 obj-$(CONFIG_PHY_QCOM_USB_HSIC)        += phy-qcom-usb-hsic.o
+obj-$(CONFIG_PHY_QCOM_USB_HS_28NM)     += phy-qcom-usb-hs-28nm.o
+obj-$(CONFIG_PHY_QCOM_USB_SS)          += phy-qcom-usb-ss.o
index 7db2a94..c190406 100644 (file)
@@ -121,6 +121,11 @@ enum qphy_reg_layout {
        QPHY_PCS_LFPS_RXTERM_IRQ_STATUS,
 };
 
+static const unsigned int msm8996_ufsphy_regs_layout[] = {
+       [QPHY_START_CTRL]               = 0x00,
+       [QPHY_PCS_READY_STATUS]         = 0x168,
+};
+
 static const unsigned int pciephy_regs_layout[] = {
        [QPHY_COM_SW_RESET]             = 0x400,
        [QPHY_COM_POWER_DOWN_CONTROL]   = 0x404,
@@ -160,6 +165,18 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
        [QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
 };
 
+static const unsigned int sdm845_qmp_pciephy_regs_layout[] = {
+       [QPHY_SW_RESET]                 = 0x00,
+       [QPHY_START_CTRL]               = 0x08,
+       [QPHY_PCS_STATUS]               = 0x174,
+};
+
+static const unsigned int sdm845_qhp_pciephy_regs_layout[] = {
+       [QPHY_SW_RESET]                 = 0x00,
+       [QPHY_START_CTRL]               = 0x08,
+       [QPHY_PCS_STATUS]               = 0x2ac,
+};
+
 static const unsigned int sdm845_ufsphy_regs_layout[] = {
        [QPHY_START_CTRL]               = 0x00,
        [QPHY_PCS_READY_STATUS]         = 0x160,
@@ -331,6 +348,75 @@ static const struct qmp_phy_init_tbl msm8998_pcie_pcs_tbl[] = {
        QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03),
 };
 
+static const struct qmp_phy_init_tbl msm8996_ufs_serdes_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_POWER_DOWN_CONTROL, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e),
+       QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0xd7),
+       QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
+       QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06),
+       QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+       QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a),
+       QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x05),
+       QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a),
+       QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
+       QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x10),
+       QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20),
+       QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x54),
+       QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
+       QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82),
+       QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
+       QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+       QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+       QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
+       QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
+       QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98),
+       QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
+       QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
+       QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
+       QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
+       QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
+       QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
+       QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
+       QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
+};
+
+static const struct qmp_phy_init_tbl msm8996_ufs_tx_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
+       QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x02),
+};
+
+static const struct qmp_phy_init_tbl msm8996_ufs_rx_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24),
+       QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x18),
+       QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
+       QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5b),
+       QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3f),
+       QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x0f),
+       QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E),
+};
+
 static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
        QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
@@ -481,6 +567,229 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_pcs_tbl[] = {
        QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3),
 };
 
+static const struct qmp_phy_init_tbl sdm845_qmp_pcie_serdes_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x007),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_TIMER1, 0xff),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_TIMER2, 0x3f),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_EP_DIV, 0x19),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_ENABLE1, 0x90),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0d),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x04),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x33),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x06),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x04),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x09),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x40),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x7e),
+       QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x15),
+};
+
+static const struct qmp_phy_init_tbl sdm845_qmp_pcie_tx_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x02),
+       QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
+       QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
+       QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06),
+};
+
+static const struct qmp_phy_init_tbl sdm845_qmp_pcie_rx_tbl[] = {
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x10),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x14),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0e),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1a),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x04),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN_HALF, 0x04),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x71),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_01, 0x59),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x71),
+       QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x40),
+};
+
+static const struct qmp_phy_init_tbl sdm845_qmp_pcie_pcs_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_ENDPOINT_REFCLK_DRIVE, 0x04),
+
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
+
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_OSC_DTCT_ACTIONS, 0x00),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x01),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x00),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB, 0x20),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x00),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK, 0x01),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_PLL_LOCK_CHK_DLY_TIME, 0x73),
+
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0xbb),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG1, 0x0d),
+
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG4, 0x00),
+};
+
+static const struct qmp_phy_init_tbl sdm845_qmp_pcie_pcs_misc_tbl[] = {
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_CONFIG2, 0x52),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG2, 0x10),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG4, 0x1a),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG5, 0x06),
+       QMP_PHY_INIT_CFG(QPHY_V3_PCS_MISC_PCIE_INT_AUX_CLK_CONFIG1, 0x00),
+};
+
+static const struct qmp_phy_init_tbl sdm845_qhp_pcie_serdes_tbl[] = {
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SYSCLK_EN_SEL, 0x27),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_EN_CENTER, 0x01),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_PER1, 0x31),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_PER2, 0x01),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1, 0xde),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2, 0x07),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1_MODE1, 0x4c),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2_MODE1, 0x06),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BIAS_EN_CKBUFLR_EN, 0x18),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CLK_ENABLE1, 0xb0),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE0, 0x8c),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE0, 0x20),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE1, 0x14),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE1, 0x34),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CP_CTRL_MODE0, 0x06),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CP_CTRL_MODE1, 0x06),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE0, 0x16),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE1, 0x16),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE0, 0x36),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE1, 0x36),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_RESTRIM_CTRL2, 0x05),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_LOCK_CMP_EN, 0x42),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DEC_START_MODE0, 0x82),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DEC_START_MODE1, 0x68),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE0, 0x55),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE0, 0x55),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE0, 0x03),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE1, 0xab),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE1, 0xaa),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE1, 0x02),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE1, 0x3f),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VCO_TUNE_MAP, 0x10),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CLK_SELECT, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_HSCLK_SEL1, 0x30),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORECLK_DIV, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORE_CLK_EN, 0x73),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CMN_CONFIG, 0x0c),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_SVS_MODE_CLK_SEL, 0x15),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CORECLK_DIV_MODE1, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_CMN_MODE, 0x01),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VREGCLK_DIV1, 0x22),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_VREGCLK_DIV2, 0x00),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BGV_TRIM, 0x20),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_COM_BG_CTRL, 0x07),
+};
+
+static const struct qmp_phy_init_tbl sdm845_qhp_pcie_tx_tbl[] = {
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL0, 0x00),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_TAP_EN, 0x0d),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_TX_BAND_MODE, 0x01),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_LANE_MODE, 0x1a),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PARALLEL_RATE, 0x2f),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE0, 0x09),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE1, 0x09),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CML_CTRL_MODE2, 0x1b),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE1, 0x01),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE2, 0x07),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE0, 0x31),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE1, 0x31),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE2, 0x03),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_THRESH_DFE, 0x02),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CGA_THRESH_DFE, 0x00),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXENGINE_EN0, 0x12),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_TRAIN_TIME, 0x25),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_CTLE_DFE_OVRLP_TIME, 0x00),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_REFRESH_TIME, 0x05),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_ENABLE_TIME, 0x01),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_VGA_GAIN, 0x26),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DFE_GAIN, 0x12),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EQ_GAIN, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_OFFSET_GAIN, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PRE_GAIN, 0x09),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EQ_INTVAL, 0x15),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_EDAC_INITVAL, 0x28),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_INITB0, 0x7f),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_INITB1, 0x07),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RCVRDONE_THRESH1, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RXEQ_CTRL, 0x70),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE0, 0x8b),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE1, 0x08),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE2, 0x0a),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE0, 0x03),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE1, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE2, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_UCDR_SO_CONFIG, 0x0c),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_BAND, 0x02),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE0, 0x5c),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE1, 0x3e),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE2, 0x3f),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_ENABLES, 0x01),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_CNTRL, 0xa0),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_SIGDET_DEGLITCH_CNTRL, 0x08),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DCC_GAIN, 0x01),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_EN_SIGNAL, 0xc3),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_PSM_RX_EN_CAL, 0x00),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_MISC_CNTRL0, 0xbc),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_TS0_TIMER, 0x7f),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DLL_HIGHDATARATE, 0x15),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL1, 0x0c),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_DRVR_CTRL2, 0x0f),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RX_RESETCODE_OFFSET, 0x04),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_VGA_INITVAL, 0x20),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RSM_START, 0x01),
+};
+
+static const struct qmp_phy_init_tbl sdm845_qhp_pcie_rx_tbl[] = {
+};
+
+static const struct qmp_phy_init_tbl sdm845_qhp_pcie_pcs_tbl[] = {
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG, 0x3f),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG, 0x50),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M3P5DB, 0x19),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M3P5DB, 0x07),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M6DB, 0x17),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M6DB, 0x09),
+       QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG5, 0x9f),
+};
+
 static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {
        QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
        QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
@@ -988,6 +1297,8 @@ struct qmp_phy_cfg {
        int rx_tbl_num;
        const struct qmp_phy_init_tbl *pcs_tbl;
        int pcs_tbl_num;
+       const struct qmp_phy_init_tbl *pcs_misc_tbl;
+       int pcs_misc_tbl_num;
 
        /* clock ids to be requested */
        const char * const *clk_list;
@@ -1122,10 +1433,18 @@ static const char * const msm8996_phy_clk_l[] = {
        "aux", "cfg_ahb", "ref",
 };
 
+static const char * const msm8996_ufs_phy_clk_l[] = {
+       "ref",
+};
+
 static const char * const qmp_v3_phy_clk_l[] = {
        "aux", "cfg_ahb", "ref", "com_aux",
 };
 
+static const char * const sdm845_pciephy_clk_l[] = {
+       "aux", "cfg_ahb", "ref", "refgen",
+};
+
 static const char * const sdm845_ufs_phy_clk_l[] = {
        "ref", "ref_aux",
 };
@@ -1139,6 +1458,10 @@ static const char * const msm8996_usb3phy_reset_l[] = {
        "phy", "common",
 };
 
+static const char * const sdm845_pciephy_reset_l[] = {
+       "phy",
+};
+
 /* list of regulators */
 static const char * const qmp_phy_vreg_l[] = {
        "vdda-phy", "vdda-pll",
@@ -1175,6 +1498,31 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
        .pwrdn_delay_max        = POWER_DOWN_DELAY_US_MAX,
 };
 
+static const struct qmp_phy_cfg msm8996_ufs_cfg = {
+       .type                   = PHY_TYPE_UFS,
+       .nlanes                 = 1,
+
+       .serdes_tbl             = msm8996_ufs_serdes_tbl,
+       .serdes_tbl_num         = ARRAY_SIZE(msm8996_ufs_serdes_tbl),
+       .tx_tbl                 = msm8996_ufs_tx_tbl,
+       .tx_tbl_num             = ARRAY_SIZE(msm8996_ufs_tx_tbl),
+       .rx_tbl                 = msm8996_ufs_rx_tbl,
+       .rx_tbl_num             = ARRAY_SIZE(msm8996_ufs_rx_tbl),
+
+       .clk_list               = msm8996_ufs_phy_clk_l,
+       .num_clks               = ARRAY_SIZE(msm8996_ufs_phy_clk_l),
+
+       .vreg_list              = qmp_phy_vreg_l,
+       .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
+
+       .regs                   = msm8996_ufsphy_regs_layout,
+
+       .start_ctrl             = SERDES_START,
+       .pwrdn_ctrl             = SW_PWRDN,
+
+       .no_pcs_sw_reset        = true,
+};
+
 static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
        .type                   = PHY_TYPE_USB3,
        .nlanes                 = 1,
@@ -1234,6 +1582,64 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
        .pwrdn_delay_max        = 1005,         /* us */
 };
 
+static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
+       .type = PHY_TYPE_PCIE,
+       .nlanes = 1,
+
+       .serdes_tbl             = sdm845_qmp_pcie_serdes_tbl,
+       .serdes_tbl_num         = ARRAY_SIZE(sdm845_qmp_pcie_serdes_tbl),
+       .tx_tbl                 = sdm845_qmp_pcie_tx_tbl,
+       .tx_tbl_num             = ARRAY_SIZE(sdm845_qmp_pcie_tx_tbl),
+       .rx_tbl                 = sdm845_qmp_pcie_rx_tbl,
+       .rx_tbl_num             = ARRAY_SIZE(sdm845_qmp_pcie_rx_tbl),
+       .pcs_tbl                = sdm845_qmp_pcie_pcs_tbl,
+       .pcs_tbl_num            = ARRAY_SIZE(sdm845_qmp_pcie_pcs_tbl),
+       .pcs_misc_tbl           = sdm845_qmp_pcie_pcs_misc_tbl,
+       .pcs_misc_tbl_num       = ARRAY_SIZE(sdm845_qmp_pcie_pcs_misc_tbl),
+       .clk_list               = sdm845_pciephy_clk_l,
+       .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
+       .reset_list             = sdm845_pciephy_reset_l,
+       .num_resets             = ARRAY_SIZE(sdm845_pciephy_reset_l),
+       .vreg_list              = qmp_phy_vreg_l,
+       .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
+       .regs                   = sdm845_qmp_pciephy_regs_layout,
+
+       .start_ctrl             = PCS_START | SERDES_START,
+       .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
+
+       .has_pwrdn_delay        = true,
+       .pwrdn_delay_min        = 995,          /* us */
+       .pwrdn_delay_max        = 1005,         /* us */
+};
+
+static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = {
+       .type = PHY_TYPE_PCIE,
+       .nlanes = 1,
+
+       .serdes_tbl             = sdm845_qhp_pcie_serdes_tbl,
+       .serdes_tbl_num         = ARRAY_SIZE(sdm845_qhp_pcie_serdes_tbl),
+       .tx_tbl                 = sdm845_qhp_pcie_tx_tbl,
+       .tx_tbl_num             = ARRAY_SIZE(sdm845_qhp_pcie_tx_tbl),
+       .rx_tbl                 = sdm845_qhp_pcie_rx_tbl,
+       .rx_tbl_num             = ARRAY_SIZE(sdm845_qhp_pcie_rx_tbl),
+       .pcs_tbl                = sdm845_qhp_pcie_pcs_tbl,
+       .pcs_tbl_num            = ARRAY_SIZE(sdm845_qhp_pcie_pcs_tbl),
+       .clk_list               = sdm845_pciephy_clk_l,
+       .num_clks               = ARRAY_SIZE(sdm845_pciephy_clk_l),
+       .reset_list             = sdm845_pciephy_reset_l,
+       .num_resets             = ARRAY_SIZE(sdm845_pciephy_reset_l),
+       .vreg_list              = qmp_phy_vreg_l,
+       .num_vregs              = ARRAY_SIZE(qmp_phy_vreg_l),
+       .regs                   = sdm845_qhp_pciephy_regs_layout,
+
+       .start_ctrl             = PCS_START | SERDES_START,
+       .pwrdn_ctrl             = SW_PWRDN | REFCLK_DRV_DSBL,
+
+       .has_pwrdn_delay        = true,
+       .pwrdn_delay_min        = 995,          /* us */
+       .pwrdn_delay_max        = 1005,         /* us */
+};
+
 static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
        .type                   = PHY_TYPE_USB3,
        .nlanes                 = 1,
@@ -1563,6 +1969,7 @@ static int qcom_qmp_phy_enable(struct phy *phy)
        void __iomem *tx = qphy->tx;
        void __iomem *rx = qphy->rx;
        void __iomem *pcs = qphy->pcs;
+       void __iomem *pcs_misc = qphy->pcs_misc;
        void __iomem *dp_com = qmp->dp_com;
        void __iomem *status;
        unsigned int mask, val, ready;
@@ -1633,6 +2040,9 @@ static int qcom_qmp_phy_enable(struct phy *phy)
        if (ret)
                goto err_lane_rst;
 
+       qcom_qmp_phy_configure(pcs_misc, cfg->regs, cfg->pcs_misc_tbl,
+                              cfg->pcs_misc_tbl_num);
+
        /*
         * Pull out PHY from POWER DOWN state.
         * This is active low enable signal to power-down PHY.
@@ -1967,7 +2377,7 @@ static const struct phy_ops qcom_qmp_phy_gen_ops = {
        .owner          = THIS_MODULE,
 };
 
-static const struct phy_ops qcom_qmp_ufs_ops = {
+static const struct phy_ops qcom_qmp_pcie_ufs_ops = {
        .power_on       = qcom_qmp_phy_enable,
        .power_off      = qcom_qmp_phy_disable,
        .set_mode       = qcom_qmp_phy_set_mode,
@@ -2067,8 +2477,8 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id)
                }
        }
 
-       if (qmp->cfg->type == PHY_TYPE_UFS)
-               ops = &qcom_qmp_ufs_ops;
+       if (qmp->cfg->type == PHY_TYPE_UFS || qmp->cfg->type == PHY_TYPE_PCIE)
+               ops = &qcom_qmp_pcie_ufs_ops;
 
        generic_phy = devm_phy_create(dev, np, ops);
        if (IS_ERR(generic_phy)) {
@@ -2091,6 +2501,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
                .compatible = "qcom,msm8996-qmp-pcie-phy",
                .data = &msm8996_pciephy_cfg,
        }, {
+               .compatible = "qcom,msm8996-qmp-ufs-phy",
+               .data = &msm8996_ufs_cfg,
+       }, {
                .compatible = "qcom,msm8996-qmp-usb3-phy",
                .data = &msm8996_usb3phy_cfg,
        }, {
@@ -2103,6 +2516,12 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
                .compatible = "qcom,ipq8074-qmp-pcie-phy",
                .data = &ipq8074_pciephy_cfg,
        }, {
+               .compatible = "qcom,sdm845-qhp-pcie-phy",
+               .data = &sdm845_qhp_pciephy_cfg,
+       }, {
+               .compatible = "qcom,sdm845-qmp-pcie-phy",
+               .data = &sdm845_qmp_pciephy_cfg,
+       }, {
                .compatible = "qcom,sdm845-qmp-usb3-phy",
                .data = &qmp_v3_usb3phy_cfg,
        }, {
index 90f793c..dece0e6 100644 (file)
 #define QPHY_V4_TX_MID_TERM_CTRL1                      0x1d8
 #define QPHY_V4_MULTI_LANE_CTRL1                       0x1e0
 
+/* PCIE GEN3 COM registers */
+#define PCIE_GEN3_QHP_COM_SSC_EN_CENTER                        0x14
+#define PCIE_GEN3_QHP_COM_SSC_PER1                     0x20
+#define PCIE_GEN3_QHP_COM_SSC_PER2                     0x24
+#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1               0x28
+#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2               0x2c
+#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE1_MODE1         0x34
+#define PCIE_GEN3_QHP_COM_SSC_STEP_SIZE2_MODE1         0x38
+#define PCIE_GEN3_QHP_COM_BIAS_EN_CKBUFLR_EN           0x54
+#define PCIE_GEN3_QHP_COM_CLK_ENABLE1                  0x58
+#define PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE0              0x6c
+#define PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE0              0x70
+#define PCIE_GEN3_QHP_COM_LOCK_CMP1_MODE1              0x78
+#define PCIE_GEN3_QHP_COM_LOCK_CMP2_MODE1              0x7c
+#define PCIE_GEN3_QHP_COM_BGV_TRIM                     0x98
+#define PCIE_GEN3_QHP_COM_CP_CTRL_MODE0                        0xb4
+#define PCIE_GEN3_QHP_COM_CP_CTRL_MODE1                        0xb8
+#define PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE0              0xc0
+#define PCIE_GEN3_QHP_COM_PLL_RCTRL_MODE1              0xc4
+#define PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE0              0xcc
+#define PCIE_GEN3_QHP_COM_PLL_CCTRL_MODE1              0xd0
+#define PCIE_GEN3_QHP_COM_SYSCLK_EN_SEL                        0xdc
+#define PCIE_GEN3_QHP_COM_RESTRIM_CTRL2                        0xf0
+#define PCIE_GEN3_QHP_COM_LOCK_CMP_EN                  0xf8
+#define PCIE_GEN3_QHP_COM_DEC_START_MODE0              0x100
+#define PCIE_GEN3_QHP_COM_DEC_START_MODE1              0x108
+#define PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE0                0x11c
+#define PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE0                0x120
+#define PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE0                0x124
+#define PCIE_GEN3_QHP_COM_DIV_FRAC_START1_MODE1                0x128
+#define PCIE_GEN3_QHP_COM_DIV_FRAC_START2_MODE1                0x12c
+#define PCIE_GEN3_QHP_COM_DIV_FRAC_START3_MODE1                0x130
+#define PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE0                0x150
+#define PCIE_GEN3_QHP_COM_INTEGLOOP_GAIN0_MODE1                0x158
+#define PCIE_GEN3_QHP_COM_VCO_TUNE_MAP                 0x178
+#define PCIE_GEN3_QHP_COM_BG_CTRL                      0x1c8
+#define PCIE_GEN3_QHP_COM_CLK_SELECT                   0x1cc
+#define PCIE_GEN3_QHP_COM_HSCLK_SEL1                   0x1d0
+#define PCIE_GEN3_QHP_COM_CORECLK_DIV                  0x1e0
+#define PCIE_GEN3_QHP_COM_CORE_CLK_EN                  0x1e8
+#define PCIE_GEN3_QHP_COM_CMN_CONFIG                   0x1f0
+#define PCIE_GEN3_QHP_COM_SVS_MODE_CLK_SEL             0x1fc
+#define PCIE_GEN3_QHP_COM_CORECLK_DIV_MODE1            0x21c
+#define PCIE_GEN3_QHP_COM_CMN_MODE                     0x224
+#define PCIE_GEN3_QHP_COM_VREGCLK_DIV1                 0x228
+#define PCIE_GEN3_QHP_COM_VREGCLK_DIV2                 0x22c
+
+/* PCIE GEN3 QHP Lane registers */
+#define PCIE_GEN3_QHP_L0_DRVR_CTRL0                    0xc
+#define PCIE_GEN3_QHP_L0_DRVR_CTRL1                    0x10
+#define PCIE_GEN3_QHP_L0_DRVR_CTRL2                    0x14
+#define PCIE_GEN3_QHP_L0_DRVR_TAP_EN                   0x18
+#define PCIE_GEN3_QHP_L0_TX_BAND_MODE                  0x60
+#define PCIE_GEN3_QHP_L0_LANE_MODE                     0x64
+#define PCIE_GEN3_QHP_L0_PARALLEL_RATE                 0x7c
+#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE0                        0xc0
+#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE1                        0xc4
+#define PCIE_GEN3_QHP_L0_CML_CTRL_MODE2                        0xc8
+#define PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE1             0xd0
+#define PCIE_GEN3_QHP_L0_PREAMP_CTRL_MODE2             0xd4
+#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE0              0xd8
+#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE1              0xdc
+#define PCIE_GEN3_QHP_L0_MIXER_CTRL_MODE2              0xe0
+#define PCIE_GEN3_QHP_L0_CTLE_THRESH_DFE               0xfc
+#define PCIE_GEN3_QHP_L0_CGA_THRESH_DFE                        0x100
+#define PCIE_GEN3_QHP_L0_RXENGINE_EN0                  0x108
+#define PCIE_GEN3_QHP_L0_CTLE_TRAIN_TIME               0x114
+#define PCIE_GEN3_QHP_L0_CTLE_DFE_OVRLP_TIME           0x118
+#define PCIE_GEN3_QHP_L0_DFE_REFRESH_TIME              0x11c
+#define PCIE_GEN3_QHP_L0_DFE_ENABLE_TIME               0x120
+#define PCIE_GEN3_QHP_L0_VGA_GAIN                      0x124
+#define PCIE_GEN3_QHP_L0_DFE_GAIN                      0x128
+#define PCIE_GEN3_QHP_L0_EQ_GAIN                       0x130
+#define PCIE_GEN3_QHP_L0_OFFSET_GAIN                   0x134
+#define PCIE_GEN3_QHP_L0_PRE_GAIN                      0x138
+#define PCIE_GEN3_QHP_L0_VGA_INITVAL                   0x13c
+#define PCIE_GEN3_QHP_L0_EQ_INTVAL                     0x154
+#define PCIE_GEN3_QHP_L0_EDAC_INITVAL                  0x160
+#define PCIE_GEN3_QHP_L0_RXEQ_INITB0                   0x168
+#define PCIE_GEN3_QHP_L0_RXEQ_INITB1                   0x16c
+#define PCIE_GEN3_QHP_L0_RCVRDONE_THRESH1              0x178
+#define PCIE_GEN3_QHP_L0_RXEQ_CTRL                     0x180
+#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE0            0x184
+#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE1            0x188
+#define PCIE_GEN3_QHP_L0_UCDR_FO_GAIN_MODE2            0x18c
+#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE0            0x190
+#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE1            0x194
+#define PCIE_GEN3_QHP_L0_UCDR_SO_GAIN_MODE2            0x198
+#define PCIE_GEN3_QHP_L0_UCDR_SO_CONFIG                        0x19c
+#define PCIE_GEN3_QHP_L0_RX_BAND                       0x1a4
+#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE0           0x1c0
+#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE1           0x1c4
+#define PCIE_GEN3_QHP_L0_RX_RCVR_PATH1_MODE2           0x1c8
+#define PCIE_GEN3_QHP_L0_SIGDET_ENABLES                        0x230
+#define PCIE_GEN3_QHP_L0_SIGDET_CNTRL                  0x234
+#define PCIE_GEN3_QHP_L0_SIGDET_DEGLITCH_CNTRL         0x238
+#define PCIE_GEN3_QHP_L0_DCC_GAIN                      0x2a4
+#define PCIE_GEN3_QHP_L0_RSM_START                     0x2a8
+#define PCIE_GEN3_QHP_L0_RX_EN_SIGNAL                  0x2ac
+#define PCIE_GEN3_QHP_L0_PSM_RX_EN_CAL                 0x2b0
+#define PCIE_GEN3_QHP_L0_RX_MISC_CNTRL0                        0x2b8
+#define PCIE_GEN3_QHP_L0_TS0_TIMER                     0x2c0
+#define PCIE_GEN3_QHP_L0_DLL_HIGHDATARATE              0x2c4
+#define PCIE_GEN3_QHP_L0_RX_RESETCODE_OFFSET           0x2cc
+
+/* PCIE GEN3 PCS registers */
+#define PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M3P5DB         0x2c
+#define PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M3P5DB         0x40
+#define PCIE_GEN3_QHP_PHY_TXMGN_MAIN_V0_M6DB           0x54
+#define PCIE_GEN3_QHP_PHY_TXMGN_POST_V0_M6DB           0x68
+#define PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG           0x15c
+#define PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG5          0x16c
+#define PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG             0x174
+
 #endif
index bf94a52..3708d43 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/clk.h>
 #define IMP_RES_OFFSET_MASK                    GENMASK(5, 0)
 #define IMP_RES_OFFSET_SHIFT                   0x0
 
+/* QUSB2PHY_PLL_BIAS_CONTROL_2 register bits */
+#define BIAS_CTRL2_RES_OFFSET_MASK             GENMASK(5, 0)
+#define BIAS_CTRL2_RES_OFFSET_SHIFT            0x0
+
+/* QUSB2PHY_CHG_CONTROL_2 register bits */
+#define CHG_CTRL2_OFFSET_MASK                  GENMASK(5, 4)
+#define CHG_CTRL2_OFFSET_SHIFT                 0x4
+
 /* QUSB2PHY_PORT_TUNE1 register bits */
 #define HSTX_TRIM_MASK                         GENMASK(7, 4)
 #define HSTX_TRIM_SHIFT                                0x4
 #define PREEMPHASIS_EN_MASK                    GENMASK(1, 0)
 #define PREEMPHASIS_EN_SHIFT                   0x0
 
+/* QUSB2PHY_PORT_TUNE2 register bits */
+#define HSDISC_TRIM_MASK                       GENMASK(1, 0)
+#define HSDISC_TRIM_SHIFT                      0x0
+
 #define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO       0x04
 #define QUSB2PHY_PLL_CLOCK_INVERTERS           0x18c
 #define QUSB2PHY_PLL_CMODE                     0x2c
@@ -177,7 +189,7 @@ static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = {
        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
 };
 
-static const unsigned int sdm845_regs_layout[] = {
+static const unsigned int qusb2_v2_regs_layout[] = {
        [QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
        [QUSB2PHY_PLL_STATUS]           = 0x1a0,
        [QUSB2PHY_PORT_TUNE1]           = 0x240,
@@ -191,7 +203,7 @@ static const unsigned int sdm845_regs_layout[] = {
        [QUSB2PHY_INTR_CTRL]            = 0x230,
 };
 
-static const struct qusb2_phy_init_tbl sdm845_init_tbl[] = {
+static const struct qusb2_phy_init_tbl qusb2_v2_init_tbl[] = {
        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x03),
        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
        QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
@@ -258,10 +270,10 @@ static const struct qusb2_phy_cfg msm8998_phy_cfg = {
        .update_tune1_with_efuse = true,
 };
 
-static const struct qusb2_phy_cfg sdm845_phy_cfg = {
-       .tbl            = sdm845_init_tbl,
-       .tbl_num        = ARRAY_SIZE(sdm845_init_tbl),
-       .regs           = sdm845_regs_layout,
+static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
+       .tbl            = qusb2_v2_init_tbl,
+       .tbl_num        = ARRAY_SIZE(qusb2_v2_init_tbl),
+       .regs           = qusb2_v2_regs_layout,
 
        .disable_ctrl   = (PWR_CTRL1_VREF_SUPPLY_TRIM | PWR_CTRL1_CLAMP_N_EN |
                           POWER_DOWN),
@@ -277,6 +289,34 @@ static const char * const qusb2_phy_vreg_names[] = {
 
 #define QUSB2_NUM_VREGS                ARRAY_SIZE(qusb2_phy_vreg_names)
 
+/* struct override_param - structure holding qusb2 v2 phy overriding param
+ * set override true if the  device tree property exists and read and assign
+ * to value
+ */
+struct override_param {
+       bool override;
+       u8 value;
+};
+
+/*struct override_params - structure holding qusb2 v2 phy overriding params
+ * @imp_res_offset: rescode offset to be updated in IMP_CTRL1 register
+ * @hstx_trim: HSTX_TRIM to be updated in TUNE1 register
+ * @preemphasis: Amplitude Pre-Emphasis to be updated in TUNE1 register
+ * @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1
+ * @bias_ctrl: bias ctrl to be updated in BIAS_CONTROL_2 register
+ * @charge_ctrl: charge ctrl to be updated in CHG_CTRL2 register
+ * @hsdisc_trim: disconnect threshold to be updated in TUNE2 register
+ */
+struct override_params {
+       struct override_param imp_res_offset;
+       struct override_param hstx_trim;
+       struct override_param preemphasis;
+       struct override_param preemphasis_width;
+       struct override_param bias_ctrl;
+       struct override_param charge_ctrl;
+       struct override_param hsdisc_trim;
+};
+
 /**
  * struct qusb2_phy - structure holding qusb2 phy attributes
  *
@@ -292,14 +332,7 @@ static const char * const qusb2_phy_vreg_names[] = {
  * @tcsr: TCSR syscon register map
  * @cell: nvmem cell containing phy tuning value
  *
- * @override_imp_res_offset: PHY should use different rescode offset
- * @imp_res_offset_value: rescode offset to be updated in IMP_CTRL1 register
- * @override_hstx_trim: PHY should use different HSTX o/p current value
- * @hstx_trim_value: HSTX_TRIM value to be updated in TUNE1 register
- * @override_preemphasis: PHY should use different pre-amphasis amplitude
- * @preemphasis_level: Amplitude Pre-Emphasis to be updated in TUNE1 register
- * @override_preemphasis_width: PHY should use different pre-emphasis duration
- * @preemphasis_width: half/full-width Pre-Emphasis updated via TUNE1
+ * @overrides: pointer to structure for all overriding tuning params
  *
  * @cfg: phy config data
  * @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
@@ -319,14 +352,7 @@ struct qusb2_phy {
        struct regmap *tcsr;
        struct nvmem_cell *cell;
 
-       bool override_imp_res_offset;
-       u8 imp_res_offset_value;
-       bool override_hstx_trim;
-       u8 hstx_trim_value;
-       bool override_preemphasis;
-       u8 preemphasis_level;
-       bool override_preemphasis_width;
-       u8 preemphasis_width;
+       struct override_params overrides;
 
        const struct qusb2_phy_cfg *cfg;
        bool has_se_clk_scheme;
@@ -394,24 +420,35 @@ void qcom_qusb2_phy_configure(void __iomem *base,
 static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy)
 {
        const struct qusb2_phy_cfg *cfg = qphy->cfg;
+       struct override_params *or = &qphy->overrides;
 
-       if (qphy->override_imp_res_offset)
+       if (or->imp_res_offset.override)
                qusb2_write_mask(qphy->base, QUSB2PHY_IMP_CTRL1,
-                            qphy->imp_res_offset_value << IMP_RES_OFFSET_SHIFT,
+               or->imp_res_offset.value << IMP_RES_OFFSET_SHIFT,
                             IMP_RES_OFFSET_MASK);
 
-       if (qphy->override_hstx_trim)
+       if (or->bias_ctrl.override)
+               qusb2_write_mask(qphy->base, QUSB2PHY_PLL_BIAS_CONTROL_2,
+               or->bias_ctrl.value << BIAS_CTRL2_RES_OFFSET_SHIFT,
+                          BIAS_CTRL2_RES_OFFSET_MASK);
+
+       if (or->charge_ctrl.override)
+               qusb2_write_mask(qphy->base, QUSB2PHY_CHG_CTRL2,
+               or->charge_ctrl.value << CHG_CTRL2_OFFSET_SHIFT,
+                            CHG_CTRL2_OFFSET_MASK);
+
+       if (or->hstx_trim.override)
                qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
-                                qphy->hstx_trim_value << HSTX_TRIM_SHIFT,
+               or->hstx_trim.value << HSTX_TRIM_SHIFT,
                                 HSTX_TRIM_MASK);
 
-       if (qphy->override_preemphasis)
+       if (or->preemphasis.override)
                qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE1],
-                               qphy->preemphasis_level << PREEMPHASIS_EN_SHIFT,
+               or->preemphasis.value << PREEMPHASIS_EN_SHIFT,
                                PREEMPHASIS_EN_MASK);
 
-       if (qphy->override_preemphasis_width) {
-               if (qphy->preemphasis_width ==
+       if (or->preemphasis_width.override) {
+               if (or->preemphasis_width.value ==
                    QUSB2_V2_PREEMPHASIS_WIDTH_HALF_BIT)
                        qusb2_setbits(qphy->base,
                                      cfg->regs[QUSB2PHY_PORT_TUNE1],
@@ -421,6 +458,11 @@ static void qusb2_phy_override_phy_params(struct qusb2_phy *qphy)
                                      cfg->regs[QUSB2PHY_PORT_TUNE1],
                                      PREEMPH_WIDTH_HALF_BIT);
        }
+
+       if (or->hsdisc_trim.override)
+               qusb2_write_mask(qphy->base, cfg->regs[QUSB2PHY_PORT_TUNE2],
+               or->hsdisc_trim.value << HSDISC_TRIM_SHIFT,
+                                HSDISC_TRIM_MASK);
 }
 
 /*
@@ -774,8 +816,8 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
                .compatible     = "qcom,msm8998-qusb2-phy",
                .data           = &msm8998_phy_cfg,
        }, {
-               .compatible     = "qcom,sdm845-qusb2-phy",
-               .data           = &sdm845_phy_cfg,
+               .compatible     = "qcom,qusb2-v2-phy",
+               .data           = &qusb2_v2_phy_cfg,
        },
        { },
 };
@@ -796,10 +838,12 @@ static int qusb2_phy_probe(struct platform_device *pdev)
        int ret, i;
        int num;
        u32 value;
+       struct override_params *or;
 
        qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
        if (!qphy)
                return -ENOMEM;
+       or = &qphy->overrides;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        qphy->base = devm_ioremap_resource(dev, res);
@@ -864,26 +908,44 @@ static int qusb2_phy_probe(struct platform_device *pdev)
 
        if (!of_property_read_u32(dev->of_node, "qcom,imp-res-offset-value",
                                  &value)) {
-               qphy->imp_res_offset_value = (u8)value;
-               qphy->override_imp_res_offset = true;
+               or->imp_res_offset.value = (u8)value;
+               or->imp_res_offset.override = true;
+       }
+
+       if (!of_property_read_u32(dev->of_node, "qcom,bias-ctrl-value",
+                                 &value)) {
+               or->bias_ctrl.value = (u8)value;
+               or->bias_ctrl.override = true;
+       }
+
+       if (!of_property_read_u32(dev->of_node, "qcom,charge-ctrl-value",
+                                 &value)) {
+               or->charge_ctrl.value = (u8)value;
+               or->charge_ctrl.override = true;
        }
 
        if (!of_property_read_u32(dev->of_node, "qcom,hstx-trim-value",
                                  &value)) {
-               qphy->hstx_trim_value = (u8)value;
-               qphy->override_hstx_trim = true;
+               or->hstx_trim.value = (u8)value;
+               or->hstx_trim.override = true;
        }
 
        if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-level",
                                     &value)) {
-               qphy->preemphasis_level = (u8)value;
-               qphy->override_preemphasis = true;
+               or->preemphasis.value = (u8)value;
+               or->preemphasis.override = true;
        }
 
        if (!of_property_read_u32(dev->of_node, "qcom,preemphasis-width",
                                     &value)) {
-               qphy->preemphasis_width = (u8)value;
-               qphy->override_preemphasis_width = true;
+               or->preemphasis_width.value = (u8)value;
+               or->preemphasis_width.override = true;
+       }
+
+       if (!of_property_read_u32(dev->of_node, "qcom,hsdisc-trim-value",
+                                 &value)) {
+               or->hsdisc_trim.value = (u8)value;
+               or->hsdisc_trim.override = true;
        }
 
        pm_runtime_set_active(dev);
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c b/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c
new file mode 100644 (file)
index 0000000..d998e65
--- /dev/null
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2009-2018, Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, Linaro Limited
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+/* PHY register and bit definitions */
+#define PHY_CTRL_COMMON0               0x078
+#define SIDDQ                          BIT(2)
+#define PHY_IRQ_CMD                    0x0d0
+#define PHY_INTR_MASK0                 0x0d4
+#define PHY_INTR_CLEAR0                        0x0dc
+#define DPDM_MASK                      0x1e
+#define DP_1_0                         BIT(4)
+#define DP_0_1                         BIT(3)
+#define DM_1_0                         BIT(2)
+#define DM_0_1                         BIT(1)
+
+enum hsphy_voltage {
+       VOL_NONE,
+       VOL_MIN,
+       VOL_MAX,
+       VOL_NUM,
+};
+
+enum hsphy_vreg {
+       VDD,
+       VDDA_1P8,
+       VDDA_3P3,
+       VREG_NUM,
+};
+
+struct hsphy_init_seq {
+       int offset;
+       int val;
+       int delay;
+};
+
+struct hsphy_data {
+       const struct hsphy_init_seq *init_seq;
+       unsigned int init_seq_num;
+};
+
+struct hsphy_priv {
+       void __iomem *base;
+       struct clk_bulk_data *clks;
+       int num_clks;
+       struct reset_control *phy_reset;
+       struct reset_control *por_reset;
+       struct regulator_bulk_data vregs[VREG_NUM];
+       const struct hsphy_data *data;
+       enum phy_mode mode;
+};
+
+static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
+                                   int submode)
+{
+       struct hsphy_priv *priv = phy_get_drvdata(phy);
+
+       priv->mode = PHY_MODE_INVALID;
+
+       if (mode > 0)
+               priv->mode = mode;
+
+       return 0;
+}
+
+static void qcom_snps_hsphy_enable_hv_interrupts(struct hsphy_priv *priv)
+{
+       u32 val;
+
+       /* Clear any existing interrupts before enabling the interrupts */
+       val = readb(priv->base + PHY_INTR_CLEAR0);
+       val |= DPDM_MASK;
+       writeb(val, priv->base + PHY_INTR_CLEAR0);
+
+       writeb(0x0, priv->base + PHY_IRQ_CMD);
+       usleep_range(200, 220);
+       writeb(0x1, priv->base + PHY_IRQ_CMD);
+
+       /* Make sure the interrupts are cleared */
+       usleep_range(200, 220);
+
+       val = readb(priv->base + PHY_INTR_MASK0);
+       switch (priv->mode) {
+       case PHY_MODE_USB_HOST_HS:
+       case PHY_MODE_USB_HOST_FS:
+       case PHY_MODE_USB_DEVICE_HS:
+       case PHY_MODE_USB_DEVICE_FS:
+               val |= DP_1_0 | DM_0_1;
+               break;
+       case PHY_MODE_USB_HOST_LS:
+       case PHY_MODE_USB_DEVICE_LS:
+               val |= DP_0_1 | DM_1_0;
+               break;
+       default:
+               /* No device connected */
+               val |= DP_0_1 | DM_0_1;
+               break;
+       }
+       writeb(val, priv->base + PHY_INTR_MASK0);
+}
+
+static void qcom_snps_hsphy_disable_hv_interrupts(struct hsphy_priv *priv)
+{
+       u32 val;
+
+       val = readb(priv->base + PHY_INTR_MASK0);
+       val &= ~DPDM_MASK;
+       writeb(val, priv->base + PHY_INTR_MASK0);
+
+       /* Clear any pending interrupts */
+       val = readb(priv->base + PHY_INTR_CLEAR0);
+       val |= DPDM_MASK;
+       writeb(val, priv->base + PHY_INTR_CLEAR0);
+
+       writeb(0x0, priv->base + PHY_IRQ_CMD);
+       usleep_range(200, 220);
+
+       writeb(0x1, priv->base + PHY_IRQ_CMD);
+       usleep_range(200, 220);
+}
+
+static void qcom_snps_hsphy_enter_retention(struct hsphy_priv *priv)
+{
+       u32 val;
+
+       val = readb(priv->base + PHY_CTRL_COMMON0);
+       val |= SIDDQ;
+       writeb(val, priv->base + PHY_CTRL_COMMON0);
+}
+
+static void qcom_snps_hsphy_exit_retention(struct hsphy_priv *priv)
+{
+       u32 val;
+
+       val = readb(priv->base + PHY_CTRL_COMMON0);
+       val &= ~SIDDQ;
+       writeb(val, priv->base + PHY_CTRL_COMMON0);
+}
+
+static int qcom_snps_hsphy_power_on(struct phy *phy)
+{
+       struct hsphy_priv *priv = phy_get_drvdata(phy);
+       int ret;
+
+       ret = regulator_bulk_enable(VREG_NUM, priv->vregs);
+       if (ret)
+               return ret;
+       ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks);
+       if (ret)
+               goto err_disable_regulator;
+       qcom_snps_hsphy_disable_hv_interrupts(priv);
+       qcom_snps_hsphy_exit_retention(priv);
+
+       return 0;
+
+err_disable_regulator:
+       regulator_bulk_disable(VREG_NUM, priv->vregs);
+
+       return ret;
+}
+
+static int qcom_snps_hsphy_power_off(struct phy *phy)
+{
+       struct hsphy_priv *priv = phy_get_drvdata(phy);
+
+       qcom_snps_hsphy_enter_retention(priv);
+       qcom_snps_hsphy_enable_hv_interrupts(priv);
+       clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
+       regulator_bulk_disable(VREG_NUM, priv->vregs);
+
+       return 0;
+}
+
+static int qcom_snps_hsphy_reset(struct hsphy_priv *priv)
+{
+       int ret;
+
+       ret = reset_control_assert(priv->phy_reset);
+       if (ret)
+               return ret;
+
+       usleep_range(10, 15);
+
+       ret = reset_control_deassert(priv->phy_reset);
+       if (ret)
+               return ret;
+
+       usleep_range(80, 100);
+
+       return 0;
+}
+
+static void qcom_snps_hsphy_init_sequence(struct hsphy_priv *priv)
+{
+       const struct hsphy_data *data = priv->data;
+       const struct hsphy_init_seq *seq;
+       int i;
+
+       /* Device match data is optional. */
+       if (!data)
+               return;
+
+       seq = data->init_seq;
+
+       for (i = 0; i < data->init_seq_num; i++, seq++) {
+               writeb(seq->val, priv->base + seq->offset);
+               if (seq->delay)
+                       usleep_range(seq->delay, seq->delay + 10);
+       }
+}
+
+static int qcom_snps_hsphy_por_reset(struct hsphy_priv *priv)
+{
+       int ret;
+
+       ret = reset_control_assert(priv->por_reset);
+       if (ret)
+               return ret;
+
+       /*
+        * The Femto PHY is POR reset in the following scenarios.
+        *
+        * 1. After overriding the parameter registers.
+        * 2. Low power mode exit from PHY retention.
+        *
+        * Ensure that SIDDQ is cleared before bringing the PHY
+        * out of reset.
+        */
+       qcom_snps_hsphy_exit_retention(priv);
+
+       /*
+        * As per databook, 10 usec delay is required between
+        * PHY POR assert and de-assert.
+        */
+       usleep_range(10, 20);
+       ret = reset_control_deassert(priv->por_reset);
+       if (ret)
+               return ret;
+
+       /*
+        * As per databook, it takes 75 usec for PHY to stabilize
+        * after the reset.
+        */
+       usleep_range(80, 100);
+
+       return 0;
+}
+
+static int qcom_snps_hsphy_init(struct phy *phy)
+{
+       struct hsphy_priv *priv = phy_get_drvdata(phy);
+       int ret;
+
+       ret = qcom_snps_hsphy_reset(priv);
+       if (ret)
+               return ret;
+
+       qcom_snps_hsphy_init_sequence(priv);
+
+       ret = qcom_snps_hsphy_por_reset(priv);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static const struct phy_ops qcom_snps_hsphy_ops = {
+       .init = qcom_snps_hsphy_init,
+       .power_on = qcom_snps_hsphy_power_on,
+       .power_off = qcom_snps_hsphy_power_off,
+       .set_mode = qcom_snps_hsphy_set_mode,
+       .owner = THIS_MODULE,
+};
+
+static const char * const qcom_snps_hsphy_clks[] = {
+       "ref",
+       "ahb",
+       "sleep",
+};
+
+static int qcom_snps_hsphy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct phy_provider *provider;
+       struct hsphy_priv *priv;
+       struct phy *phy;
+       int ret;
+       int i;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       priv->num_clks = ARRAY_SIZE(qcom_snps_hsphy_clks);
+       priv->clks = devm_kcalloc(dev, priv->num_clks, sizeof(*priv->clks),
+                                 GFP_KERNEL);
+       if (!priv->clks)
+               return -ENOMEM;
+
+       for (i = 0; i < priv->num_clks; i++)
+               priv->clks[i].id = qcom_snps_hsphy_clks[i];
+
+       ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks);
+       if (ret)
+               return ret;
+
+       priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
+       if (IS_ERR(priv->phy_reset))
+               return PTR_ERR(priv->phy_reset);
+
+       priv->por_reset = devm_reset_control_get_exclusive(dev, "por");
+       if (IS_ERR(priv->por_reset))
+               return PTR_ERR(priv->por_reset);
+
+       priv->vregs[VDD].supply = "vdd";
+       priv->vregs[VDDA_1P8].supply = "vdda1p8";
+       priv->vregs[VDDA_3P3].supply = "vdda3p3";
+
+       ret = devm_regulator_bulk_get(dev, VREG_NUM, priv->vregs);
+       if (ret)
+               return ret;
+
+       /* Get device match data */
+       priv->data = device_get_match_data(dev);
+
+       phy = devm_phy_create(dev, dev->of_node, &qcom_snps_hsphy_ops);
+       if (IS_ERR(phy))
+               return PTR_ERR(phy);
+
+       phy_set_drvdata(phy, priv);
+
+       provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(provider))
+               return PTR_ERR(provider);
+
+       ret = regulator_set_load(priv->vregs[VDDA_1P8].consumer, 19000);
+       if (ret < 0)
+               return ret;
+
+       ret = regulator_set_load(priv->vregs[VDDA_3P3].consumer, 16000);
+       if (ret < 0)
+               goto unset_1p8_load;
+
+       return 0;
+
+unset_1p8_load:
+       regulator_set_load(priv->vregs[VDDA_1P8].consumer, 0);
+
+       return ret;
+}
+
+/*
+ * The macro is used to define an initialization sequence.  Each tuple
+ * is meant to program 'value' into phy register at 'offset' with 'delay'
+ * in us followed.
+ */
+#define HSPHY_INIT_CFG(o, v, d)        { .offset = o, .val = v, .delay = d, }
+
+static const struct hsphy_init_seq init_seq_femtophy[] = {
+       HSPHY_INIT_CFG(0xc0, 0x01, 0),
+       HSPHY_INIT_CFG(0xe8, 0x0d, 0),
+       HSPHY_INIT_CFG(0x74, 0x12, 0),
+       HSPHY_INIT_CFG(0x98, 0x63, 0),
+       HSPHY_INIT_CFG(0x9c, 0x03, 0),
+       HSPHY_INIT_CFG(0xa0, 0x1d, 0),
+       HSPHY_INIT_CFG(0xa4, 0x03, 0),
+       HSPHY_INIT_CFG(0x8c, 0x23, 0),
+       HSPHY_INIT_CFG(0x78, 0x08, 0),
+       HSPHY_INIT_CFG(0x7c, 0xdc, 0),
+       HSPHY_INIT_CFG(0x90, 0xe0, 20),
+       HSPHY_INIT_CFG(0x74, 0x10, 0),
+       HSPHY_INIT_CFG(0x90, 0x60, 0),
+};
+
+static const struct hsphy_data hsphy_data_femtophy = {
+       .init_seq = init_seq_femtophy,
+       .init_seq_num = ARRAY_SIZE(init_seq_femtophy),
+};
+
+static const struct of_device_id qcom_snps_hsphy_match[] = {
+       { .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, },
+       { },
+};
+MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match);
+
+static struct platform_driver qcom_snps_hsphy_driver = {
+       .probe = qcom_snps_hsphy_probe,
+       .driver = {
+               .name = "qcom,usb-hs-28nm-phy",
+               .of_match_table = qcom_snps_hsphy_match,
+       },
+};
+module_platform_driver(qcom_snps_hsphy_driver);
+
+MODULE_DESCRIPTION("Qualcomm 28nm Hi-Speed USB PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/qualcomm/phy-qcom-usb-ss.c b/drivers/phy/qualcomm/phy-qcom-usb-ss.c
new file mode 100644 (file)
index 0000000..a3a6d3c
--- /dev/null
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2012-2014,2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, Linaro Limited
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+
+#define PHY_CTRL0                      0x6C
+#define PHY_CTRL1                      0x70
+#define PHY_CTRL2                      0x74
+#define PHY_CTRL4                      0x7C
+
+/* PHY_CTRL bits */
+#define REF_PHY_EN                     BIT(0)
+#define LANE0_PWR_ON                   BIT(2)
+#define SWI_PCS_CLK_SEL                        BIT(4)
+#define TST_PWR_DOWN                   BIT(4)
+#define PHY_RESET                      BIT(7)
+
+#define NUM_BULK_CLKS                  3
+#define NUM_BULK_REGS                  2
+
+struct ssphy_priv {
+       void __iomem *base;
+       struct device *dev;
+       struct reset_control *reset_com;
+       struct reset_control *reset_phy;
+       struct regulator_bulk_data regs[NUM_BULK_REGS];
+       struct clk_bulk_data clks[NUM_BULK_CLKS];
+       enum phy_mode mode;
+};
+
+static inline void qcom_ssphy_updatel(void __iomem *addr, u32 mask, u32 val)
+{
+       writel((readl(addr) & ~mask) | val, addr);
+}
+
+static int qcom_ssphy_do_reset(struct ssphy_priv *priv)
+{
+       int ret;
+
+       if (!priv->reset_com) {
+               qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET,
+                                  PHY_RESET);
+               usleep_range(10, 20);
+               qcom_ssphy_updatel(priv->base + PHY_CTRL1, PHY_RESET, 0);
+       } else {
+               ret = reset_control_assert(priv->reset_com);
+               if (ret) {
+                       dev_err(priv->dev, "Failed to assert reset com\n");
+                       return ret;
+               }
+
+               ret = reset_control_assert(priv->reset_phy);
+               if (ret) {
+                       dev_err(priv->dev, "Failed to assert reset phy\n");
+                       return ret;
+               }
+
+               usleep_range(10, 20);
+
+               ret = reset_control_deassert(priv->reset_com);
+               if (ret) {
+                       dev_err(priv->dev, "Failed to deassert reset com\n");
+                       return ret;
+               }
+
+               ret = reset_control_deassert(priv->reset_phy);
+               if (ret) {
+                       dev_err(priv->dev, "Failed to deassert reset phy\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int qcom_ssphy_power_on(struct phy *phy)
+{
+       struct ssphy_priv *priv = phy_get_drvdata(phy);
+       int ret;
+
+       ret = regulator_bulk_enable(NUM_BULK_REGS, priv->regs);
+       if (ret)
+               return ret;
+
+       ret = clk_bulk_prepare_enable(NUM_BULK_CLKS, priv->clks);
+       if (ret)
+               goto err_disable_regulator;
+
+       ret = qcom_ssphy_do_reset(priv);
+       if (ret)
+               goto err_disable_clock;
+
+       writeb(SWI_PCS_CLK_SEL, priv->base + PHY_CTRL0);
+       qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, LANE0_PWR_ON);
+       qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, REF_PHY_EN);
+       qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, 0);
+
+       return 0;
+err_disable_clock:
+       clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks);
+err_disable_regulator:
+       regulator_bulk_disable(NUM_BULK_REGS, priv->regs);
+
+       return ret;
+}
+
+static int qcom_ssphy_power_off(struct phy *phy)
+{
+       struct ssphy_priv *priv = phy_get_drvdata(phy);
+
+       qcom_ssphy_updatel(priv->base + PHY_CTRL4, LANE0_PWR_ON, 0);
+       qcom_ssphy_updatel(priv->base + PHY_CTRL2, REF_PHY_EN, 0);
+       qcom_ssphy_updatel(priv->base + PHY_CTRL4, TST_PWR_DOWN, TST_PWR_DOWN);
+
+       clk_bulk_disable_unprepare(NUM_BULK_CLKS, priv->clks);
+       regulator_bulk_disable(NUM_BULK_REGS, priv->regs);
+
+       return 0;
+}
+
+static int qcom_ssphy_init_clock(struct ssphy_priv *priv)
+{
+       priv->clks[0].id = "ref";
+       priv->clks[1].id = "ahb";
+       priv->clks[2].id = "pipe";
+
+       return devm_clk_bulk_get(priv->dev, NUM_BULK_CLKS, priv->clks);
+}
+
+static int qcom_ssphy_init_regulator(struct ssphy_priv *priv)
+{
+       int ret;
+
+       priv->regs[0].supply = "vdd";
+       priv->regs[1].supply = "vdda1p8";
+       ret = devm_regulator_bulk_get(priv->dev, NUM_BULK_REGS, priv->regs);
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
+                       dev_err(priv->dev, "Failed to get regulators\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int qcom_ssphy_init_reset(struct ssphy_priv *priv)
+{
+       priv->reset_com = devm_reset_control_get_optional_exclusive(priv->dev, "com");
+       if (IS_ERR(priv->reset_com)) {
+               dev_err(priv->dev, "Failed to get reset control com\n");
+               return PTR_ERR(priv->reset_com);
+       }
+
+       if (priv->reset_com) {
+               /* if reset_com is present, reset_phy is no longer optional */
+               priv->reset_phy = devm_reset_control_get_exclusive(priv->dev, "phy");
+               if (IS_ERR(priv->reset_phy)) {
+                       dev_err(priv->dev, "Failed to get reset control phy\n");
+                       return PTR_ERR(priv->reset_phy);
+               }
+       }
+
+       return 0;
+}
+
+static const struct phy_ops qcom_ssphy_ops = {
+       .power_off = qcom_ssphy_power_off,
+       .power_on = qcom_ssphy_power_on,
+       .owner = THIS_MODULE,
+};
+
+static int qcom_ssphy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct phy_provider *provider;
+       struct ssphy_priv *priv;
+       struct phy *phy;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(struct ssphy_priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = dev;
+       priv->mode = PHY_MODE_INVALID;
+
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       ret = qcom_ssphy_init_clock(priv);
+       if (ret)
+               return ret;
+
+       ret = qcom_ssphy_init_reset(priv);
+       if (ret)
+               return ret;
+
+       ret = qcom_ssphy_init_regulator(priv);
+       if (ret)
+               return ret;
+
+       phy = devm_phy_create(dev, dev->of_node, &qcom_ssphy_ops);
+       if (IS_ERR(phy)) {
+               dev_err(dev, "Failed to create the SS phy\n");
+               return PTR_ERR(phy);
+       }
+
+       phy_set_drvdata(phy, priv);
+
+       provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+       return PTR_ERR_OR_ZERO(provider);
+}
+
+static const struct of_device_id qcom_ssphy_match[] = {
+       { .compatible = "qcom,usb-ss-28nm-phy", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, qcom_ssphy_match);
+
+static struct platform_driver qcom_ssphy_driver = {
+       .probe          = qcom_ssphy_probe,
+       .driver = {
+               .name   = "qcom-usb-ssphy",
+               .of_match_table = qcom_ssphy_match,
+       },
+};
+module_platform_driver(qcom_ssphy_driver);
+
+MODULE_DESCRIPTION("Qualcomm SuperSpeed USB PHY driver");
+MODULE_LICENSE("GPL v2");
index 680cc0c..a84e9f0 100644 (file)
@@ -763,7 +763,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)
                /* put the controller in normal mode */
                property_enable(base, &rphy->phy_cfg->chg_det.opmode, true);
                rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);
-               dev_info(&rport->phy->dev, "charger = %s\n",
+               dev_dbg(&rport->phy->dev, "charger = %s\n",
                         chg_to_string(rphy->chg_type));
                return;
        default:
index 93ffbd2..e4adab3 100644 (file)
 #include <linux/resource.h>
 
 /* PHY */
+#define PCL_PHY_CLKCTRL                0x0000
+#define PORT_SEL_MASK          GENMASK(11, 9)
+#define PORT_SEL_1             FIELD_PREP(PORT_SEL_MASK, 1)
+
 #define PCL_PHY_TEST_I         0x2000
 #define PCL_PHY_TEST_O         0x2004
 #define TESTI_DAT_MASK         GENMASK(13, 6)
 struct uniphier_pciephy_priv {
        void __iomem *base;
        struct device *dev;
-       struct clk *clk;
-       struct reset_control *rst;
+       struct clk *clk, *clk_gio;
+       struct reset_control *rst, *rst_gio;
        const struct uniphier_pciephy_soc_data *data;
 };
 
 struct uniphier_pciephy_soc_data {
-       bool has_syscon;
+       bool is_legacy;
+       void (*set_phymode)(struct regmap *regmap);
 };
 
 static void uniphier_pciephy_testio_write(struct uniphier_pciephy_priv *priv,
@@ -111,16 +116,35 @@ static void uniphier_pciephy_deassert(struct uniphier_pciephy_priv *priv)
 static int uniphier_pciephy_init(struct phy *phy)
 {
        struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
+       u32 val;
        int ret;
 
        ret = clk_prepare_enable(priv->clk);
        if (ret)
                return ret;
 
-       ret = reset_control_deassert(priv->rst);
+       ret = clk_prepare_enable(priv->clk_gio);
        if (ret)
                goto out_clk_disable;
 
+       ret = reset_control_deassert(priv->rst);
+       if (ret)
+               goto out_clk_gio_disable;
+
+       ret = reset_control_deassert(priv->rst_gio);
+       if (ret)
+               goto out_rst_assert;
+
+       /* support only 1 port */
+       val = readl(priv->base + PCL_PHY_CLKCTRL);
+       val &= ~PORT_SEL_MASK;
+       val |= PORT_SEL_1;
+       writel(val, priv->base + PCL_PHY_CLKCTRL);
+
+       /* legacy controller doesn't have phy_reset and parameters */
+       if (priv->data->is_legacy)
+               return 0;
+
        uniphier_pciephy_set_param(priv, PCL_PHY_R00,
                                   RX_EQ_ADJ_EN, RX_EQ_ADJ_EN);
        uniphier_pciephy_set_param(priv, PCL_PHY_R06, RX_EQ_ADJ,
@@ -134,6 +158,10 @@ static int uniphier_pciephy_init(struct phy *phy)
 
        return 0;
 
+out_rst_assert:
+       reset_control_assert(priv->rst);
+out_clk_gio_disable:
+       clk_disable_unprepare(priv->clk_gio);
 out_clk_disable:
        clk_disable_unprepare(priv->clk);
 
@@ -144,8 +172,11 @@ static int uniphier_pciephy_exit(struct phy *phy)
 {
        struct uniphier_pciephy_priv *priv = phy_get_drvdata(phy);
 
-       uniphier_pciephy_assert(priv);
+       if (!priv->data->is_legacy)
+               uniphier_pciephy_assert(priv);
+       reset_control_assert(priv->rst_gio);
        reset_control_assert(priv->rst);
+       clk_disable_unprepare(priv->clk_gio);
        clk_disable_unprepare(priv->clk);
 
        return 0;
@@ -163,7 +194,6 @@ static int uniphier_pciephy_probe(struct platform_device *pdev)
        struct phy_provider *phy_provider;
        struct device *dev = &pdev->dev;
        struct regmap *regmap;
-       struct resource *res;
        struct phy *phy;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -176,18 +206,36 @@ static int uniphier_pciephy_probe(struct platform_device *pdev)
 
        priv->dev = dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(dev, res);
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
-       priv->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(priv->clk))
-               return PTR_ERR(priv->clk);
-
-       priv->rst = devm_reset_control_get_shared(dev, NULL);
-       if (IS_ERR(priv->rst))
-               return PTR_ERR(priv->rst);
+       if (priv->data->is_legacy) {
+               priv->clk_gio = devm_clk_get(dev, "gio");
+               if (IS_ERR(priv->clk_gio))
+                       return PTR_ERR(priv->clk_gio);
+
+               priv->rst_gio =
+                       devm_reset_control_get_shared(dev, "gio");
+               if (IS_ERR(priv->rst_gio))
+                       return PTR_ERR(priv->rst_gio);
+
+               priv->clk = devm_clk_get(dev, "link");
+               if (IS_ERR(priv->clk))
+                       return PTR_ERR(priv->clk);
+
+               priv->rst = devm_reset_control_get_shared(dev, "link");
+               if (IS_ERR(priv->rst))
+                       return PTR_ERR(priv->rst);
+       } else {
+               priv->clk = devm_clk_get(dev, NULL);
+               if (IS_ERR(priv->clk))
+                       return PTR_ERR(priv->clk);
+
+               priv->rst = devm_reset_control_get_shared(dev, NULL);
+               if (IS_ERR(priv->rst))
+                       return PTR_ERR(priv->rst);
+       }
 
        phy = devm_phy_create(dev, dev->of_node, &uniphier_pciephy_ops);
        if (IS_ERR(phy))
@@ -195,9 +243,8 @@ static int uniphier_pciephy_probe(struct platform_device *pdev)
 
        regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
                                                 "socionext,syscon");
-       if (!IS_ERR(regmap) && priv->data->has_syscon)
-               regmap_update_bits(regmap, SG_USBPCIESEL,
-                                  SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
+       if (!IS_ERR(regmap) && priv->data->set_phymode)
+               priv->data->set_phymode(regmap);
 
        phy_set_drvdata(phy, priv);
        phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
@@ -205,16 +252,31 @@ static int uniphier_pciephy_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(phy_provider);
 }
 
+static void uniphier_pciephy_ld20_setmode(struct regmap *regmap)
+{
+       regmap_update_bits(regmap, SG_USBPCIESEL,
+                          SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
+}
+
+static const struct uniphier_pciephy_soc_data uniphier_pro5_data = {
+       .is_legacy = true,
+};
+
 static const struct uniphier_pciephy_soc_data uniphier_ld20_data = {
-       .has_syscon = true,
+       .is_legacy = false,
+       .set_phymode = uniphier_pciephy_ld20_setmode,
 };
 
 static const struct uniphier_pciephy_soc_data uniphier_pxs3_data = {
-       .has_syscon = false,
+       .is_legacy = false,
 };
 
 static const struct of_device_id uniphier_pciephy_match[] = {
        {
+               .compatible = "socionext,uniphier-pro5-pcie-phy",
+               .data = &uniphier_pro5_data,
+       },
+       {
                .compatible = "socionext,uniphier-ld20-pcie-phy",
                .data = &uniphier_ld20_data,
        },
index 50f379f..a9bc741 100644 (file)
 
 #define PHY_F(regno, msb, lsb) { (regno), (msb), (lsb) }
 
+#define RX_CHK_SYNC    PHY_F(0, 5, 5)  /* RX sync mode */
+#define RX_SYNC_SEL    PHY_F(1, 1, 0)  /* RX sync length */
 #define LS_SLEW                PHY_F(10, 6, 6) /* LS mode slew rate */
 #define FS_LS_DRV      PHY_F(10, 5, 5) /* FS/LS slew rate */
 
-#define MAX_PHY_PARAMS 2
+#define MAX_PHY_PARAMS 4
 
 struct uniphier_u3hsphy_param {
        struct {
@@ -66,13 +68,14 @@ struct uniphier_u3hsphy_trim_param {
 struct uniphier_u3hsphy_priv {
        struct device *dev;
        void __iomem *base;
-       struct clk *clk, *clk_parent, *clk_ext;
-       struct reset_control *rst, *rst_parent;
+       struct clk *clk, *clk_parent, *clk_ext, *clk_parent_gio;
+       struct reset_control *rst, *rst_parent, *rst_parent_gio;
        struct regulator *vbus;
        const struct uniphier_u3hsphy_soc_data *data;
 };
 
 struct uniphier_u3hsphy_soc_data {
+       bool is_legacy;
        int nparams;
        const struct uniphier_u3hsphy_param param[MAX_PHY_PARAMS];
        u32 config0;
@@ -256,11 +259,20 @@ static int uniphier_u3hsphy_init(struct phy *phy)
        if (ret)
                return ret;
 
-       ret = reset_control_deassert(priv->rst_parent);
+       ret = clk_prepare_enable(priv->clk_parent_gio);
        if (ret)
                goto out_clk_disable;
 
-       if (!priv->data->config0 && !priv->data->config1)
+       ret = reset_control_deassert(priv->rst_parent);
+       if (ret)
+               goto out_clk_gio_disable;
+
+       ret = reset_control_deassert(priv->rst_parent_gio);
+       if (ret)
+               goto out_rst_assert;
+
+       if ((priv->data->is_legacy)
+           || (!priv->data->config0 && !priv->data->config1))
                return 0;
 
        config0 = priv->data->config0;
@@ -280,6 +292,8 @@ static int uniphier_u3hsphy_init(struct phy *phy)
 
 out_rst_assert:
        reset_control_assert(priv->rst_parent);
+out_clk_gio_disable:
+       clk_disable_unprepare(priv->clk_parent_gio);
 out_clk_disable:
        clk_disable_unprepare(priv->clk_parent);
 
@@ -290,7 +304,9 @@ static int uniphier_u3hsphy_exit(struct phy *phy)
 {
        struct uniphier_u3hsphy_priv *priv = phy_get_drvdata(phy);
 
+       reset_control_assert(priv->rst_parent_gio);
        reset_control_assert(priv->rst_parent);
+       clk_disable_unprepare(priv->clk_parent_gio);
        clk_disable_unprepare(priv->clk_parent);
 
        return 0;
@@ -309,7 +325,6 @@ static int uniphier_u3hsphy_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct uniphier_u3hsphy_priv *priv;
        struct phy_provider *phy_provider;
-       struct resource *res;
        struct phy *phy;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -322,27 +337,38 @@ static int uniphier_u3hsphy_probe(struct platform_device *pdev)
                    priv->data->nparams > MAX_PHY_PARAMS))
                return -EINVAL;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(dev, res);
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
-       priv->clk = devm_clk_get(dev, "phy");
-       if (IS_ERR(priv->clk))
-               return PTR_ERR(priv->clk);
+       if (!priv->data->is_legacy) {
+               priv->clk = devm_clk_get(dev, "phy");
+               if (IS_ERR(priv->clk))
+                       return PTR_ERR(priv->clk);
+
+               priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
+               if (IS_ERR(priv->clk_ext))
+                       return PTR_ERR(priv->clk_ext);
+
+               priv->rst = devm_reset_control_get_shared(dev, "phy");
+               if (IS_ERR(priv->rst))
+                       return PTR_ERR(priv->rst);
+
+       } else {
+               priv->clk_parent_gio = devm_clk_get(dev, "gio");
+               if (IS_ERR(priv->clk_parent_gio))
+                       return PTR_ERR(priv->clk_parent_gio);
+
+               priv->rst_parent_gio =
+                       devm_reset_control_get_shared(dev, "gio");
+               if (IS_ERR(priv->rst_parent_gio))
+                       return PTR_ERR(priv->rst_parent_gio);
+       }
 
        priv->clk_parent = devm_clk_get(dev, "link");
        if (IS_ERR(priv->clk_parent))
                return PTR_ERR(priv->clk_parent);
 
-       priv->clk_ext = devm_clk_get_optional(dev, "phy-ext");
-       if (IS_ERR(priv->clk_ext))
-               return PTR_ERR(priv->clk_ext);
-
-       priv->rst = devm_reset_control_get_shared(dev, "phy");
-       if (IS_ERR(priv->rst))
-               return PTR_ERR(priv->rst);
-
        priv->rst_parent = devm_reset_control_get_shared(dev, "link");
        if (IS_ERR(priv->rst_parent))
                return PTR_ERR(priv->rst_parent);
@@ -364,13 +390,26 @@ static int uniphier_u3hsphy_probe(struct platform_device *pdev)
        return PTR_ERR_OR_ZERO(phy_provider);
 }
 
-static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
+static const struct uniphier_u3hsphy_soc_data uniphier_pro5_data = {
+       .is_legacy = true,
        .nparams = 0,
 };
 
-static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
+static const struct uniphier_u3hsphy_soc_data uniphier_pxs2_data = {
+       .is_legacy = false,
        .nparams = 2,
        .param = {
+               { RX_CHK_SYNC, 1 },
+               { RX_SYNC_SEL, 1 },
+       },
+};
+
+static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
+       .is_legacy = false,
+       .nparams = 4,
+       .param = {
+               { RX_CHK_SYNC, 1 },
+               { RX_SYNC_SEL, 1 },
                { LS_SLEW, 1 },
                { FS_LS_DRV, 1 },
        },
@@ -380,7 +419,12 @@ static const struct uniphier_u3hsphy_soc_data uniphier_ld20_data = {
 };
 
 static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
-       .nparams = 0,
+       .is_legacy = false,
+       .nparams = 2,
+       .param = {
+               { RX_CHK_SYNC, 1 },
+               { RX_SYNC_SEL, 1 },
+       },
        .trim_func = uniphier_u3hsphy_trim_ld20,
        .config0 = 0x92316680,
        .config1 = 0x00000106,
@@ -388,6 +432,10 @@ static const struct uniphier_u3hsphy_soc_data uniphier_pxs3_data = {
 
 static const struct of_device_id uniphier_u3hsphy_match[] = {
        {
+               .compatible = "socionext,uniphier-pro5-usb3-hsphy",
+               .data = &uniphier_pro5_data,
+       },
+       {
                .compatible = "socionext,uniphier-pxs2-usb3-hsphy",
                .data = &uniphier_pxs2_data,
        },
index ec231e4..6700645 100644 (file)
@@ -215,7 +215,6 @@ static int uniphier_u3ssphy_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct uniphier_u3ssphy_priv *priv;
        struct phy_provider *phy_provider;
-       struct resource *res;
        struct phy *phy;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -228,8 +227,7 @@ static int uniphier_u3ssphy_probe(struct platform_device *pdev)
                    priv->data->nparams > MAX_PHY_PARAMS))
                return -EINVAL;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->base = devm_ioremap_resource(dev, res);
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->base))
                return PTR_ERR(priv->base);
 
@@ -315,6 +313,10 @@ static const struct of_device_id uniphier_u3ssphy_match[] = {
                .data = &uniphier_pro4_data,
        },
        {
+               .compatible = "socionext,uniphier-pro5-usb3-ssphy",
+               .data = &uniphier_pro4_data,
+       },
+       {
                .compatible = "socionext,uniphier-pxs2-usb3-ssphy",
                .data = &uniphier_pxs2_data,
        },
index f9817c3..a208aca 100644 (file)
@@ -2,6 +2,8 @@
 config PHY_TEGRA_XUSB
        tristate "NVIDIA Tegra XUSB pad controller driver"
        depends on ARCH_TEGRA
+       select USB_CONN_GPIO
+       select USB_PHY
        help
          Choose this option if you have an NVIDIA Tegra SoC.
 
index 320dd38..89b8406 100644 (file)
@@ -6,4 +6,5 @@ phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_124_SOC) += xusb-tegra124.o
 phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o
 phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o
 phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o
+phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_194_SOC) += xusb-tegra186.o
 obj-$(CONFIG_PHY_TEGRA194_P2U) += phy-tegra194-p2u.o
index 98d8492..db56c7f 100644 (file)
@@ -1422,6 +1422,8 @@ tegra124_usb2_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra124_usb2_port_ops = {
+       .release = tegra_xusb_usb2_port_release,
+       .remove = tegra_xusb_usb2_port_remove,
        .enable = tegra124_usb2_port_enable,
        .disable = tegra124_usb2_port_disable,
        .map = tegra124_usb2_port_map,
@@ -1443,6 +1445,7 @@ tegra124_ulpi_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra124_ulpi_port_ops = {
+       .release = tegra_xusb_ulpi_port_release,
        .enable = tegra124_ulpi_port_enable,
        .disable = tegra124_ulpi_port_disable,
        .map = tegra124_ulpi_port_map,
@@ -1464,6 +1467,7 @@ tegra124_hsic_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra124_hsic_port_ops = {
+       .release = tegra_xusb_hsic_port_release,
        .enable = tegra124_hsic_port_enable,
        .disable = tegra124_hsic_port_disable,
        .map = tegra124_hsic_port_map,
@@ -1647,6 +1651,8 @@ tegra124_usb3_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra124_usb3_port_ops = {
+       .release = tegra_xusb_usb3_port_release,
+       .remove = tegra_xusb_usb3_port_remove,
        .enable = tegra124_usb3_port_enable,
        .disable = tegra124_usb3_port_disable,
        .map = tegra124_usb3_port_map,
index 84c2739..5d64f69 100644 (file)
 #define  SSPX_ELPG_CLAMP_EN(x)                 BIT(0 + (x) * 3)
 #define  SSPX_ELPG_CLAMP_EN_EARLY(x)           BIT(1 + (x) * 3)
 #define  SSPX_ELPG_VCORE_DOWN(x)               BIT(2 + (x) * 3)
+#define XUSB_PADCTL_SS_PORT_CFG                        0x2c
+#define   PORTX_SPEED_SUPPORT_SHIFT(x)         ((x) * 4)
+#define   PORTX_SPEED_SUPPORT_MASK             (0x3)
+#define     PORT_SPEED_SUPPORT_GEN1            (0x0)
 
 #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x)      (0x88 + (x) * 0x40)
 #define  HS_CURR_LEVEL(x)                      ((x) & 0x3f)
@@ -301,6 +305,97 @@ static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy)
        tegra186_utmi_bias_pad_power_off(padctl);
 }
 
+static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
+                                              bool status)
+{
+       u32 value;
+
+       dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
+
+       value = padctl_readl(padctl, USB2_VBUS_ID);
+
+       if (status) {
+               value |= VBUS_OVERRIDE;
+               value &= ~ID_OVERRIDE(~0);
+               value |= ID_OVERRIDE_FLOATING;
+       } else {
+               value &= ~VBUS_OVERRIDE;
+       }
+
+       padctl_writel(padctl, value, USB2_VBUS_ID);
+
+       return 0;
+}
+
+static int tegra186_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
+                                           bool status)
+{
+       u32 value;
+
+       dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
+
+       value = padctl_readl(padctl, USB2_VBUS_ID);
+
+       if (status) {
+               if (value & VBUS_OVERRIDE) {
+                       value &= ~VBUS_OVERRIDE;
+                       padctl_writel(padctl, value, USB2_VBUS_ID);
+                       usleep_range(1000, 2000);
+
+                       value = padctl_readl(padctl, USB2_VBUS_ID);
+               }
+
+               value &= ~ID_OVERRIDE(~0);
+               value |= ID_OVERRIDE_GROUNDED;
+       } else {
+               value &= ~ID_OVERRIDE(~0);
+               value |= ID_OVERRIDE_FLOATING;
+       }
+
+       padctl_writel(padctl, value, USB2_VBUS_ID);
+
+       return 0;
+}
+
+static int tegra186_utmi_phy_set_mode(struct phy *phy, enum phy_mode mode,
+                                     int submode)
+{
+       struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+       struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+       struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
+                                                               lane->index);
+       int err = 0;
+
+       mutex_lock(&padctl->lock);
+
+       dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
+
+       if (mode == PHY_MODE_USB_OTG) {
+               if (submode == USB_ROLE_HOST) {
+                       tegra186_xusb_padctl_id_override(padctl, true);
+
+                       err = regulator_enable(port->supply);
+               } else if (submode == USB_ROLE_DEVICE) {
+                       tegra186_xusb_padctl_vbus_override(padctl, true);
+               } else if (submode == USB_ROLE_NONE) {
+                       /*
+                        * When port is peripheral only or role transitions to
+                        * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
+                        * enabled.
+                        */
+                       if (regulator_is_enabled(port->supply))
+                               regulator_disable(port->supply);
+
+                       tegra186_xusb_padctl_id_override(padctl, false);
+                       tegra186_xusb_padctl_vbus_override(padctl, false);
+               }
+       }
+
+       mutex_unlock(&padctl->lock);
+
+       return err;
+}
+
 static int tegra186_utmi_phy_power_on(struct phy *phy)
 {
        struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
@@ -439,6 +534,7 @@ static const struct phy_ops utmi_phy_ops = {
        .exit = tegra186_utmi_phy_exit,
        .power_on = tegra186_utmi_phy_power_on,
        .power_off = tegra186_utmi_phy_power_off,
+       .set_mode = tegra186_utmi_phy_set_mode,
        .owner = THIS_MODULE,
 };
 
@@ -503,19 +599,6 @@ static const char * const tegra186_usb2_functions[] = {
        "xusb",
 };
 
-static const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = {
-       TEGRA186_LANE("usb2-0", 0,  0, 0, usb2),
-       TEGRA186_LANE("usb2-1", 0,  0, 0, usb2),
-       TEGRA186_LANE("usb2-2", 0,  0, 0, usb2),
-};
-
-static const struct tegra_xusb_pad_soc tegra186_usb2_pad = {
-       .name = "usb2",
-       .num_lanes = ARRAY_SIZE(tegra186_usb2_lanes),
-       .lanes = tegra186_usb2_lanes,
-       .ops = &tegra186_usb2_pad_ops,
-};
-
 static int tegra186_usb2_port_enable(struct tegra_xusb_port *port)
 {
        return 0;
@@ -532,6 +615,8 @@ tegra186_usb2_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = {
+       .release = tegra_xusb_usb2_port_release,
+       .remove = tegra_xusb_usb2_port_remove,
        .enable = tegra186_usb2_port_enable,
        .disable = tegra186_usb2_port_disable,
        .map = tegra186_usb2_port_map,
@@ -591,6 +676,8 @@ tegra186_usb3_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = {
+       .release = tegra_xusb_usb3_port_release,
+       .remove = tegra_xusb_usb3_port_remove,
        .enable = tegra186_usb3_port_enable,
        .disable = tegra186_usb3_port_disable,
        .map = tegra186_usb3_port_map,
@@ -635,6 +722,15 @@ static int tegra186_usb3_phy_power_on(struct phy *phy)
 
        padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP);
 
+       if (padctl->soc->supports_gen2 && port->disable_gen2) {
+               value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CFG);
+               value &= ~(PORTX_SPEED_SUPPORT_MASK <<
+                       PORTX_SPEED_SUPPORT_SHIFT(index));
+               value |= (PORT_SPEED_SUPPORT_GEN1 <<
+                       PORTX_SPEED_SUPPORT_SHIFT(index));
+               padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CFG);
+       }
+
        value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
        value &= ~SSPX_ELPG_VCORE_DOWN(index);
        padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
@@ -765,27 +861,6 @@ static const char * const tegra186_usb3_functions[] = {
        "xusb",
 };
 
-static const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = {
-       TEGRA186_LANE("usb3-0", 0,  0, 0, usb3),
-       TEGRA186_LANE("usb3-1", 0,  0, 0, usb3),
-       TEGRA186_LANE("usb3-2", 0,  0, 0, usb3),
-};
-
-static const struct tegra_xusb_pad_soc tegra186_usb3_pad = {
-       .name = "usb3",
-       .num_lanes = ARRAY_SIZE(tegra186_usb3_lanes),
-       .lanes = tegra186_usb3_lanes,
-       .ops = &tegra186_usb3_pad_ops,
-};
-
-static const struct tegra_xusb_pad_soc * const tegra186_pads[] = {
-       &tegra186_usb2_pad,
-       &tegra186_usb3_pad,
-#if 0 /* TODO implement */
-       &tegra186_hsic_pad,
-#endif
-};
-
 static int
 tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
 {
@@ -802,7 +877,9 @@ tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl)
 
        err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
        if (err) {
-               dev_err(dev, "failed to read calibration fuse: %d\n", err);
+               if (err != -EPROBE_DEFER)
+                       dev_err(dev, "failed to read calibration fuse: %d\n",
+                               err);
                return err;
        }
 
@@ -857,34 +934,13 @@ static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl)
 {
 }
 
-static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
-                                              bool status)
-{
-       u32 value;
-
-       dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
-
-       value = padctl_readl(padctl, USB2_VBUS_ID);
-
-       if (status) {
-               value |= VBUS_OVERRIDE;
-               value &= ~ID_OVERRIDE(~0);
-               value |= ID_OVERRIDE_FLOATING;
-       } else {
-               value &= ~VBUS_OVERRIDE;
-       }
-
-       padctl_writel(padctl, value, USB2_VBUS_ID);
-
-       return 0;
-}
-
 static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = {
        .probe = tegra186_xusb_padctl_probe,
        .remove = tegra186_xusb_padctl_remove,
        .vbus_override = tegra186_xusb_padctl_vbus_override,
 };
 
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
 static const char * const tegra186_xusb_padctl_supply_names[] = {
        "avdd-pll-erefeut",
        "avdd-usb",
@@ -892,6 +948,40 @@ static const char * const tegra186_xusb_padctl_supply_names[] = {
        "vddio-hsic",
 };
 
+static const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = {
+       TEGRA186_LANE("usb2-0", 0,  0, 0, usb2),
+       TEGRA186_LANE("usb2-1", 0,  0, 0, usb2),
+       TEGRA186_LANE("usb2-2", 0,  0, 0, usb2),
+};
+
+static const struct tegra_xusb_pad_soc tegra186_usb2_pad = {
+       .name = "usb2",
+       .num_lanes = ARRAY_SIZE(tegra186_usb2_lanes),
+       .lanes = tegra186_usb2_lanes,
+       .ops = &tegra186_usb2_pad_ops,
+};
+
+static const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = {
+       TEGRA186_LANE("usb3-0", 0,  0, 0, usb3),
+       TEGRA186_LANE("usb3-1", 0,  0, 0, usb3),
+       TEGRA186_LANE("usb3-2", 0,  0, 0, usb3),
+};
+
+static const struct tegra_xusb_pad_soc tegra186_usb3_pad = {
+       .name = "usb3",
+       .num_lanes = ARRAY_SIZE(tegra186_usb3_lanes),
+       .lanes = tegra186_usb3_lanes,
+       .ops = &tegra186_usb3_pad_ops,
+};
+
+static const struct tegra_xusb_pad_soc * const tegra186_pads[] = {
+       &tegra186_usb2_pad,
+       &tegra186_usb3_pad,
+#if 0 /* TODO implement */
+       &tegra186_hsic_pad,
+#endif
+};
+
 const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
        .num_pads = ARRAY_SIZE(tegra186_pads),
        .pads = tegra186_pads,
@@ -916,6 +1006,67 @@ const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = {
        .num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names),
 };
 EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc);
+#endif
+
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC)
+static const char * const tegra194_xusb_padctl_supply_names[] = {
+       "avdd-usb",
+       "vclamp-usb",
+};
+
+static const struct tegra_xusb_lane_soc tegra194_usb2_lanes[] = {
+       TEGRA186_LANE("usb2-0", 0,  0, 0, usb2),
+       TEGRA186_LANE("usb2-1", 0,  0, 0, usb2),
+       TEGRA186_LANE("usb2-2", 0,  0, 0, usb2),
+       TEGRA186_LANE("usb2-3", 0,  0, 0, usb2),
+};
+
+static const struct tegra_xusb_pad_soc tegra194_usb2_pad = {
+       .name = "usb2",
+       .num_lanes = ARRAY_SIZE(tegra194_usb2_lanes),
+       .lanes = tegra194_usb2_lanes,
+       .ops = &tegra186_usb2_pad_ops,
+};
+
+static const struct tegra_xusb_lane_soc tegra194_usb3_lanes[] = {
+       TEGRA186_LANE("usb3-0", 0,  0, 0, usb3),
+       TEGRA186_LANE("usb3-1", 0,  0, 0, usb3),
+       TEGRA186_LANE("usb3-2", 0,  0, 0, usb3),
+       TEGRA186_LANE("usb3-3", 0,  0, 0, usb3),
+};
+
+static const struct tegra_xusb_pad_soc tegra194_usb3_pad = {
+       .name = "usb3",
+       .num_lanes = ARRAY_SIZE(tegra194_usb3_lanes),
+       .lanes = tegra194_usb3_lanes,
+       .ops = &tegra186_usb3_pad_ops,
+};
+
+static const struct tegra_xusb_pad_soc * const tegra194_pads[] = {
+       &tegra194_usb2_pad,
+       &tegra194_usb3_pad,
+};
+
+const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc = {
+       .num_pads = ARRAY_SIZE(tegra194_pads),
+       .pads = tegra194_pads,
+       .ports = {
+               .usb2 = {
+                       .ops = &tegra186_usb2_port_ops,
+                       .count = 4,
+               },
+               .usb3 = {
+                       .ops = &tegra186_usb3_port_ops,
+                       .count = 4,
+               },
+       },
+       .ops = &tegra186_xusb_padctl_ops,
+       .supply_names = tegra194_xusb_padctl_supply_names,
+       .num_supplies = ARRAY_SIZE(tegra194_xusb_padctl_supply_names),
+       .supports_gen2 = true,
+};
+EXPORT_SYMBOL_GPL(tegra194_xusb_padctl_soc);
+#endif
 
 MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>");
 MODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver");
index 394913b..66bd461 100644 (file)
 #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT 18
 #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK 0xf
 #define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING 8
+#define XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED 0
 
 struct tegra210_xusb_fuse_calibration {
        u32 hs_curr_level[4];
@@ -935,6 +936,103 @@ static int tegra210_usb2_phy_exit(struct phy *phy)
        return tegra210_xusb_padctl_disable(lane->pad->padctl);
 }
 
+static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
+                                             bool status)
+{
+       u32 value;
+
+       dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
+
+       value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
+
+       if (status) {
+               value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
+               value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
+                          XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
+               value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
+                        XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
+       } else {
+               value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
+       }
+
+       padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
+
+       return 0;
+}
+
+static int tegra210_xusb_padctl_id_override(struct tegra_xusb_padctl *padctl,
+                                           bool status)
+{
+       u32 value;
+
+       dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
+
+       value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
+
+       if (status) {
+               if (value & XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON) {
+                       value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
+                       padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
+                       usleep_range(1000, 2000);
+
+                       value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
+               }
+
+               value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
+                          XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
+               value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_GROUNDED <<
+                        XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
+       } else {
+               value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
+                          XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
+               value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
+                        XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
+       }
+
+       padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
+
+       return 0;
+}
+
+static int tegra210_usb2_phy_set_mode(struct phy *phy, enum phy_mode mode,
+                                     int submode)
+{
+       struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
+       struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+       struct tegra_xusb_usb2_port *port = tegra_xusb_find_usb2_port(padctl,
+                                                               lane->index);
+       int err = 0;
+
+       mutex_lock(&padctl->lock);
+
+       dev_dbg(&port->base.dev, "%s: mode %d", __func__, mode);
+
+       if (mode == PHY_MODE_USB_OTG) {
+               if (submode == USB_ROLE_HOST) {
+                       tegra210_xusb_padctl_id_override(padctl, true);
+
+                       err = regulator_enable(port->supply);
+               } else if (submode == USB_ROLE_DEVICE) {
+                       tegra210_xusb_padctl_vbus_override(padctl, true);
+               } else if (submode == USB_ROLE_NONE) {
+                       /*
+                        * When port is peripheral only or role transitions to
+                        * USB_ROLE_NONE from USB_ROLE_DEVICE, regulator is not
+                        * be enabled.
+                        */
+                       if (regulator_is_enabled(port->supply))
+                               regulator_disable(port->supply);
+
+                       tegra210_xusb_padctl_id_override(padctl, false);
+                       tegra210_xusb_padctl_vbus_override(padctl, false);
+               }
+       }
+
+       mutex_unlock(&padctl->lock);
+
+       return err;
+}
+
 static int tegra210_usb2_phy_power_on(struct phy *phy)
 {
        struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
@@ -1048,9 +1146,11 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
        padctl_writel(padctl, value,
                      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
 
-       err = regulator_enable(port->supply);
-       if (err)
-               return err;
+       if (port->supply && port->mode == USB_DR_MODE_HOST) {
+               err = regulator_enable(port->supply);
+               if (err)
+                       return err;
+       }
 
        mutex_lock(&padctl->lock);
 
@@ -1164,6 +1264,7 @@ static const struct phy_ops tegra210_usb2_phy_ops = {
        .exit = tegra210_usb2_phy_exit,
        .power_on = tegra210_usb2_phy_power_on,
        .power_off = tegra210_usb2_phy_power_off,
+       .set_mode = tegra210_usb2_phy_set_mode,
        .owner = THIS_MODULE,
 };
 
@@ -1852,6 +1953,8 @@ tegra210_usb2_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra210_usb2_port_ops = {
+       .release = tegra_xusb_usb2_port_release,
+       .remove = tegra_xusb_usb2_port_remove,
        .enable = tegra210_usb2_port_enable,
        .disable = tegra210_usb2_port_disable,
        .map = tegra210_usb2_port_map,
@@ -1873,6 +1976,7 @@ tegra210_hsic_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra210_hsic_port_ops = {
+       .release = tegra_xusb_hsic_port_release,
        .enable = tegra210_hsic_port_enable,
        .disable = tegra210_hsic_port_disable,
        .map = tegra210_hsic_port_map,
@@ -2018,35 +2122,13 @@ tegra210_usb3_port_map(struct tegra_xusb_port *port)
 }
 
 static const struct tegra_xusb_port_ops tegra210_usb3_port_ops = {
+       .release = tegra_xusb_usb3_port_release,
+       .remove = tegra_xusb_usb3_port_remove,
        .enable = tegra210_usb3_port_enable,
        .disable = tegra210_usb3_port_disable,
        .map = tegra210_usb3_port_map,
 };
 
-static int tegra210_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
-                                             bool status)
-{
-       u32 value;
-
-       dev_dbg(padctl->dev, "%s vbus override\n", status ? "set" : "clear");
-
-       value = padctl_readl(padctl, XUSB_PADCTL_USB2_VBUS_ID);
-
-       if (status) {
-               value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
-               value &= ~(XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_MASK <<
-                          XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT);
-               value |= XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_FLOATING <<
-                        XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_SHIFT;
-       } else {
-               value &= ~XUSB_PADCTL_USB2_VBUS_ID_OVERRIDE_VBUS_ON;
-       }
-
-       padctl_writel(padctl, value, XUSB_PADCTL_USB2_VBUS_ID);
-
-       return 0;
-}
-
 static int tegra210_utmi_port_reset(struct phy *phy)
 {
        struct tegra_xusb_padctl *padctl;
index f98ec39..de4a46f 100644 (file)
@@ -66,6 +66,12 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = {
                .data = &tegra186_xusb_padctl_soc,
        },
 #endif
+#if defined(CONFIG_ARCH_TEGRA_194_SOC)
+       {
+               .compatible = "nvidia,tegra194-xusb-padctl",
+               .data = &tegra194_xusb_padctl_soc,
+       },
+#endif
        { }
 };
 MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
@@ -501,6 +507,10 @@ tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl, unsigned int index)
 
 static void tegra_xusb_port_release(struct device *dev)
 {
+       struct tegra_xusb_port *port = to_tegra_xusb_port(dev);
+
+       if (port->ops->release)
+               port->ops->release(port);
 }
 
 static struct device_type tegra_xusb_port_type = {
@@ -541,6 +551,16 @@ unregister:
 
 static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
 {
+       if (!IS_ERR_OR_NULL(port->usb_role_sw)) {
+               of_platform_depopulate(&port->dev);
+               usb_role_switch_unregister(port->usb_role_sw);
+               cancel_work_sync(&port->usb_phy_work);
+               usb_remove_phy(&port->usb_phy);
+       }
+
+       if (port->ops->remove)
+               port->ops->remove(port);
+
        device_unregister(&port->dev);
 }
 
@@ -551,11 +571,146 @@ static const char *const modes[] = {
        [USB_DR_MODE_OTG] = "otg",
 };
 
+static const char * const usb_roles[] = {
+       [USB_ROLE_NONE]         = "none",
+       [USB_ROLE_HOST]         = "host",
+       [USB_ROLE_DEVICE]       = "device",
+};
+
+static enum usb_phy_events to_usb_phy_event(enum usb_role role)
+{
+       switch (role) {
+       case USB_ROLE_DEVICE:
+               return USB_EVENT_VBUS;
+
+       case USB_ROLE_HOST:
+               return USB_EVENT_ID;
+
+       default:
+               return USB_EVENT_NONE;
+       }
+}
+
+static void tegra_xusb_usb_phy_work(struct work_struct *work)
+{
+       struct tegra_xusb_port *port = container_of(work,
+                                                   struct tegra_xusb_port,
+                                                   usb_phy_work);
+       enum usb_role role = usb_role_switch_get_role(port->usb_role_sw);
+
+       usb_phy_set_event(&port->usb_phy, to_usb_phy_event(role));
+
+       dev_dbg(&port->dev, "%s(): calling notifier for role %s\n", __func__,
+               usb_roles[role]);
+
+       atomic_notifier_call_chain(&port->usb_phy.notifier, 0, &port->usb_phy);
+}
+
+static int tegra_xusb_role_sw_set(struct usb_role_switch *sw,
+                                 enum usb_role role)
+{
+       struct tegra_xusb_port *port = usb_role_switch_get_drvdata(sw);
+
+       dev_dbg(&port->dev, "%s(): role %s\n", __func__, usb_roles[role]);
+
+       schedule_work(&port->usb_phy_work);
+
+       return 0;
+}
+
+static int tegra_xusb_set_peripheral(struct usb_otg *otg,
+                                    struct usb_gadget *gadget)
+{
+       struct tegra_xusb_port *port = container_of(otg->usb_phy,
+                                                   struct tegra_xusb_port,
+                                                   usb_phy);
+
+       if (gadget != NULL)
+               schedule_work(&port->usb_phy_work);
+
+       return 0;
+}
+
+static int tegra_xusb_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct tegra_xusb_port *port = container_of(otg->usb_phy,
+                                                   struct tegra_xusb_port,
+                                                   usb_phy);
+
+       if (host != NULL)
+               schedule_work(&port->usb_phy_work);
+
+       return 0;
+}
+
+
+static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
+{
+       struct tegra_xusb_lane *lane;
+       struct usb_role_switch_desc role_sx_desc = {
+               .fwnode = dev_fwnode(&port->dev),
+               .set = tegra_xusb_role_sw_set,
+       };
+       int err = 0;
+
+       /*
+        * USB role switch driver needs parent driver owner info. This is a
+        * suboptimal solution. TODO: Need to revisit this in a follow-up patch
+        * where an optimal solution is possible with changes to USB role
+        * switch driver.
+        */
+       port->dev.driver = devm_kzalloc(&port->dev,
+                                       sizeof(struct device_driver),
+                                       GFP_KERNEL);
+       port->dev.driver->owner  = THIS_MODULE;
+
+       port->usb_role_sw = usb_role_switch_register(&port->dev,
+                                                    &role_sx_desc);
+       if (IS_ERR(port->usb_role_sw)) {
+               err = PTR_ERR(port->usb_role_sw);
+               dev_err(&port->dev, "failed to register USB role switch: %d",
+                       err);
+               return err;
+       }
+
+       INIT_WORK(&port->usb_phy_work, tegra_xusb_usb_phy_work);
+       usb_role_switch_set_drvdata(port->usb_role_sw, port);
+
+       port->usb_phy.otg = devm_kzalloc(&port->dev, sizeof(struct usb_otg),
+                                        GFP_KERNEL);
+       if (!port->usb_phy.otg)
+               return -ENOMEM;
+
+       lane = tegra_xusb_find_lane(port->padctl, "usb2", port->index);
+
+       /*
+        * Assign phy dev to usb-phy dev. Host/device drivers can use phy
+        * reference to retrieve usb-phy details.
+        */
+       port->usb_phy.dev = &lane->pad->lanes[port->index]->dev;
+       port->usb_phy.dev->driver = port->padctl->dev->driver;
+       port->usb_phy.otg->usb_phy = &port->usb_phy;
+       port->usb_phy.otg->set_peripheral = tegra_xusb_set_peripheral;
+       port->usb_phy.otg->set_host = tegra_xusb_set_host;
+
+       err = usb_add_phy_dev(&port->usb_phy);
+       if (err < 0) {
+               dev_err(&port->dev, "Failed to add USB PHY: %d\n", err);
+               return err;
+       }
+
+       /* populate connector entry */
+       of_platform_populate(port->dev.of_node, NULL, NULL, &port->dev);
+
+       return err;
+}
+
 static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
 {
        struct tegra_xusb_port *port = &usb2->base;
        struct device_node *np = port->dev.of_node;
        const char *mode;
+       int err;
 
        usb2->internal = of_property_read_bool(np, "nvidia,internal");
 
@@ -572,7 +727,21 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
                usb2->mode = USB_DR_MODE_HOST;
        }
 
-       usb2->supply = devm_regulator_get(&port->dev, "vbus");
+       /* usb-role-switch property is mandatory for OTG/Peripheral modes */
+       if (usb2->mode == USB_DR_MODE_PERIPHERAL ||
+           usb2->mode == USB_DR_MODE_OTG) {
+               if (of_property_read_bool(np, "usb-role-switch")) {
+                       err = tegra_xusb_setup_usb_role_switch(port);
+                       if (err < 0)
+                               return err;
+               } else {
+                       dev_err(&port->dev, "usb-role-switch not found for %s mode",
+                               modes[usb2->mode]);
+                       return -EINVAL;
+               }
+       }
+
+       usb2->supply = regulator_get(&port->dev, "vbus");
        return PTR_ERR_OR_ZERO(usb2->supply);
 }
 
@@ -591,7 +760,7 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
        if (!np || !of_device_is_available(np))
                goto out;
 
-       usb2 = devm_kzalloc(padctl->dev, sizeof(*usb2), GFP_KERNEL);
+       usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL);
        if (!usb2) {
                err = -ENOMEM;
                goto out;
@@ -622,6 +791,20 @@ out:
        return err;
 }
 
+void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port)
+{
+       struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
+
+       kfree(usb2);
+}
+
+void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port)
+{
+       struct tegra_xusb_usb2_port *usb2 = to_usb2_port(port);
+
+       regulator_put(usb2->supply);
+}
+
 static int tegra_xusb_ulpi_port_parse_dt(struct tegra_xusb_ulpi_port *ulpi)
 {
        struct tegra_xusb_port *port = &ulpi->base;
@@ -643,7 +826,7 @@ static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl,
        if (!np || !of_device_is_available(np))
                goto out;
 
-       ulpi = devm_kzalloc(padctl->dev, sizeof(*ulpi), GFP_KERNEL);
+       ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
        if (!ulpi) {
                err = -ENOMEM;
                goto out;
@@ -674,6 +857,13 @@ out:
        return err;
 }
 
+void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port)
+{
+       struct tegra_xusb_ulpi_port *ulpi = to_ulpi_port(port);
+
+       kfree(ulpi);
+}
+
 static int tegra_xusb_hsic_port_parse_dt(struct tegra_xusb_hsic_port *hsic)
 {
        /* XXX */
@@ -691,7 +881,7 @@ static int tegra_xusb_add_hsic_port(struct tegra_xusb_padctl *padctl,
        if (!np || !of_device_is_available(np))
                goto out;
 
-       hsic = devm_kzalloc(padctl->dev, sizeof(*hsic), GFP_KERNEL);
+       hsic = kzalloc(sizeof(*hsic), GFP_KERNEL);
        if (!hsic) {
                err = -ENOMEM;
                goto out;
@@ -722,10 +912,18 @@ out:
        return err;
 }
 
+void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port)
+{
+       struct tegra_xusb_hsic_port *hsic = to_hsic_port(port);
+
+       kfree(hsic);
+}
+
 static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
 {
        struct tegra_xusb_port *port = &usb3->base;
        struct device_node *np = port->dev.of_node;
+       enum usb_device_speed maximum_speed;
        u32 value;
        int err;
 
@@ -739,7 +937,17 @@ static int tegra_xusb_usb3_port_parse_dt(struct tegra_xusb_usb3_port *usb3)
 
        usb3->internal = of_property_read_bool(np, "nvidia,internal");
 
-       usb3->supply = devm_regulator_get(&port->dev, "vbus");
+       if (device_property_present(&port->dev, "maximum-speed")) {
+               maximum_speed =  usb_get_maximum_speed(&port->dev);
+               if (maximum_speed == USB_SPEED_SUPER)
+                       usb3->disable_gen2 = true;
+               else if (maximum_speed == USB_SPEED_SUPER_PLUS)
+                       usb3->disable_gen2 = false;
+               else
+                       return -EINVAL;
+       }
+
+       usb3->supply = regulator_get(&port->dev, "vbus");
        return PTR_ERR_OR_ZERO(usb3->supply);
 }
 
@@ -759,7 +967,7 @@ static int tegra_xusb_add_usb3_port(struct tegra_xusb_padctl *padctl,
        if (!np || !of_device_is_available(np))
                goto out;
 
-       usb3 = devm_kzalloc(padctl->dev, sizeof(*usb3), GFP_KERNEL);
+       usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL);
        if (!usb3) {
                err = -ENOMEM;
                goto out;
@@ -790,6 +998,20 @@ out:
        return err;
 }
 
+void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port)
+{
+       struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
+
+       kfree(usb3);
+}
+
+void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port)
+{
+       struct tegra_xusb_usb3_port *usb3 = to_usb3_port(port);
+
+       regulator_put(usb3->supply);
+}
+
 static void __tegra_xusb_remove_ports(struct tegra_xusb_padctl *padctl)
 {
        struct tegra_xusb_port *port, *tmp;
@@ -1001,7 +1223,13 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 
        err = tegra_xusb_setup_ports(padctl);
        if (err) {
-               dev_err(&pdev->dev, "failed to setup XUSB ports: %d\n", err);
+               const char *level = KERN_ERR;
+
+               if (err == -EPROBE_DEFER)
+                       level = KERN_DEBUG;
+
+               dev_printk(level, &pdev->dev,
+                          dev_fmt("failed to setup XUSB ports: %d\n"), err);
                goto remove_pads;
        }
 
@@ -1143,6 +1371,27 @@ int tegra_phy_xusb_utmi_port_reset(struct phy *phy)
 }
 EXPORT_SYMBOL_GPL(tegra_phy_xusb_utmi_port_reset);
 
+int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
+                                   unsigned int port)
+{
+       struct tegra_xusb_usb2_port *usb2;
+       struct tegra_xusb_usb3_port *usb3;
+       int i;
+
+       usb2 = tegra_xusb_find_usb2_port(padctl, port);
+       if (!usb2)
+               return -EINVAL;
+
+       for (i = 0; i < padctl->soc->ports.usb3.count; i++) {
+               usb3 = tegra_xusb_find_usb3_port(padctl, i);
+               if (usb3 && usb3->port == usb2->base.index)
+                       return usb3->base.index;
+       }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_usb3_companion);
+
 MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
 MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver");
 MODULE_LICENSE("GPL v2");
index da94fcc..ea35af7 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/workqueue.h>
 
 #include <linux/usb/otg.h>
+#include <linux/usb/role.h>
 
 /* legacy entry points for backwards-compatibility */
 int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev);
@@ -266,9 +267,18 @@ struct tegra_xusb_port {
        struct list_head list;
        struct device dev;
 
+       struct usb_role_switch *usb_role_sw;
+       struct work_struct usb_phy_work;
+       struct usb_phy usb_phy;
+
        const struct tegra_xusb_port_ops *ops;
 };
 
+static inline struct tegra_xusb_port *to_tegra_xusb_port(struct device *dev)
+{
+       return container_of(dev, struct tegra_xusb_port, dev);
+}
+
 struct tegra_xusb_lane_map {
        unsigned int port;
        const char *type;
@@ -303,6 +313,8 @@ to_usb2_port(struct tegra_xusb_port *port)
 struct tegra_xusb_usb2_port *
 tegra_xusb_find_usb2_port(struct tegra_xusb_padctl *padctl,
                          unsigned int index);
+void tegra_xusb_usb2_port_release(struct tegra_xusb_port *port);
+void tegra_xusb_usb2_port_remove(struct tegra_xusb_port *port);
 
 struct tegra_xusb_ulpi_port {
        struct tegra_xusb_port base;
@@ -317,6 +329,8 @@ to_ulpi_port(struct tegra_xusb_port *port)
        return container_of(port, struct tegra_xusb_ulpi_port, base);
 }
 
+void tegra_xusb_ulpi_port_release(struct tegra_xusb_port *port);
+
 struct tegra_xusb_hsic_port {
        struct tegra_xusb_port base;
 };
@@ -327,12 +341,15 @@ to_hsic_port(struct tegra_xusb_port *port)
        return container_of(port, struct tegra_xusb_hsic_port, base);
 }
 
+void tegra_xusb_hsic_port_release(struct tegra_xusb_port *port);
+
 struct tegra_xusb_usb3_port {
        struct tegra_xusb_port base;
        struct regulator *supply;
        bool context_saved;
        unsigned int port;
        bool internal;
+       bool disable_gen2;
 
        u32 tap1;
        u32 amp;
@@ -349,8 +366,12 @@ to_usb3_port(struct tegra_xusb_port *port)
 struct tegra_xusb_usb3_port *
 tegra_xusb_find_usb3_port(struct tegra_xusb_padctl *padctl,
                          unsigned int index);
+void tegra_xusb_usb3_port_release(struct tegra_xusb_port *port);
+void tegra_xusb_usb3_port_remove(struct tegra_xusb_port *port);
 
 struct tegra_xusb_port_ops {
+       void (*release)(struct tegra_xusb_port *port);
+       void (*remove)(struct tegra_xusb_port *port);
        int (*enable)(struct tegra_xusb_port *port);
        void (*disable)(struct tegra_xusb_port *port);
        struct tegra_xusb_lane *(*map)(struct tegra_xusb_port *port);
@@ -392,6 +413,7 @@ struct tegra_xusb_padctl_soc {
 
        const char * const *supply_names;
        unsigned int num_supplies;
+       bool supports_gen2;
        bool need_fake_usb3_port;
 };
 
@@ -448,5 +470,8 @@ extern const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc;
 #if defined(CONFIG_ARCH_TEGRA_186_SOC)
 extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc;
 #endif
+#if defined(CONFIG_ARCH_TEGRA_194_SOC)
+extern const struct tegra_xusb_padctl_soc tegra194_xusb_padctl_soc;
+#endif
 
 #endif /* __PHY_TEGRA_XUSB_H */
index a28bd15..7edd5c3 100644 (file)
@@ -80,20 +80,20 @@ static int phy_gmii_sel_mode(struct phy *phy, enum phy_mode mode, int submode)
                break;
 
        case PHY_INTERFACE_MODE_MII:
-               mode = AM33XX_GMII_SEL_MODE_MII;
+       case PHY_INTERFACE_MODE_GMII:
+               gmii_sel_mode = AM33XX_GMII_SEL_MODE_MII;
                break;
 
        default:
-               dev_warn(dev,
-                        "port%u: unsupported mode: \"%s\". Defaulting to MII.\n",
-                        if_phy->id, phy_modes(rgmii_id));
+               dev_warn(dev, "port%u: unsupported mode: \"%s\"\n",
+                        if_phy->id, phy_modes(submode));
                return -EINVAL;
        }
 
        if_phy->phy_if_mode = submode;
 
        dev_dbg(dev, "%s id:%u mode:%u rgmii_id:%d rmii_clk_ext:%d\n",
-               __func__, if_phy->id, mode, rgmii_id,
+               __func__, if_phy->id, submode, rgmii_id,
                if_phy->rmii_clock_external);
 
        regfield = if_phy->fields[PHY_GMII_SEL_PORT_MODE];
@@ -170,6 +170,21 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_dm814 = {
        .regfields = phy_gmii_sel_fields_am33xx,
 };
 
+static const
+struct reg_field phy_gmii_sel_fields_am654[][PHY_GMII_SEL_LAST] = {
+       {
+               [PHY_GMII_SEL_PORT_MODE] = REG_FIELD(0x4040, 0, 1),
+               [PHY_GMII_SEL_RGMII_ID_MODE] = REG_FIELD((~0), 0, 0),
+               [PHY_GMII_SEL_RMII_IO_CLK_EN] = REG_FIELD((~0), 0, 0),
+       },
+};
+
+static const
+struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
+       .num_ports = 1,
+       .regfields = phy_gmii_sel_fields_am654,
+};
+
 static const struct of_device_id phy_gmii_sel_id_table[] = {
        {
                .compatible     = "ti,am3352-phy-gmii-sel",
@@ -187,6 +202,10 @@ static const struct of_device_id phy_gmii_sel_id_table[] = {
                .compatible     = "ti,dm814-phy-gmii-sel",
                .data           = &phy_gmii_sel_soc_dm814,
        },
+       {
+               .compatible     = "ti,am654-phy-gmii-sel",
+               .data           = &phy_gmii_sel_soc_am654,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, phy_gmii_sel_id_table);
index 7b6409e..dce2626 100644 (file)
@@ -1073,13 +1073,26 @@ static int madera_pin_probe(struct platform_device *pdev)
                return ret;
        }
 
+       platform_set_drvdata(pdev, priv);
+
        dev_dbg(priv->dev, "pinctrl probed ok\n");
 
        return 0;
 }
 
+static int madera_pin_remove(struct platform_device *pdev)
+{
+       struct madera_pin_private *priv = platform_get_drvdata(pdev);
+
+       if (priv->madera->pdata.gpio_configs)
+               pinctrl_unregister_mappings(priv->madera->pdata.gpio_configs);
+
+       return 0;
+}
+
 static struct platform_driver madera_pin_driver = {
        .probe = madera_pin_probe,
+       .remove = madera_pin_remove,
        .driver = {
                .name = "madera-pinctrl",
        },
index 446d84f..f23c55e 100644 (file)
@@ -2021,7 +2021,6 @@ static int pinctrl_claim_hogs(struct pinctrl_dev *pctldev)
                return PTR_ERR(pctldev->p);
        }
 
-       kref_get(&pctldev->p->users);
        pctldev->hog_default =
                pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
        if (IS_ERR(pctldev->hog_default)) {
index 9357f7c..1ed20ac 100644 (file)
@@ -127,11 +127,12 @@ 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)
-                               return driver_deferred_probe_check_state_continue(p->dev);
-
-                       return driver_deferred_probe_check_state(p->dev);
+                       if (IS_ENABLED(CONFIG_MODULES) && !allow_default &&
+                           (ret == -ENODEV))
+                               ret = -EPROBE_DEFER;
+                       return ret;
                }
                /* If we're creating a hog we can use the passed pctldev */
                if (hog_pctldev && (np_pctldev == p->dev->of_node)) {
index 73bf1d9..23cf04b 100644 (file)
@@ -23,12 +23,12 @@ struct imx_sc_msg_req_pad_set {
        struct imx_sc_rpc_msg hdr;
        u32 val;
        u16 pad;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_req_pad_get {
        struct imx_sc_rpc_msg hdr;
        u16 pad;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_resp_pad_get {
        struct imx_sc_rpc_msg hdr;
index 1b6e864..2ac921c 100644 (file)
@@ -147,8 +147,8 @@ static const unsigned int sdio_d0_pins[]    = { GPIOX_0 };
 static const unsigned int sdio_d1_pins[]       = { GPIOX_1 };
 static const unsigned int sdio_d2_pins[]       = { GPIOX_2 };
 static const unsigned int sdio_d3_pins[]       = { GPIOX_3 };
-static const unsigned int sdio_cmd_pins[]      = { GPIOX_4 };
-static const unsigned int sdio_clk_pins[]      = { GPIOX_5 };
+static const unsigned int sdio_clk_pins[]      = { GPIOX_4 };
+static const unsigned int sdio_cmd_pins[]      = { GPIOX_5 };
 static const unsigned int sdio_irq_pins[]      = { GPIOX_7 };
 
 static const unsigned int nand_ce0_pins[]      = { BOOT_8 };
index a454f57..62c02b9 100644 (file)
@@ -451,7 +451,7 @@ static int pinctrl_falcon_probe(struct platform_device *pdev)
                falcon_info.clk[*bank] = clk_get(&ppdev->dev, NULL);
                if (IS_ERR(falcon_info.clk[*bank])) {
                        dev_err(&ppdev->dev, "failed to get clock\n");
-                       of_node_put(np)
+                       of_node_put(np);
                        return PTR_ERR(falcon_info.clk[*bank]);
                }
                falcon_info.membase[*bank] = devm_ioremap_resource(&pdev->dev,
index 9a8daa2..1a948c3 100644 (file)
@@ -1104,7 +1104,6 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
        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;
-       pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent;
        pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type;
        pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake;
        pctrl->irq_chip.irq_request_resources = msm_gpio_irq_reqres;
@@ -1118,7 +1117,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
                if (!chip->irq.parent_domain)
                        return -EPROBE_DEFER;
                chip->irq.child_to_parent_hwirq = msm_gpio_wakeirq;
-
+               pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent;
                /*
                 * Let's skip handling the GPIOs, if the parent irqchip
                 * is handling the direct connect IRQ of the GPIO.
index fba1d41..338a15d 100644 (file)
@@ -794,7 +794,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
        girq->fwnode = of_node_to_fwnode(pctrl->dev->of_node);
        girq->parent_domain = parent_domain;
        girq->child_to_parent_hwirq = pm8xxx_child_to_parent_hwirq;
-       girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_fourcell;
+       girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell;
        girq->child_offset_to_irq = pm8xxx_child_offset_to_irq;
        girq->child_irq_domain_ops.translate = pm8xxx_domain_translate;
 
index 2d5e043..af3b24f 100644 (file)
@@ -92,6 +92,7 @@ struct stm32_gpio_bank {
        u32 bank_nr;
        u32 bank_ioport_nr;
        u32 pin_backup[STM32_GPIO_PINS_PER_BANK];
+       u8 irq_type[STM32_GPIO_PINS_PER_BANK];
 };
 
 struct stm32_pinctrl {
@@ -303,6 +304,50 @@ static const struct gpio_chip stm32_gpio_template = {
        .get_direction          = stm32_gpio_get_direction,
 };
 
+static void stm32_gpio_irq_trigger(struct irq_data *d)
+{
+       struct stm32_gpio_bank *bank = d->domain->host_data;
+       int level;
+
+       /* If level interrupt type then retrig */
+       level = stm32_gpio_get(&bank->gpio_chip, d->hwirq);
+       if ((level == 0 && bank->irq_type[d->hwirq] == IRQ_TYPE_LEVEL_LOW) ||
+           (level == 1 && bank->irq_type[d->hwirq] == IRQ_TYPE_LEVEL_HIGH))
+               irq_chip_retrigger_hierarchy(d);
+}
+
+static void stm32_gpio_irq_eoi(struct irq_data *d)
+{
+       irq_chip_eoi_parent(d);
+       stm32_gpio_irq_trigger(d);
+};
+
+static int stm32_gpio_set_type(struct irq_data *d, unsigned int type)
+{
+       struct stm32_gpio_bank *bank = d->domain->host_data;
+       u32 parent_type;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+       case IRQ_TYPE_EDGE_FALLING:
+       case IRQ_TYPE_EDGE_BOTH:
+               parent_type = type;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               parent_type = IRQ_TYPE_EDGE_RISING;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               parent_type = IRQ_TYPE_EDGE_FALLING;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       bank->irq_type[d->hwirq] = type;
+
+       return irq_chip_set_type_parent(d, parent_type);
+};
+
 static int stm32_gpio_irq_request_resources(struct irq_data *irq_data)
 {
        struct stm32_gpio_bank *bank = irq_data->domain->host_data;
@@ -330,13 +375,19 @@ static void stm32_gpio_irq_release_resources(struct irq_data *irq_data)
        gpiochip_unlock_as_irq(&bank->gpio_chip, irq_data->hwirq);
 }
 
+static void stm32_gpio_irq_unmask(struct irq_data *d)
+{
+       irq_chip_unmask_parent(d);
+       stm32_gpio_irq_trigger(d);
+}
+
 static struct irq_chip stm32_gpio_irq_chip = {
        .name           = "stm32gpio",
-       .irq_eoi        = irq_chip_eoi_parent,
+       .irq_eoi        = stm32_gpio_irq_eoi,
        .irq_ack        = irq_chip_ack_parent,
        .irq_mask       = irq_chip_mask_parent,
-       .irq_unmask     = irq_chip_unmask_parent,
-       .irq_set_type   = irq_chip_set_type_parent,
+       .irq_unmask     = stm32_gpio_irq_unmask,
+       .irq_set_type   = stm32_gpio_set_type,
        .irq_set_wake   = irq_chip_set_wake_parent,
        .irq_request_resources = stm32_gpio_irq_request_resources,
        .irq_release_resources = stm32_gpio_irq_release_resources,
index e69682c..62f2761 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <linux/platform_data/wilco-ec.h>
 #include <linux/string.h>
-#include <linux/unaligned/le_memmove.h>
+#include <asm/unaligned.h>
 
 /* Operation code; what the EC should do with the property */
 enum ec_property_op {
index 587403c..cd9e275 100644 (file)
@@ -1252,6 +1252,7 @@ config INTEL_TURBO_MAX_3
 config TOUCHSCREEN_DMI
        bool "DMI based touchscreen configuration info"
        depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD
+       select EFI_EMBEDDED_FIRMWARE if EFI
        ---help---
          Certain ACPI based tablets with e.g. Silead or Chipone touchscreens
          do not have enough data in ACPI tables for the touchscreen driver to
index bfcc1d1..b531fe8 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/miscdevice.h>
 #include <linux/uaccess.h>
+#include <linux/fs.h>
 
 struct smo8800_device {
        u32 irq;                     /* acpi device irq */
index 2b1a073..8592720 100644 (file)
@@ -358,15 +358,13 @@ static struct notifier_block uncore_pm_nb = {
        .notifier_call = uncore_pm_notify,
 };
 
-#define ICPU(model)     { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
-
 static const struct x86_cpu_id intel_uncore_cpu_ids[] = {
-       ICPU(INTEL_FAM6_BROADWELL_G),
-       ICPU(INTEL_FAM6_BROADWELL_X),
-       ICPU(INTEL_FAM6_BROADWELL_D),
-       ICPU(INTEL_FAM6_SKYLAKE_X),
-       ICPU(INTEL_FAM6_ICELAKE_X),
-       ICPU(INTEL_FAM6_ICELAKE_D),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,   NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X,   NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D,   NULL),
        {}
 };
 
index f14e2c5..7b23efc 100644 (file)
@@ -148,8 +148,8 @@ static struct irq_chip int0002_cht_irqchip = {
 };
 
 static const struct x86_cpu_id int0002_cpu_ids[] = {
-       INTEL_CPU_FAM6(ATOM_SILVERMONT, int0002_byt_irqchip),   /* Valleyview, Bay Trail  */
-       INTEL_CPU_FAM6(ATOM_AIRMONT, int0002_cht_irqchip),      /* Braswell, Cherry Trail */
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,     &int0002_byt_irqchip),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        &int0002_cht_irqchip),
        {}
 };
 
index 6f43683..9c9f209 100644 (file)
@@ -113,8 +113,8 @@ static const struct mid_pb_ddata mrfld_ddata = {
 };
 
 static const struct x86_cpu_id mid_pb_cpu_ids[] = {
-       INTEL_CPU_FAM6(ATOM_SALTWELL_MID,       mfld_ddata),
-       INTEL_CPU_FAM6(ATOM_SILVERMONT_MID,     mrfld_ddata),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SALTWELL_MID,   &mfld_ddata),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &mrfld_ddata),
        {}
 };
 
index 144faa8..3df33ff 100644 (file)
@@ -871,18 +871,18 @@ static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
 #endif /* CONFIG_DEBUG_FS */
 
 static const struct x86_cpu_id intel_pmc_core_ids[] = {
-       INTEL_CPU_FAM6(SKYLAKE_L, spt_reg_map),
-       INTEL_CPU_FAM6(SKYLAKE, spt_reg_map),
-       INTEL_CPU_FAM6(KABYLAKE_L, spt_reg_map),
-       INTEL_CPU_FAM6(KABYLAKE, spt_reg_map),
-       INTEL_CPU_FAM6(CANNONLAKE_L, cnp_reg_map),
-       INTEL_CPU_FAM6(ICELAKE_L, icl_reg_map),
-       INTEL_CPU_FAM6(ICELAKE_NNPI, icl_reg_map),
-       INTEL_CPU_FAM6(COMETLAKE, cnp_reg_map),
-       INTEL_CPU_FAM6(COMETLAKE_L, cnp_reg_map),
-       INTEL_CPU_FAM6(TIGERLAKE_L, tgl_reg_map),
-       INTEL_CPU_FAM6(TIGERLAKE, tgl_reg_map),
-       INTEL_CPU_FAM6(ATOM_TREMONT, tgl_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,           &spt_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,             &spt_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,          &spt_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,            &spt_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L,        &cnp_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,           &icl_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI,        &icl_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE,           &cnp_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L,         &cnp_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,         &tgl_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE,           &tgl_reg_map),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT,        &tgl_reg_map),
        {}
 };
 
index e1266f5..7312818 100644 (file)
@@ -38,14 +38,14 @@ static struct platform_device pmc_core_device = {
  * other list may grow, but this list should not.
  */
 static const struct x86_cpu_id intel_pmc_core_platform_ids[] = {
-       INTEL_CPU_FAM6(SKYLAKE_L, pmc_core_device),
-       INTEL_CPU_FAM6(SKYLAKE, pmc_core_device),
-       INTEL_CPU_FAM6(KABYLAKE_L, pmc_core_device),
-       INTEL_CPU_FAM6(KABYLAKE, pmc_core_device),
-       INTEL_CPU_FAM6(CANNONLAKE_L, pmc_core_device),
-       INTEL_CPU_FAM6(ICELAKE_L, pmc_core_device),
-       INTEL_CPU_FAM6(COMETLAKE, pmc_core_device),
-       INTEL_CPU_FAM6(COMETLAKE_L, pmc_core_device),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,           &pmc_core_device),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,             &pmc_core_device),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,          &pmc_core_device),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,            &pmc_core_device),
+       X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L,        &pmc_core_device),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,           &pmc_core_device),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE,           &pmc_core_device),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L,         &pmc_core_device),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_platform_ids);
index 89b042a..1b6eab0 100644 (file)
@@ -160,10 +160,8 @@ static struct notifier_block isst_pm_nb = {
        .notifier_call = isst_pm_notify,
 };
 
-#define ICPU(model)     { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
-
 static const struct x86_cpu_id isst_if_cpu_ids[] = {
-       ICPU(INTEL_FAM6_SKYLAKE_X),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, isst_if_cpu_ids);
index 8e3fb55..8a53d3b 100644 (file)
@@ -308,11 +308,10 @@ static struct telemetry_debugfs_conf telem_apl_debugfs_conf = {
 };
 
 static const struct x86_cpu_id telemetry_debugfs_cpu_ids[] = {
-       INTEL_CPU_FAM6(ATOM_GOLDMONT, telem_apl_debugfs_conf),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, telem_apl_debugfs_conf),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,       &telem_apl_debugfs_conf),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS,  &telem_apl_debugfs_conf),
        {}
 };
-
 MODULE_DEVICE_TABLE(x86cpu, telemetry_debugfs_cpu_ids);
 
 static int telemetry_debugfs_check_evts(void)
index c4c742b..987a24e 100644 (file)
@@ -67,9 +67,6 @@
 #define TELEM_CLEAR_VERBOSITY_BITS(x)  ((x) &= ~(BIT(27) | BIT(28)))
 #define TELEM_SET_VERBOSITY_BITS(x, y) ((x) |= ((y) << 27))
 
-#define TELEM_CPU(model, data) \
-       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data }
-
 enum telemetry_action {
        TELEM_UPDATE = 0,
        TELEM_ADD,
@@ -183,8 +180,8 @@ static struct telemetry_plt_config telem_glk_config = {
 };
 
 static const struct x86_cpu_id telemetry_cpu_ids[] = {
-       TELEM_CPU(INTEL_FAM6_ATOM_GOLDMONT, telem_apl_config),
-       TELEM_CPU(INTEL_FAM6_ATOM_GOLDMONT_PLUS, telem_glk_config),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,       &telem_apl_config),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS,  &telem_glk_config),
        {}
 };
 
index 7b9cc84..892140b 100644 (file)
@@ -113,11 +113,9 @@ static int itmt_legacy_cpu_online(unsigned int cpu)
        return 0;
 }
 
-#define ICPU(model)     { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
-
 static const struct x86_cpu_id itmt_legacy_cpu_ids[] = {
-       ICPU(INTEL_FAM6_BROADWELL_X),
-       ICPU(INTEL_FAM6_SKYLAKE_X),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, NULL),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,   NULL),
        {}
 };
 
index 93177e6..6ec8923 100644 (file)
 #include <linux/acpi.h>
 #include <linux/device.h>
 #include <linux/dmi.h>
+#include <linux/efi_embedded_fw.h>
 #include <linux/i2c.h>
 #include <linux/notifier.h>
 #include <linux/property.h>
 #include <linux/string.h>
 
 struct ts_dmi_data {
+       /* The EFI embedded-fw code expects this to be the first member! */
+       struct efi_embedded_fw_desc embedded_fw;
        const char *acpi_name;
        const struct property_entry *properties;
 };
@@ -64,6 +67,15 @@ static const struct property_entry chuwi_hi8_pro_props[] = {
 };
 
 static const struct ts_dmi_data chuwi_hi8_pro_data = {
+       .embedded_fw = {
+               .name   = "silead/gsl3680-chuwi-hi8-pro.fw",
+               .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
+               .length = 39864,
+               .sha256 = { 0xc0, 0x88, 0xc5, 0xef, 0xd1, 0x70, 0x77, 0x59,
+                           0x4e, 0xe9, 0xc4, 0xd8, 0x2e, 0xcd, 0xbf, 0x95,
+                           0x32, 0xd9, 0x03, 0x28, 0x0d, 0x48, 0x9f, 0x92,
+                           0x35, 0x37, 0xf6, 0x8b, 0x2a, 0xe4, 0x73, 0xff },
+       },
        .acpi_name      = "MSSL1680:00",
        .properties     = chuwi_hi8_pro_props,
 };
@@ -120,6 +132,18 @@ static const struct ts_dmi_data chuwi_vi8_data = {
        .properties     = chuwi_vi8_props,
 };
 
+static const struct ts_dmi_data chuwi_vi8_plus_data = {
+       .embedded_fw = {
+               .name   = "chipone/icn8505-HAMP0002.fw",
+               .prefix = { 0xb0, 0x07, 0x00, 0x00, 0xe4, 0x07, 0x00, 0x00 },
+               .length = 35012,
+               .sha256 = { 0x93, 0xe5, 0x49, 0xe0, 0xb6, 0xa2, 0xb4, 0xb3,
+                           0x88, 0x96, 0x34, 0x97, 0x5e, 0xa8, 0x13, 0x78,
+                           0x72, 0x98, 0xb8, 0x29, 0xeb, 0x5c, 0xa7, 0xf1,
+                           0x25, 0x13, 0x43, 0xf4, 0x30, 0x7c, 0xfc, 0x7c },
+       },
+};
+
 static const struct property_entry chuwi_vi10_props[] = {
        PROPERTY_ENTRY_U32("touchscreen-min-x", 0),
        PROPERTY_ENTRY_U32("touchscreen-min-y", 4),
@@ -181,6 +205,15 @@ static const struct property_entry cube_iwork8_air_props[] = {
 };
 
 static const struct ts_dmi_data cube_iwork8_air_data = {
+       .embedded_fw = {
+               .name   = "silead/gsl3670-cube-iwork8-air.fw",
+               .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
+               .length = 38808,
+               .sha256 = { 0xff, 0x62, 0x2d, 0xd1, 0x8a, 0x78, 0x04, 0x7b,
+                           0x33, 0x06, 0xb0, 0x4f, 0x7f, 0x02, 0x08, 0x9c,
+                           0x96, 0xd4, 0x9f, 0x04, 0xe1, 0x47, 0x25, 0x25,
+                           0x60, 0x77, 0x41, 0x33, 0xeb, 0x12, 0x82, 0xfc },
+       },
        .acpi_name      = "MSSL1680:00",
        .properties     = cube_iwork8_air_props,
 };
@@ -387,6 +420,15 @@ static const struct property_entry onda_v80_plus_v3_props[] = {
 };
 
 static const struct ts_dmi_data onda_v80_plus_v3_data = {
+       .embedded_fw = {
+               .name   = "silead/gsl3676-onda-v80-plus-v3.fw",
+               .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
+               .length = 37224,
+               .sha256 = { 0x8f, 0xbd, 0x8f, 0x0c, 0x6b, 0xba, 0x5b, 0xf5,
+                           0xa3, 0xc7, 0xa3, 0xc0, 0x4f, 0xcd, 0xdf, 0x32,
+                           0xcc, 0xe4, 0x70, 0xd6, 0x46, 0x9c, 0xd7, 0xa7,
+                           0x4b, 0x82, 0x3f, 0xab, 0xc7, 0x90, 0xea, 0x23 },
+       },
        .acpi_name      = "MSSL1680:00",
        .properties     = onda_v80_plus_v3_props,
 };
@@ -449,6 +491,15 @@ static const struct property_entry pipo_w2s_props[] = {
 };
 
 static const struct ts_dmi_data pipo_w2s_data = {
+       .embedded_fw = {
+               .name   = "silead/gsl1680-pipo-w2s.fw",
+               .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 },
+               .length = 39072,
+               .sha256 = { 0xd0, 0x58, 0xc4, 0x7d, 0x55, 0x2d, 0x62, 0x18,
+                           0xd1, 0x6a, 0x71, 0x73, 0x0b, 0x3f, 0xbe, 0x60,
+                           0xbb, 0x45, 0x8c, 0x52, 0x27, 0xb7, 0x18, 0xf4,
+                           0x31, 0x00, 0x6a, 0x49, 0x76, 0xd8, 0x7c, 0xd3 },
+       },
        .acpi_name      = "MSSL1680:00",
        .properties     = pipo_w2s_props,
 };
@@ -641,7 +692,7 @@ static const struct ts_dmi_data trekstor_surftab_wintron70_data = {
 };
 
 /* NOTE: Please keep this table sorted alphabetically */
-static const struct dmi_system_id touchscreen_dmi_table[] = {
+const struct dmi_system_id touchscreen_dmi_table[] = {
        {
                /* Chuwi Hi8 */
                .driver_data = (void *)&chuwi_hi8_data,
@@ -704,6 +755,15 @@ static const struct dmi_system_id touchscreen_dmi_table[] = {
                },
        },
        {
+               /* Chuwi Vi8 Plus (CWI519) */
+               .driver_data = (void *)&chuwi_vi8_plus_data,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"),
+               },
+       },
+       {
                /* Chuwi Vi10 (CWI505) */
                .driver_data = (void *)&chuwi_vi10_data,
                .matches = {
@@ -1106,6 +1166,9 @@ static int __init ts_dmi_init(void)
                return 0; /* Not an error */
 
        ts_data = dmi_id->driver_data;
+       /* Some dmi table entries only provide an efi_embedded_fw_desc */
+       if (!ts_data->properties)
+               return 0;
 
        error = bus_register_notifier(&i2c_bus_type, &ts_dmi_notifier);
        if (error)
index dc2e966..941739d 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/uaccess.h>
 #include <linux/uuid.h>
 #include <linux/wmi.h>
+#include <linux/fs.h>
 #include <uapi/linux/wmi.h>
 
 ACPI_MODULE_NAME("wmi");
index cd12706..e9bbd3c 100644 (file)
@@ -67,7 +67,7 @@ struct idle_inject_device {
        struct hrtimer timer;
        unsigned int idle_duration_us;
        unsigned int run_duration_us;
-       unsigned long int cpumask[0];
+       unsigned long cpumask[];
 };
 
 static DEFINE_PER_CPU(struct idle_inject_thread, idle_inject_thread);
index 73257cf..eb32865 100644 (file)
@@ -951,52 +951,51 @@ static const struct rapl_defaults rapl_defaults_cht = {
 };
 
 static const struct x86_cpu_id rapl_ids[] __initconst = {
-       INTEL_CPU_FAM6(SANDYBRIDGE, rapl_defaults_core),
-       INTEL_CPU_FAM6(SANDYBRIDGE_X, rapl_defaults_core),
-
-       INTEL_CPU_FAM6(IVYBRIDGE, rapl_defaults_core),
-       INTEL_CPU_FAM6(IVYBRIDGE_X, rapl_defaults_core),
-
-       INTEL_CPU_FAM6(HASWELL, rapl_defaults_core),
-       INTEL_CPU_FAM6(HASWELL_L, rapl_defaults_core),
-       INTEL_CPU_FAM6(HASWELL_G, rapl_defaults_core),
-       INTEL_CPU_FAM6(HASWELL_X, rapl_defaults_hsw_server),
-
-       INTEL_CPU_FAM6(BROADWELL, rapl_defaults_core),
-       INTEL_CPU_FAM6(BROADWELL_G, rapl_defaults_core),
-       INTEL_CPU_FAM6(BROADWELL_D, rapl_defaults_core),
-       INTEL_CPU_FAM6(BROADWELL_X, rapl_defaults_hsw_server),
-
-       INTEL_CPU_FAM6(SKYLAKE, rapl_defaults_core),
-       INTEL_CPU_FAM6(SKYLAKE_L, rapl_defaults_core),
-       INTEL_CPU_FAM6(SKYLAKE_X, rapl_defaults_hsw_server),
-       INTEL_CPU_FAM6(KABYLAKE_L, rapl_defaults_core),
-       INTEL_CPU_FAM6(KABYLAKE, rapl_defaults_core),
-       INTEL_CPU_FAM6(CANNONLAKE_L, rapl_defaults_core),
-       INTEL_CPU_FAM6(ICELAKE_L, rapl_defaults_core),
-       INTEL_CPU_FAM6(ICELAKE, rapl_defaults_core),
-       INTEL_CPU_FAM6(ICELAKE_NNPI, rapl_defaults_core),
-       INTEL_CPU_FAM6(ICELAKE_X, rapl_defaults_hsw_server),
-       INTEL_CPU_FAM6(ICELAKE_D, rapl_defaults_hsw_server),
-       INTEL_CPU_FAM6(COMETLAKE_L, rapl_defaults_core),
-       INTEL_CPU_FAM6(COMETLAKE, rapl_defaults_core),
-       INTEL_CPU_FAM6(TIGERLAKE_L, rapl_defaults_core),
-
-       INTEL_CPU_FAM6(ATOM_SILVERMONT, rapl_defaults_byt),
-       INTEL_CPU_FAM6(ATOM_AIRMONT, rapl_defaults_cht),
-       INTEL_CPU_FAM6(ATOM_SILVERMONT_MID, rapl_defaults_tng),
-       INTEL_CPU_FAM6(ATOM_AIRMONT_MID, rapl_defaults_ann),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT, rapl_defaults_core),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, rapl_defaults_core),
-       INTEL_CPU_FAM6(ATOM_GOLDMONT_D, rapl_defaults_core),
-       INTEL_CPU_FAM6(ATOM_TREMONT_D, rapl_defaults_core),
-       INTEL_CPU_FAM6(ATOM_TREMONT_L, rapl_defaults_core),
-
-       INTEL_CPU_FAM6(XEON_PHI_KNL, rapl_defaults_hsw_server),
-       INTEL_CPU_FAM6(XEON_PHI_KNM, rapl_defaults_hsw_server),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE,         &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X,       &rapl_defaults_core),
+
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE,           &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X,         &rapl_defaults_core),
+
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL,             &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L,           &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G,           &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X,           &rapl_defaults_hsw_server),
+
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL,           &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G,         &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D,         &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X,         &rapl_defaults_hsw_server),
+
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE,             &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L,           &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X,           &rapl_defaults_hsw_server),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L,          &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE,            &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L,        &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L,           &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE,             &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI,        &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X,           &rapl_defaults_hsw_server),
+       X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D,           &rapl_defaults_hsw_server),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L,         &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE,           &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L,         &rapl_defaults_core),
+
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,     &rapl_defaults_byt),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,        &rapl_defaults_cht),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &rapl_defaults_tng),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_MID,    &rapl_defaults_ann),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT,       &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS,  &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D,     &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D,      &rapl_defaults_core),
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L,      &rapl_defaults_core),
+
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL,        &rapl_defaults_hsw_server),
+       X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM,        &rapl_defaults_hsw_server),
        {}
 };
-
 MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
 
 /* Read once for all raw primitive data for domains */
index 88a3c56..9e4378d 100644 (file)
@@ -183,7 +183,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
        if (timer_active)
                omap->pdata->stop(omap->dm_timer);
 
-       omap->pdata->set_load(omap->dm_timer, true, load_value);
+       omap->pdata->set_load(omap->dm_timer, load_value);
        omap->pdata->set_match(omap->dm_timer, true, match_value);
 
        dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n",
@@ -192,7 +192,8 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
        omap->pdata->set_pwm(omap->dm_timer,
                              pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED,
                              true,
-                             PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+                             PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE,
+                             true);
 
        /* If config was called while timer was running it must be reenabled. */
        if (timer_active)
@@ -222,7 +223,8 @@ static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
        omap->pdata->set_pwm(omap->dm_timer,
                              polarity == PWM_POLARITY_INVERSED,
                              true,
-                             PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE);
+                             PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE,
+                             true);
        mutex_unlock(&omap->mutex);
 
        return 0;
index 074a2ef..f4b72cb 100644 (file)
@@ -107,6 +107,7 @@ config REGULATOR_AD5398
 
 config REGULATOR_ANATOP
        tristate "Freescale i.MX on-chip ANATOP LDO regulators"
+       depends on ARCH_MXC || COMPILE_TEST
        depends on MFD_SYSCON
        help
          Say y here to support Freescale i.MX on-chip ANATOP LDOs
@@ -613,6 +614,16 @@ config REGULATOR_MCP16502
          through the regulator interface. In addition it enables
          suspend-to-ram/standby transition.
 
+config REGULATOR_MP5416
+       tristate "Monolithic MP5416 PMIC"
+       depends on I2C && OF
+       select REGMAP_I2C
+       help
+         Say y here to support the MP5416 PMIC. This will enable supports
+         the software controllable 4 buck and 4 LDO regulators.
+         Say M here if you want to include support for the regulator as a
+         module.
+
 config REGULATOR_MP8859
        tristate "MPS MP8859 regulator driver"
        depends on I2C
@@ -624,6 +635,13 @@ config REGULATOR_MP8859
          Say M here if you want to include support for the regulator as a
          module. The module will be named "mp8859".
 
+config REGULATOR_MP886X
+       tristate "MPS MP8869 regulator driver"
+       depends on I2C && (OF || COMPILE_TEST)
+       select REGMAP_I2C
+       help
+         This driver supports the MP8869 voltage regulator.
+
 config REGULATOR_MPQ7920
        tristate "Monolithic MPQ7920 PMIC"
        depends on I2C && OF
index c0d6b96..6610ee0 100644 (file)
@@ -78,7 +78,9 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o
+obj-$(CONFIG_REGULATOR_MP5416) += mp5416.o
 obj-$(CONFIG_REGULATOR_MP8859) += mp8859.o
+obj-$(CONFIG_REGULATOR_MP886X) += mp886x.o
 obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
 obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
index 754739d..ca92b3d 100644 (file)
@@ -305,9 +305,13 @@ static int anatop_regulator_probe(struct platform_device *pdev)
        /* register regulator */
        rdev = devm_regulator_register(dev, rdesc, &config);
        if (IS_ERR(rdev)) {
-               dev_err(dev, "failed to register %s\n",
-                       rdesc->name);
-               return PTR_ERR(rdev);
+               ret = PTR_ERR(rdev);
+               if (ret == -EPROBE_DEFER)
+                       dev_dbg(dev, "failed to register %s, deferring...\n",
+                               rdesc->name);
+               else
+                       dev_err(dev, "failed to register %s\n", rdesc->name);
+               return ret;
        }
 
        platform_set_drvdata(pdev, rdev);
index 16f0c85..1e6eb5b 100644 (file)
@@ -381,8 +381,7 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp)
                        mask = AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_RATE_MASK |
                               AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN_MASK;
                        enable = (ramp > 0) ?
-                                AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN :
-                                !AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN;
+                                AXP20X_DCDC2_LDO3_V_RAMP_DCDC2_EN : 0;
                        break;
                }
 
@@ -393,8 +392,7 @@ static int axp20x_set_ramp_delay(struct regulator_dev *rdev, int ramp)
                        mask = AXP20X_DCDC2_LDO3_V_RAMP_LDO3_RATE_MASK |
                               AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN_MASK;
                        enable = (ramp > 0) ?
-                                AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN :
-                                !AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN;
+                                AXP20X_DCDC2_LDO3_V_RAMP_LDO3_EN : 0;
                        break;
                }
 
index d015d99..c340505 100644 (file)
@@ -1849,7 +1849,6 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
 {
        struct regulator_dev *rdev;
        struct regulator *regulator;
-       const char *devname = dev ? dev_name(dev) : "deviceless";
        struct device_link *link;
        int ret;
 
@@ -1887,9 +1886,7 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
                         * enabled, even if it isn't hooked up, and just
                         * provide a dummy.
                         */
-                       dev_warn(dev,
-                                "%s supply %s not found, using dummy regulator\n",
-                                devname, id);
+                       dev_warn(dev, "supply %s not found, using dummy regulator\n", id);
                        rdev = dummy_regulator_rdev;
                        get_device(&rdev->dev);
                        break;
@@ -5757,6 +5754,10 @@ static DECLARE_DELAYED_WORK(regulator_init_complete_work,
 
 static int __init regulator_init_complete(void)
 {
+       int delay = driver_deferred_probe_timeout;
+
+       if (delay < 0)
+               delay = 0;
        /*
         * Since DT doesn't provide an idiomatic mechanism for
         * enabling full constraints and since it's much more natural
@@ -5767,18 +5768,17 @@ static int __init regulator_init_complete(void)
                has_full_constraints = true;
 
        /*
-        * We punt completion for an arbitrary amount of time since
-        * systems like distros will load many drivers from userspace
-        * so consumers might not always be ready yet, this is
-        * particularly an issue with laptops where this might bounce
-        * the display off then on.  Ideally we'd get a notification
-        * from userspace when this happens but we don't so just wait
-        * a bit and hope we waited long enough.  It'd be better if
-        * we'd only do this on systems that need it, and a kernel
-        * command line option might be useful.
+        * If driver_deferred_probe_timeout is set, we punt
+        * completion for that many seconds since systems like
+        * distros will load many drivers from userspace so consumers
+        * might not always be ready yet, this is particularly an
+        * issue with laptops where this might bounce the display off
+        * then on.  Ideally we'd get a notification from userspace
+        * when this happens but we don't so just wait a bit and hope
+        * we waited long enough.  It'd be better if we'd only do
+        * this on systems that need it.
         */
-       schedule_delayed_work(&regulator_init_complete_work,
-                             msecs_to_jiffies(30000));
+       schedule_delayed_work(&regulator_init_complete_work, delay * HZ);
 
        return 0;
 }
index d3ce027..d8112f5 100644 (file)
@@ -73,7 +73,7 @@ struct da9062_regulators {
        int                                     irq_ldo_lim;
        unsigned                                n_regulators;
        /* Array size to be defined during init. Keep at end. */
-       struct da9062_regulator                 regulator[0];
+       struct da9062_regulator                 regulator[];
 };
 
 /* Regulator operations */
index 2aceb3b..e1d6c8f 100644 (file)
@@ -66,7 +66,7 @@ struct da9063_regulator_data {
 };
 
 struct da9063_regulators_pdata {
-       unsigned                        n_regulators;
+       unsigned int                    n_regulators;
        struct da9063_regulator_data    *regulator_data;
 };
 
@@ -100,6 +100,7 @@ struct da9063_regulator_info {
        .desc.vsel_mask = DA9063_V##regl_name##_MASK, \
        .desc.linear_min_sel = DA9063_V##regl_name##_BIAS, \
        .sleep = BFIELD(DA9063_REG_V##regl_name##_A, DA9063_LDO_SL), \
+       .suspend = BFIELD(DA9063_REG_##regl_name##_CONT, DA9063_LDO_CONF), \
        .suspend_sleep = BFIELD(DA9063_REG_V##regl_name##_B, DA9063_LDO_SL), \
        .suspend_vsel_reg = DA9063_REG_V##regl_name##_B
 
@@ -124,6 +125,7 @@ struct da9063_regulator_info {
        .desc.vsel_mask = DA9063_VBUCK_MASK, \
        .desc.linear_min_sel = DA9063_VBUCK_BIAS, \
        .sleep = BFIELD(DA9063_REG_V##regl_name##_A, DA9063_BUCK_SL), \
+       .suspend = BFIELD(DA9063_REG_##regl_name##_CONT, DA9063_BUCK_CONF), \
        .suspend_sleep = BFIELD(DA9063_REG_V##regl_name##_B, DA9063_BUCK_SL), \
        .suspend_vsel_reg = DA9063_REG_V##regl_name##_B, \
        .mode = BFIELD(DA9063_REG_##regl_name##_CFG, DA9063_BUCK_MODE_MASK)
@@ -131,7 +133,7 @@ struct da9063_regulator_info {
 /* Defines asignment of regulators info table to chip model */
 struct da9063_dev_model {
        const struct da9063_regulator_info      *regulator_info;
-       unsigned                                n_regulators;
+       unsigned int                            n_regulators;
        enum da9063_type                        type;
 };
 
@@ -150,9 +152,9 @@ struct da9063_regulator {
 
 /* Encapsulates all information for the regulators driver */
 struct da9063_regulators {
-       unsigned                                n_regulators;
+       unsigned int                            n_regulators;
        /* Array size to be defined during init. Keep at end. */
-       struct da9063_regulator                 regulator[0];
+       struct da9063_regulator                 regulator[];
 };
 
 /* BUCK modes for DA9063 */
@@ -165,38 +167,46 @@ enum {
 
 /* Regulator operations */
 
-/* Current limits array (in uA) for BCORE1, BCORE2, BPRO.
-   Entry indexes corresponds to register values. */
+/*
+ * Current limits array (in uA) for BCORE1, BCORE2, BPRO.
+ * Entry indexes corresponds to register values.
+ */
 static const unsigned int da9063_buck_a_limits[] = {
         500000,  600000,  700000,  800000,  900000, 1000000, 1100000, 1200000,
        1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000
 };
 
-/* Current limits array (in uA) for BMEM, BIO, BPERI.
-   Entry indexes corresponds to register values. */
+/*
+ * Current limits array (in uA) for BMEM, BIO, BPERI.
+ * Entry indexes corresponds to register values.
+ */
 static const unsigned int da9063_buck_b_limits[] = {
        1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000,
        2300000, 2400000, 2500000, 2600000, 2700000, 2800000, 2900000, 3000000
 };
 
-/* Current limits array (in uA) for merged BCORE1 and BCORE2.
-   Entry indexes corresponds to register values. */
+/*
+ * Current limits array (in uA) for merged BCORE1 and BCORE2.
+ * Entry indexes corresponds to register values.
+ */
 static const unsigned int da9063_bcores_merged_limits[] = {
        1000000, 1200000, 1400000, 1600000, 1800000, 2000000, 2200000, 2400000,
        2600000, 2800000, 3000000, 3200000, 3400000, 3600000, 3800000, 4000000
 };
 
-/* Current limits array (in uA) for merged BMEM and BIO.
-   Entry indexes corresponds to register values. */
+/*
+ * Current limits array (in uA) for merged BMEM and BIO.
+ * Entry indexes corresponds to register values.
+ */
 static const unsigned int da9063_bmem_bio_merged_limits[] = {
        3000000, 3200000, 3400000, 3600000, 3800000, 4000000, 4200000, 4400000,
        4600000, 4800000, 5000000, 5200000, 5400000, 5600000, 5800000, 6000000
 };
 
-static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned mode)
+static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
 {
        struct da9063_regulator *regl = rdev_get_drvdata(rdev);
-       unsigned val;
+       unsigned int val;
 
        switch (mode) {
        case REGULATOR_MODE_FAST:
@@ -221,10 +231,9 @@ static int da9063_buck_set_mode(struct regulator_dev *rdev, unsigned mode)
  * There are 3 modes to map to: FAST, NORMAL, and STANDBY.
  */
 
-static unsigned da9063_buck_get_mode(struct regulator_dev *rdev)
+static unsigned int da9063_buck_get_mode(struct regulator_dev *rdev)
 {
        struct da9063_regulator *regl = rdev_get_drvdata(rdev);
-       struct regmap_field *field;
        unsigned int val;
        int ret;
 
@@ -245,18 +254,7 @@ static unsigned da9063_buck_get_mode(struct regulator_dev *rdev)
                return REGULATOR_MODE_NORMAL;
        }
 
-       /* Detect current regulator state */
-       ret = regmap_field_read(regl->suspend, &val);
-       if (ret < 0)
-               return 0;
-
-       /* Read regulator mode from proper register, depending on state */
-       if (val)
-               field = regl->suspend_sleep;
-       else
-               field = regl->sleep;
-
-       ret = regmap_field_read(field, &val);
+       ret = regmap_field_read(regl->sleep, &val);
        if (ret < 0)
                return 0;
 
@@ -271,10 +269,10 @@ static unsigned da9063_buck_get_mode(struct regulator_dev *rdev)
  * There are 2 modes to map to: NORMAL and STANDBY (sleep) for each state.
  */
 
-static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned mode)
+static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned int mode)
 {
        struct da9063_regulator *regl = rdev_get_drvdata(rdev);
-       unsigned val;
+       unsigned int val;
 
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
@@ -290,24 +288,12 @@ static int da9063_ldo_set_mode(struct regulator_dev *rdev, unsigned mode)
        return regmap_field_write(regl->sleep, val);
 }
 
-static unsigned da9063_ldo_get_mode(struct regulator_dev *rdev)
+static unsigned int da9063_ldo_get_mode(struct regulator_dev *rdev)
 {
        struct da9063_regulator *regl = rdev_get_drvdata(rdev);
-       struct regmap_field *field;
        int ret, val;
 
-       /* Detect current regulator state */
-       ret = regmap_field_read(regl->suspend, &val);
-       if (ret < 0)
-               return 0;
-
-       /* Read regulator mode from proper register, depending on state */
-       if (val)
-               field = regl->suspend_sleep;
-       else
-               field = regl->sleep;
-
-       ret = regmap_field_read(field, &val);
+       ret = regmap_field_read(regl->sleep, &val);
        if (ret < 0)
                return 0;
 
@@ -383,7 +369,8 @@ static int da9063_suspend_disable(struct regulator_dev *rdev)
        return regmap_field_write(regl->suspend, 0);
 }
 
-static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev, unsigned mode)
+static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev,
+                               unsigned int mode)
 {
        struct da9063_regulator *regl = rdev_get_drvdata(rdev);
        int val;
@@ -405,10 +392,11 @@ static int da9063_buck_set_suspend_mode(struct regulator_dev *rdev, unsigned mod
        return regmap_field_write(regl->mode, val);
 }
 
-static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, unsigned mode)
+static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev,
+                               unsigned int mode)
 {
        struct da9063_regulator *regl = rdev_get_drvdata(rdev);
-       unsigned val;
+       unsigned int val;
 
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
@@ -465,42 +453,36 @@ static const struct da9063_regulator_info da9063_regulator_info[] = {
                            da9063_buck_a_limits,
                            DA9063_REG_BUCK_ILIM_C, DA9063_BCORE1_ILIM_MASK),
                DA9063_BUCK_COMMON_FIELDS(BCORE1),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE1_SEL),
        },
        {
                DA9063_BUCK(DA9063, BCORE2, 300, 10, 1570,
                            da9063_buck_a_limits,
                            DA9063_REG_BUCK_ILIM_C, DA9063_BCORE2_ILIM_MASK),
                DA9063_BUCK_COMMON_FIELDS(BCORE2),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE2_SEL),
        },
        {
                DA9063_BUCK(DA9063, BPRO, 530, 10, 1800,
                            da9063_buck_a_limits,
                            DA9063_REG_BUCK_ILIM_B, DA9063_BPRO_ILIM_MASK),
                DA9063_BUCK_COMMON_FIELDS(BPRO),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBPRO_SEL),
        },
        {
                DA9063_BUCK(DA9063, BMEM, 800, 20, 3340,
                            da9063_buck_b_limits,
                            DA9063_REG_BUCK_ILIM_A, DA9063_BMEM_ILIM_MASK),
                DA9063_BUCK_COMMON_FIELDS(BMEM),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBMEM_SEL),
        },
        {
                DA9063_BUCK(DA9063, BIO, 800, 20, 3340,
                            da9063_buck_b_limits,
                            DA9063_REG_BUCK_ILIM_A, DA9063_BIO_ILIM_MASK),
                DA9063_BUCK_COMMON_FIELDS(BIO),
-               .suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VBIO_SEL),
        },
        {
                DA9063_BUCK(DA9063, BPERI, 800, 20, 3340,
                            da9063_buck_b_limits,
                            DA9063_REG_BUCK_ILIM_B, DA9063_BPERI_ILIM_MASK),
                DA9063_BUCK_COMMON_FIELDS(BPERI),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBPERI_SEL),
        },
        {
                DA9063_BUCK(DA9063, BCORES_MERGED, 300, 10, 1570,
@@ -508,7 +490,6 @@ static const struct da9063_regulator_info da9063_regulator_info[] = {
                            DA9063_REG_BUCK_ILIM_C, DA9063_BCORE1_ILIM_MASK),
                /* BCORES_MERGED uses the same register fields as BCORE1 */
                DA9063_BUCK_COMMON_FIELDS(BCORE1),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBCORE1_SEL),
        },
        {
                DA9063_BUCK(DA9063, BMEM_BIO_MERGED, 800, 20, 3340,
@@ -516,21 +497,17 @@ static const struct da9063_regulator_info da9063_regulator_info[] = {
                            DA9063_REG_BUCK_ILIM_A, DA9063_BMEM_ILIM_MASK),
                /* BMEM_BIO_MERGED uses the same register fields as BMEM */
                DA9063_BUCK_COMMON_FIELDS(BMEM),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VBMEM_SEL),
        },
        {
                DA9063_LDO(DA9063, LDO3, 900, 20, 3440),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO3_SEL),
                .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO3_LIM),
        },
        {
                DA9063_LDO(DA9063, LDO7, 900, 50, 3600),
-               .suspend = BFIELD(DA9063_REG_LDO7_CONT, DA9063_VLDO7_SEL),
                .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO7_LIM),
        },
        {
                DA9063_LDO(DA9063, LDO8, 900, 50, 3600),
-               .suspend = BFIELD(DA9063_REG_LDO8_CONT, DA9063_VLDO8_SEL),
                .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO8_LIM),
        },
        {
@@ -539,36 +516,29 @@ static const struct da9063_regulator_info da9063_regulator_info[] = {
        },
        {
                DA9063_LDO(DA9063, LDO11, 900, 50, 3600),
-               .suspend = BFIELD(DA9063_REG_LDO11_CONT, DA9063_VLDO11_SEL),
                .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO11_LIM),
        },
 
        /* The following LDOs are present only on DA9063, not on DA9063L */
        {
                DA9063_LDO(DA9063, LDO1, 600, 20, 1860),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO1_SEL),
        },
        {
                DA9063_LDO(DA9063, LDO2, 600, 20, 1860),
-               .suspend = BFIELD(DA9063_REG_DVC_1, DA9063_VLDO2_SEL),
        },
        {
                DA9063_LDO(DA9063, LDO4, 900, 20, 3440),
-               .suspend = BFIELD(DA9063_REG_DVC_2, DA9063_VLDO4_SEL),
                .oc_event = BFIELD(DA9063_REG_STATUS_D, DA9063_LDO4_LIM),
        },
        {
                DA9063_LDO(DA9063, LDO5, 900, 50, 3600),
-               .suspend = BFIELD(DA9063_REG_LDO5_CONT, DA9063_VLDO5_SEL),
        },
        {
                DA9063_LDO(DA9063, LDO6, 900, 50, 3600),
-               .suspend = BFIELD(DA9063_REG_LDO6_CONT, DA9063_VLDO6_SEL),
        },
 
        {
                DA9063_LDO(DA9063, LDO10, 900, 50, 3600),
-               .suspend = BFIELD(DA9063_REG_LDO10_CONT, DA9063_VLDO10_SEL),
        },
 };
 
@@ -593,7 +563,7 @@ static irqreturn_t da9063_ldo_lim_event(int irq, void *data)
        struct da9063_regulators *regulators = data;
        struct da9063 *hw = regulators->regulator[0].hw;
        struct da9063_regulator *regl;
-       int bits, i , ret;
+       int bits, i, ret;
 
        ret = regmap_read(hw->regmap, DA9063_REG_STATUS_D, &bits);
        if (ret < 0)
@@ -605,10 +575,10 @@ static irqreturn_t da9063_ldo_lim_event(int irq, void *data)
                        continue;
 
                if (BIT(regl->info->oc_event.lsb) & bits) {
-                       regulator_lock(regl->rdev);
+                       regulator_lock(regl->rdev);
                        regulator_notifier_call_chain(regl->rdev,
                                        REGULATOR_EVENT_OVER_CURRENT, NULL);
-                       regulator_unlock(regl->rdev);
+                       regulator_unlock(regl->rdev);
                }
        }
 
@@ -833,7 +803,7 @@ static int da9063_regulator_probe(struct platform_device *pdev)
 
                if (regl->info->suspend_sleep.reg) {
                        regl->suspend_sleep = devm_regmap_field_alloc(&pdev->dev,
-                                       da9063->regmap, regl->info->suspend_sleep);
+                               da9063->regmap, regl->info->suspend_sleep);
                        if (IS_ERR(regl->suspend_sleep))
                                return PTR_ERR(regl->suspend_sleep);
                }
@@ -867,12 +837,10 @@ static int da9063_regulator_probe(struct platform_device *pdev)
                                NULL, da9063_ldo_lim_event,
                                IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                "LDO_LIM", regulators);
-       if (ret) {
+       if (ret)
                dev_err(&pdev->dev, "Failed to request LDO_LIM IRQ.\n");
-               return ret;
-       }
 
-       return 0;
+       return ret;
 }
 
 static struct platform_driver da9063_regulator_driver = {
diff --git a/drivers/regulator/mp5416.c b/drivers/regulator/mp5416.c
new file mode 100644 (file)
index 0000000..67ce1b5
--- /dev/null
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// mp5416.c  - regulator driver for mps mp5416
+//
+// Copyright 2020 Monolithic Power Systems, Inc
+//
+// Author: Saravanan Sekar <sravanhome@gmail.com>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/i2c.h>
+
+#define MP5416_REG_CTL0                        0x00
+#define MP5416_REG_CTL1                        0x01
+#define MP5416_REG_CTL2                        0x02
+#define MP5416_REG_ILIM                        0x03
+#define MP5416_REG_BUCK1               0x04
+#define MP5416_REG_BUCK2               0x05
+#define MP5416_REG_BUCK3               0x06
+#define MP5416_REG_BUCK4               0x07
+#define MP5416_REG_LDO1                        0x08
+#define MP5416_REG_LDO2                        0x09
+#define MP5416_REG_LDO3                        0x0a
+#define MP5416_REG_LDO4                        0x0b
+
+#define MP5416_REGULATOR_EN            BIT(7)
+#define MP5416_MASK_VSET               0x7f
+#define MP5416_MASK_BUCK1_ILIM         0xc0
+#define MP5416_MASK_BUCK2_ILIM         0x0c
+#define MP5416_MASK_BUCK3_ILIM         0x30
+#define MP5416_MASK_BUCK4_ILIM         0x03
+#define MP5416_MASK_DVS_SLEWRATE       0xc0
+
+/* values in uV */
+#define MP5416_VOLT1_MIN               600000
+#define MP5416_VOLT1_MAX               2187500
+#define MP5416_VOLT1_STEP              12500
+#define MP5416_VOLT2_MIN               800000
+#define MP5416_VOLT2_MAX               3975000
+#define MP5416_VOLT2_STEP              25000
+
+#define MP5416_VOLT1_RANGE \
+       ((MP5416_VOLT1_MAX - MP5416_VOLT1_MIN)/MP5416_VOLT1_STEP + 1)
+#define MP5416_VOLT2_RANGE \
+       ((MP5416_VOLT2_MAX - MP5416_VOLT2_MIN)/MP5416_VOLT2_STEP + 1)
+
+#define MP5416BUCK(_name, _id, _ilim, _dreg, _dval, _vsel)             \
+       [MP5416_BUCK ## _id] = {                                        \
+               .id = MP5416_BUCK ## _id,                               \
+               .name = _name,                                          \
+               .of_match = _name,                                      \
+               .regulators_node = "regulators",                        \
+               .ops = &mp5416_buck_ops,                                \
+               .min_uV = MP5416_VOLT ##_vsel## _MIN,                   \
+               .uV_step = MP5416_VOLT ##_vsel## _STEP,                 \
+               .n_voltages = MP5416_VOLT ##_vsel## _RANGE,             \
+               .curr_table = _ilim,                                    \
+               .n_current_limits = ARRAY_SIZE(_ilim),                  \
+               .csel_reg = MP5416_REG_ILIM,                            \
+               .csel_mask = MP5416_MASK_BUCK ## _id ##_ILIM,           \
+               .vsel_reg = MP5416_REG_BUCK ## _id,                     \
+               .vsel_mask = MP5416_MASK_VSET,                          \
+               .enable_reg = MP5416_REG_BUCK ## _id,                   \
+               .enable_mask = MP5416_REGULATOR_EN,                     \
+               .active_discharge_on    = _dval,                        \
+               .active_discharge_reg   = _dreg,                        \
+               .active_discharge_mask  = _dval,                        \
+               .owner                  = THIS_MODULE,                  \
+       }
+
+#define MP5416LDO(_name, _id, _dval)                                   \
+       [MP5416_LDO ## _id] = {                                         \
+               .id = MP5416_LDO ## _id,                                \
+               .name = _name,                                          \
+               .of_match = _name,                                      \
+               .regulators_node = "regulators",                        \
+               .ops = &mp5416_ldo_ops,                                 \
+               .min_uV = MP5416_VOLT2_MIN,                             \
+               .uV_step = MP5416_VOLT2_STEP,                           \
+               .n_voltages = MP5416_VOLT2_RANGE,                       \
+               .vsel_reg = MP5416_REG_LDO ##_id,                       \
+               .vsel_mask = MP5416_MASK_VSET,                          \
+               .enable_reg = MP5416_REG_LDO ##_id,                     \
+               .enable_mask = MP5416_REGULATOR_EN,                     \
+               .active_discharge_on    = _dval,                        \
+               .active_discharge_reg   = MP5416_REG_CTL2,              \
+               .active_discharge_mask  = _dval,                        \
+               .owner                  = THIS_MODULE,                  \
+       }
+
+enum mp5416_regulators {
+       MP5416_BUCK1,
+       MP5416_BUCK2,
+       MP5416_BUCK3,
+       MP5416_BUCK4,
+       MP5416_LDO1,
+       MP5416_LDO2,
+       MP5416_LDO3,
+       MP5416_LDO4,
+       MP5416_MAX_REGULATORS,
+};
+
+static const struct regmap_config mp5416_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0x0d,
+};
+
+/* Current limits array (in uA)
+ * ILIM1 & ILIM3
+ */
+static const unsigned int mp5416_I_limits1[] = {
+       3800000, 4600000, 5600000, 6800000
+};
+
+/* ILIM2 & ILIM4 */
+static const unsigned int mp5416_I_limits2[] = {
+       2200000, 3200000, 4200000, 5200000
+};
+
+static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay);
+
+static const struct regulator_ops mp5416_ldo_ops = {
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .is_enabled             = regulator_is_enabled_regmap,
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .set_active_discharge   = regulator_set_active_discharge_regmap,
+};
+
+static const struct regulator_ops mp5416_buck_ops = {
+       .enable                 = regulator_enable_regmap,
+       .disable                = regulator_disable_regmap,
+       .is_enabled             = regulator_is_enabled_regmap,
+       .list_voltage           = regulator_list_voltage_linear,
+       .map_voltage            = regulator_map_voltage_linear,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
+       .set_active_discharge   = regulator_set_active_discharge_regmap,
+       .get_current_limit      = regulator_get_current_limit_regmap,
+       .set_current_limit      = regulator_set_current_limit_regmap,
+       .set_ramp_delay         = mp5416_set_ramp_delay,
+};
+
+static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = {
+       MP5416BUCK("buck1", 1, mp5416_I_limits1, MP5416_REG_CTL1, BIT(0), 1),
+       MP5416BUCK("buck2", 2, mp5416_I_limits2, MP5416_REG_CTL1, BIT(1), 2),
+       MP5416BUCK("buck3", 3, mp5416_I_limits1, MP5416_REG_CTL1, BIT(2), 1),
+       MP5416BUCK("buck4", 4, mp5416_I_limits2, MP5416_REG_CTL2, BIT(5), 2),
+       MP5416LDO("ldo1", 1, BIT(4)),
+       MP5416LDO("ldo2", 2, BIT(3)),
+       MP5416LDO("ldo3", 3, BIT(2)),
+       MP5416LDO("ldo4", 4, BIT(1)),
+};
+
+/*
+ * DVS ramp rate BUCK1 to BUCK4
+ * 00: 32mV/us
+ * 01: 16mV/us
+ * 10: 8mV/us
+ * 11: 4mV/us
+ */
+static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
+{
+       unsigned int ramp_val;
+
+       if (ramp_delay > 32000 || ramp_delay < 0)
+               return -EINVAL;
+
+       if (ramp_delay <= 4000)
+               ramp_val = 3;
+       else if (ramp_delay <= 8000)
+               ramp_val = 2;
+       else if (ramp_delay <= 16000)
+               ramp_val = 1;
+       else
+               ramp_val = 0;
+
+       return regmap_update_bits(rdev->regmap, MP5416_REG_CTL2,
+                                 MP5416_MASK_DVS_SLEWRATE, ramp_val << 6);
+}
+
+static int mp5416_i2c_probe(struct i2c_client *client)
+{
+       struct device *dev = &client->dev;
+       struct regulator_config config = { NULL, };
+       struct regulator_dev *rdev;
+       struct regmap *regmap;
+       int i;
+
+       regmap = devm_regmap_init_i2c(client, &mp5416_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to allocate regmap!\n");
+               return PTR_ERR(regmap);
+       }
+
+       config.dev = dev;
+       config.regmap = regmap;
+
+       for (i = 0; i < MP5416_MAX_REGULATORS; i++) {
+               rdev = devm_regulator_register(dev,
+                                              &mp5416_regulators_desc[i],
+                                              &config);
+               if (IS_ERR(rdev)) {
+                       dev_err(dev, "Failed to register regulator!\n");
+                       return PTR_ERR(rdev);
+               }
+       }
+
+       return 0;
+}
+
+static const struct of_device_id mp5416_of_match[] = {
+       { .compatible = "mps,mp5416" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, mp5416_of_match);
+
+static const struct i2c_device_id mp5416_id[] = {
+       { "mp5416", },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, mp5416_id);
+
+static struct i2c_driver mp5416_regulator_driver = {
+       .driver = {
+               .name = "mp5416",
+               .of_match_table = of_match_ptr(mp5416_of_match),
+       },
+       .probe_new = mp5416_i2c_probe,
+       .id_table = mp5416_id,
+};
+module_i2c_driver(mp5416_regulator_driver);
+
+MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
+MODULE_DESCRIPTION("MP5416 PMIC regulator driver");
+MODULE_LICENSE("GPL");
index 1d26b50..6ed9876 100644 (file)
@@ -95,6 +95,7 @@ static const struct regulator_desc mp8859_regulators[] = {
                .id = 0,
                .type = REGULATOR_VOLTAGE,
                .name = "mp8859_dcdc",
+               .supply_name = "vin",
                .of_match = of_match_ptr("mp8859_dcdc"),
                .n_voltages = VOL_MAX_IDX + 1,
                .linear_ranges = mp8859_dcdc_ranges,
diff --git a/drivers/regulator/mp886x.c b/drivers/regulator/mp886x.c
new file mode 100644 (file)
index 0000000..1786f71
--- /dev/null
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// MP8867/MP8869 regulator driver
+//
+// Copyright (C) 2020 Synaptics Incorporated
+//
+// Author: Jisheng Zhang <jszhang@kernel.org>
+
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MP886X_VSEL            0x00
+#define  MP886X_V_BOOT         (1 << 7)
+#define MP886X_SYSCNTLREG1     0x01
+#define  MP886X_MODE           (1 << 0)
+#define  MP886X_GO             (1 << 6)
+#define  MP886X_EN             (1 << 7)
+
+struct mp886x_device_info {
+       struct device *dev;
+       struct regulator_desc desc;
+       struct regulator_init_data *regulator;
+       struct gpio_desc *en_gpio;
+       u32 r[2];
+       unsigned int sel;
+};
+
+static int mp886x_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+       switch (mode) {
+       case REGULATOR_MODE_FAST:
+               regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
+                                  MP886X_MODE, MP886X_MODE);
+               break;
+       case REGULATOR_MODE_NORMAL:
+               regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
+                                  MP886X_MODE, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static unsigned int mp886x_get_mode(struct regulator_dev *rdev)
+{
+       u32 val;
+       int ret;
+
+       ret = regmap_read(rdev->regmap, MP886X_SYSCNTLREG1, &val);
+       if (ret < 0)
+               return ret;
+       if (val & MP886X_MODE)
+               return REGULATOR_MODE_FAST;
+       else
+               return REGULATOR_MODE_NORMAL;
+}
+
+static int mp8869_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+       int ret;
+
+       ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
+                                MP886X_GO, MP886X_GO);
+       if (ret < 0)
+               return ret;
+
+       sel <<= ffs(rdev->desc->vsel_mask) - 1;
+       return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+                                 MP886X_V_BOOT | rdev->desc->vsel_mask, sel);
+}
+
+static inline unsigned int mp8869_scale(unsigned int uv, u32 r1, u32 r2)
+{
+       u32 tmp = uv * r1 / r2;
+
+       return uv + tmp;
+}
+
+static int mp8869_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct mp886x_device_info *di = rdev_get_drvdata(rdev);
+       int ret, uv;
+       unsigned int val;
+       bool fbloop;
+
+       ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+       if (ret)
+               return ret;
+
+       fbloop = val & MP886X_V_BOOT;
+       if (fbloop) {
+               uv = rdev->desc->min_uV;
+               uv = mp8869_scale(uv, di->r[0], di->r[1]);
+               return regulator_map_voltage_linear(rdev, uv, uv);
+       }
+
+       val &= rdev->desc->vsel_mask;
+       val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+       return val;
+}
+
+static const struct regulator_ops mp8869_regulator_ops = {
+       .set_voltage_sel = mp8869_set_voltage_sel,
+       .get_voltage_sel = mp8869_get_voltage_sel,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .map_voltage = regulator_map_voltage_linear,
+       .list_voltage = regulator_list_voltage_linear,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_mode = mp886x_set_mode,
+       .get_mode = mp886x_get_mode,
+};
+
+static int mp8867_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
+{
+       struct mp886x_device_info *di = rdev_get_drvdata(rdev);
+       int ret, delta;
+
+       ret = mp8869_set_voltage_sel(rdev, sel);
+       if (ret < 0)
+               return ret;
+
+       delta = di->sel - sel;
+       if (abs(delta) <= 5)
+               ret = regmap_update_bits(rdev->regmap, MP886X_SYSCNTLREG1,
+                                        MP886X_GO, 0);
+       di->sel = sel;
+
+       return ret;
+}
+
+static int mp8867_get_voltage_sel(struct regulator_dev *rdev)
+{
+       struct mp886x_device_info *di = rdev_get_drvdata(rdev);
+       int ret, uv;
+       unsigned int val;
+       bool fbloop;
+
+       ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val);
+       if (ret)
+               return ret;
+
+       fbloop = val & MP886X_V_BOOT;
+
+       val &= rdev->desc->vsel_mask;
+       val >>= ffs(rdev->desc->vsel_mask) - 1;
+
+       if (fbloop) {
+               uv = regulator_list_voltage_linear(rdev, val);
+               uv = mp8869_scale(uv, di->r[0], di->r[1]);
+               return regulator_map_voltage_linear(rdev, uv, uv);
+       }
+
+       return val;
+}
+
+static const struct regulator_ops mp8867_regulator_ops = {
+       .set_voltage_sel = mp8867_set_voltage_sel,
+       .get_voltage_sel = mp8867_get_voltage_sel,
+       .set_voltage_time_sel = regulator_set_voltage_time_sel,
+       .map_voltage = regulator_map_voltage_linear,
+       .list_voltage = regulator_list_voltage_linear,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+       .set_mode = mp886x_set_mode,
+       .get_mode = mp886x_get_mode,
+};
+
+static int mp886x_regulator_register(struct mp886x_device_info *di,
+                                    struct regulator_config *config)
+{
+       struct regulator_desc *rdesc = &di->desc;
+       struct regulator_dev *rdev;
+
+       rdesc->name = "mp886x-reg";
+       rdesc->supply_name = "vin";
+       rdesc->ops = of_device_get_match_data(di->dev);
+       rdesc->type = REGULATOR_VOLTAGE;
+       rdesc->n_voltages = 128;
+       rdesc->enable_reg = MP886X_SYSCNTLREG1;
+       rdesc->enable_mask = MP886X_EN;
+       rdesc->min_uV = 600000;
+       rdesc->uV_step = 10000;
+       rdesc->vsel_reg = MP886X_VSEL;
+       rdesc->vsel_mask = 0x3f;
+       rdesc->owner = THIS_MODULE;
+
+       rdev = devm_regulator_register(di->dev, &di->desc, config);
+       if (IS_ERR(rdev))
+               return PTR_ERR(rdev);
+       di->sel = rdesc->ops->get_voltage_sel(rdev);
+       return 0;
+}
+
+static const struct regmap_config mp886x_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int mp886x_i2c_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       struct device *dev = &client->dev;
+       struct device_node *np = dev->of_node;
+       struct mp886x_device_info *di;
+       struct regulator_config config = { };
+       struct regmap *regmap;
+       int ret;
+
+       di = devm_kzalloc(dev, sizeof(struct mp886x_device_info), GFP_KERNEL);
+       if (!di)
+               return -ENOMEM;
+
+       di->regulator = of_get_regulator_init_data(dev, np, &di->desc);
+       if (!di->regulator) {
+               dev_err(dev, "Platform data not found!\n");
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_array(np, "mps,fb-voltage-divider",
+                                        di->r, 2);
+       if (ret)
+               return ret;
+
+       di->en_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
+       if (IS_ERR(di->en_gpio))
+               return PTR_ERR(di->en_gpio);
+
+       di->dev = dev;
+
+       regmap = devm_regmap_init_i2c(client, &mp886x_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(dev, "Failed to allocate regmap!\n");
+               return PTR_ERR(regmap);
+       }
+       i2c_set_clientdata(client, di);
+
+       config.dev = di->dev;
+       config.init_data = di->regulator;
+       config.regmap = regmap;
+       config.driver_data = di;
+       config.of_node = np;
+
+       ret = mp886x_regulator_register(di, &config);
+       if (ret < 0)
+               dev_err(dev, "Failed to register regulator!\n");
+       return ret;
+}
+
+static const struct of_device_id mp886x_dt_ids[] = {
+       {
+               .compatible = "mps,mp8867",
+               .data = &mp8867_regulator_ops
+       },
+       {
+               .compatible = "mps,mp8869",
+               .data = &mp8869_regulator_ops
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mp886x_dt_ids);
+
+static const struct i2c_device_id mp886x_id[] = {
+       { "mp886x", },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, mp886x_id);
+
+static struct i2c_driver mp886x_regulator_driver = {
+       .driver = {
+               .name = "mp886x-regulator",
+               .of_match_table = of_match_ptr(mp886x_dt_ids),
+       },
+       .probe = mp886x_i2c_probe,
+       .id_table = mp886x_id,
+};
+module_i2c_driver(mp886x_regulator_driver);
+
+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
+MODULE_DESCRIPTION("MP886x regulator driver");
+MODULE_LICENSE("GPL v2");
index e74e111..638329b 100644 (file)
@@ -354,7 +354,11 @@ static int pwm_regulator_probe(struct platform_device *pdev)
        drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
        if (IS_ERR(drvdata->pwm)) {
                ret = PTR_ERR(drvdata->pwm);
-               dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret);
+               if (ret == -EPROBE_DEFER)
+                       dev_dbg(&pdev->dev,
+                               "Failed to get PWM, deferring probe\n");
+               else
+                       dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret);
                return ret;
        }
 
index 7407cd5..7fc97f2 100644 (file)
@@ -925,12 +925,21 @@ static const struct rpm_regulator_data rpm_pm8921_regulators[] = {
        { }
 };
 
+static const struct rpm_regulator_data rpm_smb208_regulators[] = {
+       { "s1a",  QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" },
+       { "s1b",  QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" },
+       { "s2a",  QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" },
+       { "s2b",  QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" },
+       { }
+};
+
 static const struct of_device_id rpm_of_match[] = {
        { .compatible = "qcom,rpm-pm8018-regulators",
                .data = &rpm_pm8018_regulators },
        { .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators },
        { .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators },
        { .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators },
+       { .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators },
        { }
 };
 MODULE_DEVICE_TABLE(of, rpm_of_match);
index fff8d5f..fdde419 100644 (file)
@@ -445,6 +445,44 @@ static const struct regulator_desc pm8994_lnldo = {
        .ops = &rpm_smps_ldo_ops_fixed,
 };
 
+static const struct regulator_desc pmi8994_ftsmps = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(350000,  0, 199, 5000),
+               REGULATOR_LINEAR_RANGE(700000, 200, 349, 10000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 350,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pmi8994_hfsmps = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(350000,  0,  80, 12500),
+               REGULATOR_LINEAR_RANGE(700000, 81, 141, 25000),
+       },
+       .n_linear_ranges = 2,
+       .n_voltages = 142,
+       .ops = &rpm_smps_ldo_ops,
+};
+
+static const struct regulator_desc pmi8994_bby = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(3000000, 0, 44, 50000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 45,
+       .ops = &rpm_bob_ops,
+};
+
+static const struct regulator_desc pmi8994_boost = {
+       .linear_ranges = (struct regulator_linear_range[]) {
+               REGULATOR_LINEAR_RANGE(4000000, 0, 30, 50000),
+       },
+       .n_linear_ranges = 1,
+       .n_voltages = 31,
+       .ops = &rpm_smps_ldo_ops,
+};
+
 static const struct regulator_desc pm8998_ftsmps = {
        .linear_ranges = (struct regulator_linear_range[]) {
                REGULATOR_LINEAR_RANGE(320000, 0, 258, 4000),
@@ -780,6 +818,14 @@ static const struct rpm_regulator_data rpm_pm8994_regulators[] = {
        {}
 };
 
+static const struct rpm_regulator_data rpm_pmi8994_regulators[] = {
+       { "s1", QCOM_SMD_RPM_SMPB, 1, &pmi8994_ftsmps, "vdd_s1" },
+       { "s2", QCOM_SMD_RPM_SMPB, 2, &pmi8994_hfsmps, "vdd_s2" },
+       { "s2", QCOM_SMD_RPM_SMPB, 3, &pmi8994_hfsmps, "vdd_s3" },
+       { "boost-bypass", QCOM_SMD_RPM_BBYB, 1, &pmi8994_bby, "vdd_bst_byp" },
+       {}
+};
+
 static const struct rpm_regulator_data rpm_pm8998_regulators[] = {
        { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8998_ftsmps, "vdd_s1" },
        { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8998_ftsmps, "vdd_s2" },
@@ -862,6 +908,7 @@ static const struct of_device_id rpm_of_match[] = {
        { .compatible = "qcom,rpm-pm8994-regulators", .data = &rpm_pm8994_regulators },
        { .compatible = "qcom,rpm-pm8998-regulators", .data = &rpm_pm8998_regulators },
        { .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators },
+       { .compatible = "qcom,rpm-pmi8994-regulators", .data = &rpm_pmi8994_regulators },
        { .compatible = "qcom,rpm-pmi8998-regulators", .data = &rpm_pmi8998_regulators },
        { .compatible = "qcom,rpm-pms405-regulators", .data = &rpm_pms405_regulators },
        {}
index bdfaf7e..992bc18 100644 (file)
@@ -88,7 +88,7 @@ static int stm32_vrefbuf_disable(struct regulator_dev *rdev)
        }
 
        val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
-       val = (val & ~STM32_ENVR) | STM32_HIZ;
+       val &= ~STM32_ENVR;
        writel_relaxed(val, priv->base + STM32_VREFBUF_CSR);
 
        pm_runtime_mark_last_busy(priv->dev);
@@ -175,6 +175,7 @@ static const struct regulator_desc stm32_vrefbuf_regu = {
        .volt_table = stm32_vrefbuf_voltages,
        .n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages),
        .ops = &stm32_vrefbuf_volt_ops,
+       .off_on_delay = 1000,
        .type = REGULATOR_VOLTAGE,
        .owner = THIS_MODULE,
 };
index 461b0e5..d9efbfd 100644 (file)
@@ -51,6 +51,7 @@ config RESET_BRCMSTB
 
 config RESET_BRCMSTB_RESCAL
        bool "Broadcom STB RESCAL reset controller"
+       depends on HAS_IOMEM
        default ARCH_BRCMSTB || COMPILE_TEST
        help
          This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on
@@ -73,7 +74,7 @@ config RESET_IMX7
 
 config RESET_INTEL_GW
        bool "Intel Reset Controller Driver"
-       depends on OF
+       depends on OF && HAS_IOMEM
        select REGMAP_MMIO
        help
          This enables the reset controller driver for Intel Gateway SoCs.
index 34c8b6c..8e50388 100644 (file)
@@ -327,6 +327,7 @@ config RTC_DRV_MAX6900
 config RTC_DRV_MAX8907
        tristate "Maxim MAX8907"
        depends on MFD_MAX8907 || COMPILE_TEST
+       select REGMAP_IRQ
        help
          If you say yes here you will get support for the
          RTC of Maxim MAX8907 PMIC.
index 4ac8f19..24c7dfa 100644 (file)
@@ -12,10 +12,6 @@ obj-$(CONFIG_RTC_CLASS)              += rtc-core.o
 obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
 rtc-core-y                     := class.o interface.o
 
-ifdef CONFIG_RTC_DRV_EFI
-rtc-core-y                     += rtc-efi-platform.o
-endif
-
 rtc-core-$(CONFIG_RTC_NVMEM)           += nvmem.o
 rtc-core-$(CONFIG_RTC_INTF_DEV)                += dev.o
 rtc-core-$(CONFIG_RTC_INTF_PROC)       += proc.o
index b795fe4..82bfe00 100644 (file)
@@ -1345,7 +1345,7 @@ static const struct pnp_device_id rtc_ids[] = {
 MODULE_DEVICE_TABLE(pnp, rtc_ids);
 
 static struct pnp_driver cmos_pnp_driver = {
-       .name           = (char *) driver_name,
+       .name           = driver_name,
        .id_table       = rtc_ids,
        .probe          = cmos_pnp_probe,
        .remove         = cmos_pnp_remove,
diff --git a/drivers/rtc/rtc-efi-platform.c b/drivers/rtc/rtc-efi-platform.c
deleted file mode 100644 (file)
index 6c037dc..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Moved from arch/ia64/kernel/time.c
- *
- * Copyright (C) 1998-2003 Hewlett-Packard Co
- *     Stephane Eranian <eranian@hpl.hp.com>
- *     David Mosberger <davidm@hpl.hp.com>
- * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
- * Copyright (C) 1999-2000 VA Linux Systems
- * Copyright (C) 1999-2000 Walt Drummond <drummond@valinux.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/efi.h>
-#include <linux/platform_device.h>
-
-static struct platform_device rtc_efi_dev = {
-       .name = "rtc-efi",
-       .id = -1,
-};
-
-static int __init rtc_init(void)
-{
-       if (efi_enabled(EFI_RUNTIME_SERVICES))
-               if (platform_device_register(&rtc_efi_dev) < 0)
-                       pr_err("unable to register rtc device...\n");
-
-       /* not necessarily an error */
-       return 0;
-}
-module_init(rtc_init);
index 6cca727..cf87eb2 100644 (file)
@@ -178,6 +178,8 @@ struct dasd_block *dasd_alloc_block(void)
                     (unsigned long) block);
        INIT_LIST_HEAD(&block->ccw_queue);
        spin_lock_init(&block->queue_lock);
+       INIT_LIST_HEAD(&block->format_list);
+       spin_lock_init(&block->format_lock);
        timer_setup(&block->timer, dasd_block_timeout, 0);
        spin_lock_init(&block->profile.lock);
 
@@ -1779,20 +1781,26 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
 
        if (dasd_ese_needs_format(cqr->block, irb)) {
                if (rq_data_dir((struct request *)cqr->callback_data) == READ) {
-                       device->discipline->ese_read(cqr);
+                       device->discipline->ese_read(cqr, irb);
                        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);
+               fcqr = device->discipline->ese_format(device, cqr, irb);
                if (IS_ERR(fcqr)) {
+                       if (PTR_ERR(fcqr) == -EINVAL) {
+                               cqr->status = DASD_CQR_ERROR;
+                               return;
+                       }
                        /*
                         * If we can't format now, let the request go
                         * one extra round. Maybe we can format later.
                         */
                        cqr->status = DASD_CQR_QUEUED;
+                       dasd_schedule_device_bh(device);
+                       return;
                } else {
                        fcqr->status = DASD_CQR_QUEUED;
                        cqr->status = DASD_CQR_QUEUED;
@@ -2748,11 +2756,13 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
 {
        struct request *req;
        blk_status_t error = BLK_STS_OK;
+       unsigned int proc_bytes;
        int status;
 
        req = (struct request *) cqr->callback_data;
        dasd_profile_end(cqr->block, cqr, req);
 
+       proc_bytes = cqr->proc_bytes;
        status = cqr->block->base->discipline->free_cp(cqr, req);
        if (status < 0)
                error = errno_to_blk_status(status);
@@ -2783,7 +2793,18 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr)
                blk_mq_end_request(req, error);
                blk_mq_run_hw_queues(req->q, true);
        } else {
-               blk_mq_complete_request(req);
+               /*
+                * Partial completed requests can happen with ESE devices.
+                * During read we might have gotten a NRF error and have to
+                * complete a request partially.
+                */
+               if (proc_bytes) {
+                       blk_update_request(req, BLK_STS_OK,
+                                          blk_rq_bytes(req) - proc_bytes);
+                       blk_mq_requeue_request(req, true);
+               } else {
+                       blk_mq_complete_request(req);
+               }
        }
 }
 
index a28b9ff..ad44d22 100644 (file)
@@ -207,6 +207,45 @@ static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head)
        geo->head |= head;
 }
 
+/*
+ * calculate failing track from sense data depending if
+ * it is an EAV device or not
+ */
+static int dasd_eckd_track_from_irb(struct irb *irb, struct dasd_device *device,
+                                   sector_t *track)
+{
+       struct dasd_eckd_private *private = device->private;
+       u8 *sense = NULL;
+       u32 cyl;
+       u8 head;
+
+       sense = dasd_get_sense(irb);
+       if (!sense) {
+               DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+                             "ESE error no sense data\n");
+               return -EINVAL;
+       }
+       if (!(sense[27] & DASD_SENSE_BIT_2)) {
+               DBF_DEV_EVENT(DBF_WARNING, device, "%s",
+                             "ESE error no valid track data\n");
+               return -EINVAL;
+       }
+
+       if (sense[27] & DASD_SENSE_BIT_3) {
+               /* enhanced addressing */
+               cyl = sense[30] << 20;
+               cyl |= (sense[31] & 0xF0) << 12;
+               cyl |= sense[28] << 8;
+               cyl |= sense[29];
+       } else {
+               cyl = sense[29] << 8;
+               cyl |= sense[30];
+       }
+       head = sense[31] & 0x0F;
+       *track = cyl * private->rdc_data.trk_per_cyl + head;
+       return 0;
+}
+
 static int set_timestamp(struct ccw1 *ccw, struct DE_eckd_data *data,
                     struct dasd_device *device)
 {
@@ -2986,6 +3025,37 @@ static int dasd_eckd_format_device(struct dasd_device *base,
                                             0, NULL);
 }
 
+static bool test_and_set_format_track(struct dasd_format_entry *to_format,
+                                     struct dasd_block *block)
+{
+       struct dasd_format_entry *format;
+       unsigned long flags;
+       bool rc = false;
+
+       spin_lock_irqsave(&block->format_lock, flags);
+       list_for_each_entry(format, &block->format_list, list) {
+               if (format->track == to_format->track) {
+                       rc = true;
+                       goto out;
+               }
+       }
+       list_add_tail(&to_format->list, &block->format_list);
+
+out:
+       spin_unlock_irqrestore(&block->format_lock, flags);
+       return rc;
+}
+
+static void clear_format_track(struct dasd_format_entry *format,
+                             struct dasd_block *block)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&block->format_lock, flags);
+       list_del_init(&format->list);
+       spin_unlock_irqrestore(&block->format_lock, flags);
+}
+
 /*
  * Callback function to free ESE format requests.
  */
@@ -2993,15 +3063,19 @@ 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;
+       struct dasd_format_entry *format = data;
 
+       clear_format_track(format, cqr->basedev->block);
        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)
+dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr,
+                    struct irb *irb)
 {
        struct dasd_eckd_private *private;
+       struct dasd_format_entry *format;
        struct format_data_t fdata;
        unsigned int recs_per_trk;
        struct dasd_ccw_req *fcqr;
@@ -3011,23 +3085,39 @@ dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr)
        struct request *req;
        sector_t first_trk;
        sector_t last_trk;
+       sector_t curr_trk;
        int rc;
 
        req = cqr->callback_data;
-       base = cqr->block->base;
+       block = cqr->block;
+       base = block->base;
        private = base->private;
-       block = base->block;
        blksize = block->bp_block;
        recs_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+       format = &startdev->format_entry;
 
        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);
+       rc = dasd_eckd_track_from_irb(irb, base, &curr_trk);
+       if (rc)
+               return ERR_PTR(rc);
 
-       fdata.start_unit = first_trk;
-       fdata.stop_unit = last_trk;
+       if (curr_trk < first_trk || curr_trk > last_trk) {
+               DBF_DEV_EVENT(DBF_WARNING, startdev,
+                             "ESE error track %llu not within range %llu - %llu\n",
+                             curr_trk, first_trk, last_trk);
+               return ERR_PTR(-EINVAL);
+       }
+       format->track = curr_trk;
+       /* test if track is already in formatting by another thread */
+       if (test_and_set_format_track(format, block))
+               return ERR_PTR(-EEXIST);
+
+       fdata.start_unit = curr_trk;
+       fdata.stop_unit = curr_trk;
        fdata.blksize = blksize;
        fdata.intensity = private->uses_cdl ? DASD_FMT_INT_COMPAT : 0;
 
@@ -3044,6 +3134,7 @@ dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr)
                return fcqr;
 
        fcqr->callback = dasd_eckd_ese_format_cb;
+       fcqr->callback_data = (void *) format;
 
        return fcqr;
 }
@@ -3051,29 +3142,87 @@ dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr)
 /*
  * 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.
+ *
+ * The first unformatted track is the one that got the NRF error, the address is
+ * encoded in the sense data.
+ *
+ * All tracks before have returned valid data and should not be touched.
+ * All tracks after the unformatted track might be formatted or not. This is
+ * currently not known, remember the processed data and return the remainder of
+ * the request to the blocklayer in __dasd_cleanup_cqr().
  */
-static void dasd_eckd_ese_read(struct dasd_ccw_req *cqr)
+static int dasd_eckd_ese_read(struct dasd_ccw_req *cqr, struct irb *irb)
 {
+       struct dasd_eckd_private *private;
+       sector_t first_trk, last_trk;
+       sector_t first_blk, last_blk;
        unsigned int blksize, off;
+       unsigned int recs_per_trk;
        struct dasd_device *base;
        struct req_iterator iter;
+       struct dasd_block *block;
+       unsigned int skip_block;
+       unsigned int blk_count;
        struct request *req;
        struct bio_vec bv;
+       sector_t curr_trk;
+       sector_t end_blk;
        char *dst;
+       int rc;
 
        req = (struct request *) cqr->callback_data;
        base = cqr->block->base;
        blksize = base->block->bp_block;
+       block =  cqr->block;
+       private = base->private;
+       skip_block = 0;
+       blk_count = 0;
+
+       recs_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+       first_trk = first_blk = blk_rq_pos(req) >> block->s2b_shift;
+       sector_div(first_trk, recs_per_trk);
+       last_trk = last_blk =
+               (blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
+       sector_div(last_trk, recs_per_trk);
+       rc = dasd_eckd_track_from_irb(irb, base, &curr_trk);
+       if (rc)
+               return rc;
+
+       /* sanity check if the current track from sense data is valid */
+       if (curr_trk < first_trk || curr_trk > last_trk) {
+               DBF_DEV_EVENT(DBF_WARNING, base,
+                             "ESE error track %llu not within range %llu - %llu\n",
+                             curr_trk, first_trk, last_trk);
+               return -EINVAL;
+       }
+
+       /*
+        * if not the first track got the NRF error we have to skip over valid
+        * blocks
+        */
+       if (curr_trk != first_trk)
+               skip_block = curr_trk * recs_per_trk - first_blk;
+
+       /* we have no information beyond the current track */
+       end_blk = (curr_trk + 1) * recs_per_trk;
 
        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) {
+                       if (first_blk + blk_count >= end_blk) {
+                               cqr->proc_bytes = blk_count * blksize;
+                               return 0;
+                       }
+                       if (dst && !skip_block) {
                                dst += off;
                                memset(dst, 0, blksize);
+                       } else {
+                               skip_block--;
                        }
+                       blk_count++;
                }
        }
+       return 0;
 }
 
 /*
index 91c9f95..fa552f9 100644 (file)
@@ -187,6 +187,7 @@ struct dasd_ccw_req {
 
        void (*callback)(struct dasd_ccw_req *, void *data);
        void *callback_data;
+       unsigned int proc_bytes;        /* bytes for partial completion */
 };
 
 /*
@@ -387,8 +388,9 @@ struct dasd_discipline {
        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 *);
+       struct dasd_ccw_req *(*ese_format)(struct dasd_device *,
+                                          struct dasd_ccw_req *, struct irb *);
+       int (*ese_read)(struct dasd_ccw_req *, struct irb *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -474,6 +476,11 @@ struct dasd_profile {
        spinlock_t lock;
 };
 
+struct dasd_format_entry {
+       struct list_head list;
+       sector_t track;
+};
+
 struct dasd_device {
        /* Block device stuff. */
        struct dasd_block *block;
@@ -539,6 +546,7 @@ struct dasd_device {
        struct dentry *debugfs_dentry;
        struct dentry *hosts_dentry;
        struct dasd_profile profile;
+       struct dasd_format_entry format_entry;
 };
 
 struct dasd_block {
@@ -564,6 +572,9 @@ struct dasd_block {
 
        struct dentry *debugfs_dentry;
        struct dasd_profile profile;
+
+       struct list_head format_list;
+       spinlock_t format_lock;
 };
 
 struct dasd_attention_data {
index 63502ca..80d2229 100644 (file)
@@ -636,10 +636,10 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char
        }
        dev_info->gd->major = dcssblk_major;
        dev_info->gd->fops = &dcssblk_devops;
-       dev_info->dcssblk_queue = blk_alloc_queue(GFP_KERNEL);
+       dev_info->dcssblk_queue =
+               blk_alloc_queue(dcssblk_make_request, NUMA_NO_NODE);
        dev_info->gd->queue = dev_info->dcssblk_queue;
        dev_info->gd->private_data = dev_info;
-       blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);
        blk_queue_logical_block_size(dev_info->dcssblk_queue, 4096);
        blk_queue_flag_set(QUEUE_FLAG_DAX, dev_info->dcssblk_queue);
 
index 3df5d68..45a04da 100644 (file)
@@ -343,14 +343,14 @@ static int __init xpram_setup_blkdev(void)
                xpram_disks[i] = alloc_disk(1);
                if (!xpram_disks[i])
                        goto out;
-               xpram_queues[i] = blk_alloc_queue(GFP_KERNEL);
+               xpram_queues[i] = blk_alloc_queue(xpram_make_request,
+                               NUMA_NO_NODE);
                if (!xpram_queues[i]) {
                        put_disk(xpram_disks[i]);
                        goto out;
                }
                blk_queue_flag_set(QUEUE_FLAG_NONROT, xpram_queues[i]);
                blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, xpram_queues[i]);
-               blk_queue_make_request(xpram_queues[i], xpram_make_request);
                blk_queue_logical_block_size(xpram_queues[i], 4096);
        }
 
index 9575a62..468cada 100644 (file)
@@ -369,7 +369,7 @@ enum qeth_qdio_info_states {
 struct qeth_buffer_pool_entry {
        struct list_head list;
        struct list_head init_list;
-       void *elements[QDIO_MAX_ELEMENTS_PER_BUFFER];
+       struct page *elements[QDIO_MAX_ELEMENTS_PER_BUFFER];
 };
 
 struct qeth_qdio_buffer_pool {
@@ -983,7 +983,7 @@ extern const struct attribute_group qeth_device_blkt_group;
 extern const struct device_type qeth_generic_devtype;
 
 const char *qeth_get_cardname_short(struct qeth_card *);
-int qeth_realloc_buffer_pool(struct qeth_card *, int);
+int qeth_resize_buffer_pool(struct qeth_card *card, unsigned int count);
 int qeth_core_load_discipline(struct qeth_card *, enum qeth_discipline_id);
 void qeth_core_free_discipline(struct qeth_card *);
 
index 8ca85c8..6d3f2f1 100644 (file)
@@ -65,7 +65,6 @@ static struct lock_class_key qdio_out_skb_queue_key;
 static void qeth_issue_next_read_cb(struct qeth_card *card,
                                    struct qeth_cmd_buffer *iob,
                                    unsigned int data_length);
-static void qeth_free_buffer_pool(struct qeth_card *);
 static int qeth_qdio_establish(struct qeth_card *);
 static void qeth_free_qdio_queues(struct qeth_card *card);
 static void qeth_notify_skbs(struct qeth_qdio_out_q *queue,
@@ -212,49 +211,121 @@ void qeth_clear_working_pool_list(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_clear_working_pool_list);
 
+static void qeth_free_pool_entry(struct qeth_buffer_pool_entry *entry)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(entry->elements); i++) {
+               if (entry->elements[i])
+                       __free_page(entry->elements[i]);
+       }
+
+       kfree(entry);
+}
+
+static void qeth_free_buffer_pool(struct qeth_card *card)
+{
+       struct qeth_buffer_pool_entry *entry, *tmp;
+
+       list_for_each_entry_safe(entry, tmp, &card->qdio.init_pool.entry_list,
+                                init_list) {
+               list_del(&entry->init_list);
+               qeth_free_pool_entry(entry);
+       }
+}
+
+static struct qeth_buffer_pool_entry *qeth_alloc_pool_entry(unsigned int pages)
+{
+       struct qeth_buffer_pool_entry *entry;
+       unsigned int i;
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return NULL;
+
+       for (i = 0; i < pages; i++) {
+               entry->elements[i] = alloc_page(GFP_KERNEL);
+
+               if (!entry->elements[i]) {
+                       qeth_free_pool_entry(entry);
+                       return NULL;
+               }
+       }
+
+       return entry;
+}
+
 static int qeth_alloc_buffer_pool(struct qeth_card *card)
 {
-       struct qeth_buffer_pool_entry *pool_entry;
-       void *ptr;
-       int i, j;
+       unsigned int buf_elements = QETH_MAX_BUFFER_ELEMENTS(card);
+       unsigned int i;
 
        QETH_CARD_TEXT(card, 5, "alocpool");
        for (i = 0; i < card->qdio.init_pool.buf_count; ++i) {
-               pool_entry = kzalloc(sizeof(*pool_entry), GFP_KERNEL);
-               if (!pool_entry) {
+               struct qeth_buffer_pool_entry *entry;
+
+               entry = qeth_alloc_pool_entry(buf_elements);
+               if (!entry) {
                        qeth_free_buffer_pool(card);
                        return -ENOMEM;
                }
-               for (j = 0; j < QETH_MAX_BUFFER_ELEMENTS(card); ++j) {
-                       ptr = (void *) __get_free_page(GFP_KERNEL);
-                       if (!ptr) {
-                               while (j > 0)
-                                       free_page((unsigned long)
-                                                 pool_entry->elements[--j]);
-                               kfree(pool_entry);
-                               qeth_free_buffer_pool(card);
-                               return -ENOMEM;
-                       }
-                       pool_entry->elements[j] = ptr;
-               }
-               list_add(&pool_entry->init_list,
-                        &card->qdio.init_pool.entry_list);
+
+               list_add(&entry->init_list, &card->qdio.init_pool.entry_list);
        }
        return 0;
 }
 
-int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
+int qeth_resize_buffer_pool(struct qeth_card *card, unsigned int count)
 {
+       unsigned int buf_elements = QETH_MAX_BUFFER_ELEMENTS(card);
+       struct qeth_qdio_buffer_pool *pool = &card->qdio.init_pool;
+       struct qeth_buffer_pool_entry *entry, *tmp;
+       int delta = count - pool->buf_count;
+       LIST_HEAD(entries);
+
        QETH_CARD_TEXT(card, 2, "realcbp");
 
-       /* TODO: steel/add buffers from/to a running card's buffer pool (?) */
-       qeth_clear_working_pool_list(card);
-       qeth_free_buffer_pool(card);
-       card->qdio.in_buf_pool.buf_count = bufcnt;
-       card->qdio.init_pool.buf_count = bufcnt;
-       return qeth_alloc_buffer_pool(card);
+       /* Defer until queue is allocated: */
+       if (!card->qdio.in_q)
+               goto out;
+
+       /* Remove entries from the pool: */
+       while (delta < 0) {
+               entry = list_first_entry(&pool->entry_list,
+                                        struct qeth_buffer_pool_entry,
+                                        init_list);
+               list_del(&entry->init_list);
+               qeth_free_pool_entry(entry);
+
+               delta++;
+       }
+
+       /* Allocate additional entries: */
+       while (delta > 0) {
+               entry = qeth_alloc_pool_entry(buf_elements);
+               if (!entry) {
+                       list_for_each_entry_safe(entry, tmp, &entries,
+                                                init_list) {
+                               list_del(&entry->init_list);
+                               qeth_free_pool_entry(entry);
+                       }
+
+                       return -ENOMEM;
+               }
+
+               list_add(&entry->init_list, &entries);
+
+               delta--;
+       }
+
+       list_splice(&entries, &pool->entry_list);
+
+out:
+       card->qdio.in_buf_pool.buf_count = count;
+       pool->buf_count = count;
+       return 0;
 }
-EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool);
+EXPORT_SYMBOL_GPL(qeth_resize_buffer_pool);
 
 static void qeth_free_qdio_queue(struct qeth_qdio_q *q)
 {
@@ -1170,19 +1241,6 @@ void qeth_drain_output_queues(struct qeth_card *card)
 }
 EXPORT_SYMBOL_GPL(qeth_drain_output_queues);
 
-static void qeth_free_buffer_pool(struct qeth_card *card)
-{
-       struct qeth_buffer_pool_entry *pool_entry, *tmp;
-       int i = 0;
-       list_for_each_entry_safe(pool_entry, tmp,
-                                &card->qdio.init_pool.entry_list, init_list){
-               for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i)
-                       free_page((unsigned long)pool_entry->elements[i]);
-               list_del(&pool_entry->init_list);
-               kfree(pool_entry);
-       }
-}
-
 static int qeth_osa_set_output_queues(struct qeth_card *card, bool single)
 {
        unsigned int count = single ? 1 : card->dev->num_tx_queues;
@@ -1204,7 +1262,6 @@ static int qeth_osa_set_output_queues(struct qeth_card *card, bool single)
        if (count == 1)
                dev_info(&card->gdev->dev, "Priority Queueing not supported\n");
 
-       card->qdio.default_out_queue = single ? 0 : QETH_DEFAULT_QUEUE;
        card->qdio.no_out_queues = count;
        return 0;
 }
@@ -2393,7 +2450,6 @@ static void qeth_free_qdio_queues(struct qeth_card *card)
                return;
 
        qeth_free_cq(card);
-       cancel_delayed_work_sync(&card->buffer_reclaim_work);
        for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
                if (card->qdio.in_q->bufs[j].rx_skb)
                        dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb);
@@ -2575,7 +2631,6 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(
        struct list_head *plh;
        struct qeth_buffer_pool_entry *entry;
        int i, free;
-       struct page *page;
 
        if (list_empty(&card->qdio.in_buf_pool.entry_list))
                return NULL;
@@ -2584,7 +2639,7 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(
                entry = list_entry(plh, struct qeth_buffer_pool_entry, list);
                free = 1;
                for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
-                       if (page_count(virt_to_page(entry->elements[i])) > 1) {
+                       if (page_count(entry->elements[i]) > 1) {
                                free = 0;
                                break;
                        }
@@ -2599,15 +2654,15 @@ static struct qeth_buffer_pool_entry *qeth_find_free_buffer_pool_entry(
        entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
                        struct qeth_buffer_pool_entry, list);
        for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
-               if (page_count(virt_to_page(entry->elements[i])) > 1) {
-                       page = alloc_page(GFP_ATOMIC);
-                       if (!page) {
+               if (page_count(entry->elements[i]) > 1) {
+                       struct page *page = alloc_page(GFP_ATOMIC);
+
+                       if (!page)
                                return NULL;
-                       } else {
-                               free_page((unsigned long)entry->elements[i]);
-                               entry->elements[i] = page_address(page);
-                               QETH_CARD_STAT_INC(card, rx_sg_alloc_page);
-                       }
+
+                       __free_page(entry->elements[i]);
+                       entry->elements[i] = page;
+                       QETH_CARD_STAT_INC(card, rx_sg_alloc_page);
                }
        }
        list_del_init(&entry->list);
@@ -2625,12 +2680,12 @@ static int qeth_init_input_buffer(struct qeth_card *card,
                                               ETH_HLEN +
                                               sizeof(struct ipv6hdr));
                if (!buf->rx_skb)
-                       return 1;
+                       return -ENOMEM;
        }
 
        pool_entry = qeth_find_free_buffer_pool_entry(card);
        if (!pool_entry)
-               return 1;
+               return -ENOBUFS;
 
        /*
         * since the buffer is accessed only from the input_tasklet
@@ -2643,7 +2698,7 @@ static int qeth_init_input_buffer(struct qeth_card *card,
        for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
                buf->buffer->element[i].length = PAGE_SIZE;
                buf->buffer->element[i].addr =
-                       virt_to_phys(pool_entry->elements[i]);
+                       page_to_phys(pool_entry->elements[i]);
                if (i == QETH_MAX_BUFFER_ELEMENTS(card) - 1)
                        buf->buffer->element[i].eflags = SBAL_EFLAGS_LAST_ENTRY;
                else
@@ -2675,10 +2730,15 @@ static int qeth_init_qdio_queues(struct qeth_card *card)
        /* inbound queue */
        qdio_reset_buffers(card->qdio.in_q->qdio_bufs, QDIO_MAX_BUFFERS_PER_Q);
        memset(&card->rx, 0, sizeof(struct qeth_rx));
+
        qeth_initialize_working_pool_list(card);
        /*give only as many buffers to hardware as we have buffer pool entries*/
-       for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; ++i)
-               qeth_init_input_buffer(card, &card->qdio.in_q->bufs[i]);
+       for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; i++) {
+               rc = qeth_init_input_buffer(card, &card->qdio.in_q->bufs[i]);
+               if (rc)
+                       return rc;
+       }
+
        card->qdio.in_q->next_buf_to_init =
                card->qdio.in_buf_pool.buf_count - 1;
        rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0,
index 2bd9993..78cae61 100644 (file)
@@ -247,8 +247,8 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
        struct qeth_card *card = dev_get_drvdata(dev);
+       unsigned int cnt;
        char *tmp;
-       int cnt, old_cnt;
        int rc = 0;
 
        mutex_lock(&card->conf_mutex);
@@ -257,13 +257,12 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev,
                goto out;
        }
 
-       old_cnt = card->qdio.in_buf_pool.buf_count;
        cnt = simple_strtoul(buf, &tmp, 10);
        cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN :
                ((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt);
-       if (old_cnt != cnt) {
-               rc = qeth_realloc_buffer_pool(card, cnt);
-       }
+
+       rc = qeth_resize_buffer_pool(card, cnt);
+
 out:
        mutex_unlock(&card->conf_mutex);
        return rc ? rc : count;
index 9972d96..8fb2937 100644 (file)
@@ -284,6 +284,7 @@ static void qeth_l2_stop_card(struct qeth_card *card)
        if (card->state == CARD_STATE_SOFTSETUP) {
                qeth_clear_ipacmd_list(card);
                qeth_drain_output_queues(card);
+               cancel_delayed_work_sync(&card->buffer_reclaim_work);
                card->state = CARD_STATE_DOWN;
        }
 
index 317d566..82f800d 100644 (file)
@@ -1178,6 +1178,7 @@ static void qeth_l3_stop_card(struct qeth_card *card)
                qeth_l3_clear_ip_htable(card, 1);
                qeth_clear_ipacmd_list(card);
                qeth_drain_output_queues(card);
+               cancel_delayed_work_sync(&card->buffer_reclaim_work);
                card->state = CARD_STATE_DOWN;
        }
 
index 29f2517..a3d1c3b 100644 (file)
@@ -206,12 +206,11 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
                qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
                if (card->ssqd.qdioac2 & CHSC_AC2_SNIFFER_AVAILABLE) {
                        card->options.sniffer = i;
-                       if (card->qdio.init_pool.buf_count !=
-                                       QETH_IN_BUF_COUNT_MAX)
-                               qeth_realloc_buffer_pool(card,
-                                       QETH_IN_BUF_COUNT_MAX);
-               } else
+                       qeth_resize_buffer_pool(card, QETH_IN_BUF_COUNT_MAX);
+               } else {
                        rc = -EPERM;
+               }
+
                break;
        default:
                rc = -EINVAL;
index 2b1e4da..4bfb79f 100644 (file)
@@ -410,7 +410,7 @@ struct fsf_qtcb_bottom_port {
        u8 cb_util;
        u8 a_util;
        u8 res2;
-       u16 temperature;
+       s16 temperature;
        u16 vcc;
        u16 tx_bias;
        u16 tx_power;
index 494b9fe..a711a0d 100644 (file)
@@ -800,7 +800,7 @@ static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400,
        static ZFCP_DEV_ATTR(adapter_diag_sfp, _name, 0400,                    \
                             zfcp_sysfs_adapter_diag_sfp_##_name##_show, NULL)
 
-ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 5, "%hu");
+ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 6, "%hd");
 ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, 5, "%hu");
 ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, 5, "%hu");
 ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, 5, "%hu");
index 3170b29..1862594 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/jiffies.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
+#include <linux/msdos_partition.h>
 #include <scsi/scsicam.h>
 
 #include <asm/dma.h>
@@ -3410,9 +3411,10 @@ static int blogic_diskparam(struct scsi_device *sdev, struct block_device *dev,
           a partition table entry whose end_head matches one of the
           standard BusLogic geometry translations (64/32, 128/32, or 255/63).
         */
-       if (*(unsigned short *) (buf + 64) == 0xAA55) {
-               struct partition *part1_entry = (struct partition *) buf;
-               struct partition *part_entry = part1_entry;
+       if (*(unsigned short *) (buf + 64) == MSDOS_LABEL_MAGIC) {
+               struct msdos_partition *part1_entry =
+                               (struct msdos_partition *)buf;
+               struct msdos_partition *part_entry = part1_entry;
                int saved_cyl = diskparam->cylinders, part_no;
                unsigned char part_end_head = 0, part_end_sector = 0;
 
index a7881f8..1b6eaf8 100644 (file)
@@ -989,6 +989,7 @@ config SCSI_SYM53C8XX_MMIO
 config SCSI_IPR
        tristate "IBM Power Linux RAID adapter support"
        depends on PCI && SCSI && ATA
+       select SATA_HOST
        select FW_LOADER
        select IRQ_POLL
        select SGL_ALLOC
index ee6bc2f..0443b74 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/syscalls.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
+#include <linux/msdos_partition.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -328,9 +329,9 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
        buf = scsi_bios_ptable(bdev);
        if (!buf)
                return 0;
-       if(*(__le16 *)(buf + 0x40) == cpu_to_le16(0xaa55)) {
-               struct partition *first = (struct partition * )buf;
-               struct partition *entry = first;
+       if (*(__le16 *)(buf + 0x40) == cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+               struct msdos_partition *first = (struct msdos_partition *)buf;
+               struct msdos_partition *entry = first;
                int saved_cylinders = param->cylinders;
                int num;
                unsigned char end_head, end_sec;
index 5799251..dc4fe33 100644 (file)
@@ -723,24 +723,17 @@ static int
 ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
                    sector_t capacity, int geom[])
 {
-       uint8_t *bh;
        int      heads;
        int      sectors;
        int      cylinders;
-       int      ret;
        int      extended;
        struct   ahd_softc *ahd;
 
        ahd = *((struct ahd_softc **)sdev->host->hostdata);
 
-       bh = scsi_bios_ptable(bdev);
-       if (bh) {
-               ret = scsi_partsize(bh, capacity,
-                                   &geom[2], &geom[0], &geom[1]);
-               kfree(bh);
-               if (ret != -1)
-                       return (ret);
-       }
+       if (scsi_partsize(bdev, capacity, geom))
+               return 0;
+
        heads = 64;
        sectors = 32;
        cylinders = aic_sector_div(capacity, heads, sectors);
index d5c4a0d..2edfa05 100644 (file)
@@ -695,11 +695,9 @@ static int
 ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
                    sector_t capacity, int geom[])
 {
-       uint8_t *bh;
        int      heads;
        int      sectors;
        int      cylinders;
-       int      ret;
        int      extended;
        struct   ahc_softc *ahc;
        u_int    channel;
@@ -707,14 +705,9 @@ ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
        ahc = *((struct ahc_softc **)sdev->host->hostdata);
        channel = sdev_channel(sdev);
 
-       bh = scsi_bios_ptable(bdev);
-       if (bh) {
-               ret = scsi_partsize(bh, capacity,
-                                   &geom[2], &geom[0], &geom[1]);
-               kfree(bh);
-               if (ret != -1)
-                       return (ret);
-       }
+       if (scsi_partsize(bdev, capacity, geom))
+               return 0;
+
        heads = 64;
        sectors = 32;
        cylinders = aic_sector_div(capacity, heads, sectors);
index 40dc8ea..c2c79a3 100644 (file)
@@ -353,16 +353,11 @@ static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
 static int arcmsr_bios_param(struct scsi_device *sdev,
                struct block_device *bdev, sector_t capacity, int *geom)
 {
-       int ret, heads, sectors, cylinders, total_capacity;
-       unsigned char *buffer;/* return copy of block device's partition table */
+       int heads, sectors, cylinders, total_capacity;
+
+       if (scsi_partsize(bdev, capacity, geom))
+               return 0;
 
-       buffer = scsi_bios_ptable(bdev);
-       if (buffer) {
-               ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]);
-               kfree(buffer);
-               if (ret != -1)
-                       return ret;
-       }
        total_capacity = capacity;
        heads = 64;
        sectors = 32;
index ae45cbe..cd8db13 100644 (file)
@@ -9950,6 +9950,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
        ioa_cfg->max_devs_supported = ipr_max_devs;
 
        if (ioa_cfg->sis64) {
+               host->max_channel = IPR_MAX_SIS64_BUSES;
                host->max_id = IPR_MAX_SIS64_TARGETS_PER_BUS;
                host->max_lun = IPR_MAX_SIS64_LUNS_PER_TARGET;
                if (ipr_max_devs > IPR_MAX_SIS64_DEVS)
@@ -9958,6 +9959,7 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
                                           + ((sizeof(struct ipr_config_table_entry64)
                                               * ioa_cfg->max_devs_supported)));
        } else {
+               host->max_channel = IPR_VSET_BUS;
                host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS;
                host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET;
                if (ipr_max_devs > IPR_MAX_PHYSICAL_DEVS)
@@ -9967,7 +9969,6 @@ static void ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
                                               * ioa_cfg->max_devs_supported)));
        }
 
-       host->max_channel = IPR_VSET_BUS;
        host->unique_id = host->host_no;
        host->max_cmd_len = IPR_MAX_CDB_LEN;
        host->can_queue = ioa_cfg->max_cmds;
index a67baeb..b97aa9a 100644 (file)
@@ -1300,6 +1300,7 @@ struct ipr_resource_entry {
 #define IPR_ARRAY_VIRTUAL_BUS                  0x1
 #define IPR_VSET_VIRTUAL_BUS                   0x2
 #define IPR_IOAFP_VIRTUAL_BUS                  0x3
+#define IPR_MAX_SIS64_BUSES                    0x4
 
 #define IPR_GET_RES_PHYS_LOC(res) \
        (((res)->bus << 24) | ((res)->target << 8) | (res)->lun)
index b48aac8..974c3b9 100644 (file)
@@ -621,7 +621,7 @@ static int isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return -ENOMEM;
        pci_set_drvdata(pdev, pci_info);
 
-       if (efi_enabled(EFI_RUNTIME_SERVICES))
+       if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                orom = isci_get_efi_var(pdev);
 
        if (!orom)
index 9c5f7c9..2b865c6 100644 (file)
@@ -628,6 +628,8 @@ redisc:
        }
 out:
        kref_put(&rdata->kref, fc_rport_destroy);
+       if (!IS_ERR(fp))
+               fc_frame_free(fp);
 }
 
 /**
index 5c6a5ef..052ee3a 100644 (file)
@@ -19,6 +19,7 @@ config SCSI_SAS_ATA
        bool "ATA support for libsas (requires libata)"
        depends on SCSI_SAS_LIBSAS
        depends on ATA = y || ATA = SCSI_SAS_LIBSAS
+       select SATA_HOST
        help
                Builds in ATA support into libsas.  Will necessitate
                the loading of libata along with libsas.
index ff6d4aa..f27ffd0 100644 (file)
@@ -2795,11 +2795,9 @@ megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev,
                    sector_t capacity, int geom[])
 {
        adapter_t       *adapter;
-       unsigned char   *bh;
        int     heads;
        int     sectors;
        int     cylinders;
-       int     rval;
 
        /* Get pointer to host config structure */
        adapter = (adapter_t *)sdev->host->hostdata;
@@ -2826,15 +2824,8 @@ megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev,
                        geom[2] = cylinders;
        }
        else {
-               bh = scsi_bios_ptable(bdev);
-
-               if( bh ) {
-                       rval = scsi_partsize(bh, capacity,
-                                           &geom[2], &geom[0], &geom[1]);
-                       kfree(bh);
-                       if( rval != -1 )
-                               return rval;
-               }
+               if (scsi_partsize(bdev, capacity, geom))
+                       return 0;
 
                dev_info(&adapter->dev->dev,
                         "invalid partition on this disk on channel %d\n",
index b520a98..7a94e11 100644 (file)
@@ -864,7 +864,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
                goto qc24_fail_command;
        }
 
-       if (atomic_read(&fcport->state) != FCS_ONLINE) {
+       if (atomic_read(&fcport->state) != FCS_ONLINE || fcport->deleted) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
                        atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
                        ql_dbg(ql_dbg_io, vha, 0x3005,
@@ -946,7 +946,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd,
                goto qc24_fail_command;
        }
 
-       if (atomic_read(&fcport->state) != FCS_ONLINE) {
+       if (atomic_read(&fcport->state) != FCS_ONLINE || fcport->deleted) {
                if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
                        atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
                        ql_dbg(ql_dbg_io, vha, 0x3077,
index 44cb054..4c6c448 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/hrtimer.h>
 #include <linux/uuid.h>
 #include <linux/t10-pi.h>
+#include <linux/msdos_partition.h>
 
 #include <net/checksum.h>
 
@@ -4146,7 +4147,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
 static void __init sdebug_build_parts(unsigned char *ramp,
                                      unsigned long store_size)
 {
-       struct partition *pp;
+       struct msdos_partition *pp;
        int starts[SDEBUG_MAX_PARTS + 2];
        int sectors_per_part, num_sectors, k;
        int heads_by_sects, start_sec, end_sec;
@@ -4171,7 +4172,7 @@ static void __init sdebug_build_parts(unsigned char *ramp,
 
        ramp[510] = 0x55;       /* magic partition markings */
        ramp[511] = 0xAA;
-       pp = (struct partition *)(ramp + 0x1be);
+       pp = (struct msdos_partition *)(ramp + 0x1be);
        for (k = 0; starts[k + 1]; ++k, ++pp) {
                start_sec = starts[k];
                end_sec = starts[k + 1] - 1;
index e969138..682cf08 100644 (file)
 #include <linux/genhd.h>
 #include <linux/kernel.h>
 #include <linux/blkdev.h>
+#include <linux/msdos_partition.h>
 #include <asm/unaligned.h>
 
 #include <scsi/scsicam.h>
 
-
-static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
-                  unsigned int *secs);
-
 /**
  * scsi_bios_ptable - Read PC partition table out of first sector of device.
  * @dev: from this device
@@ -35,105 +32,48 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds
  */
 unsigned char *scsi_bios_ptable(struct block_device *dev)
 {
-       unsigned char *res = kmalloc(66, GFP_KERNEL);
-       if (res) {
-               struct block_device *bdev = dev->bd_contains;
-               Sector sect;
-               void *data = read_dev_sector(bdev, 0, &sect);
-               if (data) {
-                       memcpy(res, data + 0x1be, 66);
-                       put_dev_sector(sect);
-               } else {
-                       kfree(res);
-                       res = NULL;
-               }
-       }
-       return res;
-}
-EXPORT_SYMBOL(scsi_bios_ptable);
-
-/**
- * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors.
- * @bdev: which device
- * @capacity: size of the disk in sectors
- * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders
- *
- * Description : determine the BIOS mapping/geometry used for a drive in a
- *      SCSI-CAM system, storing the results in ip as required
- *      by the HDIO_GETGEO ioctl().
- *
- * Returns : -1 on failure, 0 on success.
- */
-
-int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
-{
-       unsigned char *p;
-       u64 capacity64 = capacity;      /* Suppress gcc warning */
-       int ret;
-
-       p = scsi_bios_ptable(bdev);
-       if (!p)
-               return -1;
-
-       /* try to infer mapping from partition table */
-       ret = scsi_partsize(p, (unsigned long)capacity, (unsigned int *)ip + 2,
-                              (unsigned int *)ip + 0, (unsigned int *)ip + 1);
-       kfree(p);
-
-       if (ret == -1 && capacity64 < (1ULL << 32)) {
-               /* pick some standard mapping with at most 1024 cylinders,
-                  and at most 62 sectors per track - this works up to
-                  7905 MB */
-               ret = setsize((unsigned long)capacity, (unsigned int *)ip + 2,
-                      (unsigned int *)ip + 0, (unsigned int *)ip + 1);
-       }
-
-       /* if something went wrong, then apparently we have to return
-          a geometry with more than 1024 cylinders */
-       if (ret || ip[0] > 255 || ip[1] > 63) {
-               if ((capacity >> 11) > 65534) {
-                       ip[0] = 255;
-                       ip[1] = 63;
-               } else {
-                       ip[0] = 64;
-                       ip[1] = 32;
-               }
+       struct address_space *mapping = dev->bd_contains->bd_inode->i_mapping;
+       unsigned char *res = NULL;
+       struct page *page;
 
-               if (capacity > 65535*63*255)
-                       ip[2] = 65535;
-               else
-                       ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
-       }
+       page = read_mapping_page(mapping, 0, NULL);
+       if (IS_ERR(page))
+               return NULL;
 
-       return 0;
+       if (!PageError(page))
+               res = kmemdup(page_address(page) + 0x1be, 66, GFP_KERNEL);
+       put_page(page);
+       return res;
 }
-EXPORT_SYMBOL(scsicam_bios_param);
+EXPORT_SYMBOL(scsi_bios_ptable);
 
 /**
  * scsi_partsize - Parse cylinders/heads/sectors from PC partition table
- * @buf: partition table, see scsi_bios_ptable()
+ * @bdev: block device to parse
  * @capacity: size of the disk in sectors
- * @cyls: put cylinders here
- * @hds: put heads here
- * @secs: put sectors here
+ * @geom: output in form of [hds, cylinders, sectors]
  *
  * Determine the BIOS mapping/geometry used to create the partition
- * table, storing the results in @cyls, @hds, and @secs
+ * table, storing the results in @geom.
  *
- * Returns: -1 on failure, 0 on success.
+ * Returns: %false on failure, %true on success.
  */
-
-int scsi_partsize(unsigned char *buf, unsigned long capacity,
-              unsigned int *cyls, unsigned int *hds, unsigned int *secs)
+bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3])
 {
-       struct partition *p = (struct partition *)buf, *largest = NULL;
-       int i, largest_cyl;
        int cyl, ext_cyl, end_head, end_cyl, end_sector;
        unsigned int logical_end, physical_end, ext_physical_end;
+       struct msdos_partition *p, *largest = NULL;
+       void *buf;
+       int ret = false;
 
+       buf = scsi_bios_ptable(bdev);
+       if (!buf)
+               return false;
 
        if (*(unsigned short *) (buf + 64) == 0xAA55) {
-               for (largest_cyl = -1, i = 0; i < 4; ++i, ++p) {
+               int largest_cyl = -1, i;
+
+               for (i = 0, p = buf; i < 4; i++, p++) {
                        if (!p->sys_ind)
                                continue;
 #ifdef DEBUG
@@ -153,7 +93,7 @@ int scsi_partsize(unsigned char *buf, unsigned long capacity,
                end_sector = largest->end_sector & 0x3f;
 
                if (end_head + 1 == 0 || end_sector == 0)
-                       return -1;
+                       goto out_free_buf;
 
 #ifdef DEBUG
                printk("scsicam_bios_param : end at h = %d, c = %d, s = %d\n",
@@ -178,19 +118,24 @@ int scsi_partsize(unsigned char *buf, unsigned long capacity,
                  ,logical_end, physical_end, ext_physical_end, ext_cyl);
 #endif
 
-               if ((logical_end == physical_end) ||
-                 (end_cyl == 1023 && ext_physical_end == logical_end)) {
-                       *secs = end_sector;
-                       *hds = end_head + 1;
-                       *cyls = capacity / ((end_head + 1) * end_sector);
-                       return 0;
+               if (logical_end == physical_end ||
+                   (end_cyl == 1023 && ext_physical_end == logical_end)) {
+                       geom[0] = end_head + 1;
+                       geom[1] = end_sector;
+                       geom[2] = (unsigned long)capacity /
+                               ((end_head + 1) * end_sector);
+                       ret = true;
+                       goto out_free_buf;
                }
 #ifdef DEBUG
                printk("scsicam_bios_param : logical (%u) != physical (%u)\n",
                       logical_end, physical_end);
 #endif
        }
-       return -1;
+
+out_free_buf:
+       kfree(buf);
+       return ret;
 }
 EXPORT_SYMBOL(scsi_partsize);
 
@@ -258,3 +203,56 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds
        *hds = (unsigned int) heads;
        return (rv);
 }
+
+/**
+ * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors.
+ * @bdev: which device
+ * @capacity: size of the disk in sectors
+ * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders
+ *
+ * Description : determine the BIOS mapping/geometry used for a drive in a
+ *      SCSI-CAM system, storing the results in ip as required
+ *      by the HDIO_GETGEO ioctl().
+ *
+ * Returns : -1 on failure, 0 on success.
+ */
+int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
+{
+       u64 capacity64 = capacity;      /* Suppress gcc warning */
+       int ret = 0;
+
+       /* try to infer mapping from partition table */
+       if (scsi_partsize(bdev, capacity, ip))
+               return 0;
+
+       if (capacity64 < (1ULL << 32)) {
+               /*
+                * Pick some standard mapping with at most 1024 cylinders, and
+                * at most 62 sectors per track - this works up to 7905 MB.
+                */
+               ret = setsize((unsigned long)capacity, (unsigned int *)ip + 2,
+                      (unsigned int *)ip + 0, (unsigned int *)ip + 1);
+       }
+
+       /*
+        * If something went wrong, then apparently we have to return a geometry
+        * with more than 1024 cylinders.
+        */
+       if (ret || ip[0] > 255 || ip[1] > 63) {
+               if ((capacity >> 11) > 65534) {
+                       ip[0] = 255;
+                       ip[1] = 63;
+               } else {
+                       ip[0] = 64;
+                       ip[1] = 32;
+               }
+
+               if (capacity > 65535*63*255)
+                       ip[2] = 65535;
+               else
+                       ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(scsicam_bios_param);
index 8ca9299..a793cb0 100644 (file)
@@ -3169,9 +3169,11 @@ static int sd_revalidate_disk(struct gendisk *disk)
        if (sd_validate_opt_xfer_size(sdkp, dev_max)) {
                q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks);
                rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
-       } else
+       } else {
+               q->limits.io_opt = 0;
                rw_max = min_not_zero(logical_to_sectors(sdp, dev_max),
                                      (sector_t)BLK_DEF_MAX_SECTORS);
+       }
 
        /* Do not exceed controller limit */
        rw_max = min(rw_max, queue_max_hw_sectors(q));
@@ -3187,7 +3189,8 @@ static int sd_revalidate_disk(struct gendisk *disk)
 
        sdkp->first_scan = 0;
 
-       set_capacity(disk, logical_to_sectors(sdp, sdkp->capacity));
+       set_capacity_revalidate_and_notify(disk,
+               logical_to_sectors(sdp, sdkp->capacity), false);
        sd_config_write_same(sdkp);
        kfree(buffer);
 
index e4282bc..f45c22b 100644 (file)
@@ -161,6 +161,7 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
                        unsigned int nr_zones, report_zones_cb cb, void *data)
 {
        struct scsi_disk *sdkp = scsi_disk(disk);
+       sector_t capacity = logical_to_sectors(sdkp->device, sdkp->capacity);
        unsigned int nr, i;
        unsigned char *buf;
        size_t offset, buflen = 0;
@@ -171,11 +172,15 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
                /* Not a zoned device */
                return -EOPNOTSUPP;
 
+       if (!capacity)
+               /* Device gone or invalid */
+               return -ENODEV;
+
        buf = sd_zbc_alloc_report_buffer(sdkp, nr_zones, &buflen);
        if (!buf)
                return -ENOMEM;
 
-       while (zone_idx < nr_zones && sector < get_capacity(disk)) {
+       while (zone_idx < nr_zones && sector < capacity) {
                ret = sd_zbc_do_report_zones(sdkp, buf, buflen,
                                sectors_to_logical(sdkp->device, sector), true);
                if (ret)
index 0fbb8fe..e4240e4 100644 (file)
@@ -688,7 +688,7 @@ static const struct block_device_operations sr_bdops =
        .release        = sr_block_release,
        .ioctl          = sr_block_ioctl,
 #ifdef CONFIG_COMPAT
-       .ioctl          = sr_block_compat_ioctl,
+       .compat_ioctl   = sr_block_compat_ioctl,
 #endif
        .check_events   = sr_block_check_events,
        .revalidate_disk = sr_block_revalidate_disk,
index abd0e6b..2d70569 100644 (file)
@@ -3884,18 +3884,25 @@ EXPORT_SYMBOL_GPL(ufshcd_uic_hibern8_exit);
 void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
 {
        unsigned long flags;
+       bool update = false;
 
-       if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT))
+       if (!ufshcd_is_auto_hibern8_supported(hba))
                return;
 
        spin_lock_irqsave(hba->host->host_lock, flags);
-       if (hba->ahit == ahit)
-               goto out_unlock;
-       hba->ahit = ahit;
-       if (!pm_runtime_suspended(hba->dev))
-               ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER);
-out_unlock:
+       if (hba->ahit != ahit) {
+               hba->ahit = ahit;
+               update = true;
+       }
        spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+       if (update && !pm_runtime_suspended(hba->dev)) {
+               pm_runtime_get_sync(hba->dev);
+               ufshcd_hold(hba, false);
+               ufshcd_auto_hibern8_enable(hba);
+               ufshcd_release(hba);
+               pm_runtime_put(hba->dev);
+       }
 }
 EXPORT_SYMBOL_GPL(ufshcd_auto_hibern8_update);
 
index e3f5ebc..fc2575f 100644 (file)
@@ -1320,6 +1320,9 @@ static const struct of_device_id qcom_slim_ngd_dt_match[] = {
        {
                .compatible = "qcom,slim-ngd-v1.5.0",
                .data = &ngd_v1_5_offset_info,
+       },{
+               .compatible = "qcom,slim-ngd-v2.1.0",
+               .data = &ngd_v1_5_offset_info,
        },
        {}
 };
index 70014ec..7b642c3 100644 (file)
@@ -233,10 +233,6 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev)
                goto err_allocate_irqs;
        }
 
-       err = register_dpio_irq_handlers(dpio_dev, desc.cpu);
-       if (err)
-               goto err_register_dpio_irq;
-
        priv->io = dpaa2_io_create(&desc, dev);
        if (!priv->io) {
                dev_err(dev, "dpaa2_io_create failed\n");
@@ -244,6 +240,10 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev)
                goto err_dpaa2_io_create;
        }
 
+       err = register_dpio_irq_handlers(dpio_dev, desc.cpu);
+       if (err)
+               goto err_register_dpio_irq;
+
        dev_info(dev, "probed\n");
        dev_dbg(dev, "   receives_notifications = %d\n",
                desc.receives_notifications);
index fb70b8a..20d37ea 100644 (file)
@@ -25,7 +25,7 @@ struct imx_sc_msg_misc_get_soc_id {
                        u32 id;
                } resp;
        } data;
-} __packed;
+} __packed __aligned(4);
 
 struct imx_sc_msg_misc_get_soc_uid {
        struct imx_sc_rpc_msg hdr;
index 2dad496..8d4d050 100644 (file)
@@ -59,7 +59,7 @@ static int __init exynos_chipid_early_init(void)
        syscon = of_find_compatible_node(NULL, NULL,
                                         "samsung,exynos4210-chipid");
        if (!syscon)
-               return ENODEV;
+               return -ENODEV;
 
        regmap = device_node_to_regmap(syscon);
        of_node_put(syscon);
index d6ed0c3..efce98e 100644 (file)
@@ -62,6 +62,13 @@ config SPI_ALTERA
        help
          This is the driver for the Altera SPI Controller.
 
+config SPI_AR934X
+       tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver"
+       depends on ATH79 || COMPILE_TEST
+       help
+         This enables support for the SPI controller present on the
+         Qualcomm Atheros AR934X/QCA95XX SoCs.
+
 config SPI_ATH79
        tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver"
        depends on ATH79 || COMPILE_TEST
@@ -264,6 +271,13 @@ config SPI_FALCON
          has only been tested with m25p80 type chips. The hardware has no
          support for other types of SPI peripherals.
 
+config SPI_FSI
+       tristate "FSI SPI driver"
+       depends on FSI
+       help
+         This enables support for the driver for FSI bus attached SPI
+         controllers.
+
 config SPI_FSL_LPSPI
        tristate "Freescale i.MX LPSPI controller"
        depends on ARCH_MXC || COMPILE_TEST
@@ -285,7 +299,6 @@ config SPI_HISI_SFC_V3XX
        tristate "HiSilicon SPI-NOR Flash Controller for Hi16XX chipsets"
        depends on (ARM64 && ACPI) || COMPILE_TEST
        depends on HAS_IOMEM
-       select CONFIG_MTD_SPI_NOR
        help
          This enables support for HiSilicon v3xx SPI-NOR flash controller
          found in hi16xx chipsets.
@@ -415,6 +428,7 @@ config SPI_FSL_ESPI
 
 config SPI_MESON_SPICC
        tristate "Amlogic Meson SPICC controller"
+       depends on COMMON_CLK
        depends on ARCH_MESON || COMPILE_TEST
        help
          This enables master mode support for the SPICC (SPI communication
@@ -443,6 +457,16 @@ config SPI_MT7621
        help
          This selects a driver for the MediaTek MT7621 SPI Controller.
 
+config SPI_MTK_NOR
+       tristate "MediaTek SPI NOR controller"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       help
+         This enables support for SPI NOR controller found on MediaTek
+         ARM SoCs. This is a controller specifically for SPI-NOR flash.
+         It can perform generic SPI transfers up to 6 bytes via generic
+         SPI interface as well as several SPI-NOR specific instructions
+         via SPI MEM interface.
+
 config SPI_NPCM_FIU
        tristate "Nuvoton NPCM FLASH Interface Unit"
        depends on ARCH_NPCM || COMPILE_TEST
@@ -890,6 +914,17 @@ config SPI_ZYNQMP_GQSPI
 # Add new SPI master controllers in alphabetical order above this line
 #
 
+comment "SPI Multiplexer support"
+
+config SPI_MUX
+       tristate "SPI multiplexer support"
+       select MULTIPLEXER
+       help
+         This adds support for SPI multiplexers. Each SPI mux will be
+         accessible as a SPI controller, the devices behind the mux will appear
+         to be chip selects on this controller. It is still necessary to
+         select one or more specific mux-controller drivers.
+
 #
 # There are lots of SPI device types, with sensors and memory
 # being probably the most widely used ones.
index 9b65ec5..28f6013 100644 (file)
@@ -9,11 +9,13 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
 # config declarations into driver model code
 obj-$(CONFIG_SPI_MASTER)               += spi.o
 obj-$(CONFIG_SPI_MEM)                  += spi-mem.o
+obj-$(CONFIG_SPI_MUX)                  += spi-mux.o
 obj-$(CONFIG_SPI_SPIDEV)               += spidev.o
 obj-$(CONFIG_SPI_LOOPBACK_TEST)                += spi-loopback-test.o
 
 # SPI master controller drivers (bus)
 obj-$(CONFIG_SPI_ALTERA)               += spi-altera.o
+obj-$(CONFIG_SPI_AR934X)               += spi-ar934x.o
 obj-$(CONFIG_SPI_ARMADA_3700)          += spi-armada-3700.o
 obj-$(CONFIG_SPI_ATMEL)                        += spi-atmel.o
 obj-$(CONFIG_SPI_ATMEL_QUADSPI)                += atmel-quadspi.o
@@ -40,6 +42,7 @@ spi-dw-midpci-objs                    := spi-dw-pci.o spi-dw-mid.o
 obj-$(CONFIG_SPI_EFM32)                        += spi-efm32.o
 obj-$(CONFIG_SPI_EP93XX)               += spi-ep93xx.o
 obj-$(CONFIG_SPI_FALCON)               += spi-falcon.o
+obj-$(CONFIG_SPI_FSI)                  += spi-fsi.o
 obj-$(CONFIG_SPI_FSL_CPM)              += spi-fsl-cpm.o
 obj-$(CONFIG_SPI_FSL_DSPI)             += spi-fsl-dspi.o
 obj-$(CONFIG_SPI_FSL_LIB)              += spi-fsl-lib.o
@@ -62,6 +65,7 @@ obj-$(CONFIG_SPI_MPC52xx_PSC)         += spi-mpc52xx-psc.o
 obj-$(CONFIG_SPI_MPC52xx)              += spi-mpc52xx.o
 obj-$(CONFIG_SPI_MT65XX)                += spi-mt65xx.o
 obj-$(CONFIG_SPI_MT7621)               += spi-mt7621.o
+obj-$(CONFIG_SPI_MTK_NOR)              += spi-mtk-nor.o
 obj-$(CONFIG_SPI_MXIC)                 += spi-mxic.o
 obj-$(CONFIG_SPI_MXS)                  += spi-mxs.o
 obj-$(CONFIG_SPI_NPCM_FIU)             += spi-npcm-fiu.o
index fd8007e..cb44d1e 100644 (file)
@@ -149,6 +149,7 @@ struct atmel_qspi {
        struct clk              *qspick;
        struct platform_device  *pdev;
        const struct atmel_qspi_caps *caps;
+       resource_size_t         mmap_size;
        u32                     pending;
        u32                     mr;
        u32                     scr;
@@ -172,6 +173,81 @@ static const struct atmel_qspi_mode atmel_qspi_modes[] = {
        { 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD },
 };
 
+#ifdef VERBOSE_DEBUG
+static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz)
+{
+       switch (offset) {
+       case QSPI_CR:
+               return "CR";
+       case QSPI_MR:
+               return "MR";
+       case QSPI_RD:
+               return "MR";
+       case QSPI_TD:
+               return "TD";
+       case QSPI_SR:
+               return "SR";
+       case QSPI_IER:
+               return "IER";
+       case QSPI_IDR:
+               return "IDR";
+       case QSPI_IMR:
+               return "IMR";
+       case QSPI_SCR:
+               return "SCR";
+       case QSPI_IAR:
+               return "IAR";
+       case QSPI_ICR:
+               return "ICR/WICR";
+       case QSPI_IFR:
+               return "IFR";
+       case QSPI_RICR:
+               return "RICR";
+       case QSPI_SMR:
+               return "SMR";
+       case QSPI_SKR:
+               return "SKR";
+       case QSPI_WPMR:
+               return "WPMR";
+       case QSPI_WPSR:
+               return "WPSR";
+       case QSPI_VERSION:
+               return "VERSION";
+       default:
+               snprintf(tmp, sz, "0x%02x", offset);
+               break;
+       }
+
+       return tmp;
+}
+#endif /* VERBOSE_DEBUG */
+
+static u32 atmel_qspi_read(struct atmel_qspi *aq, u32 offset)
+{
+       u32 value = readl_relaxed(aq->regs + offset);
+
+#ifdef VERBOSE_DEBUG
+       char tmp[8];
+
+       dev_vdbg(&aq->pdev->dev, "read 0x%08x from %s\n", value,
+                atmel_qspi_reg_name(offset, tmp, sizeof(tmp)));
+#endif /* VERBOSE_DEBUG */
+
+       return value;
+}
+
+static void atmel_qspi_write(u32 value, struct atmel_qspi *aq, u32 offset)
+{
+#ifdef VERBOSE_DEBUG
+       char tmp[8];
+
+       dev_vdbg(&aq->pdev->dev, "write 0x%08x into %s\n", value,
+                atmel_qspi_reg_name(offset, tmp, sizeof(tmp)));
+#endif /* VERBOSE_DEBUG */
+
+       writel_relaxed(value, aq->regs + offset);
+}
+
 static inline bool atmel_qspi_is_compatible(const struct spi_mem_op *op,
                                            const struct atmel_qspi_mode *mode)
 {
@@ -292,32 +368,32 @@ static int atmel_qspi_set_cfg(struct atmel_qspi *aq,
         * Serial Memory Mode (SMM).
         */
        if (aq->mr != QSPI_MR_SMM) {
-               writel_relaxed(QSPI_MR_SMM, aq->regs + QSPI_MR);
+               atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR);
                aq->mr = QSPI_MR_SMM;
        }
 
        /* Clear pending interrupts */
-       (void)readl_relaxed(aq->regs + QSPI_SR);
+       (void)atmel_qspi_read(aq, QSPI_SR);
 
        if (aq->caps->has_ricr) {
                if (!op->addr.nbytes && op->data.dir == SPI_MEM_DATA_IN)
                        ifr |= QSPI_IFR_APBTFRTYP_READ;
 
                /* Set QSPI Instruction Frame registers */
-               writel_relaxed(iar, aq->regs + QSPI_IAR);
+               atmel_qspi_write(iar, aq, QSPI_IAR);
                if (op->data.dir == SPI_MEM_DATA_IN)
-                       writel_relaxed(icr, aq->regs + QSPI_RICR);
+                       atmel_qspi_write(icr, aq, QSPI_RICR);
                else
-                       writel_relaxed(icr, aq->regs + QSPI_WICR);
-               writel_relaxed(ifr, aq->regs + QSPI_IFR);
+                       atmel_qspi_write(icr, aq, QSPI_WICR);
+               atmel_qspi_write(ifr, aq, QSPI_IFR);
        } else {
                if (op->data.dir == SPI_MEM_DATA_OUT)
                        ifr |= QSPI_IFR_SAMA5D2_WRITE_TRSFR;
 
                /* Set QSPI Instruction Frame registers */
-               writel_relaxed(iar, aq->regs + QSPI_IAR);
-               writel_relaxed(icr, aq->regs + QSPI_ICR);
-               writel_relaxed(ifr, aq->regs + QSPI_IFR);
+               atmel_qspi_write(iar, aq, QSPI_IAR);
+               atmel_qspi_write(icr, aq, QSPI_ICR);
+               atmel_qspi_write(ifr, aq, QSPI_IFR);
        }
 
        return 0;
@@ -329,6 +405,14 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
        u32 sr, offset;
        int err;
 
+       /*
+        * Check if the address exceeds the MMIO window size. An improvement
+        * would be to add support for regular SPI mode and fall back to it
+        * when the flash memories overrun the controller's memory space.
+        */
+       if (op->addr.val + op->data.nbytes > aq->mmap_size)
+               return -ENOTSUPP;
+
        err = atmel_qspi_set_cfg(aq, op, &offset);
        if (err)
                return err;
@@ -336,7 +420,7 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
        /* Skip to the final steps if there is no data */
        if (op->data.nbytes) {
                /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */
-               (void)readl_relaxed(aq->regs + QSPI_IFR);
+               (void)atmel_qspi_read(aq, QSPI_IFR);
 
                /* Send/Receive data */
                if (op->data.dir == SPI_MEM_DATA_IN)
@@ -347,22 +431,22 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
                                     op->data.nbytes);
 
                /* Release the chip-select */
-               writel_relaxed(QSPI_CR_LASTXFER, aq->regs + QSPI_CR);
+               atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR);
        }
 
        /* Poll INSTRuction End status */
-       sr = readl_relaxed(aq->regs + QSPI_SR);
+       sr = atmel_qspi_read(aq, QSPI_SR);
        if ((sr & QSPI_SR_CMD_COMPLETED) == QSPI_SR_CMD_COMPLETED)
                return err;
 
        /* Wait for INSTRuction End interrupt */
        reinit_completion(&aq->cmd_completion);
        aq->pending = sr & QSPI_SR_CMD_COMPLETED;
-       writel_relaxed(QSPI_SR_CMD_COMPLETED, aq->regs + QSPI_IER);
+       atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IER);
        if (!wait_for_completion_timeout(&aq->cmd_completion,
                                         msecs_to_jiffies(1000)))
                err = -ETIMEDOUT;
-       writel_relaxed(QSPI_SR_CMD_COMPLETED, aq->regs + QSPI_IDR);
+       atmel_qspi_write(QSPI_SR_CMD_COMPLETED, aq, QSPI_IDR);
 
        return err;
 }
@@ -401,7 +485,7 @@ static int atmel_qspi_setup(struct spi_device *spi)
                scbr--;
 
        aq->scr = QSPI_SCR_SCBR(scbr);
-       writel_relaxed(aq->scr, aq->regs + QSPI_SCR);
+       atmel_qspi_write(aq->scr, aq, QSPI_SCR);
 
        return 0;
 }
@@ -409,14 +493,14 @@ static int atmel_qspi_setup(struct spi_device *spi)
 static void atmel_qspi_init(struct atmel_qspi *aq)
 {
        /* Reset the QSPI controller */
-       writel_relaxed(QSPI_CR_SWRST, aq->regs + QSPI_CR);
+       atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR);
 
        /* Set the QSPI controller by default in Serial Memory Mode */
-       writel_relaxed(QSPI_MR_SMM, aq->regs + QSPI_MR);
+       atmel_qspi_write(QSPI_MR_SMM, aq, QSPI_MR);
        aq->mr = QSPI_MR_SMM;
 
        /* Enable the QSPI controller */
-       writel_relaxed(QSPI_CR_QSPIEN, aq->regs + QSPI_CR);
+       atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR);
 }
 
 static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
@@ -424,8 +508,8 @@ static irqreturn_t atmel_qspi_interrupt(int irq, void *dev_id)
        struct atmel_qspi *aq = dev_id;
        u32 status, mask, pending;
 
-       status = readl_relaxed(aq->regs + QSPI_SR);
-       mask = readl_relaxed(aq->regs + QSPI_IMR);
+       status = atmel_qspi_read(aq, QSPI_SR);
+       mask = atmel_qspi_read(aq, QSPI_IMR);
        pending = status & mask;
 
        if (!pending)
@@ -480,6 +564,8 @@ static int atmel_qspi_probe(struct platform_device *pdev)
                goto exit;
        }
 
+       aq->mmap_size = resource_size(res);
+
        /* Get the peripheral clock */
        aq->pclk = devm_clk_get(&pdev->dev, "pclk");
        if (IS_ERR(aq->pclk))
@@ -558,7 +644,7 @@ static int atmel_qspi_remove(struct platform_device *pdev)
        struct atmel_qspi *aq = spi_controller_get_devdata(ctrl);
 
        spi_unregister_controller(ctrl);
-       writel_relaxed(QSPI_CR_QSPIDIS, aq->regs + QSPI_CR);
+       atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR);
        clk_disable_unprepare(aq->qspick);
        clk_disable_unprepare(aq->pclk);
        return 0;
@@ -585,7 +671,7 @@ static int __maybe_unused atmel_qspi_resume(struct device *dev)
 
        atmel_qspi_init(aq);
 
-       writel_relaxed(aq->scr, aq->regs + QSPI_SCR);
+       atmel_qspi_write(aq->scr, aq, QSPI_SCR);
 
        return 0;
 }
diff --git a/drivers/spi/spi-ar934x.c b/drivers/spi/spi-ar934x.c
new file mode 100644 (file)
index 0000000..d08dec0
--- /dev/null
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// SPI controller driver for Qualcomm Atheros AR934x/QCA95xx SoCs
+//
+// Copyright (C) 2020 Chuanhong Guo <gch981213@gmail.com>
+//
+// Based on spi-mt7621.c:
+// Copyright (C) 2011 Sergiy <piratfm@gmail.com>
+// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name>
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+
+#define DRIVER_NAME "spi-ar934x"
+
+#define AR934X_SPI_REG_FS              0x00
+#define AR934X_SPI_ENABLE              BIT(0)
+
+#define AR934X_SPI_REG_IOC             0x08
+#define AR934X_SPI_IOC_INITVAL         0x70000
+
+#define AR934X_SPI_REG_CTRL            0x04
+#define AR934X_SPI_CLK_MASK            GENMASK(5, 0)
+
+#define AR934X_SPI_DATAOUT             0x10
+
+#define AR934X_SPI_REG_SHIFT_CTRL      0x14
+#define AR934X_SPI_SHIFT_EN            BIT(31)
+#define AR934X_SPI_SHIFT_CS(n)         BIT(28 + (n))
+#define AR934X_SPI_SHIFT_TERM          26
+#define AR934X_SPI_SHIFT_VAL(cs, term, count)                  \
+       (AR934X_SPI_SHIFT_EN | AR934X_SPI_SHIFT_CS(cs) |        \
+       (term) << AR934X_SPI_SHIFT_TERM | (count))
+
+#define AR934X_SPI_DATAIN 0x18
+
+struct ar934x_spi {
+       struct spi_controller *ctlr;
+       void __iomem *base;
+       struct clk *clk;
+       unsigned int clk_freq;
+};
+
+static inline int ar934x_spi_clk_div(struct ar934x_spi *sp, unsigned int freq)
+{
+       int div = DIV_ROUND_UP(sp->clk_freq, freq * 2) - 1;
+
+       if (div < 0)
+               return 0;
+       else if (div > AR934X_SPI_CLK_MASK)
+               return -EINVAL;
+       else
+               return div;
+}
+
+static int ar934x_spi_setup(struct spi_device *spi)
+{
+       struct ar934x_spi *sp = spi_controller_get_devdata(spi->master);
+
+       if ((spi->max_speed_hz == 0) ||
+           (spi->max_speed_hz > (sp->clk_freq / 2))) {
+               spi->max_speed_hz = sp->clk_freq / 2;
+       } else if (spi->max_speed_hz < (sp->clk_freq / 128)) {
+               dev_err(&spi->dev, "spi clock is too low\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ar934x_spi_transfer_one_message(struct spi_controller *master,
+                                          struct spi_message *m)
+{
+       struct ar934x_spi *sp = spi_controller_get_devdata(master);
+       struct spi_transfer *t = NULL;
+       struct spi_device *spi = m->spi;
+       unsigned long trx_done, trx_cur;
+       int stat = 0;
+       u8 term = 0;
+       int div, i;
+       u32 reg;
+       const u8 *tx_buf;
+       u8 *buf;
+
+       m->actual_length = 0;
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (t->speed_hz)
+                       div = ar934x_spi_clk_div(sp, t->speed_hz);
+               else
+                       div = ar934x_spi_clk_div(sp, spi->max_speed_hz);
+               if (div < 0) {
+                       stat = -EIO;
+                       goto msg_done;
+               }
+
+               reg = ioread32(sp->base + AR934X_SPI_REG_CTRL);
+               reg &= ~AR934X_SPI_CLK_MASK;
+               reg |= div;
+               iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL);
+               iowrite32(0, sp->base + AR934X_SPI_DATAOUT);
+
+               for (trx_done = 0; trx_done < t->len; trx_done += 4) {
+                       trx_cur = t->len - trx_done;
+                       if (trx_cur > 4)
+                               trx_cur = 4;
+                       else if (list_is_last(&t->transfer_list, &m->transfers))
+                               term = 1;
+
+                       if (t->tx_buf) {
+                               tx_buf = t->tx_buf + trx_done;
+                               reg = tx_buf[0];
+                               for (i = 1; i < trx_cur; i++)
+                                       reg = reg << 8 | tx_buf[i];
+                               iowrite32(reg, sp->base + AR934X_SPI_DATAOUT);
+                       }
+
+                       reg = AR934X_SPI_SHIFT_VAL(spi->chip_select, term,
+                                                  trx_cur * 8);
+                       iowrite32(reg, sp->base + AR934X_SPI_REG_SHIFT_CTRL);
+                       stat = readl_poll_timeout(
+                               sp->base + AR934X_SPI_REG_SHIFT_CTRL, reg,
+                               !(reg & AR934X_SPI_SHIFT_EN), 0, 5);
+                       if (stat < 0)
+                               goto msg_done;
+
+                       if (t->rx_buf) {
+                               reg = ioread32(sp->base + AR934X_SPI_DATAIN);
+                               buf = t->rx_buf + trx_done;
+                               for (i = 0; i < trx_cur; i++) {
+                                       buf[trx_cur - i - 1] = reg & 0xff;
+                                       reg >>= 8;
+                               }
+                       }
+               }
+               m->actual_length += t->len;
+       }
+
+msg_done:
+       m->status = stat;
+       spi_finalize_current_message(master);
+
+       return 0;
+}
+
+static const struct of_device_id ar934x_spi_match[] = {
+       { .compatible = "qca,ar934x-spi" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ar934x_spi_match);
+
+static int ar934x_spi_probe(struct platform_device *pdev)
+{
+       struct spi_controller *ctlr;
+       struct ar934x_spi *sp;
+       void __iomem *base;
+       struct clk *clk;
+       int ret;
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               return PTR_ERR(clk);
+       }
+
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               return ret;
+
+       ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp));
+       if (!ctlr) {
+               dev_info(&pdev->dev, "failed to allocate spi controller\n");
+               return -ENOMEM;
+       }
+
+       /* disable flash mapping and expose spi controller registers */
+       iowrite32(AR934X_SPI_ENABLE, base + AR934X_SPI_REG_FS);
+       /* restore pins to default state: CSn=1 DO=CLK=0 */
+       iowrite32(AR934X_SPI_IOC_INITVAL, base + AR934X_SPI_REG_IOC);
+
+       ctlr->mode_bits = SPI_LSB_FIRST;
+       ctlr->setup = ar934x_spi_setup;
+       ctlr->transfer_one_message = ar934x_spi_transfer_one_message;
+       ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+       ctlr->dev.of_node = pdev->dev.of_node;
+       ctlr->num_chipselect = 3;
+
+       dev_set_drvdata(&pdev->dev, ctlr);
+
+       sp = spi_controller_get_devdata(ctlr);
+       sp->base = base;
+       sp->clk = clk;
+       sp->clk_freq = clk_get_rate(clk);
+       sp->ctlr = ctlr;
+
+       return devm_spi_register_controller(&pdev->dev, ctlr);
+}
+
+static int ar934x_spi_remove(struct platform_device *pdev)
+{
+       struct spi_controller *ctlr;
+       struct ar934x_spi *sp;
+
+       ctlr = dev_get_drvdata(&pdev->dev);
+       sp = spi_controller_get_devdata(ctlr);
+
+       clk_disable_unprepare(sp->clk);
+
+       return 0;
+}
+
+static struct platform_driver ar934x_spi_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .of_match_table = ar934x_spi_match,
+       },
+       .probe = ar934x_spi_probe,
+       .remove = ar934x_spi_remove,
+};
+
+module_platform_driver(ar934x_spi_driver);
+
+MODULE_DESCRIPTION("SPI controller driver for Qualcomm Atheros AR934x/QCA95xx");
+MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
index 7327309..6c23530 100644 (file)
@@ -366,7 +366,6 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
                        goto out_disable_clk;
 
                rate = clk_get_rate(pll_clk);
-               clk_disable_unprepare(pll_clk);
                if (!rate) {
                        ret = -EINVAL;
                        goto out_disable_pll_clk;
index 64d4c44..ea6e4a7 100644 (file)
@@ -6,14 +6,13 @@
 #include <linux/io.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
-#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_data/efm32-spi.h>
+#include <linux/of.h>
 
 #define DRIVER_NAME "efm32-spi"
 
@@ -82,9 +81,6 @@ struct efm32_spi_ddata {
        const u8 *tx_buf;
        u8 *rx_buf;
        unsigned tx_len, rx_len;
-
-       /* chip selects */
-       unsigned csgpio[];
 };
 
 #define ddata_to_dev(ddata)    (&(ddata->bitbang.master->dev))
@@ -102,14 +98,6 @@ static u32 efm32_spi_read32(struct efm32_spi_ddata *ddata, unsigned offset)
        return readl_relaxed(ddata->base + offset);
 }
 
-static void efm32_spi_chipselect(struct spi_device *spi, int is_on)
-{
-       struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master);
-       int value = !(spi->mode & SPI_CS_HIGH) == !(is_on == BITBANG_CS_ACTIVE);
-
-       gpio_set_value(ddata->csgpio[spi->chip_select], value);
-}
-
 static int efm32_spi_setup_transfer(struct spi_device *spi,
                struct spi_transfer *t)
 {
@@ -320,17 +308,11 @@ static int efm32_spi_probe(struct platform_device *pdev)
        int ret;
        struct spi_master *master;
        struct device_node *np = pdev->dev.of_node;
-       int num_cs, i;
 
        if (!np)
                return -EINVAL;
 
-       num_cs = of_gpio_named_count(np, "cs-gpios");
-       if (num_cs < 0)
-               return num_cs;
-
-       master = spi_alloc_master(&pdev->dev,
-                       sizeof(*ddata) + num_cs * sizeof(unsigned));
+       master = spi_alloc_master(&pdev->dev, sizeof(*ddata));
        if (!master) {
                dev_dbg(&pdev->dev,
                                "failed to allocate spi master controller\n");
@@ -340,14 +322,13 @@ static int efm32_spi_probe(struct platform_device *pdev)
 
        master->dev.of_node = pdev->dev.of_node;
 
-       master->num_chipselect = num_cs;
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+       master->use_gpio_descriptors = true;
 
        ddata = spi_master_get_devdata(master);
 
        ddata->bitbang.master = master;
-       ddata->bitbang.chipselect = efm32_spi_chipselect;
        ddata->bitbang.setup_transfer = efm32_spi_setup_transfer;
        ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
 
@@ -361,25 +342,6 @@ static int efm32_spi_probe(struct platform_device *pdev)
                goto err;
        }
 
-       for (i = 0; i < num_cs; ++i) {
-               ret = of_get_named_gpio(np, "cs-gpios", i);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "failed to get csgpio#%u (%d)\n",
-                                       i, ret);
-                       goto err;
-               }
-               ddata->csgpio[i] = ret;
-               dev_dbg(&pdev->dev, "csgpio#%u = %u\n", i, ddata->csgpio[i]);
-               ret = devm_gpio_request_one(&pdev->dev, ddata->csgpio[i],
-                               GPIOF_OUT_INIT_LOW, DRIVER_NAME);
-               if (ret < 0) {
-                       dev_err(&pdev->dev,
-                                       "failed to configure csgpio#%u (%d)\n",
-                                       i, ret);
-                       goto err;
-               }
-       }
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                ret = -ENODEV;
diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c
new file mode 100644 (file)
index 0000000..37a3e0f
--- /dev/null
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (C) IBM Corporation 2020
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/fsi.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+#define FSI_ENGID_SPI                  0x23
+#define FSI_MBOX_ROOT_CTRL_8           0x2860
+
+#define FSI2SPI_DATA0                  0x00
+#define FSI2SPI_DATA1                  0x04
+#define FSI2SPI_CMD                    0x08
+#define  FSI2SPI_CMD_WRITE              BIT(31)
+#define FSI2SPI_RESET                  0x18
+#define FSI2SPI_STATUS                 0x1c
+#define  FSI2SPI_STATUS_ANY_ERROR       BIT(31)
+#define FSI2SPI_IRQ                    0x20
+
+#define SPI_FSI_BASE                   0x70000
+#define SPI_FSI_INIT_TIMEOUT_MS                1000
+#define SPI_FSI_MAX_TRANSFER_SIZE      2048
+
+#define SPI_FSI_ERROR                  0x0
+#define SPI_FSI_COUNTER_CFG            0x1
+#define  SPI_FSI_COUNTER_CFG_LOOPS(x)   (((u64)(x) & 0xffULL) << 32)
+#define SPI_FSI_CFG1                   0x2
+#define SPI_FSI_CLOCK_CFG              0x3
+#define  SPI_FSI_CLOCK_CFG_MM_ENABLE    BIT_ULL(32)
+#define  SPI_FSI_CLOCK_CFG_ECC_DISABLE  (BIT_ULL(35) | BIT_ULL(33))
+#define  SPI_FSI_CLOCK_CFG_RESET1       (BIT_ULL(36) | BIT_ULL(38))
+#define  SPI_FSI_CLOCK_CFG_RESET2       (BIT_ULL(37) | BIT_ULL(39))
+#define  SPI_FSI_CLOCK_CFG_MODE                 (BIT_ULL(41) | BIT_ULL(42))
+#define  SPI_FSI_CLOCK_CFG_SCK_RECV_DEL         GENMASK_ULL(51, 44)
+#define   SPI_FSI_CLOCK_CFG_SCK_NO_DEL   BIT_ULL(51)
+#define  SPI_FSI_CLOCK_CFG_SCK_DIV      GENMASK_ULL(63, 52)
+#define SPI_FSI_MMAP                   0x4
+#define SPI_FSI_DATA_TX                        0x5
+#define SPI_FSI_DATA_RX                        0x6
+#define SPI_FSI_SEQUENCE               0x7
+#define  SPI_FSI_SEQUENCE_STOP          0x00
+#define  SPI_FSI_SEQUENCE_SEL_SLAVE(x)  (0x10 | ((x) & 0xf))
+#define  SPI_FSI_SEQUENCE_SHIFT_OUT(x)  (0x30 | ((x) & 0xf))
+#define  SPI_FSI_SEQUENCE_SHIFT_IN(x)   (0x40 | ((x) & 0xf))
+#define  SPI_FSI_SEQUENCE_COPY_DATA_TX  0xc0
+#define  SPI_FSI_SEQUENCE_BRANCH(x)     (0xe0 | ((x) & 0xf))
+#define SPI_FSI_STATUS                 0x8
+#define  SPI_FSI_STATUS_ERROR           \
+       (GENMASK_ULL(31, 21) | GENMASK_ULL(15, 12))
+#define  SPI_FSI_STATUS_SEQ_STATE       GENMASK_ULL(55, 48)
+#define   SPI_FSI_STATUS_SEQ_STATE_IDLE          BIT_ULL(48)
+#define  SPI_FSI_STATUS_TDR_UNDERRUN    BIT_ULL(57)
+#define  SPI_FSI_STATUS_TDR_OVERRUN     BIT_ULL(58)
+#define  SPI_FSI_STATUS_TDR_FULL        BIT_ULL(59)
+#define  SPI_FSI_STATUS_RDR_UNDERRUN    BIT_ULL(61)
+#define  SPI_FSI_STATUS_RDR_OVERRUN     BIT_ULL(62)
+#define  SPI_FSI_STATUS_RDR_FULL        BIT_ULL(63)
+#define  SPI_FSI_STATUS_ANY_ERROR       \
+       (SPI_FSI_STATUS_ERROR | SPI_FSI_STATUS_TDR_UNDERRUN | \
+        SPI_FSI_STATUS_TDR_OVERRUN | SPI_FSI_STATUS_RDR_UNDERRUN | \
+        SPI_FSI_STATUS_RDR_OVERRUN)
+#define SPI_FSI_PORT_CTRL              0x9
+
+struct fsi_spi {
+       struct device *dev;     /* SPI controller device */
+       struct fsi_device *fsi; /* FSI2SPI CFAM engine device */
+       u32 base;
+};
+
+struct fsi_spi_sequence {
+       int bit;
+       u64 data;
+};
+
+static int fsi_spi_check_status(struct fsi_spi *ctx)
+{
+       int rc;
+       u32 sts;
+       __be32 sts_be;
+
+       rc = fsi_device_read(ctx->fsi, FSI2SPI_STATUS, &sts_be,
+                            sizeof(sts_be));
+       if (rc)
+               return rc;
+
+       sts = be32_to_cpu(sts_be);
+       if (sts & FSI2SPI_STATUS_ANY_ERROR) {
+               dev_err(ctx->dev, "Error with FSI2SPI interface: %08x.\n", sts);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int fsi_spi_read_reg(struct fsi_spi *ctx, u32 offset, u64 *value)
+{
+       int rc;
+       __be32 cmd_be;
+       __be32 data_be;
+       u32 cmd = offset + ctx->base;
+
+       *value = 0ULL;
+
+       if (cmd & FSI2SPI_CMD_WRITE)
+               return -EINVAL;
+
+       cmd_be = cpu_to_be32(cmd);
+       rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be));
+       if (rc)
+               return rc;
+
+       rc = fsi_spi_check_status(ctx);
+       if (rc)
+               return rc;
+
+       rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA0, &data_be,
+                            sizeof(data_be));
+       if (rc)
+               return rc;
+
+       *value |= (u64)be32_to_cpu(data_be) << 32;
+
+       rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA1, &data_be,
+                            sizeof(data_be));
+       if (rc)
+               return rc;
+
+       *value |= (u64)be32_to_cpu(data_be);
+       dev_dbg(ctx->dev, "Read %02x[%016llx].\n", offset, *value);
+
+       return 0;
+}
+
+static int fsi_spi_write_reg(struct fsi_spi *ctx, u32 offset, u64 value)
+{
+       int rc;
+       __be32 cmd_be;
+       __be32 data_be;
+       u32 cmd = offset + ctx->base;
+
+       if (cmd & FSI2SPI_CMD_WRITE)
+               return -EINVAL;
+
+       dev_dbg(ctx->dev, "Write %02x[%016llx].\n", offset, value);
+
+       data_be = cpu_to_be32(upper_32_bits(value));
+       rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA0, &data_be,
+                             sizeof(data_be));
+       if (rc)
+               return rc;
+
+       data_be = cpu_to_be32(lower_32_bits(value));
+       rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA1, &data_be,
+                             sizeof(data_be));
+       if (rc)
+               return rc;
+
+       cmd_be = cpu_to_be32(cmd | FSI2SPI_CMD_WRITE);
+       rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be));
+       if (rc)
+               return rc;
+
+       return fsi_spi_check_status(ctx);
+}
+
+static int fsi_spi_data_in(u64 in, u8 *rx, int len)
+{
+       int i;
+       int num_bytes = min(len, 8);
+
+       for (i = 0; i < num_bytes; ++i)
+               rx[i] = (u8)(in >> (8 * ((num_bytes - 1) - i)));
+
+       return num_bytes;
+}
+
+static int fsi_spi_data_out(u64 *out, const u8 *tx, int len)
+{
+       int i;
+       int num_bytes = min(len, 8);
+       u8 *out_bytes = (u8 *)out;
+
+       /* Unused bytes of the tx data should be 0. */
+       *out = 0ULL;
+
+       for (i = 0; i < num_bytes; ++i)
+               out_bytes[8 - (i + 1)] = tx[i];
+
+       return num_bytes;
+}
+
+static int fsi_spi_reset(struct fsi_spi *ctx)
+{
+       int rc;
+
+       dev_dbg(ctx->dev, "Resetting SPI controller.\n");
+
+       rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,
+                              SPI_FSI_CLOCK_CFG_RESET1);
+       if (rc)
+               return rc;
+
+       return fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,
+                                SPI_FSI_CLOCK_CFG_RESET2);
+}
+
+static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val)
+{
+       /*
+        * Add the next byte of instruction to the 8-byte sequence register.
+        * Then decrement the counter so that the next instruction will go in
+        * the right place. Return the number of "slots" left in the sequence
+        * register.
+        */
+       seq->data |= (u64)val << seq->bit;
+       seq->bit -= 8;
+
+       return ((64 - seq->bit) / 8) - 2;
+}
+
+static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq)
+{
+       seq->bit = 56;
+       seq->data = 0ULL;
+}
+
+static int fsi_spi_sequence_transfer(struct fsi_spi *ctx,
+                                    struct fsi_spi_sequence *seq,
+                                    struct spi_transfer *transfer)
+{
+       int loops;
+       int idx;
+       int rc;
+       u8 len = min(transfer->len, 8U);
+       u8 rem = transfer->len % len;
+
+       loops = transfer->len / len;
+
+       if (transfer->tx_buf) {
+               idx = fsi_spi_sequence_add(seq,
+                                          SPI_FSI_SEQUENCE_SHIFT_OUT(len));
+               if (rem)
+                       rem = SPI_FSI_SEQUENCE_SHIFT_OUT(rem);
+       } else if (transfer->rx_buf) {
+               idx = fsi_spi_sequence_add(seq,
+                                          SPI_FSI_SEQUENCE_SHIFT_IN(len));
+               if (rem)
+                       rem = SPI_FSI_SEQUENCE_SHIFT_IN(rem);
+       } else {
+               return -EINVAL;
+       }
+
+       if (loops > 1) {
+               fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx));
+
+               if (rem)
+                       fsi_spi_sequence_add(seq, rem);
+
+               rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG,
+                                      SPI_FSI_COUNTER_CFG_LOOPS(loops - 1));
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static int fsi_spi_transfer_data(struct fsi_spi *ctx,
+                                struct spi_transfer *transfer)
+{
+       int rc = 0;
+       u64 status = 0ULL;
+
+       if (transfer->tx_buf) {
+               int nb;
+               int sent = 0;
+               u64 out = 0ULL;
+               const u8 *tx = transfer->tx_buf;
+
+               while (transfer->len > sent) {
+                       nb = fsi_spi_data_out(&out, &tx[sent],
+                                             (int)transfer->len - sent);
+
+                       rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, out);
+                       if (rc)
+                               return rc;
+
+                       do {
+                               rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS,
+                                                     &status);
+                               if (rc)
+                                       return rc;
+
+                               if (status & SPI_FSI_STATUS_ANY_ERROR) {
+                                       rc = fsi_spi_reset(ctx);
+                                       if (rc)
+                                               return rc;
+
+                                       return -EREMOTEIO;
+                               }
+                       } while (status & SPI_FSI_STATUS_TDR_FULL);
+
+                       sent += nb;
+               }
+       } else if (transfer->rx_buf) {
+               int recv = 0;
+               u64 in = 0ULL;
+               u8 *rx = transfer->rx_buf;
+
+               while (transfer->len > recv) {
+                       do {
+                               rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS,
+                                                     &status);
+                               if (rc)
+                                       return rc;
+
+                               if (status & SPI_FSI_STATUS_ANY_ERROR) {
+                                       rc = fsi_spi_reset(ctx);
+                                       if (rc)
+                                               return rc;
+
+                                       return -EREMOTEIO;
+                               }
+                       } while (!(status & SPI_FSI_STATUS_RDR_FULL));
+
+                       rc = fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, &in);
+                       if (rc)
+                               return rc;
+
+                       recv += fsi_spi_data_in(in, &rx[recv],
+                                               (int)transfer->len - recv);
+               }
+       }
+
+       return 0;
+}
+
+static int fsi_spi_transfer_init(struct fsi_spi *ctx)
+{
+       int rc;
+       bool reset = false;
+       unsigned long end;
+       u64 seq_state;
+       u64 clock_cfg = 0ULL;
+       u64 status = 0ULL;
+       u64 wanted_clock_cfg = SPI_FSI_CLOCK_CFG_ECC_DISABLE |
+               SPI_FSI_CLOCK_CFG_SCK_NO_DEL |
+               FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 4);
+
+       end = jiffies + msecs_to_jiffies(SPI_FSI_INIT_TIMEOUT_MS);
+       do {
+               if (time_after(jiffies, end))
+                       return -ETIMEDOUT;
+
+               rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, &status);
+               if (rc)
+                       return rc;
+
+               seq_state = status & SPI_FSI_STATUS_SEQ_STATE;
+
+               if (status & (SPI_FSI_STATUS_ANY_ERROR |
+                             SPI_FSI_STATUS_TDR_FULL |
+                             SPI_FSI_STATUS_RDR_FULL)) {
+                       if (reset)
+                               return -EIO;
+
+                       rc = fsi_spi_reset(ctx);
+                       if (rc)
+                               return rc;
+
+                       reset = true;
+                       continue;
+               }
+       } while (seq_state && (seq_state != SPI_FSI_STATUS_SEQ_STATE_IDLE));
+
+       rc = fsi_spi_read_reg(ctx, SPI_FSI_CLOCK_CFG, &clock_cfg);
+       if (rc)
+               return rc;
+
+       if ((clock_cfg & (SPI_FSI_CLOCK_CFG_MM_ENABLE |
+                         SPI_FSI_CLOCK_CFG_ECC_DISABLE |
+                         SPI_FSI_CLOCK_CFG_MODE |
+                         SPI_FSI_CLOCK_CFG_SCK_RECV_DEL |
+                         SPI_FSI_CLOCK_CFG_SCK_DIV)) != wanted_clock_cfg)
+               rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,
+                                      wanted_clock_cfg);
+
+       return rc;
+}
+
+static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
+                                       struct spi_message *mesg)
+{
+       int rc = 0;
+       u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(mesg->spi->chip_select + 1);
+       struct spi_transfer *transfer;
+       struct fsi_spi *ctx = spi_controller_get_devdata(ctlr);
+
+       list_for_each_entry(transfer, &mesg->transfers, transfer_list) {
+               struct fsi_spi_sequence seq;
+               struct spi_transfer *next = NULL;
+
+               /* Sequencer must do shift out (tx) first. */
+               if (!transfer->tx_buf ||
+                   transfer->len > SPI_FSI_MAX_TRANSFER_SIZE) {
+                       rc = -EINVAL;
+                       goto error;
+               }
+
+               dev_dbg(ctx->dev, "Start tx of %d bytes.\n", transfer->len);
+
+               rc = fsi_spi_transfer_init(ctx);
+               if (rc < 0)
+                       goto error;
+
+               fsi_spi_sequence_init(&seq);
+               fsi_spi_sequence_add(&seq, seq_slave);
+
+               rc = fsi_spi_sequence_transfer(ctx, &seq, transfer);
+               if (rc)
+                       goto error;
+
+               if (!list_is_last(&transfer->transfer_list,
+                                 &mesg->transfers)) {
+                       next = list_next_entry(transfer, transfer_list);
+
+                       /* Sequencer can only do shift in (rx) after tx. */
+                       if (next->rx_buf) {
+                               if (next->len > SPI_FSI_MAX_TRANSFER_SIZE) {
+                                       rc = -EINVAL;
+                                       goto error;
+                               }
+
+                               dev_dbg(ctx->dev, "Sequence rx of %d bytes.\n",
+                                       next->len);
+
+                               rc = fsi_spi_sequence_transfer(ctx, &seq,
+                                                              next);
+                               if (rc)
+                                       goto error;
+                       } else {
+                               next = NULL;
+                       }
+               }
+
+               fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SEL_SLAVE(0));
+
+               rc = fsi_spi_write_reg(ctx, SPI_FSI_SEQUENCE, seq.data);
+               if (rc)
+                       goto error;
+
+               rc = fsi_spi_transfer_data(ctx, transfer);
+               if (rc)
+                       goto error;
+
+               if (next) {
+                       rc = fsi_spi_transfer_data(ctx, next);
+                       if (rc)
+                               goto error;
+
+                       transfer = next;
+               }
+       }
+
+error:
+       mesg->status = rc;
+       spi_finalize_current_message(ctlr);
+
+       return rc;
+}
+
+static size_t fsi_spi_max_transfer_size(struct spi_device *spi)
+{
+       return SPI_FSI_MAX_TRANSFER_SIZE;
+}
+
+static int fsi_spi_probe(struct device *dev)
+{
+       int rc;
+       u32 root_ctrl_8;
+       struct device_node *np;
+       int num_controllers_registered = 0;
+       struct fsi_device *fsi = to_fsi_dev(dev);
+
+       /*
+        * Check the SPI mux before attempting to probe. If the mux isn't set
+        * then the SPI controllers can't access their slave devices.
+        */
+       rc = fsi_slave_read(fsi->slave, FSI_MBOX_ROOT_CTRL_8, &root_ctrl_8,
+                           sizeof(root_ctrl_8));
+       if (rc)
+               return rc;
+
+       if (!root_ctrl_8) {
+               dev_dbg(dev, "SPI mux not set, aborting probe.\n");
+               return -ENODEV;
+       }
+
+       for_each_available_child_of_node(dev->of_node, np) {
+               u32 base;
+               struct fsi_spi *ctx;
+               struct spi_controller *ctlr;
+
+               if (of_property_read_u32(np, "reg", &base))
+                       continue;
+
+               ctlr = spi_alloc_master(dev, sizeof(*ctx));
+               if (!ctlr)
+                       break;
+
+               ctlr->dev.of_node = np;
+               ctlr->num_chipselect = of_get_available_child_count(np) ?: 1;
+               ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
+               ctlr->max_transfer_size = fsi_spi_max_transfer_size;
+               ctlr->transfer_one_message = fsi_spi_transfer_one_message;
+
+               ctx = spi_controller_get_devdata(ctlr);
+               ctx->dev = &ctlr->dev;
+               ctx->fsi = fsi;
+               ctx->base = base + SPI_FSI_BASE;
+
+               rc = devm_spi_register_controller(dev, ctlr);
+               if (rc)
+                       spi_controller_put(ctlr);
+               else
+                       num_controllers_registered++;
+       }
+
+       if (!num_controllers_registered)
+               return -ENODEV;
+
+       return 0;
+}
+
+static const struct fsi_device_id fsi_spi_ids[] = {
+       { FSI_ENGID_SPI, FSI_VERSION_ANY },
+       { }
+};
+MODULE_DEVICE_TABLE(fsi, fsi_spi_ids);
+
+static struct fsi_driver fsi_spi_driver = {
+       .id_table = fsi_spi_ids,
+       .drv = {
+               .name = "spi-fsi",
+               .bus = &fsi_bus_type,
+               .probe = fsi_spi_probe,
+       },
+};
+module_fsi_driver(fsi_spi_driver);
+
+MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");
+MODULE_DESCRIPTION("FSI attached SPI controller");
+MODULE_LICENSE("GPL");
index 6ec2dcb..50e41f6 100644 (file)
 
 #define DRIVER_NAME                    "fsl-dspi"
 
-#ifdef CONFIG_M5441x
-#define DSPI_FIFO_SIZE                 16
-#else
-#define DSPI_FIFO_SIZE                 4
-#endif
-#define DSPI_DMA_BUFSIZE               (DSPI_FIFO_SIZE * 1024)
-
 #define SPI_MCR                                0x00
 #define SPI_MCR_MASTER                 BIT(31)
-#define SPI_MCR_PCSIS                  (0x3F << 16)
+#define SPI_MCR_PCSIS(x)               ((x) << 16)
 #define SPI_MCR_CLR_TXF                        BIT(11)
 #define SPI_MCR_CLR_RXF                        BIT(10)
 #define SPI_MCR_XSPI                   BIT(3)
@@ -79,6 +72,7 @@
 #define SPI_RSER                       0x30
 #define SPI_RSER_TCFQE                 BIT(31)
 #define SPI_RSER_EOQFE                 BIT(28)
+#define SPI_RSER_CMDTCFE               BIT(23)
 
 #define SPI_PUSHR                      0x34
 #define SPI_PUSHR_CMD_CONT             BIT(15)
 #define SPI_FRAME_BITS(bits)           SPI_CTAR_FMSZ((bits) - 1)
 #define SPI_FRAME_EBITS(bits)          SPI_CTARE_FMSZE(((bits) - 1) >> 4)
 
-/* Register offsets for regmap_pushr */
-#define PUSHR_CMD                      0x0
-#define PUSHR_TX                       0x2
-
 #define DMA_COMPLETION_TIMEOUT         msecs_to_jiffies(3000)
 
 struct chip_data {
        u32                     ctar_val;
-       u16                     void_write_data;
 };
 
 enum dspi_trans_mode {
        DSPI_EOQ_MODE = 0,
-       DSPI_TCFQ_MODE,
+       DSPI_XSPI_MODE,
        DSPI_DMA_MODE,
 };
 
 struct fsl_dspi_devtype_data {
        enum dspi_trans_mode    trans_mode;
        u8                      max_clock_factor;
-       bool                    ptp_sts_supported;
-       bool                    xspi_mode;
-};
-
-static const struct fsl_dspi_devtype_data vf610_data = {
-       .trans_mode             = DSPI_DMA_MODE,
-       .max_clock_factor       = 2,
-};
-
-static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
-       .trans_mode             = DSPI_TCFQ_MODE,
-       .max_clock_factor       = 8,
-       .ptp_sts_supported      = true,
-       .xspi_mode              = true,
+       int                     fifo_size;
 };
 
-static const struct fsl_dspi_devtype_data ls2085a_data = {
-       .trans_mode             = DSPI_TCFQ_MODE,
-       .max_clock_factor       = 8,
-       .ptp_sts_supported      = true,
+enum {
+       LS1021A,
+       LS1012A,
+       LS1028A,
+       LS1043A,
+       LS1046A,
+       LS2080A,
+       LS2085A,
+       LX2160A,
+       MCF5441X,
+       VF610,
 };
 
-static const struct fsl_dspi_devtype_data coldfire_data = {
-       .trans_mode             = DSPI_EOQ_MODE,
-       .max_clock_factor       = 8,
+static const struct fsl_dspi_devtype_data devtype_data[] = {
+       [VF610] = {
+               .trans_mode             = DSPI_DMA_MODE,
+               .max_clock_factor       = 2,
+               .fifo_size              = 4,
+       },
+       [LS1021A] = {
+               /* Has A-011218 DMA erratum */
+               .trans_mode             = DSPI_XSPI_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 4,
+       },
+       [LS1012A] = {
+               /* Has A-011218 DMA erratum */
+               .trans_mode             = DSPI_XSPI_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 16,
+       },
+       [LS1028A] = {
+               .trans_mode             = DSPI_XSPI_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 4,
+       },
+       [LS1043A] = {
+               /* Has A-011218 DMA erratum */
+               .trans_mode             = DSPI_XSPI_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 16,
+       },
+       [LS1046A] = {
+               /* Has A-011218 DMA erratum */
+               .trans_mode             = DSPI_XSPI_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 16,
+       },
+       [LS2080A] = {
+               .trans_mode             = DSPI_DMA_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 4,
+       },
+       [LS2085A] = {
+               .trans_mode             = DSPI_DMA_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 4,
+       },
+       [LX2160A] = {
+               .trans_mode             = DSPI_DMA_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 4,
+       },
+       [MCF5441X] = {
+               .trans_mode             = DSPI_EOQ_MODE,
+               .max_clock_factor       = 8,
+               .fifo_size              = 16,
+       },
 };
 
 struct fsl_dspi_dma {
-       /* Length of transfer in words of DSPI_FIFO_SIZE */
-       u32                                     curr_xfer_len;
-
        u32                                     *tx_dma_buf;
        struct dma_chan                         *chan_tx;
        dma_addr_t                              tx_dma_phys;
@@ -189,36 +221,99 @@ struct fsl_dspi {
        size_t                                  len;
        const void                              *tx;
        void                                    *rx;
-       void                                    *rx_end;
-       u16                                     void_write_data;
        u16                                     tx_cmd;
-       u8                                      bits_per_word;
-       u8                                      bytes_per_word;
        const struct fsl_dspi_devtype_data      *devtype_data;
 
-       wait_queue_head_t                       waitq;
-       u32                                     waitflags;
+       struct completion                       xfer_done;
 
        struct fsl_dspi_dma                     *dma;
+
+       int                                     oper_word_size;
+       int                                     oper_bits_per_word;
+
+       int                                     words_in_flight;
+
+       /*
+        * Offsets for CMD and TXDATA within SPI_PUSHR when accessed
+        * individually (in XSPI mode)
+        */
+       int                                     pushr_cmd;
+       int                                     pushr_tx;
+
+       void (*host_to_dev)(struct fsl_dspi *dspi, u32 *txdata);
+       void (*dev_to_host)(struct fsl_dspi *dspi, u32 rxdata);
 };
 
+static void dspi_native_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
+{
+       memcpy(txdata, dspi->tx, dspi->oper_word_size);
+       dspi->tx += dspi->oper_word_size;
+}
+
+static void dspi_native_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
+{
+       memcpy(dspi->rx, &rxdata, dspi->oper_word_size);
+       dspi->rx += dspi->oper_word_size;
+}
+
+static void dspi_8on32_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
+{
+       *txdata = cpu_to_be32(*(u32 *)dspi->tx);
+       dspi->tx += sizeof(u32);
+}
+
+static void dspi_8on32_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
+{
+       *(u32 *)dspi->rx = be32_to_cpu(rxdata);
+       dspi->rx += sizeof(u32);
+}
+
+static void dspi_8on16_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
+{
+       *txdata = cpu_to_be16(*(u16 *)dspi->tx);
+       dspi->tx += sizeof(u16);
+}
+
+static void dspi_8on16_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
+{
+       *(u16 *)dspi->rx = be16_to_cpu(rxdata);
+       dspi->rx += sizeof(u16);
+}
+
+static void dspi_16on32_host_to_dev(struct fsl_dspi *dspi, u32 *txdata)
+{
+       u16 hi = *(u16 *)dspi->tx;
+       u16 lo = *(u16 *)(dspi->tx + 2);
+
+       *txdata = (u32)hi << 16 | lo;
+       dspi->tx += sizeof(u32);
+}
+
+static void dspi_16on32_dev_to_host(struct fsl_dspi *dspi, u32 rxdata)
+{
+       u16 hi = rxdata & 0xffff;
+       u16 lo = rxdata >> 16;
+
+       *(u16 *)dspi->rx = lo;
+       *(u16 *)(dspi->rx + 2) = hi;
+       dspi->rx += sizeof(u32);
+}
+
+/*
+ * Pop one word from the TX buffer for pushing into the
+ * PUSHR register (TX FIFO)
+ */
 static u32 dspi_pop_tx(struct fsl_dspi *dspi)
 {
        u32 txdata = 0;
 
-       if (dspi->tx) {
-               if (dspi->bytes_per_word == 1)
-                       txdata = *(u8 *)dspi->tx;
-               else if (dspi->bytes_per_word == 2)
-                       txdata = *(u16 *)dspi->tx;
-               else  /* dspi->bytes_per_word == 4 */
-                       txdata = *(u32 *)dspi->tx;
-               dspi->tx += dspi->bytes_per_word;
-       }
-       dspi->len -= dspi->bytes_per_word;
+       if (dspi->tx)
+               dspi->host_to_dev(dspi, &txdata);
+       dspi->len -= dspi->oper_word_size;
        return txdata;
 }
 
+/* Prepare one TX FIFO entry (txdata plus cmd) */
 static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
 {
        u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
@@ -231,21 +326,12 @@ static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
        return cmd << 16 | data;
 }
 
+/* Push one word to the RX buffer from the POPR register (RX FIFO) */
 static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
 {
        if (!dspi->rx)
                return;
-
-       /* Mask off undefined bits */
-       rxdata &= (1 << dspi->bits_per_word) - 1;
-
-       if (dspi->bytes_per_word == 1)
-               *(u8 *)dspi->rx = rxdata;
-       else if (dspi->bytes_per_word == 2)
-               *(u16 *)dspi->rx = rxdata;
-       else /* dspi->bytes_per_word == 4 */
-               *(u32 *)dspi->rx = rxdata;
-       dspi->rx += dspi->bytes_per_word;
+       dspi->dev_to_host(dspi, rxdata);
 }
 
 static void dspi_tx_dma_callback(void *arg)
@@ -263,7 +349,7 @@ static void dspi_rx_dma_callback(void *arg)
        int i;
 
        if (dspi->rx) {
-               for (i = 0; i < dma->curr_xfer_len; i++)
+               for (i = 0; i < dspi->words_in_flight; i++)
                        dspi_push_rx(dspi, dspi->dma->rx_dma_buf[i]);
        }
 
@@ -277,12 +363,12 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
        int time_left;
        int i;
 
-       for (i = 0; i < dma->curr_xfer_len; i++)
+       for (i = 0; i < dspi->words_in_flight; i++)
                dspi->dma->tx_dma_buf[i] = dspi_pop_tx_pushr(dspi);
 
        dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
                                        dma->tx_dma_phys,
-                                       dma->curr_xfer_len *
+                                       dspi->words_in_flight *
                                        DMA_SLAVE_BUSWIDTH_4_BYTES,
                                        DMA_MEM_TO_DEV,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -300,7 +386,7 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
 
        dma->rx_desc = dmaengine_prep_slave_single(dma->chan_rx,
                                        dma->rx_dma_phys,
-                                       dma->curr_xfer_len *
+                                       dspi->words_in_flight *
                                        DMA_SLAVE_BUSWIDTH_4_BYTES,
                                        DMA_DEV_TO_MEM,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -348,45 +434,42 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
        return 0;
 }
 
+static void dspi_setup_accel(struct fsl_dspi *dspi);
+
 static int dspi_dma_xfer(struct fsl_dspi *dspi)
 {
        struct spi_message *message = dspi->cur_msg;
        struct device *dev = &dspi->pdev->dev;
-       struct fsl_dspi_dma *dma = dspi->dma;
-       int curr_remaining_bytes;
-       int bytes_per_buffer;
        int ret = 0;
 
-       curr_remaining_bytes = dspi->len;
-       bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE;
-       while (curr_remaining_bytes) {
-               /* Check if current transfer fits the DMA buffer */
-               dma->curr_xfer_len = curr_remaining_bytes
-                       / dspi->bytes_per_word;
-               if (dma->curr_xfer_len > bytes_per_buffer)
-                       dma->curr_xfer_len = bytes_per_buffer;
+       /*
+        * dspi->len gets decremented by dspi_pop_tx_pushr in
+        * dspi_next_xfer_dma_submit
+        */
+       while (dspi->len) {
+               /* Figure out operational bits-per-word for this chunk */
+               dspi_setup_accel(dspi);
+
+               dspi->words_in_flight = dspi->len / dspi->oper_word_size;
+               if (dspi->words_in_flight > dspi->devtype_data->fifo_size)
+                       dspi->words_in_flight = dspi->devtype_data->fifo_size;
+
+               message->actual_length += dspi->words_in_flight *
+                                         dspi->oper_word_size;
 
                ret = dspi_next_xfer_dma_submit(dspi);
                if (ret) {
                        dev_err(dev, "DMA transfer failed\n");
-                       goto exit;
-
-               } else {
-                       const int len =
-                               dma->curr_xfer_len * dspi->bytes_per_word;
-                       curr_remaining_bytes -= len;
-                       message->actual_length += len;
-                       if (curr_remaining_bytes < 0)
-                               curr_remaining_bytes = 0;
+                       break;
                }
        }
 
-exit:
        return ret;
 }
 
 static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
 {
+       int dma_bufsize = dspi->devtype_data->fifo_size * 2;
        struct device *dev = &dspi->pdev->dev;
        struct dma_slave_config cfg;
        struct fsl_dspi_dma *dma;
@@ -410,15 +493,17 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
                goto err_tx_channel;
        }
 
-       dma->tx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE,
-                                            &dma->tx_dma_phys, GFP_KERNEL);
+       dma->tx_dma_buf = dma_alloc_coherent(dma->chan_tx->device->dev,
+                                            dma_bufsize, &dma->tx_dma_phys,
+                                            GFP_KERNEL);
        if (!dma->tx_dma_buf) {
                ret = -ENOMEM;
                goto err_tx_dma_buf;
        }
 
-       dma->rx_dma_buf = dma_alloc_coherent(dev, DSPI_DMA_BUFSIZE,
-                                            &dma->rx_dma_phys, GFP_KERNEL);
+       dma->rx_dma_buf = dma_alloc_coherent(dma->chan_rx->device->dev,
+                                            dma_bufsize, &dma->rx_dma_phys,
+                                            GFP_KERNEL);
        if (!dma->rx_dma_buf) {
                ret = -ENOMEM;
                goto err_rx_dma_buf;
@@ -454,11 +539,11 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr)
        return 0;
 
 err_slave_config:
-       dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
-                       dma->rx_dma_buf, dma->rx_dma_phys);
+       dma_free_coherent(dma->chan_rx->device->dev,
+                         dma_bufsize, dma->rx_dma_buf, dma->rx_dma_phys);
 err_rx_dma_buf:
-       dma_free_coherent(dev, DSPI_DMA_BUFSIZE,
-                       dma->tx_dma_buf, dma->tx_dma_phys);
+       dma_free_coherent(dma->chan_tx->device->dev,
+                         dma_bufsize, dma->tx_dma_buf, dma->tx_dma_phys);
 err_tx_dma_buf:
        dma_release_channel(dma->chan_tx);
 err_tx_channel:
@@ -472,21 +557,21 @@ err_tx_channel:
 
 static void dspi_release_dma(struct fsl_dspi *dspi)
 {
+       int dma_bufsize = dspi->devtype_data->fifo_size * 2;
        struct fsl_dspi_dma *dma = dspi->dma;
-       struct device *dev = &dspi->pdev->dev;
 
        if (!dma)
                return;
 
        if (dma->chan_tx) {
-               dma_unmap_single(dev, dma->tx_dma_phys,
-                                DSPI_DMA_BUFSIZE, DMA_TO_DEVICE);
+               dma_unmap_single(dma->chan_tx->device->dev, dma->tx_dma_phys,
+                                dma_bufsize, DMA_TO_DEVICE);
                dma_release_channel(dma->chan_tx);
        }
 
        if (dma->chan_rx) {
-               dma_unmap_single(dev, dma->rx_dma_phys,
-                                DSPI_DMA_BUFSIZE, DMA_FROM_DEVICE);
+               dma_unmap_single(dma->chan_rx->device->dev, dma->rx_dma_phys,
+                                dma_bufsize, DMA_FROM_DEVICE);
                dma_release_channel(dma->chan_rx);
        }
 }
@@ -562,124 +647,220 @@ static void ns_delay_scale(char *psc, char *sc, int delay_ns,
        }
 }
 
-static void fifo_write(struct fsl_dspi *dspi)
+static void dspi_pushr_write(struct fsl_dspi *dspi)
 {
        regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi));
 }
 
-static void cmd_fifo_write(struct fsl_dspi *dspi)
+static void dspi_pushr_cmd_write(struct fsl_dspi *dspi, u16 cmd)
 {
-       u16 cmd = dspi->tx_cmd;
-
-       if (dspi->len > 0)
+       /*
+        * The only time when the PCS doesn't need continuation after this word
+        * is when it's last. We need to look ahead, because we actually call
+        * dspi_pop_tx (the function that decrements dspi->len) _after_
+        * dspi_pushr_cmd_write with XSPI mode. As for how much in advance? One
+        * word is enough. If there's more to transmit than that,
+        * dspi_xspi_write will know to split the FIFO writes in 2, and
+        * generate a new PUSHR command with the final word that will have PCS
+        * deasserted (not continued) here.
+        */
+       if (dspi->len > dspi->oper_word_size)
                cmd |= SPI_PUSHR_CMD_CONT;
-       regmap_write(dspi->regmap_pushr, PUSHR_CMD, cmd);
+       regmap_write(dspi->regmap_pushr, dspi->pushr_cmd, cmd);
 }
 
-static void tx_fifo_write(struct fsl_dspi *dspi, u16 txdata)
+static void dspi_pushr_txdata_write(struct fsl_dspi *dspi, u16 txdata)
 {
-       regmap_write(dspi->regmap_pushr, PUSHR_TX, txdata);
+       regmap_write(dspi->regmap_pushr, dspi->pushr_tx, txdata);
 }
 
-static void dspi_tcfq_write(struct fsl_dspi *dspi)
+static void dspi_xspi_fifo_write(struct fsl_dspi *dspi, int num_words)
 {
-       /* Clear transfer count */
-       dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
+       int num_bytes = num_words * dspi->oper_word_size;
+       u16 tx_cmd = dspi->tx_cmd;
 
-       if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) {
-               /* Write the CMD FIFO entry first, and then the two
-                * corresponding TX FIFO entries.
-                */
-               u32 data = dspi_pop_tx(dspi);
+       /*
+        * If the PCS needs to de-assert (i.e. we're at the end of the buffer
+        * and cs_change does not want the PCS to stay on), then we need a new
+        * PUSHR command, since this one (for the body of the buffer)
+        * necessarily has the CONT bit set.
+        * So send one word less during this go, to force a split and a command
+        * with a single word next time, when CONT will be unset.
+        */
+       if (!(dspi->tx_cmd & SPI_PUSHR_CMD_CONT) && num_bytes == dspi->len)
+               tx_cmd |= SPI_PUSHR_CMD_EOQ;
 
-               cmd_fifo_write(dspi);
-               tx_fifo_write(dspi, data & 0xFFFF);
-               tx_fifo_write(dspi, data >> 16);
-       } else {
-               /* Write one entry to both TX FIFO and CMD FIFO
-                * simultaneously.
-                */
-               fifo_write(dspi);
-       }
-}
+       /* Update CTARE */
+       regmap_write(dspi->regmap, SPI_CTARE(0),
+                    SPI_FRAME_EBITS(dspi->oper_bits_per_word) |
+                    SPI_CTARE_DTCP(num_words));
 
-static u32 fifo_read(struct fsl_dspi *dspi)
-{
-       u32 rxdata = 0;
+       /*
+        * Write the CMD FIFO entry first, and then the two
+        * corresponding TX FIFO entries (or one...).
+        */
+       dspi_pushr_cmd_write(dspi, tx_cmd);
 
-       regmap_read(dspi->regmap, SPI_POPR, &rxdata);
-       return rxdata;
-}
+       /* Fill TX FIFO with as many transfers as possible */
+       while (num_words--) {
+               u32 data = dspi_pop_tx(dspi);
 
-static void dspi_tcfq_read(struct fsl_dspi *dspi)
-{
-       dspi_push_rx(dspi, fifo_read(dspi));
+               dspi_pushr_txdata_write(dspi, data & 0xFFFF);
+               if (dspi->oper_bits_per_word > 16)
+                       dspi_pushr_txdata_write(dspi, data >> 16);
+       }
 }
 
-static void dspi_eoq_write(struct fsl_dspi *dspi)
+static void dspi_eoq_fifo_write(struct fsl_dspi *dspi, int num_words)
 {
-       int fifo_size = DSPI_FIFO_SIZE;
        u16 xfer_cmd = dspi->tx_cmd;
 
        /* Fill TX FIFO with as many transfers as possible */
-       while (dspi->len && fifo_size--) {
+       while (num_words--) {
                dspi->tx_cmd = xfer_cmd;
                /* Request EOQF for last transfer in FIFO */
-               if (dspi->len == dspi->bytes_per_word || fifo_size == 0)
+               if (num_words == 0)
                        dspi->tx_cmd |= SPI_PUSHR_CMD_EOQ;
-               /* Clear transfer count for first transfer in FIFO */
-               if (fifo_size == (DSPI_FIFO_SIZE - 1))
-                       dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
                /* Write combined TX FIFO and CMD FIFO entry */
-               fifo_write(dspi);
+               dspi_pushr_write(dspi);
        }
 }
 
-static void dspi_eoq_read(struct fsl_dspi *dspi)
+static u32 dspi_popr_read(struct fsl_dspi *dspi)
 {
-       int fifo_size = DSPI_FIFO_SIZE;
+       u32 rxdata = 0;
+
+       regmap_read(dspi->regmap, SPI_POPR, &rxdata);
+       return rxdata;
+}
+
+static void dspi_fifo_read(struct fsl_dspi *dspi)
+{
+       int num_fifo_entries = dspi->words_in_flight;
 
        /* Read one FIFO entry and push to rx buffer */
-       while ((dspi->rx < dspi->rx_end) && fifo_size--)
-               dspi_push_rx(dspi, fifo_read(dspi));
+       while (num_fifo_entries--)
+               dspi_push_rx(dspi, dspi_popr_read(dspi));
 }
 
-static int dspi_rxtx(struct fsl_dspi *dspi)
+static void dspi_setup_accel(struct fsl_dspi *dspi)
 {
+       struct spi_transfer *xfer = dspi->cur_transfer;
+       bool odd = !!(dspi->len & 1);
+
+       /* No accel for frames not multiple of 8 bits at the moment */
+       if (xfer->bits_per_word % 8)
+               goto no_accel;
+
+       if (!odd && dspi->len <= dspi->devtype_data->fifo_size * 2) {
+               dspi->oper_bits_per_word = 16;
+       } else if (odd && dspi->len <= dspi->devtype_data->fifo_size) {
+               dspi->oper_bits_per_word = 8;
+       } else {
+               /* Start off with maximum supported by hardware */
+               if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
+                       dspi->oper_bits_per_word = 32;
+               else
+                       dspi->oper_bits_per_word = 16;
+
+               /*
+                * And go down only if the buffer can't be sent with
+                * words this big
+                */
+               do {
+                       if (dspi->len >= DIV_ROUND_UP(dspi->oper_bits_per_word, 8))
+                               break;
+
+                       dspi->oper_bits_per_word /= 2;
+               } while (dspi->oper_bits_per_word > 8);
+       }
+
+       if (xfer->bits_per_word == 8 && dspi->oper_bits_per_word == 32) {
+               dspi->dev_to_host = dspi_8on32_dev_to_host;
+               dspi->host_to_dev = dspi_8on32_host_to_dev;
+       } else if (xfer->bits_per_word == 8 && dspi->oper_bits_per_word == 16) {
+               dspi->dev_to_host = dspi_8on16_dev_to_host;
+               dspi->host_to_dev = dspi_8on16_host_to_dev;
+       } else if (xfer->bits_per_word == 16 && dspi->oper_bits_per_word == 32) {
+               dspi->dev_to_host = dspi_16on32_dev_to_host;
+               dspi->host_to_dev = dspi_16on32_host_to_dev;
+       } else {
+no_accel:
+               dspi->dev_to_host = dspi_native_dev_to_host;
+               dspi->host_to_dev = dspi_native_host_to_dev;
+               dspi->oper_bits_per_word = xfer->bits_per_word;
+       }
+
+       dspi->oper_word_size = DIV_ROUND_UP(dspi->oper_bits_per_word, 8);
+
+       /*
+        * Update CTAR here (code is common for EOQ, XSPI and DMA modes).
+        * We will update CTARE in the portion specific to XSPI, when we
+        * also know the preload value (DTCP).
+        */
+       regmap_write(dspi->regmap, SPI_CTAR(0),
+                    dspi->cur_chip->ctar_val |
+                    SPI_FRAME_BITS(dspi->oper_bits_per_word));
+}
+
+static void dspi_fifo_write(struct fsl_dspi *dspi)
+{
+       int num_fifo_entries = dspi->devtype_data->fifo_size;
+       struct spi_transfer *xfer = dspi->cur_transfer;
        struct spi_message *msg = dspi->cur_msg;
-       enum dspi_trans_mode trans_mode;
-       u16 spi_tcnt;
-       u32 spi_tcr;
+       int num_words, num_bytes;
 
-       spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer,
-                               dspi->progress, !dspi->irq);
+       dspi_setup_accel(dspi);
+
+       /* In XSPI mode each 32-bit word occupies 2 TX FIFO entries */
+       if (dspi->oper_word_size == 4)
+               num_fifo_entries /= 2;
 
-       /* Get transfer counter (in number of SPI transfers). It was
-        * reset to 0 when transfer(s) were started.
+       /*
+        * Integer division intentionally trims off odd (or non-multiple of 4)
+        * numbers of bytes at the end of the buffer, which will be sent next
+        * time using a smaller oper_word_size.
         */
-       regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
-       spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
+       num_words = dspi->len / dspi->oper_word_size;
+       if (num_words > num_fifo_entries)
+               num_words = num_fifo_entries;
+
        /* Update total number of bytes that were transferred */
-       msg->actual_length += spi_tcnt * dspi->bytes_per_word;
-       dspi->progress += spi_tcnt;
+       num_bytes = num_words * dspi->oper_word_size;
+       msg->actual_length += num_bytes;
+       dspi->progress += num_bytes / DIV_ROUND_UP(xfer->bits_per_word, 8);
 
-       trans_mode = dspi->devtype_data->trans_mode;
-       if (trans_mode == DSPI_EOQ_MODE)
-               dspi_eoq_read(dspi);
-       else if (trans_mode == DSPI_TCFQ_MODE)
-               dspi_tcfq_read(dspi);
+       /*
+        * Update shared variable for use in the next interrupt (both in
+        * dspi_fifo_read and in dspi_fifo_write).
+        */
+       dspi->words_in_flight = num_words;
+
+       spi_take_timestamp_pre(dspi->ctlr, xfer, dspi->progress, !dspi->irq);
+
+       if (dspi->devtype_data->trans_mode == DSPI_EOQ_MODE)
+               dspi_eoq_fifo_write(dspi, num_words);
+       else
+               dspi_xspi_fifo_write(dspi, num_words);
+       /*
+        * Everything after this point is in a potential race with the next
+        * interrupt, so we must never use dspi->words_in_flight again since it
+        * might already be modified by the next dspi_fifo_write.
+        */
+
+       spi_take_timestamp_post(dspi->ctlr, dspi->cur_transfer,
+                               dspi->progress, !dspi->irq);
+}
+
+static int dspi_rxtx(struct fsl_dspi *dspi)
+{
+       dspi_fifo_read(dspi);
 
        if (!dspi->len)
                /* Success! */
                return 0;
 
-       spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
-                              dspi->progress, !dspi->irq);
-
-       if (trans_mode == DSPI_EOQ_MODE)
-               dspi_eoq_write(dspi);
-       else if (trans_mode == DSPI_TCFQ_MODE)
-               dspi_tcfq_write(dspi);
+       dspi_fifo_write(dspi);
 
        return -EINPROGRESS;
 }
@@ -693,7 +874,7 @@ static int dspi_poll(struct fsl_dspi *dspi)
                regmap_read(dspi->regmap, SPI_SR, &spi_sr);
                regmap_write(dspi->regmap, SPI_SR, spi_sr);
 
-               if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF))
+               if (spi_sr & (SPI_SR_EOQF | SPI_SR_CMDTCF))
                        break;
        } while (--tries);
 
@@ -711,13 +892,11 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
        regmap_read(dspi->regmap, SPI_SR, &spi_sr);
        regmap_write(dspi->regmap, SPI_SR, spi_sr);
 
-       if (!(spi_sr & SPI_SR_EOQF))
+       if (!(spi_sr & (SPI_SR_EOQF | SPI_SR_CMDTCF)))
                return IRQ_NONE;
 
-       if (dspi_rxtx(dspi) == 0) {
-               dspi->waitflags = 1;
-               wake_up_interruptible(&dspi->waitq);
-       }
+       if (dspi_rxtx(dspi) == 0)
+               complete(&dspi->xfer_done);
 
        return IRQ_HANDLED;
 }
@@ -727,7 +906,6 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
 {
        struct fsl_dspi *dspi = spi_controller_get_devdata(ctlr);
        struct spi_device *spi = message->spi;
-       enum dspi_trans_mode trans_mode;
        struct spi_transfer *transfer;
        int status = 0;
 
@@ -757,76 +935,38 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
                                dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
                }
 
-               dspi->void_write_data = dspi->cur_chip->void_write_data;
-
                dspi->tx = transfer->tx_buf;
                dspi->rx = transfer->rx_buf;
-               dspi->rx_end = dspi->rx + transfer->len;
                dspi->len = transfer->len;
                dspi->progress = 0;
-               /* Validated transfer specific frame size (defaults applied) */
-               dspi->bits_per_word = transfer->bits_per_word;
-               if (transfer->bits_per_word <= 8)
-                       dspi->bytes_per_word = 1;
-               else if (transfer->bits_per_word <= 16)
-                       dspi->bytes_per_word = 2;
-               else
-                       dspi->bytes_per_word = 4;
 
                regmap_update_bits(dspi->regmap, SPI_MCR,
                                   SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
                                   SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
-               regmap_write(dspi->regmap, SPI_CTAR(0),
-                            dspi->cur_chip->ctar_val |
-                            SPI_FRAME_BITS(transfer->bits_per_word));
-               if (dspi->devtype_data->xspi_mode)
-                       regmap_write(dspi->regmap, SPI_CTARE(0),
-                                    SPI_FRAME_EBITS(transfer->bits_per_word) |
-                                    SPI_CTARE_DTCP(1));
 
                spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,
                                       dspi->progress, !dspi->irq);
 
-               trans_mode = dspi->devtype_data->trans_mode;
-               switch (trans_mode) {
-               case DSPI_EOQ_MODE:
-                       regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
-                       dspi_eoq_write(dspi);
-                       break;
-               case DSPI_TCFQ_MODE:
-                       regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE);
-                       dspi_tcfq_write(dspi);
-                       break;
-               case DSPI_DMA_MODE:
-                       regmap_write(dspi->regmap, SPI_RSER,
-                                    SPI_RSER_TFFFE | SPI_RSER_TFFFD |
-                                    SPI_RSER_RFDFE | SPI_RSER_RFDFD);
+               if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
                        status = dspi_dma_xfer(dspi);
-                       break;
-               default:
-                       dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n",
-                               trans_mode);
-                       status = -EINVAL;
-                       goto out;
-               }
-
-               if (!dspi->irq) {
-                       do {
-                               status = dspi_poll(dspi);
-                       } while (status == -EINPROGRESS);
-               } else if (trans_mode != DSPI_DMA_MODE) {
-                       status = wait_event_interruptible(dspi->waitq,
-                                                         dspi->waitflags);
-                       dspi->waitflags = 0;
+               } else {
+                       dspi_fifo_write(dspi);
+
+                       if (dspi->irq) {
+                               wait_for_completion(&dspi->xfer_done);
+                               reinit_completion(&dspi->xfer_done);
+                       } else {
+                               do {
+                                       status = dspi_poll(dspi);
+                               } while (status == -EINPROGRESS);
+                       }
                }
                if (status)
-                       dev_err(&dspi->pdev->dev,
-                               "Waiting for transfer to complete failed!\n");
+                       break;
 
                spi_transfer_delay_exec(transfer);
        }
 
-out:
        message->status = status;
        spi_finalize_current_message(ctlr);
 
@@ -864,8 +1004,6 @@ static int dspi_setup(struct spi_device *spi)
                sck_cs_delay = pdata->sck_cs_delay;
        }
 
-       chip->void_write_data = 0;
-
        clkrate = clk_get_rate(dspi->clk);
        hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
 
@@ -909,9 +1047,34 @@ static void dspi_cleanup(struct spi_device *spi)
 }
 
 static const struct of_device_id fsl_dspi_dt_ids[] = {
-       { .compatible = "fsl,vf610-dspi", .data = &vf610_data, },
-       { .compatible = "fsl,ls1021a-v1.0-dspi", .data = &ls1021a_v1_data, },
-       { .compatible = "fsl,ls2085a-dspi", .data = &ls2085a_data, },
+       {
+               .compatible = "fsl,vf610-dspi",
+               .data = &devtype_data[VF610],
+       }, {
+               .compatible = "fsl,ls1021a-v1.0-dspi",
+               .data = &devtype_data[LS1021A],
+       }, {
+               .compatible = "fsl,ls1012a-dspi",
+               .data = &devtype_data[LS1012A],
+       }, {
+               .compatible = "fsl,ls1028a-dspi",
+               .data = &devtype_data[LS1028A],
+       }, {
+               .compatible = "fsl,ls1043a-dspi",
+               .data = &devtype_data[LS1043A],
+       }, {
+               .compatible = "fsl,ls1046a-dspi",
+               .data = &devtype_data[LS1046A],
+       }, {
+               .compatible = "fsl,ls2080a-dspi",
+               .data = &devtype_data[LS2080A],
+       }, {
+               .compatible = "fsl,ls2085a-dspi",
+               .data = &devtype_data[LS2085A],
+       }, {
+               .compatible = "fsl,lx2160a-dspi",
+               .data = &devtype_data[LX2160A],
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids);
@@ -997,20 +1160,40 @@ static const struct regmap_config dspi_xspi_regmap_config[] = {
        },
 };
 
-static void dspi_init(struct fsl_dspi *dspi)
+static int dspi_init(struct fsl_dspi *dspi)
 {
-       unsigned int mcr = SPI_MCR_PCSIS;
+       unsigned int mcr;
+
+       /* Set idle states for all chip select signals to high */
+       mcr = SPI_MCR_PCSIS(GENMASK(dspi->ctlr->num_chipselect - 1, 0));
 
-       if (dspi->devtype_data->xspi_mode)
+       if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
                mcr |= SPI_MCR_XSPI;
        if (!spi_controller_is_slave(dspi->ctlr))
                mcr |= SPI_MCR_MASTER;
 
        regmap_write(dspi->regmap, SPI_MCR, mcr);
        regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
-       if (dspi->devtype_data->xspi_mode)
-               regmap_write(dspi->regmap, SPI_CTARE(0),
-                            SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1));
+
+       switch (dspi->devtype_data->trans_mode) {
+       case DSPI_EOQ_MODE:
+               regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
+               break;
+       case DSPI_XSPI_MODE:
+               regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_CMDTCFE);
+               break;
+       case DSPI_DMA_MODE:
+               regmap_write(dspi->regmap, SPI_RSER,
+                            SPI_RSER_TFFFE | SPI_RSER_TFFFD |
+                            SPI_RSER_RFDFE | SPI_RSER_RFDFD);
+               break;
+       default:
+               dev_err(&dspi->pdev->dev, "unsupported trans_mode %u\n",
+                       dspi->devtype_data->trans_mode);
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 static int dspi_slave_abort(struct spi_master *master)
@@ -1021,8 +1204,10 @@ static int dspi_slave_abort(struct spi_master *master)
         * Terminate all pending DMA transactions for the SPI working
         * in SLAVE mode.
         */
-       dmaengine_terminate_sync(dspi->dma->chan_rx);
-       dmaengine_terminate_sync(dspi->dma->chan_tx);
+       if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) {
+               dmaengine_terminate_sync(dspi->dma->chan_rx);
+               dmaengine_terminate_sync(dspi->dma->chan_tx);
+       }
 
        /* Clear the internal DSPI RX and TX FIFO buffers */
        regmap_update_bits(dspi->regmap, SPI_MCR,
@@ -1032,16 +1217,33 @@ static int dspi_slave_abort(struct spi_master *master)
        return 0;
 }
 
+/*
+ * EOQ mode will inevitably deassert its PCS signal on last word in a queue
+ * (hardware limitation), so we need to inform the spi_device that larger
+ * buffers than the FIFO size are going to have the chip select randomly
+ * toggling, so it has a chance to adapt its message sizes.
+ */
+static size_t dspi_max_message_size(struct spi_device *spi)
+{
+       struct fsl_dspi *dspi = spi_controller_get_devdata(spi->controller);
+
+       if (dspi->devtype_data->trans_mode == DSPI_EOQ_MODE)
+               return dspi->devtype_data->fifo_size;
+
+       return SIZE_MAX;
+}
+
 static int dspi_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        const struct regmap_config *regmap_config;
        struct fsl_dspi_platform_data *pdata;
        struct spi_controller *ctlr;
-       int ret, cs_num, bus_num;
+       int ret, cs_num, bus_num = -1;
        struct fsl_dspi *dspi;
        struct resource *res;
        void __iomem *base;
+       bool big_endian;
 
        ctlr = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
        if (!ctlr)
@@ -1053,6 +1255,7 @@ static int dspi_probe(struct platform_device *pdev)
 
        ctlr->setup = dspi_setup;
        ctlr->transfer_one_message = dspi_transfer_one_message;
+       ctlr->max_message_size = dspi_max_message_size;
        ctlr->dev.of_node = pdev->dev.of_node;
 
        ctlr->cleanup = dspi_cleanup;
@@ -1064,7 +1267,9 @@ static int dspi_probe(struct platform_device *pdev)
                ctlr->num_chipselect = pdata->cs_num;
                ctlr->bus_num = pdata->bus_num;
 
-               dspi->devtype_data = &coldfire_data;
+               /* Only Coldfire uses platform data */
+               dspi->devtype_data = &devtype_data[MCF5441X];
+               big_endian = true;
        } else {
 
                ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
@@ -1074,11 +1279,7 @@ static int dspi_probe(struct platform_device *pdev)
                }
                ctlr->num_chipselect = cs_num;
 
-               ret = of_property_read_u32(np, "bus-num", &bus_num);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "can't get bus-num\n");
-                       goto out_ctlr_put;
-               }
+               of_property_read_u32(np, "bus-num", &bus_num);
                ctlr->bus_num = bus_num;
 
                if (of_property_read_bool(np, "spi-slave"))
@@ -1090,9 +1291,18 @@ static int dspi_probe(struct platform_device *pdev)
                        ret = -EFAULT;
                        goto out_ctlr_put;
                }
+
+               big_endian = of_device_is_big_endian(np);
+       }
+       if (big_endian) {
+               dspi->pushr_cmd = 0;
+               dspi->pushr_tx = 2;
+       } else {
+               dspi->pushr_cmd = 2;
+               dspi->pushr_tx = 0;
        }
 
-       if (dspi->devtype_data->xspi_mode)
+       if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
                ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        else
                ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
@@ -1104,7 +1314,7 @@ static int dspi_probe(struct platform_device *pdev)
                goto out_ctlr_put;
        }
 
-       if (dspi->devtype_data->xspi_mode)
+       if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)
                regmap_config = &dspi_xspi_regmap_config[0];
        else
                regmap_config = &dspi_regmap_config;
@@ -1116,7 +1326,7 @@ static int dspi_probe(struct platform_device *pdev)
                goto out_ctlr_put;
        }
 
-       if (dspi->devtype_data->xspi_mode) {
+       if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE) {
                dspi->regmap_pushr = devm_regmap_init_mmio(
                        &pdev->dev, base + SPI_PUSHR,
                        &dspi_xspi_regmap_config[1]);
@@ -1139,10 +1349,9 @@ static int dspi_probe(struct platform_device *pdev)
        if (ret)
                goto out_ctlr_put;
 
-       dspi_init(dspi);
-
-       if (dspi->devtype_data->trans_mode == DSPI_TCFQ_MODE)
-               goto poll_mode;
+       ret = dspi_init(dspi);
+       if (ret)
+               goto out_clk_put;
 
        dspi->irq = platform_get_irq(pdev, 0);
        if (dspi->irq <= 0) {
@@ -1159,7 +1368,7 @@ static int dspi_probe(struct platform_device *pdev)
                goto out_clk_put;
        }
 
-       init_waitqueue_head(&dspi->waitq);
+       init_completion(&dspi->xfer_done);
 
 poll_mode:
 
@@ -1174,7 +1383,8 @@ poll_mode:
        ctlr->max_speed_hz =
                clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
 
-       ctlr->ptp_sts_supported = dspi->devtype_data->ptp_sts_supported;
+       if (dspi->devtype_data->trans_mode != DSPI_DMA_MODE)
+               ctlr->ptp_sts_supported = true;
 
        platform_set_drvdata(pdev, ctlr);
 
index d0b8cc7..8b41b70 100644 (file)
@@ -86,8 +86,6 @@
 #define TCR_RXMSK      BIT(19)
 #define TCR_TXMSK      BIT(18)
 
-static int clkdivs[] = {1, 2, 4, 8, 16, 32, 64, 128};
-
 struct lpspi_config {
        u8 bpw;
        u8 chip_select;
@@ -125,7 +123,7 @@ struct fsl_lpspi_data {
        struct completion dma_rx_completion;
        struct completion dma_tx_completion;
 
-       int chipselect[0];
+       int chipselect[];
 };
 
 static const struct of_device_id fsl_lpspi_dt_ids[] = {
@@ -331,15 +329,14 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data *fsl_lpspi)
        }
 
        for (prescale = 0; prescale < 8; prescale++) {
-               scldiv = perclk_rate /
-                        (clkdivs[prescale] * config.speed_hz) - 2;
+               scldiv = perclk_rate / config.speed_hz / (1 << prescale) - 2;
                if (scldiv < 256) {
                        fsl_lpspi->config.prescale = prescale;
                        break;
                }
        }
 
-       if (prescale == 8 && scldiv >= 256)
+       if (scldiv >= 256)
                return -EINVAL;
 
        writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16),
index e8a499c..02e5cba 100644 (file)
@@ -484,7 +484,7 @@ static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q)
        }
 
        if (needs_wakeup_wait_mode(q))
-               pm_qos_add_request(&q->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, 0);
+               cpu_latency_qos_add_request(&q->pm_qos_req, 0);
 
        return 0;
 }
@@ -492,7 +492,7 @@ static int fsl_qspi_clk_prep_enable(struct fsl_qspi *q)
 static void fsl_qspi_clk_disable_unprep(struct fsl_qspi *q)
 {
        if (needs_wakeup_wait_mode(q))
-               pm_qos_remove_request(&q->pm_qos_req);
+               cpu_latency_qos_remove_request(&q->pm_qos_req);
 
        clk_disable_unprepare(q->clk);
        clk_disable_unprepare(q->clk_en);
index 6f3d64a..c397242 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/io.h>
 #include <linux/log2.h>
 #include <linux/module.h>
-#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/qcom-geni-se.h>
@@ -536,6 +535,7 @@ static int spi_geni_probe(struct platform_device *pdev)
        struct spi_geni_master *mas;
        void __iomem *base;
        struct clk *clk;
+       struct device *dev = &pdev->dev;
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
@@ -545,28 +545,25 @@ static int spi_geni_probe(struct platform_device *pdev)
        if (IS_ERR(base))
                return PTR_ERR(base);
 
-       clk = devm_clk_get(&pdev->dev, "se");
-       if (IS_ERR(clk)) {
-               dev_err(&pdev->dev, "Err getting SE Core clk %ld\n",
-                                               PTR_ERR(clk));
+       clk = devm_clk_get(dev, "se");
+       if (IS_ERR(clk))
                return PTR_ERR(clk);
-       }
 
-       spi = spi_alloc_master(&pdev->dev, sizeof(*mas));
+       spi = spi_alloc_master(dev, sizeof(*mas));
        if (!spi)
                return -ENOMEM;
 
        platform_set_drvdata(pdev, spi);
        mas = spi_master_get_devdata(spi);
        mas->irq = irq;
-       mas->dev = &pdev->dev;
-       mas->se.dev = &pdev->dev;
-       mas->se.wrapper = dev_get_drvdata(pdev->dev.parent);
+       mas->dev = dev;
+       mas->se.dev = dev;
+       mas->se.wrapper = dev_get_drvdata(dev->parent);
        mas->se.base = base;
        mas->se.clk = clk;
 
        spi->bus_num = -1;
-       spi->dev.of_node = pdev->dev.of_node;
+       spi->dev.of_node = dev->of_node;
        spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH;
        spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        spi->num_chipselect = 4;
@@ -579,14 +576,13 @@ static int spi_geni_probe(struct platform_device *pdev)
 
        init_completion(&mas->xfer_done);
        spin_lock_init(&mas->lock);
-       pm_runtime_enable(&pdev->dev);
+       pm_runtime_enable(dev);
 
        ret = spi_geni_init(mas);
        if (ret)
                goto spi_geni_probe_runtime_disable;
 
-       ret = request_irq(mas->irq, geni_spi_isr,
-                       IRQF_TRIGGER_HIGH, "spi_geni", spi);
+       ret = request_irq(mas->irq, geni_spi_isr, 0, dev_name(dev), spi);
        if (ret)
                goto spi_geni_probe_runtime_disable;
 
@@ -598,7 +594,7 @@ static int spi_geni_probe(struct platform_device *pdev)
 spi_geni_probe_free_irq:
        free_irq(mas->irq, spi);
 spi_geni_probe_runtime_disable:
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_disable(dev);
        spi_master_put(spi);
        return ret;
 }
index 4cf8fc8..e3b5725 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/acpi.h>
 #include <linux/bitops.h>
+#include <linux/dmi.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #define HISI_SFC_V3XX_VERSION (0x1f8)
 
 #define HISI_SFC_V3XX_CMD_CFG (0x300)
+#define HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT (1 << 17)
+#define HISI_SFC_V3XX_CMD_CFG_DUAL_IO (2 << 17)
+#define HISI_SFC_V3XX_CMD_CFG_FULL_DIO (3 << 17)
+#define HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT (5 << 17)
+#define HISI_SFC_V3XX_CMD_CFG_QUAD_IO (6 << 17)
+#define HISI_SFC_V3XX_CMD_CFG_FULL_QIO (7 << 17)
 #define HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF 9
 #define HISI_SFC_V3XX_CMD_CFG_RW_MSK BIT(8)
 #define HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK BIT(7)
@@ -161,6 +168,43 @@ static int hisi_sfc_v3xx_generic_exec_op(struct hisi_sfc_v3xx_host *host,
        if (op->addr.nbytes)
                config |= HISI_SFC_V3XX_CMD_CFG_ADDR_EN_MSK;
 
+       switch (op->data.buswidth) {
+       case 0 ... 1:
+               break;
+       case 2:
+               if (op->addr.buswidth <= 1) {
+                       config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IN_DUAL_OUT;
+               } else if (op->addr.buswidth == 2) {
+                       if (op->cmd.buswidth <= 1) {
+                               config |= HISI_SFC_V3XX_CMD_CFG_DUAL_IO;
+                       } else if (op->cmd.buswidth == 2) {
+                               config |= HISI_SFC_V3XX_CMD_CFG_FULL_DIO;
+                       } else {
+                               return -EIO;
+                       }
+               } else {
+                       return -EIO;
+               }
+               break;
+       case 4:
+               if (op->addr.buswidth <= 1) {
+                       config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IN_QUAD_OUT;
+               } else if (op->addr.buswidth == 4) {
+                       if (op->cmd.buswidth <= 1) {
+                               config |= HISI_SFC_V3XX_CMD_CFG_QUAD_IO;
+                       } else if (op->cmd.buswidth == 4) {
+                               config |= HISI_SFC_V3XX_CMD_CFG_FULL_QIO;
+                       } else {
+                               return -EIO;
+                       }
+               } else {
+                       return -EIO;
+               }
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
        if (op->data.dir != SPI_MEM_NO_DATA) {
                config |= (len - 1) << HISI_SFC_V3XX_CMD_CFG_DATA_CNT_OFF;
                config |= HISI_SFC_V3XX_CMD_CFG_DATA_EN_MSK;
@@ -207,6 +251,44 @@ static const struct spi_controller_mem_ops hisi_sfc_v3xx_mem_ops = {
        .exec_op = hisi_sfc_v3xx_exec_op,
 };
 
+static int hisi_sfc_v3xx_buswidth_override_bits;
+
+/*
+ * ACPI FW does not allow us to currently set the device buswidth, so quirk it
+ * depending on the board.
+ */
+static int __init hisi_sfc_v3xx_dmi_quirk(const struct dmi_system_id *d)
+{
+       hisi_sfc_v3xx_buswidth_override_bits = SPI_RX_QUAD | SPI_TX_QUAD;
+
+       return 0;
+}
+
+static const struct dmi_system_id hisi_sfc_v3xx_dmi_quirk_table[]  = {
+       {
+       .callback = hisi_sfc_v3xx_dmi_quirk,
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "D06"),
+       },
+       },
+       {
+       .callback = hisi_sfc_v3xx_dmi_quirk,
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 2280 V2"),
+       },
+       },
+       {
+       .callback = hisi_sfc_v3xx_dmi_quirk,
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Huawei"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "TaiShan 200 (Model 2280)"),
+       },
+       },
+       {}
+};
+
 static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -222,6 +304,8 @@ static int hisi_sfc_v3xx_probe(struct platform_device *pdev)
        ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
                          SPI_TX_DUAL | SPI_TX_QUAD;
 
+       ctlr->buswidth_override_bits = hisi_sfc_v3xx_buswidth_override_bits;
+
        host = spi_controller_get_devdata(ctlr);
        host->dev = dev;
 
@@ -277,7 +361,20 @@ static struct platform_driver hisi_sfc_v3xx_spi_driver = {
        .probe  = hisi_sfc_v3xx_probe,
 };
 
-module_platform_driver(hisi_sfc_v3xx_spi_driver);
+static int __init hisi_sfc_v3xx_spi_init(void)
+{
+       dmi_check_system(hisi_sfc_v3xx_dmi_quirk_table);
+
+       return platform_driver_register(&hisi_sfc_v3xx_spi_driver);
+}
+
+static void __exit hisi_sfc_v3xx_spi_exit(void)
+{
+       platform_driver_unregister(&hisi_sfc_v3xx_spi_driver);
+}
+
+module_init(hisi_sfc_v3xx_spi_init);
+module_exit(hisi_sfc_v3xx_spi_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
index e5a46f0..adaa0c4 100644 (file)
@@ -418,12 +418,13 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
        struct spi_controller *ctlr = mem->spi->controller;
        size_t len;
 
-       len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
-
        if (ctlr->mem_ops && ctlr->mem_ops->adjust_op_size)
                return ctlr->mem_ops->adjust_op_size(mem, op);
 
        if (!ctlr->mem_ops || !ctlr->mem_ops->exec_op) {
+               len = sizeof(op->cmd.opcode) + op->addr.nbytes +
+                     op->dummy.nbytes;
+
                if (len > spi_max_transfer_size(mem->spi))
                        return -EINVAL;
 
@@ -487,7 +488,7 @@ static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc,
  * This function is creating a direct mapping descriptor which can then be used
  * to access the memory using spi_mem_dirmap_read() or spi_mem_dirmap_write().
  * If the SPI controller driver does not support direct mapping, this function
- * fallback to an implementation using spi_mem_exec_op(), so that the caller
+ * fallback to an implementation using spi_mem_exec_op(), so that the caller
  * doesn't have to bother implementing a fallback on his own.
  *
  * Return: a valid pointer in case of success, and ERR_PTR() otherwise.
index 7f5680f..77f7d0e 100644 (file)
@@ -9,11 +9,13 @@
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/types.h>
@@ -33,7 +35,6 @@
  *   to have a CS go down over the full transfer
  */
 
-#define SPICC_MAX_FREQ 30000000
 #define SPICC_MAX_BURST        128
 
 /* Register Map */
 #define SPICC_SWAP_RO          BIT(14) /* RX FIFO Data Swap Read-Only */
 #define SPICC_SWAP_W1          BIT(15) /* RX FIFO Data Swap Write-Only */
 #define SPICC_DLYCTL_RO_MASK   GENMASK(20, 15) /* Delay Control Read-Only */
-#define SPICC_DLYCTL_W1_MASK   GENMASK(21, 16) /* Delay Control Write-Only */
+#define SPICC_MO_DELAY_MASK    GENMASK(17, 16) /* Master Output Delay */
+#define SPICC_MO_NO_DELAY      0
+#define SPICC_MO_DELAY_1_CYCLE 1
+#define SPICC_MO_DELAY_2_CYCLE 2
+#define SPICC_MO_DELAY_3_CYCLE 3
+#define SPICC_MI_DELAY_MASK    GENMASK(19, 18) /* Master Input Delay */
+#define SPICC_MI_NO_DELAY      0
+#define SPICC_MI_DELAY_1_CYCLE 1
+#define SPICC_MI_DELAY_2_CYCLE 2
+#define SPICC_MI_DELAY_3_CYCLE 3
+#define SPICC_MI_CAP_DELAY_MASK        GENMASK(21, 20) /* Master Capture Delay */
+#define SPICC_CAP_AHEAD_2_CYCLE        0
+#define SPICC_CAP_AHEAD_1_CYCLE        1
+#define SPICC_CAP_NO_DELAY     2
+#define SPICC_CAP_DELAY_1_CYCLE        3
 #define SPICC_FIFORST_RO_MASK  GENMASK(22, 21) /* FIFO Softreset Read-Only */
 #define SPICC_FIFORST_W1_MASK  GENMASK(23, 22) /* FIFO Softreset Write-Only */
 
 
 #define SPICC_DWADDR   0x24    /* Write Address of DMA */
 
+#define SPICC_ENH_CTL0 0x38    /* Enhanced Feature */
+#define SPICC_ENH_CLK_CS_DELAY_MASK    GENMASK(15, 0)
+#define SPICC_ENH_DATARATE_MASK                GENMASK(23, 16)
+#define SPICC_ENH_DATARATE_EN          BIT(24)
+#define SPICC_ENH_MOSI_OEN             BIT(25)
+#define SPICC_ENH_CLK_OEN              BIT(26)
+#define SPICC_ENH_CS_OEN               BIT(27)
+#define SPICC_ENH_CLK_CS_DELAY_EN      BIT(28)
+#define SPICC_ENH_MAIN_CLK_AO          BIT(29)
+
 #define writel_bits_relaxed(mask, val, addr) \
        writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr)
 
-#define SPICC_BURST_MAX        16
-#define SPICC_FIFO_HALF 10
+struct meson_spicc_data {
+       unsigned int                    max_speed_hz;
+       unsigned int                    min_speed_hz;
+       unsigned int                    fifo_size;
+       bool                            has_oen;
+       bool                            has_enhance_clk_div;
+       bool                            has_pclk;
+};
 
 struct meson_spicc_device {
        struct spi_master               *master;
        struct platform_device          *pdev;
        void __iomem                    *base;
        struct clk                      *core;
+       struct clk                      *pclk;
+       struct clk                      *clk;
        struct spi_message              *message;
        struct spi_transfer             *xfer;
+       const struct meson_spicc_data   *data;
        u8                              *tx_buf;
        u8                              *rx_buf;
        unsigned int                    bytes_per_word;
        unsigned long                   tx_remain;
-       unsigned long                   txb_remain;
        unsigned long                   rx_remain;
-       unsigned long                   rxb_remain;
        unsigned long                   xfer_remain;
-       bool                            is_burst_end;
-       bool                            is_last_burst;
 };
 
+static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
+{
+       u32 conf;
+
+       if (!spicc->data->has_oen)
+               return;
+
+       conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) |
+               SPICC_ENH_MOSI_OEN | SPICC_ENH_CLK_OEN | SPICC_ENH_CS_OEN;
+
+       writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0);
+}
+
 static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc)
 {
        return !!FIELD_GET(SPICC_TF,
@@ -146,7 +189,7 @@ static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc)
 
 static inline bool meson_spicc_rxready(struct meson_spicc_device *spicc)
 {
-       return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF_EN,
+       return FIELD_GET(SPICC_RH | SPICC_RR | SPICC_RF,
                         readl_relaxed(spicc->base + SPICC_STATREG));
 }
 
@@ -201,34 +244,22 @@ static inline void meson_spicc_tx(struct meson_spicc_device *spicc)
                               spicc->base + SPICC_TXDATA);
 }
 
-static inline u32 meson_spicc_setup_rx_irq(struct meson_spicc_device *spicc,
-                                          u32 irq_ctrl)
+static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc)
 {
-       if (spicc->rx_remain > SPICC_FIFO_HALF)
-               irq_ctrl |= SPICC_RH_EN;
-       else
-               irq_ctrl |= SPICC_RR_EN;
-
-       return irq_ctrl;
-}
 
-static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc,
-                                          unsigned int burst_len)
-{
+       unsigned int burst_len = min_t(unsigned int,
+                                      spicc->xfer_remain /
+                                      spicc->bytes_per_word,
+                                      spicc->data->fifo_size);
        /* Setup Xfer variables */
        spicc->tx_remain = burst_len;
        spicc->rx_remain = burst_len;
        spicc->xfer_remain -= burst_len * spicc->bytes_per_word;
-       spicc->is_burst_end = false;
-       if (burst_len < SPICC_BURST_MAX || !spicc->xfer_remain)
-               spicc->is_last_burst = true;
-       else
-               spicc->is_last_burst = false;
 
        /* Setup burst length */
        writel_bits_relaxed(SPICC_BURSTLENGTH_MASK,
                        FIELD_PREP(SPICC_BURSTLENGTH_MASK,
-                               burst_len),
+                               burst_len - 1),
                        spicc->base + SPICC_CONREG);
 
        /* Fill TX FIFO */
@@ -238,97 +269,71 @@ static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc,
 static irqreturn_t meson_spicc_irq(int irq, void *data)
 {
        struct meson_spicc_device *spicc = (void *) data;
-       u32 ctrl = readl_relaxed(spicc->base + SPICC_INTREG);
-       u32 stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl;
 
-       ctrl &= ~(SPICC_RH_EN | SPICC_RR_EN);
+       writel_bits_relaxed(SPICC_TC, SPICC_TC, spicc->base + SPICC_STATREG);
 
        /* Empty RX FIFO */
        meson_spicc_rx(spicc);
 
-       /* Enable TC interrupt since we transferred everything */
-       if (!spicc->tx_remain && !spicc->rx_remain) {
-               spicc->is_burst_end = true;
-
-               /* Enable TC interrupt */
-               ctrl |= SPICC_TC_EN;
+       if (!spicc->xfer_remain) {
+               /* Disable all IRQs */
+               writel(0, spicc->base + SPICC_INTREG);
 
-               /* Reload IRQ status */
-               stat = readl_relaxed(spicc->base + SPICC_STATREG) & ctrl;
-       }
-
-       /* Check transfer complete */
-       if ((stat & SPICC_TC) && spicc->is_burst_end) {
-               unsigned int burst_len;
-
-               /* Clear TC bit */
-               writel_relaxed(SPICC_TC, spicc->base + SPICC_STATREG);
-
-               /* Disable TC interrupt */
-               ctrl &= ~SPICC_TC_EN;
-
-               if (spicc->is_last_burst) {
-                       /* Disable all IRQs */
-                       writel(0, spicc->base + SPICC_INTREG);
-
-                       spi_finalize_current_transfer(spicc->master);
-
-                       return IRQ_HANDLED;
-               }
-
-               burst_len = min_t(unsigned int,
-                                 spicc->xfer_remain / spicc->bytes_per_word,
-                                 SPICC_BURST_MAX);
+               spi_finalize_current_transfer(spicc->master);
 
-               /* Setup burst */
-               meson_spicc_setup_burst(spicc, burst_len);
-
-               /* Restart burst */
-               writel_bits_relaxed(SPICC_XCH, SPICC_XCH,
-                                   spicc->base + SPICC_CONREG);
+               return IRQ_HANDLED;
        }
 
-       /* Setup RX interrupt trigger */
-       ctrl = meson_spicc_setup_rx_irq(spicc, ctrl);
+       /* Setup burst */
+       meson_spicc_setup_burst(spicc);
 
-       /* Reconfigure interrupts */
-       writel(ctrl, spicc->base + SPICC_INTREG);
+       /* Start burst */
+       writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
 
        return IRQ_HANDLED;
 }
 
-static u32 meson_spicc_setup_speed(struct meson_spicc_device *spicc, u32 conf,
-                                  u32 speed)
+static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc)
 {
-       unsigned long parent, value;
-       unsigned int i, div;
-
-       parent = clk_get_rate(spicc->core);
-
-       /* Find closest inferior/equal possible speed */
-       for (i = 0 ; i < 7 ; ++i) {
-               /* 2^(data_rate+2) */
-               value = parent >> (i + 2);
-
-               if (value <= speed)
-                       break;
+       u32 div, hz;
+       u32 mi_delay, cap_delay;
+       u32 conf;
+
+       if (spicc->data->has_enhance_clk_div) {
+               div = FIELD_GET(SPICC_ENH_DATARATE_MASK,
+                               readl_relaxed(spicc->base + SPICC_ENH_CTL0));
+               div++;
+               div <<= 1;
+       } else {
+               div = FIELD_GET(SPICC_DATARATE_MASK,
+                               readl_relaxed(spicc->base + SPICC_CONREG));
+               div += 2;
+               div = 1 << div;
        }
 
-       /* If provided speed it lower than max divider, use max divider */
-       if (i > 7) {
-               div = 7;
-               dev_warn_once(&spicc->pdev->dev, "unable to get close to speed %u\n",
-                             speed);
-       } else
-               div = i;
-
-       dev_dbg(&spicc->pdev->dev, "parent %lu, speed %u -> %lu (%u)\n",
-               parent, speed, value, div);
-
-       conf &= ~SPICC_DATARATE_MASK;
-       conf |= FIELD_PREP(SPICC_DATARATE_MASK, div);
-
-       return conf;
+       mi_delay = SPICC_MI_NO_DELAY;
+       cap_delay = SPICC_CAP_AHEAD_2_CYCLE;
+       hz = clk_get_rate(spicc->clk);
+
+       if (hz >= 100000000)
+               cap_delay = SPICC_CAP_DELAY_1_CYCLE;
+       else if (hz >= 80000000)
+               cap_delay = SPICC_CAP_NO_DELAY;
+       else if (hz >= 40000000)
+               cap_delay = SPICC_CAP_AHEAD_1_CYCLE;
+       else if (div >= 16)
+               mi_delay = SPICC_MI_DELAY_3_CYCLE;
+       else if (div >= 8)
+               mi_delay = SPICC_MI_DELAY_2_CYCLE;
+       else if (div >= 6)
+               mi_delay = SPICC_MI_DELAY_1_CYCLE;
+
+       conf = readl_relaxed(spicc->base + SPICC_TESTREG);
+       conf &= ~(SPICC_MO_DELAY_MASK | SPICC_MI_DELAY_MASK
+                 | SPICC_MI_CAP_DELAY_MASK);
+       conf |= FIELD_PREP(SPICC_MI_DELAY_MASK, mi_delay);
+       conf |= FIELD_PREP(SPICC_MI_CAP_DELAY_MASK, cap_delay);
+       writel_relaxed(conf, spicc->base + SPICC_TESTREG);
 }
 
 static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
@@ -339,9 +344,6 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
        /* Read original configuration */
        conf = conf_orig = readl_relaxed(spicc->base + SPICC_CONREG);
 
-       /* Select closest divider */
-       conf = meson_spicc_setup_speed(spicc, conf, xfer->speed_hz);
-
        /* Setup word width */
        conf &= ~SPICC_BITLENGTH_MASK;
        conf |= FIELD_PREP(SPICC_BITLENGTH_MASK,
@@ -350,6 +352,32 @@ static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
        /* Ignore if unchanged */
        if (conf != conf_orig)
                writel_relaxed(conf, spicc->base + SPICC_CONREG);
+
+       clk_set_rate(spicc->clk, xfer->speed_hz);
+
+       meson_spicc_auto_io_delay(spicc);
+
+       writel_relaxed(0, spicc->base + SPICC_DMAREG);
+}
+
+static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc)
+{
+       u32 data;
+
+       if (spicc->data->has_oen)
+               writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO,
+                                   SPICC_ENH_MAIN_CLK_AO,
+                                   spicc->base + SPICC_ENH_CTL0);
+
+       writel_bits_relaxed(SPICC_FIFORST_W1_MASK, SPICC_FIFORST_W1_MASK,
+                           spicc->base + SPICC_TESTREG);
+
+       while (meson_spicc_rxready(spicc))
+               data = readl_relaxed(spicc->base + SPICC_RXDATA);
+
+       if (spicc->data->has_oen)
+               writel_bits_relaxed(SPICC_ENH_MAIN_CLK_AO, 0,
+                                   spicc->base + SPICC_ENH_CTL0);
 }
 
 static int meson_spicc_transfer_one(struct spi_master *master,
@@ -357,8 +385,6 @@ static int meson_spicc_transfer_one(struct spi_master *master,
                                    struct spi_transfer *xfer)
 {
        struct meson_spicc_device *spicc = spi_master_get_devdata(master);
-       unsigned int burst_len;
-       u32 irq = 0;
 
        /* Store current transfer */
        spicc->xfer = xfer;
@@ -372,22 +398,22 @@ static int meson_spicc_transfer_one(struct spi_master *master,
        spicc->bytes_per_word =
           DIV_ROUND_UP(spicc->xfer->bits_per_word, 8);
 
+       if (xfer->len % spicc->bytes_per_word)
+               return -EINVAL;
+
        /* Setup transfer parameters */
        meson_spicc_setup_xfer(spicc, xfer);
 
-       burst_len = min_t(unsigned int,
-                         spicc->xfer_remain / spicc->bytes_per_word,
-                         SPICC_BURST_MAX);
+       meson_spicc_reset_fifo(spicc);
 
-       meson_spicc_setup_burst(spicc, burst_len);
-
-       irq = meson_spicc_setup_rx_irq(spicc, irq);
+       /* Setup burst */
+       meson_spicc_setup_burst(spicc);
 
        /* Start burst */
        writel_bits_relaxed(SPICC_XCH, SPICC_XCH, spicc->base + SPICC_CONREG);
 
        /* Enable interrupts */
-       writel_relaxed(irq, spicc->base + SPICC_INTREG);
+       writel_relaxed(SPICC_TC_EN, spicc->base + SPICC_INTREG);
 
        return 1;
 }
@@ -444,7 +470,7 @@ static int meson_spicc_prepare_message(struct spi_master *master,
        /* Setup no wait cycles by default */
        writel_relaxed(0, spicc->base + SPICC_PERIODREG);
 
-       writel_bits_relaxed(BIT(24), BIT(24), spicc->base + SPICC_TESTREG);
+       writel_bits_relaxed(SPICC_LBC_W1, 0, spicc->base + SPICC_TESTREG);
 
        return 0;
 }
@@ -456,9 +482,6 @@ static int meson_spicc_unprepare_transfer(struct spi_master *master)
        /* Disable all IRQs */
        writel(0, spicc->base + SPICC_INTREG);
 
-       /* Disable controller */
-       writel_bits_relaxed(SPICC_ENABLE, 0, spicc->base + SPICC_CONREG);
-
        device_reset_optional(&spicc->pdev->dev);
 
        return 0;
@@ -477,11 +500,167 @@ static void meson_spicc_cleanup(struct spi_device *spi)
        spi->controller_state = NULL;
 }
 
+/*
+ * The Clock Mux
+ *            x-----------------x   x------------x    x------\
+ *        |---| pow2 fixed div  |---| pow2 div   |----|      |
+ *        |   x-----------------x   x------------x    |      |
+ * src ---|                                           | mux  |-- out
+ *        |   x-----------------x   x------------x    |      |
+ *        |---| enh fixed div   |---| enh div    |0---|      |
+ *            x-----------------x   x------------x    x------/
+ *
+ * Clk path for GX series:
+ *    src -> pow2 fixed div -> pow2 div -> out
+ *
+ * Clk path for AXG series:
+ *    src -> pow2 fixed div -> pow2 div -> mux -> out
+ *    src -> enh fixed div -> enh div -> mux -> out
+ *
+ * Clk path for G12A series:
+ *    pclk -> pow2 fixed div -> pow2 div -> mux -> out
+ *    pclk -> enh fixed div -> enh div -> mux -> out
+ */
+
+static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
+{
+       struct device *dev = &spicc->pdev->dev;
+       struct clk_fixed_factor *pow2_fixed_div, *enh_fixed_div;
+       struct clk_divider *pow2_div, *enh_div;
+       struct clk_mux *mux;
+       struct clk_init_data init;
+       struct clk *clk;
+       struct clk_parent_data parent_data[2];
+       char name[64];
+
+       memset(&init, 0, sizeof(init));
+       memset(&parent_data, 0, sizeof(parent_data));
+
+       init.parent_data = parent_data;
+
+       /* algorithm for pow2 div: rate = freq / 4 / (2 ^ N) */
+
+       pow2_fixed_div = devm_kzalloc(dev, sizeof(*pow2_fixed_div), GFP_KERNEL);
+       if (!pow2_fixed_div)
+               return -ENOMEM;
+
+       snprintf(name, sizeof(name), "%s#pow2_fixed_div", dev_name(dev));
+       init.name = name;
+       init.ops = &clk_fixed_factor_ops;
+       init.flags = 0;
+       if (spicc->data->has_pclk)
+               parent_data[0].hw = __clk_get_hw(spicc->pclk);
+       else
+               parent_data[0].hw = __clk_get_hw(spicc->core);
+       init.num_parents = 1;
+
+       pow2_fixed_div->mult = 1,
+       pow2_fixed_div->div = 4,
+       pow2_fixed_div->hw.init = &init;
+
+       clk = devm_clk_register(dev, &pow2_fixed_div->hw);
+       if (WARN_ON(IS_ERR(clk)))
+               return PTR_ERR(clk);
+
+       pow2_div = devm_kzalloc(dev, sizeof(*pow2_div), GFP_KERNEL);
+       if (!pow2_div)
+               return -ENOMEM;
+
+       snprintf(name, sizeof(name), "%s#pow2_div", dev_name(dev));
+       init.name = name;
+       init.ops = &clk_divider_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       parent_data[0].hw = &pow2_fixed_div->hw;
+       init.num_parents = 1;
+
+       pow2_div->shift = 16,
+       pow2_div->width = 3,
+       pow2_div->flags = CLK_DIVIDER_POWER_OF_TWO,
+       pow2_div->reg = spicc->base + SPICC_CONREG;
+       pow2_div->hw.init = &init;
+
+       clk = devm_clk_register(dev, &pow2_div->hw);
+       if (WARN_ON(IS_ERR(clk)))
+               return PTR_ERR(clk);
+
+       if (!spicc->data->has_enhance_clk_div) {
+               spicc->clk = clk;
+               return 0;
+       }
+
+       /* algorithm for enh div: rate = freq / 2 / (N + 1) */
+
+       enh_fixed_div = devm_kzalloc(dev, sizeof(*enh_fixed_div), GFP_KERNEL);
+       if (!enh_fixed_div)
+               return -ENOMEM;
+
+       snprintf(name, sizeof(name), "%s#enh_fixed_div", dev_name(dev));
+       init.name = name;
+       init.ops = &clk_fixed_factor_ops;
+       init.flags = 0;
+       if (spicc->data->has_pclk)
+               parent_data[0].hw = __clk_get_hw(spicc->pclk);
+       else
+               parent_data[0].hw = __clk_get_hw(spicc->core);
+       init.num_parents = 1;
+
+       enh_fixed_div->mult = 1,
+       enh_fixed_div->div = 2,
+       enh_fixed_div->hw.init = &init;
+
+       clk = devm_clk_register(dev, &enh_fixed_div->hw);
+       if (WARN_ON(IS_ERR(clk)))
+               return PTR_ERR(clk);
+
+       enh_div = devm_kzalloc(dev, sizeof(*enh_div), GFP_KERNEL);
+       if (!enh_div)
+               return -ENOMEM;
+
+       snprintf(name, sizeof(name), "%s#enh_div", dev_name(dev));
+       init.name = name;
+       init.ops = &clk_divider_ops;
+       init.flags = CLK_SET_RATE_PARENT;
+       parent_data[0].hw = &enh_fixed_div->hw;
+       init.num_parents = 1;
+
+       enh_div->shift  = 16,
+       enh_div->width  = 8,
+       enh_div->reg = spicc->base + SPICC_ENH_CTL0;
+       enh_div->hw.init = &init;
+
+       clk = devm_clk_register(dev, &enh_div->hw);
+       if (WARN_ON(IS_ERR(clk)))
+               return PTR_ERR(clk);
+
+       mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
+       if (!mux)
+               return -ENOMEM;
+
+       snprintf(name, sizeof(name), "%s#sel", dev_name(dev));
+       init.name = name;
+       init.ops = &clk_mux_ops;
+       parent_data[0].hw = &pow2_div->hw;
+       parent_data[1].hw = &enh_div->hw;
+       init.num_parents = 2;
+       init.flags = CLK_SET_RATE_PARENT;
+
+       mux->mask = 0x1,
+       mux->shift = 24,
+       mux->reg = spicc->base + SPICC_ENH_CTL0;
+       mux->hw.init = &init;
+
+       spicc->clk = devm_clk_register(dev, &mux->hw);
+       if (WARN_ON(IS_ERR(spicc->clk)))
+               return PTR_ERR(spicc->clk);
+
+       return 0;
+}
+
 static int meson_spicc_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
        struct meson_spicc_device *spicc;
-       int ret, irq, rate;
+       int ret, irq;
 
        master = spi_alloc_master(&pdev->dev, sizeof(*spicc));
        if (!master) {
@@ -491,6 +670,13 @@ static int meson_spicc_probe(struct platform_device *pdev)
        spicc = spi_master_get_devdata(master);
        spicc->master = master;
 
+       spicc->data = of_device_get_match_data(&pdev->dev);
+       if (!spicc->data) {
+               dev_err(&pdev->dev, "failed to get match data\n");
+               ret = -EINVAL;
+               goto out_master;
+       }
+
        spicc->pdev = pdev;
        platform_set_drvdata(pdev, spicc);
 
@@ -501,6 +687,10 @@ static int meson_spicc_probe(struct platform_device *pdev)
                goto out_master;
        }
 
+       /* Set master mode and enable controller */
+       writel_relaxed(SPICC_ENABLE | SPICC_MODE_MASTER,
+                      spicc->base + SPICC_CONREG);
+
        /* Disable all IRQs */
        writel_relaxed(0, spicc->base + SPICC_INTREG);
 
@@ -519,12 +709,26 @@ static int meson_spicc_probe(struct platform_device *pdev)
                goto out_master;
        }
 
+       if (spicc->data->has_pclk) {
+               spicc->pclk = devm_clk_get(&pdev->dev, "pclk");
+               if (IS_ERR(spicc->pclk)) {
+                       dev_err(&pdev->dev, "pclk clock request failed\n");
+                       ret = PTR_ERR(spicc->pclk);
+                       goto out_master;
+               }
+       }
+
        ret = clk_prepare_enable(spicc->core);
        if (ret) {
                dev_err(&pdev->dev, "core clock enable failed\n");
                goto out_master;
        }
-       rate = clk_get_rate(spicc->core);
+
+       ret = clk_prepare_enable(spicc->pclk);
+       if (ret) {
+               dev_err(&pdev->dev, "pclk clock enable failed\n");
+               goto out_master;
+       }
 
        device_reset_optional(&pdev->dev);
 
@@ -536,7 +740,8 @@ static int meson_spicc_probe(struct platform_device *pdev)
                                     SPI_BPW_MASK(16) |
                                     SPI_BPW_MASK(8);
        master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
-       master->min_speed_hz = rate >> 9;
+       master->min_speed_hz = spicc->data->min_speed_hz;
+       master->max_speed_hz = spicc->data->max_speed_hz;
        master->setup = meson_spicc_setup;
        master->cleanup = meson_spicc_cleanup;
        master->prepare_message = meson_spicc_prepare_message;
@@ -544,11 +749,13 @@ static int meson_spicc_probe(struct platform_device *pdev)
        master->transfer_one = meson_spicc_transfer_one;
        master->use_gpio_descriptors = true;
 
-       /* Setup max rate according to the Meson GX datasheet */
-       if ((rate >> 2) > SPICC_MAX_FREQ)
-               master->max_speed_hz = SPICC_MAX_FREQ;
-       else
-               master->max_speed_hz = rate >> 2;
+       meson_spicc_oen_enable(spicc);
+
+       ret = meson_spicc_clk_init(spicc);
+       if (ret) {
+               dev_err(&pdev->dev, "clock registration failed\n");
+               goto out_master;
+       }
 
        ret = devm_spi_register_master(&pdev->dev, master);
        if (ret) {
@@ -560,6 +767,7 @@ static int meson_spicc_probe(struct platform_device *pdev)
 
 out_clk:
        clk_disable_unprepare(spicc->core);
+       clk_disable_unprepare(spicc->pclk);
 
 out_master:
        spi_master_put(master);
@@ -575,13 +783,47 @@ static int meson_spicc_remove(struct platform_device *pdev)
        writel(0, spicc->base + SPICC_CONREG);
 
        clk_disable_unprepare(spicc->core);
+       clk_disable_unprepare(spicc->pclk);
 
        return 0;
 }
 
+static const struct meson_spicc_data meson_spicc_gx_data = {
+       .max_speed_hz           = 30000000,
+       .min_speed_hz           = 325000,
+       .fifo_size              = 16,
+};
+
+static const struct meson_spicc_data meson_spicc_axg_data = {
+       .max_speed_hz           = 80000000,
+       .min_speed_hz           = 325000,
+       .fifo_size              = 16,
+       .has_oen                = true,
+       .has_enhance_clk_div    = true,
+};
+
+static const struct meson_spicc_data meson_spicc_g12a_data = {
+       .max_speed_hz           = 166666666,
+       .min_speed_hz           = 50000,
+       .fifo_size              = 15,
+       .has_oen                = true,
+       .has_enhance_clk_div    = true,
+       .has_pclk               = true,
+};
+
 static const struct of_device_id meson_spicc_of_match[] = {
-       { .compatible = "amlogic,meson-gx-spicc", },
-       { .compatible = "amlogic,meson-axg-spicc", },
+       {
+               .compatible     = "amlogic,meson-gx-spicc",
+               .data           = &meson_spicc_gx_data,
+       },
+       {
+               .compatible = "amlogic,meson-axg-spicc",
+               .data           = &meson_spicc_axg_data,
+       },
+       {
+               .compatible = "amlogic,meson-g12a-spicc",
+               .data           = &meson_spicc_g12a_data,
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, meson_spicc_of_match);
diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c
new file mode 100644 (file)
index 0000000..c15a991
--- /dev/null
@@ -0,0 +1,689 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Mediatek SPI NOR controller driver
+//
+// Copyright (C) 2020 Chuanhong Guo <gch981213@gmail.com>
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/string.h>
+
+#define DRIVER_NAME "mtk-spi-nor"
+
+#define MTK_NOR_REG_CMD                        0x00
+#define MTK_NOR_CMD_WRITE              BIT(4)
+#define MTK_NOR_CMD_PROGRAM            BIT(2)
+#define MTK_NOR_CMD_READ               BIT(0)
+#define MTK_NOR_CMD_MASK               GENMASK(5, 0)
+
+#define MTK_NOR_REG_PRG_CNT            0x04
+#define MTK_NOR_REG_RDATA              0x0c
+
+#define MTK_NOR_REG_RADR0              0x10
+#define MTK_NOR_REG_RADR(n)            (MTK_NOR_REG_RADR0 + 4 * (n))
+#define MTK_NOR_REG_RADR3              0xc8
+
+#define MTK_NOR_REG_WDATA              0x1c
+
+#define MTK_NOR_REG_PRGDATA0           0x20
+#define MTK_NOR_REG_PRGDATA(n)         (MTK_NOR_REG_PRGDATA0 + 4 * (n))
+#define MTK_NOR_REG_PRGDATA_MAX                5
+
+#define MTK_NOR_REG_SHIFT0             0x38
+#define MTK_NOR_REG_SHIFT(n)           (MTK_NOR_REG_SHIFT0 + 4 * (n))
+#define MTK_NOR_REG_SHIFT_MAX          9
+
+#define MTK_NOR_REG_CFG1               0x60
+#define MTK_NOR_FAST_READ              BIT(0)
+
+#define MTK_NOR_REG_CFG2               0x64
+#define MTK_NOR_WR_CUSTOM_OP_EN                BIT(4)
+#define MTK_NOR_WR_BUF_EN              BIT(0)
+
+#define MTK_NOR_REG_PP_DATA            0x98
+
+#define MTK_NOR_REG_IRQ_STAT           0xa8
+#define MTK_NOR_REG_IRQ_EN             0xac
+#define MTK_NOR_IRQ_DMA                        BIT(7)
+#define MTK_NOR_IRQ_MASK               GENMASK(7, 0)
+
+#define MTK_NOR_REG_CFG3               0xb4
+#define MTK_NOR_DISABLE_WREN           BIT(7)
+#define MTK_NOR_DISABLE_SR_POLL                BIT(5)
+
+#define MTK_NOR_REG_WP                 0xc4
+#define MTK_NOR_ENABLE_SF_CMD          0x30
+
+#define MTK_NOR_REG_BUSCFG             0xcc
+#define MTK_NOR_4B_ADDR                        BIT(4)
+#define MTK_NOR_QUAD_ADDR              BIT(3)
+#define MTK_NOR_QUAD_READ              BIT(2)
+#define MTK_NOR_DUAL_ADDR              BIT(1)
+#define MTK_NOR_DUAL_READ              BIT(0)
+#define MTK_NOR_BUS_MODE_MASK          GENMASK(4, 0)
+
+#define MTK_NOR_REG_DMA_CTL            0x718
+#define MTK_NOR_DMA_START              BIT(0)
+
+#define MTK_NOR_REG_DMA_FADR           0x71c
+#define MTK_NOR_REG_DMA_DADR           0x720
+#define MTK_NOR_REG_DMA_END_DADR       0x724
+
+#define MTK_NOR_PRG_MAX_SIZE           6
+// Reading DMA src/dst addresses have to be 16-byte aligned
+#define MTK_NOR_DMA_ALIGN              16
+#define MTK_NOR_DMA_ALIGN_MASK         (MTK_NOR_DMA_ALIGN - 1)
+// and we allocate a bounce buffer if destination address isn't aligned.
+#define MTK_NOR_BOUNCE_BUF_SIZE                PAGE_SIZE
+
+// Buffered page program can do one 128-byte transfer
+#define MTK_NOR_PP_SIZE                        128
+
+#define CLK_TO_US(sp, clkcnt)          ((clkcnt) * 1000000 / sp->spi_freq)
+
+struct mtk_nor {
+       struct spi_controller *ctlr;
+       struct device *dev;
+       void __iomem *base;
+       u8 *buffer;
+       struct clk *spi_clk;
+       struct clk *ctlr_clk;
+       unsigned int spi_freq;
+       bool wbuf_en;
+       bool has_irq;
+       struct completion op_done;
+};
+
+static inline void mtk_nor_rmw(struct mtk_nor *sp, u32 reg, u32 set, u32 clr)
+{
+       u32 val = readl(sp->base + reg);
+
+       val &= ~clr;
+       val |= set;
+       writel(val, sp->base + reg);
+}
+
+static inline int mtk_nor_cmd_exec(struct mtk_nor *sp, u32 cmd, ulong clk)
+{
+       ulong delay = CLK_TO_US(sp, clk);
+       u32 reg;
+       int ret;
+
+       writel(cmd, sp->base + MTK_NOR_REG_CMD);
+       ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CMD, reg, !(reg & cmd),
+                                delay / 3, (delay + 1) * 200);
+       if (ret < 0)
+               dev_err(sp->dev, "command %u timeout.\n", cmd);
+       return ret;
+}
+
+static void mtk_nor_set_addr(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+       u32 addr = op->addr.val;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               writeb(addr & 0xff, sp->base + MTK_NOR_REG_RADR(i));
+               addr >>= 8;
+       }
+       if (op->addr.nbytes == 4) {
+               writeb(addr & 0xff, sp->base + MTK_NOR_REG_RADR3);
+               mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, MTK_NOR_4B_ADDR, 0);
+       } else {
+               mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, 0, MTK_NOR_4B_ADDR);
+       }
+}
+
+static bool mtk_nor_match_read(const struct spi_mem_op *op)
+{
+       int dummy = 0;
+
+       if (op->dummy.buswidth)
+               dummy = op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth;
+
+       if ((op->data.buswidth == 2) || (op->data.buswidth == 4)) {
+               if (op->addr.buswidth == 1)
+                       return dummy == 8;
+               else if (op->addr.buswidth == 2)
+                       return dummy == 4;
+               else if (op->addr.buswidth == 4)
+                       return dummy == 6;
+       } else if ((op->addr.buswidth == 1) && (op->data.buswidth == 1)) {
+               if (op->cmd.opcode == 0x03)
+                       return dummy == 0;
+               else if (op->cmd.opcode == 0x0b)
+                       return dummy == 8;
+       }
+       return false;
+}
+
+static int mtk_nor_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+       size_t len;
+
+       if (!op->data.nbytes)
+               return 0;
+
+       if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
+               if ((op->data.dir == SPI_MEM_DATA_IN) &&
+                   mtk_nor_match_read(op)) {
+                       if ((op->addr.val & MTK_NOR_DMA_ALIGN_MASK) ||
+                           (op->data.nbytes < MTK_NOR_DMA_ALIGN))
+                               op->data.nbytes = 1;
+                       else if (!((ulong)(op->data.buf.in) &
+                                  MTK_NOR_DMA_ALIGN_MASK))
+                               op->data.nbytes &= ~MTK_NOR_DMA_ALIGN_MASK;
+                       else if (op->data.nbytes > MTK_NOR_BOUNCE_BUF_SIZE)
+                               op->data.nbytes = MTK_NOR_BOUNCE_BUF_SIZE;
+                       return 0;
+               } else if (op->data.dir == SPI_MEM_DATA_OUT) {
+                       if (op->data.nbytes >= MTK_NOR_PP_SIZE)
+                               op->data.nbytes = MTK_NOR_PP_SIZE;
+                       else
+                               op->data.nbytes = 1;
+                       return 0;
+               }
+       }
+
+       len = MTK_NOR_PRG_MAX_SIZE - sizeof(op->cmd.opcode) - op->addr.nbytes -
+             op->dummy.nbytes;
+       if (op->data.nbytes > len)
+               op->data.nbytes = len;
+
+       return 0;
+}
+
+static bool mtk_nor_supports_op(struct spi_mem *mem,
+                               const struct spi_mem_op *op)
+{
+       size_t len;
+
+       if (op->cmd.buswidth != 1)
+               return false;
+
+       if ((op->addr.nbytes == 3) || (op->addr.nbytes == 4)) {
+               if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op))
+                       return true;
+               else if (op->data.dir == SPI_MEM_DATA_OUT)
+                       return (op->addr.buswidth == 1) &&
+                              (op->dummy.buswidth == 0) &&
+                              (op->data.buswidth == 1);
+       }
+       len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes;
+       if ((len > MTK_NOR_PRG_MAX_SIZE) ||
+           ((op->data.nbytes) && (len == MTK_NOR_PRG_MAX_SIZE)))
+               return false;
+       return true;
+}
+
+static void mtk_nor_setup_bus(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+       u32 reg = 0;
+
+       if (op->addr.nbytes == 4)
+               reg |= MTK_NOR_4B_ADDR;
+
+       if (op->data.buswidth == 4) {
+               reg |= MTK_NOR_QUAD_READ;
+               writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA(4));
+               if (op->addr.buswidth == 4)
+                       reg |= MTK_NOR_QUAD_ADDR;
+       } else if (op->data.buswidth == 2) {
+               reg |= MTK_NOR_DUAL_READ;
+               writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA(3));
+               if (op->addr.buswidth == 2)
+                       reg |= MTK_NOR_DUAL_ADDR;
+       } else {
+               if (op->cmd.opcode == 0x0b)
+                       mtk_nor_rmw(sp, MTK_NOR_REG_CFG1, MTK_NOR_FAST_READ, 0);
+               else
+                       mtk_nor_rmw(sp, MTK_NOR_REG_CFG1, 0, MTK_NOR_FAST_READ);
+       }
+       mtk_nor_rmw(sp, MTK_NOR_REG_BUSCFG, reg, MTK_NOR_BUS_MODE_MASK);
+}
+
+static int mtk_nor_read_dma(struct mtk_nor *sp, u32 from, unsigned int length,
+                           u8 *buffer)
+{
+       int ret = 0;
+       ulong delay;
+       u32 reg;
+       dma_addr_t dma_addr;
+
+       dma_addr = dma_map_single(sp->dev, buffer, length, DMA_FROM_DEVICE);
+       if (dma_mapping_error(sp->dev, dma_addr)) {
+               dev_err(sp->dev, "failed to map dma buffer.\n");
+               return -EINVAL;
+       }
+
+       writel(from, sp->base + MTK_NOR_REG_DMA_FADR);
+       writel(dma_addr, sp->base + MTK_NOR_REG_DMA_DADR);
+       writel(dma_addr + length, sp->base + MTK_NOR_REG_DMA_END_DADR);
+
+       if (sp->has_irq) {
+               reinit_completion(&sp->op_done);
+               mtk_nor_rmw(sp, MTK_NOR_REG_IRQ_EN, MTK_NOR_IRQ_DMA, 0);
+       }
+
+       mtk_nor_rmw(sp, MTK_NOR_REG_DMA_CTL, MTK_NOR_DMA_START, 0);
+
+       delay = CLK_TO_US(sp, (length + 5) * BITS_PER_BYTE);
+
+       if (sp->has_irq) {
+               if (!wait_for_completion_timeout(&sp->op_done,
+                                                (delay + 1) * 100))
+                       ret = -ETIMEDOUT;
+       } else {
+               ret = readl_poll_timeout(sp->base + MTK_NOR_REG_DMA_CTL, reg,
+                                        !(reg & MTK_NOR_DMA_START), delay / 3,
+                                        (delay + 1) * 100);
+       }
+
+       dma_unmap_single(sp->dev, dma_addr, length, DMA_FROM_DEVICE);
+       if (ret < 0)
+               dev_err(sp->dev, "dma read timeout.\n");
+
+       return ret;
+}
+
+static int mtk_nor_read_bounce(struct mtk_nor *sp, u32 from,
+                              unsigned int length, u8 *buffer)
+{
+       unsigned int rdlen;
+       int ret;
+
+       if (length & MTK_NOR_DMA_ALIGN_MASK)
+               rdlen = (length + MTK_NOR_DMA_ALIGN) & ~MTK_NOR_DMA_ALIGN_MASK;
+       else
+               rdlen = length;
+
+       ret = mtk_nor_read_dma(sp, from, rdlen, sp->buffer);
+       if (ret)
+               return ret;
+
+       memcpy(buffer, sp->buffer, length);
+       return 0;
+}
+
+static int mtk_nor_read_pio(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+       u8 *buf = op->data.buf.in;
+       int ret;
+
+       ret = mtk_nor_cmd_exec(sp, MTK_NOR_CMD_READ, 6 * BITS_PER_BYTE);
+       if (!ret)
+               buf[0] = readb(sp->base + MTK_NOR_REG_RDATA);
+       return ret;
+}
+
+static int mtk_nor_write_buffer_enable(struct mtk_nor *sp)
+{
+       int ret;
+       u32 val;
+
+       if (sp->wbuf_en)
+               return 0;
+
+       val = readl(sp->base + MTK_NOR_REG_CFG2);
+       writel(val | MTK_NOR_WR_BUF_EN, sp->base + MTK_NOR_REG_CFG2);
+       ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CFG2, val,
+                                val & MTK_NOR_WR_BUF_EN, 0, 10000);
+       if (!ret)
+               sp->wbuf_en = true;
+       return ret;
+}
+
+static int mtk_nor_write_buffer_disable(struct mtk_nor *sp)
+{
+       int ret;
+       u32 val;
+
+       if (!sp->wbuf_en)
+               return 0;
+       val = readl(sp->base + MTK_NOR_REG_CFG2);
+       writel(val & ~MTK_NOR_WR_BUF_EN, sp->base + MTK_NOR_REG_CFG2);
+       ret = readl_poll_timeout(sp->base + MTK_NOR_REG_CFG2, val,
+                                !(val & MTK_NOR_WR_BUF_EN), 0, 10000);
+       if (!ret)
+               sp->wbuf_en = false;
+       return ret;
+}
+
+static int mtk_nor_pp_buffered(struct mtk_nor *sp, const struct spi_mem_op *op)
+{
+       const u8 *buf = op->data.buf.out;
+       u32 val;
+       int ret, i;
+
+       ret = mtk_nor_write_buffer_enable(sp);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < op->data.nbytes; i += 4) {
+               val = buf[i + 3] << 24 | buf[i + 2] << 16 | buf[i + 1] << 8 |
+                     buf[i];
+               writel(val, sp->base + MTK_NOR_REG_PP_DATA);
+       }
+       return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE,
+                               (op->data.nbytes + 5) * BITS_PER_BYTE);
+}
+
+static int mtk_nor_pp_unbuffered(struct mtk_nor *sp,
+                                const struct spi_mem_op *op)
+{
+       const u8 *buf = op->data.buf.out;
+       int ret;
+
+       ret = mtk_nor_write_buffer_disable(sp);
+       if (ret < 0)
+               return ret;
+       writeb(buf[0], sp->base + MTK_NOR_REG_WDATA);
+       return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE, 6 * BITS_PER_BYTE);
+}
+
+int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+       struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master);
+       int ret;
+
+       if ((op->data.nbytes == 0) ||
+           ((op->addr.nbytes != 3) && (op->addr.nbytes != 4)))
+               return -ENOTSUPP;
+
+       if (op->data.dir == SPI_MEM_DATA_OUT) {
+               mtk_nor_set_addr(sp, op);
+               writeb(op->cmd.opcode, sp->base + MTK_NOR_REG_PRGDATA0);
+               if (op->data.nbytes == MTK_NOR_PP_SIZE)
+                       return mtk_nor_pp_buffered(sp, op);
+               return mtk_nor_pp_unbuffered(sp, op);
+       }
+
+       if ((op->data.dir == SPI_MEM_DATA_IN) && mtk_nor_match_read(op)) {
+               ret = mtk_nor_write_buffer_disable(sp);
+               if (ret < 0)
+                       return ret;
+               mtk_nor_setup_bus(sp, op);
+               if (op->data.nbytes == 1) {
+                       mtk_nor_set_addr(sp, op);
+                       return mtk_nor_read_pio(sp, op);
+               } else if (((ulong)(op->data.buf.in) &
+                           MTK_NOR_DMA_ALIGN_MASK)) {
+                       return mtk_nor_read_bounce(sp, op->addr.val,
+                                                  op->data.nbytes,
+                                                  op->data.buf.in);
+               } else {
+                       return mtk_nor_read_dma(sp, op->addr.val,
+                                               op->data.nbytes,
+                                               op->data.buf.in);
+               }
+       }
+
+       return -ENOTSUPP;
+}
+
+static int mtk_nor_setup(struct spi_device *spi)
+{
+       struct mtk_nor *sp = spi_controller_get_devdata(spi->master);
+
+       if (spi->max_speed_hz && (spi->max_speed_hz < sp->spi_freq)) {
+               dev_err(&spi->dev, "spi clock should be %u Hz.\n",
+                       sp->spi_freq);
+               return -EINVAL;
+       }
+       spi->max_speed_hz = sp->spi_freq;
+
+       return 0;
+}
+
+static int mtk_nor_transfer_one_message(struct spi_controller *master,
+                                       struct spi_message *m)
+{
+       struct mtk_nor *sp = spi_controller_get_devdata(master);
+       struct spi_transfer *t = NULL;
+       unsigned long trx_len = 0;
+       int stat = 0;
+       int reg_offset = MTK_NOR_REG_PRGDATA_MAX;
+       void __iomem *reg;
+       const u8 *txbuf;
+       u8 *rxbuf;
+       int i;
+
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               txbuf = t->tx_buf;
+               for (i = 0; i < t->len; i++, reg_offset--) {
+                       reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset);
+                       if (txbuf)
+                               writeb(txbuf[i], reg);
+                       else
+                               writeb(0, reg);
+               }
+               trx_len += t->len;
+       }
+
+       writel(trx_len * BITS_PER_BYTE, sp->base + MTK_NOR_REG_PRG_CNT);
+
+       stat = mtk_nor_cmd_exec(sp, MTK_NOR_CMD_PROGRAM,
+                               trx_len * BITS_PER_BYTE);
+       if (stat < 0)
+               goto msg_done;
+
+       reg_offset = trx_len - 1;
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               rxbuf = t->rx_buf;
+               for (i = 0; i < t->len; i++, reg_offset--) {
+                       reg = sp->base + MTK_NOR_REG_SHIFT(reg_offset);
+                       if (rxbuf)
+                               rxbuf[i] = readb(reg);
+               }
+       }
+
+       m->actual_length = trx_len;
+msg_done:
+       m->status = stat;
+       spi_finalize_current_message(master);
+
+       return 0;
+}
+
+static void mtk_nor_disable_clk(struct mtk_nor *sp)
+{
+       clk_disable_unprepare(sp->spi_clk);
+       clk_disable_unprepare(sp->ctlr_clk);
+}
+
+static int mtk_nor_enable_clk(struct mtk_nor *sp)
+{
+       int ret;
+
+       ret = clk_prepare_enable(sp->spi_clk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(sp->ctlr_clk);
+       if (ret) {
+               clk_disable_unprepare(sp->spi_clk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mtk_nor_init(struct mtk_nor *sp)
+{
+       int ret;
+
+       ret = mtk_nor_enable_clk(sp);
+       if (ret)
+               return ret;
+
+       sp->spi_freq = clk_get_rate(sp->spi_clk);
+
+       writel(MTK_NOR_ENABLE_SF_CMD, sp->base + MTK_NOR_REG_WP);
+       mtk_nor_rmw(sp, MTK_NOR_REG_CFG2, MTK_NOR_WR_CUSTOM_OP_EN, 0);
+       mtk_nor_rmw(sp, MTK_NOR_REG_CFG3,
+                   MTK_NOR_DISABLE_WREN | MTK_NOR_DISABLE_SR_POLL, 0);
+
+       return ret;
+}
+
+static irqreturn_t mtk_nor_irq_handler(int irq, void *data)
+{
+       struct mtk_nor *sp = data;
+       u32 irq_status, irq_enabled;
+
+       irq_status = readl(sp->base + MTK_NOR_REG_IRQ_STAT);
+       irq_enabled = readl(sp->base + MTK_NOR_REG_IRQ_EN);
+       // write status back to clear interrupt
+       writel(irq_status, sp->base + MTK_NOR_REG_IRQ_STAT);
+
+       if (!(irq_status & irq_enabled))
+               return IRQ_NONE;
+
+       if (irq_status & MTK_NOR_IRQ_DMA) {
+               complete(&sp->op_done);
+               writel(0, sp->base + MTK_NOR_REG_IRQ_EN);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static size_t mtk_max_msg_size(struct spi_device *spi)
+{
+       return MTK_NOR_PRG_MAX_SIZE;
+}
+
+static const struct spi_controller_mem_ops mtk_nor_mem_ops = {
+       .adjust_op_size = mtk_nor_adjust_op_size,
+       .supports_op = mtk_nor_supports_op,
+       .exec_op = mtk_nor_exec_op
+};
+
+static const struct of_device_id mtk_nor_match[] = {
+       { .compatible = "mediatek,mt8173-nor" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_nor_match);
+
+static int mtk_nor_probe(struct platform_device *pdev)
+{
+       struct spi_controller *ctlr;
+       struct mtk_nor *sp;
+       void __iomem *base;
+       u8 *buffer;
+       struct clk *spi_clk, *ctlr_clk;
+       int ret, irq;
+
+       base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       spi_clk = devm_clk_get(&pdev->dev, "spi");
+       if (IS_ERR(spi_clk))
+               return PTR_ERR(spi_clk);
+
+       ctlr_clk = devm_clk_get(&pdev->dev, "sf");
+       if (IS_ERR(ctlr_clk))
+               return PTR_ERR(ctlr_clk);
+
+       buffer = devm_kmalloc(&pdev->dev,
+                             MTK_NOR_BOUNCE_BUF_SIZE + MTK_NOR_DMA_ALIGN,
+                             GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       if ((ulong)buffer & MTK_NOR_DMA_ALIGN_MASK)
+               buffer = (u8 *)(((ulong)buffer + MTK_NOR_DMA_ALIGN) &
+                               ~MTK_NOR_DMA_ALIGN_MASK);
+
+       ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp));
+       if (!ctlr) {
+               dev_err(&pdev->dev, "failed to allocate spi controller\n");
+               return -ENOMEM;
+       }
+
+       ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+       ctlr->dev.of_node = pdev->dev.of_node;
+       ctlr->max_message_size = mtk_max_msg_size;
+       ctlr->mem_ops = &mtk_nor_mem_ops;
+       ctlr->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL | SPI_TX_QUAD;
+       ctlr->num_chipselect = 1;
+       ctlr->setup = mtk_nor_setup;
+       ctlr->transfer_one_message = mtk_nor_transfer_one_message;
+
+       dev_set_drvdata(&pdev->dev, ctlr);
+
+       sp = spi_controller_get_devdata(ctlr);
+       sp->base = base;
+       sp->buffer = buffer;
+       sp->has_irq = false;
+       sp->wbuf_en = false;
+       sp->ctlr = ctlr;
+       sp->dev = &pdev->dev;
+       sp->spi_clk = spi_clk;
+       sp->ctlr_clk = ctlr_clk;
+
+       irq = platform_get_irq_optional(pdev, 0);
+       if (irq < 0) {
+               dev_warn(sp->dev, "IRQ not available.");
+       } else {
+               writel(MTK_NOR_IRQ_MASK, base + MTK_NOR_REG_IRQ_STAT);
+               writel(0, base + MTK_NOR_REG_IRQ_EN);
+               ret = devm_request_irq(sp->dev, irq, mtk_nor_irq_handler, 0,
+                                      pdev->name, sp);
+               if (ret < 0) {
+                       dev_warn(sp->dev, "failed to request IRQ.");
+               } else {
+                       init_completion(&sp->op_done);
+                       sp->has_irq = true;
+               }
+       }
+
+       ret = mtk_nor_init(sp);
+       if (ret < 0) {
+               kfree(ctlr);
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "spi frequency: %d Hz\n", sp->spi_freq);
+
+       return devm_spi_register_controller(&pdev->dev, ctlr);
+}
+
+static int mtk_nor_remove(struct platform_device *pdev)
+{
+       struct spi_controller *ctlr;
+       struct mtk_nor *sp;
+
+       ctlr = dev_get_drvdata(&pdev->dev);
+       sp = spi_controller_get_devdata(ctlr);
+
+       mtk_nor_disable_clk(sp);
+
+       return 0;
+}
+
+static struct platform_driver mtk_nor_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .of_match_table = mtk_nor_match,
+       },
+       .probe = mtk_nor_probe,
+       .remove = mtk_nor_remove,
+};
+
+module_platform_driver(mtk_nor_driver);
+
+MODULE_DESCRIPTION("Mediatek SPI NOR controller driver");
+MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/spi-mux.c b/drivers/spi/spi-mux.c
new file mode 100644 (file)
index 0000000..4f94c91
--- /dev/null
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// General Purpose SPI multiplexer
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mux/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#define SPI_MUX_NO_CS  ((unsigned int)-1)
+
+/**
+ * DOC: Driver description
+ *
+ * This driver supports a MUX on an SPI bus. This can be useful when you need
+ * more chip selects than the hardware peripherals support, or than are
+ * available in a particular board setup.
+ *
+ * The driver will create an additional SPI controller. Devices added under the
+ * mux will be handled as 'chip selects' on this controller.
+ */
+
+/**
+ * struct spi_mux_priv - the basic spi_mux structure
+ * @spi:               pointer to the device struct attached to the parent
+ *                     spi controller
+ * @current_cs:                The current chip select set in the mux
+ * @child_msg_complete: The mux replaces the complete callback in the child's
+ *                     message to its own callback; this field is used by the
+ *                     driver to store the child's callback during a transfer
+ * @child_msg_context: Used to store the child's context to the callback
+ * @child_msg_dev:     Used to store the spi_device pointer to the child
+ * @mux:               mux_control structure used to provide chip selects for
+ *                     downstream spi devices
+ */
+struct spi_mux_priv {
+       struct spi_device       *spi;
+       unsigned int            current_cs;
+
+       void                    (*child_msg_complete)(void *context);
+       void                    *child_msg_context;
+       struct spi_device       *child_msg_dev;
+       struct mux_control      *mux;
+};
+
+/* should not get called when the parent controller is doing a transfer */
+static int spi_mux_select(struct spi_device *spi)
+{
+       struct spi_mux_priv *priv = spi_controller_get_devdata(spi->controller);
+       int ret;
+
+       if (priv->current_cs == spi->chip_select)
+               return 0;
+
+       dev_dbg(&priv->spi->dev, "setting up the mux for cs %d\n",
+               spi->chip_select);
+
+       /* copy the child device's settings except for the cs */
+       priv->spi->max_speed_hz = spi->max_speed_hz;
+       priv->spi->mode = spi->mode;
+       priv->spi->bits_per_word = spi->bits_per_word;
+
+       ret = mux_control_select(priv->mux, spi->chip_select);
+       if (ret)
+               return ret;
+
+       priv->current_cs = spi->chip_select;
+
+       return 0;
+}
+
+static int spi_mux_setup(struct spi_device *spi)
+{
+       struct spi_mux_priv *priv = spi_controller_get_devdata(spi->controller);
+
+       /*
+        * can be called multiple times, won't do a valid setup now but we will
+        * change the settings when we do a transfer (necessary because we
+        * can't predict from which device it will be anyway)
+        */
+       return spi_setup(priv->spi);
+}
+
+static void spi_mux_complete_cb(void *context)
+{
+       struct spi_mux_priv *priv = (struct spi_mux_priv *)context;
+       struct spi_controller *ctlr = spi_get_drvdata(priv->spi);
+       struct spi_message *m = ctlr->cur_msg;
+
+       m->complete = priv->child_msg_complete;
+       m->context = priv->child_msg_context;
+       m->spi = priv->child_msg_dev;
+       spi_finalize_current_message(ctlr);
+       mux_control_deselect(priv->mux);
+}
+
+static int spi_mux_transfer_one_message(struct spi_controller *ctlr,
+                                               struct spi_message *m)
+{
+       struct spi_mux_priv *priv = spi_controller_get_devdata(ctlr);
+       struct spi_device *spi = m->spi;
+       int ret;
+
+       ret = spi_mux_select(spi);
+       if (ret)
+               return ret;
+
+       /*
+        * Replace the complete callback, context and spi_device with our own
+        * pointers. Save originals
+        */
+       priv->child_msg_complete = m->complete;
+       priv->child_msg_context = m->context;
+       priv->child_msg_dev = m->spi;
+
+       m->complete = spi_mux_complete_cb;
+       m->context = priv;
+       m->spi = priv->spi;
+
+       /* do the transfer */
+       return spi_async(priv->spi, m);
+}
+
+static int spi_mux_probe(struct spi_device *spi)
+{
+       struct spi_controller *ctlr;
+       struct spi_mux_priv *priv;
+       int ret;
+
+       ctlr = spi_alloc_master(&spi->dev, sizeof(*priv));
+       if (!ctlr)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, ctlr);
+       priv = spi_controller_get_devdata(ctlr);
+       priv->spi = spi;
+
+       priv->mux = devm_mux_control_get(&spi->dev, NULL);
+       if (IS_ERR(priv->mux)) {
+               ret = PTR_ERR(priv->mux);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&spi->dev, "failed to get control-mux\n");
+               goto err_put_ctlr;
+       }
+
+       priv->current_cs = SPI_MUX_NO_CS;
+
+       /* supported modes are the same as our parent's */
+       ctlr->mode_bits = spi->controller->mode_bits;
+       ctlr->flags = spi->controller->flags;
+       ctlr->transfer_one_message = spi_mux_transfer_one_message;
+       ctlr->setup = spi_mux_setup;
+       ctlr->num_chipselect = mux_control_states(priv->mux);
+       ctlr->bus_num = -1;
+       ctlr->dev.of_node = spi->dev.of_node;
+
+       ret = devm_spi_register_controller(&spi->dev, ctlr);
+       if (ret)
+               goto err_put_ctlr;
+
+       return 0;
+
+err_put_ctlr:
+       spi_controller_put(ctlr);
+
+       return ret;
+}
+
+static const struct of_device_id spi_mux_of_match[] = {
+       { .compatible = "spi-mux" },
+       { }
+};
+
+static struct spi_driver spi_mux_driver = {
+       .probe  = spi_mux_probe,
+       .driver = {
+               .name   = "spi-mux",
+               .of_match_table = spi_mux_of_match,
+       },
+};
+
+module_spi_driver(spi_mux_driver);
+
+MODULE_DESCRIPTION("SPI multiplexer");
+MODULE_LICENSE("GPL");
index dce85ee..918918a 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/ioport.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -32,7 +31,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/completion.h>
-#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/module.h>
index 8c5084a..1ccda82 100644 (file)
 
 #define POLL_TOUT              5000
 #define NXP_FSPI_MAX_CHIPSELECT                4
+#define NXP_FSPI_MIN_IOMAP     SZ_4M
 
 struct nxp_fspi_devtype_data {
        unsigned int rxfifo;
@@ -324,11 +325,29 @@ static const struct nxp_fspi_devtype_data lx2160a_data = {
        .little_endian = true,  /* little-endian    */
 };
 
+static const struct nxp_fspi_devtype_data imx8mm_data = {
+       .rxfifo = SZ_512,       /* (64  * 64 bits)  */
+       .txfifo = SZ_1K,        /* (128 * 64 bits)  */
+       .ahb_buf_size = SZ_2K,  /* (256 * 64 bits)  */
+       .quirks = 0,
+       .little_endian = true,  /* little-endian    */
+};
+
+static const struct nxp_fspi_devtype_data imx8qxp_data = {
+       .rxfifo = SZ_512,       /* (64  * 64 bits)  */
+       .txfifo = SZ_1K,        /* (128 * 64 bits)  */
+       .ahb_buf_size = SZ_2K,  /* (256 * 64 bits)  */
+       .quirks = 0,
+       .little_endian = true,  /* little-endian    */
+};
+
 struct nxp_fspi {
        void __iomem *iobase;
        void __iomem *ahb_addr;
        u32 memmap_phy;
        u32 memmap_phy_size;
+       u32 memmap_start;
+       u32 memmap_len;
        struct clk *clk, *clk_en;
        struct device *dev;
        struct completion c;
@@ -641,12 +660,35 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi)
        f->selected = spi->chip_select;
 }
 
-static void nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op)
+static int nxp_fspi_read_ahb(struct nxp_fspi *f, const struct spi_mem_op *op)
 {
+       u32 start = op->addr.val;
        u32 len = op->data.nbytes;
 
+       /* if necessary, ioremap before AHB read */
+       if ((!f->ahb_addr) || start < f->memmap_start ||
+            start + len > f->memmap_start + f->memmap_len) {
+               if (f->ahb_addr)
+                       iounmap(f->ahb_addr);
+
+               f->memmap_start = start;
+               f->memmap_len = len > NXP_FSPI_MIN_IOMAP ?
+                               len : NXP_FSPI_MIN_IOMAP;
+
+               f->ahb_addr = ioremap_wc(f->memmap_phy + f->memmap_start,
+                                        f->memmap_len);
+
+               if (!f->ahb_addr) {
+                       dev_err(f->dev, "failed to alloc memory\n");
+                       return -ENOMEM;
+               }
+       }
+
        /* Read out the data directly from the AHB buffer. */
-       memcpy_fromio(op->data.buf.in, (f->ahb_addr + op->addr.val), len);
+       memcpy_fromio(op->data.buf.in,
+                     f->ahb_addr + start - f->memmap_start, len);
+
+       return 0;
 }
 
 static void nxp_fspi_fill_txfifo(struct nxp_fspi *f,
@@ -806,7 +848,7 @@ static int nxp_fspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
         */
        if (op->data.nbytes > (f->devtype_data->rxfifo - 4) &&
            op->data.dir == SPI_MEM_DATA_IN) {
-               nxp_fspi_read_ahb(f, op);
+               err = nxp_fspi_read_ahb(f, op);
        } else {
                if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
                        nxp_fspi_fill_txfifo(f, op);
@@ -871,8 +913,9 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f)
        fspi_writel(f, FSPI_DLLBCR_OVRDEN, base + FSPI_DLLBCR);
 
        /* enable module */
-       fspi_writel(f, FSPI_MCR0_AHB_TIMEOUT(0xFF) | FSPI_MCR0_IP_TIMEOUT(0xFF),
-                base + FSPI_MCR0);
+       fspi_writel(f, FSPI_MCR0_AHB_TIMEOUT(0xFF) |
+                   FSPI_MCR0_IP_TIMEOUT(0xFF) | (u32) FSPI_MCR0_OCTCOMB_EN,
+                   base + FSPI_MCR0);
 
        /*
         * Disable same device enable bit and configure all slave devices
@@ -976,9 +1019,8 @@ static int nxp_fspi_probe(struct platform_device *pdev)
 
        /* find the resources - controller memory mapped space */
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fspi_mmap");
-       f->ahb_addr = devm_ioremap_resource(dev, res);
-       if (IS_ERR(f->ahb_addr)) {
-               ret = PTR_ERR(f->ahb_addr);
+       if (!res) {
+               ret = -ENODEV;
                goto err_put_ctrl;
        }
 
@@ -1057,6 +1099,9 @@ static int nxp_fspi_remove(struct platform_device *pdev)
 
        mutex_destroy(&f->lock);
 
+       if (f->ahb_addr)
+               iounmap(f->ahb_addr);
+
        return 0;
 }
 
@@ -1076,6 +1121,8 @@ static int nxp_fspi_resume(struct device *dev)
 
 static const struct of_device_id nxp_fspi_dt_ids[] = {
        { .compatible = "nxp,lx2160a-fspi", .data = (void *)&lx2160a_data, },
+       { .compatible = "nxp,imx8mm-fspi", .data = (void *)&imx8mm_data, },
+       { .compatible = "nxp,imx8qxp-fspi", .data = (void *)&imx8qxp_data, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, nxp_fspi_dt_ids);
index 7e2292c..e9e2567 100644 (file)
@@ -130,6 +130,7 @@ struct omap2_mcspi {
        int                     fifo_depth;
        bool                    slave_aborted;
        unsigned int            pin_dir:1;
+       size_t                  max_xfer_len;
 };
 
 struct omap2_mcspi_cs {
@@ -974,20 +975,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
  * Note that we currently allow DMA only if we get a channel
  * for both rx and tx. Otherwise we'll do PIO for both rx and tx.
  */
-static int omap2_mcspi_request_dma(struct spi_device *spi)
+static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi,
+                                  struct omap2_mcspi_dma *mcspi_dma)
 {
-       struct spi_master       *master = spi->master;
-       struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_dma  *mcspi_dma;
        int ret = 0;
 
-       mcspi = spi_master_get_devdata(master);
-       mcspi_dma = mcspi->dma_channels + spi->chip_select;
-
-       init_completion(&mcspi_dma->dma_rx_completion);
-       init_completion(&mcspi_dma->dma_tx_completion);
-
-       mcspi_dma->dma_rx = dma_request_chan(&master->dev,
+       mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
                                             mcspi_dma->dma_rx_ch_name);
        if (IS_ERR(mcspi_dma->dma_rx)) {
                ret = PTR_ERR(mcspi_dma->dma_rx);
@@ -995,7 +988,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
                goto no_dma;
        }
 
-       mcspi_dma->dma_tx = dma_request_chan(&master->dev,
+       mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,
                                             mcspi_dma->dma_tx_ch_name);
        if (IS_ERR(mcspi_dma->dma_tx)) {
                ret = PTR_ERR(mcspi_dma->dma_tx);
@@ -1004,20 +997,40 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
                mcspi_dma->dma_rx = NULL;
        }
 
+       init_completion(&mcspi_dma->dma_rx_completion);
+       init_completion(&mcspi_dma->dma_tx_completion);
+
 no_dma:
        return ret;
 }
 
+static void omap2_mcspi_release_dma(struct spi_master *master)
+{
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+       struct omap2_mcspi_dma  *mcspi_dma;
+       int i;
+
+       for (i = 0; i < master->num_chipselect; i++) {
+               mcspi_dma = &mcspi->dma_channels[i];
+
+               if (mcspi_dma->dma_rx) {
+                       dma_release_channel(mcspi_dma->dma_rx);
+                       mcspi_dma->dma_rx = NULL;
+               }
+               if (mcspi_dma->dma_tx) {
+                       dma_release_channel(mcspi_dma->dma_tx);
+                       mcspi_dma->dma_tx = NULL;
+               }
+       }
+}
+
 static int omap2_mcspi_setup(struct spi_device *spi)
 {
        int                     ret;
        struct omap2_mcspi      *mcspi = spi_master_get_devdata(spi->master);
        struct omap2_mcspi_regs *ctx = &mcspi->ctx;
-       struct omap2_mcspi_dma  *mcspi_dma;
        struct omap2_mcspi_cs   *cs = spi->controller_state;
 
-       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-
        if (!cs) {
                cs = kzalloc(sizeof *cs, GFP_KERNEL);
                if (!cs)
@@ -1042,13 +1055,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                }
        }
 
-       if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
-               ret = omap2_mcspi_request_dma(spi);
-               if (ret)
-                       dev_warn(&spi->dev, "not using DMA for McSPI (%d)\n",
-                                ret);
-       }
-
        ret = pm_runtime_get_sync(mcspi->dev);
        if (ret < 0) {
                pm_runtime_put_noidle(mcspi->dev);
@@ -1065,12 +1071,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)
 
 static void omap2_mcspi_cleanup(struct spi_device *spi)
 {
-       struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_dma  *mcspi_dma;
        struct omap2_mcspi_cs   *cs;
 
-       mcspi = spi_master_get_devdata(spi->master);
-
        if (spi->controller_state) {
                /* Unlink controller state from context save list */
                cs = spi->controller_state;
@@ -1079,19 +1081,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
                kfree(cs);
        }
 
-       if (spi->chip_select < spi->master->num_chipselect) {
-               mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-
-               if (mcspi_dma->dma_rx) {
-                       dma_release_channel(mcspi_dma->dma_rx);
-                       mcspi_dma->dma_rx = NULL;
-               }
-               if (mcspi_dma->dma_tx) {
-                       dma_release_channel(mcspi_dma->dma_tx);
-                       mcspi_dma->dma_tx = NULL;
-               }
-       }
-
        if (gpio_is_valid(spi->cs_gpio))
                gpio_free(spi->cs_gpio);
 }
@@ -1302,9 +1291,24 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,
        if (spi_controller_is_slave(master))
                return true;
 
+       master->dma_rx = mcspi_dma->dma_rx;
+       master->dma_tx = mcspi_dma->dma_tx;
+
        return (xfer->len >= DMA_MIN_BYTES);
 }
 
+static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
+{
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+       struct omap2_mcspi_dma *mcspi_dma =
+               &mcspi->dma_channels[spi->chip_select];
+
+       if (mcspi->max_xfer_len && mcspi_dma->dma_rx)
+               return mcspi->max_xfer_len;
+
+       return SIZE_MAX;
+}
+
 static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
 {
        struct spi_master       *master = mcspi->master;
@@ -1373,6 +1377,11 @@ static struct omap2_mcspi_platform_config omap4_pdata = {
        .regs_offset = OMAP4_MCSPI_REG_OFFSET,
 };
 
+static struct omap2_mcspi_platform_config am654_pdata = {
+       .regs_offset = OMAP4_MCSPI_REG_OFFSET,
+       .max_xfer_len = SZ_4K - 1,
+};
+
 static const struct of_device_id omap_mcspi_of_match[] = {
        {
                .compatible = "ti,omap2-mcspi",
@@ -1382,6 +1391,10 @@ static const struct of_device_id omap_mcspi_of_match[] = {
                .compatible = "ti,omap4-mcspi",
                .data = &omap4_pdata,
        },
+       {
+               .compatible = "ti,am654-mcspi",
+               .data = &am654_pdata,
+       },
        { },
 };
 MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
@@ -1439,6 +1452,10 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
                mcspi->pin_dir = pdata->pin_dir;
        }
        regs_offset = pdata->regs_offset;
+       if (pdata->max_xfer_len) {
+               mcspi->max_xfer_len = pdata->max_xfer_len;
+               master->max_transfer_size = omap2_mcspi_max_xfer_size;
+       }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mcspi->base = devm_ioremap_resource(&pdev->dev, r);
@@ -1464,6 +1481,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        for (i = 0; i < master->num_chipselect; i++) {
                sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
                sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
+
+               status = omap2_mcspi_request_dma(mcspi,
+                                                &mcspi->dma_channels[i]);
+               if (status == -EPROBE_DEFER)
+                       goto free_master;
        }
 
        status = platform_get_irq(pdev, 0);
@@ -1501,6 +1523,7 @@ disable_pm:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 free_master:
+       omap2_mcspi_release_dma(master);
        spi_master_put(master);
        return status;
 }
@@ -1510,6 +1533,8 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
        struct spi_master *master = platform_get_drvdata(pdev);
        struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
 
+       omap2_mcspi_release_dma(master);
+
        pm_runtime_dont_use_autosuspend(mcspi->dev);
        pm_runtime_put_sync(mcspi->dev);
        pm_runtime_disable(&pdev->dev);
index 4c7a71f..73d2a65 100644 (file)
@@ -70,6 +70,10 @@ MODULE_ALIAS("platform:pxa2xx-spi");
 #define LPSS_CAPS_CS_EN_SHIFT                  9
 #define LPSS_CAPS_CS_EN_MASK                   (0xf << LPSS_CAPS_CS_EN_SHIFT)
 
+#define LPSS_PRIV_CLOCK_GATE 0x38
+#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3
+#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3
+
 struct lpss_config {
        /* LPSS offset from drv_data->ioaddr */
        unsigned offset;
@@ -86,6 +90,8 @@ struct lpss_config {
        unsigned cs_sel_shift;
        unsigned cs_sel_mask;
        unsigned cs_num;
+       /* Quirks */
+       unsigned cs_clk_stays_gated : 1;
 };
 
 /* Keep these sorted with enum pxa_ssp_type */
@@ -156,6 +162,7 @@ static const struct lpss_config lpss_platforms[] = {
                .tx_threshold_hi = 56,
                .cs_sel_shift = 8,
                .cs_sel_mask = 3 << 8,
+               .cs_clk_stays_gated = true,
        },
 };
 
@@ -185,6 +192,11 @@ static bool is_quark_x1000_ssp(const struct driver_data *drv_data)
        return drv_data->ssp_type == QUARK_X1000_SSP;
 }
 
+static bool is_mmp2_ssp(const struct driver_data *drv_data)
+{
+       return drv_data->ssp_type == MMP2_SSP;
+}
+
 static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data)
 {
        switch (drv_data->ssp_type) {
@@ -383,6 +395,22 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
        else
                value |= LPSS_CS_CONTROL_CS_HIGH;
        __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
+       if (config->cs_clk_stays_gated) {
+               u32 clkgate;
+
+               /*
+                * Changing CS alone when dynamic clock gating is on won't
+                * actually flip CS at that time. This ruins SPI transfers
+                * that specify delays, or have no data. Toggle the clock mode
+                * to force on briefly to poke the CS pin to move.
+                */
+               clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE);
+               value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) |
+                       LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON;
+
+               __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value);
+               __lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate);
+       }
 }
 
 static void cs_assert(struct spi_device *spi)
@@ -463,8 +491,8 @@ int pxa2xx_spi_flush(struct driver_data *drv_data)
 
 static void pxa2xx_spi_off(struct driver_data *drv_data)
 {
-       /* On MMP, disabling SSE seems to corrupt the rx fifo */
-       if (drv_data->ssp_type == MMP2_SSP)
+       /* On MMP, disabling SSE seems to corrupt the Rx FIFO */
+       if (is_mmp2_ssp(drv_data))
                return;
 
        pxa2xx_spi_write(drv_data, SSCR0,
@@ -1070,7 +1098,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
            || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask)
            != (cr1 & change_mask)) {
                /* stop the SSP, and update the other bits */
-               if (drv_data->ssp_type != MMP2_SSP)
+               if (!is_mmp2_ssp(drv_data))
                        pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE);
                if (!pxa25x_ssp_comp(drv_data))
                        pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
@@ -1084,7 +1112,7 @@ static int pxa2xx_spi_transfer_one(struct spi_controller *controller,
                        pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
        }
 
-       if (drv_data->ssp_type == MMP2_SSP) {
+       if (is_mmp2_ssp(drv_data)) {
                u8 tx_level = (pxa2xx_spi_read(drv_data, SSSR)
                                        & SSSR_TFL_MASK) >> 8;
 
@@ -1548,18 +1576,18 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
        else if (pcidev_id)
                type = (enum pxa_ssp_type)pcidev_id->driver_data;
        else
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        ssp = &pdata->ssp;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(ssp->mmio_base))
-               return NULL;
+               return ERR_CAST(ssp->mmio_base);
 
        ssp->phys_base = res->start;
 
@@ -1573,11 +1601,11 @@ pxa2xx_spi_init_pdata(struct platform_device *pdev)
 
        ssp->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssp->clk))
-               return NULL;
+               return ERR_CAST(ssp->clk);
 
        ssp->irq = platform_get_irq(pdev, 0);
        if (ssp->irq < 0)
-               return NULL;
+               return ERR_PTR(ssp->irq);
 
        ssp->type = type;
        ssp->dev = &pdev->dev;
@@ -1634,9 +1662,9 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
        platform_info = dev_get_platdata(dev);
        if (!platform_info) {
                platform_info = pxa2xx_spi_init_pdata(pdev);
-               if (!platform_info) {
+               if (IS_ERR(platform_info)) {
                        dev_err(&pdev->dev, "missing platform data\n");
-                       return -ENODEV;
+                       return PTR_ERR(platform_info);
                }
        }
 
@@ -1884,11 +1912,7 @@ out_error_controller_alloc:
 static int pxa2xx_spi_remove(struct platform_device *pdev)
 {
        struct driver_data *drv_data = platform_get_drvdata(pdev);
-       struct ssp_device *ssp;
-
-       if (!drv_data)
-               return 0;
-       ssp = drv_data->ssp;
+       struct ssp_device *ssp = drv_data->ssp;
 
        pm_runtime_get_sync(&pdev->dev);
 
index dd3434a..a364b99 100644 (file)
@@ -1217,6 +1217,11 @@ static int spi_qup_suspend(struct device *device)
        struct spi_qup *controller = spi_master_get_devdata(master);
        int ret;
 
+       if (pm_runtime_suspended(device)) {
+               ret = spi_qup_pm_resume_runtime(device);
+               if (ret)
+                       return ret;
+       }
        ret = spi_master_suspend(master);
        if (ret)
                return ret;
@@ -1225,10 +1230,8 @@ static int spi_qup_suspend(struct device *device)
        if (ret)
                return ret;
 
-       if (!pm_runtime_suspended(device)) {
-               clk_disable_unprepare(controller->cclk);
-               clk_disable_unprepare(controller->iclk);
-       }
+       clk_disable_unprepare(controller->cclk);
+       clk_disable_unprepare(controller->iclk);
        return 0;
 }
 
index 2cc6d99..70ef63e 100644 (file)
@@ -843,14 +843,17 @@ static const struct dev_pm_ops rockchip_spi_pm = {
 };
 
 static const struct of_device_id rockchip_spi_dt_match[] = {
-       { .compatible = "rockchip,rv1108-spi", },
+       { .compatible = "rockchip,px30-spi", },
        { .compatible = "rockchip,rk3036-spi", },
        { .compatible = "rockchip,rk3066-spi", },
        { .compatible = "rockchip,rk3188-spi", },
        { .compatible = "rockchip,rk3228-spi", },
        { .compatible = "rockchip,rk3288-spi", },
+       { .compatible = "rockchip,rk3308-spi", },
+       { .compatible = "rockchip,rk3328-spi", },
        { .compatible = "rockchip,rk3368-spi", },
        { .compatible = "rockchip,rk3399-spi", },
+       { .compatible = "rockchip,rv1108-spi", },
        { },
 };
 MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);
index 85575d4..06192c9 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/sh_dma.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/rspi.h>
+#include <linux/spinlock.h>
 
 #define RSPI_SPCR              0x00    /* Control Register */
 #define RSPI_SSLP              0x01    /* Slave Select Polarity Register */
@@ -79,8 +80,7 @@
 #define SPCR_BSWAP             0x01    /* Byte Swap of read-data for DMAC */
 
 /* SSLP - Slave Select Polarity Register */
-#define SSLP_SSL1P             0x02    /* SSL1 Signal Polarity Setting */
-#define SSLP_SSL0P             0x01    /* SSL0 Signal Polarity Setting */
+#define SSLP_SSLP(i)           BIT(i)  /* SSLi Signal Polarity Setting */
 
 /* SPPCR - Pin Control Register */
 #define SPPCR_MOIFE            0x20    /* MOSI Idle Value Fixing Enable */
@@ -181,7 +181,9 @@ struct rspi_data {
        void __iomem *addr;
        u32 max_speed_hz;
        struct spi_controller *ctlr;
+       struct platform_device *pdev;
        wait_queue_head_t wait;
+       spinlock_t lock;                /* Protects RMW-access to RSPI_SSLP */
        struct clk *clk;
        u16 spcmd;
        u8 spsr;
@@ -239,7 +241,7 @@ struct spi_ops {
        int (*set_config_register)(struct rspi_data *rspi, int access_size);
        int (*transfer_one)(struct spi_controller *ctlr,
                            struct spi_device *spi, struct spi_transfer *xfer);
-       u16 mode_bits;
+       u16 extra_mode_bits;
        u16 flags;
        u16 fifo_size;
        u8 num_hw_ss;
@@ -919,6 +921,29 @@ static int qspi_setup_sequencer(struct rspi_data *rspi,
        return 0;
 }
 
+static int rspi_setup(struct spi_device *spi)
+{
+       struct rspi_data *rspi = spi_controller_get_devdata(spi->controller);
+       u8 sslp;
+
+       if (spi->cs_gpiod)
+               return 0;
+
+       pm_runtime_get_sync(&rspi->pdev->dev);
+       spin_lock_irq(&rspi->lock);
+
+       sslp = rspi_read8(rspi, RSPI_SSLP);
+       if (spi->mode & SPI_CS_HIGH)
+               sslp |= SSLP_SSLP(spi->chip_select);
+       else
+               sslp &= ~SSLP_SSLP(spi->chip_select);
+       rspi_write8(rspi, sslp, RSPI_SSLP);
+
+       spin_unlock_irq(&rspi->lock);
+       pm_runtime_put(&rspi->pdev->dev);
+       return 0;
+}
+
 static int rspi_prepare_message(struct spi_controller *ctlr,
                                struct spi_message *msg)
 {
@@ -933,6 +958,8 @@ static int rspi_prepare_message(struct spi_controller *ctlr,
                rspi->spcmd |= SPCMD_CPOL;
        if (spi->mode & SPI_CPHA)
                rspi->spcmd |= SPCMD_CPHA;
+       if (spi->mode & SPI_LSB_FIRST)
+               rspi->spcmd |= SPCMD_LSBF;
 
        /* Configure slave signal to assert */
        rspi->spcmd |= SPCMD_SSLA(spi->cs_gpiod ? rspi->ctlr->unused_native_cs
@@ -1122,7 +1149,6 @@ static int rspi_remove(struct platform_device *pdev)
 static const struct spi_ops rspi_ops = {
        .set_config_register =  rspi_set_config_register,
        .transfer_one =         rspi_transfer_one,
-       .mode_bits =            SPI_CPHA | SPI_CPOL | SPI_LOOP,
        .flags =                SPI_CONTROLLER_MUST_TX,
        .fifo_size =            8,
        .num_hw_ss =            2,
@@ -1131,7 +1157,6 @@ static const struct spi_ops rspi_ops = {
 static const struct spi_ops rspi_rz_ops = {
        .set_config_register =  rspi_rz_set_config_register,
        .transfer_one =         rspi_rz_transfer_one,
-       .mode_bits =            SPI_CPHA | SPI_CPOL | SPI_LOOP,
        .flags =                SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX,
        .fifo_size =            8,      /* 8 for TX, 32 for RX */
        .num_hw_ss =            1,
@@ -1140,8 +1165,7 @@ static const struct spi_ops rspi_rz_ops = {
 static const struct spi_ops qspi_ops = {
        .set_config_register =  qspi_set_config_register,
        .transfer_one =         qspi_transfer_one,
-       .mode_bits =            SPI_CPHA | SPI_CPOL | SPI_LOOP |
-                               SPI_TX_DUAL | SPI_TX_QUAD |
+       .extra_mode_bits =      SPI_TX_DUAL | SPI_TX_QUAD |
                                SPI_RX_DUAL | SPI_RX_QUAD,
        .flags =                SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX,
        .fifo_size =            32,
@@ -1249,16 +1273,20 @@ static int rspi_probe(struct platform_device *pdev)
                goto error1;
        }
 
+       rspi->pdev = pdev;
        pm_runtime_enable(&pdev->dev);
 
        init_waitqueue_head(&rspi->wait);
+       spin_lock_init(&rspi->lock);
 
        ctlr->bus_num = pdev->id;
+       ctlr->setup = rspi_setup;
        ctlr->auto_runtime_pm = true;
        ctlr->transfer_one = ops->transfer_one;
        ctlr->prepare_message = rspi_prepare_message;
        ctlr->unprepare_message = rspi_unprepare_message;
-       ctlr->mode_bits = ops->mode_bits;
+       ctlr->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST |
+                         SPI_LOOP | ops->extra_mode_bits;
        ctlr->flags = ops->flags;
        ctlr->dev.of_node = pdev->dev.of_node;
        ctlr->use_gpio_descriptors = true;
index 2d6e37f..2cb3b61 100644 (file)
@@ -227,7 +227,7 @@ static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
 struct spi_fiq_code {
        u32     length;
        u32     ack_offset;
-       u8      data[0];
+       u8      data[];
 };
 
 extern struct spi_fiq_code s3c24xx_spi_fiq_txrx;
index 4ef569b..d066f51 100644 (file)
@@ -565,7 +565,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        qspi->io_base = devm_ioremap_resource(dev, res);
        if (IS_ERR(qspi->io_base)) {
                ret = PTR_ERR(qspi->io_base);
-               goto err;
+               goto err_master_put;
        }
 
        qspi->phys_base = res->start;
@@ -574,24 +574,26 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        qspi->mm_base = devm_ioremap_resource(dev, res);
        if (IS_ERR(qspi->mm_base)) {
                ret = PTR_ERR(qspi->mm_base);
-               goto err;
+               goto err_master_put;
        }
 
        qspi->mm_size = resource_size(res);
        if (qspi->mm_size > STM32_QSPI_MAX_MMAP_SZ) {
                ret = -EINVAL;
-               goto err;
+               goto err_master_put;
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0)
-               return irq;
+       if (irq < 0) {
+               ret = irq;
+               goto err_master_put;
+       }
 
        ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
                               dev_name(dev), qspi);
        if (ret) {
                dev_err(dev, "failed to request irq\n");
-               goto err;
+               goto err_master_put;
        }
 
        init_completion(&qspi->data_completion);
@@ -599,23 +601,27 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        qspi->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(qspi->clk)) {
                ret = PTR_ERR(qspi->clk);
-               goto err;
+               goto err_master_put;
        }
 
        qspi->clk_rate = clk_get_rate(qspi->clk);
        if (!qspi->clk_rate) {
                ret = -EINVAL;
-               goto err;
+               goto err_master_put;
        }
 
        ret = clk_prepare_enable(qspi->clk);
        if (ret) {
                dev_err(dev, "can not enable the clock\n");
-               goto err;
+               goto err_master_put;
        }
 
        rstc = devm_reset_control_get_exclusive(dev, NULL);
-       if (!IS_ERR(rstc)) {
+       if (IS_ERR(rstc)) {
+               ret = PTR_ERR(rstc);
+               if (ret == -EPROBE_DEFER)
+                       goto err_qspi_release;
+       } else {
                reset_control_assert(rstc);
                udelay(2);
                reset_control_deassert(rstc);
@@ -625,7 +631,7 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, qspi);
        ret = stm32_qspi_dma_setup(qspi);
        if (ret)
-               goto err;
+               goto err_qspi_release;
 
        mutex_init(&qspi->lock);
 
@@ -641,8 +647,9 @@ static int stm32_qspi_probe(struct platform_device *pdev)
        if (!ret)
                return 0;
 
-err:
+err_qspi_release:
        stm32_qspi_release(qspi);
+err_master_put:
        spi_master_put(qspi->ctrl);
 
        return ret;
index e041f9c..44ac6eb 100644 (file)
 #define SPI_DMA_MIN_BYTES      16
 
 /**
- * stm32_spi_reg - stm32 SPI register & bitfield desc
+ * struct stm32_spi_reg - stm32 SPI register & bitfield desc
  * @reg:               register offset
  * @mask:              bitfield mask
  * @shift:             left shift
@@ -187,16 +187,16 @@ struct stm32_spi_reg {
 };
 
 /**
- * stm32_spi_regspec - stm32 registers definition, compatible dependent data
- * en: enable register and SPI enable bit
- * dma_rx_en: SPI DMA RX enable register end SPI DMA RX enable bit
- * dma_tx_en: SPI DMA TX enable register end SPI DMA TX enable bit
- * cpol: clock polarity register and polarity bit
- * cpha: clock phase register and phase bit
- * lsb_first: LSB transmitted first register and bit
- * br: baud rate register and bitfields
- * rx: SPI RX data register
- * tx: SPI TX data register
+ * struct stm32_spi_regspec - stm32 registers definition, compatible dependent data
+ * @en: enable register and SPI enable bit
+ * @dma_rx_en: SPI DMA RX enable register end SPI DMA RX enable bit
+ * @dma_tx_en: SPI DMA TX enable register end SPI DMA TX enable bit
+ * @cpol: clock polarity register and polarity bit
+ * @cpha: clock phase register and phase bit
+ * @lsb_first: LSB transmitted first register and bit
+ * @br: baud rate register and bitfields
+ * @rx: SPI RX data register
+ * @tx: SPI TX data register
  */
 struct stm32_spi_regspec {
        const struct stm32_spi_reg en;
@@ -213,7 +213,7 @@ struct stm32_spi_regspec {
 struct stm32_spi;
 
 /**
- * stm32_spi_cfg - stm32 compatible configuration data
+ * struct stm32_spi_cfg - stm32 compatible configuration data
  * @regs: registers descriptions
  * @get_fifo_size: routine to get fifo size
  * @get_bpw_mask: routine to get bits per word mask
@@ -223,13 +223,13 @@ struct stm32_spi;
  * @set_mode: routine to configure registers to desired mode
  * @set_data_idleness: optional routine to configure registers to desired idle
  * time between frames (if driver has this functionality)
- * set_number_of_data: optional routine to configure registers to desired
+ * @set_number_of_data: optional routine to configure registers to desired
  * number of data (if driver has this functionality)
  * @can_dma: routine to determine if the transfer is eligible for DMA use
  * @transfer_one_dma_start: routine to start transfer a single spi_transfer
  * using DMA
- * @dma_rx cb: routine to call after DMA RX channel operation is complete
- * @dma_tx cb: routine to call after DMA TX channel operation is complete
+ * @dma_rx_cb: routine to call after DMA RX channel operation is complete
+ * @dma_tx_cb: routine to call after DMA TX channel operation is complete
  * @transfer_one_irq: routine to configure interrupts for driver
  * @irq_handler_event: Interrupt handler for SPI controller events
  * @irq_handler_thread: thread of interrupt handler for SPI controller
@@ -587,6 +587,7 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi)
 /**
  * stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register
  * @spi: pointer to the spi controller data structure
+ * @flush: boolean indicating that FIFO should be flushed
  *
  * Write in rx_buf depends on remaining bytes to avoid to write beyond
  * rx_buf end.
@@ -756,6 +757,9 @@ static void stm32h7_spi_disable(struct stm32_spi *spi)
 
 /**
  * stm32_spi_can_dma - Determine if the transfer is eligible for DMA use
+ * @master: controller master interface
+ * @spi_dev: pointer to the spi device
+ * @transfer: pointer to spi transfer
  *
  * If driver has fifo and the current transfer size is greater than fifo size,
  * use DMA. Otherwise use DMA for transfer longer than defined DMA min bytes.
@@ -974,6 +978,8 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
 
 /**
  * stm32_spi_prepare_msg - set up the controller to transfer a single message
+ * @master: controller master interface
+ * @msg: pointer to spi message
  */
 static int stm32_spi_prepare_msg(struct spi_master *master,
                                 struct spi_message *msg)
@@ -1026,6 +1032,7 @@ static int stm32_spi_prepare_msg(struct spi_master *master,
 
 /**
  * stm32f4_spi_dma_tx_cb - dma callback
+ * @data: pointer to the spi controller data structure
  *
  * DMA callback is called when the transfer is complete for DMA TX channel.
  */
@@ -1041,6 +1048,7 @@ static void stm32f4_spi_dma_tx_cb(void *data)
 
 /**
  * stm32f4_spi_dma_rx_cb - dma callback
+ * @data: pointer to the spi controller data structure
  *
  * DMA callback is called when the transfer is complete for DMA RX channel.
  */
@@ -1054,6 +1062,7 @@ static void stm32f4_spi_dma_rx_cb(void *data)
 
 /**
  * stm32h7_spi_dma_cb - dma callback
+ * @data: pointer to the spi controller data structure
  *
  * DMA callback is called when the transfer is complete or when an error
  * occurs. If the transfer is complete, EOT flag is raised.
@@ -1079,6 +1088,9 @@ static void stm32h7_spi_dma_cb(void *data)
 /**
  * stm32_spi_dma_config - configure dma slave channel depending on current
  *                       transfer bits_per_word.
+ * @spi: pointer to the spi controller data structure
+ * @dma_conf: pointer to the dma_slave_config structure
+ * @dir: direction of the dma transfer
  */
 static void stm32_spi_dma_config(struct stm32_spi *spi,
                                 struct dma_slave_config *dma_conf,
@@ -1126,6 +1138,7 @@ static void stm32_spi_dma_config(struct stm32_spi *spi,
 /**
  * stm32f4_spi_transfer_one_irq - transfer a single spi_transfer using
  *                               interrupts
+ * @spi: pointer to the spi controller data structure
  *
  * It must returns 0 if the transfer is finished or 1 if the transfer is still
  * in progress.
@@ -1166,6 +1179,7 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)
 /**
  * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using
  *                               interrupts
+ * @spi: pointer to the spi controller data structure
  *
  * It must returns 0 if the transfer is finished or 1 if the transfer is still
  * in progress.
@@ -1207,6 +1221,7 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi)
 /**
  * stm32f4_spi_transfer_one_dma_start - Set SPI driver registers to start
  *                                     transfer using DMA
+ * @spi: pointer to the spi controller data structure
  */
 static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi)
 {
@@ -1227,6 +1242,7 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi)
 /**
  * stm32h7_spi_transfer_one_dma_start - Set SPI driver registers to start
  *                                     transfer using DMA
+ * @spi: pointer to the spi controller data structure
  */
 static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
 {
@@ -1243,6 +1259,8 @@ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi)
 
 /**
  * stm32_spi_transfer_one_dma - transfer a single spi_transfer using DMA
+ * @spi: pointer to the spi controller data structure
+ * @xfer: pointer to the spi_transfer structure
  *
  * It must returns 0 if the transfer is finished or 1 if the transfer is still
  * in progress.
@@ -1405,7 +1423,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv)
 /**
  * stm32_spi_communication_type - return transfer communication type
  * @spi_dev: pointer to the spi device
- * transfer: pointer to spi transfer
+ * @transfer: pointer to spi transfer
  */
 static unsigned int stm32_spi_communication_type(struct spi_device *spi_dev,
                                                 struct spi_transfer *transfer)
@@ -1522,7 +1540,7 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len)
 /**
  * stm32h7_spi_number_of_data - configure number of data at current transfer
  * @spi: pointer to the spi controller data structure
- * @len: transfer length
+ * @nb_words: transfer length (in words)
  */
 static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words)
 {
@@ -1546,6 +1564,9 @@ static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words)
  * stm32_spi_transfer_one_setup - common setup to transfer a single
  *                               spi_transfer either using DMA or
  *                               interrupts.
+ * @spi: pointer to the spi controller data structure
+ * @spi_dev: pointer to the spi device
+ * @transfer: pointer to spi transfer
  */
 static int stm32_spi_transfer_one_setup(struct stm32_spi *spi,
                                        struct spi_device *spi_dev,
@@ -1625,6 +1646,9 @@ out:
 
 /**
  * stm32_spi_transfer_one - transfer a single spi_transfer
+ * @master: controller master interface
+ * @spi_dev: pointer to the spi device
+ * @transfer: pointer to spi transfer
  *
  * It must return 0 if the transfer is finished or 1 if the transfer is still
  * in progress.
@@ -1658,6 +1682,8 @@ static int stm32_spi_transfer_one(struct spi_master *master,
 
 /**
  * stm32_spi_unprepare_msg - relax the hardware
+ * @master: controller master interface
+ * @msg: pointer to the spi message
  */
 static int stm32_spi_unprepare_msg(struct spi_master *master,
                                   struct spi_message *msg)
@@ -1671,6 +1697,7 @@ static int stm32_spi_unprepare_msg(struct spi_master *master,
 
 /**
  * stm32f4_spi_config - Configure SPI controller as SPI master
+ * @spi: pointer to the spi controller data structure
  */
 static int stm32f4_spi_config(struct stm32_spi *spi)
 {
@@ -1701,6 +1728,7 @@ static int stm32f4_spi_config(struct stm32_spi *spi)
 
 /**
  * stm32h7_spi_config - Configure SPI controller as SPI master
+ * @spi: pointer to the spi controller data structure
  */
 static int stm32h7_spi_config(struct stm32_spi *spi)
 {
index 60c4de4..7412a30 100644 (file)
@@ -401,9 +401,6 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
 
        zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry);
 
-       /* Dummy generic FIFO entry */
-       zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0);
-
        /* Manually start the generic FIFO command */
        zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
                        zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
index 38b4c78..c92c894 100644 (file)
@@ -510,6 +510,7 @@ struct spi_device *spi_alloc_device(struct spi_controller *ctlr)
        spi->dev.bus = &spi_bus_type;
        spi->dev.release = spidev_release;
        spi->cs_gpio = -ENOENT;
+       spi->mode = ctlr->buswidth_override_bits;
 
        spin_lock_init(&spi->statistics.lock);
 
@@ -1514,17 +1515,15 @@ void spi_take_timestamp_pre(struct spi_controller *ctlr,
        if (!xfer->ptp_sts)
                return;
 
-       if (xfer->timestamped_pre)
+       if (xfer->timestamped)
                return;
 
-       if (progress < xfer->ptp_sts_word_pre)
+       if (progress > xfer->ptp_sts_word_pre)
                return;
 
        /* Capture the resolution of the timestamp */
        xfer->ptp_sts_word_pre = progress;
 
-       xfer->timestamped_pre = true;
-
        if (irqs_off) {
                local_irq_save(ctlr->irq_flags);
                preempt_disable();
@@ -1553,7 +1552,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr,
        if (!xfer->ptp_sts)
                return;
 
-       if (xfer->timestamped_post)
+       if (xfer->timestamped)
                return;
 
        if (progress < xfer->ptp_sts_word_post)
@@ -1569,7 +1568,7 @@ void spi_take_timestamp_post(struct spi_controller *ctlr,
        /* Capture the resolution of the timestamp */
        xfer->ptp_sts_word_post = progress;
 
-       xfer->timestamped_post = true;
+       xfer->timestamped = true;
 }
 EXPORT_SYMBOL_GPL(spi_take_timestamp_post);
 
@@ -1674,12 +1673,9 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
                }
        }
 
-       if (unlikely(ctlr->ptp_sts_supported)) {
-               list_for_each_entry(xfer, &mesg->transfers, transfer_list) {
-                       WARN_ON_ONCE(xfer->ptp_sts && !xfer->timestamped_pre);
-                       WARN_ON_ONCE(xfer->ptp_sts && !xfer->timestamped_post);
-               }
-       }
+       if (unlikely(ctlr->ptp_sts_supported))
+               list_for_each_entry(xfer, &mesg->transfers, transfer_list)
+                       WARN_ON_ONCE(xfer->ptp_sts && !xfer->timestamped);
 
        spi_unmap_msg(ctlr, mesg);
 
@@ -1955,13 +1951,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
                spi->mode |= SPI_CS_HIGH;
 
        /* Device speed */
-       rc = of_property_read_u32(nc, "spi-max-frequency", &value);
-       if (rc) {
-               dev_err(&ctlr->dev,
-                       "%pOF has no valid 'spi-max-frequency' property (%d)\n", nc, rc);
-               return rc;
-       }
-       spi->max_speed_hz = value;
+       if (!of_property_read_u32(nc, "spi-max-frequency", &value))
+               spi->max_speed_hz = value;
 
        return 0;
 }
@@ -2181,9 +2172,10 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr,
                return AE_NO_MEMORY;
        }
 
+
        ACPI_COMPANION_SET(&spi->dev, adev);
        spi->max_speed_hz       = lookup.max_speed_hz;
-       spi->mode               = lookup.mode;
+       spi->mode               |= lookup.mode;
        spi->irq                = lookup.irq;
        spi->bits_per_word      = lookup.bits_per_word;
        spi->chip_select        = lookup.chip_select;
@@ -2639,7 +2631,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                if (ctlr->use_gpio_descriptors) {
                        status = spi_get_gpio_descs(ctlr);
                        if (status)
-                               return status;
+                               goto free_bus_id;
                        /*
                         * A controller using GPIO descriptors always
                         * supports SPI_CS_HIGH if need be.
@@ -2649,7 +2641,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                        /* Legacy code path for GPIOs from DT */
                        status = of_spi_get_gpio_numbers(ctlr);
                        if (status)
-                               return status;
+                               goto free_bus_id;
                }
        }
 
@@ -2657,17 +2649,14 @@ int spi_register_controller(struct spi_controller *ctlr)
         * Even if it's just one always-selected device, there must
         * be at least one chipselect.
         */
-       if (!ctlr->num_chipselect)
-               return -EINVAL;
+       if (!ctlr->num_chipselect) {
+               status = -EINVAL;
+               goto free_bus_id;
+       }
 
        status = device_add(&ctlr->dev);
-       if (status < 0) {
-               /* free bus id */
-               mutex_lock(&board_lock);
-               idr_remove(&spi_master_idr, ctlr->bus_num);
-               mutex_unlock(&board_lock);
-               goto done;
-       }
+       if (status < 0)
+               goto free_bus_id;
        dev_dbg(dev, "registered %s %s\n",
                        spi_controller_is_slave(ctlr) ? "slave" : "master",
                        dev_name(&ctlr->dev));
@@ -2683,11 +2672,7 @@ int spi_register_controller(struct spi_controller *ctlr)
                status = spi_controller_initialize_queue(ctlr);
                if (status) {
                        device_del(&ctlr->dev);
-                       /* free bus id */
-                       mutex_lock(&board_lock);
-                       idr_remove(&spi_master_idr, ctlr->bus_num);
-                       mutex_unlock(&board_lock);
-                       goto done;
+                       goto free_bus_id;
                }
        }
        /* add statistics */
@@ -2702,7 +2687,12 @@ int spi_register_controller(struct spi_controller *ctlr)
        /* Register devices from the device tree and ACPI */
        of_register_spi_devices(ctlr);
        acpi_register_spi_devices(ctlr);
-done:
+       return status;
+
+free_bus_id:
+       mutex_lock(&board_lock);
+       idr_remove(&spi_master_idr, ctlr->bus_num);
+       mutex_unlock(&board_lock);
        return status;
 }
 EXPORT_SYMBOL_GPL(spi_register_controller);
@@ -4036,7 +4026,7 @@ static struct spi_device *acpi_spi_find_device_by_adev(struct acpi_device *adev)
        struct device *dev;
 
        dev = bus_find_device_by_acpi_dev(&spi_bus_type, adev);
-       return dev ? to_spi_device(dev) : NULL;
+       return to_spi_device(dev);
 }
 
 static int acpi_spi_notify(struct notifier_block *nb, unsigned long value,
index 1e217e3..80dd102 100644 (file)
@@ -275,14 +275,14 @@ static int spidev_message(struct spidev_data *spidev,
 #ifdef VERBOSE
                dev_dbg(&spidev->spi->dev,
                        "  xfer len %u %s%s%s%dbits %u usec %u usec %uHz\n",
-                       u_tmp->len,
-                       u_tmp->rx_buf ? "rx " : "",
-                       u_tmp->tx_buf ? "tx " : "",
-                       u_tmp->cs_change ? "cs " : "",
-                       u_tmp->bits_per_word ? : spidev->spi->bits_per_word,
-                       u_tmp->delay_usecs,
-                       u_tmp->word_delay_usecs,
-                       u_tmp->speed_hz ? : spidev->spi->max_speed_hz);
+                       k_tmp->len,
+                       k_tmp->rx_buf ? "rx " : "",
+                       k_tmp->tx_buf ? "tx " : "",
+                       k_tmp->cs_change ? "cs " : "",
+                       k_tmp->bits_per_word ? : spidev->spi->bits_per_word,
+                       k_tmp->delay.value,
+                       k_tmp->word_delay.value,
+                       k_tmp->speed_hz ? : spidev->spi->max_speed_hz);
 #endif
                spi_message_add_tail(k_tmp, &msg);
        }
@@ -396,6 +396,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                else
                        retval = get_user(tmp, (u32 __user *)arg);
                if (retval == 0) {
+                       struct spi_controller *ctlr = spi->controller;
                        u32     save = spi->mode;
 
                        if (tmp & ~SPI_MODE_MASK) {
@@ -403,6 +404,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                                break;
                        }
 
+                       if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
+                           ctlr->cs_gpiods[spi->chip_select])
+                               tmp |= SPI_CS_HIGH;
+
                        tmp |= spi->mode & ~SPI_MODE_MASK;
                        spi->mode = (u16)tmp;
                        retval = spi_setup(spi);
@@ -449,10 +454,11 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
                        spi->max_speed_hz = tmp;
                        retval = spi_setup(spi);
-                       if (retval >= 0)
+                       if (retval == 0) {
                                spidev->speed_hz = tmp;
-                       else
-                               dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
+                               dev_dbg(&spi->dev, "%d Hz (max)\n",
+                                       spidev->speed_hz);
+                       }
                        spi->max_speed_hz = save;
                }
                break;
index baccd7c..a9939ff 100644 (file)
@@ -42,6 +42,10 @@ source "drivers/staging/rtl8188eu/Kconfig"
 
 source "drivers/staging/rts5208/Kconfig"
 
+source "drivers/staging/octeon/Kconfig"
+
+source "drivers/staging/octeon-usb/Kconfig"
+
 source "drivers/staging/vt6655/Kconfig"
 
 source "drivers/staging/vt6656/Kconfig"
@@ -112,15 +116,8 @@ source "drivers/staging/fieldbus/Kconfig"
 
 source "drivers/staging/kpc2000/Kconfig"
 
-source "drivers/staging/wusbcore/Kconfig"
-source "drivers/staging/uwb/Kconfig"
-
-source "drivers/staging/exfat/Kconfig"
-
 source "drivers/staging/qlge/Kconfig"
 
-source "drivers/staging/hp/Kconfig"
-
 source "drivers/staging/wfx/Kconfig"
 
 endif # STAGING
index fdd03fd..4d34198 100644 (file)
@@ -12,6 +12,8 @@ obj-$(CONFIG_R8712U)          += rtl8712/
 obj-$(CONFIG_R8188EU)          += rtl8188eu/
 obj-$(CONFIG_RTS5208)          += rts5208/
 obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
+obj-$(CONFIG_OCTEON_ETHERNET)  += octeon/
+obj-$(CONFIG_OCTEON_USB)       += octeon-usb/
 obj-$(CONFIG_VT6655)           += vt6655/
 obj-$(CONFIG_VT6656)           += vt6656/
 obj-$(CONFIG_VME_BUS)          += vme/
@@ -46,9 +48,5 @@ obj-$(CONFIG_STAGING_GASKET_FRAMEWORK)        += gasket/
 obj-$(CONFIG_XIL_AXIS_FIFO)    += axis-fifo/
 obj-$(CONFIG_FIELDBUS_DEV)     += fieldbus/
 obj-$(CONFIG_KPC2000)          += kpc2000/
-obj-$(CONFIG_UWB)              += uwb/
-obj-$(CONFIG_USB_WUSB)         += wusbcore/
-obj-$(CONFIG_STAGING_EXFAT_FS) += exfat/
 obj-$(CONFIG_QLGE)             += qlge/
-obj-$(CONFIG_NET_VENDOR_HP)    += hp/
 obj-$(CONFIG_WFX)              += wfx/
index e15e33e..89dc84d 100644 (file)
@@ -484,14 +484,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
                s->async->events |= COMEDI_CB_EOA;
                return;
        }
-#if 0
-       /* clear the dual dma flag, making this the last dma segment */
-       /* XXX probably wrong */
-       if (!devpriv->ntrig) {
-               devpriv->supcsr &= ~DT2821_SUPCSR_DDMA;
-               outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
-       }
-#endif
+
        /* restart the channel */
        dt282x_prep_ai_dma(dev, dma->cur_dma, 0);
 
@@ -534,28 +527,7 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
                s_ao->async->events |= COMEDI_CB_ERROR;
                handled = 1;
        }
-#if 0
-       if (adcsr & DT2821_ADCSR_ADDONE) {
-               unsigned short data;
-
-               data = inw(dev->iobase + DT2821_ADDAT_REG);
-               data &= s->maxdata;
-               if (devpriv->ad_2scomp)
-                       data = comedi_offset_munge(s, data);
 
-               comedi_buf_write_samples(s, &data, 1);
-
-               devpriv->nread--;
-               if (!devpriv->nread) {
-                       s->async->events |= COMEDI_CB_EOA;
-               } else {
-                       if (supcsr & DT2821_SUPCSR_SCDN)
-                               outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
-                                    dev->iobase + DT2821_SUPCSR_REG);
-               }
-               handled = 1;
-       }
-#endif
        comedi_handle_events(dev, s);
        if (s_ao)
                comedi_handle_events(dev, s_ao);
index f7c365b..011e191 100644 (file)
@@ -439,9 +439,8 @@ static int dt3k_ai_cmdtest(struct comedi_device *dev,
 
                if (cmd->scan_begin_src == TRIG_TIMER) {
                        arg = cmd->convert_arg * cmd->scan_end_arg;
-                       err |= comedi_check_trigger_arg_min(&cmd->
-                                                           scan_begin_arg,
-                                                           arg);
+                       err |= comedi_check_trigger_arg_min(
+                               &cmd->scan_begin_arg, arg);
                }
        }
 
index 4ee9b26..75d5c9c 100644 (file)
@@ -1035,7 +1035,7 @@ static int ni_660x_auto_attach(struct comedi_device *dev,
        ni_660x_init_tio_chips(dev, board->n_chips);
 
        /* prepare the device for globally-named routes. */
-       if (ni_assign_device_routes("ni_660x", board->name,
+       if (ni_assign_device_routes("ni_660x", board->name, NULL,
                                    &devpriv->routing_tables) < 0) {
                dev_warn(dev->class_dev, "%s: %s device has no signal routing table.\n",
                         __func__, board->name);
index 68ad967..0bca7d7 100644 (file)
@@ -266,19 +266,9 @@ static int atmio16d_ai_cmdtest(struct comedi_device *dev,
        if (cmd->scan_begin_src == TRIG_FOLLOW) {
                /* internal trigger */
                err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
-       } else {
-#if 0
-               /* external trigger */
-               /* should be level/edge, hi/lo specification here */
-               err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
-#endif
        }
 
        err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000);
-#if 0
-       err |= comedi_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER);
-#endif
-
        err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
                                           cmd->chanlist_len);
 
index 406952f..ce0f850 100644 (file)
@@ -560,14 +560,13 @@ static int labpc_ai_cmdtest(struct comedi_device *dev,
        /* make sure scan timing is not too fast */
        if (cmd->scan_begin_src == TRIG_TIMER) {
                if (cmd->convert_src == TRIG_TIMER) {
-                       err |= comedi_check_trigger_arg_min(&cmd->
-                                                           scan_begin_arg,
-                                                           cmd->convert_arg *
-                                                           cmd->chanlist_len);
+                       err |= comedi_check_trigger_arg_min(
+                                       &cmd->scan_begin_arg,
+                                       cmd->convert_arg * cmd->chanlist_len);
                }
-               err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
-                                                   board->ai_speed *
-                                                   cmd->chanlist_len);
+               err |= comedi_check_trigger_arg_min(
+                                       &cmd->scan_begin_arg,
+                                       board->ai_speed * cmd->chanlist_len);
        }
 
        switch (cmd->stop_src) {
index f98e3ae..d99f406 100644 (file)
@@ -2199,9 +2199,10 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
                break;
        case TRIG_EXT:
                ai_trig |= NISTC_AI_TRIG_START1_SEL(
-                       ni_get_reg_value_roffs(CR_CHAN(cmd->start_arg),
-                                              NI_AI_StartTrigger,
-                                              &devpriv->routing_tables, 1));
+                               ni_get_reg_value_roffs(
+                                       CR_CHAN(cmd->start_arg),
+                                       NI_AI_StartTrigger,
+                                       &devpriv->routing_tables, 1));
 
                if (cmd->start_arg & CR_INVERT)
                        ai_trig |= NISTC_AI_TRIG_START1_POLARITY;
@@ -2311,10 +2312,12 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
                    (cmd->scan_begin_arg & ~CR_EDGE) !=
                    (cmd->convert_arg & ~CR_EDGE))
                        start_stop_select |= NISTC_AI_START_SYNC;
+
                start_stop_select |= NISTC_AI_START_SEL(
-                       ni_get_reg_value_roffs(CR_CHAN(cmd->scan_begin_arg),
-                                              NI_AI_SampleClock,
-                                              &devpriv->routing_tables, 1));
+                                       ni_get_reg_value_roffs(
+                                               CR_CHAN(cmd->scan_begin_arg),
+                                               NI_AI_SampleClock,
+                                               &devpriv->routing_tables, 1));
                ni_stc_writew(dev, start_stop_select, NISTC_AI_START_STOP_REG);
                break;
        }
@@ -2343,9 +2346,10 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
                break;
        case TRIG_EXT:
                mode1 |= NISTC_AI_MODE1_CONVERT_SRC(
-                       ni_get_reg_value_roffs(CR_CHAN(cmd->convert_arg),
-                                              NI_AI_ConvertClock,
-                                              &devpriv->routing_tables, 1));
+                               ni_get_reg_value_roffs(
+                                               CR_CHAN(cmd->convert_arg),
+                                               NI_AI_ConvertClock,
+                                               &devpriv->routing_tables, 1));
                if ((cmd->convert_arg & CR_INVERT) == 0)
                        mode1 |= NISTC_AI_MODE1_CONVERT_POLARITY;
                ni_stc_writew(dev, mode1, NISTC_AI_MODE1_REG);
@@ -2970,9 +2974,11 @@ static void ni_ao_cmd_set_trigger(struct comedi_device *dev,
                          NISTC_AO_TRIG_START1_SYNC;
        } else { /* TRIG_EXT */
                trigsel = NISTC_AO_TRIG_START1_SEL(
-                       ni_get_reg_value_roffs(CR_CHAN(cmd->start_arg),
-                                              NI_AO_StartTrigger,
-                                              &devpriv->routing_tables, 1));
+                               ni_get_reg_value_roffs(
+                                               CR_CHAN(cmd->start_arg),
+                                               NI_AO_StartTrigger,
+                                               &devpriv->routing_tables, 1));
+
                /* 0=active high, 1=active low. see daq-stc 3-24 (p186) */
                if (cmd->start_arg & CR_INVERT)
                        trigsel |= NISTC_AO_TRIG_START1_POLARITY;
@@ -3079,12 +3085,10 @@ static void ni_ao_cmd_set_update(struct comedi_device *dev,
         * zero out these bit fields to be set below. Does an ao-reset do this
         * automatically?
         */
-       devpriv->ao_mode1 &= ~(
-         NISTC_AO_MODE1_UI_SRC_MASK         |
-         NISTC_AO_MODE1_UI_SRC_POLARITY     |
-         NISTC_AO_MODE1_UPDATE_SRC_MASK     |
-         NISTC_AO_MODE1_UPDATE_SRC_POLARITY
-       );
+       devpriv->ao_mode1 &=  ~(NISTC_AO_MODE1_UI_SRC_MASK         |
+                               NISTC_AO_MODE1_UI_SRC_POLARITY     |
+                               NISTC_AO_MODE1_UPDATE_SRC_MASK     |
+                               NISTC_AO_MODE1_UPDATE_SRC_POLARITY);
 
        if (cmd->scan_begin_src == TRIG_TIMER) {
                unsigned int trigvar;
@@ -3134,9 +3138,10 @@ static void ni_ao_cmd_set_update(struct comedi_device *dev,
                /* FIXME:  assert scan_begin_arg != 0, ret failure otherwise */
                devpriv->ao_cmd2  |= NISTC_AO_CMD2_BC_GATE_ENA;
                devpriv->ao_mode1 |= NISTC_AO_MODE1_UPDATE_SRC(
-                       ni_get_reg_value(CR_CHAN(cmd->scan_begin_arg),
-                                        NI_AO_SampleClock,
-                                        &devpriv->routing_tables));
+                                       ni_get_reg_value(
+                                               CR_CHAN(cmd->scan_begin_arg),
+                                               NI_AO_SampleClock,
+                                               &devpriv->routing_tables));
                if (cmd->scan_begin_arg & CR_INVERT)
                        devpriv->ao_mode1 |= NISTC_AO_MODE1_UPDATE_SRC_POLARITY;
        }
@@ -3673,9 +3678,10 @@ static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        cdo_mode_bits = NI_M_CDO_MODE_FIFO_MODE |
                        NI_M_CDO_MODE_HALT_ON_ERROR |
                        NI_M_CDO_MODE_SAMPLE_SRC(
-                               ni_get_reg_value(CR_CHAN(cmd->scan_begin_arg),
-                                                NI_DO_SampleClock,
-                                                &devpriv->routing_tables));
+                               ni_get_reg_value(
+                                       CR_CHAN(cmd->scan_begin_arg),
+                                       NI_DO_SampleClock,
+                                       &devpriv->routing_tables));
        if (cmd->scan_begin_arg & CR_INVERT)
                cdo_mode_bits |= NI_M_CDO_MODE_POLARITY;
        ni_writel(dev, cdo_mode_bits, NI_M_CDO_MODE_REG);
@@ -5975,6 +5981,7 @@ static int ni_E_init(struct comedi_device *dev,
 
        /* prepare the device for globally-named routes. */
        if (ni_assign_device_routes(dev_family, board->name,
+                                   board->alt_route_name,
                                    &devpriv->routing_tables) < 0) {
                dev_warn(dev->class_dev, "%s: %s device has no signal routing table.\n",
                         __func__, board->name);
index 14b26ff..7c82d5f 100644 (file)
@@ -888,6 +888,7 @@ static const struct ni_board_struct ni_boards[] = {
        },
        [BOARD_PCIE6251] = {
                .name           = "pcie-6251",
+               .alt_route_name = "pci-6251",
                .n_adchan       = 16,
                .ai_maxdata     = 0xffff,
                .ai_fifo_depth  = 4095,
@@ -976,6 +977,7 @@ static const struct ni_board_struct ni_boards[] = {
        },
        [BOARD_PCIE6259] = {
                .name           = "pcie-6259",
+               .alt_route_name = "pci-6259",
                .n_adchan       = 32,
                .ai_maxdata     = 0xffff,
                .ai_fifo_depth  = 4095,
index 8f398b3..07cb970 100644 (file)
 #define RVi(table, src, dest)  ((table)[(dest) * NI_NUM_NAMES + (src)])
 
 /*
- * Find the proper route_values and ni_device_routes tables for this particular
- * device.
- *
- * Return: -ENODATA if either was not found; 0 if both were found.
+ * Find the route values for a device family.
  */
-static int ni_find_device_routes(const char *device_family,
-                                const char *board_name,
-                                struct ni_route_tables *tables)
+static const u8 *ni_find_route_values(const char *device_family)
 {
-       const struct ni_device_routes *dr = NULL;
        const u8 *rv = NULL;
        int i;
 
-       /* First, find the register_values table for this device family */
        for (i = 0; ni_all_route_values[i]; ++i) {
                if (memcmp(ni_all_route_values[i]->family, device_family,
                           strnlen(device_family, 30)) == 0) {
@@ -71,8 +64,18 @@ static int ni_find_device_routes(const char *device_family,
                        break;
                }
        }
+       return rv;
+}
+
+/*
+ * Find the valid routes for a board.
+ */
+static const struct ni_device_routes *
+ni_find_valid_routes(const char *board_name)
+{
+       const struct ni_device_routes *dr = NULL;
+       int i;
 
-       /* Second, find the set of routes valid for this device. */
        for (i = 0; ni_device_routes_list[i]; ++i) {
                if (memcmp(ni_device_routes_list[i]->device, board_name,
                           strnlen(board_name, 30)) == 0) {
@@ -80,6 +83,31 @@ static int ni_find_device_routes(const char *device_family,
                        break;
                }
        }
+       return dr;
+}
+
+/*
+ * Find the proper route_values and ni_device_routes tables for this particular
+ * device.  Possibly try an alternate board name if device routes not found
+ * for the actual board name.
+ *
+ * Return: -ENODATA if either was not found; 0 if both were found.
+ */
+static int ni_find_device_routes(const char *device_family,
+                                const char *board_name,
+                                const char *alt_board_name,
+                                struct ni_route_tables *tables)
+{
+       const struct ni_device_routes *dr;
+       const u8 *rv;
+
+       /* First, find the register_values table for this device family */
+       rv = ni_find_route_values(device_family);
+
+       /* Second, find the set of routes valid for this device. */
+       dr = ni_find_valid_routes(board_name);
+       if (!dr && alt_board_name)
+               dr = ni_find_valid_routes(alt_board_name);
 
        tables->route_values = rv;
        tables->valid_routes = dr;
@@ -93,15 +121,28 @@ static int ni_find_device_routes(const char *device_family,
 /**
  * ni_assign_device_routes() - Assign the proper lookup table for NI signal
  *                            routing to the specified NI device.
+ * @device_family: Device family name (determines route values).
+ * @board_name: Board name (determines set of routes).
+ * @alt_board_name: Optional alternate board name to try on failure.
+ * @tables: Pointer to assigned routing information.
+ *
+ * Finds the route values for the device family and the set of valid routes
+ * for the board.  If valid routes could not be found for the actual board
+ * name and an alternate board name has been specified, try that one.
+ *
+ * On failure, the assigned routing information may be partially filled
+ * (for example, with the route values but not the set of valid routes).
  *
  * Return: -ENODATA if assignment was not successful; 0 if successful.
  */
 int ni_assign_device_routes(const char *device_family,
                            const char *board_name,
+                           const char *alt_board_name,
                            struct ni_route_tables *tables)
 {
        memset(tables, 0, sizeof(struct ni_route_tables));
-       return ni_find_device_routes(device_family, board_name, tables);
+       return ni_find_device_routes(device_family, board_name, alt_board_name,
+                                    tables);
 }
 EXPORT_SYMBOL_GPL(ni_assign_device_routes);
 
index 3211a16..b7680fd 100644 (file)
@@ -76,6 +76,7 @@ struct ni_route_tables {
  */
 int ni_assign_device_routes(const char *device_family,
                            const char *board_name,
+                           const char *alt_board_name,
                            struct ni_route_tables *tables);
 
 /*
index 35427f8..fbc0b75 100644 (file)
@@ -941,6 +941,7 @@ enum ni_reg_type {
 
 struct ni_board_struct {
        const char *name;
+       const char *alt_route_name;
        int device_id;
        int isapnp_id;
 
index b264db3..f6154ad 100644 (file)
@@ -1342,8 +1342,8 @@ static int ni_m_gate2_to_generic_gate(unsigned int gate, unsigned int *src)
 
 static inline unsigned int ni_tio_get_gate_mode(struct ni_gpct *counter)
 {
-       unsigned int mode = ni_tio_get_soft_copy(
-               counter, NITIO_MODE_REG(counter->counter_index));
+       unsigned int mode = ni_tio_get_soft_copy(counter,
+                               NITIO_MODE_REG(counter->counter_index));
        unsigned int ret = 0;
 
        if ((mode & GI_GATING_MODE_MASK) == GI_GATING_DISABLED)
@@ -1358,8 +1358,8 @@ static inline unsigned int ni_tio_get_gate_mode(struct ni_gpct *counter)
 
 static inline unsigned int ni_tio_get_gate2_mode(struct ni_gpct *counter)
 {
-       unsigned int mode = ni_tio_get_soft_copy(
-               counter, NITIO_GATE2_REG(counter->counter_index));
+       unsigned int mode = ni_tio_get_soft_copy(counter,
+                               NITIO_GATE2_REG(counter->counter_index));
        unsigned int ret = 0;
 
        if (!(mode & GI_GATE2_MODE))
index bb400e0..8c04af0 100644 (file)
@@ -815,9 +815,8 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
 
                if (cmd->scan_begin_src == TRIG_TIMER) {
                        arg = cmd->convert_arg * cmd->scan_end_arg;
-                       err |= comedi_check_trigger_arg_min(&cmd->
-                                                           scan_begin_arg,
-                                                           arg);
+                       err |= comedi_check_trigger_arg_min(
+                                       &cmd->scan_begin_arg, arg);
                }
        }
 
index 39049d3..084a8e7 100644 (file)
@@ -1892,8 +1892,7 @@ static int s626_ai_cmdtest(struct comedi_device *dev,
                if (cmd->scan_begin_src == TRIG_TIMER) {
                        arg = cmd->convert_arg * cmd->scan_end_arg;
                        err |= comedi_check_trigger_arg_min(
-                               &cmd->scan_begin_arg,
-                               arg);
+                                       &cmd->scan_begin_arg, arg);
                }
        }
 
diff --git a/drivers/staging/exfat/Kconfig b/drivers/staging/exfat/Kconfig
deleted file mode 100644 (file)
index 292a19d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-config STAGING_EXFAT_FS
-       tristate "exFAT fs support"
-       depends on BLOCK
-       select NLS
-       help
-         This adds support for the exFAT file system.
-
-config STAGING_EXFAT_DISCARD
-       bool "enable discard support"
-       depends on STAGING_EXFAT_FS
-       default y
-
-config STAGING_EXFAT_DELAYED_SYNC
-       bool "enable delayed sync"
-       depends on STAGING_EXFAT_FS
-       default n
-
-config STAGING_EXFAT_KERNEL_DEBUG
-       bool "enable kernel debug features via ioctl"
-       depends on STAGING_EXFAT_FS
-       default n
-
-config STAGING_EXFAT_DEBUG_MSG
-       bool "print debug messages"
-       depends on STAGING_EXFAT_FS
-       default n
-
-config STAGING_EXFAT_DEFAULT_CODEPAGE
-       int "Default codepage for exFAT"
-       default 437
-       depends on STAGING_EXFAT_FS
-       help
-         This option should be set to the codepage of your exFAT filesystems.
-
-config STAGING_EXFAT_DEFAULT_IOCHARSET
-       string "Default iocharset for exFAT"
-       default "utf8"
-       depends on STAGING_EXFAT_FS
-       help
-         Set this to the default input/output character set you'd like exFAT to use.
diff --git a/drivers/staging/exfat/Makefile b/drivers/staging/exfat/Makefile
deleted file mode 100644 (file)
index 057556e..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-obj-$(CONFIG_STAGING_EXFAT_FS) += exfat.o
-
-exfat-y :=     exfat_core.o    \
-               exfat_super.o   \
-               exfat_blkdev.o  \
-               exfat_cache.o   \
-               exfat_nls.o     \
-               exfat_upcase.o
diff --git a/drivers/staging/exfat/TODO b/drivers/staging/exfat/TODO
deleted file mode 100644 (file)
index a283ce5..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-A laundry list of things that need looking at, most of which will
-require more work than the average checkpatch cleanup...
-
-Note that some of these entries may not be bugs - they're things
-that need to be looked at, and *possibly* fixed.
-
-Clean up the ffsCamelCase function names.
-
-Fix (thing)->flags to not use magic numbers - multiple offenders
-
-Sort out all the s32/u32/u8 nonsense - most of these should be plain int.
-
-exfat_core.c - ffsReadFile - the goto err_out seem to leak a brelse().
-same for ffsWriteFile.
-
-All the calls to fs_sync() need to be looked at, particularly in the
-context of EXFAT_DELAYED_SYNC. Currently, if that's defined, we only
-flush to disk when sync() gets called.  We should be doing at least
-metadata flushes at appropriate times.
-
-ffsTruncateFile -  if (old_size <= new_size) {
-That doesn't look right. How did it ever work? Are they relying on lazy
-block allocation when actual writes happen? If nothing else, it never
-does the 'fid->size = new_size' and do the inode update....
-
-ffsSetAttr() is just dangling in the breeze, not wired up at all...
-
-Convert global mutexes to a per-superblock mutex.
-
-Right now, we load exactly one UTF-8 table. Check to see
-if that plays nice with different codepage and iocharset values
-for simultanous mounts of different devices
-
-exfat_rmdir() checks for -EBUSY but ffsRemoveDir() doesn't return it.
-In fact, there's a complete lack of -EBUSY testing anywhere.
-
-There's probably a few missing checks for -EEXIST
-
-check return codes of sync_dirty_buffer()
-
-Why is remove_file doing a num_entries++??
-
-Double check a lot of can't-happen parameter checks (for null pointers for
-things that have only one call site and can't pass a null, etc).
-
-All the DEBUG stuff can probably be tossed, including the ioctl(). Either
-that, or convert to a proper fault-injection system.
-
-exfat_remount does exactly one thing.  Fix to actually deal with remount
-options, particularly handling R/O correctly.  For that matter, allow
-R/O mounts in the first place.
-
-Figure out why the VFAT code used multi_sector_(read|write) but the
-exfat code doesn't use it. The difference matters on SSDs with wear leveling.
-
-exfat_fat_sync(), exfat_buf_sync(), and sync_alloc_bitmap()
-aren't called anyplace....
-
-Create helper function for exfat_set_entry_time() and exfat_set_entry_type()
-because it's sort of ugly to be calling the same functionn directly and
-other code calling through the fs_func struc ponters...
-
-clean up the remaining vol_type checks, which are of two types:
-some are ?: operators with magic numbers, and the rest are places
-where we're doing stuff with '.' and '..'.
-
-Patches to:
-       Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-       Valdis Kletnieks <valdis.kletnieks@vt.edu>
diff --git a/drivers/staging/exfat/exfat.h b/drivers/staging/exfat/exfat.h
deleted file mode 100644 (file)
index 4d87360..0000000
+++ /dev/null
@@ -1,824 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
- */
-
-#ifndef _EXFAT_H
-#define _EXFAT_H
-
-#include <linux/types.h>
-#include <linux/buffer_head.h>
-
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-  /* For Debugging Purpose */
-       /* IOCTL code 'f' used by
-        *   - file systems typically #0~0x1F
-        *   - embedded terminal devices #128~
-        *   - exts for debugging purpose #99
-        * number 100 and 101 is available now but has possible conflicts
-        */
-#define EXFAT_IOC_GET_DEBUGFLAGS       _IOR('f', 100, long)
-#define EXFAT_IOC_SET_DEBUGFLAGS       _IOW('f', 101, long)
-
-#define EXFAT_DEBUGFLAGS_INVALID_UMOUNT        0x01
-#define EXFAT_DEBUGFLAGS_ERROR_RW      0x02
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-
-#ifdef CONFIG_STAGING_EXFAT_DEBUG_MSG
-#define DEBUG  1
-#else
-#undef DEBUG
-#endif
-
-#define EFSCORRUPTED   EUCLEAN         /* Filesystem is corrupted */
-
-#define DENTRY_SIZE            32      /* dir entry size */
-#define DENTRY_SIZE_BITS       5
-
-/* PBR entries */
-#define PBR_SIGNATURE  0xAA55
-#define EXT_SIGNATURE  0xAA550000
-#define VOL_LABEL      "NO NAME    "   /* size should be 11 */
-#define OEM_NAME       "MSWIN4.1"      /* size should be 8 */
-#define STR_FAT12      "FAT12   "      /* size should be 8 */
-#define STR_FAT16      "FAT16   "      /* size should be 8 */
-#define STR_FAT32      "FAT32   "      /* size should be 8 */
-#define STR_EXFAT      "EXFAT   "      /* size should be 8 */
-#define VOL_CLEAN      0x0000
-#define VOL_DIRTY      0x0002
-
-/* max number of clusters */
-#define FAT12_THRESHOLD                4087            /* 2^12 - 1 + 2 (clu 0 & 1) */
-#define FAT16_THRESHOLD                65527           /* 2^16 - 1 + 2 */
-#define FAT32_THRESHOLD                268435457       /* 2^28 - 1 + 2 */
-#define EXFAT_THRESHOLD                268435457       /* 2^28 - 1 + 2 */
-
-/* file types */
-#define TYPE_UNUSED            0x0000
-#define TYPE_DELETED           0x0001
-#define TYPE_INVALID           0x0002
-#define TYPE_CRITICAL_PRI      0x0100
-#define TYPE_BITMAP            0x0101
-#define TYPE_UPCASE            0x0102
-#define TYPE_VOLUME            0x0103
-#define TYPE_DIR               0x0104
-#define TYPE_FILE              0x011F
-#define TYPE_SYMLINK           0x015F
-#define TYPE_CRITICAL_SEC      0x0200
-#define TYPE_STREAM            0x0201
-#define TYPE_EXTEND            0x0202
-#define TYPE_ACL               0x0203
-#define TYPE_BENIGN_PRI                0x0400
-#define TYPE_GUID              0x0401
-#define TYPE_PADDING           0x0402
-#define TYPE_ACLTAB            0x0403
-#define TYPE_BENIGN_SEC                0x0800
-#define TYPE_ALL               0x0FFF
-
-/* time modes */
-#define TM_CREATE              0
-#define TM_MODIFY              1
-#define TM_ACCESS              2
-
-/* checksum types */
-#define CS_DIR_ENTRY           0
-#define CS_PBR_SECTOR          1
-#define CS_DEFAULT             2
-
-#define CLUSTER_16(x)          ((u16)(x))
-#define CLUSTER_32(x)          ((u32)(x))
-
-#define START_SECTOR(x)                                                        \
-       ((((sector_t)((x) - 2)) << p_fs->sectors_per_clu_bits) +        \
-        p_fs->data_start_sector)
-
-#define IS_LAST_SECTOR_IN_CLUSTER(sec)                         \
-       ((((sec) - p_fs->data_start_sector + 1) &               \
-         ((1 <<  p_fs->sectors_per_clu_bits) - 1)) == 0)
-
-#define GET_CLUSTER_FROM_SECTOR(sec)                           \
-       ((u32)((((sec) - p_fs->data_start_sector) >>            \
-               p_fs->sectors_per_clu_bits) + 2))
-
-#define GET16(p_src)                                           \
-       (((u16)(p_src)[0]) | (((u16)(p_src)[1]) << 8))
-#define GET32(p_src)                                           \
-       (((u32)(p_src)[0]) | (((u32)(p_src)[1]) << 8) |         \
-       (((u32)(p_src)[2]) << 16) | (((u32)(p_src)[3]) << 24))
-#define GET64(p_src) \
-       (((u64)(p_src)[0]) | (((u64)(p_src)[1]) << 8) |         \
-       (((u64)(p_src)[2]) << 16) | (((u64)(p_src)[3]) << 24) | \
-       (((u64)(p_src)[4]) << 32) | (((u64)(p_src)[5]) << 40) | \
-       (((u64)(p_src)[6]) << 48) | (((u64)(p_src)[7]) << 56))
-
-#define SET16(p_dst, src)                                      \
-       do {                                                    \
-               (p_dst)[0] = (u8)(src);                         \
-               (p_dst)[1] = (u8)(((u16)(src)) >> 8);           \
-       } while (0)
-#define SET32(p_dst, src)                                      \
-       do {                                                    \
-               (p_dst)[0] = (u8)(src);                         \
-               (p_dst)[1] = (u8)(((u32)(src)) >> 8);           \
-               (p_dst)[2] = (u8)(((u32)(src)) >> 16);          \
-               (p_dst)[3] = (u8)(((u32)(src)) >> 24);          \
-       } while (0)
-#define SET64(p_dst, src)                                      \
-       do {                                                    \
-               (p_dst)[0] = (u8)(src);                         \
-               (p_dst)[1] = (u8)(((u64)(src)) >> 8);           \
-               (p_dst)[2] = (u8)(((u64)(src)) >> 16);          \
-               (p_dst)[3] = (u8)(((u64)(src)) >> 24);          \
-               (p_dst)[4] = (u8)(((u64)(src)) >> 32);          \
-               (p_dst)[5] = (u8)(((u64)(src)) >> 40);          \
-               (p_dst)[6] = (u8)(((u64)(src)) >> 48);          \
-               (p_dst)[7] = (u8)(((u64)(src)) >> 56);          \
-       } while (0)
-
-#ifdef __LITTLE_ENDIAN
-#define GET16_A(p_src)         (*((u16 *)(p_src)))
-#define GET32_A(p_src)         (*((u32 *)(p_src)))
-#define GET64_A(p_src)         (*((u64 *)(p_src)))
-#define SET16_A(p_dst, src)    (*((u16 *)(p_dst)) = (u16)(src))
-#define SET32_A(p_dst, src)    (*((u32 *)(p_dst)) = (u32)(src))
-#define SET64_A(p_dst, src)    (*((u64 *)(p_dst)) = (u64)(src))
-#else /* BIG_ENDIAN */
-#define GET16_A(p_src)         GET16(p_src)
-#define GET32_A(p_src)         GET32(p_src)
-#define GET64_A(p_src)         GET64(p_src)
-#define SET16_A(p_dst, src)    SET16(p_dst, src)
-#define SET32_A(p_dst, src)    SET32(p_dst, src)
-#define SET64_A(p_dst, src)    SET64(p_dst, src)
-#endif
-
-/* cache size (in number of sectors) */
-/* (should be an exponential value of 2) */
-#define FAT_CACHE_SIZE         128
-#define FAT_CACHE_HASH_SIZE    64
-#define BUF_CACHE_SIZE         256
-#define BUF_CACHE_HASH_SIZE    64
-
-/* Upcase table macro */
-#define HIGH_INDEX_BIT (8)
-#define HIGH_INDEX_MASK        (0xFF00)
-#define LOW_INDEX_BIT  (16 - HIGH_INDEX_BIT)
-#define UTBL_ROW_COUNT BIT(LOW_INDEX_BIT)
-#define UTBL_COL_COUNT BIT(HIGH_INDEX_BIT)
-
-static inline u16 get_col_index(u16 i)
-{
-       return i >> LOW_INDEX_BIT;
-}
-
-static inline u16 get_row_index(u16 i)
-{
-       return i & ~HIGH_INDEX_MASK;
-}
-
-#define EXFAT_SUPER_MAGIC       (0x2011BAB0L)
-#define EXFAT_ROOT_INO          1
-
-/* FAT types */
-#define FAT12                  0x01    /* FAT12 */
-#define FAT16                  0x0E    /* Win95 FAT16 (LBA) */
-#define FAT32                  0x0C    /* Win95 FAT32 (LBA) */
-#define EXFAT                  0x07    /* exFAT */
-
-/* file name lengths */
-#define MAX_CHARSET_SIZE       3       /* max size of multi-byte character */
-#define MAX_PATH_DEPTH         15      /* max depth of path name */
-#define MAX_NAME_LENGTH                256     /* max len of filename including NULL */
-#define MAX_PATH_LENGTH                260     /* max len of pathname including NULL */
-#define DOS_NAME_LENGTH                11      /* DOS filename length excluding NULL */
-#define DOS_PATH_LENGTH                80      /* DOS pathname length excluding NULL */
-
-/* file attributes */
-#define ATTR_NORMAL            0x0000
-#define ATTR_READONLY          0x0001
-#define ATTR_HIDDEN            0x0002
-#define ATTR_SYSTEM            0x0004
-#define ATTR_VOLUME            0x0008
-#define ATTR_SUBDIR            0x0010
-#define ATTR_ARCHIVE           0x0020
-#define ATTR_SYMLINK           0x0040
-#define ATTR_EXTEND            0x000F
-#define ATTR_RWMASK            0x007E
-
-/* file creation modes */
-#define FM_REGULAR              0x00
-#define FM_SYMLINK              0x40
-
-#define NUM_UPCASE              2918
-
-#define DOS_CUR_DIR_NAME        ".          "
-#define DOS_PAR_DIR_NAME        "..         "
-
-#ifdef __LITTLE_ENDIAN
-#define UNI_CUR_DIR_NAME        ".\0"
-#define UNI_PAR_DIR_NAME        ".\0.\0"
-#else
-#define UNI_CUR_DIR_NAME        "\0."
-#define UNI_PAR_DIR_NAME        "\0.\0."
-#endif
-
-struct date_time_t {
-       u16      Year;
-       u16      Month;
-       u16      Day;
-       u16      Hour;
-       u16      Minute;
-       u16      Second;
-       u16      MilliSecond;
-};
-
-struct part_info_t {
-       u32      Offset;    /* start sector number of the partition */
-       u32      Size;      /* in sectors */
-};
-
-struct dev_info_t {
-       u32      SecSize;    /* sector size in bytes */
-       u32      DevSize;    /* block device size in sectors */
-};
-
-struct vol_info_t {
-       u32      FatType;
-       u32      ClusterSize;
-       u32      NumClusters;
-       u32      FreeClusters;
-       u32      UsedClusters;
-};
-
-/* directory structure */
-struct chain_t {
-       u32      dir;
-       s32       size;
-       u8       flags;
-};
-
-struct file_id_t {
-       struct chain_t     dir;
-       s32       entry;
-       u32      type;
-       u32      attr;
-       u32      start_clu;
-       u64      size;
-       u8       flags;
-       s64       rwoffset;
-       s32       hint_last_off;
-       u32      hint_last_clu;
-};
-
-struct dir_entry_t {
-       char Name[MAX_NAME_LENGTH * MAX_CHARSET_SIZE];
-
-       /* used only for FAT12/16/32, not used for exFAT */
-       char ShortName[DOS_NAME_LENGTH + 2];
-
-       u32 Attr;
-       u64 Size;
-       u32 NumSubdirs;
-       struct date_time_t CreateTimestamp;
-       struct date_time_t ModifyTimestamp;
-       struct date_time_t AccessTimestamp;
-};
-
-struct timestamp_t {
-       u16      sec;        /* 0 ~ 59               */
-       u16      min;        /* 0 ~ 59               */
-       u16      hour;       /* 0 ~ 23               */
-       u16      day;        /* 1 ~ 31               */
-       u16      mon;        /* 1 ~ 12               */
-       u16      year;       /* 0 ~ 127 (since 1980) */
-};
-
-/* MS_DOS FAT partition boot record (512 bytes) */
-struct pbr_sector_t {
-       u8       jmp_boot[3];
-       u8       oem_name[8];
-       u8       bpb[109];
-       u8       boot_code[390];
-       u8       signature[2];
-};
-
-/* MS-DOS FAT12/16 BIOS parameter block (51 bytes) */
-struct bpb16_t {
-       u8       sector_size[2];
-       u8       sectors_per_clu;
-       u8       num_reserved[2];
-       u8       num_fats;
-       u8       num_root_entries[2];
-       u8       num_sectors[2];
-       u8       media_type;
-       u8       num_fat_sectors[2];
-       u8       sectors_in_track[2];
-       u8       num_heads[2];
-       u8       num_hid_sectors[4];
-       u8       num_huge_sectors[4];
-
-       u8       phy_drv_no;
-       u8       reserved;
-       u8       ext_signature;
-       u8       vol_serial[4];
-       u8       vol_label[11];
-       u8       vol_type[8];
-};
-
-/* MS-DOS FAT32 BIOS parameter block (79 bytes) */
-struct bpb32_t {
-       u8       sector_size[2];
-       u8       sectors_per_clu;
-       u8       num_reserved[2];
-       u8       num_fats;
-       u8       num_root_entries[2];
-       u8       num_sectors[2];
-       u8       media_type;
-       u8       num_fat_sectors[2];
-       u8       sectors_in_track[2];
-       u8       num_heads[2];
-       u8       num_hid_sectors[4];
-       u8       num_huge_sectors[4];
-       u8       num_fat32_sectors[4];
-       u8       ext_flags[2];
-       u8       fs_version[2];
-       u8       root_cluster[4];
-       u8       fsinfo_sector[2];
-       u8       backup_sector[2];
-       u8       reserved[12];
-
-       u8       phy_drv_no;
-       u8       ext_reserved;
-       u8       ext_signature;
-       u8       vol_serial[4];
-       u8       vol_label[11];
-       u8       vol_type[8];
-};
-
-/* MS-DOS EXFAT BIOS parameter block (109 bytes) */
-struct bpbex_t {
-       u8       reserved1[53];
-       u8       vol_offset[8];
-       u8       vol_length[8];
-       u8       fat_offset[4];
-       u8       fat_length[4];
-       u8       clu_offset[4];
-       u8       clu_count[4];
-       u8       root_cluster[4];
-       u8       vol_serial[4];
-       u8       fs_version[2];
-       u8       vol_flags[2];
-       u8       sector_size_bits;
-       u8       sectors_per_clu_bits;
-       u8       num_fats;
-       u8       phy_drv_no;
-       u8       perc_in_use;
-       u8       reserved2[7];
-};
-
-/* MS-DOS FAT file system information sector (512 bytes) */
-struct fsi_sector_t {
-       u8       signature1[4];
-       u8       reserved1[480];
-       u8       signature2[4];
-       u8       free_cluster[4];
-       u8       next_cluster[4];
-       u8       reserved2[14];
-       u8       signature3[2];
-};
-
-/* MS-DOS FAT directory entry (32 bytes) */
-struct dentry_t {
-       u8       dummy[32];
-};
-
-struct dos_dentry_t {
-       u8       name[DOS_NAME_LENGTH];
-       u8       attr;
-       u8       lcase;
-       u8       create_time_ms;
-       u8       create_time[2];
-       u8       create_date[2];
-       u8       access_date[2];
-       u8       start_clu_hi[2];
-       u8       modify_time[2];
-       u8       modify_date[2];
-       u8       start_clu_lo[2];
-       u8       size[4];
-};
-
-/* MS-DOS FAT extended directory entry (32 bytes) */
-struct ext_dentry_t {
-       u8       order;
-       u8       unicode_0_4[10];
-       u8       attr;
-       u8       sysid;
-       u8       checksum;
-       u8       unicode_5_10[12];
-       u8       start_clu[2];
-       u8       unicode_11_12[4];
-};
-
-/* MS-DOS EXFAT file directory entry (32 bytes) */
-struct file_dentry_t {
-       u8       type;
-       u8       num_ext;
-       u8       checksum[2];
-       u8       attr[2];
-       u8       reserved1[2];
-       u8       create_time[2];
-       u8       create_date[2];
-       u8       modify_time[2];
-       u8       modify_date[2];
-       u8       access_time[2];
-       u8       access_date[2];
-       u8       create_time_ms;
-       u8       modify_time_ms;
-       u8       access_time_ms;
-       u8       reserved2[9];
-};
-
-/* MS-DOS EXFAT stream extension directory entry (32 bytes) */
-struct strm_dentry_t {
-       u8       type;
-       u8       flags;
-       u8       reserved1;
-       u8       name_len;
-       u8       name_hash[2];
-       u8       reserved2[2];
-       u8       valid_size[8];
-       u8       reserved3[4];
-       u8       start_clu[4];
-       u8       size[8];
-};
-
-/* MS-DOS EXFAT file name directory entry (32 bytes) */
-struct name_dentry_t {
-       u8       type;
-       u8       flags;
-       u8       unicode_0_14[30];
-};
-
-/* MS-DOS EXFAT allocation bitmap directory entry (32 bytes) */
-struct bmap_dentry_t {
-       u8       type;
-       u8       flags;
-       u8       reserved[18];
-       u8       start_clu[4];
-       u8       size[8];
-};
-
-/* MS-DOS EXFAT up-case table directory entry (32 bytes) */
-struct case_dentry_t {
-       u8       type;
-       u8       reserved1[3];
-       u8       checksum[4];
-       u8       reserved2[12];
-       u8       start_clu[4];
-       u8       size[8];
-};
-
-/* MS-DOS EXFAT volume label directory entry (32 bytes) */
-struct volm_dentry_t {
-       u8       type;
-       u8       label_len;
-       u8       unicode_0_10[22];
-       u8       reserved[8];
-};
-
-/* unused entry hint information */
-struct uentry_t {
-       u32      dir;
-       s32       entry;
-       struct chain_t     clu;
-};
-
-/* DOS name structure */
-struct dos_name_t {
-       u8       name[DOS_NAME_LENGTH];
-       u8       name_case;
-};
-
-/* unicode name structure */
-struct uni_name_t {
-       u16      name[MAX_NAME_LENGTH];
-       u16      name_hash;
-       u8       name_len;
-};
-
-struct buf_cache_t {
-       struct buf_cache_t *next;
-       struct buf_cache_t *prev;
-       struct buf_cache_t *hash_next;
-       struct buf_cache_t *hash_prev;
-       s32                drv;
-       sector_t          sec;
-       u32               flag;
-       struct buffer_head   *buf_bh;
-};
-
-struct fs_info_t {
-       u32      drv;                    /* drive ID */
-       u32      vol_type;               /* volume FAT type */
-       u32      vol_id;                 /* volume serial number */
-
-       u64      num_sectors;            /* num of sectors in volume */
-       u32      num_clusters;           /* num of clusters in volume */
-       u32      cluster_size;           /* cluster size in bytes */
-       u32      cluster_size_bits;
-       u32      sectors_per_clu;        /* cluster size in sectors */
-       u32      sectors_per_clu_bits;
-
-       u32      PBR_sector;             /* PBR sector */
-       u32      FAT1_start_sector;      /* FAT1 start sector */
-       u32      FAT2_start_sector;      /* FAT2 start sector */
-       u32      root_start_sector;      /* root dir start sector */
-       u32      data_start_sector;      /* data area start sector */
-       u32      num_FAT_sectors;        /* num of FAT sectors */
-
-       u32      root_dir;               /* root dir cluster */
-       u32      dentries_in_root;       /* num of dentries in root dir */
-       u32      dentries_per_clu;       /* num of dentries per cluster */
-
-       u32      vol_flag;               /* volume dirty flag */
-       struct buffer_head *pbr_bh;         /* PBR sector */
-
-       u32      map_clu;                /* allocation bitmap start cluster */
-       u32      map_sectors;            /* num of allocation bitmap sectors */
-       struct buffer_head **vol_amap;      /* allocation bitmap */
-
-       u16 **vol_utbl;                 /* upcase table */
-
-       u32 clu_srch_ptr;               /* cluster search pointer */
-       u32 used_clusters;              /* number of used clusters */
-       struct uentry_t hint_uentry;    /* unused entry hint information */
-
-       u32 dev_ejected;        /* block device operation error flag */
-
-       struct mutex v_mutex;
-
-       /* FAT cache */
-       struct buf_cache_t FAT_cache_array[FAT_CACHE_SIZE];
-       struct buf_cache_t FAT_cache_lru_list;
-       struct buf_cache_t FAT_cache_hash_list[FAT_CACHE_HASH_SIZE];
-
-       /* buf cache */
-       struct buf_cache_t buf_cache_array[BUF_CACHE_SIZE];
-       struct buf_cache_t buf_cache_lru_list;
-       struct buf_cache_t buf_cache_hash_list[BUF_CACHE_HASH_SIZE];
-};
-
-#define ES_2_ENTRIES           2
-#define ES_3_ENTRIES           3
-#define ES_ALL_ENTRIES         0
-
-struct entry_set_cache_t {
-       /* sector number that contains file_entry */
-       sector_t sector;
-
-       /* byte offset in the sector */
-       s32 offset;
-
-       /*
-        * flag in stream entry.
-        * 01 for cluster chain,
-        * 03 for contig. clusteres.
-        */
-       s32 alloc_flag;
-
-       u32 num_entries;
-
-       /* __buf should be the last member */
-       void *__buf;
-};
-
-#define EXFAT_ERRORS_CONT      1       /* ignore error and continue */
-#define EXFAT_ERRORS_PANIC     2       /* panic on error */
-#define EXFAT_ERRORS_RO                3       /* remount r/o on error */
-
-/* ioctl command */
-#define EXFAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x12, __u32)
-
-struct exfat_mount_options {
-       kuid_t fs_uid;
-       kgid_t fs_gid;
-       unsigned short fs_fmask;
-       unsigned short fs_dmask;
-
-       /* permission for setting the [am]time */
-       unsigned short allow_utime;
-
-       /* codepage for shortname conversions */
-       unsigned short codepage;
-
-       /* charset for filename input/display */
-       char *iocharset;
-
-       unsigned char casesensitive;
-
-       /* on error: continue, panic, remount-ro */
-       unsigned char errors;
-#ifdef CONFIG_STAGING_EXFAT_DISCARD
-       /* flag on if -o dicard specified and device support discard() */
-       unsigned char discard;
-#endif /* CONFIG_STAGING_EXFAT_DISCARD */
-};
-
-#define EXFAT_HASH_BITS                8
-#define EXFAT_HASH_SIZE                BIT(EXFAT_HASH_BITS)
-
-/*
- * EXFAT file system in-core superblock data
- */
-struct bd_info_t {
-       s32 sector_size;        /* in bytes */
-       s32 sector_size_bits;
-       s32 sector_size_mask;
-
-       /* total number of sectors in this block device */
-       s32 num_sectors;
-
-       /* opened or not */
-       bool opened;
-};
-
-struct exfat_sb_info {
-       struct fs_info_t fs_info;
-       struct bd_info_t bd_info;
-
-       struct exfat_mount_options options;
-
-       int s_dirt;
-       struct mutex s_lock;
-       struct nls_table *nls_disk; /* Codepage used on disk */
-       struct nls_table *nls_io;   /* Charset used for input and display */
-
-       struct inode *fat_inode;
-
-       spinlock_t inode_hash_lock;
-       struct hlist_head inode_hashtable[EXFAT_HASH_SIZE];
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-       long debug_flags;
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-};
-
-/*
- * EXFAT file system inode data in memory
- */
-struct exfat_inode_info {
-       struct file_id_t fid;
-       char  *target;
-       /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */
-       loff_t mmu_private;     /* physically allocated size */
-       loff_t i_pos;           /* on-disk position of directory entry or 0 */
-       struct hlist_node i_hash_fat;   /* hash by i_location */
-       struct rw_semaphore truncate_lock;
-       struct inode vfs_inode;
-       struct rw_semaphore i_alloc_sem; /* protect bmap against truncate */
-};
-
-#define EXFAT_SB(sb)           ((struct exfat_sb_info *)((sb)->s_fs_info))
-
-static inline struct exfat_inode_info *EXFAT_I(struct inode *inode)
-{
-       return container_of(inode, struct exfat_inode_info, vfs_inode);
-}
-
-/* NLS management function */
-u16 nls_upper(struct super_block *sb, u16 a);
-int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b);
-void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring,
-                           struct uni_name_t *p_uniname);
-void nls_cstring_to_uniname(struct super_block *sb,
-                           struct uni_name_t *p_uniname, u8 *p_cstring,
-                           bool *p_lossy);
-
-/* buffer cache management */
-void exfat_buf_init(struct super_block *sb);
-void exfat_buf_shutdown(struct super_block *sb);
-int exfat_fat_read(struct super_block *sb, u32 loc, u32 *content);
-s32 exfat_fat_write(struct super_block *sb, u32 loc, u32 content);
-u8 *exfat_fat_getblk(struct super_block *sb, sector_t sec);
-void exfat_fat_modify(struct super_block *sb, sector_t sec);
-void exfat_fat_release_all(struct super_block *sb);
-void exfat_fat_sync(struct super_block *sb);
-u8 *exfat_buf_getblk(struct super_block *sb, sector_t sec);
-void exfat_buf_modify(struct super_block *sb, sector_t sec);
-void exfat_buf_lock(struct super_block *sb, sector_t sec);
-void exfat_buf_unlock(struct super_block *sb, sector_t sec);
-void exfat_buf_release(struct super_block *sb, sector_t sec);
-void exfat_buf_release_all(struct super_block *sb);
-void exfat_buf_sync(struct super_block *sb);
-
-/* fs management functions */
-void fs_set_vol_flags(struct super_block *sb, u32 new_flag);
-void fs_error(struct super_block *sb);
-
-/* cluster management functions */
-s32 count_num_clusters(struct super_block *sb, struct chain_t *dir);
-void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len);
-
-/* allocation bitmap management functions */
-s32 load_alloc_bitmap(struct super_block *sb);
-void free_alloc_bitmap(struct super_block *sb);
-void sync_alloc_bitmap(struct super_block *sb);
-
-/* upcase table management functions */
-s32 load_upcase_table(struct super_block *sb);
-void free_upcase_table(struct super_block *sb);
-
-/* dir entry management functions */
-struct timestamp_t *tm_current(struct timestamp_t *tm);
-
-struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir,
-                                 s32 entry, sector_t *sector);
-struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb,
-                                              struct chain_t *p_dir, s32 entry,
-                                              u32 type,
-                                              struct dentry_t **file_ep);
-void release_entry_set(struct entry_set_cache_t *es);
-s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir,
-                          u32 type);
-void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir,
-                        s32 entry);
-void update_dir_checksum_with_entry_set(struct super_block *sb,
-                                       struct entry_set_cache_t *es);
-bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir);
-
-/* name conversion functions */
-s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir,
-                                struct uni_name_t *p_uniname, s32 *entries,
-                                struct dos_name_t *p_dosname);
-u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type);
-
-/* name resolution functions */
-s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir,
-                struct uni_name_t *p_uniname);
-
-/* file operation functions */
-s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr);
-s32 create_dir(struct inode *inode, struct chain_t *p_dir,
-              struct uni_name_t *p_uniname, struct file_id_t *fid);
-s32 create_file(struct inode *inode, struct chain_t *p_dir,
-               struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid);
-void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry);
-s32 exfat_rename_file(struct inode *inode, struct chain_t *p_dir, s32 old_entry,
-                     struct uni_name_t *p_uniname, struct file_id_t *fid);
-s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry,
-             struct chain_t *p_newdir, struct uni_name_t *p_uniname,
-             struct file_id_t *fid);
-
-/* sector read/write functions */
-int sector_read(struct super_block *sb, sector_t sec,
-               struct buffer_head **bh, bool read);
-int sector_write(struct super_block *sb, sector_t sec,
-                struct buffer_head *bh, bool sync);
-int multi_sector_read(struct super_block *sb, sector_t sec,
-                     struct buffer_head **bh, s32 num_secs, bool read);
-int multi_sector_write(struct super_block *sb, sector_t sec,
-                      struct buffer_head *bh, s32 num_secs, bool sync);
-
-void exfat_bdev_open(struct super_block *sb);
-void exfat_bdev_close(struct super_block *sb);
-int exfat_bdev_read(struct super_block *sb, sector_t secno,
-             struct buffer_head **bh, u32 num_secs, bool read);
-int exfat_bdev_write(struct super_block *sb, sector_t secno,
-              struct buffer_head *bh, u32 num_secs, bool sync);
-int exfat_bdev_sync(struct super_block *sb);
-
-/* cluster operation functions */
-s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc,
-                       struct chain_t *p_chain);
-void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain,
-                       s32 do_relse);
-s32 exfat_count_used_clusters(struct super_block *sb);
-
-/* dir operation functions */
-s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir,
-                        struct uni_name_t *p_uniname, s32 num_entries,
-                        struct dos_name_t *p_dosname, u32 type);
-void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir,
-                           s32 entry, s32 order, s32 num_entries);
-void exfat_get_uni_name_from_ext_entry(struct super_block *sb,
-                                      struct chain_t *p_dir, s32 entry,
-                                      u16 *uniname);
-s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir,
-                           s32 entry, struct dentry_t *p_entry);
-s32 exfat_calc_num_entries(struct uni_name_t *p_uniname);
-
-/* dir entry getter/setter */
-u32 exfat_get_entry_type(struct dentry_t *p_entry);
-u32 exfat_get_entry_attr(struct dentry_t *p_entry);
-void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr);
-u8 exfat_get_entry_flag(struct dentry_t *p_entry);
-void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags);
-u32 exfat_get_entry_clu0(struct dentry_t *p_entry);
-void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu);
-u64 exfat_get_entry_size(struct dentry_t *p_entry);
-void exfat_set_entry_size(struct dentry_t *p_entry, u64 size);
-void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
-                         u8 mode);
-void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
-                         u8 mode);
-
-extern const u8 uni_upcase[];
-#endif /* _EXFAT_H */
diff --git a/drivers/staging/exfat/exfat_blkdev.c b/drivers/staging/exfat/exfat_blkdev.c
deleted file mode 100644 (file)
index 0a3dc35..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
- */
-
-#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
-#include <linux/fs.h>
-#include "exfat.h"
-
-void exfat_bdev_open(struct super_block *sb)
-{
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       if (p_bd->opened)
-               return;
-
-       p_bd->sector_size      = bdev_logical_block_size(sb->s_bdev);
-       p_bd->sector_size_bits = ilog2(p_bd->sector_size);
-       p_bd->sector_size_mask = p_bd->sector_size - 1;
-       p_bd->num_sectors      = i_size_read(sb->s_bdev->bd_inode) >>
-                                p_bd->sector_size_bits;
-       p_bd->opened = true;
-}
-
-void exfat_bdev_close(struct super_block *sb)
-{
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       p_bd->opened = false;
-}
-
-int exfat_bdev_read(struct super_block *sb, sector_t secno, struct buffer_head **bh,
-                   u32 num_secs, bool read)
-{
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       long flags = sbi->debug_flags;
-
-       if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
-               return -EIO;
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-
-       if (!p_bd->opened)
-               return -ENODEV;
-
-       if (*bh)
-               __brelse(*bh);
-
-       if (read)
-               *bh = __bread(sb->s_bdev, secno,
-                             num_secs << p_bd->sector_size_bits);
-       else
-               *bh = __getblk(sb->s_bdev, secno,
-                              num_secs << p_bd->sector_size_bits);
-
-       if (*bh)
-               return 0;
-
-       WARN(!p_fs->dev_ejected,
-            "[EXFAT] No bh, device seems wrong or to be ejected.\n");
-
-       return -EIO;
-}
-
-int exfat_bdev_write(struct super_block *sb, sector_t secno, struct buffer_head *bh,
-                    u32 num_secs, bool sync)
-{
-       s32 count;
-       struct buffer_head *bh2;
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       long flags = sbi->debug_flags;
-
-       if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
-               return -EIO;
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-
-       if (!p_bd->opened)
-               return -ENODEV;
-
-       if (secno == bh->b_blocknr) {
-               lock_buffer(bh);
-               set_buffer_uptodate(bh);
-               mark_buffer_dirty(bh);
-               unlock_buffer(bh);
-               if (sync && (sync_dirty_buffer(bh) != 0))
-                       return -EIO;
-       } else {
-               count = num_secs << p_bd->sector_size_bits;
-
-               bh2 = __getblk(sb->s_bdev, secno, count);
-               if (!bh2)
-                       goto no_bh;
-
-               lock_buffer(bh2);
-               memcpy(bh2->b_data, bh->b_data, count);
-               set_buffer_uptodate(bh2);
-               mark_buffer_dirty(bh2);
-               unlock_buffer(bh2);
-               if (sync && (sync_dirty_buffer(bh2) != 0)) {
-                       __brelse(bh2);
-                       goto no_bh;
-               }
-               __brelse(bh2);
-       }
-
-       return 0;
-
-no_bh:
-       WARN(!p_fs->dev_ejected,
-            "[EXFAT] No bh, device seems wrong or to be ejected.\n");
-
-       return -EIO;
-}
-
-int exfat_bdev_sync(struct super_block *sb)
-{
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       long flags = sbi->debug_flags;
-
-       if (flags & EXFAT_DEBUGFLAGS_ERROR_RW)
-               return -EIO;
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-
-       if (!p_bd->opened)
-               return -ENODEV;
-
-       return sync_blockdev(sb->s_bdev);
-}
diff --git a/drivers/staging/exfat/exfat_cache.c b/drivers/staging/exfat/exfat_cache.c
deleted file mode 100644 (file)
index 3fd5604..0000000
+++ /dev/null
@@ -1,555 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
- */
-
-#include <linux/buffer_head.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include "exfat.h"
-
-#define LOCKBIT                0x01
-#define DIRTYBIT       0x02
-
-/* Local variables */
-static DEFINE_MUTEX(f_mutex);
-static DEFINE_MUTEX(b_mutex);
-
-static struct buf_cache_t *FAT_cache_find(struct super_block *sb, sector_t sec)
-{
-       s32 off;
-       struct buf_cache_t *bp, *hp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       off = (sec +
-              (sec >> p_fs->sectors_per_clu_bits)) & (FAT_CACHE_HASH_SIZE - 1);
-
-       hp = &p_fs->FAT_cache_hash_list[off];
-       for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) {
-               if ((bp->drv == p_fs->drv) && (bp->sec == sec)) {
-                       WARN(!bp->buf_bh,
-                            "[EXFAT] FAT_cache has no bh. It will make system panic.\n");
-
-                       touch_buffer(bp->buf_bh);
-                       return bp;
-               }
-       }
-       return NULL;
-}
-
-static void push_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list)
-{
-       bp->next = list->next;
-       bp->prev = list;
-       list->next->prev = bp;
-       list->next = bp;
-}
-
-static void push_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list)
-{
-       bp->prev = list->prev;
-       bp->next = list;
-       list->prev->next = bp;
-       list->prev = bp;
-}
-
-static void move_to_mru(struct buf_cache_t *bp, struct buf_cache_t *list)
-{
-       bp->prev->next = bp->next;
-       bp->next->prev = bp->prev;
-       push_to_mru(bp, list);
-}
-
-static void move_to_lru(struct buf_cache_t *bp, struct buf_cache_t *list)
-{
-       bp->prev->next = bp->next;
-       bp->next->prev = bp->prev;
-       push_to_lru(bp, list);
-}
-
-static struct buf_cache_t *FAT_cache_get(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       bp = p_fs->FAT_cache_lru_list.prev;
-
-       move_to_mru(bp, &p_fs->FAT_cache_lru_list);
-       return bp;
-}
-
-static void FAT_cache_insert_hash(struct super_block *sb,
-                                 struct buf_cache_t *bp)
-{
-       s32 off;
-       struct buf_cache_t *hp;
-       struct fs_info_t *p_fs;
-
-       p_fs = &(EXFAT_SB(sb)->fs_info);
-       off = (bp->sec +
-              (bp->sec >> p_fs->sectors_per_clu_bits)) &
-               (FAT_CACHE_HASH_SIZE - 1);
-
-       hp = &p_fs->FAT_cache_hash_list[off];
-       bp->hash_next = hp->hash_next;
-       bp->hash_prev = hp;
-       hp->hash_next->hash_prev = bp;
-       hp->hash_next = bp;
-}
-
-static void FAT_cache_remove_hash(struct buf_cache_t *bp)
-{
-       (bp->hash_prev)->hash_next = bp->hash_next;
-       (bp->hash_next)->hash_prev = bp->hash_prev;
-}
-
-static void buf_cache_insert_hash(struct super_block *sb,
-                                 struct buf_cache_t *bp)
-{
-       s32 off;
-       struct buf_cache_t *hp;
-       struct fs_info_t *p_fs;
-
-       p_fs = &(EXFAT_SB(sb)->fs_info);
-       off = (bp->sec +
-              (bp->sec >> p_fs->sectors_per_clu_bits)) &
-               (BUF_CACHE_HASH_SIZE - 1);
-
-       hp = &p_fs->buf_cache_hash_list[off];
-       bp->hash_next = hp->hash_next;
-       bp->hash_prev = hp;
-       hp->hash_next->hash_prev = bp;
-       hp->hash_next = bp;
-}
-
-static void buf_cache_remove_hash(struct buf_cache_t *bp)
-{
-       (bp->hash_prev)->hash_next = bp->hash_next;
-       (bp->hash_next)->hash_prev = bp->hash_prev;
-}
-
-void exfat_buf_init(struct super_block *sb)
-{
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       int i;
-
-       /* LRU list */
-       p_fs->FAT_cache_lru_list.next = &p_fs->FAT_cache_lru_list;
-       p_fs->FAT_cache_lru_list.prev = &p_fs->FAT_cache_lru_list;
-
-       for (i = 0; i < FAT_CACHE_SIZE; i++) {
-               p_fs->FAT_cache_array[i].drv = -1;
-               p_fs->FAT_cache_array[i].sec = ~0;
-               p_fs->FAT_cache_array[i].flag = 0;
-               p_fs->FAT_cache_array[i].buf_bh = NULL;
-               p_fs->FAT_cache_array[i].prev = NULL;
-               p_fs->FAT_cache_array[i].next = NULL;
-               push_to_mru(&p_fs->FAT_cache_array[i],
-                           &p_fs->FAT_cache_lru_list);
-       }
-
-       p_fs->buf_cache_lru_list.next = &p_fs->buf_cache_lru_list;
-       p_fs->buf_cache_lru_list.prev = &p_fs->buf_cache_lru_list;
-
-       for (i = 0; i < BUF_CACHE_SIZE; i++) {
-               p_fs->buf_cache_array[i].drv = -1;
-               p_fs->buf_cache_array[i].sec = ~0;
-               p_fs->buf_cache_array[i].flag = 0;
-               p_fs->buf_cache_array[i].buf_bh = NULL;
-               p_fs->buf_cache_array[i].prev = NULL;
-               p_fs->buf_cache_array[i].next = NULL;
-               push_to_mru(&p_fs->buf_cache_array[i],
-                           &p_fs->buf_cache_lru_list);
-       }
-
-       /* HASH list */
-       for (i = 0; i < FAT_CACHE_HASH_SIZE; i++) {
-               p_fs->FAT_cache_hash_list[i].drv = -1;
-               p_fs->FAT_cache_hash_list[i].sec = ~0;
-               p_fs->FAT_cache_hash_list[i].hash_next =
-                       &p_fs->FAT_cache_hash_list[i];
-               p_fs->FAT_cache_hash_list[i].hash_prev =
-                       &p_fs->FAT_cache_hash_list[i];
-       }
-
-       for (i = 0; i < FAT_CACHE_SIZE; i++)
-               FAT_cache_insert_hash(sb, &p_fs->FAT_cache_array[i]);
-
-       for (i = 0; i < BUF_CACHE_HASH_SIZE; i++) {
-               p_fs->buf_cache_hash_list[i].drv = -1;
-               p_fs->buf_cache_hash_list[i].sec = ~0;
-               p_fs->buf_cache_hash_list[i].hash_next =
-                       &p_fs->buf_cache_hash_list[i];
-               p_fs->buf_cache_hash_list[i].hash_prev =
-                       &p_fs->buf_cache_hash_list[i];
-       }
-
-       for (i = 0; i < BUF_CACHE_SIZE; i++)
-               buf_cache_insert_hash(sb, &p_fs->buf_cache_array[i]);
-}
-
-void exfat_buf_shutdown(struct super_block *sb)
-{
-}
-
-static int __exfat_fat_read(struct super_block *sb, u32 loc, u32 *content)
-{
-       s32 off;
-       u32 _content;
-       sector_t sec;
-       u8 *fat_sector, *fat_entry;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       sec = p_fs->FAT1_start_sector +
-               (loc >> (p_bd->sector_size_bits - 2));
-       off = (loc << 2) & p_bd->sector_size_mask;
-
-       fat_sector = exfat_fat_getblk(sb, sec);
-       if (!fat_sector)
-               return -1;
-
-       fat_entry = &fat_sector[off];
-       _content = GET32_A(fat_entry);
-
-       if (_content >= CLUSTER_32(0xFFFFFFF8)) {
-               *content = CLUSTER_32(~0);
-               return 0;
-       }
-       *content = CLUSTER_32(_content);
-       return 0;
-}
-
-/* in : sb, loc
- * out: content
- * returns 0 on success
- *            -1 on error
- */
-int exfat_fat_read(struct super_block *sb, u32 loc, u32 *content)
-{
-       s32 ret;
-
-       mutex_lock(&f_mutex);
-       ret = __exfat_fat_read(sb, loc, content);
-       mutex_unlock(&f_mutex);
-
-       return ret;
-}
-
-static s32 __exfat_fat_write(struct super_block *sb, u32 loc, u32 content)
-{
-       s32 off;
-       sector_t sec;
-       u8 *fat_sector, *fat_entry;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       sec = p_fs->FAT1_start_sector + (loc >>
-                                        (p_bd->sector_size_bits - 2));
-       off = (loc << 2) & p_bd->sector_size_mask;
-
-       fat_sector = exfat_fat_getblk(sb, sec);
-       if (!fat_sector)
-               return -1;
-
-       fat_entry = &fat_sector[off];
-
-       SET32_A(fat_entry, content);
-
-       exfat_fat_modify(sb, sec);
-       return 0;
-}
-
-int exfat_fat_write(struct super_block *sb, u32 loc, u32 content)
-{
-       s32 ret;
-
-       mutex_lock(&f_mutex);
-       ret = __exfat_fat_write(sb, loc, content);
-       mutex_unlock(&f_mutex);
-
-       return ret;
-}
-
-u8 *exfat_fat_getblk(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       bp = FAT_cache_find(sb, sec);
-       if (bp) {
-               move_to_mru(bp, &p_fs->FAT_cache_lru_list);
-               return bp->buf_bh->b_data;
-       }
-
-       bp = FAT_cache_get(sb, sec);
-
-       FAT_cache_remove_hash(bp);
-
-       bp->drv = p_fs->drv;
-       bp->sec = sec;
-       bp->flag = 0;
-
-       FAT_cache_insert_hash(sb, bp);
-
-       if (sector_read(sb, sec, &bp->buf_bh, 1) != 0) {
-               FAT_cache_remove_hash(bp);
-               bp->drv = -1;
-               bp->sec = ~0;
-               bp->flag = 0;
-               bp->buf_bh = NULL;
-
-               move_to_lru(bp, &p_fs->FAT_cache_lru_list);
-               return NULL;
-       }
-
-       return bp->buf_bh->b_data;
-}
-
-void exfat_fat_modify(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-
-       bp = FAT_cache_find(sb, sec);
-       if (bp)
-               sector_write(sb, sec, bp->buf_bh, 0);
-}
-
-void exfat_fat_release_all(struct super_block *sb)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       mutex_lock(&f_mutex);
-
-       bp = p_fs->FAT_cache_lru_list.next;
-       while (bp != &p_fs->FAT_cache_lru_list) {
-               if (bp->drv == p_fs->drv) {
-                       bp->drv = -1;
-                       bp->sec = ~0;
-                       bp->flag = 0;
-
-                       if (bp->buf_bh) {
-                               __brelse(bp->buf_bh);
-                               bp->buf_bh = NULL;
-                       }
-               }
-               bp = bp->next;
-       }
-
-       mutex_unlock(&f_mutex);
-}
-
-void exfat_fat_sync(struct super_block *sb)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       mutex_lock(&f_mutex);
-
-       bp = p_fs->FAT_cache_lru_list.next;
-       while (bp != &p_fs->FAT_cache_lru_list) {
-               if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) {
-                       sync_dirty_buffer(bp->buf_bh);
-                       bp->flag &= ~(DIRTYBIT);
-               }
-               bp = bp->next;
-       }
-
-       mutex_unlock(&f_mutex);
-}
-
-static struct buf_cache_t *buf_cache_find(struct super_block *sb, sector_t sec)
-{
-       s32 off;
-       struct buf_cache_t *bp, *hp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       off = (sec + (sec >> p_fs->sectors_per_clu_bits)) &
-               (BUF_CACHE_HASH_SIZE - 1);
-
-       hp = &p_fs->buf_cache_hash_list[off];
-       for (bp = hp->hash_next; bp != hp; bp = bp->hash_next) {
-               if ((bp->drv == p_fs->drv) && (bp->sec == sec)) {
-                       touch_buffer(bp->buf_bh);
-                       return bp;
-               }
-       }
-       return NULL;
-}
-
-static struct buf_cache_t *buf_cache_get(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       bp = p_fs->buf_cache_lru_list.prev;
-       while (bp->flag & LOCKBIT)
-               bp = bp->prev;
-
-       move_to_mru(bp, &p_fs->buf_cache_lru_list);
-       return bp;
-}
-
-static u8 *__exfat_buf_getblk(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       bp = buf_cache_find(sb, sec);
-       if (bp) {
-               move_to_mru(bp, &p_fs->buf_cache_lru_list);
-               return bp->buf_bh->b_data;
-       }
-
-       bp = buf_cache_get(sb, sec);
-
-       buf_cache_remove_hash(bp);
-
-       bp->drv = p_fs->drv;
-       bp->sec = sec;
-       bp->flag = 0;
-
-       buf_cache_insert_hash(sb, bp);
-
-       if (sector_read(sb, sec, &bp->buf_bh, 1) != 0) {
-               buf_cache_remove_hash(bp);
-               bp->drv = -1;
-               bp->sec = ~0;
-               bp->flag = 0;
-               bp->buf_bh = NULL;
-
-               move_to_lru(bp, &p_fs->buf_cache_lru_list);
-               return NULL;
-       }
-
-       return bp->buf_bh->b_data;
-}
-
-u8 *exfat_buf_getblk(struct super_block *sb, sector_t sec)
-{
-       u8 *buf;
-
-       mutex_lock(&b_mutex);
-       buf = __exfat_buf_getblk(sb, sec);
-       mutex_unlock(&b_mutex);
-
-       return buf;
-}
-
-void exfat_buf_modify(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-
-       mutex_lock(&b_mutex);
-
-       bp = buf_cache_find(sb, sec);
-       if (likely(bp))
-               sector_write(sb, sec, bp->buf_bh, 0);
-
-       WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n",
-            (unsigned long long)sec);
-
-       mutex_unlock(&b_mutex);
-}
-
-void exfat_buf_lock(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-
-       mutex_lock(&b_mutex);
-
-       bp = buf_cache_find(sb, sec);
-       if (likely(bp))
-               bp->flag |= LOCKBIT;
-
-       WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n",
-            (unsigned long long)sec);
-
-       mutex_unlock(&b_mutex);
-}
-
-void exfat_buf_unlock(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-
-       mutex_lock(&b_mutex);
-
-       bp = buf_cache_find(sb, sec);
-       if (likely(bp))
-               bp->flag &= ~(LOCKBIT);
-
-       WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n",
-            (unsigned long long)sec);
-
-       mutex_unlock(&b_mutex);
-}
-
-void exfat_buf_release(struct super_block *sb, sector_t sec)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       mutex_lock(&b_mutex);
-
-       bp = buf_cache_find(sb, sec);
-       if (likely(bp)) {
-               bp->drv = -1;
-               bp->sec = ~0;
-               bp->flag = 0;
-
-               if (bp->buf_bh) {
-                       __brelse(bp->buf_bh);
-                       bp->buf_bh = NULL;
-               }
-
-               move_to_lru(bp, &p_fs->buf_cache_lru_list);
-       }
-
-       mutex_unlock(&b_mutex);
-}
-
-void exfat_buf_release_all(struct super_block *sb)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       mutex_lock(&b_mutex);
-
-       bp = p_fs->buf_cache_lru_list.next;
-       while (bp != &p_fs->buf_cache_lru_list) {
-               if (bp->drv == p_fs->drv) {
-                       bp->drv = -1;
-                       bp->sec = ~0;
-                       bp->flag = 0;
-
-                       if (bp->buf_bh) {
-                               __brelse(bp->buf_bh);
-                               bp->buf_bh = NULL;
-                       }
-               }
-               bp = bp->next;
-       }
-
-       mutex_unlock(&b_mutex);
-}
-
-void exfat_buf_sync(struct super_block *sb)
-{
-       struct buf_cache_t *bp;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       mutex_lock(&b_mutex);
-
-       bp = p_fs->buf_cache_lru_list.next;
-       while (bp != &p_fs->buf_cache_lru_list) {
-               if ((bp->drv == p_fs->drv) && (bp->flag & DIRTYBIT)) {
-                       sync_dirty_buffer(bp->buf_bh);
-                       bp->flag &= ~(DIRTYBIT);
-               }
-               bp = bp->next;
-       }
-
-       mutex_unlock(&b_mutex);
-}
diff --git a/drivers/staging/exfat/exfat_core.c b/drivers/staging/exfat/exfat_core.c
deleted file mode 100644 (file)
index 07b460d..0000000
+++ /dev/null
@@ -1,2582 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
- */
-
-#include <linux/types.h>
-#include <linux/buffer_head.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include <linux/blkdev.h>
-#include <linux/slab.h>
-#include "exfat.h"
-
-static void __set_sb_dirty(struct super_block *sb)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-
-       sbi->s_dirt = 1;
-}
-
-static u8 name_buf[MAX_PATH_LENGTH * MAX_CHARSET_SIZE];
-
-static u8 free_bit[] = {
-       0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /*   0 ~  19 */
-       0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, /*  20 ~  39 */
-       0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /*  40 ~  59 */
-       0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /*  60 ~  79 */
-       0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, /*  80 ~  99 */
-       0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, /* 100 ~ 119 */
-       0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 120 ~ 139 */
-       0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 140 ~ 159 */
-       0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, /* 160 ~ 179 */
-       0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, /* 180 ~ 199 */
-       0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, /* 200 ~ 219 */
-       0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 220 ~ 239 */
-       0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0                 /* 240 ~ 254 */
-};
-
-static u8 used_bit[] = {
-       0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, /*   0 ~  19 */
-       2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, /*  20 ~  39 */
-       2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, /*  40 ~  59 */
-       4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /*  60 ~  79 */
-       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, /*  80 ~  99 */
-       3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, /* 100 ~ 119 */
-       4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, /* 120 ~ 139 */
-       3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 140 ~ 159 */
-       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, /* 160 ~ 179 */
-       4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, /* 180 ~ 199 */
-       3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, /* 200 ~ 219 */
-       5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 220 ~ 239 */
-       4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8              /* 240 ~ 255 */
-};
-
-#define BITMAP_LOC(v)           ((v) >> 3)
-#define BITMAP_SHIFT(v)         ((v) & 0x07)
-
-static inline s32 exfat_bitmap_test(u8 *bitmap, int i)
-{
-       u8 data;
-
-       data = bitmap[BITMAP_LOC(i)];
-       if ((data >> BITMAP_SHIFT(i)) & 0x01)
-               return 1;
-       return 0;
-}
-
-static inline void exfat_bitmap_set(u8 *bitmap, int i)
-{
-       bitmap[BITMAP_LOC(i)] |= (0x01 << BITMAP_SHIFT(i));
-}
-
-static inline void exfat_bitmap_clear(u8 *bitmap, int i)
-{
-       bitmap[BITMAP_LOC(i)] &= ~(0x01 << BITMAP_SHIFT(i));
-}
-
-/*
- *  File System Management Functions
- */
-
-void fs_set_vol_flags(struct super_block *sb, u32 new_flag)
-{
-       struct pbr_sector_t *p_pbr;
-       struct bpbex_t *p_bpb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (p_fs->vol_flag == new_flag)
-               return;
-
-       p_fs->vol_flag = new_flag;
-
-       if (!p_fs->pbr_bh) {
-               if (sector_read(sb, p_fs->PBR_sector,
-                               &p_fs->pbr_bh, 1) != 0)
-                       return;
-       }
-
-       p_pbr = (struct pbr_sector_t *)p_fs->pbr_bh->b_data;
-       p_bpb = (struct bpbex_t *)p_pbr->bpb;
-       SET16(p_bpb->vol_flags, (u16)new_flag);
-
-       /* XXX duyoung
-        * what can we do here? (cuz fs_set_vol_flags() is void)
-        */
-       if ((new_flag == VOL_DIRTY) && (!buffer_dirty(p_fs->pbr_bh)))
-               sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 1);
-       else
-               sector_write(sb, p_fs->PBR_sector, p_fs->pbr_bh, 0);
-}
-
-void fs_error(struct super_block *sb)
-{
-       struct exfat_mount_options *opts = &EXFAT_SB(sb)->options;
-
-       if (opts->errors == EXFAT_ERRORS_PANIC) {
-               panic("[EXFAT] Filesystem panic from previous error\n");
-       } else if ((opts->errors == EXFAT_ERRORS_RO) && !sb_rdonly(sb)) {
-               sb->s_flags |= SB_RDONLY;
-               pr_err("[EXFAT] Filesystem has been set read-only\n");
-       }
-}
-
-/*
- *  Cluster Management Functions
- */
-
-static s32 clear_cluster(struct super_block *sb, u32 clu)
-{
-       sector_t s, n;
-       s32 ret = 0;
-       struct buffer_head *tmp_bh = NULL;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       if (clu == CLUSTER_32(0)) { /* FAT16 root_dir */
-               s = p_fs->root_start_sector;
-               n = p_fs->data_start_sector;
-       } else {
-               s = START_SECTOR(clu);
-               n = s + p_fs->sectors_per_clu;
-       }
-
-       for (; s < n; s++) {
-               ret = sector_read(sb, s, &tmp_bh, 0);
-               if (ret != 0)
-                       return ret;
-
-               memset((char *)tmp_bh->b_data, 0x0, p_bd->sector_size);
-               ret = sector_write(sb, s, tmp_bh, 0);
-               if (ret != 0)
-                       break;
-       }
-
-       brelse(tmp_bh);
-       return ret;
-}
-
-static s32 set_alloc_bitmap(struct super_block *sb, u32 clu)
-{
-       int i, b;
-       sector_t sector;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       i = clu >> (p_bd->sector_size_bits + 3);
-       b = clu & ((p_bd->sector_size << 3) - 1);
-
-       sector = START_SECTOR(p_fs->map_clu) + i;
-
-       exfat_bitmap_set((u8 *)p_fs->vol_amap[i]->b_data, b);
-
-       return sector_write(sb, sector, p_fs->vol_amap[i], 0);
-}
-
-static s32 clr_alloc_bitmap(struct super_block *sb, u32 clu)
-{
-       int i, b;
-       sector_t sector;
-#ifdef CONFIG_STAGING_EXFAT_DISCARD
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct exfat_mount_options *opts = &sbi->options;
-       int ret;
-#endif /* CONFIG_STAGING_EXFAT_DISCARD */
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       i = clu >> (p_bd->sector_size_bits + 3);
-       b = clu & ((p_bd->sector_size << 3) - 1);
-
-       sector = START_SECTOR(p_fs->map_clu) + i;
-
-       exfat_bitmap_clear((u8 *)p_fs->vol_amap[i]->b_data, b);
-
-#ifdef CONFIG_STAGING_EXFAT_DISCARD
-       if (opts->discard) {
-               ret = sb_issue_discard(sb, START_SECTOR(clu),
-                                      (1 << p_fs->sectors_per_clu_bits),
-                                      GFP_NOFS, 0);
-               if (ret == -EOPNOTSUPP) {
-                       pr_warn("discard not supported by device, disabling");
-                       opts->discard = 0;
-               } else {
-                       return ret;
-               }
-       }
-#endif /* CONFIG_STAGING_EXFAT_DISCARD */
-
-       return sector_write(sb, sector, p_fs->vol_amap[i], 0);
-}
-
-static u32 test_alloc_bitmap(struct super_block *sb, u32 clu)
-{
-       int i, map_i, map_b;
-       u32 clu_base, clu_free;
-       u8 k, clu_mask;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       clu_base = (clu & ~(0x7)) + 2;
-       clu_mask = (1 << (clu - clu_base + 2)) - 1;
-
-       map_i = clu >> (p_bd->sector_size_bits + 3);
-       map_b = (clu >> 3) & p_bd->sector_size_mask;
-
-       for (i = 2; i < p_fs->num_clusters; i += 8) {
-               k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b);
-               if (clu_mask > 0) {
-                       k |= clu_mask;
-                       clu_mask = 0;
-               }
-               if (k < 0xFF) {
-                       clu_free = clu_base + free_bit[k];
-                       if (clu_free < p_fs->num_clusters)
-                               return clu_free;
-               }
-               clu_base += 8;
-
-               if (((++map_b) >= p_bd->sector_size) ||
-                   (clu_base >= p_fs->num_clusters)) {
-                       if ((++map_i) >= p_fs->map_sectors) {
-                               clu_base = 2;
-                               map_i = 0;
-                       }
-                       map_b = 0;
-               }
-       }
-
-       return CLUSTER_32(~0);
-}
-
-s32 exfat_alloc_cluster(struct super_block *sb, s32 num_alloc,
-                       struct chain_t *p_chain)
-{
-       s32 num_clusters = 0;
-       u32 hint_clu, new_clu, last_clu = CLUSTER_32(~0);
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       hint_clu = p_chain->dir;
-       if (hint_clu == CLUSTER_32(~0)) {
-               hint_clu = test_alloc_bitmap(sb, p_fs->clu_srch_ptr - 2);
-               if (hint_clu == CLUSTER_32(~0))
-                       return 0;
-       } else if (hint_clu >= p_fs->num_clusters) {
-               hint_clu = 2;
-               p_chain->flags = 0x01;
-       }
-
-       __set_sb_dirty(sb);
-
-       p_chain->dir = CLUSTER_32(~0);
-
-       while ((new_clu = test_alloc_bitmap(sb, hint_clu - 2)) != CLUSTER_32(~0)) {
-               if (new_clu != hint_clu) {
-                       if (p_chain->flags == 0x03) {
-                               exfat_chain_cont_cluster(sb, p_chain->dir,
-                                                        num_clusters);
-                               p_chain->flags = 0x01;
-                       }
-               }
-
-               if (set_alloc_bitmap(sb, new_clu - 2) != 0)
-                       return -EIO;
-
-               num_clusters++;
-
-               if (p_chain->flags == 0x01) {
-                       if (exfat_fat_write(sb, new_clu, CLUSTER_32(~0)) < 0)
-                               return -EIO;
-               }
-
-               if (p_chain->dir == CLUSTER_32(~0)) {
-                       p_chain->dir = new_clu;
-               } else {
-                       if (p_chain->flags == 0x01) {
-                               if (exfat_fat_write(sb, last_clu, new_clu) < 0)
-                                       return -EIO;
-                       }
-               }
-               last_clu = new_clu;
-
-               if ((--num_alloc) == 0) {
-                       p_fs->clu_srch_ptr = hint_clu;
-                       if (p_fs->used_clusters != UINT_MAX)
-                               p_fs->used_clusters += num_clusters;
-
-                       p_chain->size += num_clusters;
-                       return num_clusters;
-               }
-
-               hint_clu = new_clu + 1;
-               if (hint_clu >= p_fs->num_clusters) {
-                       hint_clu = 2;
-
-                       if (p_chain->flags == 0x03) {
-                               exfat_chain_cont_cluster(sb, p_chain->dir,
-                                                        num_clusters);
-                               p_chain->flags = 0x01;
-                       }
-               }
-       }
-
-       p_fs->clu_srch_ptr = hint_clu;
-       if (p_fs->used_clusters != UINT_MAX)
-               p_fs->used_clusters += num_clusters;
-
-       p_chain->size += num_clusters;
-       return num_clusters;
-}
-
-void exfat_free_cluster(struct super_block *sb, struct chain_t *p_chain,
-                       s32 do_relse)
-{
-       s32 num_clusters = 0;
-       u32 clu;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       int i;
-       sector_t sector;
-
-       if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0)))
-               return;
-
-       if (p_chain->size <= 0) {
-               pr_err("[EXFAT] free_cluster : skip free-req clu:%u, because of zero-size truncation\n",
-                      p_chain->dir);
-               return;
-       }
-
-       __set_sb_dirty(sb);
-       clu = p_chain->dir;
-
-       if (p_chain->flags == 0x03) {
-               do {
-                       if (do_relse) {
-                               sector = START_SECTOR(clu);
-                               for (i = 0; i < p_fs->sectors_per_clu; i++)
-                                       exfat_buf_release(sb, sector + i);
-                       }
-
-                       if (clr_alloc_bitmap(sb, clu - 2) != 0)
-                               break;
-                       clu++;
-
-                       num_clusters++;
-               } while (num_clusters < p_chain->size);
-       } else {
-               do {
-                       if (p_fs->dev_ejected)
-                               break;
-
-                       if (do_relse) {
-                               sector = START_SECTOR(clu);
-                               for (i = 0; i < p_fs->sectors_per_clu; i++)
-                                       exfat_buf_release(sb, sector + i);
-                       }
-
-                       if (clr_alloc_bitmap(sb, clu - 2) != 0)
-                               break;
-
-                       if (exfat_fat_read(sb, clu, &clu) == -1)
-                               break;
-                       num_clusters++;
-               } while ((clu != CLUSTER_32(0)) && (clu != CLUSTER_32(~0)));
-       }
-
-       if (p_fs->used_clusters != UINT_MAX)
-               p_fs->used_clusters -= num_clusters;
-}
-
-static u32 find_last_cluster(struct super_block *sb, struct chain_t *p_chain)
-{
-       u32 clu, next;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       clu = p_chain->dir;
-
-       if (p_chain->flags == 0x03) {
-               clu += p_chain->size - 1;
-       } else {
-               while ((exfat_fat_read(sb, clu, &next) == 0) &&
-                      (next != CLUSTER_32(~0))) {
-                       if (p_fs->dev_ejected)
-                               break;
-                       clu = next;
-               }
-       }
-
-       return clu;
-}
-
-s32 count_num_clusters(struct super_block *sb, struct chain_t *p_chain)
-{
-       int i, count = 0;
-       u32 clu;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if ((p_chain->dir == CLUSTER_32(0)) || (p_chain->dir == CLUSTER_32(~0)))
-               return 0;
-
-       clu = p_chain->dir;
-
-       if (p_chain->flags == 0x03) {
-               count = p_chain->size;
-       } else {
-               for (i = 2; i < p_fs->num_clusters; i++) {
-                       count++;
-                       if (exfat_fat_read(sb, clu, &clu) != 0)
-                               return 0;
-                       if (clu == CLUSTER_32(~0))
-                               break;
-               }
-       }
-
-       return count;
-}
-
-s32 exfat_count_used_clusters(struct super_block *sb)
-{
-       int i, map_i, map_b, count = 0;
-       u8 k;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       map_i = 0;
-       map_b = 0;
-
-       for (i = 2; i < p_fs->num_clusters; i += 8) {
-               k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b);
-               count += used_bit[k];
-
-               if ((++map_b) >= p_bd->sector_size) {
-                       map_i++;
-                       map_b = 0;
-               }
-       }
-
-       return count;
-}
-
-void exfat_chain_cont_cluster(struct super_block *sb, u32 chain, s32 len)
-{
-       if (len == 0)
-               return;
-
-       while (len > 1) {
-               if (exfat_fat_write(sb, chain, chain + 1) < 0)
-                       break;
-               chain++;
-               len--;
-       }
-       exfat_fat_write(sb, chain, CLUSTER_32(~0));
-}
-
-/*
- *  Allocation Bitmap Management Functions
- */
-
-s32 load_alloc_bitmap(struct super_block *sb)
-{
-       int i, j, ret;
-       u32 map_size;
-       u32 type;
-       sector_t sector;
-       struct chain_t clu;
-       struct bmap_dentry_t *ep;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       clu.dir = p_fs->root_dir;
-       clu.flags = 0x01;
-
-       while (clu.dir != CLUSTER_32(~0)) {
-               if (p_fs->dev_ejected)
-                       break;
-
-               for (i = 0; i < p_fs->dentries_per_clu; i++) {
-                       ep = (struct bmap_dentry_t *)get_entry_in_dir(sb, &clu,
-                                                                     i, NULL);
-                       if (!ep)
-                               return -ENOENT;
-
-                       type = exfat_get_entry_type((struct dentry_t *)ep);
-
-                       if (type == TYPE_UNUSED)
-                               break;
-                       if (type != TYPE_BITMAP)
-                               continue;
-
-                       if (ep->flags == 0x0) {
-                               p_fs->map_clu  = GET32_A(ep->start_clu);
-                               map_size = (u32)GET64_A(ep->size);
-
-                               p_fs->map_sectors = ((map_size - 1) >> p_bd->sector_size_bits) + 1;
-
-                               p_fs->vol_amap = kmalloc_array(p_fs->map_sectors,
-                                                              sizeof(struct buffer_head *),
-                                                              GFP_KERNEL);
-                               if (!p_fs->vol_amap)
-                                       return -ENOMEM;
-
-                               sector = START_SECTOR(p_fs->map_clu);
-
-                               for (j = 0; j < p_fs->map_sectors; j++) {
-                                       p_fs->vol_amap[j] = NULL;
-                                       ret = sector_read(sb, sector + j, &p_fs->vol_amap[j], 1);
-                                       if (ret != 0) {
-                                               /*  release all buffers and free vol_amap */
-                                               i = 0;
-                                               while (i < j)
-                                                       brelse(p_fs->vol_amap[i++]);
-
-                                               kfree(p_fs->vol_amap);
-                                               p_fs->vol_amap = NULL;
-                                               return ret;
-                                       }
-                               }
-
-                               p_fs->pbr_bh = NULL;
-                               return 0;
-                       }
-               }
-
-               if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0)
-                       return -EIO;
-       }
-
-       return -EFSCORRUPTED;
-}
-
-void free_alloc_bitmap(struct super_block *sb)
-{
-       int i;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       brelse(p_fs->pbr_bh);
-
-       for (i = 0; i < p_fs->map_sectors; i++)
-               __brelse(p_fs->vol_amap[i]);
-
-       kfree(p_fs->vol_amap);
-       p_fs->vol_amap = NULL;
-}
-
-void sync_alloc_bitmap(struct super_block *sb)
-{
-       int i;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (!p_fs->vol_amap)
-               return;
-
-       for (i = 0; i < p_fs->map_sectors; i++)
-               sync_dirty_buffer(p_fs->vol_amap[i]);
-}
-
-/*
- *  Upcase table Management Functions
- */
-static s32 __load_upcase_table(struct super_block *sb, sector_t sector,
-                              u32 num_sectors, u32 utbl_checksum)
-{
-       int i, ret = -EINVAL;
-       u32 j;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-       struct buffer_head *tmp_bh = NULL;
-       sector_t end_sector = num_sectors + sector;
-
-       bool    skip = false;
-       u32     index = 0;
-       u16     uni = 0;
-       u16 **upcase_table;
-
-       u32 checksum = 0;
-
-       upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL);
-       p_fs->vol_utbl = upcase_table;
-       if (!upcase_table)
-               return -ENOMEM;
-       memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *));
-
-       while (sector < end_sector) {
-               ret = sector_read(sb, sector, &tmp_bh, 1);
-               if (ret != 0) {
-                       pr_debug("sector read (0x%llX)fail\n",
-                                (unsigned long long)sector);
-                       goto error;
-               }
-               sector++;
-
-               for (i = 0; i < p_bd->sector_size && index <= 0xFFFF; i += 2) {
-                       uni = GET16(((u8 *)tmp_bh->b_data) + i);
-
-                       checksum = ((checksum & 1) ? 0x80000000 : 0) +
-                                  (checksum >> 1) + *(((u8 *)tmp_bh->b_data) +
-                                                      i);
-                       checksum = ((checksum & 1) ? 0x80000000 : 0) +
-                                  (checksum >> 1) + *(((u8 *)tmp_bh->b_data) +
-                                                      (i + 1));
-
-                       if (skip) {
-                               pr_debug("skip from 0x%X ", index);
-                               index += uni;
-                               pr_debug("to 0x%X (amount of 0x%X)\n",
-                                        index, uni);
-                               skip = false;
-                       } else if (uni == index) {
-                               index++;
-                       } else if (uni == 0xFFFF) {
-                               skip = true;
-                       } else { /* uni != index , uni != 0xFFFF */
-                               u16 col_index = get_col_index(index);
-
-                               if (!upcase_table[col_index]) {
-                                       pr_debug("alloc = 0x%X\n", col_index);
-                                       upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT,
-                                               sizeof(u16), GFP_KERNEL);
-                                       if (!upcase_table[col_index]) {
-                                               ret = -ENOMEM;
-                                               goto error;
-                                       }
-
-                                       for (j = 0; j < UTBL_ROW_COUNT; j++)
-                                               upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
-                               }
-
-                               upcase_table[col_index][get_row_index(index)] = uni;
-                               index++;
-                       }
-               }
-       }
-       if (index >= 0xFFFF && utbl_checksum == checksum) {
-               if (tmp_bh)
-                       brelse(tmp_bh);
-               return 0;
-       }
-       ret = -EINVAL;
-error:
-       if (tmp_bh)
-               brelse(tmp_bh);
-       free_upcase_table(sb);
-       return ret;
-}
-
-static s32 __load_default_upcase_table(struct super_block *sb)
-{
-       int i, ret = -EINVAL;
-       u32 j;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       bool    skip = false;
-       u32     index = 0;
-       u16     uni = 0;
-       u16 **upcase_table;
-
-       upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL);
-       p_fs->vol_utbl = upcase_table;
-       if (!upcase_table)
-               return -ENOMEM;
-       memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *));
-
-       for (i = 0; index <= 0xFFFF && i < NUM_UPCASE * 2; i += 2) {
-               uni = GET16(uni_upcase + i);
-               if (skip) {
-                       pr_debug("skip from 0x%X ", index);
-                       index += uni;
-                       pr_debug("to 0x%X (amount of 0x%X)\n", index, uni);
-                       skip = false;
-               } else if (uni == index) {
-                       index++;
-               } else if (uni == 0xFFFF) {
-                       skip = true;
-               } else { /* uni != index , uni != 0xFFFF */
-                       u16 col_index = get_col_index(index);
-
-                       if (!upcase_table[col_index]) {
-                               pr_debug("alloc = 0x%X\n", col_index);
-                               upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT,
-                                                                       sizeof(u16),
-                                                                       GFP_KERNEL);
-                               if (!upcase_table[col_index]) {
-                                       ret = -ENOMEM;
-                                       goto error;
-                               }
-
-                               for (j = 0; j < UTBL_ROW_COUNT; j++)
-                                       upcase_table[col_index][j] = (col_index << LOW_INDEX_BIT) | j;
-                       }
-
-                       upcase_table[col_index][get_row_index(index)] = uni;
-                       index++;
-               }
-       }
-
-       if (index >= 0xFFFF)
-               return 0;
-
-error:
-       /* FATAL error: default upcase table has error */
-       free_upcase_table(sb);
-       return ret;
-}
-
-s32 load_upcase_table(struct super_block *sb)
-{
-       int i;
-       u32 tbl_clu, tbl_size;
-       sector_t sector;
-       u32 type, num_sectors;
-       struct chain_t clu;
-       struct case_dentry_t *ep;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       clu.dir = p_fs->root_dir;
-       clu.flags = 0x01;
-
-       if (p_fs->dev_ejected)
-               return -EIO;
-
-       while (clu.dir != CLUSTER_32(~0)) {
-               for (i = 0; i < p_fs->dentries_per_clu; i++) {
-                       ep = (struct case_dentry_t *)get_entry_in_dir(sb, &clu,
-                                                                     i, NULL);
-                       if (!ep)
-                               return -ENOENT;
-
-                       type = exfat_get_entry_type((struct dentry_t *)ep);
-
-                       if (type == TYPE_UNUSED)
-                               break;
-                       if (type != TYPE_UPCASE)
-                               continue;
-
-                       tbl_clu  = GET32_A(ep->start_clu);
-                       tbl_size = (u32)GET64_A(ep->size);
-
-                       sector = START_SECTOR(tbl_clu);
-                       num_sectors = ((tbl_size - 1) >> p_bd->sector_size_bits) + 1;
-                       if (__load_upcase_table(sb, sector, num_sectors,
-                                               GET32_A(ep->checksum)) != 0)
-                               break;
-                       return 0;
-               }
-               if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0)
-                       return -EIO;
-       }
-       /* load default upcase table */
-       return __load_default_upcase_table(sb);
-}
-
-void free_upcase_table(struct super_block *sb)
-{
-       u32 i;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       u16 **upcase_table;
-
-       upcase_table = p_fs->vol_utbl;
-       for (i = 0; i < UTBL_COL_COUNT; i++)
-               kfree(upcase_table[i]);
-
-       kfree(p_fs->vol_utbl);
-       p_fs->vol_utbl = NULL;
-}
-
-/*
- *  Directory Entry Management Functions
- */
-
-u32 exfat_get_entry_type(struct dentry_t *p_entry)
-{
-       struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
-
-       if (ep->type == 0x0) {
-               return TYPE_UNUSED;
-       } else if (ep->type < 0x80) {
-               return TYPE_DELETED;
-       } else if (ep->type == 0x80) {
-               return TYPE_INVALID;
-       } else if (ep->type < 0xA0) {
-               if (ep->type == 0x81) {
-                       return TYPE_BITMAP;
-               } else if (ep->type == 0x82) {
-                       return TYPE_UPCASE;
-               } else if (ep->type == 0x83) {
-                       return TYPE_VOLUME;
-               } else if (ep->type == 0x85) {
-                       if (GET16_A(ep->attr) & ATTR_SUBDIR)
-                               return TYPE_DIR;
-                       else
-                               return TYPE_FILE;
-               }
-               return TYPE_CRITICAL_PRI;
-       } else if (ep->type < 0xC0) {
-               if (ep->type == 0xA0)
-                       return TYPE_GUID;
-               else if (ep->type == 0xA1)
-                       return TYPE_PADDING;
-               else if (ep->type == 0xA2)
-                       return TYPE_ACLTAB;
-               return TYPE_BENIGN_PRI;
-       } else if (ep->type < 0xE0) {
-               if (ep->type == 0xC0)
-                       return TYPE_STREAM;
-               else if (ep->type == 0xC1)
-                       return TYPE_EXTEND;
-               else if (ep->type == 0xC2)
-                       return TYPE_ACL;
-               return TYPE_CRITICAL_SEC;
-       }
-
-       return TYPE_BENIGN_SEC;
-}
-
-static void exfat_set_entry_type(struct dentry_t *p_entry, u32 type)
-{
-       struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
-
-       if (type == TYPE_UNUSED) {
-               ep->type = 0x0;
-       } else if (type == TYPE_DELETED) {
-               ep->type &= ~0x80;
-       } else if (type == TYPE_STREAM) {
-               ep->type = 0xC0;
-       } else if (type == TYPE_EXTEND) {
-               ep->type = 0xC1;
-       } else if (type == TYPE_BITMAP) {
-               ep->type = 0x81;
-       } else if (type == TYPE_UPCASE) {
-               ep->type = 0x82;
-       } else if (type == TYPE_VOLUME) {
-               ep->type = 0x83;
-       } else if (type == TYPE_DIR) {
-               ep->type = 0x85;
-               SET16_A(ep->attr, ATTR_SUBDIR);
-       } else if (type == TYPE_FILE) {
-               ep->type = 0x85;
-               SET16_A(ep->attr, ATTR_ARCHIVE);
-       } else if (type == TYPE_SYMLINK) {
-               ep->type = 0x85;
-               SET16_A(ep->attr, ATTR_ARCHIVE | ATTR_SYMLINK);
-       }
-}
-
-u32 exfat_get_entry_attr(struct dentry_t *p_entry)
-{
-       struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
-
-       return (u32)GET16_A(ep->attr);
-}
-
-void exfat_set_entry_attr(struct dentry_t *p_entry, u32 attr)
-{
-       struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
-
-       SET16_A(ep->attr, (u16)attr);
-}
-
-u8 exfat_get_entry_flag(struct dentry_t *p_entry)
-{
-       struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
-
-       return ep->flags;
-}
-
-void exfat_set_entry_flag(struct dentry_t *p_entry, u8 flags)
-{
-       struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
-
-       ep->flags = flags;
-}
-
-u32 exfat_get_entry_clu0(struct dentry_t *p_entry)
-{
-       struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
-
-       return GET32_A(ep->start_clu);
-}
-
-void exfat_set_entry_clu0(struct dentry_t *p_entry, u32 start_clu)
-{
-       struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
-
-       SET32_A(ep->start_clu, start_clu);
-}
-
-u64 exfat_get_entry_size(struct dentry_t *p_entry)
-{
-       struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
-
-       return GET64_A(ep->valid_size);
-}
-
-void exfat_set_entry_size(struct dentry_t *p_entry, u64 size)
-{
-       struct strm_dentry_t *ep = (struct strm_dentry_t *)p_entry;
-
-       SET64_A(ep->valid_size, size);
-       SET64_A(ep->size, size);
-}
-
-void exfat_get_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
-                         u8 mode)
-{
-       u16 t = 0x00, d = 0x21;
-       struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
-
-       switch (mode) {
-       case TM_CREATE:
-               t = GET16_A(ep->create_time);
-               d = GET16_A(ep->create_date);
-               break;
-       case TM_MODIFY:
-               t = GET16_A(ep->modify_time);
-               d = GET16_A(ep->modify_date);
-               break;
-       case TM_ACCESS:
-               t = GET16_A(ep->access_time);
-               d = GET16_A(ep->access_date);
-               break;
-       }
-
-       tp->sec  = (t & 0x001F) << 1;
-       tp->min  = (t >> 5) & 0x003F;
-       tp->hour = (t >> 11);
-       tp->day  = (d & 0x001F);
-       tp->mon  = (d >> 5) & 0x000F;
-       tp->year = (d >> 9);
-}
-
-void exfat_set_entry_time(struct dentry_t *p_entry, struct timestamp_t *tp,
-                         u8 mode)
-{
-       u16 t, d;
-       struct file_dentry_t *ep = (struct file_dentry_t *)p_entry;
-
-       t = (tp->hour << 11) | (tp->min << 5) | (tp->sec >> 1);
-       d = (tp->year <<  9) | (tp->mon << 5) |  tp->day;
-
-       switch (mode) {
-       case TM_CREATE:
-               SET16_A(ep->create_time, t);
-               SET16_A(ep->create_date, d);
-               break;
-       case TM_MODIFY:
-               SET16_A(ep->modify_time, t);
-               SET16_A(ep->modify_date, d);
-               break;
-       case TM_ACCESS:
-               SET16_A(ep->access_time, t);
-               SET16_A(ep->access_date, d);
-               break;
-       }
-}
-
-static void init_file_entry(struct file_dentry_t *ep, u32 type)
-{
-       struct timestamp_t tm, *tp;
-
-       exfat_set_entry_type((struct dentry_t *)ep, type);
-
-       tp = tm_current(&tm);
-       exfat_set_entry_time((struct dentry_t *)ep, tp, TM_CREATE);
-       exfat_set_entry_time((struct dentry_t *)ep, tp, TM_MODIFY);
-       exfat_set_entry_time((struct dentry_t *)ep, tp, TM_ACCESS);
-       ep->create_time_ms = 0;
-       ep->modify_time_ms = 0;
-       ep->access_time_ms = 0;
-}
-
-static void init_strm_entry(struct strm_dentry_t *ep, u8 flags, u32 start_clu, u64 size)
-{
-       exfat_set_entry_type((struct dentry_t *)ep, TYPE_STREAM);
-       ep->flags = flags;
-       SET32_A(ep->start_clu, start_clu);
-       SET64_A(ep->valid_size, size);
-       SET64_A(ep->size, size);
-}
-
-static void init_name_entry(struct name_dentry_t *ep, u16 *uniname)
-{
-       int i;
-
-       exfat_set_entry_type((struct dentry_t *)ep, TYPE_EXTEND);
-       ep->flags = 0x0;
-
-       for (i = 0; i < 30; i++, i++) {
-               SET16_A(ep->unicode_0_14 + i, *uniname);
-               if (*uniname == 0x0)
-                       break;
-               uniname++;
-       }
-}
-
-static s32 exfat_init_dir_entry(struct super_block *sb, struct chain_t *p_dir,
-                               s32 entry, u32 type, u32 start_clu, u64 size)
-{
-       sector_t sector;
-       u8 flags;
-       struct file_dentry_t *file_ep;
-       struct strm_dentry_t *strm_ep;
-
-       flags = (type == TYPE_FILE) ? 0x01 : 0x03;
-
-       /* we cannot use get_entry_set_in_dir here because file ep is not initialized yet */
-       file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
-                                                          &sector);
-       if (!file_ep)
-               return -ENOENT;
-
-       strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1,
-                                                          &sector);
-       if (!strm_ep)
-               return -ENOENT;
-
-       init_file_entry(file_ep, type);
-       exfat_buf_modify(sb, sector);
-
-       init_strm_entry(strm_ep, flags, start_clu, size);
-       exfat_buf_modify(sb, sector);
-
-       return 0;
-}
-
-static s32 exfat_init_ext_entry(struct super_block *sb, struct chain_t *p_dir,
-                               s32 entry, s32 num_entries,
-                               struct uni_name_t *p_uniname,
-                               struct dos_name_t *p_dosname)
-{
-       int i;
-       sector_t sector;
-       u16 *uniname = p_uniname->name;
-       struct file_dentry_t *file_ep;
-       struct strm_dentry_t *strm_ep;
-       struct name_dentry_t *name_ep;
-
-       file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
-                                                          &sector);
-       if (!file_ep)
-               return -ENOENT;
-
-       file_ep->num_ext = (u8)(num_entries - 1);
-       exfat_buf_modify(sb, sector);
-
-       strm_ep = (struct strm_dentry_t *)get_entry_in_dir(sb, p_dir, entry + 1,
-                                                          &sector);
-       if (!strm_ep)
-               return -ENOENT;
-
-       strm_ep->name_len = p_uniname->name_len;
-       SET16_A(strm_ep->name_hash, p_uniname->name_hash);
-       exfat_buf_modify(sb, sector);
-
-       for (i = 2; i < num_entries; i++) {
-               name_ep = (struct name_dentry_t *)get_entry_in_dir(sb, p_dir,
-                                                                  entry + i,
-                                                                  &sector);
-               if (!name_ep)
-                       return -ENOENT;
-
-               init_name_entry(name_ep, uniname);
-               exfat_buf_modify(sb, sector);
-               uniname += 15;
-       }
-
-       update_dir_checksum(sb, p_dir, entry);
-
-       return 0;
-}
-
-void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir,
-                           s32 entry, s32 order, s32 num_entries)
-{
-       int i;
-       sector_t sector;
-       struct dentry_t *ep;
-
-       for (i = order; i < num_entries; i++) {
-               ep = get_entry_in_dir(sb, p_dir, entry + i, &sector);
-               if (!ep)
-                       return;
-
-               exfat_set_entry_type(ep, TYPE_DELETED);
-               exfat_buf_modify(sb, sector);
-       }
-}
-
-void update_dir_checksum(struct super_block *sb, struct chain_t *p_dir,
-                        s32 entry)
-{
-       int i, num_entries;
-       sector_t sector;
-       u16 chksum;
-       struct file_dentry_t *file_ep;
-       struct dentry_t *ep;
-
-       file_ep = (struct file_dentry_t *)get_entry_in_dir(sb, p_dir, entry,
-                                                          &sector);
-       if (!file_ep)
-               return;
-
-       exfat_buf_lock(sb, sector);
-
-       num_entries = (s32)file_ep->num_ext + 1;
-       chksum = calc_checksum_2byte((void *)file_ep, DENTRY_SIZE, 0,
-                                    CS_DIR_ENTRY);
-
-       for (i = 1; i < num_entries; i++) {
-               ep = get_entry_in_dir(sb, p_dir, entry + i, NULL);
-               if (!ep) {
-                       exfat_buf_unlock(sb, sector);
-                       return;
-               }
-
-               chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum,
-                                            CS_DEFAULT);
-       }
-
-       SET16_A(file_ep->checksum, chksum);
-       exfat_buf_modify(sb, sector);
-       exfat_buf_unlock(sb, sector);
-}
-
-static s32 __write_partial_entries_in_entry_set(struct super_block *sb,
-                                               struct entry_set_cache_t *es,
-                                               sector_t sec, s32 off, u32 count)
-{
-       s32 num_entries, buf_off = (off - es->offset);
-       u32 remaining_byte_in_sector, copy_entries;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-       u32 clu;
-       u8 *buf, *esbuf = (u8 *)&es->__buf;
-
-       pr_debug("%s entered es %p sec %llu off %d count %d\n",
-                __func__, es, (unsigned long long)sec, off, count);
-       num_entries = count;
-
-       while (num_entries) {
-               /* white per sector base */
-               remaining_byte_in_sector = (1 << p_bd->sector_size_bits) - off;
-               copy_entries = min_t(s32,
-                                    remaining_byte_in_sector >> DENTRY_SIZE_BITS,
-                                    num_entries);
-               buf = exfat_buf_getblk(sb, sec);
-               if (!buf)
-                       goto err_out;
-               pr_debug("es->buf %p buf_off %u\n", esbuf, buf_off);
-               pr_debug("copying %d entries from %p to sector %llu\n",
-                        copy_entries, (esbuf + buf_off),
-                        (unsigned long long)sec);
-               memcpy(buf + off, esbuf + buf_off,
-                      copy_entries << DENTRY_SIZE_BITS);
-               exfat_buf_modify(sb, sec);
-               num_entries -= copy_entries;
-
-               if (num_entries) {
-                       /* get next sector */
-                       if (IS_LAST_SECTOR_IN_CLUSTER(sec)) {
-                               clu = GET_CLUSTER_FROM_SECTOR(sec);
-                               if (es->alloc_flag == 0x03) {
-                                       clu++;
-                               } else {
-                                       if (exfat_fat_read(sb, clu, &clu) == -1)
-                                               goto err_out;
-                               }
-                               sec = START_SECTOR(clu);
-                       } else {
-                               sec++;
-                       }
-                       off = 0;
-                       buf_off += copy_entries << DENTRY_SIZE_BITS;
-               }
-       }
-
-       pr_debug("%s exited successfully\n", __func__);
-       return 0;
-err_out:
-       pr_debug("%s failed\n", __func__);
-       return -EINVAL;
-}
-
-/* write back all entries in entry set */
-static s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es)
-{
-       return __write_partial_entries_in_entry_set(sb, es, es->sector,
-                                                   es->offset,
-                                                   es->num_entries);
-}
-
-void update_dir_checksum_with_entry_set(struct super_block *sb,
-                                       struct entry_set_cache_t *es)
-{
-       struct dentry_t *ep;
-       u16 chksum = 0;
-       s32 chksum_type = CS_DIR_ENTRY, i;
-
-       ep = (struct dentry_t *)&es->__buf;
-       for (i = 0; i < es->num_entries; i++) {
-               pr_debug("%s ep %p\n", __func__, ep);
-               chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum,
-                                            chksum_type);
-               ep++;
-               chksum_type = CS_DEFAULT;
-       }
-
-       ep = (struct dentry_t *)&es->__buf;
-       SET16_A(((struct file_dentry_t *)ep)->checksum, chksum);
-       write_whole_entry_set(sb, es);
-}
-
-static s32 _walk_fat_chain(struct super_block *sb, struct chain_t *p_dir,
-                          s32 byte_offset, u32 *clu)
-{
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       s32 clu_offset;
-       u32 cur_clu;
-
-       clu_offset = byte_offset >> p_fs->cluster_size_bits;
-       cur_clu = p_dir->dir;
-
-       if (p_dir->flags == 0x03) {
-               cur_clu += clu_offset;
-       } else {
-               while (clu_offset > 0) {
-                       if (exfat_fat_read(sb, cur_clu, &cur_clu) == -1)
-                               return -EIO;
-                       clu_offset--;
-               }
-       }
-
-       if (clu)
-               *clu = cur_clu;
-       return 0;
-}
-
-static s32 find_location(struct super_block *sb, struct chain_t *p_dir, s32 entry,
-                        sector_t *sector, s32 *offset)
-{
-       s32 off, ret;
-       u32 clu = 0;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       off = entry << DENTRY_SIZE_BITS;
-
-       if (p_dir->dir == CLUSTER_32(0)) { /* FAT16 root_dir */
-               *offset = off & p_bd->sector_size_mask;
-               *sector = off >> p_bd->sector_size_bits;
-               *sector += p_fs->root_start_sector;
-       } else {
-               ret = _walk_fat_chain(sb, p_dir, off, &clu);
-               if (ret != 0)
-                       return ret;
-
-               /* byte offset in cluster */
-               off &= p_fs->cluster_size - 1;
-
-               /* byte offset in sector    */
-               *offset = off & p_bd->sector_size_mask;
-
-               /* sector offset in cluster */
-               *sector = off >> p_bd->sector_size_bits;
-               *sector += START_SECTOR(clu);
-       }
-       return 0;
-}
-
-struct dentry_t *get_entry_in_dir(struct super_block *sb, struct chain_t *p_dir,
-                                 s32 entry, sector_t *sector)
-{
-       s32 off;
-       sector_t sec;
-       u8 *buf;
-
-       if (find_location(sb, p_dir, entry, &sec, &off) != 0)
-               return NULL;
-
-       buf = exfat_buf_getblk(sb, sec);
-
-       if (!buf)
-               return NULL;
-
-       if (sector)
-               *sector = sec;
-       return (struct dentry_t *)(buf + off);
-}
-
-/* returns a set of dentries for a file or dir.
- * Note that this is a copy (dump) of dentries so that user should call write_entry_set()
- * to apply changes made in this entry set to the real device.
- * in:
- *   sb+p_dir+entry: indicates a file/dir
- *   type:  specifies how many dentries should be included.
- * out:
- *   file_ep: will point the first dentry(= file dentry) on success
- * return:
- *   pointer of entry set on success,
- *   NULL on failure.
- */
-
-#define ES_MODE_STARTED                                0
-#define ES_MODE_GET_FILE_ENTRY                 1
-#define ES_MODE_GET_STRM_ENTRY                 2
-#define ES_MODE_GET_NAME_ENTRY                 3
-#define ES_MODE_GET_CRITICAL_SEC_ENTRY         4
-struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb,
-                                              struct chain_t *p_dir, s32 entry,
-                                              u32 type,
-                                              struct dentry_t **file_ep)
-{
-       s32 off, ret, byte_offset;
-       u32 clu = 0;
-       sector_t sec;
-       u32 entry_type;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-       struct entry_set_cache_t *es = NULL;
-       struct dentry_t *ep, *pos;
-       u8 *buf;
-       u8 num_entries;
-       s32 mode = ES_MODE_STARTED;
-       size_t bufsize;
-
-       pr_debug("%s entered p_dir dir %u flags %x size %d\n",
-                __func__, p_dir->dir, p_dir->flags, p_dir->size);
-
-       byte_offset = entry << DENTRY_SIZE_BITS;
-       ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu);
-       if (ret != 0)
-               return NULL;
-
-       /* byte offset in cluster */
-       byte_offset &= p_fs->cluster_size - 1;
-
-       /* byte offset in sector    */
-       off = byte_offset & p_bd->sector_size_mask;
-
-       /* sector offset in cluster */
-       sec = byte_offset >> p_bd->sector_size_bits;
-       sec += START_SECTOR(clu);
-
-       buf = exfat_buf_getblk(sb, sec);
-       if (!buf)
-               goto err_out;
-
-       ep = (struct dentry_t *)(buf + off);
-       entry_type = exfat_get_entry_type(ep);
-
-       if ((entry_type != TYPE_FILE) && (entry_type != TYPE_DIR))
-               goto err_out;
-
-       if (type == ES_ALL_ENTRIES)
-               num_entries = ((struct file_dentry_t *)ep)->num_ext + 1;
-       else
-               num_entries = type;
-
-       bufsize = offsetof(struct entry_set_cache_t, __buf) + (num_entries) *
-                 sizeof(struct dentry_t);
-       pr_debug("%s: trying to kmalloc %zx bytes for %d entries\n", __func__,
-                bufsize, num_entries);
-       es = kmalloc(bufsize, GFP_KERNEL);
-       if (!es)
-               goto err_out;
-
-       es->num_entries = num_entries;
-       es->sector = sec;
-       es->offset = off;
-       es->alloc_flag = p_dir->flags;
-
-       pos = (struct dentry_t *)&es->__buf;
-
-       while (num_entries) {
-               /*
-                * instead of copying whole sector, we will check every entry.
-                * this will provide minimum stablity and consistency.
-                */
-               entry_type = exfat_get_entry_type(ep);
-
-               if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED))
-                       goto err_out;
-
-               switch (mode) {
-               case ES_MODE_STARTED:
-                       if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR))
-                               mode = ES_MODE_GET_FILE_ENTRY;
-                       else
-                               goto err_out;
-                       break;
-               case ES_MODE_GET_FILE_ENTRY:
-                       if (entry_type == TYPE_STREAM)
-                               mode = ES_MODE_GET_STRM_ENTRY;
-                       else
-                               goto err_out;
-                       break;
-               case ES_MODE_GET_STRM_ENTRY:
-                       if (entry_type == TYPE_EXTEND)
-                               mode = ES_MODE_GET_NAME_ENTRY;
-                       else
-                               goto err_out;
-                       break;
-               case ES_MODE_GET_NAME_ENTRY:
-                       if (entry_type == TYPE_EXTEND)
-                               break;
-                       else if (entry_type == TYPE_STREAM)
-                               goto err_out;
-                       else if (entry_type & TYPE_CRITICAL_SEC)
-                               mode = ES_MODE_GET_CRITICAL_SEC_ENTRY;
-                       else
-                               goto err_out;
-                       break;
-               case ES_MODE_GET_CRITICAL_SEC_ENTRY:
-                       if ((entry_type == TYPE_EXTEND) ||
-                           (entry_type == TYPE_STREAM))
-                               goto err_out;
-                       else if ((entry_type & TYPE_CRITICAL_SEC) !=
-                                TYPE_CRITICAL_SEC)
-                               goto err_out;
-                       break;
-               }
-
-               memcpy(pos, ep, sizeof(struct dentry_t));
-
-               if (--num_entries == 0)
-                       break;
-
-               if (((off + DENTRY_SIZE) & p_bd->sector_size_mask) <
-                   (off &  p_bd->sector_size_mask)) {
-                       /* get the next sector */
-                       if (IS_LAST_SECTOR_IN_CLUSTER(sec)) {
-                               if (es->alloc_flag == 0x03) {
-                                       clu++;
-                               } else {
-                                       if (exfat_fat_read(sb, clu, &clu) == -1)
-                                               goto err_out;
-                               }
-                               sec = START_SECTOR(clu);
-                       } else {
-                               sec++;
-                       }
-                       buf = exfat_buf_getblk(sb, sec);
-                       if (!buf)
-                               goto err_out;
-                       off = 0;
-                       ep = (struct dentry_t *)(buf);
-               } else {
-                       ep++;
-                       off += DENTRY_SIZE;
-               }
-               pos++;
-       }
-
-       if (file_ep)
-               *file_ep = (struct dentry_t *)&es->__buf;
-
-       pr_debug("%s exiting es %p sec %llu offset %d flags %d, num_entries %u buf ptr %p\n",
-                __func__, es, (unsigned long long)es->sector, es->offset,
-                es->alloc_flag, es->num_entries, &es->__buf);
-       return es;
-err_out:
-       pr_debug("%s exited NULL (es %p)\n", __func__, es);
-       kfree(es);
-       return NULL;
-}
-
-void release_entry_set(struct entry_set_cache_t *es)
-{
-       pr_debug("%s es=%p\n", __func__, es);
-       kfree(es);
-}
-
-/* search EMPTY CONTINUOUS "num_entries" entries */
-static s32 search_deleted_or_unused_entry(struct super_block *sb,
-                                         struct chain_t *p_dir,
-                                         s32 num_entries)
-{
-       int i, dentry, num_empty = 0;
-       s32 dentries_per_clu;
-       u32 type;
-       struct chain_t clu;
-       struct dentry_t *ep;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
-               dentries_per_clu = p_fs->dentries_in_root;
-       else
-               dentries_per_clu = p_fs->dentries_per_clu;
-
-       if (p_fs->hint_uentry.dir == p_dir->dir) {
-               if (p_fs->hint_uentry.entry == -1)
-                       return -1;
-
-               clu.dir = p_fs->hint_uentry.clu.dir;
-               clu.size = p_fs->hint_uentry.clu.size;
-               clu.flags = p_fs->hint_uentry.clu.flags;
-
-               dentry = p_fs->hint_uentry.entry;
-       } else {
-               p_fs->hint_uentry.entry = -1;
-
-               clu.dir = p_dir->dir;
-               clu.size = p_dir->size;
-               clu.flags = p_dir->flags;
-
-               dentry = 0;
-       }
-
-       while (clu.dir != CLUSTER_32(~0)) {
-               if (p_fs->dev_ejected)
-                       break;
-
-               if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
-                       i = dentry % dentries_per_clu;
-               else
-                       i = dentry & (dentries_per_clu - 1);
-
-               for (; i < dentries_per_clu; i++, dentry++) {
-                       ep = get_entry_in_dir(sb, &clu, i, NULL);
-                       if (!ep)
-                               return -1;
-
-                       type = exfat_get_entry_type(ep);
-
-                       if (type == TYPE_UNUSED) {
-                               num_empty++;
-                               if (p_fs->hint_uentry.entry == -1) {
-                                       p_fs->hint_uentry.dir = p_dir->dir;
-                                       p_fs->hint_uentry.entry = dentry;
-
-                                       p_fs->hint_uentry.clu.dir = clu.dir;
-                                       p_fs->hint_uentry.clu.size = clu.size;
-                                       p_fs->hint_uentry.clu.flags = clu.flags;
-                               }
-                       } else if (type == TYPE_DELETED) {
-                               num_empty++;
-                       } else {
-                               num_empty = 0;
-                       }
-
-                       if (num_empty >= num_entries) {
-                               p_fs->hint_uentry.dir = CLUSTER_32(~0);
-                               p_fs->hint_uentry.entry = -1;
-
-                               if (p_fs->vol_type == EXFAT)
-                                       return dentry - (num_entries - 1);
-                               else
-                                       return dentry;
-                       }
-               }
-
-               if (p_dir->dir == CLUSTER_32(0))
-                       break; /* FAT16 root_dir */
-
-               if (clu.flags == 0x03) {
-                       if ((--clu.size) > 0)
-                               clu.dir++;
-                       else
-                               clu.dir = CLUSTER_32(~0);
-               } else {
-                       if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0)
-                               return -1;
-               }
-       }
-
-       return -1;
-}
-
-static s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, s32 num_entries)
-{
-       s32 ret, dentry;
-       u32 last_clu;
-       sector_t sector;
-       u64 size = 0;
-       struct chain_t clu;
-       struct dentry_t *ep = NULL;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-
-       if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
-               return search_deleted_or_unused_entry(sb, p_dir, num_entries);
-
-       while ((dentry = search_deleted_or_unused_entry(sb, p_dir, num_entries)) < 0) {
-               if (p_fs->dev_ejected)
-                       break;
-
-               if (p_dir->dir != p_fs->root_dir)
-                       size = i_size_read(inode);
-
-               last_clu = find_last_cluster(sb, p_dir);
-               clu.dir = last_clu + 1;
-               clu.size = 0;
-               clu.flags = p_dir->flags;
-
-               /* (1) allocate a cluster */
-               ret = exfat_alloc_cluster(sb, 1, &clu);
-               if (ret < 1)
-                       return -EIO;
-
-               if (clear_cluster(sb, clu.dir) != 0)
-                       return -EIO;
-
-               /* (2) append to the FAT chain */
-               if (clu.flags != p_dir->flags) {
-                       exfat_chain_cont_cluster(sb, p_dir->dir, p_dir->size);
-                       p_dir->flags = 0x01;
-                       p_fs->hint_uentry.clu.flags = 0x01;
-               }
-               if (clu.flags == 0x01)
-                       if (exfat_fat_write(sb, last_clu, clu.dir) < 0)
-                               return -EIO;
-
-               if (p_fs->hint_uentry.entry == -1) {
-                       p_fs->hint_uentry.dir = p_dir->dir;
-                       p_fs->hint_uentry.entry = p_dir->size << (p_fs->cluster_size_bits - DENTRY_SIZE_BITS);
-
-                       p_fs->hint_uentry.clu.dir = clu.dir;
-                       p_fs->hint_uentry.clu.size = 0;
-                       p_fs->hint_uentry.clu.flags = clu.flags;
-               }
-               p_fs->hint_uentry.clu.size++;
-               p_dir->size++;
-
-               /* (3) update the directory entry */
-               if (p_dir->dir != p_fs->root_dir) {
-                       size += p_fs->cluster_size;
-
-                       ep = get_entry_in_dir(sb, &fid->dir,
-                                             fid->entry + 1, &sector);
-                       if (!ep)
-                               return -ENOENT;
-                       exfat_set_entry_size(ep, size);
-                       exfat_set_entry_flag(ep, p_dir->flags);
-                       exfat_buf_modify(sb, sector);
-
-                       update_dir_checksum(sb, &fid->dir,
-                                           fid->entry);
-               }
-
-               i_size_write(inode, i_size_read(inode) + p_fs->cluster_size);
-               EXFAT_I(inode)->mmu_private += p_fs->cluster_size;
-               EXFAT_I(inode)->fid.size += p_fs->cluster_size;
-               EXFAT_I(inode)->fid.flags = p_dir->flags;
-               inode->i_blocks += 1 << (p_fs->cluster_size_bits - 9);
-       }
-
-       return dentry;
-}
-
-static s32 extract_uni_name_from_name_entry(struct name_dentry_t *ep, u16 *uniname,
-                                           s32 order)
-{
-       int i, len = 0;
-
-       for (i = 0; i < 30; i += 2) {
-               *uniname = GET16_A(ep->unicode_0_14 + i);
-               if (*uniname == 0x0)
-                       return len;
-               uniname++;
-               len++;
-       }
-
-       *uniname = 0x0;
-       return len;
-}
-
-/* return values of exfat_find_dir_entry()
- * >= 0 : return dir entiry position with the name in dir
- * -1 : (root dir, ".") it is the root dir itself
- * -2 : entry with the name does not exist
- */
-s32 exfat_find_dir_entry(struct super_block *sb, struct chain_t *p_dir,
-                        struct uni_name_t *p_uniname, s32 num_entries,
-                        struct dos_name_t *p_dosname, u32 type)
-{
-       int i = 0, dentry = 0, num_ext_entries = 0, len, step;
-       s32 order = 0;
-       bool is_feasible_entry = false;
-       s32 dentries_per_clu, num_empty = 0;
-       u32 entry_type;
-       u16 entry_uniname[16], *uniname = NULL, unichar;
-       struct chain_t clu;
-       struct dentry_t *ep;
-       struct file_dentry_t *file_ep;
-       struct strm_dentry_t *strm_ep;
-       struct name_dentry_t *name_ep;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (p_dir->dir == p_fs->root_dir) {
-               if ((!nls_uniname_cmp(sb, p_uniname->name,
-                                     (u16 *)UNI_CUR_DIR_NAME)) ||
-                       (!nls_uniname_cmp(sb, p_uniname->name,
-                                         (u16 *)UNI_PAR_DIR_NAME)))
-                       return -1; // special case, root directory itself
-       }
-
-       if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
-               dentries_per_clu = p_fs->dentries_in_root;
-       else
-               dentries_per_clu = p_fs->dentries_per_clu;
-
-       clu.dir = p_dir->dir;
-       clu.size = p_dir->size;
-       clu.flags = p_dir->flags;
-
-       p_fs->hint_uentry.dir = p_dir->dir;
-       p_fs->hint_uentry.entry = -1;
-
-       while (clu.dir != CLUSTER_32(~0)) {
-               if (p_fs->dev_ejected)
-                       break;
-
-               while (i < dentries_per_clu) {
-                       ep = get_entry_in_dir(sb, &clu, i, NULL);
-                       if (!ep)
-                               return -2;
-
-                       entry_type = exfat_get_entry_type(ep);
-                       step = 1;
-
-                       if ((entry_type == TYPE_UNUSED) || (entry_type == TYPE_DELETED)) {
-                               is_feasible_entry = false;
-
-                               if (p_fs->hint_uentry.entry == -1) {
-                                       num_empty++;
-
-                                       if (num_empty == 1) {
-                                               p_fs->hint_uentry.clu.dir = clu.dir;
-                                               p_fs->hint_uentry.clu.size = clu.size;
-                                               p_fs->hint_uentry.clu.flags = clu.flags;
-                                       }
-                                       if ((num_empty >= num_entries) || (entry_type == TYPE_UNUSED))
-                                               p_fs->hint_uentry.entry = dentry - (num_empty - 1);
-                               }
-
-                               if (entry_type == TYPE_UNUSED)
-                                       return -2;
-                       } else {
-                               num_empty = 0;
-
-                               if ((entry_type == TYPE_FILE) || (entry_type == TYPE_DIR)) {
-                                       file_ep = (struct file_dentry_t *)ep;
-                                       if ((type == TYPE_ALL) || (type == entry_type)) {
-                                               num_ext_entries = file_ep->num_ext;
-                                               is_feasible_entry = true;
-                                       } else {
-                                               is_feasible_entry = false;
-                                               step = file_ep->num_ext + 1;
-                                       }
-                               } else if (entry_type == TYPE_STREAM) {
-                                       if (is_feasible_entry) {
-                                               strm_ep = (struct strm_dentry_t *)ep;
-                                               if (p_uniname->name_hash == GET16_A(strm_ep->name_hash) &&
-                                                   p_uniname->name_len == strm_ep->name_len) {
-                                                       order = 1;
-                                               } else {
-                                                       is_feasible_entry = false;
-                                                       step = num_ext_entries;
-                                               }
-                                       }
-                               } else if (entry_type == TYPE_EXTEND) {
-                                       if (is_feasible_entry) {
-                                               name_ep = (struct name_dentry_t *)ep;
-
-                                               if ((++order) == 2)
-                                                       uniname = p_uniname->name;
-                                               else
-                                                       uniname += 15;
-
-                                               len = extract_uni_name_from_name_entry(name_ep,
-                                                               entry_uniname, order);
-
-                                               unichar = *(uniname + len);
-                                               *(uniname + len) = 0x0;
-
-                                               if (nls_uniname_cmp(sb, uniname, entry_uniname)) {
-                                                       is_feasible_entry = false;
-                                                       step = num_ext_entries - order + 1;
-                                               } else if (order == num_ext_entries) {
-                                                       p_fs->hint_uentry.dir = CLUSTER_32(~0);
-                                                       p_fs->hint_uentry.entry = -1;
-                                                       return dentry - (num_ext_entries);
-                                               }
-
-                                               *(uniname + len) = unichar;
-                                       }
-                               } else {
-                                       is_feasible_entry = false;
-                               }
-                       }
-
-                       i += step;
-                       dentry += step;
-               }
-
-               i -= dentries_per_clu;
-
-               if (p_dir->dir == CLUSTER_32(0))
-                       break; /* FAT16 root_dir */
-
-               if (clu.flags == 0x03) {
-                       if ((--clu.size) > 0)
-                               clu.dir++;
-                       else
-                               clu.dir = CLUSTER_32(~0);
-               } else {
-                       if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0)
-                               return -2;
-               }
-       }
-
-       return -2;
-}
-
-s32 exfat_count_ext_entries(struct super_block *sb, struct chain_t *p_dir,
-                           s32 entry, struct dentry_t *p_entry)
-{
-       int i, count = 0;
-       u32 type;
-       struct file_dentry_t *file_ep = (struct file_dentry_t *)p_entry;
-       struct dentry_t *ext_ep;
-
-       for (i = 0, entry++; i < file_ep->num_ext; i++, entry++) {
-               ext_ep = get_entry_in_dir(sb, p_dir, entry, NULL);
-               if (!ext_ep)
-                       return -1;
-
-               type = exfat_get_entry_type(ext_ep);
-               if ((type == TYPE_EXTEND) || (type == TYPE_STREAM))
-                       count++;
-               else
-                       return count;
-       }
-
-       return count;
-}
-
-s32 count_dos_name_entries(struct super_block *sb, struct chain_t *p_dir,
-                          u32 type)
-{
-       int i, count = 0;
-       s32 dentries_per_clu;
-       u32 entry_type;
-       struct chain_t clu;
-       struct dentry_t *ep;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
-               dentries_per_clu = p_fs->dentries_in_root;
-       else
-               dentries_per_clu = p_fs->dentries_per_clu;
-
-       clu.dir = p_dir->dir;
-       clu.size = p_dir->size;
-       clu.flags = p_dir->flags;
-
-       while (clu.dir != CLUSTER_32(~0)) {
-               if (p_fs->dev_ejected)
-                       break;
-
-               for (i = 0; i < dentries_per_clu; i++) {
-                       ep = get_entry_in_dir(sb, &clu, i, NULL);
-                       if (!ep)
-                               return -ENOENT;
-
-                       entry_type = exfat_get_entry_type(ep);
-
-                       if (entry_type == TYPE_UNUSED)
-                               return count;
-                       if (!(type & TYPE_CRITICAL_PRI) &&
-                           !(type & TYPE_BENIGN_PRI))
-                               continue;
-
-                       if ((type == TYPE_ALL) || (type == entry_type))
-                               count++;
-               }
-
-               if (p_dir->dir == CLUSTER_32(0))
-                       break; /* FAT16 root_dir */
-
-               if (clu.flags == 0x03) {
-                       if ((--clu.size) > 0)
-                               clu.dir++;
-                       else
-                               clu.dir = CLUSTER_32(~0);
-               } else {
-                       if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0)
-                               return -EIO;
-               }
-       }
-
-       return count;
-}
-
-bool is_dir_empty(struct super_block *sb, struct chain_t *p_dir)
-{
-       int i, count = 0;
-       s32 dentries_per_clu;
-       u32 type;
-       struct chain_t clu;
-       struct dentry_t *ep;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
-               dentries_per_clu = p_fs->dentries_in_root;
-       else
-               dentries_per_clu = p_fs->dentries_per_clu;
-
-       clu.dir = p_dir->dir;
-       clu.size = p_dir->size;
-       clu.flags = p_dir->flags;
-
-       while (clu.dir != CLUSTER_32(~0)) {
-               if (p_fs->dev_ejected)
-                       break;
-
-               for (i = 0; i < dentries_per_clu; i++) {
-                       ep = get_entry_in_dir(sb, &clu, i, NULL);
-                       if (!ep)
-                               break;
-
-                       type = exfat_get_entry_type(ep);
-
-                       if (type == TYPE_UNUSED)
-                               return true;
-                       if ((type != TYPE_FILE) && (type != TYPE_DIR))
-                               continue;
-
-                       if (p_dir->dir == CLUSTER_32(0)) /* FAT16 root_dir */
-                               return false;
-
-                       if (p_fs->vol_type == EXFAT)
-                               return false;
-                       if ((p_dir->dir == p_fs->root_dir) || ((++count) > 2))
-                               return false;
-               }
-
-               if (p_dir->dir == CLUSTER_32(0))
-                       break; /* FAT16 root_dir */
-
-               if (clu.flags == 0x03) {
-                       if ((--clu.size) > 0)
-                               clu.dir++;
-                       else
-                               clu.dir = CLUSTER_32(~0);
-               }
-               if (exfat_fat_read(sb, clu.dir, &clu.dir) != 0)
-                       break;
-       }
-
-       return true;
-}
-
-/*
- *  Name Conversion Functions
- */
-
-/* input  : dir, uni_name
- * output : num_of_entry, dos_name(format : aaaaaa~1.bbb)
- */
-s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir,
-                                struct uni_name_t *p_uniname, s32 *entries,
-                                struct dos_name_t *p_dosname)
-{
-       s32 num_entries;
-
-       num_entries = exfat_calc_num_entries(p_uniname);
-       if (num_entries == 0)
-               return -EINVAL;
-
-       *entries = num_entries;
-
-       return 0;
-}
-
-void exfat_get_uni_name_from_ext_entry(struct super_block *sb,
-                                      struct chain_t *p_dir, s32 entry,
-                                      u16 *uniname)
-{
-       int i;
-       struct dentry_t *ep;
-       struct entry_set_cache_t *es;
-
-       es = get_entry_set_in_dir(sb, p_dir, entry, ES_ALL_ENTRIES, &ep);
-       if (!es || es->num_entries < 3) {
-               if (es)
-                       release_entry_set(es);
-               return;
-       }
-
-       ep += 2;
-
-       /*
-        * First entry  : file entry
-        * Second entry : stream-extension entry
-        * Third entry  : first file-name entry
-        * So, the index of first file-name dentry should start from 2.
-        */
-       for (i = 2; i < es->num_entries; i++, ep++) {
-               if (exfat_get_entry_type(ep) == TYPE_EXTEND)
-                       extract_uni_name_from_name_entry((struct name_dentry_t *)
-                                                        ep, uniname, i);
-               else
-                       goto out;
-               uniname += 15;
-       }
-
-out:
-       release_entry_set(es);
-}
-
-s32 exfat_calc_num_entries(struct uni_name_t *p_uniname)
-{
-       s32 len;
-
-       len = p_uniname->name_len;
-       if (len == 0)
-               return 0;
-
-       /* 1 file entry + 1 stream entry + name entries */
-       return (len - 1) / 15 + 3;
-}
-
-u16 calc_checksum_2byte(void *data, s32 len, u16 chksum, s32 type)
-{
-       int i;
-       u8 *c = (u8 *)data;
-
-       switch (type) {
-       case CS_DIR_ENTRY:
-               for (i = 0; i < len; i++, c++) {
-                       if ((i == 2) || (i == 3))
-                               continue;
-                       chksum = (((chksum & 1) << 15) |
-                                 ((chksum & 0xFFFE) >> 1)) + (u16)*c;
-               }
-               break;
-       default
-                       :
-               for (i = 0; i < len; i++, c++)
-                       chksum = (((chksum & 1) << 15) |
-                                 ((chksum & 0xFFFE) >> 1)) + (u16)*c;
-       }
-
-       return chksum;
-}
-
-/*
- *  Name Resolution Functions
- */
-
-/* return values of resolve_path()
- * > 0 : return the length of the path
- * < 0 : return error
- */
-s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir,
-                struct uni_name_t *p_uniname)
-{
-       bool lossy = false;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-
-       if (strscpy(name_buf, path, sizeof(name_buf)) < 0)
-               return -EINVAL;
-
-       nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy);
-       if (lossy)
-               return -EINVAL;
-
-       fid->size = i_size_read(inode);
-
-       p_dir->dir = fid->start_clu;
-       p_dir->size = (s32)(fid->size >> p_fs->cluster_size_bits);
-       p_dir->flags = fid->flags;
-
-       return 0;
-}
-
-s32 exfat_mount(struct super_block *sb, struct pbr_sector_t *p_pbr)
-{
-       struct bpbex_t *p_bpb = (struct bpbex_t *)p_pbr->bpb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       if (p_bpb->num_fats == 0)
-               return -EFSCORRUPTED;
-
-       p_fs->sectors_per_clu = 1 << p_bpb->sectors_per_clu_bits;
-       p_fs->sectors_per_clu_bits = p_bpb->sectors_per_clu_bits;
-       p_fs->cluster_size_bits = p_fs->sectors_per_clu_bits +
-                                 p_bd->sector_size_bits;
-       p_fs->cluster_size = 1 << p_fs->cluster_size_bits;
-
-       p_fs->num_FAT_sectors = GET32(p_bpb->fat_length);
-
-       p_fs->FAT1_start_sector = p_fs->PBR_sector + GET32(p_bpb->fat_offset);
-       if (p_bpb->num_fats == 1)
-               p_fs->FAT2_start_sector = p_fs->FAT1_start_sector;
-       else
-               p_fs->FAT2_start_sector = p_fs->FAT1_start_sector +
-                                         p_fs->num_FAT_sectors;
-
-       p_fs->root_start_sector = p_fs->PBR_sector + GET32(p_bpb->clu_offset);
-       p_fs->data_start_sector = p_fs->root_start_sector;
-
-       p_fs->num_sectors = GET64(p_bpb->vol_length);
-       p_fs->num_clusters = GET32(p_bpb->clu_count) + 2;
-       /* because the cluster index starts with 2 */
-
-       p_fs->vol_type = EXFAT;
-       p_fs->vol_id = GET32(p_bpb->vol_serial);
-
-       p_fs->root_dir = GET32(p_bpb->root_cluster);
-       p_fs->dentries_in_root = 0;
-       p_fs->dentries_per_clu = 1 << (p_fs->cluster_size_bits -
-                                      DENTRY_SIZE_BITS);
-
-       p_fs->vol_flag = (u32)GET16(p_bpb->vol_flags);
-       p_fs->clu_srch_ptr = 2;
-       p_fs->used_clusters = UINT_MAX;
-
-       return 0;
-}
-
-s32 create_dir(struct inode *inode, struct chain_t *p_dir,
-              struct uni_name_t *p_uniname, struct file_id_t *fid)
-{
-       s32 ret, dentry, num_entries;
-       u64 size;
-       struct chain_t clu;
-       struct dos_name_t dos_name;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries,
-                                          &dos_name);
-       if (ret)
-               return ret;
-
-       /* find_empty_entry must be called before alloc_cluster */
-       dentry = find_empty_entry(inode, p_dir, num_entries);
-       if (dentry < 0)
-               return -ENOSPC;
-
-       clu.dir = CLUSTER_32(~0);
-       clu.size = 0;
-       clu.flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
-
-       /* (1) allocate a cluster */
-       ret = exfat_alloc_cluster(sb, 1, &clu);
-       if (ret < 0)
-               return ret;
-       else if (ret == 0)
-               return -ENOSPC;
-
-       ret = clear_cluster(sb, clu.dir);
-       if (ret != 0)
-               return ret;
-
-       size = p_fs->cluster_size;
-
-       /* (2) update the directory entry */
-       /* make sub-dir entry in parent directory */
-       ret = exfat_init_dir_entry(sb, p_dir, dentry, TYPE_DIR, clu.dir,
-                                  size);
-       if (ret != 0)
-               return ret;
-
-       ret = exfat_init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname,
-                                  &dos_name);
-       if (ret != 0)
-               return ret;
-
-       fid->dir.dir = p_dir->dir;
-       fid->dir.size = p_dir->size;
-       fid->dir.flags = p_dir->flags;
-       fid->entry = dentry;
-
-       fid->attr = ATTR_SUBDIR;
-       fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
-       fid->size = size;
-       fid->start_clu = clu.dir;
-
-       fid->type = TYPE_DIR;
-       fid->rwoffset = 0;
-       fid->hint_last_off = -1;
-
-       return 0;
-}
-
-s32 create_file(struct inode *inode, struct chain_t *p_dir,
-               struct uni_name_t *p_uniname, u8 mode, struct file_id_t *fid)
-{
-       s32 ret, dentry, num_entries;
-       struct dos_name_t dos_name;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname, &num_entries,
-                                          &dos_name);
-       if (ret)
-               return ret;
-
-       /* find_empty_entry must be called before alloc_cluster() */
-       dentry = find_empty_entry(inode, p_dir, num_entries);
-       if (dentry < 0)
-               return -ENOSPC;
-
-       /* (1) update the directory entry */
-       /* fill the dos name directory entry information of the created file.
-        * the first cluster is not determined yet. (0)
-        */
-       ret = exfat_init_dir_entry(sb, p_dir, dentry, TYPE_FILE | mode,
-                                  CLUSTER_32(0), 0);
-       if (ret != 0)
-               return ret;
-
-       ret = exfat_init_ext_entry(sb, p_dir, dentry, num_entries, p_uniname,
-                                  &dos_name);
-       if (ret != 0)
-               return ret;
-
-       fid->dir.dir = p_dir->dir;
-       fid->dir.size = p_dir->size;
-       fid->dir.flags = p_dir->flags;
-       fid->entry = dentry;
-
-       fid->attr = ATTR_ARCHIVE | mode;
-       fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
-       fid->size = 0;
-       fid->start_clu = CLUSTER_32(~0);
-
-       fid->type = TYPE_FILE;
-       fid->rwoffset = 0;
-       fid->hint_last_off = -1;
-
-       return 0;
-}
-
-void remove_file(struct inode *inode, struct chain_t *p_dir, s32 entry)
-{
-       s32 num_entries;
-       sector_t sector;
-       struct dentry_t *ep;
-       struct super_block *sb = inode->i_sb;
-
-       ep = get_entry_in_dir(sb, p_dir, entry, &sector);
-       if (!ep)
-               return;
-
-       exfat_buf_lock(sb, sector);
-
-       /* exfat_buf_lock() before call count_ext_entries() */
-       num_entries = exfat_count_ext_entries(sb, p_dir, entry, ep);
-       if (num_entries < 0) {
-               exfat_buf_unlock(sb, sector);
-               return;
-       }
-       num_entries++;
-
-       exfat_buf_unlock(sb, sector);
-
-       /* (1) update the directory entry */
-       exfat_delete_dir_entry(sb, p_dir, entry, 0, num_entries);
-}
-
-s32 exfat_rename_file(struct inode *inode, struct chain_t *p_dir, s32 oldentry,
-                     struct uni_name_t *p_uniname, struct file_id_t *fid)
-{
-       s32 ret, newentry = -1, num_old_entries, num_new_entries;
-       sector_t sector_old, sector_new;
-       struct dos_name_t dos_name;
-       struct dentry_t *epold, *epnew;
-       struct super_block *sb = inode->i_sb;
-
-       epold = get_entry_in_dir(sb, p_dir, oldentry, &sector_old);
-       if (!epold)
-               return -ENOENT;
-
-       exfat_buf_lock(sb, sector_old);
-
-       /* exfat_buf_lock() before call count_ext_entries() */
-       num_old_entries = exfat_count_ext_entries(sb, p_dir, oldentry,
-                                                 epold);
-       if (num_old_entries < 0) {
-               exfat_buf_unlock(sb, sector_old);
-               return -ENOENT;
-       }
-       num_old_entries++;
-
-       ret = get_num_entries_and_dos_name(sb, p_dir, p_uniname,
-                                          &num_new_entries, &dos_name);
-       if (ret) {
-               exfat_buf_unlock(sb, sector_old);
-               return ret;
-       }
-
-       if (num_old_entries < num_new_entries) {
-               newentry = find_empty_entry(inode, p_dir, num_new_entries);
-               if (newentry < 0) {
-                       exfat_buf_unlock(sb, sector_old);
-                       return -ENOSPC;
-               }
-
-               epnew = get_entry_in_dir(sb, p_dir, newentry, &sector_new);
-               if (!epnew) {
-                       exfat_buf_unlock(sb, sector_old);
-                       return -ENOENT;
-               }
-
-               memcpy((void *)epnew, (void *)epold, DENTRY_SIZE);
-               if (exfat_get_entry_type(epnew) == TYPE_FILE) {
-                       exfat_set_entry_attr(epnew,
-                                            exfat_get_entry_attr(epnew) |
-                                            ATTR_ARCHIVE);
-                       fid->attr |= ATTR_ARCHIVE;
-               }
-               exfat_buf_modify(sb, sector_new);
-               exfat_buf_unlock(sb, sector_old);
-
-               epold = get_entry_in_dir(sb, p_dir, oldentry + 1,
-                                        &sector_old);
-               exfat_buf_lock(sb, sector_old);
-               epnew = get_entry_in_dir(sb, p_dir, newentry + 1,
-                                        &sector_new);
-
-               if (!epold || !epnew) {
-                       exfat_buf_unlock(sb, sector_old);
-                       return -ENOENT;
-               }
-
-               memcpy((void *)epnew, (void *)epold, DENTRY_SIZE);
-               exfat_buf_modify(sb, sector_new);
-               exfat_buf_unlock(sb, sector_old);
-
-               ret = exfat_init_ext_entry(sb, p_dir, newentry,
-                                          num_new_entries, p_uniname,
-                                          &dos_name);
-               if (ret != 0)
-                       return ret;
-
-               exfat_delete_dir_entry(sb, p_dir, oldentry, 0,
-                                      num_old_entries);
-               fid->entry = newentry;
-       } else {
-               if (exfat_get_entry_type(epold) == TYPE_FILE) {
-                       exfat_set_entry_attr(epold,
-                                            exfat_get_entry_attr(epold) |
-                                            ATTR_ARCHIVE);
-                       fid->attr |= ATTR_ARCHIVE;
-               }
-               exfat_buf_modify(sb, sector_old);
-               exfat_buf_unlock(sb, sector_old);
-
-               ret = exfat_init_ext_entry(sb, p_dir, oldentry,
-                                          num_new_entries, p_uniname,
-                                          &dos_name);
-               if (ret != 0)
-                       return ret;
-
-               exfat_delete_dir_entry(sb, p_dir, oldentry, num_new_entries,
-                                      num_old_entries);
-       }
-
-       return 0;
-}
-
-s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry,
-             struct chain_t *p_newdir, struct uni_name_t *p_uniname,
-             struct file_id_t *fid)
-{
-       s32 ret, newentry, num_new_entries, num_old_entries;
-       sector_t sector_mov, sector_new;
-       struct dos_name_t dos_name;
-       struct dentry_t *epmov, *epnew;
-       struct super_block *sb = inode->i_sb;
-
-       epmov = get_entry_in_dir(sb, p_olddir, oldentry, &sector_mov);
-       if (!epmov)
-               return -ENOENT;
-
-       /* check if the source and target directory is the same */
-       if (exfat_get_entry_type(epmov) == TYPE_DIR &&
-           exfat_get_entry_clu0(epmov) == p_newdir->dir)
-               return -EINVAL;
-
-       exfat_buf_lock(sb, sector_mov);
-
-       /* exfat_buf_lock() before call count_ext_entries() */
-       num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry,
-                                                 epmov);
-       if (num_old_entries < 0) {
-               exfat_buf_unlock(sb, sector_mov);
-               return -ENOENT;
-       }
-       num_old_entries++;
-
-       ret = get_num_entries_and_dos_name(sb, p_newdir, p_uniname,
-                                          &num_new_entries, &dos_name);
-       if (ret) {
-               exfat_buf_unlock(sb, sector_mov);
-               return ret;
-       }
-
-       newentry = find_empty_entry(inode, p_newdir, num_new_entries);
-       if (newentry < 0) {
-               exfat_buf_unlock(sb, sector_mov);
-               return -ENOSPC;
-       }
-
-       epnew = get_entry_in_dir(sb, p_newdir, newentry, &sector_new);
-       if (!epnew) {
-               exfat_buf_unlock(sb, sector_mov);
-               return -ENOENT;
-       }
-
-       memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE);
-       if (exfat_get_entry_type(epnew) == TYPE_FILE) {
-               exfat_set_entry_attr(epnew, exfat_get_entry_attr(epnew) |
-                                    ATTR_ARCHIVE);
-               fid->attr |= ATTR_ARCHIVE;
-       }
-       exfat_buf_modify(sb, sector_new);
-       exfat_buf_unlock(sb, sector_mov);
-
-       epmov = get_entry_in_dir(sb, p_olddir, oldentry + 1,
-                                &sector_mov);
-       exfat_buf_lock(sb, sector_mov);
-       epnew = get_entry_in_dir(sb, p_newdir, newentry + 1,
-                                &sector_new);
-       if (!epmov || !epnew) {
-               exfat_buf_unlock(sb, sector_mov);
-               return -ENOENT;
-       }
-
-       memcpy((void *)epnew, (void *)epmov, DENTRY_SIZE);
-       exfat_buf_modify(sb, sector_new);
-       exfat_buf_unlock(sb, sector_mov);
-
-       ret = exfat_init_ext_entry(sb, p_newdir, newentry, num_new_entries,
-                                  p_uniname, &dos_name);
-       if (ret != 0)
-               return ret;
-
-       exfat_delete_dir_entry(sb, p_olddir, oldentry, 0, num_old_entries);
-
-       fid->dir.dir = p_newdir->dir;
-       fid->dir.size = p_newdir->size;
-       fid->dir.flags = p_newdir->flags;
-
-       fid->entry = newentry;
-
-       return 0;
-}
-
-/*
- *  Sector Read/Write Functions
- */
-
-int sector_read(struct super_block *sb, sector_t sec, struct buffer_head **bh,
-               bool read)
-{
-       s32 ret = -EIO;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if ((sec >= (p_fs->PBR_sector + p_fs->num_sectors)) &&
-           (p_fs->num_sectors > 0)) {
-               pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n",
-                      __func__, (unsigned long long)sec);
-               fs_error(sb);
-               return ret;
-       }
-
-       if (!p_fs->dev_ejected) {
-               ret = exfat_bdev_read(sb, sec, bh, 1, read);
-               if (ret != 0)
-                       p_fs->dev_ejected = 1;
-       }
-
-       return ret;
-}
-
-int sector_write(struct super_block *sb, sector_t sec, struct buffer_head *bh,
-                bool sync)
-{
-       s32 ret = -EIO;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (sec >= (p_fs->PBR_sector + p_fs->num_sectors) &&
-           (p_fs->num_sectors > 0)) {
-               pr_err("[EXFAT] %s: out of range error! (sec = %llu)\n",
-                      __func__, (unsigned long long)sec);
-               fs_error(sb);
-               return ret;
-       }
-
-       if (!bh) {
-               pr_err("[EXFAT] %s: bh is NULL!\n", __func__);
-               fs_error(sb);
-               return ret;
-       }
-
-       if (!p_fs->dev_ejected) {
-               ret = exfat_bdev_write(sb, sec, bh, 1, sync);
-               if (ret != 0)
-                       p_fs->dev_ejected = 1;
-       }
-
-       return ret;
-}
-
-int multi_sector_read(struct super_block *sb, sector_t sec,
-                     struct buffer_head **bh, s32 num_secs, bool read)
-{
-       s32 ret = -EIO;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors)) &&
-           (p_fs->num_sectors > 0)) {
-               pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n",
-                      __func__, (unsigned long long)sec, num_secs);
-               fs_error(sb);
-               return ret;
-       }
-
-       if (!p_fs->dev_ejected) {
-               ret = exfat_bdev_read(sb, sec, bh, num_secs, read);
-               if (ret != 0)
-                       p_fs->dev_ejected = 1;
-       }
-
-       return ret;
-}
-
-int multi_sector_write(struct super_block *sb, sector_t sec,
-                      struct buffer_head *bh, s32 num_secs, bool sync)
-{
-       s32 ret = -EIO;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if ((sec + num_secs) > (p_fs->PBR_sector + p_fs->num_sectors) &&
-           (p_fs->num_sectors > 0)) {
-               pr_err("[EXFAT] %s: out of range error! (sec = %llu, num_secs = %d)\n",
-                      __func__, (unsigned long long)sec, num_secs);
-               fs_error(sb);
-               return ret;
-       }
-       if (!bh) {
-               pr_err("[EXFAT] %s: bh is NULL!\n", __func__);
-               fs_error(sb);
-               return ret;
-       }
-
-       if (!p_fs->dev_ejected) {
-               ret = exfat_bdev_write(sb, sec, bh, num_secs, sync);
-               if (ret != 0)
-                       p_fs->dev_ejected = 1;
-       }
-
-       return ret;
-}
diff --git a/drivers/staging/exfat/exfat_nls.c b/drivers/staging/exfat/exfat_nls.c
deleted file mode 100644 (file)
index 91e8b0c..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
- */
-
-#include <linux/string.h>
-#include <linux/nls.h>
-#include "exfat.h"
-
-static u16 bad_uni_chars[] = {
-       /* " * / : < > ? \ | */
-       0x0022,         0x002A, 0x002F, 0x003A,
-       0x003C, 0x003E, 0x003F, 0x005C, 0x007C,
-       0
-};
-
-static int convert_ch_to_uni(struct nls_table *nls, u16 *uni, u8 *ch,
-                            bool *lossy)
-{
-       int len;
-
-       *uni = 0x0;
-
-       if (ch[0] < 0x80) {
-               *uni = (u16)ch[0];
-               return 1;
-       }
-
-       len = nls->char2uni(ch, NLS_MAX_CHARSET_SIZE, uni);
-       if (len < 0) {
-               /* conversion failed */
-               pr_info("%s: fail to use nls\n", __func__);
-               if (lossy)
-                       *lossy = true;
-               *uni = (u16)'_';
-               if (!strcmp(nls->charset, "utf8"))
-                       return 1;
-               else
-                       return 2;
-       }
-
-       return len;
-}
-
-static int convert_uni_to_ch(struct nls_table *nls, u8 *ch, u16 uni,
-                            bool *lossy)
-{
-       int len;
-
-       ch[0] = 0x0;
-
-       if (uni < 0x0080) {
-               ch[0] = (u8)uni;
-               return 1;
-       }
-
-       len = nls->uni2char(uni, ch, NLS_MAX_CHARSET_SIZE);
-       if (len < 0) {
-               /* conversion failed */
-               pr_info("%s: fail to use nls\n", __func__);
-               if (lossy)
-                       *lossy = true;
-               ch[0] = '_';
-               return 1;
-       }
-
-       return len;
-}
-
-u16 nls_upper(struct super_block *sb, u16 a)
-{
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       if (EXFAT_SB(sb)->options.casesensitive)
-               return a;
-       if (p_fs->vol_utbl && p_fs->vol_utbl[get_col_index(a)])
-               return p_fs->vol_utbl[get_col_index(a)][get_row_index(a)];
-       else
-               return a;
-}
-
-static u16 *nls_wstrchr(u16 *str, u16 wchar)
-{
-       while (*str) {
-               if (*(str++) == wchar)
-                       return str;
-       }
-
-       return NULL;
-}
-
-int nls_uniname_cmp(struct super_block *sb, u16 *a, u16 *b)
-{
-       int i;
-
-       for (i = 0; i < MAX_NAME_LENGTH; i++, a++, b++) {
-               if (nls_upper(sb, *a) != nls_upper(sb, *b))
-                       return 1;
-               if (*a == 0x0)
-                       return 0;
-       }
-       return 0;
-}
-
-void nls_uniname_to_cstring(struct super_block *sb, u8 *p_cstring,
-                           struct uni_name_t *p_uniname)
-{
-       int i, j, len;
-       u8 buf[MAX_CHARSET_SIZE];
-       u16 *uniname = p_uniname->name;
-       struct nls_table *nls = EXFAT_SB(sb)->nls_io;
-
-       if (!nls) {
-               len = utf16s_to_utf8s(uniname, MAX_NAME_LENGTH,
-                                     UTF16_HOST_ENDIAN, p_cstring,
-                                     MAX_NAME_LENGTH);
-               p_cstring[len] = 0;
-               return;
-       }
-
-       i = 0;
-       while (i < (MAX_NAME_LENGTH - 1)) {
-               if (*uniname == (u16)'\0')
-                       break;
-
-               len = convert_uni_to_ch(nls, buf, *uniname, NULL);
-
-               if (len > 1) {
-                       for (j = 0; j < len; j++)
-                               *p_cstring++ = (char)*(buf + j);
-               } else { /* len == 1 */
-                       *p_cstring++ = (char)*buf;
-               }
-
-               uniname++;
-               i++;
-       }
-
-       *p_cstring = '\0';
-}
-
-void nls_cstring_to_uniname(struct super_block *sb,
-                           struct uni_name_t *p_uniname, u8 *p_cstring,
-                           bool *p_lossy)
-{
-       int i, j;
-       bool lossy = false;
-       u8 *end_of_name;
-       u8 upname[MAX_NAME_LENGTH * 2];
-       u16 *uniname = p_uniname->name;
-       struct nls_table *nls = EXFAT_SB(sb)->nls_io;
-
-       /* strip all trailing spaces */
-       end_of_name = p_cstring + strlen(p_cstring);
-
-       while (*(--end_of_name) == ' ') {
-               if (end_of_name < p_cstring)
-                       break;
-       }
-       *(++end_of_name) = '\0';
-
-       if (strcmp(p_cstring, ".") && strcmp(p_cstring, "..")) {
-               /* strip all trailing periods */
-               while (*(--end_of_name) == '.') {
-                       if (end_of_name < p_cstring)
-                               break;
-               }
-               *(++end_of_name) = '\0';
-       }
-
-       if (*p_cstring == '\0')
-               lossy = true;
-
-       if (!nls) {
-               i = utf8s_to_utf16s(p_cstring, MAX_NAME_LENGTH,
-                                   UTF16_HOST_ENDIAN, uniname,
-                                   MAX_NAME_LENGTH);
-               for (j = 0; j < i; j++)
-                       SET16_A(upname + j * 2, nls_upper(sb, uniname[j]));
-               uniname[i] = '\0';
-       } else {
-               i = 0;
-               j = 0;
-               while (j < (MAX_NAME_LENGTH - 1)) {
-                       if (*(p_cstring + i) == '\0')
-                               break;
-
-                       i += convert_ch_to_uni(nls, uniname,
-                                              (u8 *)(p_cstring + i), &lossy);
-
-                       if ((*uniname < 0x0020) ||
-                           nls_wstrchr(bad_uni_chars, *uniname))
-                               lossy = true;
-
-                       SET16_A(upname + j * 2, nls_upper(sb, *uniname));
-
-                       uniname++;
-                       j++;
-               }
-
-               if (*(p_cstring + i) != '\0')
-                       lossy = true;
-               *uniname = (u16)'\0';
-       }
-
-       p_uniname->name_len = j;
-       p_uniname->name_hash = calc_checksum_2byte(upname, j << 1, 0,
-                                                  CS_DEFAULT);
-
-       if (p_lossy)
-               *p_lossy = lossy;
-}
diff --git a/drivers/staging/exfat/exfat_super.c b/drivers/staging/exfat/exfat_super.c
deleted file mode 100644 (file)
index b81d2a8..0000000
+++ /dev/null
@@ -1,3883 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/seq_file.h>
-#include <linux/pagemap.h>
-#include <linux/mpage.h>
-#include <linux/buffer_head.h>
-#include <linux/exportfs.h>
-#include <linux/mount.h>
-#include <linux/vfs.h>
-#include <linux/aio.h>
-#include <linux/iversion.h>
-#include <linux/parser.h>
-#include <linux/uio.h>
-#include <linux/writeback.h>
-#include <linux/log2.h>
-#include <linux/hash.h>
-#include <linux/backing-dev.h>
-#include <linux/sched.h>
-#include <linux/fs_struct.h>
-#include <linux/namei.h>
-#include <linux/random.h>
-#include <linux/string.h>
-#include <linux/nls.h>
-#include <linux/mutex.h>
-#include <linux/swap.h>
-
-#define EXFAT_VERSION  "1.3.0"
-
-#include "exfat.h"
-
-static struct kmem_cache *exfat_inode_cachep;
-
-static int exfat_default_codepage = CONFIG_STAGING_EXFAT_DEFAULT_CODEPAGE;
-static char exfat_default_iocharset[] = CONFIG_STAGING_EXFAT_DEFAULT_IOCHARSET;
-
-#define INC_IVERSION(x) (inode_inc_iversion(x))
-#define GET_IVERSION(x) (inode_peek_iversion_raw(x))
-#define SET_IVERSION(x, y) (inode_set_iversion(x, y))
-
-static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos);
-static int exfat_sync_inode(struct inode *inode);
-static struct inode *exfat_build_inode(struct super_block *sb,
-                                      struct file_id_t *fid, loff_t i_pos);
-static int exfat_write_inode(struct inode *inode,
-                            struct writeback_control *wbc);
-static void exfat_write_super(struct super_block *sb);
-
-#define UNIX_SECS_1980    315532800L
-#define UNIX_SECS_2108    4354819200L
-
-/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
-static void exfat_time_fat2unix(struct timespec64 *ts, struct date_time_t *tp)
-{
-       ts->tv_sec = mktime64(tp->Year + 1980, tp->Month + 1, tp->Day,
-                             tp->Hour, tp->Minute, tp->Second);
-
-       ts->tv_nsec = tp->MilliSecond * NSEC_PER_MSEC;
-}
-
-/* Convert linear UNIX date to a FAT time/date pair. */
-static void exfat_time_unix2fat(struct timespec64 *ts, struct date_time_t *tp)
-{
-       time64_t second = ts->tv_sec;
-       struct tm tm;
-
-       time64_to_tm(second, 0, &tm);
-
-       if (second < UNIX_SECS_1980) {
-               tp->MilliSecond = 0;
-               tp->Second      = 0;
-               tp->Minute      = 0;
-               tp->Hour        = 0;
-               tp->Day         = 1;
-               tp->Month       = 1;
-               tp->Year        = 0;
-               return;
-       }
-
-       if (second >= UNIX_SECS_2108) {
-               tp->MilliSecond = 999;
-               tp->Second      = 59;
-               tp->Minute      = 59;
-               tp->Hour        = 23;
-               tp->Day         = 31;
-               tp->Month       = 12;
-               tp->Year        = 127;
-               return;
-       }
-
-       tp->MilliSecond = ts->tv_nsec / NSEC_PER_MSEC;
-       tp->Second      = tm.tm_sec;
-       tp->Minute      = tm.tm_min;
-       tp->Hour        = tm.tm_hour;
-       tp->Day         = tm.tm_mday;
-       tp->Month       = tm.tm_mon + 1;
-       tp->Year        = tm.tm_year + 1900 - 1980;
-}
-
-struct timestamp_t *tm_current(struct timestamp_t *tp)
-{
-       time64_t second = ktime_get_real_seconds();
-       struct tm tm;
-
-       time64_to_tm(second, 0, &tm);
-
-       if (second < UNIX_SECS_1980) {
-               tp->sec  = 0;
-               tp->min  = 0;
-               tp->hour = 0;
-               tp->day  = 1;
-               tp->mon  = 1;
-               tp->year = 0;
-               return tp;
-       }
-
-       if (second >= UNIX_SECS_2108) {
-               tp->sec  = 59;
-               tp->min  = 59;
-               tp->hour = 23;
-               tp->day  = 31;
-               tp->mon  = 12;
-               tp->year = 127;
-               return tp;
-       }
-
-       tp->sec  = tm.tm_sec;
-       tp->min  = tm.tm_min;
-       tp->hour = tm.tm_hour;
-       tp->day  = tm.tm_mday;
-       tp->mon  = tm.tm_mon + 1;
-       tp->year = tm.tm_year + 1900 - 1980;
-
-       return tp;
-}
-
-static void __lock_super(struct super_block *sb)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-
-       mutex_lock(&sbi->s_lock);
-}
-
-static void __unlock_super(struct super_block *sb)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-
-       mutex_unlock(&sbi->s_lock);
-}
-
-static int __is_sb_dirty(struct super_block *sb)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-
-       return sbi->s_dirt;
-}
-
-static void __set_sb_clean(struct super_block *sb)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-
-       sbi->s_dirt = 0;
-}
-
-static int __exfat_revalidate(struct dentry *dentry)
-{
-       return 0;
-}
-
-static int exfat_revalidate(struct dentry *dentry, unsigned int flags)
-{
-       if (flags & LOOKUP_RCU)
-               return -ECHILD;
-
-       if (dentry->d_inode)
-               return 1;
-       return __exfat_revalidate(dentry);
-}
-
-static int exfat_revalidate_ci(struct dentry *dentry, unsigned int flags)
-{
-       if (flags & LOOKUP_RCU)
-               return -ECHILD;
-
-       if (dentry->d_inode)
-               return 1;
-
-       if (!flags)
-               return 0;
-
-       if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
-               return 0;
-
-       return __exfat_revalidate(dentry);
-}
-
-static unsigned int __exfat_striptail_len(unsigned int len, const char *name)
-{
-       while (len && name[len - 1] == '.')
-               len--;
-       return len;
-}
-
-static unsigned int exfat_striptail_len(const struct qstr *qstr)
-{
-       return __exfat_striptail_len(qstr->len, qstr->name);
-}
-
-static int exfat_d_hash(const struct dentry *dentry, struct qstr *qstr)
-{
-       qstr->hash = full_name_hash(dentry, qstr->name,
-                                   exfat_striptail_len(qstr));
-       return 0;
-}
-
-static int exfat_d_hashi(const struct dentry *dentry, struct qstr *qstr)
-{
-       struct super_block *sb = dentry->d_sb;
-       const unsigned char *name;
-       unsigned int len;
-       unsigned long hash;
-
-       name = qstr->name;
-       len = exfat_striptail_len(qstr);
-
-       hash = init_name_hash(dentry);
-       while (len--)
-               hash = partial_name_hash(nls_upper(sb, *name++), hash);
-       qstr->hash = end_name_hash(hash);
-
-       return 0;
-}
-
-static int exfat_cmpi(const struct dentry *dentry, unsigned int len,
-                     const char *str, const struct qstr *name)
-{
-       struct nls_table *t = EXFAT_SB(dentry->d_sb)->nls_io;
-       unsigned int alen, blen;
-
-       alen = exfat_striptail_len(name);
-       blen = __exfat_striptail_len(len, str);
-       if (alen == blen) {
-               if (!t) {
-                       if (strncasecmp(name->name, str, alen) == 0)
-                               return 0;
-               } else {
-                       if (nls_strnicmp(t, name->name, str, alen) == 0)
-                               return 0;
-               }
-       }
-       return 1;
-}
-
-static int exfat_cmp(const struct dentry *dentry, unsigned int len,
-                    const char *str, const struct qstr *name)
-{
-       unsigned int alen, blen;
-
-       alen = exfat_striptail_len(name);
-       blen = __exfat_striptail_len(len, str);
-       if (alen == blen) {
-               if (strncmp(name->name, str, alen) == 0)
-                       return 0;
-       }
-       return 1;
-}
-
-static const struct dentry_operations exfat_ci_dentry_ops = {
-       .d_revalidate   = exfat_revalidate_ci,
-       .d_hash         = exfat_d_hashi,
-       .d_compare      = exfat_cmpi,
-};
-
-static const struct dentry_operations exfat_dentry_ops = {
-       .d_revalidate   = exfat_revalidate,
-       .d_hash         = exfat_d_hash,
-       .d_compare      = exfat_cmp,
-};
-
-static DEFINE_MUTEX(z_mutex);
-
-static inline void fs_sync(struct super_block *sb, bool do_sync)
-{
-       if (do_sync)
-               exfat_bdev_sync(sb);
-}
-
-/*
- * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to
- * save ATTR_RO instead of ->i_mode.
- *
- * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only
- * bit, it's just used as flag for app.
- */
-static inline int exfat_mode_can_hold_ro(struct inode *inode)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
-
-       if (S_ISDIR(inode->i_mode))
-               return 0;
-
-       if ((~sbi->options.fs_fmask) & 0222)
-               return 1;
-       return 0;
-}
-
-/* Convert attribute bits and a mask to the UNIX mode. */
-static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi, u32 attr,
-                                    mode_t mode)
-{
-       if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR))
-               mode &= ~0222;
-
-       if (attr & ATTR_SUBDIR)
-               return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
-       else if (attr & ATTR_SYMLINK)
-               return (mode & ~sbi->options.fs_dmask) | S_IFLNK;
-       else
-               return (mode & ~sbi->options.fs_fmask) | S_IFREG;
-}
-
-/* Return the FAT attribute byte for this inode */
-static inline u32 exfat_make_attr(struct inode *inode)
-{
-       if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222))
-               return (EXFAT_I(inode)->fid.attr) | ATTR_READONLY;
-       else
-               return EXFAT_I(inode)->fid.attr;
-}
-
-static inline void exfat_save_attr(struct inode *inode, u32 attr)
-{
-       if (exfat_mode_can_hold_ro(inode))
-               EXFAT_I(inode)->fid.attr = attr & ATTR_RWMASK;
-       else
-               EXFAT_I(inode)->fid.attr = attr & (ATTR_RWMASK | ATTR_READONLY);
-}
-
-static int ffsMountVol(struct super_block *sb)
-{
-       int i, ret;
-       struct pbr_sector_t *p_pbr;
-       struct buffer_head *tmp_bh = NULL;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       pr_info("[EXFAT] trying to mount...\n");
-
-       mutex_lock(&z_mutex);
-
-       exfat_buf_init(sb);
-
-       mutex_init(&p_fs->v_mutex);
-       p_fs->dev_ejected = 0;
-
-       /* open the block device */
-       exfat_bdev_open(sb);
-
-       if (p_bd->sector_size < sb->s_blocksize) {
-               printk(KERN_INFO "EXFAT: mount failed - sector size %d less than blocksize %ld\n",
-                      p_bd->sector_size,  sb->s_blocksize);
-               ret = -EINVAL;
-               goto out;
-       }
-       if (p_bd->sector_size > sb->s_blocksize)
-               sb_set_blocksize(sb, p_bd->sector_size);
-
-       /* read Sector 0 */
-       if (sector_read(sb, 0, &tmp_bh, 1) != 0) {
-               ret = -EIO;
-               goto out;
-       }
-
-       p_fs->PBR_sector = 0;
-
-       p_pbr = (struct pbr_sector_t *)tmp_bh->b_data;
-
-       /* check the validity of PBR */
-       if (GET16_A(p_pbr->signature) != PBR_SIGNATURE) {
-               brelse(tmp_bh);
-               exfat_bdev_close(sb);
-               ret = -EFSCORRUPTED;
-               goto out;
-       }
-
-       /* fill fs_struct */
-       for (i = 0; i < 53; i++)
-               if (p_pbr->bpb[i])
-                       break;
-
-       if (i < 53) {
-               /* Not sure how we'd get here, but complain if it does */
-               ret = -EINVAL;
-               pr_info("EXFAT: Attempted to mount VFAT filesystem\n");
-               goto out;
-       } else {
-               ret = exfat_mount(sb, p_pbr);
-       }
-
-       brelse(tmp_bh);
-
-       if (ret) {
-               exfat_bdev_close(sb);
-               goto out;
-       }
-
-       ret = load_alloc_bitmap(sb);
-       if (ret) {
-               exfat_bdev_close(sb);
-               goto out;
-       }
-       ret = load_upcase_table(sb);
-       if (ret) {
-               free_alloc_bitmap(sb);
-               exfat_bdev_close(sb);
-               goto out;
-       }
-
-       if (p_fs->dev_ejected) {
-               free_upcase_table(sb);
-               free_alloc_bitmap(sb);
-               exfat_bdev_close(sb);
-               ret = -EIO;
-               goto out;
-       }
-
-       pr_info("[EXFAT] mounted successfully\n");
-
-out:
-       mutex_unlock(&z_mutex);
-
-       return ret;
-}
-
-static int ffsUmountVol(struct super_block *sb)
-{
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       int err = 0;
-
-       pr_info("[EXFAT] trying to unmount...\n");
-
-       mutex_lock(&z_mutex);
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-
-       free_upcase_table(sb);
-       free_alloc_bitmap(sb);
-
-       exfat_fat_release_all(sb);
-       exfat_buf_release_all(sb);
-
-       /* close the block device */
-       exfat_bdev_close(sb);
-
-       if (p_fs->dev_ejected) {
-               pr_info("[EXFAT] unmounted with media errors. Device is already ejected.\n");
-               err = -EIO;
-       }
-
-       exfat_buf_shutdown(sb);
-
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-       mutex_unlock(&z_mutex);
-
-       pr_info("[EXFAT] unmounted successfully\n");
-
-       return err;
-}
-
-static int ffsGetVolInfo(struct super_block *sb, struct vol_info_t *info)
-{
-       int err = 0;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       /* check the validity of pointer parameters */
-       if (!info)
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       if (p_fs->used_clusters == UINT_MAX)
-               p_fs->used_clusters = exfat_count_used_clusters(sb);
-
-       info->FatType = p_fs->vol_type;
-       info->ClusterSize = p_fs->cluster_size;
-       info->NumClusters = p_fs->num_clusters - 2; /* clu 0 & 1 */
-       info->UsedClusters = p_fs->used_clusters;
-       info->FreeClusters = info->NumClusters - info->UsedClusters;
-
-       if (p_fs->dev_ejected)
-               err = -EIO;
-
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return err;
-}
-
-static int ffsSyncVol(struct super_block *sb, bool do_sync)
-{
-       int err = 0;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       /* synchronize the file system */
-       fs_sync(sb, do_sync);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-
-       if (p_fs->dev_ejected)
-               err = -EIO;
-
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return err;
-}
-
-/*----------------------------------------------------------------------*/
-/*  File Operation Functions                                            */
-/*----------------------------------------------------------------------*/
-
-static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid)
-{
-       int ret, dentry, num_entries;
-       struct chain_t dir;
-       struct uni_name_t uni_name;
-       struct dos_name_t dos_name;
-       struct dentry_t *ep, *ep2;
-       struct entry_set_cache_t *es = NULL;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       pr_debug("%s entered\n", __func__);
-
-       /* check the validity of pointer parameters */
-       if (!fid || !path || (*path == '\0'))
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       /* check the validity of directory name in the given pathname */
-       ret = resolve_path(inode, path, &dir, &uni_name);
-       if (ret)
-               goto out;
-
-       ret = get_num_entries_and_dos_name(sb, &dir, &uni_name, &num_entries,
-                                          &dos_name);
-       if (ret)
-               goto out;
-
-       /* search the file name for directories */
-       dentry = exfat_find_dir_entry(sb, &dir, &uni_name, num_entries,
-                                     &dos_name, TYPE_ALL);
-       if (dentry < -1) {
-               ret = -ENOENT;
-               goto out;
-       }
-
-       fid->dir.dir = dir.dir;
-       fid->dir.size = dir.size;
-       fid->dir.flags = dir.flags;
-       fid->entry = dentry;
-
-       if (dentry == -1) {
-               fid->type = TYPE_DIR;
-               fid->rwoffset = 0;
-               fid->hint_last_off = -1;
-
-               fid->attr = ATTR_SUBDIR;
-               fid->flags = 0x01;
-               fid->size = 0;
-               fid->start_clu = p_fs->root_dir;
-       } else {
-               es = get_entry_set_in_dir(sb, &dir, dentry,
-                                         ES_2_ENTRIES, &ep);
-               if (!es) {
-                       ret =  -ENOENT;
-                       goto out;
-               }
-               ep2 = ep + 1;
-
-               fid->type = exfat_get_entry_type(ep);
-               fid->rwoffset = 0;
-               fid->hint_last_off = -1;
-               fid->attr = exfat_get_entry_attr(ep);
-
-               fid->size = exfat_get_entry_size(ep2);
-               if ((fid->type == TYPE_FILE) && (fid->size == 0)) {
-                       fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
-                       fid->start_clu = CLUSTER_32(~0);
-               } else {
-                       fid->flags = exfat_get_entry_flag(ep2);
-                       fid->start_clu = exfat_get_entry_clu0(ep2);
-               }
-
-               release_entry_set(es);
-       }
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-static int ffsCreateFile(struct inode *inode, char *path, u8 mode,
-                        struct file_id_t *fid)
-{
-       struct chain_t dir;
-       struct uni_name_t uni_name;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       int ret = 0;
-
-       /* check the validity of pointer parameters */
-       if (!fid || !path || (*path == '\0'))
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       /* check the validity of directory name in the given pathname */
-       ret = resolve_path(inode, path, &dir, &uni_name);
-       if (ret)
-               goto out;
-
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       /* create a new file */
-       ret = create_file(inode, &dir, &uni_name, mode, fid);
-
-#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-#endif
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-static int ffsReadFile(struct inode *inode, struct file_id_t *fid, void *buffer,
-                      u64 count, u64 *rcount)
-{
-       s32 offset, sec_offset, clu_offset;
-       u32 clu;
-       int ret = 0;
-       sector_t LogSector;
-       u64 oneblkread, read_bytes;
-       struct buffer_head *tmp_bh = NULL;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       /* check the validity of the given file id */
-       if (!fid)
-               return -EINVAL;
-
-       /* check the validity of pointer parameters */
-       if (!buffer)
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       /* check if the given file ID is opened */
-       if (fid->type != TYPE_FILE) {
-               ret = -EPERM;
-               goto out;
-       }
-
-       if (fid->rwoffset > fid->size)
-               fid->rwoffset = fid->size;
-
-       if (count > (fid->size - fid->rwoffset))
-               count = fid->size - fid->rwoffset;
-
-       if (count == 0) {
-               if (rcount)
-                       *rcount = 0;
-               ret = 0;
-               goto out;
-       }
-
-       read_bytes = 0;
-
-       while (count > 0) {
-               clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits);
-               clu = fid->start_clu;
-
-               if (fid->flags == 0x03) {
-                       clu += clu_offset;
-               } else {
-                       /* hint information */
-                       if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
-                           (clu_offset >= fid->hint_last_off)) {
-                               clu_offset -= fid->hint_last_off;
-                               clu = fid->hint_last_clu;
-                       }
-
-                       while (clu_offset > 0) {
-                               /* clu = exfat_fat_read(sb, clu); */
-                               if (exfat_fat_read(sb, clu, &clu) == -1) {
-                                       ret = -EIO;
-                                       goto out;
-                               }
-
-                               clu_offset--;
-                       }
-               }
-
-               /* hint information */
-               fid->hint_last_off = (s32)(fid->rwoffset >>
-                                          p_fs->cluster_size_bits);
-               fid->hint_last_clu = clu;
-
-               /* byte offset in cluster */
-               offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1));
-
-               /* sector offset in cluster */
-               sec_offset = offset >> p_bd->sector_size_bits;
-
-               /* byte offset in sector */
-               offset &= p_bd->sector_size_mask;
-
-               LogSector = START_SECTOR(clu) + sec_offset;
-
-               oneblkread = (u64)(p_bd->sector_size - offset);
-               if (oneblkread > count)
-                       oneblkread = count;
-
-               if ((offset == 0) && (oneblkread == p_bd->sector_size)) {
-                       if (sector_read(sb, LogSector, &tmp_bh, 1) !=
-                           0)
-                               goto err_out;
-                       memcpy((char *)buffer + read_bytes,
-                              (char *)tmp_bh->b_data, (s32)oneblkread);
-               } else {
-                       if (sector_read(sb, LogSector, &tmp_bh, 1) !=
-                           0)
-                               goto err_out;
-                       memcpy((char *)buffer + read_bytes,
-                              (char *)tmp_bh->b_data + offset,
-                              (s32)oneblkread);
-               }
-               count -= oneblkread;
-               read_bytes += oneblkread;
-               fid->rwoffset += oneblkread;
-       }
-       brelse(tmp_bh);
-
-/* How did this ever work and not leak a brlse()?? */
-err_out:
-       /* set the size of read bytes */
-       if (rcount)
-               *rcount = read_bytes;
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-static int ffsWriteFile(struct inode *inode, struct file_id_t *fid,
-                       void *buffer, u64 count, u64 *wcount)
-{
-       bool modified = false;
-       s32 offset, sec_offset, clu_offset;
-       s32 num_clusters, num_alloc, num_alloced = (s32)~0;
-       int ret = 0;
-       u32 clu, last_clu;
-       sector_t LogSector;
-       u64 oneblkwrite, write_bytes;
-       struct chain_t new_clu;
-       struct timestamp_t tm;
-       struct dentry_t *ep, *ep2;
-       struct entry_set_cache_t *es = NULL;
-       struct buffer_head *tmp_bh = NULL;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-
-       /* check the validity of the given file id */
-       if (!fid)
-               return -EINVAL;
-
-       /* check the validity of pointer parameters */
-       if (!buffer)
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       /* check if the given file ID is opened */
-       if (fid->type != TYPE_FILE) {
-               ret = -EPERM;
-               goto out;
-       }
-
-       if (fid->rwoffset > fid->size)
-               fid->rwoffset = fid->size;
-
-       if (count == 0) {
-               if (wcount)
-                       *wcount = 0;
-               ret = 0;
-               goto out;
-       }
-
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       if (fid->size == 0)
-               num_clusters = 0;
-       else
-               num_clusters = (s32)((fid->size - 1) >>
-                                    p_fs->cluster_size_bits) + 1;
-
-       write_bytes = 0;
-
-       while (count > 0) {
-               clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits);
-               clu = fid->start_clu;
-               last_clu = fid->start_clu;
-
-               if (fid->flags == 0x03) {
-                       if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) {
-                               last_clu += clu_offset - 1;
-
-                               if (clu_offset == num_clusters)
-                                       clu = CLUSTER_32(~0);
-                               else
-                                       clu += clu_offset;
-                       }
-               } else {
-                       /* hint information */
-                       if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
-                           (clu_offset >= fid->hint_last_off)) {
-                               clu_offset -= fid->hint_last_off;
-                               clu = fid->hint_last_clu;
-                       }
-
-                       while ((clu_offset > 0) && (clu != CLUSTER_32(~0))) {
-                               last_clu = clu;
-                               /* clu = exfat_fat_read(sb, clu); */
-                               if (exfat_fat_read(sb, clu, &clu) == -1) {
-                                       ret = -EIO;
-                                       goto out;
-                               }
-                               clu_offset--;
-                       }
-               }
-
-               if (clu == CLUSTER_32(~0)) {
-                       num_alloc = (s32)((count - 1) >>
-                                         p_fs->cluster_size_bits) + 1;
-                       new_clu.dir = (last_clu == CLUSTER_32(~0)) ?
-                                       CLUSTER_32(~0) : last_clu + 1;
-                       new_clu.size = 0;
-                       new_clu.flags = fid->flags;
-
-                       /* (1) allocate a chain of clusters */
-                       num_alloced = exfat_alloc_cluster(sb,
-                                                         num_alloc,
-                                                         &new_clu);
-                       if (num_alloced == 0)
-                               break;
-                       if (num_alloced < 0) {
-                               ret = num_alloced;
-                               goto out;
-                       }
-
-                       /* (2) append to the FAT chain */
-                       if (last_clu == CLUSTER_32(~0)) {
-                               if (new_clu.flags == 0x01)
-                                       fid->flags = 0x01;
-                               fid->start_clu = new_clu.dir;
-                               modified = true;
-                       } else {
-                               if (new_clu.flags != fid->flags) {
-                                       exfat_chain_cont_cluster(sb,
-                                                                fid->start_clu,
-                                                                num_clusters);
-                                       fid->flags = 0x01;
-                                       modified = true;
-                               }
-                               if (new_clu.flags == 0x01)
-                                       exfat_fat_write(sb, last_clu, new_clu.dir);
-                       }
-
-                       num_clusters += num_alloced;
-                       clu = new_clu.dir;
-               }
-
-               /* hint information */
-               fid->hint_last_off = (s32)(fid->rwoffset >>
-                                          p_fs->cluster_size_bits);
-               fid->hint_last_clu = clu;
-
-               /* byte offset in cluster   */
-               offset = (s32)(fid->rwoffset & (p_fs->cluster_size - 1));
-
-               /* sector offset in cluster */
-               sec_offset = offset >> p_bd->sector_size_bits;
-
-               /* byte offset in sector    */
-               offset &= p_bd->sector_size_mask;
-
-               LogSector = START_SECTOR(clu) + sec_offset;
-
-               oneblkwrite = (u64)(p_bd->sector_size - offset);
-               if (oneblkwrite > count)
-                       oneblkwrite = count;
-
-               if ((offset == 0) && (oneblkwrite == p_bd->sector_size)) {
-                       if (sector_read(sb, LogSector, &tmp_bh, 0) !=
-                           0)
-                               goto err_out;
-                       memcpy((char *)tmp_bh->b_data,
-                              (char *)buffer + write_bytes, (s32)oneblkwrite);
-                       if (sector_write(sb, LogSector, tmp_bh, 0) !=
-                           0) {
-                               brelse(tmp_bh);
-                               goto err_out;
-                       }
-               } else {
-                       if ((offset > 0) ||
-                           ((fid->rwoffset + oneblkwrite) < fid->size)) {
-                               if (sector_read(sb, LogSector, &tmp_bh, 1) !=
-                                   0)
-                                       goto err_out;
-                       } else {
-                               if (sector_read(sb, LogSector, &tmp_bh, 0) !=
-                                   0)
-                                       goto err_out;
-                       }
-
-                       memcpy((char *)tmp_bh->b_data + offset,
-                              (char *)buffer + write_bytes, (s32)oneblkwrite);
-                       if (sector_write(sb, LogSector, tmp_bh, 0) !=
-                           0) {
-                               brelse(tmp_bh);
-                               goto err_out;
-                       }
-               }
-
-               count -= oneblkwrite;
-               write_bytes += oneblkwrite;
-               fid->rwoffset += oneblkwrite;
-
-               fid->attr |= ATTR_ARCHIVE;
-
-               if (fid->size < fid->rwoffset) {
-                       fid->size = fid->rwoffset;
-                       modified = true;
-               }
-       }
-
-       brelse(tmp_bh);
-
-       /* (3) update the direcoty entry */
-       es = get_entry_set_in_dir(sb, &fid->dir, fid->entry,
-                                 ES_ALL_ENTRIES, &ep);
-       if (!es)
-               goto err_out;
-       ep2 = ep + 1;
-
-       exfat_set_entry_time(ep, tm_current(&tm), TM_MODIFY);
-       exfat_set_entry_attr(ep, fid->attr);
-
-       if (modified) {
-               if (exfat_get_entry_flag(ep2) != fid->flags)
-                       exfat_set_entry_flag(ep2, fid->flags);
-
-               if (exfat_get_entry_size(ep2) != fid->size)
-                       exfat_set_entry_size(ep2, fid->size);
-
-               if (exfat_get_entry_clu0(ep2) != fid->start_clu)
-                       exfat_set_entry_clu0(ep2, fid->start_clu);
-       }
-
-       update_dir_checksum_with_entry_set(sb, es);
-       release_entry_set(es);
-
-#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-#endif
-
-err_out:
-       /* set the size of written bytes */
-       if (wcount)
-               *wcount = write_bytes;
-
-       if (num_alloced == 0)
-               ret = -ENOSPC;
-
-       else if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size)
-{
-       s32 num_clusters;
-       u32 last_clu = CLUSTER_32(0);
-       int ret = 0;
-       struct chain_t clu;
-       struct timestamp_t tm;
-       struct dentry_t *ep, *ep2;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-       struct entry_set_cache_t *es = NULL;
-
-       pr_debug("%s entered (inode %p size %llu)\n", __func__, inode,
-                new_size);
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       /* check if the given file ID is opened */
-       if (fid->type != TYPE_FILE) {
-               ret = -EPERM;
-               goto out;
-       }
-
-       if (fid->size != old_size) {
-               pr_err("[EXFAT] truncate : can't skip it because of size-mismatch(old:%lld->fid:%lld).\n",
-                      old_size, fid->size);
-       }
-
-       if (old_size <= new_size) {
-               ret = 0;
-               goto out;
-       }
-
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       clu.dir = fid->start_clu;
-       clu.size = (s32)((old_size - 1) >> p_fs->cluster_size_bits) + 1;
-       clu.flags = fid->flags;
-
-       if (new_size > 0) {
-               num_clusters = (s32)((new_size - 1) >>
-                                    p_fs->cluster_size_bits) + 1;
-
-               if (clu.flags == 0x03) {
-                       clu.dir += num_clusters;
-               } else {
-                       while (num_clusters > 0) {
-                               last_clu = clu.dir;
-                               if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) {
-                                       ret = -EIO;
-                                       goto out;
-                               }
-                               num_clusters--;
-                       }
-               }
-
-               clu.size -= num_clusters;
-       }
-
-       fid->size = new_size;
-       fid->attr |= ATTR_ARCHIVE;
-       if (new_size == 0) {
-               fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
-               fid->start_clu = CLUSTER_32(~0);
-       }
-
-       /* (1) update the directory entry */
-       es = get_entry_set_in_dir(sb, &fid->dir, fid->entry,
-                                 ES_ALL_ENTRIES, &ep);
-       if (!es) {
-               ret = -ENOENT;
-               goto out;
-               }
-       ep2 = ep + 1;
-
-       exfat_set_entry_time(ep, tm_current(&tm), TM_MODIFY);
-       exfat_set_entry_attr(ep, fid->attr);
-
-       exfat_set_entry_size(ep2, new_size);
-       if (new_size == 0) {
-               exfat_set_entry_flag(ep2, 0x01);
-               exfat_set_entry_clu0(ep2, CLUSTER_32(0));
-       }
-
-       update_dir_checksum_with_entry_set(sb, es);
-       release_entry_set(es);
-
-       /* (2) cut off from the FAT chain */
-       if (last_clu != CLUSTER_32(0)) {
-               if (fid->flags == 0x01)
-                       exfat_fat_write(sb, last_clu, CLUSTER_32(~0));
-       }
-
-       /* (3) free the clusters */
-       exfat_free_cluster(sb, &clu, 0);
-
-       /* hint information */
-       fid->hint_last_off = -1;
-       if (fid->rwoffset > fid->size)
-               fid->rwoffset = fid->size;
-
-#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-#endif
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       pr_debug("%s exited (%d)\n", __func__, ret);
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-static void update_parent_info(struct file_id_t *fid,
-                              struct inode *parent_inode)
-{
-       struct fs_info_t *p_fs = &(EXFAT_SB(parent_inode->i_sb)->fs_info);
-       struct file_id_t *parent_fid = &(EXFAT_I(parent_inode)->fid);
-
-       if (unlikely((parent_fid->flags != fid->dir.flags) ||
-                    (parent_fid->size !=
-                     (fid->dir.size << p_fs->cluster_size_bits)) ||
-                    (parent_fid->start_clu != fid->dir.dir))) {
-               fid->dir.dir = parent_fid->start_clu;
-               fid->dir.flags = parent_fid->flags;
-               fid->dir.size = ((parent_fid->size + (p_fs->cluster_size - 1))
-                                               >> p_fs->cluster_size_bits);
-       }
-}
-
-static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid,
-                      struct inode *new_parent_inode, struct dentry *new_dentry)
-{
-       s32 ret;
-       s32 dentry;
-       struct chain_t olddir, newdir;
-       struct chain_t *p_dir = NULL;
-       struct uni_name_t uni_name;
-       struct dentry_t *ep;
-       struct super_block *sb = old_parent_inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       u8 *new_path = (u8 *)new_dentry->d_name.name;
-       struct inode *new_inode = new_dentry->d_inode;
-       int num_entries;
-       struct file_id_t *new_fid = NULL;
-       s32 new_entry = 0;
-
-       /* check the validity of the given file id */
-       if (!fid)
-               return -EINVAL;
-
-       /* check the validity of pointer parameters */
-       if (!new_path || (*new_path == '\0'))
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       update_parent_info(fid, old_parent_inode);
-
-       olddir.dir = fid->dir.dir;
-       olddir.size = fid->dir.size;
-       olddir.flags = fid->dir.flags;
-
-       dentry = fid->entry;
-
-       /* check if the old file is "." or ".." */
-       if (p_fs->vol_type != EXFAT) {
-               if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) {
-                       ret = -EPERM;
-                       goto out2;
-               }
-       }
-
-       ep = get_entry_in_dir(sb, &olddir, dentry, NULL);
-       if (!ep) {
-               ret = -ENOENT;
-               goto out2;
-       }
-
-       if (exfat_get_entry_attr(ep) & ATTR_READONLY) {
-               ret = -EPERM;
-               goto out2;
-       }
-
-       /* check whether new dir is existing directory and empty */
-       if (new_inode) {
-               u32 entry_type;
-
-               ret = -ENOENT;
-               new_fid = &EXFAT_I(new_inode)->fid;
-
-               update_parent_info(new_fid, new_parent_inode);
-
-               p_dir = &new_fid->dir;
-               new_entry = new_fid->entry;
-               ep = get_entry_in_dir(sb, p_dir, new_entry, NULL);
-               if (!ep)
-                       goto out;
-
-               entry_type = exfat_get_entry_type(ep);
-
-               if (entry_type == TYPE_DIR) {
-                       struct chain_t new_clu;
-
-                       new_clu.dir = new_fid->start_clu;
-                       new_clu.size = (s32)((new_fid->size - 1) >>
-                                            p_fs->cluster_size_bits) + 1;
-                       new_clu.flags = new_fid->flags;
-
-                       if (!is_dir_empty(sb, &new_clu)) {
-                               ret = -EEXIST;
-                               goto out;
-                       }
-               }
-       }
-
-       /* check the validity of directory name in the given new pathname */
-       ret = resolve_path(new_parent_inode, new_path, &newdir, &uni_name);
-       if (ret)
-               goto out2;
-
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       if (olddir.dir == newdir.dir)
-               ret = exfat_rename_file(new_parent_inode, &olddir, dentry,
-                                       &uni_name, fid);
-       else
-               ret = move_file(new_parent_inode, &olddir, dentry, &newdir,
-                               &uni_name, fid);
-
-       if ((ret == 0) && new_inode) {
-               /* delete entries of new_dir */
-               ep = get_entry_in_dir(sb, p_dir, new_entry, NULL);
-               if (!ep)
-                       goto out;
-
-               num_entries = exfat_count_ext_entries(sb, p_dir,
-                                                     new_entry, ep);
-               if (num_entries < 0)
-                       goto out;
-               exfat_delete_dir_entry(sb, p_dir, new_entry, 0,
-                                      num_entries + 1);
-       }
-out:
-#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-#endif
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-out2:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid)
-{
-       s32 dentry;
-       int ret = 0;
-       struct chain_t dir, clu_to_free;
-       struct dentry_t *ep;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       /* check the validity of the given file id */
-       if (!fid)
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       dir.dir = fid->dir.dir;
-       dir.size = fid->dir.size;
-       dir.flags = fid->dir.flags;
-
-       dentry = fid->entry;
-
-       ep = get_entry_in_dir(sb, &dir, dentry, NULL);
-       if (!ep) {
-               ret = -ENOENT;
-               goto out;
-       }
-
-       if (exfat_get_entry_attr(ep) & ATTR_READONLY) {
-               ret = -EPERM;
-               goto out;
-       }
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       /* (1) update the directory entry */
-       remove_file(inode, &dir, dentry);
-
-       clu_to_free.dir = fid->start_clu;
-       clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1;
-       clu_to_free.flags = fid->flags;
-
-       /* (2) free the clusters */
-       exfat_free_cluster(sb, &clu_to_free, 0);
-
-       fid->size = 0;
-       fid->start_clu = CLUSTER_32(~0);
-       fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
-
-#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-#endif
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-#if 0
-/* Not currently wired up */
-static int ffsSetAttr(struct inode *inode, u32 attr)
-{
-       u32 type;
-       int ret = 0;
-       sector_t sector = 0;
-       struct dentry_t *ep;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-       u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
-       struct entry_set_cache_t *es = NULL;
-
-       if (fid->attr == attr) {
-               if (p_fs->dev_ejected)
-                       return -EIO;
-               return 0;
-       }
-
-       if (is_dir) {
-               if ((fid->dir.dir == p_fs->root_dir) &&
-                   (fid->entry == -1)) {
-                       if (p_fs->dev_ejected)
-                               return -EIO;
-                       return 0;
-               }
-       }
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       /* get the directory entry of given file */
-       es = get_entry_set_in_dir(sb, &fid->dir, fid->entry,
-                                 ES_ALL_ENTRIES, &ep);
-       if (!es) {
-               ret = -ENOENT;
-               goto out;
-       }
-
-       type = exfat_get_entry_type(ep);
-
-       if (((type == TYPE_FILE) && (attr & ATTR_SUBDIR)) ||
-           ((type == TYPE_DIR) && (!(attr & ATTR_SUBDIR)))) {
-               if (p_fs->dev_ejected)
-                       ret = -EIO;
-               else
-                       ret = -EINVAL;
-
-               release_entry_set(es);
-               goto out;
-       }
-
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       /* set the file attribute */
-       fid->attr = attr;
-       exfat_set_entry_attr(ep, attr);
-
-       update_dir_checksum_with_entry_set(sb, es);
-       release_entry_set(es);
-
-#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-#endif
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-#endif
-
-static int ffsReadStat(struct inode *inode, struct dir_entry_t *info)
-{
-       s32 count;
-       int ret = 0;
-       struct chain_t dir;
-       struct uni_name_t uni_name;
-       struct timestamp_t tm;
-       struct dentry_t *ep, *ep2;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-       struct entry_set_cache_t *es = NULL;
-       u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
-
-       pr_debug("%s entered\n", __func__);
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       if (is_dir) {
-               if ((fid->dir.dir == p_fs->root_dir) &&
-                   (fid->entry == -1)) {
-                       info->Attr = ATTR_SUBDIR;
-                       memset((char *)&info->CreateTimestamp, 0,
-                              sizeof(struct date_time_t));
-                       memset((char *)&info->ModifyTimestamp, 0,
-                              sizeof(struct date_time_t));
-                       memset((char *)&info->AccessTimestamp, 0,
-                              sizeof(struct date_time_t));
-                       strcpy(info->ShortName, ".");
-                       strcpy(info->Name, ".");
-
-                       dir.dir = p_fs->root_dir;
-                       dir.flags = 0x01;
-
-                       if (p_fs->root_dir == CLUSTER_32(0)) {
-                               /* FAT16 root_dir */
-                               info->Size = p_fs->dentries_in_root <<
-                                               DENTRY_SIZE_BITS;
-                       } else {
-                               info->Size = count_num_clusters(sb, &dir) <<
-                                               p_fs->cluster_size_bits;
-                       }
-
-                       count = count_dos_name_entries(sb, &dir, TYPE_DIR);
-                       if (count < 0) {
-                               ret = count; /* propagate error upward */
-                               goto out;
-                       }
-                       info->NumSubdirs = count;
-
-                       if (p_fs->dev_ejected)
-                               ret = -EIO;
-                       goto out;
-               }
-       }
-
-       /* get the directory entry of given file or directory */
-       es = get_entry_set_in_dir(sb, &fid->dir, fid->entry,
-                                 ES_2_ENTRIES, &ep);
-       if (!es) {
-               ret = -ENOENT;
-               goto out;
-       }
-       ep2 = ep + 1;
-
-       /* set FILE_INFO structure using the acquired struct dentry_t */
-       info->Attr = exfat_get_entry_attr(ep);
-
-       exfat_get_entry_time(ep, &tm, TM_CREATE);
-       info->CreateTimestamp.Year = tm.year;
-       info->CreateTimestamp.Month = tm.mon;
-       info->CreateTimestamp.Day = tm.day;
-       info->CreateTimestamp.Hour = tm.hour;
-       info->CreateTimestamp.Minute = tm.min;
-       info->CreateTimestamp.Second = tm.sec;
-       info->CreateTimestamp.MilliSecond = 0;
-
-       exfat_get_entry_time(ep, &tm, TM_MODIFY);
-       info->ModifyTimestamp.Year = tm.year;
-       info->ModifyTimestamp.Month = tm.mon;
-       info->ModifyTimestamp.Day = tm.day;
-       info->ModifyTimestamp.Hour = tm.hour;
-       info->ModifyTimestamp.Minute = tm.min;
-       info->ModifyTimestamp.Second = tm.sec;
-       info->ModifyTimestamp.MilliSecond = 0;
-
-       memset((char *)&info->AccessTimestamp, 0, sizeof(struct date_time_t));
-
-       *uni_name.name = 0x0;
-       /* XXX this is very bad for exfat cuz name is already included in es.
-        * API should be revised
-        */
-       exfat_get_uni_name_from_ext_entry(sb, &fid->dir, fid->entry,
-                                         uni_name.name);
-       nls_uniname_to_cstring(sb, info->Name, &uni_name);
-
-       info->NumSubdirs = 2;
-
-       info->Size = exfat_get_entry_size(ep2);
-
-       release_entry_set(es);
-
-       if (is_dir) {
-               dir.dir = fid->start_clu;
-               dir.flags = 0x01;
-
-               if (info->Size == 0)
-                       info->Size = (u64)count_num_clusters(sb, &dir) <<
-                                       p_fs->cluster_size_bits;
-
-               count = count_dos_name_entries(sb, &dir, TYPE_DIR);
-               if (count < 0) {
-                       ret = count; /* propagate error upward */
-                       goto out;
-               }
-               info->NumSubdirs += count;
-       }
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       pr_debug("%s exited successfully\n", __func__);
-       return ret;
-}
-
-static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info)
-{
-       int ret = 0;
-       struct timestamp_t tm;
-       struct dentry_t *ep, *ep2;
-       struct entry_set_cache_t *es = NULL;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-       u8 is_dir = (fid->type == TYPE_DIR) ? 1 : 0;
-
-       pr_debug("%s entered (inode %p info %p\n", __func__, inode, info);
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       if (is_dir) {
-               if ((fid->dir.dir == p_fs->root_dir) &&
-                   (fid->entry == -1)) {
-                       if (p_fs->dev_ejected)
-                               ret = -EIO;
-                       ret = 0;
-                       goto out;
-               }
-       }
-
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       /* get the directory entry of given file or directory */
-       es = get_entry_set_in_dir(sb, &fid->dir, fid->entry,
-                                 ES_ALL_ENTRIES, &ep);
-       if (!es) {
-               ret = -ENOENT;
-               goto out;
-       }
-       ep2 = ep + 1;
-
-       exfat_set_entry_attr(ep, info->Attr);
-
-       /* set FILE_INFO structure using the acquired struct dentry_t */
-       tm.sec  = info->CreateTimestamp.Second;
-       tm.min  = info->CreateTimestamp.Minute;
-       tm.hour = info->CreateTimestamp.Hour;
-       tm.day  = info->CreateTimestamp.Day;
-       tm.mon  = info->CreateTimestamp.Month;
-       tm.year = info->CreateTimestamp.Year;
-       exfat_set_entry_time(ep, &tm, TM_CREATE);
-
-       tm.sec  = info->ModifyTimestamp.Second;
-       tm.min  = info->ModifyTimestamp.Minute;
-       tm.hour = info->ModifyTimestamp.Hour;
-       tm.day  = info->ModifyTimestamp.Day;
-       tm.mon  = info->ModifyTimestamp.Month;
-       tm.year = info->ModifyTimestamp.Year;
-       exfat_set_entry_time(ep, &tm, TM_MODIFY);
-
-       exfat_set_entry_size(ep2, info->Size);
-
-       update_dir_checksum_with_entry_set(sb, es);
-       release_entry_set(es);
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       pr_debug("%s exited (%d)\n", __func__, ret);
-
-       return ret;
-}
-
-static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu)
-{
-       s32 num_clusters, num_alloced;
-       bool modified = false;
-       u32 last_clu;
-       int ret = 0;
-       struct chain_t new_clu;
-       struct dentry_t *ep;
-       struct entry_set_cache_t *es = NULL;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-
-       /* check the validity of pointer parameters */
-       if (!clu)
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits;
-
-       if (EXFAT_I(inode)->mmu_private == 0)
-               num_clusters = 0;
-       else
-               num_clusters = (s32)((EXFAT_I(inode)->mmu_private - 1) >>
-                                    p_fs->cluster_size_bits) + 1;
-
-       *clu = last_clu = fid->start_clu;
-
-       if (fid->flags == 0x03) {
-               if ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) {
-                       last_clu += clu_offset - 1;
-
-                       if (clu_offset == num_clusters)
-                               *clu = CLUSTER_32(~0);
-                       else
-                               *clu += clu_offset;
-               }
-       } else {
-               /* hint information */
-               if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
-                   (clu_offset >= fid->hint_last_off)) {
-                       clu_offset -= fid->hint_last_off;
-                       *clu = fid->hint_last_clu;
-               }
-
-               while ((clu_offset > 0) && (*clu != CLUSTER_32(~0))) {
-                       last_clu = *clu;
-                       if (exfat_fat_read(sb, *clu, clu) == -1) {
-                               ret = -EIO;
-                               goto out;
-                       }
-                       clu_offset--;
-               }
-       }
-
-       if (*clu == CLUSTER_32(~0)) {
-               fs_set_vol_flags(sb, VOL_DIRTY);
-
-               new_clu.dir = (last_clu == CLUSTER_32(~0)) ? CLUSTER_32(~0) :
-                                       last_clu + 1;
-               new_clu.size = 0;
-               new_clu.flags = fid->flags;
-
-               /* (1) allocate a cluster */
-               num_alloced = exfat_alloc_cluster(sb, 1, &new_clu);
-               if (num_alloced < 0) {
-                       ret = -EIO;
-                       goto out;
-               } else if (num_alloced == 0) {
-                       ret = -ENOSPC;
-                       goto out;
-               }
-
-               /* (2) append to the FAT chain */
-               if (last_clu == CLUSTER_32(~0)) {
-                       if (new_clu.flags == 0x01)
-                               fid->flags = 0x01;
-                       fid->start_clu = new_clu.dir;
-                       modified = true;
-               } else {
-                       if (new_clu.flags != fid->flags) {
-                               exfat_chain_cont_cluster(sb, fid->start_clu,
-                                                        num_clusters);
-                               fid->flags = 0x01;
-                               modified = true;
-                       }
-                       if (new_clu.flags == 0x01)
-                               exfat_fat_write(sb, last_clu, new_clu.dir);
-               }
-
-               num_clusters += num_alloced;
-               *clu = new_clu.dir;
-
-               es = get_entry_set_in_dir(sb, &fid->dir, fid->entry,
-                                         ES_ALL_ENTRIES, &ep);
-               if (!es) {
-                       ret = -ENOENT;
-                       goto out;
-               }
-               /* get stream entry */
-               ep++;
-
-               /* (3) update directory entry */
-               if (modified) {
-                       if (exfat_get_entry_flag(ep) != fid->flags)
-                               exfat_set_entry_flag(ep, fid->flags);
-
-                       if (exfat_get_entry_clu0(ep) != fid->start_clu)
-                               exfat_set_entry_clu0(ep, fid->start_clu);
-               }
-
-               update_dir_checksum_with_entry_set(sb, es);
-               release_entry_set(es);
-
-               /* add number of new blocks to inode */
-               inode->i_blocks += num_alloced << (p_fs->cluster_size_bits - 9);
-       }
-
-       /* hint information */
-       fid->hint_last_off = (s32)(fid->rwoffset >> p_fs->cluster_size_bits);
-       fid->hint_last_clu = *clu;
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-/*----------------------------------------------------------------------*/
-/*  Directory Operation Functions                                       */
-/*----------------------------------------------------------------------*/
-
-static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid)
-{
-       int ret = 0;
-       struct chain_t dir;
-       struct uni_name_t uni_name;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       pr_debug("%s entered\n", __func__);
-
-       /* check the validity of pointer parameters */
-       if (!fid || !path || (*path == '\0'))
-               return -EINVAL;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       /* check the validity of directory name in the given old pathname */
-       ret = resolve_path(inode, path, &dir, &uni_name);
-       if (ret)
-               goto out;
-
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       ret = create_dir(inode, &dir, &uni_name, fid);
-
-#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-#endif
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry)
-{
-       int i, dentry, clu_offset;
-       int ret = 0;
-       s32 dentries_per_clu, dentries_per_clu_bits = 0;
-       u32 type;
-       sector_t sector;
-       struct chain_t dir, clu;
-       struct uni_name_t uni_name;
-       struct timestamp_t tm;
-       struct dentry_t *ep;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-
-       /* check the validity of pointer parameters */
-       if (!dir_entry)
-               return -EINVAL;
-
-       /* check if the given file ID is opened */
-       if (fid->type != TYPE_DIR)
-               return -ENOTDIR;
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       if (fid->entry == -1) {
-               dir.dir = p_fs->root_dir;
-               dir.flags = 0x01;
-       } else {
-               dir.dir = fid->start_clu;
-               dir.size = (s32)(fid->size >> p_fs->cluster_size_bits);
-               dir.flags = fid->flags;
-       }
-
-       dentry = (s32)fid->rwoffset;
-
-       if (dir.dir == CLUSTER_32(0)) {
-               /* FAT16 root_dir */
-               dentries_per_clu = p_fs->dentries_in_root;
-
-               if (dentry == dentries_per_clu) {
-                       clu.dir = CLUSTER_32(~0);
-               } else {
-                       clu.dir = dir.dir;
-                       clu.size = dir.size;
-                       clu.flags = dir.flags;
-               }
-       } else {
-               dentries_per_clu = p_fs->dentries_per_clu;
-               dentries_per_clu_bits = ilog2(dentries_per_clu);
-
-               clu_offset = dentry >> dentries_per_clu_bits;
-               clu.dir = dir.dir;
-               clu.size = dir.size;
-               clu.flags = dir.flags;
-
-               if (clu.flags == 0x03) {
-                       clu.dir += clu_offset;
-                       clu.size -= clu_offset;
-               } else {
-                       /* hint_information */
-                       if ((clu_offset > 0) && (fid->hint_last_off > 0) &&
-                           (clu_offset >= fid->hint_last_off)) {
-                               clu_offset -= fid->hint_last_off;
-                               clu.dir = fid->hint_last_clu;
-                       }
-
-                       while (clu_offset > 0) {
-                               /* clu.dir = exfat_fat_read(sb, clu.dir); */
-                               if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) {
-                                       ret = -EIO;
-                                       goto out;
-                               }
-                               clu_offset--;
-                       }
-               }
-       }
-
-       while (clu.dir != CLUSTER_32(~0)) {
-               if (p_fs->dev_ejected)
-                       break;
-
-               if (dir.dir == CLUSTER_32(0)) /* FAT16 root_dir */
-                       i = dentry % dentries_per_clu;
-               else
-                       i = dentry & (dentries_per_clu - 1);
-
-               for ( ; i < dentries_per_clu; i++, dentry++) {
-                       ep = get_entry_in_dir(sb, &clu, i, &sector);
-                       if (!ep) {
-                               ret = -ENOENT;
-                               goto out;
-                       }
-                       type = exfat_get_entry_type(ep);
-
-                       if (type == TYPE_UNUSED)
-                               break;
-
-                       if ((type != TYPE_FILE) && (type != TYPE_DIR))
-                               continue;
-
-                       exfat_buf_lock(sb, sector);
-                       dir_entry->Attr = exfat_get_entry_attr(ep);
-
-                       exfat_get_entry_time(ep, &tm, TM_CREATE);
-                       dir_entry->CreateTimestamp.Year = tm.year;
-                       dir_entry->CreateTimestamp.Month = tm.mon;
-                       dir_entry->CreateTimestamp.Day = tm.day;
-                       dir_entry->CreateTimestamp.Hour = tm.hour;
-                       dir_entry->CreateTimestamp.Minute = tm.min;
-                       dir_entry->CreateTimestamp.Second = tm.sec;
-                       dir_entry->CreateTimestamp.MilliSecond = 0;
-
-                       exfat_get_entry_time(ep, &tm, TM_MODIFY);
-                       dir_entry->ModifyTimestamp.Year = tm.year;
-                       dir_entry->ModifyTimestamp.Month = tm.mon;
-                       dir_entry->ModifyTimestamp.Day = tm.day;
-                       dir_entry->ModifyTimestamp.Hour = tm.hour;
-                       dir_entry->ModifyTimestamp.Minute = tm.min;
-                       dir_entry->ModifyTimestamp.Second = tm.sec;
-                       dir_entry->ModifyTimestamp.MilliSecond = 0;
-
-                       memset((char *)&dir_entry->AccessTimestamp, 0,
-                              sizeof(struct date_time_t));
-
-                       *uni_name.name = 0x0;
-                       exfat_get_uni_name_from_ext_entry(sb, &dir, dentry,
-                                                         uni_name.name);
-                       nls_uniname_to_cstring(sb, dir_entry->Name, &uni_name);
-                       exfat_buf_unlock(sb, sector);
-
-                       ep = get_entry_in_dir(sb, &clu, i + 1, NULL);
-                       if (!ep) {
-                               ret = -ENOENT;
-                               goto out;
-                       }
-
-                       dir_entry->Size = exfat_get_entry_size(ep);
-
-                       /* hint information */
-                       if (dir.dir == CLUSTER_32(0)) { /* FAT16 root_dir */
-                       } else {
-                               fid->hint_last_off = dentry >>
-                                                       dentries_per_clu_bits;
-                               fid->hint_last_clu = clu.dir;
-                       }
-
-                       fid->rwoffset = (s64)(++dentry);
-
-                       if (p_fs->dev_ejected)
-                               ret = -EIO;
-                       goto out;
-               }
-
-               if (dir.dir == CLUSTER_32(0))
-                       break; /* FAT16 root_dir */
-
-               if (clu.flags == 0x03) {
-                       if ((--clu.size) > 0)
-                               clu.dir++;
-                       else
-                               clu.dir = CLUSTER_32(~0);
-               } else {
-                       /* clu.dir = exfat_fat_read(sb, clu.dir); */
-                       if (exfat_fat_read(sb, clu.dir, &clu.dir) == -1) {
-                               ret = -EIO;
-                               goto out;
-                       }
-               }
-       }
-
-       *dir_entry->Name = '\0';
-
-       fid->rwoffset = (s64)(++dentry);
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid)
-{
-       s32 dentry;
-       int ret = 0;
-       struct chain_t dir, clu_to_free;
-       struct super_block *sb = inode->i_sb;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       /* check the validity of the given file id */
-       if (!fid)
-               return -EINVAL;
-
-       dir.dir = fid->dir.dir;
-       dir.size = fid->dir.size;
-       dir.flags = fid->dir.flags;
-
-       dentry = fid->entry;
-
-       /* check if the file is "." or ".." */
-       if (p_fs->vol_type != EXFAT) {
-               if ((dir.dir != p_fs->root_dir) && (dentry < 2))
-                       return -EPERM;
-       }
-
-       /* acquire the lock for file system critical section */
-       mutex_lock(&p_fs->v_mutex);
-
-       clu_to_free.dir = fid->start_clu;
-       clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1;
-       clu_to_free.flags = fid->flags;
-
-       if (!is_dir_empty(sb, &clu_to_free)) {
-               ret = -ENOTEMPTY;
-               goto out;
-       }
-
-       fs_set_vol_flags(sb, VOL_DIRTY);
-
-       /* (1) update the directory entry */
-       remove_file(inode, &dir, dentry);
-
-       /* (2) free the clusters */
-       exfat_free_cluster(sb, &clu_to_free, 1);
-
-       fid->size = 0;
-       fid->start_clu = CLUSTER_32(~0);
-       fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01;
-
-#ifndef CONFIG_STAGING_EXFAT_DELAYED_SYNC
-       fs_sync(sb, true);
-       fs_set_vol_flags(sb, VOL_CLEAN);
-#endif
-
-       if (p_fs->dev_ejected)
-               ret = -EIO;
-
-out:
-       /* release the lock for file system critical section */
-       mutex_unlock(&p_fs->v_mutex);
-
-       return ret;
-}
-
-/*======================================================================*/
-/*  Directory Entry Operations                                          */
-/*======================================================================*/
-
-static int exfat_readdir(struct file *filp, struct dir_context *ctx)
-{
-       struct inode *inode = file_inode(filp);
-       struct super_block *sb = inode->i_sb;
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct fs_info_t *p_fs = &sbi->fs_info;
-       struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info);
-       struct dir_entry_t de;
-       unsigned long inum;
-       loff_t cpos;
-       int err = 0;
-
-       __lock_super(sb);
-
-       cpos = ctx->pos;
-       /* Fake . and .. for the root directory. */
-       if ((p_fs->vol_type == EXFAT) || (inode->i_ino == EXFAT_ROOT_INO)) {
-               while (cpos < 2) {
-                       if (inode->i_ino == EXFAT_ROOT_INO)
-                               inum = EXFAT_ROOT_INO;
-                       else if (cpos == 0)
-                               inum = inode->i_ino;
-                       else /* (cpos == 1) */
-                               inum = parent_ino(filp->f_path.dentry);
-
-                       if (!dir_emit_dots(filp, ctx))
-                               goto out;
-                       cpos++;
-                       ctx->pos++;
-               }
-               if (cpos == 2)
-                       cpos = 0;
-       }
-       if (cpos & (DENTRY_SIZE - 1)) {
-               err = -ENOENT;
-               goto out;
-       }
-
-get_new:
-       EXFAT_I(inode)->fid.size = i_size_read(inode);
-       EXFAT_I(inode)->fid.rwoffset = cpos >> DENTRY_SIZE_BITS;
-
-       err = ffsReadDir(inode, &de);
-       if (err) {
-               /* at least we tried to read a sector
-                * move cpos to next sector position (should be aligned)
-                */
-               if (err == -EIO) {
-                       cpos += 1 << p_bd->sector_size_bits;
-                       cpos &= ~((1 << p_bd->sector_size_bits) - 1);
-               }
-
-               goto end_of_dir;
-       }
-
-       cpos = EXFAT_I(inode)->fid.rwoffset << DENTRY_SIZE_BITS;
-
-       if (!de.Name[0])
-               goto end_of_dir;
-
-       if (!memcmp(de.ShortName, DOS_CUR_DIR_NAME, DOS_NAME_LENGTH)) {
-               inum = inode->i_ino;
-       } else if (!memcmp(de.ShortName, DOS_PAR_DIR_NAME, DOS_NAME_LENGTH)) {
-               inum = parent_ino(filp->f_path.dentry);
-       } else {
-               loff_t i_pos = ((loff_t)EXFAT_I(inode)->fid.start_clu << 32) |
-                               ((EXFAT_I(inode)->fid.rwoffset - 1) & 0xffffffff);
-               struct inode *tmp = exfat_iget(sb, i_pos);
-
-               if (tmp) {
-                       inum = tmp->i_ino;
-                       iput(tmp);
-               } else {
-                       inum = iunique(sb, EXFAT_ROOT_INO);
-               }
-       }
-
-       if (!dir_emit(ctx, de.Name, strlen(de.Name), inum,
-                     (de.Attr & ATTR_SUBDIR) ? DT_DIR : DT_REG))
-               goto out;
-
-       ctx->pos = cpos;
-       goto get_new;
-
-end_of_dir:
-       ctx->pos = cpos;
-out:
-       __unlock_super(sb);
-       return err;
-}
-
-static int exfat_ioctl_volume_id(struct inode *dir)
-{
-       struct super_block *sb = dir->i_sb;
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct fs_info_t *p_fs = &sbi->fs_info;
-
-       return p_fs->vol_id;
-}
-
-static long exfat_generic_ioctl(struct file *filp, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct inode *inode = filp->f_path.dentry->d_inode;
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-       unsigned int flags;
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-
-       switch (cmd) {
-       case EXFAT_IOCTL_GET_VOLUME_ID:
-               return exfat_ioctl_volume_id(inode);
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-       case EXFAT_IOC_GET_DEBUGFLAGS: {
-               struct super_block *sb = inode->i_sb;
-               struct exfat_sb_info *sbi = EXFAT_SB(sb);
-
-               flags = sbi->debug_flags;
-               return put_user(flags, (int __user *)arg);
-       }
-       case EXFAT_IOC_SET_DEBUGFLAGS: {
-               struct super_block *sb = inode->i_sb;
-               struct exfat_sb_info *sbi = EXFAT_SB(sb);
-
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-
-               if (get_user(flags, (int __user *)arg))
-                       return -EFAULT;
-
-               __lock_super(sb);
-               sbi->debug_flags = flags;
-               __unlock_super(sb);
-
-               return 0;
-       }
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-       default:
-               return -ENOTTY; /* Inappropriate ioctl for device */
-       }
-}
-
-static const struct file_operations exfat_dir_operations = {
-       .llseek     = generic_file_llseek,
-       .read       = generic_read_dir,
-       .iterate    = exfat_readdir,
-       .unlocked_ioctl = exfat_generic_ioctl,
-       .fsync      = generic_file_fsync,
-};
-
-static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-                       bool excl)
-{
-       struct super_block *sb = dir->i_sb;
-       struct timespec64 curtime;
-       struct inode *inode;
-       struct file_id_t fid;
-       loff_t i_pos;
-       int err;
-
-       __lock_super(sb);
-
-       pr_debug("%s entered\n", __func__);
-
-       err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_REGULAR, &fid);
-       if (err)
-               goto out;
-
-       INC_IVERSION(dir);
-       curtime = current_time(dir);
-       dir->i_ctime = curtime;
-       dir->i_mtime = curtime;
-       dir->i_atime = curtime;
-       if (IS_DIRSYNC(dir))
-               (void)exfat_sync_inode(dir);
-       else
-               mark_inode_dirty(dir);
-
-       i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff);
-
-       inode = exfat_build_inode(sb, &fid, i_pos);
-       if (IS_ERR(inode)) {
-               err = PTR_ERR(inode);
-               goto out;
-       }
-       INC_IVERSION(inode);
-       curtime = current_time(inode);
-       inode->i_mtime = curtime;
-       inode->i_atime = curtime;
-       inode->i_ctime = curtime;
-       /*
-        * timestamp is already written, so mark_inode_dirty() is unnecessary.
-        */
-
-       dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
-       d_instantiate(dentry, inode);
-
-out:
-       __unlock_super(sb);
-       pr_debug("%s exited\n", __func__);
-       return err;
-}
-
-static int exfat_find(struct inode *dir, struct qstr *qname,
-                     struct file_id_t *fid)
-{
-       int err;
-
-       if (qname->len == 0)
-               return -ENOENT;
-
-       err = ffsLookupFile(dir, (u8 *)qname->name, fid);
-       if (err)
-               return -ENOENT;
-
-       return 0;
-}
-
-static int exfat_d_anon_disconn(struct dentry *dentry)
-{
-       return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED);
-}
-
-static struct dentry *exfat_lookup(struct inode *dir, struct dentry *dentry,
-                                  unsigned int flags)
-{
-       struct super_block *sb = dir->i_sb;
-       struct inode *inode;
-       struct dentry *alias;
-       int err;
-       struct file_id_t fid;
-       loff_t i_pos;
-       u64 ret;
-       mode_t i_mode;
-
-       __lock_super(sb);
-       pr_debug("%s entered\n", __func__);
-       err = exfat_find(dir, &dentry->d_name, &fid);
-       if (err) {
-               if (err == -ENOENT) {
-                       inode = NULL;
-                       goto out;
-               }
-               goto error;
-       }
-
-       i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff);
-       inode = exfat_build_inode(sb, &fid, i_pos);
-       if (IS_ERR(inode)) {
-               err = PTR_ERR(inode);
-               goto error;
-       }
-
-       i_mode = inode->i_mode;
-       if (S_ISLNK(i_mode) && !EXFAT_I(inode)->target) {
-               EXFAT_I(inode)->target = kmalloc(i_size_read(inode) + 1,
-                                                GFP_KERNEL);
-               if (!EXFAT_I(inode)->target) {
-                       err = -ENOMEM;
-                       goto error;
-               }
-               ffsReadFile(dir, &fid, EXFAT_I(inode)->target,
-                           i_size_read(inode), &ret);
-               *(EXFAT_I(inode)->target + i_size_read(inode)) = '\0';
-       }
-
-       alias = d_find_alias(inode);
-       if (alias && !exfat_d_anon_disconn(alias)) {
-               BUG_ON(d_unhashed(alias));
-               if (!S_ISDIR(i_mode))
-                       d_move(alias, dentry);
-               iput(inode);
-               __unlock_super(sb);
-               pr_debug("%s exited 1\n", __func__);
-               return alias;
-       }
-       dput(alias);
-out:
-       __unlock_super(sb);
-       dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
-       dentry = d_splice_alias(inode, dentry);
-       if (dentry)
-               dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
-       pr_debug("%s exited 2\n", __func__);
-       return dentry;
-
-error:
-       __unlock_super(sb);
-       pr_debug("%s exited 3\n", __func__);
-       return ERR_PTR(err);
-}
-
-static inline unsigned long exfat_hash(loff_t i_pos)
-{
-       return hash_32(i_pos, EXFAT_HASH_BITS);
-}
-
-static void exfat_attach(struct inode *inode, loff_t i_pos)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
-       struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos);
-
-       spin_lock(&sbi->inode_hash_lock);
-       EXFAT_I(inode)->i_pos = i_pos;
-       hlist_add_head(&EXFAT_I(inode)->i_hash_fat, head);
-       spin_unlock(&sbi->inode_hash_lock);
-}
-
-static void exfat_detach(struct inode *inode)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
-
-       spin_lock(&sbi->inode_hash_lock);
-       hlist_del_init(&EXFAT_I(inode)->i_hash_fat);
-       EXFAT_I(inode)->i_pos = 0;
-       spin_unlock(&sbi->inode_hash_lock);
-}
-
-static int exfat_unlink(struct inode *dir, struct dentry *dentry)
-{
-       struct inode *inode = dentry->d_inode;
-       struct super_block *sb = dir->i_sb;
-       struct timespec64 curtime;
-       int err;
-
-       __lock_super(sb);
-
-       pr_debug("%s entered\n", __func__);
-
-       EXFAT_I(inode)->fid.size = i_size_read(inode);
-
-       err = ffsRemoveFile(dir, &(EXFAT_I(inode)->fid));
-       if (err)
-               goto out;
-
-       INC_IVERSION(dir);
-       curtime = current_time(dir);
-       dir->i_mtime = curtime;
-       dir->i_atime = curtime;
-       if (IS_DIRSYNC(dir))
-               (void)exfat_sync_inode(dir);
-       else
-               mark_inode_dirty(dir);
-
-       clear_nlink(inode);
-       curtime = current_time(inode);
-       inode->i_mtime = curtime;
-       inode->i_atime = curtime;
-       exfat_detach(inode);
-       remove_inode_hash(inode);
-
-out:
-       __unlock_super(sb);
-       pr_debug("%s exited\n", __func__);
-       return err;
-}
-
-static int exfat_symlink(struct inode *dir, struct dentry *dentry,
-                        const char *target)
-{
-       struct super_block *sb = dir->i_sb;
-       struct timespec64 curtime;
-       struct inode *inode;
-       struct file_id_t fid;
-       loff_t i_pos;
-       int err;
-       u64 len = (u64)strlen(target);
-       u64 ret;
-
-       __lock_super(sb);
-
-       pr_debug("%s entered\n", __func__);
-
-       err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_SYMLINK, &fid);
-       if (err)
-               goto out;
-
-
-       err = ffsWriteFile(dir, &fid, (char *)target, len, &ret);
-
-       if (err) {
-               ffsRemoveFile(dir, &fid);
-               goto out;
-       }
-
-       INC_IVERSION(dir);
-       curtime = current_time(dir);
-       dir->i_ctime = curtime;
-       dir->i_mtime = curtime;
-       dir->i_atime = curtime;
-       if (IS_DIRSYNC(dir))
-               (void)exfat_sync_inode(dir);
-       else
-               mark_inode_dirty(dir);
-
-       i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff);
-
-       inode = exfat_build_inode(sb, &fid, i_pos);
-       if (IS_ERR(inode)) {
-               err = PTR_ERR(inode);
-               goto out;
-       }
-       INC_IVERSION(inode);
-       curtime = current_time(inode);
-       inode->i_mtime = curtime;
-       inode->i_atime = curtime;
-       inode->i_ctime = curtime;
-       /* timestamp is already written, so mark_inode_dirty() is unneeded. */
-
-       EXFAT_I(inode)->target = kmemdup(target, len + 1, GFP_KERNEL);
-       if (!EXFAT_I(inode)->target) {
-               err = -ENOMEM;
-               goto out;
-       }
-
-       dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
-       d_instantiate(dentry, inode);
-
-out:
-       __unlock_super(sb);
-       pr_debug("%s exited\n", __func__);
-       return err;
-}
-
-static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
-{
-       struct super_block *sb = dir->i_sb;
-       struct timespec64 curtime;
-       struct inode *inode;
-       struct file_id_t fid;
-       loff_t i_pos;
-       int err;
-
-       __lock_super(sb);
-
-       pr_debug("%s entered\n", __func__);
-
-       err = ffsCreateDir(dir, (u8 *)dentry->d_name.name, &fid);
-       if (err)
-               goto out;
-
-       INC_IVERSION(dir);
-       curtime = current_time(dir);
-       dir->i_ctime = curtime;
-       dir->i_mtime = curtime;
-       dir->i_atime = curtime;
-       if (IS_DIRSYNC(dir))
-               (void)exfat_sync_inode(dir);
-       else
-               mark_inode_dirty(dir);
-       inc_nlink(dir);
-
-       i_pos = ((loff_t)fid.dir.dir << 32) | (fid.entry & 0xffffffff);
-
-       inode = exfat_build_inode(sb, &fid, i_pos);
-       if (IS_ERR(inode)) {
-               err = PTR_ERR(inode);
-               goto out;
-       }
-       INC_IVERSION(inode);
-       curtime = current_time(inode);
-       inode->i_mtime = curtime;
-       inode->i_atime = curtime;
-       inode->i_ctime = curtime;
-       /* timestamp is already written, so mark_inode_dirty() is unneeded. */
-
-       dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode);
-       d_instantiate(dentry, inode);
-
-out:
-       __unlock_super(sb);
-       pr_debug("%s exited\n", __func__);
-       return err;
-}
-
-static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
-{
-       struct inode *inode = dentry->d_inode;
-       struct super_block *sb = dir->i_sb;
-       struct timespec64 curtime;
-       int err;
-
-       __lock_super(sb);
-
-       pr_debug("%s entered\n", __func__);
-
-       EXFAT_I(inode)->fid.size = i_size_read(inode);
-
-       err = ffsRemoveDir(dir, &(EXFAT_I(inode)->fid));
-       if (err)
-               goto out;
-
-       INC_IVERSION(dir);
-       curtime = current_time(dir);
-       dir->i_mtime = curtime;
-       dir->i_atime = curtime;
-       if (IS_DIRSYNC(dir))
-               (void)exfat_sync_inode(dir);
-       else
-               mark_inode_dirty(dir);
-       drop_nlink(dir);
-
-       clear_nlink(inode);
-       curtime = current_time(inode);
-       inode->i_mtime = curtime;
-       inode->i_atime = curtime;
-       exfat_detach(inode);
-       remove_inode_hash(inode);
-
-out:
-       __unlock_super(sb);
-       pr_debug("%s exited\n", __func__);
-       return err;
-}
-
-static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry,
-                       struct inode *new_dir, struct dentry *new_dentry,
-                       unsigned int flags)
-{
-       struct inode *old_inode, *new_inode;
-       struct super_block *sb = old_dir->i_sb;
-       struct timespec64 curtime;
-       loff_t i_pos;
-       int err;
-
-       if (flags)
-               return -EINVAL;
-
-       __lock_super(sb);
-
-       pr_debug("%s entered\n", __func__);
-
-       old_inode = old_dentry->d_inode;
-       new_inode = new_dentry->d_inode;
-
-       EXFAT_I(old_inode)->fid.size = i_size_read(old_inode);
-
-       err = ffsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir,
-                         new_dentry);
-       if (err)
-               goto out;
-
-       INC_IVERSION(new_dir);
-       curtime = current_time(new_dir);
-       new_dir->i_ctime = curtime;
-       new_dir->i_mtime = curtime;
-       new_dir->i_atime = curtime;
-
-       if (IS_DIRSYNC(new_dir))
-               (void)exfat_sync_inode(new_dir);
-       else
-               mark_inode_dirty(new_dir);
-
-       i_pos = ((loff_t)EXFAT_I(old_inode)->fid.dir.dir << 32) |
-                       (EXFAT_I(old_inode)->fid.entry & 0xffffffff);
-
-       exfat_detach(old_inode);
-       exfat_attach(old_inode, i_pos);
-       if (IS_DIRSYNC(new_dir))
-               (void)exfat_sync_inode(old_inode);
-       else
-               mark_inode_dirty(old_inode);
-
-       if ((S_ISDIR(old_inode->i_mode)) && (old_dir != new_dir)) {
-               drop_nlink(old_dir);
-               if (!new_inode)
-                       inc_nlink(new_dir);
-       }
-       INC_IVERSION(old_dir);
-       curtime = current_time(old_dir);
-       old_dir->i_ctime = curtime;
-       old_dir->i_mtime = curtime;
-       if (IS_DIRSYNC(old_dir))
-               (void)exfat_sync_inode(old_dir);
-       else
-               mark_inode_dirty(old_dir);
-
-       if (new_inode) {
-               exfat_detach(new_inode);
-               drop_nlink(new_inode);
-               if (S_ISDIR(new_inode->i_mode))
-                       drop_nlink(new_inode);
-               new_inode->i_ctime = current_time(new_inode);
-       }
-
-out:
-       __unlock_super(sb);
-       pr_debug("%s exited\n", __func__);
-       return err;
-}
-
-static int exfat_cont_expand(struct inode *inode, loff_t size)
-{
-       struct address_space *mapping = inode->i_mapping;
-       loff_t start = i_size_read(inode), count = size - i_size_read(inode);
-       struct timespec64 curtime;
-       int err, err2;
-
-       err = generic_cont_expand_simple(inode, size);
-       if (err != 0)
-               return err;
-
-       curtime = current_time(inode);
-       inode->i_ctime = curtime;
-       inode->i_mtime = curtime;
-       mark_inode_dirty(inode);
-
-       if (IS_SYNC(inode)) {
-               err = filemap_fdatawrite_range(mapping, start,
-                                              start + count - 1);
-               err2 = sync_mapping_buffers(mapping);
-               err = (err) ? (err) : (err2);
-               err2 = write_inode_now(inode, 1);
-               err = (err) ? (err) : (err2);
-               if (!err)
-                       err =  filemap_fdatawait_range(mapping, start,
-                                                      start + count - 1);
-       }
-       return err;
-}
-
-static int exfat_allow_set_time(struct exfat_sb_info *sbi, struct inode *inode)
-{
-       mode_t allow_utime = sbi->options.allow_utime;
-
-       if (!uid_eq(current_fsuid(), inode->i_uid)) {
-               if (in_group_p(inode->i_gid))
-                       allow_utime >>= 3;
-               if (allow_utime & MAY_WRITE)
-                       return 1;
-       }
-
-       /* use a default check */
-       return 0;
-}
-
-static int exfat_sanitize_mode(const struct exfat_sb_info *sbi,
-                              struct inode *inode, umode_t *mode_ptr)
-{
-       mode_t i_mode, mask, perm;
-
-       i_mode = inode->i_mode;
-
-       if (S_ISREG(i_mode) || S_ISLNK(i_mode))
-               mask = sbi->options.fs_fmask;
-       else
-               mask = sbi->options.fs_dmask;
-
-       perm = *mode_ptr & ~(S_IFMT | mask);
-
-       /* Of the r and x bits, all (subject to umask) must be present.*/
-       if ((perm & 0555) != (i_mode & 0555))
-               return -EPERM;
-
-       if (exfat_mode_can_hold_ro(inode)) {
-               /*
-                * Of the w bits, either all (subject to umask) or none must be
-                * present.
-                */
-               if ((perm & 0222) && ((perm & 0222) != (0222 & ~mask)))
-                       return -EPERM;
-       } else {
-               /*
-                * If exfat_mode_can_hold_ro(inode) is false, can't change w
-                * bits.
-                */
-               if ((perm & 0222) != (0222 & ~mask))
-                       return -EPERM;
-       }
-
-       *mode_ptr &= S_IFMT | perm;
-
-       return 0;
-}
-
-static void exfat_truncate(struct inode *inode, loff_t old_size)
-{
-       struct super_block *sb = inode->i_sb;
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct fs_info_t *p_fs = &sbi->fs_info;
-       struct timespec64 curtime;
-       int err;
-
-       __lock_super(sb);
-
-       /*
-        * This protects against truncating a file bigger than it was then
-        * trying to write into the hole.
-        */
-       if (EXFAT_I(inode)->mmu_private > i_size_read(inode))
-               EXFAT_I(inode)->mmu_private = i_size_read(inode);
-
-       if (EXFAT_I(inode)->fid.start_clu == 0)
-               goto out;
-
-       err = ffsTruncateFile(inode, old_size, i_size_read(inode));
-       if (err)
-               goto out;
-
-       curtime = current_time(inode);
-       inode->i_ctime = curtime;
-       inode->i_mtime = curtime;
-       if (IS_DIRSYNC(inode))
-               (void)exfat_sync_inode(inode);
-       else
-               mark_inode_dirty(inode);
-
-       inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1)) &
-                          ~((loff_t)p_fs->cluster_size - 1)) >> 9;
-out:
-       __unlock_super(sb);
-}
-
-static int exfat_setattr(struct dentry *dentry, struct iattr *attr)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(dentry->d_sb);
-       struct inode *inode = dentry->d_inode;
-       unsigned int ia_valid;
-       int error;
-       loff_t old_size;
-
-       pr_debug("%s entered\n", __func__);
-
-       if ((attr->ia_valid & ATTR_SIZE) &&
-           attr->ia_size > i_size_read(inode)) {
-               error = exfat_cont_expand(inode, attr->ia_size);
-               if (error || attr->ia_valid == ATTR_SIZE)
-                       return error;
-               attr->ia_valid &= ~ATTR_SIZE;
-       }
-
-       ia_valid = attr->ia_valid;
-
-       if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) &&
-           exfat_allow_set_time(sbi, inode)) {
-               attr->ia_valid &= ~(ATTR_MTIME_SET |
-                                   ATTR_ATIME_SET |
-                                   ATTR_TIMES_SET);
-       }
-
-       error = setattr_prepare(dentry, attr);
-       attr->ia_valid = ia_valid;
-       if (error)
-               return error;
-
-       if (((attr->ia_valid & ATTR_UID) &&
-            (!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
-           ((attr->ia_valid & ATTR_GID) &&
-            (!gid_eq(attr->ia_gid, sbi->options.fs_gid))) ||
-           ((attr->ia_valid & ATTR_MODE) &&
-            (attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | 0777)))) {
-               return -EPERM;
-       }
-
-       /*
-        * We don't return -EPERM here. Yes, strange, but this is too
-        * old behavior.
-        */
-       if (attr->ia_valid & ATTR_MODE) {
-               if (exfat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0)
-                       attr->ia_valid &= ~ATTR_MODE;
-       }
-
-       EXFAT_I(inode)->fid.size = i_size_read(inode);
-
-       if (attr->ia_valid & ATTR_SIZE) {
-               old_size = i_size_read(inode);
-               down_write(&EXFAT_I(inode)->truncate_lock);
-               truncate_setsize(inode, attr->ia_size);
-               exfat_truncate(inode, old_size);
-               up_write(&EXFAT_I(inode)->truncate_lock);
-       }
-       setattr_copy(inode, attr);
-       mark_inode_dirty(inode);
-
-       pr_debug("%s exited\n", __func__);
-       return error;
-}
-
-static int exfat_getattr(const struct path *path, struct kstat *stat,
-                        u32 request_mask, unsigned int flags)
-{
-       struct inode *inode = path->dentry->d_inode;
-
-       pr_debug("%s entered\n", __func__);
-
-       generic_fillattr(inode, stat);
-       stat->blksize = EXFAT_SB(inode->i_sb)->fs_info.cluster_size;
-
-       pr_debug("%s exited\n", __func__);
-       return 0;
-}
-
-static const struct inode_operations exfat_dir_inode_operations = {
-       .create        = exfat_create,
-       .lookup        = exfat_lookup,
-       .unlink        = exfat_unlink,
-       .symlink       = exfat_symlink,
-       .mkdir         = exfat_mkdir,
-       .rmdir         = exfat_rmdir,
-       .rename        = exfat_rename,
-       .setattr       = exfat_setattr,
-       .getattr       = exfat_getattr,
-};
-
-/*======================================================================*/
-/*  File Operations                                                     */
-/*======================================================================*/
-static const char *exfat_get_link(struct dentry *dentry, struct inode *inode,
-                                 struct delayed_call *done)
-{
-       struct exfat_inode_info *ei = EXFAT_I(inode);
-
-       if (ei->target) {
-               char *cookie = ei->target;
-
-               if (cookie)
-                       return (char *)(ei->target);
-       }
-       return NULL;
-}
-
-static const struct inode_operations exfat_symlink_inode_operations = {
-               .get_link = exfat_get_link,
-};
-
-static int exfat_file_release(struct inode *inode, struct file *filp)
-{
-       struct super_block *sb = inode->i_sb;
-
-       EXFAT_I(inode)->fid.size = i_size_read(inode);
-       ffsSyncVol(sb, false);
-       return 0;
-}
-
-static const struct file_operations exfat_file_operations = {
-       .llseek      = generic_file_llseek,
-       .read_iter   = generic_file_read_iter,
-       .write_iter  = generic_file_write_iter,
-       .mmap        = generic_file_mmap,
-       .release     = exfat_file_release,
-       .unlocked_ioctl  = exfat_generic_ioctl,
-       .fsync       = generic_file_fsync,
-       .splice_read = generic_file_splice_read,
-};
-
-static const struct inode_operations exfat_file_inode_operations = {
-       .setattr     = exfat_setattr,
-       .getattr     = exfat_getattr,
-};
-
-/*======================================================================*/
-/*  Address Space Operations                                            */
-/*======================================================================*/
-
-static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys,
-                     unsigned long *mapped_blocks, int *create)
-{
-       struct super_block *sb = inode->i_sb;
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct fs_info_t *p_fs = &sbi->fs_info;
-       const unsigned long blocksize = sb->s_blocksize;
-       const unsigned char blocksize_bits = sb->s_blocksize_bits;
-       sector_t last_block;
-       int err, clu_offset, sec_offset;
-       unsigned int cluster;
-
-       *phys = 0;
-       *mapped_blocks = 0;
-
-       last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits;
-       if (sector >= last_block) {
-               if (*create == 0)
-                       return 0;
-       } else {
-               *create = 0;
-       }
-
-       /* cluster offset */
-       clu_offset = sector >> p_fs->sectors_per_clu_bits;
-
-       /* sector offset in cluster */
-       sec_offset = sector & (p_fs->sectors_per_clu - 1);
-
-       EXFAT_I(inode)->fid.size = i_size_read(inode);
-
-       err = ffsMapCluster(inode, clu_offset, &cluster);
-
-       if (!err && (cluster != CLUSTER_32(~0))) {
-               *phys = START_SECTOR(cluster) + sec_offset;
-               *mapped_blocks = p_fs->sectors_per_clu - sec_offset;
-       }
-
-       return 0;
-}
-
-static int exfat_get_block(struct inode *inode, sector_t iblock,
-                          struct buffer_head *bh_result, int create)
-{
-       struct super_block *sb = inode->i_sb;
-       unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
-       int err;
-       unsigned long mapped_blocks;
-       sector_t phys;
-
-       __lock_super(sb);
-
-       err = exfat_bmap(inode, iblock, &phys, &mapped_blocks, &create);
-       if (err) {
-               __unlock_super(sb);
-               return err;
-       }
-
-       if (phys) {
-               max_blocks = min(mapped_blocks, max_blocks);
-               if (create) {
-                       EXFAT_I(inode)->mmu_private += max_blocks <<
-                                                       sb->s_blocksize_bits;
-                       set_buffer_new(bh_result);
-               }
-               map_bh(bh_result, sb, phys);
-       }
-
-       bh_result->b_size = max_blocks << sb->s_blocksize_bits;
-       __unlock_super(sb);
-
-       return 0;
-}
-
-static int exfat_readpage(struct file *file, struct page *page)
-{
-       return  mpage_readpage(page, exfat_get_block);
-}
-
-static int exfat_readpages(struct file *file, struct address_space *mapping,
-                          struct list_head *pages, unsigned int nr_pages)
-{
-       return  mpage_readpages(mapping, pages, nr_pages, exfat_get_block);
-}
-
-static int exfat_writepage(struct page *page, struct writeback_control *wbc)
-{
-       return block_write_full_page(page, exfat_get_block, wbc);
-}
-
-static int exfat_writepages(struct address_space *mapping,
-                           struct writeback_control *wbc)
-{
-       return mpage_writepages(mapping, wbc, exfat_get_block);
-}
-
-static void exfat_write_failed(struct address_space *mapping, loff_t to)
-{
-       struct inode *inode = mapping->host;
-
-       if (to > i_size_read(inode)) {
-               truncate_pagecache(inode, i_size_read(inode));
-               EXFAT_I(inode)->fid.size = i_size_read(inode);
-               exfat_truncate(inode, i_size_read(inode));
-       }
-}
-
-static int exfat_write_begin(struct file *file, struct address_space *mapping,
-                            loff_t pos, unsigned int len, unsigned int flags,
-                            struct page **pagep, void **fsdata)
-{
-       int ret;
-
-       *pagep = NULL;
-       ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                              exfat_get_block,
-                              &EXFAT_I(mapping->host)->mmu_private);
-
-       if (ret < 0)
-               exfat_write_failed(mapping, pos + len);
-       return ret;
-}
-
-static int exfat_write_end(struct file *file, struct address_space *mapping,
-                          loff_t pos, unsigned int len, unsigned int copied,
-                          struct page *pagep, void *fsdata)
-{
-       struct inode *inode = mapping->host;
-       struct file_id_t *fid = &(EXFAT_I(inode)->fid);
-       struct timespec64 curtime;
-       int err;
-
-       err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
-
-       if (err < len)
-               exfat_write_failed(mapping, pos + len);
-
-       if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) {
-               curtime = current_time(inode);
-               inode->i_mtime = curtime;
-               inode->i_ctime = curtime;
-               fid->attr |= ATTR_ARCHIVE;
-               mark_inode_dirty(inode);
-       }
-       return err;
-}
-
-static ssize_t exfat_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
-{
-       struct inode *inode = iocb->ki_filp->f_mapping->host;
-       struct address_space *mapping = iocb->ki_filp->f_mapping;
-       ssize_t ret;
-       int rw;
-
-       rw = iov_iter_rw(iter);
-
-       if (rw == WRITE) {
-               if (EXFAT_I(inode)->mmu_private < iov_iter_count(iter))
-                       return 0;
-       }
-       ret = blockdev_direct_IO(iocb, inode, iter, exfat_get_block);
-
-       if ((ret < 0) && (rw & WRITE))
-               exfat_write_failed(mapping, iov_iter_count(iter));
-       return ret;
-}
-
-static sector_t _exfat_bmap(struct address_space *mapping, sector_t block)
-{
-       sector_t blocknr;
-
-       /* exfat_get_cluster() assumes the requested blocknr isn't truncated. */
-       down_read(&EXFAT_I(mapping->host)->truncate_lock);
-       blocknr = generic_block_bmap(mapping, block, exfat_get_block);
-       up_read(&EXFAT_I(mapping->host)->truncate_lock);
-
-       return blocknr;
-}
-
-static const struct address_space_operations exfat_aops = {
-       .readpage    = exfat_readpage,
-       .readpages   = exfat_readpages,
-       .writepage   = exfat_writepage,
-       .writepages  = exfat_writepages,
-       .write_begin = exfat_write_begin,
-       .write_end   = exfat_write_end,
-       .direct_IO   = exfat_direct_IO,
-       .bmap        = _exfat_bmap
-};
-
-/*======================================================================*/
-/*  Super Operations                                                    */
-/*======================================================================*/
-
-static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct exfat_inode_info *info;
-       struct hlist_head *head = sbi->inode_hashtable + exfat_hash(i_pos);
-       struct inode *inode = NULL;
-
-       spin_lock(&sbi->inode_hash_lock);
-       hlist_for_each_entry(info, head, i_hash_fat) {
-               BUG_ON(info->vfs_inode.i_sb != sb);
-
-               if (i_pos != info->i_pos)
-                       continue;
-               inode = igrab(&info->vfs_inode);
-               if (inode)
-                       break;
-       }
-       spin_unlock(&sbi->inode_hash_lock);
-       return inode;
-}
-
-/* doesn't deal with root inode */
-static int exfat_fill_inode(struct inode *inode, struct file_id_t *fid)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
-       struct fs_info_t *p_fs = &sbi->fs_info;
-       struct dir_entry_t info;
-
-       memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(struct file_id_t));
-
-       ffsReadStat(inode, &info);
-
-       EXFAT_I(inode)->i_pos = 0;
-       EXFAT_I(inode)->target = NULL;
-       inode->i_uid = sbi->options.fs_uid;
-       inode->i_gid = sbi->options.fs_gid;
-       INC_IVERSION(inode);
-       inode->i_generation = prandom_u32();
-
-       if (info.Attr & ATTR_SUBDIR) { /* directory */
-               inode->i_generation &= ~1;
-               inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777);
-               inode->i_op = &exfat_dir_inode_operations;
-               inode->i_fop = &exfat_dir_operations;
-
-               i_size_write(inode, info.Size);
-               EXFAT_I(inode)->mmu_private = i_size_read(inode);
-               set_nlink(inode, info.NumSubdirs);
-       } else if (info.Attr & ATTR_SYMLINK) { /* symbolic link */
-               inode->i_generation |= 1;
-               inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777);
-               inode->i_op = &exfat_symlink_inode_operations;
-
-               i_size_write(inode, info.Size);
-               EXFAT_I(inode)->mmu_private = i_size_read(inode);
-       } else { /* regular file */
-               inode->i_generation |= 1;
-               inode->i_mode = exfat_make_mode(sbi, info.Attr, 0777);
-               inode->i_op = &exfat_file_inode_operations;
-               inode->i_fop = &exfat_file_operations;
-               inode->i_mapping->a_ops = &exfat_aops;
-               inode->i_mapping->nrpages = 0;
-
-               i_size_write(inode, info.Size);
-               EXFAT_I(inode)->mmu_private = i_size_read(inode);
-       }
-       exfat_save_attr(inode, info.Attr);
-
-       inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1))
-                               & ~((loff_t)p_fs->cluster_size - 1)) >> 9;
-
-       exfat_time_fat2unix(&inode->i_mtime, &info.ModifyTimestamp);
-       exfat_time_fat2unix(&inode->i_ctime, &info.CreateTimestamp);
-       exfat_time_fat2unix(&inode->i_atime, &info.AccessTimestamp);
-
-       return 0;
-}
-
-static struct inode *exfat_build_inode(struct super_block *sb,
-                                      struct file_id_t *fid, loff_t i_pos)
-{
-       struct inode *inode;
-       int err;
-
-       inode = exfat_iget(sb, i_pos);
-       if (inode)
-               goto out;
-       inode = new_inode(sb);
-       if (!inode) {
-               inode = ERR_PTR(-ENOMEM);
-               goto out;
-       }
-       inode->i_ino = iunique(sb, EXFAT_ROOT_INO);
-       SET_IVERSION(inode, 1);
-       err = exfat_fill_inode(inode, fid);
-       if (err) {
-               iput(inode);
-               inode = ERR_PTR(err);
-               goto out;
-       }
-       exfat_attach(inode, i_pos);
-       insert_inode_hash(inode);
-out:
-       return inode;
-}
-
-static int exfat_sync_inode(struct inode *inode)
-{
-       return exfat_write_inode(inode, NULL);
-}
-
-static struct inode *exfat_alloc_inode(struct super_block *sb)
-{
-       struct exfat_inode_info *ei;
-
-       ei = kmem_cache_alloc(exfat_inode_cachep, GFP_NOFS);
-       if (!ei)
-               return NULL;
-
-       init_rwsem(&ei->truncate_lock);
-
-       return &ei->vfs_inode;
-}
-
-static void exfat_destroy_inode(struct inode *inode)
-{
-       kfree(EXFAT_I(inode)->target);
-       EXFAT_I(inode)->target = NULL;
-
-       kmem_cache_free(exfat_inode_cachep, EXFAT_I(inode));
-}
-
-static int exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
-{
-       struct dir_entry_t info;
-
-       if (inode->i_ino == EXFAT_ROOT_INO)
-               return 0;
-
-       info.Attr = exfat_make_attr(inode);
-       info.Size = i_size_read(inode);
-
-       exfat_time_unix2fat(&inode->i_mtime, &info.ModifyTimestamp);
-       exfat_time_unix2fat(&inode->i_ctime, &info.CreateTimestamp);
-       exfat_time_unix2fat(&inode->i_atime, &info.AccessTimestamp);
-
-       ffsWriteStat(inode, &info);
-
-       return 0;
-}
-
-static void exfat_evict_inode(struct inode *inode)
-{
-       truncate_inode_pages(&inode->i_data, 0);
-
-       if (!inode->i_nlink)
-               i_size_write(inode, 0);
-       invalidate_inode_buffers(inode);
-       clear_inode(inode);
-       exfat_detach(inode);
-
-       remove_inode_hash(inode);
-}
-
-static void exfat_free_super(struct exfat_sb_info *sbi)
-{
-       if (sbi->nls_disk)
-               unload_nls(sbi->nls_disk);
-       if (sbi->nls_io)
-               unload_nls(sbi->nls_io);
-       if (sbi->options.iocharset != exfat_default_iocharset)
-               kfree(sbi->options.iocharset);
-       /* mutex_init is in exfat_fill_super function. only for 3.7+ */
-       mutex_destroy(&sbi->s_lock);
-       kvfree(sbi);
-}
-
-static void exfat_put_super(struct super_block *sb)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-
-       if (__is_sb_dirty(sb))
-               exfat_write_super(sb);
-
-       ffsUmountVol(sb);
-
-       sb->s_fs_info = NULL;
-       exfat_free_super(sbi);
-}
-
-static void exfat_write_super(struct super_block *sb)
-{
-       __lock_super(sb);
-
-       __set_sb_clean(sb);
-
-       if (!sb_rdonly(sb))
-               ffsSyncVol(sb, true);
-
-       __unlock_super(sb);
-}
-
-static int exfat_sync_fs(struct super_block *sb, int wait)
-{
-       int err = 0;
-
-       if (__is_sb_dirty(sb)) {
-               __lock_super(sb);
-               __set_sb_clean(sb);
-               err = ffsSyncVol(sb, true);
-               __unlock_super(sb);
-       }
-
-       return err;
-}
-
-static int exfat_statfs(struct dentry *dentry, struct kstatfs *buf)
-{
-       struct super_block *sb = dentry->d_sb;
-       u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-       struct vol_info_t info;
-
-       if (p_fs->used_clusters == UINT_MAX) {
-               if (ffsGetVolInfo(sb, &info) == -EIO)
-                       return -EIO;
-
-       } else {
-               info.FatType = p_fs->vol_type;
-               info.ClusterSize = p_fs->cluster_size;
-               info.NumClusters = p_fs->num_clusters - 2;
-               info.UsedClusters = p_fs->used_clusters;
-               info.FreeClusters = info.NumClusters - info.UsedClusters;
-
-               if (p_fs->dev_ejected)
-                       pr_info("[EXFAT] statfs on device that is ejected\n");
-       }
-
-       buf->f_type = sb->s_magic;
-       buf->f_bsize = info.ClusterSize;
-       buf->f_blocks = info.NumClusters;
-       buf->f_bfree = info.FreeClusters;
-       buf->f_bavail = info.FreeClusters;
-       buf->f_fsid.val[0] = (u32)id;
-       buf->f_fsid.val[1] = (u32)(id >> 32);
-       buf->f_namelen = 260;
-
-       return 0;
-}
-
-static int exfat_remount(struct super_block *sb, int *flags, char *data)
-{
-       *flags |= SB_NODIRATIME;
-       return 0;
-}
-
-static int exfat_show_options(struct seq_file *m, struct dentry *root)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(root->d_sb);
-       struct exfat_mount_options *opts = &sbi->options;
-
-       if (__kuid_val(opts->fs_uid))
-               seq_printf(m, ",uid=%u", __kuid_val(opts->fs_uid));
-       if (__kgid_val(opts->fs_gid))
-               seq_printf(m, ",gid=%u", __kgid_val(opts->fs_gid));
-       seq_printf(m, ",fmask=%04o", opts->fs_fmask);
-       seq_printf(m, ",dmask=%04o", opts->fs_dmask);
-       if (opts->allow_utime)
-               seq_printf(m, ",allow_utime=%04o", opts->allow_utime);
-       if (sbi->nls_disk)
-               seq_printf(m, ",codepage=%s", sbi->nls_disk->charset);
-       if (sbi->nls_io)
-               seq_printf(m, ",iocharset=%s", sbi->nls_io->charset);
-       seq_printf(m, ",namecase=%u", opts->casesensitive);
-       if (opts->errors == EXFAT_ERRORS_CONT)
-               seq_puts(m, ",errors=continue");
-       else if (opts->errors == EXFAT_ERRORS_PANIC)
-               seq_puts(m, ",errors=panic");
-       else
-               seq_puts(m, ",errors=remount-ro");
-#ifdef CONFIG_STAGING_EXFAT_DISCARD
-       if (opts->discard)
-               seq_puts(m, ",discard");
-#endif
-       return 0;
-}
-
-static const struct super_operations exfat_sops = {
-       .alloc_inode   = exfat_alloc_inode,
-       .destroy_inode = exfat_destroy_inode,
-       .write_inode   = exfat_write_inode,
-       .evict_inode  = exfat_evict_inode,
-       .put_super     = exfat_put_super,
-       .sync_fs       = exfat_sync_fs,
-       .statfs        = exfat_statfs,
-       .remount_fs    = exfat_remount,
-       .show_options  = exfat_show_options,
-};
-
-/*======================================================================*/
-/*  Export Operations                                                   */
-/*======================================================================*/
-
-static struct inode *exfat_nfs_get_inode(struct super_block *sb, u64 ino,
-                                        u32 generation)
-{
-       struct inode *inode = NULL;
-
-       if (ino < EXFAT_ROOT_INO)
-               return inode;
-       inode = ilookup(sb, ino);
-
-       if (inode && generation && (inode->i_generation != generation)) {
-               iput(inode);
-               inode = NULL;
-       }
-
-       return inode;
-}
-
-static struct dentry *exfat_fh_to_dentry(struct super_block *sb,
-                                        struct fid *fid, int fh_len,
-                                        int fh_type)
-{
-       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
-                               exfat_nfs_get_inode);
-}
-
-static struct dentry *exfat_fh_to_parent(struct super_block *sb,
-                                        struct fid *fid, int fh_len,
-                                        int fh_type)
-{
-       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
-                               exfat_nfs_get_inode);
-}
-
-static const struct export_operations exfat_export_ops = {
-       .fh_to_dentry   = exfat_fh_to_dentry,
-       .fh_to_parent   = exfat_fh_to_parent,
-};
-
-/*======================================================================*/
-/*  Super Block Read Operations                                         */
-/*======================================================================*/
-
-enum {
-       Opt_uid,
-       Opt_gid,
-       Opt_umask,
-       Opt_dmask,
-       Opt_fmask,
-       Opt_allow_utime,
-       Opt_codepage,
-       Opt_charset,
-       Opt_namecase,
-       Opt_debug,
-       Opt_err_cont,
-       Opt_err_panic,
-       Opt_err_ro,
-       Opt_utf8_hack,
-       Opt_err,
-#ifdef CONFIG_STAGING_EXFAT_DISCARD
-       Opt_discard,
-#endif /* EXFAT_CONFIG_DISCARD */
-};
-
-static const match_table_t exfat_tokens = {
-       {Opt_uid, "uid=%u"},
-       {Opt_gid, "gid=%u"},
-       {Opt_umask, "umask=%o"},
-       {Opt_dmask, "dmask=%o"},
-       {Opt_fmask, "fmask=%o"},
-       {Opt_allow_utime, "allow_utime=%o"},
-       {Opt_codepage, "codepage=%u"},
-       {Opt_charset, "iocharset=%s"},
-       {Opt_namecase, "namecase=%u"},
-       {Opt_debug, "debug"},
-       {Opt_err_cont, "errors=continue"},
-       {Opt_err_panic, "errors=panic"},
-       {Opt_err_ro, "errors=remount-ro"},
-       {Opt_utf8_hack, "utf8"},
-#ifdef CONFIG_STAGING_EXFAT_DISCARD
-       {Opt_discard, "discard"},
-#endif /* CONFIG_STAGING_EXFAT_DISCARD */
-       {Opt_err, NULL}
-};
-
-static int parse_options(char *options, int silent, int *debug,
-                        struct exfat_mount_options *opts)
-{
-       char *p;
-       substring_t args[MAX_OPT_ARGS];
-       int option;
-       char *iocharset;
-
-       opts->fs_uid = current_uid();
-       opts->fs_gid = current_gid();
-       opts->fs_fmask = current->fs->umask;
-       opts->fs_dmask = current->fs->umask;
-       opts->allow_utime = U16_MAX;
-       opts->codepage = exfat_default_codepage;
-       opts->iocharset = exfat_default_iocharset;
-       opts->casesensitive = 0;
-       opts->errors = EXFAT_ERRORS_RO;
-#ifdef CONFIG_STAGING_EXFAT_DISCARD
-       opts->discard = 0;
-#endif
-       *debug = 0;
-
-       if (!options)
-               goto out;
-
-       while ((p = strsep(&options, ","))) {
-               int token;
-
-               if (!*p)
-                       continue;
-
-               token = match_token(p, exfat_tokens, args);
-               switch (token) {
-               case Opt_uid:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       opts->fs_uid = KUIDT_INIT(option);
-                       break;
-               case Opt_gid:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       opts->fs_gid = KGIDT_INIT(option);
-                       break;
-               case Opt_umask:
-               case Opt_dmask:
-               case Opt_fmask:
-                       if (match_octal(&args[0], &option))
-                               return 0;
-                       if (token != Opt_dmask)
-                               opts->fs_fmask = option;
-                       if (token != Opt_fmask)
-                               opts->fs_dmask = option;
-                       break;
-               case Opt_allow_utime:
-                       if (match_octal(&args[0], &option))
-                               return 0;
-                       opts->allow_utime = option & 0022;
-                       break;
-               case Opt_codepage:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       opts->codepage = option;
-                       break;
-               case Opt_charset:
-                       if (opts->iocharset != exfat_default_iocharset)
-                               kfree(opts->iocharset);
-                       iocharset = match_strdup(&args[0]);
-                       if (!iocharset)
-                               return -ENOMEM;
-                       opts->iocharset = iocharset;
-                       break;
-               case Opt_namecase:
-                       if (match_int(&args[0], &option))
-                               return 0;
-                       opts->casesensitive = option;
-                       break;
-               case Opt_err_cont:
-                       opts->errors = EXFAT_ERRORS_CONT;
-                       break;
-               case Opt_err_panic:
-                       opts->errors = EXFAT_ERRORS_PANIC;
-                       break;
-               case Opt_err_ro:
-                       opts->errors = EXFAT_ERRORS_RO;
-                       break;
-               case Opt_debug:
-                       *debug = 1;
-                       break;
-#ifdef CONFIG_STAGING_EXFAT_DISCARD
-               case Opt_discard:
-                       opts->discard = 1;
-                       break;
-#endif /* CONFIG_STAGING_EXFAT_DISCARD */
-               case Opt_utf8_hack:
-                       break;
-               default:
-                       if (!silent)
-                               pr_err("[EXFAT] Unrecognized mount option %s or missing value\n",
-                                      p);
-                       return -EINVAL;
-               }
-       }
-
-out:
-       if (opts->allow_utime == U16_MAX)
-               opts->allow_utime = ~opts->fs_dmask & 0022;
-
-       return 0;
-}
-
-static void exfat_hash_init(struct super_block *sb)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       int i;
-
-       spin_lock_init(&sbi->inode_hash_lock);
-       for (i = 0; i < EXFAT_HASH_SIZE; i++)
-               INIT_HLIST_HEAD(&sbi->inode_hashtable[i]);
-}
-
-static int exfat_read_root(struct inode *inode)
-{
-       struct super_block *sb = inode->i_sb;
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct fs_info_t *p_fs = &sbi->fs_info;
-       struct timespec64 curtime;
-       struct dir_entry_t info;
-
-       EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir;
-       EXFAT_I(inode)->fid.dir.flags = 0x01;
-       EXFAT_I(inode)->fid.entry = -1;
-       EXFAT_I(inode)->fid.start_clu = p_fs->root_dir;
-       EXFAT_I(inode)->fid.flags = 0x01;
-       EXFAT_I(inode)->fid.type = TYPE_DIR;
-       EXFAT_I(inode)->fid.rwoffset = 0;
-       EXFAT_I(inode)->fid.hint_last_off = -1;
-
-       EXFAT_I(inode)->target = NULL;
-
-       ffsReadStat(inode, &info);
-
-       inode->i_uid = sbi->options.fs_uid;
-       inode->i_gid = sbi->options.fs_gid;
-       INC_IVERSION(inode);
-       inode->i_generation = 0;
-       inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777);
-       inode->i_op = &exfat_dir_inode_operations;
-       inode->i_fop = &exfat_dir_operations;
-
-       i_size_write(inode, info.Size);
-       inode->i_blocks = ((i_size_read(inode) + (p_fs->cluster_size - 1))
-                               & ~((loff_t)p_fs->cluster_size - 1)) >> 9;
-       EXFAT_I(inode)->i_pos = ((loff_t)p_fs->root_dir << 32) | 0xffffffff;
-       EXFAT_I(inode)->mmu_private = i_size_read(inode);
-
-       exfat_save_attr(inode, ATTR_SUBDIR);
-       curtime = current_time(inode);
-       inode->i_mtime = curtime;
-       inode->i_atime = curtime;
-       inode->i_ctime = curtime;
-       set_nlink(inode, info.NumSubdirs + 2);
-
-       return 0;
-}
-
-static void setup_dops(struct super_block *sb)
-{
-       if (EXFAT_SB(sb)->options.casesensitive == 0)
-               sb->s_d_op = &exfat_ci_dentry_ops;
-       else
-               sb->s_d_op = &exfat_dentry_ops;
-}
-
-static int exfat_fill_super(struct super_block *sb, void *data, int silent)
-{
-       struct inode *root_inode = NULL;
-       struct exfat_sb_info *sbi;
-       int debug, ret;
-       long error;
-
-       /*
-        * GFP_KERNEL is ok here, because while we do hold the
-        * supeblock lock, memory pressure can't call back into
-        * the filesystem, since we're only just about to mount
-        * it and have no inodes etc active!
-        */
-       sbi = kvzalloc(sizeof(*sbi), GFP_KERNEL);
-       if (!sbi)
-               return -ENOMEM;
-       mutex_init(&sbi->s_lock);
-       sb->s_fs_info = sbi;
-       sb->s_flags |= SB_NODIRATIME;
-       sb->s_magic = EXFAT_SUPER_MAGIC;
-       sb->s_op = &exfat_sops;
-       sb->s_export_op = &exfat_export_ops;
-
-       error = parse_options(data, silent, &debug, &sbi->options);
-       if (error)
-               goto out_fail;
-
-       setup_dops(sb);
-
-       error = -EIO;
-       sb_min_blocksize(sb, 512);
-       sb->s_maxbytes = 0x7fffffffffffffffLL;    /* maximum file size */
-
-       ret = ffsMountVol(sb);
-       if (ret) {
-               if (!silent)
-                       pr_err("[EXFAT] ffsMountVol failed\n");
-
-               goto out_fail;
-       }
-
-       /* set up enough so that it can read an inode */
-       exfat_hash_init(sb);
-
-       /*
-        * The low byte of FAT's first entry must have same value with
-        * media-field.  But in real world, too many devices is
-        * writing wrong value.  So, removed that validity check.
-        *
-        * if (FAT_FIRST_ENT(sb, media) != first)
-        */
-
-       sbi->nls_io = load_nls(sbi->options.iocharset);
-
-       error = -ENOMEM;
-       root_inode = new_inode(sb);
-       if (!root_inode)
-               goto out_fail2;
-       root_inode->i_ino = EXFAT_ROOT_INO;
-       SET_IVERSION(root_inode, 1);
-
-       error = exfat_read_root(root_inode);
-       if (error < 0)
-               goto out_fail2;
-       error = -ENOMEM;
-       exfat_attach(root_inode, EXFAT_I(root_inode)->i_pos);
-       insert_inode_hash(root_inode);
-       sb->s_root = d_make_root(root_inode);
-       if (!sb->s_root) {
-               pr_err("[EXFAT] Getting the root inode failed\n");
-               goto out_fail2;
-       }
-
-       return 0;
-
-out_fail2:
-       ffsUmountVol(sb);
-out_fail:
-       if (root_inode)
-               iput(root_inode);
-       sb->s_fs_info = NULL;
-       exfat_free_super(sbi);
-       return error;
-}
-
-static struct dentry *exfat_fs_mount(struct file_system_type *fs_type,
-                                    int flags, const char *dev_name,
-                                    void *data)
-{
-       return mount_bdev(fs_type, flags, dev_name, data, exfat_fill_super);
-}
-
-static void init_once(void *foo)
-{
-       struct exfat_inode_info *ei = (struct exfat_inode_info *)foo;
-
-       INIT_HLIST_NODE(&ei->i_hash_fat);
-       inode_init_once(&ei->vfs_inode);
-}
-
-static int __init exfat_init_inodecache(void)
-{
-       exfat_inode_cachep = kmem_cache_create("exfat_inode_cache",
-                                              sizeof(struct exfat_inode_info),
-                                              0,
-                                              (SLAB_RECLAIM_ACCOUNT |
-                                               SLAB_MEM_SPREAD),
-                                              init_once);
-       if (!exfat_inode_cachep)
-               return -ENOMEM;
-       return 0;
-}
-
-static void __exit exfat_destroy_inodecache(void)
-{
-       /*
-        * Make sure all delayed rcu free inodes are flushed before we
-        * destroy cache.
-        */
-       rcu_barrier();
-       kmem_cache_destroy(exfat_inode_cachep);
-}
-
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-static void exfat_debug_kill_sb(struct super_block *sb)
-{
-       struct exfat_sb_info *sbi = EXFAT_SB(sb);
-       struct block_device *bdev = sb->s_bdev;
-       struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info);
-
-       long flags;
-
-       if (sbi) {
-               flags = sbi->debug_flags;
-
-               if (flags & EXFAT_DEBUGFLAGS_INVALID_UMOUNT) {
-                       /*
-                        * invalidate_bdev drops all device cache include
-                        * dirty. We use this to simulate device removal.
-                        */
-                       mutex_lock(&p_fs->v_mutex);
-                       exfat_fat_release_all(sb);
-                       exfat_buf_release_all(sb);
-                       mutex_unlock(&p_fs->v_mutex);
-
-                       invalidate_bdev(bdev);
-               }
-       }
-
-       kill_block_super(sb);
-}
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-
-static struct file_system_type exfat_fs_type = {
-       .owner       = THIS_MODULE,
-       .name        = "exfat",
-       .mount       = exfat_fs_mount,
-#ifdef CONFIG_STAGING_EXFAT_KERNEL_DEBUG
-       .kill_sb    = exfat_debug_kill_sb,
-#else
-       .kill_sb    = kill_block_super,
-#endif /* CONFIG_STAGING_EXFAT_KERNEL_DEBUG */
-       .fs_flags    = FS_REQUIRES_DEV,
-};
-
-static int __init init_exfat(void)
-{
-       int err;
-
-       BUILD_BUG_ON(sizeof(struct dentry_t) != DENTRY_SIZE);
-       BUILD_BUG_ON(sizeof(struct dos_dentry_t) != DENTRY_SIZE);
-       BUILD_BUG_ON(sizeof(struct ext_dentry_t) != DENTRY_SIZE);
-       BUILD_BUG_ON(sizeof(struct file_dentry_t) != DENTRY_SIZE);
-       BUILD_BUG_ON(sizeof(struct strm_dentry_t) != DENTRY_SIZE);
-       BUILD_BUG_ON(sizeof(struct name_dentry_t) != DENTRY_SIZE);
-       BUILD_BUG_ON(sizeof(struct bmap_dentry_t) != DENTRY_SIZE);
-       BUILD_BUG_ON(sizeof(struct case_dentry_t) != DENTRY_SIZE);
-       BUILD_BUG_ON(sizeof(struct volm_dentry_t) != DENTRY_SIZE);
-
-       pr_info("exFAT: Version %s\n", EXFAT_VERSION);
-
-       err = exfat_init_inodecache();
-       if (err)
-               return err;
-
-       err = register_filesystem(&exfat_fs_type);
-       if (err)
-               return err;
-
-       return 0;
-}
-
-static void __exit exit_exfat(void)
-{
-       exfat_destroy_inodecache();
-       unregister_filesystem(&exfat_fs_type);
-}
-
-module_init(init_exfat);
-module_exit(exit_exfat);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("exFAT Filesystem Driver");
-MODULE_ALIAS_FS("exfat");
diff --git a/drivers/staging/exfat/exfat_upcase.c b/drivers/staging/exfat/exfat_upcase.c
deleted file mode 100644 (file)
index b91a1fa..0000000
+++ /dev/null
@@ -1,740 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
- */
-
-#include <linux/types.h>
-#include "exfat.h"
-
-const u8 uni_upcase[NUM_UPCASE << 1] = {
-       0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00,
-       0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00,
-       0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0x0B, 0x00,
-       0x0C, 0x00, 0x0D, 0x00, 0x0E, 0x00, 0x0F, 0x00,
-       0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00,
-       0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
-       0x18, 0x00, 0x19, 0x00, 0x1A, 0x00, 0x1B, 0x00,
-       0x1C, 0x00, 0x1D, 0x00, 0x1E, 0x00, 0x1F, 0x00,
-       0x20, 0x00, 0x21, 0x00, 0x22, 0x00, 0x23, 0x00,
-       0x24, 0x00, 0x25, 0x00, 0x26, 0x00, 0x27, 0x00,
-       0x28, 0x00, 0x29, 0x00, 0x2A, 0x00, 0x2B, 0x00,
-       0x2C, 0x00, 0x2D, 0x00, 0x2E, 0x00, 0x2F, 0x00,
-       0x30, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00,
-       0x34, 0x00, 0x35, 0x00, 0x36, 0x00, 0x37, 0x00,
-       0x38, 0x00, 0x39, 0x00, 0x3A, 0x00, 0x3B, 0x00,
-       0x3C, 0x00, 0x3D, 0x00, 0x3E, 0x00, 0x3F, 0x00,
-       0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00,
-       0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
-       0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00,
-       0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00,
-       0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
-       0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
-       0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x5B, 0x00,
-       0x5C, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x5F, 0x00,
-       0x60, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00,
-       0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00,
-       0x48, 0x00, 0x49, 0x00, 0x4A, 0x00, 0x4B, 0x00,
-       0x4C, 0x00, 0x4D, 0x00, 0x4E, 0x00, 0x4F, 0x00,
-       0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
-       0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x00,
-       0x58, 0x00, 0x59, 0x00, 0x5A, 0x00, 0x7B, 0x00,
-       0x7C, 0x00, 0x7D, 0x00, 0x7E, 0x00, 0x7F, 0x00,
-       0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00,
-       0x84, 0x00, 0x85, 0x00, 0x86, 0x00, 0x87, 0x00,
-       0x88, 0x00, 0x89, 0x00, 0x8A, 0x00, 0x8B, 0x00,
-       0x8C, 0x00, 0x8D, 0x00, 0x8E, 0x00, 0x8F, 0x00,
-       0x90, 0x00, 0x91, 0x00, 0x92, 0x00, 0x93, 0x00,
-       0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00,
-       0x98, 0x00, 0x99, 0x00, 0x9A, 0x00, 0x9B, 0x00,
-       0x9C, 0x00, 0x9D, 0x00, 0x9E, 0x00, 0x9F, 0x00,
-       0xA0, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, 0x00,
-       0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, 0x00,
-       0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, 0x00,
-       0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, 0x00,
-       0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, 0x00,
-       0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, 0x00,
-       0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, 0x00,
-       0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, 0x00,
-       0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00,
-       0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00,
-       0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00,
-       0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00,
-       0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00,
-       0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, 0x00,
-       0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00,
-       0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, 0x00,
-       0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, 0x00,
-       0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, 0x00,
-       0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, 0x00,
-       0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, 0x00,
-       0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, 0x00,
-       0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xF7, 0x00,
-       0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, 0x00,
-       0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0x78, 0x01,
-       0x00, 0x01, 0x00, 0x01, 0x02, 0x01, 0x02, 0x01,
-       0x04, 0x01, 0x04, 0x01, 0x06, 0x01, 0x06, 0x01,
-       0x08, 0x01, 0x08, 0x01, 0x0A, 0x01, 0x0A, 0x01,
-       0x0C, 0x01, 0x0C, 0x01, 0x0E, 0x01, 0x0E, 0x01,
-       0x10, 0x01, 0x10, 0x01, 0x12, 0x01, 0x12, 0x01,
-       0x14, 0x01, 0x14, 0x01, 0x16, 0x01, 0x16, 0x01,
-       0x18, 0x01, 0x18, 0x01, 0x1A, 0x01, 0x1A, 0x01,
-       0x1C, 0x01, 0x1C, 0x01, 0x1E, 0x01, 0x1E, 0x01,
-       0x20, 0x01, 0x20, 0x01, 0x22, 0x01, 0x22, 0x01,
-       0x24, 0x01, 0x24, 0x01, 0x26, 0x01, 0x26, 0x01,
-       0x28, 0x01, 0x28, 0x01, 0x2A, 0x01, 0x2A, 0x01,
-       0x2C, 0x01, 0x2C, 0x01, 0x2E, 0x01, 0x2E, 0x01,
-       0x30, 0x01, 0x31, 0x01, 0x32, 0x01, 0x32, 0x01,
-       0x34, 0x01, 0x34, 0x01, 0x36, 0x01, 0x36, 0x01,
-       0x38, 0x01, 0x39, 0x01, 0x39, 0x01, 0x3B, 0x01,
-       0x3B, 0x01, 0x3D, 0x01, 0x3D, 0x01, 0x3F, 0x01,
-       0x3F, 0x01, 0x41, 0x01, 0x41, 0x01, 0x43, 0x01,
-       0x43, 0x01, 0x45, 0x01, 0x45, 0x01, 0x47, 0x01,
-       0x47, 0x01, 0x49, 0x01, 0x4A, 0x01, 0x4A, 0x01,
-       0x4C, 0x01, 0x4C, 0x01, 0x4E, 0x01, 0x4E, 0x01,
-       0x50, 0x01, 0x50, 0x01, 0x52, 0x01, 0x52, 0x01,
-       0x54, 0x01, 0x54, 0x01, 0x56, 0x01, 0x56, 0x01,
-       0x58, 0x01, 0x58, 0x01, 0x5A, 0x01, 0x5A, 0x01,
-       0x5C, 0x01, 0x5C, 0x01, 0x5E, 0x01, 0x5E, 0x01,
-       0x60, 0x01, 0x60, 0x01, 0x62, 0x01, 0x62, 0x01,
-       0x64, 0x01, 0x64, 0x01, 0x66, 0x01, 0x66, 0x01,
-       0x68, 0x01, 0x68, 0x01, 0x6A, 0x01, 0x6A, 0x01,
-       0x6C, 0x01, 0x6C, 0x01, 0x6E, 0x01, 0x6E, 0x01,
-       0x70, 0x01, 0x70, 0x01, 0x72, 0x01, 0x72, 0x01,
-       0x74, 0x01, 0x74, 0x01, 0x76, 0x01, 0x76, 0x01,
-       0x78, 0x01, 0x79, 0x01, 0x79, 0x01, 0x7B, 0x01,
-       0x7B, 0x01, 0x7D, 0x01, 0x7D, 0x01, 0x7F, 0x01,
-       0x43, 0x02, 0x81, 0x01, 0x82, 0x01, 0x82, 0x01,
-       0x84, 0x01, 0x84, 0x01, 0x86, 0x01, 0x87, 0x01,
-       0x87, 0x01, 0x89, 0x01, 0x8A, 0x01, 0x8B, 0x01,
-       0x8B, 0x01, 0x8D, 0x01, 0x8E, 0x01, 0x8F, 0x01,
-       0x90, 0x01, 0x91, 0x01, 0x91, 0x01, 0x93, 0x01,
-       0x94, 0x01, 0xF6, 0x01, 0x96, 0x01, 0x97, 0x01,
-       0x98, 0x01, 0x98, 0x01, 0x3D, 0x02, 0x9B, 0x01,
-       0x9C, 0x01, 0x9D, 0x01, 0x20, 0x02, 0x9F, 0x01,
-       0xA0, 0x01, 0xA0, 0x01, 0xA2, 0x01, 0xA2, 0x01,
-       0xA4, 0x01, 0xA4, 0x01, 0xA6, 0x01, 0xA7, 0x01,
-       0xA7, 0x01, 0xA9, 0x01, 0xAA, 0x01, 0xAB, 0x01,
-       0xAC, 0x01, 0xAC, 0x01, 0xAE, 0x01, 0xAF, 0x01,
-       0xAF, 0x01, 0xB1, 0x01, 0xB2, 0x01, 0xB3, 0x01,
-       0xB3, 0x01, 0xB5, 0x01, 0xB5, 0x01, 0xB7, 0x01,
-       0xB8, 0x01, 0xB8, 0x01, 0xBA, 0x01, 0xBB, 0x01,
-       0xBC, 0x01, 0xBC, 0x01, 0xBE, 0x01, 0xF7, 0x01,
-       0xC0, 0x01, 0xC1, 0x01, 0xC2, 0x01, 0xC3, 0x01,
-       0xC4, 0x01, 0xC5, 0x01, 0xC4, 0x01, 0xC7, 0x01,
-       0xC8, 0x01, 0xC7, 0x01, 0xCA, 0x01, 0xCB, 0x01,
-       0xCA, 0x01, 0xCD, 0x01, 0xCD, 0x01, 0xCF, 0x01,
-       0xCF, 0x01, 0xD1, 0x01, 0xD1, 0x01, 0xD3, 0x01,
-       0xD3, 0x01, 0xD5, 0x01, 0xD5, 0x01, 0xD7, 0x01,
-       0xD7, 0x01, 0xD9, 0x01, 0xD9, 0x01, 0xDB, 0x01,
-       0xDB, 0x01, 0x8E, 0x01, 0xDE, 0x01, 0xDE, 0x01,
-       0xE0, 0x01, 0xE0, 0x01, 0xE2, 0x01, 0xE2, 0x01,
-       0xE4, 0x01, 0xE4, 0x01, 0xE6, 0x01, 0xE6, 0x01,
-       0xE8, 0x01, 0xE8, 0x01, 0xEA, 0x01, 0xEA, 0x01,
-       0xEC, 0x01, 0xEC, 0x01, 0xEE, 0x01, 0xEE, 0x01,
-       0xF0, 0x01, 0xF1, 0x01, 0xF2, 0x01, 0xF1, 0x01,
-       0xF4, 0x01, 0xF4, 0x01, 0xF6, 0x01, 0xF7, 0x01,
-       0xF8, 0x01, 0xF8, 0x01, 0xFA, 0x01, 0xFA, 0x01,
-       0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0xFE, 0x01,
-       0x00, 0x02, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
-       0x04, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x02,
-       0x08, 0x02, 0x08, 0x02, 0x0A, 0x02, 0x0A, 0x02,
-       0x0C, 0x02, 0x0C, 0x02, 0x0E, 0x02, 0x0E, 0x02,
-       0x10, 0x02, 0x10, 0x02, 0x12, 0x02, 0x12, 0x02,
-       0x14, 0x02, 0x14, 0x02, 0x16, 0x02, 0x16, 0x02,
-       0x18, 0x02, 0x18, 0x02, 0x1A, 0x02, 0x1A, 0x02,
-       0x1C, 0x02, 0x1C, 0x02, 0x1E, 0x02, 0x1E, 0x02,
-       0x20, 0x02, 0x21, 0x02, 0x22, 0x02, 0x22, 0x02,
-       0x24, 0x02, 0x24, 0x02, 0x26, 0x02, 0x26, 0x02,
-       0x28, 0x02, 0x28, 0x02, 0x2A, 0x02, 0x2A, 0x02,
-       0x2C, 0x02, 0x2C, 0x02, 0x2E, 0x02, 0x2E, 0x02,
-       0x30, 0x02, 0x30, 0x02, 0x32, 0x02, 0x32, 0x02,
-       0x34, 0x02, 0x35, 0x02, 0x36, 0x02, 0x37, 0x02,
-       0x38, 0x02, 0x39, 0x02, 0x65, 0x2C, 0x3B, 0x02,
-       0x3B, 0x02, 0x3D, 0x02, 0x66, 0x2C, 0x3F, 0x02,
-       0x40, 0x02, 0x41, 0x02, 0x41, 0x02, 0x43, 0x02,
-       0x44, 0x02, 0x45, 0x02, 0x46, 0x02, 0x46, 0x02,
-       0x48, 0x02, 0x48, 0x02, 0x4A, 0x02, 0x4A, 0x02,
-       0x4C, 0x02, 0x4C, 0x02, 0x4E, 0x02, 0x4E, 0x02,
-       0x50, 0x02, 0x51, 0x02, 0x52, 0x02, 0x81, 0x01,
-       0x86, 0x01, 0x55, 0x02, 0x89, 0x01, 0x8A, 0x01,
-       0x58, 0x02, 0x8F, 0x01, 0x5A, 0x02, 0x90, 0x01,
-       0x5C, 0x02, 0x5D, 0x02, 0x5E, 0x02, 0x5F, 0x02,
-       0x93, 0x01, 0x61, 0x02, 0x62, 0x02, 0x94, 0x01,
-       0x64, 0x02, 0x65, 0x02, 0x66, 0x02, 0x67, 0x02,
-       0x97, 0x01, 0x96, 0x01, 0x6A, 0x02, 0x62, 0x2C,
-       0x6C, 0x02, 0x6D, 0x02, 0x6E, 0x02, 0x9C, 0x01,
-       0x70, 0x02, 0x71, 0x02, 0x9D, 0x01, 0x73, 0x02,
-       0x74, 0x02, 0x9F, 0x01, 0x76, 0x02, 0x77, 0x02,
-       0x78, 0x02, 0x79, 0x02, 0x7A, 0x02, 0x7B, 0x02,
-       0x7C, 0x02, 0x64, 0x2C, 0x7E, 0x02, 0x7F, 0x02,
-       0xA6, 0x01, 0x81, 0x02, 0x82, 0x02, 0xA9, 0x01,
-       0x84, 0x02, 0x85, 0x02, 0x86, 0x02, 0x87, 0x02,
-       0xAE, 0x01, 0x44, 0x02, 0xB1, 0x01, 0xB2, 0x01,
-       0x45, 0x02, 0x8D, 0x02, 0x8E, 0x02, 0x8F, 0x02,
-       0x90, 0x02, 0x91, 0x02, 0xB7, 0x01, 0x93, 0x02,
-       0x94, 0x02, 0x95, 0x02, 0x96, 0x02, 0x97, 0x02,
-       0x98, 0x02, 0x99, 0x02, 0x9A, 0x02, 0x9B, 0x02,
-       0x9C, 0x02, 0x9D, 0x02, 0x9E, 0x02, 0x9F, 0x02,
-       0xA0, 0x02, 0xA1, 0x02, 0xA2, 0x02, 0xA3, 0x02,
-       0xA4, 0x02, 0xA5, 0x02, 0xA6, 0x02, 0xA7, 0x02,
-       0xA8, 0x02, 0xA9, 0x02, 0xAA, 0x02, 0xAB, 0x02,
-       0xAC, 0x02, 0xAD, 0x02, 0xAE, 0x02, 0xAF, 0x02,
-       0xB0, 0x02, 0xB1, 0x02, 0xB2, 0x02, 0xB3, 0x02,
-       0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, 0xB7, 0x02,
-       0xB8, 0x02, 0xB9, 0x02, 0xBA, 0x02, 0xBB, 0x02,
-       0xBC, 0x02, 0xBD, 0x02, 0xBE, 0x02, 0xBF, 0x02,
-       0xC0, 0x02, 0xC1, 0x02, 0xC2, 0x02, 0xC3, 0x02,
-       0xC4, 0x02, 0xC5, 0x02, 0xC6, 0x02, 0xC7, 0x02,
-       0xC8, 0x02, 0xC9, 0x02, 0xCA, 0x02, 0xCB, 0x02,
-       0xCC, 0x02, 0xCD, 0x02, 0xCE, 0x02, 0xCF, 0x02,
-       0xD0, 0x02, 0xD1, 0x02, 0xD2, 0x02, 0xD3, 0x02,
-       0xD4, 0x02, 0xD5, 0x02, 0xD6, 0x02, 0xD7, 0x02,
-       0xD8, 0x02, 0xD9, 0x02, 0xDA, 0x02, 0xDB, 0x02,
-       0xDC, 0x02, 0xDD, 0x02, 0xDE, 0x02, 0xDF, 0x02,
-       0xE0, 0x02, 0xE1, 0x02, 0xE2, 0x02, 0xE3, 0x02,
-       0xE4, 0x02, 0xE5, 0x02, 0xE6, 0x02, 0xE7, 0x02,
-       0xE8, 0x02, 0xE9, 0x02, 0xEA, 0x02, 0xEB, 0x02,
-       0xEC, 0x02, 0xED, 0x02, 0xEE, 0x02, 0xEF, 0x02,
-       0xF0, 0x02, 0xF1, 0x02, 0xF2, 0x02, 0xF3, 0x02,
-       0xF4, 0x02, 0xF5, 0x02, 0xF6, 0x02, 0xF7, 0x02,
-       0xF8, 0x02, 0xF9, 0x02, 0xFA, 0x02, 0xFB, 0x02,
-       0xFC, 0x02, 0xFD, 0x02, 0xFE, 0x02, 0xFF, 0x02,
-       0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03,
-       0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x07, 0x03,
-       0x08, 0x03, 0x09, 0x03, 0x0A, 0x03, 0x0B, 0x03,
-       0x0C, 0x03, 0x0D, 0x03, 0x0E, 0x03, 0x0F, 0x03,
-       0x10, 0x03, 0x11, 0x03, 0x12, 0x03, 0x13, 0x03,
-       0x14, 0x03, 0x15, 0x03, 0x16, 0x03, 0x17, 0x03,
-       0x18, 0x03, 0x19, 0x03, 0x1A, 0x03, 0x1B, 0x03,
-       0x1C, 0x03, 0x1D, 0x03, 0x1E, 0x03, 0x1F, 0x03,
-       0x20, 0x03, 0x21, 0x03, 0x22, 0x03, 0x23, 0x03,
-       0x24, 0x03, 0x25, 0x03, 0x26, 0x03, 0x27, 0x03,
-       0x28, 0x03, 0x29, 0x03, 0x2A, 0x03, 0x2B, 0x03,
-       0x2C, 0x03, 0x2D, 0x03, 0x2E, 0x03, 0x2F, 0x03,
-       0x30, 0x03, 0x31, 0x03, 0x32, 0x03, 0x33, 0x03,
-       0x34, 0x03, 0x35, 0x03, 0x36, 0x03, 0x37, 0x03,
-       0x38, 0x03, 0x39, 0x03, 0x3A, 0x03, 0x3B, 0x03,
-       0x3C, 0x03, 0x3D, 0x03, 0x3E, 0x03, 0x3F, 0x03,
-       0x40, 0x03, 0x41, 0x03, 0x42, 0x03, 0x43, 0x03,
-       0x44, 0x03, 0x45, 0x03, 0x46, 0x03, 0x47, 0x03,
-       0x48, 0x03, 0x49, 0x03, 0x4A, 0x03, 0x4B, 0x03,
-       0x4C, 0x03, 0x4D, 0x03, 0x4E, 0x03, 0x4F, 0x03,
-       0x50, 0x03, 0x51, 0x03, 0x52, 0x03, 0x53, 0x03,
-       0x54, 0x03, 0x55, 0x03, 0x56, 0x03, 0x57, 0x03,
-       0x58, 0x03, 0x59, 0x03, 0x5A, 0x03, 0x5B, 0x03,
-       0x5C, 0x03, 0x5D, 0x03, 0x5E, 0x03, 0x5F, 0x03,
-       0x60, 0x03, 0x61, 0x03, 0x62, 0x03, 0x63, 0x03,
-       0x64, 0x03, 0x65, 0x03, 0x66, 0x03, 0x67, 0x03,
-       0x68, 0x03, 0x69, 0x03, 0x6A, 0x03, 0x6B, 0x03,
-       0x6C, 0x03, 0x6D, 0x03, 0x6E, 0x03, 0x6F, 0x03,
-       0x70, 0x03, 0x71, 0x03, 0x72, 0x03, 0x73, 0x03,
-       0x74, 0x03, 0x75, 0x03, 0x76, 0x03, 0x77, 0x03,
-       0x78, 0x03, 0x79, 0x03, 0x7A, 0x03, 0xFD, 0x03,
-       0xFE, 0x03, 0xFF, 0x03, 0x7E, 0x03, 0x7F, 0x03,
-       0x80, 0x03, 0x81, 0x03, 0x82, 0x03, 0x83, 0x03,
-       0x84, 0x03, 0x85, 0x03, 0x86, 0x03, 0x87, 0x03,
-       0x88, 0x03, 0x89, 0x03, 0x8A, 0x03, 0x8B, 0x03,
-       0x8C, 0x03, 0x8D, 0x03, 0x8E, 0x03, 0x8F, 0x03,
-       0x90, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
-       0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
-       0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03,
-       0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03,
-       0xA0, 0x03, 0xA1, 0x03, 0xA2, 0x03, 0xA3, 0x03,
-       0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03,
-       0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03,
-       0x86, 0x03, 0x88, 0x03, 0x89, 0x03, 0x8A, 0x03,
-       0xB0, 0x03, 0x91, 0x03, 0x92, 0x03, 0x93, 0x03,
-       0x94, 0x03, 0x95, 0x03, 0x96, 0x03, 0x97, 0x03,
-       0x98, 0x03, 0x99, 0x03, 0x9A, 0x03, 0x9B, 0x03,
-       0x9C, 0x03, 0x9D, 0x03, 0x9E, 0x03, 0x9F, 0x03,
-       0xA0, 0x03, 0xA1, 0x03, 0xA3, 0x03, 0xA3, 0x03,
-       0xA4, 0x03, 0xA5, 0x03, 0xA6, 0x03, 0xA7, 0x03,
-       0xA8, 0x03, 0xA9, 0x03, 0xAA, 0x03, 0xAB, 0x03,
-       0x8C, 0x03, 0x8E, 0x03, 0x8F, 0x03, 0xCF, 0x03,
-       0xD0, 0x03, 0xD1, 0x03, 0xD2, 0x03, 0xD3, 0x03,
-       0xD4, 0x03, 0xD5, 0x03, 0xD6, 0x03, 0xD7, 0x03,
-       0xD8, 0x03, 0xD8, 0x03, 0xDA, 0x03, 0xDA, 0x03,
-       0xDC, 0x03, 0xDC, 0x03, 0xDE, 0x03, 0xDE, 0x03,
-       0xE0, 0x03, 0xE0, 0x03, 0xE2, 0x03, 0xE2, 0x03,
-       0xE4, 0x03, 0xE4, 0x03, 0xE6, 0x03, 0xE6, 0x03,
-       0xE8, 0x03, 0xE8, 0x03, 0xEA, 0x03, 0xEA, 0x03,
-       0xEC, 0x03, 0xEC, 0x03, 0xEE, 0x03, 0xEE, 0x03,
-       0xF0, 0x03, 0xF1, 0x03, 0xF9, 0x03, 0xF3, 0x03,
-       0xF4, 0x03, 0xF5, 0x03, 0xF6, 0x03, 0xF7, 0x03,
-       0xF7, 0x03, 0xF9, 0x03, 0xFA, 0x03, 0xFA, 0x03,
-       0xFC, 0x03, 0xFD, 0x03, 0xFE, 0x03, 0xFF, 0x03,
-       0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04,
-       0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
-       0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04,
-       0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04,
-       0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
-       0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
-       0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04,
-       0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04,
-       0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
-       0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
-       0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04,
-       0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04,
-       0x10, 0x04, 0x11, 0x04, 0x12, 0x04, 0x13, 0x04,
-       0x14, 0x04, 0x15, 0x04, 0x16, 0x04, 0x17, 0x04,
-       0x18, 0x04, 0x19, 0x04, 0x1A, 0x04, 0x1B, 0x04,
-       0x1C, 0x04, 0x1D, 0x04, 0x1E, 0x04, 0x1F, 0x04,
-       0x20, 0x04, 0x21, 0x04, 0x22, 0x04, 0x23, 0x04,
-       0x24, 0x04, 0x25, 0x04, 0x26, 0x04, 0x27, 0x04,
-       0x28, 0x04, 0x29, 0x04, 0x2A, 0x04, 0x2B, 0x04,
-       0x2C, 0x04, 0x2D, 0x04, 0x2E, 0x04, 0x2F, 0x04,
-       0x00, 0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x04,
-       0x04, 0x04, 0x05, 0x04, 0x06, 0x04, 0x07, 0x04,
-       0x08, 0x04, 0x09, 0x04, 0x0A, 0x04, 0x0B, 0x04,
-       0x0C, 0x04, 0x0D, 0x04, 0x0E, 0x04, 0x0F, 0x04,
-       0x60, 0x04, 0x60, 0x04, 0x62, 0x04, 0x62, 0x04,
-       0x64, 0x04, 0x64, 0x04, 0x66, 0x04, 0x66, 0x04,
-       0x68, 0x04, 0x68, 0x04, 0x6A, 0x04, 0x6A, 0x04,
-       0x6C, 0x04, 0x6C, 0x04, 0x6E, 0x04, 0x6E, 0x04,
-       0x70, 0x04, 0x70, 0x04, 0x72, 0x04, 0x72, 0x04,
-       0x74, 0x04, 0x74, 0x04, 0x76, 0x04, 0x76, 0x04,
-       0x78, 0x04, 0x78, 0x04, 0x7A, 0x04, 0x7A, 0x04,
-       0x7C, 0x04, 0x7C, 0x04, 0x7E, 0x04, 0x7E, 0x04,
-       0x80, 0x04, 0x80, 0x04, 0x82, 0x04, 0x83, 0x04,
-       0x84, 0x04, 0x85, 0x04, 0x86, 0x04, 0x87, 0x04,
-       0x88, 0x04, 0x89, 0x04, 0x8A, 0x04, 0x8A, 0x04,
-       0x8C, 0x04, 0x8C, 0x04, 0x8E, 0x04, 0x8E, 0x04,
-       0x90, 0x04, 0x90, 0x04, 0x92, 0x04, 0x92, 0x04,
-       0x94, 0x04, 0x94, 0x04, 0x96, 0x04, 0x96, 0x04,
-       0x98, 0x04, 0x98, 0x04, 0x9A, 0x04, 0x9A, 0x04,
-       0x9C, 0x04, 0x9C, 0x04, 0x9E, 0x04, 0x9E, 0x04,
-       0xA0, 0x04, 0xA0, 0x04, 0xA2, 0x04, 0xA2, 0x04,
-       0xA4, 0x04, 0xA4, 0x04, 0xA6, 0x04, 0xA6, 0x04,
-       0xA8, 0x04, 0xA8, 0x04, 0xAA, 0x04, 0xAA, 0x04,
-       0xAC, 0x04, 0xAC, 0x04, 0xAE, 0x04, 0xAE, 0x04,
-       0xB0, 0x04, 0xB0, 0x04, 0xB2, 0x04, 0xB2, 0x04,
-       0xB4, 0x04, 0xB4, 0x04, 0xB6, 0x04, 0xB6, 0x04,
-       0xB8, 0x04, 0xB8, 0x04, 0xBA, 0x04, 0xBA, 0x04,
-       0xBC, 0x04, 0xBC, 0x04, 0xBE, 0x04, 0xBE, 0x04,
-       0xC0, 0x04, 0xC1, 0x04, 0xC1, 0x04, 0xC3, 0x04,
-       0xC3, 0x04, 0xC5, 0x04, 0xC5, 0x04, 0xC7, 0x04,
-       0xC7, 0x04, 0xC9, 0x04, 0xC9, 0x04, 0xCB, 0x04,
-       0xCB, 0x04, 0xCD, 0x04, 0xCD, 0x04, 0xC0, 0x04,
-       0xD0, 0x04, 0xD0, 0x04, 0xD2, 0x04, 0xD2, 0x04,
-       0xD4, 0x04, 0xD4, 0x04, 0xD6, 0x04, 0xD6, 0x04,
-       0xD8, 0x04, 0xD8, 0x04, 0xDA, 0x04, 0xDA, 0x04,
-       0xDC, 0x04, 0xDC, 0x04, 0xDE, 0x04, 0xDE, 0x04,
-       0xE0, 0x04, 0xE0, 0x04, 0xE2, 0x04, 0xE2, 0x04,
-       0xE4, 0x04, 0xE4, 0x04, 0xE6, 0x04, 0xE6, 0x04,
-       0xE8, 0x04, 0xE8, 0x04, 0xEA, 0x04, 0xEA, 0x04,
-       0xEC, 0x04, 0xEC, 0x04, 0xEE, 0x04, 0xEE, 0x04,
-       0xF0, 0x04, 0xF0, 0x04, 0xF2, 0x04, 0xF2, 0x04,
-       0xF4, 0x04, 0xF4, 0x04, 0xF6, 0x04, 0xF6, 0x04,
-       0xF8, 0x04, 0xF8, 0x04, 0xFA, 0x04, 0xFA, 0x04,
-       0xFC, 0x04, 0xFC, 0x04, 0xFE, 0x04, 0xFE, 0x04,
-       0x00, 0x05, 0x00, 0x05, 0x02, 0x05, 0x02, 0x05,
-       0x04, 0x05, 0x04, 0x05, 0x06, 0x05, 0x06, 0x05,
-       0x08, 0x05, 0x08, 0x05, 0x0A, 0x05, 0x0A, 0x05,
-       0x0C, 0x05, 0x0C, 0x05, 0x0E, 0x05, 0x0E, 0x05,
-       0x10, 0x05, 0x10, 0x05, 0x12, 0x05, 0x12, 0x05,
-       0x14, 0x05, 0x15, 0x05, 0x16, 0x05, 0x17, 0x05,
-       0x18, 0x05, 0x19, 0x05, 0x1A, 0x05, 0x1B, 0x05,
-       0x1C, 0x05, 0x1D, 0x05, 0x1E, 0x05, 0x1F, 0x05,
-       0x20, 0x05, 0x21, 0x05, 0x22, 0x05, 0x23, 0x05,
-       0x24, 0x05, 0x25, 0x05, 0x26, 0x05, 0x27, 0x05,
-       0x28, 0x05, 0x29, 0x05, 0x2A, 0x05, 0x2B, 0x05,
-       0x2C, 0x05, 0x2D, 0x05, 0x2E, 0x05, 0x2F, 0x05,
-       0x30, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
-       0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
-       0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05,
-       0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05,
-       0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05,
-       0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
-       0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05,
-       0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05,
-       0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05,
-       0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0x57, 0x05,
-       0x58, 0x05, 0x59, 0x05, 0x5A, 0x05, 0x5B, 0x05,
-       0x5C, 0x05, 0x5D, 0x05, 0x5E, 0x05, 0x5F, 0x05,
-       0x60, 0x05, 0x31, 0x05, 0x32, 0x05, 0x33, 0x05,
-       0x34, 0x05, 0x35, 0x05, 0x36, 0x05, 0x37, 0x05,
-       0x38, 0x05, 0x39, 0x05, 0x3A, 0x05, 0x3B, 0x05,
-       0x3C, 0x05, 0x3D, 0x05, 0x3E, 0x05, 0x3F, 0x05,
-       0x40, 0x05, 0x41, 0x05, 0x42, 0x05, 0x43, 0x05,
-       0x44, 0x05, 0x45, 0x05, 0x46, 0x05, 0x47, 0x05,
-       0x48, 0x05, 0x49, 0x05, 0x4A, 0x05, 0x4B, 0x05,
-       0x4C, 0x05, 0x4D, 0x05, 0x4E, 0x05, 0x4F, 0x05,
-       0x50, 0x05, 0x51, 0x05, 0x52, 0x05, 0x53, 0x05,
-       0x54, 0x05, 0x55, 0x05, 0x56, 0x05, 0xFF, 0xFF,
-       0xF6, 0x17, 0x63, 0x2C, 0x7E, 0x1D, 0x7F, 0x1D,
-       0x80, 0x1D, 0x81, 0x1D, 0x82, 0x1D, 0x83, 0x1D,
-       0x84, 0x1D, 0x85, 0x1D, 0x86, 0x1D, 0x87, 0x1D,
-       0x88, 0x1D, 0x89, 0x1D, 0x8A, 0x1D, 0x8B, 0x1D,
-       0x8C, 0x1D, 0x8D, 0x1D, 0x8E, 0x1D, 0x8F, 0x1D,
-       0x90, 0x1D, 0x91, 0x1D, 0x92, 0x1D, 0x93, 0x1D,
-       0x94, 0x1D, 0x95, 0x1D, 0x96, 0x1D, 0x97, 0x1D,
-       0x98, 0x1D, 0x99, 0x1D, 0x9A, 0x1D, 0x9B, 0x1D,
-       0x9C, 0x1D, 0x9D, 0x1D, 0x9E, 0x1D, 0x9F, 0x1D,
-       0xA0, 0x1D, 0xA1, 0x1D, 0xA2, 0x1D, 0xA3, 0x1D,
-       0xA4, 0x1D, 0xA5, 0x1D, 0xA6, 0x1D, 0xA7, 0x1D,
-       0xA8, 0x1D, 0xA9, 0x1D, 0xAA, 0x1D, 0xAB, 0x1D,
-       0xAC, 0x1D, 0xAD, 0x1D, 0xAE, 0x1D, 0xAF, 0x1D,
-       0xB0, 0x1D, 0xB1, 0x1D, 0xB2, 0x1D, 0xB3, 0x1D,
-       0xB4, 0x1D, 0xB5, 0x1D, 0xB6, 0x1D, 0xB7, 0x1D,
-       0xB8, 0x1D, 0xB9, 0x1D, 0xBA, 0x1D, 0xBB, 0x1D,
-       0xBC, 0x1D, 0xBD, 0x1D, 0xBE, 0x1D, 0xBF, 0x1D,
-       0xC0, 0x1D, 0xC1, 0x1D, 0xC2, 0x1D, 0xC3, 0x1D,
-       0xC4, 0x1D, 0xC5, 0x1D, 0xC6, 0x1D, 0xC7, 0x1D,
-       0xC8, 0x1D, 0xC9, 0x1D, 0xCA, 0x1D, 0xCB, 0x1D,
-       0xCC, 0x1D, 0xCD, 0x1D, 0xCE, 0x1D, 0xCF, 0x1D,
-       0xD0, 0x1D, 0xD1, 0x1D, 0xD2, 0x1D, 0xD3, 0x1D,
-       0xD4, 0x1D, 0xD5, 0x1D, 0xD6, 0x1D, 0xD7, 0x1D,
-       0xD8, 0x1D, 0xD9, 0x1D, 0xDA, 0x1D, 0xDB, 0x1D,
-       0xDC, 0x1D, 0xDD, 0x1D, 0xDE, 0x1D, 0xDF, 0x1D,
-       0xE0, 0x1D, 0xE1, 0x1D, 0xE2, 0x1D, 0xE3, 0x1D,
-       0xE4, 0x1D, 0xE5, 0x1D, 0xE6, 0x1D, 0xE7, 0x1D,
-       0xE8, 0x1D, 0xE9, 0x1D, 0xEA, 0x1D, 0xEB, 0x1D,
-       0xEC, 0x1D, 0xED, 0x1D, 0xEE, 0x1D, 0xEF, 0x1D,
-       0xF0, 0x1D, 0xF1, 0x1D, 0xF2, 0x1D, 0xF3, 0x1D,
-       0xF4, 0x1D, 0xF5, 0x1D, 0xF6, 0x1D, 0xF7, 0x1D,
-       0xF8, 0x1D, 0xF9, 0x1D, 0xFA, 0x1D, 0xFB, 0x1D,
-       0xFC, 0x1D, 0xFD, 0x1D, 0xFE, 0x1D, 0xFF, 0x1D,
-       0x00, 0x1E, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E,
-       0x04, 0x1E, 0x04, 0x1E, 0x06, 0x1E, 0x06, 0x1E,
-       0x08, 0x1E, 0x08, 0x1E, 0x0A, 0x1E, 0x0A, 0x1E,
-       0x0C, 0x1E, 0x0C, 0x1E, 0x0E, 0x1E, 0x0E, 0x1E,
-       0x10, 0x1E, 0x10, 0x1E, 0x12, 0x1E, 0x12, 0x1E,
-       0x14, 0x1E, 0x14, 0x1E, 0x16, 0x1E, 0x16, 0x1E,
-       0x18, 0x1E, 0x18, 0x1E, 0x1A, 0x1E, 0x1A, 0x1E,
-       0x1C, 0x1E, 0x1C, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E,
-       0x20, 0x1E, 0x20, 0x1E, 0x22, 0x1E, 0x22, 0x1E,
-       0x24, 0x1E, 0x24, 0x1E, 0x26, 0x1E, 0x26, 0x1E,
-       0x28, 0x1E, 0x28, 0x1E, 0x2A, 0x1E, 0x2A, 0x1E,
-       0x2C, 0x1E, 0x2C, 0x1E, 0x2E, 0x1E, 0x2E, 0x1E,
-       0x30, 0x1E, 0x30, 0x1E, 0x32, 0x1E, 0x32, 0x1E,
-       0x34, 0x1E, 0x34, 0x1E, 0x36, 0x1E, 0x36, 0x1E,
-       0x38, 0x1E, 0x38, 0x1E, 0x3A, 0x1E, 0x3A, 0x1E,
-       0x3C, 0x1E, 0x3C, 0x1E, 0x3E, 0x1E, 0x3E, 0x1E,
-       0x40, 0x1E, 0x40, 0x1E, 0x42, 0x1E, 0x42, 0x1E,
-       0x44, 0x1E, 0x44, 0x1E, 0x46, 0x1E, 0x46, 0x1E,
-       0x48, 0x1E, 0x48, 0x1E, 0x4A, 0x1E, 0x4A, 0x1E,
-       0x4C, 0x1E, 0x4C, 0x1E, 0x4E, 0x1E, 0x4E, 0x1E,
-       0x50, 0x1E, 0x50, 0x1E, 0x52, 0x1E, 0x52, 0x1E,
-       0x54, 0x1E, 0x54, 0x1E, 0x56, 0x1E, 0x56, 0x1E,
-       0x58, 0x1E, 0x58, 0x1E, 0x5A, 0x1E, 0x5A, 0x1E,
-       0x5C, 0x1E, 0x5C, 0x1E, 0x5E, 0x1E, 0x5E, 0x1E,
-       0x60, 0x1E, 0x60, 0x1E, 0x62, 0x1E, 0x62, 0x1E,
-       0x64, 0x1E, 0x64, 0x1E, 0x66, 0x1E, 0x66, 0x1E,
-       0x68, 0x1E, 0x68, 0x1E, 0x6A, 0x1E, 0x6A, 0x1E,
-       0x6C, 0x1E, 0x6C, 0x1E, 0x6E, 0x1E, 0x6E, 0x1E,
-       0x70, 0x1E, 0x70, 0x1E, 0x72, 0x1E, 0x72, 0x1E,
-       0x74, 0x1E, 0x74, 0x1E, 0x76, 0x1E, 0x76, 0x1E,
-       0x78, 0x1E, 0x78, 0x1E, 0x7A, 0x1E, 0x7A, 0x1E,
-       0x7C, 0x1E, 0x7C, 0x1E, 0x7E, 0x1E, 0x7E, 0x1E,
-       0x80, 0x1E, 0x80, 0x1E, 0x82, 0x1E, 0x82, 0x1E,
-       0x84, 0x1E, 0x84, 0x1E, 0x86, 0x1E, 0x86, 0x1E,
-       0x88, 0x1E, 0x88, 0x1E, 0x8A, 0x1E, 0x8A, 0x1E,
-       0x8C, 0x1E, 0x8C, 0x1E, 0x8E, 0x1E, 0x8E, 0x1E,
-       0x90, 0x1E, 0x90, 0x1E, 0x92, 0x1E, 0x92, 0x1E,
-       0x94, 0x1E, 0x94, 0x1E, 0x96, 0x1E, 0x97, 0x1E,
-       0x98, 0x1E, 0x99, 0x1E, 0x9A, 0x1E, 0x9B, 0x1E,
-       0x9C, 0x1E, 0x9D, 0x1E, 0x9E, 0x1E, 0x9F, 0x1E,
-       0xA0, 0x1E, 0xA0, 0x1E, 0xA2, 0x1E, 0xA2, 0x1E,
-       0xA4, 0x1E, 0xA4, 0x1E, 0xA6, 0x1E, 0xA6, 0x1E,
-       0xA8, 0x1E, 0xA8, 0x1E, 0xAA, 0x1E, 0xAA, 0x1E,
-       0xAC, 0x1E, 0xAC, 0x1E, 0xAE, 0x1E, 0xAE, 0x1E,
-       0xB0, 0x1E, 0xB0, 0x1E, 0xB2, 0x1E, 0xB2, 0x1E,
-       0xB4, 0x1E, 0xB4, 0x1E, 0xB6, 0x1E, 0xB6, 0x1E,
-       0xB8, 0x1E, 0xB8, 0x1E, 0xBA, 0x1E, 0xBA, 0x1E,
-       0xBC, 0x1E, 0xBC, 0x1E, 0xBE, 0x1E, 0xBE, 0x1E,
-       0xC0, 0x1E, 0xC0, 0x1E, 0xC2, 0x1E, 0xC2, 0x1E,
-       0xC4, 0x1E, 0xC4, 0x1E, 0xC6, 0x1E, 0xC6, 0x1E,
-       0xC8, 0x1E, 0xC8, 0x1E, 0xCA, 0x1E, 0xCA, 0x1E,
-       0xCC, 0x1E, 0xCC, 0x1E, 0xCE, 0x1E, 0xCE, 0x1E,
-       0xD0, 0x1E, 0xD0, 0x1E, 0xD2, 0x1E, 0xD2, 0x1E,
-       0xD4, 0x1E, 0xD4, 0x1E, 0xD6, 0x1E, 0xD6, 0x1E,
-       0xD8, 0x1E, 0xD8, 0x1E, 0xDA, 0x1E, 0xDA, 0x1E,
-       0xDC, 0x1E, 0xDC, 0x1E, 0xDE, 0x1E, 0xDE, 0x1E,
-       0xE0, 0x1E, 0xE0, 0x1E, 0xE2, 0x1E, 0xE2, 0x1E,
-       0xE4, 0x1E, 0xE4, 0x1E, 0xE6, 0x1E, 0xE6, 0x1E,
-       0xE8, 0x1E, 0xE8, 0x1E, 0xEA, 0x1E, 0xEA, 0x1E,
-       0xEC, 0x1E, 0xEC, 0x1E, 0xEE, 0x1E, 0xEE, 0x1E,
-       0xF0, 0x1E, 0xF0, 0x1E, 0xF2, 0x1E, 0xF2, 0x1E,
-       0xF4, 0x1E, 0xF4, 0x1E, 0xF6, 0x1E, 0xF6, 0x1E,
-       0xF8, 0x1E, 0xF8, 0x1E, 0xFA, 0x1E, 0xFB, 0x1E,
-       0xFC, 0x1E, 0xFD, 0x1E, 0xFE, 0x1E, 0xFF, 0x1E,
-       0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F,
-       0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F,
-       0x08, 0x1F, 0x09, 0x1F, 0x0A, 0x1F, 0x0B, 0x1F,
-       0x0C, 0x1F, 0x0D, 0x1F, 0x0E, 0x1F, 0x0F, 0x1F,
-       0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F,
-       0x1C, 0x1F, 0x1D, 0x1F, 0x16, 0x1F, 0x17, 0x1F,
-       0x18, 0x1F, 0x19, 0x1F, 0x1A, 0x1F, 0x1B, 0x1F,
-       0x1C, 0x1F, 0x1D, 0x1F, 0x1E, 0x1F, 0x1F, 0x1F,
-       0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F,
-       0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F,
-       0x28, 0x1F, 0x29, 0x1F, 0x2A, 0x1F, 0x2B, 0x1F,
-       0x2C, 0x1F, 0x2D, 0x1F, 0x2E, 0x1F, 0x2F, 0x1F,
-       0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F,
-       0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F,
-       0x38, 0x1F, 0x39, 0x1F, 0x3A, 0x1F, 0x3B, 0x1F,
-       0x3C, 0x1F, 0x3D, 0x1F, 0x3E, 0x1F, 0x3F, 0x1F,
-       0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F,
-       0x4C, 0x1F, 0x4D, 0x1F, 0x46, 0x1F, 0x47, 0x1F,
-       0x48, 0x1F, 0x49, 0x1F, 0x4A, 0x1F, 0x4B, 0x1F,
-       0x4C, 0x1F, 0x4D, 0x1F, 0x4E, 0x1F, 0x4F, 0x1F,
-       0x50, 0x1F, 0x59, 0x1F, 0x52, 0x1F, 0x5B, 0x1F,
-       0x54, 0x1F, 0x5D, 0x1F, 0x56, 0x1F, 0x5F, 0x1F,
-       0x58, 0x1F, 0x59, 0x1F, 0x5A, 0x1F, 0x5B, 0x1F,
-       0x5C, 0x1F, 0x5D, 0x1F, 0x5E, 0x1F, 0x5F, 0x1F,
-       0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F,
-       0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F,
-       0x68, 0x1F, 0x69, 0x1F, 0x6A, 0x1F, 0x6B, 0x1F,
-       0x6C, 0x1F, 0x6D, 0x1F, 0x6E, 0x1F, 0x6F, 0x1F,
-       0xBA, 0x1F, 0xBB, 0x1F, 0xC8, 0x1F, 0xC9, 0x1F,
-       0xCA, 0x1F, 0xCB, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F,
-       0xF8, 0x1F, 0xF9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F,
-       0xFA, 0x1F, 0xFB, 0x1F, 0x7E, 0x1F, 0x7F, 0x1F,
-       0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F,
-       0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F,
-       0x88, 0x1F, 0x89, 0x1F, 0x8A, 0x1F, 0x8B, 0x1F,
-       0x8C, 0x1F, 0x8D, 0x1F, 0x8E, 0x1F, 0x8F, 0x1F,
-       0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F,
-       0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F,
-       0x98, 0x1F, 0x99, 0x1F, 0x9A, 0x1F, 0x9B, 0x1F,
-       0x9C, 0x1F, 0x9D, 0x1F, 0x9E, 0x1F, 0x9F, 0x1F,
-       0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F,
-       0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F,
-       0xA8, 0x1F, 0xA9, 0x1F, 0xAA, 0x1F, 0xAB, 0x1F,
-       0xAC, 0x1F, 0xAD, 0x1F, 0xAE, 0x1F, 0xAF, 0x1F,
-       0xB8, 0x1F, 0xB9, 0x1F, 0xB2, 0x1F, 0xBC, 0x1F,
-       0xB4, 0x1F, 0xB5, 0x1F, 0xB6, 0x1F, 0xB7, 0x1F,
-       0xB8, 0x1F, 0xB9, 0x1F, 0xBA, 0x1F, 0xBB, 0x1F,
-       0xBC, 0x1F, 0xBD, 0x1F, 0xBE, 0x1F, 0xBF, 0x1F,
-       0xC0, 0x1F, 0xC1, 0x1F, 0xC2, 0x1F, 0xC3, 0x1F,
-       0xC4, 0x1F, 0xC5, 0x1F, 0xC6, 0x1F, 0xC7, 0x1F,
-       0xC8, 0x1F, 0xC9, 0x1F, 0xCA, 0x1F, 0xCB, 0x1F,
-       0xC3, 0x1F, 0xCD, 0x1F, 0xCE, 0x1F, 0xCF, 0x1F,
-       0xD8, 0x1F, 0xD9, 0x1F, 0xD2, 0x1F, 0xD3, 0x1F,
-       0xD4, 0x1F, 0xD5, 0x1F, 0xD6, 0x1F, 0xD7, 0x1F,
-       0xD8, 0x1F, 0xD9, 0x1F, 0xDA, 0x1F, 0xDB, 0x1F,
-       0xDC, 0x1F, 0xDD, 0x1F, 0xDE, 0x1F, 0xDF, 0x1F,
-       0xE8, 0x1F, 0xE9, 0x1F, 0xE2, 0x1F, 0xE3, 0x1F,
-       0xE4, 0x1F, 0xEC, 0x1F, 0xE6, 0x1F, 0xE7, 0x1F,
-       0xE8, 0x1F, 0xE9, 0x1F, 0xEA, 0x1F, 0xEB, 0x1F,
-       0xEC, 0x1F, 0xED, 0x1F, 0xEE, 0x1F, 0xEF, 0x1F,
-       0xF0, 0x1F, 0xF1, 0x1F, 0xF2, 0x1F, 0xF3, 0x1F,
-       0xF4, 0x1F, 0xF5, 0x1F, 0xF6, 0x1F, 0xF7, 0x1F,
-       0xF8, 0x1F, 0xF9, 0x1F, 0xFA, 0x1F, 0xFB, 0x1F,
-       0xF3, 0x1F, 0xFD, 0x1F, 0xFE, 0x1F, 0xFF, 0x1F,
-       0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20,
-       0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20,
-       0x08, 0x20, 0x09, 0x20, 0x0A, 0x20, 0x0B, 0x20,
-       0x0C, 0x20, 0x0D, 0x20, 0x0E, 0x20, 0x0F, 0x20,
-       0x10, 0x20, 0x11, 0x20, 0x12, 0x20, 0x13, 0x20,
-       0x14, 0x20, 0x15, 0x20, 0x16, 0x20, 0x17, 0x20,
-       0x18, 0x20, 0x19, 0x20, 0x1A, 0x20, 0x1B, 0x20,
-       0x1C, 0x20, 0x1D, 0x20, 0x1E, 0x20, 0x1F, 0x20,
-       0x20, 0x20, 0x21, 0x20, 0x22, 0x20, 0x23, 0x20,
-       0x24, 0x20, 0x25, 0x20, 0x26, 0x20, 0x27, 0x20,
-       0x28, 0x20, 0x29, 0x20, 0x2A, 0x20, 0x2B, 0x20,
-       0x2C, 0x20, 0x2D, 0x20, 0x2E, 0x20, 0x2F, 0x20,
-       0x30, 0x20, 0x31, 0x20, 0x32, 0x20, 0x33, 0x20,
-       0x34, 0x20, 0x35, 0x20, 0x36, 0x20, 0x37, 0x20,
-       0x38, 0x20, 0x39, 0x20, 0x3A, 0x20, 0x3B, 0x20,
-       0x3C, 0x20, 0x3D, 0x20, 0x3E, 0x20, 0x3F, 0x20,
-       0x40, 0x20, 0x41, 0x20, 0x42, 0x20, 0x43, 0x20,
-       0x44, 0x20, 0x45, 0x20, 0x46, 0x20, 0x47, 0x20,
-       0x48, 0x20, 0x49, 0x20, 0x4A, 0x20, 0x4B, 0x20,
-       0x4C, 0x20, 0x4D, 0x20, 0x4E, 0x20, 0x4F, 0x20,
-       0x50, 0x20, 0x51, 0x20, 0x52, 0x20, 0x53, 0x20,
-       0x54, 0x20, 0x55, 0x20, 0x56, 0x20, 0x57, 0x20,
-       0x58, 0x20, 0x59, 0x20, 0x5A, 0x20, 0x5B, 0x20,
-       0x5C, 0x20, 0x5D, 0x20, 0x5E, 0x20, 0x5F, 0x20,
-       0x60, 0x20, 0x61, 0x20, 0x62, 0x20, 0x63, 0x20,
-       0x64, 0x20, 0x65, 0x20, 0x66, 0x20, 0x67, 0x20,
-       0x68, 0x20, 0x69, 0x20, 0x6A, 0x20, 0x6B, 0x20,
-       0x6C, 0x20, 0x6D, 0x20, 0x6E, 0x20, 0x6F, 0x20,
-       0x70, 0x20, 0x71, 0x20, 0x72, 0x20, 0x73, 0x20,
-       0x74, 0x20, 0x75, 0x20, 0x76, 0x20, 0x77, 0x20,
-       0x78, 0x20, 0x79, 0x20, 0x7A, 0x20, 0x7B, 0x20,
-       0x7C, 0x20, 0x7D, 0x20, 0x7E, 0x20, 0x7F, 0x20,
-       0x80, 0x20, 0x81, 0x20, 0x82, 0x20, 0x83, 0x20,
-       0x84, 0x20, 0x85, 0x20, 0x86, 0x20, 0x87, 0x20,
-       0x88, 0x20, 0x89, 0x20, 0x8A, 0x20, 0x8B, 0x20,
-       0x8C, 0x20, 0x8D, 0x20, 0x8E, 0x20, 0x8F, 0x20,
-       0x90, 0x20, 0x91, 0x20, 0x92, 0x20, 0x93, 0x20,
-       0x94, 0x20, 0x95, 0x20, 0x96, 0x20, 0x97, 0x20,
-       0x98, 0x20, 0x99, 0x20, 0x9A, 0x20, 0x9B, 0x20,
-       0x9C, 0x20, 0x9D, 0x20, 0x9E, 0x20, 0x9F, 0x20,
-       0xA0, 0x20, 0xA1, 0x20, 0xA2, 0x20, 0xA3, 0x20,
-       0xA4, 0x20, 0xA5, 0x20, 0xA6, 0x20, 0xA7, 0x20,
-       0xA8, 0x20, 0xA9, 0x20, 0xAA, 0x20, 0xAB, 0x20,
-       0xAC, 0x20, 0xAD, 0x20, 0xAE, 0x20, 0xAF, 0x20,
-       0xB0, 0x20, 0xB1, 0x20, 0xB2, 0x20, 0xB3, 0x20,
-       0xB4, 0x20, 0xB5, 0x20, 0xB6, 0x20, 0xB7, 0x20,
-       0xB8, 0x20, 0xB9, 0x20, 0xBA, 0x20, 0xBB, 0x20,
-       0xBC, 0x20, 0xBD, 0x20, 0xBE, 0x20, 0xBF, 0x20,
-       0xC0, 0x20, 0xC1, 0x20, 0xC2, 0x20, 0xC3, 0x20,
-       0xC4, 0x20, 0xC5, 0x20, 0xC6, 0x20, 0xC7, 0x20,
-       0xC8, 0x20, 0xC9, 0x20, 0xCA, 0x20, 0xCB, 0x20,
-       0xCC, 0x20, 0xCD, 0x20, 0xCE, 0x20, 0xCF, 0x20,
-       0xD0, 0x20, 0xD1, 0x20, 0xD2, 0x20, 0xD3, 0x20,
-       0xD4, 0x20, 0xD5, 0x20, 0xD6, 0x20, 0xD7, 0x20,
-       0xD8, 0x20, 0xD9, 0x20, 0xDA, 0x20, 0xDB, 0x20,
-       0xDC, 0x20, 0xDD, 0x20, 0xDE, 0x20, 0xDF, 0x20,
-       0xE0, 0x20, 0xE1, 0x20, 0xE2, 0x20, 0xE3, 0x20,
-       0xE4, 0x20, 0xE5, 0x20, 0xE6, 0x20, 0xE7, 0x20,
-       0xE8, 0x20, 0xE9, 0x20, 0xEA, 0x20, 0xEB, 0x20,
-       0xEC, 0x20, 0xED, 0x20, 0xEE, 0x20, 0xEF, 0x20,
-       0xF0, 0x20, 0xF1, 0x20, 0xF2, 0x20, 0xF3, 0x20,
-       0xF4, 0x20, 0xF5, 0x20, 0xF6, 0x20, 0xF7, 0x20,
-       0xF8, 0x20, 0xF9, 0x20, 0xFA, 0x20, 0xFB, 0x20,
-       0xFC, 0x20, 0xFD, 0x20, 0xFE, 0x20, 0xFF, 0x20,
-       0x00, 0x21, 0x01, 0x21, 0x02, 0x21, 0x03, 0x21,
-       0x04, 0x21, 0x05, 0x21, 0x06, 0x21, 0x07, 0x21,
-       0x08, 0x21, 0x09, 0x21, 0x0A, 0x21, 0x0B, 0x21,
-       0x0C, 0x21, 0x0D, 0x21, 0x0E, 0x21, 0x0F, 0x21,
-       0x10, 0x21, 0x11, 0x21, 0x12, 0x21, 0x13, 0x21,
-       0x14, 0x21, 0x15, 0x21, 0x16, 0x21, 0x17, 0x21,
-       0x18, 0x21, 0x19, 0x21, 0x1A, 0x21, 0x1B, 0x21,
-       0x1C, 0x21, 0x1D, 0x21, 0x1E, 0x21, 0x1F, 0x21,
-       0x20, 0x21, 0x21, 0x21, 0x22, 0x21, 0x23, 0x21,
-       0x24, 0x21, 0x25, 0x21, 0x26, 0x21, 0x27, 0x21,
-       0x28, 0x21, 0x29, 0x21, 0x2A, 0x21, 0x2B, 0x21,
-       0x2C, 0x21, 0x2D, 0x21, 0x2E, 0x21, 0x2F, 0x21,
-       0x30, 0x21, 0x31, 0x21, 0x32, 0x21, 0x33, 0x21,
-       0x34, 0x21, 0x35, 0x21, 0x36, 0x21, 0x37, 0x21,
-       0x38, 0x21, 0x39, 0x21, 0x3A, 0x21, 0x3B, 0x21,
-       0x3C, 0x21, 0x3D, 0x21, 0x3E, 0x21, 0x3F, 0x21,
-       0x40, 0x21, 0x41, 0x21, 0x42, 0x21, 0x43, 0x21,
-       0x44, 0x21, 0x45, 0x21, 0x46, 0x21, 0x47, 0x21,
-       0x48, 0x21, 0x49, 0x21, 0x4A, 0x21, 0x4B, 0x21,
-       0x4C, 0x21, 0x4D, 0x21, 0x32, 0x21, 0x4F, 0x21,
-       0x50, 0x21, 0x51, 0x21, 0x52, 0x21, 0x53, 0x21,
-       0x54, 0x21, 0x55, 0x21, 0x56, 0x21, 0x57, 0x21,
-       0x58, 0x21, 0x59, 0x21, 0x5A, 0x21, 0x5B, 0x21,
-       0x5C, 0x21, 0x5D, 0x21, 0x5E, 0x21, 0x5F, 0x21,
-       0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
-       0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
-       0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21,
-       0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21,
-       0x60, 0x21, 0x61, 0x21, 0x62, 0x21, 0x63, 0x21,
-       0x64, 0x21, 0x65, 0x21, 0x66, 0x21, 0x67, 0x21,
-       0x68, 0x21, 0x69, 0x21, 0x6A, 0x21, 0x6B, 0x21,
-       0x6C, 0x21, 0x6D, 0x21, 0x6E, 0x21, 0x6F, 0x21,
-       0x80, 0x21, 0x81, 0x21, 0x82, 0x21, 0x83, 0x21,
-       0x83, 0x21, 0xFF, 0xFF, 0x4B, 0x03, 0xB6, 0x24,
-       0xB7, 0x24, 0xB8, 0x24, 0xB9, 0x24, 0xBA, 0x24,
-       0xBB, 0x24, 0xBC, 0x24, 0xBD, 0x24, 0xBE, 0x24,
-       0xBF, 0x24, 0xC0, 0x24, 0xC1, 0x24, 0xC2, 0x24,
-       0xC3, 0x24, 0xC4, 0x24, 0xC5, 0x24, 0xC6, 0x24,
-       0xC7, 0x24, 0xC8, 0x24, 0xC9, 0x24, 0xCA, 0x24,
-       0xCB, 0x24, 0xCC, 0x24, 0xCD, 0x24, 0xCE, 0x24,
-       0xCF, 0x24, 0xFF, 0xFF, 0x46, 0x07, 0x00, 0x2C,
-       0x01, 0x2C, 0x02, 0x2C, 0x03, 0x2C, 0x04, 0x2C,
-       0x05, 0x2C, 0x06, 0x2C, 0x07, 0x2C, 0x08, 0x2C,
-       0x09, 0x2C, 0x0A, 0x2C, 0x0B, 0x2C, 0x0C, 0x2C,
-       0x0D, 0x2C, 0x0E, 0x2C, 0x0F, 0x2C, 0x10, 0x2C,
-       0x11, 0x2C, 0x12, 0x2C, 0x13, 0x2C, 0x14, 0x2C,
-       0x15, 0x2C, 0x16, 0x2C, 0x17, 0x2C, 0x18, 0x2C,
-       0x19, 0x2C, 0x1A, 0x2C, 0x1B, 0x2C, 0x1C, 0x2C,
-       0x1D, 0x2C, 0x1E, 0x2C, 0x1F, 0x2C, 0x20, 0x2C,
-       0x21, 0x2C, 0x22, 0x2C, 0x23, 0x2C, 0x24, 0x2C,
-       0x25, 0x2C, 0x26, 0x2C, 0x27, 0x2C, 0x28, 0x2C,
-       0x29, 0x2C, 0x2A, 0x2C, 0x2B, 0x2C, 0x2C, 0x2C,
-       0x2D, 0x2C, 0x2E, 0x2C, 0x5F, 0x2C, 0x60, 0x2C,
-       0x60, 0x2C, 0x62, 0x2C, 0x63, 0x2C, 0x64, 0x2C,
-       0x65, 0x2C, 0x66, 0x2C, 0x67, 0x2C, 0x67, 0x2C,
-       0x69, 0x2C, 0x69, 0x2C, 0x6B, 0x2C, 0x6B, 0x2C,
-       0x6D, 0x2C, 0x6E, 0x2C, 0x6F, 0x2C, 0x70, 0x2C,
-       0x71, 0x2C, 0x72, 0x2C, 0x73, 0x2C, 0x74, 0x2C,
-       0x75, 0x2C, 0x75, 0x2C, 0x77, 0x2C, 0x78, 0x2C,
-       0x79, 0x2C, 0x7A, 0x2C, 0x7B, 0x2C, 0x7C, 0x2C,
-       0x7D, 0x2C, 0x7E, 0x2C, 0x7F, 0x2C, 0x80, 0x2C,
-       0x80, 0x2C, 0x82, 0x2C, 0x82, 0x2C, 0x84, 0x2C,
-       0x84, 0x2C, 0x86, 0x2C, 0x86, 0x2C, 0x88, 0x2C,
-       0x88, 0x2C, 0x8A, 0x2C, 0x8A, 0x2C, 0x8C, 0x2C,
-       0x8C, 0x2C, 0x8E, 0x2C, 0x8E, 0x2C, 0x90, 0x2C,
-       0x90, 0x2C, 0x92, 0x2C, 0x92, 0x2C, 0x94, 0x2C,
-       0x94, 0x2C, 0x96, 0x2C, 0x96, 0x2C, 0x98, 0x2C,
-       0x98, 0x2C, 0x9A, 0x2C, 0x9A, 0x2C, 0x9C, 0x2C,
-       0x9C, 0x2C, 0x9E, 0x2C, 0x9E, 0x2C, 0xA0, 0x2C,
-       0xA0, 0x2C, 0xA2, 0x2C, 0xA2, 0x2C, 0xA4, 0x2C,
-       0xA4, 0x2C, 0xA6, 0x2C, 0xA6, 0x2C, 0xA8, 0x2C,
-       0xA8, 0x2C, 0xAA, 0x2C, 0xAA, 0x2C, 0xAC, 0x2C,
-       0xAC, 0x2C, 0xAE, 0x2C, 0xAE, 0x2C, 0xB0, 0x2C,
-       0xB0, 0x2C, 0xB2, 0x2C, 0xB2, 0x2C, 0xB4, 0x2C,
-       0xB4, 0x2C, 0xB6, 0x2C, 0xB6, 0x2C, 0xB8, 0x2C,
-       0xB8, 0x2C, 0xBA, 0x2C, 0xBA, 0x2C, 0xBC, 0x2C,
-       0xBC, 0x2C, 0xBE, 0x2C, 0xBE, 0x2C, 0xC0, 0x2C,
-       0xC0, 0x2C, 0xC2, 0x2C, 0xC2, 0x2C, 0xC4, 0x2C,
-       0xC4, 0x2C, 0xC6, 0x2C, 0xC6, 0x2C, 0xC8, 0x2C,
-       0xC8, 0x2C, 0xCA, 0x2C, 0xCA, 0x2C, 0xCC, 0x2C,
-       0xCC, 0x2C, 0xCE, 0x2C, 0xCE, 0x2C, 0xD0, 0x2C,
-       0xD0, 0x2C, 0xD2, 0x2C, 0xD2, 0x2C, 0xD4, 0x2C,
-       0xD4, 0x2C, 0xD6, 0x2C, 0xD6, 0x2C, 0xD8, 0x2C,
-       0xD8, 0x2C, 0xDA, 0x2C, 0xDA, 0x2C, 0xDC, 0x2C,
-       0xDC, 0x2C, 0xDE, 0x2C, 0xDE, 0x2C, 0xE0, 0x2C,
-       0xE0, 0x2C, 0xE2, 0x2C, 0xE2, 0x2C, 0xE4, 0x2C,
-       0xE5, 0x2C, 0xE6, 0x2C, 0xE7, 0x2C, 0xE8, 0x2C,
-       0xE9, 0x2C, 0xEA, 0x2C, 0xEB, 0x2C, 0xEC, 0x2C,
-       0xED, 0x2C, 0xEE, 0x2C, 0xEF, 0x2C, 0xF0, 0x2C,
-       0xF1, 0x2C, 0xF2, 0x2C, 0xF3, 0x2C, 0xF4, 0x2C,
-       0xF5, 0x2C, 0xF6, 0x2C, 0xF7, 0x2C, 0xF8, 0x2C,
-       0xF9, 0x2C, 0xFA, 0x2C, 0xFB, 0x2C, 0xFC, 0x2C,
-       0xFD, 0x2C, 0xFE, 0x2C, 0xFF, 0x2C, 0xA0, 0x10,
-       0xA1, 0x10, 0xA2, 0x10, 0xA3, 0x10, 0xA4, 0x10,
-       0xA5, 0x10, 0xA6, 0x10, 0xA7, 0x10, 0xA8, 0x10,
-       0xA9, 0x10, 0xAA, 0x10, 0xAB, 0x10, 0xAC, 0x10,
-       0xAD, 0x10, 0xAE, 0x10, 0xAF, 0x10, 0xB0, 0x10,
-       0xB1, 0x10, 0xB2, 0x10, 0xB3, 0x10, 0xB4, 0x10,
-       0xB5, 0x10, 0xB6, 0x10, 0xB7, 0x10, 0xB8, 0x10,
-       0xB9, 0x10, 0xBA, 0x10, 0xBB, 0x10, 0xBC, 0x10,
-       0xBD, 0x10, 0xBE, 0x10, 0xBF, 0x10, 0xC0, 0x10,
-       0xC1, 0x10, 0xC2, 0x10, 0xC3, 0x10, 0xC4, 0x10,
-       0xC5, 0x10, 0xFF, 0xFF, 0x1B, 0xD2, 0x21, 0xFF,
-       0x22, 0xFF, 0x23, 0xFF, 0x24, 0xFF, 0x25, 0xFF,
-       0x26, 0xFF, 0x27, 0xFF, 0x28, 0xFF, 0x29, 0xFF,
-       0x2A, 0xFF, 0x2B, 0xFF, 0x2C, 0xFF, 0x2D, 0xFF,
-       0x2E, 0xFF, 0x2F, 0xFF, 0x30, 0xFF, 0x31, 0xFF,
-       0x32, 0xFF, 0x33, 0xFF, 0x34, 0xFF, 0x35, 0xFF,
-       0x36, 0xFF, 0x37, 0xFF, 0x38, 0xFF, 0x39, 0xFF,
-       0x3A, 0xFF, 0x5B, 0xFF, 0x5C, 0xFF, 0x5D, 0xFF,
-       0x5E, 0xFF, 0x5F, 0xFF, 0x60, 0xFF, 0x61, 0xFF,
-       0x62, 0xFF, 0x63, 0xFF, 0x64, 0xFF, 0x65, 0xFF,
-       0x66, 0xFF, 0x67, 0xFF, 0x68, 0xFF, 0x69, 0xFF,
-       0x6A, 0xFF, 0x6B, 0xFF, 0x6C, 0xFF, 0x6D, 0xFF,
-       0x6E, 0xFF, 0x6F, 0xFF, 0x70, 0xFF, 0x71, 0xFF,
-       0x72, 0xFF, 0x73, 0xFF, 0x74, 0xFF, 0x75, 0xFF,
-       0x76, 0xFF, 0x77, 0xFF, 0x78, 0xFF, 0x79, 0xFF,
-       0x7A, 0xFF, 0x7B, 0xFF, 0x7C, 0xFF, 0x7D, 0xFF,
-       0x7E, 0xFF, 0x7F, 0xFF, 0x80, 0xFF, 0x81, 0xFF,
-       0x82, 0xFF, 0x83, 0xFF, 0x84, 0xFF, 0x85, 0xFF,
-       0x86, 0xFF, 0x87, 0xFF, 0x88, 0xFF, 0x89, 0xFF,
-       0x8A, 0xFF, 0x8B, 0xFF, 0x8C, 0xFF, 0x8D, 0xFF,
-       0x8E, 0xFF, 0x8F, 0xFF, 0x90, 0xFF, 0x91, 0xFF,
-       0x92, 0xFF, 0x93, 0xFF, 0x94, 0xFF, 0x95, 0xFF,
-       0x96, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF,
-       0x9A, 0xFF, 0x9B, 0xFF, 0x9C, 0xFF, 0x9D, 0xFF,
-       0x9E, 0xFF, 0x9F, 0xFF, 0xA0, 0xFF, 0xA1, 0xFF,
-       0xA2, 0xFF, 0xA3, 0xFF, 0xA4, 0xFF, 0xA5, 0xFF,
-       0xA6, 0xFF, 0xA7, 0xFF, 0xA8, 0xFF, 0xA9, 0xFF,
-       0xAA, 0xFF, 0xAB, 0xFF, 0xAC, 0xFF, 0xAD, 0xFF,
-       0xAE, 0xFF, 0xAF, 0xFF, 0xB0, 0xFF, 0xB1, 0xFF,
-       0xB2, 0xFF, 0xB3, 0xFF, 0xB4, 0xFF, 0xB5, 0xFF,
-       0xB6, 0xFF, 0xB7, 0xFF, 0xB8, 0xFF, 0xB9, 0xFF,
-       0xBA, 0xFF, 0xBB, 0xFF, 0xBC, 0xFF, 0xBD, 0xFF,
-       0xBE, 0xFF, 0xBF, 0xFF, 0xC0, 0xFF, 0xC1, 0xFF,
-       0xC2, 0xFF, 0xC3, 0xFF, 0xC4, 0xFF, 0xC5, 0xFF,
-       0xC6, 0xFF, 0xC7, 0xFF, 0xC8, 0xFF, 0xC9, 0xFF,
-       0xCA, 0xFF, 0xCB, 0xFF, 0xCC, 0xFF, 0xCD, 0xFF,
-       0xCE, 0xFF, 0xCF, 0xFF, 0xD0, 0xFF, 0xD1, 0xFF,
-       0xD2, 0xFF, 0xD3, 0xFF, 0xD4, 0xFF, 0xD5, 0xFF,
-       0xD6, 0xFF, 0xD7, 0xFF, 0xD8, 0xFF, 0xD9, 0xFF,
-       0xDA, 0xFF, 0xDB, 0xFF, 0xDC, 0xFF, 0xDD, 0xFF,
-       0xDE, 0xFF, 0xDF, 0xFF, 0xE0, 0xFF, 0xE1, 0xFF,
-       0xE2, 0xFF, 0xE3, 0xFF, 0xE4, 0xFF, 0xE5, 0xFF,
-       0xE6, 0xFF, 0xE7, 0xFF, 0xE8, 0xFF, 0xE9, 0xFF,
-       0xEA, 0xFF, 0xEB, 0xFF, 0xEC, 0xFF, 0xED, 0xFF,
-       0xEE, 0xFF, 0xEF, 0xFF, 0xF0, 0xFF, 0xF1, 0xFF,
-       0xF2, 0xFF, 0xF3, 0xFF, 0xF4, 0xFF, 0xF5, 0xFF,
-       0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF, 0xF9, 0xFF,
-       0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF, 0xFD, 0xFF,
-       0xFE, 0xFF, 0xFF, 0xFF
-};
index d3e098b..4f362da 100644 (file)
@@ -1186,7 +1186,9 @@ static struct fbtft_platform_data *fbtft_properties_read(struct device *dev)
        if (device_property_present(dev, "led-gpios"))
                pdata->display.backlight = 1;
        if (device_property_present(dev, "init"))
-               pdata->display.fbtftops.init_display = fbtft_init_display_from_property;
+               pdata->display.fbtftops.init_display =
+                       fbtft_init_display_from_property;
+
        pdata->display.fbtftops.request_gpios = fbtft_request_gpios;
 
        return pdata;
index 2a5c630..26e52cc 100644 (file)
@@ -25,6 +25,7 @@ int fbtft_gamma_parse_str(struct fbtft_par *par, u32 *curves,
        unsigned long val = 0;
        int ret = 0;
        int curve_counter, value_counter;
+       int _count;
 
        fbtft_par_dbg(DEBUG_SYSFS, par, "%s() str=\n", __func__);
 
@@ -68,7 +69,10 @@ int fbtft_gamma_parse_str(struct fbtft_par *par, u32 *curves,
                        ret = get_next_ulong(&curve_p, &val, " ", 16);
                        if (ret)
                                goto out;
-                       curves[curve_counter * par->gamma.num_values + value_counter] = val;
+
+                       _count = curve_counter * par->gamma.num_values +
+                                value_counter;
+                       curves[_count] = val;
                        value_counter++;
                }
                if (value_counter != par->gamma.num_values) {
index 5f782da..76f8c09 100644 (file)
@@ -348,9 +348,17 @@ module_exit(fbtft_driver_module_exit);
 
 /* shorthand debug levels */
 #define DEBUG_LEVEL_1  DEBUG_REQUEST_GPIOS
-#define DEBUG_LEVEL_2  (DEBUG_LEVEL_1 | DEBUG_DRIVER_INIT_FUNCTIONS | DEBUG_TIME_FIRST_UPDATE)
-#define DEBUG_LEVEL_3  (DEBUG_LEVEL_2 | DEBUG_RESET | DEBUG_INIT_DISPLAY | DEBUG_BLANK | DEBUG_REQUEST_GPIOS | DEBUG_FREE_GPIOS | DEBUG_VERIFY_GPIOS | DEBUG_BACKLIGHT | DEBUG_SYSFS)
-#define DEBUG_LEVEL_4  (DEBUG_LEVEL_2 | DEBUG_FB_READ | DEBUG_FB_WRITE | DEBUG_FB_FILLRECT | DEBUG_FB_COPYAREA | DEBUG_FB_IMAGEBLIT | DEBUG_FB_BLANK)
+#define DEBUG_LEVEL_2  (DEBUG_LEVEL_1 | DEBUG_DRIVER_INIT_FUNCTIONS        \
+                                      | DEBUG_TIME_FIRST_UPDATE)
+#define DEBUG_LEVEL_3  (DEBUG_LEVEL_2 | DEBUG_RESET | DEBUG_INIT_DISPLAY   \
+                                      | DEBUG_BLANK | DEBUG_REQUEST_GPIOS  \
+                                      | DEBUG_FREE_GPIOS                   \
+                                      | DEBUG_VERIFY_GPIOS                 \
+                                      | DEBUG_BACKLIGHT | DEBUG_SYSFS)
+#define DEBUG_LEVEL_4  (DEBUG_LEVEL_2 | DEBUG_FB_READ | DEBUG_FB_WRITE     \
+                                      | DEBUG_FB_FILLRECT                  \
+                                      | DEBUG_FB_COPYAREA                  \
+                                      | DEBUG_FB_IMAGEBLIT | DEBUG_FB_BLANK)
 #define DEBUG_LEVEL_5  (DEBUG_LEVEL_3 | DEBUG_UPDATE_DISPLAY)
 #define DEBUG_LEVEL_6  (DEBUG_LEVEL_4 | DEBUG_LEVEL_5)
 #define DEBUG_LEVEL_7  0xFFFFFFFF
@@ -398,8 +406,8 @@ do {                                                         \
 
 #define fbtft_par_dbg(level, par, format, arg...)            \
 do {                                                         \
-       if (unlikely(par->debug & level))                    \
-               dev_info(par->info->device, format, ##arg);  \
+       if (unlikely((par)->debug & (level)))                    \
+               dev_info((par)->info->device, format, ##arg);  \
 } while (0)
 
 #define fbtft_par_dbg_hex(level, par, dev, type, buf, num, format, arg...) \
index 39c0fe3..676d1ad 100644 (file)
@@ -1492,7 +1492,8 @@ static void ethsw_unregister_notifier(struct device *dev)
        err = unregister_switchdev_blocking_notifier(nb);
        if (err)
                dev_err(dev,
-                       "Failed to unregister switchdev blocking notifier (%d)\n", err);
+                       "Failed to unregister switchdev blocking notifier (%d)\n",
+                       err);
 
        err = unregister_switchdev_notifier(&ethsw->port_switchdev_nb);
        if (err)
index be6b50f..cd181a6 100644 (file)
@@ -692,8 +692,7 @@ static bool gasket_mmap_has_permissions(struct gasket_dev *gasket_dev,
                (vma->vm_flags & (VM_WRITE | VM_READ | VM_EXEC));
        if (requested_permissions & ~(bar_permissions)) {
                dev_dbg(gasket_dev->dev,
-                       "Attempting to map a region with requested permissions "
-                       "0x%x, but region has permissions 0x%x.\n",
+                       "Attempting to map a region with requested permissions 0x%x, but region has permissions 0x%x.\n",
                        requested_permissions, bar_permissions);
                return false;
        }
@@ -1180,8 +1179,7 @@ static int gasket_open(struct inode *inode, struct file *filp)
        inode->i_size = 0;
 
        dev_dbg(gasket_dev->dev,
-               "Attempting to open with tgid %u (%s) (f_mode: 0%03o, "
-               "fmode_write: %d is_root: %u)\n",
+               "Attempting to open with tgid %u (%s) (f_mode: 0%03o, fmode_write: %d is_root: %u)\n",
                current->tgid, task_name, filp->f_mode,
                (filp->f_mode & FMODE_WRITE), is_root);
 
@@ -1258,8 +1256,7 @@ static int gasket_release(struct inode *inode, struct file *file)
        mutex_lock(&gasket_dev->mutex);
 
        dev_dbg(gasket_dev->dev,
-               "Releasing device node. Call origin: tgid %u (%s) "
-               "(f_mode: 0%03o, fmode_write: %d, is_root: %u)\n",
+               "Releasing device node. Call origin: tgid %u (%s) (f_mode: 0%03o, fmode_write: %d, is_root: %u)\n",
                current->tgid, task_name, file->f_mode,
                (file->f_mode & FMODE_WRITE), is_root);
        dev_dbg(gasket_dev->dev, "Current open count (owning tgid %u): %d\n",
index db11498..354727f 100644 (file)
@@ -513,7 +513,7 @@ static int gdm_lte_event_send(struct net_device *dev, char *buf, int len)
 
        length = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev),
                                  hci->len) + HCI_HEADER_SIZE;
-       return netlink_send(lte_event.sock, idx, 0, buf, length);
+       return netlink_send(lte_event.sock, idx, 0, buf, length, dev);
 }
 
 static void gdm_lte_event_rcv(struct net_device *dev, u16 type,
index 51c22e3..87b8d92 100644 (file)
@@ -29,7 +29,7 @@ struct mux_pkt_header {
        __le32 seq_num;
        __le32 payload_size;
        __le16 packet_type;
-       unsigned char data[0];
+       unsigned char data[];
 };
 
 struct mux_tx {
index 6dea369..faecdfb 100644 (file)
@@ -28,7 +28,7 @@
 struct hci_packet {
        __dev16 cmd_evt;
        __dev16 len;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 struct tlv {
@@ -51,7 +51,7 @@ struct sdu {
        __dev32 dft_eps_ID;
        __dev32 bearer_ID;
        __dev32 nic_type;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 struct multi_sdu {
@@ -59,7 +59,7 @@ struct multi_sdu {
        __dev16 len;
        __dev16 num_packet;
        __dev16 reserved;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 struct hci_pdn_table_ind {
index 92440c3..7902e52 100644 (file)
@@ -89,7 +89,8 @@ struct sock *netlink_init(int unit,
        return sock;
 }
 
-int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len,
+                struct net_device *dev)
 {
        static u32 seq;
        struct sk_buff *skb = NULL;
@@ -118,8 +119,8 @@ int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
                return len;
 
        if (ret != -ESRCH)
-               pr_err("nl broadcast g=%d, t=%d, l=%d, r=%d\n",
-                      group, type, len, ret);
+               netdev_err(dev, "nl broadcast g=%d, t=%d, l=%d, r=%d\n",
+                          group, type, len, ret);
        else if (netlink_has_listeners(sock, group + 1))
                return -EAGAIN;
 
index c9e1d3b..d42eea9 100644 (file)
@@ -10,6 +10,7 @@
 struct sock *netlink_init(int unit,
                          void (*cb)(struct net_device *dev,
                                     u16 type, void *msg, int len));
-int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len);
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len,
+                struct net_device *dev);
 
 #endif /* _NETLINK_K_H_ */
index 3f1f4dd..efec0f8 100644 (file)
@@ -65,7 +65,7 @@
 struct audio_apbridgea_hdr {
        __u8    type;
        __le16  i2s_port;
-       __u8    data[0];
+       __u8    data[];
 } __packed;
 
 struct audio_apbridgea_set_config_request {
index 1ff34ab..36d99f9 100644 (file)
@@ -364,8 +364,7 @@ static int gb_gpio_request_handler(struct gb_operation *op)
        struct gb_message *request;
        struct gb_gpio_irq_event_request *event;
        u8 type = op->type;
-       int irq;
-       struct irq_desc *desc;
+       int irq, ret;
 
        if (type != GB_GPIO_TYPE_IRQ_EVENT) {
                dev_err(dev, "unsupported unsolicited request: %u\n", type);
@@ -391,17 +390,15 @@ static int gb_gpio_request_handler(struct gb_operation *op)
                dev_err(dev, "failed to find IRQ\n");
                return -EINVAL;
        }
-       desc = irq_to_desc(irq);
-       if (!desc) {
-               dev_err(dev, "failed to look up irq\n");
-               return -EINVAL;
-       }
 
        local_irq_disable();
-       generic_handle_irq_desc(desc);
+       ret = generic_handle_irq(irq);
        local_irq_enable();
 
-       return 0;
+       if (ret)
+               dev_err(dev, "failed to invoke irq handler\n");
+
+       return ret;
 }
 
 static int gb_gpio_request(struct gpio_chip *chip, unsigned int offset)
index ab06fc3..de2f651 100644 (file)
@@ -215,20 +215,6 @@ static int gb_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
        return gb_i2c_transfer_operation(gb_i2c_dev, msgs, msg_count);
 }
 
-#if 0
-/* Later */
-static int gb_i2c_smbus_xfer(struct i2c_adapter *adap,
-                            u16 addr, unsigned short flags, char read_write,
-                            u8 command, int size, union i2c_smbus_data *data)
-{
-       struct gb_i2c_device *gb_i2c_dev;
-
-       gb_i2c_dev = i2c_get_adapdata(adap);
-
-       return 0;
-}
-#endif
-
 static u32 gb_i2c_functionality(struct i2c_adapter *adap)
 {
        struct gb_i2c_device *gb_i2c_dev = i2c_get_adapdata(adap);
@@ -238,7 +224,6 @@ static u32 gb_i2c_functionality(struct i2c_adapter *adap)
 
 static const struct i2c_algorithm gb_i2c_algorithm = {
        .master_xfer    = gb_i2c_master_xfer,
-       /* .smbus_xfer  = gb_i2c_smbus_xfer, */
        .functionality  = gb_i2c_functionality,
 };
 
@@ -281,7 +266,6 @@ static int gb_i2c_probe(struct gbphy_device *gbphy_dev,
        adapter->owner = THIS_MODULE;
        adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        adapter->algo = &gb_i2c_algorithm;
-       /* adapter->algo_data = what? */
 
        adapter->dev.parent = &gbphy_dev->dev;
        snprintf(adapter->name, sizeof(adapter->name), "Greybus i2c adapter");
index 64a17df..2a375f4 100644 (file)
@@ -29,7 +29,7 @@ struct gb_raw {
 struct raw_data {
        struct list_head entry;
        u32 len;
-       u8 data[0];
+       u8 data[];
 };
 
 static struct class *raw_class;
index ba6f905..867bf28 100644 (file)
@@ -19,6 +19,7 @@
 #include <signal.h>
 
 #define MAX_NUM_DEVICES 10
+#define MAX_SYSFS_PREFIX 0x80
 #define MAX_SYSFS_PATH 0x200
 #define CSV_MAX_LINE   0x1000
 #define SYSFS_MAX_INT  0x20
@@ -67,7 +68,7 @@ struct loopback_results {
 };
 
 struct loopback_device {
-       char name[MAX_SYSFS_PATH];
+       char name[MAX_STR_LEN];
        char sysfs_entry[MAX_SYSFS_PATH];
        char debugfs_entry[MAX_SYSFS_PATH];
        struct loopback_results results;
@@ -93,8 +94,8 @@ struct loopback_test {
        int stop_all;
        int poll_count;
        char test_name[MAX_STR_LEN];
-       char sysfs_prefix[MAX_SYSFS_PATH];
-       char debugfs_prefix[MAX_SYSFS_PATH];
+       char sysfs_prefix[MAX_SYSFS_PREFIX];
+       char debugfs_prefix[MAX_SYSFS_PREFIX];
        struct timespec poll_timeout;
        struct loopback_device devices[MAX_NUM_DEVICES];
        struct loopback_results aggregate_results;
@@ -637,7 +638,7 @@ baddir:
 static int open_poll_files(struct loopback_test *t)
 {
        struct loopback_device *dev;
-       char buf[MAX_STR_LEN];
+       char buf[MAX_SYSFS_PATH + MAX_STR_LEN];
        char dummy;
        int fds_idx = 0;
        int i;
@@ -655,7 +656,7 @@ static int open_poll_files(struct loopback_test *t)
                        goto err;
                }
                read(t->fds[fds_idx].fd, &dummy, 1);
-               t->fds[fds_idx].events = EPOLLERR|EPOLLPRI;
+               t->fds[fds_idx].events = POLLERR | POLLPRI;
                t->fds[fds_idx].revents = 0;
                fds_idx++;
        }
@@ -748,7 +749,7 @@ static int wait_for_complete(struct loopback_test *t)
                }
 
                for (i = 0; i < t->poll_count; i++) {
-                       if (t->fds[i].revents & EPOLLPRI) {
+                       if (t->fds[i].revents & POLLPRI) {
                                /* Dummy read to clear the event */
                                read(t->fds[i].fd, &dummy, 1);
                                number_of_events++;
@@ -801,8 +802,9 @@ static void prepare_devices(struct loopback_test *t)
                        write_sysfs_val(t->devices[i].sysfs_entry,
                                        "outstanding_operations_max",
                                        t->async_outstanding_operations);
-               } else
+               } else {
                        write_sysfs_val(t->devices[i].sysfs_entry, "async", 0);
+               }
        }
 }
 
@@ -907,10 +909,10 @@ int main(int argc, char *argv[])
                        t.iteration_max = atoi(optarg);
                        break;
                case 'S':
-                       snprintf(t.sysfs_prefix, MAX_SYSFS_PATH, "%s", optarg);
+                       snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg);
                        break;
                case 'D':
-                       snprintf(t.debugfs_prefix, MAX_SYSFS_PATH, "%s", optarg);
+                       snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", optarg);
                        break;
                case 'm':
                        t.mask = atol(optarg);
@@ -961,10 +963,10 @@ int main(int argc, char *argv[])
        }
 
        if (!strcmp(t.sysfs_prefix, ""))
-               snprintf(t.sysfs_prefix, MAX_SYSFS_PATH, "%s", sysfs_prefix);
+               snprintf(t.sysfs_prefix, MAX_SYSFS_PREFIX, "%s", sysfs_prefix);
 
        if (!strcmp(t.debugfs_prefix, ""))
-               snprintf(t.debugfs_prefix, MAX_SYSFS_PATH, "%s", debugfs_prefix);
+               snprintf(t.debugfs_prefix, MAX_SYSFS_PREFIX, "%s", debugfs_prefix);
 
        ret = find_loopback_devices(&t);
        if (ret)
diff --git a/drivers/staging/hp/Kconfig b/drivers/staging/hp/Kconfig
deleted file mode 100644 (file)
index f20ab21..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# HP network device configuration
-#
-
-config NET_VENDOR_HP
-       bool "HP devices"
-       default y
-       depends on ETHERNET
-       depends on ISA || EISA || PCI
-       ---help---
-         If you have a network (Ethernet) card belonging to this class, say Y.
-
-         Note that the answer to this question doesn't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about HP cards. If you say Y, you will be asked for
-         your specific card in the following questions.
-
-if NET_VENDOR_HP
-
-config HP100
-       tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support"
-       depends on (ISA || EISA || PCI)
-       ---help---
-         If you have a network (Ethernet) card of this type, say Y here.
-
-         To compile this driver as a module, choose M here. The module
-         will be called hp100.
-
-endif # NET_VENDOR_HP
diff --git a/drivers/staging/hp/Makefile b/drivers/staging/hp/Makefile
deleted file mode 100644 (file)
index 5ed723b..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the HP network device drivers.
-#
-
-obj-$(CONFIG_HP100) += hp100.o
diff --git a/drivers/staging/hp/hp100.c b/drivers/staging/hp/hp100.c
deleted file mode 100644 (file)
index e2f0b58..0000000
+++ /dev/null
@@ -1,3034 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
-** hp100.c
-** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
-**
-** $Id: hp100.c,v 1.58 2001/09/24 18:03:01 perex Exp perex $
-**
-** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
-** Extended for new busmaster capable chipsets by
-** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
-**
-** Maintained by: Jaroslav Kysela <perex@perex.cz>
-**
-** This driver has only been tested with
-** -- HP J2585B 10/100 Mbit/s PCI Busmaster
-** -- HP J2585A 10/100 Mbit/s PCI
-** -- HP J2970A 10 Mbit/s PCI Combo 10base-T/BNC
-** -- HP J2973A 10 Mbit/s PCI 10base-T
-** -- HP J2573  10/100 ISA
-** -- Compex ReadyLink ENET100-VG4  10/100 Mbit/s PCI / EISA
-** -- Compex FreedomLine 100/VG  10/100 Mbit/s ISA / EISA / PCI
-**
-** but it should also work with the other CASCADE based adapters.
-**
-** TODO:
-**       -  J2573 seems to hang sometimes when in shared memory mode.
-**       -  Mode for Priority TX
-**       -  Check PCI registers, performance might be improved?
-**       -  To reduce interrupt load in busmaster, one could switch off
-**          the interrupts that are used to refill the queues whenever the
-**          queues are filled up to more than a certain threshold.
-**       -  some updates for EISA version of card
-**
-**
-**
-** 1.57c -> 1.58
-**   - used indent to change coding-style
-**   - added KTI DP-200 EISA ID
-**   - ioremap is also used for low (<1MB) memory (multi-architecture support)
-**
-** 1.57b -> 1.57c - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-**   - release resources on failure in init_module
-**
-** 1.57 -> 1.57b - Jean II
-**   - fix spinlocks, SMP is now working !
-**
-** 1.56 -> 1.57
-**   - updates for new PCI interface for 2.1 kernels
-**
-** 1.55 -> 1.56
-**   - removed printk in misc. interrupt and update statistics to allow
-**     monitoring of card status
-**   - timing changes in xmit routines, relogin to 100VG hub added when
-**     driver does reset
-**   - included fix for Compex FreedomLine PCI adapter
-**
-** 1.54 -> 1.55
-**   - fixed bad initialization in init_module
-**   - added Compex FreedomLine adapter
-**   - some fixes in card initialization
-**
-** 1.53 -> 1.54
-**   - added hardware multicast filter support (doesn't work)
-**   - little changes in hp100_sense_lan routine
-**     - added support for Coax and AUI (J2970)
-**   - fix for multiple cards and hp100_mode parameter (insmod)
-**   - fix for shared IRQ
-**
-** 1.52 -> 1.53
-**   - fixed bug in multicast support
-**
-*/
-
-#define HP100_DEFAULT_PRIORITY_TX 0
-
-#undef HP100_DEBUG
-#undef HP100_DEBUG_B           /* Trace  */
-#undef HP100_DEBUG_BM          /* Debug busmaster code (PDL stuff) */
-
-#undef HP100_DEBUG_TRAINING    /* Debug login-to-hub procedure */
-#undef HP100_DEBUG_TX
-#undef HP100_DEBUG_IRQ
-#undef HP100_DEBUG_RX
-
-#undef HP100_MULTICAST_FILTER  /* Need to be debugged... */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/eisa.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-
-#include <asm/io.h>
-
-#include "hp100.h"
-
-/*
- *  defines
- */
-
-#define HP100_BUS_ISA     0
-#define HP100_BUS_EISA    1
-#define HP100_BUS_PCI     2
-
-#define HP100_REGION_SIZE      0x20    /* for ioports */
-#define HP100_SIG_LEN          8       /* same as EISA_SIG_LEN */
-
-#define HP100_MAX_PACKET_SIZE  (1536+4)
-#define HP100_MIN_PACKET_SIZE  60
-
-#ifndef HP100_DEFAULT_RX_RATIO
-/* default - 75% onboard memory on the card are used for RX packets */
-#define HP100_DEFAULT_RX_RATIO 75
-#endif
-
-#ifndef HP100_DEFAULT_PRIORITY_TX
-/* default - don't enable transmit outgoing packets as priority */
-#define HP100_DEFAULT_PRIORITY_TX 0
-#endif
-
-/*
- *  structures
- */
-
-struct hp100_private {
-       spinlock_t lock;
-       char id[HP100_SIG_LEN];
-       u_short chip;
-       u_short soft_model;
-       u_int memory_size;
-       u_int virt_memory_size;
-       u_short rx_ratio;       /* 1 - 99 */
-       u_short priority_tx;    /* != 0 - priority tx */
-       u_short mode;           /* PIO, Shared Mem or Busmaster */
-       u_char bus;
-       struct pci_dev *pci_dev;
-       short mem_mapped;       /* memory mapped access */
-       void __iomem *mem_ptr_virt;     /* virtual memory mapped area, maybe NULL */
-       unsigned long mem_ptr_phys;     /* physical memory mapped area */
-       short lan_type;         /* 10Mb/s, 100Mb/s or -1 (error) */
-       int hub_status;         /* was login to hub successful? */
-       u_char mac1_mode;
-       u_char mac2_mode;
-       u_char hash_bytes[8];
-
-       /* Rings for busmaster mode: */
-       hp100_ring_t *rxrhead;  /* Head (oldest) index into rxring */
-       hp100_ring_t *rxrtail;  /* Tail (newest) index into rxring */
-       hp100_ring_t *txrhead;  /* Head (oldest) index into txring */
-       hp100_ring_t *txrtail;  /* Tail (newest) index into txring */
-
-       hp100_ring_t rxring[MAX_RX_PDL];
-       hp100_ring_t txring[MAX_TX_PDL];
-
-       u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */
-       u_long whatever_offset; /* Offset to bus/phys/dma address */
-       int rxrcommit;          /* # Rx PDLs committed to adapter */
-       int txrcommit;          /* # Tx PDLs committed to adapter */
-};
-
-/*
- *  variables
- */
-#ifdef CONFIG_ISA
-static const char *hp100_isa_tbl[] = {
-       "HWPF150", /* HP J2573 rev A */
-       "HWP1950", /* HP J2573 */
-};
-#endif
-
-static const struct eisa_device_id hp100_eisa_tbl[] = {
-       { "HWPF180" }, /* HP J2577 rev A */
-       { "HWP1920" }, /* HP 27248B */
-       { "HWP1940" }, /* HP J2577 */
-       { "HWP1990" }, /* HP J2577 */
-       { "CPX0301" }, /* ReadyLink ENET100-VG4 */
-       { "CPX0401" }, /* FreedomLine 100/VG */
-       { "" }         /* Mandatory final entry ! */
-};
-MODULE_DEVICE_TABLE(eisa, hp100_eisa_tbl);
-
-static const struct pci_device_id hp100_pci_tbl[] = {
-       {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, PCI_ANY_ID, PCI_ANY_ID,},
-       {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, PCI_ANY_ID, PCI_ANY_ID,},
-       {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2970A, PCI_ANY_ID, PCI_ANY_ID,},
-       {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2973A, PCI_ANY_ID, PCI_ANY_ID,},
-       {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, PCI_ANY_ID, PCI_ANY_ID,},
-       {PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG, PCI_ANY_ID, PCI_ANY_ID,},
-/*     {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_DP200, PCI_ANY_ID, PCI_ANY_ID }, */
-       {}                      /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, hp100_pci_tbl);
-
-static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO;
-static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX;
-static int hp100_mode = 1;
-
-module_param(hp100_rx_ratio, int, 0);
-module_param(hp100_priority_tx, int, 0);
-module_param(hp100_mode, int, 0);
-
-/*
- *  prototypes
- */
-
-static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus,
-                       struct pci_dev *pci_dev);
-
-
-static int hp100_open(struct net_device *dev);
-static int hp100_close(struct net_device *dev);
-static netdev_tx_t hp100_start_xmit(struct sk_buff *skb,
-                                   struct net_device *dev);
-static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb,
-                                      struct net_device *dev);
-static void hp100_rx(struct net_device *dev);
-static struct net_device_stats *hp100_get_stats(struct net_device *dev);
-static void hp100_misc_interrupt(struct net_device *dev);
-static void hp100_update_stats(struct net_device *dev);
-static void hp100_clear_stats(struct hp100_private *lp, int ioaddr);
-static void hp100_set_multicast_list(struct net_device *dev);
-static irqreturn_t hp100_interrupt(int irq, void *dev_id);
-static void hp100_start_interface(struct net_device *dev);
-static void hp100_stop_interface(struct net_device *dev);
-static void hp100_load_eeprom(struct net_device *dev, u_short ioaddr);
-static int hp100_sense_lan(struct net_device *dev);
-static int hp100_login_to_vg_hub(struct net_device *dev,
-                                u_short force_relogin);
-static int hp100_down_vg_link(struct net_device *dev);
-static void hp100_cascade_reset(struct net_device *dev, u_short enable);
-static void hp100_BM_shutdown(struct net_device *dev);
-static void hp100_mmuinit(struct net_device *dev);
-static void hp100_init_pdls(struct net_device *dev);
-static int hp100_init_rxpdl(struct net_device *dev,
-                           register hp100_ring_t * ringptr,
-                           register u_int * pdlptr);
-static int hp100_init_txpdl(struct net_device *dev,
-                           register hp100_ring_t * ringptr,
-                           register u_int * pdlptr);
-static void hp100_rxfill(struct net_device *dev);
-static void hp100_hwinit(struct net_device *dev);
-static void hp100_clean_txring(struct net_device *dev);
-#ifdef HP100_DEBUG
-static void hp100_RegisterDump(struct net_device *dev);
-#endif
-
-/* Conversion to new PCI API :
- * Convert an address in a kernel buffer to a bus/phys/dma address.
- * This work *only* for memory fragments part of lp->page_vaddr,
- * because it was properly DMA allocated via pci_alloc_consistent(),
- * so we just need to "retrieve" the original mapping to bus/phys/dma
- * address - Jean II */
-static inline dma_addr_t virt_to_whatever(struct net_device *dev, u32 * ptr)
-{
-       struct hp100_private *lp = netdev_priv(dev);
-       return ((u_long) ptr) + lp->whatever_offset;
-}
-
-static inline u_int pdl_map_data(struct hp100_private *lp, void *data)
-{
-       return pci_map_single(lp->pci_dev, data,
-                             MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE);
-}
-
-/* TODO: This function should not really be needed in a good design... */
-static void wait(void)
-{
-       mdelay(1);
-}
-
-/*
- *  probe functions
- *  These functions should - if possible - avoid doing write operations
- *  since this could cause problems when the card is not installed.
- */
-
-/*
- * Read board id and convert to string.
- * Effectively same code as decode_eisa_sig
- */
-static const char *hp100_read_id(int ioaddr)
-{
-       int i;
-       static char str[HP100_SIG_LEN];
-       unsigned char sig[4], sum;
-        unsigned short rev;
-
-       hp100_page(ID_MAC_ADDR);
-       sum = 0;
-       for (i = 0; i < 4; i++) {
-               sig[i] = hp100_inb(BOARD_ID + i);
-               sum += sig[i];
-       }
-
-       sum += hp100_inb(BOARD_ID + i);
-       if (sum != 0xff)
-               return NULL;    /* bad checksum */
-
-        str[0] = ((sig[0] >> 2) & 0x1f) + ('A' - 1);
-        str[1] = (((sig[0] & 3) << 3) | (sig[1] >> 5)) + ('A' - 1);
-        str[2] = (sig[1] & 0x1f) + ('A' - 1);
-        rev = (sig[2] << 8) | sig[3];
-        sprintf(str + 3, "%04X", rev);
-
-       return str;
-}
-
-#ifdef CONFIG_ISA
-static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr)
-{
-       const char *sig;
-       int i;
-
-       if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100"))
-               goto err;
-
-       if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) {
-               release_region(ioaddr, HP100_REGION_SIZE);
-               goto err;
-       }
-
-       sig = hp100_read_id(ioaddr);
-       release_region(ioaddr, HP100_REGION_SIZE);
-
-       if (sig == NULL)
-               goto err;
-
-       i = match_string(hp100_isa_tbl, ARRAY_SIZE(hp100_isa_tbl), sig);
-       if (i < 0)
-               goto err;
-
-       return hp100_probe1(dev, ioaddr, HP100_BUS_ISA, NULL);
- err:
-       return -ENODEV;
-
-}
-/*
- * Probe for ISA board.
- * EISA and PCI are handled by device infrastructure.
- */
-
-static int  __init hp100_isa_probe(struct net_device *dev, int addr)
-{
-       int err = -ENODEV;
-
-       /* Probe for a specific ISA address */
-       if (addr > 0xff && addr < 0x400)
-               err = hp100_isa_probe1(dev, addr);
-
-       else if (addr != 0)
-               err = -ENXIO;
-
-       else {
-               /* Probe all ISA possible port regions */
-               for (addr = 0x100; addr < 0x400; addr += 0x20) {
-                       err = hp100_isa_probe1(dev, addr);
-                       if (!err)
-                               break;
-               }
-       }
-       return err;
-}
-#endif /* CONFIG_ISA */
-
-#if !defined(MODULE) && defined(CONFIG_ISA)
-struct net_device * __init hp100_probe(int unit)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
-       int err;
-
-       if (!dev)
-               return ERR_PTR(-ENODEV);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4200, TRACE);
-       printk("hp100: %s: probe\n", dev->name);
-#endif
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       err = hp100_isa_probe(dev, dev->base_addr);
-       if (err)
-               goto out;
-
-       return dev;
- out:
-       free_netdev(dev);
-       return ERR_PTR(err);
-}
-#endif /* !MODULE && CONFIG_ISA */
-
-static const struct net_device_ops hp100_bm_netdev_ops = {
-       .ndo_open               = hp100_open,
-       .ndo_stop               = hp100_close,
-       .ndo_start_xmit         = hp100_start_xmit_bm,
-       .ndo_get_stats          = hp100_get_stats,
-       .ndo_set_rx_mode        = hp100_set_multicast_list,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static const struct net_device_ops hp100_netdev_ops = {
-       .ndo_open               = hp100_open,
-       .ndo_stop               = hp100_close,
-       .ndo_start_xmit         = hp100_start_xmit,
-       .ndo_get_stats          = hp100_get_stats,
-       .ndo_set_rx_mode        = hp100_set_multicast_list,
-       .ndo_set_mac_address    = eth_mac_addr,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static int hp100_probe1(struct net_device *dev, int ioaddr, u_char bus,
-                       struct pci_dev *pci_dev)
-{
-       int i;
-       int err = -ENODEV;
-       const char *eid;
-       u_int chip;
-       u_char uc;
-       u_int memory_size = 0, virt_memory_size = 0;
-       u_short local_mode, lsw;
-       short mem_mapped;
-       unsigned long mem_ptr_phys;
-       void __iomem *mem_ptr_virt;
-       struct hp100_private *lp;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4201, TRACE);
-       printk("hp100: %s: probe1\n", dev->name);
-#endif
-
-       /* memory region for programmed i/o */
-       if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100"))
-               goto out1;
-
-       if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE)
-               goto out2;
-
-       chip = hp100_inw(PAGING) & HP100_CHIPID_MASK;
-#ifdef HP100_DEBUG
-       if (chip == HP100_CHIPID_SHASTA)
-               printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name);
-       else if (chip == HP100_CHIPID_RAINIER)
-               printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name);
-       else if (chip == HP100_CHIPID_LASSEN)
-               printk("hp100: %s: Lassen Chip detected.\n", dev->name);
-       else
-               printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n", dev->name, chip);
-#endif
-
-       dev->base_addr = ioaddr;
-
-       eid = hp100_read_id(ioaddr);
-       if (eid == NULL) {      /* bad checksum? */
-               printk(KERN_WARNING "%s: bad ID checksum at base port 0x%x\n",
-                      __func__, ioaddr);
-               goto out2;
-       }
-
-       hp100_page(ID_MAC_ADDR);
-       for (i = uc = 0; i < 7; i++)
-               uc += hp100_inb(LAN_ADDR + i);
-       if (uc != 0xff) {
-               printk(KERN_WARNING
-                      "%s: bad lan address checksum at port 0x%x)\n",
-                      __func__, ioaddr);
-               err = -EIO;
-               goto out2;
-       }
-
-       /* Make sure, that all registers are correctly updated... */
-
-       hp100_load_eeprom(dev, ioaddr);
-       wait();
-
-       /*
-        * Determine driver operation mode
-        *
-        * Use the variable "hp100_mode" upon insmod or as kernel parameter to
-        * force driver modes:
-        * hp100_mode=1 -> default, use busmaster mode if configured.
-        * hp100_mode=2 -> enable shared memory mode
-        * hp100_mode=3 -> force use of i/o mapped mode.
-        * hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
-        */
-
-       /*
-        * LSW values:
-        *   0x2278 -> J2585B, PnP shared memory mode
-        *   0x2270 -> J2585B, shared memory mode, 0xdc000
-        *   0xa23c -> J2585B, I/O mapped mode
-        *   0x2240 -> EISA COMPEX, BusMaster (Shasta Chip)
-        *   0x2220 -> EISA HP, I/O (Shasta Chip)
-        *   0x2260 -> EISA HP, BusMaster (Shasta Chip)
-        */
-
-#if 0
-       local_mode = 0x2270;
-       hp100_outw(0xfefe, OPTION_LSW);
-       hp100_outw(local_mode | HP100_SET_LB | HP100_SET_HB, OPTION_LSW);
-#endif
-
-       /* hp100_mode value maybe used in future by another card */
-       local_mode = hp100_mode;
-       if (local_mode < 1 || local_mode > 4)
-               local_mode = 1; /* default */
-#ifdef HP100_DEBUG
-       printk("hp100: %s: original LSW = 0x%x\n", dev->name,
-              hp100_inw(OPTION_LSW));
-#endif
-
-       if (local_mode == 3) {
-               hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW);
-               hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW);
-               hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW);
-               printk("hp100: IO mapped mode forced.\n");
-       } else if (local_mode == 2) {
-               hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW);
-               hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW);
-               hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW);
-               printk("hp100: Shared memory mode requested.\n");
-       } else if (local_mode == 4) {
-               if (chip == HP100_CHIPID_LASSEN) {
-                       hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_SET_HB, OPTION_LSW);
-                       hp100_outw(HP100_IO_EN | HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW);
-                       printk("hp100: Busmaster mode requested.\n");
-               }
-               local_mode = 1;
-       }
-
-       if (local_mode == 1) {  /* default behaviour */
-               lsw = hp100_inw(OPTION_LSW);
-
-               if ((lsw & HP100_IO_EN) && (~lsw & HP100_MEM_EN) &&
-                   (~lsw & (HP100_BM_WRITE | HP100_BM_READ))) {
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: IO_EN bit is set on card.\n", dev->name);
-#endif
-                       local_mode = 3;
-               } else if (chip == HP100_CHIPID_LASSEN &&
-                          (lsw & (HP100_BM_WRITE | HP100_BM_READ)) == (HP100_BM_WRITE | HP100_BM_READ)) {
-                       /* Conversion to new PCI API :
-                        * I don't have the doc, but I assume that the card
-                        * can map the full 32bit address space.
-                        * Also, we can have EISA Busmaster cards (not tested),
-                        * so beware !!! - Jean II */
-                       if((bus == HP100_BUS_PCI) &&
-                          (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)))) {
-                               /* Gracefully fallback to shared memory */
-                               goto busmasterfail;
-                       }
-                       printk("hp100: Busmaster mode enabled.\n");
-                       hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW);
-               } else {
-               busmasterfail:
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name);
-                       printk("hp100: %s: Trying shared memory mode.\n", dev->name);
-#endif
-                       /* In this case, try shared memory mode */
-                       local_mode = 2;
-                       hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW);
-                       /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */
-               }
-       }
-#ifdef HP100_DEBUG
-       printk("hp100: %s: new LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW));
-#endif
-
-       /* Check for shared memory on the card, eventually remap it */
-       hp100_page(HW_MAP);
-       mem_mapped = ((hp100_inw(OPTION_LSW) & (HP100_MEM_EN)) != 0);
-       mem_ptr_phys = 0UL;
-       mem_ptr_virt = NULL;
-       memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07));
-       virt_memory_size = 0;
-
-       /* For memory mapped or busmaster mode, we want the memory address */
-       if (mem_mapped || (local_mode == 1)) {
-               mem_ptr_phys = (hp100_inw(MEM_MAP_LSW) | (hp100_inw(MEM_MAP_MSW) << 16));
-               mem_ptr_phys &= ~0x1fff;        /* 8k alignment */
-
-               if (bus == HP100_BUS_ISA && (mem_ptr_phys & ~0xfffff) != 0) {
-                       printk("hp100: Can only use programmed i/o mode.\n");
-                       mem_ptr_phys = 0;
-                       mem_mapped = 0;
-                       local_mode = 3; /* Use programmed i/o */
-               }
-
-               /* We do not need access to shared memory in busmaster mode */
-               /* However in slave mode we need to remap high (>1GB) card memory  */
-               if (local_mode != 1) {  /* = not busmaster */
-                       /* We try with smaller memory sizes, if ioremap fails */
-                       for (virt_memory_size = memory_size; virt_memory_size > 16383; virt_memory_size >>= 1) {
-                               if ((mem_ptr_virt = ioremap((u_long) mem_ptr_phys, virt_memory_size)) == NULL) {
-#ifdef HP100_DEBUG
-                                       printk("hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, mem_ptr_phys);
-#endif
-                               } else {
-#ifdef HP100_DEBUG
-                                       printk("hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to %p.\n", dev->name, virt_memory_size, mem_ptr_phys, mem_ptr_virt);
-#endif
-                                       break;
-                               }
-                       }
-
-                       if (mem_ptr_virt == NULL) {     /* all ioremap tries failed */
-                               printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n");
-                               local_mode = 3;
-                               virt_memory_size = 0;
-                       }
-               }
-       }
-
-       if (local_mode == 3) {  /* io mapped forced */
-               mem_mapped = 0;
-               mem_ptr_phys = 0;
-               mem_ptr_virt = NULL;
-               printk("hp100: Using (slow) programmed i/o mode.\n");
-       }
-
-       /* Initialise the "private" data structure for this card. */
-       lp = netdev_priv(dev);
-
-       spin_lock_init(&lp->lock);
-       strlcpy(lp->id, eid, HP100_SIG_LEN);
-       lp->chip = chip;
-       lp->mode = local_mode;
-       lp->bus = bus;
-       lp->pci_dev = pci_dev;
-       lp->priority_tx = hp100_priority_tx;
-       lp->rx_ratio = hp100_rx_ratio;
-       lp->mem_ptr_phys = mem_ptr_phys;
-       lp->mem_ptr_virt = mem_ptr_virt;
-       hp100_page(ID_MAC_ADDR);
-       lp->soft_model = hp100_inb(SOFT_MODEL);
-       lp->mac1_mode = HP100_MAC1MODE3;
-       lp->mac2_mode = HP100_MAC2MODE3;
-       memset(&lp->hash_bytes, 0x00, 8);
-
-       dev->base_addr = ioaddr;
-
-       lp->memory_size = memory_size;
-       lp->virt_memory_size = virt_memory_size;
-       lp->rx_ratio = hp100_rx_ratio;  /* can be conf'd with insmod */
-
-       if (lp->mode == 1)      /* busmaster */
-               dev->netdev_ops = &hp100_bm_netdev_ops;
-       else
-               dev->netdev_ops = &hp100_netdev_ops;
-
-       /* Ask the card for which IRQ line it is configured */
-       if (bus == HP100_BUS_PCI) {
-               dev->irq = pci_dev->irq;
-       } else {
-               hp100_page(HW_MAP);
-               dev->irq = hp100_inb(IRQ_CHANNEL) & HP100_IRQMASK;
-               if (dev->irq == 2)
-                       dev->irq = 9;
-       }
-
-       if (lp->mode == 1)      /* busmaster */
-               dev->dma = 4;
-
-       /* Ask the card for its MAC address and store it for later use. */
-       hp100_page(ID_MAC_ADDR);
-       for (i = uc = 0; i < 6; i++)
-               dev->dev_addr[i] = hp100_inb(LAN_ADDR + i);
-
-       /* Reset statistics (counters) */
-       hp100_clear_stats(lp, ioaddr);
-
-       /* If busmaster mode is wanted, a dma-capable memory area is needed for
-        * the rx and tx PDLs
-        * PCI cards can access the whole PC memory. Therefore GFP_DMA is not
-        * needed for the allocation of the memory area.
-        */
-
-       /* TODO: We do not need this with old cards, where PDLs are stored
-        * in the cards shared memory area. But currently, busmaster has been
-        * implemented/tested only with the lassen chip anyway... */
-       if (lp->mode == 1) {    /* busmaster */
-               dma_addr_t page_baddr;
-               /* Get physically continuous memory for TX & RX PDLs    */
-               /* Conversion to new PCI API :
-                * Pages are always aligned and zeroed, no need to it ourself.
-                * Doc says should be OK for EISA bus as well - Jean II */
-               lp->page_vaddr_algn = pci_alloc_consistent(lp->pci_dev, MAX_RINGSIZE, &page_baddr);
-               if (!lp->page_vaddr_algn) {
-                       err = -ENOMEM;
-                       goto out_mem_ptr;
-               }
-               lp->whatever_offset = ((u_long) page_baddr) - ((u_long) lp->page_vaddr_algn);
-
-#ifdef HP100_DEBUG_BM
-               printk("hp100: %s: Reserved DMA memory from 0x%x to 0x%x\n", dev->name, (u_int) lp->page_vaddr_algn, (u_int) lp->page_vaddr_algn + MAX_RINGSIZE);
-#endif
-               lp->rxrcommit = lp->txrcommit = 0;
-               lp->rxrhead = lp->rxrtail = &(lp->rxring[0]);
-               lp->txrhead = lp->txrtail = &(lp->txring[0]);
-       }
-
-       /* Initialise the card. */
-       /* (I'm not really sure if it's a good idea to do this during probing, but
-        * like this it's assured that the lan connection type can be sensed
-        * correctly)
-        */
-       hp100_hwinit(dev);
-
-       /* Try to find out which kind of LAN the card is connected to. */
-       lp->lan_type = hp100_sense_lan(dev);
-
-       /* Print out a message what about what we think we have probed. */
-       printk("hp100: at 0x%x, IRQ %d, ", ioaddr, dev->irq);
-       switch (bus) {
-       case HP100_BUS_EISA:
-               printk("EISA");
-               break;
-       case HP100_BUS_PCI:
-               printk("PCI");
-               break;
-       default:
-               printk("ISA");
-               break;
-       }
-       printk(" bus, %dk SRAM (rx/tx %d%%).\n", lp->memory_size >> 10, lp->rx_ratio);
-
-       if (lp->mode == 2) {    /* memory mapped */
-               printk("hp100: Memory area at 0x%lx-0x%lx", mem_ptr_phys,
-                               (mem_ptr_phys + (mem_ptr_phys > 0x100000 ? (u_long) lp->memory_size : 16 * 1024)) - 1);
-               if (mem_ptr_virt)
-                       printk(" (virtual base %p)", mem_ptr_virt);
-               printk(".\n");
-
-               /* Set for info when doing ifconfig */
-               dev->mem_start = mem_ptr_phys;
-               dev->mem_end = mem_ptr_phys + lp->memory_size;
-       }
-
-       printk("hp100: ");
-       if (lp->lan_type != HP100_LAN_ERR)
-               printk("Adapter is attached to ");
-       switch (lp->lan_type) {
-       case HP100_LAN_100:
-               printk("100Mb/s Voice Grade AnyLAN network.\n");
-               break;
-       case HP100_LAN_10:
-               printk("10Mb/s network (10baseT).\n");
-               break;
-       case HP100_LAN_COAX:
-               printk("10Mb/s network (coax).\n");
-               break;
-       default:
-               printk("Warning! Link down.\n");
-       }
-
-       err = register_netdev(dev);
-       if (err)
-               goto out3;
-
-       return 0;
-out3:
-       if (local_mode == 1)
-               pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f,
-                                   lp->page_vaddr_algn,
-                                   virt_to_whatever(dev, lp->page_vaddr_algn));
-out_mem_ptr:
-       if (mem_ptr_virt)
-               iounmap(mem_ptr_virt);
-out2:
-       release_region(ioaddr, HP100_REGION_SIZE);
-out1:
-       return err;
-}
-
-/* This procedure puts the card into a stable init state */
-static void hp100_hwinit(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4202, TRACE);
-       printk("hp100: %s: hwinit\n", dev->name);
-#endif
-
-       /* Initialise the card. -------------------------------------------- */
-
-       /* Clear all pending Ints and disable Ints */
-       hp100_page(PERFORMANCE);
-       hp100_outw(0xfefe, IRQ_MASK);   /* mask off all ints */
-       hp100_outw(0xffff, IRQ_STATUS); /* clear all pending ints */
-
-       hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
-       hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW);
-
-       if (lp->mode == 1) {
-               hp100_BM_shutdown(dev); /* disables BM, puts cascade in reset */
-               wait();
-       } else {
-               hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
-               hp100_cascade_reset(dev, 1);
-               hp100_page(MAC_CTRL);
-               hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1);
-       }
-
-       /* Initiate EEPROM reload */
-       hp100_load_eeprom(dev, 0);
-
-       wait();
-
-       /* Go into reset again. */
-       hp100_cascade_reset(dev, 1);
-
-       /* Set Option Registers to a safe state  */
-       hp100_outw(HP100_DEBUG_EN |
-                  HP100_RX_HDR |
-                  HP100_EE_EN |
-                  HP100_BM_WRITE |
-                  HP100_BM_READ | HP100_RESET_HB |
-                  HP100_FAKE_INT |
-                  HP100_INT_EN |
-                  HP100_MEM_EN |
-                  HP100_IO_EN | HP100_RESET_LB, OPTION_LSW);
-
-       hp100_outw(HP100_TRI_INT |
-                  HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW);
-
-       hp100_outb(HP100_PRIORITY_TX |
-                  HP100_ADV_NXT_PKT |
-                  HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW);
-
-       /* TODO: Configure MMU for Ram Test. */
-       /* TODO: Ram Test. */
-
-       /* Re-check if adapter is still at same i/o location      */
-       /* (If the base i/o in eeprom has been changed but the    */
-       /* registers had not been changed, a reload of the eeprom */
-       /* would move the adapter to the address stored in eeprom */
-
-       /* TODO: Code to implement. */
-
-       /* Until here it was code from HWdiscover procedure. */
-       /* Next comes code from mmuinit procedure of SCO BM driver which is
-        * called from HWconfigure in the SCO driver.  */
-
-       /* Initialise MMU, eventually switch on Busmaster Mode, initialise
-        * multicast filter...
-        */
-       hp100_mmuinit(dev);
-
-       /* We don't turn the interrupts on here - this is done by start_interface. */
-       wait();                 /* TODO: Do we really need this? */
-
-       /* Enable Hardware (e.g. unreset) */
-       hp100_cascade_reset(dev, 0);
-
-       /* ------- initialisation complete ----------- */
-
-       /* Finally try to log in the Hub if there may be a VG connection. */
-       if ((lp->lan_type == HP100_LAN_100) || (lp->lan_type == HP100_LAN_ERR))
-               hp100_login_to_vg_hub(dev, 0);  /* relogin */
-
-}
-
-
-/*
- * mmuinit - Reinitialise Cascade MMU and MAC settings.
- * Note: Must already be in reset and leaves card in reset.
- */
-static void hp100_mmuinit(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-       int i;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4203, TRACE);
-       printk("hp100: %s: mmuinit\n", dev->name);
-#endif
-
-#ifdef HP100_DEBUG
-       if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) {
-               printk("hp100: %s: Not in reset when entering mmuinit. Fix me.\n", dev->name);
-               return;
-       }
-#endif
-
-       /* Make sure IRQs are masked off and ack'ed. */
-       hp100_page(PERFORMANCE);
-       hp100_outw(0xfefe, IRQ_MASK);   /* mask off all ints */
-       hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
-
-       /*
-        * Enable Hardware
-        * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En
-        * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable
-        * - Clear Priority, Advance Pkt and Xmit Cmd
-        */
-
-       hp100_outw(HP100_DEBUG_EN |
-                  HP100_RX_HDR |
-                  HP100_EE_EN | HP100_RESET_HB |
-                  HP100_IO_EN |
-                  HP100_FAKE_INT |
-                  HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
-
-       hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW);
-
-       if (lp->mode == 1) {    /* busmaster */
-               hp100_outw(HP100_BM_WRITE |
-                          HP100_BM_READ |
-                          HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW);
-       } else if (lp->mode == 2) {     /* memory mapped */
-               hp100_outw(HP100_BM_WRITE |
-                          HP100_BM_READ | HP100_RESET_HB, OPTION_LSW);
-               hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW);
-               hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW);
-               hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW);
-       } else if (lp->mode == 3) {     /* i/o mapped mode */
-               hp100_outw(HP100_MMAP_DIS | HP100_SET_HB |
-                          HP100_IO_EN | HP100_SET_LB, OPTION_LSW);
-       }
-
-       hp100_page(HW_MAP);
-       hp100_outb(0, EARLYRXCFG);
-       hp100_outw(0, EARLYTXCFG);
-
-       /*
-        * Enable Bus Master mode
-        */
-       if (lp->mode == 1) {    /* busmaster */
-               /* Experimental: Set some PCI configuration bits */
-               hp100_page(HW_MAP);
-               hp100_andb(~HP100_PDL_USE3, MODECTRL1); /* BM engine read maximum */
-               hp100_andb(~HP100_TX_DUALQ, MODECTRL1); /* No Queue for Priority TX */
-
-               /* PCI Bus failures should result in a Misc. Interrupt */
-               hp100_orb(HP100_EN_BUS_FAIL, MODECTRL2);
-
-               hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW);
-               hp100_page(HW_MAP);
-               /* Use Burst Mode and switch on PAGE_CK */
-               hp100_orb(HP100_BM_BURST_RD | HP100_BM_BURST_WR, BM);
-               if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA))
-                       hp100_orb(HP100_BM_PAGE_CK, BM);
-               hp100_orb(HP100_BM_MASTER, BM);
-       } else {                /* not busmaster */
-
-               hp100_page(HW_MAP);
-               hp100_andb(~HP100_BM_MASTER, BM);
-       }
-
-       /*
-        * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs
-        */
-       hp100_page(MMU_CFG);
-       if (lp->mode == 1) {    /* only needed for Busmaster */
-               int xmit_stop, recv_stop;
-
-               if ((lp->chip == HP100_CHIPID_RAINIER) ||
-                   (lp->chip == HP100_CHIPID_SHASTA)) {
-                       int pdl_stop;
-
-                       /*
-                        * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and
-                        * 4 bytes for header). We will leave NUM_RXPDLS * 508 (rounded
-                        * to the next higher 1k boundary) bytes for the rx-pdl's
-                        * Note: For non-etr chips the transmit stop register must be
-                        * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
-                        */
-                       pdl_stop = lp->memory_size;
-                       xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff);
-                       recv_stop = (xmit_stop * (lp->rx_ratio) / 100) & ~(0x03ff);
-                       hp100_outw((pdl_stop >> 4) - 1, PDL_MEM_STOP);
-#ifdef HP100_DEBUG_BM
-                       printk("hp100: %s: PDL_STOP = 0x%x\n", dev->name, pdl_stop);
-#endif
-               } else {
-                       /* ETR chip (Lassen) in busmaster mode */
-                       xmit_stop = (lp->memory_size) - 1;
-                       recv_stop = ((lp->memory_size * lp->rx_ratio) / 100) & ~(0x03ff);
-               }
-
-               hp100_outw(xmit_stop >> 4, TX_MEM_STOP);
-               hp100_outw(recv_stop >> 4, RX_MEM_STOP);
-#ifdef HP100_DEBUG_BM
-               printk("hp100: %s: TX_STOP  = 0x%x\n", dev->name, xmit_stop >> 4);
-               printk("hp100: %s: RX_STOP  = 0x%x\n", dev->name, recv_stop >> 4);
-#endif
-       } else {
-               /* Slave modes (memory mapped and programmed io)  */
-               hp100_outw((((lp->memory_size * lp->rx_ratio) / 100) >> 4), RX_MEM_STOP);
-               hp100_outw(((lp->memory_size - 1) >> 4), TX_MEM_STOP);
-#ifdef HP100_DEBUG
-               printk("hp100: %s: TX_MEM_STOP: 0x%x\n", dev->name, hp100_inw(TX_MEM_STOP));
-               printk("hp100: %s: RX_MEM_STOP: 0x%x\n", dev->name, hp100_inw(RX_MEM_STOP));
-#endif
-       }
-
-       /* Write MAC address into page 1 */
-       hp100_page(MAC_ADDRESS);
-       for (i = 0; i < 6; i++)
-               hp100_outb(dev->dev_addr[i], MAC_ADDR + i);
-
-       /* Zero the multicast hash registers */
-       for (i = 0; i < 8; i++)
-               hp100_outb(0x0, HASH_BYTE0 + i);
-
-       /* Set up MAC defaults */
-       hp100_page(MAC_CTRL);
-
-       /* Go to LAN Page and zero all filter bits */
-       /* Zero accept error, accept multicast, accept broadcast and accept */
-       /* all directed packet bits */
-       hp100_andb(~(HP100_RX_EN |
-                    HP100_TX_EN |
-                    HP100_ACC_ERRORED |
-                    HP100_ACC_MC |
-                    HP100_ACC_BC | HP100_ACC_PHY), MAC_CFG_1);
-
-       hp100_outb(0x00, MAC_CFG_2);
-
-       /* Zero the frame format bit. This works around a training bug in the */
-       /* new hubs. */
-       hp100_outb(0x00, VG_LAN_CFG_2); /* (use 802.3) */
-
-       if (lp->priority_tx)
-               hp100_outb(HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW);
-       else
-               hp100_outb(HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW);
-
-       hp100_outb(HP100_ADV_NXT_PKT |
-                  HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW);
-
-       /* If busmaster, initialize the PDLs */
-       if (lp->mode == 1)
-               hp100_init_pdls(dev);
-
-       /* Go to performance page and initialize isr and imr registers */
-       hp100_page(PERFORMANCE);
-       hp100_outw(0xfefe, IRQ_MASK);   /* mask off all ints */
-       hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
-}
-
-/*
- *  open/close functions
- */
-
-static int hp100_open(struct net_device *dev)
-{
-       struct hp100_private *lp = netdev_priv(dev);
-#ifdef HP100_DEBUG_B
-       int ioaddr = dev->base_addr;
-#endif
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4204, TRACE);
-       printk("hp100: %s: open\n", dev->name);
-#endif
-
-       /* New: if bus is PCI or EISA, interrupts might be shared interrupts */
-       if (request_irq(dev->irq, hp100_interrupt,
-                       lp->bus == HP100_BUS_PCI || lp->bus ==
-                       HP100_BUS_EISA ? IRQF_SHARED : 0,
-                       dev->name, dev)) {
-               printk("hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq);
-               return -EAGAIN;
-       }
-
-       netif_trans_update(dev); /* prevent tx timeout */
-       netif_start_queue(dev);
-
-       lp->lan_type = hp100_sense_lan(dev);
-       lp->mac1_mode = HP100_MAC1MODE3;
-       lp->mac2_mode = HP100_MAC2MODE3;
-       memset(&lp->hash_bytes, 0x00, 8);
-
-       hp100_stop_interface(dev);
-
-       hp100_hwinit(dev);
-
-       hp100_start_interface(dev);     /* sets mac modes, enables interrupts */
-
-       return 0;
-}
-
-/* The close function is called when the interface is to be brought down */
-static int hp100_close(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4205, TRACE);
-       printk("hp100: %s: close\n", dev->name);
-#endif
-
-       hp100_page(PERFORMANCE);
-       hp100_outw(0xfefe, IRQ_MASK);   /* mask off all IRQs */
-
-       hp100_stop_interface(dev);
-
-       if (lp->lan_type == HP100_LAN_100)
-               lp->hub_status = hp100_login_to_vg_hub(dev, 0);
-
-       netif_stop_queue(dev);
-
-       free_irq(dev->irq, dev);
-
-#ifdef HP100_DEBUG
-       printk("hp100: %s: close LSW = 0x%x\n", dev->name,
-              hp100_inw(OPTION_LSW));
-#endif
-
-       return 0;
-}
-
-
-/*
- * Configure the PDL Rx rings and LAN
- */
-static void hp100_init_pdls(struct net_device *dev)
-{
-       struct hp100_private *lp = netdev_priv(dev);
-       hp100_ring_t *ringptr;
-       u_int *pageptr;         /* Warning : increment by 4 - Jean II */
-       int i;
-
-#ifdef HP100_DEBUG_B
-       int ioaddr = dev->base_addr;
-#endif
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4206, TRACE);
-       printk("hp100: %s: init pdls\n", dev->name);
-#endif
-
-       if (!lp->page_vaddr_algn)
-               printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n", dev->name);
-       else {
-               /* pageptr shall point into the DMA accessible memory region  */
-               /* we use this pointer to status the upper limit of allocated */
-               /* memory in the allocated page. */
-               /* note: align the pointers to the pci cache line size */
-               memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE);   /* Zero  Rx/Tx ring page */
-               pageptr = lp->page_vaddr_algn;
-
-               lp->rxrcommit = 0;
-               ringptr = lp->rxrhead = lp->rxrtail = &(lp->rxring[0]);
-
-               /* Initialise Rx Ring */
-               for (i = MAX_RX_PDL - 1; i >= 0; i--) {
-                       lp->rxring[i].next = ringptr;
-                       ringptr = &(lp->rxring[i]);
-                       pageptr += hp100_init_rxpdl(dev, ringptr, pageptr);
-               }
-
-               /* Initialise Tx Ring */
-               lp->txrcommit = 0;
-               ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]);
-               for (i = MAX_TX_PDL - 1; i >= 0; i--) {
-                       lp->txring[i].next = ringptr;
-                       ringptr = &(lp->txring[i]);
-                       pageptr += hp100_init_txpdl(dev, ringptr, pageptr);
-               }
-       }
-}
-
-
-/* These functions "format" the entries in the pdl structure   */
-/* They return how much memory the fragments need.            */
-static int hp100_init_rxpdl(struct net_device *dev,
-                           register hp100_ring_t * ringptr,
-                           register u32 * pdlptr)
-{
-       /* pdlptr is starting address for this pdl */
-
-       if (0 != (((unsigned long) pdlptr) & 0xf))
-               printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%lx.\n",
-                      dev->name, (unsigned long) pdlptr);
-
-       ringptr->pdl = pdlptr + 1;
-       ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1);
-       ringptr->skb = NULL;
-
-       /*
-        * Write address and length of first PDL Fragment (which is used for
-        * storing the RX-Header
-        * We use the 4 bytes _before_ the PDH in the pdl memory area to
-        * store this information. (PDH is at offset 0x04)
-        */
-       /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
-
-       *(pdlptr + 2) = (u_int) virt_to_whatever(dev, pdlptr);  /* Address Frag 1 */
-       *(pdlptr + 3) = 4;      /* Length  Frag 1 */
-
-       return roundup(MAX_RX_FRAG * 2 + 2, 4);
-}
-
-
-static int hp100_init_txpdl(struct net_device *dev,
-                           register hp100_ring_t * ringptr,
-                           register u32 * pdlptr)
-{
-       if (0 != (((unsigned long) pdlptr) & 0xf))
-               printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%lx.\n", dev->name, (unsigned long) pdlptr);
-
-       ringptr->pdl = pdlptr;  /* +1; */
-       ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr);     /* +1 */
-       ringptr->skb = NULL;
-
-       return roundup(MAX_TX_FRAG * 2 + 2, 4);
-}
-
-/*
- * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes
- * for possible odd word alignment rounding up to next dword and set PDL
- * address for fragment#2
- * Returns: 0 if unable to allocate skb_buff
- *          1 if successful
- */
-static int hp100_build_rx_pdl(hp100_ring_t * ringptr,
-                             struct net_device *dev)
-{
-#ifdef HP100_DEBUG_B
-       int ioaddr = dev->base_addr;
-#endif
-#ifdef HP100_DEBUG_BM
-       u_int *p;
-#endif
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4207, TRACE);
-       printk("hp100: %s: build rx pdl\n", dev->name);
-#endif
-
-       /* Allocate skb buffer of maximum size */
-       /* Note: This depends on the alloc_skb functions allocating more
-        * space than requested, i.e. aligning to 16bytes */
-
-       ringptr->skb = netdev_alloc_skb(dev, roundup(MAX_ETHER_SIZE + 2, 4));
-
-       if (NULL != ringptr->skb) {
-               /*
-                * Reserve 2 bytes at the head of the buffer to land the IP header
-                * on a long word boundary (According to the Network Driver section
-                * in the Linux KHG, this should help to increase performance.)
-                */
-               skb_reserve(ringptr->skb, 2);
-
-               ringptr->skb->data = skb_put(ringptr->skb, MAX_ETHER_SIZE);
-
-               /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */
-               /* Note: 1st Fragment is used for the 4 byte packet status
-                * (receive header). Its PDL entries are set up by init_rxpdl. So
-                * here we only have to set up the PDL fragment entries for the data
-                * part. Those 4 bytes will be stored in the DMA memory region
-                * directly before the PDL.
-                */
-#ifdef HP100_DEBUG_BM
-               printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n",
-                                    dev->name, (u_int) ringptr->pdl,
-                                    roundup(MAX_ETHER_SIZE + 2, 4),
-                                    (unsigned int) ringptr->skb->data);
-#endif
-
-               /* Conversion to new PCI API : map skbuf data to PCI bus.
-                * Doc says it's OK for EISA as well - Jean II */
-               ringptr->pdl[0] = 0x00020000;   /* Write PDH */
-               ringptr->pdl[3] = pdl_map_data(netdev_priv(dev),
-                                              ringptr->skb->data);
-               ringptr->pdl[4] = MAX_ETHER_SIZE;       /* Length of Data */
-
-#ifdef HP100_DEBUG_BM
-               for (p = (ringptr->pdl); p < (ringptr->pdl + 5); p++)
-                       printk("hp100: %s: Adr 0x%.8x = 0x%.8x\n", dev->name, (u_int) p, (u_int) * p);
-#endif
-               return 1;
-       }
-       /* else: */
-       /* alloc_skb failed (no memory) -> still can receive the header
-        * fragment into PDL memory. make PDL safe by clearing msgptr and
-        * making the PDL only 1 fragment (i.e. the 4 byte packet status)
-        */
-#ifdef HP100_DEBUG_BM
-       printk("hp100: %s: build_rx_pdl: PDH@0x%x, No space for skb.\n", dev->name, (u_int) ringptr->pdl);
-#endif
-
-       ringptr->pdl[0] = 0x00010000;   /* PDH: Count=1 Fragment */
-
-       return 0;
-}
-
-/*
- *  hp100_rxfill - attempt to fill the Rx Ring will empty skb's
- *
- * Makes assumption that skb's are always contiguous memory areas and
- * therefore PDLs contain only 2 physical fragments.
- * -  While the number of Rx PDLs with buffers is less than maximum
- *      a.  Get a maximum packet size skb
- *      b.  Put the physical address of the buffer into the PDL.
- *      c.  Output physical address of PDL to adapter.
- */
-static void hp100_rxfill(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-
-       struct hp100_private *lp = netdev_priv(dev);
-       hp100_ring_t *ringptr;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4208, TRACE);
-       printk("hp100: %s: rxfill\n", dev->name);
-#endif
-
-       hp100_page(PERFORMANCE);
-
-       while (lp->rxrcommit < MAX_RX_PDL) {
-               /*
-                  ** Attempt to get a buffer and build a Rx PDL.
-                */
-               ringptr = lp->rxrtail;
-               if (0 == hp100_build_rx_pdl(ringptr, dev)) {
-                       return; /* None available, return */
-               }
-
-               /* Hand this PDL over to the card */
-               /* Note: This needs performance page selected! */
-#ifdef HP100_DEBUG_BM
-               printk("hp100: %s: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n",
-                                    dev->name, lp->rxrcommit, (u_int) ringptr->pdl,
-                                    (u_int) ringptr->pdl_paddr, (u_int) ringptr->pdl[3]);
-#endif
-
-               hp100_outl((u32) ringptr->pdl_paddr, RX_PDA);
-
-               lp->rxrcommit += 1;
-               lp->rxrtail = ringptr->next;
-       }
-}
-
-/*
- * BM_shutdown - shutdown bus mastering and leave chip in reset state
- */
-
-static void hp100_BM_shutdown(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-       unsigned long time;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4209, TRACE);
-       printk("hp100: %s: bm shutdown\n", dev->name);
-#endif
-
-       hp100_page(PERFORMANCE);
-       hp100_outw(0xfefe, IRQ_MASK);   /* mask off all ints */
-       hp100_outw(0xffff, IRQ_STATUS); /* Ack all ints */
-
-       /* Ensure Interrupts are off */
-       hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW);
-
-       /* Disable all MAC activity */
-       hp100_page(MAC_CTRL);
-       hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1);    /* stop rx/tx */
-
-       /* If cascade MMU is not already in reset */
-       if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) {
-               /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so
-                * MMU pointers will not be reset out from underneath
-                */
-               hp100_page(MAC_CTRL);
-               for (time = 0; time < 5000; time++) {
-                       if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == (HP100_TX_IDLE | HP100_RX_IDLE))
-                               break;
-               }
-
-               /* Shutdown algorithm depends on the generation of Cascade */
-               if (lp->chip == HP100_CHIPID_LASSEN) {  /* ETR shutdown/reset */
-                       /* Disable Busmaster mode and wait for bit to go to zero. */
-                       hp100_page(HW_MAP);
-                       hp100_andb(~HP100_BM_MASTER, BM);
-                       /* 100 ms timeout */
-                       for (time = 0; time < 32000; time++) {
-                               if (0 == (hp100_inb(BM) & HP100_BM_MASTER))
-                                       break;
-                       }
-               } else {        /* Shasta or Rainier Shutdown/Reset */
-                       /* To ensure all bus master inloading activity has ceased,
-                        * wait for no Rx PDAs or no Rx packets on card.
-                        */
-                       hp100_page(PERFORMANCE);
-                       /* 100 ms timeout */
-                       for (time = 0; time < 10000; time++) {
-                               /* RX_PDL: PDLs not executed. */
-                               /* RX_PKT_CNT: RX'd packets on card. */
-                               if ((hp100_inb(RX_PDL) == 0) && (hp100_inb(RX_PKT_CNT) == 0))
-                                       break;
-                       }
-
-                       if (time >= 10000)
-                               printk("hp100: %s: BM shutdown error.\n", dev->name);
-
-                       /* To ensure all bus master outloading activity has ceased,
-                        * wait until the Tx PDA count goes to zero or no more Tx space
-                        * available in the Tx region of the card.
-                        */
-                       /* 100 ms timeout */
-                       for (time = 0; time < 10000; time++) {
-                               if ((0 == hp100_inb(TX_PKT_CNT)) &&
-                                   (0 != (hp100_inb(TX_MEM_FREE) & HP100_AUTO_COMPARE)))
-                                       break;
-                       }
-
-                       /* Disable Busmaster mode */
-                       hp100_page(HW_MAP);
-                       hp100_andb(~HP100_BM_MASTER, BM);
-               }       /* end of shutdown procedure for non-etr parts */
-
-               hp100_cascade_reset(dev, 1);
-       }
-       hp100_page(PERFORMANCE);
-       /* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */
-       /* Busmaster mode should be shut down now. */
-}
-
-static int hp100_check_lan(struct net_device *dev)
-{
-       struct hp100_private *lp = netdev_priv(dev);
-
-       if (lp->lan_type < 0) { /* no LAN type detected yet? */
-               hp100_stop_interface(dev);
-               if ((lp->lan_type = hp100_sense_lan(dev)) < 0) {
-                       printk("hp100: %s: no connection found - check wire\n", dev->name);
-                       hp100_start_interface(dev);     /* 10Mb/s RX packets maybe handled */
-                       return -EIO;
-               }
-               if (lp->lan_type == HP100_LAN_100)
-                       lp->hub_status = hp100_login_to_vg_hub(dev, 0); /* relogin */
-               hp100_start_interface(dev);
-       }
-       return 0;
-}
-
-/*
- *  transmit functions
- */
-
-/* tx function for busmaster mode */
-static netdev_tx_t hp100_start_xmit_bm(struct sk_buff *skb,
-                                      struct net_device *dev)
-{
-       unsigned long flags;
-       int i, ok_flag;
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-       hp100_ring_t *ringptr;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4210, TRACE);
-       printk("hp100: %s: start_xmit_bm\n", dev->name);
-#endif
-       if (skb->len <= 0)
-               goto drop;
-
-       if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
-               return NETDEV_TX_OK;
-
-       /* Get Tx ring tail pointer */
-       if (lp->txrtail->next == lp->txrhead) {
-               /* No memory. */
-#ifdef HP100_DEBUG
-               printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name);
-#endif
-               /* not waited long enough since last tx? */
-               if (time_before(jiffies, dev_trans_start(dev) + HZ))
-                       goto drop;
-
-               if (hp100_check_lan(dev))
-                       goto drop;
-
-               if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) {
-                       /* we have a 100Mb/s adapter but it isn't connected to hub */
-                       printk("hp100: %s: login to 100Mb/s hub retry\n", dev->name);
-                       hp100_stop_interface(dev);
-                       lp->hub_status = hp100_login_to_vg_hub(dev, 0);
-                       hp100_start_interface(dev);
-               } else {
-                       spin_lock_irqsave(&lp->lock, flags);
-                       hp100_ints_off();       /* Useful ? Jean II */
-                       i = hp100_sense_lan(dev);
-                       hp100_ints_on();
-                       spin_unlock_irqrestore(&lp->lock, flags);
-                       if (i == HP100_LAN_ERR)
-                               printk("hp100: %s: link down detected\n", dev->name);
-                       else if (lp->lan_type != i) {   /* cable change! */
-                               /* it's very hard - all network settings must be changed!!! */
-                               printk("hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name);
-                               lp->lan_type = i;
-                               hp100_stop_interface(dev);
-                               if (lp->lan_type == HP100_LAN_100)
-                                       lp->hub_status = hp100_login_to_vg_hub(dev, 0);
-                               hp100_start_interface(dev);
-                       } else {
-                               printk("hp100: %s: interface reset\n", dev->name);
-                               hp100_stop_interface(dev);
-                               if (lp->lan_type == HP100_LAN_100)
-                                       lp->hub_status = hp100_login_to_vg_hub(dev, 0);
-                               hp100_start_interface(dev);
-                       }
-               }
-
-               goto drop;
-       }
-
-       /*
-        * we have to turn int's off before modifying this, otherwise
-        * a tx_pdl_cleanup could occur at the same time
-        */
-       spin_lock_irqsave(&lp->lock, flags);
-       ringptr = lp->txrtail;
-       lp->txrtail = ringptr->next;
-
-       /* Check whether packet has minimal packet size */
-       ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
-       i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
-
-       ringptr->skb = skb;
-       ringptr->pdl[0] = ((1 << 16) | i);      /* PDH: 1 Fragment & length */
-       if (lp->chip == HP100_CHIPID_SHASTA) {
-               /* TODO:Could someone who has the EISA card please check if this works? */
-               ringptr->pdl[2] = i;
-       } else {                /* Lassen */
-               /* In the PDL, don't use the padded size but the real packet size: */
-               ringptr->pdl[2] = skb->len;     /* 1st Frag: Length of frag */
-       }
-       /* Conversion to new PCI API : map skbuf data to PCI bus.
-        * Doc says it's OK for EISA as well - Jean II */
-       ringptr->pdl[1] = ((u32) pci_map_single(lp->pci_dev, skb->data, ringptr->pdl[2], PCI_DMA_TODEVICE));    /* 1st Frag: Adr. of data */
-
-       /* Hand this PDL to the card. */
-       hp100_outl(ringptr->pdl_paddr, TX_PDA_L);       /* Low Prio. Queue */
-
-       lp->txrcommit++;
-
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       return NETDEV_TX_OK;
-
-drop:
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-
-/* clean_txring checks if packets have been sent by the card by reading
- * the TX_PDL register from the performance page and comparing it to the
- * number of committed packets. It then frees the skb's of the packets that
- * obviously have been sent to the network.
- *
- * Needs the PERFORMANCE page selected.
- */
-static void hp100_clean_txring(struct net_device *dev)
-{
-       struct hp100_private *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       int donecount;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4211, TRACE);
-       printk("hp100: %s: clean txring\n", dev->name);
-#endif
-
-       /* How many PDLs have been transmitted? */
-       donecount = (lp->txrcommit) - hp100_inb(TX_PDL);
-
-#ifdef HP100_DEBUG
-       if (donecount > MAX_TX_PDL)
-               printk("hp100: %s: Warning: More PDLs transmitted than committed to card???\n", dev->name);
-#endif
-
-       for (; 0 != donecount; donecount--) {
-#ifdef HP100_DEBUG_BM
-               printk("hp100: %s: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n",
-                               dev->name, (u_int) lp->txrhead->skb->data,
-                               lp->txrcommit, hp100_inb(TX_PDL), donecount);
-#endif
-               /* Conversion to new PCI API : NOP */
-               pci_unmap_single(lp->pci_dev, (dma_addr_t) lp->txrhead->pdl[1], lp->txrhead->pdl[2], PCI_DMA_TODEVICE);
-               dev_consume_skb_any(lp->txrhead->skb);
-               lp->txrhead->skb = NULL;
-               lp->txrhead = lp->txrhead->next;
-               lp->txrcommit--;
-       }
-}
-
-/* tx function for slave modes */
-static netdev_tx_t hp100_start_xmit(struct sk_buff *skb,
-                                   struct net_device *dev)
-{
-       unsigned long flags;
-       int i, ok_flag;
-       int ioaddr = dev->base_addr;
-       u_short val;
-       struct hp100_private *lp = netdev_priv(dev);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4212, TRACE);
-       printk("hp100: %s: start_xmit\n", dev->name);
-#endif
-       if (skb->len <= 0)
-               goto drop;
-
-       if (hp100_check_lan(dev))
-               goto drop;
-
-       /* If there is not enough free memory on the card... */
-       i = hp100_inl(TX_MEM_FREE) & 0x7fffffff;
-       if (!(((i / 2) - 539) > (skb->len + 16) && (hp100_inb(TX_PKT_CNT) < 255))) {
-#ifdef HP100_DEBUG
-               printk("hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i);
-#endif
-               /* not waited long enough since last failed tx try? */
-               if (time_before(jiffies, dev_trans_start(dev) + HZ)) {
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: trans_start timing problem\n",
-                              dev->name);
-#endif
-                       goto drop;
-               }
-               if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) {
-                       /* we have a 100Mb/s adapter but it isn't connected to hub */
-                       printk("hp100: %s: login to 100Mb/s hub retry\n", dev->name);
-                       hp100_stop_interface(dev);
-                       lp->hub_status = hp100_login_to_vg_hub(dev, 0);
-                       hp100_start_interface(dev);
-               } else {
-                       spin_lock_irqsave(&lp->lock, flags);
-                       hp100_ints_off();       /* Useful ? Jean II */
-                       i = hp100_sense_lan(dev);
-                       hp100_ints_on();
-                       spin_unlock_irqrestore(&lp->lock, flags);
-                       if (i == HP100_LAN_ERR)
-                               printk("hp100: %s: link down detected\n", dev->name);
-                       else if (lp->lan_type != i) {   /* cable change! */
-                               /* it's very hard - all network setting must be changed!!! */
-                               printk("hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name);
-                               lp->lan_type = i;
-                               hp100_stop_interface(dev);
-                               if (lp->lan_type == HP100_LAN_100)
-                                       lp->hub_status = hp100_login_to_vg_hub(dev, 0);
-                               hp100_start_interface(dev);
-                       } else {
-                               printk("hp100: %s: interface reset\n", dev->name);
-                               hp100_stop_interface(dev);
-                               if (lp->lan_type == HP100_LAN_100)
-                                       lp->hub_status = hp100_login_to_vg_hub(dev, 0);
-                               hp100_start_interface(dev);
-                               mdelay(1);
-                       }
-               }
-               goto drop;
-       }
-
-       for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) {
-#ifdef HP100_DEBUG_TX
-               printk("hp100: %s: start_xmit: busy\n", dev->name);
-#endif
-       }
-
-       spin_lock_irqsave(&lp->lock, flags);
-       hp100_ints_off();
-       val = hp100_inw(IRQ_STATUS);
-       /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set
-        * when the current packet being transmitted on the wire is completed. */
-       hp100_outw(HP100_TX_COMPLETE, IRQ_STATUS);
-#ifdef HP100_DEBUG_TX
-       printk("hp100: %s: start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",
-                       dev->name, val, hp100_inw(IRQ_MASK), (int) skb->len);
-#endif
-
-       ok_flag = skb->len >= HP100_MIN_PACKET_SIZE;
-       i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE;
-
-       hp100_outw(i, DATA32);  /* tell card the total packet length */
-       hp100_outw(i, FRAGMENT_LEN);    /* and first/only fragment length    */
-
-       if (lp->mode == 2) {    /* memory mapped */
-               /* Note: The J2585B needs alignment to 32bits here!  */
-               memcpy_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3);
-               if (!ok_flag)
-                       memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len);
-       } else {                /* programmed i/o */
-               outsl(ioaddr + HP100_REG_DATA32, skb->data,
-                     (skb->len + 3) >> 2);
-               if (!ok_flag)
-                       for (i = (skb->len + 3) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4)
-                               hp100_outl(0, DATA32);
-       }
-
-       hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW);    /* send packet */
-
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-       hp100_ints_on();
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       dev_consume_skb_any(skb);
-
-#ifdef HP100_DEBUG_TX
-       printk("hp100: %s: start_xmit: end\n", dev->name);
-#endif
-
-       return NETDEV_TX_OK;
-
-drop:
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-
-}
-
-
-/*
- * Receive Function (Non-Busmaster mode)
- * Called when an "Receive Packet" interrupt occurs, i.e. the receive
- * packet counter is non-zero.
- * For non-busmaster, this function does the whole work of transferring
- * the packet to the host memory and then up to higher layers via skb
- * and netif_rx.
- */
-
-static void hp100_rx(struct net_device *dev)
-{
-       int packets, pkt_len;
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-       u_int header;
-       struct sk_buff *skb;
-
-#ifdef DEBUG_B
-       hp100_outw(0x4213, TRACE);
-       printk("hp100: %s: rx\n", dev->name);
-#endif
-
-       /* First get indication of received lan packet */
-       /* RX_PKT_CND indicates the number of packets which have been fully */
-       /* received onto the card but have not been fully transferred of the card */
-       packets = hp100_inb(RX_PKT_CNT);
-#ifdef HP100_DEBUG_RX
-       if (packets > 1)
-               printk("hp100: %s: rx: waiting packets = %d\n", dev->name, packets);
-#endif
-
-       while (packets-- > 0) {
-               /* If ADV_NXT_PKT is still set, we have to wait until the card has */
-               /* really advanced to the next packet. */
-               for (pkt_len = 0; pkt_len < 6000 && (hp100_inb(OPTION_MSW) & HP100_ADV_NXT_PKT); pkt_len++) {
-#ifdef HP100_DEBUG_RX
-                       printk ("hp100: %s: rx: busy, remaining packets = %d\n", dev->name, packets);
-#endif
-               }
-
-               /* First we get the header, which contains information about the */
-               /* actual length of the received packet. */
-               if (lp->mode == 2) {    /* memory mapped mode */
-                       header = readl(lp->mem_ptr_virt);
-               } else          /* programmed i/o */
-                       header = hp100_inl(DATA32);
-
-               pkt_len = ((header & HP100_PKT_LEN_MASK) + 3) & ~3;
-
-#ifdef HP100_DEBUG_RX
-               printk("hp100: %s: rx: new packet - length=%d, errors=0x%x, dest=0x%x\n",
-                                    dev->name, header & HP100_PKT_LEN_MASK,
-                                    (header >> 16) & 0xfff8, (header >> 16) & 7);
-#endif
-
-               /* Now we allocate the skb and transfer the data into it. */
-               skb = netdev_alloc_skb(dev, pkt_len + 2);
-               if (skb == NULL) {      /* Not enough memory->drop packet */
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n",
-                                            dev->name, pkt_len);
-#endif
-                       dev->stats.rx_dropped++;
-               } else {        /* skb successfully allocated */
-
-                       u_char *ptr;
-
-                       skb_reserve(skb,2);
-
-                       /* ptr to start of the sk_buff data area */
-                       skb_put(skb, pkt_len);
-                       ptr = skb->data;
-
-                       /* Now transfer the data from the card into that area */
-                       if (lp->mode == 2)
-                               memcpy_fromio(ptr, lp->mem_ptr_virt,pkt_len);
-                       else    /* io mapped */
-                               insl(ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2);
-
-                       skb->protocol = eth_type_trans(skb, dev);
-
-#ifdef HP100_DEBUG_RX
-                       printk("hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                                       dev->name, ptr[0], ptr[1], ptr[2], ptr[3],
-                                       ptr[4], ptr[5], ptr[6], ptr[7], ptr[8],
-                                       ptr[9], ptr[10], ptr[11]);
-#endif
-                       netif_rx(skb);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += pkt_len;
-               }
-
-               /* Indicate the card that we have got the packet */
-               hp100_outb(HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW);
-
-               switch (header & 0x00070000) {
-               case (HP100_MULTI_ADDR_HASH << 16):
-               case (HP100_MULTI_ADDR_NO_HASH << 16):
-                       dev->stats.multicast++;
-                       break;
-               }
-       }                       /* end of while(there are packets) loop */
-#ifdef HP100_DEBUG_RX
-       printk("hp100_rx: %s: end\n", dev->name);
-#endif
-}
-
-/*
- * Receive Function for Busmaster Mode
- */
-static void hp100_rx_bm(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-       hp100_ring_t *ptr;
-       u_int header;
-       int pkt_len;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4214, TRACE);
-       printk("hp100: %s: rx_bm\n", dev->name);
-#endif
-
-#ifdef HP100_DEBUG
-       if (0 == lp->rxrcommit) {
-               printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name);
-               return;
-       } else
-               /* RX_PKT_CNT states how many PDLs are currently formatted and available to
-                * the cards BM engine */
-       if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) {
-               printk("hp100: %s: More packets received than committed? RX_PKT_CNT=0x%x, commit=0x%x\n",
-                                    dev->name, hp100_inw(RX_PKT_CNT) & 0x00ff,
-                                    lp->rxrcommit);
-               return;
-       }
-#endif
-
-       while ((lp->rxrcommit > hp100_inb(RX_PDL))) {
-               /*
-                * The packet was received into the pdl pointed to by lp->rxrhead (
-                * the oldest pdl in the ring
-                */
-
-               /* First we get the header, which contains information about the */
-               /* actual length of the received packet. */
-
-               ptr = lp->rxrhead;
-
-               header = *(ptr->pdl - 1);
-               pkt_len = (header & HP100_PKT_LEN_MASK);
-
-               /* Conversion to new PCI API : NOP */
-               pci_unmap_single(lp->pci_dev, (dma_addr_t) ptr->pdl[3], MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE);
-
-#ifdef HP100_DEBUG_BM
-               printk("hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n",
-                               dev->name, (u_int) (ptr->pdl - 1), (u_int) header,
-                               pkt_len, (header >> 16) & 0xfff8, (header >> 16) & 7);
-               printk("hp100: %s: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n",
-                               dev->name, hp100_inb(RX_PDL), hp100_inb(TX_PDL),
-                               hp100_inb(RX_PKT_CNT), (u_int) * (ptr->pdl),
-                               (u_int) * (ptr->pdl + 3), (u_int) * (ptr->pdl + 4));
-#endif
-
-               if ((pkt_len >= MIN_ETHER_SIZE) &&
-                   (pkt_len <= MAX_ETHER_SIZE)) {
-                       if (ptr->skb == NULL) {
-                               printk("hp100: %s: rx_bm: skb null\n", dev->name);
-                               /* can happen if we only allocated room for the pdh due to memory shortage. */
-                               dev->stats.rx_dropped++;
-                       } else {
-                               skb_trim(ptr->skb, pkt_len);    /* Shorten it */
-                               ptr->skb->protocol =
-                                   eth_type_trans(ptr->skb, dev);
-
-                               netif_rx(ptr->skb);     /* Up and away... */
-
-                               dev->stats.rx_packets++;
-                               dev->stats.rx_bytes += pkt_len;
-                       }
-
-                       switch (header & 0x00070000) {
-                       case (HP100_MULTI_ADDR_HASH << 16):
-                       case (HP100_MULTI_ADDR_NO_HASH << 16):
-                               dev->stats.multicast++;
-                               break;
-                       }
-               } else {
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n", dev->name, pkt_len);
-#endif
-                       if (ptr->skb != NULL)
-                               dev_kfree_skb_any(ptr->skb);
-                       dev->stats.rx_errors++;
-               }
-
-               lp->rxrhead = lp->rxrhead->next;
-
-               /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */
-               if (0 == hp100_build_rx_pdl(lp->rxrtail, dev)) {
-                       /* No space for skb, header can still be received. */
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: rx_bm: No space for new PDL.\n", dev->name);
-#endif
-                       return;
-               } else {        /* successfully allocated new PDL - put it in ringlist at tail. */
-                       hp100_outl((u32) lp->rxrtail->pdl_paddr, RX_PDA);
-                       lp->rxrtail = lp->rxrtail->next;
-               }
-
-       }
-}
-
-/*
- *  statistics
- */
-static struct net_device_stats *hp100_get_stats(struct net_device *dev)
-{
-       unsigned long flags;
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4215, TRACE);
-#endif
-
-       spin_lock_irqsave(&lp->lock, flags);
-       hp100_ints_off();       /* Useful ? Jean II */
-       hp100_update_stats(dev);
-       hp100_ints_on();
-       spin_unlock_irqrestore(&lp->lock, flags);
-       return &(dev->stats);
-}
-
-static void hp100_update_stats(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       u_short val;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4216, TRACE);
-       printk("hp100: %s: update-stats\n", dev->name);
-#endif
-
-       /* Note: Statistics counters clear when read. */
-       hp100_page(MAC_CTRL);
-       val = hp100_inw(DROPPED) & 0x0fff;
-       dev->stats.rx_errors += val;
-       dev->stats.rx_over_errors += val;
-       val = hp100_inb(CRC);
-       dev->stats.rx_errors += val;
-       dev->stats.rx_crc_errors += val;
-       val = hp100_inb(ABORT);
-       dev->stats.tx_errors += val;
-       dev->stats.tx_aborted_errors += val;
-       hp100_page(PERFORMANCE);
-}
-
-static void hp100_misc_interrupt(struct net_device *dev)
-{
-#ifdef HP100_DEBUG_B
-       int ioaddr = dev->base_addr;
-#endif
-
-#ifdef HP100_DEBUG_B
-       int ioaddr = dev->base_addr;
-       hp100_outw(0x4216, TRACE);
-       printk("hp100: %s: misc_interrupt\n", dev->name);
-#endif
-
-       /* Note: Statistics counters clear when read. */
-       dev->stats.rx_errors++;
-       dev->stats.tx_errors++;
-}
-
-static void hp100_clear_stats(struct hp100_private *lp, int ioaddr)
-{
-       unsigned long flags;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4217, TRACE);
-       printk("hp100: %s: clear_stats\n", dev->name);
-#endif
-
-       spin_lock_irqsave(&lp->lock, flags);
-       hp100_page(MAC_CTRL);   /* get all statistics bytes */
-       hp100_inw(DROPPED);
-       hp100_inb(CRC);
-       hp100_inb(ABORT);
-       hp100_page(PERFORMANCE);
-       spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-
-/*
- *  multicast setup
- */
-
-/*
- *  Set or clear the multicast filter for this adapter.
- */
-
-static void hp100_set_multicast_list(struct net_device *dev)
-{
-       unsigned long flags;
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4218, TRACE);
-       printk("hp100: %s: set_mc_list\n", dev->name);
-#endif
-
-       spin_lock_irqsave(&lp->lock, flags);
-       hp100_ints_off();
-       hp100_page(MAC_CTRL);
-       hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1);    /* stop rx/tx */
-
-       if (dev->flags & IFF_PROMISC) {
-               lp->mac2_mode = HP100_MAC2MODE6;        /* promiscuous mode = get all good */
-               lp->mac1_mode = HP100_MAC1MODE6;        /* packets on the net */
-               memset(&lp->hash_bytes, 0xff, 8);
-       } else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) {
-               lp->mac2_mode = HP100_MAC2MODE5;        /* multicast mode = get packets for */
-               lp->mac1_mode = HP100_MAC1MODE5;        /* me, broadcasts and all multicasts */
-#ifdef HP100_MULTICAST_FILTER  /* doesn't work!!! */
-               if (dev->flags & IFF_ALLMULTI) {
-                       /* set hash filter to receive all multicast packets */
-                       memset(&lp->hash_bytes, 0xff, 8);
-               } else {
-                       int i, idx;
-                       u_char *addrs;
-                       struct netdev_hw_addr *ha;
-
-                       memset(&lp->hash_bytes, 0x00, 8);
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: computing hash filter - mc_count = %i\n",
-                              dev->name, netdev_mc_count(dev));
-#endif
-                       netdev_for_each_mc_addr(ha, dev) {
-                               addrs = ha->addr;
-#ifdef HP100_DEBUG
-                               printk("hp100: %s: multicast = %pM, ",
-                                            dev->name, addrs);
-#endif
-                               for (i = idx = 0; i < 6; i++) {
-                                       idx ^= *addrs++ & 0x3f;
-                                       printk(":%02x:", idx);
-                               }
-#ifdef HP100_DEBUG
-                               printk("idx = %i\n", idx);
-#endif
-                               lp->hash_bytes[idx >> 3] |= (1 << (idx & 7));
-                       }
-               }
-#else
-               memset(&lp->hash_bytes, 0xff, 8);
-#endif
-       } else {
-               lp->mac2_mode = HP100_MAC2MODE3;        /* normal mode = get packets for me */
-               lp->mac1_mode = HP100_MAC1MODE3;        /* and broadcasts */
-               memset(&lp->hash_bytes, 0x00, 8);
-       }
-
-       if (((hp100_inb(MAC_CFG_1) & 0x0f) != lp->mac1_mode) ||
-           (hp100_inb(MAC_CFG_2) != lp->mac2_mode)) {
-               int i;
-
-               hp100_outb(lp->mac2_mode, MAC_CFG_2);
-               hp100_andb(HP100_MAC1MODEMASK, MAC_CFG_1);      /* clear mac1 mode bits */
-               hp100_orb(lp->mac1_mode, MAC_CFG_1);    /* and set the new mode */
-
-               hp100_page(MAC_ADDRESS);
-               for (i = 0; i < 8; i++)
-                       hp100_outb(lp->hash_bytes[i], HASH_BYTE0 + i);
-#ifdef HP100_DEBUG
-               printk("hp100: %s: mac1 = 0x%x, mac2 = 0x%x, multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-                                    dev->name, lp->mac1_mode, lp->mac2_mode,
-                                    lp->hash_bytes[0], lp->hash_bytes[1],
-                                    lp->hash_bytes[2], lp->hash_bytes[3],
-                                    lp->hash_bytes[4], lp->hash_bytes[5],
-                                    lp->hash_bytes[6], lp->hash_bytes[7]);
-#endif
-
-               if (lp->lan_type == HP100_LAN_100) {
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name);
-#endif
-                       lp->hub_status = hp100_login_to_vg_hub(dev, 1); /* force a relogin to the hub */
-               }
-       } else {
-               int i;
-               u_char old_hash_bytes[8];
-
-               hp100_page(MAC_ADDRESS);
-               for (i = 0; i < 8; i++)
-                       old_hash_bytes[i] = hp100_inb(HASH_BYTE0 + i);
-               if (memcmp(old_hash_bytes, &lp->hash_bytes, 8)) {
-                       for (i = 0; i < 8; i++)
-                               hp100_outb(lp->hash_bytes[i], HASH_BYTE0 + i);
-#ifdef HP100_DEBUG
-                       printk("hp100: %s: multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-                                       dev->name, lp->hash_bytes[0],
-                                       lp->hash_bytes[1], lp->hash_bytes[2],
-                                       lp->hash_bytes[3], lp->hash_bytes[4],
-                                       lp->hash_bytes[5], lp->hash_bytes[6],
-                                       lp->hash_bytes[7]);
-#endif
-
-                       if (lp->lan_type == HP100_LAN_100) {
-#ifdef HP100_DEBUG
-                               printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name);
-#endif
-                               lp->hub_status = hp100_login_to_vg_hub(dev, 1); /* force a relogin to the hub */
-                       }
-               }
-       }
-
-       hp100_page(MAC_CTRL);
-       hp100_orb(HP100_RX_EN | HP100_RX_IDLE | /* enable rx */
-                 HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1);      /* enable tx */
-
-       hp100_page(PERFORMANCE);
-       hp100_ints_on();
-       spin_unlock_irqrestore(&lp->lock, flags);
-}
-
-/*
- *  hardware interrupt handling
- */
-
-static irqreturn_t hp100_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = (struct net_device *) dev_id;
-       struct hp100_private *lp = netdev_priv(dev);
-
-       int ioaddr;
-       u_int val;
-
-       if (dev == NULL)
-               return IRQ_NONE;
-       ioaddr = dev->base_addr;
-
-       spin_lock(&lp->lock);
-
-       hp100_ints_off();
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4219, TRACE);
-#endif
-
-       /*  hp100_page( PERFORMANCE ); */
-       val = hp100_inw(IRQ_STATUS);
-#ifdef HP100_DEBUG_IRQ
-       printk("hp100: %s: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n",
-                            dev->name, lp->mode, (u_int) val, hp100_inb(RX_PKT_CNT),
-                            hp100_inb(RX_PDL), hp100_inb(TX_PKT_CNT), hp100_inb(TX_PDL));
-#endif
-
-       if (val == 0) {         /* might be a shared interrupt */
-               spin_unlock(&lp->lock);
-               hp100_ints_on();
-               return IRQ_NONE;
-       }
-       /* We're only interested in those interrupts we really enabled. */
-       /* val &= hp100_inw( IRQ_MASK ); */
-
-       /*
-        * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
-        * is considered executed whenever the RX_PDL data structure is no longer
-        * needed.
-        */
-       if (val & HP100_RX_PDL_FILL_COMPL) {
-               if (lp->mode == 1)
-                       hp100_rx_bm(dev);
-               else {
-                       printk("hp100: %s: rx_pdl_fill_compl interrupt although not busmaster?\n", dev->name);
-               }
-       }
-
-       /*
-        * The RX_PACKET interrupt is set, when the receive packet counter is
-        * non zero. We use this interrupt for receiving in slave mode. In
-        * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill
-        * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then
-        * we somehow have missed a rx_pdl_fill_compl interrupt.
-        */
-
-       if (val & HP100_RX_PACKET) {    /* Receive Packet Counter is non zero */
-               if (lp->mode != 1)      /* non busmaster */
-                       hp100_rx(dev);
-               else if (!(val & HP100_RX_PDL_FILL_COMPL)) {
-                       /* Shouldn't happen - maybe we missed a RX_PDL_FILL Interrupt?  */
-                       hp100_rx_bm(dev);
-               }
-       }
-
-       /*
-        * Ack. that we have noticed the interrupt and thereby allow next one.
-        * Note that this is now done after the slave rx function, since first
-        * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt
-        * on the J2573.
-        */
-       hp100_outw(val, IRQ_STATUS);
-
-       /*
-        * RX_ERROR is set when a packet is dropped due to no memory resources on
-        * the card or when a RCV_ERR occurs.
-        * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
-        * only in the 802.3 MAC and happens when 16 collisions occur during a TX
-        */
-       if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) {
-#ifdef HP100_DEBUG_IRQ
-               printk("hp100: %s: TX/RX Error IRQ\n", dev->name);
-#endif
-               hp100_update_stats(dev);
-               if (lp->mode == 1) {
-                       hp100_rxfill(dev);
-                       hp100_clean_txring(dev);
-               }
-       }
-
-       /*
-        * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
-        */
-       if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO)))
-               hp100_rxfill(dev);
-
-       /*
-        * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
-        * is completed
-        */
-       if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE)))
-               hp100_clean_txring(dev);
-
-       /*
-        * MISC_ERROR is set when either the LAN link goes down or a detected
-        * bus error occurs.
-        */
-       if (val & HP100_MISC_ERROR) {   /* New for J2585B */
-#ifdef HP100_DEBUG_IRQ
-               printk
-                   ("hp100: %s: Misc. Error Interrupt - Check cabling.\n",
-                    dev->name);
-#endif
-               if (lp->mode == 1) {
-                       hp100_clean_txring(dev);
-                       hp100_rxfill(dev);
-               }
-               hp100_misc_interrupt(dev);
-       }
-
-       spin_unlock(&lp->lock);
-       hp100_ints_on();
-       return IRQ_HANDLED;
-}
-
-/*
- *  some misc functions
- */
-
-static void hp100_start_interface(struct net_device *dev)
-{
-       unsigned long flags;
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4220, TRACE);
-       printk("hp100: %s: hp100_start_interface\n", dev->name);
-#endif
-
-       spin_lock_irqsave(&lp->lock, flags);
-
-       /* Ensure the adapter does not want to request an interrupt when */
-       /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */
-       hp100_page(PERFORMANCE);
-       hp100_outw(0xfefe, IRQ_MASK);   /* mask off all ints */
-       hp100_outw(0xffff, IRQ_STATUS); /* ack all IRQs */
-       hp100_outw(HP100_FAKE_INT | HP100_INT_EN | HP100_RESET_LB,
-                  OPTION_LSW);
-       /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */
-       hp100_outw(HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW);
-
-       if (lp->mode == 1) {
-               /* Make sure BM bit is set... */
-               hp100_page(HW_MAP);
-               hp100_orb(HP100_BM_MASTER, BM);
-               hp100_rxfill(dev);
-       } else if (lp->mode == 2) {
-               /* Enable memory mapping. Note: Don't do this when busmaster. */
-               hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW);
-       }
-
-       hp100_page(PERFORMANCE);
-       hp100_outw(0xfefe, IRQ_MASK);   /* mask off all ints */
-       hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
-
-       /* enable a few interrupts: */
-       if (lp->mode == 1) {    /* busmaster mode */
-               hp100_outw(HP100_RX_PDL_FILL_COMPL |
-                          HP100_RX_PDA_ZERO | HP100_RX_ERROR |
-                          /* HP100_RX_PACKET    | */
-                          /* HP100_RX_EARLY_INT |  */ HP100_SET_HB |
-                          /* HP100_TX_PDA_ZERO  |  */
-                          HP100_TX_COMPLETE |
-                          /* HP100_MISC_ERROR   |  */
-                          HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK);
-       } else {
-               hp100_outw(HP100_RX_PACKET |
-                          HP100_RX_ERROR | HP100_SET_HB |
-                          HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK);
-       }
-
-       /* Note : before hp100_set_multicast_list(), because it will play with
-        * spinlock itself... Jean II */
-       spin_unlock_irqrestore(&lp->lock, flags);
-
-       /* Enable MAC Tx and RX, set MAC modes, ... */
-       hp100_set_multicast_list(dev);
-}
-
-static void hp100_stop_interface(struct net_device *dev)
-{
-       struct hp100_private *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       u_int val;
-
-#ifdef HP100_DEBUG_B
-       printk("hp100: %s: hp100_stop_interface\n", dev->name);
-       hp100_outw(0x4221, TRACE);
-#endif
-
-       if (lp->mode == 1)
-               hp100_BM_shutdown(dev);
-       else {
-               /* Note: MMAP_DIS will be reenabled by start_interface */
-               hp100_outw(HP100_INT_EN | HP100_RESET_LB |
-                          HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB,
-                          OPTION_LSW);
-               val = hp100_inw(OPTION_LSW);
-
-               hp100_page(MAC_CTRL);
-               hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1);
-
-               if (!(val & HP100_HW_RST))
-                       return; /* If reset, imm. return ... */
-               /* ... else: busy wait until idle */
-               for (val = 0; val < 6000; val++)
-                       if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == (HP100_TX_IDLE | HP100_RX_IDLE)) {
-                               hp100_page(PERFORMANCE);
-                               return;
-                       }
-               printk("hp100: %s: hp100_stop_interface - timeout\n", dev->name);
-               hp100_page(PERFORMANCE);
-       }
-}
-
-static void hp100_load_eeprom(struct net_device *dev, u_short probe_ioaddr)
-{
-       int i;
-       int ioaddr = probe_ioaddr > 0 ? probe_ioaddr : dev->base_addr;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4222, TRACE);
-#endif
-
-       hp100_page(EEPROM_CTRL);
-       hp100_andw(~HP100_EEPROM_LOAD, EEPROM_CTRL);
-       hp100_orw(HP100_EEPROM_LOAD, EEPROM_CTRL);
-       for (i = 0; i < 10000; i++)
-               if (!(hp100_inb(OPTION_MSW) & HP100_EE_LOAD))
-                       return;
-       printk("hp100: %s: hp100_load_eeprom - timeout\n", dev->name);
-}
-
-/*  Sense connection status.
- *  return values: LAN_10  - Connected to 10Mbit/s network
- *                 LAN_100 - Connected to 100Mbit/s network
- *                 LAN_ERR - not connected or 100Mbit/s Hub down
- */
-static int hp100_sense_lan(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       u_short val_VG, val_10;
-       struct hp100_private *lp = netdev_priv(dev);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4223, TRACE);
-#endif
-
-       hp100_page(MAC_CTRL);
-       val_10 = hp100_inb(10_LAN_CFG_1);
-       val_VG = hp100_inb(VG_LAN_CFG_1);
-       hp100_page(PERFORMANCE);
-#ifdef HP100_DEBUG
-       printk("hp100: %s: sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n",
-              dev->name, val_VG, val_10);
-#endif
-
-       if (val_10 & HP100_LINK_BEAT_ST)        /* 10Mb connection is active */
-               return HP100_LAN_10;
-
-       if (val_10 & HP100_AUI_ST) {    /* have we BNC or AUI onboard? */
-               /*
-                * This can be overriden by dos utility, so if this has no effect,
-                * perhaps you need to download that utility from HP and set card
-                * back to "auto detect".
-                */
-               val_10 |= HP100_AUI_SEL | HP100_LOW_TH;
-               hp100_page(MAC_CTRL);
-               hp100_outb(val_10, 10_LAN_CFG_1);
-               hp100_page(PERFORMANCE);
-               return HP100_LAN_COAX;
-       }
-
-       /* Those cards don't have a 100 Mbit connector */
-       if ( !strcmp(lp->id, "HWP1920")  ||
-            (lp->pci_dev &&
-             lp->pci_dev->vendor == PCI_VENDOR_ID &&
-             (lp->pci_dev->device == PCI_DEVICE_ID_HP_J2970A ||
-              lp->pci_dev->device == PCI_DEVICE_ID_HP_J2973A)))
-               return HP100_LAN_ERR;
-
-       if (val_VG & HP100_LINK_CABLE_ST)       /* Can hear the HUBs tone. */
-               return HP100_LAN_100;
-       return HP100_LAN_ERR;
-}
-
-static int hp100_down_vg_link(struct net_device *dev)
-{
-       struct hp100_private *lp = netdev_priv(dev);
-       int ioaddr = dev->base_addr;
-       unsigned long time;
-       long savelan, newlan;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4224, TRACE);
-       printk("hp100: %s: down_vg_link\n", dev->name);
-#endif
-
-       hp100_page(MAC_CTRL);
-       time = jiffies + (HZ / 4);
-       do {
-               if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST)
-                       break;
-               if (!in_interrupt())
-                       schedule_timeout_interruptible(1);
-       } while (time_after(time, jiffies));
-
-       if (time_after_eq(jiffies, time))       /* no signal->no logout */
-               return 0;
-
-       /* Drop the VG Link by clearing the link up cmd and load addr. */
-
-       hp100_andb(~(HP100_LOAD_ADDR | HP100_LINK_CMD), VG_LAN_CFG_1);
-       hp100_orb(HP100_VG_SEL, VG_LAN_CFG_1);
-
-       /* Conditionally stall for >250ms on Link-Up Status (to go down) */
-       time = jiffies + (HZ / 2);
-       do {
-               if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST))
-                       break;
-               if (!in_interrupt())
-                       schedule_timeout_interruptible(1);
-       } while (time_after(time, jiffies));
-
-#ifdef HP100_DEBUG
-       if (time_after_eq(jiffies, time))
-               printk("hp100: %s: down_vg_link: Link does not go down?\n", dev->name);
-#endif
-
-       /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */
-       /* logout under traffic (even though all the status bits are cleared),  */
-       /* do this workaround to get the Rev 1 MAC in its idle state */
-       if (lp->chip == HP100_CHIPID_LASSEN) {
-               /* Reset VG MAC to insure it leaves the logoff state even if */
-               /* the Hub is still emitting tones */
-               hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1);
-               udelay(1500);   /* wait for >1ms */
-               hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1);        /* Release Reset */
-               udelay(1500);
-       }
-
-       /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */
-       /* to get the VG mac to full reset. This is not req.d with later chips */
-       /* Note: It will take the between 1 and 2 seconds for the VG mac to be */
-       /* selected again! This will be left to the connect hub function to */
-       /* perform if desired.  */
-       if (lp->chip == HP100_CHIPID_LASSEN) {
-               /* Have to write to 10 and 100VG control registers simultaneously */
-               savelan = newlan = hp100_inl(10_LAN_CFG_1);     /* read 10+100 LAN_CFG regs */
-               newlan &= ~(HP100_VG_SEL << 16);
-               newlan |= (HP100_DOT3_MAC) << 8;
-               hp100_andb(~HP100_AUTO_MODE, MAC_CFG_3);        /* Autosel off */
-               hp100_outl(newlan, 10_LAN_CFG_1);
-
-               /* Conditionally stall for 5sec on VG selected. */
-               time = jiffies + (HZ * 5);
-               do {
-                       if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST))
-                               break;
-                       if (!in_interrupt())
-                               schedule_timeout_interruptible(1);
-               } while (time_after(time, jiffies));
-
-               hp100_orb(HP100_AUTO_MODE, MAC_CFG_3);  /* Autosel back on */
-               hp100_outl(savelan, 10_LAN_CFG_1);
-       }
-
-       time = jiffies + (3 * HZ);      /* Timeout 3s */
-       do {
-               if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0)
-                       break;
-               if (!in_interrupt())
-                       schedule_timeout_interruptible(1);
-       } while (time_after(time, jiffies));
-
-       if (time_before_eq(time, jiffies)) {
-#ifdef HP100_DEBUG
-               printk("hp100: %s: down_vg_link: timeout\n", dev->name);
-#endif
-               return -EIO;
-       }
-
-       time = jiffies + (2 * HZ);      /* This seems to take a while.... */
-       do {
-               if (!in_interrupt())
-                       schedule_timeout_interruptible(1);
-       } while (time_after(time, jiffies));
-
-       return 0;
-}
-
-static int hp100_login_to_vg_hub(struct net_device *dev, u_short force_relogin)
-{
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-       u_short val = 0;
-       unsigned long time;
-       int startst;
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4225, TRACE);
-       printk("hp100: %s: login_to_vg_hub\n", dev->name);
-#endif
-
-       /* Initiate a login sequence iff VG MAC is enabled and either Load Address
-        * bit is zero or the force relogin flag is set (e.g. due to MAC address or
-        * promiscuous mode change)
-        */
-       hp100_page(MAC_CTRL);
-       startst = hp100_inb(VG_LAN_CFG_1);
-       if ((force_relogin == 1) || (hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) {
-#ifdef HP100_DEBUG_TRAINING
-               printk("hp100: %s: Start training\n", dev->name);
-#endif
-
-               /* Ensure VG Reset bit is 1 (i.e., do not reset) */
-               hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1);
-
-               /* If Lassen AND auto-select-mode AND VG tones were sensed on */
-               /* entry then temporarily put them into force 100Mbit mode */
-               if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST))
-                       hp100_andb(~HP100_DOT3_MAC, 10_LAN_CFG_2);
-
-               /* Drop the VG link by zeroing Link Up Command and Load Address  */
-               hp100_andb(~(HP100_LINK_CMD /* |HP100_LOAD_ADDR */ ), VG_LAN_CFG_1);
-
-#ifdef HP100_DEBUG_TRAINING
-               printk("hp100: %s: Bring down the link\n", dev->name);
-#endif
-
-               /* Wait for link to drop */
-               time = jiffies + (HZ / 10);
-               do {
-                       if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST))
-                               break;
-                       if (!in_interrupt())
-                               schedule_timeout_interruptible(1);
-               } while (time_after(time, jiffies));
-
-               /* Start an addressed training and optionally request promiscuous port */
-               if ((dev->flags) & IFF_PROMISC) {
-                       hp100_orb(HP100_PROM_MODE, VG_LAN_CFG_2);
-                       if (lp->chip == HP100_CHIPID_LASSEN)
-                               hp100_orw(HP100_MACRQ_PROMSC, TRAIN_REQUEST);
-               } else {
-                       hp100_andb(~HP100_PROM_MODE, VG_LAN_CFG_2);
-                       /* For ETR parts we need to reset the prom. bit in the training
-                        * register, otherwise promiscious mode won't be disabled.
-                        */
-                       if (lp->chip == HP100_CHIPID_LASSEN) {
-                               hp100_andw(~HP100_MACRQ_PROMSC, TRAIN_REQUEST);
-                       }
-               }
-
-               /* With ETR parts, frame format request bits can be set. */
-               if (lp->chip == HP100_CHIPID_LASSEN)
-                       hp100_orb(HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST);
-
-               hp100_orb(HP100_LINK_CMD | HP100_LOAD_ADDR | HP100_VG_RESET, VG_LAN_CFG_1);
-
-               /* Note: Next wait could be omitted for Hood and earlier chips under */
-               /* certain circumstances */
-               /* TODO: check if hood/earlier and skip wait. */
-
-               /* Wait for either short timeout for VG tones or long for login    */
-               /* Wait for the card hardware to signalise link cable status ok... */
-               hp100_page(MAC_CTRL);
-               time = jiffies + (1 * HZ);      /* 1 sec timeout for cable st */
-               do {
-                       if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST)
-                               break;
-                       if (!in_interrupt())
-                               schedule_timeout_interruptible(1);
-               } while (time_before(jiffies, time));
-
-               if (time_after_eq(jiffies, time)) {
-#ifdef HP100_DEBUG_TRAINING
-                       printk("hp100: %s: Link cable status not ok? Training aborted.\n", dev->name);
-#endif
-               } else {
-#ifdef HP100_DEBUG_TRAINING
-                       printk
-                           ("hp100: %s: HUB tones detected. Trying to train.\n",
-                            dev->name);
-#endif
-
-                       time = jiffies + (2 * HZ);      /* again a timeout */
-                       do {
-                               val = hp100_inb(VG_LAN_CFG_1);
-                               if ((val & (HP100_LINK_UP_ST))) {
-#ifdef HP100_DEBUG_TRAINING
-                                       printk("hp100: %s: Passed training.\n", dev->name);
-#endif
-                                       break;
-                               }
-                               if (!in_interrupt())
-                                       schedule_timeout_interruptible(1);
-                       } while (time_after(time, jiffies));
-               }
-
-               /* If LINK_UP_ST is set, then we are logged into the hub. */
-               if (time_before_eq(jiffies, time) && (val & HP100_LINK_UP_ST)) {
-#ifdef HP100_DEBUG_TRAINING
-                       printk("hp100: %s: Successfully logged into the HUB.\n", dev->name);
-                       if (lp->chip == HP100_CHIPID_LASSEN) {
-                               val = hp100_inw(TRAIN_ALLOW);
-                               printk("hp100: %s: Card supports 100VG MAC Version \"%s\" ",
-                                            dev->name, (hp100_inw(TRAIN_REQUEST) & HP100_CARD_MACVER) ? "802.12" : "Pre");
-                               printk("Driver will use MAC Version \"%s\"\n", (val & HP100_HUB_MACVER) ? "802.12" : "Pre");
-                               printk("hp100: %s: Frame format is %s.\n", dev->name, (val & HP100_MALLOW_FRAMEFMT) ? "802.5" : "802.3");
-                       }
-#endif
-               } else {
-                       /* If LINK_UP_ST is not set, login was not successful */
-                       printk("hp100: %s: Problem logging into the HUB.\n", dev->name);
-                       if (lp->chip == HP100_CHIPID_LASSEN) {
-                               /* Check allowed Register to find out why there is a problem. */
-                               val = hp100_inw(TRAIN_ALLOW);   /* won't work on non-ETR card */
-#ifdef HP100_DEBUG_TRAINING
-                               printk("hp100: %s: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", dev->name, hp100_inw(TRAIN_REQUEST), val);
-#endif
-                               if (val & HP100_MALLOW_ACCDENIED)
-                                       printk("hp100: %s: HUB access denied.\n", dev->name);
-                               if (val & HP100_MALLOW_CONFIGURE)
-                                       printk("hp100: %s: MAC Configuration is incompatible with the Network.\n", dev->name);
-                               if (val & HP100_MALLOW_DUPADDR)
-                                       printk("hp100: %s: Duplicate MAC Address on the Network.\n", dev->name);
-                       }
-               }
-
-               /* If we have put the chip into forced 100 Mbit mode earlier, go back */
-               /* to auto-select mode */
-
-               if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) {
-                       hp100_page(MAC_CTRL);
-                       hp100_orb(HP100_DOT3_MAC, 10_LAN_CFG_2);
-               }
-
-               val = hp100_inb(VG_LAN_CFG_1);
-
-               /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */
-               hp100_page(PERFORMANCE);
-               hp100_outw(HP100_MISC_ERROR, IRQ_STATUS);
-
-               if (val & HP100_LINK_UP_ST)
-                       return 0;       /* login was ok */
-               else {
-                       printk("hp100: %s: Training failed.\n", dev->name);
-                       hp100_down_vg_link(dev);
-                       return -EIO;
-               }
-       }
-       /* no forced relogin & already link there->no training. */
-       return -EIO;
-}
-
-static void hp100_cascade_reset(struct net_device *dev, u_short enable)
-{
-       int ioaddr = dev->base_addr;
-       struct hp100_private *lp = netdev_priv(dev);
-
-#ifdef HP100_DEBUG_B
-       hp100_outw(0x4226, TRACE);
-       printk("hp100: %s: cascade_reset\n", dev->name);
-#endif
-
-       if (enable) {
-               hp100_outw(HP100_HW_RST | HP100_RESET_LB, OPTION_LSW);
-               if (lp->chip == HP100_CHIPID_LASSEN) {
-                       /* Lassen requires a PCI transmit fifo reset */
-                       hp100_page(HW_MAP);
-                       hp100_andb(~HP100_PCI_RESET, PCICTRL2);
-                       hp100_orb(HP100_PCI_RESET, PCICTRL2);
-                       /* Wait for min. 300 ns */
-                       /* we can't use jiffies here, because it may be */
-                       /* that we have disabled the timer... */
-                       udelay(400);
-                       hp100_andb(~HP100_PCI_RESET, PCICTRL2);
-                       hp100_page(PERFORMANCE);
-               }
-       } else {                /* bring out of reset */
-               hp100_outw(HP100_HW_RST | HP100_SET_LB, OPTION_LSW);
-               udelay(400);
-               hp100_page(PERFORMANCE);
-       }
-}
-
-#ifdef HP100_DEBUG
-void hp100_RegisterDump(struct net_device *dev)
-{
-       int ioaddr = dev->base_addr;
-       int Page;
-       int Register;
-
-       /* Dump common registers */
-       printk("hp100: %s: Cascade Register Dump\n", dev->name);
-       printk("hardware id #1: 0x%.2x\n", hp100_inb(HW_ID));
-       printk("hardware id #2/paging: 0x%.2x\n", hp100_inb(PAGING));
-       printk("option #1: 0x%.4x\n", hp100_inw(OPTION_LSW));
-       printk("option #2: 0x%.4x\n", hp100_inw(OPTION_MSW));
-
-       /* Dump paged registers */
-       for (Page = 0; Page < 8; Page++) {
-               /* Dump registers */
-               printk("page: 0x%.2x\n", Page);
-               outw(Page, ioaddr + 0x02);
-               for (Register = 0x8; Register < 0x22; Register += 2) {
-                       /* Display Register contents except data port */
-                       if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) {
-                               printk("0x%.2x = 0x%.4x\n", Register, inw(ioaddr + Register));
-                       }
-               }
-       }
-       hp100_page(PERFORMANCE);
-}
-#endif
-
-
-static void cleanup_dev(struct net_device *d)
-{
-       struct hp100_private *p = netdev_priv(d);
-
-       unregister_netdev(d);
-       release_region(d->base_addr, HP100_REGION_SIZE);
-
-       if (p->mode == 1)       /* busmaster */
-               pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f,
-                                   p->page_vaddr_algn,
-                                   virt_to_whatever(d, p->page_vaddr_algn));
-       if (p->mem_ptr_virt)
-               iounmap(p->mem_ptr_virt);
-
-       free_netdev(d);
-}
-
-static int hp100_eisa_probe(struct device *gendev)
-{
-       struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
-       struct eisa_device *edev = to_eisa_device(gendev);
-       int err;
-
-       if (!dev)
-               return -ENOMEM;
-
-       SET_NETDEV_DEV(dev, &edev->dev);
-
-       err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL);
-       if (err)
-               goto out1;
-
-#ifdef HP100_DEBUG
-       printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name,
-              dev->base_addr);
-#endif
-       dev_set_drvdata(gendev, dev);
-       return 0;
- out1:
-       free_netdev(dev);
-       return err;
-}
-
-static int hp100_eisa_remove(struct device *gendev)
-{
-       struct net_device *dev = dev_get_drvdata(gendev);
-       cleanup_dev(dev);
-       return 0;
-}
-
-static struct eisa_driver hp100_eisa_driver = {
-        .id_table = hp100_eisa_tbl,
-        .driver   = {
-                .name    = "hp100",
-                .probe   = hp100_eisa_probe,
-               .remove  = hp100_eisa_remove,
-        }
-};
-
-static int hp100_pci_probe(struct pci_dev *pdev,
-                          const struct pci_device_id *ent)
-{
-       struct net_device *dev;
-       int ioaddr;
-       u_short pci_command;
-       int err;
-
-       if (pci_enable_device(pdev))
-               return -ENODEV;
-
-       dev = alloc_etherdev(sizeof(struct hp100_private));
-       if (!dev) {
-               err = -ENOMEM;
-               goto out0;
-       }
-
-       SET_NETDEV_DEV(dev, &pdev->dev);
-
-       pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-       if (!(pci_command & PCI_COMMAND_IO)) {
-#ifdef HP100_DEBUG
-               printk("hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name);
-#endif
-               pci_command |= PCI_COMMAND_IO;
-               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-       }
-
-       if (!(pci_command & PCI_COMMAND_MASTER)) {
-#ifdef HP100_DEBUG
-               printk("hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name);
-#endif
-               pci_command |= PCI_COMMAND_MASTER;
-               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-       }
-
-       ioaddr = pci_resource_start(pdev, 0);
-       err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev);
-       if (err)
-               goto out1;
-
-#ifdef HP100_DEBUG
-       printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr);
-#endif
-       pci_set_drvdata(pdev, dev);
-       return 0;
- out1:
-       free_netdev(dev);
- out0:
-       pci_disable_device(pdev);
-       return err;
-}
-
-static void hp100_pci_remove(struct pci_dev *pdev)
-{
-       struct net_device *dev = pci_get_drvdata(pdev);
-
-       cleanup_dev(dev);
-       pci_disable_device(pdev);
-}
-
-
-static struct pci_driver hp100_pci_driver = {
-       .name           = "hp100",
-       .id_table       = hp100_pci_tbl,
-       .probe          = hp100_pci_probe,
-       .remove         = hp100_pci_remove,
-};
-
-/*
- *  module section
- */
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, "
-              "Siegfried \"Frieder\" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>");
-MODULE_DESCRIPTION("HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters");
-
-/*
- * Note: to register three isa devices, use:
- * option hp100 hp100_port=0,0,0
- *        to register one card at io 0x280 as eth239, use:
- * option hp100 hp100_port=0x280
- */
-#if defined(MODULE) && defined(CONFIG_ISA)
-#define HP100_DEVICES 5
-/* Parameters set by insmod */
-static int hp100_port[HP100_DEVICES] = { 0, [1 ... (HP100_DEVICES-1)] = -1 };
-module_param_hw_array(hp100_port, int, ioport, NULL, 0);
-
-/* List of devices */
-static struct net_device *hp100_devlist[HP100_DEVICES];
-
-static int __init hp100_isa_init(void)
-{
-       struct net_device *dev;
-       int i, err, cards = 0;
-
-       /* Don't autoprobe ISA bus */
-       if (hp100_port[0] == 0)
-               return -ENODEV;
-
-       /* Loop on all possible base addresses */
-       for (i = 0; i < HP100_DEVICES && hp100_port[i] != -1; ++i) {
-               dev = alloc_etherdev(sizeof(struct hp100_private));
-               if (!dev) {
-                       while (cards > 0)
-                               cleanup_dev(hp100_devlist[--cards]);
-
-                       return -ENOMEM;
-               }
-
-               err = hp100_isa_probe(dev, hp100_port[i]);
-               if (!err)
-                       hp100_devlist[cards++] = dev;
-               else
-                       free_netdev(dev);
-       }
-
-       return cards > 0 ? 0 : -ENODEV;
-}
-
-static void hp100_isa_cleanup(void)
-{
-       int i;
-
-       for (i = 0; i < HP100_DEVICES; i++) {
-               struct net_device *dev = hp100_devlist[i];
-               if (dev)
-                       cleanup_dev(dev);
-       }
-}
-#else
-#define hp100_isa_init()       (0)
-#define hp100_isa_cleanup()    do { } while(0)
-#endif
-
-static int __init hp100_module_init(void)
-{
-       int err;
-
-       err = hp100_isa_init();
-       if (err && err != -ENODEV)
-               goto out;
-       err = eisa_driver_register(&hp100_eisa_driver);
-       if (err && err != -ENODEV)
-               goto out2;
-       err = pci_register_driver(&hp100_pci_driver);
-       if (err && err != -ENODEV)
-               goto out3;
- out:
-       return err;
- out3:
-       eisa_driver_unregister (&hp100_eisa_driver);
- out2:
-       hp100_isa_cleanup();
-       goto out;
-}
-
-
-static void __exit hp100_module_exit(void)
-{
-       hp100_isa_cleanup();
-       eisa_driver_unregister (&hp100_eisa_driver);
-       pci_unregister_driver (&hp100_pci_driver);
-}
-
-module_init(hp100_module_init)
-module_exit(hp100_module_exit)
diff --git a/drivers/staging/hp/hp100.h b/drivers/staging/hp/hp100.h
deleted file mode 100644 (file)
index 7239b94..0000000
+++ /dev/null
@@ -1,611 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
- *
- * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $
- *
- * Authors:  Jaroslav Kysela, <perex@pf.jcu.cz>
- *           Siegfried Loeffler <floeff@tunix.mathematik.uni-stuttgart.de>
- *
- * This driver is based on the 'hpfepkt' crynwr packet driver.
- */
-
-/****************************************************************************
- *  Hardware Constants
- ****************************************************************************/
-
-/*
- * Page Identifiers
- * (Swap Paging Register, PAGING, bits 3:0, Offset 0x02)
- */
-
-#define HP100_PAGE_PERFORMANCE 0x0     /* Page 0 */
-#define HP100_PAGE_MAC_ADDRESS 0x1     /* Page 1 */
-#define HP100_PAGE_HW_MAP      0x2     /* Page 2 */
-#define HP100_PAGE_EEPROM_CTRL 0x3     /* Page 3 */
-#define HP100_PAGE_MAC_CTRL    0x4     /* Page 4 */
-#define HP100_PAGE_MMU_CFG     0x5     /* Page 5 */
-#define HP100_PAGE_ID_MAC_ADDR 0x6     /* Page 6 */
-#define HP100_PAGE_MMU_POINTER 0x7     /* Page 7 */
-
-
-/* Registers that are present on all pages  */
-
-#define HP100_REG_HW_ID                0x00    /* R:  (16) Unique card ID           */
-#define HP100_REG_TRACE                0x00    /* W:  (16) Used for debug output    */
-#define HP100_REG_PAGING       0x02    /* R:  (16),15:4 Card ID             */
-                                       /* W:  (16),3:0 Switch pages         */
-#define HP100_REG_OPTION_LSW   0x04    /* RW: (16) Select card functions    */
-#define HP100_REG_OPTION_MSW   0x06    /* RW: (16) Select card functions    */
-
-/*  Page 0 - Performance  */
-
-#define HP100_REG_IRQ_STATUS   0x08    /* RW: (16) Which ints are pending   */
-#define HP100_REG_IRQ_MASK     0x0a    /* RW: (16) Select ints to allow     */
-#define HP100_REG_FRAGMENT_LEN 0x0c    /* W: (16)12:0 Current fragment len */
-/* Note: For 32 bit systems, fragment len and offset registers are available */
-/*       at offset 0x28 and 0x2c, where they can be written as 32bit values. */
-#define HP100_REG_OFFSET       0x0e    /* RW: (16)12:0 Offset to start read */
-#define HP100_REG_DATA32       0x10    /* RW: (32) I/O mode data port       */
-#define HP100_REG_DATA16       0x12    /* RW: WORDs must be read from here  */
-#define HP100_REG_TX_MEM_FREE  0x14    /* RD: (32) Amount of free Tx mem    */
-#define HP100_REG_TX_PDA_L      0x14   /* W: (32) BM: Ptr to PDL, Low Pri  */
-#define HP100_REG_TX_PDA_H      0x1c   /* W: (32) BM: Ptr to PDL, High Pri */
-#define HP100_REG_RX_PKT_CNT   0x18    /* RD: (8) Rx count of pkts on card  */
-#define HP100_REG_TX_PKT_CNT   0x19    /* RD: (8) Tx count of pkts on card  */
-#define HP100_REG_RX_PDL        0x1a   /* R: (8) BM: # rx pdl not executed */
-#define HP100_REG_TX_PDL        0x1b   /* R: (8) BM: # tx pdl not executed */
-#define HP100_REG_RX_PDA        0x18   /* W: (32) BM: Up to 31 addresses */
-                                       /*             which point to a PDL */
-#define HP100_REG_SL_EARLY      0x1c   /*    (32) Enhanced Slave Early Rx */
-#define HP100_REG_STAT_DROPPED  0x20   /* R (12) Dropped Packet Counter */
-#define HP100_REG_STAT_ERRORED  0x22   /* R (8) Errored Packet Counter */
-#define HP100_REG_STAT_ABORT    0x23   /* R (8) Abort Counter/OW Coll. Flag */
-#define HP100_REG_RX_RING       0x24   /* W (32) Slave: RX Ring Pointers */
-#define HP100_REG_32_FRAGMENT_LEN 0x28 /* W (13) Slave: Fragment Length Reg */
-#define HP100_REG_32_OFFSET     0x2c   /* W (16) Slave: Offset Register */
-
-/*  Page 1 - MAC Address/Hash Table  */
-
-#define HP100_REG_MAC_ADDR     0x08    /* RW: (8) Cards MAC address         */
-#define HP100_REG_HASH_BYTE0   0x10    /* RW: (8) Cards multicast filter    */
-
-/*  Page 2 - Hardware Mapping  */
-
-#define HP100_REG_MEM_MAP_LSW  0x08    /* RW: (16) LSW of cards mem addr    */
-#define HP100_REG_MEM_MAP_MSW  0x0a    /* RW: (16) MSW of cards mem addr    */
-#define HP100_REG_IO_MAP       0x0c    /* RW: (8) Cards I/O address         */
-#define HP100_REG_IRQ_CHANNEL  0x0d    /* RW: (8) IRQ and edge/level int    */
-#define HP100_REG_SRAM         0x0e    /* RW: (8) How much RAM on card      */
-#define HP100_REG_BM           0x0f    /* RW: (8) Controls BM functions     */
-
-/* New on Page 2 for ETR chips: */
-#define HP100_REG_MODECTRL1     0x10   /* RW: (8) Mode Control 1 */
-#define HP100_REG_MODECTRL2     0x11   /* RW: (8) Mode Control 2 */
-#define HP100_REG_PCICTRL1      0x12   /* RW: (8) PCI Cfg 1 */
-#define HP100_REG_PCICTRL2      0x13   /* RW: (8) PCI Cfg 2 */
-#define HP100_REG_PCIBUSMLAT    0x15   /* RW: (8) PCI Bus Master Latency */
-#define HP100_REG_EARLYTXCFG    0x16   /* RW: (16) Early TX Cfg/Cntrl Reg */
-#define HP100_REG_EARLYRXCFG    0x18   /* RW: (8) Early RX Cfg/Cntrl Reg */
-#define HP100_REG_ISAPNPCFG1    0x1a   /* RW: (8) ISA PnP Cfg/Cntrl Reg 1 */
-#define HP100_REG_ISAPNPCFG2    0x1b   /* RW: (8) ISA PnP Cfg/Cntrl Reg 2 */
-
-/*  Page 3 - EEPROM/Boot ROM  */
-
-#define HP100_REG_EEPROM_CTRL  0x08    /* RW: (16) Used to load EEPROM      */
-#define HP100_REG_BOOTROM_CTRL  0x0a
-
-/*  Page 4 - LAN Configuration  (MAC_CTRL) */
-
-#define HP100_REG_10_LAN_CFG_1 0x08    /* RW: (8) Set 10M XCVR functions   */
-#define HP100_REG_10_LAN_CFG_2  0x09   /* RW: (8)     10M XCVR functions   */
-#define HP100_REG_VG_LAN_CFG_1 0x0a    /* RW: (8) Set 100M XCVR functions  */
-#define HP100_REG_VG_LAN_CFG_2  0x0b   /* RW: (8) 100M LAN Training cfgregs */
-#define HP100_REG_MAC_CFG_1    0x0c    /* RW: (8) Types of pkts to accept   */
-#define HP100_REG_MAC_CFG_2    0x0d    /* RW: (8) Misc MAC functions        */
-#define HP100_REG_MAC_CFG_3     0x0e   /* RW: (8) Misc MAC functions */
-#define HP100_REG_MAC_CFG_4     0x0f   /* R:  (8) Misc MAC states */
-#define HP100_REG_DROPPED      0x10    /* R:  (16),11:0 Pkts can't fit in mem */
-#define HP100_REG_CRC          0x12    /* R:  (8) Pkts with CRC             */
-#define HP100_REG_ABORT                0x13    /* R:  (8) Aborted Tx pkts           */
-#define HP100_REG_TRAIN_REQUEST 0x14   /* RW: (16) Endnode MAC register. */
-#define HP100_REG_TRAIN_ALLOW   0x16   /* R:  (16) Hub allowed register */
-
-/*  Page 5 - MMU  */
-
-#define HP100_REG_RX_MEM_STOP  0x0c    /* RW: (16) End of Rx ring addr      */
-#define HP100_REG_TX_MEM_STOP  0x0e    /* RW: (16) End of Tx ring addr      */
-#define HP100_REG_PDL_MEM_STOP  0x10   /* Not used by 802.12 devices */
-#define HP100_REG_ECB_MEM_STOP  0x14   /* I've no idea what this is */
-
-/*  Page 6 - Card ID/Physical LAN Address  */
-
-#define HP100_REG_BOARD_ID     0x08    /* R:  (8) EISA/ISA card ID          */
-#define HP100_REG_BOARD_IO_CHCK 0x0c   /* R:  (8) Added to ID to get FFh    */
-#define HP100_REG_SOFT_MODEL   0x0d    /* R:  (8) Config program defined    */
-#define HP100_REG_LAN_ADDR     0x10    /* R:  (8) MAC addr of card          */
-#define HP100_REG_LAN_ADDR_CHCK 0x16   /* R:  (8) Added to addr to get FFh  */
-
-/*  Page 7 - MMU Current Pointers  */
-
-#define HP100_REG_PTR_RXSTART  0x08    /* R:  (16) Current begin of Rx ring */
-#define HP100_REG_PTR_RXEND    0x0a    /* R:  (16) Current end of Rx ring   */
-#define HP100_REG_PTR_TXSTART  0x0c    /* R:  (16) Current begin of Tx ring */
-#define HP100_REG_PTR_TXEND    0x0e    /* R:  (16) Current end of Rx ring   */
-#define HP100_REG_PTR_RPDLSTART 0x10
-#define HP100_REG_PTR_RPDLEND   0x12
-#define HP100_REG_PTR_RINGPTRS  0x14
-#define HP100_REG_PTR_MEMDEBUG  0x1a
-/* ------------------------------------------------------------------------ */
-
-
-/*
- * Hardware ID Register I (Always available, HW_ID, Offset 0x00)
- */
-#define HP100_HW_ID_CASCADE     0x4850 /* Identifies Cascade Chip */
-
-/*
- * Hardware ID Register 2 & Paging Register
- * (Always available, PAGING, Offset 0x02)
- * Bits 15:4 are for the Chip ID
- */
-#define HP100_CHIPID_MASK        0xFFF0
-#define HP100_CHIPID_SHASTA      0x5350        /* Not 802.12 compliant */
-                                        /* EISA BM/SL, MCA16/32 SL, ISA SL */
-#define HP100_CHIPID_RAINIER     0x5360        /* Not 802.12 compliant EISA BM, */
-                                        /* PCI SL, MCA16/32 SL, ISA SL */
-#define HP100_CHIPID_LASSEN      0x5370        /* 802.12 compliant PCI BM, PCI SL */
-                                        /* LRF supported */
-
-/*
- *  Option Registers I and II
- * (Always available, OPTION_LSW, Offset 0x04-0x05)
- */
-#define HP100_DEBUG_EN         0x8000  /* 0:Dis., 1:Enable Debug Dump Ptr. */
-#define HP100_RX_HDR           0x4000  /* 0:Dis., 1:Enable putting pkt into */
-                                       /*   system mem. before Rx interrupt */
-#define HP100_MMAP_DIS         0x2000  /* 0:Enable, 1:Disable mem.mapping. */
-                                       /*   MMAP_DIS must be 0 and MEM_EN */
-                                       /*   must be 1 for memory-mapped */
-                                       /*   mode to be enabled */
-#define HP100_EE_EN            0x1000  /* 0:Disable,1:Enable EEPROM writing */
-#define HP100_BM_WRITE         0x0800  /* 0:Slave, 1:Bus Master for Tx data */
-#define HP100_BM_READ          0x0400  /* 0:Slave, 1:Bus Master for Rx data */
-#define HP100_TRI_INT          0x0200  /* 0:Don't, 1:Do tri-state the int */
-#define HP100_MEM_EN           0x0040  /* Config program set this to */
-                                       /*   0:Disable, 1:Enable mem map. */
-                                       /*   See MMAP_DIS. */
-#define HP100_IO_EN            0x0020  /* 1:Enable I/O transfers */
-#define HP100_BOOT_EN          0x0010  /* 1:Enable boot ROM access */
-#define HP100_FAKE_INT         0x0008  /* 1:int */
-#define HP100_INT_EN           0x0004  /* 1:Enable ints from card */
-#define HP100_HW_RST           0x0002  /* 0:Reset, 1:Out of reset */
-                                       /* NIC reset on 0 to 1 transition */
-
-/*
- *  Option Register III
- * (Always available, OPTION_MSW, Offset 0x06)
- */
-#define HP100_PRIORITY_TX      0x0080  /* 1:Do all Tx pkts as priority */
-#define HP100_EE_LOAD          0x0040  /* 1:EEPROM loading, 0 when done */
-#define HP100_ADV_NXT_PKT      0x0004  /* 1:Advance to next pkt in Rx queue */
-                                       /*   h/w will set to 0 when done */
-#define HP100_TX_CMD           0x0002  /* 1:Tell h/w download done, h/w */
-                                       /*   will set to 0 when done */
-
-/*
- * Interrupt Status Registers I and II
- * (Page PERFORMANCE, IRQ_STATUS, Offset 0x08-0x09)
- * Note: With old chips, these Registers will clear when 1 is written to them
- *       with new chips this depends on setting of CLR_ISMODE
- */
-#define HP100_RX_EARLY_INT      0x2000
-#define HP100_RX_PDA_ZERO       0x1000
-#define HP100_RX_PDL_FILL_COMPL 0x0800
-#define HP100_RX_PACKET                0x0400  /* 0:No, 1:Yes pkt has been Rx */
-#define HP100_RX_ERROR         0x0200  /* 0:No, 1:Yes Rx pkt had error */
-#define HP100_TX_PDA_ZERO       0x0020 /* 1 when PDA count goes to zero */
-#define HP100_TX_SPACE_AVAIL   0x0010  /* 0:<8192, 1:>=8192 Tx free bytes */
-#define HP100_TX_COMPLETE      0x0008  /* 0:No, 1:Yes a Tx has completed */
-#define HP100_MISC_ERROR        0x0004 /* 0:No, 1:Lan Link down or bus error */
-#define HP100_TX_ERROR         0x0002  /* 0:No, 1:Yes Tx pkt had error */
-
-/*
- * Xmit Memory Free Count
- * (Page PERFORMANCE, TX_MEM_FREE, Offset 0x14) (Read only, 32bit)
- */
-#define HP100_AUTO_COMPARE     0x80000000      /* Tx Space avail & pkts<255 */
-#define HP100_FREE_SPACE       0x7fffffe0      /* Tx free memory */
-
-/*
- *  IRQ Channel
- * (Page HW_MAP, IRQ_CHANNEL, Offset 0x0d)
- */
-#define HP100_ZERO_WAIT_EN     0x80    /* 0:No, 1:Yes asserts NOWS signal */
-#define HP100_IRQ_SCRAMBLE      0x40
-#define HP100_BOND_HP           0x20
-#define HP100_LEVEL_IRQ                0x10    /* 0:Edge, 1:Level type interrupts. */
-                                       /* (Only valid on EISA cards) */
-#define HP100_IRQMASK          0x0F    /* Isolate the IRQ bits */
-
-/*
- * SRAM Parameters
- * (Page HW_MAP, SRAM, Offset 0x0e)
- */
-#define HP100_RAM_SIZE_MASK    0xe0    /* AND to get SRAM size index */
-#define HP100_RAM_SIZE_SHIFT   0x05    /* Shift count(put index in lwr bits) */
-
-/*
- * Bus Master Register
- * (Page HW_MAP, BM, Offset 0x0f)
- */
-#define HP100_BM_BURST_RD       0x01   /* EISA only: 1=Use burst trans. fm system */
-                                       /* memory to chip (tx) */
-#define HP100_BM_BURST_WR       0x02   /* EISA only: 1=Use burst trans. fm system */
-                                       /* memory to chip (rx) */
-#define HP100_BM_MASTER                0x04    /* 0:Slave, 1:BM mode */
-#define HP100_BM_PAGE_CK        0x08   /* This bit should be set whenever in */
-                                       /* an EISA system */
-#define HP100_BM_PCI_8CLK       0x40   /* ... cycles 8 clocks apart */
-
-
-/*
- * Mode Control Register I
- * (Page HW_MAP, MODECTRL1, Offset0x10)
- */
-#define HP100_TX_DUALQ          0x10
-   /* If set and BM -> dual tx pda queues */
-#define HP100_ISR_CLRMODE       0x02   /* If set ISR will clear all pending */
-                                      /* interrupts on read (etr only?) */
-#define HP100_EE_NOLOAD         0x04   /* Status whether res will be loaded */
-                                      /* from the eeprom */
-#define HP100_TX_CNT_FLG        0x08   /* Controls Early TX Reg Cnt Field */
-#define HP100_PDL_USE3          0x10   /* If set BM engine will read only */
-                                      /* first three data elements of a PDL */
-                                      /* on the first access. */
-#define HP100_BUSTYPE_MASK      0xe0   /* Three bit bus type info */
-
-/*
- * Mode Control Register II
- * (Page HW_MAP, MODECTRL2, Offset0x11)
- */
-#define HP100_EE_MASK           0x0f   /* Tell EEPROM circuit not to load */
-                                      /* certain resources */
-#define HP100_DIS_CANCEL        0x20   /* For tx dualq mode operation */
-#define HP100_EN_PDL_WB         0x40   /* 1: Status of PDL completion may be */
-                                      /* written back to system mem */
-#define HP100_EN_BUS_FAIL       0x80   /* Enables bus-fail portion of misc */
-                                      /* interrupt */
-
-/*
- * PCI Configuration and Control Register I
- * (Page HW_MAP, PCICTRL1, Offset 0x12)
- */
-#define HP100_LO_MEM            0x01   /* 1: Mapped Mem requested below 1MB */
-#define HP100_NO_MEM            0x02   /* 1: Disables Req for sysmem to PCI */
-                                      /* bios */
-#define HP100_USE_ISA           0x04   /* 1: isa type decodes will occur */
-                                      /* simultaneously with PCI decodes */
-#define HP100_IRQ_HI_MASK       0xf0   /* pgmed by pci bios */
-#define HP100_PCI_IRQ_HI_MASK   0x78   /* Isolate 4 bits for PCI IRQ  */
-
-/*
- * PCI Configuration and Control Register II
- * (Page HW_MAP, PCICTRL2, Offset 0x13)
- */
-#define HP100_RD_LINE_PDL       0x01   /* 1: PCI command Memory Read Line en */
-#define HP100_RD_TX_DATA_MASK   0x06   /* choose PCI memread cmds for TX */
-#define HP100_MWI               0x08   /* 1: en. PCI memory write invalidate */
-#define HP100_ARB_MODE          0x10   /* Select PCI arbitor type */
-#define HP100_STOP_EN           0x20   /* Enables PCI state machine to issue */
-                                      /* pci stop if cascade not ready */
-#define HP100_IGNORE_PAR        0x40   /* 1: PCI state machine ignores parity */
-#define HP100_PCI_RESET         0x80   /* 0->1: Reset PCI block */
-
-/*
- * Early TX Configuration and Control Register
- * (Page HW_MAP, EARLYTXCFG, Offset 0x16)
- */
-#define HP100_EN_EARLY_TX       0x8000 /* 1=Enable Early TX */
-#define HP100_EN_ADAPTIVE       0x4000 /* 1=Enable adaptive mode */
-#define HP100_EN_TX_UR_IRQ      0x2000 /* reserved, must be 0 */
-#define HP100_EN_LOW_TX         0x1000 /* reserved, must be 0 */
-#define HP100_ET_CNT_MASK       0x0fff /* bits 11..0: ET counters */
-
-/*
- * Early RX Configuration and Control Register
- * (Page HW_MAP, EARLYRXCFG, Offset 0x18)
- */
-#define HP100_EN_EARLY_RX       0x80   /* 1=Enable Early RX */
-#define HP100_EN_LOW_RX         0x40   /* reserved, must be 0 */
-#define HP100_RX_TRIP_MASK      0x1f   /* bits 4..0: threshold at which the
-                                        * early rx circuit will start the
-                                        * dma of received packet into system
-                                        * memory for BM */
-
-/*
- *  Serial Devices Control Register
- * (Page EEPROM_CTRL, EEPROM_CTRL, Offset 0x08)
- */
-#define HP100_EEPROM_LOAD      0x0001  /* 0->1 loads EEPROM into registers. */
-                                       /* When it goes back to 0, load is   */
-                                       /* complete. This should take ~600us. */
-
-/*
- * 10MB LAN Control and Configuration Register I
- * (Page MAC_CTRL, 10_LAN_CFG_1, Offset 0x08)
- */
-#define HP100_MAC10_SEL                0xc0    /* Get bits to indicate MAC */
-#define HP100_AUI_SEL          0x20    /* Status of AUI selection */
-#define HP100_LOW_TH           0x10    /* 0:No, 1:Yes allow better cabling */
-#define HP100_LINK_BEAT_DIS    0x08    /* 0:Enable, 1:Disable link beat */
-#define HP100_LINK_BEAT_ST     0x04    /* 0:No, 1:Yes link beat being Rx */
-#define HP100_R_ROL_ST         0x02    /* 0:No, 1:Yes Rx twisted pair has */
-                                       /*             been reversed */
-#define HP100_AUI_ST           0x01    /* 0:No, 1:Yes use AUI on TP card */
-
-/*
- * 10 MB LAN Control and Configuration Register II
- * (Page MAC_CTRL, 10_LAN_CFG_2, Offset 0x09)
- */
-#define HP100_SQU_ST           0x01    /* 0:No, 1:Yes collision signal sent */
-                                       /*       after Tx.Only used for AUI. */
-#define HP100_FULLDUP           0x02   /* 1: LXT901 XCVR fullduplx enabled */
-#define HP100_DOT3_MAC          0x04   /* 1: DOT 3 Mac sel. unless Autosel */
-
-/*
- * MAC Selection, use with MAC10_SEL bits
- */
-#define HP100_AUTO_SEL_10      0x0     /* Auto select */
-#define HP100_XCVR_LXT901_10   0x1     /* LXT901 10BaseT transceiver */
-#define HP100_XCVR_7213                0x2     /* 7213 transceiver */
-#define HP100_XCVR_82503       0x3     /* 82503 transceiver */
-
-/*
- *  100MB LAN Training Register
- * (Page MAC_CTRL, VG_LAN_CFG_2, Offset 0x0b) (old, pre 802.12)
- */
-#define HP100_FRAME_FORMAT     0x08    /* 0:802.3, 1:802.5 frames */
-#define HP100_BRIDGE           0x04    /* 0:No, 1:Yes tell hub i am a bridge */
-#define HP100_PROM_MODE                0x02    /* 0:No, 1:Yes tell hub card is */
-                                       /*         promiscuous */
-#define HP100_REPEATER         0x01    /* 0:No, 1:Yes tell hub MAC wants to */
-                                       /*         be a cascaded repeater */
-
-/*
- * 100MB LAN Control and Configuration Register
- * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a)
- */
-#define HP100_VG_SEL           0x80    /* 0:No, 1:Yes use 100 Mbit MAC */
-#define HP100_LINK_UP_ST       0x40    /* 0:No, 1:Yes endnode logged in */
-#define HP100_LINK_CABLE_ST    0x20    /* 0:No, 1:Yes cable can hear tones */
-                                       /*         from  hub */
-#define HP100_LOAD_ADDR                0x10    /* 0->1 card addr will be sent  */
-                                       /* 100ms later the link status  */
-                                       /* bits are valid */
-#define HP100_LINK_CMD         0x08    /* 0->1 link will attempt to log in. */
-                                       /* 100ms later the link status */
-                                       /* bits are valid */
-#define HP100_TRN_DONE          0x04   /* NEW ETR-Chips only: Will be reset */
-                                       /* after LinkUp Cmd is given and set */
-                                       /* when training has completed. */
-#define HP100_LINK_GOOD_ST     0x02    /* 0:No, 1:Yes cable passed training */
-#define HP100_VG_RESET         0x01    /* 0:Yes, 1:No reset the 100VG MAC */
-
-
-/*
- *  MAC Configuration Register I
- * (Page MAC_CTRL, MAC_CFG_1, Offset 0x0c)
- */
-#define HP100_RX_IDLE          0x80    /* 0:Yes, 1:No currently receiving pkts */
-#define HP100_TX_IDLE          0x40    /* 0:Yes, 1:No currently Txing pkts */
-#define HP100_RX_EN            0x20    /* 1: allow receiving of pkts */
-#define HP100_TX_EN            0x10    /* 1: allow transmitting of pkts */
-#define HP100_ACC_ERRORED      0x08    /* 0:No, 1:Yes allow Rx of errored pkts */
-#define HP100_ACC_MC           0x04    /* 0:No, 1:Yes allow Rx of multicast pkts */
-#define HP100_ACC_BC           0x02    /* 0:No, 1:Yes allow Rx of broadcast pkts */
-#define HP100_ACC_PHY          0x01    /* 0:No, 1:Yes allow Rx of ALL phys. pkts */
-#define HP100_MAC1MODEMASK     0xf0    /* Hide ACC bits */
-#define HP100_MAC1MODE1                0x00    /* Receive nothing, must also disable RX */
-#define HP100_MAC1MODE2                0x00
-#define HP100_MAC1MODE3                HP100_MAC1MODE2 | HP100_ACC_BC
-#define HP100_MAC1MODE4                HP100_MAC1MODE3 | HP100_ACC_MC
-#define HP100_MAC1MODE5                HP100_MAC1MODE4 /* set mc hash to all ones also */
-#define HP100_MAC1MODE6                HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */
-/* Note MODE6 will receive all GOOD packets on the LAN. This really needs
-   a mode 7 defined to be LAN Analyzer mode, which will receive errored and
-   runt packets, and keep the CRC bytes. */
-#define HP100_MAC1MODE7                HP100_MAC1MODE6 | HP100_ACC_ERRORED
-
-/*
- *  MAC Configuration Register II
- * (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d)
- */
-#define HP100_TR_MODE          0x80    /* 0:No, 1:Yes support Token Ring formats */
-#define HP100_TX_SAME          0x40    /* 0:No, 1:Yes Tx same packet continuous */
-#define HP100_LBK_XCVR         0x20    /* 0:No, 1:Yes loopback through MAC & */
-                                       /*   transceiver */
-#define HP100_LBK_MAC          0x10    /* 0:No, 1:Yes loopback through MAC */
-#define HP100_CRC_I            0x08    /* 0:No, 1:Yes inhibit CRC on Tx packets */
-#define HP100_ACCNA             0x04   /* 1: For 802.5: Accept only token ring
-                                        * group addr that maches NA mask */
-#define HP100_KEEP_CRC         0x02    /* 0:No, 1:Yes keep CRC on Rx packets. */
-                                       /*   The length will reflect this. */
-#define HP100_ACCFA             0x01   /* 1: For 802.5: Accept only functional
-                                        * addrs that match FA mask (page1) */
-#define HP100_MAC2MODEMASK     0x02
-#define HP100_MAC2MODE1                0x00
-#define HP100_MAC2MODE2                0x00
-#define HP100_MAC2MODE3                0x00
-#define HP100_MAC2MODE4                0x00
-#define HP100_MAC2MODE5                0x00
-#define HP100_MAC2MODE6                0x00
-#define HP100_MAC2MODE7                KEEP_CRC
-
-/*
- * MAC Configuration Register III
- * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e)
- */
-#define HP100_PACKET_PACE       0x03   /* Packet Pacing:
-                                        * 00: No packet pacing
-                                        * 01: 8 to 16 uS delay
-                                        * 10: 16 to 32 uS delay
-                                        * 11: 32 to 64 uS delay
-                                        */
-#define HP100_LRF_EN            0x04   /* 1: External LAN Rcv Filter and
-                                        * TCP/IP Checksumming enabled. */
-#define HP100_AUTO_MODE         0x10   /* 1: AutoSelect between 10/100 */
-
-/*
- * MAC Configuration Register IV
- * (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f)
- */
-#define HP100_MAC_SEL_ST        0x01   /* (R): Status of external VGSEL
-                                        * Signal, 1=100VG, 0=10Mbit sel. */
-#define HP100_LINK_FAIL_ST      0x02   /* (R): Status of Link Fail portion
-                                        * of the Misc. Interrupt */
-
-/*
- *  100 MB LAN Training Request/Allowed Registers
- * (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only)
- */
-#define HP100_MACRQ_REPEATER         0x0001    /* 1: MAC tells HUB it wants to be
-                                                *    a cascaded repeater
-                                                * 0: ... wants to be a DTE */
-#define HP100_MACRQ_PROMSC           0x0006    /* 2 bits: Promiscious mode
-                                                * 00: Rcv only unicast packets
-                                                *     specifically addr to this
-                                                *     endnode
-                                                * 10: Rcv all pckts fwded by
-                                                *     the local repeater */
-#define HP100_MACRQ_FRAMEFMT_EITHER  0x0018    /* 11: either format allowed */
-#define HP100_MACRQ_FRAMEFMT_802_3   0x0000    /* 00: 802.3 is requested */
-#define HP100_MACRQ_FRAMEFMT_802_5   0x0010    /* 10: 802.5 format is requested */
-#define HP100_CARD_MACVER            0xe000    /* R: 3 bit Cards 100VG MAC version */
-#define HP100_MALLOW_REPEATER        0x0001    /* If reset, requested access as an
-                                                * end node is allowed */
-#define HP100_MALLOW_PROMSC          0x0004    /* 2 bits: Promiscious mode
-                                                * 00: Rcv only unicast packets
-                                                *     specifically addr to this
-                                                *     endnode
-                                                * 10: Rcv all pckts fwded by
-                                                *     the local repeater */
-#define HP100_MALLOW_FRAMEFMT        0x00e0    /* 2 bits: Frame Format
-                                                * 00: 802.3 format will be used
-                                                * 10: 802.5 format will be used */
-#define HP100_MALLOW_ACCDENIED       0x0400    /* N bit */
-#define HP100_MALLOW_CONFIGURE       0x0f00    /* C bit */
-#define HP100_MALLOW_DUPADDR         0x1000    /* D bit */
-#define HP100_HUB_MACVER             0xe000    /* R: 3 bit 802.12 MAC/RMAC training */
-                                            /*    protocol of repeater */
-
-/* ****************************************************************************** */
-
-/*
- *  Set/Reset bits
- */
-#define HP100_SET_HB           0x0100  /* 0:Set fields to 0 whose mask is 1 */
-#define HP100_SET_LB           0x0001  /* HB sets upper byte, LB sets lower byte */
-#define HP100_RESET_HB         0x0000  /* For readability when resetting bits */
-#define HP100_RESET_LB         0x0000  /* For readability when resetting bits */
-
-/*
- *  Misc. Constants
- */
-#define HP100_LAN_100          100     /* lan_type value for VG */
-#define HP100_LAN_10           10      /* lan_type value for 10BaseT */
-#define HP100_LAN_COAX         9       /* lan_type value for Coax */
-#define HP100_LAN_ERR          (-1)    /* lan_type value for link down */
-
-/*
- * Bus Master Data Structures  ----------------------------------------------
- */
-
-#define MAX_RX_PDL              30     /* Card limit = 31 */
-#define MAX_RX_FRAG             2      /* Don't need more... */
-#define MAX_TX_PDL              29
-#define MAX_TX_FRAG             2      /* Limit = 31 */
-
-/* Define total PDL area size in bytes (should be 4096) */
-/* This is the size of kernel (dma) memory that will be allocated. */
-#define MAX_RINGSIZE ((MAX_RX_FRAG*8+4+4)*MAX_RX_PDL+(MAX_TX_FRAG*8+4+4)*MAX_TX_PDL)+16
-
-/* Ethernet Packet Sizes */
-#define MIN_ETHER_SIZE          60
-#define MAX_ETHER_SIZE          1514   /* Needed for preallocation of */
-                                       /* skb buffer when busmastering */
-
-/* Tx or Rx Ring Entry */
-typedef struct hp100_ring {
-       u_int *pdl;             /* Address of PDLs PDH, dword before
-                                * this address is used for rx hdr */
-       u_int pdl_paddr;        /* Physical address of PDL */
-       struct sk_buff *skb;
-       struct hp100_ring *next;
-} hp100_ring_t;
-
-
-
-/* Mask for Header Descriptor */
-#define HP100_PKT_LEN_MASK     0x1FFF  /* AND with RxLength to get length */
-
-
-/* Receive Packet Status.  Note, the error bits are only valid if ACC_ERRORED
-   bit in the MAC Configuration Register 1 is set. */
-#define HP100_RX_PRI           0x8000  /* 0:No, 1:Yes packet is priority */
-#define HP100_SDF_ERR          0x4000  /* 0:No, 1:Yes start of frame error */
-#define HP100_SKEW_ERR         0x2000  /* 0:No, 1:Yes skew out of range */
-#define HP100_BAD_SYMBOL_ERR   0x1000  /* 0:No, 1:Yes invalid symbol received */
-#define HP100_RCV_IPM_ERR      0x0800  /* 0:No, 1:Yes pkt had an invalid packet */
-                                       /*   marker */
-#define HP100_SYMBOL_BAL_ERR   0x0400  /* 0:No, 1:Yes symbol balance error */
-#define HP100_VG_ALN_ERR       0x0200  /* 0:No, 1:Yes non-octet received */
-#define HP100_TRUNC_ERR                0x0100  /* 0:No, 1:Yes the packet was truncated */
-#define HP100_RUNT_ERR         0x0040  /* 0:No, 1:Yes pkt length < Min Pkt */
-                                       /*   Length Reg. */
-#define HP100_ALN_ERR          0x0010  /* 0:No, 1:Yes align error. */
-#define HP100_CRC_ERR          0x0008  /* 0:No, 1:Yes CRC occurred. */
-
-/* The last three bits indicate the type of destination address */
-
-#define HP100_MULTI_ADDR_HASH  0x0006  /* 110: Addr multicast, matched hash */
-#define HP100_BROADCAST_ADDR   0x0003  /* x11: Addr broadcast */
-#define HP100_MULTI_ADDR_NO_HASH 0x0002        /* 010: Addr multicast, didn't match hash */
-#define HP100_PHYS_ADDR_MATCH  0x0001  /* x01: Addr was physical and mine */
-#define HP100_PHYS_ADDR_NO_MATCH 0x0000        /* x00: Addr was physical but not mine */
-
-/*
- *  macros
- */
-
-#define hp100_inb( reg ) \
-        inb( ioaddr + HP100_REG_##reg )
-#define hp100_inw( reg ) \
-       inw( ioaddr + HP100_REG_##reg )
-#define hp100_inl( reg ) \
-       inl( ioaddr + HP100_REG_##reg )
-#define hp100_outb( data, reg ) \
-       outb( data, ioaddr + HP100_REG_##reg )
-#define hp100_outw( data, reg ) \
-       outw( data, ioaddr + HP100_REG_##reg )
-#define hp100_outl( data, reg ) \
-       outl( data, ioaddr + HP100_REG_##reg )
-#define hp100_orb( data, reg ) \
-       outb( inb( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg )
-#define hp100_orw( data, reg ) \
-       outw( inw( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg )
-#define hp100_andb( data, reg ) \
-       outb( inb( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg )
-#define hp100_andw( data, reg ) \
-       outw( inw( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg )
-
-#define hp100_page( page ) \
-       outw( HP100_PAGE_##page, ioaddr + HP100_REG_PAGING )
-#define hp100_ints_off() \
-       outw( HP100_INT_EN | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_ints_on() \
-       outw( HP100_INT_EN | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_mem_map_enable() \
-       outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW )
-#define hp100_mem_map_disable() \
-       outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW )
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192 b/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192
deleted file mode 100644 (file)
index 1c35c50..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-What:          /sys/.../iio:deviceX/ac_excitation_en
-KernelVersion: 3.1.0
-Contact:       linux-iio@vger.kernel.org
-Description:
-               This attribute, if available, is used to enable the AC
-               excitation mode found on some converters. In ac excitation mode,
-               the polarity of the excitation voltage is reversed on
-               alternate cycles, to eliminate DC errors.
-
-What:          /sys/.../iio:deviceX/bridge_switch_en
-KernelVersion: 3.1.0
-Contact:       linux-iio@vger.kernel.org
-Description:
-               This attribute, if available, is used to close or open the
-               bridge power down switch found on some converters.
-               In bridge applications, such as strain gauges and load cells,
-               the bridge itself consumes the majority of the current in the
-               system. To minimize the current consumption of the system,
-               the bridge can be disconnected (when it is not being used
-               using the bridge_switch_en attribute.
index 1b8ebf2..4d46901 100644 (file)
@@ -1,10 +1,4 @@
-2018-04-15
-
-All affected drivers:
-Convert all uses of the old GPIO API from <linux/gpio.h> to the
-GPIO descriptor API in <linux/gpio/consumer.h> and look up GPIO
-lines from device tree, ACPI or board files, board files should
-use <linux/gpio/machine.h>.
+2020-02-25
 
 
 ADI Drivers:
index 39dfe3f..fef52d9 100644 (file)
@@ -250,6 +250,7 @@ static const struct adis_data adis16203_data = {
        .diag_stat_reg = ADIS16203_DIAG_STAT,
 
        .self_test_mask = ADIS16203_MSC_CTRL_SELF_TEST_EN,
+       .self_test_reg = ADIS16203_MSC_CTRL,
        .self_test_no_autoclear = true,
        .timeouts = &adis16203_timeouts,
 
index 39eb836..8bd35c6 100644 (file)
@@ -373,6 +373,7 @@ static const struct adis_data adis16240_data = {
        .diag_stat_reg = ADIS16240_DIAG_STAT,
 
        .self_test_mask = ADIS16240_MSC_CTRL_SELF_TEST_EN,
+       .self_test_reg = ADIS16240_MSC_CTRL,
        .self_test_no_autoclear = true,
        .timeouts = &adis16240_timeouts,
 
index 31cd9a1..b25f410 100644 (file)
@@ -15,18 +15,6 @@ config AD7816
          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
-       select AD_SIGMA_DELTA
-       help
-         Say yes here to build support for Analog Devices AD7190,
-         AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC).
-         If unsure, say N (but it's safe to say "Y").
-
-         To compile this driver as a module, choose M here: the
-         module will be called ad7192.
-
 config AD7280
        tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System"
        depends on SPI
index 4b76769..6436a62 100644 (file)
@@ -4,5 +4,4 @@
 #
 
 obj-$(CONFIG_AD7816) += ad7816.o
-obj-$(CONFIG_AD7192) += ad7192.o
 obj-$(CONFIG_AD7280) += ad7280a.o
index 19a5f24..bef6bd1 100644 (file)
@@ -824,6 +824,10 @@ out:
        return IRQ_HANDLED;
 }
 
+/* Note: No need to fix checkpatch warning that reads:
+ *     CHECK: spaces preferred around that '-' (ctx:VxV)
+ * The function argument is stringified and doesn't need a fix
+ */
 static IIO_DEVICE_ATTR_NAMED(in_thresh_low_value,
                             in_voltage-voltage_thresh_low_value,
                             0644,
index 93cf28f..7b00d70 100644 (file)
@@ -110,10 +110,10 @@ static ssize_t cpld_reconfigure(struct device *dev,
                                const char *buf, size_t count)
 {
        struct kp2000_device *pcard = dev_get_drvdata(dev);
-       long wr_val;
+       unsigned long wr_val;
        int rv;
 
-       rv = kstrtol(buf, 0, &wr_val);
+       rv = kstrtoul(buf, 0, &wr_val);
        if (rv < 0)
                return rv;
        if (wr_val > 7)
index 1c360da..44017d5 100644 (file)
@@ -386,8 +386,8 @@ kp_spi_transfer_one_message(struct spi_master *master, struct spi_message *m)
                        }
                }
 
-               if (transfer->delay_usecs)
-                       udelay(transfer->delay_usecs);
+               if (transfer->delay.value)
+                       ndelay(spi_delay_to_ns(&transfer->delay, transfer));
        }
 
        /* de-assert chip select to end the sequence */
index 51a4dd5..452a3f7 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+// SPDX-License-Identifier: GPL-2.0+
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -97,11 +97,10 @@ int  setup_dma_engine(struct kpc_dma_device *eng, u32 desc_cnt)
        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 {
+       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);
@@ -236,7 +235,7 @@ int  count_descriptors_available(struct kpc_dma_device *eng)
        struct kpc_dma_descriptor *cur = eng->desc_next;
 
        while (cur != eng->desc_completed) {
-               BUG_ON(cur == NULL);
+               BUG_ON(!cur);
                count++;
                cur = cur->Next;
        }
index 4052554..7caabdd 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+// SPDX-License-Identifier: GPL-2.0+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/mm.h>
@@ -18,8 +18,8 @@
 static inline
 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;
+       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;
 }
@@ -66,7 +66,8 @@ static int kpc_dma_transfer(struct dev_private_data *priv,
        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);
+       acd->user_pages = kcalloc(acd->page_count, sizeof(struct page *),
+                                 GFP_KERNEL);
        if (!acd->user_pages) {
                dev_err(&priv->ldev->pldev->dev, "Couldn't kmalloc space for for the page pointers\n");
                rv = -ENOMEM;
@@ -83,7 +84,7 @@ static int kpc_dma_transfer(struct dev_private_data *priv,
        }
 
        // 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);
+       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) {
                dev_err(&priv->ldev->pldev->dev, "Couldn't alloc sg_table (%ld)\n", rv);
                goto err_alloc_sg_table;
@@ -124,19 +125,19 @@ static int kpc_dma_transfer(struct dev_private_data *priv,
                pcnt = count_parts_for_sge(sg);
                for (p = 0 ; p < pcnt ; p++) {
                        // Fill out the descriptor
-                       BUG_ON(desc == NULL);
+                       BUG_ON(!desc);
                        clear_desc(desc);
-                       if (p != pcnt-1) {
+                       if (p != pcnt - 1)
                                desc->DescByteCount = 0x80000;
-                       } else {
+                       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)
+                       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);
@@ -148,13 +149,13 @@ static int kpc_dma_transfer(struct dev_private_data *priv,
                        desc->DescSystemAddrMS = (dma_addr & 0xFFFFFFFF00000000UL) >> 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 & 0x00000000FFFFFFFFUL) >>  0;
                        desc->DescUserControlMS = (user_ctl & 0xFFFFFFFF00000000UL) >> 32;
 
-                       if (i == acd->mapped_entry_count-1 && p == pcnt-1)
+                       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);
@@ -188,9 +189,9 @@ static int kpc_dma_transfer(struct dev_private_data *priv,
        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:
@@ -203,23 +204,21 @@ 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);
+       BUG_ON(!acd);
+       BUG_ON(!acd->user_pages);
+       BUG_ON(!acd->sgt.sgl);
+       BUG_ON(!acd->ldev);
+       BUG_ON(!acd->ldev->pldev);
 
        for (i = 0 ; i < acd->page_count ; i++) {
-               if (!PageReserved(acd->user_pages[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);
 
@@ -253,7 +252,7 @@ int  kpc_dma_open(struct inode *inode, struct file *filp)
                return -EBUSY; /* already open */
        }
 
-       priv = kzalloc(sizeof(struct dev_private_data), GFP_KERNEL);
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
index ec79a85..c3b3055 100644 (file)
@@ -1,8 +1,8 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
+// SPDX-License-Identifier: GPL-2.0+
 #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>
@@ -26,9 +26,8 @@ struct kpc_dma_device *kpc_dma_lookup_device(int minor)
 
        mutex_lock(&kpc_dma_mtx);
        list_for_each_entry(c, &kpc_dma_list, list) {
-               if (c->pldev->id == minor) {
+               if (c->pldev->id == minor)
                        goto out;
-               }
        }
        c = NULL; // not-found case
 out:
@@ -98,7 +97,7 @@ int  kpc_dma_probe(struct platform_device *pldev)
        int rv = 0;
        dev_t dev;
 
-       struct kpc_dma_device *ldev = kzalloc(sizeof(struct kpc_dma_device), GFP_KERNEL);
+       struct kpc_dma_device *ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
 
        if (!ldev) {
                dev_err(&pldev->dev, "%s: unable to kzalloc space for kpc_dma_device\n", __func__);
index 4c8cc86..8b9c978 100644 (file)
@@ -198,14 +198,14 @@ u32  GetEngineCompletePtr(struct kpc_dma_device *eng)
 static inline
 void  lock_engine(struct kpc_dma_device *eng)
 {
-       BUG_ON(eng == NULL);
+       BUG_ON(!eng);
        mutex_lock(&eng->sem);
 }
 
 static inline
 void  unlock_engine(struct kpc_dma_device *eng)
 {
-       BUG_ON(eng == NULL);
+       BUG_ON(!eng);
        mutex_unlock(&eng->sem);
 }
 
index 4b37954..6b2660c 100644 (file)
@@ -446,7 +446,8 @@ static void ks_wlan_hw_rx(struct ks_wlan_private *priv, size_t size)
                                     DUMP_PREFIX_OFFSET,
                                     rx_buffer->data, 32);
 #endif
-               ret = ks7010_sdio_writeb(priv, READ_STATUS_REG, REG_STATUS_IDLE);
+               ret = ks7010_sdio_writeb(priv, READ_STATUS_REG,
+                                        REG_STATUS_IDLE);
                if (ret)
                        netdev_err(priv->net_dev, "write READ_STATUS_REG\n");
 
index ca7dc8f..3913819 100644 (file)
@@ -70,7 +70,7 @@ struct hostif_data_request {
 #define TYPE_DATA 0x0000
 #define TYPE_AUTH 0x0001
        __le16 reserved;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 #define TYPE_PMK1 0x0001
@@ -194,7 +194,7 @@ enum mib_data_type {
 struct hostif_mib_value {
        __le16 size;
        __le16 type;
-       u8 body[0];
+       u8 body[];
 } __packed;
 
 struct hostif_mib_get_confirm_t {
index c394abf..e59a846 100644 (file)
@@ -42,4 +42,8 @@ source "drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig"
 
 source "drivers/staging/media/rkisp1/Kconfig"
 
+if MEDIA_ANALOG_TV_SUPPORT
+source "drivers/staging/media/usbvision/Kconfig"
+endif
+
 endif
index ea9fce8..23c6824 100644 (file)
@@ -10,3 +10,4 @@ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/
 obj-$(CONFIG_SOC_CAMERA)       += soc_camera/
 obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0)    += phy-rockchip-dphy-rx0/
 obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1)      += rkisp1/
+obj-$(CONFIG_VIDEO_USBVISION)  += usbvision/
index 8081716..8e306dc 100644 (file)
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 
-allegro-objs := allegro-core.o nal-h264.o
+allegro-objs := allegro-core.o nal-h264.o allegro-mail.o
 
 obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o
index 3be4169..70f133a 100644 (file)
@@ -5,7 +5,9 @@
  * Allegro DVT video encoder driver
  */
 
+#include <linux/bits.h>
 #include <linux/firmware.h>
+#include <linux/gcd.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -26,6 +28,7 @@
 #include <media/videobuf2-dma-contig.h>
 #include <media/videobuf2-v4l2.h>
 
+#include "allegro-mail.h"
 #include "nal-h264.h"
 
 /*
@@ -40,6 +43,8 @@
 #define ALLEGRO_HEIGHT_DEFAULT 1080
 #define ALLEGRO_HEIGHT_MAX 2160
 
+#define ALLEGRO_FRAMERATE_DEFAULT ((struct v4l2_fract) { 30, 1 })
+
 #define ALLEGRO_GOP_SIZE_DEFAULT 25
 #define ALLEGRO_GOP_SIZE_MAX 1000
 
@@ -176,6 +181,7 @@ struct allegro_channel {
        unsigned int width;
        unsigned int height;
        unsigned int stride;
+       struct v4l2_fract framerate;
 
        enum v4l2_colorspace colorspace;
        enum v4l2_ycbcr_encoding ycbcr_enc;
@@ -192,7 +198,7 @@ struct allegro_channel {
        unsigned int sizeimage_encoded;
        unsigned int csequence;
 
-       enum v4l2_mpeg_video_bitrate_mode bitrate_mode;
+       bool frame_rc_enable;
        unsigned int bitrate;
        unsigned int bitrate_peak;
        unsigned int cpb_size;
@@ -200,9 +206,17 @@ struct allegro_channel {
 
        struct v4l2_ctrl *mpeg_video_h264_profile;
        struct v4l2_ctrl *mpeg_video_h264_level;
-       struct v4l2_ctrl *mpeg_video_bitrate_mode;
-       struct v4l2_ctrl *mpeg_video_bitrate;
-       struct v4l2_ctrl *mpeg_video_bitrate_peak;
+       struct v4l2_ctrl *mpeg_video_h264_i_frame_qp;
+       struct v4l2_ctrl *mpeg_video_h264_max_qp;
+       struct v4l2_ctrl *mpeg_video_h264_min_qp;
+       struct v4l2_ctrl *mpeg_video_h264_p_frame_qp;
+       struct v4l2_ctrl *mpeg_video_h264_b_frame_qp;
+       struct v4l2_ctrl *mpeg_video_frame_rc_enable;
+       struct { /* video bitrate mode control cluster */
+               struct v4l2_ctrl *mpeg_video_bitrate_mode;
+               struct v4l2_ctrl *mpeg_video_bitrate;
+               struct v4l2_ctrl *mpeg_video_bitrate_peak;
+       };
        struct v4l2_ctrl *mpeg_video_cpb_size;
        struct v4l2_ctrl *mpeg_video_gop_size;
 
@@ -215,6 +229,11 @@ struct allegro_channel {
        struct list_head buffers_reference;
        struct list_head buffers_intermediate;
 
+       struct list_head source_shadow_list;
+       struct list_head stream_shadow_list;
+       /* protect shadow lists of buffers passed to firmware */
+       struct mutex shadow_list_lock;
+
        struct list_head list;
        struct completion completion;
 
@@ -236,6 +255,14 @@ allegro_get_state(struct allegro_channel *channel)
        return channel->state;
 }
 
+struct allegro_m2m_buffer {
+       struct v4l2_m2m_buffer buf;
+       struct list_head head;
+};
+
+#define to_allegro_m2m_buffer(__buf) \
+       container_of(__buf, struct allegro_m2m_buffer, buf)
+
 struct fw_info {
        unsigned int id;
        unsigned int id_codec;
@@ -258,276 +285,33 @@ static const struct fw_info supported_firmware[] = {
        },
 };
 
-enum mcu_msg_type {
-       MCU_MSG_TYPE_INIT = 0x0000,
-       MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005,
-       MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006,
-       MCU_MSG_TYPE_ENCODE_FRAME = 0x0007,
-       MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012,
-       MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e,
-       MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f,
-};
+static inline u32 to_mcu_addr(struct allegro_dev *dev, dma_addr_t phys)
+{
+       if (upper_32_bits(phys) || (lower_32_bits(phys) & MCU_CACHE_OFFSET))
+               v4l2_warn(&dev->v4l2_dev,
+                         "address %pad is outside mcu window\n", &phys);
+
+       return lower_32_bits(phys) | MCU_CACHE_OFFSET;
+}
 
-static const char *msg_type_name(enum mcu_msg_type type)
+static inline u32 to_mcu_size(struct allegro_dev *dev, size_t size)
 {
-       static char buf[9];
+       return lower_32_bits(size);
+}
 
-       switch (type) {
-       case MCU_MSG_TYPE_INIT:
-               return "INIT";
-       case MCU_MSG_TYPE_CREATE_CHANNEL:
-               return "CREATE_CHANNEL";
-       case MCU_MSG_TYPE_DESTROY_CHANNEL:
-               return "DESTROY_CHANNEL";
-       case MCU_MSG_TYPE_ENCODE_FRAME:
-               return "ENCODE_FRAME";
-       case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
-               return "PUT_STREAM_BUFFER";
-       case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
-               return "PUSH_BUFFER_INTERMEDIATE";
-       case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
-               return "PUSH_BUFFER_REFERENCE";
-       default:
-               snprintf(buf, sizeof(buf), "(0x%04x)", type);
-               return buf;
-       }
-}
-
-struct mcu_msg_header {
-       u16 length;             /* length of the body in bytes */
-       u16 type;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_init_request {
-       struct mcu_msg_header header;
-       u32 reserved0;          /* maybe a unused channel id */
-       u32 suballoc_dma;
-       u32 suballoc_size;
-       s32 l2_cache[3];
-} __attribute__ ((__packed__));
-
-struct mcu_msg_init_response {
-       struct mcu_msg_header header;
-       u32 reserved0;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_create_channel {
-       struct mcu_msg_header header;
-       u32 user_id;
-       u16 width;
-       u16 height;
-       u32 format;
-       u32 colorspace;
-       u32 src_mode;
-       u8 profile;
-       u16 constraint_set_flags;
-       s8 codec;
-       u16 level;
-       u16 tier;
-       u32 sps_param;
-       u32 pps_param;
-
-       u32 enc_option;
-#define AL_OPT_WPP                     BIT(0)
-#define AL_OPT_TILE                    BIT(1)
-#define AL_OPT_LF                      BIT(2)
-#define AL_OPT_LF_X_SLICE              BIT(3)
-#define AL_OPT_LF_X_TILE               BIT(4)
-#define AL_OPT_SCL_LST                 BIT(5)
-#define AL_OPT_CONST_INTRA_PRED                BIT(6)
-#define AL_OPT_QP_TAB_RELATIVE         BIT(7)
-#define AL_OPT_FIX_PREDICTOR           BIT(8)
-#define AL_OPT_CUSTOM_LDA              BIT(9)
-#define AL_OPT_ENABLE_AUTO_QP          BIT(10)
-#define AL_OPT_ADAPT_AUTO_QP           BIT(11)
-#define AL_OPT_TRANSFO_SKIP            BIT(13)
-#define AL_OPT_FORCE_REC               BIT(15)
-#define AL_OPT_FORCE_MV_OUT            BIT(16)
-#define AL_OPT_FORCE_MV_CLIP           BIT(17)
-#define AL_OPT_LOWLAT_SYNC             BIT(18)
-#define AL_OPT_LOWLAT_INT              BIT(19)
-#define AL_OPT_RDO_COST_MODE           BIT(20)
-
-       s8 beta_offset;
-       s8 tc_offset;
-       u16 reserved10;
-       u32 unknown11;
-       u32 unknown12;
-       u16 num_slices;
-       u16 prefetch_auto;
-       u32 prefetch_mem_offset;
-       u32 prefetch_mem_size;
-       u16 clip_hrz_range;
-       u16 clip_vrt_range;
-       u16 me_range[4];
-       u8 max_cu_size;
-       u8 min_cu_size;
-       u8 max_tu_size;
-       u8 min_tu_size;
-       u8 max_transfo_depth_inter;
-       u8 max_transfo_depth_intra;
-       u16 reserved20;
-       u32 entropy_mode;
-       u32 wp_mode;
-
-       /* rate control param */
-       u32 rate_control_mode;
-       u32 initial_rem_delay;
-       u32 cpb_size;
-       u16 framerate;
-       u16 clk_ratio;
-       u32 target_bitrate;
-       u32 max_bitrate;
-       u16 initial_qp;
-       u16 min_qp;
-       u16 max_qp;
-       s16 ip_delta;
-       s16 pb_delta;
-       u16 golden_ref;
-       u16 golden_delta;
-       u16 golden_ref_frequency;
-       u32 rate_control_option;
-
-       /* gop param */
-       u32 gop_ctrl_mode;
-       u32 freq_ird;
-       u32 freq_lt;
-       u32 gdr_mode;
-       u32 gop_length;
-       u32 unknown39;
-
-       u32 subframe_latency;
-       u32 lda_control_mode;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_create_channel_response {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       u32 user_id;
-       u32 options;
-       u32 num_core;
-       u32 pps_param;
-       u32 int_buffers_count;
-       u32 int_buffers_size;
-       u32 rec_buffers_count;
-       u32 rec_buffers_size;
-       u32 reserved;
-       u32 error_code;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_destroy_channel {
-       struct mcu_msg_header header;
-       u32 channel_id;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_destroy_channel_response {
-       struct mcu_msg_header header;
-       u32 channel_id;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_push_buffers_internal_buffer {
-       u32 dma_addr;
-       u32 mcu_addr;
-       u32 size;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_push_buffers_internal {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       struct mcu_msg_push_buffers_internal_buffer buffer[0];
-} __attribute__ ((__packed__));
-
-struct mcu_msg_put_stream_buffer {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       u32 dma_addr;
-       u32 mcu_addr;
-       u32 size;
-       u32 offset;
-       u64 stream_id;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_encode_frame {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       u32 reserved;
-
-       u32 encoding_options;
-#define AL_OPT_USE_QP_TABLE            BIT(0)
-#define AL_OPT_FORCE_LOAD              BIT(1)
-#define AL_OPT_USE_L2                  BIT(2)
-#define AL_OPT_DISABLE_INTRA           BIT(3)
-#define AL_OPT_DEPENDENT_SLICES                BIT(4)
-
-       s16 pps_qp;
-       u16 padding;
-       u64 user_param;
-       u64 src_handle;
+static inline u32 to_codec_addr(struct allegro_dev *dev, dma_addr_t phys)
+{
+       if (upper_32_bits(phys))
+               v4l2_warn(&dev->v4l2_dev,
+                         "address %pad cannot be used by codec\n", &phys);
 
-       u32 request_options;
-#define AL_OPT_SCENE_CHANGE            BIT(0)
-#define AL_OPT_RESTART_GOP             BIT(1)
-#define AL_OPT_USE_LONG_TERM           BIT(2)
-#define AL_OPT_UPDATE_PARAMS           BIT(3)
-
-       /* u32 scene_change_delay (optional) */
-       /* rate control param (optional) */
-       /* gop param (optional) */
-       u32 src_y;
-       u32 src_uv;
-       u32 stride;
-       u32 ep2;
-       u64 ep2_v;
-} __attribute__ ((__packed__));
-
-struct mcu_msg_encode_frame_response {
-       struct mcu_msg_header header;
-       u32 channel_id;
-       u64 stream_id;          /* see mcu_msg_put_stream_buffer */
-       u64 user_param;         /* see mcu_msg_encode_frame */
-       u64 src_handle;         /* see mcu_msg_encode_frame */
-       u16 skip;
-       u16 is_ref;
-       u32 initial_removal_delay;
-       u32 dpb_output_delay;
-       u32 size;
-       u32 frame_tag_size;
-       s32 stuffing;
-       s32 filler;
-       u16 num_column;
-       u16 num_row;
-       u16 qp;
-       u8 num_ref_idx_l0;
-       u8 num_ref_idx_l1;
-       u32 partition_table_offset;
-       s32 partition_table_size;
-       u32 sum_complex;
-       s32 tile_width[4];
-       s32 tile_height[22];
-       u32 error_code;
-
-       u32 slice_type;
-#define AL_ENC_SLICE_TYPE_B             0
-#define AL_ENC_SLICE_TYPE_P             1
-#define AL_ENC_SLICE_TYPE_I             2
-
-       u32 pic_struct;
-       u8 is_idr;
-       u8 is_first_slice;
-       u8 is_last_slice;
-       u8 reserved;
-       u16 pps_qp;
-       u16 reserved1;
-       u32 reserved2;
-} __attribute__ ((__packed__));
-
-union mcu_msg_response {
-       struct mcu_msg_header header;
-       struct mcu_msg_init_response init;
-       struct mcu_msg_create_channel_response create_channel;
-       struct mcu_msg_destroy_channel_response destroy_channel;
-       struct mcu_msg_encode_frame_response encode_frame;
-};
+       return lower_32_bits(phys);
+}
+
+static inline u64 ptr_to_u64(const void *ptr)
+{
+       return (uintptr_t)ptr;
+}
 
 /* Helper functions for channel and user operations */
 
@@ -572,6 +356,56 @@ static inline bool channel_exists(struct allegro_channel *channel)
        return channel->mcu_channel_id != -1;
 }
 
+#define AL_ERROR                       0x80
+#define AL_ERR_INIT_FAILED             0x81
+#define AL_ERR_NO_FRAME_DECODED                0x82
+#define AL_ERR_RESOLUTION_CHANGE       0x85
+#define AL_ERR_NO_MEMORY               0x87
+#define AL_ERR_STREAM_OVERFLOW         0x88
+#define AL_ERR_TOO_MANY_SLICES         0x89
+#define AL_ERR_BUF_NOT_READY           0x8c
+#define AL_ERR_NO_CHANNEL_AVAILABLE    0x8d
+#define AL_ERR_RESOURCE_UNAVAILABLE    0x8e
+#define AL_ERR_NOT_ENOUGH_CORES                0x8f
+#define AL_ERR_REQUEST_MALFORMED       0x90
+#define AL_ERR_CMD_NOT_ALLOWED         0x91
+#define AL_ERR_INVALID_CMD_VALUE       0x92
+
+static inline const char *allegro_err_to_string(unsigned int err)
+{
+       switch (err) {
+       case AL_ERR_INIT_FAILED:
+               return "initialization failed";
+       case AL_ERR_NO_FRAME_DECODED:
+               return "no frame decoded";
+       case AL_ERR_RESOLUTION_CHANGE:
+               return "resolution change";
+       case AL_ERR_NO_MEMORY:
+               return "out of memory";
+       case AL_ERR_STREAM_OVERFLOW:
+               return "stream buffer overflow";
+       case AL_ERR_TOO_MANY_SLICES:
+               return "too many slices";
+       case AL_ERR_BUF_NOT_READY:
+               return "buffer not ready";
+       case AL_ERR_NO_CHANNEL_AVAILABLE:
+               return "no channel available";
+       case AL_ERR_RESOURCE_UNAVAILABLE:
+               return "resource unavailable";
+       case AL_ERR_NOT_ENOUGH_CORES:
+               return "not enough cores";
+       case AL_ERR_REQUEST_MALFORMED:
+               return "request malformed";
+       case AL_ERR_CMD_NOT_ALLOWED:
+               return "command not allowed";
+       case AL_ERR_INVALID_CMD_VALUE:
+               return "invalid command value";
+       case AL_ERROR:
+       default:
+               return "unknown error";
+       }
+}
+
 static unsigned int estimate_stream_size(unsigned int width,
                                         unsigned int height)
 {
@@ -781,7 +615,7 @@ static int allegro_mbox_write(struct allegro_dev *dev,
 
        if (size > mbox->size) {
                v4l2_err(&dev->v4l2_dev,
-                        "message (%zu bytes) to large for mailbox (%zu bytes)\n",
+                        "message (%zu bytes) too large for mailbox (%zu bytes)\n",
                         size, mbox->size);
                return -EINVAL;
        }
@@ -894,8 +728,8 @@ static void allegro_mcu_send_init(struct allegro_dev *dev,
        msg.header.type = MCU_MSG_TYPE_INIT;
        msg.header.length = sizeof(msg) - sizeof(msg.header);
 
-       msg.suballoc_dma = lower_32_bits(suballoc_dma) | MCU_CACHE_OFFSET;
-       msg.suballoc_size = suballoc_size;
+       msg.suballoc_dma = to_mcu_addr(dev, suballoc_dma);
+       msg.suballoc_size = to_mcu_size(dev, suballoc_size);
 
        /* disable L2 cache */
        msg.l2_cache[0] = -1;
@@ -1001,6 +835,103 @@ v4l2_bitrate_mode_to_mcu_mode(enum v4l2_mpeg_video_bitrate_mode mode)
        }
 }
 
+static u32 v4l2_cpb_size_to_mcu(unsigned int cpb_size, unsigned int bitrate)
+{
+       unsigned int cpb_size_kbit;
+       unsigned int bitrate_kbps;
+
+       /*
+        * The mcu expects the CPB size in units of a 90 kHz clock, but the
+        * channel follows the V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE and stores
+        * the CPB size in kilobytes.
+        */
+       cpb_size_kbit = cpb_size * BITS_PER_BYTE;
+       bitrate_kbps = bitrate / 1000;
+
+       return (cpb_size_kbit * 90000) / bitrate_kbps;
+}
+
+static s16 get_qp_delta(int minuend, int subtrahend)
+{
+       if (minuend == subtrahend)
+               return -1;
+       else
+               return minuend - subtrahend;
+}
+
+static int fill_create_channel_param(struct allegro_channel *channel,
+                                    struct create_channel_param *param)
+{
+       int i_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_i_frame_qp);
+       int p_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_p_frame_qp);
+       int b_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_b_frame_qp);
+       int bitrate_mode = v4l2_ctrl_g_ctrl(channel->mpeg_video_bitrate_mode);
+
+       param->width = channel->width;
+       param->height = channel->height;
+       param->format = v4l2_pixelformat_to_mcu_format(channel->pixelformat);
+       param->colorspace =
+               v4l2_colorspace_to_mcu_colorspace(channel->colorspace);
+       param->src_mode = 0x0;
+       param->profile = v4l2_profile_to_mcu_profile(channel->profile);
+       param->constraint_set_flags = BIT(1);
+       param->codec = v4l2_pixelformat_to_mcu_codec(channel->codec);
+       param->level = v4l2_level_to_mcu_level(channel->level);
+       param->tier = 0;
+       param->sps_param = BIT(20) | 0x4a;
+       param->pps_param = BIT(2);
+       param->enc_option = AL_OPT_RDO_COST_MODE | AL_OPT_LF_X_TILE |
+                           AL_OPT_LF_X_SLICE | AL_OPT_LF;
+       param->beta_offset = -1;
+       param->tc_offset = -1;
+       param->num_slices = 1;
+       param->me_range[0] = 8;
+       param->me_range[1] = 8;
+       param->me_range[2] = 16;
+       param->me_range[3] = 16;
+       param->max_cu_size = ilog2(SIZE_MACROBLOCK);
+       param->min_cu_size = ilog2(8);
+       param->max_tu_size = 2;
+       param->min_tu_size = 2;
+       param->max_transfo_depth_intra = 1;
+       param->max_transfo_depth_inter = 1;
+
+       param->prefetch_auto = 0;
+       param->prefetch_mem_offset = 0;
+       param->prefetch_mem_size = 0;
+
+       param->rate_control_mode = channel->frame_rc_enable ?
+               v4l2_bitrate_mode_to_mcu_mode(bitrate_mode) : 0;
+
+       param->cpb_size = v4l2_cpb_size_to_mcu(channel->cpb_size,
+                                              channel->bitrate_peak);
+       /* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */
+       param->initial_rem_delay = param->cpb_size;
+       param->framerate = DIV_ROUND_UP(channel->framerate.numerator,
+                                       channel->framerate.denominator);
+       param->clk_ratio = channel->framerate.denominator == 1001 ? 1001 : 1000;
+       param->target_bitrate = channel->bitrate;
+       param->max_bitrate = channel->bitrate_peak;
+       param->initial_qp = i_frame_qp;
+       param->min_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_min_qp);
+       param->max_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_max_qp);
+       param->ip_delta = get_qp_delta(i_frame_qp, p_frame_qp);
+       param->pb_delta = get_qp_delta(p_frame_qp, b_frame_qp);
+       param->golden_ref = 0;
+       param->golden_delta = 2;
+       param->golden_ref_frequency = 10;
+       param->rate_control_option = 0x00000000;
+
+       param->gop_ctrl_mode = 0x00000000;
+       param->freq_idr = channel->gop_size;
+       param->freq_lt = 0;
+       param->gdr_mode = 0x00000000;
+       param->gop_length = channel->gop_size;
+       param->subframe_latency = 0x00000000;
+
+       return 0;
+}
+
 static int allegro_mcu_send_create_channel(struct allegro_dev *dev,
                                           struct allegro_channel *channel)
 {
@@ -1012,63 +943,8 @@ static int allegro_mcu_send_create_channel(struct allegro_dev *dev,
        msg.header.length = sizeof(msg) - sizeof(msg.header);
 
        msg.user_id = channel->user_id;
-       msg.width = channel->width;
-       msg.height = channel->height;
-       msg.format = v4l2_pixelformat_to_mcu_format(channel->pixelformat);
-       msg.colorspace = v4l2_colorspace_to_mcu_colorspace(channel->colorspace);
-       msg.src_mode = 0x0;
-       msg.profile = v4l2_profile_to_mcu_profile(channel->profile);
-       msg.constraint_set_flags = BIT(1);
-       msg.codec = v4l2_pixelformat_to_mcu_codec(channel->codec);
-       msg.level = v4l2_level_to_mcu_level(channel->level);
-       msg.tier = 0;
-       msg.sps_param = BIT(20) | 0x4a;
-       msg.pps_param = BIT(2);
-       msg.enc_option = AL_OPT_RDO_COST_MODE | AL_OPT_LF_X_TILE |
-                        AL_OPT_LF_X_SLICE | AL_OPT_LF;
-       msg.beta_offset = -1;
-       msg.tc_offset = -1;
-       msg.num_slices = 1;
-       msg.me_range[0] = 8;
-       msg.me_range[1] = 8;
-       msg.me_range[2] = 16;
-       msg.me_range[3] = 16;
-       msg.max_cu_size = ilog2(SIZE_MACROBLOCK);
-       msg.min_cu_size = ilog2(8);
-       msg.max_tu_size = 2;
-       msg.min_tu_size = 2;
-       msg.max_transfo_depth_intra = 1;
-       msg.max_transfo_depth_inter = 1;
-
-       msg.rate_control_mode =
-               v4l2_bitrate_mode_to_mcu_mode(channel->bitrate_mode);
-       /* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */
-       msg.initial_rem_delay =
-               ((channel->cpb_size * 1000) / channel->bitrate_peak) * 90000;
-       /* Encoder expects cpb_size in units of a 90 kHz clock. */
-       msg.cpb_size =
-               ((channel->cpb_size * 1000) / channel->bitrate_peak) * 90000;
-       msg.framerate = 25;
-       msg.clk_ratio = 1000;
-       msg.target_bitrate = channel->bitrate;
-       msg.max_bitrate = channel->bitrate_peak;
-       msg.initial_qp = 25;
-       msg.min_qp = 10;
-       msg.max_qp = 51;
-       msg.ip_delta = -1;
-       msg.pb_delta = -1;
-       msg.golden_ref = 0;
-       msg.golden_delta = 2;
-       msg.golden_ref_frequency = 10;
-       msg.rate_control_option = 0x00000000;
-
-       msg.gop_ctrl_mode = 0x00000000;
-       msg.freq_ird = 0x7fffffff;
-       msg.freq_lt = 0;
-       msg.gdr_mode = 0x00000000;
-       msg.gop_length = channel->gop_size;
-       msg.subframe_latency = 0x00000000;
-       msg.lda_control_mode = 0x700d0000;
+
+       fill_create_channel_param(channel, &msg.param);
 
        allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
        allegro_mcu_interrupt(dev);
@@ -1097,7 +973,8 @@ static int allegro_mcu_send_destroy_channel(struct allegro_dev *dev,
 static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev,
                                              struct allegro_channel *channel,
                                              dma_addr_t paddr,
-                                             unsigned long size)
+                                             unsigned long size,
+                                             u64 stream_id)
 {
        struct mcu_msg_put_stream_buffer msg;
 
@@ -1107,11 +984,12 @@ static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev,
        msg.header.length = sizeof(msg) - sizeof(msg.header);
 
        msg.channel_id = channel->mcu_channel_id;
-       msg.dma_addr = paddr;
-       msg.mcu_addr = paddr | MCU_CACHE_OFFSET;
+       msg.dma_addr = to_codec_addr(dev, paddr);
+       msg.mcu_addr = to_mcu_addr(dev, paddr);
        msg.size = size;
        msg.offset = ENCODER_STREAM_OFFSET;
-       msg.stream_id = 0; /* copied to mcu_msg_encode_frame_response */
+       /* copied to mcu_msg_encode_frame_response */
+       msg.stream_id = stream_id;
 
        allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
        allegro_mcu_interrupt(dev);
@@ -1121,7 +999,8 @@ static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev,
 
 static int allegro_mcu_send_encode_frame(struct allegro_dev *dev,
                                         struct allegro_channel *channel,
-                                        dma_addr_t src_y, dma_addr_t src_uv)
+                                        dma_addr_t src_y, dma_addr_t src_uv,
+                                        u64 src_handle)
 {
        struct mcu_msg_encode_frame msg;
 
@@ -1134,12 +1013,13 @@ static int allegro_mcu_send_encode_frame(struct allegro_dev *dev,
        msg.encoding_options = AL_OPT_FORCE_LOAD;
        msg.pps_qp = 26; /* qp are relative to 26 */
        msg.user_param = 0; /* copied to mcu_msg_encode_frame_response */
-       msg.src_handle = 0; /* copied to mcu_msg_encode_frame_response */
-       msg.src_y = src_y;
-       msg.src_uv = src_uv;
+       /* src_handle is copied to mcu_msg_encode_frame_response */
+       msg.src_handle = src_handle;
+       msg.src_y = to_codec_addr(dev, src_y);
+       msg.src_uv = to_codec_addr(dev, src_uv);
        msg.stride = channel->stride;
        msg.ep2 = 0x0;
-       msg.ep2_v = msg.ep2 | MCU_CACHE_OFFSET;
+       msg.ep2_v = to_mcu_addr(dev, msg.ep2);
 
        allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg));
        allegro_mcu_interrupt(dev);
@@ -1198,10 +1078,9 @@ static int allegro_mcu_push_buffer_internal(struct allegro_channel *channel,
 
        buffer = msg->buffer;
        list_for_each_entry(al_buffer, list, head) {
-               buffer->dma_addr = lower_32_bits(al_buffer->paddr);
-               buffer->mcu_addr =
-                   lower_32_bits(al_buffer->paddr) | MCU_CACHE_OFFSET;
-               buffer->size = al_buffer->size;
+               buffer->dma_addr = to_codec_addr(dev, al_buffer->paddr);
+               buffer->mcu_addr = to_mcu_addr(dev, al_buffer->paddr);
+               buffer->size = to_mcu_size(dev, al_buffer->size);
                buffer++;
        }
 
@@ -1360,9 +1239,11 @@ static ssize_t allegro_h264_write_sps(struct allegro_channel *channel,
        sps->vui.chroma_loc_info_present_flag = 1;
        sps->vui.chroma_sample_loc_type_top_field = 0;
        sps->vui.chroma_sample_loc_type_bottom_field = 0;
+
        sps->vui.timing_info_present_flag = 1;
-       sps->vui.num_units_in_tick = 1;
-       sps->vui.time_scale = 50;
+       sps->vui.num_units_in_tick = channel->framerate.denominator;
+       sps->vui.time_scale = 2 * channel->framerate.numerator;
+
        sps->vui.fixed_frame_rate_flag = 1;
        sps->vui.nal_hrd_parameters_present_flag = 0;
        sps->vui.vcl_hrd_parameters_present_flag = 1;
@@ -1375,7 +1256,8 @@ static ssize_t allegro_h264_write_sps(struct allegro_channel *channel,
        /* See Rec. ITU-T H.264 (04/2017) p. 410 E-54 */
        sps->vui.vcl_hrd_parameters.cpb_size_value_minus1[0] =
                (channel->cpb_size * 1000) / (1 << (4 + sps->vui.vcl_hrd_parameters.cpb_size_scale)) - 1;
-       sps->vui.vcl_hrd_parameters.cbr_flag[0] = 1;
+       sps->vui.vcl_hrd_parameters.cbr_flag[0] =
+               !v4l2_ctrl_g_ctrl(channel->mpeg_video_frame_rc_enable);
        sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 = 31;
        sps->vui.vcl_hrd_parameters.cpb_removal_delay_length_minus1 = 31;
        sps->vui.vcl_hrd_parameters.dpb_output_delay_length_minus1 = 31;
@@ -1438,8 +1320,11 @@ static bool allegro_channel_is_at_eos(struct allegro_channel *channel)
                break;
        case ALLEGRO_STATE_DRAIN:
        case ALLEGRO_STATE_WAIT_FOR_BUFFER:
-               if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) == 0)
+               mutex_lock(&channel->shadow_list_lock);
+               if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) == 0 &&
+                   list_empty(&channel->source_shadow_list))
                        is_at_eos = true;
+               mutex_unlock(&channel->shadow_list_lock);
                break;
        default:
                break;
@@ -1466,6 +1351,41 @@ static void allegro_channel_buf_done(struct allegro_channel *channel,
        v4l2_m2m_buf_done(buf, state);
 }
 
+static u64 allegro_put_buffer(struct allegro_channel *channel,
+                             struct list_head *list,
+                             struct vb2_v4l2_buffer *buffer)
+{
+       struct v4l2_m2m_buffer *b = container_of(buffer,
+                                                struct v4l2_m2m_buffer, vb);
+       struct allegro_m2m_buffer *shadow = to_allegro_m2m_buffer(b);
+
+       mutex_lock(&channel->shadow_list_lock);
+       list_add_tail(&shadow->head, list);
+       mutex_unlock(&channel->shadow_list_lock);
+
+       return ptr_to_u64(buffer);
+}
+
+static struct vb2_v4l2_buffer *
+allegro_get_buffer(struct allegro_channel *channel,
+                  struct list_head *list, u64 handle)
+{
+       struct allegro_m2m_buffer *shadow, *tmp;
+       struct vb2_v4l2_buffer *buffer = NULL;
+
+       mutex_lock(&channel->shadow_list_lock);
+       list_for_each_entry_safe(shadow, tmp, list, head) {
+               if (handle == ptr_to_u64(&shadow->buf.vb)) {
+                       buffer = &shadow->buf.vb;
+                       list_del_init(&shadow->head);
+                       break;
+               }
+       }
+       mutex_unlock(&channel->shadow_list_lock);
+
+       return buffer;
+}
+
 static void allegro_channel_finish_frame(struct allegro_channel *channel,
                struct mcu_msg_encode_frame_response *msg)
 {
@@ -1481,15 +1401,31 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel,
        ssize_t len;
        ssize_t free;
 
-       src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx);
+       src_buf = allegro_get_buffer(channel, &channel->source_shadow_list,
+                                    msg->src_handle);
+       if (!src_buf)
+               v4l2_warn(&dev->v4l2_dev,
+                         "channel %d: invalid source buffer\n",
+                         channel->mcu_channel_id);
+
+       dst_buf = allegro_get_buffer(channel, &channel->stream_shadow_list,
+                                    msg->stream_id);
+       if (!dst_buf)
+               v4l2_warn(&dev->v4l2_dev,
+                         "channel %d: invalid stream buffer\n",
+                         channel->mcu_channel_id);
+
+       if (!src_buf || !dst_buf)
+               goto err;
 
-       dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx);
        dst_buf->sequence = channel->csequence++;
 
-       if (msg->error_code) {
+       if (msg->error_code & AL_ERROR) {
                v4l2_err(&dev->v4l2_dev,
-                        "channel %d: error while encoding frame: %x\n",
-                        channel->mcu_channel_id, msg->error_code);
+                        "channel %d: failed to encode frame: %s (%x)\n",
+                        channel->mcu_channel_id,
+                        allegro_err_to_string(msg->error_code),
+                        msg->error_code);
                goto err;
        }
 
@@ -1562,17 +1498,22 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel,
                         channel->mcu_channel_id, len);
        }
 
-       len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free);
-       if (len < 0) {
-               v4l2_err(&dev->v4l2_dev,
-                        "failed to write %zd filler data\n", free);
-               goto err;
+       if (msg->slice_type != AL_ENC_SLICE_TYPE_I && !msg->is_idr) {
+               dst_buf->vb2_buf.planes[0].data_offset = free;
+               free = 0;
+       } else {
+               len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free);
+               if (len < 0) {
+                       v4l2_err(&dev->v4l2_dev,
+                                "failed to write %zd filler data\n", free);
+                       goto err;
+               }
+               curr += len;
+               free -= len;
+               v4l2_dbg(2, debug, &dev->v4l2_dev,
+                        "channel %d: wrote %zd bytes filler nal unit\n",
+                        channel->mcu_channel_id, len);
        }
-       curr += len;
-       free -= len;
-       v4l2_dbg(2, debug, &dev->v4l2_dev,
-                "channel %d: wrote %zd bytes filler nal unit\n",
-                channel->mcu_channel_id, len);
 
        if (free != 0) {
                v4l2_err(&dev->v4l2_dev,
@@ -1590,20 +1531,20 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel,
                dst_buf->flags |= V4L2_BUF_FLAG_PFRAME;
 
        v4l2_dbg(1, debug, &dev->v4l2_dev,
-                "channel %d: encoded frame #%03d (%s%s, %d bytes)\n",
+                "channel %d: encoded frame #%03d (%s%s, QP %d, %d bytes)\n",
                 channel->mcu_channel_id,
                 dst_buf->sequence,
                 msg->is_idr ? "IDR, " : "",
                 msg->slice_type == AL_ENC_SLICE_TYPE_I ? "I slice" :
                 msg->slice_type == AL_ENC_SLICE_TYPE_P ? "P slice" : "unknown",
-                partition->size);
+                msg->qp, partition->size);
 
 err:
-       v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
-
-       allegro_channel_buf_done(channel, dst_buf, state);
+       if (src_buf)
+               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
 
-       v4l2_m2m_job_finish(dev->m2m_dev, channel->fh.m2m_ctx);
+       if (dst_buf)
+               allegro_channel_buf_done(channel, dst_buf, state);
 }
 
 static int allegro_handle_init(struct allegro_dev *dev,
@@ -1621,6 +1562,12 @@ allegro_handle_create_channel(struct allegro_dev *dev,
        struct allegro_channel *channel;
        int err = 0;
 
+       if (msg->header.length != sizeof(*msg) - sizeof(msg->header))
+               v4l2_warn(&dev->v4l2_dev,
+                         "received message has %d bytes, but expected %zu\n",
+                         msg->header.length,
+                         sizeof(*msg) - sizeof(msg->header));
+
        channel = allegro_find_channel_by_user_id(dev, msg->user_id);
        if (IS_ERR(channel)) {
                v4l2_warn(&dev->v4l2_dev,
@@ -1632,8 +1579,10 @@ allegro_handle_create_channel(struct allegro_dev *dev,
 
        if (msg->error_code) {
                v4l2_err(&dev->v4l2_dev,
-                        "user %d: mcu failed to create channel: error %x\n",
-                        channel->user_id, msg->error_code);
+                        "user %d: mcu failed to create channel: %s (%x)\n",
+                        channel->user_id,
+                        allegro_err_to_string(msg->error_code),
+                        msg->error_code);
                err = -EIO;
                goto out;
        }
@@ -1712,6 +1661,12 @@ allegro_handle_encode_frame(struct allegro_dev *dev,
 {
        struct allegro_channel *channel;
 
+       if (msg->header.length != sizeof(*msg) - sizeof(msg->header))
+               v4l2_warn(&dev->v4l2_dev,
+                         "received message has %d bytes, but expected %zu\n",
+                         msg->header.length,
+                         sizeof(*msg) - sizeof(msg->header));
+
        channel = allegro_find_channel_by_channel_id(dev, msg->channel_id);
        if (IS_ERR(channel)) {
                v4l2_err(&dev->v4l2_dev,
@@ -1920,6 +1875,14 @@ static int allegro_mcu_reset(struct allegro_dev *dev)
 {
        int err;
 
+       /*
+        * Ensure that the AL5_MCU_WAKEUP bit is set to 0 otherwise the mcu
+        * does not go to sleep after the reset.
+        */
+       err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, 0);
+       if (err)
+               return err;
+
        err = regmap_write(dev->regmap,
                           AL5_MCU_RESET_MODE, AL5_MCU_RESET_MODE_SLEEP);
        if (err < 0)
@@ -1955,6 +1918,12 @@ static void allegro_destroy_channel(struct allegro_channel *channel)
 
        v4l2_ctrl_grab(channel->mpeg_video_h264_profile, false);
        v4l2_ctrl_grab(channel->mpeg_video_h264_level, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_i_frame_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_max_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, false);
+       v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, false);
        v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, false);
        v4l2_ctrl_grab(channel->mpeg_video_bitrate, false);
        v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, false);
@@ -2000,7 +1969,9 @@ static int allegro_create_channel(struct allegro_channel *channel)
        v4l2_dbg(1, debug, &dev->v4l2_dev,
                 "user %d: creating channel (%4.4s, %dx%d@%d)\n",
                 channel->user_id,
-                (char *)&channel->codec, channel->width, channel->height, 25);
+                (char *)&channel->codec, channel->width, channel->height,
+                DIV_ROUND_UP(channel->framerate.numerator,
+                             channel->framerate.denominator));
 
        min_level = select_minimum_h264_level(channel->width, channel->height);
        if (channel->level < min_level) {
@@ -2014,6 +1985,12 @@ static int allegro_create_channel(struct allegro_channel *channel)
 
        v4l2_ctrl_grab(channel->mpeg_video_h264_profile, true);
        v4l2_ctrl_grab(channel->mpeg_video_h264_level, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_i_frame_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_max_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, true);
+       v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, true);
        v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, true);
        v4l2_ctrl_grab(channel->mpeg_video_bitrate, true);
        v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, true);
@@ -2046,6 +2023,7 @@ static void allegro_set_default_params(struct allegro_channel *channel)
        channel->width = ALLEGRO_WIDTH_DEFAULT;
        channel->height = ALLEGRO_HEIGHT_DEFAULT;
        channel->stride = round_up(channel->width, 32);
+       channel->framerate = ALLEGRO_FRAMERATE_DEFAULT;
 
        channel->colorspace = V4L2_COLORSPACE_REC709;
        channel->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
@@ -2062,7 +2040,6 @@ static void allegro_set_default_params(struct allegro_channel *channel)
        channel->sizeimage_encoded =
                estimate_stream_size(channel->width, channel->height);
 
-       channel->bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
        channel->bitrate = maximum_bitrate(channel->level);
        channel->bitrate_peak = maximum_bitrate(channel->level);
        channel->cpb_size = maximum_cpb_size(channel->level);
@@ -2163,16 +2140,33 @@ static void allegro_stop_streaming(struct vb2_queue *q)
        struct allegro_channel *channel = vb2_get_drv_priv(q);
        struct allegro_dev *dev = channel->dev;
        struct vb2_v4l2_buffer *buffer;
+       struct allegro_m2m_buffer *shadow, *tmp;
 
        v4l2_dbg(2, debug, &dev->v4l2_dev,
                 "%s: stop streaming\n",
                 V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture");
 
        if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+               mutex_lock(&channel->shadow_list_lock);
+               list_for_each_entry_safe(shadow, tmp,
+                                        &channel->source_shadow_list, head) {
+                       list_del(&shadow->head);
+                       v4l2_m2m_buf_done(&shadow->buf.vb, VB2_BUF_STATE_ERROR);
+               }
+               mutex_unlock(&channel->shadow_list_lock);
+
                allegro_set_state(channel, ALLEGRO_STATE_STOPPED);
                while ((buffer = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx)))
                        v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR);
        } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               mutex_lock(&channel->shadow_list_lock);
+               list_for_each_entry_safe(shadow, tmp,
+                                        &channel->stream_shadow_list, head) {
+                       list_del(&shadow->head);
+                       v4l2_m2m_buf_done(&shadow->buf.vb, VB2_BUF_STATE_ERROR);
+               }
+               mutex_unlock(&channel->shadow_list_lock);
+
                allegro_destroy_channel(channel);
                while ((buffer = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx)))
                        v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR);
@@ -2203,7 +2197,7 @@ static int allegro_queue_init(void *priv,
        src_vq->drv_priv = channel;
        src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
        src_vq->ops = &allegro_queue_ops;
-       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       src_vq->buf_struct_size = sizeof(struct allegro_m2m_buffer);
        src_vq->lock = &channel->dev->lock;
        err = vb2_queue_init(src_vq);
        if (err)
@@ -2216,7 +2210,7 @@ static int allegro_queue_init(void *priv,
        dst_vq->drv_priv = channel;
        dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
        dst_vq->ops = &allegro_queue_ops;
-       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->buf_struct_size = sizeof(struct allegro_m2m_buffer);
        dst_vq->lock = &channel->dev->lock;
        err = vb2_queue_init(dst_vq);
        if (err)
@@ -2225,6 +2219,52 @@ static int allegro_queue_init(void *priv,
        return 0;
 }
 
+static int allegro_clamp_qp(struct allegro_channel *channel,
+                           struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_ctrl *next_ctrl;
+
+       if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP)
+               next_ctrl = channel->mpeg_video_h264_p_frame_qp;
+       else if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP)
+               next_ctrl = channel->mpeg_video_h264_b_frame_qp;
+       else
+               return 0;
+
+       /* Modify range automatically updates the value */
+       __v4l2_ctrl_modify_range(next_ctrl, ctrl->val, 51, 1, ctrl->val);
+
+       return allegro_clamp_qp(channel, next_ctrl);
+}
+
+static int allegro_clamp_bitrate(struct allegro_channel *channel,
+                                struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_ctrl *ctrl_bitrate = channel->mpeg_video_bitrate;
+       struct v4l2_ctrl *ctrl_bitrate_peak = channel->mpeg_video_bitrate_peak;
+
+       if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+           ctrl_bitrate_peak->val < ctrl_bitrate->val)
+               ctrl_bitrate_peak->val = ctrl_bitrate->val;
+
+       return 0;
+}
+
+static int allegro_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct allegro_channel *channel = container_of(ctrl->handler,
+                                                      struct allegro_channel,
+                                                      ctrl_handler);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               allegro_clamp_bitrate(channel, ctrl);
+               break;
+       }
+
+       return 0;
+}
+
 static int allegro_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct allegro_channel *channel = container_of(ctrl->handler,
@@ -2239,14 +2279,14 @@ static int allegro_s_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
                channel->level = ctrl->val;
                break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
-               channel->bitrate_mode = ctrl->val;
+       case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
+               channel->frame_rc_enable = ctrl->val;
                break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE:
-               channel->bitrate = ctrl->val;
-               break;
-       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
-               channel->bitrate_peak = ctrl->val;
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+               channel->bitrate = channel->mpeg_video_bitrate->val;
+               channel->bitrate_peak = channel->mpeg_video_bitrate_peak->val;
+               v4l2_ctrl_activate(channel->mpeg_video_bitrate_peak,
+                                  ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
                break;
        case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
                channel->cpb_size = ctrl->val;
@@ -2254,12 +2294,18 @@ static int allegro_s_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
                channel->gop_size = ctrl->val;
                break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+       case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
+               allegro_clamp_qp(channel, ctrl);
+               break;
        }
 
        return 0;
 }
 
 static const struct v4l2_ctrl_ops allegro_ctrl_ops = {
+       .try_ctrl = allegro_try_ctrl,
        .s_ctrl = allegro_s_ctrl,
 };
 
@@ -2270,16 +2316,18 @@ static int allegro_open(struct file *file)
        struct allegro_channel *channel = NULL;
        struct v4l2_ctrl_handler *handler;
        u64 mask;
+       int ret;
 
        channel = kzalloc(sizeof(*channel), GFP_KERNEL);
        if (!channel)
                return -ENOMEM;
 
        v4l2_fh_init(&channel->fh, vdev);
-       file->private_data = &channel->fh;
-       v4l2_fh_add(&channel->fh);
 
        init_completion(&channel->completion);
+       INIT_LIST_HEAD(&channel->source_shadow_list);
+       INIT_LIST_HEAD(&channel->stream_shadow_list);
+       mutex_init(&channel->shadow_list_lock);
 
        channel->dev = dev;
 
@@ -2298,11 +2346,42 @@ static int allegro_open(struct file *file)
                        V4L2_CID_MPEG_VIDEO_H264_LEVEL,
                        V4L2_MPEG_VIDEO_H264_LEVEL_5_1, mask,
                        V4L2_MPEG_VIDEO_H264_LEVEL_5_1);
+       channel->mpeg_video_h264_i_frame_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
+                                 0, 51, 1, 30);
+       channel->mpeg_video_h264_max_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
+                                 0, 51, 1, 51);
+       channel->mpeg_video_h264_min_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
+                                 0, 51, 1, 0);
+       channel->mpeg_video_h264_p_frame_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
+                                 0, 51, 1, 30);
+       channel->mpeg_video_h264_b_frame_qp =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
+                                 0, 51, 1, 30);
+       channel->mpeg_video_frame_rc_enable =
+               v4l2_ctrl_new_std(handler,
+                                 &allegro_ctrl_ops,
+                                 V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
+                                 false, 0x1,
+                                 true, false);
        channel->mpeg_video_bitrate_mode = v4l2_ctrl_new_std_menu(handler,
                        &allegro_ctrl_ops,
                        V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
                        V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
-                       channel->bitrate_mode);
+                       V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
        channel->mpeg_video_bitrate = v4l2_ctrl_new_std(handler,
                        &allegro_ctrl_ops,
                        V4L2_CID_MPEG_VIDEO_BITRATE,
@@ -2324,12 +2403,19 @@ static int allegro_open(struct file *file)
                        0, ALLEGRO_GOP_SIZE_MAX,
                        1, channel->gop_size);
        v4l2_ctrl_new_std(handler,
-                       &allegro_ctrl_ops,
-                       V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
-                       1, 32,
-                       1, 1);
+                         &allegro_ctrl_ops,
+                         V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+                         1, 32,
+                         1, 1);
+       if (handler->error != 0) {
+               ret = handler->error;
+               goto error;
+       }
+
        channel->fh.ctrl_handler = handler;
 
+       v4l2_ctrl_cluster(3, &channel->mpeg_video_bitrate_mode);
+
        channel->mcu_channel_id = -1;
        channel->user_id = -1;
 
@@ -2341,7 +2427,20 @@ static int allegro_open(struct file *file)
        channel->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, channel,
                                                allegro_queue_init);
 
+       if (IS_ERR(channel->fh.m2m_ctx)) {
+               ret = PTR_ERR(channel->fh.m2m_ctx);
+               goto error;
+       }
+
+       file->private_data = &channel->fh;
+       v4l2_fh_add(&channel->fh);
+
        return 0;
+
+error:
+       v4l2_ctrl_handler_free(handler);
+       kfree(channel);
+       return ret;
 }
 
 static int allegro_release(struct file *file)
@@ -2636,6 +2735,46 @@ static int allegro_ioctl_streamon(struct file *file, void *priv,
        return v4l2_m2m_streamon(file, fh->m2m_ctx, type);
 }
 
+static int allegro_g_parm(struct file *file, void *fh,
+                         struct v4l2_streamparm *a)
+{
+       struct allegro_channel *channel = fh_to_channel(fh);
+       struct v4l2_fract *timeperframe;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       timeperframe = &a->parm.output.timeperframe;
+       timeperframe->numerator = channel->framerate.denominator;
+       timeperframe->denominator = channel->framerate.numerator;
+
+       return 0;
+}
+
+static int allegro_s_parm(struct file *file, void *fh,
+                         struct v4l2_streamparm *a)
+{
+       struct allegro_channel *channel = fh_to_channel(fh);
+       struct v4l2_fract *timeperframe;
+       int div;
+
+       if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               return -EINVAL;
+
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       timeperframe = &a->parm.output.timeperframe;
+
+       if (timeperframe->numerator == 0 || timeperframe->denominator == 0)
+               return allegro_g_parm(file, fh, a);
+
+       div = gcd(timeperframe->denominator, timeperframe->numerator);
+       channel->framerate.numerator = timeperframe->denominator / div;
+       channel->framerate.denominator = timeperframe->numerator / div;
+
+       return 0;
+}
+
 static int allegro_subscribe_event(struct v4l2_fh *fh,
                                   const struct v4l2_event_subscription *sub)
 {
@@ -2674,6 +2813,9 @@ static const struct v4l2_ioctl_ops allegro_ioctl_ops = {
        .vidioc_encoder_cmd = allegro_encoder_cmd,
        .vidioc_enum_framesizes = allegro_enum_framesizes,
 
+       .vidioc_g_parm          = allegro_g_parm,
+       .vidioc_s_parm          = allegro_s_parm,
+
        .vidioc_subscribe_event = allegro_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
@@ -2701,7 +2843,7 @@ static int allegro_register_device(struct allegro_dev *dev)
        video_dev->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
        video_set_drvdata(video_dev, dev);
 
-       return video_register_device(video_dev, VFL_TYPE_GRABBER, 0);
+       return video_register_device(video_dev, VFL_TYPE_VIDEO, 0);
 }
 
 static void allegro_device_run(void *priv)
@@ -2714,18 +2856,26 @@ static void allegro_device_run(void *priv)
        dma_addr_t src_uv;
        dma_addr_t dst_addr;
        unsigned long dst_size;
+       u64 src_handle;
+       u64 dst_handle;
 
-       dst_buf = v4l2_m2m_next_dst_buf(channel->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx);
        dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
        dst_size = vb2_plane_size(&dst_buf->vb2_buf, 0);
-       allegro_mcu_send_put_stream_buffer(dev, channel, dst_addr, dst_size);
+       dst_handle = allegro_put_buffer(channel, &channel->stream_shadow_list,
+                                       dst_buf);
+       allegro_mcu_send_put_stream_buffer(dev, channel, dst_addr, dst_size,
+                                          dst_handle);
 
-       src_buf = v4l2_m2m_next_src_buf(channel->fh.m2m_ctx);
+       src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx);
        src_buf->sequence = channel->osequence++;
-
        src_y = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
        src_uv = src_y + (channel->stride * channel->height);
-       allegro_mcu_send_encode_frame(dev, channel, src_y, src_uv);
+       src_handle = allegro_put_buffer(channel, &channel->source_shadow_list,
+                                       src_buf);
+       allegro_mcu_send_encode_frame(dev, channel, src_y, src_uv, src_handle);
+
+       v4l2_m2m_job_finish(dev->m2m_dev, channel->fh.m2m_ctx);
 }
 
 static const struct v4l2_m2m_ops allegro_m2m_ops = {
@@ -2933,8 +3083,8 @@ static int allegro_probe(struct platform_device *pdev)
                return -EINVAL;
        }
        sram_regs = devm_ioremap(&pdev->dev,
-                                        sram_res->start,
-                                        resource_size(sram_res));
+                                sram_res->start,
+                                resource_size(sram_res));
        if (IS_ERR(sram_regs)) {
                dev_err(&pdev->dev, "failed to map sram\n");
                return PTR_ERR(sram_regs);
diff --git a/drivers/staging/media/allegro-dvt/allegro-mail.c b/drivers/staging/media/allegro-dvt/allegro-mail.c
new file mode 100644 (file)
index 0000000..df0d8d2
--- /dev/null
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Helper functions for handling messages that are send via mailbox to the
+ * Allegro VCU firmware.
+ */
+
+#include <linux/export.h>
+
+#include "allegro-mail.h"
+
+const char *msg_type_name(enum mcu_msg_type type)
+{
+       static char buf[9];
+
+       switch (type) {
+       case MCU_MSG_TYPE_INIT:
+               return "INIT";
+       case MCU_MSG_TYPE_CREATE_CHANNEL:
+               return "CREATE_CHANNEL";
+       case MCU_MSG_TYPE_DESTROY_CHANNEL:
+               return "DESTROY_CHANNEL";
+       case MCU_MSG_TYPE_ENCODE_FRAME:
+               return "ENCODE_FRAME";
+       case MCU_MSG_TYPE_PUT_STREAM_BUFFER:
+               return "PUT_STREAM_BUFFER";
+       case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE:
+               return "PUSH_BUFFER_INTERMEDIATE";
+       case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE:
+               return "PUSH_BUFFER_REFERENCE";
+       default:
+               snprintf(buf, sizeof(buf), "(0x%04x)", type);
+               return buf;
+       }
+}
+EXPORT_SYMBOL(msg_type_name);
diff --git a/drivers/staging/media/allegro-dvt/allegro-mail.h b/drivers/staging/media/allegro-dvt/allegro-mail.h
new file mode 100644 (file)
index 0000000..17db665
--- /dev/null
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de>
+ *
+ * Allegro VCU firmware mailbox mail definitions
+ */
+
+#ifndef ALLEGRO_MAIL_H
+#define ALLEGRO_MAIL_H
+
+#include <linux/kernel.h>
+
+enum mcu_msg_type {
+       MCU_MSG_TYPE_INIT = 0x0000,
+       MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005,
+       MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006,
+       MCU_MSG_TYPE_ENCODE_FRAME = 0x0007,
+       MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012,
+       MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e,
+       MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f,
+};
+
+const char *msg_type_name(enum mcu_msg_type type);
+
+struct mcu_msg_header {
+       u16 length;             /* length of the body in bytes */
+       u16 type;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_init_request {
+       struct mcu_msg_header header;
+       u32 reserved0;          /* maybe a unused channel id */
+       u32 suballoc_dma;
+       u32 suballoc_size;
+       s32 l2_cache[3];
+} __attribute__ ((__packed__));
+
+struct mcu_msg_init_response {
+       struct mcu_msg_header header;
+       u32 reserved0;
+} __attribute__ ((__packed__));
+
+struct create_channel_param {
+       u16 width;
+       u16 height;
+       u32 format;
+       u32 colorspace;
+       u32 src_mode;
+       u8 profile;
+       u16 constraint_set_flags;
+       s8 codec;
+       u16 level;
+       u16 tier;
+       u32 sps_param;
+       u32 pps_param;
+
+       u32 enc_option;
+#define AL_OPT_WPP                     BIT(0)
+#define AL_OPT_TILE                    BIT(1)
+#define AL_OPT_LF                      BIT(2)
+#define AL_OPT_LF_X_SLICE              BIT(3)
+#define AL_OPT_LF_X_TILE               BIT(4)
+#define AL_OPT_SCL_LST                 BIT(5)
+#define AL_OPT_CONST_INTRA_PRED                BIT(6)
+#define AL_OPT_QP_TAB_RELATIVE         BIT(7)
+#define AL_OPT_FIX_PREDICTOR           BIT(8)
+#define AL_OPT_CUSTOM_LDA              BIT(9)
+#define AL_OPT_ENABLE_AUTO_QP          BIT(10)
+#define AL_OPT_ADAPT_AUTO_QP           BIT(11)
+#define AL_OPT_TRANSFO_SKIP            BIT(13)
+#define AL_OPT_FORCE_REC               BIT(15)
+#define AL_OPT_FORCE_MV_OUT            BIT(16)
+#define AL_OPT_FORCE_MV_CLIP           BIT(17)
+#define AL_OPT_LOWLAT_SYNC             BIT(18)
+#define AL_OPT_LOWLAT_INT              BIT(19)
+#define AL_OPT_RDO_COST_MODE           BIT(20)
+
+       s8 beta_offset;
+       s8 tc_offset;
+       u16 reserved10;
+       u32 unknown11;
+       u32 unknown12;
+       u16 num_slices;
+       u16 prefetch_auto;
+       u32 prefetch_mem_offset;
+       u32 prefetch_mem_size;
+       u16 clip_hrz_range;
+       u16 clip_vrt_range;
+       u16 me_range[4];
+       u8 max_cu_size;
+       u8 min_cu_size;
+       u8 max_tu_size;
+       u8 min_tu_size;
+       u8 max_transfo_depth_inter;
+       u8 max_transfo_depth_intra;
+       u16 reserved20;
+       u32 entropy_mode;
+       u32 wp_mode;
+
+       /* rate control param */
+       u32 rate_control_mode;
+       u32 initial_rem_delay;
+       u32 cpb_size;
+       u16 framerate;
+       u16 clk_ratio;
+       u32 target_bitrate;
+       u32 max_bitrate;
+       u16 initial_qp;
+       u16 min_qp;
+       u16 max_qp;
+       s16 ip_delta;
+       s16 pb_delta;
+       u16 golden_ref;
+       u16 golden_delta;
+       u16 golden_ref_frequency;
+       u32 rate_control_option;
+
+       /* gop param */
+       u32 gop_ctrl_mode;
+       u32 freq_idr;
+       u32 freq_lt;
+       u32 gdr_mode;
+       u16 gop_length;
+       u8 num_b;
+       u8 freq_golden_ref;
+
+       u32 subframe_latency;
+       u32 lda_control_mode;
+       u32 unknown41;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_create_channel {
+       struct mcu_msg_header header;
+       u32 user_id;
+       struct create_channel_param param;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_create_channel_response {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       u32 user_id;
+       u32 options;
+       u32 num_core;
+       u32 pps_param;
+       u32 int_buffers_count;
+       u32 int_buffers_size;
+       u32 rec_buffers_count;
+       u32 rec_buffers_size;
+       u32 reserved;
+       u32 error_code;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_destroy_channel {
+       struct mcu_msg_header header;
+       u32 channel_id;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_destroy_channel_response {
+       struct mcu_msg_header header;
+       u32 channel_id;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_push_buffers_internal_buffer {
+       u32 dma_addr;
+       u32 mcu_addr;
+       u32 size;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_push_buffers_internal {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       struct mcu_msg_push_buffers_internal_buffer buffer[];
+} __attribute__ ((__packed__));
+
+struct mcu_msg_put_stream_buffer {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       u32 dma_addr;
+       u32 mcu_addr;
+       u32 size;
+       u32 offset;
+       u64 stream_id;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_encode_frame {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       u32 reserved;
+
+       u32 encoding_options;
+#define AL_OPT_USE_QP_TABLE            BIT(0)
+#define AL_OPT_FORCE_LOAD              BIT(1)
+#define AL_OPT_USE_L2                  BIT(2)
+#define AL_OPT_DISABLE_INTRA           BIT(3)
+#define AL_OPT_DEPENDENT_SLICES                BIT(4)
+
+       s16 pps_qp;
+       u16 padding;
+       u64 user_param;
+       u64 src_handle;
+
+       u32 request_options;
+#define AL_OPT_SCENE_CHANGE            BIT(0)
+#define AL_OPT_RESTART_GOP             BIT(1)
+#define AL_OPT_USE_LONG_TERM           BIT(2)
+#define AL_OPT_UPDATE_PARAMS           BIT(3)
+
+       /* u32 scene_change_delay (optional) */
+       /* rate control param (optional) */
+       /* gop param (optional) */
+       u32 src_y;
+       u32 src_uv;
+       u32 stride;
+       u32 ep2;
+       u64 ep2_v;
+} __attribute__ ((__packed__));
+
+struct mcu_msg_encode_frame_response {
+       struct mcu_msg_header header;
+       u32 channel_id;
+       u64 stream_id;          /* see mcu_msg_put_stream_buffer */
+       u64 user_param;         /* see mcu_msg_encode_frame */
+       u64 src_handle;         /* see mcu_msg_encode_frame */
+       u16 skip;
+       u16 is_ref;
+       u32 initial_removal_delay;
+       u32 dpb_output_delay;
+       u32 size;
+       u32 frame_tag_size;
+       s32 stuffing;
+       s32 filler;
+       u16 num_column;
+       u16 num_row;
+       u16 qp;
+       u8 num_ref_idx_l0;
+       u8 num_ref_idx_l1;
+       u32 partition_table_offset;
+       s32 partition_table_size;
+       u32 sum_complex;
+       s32 tile_width[4];
+       s32 tile_height[22];
+       u32 error_code;
+
+       u32 slice_type;
+#define AL_ENC_SLICE_TYPE_B             0
+#define AL_ENC_SLICE_TYPE_P             1
+#define AL_ENC_SLICE_TYPE_I             2
+
+       u32 pic_struct;
+       u8 is_idr;
+       u8 is_first_slice;
+       u8 is_last_slice;
+       u8 reserved;
+       u16 pps_qp;
+       u16 reserved1;
+       u32 reserved2;
+} __attribute__ ((__packed__));
+
+union mcu_msg_response {
+       struct mcu_msg_header header;
+       struct mcu_msg_init_response init;
+       struct mcu_msg_create_channel_response create_channel;
+       struct mcu_msg_destroy_channel_response destroy_channel;
+       struct mcu_msg_encode_frame_response encode_frame;
+};
+
+#endif
index de77fe6..99aed9a 100644 (file)
@@ -1,19 +1,27 @@
 # SPDX-License-Identifier: GPL-2.0
 config VIDEO_HANTRO
        tristate "Hantro VPU driver"
-       depends on ARCH_ROCKCHIP || COMPILE_TEST
+       depends on ARCH_MXC || ARCH_ROCKCHIP || COMPILE_TEST
        depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
        depends on MEDIA_CONTROLLER_REQUEST_API
        select VIDEOBUF2_DMA_CONTIG
        select VIDEOBUF2_VMALLOC
        select V4L2_MEM2MEM_DEV
        help
-         Support for the Hantro IP based Video Processing Unit present on
-         Rockchip SoC, which accelerates video and image encoding and
-         decoding.
+         Support for the Hantro IP based Video Processing Units present on
+         Rockchip and NXP i.MX8M SoCs, which accelerate video and image
+         encoding and decoding.
          To compile this driver as a module, choose M here: the module
          will be called hantro-vpu.
 
+config VIDEO_HANTRO_IMX8M
+       bool "Hantro VPU i.MX8M support"
+       depends on VIDEO_HANTRO
+       depends on ARCH_MXC || COMPILE_TEST
+       default y
+       help
+         Enable support for i.MX8M SoCs.
+
 config VIDEO_HANTRO_ROCKCHIP
        bool "Hantro VPU Rockchip support"
        depends on VIDEO_HANTRO
index 496b30c..68c29a9 100644 (file)
@@ -16,6 +16,9 @@ hantro-vpu-y += \
                hantro_mpeg2.o \
                hantro_vp8.o
 
+hantro-vpu-$(CONFIG_VIDEO_HANTRO_IMX8M) += \
+               imx8m_vpu_hw.o
+
 hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \
                rk3288_vpu_hw.o \
                rk3399_vpu_hw.o
index b0faa43..327ddef 100644 (file)
@@ -423,7 +423,7 @@ hantro_get_dst_buf(struct hantro_ctx *ctx)
 static inline bool
 hantro_needs_postproc(struct hantro_ctx *ctx, const struct hantro_fmt *fmt)
 {
-       return fmt->fourcc != V4L2_PIX_FMT_NV12;
+       return !hantro_is_encoder_ctx(ctx) && fmt->fourcc != V4L2_PIX_FMT_NV12;
 }
 
 static inline dma_addr_t
index 97c615a..ace1397 100644 (file)
@@ -362,6 +362,16 @@ static const struct hantro_ctrl controls[] = {
                        .max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B,
                },
        }, {
+               .codec = HANTRO_H264_DECODER,
+               .cfg = {
+                       .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+                       .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
+                       .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+                       .menu_skip_mask =
+                       BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED),
+                       .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN,
+               }
+       }, {
        },
 };
 
@@ -489,6 +499,9 @@ static const struct of_device_id of_hantro_match[] = {
        { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, },
        { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
 #endif
+#ifdef CONFIG_VIDEO_HANTRO_IMX8M
+       { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, },
+#endif
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, of_hantro_match);
@@ -558,13 +571,13 @@ static int hantro_attach_func(struct hantro_dev *vpu,
                goto err_rel_entity1;
 
        /* Connect the three entities */
-       ret = media_create_pad_link(&func->vdev.entity, 0, &func->proc, 1,
+       ret = media_create_pad_link(&func->vdev.entity, 0, &func->proc, 0,
                                    MEDIA_LNK_FL_IMMUTABLE |
                                    MEDIA_LNK_FL_ENABLED);
        if (ret)
                goto err_rel_entity2;
 
-       ret = media_create_pad_link(&func->proc, 0, &func->sink, 0,
+       ret = media_create_pad_link(&func->proc, 1, &func->sink, 0,
                                    MEDIA_LNK_FL_IMMUTABLE |
                                    MEDIA_LNK_FL_ENABLED);
        if (ret)
@@ -664,7 +677,7 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid)
 
        video_set_drvdata(vfd, vpu);
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n");
                return ret;
index 0d8afc3..b224184 100644 (file)
@@ -67,12 +67,23 @@ hantro_h1_jpeg_enc_set_qtable(struct hantro_dev *vpu,
                              unsigned char *chroma_qtable)
 {
        u32 reg, i;
+       __be32 *luma_qtable_p;
+       __be32 *chroma_qtable_p;
 
+       luma_qtable_p = (__be32 *)luma_qtable;
+       chroma_qtable_p = (__be32 *)chroma_qtable;
+
+       /*
+        * Quantization table registers must be written in contiguous blocks.
+        * DO NOT collapse the below two "for" loops into one.
+        */
        for (i = 0; i < H1_JPEG_QUANT_TABLE_COUNT; i++) {
-               reg = get_unaligned_be32(&luma_qtable[i]);
+               reg = get_unaligned_be32(&luma_qtable_p[i]);
                vepu_write_relaxed(vpu, reg, H1_REG_JPEG_LUMA_QUAT(i));
+       }
 
-               reg = get_unaligned_be32(&chroma_qtable[i]);
+       for (i = 0; i < H1_JPEG_QUANT_TABLE_COUNT; i++) {
+               reg = get_unaligned_be32(&chroma_qtable_p[i]);
                vepu_write_relaxed(vpu, reg, H1_REG_JPEG_CHROMA_QUAT(i));
        }
 }
@@ -103,8 +114,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx)
        hantro_h1_set_src_img_ctrl(vpu, ctx);
        hantro_h1_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf);
        hantro_h1_jpeg_enc_set_qtable(vpu,
-                                     hantro_jpeg_get_qtable(&jpeg_ctx, 0),
-                                     hantro_jpeg_get_qtable(&jpeg_ctx, 1));
+                                     hantro_jpeg_get_qtable(0),
+                                     hantro_jpeg_get_qtable(1));
 
        reg = H1_REG_AXI_CTRL_OUTPUT_SWAP16
                | H1_REG_AXI_CTRL_INPUT_SWAP16
index 2398d4c..7dfc9ba 100644 (file)
@@ -151,6 +151,7 @@ enum hantro_enc_fmt {
 extern const struct hantro_variant rk3399_vpu_variant;
 extern const struct hantro_variant rk3328_vpu_variant;
 extern const struct hantro_variant rk3288_vpu_variant;
+extern const struct hantro_variant imx8mq_vpu_variant;
 
 extern const struct hantro_postproc_regs hantro_g1_postproc_regs;
 
index 125eb41..36c140f 100644 (file)
 #define HUFF_CHROMA_AC_OFF     409
 
 /* Default tables from JPEG ITU-T.81
- * (ISO/IEC 10918-1) Annex K.3, I
+ * (ISO/IEC 10918-1) Annex K, tables K.1 and K.2
  */
 static const unsigned char luma_q_table[] = {
-       0x10, 0x0b, 0x0a, 0x10, 0x7c, 0x8c, 0x97, 0xa1,
-       0x0c, 0x0c, 0x0e, 0x13, 0x7e, 0x9e, 0xa0, 0x9b,
-       0x0e, 0x0d, 0x10, 0x18, 0x8c, 0x9d, 0xa9, 0x9c,
-       0x0e, 0x11, 0x16, 0x1d, 0x97, 0xbb, 0xb4, 0xa2,
-       0x12, 0x16, 0x25, 0x38, 0xa8, 0x6d, 0x67, 0xb1,
-       0x18, 0x23, 0x37, 0x40, 0xb5, 0x68, 0x71, 0xc0,
+       0x10, 0x0b, 0x0a, 0x10, 0x18, 0x28, 0x33, 0x3d,
+       0x0c, 0x0c, 0x0e, 0x13, 0x1a, 0x3a, 0x3c, 0x37,
+       0x0e, 0x0d, 0x10, 0x18, 0x28, 0x39, 0x45, 0x38,
+       0x0e, 0x11, 0x16, 0x1d, 0x33, 0x57, 0x50, 0x3e,
+       0x12, 0x16, 0x25, 0x38, 0x44, 0x6d, 0x67, 0x4d,
+       0x18, 0x23, 0x37, 0x40, 0x51, 0x68, 0x71, 0x5c,
        0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65,
-       0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0xc7,
+       0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0x63
 };
 
+static unsigned char luma_q_table_reordered[ARRAY_SIZE(luma_q_table)];
+
 static const unsigned char chroma_q_table[] = {
        0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63,
        0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63,
@@ -47,6 +49,30 @@ static const unsigned char chroma_q_table[] = {
        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
 };
 
+static unsigned char chroma_q_table_reordered[ARRAY_SIZE(chroma_q_table)];
+
+static const unsigned char zigzag[64] = {
+        0,  1,  8, 16,  9,  2,  3, 10,
+       17, 24, 32, 25, 18, 11,  4,  5,
+       12, 19, 26, 33, 40, 48, 41, 34,
+       27, 20, 13,  6,  7, 14, 21, 28,
+       35, 42, 49, 56, 57, 50, 43, 36,
+       29, 22, 15, 23, 30, 37, 44, 51,
+       58, 59, 52, 45, 38, 31, 39, 46,
+       53, 60, 61, 54, 47, 55, 62, 63
+};
+
+static const u32 hw_reorder[64] = {
+        0,  8, 16, 24,  1,  9, 17, 25,
+       32, 40, 48, 56, 33, 41, 49, 57,
+        2, 10, 18, 26,  3, 11, 19, 27,
+       34, 42, 50, 58, 35, 43, 51, 59,
+        4, 12, 20, 28,  5, 13, 21, 29,
+       36, 44, 52, 60, 37, 45, 53, 61,
+        6, 14, 22, 30,  7, 15, 23, 31,
+       38, 46, 54, 62, 39, 47, 55, 63
+};
+
 /* Huffman tables are shared with CODA */
 static const unsigned char luma_dc_table[] = {
        0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
@@ -225,20 +251,29 @@ static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = {
        0x11, 0x03, 0x11, 0x00, 0x3f, 0x00,
 };
 
+static unsigned char jpeg_scale_qp(const unsigned char qp, int scale)
+{
+       unsigned int temp;
+
+       temp = DIV_ROUND_CLOSEST((unsigned int)qp * scale, 100);
+       if (temp <= 0)
+               temp = 1;
+       if (temp > 255)
+               temp = 255;
+
+       return (unsigned char)temp;
+}
+
 static void
-jpeg_scale_quant_table(unsigned char *q_tab,
+jpeg_scale_quant_table(unsigned char *file_q_tab,
+                      unsigned char *reordered_q_tab,
                       const unsigned char *tab, int scale)
 {
-       unsigned int temp;
        int i;
 
        for (i = 0; i < 64; i++) {
-               temp = DIV_ROUND_CLOSEST((unsigned int)tab[i] * scale, 100);
-               if (temp <= 0)
-                       temp = 1;
-               if (temp > 255)
-                       temp = 255;
-               q_tab[i] = (unsigned char)temp;
+               file_q_tab[i] = jpeg_scale_qp(tab[zigzag[i]], scale);
+               reordered_q_tab[i] = jpeg_scale_qp(tab[hw_reorder[i]], scale);
        }
 }
 
@@ -256,17 +291,18 @@ static void jpeg_set_quality(unsigned char *buffer, int quality)
                scale = 200 - 2 * quality;
 
        jpeg_scale_quant_table(buffer + LUMA_QUANT_OFF,
+                              luma_q_table_reordered,
                               luma_q_table, scale);
        jpeg_scale_quant_table(buffer + CHROMA_QUANT_OFF,
+                              chroma_q_table_reordered,
                               chroma_q_table, scale);
 }
 
-unsigned char *
-hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index)
+unsigned char *hantro_jpeg_get_qtable(int index)
 {
        if (index == 0)
-               return ctx->buffer + LUMA_QUANT_OFF;
-       return ctx->buffer + CHROMA_QUANT_OFF;
+               return luma_q_table_reordered;
+       return chroma_q_table_reordered;
 }
 
 void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
index 9e8397c..9474a00 100644 (file)
@@ -9,5 +9,5 @@ struct hantro_jpeg_ctx {
        unsigned char *buffer;
 };
 
-unsigned char *hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index);
+unsigned char *hantro_jpeg_get_qtable(int index);
 void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx);
index 28a85d3..44062ff 100644 (file)
 
 #define HANTRO_PP_REG_WRITE(vpu, reg_name, val) \
 { \
-       hantro_reg_write((vpu), \
-                        &((vpu)->variant->postproc_regs->reg_name), \
-                        (val)); \
+       hantro_reg_write(vpu, \
+                        &(vpu)->variant->postproc_regs->reg_name, \
+                        val); \
 }
 
 #define HANTRO_PP_REG_WRITE_S(vpu, reg_name, val) \
 { \
-       hantro_reg_write_s((vpu), \
-                          &((vpu)->variant->postproc_regs->reg_name), \
-                          (val)); \
+       hantro_reg_write_s(vpu, \
+                          &(vpu)->variant->postproc_regs->reg_name, \
+                          val); \
 }
 
 #define VPU_PP_IN_YUYV                 0x0
index 0198bcd..f4ae2ce 100644 (file)
@@ -295,7 +295,7 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f,
                 * +---------------------------+
                 */
                if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE &&
-                   !hantro_needs_postproc(ctx, ctx->vpu_dst_fmt))
+                   !hantro_needs_postproc(ctx, fmt))
                        pix_mp->plane_fmt[0].sizeimage +=
                                64 * MB_WIDTH(pix_mp->width) *
                                     MB_WIDTH(pix_mp->height) + 32;
diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/staging/media/hantro/imx8m_vpu_hw.c
new file mode 100644 (file)
index 0000000..cb2420c
--- /dev/null
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Hantro VPU codec driver
+ *
+ * Copyright (C) 2019 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include "hantro.h"
+#include "hantro_jpeg.h"
+#include "hantro_g1_regs.h"
+
+#define CTRL_SOFT_RESET                0x00
+#define RESET_G1               BIT(1)
+#define RESET_G2               BIT(0)
+
+#define CTRL_CLOCK_ENABLE      0x04
+#define CLOCK_G1               BIT(1)
+#define CLOCK_G2               BIT(0)
+
+#define CTRL_G1_DEC_FUSE       0x08
+#define CTRL_G1_PP_FUSE                0x0c
+#define CTRL_G2_DEC_FUSE       0x10
+
+static void imx8m_soft_reset(struct hantro_dev *vpu, u32 reset_bits)
+{
+       u32 val;
+
+       /* Assert */
+       val = readl(vpu->ctrl_base + CTRL_SOFT_RESET);
+       val &= ~reset_bits;
+       writel(val, vpu->ctrl_base + CTRL_SOFT_RESET);
+
+       udelay(2);
+
+       /* Release */
+       val = readl(vpu->ctrl_base + CTRL_SOFT_RESET);
+       val |= reset_bits;
+       writel(val, vpu->ctrl_base + CTRL_SOFT_RESET);
+}
+
+static void imx8m_clk_enable(struct hantro_dev *vpu, u32 clock_bits)
+{
+       u32 val;
+
+       val = readl(vpu->ctrl_base + CTRL_CLOCK_ENABLE);
+       val |= clock_bits;
+       writel(val, vpu->ctrl_base + CTRL_CLOCK_ENABLE);
+}
+
+static int imx8mq_runtime_resume(struct hantro_dev *vpu)
+{
+       int ret;
+
+       ret = clk_bulk_prepare_enable(vpu->variant->num_clocks, vpu->clocks);
+       if (ret) {
+               dev_err(vpu->dev, "Failed to enable clocks\n");
+               return ret;
+       }
+
+       imx8m_soft_reset(vpu, RESET_G1 | RESET_G2);
+       imx8m_clk_enable(vpu, CLOCK_G1 | CLOCK_G2);
+
+       /* Set values of the fuse registers */
+       writel(0xffffffff, vpu->ctrl_base + CTRL_G1_DEC_FUSE);
+       writel(0xffffffff, vpu->ctrl_base + CTRL_G1_PP_FUSE);
+       writel(0xffffffff, vpu->ctrl_base + CTRL_G2_DEC_FUSE);
+
+       clk_bulk_disable_unprepare(vpu->variant->num_clocks, vpu->clocks);
+
+       return 0;
+}
+
+/*
+ * Supported formats.
+ */
+
+static const struct hantro_fmt imx8m_vpu_postproc_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+};
+
+static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .codec_mode = HANTRO_MODE_NONE,
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+               .codec_mode = HANTRO_MODE_MPEG2_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 1920,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 1088,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+               .codec_mode = HANTRO_MODE_VP8_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 3840,
+                       .step_width = 16,
+                       .min_height = 48,
+                       .max_height = 2160,
+                       .step_height = 16,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_H264_SLICE,
+               .codec_mode = HANTRO_MODE_H264_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = 48,
+                       .max_width = 3840,
+                       .step_width = MB_DIM,
+                       .min_height = 48,
+                       .max_height = 2160,
+                       .step_height = MB_DIM,
+               },
+       },
+};
+
+static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id)
+{
+       struct hantro_dev *vpu = dev_id;
+       enum vb2_buffer_state state;
+       u32 status;
+
+       status = vdpu_read(vpu, G1_REG_INTERRUPT);
+       state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ?
+                VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR;
+
+       vdpu_write(vpu, 0, G1_REG_INTERRUPT);
+       vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG);
+
+       hantro_irq_done(vpu, 0, state);
+
+       return IRQ_HANDLED;
+}
+
+static int imx8mq_vpu_hw_init(struct hantro_dev *vpu)
+{
+       vpu->dec_base = vpu->reg_bases[0];
+       vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1];
+
+       return 0;
+}
+
+static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx)
+{
+       struct hantro_dev *vpu = ctx->dev;
+
+       imx8m_soft_reset(vpu, RESET_G1);
+}
+
+/*
+ * Supported codec ops.
+ */
+
+static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = {
+       [HANTRO_MODE_MPEG2_DEC] = {
+               .run = hantro_g1_mpeg2_dec_run,
+               .reset = imx8m_vpu_g1_reset,
+               .init = hantro_mpeg2_dec_init,
+               .exit = hantro_mpeg2_dec_exit,
+       },
+       [HANTRO_MODE_VP8_DEC] = {
+               .run = hantro_g1_vp8_dec_run,
+               .reset = imx8m_vpu_g1_reset,
+               .init = hantro_vp8_dec_init,
+               .exit = hantro_vp8_dec_exit,
+       },
+       [HANTRO_MODE_H264_DEC] = {
+               .run = hantro_g1_h264_dec_run,
+               .reset = imx8m_vpu_g1_reset,
+               .init = hantro_h264_dec_init,
+               .exit = hantro_h264_dec_exit,
+       },
+};
+
+/*
+ * VPU variants.
+ */
+
+static const struct hantro_irq imx8mq_irqs[] = {
+       { "g1", imx8m_vpu_g1_irq },
+       { "g2", NULL /* TODO: imx8m_vpu_g2_irq */ },
+};
+
+static const char * const imx8mq_clk_names[] = { "g1", "g2", "bus" };
+static const char * const imx8mq_reg_names[] = { "g1", "g2", "ctrl" };
+
+const struct hantro_variant imx8mq_vpu_variant = {
+       .dec_fmts = imx8m_vpu_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts),
+       .postproc_fmts = imx8m_vpu_postproc_fmts,
+       .num_postproc_fmts = ARRAY_SIZE(imx8m_vpu_postproc_fmts),
+       .postproc_regs = &hantro_g1_postproc_regs,
+       .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER |
+                HANTRO_H264_DECODER,
+       .codec_ops = imx8mq_vpu_codec_ops,
+       .init = imx8mq_vpu_hw_init,
+       .runtime_resume = imx8mq_runtime_resume,
+       .irqs = imx8mq_irqs,
+       .num_irqs = ARRAY_SIZE(imx8mq_irqs),
+       .clk_names = imx8mq_clk_names,
+       .num_clocks = ARRAY_SIZE(imx8mq_clk_names),
+       .reg_names = imx8mq_reg_names,
+       .num_regs = ARRAY_SIZE(imx8mq_reg_names)
+};
index 4c2d43f..3498e61 100644 (file)
@@ -18,9 +18,8 @@
  *
  * Quantization luma table values are written to registers
  * VEPU_swreg_0-VEPU_swreg_15, and chroma table values to
- * VEPU_swreg_16-VEPU_swreg_31.
- *
- * JPEG zigzag order is expected on the quantization tables.
+ * VEPU_swreg_16-VEPU_swreg_31. A special order is needed, neither
+ * zigzag, nor linear.
  */
 
 #include <asm/unaligned.h>
@@ -98,12 +97,23 @@ rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu,
                               unsigned char *chroma_qtable)
 {
        u32 reg, i;
+       __be32 *luma_qtable_p;
+       __be32 *chroma_qtable_p;
+
+       luma_qtable_p = (__be32 *)luma_qtable;
+       chroma_qtable_p = (__be32 *)chroma_qtable;
 
+       /*
+        * Quantization table registers must be written in contiguous blocks.
+        * DO NOT collapse the below two "for" loops into one.
+        */
        for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) {
-               reg = get_unaligned_be32(&luma_qtable[i]);
+               reg = get_unaligned_be32(&luma_qtable_p[i]);
                vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i));
+       }
 
-               reg = get_unaligned_be32(&chroma_qtable[i]);
+       for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) {
+               reg = get_unaligned_be32(&chroma_qtable_p[i]);
                vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i));
        }
 }
@@ -134,8 +144,8 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx)
        rk3399_vpu_set_src_img_ctrl(vpu, ctx);
        rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf);
        rk3399_vpu_jpeg_enc_set_qtable(vpu,
-                                      hantro_jpeg_get_qtable(&jpeg_ctx, 0),
-                                      hantro_jpeg_get_qtable(&jpeg_ctx, 1));
+                                      hantro_jpeg_get_qtable(0),
+                                      hantro_jpeg_get_qtable(1));
 
        reg = VEPU_REG_OUTPUT_SWAP32
                | VEPU_REG_OUTPUT_SWAP16
index 7712e7b..d37b776 100644 (file)
@@ -643,7 +643,7 @@ static int capture_open(struct file *file)
        if (ret)
                v4l2_err(priv->src_sd, "v4l2_fh_open failed\n");
 
-       ret = v4l2_pipeline_pm_use(&vfd->entity, 1);
+       ret = v4l2_pipeline_pm_get(&vfd->entity);
        if (ret)
                v4l2_fh_release(file);
 
@@ -664,7 +664,7 @@ static int capture_release(struct file *file)
                vq->owner = NULL;
        }
 
-       v4l2_pipeline_pm_use(&vfd->entity, 0);
+       v4l2_pipeline_pm_put(&vfd->entity);
 
        v4l2_fh_release(file);
        mutex_unlock(&priv->mutex);
@@ -742,7 +742,7 @@ int imx_media_capture_device_register(struct imx_media_video_dev *vdev)
 
        vfd->v4l2_dev = v4l2_dev;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(sd, "Failed to register video device\n");
                return ret;
@@ -778,7 +778,7 @@ int imx_media_capture_device_register(struct imx_media_video_dev *vdev)
        /* setup default format */
        fmt_src.pad = priv->src_sd_pad;
        fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-       v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt_src);
+       ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt_src);
        if (ret) {
                v4l2_err(sd, "failed to get src_sd format\n");
                goto unreg;
index 2b635eb..2cc77f6 100644 (file)
@@ -849,7 +849,7 @@ int imx_media_csc_scaler_device_register(struct imx_media_video_dev *vdev)
 
        vfd->v4l2_dev = &priv->md->v4l2_dev;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(vfd->v4l2_dev, "Failed to register video device\n");
                return ret;
index b60ed4f..e76a6a8 100644 (file)
@@ -457,7 +457,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv)
        case V4L2_PIX_FMT_SGBRG16:
        case V4L2_PIX_FMT_SGRBG16:
        case V4L2_PIX_FMT_SRGGB16:
-       case V4L2_PIX_FMT_Y16:
+       case V4L2_PIX_FMT_Y10:
+       case V4L2_PIX_FMT_Y12:
                burst_size = 8;
                passthrough_bits = 16;
                break;
@@ -1459,6 +1460,8 @@ static void csi_try_fmt(struct csi_priv *priv,
                /* propagate colorimetry from sink */
                sdformat->format.colorspace = infmt->colorspace;
                sdformat->format.xfer_func = infmt->xfer_func;
+               sdformat->format.quantization = infmt->quantization;
+               sdformat->format.ycbcr_enc = infmt->ycbcr_enc;
 
                break;
        case CSI_SINK_PAD:
index 0788a18..fae9816 100644 (file)
@@ -161,17 +161,24 @@ static const struct imx_media_pixfmt rgb_formats[] = {
                .bayer  = true,
        }, {
                .fourcc = V4L2_PIX_FMT_GREY,
-               .codes = {MEDIA_BUS_FMT_Y8_1X8},
-               .cs     = IPUV3_COLORSPACE_RGB,
-               .bpp    = 8,
-               .bayer  = true,
-       }, {
-               .fourcc = V4L2_PIX_FMT_Y16,
                .codes = {
+                       MEDIA_BUS_FMT_Y8_1X8,
                        MEDIA_BUS_FMT_Y10_1X10,
                        MEDIA_BUS_FMT_Y12_1X12,
                },
                .cs     = IPUV3_COLORSPACE_RGB,
+               .bpp    = 8,
+               .bayer  = true,
+       }, {
+               .fourcc = V4L2_PIX_FMT_Y10,
+               .codes = {MEDIA_BUS_FMT_Y10_1X10},
+               .cs     = IPUV3_COLORSPACE_RGB,
+               .bpp    = 16,
+               .bayer  = true,
+       }, {
+               .fourcc = V4L2_PIX_FMT_Y12,
+               .codes = {MEDIA_BUS_FMT_Y12_1X12},
+               .cs     = IPUV3_COLORSPACE_RGB,
                .bpp    = 16,
                .bayer  = true,
        },
index cd3dd6e..8ab8230 100644 (file)
@@ -592,22 +592,19 @@ static int csi2_probe(struct platform_device *pdev)
        csi2->pllref_clk = devm_clk_get(&pdev->dev, "ref");
        if (IS_ERR(csi2->pllref_clk)) {
                v4l2_err(&csi2->sd, "failed to get pll reference clock\n");
-               ret = PTR_ERR(csi2->pllref_clk);
-               return ret;
+               return PTR_ERR(csi2->pllref_clk);
        }
 
        csi2->dphy_clk = devm_clk_get(&pdev->dev, "dphy");
        if (IS_ERR(csi2->dphy_clk)) {
                v4l2_err(&csi2->sd, "failed to get dphy clock\n");
-               ret = PTR_ERR(csi2->dphy_clk);
-               return ret;
+               return PTR_ERR(csi2->dphy_clk);
        }
 
        csi2->pix_clk = devm_clk_get(&pdev->dev, "pix");
        if (IS_ERR(csi2->pix_clk)) {
                v4l2_err(&csi2->sd, "failed to get pixel clock\n");
-               ret = PTR_ERR(csi2->pix_clk);
-               return ret;
+               return PTR_ERR(csi2->pix_clk);
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index db30e2c..acbdffb 100644 (file)
@@ -292,7 +292,7 @@ static void imx7_csi_hw_disable(struct imx7_csi *csi)
 
 static void imx7_csi_dma_reflash(struct imx7_csi *csi)
 {
-       u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR18);
+       u32 cr3;
 
        cr3 = imx7_csi_reg_read(csi, CSI_CSICR3);
        cr3 |= BIT_DMA_REFLASH_RFF;
@@ -804,6 +804,22 @@ static int imx7_csi_configure(struct imx7_csi *csi)
        case V4L2_PIX_FMT_YUYV:
                cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B;
                break;
+       case V4L2_PIX_FMT_GREY:
+               if (in_code == MEDIA_BUS_FMT_Y8_1X8)
+                       cr18 |= BIT_MIPI_DATA_FORMAT_RAW8;
+               else if (in_code == MEDIA_BUS_FMT_Y10_1X10)
+                       cr18 |= BIT_MIPI_DATA_FORMAT_RAW10;
+               else
+                       cr18 |= BIT_MIPI_DATA_FORMAT_RAW12;
+               break;
+       case V4L2_PIX_FMT_Y10:
+               cr18 |= BIT_MIPI_DATA_FORMAT_RAW10;
+               cr1 |= BIT_PIXEL_BIT;
+               break;
+       case V4L2_PIX_FMT_Y12:
+               cr18 |= BIT_MIPI_DATA_FORMAT_RAW12;
+               cr1 |= BIT_PIXEL_BIT;
+               break;
        case V4L2_PIX_FMT_SBGGR8:
                cr18 |= BIT_MIPI_DATA_FORMAT_RAW8;
                break;
@@ -1009,10 +1025,13 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
                sdformat->format.width = in_fmt->width;
                sdformat->format.height = in_fmt->height;
                sdformat->format.code = in_fmt->code;
+               sdformat->format.field = in_fmt->field;
                *cc = in_cc;
 
                sdformat->format.colorspace = in_fmt->colorspace;
                sdformat->format.xfer_func = in_fmt->xfer_func;
+               sdformat->format.quantization = in_fmt->quantization;
+               sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc;
                break;
        case IMX7_CSI_PAD_SINK:
                *cc = imx_media_find_mbus_format(sdformat->format.code,
@@ -1023,6 +1042,9 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi,
                                                         false);
                        sdformat->format.code = (*cc)->codes[0];
                }
+
+               if (sdformat->format.field != V4L2_FIELD_INTERLACED)
+                       sdformat->format.field = V4L2_FIELD_NONE;
                break;
        default:
                return -EINVAL;
index 383abec..fbc1a92 100644 (file)
@@ -280,6 +280,18 @@ static const struct csis_pix_format mipi_csis_formats[] = {
                .code = MEDIA_BUS_FMT_YUYV8_2X8,
                .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT,
                .data_alignment = 16,
+       }, {
+               .code = MEDIA_BUS_FMT_Y8_1X8,
+               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8,
+               .data_alignment = 8,
+       }, {
+               .code = MEDIA_BUS_FMT_Y10_1X10,
+               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10,
+               .data_alignment = 16,
+       }, {
+               .code = MEDIA_BUS_FMT_Y12_1X12,
+               .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12,
+               .data_alignment = 16,
        }
 };
 
@@ -301,6 +313,7 @@ static int mipi_csis_dump_regs(struct csi_state *state)
                { 0x20, "DPHYSTS" },
                { 0x10, "INTMSK" },
                { 0x40, "CONFIG_CH0" },
+               { 0x44, "RESOL_CH0" },
                { 0xC0, "DBG_CONFIG" },
                { 0x38, "DPHYSLAVE_L" },
                { 0x3C, "DPHYSLAVE_H" },
@@ -404,7 +417,7 @@ static void mipi_csis_set_hsync_settle(struct csi_state *state, int hs_settle)
 {
        u32 val = mipi_csis_read(state, MIPI_CSIS_DPHYCTRL);
 
-       val = ((val & ~MIPI_CSIS_DPHYCTRL_HSS_MASK) | (hs_settle << 24));
+       val = (val & ~MIPI_CSIS_DPHYCTRL_HSS_MASK) | (hs_settle << 24);
 
        mipi_csis_write(state, MIPI_CSIS_DPHYCTRL, val);
 }
@@ -417,6 +430,7 @@ static void mipi_csis_set_params(struct csi_state *state)
        val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL);
        val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK;
        val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET;
+       val |= MIPI_CSIS_CMN_CTRL_INTER_MODE;
        mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val);
 
        __mipi_csis_set_format(state);
@@ -577,7 +591,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
                state->flags |= ST_STREAMING;
        } else {
                v4l2_subdev_call(state->src_sd, video, s_stream, 0);
-               ret = v4l2_subdev_call(state->src_sd, core, s_power, 1);
+               ret = v4l2_subdev_call(state->src_sd, core, s_power, 0);
                mipi_csis_stop_stream(state);
                state->flags &= ~ST_STREAMING;
                if (state->debug)
index dc356d6..52063b6 100644 (file)
@@ -13,8 +13,6 @@ staging directory.
 - Elaborate the functionality of different selection rectangles in driver
   documentation. This may require driver changes as well.
 
-- More detailed documentation on calculating BDS, GCD etc. sizes needed.
-
 - Document different operation modes, and which buffer queues are relevant
   in each mode. To process an image, which queues require a buffer an in
   which ones is it optional?
index f36de50..4f04fe8 100644 (file)
@@ -210,12 +210,12 @@ static int imgu_hw_wait(void __iomem *base, int reg, u32 mask, u32 cmp)
 
 /* Initialize the IPU3 CSS hardware and associated h/w blocks */
 
-int imgu_css_set_powerup(struct device *dev, void __iomem *base)
+int imgu_css_set_powerup(struct device *dev, void __iomem *base,
+                        unsigned int freq)
 {
-       static const unsigned int freq = 450;
        u32 pm_ctrl, state, val;
 
-       dev_dbg(dev, "%s\n", __func__);
+       dev_dbg(dev, "%s with freq %u\n", __func__, freq);
        /* Clear the CSS busy signal */
        readl(base + IMGU_REG_GP_BUSY);
        writel(0, base + IMGU_REG_GP_BUSY);
index 6b8bab2..6108a06 100644 (file)
@@ -187,7 +187,8 @@ bool imgu_css_is_streaming(struct imgu_css *css);
 bool imgu_css_pipe_queue_empty(struct imgu_css *css, unsigned int pipe);
 
 /******************* css hw *******************/
-int imgu_css_set_powerup(struct device *dev, void __iomem *base);
+int imgu_css_set_powerup(struct device *dev, void __iomem *base,
+                        unsigned int freq);
 void imgu_css_set_powerdown(struct device *dev, void __iomem *base);
 int imgu_css_irq_ack(struct imgu_css *css);
 
index 3d969b0..5f3ff96 100644 (file)
@@ -130,7 +130,7 @@ static u32 *imgu_mmu_alloc_page_table(u32 pteval)
        for (pte = 0; pte < IPU3_PT_PTES; pte++)
                pt[pte] = pteval;
 
-       set_memory_uc((unsigned long int)pt, IPU3_PT_ORDER);
+       set_memory_uc((unsigned long)pt, IPU3_PT_ORDER);
 
        return pt;
 }
@@ -141,7 +141,7 @@ static u32 *imgu_mmu_alloc_page_table(u32 pteval)
  */
 static void imgu_mmu_free_page_table(u32 *pt)
 {
-       set_memory_wb((unsigned long int)pt, IPU3_PT_ORDER);
+       set_memory_wb((unsigned long)pt, IPU3_PT_ORDER);
        free_page((unsigned long)pt);
 }
 
index 569e27b..09c8ede 100644 (file)
@@ -1245,7 +1245,7 @@ static int imgu_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe,
        vdev->queue = &node->vbq;
        vdev->vfl_dir = node->output ? VFL_DIR_TX : VFL_DIR_RX;
        video_set_drvdata(vdev, imgu);
-       r = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       r = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (r) {
                dev_err(dev, "failed to register video device (%d)", r);
                media_entity_cleanup(&vdev->entity);
index 06a61f3..4d53aad 100644 (file)
@@ -345,8 +345,20 @@ failed:
 static int imgu_powerup(struct imgu_device *imgu)
 {
        int r;
+       unsigned int pipe;
+       unsigned int freq = 200;
+       struct v4l2_mbus_framefmt *fmt;
+
+       /* input larger than 2048*1152, ask imgu to work on high freq */
+       for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) {
+               fmt = &imgu->imgu_pipe[pipe].nodes[IMGU_NODE_IN].pad_fmt;
+               dev_dbg(&imgu->pci_dev->dev, "pipe %u input format = %ux%u",
+                       pipe, fmt->width, fmt->height);
+               if ((fmt->width * fmt->height) >= (2048 * 1152))
+                       freq = 450;
+       }
 
-       r = imgu_css_set_powerup(&imgu->pci_dev->dev, imgu->base);
+       r = imgu_css_set_powerup(&imgu->pci_dev->dev, imgu->base, freq);
        if (r)
                return r;
 
@@ -666,7 +678,7 @@ static int imgu_pci_probe(struct pci_dev *pci_dev,
        atomic_set(&imgu->qbuf_barrier, 0);
        init_waitqueue_head(&imgu->buf_drain_wq);
 
-       r = imgu_css_set_powerup(&pci_dev->dev, imgu->base);
+       r = imgu_css_set_powerup(&pci_dev->dev, imgu->base, 200);
        if (r) {
                dev_err(&pci_dev->dev,
                        "failed to power up CSS (%d)\n", r);
index 6bea129..6e726af 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for Amlogic meson video decoder driver
 
 meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
-meson-vdec-objs += vdec_1.o
-meson-vdec-objs += codec_mpeg12.o
+meson-vdec-objs += vdec_1.o vdec_hevc.o
+meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_hevc_common.o codec_vp9.o
 
 obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
diff --git a/drivers/staging/media/meson/vdec/codec_h264.c b/drivers/staging/media/meson/vdec/codec_h264.c
new file mode 100644 (file)
index 0000000..c61128f
--- /dev/null
@@ -0,0 +1,485 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "vdec_helpers.h"
+#include "dos_regs.h"
+#include "codec_h264.h"
+
+#define SIZE_EXT_FW    (20 * SZ_1K)
+#define SIZE_WORKSPACE 0x1ee000
+#define SIZE_SEI       (8 * SZ_1K)
+
+/*
+ * Offset added by the firmware which must be substracted
+ * from the workspace phyaddr
+ */
+#define WORKSPACE_BUF_OFFSET   0x1000000
+
+/* ISR status */
+#define CMD_MASK               GENMASK(7, 0)
+#define CMD_SRC_CHANGE         1
+#define CMD_FRAMES_READY       2
+#define CMD_FATAL_ERROR                6
+#define CMD_BAD_WIDTH          7
+#define CMD_BAD_HEIGHT         8
+
+#define SEI_DATA_READY BIT(15)
+
+/* Picture type */
+#define PIC_TOP_BOT    5
+#define PIC_BOT_TOP    6
+
+/* Size of Motion Vector per macroblock */
+#define MB_MV_SIZE     96
+
+/* Frame status data */
+#define PIC_STRUCT_BIT 5
+#define PIC_STRUCT_MASK        GENMASK(2, 0)
+#define BUF_IDX_MASK   GENMASK(4, 0)
+#define ERROR_FLAG     BIT(9)
+#define OFFSET_BIT     16
+#define OFFSET_MASK    GENMASK(15, 0)
+
+/* Bitstream parsed data */
+#define MB_TOTAL_BIT   8
+#define MB_TOTAL_MASK  GENMASK(15, 0)
+#define MB_WIDTH_MASK  GENMASK(7, 0)
+#define MAX_REF_BIT    24
+#define MAX_REF_MASK   GENMASK(6, 0)
+#define AR_IDC_BIT     16
+#define AR_IDC_MASK    GENMASK(7, 0)
+#define AR_PRESENT_FLAG        BIT(0)
+#define AR_EXTEND      0xff
+
+/*
+ * Buffer to send to the ESPARSER to signal End Of Stream for H.264.
+ * This is a 16x16 encoded picture that will trigger drain firmware-side.
+ * There is no known alternative.
+ */
+static const u8 eos_sequence[SZ_4K] = {
+       0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd,
+       0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef,
+       0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20,
+       0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37,
+       0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34,
+       0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20,
+       0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79,
+       0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30,
+       0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+       0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e,
+       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74,
+       0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+       0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65,
+       0x66, 0x3d, 0x31, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d,
+       0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73,
+       0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20,
+       0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65,
+       0x3d, 0x36, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e,
+       0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f,
+       0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e,
+       0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61,
+       0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
+       0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30,
+       0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a,
+       0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68,
+       0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73,
+       0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64,
+       0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63,
+       0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66,
+       0x66, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d,
+       0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
+       0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d,
+       0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d,
+       0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69,
+       0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30, 0x20, 0x72, 0x61, 0x74,
+       0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f,
+       0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69,
+       0x6e, 0x3d, 0x31, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35,
+       0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70, 0x3d, 0x34, 0x20, 0x69,
+       0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30,
+       0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80,
+       0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20,
+       0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06, 0x51, 0xe2, 0x44, 0xd4,
+       0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01,
+       0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6,
+       0x57, 0xae, 0x49, 0x30, 0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4,
+       0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb, 0xd6, 0xbe, 0x5c, 0xd7,
+       0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09,
+       0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66,
+       0xba, 0x9b, 0x82, 0x29, 0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b,
+       0x00, 0x00, 0x01, 0x0ff,
+};
+
+static const u8 *codec_h264_eos_sequence(u32 *len)
+{
+       *len = ARRAY_SIZE(eos_sequence);
+       return eos_sequence;
+}
+
+struct codec_h264 {
+       /* H.264 decoder requires an extended firmware */
+       void      *ext_fw_vaddr;
+       dma_addr_t ext_fw_paddr;
+
+       /* Buffer for the H.264 Workspace */
+       void      *workspace_vaddr;
+       dma_addr_t workspace_paddr;
+
+       /* Buffer for the H.264 references MV */
+       void      *ref_vaddr;
+       dma_addr_t ref_paddr;
+       u32        ref_size;
+
+       /* Buffer for parsed SEI data */
+       void      *sei_vaddr;
+       dma_addr_t sei_paddr;
+
+       u32 mb_width;
+       u32 mb_height;
+       u32 max_refs;
+};
+
+static int codec_h264_can_recycle(struct amvdec_core *core)
+{
+       return !amvdec_read_dos(core, AV_SCRATCH_7) ||
+              !amvdec_read_dos(core, AV_SCRATCH_8);
+}
+
+static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx)
+{
+       /*
+        * Tell the firmware it can recycle this buffer.
+        * AV_SCRATCH_8 serves the same purpose.
+        */
+       if (!amvdec_read_dos(core, AV_SCRATCH_7))
+               amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1);
+       else
+               amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1);
+}
+
+static int codec_h264_start(struct amvdec_session *sess)
+{
+       u32 workspace_offset;
+       struct amvdec_core *core = sess->core;
+       struct codec_h264 *h264 = sess->priv;
+
+       /* Allocate some memory for the H.264 decoder's state */
+       h264->workspace_vaddr =
+               dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
+                                  &h264->workspace_paddr, GFP_KERNEL);
+       if (!h264->workspace_vaddr)
+               return -ENOMEM;
+
+       /* Allocate some memory for the H.264 SEI dump */
+       h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI,
+                                            &h264->sei_paddr, GFP_KERNEL);
+       if (!h264->sei_vaddr)
+               return -ENOMEM;
+
+       amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6));
+
+       workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET;
+       amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset);
+       amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr);
+       amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr -
+                                            workspace_offset);
+
+       /* Enable "error correction" */
+       amvdec_write_dos(core, AV_SCRATCH_F,
+                        (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) |
+                        BIT(4) | BIT(7));
+
+       amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
+
+       return 0;
+}
+
+static int codec_h264_stop(struct amvdec_session *sess)
+{
+       struct codec_h264 *h264 = sess->priv;
+       struct amvdec_core *core = sess->core;
+
+       if (h264->ext_fw_vaddr)
+               dma_free_coherent(core->dev, SIZE_EXT_FW,
+                                 h264->ext_fw_vaddr, h264->ext_fw_paddr);
+
+       if (h264->workspace_vaddr)
+               dma_free_coherent(core->dev, SIZE_WORKSPACE,
+                                 h264->workspace_vaddr, h264->workspace_paddr);
+
+       if (h264->ref_vaddr)
+               dma_free_coherent(core->dev, h264->ref_size,
+                                 h264->ref_vaddr, h264->ref_paddr);
+
+       if (h264->sei_vaddr)
+               dma_free_coherent(core->dev, SIZE_SEI,
+                                 h264->sei_vaddr, h264->sei_paddr);
+
+       return 0;
+}
+
+static int codec_h264_load_extended_firmware(struct amvdec_session *sess,
+                                            const u8 *data, u32 len)
+{
+       struct codec_h264 *h264;
+       struct amvdec_core *core = sess->core;
+
+       if (len < SIZE_EXT_FW)
+               return -EINVAL;
+
+       h264 = kzalloc(sizeof(*h264), GFP_KERNEL);
+       if (!h264)
+               return -ENOMEM;
+
+       h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW,
+                                               &h264->ext_fw_paddr,
+                                               GFP_KERNEL);
+       if (!h264->ext_fw_vaddr) {
+               kfree(h264);
+               return -ENOMEM;
+       }
+
+       memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW);
+       sess->priv = h264;
+
+       return 0;
+}
+
+static const struct v4l2_fract par_table[] = {
+       { 1, 1 },   { 1, 1 },    { 12, 11 }, { 10, 11 },
+       { 16, 11 }, { 40, 33 },  { 24, 11 }, { 20, 11 },
+       { 32, 11 }, { 80, 33 },  { 18, 11 }, { 15, 11 },
+       { 64, 33 }, { 160, 99 }, { 4, 3 },   { 3, 2 },
+       { 2, 1 }
+};
+
+static void codec_h264_set_par(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       u32 seq_info = amvdec_read_dos(core, AV_SCRATCH_2);
+       u32 ar_idc = (seq_info >> AR_IDC_BIT) & AR_IDC_MASK;
+
+       if (!(seq_info & AR_PRESENT_FLAG))
+               return;
+
+       if (ar_idc == AR_EXTEND) {
+               u32 ar_info = amvdec_read_dos(core, AV_SCRATCH_3);
+
+               sess->pixelaspect.numerator = ar_info & 0xffff;
+               sess->pixelaspect.denominator = (ar_info >> 16) & 0xffff;
+               return;
+       }
+
+       if (ar_idc >= ARRAY_SIZE(par_table))
+               return;
+
+       sess->pixelaspect = par_table[ar_idc];
+}
+
+static void codec_h264_resume(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       struct codec_h264 *h264 = sess->priv;
+       u32 mb_width, mb_height, mb_total;
+
+       amvdec_set_canvases(sess,
+                           (u32[]){ ANC0_CANVAS_ADDR, 0 },
+                           (u32[]){ 24, 0 });
+
+       dev_dbg(core->dev, "max_refs = %u; actual_dpb_size = %u\n",
+               h264->max_refs, sess->num_dst_bufs);
+
+       /* Align to a multiple of 4 macroblocks */
+       mb_width = ALIGN(h264->mb_width, 4);
+       mb_height = ALIGN(h264->mb_height, 4);
+       mb_total = mb_width * mb_height;
+
+       h264->ref_size = mb_total * MB_MV_SIZE * h264->max_refs;
+       h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size,
+                                            &h264->ref_paddr, GFP_KERNEL);
+       if (!h264->ref_vaddr) {
+               amvdec_abort(sess);
+               return;
+       }
+
+       /* Address to store the references' MVs */
+       amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr);
+       /* End of ref MV */
+       amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size);
+
+       amvdec_write_dos(core, AV_SCRATCH_0, (h264->max_refs << 24) |
+                                            (sess->num_dst_bufs << 16) |
+                                            ((h264->max_refs - 1) << 8));
+}
+
+/*
+ * Configure the H.264 decoder when the parser detected a parameter set change
+ */
+static void codec_h264_src_change(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       struct codec_h264 *h264 = sess->priv;
+       u32 parsed_info, mb_total;
+       u32 crop_infor, crop_bottom, crop_right;
+       u32 frame_width, frame_height;
+
+       sess->keyframe_found = 1;
+
+       parsed_info = amvdec_read_dos(core, AV_SCRATCH_1);
+
+       /* Total number of 16x16 macroblocks */
+       mb_total = (parsed_info >> MB_TOTAL_BIT) & MB_TOTAL_MASK;
+       /* Number of macroblocks per line */
+       h264->mb_width = parsed_info & MB_WIDTH_MASK;
+       /* Number of macroblock lines */
+       h264->mb_height = mb_total / h264->mb_width;
+
+       h264->max_refs = ((parsed_info >> MAX_REF_BIT) & MAX_REF_MASK) + 1;
+
+       crop_infor = amvdec_read_dos(core, AV_SCRATCH_6);
+       crop_bottom = (crop_infor & 0xff);
+       crop_right = (crop_infor >> 16) & 0xff;
+
+       frame_width = h264->mb_width * 16 - crop_right;
+       frame_height = h264->mb_height * 16 - crop_bottom;
+
+       dev_dbg(core->dev, "frame: %ux%u; crop: %u %u\n",
+               frame_width, frame_height, crop_right, crop_bottom);
+
+       codec_h264_set_par(sess);
+       amvdec_src_change(sess, frame_width, frame_height, h264->max_refs + 5);
+}
+
+/*
+ * The bitstream offset is split in half in 2 different registers.
+ * Fetch its MSB here, which location depends on the frame number.
+ */
+static u32 get_offset_msb(struct amvdec_core *core, int frame_num)
+{
+       int take_msb = frame_num % 2;
+       int reg_offset = (frame_num / 2) * 4;
+       u32 offset_msb = amvdec_read_dos(core, AV_SCRATCH_A + reg_offset);
+
+       if (take_msb)
+               return offset_msb & 0xffff0000;
+
+       return (offset_msb & 0x0000ffff) << 16;
+}
+
+static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status)
+{
+       struct amvdec_core *core = sess->core;
+       int error_count;
+       int num_frames;
+       int i;
+
+       error_count = amvdec_read_dos(core, AV_SCRATCH_D);
+       num_frames = (status >> 8) & 0xff;
+       if (error_count) {
+               dev_warn(core->dev,
+                        "decoder error(s) happened, count %d\n", error_count);
+               amvdec_write_dos(core, AV_SCRATCH_D, 0);
+       }
+
+       for (i = 0; i < num_frames; i++) {
+               u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4);
+               u32 buffer_index = frame_status & BUF_IDX_MASK;
+               u32 pic_struct = (frame_status >> PIC_STRUCT_BIT) &
+                                PIC_STRUCT_MASK;
+               u32 offset = (frame_status >> OFFSET_BIT) & OFFSET_MASK;
+               u32 field = V4L2_FIELD_NONE;
+
+               /*
+                * A buffer decode error means it was decoded,
+                * but part of the picture will have artifacts.
+                * Typical reason is a temporarily corrupted bitstream
+                */
+               if (frame_status & ERROR_FLAG)
+                       dev_dbg(core->dev, "Buffer %d decode error\n",
+                               buffer_index);
+
+               if (pic_struct == PIC_TOP_BOT)
+                       field = V4L2_FIELD_INTERLACED_TB;
+               else if (pic_struct == PIC_BOT_TOP)
+                       field = V4L2_FIELD_INTERLACED_BT;
+
+               offset |= get_offset_msb(core, i);
+               amvdec_dst_buf_done_idx(sess, buffer_index, offset, field);
+       }
+}
+
+static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       u32 status;
+       u32 size;
+       u8 cmd;
+
+       status = amvdec_read_dos(core, AV_SCRATCH_0);
+       cmd = status & CMD_MASK;
+
+       switch (cmd) {
+       case CMD_SRC_CHANGE:
+               codec_h264_src_change(sess);
+               break;
+       case CMD_FRAMES_READY:
+               codec_h264_frames_ready(sess, status);
+               break;
+       case CMD_FATAL_ERROR:
+               dev_err(core->dev, "H.264 decoder fatal error\n");
+               goto abort;
+       case CMD_BAD_WIDTH:
+               size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
+               dev_err(core->dev, "Unsupported video width: %u\n", size);
+               goto abort;
+       case CMD_BAD_HEIGHT:
+               size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
+               dev_err(core->dev, "Unsupported video height: %u\n", size);
+               goto abort;
+       case 0: /* Unused but not worth printing for */
+       case 9:
+               break;
+       default:
+               dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd);
+               break;
+       }
+
+       if (cmd && cmd != CMD_SRC_CHANGE)
+               amvdec_write_dos(core, AV_SCRATCH_0, 0);
+
+       /* Decoder has some SEI data for us ; ignore */
+       if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY)
+               amvdec_write_dos(core, AV_SCRATCH_J, 0);
+
+       return IRQ_HANDLED;
+abort:
+       amvdec_abort(sess);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t codec_h264_isr(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+
+       amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
+
+       return IRQ_WAKE_THREAD;
+}
+
+struct amvdec_codec_ops codec_h264_ops = {
+       .start = codec_h264_start,
+       .stop = codec_h264_stop,
+       .load_extended_firmware = codec_h264_load_extended_firmware,
+       .isr = codec_h264_isr,
+       .threaded_isr = codec_h264_threaded_isr,
+       .can_recycle = codec_h264_can_recycle,
+       .recycle = codec_h264_recycle,
+       .eos_sequence = codec_h264_eos_sequence,
+       .resume = codec_h264_resume,
+};
diff --git a/drivers/staging/media/meson/vdec/codec_h264.h b/drivers/staging/media/meson/vdec/codec_h264.h
new file mode 100644 (file)
index 0000000..7cb4fb8
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_CODEC_H264_H_
+#define __MESON_VDEC_CODEC_H264_H_
+
+#include "vdec.h"
+
+extern struct amvdec_codec_ops codec_h264_ops;
+
+#endif
diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.c b/drivers/staging/media/meson/vdec/codec_hevc_common.c
new file mode 100644 (file)
index 0000000..0315cc0
--- /dev/null
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "codec_hevc_common.h"
+#include "vdec_helpers.h"
+#include "hevc_regs.h"
+
+#define MMU_COMPRESS_HEADER_SIZE 0x48000
+#define MMU_MAP_SIZE 0x4800
+
+const u16 vdec_hevc_parser_cmd[] = {
+       0x0401, 0x8401, 0x0800, 0x0402,
+       0x9002, 0x1423, 0x8CC3, 0x1423,
+       0x8804, 0x9825, 0x0800, 0x04FE,
+       0x8406, 0x8411, 0x1800, 0x8408,
+       0x8409, 0x8C2A, 0x9C2B, 0x1C00,
+       0x840F, 0x8407, 0x8000, 0x8408,
+       0x2000, 0xA800, 0x8410, 0x04DE,
+       0x840C, 0x840D, 0xAC00, 0xA000,
+       0x08C0, 0x08E0, 0xA40E, 0xFC00,
+       0x7C00
+};
+
+/* Configure decode head read mode */
+void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit)
+{
+       struct amvdec_core *core = sess->core;
+       u32 body_size = amvdec_am21c_body_size(sess->width, sess->height);
+       u32 head_size = amvdec_am21c_head_size(sess->width, sess->height);
+
+       if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) {
+               /* Enable 2-plane reference read mode */
+               amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31));
+               return;
+       }
+
+       if (codec_hevc_use_mmu(core->platform->revision,
+                              sess->pixfmt_cap, is_10bit))
+               amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(4));
+       else
+               amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0);
+
+       if (core->platform->revision < VDEC_REVISION_SM1)
+               amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32);
+       amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size);
+       amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size);
+       amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size);
+}
+EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head);
+
+static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess,
+                                         struct codec_hevc_common *comm,
+                                         int is_10bit)
+{
+       struct amvdec_core *core = sess->core;
+       struct v4l2_m2m_buffer *buf;
+       u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
+       dma_addr_t buf_y_paddr = 0;
+       dma_addr_t buf_uv_paddr = 0;
+       u32 idx = 0;
+       u32 val;
+       int i;
+
+       amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0);
+
+       v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
+               struct vb2_buffer *vb = &buf->vb.vb2_buf;
+
+               idx = vb->index;
+
+               if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit))
+                       buf_y_paddr = comm->fbc_buffer_paddr[idx];
+               else
+                       buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+               if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) {
+                       val = buf_y_paddr | (idx << 8) | 1;
+                       amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+                                        val);
+               } else {
+                       buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1);
+                       val = buf_y_paddr | ((idx * 2) << 8) | 1;
+                       amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+                                        val);
+                       val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1;
+                       amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+                                        val);
+               }
+       }
+
+       if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit))
+               val = buf_y_paddr | (idx << 8) | 1;
+       else
+               val = buf_y_paddr | ((idx * 2) << 8) | 1;
+
+       /* Fill the remaining unused slots with the last buffer's Y addr */
+       for (i = buf_num; i < MAX_REF_PIC_NUM; ++i)
+               amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val);
+
+       amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
+       amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1);
+       for (i = 0; i < 32; ++i)
+               amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
+}
+
+static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess,
+                                        struct codec_hevc_common *comm,
+                                        int is_10bit)
+{
+       struct amvdec_core *core = sess->core;
+       struct v4l2_m2m_buffer *buf;
+       u32 revision = core->platform->revision;
+       u32 pixfmt_cap = sess->pixfmt_cap;
+       int i;
+
+       amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR,
+                        BIT(2) | BIT(1));
+
+       v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
+               struct vb2_buffer *vb = &buf->vb.vb2_buf;
+               dma_addr_t buf_y_paddr = 0;
+               dma_addr_t buf_uv_paddr = 0;
+               u32 idx = vb->index;
+
+               if (codec_hevc_use_mmu(revision, pixfmt_cap, is_10bit))
+                       buf_y_paddr = comm->mmu_header_paddr[idx];
+               else if (codec_hevc_use_downsample(pixfmt_cap, is_10bit))
+                       buf_y_paddr = comm->fbc_buffer_paddr[idx];
+               else
+                       buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+               amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA,
+                                buf_y_paddr >> 5);
+
+               if (!codec_hevc_use_fbc(pixfmt_cap, is_10bit)) {
+                       buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1);
+                       amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA,
+                                        buf_uv_paddr >> 5);
+               }
+       }
+
+       amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1);
+       amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1);
+       for (i = 0; i < 32; ++i)
+               amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
+}
+
+void codec_hevc_free_fbc_buffers(struct amvdec_session *sess,
+                                struct codec_hevc_common *comm)
+{
+       struct device *dev = sess->core->dev;
+       u32 am21_size = amvdec_am21c_size(sess->width, sess->height);
+       int i;
+
+       for (i = 0; i < MAX_REF_PIC_NUM; ++i) {
+               if (comm->fbc_buffer_vaddr[i]) {
+                       dma_free_coherent(dev, am21_size,
+                                         comm->fbc_buffer_vaddr[i],
+                                         comm->fbc_buffer_paddr[i]);
+                       comm->fbc_buffer_vaddr[i] = NULL;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers);
+
+static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess,
+                                       struct codec_hevc_common *comm)
+{
+       struct device *dev = sess->core->dev;
+       struct v4l2_m2m_buffer *buf;
+       u32 am21_size = amvdec_am21c_size(sess->width, sess->height);
+
+       v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
+               u32 idx = buf->vb.vb2_buf.index;
+               dma_addr_t paddr;
+               void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr,
+                                                GFP_KERNEL);
+               if (!vaddr) {
+                       codec_hevc_free_fbc_buffers(sess, comm);
+                       return -ENOMEM;
+               }
+
+               comm->fbc_buffer_vaddr[idx] = vaddr;
+               comm->fbc_buffer_paddr[idx] = paddr;
+       }
+
+       return 0;
+}
+
+void codec_hevc_free_mmu_headers(struct amvdec_session *sess,
+                                struct codec_hevc_common *comm)
+{
+       struct device *dev = sess->core->dev;
+       int i;
+
+       for (i = 0; i < MAX_REF_PIC_NUM; ++i) {
+               if (comm->mmu_header_vaddr[i]) {
+                       dma_free_coherent(dev, MMU_COMPRESS_HEADER_SIZE,
+                                         comm->mmu_header_vaddr[i],
+                                         comm->mmu_header_paddr[i]);
+                       comm->mmu_header_vaddr[i] = NULL;
+               }
+       }
+
+       if (comm->mmu_map_vaddr) {
+               dma_free_coherent(dev, MMU_MAP_SIZE,
+                                 comm->mmu_map_vaddr,
+                                 comm->mmu_map_paddr);
+               comm->mmu_map_vaddr = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(codec_hevc_free_mmu_headers);
+
+static int codec_hevc_alloc_mmu_headers(struct amvdec_session *sess,
+                                       struct codec_hevc_common *comm)
+{
+       struct device *dev = sess->core->dev;
+       struct v4l2_m2m_buffer *buf;
+
+       comm->mmu_map_vaddr = dma_alloc_coherent(dev, MMU_MAP_SIZE,
+                                                &comm->mmu_map_paddr,
+                                                GFP_KERNEL);
+       if (!comm->mmu_map_vaddr)
+               return -ENOMEM;
+
+       v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
+               u32 idx = buf->vb.vb2_buf.index;
+               dma_addr_t paddr;
+               void *vaddr = dma_alloc_coherent(dev, MMU_COMPRESS_HEADER_SIZE,
+                                                &paddr, GFP_KERNEL);
+               if (!vaddr) {
+                       codec_hevc_free_mmu_headers(sess, comm);
+                       return -ENOMEM;
+               }
+
+               comm->mmu_header_vaddr[idx] = vaddr;
+               comm->mmu_header_paddr[idx] = paddr;
+       }
+
+       return 0;
+}
+
+int codec_hevc_setup_buffers(struct amvdec_session *sess,
+                            struct codec_hevc_common *comm,
+                            int is_10bit)
+{
+       struct amvdec_core *core = sess->core;
+       int ret;
+
+       if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) {
+               ret = codec_hevc_alloc_fbc_buffers(sess, comm);
+               if (ret)
+                       return ret;
+       }
+
+       if (codec_hevc_use_mmu(core->platform->revision,
+                              sess->pixfmt_cap, is_10bit)) {
+               ret = codec_hevc_alloc_mmu_headers(sess, comm);
+               if (ret) {
+                       codec_hevc_free_fbc_buffers(sess, comm);
+                       return ret;
+               }
+       }
+
+       if (core->platform->revision == VDEC_REVISION_GXBB)
+               codec_hevc_setup_buffers_gxbb(sess, comm, is_10bit);
+       else
+               codec_hevc_setup_buffers_gxl(sess, comm, is_10bit);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers);
+
+void codec_hevc_fill_mmu_map(struct amvdec_session *sess,
+                            struct codec_hevc_common *comm,
+                            struct vb2_buffer *vb)
+{
+       u32 size = amvdec_am21c_size(sess->width, sess->height);
+       u32 nb_pages = size / PAGE_SIZE;
+       u32 *mmu_map = comm->mmu_map_vaddr;
+       u32 first_page;
+       u32 i;
+
+       if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M)
+               first_page = comm->fbc_buffer_paddr[vb->index] >> PAGE_SHIFT;
+       else
+               first_page = vb2_dma_contig_plane_dma_addr(vb, 0) >> PAGE_SHIFT;
+
+       for (i = 0; i < nb_pages; ++i)
+               mmu_map[i] = first_page + i;
+}
+EXPORT_SYMBOL_GPL(codec_hevc_fill_mmu_map);
diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.h b/drivers/staging/media/meson/vdec/codec_hevc_common.h
new file mode 100644 (file)
index 0000000..88e4379
--- /dev/null
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Maxime Jourdan <mjourdan@baylibre.com>
+ */
+
+#ifndef __MESON_VDEC_HEVC_COMMON_H_
+#define __MESON_VDEC_HEVC_COMMON_H_
+
+#include "vdec.h"
+
+#define PARSER_CMD_SKIP_CFG_0 0x0000090b
+#define PARSER_CMD_SKIP_CFG_1 0x1b14140f
+#define PARSER_CMD_SKIP_CFG_2 0x001b1910
+
+#define VDEC_HEVC_PARSER_CMD_LEN 37
+extern const u16 vdec_hevc_parser_cmd[VDEC_HEVC_PARSER_CMD_LEN];
+
+#define MAX_REF_PIC_NUM        24
+
+struct codec_hevc_common {
+       void      *fbc_buffer_vaddr[MAX_REF_PIC_NUM];
+       dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM];
+
+       void      *mmu_header_vaddr[MAX_REF_PIC_NUM];
+       dma_addr_t mmu_header_paddr[MAX_REF_PIC_NUM];
+
+       void      *mmu_map_vaddr;
+       dma_addr_t mmu_map_paddr;
+};
+
+/* Returns 1 if we must use framebuffer compression */
+static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit)
+{
+       /* TOFIX: Handle Amlogic Compressed buffer for 8bit also */
+       return is_10bit;
+}
+
+/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */
+static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit)
+{
+       return is_10bit;
+}
+
+/* Returns 1 if we are decoding using the IOMMU */
+static inline int codec_hevc_use_mmu(u32 revision, u32 pixfmt, int is_10bit)
+{
+       return revision >= VDEC_REVISION_G12A &&
+              codec_hevc_use_fbc(pixfmt, is_10bit);
+}
+
+/**
+ * Configure decode head read mode
+ */
+void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit);
+
+void codec_hevc_free_fbc_buffers(struct amvdec_session *sess,
+                                struct codec_hevc_common *comm);
+
+void codec_hevc_free_mmu_headers(struct amvdec_session *sess,
+                                struct codec_hevc_common *comm);
+
+int codec_hevc_setup_buffers(struct amvdec_session *sess,
+                            struct codec_hevc_common *comm,
+                            int is_10bit);
+
+void codec_hevc_fill_mmu_map(struct amvdec_session *sess,
+                            struct codec_hevc_common *comm,
+                            struct vb2_buffer *vb);
+
+#endif
diff --git a/drivers/staging/media/meson/vdec/codec_vp9.c b/drivers/staging/media/meson/vdec/codec_vp9.c
new file mode 100644 (file)
index 0000000..60e4fc0
--- /dev/null
@@ -0,0 +1,2141 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Maxime Jourdan <mjourdan@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ */
+
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "dos_regs.h"
+#include "hevc_regs.h"
+#include "codec_vp9.h"
+#include "vdec_helpers.h"
+#include "codec_hevc_common.h"
+
+/* HEVC reg mapping */
+#define VP9_DEC_STATUS_REG     HEVC_ASSIST_SCRATCH_0
+       #define VP9_10B_DECODE_SLICE    5
+       #define VP9_HEAD_PARSER_DONE    0xf0
+#define VP9_RPM_BUFFER         HEVC_ASSIST_SCRATCH_1
+#define VP9_SHORT_TERM_RPS     HEVC_ASSIST_SCRATCH_2
+#define VP9_ADAPT_PROB_REG     HEVC_ASSIST_SCRATCH_3
+#define VP9_MMU_MAP_BUFFER     HEVC_ASSIST_SCRATCH_4
+#define VP9_PPS_BUFFER         HEVC_ASSIST_SCRATCH_5
+#define VP9_SAO_UP             HEVC_ASSIST_SCRATCH_6
+#define VP9_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7
+#define VP9_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8
+#define VP9_PROB_SWAP_BUFFER   HEVC_ASSIST_SCRATCH_9
+#define VP9_COUNT_SWAP_BUFFER  HEVC_ASSIST_SCRATCH_A
+#define VP9_SEG_MAP_BUFFER     HEVC_ASSIST_SCRATCH_B
+#define VP9_SCALELUT           HEVC_ASSIST_SCRATCH_D
+#define VP9_WAIT_FLAG          HEVC_ASSIST_SCRATCH_E
+#define LMEM_DUMP_ADR          HEVC_ASSIST_SCRATCH_F
+#define NAL_SEARCH_CTL         HEVC_ASSIST_SCRATCH_I
+#define VP9_DECODE_MODE                HEVC_ASSIST_SCRATCH_J
+       #define DECODE_MODE_SINGLE 0
+#define DECODE_STOP_POS                HEVC_ASSIST_SCRATCH_K
+#define HEVC_DECODE_COUNT      HEVC_ASSIST_SCRATCH_M
+#define HEVC_DECODE_SIZE       HEVC_ASSIST_SCRATCH_N
+
+/* VP9 Constants */
+#define LCU_SIZE               64
+#define MAX_REF_PIC_NUM                24
+#define REFS_PER_FRAME         3
+#define REF_FRAMES             8
+#define MV_MEM_UNIT            0x240
+#define ADAPT_PROB_SIZE                0xf80
+
+enum FRAME_TYPE {
+       KEY_FRAME = 0,
+       INTER_FRAME = 1,
+       FRAME_TYPES,
+};
+
+/* VP9 Workspace layout */
+#define MPRED_MV_BUF_SIZE 0x120000
+
+#define IPP_SIZE       0x4000
+#define SAO_ABV_SIZE   0x30000
+#define SAO_VB_SIZE    0x30000
+#define SH_TM_RPS_SIZE 0x800
+#define VPS_SIZE       0x800
+#define SPS_SIZE       0x800
+#define PPS_SIZE       0x2000
+#define SAO_UP_SIZE    0x2800
+#define SWAP_BUF_SIZE  0x800
+#define SWAP_BUF2_SIZE 0x800
+#define SCALELUT_SIZE  0x8000
+#define DBLK_PARA_SIZE 0x80000
+#define DBLK_DATA_SIZE 0x80000
+#define SEG_MAP_SIZE   0xd800
+#define PROB_SIZE      0x5000
+#define COUNT_SIZE     0x3000
+#define MMU_VBH_SIZE   0x5000
+#define MPRED_ABV_SIZE 0x10000
+#define MPRED_MV_SIZE  (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM)
+#define RPM_BUF_SIZE   0x100
+#define LMEM_SIZE      0x800
+
+#define IPP_OFFSET       0x00
+#define SAO_ABV_OFFSET   (IPP_OFFSET + IPP_SIZE)
+#define SAO_VB_OFFSET    (SAO_ABV_OFFSET + SAO_ABV_SIZE)
+#define SH_TM_RPS_OFFSET (SAO_VB_OFFSET + SAO_VB_SIZE)
+#define VPS_OFFSET       (SH_TM_RPS_OFFSET + SH_TM_RPS_SIZE)
+#define SPS_OFFSET       (VPS_OFFSET + VPS_SIZE)
+#define PPS_OFFSET       (SPS_OFFSET + SPS_SIZE)
+#define SAO_UP_OFFSET    (PPS_OFFSET + PPS_SIZE)
+#define SWAP_BUF_OFFSET  (SAO_UP_OFFSET + SAO_UP_SIZE)
+#define SWAP_BUF2_OFFSET (SWAP_BUF_OFFSET + SWAP_BUF_SIZE)
+#define SCALELUT_OFFSET  (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE)
+#define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE)
+#define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE)
+#define SEG_MAP_OFFSET   (DBLK_DATA_OFFSET + DBLK_DATA_SIZE)
+#define PROB_OFFSET      (SEG_MAP_OFFSET + SEG_MAP_SIZE)
+#define COUNT_OFFSET     (PROB_OFFSET + PROB_SIZE)
+#define MMU_VBH_OFFSET   (COUNT_OFFSET + COUNT_SIZE)
+#define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE)
+#define MPRED_MV_OFFSET  (MPRED_ABV_OFFSET + MPRED_ABV_SIZE)
+#define RPM_OFFSET       (MPRED_MV_OFFSET + MPRED_MV_SIZE)
+#define LMEM_OFFSET      (RPM_OFFSET + RPM_BUF_SIZE)
+
+#define SIZE_WORKSPACE ALIGN(LMEM_OFFSET + LMEM_SIZE, 64 * SZ_1K)
+
+#define NONE           -1
+#define INTRA_FRAME     0
+#define LAST_FRAME      1
+#define GOLDEN_FRAME    2
+#define ALTREF_FRAME    3
+#define MAX_REF_FRAMES  4
+
+/*
+ * Defines, declarations, sub-functions for vp9 de-block loop
+       filter Thr/Lvl table update
+ * - struct segmentation is for loop filter only (removed something)
+ * - function "vp9_loop_filter_init" and "vp9_loop_filter_frame_init" will
+       be instantiated in C_Entry
+ * - vp9_loop_filter_init run once before decoding start
+ * - vp9_loop_filter_frame_init run before every frame decoding start
+ * - set video format to VP9 is in vp9_loop_filter_init
+ */
+#define MAX_LOOP_FILTER                63
+#define MAX_REF_LF_DELTAS      4
+#define MAX_MODE_LF_DELTAS     2
+#define SEGMENT_DELTADATA      0
+#define SEGMENT_ABSDATA                1
+#define MAX_SEGMENTS           8
+
+/* VP9 PROB processing defines */
+#define VP9_PARTITION_START      0
+#define VP9_PARTITION_SIZE_STEP  (3 * 4)
+#define VP9_PARTITION_ONE_SIZE   (4 * VP9_PARTITION_SIZE_STEP)
+#define VP9_PARTITION_KEY_START  0
+#define VP9_PARTITION_P_START    VP9_PARTITION_ONE_SIZE
+#define VP9_PARTITION_SIZE       (2 * VP9_PARTITION_ONE_SIZE)
+#define VP9_SKIP_START           (VP9_PARTITION_START + VP9_PARTITION_SIZE)
+#define VP9_SKIP_SIZE            4 /* only use 3*/
+#define VP9_TX_MODE_START        (VP9_SKIP_START + VP9_SKIP_SIZE)
+#define VP9_TX_MODE_8_0_OFFSET   0
+#define VP9_TX_MODE_8_1_OFFSET   1
+#define VP9_TX_MODE_16_0_OFFSET  2
+#define VP9_TX_MODE_16_1_OFFSET  4
+#define VP9_TX_MODE_32_0_OFFSET  6
+#define VP9_TX_MODE_32_1_OFFSET  9
+#define VP9_TX_MODE_SIZE         12
+#define VP9_COEF_START           (VP9_TX_MODE_START + VP9_TX_MODE_SIZE)
+#define VP9_COEF_BAND_0_OFFSET   0
+#define VP9_COEF_BAND_1_OFFSET   (VP9_COEF_BAND_0_OFFSET + 3 * 3 + 1)
+#define VP9_COEF_BAND_2_OFFSET   (VP9_COEF_BAND_1_OFFSET + 6 * 3)
+#define VP9_COEF_BAND_3_OFFSET   (VP9_COEF_BAND_2_OFFSET + 6 * 3)
+#define VP9_COEF_BAND_4_OFFSET   (VP9_COEF_BAND_3_OFFSET + 6 * 3)
+#define VP9_COEF_BAND_5_OFFSET   (VP9_COEF_BAND_4_OFFSET + 6 * 3)
+#define VP9_COEF_SIZE_ONE_SET    100 /* ((3 + 5 * 6) * 3 + 1 padding)*/
+#define VP9_COEF_4X4_START       (VP9_COEF_START + 0 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_8X8_START       (VP9_COEF_START + 4 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_16X16_START     (VP9_COEF_START + 8 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_32X32_START     (VP9_COEF_START + 12 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_SIZE_PLANE      (2 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_COEF_SIZE            (4 * 2 * 2 * VP9_COEF_SIZE_ONE_SET)
+#define VP9_INTER_MODE_START     (VP9_COEF_START + VP9_COEF_SIZE)
+#define VP9_INTER_MODE_SIZE      24 /* only use 21 (# * 7)*/
+#define VP9_INTERP_START         (VP9_INTER_MODE_START + VP9_INTER_MODE_SIZE)
+#define VP9_INTERP_SIZE          8
+#define VP9_INTRA_INTER_START    (VP9_INTERP_START + VP9_INTERP_SIZE)
+#define VP9_INTRA_INTER_SIZE     4
+#define VP9_INTERP_INTRA_INTER_START  VP9_INTERP_START
+#define VP9_INTERP_INTRA_INTER_SIZE   (VP9_INTERP_SIZE + VP9_INTRA_INTER_SIZE)
+#define VP9_COMP_INTER_START     \
+               (VP9_INTERP_INTRA_INTER_START + VP9_INTERP_INTRA_INTER_SIZE)
+#define VP9_COMP_INTER_SIZE      5
+#define VP9_COMP_REF_START       (VP9_COMP_INTER_START + VP9_COMP_INTER_SIZE)
+#define VP9_COMP_REF_SIZE        5
+#define VP9_SINGLE_REF_START     (VP9_COMP_REF_START + VP9_COMP_REF_SIZE)
+#define VP9_SINGLE_REF_SIZE      10
+#define VP9_REF_MODE_START       VP9_COMP_INTER_START
+#define VP9_REF_MODE_SIZE        \
+               (VP9_COMP_INTER_SIZE + VP9_COMP_REF_SIZE + VP9_SINGLE_REF_SIZE)
+#define VP9_IF_Y_MODE_START      (VP9_REF_MODE_START + VP9_REF_MODE_SIZE)
+#define VP9_IF_Y_MODE_SIZE       36
+#define VP9_IF_UV_MODE_START     (VP9_IF_Y_MODE_START + VP9_IF_Y_MODE_SIZE)
+#define VP9_IF_UV_MODE_SIZE      92 /* only use 90*/
+#define VP9_MV_JOINTS_START      (VP9_IF_UV_MODE_START + VP9_IF_UV_MODE_SIZE)
+#define VP9_MV_JOINTS_SIZE       3
+#define VP9_MV_SIGN_0_START      (VP9_MV_JOINTS_START + VP9_MV_JOINTS_SIZE)
+#define VP9_MV_SIGN_0_SIZE       1
+#define VP9_MV_CLASSES_0_START   (VP9_MV_SIGN_0_START + VP9_MV_SIGN_0_SIZE)
+#define VP9_MV_CLASSES_0_SIZE    10
+#define VP9_MV_CLASS0_0_START    \
+               (VP9_MV_CLASSES_0_START + VP9_MV_CLASSES_0_SIZE)
+#define VP9_MV_CLASS0_0_SIZE     1
+#define VP9_MV_BITS_0_START      (VP9_MV_CLASS0_0_START + VP9_MV_CLASS0_0_SIZE)
+#define VP9_MV_BITS_0_SIZE       10
+#define VP9_MV_SIGN_1_START      (VP9_MV_BITS_0_START + VP9_MV_BITS_0_SIZE)
+#define VP9_MV_SIGN_1_SIZE       1
+#define VP9_MV_CLASSES_1_START   \
+                       (VP9_MV_SIGN_1_START + VP9_MV_SIGN_1_SIZE)
+#define VP9_MV_CLASSES_1_SIZE    10
+#define VP9_MV_CLASS0_1_START    \
+                       (VP9_MV_CLASSES_1_START + VP9_MV_CLASSES_1_SIZE)
+#define VP9_MV_CLASS0_1_SIZE     1
+#define VP9_MV_BITS_1_START      \
+                       (VP9_MV_CLASS0_1_START + VP9_MV_CLASS0_1_SIZE)
+#define VP9_MV_BITS_1_SIZE       10
+#define VP9_MV_CLASS0_FP_0_START \
+                       (VP9_MV_BITS_1_START + VP9_MV_BITS_1_SIZE)
+#define VP9_MV_CLASS0_FP_0_SIZE  9
+#define VP9_MV_CLASS0_FP_1_START \
+                       (VP9_MV_CLASS0_FP_0_START + VP9_MV_CLASS0_FP_0_SIZE)
+#define VP9_MV_CLASS0_FP_1_SIZE  9
+#define VP9_MV_CLASS0_HP_0_START \
+                       (VP9_MV_CLASS0_FP_1_START + VP9_MV_CLASS0_FP_1_SIZE)
+#define VP9_MV_CLASS0_HP_0_SIZE  2
+#define VP9_MV_CLASS0_HP_1_START \
+                       (VP9_MV_CLASS0_HP_0_START + VP9_MV_CLASS0_HP_0_SIZE)
+#define VP9_MV_CLASS0_HP_1_SIZE  2
+#define VP9_MV_START             VP9_MV_JOINTS_START
+#define VP9_MV_SIZE              72 /*only use 69*/
+
+#define VP9_TOTAL_SIZE           (VP9_MV_START + VP9_MV_SIZE)
+
+/* VP9 COUNT mem processing defines */
+#define VP9_COEF_COUNT_START           0
+#define VP9_COEF_COUNT_BAND_0_OFFSET   0
+#define VP9_COEF_COUNT_BAND_1_OFFSET   \
+                       (VP9_COEF_COUNT_BAND_0_OFFSET + 3 * 5)
+#define VP9_COEF_COUNT_BAND_2_OFFSET   \
+                       (VP9_COEF_COUNT_BAND_1_OFFSET + 6 * 5)
+#define VP9_COEF_COUNT_BAND_3_OFFSET   \
+                       (VP9_COEF_COUNT_BAND_2_OFFSET + 6 * 5)
+#define VP9_COEF_COUNT_BAND_4_OFFSET   \
+                       (VP9_COEF_COUNT_BAND_3_OFFSET + 6 * 5)
+#define VP9_COEF_COUNT_BAND_5_OFFSET   \
+                       (VP9_COEF_COUNT_BAND_4_OFFSET + 6 * 5)
+#define VP9_COEF_COUNT_SIZE_ONE_SET    165 /* ((3 + 5 * 6) * 5 */
+#define VP9_COEF_COUNT_4X4_START       \
+               (VP9_COEF_COUNT_START + 0 * VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_8X8_START       \
+               (VP9_COEF_COUNT_START + 4 * VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_16X16_START     \
+               (VP9_COEF_COUNT_START + 8 * VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_32X32_START     \
+               (VP9_COEF_COUNT_START + 12 * VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_SIZE_PLANE      (2 * VP9_COEF_COUNT_SIZE_ONE_SET)
+#define VP9_COEF_COUNT_SIZE            (4 * 2 * 2 * VP9_COEF_COUNT_SIZE_ONE_SET)
+
+#define VP9_INTRA_INTER_COUNT_START    \
+               (VP9_COEF_COUNT_START + VP9_COEF_COUNT_SIZE)
+#define VP9_INTRA_INTER_COUNT_SIZE     (4 * 2)
+#define VP9_COMP_INTER_COUNT_START     \
+               (VP9_INTRA_INTER_COUNT_START + VP9_INTRA_INTER_COUNT_SIZE)
+#define VP9_COMP_INTER_COUNT_SIZE      (5 * 2)
+#define VP9_COMP_REF_COUNT_START       \
+               (VP9_COMP_INTER_COUNT_START + VP9_COMP_INTER_COUNT_SIZE)
+#define VP9_COMP_REF_COUNT_SIZE        (5 * 2)
+#define VP9_SINGLE_REF_COUNT_START     \
+               (VP9_COMP_REF_COUNT_START + VP9_COMP_REF_COUNT_SIZE)
+#define VP9_SINGLE_REF_COUNT_SIZE      (10 * 2)
+#define VP9_TX_MODE_COUNT_START        \
+               (VP9_SINGLE_REF_COUNT_START + VP9_SINGLE_REF_COUNT_SIZE)
+#define VP9_TX_MODE_COUNT_SIZE         (12 * 2)
+#define VP9_SKIP_COUNT_START           \
+               (VP9_TX_MODE_COUNT_START + VP9_TX_MODE_COUNT_SIZE)
+#define VP9_SKIP_COUNT_SIZE            (3 * 2)
+#define VP9_MV_SIGN_0_COUNT_START      \
+               (VP9_SKIP_COUNT_START + VP9_SKIP_COUNT_SIZE)
+#define VP9_MV_SIGN_0_COUNT_SIZE       (1 * 2)
+#define VP9_MV_SIGN_1_COUNT_START      \
+               (VP9_MV_SIGN_0_COUNT_START + VP9_MV_SIGN_0_COUNT_SIZE)
+#define VP9_MV_SIGN_1_COUNT_SIZE       (1 * 2)
+#define VP9_MV_BITS_0_COUNT_START      \
+               (VP9_MV_SIGN_1_COUNT_START + VP9_MV_SIGN_1_COUNT_SIZE)
+#define VP9_MV_BITS_0_COUNT_SIZE       (10 * 2)
+#define VP9_MV_BITS_1_COUNT_START      \
+               (VP9_MV_BITS_0_COUNT_START + VP9_MV_BITS_0_COUNT_SIZE)
+#define VP9_MV_BITS_1_COUNT_SIZE       (10 * 2)
+#define VP9_MV_CLASS0_HP_0_COUNT_START \
+               (VP9_MV_BITS_1_COUNT_START + VP9_MV_BITS_1_COUNT_SIZE)
+#define VP9_MV_CLASS0_HP_0_COUNT_SIZE  (2 * 2)
+#define VP9_MV_CLASS0_HP_1_COUNT_START \
+               (VP9_MV_CLASS0_HP_0_COUNT_START + VP9_MV_CLASS0_HP_0_COUNT_SIZE)
+#define VP9_MV_CLASS0_HP_1_COUNT_SIZE  (2 * 2)
+
+/* Start merge_tree */
+#define VP9_INTER_MODE_COUNT_START     \
+               (VP9_MV_CLASS0_HP_1_COUNT_START + VP9_MV_CLASS0_HP_1_COUNT_SIZE)
+#define VP9_INTER_MODE_COUNT_SIZE      (7 * 4)
+#define VP9_IF_Y_MODE_COUNT_START      \
+               (VP9_INTER_MODE_COUNT_START + VP9_INTER_MODE_COUNT_SIZE)
+#define VP9_IF_Y_MODE_COUNT_SIZE       (10 * 4)
+#define VP9_IF_UV_MODE_COUNT_START     \
+               (VP9_IF_Y_MODE_COUNT_START + VP9_IF_Y_MODE_COUNT_SIZE)
+#define VP9_IF_UV_MODE_COUNT_SIZE      (10 * 10)
+#define VP9_PARTITION_P_COUNT_START    \
+               (VP9_IF_UV_MODE_COUNT_START + VP9_IF_UV_MODE_COUNT_SIZE)
+#define VP9_PARTITION_P_COUNT_SIZE     (4 * 4 * 4)
+#define VP9_INTERP_COUNT_START         \
+               (VP9_PARTITION_P_COUNT_START + VP9_PARTITION_P_COUNT_SIZE)
+#define VP9_INTERP_COUNT_SIZE          (4 * 3)
+#define VP9_MV_JOINTS_COUNT_START      \
+               (VP9_INTERP_COUNT_START + VP9_INTERP_COUNT_SIZE)
+#define VP9_MV_JOINTS_COUNT_SIZE       (1 * 4)
+#define VP9_MV_CLASSES_0_COUNT_START   \
+               (VP9_MV_JOINTS_COUNT_START + VP9_MV_JOINTS_COUNT_SIZE)
+#define VP9_MV_CLASSES_0_COUNT_SIZE    (1 * 11)
+#define VP9_MV_CLASS0_0_COUNT_START    \
+               (VP9_MV_CLASSES_0_COUNT_START + VP9_MV_CLASSES_0_COUNT_SIZE)
+#define VP9_MV_CLASS0_0_COUNT_SIZE     (1 * 2)
+#define VP9_MV_CLASSES_1_COUNT_START   \
+               (VP9_MV_CLASS0_0_COUNT_START + VP9_MV_CLASS0_0_COUNT_SIZE)
+#define VP9_MV_CLASSES_1_COUNT_SIZE    (1 * 11)
+#define VP9_MV_CLASS0_1_COUNT_START    \
+               (VP9_MV_CLASSES_1_COUNT_START + VP9_MV_CLASSES_1_COUNT_SIZE)
+#define VP9_MV_CLASS0_1_COUNT_SIZE     (1 * 2)
+#define VP9_MV_CLASS0_FP_0_COUNT_START \
+               (VP9_MV_CLASS0_1_COUNT_START + VP9_MV_CLASS0_1_COUNT_SIZE)
+#define VP9_MV_CLASS0_FP_0_COUNT_SIZE  (3 * 4)
+#define VP9_MV_CLASS0_FP_1_COUNT_START \
+               (VP9_MV_CLASS0_FP_0_COUNT_START + VP9_MV_CLASS0_FP_0_COUNT_SIZE)
+#define VP9_MV_CLASS0_FP_1_COUNT_SIZE  (3 * 4)
+
+#define DC_PRED    0   /* Average of above and left pixels */
+#define V_PRED     1   /* Vertical */
+#define H_PRED     2   /* Horizontal */
+#define D45_PRED   3   /* Directional 45 deg = round(arctan(1/1) * 180/pi) */
+#define D135_PRED  4   /* Directional 135 deg = 180 - 45 */
+#define D117_PRED  5   /* Directional 117 deg = 180 - 63 */
+#define D153_PRED  6   /* Directional 153 deg = 180 - 27 */
+#define D207_PRED  7   /* Directional 207 deg = 180 + 27 */
+#define D63_PRED   8   /* Directional 63 deg = round(arctan(2/1) * 180/pi) */
+#define TM_PRED    9   /* True-motion */
+
+/* Use a static inline to avoid possible side effect from num being reused */
+static inline int round_power_of_two(int value, int num)
+{
+       return (value + (1 << (num - 1))) >> num;
+}
+
+#define MODE_MV_COUNT_SAT 20
+static const int count_to_update_factor[MODE_MV_COUNT_SAT + 1] = {
+       0, 6, 12, 19, 25, 32, 38, 44, 51, 57, 64,
+       70, 76, 83, 89, 96, 102, 108, 115, 121, 128
+};
+
+union rpm_param {
+       struct {
+               u16 data[RPM_BUF_SIZE];
+       } l;
+       struct {
+               u16 profile;
+               u16 show_existing_frame;
+               u16 frame_to_show_idx;
+               u16 frame_type; /*1 bit*/
+               u16 show_frame; /*1 bit*/
+               u16 error_resilient_mode; /*1 bit*/
+               u16 intra_only; /*1 bit*/
+               u16 display_size_present; /*1 bit*/
+               u16 reset_frame_context;
+               u16 refresh_frame_flags;
+               u16 width;
+               u16 height;
+               u16 display_width;
+               u16 display_height;
+               u16 ref_info;
+               u16 same_frame_size;
+               u16 mode_ref_delta_enabled;
+               u16 ref_deltas[4];
+               u16 mode_deltas[2];
+               u16 filter_level;
+               u16 sharpness_level;
+               u16 bit_depth;
+               u16 seg_quant_info[8];
+               u16 seg_enabled;
+               u16 seg_abs_delta;
+               /* bit 15: feature enabled; bit 8, sign; bit[5:0], data */
+               u16 seg_lf_info[8];
+       } p;
+};
+
+enum SEG_LVL_FEATURES {
+       SEG_LVL_ALT_Q = 0,      /* Use alternate Quantizer */
+       SEG_LVL_ALT_LF = 1,     /* Use alternate loop filter value */
+       SEG_LVL_REF_FRAME = 2,  /* Optional Segment reference frame */
+       SEG_LVL_SKIP = 3,       /* Optional Segment (0,0) + skip mode */
+       SEG_LVL_MAX = 4         /* Number of features supported */
+};
+
+struct segmentation {
+       u8 enabled;
+       u8 update_map;
+       u8 update_data;
+       u8 abs_delta;
+       u8 temporal_update;
+       s16 feature_data[MAX_SEGMENTS][SEG_LVL_MAX];
+       unsigned int feature_mask[MAX_SEGMENTS];
+};
+
+struct loop_filter_thresh {
+       u8 mblim;
+       u8 lim;
+       u8 hev_thr;
+};
+
+struct loop_filter_info_n {
+       struct loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1];
+       u8 lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS];
+};
+
+struct loopfilter {
+       int filter_level;
+
+       int sharpness_level;
+       int last_sharpness_level;
+
+       u8 mode_ref_delta_enabled;
+       u8 mode_ref_delta_update;
+
+       /*0 = Intra, Last, GF, ARF*/
+       signed char ref_deltas[MAX_REF_LF_DELTAS];
+       signed char last_ref_deltas[MAX_REF_LF_DELTAS];
+
+       /*0 = ZERO_MV, MV*/
+       signed char mode_deltas[MAX_MODE_LF_DELTAS];
+       signed char last_mode_deltas[MAX_MODE_LF_DELTAS];
+};
+
+struct vp9_frame {
+       struct list_head list;
+       struct vb2_v4l2_buffer *vbuf;
+       int index;
+       int intra_only;
+       int show;
+       int type;
+       int done;
+       unsigned int width;
+       unsigned int height;
+};
+
+struct codec_vp9 {
+       /* VP9 context lock */
+       struct mutex lock;
+
+       /* Common part with the HEVC decoder */
+       struct codec_hevc_common common;
+
+       /* Buffer for the VP9 Workspace */
+       void      *workspace_vaddr;
+       dma_addr_t workspace_paddr;
+
+       /* Contains many information parsed from the bitstream */
+       union rpm_param rpm_param;
+
+       /* Whether we detected the bitstream as 10-bit */
+       int is_10bit;
+
+       /* Coded resolution reported by the hardware */
+       u32 width, height;
+
+       /* All ref frames used by the HW at a given time */
+       struct list_head ref_frames_list;
+       u32 frames_num;
+
+       /* In case of downsampling (decoding with FBC but outputting in NV12M),
+        * we need to allocate additional buffers for FBC.
+        */
+       void      *fbc_buffer_vaddr[MAX_REF_PIC_NUM];
+       dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM];
+
+       int ref_frame_map[REF_FRAMES];
+       int next_ref_frame_map[REF_FRAMES];
+       struct vp9_frame *frame_refs[REFS_PER_FRAME];
+
+       u32 lcu_total;
+
+       /* loop filter */
+       int default_filt_lvl;
+       struct loop_filter_info_n lfi;
+       struct loopfilter lf;
+       struct segmentation seg_4lf;
+
+       struct vp9_frame *cur_frame;
+       struct vp9_frame *prev_frame;
+};
+
+static int div_r32(s64 m, int n)
+{
+       s64 qu = div_s64(m, n);
+
+       return (int)qu;
+}
+
+static int clip_prob(int p)
+{
+       return clamp_val(p, 1, 255);
+}
+
+static int segfeature_active(struct segmentation *seg, int segment_id,
+                            enum SEG_LVL_FEATURES feature_id)
+{
+       return seg->enabled &&
+               (seg->feature_mask[segment_id] & (1 << feature_id));
+}
+
+static int get_segdata(struct segmentation *seg, int segment_id,
+                      enum SEG_LVL_FEATURES feature_id)
+{
+       return seg->feature_data[segment_id][feature_id];
+}
+
+static void vp9_update_sharpness(struct loop_filter_info_n *lfi,
+                                int sharpness_lvl)
+{
+       int lvl;
+
+       /* For each possible value for the loop filter fill out limits*/
+       for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) {
+               /* Set loop filter parameters that control sharpness.*/
+               int block_inside_limit = lvl >> ((sharpness_lvl > 0) +
+                                       (sharpness_lvl > 4));
+
+               if (sharpness_lvl > 0) {
+                       if (block_inside_limit > (9 - sharpness_lvl))
+                               block_inside_limit = (9 - sharpness_lvl);
+               }
+
+               if (block_inside_limit < 1)
+                       block_inside_limit = 1;
+
+               lfi->lfthr[lvl].lim = (u8)block_inside_limit;
+               lfi->lfthr[lvl].mblim = (u8)(2 * (lvl + 2) +
+                               block_inside_limit);
+       }
+}
+
+/* Instantiate this function once when decode is started */
+static void
+vp9_loop_filter_init(struct amvdec_core *core, struct codec_vp9 *vp9)
+{
+       struct loop_filter_info_n *lfi = &vp9->lfi;
+       struct loopfilter *lf = &vp9->lf;
+       struct segmentation *seg_4lf = &vp9->seg_4lf;
+       int i;
+
+       memset(lfi, 0, sizeof(struct loop_filter_info_n));
+       memset(lf, 0, sizeof(struct loopfilter));
+       memset(seg_4lf, 0, sizeof(struct segmentation));
+       lf->sharpness_level = 0;
+       vp9_update_sharpness(lfi, lf->sharpness_level);
+       lf->last_sharpness_level = lf->sharpness_level;
+
+       for (i = 0; i < 32; i++) {
+               unsigned int thr;
+
+               thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f) << 8) |
+                       (lfi->lfthr[i * 2 + 1].mblim & 0xff);
+               thr = (thr << 16) | ((lfi->lfthr[i * 2].lim & 0x3f) << 8) |
+                       (lfi->lfthr[i * 2].mblim & 0xff);
+
+               amvdec_write_dos(core, HEVC_DBLK_CFG9, thr);
+       }
+
+       if (core->platform->revision >= VDEC_REVISION_SM1)
+               amvdec_write_dos(core, HEVC_DBLK_CFGB,
+                                (0x3 << 14) | /* dw fifo thres r and b */
+                                (0x3 << 12) | /* dw fifo thres r or b */
+                                (0x3 << 10) | /* dw fifo thres not r/b */
+                                BIT(0)); /* VP9 video format */
+       else if (core->platform->revision >= VDEC_REVISION_G12A)
+               /* VP9 video format */
+               amvdec_write_dos(core, HEVC_DBLK_CFGB, (0x54 << 8) | BIT(0));
+       else
+               amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001);
+}
+
+static void
+vp9_loop_filter_frame_init(struct amvdec_core *core, struct segmentation *seg,
+                          struct loop_filter_info_n *lfi,
+                          struct loopfilter *lf, int default_filt_lvl)
+{
+       int i;
+       int seg_id;
+
+       /*
+        * n_shift is the multiplier for lf_deltas
+        * the multiplier is:
+        * - 1 for when filter_lvl is between 0 and 31
+        * - 2 when filter_lvl is between 32 and 63
+        */
+       const int scale = 1 << (default_filt_lvl >> 5);
+
+       /* update limits if sharpness has changed */
+       if (lf->last_sharpness_level != lf->sharpness_level) {
+               vp9_update_sharpness(lfi, lf->sharpness_level);
+               lf->last_sharpness_level = lf->sharpness_level;
+
+               /* Write to register */
+               for (i = 0; i < 32; i++) {
+                       unsigned int thr;
+
+                       thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f) << 8) |
+                             (lfi->lfthr[i * 2 + 1].mblim & 0xff);
+                       thr = (thr << 16) |
+                             ((lfi->lfthr[i * 2].lim & 0x3f) << 8) |
+                             (lfi->lfthr[i * 2].mblim & 0xff);
+
+                       amvdec_write_dos(core, HEVC_DBLK_CFG9, thr);
+               }
+       }
+
+       for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) {
+               int lvl_seg = default_filt_lvl;
+
+               if (segfeature_active(seg, seg_id, SEG_LVL_ALT_LF)) {
+                       const int data = get_segdata(seg, seg_id,
+                                               SEG_LVL_ALT_LF);
+                       lvl_seg = clamp_t(int,
+                                         seg->abs_delta == SEGMENT_ABSDATA ?
+                                               data : default_filt_lvl + data,
+                                         0, MAX_LOOP_FILTER);
+               }
+
+               if (!lf->mode_ref_delta_enabled) {
+                       /*
+                        * We could get rid of this if we assume that deltas
+                        * are set to zero when not in use.
+                        * encoder always uses deltas
+                        */
+                       memset(lfi->lvl[seg_id], lvl_seg,
+                              sizeof(lfi->lvl[seg_id]));
+               } else {
+                       int ref, mode;
+                       const int intra_lvl =
+                               lvl_seg + lf->ref_deltas[INTRA_FRAME] * scale;
+                       lfi->lvl[seg_id][INTRA_FRAME][0] =
+                               clamp_val(intra_lvl, 0, MAX_LOOP_FILTER);
+
+                       for (ref = LAST_FRAME; ref < MAX_REF_FRAMES; ++ref) {
+                               for (mode = 0; mode < MAX_MODE_LF_DELTAS;
+                                    ++mode) {
+                                       const int inter_lvl =
+                                               lvl_seg +
+                                               lf->ref_deltas[ref] * scale +
+                                               lf->mode_deltas[mode] * scale;
+                                       lfi->lvl[seg_id][ref][mode] =
+                                               clamp_val(inter_lvl, 0,
+                                                         MAX_LOOP_FILTER);
+                               }
+                       }
+               }
+       }
+
+       for (i = 0; i < 16; i++) {
+               unsigned int level;
+
+               level = ((lfi->lvl[i >> 1][3][i & 1] & 0x3f) << 24) |
+                       ((lfi->lvl[i >> 1][2][i & 1] & 0x3f) << 16) |
+                       ((lfi->lvl[i >> 1][1][i & 1] & 0x3f) << 8) |
+                       (lfi->lvl[i >> 1][0][i & 1] & 0x3f);
+               if (!default_filt_lvl)
+                       level = 0;
+
+               amvdec_write_dos(core, HEVC_DBLK_CFGA, level);
+       }
+}
+
+static void codec_vp9_flush_output(struct amvdec_session *sess)
+{
+       struct codec_vp9 *vp9 = sess->priv;
+       struct vp9_frame *tmp, *n;
+
+       mutex_lock(&vp9->lock);
+       list_for_each_entry_safe(tmp, n, &vp9->ref_frames_list, list) {
+               if (!tmp->done) {
+                       if (tmp->show)
+                               amvdec_dst_buf_done(sess, tmp->vbuf,
+                                                   V4L2_FIELD_NONE);
+                       else
+                               v4l2_m2m_buf_queue(sess->m2m_ctx, tmp->vbuf);
+
+                       vp9->frames_num--;
+               }
+
+               list_del(&tmp->list);
+               kfree(tmp);
+       }
+       mutex_unlock(&vp9->lock);
+}
+
+static u32 codec_vp9_num_pending_bufs(struct amvdec_session *sess)
+{
+       struct codec_vp9 *vp9 = sess->priv;
+
+       if (!vp9)
+               return 0;
+
+       return vp9->frames_num;
+}
+
+static int codec_vp9_alloc_workspace(struct amvdec_core *core,
+                                    struct codec_vp9 *vp9)
+{
+       /* Allocate some memory for the VP9 decoder's state */
+       vp9->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
+                                                 &vp9->workspace_paddr,
+                                                 GFP_KERNEL);
+       if (!vp9->workspace_vaddr) {
+               dev_err(core->dev, "Failed to allocate VP9 Workspace\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void codec_vp9_setup_workspace(struct amvdec_session *sess,
+                                     struct codec_vp9 *vp9)
+{
+       struct amvdec_core *core = sess->core;
+       u32 revision = core->platform->revision;
+       dma_addr_t wkaddr = vp9->workspace_paddr;
+
+       amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET);
+       amvdec_write_dos(core, VP9_RPM_BUFFER, wkaddr + RPM_OFFSET);
+       amvdec_write_dos(core, VP9_SHORT_TERM_RPS, wkaddr + SH_TM_RPS_OFFSET);
+       amvdec_write_dos(core, VP9_PPS_BUFFER, wkaddr + PPS_OFFSET);
+       amvdec_write_dos(core, VP9_SAO_UP, wkaddr + SAO_UP_OFFSET);
+
+       amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER,
+                        wkaddr + SWAP_BUF_OFFSET);
+       amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2,
+                        wkaddr + SWAP_BUF2_OFFSET);
+       amvdec_write_dos(core, VP9_SCALELUT, wkaddr + SCALELUT_OFFSET);
+
+       if (core->platform->revision >= VDEC_REVISION_G12A)
+               amvdec_write_dos(core, HEVC_DBLK_CFGE,
+                                wkaddr + DBLK_PARA_OFFSET);
+
+       amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET);
+       amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET);
+       amvdec_write_dos(core, VP9_SEG_MAP_BUFFER, wkaddr + SEG_MAP_OFFSET);
+       amvdec_write_dos(core, VP9_PROB_SWAP_BUFFER, wkaddr + PROB_OFFSET);
+       amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET);
+       amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET);
+
+       if (codec_hevc_use_mmu(revision, sess->pixfmt_cap, vp9->is_10bit)) {
+               amvdec_write_dos(core, HEVC_SAO_MMU_VH0_ADDR,
+                                wkaddr + MMU_VBH_OFFSET);
+               amvdec_write_dos(core, HEVC_SAO_MMU_VH1_ADDR,
+                                wkaddr + MMU_VBH_OFFSET + (MMU_VBH_SIZE / 2));
+
+               if (revision >= VDEC_REVISION_G12A)
+                       amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR,
+                                        vp9->common.mmu_map_paddr);
+               else
+                       amvdec_write_dos(core, VP9_MMU_MAP_BUFFER,
+                                        vp9->common.mmu_map_paddr);
+       }
+}
+
+static int codec_vp9_start(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       struct codec_vp9 *vp9;
+       u32 val;
+       int i;
+       int ret;
+
+       vp9 = kzalloc(sizeof(*vp9), GFP_KERNEL);
+       if (!vp9)
+               return -ENOMEM;
+
+       ret = codec_vp9_alloc_workspace(core, vp9);
+       if (ret)
+               goto free_vp9;
+
+       codec_vp9_setup_workspace(sess, vp9);
+       amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0));
+       /* stream_fifo_hole */
+       if (core->platform->revision >= VDEC_REVISION_G12A)
+               amvdec_write_dos_bits(core, HEVC_STREAM_FIFO_CTL, BIT(29));
+
+       val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x7fffffff;
+       val |= (3 << 29) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | BIT(0);
+       amvdec_write_dos(core, HEVC_PARSER_INT_CONTROL, val);
+       amvdec_write_dos_bits(core, HEVC_SHIFT_STATUS, BIT(0));
+       amvdec_write_dos(core, HEVC_SHIFT_CONTROL, BIT(10) | BIT(9) |
+                        (3 << 6) | BIT(5) | BIT(2) | BIT(1) | BIT(0));
+       amvdec_write_dos(core, HEVC_CABAC_CONTROL, BIT(0));
+       amvdec_write_dos(core, HEVC_PARSER_CORE_CONTROL, BIT(0));
+       amvdec_write_dos(core, HEVC_SHIFT_STARTCODE, 0x00000001);
+
+       amvdec_write_dos(core, VP9_DEC_STATUS_REG, 0);
+
+       amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16));
+       for (i = 0; i < ARRAY_SIZE(vdec_hevc_parser_cmd); ++i)
+               amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE,
+                                vdec_hevc_parser_cmd[i]);
+
+       amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0);
+       amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1);
+       amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2);
+       amvdec_write_dos(core, HEVC_PARSER_IF_CONTROL,
+                        BIT(5) | BIT(2) | BIT(0));
+
+       amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(0));
+       amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(1));
+
+       amvdec_write_dos(core, VP9_WAIT_FLAG, 1);
+
+       /* clear mailbox interrupt */
+       amvdec_write_dos(core, HEVC_ASSIST_MBOX1_CLR_REG, 1);
+       /* enable mailbox interrupt */
+       amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 1);
+       /* disable PSCALE for hardware sharing */
+       amvdec_write_dos(core, HEVC_PSCALE_CTRL, 0);
+       /* Let the uCode do all the parsing */
+       amvdec_write_dos(core, NAL_SEARCH_CTL, 0x8);
+
+       amvdec_write_dos(core, DECODE_STOP_POS, 0);
+       amvdec_write_dos(core, VP9_DECODE_MODE, DECODE_MODE_SINGLE);
+
+       pr_debug("decode_count: %u; decode_size: %u\n",
+                amvdec_read_dos(core, HEVC_DECODE_COUNT),
+                amvdec_read_dos(core, HEVC_DECODE_SIZE));
+
+       vp9_loop_filter_init(core, vp9);
+
+       INIT_LIST_HEAD(&vp9->ref_frames_list);
+       mutex_init(&vp9->lock);
+       memset(&vp9->ref_frame_map, -1, sizeof(vp9->ref_frame_map));
+       memset(&vp9->next_ref_frame_map, -1, sizeof(vp9->next_ref_frame_map));
+       for (i = 0; i < REFS_PER_FRAME; ++i)
+               vp9->frame_refs[i] = NULL;
+       sess->priv = vp9;
+
+       return 0;
+
+free_vp9:
+       kfree(vp9);
+       return ret;
+}
+
+static int codec_vp9_stop(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       struct codec_vp9 *vp9 = sess->priv;
+
+       mutex_lock(&vp9->lock);
+       if (vp9->workspace_vaddr)
+               dma_free_coherent(core->dev, SIZE_WORKSPACE,
+                                 vp9->workspace_vaddr,
+                                 vp9->workspace_paddr);
+
+       codec_hevc_free_fbc_buffers(sess, &vp9->common);
+       mutex_unlock(&vp9->lock);
+
+       return 0;
+}
+
+static void codec_vp9_set_sao(struct amvdec_session *sess,
+                             struct vb2_buffer *vb)
+{
+       struct amvdec_core *core = sess->core;
+       struct codec_vp9 *vp9 = sess->priv;
+
+       dma_addr_t buf_y_paddr;
+       dma_addr_t buf_u_v_paddr;
+       u32 val;
+
+       if (codec_hevc_use_downsample(sess->pixfmt_cap, vp9->is_10bit))
+               buf_y_paddr =
+                       vp9->common.fbc_buffer_paddr[vb->index];
+       else
+               buf_y_paddr =
+                      vb2_dma_contig_plane_dma_addr(vb, 0);
+
+       if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) {
+               val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200;
+               amvdec_write_dos(core, HEVC_SAO_CTRL5, val);
+               amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr);
+       }
+
+       if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) {
+               buf_y_paddr =
+                      vb2_dma_contig_plane_dma_addr(vb, 0);
+               buf_u_v_paddr =
+                      vb2_dma_contig_plane_dma_addr(vb, 1);
+               amvdec_write_dos(core, HEVC_SAO_Y_START_ADDR, buf_y_paddr);
+               amvdec_write_dos(core, HEVC_SAO_C_START_ADDR, buf_u_v_paddr);
+               amvdec_write_dos(core, HEVC_SAO_Y_WPTR, buf_y_paddr);
+               amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr);
+       }
+
+       if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap,
+                              vp9->is_10bit)) {
+               amvdec_write_dos(core, HEVC_CM_HEADER_START_ADDR,
+                                vp9->common.mmu_header_paddr[vb->index]);
+               /* use HEVC_CM_HEADER_START_ADDR */
+               amvdec_write_dos_bits(core, HEVC_SAO_CTRL5, BIT(10));
+       }
+
+       amvdec_write_dos(core, HEVC_SAO_Y_LENGTH,
+                        amvdec_get_output_size(sess));
+       amvdec_write_dos(core, HEVC_SAO_C_LENGTH,
+                        (amvdec_get_output_size(sess) / 2));
+
+       if (core->platform->revision >= VDEC_REVISION_G12A) {
+               amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB,
+                                     BIT(4) | BIT(5) | BIT(8) | BIT(9));
+               /* enable first, compressed write */
+               if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit))
+                       amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(8));
+
+               /* enable second, uncompressed write */
+               if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M)
+                       amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(9));
+
+               /* dblk pipeline mode=1 for performance */
+               if (sess->width >= 1280)
+                       amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(4));
+
+               pr_debug("HEVC_DBLK_CFGB: %08X\n",
+                        amvdec_read_dos(core, HEVC_DBLK_CFGB));
+       }
+
+       val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff0;
+       val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */
+       if (core->platform->revision < VDEC_REVISION_G12A) {
+               val &= ~0x3;
+               if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit))
+                       val |= BIT(0); /* disable cm compression */
+               /* TOFIX: Handle Amlogic Framebuffer compression */
+       }
+
+       amvdec_write_dos(core, HEVC_SAO_CTRL1, val);
+       pr_debug("HEVC_SAO_CTRL1: %08X\n", val);
+
+       /* no downscale for NV12 */
+       val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000;
+       amvdec_write_dos(core, HEVC_SAO_CTRL5, val);
+
+       val = amvdec_read_dos(core, HEVCD_IPP_AXIIF_CONFIG) & ~0x30;
+       val |= 0xf;
+       val &= ~BIT(12); /* NV12 */
+       amvdec_write_dos(core, HEVCD_IPP_AXIIF_CONFIG, val);
+}
+
+static dma_addr_t codec_vp9_get_frame_mv_paddr(struct codec_vp9 *vp9,
+                                              struct vp9_frame *frame)
+{
+       return vp9->workspace_paddr + MPRED_MV_OFFSET +
+              (frame->index * MPRED_MV_BUF_SIZE);
+}
+
+static void codec_vp9_set_mpred_mv(struct amvdec_core *core,
+                                  struct codec_vp9 *vp9)
+{
+       int mpred_mv_rd_end_addr;
+       int use_prev_frame_mvs = vp9->prev_frame->width ==
+                                       vp9->cur_frame->width &&
+                                vp9->prev_frame->height ==
+                                       vp9->cur_frame->height &&
+                                !vp9->prev_frame->intra_only &&
+                                vp9->prev_frame->show &&
+                                vp9->prev_frame->type != KEY_FRAME;
+
+       amvdec_write_dos(core, HEVC_MPRED_CTRL3, 0x24122412);
+       amvdec_write_dos(core, HEVC_MPRED_ABV_START_ADDR,
+                        vp9->workspace_paddr + MPRED_ABV_OFFSET);
+
+       amvdec_clear_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6));
+       if (use_prev_frame_mvs)
+               amvdec_write_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6));
+
+       amvdec_write_dos(core, HEVC_MPRED_MV_WR_START_ADDR,
+                        codec_vp9_get_frame_mv_paddr(vp9, vp9->cur_frame));
+       amvdec_write_dos(core, HEVC_MPRED_MV_WPTR,
+                        codec_vp9_get_frame_mv_paddr(vp9, vp9->cur_frame));
+
+       amvdec_write_dos(core, HEVC_MPRED_MV_RD_START_ADDR,
+                        codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame));
+       amvdec_write_dos(core, HEVC_MPRED_MV_RPTR,
+                        codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame));
+
+       mpred_mv_rd_end_addr =
+                       codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame) +
+                       (vp9->lcu_total * MV_MEM_UNIT);
+       amvdec_write_dos(core, HEVC_MPRED_MV_RD_END_ADDR, mpred_mv_rd_end_addr);
+}
+
+static void codec_vp9_update_next_ref(struct codec_vp9 *vp9)
+{
+       union rpm_param *param = &vp9->rpm_param;
+       u32 buf_idx = vp9->cur_frame->index;
+       int ref_index = 0;
+       int refresh_frame_flags;
+       int mask;
+
+       refresh_frame_flags = vp9->cur_frame->type == KEY_FRAME ?
+                               0xff : param->p.refresh_frame_flags;
+
+       for (mask = refresh_frame_flags; mask; mask >>= 1) {
+               pr_debug("mask=%08X; ref_index=%d\n", mask, ref_index);
+               if (mask & 1)
+                       vp9->next_ref_frame_map[ref_index] = buf_idx;
+               else
+                       vp9->next_ref_frame_map[ref_index] =
+                               vp9->ref_frame_map[ref_index];
+
+               ++ref_index;
+       }
+
+       for (; ref_index < REF_FRAMES; ++ref_index)
+               vp9->next_ref_frame_map[ref_index] =
+                       vp9->ref_frame_map[ref_index];
+}
+
+static void codec_vp9_save_refs(struct codec_vp9 *vp9)
+{
+       union rpm_param *param = &vp9->rpm_param;
+       int i;
+
+       for (i = 0; i < REFS_PER_FRAME; ++i) {
+               const int ref = (param->p.ref_info >>
+                                (((REFS_PER_FRAME - i - 1) * 4) + 1)) & 0x7;
+
+               if (vp9->ref_frame_map[ref] < 0)
+                       continue;
+
+               pr_warn("%s: FIXME, would need to save ref %d\n",
+                       __func__, vp9->ref_frame_map[ref]);
+       }
+}
+
+static void codec_vp9_update_ref(struct codec_vp9 *vp9)
+{
+       union rpm_param *param = &vp9->rpm_param;
+       int ref_index = 0;
+       int mask;
+       int refresh_frame_flags;
+
+       if (!vp9->cur_frame)
+               return;
+
+       refresh_frame_flags = vp9->cur_frame->type == KEY_FRAME ?
+                               0xff : param->p.refresh_frame_flags;
+
+       for (mask = refresh_frame_flags; mask; mask >>= 1) {
+               vp9->ref_frame_map[ref_index] =
+                       vp9->next_ref_frame_map[ref_index];
+               ++ref_index;
+       }
+
+       if (param->p.show_existing_frame)
+               return;
+
+       for (; ref_index < REF_FRAMES; ++ref_index)
+               vp9->ref_frame_map[ref_index] =
+                       vp9->next_ref_frame_map[ref_index];
+}
+
+static struct vp9_frame *codec_vp9_get_frame_by_idx(struct codec_vp9 *vp9,
+                                                   int idx)
+{
+       struct vp9_frame *frame;
+
+       list_for_each_entry(frame, &vp9->ref_frames_list, list) {
+               if (frame->index == idx)
+                       return frame;
+       }
+
+       return NULL;
+}
+
+static void codec_vp9_sync_ref(struct codec_vp9 *vp9)
+{
+       union rpm_param *param = &vp9->rpm_param;
+       int i;
+
+       for (i = 0; i < REFS_PER_FRAME; ++i) {
+               const int ref = (param->p.ref_info >>
+                                (((REFS_PER_FRAME - i - 1) * 4) + 1)) & 0x7;
+               const int idx = vp9->ref_frame_map[ref];
+
+               vp9->frame_refs[i] = codec_vp9_get_frame_by_idx(vp9, idx);
+               if (!vp9->frame_refs[i])
+                       pr_warn("%s: couldn't find VP9 ref %d\n", __func__,
+                               idx);
+       }
+}
+
+static void codec_vp9_set_refs(struct amvdec_session *sess,
+                              struct codec_vp9 *vp9)
+{
+       struct amvdec_core *core = sess->core;
+       int i;
+
+       for (i = 0; i < REFS_PER_FRAME; ++i) {
+               struct vp9_frame *frame = vp9->frame_refs[i];
+               int id_y;
+               int id_u_v;
+
+               if (!frame)
+                       continue;
+
+               if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) {
+                       id_y = frame->index;
+                       id_u_v = id_y;
+               } else {
+                       id_y = frame->index * 2;
+                       id_u_v = id_y + 1;
+               }
+
+               amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR,
+                                (id_u_v << 16) | (id_u_v << 8) | id_y);
+       }
+}
+
+static void codec_vp9_set_mc(struct amvdec_session *sess,
+                            struct codec_vp9 *vp9)
+{
+       struct amvdec_core *core = sess->core;
+       u32 scale = 0;
+       u32 sz;
+       int i;
+
+       amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1);
+       codec_vp9_set_refs(sess, vp9);
+       amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR,
+                        (16 << 8) | 1);
+       codec_vp9_set_refs(sess, vp9);
+
+       amvdec_write_dos(core, VP9D_MPP_REFINFO_TBL_ACCCONFIG, BIT(2));
+       for (i = 0; i < REFS_PER_FRAME; ++i) {
+               if (!vp9->frame_refs[i])
+                       continue;
+
+               if (vp9->frame_refs[i]->width != vp9->width ||
+                   vp9->frame_refs[i]->height != vp9->height)
+                       scale = 1;
+
+               sz = amvdec_am21c_body_size(vp9->frame_refs[i]->width,
+                                           vp9->frame_refs[i]->height);
+
+               amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA,
+                                vp9->frame_refs[i]->width);
+               amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA,
+                                vp9->frame_refs[i]->height);
+               amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA,
+                                (vp9->frame_refs[i]->width << 14) /
+                                vp9->width);
+               amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA,
+                                (vp9->frame_refs[i]->height << 14) /
+                                vp9->height);
+               amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, sz >> 5);
+       }
+
+       amvdec_write_dos(core, VP9D_MPP_REF_SCALE_ENBL, scale);
+}
+
+static struct vp9_frame *codec_vp9_get_new_frame(struct amvdec_session *sess)
+{
+       struct codec_vp9 *vp9 = sess->priv;
+       union rpm_param *param = &vp9->rpm_param;
+       struct vb2_v4l2_buffer *vbuf;
+       struct vp9_frame *new_frame;
+
+       new_frame = kzalloc(sizeof(*new_frame), GFP_KERNEL);
+       if (!new_frame)
+               return NULL;
+
+       vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx);
+       if (!vbuf) {
+               dev_err(sess->core->dev, "No dst buffer available\n");
+               kfree(new_frame);
+               return NULL;
+       }
+
+       while (codec_vp9_get_frame_by_idx(vp9, vbuf->vb2_buf.index)) {
+               struct vb2_v4l2_buffer *old_vbuf = vbuf;
+
+               vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx);
+               v4l2_m2m_buf_queue(sess->m2m_ctx, old_vbuf);
+               if (!vbuf) {
+                       dev_err(sess->core->dev, "No dst buffer available\n");
+                       kfree(new_frame);
+                       return NULL;
+               }
+       }
+
+       new_frame->vbuf = vbuf;
+       new_frame->index = vbuf->vb2_buf.index;
+       new_frame->intra_only = param->p.intra_only;
+       new_frame->show = param->p.show_frame;
+       new_frame->type = param->p.frame_type;
+       new_frame->width = vp9->width;
+       new_frame->height = vp9->height;
+       list_add_tail(&new_frame->list, &vp9->ref_frames_list);
+       vp9->frames_num++;
+
+       return new_frame;
+}
+
+static void codec_vp9_show_existing_frame(struct codec_vp9 *vp9)
+{
+       union rpm_param *param = &vp9->rpm_param;
+
+       if (!param->p.show_existing_frame)
+               return;
+
+       pr_debug("showing frame %u\n", param->p.frame_to_show_idx);
+}
+
+static void codec_vp9_rm_noshow_frame(struct amvdec_session *sess)
+{
+       struct codec_vp9 *vp9 = sess->priv;
+       struct vp9_frame *tmp;
+
+       list_for_each_entry(tmp, &vp9->ref_frames_list, list) {
+               if (tmp->show)
+                       continue;
+
+               pr_debug("rm noshow: %u\n", tmp->index);
+               v4l2_m2m_buf_queue(sess->m2m_ctx, tmp->vbuf);
+               list_del(&tmp->list);
+               kfree(tmp);
+               vp9->frames_num--;
+               return;
+       }
+}
+
+static void codec_vp9_process_frame(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       struct codec_vp9 *vp9 = sess->priv;
+       union rpm_param *param = &vp9->rpm_param;
+       int intra_only;
+
+       if (!param->p.show_frame)
+               codec_vp9_rm_noshow_frame(sess);
+
+       vp9->cur_frame = codec_vp9_get_new_frame(sess);
+       if (!vp9->cur_frame)
+               return;
+
+       pr_debug("frame %d: type: %08X; show_exist: %u; show: %u, intra_only: %u\n",
+                vp9->cur_frame->index,
+                param->p.frame_type, param->p.show_existing_frame,
+                param->p.show_frame, param->p.intra_only);
+
+       if (param->p.frame_type != KEY_FRAME)
+               codec_vp9_sync_ref(vp9);
+       codec_vp9_update_next_ref(vp9);
+       codec_vp9_show_existing_frame(vp9);
+
+       if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap,
+                              vp9->is_10bit))
+               codec_hevc_fill_mmu_map(sess, &vp9->common,
+                                       &vp9->cur_frame->vbuf->vb2_buf);
+
+       intra_only = param->p.show_frame ? 0 : param->p.intra_only;
+
+       /* clear mpred (for keyframe only) */
+       if (param->p.frame_type != KEY_FRAME && !intra_only) {
+               codec_vp9_set_mc(sess, vp9);
+               codec_vp9_set_mpred_mv(core, vp9);
+       } else {
+               amvdec_clear_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6));
+       }
+
+       amvdec_write_dos(core, HEVC_PARSER_PICTURE_SIZE,
+                        (vp9->height << 16) | vp9->width);
+       codec_vp9_set_sao(sess, &vp9->cur_frame->vbuf->vb2_buf);
+
+       vp9_loop_filter_frame_init(core, &vp9->seg_4lf,
+                                  &vp9->lfi, &vp9->lf,
+                                  vp9->default_filt_lvl);
+
+       /* ask uCode to start decoding */
+       amvdec_write_dos(core, VP9_DEC_STATUS_REG, VP9_10B_DECODE_SLICE);
+}
+
+static void codec_vp9_process_lf(struct codec_vp9 *vp9)
+{
+       union rpm_param *param = &vp9->rpm_param;
+       int i;
+
+       vp9->lf.mode_ref_delta_enabled = param->p.mode_ref_delta_enabled;
+       vp9->lf.sharpness_level = param->p.sharpness_level;
+       vp9->default_filt_lvl = param->p.filter_level;
+       vp9->seg_4lf.enabled = param->p.seg_enabled;
+       vp9->seg_4lf.abs_delta = param->p.seg_abs_delta;
+
+       for (i = 0; i < 4; i++)
+               vp9->lf.ref_deltas[i] = param->p.ref_deltas[i];
+
+       for (i = 0; i < 2; i++)
+               vp9->lf.mode_deltas[i] = param->p.mode_deltas[i];
+
+       for (i = 0; i < MAX_SEGMENTS; i++)
+               vp9->seg_4lf.feature_mask[i] =
+                       (param->p.seg_lf_info[i] & 0x8000) ?
+                               (1 << SEG_LVL_ALT_LF) : 0;
+
+       for (i = 0; i < MAX_SEGMENTS; i++)
+               vp9->seg_4lf.feature_data[i][SEG_LVL_ALT_LF] =
+                       (param->p.seg_lf_info[i] & 0x100) ?
+                               -(param->p.seg_lf_info[i] & 0x3f)
+                               : (param->p.seg_lf_info[i] & 0x3f);
+}
+
+static void codec_vp9_resume(struct amvdec_session *sess)
+{
+       struct codec_vp9 *vp9 = sess->priv;
+
+       mutex_lock(&vp9->lock);
+       if (codec_hevc_setup_buffers(sess, &vp9->common, vp9->is_10bit)) {
+               mutex_unlock(&vp9->lock);
+               amvdec_abort(sess);
+               return;
+       }
+
+       codec_vp9_setup_workspace(sess, vp9);
+       codec_hevc_setup_decode_head(sess, vp9->is_10bit);
+       codec_vp9_process_lf(vp9);
+       codec_vp9_process_frame(sess);
+
+       mutex_unlock(&vp9->lock);
+}
+
+/*
+ * The RPM section within the workspace contains
+ * many information regarding the parsed bitstream
+ */
+static void codec_vp9_fetch_rpm(struct amvdec_session *sess)
+{
+       struct codec_vp9 *vp9 = sess->priv;
+       u16 *rpm_vaddr = vp9->workspace_vaddr + RPM_OFFSET;
+       int i, j;
+
+       for (i = 0; i < RPM_BUF_SIZE; i += 4)
+               for (j = 0; j < 4; j++)
+                       vp9->rpm_param.l.data[i + j] = rpm_vaddr[i + 3 - j];
+}
+
+static int codec_vp9_process_rpm(struct codec_vp9 *vp9)
+{
+       union rpm_param *param = &vp9->rpm_param;
+       int src_changed = 0;
+       int is_10bit = 0;
+       int pic_width_64 = ALIGN(param->p.width, 64);
+       int pic_height_32 = ALIGN(param->p.height, 32);
+       int pic_width_lcu  = (pic_width_64 % LCU_SIZE) ?
+                               pic_width_64 / LCU_SIZE  + 1
+                               : pic_width_64 / LCU_SIZE;
+       int pic_height_lcu = (pic_height_32 % LCU_SIZE) ?
+                               pic_height_32 / LCU_SIZE + 1
+                               : pic_height_32 / LCU_SIZE;
+       vp9->lcu_total = pic_width_lcu * pic_height_lcu;
+
+       if (param->p.bit_depth == 10)
+               is_10bit = 1;
+
+       if (vp9->width != param->p.width || vp9->height != param->p.height ||
+           vp9->is_10bit != is_10bit)
+               src_changed = 1;
+
+       vp9->width = param->p.width;
+       vp9->height = param->p.height;
+       vp9->is_10bit = is_10bit;
+
+       pr_debug("width: %u; height: %u; is_10bit: %d; src_changed: %d\n",
+                vp9->width, vp9->height, is_10bit, src_changed);
+
+       return src_changed;
+}
+
+static bool codec_vp9_is_ref(struct codec_vp9 *vp9, struct vp9_frame *frame)
+{
+       int i;
+
+       for (i = 0; i < REF_FRAMES; ++i)
+               if (vp9->ref_frame_map[i] == frame->index)
+                       return true;
+
+       return false;
+}
+
+static void codec_vp9_show_frame(struct amvdec_session *sess)
+{
+       struct codec_vp9 *vp9 = sess->priv;
+       struct vp9_frame *tmp, *n;
+
+       list_for_each_entry_safe(tmp, n, &vp9->ref_frames_list, list) {
+               if (!tmp->show || tmp == vp9->cur_frame)
+                       continue;
+
+               if (!tmp->done) {
+                       pr_debug("Doning %u\n", tmp->index);
+                       amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE);
+                       tmp->done = 1;
+                       vp9->frames_num--;
+               }
+
+               if (codec_vp9_is_ref(vp9, tmp) || tmp == vp9->prev_frame)
+                       continue;
+
+               pr_debug("deleting %d\n", tmp->index);
+               list_del(&tmp->list);
+               kfree(tmp);
+       }
+}
+
+static void vp9_tree_merge_probs(unsigned int *prev_prob,
+                                unsigned int *cur_prob,
+                                int coef_node_start, int tree_left,
+                                int tree_right,
+                                int tree_i, int node)
+{
+       int prob_32, prob_res, prob_shift;
+       int pre_prob, new_prob;
+       int den, m_count, get_prob, factor;
+
+       prob_32 = prev_prob[coef_node_start / 4 * 2];
+       prob_res = coef_node_start & 3;
+       prob_shift = prob_res * 8;
+       pre_prob = (prob_32 >> prob_shift) & 0xff;
+
+       den = tree_left + tree_right;
+
+       if (den == 0) {
+               new_prob = pre_prob;
+       } else {
+               m_count = den < MODE_MV_COUNT_SAT ? den : MODE_MV_COUNT_SAT;
+               get_prob =
+                       clip_prob(div_r32(((int64_t)tree_left * 256 +
+                                          (den >> 1)),
+                                         den));
+
+               /* weighted_prob */
+               factor = count_to_update_factor[m_count];
+               new_prob = round_power_of_two(pre_prob * (256 - factor) +
+                                             get_prob * factor, 8);
+       }
+
+       cur_prob[coef_node_start / 4 * 2] =
+               (cur_prob[coef_node_start / 4 * 2] & (~(0xff << prob_shift))) |
+               (new_prob << prob_shift);
+}
+
+static void adapt_coef_probs_cxt(unsigned int *prev_prob,
+                                unsigned int *cur_prob,
+                                unsigned int *count,
+                                int update_factor,
+                                int cxt_num,
+                                int coef_cxt_start,
+                                int coef_count_cxt_start)
+{
+       int prob_32, prob_res, prob_shift;
+       int pre_prob, new_prob;
+       int num, den, m_count, get_prob, factor;
+       int node, coef_node_start;
+       int count_sat = 24;
+       int cxt;
+
+       for (cxt = 0; cxt < cxt_num; cxt++) {
+               const int n0 = count[coef_count_cxt_start];
+               const int n1 = count[coef_count_cxt_start + 1];
+               const int n2 = count[coef_count_cxt_start + 2];
+               const int neob = count[coef_count_cxt_start + 3];
+               const int nneob = count[coef_count_cxt_start + 4];
+               const unsigned int branch_ct[3][2] = {
+                       { neob, nneob },
+                       { n0, n1 + n2 },
+                       { n1, n2 }
+               };
+
+               coef_node_start = coef_cxt_start;
+               for (node = 0 ; node < 3 ; node++) {
+                       prob_32 = prev_prob[coef_node_start / 4 * 2];
+                       prob_res = coef_node_start & 3;
+                       prob_shift = prob_res * 8;
+                       pre_prob = (prob_32 >> prob_shift) & 0xff;
+
+                       /* get binary prob */
+                       num = branch_ct[node][0];
+                       den = branch_ct[node][0] + branch_ct[node][1];
+                       m_count = den < count_sat ? den : count_sat;
+
+                       get_prob = (den == 0) ?
+                                       128u :
+                                       clip_prob(div_r32(((int64_t)num * 256 +
+                                                         (den >> 1)), den));
+
+                       factor = update_factor * m_count / count_sat;
+                       new_prob =
+                               round_power_of_two(pre_prob * (256 - factor) +
+                                                  get_prob * factor, 8);
+
+                       cur_prob[coef_node_start / 4 * 2] =
+                               (cur_prob[coef_node_start / 4 * 2] &
+                                (~(0xff << prob_shift))) |
+                               (new_prob << prob_shift);
+
+                       coef_node_start += 1;
+               }
+
+               coef_cxt_start = coef_cxt_start + 3;
+               coef_count_cxt_start = coef_count_cxt_start + 5;
+       }
+}
+
+static void adapt_coef_probs(int prev_kf, int cur_kf, int pre_fc,
+                            unsigned int *prev_prob, unsigned int *cur_prob,
+                            unsigned int *count)
+{
+       int tx_size, coef_tx_size_start, coef_count_tx_size_start;
+       int plane, coef_plane_start, coef_count_plane_start;
+       int type, coef_type_start, coef_count_type_start;
+       int band, coef_band_start, coef_count_band_start;
+       int cxt_num;
+       int coef_cxt_start, coef_count_cxt_start;
+       int node, coef_node_start, coef_count_node_start;
+
+       int tree_i, tree_left, tree_right;
+       int mvd_i;
+
+       int update_factor = cur_kf ? 112 : (prev_kf ? 128 : 112);
+
+       int prob_32;
+       int prob_res;
+       int prob_shift;
+       int pre_prob;
+
+       int den;
+       int get_prob;
+       int m_count;
+       int factor;
+
+       int new_prob;
+
+       for (tx_size = 0 ; tx_size < 4 ; tx_size++) {
+               coef_tx_size_start = VP9_COEF_START +
+                               tx_size * 4 * VP9_COEF_SIZE_ONE_SET;
+               coef_count_tx_size_start = VP9_COEF_COUNT_START +
+                               tx_size * 4 * VP9_COEF_COUNT_SIZE_ONE_SET;
+               coef_plane_start = coef_tx_size_start;
+               coef_count_plane_start = coef_count_tx_size_start;
+
+               for (plane = 0 ; plane < 2 ; plane++) {
+                       coef_type_start = coef_plane_start;
+                       coef_count_type_start = coef_count_plane_start;
+
+                       for (type = 0 ; type < 2 ; type++) {
+                               coef_band_start = coef_type_start;
+                               coef_count_band_start = coef_count_type_start;
+
+                               for (band = 0 ; band < 6 ; band++) {
+                                       if (band == 0)
+                                               cxt_num = 3;
+                                       else
+                                               cxt_num = 6;
+                                       coef_cxt_start = coef_band_start;
+                                       coef_count_cxt_start =
+                                               coef_count_band_start;
+
+                                       adapt_coef_probs_cxt(prev_prob,
+                                                            cur_prob,
+                                                            count,
+                                                            update_factor,
+                                                            cxt_num,
+                                                            coef_cxt_start,
+                                                       coef_count_cxt_start);
+
+                                       if (band == 0) {
+                                               coef_band_start += 10;
+                                               coef_count_band_start += 15;
+                                       } else {
+                                               coef_band_start += 18;
+                                               coef_count_band_start += 30;
+                                       }
+                               }
+                               coef_type_start += VP9_COEF_SIZE_ONE_SET;
+                               coef_count_type_start +=
+                                       VP9_COEF_COUNT_SIZE_ONE_SET;
+                       }
+
+                       coef_plane_start += 2 * VP9_COEF_SIZE_ONE_SET;
+                       coef_count_plane_start +=
+                               2 * VP9_COEF_COUNT_SIZE_ONE_SET;
+               }
+       }
+
+       if (cur_kf == 0) {
+               /* mode_mv_merge_probs - merge_intra_inter_prob */
+               for (coef_count_node_start = VP9_INTRA_INTER_COUNT_START;
+                    coef_count_node_start < (VP9_MV_CLASS0_HP_1_COUNT_START +
+                                             VP9_MV_CLASS0_HP_1_COUNT_SIZE);
+                    coef_count_node_start += 2) {
+                       if (coef_count_node_start ==
+                                       VP9_INTRA_INTER_COUNT_START)
+                               coef_node_start = VP9_INTRA_INTER_START;
+                       else if (coef_count_node_start ==
+                                       VP9_COMP_INTER_COUNT_START)
+                               coef_node_start = VP9_COMP_INTER_START;
+                       else if (coef_count_node_start ==
+                                       VP9_TX_MODE_COUNT_START)
+                               coef_node_start = VP9_TX_MODE_START;
+                       else if (coef_count_node_start ==
+                                       VP9_SKIP_COUNT_START)
+                               coef_node_start = VP9_SKIP_START;
+                       else if (coef_count_node_start ==
+                                       VP9_MV_SIGN_0_COUNT_START)
+                               coef_node_start = VP9_MV_SIGN_0_START;
+                       else if (coef_count_node_start ==
+                                       VP9_MV_SIGN_1_COUNT_START)
+                               coef_node_start = VP9_MV_SIGN_1_START;
+                       else if (coef_count_node_start ==
+                                       VP9_MV_BITS_0_COUNT_START)
+                               coef_node_start = VP9_MV_BITS_0_START;
+                       else if (coef_count_node_start ==
+                                       VP9_MV_BITS_1_COUNT_START)
+                               coef_node_start = VP9_MV_BITS_1_START;
+                       else if (coef_count_node_start ==
+                                       VP9_MV_CLASS0_HP_0_COUNT_START)
+                               coef_node_start = VP9_MV_CLASS0_HP_0_START;
+
+                       den = count[coef_count_node_start] +
+                             count[coef_count_node_start + 1];
+
+                       prob_32 = prev_prob[coef_node_start / 4 * 2];
+                       prob_res = coef_node_start & 3;
+                       prob_shift = prob_res * 8;
+                       pre_prob = (prob_32 >> prob_shift) & 0xff;
+
+                       if (den == 0) {
+                               new_prob = pre_prob;
+                       } else {
+                               m_count = den < MODE_MV_COUNT_SAT ?
+                                               den : MODE_MV_COUNT_SAT;
+                               get_prob =
+                               clip_prob(div_r32(((int64_t)
+                                       count[coef_count_node_start] * 256 +
+                                       (den >> 1)),
+                                       den));
+
+                               /* weighted prob */
+                               factor = count_to_update_factor[m_count];
+                               new_prob =
+                                       round_power_of_two(pre_prob *
+                                                          (256 - factor) +
+                                                          get_prob * factor,
+                                                          8);
+                       }
+
+                       cur_prob[coef_node_start / 4 * 2] =
+                               (cur_prob[coef_node_start / 4 * 2] &
+                                (~(0xff << prob_shift))) |
+                               (new_prob << prob_shift);
+
+                       coef_node_start = coef_node_start + 1;
+               }
+
+               coef_node_start = VP9_INTER_MODE_START;
+               coef_count_node_start = VP9_INTER_MODE_COUNT_START;
+               for (tree_i = 0 ; tree_i < 7 ; tree_i++) {
+                       for (node = 0 ; node < 3 ; node++) {
+                               unsigned int start = coef_count_node_start;
+
+                               switch (node) {
+                               case 2:
+                                       tree_left = count[start + 1];
+                                       tree_right = count[start + 3];
+                                       break;
+                               case 1:
+                                       tree_left = count[start + 0];
+                                       tree_right = count[start + 1] +
+                                                    count[start + 3];
+                                       break;
+                               default:
+                                       tree_left = count[start + 2];
+                                       tree_right = count[start + 0] +
+                                                    count[start + 1] +
+                                                    count[start + 3];
+                                       break;
+                               }
+
+                               vp9_tree_merge_probs(prev_prob, cur_prob,
+                                                    coef_node_start,
+                                                    tree_left, tree_right,
+                                                    tree_i, node);
+
+                               coef_node_start = coef_node_start + 1;
+                       }
+
+                       coef_count_node_start = coef_count_node_start + 4;
+               }
+
+               coef_node_start = VP9_IF_Y_MODE_START;
+               coef_count_node_start = VP9_IF_Y_MODE_COUNT_START;
+               for (tree_i = 0 ; tree_i < 14 ; tree_i++) {
+                       for (node = 0 ; node < 9 ; node++) {
+                               unsigned int start = coef_count_node_start;
+
+                               switch (node) {
+                               case 8:
+                                       tree_left =
+                                               count[start + D153_PRED];
+                                       tree_right =
+                                               count[start + D207_PRED];
+                                       break;
+                               case 7:
+                                       tree_left =
+                                               count[start + D63_PRED];
+                                       tree_right =
+                                               count[start + D207_PRED] +
+                                               count[start + D153_PRED];
+                                       break;
+                               case 6:
+                                       tree_left =
+                                               count[start + D45_PRED];
+                                       tree_right =
+                                               count[start + D207_PRED] +
+                                               count[start + D153_PRED] +
+                                               count[start + D63_PRED];
+                                       break;
+                               case 5:
+                                       tree_left =
+                                               count[start + D135_PRED];
+                                       tree_right =
+                                               count[start + D117_PRED];
+                                       break;
+                               case 4:
+                                       tree_left =
+                                               count[start + H_PRED];
+                                       tree_right =
+                                               count[start + D117_PRED] +
+                                               count[start + D135_PRED];
+                                       break;
+                               case 3:
+                                       tree_left =
+                                               count[start + H_PRED] +
+                                               count[start + D117_PRED] +
+                                               count[start + D135_PRED];
+                                       tree_right =
+                                               count[start + D45_PRED] +
+                                               count[start + D207_PRED] +
+                                               count[start + D153_PRED] +
+                                               count[start + D63_PRED];
+                                       break;
+                               case 2:
+                                       tree_left =
+                                               count[start + V_PRED];
+                                       tree_right =
+                                               count[start + H_PRED] +
+                                               count[start + D117_PRED] +
+                                               count[start + D135_PRED] +
+                                               count[start + D45_PRED] +
+                                               count[start + D207_PRED] +
+                                               count[start + D153_PRED] +
+                                               count[start + D63_PRED];
+                                       break;
+                               case 1:
+                                       tree_left =
+                                               count[start + TM_PRED];
+                                       tree_right =
+                                               count[start + V_PRED] +
+                                               count[start + H_PRED] +
+                                               count[start + D117_PRED] +
+                                               count[start + D135_PRED] +
+                                               count[start + D45_PRED] +
+                                               count[start + D207_PRED] +
+                                               count[start + D153_PRED] +
+                                               count[start + D63_PRED];
+                                       break;
+                               default:
+                                       tree_left =
+                                               count[start + DC_PRED];
+                                       tree_right =
+                                               count[start + TM_PRED] +
+                                               count[start + V_PRED] +
+                                               count[start + H_PRED] +
+                                               count[start + D117_PRED] +
+                                               count[start + D135_PRED] +
+                                               count[start + D45_PRED] +
+                                               count[start + D207_PRED] +
+                                               count[start + D153_PRED] +
+                                               count[start + D63_PRED];
+                                       break;
+                               }
+
+                               vp9_tree_merge_probs(prev_prob, cur_prob,
+                                                    coef_node_start,
+                                                    tree_left, tree_right,
+                                                    tree_i, node);
+
+                               coef_node_start = coef_node_start + 1;
+                       }
+                       coef_count_node_start = coef_count_node_start + 10;
+               }
+
+               coef_node_start = VP9_PARTITION_P_START;
+               coef_count_node_start = VP9_PARTITION_P_COUNT_START;
+               for (tree_i = 0 ; tree_i < 16 ; tree_i++) {
+                       for (node = 0 ; node < 3 ; node++) {
+                               unsigned int start = coef_count_node_start;
+
+                               switch (node) {
+                               case 2:
+                                       tree_left = count[start + 2];
+                                       tree_right = count[start + 3];
+                                       break;
+                               case 1:
+                                       tree_left = count[start + 1];
+                                       tree_right = count[start + 2] +
+                                                    count[start + 3];
+                                       break;
+                               default:
+                                       tree_left = count[start + 0];
+                                       tree_right = count[start + 1] +
+                                                    count[start + 2] +
+                                                    count[start + 3];
+                                       break;
+                               }
+
+                               vp9_tree_merge_probs(prev_prob, cur_prob,
+                                                    coef_node_start,
+                                                    tree_left, tree_right,
+                                                    tree_i, node);
+
+                               coef_node_start = coef_node_start + 1;
+                       }
+
+                       coef_count_node_start = coef_count_node_start + 4;
+               }
+
+               coef_node_start = VP9_INTERP_START;
+               coef_count_node_start = VP9_INTERP_COUNT_START;
+               for (tree_i = 0 ; tree_i < 4 ; tree_i++) {
+                       for (node = 0 ; node < 2 ; node++) {
+                               unsigned int start = coef_count_node_start;
+
+                               switch (node) {
+                               case 1:
+                                       tree_left = count[start + 1];
+                                       tree_right = count[start + 2];
+                                       break;
+                               default:
+                                       tree_left = count[start + 0];
+                                       tree_right = count[start + 1] +
+                                                    count[start + 2];
+                                       break;
+                               }
+
+                               vp9_tree_merge_probs(prev_prob, cur_prob,
+                                                    coef_node_start,
+                                                    tree_left, tree_right,
+                                                    tree_i, node);
+
+                               coef_node_start = coef_node_start + 1;
+                       }
+                       coef_count_node_start = coef_count_node_start + 3;
+               }
+
+               coef_node_start = VP9_MV_JOINTS_START;
+               coef_count_node_start = VP9_MV_JOINTS_COUNT_START;
+               for (tree_i = 0 ; tree_i < 1 ; tree_i++) {
+                       for (node = 0 ; node < 3 ; node++) {
+                               unsigned int start = coef_count_node_start;
+
+                               switch (node) {
+                               case 2:
+                                       tree_left = count[start + 2];
+                                       tree_right = count[start + 3];
+                                       break;
+                               case 1:
+                                       tree_left = count[start + 1];
+                                       tree_right = count[start + 2] +
+                                                    count[start + 3];
+                                       break;
+                               default:
+                                       tree_left = count[start + 0];
+                                       tree_right = count[start + 1] +
+                                                    count[start + 2] +
+                                                    count[start + 3];
+                                       break;
+                               }
+
+                               vp9_tree_merge_probs(prev_prob, cur_prob,
+                                                    coef_node_start,
+                                                    tree_left, tree_right,
+                                                    tree_i, node);
+
+                               coef_node_start = coef_node_start + 1;
+                       }
+                       coef_count_node_start = coef_count_node_start + 4;
+               }
+
+               for (mvd_i = 0 ; mvd_i < 2 ; mvd_i++) {
+                       coef_node_start = mvd_i ? VP9_MV_CLASSES_1_START :
+                                                 VP9_MV_CLASSES_0_START;
+                       coef_count_node_start = mvd_i ?
+                                       VP9_MV_CLASSES_1_COUNT_START :
+                                       VP9_MV_CLASSES_0_COUNT_START;
+                       tree_i = 0;
+                       for (node = 0; node < 10; node++) {
+                               unsigned int start = coef_count_node_start;
+
+                               switch (node) {
+                               case 9:
+                                       tree_left = count[start + 9];
+                                       tree_right = count[start + 10];
+                                       break;
+                               case 8:
+                                       tree_left = count[start + 7];
+                                       tree_right = count[start + 8];
+                                       break;
+                               case 7:
+                                       tree_left = count[start + 7] +
+                                                    count[start + 8];
+                                       tree_right = count[start + 9] +
+                                                    count[start + 10];
+                                       break;
+                               case 6:
+                                       tree_left = count[start + 6];
+                                       tree_right = count[start + 7] +
+                                                    count[start + 8] +
+                                                    count[start + 9] +
+                                                    count[start + 10];
+                                       break;
+                               case 5:
+                                       tree_left = count[start + 4];
+                                       tree_right = count[start + 5];
+                                       break;
+                               case 4:
+                                       tree_left = count[start + 4] +
+                                                   count[start + 5];
+                                       tree_right = count[start + 6] +
+                                                    count[start + 7] +
+                                                    count[start + 8] +
+                                                    count[start + 9] +
+                                                    count[start + 10];
+                                       break;
+                               case 3:
+                                       tree_left = count[start + 2];
+                                       tree_right = count[start + 3];
+                                       break;
+                               case 2:
+                                       tree_left = count[start + 2] +
+                                                   count[start + 3];
+                                       tree_right = count[start + 4] +
+                                                    count[start + 5] +
+                                                    count[start + 6] +
+                                                    count[start + 7] +
+                                                    count[start + 8] +
+                                                    count[start + 9] +
+                                                    count[start + 10];
+                                       break;
+                               case 1:
+                                       tree_left = count[start + 1];
+                                       tree_right = count[start + 2] +
+                                                    count[start + 3] +
+                                                    count[start + 4] +
+                                                    count[start + 5] +
+                                                    count[start + 6] +
+                                                    count[start + 7] +
+                                                    count[start + 8] +
+                                                    count[start + 9] +
+                                                    count[start + 10];
+                                       break;
+                               default:
+                                       tree_left = count[start + 0];
+                                       tree_right = count[start + 1] +
+                                                    count[start + 2] +
+                                                    count[start + 3] +
+                                                    count[start + 4] +
+                                                    count[start + 5] +
+                                                    count[start + 6] +
+                                                    count[start + 7] +
+                                                    count[start + 8] +
+                                                    count[start + 9] +
+                                                    count[start + 10];
+                                       break;
+                               }
+
+                               vp9_tree_merge_probs(prev_prob, cur_prob,
+                                                    coef_node_start,
+                                                    tree_left, tree_right,
+                                                    tree_i, node);
+
+                               coef_node_start = coef_node_start + 1;
+                       }
+
+                       coef_node_start = mvd_i ? VP9_MV_CLASS0_1_START :
+                                                 VP9_MV_CLASS0_0_START;
+                       coef_count_node_start = mvd_i ?
+                                               VP9_MV_CLASS0_1_COUNT_START :
+                                               VP9_MV_CLASS0_0_COUNT_START;
+                       tree_i = 0;
+                       node = 0;
+                       tree_left = count[coef_count_node_start + 0];
+                       tree_right = count[coef_count_node_start + 1];
+
+                       vp9_tree_merge_probs(prev_prob, cur_prob,
+                                            coef_node_start,
+                                            tree_left, tree_right,
+                                            tree_i, node);
+                       coef_node_start = mvd_i ? VP9_MV_CLASS0_FP_1_START :
+                                                 VP9_MV_CLASS0_FP_0_START;
+                       coef_count_node_start = mvd_i ?
+                                       VP9_MV_CLASS0_FP_1_COUNT_START :
+                                       VP9_MV_CLASS0_FP_0_COUNT_START;
+
+                       for (tree_i = 0; tree_i < 3; tree_i++) {
+                               for (node = 0; node < 3; node++) {
+                                       unsigned int start =
+                                               coef_count_node_start;
+                                       switch (node) {
+                                       case 2:
+                                               tree_left = count[start + 2];
+                                               tree_right = count[start + 3];
+                                               break;
+                                       case 1:
+                                               tree_left = count[start + 1];
+                                               tree_right = count[start + 2] +
+                                                            count[start + 3];
+                                               break;
+                                       default:
+                                               tree_left = count[start + 0];
+                                               tree_right = count[start + 1] +
+                                                            count[start + 2] +
+                                                            count[start + 3];
+                                               break;
+                                       }
+
+                                       vp9_tree_merge_probs(prev_prob,
+                                                            cur_prob,
+                                                            coef_node_start,
+                                                            tree_left,
+                                                            tree_right,
+                                                            tree_i, node);
+
+                                       coef_node_start = coef_node_start + 1;
+                               }
+                               coef_count_node_start =
+                                       coef_count_node_start + 4;
+                       }
+               }
+       }
+}
+
+static irqreturn_t codec_vp9_threaded_isr(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       struct codec_vp9 *vp9 = sess->priv;
+       u32 dec_status = amvdec_read_dos(core, VP9_DEC_STATUS_REG);
+       u32 prob_status = amvdec_read_dos(core, VP9_ADAPT_PROB_REG);
+       int i;
+
+       if (!vp9)
+               return IRQ_HANDLED;
+
+       mutex_lock(&vp9->lock);
+       if (dec_status != VP9_HEAD_PARSER_DONE) {
+               dev_err(core->dev_dec, "Unrecognized dec_status: %08X\n",
+                       dec_status);
+               amvdec_abort(sess);
+               goto unlock;
+       }
+
+       pr_debug("ISR: %08X;%08X\n", dec_status, prob_status);
+       sess->keyframe_found = 1;
+
+       if ((prob_status & 0xff) == 0xfd && vp9->cur_frame) {
+               /* VP9_REQ_ADAPT_PROB */
+               u8 *prev_prob_b = ((u8 *)vp9->workspace_vaddr +
+                                        PROB_OFFSET) +
+                                       ((prob_status >> 8) * 0x1000);
+               u8 *cur_prob_b = ((u8 *)vp9->workspace_vaddr +
+                                        PROB_OFFSET) + 0x4000;
+               u8 *count_b = (u8 *)vp9->workspace_vaddr +
+                                  COUNT_OFFSET;
+               int last_frame_type = vp9->prev_frame ?
+                                               vp9->prev_frame->type :
+                                               KEY_FRAME;
+
+               adapt_coef_probs(last_frame_type == KEY_FRAME,
+                                vp9->cur_frame->type == KEY_FRAME ? 1 : 0,
+                                prob_status >> 8,
+                                (unsigned int *)prev_prob_b,
+                                (unsigned int *)cur_prob_b,
+                                (unsigned int *)count_b);
+
+               memcpy(prev_prob_b, cur_prob_b, ADAPT_PROB_SIZE);
+               amvdec_write_dos(core, VP9_ADAPT_PROB_REG, 0);
+       }
+
+       /* Invalidate first 3 refs */
+       for (i = 0; i < REFS_PER_FRAME ; ++i)
+               vp9->frame_refs[i] = NULL;
+
+       vp9->prev_frame = vp9->cur_frame;
+       codec_vp9_update_ref(vp9);
+
+       codec_vp9_fetch_rpm(sess);
+       if (codec_vp9_process_rpm(vp9)) {
+               amvdec_src_change(sess, vp9->width, vp9->height, 16);
+
+               /* No frame is actually processed */
+               vp9->cur_frame = NULL;
+
+               /* Show the remaining frame */
+               codec_vp9_show_frame(sess);
+
+               /* FIXME: Save refs for resized frame */
+               if (vp9->frames_num)
+                       codec_vp9_save_refs(vp9);
+
+               goto unlock;
+       }
+
+       codec_vp9_process_lf(vp9);
+       codec_vp9_process_frame(sess);
+       codec_vp9_show_frame(sess);
+
+unlock:
+       mutex_unlock(&vp9->lock);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t codec_vp9_isr(struct amvdec_session *sess)
+{
+       return IRQ_WAKE_THREAD;
+}
+
+struct amvdec_codec_ops codec_vp9_ops = {
+       .start = codec_vp9_start,
+       .stop = codec_vp9_stop,
+       .isr = codec_vp9_isr,
+       .threaded_isr = codec_vp9_threaded_isr,
+       .num_pending_bufs = codec_vp9_num_pending_bufs,
+       .drain = codec_vp9_flush_output,
+       .resume = codec_vp9_resume,
+};
diff --git a/drivers/staging/media/meson/vdec/codec_vp9.h b/drivers/staging/media/meson/vdec/codec_vp9.h
new file mode 100644 (file)
index 0000000..62db65a
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
+ */
+
+#ifndef __MESON_VDEC_CODEC_VP9_H_
+#define __MESON_VDEC_CODEC_VP9_H_
+
+#include "vdec.h"
+
+extern struct amvdec_codec_ops codec_vp9_ops;
+
+#endif
index 95102a4..db70227 100644 (file)
@@ -52,6 +52,7 @@
 #define PARSER_VIDEO_HOLE      0x90
 
 #define SEARCH_PATTERN_LEN     512
+#define VP9_HEADER_SIZE                16
 
 static DECLARE_WAIT_QUEUE_HEAD(wq);
 static int search_done;
@@ -74,27 +75,140 @@ static irqreturn_t esparser_isr(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
+/*
+ * VP9 frame headers need to be appended by a 16-byte long
+ * Amlogic custom header
+ */
+static int vp9_update_header(struct amvdec_core *core, struct vb2_buffer *buf)
+{
+       u8 *dp;
+       u8 marker;
+       int dsize;
+       int num_frames, cur_frame;
+       int cur_mag, mag, mag_ptr;
+       int frame_size[8], tot_frame_size[8];
+       int total_datasize = 0;
+       int new_frame_size;
+       unsigned char *old_header = NULL;
+
+       dp = (uint8_t *)vb2_plane_vaddr(buf, 0);
+       dsize = vb2_get_plane_payload(buf, 0);
+
+       if (dsize == vb2_plane_size(buf, 0)) {
+               dev_warn(core->dev, "%s: unable to update header\n", __func__);
+               return 0;
+       }
+
+       marker = dp[dsize - 1];
+       if ((marker & 0xe0) == 0xc0) {
+               num_frames = (marker & 0x7) + 1;
+               mag = ((marker >> 3) & 0x3) + 1;
+               mag_ptr = dsize - mag * num_frames - 2;
+               if (dp[mag_ptr] != marker)
+                       return 0;
+
+               mag_ptr++;
+               for (cur_frame = 0; cur_frame < num_frames; cur_frame++) {
+                       frame_size[cur_frame] = 0;
+                       for (cur_mag = 0; cur_mag < mag; cur_mag++) {
+                               frame_size[cur_frame] |=
+                                       (dp[mag_ptr] << (cur_mag * 8));
+                               mag_ptr++;
+                       }
+                       if (cur_frame == 0)
+                               tot_frame_size[cur_frame] =
+                                       frame_size[cur_frame];
+                       else
+                               tot_frame_size[cur_frame] =
+                                       tot_frame_size[cur_frame - 1] +
+                                       frame_size[cur_frame];
+                       total_datasize += frame_size[cur_frame];
+               }
+       } else {
+               num_frames = 1;
+               frame_size[0] = dsize;
+               tot_frame_size[0] = dsize;
+               total_datasize = dsize;
+       }
+
+       new_frame_size = total_datasize + num_frames * VP9_HEADER_SIZE;
+
+       if (new_frame_size >= vb2_plane_size(buf, 0)) {
+               dev_warn(core->dev, "%s: unable to update header\n", __func__);
+               return 0;
+       }
+
+       for (cur_frame = num_frames - 1; cur_frame >= 0; cur_frame--) {
+               int framesize = frame_size[cur_frame];
+               int framesize_header = framesize + 4;
+               int oldframeoff = tot_frame_size[cur_frame] - framesize;
+               int outheaderoff =  oldframeoff + cur_frame * VP9_HEADER_SIZE;
+               u8 *fdata = dp + outheaderoff;
+               u8 *old_framedata = dp + oldframeoff;
+
+               memmove(fdata + VP9_HEADER_SIZE, old_framedata, framesize);
+
+               fdata[0] = (framesize_header >> 24) & 0xff;
+               fdata[1] = (framesize_header >> 16) & 0xff;
+               fdata[2] = (framesize_header >> 8) & 0xff;
+               fdata[3] = (framesize_header >> 0) & 0xff;
+               fdata[4] = ((framesize_header >> 24) & 0xff) ^ 0xff;
+               fdata[5] = ((framesize_header >> 16) & 0xff) ^ 0xff;
+               fdata[6] = ((framesize_header >> 8) & 0xff) ^ 0xff;
+               fdata[7] = ((framesize_header >> 0) & 0xff) ^ 0xff;
+               fdata[8] = 0;
+               fdata[9] = 0;
+               fdata[10] = 0;
+               fdata[11] = 1;
+               fdata[12] = 'A';
+               fdata[13] = 'M';
+               fdata[14] = 'L';
+               fdata[15] = 'V';
+
+               if (!old_header) {
+                       /* nothing */
+               } else if (old_header > fdata + 16 + framesize) {
+                       dev_dbg(core->dev, "%s: data has gaps, setting to 0\n",
+                               __func__);
+                       memset(fdata + 16 + framesize, 0,
+                              (old_header - fdata + 16 + framesize));
+               } else if (old_header < fdata + 16 + framesize) {
+                       dev_err(core->dev, "%s: data overwritten\n", __func__);
+               }
+               old_header = fdata;
+       }
+
+       return new_frame_size;
+}
+
 /* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger
  * ISRs.
  * Also append a start code 000001ff at the end to trigger
  * the ESPARSER interrupt.
  */
-static u32 esparser_pad_start_code(struct vb2_buffer *vb)
+static u32 esparser_pad_start_code(struct amvdec_core *core,
+                                  struct vb2_buffer *vb,
+                                  u32 payload_size)
 {
-       u32 payload_size = vb2_get_plane_payload(vb, 0);
        u32 pad_size = 0;
-       u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size;
+       u8 *vaddr = vb2_plane_vaddr(vb, 0);
 
        if (payload_size < ESPARSER_MIN_PACKET_SIZE) {
                pad_size = ESPARSER_MIN_PACKET_SIZE - payload_size;
-               memset(vaddr, 0, pad_size);
+               memset(vaddr + payload_size, 0, pad_size);
+       }
+
+       if ((payload_size + pad_size + SEARCH_PATTERN_LEN) >
+                                               vb2_plane_size(vb, 0)) {
+               dev_warn(core->dev, "%s: unable to pad start code\n", __func__);
+               return pad_size;
        }
 
-       memset(vaddr + pad_size, 0, SEARCH_PATTERN_LEN);
-       vaddr[pad_size]     = 0x00;
-       vaddr[pad_size + 1] = 0x00;
-       vaddr[pad_size + 2] = 0x01;
-       vaddr[pad_size + 3] = 0xff;
+       memset(vaddr + payload_size + pad_size, 0, SEARCH_PATTERN_LEN);
+       vaddr[payload_size + pad_size]     = 0x00;
+       vaddr[payload_size + pad_size + 1] = 0x00;
+       vaddr[payload_size + pad_size + 2] = 0x01;
+       vaddr[payload_size + pad_size + 3] = 0xff;
 
        return pad_size;
 }
@@ -181,30 +295,60 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
        struct vb2_buffer *vb = &vbuf->vb2_buf;
        struct amvdec_core *core = sess->core;
        struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
-       u32 num_dst_bufs = 0;
        u32 payload_size = vb2_get_plane_payload(vb, 0);
        dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0);
+       u32 num_dst_bufs = 0;
        u32 offset;
        u32 pad_size;
 
-       if (codec_ops->num_pending_bufs)
-               num_dst_bufs = codec_ops->num_pending_bufs(sess);
-
-       num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
-
-       if (esparser_vififo_get_free_space(sess) < payload_size ||
-           atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
+       /*
+        * When max ref frame is held by VP9, this should be -= 3 to prevent a
+        * shortage of CAPTURE buffers on the decoder side.
+        * For the future, a good enhancement of the way this is handled could
+        * be to notify new capture buffers to the decoding modules, so that
+        * they could pause when there is no capture buffer available and
+        * resume on this notification.
+        */
+       if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) {
+               if (codec_ops->num_pending_bufs)
+                       num_dst_bufs = codec_ops->num_pending_bufs(sess);
+
+               num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
+               if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9)
+                       num_dst_bufs -= 3;
+
+               if (esparser_vififo_get_free_space(sess) < payload_size ||
+                   atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
+                       return -EAGAIN;
+       } else if (esparser_vififo_get_free_space(sess) < payload_size) {
                return -EAGAIN;
+       }
 
        v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf);
 
        offset = esparser_get_offset(sess);
 
-       amvdec_add_ts_reorder(sess, vb->timestamp, offset);
-       dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n",
-               vb->timestamp, payload_size, offset);
+       amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags);
+       dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X flags = %08X\n",
+               vb->timestamp, payload_size, offset, vbuf->flags);
+
+       vbuf->flags = 0;
+       vbuf->field = V4L2_FIELD_NONE;
+       vbuf->sequence = sess->sequence_out++;
+
+       if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) {
+               payload_size = vp9_update_header(core, vb);
 
-       pad_size = esparser_pad_start_code(vb);
+               /* If unable to alter buffer to add headers */
+               if (payload_size == 0) {
+                       amvdec_remove_ts(sess, vb->timestamp);
+                       v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+
+                       return 0;
+               }
+       }
+
+       pad_size = esparser_pad_start_code(core, vb, payload_size);
        ret = esparser_write_data(core, phy, payload_size + pad_size);
 
        if (ret <= 0) {
@@ -216,19 +360,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
                return 0;
        }
 
-       /* We need to wait until we parse the first keyframe.
-        * All buffers prior to the first keyframe must be dropped.
-        */
-       if (!sess->keyframe_found)
-               usleep_range(1000, 2000);
-
-       if (sess->keyframe_found)
-               atomic_inc(&sess->esparser_queued_bufs);
-       else
-               amvdec_remove_ts(sess, vb->timestamp);
-
-       vbuf->flags = 0;
-       vbuf->field = V4L2_FIELD_NONE;
+       atomic_inc(&sess->esparser_queued_bufs);
        v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
 
        return 0;
diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h
new file mode 100644 (file)
index 0000000..0392f41
--- /dev/null
@@ -0,0 +1,218 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __MESON_VDEC_HEVC_REGS_H_
+#define __MESON_VDEC_HEVC_REGS_H_
+
+#define HEVC_ASSIST_MMU_MAP_ADDR 0xc024
+
+#define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4
+#define HEVC_ASSIST_MBOX1_MASK 0xc1d8
+
+#define HEVC_ASSIST_SCRATCH_0 0xc300
+#define HEVC_ASSIST_SCRATCH_1 0xc304
+#define HEVC_ASSIST_SCRATCH_2 0xc308
+#define HEVC_ASSIST_SCRATCH_3 0xc30c
+#define HEVC_ASSIST_SCRATCH_4 0xc310
+#define HEVC_ASSIST_SCRATCH_5 0xc314
+#define HEVC_ASSIST_SCRATCH_6 0xc318
+#define HEVC_ASSIST_SCRATCH_7 0xc31c
+#define HEVC_ASSIST_SCRATCH_8 0xc320
+#define HEVC_ASSIST_SCRATCH_9 0xc324
+#define HEVC_ASSIST_SCRATCH_A 0xc328
+#define HEVC_ASSIST_SCRATCH_B 0xc32c
+#define HEVC_ASSIST_SCRATCH_C 0xc330
+#define HEVC_ASSIST_SCRATCH_D 0xc334
+#define HEVC_ASSIST_SCRATCH_E 0xc338
+#define HEVC_ASSIST_SCRATCH_F 0xc33c
+#define HEVC_ASSIST_SCRATCH_G 0xc340
+#define HEVC_ASSIST_SCRATCH_H 0xc344
+#define HEVC_ASSIST_SCRATCH_I 0xc348
+#define HEVC_ASSIST_SCRATCH_J 0xc34c
+#define HEVC_ASSIST_SCRATCH_K 0xc350
+#define HEVC_ASSIST_SCRATCH_L 0xc354
+#define HEVC_ASSIST_SCRATCH_M 0xc358
+#define HEVC_ASSIST_SCRATCH_N 0xc35c
+
+#define HEVC_PARSER_VERSION 0xc400
+#define HEVC_STREAM_CONTROL 0xc404
+#define HEVC_STREAM_START_ADDR 0xc408
+#define HEVC_STREAM_END_ADDR 0xc40c
+#define HEVC_STREAM_WR_PTR 0xc410
+#define HEVC_STREAM_RD_PTR 0xc414
+#define HEVC_STREAM_LEVEL 0xc418
+#define HEVC_STREAM_FIFO_CTL 0xc41c
+#define HEVC_SHIFT_CONTROL 0xc420
+#define HEVC_SHIFT_STARTCODE 0xc424
+#define HEVC_SHIFT_EMULATECODE 0xc428
+#define HEVC_SHIFT_STATUS 0xc42c
+#define HEVC_SHIFTED_DATA 0xc430
+#define HEVC_SHIFT_BYTE_COUNT 0xc434
+#define HEVC_SHIFT_COMMAND 0xc438
+#define HEVC_ELEMENT_RESULT 0xc43c
+#define HEVC_CABAC_CONTROL 0xc440
+#define HEVC_PARSER_SLICE_INFO 0xc444
+#define HEVC_PARSER_CMD_WRITE 0xc448
+#define HEVC_PARSER_CORE_CONTROL 0xc44c
+#define HEVC_PARSER_CMD_FETCH 0xc450
+#define HEVC_PARSER_CMD_STATUS 0xc454
+#define HEVC_PARSER_LCU_INFO 0xc458
+#define HEVC_PARSER_HEADER_INFO 0xc45c
+#define HEVC_PARSER_INT_CONTROL 0xc480
+#define HEVC_PARSER_INT_STATUS 0xc484
+#define HEVC_PARSER_IF_CONTROL 0xc488
+#define HEVC_PARSER_PICTURE_SIZE 0xc48c
+#define HEVC_PARSER_LCU_START 0xc490
+#define HEVC_PARSER_HEADER_INFO2 0xc494
+#define HEVC_PARSER_QUANT_READ 0xc498
+#define HEVC_PARSER_RESERVED_27 0xc49c
+#define HEVC_PARSER_CMD_SKIP_0 0xc4a0
+#define HEVC_PARSER_CMD_SKIP_1 0xc4a4
+#define HEVC_PARSER_CMD_SKIP_2 0xc4a8
+#define HEVC_SAO_IF_STATUS 0xc4c0
+#define HEVC_SAO_IF_DATA_Y 0xc4c4
+#define HEVC_SAO_IF_DATA_U 0xc4c8
+#define HEVC_SAO_IF_DATA_V 0xc4cc
+#define HEVC_STREAM_SWAP_ADDR 0xc4d0
+#define HEVC_STREAM_SWAP_CTRL 0xc4d4
+#define HEVC_IQIT_IF_WAIT_CNT 0xc4d8
+#define HEVC_MPRED_IF_WAIT_CNT 0xc4dc
+#define HEVC_SAO_IF_WAIT_CNT 0xc4e0
+
+#define HEVC_MPRED_VERSION 0xc800
+#define HEVC_MPRED_CTRL0 0xc804
+       #define MPRED_CTRL0_NEW_PIC     BIT(2)
+       #define MPRED_CTRL0_NEW_TILE    BIT(3)
+       #define MPRED_CTRL0_NEW_SLI_SEG BIT(4)
+       #define MPRED_CTRL0_TMVP        BIT(5)
+       #define MPRED_CTRL0_LDC         BIT(6)
+       #define MPRED_CTRL0_COL_FROM_L0 BIT(7)
+       #define MPRED_CTRL0_ABOVE_EN    BIT(9)
+       #define MPRED_CTRL0_MV_WR_EN    BIT(10)
+       #define MPRED_CTRL0_MV_RD_EN    BIT(11)
+       #define MPRED_CTRL0_BUF_LINEAR  BIT(13)
+#define HEVC_MPRED_CTRL1 0xc808
+#define HEVC_MPRED_INT_EN 0xc80c
+#define HEVC_MPRED_INT_STATUS 0xc810
+#define HEVC_MPRED_PIC_SIZE 0xc814
+#define HEVC_MPRED_PIC_SIZE_LCU 0xc818
+#define HEVC_MPRED_TILE_START 0xc81c
+#define HEVC_MPRED_TILE_SIZE_LCU 0xc820
+#define HEVC_MPRED_REF_NUM 0xc824
+#define HEVC_MPRED_REF_EN_L0 0xc830
+#define HEVC_MPRED_REF_EN_L1 0xc834
+#define HEVC_MPRED_COLREF_EN_L0 0xc838
+#define HEVC_MPRED_COLREF_EN_L1 0xc83c
+#define HEVC_MPRED_AXI_WCTRL 0xc840
+#define HEVC_MPRED_AXI_RCTRL 0xc844
+#define HEVC_MPRED_ABV_START_ADDR 0xc848
+#define HEVC_MPRED_MV_WR_START_ADDR 0xc84c
+#define HEVC_MPRED_MV_RD_START_ADDR 0xc850
+#define HEVC_MPRED_MV_WPTR 0xc854
+#define HEVC_MPRED_MV_RPTR 0xc858
+#define HEVC_MPRED_MV_WR_ROW_JUMP 0xc85c
+#define HEVC_MPRED_MV_RD_ROW_JUMP 0xc860
+#define HEVC_MPRED_CURR_LCU 0xc864
+#define HEVC_MPRED_ABV_WPTR 0xc868
+#define HEVC_MPRED_ABV_RPTR 0xc86c
+#define HEVC_MPRED_CTRL2 0xc870
+#define HEVC_MPRED_CTRL3 0xc874
+#define HEVC_MPRED_L0_REF00_POC 0xc880
+#define HEVC_MPRED_L1_REF00_POC 0xc8c0
+
+#define HEVC_MPRED_CTRL4 0xc930
+
+#define HEVC_MPRED_CUR_POC 0xc980
+#define HEVC_MPRED_COL_POC 0xc984
+#define HEVC_MPRED_MV_RD_END_ADDR 0xc988
+
+#define HEVC_MSP 0xcc00
+#define HEVC_MPSR 0xcc04
+#define HEVC_MCPU_INTR_MSK 0xcc10
+#define HEVC_MCPU_INTR_REQ 0xcc14
+#define HEVC_CPSR 0xcc84
+
+#define HEVC_IMEM_DMA_CTRL 0xcd00
+#define HEVC_IMEM_DMA_ADR 0xcd04
+#define HEVC_IMEM_DMA_COUNT 0xcd08
+
+#define HEVCD_IPP_TOP_CNTL 0xd000
+#define HEVCD_IPP_LINEBUFF_BASE 0xd024
+#define HEVCD_IPP_AXIIF_CONFIG 0xd02c
+
+#define VP9D_MPP_REF_SCALE_ENBL                0xd104
+#define VP9D_MPP_REFINFO_TBL_ACCCONFIG 0xd108
+#define VP9D_MPP_REFINFO_DATA          0xd10c
+
+#define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180
+#define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184
+#define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190
+
+#define HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR 0xd300
+#define HEVCD_MPP_ANC_CANVAS_DATA_ADDR 0xd304
+#define HEVCD_MPP_DECOMP_CTL1 0xd308
+#define HEVCD_MPP_DECOMP_CTL2 0xd30c
+#define HEVCD_MCRCC_CTL1 0xd3c0
+#define HEVCD_MCRCC_CTL2 0xd3c4
+#define HEVCD_MCRCC_CTL3 0xd3c8
+
+#define HEVC_DBLK_CFG0 0xd400
+#define HEVC_DBLK_CFG1 0xd404
+#define HEVC_DBLK_CFG2 0xd408
+#define HEVC_DBLK_CFG3 0xd40c
+#define HEVC_DBLK_CFG4 0xd410
+#define HEVC_DBLK_CFG5 0xd414
+#define HEVC_DBLK_CFG6 0xd418
+#define HEVC_DBLK_CFG7 0xd41c
+#define HEVC_DBLK_CFG8 0xd420
+#define HEVC_DBLK_CFG9 0xd424
+#define HEVC_DBLK_CFGA 0xd428
+#define HEVC_DBLK_STS0 0xd42c
+#define HEVC_DBLK_CFGB 0xd42c
+#define HEVC_DBLK_STS1 0xd430
+#define HEVC_DBLK_CFGE 0xd438
+
+#define HEVC_SAO_VERSION 0xd800
+#define HEVC_SAO_CTRL0 0xd804
+#define HEVC_SAO_CTRL1 0xd808
+#define HEVC_SAO_PIC_SIZE 0xd814
+#define HEVC_SAO_PIC_SIZE_LCU 0xd818
+#define HEVC_SAO_TILE_START 0xd81c
+#define HEVC_SAO_TILE_SIZE_LCU 0xd820
+#define HEVC_SAO_Y_START_ADDR 0xd82c
+#define HEVC_SAO_Y_LENGTH 0xd830
+#define HEVC_SAO_C_START_ADDR 0xd834
+#define HEVC_SAO_C_LENGTH 0xd838
+#define HEVC_SAO_Y_WPTR 0xd83c
+#define HEVC_SAO_C_WPTR 0xd840
+#define HEVC_SAO_ABV_START_ADDR 0xd844
+#define HEVC_SAO_VB_WR_START_ADDR 0xd848
+#define HEVC_SAO_VB_RD_START_ADDR 0xd84c
+#define HEVC_SAO_ABV_WPTR 0xd850
+#define HEVC_SAO_ABV_RPTR 0xd854
+#define HEVC_SAO_VB_WPTR 0xd858
+#define HEVC_SAO_VB_RPTR 0xd85c
+#define HEVC_SAO_CTRL2 0xd880
+#define HEVC_SAO_CTRL3 0xd884
+#define HEVC_SAO_CTRL4 0xd888
+#define HEVC_SAO_CTRL5 0xd88c
+#define HEVC_SAO_CTRL6 0xd890
+#define HEVC_SAO_CTRL7 0xd894
+#define HEVC_CM_BODY_START_ADDR 0xd898
+#define HEVC_CM_BODY_LENGTH 0xd89c
+#define HEVC_CM_HEADER_START_ADDR 0xd8a0
+#define HEVC_CM_HEADER_LENGTH 0xd8a4
+#define HEVC_CM_HEADER_OFFSET 0xd8ac
+#define HEVC_SAO_MMU_VH0_ADDR 0xd8e8
+#define HEVC_SAO_MMU_VH1_ADDR 0xd8ec
+
+#define HEVC_IQIT_CLK_RST_CTRL 0xdc00
+#define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08
+#define HEVC_IQIT_SCALELUT_RD_ADDR 0xdc0c
+#define HEVC_IQIT_SCALELUT_DATA 0xdc10
+
+#define HEVC_PSCALE_CTRL 0xe444
+
+#endif
index 5c5dabe..3040136 100644 (file)
@@ -168,7 +168,10 @@ static void process_num_buffers(struct vb2_queue *q,
 {
        const struct amvdec_format *fmt_out = sess->fmt_out;
        unsigned int buffers_total = q->num_buffers + *num_buffers;
+       u32 min_buf_capture = v4l2_ctrl_g_ctrl(sess->ctrl_min_buf_capture);
 
+       if (q->num_buffers + *num_buffers < min_buf_capture)
+               *num_buffers = min_buf_capture - q->num_buffers;
        if (is_reqbufs && buffers_total < fmt_out->min_buffers)
                *num_buffers = fmt_out->min_buffers - q->num_buffers;
        if (buffers_total > fmt_out->max_buffers)
@@ -193,7 +196,8 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
        if (*num_planes) {
                switch (q->type) {
                case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-                       if (*num_planes != 1 || sizes[0] < output_size)
+                       if (*num_planes != 1 ||
+                           sizes[0] < sess->src_buffer_size)
                                return -EINVAL;
                        break;
                case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
@@ -224,7 +228,7 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
 
        switch (q->type) {
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-               sizes[0] = amvdec_get_output_size(sess);
+               sizes[0] = sess->src_buffer_size;
                *num_planes = 1;
                break;
        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
@@ -250,6 +254,7 @@ static int vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
                return -EINVAL;
        }
 
+       sess->changed_format = 1;
        return 0;
 }
 
@@ -261,10 +266,11 @@ static void vdec_vb2_buf_queue(struct vb2_buffer *vb)
 
        v4l2_m2m_buf_queue(m2m_ctx, vbuf);
 
-       if (!sess->streamon_out || !sess->streamon_cap)
+       if (!sess->streamon_out)
                return;
 
-       if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+       if (sess->streamon_cap &&
+           vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
            vdec_codec_needs_recycle(sess))
                vdec_queue_recycle(sess, vb);
 
@@ -289,16 +295,22 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
        else
                sess->streamon_cap = 1;
 
-       if (!sess->streamon_out || !sess->streamon_cap)
+       if (!sess->streamon_out)
                return 0;
 
        if (sess->status == STATUS_NEEDS_RESUME &&
-           q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+           q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
+           sess->changed_format) {
                codec_ops->resume(sess);
                sess->status = STATUS_RUNNING;
                return 0;
        }
 
+       if (sess->status == STATUS_RUNNING ||
+           sess->status == STATUS_NEEDS_RESUME ||
+           sess->status == STATUS_INIT)
+               return 0;
+
        sess->vififo_size = SIZE_VIFIFO;
        sess->vififo_vaddr =
                dma_alloc_coherent(sess->core->dev, sess->vififo_size,
@@ -323,13 +335,14 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
                goto vififo_free;
 
        sess->sequence_cap = 0;
+       sess->sequence_out = 0;
        if (vdec_codec_needs_recycle(sess))
                sess->recycle_thread = kthread_run(vdec_recycle_thread, sess,
                                                   "vdec_recycle");
 
-       sess->status = STATUS_RUNNING;
+       sess->status = STATUS_INIT;
        core->cur_sess = sess;
-
+       schedule_work(&sess->esparser_queue_work);
        return 0;
 
 vififo_free:
@@ -382,10 +395,12 @@ static void vdec_reset_bufs_recycle(struct amvdec_session *sess)
 static void vdec_stop_streaming(struct vb2_queue *q)
 {
        struct amvdec_session *sess = vb2_get_drv_priv(q);
+       struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
        struct amvdec_core *core = sess->core;
        struct vb2_v4l2_buffer *buf;
 
        if (sess->status == STATUS_RUNNING ||
+           sess->status == STATUS_INIT ||
            (sess->status == STATUS_NEEDS_RESUME &&
             (!sess->streamon_out || !sess->streamon_cap))) {
                if (vdec_codec_needs_recycle(sess))
@@ -409,6 +424,10 @@ static void vdec_stop_streaming(struct vb2_queue *q)
 
                sess->streamon_out = 0;
        } else {
+               /* Drain remaining refs if was still running */
+               if (sess->status >= STATUS_RUNNING && codec_ops->drain)
+                       codec_ops->drain(sess);
+
                while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx)))
                        v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
 
@@ -476,20 +495,34 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size,
        struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
        struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
        const struct amvdec_format *fmts = sess->core->platform->formats;
-       const struct amvdec_format *fmt_out;
+       const struct amvdec_format *fmt_out = NULL;
+       u32 output_size = 0;
 
        memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
        memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
 
-       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+       switch (f->type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
                fmt_out = find_format(fmts, size, pixmp->pixelformat);
                if (!fmt_out) {
                        pixmp->pixelformat = V4L2_PIX_FMT_MPEG2;
                        fmt_out = find_format(fmts, size, pixmp->pixelformat);
                }
+               break;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               fmt_out = sess->fmt_out;
+               break;
+       default:
+               return NULL;
+       }
+
+       pixmp->width  = clamp(pixmp->width,  (u32)256, fmt_out->max_width);
+       pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height);
+       output_size = get_output_size(pixmp->width, pixmp->height);
 
-               pfmt[0].sizeimage =
-                       get_output_size(pixmp->width, pixmp->height);
+       if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               if (!pfmt[0].sizeimage)
+                       pfmt[0].sizeimage = sess->src_buffer_size;
                pfmt[0].bytesperline = 0;
                pixmp->num_planes = 1;
        } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
@@ -499,35 +532,25 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size,
 
                memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved));
                if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) {
-                       pfmt[0].sizeimage =
-                               get_output_size(pixmp->width, pixmp->height);
-                       pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
+                       pfmt[0].sizeimage = output_size;
+                       pfmt[0].bytesperline = ALIGN(pixmp->width, 32);
 
-                       pfmt[1].sizeimage =
-                             get_output_size(pixmp->width, pixmp->height) / 2;
-                       pfmt[1].bytesperline = ALIGN(pixmp->width, 64);
+                       pfmt[1].sizeimage = output_size / 2;
+                       pfmt[1].bytesperline = ALIGN(pixmp->width, 32);
                        pixmp->num_planes = 2;
                } else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) {
-                       pfmt[0].sizeimage =
-                               get_output_size(pixmp->width, pixmp->height);
-                       pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
+                       pfmt[0].sizeimage = output_size;
+                       pfmt[0].bytesperline = ALIGN(pixmp->width, 32);
 
-                       pfmt[1].sizeimage =
-                             get_output_size(pixmp->width, pixmp->height) / 4;
-                       pfmt[1].bytesperline = ALIGN(pixmp->width, 64) / 2;
+                       pfmt[1].sizeimage = output_size / 4;
+                       pfmt[1].bytesperline = ALIGN(pixmp->width, 32) / 2;
 
-                       pfmt[2].sizeimage =
-                             get_output_size(pixmp->width, pixmp->height) / 4;
-                       pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2;
+                       pfmt[2].sizeimage = output_size / 2;
+                       pfmt[2].bytesperline = ALIGN(pixmp->width, 32) / 2;
                        pixmp->num_planes = 3;
                }
-       } else {
-               return NULL;
        }
 
-       pixmp->width  = clamp(pixmp->width,  (u32)256, fmt_out->max_width);
-       pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height);
-
        if (pixmp->field == V4L2_FIELD_ANY)
                pixmp->field = V4L2_FIELD_NONE;
 
@@ -586,6 +609,8 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
        orig_pixmp = *pixmp;
 
        fmt_out = vdec_try_fmt_common(sess, num_formats, f);
+       if (!fmt_out)
+               return -EINVAL;
 
        if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
                pixfmt_out = pixmp->pixelformat;
@@ -610,6 +635,7 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
                sess->ycbcr_enc = pixmp->ycbcr_enc;
                sess->quantization = pixmp->quantization;
                sess->xfer_func = pixmp->xfer_func;
+               sess->src_buffer_size = pixmp->plane_fmt[0].sizeimage;
        }
 
        memset(&format, 0, sizeof(format));
@@ -701,29 +727,31 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
        if (!(sess->streamon_out & sess->streamon_cap))
                return 0;
 
-       /* Currently not handled since we do not support dynamic resolution
-        * for MPEG2. We consider both queues streaming to mean that the
-        * decoding session is started
-        */
-       if (cmd->cmd == V4L2_DEC_CMD_START)
+       if (cmd->cmd == V4L2_DEC_CMD_START) {
+               v4l2_m2m_clear_state(sess->m2m_ctx);
+               sess->should_stop = 0;
                return 0;
+       }
 
        /* Should not happen */
        if (cmd->cmd != V4L2_DEC_CMD_STOP)
                return -EINVAL;
 
        dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n");
+
        sess->should_stop = 1;
 
-       vdec_wait_inactive(sess);
+       v4l2_m2m_mark_stopped(sess->m2m_ctx);
 
        if (codec_ops->drain) {
+               vdec_wait_inactive(sess);
                codec_ops->drain(sess);
        } else if (codec_ops->eos_sequence) {
                u32 len;
                const u8 *data = codec_ops->eos_sequence(&len);
 
                esparser_queue_eos(sess->core, data, len);
+               vdec_wait_inactive(sess);
        }
 
        return ret;
@@ -883,6 +911,7 @@ static int vdec_open(struct file *file)
        sess->height = 720;
        sess->pixelaspect.numerator = 1;
        sess->pixelaspect.denominator = 1;
+       sess->src_buffer_size = SZ_1M;
 
        INIT_LIST_HEAD(&sess->timestamps);
        INIT_LIST_HEAD(&sess->bufs_recycle);
@@ -1076,7 +1105,7 @@ static int vdec_probe(struct platform_device *pdev)
 
        video_set_drvdata(vdev, core);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(dev, "Failed registering video device\n");
                goto err_vdev_release;
index 0faa1ec..f95445a 100644 (file)
@@ -29,13 +29,19 @@ struct amvdec_buffer {
  * struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset
  *
  * @list: used to make lists out of this struct
- * @ts: timestamp
+ * @tc: timecode from the v4l2 buffer
+ * @ts: timestamp from the VB2 buffer
  * @offset: offset in the VIFIFO where the associated packet was written
+ * @flags: flags from the v4l2 buffer
+ * @used_count: times this timestamp was checked for a match with a dst buffer
  */
 struct amvdec_timestamp {
        struct list_head list;
+       struct v4l2_timecode tc;
        u64 ts;
        u32 offset;
+       u32 flags;
+       u32 used_count;
 };
 
 struct amvdec_session;
@@ -165,6 +171,7 @@ struct amvdec_format {
 
 enum amvdec_status {
        STATUS_STOPPED,
+       STATUS_INIT,
        STATUS_RUNNING,
        STATUS_NEEDS_RESUME,
 };
@@ -180,6 +187,7 @@ enum amvdec_status {
  * @ctrl_min_buf_capture: V4L2 control V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
  * @fmt_out: vdec pixel format for the OUTPUT queue
  * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue
+ * @src_buffer_size: size in bytes of the OUTPUT buffers' only plane
  * @width: current picture width
  * @height: current picture height
  * @colorspace: current colorspace
@@ -221,6 +229,7 @@ struct amvdec_session {
 
        const struct amvdec_format *fmt_out;
        u32 pixfmt_cap;
+       u32 src_buffer_size;
 
        u32 width;
        u32 height;
@@ -235,10 +244,11 @@ struct amvdec_session {
        struct work_struct esparser_queue_work;
 
        unsigned int streamon_cap, streamon_out;
-       unsigned int sequence_cap;
+       unsigned int sequence_cap, sequence_out;
        unsigned int should_stop;
        unsigned int keyframe_found;
        unsigned int num_dst_bufs;
+       unsigned int changed_format;
 
        u8 canvas_alloc[MAX_CANVAS];
        u32 canvas_num;
index f16948b..7f07a91 100644 (file)
@@ -50,6 +50,33 @@ void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val)
 }
 EXPORT_SYMBOL_GPL(amvdec_write_parser);
 
+/* 4 KiB per 64x32 block */
+u32 amvdec_am21c_body_size(u32 width, u32 height)
+{
+       u32 width_64 = ALIGN(width, 64) / 64;
+       u32 height_32 = ALIGN(height, 32) / 32;
+
+       return SZ_4K * width_64 * height_32;
+}
+EXPORT_SYMBOL_GPL(amvdec_am21c_body_size);
+
+/* 32 bytes per 128x64 block */
+u32 amvdec_am21c_head_size(u32 width, u32 height)
+{
+       u32 width_128 = ALIGN(width, 128) / 128;
+       u32 height_64 = ALIGN(height, 64) / 64;
+
+       return 32 * width_128 * height_64;
+}
+EXPORT_SYMBOL_GPL(amvdec_am21c_head_size);
+
+u32 amvdec_am21c_size(u32 width, u32 height)
+{
+       return ALIGN(amvdec_am21c_body_size(width, height) +
+                    amvdec_am21c_head_size(width, height), SZ_64K);
+}
+EXPORT_SYMBOL_GPL(amvdec_am21c_size);
+
 static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id)
 {
        int ret;
@@ -154,8 +181,8 @@ int amvdec_set_canvases(struct amvdec_session *sess,
 {
        struct v4l2_m2m_buffer *buf;
        u32 pixfmt = sess->pixfmt_cap;
-       u32 width = ALIGN(sess->width, 64);
-       u32 height = ALIGN(sess->height, 64);
+       u32 width = ALIGN(sess->width, 32);
+       u32 height = ALIGN(sess->height, 32);
        u32 reg_cur = reg_base[0];
        u32 reg_num_cur = 0;
        u32 reg_base_cur = 0;
@@ -200,33 +227,23 @@ int amvdec_set_canvases(struct amvdec_session *sess,
 }
 EXPORT_SYMBOL_GPL(amvdec_set_canvases);
 
-void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset)
+void amvdec_add_ts(struct amvdec_session *sess, u64 ts,
+                  struct v4l2_timecode tc, u32 offset, u32 vbuf_flags)
 {
-       struct amvdec_timestamp *new_ts, *tmp;
+       struct amvdec_timestamp *new_ts;
        unsigned long flags;
 
-       new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL);
+       new_ts = kzalloc(sizeof(*new_ts), GFP_KERNEL);
        new_ts->ts = ts;
+       new_ts->tc = tc;
        new_ts->offset = offset;
+       new_ts->flags = vbuf_flags;
 
        spin_lock_irqsave(&sess->ts_spinlock, flags);
-
-       if (list_empty(&sess->timestamps))
-               goto add_tail;
-
-       list_for_each_entry(tmp, &sess->timestamps, list) {
-               if (ts <= tmp->ts) {
-                       list_add_tail(&new_ts->list, &tmp->list);
-                       goto unlock;
-               }
-       }
-
-add_tail:
        list_add_tail(&new_ts->list, &sess->timestamps);
-unlock:
        spin_unlock_irqrestore(&sess->ts_spinlock, flags);
 }
-EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder);
+EXPORT_SYMBOL_GPL(amvdec_add_ts);
 
 void amvdec_remove_ts(struct amvdec_session *sess, u64 ts)
 {
@@ -251,8 +268,8 @@ EXPORT_SYMBOL_GPL(amvdec_remove_ts);
 
 static void dst_buf_done(struct amvdec_session *sess,
                         struct vb2_v4l2_buffer *vbuf,
-                        u32 field,
-                        u64 timestamp)
+                        u32 field, u64 timestamp,
+                        struct v4l2_timecode timecode, u32 flags)
 {
        struct device *dev = sess->core->dev_dec;
        u32 output_size = amvdec_get_output_size(sess);
@@ -271,19 +288,27 @@ static void dst_buf_done(struct amvdec_session *sess,
 
        vbuf->vb2_buf.timestamp = timestamp;
        vbuf->sequence = sess->sequence_cap++;
+       vbuf->flags = flags;
+       vbuf->timecode = timecode;
 
        if (sess->should_stop &&
-           atomic_read(&sess->esparser_queued_bufs) <= 2) {
+           atomic_read(&sess->esparser_queued_bufs) <= 1) {
                const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
 
-               dev_dbg(dev, "Signaling EOS\n");
+               dev_dbg(dev, "Signaling EOS, sequence_cap = %u\n",
+                       sess->sequence_cap - 1);
                v4l2_event_queue_fh(&sess->fh, &ev);
                vbuf->flags |= V4L2_BUF_FLAG_LAST;
+       } else if (sess->status == STATUS_NEEDS_RESUME) {
+               /* Mark LAST for drained show frames during a source change */
+               vbuf->flags |= V4L2_BUF_FLAG_LAST;
+               sess->sequence_cap = 0;
        } else if (sess->should_stop)
                dev_dbg(dev, "should_stop, %u bufs remain\n",
                        atomic_read(&sess->esparser_queued_bufs));
 
-       dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index);
+       dev_dbg(dev, "Buffer %u done, ts = %llu, flags = %08X\n",
+               vbuf->vb2_buf.index, timestamp, flags);
        vbuf->field = field;
        v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
 
@@ -297,7 +322,9 @@ void amvdec_dst_buf_done(struct amvdec_session *sess,
        struct device *dev = sess->core->dev_dec;
        struct amvdec_timestamp *tmp;
        struct list_head *timestamps = &sess->timestamps;
+       struct v4l2_timecode timecode;
        u64 timestamp;
+       u32 vbuf_flags;
        unsigned long flags;
 
        spin_lock_irqsave(&sess->ts_spinlock, flags);
@@ -312,11 +339,13 @@ void amvdec_dst_buf_done(struct amvdec_session *sess,
 
        tmp = list_first_entry(timestamps, struct amvdec_timestamp, list);
        timestamp = tmp->ts;
+       timecode = tmp->tc;
+       vbuf_flags = tmp->flags;
        list_del(&tmp->list);
        kfree(tmp);
        spin_unlock_irqrestore(&sess->ts_spinlock, flags);
 
-       dst_buf_done(sess, vbuf, field, timestamp);
+       dst_buf_done(sess, vbuf, field, timestamp, timecode, vbuf_flags);
        atomic_dec(&sess->esparser_queued_bufs);
 }
 EXPORT_SYMBOL_GPL(amvdec_dst_buf_done);
@@ -328,48 +357,43 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
        struct device *dev = sess->core->dev_dec;
        struct amvdec_timestamp *match = NULL;
        struct amvdec_timestamp *tmp, *n;
+       struct v4l2_timecode timecode = { 0 };
        u64 timestamp = 0;
+       u32 vbuf_flags = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&sess->ts_spinlock, flags);
 
        /* Look for our vififo offset to get the corresponding timestamp. */
        list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
-               s64 delta = (s64)offset - tmp->offset;
-
-               /* Offsets reported by codecs usually differ slightly,
-                * so we need some wiggle room.
-                * 4KiB being the minimum packet size, there is no risk here.
-                */
-               if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) {
-                       match = tmp;
+               if (tmp->offset > offset) {
+                       /*
+                        * Delete any record that remained unused for 32 match
+                        * checks
+                        */
+                       if (tmp->used_count++ >= 32) {
+                               list_del(&tmp->list);
+                               kfree(tmp);
+                       }
                        break;
                }
 
-               if (!allow_drop)
-                       continue;
-
-               /* Delete any timestamp entry that appears before our target
-                * (not all src packets/timestamps lead to a frame)
-                */
-               if (delta > 0 || delta < -1 * (s32)sess->vififo_size) {
-                       atomic_dec(&sess->esparser_queued_bufs);
-                       list_del(&tmp->list);
-                       kfree(tmp);
-               }
+               match = tmp;
        }
 
        if (!match) {
-               dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n",
+               dev_err(dev, "Buffer %u done but can't match offset (%08X)\n",
                        vbuf->vb2_buf.index, offset);
        } else {
                timestamp = match->ts;
+               timecode = match->tc;
+               vbuf_flags = match->flags;
                list_del(&match->list);
                kfree(match);
        }
        spin_unlock_irqrestore(&sess->ts_spinlock, flags);
 
-       dst_buf_done(sess, vbuf, field, timestamp);
+       dst_buf_done(sess, vbuf, field, timestamp, timecode, vbuf_flags);
        if (match)
                atomic_dec(&sess->esparser_queued_bufs);
 }
@@ -420,16 +444,19 @@ void amvdec_src_change(struct amvdec_session *sess, u32 width,
 
        v4l2_ctrl_s_ctrl(sess->ctrl_min_buf_capture, dpb_size);
 
-       /* Check if the capture queue is already configured well for our
+       /*
+        * Check if the capture queue is already configured well for our
         * usecase. If so, keep decoding with it and do not send the event
         */
-       if (sess->width == width &&
+       if (sess->streamon_cap &&
+           sess->width == width &&
            sess->height == height &&
            dpb_size <= sess->num_dst_bufs) {
                sess->fmt_out->codec_ops->resume(sess);
                return;
        }
 
+       sess->changed_format = 0;
        sess->width = width;
        sess->height = height;
        sess->status = STATUS_NEEDS_RESUME;
index a455a9e..cfaed52 100644 (file)
@@ -27,6 +27,10 @@ void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val);
 u32 amvdec_read_parser(struct amvdec_core *core, u32 reg);
 void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val);
 
+u32 amvdec_am21c_body_size(u32 width, u32 height);
+u32 amvdec_am21c_head_size(u32 width, u32 height);
+u32 amvdec_am21c_size(u32 width, u32 height);
+
 /**
  * amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding
  *
@@ -44,13 +48,15 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
                                u32 offset, u32 field, bool allow_drop);
 
 /**
- * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order
+ * amvdec_add_ts() - Add a timestamp to the list
  *
  * @sess: current session
  * @ts: timestamp to add
  * @offset: offset in the VIFIFO where the associated packet was written
+ * @flags the vb2_v4l2_buffer flags
  */
-void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset);
+void amvdec_add_ts(struct amvdec_session *sess, u64 ts,
+                  struct v4l2_timecode tc, u32 offset, u32 flags);
 void amvdec_remove_ts(struct amvdec_session *sess, u64 ts);
 
 /**
diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c
new file mode 100644 (file)
index 0000000..9530e58
--- /dev/null
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
+ *
+ * VDEC_HEVC is a video decoding block that allows decoding of
+ * HEVC, VP9
+ */
+
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include "vdec_1.h"
+#include "vdec_helpers.h"
+#include "vdec_hevc.h"
+#include "hevc_regs.h"
+#include "dos_regs.h"
+
+/* AO Registers */
+#define AO_RTI_GEN_PWR_SLEEP0  0xe8
+#define AO_RTI_GEN_PWR_ISO0    0xec
+       #define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6))
+       #define GEN_PWR_VDEC_HEVC_SM1 (BIT(2))
+
+#define MC_SIZE        (4096 * 4)
+
+static int vdec_hevc_load_firmware(struct amvdec_session *sess,
+                                  const char *fwname)
+{
+       struct amvdec_core *core = sess->core;
+       struct device *dev = core->dev_dec;
+       const struct firmware *fw;
+       static void *mc_addr;
+       static dma_addr_t mc_addr_map;
+       int ret;
+       u32 i = 100;
+
+       ret = request_firmware(&fw, fwname, dev);
+       if (ret < 0)  {
+               dev_err(dev, "Unable to request firmware %s\n", fwname);
+               return ret;
+       }
+
+       if (fw->size < MC_SIZE) {
+               dev_err(dev, "Firmware size %zu is too small. Expected %u.\n",
+                       fw->size, MC_SIZE);
+               ret = -EINVAL;
+               goto release_firmware;
+       }
+
+       mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map,
+                                    GFP_KERNEL);
+       if (!mc_addr) {
+               ret = -ENOMEM;
+               goto release_firmware;
+       }
+
+       memcpy(mc_addr, fw->data, MC_SIZE);
+
+       amvdec_write_dos(core, HEVC_MPSR, 0);
+       amvdec_write_dos(core, HEVC_CPSR, 0);
+
+       amvdec_write_dos(core, HEVC_IMEM_DMA_ADR, mc_addr_map);
+       amvdec_write_dos(core, HEVC_IMEM_DMA_COUNT, MC_SIZE / 4);
+       amvdec_write_dos(core, HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
+
+       while (i && (readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000))
+               i--;
+
+       if (i == 0) {
+               dev_err(dev, "Firmware load fail (DMA hang?)\n");
+               ret = -ENODEV;
+       }
+
+       dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map);
+release_firmware:
+       release_firmware(fw);
+       return ret;
+}
+
+static void vdec_hevc_stbuf_init(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+
+       amvdec_write_dos(core, HEVC_STREAM_CONTROL,
+                        amvdec_read_dos(core, HEVC_STREAM_CONTROL) & ~1);
+       amvdec_write_dos(core, HEVC_STREAM_START_ADDR, sess->vififo_paddr);
+       amvdec_write_dos(core, HEVC_STREAM_END_ADDR,
+                        sess->vififo_paddr + sess->vififo_size);
+       amvdec_write_dos(core, HEVC_STREAM_RD_PTR, sess->vififo_paddr);
+       amvdec_write_dos(core, HEVC_STREAM_WR_PTR, sess->vififo_paddr);
+}
+
+/* VDEC_HEVC specific ESPARSER configuration */
+static void vdec_hevc_conf_esparser(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+
+       /* set vififo_vbuf_rp_sel=>vdec_hevc */
+       amvdec_write_dos(core, DOS_GEN_CTRL0, 3 << 1);
+       amvdec_write_dos(core, HEVC_STREAM_CONTROL,
+                        amvdec_read_dos(core, HEVC_STREAM_CONTROL) | BIT(3));
+       amvdec_write_dos(core, HEVC_STREAM_CONTROL,
+                        amvdec_read_dos(core, HEVC_STREAM_CONTROL) | 1);
+       amvdec_write_dos(core, HEVC_STREAM_FIFO_CTL,
+                        amvdec_read_dos(core, HEVC_STREAM_FIFO_CTL) | BIT(29));
+}
+
+static u32 vdec_hevc_vififo_level(struct amvdec_session *sess)
+{
+       return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL);
+}
+
+static int vdec_hevc_stop(struct amvdec_session *sess)
+{
+       struct amvdec_core *core = sess->core;
+       struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+
+       /* Disable interrupt */
+       amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 0);
+       /* Disable firmware processor */
+       amvdec_write_dos(core, HEVC_MPSR, 0);
+
+       if (sess->priv)
+               codec_ops->stop(sess);
+
+       /* Enable VDEC_HEVC Isolation */
+       if (core->platform->revision == VDEC_REVISION_SM1)
+               regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
+                                  GEN_PWR_VDEC_HEVC_SM1,
+                                  GEN_PWR_VDEC_HEVC_SM1);
+       else
+               regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
+                                  0xc00, 0xc00);
+
+       /* VDEC_HEVC Memories */
+       amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0xffffffffUL);
+
+       if (core->platform->revision == VDEC_REVISION_SM1)
+               regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                                  GEN_PWR_VDEC_HEVC_SM1,
+                                  GEN_PWR_VDEC_HEVC_SM1);
+       else
+               regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                                  GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC);
+
+       clk_disable_unprepare(core->vdec_hevc_clk);
+       if (core->platform->revision == VDEC_REVISION_G12A ||
+           core->platform->revision == VDEC_REVISION_SM1)
+               clk_disable_unprepare(core->vdec_hevcf_clk);
+
+       return 0;
+}
+
+static int vdec_hevc_start(struct amvdec_session *sess)
+{
+       int ret;
+       struct amvdec_core *core = sess->core;
+       struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+
+       if (core->platform->revision == VDEC_REVISION_G12A ||
+           core->platform->revision == VDEC_REVISION_SM1) {
+               clk_set_rate(core->vdec_hevcf_clk, 666666666);
+               ret = clk_prepare_enable(core->vdec_hevcf_clk);
+               if (ret)
+                       return ret;
+       }
+
+       clk_set_rate(core->vdec_hevc_clk, 666666666);
+       ret = clk_prepare_enable(core->vdec_hevc_clk);
+       if (ret)
+               return ret;
+
+       if (core->platform->revision == VDEC_REVISION_SM1)
+               regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                                  GEN_PWR_VDEC_HEVC_SM1, 0);
+       else
+               regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                                  GEN_PWR_VDEC_HEVC, 0);
+       usleep_range(10, 20);
+
+       /* Reset VDEC_HEVC*/
+       amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff);
+       amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000);
+
+       amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff);
+
+       /* VDEC_HEVC Memories */
+       amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000);
+
+       /* Remove VDEC_HEVC Isolation */
+       if (core->platform->revision == VDEC_REVISION_SM1)
+               regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
+                                  GEN_PWR_VDEC_HEVC_SM1, 0);
+       else
+               regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0,
+                                  0xc00, 0);
+
+       amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff);
+       amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000);
+
+       vdec_hevc_stbuf_init(sess);
+
+       ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path);
+       if (ret)
+               goto stop;
+
+       ret = codec_ops->start(sess);
+       if (ret)
+               goto stop;
+
+       amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11));
+       amvdec_write_dos(core, DOS_SW_RESET3, 0);
+       amvdec_read_dos(core, DOS_SW_RESET3);
+
+       amvdec_write_dos(core, HEVC_MPSR, 1);
+       /* Let the firmware settle */
+       usleep_range(10, 20);
+
+       return 0;
+
+stop:
+       vdec_hevc_stop(sess);
+       return ret;
+}
+
+struct amvdec_ops vdec_hevc_ops = {
+       .start = vdec_hevc_start,
+       .stop = vdec_hevc_stop,
+       .conf_esparser = vdec_hevc_conf_esparser,
+       .vififo_level = vdec_hevc_vififo_level,
+};
diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.h b/drivers/staging/media/meson/vdec/vdec_hevc.h
new file mode 100644 (file)
index 0000000..cd576a7
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
+ */
+
+#ifndef __MESON_VDEC_VDEC_HEVC_H_
+#define __MESON_VDEC_VDEC_HEVC_H_
+
+#include "vdec.h"
+
+extern struct amvdec_ops vdec_hevc_ops;
+
+#endif
index ea39f82..eabbeba 100644 (file)
@@ -8,10 +8,25 @@
 #include "vdec.h"
 
 #include "vdec_1.h"
+#include "vdec_hevc.h"
 #include "codec_mpeg12.h"
+#include "codec_h264.h"
+#include "codec_vp9.h"
 
 static const struct amvdec_format vdec_formats_gxbb[] = {
        {
+               .pixfmt = V4L2_PIX_FMT_H264,
+               .min_buffers = 2,
+               .max_buffers = 24,
+               .max_width = 1920,
+               .max_height = 1080,
+               .vdec_ops = &vdec_1_ops,
+               .codec_ops = &codec_h264_ops,
+               .firmware_path = "meson/vdec/gxbb_h264.bin",
+               .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED |
+                        V4L2_FMT_FLAG_DYN_RESOLUTION,
+       }, {
                .pixfmt = V4L2_PIX_FMT_MPEG1,
                .min_buffers = 8,
                .max_buffers = 8,
@@ -21,6 +36,7 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        }, {
                .pixfmt = V4L2_PIX_FMT_MPEG2,
                .min_buffers = 8,
@@ -31,11 +47,36 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        },
 };
 
 static const struct amvdec_format vdec_formats_gxl[] = {
        {
+               .pixfmt = V4L2_PIX_FMT_VP9,
+               .min_buffers = 16,
+               .max_buffers = 24,
+               .max_width = 3840,
+               .max_height = 2160,
+               .vdec_ops = &vdec_hevc_ops,
+               .codec_ops = &codec_vp9_ops,
+               .firmware_path = "meson/vdec/gxl_vp9.bin",
+               .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED |
+                        V4L2_FMT_FLAG_DYN_RESOLUTION,
+       }, {
+               .pixfmt = V4L2_PIX_FMT_H264,
+               .min_buffers = 2,
+               .max_buffers = 24,
+               .max_width = 3840,
+               .max_height = 2160,
+               .vdec_ops = &vdec_1_ops,
+               .codec_ops = &codec_h264_ops,
+               .firmware_path = "meson/vdec/gxl_h264.bin",
+               .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED |
+                        V4L2_FMT_FLAG_DYN_RESOLUTION,
+       }, {
                .pixfmt = V4L2_PIX_FMT_MPEG1,
                .min_buffers = 8,
                .max_buffers = 8,
@@ -45,6 +86,7 @@ static const struct amvdec_format vdec_formats_gxl[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        }, {
                .pixfmt = V4L2_PIX_FMT_MPEG2,
                .min_buffers = 8,
@@ -55,11 +97,24 @@ static const struct amvdec_format vdec_formats_gxl[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        },
 };
 
 static const struct amvdec_format vdec_formats_gxm[] = {
        {
+               .pixfmt = V4L2_PIX_FMT_H264,
+               .min_buffers = 2,
+               .max_buffers = 24,
+               .max_width = 3840,
+               .max_height = 2160,
+               .vdec_ops = &vdec_1_ops,
+               .codec_ops = &codec_h264_ops,
+               .firmware_path = "meson/vdec/gxm_h264.bin",
+               .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED |
+                        V4L2_FMT_FLAG_DYN_RESOLUTION,
+       }, {
                .pixfmt = V4L2_PIX_FMT_MPEG1,
                .min_buffers = 8,
                .max_buffers = 8,
@@ -69,6 +124,7 @@ static const struct amvdec_format vdec_formats_gxm[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        }, {
                .pixfmt = V4L2_PIX_FMT_MPEG2,
                .min_buffers = 8,
@@ -79,11 +135,36 @@ static const struct amvdec_format vdec_formats_gxm[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        },
 };
 
 static const struct amvdec_format vdec_formats_g12a[] = {
        {
+               .pixfmt = V4L2_PIX_FMT_VP9,
+               .min_buffers = 16,
+               .max_buffers = 24,
+               .max_width = 3840,
+               .max_height = 2160,
+               .vdec_ops = &vdec_hevc_ops,
+               .codec_ops = &codec_vp9_ops,
+               .firmware_path = "meson/vdec/g12a_vp9.bin",
+               .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED |
+                        V4L2_FMT_FLAG_DYN_RESOLUTION,
+       }, {
+               .pixfmt = V4L2_PIX_FMT_H264,
+               .min_buffers = 2,
+               .max_buffers = 24,
+               .max_width = 3840,
+               .max_height = 2160,
+               .vdec_ops = &vdec_1_ops,
+               .codec_ops = &codec_h264_ops,
+               .firmware_path = "meson/vdec/g12a_h264.bin",
+               .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED |
+                        V4L2_FMT_FLAG_DYN_RESOLUTION,
+       }, {
                .pixfmt = V4L2_PIX_FMT_MPEG1,
                .min_buffers = 8,
                .max_buffers = 8,
@@ -93,6 +174,7 @@ static const struct amvdec_format vdec_formats_g12a[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        }, {
                .pixfmt = V4L2_PIX_FMT_MPEG2,
                .min_buffers = 8,
@@ -103,11 +185,36 @@ static const struct amvdec_format vdec_formats_g12a[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        },
 };
 
 static const struct amvdec_format vdec_formats_sm1[] = {
        {
+               .pixfmt = V4L2_PIX_FMT_VP9,
+               .min_buffers = 16,
+               .max_buffers = 24,
+               .max_width = 3840,
+               .max_height = 2160,
+               .vdec_ops = &vdec_hevc_ops,
+               .codec_ops = &codec_vp9_ops,
+               .firmware_path = "meson/vdec/sm1_vp9_mmu.bin",
+               .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED |
+                        V4L2_FMT_FLAG_DYN_RESOLUTION,
+       }, {
+               .pixfmt = V4L2_PIX_FMT_H264,
+               .min_buffers = 2,
+               .max_buffers = 24,
+               .max_width = 3840,
+               .max_height = 2160,
+               .vdec_ops = &vdec_1_ops,
+               .codec_ops = &codec_h264_ops,
+               .firmware_path = "meson/vdec/g12a_h264.bin",
+               .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED |
+                        V4L2_FMT_FLAG_DYN_RESOLUTION,
+       }, {
                .pixfmt = V4L2_PIX_FMT_MPEG1,
                .min_buffers = 8,
                .max_buffers = 8,
@@ -117,6 +224,7 @@ static const struct amvdec_format vdec_formats_sm1[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        }, {
                .pixfmt = V4L2_PIX_FMT_MPEG2,
                .min_buffers = 8,
@@ -127,6 +235,7 @@ static const struct amvdec_format vdec_formats_sm1[] = {
                .codec_ops = &codec_mpeg12_ops,
                .firmware_path = "meson/vdec/gxl_mpeg12.bin",
                .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
+               .flags = V4L2_FMT_FLAG_COMPRESSED,
        },
 };
 
index 673aa3a..66975a3 100644 (file)
@@ -1111,7 +1111,7 @@ static int iss_video_open(struct file *file)
                goto done;
        }
 
-       ret = v4l2_pipeline_pm_use(&video->video.entity, 1);
+       ret = v4l2_pipeline_pm_get(&video->video.entity);
        if (ret < 0) {
                omap4iss_put(video->iss);
                goto done;
@@ -1160,7 +1160,7 @@ static int iss_video_release(struct file *file)
        /* Disable streaming and free the buffers queue resources. */
        iss_video_streamoff(file, vfh, video->type);
 
-       v4l2_pipeline_pm_use(&video->video.entity, 0);
+       v4l2_pipeline_pm_put(&video->video.entity);
 
        /* Release the videobuf2 queue */
        vb2_queue_release(&handle->queue);
@@ -1242,7 +1242,7 @@ int omap4iss_video_init(struct iss_video *video, const char *name)
        video->video.fops = &iss_video_fops;
        snprintf(video->video.name, sizeof(video->video.name),
                 "OMAP4 ISS %s %s", name, direction);
-       video->video.vfl_type = VFL_TYPE_GRABBER;
+       video->video.vfl_type = VFL_TYPE_VIDEO;
        video->video.release = video_device_release_empty;
        video->video.ioctl_ops = &iss_video_ioctl_ops;
        video->pipe.stream_state = ISS_PIPELINE_STREAM_STOPPED;
@@ -1270,7 +1270,7 @@ int omap4iss_video_register(struct iss_video *video, struct v4l2_device *vdev)
                video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT;
        video->video.device_caps |= V4L2_CAP_STREAMING;
 
-       ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1);
        if (ret < 0)
                dev_err(video->iss->dev,
                        "could not register video device (%d)\n", ret);
index 03cd9a4..0aa9877 100644 (file)
@@ -1,4 +1,3 @@
-* Fix serialization on subdev ops.
 * Don't use v4l2_async_notifier_parse_fwnode_endpoints_by_port().
 e.g. isp_parse_of_endpoints in drivers/media/platform/omap3isp/isp.c
 cio2_parse_firmware in drivers/media/pci/intel/ipu3/ipu3-cio2.c.
index 524e0dd..24fe6a7 100644 (file)
@@ -937,10 +937,7 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue)
 
        rkisp1_return_all_buffers(cap, VB2_BUF_STATE_ERROR);
 
-       ret = v4l2_pipeline_pm_use(&node->vdev.entity, 0);
-       if (ret)
-               dev_err(rkisp1->dev, "pipeline close failed error:%d\n", ret);
-
+       v4l2_pipeline_pm_put(&node->vdev.entity);
        ret = pm_runtime_put(rkisp1->dev);
        if (ret)
                dev_err(rkisp1->dev, "power down failed error:%d\n", ret);
@@ -999,7 +996,7 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count)
                dev_err(cap->rkisp1->dev, "power up failed %d\n", ret);
                goto err_destroy_dummy;
        }
-       ret = v4l2_pipeline_pm_use(entity, 1);
+       ret = v4l2_pipeline_pm_get(entity);
        if (ret) {
                dev_err(cap->rkisp1->dev, "open cif pipeline failed %d\n", ret);
                goto err_pipe_pm_put;
@@ -1025,7 +1022,7 @@ err_pipe_disable:
        rkisp1_pipeline_sink_walk(entity, NULL, rkisp1_pipeline_disable_cb);
 err_stop_stream:
        rkisp1_stream_stop(cap);
-       v4l2_pipeline_pm_use(entity, 0);
+       v4l2_pipeline_pm_put(entity);
 err_pipe_pm_put:
        pm_runtime_put(cap->rkisp1->dev);
 err_destroy_dummy:
@@ -1344,7 +1341,7 @@ static int rkisp1_register_capture(struct rkisp1_capture *cap)
 
        q = &node->buf_queue;
        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-       q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR;
+       q->io_modes = VB2_MMAP | VB2_DMABUF;
        q->drv_priv = cap;
        q->ops = &rkisp1_vb2_ops;
        q->mem_ops = &vb2_dma_contig_memops;
@@ -1362,7 +1359,7 @@ static int rkisp1_register_capture(struct rkisp1_capture *cap)
 
        vdev->queue = q;
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(cap->rkisp1->dev,
                        "failed to register %s, ret=%d\n", vdev->name, ret);
index 369a401..b291cc6 100644 (file)
@@ -96,6 +96,7 @@ struct rkisp1_sensor_async {
  * @sink_crop: crop for sink pad
  * @src_fmt: output format
  * @src_crop: output size
+ * @ops_lock: ops serialization
  *
  * @is_dphy_errctrl_disabled : if dphy errctrl is disabled (avoid endless interrupt)
  * @frame_sequence: used to synchronize frame_id between video devices.
@@ -107,6 +108,7 @@ struct rkisp1_isp {
        struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX];
        const struct rkisp1_isp_mbus_info *sink_fmt;
        const struct rkisp1_isp_mbus_info *src_fmt;
+       struct mutex ops_lock;
        bool is_dphy_errctrl_disabled;
        atomic_t frame_sequence;
 };
@@ -224,6 +226,7 @@ struct rkisp1_resizer {
        struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX];
        const struct rkisp1_rsz_config *config;
        enum rkisp1_fmt_pix_type fmt_type;
+       struct mutex ops_lock;
 };
 
 struct rkisp1_debug {
index 558126e..b1b3c05 100644 (file)
@@ -128,7 +128,7 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1)
 
                ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode,
                                                  MEDIA_PAD_FL_SOURCE);
-               if (ret) {
+               if (ret < 0) {
                        dev_err(sd->dev, "failed to find src pad for %s\n",
                                sd->name);
                        return ret;
@@ -145,14 +145,15 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1)
                flags = 0;
        }
 
-       flags = MEDIA_LNK_FL_ENABLED;
+       flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
 
        /* create ISP->RSZ->CAP links */
        for (i = 0; i < 2; i++) {
                source = &rkisp1->isp.sd.entity;
                sink = &rkisp1->resizer_devs[i].sd.entity;
                ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO,
-                                           sink, RKISP1_RSZ_PAD_SINK, flags);
+                                           sink, RKISP1_RSZ_PAD_SINK,
+                                           MEDIA_LNK_FL_ENABLED);
                if (ret)
                        return ret;
 
@@ -219,19 +220,17 @@ static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
                container_of(notifier, struct rkisp1_device, notifier);
        int ret;
 
-       mutex_lock(&rkisp1->media_dev.graph_mutex);
        ret = rkisp1_create_links(rkisp1);
        if (ret)
-               goto unlock;
+               return ret;
+
        ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
        if (ret)
-               goto unlock;
+               return ret;
 
        dev_dbg(rkisp1->dev, "Async subdev notifier completed\n");
 
-unlock:
-       mutex_unlock(&rkisp1->media_dev.graph_mutex);
-       return ret;
+       return 0;
 }
 
 static int rkisp1_fwnode_parse(struct device *dev,
@@ -502,8 +501,7 @@ static int rkisp1_probe(struct platform_device *pdev)
        strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME,
                sizeof(rkisp1->media_dev.model));
        rkisp1->media_dev.dev = &pdev->dev;
-       strscpy(rkisp1->media_dev.bus_info,
-               "platform: " RKISP1_DRIVER_NAME,
+       strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO,
                sizeof(rkisp1->media_dev.bus_info));
        media_device_init(&rkisp1->media_dev);
 
index 328c7ea..fa53f05 100644 (file)
@@ -28,9 +28,9 @@
 #define RKISP1_DIR_SINK_SRC (RKISP1_DIR_SINK | RKISP1_DIR_SRC)
 
 /*
- * NOTE: MIPI controller and input MUX are also configured in this file,
- * because ISP Subdev is not only describe ISP submodule(input size,format,
- * output size, format), but also a virtual route device.
+ * NOTE: MIPI controller and input MUX are also configured in this file.
+ * This is because ISP Subdev describes not only ISP submodule (input size,
+ * format, output size, format), but also a virtual route device.
  */
 
 /*
@@ -504,7 +504,7 @@ static int rkisp1_config_cif(struct rkisp1_device *rkisp1)
        return 0;
 }
 
-static int rkisp1_isp_stop(struct rkisp1_device *rkisp1)
+static void rkisp1_isp_stop(struct rkisp1_device *rkisp1)
 {
        u32 val;
 
@@ -540,8 +540,6 @@ static int rkisp1_isp_stop(struct rkisp1_device *rkisp1)
                     RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST,
                     RKISP1_CIF_IRCL);
        rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL);
-
-       return 0;
 }
 
 static void rkisp1_config_clk(struct rkisp1_device *rkisp1)
@@ -555,7 +553,7 @@ static void rkisp1_config_clk(struct rkisp1_device *rkisp1)
        rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL);
 }
 
-static int rkisp1_isp_start(struct rkisp1_device *rkisp1)
+static void rkisp1_isp_start(struct rkisp1_device *rkisp1)
 {
        struct rkisp1_sensor_async *sensor = rkisp1->active_sensor;
        u32 val;
@@ -580,8 +578,6 @@ static int rkisp1_isp_start(struct rkisp1_device *rkisp1)
         * the MIPI interface and before starting the sensor output.
         */
        usleep_range(1000, 1200);
-
-       return 0;
 }
 
 /* ----------------------------------------------------------------------------
@@ -683,7 +679,7 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
 
        src_fmt->code = format->code;
        mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code);
-       if (!mbus_info) {
+       if (!mbus_info || !(mbus_info->direction & RKISP1_DIR_SRC)) {
                src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
                mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code);
        }
@@ -767,7 +763,7 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
                                          which);
        sink_fmt->code = format->code;
        mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
-       if (!mbus_info) {
+       if (!mbus_info || !(mbus_info->direction & RKISP1_DIR_SINK)) {
                sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT;
                mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
        }
@@ -795,7 +791,9 @@ static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd,
 {
        struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
 
+       mutex_lock(&isp->ops_lock);
        fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad, fmt->which);
+       mutex_unlock(&isp->ops_lock);
        return 0;
 }
 
@@ -805,6 +803,7 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
 {
        struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
 
+       mutex_lock(&isp->ops_lock);
        if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO)
                rkisp1_isp_set_sink_fmt(isp, cfg, &fmt->format, fmt->which);
        else if (fmt->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
@@ -813,6 +812,7 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
                fmt->format = *rkisp1_isp_get_pad_fmt(isp, cfg, fmt->pad,
                                                      fmt->which);
 
+       mutex_unlock(&isp->ops_lock);
        return 0;
 }
 
@@ -821,11 +821,13 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
                                    struct v4l2_subdev_selection *sel)
 {
        struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+       int ret = 0;
 
        if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO &&
            sel->pad != RKISP1_ISP_PAD_SINK_VIDEO)
                return -EINVAL;
 
+       mutex_lock(&isp->ops_lock);
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP_BOUNDS:
                if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO) {
@@ -848,10 +850,10 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
                                                  sel->which);
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
-
-       return 0;
+       mutex_unlock(&isp->ops_lock);
+       return ret;
 }
 
 static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
@@ -861,21 +863,23 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
        struct rkisp1_device *rkisp1 =
                container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev);
        struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+       int ret = 0;
 
        if (sel->target != V4L2_SEL_TGT_CROP)
                return -EINVAL;
 
        dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__,
                sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
-
+       mutex_lock(&isp->ops_lock);
        if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO)
                rkisp1_isp_set_sink_crop(isp, cfg, &sel->r, sel->which);
        else if (sel->pad == RKISP1_ISP_PAD_SOURCE_VIDEO)
                rkisp1_isp_set_src_crop(isp, cfg, &sel->r, sel->which);
        else
-               return -EINVAL;
+               ret = -EINVAL;
 
-       return 0;
+       mutex_unlock(&isp->ops_lock);
+       return ret;
 }
 
 static int rkisp1_subdev_link_validate(struct media_link *link)
@@ -936,13 +940,12 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
 {
        struct rkisp1_device *rkisp1 =
                container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev);
+       struct rkisp1_isp *isp = &rkisp1->isp;
        struct v4l2_subdev *sensor_sd;
        int ret = 0;
 
        if (!enable) {
-               ret = rkisp1_isp_stop(rkisp1);
-               if (ret)
-                       return ret;
+               rkisp1_isp_stop(rkisp1);
                rkisp1_mipi_csi2_stop(rkisp1->active_sensor);
                return 0;
        }
@@ -953,22 +956,23 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
        rkisp1->active_sensor = container_of(sensor_sd->asd,
                                             struct rkisp1_sensor_async, asd);
 
+       if (rkisp1->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY)
+               return -EINVAL;
+
        atomic_set(&rkisp1->isp.frame_sequence, -1);
+       mutex_lock(&isp->ops_lock);
        ret = rkisp1_config_cif(rkisp1);
        if (ret)
-               return ret;
-
-       if (rkisp1->active_sensor->mbus.type != V4L2_MBUS_CSI2_DPHY)
-               return -EINVAL;
+               goto mutex_unlock;
 
        ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor);
        if (ret)
-               return ret;
+               goto mutex_unlock;
 
-       ret = rkisp1_isp_start(rkisp1);
-       if (ret)
-               rkisp1_mipi_csi2_stop(rkisp1->active_sensor);
+       rkisp1_isp_start(rkisp1);
 
+mutex_unlock:
+       mutex_unlock(&isp->ops_lock);
        return ret;
 }
 
@@ -1028,6 +1032,7 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1,
        isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT);
        isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT);
 
+       mutex_init(&isp->ops_lock);
        ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads);
        if (ret)
                return ret;
index 781f0ca..44d542c 100644 (file)
@@ -1605,7 +1605,7 @@ int rkisp1_params_register(struct rkisp1_params *params,
        ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
        if (ret)
                goto err_release_queue;
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(&vdev->dev,
                        "failed to register %s, ret=%d\n", vdev->name, ret);
index 8cdc29c..87799fb 100644 (file)
@@ -503,6 +503,8 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
                sink_crop->top = 0;
                sink_crop->width = sink_fmt->width;
                sink_crop->height = sink_fmt->height;
+
+               *r = *sink_crop;
                return;
        }
 
@@ -537,15 +539,6 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
        if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
                rsz->fmt_type = mbus_info->fmt_type;
 
-       if (rsz->id == RKISP1_MAINPATH &&
-           mbus_info->fmt_type == RKISP1_FMT_BAYER) {
-               sink_crop->left = 0;
-               sink_crop->top = 0;
-               sink_crop->width = sink_fmt->width;
-               sink_crop->height = sink_fmt->height;
-               return;
-       }
-
        /* Propagete to source pad */
        src_fmt->code = sink_fmt->code;
 
@@ -569,7 +562,9 @@ static int rkisp1_rsz_get_fmt(struct v4l2_subdev *sd,
        struct rkisp1_resizer *rsz =
                container_of(sd, struct rkisp1_resizer, sd);
 
+       mutex_lock(&rsz->ops_lock);
        fmt->format = *rkisp1_rsz_get_pad_fmt(rsz, cfg, fmt->pad, fmt->which);
+       mutex_unlock(&rsz->ops_lock);
        return 0;
 }
 
@@ -580,11 +575,13 @@ static int rkisp1_rsz_set_fmt(struct v4l2_subdev *sd,
        struct rkisp1_resizer *rsz =
                container_of(sd, struct rkisp1_resizer, sd);
 
+       mutex_lock(&rsz->ops_lock);
        if (fmt->pad == RKISP1_RSZ_PAD_SINK)
                rkisp1_rsz_set_sink_fmt(rsz, cfg, &fmt->format, fmt->which);
        else
                rkisp1_rsz_set_src_fmt(rsz, cfg, &fmt->format, fmt->which);
 
+       mutex_unlock(&rsz->ops_lock);
        return 0;
 }
 
@@ -595,10 +592,12 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
        struct rkisp1_resizer *rsz =
                container_of(sd, struct rkisp1_resizer, sd);
        struct v4l2_mbus_framefmt *mf_sink;
+       int ret = 0;
 
        if (sel->pad == RKISP1_RSZ_PAD_SRC)
                return -EINVAL;
 
+       mutex_lock(&rsz->ops_lock);
        switch (sel->target) {
        case V4L2_SEL_TGT_CROP_BOUNDS:
                mf_sink = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK,
@@ -613,10 +612,11 @@ static int rkisp1_rsz_get_selection(struct v4l2_subdev *sd,
                                                  sel->which);
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
 
-       return 0;
+       mutex_unlock(&rsz->ops_lock);
+       return ret;
 }
 
 static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd,
@@ -632,7 +632,9 @@ static int rkisp1_rsz_set_selection(struct v4l2_subdev *sd,
        dev_dbg(sd->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__,
                sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
 
+       mutex_lock(&rsz->ops_lock);
        rkisp1_rsz_set_sink_crop(rsz, cfg, &sel->r, sel->which);
+       mutex_unlock(&rsz->ops_lock);
 
        return 0;
 }
@@ -672,9 +674,11 @@ static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable)
        if (other->is_streaming)
                when = RKISP1_SHADOW_REGS_ASYNC;
 
+       mutex_lock(&rsz->ops_lock);
        rkisp1_rsz_config(rsz, when);
        rkisp1_dcrop_config(rsz);
 
+       mutex_unlock(&rsz->ops_lock);
        return 0;
 }
 
@@ -720,6 +724,7 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
 
        rsz->fmt_type = RKISP1_DEF_FMT_TYPE;
 
+       mutex_init(&rsz->ops_lock);
        ret = media_entity_pads_init(&sd->entity, 2, pads);
        if (ret)
                return ret;
index d98ea15..6dfcbdc 100644 (file)
@@ -70,8 +70,7 @@ static int rkisp1_stats_querycap(struct file *file,
 
        strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver));
        strscpy(cap->card, vdev->name, sizeof(cap->card));
-       strscpy(cap->bus_info, "platform: " RKISP1_DRIVER_NAME,
-               sizeof(cap->bus_info));
+       strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info));
 
        return 0;
 }
@@ -487,7 +486,7 @@ int rkisp1_stats_register(struct rkisp1_stats *stats,
        if (ret)
                goto err_release_queue;
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                dev_err(&vdev->dev,
                        "failed to register %s, ret=%d\n", vdev->name, ret);
index 7b9448e..39f513f 100644 (file)
@@ -2068,7 +2068,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
                v4l2_disable_ioctl(icd->vdev, VIDIOC_S_STD);
                v4l2_disable_ioctl(icd->vdev, VIDIOC_ENUMSTD);
        }
-       ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(icd->vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0) {
                dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
                return ret;
index c6ddd46..05a8551 100644 (file)
@@ -414,7 +414,7 @@ static int cedrus_probe(struct platform_device *pdev)
        dev->mdev.ops = &cedrus_m2m_media_ops;
        dev->v4l2_dev.mdev = &dev->mdev;
 
-       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
                goto err_m2m;
index bfb4a48..54ee2aa 100644 (file)
@@ -610,8 +610,12 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx)
                        goto err_mv_col_buf;
                }
 
+               /*
+                * NOTE: Multiplying by two deviates from CedarX logic, but it
+                * is for some unknown reason needed for H264 4K decoding on H6.
+                */
                ctx->codec.h264.intra_pred_buf_size =
-                       ALIGN(ctx->src_fmt.width, 64) * 5;
+                       ALIGN(ctx->src_fmt.width, 64) * 5 * 2;
                ctx->codec.h264.intra_pred_buf =
                        dma_alloc_coherent(dev->dev,
                                           ctx->codec.h264.intra_pred_buf_size,
index e18fd48..d3e6351 100644 (file)
@@ -949,7 +949,6 @@ static int tegra_vde_runtime_resume(struct device *dev)
 static int tegra_vde_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct resource *regs;
        struct tegra_vde *vde;
        int irq, err;
 
@@ -959,75 +958,39 @@ static int tegra_vde_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, vde);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sxe");
-       if (!regs)
-               return -ENODEV;
-
-       vde->sxe = devm_ioremap_resource(dev, regs);
+       vde->sxe = devm_platform_ioremap_resource_byname(pdev, "sxe");
        if (IS_ERR(vde->sxe))
                return PTR_ERR(vde->sxe);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "bsev");
-       if (!regs)
-               return -ENODEV;
-
-       vde->bsev = devm_ioremap_resource(dev, regs);
+       vde->bsev = devm_platform_ioremap_resource_byname(pdev, "bsev");
        if (IS_ERR(vde->bsev))
                return PTR_ERR(vde->bsev);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mbe");
-       if (!regs)
-               return -ENODEV;
-
-       vde->mbe = devm_ioremap_resource(dev, regs);
+       vde->mbe = devm_platform_ioremap_resource_byname(pdev, "mbe");
        if (IS_ERR(vde->mbe))
                return PTR_ERR(vde->mbe);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ppe");
-       if (!regs)
-               return -ENODEV;
-
-       vde->ppe = devm_ioremap_resource(dev, regs);
+       vde->ppe = devm_platform_ioremap_resource_byname(pdev, "ppe");
        if (IS_ERR(vde->ppe))
                return PTR_ERR(vde->ppe);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mce");
-       if (!regs)
-               return -ENODEV;
-
-       vde->mce = devm_ioremap_resource(dev, regs);
+       vde->mce = devm_platform_ioremap_resource_byname(pdev, "mce");
        if (IS_ERR(vde->mce))
                return PTR_ERR(vde->mce);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tfe");
-       if (!regs)
-               return -ENODEV;
-
-       vde->tfe = devm_ioremap_resource(dev, regs);
+       vde->tfe = devm_platform_ioremap_resource_byname(pdev, "tfe");
        if (IS_ERR(vde->tfe))
                return PTR_ERR(vde->tfe);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ppb");
-       if (!regs)
-               return -ENODEV;
-
-       vde->ppb = devm_ioremap_resource(dev, regs);
+       vde->ppb = devm_platform_ioremap_resource_byname(pdev, "ppb");
        if (IS_ERR(vde->ppb))
                return PTR_ERR(vde->ppb);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vdma");
-       if (!regs)
-               return -ENODEV;
-
-       vde->vdma = devm_ioremap_resource(dev, regs);
+       vde->vdma = devm_platform_ioremap_resource_byname(pdev, "vdma");
        if (IS_ERR(vde->vdma))
                return PTR_ERR(vde->vdma);
 
-       regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "frameid");
-       if (!regs)
-               return -ENODEV;
-
-       vde->frameid = devm_ioremap_resource(dev, regs);
+       vde->frameid = devm_platform_ioremap_resource_byname(pdev, "frameid");
        if (IS_ERR(vde->frameid))
                return PTR_ERR(vde->frameid);
 
similarity index 51%
rename from drivers/media/usb/usbvision/Kconfig
rename to drivers/staging/media/usbvision/Kconfig
index e1039fd..c6e1afb 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config VIDEO_USBVISION
-       tristate "USB video devices based on Nogatech NT1003/1004/1005"
-       depends on I2C && VIDEO_V4L2
+       tristate "USB video devices based on Nogatech NT1003/1004/1005 (Deprecated)"
+       depends on MEDIA_USB_SUPPORT && I2C && VIDEO_V4L2
        select VIDEO_TUNER
        select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
        help
@@ -9,5 +9,10 @@ config VIDEO_USBVISION
          NT1003/1004/1005 USB Bridges. This driver enables using those
          devices.
 
+         This driver is deprecated and scheduled for removal by the
+         end of 2020. See the TODO file in drivers/staging/media/usbvision
+         for a list of actions that have to be done in order to prevent
+         removal of this driver.
+
          To compile this driver as a module, choose M here: the
          module will be called usbvision.
diff --git a/drivers/staging/media/usbvision/TODO b/drivers/staging/media/usbvision/TODO
new file mode 100644 (file)
index 0000000..e9fb4d1
--- /dev/null
@@ -0,0 +1,11 @@
+The driver is deprecated and scheduled for removal by the end
+of 2020.
+
+In order to prevent removal the following actions would have to
+be taken:
+
+- clean up the code
+- convert to the vb2 framework
+- fix the disconnect and free-on-last-user handling (i.e., add
+  a release callback for struct v4l2_device and rework the code
+  to use that correctly).
@@ -1271,7 +1271,7 @@ static int usbvision_register_video(struct usb_usbvision *usbvision)
        if (usbvision->have_tuner)
                usbvision->vdev.device_caps |= V4L2_CAP_TUNER;
 
-       if (video_register_device(&usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
+       if (video_register_device(&usbvision->vdev, VFL_TYPE_VIDEO, video_nr) < 0)
                goto err_exit;
        printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n",
               usbvision->nr, video_device_node_name(&usbvision->vdev));
index 6262eb2..c5a99f7 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
-menuconfig MOST
+menuconfig MOST_COMPONENTS
        tristate "MOST support"
-       depends on HAS_DMA && CONFIGFS_FS
+       depends on HAS_DMA && CONFIGFS_FS && MOST
        default n
        help
          Say Y here if you want to enable MOST support.
@@ -16,7 +16,7 @@ menuconfig MOST
 
 
 
-if MOST
+if MOST_COMPONENTS
 
 source "drivers/staging/most/cdev/Kconfig"
 
index 20a99ec..a803a98 100644 (file)
@@ -1,7 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_MOST) += most_core.o
-most_core-y := core.o
-most_core-y += configfs.o
 
 obj-$(CONFIG_MOST_CDEV)        += cdev/
 obj-$(CONFIG_MOST_NET) += net/
index 71943d1..cc1e3de 100644 (file)
@@ -16,8 +16,7 @@
 #include <linux/kfifo.h>
 #include <linux/uaccess.h>
 #include <linux/idr.h>
-
-#include "../most.h"
+#include <linux/most.h>
 
 #define CHRDEV_REGION_SIZE 50
 
index 1659328..8e0f27e 100644 (file)
@@ -20,8 +20,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/sched.h>
 #include <linux/kthread.h>
-
-#include "../most.h"
+#include <linux/most.h>
 #include "hal.h"
 #include "errors.h"
 #include "sysfs.h"
index 2980f70..893a8ba 100644 (file)
@@ -13,8 +13,7 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/err.h>
-
-#include "../most.h"
+#include <linux/most.h>
 
 enum { CH_RX, CH_TX, NUM_CHANNELS };
 
index 5547e36..830f089 100644 (file)
@@ -15,8 +15,7 @@
 #include <linux/list.h>
 #include <linux/wait.h>
 #include <linux/kobject.h>
-
-#include "../most.h"
+#include <linux/most.h>
 
 #define MEP_HDR_LEN 8
 #define MDP_HDR_LEN 16
index 44cf233..1527f41 100644 (file)
@@ -17,8 +17,7 @@
 #include <sound/pcm_params.h>
 #include <linux/sched.h>
 #include <linux/kthread.h>
-
-#include "../most.h"
+#include <linux/most.h>
 
 #define DRIVER_NAME "sound"
 #define STRING_SIZE    80
index 0bda88c..e8c5a8c 100644 (file)
@@ -23,8 +23,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/etherdevice.h>
 #include <linux/uaccess.h>
-
-#include "../most.h"
+#include <linux/most.h>
 
 #define USB_MTU                        512
 #define NO_ISOCHRONOUS_URB     0
index d32ae49..829df89 100644 (file)
@@ -20,8 +20,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
-
-#include "../most.h"
+#include <linux/most.h>
 
 #define V4L2_CMP_MAX_INPUT  1
 
@@ -74,7 +73,7 @@ static int comp_vdev_open(struct file *filp)
        struct comp_fh *fh;
 
        switch (vdev->vfl_type) {
-       case VFL_TYPE_GRABBER:
+       case VFL_TYPE_VIDEO:
                break;
        default:
                return -EINVAL;
@@ -424,7 +423,7 @@ static int comp_register_videodev(struct most_video_dev *mdev)
 
        /* Register the v4l2 device */
        video_set_drvdata(mdev->vdev, mdev);
-       ret = video_register_device(mdev->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(mdev->vdev, VFL_TYPE_VIDEO, -1);
        if (ret) {
                v4l2_err(&mdev->v4l2_dev, "video_register_device failed (%d)\n",
                         ret);
index 20b8989..14592ed 100644 (file)
@@ -220,8 +220,7 @@ static void hsdma_dump_reg(struct mtk_hsdam_engine *hsdma)
                        mtk_hsdma_read(hsdma, HSDMA_REG_RX_CRX),
                        mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX));
 
-       dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, "
-                       "intr_stat %08x, intr_mask %08x\n",
+       dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, intr_stat %08x, intr_mask %08x\n",
                        mtk_hsdma_read(hsdma, HSDMA_REG_INFO),
                        mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG),
                        mtk_hsdma_read(hsdma, HSDMA_REG_DELAY_INT),
index 1fb560f..a7c0d31 100644 (file)
 &pcie {
        pinctrl-names = "default";
        pinctrl-0 = <&pcie_pins>;
+
+       reset-gpios = <&gpio 19 GPIO_ACTIVE_LOW>,
+                       <&gpio 8 GPIO_ACTIVE_LOW>,
+                       <&gpio 7 GPIO_ACTIVE_LOW>;
        status = "okay";
 };
 
index d89d68f..9e5cf68 100644 (file)
                pcie_pins: pcie0 {
                        pcie0 {
                                groups = "pcie";
-                               function = "pcie rst";
+                               function = "gpio";
                        };
                };
 
                #address-cells = <3>;
                #size-cells = <2>;
 
-               perst-gpio = <&gpio 19 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pcie_pins>;
 
 
                status = "disabled";
 
-               resets = <&rstctrl 23 &rstctrl 24 &rstctrl 25 &rstctrl 26>;
-               reset-names = "pcie", "pcie0", "pcie1", "pcie2";
+               resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>;
+               reset-names = "pcie0", "pcie1", "pcie2";
                clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>;
                clock-names = "pcie0", "pcie1", "pcie2";
-               phys = <&pcie0_phy 0>, <&pcie0_phy 1>, <&pcie1_phy 0>;
-               phy-names = "pcie-phy0", "pcie-phy1", "pcie-phy2";
+               phys = <&pcie0_phy 1>, <&pcie2_phy 0>;
+               phy-names = "pcie-phy0", "pcie-phy2";
+
+               reset-gpios = <&gpio 19 GPIO_ACTIVE_LOW>;
 
                pcie@0,0 {
                        reg = <0x0000 0 0 0 0>;
                #phy-cells = <1>;
        };
 
-       pcie1_phy: pcie-phy@1e14a000 {
+       pcie2_phy: pcie-phy@1e14a000 {
                compatible = "mediatek,mt7621-pci-phy";
                reg = <0x1e14a000 0x0700>;
                #phy-cells = <1>;
index d2a07f1..57743fd 100644 (file)
 
 #define RG_PE1_FRC_MSTCKDIV                    BIT(5)
 
-#define MAX_PHYS       2
+#define XTAL_MODE_SEL_SHIFT                    6
+#define XTAL_MODE_SEL_MASK                     0x7
 
-/**
- * struct mt7621_pci_phy_instance - Mt7621 Pcie PHY device
- * @phy: pointer to the kernel PHY device
- * @port_base: base register
- * @index: internal ID to identify the Mt7621 PCIe PHY
- */
-struct mt7621_pci_phy_instance {
-       struct phy *phy;
-       void __iomem *port_base;
-       u32 index;
-};
+#define MAX_PHYS       2
 
 /**
  * struct mt7621_pci_phy - Mt7621 Pcie PHY core
  * @dev: pointer to device
  * @regmap: kernel regmap pointer
- * @phys: pointer to Mt7621 PHY device
- * @nphys: number of PHY devices for this core
+ * @phy: pointer to the kernel PHY device
+ * @port_base: base register
+ * @has_dual_port: if the phy has dual ports.
  * @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst'
  * needs to be executed. Depends on chip revision.
  */
 struct mt7621_pci_phy {
        struct device *dev;
        struct regmap *regmap;
-       struct mt7621_pci_phy_instance **phys;
-       int nphys;
+       struct phy *phy;
+       void __iomem *port_base;
+       bool has_dual_port;
        bool bypass_pipe_rst;
 };
 
@@ -120,162 +113,152 @@ static inline void phy_write(struct mt7621_pci_phy *phy, u32 val, u32 reg)
        regmap_write(phy->regmap, reg, val);
 }
 
-static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy,
-                                  struct mt7621_pci_phy_instance *instance)
+static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy,
+                                 u32 reg, u32 clr, u32 set)
+{
+       u32 val = phy_read(phy, reg);
+
+       val &= ~clr;
+       val |= set;
+       phy_write(phy, val, reg);
+}
+
+static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy)
 {
-       u32 offset = (instance->index != 1) ?
-               RG_PE1_PIPE_REG : RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH;
-       u32 reg;
-
-       reg = phy_read(phy, offset);
-       reg &= ~(RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC);
-       reg |= (RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC);
-       phy_write(phy, reg, offset);
+       mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_RST);
+       mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_CMD_FRC);
+
+       if (phy->has_dual_port) {
+               mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH,
+                              0, RG_PE1_PIPE_RST);
+               mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH,
+                              0, RG_PE1_PIPE_CMD_FRC);
+       }
 }
 
-static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy,
-                                  struct mt7621_pci_phy_instance *instance)
+static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy)
 {
        struct device *dev = phy->dev;
-       u32 reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
-       u32 offset;
-       u32 val;
+       u32 xtal_mode;
+
+       xtal_mode = (rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0)
+                    >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK;
 
-       reg = (reg >> 6) & 0x7;
        /* Set PCIe Port PHY to disable SSC */
        /* Debug Xtal Type */
-       val = phy_read(phy, RG_PE1_FRC_H_XTAL_REG);
-       val &= ~(RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE);
-       val |= RG_PE1_FRC_H_XTAL_TYPE;
-       val |= RG_PE1_H_XTAL_TYPE_VAL(0x00);
-       phy_write(phy, val, RG_PE1_FRC_H_XTAL_REG);
+       mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG,
+                      RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE,
+                      RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE_VAL(0x00));
 
        /* disable port */
-       offset = (instance->index != 1) ?
-               RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
-       val = phy_read(phy, offset);
-       val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
-       val |= RG_PE1_FRC_PHY_EN;
-       phy_write(phy, val, offset);
-
-       /* Set Pre-divider ratio (for host mode) */
-       val = phy_read(phy, RG_PE1_H_PLL_REG);
-       val &= ~(RG_PE1_H_PLL_PREDIV);
-
-       if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */
-               val |= RG_PE1_H_PLL_PREDIV_VAL(0x01);
-               phy_write(phy, val, RG_PE1_H_PLL_REG);
+       mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG,
+                      RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
+
+       if (phy->has_dual_port) {
+               mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
+                              RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
+       }
+
+       if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */
+               /* Set Pre-divider ratio (for host mode) */
+               mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
+                              RG_PE1_H_PLL_PREDIV,
+                              RG_PE1_H_PLL_PREDIV_VAL(0x01));
                dev_info(dev, "Xtal is 40MHz\n");
-       } else { /* 25MHz | 20MHz Xtal */
-               val |= RG_PE1_H_PLL_PREDIV_VAL(0x00);
-               phy_write(phy, val, RG_PE1_H_PLL_REG);
-               if (reg >= 6) {
-                       dev_info(dev, "Xtal is 25MHz\n");
-
-                       /* Select feedback clock */
-                       val = phy_read(phy, RG_PE1_H_PLL_FBKSEL_REG);
-                       val &= ~(RG_PE1_H_PLL_FBKSEL);
-                       val |= RG_PE1_H_PLL_FBKSEL_VAL(0x01);
-                       phy_write(phy, val, RG_PE1_H_PLL_FBKSEL_REG);
-
-                       /* DDS NCPO PCW (for host mode) */
-                       val = phy_read(phy, RG_PE1_H_LCDDS_SSC_PRD_REG);
-                       val &= ~(RG_PE1_H_LCDDS_SSC_PRD);
-                       val |= RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000);
-                       phy_write(phy, val, RG_PE1_H_LCDDS_SSC_PRD_REG);
-
-                       /* DDS SSC dither period control */
-                       val = phy_read(phy, RG_PE1_H_LCDDS_SSC_PRD_REG);
-                       val &= ~(RG_PE1_H_LCDDS_SSC_PRD);
-                       val |= RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d);
-                       phy_write(phy, val, RG_PE1_H_LCDDS_SSC_PRD_REG);
-
-                       /* DDS SSC dither amplitude control */
-                       val = phy_read(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG);
-                       val &= ~(RG_PE1_H_LCDDS_SSC_DELTA |
-                                RG_PE1_H_LCDDS_SSC_DELTA1);
-                       val |= RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a);
-                       val |= RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a);
-                       phy_write(phy, val, RG_PE1_H_LCDDS_SSC_DELTA_REG);
-               } else {
-                       dev_info(dev, "Xtal is 20MHz\n");
-               }
+       } else if (xtal_mode >= 6) { /* 25MHz Xal */
+               mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
+                              RG_PE1_H_PLL_PREDIV,
+                              RG_PE1_H_PLL_PREDIV_VAL(0x00));
+               /* Select feedback clock */
+               mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG,
+                              RG_PE1_H_PLL_FBKSEL,
+                              RG_PE1_H_PLL_FBKSEL_VAL(0x01));
+               /* DDS NCPO PCW (for host mode) */
+               mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG,
+                              RG_PE1_H_LCDDS_SSC_PRD,
+                              RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000));
+               /* DDS SSC dither period control */
+               mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG,
+                              RG_PE1_H_LCDDS_SSC_PRD,
+                              RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d));
+               /* DDS SSC dither amplitude control */
+               mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG,
+                              RG_PE1_H_LCDDS_SSC_DELTA |
+                              RG_PE1_H_LCDDS_SSC_DELTA1,
+                              RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a) |
+                              RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a));
+               dev_info(dev, "Xtal is 25MHz\n");
+       } else { /* 20MHz Xtal */
+               mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
+                              RG_PE1_H_PLL_PREDIV,
+                              RG_PE1_H_PLL_PREDIV_VAL(0x00));
+
+               dev_info(dev, "Xtal is 20MHz\n");
        }
 
        /* DDS clock inversion */
-       val = phy_read(phy, RG_PE1_LCDDS_CLK_PH_INV_REG);
-       val &= ~(RG_PE1_LCDDS_CLK_PH_INV);
-       val |= RG_PE1_LCDDS_CLK_PH_INV;
-       phy_write(phy, val, RG_PE1_LCDDS_CLK_PH_INV_REG);
+       mt7621_phy_rmw(phy, RG_PE1_LCDDS_CLK_PH_INV_REG,
+                      RG_PE1_LCDDS_CLK_PH_INV, RG_PE1_LCDDS_CLK_PH_INV);
 
        /* Set PLL bits */
-       val = phy_read(phy, RG_PE1_H_PLL_REG);
-       val &= ~(RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR |
-                RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN);
-       val |= RG_PE1_H_PLL_BC_VAL(0x02);
-       val |= RG_PE1_H_PLL_BP_VAL(0x06);
-       val |= RG_PE1_H_PLL_IR_VAL(0x02);
-       val |= RG_PE1_H_PLL_IC_VAL(0x01);
-       val |= RG_PE1_PLL_DIVEN_VAL(0x02);
-       phy_write(phy, val, RG_PE1_H_PLL_REG);
-
-       val = phy_read(phy, RG_PE1_H_PLL_BR_REG);
-       val &= ~(RG_PE1_H_PLL_BR);
-       val |= RG_PE1_H_PLL_BR_VAL(0x00);
-       phy_write(phy, val, RG_PE1_H_PLL_BR_REG);
-
-       if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */
+       mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
+                      RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR |
+                      RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN,
+                      RG_PE1_H_PLL_BC_VAL(0x02) | RG_PE1_H_PLL_BP_VAL(0x06) |
+                      RG_PE1_H_PLL_IR_VAL(0x02) | RG_PE1_H_PLL_IC_VAL(0x01) |
+                      RG_PE1_PLL_DIVEN_VAL(0x02));
+
+       mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG,
+                      RG_PE1_H_PLL_BR, RG_PE1_H_PLL_BR_VAL(0x00));
+
+       if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */
                /* set force mode enable of da_pe1_mstckdiv */
-               val = phy_read(phy, RG_PE1_MSTCKDIV_REG);
-               val &= ~(RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV);
-               val |= (RG_PE1_MSTCKDIV_VAL(0x01) | RG_PE1_FRC_MSTCKDIV);
-               phy_write(phy, val, RG_PE1_MSTCKDIV_REG);
+               mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG,
+                              RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV,
+                              RG_PE1_MSTCKDIV_VAL(0x01) | RG_PE1_FRC_MSTCKDIV);
        }
 }
 
 static int mt7621_pci_phy_init(struct phy *phy)
 {
-       struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy);
-       struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent);
+       struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
 
        if (mphy->bypass_pipe_rst)
-               mt7621_bypass_pipe_rst(mphy, instance);
+               mt7621_bypass_pipe_rst(mphy);
 
-       mt7621_set_phy_for_ssc(mphy, instance);
+       mt7621_set_phy_for_ssc(mphy);
 
        return 0;
 }
 
 static int mt7621_pci_phy_power_on(struct phy *phy)
 {
-       struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy);
-       struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent);
-       u32 offset = (instance->index != 1) ?
-               RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
-       u32 val;
+       struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
 
        /* Enable PHY and disable force mode */
-       val = phy_read(mphy, offset);
-       val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
-       val |= (RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
-       phy_write(mphy, val, offset);
+       mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG,
+                      RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN);
+
+       if (mphy->has_dual_port) {
+               mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
+                              RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN);
+       }
 
        return 0;
 }
 
 static int mt7621_pci_phy_power_off(struct phy *phy)
 {
-       struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy);
-       struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent);
-       u32 offset = (instance->index != 1) ?
-               RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
-       u32 val;
+       struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
 
        /* Disable PHY */
-       val = phy_read(mphy, offset);
-       val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
-       val |= RG_PE1_FRC_PHY_EN;
-       phy_write(mphy, val, offset);
+       mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG,
+                      RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
+
+       if (mphy->has_dual_port) {
+               mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
+                              RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
+       }
 
        return 0;
 }
@@ -298,13 +281,15 @@ static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev,
 {
        struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev);
 
-       if (args->args_count == 0)
-               return mt7621_phy->phys[0]->phy;
-
        if (WARN_ON(args->args[0] >= MAX_PHYS))
                return ERR_PTR(-ENODEV);
 
-       return mt7621_phy->phys[args->args[0]]->phy;
+       mt7621_phy->has_dual_port = args->args[0];
+
+       dev_info(dev, "PHY for 0x%08x (dual port = %d)\n",
+                (unsigned int)mt7621_phy->port_base, mt7621_phy->has_dual_port);
+
+       return mt7621_phy->phy;
 }
 
 static const struct soc_device_attribute mt7621_pci_quirks_match[] = {
@@ -325,19 +310,11 @@ static int mt7621_pci_phy_probe(struct platform_device *pdev)
        struct phy_provider *provider;
        struct mt7621_pci_phy *phy;
        struct resource *res;
-       int port;
-       void __iomem *port_base;
 
        phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
        if (!phy)
                return -ENOMEM;
 
-       phy->nphys = MAX_PHYS;
-       phy->phys = devm_kcalloc(dev, phy->nphys,
-                                sizeof(*phy->phys), GFP_KERNEL);
-       if (!phy->phys)
-               return -ENOMEM;
-
        attr = soc_device_match(mt7621_pci_quirks_match);
        if (attr)
                phy->bypass_pipe_rst = true;
@@ -351,39 +328,25 @@ static int mt7621_pci_phy_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       port_base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(port_base)) {
+       phy->port_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(phy->port_base)) {
                dev_err(dev, "failed to remap phy regs\n");
-               return PTR_ERR(port_base);
+               return PTR_ERR(phy->port_base);
        }
 
-       phy->regmap = devm_regmap_init_mmio(phy->dev, port_base,
+       phy->regmap = devm_regmap_init_mmio(phy->dev, phy->port_base,
                                            &mt7621_pci_phy_regmap_config);
        if (IS_ERR(phy->regmap))
                return PTR_ERR(phy->regmap);
 
-       for (port = 0; port < MAX_PHYS; port++) {
-               struct mt7621_pci_phy_instance *instance;
-               struct phy *pphy;
-
-               instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
-               if (!instance)
-                       return -ENOMEM;
-
-               phy->phys[port] = instance;
-
-               pphy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops);
-               if (IS_ERR(phy)) {
-                       dev_err(dev, "failed to create phy\n");
-                       return PTR_ERR(phy);
-               }
-
-               instance->port_base = port_base;
-               instance->phy = pphy;
-               instance->index = port;
-               phy_set_drvdata(pphy, instance);
+       phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops);
+       if (IS_ERR(phy)) {
+               dev_err(dev, "failed to create phy\n");
+               return PTR_ERR(phy);
        }
 
+       phy_set_drvdata(phy->phy, phy);
+
        provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate);
 
        return PTR_ERR_OR_ZERO(provider);
@@ -403,12 +366,7 @@ static struct platform_driver mt7621_pci_phy_driver = {
        },
 };
 
-static int __init mt7621_pci_phy_drv_init(void)
-{
-       return platform_driver_register(&mt7621_pci_phy_driver);
-}
-
-module_init(mt7621_pci_phy_drv_init);
+builtin_platform_driver(mt7621_pci_phy_driver);
 
 MODULE_AUTHOR("Sergio Paracuellos <sergio.paracuellos@gmail.com>");
 MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver");
index 604ec81..327a682 100644 (file)
@@ -6,7 +6,6 @@ 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)
@@ -24,6 +23,7 @@ Required properties:
   See ../clocks/clock-bindings.txt for details.
 - clock-names: Must be "pcie0", "pcie1", "pcieN"... based on the number of
   root ports.
+- reset-gpios: GPIO specs for the reset pins.
 
 In addition, the device tree node must have sub-nodes describing each PCIe port
 interface, having the following mandatory properties:
@@ -49,7 +49,6 @@ Example for MT7621:
                #address-cells = <3>;
                #size-cells = <2>;
 
-               perst-gpio = <&gpio 19 GPIO_ACTIVE_HIGH>;
                pinctrl-names = "default";
                pinctrl-0 = <&pcie_pins>;
 
@@ -74,6 +73,10 @@ Example for MT7621:
                clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>;
                clock-names = "pcie0", "pcie1", "pcie2";
 
+               reset-gpios = <&gpio 19 GPIO_ACTIVE_LOW>,
+                               <&gpio 8 GPIO_ACTIVE_LOW>,
+                               <&gpio 7 GPIO_ACTIVE_LOW>;
+
                pcie@0,0 {
                        reg = <0x0000 0 0 0 0>;
                        #address-cells = <3>;
index 3633c92..f58e3a5 100644 (file)
@@ -45,8 +45,6 @@
 
 /* rt_sysc_membase relative registers */
 #define RALINK_CLKCFG1                 0x30
-#define RALINK_PCIE_CLK_GEN            0x7c
-#define RALINK_PCIE_CLK_GEN1           0x80
 
 /* Host-PCI bridge registers */
 #define RALINK_PCI_PCICFG_ADDR         0x0000
 #define RALINK_PCI_IOBASE              0x002C
 
 /* PCICFG virtual bridges */
-#define MT7621_BR0_MASK                        GENMASK(19, 16)
-#define MT7621_BR1_MASK                        GENMASK(23, 20)
-#define MT7621_BR2_MASK                        GENMASK(27, 24)
-#define MT7621_BR_ALL_MASK             GENMASK(27, 16)
-#define MT7621_BR0_SHIFT               16
-#define MT7621_BR1_SHIFT               20
-#define MT7621_BR2_SHIFT               24
+#define PCIE_P2P_MAX                   3
+#define PCIE_P2P_BR_DEVNUM_SHIFT(p)    (16 + (p) * 4)
+#define PCIE_P2P_BR_DEVNUM0_SHIFT      PCIE_P2P_BR_DEVNUM_SHIFT(0)
+#define PCIE_P2P_BR_DEVNUM1_SHIFT      PCIE_P2P_BR_DEVNUM_SHIFT(1)
+#define PCIE_P2P_BR_DEVNUM2_SHIFT      PCIE_P2P_BR_DEVNUM_SHIFT(2)
+#define PCIE_P2P_BR_DEVNUM_MASK                0xf
+#define PCIE_P2P_BR_DEVNUM_MASK_FULL   (0xfff << PCIE_P2P_BR_DEVNUM0_SHIFT)
 
 /* PCIe RC control registers */
 #define MT7621_PCIE_OFFSET             0x2000
 #define PCIE_PORT_CLK_EN(x)            BIT(24 + (x))
 #define PCIE_PORT_LINKUP               BIT(0)
 
-#define PCIE_CLK_GEN_EN                        BIT(31)
-#define PCIE_CLK_GEN_DIS               0
-#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
+#define PERST_DELAY_MS                 100
 
 /**
  * struct mt7621_pcie_port - PCIe port information
  * @pcie: pointer to PCIe host info
  * @phy: pointer to PHY control block
  * @pcie_rst: pointer to port reset control
+ * @gpio_rst: gpio reset
  * @slot: port slot
  * @enabled: indicates if port is enabled
  */
@@ -110,6 +105,7 @@ struct mt7621_pcie_port {
        struct mt7621_pcie *pcie;
        struct phy *phy;
        struct reset_control *pcie_rst;
+       struct gpio_desc *gpio_rst;
        u32 slot;
        bool enabled;
 };
@@ -122,9 +118,8 @@ struct mt7621_pcie_port {
  * @busn: bus range
  * @offset: IO / Memory offset
  * @dev: Pointer to PCIe device
+ * @io_map_base: virtual memory base address for io
  * @ports: pointer to PCIe port information
- * @perst: gpio reset
- * @rst: pointer to pcie reset
  * @resets_inverted: depends on chip revision
  * reset lines are inverted.
  */
@@ -138,9 +133,8 @@ struct mt7621_pcie {
                resource_size_t mem;
                resource_size_t io;
        } offset;
+       unsigned long io_map_base;
        struct list_head ports;
-       struct gpio_desc *perst;
-       struct reset_control *rst;
        bool resets_inverted;
 };
 
@@ -154,6 +148,15 @@ static inline void pcie_write(struct mt7621_pcie *pcie, u32 val, u32 reg)
        writel(val, pcie->base + reg);
 }
 
+static inline void pcie_rmw(struct mt7621_pcie *pcie, u32 reg, u32 clr, u32 set)
+{
+       u32 val = readl(pcie->base + reg);
+
+       val &= ~clr;
+       val |= set;
+       writel(val, pcie->base + reg);
+}
+
 static inline u32 pcie_port_read(struct mt7621_pcie_port *port, u32 reg)
 {
        return readl(port->base + reg);
@@ -207,16 +210,16 @@ 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)
+static inline void mt7621_rst_gpio_pcie_assert(struct mt7621_pcie_port *port)
 {
-       gpiod_set_value(pcie->perst, 0);
-       mdelay(PERST_DELAY_US);
+       if (port->gpio_rst)
+               gpiod_set_value(port->gpio_rst, 1);
 }
 
-static inline void mt7621_perst_gpio_pcie_deassert(struct mt7621_pcie *pcie)
+static inline void mt7621_rst_gpio_pcie_deassert(struct mt7621_pcie_port *port)
 {
-       gpiod_set_value(pcie->perst, 1);
-       mdelay(PERST_DELAY_US);
+       if (port->gpio_rst)
+               gpiod_set_value(port->gpio_rst, 0);
 }
 
 static inline bool mt7621_pcie_port_is_linkup(struct mt7621_pcie_port *port)
@@ -224,6 +227,11 @@ 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_enable(struct mt7621_pcie_port *port)
+{
+       rt_sysc_m32(0, PCIE_PORT_CLK_EN(port->slot), RALINK_CLKCFG1);
+}
+
 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);
@@ -249,13 +257,6 @@ static inline void mt7621_control_deassert(struct mt7621_pcie_port *port)
                reset_control_assert(port->pcie_rst);
 }
 
-static void mt7621_reset_port(struct mt7621_pcie_port *port)
-{
-       mt7621_control_assert(port);
-       msleep(100);
-       mt7621_control_deassert(port);
-}
-
 static void setup_cm_memory_region(struct mt7621_pcie *pcie)
 {
        struct resource *mem_resource = &pcie->mem;
@@ -292,22 +293,21 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie)
        }
 
        for_each_of_pci_range(&parser, &range) {
-               struct resource *res = NULL;
-
                switch (range.flags & IORESOURCE_TYPE_BITS) {
                case IORESOURCE_IO:
-                       ioremap(range.cpu_addr, range.size);
-                       res = &pcie->io;
+                       pcie->io_map_base =
+                               (unsigned long)ioremap(range.cpu_addr,
+                                                      range.size);
+                       of_pci_range_to_resource(&range, node, &pcie->io);
+                       pcie->io.start = range.cpu_addr;
+                       pcie->io.end = range.cpu_addr + range.size - 1;
                        pcie->offset.io = 0x00000000UL;
                        break;
                case IORESOURCE_MEM:
-                       res = &pcie->mem;
+                       of_pci_range_to_resource(&range, node, &pcie->mem);
                        pcie->offset.mem = 0x00000000UL;
                        break;
                }
-
-               if (res)
-                       of_pci_range_to_resource(&range, node, res);
        }
 
        err = of_pci_parse_bus_range(node, &pcie->busn);
@@ -319,6 +319,8 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie)
                pcie->busn.flags = IORESOURCE_BUS;
        }
 
+       set_io_port_base(pcie->io_map_base);
+
        return 0;
 }
 
@@ -356,9 +358,16 @@ static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie,
 
        snprintf(name, sizeof(name), "pcie-phy%d", slot);
        port->phy = devm_phy_get(dev, name);
-       if (IS_ERR(port->phy))
+       if (IS_ERR(port->phy) && slot != 1)
                return PTR_ERR(port->phy);
 
+       port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot,
+                                                      GPIOD_OUT_LOW);
+       if (IS_ERR(port->gpio_rst)) {
+               dev_err(dev, "Failed to get GPIO for PCIe%d\n", slot);
+               return PTR_ERR(port->gpio_rst);
+       }
+
        port->slot = slot;
        port->pcie = pcie;
 
@@ -375,12 +384,6 @@ 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");
@@ -391,12 +394,6 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
        if (IS_ERR(pcie->base))
                return PTR_ERR(pcie->base);
 
-       pcie->rst = devm_reset_control_get_exclusive(dev, "pcie");
-       if (PTR_ERR(pcie->rst) == -EPROBE_DEFER) {
-               dev_err(dev, "failed to get pcie reset control\n");
-               return PTR_ERR(pcie->rst);
-       }
-
        for_each_available_child_of_node(node, child) {
                int slot;
 
@@ -426,12 +423,6 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
        u32 slot = port->slot;
        int err;
 
-       /*
-        * Any MT7621 Ralink pcie controller that doesn't have 0x0101 at
-        * the end of the chip_id has inverted PCI resets.
-        */
-       mt7621_reset_port(port);
-
        err = phy_init(port->phy);
        if (err) {
                dev_err(dev, "failed to initialize port%d phy\n", slot);
@@ -450,34 +441,66 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
        return 0;
 }
 
+static void mt7621_pcie_reset_assert(struct mt7621_pcie *pcie)
+{
+       struct mt7621_pcie_port *port;
+
+       list_for_each_entry(port, &pcie->ports, list) {
+               /* PCIe RC reset assert */
+               mt7621_control_assert(port);
+
+               /* PCIe EP reset assert */
+               mt7621_rst_gpio_pcie_assert(port);
+       }
+
+       mdelay(PERST_DELAY_MS);
+}
+
+static void mt7621_pcie_reset_rc_deassert(struct mt7621_pcie *pcie)
+{
+       struct mt7621_pcie_port *port;
+
+       list_for_each_entry(port, &pcie->ports, list)
+               mt7621_control_deassert(port);
+}
+
+static void mt7621_pcie_reset_ep_deassert(struct mt7621_pcie *pcie)
+{
+       struct mt7621_pcie_port *port;
+
+       list_for_each_entry(port, &pcie->ports, list)
+               mt7621_rst_gpio_pcie_deassert(port);
+
+       mdelay(PERST_DELAY_MS);
+}
+
 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);
+       mt7621_pcie_reset_assert(pcie);
+       mt7621_pcie_reset_rc_deassert(pcie);
 
        list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
                u32 slot = port->slot;
 
+               if (slot == 1) {
+                       port->enabled = true;
+                       continue;
+               }
+
                err = mt7621_pcie_init_port(port);
                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);
+       mt7621_pcie_reset_ep_deassert(pcie);
 
        list_for_each_entry(port, &pcie->ports, list) {
                u32 slot = port->slot;
@@ -485,19 +508,13 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
                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);
+                       if (slot != 1)
+                               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);
-       rt_sysc_m32(PCIE_CLK_GEN_DIS, PCIE_CLK_GEN_EN, RALINK_PCIE_CLK_GEN);
-       msleep(50);
-       reset_control_deassert(pcie->rst);
 }
 
 static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
@@ -531,10 +548,15 @@ static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
        u32 slot;
        u32 val;
 
+       /* Setup MEMWIN and IOWIN */
+       pcie_write(pcie, 0xffffffff, RALINK_PCI_MEMBASE);
+       pcie_write(pcie, pcie->io.start, RALINK_PCI_IOBASE);
+
        list_for_each_entry(port, &pcie->ports, list) {
                if (port->enabled) {
+                       mt7621_pcie_port_clk_enable(port);
                        mt7621_pcie_enable_port(port);
-                       dev_info(dev, "PCIE%d enabled\n", num_slots_enabled);
+                       dev_info(dev, "PCIE%d enabled\n", port->slot);
                        num_slots_enabled++;
                }
        }
@@ -554,7 +576,9 @@ static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
 static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie)
 {
        u32 pcie_link_status = 0;
-       u32 val = 0;
+       u32 n;
+       int i;
+       u32 p2p_br_devnum[PCIE_P2P_MAX];
        struct mt7621_pcie_port *port;
 
        list_for_each_entry(port, &pcie->ports, list) {
@@ -567,50 +591,20 @@ static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie)
        if (pcie_link_status == 0)
                return -1;
 
-       /*
-        * pcie(2/1/0) link status      pcie2_num       pcie1_num       pcie0_num
-        * 3'b000                       x               x               x
-        * 3'b001                       x               x               0
-        * 3'b010                       x               0               x
-        * 3'b011                       x               1               0
-        * 3'b100                       0               x               x
-        * 3'b101                       1               x               0
-        * 3'b110                       1               0               x
-        * 3'b111                       2               1               0
-        */
-       switch (pcie_link_status) {
-       case 2:
-               val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
-               val &= ~(MT7621_BR0_MASK | MT7621_BR1_MASK);
-               val |= 0x1 << MT7621_BR0_SHIFT;
-               val |= 0x0 << MT7621_BR1_SHIFT;
-               pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-               break;
-       case 4:
-               val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
-               val &= ~MT7621_BR_ALL_MASK;
-               val |= 0x1 << MT7621_BR0_SHIFT;
-               val |= 0x2 << MT7621_BR1_SHIFT;
-               val |= 0x0 << MT7621_BR2_SHIFT;
-               pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-               break;
-       case 5:
-               val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
-               val &= ~MT7621_BR_ALL_MASK;
-               val |= 0x0 << MT7621_BR0_SHIFT;
-               val |= 0x2 << MT7621_BR1_SHIFT;
-               val |= 0x1 << MT7621_BR2_SHIFT;
-               pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-               break;
-       case 6:
-               val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
-               val &= ~MT7621_BR_ALL_MASK;
-               val |= 0x2 << MT7621_BR0_SHIFT;
-               val |= 0x0 << MT7621_BR1_SHIFT;
-               val |= 0x1 << MT7621_BR2_SHIFT;
-               pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-               break;
-       }
+       n = 0;
+       for (i = 0; i < PCIE_P2P_MAX; i++)
+               if (pcie_link_status & BIT(i))
+                       p2p_br_devnum[i] = n++;
+
+       for (i = 0; i < PCIE_P2P_MAX; i++)
+               if ((pcie_link_status & BIT(i)) == 0)
+                       p2p_br_devnum[i] = n++;
+
+       pcie_rmw(pcie, RALINK_PCI_PCICFG_ADDR,
+                PCIE_P2P_BR_DEVNUM_MASK_FULL,
+                (p2p_br_devnum[0] << PCIE_P2P_BR_DEVNUM0_SHIFT) |
+                (p2p_br_devnum[1] << PCIE_P2P_BR_DEVNUM1_SHIFT) |
+                (p2p_br_devnum[2] << PCIE_P2P_BR_DEVNUM2_SHIFT));
 
        return 0;
 }
@@ -678,11 +672,15 @@ static int mt7621_pci_probe(struct platform_device *pdev)
                return err;
        }
 
+       err = mt7621_pci_parse_request_of_pci_ranges(pcie);
+       if (err) {
+               dev_err(dev, "Error requesting pci resources from ranges");
+               return err;
+       }
+
        /* set resources limits */
-       iomem_resource.start = 0;
-       iomem_resource.end = ~0UL; /* no limit */
-       ioport_resource.start = 0;
-       ioport_resource.end = ~0UL; /* no limit */
+       ioport_resource.start = pcie->io.start;
+       ioport_resource.end = pcie->io.end;
 
        mt7621_pcie_init_ports(pcie);
 
@@ -694,12 +692,6 @@ static int mt7621_pci_probe(struct platform_device *pdev)
 
        mt7621_pcie_enable_ports(pcie);
 
-       err = mt7621_pci_parse_request_of_pci_ranges(pcie);
-       if (err) {
-               dev_err(dev, "Error requesting pci resources from ranges");
-               return err;
-       }
-
        setup_cm_memory_region(pcie);
 
        err = mt7621_pcie_request_resources(pcie, &res);
@@ -731,9 +723,4 @@ static struct platform_driver mt7621_pci_driver = {
        },
 };
 
-static int __init mt7621_pci_init(void)
-{
-       return platform_driver_register(&mt7621_pci_driver);
-}
-
-module_init(mt7621_pci_init);
+builtin_platform_driver(mt7621_pci_driver);
index f152d84..c8d4c13 100644 (file)
@@ -1,5 +1,5 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
- *
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
+/*
  * Copyright (c) 2003-2012 Broadcom Corporation
  * All Rights Reserved
  */
index 518ea80..8365b74 100644 (file)
@@ -1,5 +1,5 @@
-/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
- *
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
+/*
  * Copyright (c) 2003-2012 Broadcom Corporation
  * All Rights Reserved
  */
diff --git a/drivers/staging/octeon-usb/Kconfig b/drivers/staging/octeon-usb/Kconfig
new file mode 100644 (file)
index 0000000..6a5d842
--- /dev/null
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+config OCTEON_USB
+       tristate "Cavium Networks Octeon USB support"
+       depends on CAVIUM_OCTEON_SOC && USB
+       help
+         This driver supports USB host controller on some Cavium
+         Networks' products in the Octeon family.
+
+         To compile this driver as a module, choose M here. The module
+         will be called octeon-hcd.
+
diff --git a/drivers/staging/octeon-usb/Makefile b/drivers/staging/octeon-usb/Makefile
new file mode 100644 (file)
index 0000000..9873a01
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-${CONFIG_OCTEON_USB} := octeon-hcd.o
diff --git a/drivers/staging/octeon-usb/TODO b/drivers/staging/octeon-usb/TODO
new file mode 100644 (file)
index 0000000..2b29acc
--- /dev/null
@@ -0,0 +1,8 @@
+This driver is functional and has been tested on EdgeRouter Lite,
+D-Link DSR-1000N and EBH5600 evaluation board with USB mass storage.
+
+TODO:
+       - kernel coding style
+       - checkpatch warnings
+
+Contact: Aaro Koskinen <aaro.koskinen@iki.fi>
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
new file mode 100644 (file)
index 0000000..61471a1
--- /dev/null
@@ -0,0 +1,3737 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Cavium Networks
+ *
+ * Some parts of the code were originally released under BSD license:
+ *
+ * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ *   * Neither the name of Cavium Networks nor the names of
+ *     its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written
+ *     permission.
+ *
+ * This Software, including technical data, may be subject to U.S. export
+ * control laws, including the U.S. Export Administration Act and its associated
+ * regulations, and may be subject to export or import regulations in other
+ * countries.
+ *
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+ * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
+ * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
+ * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION
+ * OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
+ * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
+ * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
+ * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
+ * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
+ */
+
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb/hcd.h>
+#include <linux/prefetch.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <asm/octeon/octeon.h>
+
+#include "octeon-hcd.h"
+
+/**
+ * enum cvmx_usb_speed - the possible USB device speeds
+ *
+ * @CVMX_USB_SPEED_HIGH: Device is operation at 480Mbps
+ * @CVMX_USB_SPEED_FULL: Device is operation at 12Mbps
+ * @CVMX_USB_SPEED_LOW:  Device is operation at 1.5Mbps
+ */
+enum cvmx_usb_speed {
+       CVMX_USB_SPEED_HIGH = 0,
+       CVMX_USB_SPEED_FULL = 1,
+       CVMX_USB_SPEED_LOW = 2,
+};
+
+/**
+ * enum cvmx_usb_transfer - the possible USB transfer types
+ *
+ * @CVMX_USB_TRANSFER_CONTROL:    USB transfer type control for hub and status
+ *                                transfers
+ * @CVMX_USB_TRANSFER_ISOCHRONOUS: USB transfer type isochronous for low
+ *                                priority periodic transfers
+ * @CVMX_USB_TRANSFER_BULK:       USB transfer type bulk for large low priority
+ *                                transfers
+ * @CVMX_USB_TRANSFER_INTERRUPT:   USB transfer type interrupt for high priority
+ *                                periodic transfers
+ */
+enum cvmx_usb_transfer {
+       CVMX_USB_TRANSFER_CONTROL = 0,
+       CVMX_USB_TRANSFER_ISOCHRONOUS = 1,
+       CVMX_USB_TRANSFER_BULK = 2,
+       CVMX_USB_TRANSFER_INTERRUPT = 3,
+};
+
+/**
+ * enum cvmx_usb_direction - the transfer directions
+ *
+ * @CVMX_USB_DIRECTION_OUT: Data is transferring from Octeon to the device/host
+ * @CVMX_USB_DIRECTION_IN:  Data is transferring from the device/host to Octeon
+ */
+enum cvmx_usb_direction {
+       CVMX_USB_DIRECTION_OUT,
+       CVMX_USB_DIRECTION_IN,
+};
+
+/**
+ * enum cvmx_usb_status - possible callback function status codes
+ *
+ * @CVMX_USB_STATUS_OK:                  The transaction / operation finished without
+ *                               any errors
+ * @CVMX_USB_STATUS_SHORT:       FIXME: This is currently not implemented
+ * @CVMX_USB_STATUS_CANCEL:      The transaction was canceled while in flight
+ *                               by a user call to cvmx_usb_cancel
+ * @CVMX_USB_STATUS_ERROR:       The transaction aborted with an unexpected
+ *                               error status
+ * @CVMX_USB_STATUS_STALL:       The transaction received a USB STALL response
+ *                               from the device
+ * @CVMX_USB_STATUS_XACTERR:     The transaction failed with an error from the
+ *                               device even after a number of retries
+ * @CVMX_USB_STATUS_DATATGLERR:          The transaction failed with a data toggle
+ *                               error even after a number of retries
+ * @CVMX_USB_STATUS_BABBLEERR:   The transaction failed with a babble error
+ * @CVMX_USB_STATUS_FRAMEERR:    The transaction failed with a frame error
+ *                               even after a number of retries
+ */
+enum cvmx_usb_status {
+       CVMX_USB_STATUS_OK,
+       CVMX_USB_STATUS_SHORT,
+       CVMX_USB_STATUS_CANCEL,
+       CVMX_USB_STATUS_ERROR,
+       CVMX_USB_STATUS_STALL,
+       CVMX_USB_STATUS_XACTERR,
+       CVMX_USB_STATUS_DATATGLERR,
+       CVMX_USB_STATUS_BABBLEERR,
+       CVMX_USB_STATUS_FRAMEERR,
+};
+
+/**
+ * struct cvmx_usb_port_status - the USB port status information
+ *
+ * @port_enabled:      1 = Usb port is enabled, 0 = disabled
+ * @port_over_current: 1 = Over current detected, 0 = Over current not
+ *                     detected. Octeon doesn't support over current detection.
+ * @port_powered:      1 = Port power is being supplied to the device, 0 =
+ *                     power is off. Octeon doesn't support turning port power
+ *                     off.
+ * @port_speed:                Current port speed.
+ * @connected:         1 = A device is connected to the port, 0 = No device is
+ *                     connected.
+ * @connect_change:    1 = Device connected state changed since the last set
+ *                     status call.
+ */
+struct cvmx_usb_port_status {
+       u32 reserved                    : 25;
+       u32 port_enabled                : 1;
+       u32 port_over_current           : 1;
+       u32 port_powered                : 1;
+       enum cvmx_usb_speed port_speed  : 2;
+       u32 connected                   : 1;
+       u32 connect_change              : 1;
+};
+
+/**
+ * struct cvmx_usb_iso_packet - descriptor for Isochronous packets
+ *
+ * @offset:    This is the offset in bytes into the main buffer where this data
+ *             is stored.
+ * @length:    This is the length in bytes of the data.
+ * @status:    This is the status of this individual packet transfer.
+ */
+struct cvmx_usb_iso_packet {
+       int offset;
+       int length;
+       enum cvmx_usb_status status;
+};
+
+/**
+ * enum cvmx_usb_initialize_flags - flags used by the initialization function
+ *
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI:    The USB port uses a 12MHz crystal
+ *                                           as clock source at USB_XO and
+ *                                           USB_XI.
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND:   The USB port uses 12/24/48MHz 2.5V
+ *                                           board clock source at USB_XO.
+ *                                           USB_XI should be tied to GND.
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK: Mask for clock speed field
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:    Speed of reference clock or
+ *                                           crystal
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:    Speed of reference clock
+ * @CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:    Speed of reference clock
+ * @CVMX_USB_INITIALIZE_FLAGS_NO_DMA:        Disable DMA and used polled IO for
+ *                                           data transfer use for the USB
+ */
+enum cvmx_usb_initialize_flags {
+       CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI           = 1 << 0,
+       CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND          = 1 << 1,
+       CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK        = 3 << 3,
+       CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ           = 1 << 3,
+       CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ           = 2 << 3,
+       CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ           = 3 << 3,
+       /* Bits 3-4 used to encode the clock frequency */
+       CVMX_USB_INITIALIZE_FLAGS_NO_DMA                = 1 << 5,
+};
+
+/**
+ * enum cvmx_usb_pipe_flags - internal flags for a pipe.
+ *
+ * @CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is
+ *                                actively using hardware.
+ * @CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high speed
+ *                                pipe is in the ping state.
+ */
+enum cvmx_usb_pipe_flags {
+       CVMX_USB_PIPE_FLAGS_SCHEDULED   = 1 << 17,
+       CVMX_USB_PIPE_FLAGS_NEED_PING   = 1 << 18,
+};
+
+/* Maximum number of times to retry failed transactions */
+#define MAX_RETRIES            3
+
+/* Maximum number of hardware channels supported by the USB block */
+#define MAX_CHANNELS           8
+
+/*
+ * The low level hardware can transfer a maximum of this number of bytes in each
+ * transfer. The field is 19 bits wide
+ */
+#define MAX_TRANSFER_BYTES     ((1 << 19) - 1)
+
+/*
+ * The low level hardware can transfer a maximum of this number of packets in
+ * each transfer. The field is 10 bits wide
+ */
+#define MAX_TRANSFER_PACKETS   ((1 << 10) - 1)
+
+/**
+ * Logical transactions may take numerous low level
+ * transactions, especially when splits are concerned. This
+ * enum represents all of the possible stages a transaction can
+ * be in. Note that split completes are always even. This is so
+ * the NAK handler can backup to the previous low level
+ * transaction with a simple clearing of bit 0.
+ */
+enum cvmx_usb_stage {
+       CVMX_USB_STAGE_NON_CONTROL,
+       CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE,
+       CVMX_USB_STAGE_SETUP,
+       CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE,
+       CVMX_USB_STAGE_DATA,
+       CVMX_USB_STAGE_DATA_SPLIT_COMPLETE,
+       CVMX_USB_STAGE_STATUS,
+       CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE,
+};
+
+/**
+ * struct cvmx_usb_transaction - describes each pending USB transaction
+ *                              regardless of type. These are linked together
+ *                              to form a list of pending requests for a pipe.
+ *
+ * @node:              List node for transactions in the pipe.
+ * @type:              Type of transaction, duplicated of the pipe.
+ * @flags:             State flags for this transaction.
+ * @buffer:            User's physical buffer address to read/write.
+ * @buffer_length:     Size of the user's buffer in bytes.
+ * @control_header:    For control transactions, physical address of the 8
+ *                     byte standard header.
+ * @iso_start_frame:   For ISO transactions, the starting frame number.
+ * @iso_number_packets:        For ISO transactions, the number of packets in the
+ *                     request.
+ * @iso_packets:       For ISO transactions, the sub packets in the request.
+ * @actual_bytes:      Actual bytes transfer for this transaction.
+ * @stage:             For control transactions, the current stage.
+ * @urb:               URB.
+ */
+struct cvmx_usb_transaction {
+       struct list_head node;
+       enum cvmx_usb_transfer type;
+       u64 buffer;
+       int buffer_length;
+       u64 control_header;
+       int iso_start_frame;
+       int iso_number_packets;
+       struct cvmx_usb_iso_packet *iso_packets;
+       int xfersize;
+       int pktcnt;
+       int retries;
+       int actual_bytes;
+       enum cvmx_usb_stage stage;
+       struct urb *urb;
+};
+
+/**
+ * struct cvmx_usb_pipe - a pipe represents a virtual connection between Octeon
+ *                       and some USB device. It contains a list of pending
+ *                       request to the device.
+ *
+ * @node:              List node for pipe list
+ * @next:              Pipe after this one in the list
+ * @transactions:      List of pending transactions
+ * @interval:          For periodic pipes, the interval between packets in
+ *                     frames
+ * @next_tx_frame:     The next frame this pipe is allowed to transmit on
+ * @flags:             State flags for this pipe
+ * @device_speed:      Speed of device connected to this pipe
+ * @transfer_type:     Type of transaction supported by this pipe
+ * @transfer_dir:      IN or OUT. Ignored for Control
+ * @multi_count:       Max packet in a row for the device
+ * @max_packet:                The device's maximum packet size in bytes
+ * @device_addr:       USB device address at other end of pipe
+ * @endpoint_num:      USB endpoint number at other end of pipe
+ * @hub_device_addr:   Hub address this device is connected to
+ * @hub_port:          Hub port this device is connected to
+ * @pid_toggle:                This toggles between 0/1 on every packet send to track
+ *                     the data pid needed
+ * @channel:           Hardware DMA channel for this pipe
+ * @split_sc_frame:    The low order bits of the frame number the split
+ *                     complete should be sent on
+ */
+struct cvmx_usb_pipe {
+       struct list_head node;
+       struct list_head transactions;
+       u64 interval;
+       u64 next_tx_frame;
+       enum cvmx_usb_pipe_flags flags;
+       enum cvmx_usb_speed device_speed;
+       enum cvmx_usb_transfer transfer_type;
+       enum cvmx_usb_direction transfer_dir;
+       int multi_count;
+       u16 max_packet;
+       u8 device_addr;
+       u8 endpoint_num;
+       u8 hub_device_addr;
+       u8 hub_port;
+       u8 pid_toggle;
+       u8 channel;
+       s8 split_sc_frame;
+};
+
+struct cvmx_usb_tx_fifo {
+       struct {
+               int channel;
+               int size;
+               u64 address;
+       } entry[MAX_CHANNELS + 1];
+       int head;
+       int tail;
+};
+
+/**
+ * struct octeon_hcd - the state of the USB block
+ *
+ * lock:                  Serialization lock.
+ * init_flags:            Flags passed to initialize.
+ * index:                 Which USB block this is for.
+ * idle_hardware_channels: Bit set for every idle hardware channel.
+ * usbcx_hprt:            Stored port status so we don't need to read a CSR to
+ *                        determine splits.
+ * pipe_for_channel:      Map channels to pipes.
+ * pipe:                  Storage for pipes.
+ * indent:                Used by debug output to indent functions.
+ * port_status:                   Last port status used for change notification.
+ * idle_pipes:            List of open pipes that have no transactions.
+ * active_pipes:          Active pipes indexed by transfer type.
+ * frame_number:          Increments every SOF interrupt for time keeping.
+ * active_split:          Points to the current active split, or NULL.
+ */
+struct octeon_hcd {
+       spinlock_t lock; /* serialization lock */
+       int init_flags;
+       int index;
+       int idle_hardware_channels;
+       union cvmx_usbcx_hprt usbcx_hprt;
+       struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS];
+       int indent;
+       struct cvmx_usb_port_status port_status;
+       struct list_head idle_pipes;
+       struct list_head active_pipes[4];
+       u64 frame_number;
+       struct cvmx_usb_transaction *active_split;
+       struct cvmx_usb_tx_fifo periodic;
+       struct cvmx_usb_tx_fifo nonperiodic;
+};
+
+/*
+ * This macro logically sets a single field in a CSR. It does the sequence
+ * read, modify, and write
+ */
+#define USB_SET_FIELD32(address, _union, field, value)         \
+       do {                                                    \
+               union _union c;                                 \
+                                                               \
+               c.u32 = cvmx_usb_read_csr32(usb, address);      \
+               c.s.field = value;                              \
+               cvmx_usb_write_csr32(usb, address, c.u32);      \
+       } while (0)
+
+/* Returns the IO address to push/pop stuff data from the FIFOs */
+#define USB_FIFO_ADDRESS(channel, usb_index) \
+       (CVMX_USBCX_GOTGCTL(usb_index) + ((channel) + 1) * 0x1000)
+
+/**
+ * struct octeon_temp_buffer - a bounce buffer for USB transfers
+ * @orig_buffer: the original buffer passed by the USB stack
+ * @data:       the newly allocated temporary buffer (excluding meta-data)
+ *
+ * Both the DMA engine and FIFO mode will always transfer full 32-bit words. If
+ * the buffer is too short, we need to allocate a temporary one, and this struct
+ * represents it.
+ */
+struct octeon_temp_buffer {
+       void *orig_buffer;
+       u8 data[];
+};
+
+static inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p)
+{
+       return container_of((void *)p, struct usb_hcd, hcd_priv);
+}
+
+/**
+ * octeon_alloc_temp_buffer - allocate a temporary buffer for USB transfer
+ *                            (if needed)
+ * @urb:       URB.
+ * @mem_flags: Memory allocation flags.
+ *
+ * This function allocates a temporary bounce buffer whenever it's needed
+ * due to HW limitations.
+ */
+static int octeon_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+{
+       struct octeon_temp_buffer *temp;
+
+       if (urb->num_sgs || urb->sg ||
+           (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) ||
+           !(urb->transfer_buffer_length % sizeof(u32)))
+               return 0;
+
+       temp = kmalloc(ALIGN(urb->transfer_buffer_length, sizeof(u32)) +
+                      sizeof(*temp), mem_flags);
+       if (!temp)
+               return -ENOMEM;
+
+       temp->orig_buffer = urb->transfer_buffer;
+       if (usb_urb_dir_out(urb))
+               memcpy(temp->data, urb->transfer_buffer,
+                      urb->transfer_buffer_length);
+       urb->transfer_buffer = temp->data;
+       urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
+
+       return 0;
+}
+
+/**
+ * octeon_free_temp_buffer - free a temporary buffer used by USB transfers.
+ * @urb: URB.
+ *
+ * Frees a buffer allocated by octeon_alloc_temp_buffer().
+ */
+static void octeon_free_temp_buffer(struct urb *urb)
+{
+       struct octeon_temp_buffer *temp;
+       size_t length;
+
+       if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
+               return;
+
+       temp = container_of(urb->transfer_buffer, struct octeon_temp_buffer,
+                           data);
+       if (usb_urb_dir_in(urb)) {
+               if (usb_pipeisoc(urb->pipe))
+                       length = urb->transfer_buffer_length;
+               else
+                       length = urb->actual_length;
+
+               memcpy(temp->orig_buffer, urb->transfer_buffer, length);
+       }
+       urb->transfer_buffer = temp->orig_buffer;
+       urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
+       kfree(temp);
+}
+
+/**
+ * octeon_map_urb_for_dma - Octeon-specific map_urb_for_dma().
+ * @hcd:       USB HCD structure.
+ * @urb:       URB.
+ * @mem_flags: Memory allocation flags.
+ */
+static int octeon_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+                                 gfp_t mem_flags)
+{
+       int ret;
+
+       ret = octeon_alloc_temp_buffer(urb, mem_flags);
+       if (ret)
+               return ret;
+
+       ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+       if (ret)
+               octeon_free_temp_buffer(urb);
+
+       return ret;
+}
+
+/**
+ * octeon_unmap_urb_for_dma - Octeon-specific unmap_urb_for_dma()
+ * @hcd:       USB HCD structure.
+ * @urb:       URB.
+ */
+static void octeon_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+       usb_hcd_unmap_urb_for_dma(hcd, urb);
+       octeon_free_temp_buffer(urb);
+}
+
+/**
+ * Read a USB 32bit CSR. It performs the necessary address swizzle
+ * for 32bit CSRs and logs the value in a readable format if
+ * debugging is on.
+ *
+ * @usb:     USB block this access is for
+ * @address: 64bit address to read
+ *
+ * Returns: Result of the read
+ */
+static inline u32 cvmx_usb_read_csr32(struct octeon_hcd *usb, u64 address)
+{
+       return cvmx_read64_uint32(address ^ 4);
+}
+
+/**
+ * Write a USB 32bit CSR. It performs the necessary address
+ * swizzle for 32bit CSRs and logs the value in a readable format
+ * if debugging is on.
+ *
+ * @usb:     USB block this access is for
+ * @address: 64bit address to write
+ * @value:   Value to write
+ */
+static inline void cvmx_usb_write_csr32(struct octeon_hcd *usb,
+                                       u64 address, u32 value)
+{
+       cvmx_write64_uint32(address ^ 4, value);
+       cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+}
+
+/**
+ * Return non zero if this pipe connects to a non HIGH speed
+ * device through a high speed hub.
+ *
+ * @usb:    USB block this access is for
+ * @pipe:   Pipe to check
+ *
+ * Returns: Non zero if we need to do split transactions
+ */
+static inline int cvmx_usb_pipe_needs_split(struct octeon_hcd *usb,
+                                           struct cvmx_usb_pipe *pipe)
+{
+       return pipe->device_speed != CVMX_USB_SPEED_HIGH &&
+              usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH;
+}
+
+/**
+ * Trivial utility function to return the correct PID for a pipe
+ *
+ * @pipe:   pipe to check
+ *
+ * Returns: PID for pipe
+ */
+static inline int cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe)
+{
+       if (pipe->pid_toggle)
+               return 2; /* Data1 */
+       return 0; /* Data0 */
+}
+
+/* Loops through register until txfflsh or rxfflsh become zero.*/
+static int cvmx_wait_tx_rx(struct octeon_hcd *usb, int fflsh_type)
+{
+       int result;
+       u64 address = CVMX_USBCX_GRSTCTL(usb->index);
+       u64 done = cvmx_get_cycle() + 100 *
+                  (u64)octeon_get_clock_rate / 1000000;
+       union cvmx_usbcx_grstctl c;
+
+       while (1) {
+               c.u32 = cvmx_usb_read_csr32(usb, address);
+               if (fflsh_type == 0 && c.s.txfflsh == 0) {
+                       result = 0;
+                       break;
+               } else if (fflsh_type == 1 && c.s.rxfflsh == 0) {
+                       result = 0;
+                       break;
+               } else if (cvmx_get_cycle() > done) {
+                       result = -1;
+                       break;
+               }
+
+               __delay(100);
+       }
+       return result;
+}
+
+static void cvmx_fifo_setup(struct octeon_hcd *usb)
+{
+       union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
+       union cvmx_usbcx_gnptxfsiz npsiz;
+       union cvmx_usbcx_hptxfsiz psiz;
+
+       usbcx_ghwcfg3.u32 = cvmx_usb_read_csr32(usb,
+                                               CVMX_USBCX_GHWCFG3(usb->index));
+
+       /*
+        * Program the USBC_GRXFSIZ register to select the size of the receive
+        * FIFO (25%).
+        */
+       USB_SET_FIELD32(CVMX_USBCX_GRXFSIZ(usb->index), cvmx_usbcx_grxfsiz,
+                       rxfdep, usbcx_ghwcfg3.s.dfifodepth / 4);
+
+       /*
+        * Program the USBC_GNPTXFSIZ register to select the size and the start
+        * address of the non-periodic transmit FIFO for nonperiodic
+        * transactions (50%).
+        */
+       npsiz.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index));
+       npsiz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
+       npsiz.s.nptxfstaddr = usbcx_ghwcfg3.s.dfifodepth / 4;
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_GNPTXFSIZ(usb->index), npsiz.u32);
+
+       /*
+        * Program the USBC_HPTXFSIZ register to select the size and start
+        * address of the periodic transmit FIFO for periodic transactions
+        * (25%).
+        */
+       psiz.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index));
+       psiz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
+       psiz.s.ptxfstaddr = 3 * usbcx_ghwcfg3.s.dfifodepth / 4;
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_HPTXFSIZ(usb->index), psiz.u32);
+
+       /* Flush all FIFOs */
+       USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+                       cvmx_usbcx_grstctl, txfnum, 0x10);
+       USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+                       cvmx_usbcx_grstctl, txfflsh, 1);
+       cvmx_wait_tx_rx(usb, 0);
+       USB_SET_FIELD32(CVMX_USBCX_GRSTCTL(usb->index),
+                       cvmx_usbcx_grstctl, rxfflsh, 1);
+       cvmx_wait_tx_rx(usb, 1);
+}
+
+/**
+ * Shutdown a USB port after a call to cvmx_usb_initialize().
+ * The port should be disabled with all pipes closed when this
+ * function is called.
+ *
+ * @usb: USB device state populated by cvmx_usb_initialize().
+ *
+ * Returns: 0 or a negative error code.
+ */
+static int cvmx_usb_shutdown(struct octeon_hcd *usb)
+{
+       union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+
+       /* Make sure all pipes are closed */
+       if (!list_empty(&usb->idle_pipes) ||
+           !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_ISOCHRONOUS]) ||
+           !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_INTERRUPT]) ||
+           !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_CONTROL]) ||
+           !list_empty(&usb->active_pipes[CVMX_USB_TRANSFER_BULK]))
+               return -EBUSY;
+
+       /* Disable the clocks and put them in power on reset */
+       usbn_clk_ctl.u64 = cvmx_read64_uint64(CVMX_USBNX_CLK_CTL(usb->index));
+       usbn_clk_ctl.s.enable = 1;
+       usbn_clk_ctl.s.por = 1;
+       usbn_clk_ctl.s.hclk_rst = 1;
+       usbn_clk_ctl.s.prst = 0;
+       usbn_clk_ctl.s.hrst = 0;
+       cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+       return 0;
+}
+
+/**
+ * Initialize a USB port for use. This must be called before any
+ * other access to the Octeon USB port is made. The port starts
+ * off in the disabled state.
+ *
+ * @dev:        Pointer to struct device for logging purposes.
+ * @usb:        Pointer to struct octeon_hcd.
+ *
+ * Returns: 0 or a negative error code.
+ */
+static int cvmx_usb_initialize(struct device *dev,
+                              struct octeon_hcd *usb)
+{
+       int channel;
+       int divisor;
+       int retries = 0;
+       union cvmx_usbcx_hcfg usbcx_hcfg;
+       union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+       union cvmx_usbcx_gintsts usbc_gintsts;
+       union cvmx_usbcx_gahbcfg usbcx_gahbcfg;
+       union cvmx_usbcx_gintmsk usbcx_gintmsk;
+       union cvmx_usbcx_gusbcfg usbcx_gusbcfg;
+       union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status;
+
+retry:
+       /*
+        * Power On Reset and PHY Initialization
+        *
+        * 1. Wait for DCOK to assert (nothing to do)
+        *
+        * 2a. Write USBN0/1_CLK_CTL[POR] = 1 and
+        *     USBN0/1_CLK_CTL[HRST,PRST,HCLK_RST] = 0
+        */
+       usbn_clk_ctl.u64 = cvmx_read64_uint64(CVMX_USBNX_CLK_CTL(usb->index));
+       usbn_clk_ctl.s.por = 1;
+       usbn_clk_ctl.s.hrst = 0;
+       usbn_clk_ctl.s.prst = 0;
+       usbn_clk_ctl.s.hclk_rst = 0;
+       usbn_clk_ctl.s.enable = 0;
+       /*
+        * 2b. Select the USB reference clock/crystal parameters by writing
+        *     appropriate values to USBN0/1_CLK_CTL[P_C_SEL, P_RTYPE, P_COM_ON]
+        */
+       if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND) {
+               /*
+                * The USB port uses 12/24/48MHz 2.5V board clock
+                * source at USB_XO. USB_XI should be tied to GND.
+                * Most Octeon evaluation boards require this setting
+                */
+               if (OCTEON_IS_MODEL(OCTEON_CN3XXX) ||
+                   OCTEON_IS_MODEL(OCTEON_CN56XX) ||
+                   OCTEON_IS_MODEL(OCTEON_CN50XX))
+                       /* From CN56XX,CN50XX,CN31XX,CN30XX manuals */
+                       usbn_clk_ctl.s.p_rtype = 2; /* p_rclk=1 & p_xenbn=0 */
+               else
+                       /* From CN52XX manual */
+                       usbn_clk_ctl.s.p_rtype = 1;
+
+               switch (usb->init_flags &
+                       CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) {
+               case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:
+                       usbn_clk_ctl.s.p_c_sel = 0;
+                       break;
+               case CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ:
+                       usbn_clk_ctl.s.p_c_sel = 1;
+                       break;
+               case CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ:
+                       usbn_clk_ctl.s.p_c_sel = 2;
+                       break;
+               }
+       } else {
+               /*
+                * The USB port uses a 12MHz crystal as clock source
+                * at USB_XO and USB_XI
+                */
+               if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
+                       /* From CN31XX,CN30XX manual */
+                       usbn_clk_ctl.s.p_rtype = 3; /* p_rclk=1 & p_xenbn=1 */
+               else
+                       /* From CN56XX,CN52XX,CN50XX manuals. */
+                       usbn_clk_ctl.s.p_rtype = 0;
+
+               usbn_clk_ctl.s.p_c_sel = 0;
+       }
+       /*
+        * 2c. Select the HCLK via writing USBN0/1_CLK_CTL[DIVIDE, DIVIDE2] and
+        *     setting USBN0/1_CLK_CTL[ENABLE] = 1. Divide the core clock down
+        *     such that USB is as close as possible to 125Mhz
+        */
+       divisor = DIV_ROUND_UP(octeon_get_clock_rate(), 125000000);
+       /* Lower than 4 doesn't seem to work properly */
+       if (divisor < 4)
+               divisor = 4;
+       usbn_clk_ctl.s.divide = divisor;
+       usbn_clk_ctl.s.divide2 = 0;
+       cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+
+       /* 2d. Write USBN0/1_CLK_CTL[HCLK_RST] = 1 */
+       usbn_clk_ctl.s.hclk_rst = 1;
+       cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+       /* 2e.  Wait 64 core-clock cycles for HCLK to stabilize */
+       __delay(64);
+       /*
+        * 3. Program the power-on reset field in the USBN clock-control
+        *    register:
+        *    USBN_CLK_CTL[POR] = 0
+        */
+       usbn_clk_ctl.s.por = 0;
+       cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+       /* 4. Wait 1 ms for PHY clock to start */
+       mdelay(1);
+       /*
+        * 5. Program the Reset input from automatic test equipment field in the
+        *    USBP control and status register:
+        *    USBN_USBP_CTL_STATUS[ATE_RESET] = 1
+        */
+       usbn_usbp_ctl_status.u64 =
+               cvmx_read64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index));
+       usbn_usbp_ctl_status.s.ate_reset = 1;
+       cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+                           usbn_usbp_ctl_status.u64);
+       /* 6. Wait 10 cycles */
+       __delay(10);
+       /*
+        * 7. Clear ATE_RESET field in the USBN clock-control register:
+        *    USBN_USBP_CTL_STATUS[ATE_RESET] = 0
+        */
+       usbn_usbp_ctl_status.s.ate_reset = 0;
+       cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+                           usbn_usbp_ctl_status.u64);
+       /*
+        * 8. Program the PHY reset field in the USBN clock-control register:
+        *    USBN_CLK_CTL[PRST] = 1
+        */
+       usbn_clk_ctl.s.prst = 1;
+       cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+       /*
+        * 9. Program the USBP control and status register to select host or
+        *    device mode. USBN_USBP_CTL_STATUS[HST_MODE] = 0 for host, = 1 for
+        *    device
+        */
+       usbn_usbp_ctl_status.s.hst_mode = 0;
+       cvmx_write64_uint64(CVMX_USBNX_USBP_CTL_STATUS(usb->index),
+                           usbn_usbp_ctl_status.u64);
+       /* 10. Wait 1 us */
+       udelay(1);
+       /*
+        * 11. Program the hreset_n field in the USBN clock-control register:
+        *     USBN_CLK_CTL[HRST] = 1
+        */
+       usbn_clk_ctl.s.hrst = 1;
+       cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+       /* 12. Proceed to USB core initialization */
+       usbn_clk_ctl.s.enable = 1;
+       cvmx_write64_uint64(CVMX_USBNX_CLK_CTL(usb->index), usbn_clk_ctl.u64);
+       udelay(1);
+
+       /*
+        * USB Core Initialization
+        *
+        * 1. Read USBC_GHWCFG1, USBC_GHWCFG2, USBC_GHWCFG3, USBC_GHWCFG4 to
+        *    determine USB core configuration parameters.
+        *
+        *    Nothing needed
+        *
+        * 2. Program the following fields in the global AHB configuration
+        *    register (USBC_GAHBCFG)
+        *    DMA mode, USBC_GAHBCFG[DMAEn]: 1 = DMA mode, 0 = slave mode
+        *    Burst length, USBC_GAHBCFG[HBSTLEN] = 0
+        *    Nonperiodic TxFIFO empty level (slave mode only),
+        *    USBC_GAHBCFG[NPTXFEMPLVL]
+        *    Periodic TxFIFO empty level (slave mode only),
+        *    USBC_GAHBCFG[PTXFEMPLVL]
+        *    Global interrupt mask, USBC_GAHBCFG[GLBLINTRMSK] = 1
+        */
+       usbcx_gahbcfg.u32 = 0;
+       usbcx_gahbcfg.s.dmaen = !(usb->init_flags &
+                                 CVMX_USB_INITIALIZE_FLAGS_NO_DMA);
+       usbcx_gahbcfg.s.hbstlen = 0;
+       usbcx_gahbcfg.s.nptxfemplvl = 1;
+       usbcx_gahbcfg.s.ptxfemplvl = 1;
+       usbcx_gahbcfg.s.glblintrmsk = 1;
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_GAHBCFG(usb->index),
+                            usbcx_gahbcfg.u32);
+
+       /*
+        * 3. Program the following fields in USBC_GUSBCFG register.
+        *    HS/FS timeout calibration, USBC_GUSBCFG[TOUTCAL] = 0
+        *    ULPI DDR select, USBC_GUSBCFG[DDRSEL] = 0
+        *    USB turnaround time, USBC_GUSBCFG[USBTRDTIM] = 0x5
+        *    PHY low-power clock select, USBC_GUSBCFG[PHYLPWRCLKSEL] = 0
+        */
+       usbcx_gusbcfg.u32 = cvmx_usb_read_csr32(usb,
+                                               CVMX_USBCX_GUSBCFG(usb->index));
+       usbcx_gusbcfg.s.toutcal = 0;
+       usbcx_gusbcfg.s.ddrsel = 0;
+       usbcx_gusbcfg.s.usbtrdtim = 0x5;
+       usbcx_gusbcfg.s.phylpwrclksel = 0;
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_GUSBCFG(usb->index),
+                            usbcx_gusbcfg.u32);
+
+       /*
+        * 4. The software must unmask the following bits in the USBC_GINTMSK
+        *    register.
+        *    OTG interrupt mask, USBC_GINTMSK[OTGINTMSK] = 1
+        *    Mode mismatch interrupt mask, USBC_GINTMSK[MODEMISMSK] = 1
+        */
+       usbcx_gintmsk.u32 = cvmx_usb_read_csr32(usb,
+                                               CVMX_USBCX_GINTMSK(usb->index));
+       usbcx_gintmsk.s.otgintmsk = 1;
+       usbcx_gintmsk.s.modemismsk = 1;
+       usbcx_gintmsk.s.hchintmsk = 1;
+       usbcx_gintmsk.s.sofmsk = 0;
+       /* We need RX FIFO interrupts if we don't have DMA */
+       if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+               usbcx_gintmsk.s.rxflvlmsk = 1;
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTMSK(usb->index),
+                            usbcx_gintmsk.u32);
+
+       /*
+        * Disable all channel interrupts. We'll enable them per channel later.
+        */
+       for (channel = 0; channel < 8; channel++)
+               cvmx_usb_write_csr32(usb,
+                                    CVMX_USBCX_HCINTMSKX(channel, usb->index),
+                                    0);
+
+       /*
+        * Host Port Initialization
+        *
+        * 1. Program the host-port interrupt-mask field to unmask,
+        *    USBC_GINTMSK[PRTINT] = 1
+        */
+       USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+                       cvmx_usbcx_gintmsk, prtintmsk, 1);
+       USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+                       cvmx_usbcx_gintmsk, disconnintmsk, 1);
+
+       /*
+        * 2. Program the USBC_HCFG register to select full-speed host
+        *    or high-speed host.
+        */
+       usbcx_hcfg.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HCFG(usb->index));
+       usbcx_hcfg.s.fslssupp = 0;
+       usbcx_hcfg.s.fslspclksel = 0;
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_HCFG(usb->index), usbcx_hcfg.u32);
+
+       cvmx_fifo_setup(usb);
+
+       /*
+        * If the controller is getting port events right after the reset, it
+        * means the initialization failed. Try resetting the controller again
+        * in such case. This is seen to happen after cold boot on DSR-1000N.
+        */
+       usbc_gintsts.u32 = cvmx_usb_read_csr32(usb,
+                                              CVMX_USBCX_GINTSTS(usb->index));
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index),
+                            usbc_gintsts.u32);
+       dev_dbg(dev, "gintsts after reset: 0x%x\n", (int)usbc_gintsts.u32);
+       if (!usbc_gintsts.s.disconnint && !usbc_gintsts.s.prtint)
+               return 0;
+       if (retries++ >= 5)
+               return -EAGAIN;
+       dev_info(dev, "controller reset failed (gintsts=0x%x) - retrying\n",
+                (int)usbc_gintsts.u32);
+       msleep(50);
+       cvmx_usb_shutdown(usb);
+       msleep(50);
+       goto retry;
+}
+
+/**
+ * Reset a USB port. After this call succeeds, the USB port is
+ * online and servicing requests.
+ *
+ * @usb: USB device state populated by cvmx_usb_initialize().
+ */
+static void cvmx_usb_reset_port(struct octeon_hcd *usb)
+{
+       usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb,
+                                                 CVMX_USBCX_HPRT(usb->index));
+
+       /* Program the port reset bit to start the reset process */
+       USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
+                       prtrst, 1);
+
+       /*
+        * Wait at least 50ms (high speed), or 10ms (full speed) for the reset
+        * process to complete.
+        */
+       mdelay(50);
+
+       /* Program the port reset bit to 0, USBC_HPRT[PRTRST] = 0 */
+       USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
+                       prtrst, 0);
+
+       /*
+        * Read the port speed field to get the enumerated speed,
+        * USBC_HPRT[PRTSPD].
+        */
+       usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb,
+                                                 CVMX_USBCX_HPRT(usb->index));
+}
+
+/**
+ * Disable a USB port. After this call the USB port will not
+ * generate data transfers and will not generate events.
+ * Transactions in process will fail and call their
+ * associated callbacks.
+ *
+ * @usb: USB device state populated by cvmx_usb_initialize().
+ *
+ * Returns: 0 or a negative error code.
+ */
+static int cvmx_usb_disable(struct octeon_hcd *usb)
+{
+       /* Disable the port */
+       USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
+                       prtena, 1);
+       return 0;
+}
+
+/**
+ * Get the current state of the USB port. Use this call to
+ * determine if the usb port has anything connected, is enabled,
+ * or has some sort of error condition. The return value of this
+ * call has "changed" bits to signal of the value of some fields
+ * have changed between calls.
+ *
+ * @usb: USB device state populated by cvmx_usb_initialize().
+ *
+ * Returns: Port status information
+ */
+static struct cvmx_usb_port_status cvmx_usb_get_status(struct octeon_hcd *usb)
+{
+       union cvmx_usbcx_hprt usbc_hprt;
+       struct cvmx_usb_port_status result;
+
+       memset(&result, 0, sizeof(result));
+
+       usbc_hprt.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+       result.port_enabled = usbc_hprt.s.prtena;
+       result.port_over_current = usbc_hprt.s.prtovrcurract;
+       result.port_powered = usbc_hprt.s.prtpwr;
+       result.port_speed = usbc_hprt.s.prtspd;
+       result.connected = usbc_hprt.s.prtconnsts;
+       result.connect_change =
+               result.connected != usb->port_status.connected;
+
+       return result;
+}
+
+/**
+ * Open a virtual pipe between the host and a USB device. A pipe
+ * must be opened before data can be transferred between a device
+ * and Octeon.
+ *
+ * @usb:            USB device state populated by cvmx_usb_initialize().
+ * @device_addr:
+ *                  USB device address to open the pipe to
+ *                  (0-127).
+ * @endpoint_num:
+ *                  USB endpoint number to open the pipe to
+ *                  (0-15).
+ * @device_speed:
+ *                  The speed of the device the pipe is going
+ *                  to. This must match the device's speed,
+ *                  which may be different than the port speed.
+ * @max_packet:             The maximum packet length the device can
+ *                  transmit/receive (low speed=0-8, full
+ *                  speed=0-1023, high speed=0-1024). This value
+ *                  comes from the standard endpoint descriptor
+ *                  field wMaxPacketSize bits <10:0>.
+ * @transfer_type:
+ *                  The type of transfer this pipe is for.
+ * @transfer_dir:
+ *                  The direction the pipe is in. This is not
+ *                  used for control pipes.
+ * @interval:       For ISOCHRONOUS and INTERRUPT transfers,
+ *                  this is how often the transfer is scheduled
+ *                  for. All other transfers should specify
+ *                  zero. The units are in frames (8000/sec at
+ *                  high speed, 1000/sec for full speed).
+ * @multi_count:
+ *                  For high speed devices, this is the maximum
+ *                  allowed number of packet per microframe.
+ *                  Specify zero for non high speed devices. This
+ *                  value comes from the standard endpoint descriptor
+ *                  field wMaxPacketSize bits <12:11>.
+ * @hub_device_addr:
+ *                  Hub device address this device is connected
+ *                  to. Devices connected directly to Octeon
+ *                  use zero. This is only used when the device
+ *                  is full/low speed behind a high speed hub.
+ *                  The address will be of the high speed hub,
+ *                  not and full speed hubs after it.
+ * @hub_port:       Which port on the hub the device is
+ *                  connected. Use zero for devices connected
+ *                  directly to Octeon. Like hub_device_addr,
+ *                  this is only used for full/low speed
+ *                  devices behind a high speed hub.
+ *
+ * Returns: A non-NULL value is a pipe. NULL means an error.
+ */
+static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct octeon_hcd *usb,
+                                               int device_addr,
+                                               int endpoint_num,
+                                               enum cvmx_usb_speed
+                                                       device_speed,
+                                               int max_packet,
+                                               enum cvmx_usb_transfer
+                                                       transfer_type,
+                                               enum cvmx_usb_direction
+                                                       transfer_dir,
+                                               int interval, int multi_count,
+                                               int hub_device_addr,
+                                               int hub_port)
+{
+       struct cvmx_usb_pipe *pipe;
+
+       pipe = kzalloc(sizeof(*pipe), GFP_ATOMIC);
+       if (!pipe)
+               return NULL;
+       if ((device_speed == CVMX_USB_SPEED_HIGH) &&
+           (transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+           (transfer_type == CVMX_USB_TRANSFER_BULK))
+               pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
+       pipe->device_addr = device_addr;
+       pipe->endpoint_num = endpoint_num;
+       pipe->device_speed = device_speed;
+       pipe->max_packet = max_packet;
+       pipe->transfer_type = transfer_type;
+       pipe->transfer_dir = transfer_dir;
+       INIT_LIST_HEAD(&pipe->transactions);
+
+       /*
+        * All pipes use interval to rate limit NAK processing. Force an
+        * interval if one wasn't supplied
+        */
+       if (!interval)
+               interval = 1;
+       if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+               pipe->interval = interval * 8;
+               /* Force start splits to be schedule on uFrame 0 */
+               pipe->next_tx_frame = ((usb->frame_number + 7) & ~7) +
+                                       pipe->interval;
+       } else {
+               pipe->interval = interval;
+               pipe->next_tx_frame = usb->frame_number + pipe->interval;
+       }
+       pipe->multi_count = multi_count;
+       pipe->hub_device_addr = hub_device_addr;
+       pipe->hub_port = hub_port;
+       pipe->pid_toggle = 0;
+       pipe->split_sc_frame = -1;
+       list_add_tail(&pipe->node, &usb->idle_pipes);
+
+       /*
+        * We don't need to tell the hardware about this pipe yet since
+        * it doesn't have any submitted requests
+        */
+
+       return pipe;
+}
+
+/**
+ * Poll the RX FIFOs and remove data as needed. This function is only used
+ * in non DMA mode. It is very important that this function be called quickly
+ * enough to prevent FIFO overflow.
+ *
+ * @usb:       USB device state populated by cvmx_usb_initialize().
+ */
+static void cvmx_usb_poll_rx_fifo(struct octeon_hcd *usb)
+{
+       union cvmx_usbcx_grxstsph rx_status;
+       int channel;
+       int bytes;
+       u64 address;
+       u32 *ptr;
+
+       rx_status.u32 = cvmx_usb_read_csr32(usb,
+                                           CVMX_USBCX_GRXSTSPH(usb->index));
+       /* Only read data if IN data is there */
+       if (rx_status.s.pktsts != 2)
+               return;
+       /* Check if no data is available */
+       if (!rx_status.s.bcnt)
+               return;
+
+       channel = rx_status.s.chnum;
+       bytes = rx_status.s.bcnt;
+       if (!bytes)
+               return;
+
+       /* Get where the DMA engine would have written this data */
+       address = cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index) +
+                                    channel * 8);
+
+       ptr = cvmx_phys_to_ptr(address);
+       cvmx_write64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel * 8,
+                           address + bytes);
+
+       /* Loop writing the FIFO data for this packet into memory */
+       while (bytes > 0) {
+               *ptr++ = cvmx_usb_read_csr32(usb,
+                                       USB_FIFO_ADDRESS(channel, usb->index));
+               bytes -= 4;
+       }
+       CVMX_SYNCW;
+}
+
+/**
+ * Fill the TX hardware fifo with data out of the software
+ * fifos
+ *
+ * @usb:           USB device state populated by cvmx_usb_initialize().
+ * @fifo:          Software fifo to use
+ * @available:     Amount of space in the hardware fifo
+ *
+ * Returns: Non zero if the hardware fifo was too small and needs
+ *         to be serviced again.
+ */
+static int cvmx_usb_fill_tx_hw(struct octeon_hcd *usb,
+                              struct cvmx_usb_tx_fifo *fifo, int available)
+{
+       /*
+        * We're done either when there isn't anymore space or the software FIFO
+        * is empty
+        */
+       while (available && (fifo->head != fifo->tail)) {
+               int i = fifo->tail;
+               const u32 *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
+               u64 csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel,
+                                                  usb->index) ^ 4;
+               int words = available;
+
+               /* Limit the amount of data to what the SW fifo has */
+               if (fifo->entry[i].size <= available) {
+                       words = fifo->entry[i].size;
+                       fifo->tail++;
+                       if (fifo->tail > MAX_CHANNELS)
+                               fifo->tail = 0;
+               }
+
+               /* Update the next locations and counts */
+               available -= words;
+               fifo->entry[i].address += words * 4;
+               fifo->entry[i].size -= words;
+
+               /*
+                * Write the HW fifo data. The read every three writes is due
+                * to an errata on CN3XXX chips
+                */
+               while (words > 3) {
+                       cvmx_write64_uint32(csr_address, *ptr++);
+                       cvmx_write64_uint32(csr_address, *ptr++);
+                       cvmx_write64_uint32(csr_address, *ptr++);
+                       cvmx_read64_uint64(
+                                       CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+                       words -= 3;
+               }
+               cvmx_write64_uint32(csr_address, *ptr++);
+               if (--words) {
+                       cvmx_write64_uint32(csr_address, *ptr++);
+                       if (--words)
+                               cvmx_write64_uint32(csr_address, *ptr++);
+               }
+               cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
+       }
+       return fifo->head != fifo->tail;
+}
+
+/**
+ * Check the hardware FIFOs and fill them as needed
+ *
+ * @usb:       USB device state populated by cvmx_usb_initialize().
+ */
+static void cvmx_usb_poll_tx_fifo(struct octeon_hcd *usb)
+{
+       if (usb->periodic.head != usb->periodic.tail) {
+               union cvmx_usbcx_hptxsts tx_status;
+
+               tx_status.u32 = cvmx_usb_read_csr32(usb,
+                                       CVMX_USBCX_HPTXSTS(usb->index));
+               if (cvmx_usb_fill_tx_hw(usb, &usb->periodic,
+                                       tx_status.s.ptxfspcavail))
+                       USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+                                       cvmx_usbcx_gintmsk, ptxfempmsk, 1);
+               else
+                       USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+                                       cvmx_usbcx_gintmsk, ptxfempmsk, 0);
+       }
+
+       if (usb->nonperiodic.head != usb->nonperiodic.tail) {
+               union cvmx_usbcx_gnptxsts tx_status;
+
+               tx_status.u32 = cvmx_usb_read_csr32(usb,
+                                       CVMX_USBCX_GNPTXSTS(usb->index));
+               if (cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic,
+                                       tx_status.s.nptxfspcavail))
+                       USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+                                       cvmx_usbcx_gintmsk, nptxfempmsk, 1);
+               else
+                       USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+                                       cvmx_usbcx_gintmsk, nptxfempmsk, 0);
+       }
+}
+
+/**
+ * Fill the TX FIFO with an outgoing packet
+ *
+ * @usb:         USB device state populated by cvmx_usb_initialize().
+ * @channel:     Channel number to get packet from
+ */
+static void cvmx_usb_fill_tx_fifo(struct octeon_hcd *usb, int channel)
+{
+       union cvmx_usbcx_hccharx hcchar;
+       union cvmx_usbcx_hcspltx usbc_hcsplt;
+       union cvmx_usbcx_hctsizx usbc_hctsiz;
+       struct cvmx_usb_tx_fifo *fifo;
+
+       /* We only need to fill data on outbound channels */
+       hcchar.u32 = cvmx_usb_read_csr32(usb,
+                       CVMX_USBCX_HCCHARX(channel, usb->index));
+       if (hcchar.s.epdir != CVMX_USB_DIRECTION_OUT)
+               return;
+
+       /* OUT Splits only have data on the start and not the complete */
+       usbc_hcsplt.u32 = cvmx_usb_read_csr32(usb,
+                               CVMX_USBCX_HCSPLTX(channel, usb->index));
+       if (usbc_hcsplt.s.spltena && usbc_hcsplt.s.compsplt)
+               return;
+
+       /*
+        * Find out how many bytes we need to fill and convert it into 32bit
+        * words.
+        */
+       usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb,
+                               CVMX_USBCX_HCTSIZX(channel, usb->index));
+       if (!usbc_hctsiz.s.xfersize)
+               return;
+
+       if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) ||
+           (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS))
+               fifo = &usb->periodic;
+       else
+               fifo = &usb->nonperiodic;
+
+       fifo->entry[fifo->head].channel = channel;
+       fifo->entry[fifo->head].address =
+               cvmx_read64_uint64(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) +
+                                  channel * 8);
+       fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize + 3) >> 2;
+       fifo->head++;
+       if (fifo->head > MAX_CHANNELS)
+               fifo->head = 0;
+
+       cvmx_usb_poll_tx_fifo(usb);
+}
+
+/**
+ * Perform channel specific setup for Control transactions. All
+ * the generic stuff will already have been done in cvmx_usb_start_channel().
+ *
+ * @usb:         USB device state populated by cvmx_usb_initialize().
+ * @channel:     Channel to setup
+ * @pipe:        Pipe for control transaction
+ */
+static void cvmx_usb_start_channel_control(struct octeon_hcd *usb,
+                                          int channel,
+                                          struct cvmx_usb_pipe *pipe)
+{
+       struct usb_hcd *hcd = octeon_to_hcd(usb);
+       struct device *dev = hcd->self.controller;
+       struct cvmx_usb_transaction *transaction =
+               list_first_entry(&pipe->transactions, typeof(*transaction),
+                                node);
+       struct usb_ctrlrequest *header =
+               cvmx_phys_to_ptr(transaction->control_header);
+       int bytes_to_transfer = transaction->buffer_length -
+               transaction->actual_bytes;
+       int packets_to_transfer;
+       union cvmx_usbcx_hctsizx usbc_hctsiz;
+
+       usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb,
+                               CVMX_USBCX_HCTSIZX(channel, usb->index));
+
+       switch (transaction->stage) {
+       case CVMX_USB_STAGE_NON_CONTROL:
+       case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
+               dev_err(dev, "%s: ERROR - Non control stage\n", __func__);
+               break;
+       case CVMX_USB_STAGE_SETUP:
+               usbc_hctsiz.s.pid = 3; /* Setup */
+               bytes_to_transfer = sizeof(*header);
+               /* All Control operations start with a setup going OUT */
+               USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+                               cvmx_usbcx_hccharx, epdir,
+                               CVMX_USB_DIRECTION_OUT);
+               /*
+                * Setup send the control header instead of the buffer data. The
+                * buffer data will be used in the next stage
+                */
+               cvmx_write64_uint64(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) +
+                                       channel * 8,
+                                   transaction->control_header);
+               break;
+       case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
+               usbc_hctsiz.s.pid = 3; /* Setup */
+               bytes_to_transfer = 0;
+               /* All Control operations start with a setup going OUT */
+               USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+                               cvmx_usbcx_hccharx, epdir,
+                               CVMX_USB_DIRECTION_OUT);
+
+               USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
+                               cvmx_usbcx_hcspltx, compsplt, 1);
+               break;
+       case CVMX_USB_STAGE_DATA:
+               usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
+               if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+                       if (header->bRequestType & USB_DIR_IN)
+                               bytes_to_transfer = 0;
+                       else if (bytes_to_transfer > pipe->max_packet)
+                               bytes_to_transfer = pipe->max_packet;
+               }
+               USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+                               cvmx_usbcx_hccharx, epdir,
+                               ((header->bRequestType & USB_DIR_IN) ?
+                                       CVMX_USB_DIRECTION_IN :
+                                       CVMX_USB_DIRECTION_OUT));
+               break;
+       case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
+               usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
+               if (!(header->bRequestType & USB_DIR_IN))
+                       bytes_to_transfer = 0;
+               USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+                               cvmx_usbcx_hccharx, epdir,
+                               ((header->bRequestType & USB_DIR_IN) ?
+                                       CVMX_USB_DIRECTION_IN :
+                                       CVMX_USB_DIRECTION_OUT));
+               USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
+                               cvmx_usbcx_hcspltx, compsplt, 1);
+               break;
+       case CVMX_USB_STAGE_STATUS:
+               usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
+               bytes_to_transfer = 0;
+               USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+                               cvmx_usbcx_hccharx, epdir,
+                               ((header->bRequestType & USB_DIR_IN) ?
+                                       CVMX_USB_DIRECTION_OUT :
+                                       CVMX_USB_DIRECTION_IN));
+               break;
+       case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
+               usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
+               bytes_to_transfer = 0;
+               USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+                               cvmx_usbcx_hccharx, epdir,
+                               ((header->bRequestType & USB_DIR_IN) ?
+                                       CVMX_USB_DIRECTION_OUT :
+                                       CVMX_USB_DIRECTION_IN));
+               USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
+                               cvmx_usbcx_hcspltx, compsplt, 1);
+               break;
+       }
+
+       /*
+        * Make sure the transfer never exceeds the byte limit of the hardware.
+        * Further bytes will be sent as continued transactions
+        */
+       if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
+               /* Round MAX_TRANSFER_BYTES to a multiple of out packet size */
+               bytes_to_transfer = MAX_TRANSFER_BYTES / pipe->max_packet;
+               bytes_to_transfer *= pipe->max_packet;
+       }
+
+       /*
+        * Calculate the number of packets to transfer. If the length is zero
+        * we still need to transfer one packet
+        */
+       packets_to_transfer = DIV_ROUND_UP(bytes_to_transfer,
+                                          pipe->max_packet);
+       if (packets_to_transfer == 0) {
+               packets_to_transfer = 1;
+       } else if ((packets_to_transfer > 1) &&
+                       (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+               /*
+                * Limit to one packet when not using DMA. Channels must be
+                * restarted between every packet for IN transactions, so there
+                * is no reason to do multiple packets in a row
+                */
+               packets_to_transfer = 1;
+               bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+       } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
+               /*
+                * Limit the number of packet and data transferred to what the
+                * hardware can handle
+                */
+               packets_to_transfer = MAX_TRANSFER_PACKETS;
+               bytes_to_transfer = packets_to_transfer * pipe->max_packet;
+       }
+
+       usbc_hctsiz.s.xfersize = bytes_to_transfer;
+       usbc_hctsiz.s.pktcnt = packets_to_transfer;
+
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_HCTSIZX(channel, usb->index),
+                            usbc_hctsiz.u32);
+}
+
+/**
+ * Start a channel to perform the pipe's head transaction
+ *
+ * @usb:         USB device state populated by cvmx_usb_initialize().
+ * @channel:     Channel to setup
+ * @pipe:        Pipe to start
+ */
+static void cvmx_usb_start_channel(struct octeon_hcd *usb, int channel,
+                                  struct cvmx_usb_pipe *pipe)
+{
+       struct cvmx_usb_transaction *transaction =
+               list_first_entry(&pipe->transactions, typeof(*transaction),
+                                node);
+
+       /* Make sure all writes to the DMA region get flushed */
+       CVMX_SYNCW;
+
+       /* Attach the channel to the pipe */
+       usb->pipe_for_channel[channel] = pipe;
+       pipe->channel = channel;
+       pipe->flags |= CVMX_USB_PIPE_FLAGS_SCHEDULED;
+
+       /* Mark this channel as in use */
+       usb->idle_hardware_channels &= ~(1 << channel);
+
+       /* Enable the channel interrupt bits */
+       {
+               union cvmx_usbcx_hcintx usbc_hcint;
+               union cvmx_usbcx_hcintmskx usbc_hcintmsk;
+               union cvmx_usbcx_haintmsk usbc_haintmsk;
+
+               /* Clear all channel status bits */
+               usbc_hcint.u32 = cvmx_usb_read_csr32(usb,
+                                       CVMX_USBCX_HCINTX(channel, usb->index));
+
+               cvmx_usb_write_csr32(usb,
+                                    CVMX_USBCX_HCINTX(channel, usb->index),
+                                    usbc_hcint.u32);
+
+               usbc_hcintmsk.u32 = 0;
+               usbc_hcintmsk.s.chhltdmsk = 1;
+               if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+                       /*
+                        * Channels need these extra interrupts when we aren't
+                        * in DMA mode.
+                        */
+                       usbc_hcintmsk.s.datatglerrmsk = 1;
+                       usbc_hcintmsk.s.frmovrunmsk = 1;
+                       usbc_hcintmsk.s.bblerrmsk = 1;
+                       usbc_hcintmsk.s.xacterrmsk = 1;
+                       if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+                               /*
+                                * Splits don't generate xfercompl, so we need
+                                * ACK and NYET.
+                                */
+                               usbc_hcintmsk.s.nyetmsk = 1;
+                               usbc_hcintmsk.s.ackmsk = 1;
+                       }
+                       usbc_hcintmsk.s.nakmsk = 1;
+                       usbc_hcintmsk.s.stallmsk = 1;
+                       usbc_hcintmsk.s.xfercomplmsk = 1;
+               }
+               cvmx_usb_write_csr32(usb,
+                                    CVMX_USBCX_HCINTMSKX(channel, usb->index),
+                                    usbc_hcintmsk.u32);
+
+               /* Enable the channel interrupt to propagate */
+               usbc_haintmsk.u32 = cvmx_usb_read_csr32(usb,
+                                       CVMX_USBCX_HAINTMSK(usb->index));
+               usbc_haintmsk.s.haintmsk |= 1 << channel;
+               cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index),
+                                    usbc_haintmsk.u32);
+       }
+
+       /* Setup the location the DMA engine uses. */
+       {
+               u64 reg;
+               u64 dma_address = transaction->buffer +
+                                 transaction->actual_bytes;
+
+               if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+                       dma_address = transaction->buffer +
+                                       transaction->iso_packets[0].offset +
+                                       transaction->actual_bytes;
+
+               if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT)
+                       reg = CVMX_USBNX_DMA0_OUTB_CHN0(usb->index);
+               else
+                       reg = CVMX_USBNX_DMA0_INB_CHN0(usb->index);
+               cvmx_write64_uint64(reg + channel * 8, dma_address);
+       }
+
+       /* Setup both the size of the transfer and the SPLIT characteristics */
+       {
+               union cvmx_usbcx_hcspltx usbc_hcsplt = {.u32 = 0};
+               union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 = 0};
+               int packets_to_transfer;
+               int bytes_to_transfer = transaction->buffer_length -
+                       transaction->actual_bytes;
+
+               /*
+                * ISOCHRONOUS transactions store each individual transfer size
+                * in the packet structure, not the global buffer_length
+                */
+               if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+                       bytes_to_transfer =
+                               transaction->iso_packets[0].length -
+                               transaction->actual_bytes;
+
+               /*
+                * We need to do split transactions when we are talking to non
+                * high speed devices that are behind a high speed hub
+                */
+               if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+                       /*
+                        * On the start split phase (stage is even) record the
+                        * frame number we will need to send the split complete.
+                        * We only store the lower two bits since the time ahead
+                        * can only be two frames
+                        */
+                       if ((transaction->stage & 1) == 0) {
+                               if (transaction->type == CVMX_USB_TRANSFER_BULK)
+                                       pipe->split_sc_frame =
+                                               (usb->frame_number + 1) & 0x7f;
+                               else
+                                       pipe->split_sc_frame =
+                                               (usb->frame_number + 2) & 0x7f;
+                       } else {
+                               pipe->split_sc_frame = -1;
+                       }
+
+                       usbc_hcsplt.s.spltena = 1;
+                       usbc_hcsplt.s.hubaddr = pipe->hub_device_addr;
+                       usbc_hcsplt.s.prtaddr = pipe->hub_port;
+                       usbc_hcsplt.s.compsplt = (transaction->stage ==
+                               CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE);
+
+                       /*
+                        * SPLIT transactions can only ever transmit one data
+                        * packet so limit the transfer size to the max packet
+                        * size
+                        */
+                       if (bytes_to_transfer > pipe->max_packet)
+                               bytes_to_transfer = pipe->max_packet;
+
+                       /*
+                        * ISOCHRONOUS OUT splits are unique in that they limit
+                        * data transfers to 188 byte chunks representing the
+                        * begin/middle/end of the data or all
+                        */
+                       if (!usbc_hcsplt.s.compsplt &&
+                           (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+                           (pipe->transfer_type ==
+                            CVMX_USB_TRANSFER_ISOCHRONOUS)) {
+                               /*
+                                * Clear the split complete frame number as
+                                * there isn't going to be a split complete
+                                */
+                               pipe->split_sc_frame = -1;
+                               /*
+                                * See if we've started this transfer and sent
+                                * data
+                                */
+                               if (transaction->actual_bytes == 0) {
+                                       /*
+                                        * Nothing sent yet, this is either a
+                                        * begin or the entire payload
+                                        */
+                                       if (bytes_to_transfer <= 188)
+                                               /* Entire payload in one go */
+                                               usbc_hcsplt.s.xactpos = 3;
+                                       else
+                                               /* First part of payload */
+                                               usbc_hcsplt.s.xactpos = 2;
+                               } else {
+                                       /*
+                                        * Continuing the previous data, we must
+                                        * either be in the middle or at the end
+                                        */
+                                       if (bytes_to_transfer <= 188)
+                                               /* End of payload */
+                                               usbc_hcsplt.s.xactpos = 1;
+                                       else
+                                               /* Middle of payload */
+                                               usbc_hcsplt.s.xactpos = 0;
+                               }
+                               /*
+                                * Again, the transfer size is limited to 188
+                                * bytes
+                                */
+                               if (bytes_to_transfer > 188)
+                                       bytes_to_transfer = 188;
+                       }
+               }
+
+               /*
+                * Make sure the transfer never exceeds the byte limit of the
+                * hardware. Further bytes will be sent as continued
+                * transactions
+                */
+               if (bytes_to_transfer > MAX_TRANSFER_BYTES) {
+                       /*
+                        * Round MAX_TRANSFER_BYTES to a multiple of out packet
+                        * size
+                        */
+                       bytes_to_transfer = MAX_TRANSFER_BYTES /
+                               pipe->max_packet;
+                       bytes_to_transfer *= pipe->max_packet;
+               }
+
+               /*
+                * Calculate the number of packets to transfer. If the length is
+                * zero we still need to transfer one packet
+                */
+               packets_to_transfer =
+                       DIV_ROUND_UP(bytes_to_transfer, pipe->max_packet);
+               if (packets_to_transfer == 0) {
+                       packets_to_transfer = 1;
+               } else if ((packets_to_transfer > 1) &&
+                          (usb->init_flags &
+                           CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+                       /*
+                        * Limit to one packet when not using DMA. Channels must
+                        * be restarted between every packet for IN
+                        * transactions, so there is no reason to do multiple
+                        * packets in a row
+                        */
+                       packets_to_transfer = 1;
+                       bytes_to_transfer = packets_to_transfer *
+                               pipe->max_packet;
+               } else if (packets_to_transfer > MAX_TRANSFER_PACKETS) {
+                       /*
+                        * Limit the number of packet and data transferred to
+                        * what the hardware can handle
+                        */
+                       packets_to_transfer = MAX_TRANSFER_PACKETS;
+                       bytes_to_transfer = packets_to_transfer *
+                               pipe->max_packet;
+               }
+
+               usbc_hctsiz.s.xfersize = bytes_to_transfer;
+               usbc_hctsiz.s.pktcnt = packets_to_transfer;
+
+               /* Update the DATA0/DATA1 toggle */
+               usbc_hctsiz.s.pid = cvmx_usb_get_data_pid(pipe);
+               /*
+                * High speed pipes may need a hardware ping before they start
+                */
+               if (pipe->flags & CVMX_USB_PIPE_FLAGS_NEED_PING)
+                       usbc_hctsiz.s.dopng = 1;
+
+               cvmx_usb_write_csr32(usb,
+                                    CVMX_USBCX_HCSPLTX(channel, usb->index),
+                                    usbc_hcsplt.u32);
+               cvmx_usb_write_csr32(usb,
+                                    CVMX_USBCX_HCTSIZX(channel, usb->index),
+                                    usbc_hctsiz.u32);
+       }
+
+       /* Setup the Host Channel Characteristics Register */
+       {
+               union cvmx_usbcx_hccharx usbc_hcchar = {.u32 = 0};
+
+               /*
+                * Set the startframe odd/even properly. This is only used for
+                * periodic
+                */
+               usbc_hcchar.s.oddfrm = usb->frame_number & 1;
+
+               /*
+                * Set the number of back to back packets allowed by this
+                * endpoint. Split transactions interpret "ec" as the number of
+                * immediate retries of failure. These retries happen too
+                * quickly, so we disable these entirely for splits
+                */
+               if (cvmx_usb_pipe_needs_split(usb, pipe))
+                       usbc_hcchar.s.ec = 1;
+               else if (pipe->multi_count < 1)
+                       usbc_hcchar.s.ec = 1;
+               else if (pipe->multi_count > 3)
+                       usbc_hcchar.s.ec = 3;
+               else
+                       usbc_hcchar.s.ec = pipe->multi_count;
+
+               /* Set the rest of the endpoint specific settings */
+               usbc_hcchar.s.devaddr = pipe->device_addr;
+               usbc_hcchar.s.eptype = transaction->type;
+               usbc_hcchar.s.lspddev =
+                       (pipe->device_speed == CVMX_USB_SPEED_LOW);
+               usbc_hcchar.s.epdir = pipe->transfer_dir;
+               usbc_hcchar.s.epnum = pipe->endpoint_num;
+               usbc_hcchar.s.mps = pipe->max_packet;
+               cvmx_usb_write_csr32(usb,
+                                    CVMX_USBCX_HCCHARX(channel, usb->index),
+                                    usbc_hcchar.u32);
+       }
+
+       /* Do transaction type specific fixups as needed */
+       switch (transaction->type) {
+       case CVMX_USB_TRANSFER_CONTROL:
+               cvmx_usb_start_channel_control(usb, channel, pipe);
+               break;
+       case CVMX_USB_TRANSFER_BULK:
+       case CVMX_USB_TRANSFER_INTERRUPT:
+               break;
+       case CVMX_USB_TRANSFER_ISOCHRONOUS:
+               if (!cvmx_usb_pipe_needs_split(usb, pipe)) {
+                       /*
+                        * ISO transactions require different PIDs depending on
+                        * direction and how many packets are needed
+                        */
+                       if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
+                               if (pipe->multi_count < 2) /* Need DATA0 */
+                                       USB_SET_FIELD32(
+                                               CVMX_USBCX_HCTSIZX(channel,
+                                                                  usb->index),
+                                               cvmx_usbcx_hctsizx, pid, 0);
+                               else /* Need MDATA */
+                                       USB_SET_FIELD32(
+                                               CVMX_USBCX_HCTSIZX(channel,
+                                                                  usb->index),
+                                               cvmx_usbcx_hctsizx, pid, 3);
+                       }
+               }
+               break;
+       }
+       {
+               union cvmx_usbcx_hctsizx usbc_hctsiz = { .u32 =
+                       cvmx_usb_read_csr32(usb,
+                                           CVMX_USBCX_HCTSIZX(channel,
+                                                              usb->index))
+               };
+               transaction->xfersize = usbc_hctsiz.s.xfersize;
+               transaction->pktcnt = usbc_hctsiz.s.pktcnt;
+       }
+       /* Remember when we start a split transaction */
+       if (cvmx_usb_pipe_needs_split(usb, pipe))
+               usb->active_split = transaction;
+       USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+                       cvmx_usbcx_hccharx, chena, 1);
+       if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+               cvmx_usb_fill_tx_fifo(usb, channel);
+}
+
+/**
+ * Find a pipe that is ready to be scheduled to hardware.
+ * @usb:        USB device state populated by cvmx_usb_initialize().
+ * @xfer_type:  Transfer type
+ *
+ * Returns: Pipe or NULL if none are ready
+ */
+static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(struct octeon_hcd *usb,
+               enum cvmx_usb_transfer xfer_type)
+{
+       struct list_head *list = usb->active_pipes + xfer_type;
+       u64 current_frame = usb->frame_number;
+       struct cvmx_usb_pipe *pipe;
+
+       list_for_each_entry(pipe, list, node) {
+               struct cvmx_usb_transaction *t =
+                       list_first_entry(&pipe->transactions, typeof(*t),
+                                        node);
+               if (!(pipe->flags & CVMX_USB_PIPE_FLAGS_SCHEDULED) && t &&
+                   (pipe->next_tx_frame <= current_frame) &&
+                   ((pipe->split_sc_frame == -1) ||
+                    ((((int)current_frame - pipe->split_sc_frame) & 0x7f) <
+                     0x40)) &&
+                   (!usb->active_split || (usb->active_split == t))) {
+                       prefetch(t);
+                       return pipe;
+               }
+       }
+       return NULL;
+}
+
+static struct cvmx_usb_pipe *cvmx_usb_next_pipe(struct octeon_hcd *usb,
+                                               int is_sof)
+{
+       struct cvmx_usb_pipe *pipe;
+
+       /* Find a pipe needing service. */
+       if (is_sof) {
+               /*
+                * Only process periodic pipes on SOF interrupts. This way we
+                * are sure that the periodic data is sent in the beginning of
+                * the frame.
+                */
+               pipe = cvmx_usb_find_ready_pipe(usb,
+                                               CVMX_USB_TRANSFER_ISOCHRONOUS);
+               if (pipe)
+                       return pipe;
+               pipe = cvmx_usb_find_ready_pipe(usb,
+                                               CVMX_USB_TRANSFER_INTERRUPT);
+               if (pipe)
+                       return pipe;
+       }
+       pipe = cvmx_usb_find_ready_pipe(usb, CVMX_USB_TRANSFER_CONTROL);
+       if (pipe)
+               return pipe;
+       return cvmx_usb_find_ready_pipe(usb, CVMX_USB_TRANSFER_BULK);
+}
+
+/**
+ * Called whenever a pipe might need to be scheduled to the
+ * hardware.
+ *
+ * @usb:        USB device state populated by cvmx_usb_initialize().
+ * @is_sof:     True if this schedule was called on a SOF interrupt.
+ */
+static void cvmx_usb_schedule(struct octeon_hcd *usb, int is_sof)
+{
+       int channel;
+       struct cvmx_usb_pipe *pipe;
+       int need_sof;
+       enum cvmx_usb_transfer ttype;
+
+       if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+               /*
+                * Without DMA we need to be careful to not schedule something
+                * at the end of a frame and cause an overrun.
+                */
+               union cvmx_usbcx_hfnum hfnum = {
+                       .u32 = cvmx_usb_read_csr32(usb,
+                                               CVMX_USBCX_HFNUM(usb->index))
+               };
+
+               union cvmx_usbcx_hfir hfir = {
+                       .u32 = cvmx_usb_read_csr32(usb,
+                                               CVMX_USBCX_HFIR(usb->index))
+               };
+
+               if (hfnum.s.frrem < hfir.s.frint / 4)
+                       goto done;
+       }
+
+       while (usb->idle_hardware_channels) {
+               /* Find an idle channel */
+               channel = __fls(usb->idle_hardware_channels);
+               if (unlikely(channel > 7))
+                       break;
+
+               pipe = cvmx_usb_next_pipe(usb, is_sof);
+               if (!pipe)
+                       break;
+
+               cvmx_usb_start_channel(usb, channel, pipe);
+       }
+
+done:
+       /*
+        * Only enable SOF interrupts when we have transactions pending in the
+        * future that might need to be scheduled
+        */
+       need_sof = 0;
+       for (ttype = CVMX_USB_TRANSFER_CONTROL;
+            ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
+               list_for_each_entry(pipe, &usb->active_pipes[ttype], node) {
+                       if (pipe->next_tx_frame > usb->frame_number) {
+                               need_sof = 1;
+                               break;
+                       }
+               }
+       }
+       USB_SET_FIELD32(CVMX_USBCX_GINTMSK(usb->index),
+                       cvmx_usbcx_gintmsk, sofmsk, need_sof);
+}
+
+static void octeon_usb_urb_complete_callback(struct octeon_hcd *usb,
+                                            enum cvmx_usb_status status,
+                                            struct cvmx_usb_pipe *pipe,
+                                            struct cvmx_usb_transaction
+                                               *transaction,
+                                            int bytes_transferred,
+                                            struct urb *urb)
+{
+       struct usb_hcd *hcd = octeon_to_hcd(usb);
+       struct device *dev = hcd->self.controller;
+
+       if (likely(status == CVMX_USB_STATUS_OK))
+               urb->actual_length = bytes_transferred;
+       else
+               urb->actual_length = 0;
+
+       urb->hcpriv = NULL;
+
+       /* For Isochronous transactions we need to update the URB packet status
+        * list from data in our private copy
+        */
+       if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+               int i;
+               /*
+                * The pointer to the private list is stored in the setup_packet
+                * field.
+                */
+               struct cvmx_usb_iso_packet *iso_packet =
+                       (struct cvmx_usb_iso_packet *)urb->setup_packet;
+               /* Recalculate the transfer size by adding up each packet */
+               urb->actual_length = 0;
+               for (i = 0; i < urb->number_of_packets; i++) {
+                       if (iso_packet[i].status == CVMX_USB_STATUS_OK) {
+                               urb->iso_frame_desc[i].status = 0;
+                               urb->iso_frame_desc[i].actual_length =
+                                       iso_packet[i].length;
+                               urb->actual_length +=
+                                       urb->iso_frame_desc[i].actual_length;
+                       } else {
+                               dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%p transaction=%p size=%d\n",
+                                       i, urb->number_of_packets,
+                                       iso_packet[i].status, pipe,
+                                       transaction, iso_packet[i].length);
+                               urb->iso_frame_desc[i].status = -EREMOTEIO;
+                       }
+               }
+               /* Free the private list now that we don't need it anymore */
+               kfree(iso_packet);
+               urb->setup_packet = NULL;
+       }
+
+       switch (status) {
+       case CVMX_USB_STATUS_OK:
+               urb->status = 0;
+               break;
+       case CVMX_USB_STATUS_CANCEL:
+               if (urb->status == 0)
+                       urb->status = -ENOENT;
+               break;
+       case CVMX_USB_STATUS_STALL:
+               dev_dbg(dev, "status=stall pipe=%p transaction=%p size=%d\n",
+                       pipe, transaction, bytes_transferred);
+               urb->status = -EPIPE;
+               break;
+       case CVMX_USB_STATUS_BABBLEERR:
+               dev_dbg(dev, "status=babble pipe=%p transaction=%p size=%d\n",
+                       pipe, transaction, bytes_transferred);
+               urb->status = -EPIPE;
+               break;
+       case CVMX_USB_STATUS_SHORT:
+               dev_dbg(dev, "status=short pipe=%p transaction=%p size=%d\n",
+                       pipe, transaction, bytes_transferred);
+               urb->status = -EREMOTEIO;
+               break;
+       case CVMX_USB_STATUS_ERROR:
+       case CVMX_USB_STATUS_XACTERR:
+       case CVMX_USB_STATUS_DATATGLERR:
+       case CVMX_USB_STATUS_FRAMEERR:
+               dev_dbg(dev, "status=%d pipe=%p transaction=%p size=%d\n",
+                       status, pipe, transaction, bytes_transferred);
+               urb->status = -EPROTO;
+               break;
+       }
+       usb_hcd_unlink_urb_from_ep(octeon_to_hcd(usb), urb);
+       spin_unlock(&usb->lock);
+       usb_hcd_giveback_urb(octeon_to_hcd(usb), urb, urb->status);
+       spin_lock(&usb->lock);
+}
+
+/**
+ * Signal the completion of a transaction and free it. The
+ * transaction will be removed from the pipe transaction list.
+ *
+ * @usb:        USB device state populated by cvmx_usb_initialize().
+ * @pipe:       Pipe the transaction is on
+ * @transaction:
+ *              Transaction that completed
+ * @complete_code:
+ *              Completion code
+ */
+static void cvmx_usb_complete(struct octeon_hcd *usb,
+                             struct cvmx_usb_pipe *pipe,
+                             struct cvmx_usb_transaction *transaction,
+                             enum cvmx_usb_status complete_code)
+{
+       /* If this was a split then clear our split in progress marker */
+       if (usb->active_split == transaction)
+               usb->active_split = NULL;
+
+       /*
+        * Isochronous transactions need extra processing as they might not be
+        * done after a single data transfer
+        */
+       if (unlikely(transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)) {
+               /* Update the number of bytes transferred in this ISO packet */
+               transaction->iso_packets[0].length = transaction->actual_bytes;
+               transaction->iso_packets[0].status = complete_code;
+
+               /*
+                * If there are more ISOs pending and we succeeded, schedule the
+                * next one
+                */
+               if ((transaction->iso_number_packets > 1) &&
+                   (complete_code == CVMX_USB_STATUS_OK)) {
+                       /* No bytes transferred for this packet as of yet */
+                       transaction->actual_bytes = 0;
+                       /* One less ISO waiting to transfer */
+                       transaction->iso_number_packets--;
+                       /* Increment to the next location in our packet array */
+                       transaction->iso_packets++;
+                       transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+                       return;
+               }
+       }
+
+       /* Remove the transaction from the pipe list */
+       list_del(&transaction->node);
+       if (list_empty(&pipe->transactions))
+               list_move_tail(&pipe->node, &usb->idle_pipes);
+       octeon_usb_urb_complete_callback(usb, complete_code, pipe,
+                                        transaction,
+                                        transaction->actual_bytes,
+                                        transaction->urb);
+       kfree(transaction);
+}
+
+/**
+ * Submit a usb transaction to a pipe. Called for all types
+ * of transactions.
+ *
+ * @usb:
+ * @pipe:          Which pipe to submit to.
+ * @type:          Transaction type
+ * @buffer:        User buffer for the transaction
+ * @buffer_length:
+ *                 User buffer's length in bytes
+ * @control_header:
+ *                 For control transactions, the 8 byte standard header
+ * @iso_start_frame:
+ *                 For ISO transactions, the start frame
+ * @iso_number_packets:
+ *                 For ISO, the number of packet in the transaction.
+ * @iso_packets:
+ *                 A description of each ISO packet
+ * @urb:           URB for the callback
+ *
+ * Returns: Transaction or NULL on failure.
+ */
+static struct cvmx_usb_transaction *cvmx_usb_submit_transaction(
+                               struct octeon_hcd *usb,
+                               struct cvmx_usb_pipe *pipe,
+                               enum cvmx_usb_transfer type,
+                               u64 buffer,
+                               int buffer_length,
+                               u64 control_header,
+                               int iso_start_frame,
+                               int iso_number_packets,
+                               struct cvmx_usb_iso_packet *iso_packets,
+                               struct urb *urb)
+{
+       struct cvmx_usb_transaction *transaction;
+
+       if (unlikely(pipe->transfer_type != type))
+               return NULL;
+
+       transaction = kzalloc(sizeof(*transaction), GFP_ATOMIC);
+       if (unlikely(!transaction))
+               return NULL;
+
+       transaction->type = type;
+       transaction->buffer = buffer;
+       transaction->buffer_length = buffer_length;
+       transaction->control_header = control_header;
+       /* FIXME: This is not used, implement it. */
+       transaction->iso_start_frame = iso_start_frame;
+       transaction->iso_number_packets = iso_number_packets;
+       transaction->iso_packets = iso_packets;
+       transaction->urb = urb;
+       if (transaction->type == CVMX_USB_TRANSFER_CONTROL)
+               transaction->stage = CVMX_USB_STAGE_SETUP;
+       else
+               transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+
+       if (!list_empty(&pipe->transactions)) {
+               list_add_tail(&transaction->node, &pipe->transactions);
+       } else {
+               list_add_tail(&transaction->node, &pipe->transactions);
+               list_move_tail(&pipe->node,
+                              &usb->active_pipes[pipe->transfer_type]);
+
+               /*
+                * We may need to schedule the pipe if this was the head of the
+                * pipe.
+                */
+               cvmx_usb_schedule(usb, 0);
+       }
+
+       return transaction;
+}
+
+/**
+ * Call to submit a USB Bulk transfer to a pipe.
+ *
+ * @usb:           USB device state populated by cvmx_usb_initialize().
+ * @pipe:          Handle to the pipe for the transfer.
+ * @urb:           URB.
+ *
+ * Returns: A submitted transaction or NULL on failure.
+ */
+static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(
+                                               struct octeon_hcd *usb,
+                                               struct cvmx_usb_pipe *pipe,
+                                               struct urb *urb)
+{
+       return cvmx_usb_submit_transaction(usb, pipe, CVMX_USB_TRANSFER_BULK,
+                                          urb->transfer_dma,
+                                          urb->transfer_buffer_length,
+                                          0, /* control_header */
+                                          0, /* iso_start_frame */
+                                          0, /* iso_number_packets */
+                                          NULL, /* iso_packets */
+                                          urb);
+}
+
+/**
+ * Call to submit a USB Interrupt transfer to a pipe.
+ *
+ * @usb:           USB device state populated by cvmx_usb_initialize().
+ * @pipe:          Handle to the pipe for the transfer.
+ * @urb:           URB returned when the callback is called.
+ *
+ * Returns: A submitted transaction or NULL on failure.
+ */
+static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(
+                                               struct octeon_hcd *usb,
+                                               struct cvmx_usb_pipe *pipe,
+                                               struct urb *urb)
+{
+       return cvmx_usb_submit_transaction(usb, pipe,
+                                          CVMX_USB_TRANSFER_INTERRUPT,
+                                          urb->transfer_dma,
+                                          urb->transfer_buffer_length,
+                                          0, /* control_header */
+                                          0, /* iso_start_frame */
+                                          0, /* iso_number_packets */
+                                          NULL, /* iso_packets */
+                                          urb);
+}
+
+/**
+ * Call to submit a USB Control transfer to a pipe.
+ *
+ * @usb:           USB device state populated by cvmx_usb_initialize().
+ * @pipe:          Handle to the pipe for the transfer.
+ * @urb:           URB.
+ *
+ * Returns: A submitted transaction or NULL on failure.
+ */
+static struct cvmx_usb_transaction *cvmx_usb_submit_control(
+                                               struct octeon_hcd *usb,
+                                               struct cvmx_usb_pipe *pipe,
+                                               struct urb *urb)
+{
+       int buffer_length = urb->transfer_buffer_length;
+       u64 control_header = urb->setup_dma;
+       struct usb_ctrlrequest *header = cvmx_phys_to_ptr(control_header);
+
+       if ((header->bRequestType & USB_DIR_IN) == 0)
+               buffer_length = le16_to_cpu(header->wLength);
+
+       return cvmx_usb_submit_transaction(usb, pipe,
+                                          CVMX_USB_TRANSFER_CONTROL,
+                                          urb->transfer_dma, buffer_length,
+                                          control_header,
+                                          0, /* iso_start_frame */
+                                          0, /* iso_number_packets */
+                                          NULL, /* iso_packets */
+                                          urb);
+}
+
+/**
+ * Call to submit a USB Isochronous transfer to a pipe.
+ *
+ * @usb:           USB device state populated by cvmx_usb_initialize().
+ * @pipe:          Handle to the pipe for the transfer.
+ * @urb:           URB returned when the callback is called.
+ *
+ * Returns: A submitted transaction or NULL on failure.
+ */
+static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(
+                                               struct octeon_hcd *usb,
+                                               struct cvmx_usb_pipe *pipe,
+                                               struct urb *urb)
+{
+       struct cvmx_usb_iso_packet *packets;
+
+       packets = (struct cvmx_usb_iso_packet *)urb->setup_packet;
+       return cvmx_usb_submit_transaction(usb, pipe,
+                                          CVMX_USB_TRANSFER_ISOCHRONOUS,
+                                          urb->transfer_dma,
+                                          urb->transfer_buffer_length,
+                                          0, /* control_header */
+                                          urb->start_frame,
+                                          urb->number_of_packets,
+                                          packets, urb);
+}
+
+/**
+ * Cancel one outstanding request in a pipe. Canceling a request
+ * can fail if the transaction has already completed before cancel
+ * is called. Even after a successful cancel call, it may take
+ * a frame or two for the cvmx_usb_poll() function to call the
+ * associated callback.
+ *
+ * @usb:        USB device state populated by cvmx_usb_initialize().
+ * @pipe:       Pipe to cancel requests in.
+ * @transaction: Transaction to cancel, returned by the submit function.
+ *
+ * Returns: 0 or a negative error code.
+ */
+static int cvmx_usb_cancel(struct octeon_hcd *usb,
+                          struct cvmx_usb_pipe *pipe,
+                          struct cvmx_usb_transaction *transaction)
+{
+       /*
+        * If the transaction is the HEAD of the queue and scheduled. We need to
+        * treat it special
+        */
+       if (list_first_entry(&pipe->transactions, typeof(*transaction), node) ==
+           transaction && (pipe->flags & CVMX_USB_PIPE_FLAGS_SCHEDULED)) {
+               union cvmx_usbcx_hccharx usbc_hcchar;
+
+               usb->pipe_for_channel[pipe->channel] = NULL;
+               pipe->flags &= ~CVMX_USB_PIPE_FLAGS_SCHEDULED;
+
+               CVMX_SYNCW;
+
+               usbc_hcchar.u32 = cvmx_usb_read_csr32(usb,
+                               CVMX_USBCX_HCCHARX(pipe->channel, usb->index));
+               /*
+                * If the channel isn't enabled then the transaction already
+                * completed.
+                */
+               if (usbc_hcchar.s.chena) {
+                       usbc_hcchar.s.chdis = 1;
+                       cvmx_usb_write_csr32(usb,
+                                            CVMX_USBCX_HCCHARX(pipe->channel,
+                                                               usb->index),
+                                            usbc_hcchar.u32);
+               }
+       }
+       cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_CANCEL);
+       return 0;
+}
+
+/**
+ * Cancel all outstanding requests in a pipe. Logically all this
+ * does is call cvmx_usb_cancel() in a loop.
+ *
+ * @usb:        USB device state populated by cvmx_usb_initialize().
+ * @pipe:       Pipe to cancel requests in.
+ *
+ * Returns: 0 or a negative error code.
+ */
+static int cvmx_usb_cancel_all(struct octeon_hcd *usb,
+                              struct cvmx_usb_pipe *pipe)
+{
+       struct cvmx_usb_transaction *transaction, *next;
+
+       /* Simply loop through and attempt to cancel each transaction */
+       list_for_each_entry_safe(transaction, next, &pipe->transactions, node) {
+               int result = cvmx_usb_cancel(usb, pipe, transaction);
+
+               if (unlikely(result != 0))
+                       return result;
+       }
+       return 0;
+}
+
+/**
+ * Close a pipe created with cvmx_usb_open_pipe().
+ *
+ * @usb:        USB device state populated by cvmx_usb_initialize().
+ * @pipe:       Pipe to close.
+ *
+ * Returns: 0 or a negative error code. EBUSY is returned if the pipe has
+ *         outstanding transfers.
+ */
+static int cvmx_usb_close_pipe(struct octeon_hcd *usb,
+                              struct cvmx_usb_pipe *pipe)
+{
+       /* Fail if the pipe has pending transactions */
+       if (!list_empty(&pipe->transactions))
+               return -EBUSY;
+
+       list_del(&pipe->node);
+       kfree(pipe);
+
+       return 0;
+}
+
+/**
+ * Get the current USB protocol level frame number. The frame
+ * number is always in the range of 0-0x7ff.
+ *
+ * @usb: USB device state populated by cvmx_usb_initialize().
+ *
+ * Returns: USB frame number
+ */
+static int cvmx_usb_get_frame_number(struct octeon_hcd *usb)
+{
+       union cvmx_usbcx_hfnum usbc_hfnum;
+
+       usbc_hfnum.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
+
+       return usbc_hfnum.s.frnum;
+}
+
+static void cvmx_usb_transfer_control(struct octeon_hcd *usb,
+                                     struct cvmx_usb_pipe *pipe,
+                                     struct cvmx_usb_transaction *transaction,
+                                     union cvmx_usbcx_hccharx usbc_hcchar,
+                                     int buffer_space_left,
+                                     int bytes_in_last_packet)
+{
+       switch (transaction->stage) {
+       case CVMX_USB_STAGE_NON_CONTROL:
+       case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
+               /* This should be impossible */
+               cvmx_usb_complete(usb, pipe, transaction,
+                                 CVMX_USB_STATUS_ERROR);
+               break;
+       case CVMX_USB_STAGE_SETUP:
+               pipe->pid_toggle = 1;
+               if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+                       transaction->stage =
+                               CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
+               } else {
+                       struct usb_ctrlrequest *header =
+                               cvmx_phys_to_ptr(transaction->control_header);
+                       if (header->wLength)
+                               transaction->stage = CVMX_USB_STAGE_DATA;
+                       else
+                               transaction->stage = CVMX_USB_STAGE_STATUS;
+               }
+               break;
+       case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
+               {
+                       struct usb_ctrlrequest *header =
+                               cvmx_phys_to_ptr(transaction->control_header);
+                       if (header->wLength)
+                               transaction->stage = CVMX_USB_STAGE_DATA;
+                       else
+                               transaction->stage = CVMX_USB_STAGE_STATUS;
+               }
+               break;
+       case CVMX_USB_STAGE_DATA:
+               if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+                       transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
+                       /*
+                        * For setup OUT data that are splits,
+                        * the hardware doesn't appear to count
+                        * transferred data. Here we manually
+                        * update the data transferred
+                        */
+                       if (!usbc_hcchar.s.epdir) {
+                               if (buffer_space_left < pipe->max_packet)
+                                       transaction->actual_bytes +=
+                                               buffer_space_left;
+                               else
+                                       transaction->actual_bytes +=
+                                               pipe->max_packet;
+                       }
+               } else if ((buffer_space_left == 0) ||
+                          (bytes_in_last_packet < pipe->max_packet)) {
+                       pipe->pid_toggle = 1;
+                       transaction->stage = CVMX_USB_STAGE_STATUS;
+               }
+               break;
+       case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
+               if ((buffer_space_left == 0) ||
+                   (bytes_in_last_packet < pipe->max_packet)) {
+                       pipe->pid_toggle = 1;
+                       transaction->stage = CVMX_USB_STAGE_STATUS;
+               } else {
+                       transaction->stage = CVMX_USB_STAGE_DATA;
+               }
+               break;
+       case CVMX_USB_STAGE_STATUS:
+               if (cvmx_usb_pipe_needs_split(usb, pipe))
+                       transaction->stage =
+                               CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
+               else
+                       cvmx_usb_complete(usb, pipe, transaction,
+                                         CVMX_USB_STATUS_OK);
+               break;
+       case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
+               cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
+               break;
+       }
+}
+
+static void cvmx_usb_transfer_bulk(struct octeon_hcd *usb,
+                                  struct cvmx_usb_pipe *pipe,
+                                  struct cvmx_usb_transaction *transaction,
+                                  union cvmx_usbcx_hcintx usbc_hcint,
+                                  int buffer_space_left,
+                                  int bytes_in_last_packet)
+{
+       /*
+        * The only time a bulk transfer isn't complete when it finishes with
+        * an ACK is during a split transaction. For splits we need to continue
+        * the transfer if more data is needed.
+        */
+       if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+               if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
+                       transaction->stage =
+                               CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+               else if (buffer_space_left &&
+                        (bytes_in_last_packet == pipe->max_packet))
+                       transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+               else
+                       cvmx_usb_complete(usb, pipe, transaction,
+                                         CVMX_USB_STATUS_OK);
+       } else {
+               if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
+                   (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+                   (usbc_hcint.s.nak))
+                       pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
+               if (!buffer_space_left ||
+                   (bytes_in_last_packet < pipe->max_packet))
+                       cvmx_usb_complete(usb, pipe, transaction,
+                                         CVMX_USB_STATUS_OK);
+       }
+}
+
+static void cvmx_usb_transfer_intr(struct octeon_hcd *usb,
+                                  struct cvmx_usb_pipe *pipe,
+                                  struct cvmx_usb_transaction *transaction,
+                                  int buffer_space_left,
+                                  int bytes_in_last_packet)
+{
+       if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+               if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL) {
+                       transaction->stage =
+                               CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+               } else if (buffer_space_left &&
+                          (bytes_in_last_packet == pipe->max_packet)) {
+                       transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+               } else {
+                       pipe->next_tx_frame += pipe->interval;
+                       cvmx_usb_complete(usb, pipe, transaction,
+                                         CVMX_USB_STATUS_OK);
+               }
+       } else if (!buffer_space_left ||
+                  (bytes_in_last_packet < pipe->max_packet)) {
+               pipe->next_tx_frame += pipe->interval;
+               cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
+       }
+}
+
+static void cvmx_usb_transfer_isoc(struct octeon_hcd *usb,
+                                  struct cvmx_usb_pipe *pipe,
+                                  struct cvmx_usb_transaction *transaction,
+                                  int buffer_space_left,
+                                  int bytes_in_last_packet,
+                                  int bytes_this_transfer)
+{
+       if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+               /*
+                * ISOCHRONOUS OUT splits don't require a complete split stage.
+                * Instead they use a sequence of begin OUT splits to transfer
+                * the data 188 bytes at a time. Once the transfer is complete,
+                * the pipe sleeps until the next schedule interval.
+                */
+               if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
+                       /*
+                        * If no space left or this wasn't a max size packet
+                        * then this transfer is complete. Otherwise start it
+                        * again to send the next 188 bytes
+                        */
+                       if (!buffer_space_left || (bytes_this_transfer < 188)) {
+                               pipe->next_tx_frame += pipe->interval;
+                               cvmx_usb_complete(usb, pipe, transaction,
+                                                 CVMX_USB_STATUS_OK);
+                       }
+                       return;
+               }
+               if (transaction->stage ==
+                   CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
+                       /*
+                        * We are in the incoming data phase. Keep getting data
+                        * until we run out of space or get a small packet
+                        */
+                       if ((buffer_space_left == 0) ||
+                           (bytes_in_last_packet < pipe->max_packet)) {
+                               pipe->next_tx_frame += pipe->interval;
+                               cvmx_usb_complete(usb, pipe, transaction,
+                                                 CVMX_USB_STATUS_OK);
+                       }
+               } else {
+                       transaction->stage =
+                               CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+               }
+       } else {
+               pipe->next_tx_frame += pipe->interval;
+               cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
+       }
+}
+
+/**
+ * Poll a channel for status
+ *
+ * @usb:     USB device
+ * @channel: Channel to poll
+ *
+ * Returns: Zero on success
+ */
+static int cvmx_usb_poll_channel(struct octeon_hcd *usb, int channel)
+{
+       struct usb_hcd *hcd = octeon_to_hcd(usb);
+       struct device *dev = hcd->self.controller;
+       union cvmx_usbcx_hcintx usbc_hcint;
+       union cvmx_usbcx_hctsizx usbc_hctsiz;
+       union cvmx_usbcx_hccharx usbc_hcchar;
+       struct cvmx_usb_pipe *pipe;
+       struct cvmx_usb_transaction *transaction;
+       int bytes_this_transfer;
+       int bytes_in_last_packet;
+       int packets_processed;
+       int buffer_space_left;
+
+       /* Read the interrupt status bits for the channel */
+       usbc_hcint.u32 = cvmx_usb_read_csr32(usb,
+                               CVMX_USBCX_HCINTX(channel, usb->index));
+
+       if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA) {
+               usbc_hcchar.u32 = cvmx_usb_read_csr32(usb,
+                               CVMX_USBCX_HCCHARX(channel, usb->index));
+
+               if (usbc_hcchar.s.chena && usbc_hcchar.s.chdis) {
+                       /*
+                        * There seems to be a bug in CN31XX which can cause
+                        * interrupt IN transfers to get stuck until we do a
+                        * write of HCCHARX without changing things
+                        */
+                       cvmx_usb_write_csr32(usb,
+                                            CVMX_USBCX_HCCHARX(channel,
+                                                               usb->index),
+                                            usbc_hcchar.u32);
+                       return 0;
+               }
+
+               /*
+                * In non DMA mode the channels don't halt themselves. We need
+                * to manually disable channels that are left running
+                */
+               if (!usbc_hcint.s.chhltd) {
+                       if (usbc_hcchar.s.chena) {
+                               union cvmx_usbcx_hcintmskx hcintmsk;
+                               /* Disable all interrupts except CHHLTD */
+                               hcintmsk.u32 = 0;
+                               hcintmsk.s.chhltdmsk = 1;
+                               cvmx_usb_write_csr32(usb,
+                                                    CVMX_USBCX_HCINTMSKX(channel, usb->index),
+                                                    hcintmsk.u32);
+                               usbc_hcchar.s.chdis = 1;
+                               cvmx_usb_write_csr32(usb,
+                                                    CVMX_USBCX_HCCHARX(channel, usb->index),
+                                                    usbc_hcchar.u32);
+                               return 0;
+                       } else if (usbc_hcint.s.xfercompl) {
+                               /*
+                                * Successful IN/OUT with transfer complete.
+                                * Channel halt isn't needed.
+                                */
+                       } else {
+                               dev_err(dev, "USB%d: Channel %d interrupt without halt\n",
+                                       usb->index, channel);
+                               return 0;
+                       }
+               }
+       } else {
+               /*
+                * There is are no interrupts that we need to process when the
+                * channel is still running
+                */
+               if (!usbc_hcint.s.chhltd)
+                       return 0;
+       }
+
+       /* Disable the channel interrupts now that it is done */
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
+       usb->idle_hardware_channels |= (1 << channel);
+
+       /* Make sure this channel is tied to a valid pipe */
+       pipe = usb->pipe_for_channel[channel];
+       prefetch(pipe);
+       if (!pipe)
+               return 0;
+       transaction = list_first_entry(&pipe->transactions,
+                                      typeof(*transaction),
+                                      node);
+       prefetch(transaction);
+
+       /*
+        * Disconnect this pipe from the HW channel. Later the schedule
+        * function will figure out which pipe needs to go
+        */
+       usb->pipe_for_channel[channel] = NULL;
+       pipe->flags &= ~CVMX_USB_PIPE_FLAGS_SCHEDULED;
+
+       /*
+        * Read the channel config info so we can figure out how much data
+        * transferred
+        */
+       usbc_hcchar.u32 = cvmx_usb_read_csr32(usb,
+                       CVMX_USBCX_HCCHARX(channel, usb->index));
+       usbc_hctsiz.u32 = cvmx_usb_read_csr32(usb,
+                       CVMX_USBCX_HCTSIZX(channel, usb->index));
+
+       /*
+        * Calculating the number of bytes successfully transferred is dependent
+        * on the transfer direction
+        */
+       packets_processed = transaction->pktcnt - usbc_hctsiz.s.pktcnt;
+       if (usbc_hcchar.s.epdir) {
+               /*
+                * IN transactions are easy. For every byte received the
+                * hardware decrements xfersize. All we need to do is subtract
+                * the current value of xfersize from its starting value and we
+                * know how many bytes were written to the buffer
+                */
+               bytes_this_transfer = transaction->xfersize -
+                       usbc_hctsiz.s.xfersize;
+       } else {
+               /*
+                * OUT transaction don't decrement xfersize. Instead pktcnt is
+                * decremented on every successful packet send. The hardware
+                * does this when it receives an ACK, or NYET. If it doesn't
+                * receive one of these responses pktcnt doesn't change
+                */
+               bytes_this_transfer = packets_processed * usbc_hcchar.s.mps;
+               /*
+                * The last packet may not be a full transfer if we didn't have
+                * enough data
+                */
+               if (bytes_this_transfer > transaction->xfersize)
+                       bytes_this_transfer = transaction->xfersize;
+       }
+       /* Figure out how many bytes were in the last packet of the transfer */
+       if (packets_processed)
+               bytes_in_last_packet = bytes_this_transfer -
+                       (packets_processed - 1) * usbc_hcchar.s.mps;
+       else
+               bytes_in_last_packet = bytes_this_transfer;
+
+       /*
+        * As a special case, setup transactions output the setup header, not
+        * the user's data. For this reason we don't count setup data as bytes
+        * transferred
+        */
+       if ((transaction->stage == CVMX_USB_STAGE_SETUP) ||
+           (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
+               bytes_this_transfer = 0;
+
+       /*
+        * Add the bytes transferred to the running total. It is important that
+        * bytes_this_transfer doesn't count any data that needs to be
+        * retransmitted
+        */
+       transaction->actual_bytes += bytes_this_transfer;
+       if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
+               buffer_space_left = transaction->iso_packets[0].length -
+                       transaction->actual_bytes;
+       else
+               buffer_space_left = transaction->buffer_length -
+                       transaction->actual_bytes;
+
+       /*
+        * We need to remember the PID toggle state for the next transaction.
+        * The hardware already updated it for the next transaction
+        */
+       pipe->pid_toggle = !(usbc_hctsiz.s.pid == 0);
+
+       /*
+        * For high speed bulk out, assume the next transaction will need to do
+        * a ping before proceeding. If this isn't true the ACK processing below
+        * will clear this flag
+        */
+       if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
+           (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
+           (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
+               pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
+
+       if (WARN_ON_ONCE(bytes_this_transfer < 0)) {
+               /*
+                * In some rare cases the DMA engine seems to get stuck and
+                * keeps substracting same byte count over and over again. In
+                * such case we just need to fail every transaction.
+                */
+               cvmx_usb_complete(usb, pipe, transaction,
+                                 CVMX_USB_STATUS_ERROR);
+               return 0;
+       }
+
+       if (usbc_hcint.s.stall) {
+               /*
+                * STALL as a response means this transaction cannot be
+                * completed because the device can't process transactions. Tell
+                * the user. Any data that was transferred will be counted on
+                * the actual bytes transferred
+                */
+               pipe->pid_toggle = 0;
+               cvmx_usb_complete(usb, pipe, transaction,
+                                 CVMX_USB_STATUS_STALL);
+       } else if (usbc_hcint.s.xacterr) {
+               /*
+                * XactErr as a response means the device signaled
+                * something wrong with the transfer. For example, PID
+                * toggle errors cause these.
+                */
+               cvmx_usb_complete(usb, pipe, transaction,
+                                 CVMX_USB_STATUS_XACTERR);
+       } else if (usbc_hcint.s.bblerr) {
+               /* Babble Error (BblErr) */
+               cvmx_usb_complete(usb, pipe, transaction,
+                                 CVMX_USB_STATUS_BABBLEERR);
+       } else if (usbc_hcint.s.datatglerr) {
+               /* Data toggle error */
+               cvmx_usb_complete(usb, pipe, transaction,
+                                 CVMX_USB_STATUS_DATATGLERR);
+       } else if (usbc_hcint.s.nyet) {
+               /*
+                * NYET as a response is only allowed in three cases: as a
+                * response to a ping, as a response to a split transaction, and
+                * as a response to a bulk out. The ping case is handled by
+                * hardware, so we only have splits and bulk out
+                */
+               if (!cvmx_usb_pipe_needs_split(usb, pipe)) {
+                       transaction->retries = 0;
+                       /*
+                        * If there is more data to go then we need to try
+                        * again. Otherwise this transaction is complete
+                        */
+                       if ((buffer_space_left == 0) ||
+                           (bytes_in_last_packet < pipe->max_packet))
+                               cvmx_usb_complete(usb, pipe,
+                                                 transaction,
+                                                 CVMX_USB_STATUS_OK);
+               } else {
+                       /*
+                        * Split transactions retry the split complete 4 times
+                        * then rewind to the start split and do the entire
+                        * transactions again
+                        */
+                       transaction->retries++;
+                       if ((transaction->retries & 0x3) == 0) {
+                               /*
+                                * Rewind to the beginning of the transaction by
+                                * anding off the split complete bit
+                                */
+                               transaction->stage &= ~1;
+                               pipe->split_sc_frame = -1;
+                       }
+               }
+       } else if (usbc_hcint.s.ack) {
+               transaction->retries = 0;
+               /*
+                * The ACK bit can only be checked after the other error bits.
+                * This is because a multi packet transfer may succeed in a
+                * number of packets and then get a different response on the
+                * last packet. In this case both ACK and the last response bit
+                * will be set. If none of the other response bits is set, then
+                * the last packet must have been an ACK
+                *
+                * Since we got an ACK, we know we don't need to do a ping on
+                * this pipe
+                */
+               pipe->flags &= ~CVMX_USB_PIPE_FLAGS_NEED_PING;
+
+               switch (transaction->type) {
+               case CVMX_USB_TRANSFER_CONTROL:
+                       cvmx_usb_transfer_control(usb, pipe, transaction,
+                                                 usbc_hcchar,
+                                                 buffer_space_left,
+                                                 bytes_in_last_packet);
+                       break;
+               case CVMX_USB_TRANSFER_BULK:
+                       cvmx_usb_transfer_bulk(usb, pipe, transaction,
+                                              usbc_hcint, buffer_space_left,
+                                              bytes_in_last_packet);
+                       break;
+               case CVMX_USB_TRANSFER_INTERRUPT:
+                       cvmx_usb_transfer_intr(usb, pipe, transaction,
+                                              buffer_space_left,
+                                              bytes_in_last_packet);
+                       break;
+               case CVMX_USB_TRANSFER_ISOCHRONOUS:
+                       cvmx_usb_transfer_isoc(usb, pipe, transaction,
+                                              buffer_space_left,
+                                              bytes_in_last_packet,
+                                              bytes_this_transfer);
+                       break;
+               }
+       } else if (usbc_hcint.s.nak) {
+               /*
+                * If this was a split then clear our split in progress marker.
+                */
+               if (usb->active_split == transaction)
+                       usb->active_split = NULL;
+               /*
+                * NAK as a response means the device couldn't accept the
+                * transaction, but it should be retried in the future. Rewind
+                * to the beginning of the transaction by anding off the split
+                * complete bit. Retry in the next interval
+                */
+               transaction->retries = 0;
+               transaction->stage &= ~1;
+               pipe->next_tx_frame += pipe->interval;
+               if (pipe->next_tx_frame < usb->frame_number)
+                       pipe->next_tx_frame = usb->frame_number +
+                               pipe->interval -
+                               (usb->frame_number - pipe->next_tx_frame) %
+                               pipe->interval;
+       } else {
+               struct cvmx_usb_port_status port;
+
+               port = cvmx_usb_get_status(usb);
+               if (port.port_enabled) {
+                       /* We'll retry the exact same transaction again */
+                       transaction->retries++;
+               } else {
+                       /*
+                        * We get channel halted interrupts with no result bits
+                        * sets when the cable is unplugged
+                        */
+                       cvmx_usb_complete(usb, pipe, transaction,
+                                         CVMX_USB_STATUS_ERROR);
+               }
+       }
+       return 0;
+}
+
+static void octeon_usb_port_callback(struct octeon_hcd *usb)
+{
+       spin_unlock(&usb->lock);
+       usb_hcd_poll_rh_status(octeon_to_hcd(usb));
+       spin_lock(&usb->lock);
+}
+
+/**
+ * Poll the USB block for status and call all needed callback
+ * handlers. This function is meant to be called in the interrupt
+ * handler for the USB controller. It can also be called
+ * periodically in a loop for non-interrupt based operation.
+ *
+ * @usb: USB device state populated by cvmx_usb_initialize().
+ *
+ * Returns: 0 or a negative error code.
+ */
+static int cvmx_usb_poll(struct octeon_hcd *usb)
+{
+       union cvmx_usbcx_hfnum usbc_hfnum;
+       union cvmx_usbcx_gintsts usbc_gintsts;
+
+       prefetch_range(usb, sizeof(*usb));
+
+       /* Update the frame counter */
+       usbc_hfnum.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
+       if ((usb->frame_number & 0x3fff) > usbc_hfnum.s.frnum)
+               usb->frame_number += 0x4000;
+       usb->frame_number &= ~0x3fffull;
+       usb->frame_number |= usbc_hfnum.s.frnum;
+
+       /* Read the pending interrupts */
+       usbc_gintsts.u32 = cvmx_usb_read_csr32(usb,
+                                              CVMX_USBCX_GINTSTS(usb->index));
+
+       /* Clear the interrupts now that we know about them */
+       cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index),
+                            usbc_gintsts.u32);
+
+       if (usbc_gintsts.s.rxflvl) {
+               /*
+                * RxFIFO Non-Empty (RxFLvl)
+                * Indicates that there is at least one packet pending to be
+                * read from the RxFIFO.
+                *
+                * In DMA mode this is handled by hardware
+                */
+               if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+                       cvmx_usb_poll_rx_fifo(usb);
+       }
+       if (usbc_gintsts.s.ptxfemp || usbc_gintsts.s.nptxfemp) {
+               /* Fill the Tx FIFOs when not in DMA mode */
+               if (usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)
+                       cvmx_usb_poll_tx_fifo(usb);
+       }
+       if (usbc_gintsts.s.disconnint || usbc_gintsts.s.prtint) {
+               union cvmx_usbcx_hprt usbc_hprt;
+               /*
+                * Disconnect Detected Interrupt (DisconnInt)
+                * Asserted when a device disconnect is detected.
+                *
+                * Host Port Interrupt (PrtInt)
+                * The core sets this bit to indicate a change in port status of
+                * one of the O2P USB core ports in Host mode. The application
+                * must read the Host Port Control and Status (HPRT) register to
+                * determine the exact event that caused this interrupt. The
+                * application must clear the appropriate status bit in the Host
+                * Port Control and Status register to clear this bit.
+                *
+                * Call the user's port callback
+                */
+               octeon_usb_port_callback(usb);
+               /* Clear the port change bits */
+               usbc_hprt.u32 =
+                       cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
+               usbc_hprt.s.prtena = 0;
+               cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index),
+                                    usbc_hprt.u32);
+       }
+       if (usbc_gintsts.s.hchint) {
+               /*
+                * Host Channels Interrupt (HChInt)
+                * The core sets this bit to indicate that an interrupt is
+                * pending on one of the channels of the core (in Host mode).
+                * The application must read the Host All Channels Interrupt
+                * (HAINT) register to determine the exact number of the channel
+                * on which the interrupt occurred, and then read the
+                * corresponding Host Channel-n Interrupt (HCINTn) register to
+                * determine the exact cause of the interrupt. The application
+                * must clear the appropriate status bit in the HCINTn register
+                * to clear this bit.
+                */
+               union cvmx_usbcx_haint usbc_haint;
+
+               usbc_haint.u32 = cvmx_usb_read_csr32(usb,
+                                       CVMX_USBCX_HAINT(usb->index));
+               while (usbc_haint.u32) {
+                       int channel;
+
+                       channel = __fls(usbc_haint.u32);
+                       cvmx_usb_poll_channel(usb, channel);
+                       usbc_haint.u32 ^= 1 << channel;
+               }
+       }
+
+       cvmx_usb_schedule(usb, usbc_gintsts.s.sof);
+
+       return 0;
+}
+
+/* convert between an HCD pointer and the corresponding struct octeon_hcd */
+static inline struct octeon_hcd *hcd_to_octeon(struct usb_hcd *hcd)
+{
+       return (struct octeon_hcd *)(hcd->hcd_priv);
+}
+
+static irqreturn_t octeon_usb_irq(struct usb_hcd *hcd)
+{
+       struct octeon_hcd *usb = hcd_to_octeon(hcd);
+       unsigned long flags;
+
+       spin_lock_irqsave(&usb->lock, flags);
+       cvmx_usb_poll(usb);
+       spin_unlock_irqrestore(&usb->lock, flags);
+       return IRQ_HANDLED;
+}
+
+static int octeon_usb_start(struct usb_hcd *hcd)
+{
+       hcd->state = HC_STATE_RUNNING;
+       return 0;
+}
+
+static void octeon_usb_stop(struct usb_hcd *hcd)
+{
+       hcd->state = HC_STATE_HALT;
+}
+
+static int octeon_usb_get_frame_number(struct usb_hcd *hcd)
+{
+       struct octeon_hcd *usb = hcd_to_octeon(hcd);
+
+       return cvmx_usb_get_frame_number(usb);
+}
+
+static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
+                                 struct urb *urb,
+                                 gfp_t mem_flags)
+{
+       struct octeon_hcd *usb = hcd_to_octeon(hcd);
+       struct device *dev = hcd->self.controller;
+       struct cvmx_usb_transaction *transaction = NULL;
+       struct cvmx_usb_pipe *pipe;
+       unsigned long flags;
+       struct cvmx_usb_iso_packet *iso_packet;
+       struct usb_host_endpoint *ep = urb->ep;
+       int rc;
+
+       urb->status = 0;
+       spin_lock_irqsave(&usb->lock, flags);
+
+       rc = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (rc) {
+               spin_unlock_irqrestore(&usb->lock, flags);
+               return rc;
+       }
+
+       if (!ep->hcpriv) {
+               enum cvmx_usb_transfer transfer_type;
+               enum cvmx_usb_speed speed;
+               int split_device = 0;
+               int split_port = 0;
+
+               switch (usb_pipetype(urb->pipe)) {
+               case PIPE_ISOCHRONOUS:
+                       transfer_type = CVMX_USB_TRANSFER_ISOCHRONOUS;
+                       break;
+               case PIPE_INTERRUPT:
+                       transfer_type = CVMX_USB_TRANSFER_INTERRUPT;
+                       break;
+               case PIPE_CONTROL:
+                       transfer_type = CVMX_USB_TRANSFER_CONTROL;
+                       break;
+               default:
+                       transfer_type = CVMX_USB_TRANSFER_BULK;
+                       break;
+               }
+               switch (urb->dev->speed) {
+               case USB_SPEED_LOW:
+                       speed = CVMX_USB_SPEED_LOW;
+                       break;
+               case USB_SPEED_FULL:
+                       speed = CVMX_USB_SPEED_FULL;
+                       break;
+               default:
+                       speed = CVMX_USB_SPEED_HIGH;
+                       break;
+               }
+               /*
+                * For slow devices on high speed ports we need to find the hub
+                * that does the speed translation so we know where to send the
+                * split transactions.
+                */
+               if (speed != CVMX_USB_SPEED_HIGH) {
+                       /*
+                        * Start at this device and work our way up the usb
+                        * tree.
+                        */
+                       struct usb_device *dev = urb->dev;
+
+                       while (dev->parent) {
+                               /*
+                                * If our parent is high speed then he'll
+                                * receive the splits.
+                                */
+                               if (dev->parent->speed == USB_SPEED_HIGH) {
+                                       split_device = dev->parent->devnum;
+                                       split_port = dev->portnum;
+                                       break;
+                               }
+                               /*
+                                * Move up the tree one level. If we make it all
+                                * the way up the tree, then the port must not
+                                * be in high speed mode and we don't need a
+                                * split.
+                                */
+                               dev = dev->parent;
+                       }
+               }
+               pipe = cvmx_usb_open_pipe(usb, usb_pipedevice(urb->pipe),
+                                         usb_pipeendpoint(urb->pipe), speed,
+                                         le16_to_cpu(ep->desc.wMaxPacketSize)
+                                         & 0x7ff,
+                                         transfer_type,
+                                         usb_pipein(urb->pipe) ?
+                                               CVMX_USB_DIRECTION_IN :
+                                               CVMX_USB_DIRECTION_OUT,
+                                         urb->interval,
+                                         (le16_to_cpu(ep->desc.wMaxPacketSize)
+                                          >> 11) & 0x3,
+                                         split_device, split_port);
+               if (!pipe) {
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+                       spin_unlock_irqrestore(&usb->lock, flags);
+                       dev_dbg(dev, "Failed to create pipe\n");
+                       return -ENOMEM;
+               }
+               ep->hcpriv = pipe;
+       } else {
+               pipe = ep->hcpriv;
+       }
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_ISOCHRONOUS:
+               dev_dbg(dev, "Submit isochronous to %d.%d\n",
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe));
+               /*
+                * Allocate a structure to use for our private list of
+                * isochronous packets.
+                */
+               iso_packet = kmalloc_array(urb->number_of_packets,
+                                          sizeof(struct cvmx_usb_iso_packet),
+                                          GFP_ATOMIC);
+               if (iso_packet) {
+                       int i;
+                       /* Fill the list with the data from the URB */
+                       for (i = 0; i < urb->number_of_packets; i++) {
+                               iso_packet[i].offset =
+                                       urb->iso_frame_desc[i].offset;
+                               iso_packet[i].length =
+                                       urb->iso_frame_desc[i].length;
+                               iso_packet[i].status = CVMX_USB_STATUS_ERROR;
+                       }
+                       /*
+                        * Store a pointer to the list in the URB setup_packet
+                        * field. We know this currently isn't being used and
+                        * this saves us a bunch of logic.
+                        */
+                       urb->setup_packet = (char *)iso_packet;
+                       transaction = cvmx_usb_submit_isochronous(usb,
+                                                                 pipe, urb);
+                       /*
+                        * If submit failed we need to free our private packet
+                        * list.
+                        */
+                       if (!transaction) {
+                               urb->setup_packet = NULL;
+                               kfree(iso_packet);
+                       }
+               }
+               break;
+       case PIPE_INTERRUPT:
+               dev_dbg(dev, "Submit interrupt to %d.%d\n",
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe));
+               transaction = cvmx_usb_submit_interrupt(usb, pipe, urb);
+               break;
+       case PIPE_CONTROL:
+               dev_dbg(dev, "Submit control to %d.%d\n",
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe));
+               transaction = cvmx_usb_submit_control(usb, pipe, urb);
+               break;
+       case PIPE_BULK:
+               dev_dbg(dev, "Submit bulk to %d.%d\n",
+                       usb_pipedevice(urb->pipe),
+                       usb_pipeendpoint(urb->pipe));
+               transaction = cvmx_usb_submit_bulk(usb, pipe, urb);
+               break;
+       }
+       if (!transaction) {
+               usb_hcd_unlink_urb_from_ep(hcd, urb);
+               spin_unlock_irqrestore(&usb->lock, flags);
+               dev_dbg(dev, "Failed to submit\n");
+               return -ENOMEM;
+       }
+       urb->hcpriv = transaction;
+       spin_unlock_irqrestore(&usb->lock, flags);
+       return 0;
+}
+
+static int octeon_usb_urb_dequeue(struct usb_hcd *hcd,
+                                 struct urb *urb,
+                                 int status)
+{
+       struct octeon_hcd *usb = hcd_to_octeon(hcd);
+       unsigned long flags;
+       int rc;
+
+       if (!urb->dev)
+               return -EINVAL;
+
+       spin_lock_irqsave(&usb->lock, flags);
+
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc)
+               goto out;
+
+       urb->status = status;
+       cvmx_usb_cancel(usb, urb->ep->hcpriv, urb->hcpriv);
+
+out:
+       spin_unlock_irqrestore(&usb->lock, flags);
+
+       return rc;
+}
+
+static void octeon_usb_endpoint_disable(struct usb_hcd *hcd,
+                                       struct usb_host_endpoint *ep)
+{
+       struct device *dev = hcd->self.controller;
+
+       if (ep->hcpriv) {
+               struct octeon_hcd *usb = hcd_to_octeon(hcd);
+               struct cvmx_usb_pipe *pipe = ep->hcpriv;
+               unsigned long flags;
+
+               spin_lock_irqsave(&usb->lock, flags);
+               cvmx_usb_cancel_all(usb, pipe);
+               if (cvmx_usb_close_pipe(usb, pipe))
+                       dev_dbg(dev, "Closing pipe %p failed\n", pipe);
+               spin_unlock_irqrestore(&usb->lock, flags);
+               ep->hcpriv = NULL;
+       }
+}
+
+static int octeon_usb_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       struct octeon_hcd *usb = hcd_to_octeon(hcd);
+       struct cvmx_usb_port_status port_status;
+       unsigned long flags;
+
+       spin_lock_irqsave(&usb->lock, flags);
+       port_status = cvmx_usb_get_status(usb);
+       spin_unlock_irqrestore(&usb->lock, flags);
+       buf[0] = port_status.connect_change << 1;
+
+       return buf[0] != 0;
+}
+
+static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+                                 u16 wIndex, char *buf, u16 wLength)
+{
+       struct octeon_hcd *usb = hcd_to_octeon(hcd);
+       struct device *dev = hcd->self.controller;
+       struct cvmx_usb_port_status usb_port_status;
+       int port_status;
+       struct usb_hub_descriptor *desc;
+       unsigned long flags;
+
+       switch (typeReq) {
+       case ClearHubFeature:
+               dev_dbg(dev, "ClearHubFeature\n");
+               switch (wValue) {
+               case C_HUB_LOCAL_POWER:
+               case C_HUB_OVER_CURRENT:
+                       /* Nothing required here */
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case ClearPortFeature:
+               dev_dbg(dev, "ClearPortFeature\n");
+               if (wIndex != 1) {
+                       dev_dbg(dev, " INVALID\n");
+                       return -EINVAL;
+               }
+
+               switch (wValue) {
+               case USB_PORT_FEAT_ENABLE:
+                       dev_dbg(dev, " ENABLE\n");
+                       spin_lock_irqsave(&usb->lock, flags);
+                       cvmx_usb_disable(usb);
+                       spin_unlock_irqrestore(&usb->lock, flags);
+                       break;
+               case USB_PORT_FEAT_SUSPEND:
+                       dev_dbg(dev, " SUSPEND\n");
+                       /* Not supported on Octeon */
+                       break;
+               case USB_PORT_FEAT_POWER:
+                       dev_dbg(dev, " POWER\n");
+                       /* Not supported on Octeon */
+                       break;
+               case USB_PORT_FEAT_INDICATOR:
+                       dev_dbg(dev, " INDICATOR\n");
+                       /* Port inidicator not supported */
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+                       dev_dbg(dev, " C_CONNECTION\n");
+                       /* Clears drivers internal connect status change flag */
+                       spin_lock_irqsave(&usb->lock, flags);
+                       usb->port_status = cvmx_usb_get_status(usb);
+                       spin_unlock_irqrestore(&usb->lock, flags);
+                       break;
+               case USB_PORT_FEAT_C_RESET:
+                       dev_dbg(dev, " C_RESET\n");
+                       /*
+                        * Clears the driver's internal Port Reset Change flag.
+                        */
+                       spin_lock_irqsave(&usb->lock, flags);
+                       usb->port_status = cvmx_usb_get_status(usb);
+                       spin_unlock_irqrestore(&usb->lock, flags);
+                       break;
+               case USB_PORT_FEAT_C_ENABLE:
+                       dev_dbg(dev, " C_ENABLE\n");
+                       /*
+                        * Clears the driver's internal Port Enable/Disable
+                        * Change flag.
+                        */
+                       spin_lock_irqsave(&usb->lock, flags);
+                       usb->port_status = cvmx_usb_get_status(usb);
+                       spin_unlock_irqrestore(&usb->lock, flags);
+                       break;
+               case USB_PORT_FEAT_C_SUSPEND:
+                       dev_dbg(dev, " C_SUSPEND\n");
+                       /*
+                        * Clears the driver's internal Port Suspend Change
+                        * flag, which is set when resume signaling on the host
+                        * port is complete.
+                        */
+                       break;
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       dev_dbg(dev, " C_OVER_CURRENT\n");
+                       /* Clears the driver's overcurrent Change flag */
+                       spin_lock_irqsave(&usb->lock, flags);
+                       usb->port_status = cvmx_usb_get_status(usb);
+                       spin_unlock_irqrestore(&usb->lock, flags);
+                       break;
+               default:
+                       dev_dbg(dev, " UNKNOWN\n");
+                       return -EINVAL;
+               }
+               break;
+       case GetHubDescriptor:
+               dev_dbg(dev, "GetHubDescriptor\n");
+               desc = (struct usb_hub_descriptor *)buf;
+               desc->bDescLength = 9;
+               desc->bDescriptorType = 0x29;
+               desc->bNbrPorts = 1;
+               desc->wHubCharacteristics = cpu_to_le16(0x08);
+               desc->bPwrOn2PwrGood = 1;
+               desc->bHubContrCurrent = 0;
+               desc->u.hs.DeviceRemovable[0] = 0;
+               desc->u.hs.DeviceRemovable[1] = 0xff;
+               break;
+       case GetHubStatus:
+               dev_dbg(dev, "GetHubStatus\n");
+               *(__le32 *)buf = 0;
+               break;
+       case GetPortStatus:
+               dev_dbg(dev, "GetPortStatus\n");
+               if (wIndex != 1) {
+                       dev_dbg(dev, " INVALID\n");
+                       return -EINVAL;
+               }
+
+               spin_lock_irqsave(&usb->lock, flags);
+               usb_port_status = cvmx_usb_get_status(usb);
+               spin_unlock_irqrestore(&usb->lock, flags);
+               port_status = 0;
+
+               if (usb_port_status.connect_change) {
+                       port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
+                       dev_dbg(dev, " C_CONNECTION\n");
+               }
+
+               if (usb_port_status.port_enabled) {
+                       port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
+                       dev_dbg(dev, " C_ENABLE\n");
+               }
+
+               if (usb_port_status.connected) {
+                       port_status |= (1 << USB_PORT_FEAT_CONNECTION);
+                       dev_dbg(dev, " CONNECTION\n");
+               }
+
+               if (usb_port_status.port_enabled) {
+                       port_status |= (1 << USB_PORT_FEAT_ENABLE);
+                       dev_dbg(dev, " ENABLE\n");
+               }
+
+               if (usb_port_status.port_over_current) {
+                       port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
+                       dev_dbg(dev, " OVER_CURRENT\n");
+               }
+
+               if (usb_port_status.port_powered) {
+                       port_status |= (1 << USB_PORT_FEAT_POWER);
+                       dev_dbg(dev, " POWER\n");
+               }
+
+               if (usb_port_status.port_speed == CVMX_USB_SPEED_HIGH) {
+                       port_status |= USB_PORT_STAT_HIGH_SPEED;
+                       dev_dbg(dev, " HIGHSPEED\n");
+               } else if (usb_port_status.port_speed == CVMX_USB_SPEED_LOW) {
+                       port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
+                       dev_dbg(dev, " LOWSPEED\n");
+               }
+
+               *((__le32 *)buf) = cpu_to_le32(port_status);
+               break;
+       case SetHubFeature:
+               dev_dbg(dev, "SetHubFeature\n");
+               /* No HUB features supported */
+               break;
+       case SetPortFeature:
+               dev_dbg(dev, "SetPortFeature\n");
+               if (wIndex != 1) {
+                       dev_dbg(dev, " INVALID\n");
+                       return -EINVAL;
+               }
+
+               switch (wValue) {
+               case USB_PORT_FEAT_SUSPEND:
+                       dev_dbg(dev, " SUSPEND\n");
+                       return -EINVAL;
+               case USB_PORT_FEAT_POWER:
+                       dev_dbg(dev, " POWER\n");
+                       /*
+                        * Program the port power bit to drive VBUS on the USB.
+                        */
+                       spin_lock_irqsave(&usb->lock, flags);
+                       USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index),
+                                       cvmx_usbcx_hprt, prtpwr, 1);
+                       spin_unlock_irqrestore(&usb->lock, flags);
+                       return 0;
+               case USB_PORT_FEAT_RESET:
+                       dev_dbg(dev, " RESET\n");
+                       spin_lock_irqsave(&usb->lock, flags);
+                       cvmx_usb_reset_port(usb);
+                       spin_unlock_irqrestore(&usb->lock, flags);
+                       return 0;
+               case USB_PORT_FEAT_INDICATOR:
+                       dev_dbg(dev, " INDICATOR\n");
+                       /* Not supported */
+                       break;
+               default:
+                       dev_dbg(dev, " UNKNOWN\n");
+                       return -EINVAL;
+               }
+               break;
+       default:
+               dev_dbg(dev, "Unknown root hub request\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static const struct hc_driver octeon_hc_driver = {
+       .description            = "Octeon USB",
+       .product_desc           = "Octeon Host Controller",
+       .hcd_priv_size          = sizeof(struct octeon_hcd),
+       .irq                    = octeon_usb_irq,
+       .flags                  = HCD_MEMORY | HCD_DMA | HCD_USB2,
+       .start                  = octeon_usb_start,
+       .stop                   = octeon_usb_stop,
+       .urb_enqueue            = octeon_usb_urb_enqueue,
+       .urb_dequeue            = octeon_usb_urb_dequeue,
+       .endpoint_disable       = octeon_usb_endpoint_disable,
+       .get_frame_number       = octeon_usb_get_frame_number,
+       .hub_status_data        = octeon_usb_hub_status_data,
+       .hub_control            = octeon_usb_hub_control,
+       .map_urb_for_dma        = octeon_map_urb_for_dma,
+       .unmap_urb_for_dma      = octeon_unmap_urb_for_dma,
+};
+
+static int octeon_usb_probe(struct platform_device *pdev)
+{
+       int status;
+       int initialize_flags;
+       int usb_num;
+       struct resource *res_mem;
+       struct device_node *usbn_node;
+       int irq = platform_get_irq(pdev, 0);
+       struct device *dev = &pdev->dev;
+       struct octeon_hcd *usb;
+       struct usb_hcd *hcd;
+       u32 clock_rate = 48000000;
+       bool is_crystal_clock = false;
+       const char *clock_type;
+       int i;
+
+       if (!dev->of_node) {
+               dev_err(dev, "Error: empty of_node\n");
+               return -ENXIO;
+       }
+       usbn_node = dev->of_node->parent;
+
+       i = of_property_read_u32(usbn_node,
+                                "clock-frequency", &clock_rate);
+       if (i)
+               i = of_property_read_u32(usbn_node,
+                                        "refclk-frequency", &clock_rate);
+       if (i) {
+               dev_err(dev, "No USBN \"clock-frequency\"\n");
+               return -ENXIO;
+       }
+       switch (clock_rate) {
+       case 12000000:
+               initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
+               break;
+       case 24000000:
+               initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
+               break;
+       case 48000000:
+               initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
+               break;
+       default:
+               dev_err(dev, "Illegal USBN \"clock-frequency\" %u\n",
+                       clock_rate);
+               return -ENXIO;
+       }
+
+       i = of_property_read_string(usbn_node,
+                                   "cavium,refclk-type", &clock_type);
+       if (i)
+               i = of_property_read_string(usbn_node,
+                                           "refclk-type", &clock_type);
+
+       if (!i && strcmp("crystal", clock_type) == 0)
+               is_crystal_clock = true;
+
+       if (is_crystal_clock)
+               initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI;
+       else
+               initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_mem) {
+               dev_err(dev, "found no memory resource\n");
+               return -ENXIO;
+       }
+       usb_num = (res_mem->start >> 44) & 1;
+
+       if (irq < 0) {
+               /* Defective device tree, but we know how to fix it. */
+               irq_hw_number_t hwirq = usb_num ? (1 << 6) + 17 : 56;
+
+               irq = irq_create_mapping(NULL, hwirq);
+       }
+
+       /*
+        * Set the DMA mask to 64bits so we get buffers already translated for
+        * DMA.
+        */
+       i = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
+       if (i)
+               return i;
+
+       /*
+        * Only cn52XX and cn56XX have DWC_OTG USB hardware and the
+        * IOB priority registers.  Under heavy network load USB
+        * hardware can be starved by the IOB causing a crash.  Give
+        * it a priority boost if it has been waiting more than 400
+        * cycles to avoid this situation.
+        *
+        * Testing indicates that a cnt_val of 8192 is not sufficient,
+        * but no failures are seen with 4096.  We choose a value of
+        * 400 to give a safety factor of 10.
+        */
+       if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
+               union cvmx_iob_n2c_l2c_pri_cnt pri_cnt;
+
+               pri_cnt.u64 = 0;
+               pri_cnt.s.cnt_enb = 1;
+               pri_cnt.s.cnt_val = 400;
+               cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64);
+       }
+
+       hcd = usb_create_hcd(&octeon_hc_driver, dev, dev_name(dev));
+       if (!hcd) {
+               dev_dbg(dev, "Failed to allocate memory for HCD\n");
+               return -1;
+       }
+       hcd->uses_new_polling = 1;
+       usb = (struct octeon_hcd *)hcd->hcd_priv;
+
+       spin_lock_init(&usb->lock);
+
+       usb->init_flags = initialize_flags;
+
+       /* Initialize the USB state structure */
+       usb->index = usb_num;
+       INIT_LIST_HEAD(&usb->idle_pipes);
+       for (i = 0; i < ARRAY_SIZE(usb->active_pipes); i++)
+               INIT_LIST_HEAD(&usb->active_pipes[i]);
+
+       /* Due to an errata, CN31XX doesn't support DMA */
+       if (OCTEON_IS_MODEL(OCTEON_CN31XX)) {
+               usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
+               /* Only use one channel with non DMA */
+               usb->idle_hardware_channels = 0x1;
+       } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
+               /* CN5XXX have an errata with channel 3 */
+               usb->idle_hardware_channels = 0xf7;
+       } else {
+               usb->idle_hardware_channels = 0xff;
+       }
+
+       status = cvmx_usb_initialize(dev, usb);
+       if (status) {
+               dev_dbg(dev, "USB initialization failed with %d\n", status);
+               usb_put_hcd(hcd);
+               return -1;
+       }
+
+       status = usb_add_hcd(hcd, irq, 0);
+       if (status) {
+               dev_dbg(dev, "USB add HCD failed with %d\n", status);
+               usb_put_hcd(hcd);
+               return -1;
+       }
+       device_wakeup_enable(hcd->self.controller);
+
+       dev_info(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq);
+
+       return 0;
+}
+
+static int octeon_usb_remove(struct platform_device *pdev)
+{
+       int status;
+       struct device *dev = &pdev->dev;
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct octeon_hcd *usb = hcd_to_octeon(hcd);
+       unsigned long flags;
+
+       usb_remove_hcd(hcd);
+       spin_lock_irqsave(&usb->lock, flags);
+       status = cvmx_usb_shutdown(usb);
+       spin_unlock_irqrestore(&usb->lock, flags);
+       if (status)
+               dev_dbg(dev, "USB shutdown failed with %d\n", status);
+
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+static const struct of_device_id octeon_usb_match[] = {
+       {
+               .compatible = "cavium,octeon-5750-usbc",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, octeon_usb_match);
+
+static struct platform_driver octeon_usb_driver = {
+       .driver = {
+               .name           = "octeon-hcd",
+               .of_match_table = octeon_usb_match,
+       },
+       .probe      = octeon_usb_probe,
+       .remove     = octeon_usb_remove,
+};
+
+static int __init octeon_usb_driver_init(void)
+{
+       if (usb_disabled())
+               return 0;
+
+       return platform_driver_register(&octeon_usb_driver);
+}
+module_init(octeon_usb_driver_init);
+
+static void __exit octeon_usb_driver_exit(void)
+{
+       if (usb_disabled())
+               return;
+
+       platform_driver_unregister(&octeon_usb_driver);
+}
+module_exit(octeon_usb_driver_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cavium, Inc. <support@cavium.com>");
+MODULE_DESCRIPTION("Cavium Inc. OCTEON USB Host driver.");
diff --git a/drivers/staging/octeon-usb/octeon-hcd.h b/drivers/staging/octeon-usb/octeon-hcd.h
new file mode 100644 (file)
index 0000000..9ed619c
--- /dev/null
@@ -0,0 +1,1847 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Octeon HCD hardware register definitions.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Some parts of the code were originally released under BSD license:
+ *
+ * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ *   * Neither the name of Cavium Networks nor the names of
+ *     its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written
+ *     permission.
+ *
+ * This Software, including technical data, may be subject to U.S. export
+ * control laws, including the U.S. Export Administration Act and its associated
+ * regulations, and may be subject to export or import regulations in other
+ * countries.
+ *
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
+ * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR
+ * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
+ * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION
+ * OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
+ * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
+ * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
+ * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
+ * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
+ */
+
+#ifndef __OCTEON_HCD_H__
+#define __OCTEON_HCD_H__
+
+#include <asm/bitfield.h>
+
+#define CVMX_USBCXBASE 0x00016F0010000000ull
+#define CVMX_USBCXREG1(reg, bid) \
+       (CVMX_ADD_IO_SEG(CVMX_USBCXBASE | reg) + \
+        ((bid) & 1) * 0x100000000000ull)
+#define CVMX_USBCXREG2(reg, bid, off) \
+       (CVMX_ADD_IO_SEG(CVMX_USBCXBASE | reg) + \
+        (((off) & 7) + ((bid) & 1) * 0x8000000000ull) * 32)
+
+#define CVMX_USBCX_GAHBCFG(bid)                CVMX_USBCXREG1(0x008, bid)
+#define CVMX_USBCX_GHWCFG3(bid)                CVMX_USBCXREG1(0x04c, bid)
+#define CVMX_USBCX_GINTMSK(bid)                CVMX_USBCXREG1(0x018, bid)
+#define CVMX_USBCX_GINTSTS(bid)                CVMX_USBCXREG1(0x014, bid)
+#define CVMX_USBCX_GNPTXFSIZ(bid)      CVMX_USBCXREG1(0x028, bid)
+#define CVMX_USBCX_GNPTXSTS(bid)       CVMX_USBCXREG1(0x02c, bid)
+#define CVMX_USBCX_GOTGCTL(bid)                CVMX_USBCXREG1(0x000, bid)
+#define CVMX_USBCX_GRSTCTL(bid)                CVMX_USBCXREG1(0x010, bid)
+#define CVMX_USBCX_GRXFSIZ(bid)                CVMX_USBCXREG1(0x024, bid)
+#define CVMX_USBCX_GRXSTSPH(bid)       CVMX_USBCXREG1(0x020, bid)
+#define CVMX_USBCX_GUSBCFG(bid)                CVMX_USBCXREG1(0x00c, bid)
+#define CVMX_USBCX_HAINT(bid)          CVMX_USBCXREG1(0x414, bid)
+#define CVMX_USBCX_HAINTMSK(bid)       CVMX_USBCXREG1(0x418, bid)
+#define CVMX_USBCX_HCCHARX(off, bid)   CVMX_USBCXREG2(0x500, bid, off)
+#define CVMX_USBCX_HCFG(bid)           CVMX_USBCXREG1(0x400, bid)
+#define CVMX_USBCX_HCINTMSKX(off, bid) CVMX_USBCXREG2(0x50c, bid, off)
+#define CVMX_USBCX_HCINTX(off, bid)    CVMX_USBCXREG2(0x508, bid, off)
+#define CVMX_USBCX_HCSPLTX(off, bid)   CVMX_USBCXREG2(0x504, bid, off)
+#define CVMX_USBCX_HCTSIZX(off, bid)   CVMX_USBCXREG2(0x510, bid, off)
+#define CVMX_USBCX_HFIR(bid)           CVMX_USBCXREG1(0x404, bid)
+#define CVMX_USBCX_HFNUM(bid)          CVMX_USBCXREG1(0x408, bid)
+#define CVMX_USBCX_HPRT(bid)           CVMX_USBCXREG1(0x440, bid)
+#define CVMX_USBCX_HPTXFSIZ(bid)       CVMX_USBCXREG1(0x100, bid)
+#define CVMX_USBCX_HPTXSTS(bid)                CVMX_USBCXREG1(0x410, bid)
+
+#define CVMX_USBNXBID1(bid) (((bid) & 1) * 0x10000000ull)
+#define CVMX_USBNXBID2(bid) (((bid) & 1) * 0x100000000000ull)
+
+#define CVMX_USBNXREG1(reg, bid) \
+       (CVMX_ADD_IO_SEG(0x0001180068000000ull | reg) + CVMX_USBNXBID1(bid))
+#define CVMX_USBNXREG2(reg, bid) \
+       (CVMX_ADD_IO_SEG(0x00016F0000000000ull | reg) + CVMX_USBNXBID2(bid))
+
+#define CVMX_USBNX_CLK_CTL(bid)                CVMX_USBNXREG1(0x10, bid)
+#define CVMX_USBNX_DMA0_INB_CHN0(bid)  CVMX_USBNXREG2(0x818, bid)
+#define CVMX_USBNX_DMA0_OUTB_CHN0(bid) CVMX_USBNXREG2(0x858, bid)
+#define CVMX_USBNX_USBP_CTL_STATUS(bid)        CVMX_USBNXREG1(0x18, bid)
+
+/**
+ * cvmx_usbc#_gahbcfg
+ *
+ * Core AHB Configuration Register (GAHBCFG)
+ *
+ * This register can be used to configure the core after power-on or a change in
+ * mode of operation. This register mainly contains AHB system-related
+ * configuration parameters. The AHB is the processor interface to the O2P USB
+ * core. In general, software need not know about this interface except to
+ * program the values as specified.
+ *
+ * The application must program this register as part of the O2P USB core
+ * initialization. Do not change this register after the initial programming.
+ */
+union cvmx_usbcx_gahbcfg {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_gahbcfg_s
+        * @ptxfemplvl: Periodic TxFIFO Empty Level (PTxFEmpLvl)
+        *      Software should set this bit to 0x1.
+        *      Indicates when the Periodic TxFIFO Empty Interrupt bit in the
+        *      Core Interrupt register (GINTSTS.PTxFEmp) is triggered. This
+        *      bit is used only in Slave mode.
+        *      * 1'b0: GINTSTS.PTxFEmp interrupt indicates that the Periodic
+        *      TxFIFO is half empty
+        *      * 1'b1: GINTSTS.PTxFEmp interrupt indicates that the Periodic
+        *      TxFIFO is completely empty
+        * @nptxfemplvl: Non-Periodic TxFIFO Empty Level (NPTxFEmpLvl)
+        *      Software should set this bit to 0x1.
+        *      Indicates when the Non-Periodic TxFIFO Empty Interrupt bit in
+        *      the Core Interrupt register (GINTSTS.NPTxFEmp) is triggered.
+        *      This bit is used only in Slave mode.
+        *      * 1'b0: GINTSTS.NPTxFEmp interrupt indicates that the Non-
+        *      Periodic TxFIFO is half empty
+        *      * 1'b1: GINTSTS.NPTxFEmp interrupt indicates that the Non-
+        *      Periodic TxFIFO is completely empty
+        * @dmaen: DMA Enable (DMAEn)
+        *      * 1'b0: Core operates in Slave mode
+        *      * 1'b1: Core operates in a DMA mode
+        * @hbstlen: Burst Length/Type (HBstLen)
+        *      This field has not effect and should be left as 0x0.
+        * @glblintrmsk: Global Interrupt Mask (GlblIntrMsk)
+        *      Software should set this field to 0x1.
+        *      The application uses this bit to mask or unmask the interrupt
+        *      line assertion to itself. Irrespective of this bit's setting,
+        *      the interrupt status registers are updated by the core.
+        *      * 1'b0: Mask the interrupt assertion to the application.
+        *      * 1'b1: Unmask the interrupt assertion to the application.
+        */
+       struct cvmx_usbcx_gahbcfg_s {
+               __BITFIELD_FIELD(u32 reserved_9_31      : 23,
+               __BITFIELD_FIELD(u32 ptxfemplvl         : 1,
+               __BITFIELD_FIELD(u32 nptxfemplvl        : 1,
+               __BITFIELD_FIELD(u32 reserved_6_6       : 1,
+               __BITFIELD_FIELD(u32 dmaen              : 1,
+               __BITFIELD_FIELD(u32 hbstlen            : 4,
+               __BITFIELD_FIELD(u32 glblintrmsk        : 1,
+               ;)))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_ghwcfg3
+ *
+ * User HW Config3 Register (GHWCFG3)
+ *
+ * This register contains the configuration options of the O2P USB core.
+ */
+union cvmx_usbcx_ghwcfg3 {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_ghwcfg3_s
+        * @dfifodepth: DFIFO Depth (DfifoDepth)
+        *      This value is in terms of 32-bit words.
+        *      * Minimum value is 32
+        *      * Maximum value is 32768
+        * @ahbphysync: AHB and PHY Synchronous (AhbPhySync)
+        *      Indicates whether AHB and PHY clocks are synchronous to
+        *      each other.
+        *      * 1'b0: No
+        *      * 1'b1: Yes
+        *      This bit is tied to 1.
+        * @rsttype: Reset Style for Clocked always Blocks in RTL (RstType)
+        *      * 1'b0: Asynchronous reset is used in the core
+        *      * 1'b1: Synchronous reset is used in the core
+        * @optfeature: Optional Features Removed (OptFeature)
+        *      Indicates whether the User ID register, GPIO interface ports,
+        *      and SOF toggle and counter ports were removed for gate count
+        *      optimization.
+        * @vendor_control_interface_support: Vendor Control Interface Support
+        *      * 1'b0: Vendor Control Interface is not available on the core.
+        *      * 1'b1: Vendor Control Interface is available.
+        * @i2c_selection: I2C Selection
+        *      * 1'b0: I2C Interface is not available on the core.
+        *      * 1'b1: I2C Interface is available on the core.
+        * @otgen: OTG Function Enabled (OtgEn)
+        *      The application uses this bit to indicate the O2P USB core's
+        *      OTG capabilities.
+        *      * 1'b0: Not OTG capable
+        *      * 1'b1: OTG Capable
+        * @pktsizewidth: Width of Packet Size Counters (PktSizeWidth)
+        *      * 3'b000: 4 bits
+        *      * 3'b001: 5 bits
+        *      * 3'b010: 6 bits
+        *      * 3'b011: 7 bits
+        *      * 3'b100: 8 bits
+        *      * 3'b101: 9 bits
+        *      * 3'b110: 10 bits
+        *      * Others: Reserved
+        * @xfersizewidth: Width of Transfer Size Counters (XferSizeWidth)
+        *      * 4'b0000: 11 bits
+        *      * 4'b0001: 12 bits
+        *      - ...
+        *      * 4'b1000: 19 bits
+        *      * Others: Reserved
+        */
+       struct cvmx_usbcx_ghwcfg3_s {
+               __BITFIELD_FIELD(u32 dfifodepth                         : 16,
+               __BITFIELD_FIELD(u32 reserved_13_15                     : 3,
+               __BITFIELD_FIELD(u32 ahbphysync                         : 1,
+               __BITFIELD_FIELD(u32 rsttype                            : 1,
+               __BITFIELD_FIELD(u32 optfeature                         : 1,
+               __BITFIELD_FIELD(u32 vendor_control_interface_support   : 1,
+               __BITFIELD_FIELD(u32 i2c_selection                      : 1,
+               __BITFIELD_FIELD(u32 otgen                              : 1,
+               __BITFIELD_FIELD(u32 pktsizewidth                       : 3,
+               __BITFIELD_FIELD(u32 xfersizewidth                      : 4,
+               ;))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_gintmsk
+ *
+ * Core Interrupt Mask Register (GINTMSK)
+ *
+ * This register works with the Core Interrupt register to interrupt the
+ * application. When an interrupt bit is masked, the interrupt associated with
+ * that bit will not be generated. However, the Core Interrupt (GINTSTS)
+ * register bit corresponding to that interrupt will still be set.
+ * Mask interrupt: 1'b0, Unmask interrupt: 1'b1
+ */
+union cvmx_usbcx_gintmsk {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_gintmsk_s
+        * @wkupintmsk: Resume/Remote Wakeup Detected Interrupt Mask
+        *      (WkUpIntMsk)
+        * @sessreqintmsk: Session Request/New Session Detected Interrupt Mask
+        *      (SessReqIntMsk)
+        * @disconnintmsk: Disconnect Detected Interrupt Mask (DisconnIntMsk)
+        * @conidstschngmsk: Connector ID Status Change Mask (ConIDStsChngMsk)
+        * @ptxfempmsk: Periodic TxFIFO Empty Mask (PTxFEmpMsk)
+        * @hchintmsk: Host Channels Interrupt Mask (HChIntMsk)
+        * @prtintmsk: Host Port Interrupt Mask (PrtIntMsk)
+        * @fetsuspmsk: Data Fetch Suspended Mask (FetSuspMsk)
+        * @incomplpmsk: Incomplete Periodic Transfer Mask (incomplPMsk)
+        *      Incomplete Isochronous OUT Transfer Mask
+        *      (incompISOOUTMsk)
+        * @incompisoinmsk: Incomplete Isochronous IN Transfer Mask
+        *                  (incompISOINMsk)
+        * @oepintmsk: OUT Endpoints Interrupt Mask (OEPIntMsk)
+        * @inepintmsk: IN Endpoints Interrupt Mask (INEPIntMsk)
+        * @epmismsk: Endpoint Mismatch Interrupt Mask (EPMisMsk)
+        * @eopfmsk: End of Periodic Frame Interrupt Mask (EOPFMsk)
+        * @isooutdropmsk: Isochronous OUT Packet Dropped Interrupt Mask
+        *      (ISOOutDropMsk)
+        * @enumdonemsk: Enumeration Done Mask (EnumDoneMsk)
+        * @usbrstmsk: USB Reset Mask (USBRstMsk)
+        * @usbsuspmsk: USB Suspend Mask (USBSuspMsk)
+        * @erlysuspmsk: Early Suspend Mask (ErlySuspMsk)
+        * @i2cint: I2C Interrupt Mask (I2CINT)
+        * @ulpickintmsk: ULPI Carkit Interrupt Mask (ULPICKINTMsk)
+        *      I2C Carkit Interrupt Mask (I2CCKINTMsk)
+        * @goutnakeffmsk: Global OUT NAK Effective Mask (GOUTNakEffMsk)
+        * @ginnakeffmsk: Global Non-Periodic IN NAK Effective Mask
+        *                (GINNakEffMsk)
+        * @nptxfempmsk: Non-Periodic TxFIFO Empty Mask (NPTxFEmpMsk)
+        * @rxflvlmsk: Receive FIFO Non-Empty Mask (RxFLvlMsk)
+        * @sofmsk: Start of (micro)Frame Mask (SofMsk)
+        * @otgintmsk: OTG Interrupt Mask (OTGIntMsk)
+        * @modemismsk: Mode Mismatch Interrupt Mask (ModeMisMsk)
+        */
+       struct cvmx_usbcx_gintmsk_s {
+               __BITFIELD_FIELD(u32 wkupintmsk         : 1,
+               __BITFIELD_FIELD(u32 sessreqintmsk      : 1,
+               __BITFIELD_FIELD(u32 disconnintmsk      : 1,
+               __BITFIELD_FIELD(u32 conidstschngmsk    : 1,
+               __BITFIELD_FIELD(u32 reserved_27_27     : 1,
+               __BITFIELD_FIELD(u32 ptxfempmsk         : 1,
+               __BITFIELD_FIELD(u32 hchintmsk          : 1,
+               __BITFIELD_FIELD(u32 prtintmsk          : 1,
+               __BITFIELD_FIELD(u32 reserved_23_23     : 1,
+               __BITFIELD_FIELD(u32 fetsuspmsk         : 1,
+               __BITFIELD_FIELD(u32 incomplpmsk        : 1,
+               __BITFIELD_FIELD(u32 incompisoinmsk     : 1,
+               __BITFIELD_FIELD(u32 oepintmsk          : 1,
+               __BITFIELD_FIELD(u32 inepintmsk         : 1,
+               __BITFIELD_FIELD(u32 epmismsk           : 1,
+               __BITFIELD_FIELD(u32 reserved_16_16     : 1,
+               __BITFIELD_FIELD(u32 eopfmsk            : 1,
+               __BITFIELD_FIELD(u32 isooutdropmsk      : 1,
+               __BITFIELD_FIELD(u32 enumdonemsk        : 1,
+               __BITFIELD_FIELD(u32 usbrstmsk          : 1,
+               __BITFIELD_FIELD(u32 usbsuspmsk         : 1,
+               __BITFIELD_FIELD(u32 erlysuspmsk        : 1,
+               __BITFIELD_FIELD(u32 i2cint             : 1,
+               __BITFIELD_FIELD(u32 ulpickintmsk       : 1,
+               __BITFIELD_FIELD(u32 goutnakeffmsk      : 1,
+               __BITFIELD_FIELD(u32 ginnakeffmsk       : 1,
+               __BITFIELD_FIELD(u32 nptxfempmsk        : 1,
+               __BITFIELD_FIELD(u32 rxflvlmsk          : 1,
+               __BITFIELD_FIELD(u32 sofmsk             : 1,
+               __BITFIELD_FIELD(u32 otgintmsk          : 1,
+               __BITFIELD_FIELD(u32 modemismsk         : 1,
+               __BITFIELD_FIELD(u32 reserved_0_0       : 1,
+               ;))))))))))))))))))))))))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_gintsts
+ *
+ * Core Interrupt Register (GINTSTS)
+ *
+ * This register interrupts the application for system-level events in the
+ * current mode of operation (Device mode or Host mode). It is shown in
+ * Interrupt. Some of the bits in this register are valid only in Host mode,
+ * while others are valid in Device mode only. This register also indicates the
+ * current mode of operation. In order to clear the interrupt status bits of
+ * type R_SS_WC, the application must write 1'b1 into the bit. The FIFO status
+ * interrupts are read only; once software reads from or writes to the FIFO
+ * while servicing these interrupts, FIFO interrupt conditions are cleared
+ * automatically.
+ */
+union cvmx_usbcx_gintsts {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_gintsts_s
+        * @wkupint: Resume/Remote Wakeup Detected Interrupt (WkUpInt)
+        *      In Device mode, this interrupt is asserted when a resume is
+        *      detected on the USB. In Host mode, this interrupt is asserted
+        *      when a remote wakeup is detected on the USB.
+        *      For more information on how to use this interrupt, see "Partial
+        *      Power-Down and Clock Gating Programming Model" on
+        *      page 353.
+        * @sessreqint: Session Request/New Session Detected Interrupt
+        *              (SessReqInt)
+        *      In Host mode, this interrupt is asserted when a session request
+        *      is detected from the device. In Device mode, this interrupt is
+        *      asserted when the utmiotg_bvalid signal goes high.
+        *      For more information on how to use this interrupt, see "Partial
+        *      Power-Down and Clock Gating Programming Model" on
+        *      page 353.
+        * @disconnint: Disconnect Detected Interrupt (DisconnInt)
+        *      Asserted when a device disconnect is detected.
+        * @conidstschng: Connector ID Status Change (ConIDStsChng)
+        *      The core sets this bit when there is a change in connector ID
+        *      status.
+        * @ptxfemp: Periodic TxFIFO Empty (PTxFEmp)
+        *      Asserted when the Periodic Transmit FIFO is either half or
+        *      completely empty and there is space for at least one entry to be
+        *      written in the Periodic Request Queue. The half or completely
+        *      empty status is determined by the Periodic TxFIFO Empty Level
+        *      bit in the Core AHB Configuration register
+        *      (GAHBCFG.PTxFEmpLvl).
+        * @hchint: Host Channels Interrupt (HChInt)
+        *      The core sets this bit to indicate that an interrupt is pending
+        *      on one of the channels of the core (in Host mode). The
+        *      application must read the Host All Channels Interrupt (HAINT)
+        *      register to determine the exact number of the channel on which
+        *      the interrupt occurred, and then read the corresponding Host
+        *      Channel-n Interrupt (HCINTn) register to determine the exact
+        *      cause of the interrupt. The application must clear the
+        *      appropriate status bit in the HCINTn register to clear this bit.
+        * @prtint: Host Port Interrupt (PrtInt)
+        *      The core sets this bit to indicate a change in port status of
+        *      one of the O2P USB core ports in Host mode. The application must
+        *      read the Host Port Control and Status (HPRT) register to
+        *      determine the exact event that caused this interrupt. The
+        *      application must clear the appropriate status bit in the Host
+        *      Port Control and Status register to clear this bit.
+        * @fetsusp: Data Fetch Suspended (FetSusp)
+        *      This interrupt is valid only in DMA mode. This interrupt
+        *      indicates that the core has stopped fetching data for IN
+        *      endpoints due to the unavailability of TxFIFO space or Request
+        *      Queue space. This interrupt is used by the application for an
+        *      endpoint mismatch algorithm.
+        * @incomplp: Incomplete Periodic Transfer (incomplP)
+        *      In Host mode, the core sets this interrupt bit when there are
+        *      incomplete periodic transactions still pending which are
+        *      scheduled for the current microframe.
+        *      Incomplete Isochronous OUT Transfer (incompISOOUT)
+        *      The Device mode, the core sets this interrupt to indicate that
+        *      there is at least one isochronous OUT endpoint on which the
+        *      transfer is not completed in the current microframe. This
+        *      interrupt is asserted along with the End of Periodic Frame
+        *      Interrupt (EOPF) bit in this register.
+        * @incompisoin: Incomplete Isochronous IN Transfer (incompISOIN)
+        *      The core sets this interrupt to indicate that there is at least
+        *      one isochronous IN endpoint on which the transfer is not
+        *      completed in the current microframe. This interrupt is asserted
+        *      along with the End of Periodic Frame Interrupt (EOPF) bit in
+        *      this register.
+        * @oepint: OUT Endpoints Interrupt (OEPInt)
+        *      The core sets this bit to indicate that an interrupt is pending
+        *      on one of the OUT endpoints of the core (in Device mode). The
+        *      application must read the Device All Endpoints Interrupt
+        *      (DAINT) register to determine the exact number of the OUT
+        *      endpoint on which the interrupt occurred, and then read the
+        *      corresponding Device OUT Endpoint-n Interrupt (DOEPINTn)
+        *      register to determine the exact cause of the interrupt. The
+        *      application must clear the appropriate status bit in the
+        *      corresponding DOEPINTn register to clear this bit.
+        * @iepint: IN Endpoints Interrupt (IEPInt)
+        *      The core sets this bit to indicate that an interrupt is pending
+        *      on one of the IN endpoints of the core (in Device mode). The
+        *      application must read the Device All Endpoints Interrupt
+        *      (DAINT) register to determine the exact number of the IN
+        *      endpoint on which the interrupt occurred, and then read the
+        *      corresponding Device IN Endpoint-n Interrupt (DIEPINTn)
+        *      register to determine the exact cause of the interrupt. The
+        *      application must clear the appropriate status bit in the
+        *      corresponding DIEPINTn register to clear this bit.
+        * @epmis: Endpoint Mismatch Interrupt (EPMis)
+        *      Indicates that an IN token has been received for a non-periodic
+        *      endpoint, but the data for another endpoint is present in the
+        *      top of the Non-Periodic Transmit FIFO and the IN endpoint
+        *      mismatch count programmed by the application has expired.
+        * @eopf: End of Periodic Frame Interrupt (EOPF)
+        *      Indicates that the period specified in the Periodic Frame
+        *      Interval field of the Device Configuration register
+        *      (DCFG.PerFrInt) has been reached in the current microframe.
+        * @isooutdrop: Isochronous OUT Packet Dropped Interrupt (ISOOutDrop)
+        *      The core sets this bit when it fails to write an isochronous OUT
+        *      packet into the RxFIFO because the RxFIFO doesn't have
+        *      enough space to accommodate a maximum packet size packet
+        *      for the isochronous OUT endpoint.
+        * @enumdone: Enumeration Done (EnumDone)
+        *      The core sets this bit to indicate that speed enumeration is
+        *      complete. The application must read the Device Status (DSTS)
+        *      register to obtain the enumerated speed.
+        * @usbrst: USB Reset (USBRst)
+        *      The core sets this bit to indicate that a reset is detected on
+        *      the USB.
+        * @usbsusp: USB Suspend (USBSusp)
+        *      The core sets this bit to indicate that a suspend was detected
+        *      on the USB. The core enters the Suspended state when there
+        *      is no activity on the phy_line_state_i signal for an extended
+        *      period of time.
+        * @erlysusp: Early Suspend (ErlySusp)
+        *      The core sets this bit to indicate that an Idle state has been
+        *      detected on the USB for 3 ms.
+        * @i2cint: I2C Interrupt (I2CINT)
+        *      This bit is always 0x0.
+        * @ulpickint: ULPI Carkit Interrupt (ULPICKINT)
+        *      This bit is always 0x0.
+        * @goutnakeff: Global OUT NAK Effective (GOUTNakEff)
+        *      Indicates that the Set Global OUT NAK bit in the Device Control
+        *      register (DCTL.SGOUTNak), set by the application, has taken
+        *      effect in the core. This bit can be cleared by writing the Clear
+        *      Global OUT NAK bit in the Device Control register
+        *      (DCTL.CGOUTNak).
+        * @ginnakeff: Global IN Non-Periodic NAK Effective (GINNakEff)
+        *      Indicates that the Set Global Non-Periodic IN NAK bit in the
+        *      Device Control register (DCTL.SGNPInNak), set by the
+        *      application, has taken effect in the core. That is, the core has
+        *      sampled the Global IN NAK bit set by the application. This bit
+        *      can be cleared by clearing the Clear Global Non-Periodic IN
+        *      NAK bit in the Device Control register (DCTL.CGNPInNak).
+        *      This interrupt does not necessarily mean that a NAK handshake
+        *      is sent out on the USB. The STALL bit takes precedence over
+        *      the NAK bit.
+        * @nptxfemp: Non-Periodic TxFIFO Empty (NPTxFEmp)
+        *      This interrupt is asserted when the Non-Periodic TxFIFO is
+        *      either half or completely empty, and there is space for at least
+        *      one entry to be written to the Non-Periodic Transmit Request
+        *      Queue. The half or completely empty status is determined by
+        *      the Non-Periodic TxFIFO Empty Level bit in the Core AHB
+        *      Configuration register (GAHBCFG.NPTxFEmpLvl).
+        * @rxflvl: RxFIFO Non-Empty (RxFLvl)
+        *      Indicates that there is at least one packet pending to be read
+        *      from the RxFIFO.
+        * @sof: Start of (micro)Frame (Sof)
+        *      In Host mode, the core sets this bit to indicate that an SOF
+        *      (FS), micro-SOF (HS), or Keep-Alive (LS) is transmitted on the
+        *      USB. The application must write a 1 to this bit to clear the
+        *      interrupt.
+        *      In Device mode, in the core sets this bit to indicate that an
+        *      SOF token has been received on the USB. The application can read
+        *      the Device Status register to get the current (micro)frame
+        *      number. This interrupt is seen only when the core is operating
+        *      at either HS or FS.
+        * @otgint: OTG Interrupt (OTGInt)
+        *      The core sets this bit to indicate an OTG protocol event. The
+        *      application must read the OTG Interrupt Status (GOTGINT)
+        *      register to determine the exact event that caused this
+        *      interrupt. The application must clear the appropriate status bit
+        *      in the GOTGINT register to clear this bit.
+        * @modemis: Mode Mismatch Interrupt (ModeMis)
+        *      The core sets this bit when the application is trying to access:
+        *      * A Host mode register, when the core is operating in Device
+        *      mode
+        *      * A Device mode register, when the core is operating in Host
+        *      mode
+        *      The register access is completed on the AHB with an OKAY
+        *      response, but is ignored by the core internally and doesn't
+        *      affect the operation of the core.
+        * @curmod: Current Mode of Operation (CurMod)
+        *      Indicates the current mode of operation.
+        *      * 1'b0: Device mode
+        *      * 1'b1: Host mode
+        */
+       struct cvmx_usbcx_gintsts_s {
+               __BITFIELD_FIELD(u32 wkupint            : 1,
+               __BITFIELD_FIELD(u32 sessreqint         : 1,
+               __BITFIELD_FIELD(u32 disconnint         : 1,
+               __BITFIELD_FIELD(u32 conidstschng       : 1,
+               __BITFIELD_FIELD(u32 reserved_27_27     : 1,
+               __BITFIELD_FIELD(u32 ptxfemp            : 1,
+               __BITFIELD_FIELD(u32 hchint             : 1,
+               __BITFIELD_FIELD(u32 prtint             : 1,
+               __BITFIELD_FIELD(u32 reserved_23_23     : 1,
+               __BITFIELD_FIELD(u32 fetsusp            : 1,
+               __BITFIELD_FIELD(u32 incomplp           : 1,
+               __BITFIELD_FIELD(u32 incompisoin        : 1,
+               __BITFIELD_FIELD(u32 oepint             : 1,
+               __BITFIELD_FIELD(u32 iepint             : 1,
+               __BITFIELD_FIELD(u32 epmis              : 1,
+               __BITFIELD_FIELD(u32 reserved_16_16     : 1,
+               __BITFIELD_FIELD(u32 eopf               : 1,
+               __BITFIELD_FIELD(u32 isooutdrop         : 1,
+               __BITFIELD_FIELD(u32 enumdone           : 1,
+               __BITFIELD_FIELD(u32 usbrst             : 1,
+               __BITFIELD_FIELD(u32 usbsusp            : 1,
+               __BITFIELD_FIELD(u32 erlysusp           : 1,
+               __BITFIELD_FIELD(u32 i2cint             : 1,
+               __BITFIELD_FIELD(u32 ulpickint          : 1,
+               __BITFIELD_FIELD(u32 goutnakeff         : 1,
+               __BITFIELD_FIELD(u32 ginnakeff          : 1,
+               __BITFIELD_FIELD(u32 nptxfemp           : 1,
+               __BITFIELD_FIELD(u32 rxflvl             : 1,
+               __BITFIELD_FIELD(u32 sof                : 1,
+               __BITFIELD_FIELD(u32 otgint             : 1,
+               __BITFIELD_FIELD(u32 modemis            : 1,
+               __BITFIELD_FIELD(u32 curmod             : 1,
+               ;))))))))))))))))))))))))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_gnptxfsiz
+ *
+ * Non-Periodic Transmit FIFO Size Register (GNPTXFSIZ)
+ *
+ * The application can program the RAM size and the memory start address for the
+ * Non-Periodic TxFIFO.
+ */
+union cvmx_usbcx_gnptxfsiz {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_gnptxfsiz_s
+        * @nptxfdep: Non-Periodic TxFIFO Depth (NPTxFDep)
+        *      This value is in terms of 32-bit words.
+        *      Minimum value is 16
+        *      Maximum value is 32768
+        * @nptxfstaddr: Non-Periodic Transmit RAM Start Address (NPTxFStAddr)
+        *      This field contains the memory start address for Non-Periodic
+        *      Transmit FIFO RAM.
+        */
+       struct cvmx_usbcx_gnptxfsiz_s {
+               __BITFIELD_FIELD(u32 nptxfdep           : 16,
+               __BITFIELD_FIELD(u32 nptxfstaddr        : 16,
+               ;))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_gnptxsts
+ *
+ * Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS)
+ *
+ * This read-only register contains the free space information for the
+ * Non-Periodic TxFIFO and the Non-Periodic Transmit Request Queue.
+ */
+union cvmx_usbcx_gnptxsts {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_gnptxsts_s
+        * @nptxqtop: Top of the Non-Periodic Transmit Request Queue (NPTxQTop)
+        *      Entry in the Non-Periodic Tx Request Queue that is currently
+        *      being processed by the MAC.
+        *      * Bits [30:27]: Channel/endpoint number
+        *      * Bits [26:25]:
+        *      - 2'b00: IN/OUT token
+        *      - 2'b01: Zero-length transmit packet (device IN/host OUT)
+        *      - 2'b10: PING/CSPLIT token
+        *      - 2'b11: Channel halt command
+        *      * Bit [24]: Terminate (last entry for selected channel/endpoint)
+        * @nptxqspcavail: Non-Periodic Transmit Request Queue Space Available
+        *      (NPTxQSpcAvail)
+        *      Indicates the amount of free space available in the Non-
+        *      Periodic Transmit Request Queue. This queue holds both IN
+        *      and OUT requests in Host mode. Device mode has only IN
+        *      requests.
+        *      * 8'h0: Non-Periodic Transmit Request Queue is full
+        *      * 8'h1: 1 location available
+        *      * 8'h2: 2 locations available
+        *      * n: n locations available (0..8)
+        *      * Others: Reserved
+        * @nptxfspcavail: Non-Periodic TxFIFO Space Avail (NPTxFSpcAvail)
+        *      Indicates the amount of free space available in the Non-
+        *      Periodic TxFIFO.
+        *      Values are in terms of 32-bit words.
+        *      * 16'h0: Non-Periodic TxFIFO is full
+        *      * 16'h1: 1 word available
+        *      * 16'h2: 2 words available
+        *      * 16'hn: n words available (where 0..32768)
+        *      * 16'h8000: 32768 words available
+        *      * Others: Reserved
+        */
+       struct cvmx_usbcx_gnptxsts_s {
+               __BITFIELD_FIELD(u32 reserved_31_31     : 1,
+               __BITFIELD_FIELD(u32 nptxqtop           : 7,
+               __BITFIELD_FIELD(u32 nptxqspcavail      : 8,
+               __BITFIELD_FIELD(u32 nptxfspcavail      : 16,
+               ;))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_grstctl
+ *
+ * Core Reset Register (GRSTCTL)
+ *
+ * The application uses this register to reset various hardware features inside
+ * the core.
+ */
+union cvmx_usbcx_grstctl {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_grstctl_s
+        * @ahbidle: AHB Master Idle (AHBIdle)
+        *      Indicates that the AHB Master State Machine is in the IDLE
+        *      condition.
+        * @dmareq: DMA Request Signal (DMAReq)
+        *      Indicates that the DMA request is in progress. Used for debug.
+        * @txfnum: TxFIFO Number (TxFNum)
+        *      This is the FIFO number that must be flushed using the TxFIFO
+        *      Flush bit. This field must not be changed until the core clears
+        *      the TxFIFO Flush bit.
+        *      * 5'h0: Non-Periodic TxFIFO flush
+        *      * 5'h1: Periodic TxFIFO 1 flush in Device mode or Periodic
+        *      TxFIFO flush in Host mode
+        *      * 5'h2: Periodic TxFIFO 2 flush in Device mode
+        *      - ...
+        *      * 5'hF: Periodic TxFIFO 15 flush in Device mode
+        *      * 5'h10: Flush all the Periodic and Non-Periodic TxFIFOs in the
+        *      core
+        * @txfflsh: TxFIFO Flush (TxFFlsh)
+        *      This bit selectively flushes a single or all transmit FIFOs, but
+        *      cannot do so if the core is in the midst of a transaction.
+        *      The application must only write this bit after checking that the
+        *      core is neither writing to the TxFIFO nor reading from the
+        *      TxFIFO.
+        *      The application must wait until the core clears this bit before
+        *      performing any operations. This bit takes 8 clocks (of phy_clk
+        *      or hclk, whichever is slower) to clear.
+        * @rxfflsh: RxFIFO Flush (RxFFlsh)
+        *      The application can flush the entire RxFIFO using this bit, but
+        *      must first ensure that the core is not in the middle of a
+        *      transaction.
+        *      The application must only write to this bit after checking that
+        *      the core is neither reading from the RxFIFO nor writing to the
+        *      RxFIFO.
+        *      The application must wait until the bit is cleared before
+        *      performing any other operations. This bit will take 8 clocks
+        *      (slowest of PHY or AHB clock) to clear.
+        * @intknqflsh: IN Token Sequence Learning Queue Flush (INTknQFlsh)
+        *      The application writes this bit to flush the IN Token Sequence
+        *      Learning Queue.
+        * @frmcntrrst: Host Frame Counter Reset (FrmCntrRst)
+        *      The application writes this bit to reset the (micro)frame number
+        *      counter inside the core. When the (micro)frame counter is reset,
+        *      the subsequent SOF sent out by the core will have a
+        *      (micro)frame number of 0.
+        * @hsftrst: HClk Soft Reset (HSftRst)
+        *      The application uses this bit to flush the control logic in the
+        *      AHB Clock domain. Only AHB Clock Domain pipelines are reset.
+        *      * FIFOs are not flushed with this bit.
+        *      * All state machines in the AHB clock domain are reset to the
+        *      Idle state after terminating the transactions on the AHB,
+        *      following the protocol.
+        *      * CSR control bits used by the AHB clock domain state
+        *      machines are cleared.
+        *      * To clear this interrupt, status mask bits that control the
+        *      interrupt status and are generated by the AHB clock domain
+        *      state machine are cleared.
+        *      * Because interrupt status bits are not cleared, the application
+        *      can get the status of any core events that occurred after it set
+        *      this bit.
+        *      This is a self-clearing bit that the core clears after all
+        *      necessary logic is reset in the core. This may take several
+        *      clocks, depending on the core's current state.
+        * @csftrst: Core Soft Reset (CSftRst)
+        *      Resets the hclk and phy_clock domains as follows:
+        *      * Clears the interrupts and all the CSR registers except the
+        *      following register bits:
+        *      - PCGCCTL.RstPdwnModule
+        *      - PCGCCTL.GateHclk
+        *      - PCGCCTL.PwrClmp
+        *      - PCGCCTL.StopPPhyLPwrClkSelclk
+        *      - GUSBCFG.PhyLPwrClkSel
+        *      - GUSBCFG.DDRSel
+        *      - GUSBCFG.PHYSel
+        *      - GUSBCFG.FSIntf
+        *      - GUSBCFG.ULPI_UTMI_Sel
+        *      - GUSBCFG.PHYIf
+        *      - HCFG.FSLSPclkSel
+        *      - DCFG.DevSpd
+        *      * All module state machines (except the AHB Slave Unit) are
+        *      reset to the IDLE state, and all the transmit FIFOs and the
+        *      receive FIFO are flushed.
+        *      * Any transactions on the AHB Master are terminated as soon
+        *      as possible, after gracefully completing the last data phase of
+        *      an AHB transfer. Any transactions on the USB are terminated
+        *      immediately.
+        *      The application can write to this bit any time it wants to reset
+        *      the core. This is a self-clearing bit and the core clears this
+        *      bit after all the necessary logic is reset in the core, which
+        *      may take several clocks, depending on the current state of the
+        *      core. Once this bit is cleared software should wait at least 3
+        *      PHY clocks before doing any access to the PHY domain
+        *      (synchronization delay). Software should also should check that
+        *      bit 31 of this register is 1 (AHB Master is IDLE) before
+        *      starting any operation.
+        *      Typically software reset is used during software development
+        *      and also when you dynamically change the PHY selection bits
+        *      in the USB configuration registers listed above. When you
+        *      change the PHY, the corresponding clock for the PHY is
+        *      selected and used in the PHY domain. Once a new clock is
+        *      selected, the PHY domain has to be reset for proper operation.
+        */
+       struct cvmx_usbcx_grstctl_s {
+               __BITFIELD_FIELD(u32 ahbidle            : 1,
+               __BITFIELD_FIELD(u32 dmareq             : 1,
+               __BITFIELD_FIELD(u32 reserved_11_29     : 19,
+               __BITFIELD_FIELD(u32 txfnum             : 5,
+               __BITFIELD_FIELD(u32 txfflsh            : 1,
+               __BITFIELD_FIELD(u32 rxfflsh            : 1,
+               __BITFIELD_FIELD(u32 intknqflsh         : 1,
+               __BITFIELD_FIELD(u32 frmcntrrst         : 1,
+               __BITFIELD_FIELD(u32 hsftrst            : 1,
+               __BITFIELD_FIELD(u32 csftrst            : 1,
+               ;))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_grxfsiz
+ *
+ * Receive FIFO Size Register (GRXFSIZ)
+ *
+ * The application can program the RAM size that must be allocated to the
+ * RxFIFO.
+ */
+union cvmx_usbcx_grxfsiz {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_grxfsiz_s
+        * @rxfdep: RxFIFO Depth (RxFDep)
+        *      This value is in terms of 32-bit words.
+        *      * Minimum value is 16
+        *      * Maximum value is 32768
+        */
+       struct cvmx_usbcx_grxfsiz_s {
+               __BITFIELD_FIELD(u32 reserved_16_31     : 16,
+               __BITFIELD_FIELD(u32 rxfdep             : 16,
+               ;))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_grxstsph
+ *
+ * Receive Status Read and Pop Register, Host Mode (GRXSTSPH)
+ *
+ * A read to the Receive Status Read and Pop register returns and additionally
+ * pops the top data entry out of the RxFIFO.
+ * This Description is only valid when the core is in Host Mode. For Device Mode
+ * use USBC_GRXSTSPD instead.
+ * NOTE: GRXSTSPH and GRXSTSPD are physically the same register and share the
+ *      same offset in the O2P USB core. The offset difference shown in this
+ *      document is for software clarity and is actually ignored by the
+ *       hardware.
+ */
+union cvmx_usbcx_grxstsph {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_grxstsph_s
+        * @pktsts: Packet Status (PktSts)
+        *      Indicates the status of the received packet
+        *      * 4'b0010: IN data packet received
+        *      * 4'b0011: IN transfer completed (triggers an interrupt)
+        *      * 4'b0101: Data toggle error (triggers an interrupt)
+        *      * 4'b0111: Channel halted (triggers an interrupt)
+        *      * Others: Reserved
+        * @dpid: Data PID (DPID)
+        *      * 2'b00: DATA0
+        *      * 2'b10: DATA1
+        *      * 2'b01: DATA2
+        *      * 2'b11: MDATA
+        * @bcnt: Byte Count (BCnt)
+        *      Indicates the byte count of the received IN data packet
+        * @chnum: Channel Number (ChNum)
+        *      Indicates the channel number to which the current received
+        *      packet belongs.
+        */
+       struct cvmx_usbcx_grxstsph_s {
+               __BITFIELD_FIELD(u32 reserved_21_31     : 11,
+               __BITFIELD_FIELD(u32 pktsts             : 4,
+               __BITFIELD_FIELD(u32 dpid               : 2,
+               __BITFIELD_FIELD(u32 bcnt               : 11,
+               __BITFIELD_FIELD(u32 chnum              : 4,
+               ;)))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_gusbcfg
+ *
+ * Core USB Configuration Register (GUSBCFG)
+ *
+ * This register can be used to configure the core after power-on or a changing
+ * to Host mode or Device mode. It contains USB and USB-PHY related
+ * configuration parameters. The application must program this register before
+ * starting any transactions on either the AHB or the USB. Do not make changes
+ * to this register after the initial programming.
+ */
+union cvmx_usbcx_gusbcfg {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_gusbcfg_s
+        * @otgi2csel: UTMIFS or I2C Interface Select (OtgI2CSel)
+        *      This bit is always 0x0.
+        * @phylpwrclksel: PHY Low-Power Clock Select (PhyLPwrClkSel)
+        *      Software should set this bit to 0x0.
+        *      Selects either 480-MHz or 48-MHz (low-power) PHY mode. In
+        *      FS and LS modes, the PHY can usually operate on a 48-MHz
+        *      clock to save power.
+        *      * 1'b0: 480-MHz Internal PLL clock
+        *      * 1'b1: 48-MHz External Clock
+        *      In 480 MHz mode, the UTMI interface operates at either 60 or
+        *      30-MHz, depending upon whether 8- or 16-bit data width is
+        *      selected. In 48-MHz mode, the UTMI interface operates at 48
+        *      MHz in FS mode and at either 48 or 6 MHz in LS mode
+        *      (depending on the PHY vendor).
+        *      This bit drives the utmi_fsls_low_power core output signal, and
+        *      is valid only for UTMI+ PHYs.
+        * @usbtrdtim: USB Turnaround Time (USBTrdTim)
+        *      Sets the turnaround time in PHY clocks.
+        *      Specifies the response time for a MAC request to the Packet
+        *      FIFO Controller (PFC) to fetch data from the DFIFO (SPRAM).
+        *      This must be programmed to 0x5.
+        * @hnpcap: HNP-Capable (HNPCap)
+        *      This bit is always 0x0.
+        * @srpcap: SRP-Capable (SRPCap)
+        *      This bit is always 0x0.
+        * @ddrsel: ULPI DDR Select (DDRSel)
+        *      Software should set this bit to 0x0.
+        * @physel: USB 2.0 High-Speed PHY or USB 1.1 Full-Speed Serial
+        *      Software should set this bit to 0x0.
+        * @fsintf: Full-Speed Serial Interface Select (FSIntf)
+        *      Software should set this bit to 0x0.
+        * @ulpi_utmi_sel: ULPI or UTMI+ Select (ULPI_UTMI_Sel)
+        *      This bit is always 0x0.
+        * @phyif: PHY Interface (PHYIf)
+        *      This bit is always 0x1.
+        * @toutcal: HS/FS Timeout Calibration (TOutCal)
+        *      The number of PHY clocks that the application programs in this
+        *      field is added to the high-speed/full-speed interpacket timeout
+        *      duration in the core to account for any additional delays
+        *      introduced by the PHY. This may be required, since the delay
+        *      introduced by the PHY in generating the linestate condition may
+        *      vary from one PHY to another.
+        *      The USB standard timeout value for high-speed operation is
+        *      736 to 816 (inclusive) bit times. The USB standard timeout
+        *      value for full-speed operation is 16 to 18 (inclusive) bit
+        *      times. The application must program this field based on the
+        *      speed of enumeration. The number of bit times added per PHY
+        *      clock are:
+        *      High-speed operation:
+        *      * One 30-MHz PHY clock = 16 bit times
+        *      * One 60-MHz PHY clock = 8 bit times
+        *      Full-speed operation:
+        *      * One 30-MHz PHY clock = 0.4 bit times
+        *      * One 60-MHz PHY clock = 0.2 bit times
+        *      * One 48-MHz PHY clock = 0.25 bit times
+        */
+       struct cvmx_usbcx_gusbcfg_s {
+               __BITFIELD_FIELD(u32 reserved_17_31     : 15,
+               __BITFIELD_FIELD(u32 otgi2csel          : 1,
+               __BITFIELD_FIELD(u32 phylpwrclksel      : 1,
+               __BITFIELD_FIELD(u32 reserved_14_14     : 1,
+               __BITFIELD_FIELD(u32 usbtrdtim          : 4,
+               __BITFIELD_FIELD(u32 hnpcap             : 1,
+               __BITFIELD_FIELD(u32 srpcap             : 1,
+               __BITFIELD_FIELD(u32 ddrsel             : 1,
+               __BITFIELD_FIELD(u32 physel             : 1,
+               __BITFIELD_FIELD(u32 fsintf             : 1,
+               __BITFIELD_FIELD(u32 ulpi_utmi_sel      : 1,
+               __BITFIELD_FIELD(u32 phyif              : 1,
+               __BITFIELD_FIELD(u32 toutcal            : 3,
+               ;)))))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_haint
+ *
+ * Host All Channels Interrupt Register (HAINT)
+ *
+ * When a significant event occurs on a channel, the Host All Channels Interrupt
+ * register interrupts the application using the Host Channels Interrupt bit of
+ * the Core Interrupt register (GINTSTS.HChInt). This is shown in Interrupt.
+ * There is one interrupt bit per channel, up to a maximum of 16 bits. Bits in
+ * this register are set and cleared when the application sets and clears bits
+ * in the corresponding Host Channel-n Interrupt register.
+ */
+union cvmx_usbcx_haint {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_haint_s
+        * @haint: Channel Interrupts (HAINT)
+        *      One bit per channel: Bit 0 for Channel 0, bit 15 for Channel 15
+        */
+       struct cvmx_usbcx_haint_s {
+               __BITFIELD_FIELD(u32 reserved_16_31     : 16,
+               __BITFIELD_FIELD(u32 haint              : 16,
+               ;))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_haintmsk
+ *
+ * Host All Channels Interrupt Mask Register (HAINTMSK)
+ *
+ * The Host All Channel Interrupt Mask register works with the Host All Channel
+ * Interrupt register to interrupt the application when an event occurs on a
+ * channel. There is one interrupt mask bit per channel, up to a maximum of 16
+ * bits.
+ * Mask interrupt: 1'b0 Unmask interrupt: 1'b1
+ */
+union cvmx_usbcx_haintmsk {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_haintmsk_s
+        * @haintmsk: Channel Interrupt Mask (HAINTMsk)
+        *      One bit per channel: Bit 0 for channel 0, bit 15 for channel 15
+        */
+       struct cvmx_usbcx_haintmsk_s {
+               __BITFIELD_FIELD(u32 reserved_16_31     : 16,
+               __BITFIELD_FIELD(u32 haintmsk           : 16,
+               ;))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hcchar#
+ *
+ * Host Channel-n Characteristics Register (HCCHAR)
+ *
+ */
+union cvmx_usbcx_hccharx {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hccharx_s
+        * @chena: Channel Enable (ChEna)
+        *      This field is set by the application and cleared by the OTG
+        *      host.
+        *      * 1'b0: Channel disabled
+        *      * 1'b1: Channel enabled
+        * @chdis: Channel Disable (ChDis)
+        *      The application sets this bit to stop transmitting/receiving
+        *      data on a channel, even before the transfer for that channel is
+        *      complete. The application must wait for the Channel Disabled
+        *      interrupt before treating the channel as disabled.
+        * @oddfrm: Odd Frame (OddFrm)
+        *      This field is set (reset) by the application to indicate that
+        *      the OTG host must perform a transfer in an odd (micro)frame.
+        *      This field is applicable for only periodic (isochronous and
+        *      interrupt) transactions.
+        *      * 1'b0: Even (micro)frame
+        *      * 1'b1: Odd (micro)frame
+        * @devaddr: Device Address (DevAddr)
+        *      This field selects the specific device serving as the data
+        *      source or sink.
+        * @ec: Multi Count (MC) / Error Count (EC)
+        *      When the Split Enable bit of the Host Channel-n Split Control
+        *      register (HCSPLTn.SpltEna) is reset (1'b0), this field indicates
+        *      to the host the number of transactions that should be executed
+        *      per microframe for this endpoint.
+        *      * 2'b00: Reserved. This field yields undefined results.
+        *      * 2'b01: 1 transaction
+        *      * 2'b10: 2 transactions to be issued for this endpoint per
+        *      microframe
+        *      * 2'b11: 3 transactions to be issued for this endpoint per
+        *      microframe
+        *      When HCSPLTn.SpltEna is set (1'b1), this field indicates the
+        *      number of immediate retries to be performed for a periodic split
+        *      transactions on transaction errors. This field must be set to at
+        *      least 2'b01.
+        * @eptype: Endpoint Type (EPType)
+        *      Indicates the transfer type selected.
+        *      * 2'b00: Control
+        *      * 2'b01: Isochronous
+        *      * 2'b10: Bulk
+        *      * 2'b11: Interrupt
+        * @lspddev: Low-Speed Device (LSpdDev)
+        *      This field is set by the application to indicate that this
+        *      channel is communicating to a low-speed device.
+        * @epdir: Endpoint Direction (EPDir)
+        *      Indicates whether the transaction is IN or OUT.
+        *      * 1'b0: OUT
+        *      * 1'b1: IN
+        * @epnum: Endpoint Number (EPNum)
+        *      Indicates the endpoint number on the device serving as the
+        *      data source or sink.
+        * @mps: Maximum Packet Size (MPS)
+        *      Indicates the maximum packet size of the associated endpoint.
+        */
+       struct cvmx_usbcx_hccharx_s {
+               __BITFIELD_FIELD(u32 chena              : 1,
+               __BITFIELD_FIELD(u32 chdis              : 1,
+               __BITFIELD_FIELD(u32 oddfrm             : 1,
+               __BITFIELD_FIELD(u32 devaddr            : 7,
+               __BITFIELD_FIELD(u32 ec                 : 2,
+               __BITFIELD_FIELD(u32 eptype             : 2,
+               __BITFIELD_FIELD(u32 lspddev            : 1,
+               __BITFIELD_FIELD(u32 reserved_16_16     : 1,
+               __BITFIELD_FIELD(u32 epdir              : 1,
+               __BITFIELD_FIELD(u32 epnum              : 4,
+               __BITFIELD_FIELD(u32 mps                : 11,
+               ;)))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hcfg
+ *
+ * Host Configuration Register (HCFG)
+ *
+ * This register configures the core after power-on. Do not make changes to this
+ * register after initializing the host.
+ */
+union cvmx_usbcx_hcfg {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hcfg_s
+        * @fslssupp: FS- and LS-Only Support (FSLSSupp)
+        *      The application uses this bit to control the core's enumeration
+        *      speed. Using this bit, the application can make the core
+        *      enumerate as a FS host, even if the connected device supports
+        *      HS traffic. Do not make changes to this field after initial
+        *      programming.
+        *      * 1'b0: HS/FS/LS, based on the maximum speed supported by
+        *      the connected device
+        *      * 1'b1: FS/LS-only, even if the connected device can support HS
+        * @fslspclksel: FS/LS PHY Clock Select (FSLSPclkSel)
+        *      When the core is in FS Host mode
+        *      * 2'b00: PHY clock is running at 30/60 MHz
+        *      * 2'b01: PHY clock is running at 48 MHz
+        *      * Others: Reserved
+        *      When the core is in LS Host mode
+        *      * 2'b00: PHY clock is running at 30/60 MHz. When the
+        *      UTMI+/ULPI PHY Low Power mode is not selected, use
+        *      30/60 MHz.
+        *      * 2'b01: PHY clock is running at 48 MHz. When the UTMI+
+        *      PHY Low Power mode is selected, use 48MHz if the PHY
+        *      supplies a 48 MHz clock during LS mode.
+        *      * 2'b10: PHY clock is running at 6 MHz. In USB 1.1 FS mode,
+        *      use 6 MHz when the UTMI+ PHY Low Power mode is
+        *      selected and the PHY supplies a 6 MHz clock during LS
+        *      mode. If you select a 6 MHz clock during LS mode, you must
+        *      do a soft reset.
+        *      * 2'b11: Reserved
+        */
+       struct cvmx_usbcx_hcfg_s {
+               __BITFIELD_FIELD(u32 reserved_3_31      : 29,
+               __BITFIELD_FIELD(u32 fslssupp           : 1,
+               __BITFIELD_FIELD(u32 fslspclksel        : 2,
+               ;)))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hcint#
+ *
+ * Host Channel-n Interrupt Register (HCINT)
+ *
+ * This register indicates the status of a channel with respect to USB- and
+ * AHB-related events. The application must read this register when the Host
+ * Channels Interrupt bit of the Core Interrupt register (GINTSTS.HChInt) is
+ * set. Before the application can read this register, it must first read
+ * the Host All Channels Interrupt (HAINT) register to get the exact channel
+ * number for the Host Channel-n Interrupt register. The application must clear
+ * the appropriate bit in this register to clear the corresponding bits in the
+ * HAINT and GINTSTS registers.
+ */
+union cvmx_usbcx_hcintx {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hcintx_s
+        * @datatglerr: Data Toggle Error (DataTglErr)
+        * @frmovrun: Frame Overrun (FrmOvrun)
+        * @bblerr: Babble Error (BblErr)
+        * @xacterr: Transaction Error (XactErr)
+        * @nyet: NYET Response Received Interrupt (NYET)
+        * @ack: ACK Response Received Interrupt (ACK)
+        * @nak: NAK Response Received Interrupt (NAK)
+        * @stall: STALL Response Received Interrupt (STALL)
+        * @ahberr: This bit is always 0x0.
+        * @chhltd: Channel Halted (ChHltd)
+        *      Indicates the transfer completed abnormally either because of
+        *      any USB transaction error or in response to disable request by
+        *      the application.
+        * @xfercompl: Transfer Completed (XferCompl)
+        *      Transfer completed normally without any errors.
+        */
+       struct cvmx_usbcx_hcintx_s {
+               __BITFIELD_FIELD(u32 reserved_11_31     : 21,
+               __BITFIELD_FIELD(u32 datatglerr         : 1,
+               __BITFIELD_FIELD(u32 frmovrun           : 1,
+               __BITFIELD_FIELD(u32 bblerr             : 1,
+               __BITFIELD_FIELD(u32 xacterr            : 1,
+               __BITFIELD_FIELD(u32 nyet               : 1,
+               __BITFIELD_FIELD(u32 ack                : 1,
+               __BITFIELD_FIELD(u32 nak                : 1,
+               __BITFIELD_FIELD(u32 stall              : 1,
+               __BITFIELD_FIELD(u32 ahberr             : 1,
+               __BITFIELD_FIELD(u32 chhltd             : 1,
+               __BITFIELD_FIELD(u32 xfercompl          : 1,
+               ;))))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hcintmsk#
+ *
+ * Host Channel-n Interrupt Mask Register (HCINTMSKn)
+ *
+ * This register reflects the mask for each channel status described in the
+ * previous section.
+ * Mask interrupt: 1'b0 Unmask interrupt: 1'b1
+ */
+union cvmx_usbcx_hcintmskx {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hcintmskx_s
+        * @datatglerrmsk: Data Toggle Error Mask (DataTglErrMsk)
+        * @frmovrunmsk: Frame Overrun Mask (FrmOvrunMsk)
+        * @bblerrmsk: Babble Error Mask (BblErrMsk)
+        * @xacterrmsk: Transaction Error Mask (XactErrMsk)
+        * @nyetmsk: NYET Response Received Interrupt Mask (NyetMsk)
+        * @ackmsk: ACK Response Received Interrupt Mask (AckMsk)
+        * @nakmsk: NAK Response Received Interrupt Mask (NakMsk)
+        * @stallmsk: STALL Response Received Interrupt Mask (StallMsk)
+        * @ahberrmsk: AHB Error Mask (AHBErrMsk)
+        * @chhltdmsk: Channel Halted Mask (ChHltdMsk)
+        * @xfercomplmsk: Transfer Completed Mask (XferComplMsk)
+        */
+       struct cvmx_usbcx_hcintmskx_s {
+               __BITFIELD_FIELD(u32 reserved_11_31             : 21,
+               __BITFIELD_FIELD(u32 datatglerrmsk              : 1,
+               __BITFIELD_FIELD(u32 frmovrunmsk                : 1,
+               __BITFIELD_FIELD(u32 bblerrmsk                  : 1,
+               __BITFIELD_FIELD(u32 xacterrmsk                 : 1,
+               __BITFIELD_FIELD(u32 nyetmsk                    : 1,
+               __BITFIELD_FIELD(u32 ackmsk                     : 1,
+               __BITFIELD_FIELD(u32 nakmsk                     : 1,
+               __BITFIELD_FIELD(u32 stallmsk                   : 1,
+               __BITFIELD_FIELD(u32 ahberrmsk                  : 1,
+               __BITFIELD_FIELD(u32 chhltdmsk                  : 1,
+               __BITFIELD_FIELD(u32 xfercomplmsk               : 1,
+               ;))))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hcsplt#
+ *
+ * Host Channel-n Split Control Register (HCSPLT)
+ *
+ */
+union cvmx_usbcx_hcspltx {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hcspltx_s
+        * @spltena: Split Enable (SpltEna)
+        *      The application sets this field to indicate that this channel is
+        *      enabled to perform split transactions.
+        * @compsplt: Do Complete Split (CompSplt)
+        *      The application sets this field to request the OTG host to
+        *      perform a complete split transaction.
+        * @xactpos: Transaction Position (XactPos)
+        *      This field is used to determine whether to send all, first,
+        *      middle, or last payloads with each OUT transaction.
+        *      * 2'b11: All. This is the entire data payload is of this
+        *      transaction (which is less than or equal to 188 bytes).
+        *      * 2'b10: Begin. This is the first data payload of this
+        *      transaction (which is larger than 188 bytes).
+        *      * 2'b00: Mid. This is the middle payload of this transaction
+        *      (which is larger than 188 bytes).
+        *      * 2'b01: End. This is the last payload of this transaction
+        *      (which is larger than 188 bytes).
+        * @hubaddr: Hub Address (HubAddr)
+        *      This field holds the device address of the transaction
+        *      translator's hub.
+        * @prtaddr: Port Address (PrtAddr)
+        *      This field is the port number of the recipient transaction
+        *      translator.
+        */
+       struct cvmx_usbcx_hcspltx_s {
+               __BITFIELD_FIELD(u32 spltena                    : 1,
+               __BITFIELD_FIELD(u32 reserved_17_30             : 14,
+               __BITFIELD_FIELD(u32 compsplt                   : 1,
+               __BITFIELD_FIELD(u32 xactpos                    : 2,
+               __BITFIELD_FIELD(u32 hubaddr                    : 7,
+               __BITFIELD_FIELD(u32 prtaddr                    : 7,
+               ;))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hctsiz#
+ *
+ * Host Channel-n Transfer Size Register (HCTSIZ)
+ *
+ */
+union cvmx_usbcx_hctsizx {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hctsizx_s
+        * @dopng: Do Ping (DoPng)
+        *      Setting this field to 1 directs the host to do PING protocol.
+        * @pid: PID (Pid)
+        *      The application programs this field with the type of PID to use
+        *      for the initial transaction. The host will maintain this field
+        *      for the rest of the transfer.
+        *      * 2'b00: DATA0
+        *      * 2'b01: DATA2
+        *      * 2'b10: DATA1
+        *      * 2'b11: MDATA (non-control)/SETUP (control)
+        * @pktcnt: Packet Count (PktCnt)
+        *      This field is programmed by the application with the expected
+        *      number of packets to be transmitted (OUT) or received (IN).
+        *      The host decrements this count on every successful
+        *      transmission or reception of an OUT/IN packet. Once this count
+        *      reaches zero, the application is interrupted to indicate normal
+        *      completion.
+        * @xfersize: Transfer Size (XferSize)
+        *      For an OUT, this field is the number of data bytes the host will
+        *      send during the transfer.
+        *      For an IN, this field is the buffer size that the application
+        *      has reserved for the transfer. The application is expected to
+        *      program this field as an integer multiple of the maximum packet
+        *      size for IN transactions (periodic and non-periodic).
+        */
+       struct cvmx_usbcx_hctsizx_s {
+               __BITFIELD_FIELD(u32 dopng              : 1,
+               __BITFIELD_FIELD(u32 pid                : 2,
+               __BITFIELD_FIELD(u32 pktcnt             : 10,
+               __BITFIELD_FIELD(u32 xfersize           : 19,
+               ;))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hfir
+ *
+ * Host Frame Interval Register (HFIR)
+ *
+ * This register stores the frame interval information for the current speed to
+ * which the O2P USB core has enumerated.
+ */
+union cvmx_usbcx_hfir {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hfir_s
+        * @frint: Frame Interval (FrInt)
+        *      The value that the application programs to this field specifies
+        *      the interval between two consecutive SOFs (FS) or micro-
+        *      SOFs (HS) or Keep-Alive tokens (HS). This field contains the
+        *      number of PHY clocks that constitute the required frame
+        *      interval. The default value set in this field for a FS operation
+        *      when the PHY clock frequency is 60 MHz. The application can
+        *      write a value to this register only after the Port Enable bit of
+        *      the Host Port Control and Status register (HPRT.PrtEnaPort)
+        *      has been set. If no value is programmed, the core calculates
+        *      the value based on the PHY clock specified in the FS/LS PHY
+        *      Clock Select field of the Host Configuration register
+        *      (HCFG.FSLSPclkSel). Do not change the value of this field
+        *      after the initial configuration.
+        *      * 125 us (PHY clock frequency for HS)
+        *      * 1 ms (PHY clock frequency for FS/LS)
+        */
+       struct cvmx_usbcx_hfir_s {
+               __BITFIELD_FIELD(u32 reserved_16_31             : 16,
+               __BITFIELD_FIELD(u32 frint                      : 16,
+               ;))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hfnum
+ *
+ * Host Frame Number/Frame Time Remaining Register (HFNUM)
+ *
+ * This register indicates the current frame number.
+ * It also indicates the time remaining (in terms of the number of PHY clocks)
+ * in the current (micro)frame.
+ */
+union cvmx_usbcx_hfnum {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hfnum_s
+        * @frrem: Frame Time Remaining (FrRem)
+        *      Indicates the amount of time remaining in the current
+        *      microframe (HS) or frame (FS/LS), in terms of PHY clocks.
+        *      This field decrements on each PHY clock. When it reaches
+        *      zero, this field is reloaded with the value in the Frame
+        *      Interval register and a new SOF is transmitted on the USB.
+        * @frnum: Frame Number (FrNum)
+        *      This field increments when a new SOF is transmitted on the
+        *      USB, and is reset to 0 when it reaches 16'h3FFF.
+        */
+       struct cvmx_usbcx_hfnum_s {
+               __BITFIELD_FIELD(u32 frrem              : 16,
+               __BITFIELD_FIELD(u32 frnum              : 16,
+               ;))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hprt
+ *
+ * Host Port Control and Status Register (HPRT)
+ *
+ * This register is available in both Host and Device modes.
+ * Currently, the OTG Host supports only one port.
+ * A single register holds USB port-related information such as USB reset,
+ * enable, suspend, resume, connect status, and test mode for each port. The
+ * R_SS_WC bits in this register can trigger an interrupt to the application
+ * through the Host Port Interrupt bit of the Core Interrupt register
+ * (GINTSTS.PrtInt). On a Port Interrupt, the application must read this
+ * register and clear the bit that caused the interrupt. For the R_SS_WC bits,
+ * the application must write a 1 to the bit to clear the interrupt.
+ */
+union cvmx_usbcx_hprt {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hprt_s
+        * @prtspd: Port Speed (PrtSpd)
+        *      Indicates the speed of the device attached to this port.
+        *      * 2'b00: High speed
+        *      * 2'b01: Full speed
+        *      * 2'b10: Low speed
+        *      * 2'b11: Reserved
+        * @prttstctl: Port Test Control (PrtTstCtl)
+        *      The application writes a nonzero value to this field to put
+        *      the port into a Test mode, and the corresponding pattern is
+        *      signaled on the port.
+        *      * 4'b0000: Test mode disabled
+        *      * 4'b0001: Test_J mode
+        *      * 4'b0010: Test_K mode
+        *      * 4'b0011: Test_SE0_NAK mode
+        *      * 4'b0100: Test_Packet mode
+        *      * 4'b0101: Test_Force_Enable
+        *      * Others: Reserved
+        *      PrtSpd must be zero (i.e. the interface must be in high-speed
+        *      mode) to use the PrtTstCtl test modes.
+        * @prtpwr: Port Power (PrtPwr)
+        *      The application uses this field to control power to this port,
+        *      and the core clears this bit on an overcurrent condition.
+        *      * 1'b0: Power off
+        *      * 1'b1: Power on
+        * @prtlnsts: Port Line Status (PrtLnSts)
+        *      Indicates the current logic level USB data lines
+        *      * Bit [10]: Logic level of D-
+        *      * Bit [11]: Logic level of D+
+        * @prtrst: Port Reset (PrtRst)
+        *      When the application sets this bit, a reset sequence is
+        *      started on this port. The application must time the reset
+        *      period and clear this bit after the reset sequence is
+        *      complete.
+        *      * 1'b0: Port not in reset
+        *      * 1'b1: Port in reset
+        *      The application must leave this bit set for at least a
+        *      minimum duration mentioned below to start a reset on the
+        *      port. The application can leave it set for another 10 ms in
+        *      addition to the required minimum duration, before clearing
+        *      the bit, even though there is no maximum limit set by the
+        *      USB standard.
+        *      * High speed: 50 ms
+        *      * Full speed/Low speed: 10 ms
+        * @prtsusp: Port Suspend (PrtSusp)
+        *      The application sets this bit to put this port in Suspend
+        *      mode. The core only stops sending SOFs when this is set.
+        *      To stop the PHY clock, the application must set the Port
+        *      Clock Stop bit, which will assert the suspend input pin of
+        *      the PHY.
+        *      The read value of this bit reflects the current suspend
+        *      status of the port. This bit is cleared by the core after a
+        *      remote wakeup signal is detected or the application sets
+        *      the Port Reset bit or Port Resume bit in this register or the
+        *      Resume/Remote Wakeup Detected Interrupt bit or
+        *      Disconnect Detected Interrupt bit in the Core Interrupt
+        *      register (GINTSTS.WkUpInt or GINTSTS.DisconnInt,
+        *      respectively).
+        *      * 1'b0: Port not in Suspend mode
+        *      * 1'b1: Port in Suspend mode
+        * @prtres: Port Resume (PrtRes)
+        *      The application sets this bit to drive resume signaling on
+        *      the port. The core continues to drive the resume signal
+        *      until the application clears this bit.
+        *      If the core detects a USB remote wakeup sequence, as
+        *      indicated by the Port Resume/Remote Wakeup Detected
+        *      Interrupt bit of the Core Interrupt register
+        *      (GINTSTS.WkUpInt), the core starts driving resume
+        *      signaling without application intervention and clears this bit
+        *      when it detects a disconnect condition. The read value of
+        *      this bit indicates whether the core is currently driving
+        *      resume signaling.
+        *      * 1'b0: No resume driven
+        *      * 1'b1: Resume driven
+        * @prtovrcurrchng: Port Overcurrent Change (PrtOvrCurrChng)
+        *      The core sets this bit when the status of the Port
+        *      Overcurrent Active bit (bit 4) in this register changes.
+        * @prtovrcurract: Port Overcurrent Active (PrtOvrCurrAct)
+        *      Indicates the overcurrent condition of the port.
+        *      * 1'b0: No overcurrent condition
+        *      * 1'b1: Overcurrent condition
+        * @prtenchng: Port Enable/Disable Change (PrtEnChng)
+        *      The core sets this bit when the status of the Port Enable bit
+        *      [2] of this register changes.
+        * @prtena: Port Enable (PrtEna)
+        *      A port is enabled only by the core after a reset sequence,
+        *      and is disabled by an overcurrent condition, a disconnect
+        *      condition, or by the application clearing this bit. The
+        *      application cannot set this bit by a register write. It can only
+        *      clear it to disable the port. This bit does not trigger any
+        *      interrupt to the application.
+        *      * 1'b0: Port disabled
+        *      * 1'b1: Port enabled
+        * @prtconndet: Port Connect Detected (PrtConnDet)
+        *      The core sets this bit when a device connection is detected
+        *      to trigger an interrupt to the application using the Host Port
+        *      Interrupt bit of the Core Interrupt register (GINTSTS.PrtInt).
+        *      The application must write a 1 to this bit to clear the
+        *      interrupt.
+        * @prtconnsts: Port Connect Status (PrtConnSts)
+        *      * 0: No device is attached to the port.
+        *      * 1: A device is attached to the port.
+        */
+       struct cvmx_usbcx_hprt_s {
+               __BITFIELD_FIELD(u32 reserved_19_31     : 13,
+               __BITFIELD_FIELD(u32 prtspd             : 2,
+               __BITFIELD_FIELD(u32 prttstctl          : 4,
+               __BITFIELD_FIELD(u32 prtpwr             : 1,
+               __BITFIELD_FIELD(u32 prtlnsts           : 2,
+               __BITFIELD_FIELD(u32 reserved_9_9       : 1,
+               __BITFIELD_FIELD(u32 prtrst             : 1,
+               __BITFIELD_FIELD(u32 prtsusp            : 1,
+               __BITFIELD_FIELD(u32 prtres             : 1,
+               __BITFIELD_FIELD(u32 prtovrcurrchng     : 1,
+               __BITFIELD_FIELD(u32 prtovrcurract      : 1,
+               __BITFIELD_FIELD(u32 prtenchng          : 1,
+               __BITFIELD_FIELD(u32 prtena             : 1,
+               __BITFIELD_FIELD(u32 prtconndet         : 1,
+               __BITFIELD_FIELD(u32 prtconnsts         : 1,
+               ;)))))))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hptxfsiz
+ *
+ * Host Periodic Transmit FIFO Size Register (HPTXFSIZ)
+ *
+ * This register holds the size and the memory start address of the Periodic
+ * TxFIFO, as shown in Figures 310 and 311.
+ */
+union cvmx_usbcx_hptxfsiz {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hptxfsiz_s
+        * @ptxfsize: Host Periodic TxFIFO Depth (PTxFSize)
+        *      This value is in terms of 32-bit words.
+        *      * Minimum value is 16
+        *      * Maximum value is 32768
+        * @ptxfstaddr: Host Periodic TxFIFO Start Address (PTxFStAddr)
+        */
+       struct cvmx_usbcx_hptxfsiz_s {
+               __BITFIELD_FIELD(u32 ptxfsize   : 16,
+               __BITFIELD_FIELD(u32 ptxfstaddr : 16,
+               ;))
+       } s;
+};
+
+/**
+ * cvmx_usbc#_hptxsts
+ *
+ * Host Periodic Transmit FIFO/Queue Status Register (HPTXSTS)
+ *
+ * This read-only register contains the free space information for the Periodic
+ * TxFIFO and the Periodic Transmit Request Queue
+ */
+union cvmx_usbcx_hptxsts {
+       u32 u32;
+       /**
+        * struct cvmx_usbcx_hptxsts_s
+        * @ptxqtop: Top of the Periodic Transmit Request Queue (PTxQTop)
+        *      This indicates the entry in the Periodic Tx Request Queue that
+        *      is currently being processes by the MAC.
+        *      This register is used for debugging.
+        *      * Bit [31]: Odd/Even (micro)frame
+        *      - 1'b0: send in even (micro)frame
+        *      - 1'b1: send in odd (micro)frame
+        *      * Bits [30:27]: Channel/endpoint number
+        *      * Bits [26:25]: Type
+        *      - 2'b00: IN/OUT
+        *      - 2'b01: Zero-length packet
+        *      - 2'b10: CSPLIT
+        *      - 2'b11: Disable channel command
+        *      * Bit [24]: Terminate (last entry for the selected
+        *      channel/endpoint)
+        * @ptxqspcavail: Periodic Transmit Request Queue Space Available
+        *      (PTxQSpcAvail)
+        *      Indicates the number of free locations available to be written
+        *      in the Periodic Transmit Request Queue. This queue holds both
+        *      IN and OUT requests.
+        *      * 8'h0: Periodic Transmit Request Queue is full
+        *      * 8'h1: 1 location available
+        *      * 8'h2: 2 locations available
+        *      * n: n locations available (0..8)
+        *      * Others: Reserved
+        * @ptxfspcavail: Periodic Transmit Data FIFO Space Available
+        *                (PTxFSpcAvail)
+        *      Indicates the number of free locations available to be written
+        *      to in the Periodic TxFIFO.
+        *      Values are in terms of 32-bit words
+        *      * 16'h0: Periodic TxFIFO is full
+        *      * 16'h1: 1 word available
+        *      * 16'h2: 2 words available
+        *      * 16'hn: n words available (where 0..32768)
+        *      * 16'h8000: 32768 words available
+        *      * Others: Reserved
+        */
+       struct cvmx_usbcx_hptxsts_s {
+               __BITFIELD_FIELD(u32 ptxqtop            : 8,
+               __BITFIELD_FIELD(u32 ptxqspcavail       : 8,
+               __BITFIELD_FIELD(u32 ptxfspcavail       : 16,
+               ;)))
+       } s;
+};
+
+/**
+ * cvmx_usbn#_clk_ctl
+ *
+ * USBN_CLK_CTL = USBN's Clock Control
+ *
+ * This register is used to control the frequency of the hclk and the
+ * hreset and phy_rst signals.
+ */
+union cvmx_usbnx_clk_ctl {
+       u64 u64;
+       /**
+        * struct cvmx_usbnx_clk_ctl_s
+        * @divide2: The 'hclk' used by the USB subsystem is derived
+        *      from the eclk.
+        *      Also see the field DIVIDE. DIVIDE2<1> must currently
+        *      be zero because it is not implemented, so the maximum
+        *      ratio of eclk/hclk is currently 16.
+        *      The actual divide number for hclk is:
+        *      (DIVIDE2 + 1) * (DIVIDE + 1)
+        * @hclk_rst: When this field is '0' the HCLK-DIVIDER used to
+        *      generate the hclk in the USB Subsystem is held
+        *      in reset. This bit must be set to '0' before
+        *      changing the value os DIVIDE in this register.
+        *      The reset to the HCLK_DIVIDERis also asserted
+        *      when core reset is asserted.
+        * @p_x_on: Force USB-PHY on during suspend.
+        *      '1' USB-PHY XO block is powered-down during
+        *      suspend.
+        *      '0' USB-PHY XO block is powered-up during
+        *      suspend.
+        *      The value of this field must be set while POR is
+        *      active.
+        * @p_rtype: PHY reference clock type
+        *      On CN50XX/CN52XX/CN56XX the values are:
+        *              '0' The USB-PHY uses a 12MHz crystal as a clock source
+        *                  at the USB_XO and USB_XI pins.
+        *              '1' Reserved.
+        *              '2' The USB_PHY uses 12/24/48MHz 2.5V board clock at the
+        *                  USB_XO pin. USB_XI should be tied to ground in this
+        *                  case.
+        *              '3' Reserved.
+        *      On CN3xxx bits 14 and 15 are p_xenbn and p_rclk and values are:
+        *              '0' Reserved.
+        *              '1' Reserved.
+        *              '2' The PHY PLL uses the XO block output as a reference.
+        *                  The XO block uses an external clock supplied on the
+        *                  XO pin. USB_XI should be tied to ground for this
+        *                  usage.
+        *              '3' The XO block uses the clock from a crystal.
+        * @p_com_on: '0' Force USB-PHY XO Bias, Bandgap and PLL to
+        *      remain powered in Suspend Mode.
+        *      '1' The USB-PHY XO Bias, Bandgap and PLL are
+        *      powered down in suspend mode.
+        *      The value of this field must be set while POR is
+        *      active.
+        * @p_c_sel: Phy clock speed select.
+        *      Selects the reference clock / crystal frequency.
+        *      '11': Reserved
+        *      '10': 48 MHz (reserved when a crystal is used)
+        *      '01': 24 MHz (reserved when a crystal is used)
+        *      '00': 12 MHz
+        *      The value of this field must be set while POR is
+        *      active.
+        *      NOTE: if a crystal is used as a reference clock,
+        *      this field must be set to 12 MHz.
+        * @cdiv_byp: Used to enable the bypass input to the USB_CLK_DIV.
+        * @sd_mode: Scaledown mode for the USBC. Control timing events
+        *      in the USBC, for normal operation this must be '0'.
+        * @s_bist: Starts bist on the hclk memories, during the '0'
+        *      to '1' transition.
+        * @por: Power On Reset for the PHY.
+        *      Resets all the PHYS registers and state machines.
+        * @enable: When '1' allows the generation of the hclk. When
+        *      '0' the hclk will not be generated. SEE DIVIDE
+        *      field of this register.
+        * @prst: When this field is '0' the reset associated with
+        *      the phy_clk functionality in the USB Subsystem is
+        *      help in reset. This bit should not be set to '1'
+        *      until the time it takes 6 clocks (hclk or phy_clk,
+        *      whichever is slower) has passed. Under normal
+        *      operation once this bit is set to '1' it should not
+        *      be set to '0'.
+        * @hrst: When this field is '0' the reset associated with
+        *      the hclk functioanlity in the USB Subsystem is
+        *      held in reset.This bit should not be set to '1'
+        *      until 12ms after phy_clk is stable. Under normal
+        *      operation, once this bit is set to '1' it should
+        *      not be set to '0'.
+        * @divide: The frequency of 'hclk' used by the USB subsystem
+        *      is the eclk frequency divided by the value of
+        *      (DIVIDE2 + 1) * (DIVIDE + 1), also see the field
+        *      DIVIDE2 of this register.
+        *      The hclk frequency should be less than 125Mhz.
+        *      After writing a value to this field the SW should
+        *      read the field for the value written.
+        *      The ENABLE field of this register should not be set
+        *      until AFTER this field is set and then read.
+        */
+       struct cvmx_usbnx_clk_ctl_s {
+               __BITFIELD_FIELD(u64 reserved_20_63     : 44,
+               __BITFIELD_FIELD(u64 divide2            : 2,
+               __BITFIELD_FIELD(u64 hclk_rst           : 1,
+               __BITFIELD_FIELD(u64 p_x_on             : 1,
+               __BITFIELD_FIELD(u64 p_rtype            : 2,
+               __BITFIELD_FIELD(u64 p_com_on           : 1,
+               __BITFIELD_FIELD(u64 p_c_sel            : 2,
+               __BITFIELD_FIELD(u64 cdiv_byp           : 1,
+               __BITFIELD_FIELD(u64 sd_mode            : 2,
+               __BITFIELD_FIELD(u64 s_bist             : 1,
+               __BITFIELD_FIELD(u64 por                : 1,
+               __BITFIELD_FIELD(u64 enable             : 1,
+               __BITFIELD_FIELD(u64 prst               : 1,
+               __BITFIELD_FIELD(u64 hrst               : 1,
+               __BITFIELD_FIELD(u64 divide             : 3,
+               ;)))))))))))))))
+       } s;
+};
+
+/**
+ * cvmx_usbn#_usbp_ctl_status
+ *
+ * USBN_USBP_CTL_STATUS = USBP Control And Status Register
+ *
+ * Contains general control and status information for the USBN block.
+ */
+union cvmx_usbnx_usbp_ctl_status {
+       u64 u64;
+       /**
+        * struct cvmx_usbnx_usbp_ctl_status_s
+        * @txrisetune: HS Transmitter Rise/Fall Time Adjustment
+        * @txvreftune: HS DC Voltage Level Adjustment
+        * @txfslstune: FS/LS Source Impedance Adjustment
+        * @txhsxvtune: Transmitter High-Speed Crossover Adjustment
+        * @sqrxtune: Squelch Threshold Adjustment
+        * @compdistune: Disconnect Threshold Adjustment
+        * @otgtune: VBUS Valid Threshold Adjustment
+        * @otgdisable: OTG Block Disable
+        * @portreset: Per_Port Reset
+        * @drvvbus: Drive VBUS
+        * @lsbist: Low-Speed BIST Enable.
+        * @fsbist: Full-Speed BIST Enable.
+        * @hsbist: High-Speed BIST Enable.
+        * @bist_done: PHY Bist Done.
+        *      Asserted at the end of the PHY BIST sequence.
+        * @bist_err: PHY Bist Error.
+        *      Indicates an internal error was detected during
+        *      the BIST sequence.
+        * @tdata_out: PHY Test Data Out.
+        *      Presents either internally generated signals or
+        *      test register contents, based upon the value of
+        *      test_data_out_sel.
+        * @siddq: Drives the USBP (USB-PHY) SIDDQ input.
+        *      Normally should be set to zero.
+        *      When customers have no intent to use USB PHY
+        *      interface, they should:
+        *      - still provide 3.3V to USB_VDD33, and
+        *      - tie USB_REXT to 3.3V supply, and
+        *      - set USBN*_USBP_CTL_STATUS[SIDDQ]=1
+        * @txpreemphasistune: HS Transmitter Pre-Emphasis Enable
+        * @dma_bmode: When set to 1 the L2C DMA address will be updated
+        *      with byte-counts between packets. When set to 0
+        *      the L2C DMA address is incremented to the next
+        *      4-byte aligned address after adding byte-count.
+        * @usbc_end: Bigendian input to the USB Core. This should be
+        *      set to '0' for operation.
+        * @usbp_bist: PHY, This is cleared '0' to run BIST on the USBP.
+        * @tclk: PHY Test Clock, used to load TDATA_IN to the USBP.
+        * @dp_pulld: PHY DP_PULLDOWN input to the USB-PHY.
+        *      This signal enables the pull-down resistance on
+        *      the D+ line. '1' pull down-resistance is connected
+        *      to D+/ '0' pull down resistance is not connected
+        *      to D+. When an A/B device is acting as a host
+        *      (downstream-facing port), dp_pulldown and
+        *      dm_pulldown are enabled. This must not toggle
+        *      during normal operation.
+        * @dm_pulld: PHY DM_PULLDOWN input to the USB-PHY.
+        *      This signal enables the pull-down resistance on
+        *      the D- line. '1' pull down-resistance is connected
+        *      to D-. '0' pull down resistance is not connected
+        *      to D-. When an A/B device is acting as a host
+        *      (downstream-facing port), dp_pulldown and
+        *      dm_pulldown are enabled. This must not toggle
+        *      during normal operation.
+        * @hst_mode: When '0' the USB is acting as HOST, when '1'
+        *      USB is acting as device. This field needs to be
+        *      set while the USB is in reset.
+        * @tuning: Transmitter Tuning for High-Speed Operation.
+        *      Tunes the current supply and rise/fall output
+        *      times for high-speed operation.
+        *      [20:19] == 11: Current supply increased
+        *      approximately 9%
+        *      [20:19] == 10: Current supply increased
+        *      approximately 4.5%
+        *      [20:19] == 01: Design default.
+        *      [20:19] == 00: Current supply decreased
+        *      approximately 4.5%
+        *      [22:21] == 11: Rise and fall times are increased.
+        *      [22:21] == 10: Design default.
+        *      [22:21] == 01: Rise and fall times are decreased.
+        *      [22:21] == 00: Rise and fall times are decreased
+        *      further as compared to the 01 setting.
+        * @tx_bs_enh: Transmit Bit Stuffing on [15:8].
+        *      Enables or disables bit stuffing on data[15:8]
+        *      when bit-stuffing is enabled.
+        * @tx_bs_en: Transmit Bit Stuffing on [7:0].
+        *      Enables or disables bit stuffing on data[7:0]
+        *      when bit-stuffing is enabled.
+        * @loop_enb: PHY Loopback Test Enable.
+        *      '1': During data transmission the receive is
+        *      enabled.
+        *      '0': During data transmission the receive is
+        *      disabled.
+        *      Must be '0' for normal operation.
+        * @vtest_enb: Analog Test Pin Enable.
+        *      '1' The PHY's analog_test pin is enabled for the
+        *      input and output of applicable analog test signals.
+        *      '0' THe analog_test pin is disabled.
+        * @bist_enb: Built-In Self Test Enable.
+        *      Used to activate BIST in the PHY.
+        * @tdata_sel: Test Data Out Select.
+        *      '1' test_data_out[3:0] (PHY) register contents
+        *      are output. '0' internally generated signals are
+        *      output.
+        * @taddr_in: Mode Address for Test Interface.
+        *      Specifies the register address for writing to or
+        *      reading from the PHY test interface register.
+        * @tdata_in: Internal Testing Register Input Data and Select
+        *      This is a test bus. Data is present on [3:0],
+        *      and its corresponding select (enable) is present
+        *      on bits [7:4].
+        * @ate_reset: Reset input from automatic test equipment.
+        *      This is a test signal. When the USB Core is
+        *      powered up (not in Susned Mode), an automatic
+        *      tester can use this to disable phy_clock and
+        *      free_clk, then re-enable them with an aligned
+        *      phase.
+        *      '1': The phy_clk and free_clk outputs are
+        *      disabled. "0": The phy_clock and free_clk outputs
+        *      are available within a specific period after the
+        *      de-assertion.
+        */
+       struct cvmx_usbnx_usbp_ctl_status_s {
+               __BITFIELD_FIELD(u64 txrisetune         : 1,
+               __BITFIELD_FIELD(u64 txvreftune         : 4,
+               __BITFIELD_FIELD(u64 txfslstune         : 4,
+               __BITFIELD_FIELD(u64 txhsxvtune         : 2,
+               __BITFIELD_FIELD(u64 sqrxtune           : 3,
+               __BITFIELD_FIELD(u64 compdistune        : 3,
+               __BITFIELD_FIELD(u64 otgtune            : 3,
+               __BITFIELD_FIELD(u64 otgdisable         : 1,
+               __BITFIELD_FIELD(u64 portreset          : 1,
+               __BITFIELD_FIELD(u64 drvvbus            : 1,
+               __BITFIELD_FIELD(u64 lsbist             : 1,
+               __BITFIELD_FIELD(u64 fsbist             : 1,
+               __BITFIELD_FIELD(u64 hsbist             : 1,
+               __BITFIELD_FIELD(u64 bist_done          : 1,
+               __BITFIELD_FIELD(u64 bist_err           : 1,
+               __BITFIELD_FIELD(u64 tdata_out          : 4,
+               __BITFIELD_FIELD(u64 siddq              : 1,
+               __BITFIELD_FIELD(u64 txpreemphasistune  : 1,
+               __BITFIELD_FIELD(u64 dma_bmode          : 1,
+               __BITFIELD_FIELD(u64 usbc_end           : 1,
+               __BITFIELD_FIELD(u64 usbp_bist          : 1,
+               __BITFIELD_FIELD(u64 tclk               : 1,
+               __BITFIELD_FIELD(u64 dp_pulld           : 1,
+               __BITFIELD_FIELD(u64 dm_pulld           : 1,
+               __BITFIELD_FIELD(u64 hst_mode           : 1,
+               __BITFIELD_FIELD(u64 tuning             : 4,
+               __BITFIELD_FIELD(u64 tx_bs_enh          : 1,
+               __BITFIELD_FIELD(u64 tx_bs_en           : 1,
+               __BITFIELD_FIELD(u64 loop_enb           : 1,
+               __BITFIELD_FIELD(u64 vtest_enb          : 1,
+               __BITFIELD_FIELD(u64 bist_enb           : 1,
+               __BITFIELD_FIELD(u64 tdata_sel          : 1,
+               __BITFIELD_FIELD(u64 taddr_in           : 4,
+               __BITFIELD_FIELD(u64 tdata_in           : 8,
+               __BITFIELD_FIELD(u64 ate_reset          : 1,
+               ;)))))))))))))))))))))))))))))))))))
+       } s;
+};
+
+#endif /* __OCTEON_HCD_H__ */
diff --git a/drivers/staging/octeon/Kconfig b/drivers/staging/octeon/Kconfig
new file mode 100644 (file)
index 0000000..5319909
--- /dev/null
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+config OCTEON_ETHERNET
+       tristate "Cavium Networks Octeon Ethernet support"
+       depends on CAVIUM_OCTEON_SOC || COMPILE_TEST
+       depends on NETDEVICES
+       select PHYLIB
+       select MDIO_OCTEON
+       help
+         This driver supports the builtin ethernet ports on Cavium
+         Networks' products in the Octeon family. This driver supports the
+         CN3XXX and CN5XXX Octeon processors.
+
+         To compile this driver as a module, choose M here.  The module
+         will be called octeon-ethernet.
+
diff --git a/drivers/staging/octeon/Makefile b/drivers/staging/octeon/Makefile
new file mode 100644 (file)
index 0000000..3887cf5
--- /dev/null
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (C) 2005-2009 Cavium Networks
+#
+
+#
+# Makefile for Cavium OCTEON on-board ethernet driver
+#
+
+obj-${CONFIG_OCTEON_ETHERNET} :=  octeon-ethernet.o
+
+octeon-ethernet-y := ethernet.o
+octeon-ethernet-y += ethernet-mdio.o
+octeon-ethernet-y += ethernet-mem.o
+octeon-ethernet-y += ethernet-rgmii.o
+octeon-ethernet-y += ethernet-rx.o
+octeon-ethernet-y += ethernet-sgmii.o
+octeon-ethernet-y += ethernet-spi.o
+octeon-ethernet-y += ethernet-tx.o
diff --git a/drivers/staging/octeon/TODO b/drivers/staging/octeon/TODO
new file mode 100644 (file)
index 0000000..67a0a1f
--- /dev/null
@@ -0,0 +1,9 @@
+This driver is functional and supports Ethernet on OCTEON+/OCTEON2/OCTEON3
+chips at least up to CN7030.
+
+TODO:
+       - general code review and clean up
+       - make driver self-contained instead of being split between staging and
+         arch/mips/cavium-octeon.
+
+Contact: Aaro Koskinen <aaro.koskinen@iki.fi>
diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h
new file mode 100644 (file)
index 0000000..ef9e767
--- /dev/null
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+/*
+ * A few defines are used to control the operation of this driver:
+ *  USE_ASYNC_IOBDMA
+ *      Use asynchronous IO access to hardware. This uses Octeon's asynchronous
+ *      IOBDMAs to issue IO accesses without stalling. Set this to zero
+ *      to disable this. Note that IOBDMAs require CVMSEG.
+ *  REUSE_SKBUFFS_WITHOUT_FREE
+ *      Allows the TX path to free an skbuff into the FPA hardware pool. This
+ *      can significantly improve performance for forwarding and bridging, but
+ *      may be somewhat dangerous. Checks are made, but if any buffer is reused
+ *      without the proper Linux cleanup, the networking stack may have very
+ *      bizarre bugs.
+ */
+#ifndef __ETHERNET_DEFINES_H__
+#define __ETHERNET_DEFINES_H__
+
+#ifdef CONFIG_NETFILTER
+#define REUSE_SKBUFFS_WITHOUT_FREE  0
+#else
+#define REUSE_SKBUFFS_WITHOUT_FREE  1
+#endif
+
+#define USE_ASYNC_IOBDMA            (CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE > 0)
+
+/* Maximum number of SKBs to try to free per xmit packet. */
+#define MAX_OUT_QUEUE_DEPTH 1000
+
+#define FAU_TOTAL_TX_TO_CLEAN (CVMX_FAU_REG_END - sizeof(u32))
+#define FAU_NUM_PACKET_BUFFERS_TO_FREE (FAU_TOTAL_TX_TO_CLEAN - sizeof(u32))
+
+#define TOTAL_NUMBER_OF_PORTS       (CVMX_PIP_NUM_INPUT_PORTS + 1)
+
+#endif /* __ETHERNET_DEFINES_H__ */
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
new file mode 100644 (file)
index 0000000..c798672
--- /dev/null
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+#include <linux/ratelimit.h>
+#include <linux/of_mdio.h>
+#include <generated/utsrelease.h>
+#include <net/dst.h>
+
+#include "octeon-ethernet.h"
+#include "ethernet-defines.h"
+#include "ethernet-mdio.h"
+#include "ethernet-util.h"
+
+static void cvm_oct_get_drvinfo(struct net_device *dev,
+                               struct ethtool_drvinfo *info)
+{
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, UTS_RELEASE, sizeof(info->version));
+       strlcpy(info->bus_info, "Builtin", sizeof(info->bus_info));
+}
+
+static int cvm_oct_nway_reset(struct net_device *dev)
+{
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (dev->phydev)
+               return phy_start_aneg(dev->phydev);
+
+       return -EINVAL;
+}
+
+const struct ethtool_ops cvm_oct_ethtool_ops = {
+       .get_drvinfo = cvm_oct_get_drvinfo,
+       .nway_reset = cvm_oct_nway_reset,
+       .get_link = ethtool_op_get_link,
+       .get_link_ksettings = phy_ethtool_get_link_ksettings,
+       .set_link_ksettings = phy_ethtool_set_link_ksettings,
+};
+
+/**
+ * cvm_oct_ioctl - IOCTL support for PHY control
+ * @dev:    Device to change
+ * @rq:     the request
+ * @cmd:    the command
+ *
+ * Returns Zero on success
+ */
+int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       if (!dev->phydev)
+               return -EINVAL;
+
+       return phy_mii_ioctl(dev->phydev, rq, cmd);
+}
+
+void cvm_oct_note_carrier(struct octeon_ethernet *priv,
+                         union cvmx_helper_link_info li)
+{
+       if (li.s.link_up) {
+               pr_notice_ratelimited("%s: %u Mbps %s duplex, port %d, queue %d\n",
+                                     netdev_name(priv->netdev), li.s.speed,
+                                     (li.s.full_duplex) ? "Full" : "Half",
+                                     priv->port, priv->queue);
+       } else {
+               pr_notice_ratelimited("%s: Link down\n",
+                                     netdev_name(priv->netdev));
+       }
+}
+
+void cvm_oct_adjust_link(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       union cvmx_helper_link_info link_info;
+
+       link_info.u64           = 0;
+       link_info.s.link_up     = dev->phydev->link ? 1 : 0;
+       link_info.s.full_duplex = dev->phydev->duplex ? 1 : 0;
+       link_info.s.speed       = dev->phydev->speed;
+       priv->link_info         = link_info.u64;
+
+       /*
+        * The polling task need to know about link status changes.
+        */
+       if (priv->poll)
+               priv->poll(dev);
+
+       if (priv->last_link != dev->phydev->link) {
+               priv->last_link = dev->phydev->link;
+               cvmx_helper_link_set(priv->port, link_info);
+               cvm_oct_note_carrier(priv, link_info);
+       }
+}
+
+int cvm_oct_common_stop(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       int interface = INTERFACE(priv->port);
+       union cvmx_helper_link_info link_info;
+       union cvmx_gmxx_prtx_cfg gmx_cfg;
+       int index = INDEX(priv->port);
+
+       gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
+       gmx_cfg.s.en = 0;
+       cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
+
+       priv->poll = NULL;
+
+       if (dev->phydev)
+               phy_disconnect(dev->phydev);
+
+       if (priv->last_link) {
+               link_info.u64 = 0;
+               priv->last_link = 0;
+
+               cvmx_helper_link_set(priv->port, link_info);
+               cvm_oct_note_carrier(priv, link_info);
+       }
+       return 0;
+}
+
+/**
+ * cvm_oct_phy_setup_device - setup the PHY
+ *
+ * @dev:    Device to setup
+ *
+ * Returns Zero on success, negative on failure
+ */
+int cvm_oct_phy_setup_device(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       struct device_node *phy_node;
+       struct phy_device *phydev = NULL;
+
+       if (!priv->of_node)
+               goto no_phy;
+
+       phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0);
+       if (!phy_node && of_phy_is_fixed_link(priv->of_node)) {
+               int rc;
+
+               rc = of_phy_register_fixed_link(priv->of_node);
+               if (rc)
+                       return rc;
+
+               phy_node = of_node_get(priv->of_node);
+       }
+       if (!phy_node)
+               goto no_phy;
+
+       phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0,
+                               priv->phy_mode);
+       of_node_put(phy_node);
+
+       if (!phydev)
+               return -ENODEV;
+
+       priv->last_link = 0;
+       phy_start(phydev);
+
+       return 0;
+no_phy:
+       /* If there is no phy, assume a direct MAC connection and that
+        * the link is up.
+        */
+       netif_carrier_on(dev);
+       return 0;
+}
diff --git a/drivers/staging/octeon/ethernet-mdio.h b/drivers/staging/octeon/ethernet-mdio.h
new file mode 100644 (file)
index 0000000..e3771d4
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/string.h>
+#include <linux/ethtool.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <net/dst.h>
+#ifdef CONFIG_XFRM
+#include <linux/xfrm.h>
+#include <net/xfrm.h>
+#endif /* CONFIG_XFRM */
+
+extern const struct ethtool_ops cvm_oct_ethtool_ops;
+
+void octeon_mdiobus_force_mod_depencency(void);
+
+int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+int cvm_oct_phy_setup_device(struct net_device *dev);
diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c
new file mode 100644 (file)
index 0000000..5325949
--- /dev/null
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2010 Cavium Networks
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/slab.h>
+
+#include "octeon-ethernet.h"
+#include "ethernet-mem.h"
+#include "ethernet-defines.h"
+
+/**
+ * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs
+ * @pool:     Pool to allocate an skbuff for
+ * @size:     Size of the buffer needed for the pool
+ * @elements: Number of buffers to allocate
+ *
+ * Returns the actual number of buffers allocated.
+ */
+static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
+{
+       int freed = elements;
+
+       while (freed) {
+               struct sk_buff *skb = dev_alloc_skb(size + 256);
+
+               if (unlikely(!skb))
+                       break;
+               skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
+               *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
+               cvmx_fpa_free(skb->data, pool, size / 128);
+               freed--;
+       }
+       return elements - freed;
+}
+
+/**
+ * cvm_oct_free_hw_skbuff- free hardware pool skbuffs
+ * @pool:     Pool to allocate an skbuff for
+ * @size:     Size of the buffer needed for the pool
+ * @elements: Number of buffers to allocate
+ */
+static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
+{
+       char *memory;
+
+       do {
+               memory = cvmx_fpa_alloc(pool);
+               if (memory) {
+                       struct sk_buff *skb =
+                           *(struct sk_buff **)(memory - sizeof(void *));
+                       elements--;
+                       dev_kfree_skb(skb);
+               }
+       } while (memory);
+
+       if (elements < 0)
+               pr_warn("Freeing of pool %u had too many skbuffs (%d)\n",
+                       pool, elements);
+       else if (elements > 0)
+               pr_warn("Freeing of pool %u is missing %d skbuffs\n",
+                       pool, elements);
+}
+
+/**
+ * cvm_oct_fill_hw_memory - fill a hardware pool with memory.
+ * @pool:     Pool to populate
+ * @size:     Size of each buffer in the pool
+ * @elements: Number of buffers to allocate
+ *
+ * Returns the actual number of buffers allocated.
+ */
+static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
+{
+       char *memory;
+       char *fpa;
+       int freed = elements;
+
+       while (freed) {
+               /*
+                * FPA memory must be 128 byte aligned.  Since we are
+                * aligning we need to save the original pointer so we
+                * can feed it to kfree when the memory is returned to
+                * the kernel.
+                *
+                * We allocate an extra 256 bytes to allow for
+                * alignment and space for the original pointer saved
+                * just before the block.
+                */
+               memory = kmalloc(size + 256, GFP_ATOMIC);
+               if (unlikely(!memory)) {
+                       pr_warn("Unable to allocate %u bytes for FPA pool %d\n",
+                               elements * size, pool);
+                       break;
+               }
+               fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
+               *((char **)fpa - 1) = memory;
+               cvmx_fpa_free(fpa, pool, 0);
+               freed--;
+       }
+       return elements - freed;
+}
+
+/**
+ * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory
+ * @pool:     FPA pool to free
+ * @size:     Size of each buffer in the pool
+ * @elements: Number of buffers that should be in the pool
+ */
+static void cvm_oct_free_hw_memory(int pool, int size, int elements)
+{
+       char *memory;
+       char *fpa;
+
+       do {
+               fpa = cvmx_fpa_alloc(pool);
+               if (fpa) {
+                       elements--;
+                       fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa));
+                       memory = *((char **)fpa - 1);
+                       kfree(memory);
+               }
+       } while (fpa);
+
+       if (elements < 0)
+               pr_warn("Freeing of pool %u had too many buffers (%d)\n",
+                       pool, elements);
+       else if (elements > 0)
+               pr_warn("Warning: Freeing of pool %u is missing %d buffers\n",
+                       pool, elements);
+}
+
+int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
+{
+       int freed;
+
+       if (pool == CVMX_FPA_PACKET_POOL)
+               freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
+       else
+               freed = cvm_oct_fill_hw_memory(pool, size, elements);
+       return freed;
+}
+
+void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
+{
+       if (pool == CVMX_FPA_PACKET_POOL)
+               cvm_oct_free_hw_skbuff(pool, size, elements);
+       else
+               cvm_oct_free_hw_memory(pool, size, elements);
+}
diff --git a/drivers/staging/octeon/ethernet-mem.h b/drivers/staging/octeon/ethernet-mem.h
new file mode 100644 (file)
index 0000000..692dcdb
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+int cvm_oct_mem_fill_fpa(int pool, int size, int elements);
+void cvm_oct_mem_empty_fpa(int pool, int size, int elements);
diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c
new file mode 100644 (file)
index 0000000..0c4fac3
--- /dev/null
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+#include <linux/ratelimit.h>
+#include <net/dst.h>
+
+#include "octeon-ethernet.h"
+#include "ethernet-defines.h"
+#include "ethernet-util.h"
+#include "ethernet-mdio.h"
+
+static DEFINE_SPINLOCK(global_register_lock);
+
+static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable)
+{
+       union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
+       union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
+       union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
+       int interface = INTERFACE(priv->port);
+       int index = INDEX(priv->port);
+
+       /* Set preamble checking. */
+       gmxx_rxx_frm_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index,
+                                                                  interface));
+       gmxx_rxx_frm_ctl.s.pre_chk = enable;
+       cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface),
+                      gmxx_rxx_frm_ctl.u64);
+
+       /* Set FCS stripping. */
+       ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
+       if (enable)
+               ipd_sub_port_fcs.s.port_bit |= 1ull << priv->port;
+       else
+               ipd_sub_port_fcs.s.port_bit &=
+                                       0xffffffffull ^ (1ull << priv->port);
+       cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
+
+       /* Clear any error bits. */
+       gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index,
+                                                                  interface));
+       cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
+                      gmxx_rxx_int_reg.u64);
+}
+
+static void cvm_oct_check_preamble_errors(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       union cvmx_helper_link_info link_info;
+       unsigned long flags;
+
+       link_info.u64 = priv->link_info;
+
+       /*
+        * Take the global register lock since we are going to
+        * touch registers that affect more than one port.
+        */
+       spin_lock_irqsave(&global_register_lock, flags);
+
+       if (link_info.s.speed == 10 && priv->last_speed == 10) {
+               /*
+                * Read the GMXX_RXX_INT_REG[PCTERR] bit and see if we are
+                * getting preamble errors.
+                */
+               int interface = INTERFACE(priv->port);
+               int index = INDEX(priv->port);
+               union cvmx_gmxx_rxx_int_reg gmxx_rxx_int_reg;
+
+               gmxx_rxx_int_reg.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_REG
+                                                       (index, interface));
+               if (gmxx_rxx_int_reg.s.pcterr) {
+                       /*
+                        * We are getting preamble errors at 10Mbps. Most
+                        * likely the PHY is giving us packets with misaligned
+                        * preambles. In order to get these packets we need to
+                        * disable preamble checking and do it in software.
+                        */
+                       cvm_oct_set_hw_preamble(priv, false);
+                       printk_ratelimited("%s: Using 10Mbps with software preamble removal\n",
+                                          dev->name);
+               }
+       } else {
+               /*
+                * Since the 10Mbps preamble workaround is allowed we need to
+                * enable preamble checking, FCS stripping, and clear error
+                * bits on every speed change. If errors occur during 10Mbps
+                * operation the above code will change this stuff
+                */
+               if (priv->last_speed != link_info.s.speed)
+                       cvm_oct_set_hw_preamble(priv, true);
+               priv->last_speed = link_info.s.speed;
+       }
+       spin_unlock_irqrestore(&global_register_lock, flags);
+}
+
+static void cvm_oct_rgmii_poll(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       union cvmx_helper_link_info link_info;
+       bool status_change;
+
+       link_info = cvmx_helper_link_get(priv->port);
+       if (priv->link_info != link_info.u64 &&
+           cvmx_helper_link_set(priv->port, link_info))
+               link_info.u64 = priv->link_info;
+       status_change = priv->link_info != link_info.u64;
+       priv->link_info = link_info.u64;
+
+       cvm_oct_check_preamble_errors(dev);
+
+       if (likely(!status_change))
+               return;
+
+       /* Tell core. */
+       if (link_info.s.link_up) {
+               if (!netif_carrier_ok(dev))
+                       netif_carrier_on(dev);
+       } else if (netif_carrier_ok(dev)) {
+               netif_carrier_off(dev);
+       }
+       cvm_oct_note_carrier(priv, link_info);
+}
+
+int cvm_oct_rgmii_open(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       int ret;
+
+       ret = cvm_oct_common_open(dev, cvm_oct_rgmii_poll);
+       if (ret)
+               return ret;
+
+       if (dev->phydev) {
+               /*
+                * In phydev mode, we need still periodic polling for the
+                * preamble error checking, and we also need to call this
+                * function on every link state change.
+                *
+                * Only true RGMII ports need to be polled. In GMII mode, port
+                * 0 is really a RGMII port.
+                */
+               if ((priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII &&
+                    priv->port  == 0) ||
+                   (priv->imode == CVMX_HELPER_INTERFACE_MODE_RGMII)) {
+                       priv->poll = cvm_oct_check_preamble_errors;
+                       cvm_oct_check_preamble_errors(dev);
+               }
+       }
+
+       return 0;
+}
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
new file mode 100644 (file)
index 0000000..2c16230
--- /dev/null
@@ -0,0 +1,538 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2010 Cavium Networks
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/cache.h>
+#include <linux/cpumask.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/string.h>
+#include <linux/prefetch.h>
+#include <linux/ratelimit.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <net/dst.h>
+#ifdef CONFIG_XFRM
+#include <linux/xfrm.h>
+#include <net/xfrm.h>
+#endif /* CONFIG_XFRM */
+
+#include "octeon-ethernet.h"
+#include "ethernet-defines.h"
+#include "ethernet-mem.h"
+#include "ethernet-rx.h"
+#include "ethernet-util.h"
+
+static atomic_t oct_rx_ready = ATOMIC_INIT(0);
+
+static struct oct_rx_group {
+       int irq;
+       int group;
+       struct napi_struct napi;
+} oct_rx_group[16];
+
+/**
+ * cvm_oct_do_interrupt - interrupt handler.
+ * @irq: Interrupt number.
+ * @napi_id: Cookie to identify the NAPI instance.
+ *
+ * The interrupt occurs whenever the POW has packets in our group.
+ *
+ */
+static irqreturn_t cvm_oct_do_interrupt(int irq, void *napi_id)
+{
+       /* Disable the IRQ and start napi_poll. */
+       disable_irq_nosync(irq);
+       napi_schedule(napi_id);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * cvm_oct_check_rcv_error - process receive errors
+ * @work: Work queue entry pointing to the packet.
+ *
+ * Returns Non-zero if the packet can be dropped, zero otherwise.
+ */
+static inline int cvm_oct_check_rcv_error(struct cvmx_wqe *work)
+{
+       int port;
+
+       if (octeon_has_feature(OCTEON_FEATURE_PKND))
+               port = work->word0.pip.cn68xx.pknd;
+       else
+               port = work->word1.cn38xx.ipprt;
+
+       if ((work->word2.snoip.err_code == 10) && (work->word1.len <= 64)) {
+               /*
+                * Ignore length errors on min size packets. Some
+                * equipment incorrectly pads packets to 64+4FCS
+                * instead of 60+4FCS.  Note these packets still get
+                * counted as frame errors.
+                */
+       } else if (work->word2.snoip.err_code == 5 ||
+                  work->word2.snoip.err_code == 7) {
+               /*
+                * We received a packet with either an alignment error
+                * or a FCS error. This may be signalling that we are
+                * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK]
+                * off. If this is the case we need to parse the
+                * packet to determine if we can remove a non spec
+                * preamble and generate a correct packet.
+                */
+               int interface = cvmx_helper_get_interface_num(port);
+               int index = cvmx_helper_get_interface_index_num(port);
+               union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
+
+               gmxx_rxx_frm_ctl.u64 =
+                   cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
+               if (gmxx_rxx_frm_ctl.s.pre_chk == 0) {
+                       u8 *ptr =
+                           cvmx_phys_to_ptr(work->packet_ptr.s.addr);
+                       int i = 0;
+
+                       while (i < work->word1.len - 1) {
+                               if (*ptr != 0x55)
+                                       break;
+                               ptr++;
+                               i++;
+                       }
+
+                       if (*ptr == 0xd5) {
+                               /* Port received 0xd5 preamble */
+                               work->packet_ptr.s.addr += i + 1;
+                               work->word1.len -= i + 5;
+                       } else if ((*ptr & 0xf) == 0xd) {
+                               /* Port received 0xd preamble */
+                               work->packet_ptr.s.addr += i;
+                               work->word1.len -= i + 4;
+                               for (i = 0; i < work->word1.len; i++) {
+                                       *ptr =
+                                           ((*ptr & 0xf0) >> 4) |
+                                           ((*(ptr + 1) & 0xf) << 4);
+                                       ptr++;
+                               }
+                       } else {
+                               printk_ratelimited("Port %d unknown preamble, packet dropped\n",
+                                                  port);
+                               cvm_oct_free_work(work);
+                               return 1;
+                       }
+               }
+       } else {
+               printk_ratelimited("Port %d receive error code %d, packet dropped\n",
+                                  port, work->word2.snoip.err_code);
+               cvm_oct_free_work(work);
+               return 1;
+       }
+
+       return 0;
+}
+
+static void copy_segments_to_skb(struct cvmx_wqe *work, struct sk_buff *skb)
+{
+       int segments = work->word2.s.bufs;
+       union cvmx_buf_ptr segment_ptr = work->packet_ptr;
+       int len = work->word1.len;
+       int segment_size;
+
+       while (segments--) {
+               union cvmx_buf_ptr next_ptr;
+
+               next_ptr = *(union cvmx_buf_ptr *)
+                       cvmx_phys_to_ptr(segment_ptr.s.addr - 8);
+
+               /*
+                * Octeon Errata PKI-100: The segment size is wrong.
+                *
+                * Until it is fixed, calculate the segment size based on
+                * the packet pool buffer size.
+                * When it is fixed, the following line should be replaced
+                * with this one:
+                * int segment_size = segment_ptr.s.size;
+                */
+               segment_size =
+                       CVMX_FPA_PACKET_POOL_SIZE -
+                       (segment_ptr.s.addr -
+                        (((segment_ptr.s.addr >> 7) -
+                          segment_ptr.s.back) << 7));
+
+               /* Don't copy more than what is left in the packet */
+               if (segment_size > len)
+                       segment_size = len;
+
+               /* Copy the data into the packet */
+               skb_put_data(skb, cvmx_phys_to_ptr(segment_ptr.s.addr),
+                            segment_size);
+               len -= segment_size;
+               segment_ptr = next_ptr;
+       }
+}
+
+static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget)
+{
+       const int       coreid = cvmx_get_core_num();
+       u64     old_group_mask;
+       u64     old_scratch;
+       int             rx_count = 0;
+       int             did_work_request = 0;
+       int             packet_not_copied;
+
+       /* Prefetch cvm_oct_device since we know we need it soon */
+       prefetch(cvm_oct_device);
+
+       if (USE_ASYNC_IOBDMA) {
+               /* Save scratch in case userspace is using it */
+               CVMX_SYNCIOBDMA;
+               old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+       }
+
+       /* Only allow work for our group (and preserve priorities) */
+       if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
+               old_group_mask = cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid));
+               cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid),
+                              BIT(rx_group->group));
+               cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */
+       } else {
+               old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid));
+               cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid),
+                              (old_group_mask & ~0xFFFFull) |
+                              BIT(rx_group->group));
+       }
+
+       if (USE_ASYNC_IOBDMA) {
+               cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT);
+               did_work_request = 1;
+       }
+
+       while (rx_count < budget) {
+               struct sk_buff *skb = NULL;
+               struct sk_buff **pskb = NULL;
+               int skb_in_hw;
+               struct cvmx_wqe *work;
+               int port;
+
+               if (USE_ASYNC_IOBDMA && did_work_request)
+                       work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH);
+               else
+                       work = cvmx_pow_work_request_sync(CVMX_POW_NO_WAIT);
+
+               prefetch(work);
+               did_work_request = 0;
+               if (!work) {
+                       if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
+                               cvmx_write_csr(CVMX_SSO_WQ_IQ_DIS,
+                                              BIT(rx_group->group));
+                               cvmx_write_csr(CVMX_SSO_WQ_INT,
+                                              BIT(rx_group->group));
+                       } else {
+                               union cvmx_pow_wq_int wq_int;
+
+                               wq_int.u64 = 0;
+                               wq_int.s.iq_dis = BIT(rx_group->group);
+                               wq_int.s.wq_int = BIT(rx_group->group);
+                               cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64);
+                       }
+                       break;
+               }
+               pskb = (struct sk_buff **)
+                       (cvm_oct_get_buffer_ptr(work->packet_ptr) -
+                       sizeof(void *));
+               prefetch(pskb);
+
+               if (USE_ASYNC_IOBDMA && rx_count < (budget - 1)) {
+                       cvmx_pow_work_request_async_nocheck(CVMX_SCR_SCRATCH,
+                                                           CVMX_POW_NO_WAIT);
+                       did_work_request = 1;
+               }
+               rx_count++;
+
+               skb_in_hw = work->word2.s.bufs == 1;
+               if (likely(skb_in_hw)) {
+                       skb = *pskb;
+                       prefetch(&skb->head);
+                       prefetch(&skb->len);
+               }
+
+               if (octeon_has_feature(OCTEON_FEATURE_PKND))
+                       port = work->word0.pip.cn68xx.pknd;
+               else
+                       port = work->word1.cn38xx.ipprt;
+
+               prefetch(cvm_oct_device[port]);
+
+               /* Immediately throw away all packets with receive errors */
+               if (unlikely(work->word2.snoip.rcv_error)) {
+                       if (cvm_oct_check_rcv_error(work))
+                               continue;
+               }
+
+               /*
+                * We can only use the zero copy path if skbuffs are
+                * in the FPA pool and the packet fits in a single
+                * buffer.
+                */
+               if (likely(skb_in_hw)) {
+                       skb->data = skb->head + work->packet_ptr.s.addr -
+                               cvmx_ptr_to_phys(skb->head);
+                       prefetch(skb->data);
+                       skb->len = work->word1.len;
+                       skb_set_tail_pointer(skb, skb->len);
+                       packet_not_copied = 1;
+               } else {
+                       /*
+                        * We have to copy the packet. First allocate
+                        * an skbuff for it.
+                        */
+                       skb = dev_alloc_skb(work->word1.len);
+                       if (!skb) {
+                               cvm_oct_free_work(work);
+                               continue;
+                       }
+
+                       /*
+                        * Check if we've received a packet that was
+                        * entirely stored in the work entry.
+                        */
+                       if (unlikely(work->word2.s.bufs == 0)) {
+                               u8 *ptr = work->packet_data;
+
+                               if (likely(!work->word2.s.not_IP)) {
+                                       /*
+                                        * The beginning of the packet
+                                        * moves for IP packets.
+                                        */
+                                       if (work->word2.s.is_v6)
+                                               ptr += 2;
+                                       else
+                                               ptr += 6;
+                               }
+                               skb_put_data(skb, ptr, work->word1.len);
+                               /* No packet buffers to free */
+                       } else {
+                               copy_segments_to_skb(work, skb);
+                       }
+                       packet_not_copied = 0;
+               }
+               if (likely((port < TOTAL_NUMBER_OF_PORTS) &&
+                          cvm_oct_device[port])) {
+                       struct net_device *dev = cvm_oct_device[port];
+
+                       /*
+                        * Only accept packets for devices that are
+                        * currently up.
+                        */
+                       if (likely(dev->flags & IFF_UP)) {
+                               skb->protocol = eth_type_trans(skb, dev);
+                               skb->dev = dev;
+
+                               if (unlikely(work->word2.s.not_IP ||
+                                            work->word2.s.IP_exc ||
+                                            work->word2.s.L4_error ||
+                                            !work->word2.s.tcp_or_udp))
+                                       skb->ip_summed = CHECKSUM_NONE;
+                               else
+                                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+                               /* Increment RX stats for virtual ports */
+                               if (port >= CVMX_PIP_NUM_INPUT_PORTS) {
+                                       dev->stats.rx_packets++;
+                                       dev->stats.rx_bytes += skb->len;
+                               }
+                               netif_receive_skb(skb);
+                       } else {
+                               /*
+                                * Drop any packet received for a device that
+                                * isn't up.
+                                */
+                               dev->stats.rx_dropped++;
+                               dev_kfree_skb_irq(skb);
+                       }
+               } else {
+                       /*
+                        * Drop any packet received for a device that
+                        * doesn't exist.
+                        */
+                       printk_ratelimited("Port %d not controlled by Linux, packet dropped\n",
+                                          port);
+                       dev_kfree_skb_irq(skb);
+               }
+               /*
+                * Check to see if the skbuff and work share the same
+                * packet buffer.
+                */
+               if (likely(packet_not_copied)) {
+                       /*
+                        * This buffer needs to be replaced, increment
+                        * the number of buffers we need to free by
+                        * one.
+                        */
+                       cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE,
+                                             1);
+
+                       cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, 1);
+               } else {
+                       cvm_oct_free_work(work);
+               }
+       }
+       /* Restore the original POW group mask */
+       if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
+               cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), old_group_mask);
+               cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */
+       } else {
+               cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask);
+       }
+
+       if (USE_ASYNC_IOBDMA) {
+               /* Restore the scratch area */
+               cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
+       }
+       cvm_oct_rx_refill_pool(0);
+
+       return rx_count;
+}
+
+/**
+ * cvm_oct_napi_poll - the NAPI poll function.
+ * @napi: The NAPI instance.
+ * @budget: Maximum number of packets to receive.
+ *
+ * Returns the number of packets processed.
+ */
+static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
+{
+       struct oct_rx_group *rx_group = container_of(napi, struct oct_rx_group,
+                                                    napi);
+       int rx_count;
+
+       rx_count = cvm_oct_poll(rx_group, budget);
+
+       if (rx_count < budget) {
+               /* No more work */
+               napi_complete_done(napi, rx_count);
+               enable_irq(rx_group->irq);
+       }
+       return rx_count;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * cvm_oct_poll_controller - poll for receive packets
+ * device.
+ *
+ * @dev:    Device to poll. Unused
+ */
+void cvm_oct_poll_controller(struct net_device *dev)
+{
+       int i;
+
+       if (!atomic_read(&oct_rx_ready))
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(oct_rx_group); i++) {
+               if (!(pow_receive_groups & BIT(i)))
+                       continue;
+
+               cvm_oct_poll(&oct_rx_group[i], 16);
+       }
+}
+#endif
+
+void cvm_oct_rx_initialize(void)
+{
+       int i;
+       struct net_device *dev_for_napi = NULL;
+
+       for (i = 0; i < TOTAL_NUMBER_OF_PORTS; i++) {
+               if (cvm_oct_device[i]) {
+                       dev_for_napi = cvm_oct_device[i];
+                       break;
+               }
+       }
+
+       if (!dev_for_napi)
+               panic("No net_devices were allocated.");
+
+       for (i = 0; i < ARRAY_SIZE(oct_rx_group); i++) {
+               int ret;
+
+               if (!(pow_receive_groups & BIT(i)))
+                       continue;
+
+               netif_napi_add(dev_for_napi, &oct_rx_group[i].napi,
+                              cvm_oct_napi_poll, rx_napi_weight);
+               napi_enable(&oct_rx_group[i].napi);
+
+               oct_rx_group[i].irq = OCTEON_IRQ_WORKQ0 + i;
+               oct_rx_group[i].group = i;
+
+               /* Register an IRQ handler to receive POW interrupts */
+               ret = request_irq(oct_rx_group[i].irq, cvm_oct_do_interrupt, 0,
+                                 "Ethernet", &oct_rx_group[i].napi);
+               if (ret)
+                       panic("Could not acquire Ethernet IRQ %d\n",
+                             oct_rx_group[i].irq);
+
+               disable_irq_nosync(oct_rx_group[i].irq);
+
+               /* Enable POW interrupt when our port has at least one packet */
+               if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
+                       union cvmx_sso_wq_int_thrx int_thr;
+                       union cvmx_pow_wq_int_pc int_pc;
+
+                       int_thr.u64 = 0;
+                       int_thr.s.tc_en = 1;
+                       int_thr.s.tc_thr = 1;
+                       cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(i), int_thr.u64);
+
+                       int_pc.u64 = 0;
+                       int_pc.s.pc_thr = 5;
+                       cvmx_write_csr(CVMX_SSO_WQ_INT_PC, int_pc.u64);
+               } else {
+                       union cvmx_pow_wq_int_thrx int_thr;
+                       union cvmx_pow_wq_int_pc int_pc;
+
+                       int_thr.u64 = 0;
+                       int_thr.s.tc_en = 1;
+                       int_thr.s.tc_thr = 1;
+                       cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), int_thr.u64);
+
+                       int_pc.u64 = 0;
+                       int_pc.s.pc_thr = 5;
+                       cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64);
+               }
+
+               /* Schedule NAPI now. This will indirectly enable the
+                * interrupt.
+                */
+               napi_schedule(&oct_rx_group[i].napi);
+       }
+       atomic_inc(&oct_rx_ready);
+}
+
+void cvm_oct_rx_shutdown(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(oct_rx_group); i++) {
+               if (!(pow_receive_groups & BIT(i)))
+                       continue;
+
+               /* Disable POW interrupt */
+               if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+                       cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(i), 0);
+               else
+                       cvmx_write_csr(CVMX_POW_WQ_INT_THRX(i), 0);
+
+               /* Free the interrupt handler */
+               free_irq(oct_rx_group[i].irq, cvm_oct_device);
+
+               netif_napi_del(&oct_rx_group[i].napi);
+       }
+}
diff --git a/drivers/staging/octeon/ethernet-rx.h b/drivers/staging/octeon/ethernet-rx.h
new file mode 100644 (file)
index 0000000..ff6482f
--- /dev/null
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+void cvm_oct_poll_controller(struct net_device *dev);
+void cvm_oct_rx_initialize(void);
+void cvm_oct_rx_shutdown(void);
+
+static inline void cvm_oct_rx_refill_pool(int fill_threshold)
+{
+       int number_to_free;
+       int num_freed;
+       /* Refill the packet buffer pool */
+       number_to_free =
+               cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
+
+       if (number_to_free > fill_threshold) {
+               cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE,
+                                     -number_to_free);
+               num_freed = cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL,
+                                                CVMX_FPA_PACKET_POOL_SIZE,
+                                                number_to_free);
+               if (num_freed != number_to_free) {
+                       cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE,
+                                             number_to_free - num_freed);
+               }
+       }
+}
diff --git a/drivers/staging/octeon/ethernet-sgmii.c b/drivers/staging/octeon/ethernet-sgmii.c
new file mode 100644 (file)
index 0000000..d7fbd91
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+#include <linux/phy.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/ratelimit.h>
+#include <net/dst.h>
+
+#include "octeon-ethernet.h"
+#include "ethernet-defines.h"
+#include "ethernet-util.h"
+#include "ethernet-mdio.h"
+
+int cvm_oct_sgmii_open(struct net_device *dev)
+{
+       return cvm_oct_common_open(dev, cvm_oct_link_poll);
+}
+
+int cvm_oct_sgmii_init(struct net_device *dev)
+{
+       cvm_oct_common_init(dev);
+
+       /* FIXME: Need autoneg logic */
+       return 0;
+}
diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c
new file mode 100644 (file)
index 0000000..c582403
--- /dev/null
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <net/dst.h>
+
+#include "octeon-ethernet.h"
+#include "ethernet-defines.h"
+#include "ethernet-util.h"
+
+static int number_spi_ports;
+static int need_retrain[2] = { 0, 0 };
+
+static void cvm_oct_spxx_int_pr(union cvmx_spxx_int_reg spx_int_reg, int index)
+{
+       if (spx_int_reg.s.spf)
+               pr_err("SPI%d: SRX Spi4 interface down\n", index);
+       if (spx_int_reg.s.calerr)
+               pr_err("SPI%d: SRX Spi4 Calendar table parity error\n", index);
+       if (spx_int_reg.s.syncerr)
+               pr_err("SPI%d: SRX Consecutive Spi4 DIP4 errors have exceeded SPX_ERR_CTL[ERRCNT]\n",
+                      index);
+       if (spx_int_reg.s.diperr)
+               pr_err("SPI%d: SRX Spi4 DIP4 error\n", index);
+       if (spx_int_reg.s.tpaovr)
+               pr_err("SPI%d: SRX Selected port has hit TPA overflow\n",
+                      index);
+       if (spx_int_reg.s.rsverr)
+               pr_err("SPI%d: SRX Spi4 reserved control word detected\n",
+                      index);
+       if (spx_int_reg.s.drwnng)
+               pr_err("SPI%d: SRX Spi4 receive FIFO drowning/overflow\n",
+                      index);
+       if (spx_int_reg.s.clserr)
+               pr_err("SPI%d: SRX Spi4 packet closed on non-16B alignment without EOP\n",
+                      index);
+       if (spx_int_reg.s.spiovr)
+               pr_err("SPI%d: SRX Spi4 async FIFO overflow\n", index);
+       if (spx_int_reg.s.abnorm)
+               pr_err("SPI%d: SRX Abnormal packet termination (ERR bit)\n",
+                      index);
+       if (spx_int_reg.s.prtnxa)
+               pr_err("SPI%d: SRX Port out of range\n", index);
+}
+
+static void cvm_oct_stxx_int_pr(union cvmx_stxx_int_reg stx_int_reg, int index)
+{
+       if (stx_int_reg.s.syncerr)
+               pr_err("SPI%d: STX Interface encountered a fatal error\n",
+                      index);
+       if (stx_int_reg.s.frmerr)
+               pr_err("SPI%d: STX FRMCNT has exceeded STX_DIP_CNT[MAXFRM]\n",
+                      index);
+       if (stx_int_reg.s.unxfrm)
+               pr_err("SPI%d: STX Unexpected framing sequence\n", index);
+       if (stx_int_reg.s.nosync)
+               pr_err("SPI%d: STX ERRCNT has exceeded STX_DIP_CNT[MAXDIP]\n",
+                      index);
+       if (stx_int_reg.s.diperr)
+               pr_err("SPI%d: STX DIP2 error on the Spi4 Status channel\n",
+                      index);
+       if (stx_int_reg.s.datovr)
+               pr_err("SPI%d: STX Spi4 FIFO overflow error\n", index);
+       if (stx_int_reg.s.ovrbst)
+               pr_err("SPI%d: STX Transmit packet burst too big\n", index);
+       if (stx_int_reg.s.calpar1)
+               pr_err("SPI%d: STX Calendar Table Parity Error Bank%d\n",
+                      index, 1);
+       if (stx_int_reg.s.calpar0)
+               pr_err("SPI%d: STX Calendar Table Parity Error Bank%d\n",
+                      index, 0);
+}
+
+static irqreturn_t cvm_oct_spi_spx_int(int index)
+{
+       union cvmx_spxx_int_reg spx_int_reg;
+       union cvmx_stxx_int_reg stx_int_reg;
+
+       spx_int_reg.u64 = cvmx_read_csr(CVMX_SPXX_INT_REG(index));
+       cvmx_write_csr(CVMX_SPXX_INT_REG(index), spx_int_reg.u64);
+       if (!need_retrain[index]) {
+               spx_int_reg.u64 &= cvmx_read_csr(CVMX_SPXX_INT_MSK(index));
+               cvm_oct_spxx_int_pr(spx_int_reg, index);
+       }
+
+       stx_int_reg.u64 = cvmx_read_csr(CVMX_STXX_INT_REG(index));
+       cvmx_write_csr(CVMX_STXX_INT_REG(index), stx_int_reg.u64);
+       if (!need_retrain[index]) {
+               stx_int_reg.u64 &= cvmx_read_csr(CVMX_STXX_INT_MSK(index));
+               cvm_oct_stxx_int_pr(stx_int_reg, index);
+       }
+
+       cvmx_write_csr(CVMX_SPXX_INT_MSK(index), 0);
+       cvmx_write_csr(CVMX_STXX_INT_MSK(index), 0);
+       need_retrain[index] = 1;
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cvm_oct_spi_rml_interrupt(int cpl, void *dev_id)
+{
+       irqreturn_t return_status = IRQ_NONE;
+       union cvmx_npi_rsl_int_blocks rsl_int_blocks;
+
+       /* Check and see if this interrupt was caused by the GMX block */
+       rsl_int_blocks.u64 = cvmx_read_csr(CVMX_NPI_RSL_INT_BLOCKS);
+       if (rsl_int_blocks.s.spx1) /* 19 - SPX1_INT_REG & STX1_INT_REG */
+               return_status = cvm_oct_spi_spx_int(1);
+
+       if (rsl_int_blocks.s.spx0) /* 18 - SPX0_INT_REG & STX0_INT_REG */
+               return_status = cvm_oct_spi_spx_int(0);
+
+       return return_status;
+}
+
+static void cvm_oct_spi_enable_error_reporting(int interface)
+{
+       union cvmx_spxx_int_msk spxx_int_msk;
+       union cvmx_stxx_int_msk stxx_int_msk;
+
+       spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
+       spxx_int_msk.s.calerr = 1;
+       spxx_int_msk.s.syncerr = 1;
+       spxx_int_msk.s.diperr = 1;
+       spxx_int_msk.s.tpaovr = 1;
+       spxx_int_msk.s.rsverr = 1;
+       spxx_int_msk.s.drwnng = 1;
+       spxx_int_msk.s.clserr = 1;
+       spxx_int_msk.s.spiovr = 1;
+       spxx_int_msk.s.abnorm = 1;
+       spxx_int_msk.s.prtnxa = 1;
+       cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
+
+       stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
+       stxx_int_msk.s.frmerr = 1;
+       stxx_int_msk.s.unxfrm = 1;
+       stxx_int_msk.s.nosync = 1;
+       stxx_int_msk.s.diperr = 1;
+       stxx_int_msk.s.datovr = 1;
+       stxx_int_msk.s.ovrbst = 1;
+       stxx_int_msk.s.calpar1 = 1;
+       stxx_int_msk.s.calpar0 = 1;
+       cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
+}
+
+static void cvm_oct_spi_poll(struct net_device *dev)
+{
+       static int spi4000_port;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       int interface;
+
+       for (interface = 0; interface < 2; interface++) {
+               if ((priv->port == interface * 16) && need_retrain[interface]) {
+                       if (cvmx_spi_restart_interface
+                           (interface, CVMX_SPI_MODE_DUPLEX, 10) == 0) {
+                               need_retrain[interface] = 0;
+                               cvm_oct_spi_enable_error_reporting(interface);
+                       }
+               }
+
+               /*
+                * The SPI4000 TWSI interface is very slow. In order
+                * not to bring the system to a crawl, we only poll a
+                * single port every second. This means negotiation
+                * speed changes take up to 10 seconds, but at least
+                * we don't waste absurd amounts of time waiting for
+                * TWSI.
+                */
+               if (priv->port == spi4000_port) {
+                       /*
+                        * This function does nothing if it is called on an
+                        * interface without a SPI4000.
+                        */
+                       cvmx_spi4000_check_speed(interface, priv->port);
+                       /*
+                        * Normal ordering increments. By decrementing
+                        * we only match once per iteration.
+                        */
+                       spi4000_port--;
+                       if (spi4000_port < 0)
+                               spi4000_port = 10;
+               }
+       }
+}
+
+int cvm_oct_spi_init(struct net_device *dev)
+{
+       int r;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+
+       if (number_spi_ports == 0) {
+               r = request_irq(OCTEON_IRQ_RML, cvm_oct_spi_rml_interrupt,
+                               IRQF_SHARED, "SPI", &number_spi_ports);
+               if (r)
+                       return r;
+       }
+       number_spi_ports++;
+
+       if ((priv->port == 0) || (priv->port == 16)) {
+               cvm_oct_spi_enable_error_reporting(INTERFACE(priv->port));
+               priv->poll = cvm_oct_spi_poll;
+       }
+       cvm_oct_common_init(dev);
+       return 0;
+}
+
+void cvm_oct_spi_uninit(struct net_device *dev)
+{
+       int interface;
+
+       cvm_oct_common_uninit(dev);
+       number_spi_ports--;
+       if (number_spi_ports == 0) {
+               for (interface = 0; interface < 2; interface++) {
+                       cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
+                       cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
+               }
+               free_irq(OCTEON_IRQ_RML, &number_spi_ports);
+       }
+}
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
new file mode 100644 (file)
index 0000000..ab7dd82
--- /dev/null
@@ -0,0 +1,717 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2010 Cavium Networks
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/ratelimit.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <net/dst.h>
+#ifdef CONFIG_XFRM
+#include <linux/xfrm.h>
+#include <net/xfrm.h>
+#endif /* CONFIG_XFRM */
+
+#include <linux/atomic.h>
+#include <net/sch_generic.h>
+
+#include "octeon-ethernet.h"
+#include "ethernet-defines.h"
+#include "ethernet-tx.h"
+#include "ethernet-util.h"
+
+#define CVM_OCT_SKB_CB(skb)    ((u64 *)((skb)->cb))
+
+/*
+ * You can define GET_SKBUFF_QOS() to override how the skbuff output
+ * function determines which output queue is used. The default
+ * implementation always uses the base queue for the port. If, for
+ * example, you wanted to use the skb->priority field, define
+ * GET_SKBUFF_QOS as: #define GET_SKBUFF_QOS(skb) ((skb)->priority)
+ */
+#ifndef GET_SKBUFF_QOS
+#define GET_SKBUFF_QOS(skb) 0
+#endif
+
+static void cvm_oct_tx_do_cleanup(unsigned long arg);
+static DECLARE_TASKLET(cvm_oct_tx_cleanup_tasklet, cvm_oct_tx_do_cleanup, 0);
+
+/* Maximum number of SKBs to try to free per xmit packet. */
+#define MAX_SKB_TO_FREE (MAX_OUT_QUEUE_DEPTH * 2)
+
+static inline int cvm_oct_adjust_skb_to_free(int skb_to_free, int fau)
+{
+       int undo;
+
+       undo = skb_to_free > 0 ? MAX_SKB_TO_FREE : skb_to_free +
+                                                  MAX_SKB_TO_FREE;
+       if (undo > 0)
+               cvmx_fau_atomic_add32(fau, -undo);
+       skb_to_free = -skb_to_free > MAX_SKB_TO_FREE ? MAX_SKB_TO_FREE :
+                                                      -skb_to_free;
+       return skb_to_free;
+}
+
+static void cvm_oct_kick_tx_poll_watchdog(void)
+{
+       union cvmx_ciu_timx ciu_timx;
+
+       ciu_timx.u64 = 0;
+       ciu_timx.s.one_shot = 1;
+       ciu_timx.s.len = cvm_oct_tx_poll_interval;
+       cvmx_write_csr(CVMX_CIU_TIMX(1), ciu_timx.u64);
+}
+
+static void cvm_oct_free_tx_skbs(struct net_device *dev)
+{
+       int skb_to_free;
+       int qos, queues_per_port;
+       int total_freed = 0;
+       int total_remaining = 0;
+       unsigned long flags;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+
+       queues_per_port = cvmx_pko_get_num_queues(priv->port);
+       /* Drain any pending packets in the free list */
+       for (qos = 0; qos < queues_per_port; qos++) {
+               if (skb_queue_len(&priv->tx_free_list[qos]) == 0)
+                       continue;
+               skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
+                                                      MAX_SKB_TO_FREE);
+               skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free,
+                                                        priv->fau + qos * 4);
+               total_freed += skb_to_free;
+               if (skb_to_free > 0) {
+                       struct sk_buff *to_free_list = NULL;
+
+                       spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
+                       while (skb_to_free > 0) {
+                               struct sk_buff *t;
+
+                               t = __skb_dequeue(&priv->tx_free_list[qos]);
+                               t->next = to_free_list;
+                               to_free_list = t;
+                               skb_to_free--;
+                       }
+                       spin_unlock_irqrestore(&priv->tx_free_list[qos].lock,
+                                              flags);
+                       /* Do the actual freeing outside of the lock. */
+                       while (to_free_list) {
+                               struct sk_buff *t = to_free_list;
+
+                               to_free_list = to_free_list->next;
+                               dev_kfree_skb_any(t);
+                       }
+               }
+               total_remaining += skb_queue_len(&priv->tx_free_list[qos]);
+       }
+       if (total_remaining < MAX_OUT_QUEUE_DEPTH && netif_queue_stopped(dev))
+               netif_wake_queue(dev);
+       if (total_remaining)
+               cvm_oct_kick_tx_poll_watchdog();
+}
+
+/**
+ * cvm_oct_xmit - transmit a packet
+ * @skb:    Packet to send
+ * @dev:    Device info structure
+ *
+ * Returns Always returns NETDEV_TX_OK
+ */
+int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       union cvmx_pko_command_word0 pko_command;
+       union cvmx_buf_ptr hw_buffer;
+       u64 old_scratch;
+       u64 old_scratch2;
+       int qos;
+       int i;
+       enum {QUEUE_CORE, QUEUE_HW, QUEUE_DROP} queue_type;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       struct sk_buff *to_free_list;
+       int skb_to_free;
+       int buffers_to_free;
+       u32 total_to_clean;
+       unsigned long flags;
+#if REUSE_SKBUFFS_WITHOUT_FREE
+       unsigned char *fpa_head;
+#endif
+
+       /*
+        * Prefetch the private data structure.  It is larger than the
+        * one cache line.
+        */
+       prefetch(priv);
+
+       /*
+        * The check on CVMX_PKO_QUEUES_PER_PORT_* is designed to
+        * completely remove "qos" in the event neither interface
+        * supports multiple queues per port.
+        */
+       if ((CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 > 1) ||
+           (CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 > 1)) {
+               qos = GET_SKBUFF_QOS(skb);
+               if (qos <= 0)
+                       qos = 0;
+               else if (qos >= cvmx_pko_get_num_queues(priv->port))
+                       qos = 0;
+       } else {
+               qos = 0;
+       }
+
+       if (USE_ASYNC_IOBDMA) {
+               /* Save scratch in case userspace is using it */
+               CVMX_SYNCIOBDMA;
+               old_scratch = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+               old_scratch2 = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
+
+               /*
+                * Fetch and increment the number of packets to be
+                * freed.
+                */
+               cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH + 8,
+                                              FAU_NUM_PACKET_BUFFERS_TO_FREE,
+                                              0);
+               cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH,
+                                              priv->fau + qos * 4,
+                                              MAX_SKB_TO_FREE);
+       }
+
+       /*
+        * We have space for 6 segment pointers, If there will be more
+        * than that, we must linearize.
+        */
+       if (unlikely(skb_shinfo(skb)->nr_frags > 5)) {
+               if (unlikely(__skb_linearize(skb))) {
+                       queue_type = QUEUE_DROP;
+                       if (USE_ASYNC_IOBDMA) {
+                               /*
+                                * Get the number of skbuffs in use
+                                * by the hardware
+                                */
+                               CVMX_SYNCIOBDMA;
+                               skb_to_free =
+                                       cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+                       } else {
+                               /*
+                                * Get the number of skbuffs in use
+                                * by the hardware
+                                */
+                               skb_to_free =
+                                    cvmx_fau_fetch_and_add32(priv->fau +
+                                                             qos * 4,
+                                                             MAX_SKB_TO_FREE);
+                       }
+                       skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free,
+                                                                priv->fau +
+                                                                qos * 4);
+                       spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
+                       goto skip_xmit;
+               }
+       }
+
+       /*
+        * The CN3XXX series of parts has an errata (GMX-401) which
+        * causes the GMX block to hang if a collision occurs towards
+        * the end of a <68 byte packet. As a workaround for this, we
+        * pad packets to be 68 bytes whenever we are in half duplex
+        * mode. We don't handle the case of having a small packet but
+        * no room to add the padding.  The kernel should always give
+        * us at least a cache line
+        */
+       if ((skb->len < 64) && OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+               union cvmx_gmxx_prtx_cfg gmx_prt_cfg;
+               int interface = INTERFACE(priv->port);
+               int index = INDEX(priv->port);
+
+               if (interface < 2) {
+                       /* We only need to pad packet in half duplex mode */
+                       gmx_prt_cfg.u64 =
+                           cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
+                       if (gmx_prt_cfg.s.duplex == 0) {
+                               int add_bytes = 64 - skb->len;
+
+                               if ((skb_tail_pointer(skb) + add_bytes) <=
+                                   skb_end_pointer(skb))
+                                       __skb_put_zero(skb, add_bytes);
+                       }
+               }
+       }
+
+       /* Build the PKO command */
+       pko_command.u64 = 0;
+#ifdef __LITTLE_ENDIAN
+       pko_command.s.le = 1;
+#endif
+       pko_command.s.n2 = 1;   /* Don't pollute L2 with the outgoing packet */
+       pko_command.s.segs = 1;
+       pko_command.s.total_bytes = skb->len;
+       pko_command.s.size0 = CVMX_FAU_OP_SIZE_32;
+       pko_command.s.subone0 = 1;
+
+       pko_command.s.dontfree = 1;
+
+       /* Build the PKO buffer pointer */
+       hw_buffer.u64 = 0;
+       if (skb_shinfo(skb)->nr_frags == 0) {
+               hw_buffer.s.addr = XKPHYS_TO_PHYS((uintptr_t)skb->data);
+               hw_buffer.s.pool = 0;
+               hw_buffer.s.size = skb->len;
+       } else {
+               hw_buffer.s.addr = XKPHYS_TO_PHYS((uintptr_t)skb->data);
+               hw_buffer.s.pool = 0;
+               hw_buffer.s.size = skb_headlen(skb);
+               CVM_OCT_SKB_CB(skb)[0] = hw_buffer.u64;
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       skb_frag_t *fs = skb_shinfo(skb)->frags + i;
+
+                       hw_buffer.s.addr =
+                               XKPHYS_TO_PHYS((uintptr_t)skb_frag_address(fs));
+                       hw_buffer.s.size = skb_frag_size(fs);
+                       CVM_OCT_SKB_CB(skb)[i + 1] = hw_buffer.u64;
+               }
+               hw_buffer.s.addr =
+                       XKPHYS_TO_PHYS((uintptr_t)CVM_OCT_SKB_CB(skb));
+               hw_buffer.s.size = skb_shinfo(skb)->nr_frags + 1;
+               pko_command.s.segs = skb_shinfo(skb)->nr_frags + 1;
+               pko_command.s.gather = 1;
+               goto dont_put_skbuff_in_hw;
+       }
+
+       /*
+        * See if we can put this skb in the FPA pool. Any strange
+        * behavior from the Linux networking stack will most likely
+        * be caused by a bug in the following code. If some field is
+        * in use by the network stack and gets carried over when a
+        * buffer is reused, bad things may happen.  If in doubt and
+        * you dont need the absolute best performance, disable the
+        * define REUSE_SKBUFFS_WITHOUT_FREE. The reuse of buffers has
+        * shown a 25% increase in performance under some loads.
+        */
+#if REUSE_SKBUFFS_WITHOUT_FREE
+       fpa_head = skb->head + 256 - ((unsigned long)skb->head & 0x7f);
+       if (unlikely(skb->data < fpa_head)) {
+               /* TX buffer beginning can't meet FPA alignment constraints */
+               goto dont_put_skbuff_in_hw;
+       }
+       if (unlikely
+           ((skb_end_pointer(skb) - fpa_head) < CVMX_FPA_PACKET_POOL_SIZE)) {
+               /* TX buffer isn't large enough for the FPA */
+               goto dont_put_skbuff_in_hw;
+       }
+       if (unlikely(skb_shared(skb))) {
+               /* TX buffer sharing data with someone else */
+               goto dont_put_skbuff_in_hw;
+       }
+       if (unlikely(skb_cloned(skb))) {
+               /* TX buffer has been cloned */
+               goto dont_put_skbuff_in_hw;
+       }
+       if (unlikely(skb_header_cloned(skb))) {
+               /* TX buffer header has been cloned */
+               goto dont_put_skbuff_in_hw;
+       }
+       if (unlikely(skb->destructor)) {
+               /* TX buffer has a destructor */
+               goto dont_put_skbuff_in_hw;
+       }
+       if (unlikely(skb_shinfo(skb)->nr_frags)) {
+               /* TX buffer has fragments */
+               goto dont_put_skbuff_in_hw;
+       }
+       if (unlikely
+           (skb->truesize !=
+            sizeof(*skb) + skb_end_offset(skb))) {
+               /* TX buffer truesize has been changed */
+               goto dont_put_skbuff_in_hw;
+       }
+
+       /*
+        * We can use this buffer in the FPA.  We don't need the FAU
+        * update anymore
+        */
+       pko_command.s.dontfree = 0;
+
+       hw_buffer.s.back = ((unsigned long)skb->data >> 7) -
+                          ((unsigned long)fpa_head >> 7);
+
+       *(struct sk_buff **)(fpa_head - sizeof(void *)) = skb;
+
+       /*
+        * The skbuff will be reused without ever being freed. We must
+        * cleanup a bunch of core things.
+        */
+       dst_release(skb_dst(skb));
+       skb_dst_set(skb, NULL);
+       skb_ext_reset(skb);
+       nf_reset_ct(skb);
+       skb_reset_redirect(skb);
+
+#ifdef CONFIG_NET_SCHED
+       skb->tc_index = 0;
+#endif /* CONFIG_NET_SCHED */
+#endif /* REUSE_SKBUFFS_WITHOUT_FREE */
+
+dont_put_skbuff_in_hw:
+
+       /* Check if we can use the hardware checksumming */
+       if ((skb->protocol == htons(ETH_P_IP)) &&
+           (ip_hdr(skb)->version == 4) &&
+           (ip_hdr(skb)->ihl == 5) &&
+           ((ip_hdr(skb)->frag_off == 0) ||
+            (ip_hdr(skb)->frag_off == htons(1 << 14))) &&
+           ((ip_hdr(skb)->protocol == IPPROTO_TCP) ||
+            (ip_hdr(skb)->protocol == IPPROTO_UDP))) {
+               /* Use hardware checksum calc */
+               pko_command.s.ipoffp1 = skb_network_offset(skb) + 1;
+       }
+
+       if (USE_ASYNC_IOBDMA) {
+               /* Get the number of skbuffs in use by the hardware */
+               CVMX_SYNCIOBDMA;
+               skb_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+               buffers_to_free = cvmx_scratch_read64(CVMX_SCR_SCRATCH + 8);
+       } else {
+               /* Get the number of skbuffs in use by the hardware */
+               skb_to_free = cvmx_fau_fetch_and_add32(priv->fau + qos * 4,
+                                                      MAX_SKB_TO_FREE);
+               buffers_to_free =
+                   cvmx_fau_fetch_and_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
+       }
+
+       skb_to_free = cvm_oct_adjust_skb_to_free(skb_to_free,
+                                                priv->fau + qos * 4);
+
+       /*
+        * If we're sending faster than the receive can free them then
+        * don't do the HW free.
+        */
+       if ((buffers_to_free < -100) && !pko_command.s.dontfree)
+               pko_command.s.dontfree = 1;
+
+       if (pko_command.s.dontfree) {
+               queue_type = QUEUE_CORE;
+               pko_command.s.reg0 = priv->fau + qos * 4;
+       } else {
+               queue_type = QUEUE_HW;
+       }
+       if (USE_ASYNC_IOBDMA)
+               cvmx_fau_async_fetch_and_add32(CVMX_SCR_SCRATCH,
+                                              FAU_TOTAL_TX_TO_CLEAN, 1);
+
+       spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
+
+       /* Drop this packet if we have too many already queued to the HW */
+       if (unlikely(skb_queue_len(&priv->tx_free_list[qos]) >=
+                    MAX_OUT_QUEUE_DEPTH)) {
+               if (dev->tx_queue_len != 0) {
+                       /* Drop the lock when notifying the core.  */
+                       spin_unlock_irqrestore(&priv->tx_free_list[qos].lock,
+                                              flags);
+                       netif_stop_queue(dev);
+                       spin_lock_irqsave(&priv->tx_free_list[qos].lock,
+                                         flags);
+               } else {
+                       /* If not using normal queueing.  */
+                       queue_type = QUEUE_DROP;
+                       goto skip_xmit;
+               }
+       }
+
+       cvmx_pko_send_packet_prepare(priv->port, priv->queue + qos,
+                                    CVMX_PKO_LOCK_NONE);
+
+       /* Send the packet to the output queue */
+       if (unlikely(cvmx_pko_send_packet_finish(priv->port,
+                                                priv->queue + qos,
+                                                pko_command, hw_buffer,
+                                                CVMX_PKO_LOCK_NONE))) {
+               printk_ratelimited("%s: Failed to send the packet\n",
+                                  dev->name);
+               queue_type = QUEUE_DROP;
+       }
+skip_xmit:
+       to_free_list = NULL;
+
+       switch (queue_type) {
+       case QUEUE_DROP:
+               skb->next = to_free_list;
+               to_free_list = skb;
+               dev->stats.tx_dropped++;
+               break;
+       case QUEUE_HW:
+               cvmx_fau_atomic_add32(FAU_NUM_PACKET_BUFFERS_TO_FREE, -1);
+               break;
+       case QUEUE_CORE:
+               __skb_queue_tail(&priv->tx_free_list[qos], skb);
+               break;
+       default:
+               BUG();
+       }
+
+       while (skb_to_free > 0) {
+               struct sk_buff *t = __skb_dequeue(&priv->tx_free_list[qos]);
+
+               t->next = to_free_list;
+               to_free_list = t;
+               skb_to_free--;
+       }
+
+       spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
+
+       /* Do the actual freeing outside of the lock. */
+       while (to_free_list) {
+               struct sk_buff *t = to_free_list;
+
+               to_free_list = to_free_list->next;
+               dev_kfree_skb_any(t);
+       }
+
+       if (USE_ASYNC_IOBDMA) {
+               CVMX_SYNCIOBDMA;
+               total_to_clean = cvmx_scratch_read64(CVMX_SCR_SCRATCH);
+               /* Restore the scratch area */
+               cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch);
+               cvmx_scratch_write64(CVMX_SCR_SCRATCH + 8, old_scratch2);
+       } else {
+               total_to_clean =
+                       cvmx_fau_fetch_and_add32(FAU_TOTAL_TX_TO_CLEAN, 1);
+       }
+
+       if (total_to_clean & 0x3ff) {
+               /*
+                * Schedule the cleanup tasklet every 1024 packets for
+                * the pathological case of high traffic on one port
+                * delaying clean up of packets on a different port
+                * that is blocked waiting for the cleanup.
+                */
+               tasklet_schedule(&cvm_oct_tx_cleanup_tasklet);
+       }
+
+       cvm_oct_kick_tx_poll_watchdog();
+
+       return NETDEV_TX_OK;
+}
+
+/**
+ * cvm_oct_xmit_pow - transmit a packet to the POW
+ * @skb:    Packet to send
+ * @dev:    Device info structure
+
+ * Returns Always returns zero
+ */
+int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       void *packet_buffer;
+       void *copy_location;
+
+       /* Get a work queue entry */
+       struct cvmx_wqe *work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL);
+
+       if (unlikely(!work)) {
+               printk_ratelimited("%s: Failed to allocate a work queue entry\n",
+                                  dev->name);
+               dev->stats.tx_dropped++;
+               dev_kfree_skb_any(skb);
+               return 0;
+       }
+
+       /* Get a packet buffer */
+       packet_buffer = cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL);
+       if (unlikely(!packet_buffer)) {
+               printk_ratelimited("%s: Failed to allocate a packet buffer\n",
+                                  dev->name);
+               cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, 1);
+               dev->stats.tx_dropped++;
+               dev_kfree_skb_any(skb);
+               return 0;
+       }
+
+       /*
+        * Calculate where we need to copy the data to. We need to
+        * leave 8 bytes for a next pointer (unused). We also need to
+        * include any configure skip. Then we need to align the IP
+        * packet src and dest into the same 64bit word. The below
+        * calculation may add a little extra, but that doesn't
+        * hurt.
+        */
+       copy_location = packet_buffer + sizeof(u64);
+       copy_location += ((CVMX_HELPER_FIRST_MBUFF_SKIP + 7) & 0xfff8) + 6;
+
+       /*
+        * We have to copy the packet since whoever processes this
+        * packet will free it to a hardware pool. We can't use the
+        * trick of counting outstanding packets like in
+        * cvm_oct_xmit.
+        */
+       memcpy(copy_location, skb->data, skb->len);
+
+       /*
+        * Fill in some of the work queue fields. We may need to add
+        * more if the software at the other end needs them.
+        */
+       if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
+               work->word0.pip.cn38xx.hw_chksum = skb->csum;
+       work->word1.len = skb->len;
+       cvmx_wqe_set_port(work, priv->port);
+       cvmx_wqe_set_qos(work, priv->port & 0x7);
+       cvmx_wqe_set_grp(work, pow_send_group);
+       work->word1.tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
+       work->word1.tag = pow_send_group;       /* FIXME */
+       /* Default to zero. Sets of zero later are commented out */
+       work->word2.u64 = 0;
+       work->word2.s.bufs = 1;
+       work->packet_ptr.u64 = 0;
+       work->packet_ptr.s.addr = cvmx_ptr_to_phys(copy_location);
+       work->packet_ptr.s.pool = CVMX_FPA_PACKET_POOL;
+       work->packet_ptr.s.size = CVMX_FPA_PACKET_POOL_SIZE;
+       work->packet_ptr.s.back = (copy_location - packet_buffer) >> 7;
+
+       if (skb->protocol == htons(ETH_P_IP)) {
+               work->word2.s.ip_offset = 14;
+#if 0
+               work->word2.s.vlan_valid = 0;   /* FIXME */
+               work->word2.s.vlan_cfi = 0;     /* FIXME */
+               work->word2.s.vlan_id = 0;      /* FIXME */
+               work->word2.s.dec_ipcomp = 0;   /* FIXME */
+#endif
+               work->word2.s.tcp_or_udp =
+                   (ip_hdr(skb)->protocol == IPPROTO_TCP) ||
+                   (ip_hdr(skb)->protocol == IPPROTO_UDP);
+#if 0
+               /* FIXME */
+               work->word2.s.dec_ipsec = 0;
+               /* We only support IPv4 right now */
+               work->word2.s.is_v6 = 0;
+               /* Hardware would set to zero */
+               work->word2.s.software = 0;
+               /* No error, packet is internal */
+               work->word2.s.L4_error = 0;
+#endif
+               work->word2.s.is_frag = !((ip_hdr(skb)->frag_off == 0) ||
+                                         (ip_hdr(skb)->frag_off ==
+                                             cpu_to_be16(1 << 14)));
+#if 0
+               /* Assume Linux is sending a good packet */
+               work->word2.s.IP_exc = 0;
+#endif
+               work->word2.s.is_bcast = (skb->pkt_type == PACKET_BROADCAST);
+               work->word2.s.is_mcast = (skb->pkt_type == PACKET_MULTICAST);
+#if 0
+               /* This is an IP packet */
+               work->word2.s.not_IP = 0;
+               /* No error, packet is internal */
+               work->word2.s.rcv_error = 0;
+               /* No error, packet is internal */
+               work->word2.s.err_code = 0;
+#endif
+
+               /*
+                * When copying the data, include 4 bytes of the
+                * ethernet header to align the same way hardware
+                * does.
+                */
+               memcpy(work->packet_data, skb->data + 10,
+                      sizeof(work->packet_data));
+       } else {
+#if 0
+               work->word2.snoip.vlan_valid = 0;       /* FIXME */
+               work->word2.snoip.vlan_cfi = 0; /* FIXME */
+               work->word2.snoip.vlan_id = 0;  /* FIXME */
+               work->word2.snoip.software = 0; /* Hardware would set to zero */
+#endif
+               work->word2.snoip.is_rarp = skb->protocol == htons(ETH_P_RARP);
+               work->word2.snoip.is_arp = skb->protocol == htons(ETH_P_ARP);
+               work->word2.snoip.is_bcast =
+                   (skb->pkt_type == PACKET_BROADCAST);
+               work->word2.snoip.is_mcast =
+                   (skb->pkt_type == PACKET_MULTICAST);
+               work->word2.snoip.not_IP = 1;   /* IP was done up above */
+#if 0
+               /* No error, packet is internal */
+               work->word2.snoip.rcv_error = 0;
+               /* No error, packet is internal */
+               work->word2.snoip.err_code = 0;
+#endif
+               memcpy(work->packet_data, skb->data, sizeof(work->packet_data));
+       }
+
+       /* Submit the packet to the POW */
+       cvmx_pow_work_submit(work, work->word1.tag, work->word1.tag_type,
+                            cvmx_wqe_get_qos(work), cvmx_wqe_get_grp(work));
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
+       dev_consume_skb_any(skb);
+       return 0;
+}
+
+/**
+ * cvm_oct_tx_shutdown_dev - free all skb that are currently queued for TX.
+ * @dev:    Device being shutdown
+ *
+ */
+void cvm_oct_tx_shutdown_dev(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       unsigned long flags;
+       int qos;
+
+       for (qos = 0; qos < 16; qos++) {
+               spin_lock_irqsave(&priv->tx_free_list[qos].lock, flags);
+               while (skb_queue_len(&priv->tx_free_list[qos]))
+                       dev_kfree_skb_any(__skb_dequeue
+                                         (&priv->tx_free_list[qos]));
+               spin_unlock_irqrestore(&priv->tx_free_list[qos].lock, flags);
+       }
+}
+
+static void cvm_oct_tx_do_cleanup(unsigned long arg)
+{
+       int port;
+
+       for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
+               if (cvm_oct_device[port]) {
+                       struct net_device *dev = cvm_oct_device[port];
+
+                       cvm_oct_free_tx_skbs(dev);
+               }
+       }
+}
+
+static irqreturn_t cvm_oct_tx_cleanup_watchdog(int cpl, void *dev_id)
+{
+       /* Disable the interrupt.  */
+       cvmx_write_csr(CVMX_CIU_TIMX(1), 0);
+       /* Do the work in the tasklet.  */
+       tasklet_schedule(&cvm_oct_tx_cleanup_tasklet);
+       return IRQ_HANDLED;
+}
+
+void cvm_oct_tx_initialize(void)
+{
+       int i;
+
+       /* Disable the interrupt.  */
+       cvmx_write_csr(CVMX_CIU_TIMX(1), 0);
+       /* Register an IRQ handler to receive CIU_TIMX(1) interrupts */
+       i = request_irq(OCTEON_IRQ_TIMER1,
+                       cvm_oct_tx_cleanup_watchdog, 0,
+                       "Ethernet", cvm_oct_device);
+
+       if (i)
+               panic("Could not acquire Ethernet IRQ %d\n", OCTEON_IRQ_TIMER1);
+}
+
+void cvm_oct_tx_shutdown(void)
+{
+       /* Free the interrupt handler */
+       free_irq(OCTEON_IRQ_TIMER1, cvm_oct_device);
+}
diff --git a/drivers/staging/octeon/ethernet-tx.h b/drivers/staging/octeon/ethernet-tx.h
new file mode 100644 (file)
index 0000000..78936e9
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev);
+int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev);
+int cvm_oct_transmit_qos(struct net_device *dev, void *work_queue_entry,
+                        int do_free, int qos);
+void cvm_oct_tx_initialize(void);
+void cvm_oct_tx_shutdown(void);
+void cvm_oct_tx_shutdown_dev(struct net_device *dev);
diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h
new file mode 100644 (file)
index 0000000..2af83a1
--- /dev/null
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+/**
+ * cvm_oct_get_buffer_ptr - convert packet data address to pointer
+ * @packet_ptr: Packet data hardware address
+ *
+ * Returns Packet buffer pointer
+ */
+static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr)
+{
+       return cvmx_phys_to_ptr(((packet_ptr.s.addr >> 7) - packet_ptr.s.back)
+                               << 7);
+}
+
+/**
+ * INTERFACE - convert IPD port to logical interface
+ * @ipd_port: Port to check
+ *
+ * Returns Logical interface
+ */
+static inline int INTERFACE(int ipd_port)
+{
+       int interface;
+
+       if (ipd_port == CVMX_PIP_NUM_INPUT_PORTS)
+               return 10;
+       interface = cvmx_helper_get_interface_num(ipd_port);
+       if (interface >= 0)
+               return interface;
+       panic("Illegal ipd_port %d passed to %s\n", ipd_port, __func__);
+}
+
+/**
+ * INDEX - convert IPD/PKO port number to the port's interface index
+ * @ipd_port: Port to check
+ *
+ * Returns Index into interface port list
+ */
+static inline int INDEX(int ipd_port)
+{
+       return cvmx_helper_get_interface_index_num(ipd_port);
+}
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
new file mode 100644 (file)
index 0000000..f42c381
--- /dev/null
@@ -0,0 +1,992 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2007 Cavium Networks
+ */
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/phy.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/of_net.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+
+#include <net/dst.h>
+
+#include "octeon-ethernet.h"
+#include "ethernet-defines.h"
+#include "ethernet-mem.h"
+#include "ethernet-rx.h"
+#include "ethernet-tx.h"
+#include "ethernet-mdio.h"
+#include "ethernet-util.h"
+
+#define OCTEON_MAX_MTU 65392
+
+static int num_packet_buffers = 1024;
+module_param(num_packet_buffers, int, 0444);
+MODULE_PARM_DESC(num_packet_buffers, "\n"
+       "\tNumber of packet buffers to allocate and store in the\n"
+       "\tFPA. By default, 1024 packet buffers are used.\n");
+
+static int pow_receive_group = 15;
+module_param(pow_receive_group, int, 0444);
+MODULE_PARM_DESC(pow_receive_group, "\n"
+       "\tPOW group to receive packets from. All ethernet hardware\n"
+       "\twill be configured to send incoming packets to this POW\n"
+       "\tgroup. Also any other software can submit packets to this\n"
+       "\tgroup for the kernel to process.");
+
+static int receive_group_order;
+module_param(receive_group_order, int, 0444);
+MODULE_PARM_DESC(receive_group_order, "\n"
+       "\tOrder (0..4) of receive groups to take into use. Ethernet hardware\n"
+       "\twill be configured to send incoming packets to multiple POW\n"
+       "\tgroups. pow_receive_group parameter is ignored when multiple\n"
+       "\tgroups are taken into use and groups are allocated starting\n"
+       "\tfrom 0. By default, a single group is used.\n");
+
+int pow_send_group = -1;
+module_param(pow_send_group, int, 0644);
+MODULE_PARM_DESC(pow_send_group, "\n"
+       "\tPOW group to send packets to other software on. This\n"
+       "\tcontrols the creation of the virtual device pow0.\n"
+       "\talways_use_pow also depends on this value.");
+
+int always_use_pow;
+module_param(always_use_pow, int, 0444);
+MODULE_PARM_DESC(always_use_pow, "\n"
+       "\tWhen set, always send to the pow group. This will cause\n"
+       "\tpackets sent to real ethernet devices to be sent to the\n"
+       "\tPOW group instead of the hardware. Unless some other\n"
+       "\tapplication changes the config, packets will still be\n"
+       "\treceived from the low level hardware. Use this option\n"
+       "\tto allow a CVMX app to intercept all packets from the\n"
+       "\tlinux kernel. You must specify pow_send_group along with\n"
+       "\tthis option.");
+
+char pow_send_list[128] = "";
+module_param_string(pow_send_list, pow_send_list, sizeof(pow_send_list), 0444);
+MODULE_PARM_DESC(pow_send_list, "\n"
+       "\tComma separated list of ethernet devices that should use the\n"
+       "\tPOW for transmit instead of the actual ethernet hardware. This\n"
+       "\tis a per port version of always_use_pow. always_use_pow takes\n"
+       "\tprecedence over this list. For example, setting this to\n"
+       "\t\"eth2,spi3,spi7\" would cause these three devices to transmit\n"
+       "\tusing the pow_send_group.");
+
+int rx_napi_weight = 32;
+module_param(rx_napi_weight, int, 0444);
+MODULE_PARM_DESC(rx_napi_weight, "The NAPI WEIGHT parameter.");
+
+/* Mask indicating which receive groups are in use. */
+int pow_receive_groups;
+
+/*
+ * cvm_oct_poll_queue_stopping - flag to indicate polling should stop.
+ *
+ * Set to one right before cvm_oct_poll_queue is destroyed.
+ */
+atomic_t cvm_oct_poll_queue_stopping = ATOMIC_INIT(0);
+
+/*
+ * Array of every ethernet device owned by this driver indexed by
+ * the ipd input port number.
+ */
+struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
+
+u64 cvm_oct_tx_poll_interval;
+
+static void cvm_oct_rx_refill_worker(struct work_struct *work);
+static DECLARE_DELAYED_WORK(cvm_oct_rx_refill_work, cvm_oct_rx_refill_worker);
+
+static void cvm_oct_rx_refill_worker(struct work_struct *work)
+{
+       /*
+        * FPA 0 may have been drained, try to refill it if we need
+        * more than num_packet_buffers / 2, otherwise normal receive
+        * processing will refill it.  If it were drained, no packets
+        * could be received so cvm_oct_napi_poll would never be
+        * invoked to do the refill.
+        */
+       cvm_oct_rx_refill_pool(num_packet_buffers / 2);
+
+       if (!atomic_read(&cvm_oct_poll_queue_stopping))
+               schedule_delayed_work(&cvm_oct_rx_refill_work, HZ);
+}
+
+static void cvm_oct_periodic_worker(struct work_struct *work)
+{
+       struct octeon_ethernet *priv = container_of(work,
+                                                   struct octeon_ethernet,
+                                                   port_periodic_work.work);
+
+       if (priv->poll)
+               priv->poll(cvm_oct_device[priv->port]);
+
+       cvm_oct_device[priv->port]->netdev_ops->ndo_get_stats
+                                               (cvm_oct_device[priv->port]);
+
+       if (!atomic_read(&cvm_oct_poll_queue_stopping))
+               schedule_delayed_work(&priv->port_periodic_work, HZ);
+}
+
+static void cvm_oct_configure_common_hw(void)
+{
+       /* Setup the FPA */
+       cvmx_fpa_enable();
+       cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
+                            num_packet_buffers);
+       cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE,
+                            num_packet_buffers);
+       if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
+               cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
+                                    CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 1024);
+
+#ifdef __LITTLE_ENDIAN
+       {
+               union cvmx_ipd_ctl_status ipd_ctl_status;
+
+               ipd_ctl_status.u64 = cvmx_read_csr(CVMX_IPD_CTL_STATUS);
+               ipd_ctl_status.s.pkt_lend = 1;
+               ipd_ctl_status.s.wqe_lend = 1;
+               cvmx_write_csr(CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64);
+       }
+#endif
+
+       cvmx_helper_setup_red(num_packet_buffers / 4, num_packet_buffers / 8);
+}
+
+/**
+ * cvm_oct_free_work- Free a work queue entry
+ *
+ * @work_queue_entry: Work queue entry to free
+ *
+ * Returns Zero on success, Negative on failure.
+ */
+int cvm_oct_free_work(void *work_queue_entry)
+{
+       struct cvmx_wqe *work = work_queue_entry;
+
+       int segments = work->word2.s.bufs;
+       union cvmx_buf_ptr segment_ptr = work->packet_ptr;
+
+       while (segments--) {
+               union cvmx_buf_ptr next_ptr = *(union cvmx_buf_ptr *)
+                       cvmx_phys_to_ptr(segment_ptr.s.addr - 8);
+               if (unlikely(!segment_ptr.s.i))
+                       cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr),
+                                     segment_ptr.s.pool,
+                                     CVMX_FPA_PACKET_POOL_SIZE / 128);
+               segment_ptr = next_ptr;
+       }
+       cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, 1);
+
+       return 0;
+}
+EXPORT_SYMBOL(cvm_oct_free_work);
+
+/**
+ * cvm_oct_common_get_stats - get the low level ethernet statistics
+ * @dev:    Device to get the statistics from
+ *
+ * Returns Pointer to the statistics
+ */
+static struct net_device_stats *cvm_oct_common_get_stats(struct net_device *dev)
+{
+       cvmx_pip_port_status_t rx_status;
+       cvmx_pko_port_status_t tx_status;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+
+       if (priv->port < CVMX_PIP_NUM_INPUT_PORTS) {
+               if (octeon_is_simulation()) {
+                       /* The simulator doesn't support statistics */
+                       memset(&rx_status, 0, sizeof(rx_status));
+                       memset(&tx_status, 0, sizeof(tx_status));
+               } else {
+                       cvmx_pip_get_port_status(priv->port, 1, &rx_status);
+                       cvmx_pko_get_port_status(priv->port, 1, &tx_status);
+               }
+
+               dev->stats.rx_packets += rx_status.inb_packets;
+               dev->stats.tx_packets += tx_status.packets;
+               dev->stats.rx_bytes += rx_status.inb_octets;
+               dev->stats.tx_bytes += tx_status.octets;
+               dev->stats.multicast += rx_status.multicast_packets;
+               dev->stats.rx_crc_errors += rx_status.inb_errors;
+               dev->stats.rx_frame_errors += rx_status.fcs_align_err_packets;
+               dev->stats.rx_dropped += rx_status.dropped_packets;
+       }
+
+       return &dev->stats;
+}
+
+/**
+ * cvm_oct_common_change_mtu - change the link MTU
+ * @dev:     Device to change
+ * @new_mtu: The new MTU
+ *
+ * Returns Zero on success
+ */
+static int cvm_oct_common_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       int interface = INTERFACE(priv->port);
+#if IS_ENABLED(CONFIG_VLAN_8021Q)
+       int vlan_bytes = VLAN_HLEN;
+#else
+       int vlan_bytes = 0;
+#endif
+       int mtu_overhead = ETH_HLEN + ETH_FCS_LEN + vlan_bytes;
+
+       dev->mtu = new_mtu;
+
+       if ((interface < 2) &&
+           (cvmx_helper_interface_get_mode(interface) !=
+               CVMX_HELPER_INTERFACE_MODE_SPI)) {
+               int index = INDEX(priv->port);
+               /* Add ethernet header and FCS, and VLAN if configured. */
+               int max_packet = new_mtu + mtu_overhead;
+
+               if (OCTEON_IS_MODEL(OCTEON_CN3XXX) ||
+                   OCTEON_IS_MODEL(OCTEON_CN58XX)) {
+                       /* Signal errors on packets larger than the MTU */
+                       cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface),
+                                      max_packet);
+               } else {
+                       /*
+                        * Set the hardware to truncate packets larger
+                        * than the MTU and smaller the 64 bytes.
+                        */
+                       union cvmx_pip_frm_len_chkx frm_len_chk;
+
+                       frm_len_chk.u64 = 0;
+                       frm_len_chk.s.minlen = VLAN_ETH_ZLEN;
+                       frm_len_chk.s.maxlen = max_packet;
+                       cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface),
+                                      frm_len_chk.u64);
+               }
+               /*
+                * Set the hardware to truncate packets larger than
+                * the MTU. The jabber register must be set to a
+                * multiple of 8 bytes, so round up.
+                */
+               cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface),
+                              (max_packet + 7) & ~7u);
+       }
+       return 0;
+}
+
+/**
+ * cvm_oct_common_set_multicast_list - set the multicast list
+ * @dev:    Device to work on
+ */
+static void cvm_oct_common_set_multicast_list(struct net_device *dev)
+{
+       union cvmx_gmxx_prtx_cfg gmx_cfg;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       int interface = INTERFACE(priv->port);
+
+       if ((interface < 2) &&
+           (cvmx_helper_interface_get_mode(interface) !=
+               CVMX_HELPER_INTERFACE_MODE_SPI)) {
+               union cvmx_gmxx_rxx_adr_ctl control;
+               int index = INDEX(priv->port);
+
+               control.u64 = 0;
+               control.s.bcst = 1;     /* Allow broadcast MAC addresses */
+
+               if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI) ||
+                   (dev->flags & IFF_PROMISC))
+                       /* Force accept multicast packets */
+                       control.s.mcst = 2;
+               else
+                       /* Force reject multicast packets */
+                       control.s.mcst = 1;
+
+               if (dev->flags & IFF_PROMISC)
+                       /*
+                        * Reject matches if promisc. Since CAM is
+                        * shut off, should accept everything.
+                        */
+                       control.s.cam_mode = 0;
+               else
+                       /* Filter packets based on the CAM */
+                       control.s.cam_mode = 1;
+
+               gmx_cfg.u64 =
+                   cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
+               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
+                              gmx_cfg.u64 & ~1ull);
+
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface),
+                              control.u64);
+               if (dev->flags & IFF_PROMISC)
+                       cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
+                                      (index, interface), 0);
+               else
+                       cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN
+                                      (index, interface), 1);
+
+               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
+                              gmx_cfg.u64);
+       }
+}
+
+static int cvm_oct_set_mac_filter(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       union cvmx_gmxx_prtx_cfg gmx_cfg;
+       int interface = INTERFACE(priv->port);
+
+       if ((interface < 2) &&
+           (cvmx_helper_interface_get_mode(interface) !=
+               CVMX_HELPER_INTERFACE_MODE_SPI)) {
+               int i;
+               u8 *ptr = dev->dev_addr;
+               u64 mac = 0;
+               int index = INDEX(priv->port);
+
+               for (i = 0; i < 6; i++)
+                       mac = (mac << 8) | (u64)ptr[i];
+
+               gmx_cfg.u64 =
+                   cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
+               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
+                              gmx_cfg.u64 & ~1ull);
+
+               cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface),
+                              ptr[0]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface),
+                              ptr[1]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface),
+                              ptr[2]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface),
+                              ptr[3]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface),
+                              ptr[4]);
+               cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface),
+                              ptr[5]);
+               cvm_oct_common_set_multicast_list(dev);
+               cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
+                              gmx_cfg.u64);
+       }
+       return 0;
+}
+
+/**
+ * cvm_oct_common_set_mac_address - set the hardware MAC address for a device
+ * @dev:    The device in question.
+ * @addr:   Socket address.
+ *
+ * Returns Zero on success
+ */
+static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
+{
+       int r = eth_mac_addr(dev, addr);
+
+       if (r)
+               return r;
+       return cvm_oct_set_mac_filter(dev);
+}
+
+/**
+ * cvm_oct_common_init - per network device initialization
+ * @dev:    Device to initialize
+ *
+ * Returns Zero on success
+ */
+int cvm_oct_common_init(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       const u8 *mac = NULL;
+
+       if (priv->of_node)
+               mac = of_get_mac_address(priv->of_node);
+
+       if (!IS_ERR_OR_NULL(mac))
+               ether_addr_copy(dev->dev_addr, mac);
+       else
+               eth_hw_addr_random(dev);
+
+       /*
+        * Force the interface to use the POW send if always_use_pow
+        * was specified or it is in the pow send list.
+        */
+       if ((pow_send_group != -1) &&
+           (always_use_pow || strstr(pow_send_list, dev->name)))
+               priv->queue = -1;
+
+       if (priv->queue != -1)
+               dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+
+       /* We do our own locking, Linux doesn't need to */
+       dev->features |= NETIF_F_LLTX;
+       dev->ethtool_ops = &cvm_oct_ethtool_ops;
+
+       cvm_oct_set_mac_filter(dev);
+       dev_set_mtu(dev, dev->mtu);
+
+       /*
+        * Zero out stats for port so we won't mistakenly show
+        * counters from the bootloader.
+        */
+       memset(dev->netdev_ops->ndo_get_stats(dev), 0,
+              sizeof(struct net_device_stats));
+
+       if (dev->netdev_ops->ndo_stop)
+               dev->netdev_ops->ndo_stop(dev);
+
+       return 0;
+}
+
+void cvm_oct_common_uninit(struct net_device *dev)
+{
+       if (dev->phydev)
+               phy_disconnect(dev->phydev);
+}
+
+int cvm_oct_common_open(struct net_device *dev,
+                       void (*link_poll)(struct net_device *))
+{
+       union cvmx_gmxx_prtx_cfg gmx_cfg;
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       int interface = INTERFACE(priv->port);
+       int index = INDEX(priv->port);
+       union cvmx_helper_link_info link_info;
+       int rv;
+
+       rv = cvm_oct_phy_setup_device(dev);
+       if (rv)
+               return rv;
+
+       gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
+       gmx_cfg.s.en = 1;
+       if (octeon_has_feature(OCTEON_FEATURE_PKND))
+               gmx_cfg.s.pknd = priv->port;
+       cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
+
+       if (octeon_is_simulation())
+               return 0;
+
+       if (dev->phydev) {
+               int r = phy_read_status(dev->phydev);
+
+               if (r == 0 && dev->phydev->link == 0)
+                       netif_carrier_off(dev);
+               cvm_oct_adjust_link(dev);
+       } else {
+               link_info = cvmx_helper_link_get(priv->port);
+               if (!link_info.s.link_up)
+                       netif_carrier_off(dev);
+               priv->poll = link_poll;
+               link_poll(dev);
+       }
+
+       return 0;
+}
+
+void cvm_oct_link_poll(struct net_device *dev)
+{
+       struct octeon_ethernet *priv = netdev_priv(dev);
+       union cvmx_helper_link_info link_info;
+
+       link_info = cvmx_helper_link_get(priv->port);
+       if (link_info.u64 == priv->link_info)
+               return;
+
+       if (cvmx_helper_link_set(priv->port, link_info))
+               link_info.u64 = priv->link_info;
+       else
+               priv->link_info = link_info.u64;
+
+       if (link_info.s.link_up) {
+               if (!netif_carrier_ok(dev))
+                       netif_carrier_on(dev);
+       } else if (netif_carrier_ok(dev)) {
+               netif_carrier_off(dev);
+       }
+       cvm_oct_note_carrier(priv, link_info);
+}
+
+static int cvm_oct_xaui_open(struct net_device *dev)
+{
+       return cvm_oct_common_open(dev, cvm_oct_link_poll);
+}
+
+static const struct net_device_ops cvm_oct_npi_netdev_ops = {
+       .ndo_init               = cvm_oct_common_init,
+       .ndo_uninit             = cvm_oct_common_uninit,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+
+static const struct net_device_ops cvm_oct_xaui_netdev_ops = {
+       .ndo_init               = cvm_oct_common_init,
+       .ndo_uninit             = cvm_oct_common_uninit,
+       .ndo_open               = cvm_oct_xaui_open,
+       .ndo_stop               = cvm_oct_common_stop,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+
+static const struct net_device_ops cvm_oct_sgmii_netdev_ops = {
+       .ndo_init               = cvm_oct_sgmii_init,
+       .ndo_uninit             = cvm_oct_common_uninit,
+       .ndo_open               = cvm_oct_sgmii_open,
+       .ndo_stop               = cvm_oct_common_stop,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+
+static const struct net_device_ops cvm_oct_spi_netdev_ops = {
+       .ndo_init               = cvm_oct_spi_init,
+       .ndo_uninit             = cvm_oct_spi_uninit,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+
+static const struct net_device_ops cvm_oct_rgmii_netdev_ops = {
+       .ndo_init               = cvm_oct_common_init,
+       .ndo_uninit             = cvm_oct_common_uninit,
+       .ndo_open               = cvm_oct_rgmii_open,
+       .ndo_stop               = cvm_oct_common_stop,
+       .ndo_start_xmit         = cvm_oct_xmit,
+       .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+
+static const struct net_device_ops cvm_oct_pow_netdev_ops = {
+       .ndo_init               = cvm_oct_common_init,
+       .ndo_start_xmit         = cvm_oct_xmit_pow,
+       .ndo_set_rx_mode        = cvm_oct_common_set_multicast_list,
+       .ndo_set_mac_address    = cvm_oct_common_set_mac_address,
+       .ndo_do_ioctl           = cvm_oct_ioctl,
+       .ndo_change_mtu         = cvm_oct_common_change_mtu,
+       .ndo_get_stats          = cvm_oct_common_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = cvm_oct_poll_controller,
+#endif
+};
+
+static struct device_node *cvm_oct_of_get_child
+                               (const struct device_node *parent, int reg_val)
+{
+       struct device_node *node = NULL;
+       int size;
+       const __be32 *addr;
+
+       for (;;) {
+               node = of_get_next_child(parent, node);
+               if (!node)
+                       break;
+               addr = of_get_property(node, "reg", &size);
+               if (addr && (be32_to_cpu(*addr) == reg_val))
+                       break;
+       }
+       return node;
+}
+
+static struct device_node *cvm_oct_node_for_port(struct device_node *pip,
+                                                int interface, int port)
+{
+       struct device_node *ni, *np;
+
+       ni = cvm_oct_of_get_child(pip, interface);
+       if (!ni)
+               return NULL;
+
+       np = cvm_oct_of_get_child(ni, port);
+       of_node_put(ni);
+
+       return np;
+}
+
+static void cvm_set_rgmii_delay(struct octeon_ethernet *priv, int iface,
+                               int port)
+{
+       struct device_node *np = priv->of_node;
+       u32 delay_value;
+       bool rx_delay;
+       bool tx_delay;
+
+       /* By default, both RX/TX delay is enabled in
+        * __cvmx_helper_rgmii_enable().
+        */
+       rx_delay = true;
+       tx_delay = true;
+
+       if (!of_property_read_u32(np, "rx-delay", &delay_value)) {
+               cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, iface), delay_value);
+               rx_delay = delay_value > 0;
+       }
+       if (!of_property_read_u32(np, "tx-delay", &delay_value)) {
+               cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, iface), delay_value);
+               tx_delay = delay_value > 0;
+       }
+
+       if (!rx_delay && !tx_delay)
+               priv->phy_mode = PHY_INTERFACE_MODE_RGMII_ID;
+       else if (!rx_delay)
+               priv->phy_mode = PHY_INTERFACE_MODE_RGMII_RXID;
+       else if (!tx_delay)
+               priv->phy_mode = PHY_INTERFACE_MODE_RGMII_TXID;
+       else
+               priv->phy_mode = PHY_INTERFACE_MODE_RGMII;
+}
+
+static int cvm_oct_probe(struct platform_device *pdev)
+{
+       int num_interfaces;
+       int interface;
+       int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
+       int qos;
+       struct device_node *pip;
+       int mtu_overhead = ETH_HLEN + ETH_FCS_LEN;
+
+#if IS_ENABLED(CONFIG_VLAN_8021Q)
+       mtu_overhead += VLAN_HLEN;
+#endif
+
+       octeon_mdiobus_force_mod_depencency();
+
+       pip = pdev->dev.of_node;
+       if (!pip) {
+               pr_err("Error: No 'pip' in /aliases\n");
+               return -EINVAL;
+       }
+
+       cvm_oct_configure_common_hw();
+
+       cvmx_helper_initialize_packet_io_global();
+
+       if (receive_group_order) {
+               if (receive_group_order > 4)
+                       receive_group_order = 4;
+               pow_receive_groups = (1 << (1 << receive_group_order)) - 1;
+       } else {
+               pow_receive_groups = BIT(pow_receive_group);
+       }
+
+       /* Change the input group for all ports before input is enabled */
+       num_interfaces = cvmx_helper_get_number_of_interfaces();
+       for (interface = 0; interface < num_interfaces; interface++) {
+               int num_ports = cvmx_helper_ports_on_interface(interface);
+               int port;
+
+               for (port = cvmx_helper_get_ipd_port(interface, 0);
+                    port < cvmx_helper_get_ipd_port(interface, num_ports);
+                    port++) {
+                       union cvmx_pip_prt_tagx pip_prt_tagx;
+
+                       pip_prt_tagx.u64 =
+                           cvmx_read_csr(CVMX_PIP_PRT_TAGX(port));
+
+                       if (receive_group_order) {
+                               int tag_mask;
+
+                               /* We support only 16 groups at the moment, so
+                                * always disable the two additional "hidden"
+                                * tag_mask bits on CN68XX.
+                                */
+                               if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+                                       pip_prt_tagx.u64 |= 0x3ull << 44;
+
+                               tag_mask = ~((1 << receive_group_order) - 1);
+                               pip_prt_tagx.s.grptagbase       = 0;
+                               pip_prt_tagx.s.grptagmask       = tag_mask;
+                               pip_prt_tagx.s.grptag           = 1;
+                               pip_prt_tagx.s.tag_mode         = 0;
+                               pip_prt_tagx.s.inc_prt_flag     = 1;
+                               pip_prt_tagx.s.ip6_dprt_flag    = 1;
+                               pip_prt_tagx.s.ip4_dprt_flag    = 1;
+                               pip_prt_tagx.s.ip6_sprt_flag    = 1;
+                               pip_prt_tagx.s.ip4_sprt_flag    = 1;
+                               pip_prt_tagx.s.ip6_dst_flag     = 1;
+                               pip_prt_tagx.s.ip4_dst_flag     = 1;
+                               pip_prt_tagx.s.ip6_src_flag     = 1;
+                               pip_prt_tagx.s.ip4_src_flag     = 1;
+                               pip_prt_tagx.s.grp              = 0;
+                       } else {
+                               pip_prt_tagx.s.grptag   = 0;
+                               pip_prt_tagx.s.grp      = pow_receive_group;
+                       }
+
+                       cvmx_write_csr(CVMX_PIP_PRT_TAGX(port),
+                                      pip_prt_tagx.u64);
+               }
+       }
+
+       cvmx_helper_ipd_and_packet_input_enable();
+
+       memset(cvm_oct_device, 0, sizeof(cvm_oct_device));
+
+       /*
+        * Initialize the FAU used for counting packet buffers that
+        * need to be freed.
+        */
+       cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
+
+       /* Initialize the FAU used for counting tx SKBs that need to be freed */
+       cvmx_fau_atomic_write32(FAU_TOTAL_TX_TO_CLEAN, 0);
+
+       if ((pow_send_group != -1)) {
+               struct net_device *dev;
+
+               dev = alloc_etherdev(sizeof(struct octeon_ethernet));
+               if (dev) {
+                       /* Initialize the device private structure. */
+                       struct octeon_ethernet *priv = netdev_priv(dev);
+
+                       SET_NETDEV_DEV(dev, &pdev->dev);
+                       dev->netdev_ops = &cvm_oct_pow_netdev_ops;
+                       priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED;
+                       priv->port = CVMX_PIP_NUM_INPUT_PORTS;
+                       priv->queue = -1;
+                       strscpy(dev->name, "pow%d", sizeof(dev->name));
+                       for (qos = 0; qos < 16; qos++)
+                               skb_queue_head_init(&priv->tx_free_list[qos]);
+                       dev->min_mtu = VLAN_ETH_ZLEN - mtu_overhead;
+                       dev->max_mtu = OCTEON_MAX_MTU - mtu_overhead;
+
+                       if (register_netdev(dev) < 0) {
+                               pr_err("Failed to register ethernet device for POW\n");
+                               free_netdev(dev);
+                       } else {
+                               cvm_oct_device[CVMX_PIP_NUM_INPUT_PORTS] = dev;
+                               pr_info("%s: POW send group %d, receive group %d\n",
+                                       dev->name, pow_send_group,
+                                       pow_receive_group);
+                       }
+               } else {
+                       pr_err("Failed to allocate ethernet device for POW\n");
+               }
+       }
+
+       num_interfaces = cvmx_helper_get_number_of_interfaces();
+       for (interface = 0; interface < num_interfaces; interface++) {
+               cvmx_helper_interface_mode_t imode =
+                   cvmx_helper_interface_get_mode(interface);
+               int num_ports = cvmx_helper_ports_on_interface(interface);
+               int port;
+               int port_index;
+
+               for (port_index = 0,
+                    port = cvmx_helper_get_ipd_port(interface, 0);
+                    port < cvmx_helper_get_ipd_port(interface, num_ports);
+                    port_index++, port++) {
+                       struct octeon_ethernet *priv;
+                       struct net_device *dev =
+                           alloc_etherdev(sizeof(struct octeon_ethernet));
+                       if (!dev) {
+                               pr_err("Failed to allocate ethernet device for port %d\n",
+                                      port);
+                               continue;
+                       }
+
+                       /* Initialize the device private structure. */
+                       SET_NETDEV_DEV(dev, &pdev->dev);
+                       priv = netdev_priv(dev);
+                       priv->netdev = dev;
+                       priv->of_node = cvm_oct_node_for_port(pip, interface,
+                                                             port_index);
+
+                       INIT_DELAYED_WORK(&priv->port_periodic_work,
+                                         cvm_oct_periodic_worker);
+                       priv->imode = imode;
+                       priv->port = port;
+                       priv->queue = cvmx_pko_get_base_queue(priv->port);
+                       priv->fau = fau - cvmx_pko_get_num_queues(port) * 4;
+                       priv->phy_mode = PHY_INTERFACE_MODE_NA;
+                       for (qos = 0; qos < 16; qos++)
+                               skb_queue_head_init(&priv->tx_free_list[qos]);
+                       for (qos = 0; qos < cvmx_pko_get_num_queues(port);
+                            qos++)
+                               cvmx_fau_atomic_write32(priv->fau + qos * 4, 0);
+                       dev->min_mtu = VLAN_ETH_ZLEN - mtu_overhead;
+                       dev->max_mtu = OCTEON_MAX_MTU - mtu_overhead;
+
+                       switch (priv->imode) {
+                       /* These types don't support ports to IPD/PKO */
+                       case CVMX_HELPER_INTERFACE_MODE_DISABLED:
+                       case CVMX_HELPER_INTERFACE_MODE_PCIE:
+                       case CVMX_HELPER_INTERFACE_MODE_PICMG:
+                               break;
+
+                       case CVMX_HELPER_INTERFACE_MODE_NPI:
+                               dev->netdev_ops = &cvm_oct_npi_netdev_ops;
+                               strscpy(dev->name, "npi%d", sizeof(dev->name));
+                               break;
+
+                       case CVMX_HELPER_INTERFACE_MODE_XAUI:
+                               dev->netdev_ops = &cvm_oct_xaui_netdev_ops;
+                               strscpy(dev->name, "xaui%d", sizeof(dev->name));
+                               break;
+
+                       case CVMX_HELPER_INTERFACE_MODE_LOOP:
+                               dev->netdev_ops = &cvm_oct_npi_netdev_ops;
+                               strscpy(dev->name, "loop%d", sizeof(dev->name));
+                               break;
+
+                       case CVMX_HELPER_INTERFACE_MODE_SGMII:
+                               priv->phy_mode = PHY_INTERFACE_MODE_SGMII;
+                               dev->netdev_ops = &cvm_oct_sgmii_netdev_ops;
+                               strscpy(dev->name, "eth%d", sizeof(dev->name));
+                               break;
+
+                       case CVMX_HELPER_INTERFACE_MODE_SPI:
+                               dev->netdev_ops = &cvm_oct_spi_netdev_ops;
+                               strscpy(dev->name, "spi%d", sizeof(dev->name));
+                               break;
+
+                       case CVMX_HELPER_INTERFACE_MODE_GMII:
+                               priv->phy_mode = PHY_INTERFACE_MODE_GMII;
+                               dev->netdev_ops = &cvm_oct_rgmii_netdev_ops;
+                               strscpy(dev->name, "eth%d", sizeof(dev->name));
+                               break;
+
+                       case CVMX_HELPER_INTERFACE_MODE_RGMII:
+                               dev->netdev_ops = &cvm_oct_rgmii_netdev_ops;
+                               strscpy(dev->name, "eth%d", sizeof(dev->name));
+                               cvm_set_rgmii_delay(priv, interface,
+                                                   port_index);
+                               break;
+                       }
+
+                       if (!dev->netdev_ops) {
+                               free_netdev(dev);
+                       } else if (register_netdev(dev) < 0) {
+                               pr_err("Failed to register ethernet device for interface %d, port %d\n",
+                                      interface, priv->port);
+                               free_netdev(dev);
+                       } else {
+                               cvm_oct_device[priv->port] = dev;
+                               fau -=
+                                   cvmx_pko_get_num_queues(priv->port) *
+                                   sizeof(u32);
+                               schedule_delayed_work(&priv->port_periodic_work,
+                                                     HZ);
+                       }
+               }
+       }
+
+       cvm_oct_tx_initialize();
+       cvm_oct_rx_initialize();
+
+       /*
+        * 150 uS: about 10 1500-byte packets at 1GE.
+        */
+       cvm_oct_tx_poll_interval = 150 * (octeon_get_clock_rate() / 1000000);
+
+       schedule_delayed_work(&cvm_oct_rx_refill_work, HZ);
+
+       return 0;
+}
+
+static int cvm_oct_remove(struct platform_device *pdev)
+{
+       int port;
+
+       cvmx_ipd_disable();
+
+       atomic_inc_return(&cvm_oct_poll_queue_stopping);
+       cancel_delayed_work_sync(&cvm_oct_rx_refill_work);
+
+       cvm_oct_rx_shutdown();
+       cvm_oct_tx_shutdown();
+
+       cvmx_pko_disable();
+
+       /* Free the ethernet devices */
+       for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
+               if (cvm_oct_device[port]) {
+                       struct net_device *dev = cvm_oct_device[port];
+                       struct octeon_ethernet *priv = netdev_priv(dev);
+
+                       cancel_delayed_work_sync(&priv->port_periodic_work);
+
+                       cvm_oct_tx_shutdown_dev(dev);
+                       unregister_netdev(dev);
+                       free_netdev(dev);
+                       cvm_oct_device[port] = NULL;
+               }
+       }
+
+       cvmx_pko_shutdown();
+
+       cvmx_ipd_free_ptr();
+
+       /* Free the HW pools */
+       cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
+                             num_packet_buffers);
+       cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE,
+                             num_packet_buffers);
+       if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
+               cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
+                                     CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
+       return 0;
+}
+
+static const struct of_device_id cvm_oct_match[] = {
+       {
+               .compatible = "cavium,octeon-3860-pip",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, cvm_oct_match);
+
+static struct platform_driver cvm_oct_driver = {
+       .probe          = cvm_oct_probe,
+       .remove         = cvm_oct_remove,
+       .driver         = {
+               .name   = KBUILD_MODNAME,
+               .of_match_table = cvm_oct_match,
+       },
+};
+
+module_platform_driver(cvm_oct_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
+MODULE_DESCRIPTION("Cavium Networks Octeon ethernet driver.");
diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h
new file mode 100644 (file)
index 0000000..a614070
--- /dev/null
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file is based on code from OCTEON SDK by Cavium Networks.
+ *
+ * Copyright (c) 2003-2010 Cavium Networks
+ */
+
+/*
+ * External interface for the Cavium Octeon ethernet driver.
+ */
+#ifndef OCTEON_ETHERNET_H
+#define OCTEON_ETHERNET_H
+
+#include <linux/of.h>
+#include <linux/phy.h>
+
+#ifdef CONFIG_CAVIUM_OCTEON_SOC
+
+#include <asm/octeon/octeon.h>
+
+#include <asm/octeon/cvmx-asxx-defs.h>
+#include <asm/octeon/cvmx-config.h>
+#include <asm/octeon/cvmx-fau.h>
+#include <asm/octeon/cvmx-gmxx-defs.h>
+#include <asm/octeon/cvmx-helper.h>
+#include <asm/octeon/cvmx-helper-util.h>
+#include <asm/octeon/cvmx-ipd.h>
+#include <asm/octeon/cvmx-ipd-defs.h>
+#include <asm/octeon/cvmx-npi-defs.h>
+#include <asm/octeon/cvmx-pip.h>
+#include <asm/octeon/cvmx-pko.h>
+#include <asm/octeon/cvmx-pow.h>
+#include <asm/octeon/cvmx-scratch.h>
+#include <asm/octeon/cvmx-spi.h>
+#include <asm/octeon/cvmx-spxx-defs.h>
+#include <asm/octeon/cvmx-stxx-defs.h>
+#include <asm/octeon/cvmx-wqe.h>
+
+#else
+
+#include "octeon-stubs.h"
+
+#endif
+
+/**
+ * This is the definition of the Ethernet driver's private
+ * driver state stored in netdev_priv(dev).
+ */
+struct octeon_ethernet {
+       /* PKO hardware output port */
+       int port;
+       /* PKO hardware queue for the port */
+       int queue;
+       /* Hardware fetch and add to count outstanding tx buffers */
+       int fau;
+       /* My netdev. */
+       struct net_device *netdev;
+       /*
+        * Type of port. This is one of the enums in
+        * cvmx_helper_interface_mode_t
+        */
+       int imode;
+       /* PHY mode */
+       phy_interface_t phy_mode;
+       /* List of outstanding tx buffers per queue */
+       struct sk_buff_head tx_free_list[16];
+       unsigned int last_speed;
+       unsigned int last_link;
+       /* Last negotiated link state */
+       u64 link_info;
+       /* Called periodically to check link status */
+       void (*poll)(struct net_device *dev);
+       struct delayed_work     port_periodic_work;
+       struct device_node      *of_node;
+};
+
+int cvm_oct_free_work(void *work_queue_entry);
+
+int cvm_oct_rgmii_open(struct net_device *dev);
+
+int cvm_oct_sgmii_init(struct net_device *dev);
+int cvm_oct_sgmii_open(struct net_device *dev);
+
+int cvm_oct_spi_init(struct net_device *dev);
+void cvm_oct_spi_uninit(struct net_device *dev);
+
+int cvm_oct_common_init(struct net_device *dev);
+void cvm_oct_common_uninit(struct net_device *dev);
+void cvm_oct_adjust_link(struct net_device *dev);
+int cvm_oct_common_stop(struct net_device *dev);
+int cvm_oct_common_open(struct net_device *dev,
+                       void (*link_poll)(struct net_device *));
+void cvm_oct_note_carrier(struct octeon_ethernet *priv,
+                         union cvmx_helper_link_info li);
+void cvm_oct_link_poll(struct net_device *dev);
+
+extern int always_use_pow;
+extern int pow_send_group;
+extern int pow_receive_groups;
+extern char pow_send_list[];
+extern struct net_device *cvm_oct_device[];
+extern atomic_t cvm_oct_poll_queue_stopping;
+extern u64 cvm_oct_tx_poll_interval;
+
+extern int rx_napi_weight;
+
+#endif
diff --git a/drivers/staging/octeon/octeon-stubs.h b/drivers/staging/octeon/octeon-stubs.h
new file mode 100644 (file)
index 0000000..d067435
--- /dev/null
@@ -0,0 +1,1434 @@
+#define CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE       512
+
+#ifndef XKPHYS_TO_PHYS
+# define XKPHYS_TO_PHYS(p)                     (p)
+#endif
+
+#define OCTEON_IRQ_WORKQ0 0
+#define OCTEON_IRQ_RML 0
+#define OCTEON_IRQ_TIMER1 0
+#define OCTEON_IS_MODEL(x) 0
+#define octeon_has_feature(x)  0
+#define octeon_get_clock_rate()        0
+
+#define CVMX_SYNCIOBDMA                do { } while (0)
+
+#define CVMX_HELPER_INPUT_TAG_TYPE     0
+#define CVMX_HELPER_FIRST_MBUFF_SKIP   7
+#define CVMX_FAU_REG_END               (2048)
+#define CVMX_FPA_OUTPUT_BUFFER_POOL        (2)
+#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE    16
+#define CVMX_FPA_PACKET_POOL               (0)
+#define CVMX_FPA_PACKET_POOL_SIZE          16
+#define CVMX_FPA_WQE_POOL                  (1)
+#define CVMX_FPA_WQE_POOL_SIZE             16
+#define CVMX_GMXX_RXX_ADR_CAM_EN(a, b) ((a) + (b))
+#define CVMX_GMXX_RXX_ADR_CTL(a, b)    ((a) + (b))
+#define CVMX_GMXX_PRTX_CFG(a, b)       ((a) + (b))
+#define CVMX_GMXX_RXX_FRM_MAX(a, b)    ((a) + (b))
+#define CVMX_GMXX_RXX_JABBER(a, b)     ((a) + (b))
+#define CVMX_IPD_CTL_STATUS            0
+#define CVMX_PIP_FRM_LEN_CHKX(a)       (a)
+#define CVMX_PIP_NUM_INPUT_PORTS       1
+#define CVMX_SCR_SCRATCH               0
+#define CVMX_PKO_QUEUES_PER_PORT_INTERFACE0    2
+#define CVMX_PKO_QUEUES_PER_PORT_INTERFACE1    2
+#define CVMX_IPD_SUB_PORT_FCS          0
+#define CVMX_SSO_WQ_IQ_DIS             0
+#define CVMX_SSO_WQ_INT                        0
+#define CVMX_POW_WQ_INT                        0
+#define CVMX_SSO_WQ_INT_PC             0
+#define CVMX_NPI_RSL_INT_BLOCKS                0
+#define CVMX_POW_WQ_INT_PC             0
+
+union cvmx_pip_wqe_word2 {
+       uint64_t u64;
+       struct {
+               uint64_t bufs:8;
+               uint64_t ip_offset:8;
+               uint64_t vlan_valid:1;
+               uint64_t vlan_stacked:1;
+               uint64_t unassigned:1;
+               uint64_t vlan_cfi:1;
+               uint64_t vlan_id:12;
+               uint64_t pr:4;
+               uint64_t unassigned2:8;
+               uint64_t dec_ipcomp:1;
+               uint64_t tcp_or_udp:1;
+               uint64_t dec_ipsec:1;
+               uint64_t is_v6:1;
+               uint64_t software:1;
+               uint64_t L4_error:1;
+               uint64_t is_frag:1;
+               uint64_t IP_exc:1;
+               uint64_t is_bcast:1;
+               uint64_t is_mcast:1;
+               uint64_t not_IP:1;
+               uint64_t rcv_error:1;
+               uint64_t err_code:8;
+       } s;
+       struct {
+               uint64_t bufs:8;
+               uint64_t ip_offset:8;
+               uint64_t vlan_valid:1;
+               uint64_t vlan_stacked:1;
+               uint64_t unassigned:1;
+               uint64_t vlan_cfi:1;
+               uint64_t vlan_id:12;
+               uint64_t port:12;
+               uint64_t dec_ipcomp:1;
+               uint64_t tcp_or_udp:1;
+               uint64_t dec_ipsec:1;
+               uint64_t is_v6:1;
+               uint64_t software:1;
+               uint64_t L4_error:1;
+               uint64_t is_frag:1;
+               uint64_t IP_exc:1;
+               uint64_t is_bcast:1;
+               uint64_t is_mcast:1;
+               uint64_t not_IP:1;
+               uint64_t rcv_error:1;
+               uint64_t err_code:8;
+       } s_cn68xx;
+
+       struct {
+               uint64_t unused1:16;
+               uint64_t vlan:16;
+               uint64_t unused2:32;
+       } svlan;
+       struct {
+               uint64_t bufs:8;
+               uint64_t unused:8;
+               uint64_t vlan_valid:1;
+               uint64_t vlan_stacked:1;
+               uint64_t unassigned:1;
+               uint64_t vlan_cfi:1;
+               uint64_t vlan_id:12;
+               uint64_t pr:4;
+               uint64_t unassigned2:12;
+               uint64_t software:1;
+               uint64_t unassigned3:1;
+               uint64_t is_rarp:1;
+               uint64_t is_arp:1;
+               uint64_t is_bcast:1;
+               uint64_t is_mcast:1;
+               uint64_t not_IP:1;
+               uint64_t rcv_error:1;
+               uint64_t err_code:8;
+       } snoip;
+
+};
+
+union cvmx_pip_wqe_word0 {
+       struct {
+               uint64_t next_ptr:40;
+               uint8_t unused;
+               __wsum hw_chksum;
+       } cn38xx;
+       struct {
+               uint64_t pknd:6;        /* 0..5 */
+               uint64_t unused2:2;     /* 6..7 */
+               uint64_t bpid:6;        /* 8..13 */
+               uint64_t unused1:18;    /* 14..31 */
+               uint64_t l2ptr:8;       /* 32..39 */
+               uint64_t l3ptr:8;       /* 40..47 */
+               uint64_t unused0:8;     /* 48..55 */
+               uint64_t l4ptr:8;       /* 56..63 */
+       } cn68xx;
+};
+
+union cvmx_wqe_word0 {
+       uint64_t u64;
+       union cvmx_pip_wqe_word0 pip;
+};
+
+union cvmx_wqe_word1 {
+       uint64_t u64;
+       struct {
+               uint64_t tag:32;
+               uint64_t tag_type:2;
+               uint64_t varies:14;
+               uint64_t len:16;
+       };
+       struct {
+               uint64_t tag:32;
+               uint64_t tag_type:2;
+               uint64_t zero_2:3;
+               uint64_t grp:6;
+               uint64_t zero_1:1;
+               uint64_t qos:3;
+               uint64_t zero_0:1;
+               uint64_t len:16;
+       } cn68xx;
+       struct {
+               uint64_t tag:32;
+               uint64_t tag_type:2;
+               uint64_t zero_2:1;
+               uint64_t grp:4;
+               uint64_t qos:3;
+               uint64_t ipprt:6;
+               uint64_t len:16;
+       } cn38xx;
+};
+
+union cvmx_buf_ptr {
+       void *ptr;
+       uint64_t u64;
+       struct {
+               uint64_t i:1;
+               uint64_t back:4;
+               uint64_t pool:3;
+               uint64_t size:16;
+               uint64_t addr:40;
+       } s;
+};
+
+struct cvmx_wqe {
+       union cvmx_wqe_word0 word0;
+       union cvmx_wqe_word1 word1;
+       union cvmx_pip_wqe_word2 word2;
+       union cvmx_buf_ptr packet_ptr;
+       uint8_t packet_data[96];
+};
+
+union cvmx_helper_link_info {
+       uint64_t u64;
+       struct {
+               uint64_t reserved_20_63:44;
+               uint64_t link_up:1;         /**< Is the physical link up? */
+               uint64_t full_duplex:1;     /**< 1 if the link is full duplex */
+               uint64_t speed:18;          /**< Speed of the link in Mbps */
+       } s;
+};
+
+enum cvmx_fau_reg_32 {
+       CVMX_FAU_REG_32_START   = 0,
+};
+
+enum cvmx_fau_op_size {
+       CVMX_FAU_OP_SIZE_8 = 0,
+       CVMX_FAU_OP_SIZE_16 = 1,
+       CVMX_FAU_OP_SIZE_32 = 2,
+       CVMX_FAU_OP_SIZE_64 = 3
+};
+
+typedef enum {
+       CVMX_SPI_MODE_UNKNOWN = 0,
+       CVMX_SPI_MODE_TX_HALFPLEX = 1,
+       CVMX_SPI_MODE_RX_HALFPLEX = 2,
+       CVMX_SPI_MODE_DUPLEX = 3
+} cvmx_spi_mode_t;
+
+typedef enum {
+       CVMX_HELPER_INTERFACE_MODE_DISABLED,
+       CVMX_HELPER_INTERFACE_MODE_RGMII,
+       CVMX_HELPER_INTERFACE_MODE_GMII,
+       CVMX_HELPER_INTERFACE_MODE_SPI,
+       CVMX_HELPER_INTERFACE_MODE_PCIE,
+       CVMX_HELPER_INTERFACE_MODE_XAUI,
+       CVMX_HELPER_INTERFACE_MODE_SGMII,
+       CVMX_HELPER_INTERFACE_MODE_PICMG,
+       CVMX_HELPER_INTERFACE_MODE_NPI,
+       CVMX_HELPER_INTERFACE_MODE_LOOP,
+} cvmx_helper_interface_mode_t;
+
+typedef enum {
+       CVMX_POW_WAIT = 1,
+       CVMX_POW_NO_WAIT = 0,
+} cvmx_pow_wait_t;
+
+typedef enum {
+       CVMX_PKO_LOCK_NONE = 0,
+       CVMX_PKO_LOCK_ATOMIC_TAG = 1,
+       CVMX_PKO_LOCK_CMD_QUEUE = 2,
+} cvmx_pko_lock_t;
+
+typedef enum {
+       CVMX_PKO_SUCCESS,
+       CVMX_PKO_INVALID_PORT,
+       CVMX_PKO_INVALID_QUEUE,
+       CVMX_PKO_INVALID_PRIORITY,
+       CVMX_PKO_NO_MEMORY,
+       CVMX_PKO_PORT_ALREADY_SETUP,
+       CVMX_PKO_CMD_QUEUE_INIT_ERROR
+} cvmx_pko_status_t;
+
+enum cvmx_pow_tag_type {
+       CVMX_POW_TAG_TYPE_ORDERED   = 0L,
+       CVMX_POW_TAG_TYPE_ATOMIC    = 1L,
+       CVMX_POW_TAG_TYPE_NULL      = 2L,
+       CVMX_POW_TAG_TYPE_NULL_NULL = 3L
+};
+
+union cvmx_ipd_ctl_status {
+       uint64_t u64;
+       struct cvmx_ipd_ctl_status_s {
+               uint64_t reserved_18_63:46;
+               uint64_t use_sop:1;
+               uint64_t rst_done:1;
+               uint64_t clken:1;
+               uint64_t no_wptr:1;
+               uint64_t pq_apkt:1;
+               uint64_t pq_nabuf:1;
+               uint64_t ipd_full:1;
+               uint64_t pkt_off:1;
+               uint64_t len_m8:1;
+               uint64_t reset:1;
+               uint64_t addpkt:1;
+               uint64_t naddbuf:1;
+               uint64_t pkt_lend:1;
+               uint64_t wqe_lend:1;
+               uint64_t pbp_en:1;
+               uint64_t opc_mode:2;
+               uint64_t ipd_en:1;
+       } s;
+       struct cvmx_ipd_ctl_status_cn30xx {
+               uint64_t reserved_10_63:54;
+               uint64_t len_m8:1;
+               uint64_t reset:1;
+               uint64_t addpkt:1;
+               uint64_t naddbuf:1;
+               uint64_t pkt_lend:1;
+               uint64_t wqe_lend:1;
+               uint64_t pbp_en:1;
+               uint64_t opc_mode:2;
+               uint64_t ipd_en:1;
+       } cn30xx;
+       struct cvmx_ipd_ctl_status_cn38xxp2 {
+               uint64_t reserved_9_63:55;
+               uint64_t reset:1;
+               uint64_t addpkt:1;
+               uint64_t naddbuf:1;
+               uint64_t pkt_lend:1;
+               uint64_t wqe_lend:1;
+               uint64_t pbp_en:1;
+               uint64_t opc_mode:2;
+               uint64_t ipd_en:1;
+       } cn38xxp2;
+       struct cvmx_ipd_ctl_status_cn50xx {
+               uint64_t reserved_15_63:49;
+               uint64_t no_wptr:1;
+               uint64_t pq_apkt:1;
+               uint64_t pq_nabuf:1;
+               uint64_t ipd_full:1;
+               uint64_t pkt_off:1;
+               uint64_t len_m8:1;
+               uint64_t reset:1;
+               uint64_t addpkt:1;
+               uint64_t naddbuf:1;
+               uint64_t pkt_lend:1;
+               uint64_t wqe_lend:1;
+               uint64_t pbp_en:1;
+               uint64_t opc_mode:2;
+               uint64_t ipd_en:1;
+       } cn50xx;
+       struct cvmx_ipd_ctl_status_cn58xx {
+               uint64_t reserved_12_63:52;
+               uint64_t ipd_full:1;
+               uint64_t pkt_off:1;
+               uint64_t len_m8:1;
+               uint64_t reset:1;
+               uint64_t addpkt:1;
+               uint64_t naddbuf:1;
+               uint64_t pkt_lend:1;
+               uint64_t wqe_lend:1;
+               uint64_t pbp_en:1;
+               uint64_t opc_mode:2;
+               uint64_t ipd_en:1;
+       } cn58xx;
+       struct cvmx_ipd_ctl_status_cn63xxp1 {
+               uint64_t reserved_16_63:48;
+               uint64_t clken:1;
+               uint64_t no_wptr:1;
+               uint64_t pq_apkt:1;
+               uint64_t pq_nabuf:1;
+               uint64_t ipd_full:1;
+               uint64_t pkt_off:1;
+               uint64_t len_m8:1;
+               uint64_t reset:1;
+               uint64_t addpkt:1;
+               uint64_t naddbuf:1;
+               uint64_t pkt_lend:1;
+               uint64_t wqe_lend:1;
+               uint64_t pbp_en:1;
+               uint64_t opc_mode:2;
+               uint64_t ipd_en:1;
+       } cn63xxp1;
+};
+
+union cvmx_ipd_sub_port_fcs {
+       uint64_t u64;
+       struct cvmx_ipd_sub_port_fcs_s {
+               uint64_t port_bit:32;
+               uint64_t reserved_32_35:4;
+               uint64_t port_bit2:4;
+               uint64_t reserved_40_63:24;
+       } s;
+       struct cvmx_ipd_sub_port_fcs_cn30xx {
+               uint64_t port_bit:3;
+               uint64_t reserved_3_63:61;
+       } cn30xx;
+       struct cvmx_ipd_sub_port_fcs_cn38xx {
+               uint64_t port_bit:32;
+               uint64_t reserved_32_63:32;
+       } cn38xx;
+};
+
+union cvmx_ipd_sub_port_qos_cnt {
+       uint64_t u64;
+       struct cvmx_ipd_sub_port_qos_cnt_s {
+               uint64_t cnt:32;
+               uint64_t port_qos:9;
+               uint64_t reserved_41_63:23;
+       } s;
+};
+
+typedef struct {
+       uint32_t dropped_octets;
+       uint32_t dropped_packets;
+       uint32_t pci_raw_packets;
+       uint32_t octets;
+       uint32_t packets;
+       uint32_t multicast_packets;
+       uint32_t broadcast_packets;
+       uint32_t len_64_packets;
+       uint32_t len_65_127_packets;
+       uint32_t len_128_255_packets;
+       uint32_t len_256_511_packets;
+       uint32_t len_512_1023_packets;
+       uint32_t len_1024_1518_packets;
+       uint32_t len_1519_max_packets;
+       uint32_t fcs_align_err_packets;
+       uint32_t runt_packets;
+       uint32_t runt_crc_packets;
+       uint32_t oversize_packets;
+       uint32_t oversize_crc_packets;
+       uint32_t inb_packets;
+       uint64_t inb_octets;
+       uint16_t inb_errors;
+} cvmx_pip_port_status_t;
+
+typedef struct {
+       uint32_t packets;
+       uint64_t octets;
+       uint64_t doorbell;
+} cvmx_pko_port_status_t;
+
+union cvmx_pip_frm_len_chkx {
+       uint64_t u64;
+       struct cvmx_pip_frm_len_chkx_s {
+               uint64_t reserved_32_63:32;
+               uint64_t maxlen:16;
+               uint64_t minlen:16;
+       } s;
+};
+
+union cvmx_gmxx_rxx_frm_ctl {
+       uint64_t u64;
+       struct cvmx_gmxx_rxx_frm_ctl_s {
+               uint64_t pre_chk:1;
+               uint64_t pre_strp:1;
+               uint64_t ctl_drp:1;
+               uint64_t ctl_bck:1;
+               uint64_t ctl_mcst:1;
+               uint64_t ctl_smac:1;
+               uint64_t pre_free:1;
+               uint64_t vlan_len:1;
+               uint64_t pad_len:1;
+               uint64_t pre_align:1;
+               uint64_t null_dis:1;
+               uint64_t reserved_11_11:1;
+               uint64_t ptp_mode:1;
+               uint64_t reserved_13_63:51;
+       } s;
+       struct cvmx_gmxx_rxx_frm_ctl_cn30xx {
+               uint64_t pre_chk:1;
+               uint64_t pre_strp:1;
+               uint64_t ctl_drp:1;
+               uint64_t ctl_bck:1;
+               uint64_t ctl_mcst:1;
+               uint64_t ctl_smac:1;
+               uint64_t pre_free:1;
+               uint64_t vlan_len:1;
+               uint64_t pad_len:1;
+               uint64_t reserved_9_63:55;
+       } cn30xx;
+       struct cvmx_gmxx_rxx_frm_ctl_cn31xx {
+               uint64_t pre_chk:1;
+               uint64_t pre_strp:1;
+               uint64_t ctl_drp:1;
+               uint64_t ctl_bck:1;
+               uint64_t ctl_mcst:1;
+               uint64_t ctl_smac:1;
+               uint64_t pre_free:1;
+               uint64_t vlan_len:1;
+               uint64_t reserved_8_63:56;
+       } cn31xx;
+       struct cvmx_gmxx_rxx_frm_ctl_cn50xx {
+               uint64_t pre_chk:1;
+               uint64_t pre_strp:1;
+               uint64_t ctl_drp:1;
+               uint64_t ctl_bck:1;
+               uint64_t ctl_mcst:1;
+               uint64_t ctl_smac:1;
+               uint64_t pre_free:1;
+               uint64_t reserved_7_8:2;
+               uint64_t pre_align:1;
+               uint64_t null_dis:1;
+               uint64_t reserved_11_63:53;
+       } cn50xx;
+       struct cvmx_gmxx_rxx_frm_ctl_cn56xxp1 {
+               uint64_t pre_chk:1;
+               uint64_t pre_strp:1;
+               uint64_t ctl_drp:1;
+               uint64_t ctl_bck:1;
+               uint64_t ctl_mcst:1;
+               uint64_t ctl_smac:1;
+               uint64_t pre_free:1;
+               uint64_t reserved_7_8:2;
+               uint64_t pre_align:1;
+               uint64_t reserved_10_63:54;
+       } cn56xxp1;
+       struct cvmx_gmxx_rxx_frm_ctl_cn58xx {
+               uint64_t pre_chk:1;
+               uint64_t pre_strp:1;
+               uint64_t ctl_drp:1;
+               uint64_t ctl_bck:1;
+               uint64_t ctl_mcst:1;
+               uint64_t ctl_smac:1;
+               uint64_t pre_free:1;
+               uint64_t vlan_len:1;
+               uint64_t pad_len:1;
+               uint64_t pre_align:1;
+               uint64_t null_dis:1;
+               uint64_t reserved_11_63:53;
+       } cn58xx;
+       struct cvmx_gmxx_rxx_frm_ctl_cn61xx {
+               uint64_t pre_chk:1;
+               uint64_t pre_strp:1;
+               uint64_t ctl_drp:1;
+               uint64_t ctl_bck:1;
+               uint64_t ctl_mcst:1;
+               uint64_t ctl_smac:1;
+               uint64_t pre_free:1;
+               uint64_t reserved_7_8:2;
+               uint64_t pre_align:1;
+               uint64_t null_dis:1;
+               uint64_t reserved_11_11:1;
+               uint64_t ptp_mode:1;
+               uint64_t reserved_13_63:51;
+       } cn61xx;
+};
+
+union cvmx_gmxx_rxx_int_reg {
+       uint64_t u64;
+       struct cvmx_gmxx_rxx_int_reg_s {
+               uint64_t minerr:1;
+               uint64_t carext:1;
+               uint64_t maxerr:1;
+               uint64_t jabber:1;
+               uint64_t fcserr:1;
+               uint64_t alnerr:1;
+               uint64_t lenerr:1;
+               uint64_t rcverr:1;
+               uint64_t skperr:1;
+               uint64_t niberr:1;
+               uint64_t ovrerr:1;
+               uint64_t pcterr:1;
+               uint64_t rsverr:1;
+               uint64_t falerr:1;
+               uint64_t coldet:1;
+               uint64_t ifgerr:1;
+               uint64_t phy_link:1;
+               uint64_t phy_spd:1;
+               uint64_t phy_dupx:1;
+               uint64_t pause_drp:1;
+               uint64_t loc_fault:1;
+               uint64_t rem_fault:1;
+               uint64_t bad_seq:1;
+               uint64_t bad_term:1;
+               uint64_t unsop:1;
+               uint64_t uneop:1;
+               uint64_t undat:1;
+               uint64_t hg2fld:1;
+               uint64_t hg2cc:1;
+               uint64_t reserved_29_63:35;
+       } s;
+       struct cvmx_gmxx_rxx_int_reg_cn30xx {
+               uint64_t minerr:1;
+               uint64_t carext:1;
+               uint64_t maxerr:1;
+               uint64_t jabber:1;
+               uint64_t fcserr:1;
+               uint64_t alnerr:1;
+               uint64_t lenerr:1;
+               uint64_t rcverr:1;
+               uint64_t skperr:1;
+               uint64_t niberr:1;
+               uint64_t ovrerr:1;
+               uint64_t pcterr:1;
+               uint64_t rsverr:1;
+               uint64_t falerr:1;
+               uint64_t coldet:1;
+               uint64_t ifgerr:1;
+               uint64_t phy_link:1;
+               uint64_t phy_spd:1;
+               uint64_t phy_dupx:1;
+               uint64_t reserved_19_63:45;
+       } cn30xx;
+       struct cvmx_gmxx_rxx_int_reg_cn50xx {
+               uint64_t reserved_0_0:1;
+               uint64_t carext:1;
+               uint64_t reserved_2_2:1;
+               uint64_t jabber:1;
+               uint64_t fcserr:1;
+               uint64_t alnerr:1;
+               uint64_t reserved_6_6:1;
+               uint64_t rcverr:1;
+               uint64_t skperr:1;
+               uint64_t niberr:1;
+               uint64_t ovrerr:1;
+               uint64_t pcterr:1;
+               uint64_t rsverr:1;
+               uint64_t falerr:1;
+               uint64_t coldet:1;
+               uint64_t ifgerr:1;
+               uint64_t phy_link:1;
+               uint64_t phy_spd:1;
+               uint64_t phy_dupx:1;
+               uint64_t pause_drp:1;
+               uint64_t reserved_20_63:44;
+       } cn50xx;
+       struct cvmx_gmxx_rxx_int_reg_cn52xx {
+               uint64_t reserved_0_0:1;
+               uint64_t carext:1;
+               uint64_t reserved_2_2:1;
+               uint64_t jabber:1;
+               uint64_t fcserr:1;
+               uint64_t reserved_5_6:2;
+               uint64_t rcverr:1;
+               uint64_t skperr:1;
+               uint64_t reserved_9_9:1;
+               uint64_t ovrerr:1;
+               uint64_t pcterr:1;
+               uint64_t rsverr:1;
+               uint64_t falerr:1;
+               uint64_t coldet:1;
+               uint64_t ifgerr:1;
+               uint64_t reserved_16_18:3;
+               uint64_t pause_drp:1;
+               uint64_t loc_fault:1;
+               uint64_t rem_fault:1;
+               uint64_t bad_seq:1;
+               uint64_t bad_term:1;
+               uint64_t unsop:1;
+               uint64_t uneop:1;
+               uint64_t undat:1;
+               uint64_t hg2fld:1;
+               uint64_t hg2cc:1;
+               uint64_t reserved_29_63:35;
+       } cn52xx;
+       struct cvmx_gmxx_rxx_int_reg_cn56xxp1 {
+               uint64_t reserved_0_0:1;
+               uint64_t carext:1;
+               uint64_t reserved_2_2:1;
+               uint64_t jabber:1;
+               uint64_t fcserr:1;
+               uint64_t reserved_5_6:2;
+               uint64_t rcverr:1;
+               uint64_t skperr:1;
+               uint64_t reserved_9_9:1;
+               uint64_t ovrerr:1;
+               uint64_t pcterr:1;
+               uint64_t rsverr:1;
+               uint64_t falerr:1;
+               uint64_t coldet:1;
+               uint64_t ifgerr:1;
+               uint64_t reserved_16_18:3;
+               uint64_t pause_drp:1;
+               uint64_t loc_fault:1;
+               uint64_t rem_fault:1;
+               uint64_t bad_seq:1;
+               uint64_t bad_term:1;
+               uint64_t unsop:1;
+               uint64_t uneop:1;
+               uint64_t undat:1;
+               uint64_t reserved_27_63:37;
+       } cn56xxp1;
+       struct cvmx_gmxx_rxx_int_reg_cn58xx {
+               uint64_t minerr:1;
+               uint64_t carext:1;
+               uint64_t maxerr:1;
+               uint64_t jabber:1;
+               uint64_t fcserr:1;
+               uint64_t alnerr:1;
+               uint64_t lenerr:1;
+               uint64_t rcverr:1;
+               uint64_t skperr:1;
+               uint64_t niberr:1;
+               uint64_t ovrerr:1;
+               uint64_t pcterr:1;
+               uint64_t rsverr:1;
+               uint64_t falerr:1;
+               uint64_t coldet:1;
+               uint64_t ifgerr:1;
+               uint64_t phy_link:1;
+               uint64_t phy_spd:1;
+               uint64_t phy_dupx:1;
+               uint64_t pause_drp:1;
+               uint64_t reserved_20_63:44;
+       } cn58xx;
+       struct cvmx_gmxx_rxx_int_reg_cn61xx {
+               uint64_t minerr:1;
+               uint64_t carext:1;
+               uint64_t reserved_2_2:1;
+               uint64_t jabber:1;
+               uint64_t fcserr:1;
+               uint64_t reserved_5_6:2;
+               uint64_t rcverr:1;
+               uint64_t skperr:1;
+               uint64_t reserved_9_9:1;
+               uint64_t ovrerr:1;
+               uint64_t pcterr:1;
+               uint64_t rsverr:1;
+               uint64_t falerr:1;
+               uint64_t coldet:1;
+               uint64_t ifgerr:1;
+               uint64_t reserved_16_18:3;
+               uint64_t pause_drp:1;
+               uint64_t loc_fault:1;
+               uint64_t rem_fault:1;
+               uint64_t bad_seq:1;
+               uint64_t bad_term:1;
+               uint64_t unsop:1;
+               uint64_t uneop:1;
+               uint64_t undat:1;
+               uint64_t hg2fld:1;
+               uint64_t hg2cc:1;
+               uint64_t reserved_29_63:35;
+       } cn61xx;
+};
+
+union cvmx_gmxx_prtx_cfg {
+       uint64_t u64;
+       struct cvmx_gmxx_prtx_cfg_s {
+               uint64_t reserved_22_63:42;
+               uint64_t pknd:6;
+               uint64_t reserved_14_15:2;
+               uint64_t tx_idle:1;
+               uint64_t rx_idle:1;
+               uint64_t reserved_9_11:3;
+               uint64_t speed_msb:1;
+               uint64_t reserved_4_7:4;
+               uint64_t slottime:1;
+               uint64_t duplex:1;
+               uint64_t speed:1;
+               uint64_t en:1;
+       } s;
+       struct cvmx_gmxx_prtx_cfg_cn30xx {
+               uint64_t reserved_4_63:60;
+               uint64_t slottime:1;
+               uint64_t duplex:1;
+               uint64_t speed:1;
+               uint64_t en:1;
+       } cn30xx;
+       struct cvmx_gmxx_prtx_cfg_cn52xx {
+               uint64_t reserved_14_63:50;
+               uint64_t tx_idle:1;
+               uint64_t rx_idle:1;
+               uint64_t reserved_9_11:3;
+               uint64_t speed_msb:1;
+               uint64_t reserved_4_7:4;
+               uint64_t slottime:1;
+               uint64_t duplex:1;
+               uint64_t speed:1;
+               uint64_t en:1;
+       } cn52xx;
+};
+
+union cvmx_gmxx_rxx_adr_ctl {
+       uint64_t u64;
+       struct cvmx_gmxx_rxx_adr_ctl_s {
+               uint64_t reserved_4_63:60;
+               uint64_t cam_mode:1;
+               uint64_t mcst:2;
+               uint64_t bcst:1;
+       } s;
+};
+
+union cvmx_pip_prt_tagx {
+       uint64_t u64;
+       struct cvmx_pip_prt_tagx_s {
+               uint64_t reserved_54_63:10;
+               uint64_t portadd_en:1;
+               uint64_t inc_hwchk:1;
+               uint64_t reserved_50_51:2;
+               uint64_t grptagbase_msb:2;
+               uint64_t reserved_46_47:2;
+               uint64_t grptagmask_msb:2;
+               uint64_t reserved_42_43:2;
+               uint64_t grp_msb:2;
+               uint64_t grptagbase:4;
+               uint64_t grptagmask:4;
+               uint64_t grptag:1;
+               uint64_t grptag_mskip:1;
+               uint64_t tag_mode:2;
+               uint64_t inc_vs:2;
+               uint64_t inc_vlan:1;
+               uint64_t inc_prt_flag:1;
+               uint64_t ip6_dprt_flag:1;
+               uint64_t ip4_dprt_flag:1;
+               uint64_t ip6_sprt_flag:1;
+               uint64_t ip4_sprt_flag:1;
+               uint64_t ip6_nxth_flag:1;
+               uint64_t ip4_pctl_flag:1;
+               uint64_t ip6_dst_flag:1;
+               uint64_t ip4_dst_flag:1;
+               uint64_t ip6_src_flag:1;
+               uint64_t ip4_src_flag:1;
+               uint64_t tcp6_tag_type:2;
+               uint64_t tcp4_tag_type:2;
+               uint64_t ip6_tag_type:2;
+               uint64_t ip4_tag_type:2;
+               uint64_t non_tag_type:2;
+               uint64_t grp:4;
+       } s;
+       struct cvmx_pip_prt_tagx_cn30xx {
+               uint64_t reserved_40_63:24;
+               uint64_t grptagbase:4;
+               uint64_t grptagmask:4;
+               uint64_t grptag:1;
+               uint64_t reserved_30_30:1;
+               uint64_t tag_mode:2;
+               uint64_t inc_vs:2;
+               uint64_t inc_vlan:1;
+               uint64_t inc_prt_flag:1;
+               uint64_t ip6_dprt_flag:1;
+               uint64_t ip4_dprt_flag:1;
+               uint64_t ip6_sprt_flag:1;
+               uint64_t ip4_sprt_flag:1;
+               uint64_t ip6_nxth_flag:1;
+               uint64_t ip4_pctl_flag:1;
+               uint64_t ip6_dst_flag:1;
+               uint64_t ip4_dst_flag:1;
+               uint64_t ip6_src_flag:1;
+               uint64_t ip4_src_flag:1;
+               uint64_t tcp6_tag_type:2;
+               uint64_t tcp4_tag_type:2;
+               uint64_t ip6_tag_type:2;
+               uint64_t ip4_tag_type:2;
+               uint64_t non_tag_type:2;
+               uint64_t grp:4;
+       } cn30xx;
+       struct cvmx_pip_prt_tagx_cn50xx {
+               uint64_t reserved_40_63:24;
+               uint64_t grptagbase:4;
+               uint64_t grptagmask:4;
+               uint64_t grptag:1;
+               uint64_t grptag_mskip:1;
+               uint64_t tag_mode:2;
+               uint64_t inc_vs:2;
+               uint64_t inc_vlan:1;
+               uint64_t inc_prt_flag:1;
+               uint64_t ip6_dprt_flag:1;
+               uint64_t ip4_dprt_flag:1;
+               uint64_t ip6_sprt_flag:1;
+               uint64_t ip4_sprt_flag:1;
+               uint64_t ip6_nxth_flag:1;
+               uint64_t ip4_pctl_flag:1;
+               uint64_t ip6_dst_flag:1;
+               uint64_t ip4_dst_flag:1;
+               uint64_t ip6_src_flag:1;
+               uint64_t ip4_src_flag:1;
+               uint64_t tcp6_tag_type:2;
+               uint64_t tcp4_tag_type:2;
+               uint64_t ip6_tag_type:2;
+               uint64_t ip4_tag_type:2;
+               uint64_t non_tag_type:2;
+               uint64_t grp:4;
+       } cn50xx;
+};
+
+union cvmx_spxx_int_reg {
+       uint64_t u64;
+       struct cvmx_spxx_int_reg_s {
+               uint64_t reserved_32_63:32;
+               uint64_t spf:1;
+               uint64_t reserved_12_30:19;
+               uint64_t calerr:1;
+               uint64_t syncerr:1;
+               uint64_t diperr:1;
+               uint64_t tpaovr:1;
+               uint64_t rsverr:1;
+               uint64_t drwnng:1;
+               uint64_t clserr:1;
+               uint64_t spiovr:1;
+               uint64_t reserved_2_3:2;
+               uint64_t abnorm:1;
+               uint64_t prtnxa:1;
+       } s;
+};
+
+union cvmx_spxx_int_msk {
+       uint64_t u64;
+       struct cvmx_spxx_int_msk_s {
+               uint64_t reserved_12_63:52;
+               uint64_t calerr:1;
+               uint64_t syncerr:1;
+               uint64_t diperr:1;
+               uint64_t tpaovr:1;
+               uint64_t rsverr:1;
+               uint64_t drwnng:1;
+               uint64_t clserr:1;
+               uint64_t spiovr:1;
+               uint64_t reserved_2_3:2;
+               uint64_t abnorm:1;
+               uint64_t prtnxa:1;
+       } s;
+};
+
+union cvmx_pow_wq_int {
+       uint64_t u64;
+       struct cvmx_pow_wq_int_s {
+               uint64_t wq_int:16;
+               uint64_t iq_dis:16;
+               uint64_t reserved_32_63:32;
+       } s;
+};
+
+union cvmx_sso_wq_int_thrx {
+       uint64_t u64;
+       struct {
+               uint64_t iq_thr:12;
+               uint64_t reserved_12_13:2;
+               uint64_t ds_thr:12;
+               uint64_t reserved_26_27:2;
+               uint64_t tc_thr:4;
+               uint64_t tc_en:1;
+               uint64_t reserved_33_63:31;
+       } s;
+};
+
+union cvmx_stxx_int_reg {
+       uint64_t u64;
+       struct cvmx_stxx_int_reg_s {
+               uint64_t reserved_9_63:55;
+               uint64_t syncerr:1;
+               uint64_t frmerr:1;
+               uint64_t unxfrm:1;
+               uint64_t nosync:1;
+               uint64_t diperr:1;
+               uint64_t datovr:1;
+               uint64_t ovrbst:1;
+               uint64_t calpar1:1;
+               uint64_t calpar0:1;
+       } s;
+};
+
+union cvmx_stxx_int_msk {
+       uint64_t u64;
+       struct cvmx_stxx_int_msk_s {
+               uint64_t reserved_8_63:56;
+               uint64_t frmerr:1;
+               uint64_t unxfrm:1;
+               uint64_t nosync:1;
+               uint64_t diperr:1;
+               uint64_t datovr:1;
+               uint64_t ovrbst:1;
+               uint64_t calpar1:1;
+               uint64_t calpar0:1;
+       } s;
+};
+
+union cvmx_pow_wq_int_pc {
+       uint64_t u64;
+       struct cvmx_pow_wq_int_pc_s {
+               uint64_t reserved_0_7:8;
+               uint64_t pc_thr:20;
+               uint64_t reserved_28_31:4;
+               uint64_t pc:28;
+               uint64_t reserved_60_63:4;
+       } s;
+};
+
+union cvmx_pow_wq_int_thrx {
+       uint64_t u64;
+       struct cvmx_pow_wq_int_thrx_s {
+               uint64_t reserved_29_63:35;
+               uint64_t tc_en:1;
+               uint64_t tc_thr:4;
+               uint64_t reserved_23_23:1;
+               uint64_t ds_thr:11;
+               uint64_t reserved_11_11:1;
+               uint64_t iq_thr:11;
+       } s;
+       struct cvmx_pow_wq_int_thrx_cn30xx {
+               uint64_t reserved_29_63:35;
+               uint64_t tc_en:1;
+               uint64_t tc_thr:4;
+               uint64_t reserved_18_23:6;
+               uint64_t ds_thr:6;
+               uint64_t reserved_6_11:6;
+               uint64_t iq_thr:6;
+       } cn30xx;
+       struct cvmx_pow_wq_int_thrx_cn31xx {
+               uint64_t reserved_29_63:35;
+               uint64_t tc_en:1;
+               uint64_t tc_thr:4;
+               uint64_t reserved_20_23:4;
+               uint64_t ds_thr:8;
+               uint64_t reserved_8_11:4;
+               uint64_t iq_thr:8;
+       } cn31xx;
+       struct cvmx_pow_wq_int_thrx_cn52xx {
+               uint64_t reserved_29_63:35;
+               uint64_t tc_en:1;
+               uint64_t tc_thr:4;
+               uint64_t reserved_21_23:3;
+               uint64_t ds_thr:9;
+               uint64_t reserved_9_11:3;
+               uint64_t iq_thr:9;
+       } cn52xx;
+       struct cvmx_pow_wq_int_thrx_cn63xx {
+               uint64_t reserved_29_63:35;
+               uint64_t tc_en:1;
+               uint64_t tc_thr:4;
+               uint64_t reserved_22_23:2;
+               uint64_t ds_thr:10;
+               uint64_t reserved_10_11:2;
+               uint64_t iq_thr:10;
+       } cn63xx;
+};
+
+union cvmx_npi_rsl_int_blocks {
+       uint64_t u64;
+       struct cvmx_npi_rsl_int_blocks_s {
+               uint64_t reserved_32_63:32;
+               uint64_t rint_31:1;
+               uint64_t iob:1;
+               uint64_t reserved_28_29:2;
+               uint64_t rint_27:1;
+               uint64_t rint_26:1;
+               uint64_t rint_25:1;
+               uint64_t rint_24:1;
+               uint64_t asx1:1;
+               uint64_t asx0:1;
+               uint64_t rint_21:1;
+               uint64_t pip:1;
+               uint64_t spx1:1;
+               uint64_t spx0:1;
+               uint64_t lmc:1;
+               uint64_t l2c:1;
+               uint64_t rint_15:1;
+               uint64_t reserved_13_14:2;
+               uint64_t pow:1;
+               uint64_t tim:1;
+               uint64_t pko:1;
+               uint64_t ipd:1;
+               uint64_t rint_8:1;
+               uint64_t zip:1;
+               uint64_t dfa:1;
+               uint64_t fpa:1;
+               uint64_t key:1;
+               uint64_t npi:1;
+               uint64_t gmx1:1;
+               uint64_t gmx0:1;
+               uint64_t mio:1;
+       } s;
+       struct cvmx_npi_rsl_int_blocks_cn30xx {
+               uint64_t reserved_32_63:32;
+               uint64_t rint_31:1;
+               uint64_t iob:1;
+               uint64_t rint_29:1;
+               uint64_t rint_28:1;
+               uint64_t rint_27:1;
+               uint64_t rint_26:1;
+               uint64_t rint_25:1;
+               uint64_t rint_24:1;
+               uint64_t asx1:1;
+               uint64_t asx0:1;
+               uint64_t rint_21:1;
+               uint64_t pip:1;
+               uint64_t spx1:1;
+               uint64_t spx0:1;
+               uint64_t lmc:1;
+               uint64_t l2c:1;
+               uint64_t rint_15:1;
+               uint64_t rint_14:1;
+               uint64_t usb:1;
+               uint64_t pow:1;
+               uint64_t tim:1;
+               uint64_t pko:1;
+               uint64_t ipd:1;
+               uint64_t rint_8:1;
+               uint64_t zip:1;
+               uint64_t dfa:1;
+               uint64_t fpa:1;
+               uint64_t key:1;
+               uint64_t npi:1;
+               uint64_t gmx1:1;
+               uint64_t gmx0:1;
+               uint64_t mio:1;
+       } cn30xx;
+       struct cvmx_npi_rsl_int_blocks_cn38xx {
+               uint64_t reserved_32_63:32;
+               uint64_t rint_31:1;
+               uint64_t iob:1;
+               uint64_t rint_29:1;
+               uint64_t rint_28:1;
+               uint64_t rint_27:1;
+               uint64_t rint_26:1;
+               uint64_t rint_25:1;
+               uint64_t rint_24:1;
+               uint64_t asx1:1;
+               uint64_t asx0:1;
+               uint64_t rint_21:1;
+               uint64_t pip:1;
+               uint64_t spx1:1;
+               uint64_t spx0:1;
+               uint64_t lmc:1;
+               uint64_t l2c:1;
+               uint64_t rint_15:1;
+               uint64_t rint_14:1;
+               uint64_t rint_13:1;
+               uint64_t pow:1;
+               uint64_t tim:1;
+               uint64_t pko:1;
+               uint64_t ipd:1;
+               uint64_t rint_8:1;
+               uint64_t zip:1;
+               uint64_t dfa:1;
+               uint64_t fpa:1;
+               uint64_t key:1;
+               uint64_t npi:1;
+               uint64_t gmx1:1;
+               uint64_t gmx0:1;
+               uint64_t mio:1;
+       } cn38xx;
+       struct cvmx_npi_rsl_int_blocks_cn50xx {
+               uint64_t reserved_31_63:33;
+               uint64_t iob:1;
+               uint64_t lmc1:1;
+               uint64_t agl:1;
+               uint64_t reserved_24_27:4;
+               uint64_t asx1:1;
+               uint64_t asx0:1;
+               uint64_t reserved_21_21:1;
+               uint64_t pip:1;
+               uint64_t spx1:1;
+               uint64_t spx0:1;
+               uint64_t lmc:1;
+               uint64_t l2c:1;
+               uint64_t reserved_15_15:1;
+               uint64_t rad:1;
+               uint64_t usb:1;
+               uint64_t pow:1;
+               uint64_t tim:1;
+               uint64_t pko:1;
+               uint64_t ipd:1;
+               uint64_t reserved_8_8:1;
+               uint64_t zip:1;
+               uint64_t dfa:1;
+               uint64_t fpa:1;
+               uint64_t key:1;
+               uint64_t npi:1;
+               uint64_t gmx1:1;
+               uint64_t gmx0:1;
+               uint64_t mio:1;
+       } cn50xx;
+};
+
+union cvmx_pko_command_word0 {
+       uint64_t u64;
+       struct {
+               uint64_t total_bytes:16;
+               uint64_t segs:6;
+               uint64_t dontfree:1;
+               uint64_t ignore_i:1;
+               uint64_t ipoffp1:7;
+               uint64_t gather:1;
+               uint64_t rsp:1;
+               uint64_t wqp:1;
+               uint64_t n2:1;
+               uint64_t le:1;
+               uint64_t reg0:11;
+               uint64_t subone0:1;
+               uint64_t reg1:11;
+               uint64_t subone1:1;
+               uint64_t size0:2;
+               uint64_t size1:2;
+       } s;
+};
+
+union cvmx_ciu_timx {
+       uint64_t u64;
+       struct cvmx_ciu_timx_s {
+               uint64_t reserved_37_63:27;
+               uint64_t one_shot:1;
+               uint64_t len:36;
+       } s;
+};
+
+union cvmx_gmxx_rxx_rx_inbnd {
+       uint64_t u64;
+       struct cvmx_gmxx_rxx_rx_inbnd_s {
+               uint64_t status:1;
+               uint64_t speed:2;
+               uint64_t duplex:1;
+               uint64_t reserved_4_63:60;
+       } s;
+};
+
+static inline int32_t cvmx_fau_fetch_and_add32(enum cvmx_fau_reg_32 reg,
+                                              int32_t value)
+{
+       return value;
+}
+
+static inline void cvmx_fau_atomic_add32(enum cvmx_fau_reg_32 reg,
+                                        int32_t value)
+{ }
+
+static inline void cvmx_fau_atomic_write32(enum cvmx_fau_reg_32 reg,
+                                          int32_t value)
+{ }
+
+static inline uint64_t cvmx_scratch_read64(uint64_t address)
+{
+       return 0;
+}
+
+static inline void cvmx_scratch_write64(uint64_t address, uint64_t value)
+{ }
+
+static inline int cvmx_wqe_get_grp(struct cvmx_wqe *work)
+{
+       return 0;
+}
+
+static inline void *cvmx_phys_to_ptr(uint64_t physical_address)
+{
+       return (void *)(uintptr_t)(physical_address);
+}
+
+static inline uint64_t cvmx_ptr_to_phys(void *ptr)
+{
+       return (unsigned long)ptr;
+}
+
+static inline int cvmx_helper_get_interface_num(int ipd_port)
+{
+       return ipd_port;
+}
+
+static inline int cvmx_helper_get_interface_index_num(int ipd_port)
+{
+       return ipd_port;
+}
+
+static inline void cvmx_fpa_enable(void)
+{ }
+
+static inline uint64_t cvmx_read_csr(uint64_t csr_addr)
+{
+       return 0;
+}
+
+static inline void cvmx_write_csr(uint64_t csr_addr, uint64_t val)
+{ }
+
+static inline int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)
+{
+       return 0;
+}
+
+static inline void *cvmx_fpa_alloc(uint64_t pool)
+{
+       return NULL;
+}
+
+static inline void cvmx_fpa_free(void *ptr, uint64_t pool,
+                                uint64_t num_cache_lines)
+{ }
+
+static inline int octeon_is_simulation(void)
+{
+       return 1;
+}
+
+static inline void cvmx_pip_get_port_status(uint64_t port_num, uint64_t clear,
+                                           cvmx_pip_port_status_t *status)
+{ }
+
+static inline void cvmx_pko_get_port_status(uint64_t port_num, uint64_t clear,
+                                           cvmx_pko_port_status_t *status)
+{ }
+
+static inline cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int
+                                                                  interface)
+{
+       return 0;
+}
+
+static inline union cvmx_helper_link_info cvmx_helper_link_get(int ipd_port)
+{
+       union cvmx_helper_link_info ret = { .u64 = 0 };
+
+       return ret;
+}
+
+static inline int cvmx_helper_link_set(int ipd_port,
+                                      union cvmx_helper_link_info link_info)
+{
+       return 0;
+}
+
+static inline int cvmx_helper_initialize_packet_io_global(void)
+{
+       return 0;
+}
+
+static inline int cvmx_helper_get_number_of_interfaces(void)
+{
+       return 2;
+}
+
+static inline int cvmx_helper_ports_on_interface(int interface)
+{
+       return 1;
+}
+
+static inline int cvmx_helper_get_ipd_port(int interface, int port)
+{
+       return 0;
+}
+
+static inline int cvmx_helper_ipd_and_packet_input_enable(void)
+{
+       return 0;
+}
+
+static inline void cvmx_ipd_disable(void)
+{ }
+
+static inline void cvmx_ipd_free_ptr(void)
+{ }
+
+static inline void cvmx_pko_disable(void)
+{ }
+
+static inline void cvmx_pko_shutdown(void)
+{ }
+
+static inline int cvmx_pko_get_base_queue_per_core(int port, int core)
+{
+       return port;
+}
+
+static inline int cvmx_pko_get_base_queue(int port)
+{
+       return port;
+}
+
+static inline int cvmx_pko_get_num_queues(int port)
+{
+       return port;
+}
+
+static inline unsigned int cvmx_get_core_num(void)
+{
+       return 0;
+}
+
+static inline void cvmx_pow_work_request_async_nocheck(int scr_addr,
+                                                      cvmx_pow_wait_t wait)
+{ }
+
+static inline void cvmx_pow_work_request_async(int scr_addr,
+                                              cvmx_pow_wait_t wait)
+{ }
+
+static inline struct cvmx_wqe *cvmx_pow_work_response_async(int scr_addr)
+{
+       struct cvmx_wqe *wqe = (void *)(unsigned long)scr_addr;
+
+       return wqe;
+}
+
+static inline struct cvmx_wqe *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait)
+{
+       return (void *)(unsigned long)wait;
+}
+
+static inline int cvmx_spi_restart_interface(int interface,
+                                       cvmx_spi_mode_t mode, int timeout)
+{
+       return 0;
+}
+
+static inline void cvmx_fau_async_fetch_and_add32(uint64_t scraddr,
+                                                 enum cvmx_fau_reg_32 reg,
+                                                 int32_t value)
+{ }
+
+static inline union cvmx_gmxx_rxx_rx_inbnd cvmx_spi4000_check_speed(
+       int interface,
+       int port)
+{
+       union cvmx_gmxx_rxx_rx_inbnd r;
+
+       r.u64 = 0;
+       return r;
+}
+
+static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue,
+                                               cvmx_pko_lock_t use_locking)
+{ }
+
+static inline cvmx_pko_status_t cvmx_pko_send_packet_finish(uint64_t port,
+               uint64_t queue, union cvmx_pko_command_word0 pko_command,
+               union cvmx_buf_ptr packet, cvmx_pko_lock_t use_locking)
+{
+       return 0;
+}
+
+static inline void cvmx_wqe_set_port(struct cvmx_wqe *work, int port)
+{ }
+
+static inline void cvmx_wqe_set_qos(struct cvmx_wqe *work, int qos)
+{ }
+
+static inline int cvmx_wqe_get_qos(struct cvmx_wqe *work)
+{
+       return 0;
+}
+
+static inline void cvmx_wqe_set_grp(struct cvmx_wqe *work, int grp)
+{ }
+
+static inline void cvmx_pow_work_submit(struct cvmx_wqe *wqp, uint32_t tag,
+                                       enum cvmx_pow_tag_type tag_type,
+                                       uint64_t qos, uint64_t grp)
+{ }
+
+#define CVMX_ASXX_RX_CLK_SETX(a, b)    ((a) + (b))
+#define CVMX_ASXX_TX_CLK_SETX(a, b)    ((a) + (b))
+#define CVMX_CIU_TIMX(a)               (a)
+#define CVMX_GMXX_RXX_ADR_CAM0(a, b)   ((a) + (b))
+#define CVMX_GMXX_RXX_ADR_CAM1(a, b)   ((a) + (b))
+#define CVMX_GMXX_RXX_ADR_CAM2(a, b)   ((a) + (b))
+#define CVMX_GMXX_RXX_ADR_CAM3(a, b)   ((a) + (b))
+#define CVMX_GMXX_RXX_ADR_CAM4(a, b)   ((a) + (b))
+#define CVMX_GMXX_RXX_ADR_CAM5(a, b)   ((a) + (b))
+#define CVMX_GMXX_RXX_FRM_CTL(a, b)    ((a) + (b))
+#define CVMX_GMXX_RXX_INT_REG(a, b)    ((a) + (b))
+#define CVMX_GMXX_SMACX(a, b)          ((a) + (b))
+#define CVMX_PIP_PRT_TAGX(a)           (a)
+#define CVMX_POW_PP_GRP_MSKX(a)                (a)
+#define CVMX_POW_WQ_INT_THRX(a)                (a)
+#define CVMX_SPXX_INT_MSK(a)           (a)
+#define CVMX_SPXX_INT_REG(a)           (a)
+#define CVMX_SSO_PPX_GRP_MSK(a)                (a)
+#define CVMX_SSO_WQ_INT_THRX(a)                (a)
+#define CVMX_STXX_INT_MSK(a)           (a)
+#define CVMX_STXX_INT_REG(a)           (a)
index 61fad96..096137f 100644 (file)
@@ -3,51 +3,46 @@
 /plugin/;
 
 / {
-       compatible = "bcm,bcm2835", "bcm,bcm2708", "bcm,bcm2709";
+       compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709";
+};
 
-       fragment@0 {
-               target = <&spi0>;
-               __overlay__ {
-                       status = "okay";
+&spi0 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
 
-                       spidev@0{
-                               status = "disabled";
-                       };
+       spidev@0{
+               reg = <0>;
+               status = "disabled";
+       };
 
-                       spidev@1{
-                               status = "disabled";
-                       };
-               };
+       spidev@1{
+               reg = <1>;
+               status = "disabled";
        };
+};
 
-       fragment@1 {
-               target = <&gpio>;
-               __overlay__ {
-                       pi433_pins: pi433_pins {
-                               brcm,pins = <7 25 24>;
-                               brcm,function = <0 0 0>; // in in in
-                       };
-               };
+&gpio {
+       pi433_pins: pi433_pins {
+               brcm,pins = <7 25 24>;
+               brcm,function = <0 0 0>; // in in in
        };
+};
 
-       fragment@2 {
-               target = <&spi0>;
-               __overlay__ {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       status = "okay";
-
-                       pi433: pi433@0 {
-                               compatible = "Smarthome-Wolf,pi433";
-                               reg = <0>;
-                               spi-max-frequency = <10000000>;
-                               status = "okay";
-
-                               pinctrl-0 = <&pi433_pins>;
-                               DIO0-gpio = <&gpio 24 0>;
-                               DIO1-gpio = <&gpio 25 0>;
-                               DIO2-gpio = <&gpio  7 0>;
-                       };
-               };
+&spi0 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       status = "okay";
+
+       pi433: pi433@0 {
+               compatible = "Smarthome-Wolf,pi433";
+               reg = <0>;
+               spi-max-frequency = <10000000>;
+               status = "okay";
+
+               pinctrl-0 = <&pi433_pins>;
+               DIO0-gpio = <&gpio 24 0>;
+               DIO1-gpio = <&gpio 25 0>;
+               DIO2-gpio = <&gpio  7 0>;
        };
 };
index 9feb95c..16c5b7f 100644 (file)
@@ -1,5 +1,5 @@
-/* SPDX-License-Identifier: GPL-2.0+
- *
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
  * include/linux/TODO
  *
  * userspace interface for pi433 radio module
index d43a8d8..b648ba5 100644 (file)
@@ -1,5 +1,5 @@
-/* SPDX-License-Identifier: GPL-2.0+
- *
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
  * hardware abstraction/register access for HopeRf rf69 radio module
  *
  * Copyright (C) 2016 Wolf-Entwicklungen
index 3ee1952..fbf56fc 100644 (file)
@@ -1,5 +1,5 @@
-/* SPDX-License-Identifier: GPL-2.0+
- *
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
  * enumerations for HopeRf rf69 radio module
  *
  * Copyright (C) 2016 Wolf-Entwicklungen
index be5497c..a170c66 100644 (file)
@@ -1,5 +1,5 @@
-/* SPDX-License-Identifier: GPL-2.0+
- *
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
  * register description for HopeRf rf69 radio module
  *
  * Copyright (C) 2016 Wolf-Entwicklungen
index 4bc5d5f..fc8c5ca 100644 (file)
@@ -16,8 +16,8 @@
 /*
  * General definitions...
  */
-#define DRV_NAME       "qlge"
-#define DRV_STRING     "QLogic 10 Gigabit PCI-E Ethernet Driver "
+#define DRV_NAME       "qlge"
+#define DRV_STRING     "QLogic 10 Gigabit PCI-E Ethernet Driver "
 #define DRV_VERSION    "1.00.00.35"
 
 #define WQ_ADDR_ALIGN  0x3     /* 4 byte alignment */
@@ -59,7 +59,7 @@
 #define MAX_CQ 128
 #define DFLT_COALESCE_WAIT 100 /* 100 usec wait for coalescing */
 #define MAX_INTER_FRAME_WAIT 10        /* 10 usec max interframe-wait for coalescing */
-#define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT/2)
+#define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT / 2)
 #define UDELAY_COUNT 3
 #define UDELAY_DELAY 100
 
@@ -119,7 +119,6 @@ enum {
  * Processor Address Register (PROC_ADDR) bit definitions.
  */
 enum {
-
        /* Misc. stuff */
        MAILBOX_COUNT = 16,
        MAILBOX_TIMEOUT = 5,
@@ -1077,11 +1076,11 @@ struct tx_buf_desc {
  * IOCB Definitions...
  */
 
-#define OPCODE_OB_MAC_IOCB                     0x01
+#define OPCODE_OB_MAC_IOCB             0x01
 #define OPCODE_OB_MAC_TSO_IOCB         0x02
-#define OPCODE_IB_MAC_IOCB                     0x20
-#define OPCODE_IB_MPI_IOCB                     0x21
-#define OPCODE_IB_AE_IOCB                      0x3f
+#define OPCODE_IB_MAC_IOCB             0x20
+#define OPCODE_IB_MPI_IOCB             0x21
+#define OPCODE_IB_AE_IOCB              0x3f
 
 struct ob_mac_iocb_req {
        u8 opcode;
@@ -1173,15 +1172,15 @@ struct ib_mac_iocb_rsp {
        u8 flags1;
 #define IB_MAC_IOCB_RSP_OI     0x01    /* Override intr delay */
 #define IB_MAC_IOCB_RSP_I      0x02    /* Disable Intr Generation */
-#define IB_MAC_CSUM_ERR_MASK 0x1c      /* A mask to use for csum errs */
+#define IB_MAC_CSUM_ERR_MASK   0x1c    /* A mask to use for csum errs */
 #define IB_MAC_IOCB_RSP_TE     0x04    /* Checksum error */
 #define IB_MAC_IOCB_RSP_NU     0x08    /* No checksum rcvd */
 #define IB_MAC_IOCB_RSP_IE     0x10    /* IPv4 checksum error */
 #define IB_MAC_IOCB_RSP_M_MASK 0x60    /* Multicast info */
 #define IB_MAC_IOCB_RSP_M_NONE 0x00    /* Not mcast frame */
 #define IB_MAC_IOCB_RSP_M_HASH 0x20    /* HASH mcast frame */
-#define IB_MAC_IOCB_RSP_M_REG  0x40    /* Registered mcast frame */
-#define IB_MAC_IOCB_RSP_M_PROM         0x60    /* Promiscuous mcast frame */
+#define IB_MAC_IOCB_RSP_M_REG  0x40    /* Registered mcast frame */
+#define IB_MAC_IOCB_RSP_M_PROM 0x60    /* Promiscuous mcast frame */
 #define IB_MAC_IOCB_RSP_B      0x80    /* Broadcast frame */
        u8 flags2;
 #define IB_MAC_IOCB_RSP_P      0x01    /* Promiscuous frame */
@@ -1198,16 +1197,16 @@ struct ib_mac_iocb_rsp {
 #define IB_MAC_IOCB_RSP_FO     0x80    /* Failover port */
        u8 flags3;
 #define IB_MAC_IOCB_RSP_RSS_MASK       0x07    /* RSS mask */
-#define IB_MAC_IOCB_RSP_M_NONE 0x00    /* No RSS match */
-#define IB_MAC_IOCB_RSP_M_IPV4 0x04    /* IPv4 RSS match */
-#define IB_MAC_IOCB_RSP_M_IPV6 0x02    /* IPv6 RSS match */
-#define IB_MAC_IOCB_RSP_M_TCP_V4       0x05    /* TCP with IPv4 */
-#define IB_MAC_IOCB_RSP_M_TCP_V6       0x03    /* TCP with IPv6 */
-#define IB_MAC_IOCB_RSP_V4     0x08    /* IPV4 */
-#define IB_MAC_IOCB_RSP_V6     0x10    /* IPV6 */
-#define IB_MAC_IOCB_RSP_IH     0x20    /* Split after IP header */
-#define IB_MAC_IOCB_RSP_DS     0x40    /* data is in small buffer */
-#define IB_MAC_IOCB_RSP_DL     0x80    /* data is in large buffer */
+#define IB_MAC_IOCB_RSP_M_NONE         0x00    /* No RSS match */
+#define IB_MAC_IOCB_RSP_M_IPV4         0x04    /* IPv4 RSS match */
+#define IB_MAC_IOCB_RSP_M_IPV6         0x02    /* IPv6 RSS match */
+#define IB_MAC_IOCB_RSP_M_TCP_V4       0x05    /* TCP with IPv4 */
+#define IB_MAC_IOCB_RSP_M_TCP_V6       0x03    /* TCP with IPv6 */
+#define IB_MAC_IOCB_RSP_V4             0x08    /* IPV4 */
+#define IB_MAC_IOCB_RSP_V6             0x10    /* IPV6 */
+#define IB_MAC_IOCB_RSP_IH             0x20    /* Split after IP header */
+#define IB_MAC_IOCB_RSP_DS             0x40    /* data is in small buffer */
+#define IB_MAC_IOCB_RSP_DL             0x80    /* data is in large buffer */
        __le32 data_len;        /* */
        __le64 data_addr;       /* */
        __le32 rss;             /* */
@@ -1233,17 +1232,17 @@ struct ib_ae_iocb_rsp {
 #define IB_AE_IOCB_RSP_OI              0x01
 #define IB_AE_IOCB_RSP_I               0x02
        u8 event;
-#define LINK_UP_EVENT              0x00
-#define LINK_DOWN_EVENT            0x01
-#define CAM_LOOKUP_ERR_EVENT       0x06
-#define SOFT_ECC_ERROR_EVENT       0x07
-#define MGMT_ERR_EVENT             0x08
-#define TEN_GIG_MAC_EVENT          0x09
-#define GPI0_H2L_EVENT         0x10
-#define GPI0_L2H_EVENT         0x20
-#define GPI1_H2L_EVENT         0x11
-#define GPI1_L2H_EVENT         0x21
-#define PCI_ERR_ANON_BUF_RD        0x40
+#define LINK_UP_EVENT                  0x00
+#define LINK_DOWN_EVENT                        0x01
+#define CAM_LOOKUP_ERR_EVENT           0x06
+#define SOFT_ECC_ERROR_EVENT           0x07
+#define MGMT_ERR_EVENT                 0x08
+#define TEN_GIG_MAC_EVENT              0x09
+#define GPI0_H2L_EVENT                 0x10
+#define GPI0_L2H_EVENT                 0x20
+#define GPI1_H2L_EVENT                 0x11
+#define GPI1_L2H_EVENT                 0x21
+#define PCI_ERR_ANON_BUF_RD            0x40
        u8 q_id;
        __le32 reserved[15];
 } __packed;
@@ -1367,7 +1366,7 @@ struct tx_ring_desc {
        struct tx_ring_desc *next;
 };
 
-#define QL_TXQ_IDX(qdev, skb) (smp_processor_id()%(qdev->tx_ring_count))
+#define QL_TXQ_IDX(qdev, skb) (smp_processor_id() % (qdev->tx_ring_count))
 
 struct tx_ring {
        /*
@@ -1762,7 +1761,6 @@ struct ql_nic_misc {
 };
 
 struct ql_reg_dump {
-
        /* segment 0 */
        struct mpi_coredump_global_header mpi_global_header;
 
@@ -1792,7 +1790,7 @@ struct ql_reg_dump {
 
        /* segment 34 */
        struct mpi_coredump_segment_header ets_seg_hdr;
-       u32 ets[8+2];
+       u32 ets[8 + 2];
 };
 
 struct ql_mpi_coredump {
@@ -2059,7 +2057,6 @@ enum {
 };
 
 struct nic_operations {
-
        int (*get_flash) (struct ql_adapter *);
        int (*port_initialize) (struct ql_adapter *);
 };
index 8cf3961..1795533 100644 (file)
@@ -29,15 +29,13 @@ static int ql_write_other_func_reg(struct ql_adapter *qdev,
                                   u32 reg, u32 reg_val)
 {
        u32 register_to_read;
-       int status = 0;
 
        register_to_read = MPI_NIC_REG_BLOCK
                                | MPI_NIC_READ
                                | (qdev->alt_func << MPI_NIC_FUNCTION_SHIFT)
                                | reg;
-       status = ql_write_mpi_reg(qdev, register_to_read, reg_val);
 
-       return status;
+       return ql_write_mpi_reg(qdev, register_to_read, reg_val);
 }
 
 static int ql_wait_other_func_reg_rdy(struct ql_adapter *qdev, u32 reg,
@@ -499,6 +497,7 @@ static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 *buf,
                           u32 offset, u32 count)
 {
        int i, status = 0;
+
        for (i = 0; i < count; i++, buf++) {
                status = ql_read_mpi_reg(qdev, offset + i, buf);
                if (status)
@@ -552,7 +551,6 @@ static int ql_get_probe_dump(struct ql_adapter *qdev, unsigned int *buf)
        buf = ql_get_probe(qdev, PRB_MX_ADDR_FC_CLOCK,
                           PRB_MX_ADDR_VALID_FC_MOD, buf);
        return 0;
-
 }
 
 /* Read out the routing index registers */
@@ -610,7 +608,6 @@ static void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf)
 
        for (type = 0; type < MAC_ADDR_TYPE_COUNT; type++) {
                switch (type) {
-
                case 0: /* CAM */
                        initial_val |= MAC_ADDR_ADR;
                        max_index = MAC_ADDR_MAX_CAM_ENTRIES;
@@ -1204,7 +1201,6 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump)
 err:
        ql_sem_unlock(qdev, SEM_PROC_REG_MASK); /* does flush too */
        return status;
-
 }
 
 static void ql_get_core_dump(struct ql_adapter *qdev)
@@ -1324,27 +1320,10 @@ void ql_mpi_core_to_log(struct work_struct *work)
 {
        struct ql_adapter *qdev =
                container_of(work, struct ql_adapter, mpi_core_to_log.work);
-       u32 *tmp, count;
-       int i;
 
-       count = sizeof(struct ql_mpi_coredump) / sizeof(u32);
-       tmp = (u32 *)qdev->mpi_coredump;
-       netif_printk(qdev, drv, KERN_DEBUG, qdev->ndev,
-                    "Core is dumping to log file!\n");
-
-       for (i = 0; i < count; i += 8) {
-               pr_err("%.08x: %.08x %.08x %.08x %.08x %.08x "
-                       "%.08x %.08x %.08x\n", i,
-                       tmp[i + 0],
-                       tmp[i + 1],
-                       tmp[i + 2],
-                       tmp[i + 3],
-                       tmp[i + 4],
-                       tmp[i + 5],
-                       tmp[i + 6],
-                       tmp[i + 7]);
-               msleep(5);
-       }
+       print_hex_dump(KERN_DEBUG, "Core is dumping to log file!\n",
+                      DUMP_PREFIX_OFFSET, 32, 4, qdev->mpi_coredump,
+                      sizeof(*qdev->mpi_coredump), false);
 }
 
 #ifdef QL_REG_DUMP
@@ -1352,6 +1331,7 @@ static void ql_dump_intr_states(struct ql_adapter *qdev)
 {
        int i;
        u32 value;
+
        for (i = 0; i < qdev->intr_count; i++) {
                ql_write32(qdev, INTR_EN, qdev->intr_context[i].intr_read_mask);
                value = ql_read32(qdev, INTR_EN);
@@ -1437,6 +1417,7 @@ void ql_dump_routing_entries(struct ql_adapter *qdev)
 {
        int i;
        u32 value;
+
        i = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
        if (i)
                return;
@@ -1525,7 +1506,7 @@ void ql_dump_regs(struct ql_adapter *qdev)
 #ifdef QL_STAT_DUMP
 
 #define DUMP_STAT(qdev, stat)  \
-       pr_err("%s = %ld\n", #stat, (unsigned long)qdev->nic_stats.stat)
+       pr_err("%s = %ld\n", #stat, (unsigned long)(qdev)->nic_stats.stat)
 
 void ql_dump_stat(struct ql_adapter *qdev)
 {
@@ -1578,15 +1559,16 @@ void ql_dump_stat(struct ql_adapter *qdev)
 #ifdef QL_DEV_DUMP
 
 #define DUMP_QDEV_FIELD(qdev, type, field)             \
-       pr_err("qdev->%-24s = " type "\n", #field, qdev->field)
+       pr_err("qdev->%-24s = " type "\n", #field, (qdev)->(field))
 #define DUMP_QDEV_DMA_FIELD(qdev, field)               \
        pr_err("qdev->%-24s = %llx\n", #field, (unsigned long long)qdev->field)
 #define DUMP_QDEV_ARRAY(qdev, type, array, index, field) \
        pr_err("%s[%d].%s = " type "\n",                 \
-              #array, index, #field, qdev->array[index].field);
+              #array, index, #field, (qdev)->array[index].field);
 void ql_dump_qdev(struct ql_adapter *qdev)
 {
        int i;
+
        DUMP_QDEV_FIELD(qdev, "%lx", flags);
        DUMP_QDEV_FIELD(qdev, "%p", vlgrp);
        DUMP_QDEV_FIELD(qdev, "%p", pdev);
@@ -1640,9 +1622,9 @@ void ql_dump_wqicb(struct wqicb *wqicb)
               le16_to_cpu(wqicb->cq_id_rss));
        pr_err("wqicb->rid = 0x%x\n", le16_to_cpu(wqicb->rid));
        pr_err("wqicb->wq_addr = 0x%llx\n",
-              (unsigned long long) le64_to_cpu(wqicb->addr));
+              (unsigned long long)le64_to_cpu(wqicb->addr));
        pr_err("wqicb->wq_cnsmr_idx_addr = 0x%llx\n",
-              (unsigned long long) le64_to_cpu(wqicb->cnsmr_idx_addr));
+              (unsigned long long)le64_to_cpu(wqicb->cnsmr_idx_addr));
 }
 
 void ql_dump_tx_ring(struct tx_ring *tx_ring)
@@ -1653,7 +1635,7 @@ void ql_dump_tx_ring(struct tx_ring *tx_ring)
               tx_ring->wq_id);
        pr_err("tx_ring->base = %p\n", tx_ring->wq_base);
        pr_err("tx_ring->base_dma = 0x%llx\n",
-              (unsigned long long) tx_ring->wq_base_dma);
+              (unsigned long long)tx_ring->wq_base_dma);
        pr_err("tx_ring->cnsmr_idx_sh_reg, addr = 0x%p, value = %d\n",
               tx_ring->cnsmr_idx_sh_reg,
               tx_ring->cnsmr_idx_sh_reg
@@ -1672,6 +1654,7 @@ void ql_dump_tx_ring(struct tx_ring *tx_ring)
 void ql_dump_ricb(struct ricb *ricb)
 {
        int i;
+
        pr_err("===================== Dumping ricb ===============\n");
        pr_err("Dumping ricb stuff...\n");
 
@@ -1706,21 +1689,21 @@ void ql_dump_cqicb(struct cqicb *cqicb)
        pr_err("cqicb->flags = %x\n", cqicb->flags);
        pr_err("cqicb->len = %d\n", le16_to_cpu(cqicb->len));
        pr_err("cqicb->addr = 0x%llx\n",
-              (unsigned long long) le64_to_cpu(cqicb->addr));
+              (unsigned long long)le64_to_cpu(cqicb->addr));
        pr_err("cqicb->prod_idx_addr = 0x%llx\n",
-              (unsigned long long) le64_to_cpu(cqicb->prod_idx_addr));
+              (unsigned long long)le64_to_cpu(cqicb->prod_idx_addr));
        pr_err("cqicb->pkt_delay = 0x%.04x\n",
               le16_to_cpu(cqicb->pkt_delay));
        pr_err("cqicb->irq_delay = 0x%.04x\n",
               le16_to_cpu(cqicb->irq_delay));
        pr_err("cqicb->lbq_addr = 0x%llx\n",
-              (unsigned long long) le64_to_cpu(cqicb->lbq_addr));
+              (unsigned long long)le64_to_cpu(cqicb->lbq_addr));
        pr_err("cqicb->lbq_buf_size = 0x%.04x\n",
               le16_to_cpu(cqicb->lbq_buf_size));
        pr_err("cqicb->lbq_len = 0x%.04x\n",
               le16_to_cpu(cqicb->lbq_len));
        pr_err("cqicb->sbq_addr = 0x%llx\n",
-              (unsigned long long) le64_to_cpu(cqicb->sbq_addr));
+              (unsigned long long)le64_to_cpu(cqicb->sbq_addr));
        pr_err("cqicb->sbq_buf_size = 0x%.04x\n",
               le16_to_cpu(cqicb->sbq_buf_size));
        pr_err("cqicb->sbq_len = 0x%.04x\n",
@@ -1748,7 +1731,7 @@ void ql_dump_rx_ring(struct rx_ring *rx_ring)
        pr_err("rx_ring->cqicb = %p\n", &rx_ring->cqicb);
        pr_err("rx_ring->cq_base = %p\n", rx_ring->cq_base);
        pr_err("rx_ring->cq_base_dma = %llx\n",
-              (unsigned long long) rx_ring->cq_base_dma);
+              (unsigned long long)rx_ring->cq_base_dma);
        pr_err("rx_ring->cq_size = %d\n", rx_ring->cq_size);
        pr_err("rx_ring->cq_len = %d\n", rx_ring->cq_len);
        pr_err("rx_ring->prod_idx_sh_reg, addr = 0x%p, value = %d\n",
@@ -1756,7 +1739,7 @@ void ql_dump_rx_ring(struct rx_ring *rx_ring)
               rx_ring->prod_idx_sh_reg
                        ? ql_read_sh_reg(rx_ring->prod_idx_sh_reg) : 0);
        pr_err("rx_ring->prod_idx_sh_reg_dma = %llx\n",
-              (unsigned long long) rx_ring->prod_idx_sh_reg_dma);
+              (unsigned long long)rx_ring->prod_idx_sh_reg_dma);
        pr_err("rx_ring->cnsmr_idx_db_reg = %p\n",
               rx_ring->cnsmr_idx_db_reg);
        pr_err("rx_ring->cnsmr_idx = %d\n", rx_ring->cnsmr_idx);
@@ -1855,7 +1838,6 @@ void ql_dump_tx_desc(struct tx_buf_desc *tbd)
        pr_err("tbd->flags = %s %s\n",
               tbd->len & TX_DESC_C ? "C" : ".",
               tbd->len & TX_DESC_E ? "E" : ".");
-
 }
 
 void ql_dump_ob_mac_iocb(struct ob_mac_iocb_req *ob_mac_iocb)
@@ -1980,7 +1962,7 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
        pr_err("data_len        = %d\n",
               le32_to_cpu(ib_mac_rsp->data_len));
        pr_err("data_addr    = 0x%llx\n",
-              (unsigned long long) le64_to_cpu(ib_mac_rsp->data_addr));
+              (unsigned long long)le64_to_cpu(ib_mac_rsp->data_addr));
        if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK)
                pr_err("rss    = %x\n",
                       le32_to_cpu(ib_mac_rsp->rss));
@@ -1997,7 +1979,7 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
                pr_err("hdr length      = %d\n",
                       le32_to_cpu(ib_mac_rsp->hdr_len));
                pr_err("hdr addr    = 0x%llx\n",
-                      (unsigned long long) le64_to_cpu(ib_mac_rsp->hdr_addr));
+                      (unsigned long long)le64_to_cpu(ib_mac_rsp->hdr_addr));
        }
 }
 #endif
index 790997a..441ac08 100644 (file)
@@ -259,8 +259,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
                                  "Error reading status register 0x%.04x.\n",
                                  i);
                        goto end;
-               } else
+               } else {
                        *iter = data;
+               }
                iter++;
        }
 
@@ -273,8 +274,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
                                  "Error reading status register 0x%.04x.\n",
                                  i);
                        goto end;
-               } else
+               } else {
                        *iter = data;
+               }
                iter++;
        }
 
@@ -290,8 +292,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
                                  "Error reading status register 0x%.04x.\n",
                                  i);
                        goto end;
-               } else
+               } else {
                        *iter = data;
+               }
                iter++;
        }
 
@@ -304,8 +307,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
                                  "Error reading status register 0x%.04x.\n",
                                  i);
                        goto end;
-               } else
+               } else {
                        *iter = data;
+               }
                iter++;
        }
 
@@ -316,8 +320,9 @@ static void ql_update_stats(struct ql_adapter *qdev)
                netif_err(qdev, drv, qdev->ndev,
                          "Error reading status register 0x%.04x.\n", i);
                goto end;
-       } else
+       } else {
                *iter = data;
+       }
 end:
        ql_sem_unlock(qdev, qdev->xg_sem_mask);
 quit:
@@ -488,8 +493,9 @@ static int ql_start_loopback(struct ql_adapter *qdev)
        if (netif_carrier_ok(qdev->ndev)) {
                set_bit(QL_LB_LINK_UP, &qdev->flags);
                netif_carrier_off(qdev->ndev);
-       } else
+       } else {
                clear_bit(QL_LB_LINK_UP, &qdev->flags);
+       }
        qdev->link_config |= CFG_LOOPBACK_PCS;
        return ql_mb_set_port_cfg(qdev);
 }
@@ -686,7 +692,6 @@ static int ql_set_pauseparam(struct net_device *netdev,
                             struct ethtool_pauseparam *pause)
 {
        struct ql_adapter *qdev = netdev_priv(netdev);
-       int status = 0;
 
        if ((pause->rx_pause) && (pause->tx_pause))
                qdev->link_config |= CFG_PAUSE_STD;
@@ -695,8 +700,7 @@ static int ql_set_pauseparam(struct net_device *netdev,
        else
                return -EINVAL;
 
-       status = ql_mb_set_port_cfg(qdev);
-       return status;
+       return ql_mb_set_port_cfg(qdev);
 }
 
 static u32 ql_get_msglevel(struct net_device *ndev)
index ef8037d..c92820f 100644 (file)
@@ -52,16 +52,12 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
 static const u32 default_msg =
-    NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK |
-/* NETIF_MSG_TIMER |   */
-    NETIF_MSG_IFDOWN |
-    NETIF_MSG_IFUP |
-    NETIF_MSG_RX_ERR |
-    NETIF_MSG_TX_ERR |
-/*  NETIF_MSG_TX_QUEUED | */
-/*  NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS | */
-/* NETIF_MSG_PKTDATA | */
-    NETIF_MSG_HW | NETIF_MSG_WOL | 0;
+       NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK |
+       NETIF_MSG_IFDOWN |
+       NETIF_MSG_IFUP |
+       NETIF_MSG_RX_ERR |
+       NETIF_MSG_TX_ERR |
+       NETIF_MSG_HW | NETIF_MSG_WOL | 0;
 
 static int debug = -1; /* defaults above */
 module_param(debug, int, 0664);
@@ -143,6 +139,7 @@ static int ql_sem_trylock(struct ql_adapter *qdev, u32 sem_mask)
 int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask)
 {
        unsigned int wait_count = 30;
+
        do {
                if (!ql_sem_trylock(qdev, sem_mask))
                        return 0;
@@ -1210,6 +1207,7 @@ static void ql_unmap_send(struct ql_adapter *qdev,
                          struct tx_ring_desc *tx_ring_desc, int mapped)
 {
        int i;
+
        for (i = 0; i < mapped; i++) {
                if (i == 0 || (i == 7 && mapped > 7)) {
                        /*
@@ -1290,6 +1288,7 @@ static int ql_map_send(struct ql_adapter *qdev,
         */
        for (frag_idx = 0; frag_idx < frag_cnt; frag_idx++, map_idx++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_idx];
+
                tbd++;
                if (frag_idx == 6 && frag_cnt > 7) {
                        /* Let's tack on an sglist.
@@ -1649,6 +1648,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
                                (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
                        /* Unfragmented ipv4 UDP frame. */
                        struct iphdr *iph = (struct iphdr *) skb->data;
+
                        if (!(iph->frag_off &
                                htons(IP_MF|IP_OFFSET))) {
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1818,6 +1818,7 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
                 *          eventually be in trouble.
                 */
                int size, i = 0;
+
                sbq_desc = qlge_get_curr_buf(&rx_ring->sbq);
                pci_unmap_single(qdev->pdev, sbq_desc->dma_addr,
                                 SMALL_BUF_MAP_SIZE, PCI_DMA_FROMDEVICE);
@@ -1936,6 +1937,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
                                (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
                /* Unfragmented ipv4 UDP frame. */
                        struct iphdr *iph = (struct iphdr *) skb->data;
+
                        if (!(iph->frag_off &
                                htons(IP_MF|IP_OFFSET))) {
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2391,6 +2393,7 @@ static void qlge_restore_vlan(struct ql_adapter *qdev)
 static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id)
 {
        struct rx_ring *rx_ring = dev_id;
+
        napi_schedule(&rx_ring->napi);
        return IRQ_HANDLED;
 }
@@ -2497,6 +2500,7 @@ static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr)
                mac_iocb_ptr->flags2 |= OB_MAC_TSO_IOCB_LSO;
                if (likely(l3_proto == htons(ETH_P_IP))) {
                        struct iphdr *iph = ip_hdr(skb);
+
                        iph->check = 0;
                        mac_iocb_ptr->flags1 |= OB_MAC_TSO_IOCB_IP4;
                        tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
@@ -2521,6 +2525,7 @@ static void ql_hw_csum_setup(struct sk_buff *skb,
        int len;
        struct iphdr *iph = ip_hdr(skb);
        __sum16 *check;
+
        mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB;
        mac_iocb_ptr->frame_len = cpu_to_le32((u32) skb->len);
        mac_iocb_ptr->net_trans_offset =
@@ -3896,14 +3901,11 @@ static void ql_release_adapter_resources(struct ql_adapter *qdev)
 
 static int ql_get_adapter_resources(struct ql_adapter *qdev)
 {
-       int status = 0;
-
        if (ql_alloc_mem_resources(qdev)) {
                netif_err(qdev, ifup, qdev->ndev, "Unable to  allocate memory.\n");
                return -ENOMEM;
        }
-       status = ql_request_irq(qdev);
-       return status;
+       return ql_request_irq(qdev);
 }
 
 static int qlge_close(struct net_device *ndev)
@@ -4265,6 +4267,7 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
 static void qlge_tx_timeout(struct net_device *ndev, unsigned int txqueue)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
+
        ql_queue_asic_error(qdev);
 }
 
@@ -4273,6 +4276,7 @@ static void ql_asic_reset_work(struct work_struct *work)
        struct ql_adapter *qdev =
            container_of(work, struct ql_adapter, asic_reset_work.work);
        int status;
+
        rtnl_lock();
        status = ql_adapter_down(qdev);
        if (status)
@@ -4344,6 +4348,7 @@ static int ql_get_alt_pcie_func(struct ql_adapter *qdev)
 static int ql_get_board_info(struct ql_adapter *qdev)
 {
        int status;
+
        qdev->func =
            (ql_read32(qdev, STS) & STS_FUNC_ID_MASK) >> STS_FUNC_ID_SHIFT;
        if (qdev->func > 3)
@@ -4652,6 +4657,7 @@ static void qlge_remove(struct pci_dev *pdev)
 {
        struct net_device *ndev = pci_get_drvdata(pdev);
        struct ql_adapter *qdev = netdev_priv(ndev);
+
        del_timer_sync(&qdev->timer);
        ql_cancel_all_work_sync(qdev);
        unregister_netdev(ndev);
index bb03b2f..60c08d9 100644 (file)
@@ -90,9 +90,7 @@ exit:
 
 int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
 {
-       int status;
-       status = ql_write_mpi_reg(qdev, 0x00001010, 1);
-       return status;
+       return ql_write_mpi_reg(qdev, 0x00001010, 1);
 }
 
 /* Determine if we are in charge of the firwmare. If
@@ -237,6 +235,7 @@ static int ql_idc_cmplt_aen(struct ql_adapter *qdev)
 {
        int status;
        struct mbox_params *mbcp = &qdev->idc_mbc;
+
        mbcp->out_count = 4;
        status = ql_get_mb_sts(qdev, mbcp);
        if (status) {
@@ -255,6 +254,7 @@ static int ql_idc_cmplt_aen(struct ql_adapter *qdev)
 static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
 {
        int status;
+
        mbcp->out_count = 2;
 
        status = ql_get_mb_sts(qdev, mbcp);
@@ -353,6 +353,7 @@ static int ql_aen_lost(struct ql_adapter *qdev, struct mbox_params *mbcp)
                netif_err(qdev, drv, qdev->ndev, "Lost AEN broken!\n");
        else {
                int i;
+
                netif_err(qdev, drv, qdev->ndev, "Lost AEN detected.\n");
                for (i = 0; i < mbcp->out_count; i++)
                        netif_err(qdev, drv, qdev->ndev, "mbox_out[%d] = 0x%.08x.\n",
@@ -912,6 +913,7 @@ static int ql_idc_wait(struct ql_adapter *qdev)
        int status = -ETIMEDOUT;
        long wait_time = 1 * HZ;
        struct mbox_params *mbcp = &qdev->idc_mbc;
+
        do {
                /* Wait here for the command to complete
                 * via the IDC process.
@@ -1096,6 +1098,7 @@ int ql_wait_fifo_empty(struct ql_adapter *qdev)
 static int ql_set_port_cfg(struct ql_adapter *qdev)
 {
        int status;
+
        status = ql_mb_set_port_cfg(qdev);
        if (status)
                return status;
index 815dfee..f69e945 100644 (file)
@@ -199,7 +199,7 @@ _next:
                                rtw_free_cmd_obj(pcmd);
                        } else {
                                /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
-                               pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */
+                               pcmd_callback(pcmd->padapter, pcmd);/* need consider that free cmd_obj in rtw_cmd_callback */
                        }
                } else {
                        RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode));
index 6c2fe1a..d0e41f2 100644 (file)
@@ -15,7 +15,7 @@ int proc_get_drv_version(char *page, char **start,
 {
        int len = 0;
 
-       len += snprintf(page + len, count - len, "%s\n", DRIVERVERSION);
+       len += scnprintf(page + len, count - len, "%s\n", DRIVERVERSION);
 
        *eof = 1;
        return len;
@@ -86,16 +86,16 @@ int proc_get_read_reg(char *page, char **start,
 
        switch (proc_get_read_len) {
        case 1:
-               len += snprintf(page + len, count - len, "usb_read8(0x%x)=0x%x\n", proc_get_read_addr, usb_read8(padapter, proc_get_read_addr));
+               len += scnprintf(page + len, count - len, "usb_read8(0x%x)=0x%x\n", proc_get_read_addr, usb_read8(padapter, proc_get_read_addr));
                break;
        case 2:
-               len += snprintf(page + len, count - len, "usb_read16(0x%x)=0x%x\n", proc_get_read_addr, usb_read16(padapter, proc_get_read_addr));
+               len += scnprintf(page + len, count - len, "usb_read16(0x%x)=0x%x\n", proc_get_read_addr, usb_read16(padapter, proc_get_read_addr));
                break;
        case 4:
-               len += snprintf(page + len, count - len, "usb_read32(0x%x)=0x%x\n", proc_get_read_addr, usb_read32(padapter, proc_get_read_addr));
+               len += scnprintf(page + len, count - len, "usb_read32(0x%x)=0x%x\n", proc_get_read_addr, usb_read32(padapter, proc_get_read_addr));
                break;
        default:
-               len += snprintf(page + len, count - len, "error read length=%d\n", proc_get_read_len);
+               len += scnprintf(page + len, count - len, "error read length=%d\n", proc_get_read_len);
                break;
        }
 
@@ -138,7 +138,7 @@ int proc_get_adapter_state(char *page, char **start,
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        int len = 0;
 
-       len += snprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n",
+       len += scnprintf(page + len, count - len, "bSurpriseRemoved=%d, bDriverStopped=%d\n",
                                                padapter->bSurpriseRemoved, padapter->bDriverStopped);
 
        *eof = 1;
@@ -170,11 +170,11 @@ int proc_get_best_channel(char *page, char **start,
                }
 
                /*  debug */
-               len += snprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n",
+               len += scnprintf(page + len, count - len, "The rx cnt of channel %3d = %d\n",
                                        pmlmeext->channel_set[i].ChannelNum, pmlmeext->channel_set[i].rx_count);
        }
 
-       len += snprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G);
+       len += scnprintf(page + len, count - len, "best_channel_24G = %d\n", best_channel_24G);
 
        *eof = 1;
        return len;
index 29f6154..e186982 100644 (file)
@@ -236,14 +236,10 @@ int rtw_generate_ie(struct registry_priv *pregistrypriv)
        ie = rtw_set_ie(ie, _SSID_IE_, pdev_network->ssid.ssid_length, pdev_network->ssid.ssid, &sz);
 
        /* supported rates */
-       if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) {
-               if (pdev_network->Configuration.DSConfig > 14)
-                       wireless_mode = WIRELESS_11A_5N;
-               else
-                       wireless_mode = WIRELESS_11BG_24N;
-       } else {
+       if (pregistrypriv->wireless_mode == WIRELESS_11ABGN)
+               wireless_mode = WIRELESS_11BG_24N;
+       else
                wireless_mode = pregistrypriv->wireless_mode;
-       }
 
        rtw_set_supported_rate(pdev_network->SupportedRates, wireless_mode);
 
index e764436..9de2d42 100644 (file)
@@ -149,7 +149,7 @@ static void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *
            (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)))
                lifetime = 1;
        if (!isfreeall) {
-               delta_time = (curr_time - pnetwork->last_scanned)/HZ;
+               delta_time = (curr_time - pnetwork->last_scanned) / HZ;
                if (delta_time < lifetime)/*  unit:sec */
                        return;
        }
@@ -249,8 +249,8 @@ void rtw_generate_random_ibss(u8 *pibss)
        pibss[1] = 0x11;
        pibss[2] = 0x87;
        pibss[3] = (u8)(curtime & 0xff);/* p[0]; */
-       pibss[4] = (u8)((curtime>>8) & 0xff);/* p[1]; */
-       pibss[5] = (u8)((curtime>>16) & 0xff);/* p[2]; */
+       pibss[4] = (u8)((curtime >> 8) & 0xff);/* p[1]; */
+       pibss[5] = (u8)((curtime >> 16) & 0xff);/* p[2]; */
 }
 
 u8 *rtw_get_capability_from_ie(u8 *ie)
@@ -357,9 +357,9 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
                        rssi_final = rssi_ori;
        } else {
                if (sq_smp != 101) { /* from the right channel */
-                       ss_final = ((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5;
-                       sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5;
-                       rssi_final = (src->Rssi+dst->Rssi*4)/5;
+                       ss_final = ((u32)(src->PhyInfo.SignalStrength) + (u32)(dst->PhyInfo.SignalStrength) * 4) / 5;
+                       sq_final = ((u32)(src->PhyInfo.SignalQuality) + (u32)(dst->PhyInfo.SignalQuality) * 4) / 5;
+                       rssi_final = (src->Rssi + dst->Rssi * 4) / 5;
                } else {
                        /* bss info not receiving from the right channel, use the original RX signal infos */
                        ss_final = dst->PhyInfo.SignalStrength;
@@ -510,7 +510,7 @@ static int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *
        privacy = pnetwork->network.Privacy;
 
        if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
-               if (rtw_get_wps_ie(pnetwork->network.ies+_FIXED_IE_LENGTH_, pnetwork->network.ie_length-_FIXED_IE_LENGTH_, NULL, &wps_ielen))
+               if (rtw_get_wps_ie(pnetwork->network.ies + _FIXED_IE_LENGTH_, pnetwork->network.ie_length - _FIXED_IE_LENGTH_, NULL, &wps_ielen))
                        return true;
                else
                        return false;
@@ -924,8 +924,8 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net
        /* update fw_state will clr _FW_UNDER_LINKING here indirectly */
        switch (pnetwork->network.InfrastructureMode) {
        case Ndis802_11Infrastructure:
-               if (pmlmepriv->fw_state&WIFI_UNDER_WPS)
-                       pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS;
+               if (pmlmepriv->fw_state & WIFI_UNDER_WPS)
+                       pmlmepriv->fw_state = WIFI_STATION_STATE | WIFI_UNDER_WPS;
                else
                        pmlmepriv->fw_state = WIFI_STATION_STATE;
                break;
@@ -1097,14 +1097,14 @@ static u8 search_max_mac_id(struct adapter *padapter)
 #if defined(CONFIG_88EU_AP_MODE)
        if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
                for (aid = pstapriv->max_num_sta; aid > 0; aid--) {
-                       if (pstapriv->sta_aid[aid-1])
+                       if (pstapriv->sta_aid[aid - 1])
                                break;
                }
                mac_id = aid + 1;
        } else
 #endif
        {/* adhoc  id =  31~2 */
-               for (mac_id = NUM_STA-1; mac_id >= IBSS_START_MAC_ID; mac_id--) {
+               for (mac_id = NUM_STA - 1; mac_id >= IBSS_START_MAC_ID; mac_id--) {
                        if (pmlmeinfo->FW_sta_info[mac_id].status == 1)
                                break;
                }
@@ -1123,7 +1123,7 @@ void rtw_stassoc_hw_rpt(struct adapter *adapter, struct sta_info *psta)
 
        macid = search_max_mac_id(adapter);
        rtw_hal_set_hwreg(adapter, HW_VAR_TX_RPT_MAX_MACID, (u8 *)&macid);
-       media_status = (psta->mac_id<<8)|1; /*   MACID|OPMODE:1 connect */
+       media_status = (psta->mac_id << 8) | 1; /*   MACID|OPMODE:1 connect */
        rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
 }
 
@@ -1213,7 +1213,7 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf)
        if (mac_id >= 0) {
                u16 media_status;
 
-               media_status = (mac_id<<8)|0; /*   MACID|OPMODE:0 means disconnect */
+               media_status = (mac_id << 8) | 0; /*   MACID|OPMODE:0 means disconnect */
                /* for STA, AP, ADHOC mode, report disconnect stauts to FW */
                rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
        }
@@ -1640,7 +1640,7 @@ int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_
        for (i = 12; i < in_len; i += (in_ie[i + 1] + 2) /* to the next IE element */) {
                ielength = initial_out_len;
 
-               if (in_ie[i] == 0xDD && in_ie[i+2] == 0x00 && in_ie[i+3] == 0x50  && in_ie[i+4] == 0xF2 && in_ie[i+5] == 0x02 && i+5 < in_len) {
+               if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 && in_ie[i + 3] == 0x50  && in_ie[i + 4] == 0xF2 && in_ie[i + 5] == 0x02 && i + 5 < in_len) {
                        /* WMM element ID and OUI */
                        /* Append WMM IE to the last index of out_ie */
 
@@ -1734,13 +1734,13 @@ int rtw_restruct_sec_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_
                authmode = _WPA2_IE_ID_;
 
        if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
-               memcpy(out_ie+ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len);
+               memcpy(out_ie + ielength, psecuritypriv->wps_ie, psecuritypriv->wps_ie_len);
 
                ielength += psecuritypriv->wps_ie_len;
        } else if ((authmode == _WPA_IE_ID_) || (authmode == _WPA2_IE_ID_)) {
                /* copy RSN or SSN */
-               memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1]+2);
-               ielength += psecuritypriv->supplicant_ie[1]+2;
+               memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0], psecuritypriv->supplicant_ie[1] + 2);
+               ielength += psecuritypriv->supplicant_ie[1] + 2;
                rtw_report_sec_ie(adapter, authmode, psecuritypriv->supplicant_ie);
        }
 
@@ -1865,7 +1865,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_
 
        phtpriv->ht_option = false;
 
-       p = rtw_get_ie(in_ie+12, _HT_CAPABILITY_IE_, &ielen, in_len-12);
+       p = rtw_get_ie(in_ie + 12, _HT_CAPABILITY_IE_, &ielen, in_len - 12);
 
        if (p && ielen > 0) {
                struct ieee80211_ht_cap ht_cap;
@@ -1904,16 +1904,16 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_
                else
                        ht_cap.ampdu_params_info |= IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00;
 
-               rtw_set_ie(out_ie+out_len, _HT_CAPABILITY_IE_,
+               rtw_set_ie(out_ie + out_len, _HT_CAPABILITY_IE_,
                           sizeof(struct ieee80211_ht_cap),
                           (unsigned char *)&ht_cap, pout_len);
 
                phtpriv->ht_option = true;
 
-               p = rtw_get_ie(in_ie+12, _HT_ADD_INFO_IE_, &ielen, in_len-12);
+               p = rtw_get_ie(in_ie + 12, _HT_ADD_INFO_IE_, &ielen, in_len - 12);
                if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) {
                        out_len = *pout_len;
-                       rtw_set_ie(out_ie+out_len, _HT_ADD_INFO_IE_, ielen, p+2, pout_len);
+                       rtw_set_ie(out_ie + out_len, _HT_ADD_INFO_IE_, ielen, p + 2, pout_len);
                }
        }
        return phtpriv->ht_option;
index 36841d2..04897cd 100644 (file)
@@ -1151,7 +1151,7 @@ static void issue_assocreq(struct adapter *padapter)
                                if (!padapter->registrypriv.wifi_spec) {
                                        /* Commented by Kurt 20110629 */
                                        /* In some older APs, WPS handshake */
-                                       /* would be fail if we append vender extensions informations to AP */
+                                       /* would be fail if we append vender extensions information to AP */
                                        if (!memcmp(pIE->data, WPS_OUI, 4))
                                                pIE->Length = 14;
                                }
index 95f1b14..ebe19e0 100644 (file)
@@ -18,26 +18,26 @@ void dump_chip_info(struct HAL_VERSION      chip_vers)
        uint cnt = 0;
        char buf[128];
 
-       cnt += sprintf((buf+cnt), "Chip Version Info: CHIP_8188E_");
-       cnt += sprintf((buf+cnt), "%s_", chip_vers.ChipType == NORMAL_CHIP ?
+       cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8188E_");
+       cnt += sprintf((buf + cnt), "%s_", chip_vers.ChipType == NORMAL_CHIP ?
                       "Normal_Chip" : "Test_Chip");
-       cnt += sprintf((buf+cnt), "%s_", chip_vers.VendorType == CHIP_VENDOR_TSMC ?
+       cnt += sprintf((buf + cnt), "%s_", chip_vers.VendorType == CHIP_VENDOR_TSMC ?
                       "TSMC" : "UMC");
        if (chip_vers.CUTVersion == A_CUT_VERSION)
-               cnt += sprintf((buf+cnt), "A_CUT_");
+               cnt += sprintf((buf + cnt), "A_CUT_");
        else if (chip_vers.CUTVersion == B_CUT_VERSION)
-               cnt += sprintf((buf+cnt), "B_CUT_");
+               cnt += sprintf((buf + cnt), "B_CUT_");
        else if (chip_vers.CUTVersion == C_CUT_VERSION)
-               cnt += sprintf((buf+cnt), "C_CUT_");
+               cnt += sprintf((buf + cnt), "C_CUT_");
        else if (chip_vers.CUTVersion == D_CUT_VERSION)
-               cnt += sprintf((buf+cnt), "D_CUT_");
+               cnt += sprintf((buf + cnt), "D_CUT_");
        else if (chip_vers.CUTVersion == E_CUT_VERSION)
-               cnt += sprintf((buf+cnt), "E_CUT_");
+               cnt += sprintf((buf + cnt), "E_CUT_");
        else
-               cnt += sprintf((buf+cnt), "UNKNOWN_CUT(%d)_",
+               cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_",
                               chip_vers.CUTVersion);
-       cnt += sprintf((buf+cnt), "1T1R_");
-       cnt += sprintf((buf+cnt), "RomVer(0)\n");
+       cnt += sprintf((buf + cnt), "1T1R_");
+       cnt += sprintf((buf + cnt), "RomVer(0)\n");
 
        pr_info("%s", buf);
 }
index 7489491..698377e 100644 (file)
@@ -342,7 +342,7 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
        u8 CurrentIGI = pDM_DigTable->CurIGValue;
 
        ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG()==>\n"));
-       if ((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) {
+       if ((!(pDM_Odm->SupportAbility & ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))) {
                ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
                             ("odm_DIG() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n"));
                return;
@@ -419,7 +419,7 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
                }
 
                if (pDM_DigTable->LargeFAHit >= 3) {
-                       if ((pDM_DigTable->ForbiddenIGI+1) > pDM_DigTable->rx_gain_range_max)
+                       if ((pDM_DigTable->ForbiddenIGI + 1) > pDM_DigTable->rx_gain_range_max)
                                pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max;
                        else
                                pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1);
@@ -432,7 +432,7 @@ void odm_DIG(struct odm_dm_struct *pDM_Odm)
                        pDM_DigTable->Recover_cnt--;
                } else {
                        if (pDM_DigTable->LargeFAHit < 3) {
-                               if ((pDM_DigTable->ForbiddenIGI-1) < DIG_Dynamic_MIN) { /* DM_DIG_MIN) */
+                               if ((pDM_DigTable->ForbiddenIGI - 1) < DIG_Dynamic_MIN) { /* DM_DIG_MIN) */
                                        pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
                                        pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
                                        ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG(): Normal Case: At Lower Bound\n"));
@@ -518,24 +518,24 @@ void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm)
        phy_set_bb_reg(adapter, ODM_REG_OFDM_FA_RSTD_11N, BIT(31), 1); /* hold page D counter */
 
        ret_value = phy_query_bb_reg(adapter, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord);
-       FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff);
-       FalseAlmCnt->Cnt_SB_Search_fail = (ret_value & 0xffff0000)>>16;
+       FalseAlmCnt->Cnt_Fast_Fsync = (ret_value & 0xffff);
+       FalseAlmCnt->Cnt_SB_Search_fail = (ret_value & 0xffff0000) >> 16;
        ret_value = phy_query_bb_reg(adapter, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord);
-       FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff);
-       FalseAlmCnt->Cnt_Parity_Fail = (ret_value & 0xffff0000)>>16;
+       FalseAlmCnt->Cnt_OFDM_CCA = (ret_value & 0xffff);
+       FalseAlmCnt->Cnt_Parity_Fail = (ret_value & 0xffff0000) >> 16;
        ret_value = phy_query_bb_reg(adapter, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord);
-       FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff);
-       FalseAlmCnt->Cnt_Crc8_fail = (ret_value & 0xffff0000)>>16;
+       FalseAlmCnt->Cnt_Rate_Illegal = (ret_value & 0xffff);
+       FalseAlmCnt->Cnt_Crc8_fail = (ret_value & 0xffff0000) >> 16;
        ret_value = phy_query_bb_reg(adapter, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord);
-       FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff);
+       FalseAlmCnt->Cnt_Mcs_fail = (ret_value & 0xffff);
 
        FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail + FalseAlmCnt->Cnt_Rate_Illegal +
                                     FalseAlmCnt->Cnt_Crc8_fail + FalseAlmCnt->Cnt_Mcs_fail +
                                     FalseAlmCnt->Cnt_Fast_Fsync + FalseAlmCnt->Cnt_SB_Search_fail;
 
        ret_value = phy_query_bb_reg(adapter, ODM_REG_SC_CNT_11N, bMaskDWord);
-       FalseAlmCnt->Cnt_BW_LSC = (ret_value&0xffff);
-       FalseAlmCnt->Cnt_BW_USC = (ret_value & 0xffff0000)>>16;
+       FalseAlmCnt->Cnt_BW_LSC = (ret_value & 0xffff);
+       FalseAlmCnt->Cnt_BW_USC = (ret_value & 0xffff0000) >> 16;
 
        /* hold cck counter */
        phy_set_bb_reg(adapter, ODM_REG_CCK_FA_RST_11N, BIT(12), 1);
@@ -544,10 +544,10 @@ void odm_FalseAlarmCounterStatistics(struct odm_dm_struct *pDM_Odm)
        ret_value = phy_query_bb_reg(adapter, ODM_REG_CCK_FA_LSB_11N, bMaskByte0);
        FalseAlmCnt->Cnt_Cck_fail = ret_value;
        ret_value = phy_query_bb_reg(adapter, ODM_REG_CCK_FA_MSB_11N, bMaskByte3);
-       FalseAlmCnt->Cnt_Cck_fail +=  (ret_value & 0xff)<<8;
+       FalseAlmCnt->Cnt_Cck_fail +=  (ret_value & 0xff) << 8;
 
        ret_value = phy_query_bb_reg(adapter, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord);
-       FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) | ((ret_value&0xFF00)>>8);
+       FalseAlmCnt->Cnt_CCK_CCA = ((ret_value & 0xFF) << 8) | ((ret_value & 0xFF00) >> 8);
 
        FalseAlmCnt->Cnt_all = (FalseAlmCnt->Cnt_Fast_Fsync +
                                FalseAlmCnt->Cnt_SB_Search_fail +
@@ -583,14 +583,14 @@ void odm_CCKPacketDetectionThresh(struct odm_dm_struct *pDM_Odm)
        u8 CurCCK_CCAThres;
        struct false_alarm_stats *FalseAlmCnt = &(pDM_Odm->FalseAlmCnt);
 
-       if (!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD|ODM_BB_FA_CNT)))
+       if (!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD | ODM_BB_FA_CNT)))
                return;
        if (pDM_Odm->ExtLNA)
                return;
        if (pDM_Odm->bLinked) {
                if (pDM_Odm->RSSI_Min > 25) {
                        CurCCK_CCAThres = 0xcd;
-               } else if ((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) {
+               } else if (pDM_Odm->RSSI_Min > 10) {
                        CurCCK_CCAThres = 0x83;
                } else {
                        if (FalseAlmCnt->Cnt_Cck_fail > 1000)
@@ -630,10 +630,10 @@ void ODM_RF_Saving(struct odm_dm_struct *pDM_Odm, u8 bForceInNormal)
                Rssi_Low_bound = 45;
        }
        if (pDM_PSTable->initialize == 0) {
-               pDM_PSTable->Reg874 = (phy_query_bb_reg(adapter, 0x874, bMaskDWord)&0x1CC000)>>14;
-               pDM_PSTable->RegC70 = (phy_query_bb_reg(adapter, 0xc70, bMaskDWord) & BIT(3))>>3;
-               pDM_PSTable->Reg85C = (phy_query_bb_reg(adapter, 0x85c, bMaskDWord)&0xFF000000)>>24;
-               pDM_PSTable->RegA74 = (phy_query_bb_reg(adapter, 0xa74, bMaskDWord)&0xF000)>>12;
+               pDM_PSTable->Reg874 = (phy_query_bb_reg(adapter, 0x874, bMaskDWord) & 0x1CC000) >> 14;
+               pDM_PSTable->RegC70 = (phy_query_bb_reg(adapter, 0xc70, bMaskDWord) & BIT(3)) >> 3;
+               pDM_PSTable->Reg85C = (phy_query_bb_reg(adapter, 0x85c, bMaskDWord) & 0xFF000000) >> 24;
+               pDM_PSTable->RegA74 = (phy_query_bb_reg(adapter, 0xa74, bMaskDWord) & 0xF000) >> 12;
                pDM_PSTable->initialize = 1;
        }
 
@@ -718,13 +718,13 @@ u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, u32 ra_mask, u
                else
                        rate_bitmap = 0x0000000f;
                break;
-       case (ODM_WM_A|ODM_WM_G):
+       case (ODM_WM_A | ODM_WM_G):
                if (rssi_level == DM_RATR_STA_HIGH)
                        rate_bitmap = 0x00000f00;
                else
                        rate_bitmap = 0x00000ff0;
                break;
-       case (ODM_WM_B|ODM_WM_G):
+       case (ODM_WM_B | ODM_WM_G):
                if (rssi_level == DM_RATR_STA_HIGH)
                        rate_bitmap = 0x00000f00;
                else if (rssi_level == DM_RATR_STA_MIDDLE)
@@ -732,8 +732,8 @@ u32 ODM_Get_Rate_Bitmap(struct odm_dm_struct *pDM_Odm, u32 macid, u32 ra_mask, u
                else
                        rate_bitmap = 0x00000ff5;
                break;
-       case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
-       case (ODM_WM_A|ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
+       case (ODM_WM_B | ODM_WM_G | ODM_WM_N24G):
+       case (ODM_WM_A | ODM_WM_B | ODM_WM_G | ODM_WM_N24G):
                if (rssi_level == DM_RATR_STA_HIGH) {
                        rate_bitmap = 0x000f0000;
                } else if (rssi_level == DM_RATR_STA_MIDDLE) {
@@ -911,7 +911,7 @@ void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
                        if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB)
                                tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
                        if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1))
-                               PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16));
+                               PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB << 16));
                }
        }
 
index d5a9ac5..a6f2731 100644 (file)
@@ -103,33 +103,33 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
                switch (LNA_idx) {
                case 7:
                        if (VGA_idx <= 27)
-                               rx_pwr_all = -100 + 2 * (27-VGA_idx); /* VGA_idx = 27~2 */
+                               rx_pwr_all = -100 + 2 * (27 - VGA_idx); /* VGA_idx = 27~2 */
                        else
                                rx_pwr_all = -100;
                        break;
                case 6:
-                       rx_pwr_all = -48 + 2 * (2-VGA_idx); /* VGA_idx = 2~0 */
+                       rx_pwr_all = -48 + 2 * (2 - VGA_idx); /* VGA_idx = 2~0 */
                        break;
                case 5:
-                       rx_pwr_all = -42 + 2 * (7-VGA_idx); /* VGA_idx = 7~5 */
+                       rx_pwr_all = -42 + 2 * (7 - VGA_idx); /* VGA_idx = 7~5 */
                        break;
                case 4:
-                       rx_pwr_all = -36 + 2 * (7-VGA_idx); /* VGA_idx = 7~4 */
+                       rx_pwr_all = -36 + 2 * (7 - VGA_idx); /* VGA_idx = 7~4 */
                        break;
                case 3:
-                       rx_pwr_all = -24 + 2 * (7-VGA_idx); /* VGA_idx = 7~0 */
+                       rx_pwr_all = -24 + 2 * (7 - VGA_idx); /* VGA_idx = 7~0 */
                        break;
                case 2:
                        if (cck_highpwr)
-                               rx_pwr_all = -12 + 2 * (5-VGA_idx); /* VGA_idx = 5~0 */
+                               rx_pwr_all = -12 + 2 * (5 - VGA_idx); /* VGA_idx = 5~0 */
                        else
-                               rx_pwr_all = -6 + 2 * (5-VGA_idx);
+                               rx_pwr_all = -6 + 2 * (5 - VGA_idx);
                        break;
                case 1:
-                       rx_pwr_all = 8-2 * VGA_idx;
+                       rx_pwr_all = 8 - 2 * VGA_idx;
                        break;
                case 0:
-                       rx_pwr_all = 14-2 * VGA_idx;
+                       rx_pwr_all = 14 - 2 * VGA_idx;
                        break;
                default:
                        break;
@@ -138,7 +138,7 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
                PWDB_ALL = odm_query_rxpwrpercentage(rx_pwr_all);
                if (!cck_highpwr) {
                        if (PWDB_ALL >= 80)
-                               PWDB_ALL = ((PWDB_ALL-80)<<1) + ((PWDB_ALL-80)>>1) + 80;
+                               PWDB_ALL = ((PWDB_ALL - 80) << 1) + ((PWDB_ALL - 80) >> 1) + 80;
                        else if ((PWDB_ALL <= 78) && (PWDB_ALL >= 20))
                                PWDB_ALL += 3;
                        if (PWDB_ALL > 100)
@@ -162,7 +162,7 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
                                else if (SQ_rpt < 20)
                                        SQ = 100;
                                else
-                                       SQ = ((64-SQ_rpt) * 100) / 44;
+                                       SQ = ((64 - SQ_rpt) * 100) / 44;
                        }
                        pPhyInfo->SignalQuality = SQ;
                        pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = SQ;
@@ -200,8 +200,8 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct odm_dm_struct *dm_odm,
                        pPhyInfo->RxMIMOSignalStrength[i] = (u8)RSSI;
 
                        /* Get Rx snr value in DB */
-                       pPhyInfo->RxSNR[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
-                       dm_odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
+                       pPhyInfo->RxSNR[i] = (s32)(pPhyStaRpt->path_rxsnr[i] / 2);
+                       dm_odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i] / 2);
                }
                /*  (2)PWDB, Average PWDB calculated by hardware (for rate adaptive) */
                rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f) - 110;
@@ -280,8 +280,8 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
        if (dm_odm->AntDivType == CG_TRX_SMART_ANTDIV) {
                if (pDM_FatTable->FAT_State == FAT_TRAINING_STATE) {
                        if (pPktinfo->bPacketToSelf) {
-                               antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |
-                                               (pDM_FatTable->antsel_rx_keep_1<<1) |
+                               antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2 << 2) |
+                                               (pDM_FatTable->antsel_rx_keep_1 << 1) |
                                                pDM_FatTable->antsel_rx_keep_0;
                                pDM_FatTable->antSumRSSI[antsel_tr_mux] += pPhyInfo->RxPWDBAll;
                                pDM_FatTable->antRSSIcnt[antsel_tr_mux]++;
@@ -289,8 +289,8 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
                }
        } else if ((dm_odm->AntDivType == CG_TRX_HW_ANTDIV) || (dm_odm->AntDivType == CGCS_RX_HW_ANTDIV)) {
                if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) {
-                       antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2<<2) |
-                                       (pDM_FatTable->antsel_rx_keep_1<<1) | pDM_FatTable->antsel_rx_keep_0;
+                       antsel_tr_mux = (pDM_FatTable->antsel_rx_keep_2 << 2) |
+                                       (pDM_FatTable->antsel_rx_keep_1 << 1) | pDM_FatTable->antsel_rx_keep_0;
                        rtl88eu_dm_ant_sel_statistics(dm_odm, antsel_tr_mux, pPktinfo->StationID, pPhyInfo->RxPWDBAll);
                }
        }
@@ -328,17 +328,17 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
                        } else {
                                if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) {
                                        UndecoratedSmoothedOFDM =
-                                                       (((UndecoratedSmoothedOFDM) * (Rx_Smooth_Factor-1)) +
+                                                       (((UndecoratedSmoothedOFDM) * (Rx_Smooth_Factor - 1)) +
                                                        (RSSI_Ave)) / (Rx_Smooth_Factor);
                                        UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1;
                                } else {
                                        UndecoratedSmoothedOFDM =
-                                                       (((UndecoratedSmoothedOFDM) * (Rx_Smooth_Factor-1)) +
+                                                       (((UndecoratedSmoothedOFDM) * (Rx_Smooth_Factor - 1)) +
                                                        (RSSI_Ave)) / (Rx_Smooth_Factor);
                                }
                        }
 
-                       pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT(0);
+                       pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap << 1) | BIT(0);
 
                } else {
                        RSSI_Ave = pPhyInfo->RxPWDBAll;
@@ -349,16 +349,16 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
                        } else {
                                if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) {
                                        UndecoratedSmoothedCCK =
-                                                       ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor-1)) +
+                                                       ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor - 1)) +
                                                        pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor;
                                        UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1;
                                } else {
                                        UndecoratedSmoothedCCK =
-                                                       ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor-1)) +
+                                                       ((UndecoratedSmoothedCCK * (Rx_Smooth_Factor - 1)) +
                                                        pPhyInfo->RxPWDBAll) / Rx_Smooth_Factor;
                                }
                        }
-                       pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1;
+                       pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap << 1;
                }
                /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */
                if (pEntry->rssi_stat.ValidBit >= 64)
@@ -367,16 +367,16 @@ static void odm_Process_RSSIForDM(struct odm_dm_struct *dm_odm,
                        pEntry->rssi_stat.ValidBit++;
 
                for (i = 0; i < pEntry->rssi_stat.ValidBit; i++)
-                       OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap>>i) & BIT(0);
+                       OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap >> i) & BIT(0);
 
                if (pEntry->rssi_stat.ValidBit == 64) {
                        Weighting = min_t(u32, OFDM_pkt << 4, 64);
-                       UndecoratedSmoothedPWDB = (Weighting * UndecoratedSmoothedOFDM + (64-Weighting) * UndecoratedSmoothedCCK)>>6;
+                       UndecoratedSmoothedPWDB = (Weighting * UndecoratedSmoothedOFDM + (64 - Weighting) * UndecoratedSmoothedCCK) >> 6;
                } else {
                        if (pEntry->rssi_stat.ValidBit != 0)
                                UndecoratedSmoothedPWDB = (OFDM_pkt * UndecoratedSmoothedOFDM +
-                                                         (pEntry->rssi_stat.ValidBit-OFDM_pkt) *
-                                                         UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit;
+                                                         (pEntry->rssi_stat.ValidBit - OFDM_pkt) *
+                                                         UndecoratedSmoothedCCK) / pEntry->rssi_stat.ValidBit;
                        else
                                UndecoratedSmoothedPWDB = 0;
                }
index afaf9e5..b902581 100644 (file)
@@ -69,10 +69,10 @@ static u32 rf_serial_read(struct adapter *adapt,
                                            bMaskDWord);
 
        tmplong2 = (tmplong2 & (~bLSSIReadAddress)) |
-                  (offset<<23) | bLSSIReadEdge;
+                  (offset << 23) | bLSSIReadEdge;
 
        phy_set_bb_reg(adapt, rFPGA0_XA_HSSIParameter2, bMaskDWord,
-                      tmplong&(~bLSSIReadEdge));
+                      tmplong & (~bLSSIReadEdge));
        udelay(10);
 
        phy_set_bb_reg(adapt, phyreg->rfHSSIPara2, bMaskDWord, tmplong2);
@@ -102,7 +102,7 @@ static void rf_serial_write(struct adapter *adapt,
        struct bb_reg_def *phyreg = &adapt->HalData->PHYRegDef[rfpath];
 
        offset &= 0xff;
-       data_and_addr = ((offset<<20) | (data&0x000fffff)) & 0x0fffffff;
+       data_and_addr = ((offset << 20) | (data & 0x000fffff)) & 0x0fffffff;
        phy_set_bb_reg(adapt, phyreg->rf3wireOffset, bMaskDWord, data_and_addr);
 }
 
@@ -143,20 +143,20 @@ static void get_tx_power_index(struct adapter *adapt, u8 channel, u8 *cck_pwr,
        for (TxCount = 0; TxCount < path_nums; TxCount++) {
                if (TxCount == RF_PATH_A) {
                        cck_pwr[TxCount] = hal_data->Index24G_CCK_Base[TxCount][index];
-                       ofdm_pwr[TxCount] = hal_data->Index24G_BW40_Base[RF_PATH_A][index]+
+                       ofdm_pwr[TxCount] = hal_data->Index24G_BW40_Base[RF_PATH_A][index] +
                                            hal_data->OFDM_24G_Diff[TxCount][RF_PATH_A];
 
-                       bw20_pwr[TxCount] = hal_data->Index24G_BW40_Base[RF_PATH_A][index]+
+                       bw20_pwr[TxCount] = hal_data->Index24G_BW40_Base[RF_PATH_A][index] +
                                            hal_data->BW20_24G_Diff[TxCount][RF_PATH_A];
                        bw40_pwr[TxCount] = hal_data->Index24G_BW40_Base[TxCount][index];
                } else if (TxCount == RF_PATH_B) {
                        cck_pwr[TxCount] = hal_data->Index24G_CCK_Base[TxCount][index];
-                       ofdm_pwr[TxCount] = hal_data->Index24G_BW40_Base[RF_PATH_A][index]+
-                       hal_data->BW20_24G_Diff[RF_PATH_A][index]+
+                       ofdm_pwr[TxCount] = hal_data->Index24G_BW40_Base[RF_PATH_A][index] +
+                       hal_data->BW20_24G_Diff[RF_PATH_A][index] +
                        hal_data->BW20_24G_Diff[TxCount][index];
 
-                       bw20_pwr[TxCount] = hal_data->Index24G_BW40_Base[RF_PATH_A][index]+
-                       hal_data->BW20_24G_Diff[TxCount][RF_PATH_A]+
+                       bw20_pwr[TxCount] = hal_data->Index24G_BW40_Base[RF_PATH_A][index] +
+                       hal_data->BW20_24G_Diff[TxCount][RF_PATH_A] +
                        hal_data->BW20_24G_Diff[TxCount][index];
                        bw40_pwr[TxCount] = hal_data->Index24G_BW40_Base[TxCount][index];
                }
@@ -205,7 +205,7 @@ static void phy_set_bw_mode_callback(struct adapter *adapt)
        /* Set MAC register */
 
        reg_bw_opmode = usb_read8(adapt, REG_BWOPMODE);
-       reg_prsr_rsc = usb_read8(adapt, REG_RRSR+2);
+       reg_prsr_rsc = usb_read8(adapt, REG_RRSR + 2);
 
        switch (hal_data->CurrentChannelBW) {
        case HT_CHANNEL_WIDTH_20:
@@ -215,9 +215,9 @@ static void phy_set_bw_mode_callback(struct adapter *adapt)
        case HT_CHANNEL_WIDTH_40:
                reg_bw_opmode &= ~BW_OPMODE_20MHZ;
                usb_write8(adapt, REG_BWOPMODE, reg_bw_opmode);
-               reg_prsr_rsc = (reg_prsr_rsc&0x90) |
-                              (hal_data->nCur40MhzPrimeSC<<5);
-               usb_write8(adapt, REG_RRSR+2, reg_prsr_rsc);
+               reg_prsr_rsc = (reg_prsr_rsc & 0x90) |
+                              (hal_data->nCur40MhzPrimeSC << 5);
+               usb_write8(adapt, REG_RRSR + 2, reg_prsr_rsc);
                break;
        default:
                break;
@@ -236,7 +236,7 @@ static void phy_set_bw_mode_callback(struct adapter *adapt)
                 * These settings are required only for 40MHz
                 */
                phy_set_bb_reg(adapt, rCCK0_System, bCCKSideBand,
-                   (hal_data->nCur40MhzPrimeSC>>1));
+                   (hal_data->nCur40MhzPrimeSC >> 1));
                phy_set_bb_reg(adapt, rOFDM1_LSTF, 0xC00,
                               hal_data->nCur40MhzPrimeSC);
                phy_set_bb_reg(adapt, 0x818, (BIT(26) | BIT(27)),
@@ -337,8 +337,8 @@ void rtl88eu_dm_txpower_track_adjust(struct odm_dm_struct *dm_odm, u8 type,
        if (pwr_value >= ODM_TXPWRTRACK_MAX_IDX_88E && *direction == 1)
                pwr_value = ODM_TXPWRTRACK_MAX_IDX_88E;
 
-       *out_write_val = pwr_value | (pwr_value<<8) | (pwr_value<<16) |
-                        (pwr_value<<24);
+       *out_write_val = pwr_value | (pwr_value << 8) | (pwr_value << 16) |
+                        (pwr_value << 24);
 }
 
 static void dm_txpwr_track_setpwr(struct odm_dm_struct *dm_odm)
@@ -389,9 +389,9 @@ void rtl88eu_dm_txpower_tracking_callback_thermalmeter(struct adapter *adapt)
 
        if (thermal_val) {
                /* Query OFDM path A default setting */
-               ele_d = phy_query_bb_reg(adapt, rOFDM0_XATxIQImbalance, bMaskDWord)&bMaskOFDM_D;
+               ele_d = phy_query_bb_reg(adapt, rOFDM0_XATxIQImbalance, bMaskDWord) & bMaskOFDM_D;
                for (i = 0; i < OFDM_TABLE_SIZE_92D; i++) {
-                       if (ele_d == (OFDMSwingTable[i]&bMaskOFDM_D)) {
+                       if (ele_d == (OFDMSwingTable[i] & bMaskOFDM_D)) {
                                ofdm_index_old[0] = (u8)i;
                                dm_odm->BbSwingIdxOfdmBase = (u8)i;
                                break;
@@ -472,18 +472,18 @@ void rtl88eu_dm_txpower_tracking_callback_thermalmeter(struct adapter *adapt)
                                }
                        }
                        if (offset >= index_mapping_NUM_88E)
-                               offset = index_mapping_NUM_88E-1;
+                               offset = index_mapping_NUM_88E - 1;
 
                        /* Updating ofdm_index values with new OFDM / CCK offset */
                        ofdm_index[0] = dm_odm->RFCalibrateInfo.OFDM_index[0] + ofdm_index_mapping[j][offset];
-                       if (ofdm_index[0] > OFDM_TABLE_SIZE_92D-1)
-                               ofdm_index[0] = OFDM_TABLE_SIZE_92D-1;
+                       if (ofdm_index[0] > OFDM_TABLE_SIZE_92D - 1)
+                               ofdm_index[0] = OFDM_TABLE_SIZE_92D - 1;
                        else if (ofdm_index[0] < ofdm_min_index)
                                ofdm_index[0] = ofdm_min_index;
 
                        cck_index = dm_odm->RFCalibrateInfo.CCK_index + ofdm_index_mapping[j][offset];
-                       if (cck_index > CCK_TABLE_SIZE-1)
-                               cck_index = CCK_TABLE_SIZE-1;
+                       if (cck_index > CCK_TABLE_SIZE - 1)
+                               cck_index = CCK_TABLE_SIZE - 1;
                        else if (cck_index < 0)
                                cck_index = 0;
 
@@ -548,8 +548,8 @@ static u8 phy_path_a_iqk(struct adapter *adapt, bool config_pathb)
        reg_e9c = phy_query_bb_reg(adapt, rTx_Power_After_IQK_A, bMaskDWord);
 
        if (!(reg_eac & BIT(28)) &&
-           (((reg_e94 & 0x03FF0000)>>16) != 0x142) &&
-           (((reg_e9c & 0x03FF0000)>>16) != 0x42))
+           (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+           (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
                result |= 0x01;
        return result;
 }
@@ -600,13 +600,13 @@ static u8 phy_path_a_rx_iqk(struct adapter *adapt, bool configPathB)
        reg_e9c = phy_query_bb_reg(adapt, rTx_Power_After_IQK_A, bMaskDWord);
 
        if (!(reg_eac & BIT(28)) &&
-           (((reg_e94 & 0x03FF0000)>>16) != 0x142) &&
-           (((reg_e9c & 0x03FF0000)>>16) != 0x42))
+           (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+           (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
                result |= 0x01;
        else                                    /* if Tx not OK, ignore Rx */
                return result;
 
-       u4tmp = 0x80007C00 | (reg_e94&0x3FF0000)  | ((reg_e9c&0x3FF0000) >> 16);
+       u4tmp = 0x80007C00 | (reg_e94 & 0x3FF0000)  | ((reg_e9c & 0x3FF0000) >> 16);
        phy_set_bb_reg(adapt, rTx_IQK, bMaskDWord, u4tmp);
 
        /* 1 RX IQK */
@@ -648,8 +648,8 @@ static u8 phy_path_a_rx_iqk(struct adapter *adapt, bool configPathB)
        phy_set_rf_reg(adapt, RF_PATH_A, 0xdf, bRFRegOffsetMask, 0x180);
 
        if (!(reg_eac & BIT(27)) && /* if Tx is OK, check whether Rx is OK */
-           (((reg_ea4 & 0x03FF0000)>>16) != 0x132) &&
-           (((reg_eac & 0x03FF0000)>>16) != 0x36))
+           (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
+           (((reg_eac & 0x03FF0000) >> 16) != 0x36))
                result |= 0x02;
        else
                ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
@@ -677,15 +677,15 @@ static u8 phy_path_b_iqk(struct adapter *adapt)
        regecc = phy_query_bb_reg(adapt, rRx_Power_After_IQK_B_2, bMaskDWord);
 
        if (!(regeac & BIT(31)) &&
-           (((regeb4 & 0x03FF0000)>>16) != 0x142) &&
-           (((regebc & 0x03FF0000)>>16) != 0x42))
+           (((regeb4 & 0x03FF0000) >> 16) != 0x142) &&
+           (((regebc & 0x03FF0000) >> 16) != 0x42))
                result |= 0x01;
        else
                return result;
 
        if (!(regeac & BIT(30)) &&
-           (((regec4 & 0x03FF0000)>>16) != 0x132) &&
-           (((regecc & 0x03FF0000)>>16) != 0x36))
+           (((regec4 & 0x03FF0000) >> 16) != 0x132) &&
+           (((regecc & 0x03FF0000) >> 16) != 0x36))
                result |= 0x02;
        else
                ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION,
@@ -711,7 +711,7 @@ static void patha_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8],
                tx0_a = (x * oldval_0) >> 8;
                phy_set_bb_reg(adapt, rOFDM0_XATxIQImbalance, 0x3FF, tx0_a);
                phy_set_bb_reg(adapt, rOFDM0_ECCAThreshold, BIT(31),
-                              ((x * oldval_0>>7) & 0x1));
+                              ((x * oldval_0 >> 7) & 0x1));
 
                y = result[final_candidate][1];
                if ((y & 0x00000200) != 0)
@@ -719,11 +719,11 @@ static void patha_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8],
 
                tx0_c = (y * oldval_0) >> 8;
                phy_set_bb_reg(adapt, rOFDM0_XCTxAFE, 0xF0000000,
-                              ((tx0_c&0x3C0)>>6));
+                              ((tx0_c & 0x3C0) >> 6));
                phy_set_bb_reg(adapt, rOFDM0_XATxIQImbalance, 0x003F0000,
-                              (tx0_c&0x3F));
+                              (tx0_c & 0x3F));
                phy_set_bb_reg(adapt, rOFDM0_ECCAThreshold, BIT(29),
-                              ((y * oldval_0>>7) & 0x1));
+                              ((y * oldval_0 >> 7) & 0x1));
 
                if (txonly)
                        return;
@@ -757,7 +757,7 @@ static void pathb_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8],
                phy_set_bb_reg(adapt, rOFDM0_XBTxIQImbalance, 0x3FF, tx1_a);
 
                phy_set_bb_reg(adapt, rOFDM0_ECCAThreshold, BIT(27),
-                              ((x * oldval_1>>7) & 0x1));
+                              ((x * oldval_1 >> 7) & 0x1));
 
                y = result[final_candidate][5];
                if ((y & 0x00000200) != 0)
@@ -766,11 +766,11 @@ static void pathb_fill_iqk(struct adapter *adapt, bool iqkok, s32 result[][8],
                tx1_c = (y * oldval_1) >> 8;
 
                phy_set_bb_reg(adapt, rOFDM0_XDTxAFE, 0xF0000000,
-                              ((tx1_c&0x3C0)>>6));
+                              ((tx1_c & 0x3C0) >> 6));
                phy_set_bb_reg(adapt, rOFDM0_XBTxIQImbalance, 0x003F0000,
-                              (tx1_c&0x3F));
+                              (tx1_c & 0x3F));
                phy_set_bb_reg(adapt, rOFDM0_ECCAThreshold, BIT(25),
-                              ((y * oldval_1>>7) & 0x1));
+                              ((y * oldval_1 >> 7) & 0x1));
 
                if (txonly)
                        return;
@@ -851,9 +851,9 @@ static void mac_setting_calibration(struct adapter *adapt, u32 *mac_reg, u32 *ba
        usb_write8(adapt, mac_reg[i], 0x3F);
 
        for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
-               usb_write8(adapt, mac_reg[i], (u8)(backup[i]&(~BIT(3))));
+               usb_write8(adapt, mac_reg[i], (u8)(backup[i] & (~BIT(3))));
 
-       usb_write8(adapt, mac_reg[i], (u8)(backup[i]&(~BIT(5))));
+       usb_write8(adapt, mac_reg[i], (u8)(backup[i] & (~BIT(5))));
 }
 
 static void path_a_standby(struct adapter *adapt)
@@ -902,22 +902,22 @@ static bool simularity_compare(struct adapter *adapt, s32 resulta[][8],
 
                if (diff > MAX_TOLERANCE) {
                        if ((i == 2 || i == 6) && !sim_bitmap) {
-                               if (resulta[c1][i] + resulta[c1][i+1] == 0)
-                                       final_candidate[(i/4)] = c2;
-                               else if (resulta[c2][i] + resulta[c2][i+1] == 0)
-                                       final_candidate[(i/4)] = c1;
+                               if (resulta[c1][i] + resulta[c1][i + 1] == 0)
+                                       final_candidate[(i / 4)] = c2;
+                               else if (resulta[c2][i] + resulta[c2][i + 1] == 0)
+                                       final_candidate[(i / 4)] = c1;
                                else
-                                       sim_bitmap = sim_bitmap | (1<<i);
+                                       sim_bitmap = sim_bitmap | (1 << i);
                        } else {
-                               sim_bitmap = sim_bitmap | (1<<i);
+                               sim_bitmap = sim_bitmap | (1 << i);
                        }
                }
        }
 
        if (sim_bitmap == 0) {
-               for (i = 0; i < (bound/4); i++) {
+               for (i = 0; i < (bound / 4); i++) {
                        if (final_candidate[i] != 0xFF) {
-                               for (j = i*4; j < (i+1)*4-2; j++)
+                               for (j = i * 4; j < (i + 1) * 4 - 2; j++)
                                        resulta[3][j] = resulta[final_candidate[i]][j];
                                result = false;
                        }
@@ -1038,9 +1038,9 @@ static void phy_iq_calibrate(struct adapter *adapt, s32 result[][8],
                path_a_ok = phy_path_a_iqk(adapt, is2t);
                if (path_a_ok == 0x01) {
                                result[t][0] = (phy_query_bb_reg(adapt, rTx_Power_Before_IQK_A,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                                result[t][1] = (phy_query_bb_reg(adapt, rTx_Power_After_IQK_A,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                        break;
                }
        }
@@ -1049,9 +1049,9 @@ static void phy_iq_calibrate(struct adapter *adapt, s32 result[][8],
                path_a_ok = phy_path_a_rx_iqk(adapt, is2t);
                if (path_a_ok == 0x03) {
                                result[t][2] = (phy_query_bb_reg(adapt, rRx_Power_Before_IQK_A_2,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                                result[t][3] = (phy_query_bb_reg(adapt, rRx_Power_After_IQK_A_2,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                        break;
                }
                ODM_RT_TRACE(dm_odm, ODM_COMP_CALIBRATION, ODM_DBG_LOUD,
@@ -1073,19 +1073,19 @@ static void phy_iq_calibrate(struct adapter *adapt, s32 result[][8],
                        path_b_ok = phy_path_b_iqk(adapt);
                        if (path_b_ok == 0x03) {
                                result[t][4] = (phy_query_bb_reg(adapt, rTx_Power_Before_IQK_B,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                                result[t][5] = (phy_query_bb_reg(adapt, rTx_Power_After_IQK_B,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                                result[t][6] = (phy_query_bb_reg(adapt, rRx_Power_Before_IQK_B_2,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                                result[t][7] = (phy_query_bb_reg(adapt, rRx_Power_After_IQK_B_2,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                                break;
                        } else if (i == (retry_count - 1) && path_b_ok == 0x01) {       /* Tx IQK OK */
                                result[t][4] = (phy_query_bb_reg(adapt, rTx_Power_Before_IQK_B,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                                result[t][5] = (phy_query_bb_reg(adapt, rTx_Power_After_IQK_B,
-                                                                bMaskDWord)&0x3FF0000)>>16;
+                                                                bMaskDWord) & 0x3FF0000) >> 16;
                        }
                }
 
@@ -1138,12 +1138,12 @@ static void phy_lc_calibrate(struct adapter *adapt, bool is2t)
        /* Check continuous TX and Packet TX */
        tmpreg = usb_read8(adapt, 0xd03);
 
-       if ((tmpreg&0x70) != 0)
-               usb_write8(adapt, 0xd03, tmpreg&0x8F);
+       if ((tmpreg & 0x70) != 0)
+               usb_write8(adapt, 0xd03, tmpreg & 0x8F);
        else
                usb_write8(adapt, REG_TXPAUSE, 0xFF);
 
-       if ((tmpreg&0x70) != 0) {
+       if ((tmpreg & 0x70) != 0) {
                /* 1. Read original RF mode */
                /* Path-A */
                rf_a_mode = rtw_hal_read_rfreg(adapt, RF_PATH_A, RF_AC,
@@ -1157,12 +1157,12 @@ static void phy_lc_calibrate(struct adapter *adapt, bool is2t)
                /* 2. Set RF mode = standby mode */
                /* Path-A */
                phy_set_rf_reg(adapt, RF_PATH_A, RF_AC, bMask12Bits,
-                              (rf_a_mode&0x8FFFF)|0x10000);
+                              (rf_a_mode & 0x8FFFF) | 0x10000);
 
                /* Path-B */
                if (is2t)
                        phy_set_rf_reg(adapt, RF_PATH_B, RF_AC, bMask12Bits,
-                                      (rf_b_mode&0x8FFFF)|0x10000);
+                                      (rf_b_mode & 0x8FFFF) | 0x10000);
        }
 
        /* 3. Read RF reg18 */
@@ -1170,12 +1170,12 @@ static void phy_lc_calibrate(struct adapter *adapt, bool is2t)
 
        /* 4. Set LC calibration begin bit15 */
        phy_set_rf_reg(adapt, RF_PATH_A, RF_CHNLBW, bMask12Bits,
-                      lc_cal|0x08000);
+                      lc_cal | 0x08000);
 
        msleep(100);
 
        /* Restore original situation */
-       if ((tmpreg&0x70) != 0) {
+       if ((tmpreg & 0x70) != 0) {
                /* Deal with continuous TX case */
                /* Path-A */
                usb_write8(adapt, 0xd03, tmpreg);
index 249cbc3..77edd7a 100644 (file)
@@ -85,7 +85,7 @@ u8 rtl88eu_pwrseqcmdparsing(struct adapter *padapter, u8 cut_vers,
                                if (GET_PWR_CFG_VALUE(pwrcfgcmd) == PWRSEQ_DELAY_US)
                                        udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd));
                                else
-                                       udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd)*1000);
+                                       udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd) * 1000);
                                break;
                        case PWR_CMD_END:
                                /* When this command is parsed, end the process */
index 6fe4dae..00a9f69 100644 (file)
@@ -49,9 +49,9 @@ void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel)
                tx_agc[RF_PATH_B] = 0x3f3f3f3f;
                for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
                        tx_agc[idx1] = powerlevel[idx1] |
-                                     (powerlevel[idx1]<<8) |
-                                     (powerlevel[idx1]<<16) |
-                                     (powerlevel[idx1]<<24);
+                                     (powerlevel[idx1] << 8) |
+                                     (powerlevel[idx1] << 16) |
+                                     (powerlevel[idx1] << 24);
                }
        } else {
                if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
@@ -63,17 +63,17 @@ void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel)
                } else {
                        for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
                                tx_agc[idx1] = powerlevel[idx1] |
-                                              (powerlevel[idx1]<<8) |
-                                              (powerlevel[idx1]<<16) |
-                                              (powerlevel[idx1]<<24);
+                                              (powerlevel[idx1] << 8) |
+                                              (powerlevel[idx1] << 16) |
+                                              (powerlevel[idx1] << 24);
                        }
                        if (hal_data->EEPROMRegulatory == 0) {
                                tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][6] +
-                                        (hal_data->MCSTxPowerLevelOriginalOffset[0][7]<<8);
+                                        (hal_data->MCSTxPowerLevelOriginalOffset[0][7] << 8);
                                tx_agc[RF_PATH_A] += tmpval;
 
                                tmpval = hal_data->MCSTxPowerLevelOriginalOffset[0][14] +
-                                        (hal_data->MCSTxPowerLevelOriginalOffset[0][15]<<24);
+                                        (hal_data->MCSTxPowerLevelOriginalOffset[0][15] << 24);
                                tx_agc[RF_PATH_B] += tmpval;
                        }
                }
@@ -100,15 +100,15 @@ void rtl88eu_phy_rf6052_set_cck_txpower(struct adapter *adapt, u8 *powerlevel)
        }
 
        /*  rf-A cck tx power */
-       tmpval = tx_agc[RF_PATH_A]&0xff;
+       tmpval = tx_agc[RF_PATH_A] & 0xff;
        phy_set_bb_reg(adapt, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
-       tmpval = tx_agc[RF_PATH_A]>>8;
+       tmpval = tx_agc[RF_PATH_A] >> 8;
        phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
 
        /*  rf-B cck tx power */
-       tmpval = tx_agc[RF_PATH_B]>>24;
+       tmpval = tx_agc[RF_PATH_B] >> 24;
        phy_set_bb_reg(adapt, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
-       tmpval = tx_agc[RF_PATH_B]&0x00ffffff;
+       tmpval = tx_agc[RF_PATH_B] & 0x00ffffff;
        phy_set_bb_reg(adapt, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
 }
 
@@ -124,9 +124,9 @@ static void getpowerbase88e(struct adapter *adapt, u8 *pwr_level_ofdm,
        for (i = 0; i < 2; i++) {
                powerbase0 = pwr_level_ofdm[i];
 
-               powerbase0 = (powerbase0<<24) | (powerbase0<<16) |
-                            (powerbase0<<8) | powerbase0;
-               *(ofdmbase+i) = powerbase0;
+               powerbase0 = (powerbase0 << 24) | (powerbase0 << 16) |
+                            (powerbase0 << 8) | powerbase0;
+               *(ofdmbase + i) = powerbase0;
        }
        /* Check HT20 to HT40 diff */
        if (adapt->HalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
@@ -134,8 +134,8 @@ static void getpowerbase88e(struct adapter *adapt, u8 *pwr_level_ofdm,
        else
                powerlevel[0] = pwr_level_bw40[0];
        powerbase1 = powerlevel[0];
-       powerbase1 = (powerbase1<<24) | (powerbase1<<16) |
-                    (powerbase1<<8) | powerbase1;
+       powerbase1 = (powerbase1 << 24) | (powerbase1 << 16) |
+                    (powerbase1 << 8) | powerbase1;
        *mcs_base = powerbase1;
 }
 static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
@@ -157,7 +157,7 @@ static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
                switch (regulatory) {
                case 0:
                        chnlGroup = 0;
-                       write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
+                       write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
                                ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
                        break;
                case 1: /*  Realtek regulatory */
@@ -167,7 +167,7 @@ static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
                        if (hal_data->pwrGroupCnt >= hal_data->PGMaxGroup)
                                Hal_GetChnlGroup88E(channel, &chnlGroup);
 
-                       write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf ? 8 : 0)] +
+                       write_val = hal_data->MCSTxPowerLevelOriginalOffset[chnlGroup][index + (rf ? 8 : 0)] +
                                        ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
                        break;
                case 2: /*  Better regulatory */
@@ -179,14 +179,14 @@ static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
                        chnlGroup = 0;
 
                        if (index < 2)
-                               pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel-1];
+                               pwr_diff = hal_data->TxPwrLegacyHtDiff[rf][channel - 1];
                        else if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
-                               pwr_diff = hal_data->TxPwrHt20Diff[rf][channel-1];
+                               pwr_diff = hal_data->TxPwrHt20Diff[rf][channel - 1];
 
                        if (hal_data->CurrentChannelBW == HT_CHANNEL_WIDTH_40)
-                               customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel-1];
+                               customer_pwr_limit = hal_data->PwrGroupHT40[rf][channel - 1];
                        else
-                               customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel-1];
+                               customer_pwr_limit = hal_data->PwrGroupHT20[rf][channel - 1];
 
                        if (pwr_diff >= customer_pwr_limit)
                                pwr_diff = 0;
@@ -200,9 +200,9 @@ static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
                                if (pwr_diff_limit[i] > pwr_diff)
                                        pwr_diff_limit[i] = pwr_diff;
                        }
-                       customer_limit = (pwr_diff_limit[3]<<24) |
-                                        (pwr_diff_limit[2]<<16) |
-                                        (pwr_diff_limit[1]<<8) |
+                       customer_limit = (pwr_diff_limit[3] << 24) |
+                                        (pwr_diff_limit[2] << 16) |
+                                        (pwr_diff_limit[1] << 8) |
                                         (pwr_diff_limit[0]);
                        write_val = customer_limit + ((index < 2) ? powerbase0[rf] : powerbase1[rf]);
                        break;
@@ -221,7 +221,7 @@ static void get_rx_power_val_by_reg(struct adapter *adapt, u8 channel,
                else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
                        write_val = 0x00000000;
 
-               *(out_val+rf) = write_val;
+               *(out_val + rf) = write_val;
        }
 }
 
@@ -240,12 +240,12 @@ static void write_ofdm_pwr_reg(struct adapter *adapt, u8 index, u32 *pvalue)
        for (rf = 0; rf < 2; rf++) {
                write_val = pvalue[rf];
                for (i = 0; i < 4; i++) {
-                       pwr_val[i] = (u8)((write_val & (0x7f<<(i*8)))>>(i*8));
+                       pwr_val[i] = (u8)((write_val & (0x7f << (i * 8))) >> (i * 8));
                        if (pwr_val[i]  > RF6052_MAX_TX_PWR)
                                pwr_val[i]  = RF6052_MAX_TX_PWR;
                }
-               write_val = (pwr_val[3]<<24) | (pwr_val[2]<<16) |
-                           (pwr_val[1]<<8) | pwr_val[0];
+               write_val = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
+                           (pwr_val[1] << 8) | pwr_val[0];
 
                if (rf == 0)
                        regoffset = regoffset_a[index];
index 47b1bf5..0b20e62 100644 (file)
@@ -15,7 +15,7 @@ static bool check_condition(struct adapter *adapt, const u32  condition)
        u32 _board = odm->BoardType;
        u32 _platform = odm->SupportPlatform;
        u32 _interface = odm->SupportInterface;
-       u32 cond = condition;
+       u32 cond;
 
        if (condition == 0xCDCDCDCD)
                return true;
@@ -143,7 +143,7 @@ static u32 Array_RadioA_1T_8188E[] = {
 #define READ_NEXT_PAIR(v1, v2, i)      \
 do {                                                           \
        i += 2; v1 = array[i];                  \
-       v2 = array[i+1];                                \
+       v2 = array[i + 1];                              \
 } while (0)
 
 #define RFREG_OFFSET_MASK 0xfffff
@@ -190,7 +190,7 @@ static bool rtl88e_phy_config_rf_with_headerfile(struct adapter *adapt)
 
        for (i = 0; i < array_len; i += 2) {
                u32 v1 = array[i];
-               u32 v2 = array[i+1];
+               u32 v2 = array[i + 1];
 
                if (v1 < 0xCDCDCDCD) {
                        rtl8188e_config_rf_reg(adapt, v1, v2);
index 7646167..371e746 100644 (file)
@@ -113,24 +113,24 @@ void rtw_hal_add_ra_tid(struct adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_le
        struct odm_dm_struct *odmpriv = &pAdapter->HalData->odmpriv;
        u8 macid, init_rate, raid, shortGIrate = false;
 
-       macid = arg&0x1f;
+       macid = arg & 0x1f;
 
-       raid = (bitmap>>28) & 0x0f;
+       raid = (bitmap >> 28) & 0x0f;
        bitmap &= 0x0fffffff;
 
        if (rssi_level != DM_RATR_STA_INIT)
                bitmap = ODM_Get_Rate_Bitmap(odmpriv, macid, bitmap, rssi_level);
 
-       bitmap |= ((raid<<28)&0xf0000000);
+       bitmap |= ((raid << 28) & 0xf0000000);
 
-       init_rate = get_highest_rate_idx(bitmap&0x0fffffff)&0x3f;
+       init_rate = get_highest_rate_idx(bitmap & 0x0fffffff) & 0x3f;
 
        shortGIrate = (arg & BIT(5)) ? true : false;
 
        if (shortGIrate)
                init_rate |= BIT(6);
 
-       raid = (bitmap>>28) & 0x0f;
+       raid = (bitmap >> 28) & 0x0f;
 
        bitmap &= 0x0fffffff;
 
@@ -172,7 +172,7 @@ void rtl8188e_set_FwPwrMode_cmd(struct adapter *adapt, u8 Mode)
                break;
        }
 
-       H2CSetPwrMode.SmartPS_RLBM = (((pwrpriv->smart_ps<<4)&0xf0) | (RLBM & 0x0f));
+       H2CSetPwrMode.SmartPS_RLBM = (((pwrpriv->smart_ps << 4) & 0xf0) | (RLBM & 0x0f));
 
        H2CSetPwrMode.AwakeInterval = 1;
 
@@ -239,9 +239,9 @@ static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength)
        pframe += 2;
        pktlen += 2;
 
-       if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+       if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
                pktlen += cur_network->ie_length - sizeof(struct ndis_802_11_fixed_ie);
-               memcpy(pframe, cur_network->ies+sizeof(struct ndis_802_11_fixed_ie), pktlen);
+               memcpy(pframe, cur_network->ies + sizeof(struct ndis_802_11_fixed_ie), pktlen);
 
                goto _ConstructBeacon;
        }
@@ -258,7 +258,7 @@ static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength)
        /*  DS parameter set */
        pframe = rtw_set_ie(pframe, _DSSET_IE_, 1, (unsigned char *)&(cur_network->Configuration.DSConfig), &pktlen);
 
-       if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+       if ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) {
                u32 ATIMWindow;
                /*  IBSS Parameter Set... */
                ATIMWindow = 0;
@@ -473,7 +473,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
        /* 3 (2) ps-poll *1 page */
        RsvdPageLoc.LocPsPoll = PageNum;
        ConstructPSPoll(adapt, &ReservedPagePacket[BufIndex], &PSPollLength);
-       rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false);
+       rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex - TxDescLen], PSPollLength, true, false);
 
        PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength);
        PageNum += PageNeed;
@@ -483,7 +483,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
        /* 3 (3) null data * 1 page */
        RsvdPageLoc.LocNullData = PageNum;
        ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, pnetwork->MacAddress, false, 0, 0, false);
-       rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
+       rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex - TxDescLen], NullDataLength, false, false);
 
        PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
        PageNum += PageNeed;
@@ -493,7 +493,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
        /* 3 (4) probe response * 1page */
        RsvdPageLoc.LocProbeRsp = PageNum;
        ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, pnetwork->MacAddress, false);
-       rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
+       rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex - TxDescLen], ProbeRspLength, false, false);
 
        PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
        PageNum += PageNeed;
@@ -504,7 +504,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
        RsvdPageLoc.LocQosNull = PageNum;
        ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex],
                                  &QosNullLength, pnetwork->MacAddress, true, 0, 0, false);
-       rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
+       rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex - TxDescLen], QosNullLength, false, false);
 
        PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
        PageNum += PageNeed;
@@ -546,17 +546,17 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
        if (mstatus == 1) {
                /*  We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
                /*  Suggested by filen. Added by tynli. */
-               usb_write16(adapt, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
+               usb_write16(adapt, REG_BCN_PSR_RPT, (0xC000 | pmlmeinfo->aid));
                /*  Do not set TSF again here or vWiFi beacon DMA INT will not work. */
 
                /* Set REG_CR bit 8. DMA beacon by SW. */
                haldata->RegCR_1 |= BIT(0);
-               usb_write8(adapt,  REG_CR+1, haldata->RegCR_1);
+               usb_write8(adapt,  REG_CR + 1, haldata->RegCR_1);
 
                /*  Disable Hw protection for a time which revserd for Hw sending beacon. */
                /*  Fix download reserved page packet fail that access collision with the protection time. */
                /*  2010.05.11. Added by tynli. */
-               usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL)&(~BIT(3)));
+               usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL) & (~BIT(3)));
                usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL) | BIT(4));
 
                if (haldata->RegFwHwTxQCtrl & BIT(6)) {
@@ -565,7 +565,7 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
                }
 
                /*  Set FWHW_TXQ_CTRL 0x422[6]=0 to tell Hw the packet is not a real beacon frame. */
-               usb_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl&(~BIT(6))));
+               usb_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl & (~BIT(6))));
                haldata->RegFwHwTxQCtrl &= (~BIT(6));
 
                /*  Clear beacon valid check bit. */
@@ -582,7 +582,7 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
                                /*  check rsvd page download OK. */
                                rtw_hal_get_hwreg(adapt, HW_VAR_BCN_VALID, (u8 *)(&bcn_valid));
                                poll++;
-                       } while (!bcn_valid && (poll%10) != 0 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
+                       } while (!bcn_valid && (poll % 10) != 0 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
                } while (!bcn_valid && DLBcnCount <= 100 && !adapt->bSurpriseRemoved && !adapt->bDriverStopped);
 
                if (adapt->bSurpriseRemoved || adapt->bDriverStopped)
@@ -600,7 +600,7 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
 
                /*  Enable Bcn */
                usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL) | BIT(3));
-               usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL)&(~BIT(4)));
+               usb_write8(adapt, REG_BCN_CTRL, usb_read8(adapt, REG_BCN_CTRL) & (~BIT(4)));
 
                /*  To make sure that if there exists an adapter which would like to send beacon. */
                /*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
@@ -608,7 +608,7 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
                /*  the beacon cannot be sent by HW. */
                /*  2010.06.23. Added by tynli. */
                if (bSendBeacon) {
-                       usb_write8(adapt, REG_FWHW_TXQ_CTRL+2, (haldata->RegFwHwTxQCtrl | BIT(6)));
+                       usb_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl | BIT(6)));
                        haldata->RegFwHwTxQCtrl |= BIT(6);
                }
 
@@ -621,6 +621,6 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus)
                /*  Do not enable HW DMA BCN or it will cause Pcie interface hang by timing issue. 2011.11.24. by tynli. */
                /*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
                haldata->RegCR_1 &= (~BIT(0));
-               usb_write8(adapt,  REG_CR+1, haldata->RegCR_1);
+               usb_write8(adapt,  REG_CR + 1, haldata->RegCR_1);
        }
 }
index 57ae0e8..740004d 100644 (file)
@@ -22,7 +22,7 @@ void iol_mode_enable(struct adapter *padapter, u8 enable)
        if (enable) {
                /* Enable initial offload */
                reg_0xf0 = usb_read8(padapter, REG_SYS_CFG);
-               usb_write8(padapter, REG_SYS_CFG, reg_0xf0|SW_OFFLOAD_EN);
+               usb_write8(padapter, REG_SYS_CFG, reg_0xf0 | SW_OFFLOAD_EN);
 
                if (!padapter->bFWReady) {
                        DBG_88E("bFWReady == false call reset 8051...\n");
@@ -42,9 +42,9 @@ s32 iol_execute(struct adapter *padapter, u8 control)
        u8 reg_0x88 = 0;
        unsigned long start = 0;
 
-       control = control&0x0f;
+       control = control & 0x0f;
        reg_0x88 = usb_read8(padapter, REG_HMEBOX_E0);
-       usb_write8(padapter, REG_HMEBOX_E0,  reg_0x88|control);
+       usb_write8(padapter, REG_HMEBOX_E0,  reg_0x88 | control);
 
        start = jiffies;
        while ((reg_0x88 = usb_read8(padapter, REG_HMEBOX_E0)) & control &&
@@ -54,7 +54,7 @@ s32 iol_execute(struct adapter *padapter, u8 control)
 
        reg_0x88 = usb_read8(padapter, REG_HMEBOX_E0);
        status = (reg_0x88 & control) ? _FAIL : _SUCCESS;
-       if (reg_0x88 & control<<4)
+       if (reg_0x88 & control << 4)
                status = _FAIL;
        return status;
 }
@@ -64,7 +64,7 @@ static s32 iol_InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy)
        s32 rst = _SUCCESS;
 
        iol_mode_enable(padapter, 1);
-       usb_write8(padapter, REG_TDECTRL+1, txpktbuf_bndy);
+       usb_write8(padapter, REG_TDECTRL + 1, txpktbuf_bndy);
        rst = iol_execute(padapter, CMD_INIT_LLT);
        iol_mode_enable(padapter, 0);
        return rst;
@@ -92,9 +92,9 @@ void _8051Reset88E(struct adapter *padapter)
 {
        u8 u1bTmp;
 
-       u1bTmp = usb_read8(padapter, REG_SYS_FUNC_EN+1);
-       usb_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp&(~BIT(2)));
-       usb_write8(padapter, REG_SYS_FUNC_EN+1, u1bTmp|(BIT(2)));
+       u1bTmp = usb_read8(padapter, REG_SYS_FUNC_EN + 1);
+       usb_write8(padapter, REG_SYS_FUNC_EN + 1, u1bTmp & (~BIT(2)));
+       usb_write8(padapter, REG_SYS_FUNC_EN + 1, u1bTmp | (BIT(2)));
        DBG_88E("=====> _8051Reset88E(): 8051 reset success .\n");
 }
 
@@ -122,7 +122,7 @@ void rtw_hal_read_chip_version(struct adapter *padapter)
        value32 = usb_read32(padapter, REG_SYS_CFG);
        ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP);
        ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC);
-       ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK)>>CHIP_VER_RTL_SHIFT; /*  IC version (CUT) */
+       ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK) >> CHIP_VER_RTL_SHIFT; /*  IC version (CUT) */
 
        dump_chip_info(ChipVersion);
 
@@ -163,10 +163,10 @@ void rtw_hal_notch_filter(struct adapter *adapter, bool enable)
 {
        if (enable) {
                DBG_88E("Enable notch filter\n");
-               usb_write8(adapter, rOFDM0_RxDSP+1, usb_read8(adapter, rOFDM0_RxDSP+1) | BIT(1));
+               usb_write8(adapter, rOFDM0_RxDSP + 1, usb_read8(adapter, rOFDM0_RxDSP + 1) | BIT(1));
        } else {
                DBG_88E("Disable notch filter\n");
-               usb_write8(adapter, rOFDM0_RxDSP+1, usb_read8(adapter, rOFDM0_RxDSP+1) & ~BIT(1));
+               usb_write8(adapter, rOFDM0_RxDSP + 1, usb_read8(adapter, rOFDM0_RxDSP + 1) & ~BIT(1));
        }
 }
 
@@ -308,7 +308,7 @@ static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G,
                        if (pwrInfo24G->IndexCCK_Base[rfPath][group] == 0xFF)
                                pwrInfo24G->IndexCCK_Base[rfPath][group] = EEPROM_DEFAULT_24G_INDEX;
                }
-               for (group = 0; group < MAX_CHNL_GROUP_24G-1; group++) {
+               for (group = 0; group < MAX_CHNL_GROUP_24G - 1; group++) {
                        pwrInfo24G->IndexBW40_Base[rfPath][group] =     PROMContent[eeAddr++];
                        if (pwrInfo24G->IndexBW40_Base[rfPath][group] == 0xFF)
                                pwrInfo24G->IndexBW40_Base[rfPath][group] =     EEPROM_DEFAULT_24G_INDEX;
@@ -319,7 +319,7 @@ static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G,
                                if (PROMContent[eeAddr] == 0xFF) {
                                        pwrInfo24G->BW20_Diff[rfPath][TxCount] = EEPROM_DEFAULT_24G_HT20_DIFF;
                                } else {
-                                       pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0xf0)>>4;
+                                       pwrInfo24G->BW20_Diff[rfPath][TxCount] = (PROMContent[eeAddr] & 0xf0) >> 4;
                                        if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT(3))            /* 4bit sign number to 8 bit sign number */
                                                pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0;
                                }
@@ -327,7 +327,7 @@ static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G,
                                if (PROMContent[eeAddr] == 0xFF) {
                                        pwrInfo24G->OFDM_Diff[rfPath][TxCount] =        EEPROM_DEFAULT_24G_OFDM_DIFF;
                                } else {
-                                       pwrInfo24G->OFDM_Diff[rfPath][TxCount] =        (PROMContent[eeAddr]&0x0f);
+                                       pwrInfo24G->OFDM_Diff[rfPath][TxCount] =        (PROMContent[eeAddr] & 0x0f);
                                        if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT(3))            /* 4bit sign number to 8 bit sign number */
                                                pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0;
                                }
@@ -337,7 +337,7 @@ static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G,
                                if (PROMContent[eeAddr] == 0xFF) {
                                        pwrInfo24G->BW40_Diff[rfPath][TxCount] =        EEPROM_DEFAULT_DIFF;
                                } else {
-                                       pwrInfo24G->BW40_Diff[rfPath][TxCount] =        (PROMContent[eeAddr]&0xf0)>>4;
+                                       pwrInfo24G->BW40_Diff[rfPath][TxCount] =        (PROMContent[eeAddr] & 0xf0) >> 4;
                                        if (pwrInfo24G->BW40_Diff[rfPath][TxCount] & BIT(3))            /* 4bit sign number to 8 bit sign number */
                                                pwrInfo24G->BW40_Diff[rfPath][TxCount] |= 0xF0;
                                }
@@ -345,7 +345,7 @@ static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G,
                                if (PROMContent[eeAddr] == 0xFF) {
                                        pwrInfo24G->BW20_Diff[rfPath][TxCount] =        EEPROM_DEFAULT_DIFF;
                                } else {
-                                       pwrInfo24G->BW20_Diff[rfPath][TxCount] =        (PROMContent[eeAddr]&0x0f);
+                                       pwrInfo24G->BW20_Diff[rfPath][TxCount] =        (PROMContent[eeAddr] & 0x0f);
                                        if (pwrInfo24G->BW20_Diff[rfPath][TxCount] & BIT(3))            /* 4bit sign number to 8 bit sign number */
                                                pwrInfo24G->BW20_Diff[rfPath][TxCount] |= 0xF0;
                                }
@@ -354,7 +354,7 @@ static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G,
                                if (PROMContent[eeAddr] == 0xFF) {
                                        pwrInfo24G->OFDM_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
                                } else {
-                                       pwrInfo24G->OFDM_Diff[rfPath][TxCount] =        (PROMContent[eeAddr]&0xf0)>>4;
+                                       pwrInfo24G->OFDM_Diff[rfPath][TxCount] =        (PROMContent[eeAddr] & 0xf0) >> 4;
                                        if (pwrInfo24G->OFDM_Diff[rfPath][TxCount] & BIT(3))            /* 4bit sign number to 8 bit sign number */
                                                pwrInfo24G->OFDM_Diff[rfPath][TxCount] |= 0xF0;
                                }
@@ -362,7 +362,7 @@ static void Hal_ReadPowerValueFromPROM_8188E(struct txpowerinfo24g *pwrInfo24G,
                                if (PROMContent[eeAddr] == 0xFF) {
                                        pwrInfo24G->CCK_Diff[rfPath][TxCount] = EEPROM_DEFAULT_DIFF;
                                } else {
-                                       pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr]&0x0f);
+                                       pwrInfo24G->CCK_Diff[rfPath][TxCount] = (PROMContent[eeAddr] & 0x0f);
                                        if (pwrInfo24G->CCK_Diff[rfPath][TxCount] & BIT(3))             /* 4bit sign number to 8 bit sign number */
                                                pwrInfo24G->CCK_Diff[rfPath][TxCount] |= 0xF0;
                                }
@@ -450,9 +450,9 @@ void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *PROMContent, bool Auto
 
        /*  2010/10/19 MH Add Regulator recognize for CU. */
        if (!AutoLoadFail) {
-               pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x7);     /* bit0~2 */
+               pHalData->EEPROMRegulatory = (PROMContent[EEPROM_RF_BOARD_OPTION_88E] & 0x7);   /* bit0~2 */
                if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
-                       pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION&0x7); /* bit0~2 */
+                       pHalData->EEPROMRegulatory = (EEPROM_DEFAULT_BOARD_OPTION & 0x7);       /* bit0~2 */
        } else {
                pHalData->EEPROMRegulatory = 0;
        }
@@ -532,9 +532,9 @@ void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool
        if (!AutoLoadFail) {
                /*  Antenna Diversity setting. */
                if (registry_par->antdiv_cfg == 2) { /*  2:By EFUSE */
-                       pHalData->AntDivCfg = (PROMContent[EEPROM_RF_BOARD_OPTION_88E]&0x18)>>3;
+                       pHalData->AntDivCfg = (PROMContent[EEPROM_RF_BOARD_OPTION_88E] & 0x18) >> 3;
                        if (PROMContent[EEPROM_RF_BOARD_OPTION_88E] == 0xFF)
-                               pHalData->AntDivCfg = (EEPROM_DEFAULT_BOARD_OPTION&0x18)>>3;
+                               pHalData->AntDivCfg = (EEPROM_DEFAULT_BOARD_OPTION & 0x18) >> 3;
                } else {
                        pHalData->AntDivCfg = registry_par->antdiv_cfg;  /*  0:OFF , 1:ON, 2:By EFUSE */
                }
index 0a90082..7d0135f 100644 (file)
@@ -182,7 +182,7 @@ void update_recvframe_phyinfo_88e(struct recv_frame *precvframe,
                        rtl8188e_process_phy_info(padapter, precvframe);
                }
        } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) {
-               if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE)) {
+               if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) {
                        if (psta)
                                precvframe->psta = psta;
                }
index 2808f2b..7d315bd 100644 (file)
@@ -58,12 +58,12 @@ void rtl8188e_fill_fake_txdesc(struct adapter *adapt, u8 *desc, u32 BufferLen, u
        /* offset 0 */
        ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); /* own, bFirstSeg, bLastSeg; */
 
-       ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000); /* 32 bytes for TX Desc */
+       ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) << OFFSET_SHT) & 0x00ff0000); /* 32 bytes for TX Desc */
 
-       ptxdesc->txdw0 |= cpu_to_le32(BufferLen&0x0000ffff); /*  Buffer size + command header */
+       ptxdesc->txdw0 |= cpu_to_le32(BufferLen & 0x0000ffff); /*  Buffer size + command header */
 
        /* offset 4 */
-       ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT<<QSEL_SHT)&0x00001f00); /*  Fixed queue of Mgnt queue */
+       ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT << QSEL_SHT) & 0x00001f00); /*  Fixed queue of Mgnt queue */
 
        /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed to error vlaue by Hw. */
        if (ispspoll) {
@@ -91,16 +91,16 @@ static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxd
                /* SEC_TYPE : 0:NO_ENC,1:WEP40/TKIP,2:WAPI,3:AES */
                case _WEP40_:
                case _WEP104_:
-                       ptxdesc->txdw1 |= cpu_to_le32((0x01<<SEC_TYPE_SHT)&0x00c00000);
+                       ptxdesc->txdw1 |= cpu_to_le32((0x01 << SEC_TYPE_SHT) & 0x00c00000);
                        ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
                        break;
                case _TKIP_:
                case _TKIP_WTMIC_:
-                       ptxdesc->txdw1 |= cpu_to_le32((0x01<<SEC_TYPE_SHT)&0x00c00000);
+                       ptxdesc->txdw1 |= cpu_to_le32((0x01 << SEC_TYPE_SHT) & 0x00c00000);
                        ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
                        break;
                case _AES_:
-                       ptxdesc->txdw1 |= cpu_to_le32((0x03<<SEC_TYPE_SHT)&0x00c00000);
+                       ptxdesc->txdw1 |= cpu_to_le32((0x03 << SEC_TYPE_SHT) & 0x00c00000);
                        ptxdesc->txdw2 |= cpu_to_le32(0x7 << AMPDU_DENSITY_SHT);
                        break;
                case _NO_PRIVACY_:
@@ -127,7 +127,7 @@ static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw)
                *pdw |= cpu_to_le32(HW_RTS_EN);
                /*  Set RTS BW */
                if (pattrib->ht_en) {
-                       *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0;
+                       *pdw |= (pattrib->bwmode & HT_CHANNEL_WIDTH_40) ?       cpu_to_le32(BIT(27)) : 0;
 
                        if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
                                *pdw |= cpu_to_le32((0x01 << 28) & 0x30000000);
@@ -144,7 +144,7 @@ static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw)
 static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw)
 {
        if (pattrib->ht_en) {
-               *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0;
+               *pdw |= (pattrib->bwmode & HT_CHANNEL_WIDTH_40) ?       cpu_to_le32(BIT(25)) : 0;
 
                if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
                        *pdw |= cpu_to_le32((0x01 << DATA_SC_SHT) & 0x003f0000);
@@ -171,7 +171,7 @@ static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bag
 
        if (adapt->registrypriv.mp_mode == 0) {
                if ((!bagg_pkt) && (urb_zero_packet_chk(adapt, sz) == 0)) {
-                       ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ);
+                       ptxdesc = (struct tx_desc *)(pmem + PACKET_OFFSET_SZ);
                        pull = 1;
                }
        }
@@ -263,11 +263,11 @@ static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bag
                                ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/*  DATA_SHORT */
                        ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
                }
-       } else if ((pxmitframe->frame_tag&0x0f) == MGNT_FRAMETAG) {
+       } else if ((pxmitframe->frame_tag & 0x0f) == MGNT_FRAMETAG) {
                /* offset 4 */
                ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id & 0x3f);
 
-               qsel = (uint)(pattrib->qsel&0x0000001f);
+               qsel = (uint)(pattrib->qsel & 0x0000001f);
                ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
 
                ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid << RATE_ID_SHT) & 0x000f0000);
@@ -278,7 +278,7 @@ static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bag
                        ptxdesc->txdw2 |= cpu_to_le32(BIT(19));
 
                /* offset 12 */
-               ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<SEQ_SHT)&0x0FFF0000);
+               ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0x0FFF0000);
 
                /* offset 20 */
                ptxdesc->txdw5 |= cpu_to_le32(RTY_LMT_EN);/* retry limit enable */
@@ -288,7 +288,7 @@ static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bag
                        ptxdesc->txdw5 |= cpu_to_le32(0x00300000);/* retry limit = 12 */
 
                ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
-       } else if ((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) {
+       } else if ((pxmitframe->frame_tag & 0x0f) == TXAGG_FRAMETAG) {
                DBG_88E("pxmitframe->frame_tag == TXAGG_FRAMETAG\n");
        } else {
                DBG_88E("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag);
@@ -301,7 +301,7 @@ static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bag
                /* offset 8 */
 
                /* offset 12 */
-               ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<SEQ_SHT)&0x0fff0000);
+               ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum << SEQ_SHT) & 0x0fff0000);
 
                /* offset 20 */
                ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate(pmlmeext->tx_rate));
@@ -466,7 +466,7 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt,
 
        /* 3 2. aggregate same priority and same DA(AP or STA) frames */
        pfirstframe = pxmitframe;
-       len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE + (pfirstframe->pkt_offset*PACKET_OFFSET_SZ);
+       len = xmitframe_need_length(pfirstframe) + TXDESC_SIZE + (pfirstframe->pkt_offset * PACKET_OFFSET_SZ);
        pbuf_tail = len;
        pbuf = round_up(pbuf_tail, 8);
 
@@ -517,7 +517,7 @@ bool rtl8188eu_xmitframe_complete(struct adapter *adapt,
                pxmitframe->agg_num = 0; /*  not first frame of aggregation */
                pxmitframe->pkt_offset = 0; /*  not first frame of aggregation, no need to reserve offset */
 
-               len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE + (pxmitframe->pkt_offset*PACKET_OFFSET_SZ);
+               len = xmitframe_need_length(pxmitframe) + TXDESC_SIZE + (pxmitframe->pkt_offset * PACKET_OFFSET_SZ);
 
                if (round_up(pbuf + len, 8) > MAX_XMITBUF_SZ) {
                        pxmitframe->agg_num = 1;
index ba7e15f..b9f11ef 100644 (file)
@@ -112,7 +112,7 @@ struct pkt_attrib {
        u32     last_txcmdsz;
        u8      nr_frags;
        u8      encrypt;        /* when 0 indicate no encrypt. when non-zero,
-                                * indicate the encrypt algorith
+                                * indicate the encrypt algorithm
                                 */
        u8      iv_len;
        u8      icv_len;
index ba53959..9a89791 100644 (file)
@@ -193,12 +193,12 @@ static char *translate_scan(struct adapter *padapter,
        /*Add basic and extended rates */
        max_rate = 0;
        p = custom;
-       p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
+       p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
        while (pnetwork->network.SupportedRates[i] != 0) {
                rate = pnetwork->network.SupportedRates[i]&0x7F;
                if (rate > max_rate)
                        max_rate = rate;
-               p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+               p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
                              "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
                i++;
        }
index 69d4b1d..4d6d034 100644 (file)
@@ -26,18 +26,17 @@ void _rtw_init_queue(struct __queue *pqueue)
 
 struct net_device *rtw_alloc_etherdev_with_old_priv(void *old_priv)
 {
-       struct net_device *pnetdev;
+       struct net_device *netdev;
        struct rtw_netdev_priv_indicator *pnpi;
 
-       pnetdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
-       if (!pnetdev)
-               goto RETURN;
+       netdev = alloc_etherdev_mq(sizeof(struct rtw_netdev_priv_indicator), 4);
+       if (!netdev)
+               return NULL;
 
-       pnpi = netdev_priv(pnetdev);
+       pnpi = netdev_priv(netdev);
        pnpi->priv = old_priv;
 
-RETURN:
-       return pnetdev;
+       return netdev;
 }
 
 void rtw_free_netdev(struct net_device *netdev)
@@ -45,18 +44,15 @@ void rtw_free_netdev(struct net_device *netdev)
        struct rtw_netdev_priv_indicator *pnpi;
 
        if (!netdev)
-               goto RETURN;
+               return;
 
        pnpi = netdev_priv(netdev);
 
        if (!pnpi->priv)
-               goto RETURN;
+               return;
 
        vfree(pnpi->priv);
        free_netdev(netdev);
-
-RETURN:
-       return;
 }
 
 void rtw_buf_free(u8 **buf, u32 *buf_len)
index b5d42f4..f7f09c0 100644 (file)
@@ -32,12 +32,14 @@ static const struct usb_device_id rtw_usb_id_tbl[] = {
        /****** 8188EUS ********/
        {USB_DEVICE(0x056e, 0x4008)}, /* Elecom WDC-150SU2M */
        {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
+       {USB_DEVICE(0x0B05, 0x18F0)}, /* ASUS USB-N10 Nano B1 */
        {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
        {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
        {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */
        {USB_DEVICE(0x2001, 0x331B)}, /* D-Link DWA-121 rev B1 */
        {USB_DEVICE(0x2357, 0x010c)}, /* TP-Link TL-WN722N v2 */
        {USB_DEVICE(0x2357, 0x0111)}, /* TP-Link TL-WN727N v5.21 */
+       {USB_DEVICE(0x2C4E, 0x0102)}, /* MERCUSYS MW150US v2 */
        {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0xffef)}, /* Rosewill RNX-N150NUB */
        {}      /* Terminating entry */
index 980b850..ddcd788 100644 (file)
@@ -304,7 +304,7 @@ static void _rtl92e_read_eeprom_info(struct net_device *dev)
        u16 i, usValue, IC_Version;
        u16 EEPROMId;
 
-       RT_TRACE(COMP_INIT, "====> _rtl92e_read_eeprom_info\n");
+       RT_TRACE(COMP_INIT, "====> %s\n", __func__);
 
        EEPROMId = rtl92e_eeprom_read(dev, 0);
        if (EEPROMId != RTL8190_EEPROM_ID) {
@@ -1354,8 +1354,8 @@ static u8 _rtl92e_rate_hw_to_mgn(bool bIsHT, u8 rate)
 
                default:
                        RT_TRACE(COMP_RECV,
-                                "_rtl92e_rate_hw_to_mgn(): Non supportedRate [%x], bIsHT = %d!!!\n",
-                                rate, bIsHT);
+                                "%s: Non supportedRate [%x], bIsHT = %d!!!\n",
+                                __func__, rate, bIsHT);
                        break;
                }
 
@@ -1415,8 +1415,8 @@ static u8 _rtl92e_rate_hw_to_mgn(bool bIsHT, u8 rate)
 
                default:
                        RT_TRACE(COMP_RECV,
-                                "_rtl92e_rate_hw_to_mgn(): Non supported Rate [%x], bIsHT = %d!!!\n",
-                                rate, bIsHT);
+                                "%s: Non supported Rate [%x], bIsHT = %d!!!\n",
+                                __func__, rate, bIsHT);
                        break;
                }
        }
index 7d78f16..4111381 100644 (file)
@@ -1124,14 +1124,14 @@ static void _rtl92e_cck_tx_power_track_bw_switch_thermal(struct net_device *dev)
                        priv->Record_CCK_20Mindex = 6;
                priv->CCK_index = priv->Record_CCK_20Mindex;
                RT_TRACE(COMP_POWER_TRACKING,
-                        "20MHz, _rtl92e_cck_tx_power_track_bw_switch_thermal(),CCK_index = %d\n",
+                        "20MHz, %s,CCK_index = %d\n", __func__,
                         priv->CCK_index);
        break;
 
        case HT_CHANNEL_WIDTH_20_40:
                priv->CCK_index = priv->Record_CCK_40Mindex;
                RT_TRACE(COMP_POWER_TRACKING,
-                        "40MHz, _rtl92e_cck_tx_power_track_bw_switch_thermal(), CCK_index = %d\n",
+                        "40MHz, %s, CCK_index = %d\n", __func__,
                         priv->CCK_index);
        break;
        }
@@ -1155,7 +1155,7 @@ static void _rtl92e_set_bw_mode_work_item(struct net_device *dev)
        u8 regBwOpMode;
 
        RT_TRACE(COMP_SWBW,
-                "==>_rtl92e_set_bw_mode_work_item()  Switch to %s bandwidth\n",
+                "==>%s Switch to %s bandwidth\n", __func__,
                 priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 ?
                         "20MHz" : "40MHz");
 
@@ -1416,15 +1416,14 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
 
        if (priv->SetRFPowerStateInProgress)
                return false;
-       RT_TRACE(COMP_PS, "===========> _rtl92e_set_rf_power_state()!\n");
+       RT_TRACE(COMP_PS, "===========> %s!\n", __func__);
        priv->SetRFPowerStateInProgress = true;
 
        switch (priv->rf_chip) {
        case RF_8256:
                switch (eRFPowerState) {
                case eRfOn:
-                       RT_TRACE(COMP_PS,
-                                "_rtl92e_set_rf_power_state() eRfOn!\n");
+                       RT_TRACE(COMP_PS, "%s eRfOn!\n", __func__);
                        if ((priv->rtllib->eRFPowerState == eRfOff) &&
                             RT_IN_PS_LEVEL(pPSC, RT_RF_OFF_LEVL_HALT_NIC)) {
                                bool rtstatus;
@@ -1490,10 +1489,8 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
                                }
 
                                if (i >= MAX_DOZE_WAITING_TIMES_9x) {
-                                       RT_TRACE(COMP_POWER,
-                                                "\n\n\n TimeOut!! _rtl92e_set_rf_power_state(): eRfOff: %d times TcbBusyQueue[%d] != 0 !!!\n",
-                                                MAX_DOZE_WAITING_TIMES_9x,
-                                                QueueID);
+                                       RT_TRACE(COMP_POWER, "\n\n\n TimeOut!! %s: eRfOff: %d times TcbBusyQueue[%d] != 0 !!!\n",
+                                                __func__, MAX_DOZE_WAITING_TIMES_9x, QueueID);
                                        break;
                                }
                        }
@@ -1501,8 +1498,7 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
                        break;
 
                case eRfOff:
-                       RT_TRACE(COMP_PS,
-                                "_rtl92e_set_rf_power_state() eRfOff/Sleep !\n");
+                       RT_TRACE(COMP_PS, "%s eRfOff/Sleep !\n", __func__);
 
                        for (QueueID = 0, i = 0; QueueID < MAX_TX_QUEUE; ) {
                                ring = &priv->tx_ring[QueueID];
@@ -1567,9 +1563,7 @@ static bool _rtl92e_set_rf_power_state(struct net_device *dev,
        }
 
        priv->SetRFPowerStateInProgress = false;
-       RT_TRACE(COMP_PS,
-                "<=========== _rtl92e_set_rf_power_state() bResult = %d!\n",
-                bResult);
+       RT_TRACE(COMP_PS, "<=========== %s bResult = %d!\n", __func__, bResult);
        return bResult;
 }
 
@@ -1581,21 +1575,17 @@ bool rtl92e_set_rf_power_state(struct net_device *dev,
        bool bResult = false;
 
        RT_TRACE(COMP_PS,
-                "---------> rtl92e_set_rf_power_state(): eRFPowerState(%d)\n",
-                eRFPowerState);
+                "---------> %s: eRFPowerState(%d)\n", __func__, eRFPowerState);
        if (eRFPowerState == priv->rtllib->eRFPowerState &&
            priv->bHwRfOffAction == 0) {
-               RT_TRACE(COMP_PS,
-                        "<--------- rtl92e_set_rf_power_state(): discard the request for eRFPowerState(%d) is the same.\n",
-                        eRFPowerState);
+               RT_TRACE(COMP_PS, "<--------- %s: discard the request for eRFPowerState(%d) is the same.\n",
+                        __func__, eRFPowerState);
                return bResult;
        }
 
        bResult = _rtl92e_set_rf_power_state(dev, eRFPowerState);
 
-       RT_TRACE(COMP_PS,
-                "<--------- rtl92e_set_rf_power_state(): bResult(%d)\n",
-                bResult);
+       RT_TRACE(COMP_PS, "<--------- %s: bResult(%d)\n", __func__, bResult);
 
        return bResult;
 }
index 627ea10..c850651 100644 (file)
@@ -108,8 +108,8 @@ void rtl92e_set_key(struct net_device *dev, u8 EntryNo, u8 KeyIndex,
        }
 
        RT_TRACE(COMP_SEC,
-                "====>to rtl92e_set_key(), dev:%p, EntryNo:%d, KeyIndex:%d,KeyType:%d, MacAddr %pM\n",
-                dev, EntryNo, KeyIndex, KeyType, MacAddr);
+                "====>to %s, dev:%p, EntryNo:%d, KeyIndex:%d,KeyType:%d, MacAddr %pM\n",
+                __func__, dev, EntryNo, KeyIndex, KeyType, MacAddr);
 
        if (DefaultKey)
                usConfig |= BIT15 | (KeyType<<2);
@@ -163,7 +163,7 @@ void rtl92e_cam_restore(struct net_device *dev)
                0xff, 0xff, 0xff, 0xff, 0xff, 0xff
        };
 
-       RT_TRACE(COMP_SEC, "rtl92e_cam_restore:\n");
+       RT_TRACE(COMP_SEC, "%s:\n", __func__);
 
 
        if ((priv->rtllib->pairwise_key_type == KEY_TYPE_WEP40) ||
index 11183b9..d3664e5 100644 (file)
@@ -145,21 +145,21 @@ bool rtl92e_set_rf_state(struct net_device *dev,
        unsigned long flag;
 
        RT_TRACE((COMP_PS | COMP_RF),
-                "===>rtl92e_set_rf_state(): StateToSet(%d)\n", StateToSet);
+                "===>%s: StateToSet(%d)\n", __func__, StateToSet);
 
        while (true) {
                spin_lock_irqsave(&priv->rf_ps_lock, flag);
                if (priv->RFChangeInProgress) {
                        spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
                        RT_TRACE((COMP_PS | COMP_RF),
-                                "rtl92e_set_rf_state(): RF Change in progress! Wait to set..StateToSet(%d).\n",
-                                StateToSet);
+                                "%s: RF Change in progress! Wait to set..StateToSet(%d).\n",
+                                __func__, StateToSet);
 
                        while (priv->RFChangeInProgress) {
                                RFWaitCounter++;
                                RT_TRACE((COMP_PS | COMP_RF),
-                                        "rtl92e_set_rf_state(): Wait 1 ms (%d times)...\n",
-                                        RFWaitCounter);
+                                        "%s: Wait 1 ms (%d times)...\n",
+                                        __func__, RFWaitCounter);
                                mdelay(1);
 
                                if (RFWaitCounter > 100) {
@@ -195,8 +195,8 @@ bool rtl92e_set_rf_state(struct net_device *dev,
                                bConnectBySSID = true;
                } else {
                        RT_TRACE((COMP_PS | COMP_RF),
-                                "rtl92e_set_rf_state - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n",
-                                 priv->rtllib->RfOffReason, ChangeSource);
+                                "%s - eRfon reject pMgntInfo->RfOffReason= 0x%x, ChangeSource=0x%X\n",
+                                __func__, priv->rtllib->RfOffReason, ChangeSource);
        }
 
                break;
@@ -232,8 +232,8 @@ bool rtl92e_set_rf_state(struct net_device *dev,
 
        if (bActionAllowed) {
                RT_TRACE((COMP_PS | COMP_RF),
-                        "rtl92e_set_rf_state(): Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n",
-                        StateToSet, priv->rtllib->RfOffReason);
+                        "%s: Action is allowed.... StateToSet(%d), RfOffReason(%#X)\n",
+                        __func__, StateToSet, priv->rtllib->RfOffReason);
                PHY_SetRFPowerState(dev, StateToSet);
                if (StateToSet == eRfOn) {
 
@@ -245,15 +245,15 @@ bool rtl92e_set_rf_state(struct net_device *dev,
                }
        } else {
                RT_TRACE((COMP_PS | COMP_RF),
-                        "rtl92e_set_rf_state(): Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n",
-                        StateToSet, ChangeSource, priv->rtllib->RfOffReason);
+                        "%s: Action is rejected.... StateToSet(%d), ChangeSource(%#X), RfOffReason(%#X)\n",
+                        __func__, StateToSet, ChangeSource, priv->rtllib->RfOffReason);
        }
 
        spin_lock_irqsave(&priv->rf_ps_lock, flag);
        priv->RFChangeInProgress = false;
        spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
 
-       RT_TRACE((COMP_PS | COMP_RF), "<===rtl92e_set_rf_state()\n");
+       RT_TRACE((COMP_PS | COMP_RF), "<===%s\n", __func__);
        return bActionAllowed;
 }
 
@@ -732,7 +732,7 @@ static int _rtl92e_sta_up(struct net_device *dev, bool is_silent_reset)
        struct r8192_priv *priv = rtllib_priv(dev);
        struct rt_pwr_save_ctrl *pPSC = (struct rt_pwr_save_ctrl *)
                                        (&priv->rtllib->PowerSaveControl);
-       bool init_status = true;
+       bool init_status;
 
        priv->bDriverIsGoingToUnload = false;
        priv->bdisable_nic = false;
index 816d31c..2d5e4a0 100644 (file)
@@ -119,8 +119,8 @@ static struct sk_buff *rtllib_ADDBA(struct rtllib_device *ieee, u8 *Dst,
        }
 
 #ifdef VERBOSE_DEBUG
-       print_hex_dump_bytes("rtllib_ADDBA(): ", DUMP_PREFIX_NONE, skb->data,
-                            skb->len);
+       print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data,
+                            __func__, skb->len);
 #endif
        return skb;
 }
@@ -170,8 +170,8 @@ static struct sk_buff *rtllib_DELBA(struct rtllib_device *ieee, u8 *dst,
        tag += 2;
 
 #ifdef VERBOSE_DEBUG
-       print_hex_dump_bytes("rtllib_DELBA(): ", DUMP_PREFIX_NONE, skb->data,
-                            skb->len);
+       print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data,
+                            __func__, skb->len);
 #endif
        return skb;
 }
@@ -235,7 +235,7 @@ int rtllib_rx_ADDBAReq(struct rtllib_device *ieee, struct sk_buff *skb)
        }
 
 #ifdef VERBOSE_DEBUG
-       print_hex_dump_bytes("rtllib_rx_ADDBAReq(): ", DUMP_PREFIX_NONE,
+       print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, __func__,
                             skb->data, skb->len);
 #endif
 
@@ -433,8 +433,8 @@ int rtllib_rx_DELBA(struct rtllib_device *ieee, struct sk_buff *skb)
        }
 
 #ifdef VERBOSE_DEBUG
-       print_hex_dump_bytes("rtllib_rx_DELBA(): ", DUMP_PREFIX_NONE, skb->data,
-                            skb->len);
+       print_hex_dump_bytes("%s: ", DUMP_PREFIX_NONE, skb->data,
+                            __func__, skb->len);
 #endif
        delba = (struct rtllib_hdr_3addr *)skb->data;
        dst = (u8 *)(&delba->addr2[0]);
index f02263a..d83d725 100644 (file)
@@ -545,7 +545,7 @@ void HTOnAssocRsp(struct rtllib_device *ieee)
 
 
 #ifdef VERBOSE_DEBUG
-       print_hex_dump_bytes("HTOnAssocRsp(): ", DUMP_PREFIX_NONE,
+       print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE,
                             pPeerHTCap, sizeof(struct ht_capab_ele));
 #endif
        HTSetConnectBwMode(ieee, (enum ht_channel_width)(pPeerHTCap->ChlWidth),
index 672bf09..47b2669 100644 (file)
@@ -440,7 +440,7 @@ void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr)
 {
        struct ts_common_info *pTS, *pTmpTS;
 
-       netdev_info(ieee->dev, "===========>RemovePeerTS, %pM\n", Addr);
+       netdev_info(ieee->dev, "===========>%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) {
index 328f410..b84f00b 100644 (file)
@@ -728,14 +728,14 @@ struct rtllib_pspoll_hdr {
 struct rtllib_hdr {
        __le16 frame_ctl;
        __le16 duration_id;
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtllib_hdr_1addr {
        __le16 frame_ctl;
        __le16 duration_id;
        u8 addr1[ETH_ALEN];
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtllib_hdr_2addr {
@@ -743,7 +743,7 @@ struct rtllib_hdr_2addr {
        __le16 duration_id;
        u8 addr1[ETH_ALEN];
        u8 addr2[ETH_ALEN];
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtllib_hdr_3addr {
@@ -753,7 +753,7 @@ struct rtllib_hdr_3addr {
        u8 addr2[ETH_ALEN];
        u8 addr3[ETH_ALEN];
        __le16 seq_ctl;
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtllib_hdr_4addr {
@@ -764,7 +764,7 @@ struct rtllib_hdr_4addr {
        u8 addr3[ETH_ALEN];
        __le16 seq_ctl;
        u8 addr4[ETH_ALEN];
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtllib_hdr_3addrqos {
@@ -775,7 +775,7 @@ struct rtllib_hdr_3addrqos {
        u8 addr3[ETH_ALEN];
        __le16 seq_ctl;
        __le16 qos_ctl;
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtllib_hdr_4addrqos {
@@ -787,13 +787,13 @@ struct rtllib_hdr_4addrqos {
        __le16 seq_ctl;
        u8 addr4[ETH_ALEN];
        __le16 qos_ctl;
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtllib_info_element {
        u8 id;
        u8 len;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 struct rtllib_authentication {
@@ -802,7 +802,7 @@ struct rtllib_authentication {
        __le16 transaction;
        __le16 status;
        /*challenge*/
-       struct rtllib_info_element info_element[0];
+       struct rtllib_info_element info_element[];
 } __packed;
 
 struct rtllib_disauth {
@@ -818,7 +818,7 @@ struct rtllib_disassoc {
 struct rtllib_probe_request {
        struct rtllib_hdr_3addr header;
        /* SSID, supported rates */
-       struct rtllib_info_element info_element[0];
+       struct rtllib_info_element info_element[];
 } __packed;
 
 struct rtllib_probe_response {
@@ -829,7 +829,7 @@ struct rtllib_probe_response {
        /* SSID, supported rates, FH params, DS params,
         * CF params, IBSS params, TIM (if beacon), RSN
         */
-       struct rtllib_info_element info_element[0];
+       struct rtllib_info_element info_element[];
 } __packed;
 
 /* Alias beacon for probe_response */
@@ -840,7 +840,7 @@ struct rtllib_assoc_request_frame {
        __le16 capability;
        __le16 listen_interval;
        /* SSID, supported rates, RSN */
-       struct rtllib_info_element info_element[0];
+       struct rtllib_info_element info_element[];
 } __packed;
 
 struct rtllib_assoc_response_frame {
@@ -848,7 +848,7 @@ struct rtllib_assoc_response_frame {
        __le16 capability;
        __le16 status;
        __le16 aid;
-       struct rtllib_info_element info_element[0]; /* supported rates */
+       struct rtllib_info_element info_element[]; /* supported rates */
 } __packed;
 
 struct rtllib_txb {
@@ -859,7 +859,7 @@ struct rtllib_txb {
        u16 reserved;
        __le16 frag_size;
        __le16 payload_size;
-       struct sk_buff *fragments[0];
+       struct sk_buff *fragments[];
 };
 
 #define MAX_SUBFRAME_COUNT               64
@@ -1792,7 +1792,7 @@ struct rtllib_device {
        /* This must be the last item so that it points to the data
         * allocated beyond this structure by alloc_rtllib
         */
-       u8 priv[0];
+       u8 priv[];
 };
 
 #define IEEE_A     (1<<0)
index 0bae0a0..d31b5e1 100644 (file)
@@ -2092,7 +2092,7 @@ int rtllib_parse_info_param(struct rtllib_device *ieee,
                                                 MAX_RATES_LENGTH);
                        for (i = 0; i < network->rates_len; i++) {
                                network->rates[i] = info_element->data[i];
-                               p += snprintf(p, sizeof(rates_str) -
+                               p += scnprintf(p, sizeof(rates_str) -
                                              (p - rates_str), "%02X ",
                                              network->rates[i]);
                                if (rtllib_is_ofdm_rate
@@ -2120,7 +2120,7 @@ int rtllib_parse_info_param(struct rtllib_device *ieee,
                                                    MAX_RATES_EX_LENGTH);
                        for (i = 0; i < network->rates_ex_len; i++) {
                                network->rates_ex[i] = info_element->data[i];
-                               p += snprintf(p, sizeof(rates_str) -
+                               p += scnprintf(p, sizeof(rates_str) -
                                              (p - rates_str), "%02X ",
                                              network->rates_ex[i]);
                                if (rtllib_is_ofdm_rate
index 8cddb2e..79d7ad7 100644 (file)
@@ -241,7 +241,7 @@ static int rtllib_classify(struct sk_buff *skb, u8 bIsAmsdu)
                return 0;
 
 #ifdef VERBOSE_DEBUG
-       print_hex_dump_bytes("rtllib_classify(): ", DUMP_PREFIX_NONE, skb->data,
+       print_hex_dump_bytes("%s: ", __func__, DUMP_PREFIX_NONE, skb->data,
                             skb->len);
 #endif
        ip = ip_hdr(skb);
index beb4096..7e7df50 100644 (file)
@@ -114,7 +114,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
        /* Add basic and extended rates */
        max_rate = 0;
        p = custom;
-       p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
+       p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
        for (i = 0, j = 0; i < network->rates_len;) {
                if (j < network->rates_ex_len &&
                    ((network->rates_ex[j] & 0x7F) <
@@ -124,12 +124,12 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
                        rate = network->rates[i++] & 0x7F;
                if (rate > max_rate)
                        max_rate = rate;
-               p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+               p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
                              "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
        }
        for (; j < network->rates_ex_len; j++) {
                rate = network->rates_ex[j] & 0x7F;
-               p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+               p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
                              "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
                if (rate > max_rate)
                        max_rate = rate;
@@ -226,7 +226,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
         */
        iwe.cmd = IWEVCUSTOM;
        p = custom;
-       p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+       p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
                      " Last beacon: %lums ago",
                      (jiffies - network->last_scanned) / (HZ / 100));
        iwe.u.data.length = p - custom;
index 9576b64..39f4ddd 100644 (file)
@@ -886,14 +886,14 @@ enum ieee80211_mfie {
 struct rtl_80211_hdr {
        __le16 frame_ctl;
        __le16 duration_id;
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtl_80211_hdr_1addr {
        __le16 frame_ctl;
        __le16 duration_id;
        u8 addr1[ETH_ALEN];
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtl_80211_hdr_2addr {
@@ -901,7 +901,7 @@ struct rtl_80211_hdr_2addr {
        __le16 duration_id;
        u8 addr1[ETH_ALEN];
        u8 addr2[ETH_ALEN];
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtl_80211_hdr_3addr {
@@ -911,7 +911,7 @@ struct rtl_80211_hdr_3addr {
        u8 addr2[ETH_ALEN];
        u8 addr3[ETH_ALEN];
        __le16 seq_ctl;
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtl_80211_hdr_4addr {
@@ -922,7 +922,7 @@ struct rtl_80211_hdr_4addr {
        u8 addr3[ETH_ALEN];
        __le16 seq_ctl;
        u8 addr4[ETH_ALEN];
-       u8 payload[0];
+       u8 payload[];
 } __packed;
 
 struct rtl_80211_hdr_3addrqos {
@@ -951,7 +951,7 @@ struct rtl_80211_hdr_4addrqos {
 struct ieee80211_info_element {
        u8 id;
        u8 len;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 struct ieee80211_authentication {
@@ -960,7 +960,7 @@ struct ieee80211_authentication {
        __le16 transaction;
        __le16 status;
        /*challenge*/
-       struct ieee80211_info_element info_element[0];
+       struct ieee80211_info_element info_element[];
 } __packed;
 
 struct ieee80211_disassoc {
@@ -971,7 +971,7 @@ struct ieee80211_disassoc {
 struct ieee80211_probe_request {
        struct rtl_80211_hdr_3addr header;
        /* SSID, supported rates */
-       struct ieee80211_info_element info_element[0];
+       struct ieee80211_info_element info_element[];
 } __packed;
 
 struct ieee80211_probe_response {
@@ -982,7 +982,7 @@ struct ieee80211_probe_response {
        /* SSID, supported rates, FH params, DS params,
         * CF params, IBSS params, TIM (if beacon), RSN
         */
-       struct ieee80211_info_element info_element[0];
+       struct ieee80211_info_element info_element[];
 } __packed;
 
 /* Alias beacon for probe_response */
@@ -993,7 +993,7 @@ struct ieee80211_assoc_request_frame {
        __le16 capability;
        __le16 listen_interval;
        /* SSID, supported rates, RSN */
-       struct ieee80211_info_element info_element[0];
+       struct ieee80211_info_element info_element[];
 } __packed;
 
 struct ieee80211_reassoc_request_frame {
@@ -1002,7 +1002,7 @@ struct ieee80211_reassoc_request_frame {
        __le16 listen_interval;
        u8 current_ap[ETH_ALEN];
        /* SSID, supported rates, RSN */
-       struct ieee80211_info_element info_element[0];
+       struct ieee80211_info_element info_element[];
 } __packed;
 
 struct ieee80211_assoc_response_frame {
@@ -1010,7 +1010,7 @@ struct ieee80211_assoc_response_frame {
        __le16 capability;
        __le16 status;
        __le16 aid;
-       struct ieee80211_info_element info_element[0]; /* supported rates */
+       struct ieee80211_info_element info_element[]; /* supported rates */
 } __packed;
 
 struct ieee80211_txb {
@@ -1021,7 +1021,7 @@ struct ieee80211_txb {
        u16 reserved;
        __le16 frag_size;
        __le16 payload_size;
-       struct sk_buff *fragments[0];
+       struct sk_buff *fragments[];
 };
 
 #define MAX_TX_AGG_COUNT                 16
@@ -2007,7 +2007,7 @@ struct ieee80211_device {
        /* This must be the last item so that it points to the data
         * allocated beyond this structure by alloc_ieee80211
         */
-       u8 priv[0];
+       u8 priv[];
 };
 
 #define IEEE_A            (1<<0)
index 6f47101..ffe624e 100644 (file)
@@ -388,20 +388,20 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        keyidx = pos[3];
        if (!(keyidx & BIT(5))) {
                if (net_ratelimit()) {
-                       printk(KERN_DEBUG "TKIP: received packet without ExtIV"
+                       netdev_dbg(skb->dev, "TKIP: received packet without ExtIV"
                               " flag from %pM\n", hdr->addr2);
                }
                return -2;
        }
        keyidx >>= 6;
        if (tkey->key_idx != keyidx) {
-               printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
+               netdev_dbg(skb->dev, "TKIP: RX tkey->key_idx=%d frame "
                       "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
                return -6;
        }
        if (!tkey->key_set) {
                if (net_ratelimit()) {
-                       printk(KERN_DEBUG "TKIP: received packet from %pM"
+                       netdev_dbg(skb->dev, "TKIP: received packet from %pM"
                               " with keyid=%d that does not have a configured"
                               " key\n", hdr->addr2, keyidx);
                }
@@ -417,7 +417,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
                if (iv32 < tkey->rx_iv32 ||
                (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
                        if (net_ratelimit()) {
-                               printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
+                               netdev_dbg(skb->dev, "TKIP: replay detected: STA=%pM"
                                " previous TSC %08x%04x received TSC "
                                "%08x%04x\n", hdr->addr2,
                                tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
@@ -445,7 +445,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
                skcipher_request_zero(req);
                if (err) {
                        if (net_ratelimit()) {
-                               printk(KERN_DEBUG ": TKIP: failed to decrypt "
+                               netdev_dbg(skb->dev, "TKIP: failed to decrypt "
                                                "received packet from %pM\n",
                                                hdr->addr2);
                        }
@@ -468,7 +468,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
                                tkey->rx_phase1_done = 0;
                        }
                        if (net_ratelimit()) {
-                               printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+                               netdev_dbg(skb->dev, "TKIP: ICV error detected: STA="
                                "%pM\n", hdr->addr2);
                        }
                        tkey->dot11RSNAStatsTKIPICVErrors++;
@@ -559,7 +559,7 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *pri
        hdr = (struct rtl_80211_hdr_4addr *)skb->data;
 
        if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
-               printk(KERN_DEBUG "Invalid packet for Michael MIC add "
+               netdev_dbg(skb->dev, "Invalid packet for Michael MIC add "
                       "(tailroom=%d hdr_len=%d skb->len=%d)\n",
                       skb_tailroom(skb), hdr_len, skb->len);
                return -1;
@@ -628,10 +628,9 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
                struct rtl_80211_hdr_4addr *hdr;
                hdr = (struct rtl_80211_hdr_4addr *)skb->data;
 
-               printk(KERN_DEBUG "%s: Michael MIC verification failed for "
+               netdev_dbg(skb->dev, "Michael MIC verification failed for "
                       "MSDU from %pM keyidx=%d\n",
-                      skb->dev ? skb->dev->name : "N/A", hdr->addr2,
-                      keyidx);
+                      hdr->addr2, keyidx);
                if (skb->dev)
                        ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
                tkey->dot11RSNAStatsTKIPLocalMICFailures++;
index aa9dab8..a5a1b14 100644 (file)
@@ -68,8 +68,7 @@ static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee)
                                 sizeof(struct ieee80211_network),
                                 GFP_KERNEL);
        if (!ieee->networks) {
-               printk(KERN_WARNING "%s: Out of memory allocating beacons\n",
-                      ieee->dev->name);
+               netdev_warn(ieee->dev, "Out of memory allocating beacons\n");
                return -ENOMEM;
        }
 
index 90692db..d8eb907 100644 (file)
@@ -131,7 +131,7 @@ static void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p)
        *tag++ = 0x00;
 
        *tag_p = tag;
-       printk(KERN_ALERT "This is enable turbo mode IE process\n");
+       netdev_alert(ieee->dev, "This is enable turbo mode IE process\n");
 }
 #endif
 
@@ -1270,14 +1270,15 @@ static void ieee80211_associate_step2(struct ieee80211_device *ieee)
 static void ieee80211_associate_complete_wq(struct work_struct *work)
 {
        struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq);
-       printk(KERN_INFO "Associated successfully\n");
+
+       netdev_info(ieee->dev, "Associated successfully\n");
        if (ieee80211_is_54g(&ieee->current_network) &&
            (ieee->modulation & IEEE80211_OFDM_MODULATION)) {
                ieee->rate = 108;
-               printk(KERN_INFO"Using G rates:%d\n", ieee->rate);
+               netdev_info(ieee->dev, "Using G rates:%d\n", ieee->rate);
        } else {
                ieee->rate = 22;
-               printk(KERN_INFO"Using B rates:%d\n", ieee->rate);
+               netdev_info(ieee->dev, "Using B rates:%d\n", ieee->rate);
        }
        if (ieee->pHTInfo->bCurrentHTSupport && ieee->pHTInfo->bEnableHT) {
                printk("Successfully associated, ht enabled\n");
@@ -1391,12 +1392,13 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
 
                        strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE);
                        ieee->current_network.ssid_len = tmp_ssid_len;
-                       printk(KERN_INFO"Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d\n",
-                              ieee->current_network.ssid,
-                              ieee->current_network.channel,
-                              ieee->current_network.qos_data.supported,
-                              ieee->pHTInfo->bEnableHT,
-                              ieee->current_network.bssht.bdSupportHT);
+                       netdev_info(ieee->dev,
+                                   "Linking with %s,channel:%d, qos:%d, myHT:%d, networkHT:%d\n",
+                                   ieee->current_network.ssid,
+                                   ieee->current_network.channel,
+                                   ieee->current_network.qos_data.supported,
+                                   ieee->pHTInfo->bEnableHT,
+                                   ieee->current_network.bssht.bdSupportHT);
 
                        //ieee->pHTInfo->IOTAction = 0;
                        HTResetIOTSetting(ieee->pHTInfo);
@@ -1421,11 +1423,13 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
                                    (ieee->modulation & IEEE80211_OFDM_MODULATION)) {
                                        ieee->rate = 108;
                                        ieee->SetWirelessMode(ieee->dev, IEEE_G);
-                                       printk(KERN_INFO"Using G rates\n");
+                                       netdev_info(ieee->dev,
+                                                   "Using G rates\n");
                                } else {
                                        ieee->rate = 22;
                                        ieee->SetWirelessMode(ieee->dev, IEEE_B);
-                                       printk(KERN_INFO"Using B rates\n");
+                                       netdev_info(ieee->dev,
+                                                   "Using B rates\n");
                                }
                                memset(ieee->dot11HTOperationalRateSet, 0, 16);
                                //HTSetConnectBwMode(ieee, HT_CHANNEL_WIDTH_20, HT_EXTCHNL_OFFSET_NO_EXT);
@@ -1622,7 +1626,7 @@ ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb)
        if (assoc_rq_parse(skb, dest) != -1)
                ieee80211_resp_to_assoc_rq(ieee, dest);
 
-       printk(KERN_INFO"New client associated: %pM\n", dest);
+       netdev_info(ieee->dev, "New client associated: %pM\n", dest);
        //FIXME
 }
 
index b1baaa1..f434a26 100644 (file)
@@ -459,8 +459,8 @@ int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee,
        else
                ieee->raw_tx = 0;
 
-       printk(KERN_INFO"raw TX is %s\n",
-             ieee->raw_tx ? "enabled" : "disabled");
+       netdev_info(ieee->dev, "raw TX is %s\n",
+                   ieee->raw_tx ? "enabled" : "disabled");
 
        if (ieee->iw_mode == IW_MODE_MONITOR) {
                if (prev == 0 && ieee->raw_tx) {
index f0b6b83..0ee054d 100644 (file)
@@ -180,9 +180,8 @@ int ieee80211_encrypt_fragment(
                        struct rtl_80211_hdr_3addrqos *header;
 
                        header = (struct rtl_80211_hdr_3addrqos *)frag->data;
-                       printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-                              "TX packet to %pM\n",
-                              ieee->dev->name, header->addr1);
+                       netdev_dbg(ieee->dev, "TKIP countermeasures: dropped "
+                              "TX packet to %pM\n", header->addr1);
                }
                return -1;
        }
@@ -204,8 +203,8 @@ int ieee80211_encrypt_fragment(
 
        atomic_dec(&crypt->refcnt);
        if (res < 0) {
-               printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
-                      ieee->dev->name, frag->len);
+               netdev_info(ieee->dev, "Encryption failed: len=%d.\n",
+                           frag->len);
                ieee->ieee_stats.tx_discards++;
                return -1;
        }
@@ -557,16 +556,15 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
         */
        if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)) ||
           ((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) {
-               printk(KERN_WARNING "%s: No xmit handler.\n",
-                      ieee->dev->name);
+               netdev_warn(ieee->dev, "No xmit handler.\n");
                goto success;
        }
 
 
        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);
+                       netdev_warn(ieee->dev, "skb too small (%d).\n",
+                                   skb->len);
                        goto success;
                }
 
@@ -685,8 +683,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                 */
                txb = ieee80211_alloc_txb(nr_frags, frag_size + ieee->tx_headroom, GFP_ATOMIC);
                if (unlikely(!txb)) {
-                       printk(KERN_WARNING "%s: Could not allocate TXB\n",
-                       ieee->dev->name);
+                       netdev_warn(ieee->dev, "Could not allocate TXB\n");
                        goto failed;
                }
                txb->encrypted = encrypt;
@@ -779,15 +776,14 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        } else {
                if (unlikely(skb->len < sizeof(struct rtl_80211_hdr_3addr))) {
-                       printk(KERN_WARNING "%s: skb too small (%d).\n",
-                       ieee->dev->name, skb->len);
+                       netdev_warn(ieee->dev, "skb too small (%d).\n",
+                                   skb->len);
                        goto success;
                }
 
                txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC);
                if (!txb) {
-                       printk(KERN_WARNING "%s: Could not allocate TXB\n",
-                       ieee->dev->name);
+                       netdev_warn(ieee->dev, "Could not allocate TXB\n");
                        goto failed;
                }
 
index 33c596f..22373c0 100644 (file)
@@ -356,9 +356,8 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
                        kfree(new_crypt);
                        new_crypt = NULL;
 
-                       printk(KERN_WARNING "%s: could not initialize WEP: "
-                              "load module ieee80211_crypt_wep\n",
-                              dev->name);
+                       netdev_warn(dev, "could not initialize WEP: "
+                                   "load module ieee80211_crypt_wep\n");
                        return -EOPNOTSUPP;
                }
                *crypt = new_crypt;
@@ -436,7 +435,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
        if (ieee->reset_on_keychange &&
            ieee->iw_mode != IW_MODE_INFRA &&
            ieee->reset_port && ieee->reset_port(dev)) {
-               printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
+               netdev_dbg(ieee->dev, "reset_port failed\n");
                return -EINVAL;
        }
        return 0;
index 5cee103..3aabb40 100644 (file)
@@ -380,7 +380,7 @@ bool GetTs(
                                }
 
                                IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr);
-                               // Prepare TS Info releated field
+                               // Prepare TS Info related field
                                pTSInfo->uc_traffic_type = 0;           // Traffic type: WMM is reserved in this field
                                pTSInfo->uc_tsid = UP;                  // TSID
                                pTSInfo->uc_direction = Dir;            // Direction: if there is DirectLink, this need additional consideration.
index 89dd1fb..fcfb902 100644 (file)
@@ -613,13 +613,13 @@ static void rtl8192_proc_init_one(struct net_device *dev)
        if (!dir)
                return;
 
-       proc_create_single("stats-rx", S_IFREG | S_IRUGO, dir,
+       proc_create_single("stats-rx", S_IFREG | 0444, dir,
                           proc_get_stats_rx);
-       proc_create_single("stats-tx", S_IFREG | S_IRUGO, dir,
+       proc_create_single("stats-tx", S_IFREG | 0444, dir,
                           proc_get_stats_tx);
-       proc_create_single("stats-ap", S_IFREG | S_IRUGO, dir,
+       proc_create_single("stats-ap", S_IFREG | 0444, dir,
                           proc_get_stats_ap);
-       proc_create_single("registers", S_IFREG | S_IRUGO, dir,
+       proc_create_single("registers", S_IFREG | 0444, dir,
                           proc_get_registers);
 }
 
@@ -4877,50 +4877,50 @@ void EnableHWSecurityConfig8192(struct net_device *dev)
        write_nic_byte(dev, SECR,  SECR_value);
 }
 
-void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType,
-           u8 *MacAddr, u8 DefaultKey, u32 *KeyContent)
+void setKey(struct net_device *dev, u8 entryno, u8 keyindex, u16 keytype,
+           u8 *macaddr, u8 defaultkey, u32 *keycontent)
 {
-       u32 TargetCommand = 0;
-       u32 TargetContent = 0;
-       u16 usConfig = 0;
+       u32 target_command = 0;
+       u32 target_content = 0;
+       u16 us_config = 0;
        u8 i;
 
-       if (EntryNo >= TOTAL_CAM_ENTRY)
-               RT_TRACE(COMP_ERR, "cam entry exceeds in setKey()\n");
+       if (entryno >= TOTAL_CAM_ENTRY)
+               RT_TRACE(COMP_ERR, "cam entry exceeds in %s\n", __func__);
 
        RT_TRACE(COMP_SEC,
-                "====>to setKey(), dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr%pM\n",
-                dev, EntryNo, KeyIndex, KeyType, MacAddr);
+                "====>to %s, dev:%p, EntryNo:%d, KeyIndex:%d, KeyType:%d, MacAddr%pM\n",
+                __func__, dev, entryno, keyindex, keytype, macaddr);
 
-       if (DefaultKey)
-               usConfig |= BIT(15) | (KeyType << 2);
+       if (defaultkey)
+               us_config |= BIT(15) | (keytype << 2);
        else
-               usConfig |= BIT(15) | (KeyType << 2) | KeyIndex;
+               us_config |= BIT(15) | (keytype << 2) | keyindex;
 
        for (i = 0; i < CAM_CONTENT_COUNT; i++) {
-               TargetCommand  = i + CAM_CONTENT_COUNT * EntryNo;
-               TargetCommand |= BIT(31) | BIT(16);
+               target_command  = i + CAM_CONTENT_COUNT * entryno;
+               target_command |= BIT(31) | BIT(16);
 
                if (i == 0) { /* MAC|Config */
-                       TargetContent = (u32)(*(MacAddr + 0)) << 16 |
-                                       (u32)(*(MacAddr + 1)) << 24 |
-                                       (u32)usConfig;
+                       target_content = (u32)(*(macaddr + 0)) << 16 |
+                                       (u32)(*(macaddr + 1)) << 24 |
+                                       (u32)us_config;
 
-                       write_nic_dword(dev, WCAMI, TargetContent);
-                       write_nic_dword(dev, RWCAM, TargetCommand);
+                       write_nic_dword(dev, WCAMI, target_content);
+                       write_nic_dword(dev, RWCAM, target_command);
                } else if (i == 1) { /* MAC */
-                       TargetContent = (u32)(*(MacAddr + 2))    |
-                                       (u32)(*(MacAddr + 3)) <<  8 |
-                                       (u32)(*(MacAddr + 4)) << 16 |
-                                       (u32)(*(MacAddr + 5)) << 24;
-                       write_nic_dword(dev, WCAMI, TargetContent);
-                       write_nic_dword(dev, RWCAM, TargetCommand);
+                       target_content = (u32)(*(macaddr + 2))   |
+                                       (u32)(*(macaddr + 3)) <<  8 |
+                                       (u32)(*(macaddr + 4)) << 16 |
+                                       (u32)(*(macaddr + 5)) << 24;
+                       write_nic_dword(dev, WCAMI, target_content);
+                       write_nic_dword(dev, RWCAM, target_command);
                } else {
                        /* Key Material */
-                       if (KeyContent) {
+                       if (keycontent) {
                                write_nic_dword(dev, WCAMI,
-                                               *(KeyContent + i - 2));
-                               write_nic_dword(dev, RWCAM, TargetCommand);
+                                               *(keycontent + i - 2));
+                               write_nic_dword(dev, RWCAM, target_command);
                        }
                }
        }
index 0118edb..1005325 100644 (file)
@@ -588,7 +588,7 @@ static int r8192_wx_set_enc(struct net_device *dev,
                                hwkey);                 /* KeyContent */
 
                } else {
-                       printk("wrong type in WEP, not WEP40 and WEP104\n");
+                       netdev_warn(dev, "wrong type in WEP, not WEP40 and WEP104\n");
                }
 
        }
index 555e525..37b99cf 100644 (file)
@@ -1531,7 +1531,7 @@ void rtl8192_SetBWModeWorkItem(struct net_device *dev)
                rtl8192_setBBreg(dev, rFPGA0_RFMOD, bRFMOD, 0x1);
                rtl8192_setBBreg(dev, rFPGA1_RFMOD, bRFMOD, 0x1);
                rtl8192_setBBreg(dev, rCCK0_System, bCCKSideBand,
-                                priv->nCur40MhzPrimeSC>>1);
+                                priv->nCur40MhzPrimeSC >> 1);
                rtl8192_setBBreg(dev, rFPGA0_AnalogParameter1, 0x00100000, 0);
                rtl8192_setBBreg(dev, rOFDM1_LSTF, 0xC00,
                                 priv->nCur40MhzPrimeSC);
index b6dcda7..c62747c 100644 (file)
@@ -6,13 +6,16 @@ config R8712U
        select WEXT_PRIV
        select FW_LOADER
        help
-           This option adds the Realtek RTL8712 USB device such as the D-Link DWA-130.
+           This option adds the Realtek RTL8712 USB device such as the
+           D-Link DWA-130.
+
            If built as a module, it will be called r8712u.
 
 config R8712_TX_AGGR
        bool "Realtek RTL8712U Transmit Aggregation code"
        depends on R8712U && BROKEN
        help
-           This option provides transmit aggregation for the Realtek RTL8712 USB device.
+           This option provides transmit aggregation for the Realtek
+           RTL8712 USB device.
 
 
index 8098f69..dabaa8f 100644 (file)
@@ -535,7 +535,7 @@ struct ieee80211_info_element_hdr {
 struct ieee80211_info_element {
        u8 id;
        u8 len;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 /*
@@ -597,7 +597,7 @@ struct ieee80211_txb {
        u16 reserved;
        u16 frag_size;
        u16 payload_size;
-       struct sk_buff *fragments[0];
+       struct sk_buff *fragments[];
 };
 
 /* SWEEP TABLE ENTRIES NUMBER*/
index 98d7fbf..254182a 100644 (file)
@@ -478,7 +478,7 @@ struct drvint_cmd_parm {
        unsigned char *pbuf;
 };
 
-/*------------------- Below are used for RF/BB tunning ---------------------*/
+/*------------------- Below are used for RF/BB tuning ---------------------*/
 
 struct setantenna_parm {
        u8      tx_antset;
index 1a39a96..2402025 100644 (file)
@@ -44,9 +44,9 @@ static int init_mp_priv(struct mp_priv *pmp_priv)
        pmp_priv->pallocated_mp_xmitframe_buf = kmalloc(NR_MP_XMITFRAME *
                                sizeof(struct mp_xmit_frame) + 4,
                                GFP_ATOMIC);
-       if (!pmp_priv->pallocated_mp_xmitframe_buf) {
+       if (!pmp_priv->pallocated_mp_xmitframe_buf)
                return -ENOMEM;
-       }
+
        pmp_priv->pmp_xmtframe_buf = pmp_priv->pallocated_mp_xmitframe_buf +
                         4 -
                         ((addr_t)(pmp_priv->pallocated_mp_xmitframe_buf) & 3);
index 64e2ae4..59fa666 100644 (file)
@@ -48,7 +48,7 @@ struct eeprom_rw_param {
 struct EFUSE_ACCESS_STRUCT {
        u16     start_addr;
        u16     cnts;
-       u8      data[0];
+       u8      data[];
 };
 
 struct burst_rw_reg {
@@ -324,7 +324,7 @@ struct mp_ioctl_handler {
 struct mp_ioctl_param {
        unsigned int subcode;
        unsigned int len;
-       unsigned char data[0];
+       unsigned char data[];
 };
 
 #define GEN_MP_IOCTL_SUBCODE(code) _MP_IOCTL_ ## code ## _CMD_
index d479f73..ca5072e 100644 (file)
@@ -30,7 +30,7 @@
 /*--------------------------Define Parameters-------------------------------*/
 
 /*============================================================
- *       8192S Regsiter offset definition
+ *       8192S Register offset definition
  *============================================================
  *
  *
index 0146a77..e93f356 100644 (file)
@@ -53,7 +53,7 @@ struct rx_pkt_attrib {
        u8      privacy; /* in frame_ctrl field */
        u8      bdecrypted;
        int     hdrlen;  /* the WLAN Header Len */
-       int     encrypt; /* 0 no encrypt. != 0 encrypt algorith */
+       int     encrypt; /* 0 no encrypt. != 0 encrypt algorithm */
        int     iv_len;
        int     icv_len;
        int     priority;
@@ -105,7 +105,7 @@ struct recv_priv {
        u8 *precv_buf;    /* 4 alignment */
        struct  __queue free_recv_buf_queue;
        u32     free_recv_buf_queue_cnt;
-       /* For the phy informatiom */
+       /* For the phy information */
        s8 rssi;
        u8 signal;
        u8 noise;
index 7117d16..a76e813 100644 (file)
@@ -2417,7 +2417,7 @@ void stop_ap_mode(struct adapter *padapter)
                paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list);
                plist = get_next(plist);
 
-               if (paclnode->valid == true) {
+               if (paclnode->valid) {
                        paclnode->valid = false;
 
                        list_del_init(&paclnode->list);
index 13a9b54..efb5135 100644 (file)
@@ -194,14 +194,16 @@ int rtw_init_cmd_priv(struct      cmd_priv *pcmdpriv)
 
        pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf  +  4 - ((SIZE_PTR)(pcmdpriv->rsp_allocated_buf) & 3);
 
-       pcmdpriv->cmd_issued_cnt = pcmdpriv->cmd_done_cnt = pcmdpriv->rsp_cnt = 0;
+       pcmdpriv->cmd_issued_cnt = 0;
+       pcmdpriv->cmd_done_cnt = 0;
+       pcmdpriv->rsp_cnt = 0;
 
        mutex_init(&pcmdpriv->sctx_mutex);
 exit:
        return res;
 }
 
-static void c2h_wk_callback(_workitem *work);
+static void c2h_wk_callback(_workitem * work);
 int rtw_init_evt_priv(struct evt_priv *pevtpriv)
 {
        /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
@@ -360,11 +362,7 @@ exit:
 
 struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
 {
-       struct cmd_obj *cmd_obj;
-
-       cmd_obj = _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
-
-       return cmd_obj;
+       return _rtw_dequeue_cmd(&pcmdpriv->cmd_queue);
 }
 
 void rtw_free_cmd_obj(struct cmd_obj *pcmd)
@@ -520,7 +518,7 @@ post_process:
                                rtw_free_cmd_obj(pcmd);
                        } else {
                                /* todo: !!! fill rsp_buf to pcmd->rsp if (pcmd->rsp!= NULL) */
-                               pcmd_callback(pcmd->padapter, pcmd);/* need conider that free cmd_obj in rtw_cmd_callback */
+                               pcmd_callback(pcmd->padapter, pcmd);/* need consider that free cmd_obj in rtw_cmd_callback */
                        }
                } else {
                        RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("%s: cmdcode = 0x%x callback not defined!\n", __func__, pcmd->cmdcode));
@@ -989,7 +987,7 @@ u8 rtw_setstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 unicast_
                memcpy(&psetstakey_para->key, &psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey, 16);
        }
 
-       /* jeff: set this becasue at least sw key is ready */
+       /* jeff: set this because at least sw key is ready */
        padapter->securitypriv.busetkipkey = true;
 
        if (enqueue) {
@@ -2138,7 +2136,8 @@ void rtw_setassocsta_cmdrsp_callback(struct adapter *padapter,  struct cmd_obj *
                goto exit;
        }
 
-       psta->aid = psta->mac_id = passocsta_rsp->cam_id;
+       psta->aid = passocsta_rsp->cam_id;
+       psta->mac_id = passocsta_rsp->cam_id;
 
        spin_lock_bh(&pmlmepriv->lock);
 
index 3b88481..8794638 100644 (file)
@@ -43,9 +43,8 @@ Efuse_Read1ByteFromFakeContent(
        u16     Offset,
        u8 *Value)
 {
-       if (Offset >= EFUSE_MAX_HW_SIZE) {
+       if (Offset >= EFUSE_MAX_HW_SIZE)
                return false;
-       }
        /* DbgPrint("Read fake content, offset = %d\n", Offset); */
        if (fakeEfuseBank == 0)
                *Value = fakeEfuseContent[Offset];
@@ -65,14 +64,12 @@ Efuse_Write1ByteToFakeContent(
        u16     Offset,
        u8 Value)
 {
-       if (Offset >= EFUSE_MAX_HW_SIZE) {
+       if (Offset >= EFUSE_MAX_HW_SIZE)
                return false;
-       }
        if (fakeEfuseBank == 0)
                fakeEfuseContent[Offset] = Value;
-       else {
+       else
                fakeBTEfuseContent[fakeEfuseBank-1][Offset] = Value;
-       }
        return true;
 }
 
@@ -244,10 +241,8 @@ u16        Address)
                while (!(Bytetemp & 0x80)) {
                        Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
                        k++;
-                       if (k == 1000) {
-                               k = 0;
+                       if (k == 1000)
                                break;
-                       }
                }
                return rtw_read8(Adapter, EFUSE_CTRL);
        } else
@@ -271,8 +266,7 @@ bool                bPseudoTest)
        /* DBG_871X("===> EFUSE_OneByteRead() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */
 
        if (bPseudoTest) {
-               bResult = Efuse_Read1ByteFromFakeContent(padapter, addr, data);
-               return bResult;
+               return Efuse_Read1ByteFromFakeContent(padapter, addr, data);
        }
 
        /*  <20130121, Kordan> For SMIC EFUSE specificatoin. */
@@ -324,8 +318,7 @@ bool                bPseudoTest)
        /* DBG_871X("===> EFUSE_OneByteWrite() start, 0x34 = 0x%X\n", rtw_read32(padapter, EFUSE_TEST)); */
 
        if (bPseudoTest) {
-               bResult = Efuse_Write1ByteToFakeContent(padapter, addr, data);
-               return bResult;
+               return Efuse_Write1ByteToFakeContent(padapter, addr, data);
        }
 
 
index 6018d87..ca98274 100644 (file)
@@ -217,7 +217,7 @@ u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, u
  * rtw_ies_remove_ie - Find matching IEs and remove
  * @ies: Address of IEs to search
  * @ies_len: Pointer of length of ies, will update to new length
- * @offset: The offset to start scarch
+ * @offset: The offset to start search
  * @eid: Element ID to match
  * @oui: OUI to match
  * @oui_len: OUI length
index 5716857..c3f63f9 100644 (file)
@@ -37,7 +37,6 @@ jackson@realtek.com.tw
 
 u8 _rtw_read8(struct adapter *adapter, u32 addr)
 {
-       u8 r_val;
        /* struct       io_queue        *pio_queue = (struct io_queue *)adapter->pio_queue; */
        struct io_priv *pio_priv = &adapter->iopriv;
        struct  intf_hdl                *pintfhdl = &(pio_priv->intf);
@@ -45,8 +44,7 @@ u8 _rtw_read8(struct adapter *adapter, u32 addr)
 
        _read8 = pintfhdl->io_ops._read8;
 
-       r_val = _read8(pintfhdl, addr);
-       return r_val;
+       return _read8(pintfhdl, addr);
 }
 
 u16 _rtw_read16(struct adapter *adapter, u32 addr)
@@ -142,13 +140,10 @@ u32 _rtw_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
        u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
        struct io_priv *pio_priv = &adapter->iopriv;
        struct  intf_hdl                *pintfhdl = &(pio_priv->intf);
-       u32 ret;
 
        _write_port = pintfhdl->io_ops._write_port;
 
-       ret = _write_port(pintfhdl, addr, cnt, pmem);
-
-       return ret;
+       return _write_port(pintfhdl, addr, cnt, pmem);
 }
 
 int rtw_init_io_priv(struct adapter *padapter, void (*set_intf_ops)(struct adapter *padapter, struct _io_ops *pops))
index eb08569..8b5f6a6 100644 (file)
@@ -439,7 +439,7 @@ u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter,
 
                if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) {
                        if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
-                               rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether  issue dis-assoc_cmd or not */
+                               rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have checked whether issue dis-assoc_cmd or not */
                        }
               }
 
index 71fcb46..d7a58af 100644 (file)
@@ -2772,16 +2772,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe
 
        /* maybe needs check if ap supports rx ampdu. */
        if (!(phtpriv->ampdu_enable) && pregistrypriv->ampdu_enable == 1) {
-               if (pregistrypriv->wifi_spec == 1) {
-                       /* remove this part because testbed AP should disable RX AMPDU */
-                       /* phtpriv->ampdu_enable = false; */
-                       phtpriv->ampdu_enable = true;
-               } else {
-                       phtpriv->ampdu_enable = true;
-               }
-       } else if (pregistrypriv->ampdu_enable == 2) {
-               /* remove this part because testbed AP should disable RX AMPDU */
-               /* phtpriv->ampdu_enable = true; */
+               phtpriv->ampdu_enable = true;
        }
 
        /* check Max Rx A-MPDU Size */
index c642825..8f9da1d 100644 (file)
@@ -219,6 +219,7 @@ static RT_CHANNEL_PLAN_MAP RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03, 0x02};
 int rtw_ch_set_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch)
 {
        int i;
+
        for (i = 0; ch_set[i].ChannelNum != 0; i++) {
                if (ch == ch_set[i].ChannelNum)
                        break;
@@ -2184,6 +2185,7 @@ unsigned int OnAction_sa_query(struct adapter *padapter, union recv_frame *precv
        }
        if (0) {
                int pp;
+
                printk("pattrib->pktlen = %d =>", pattrib->pkt_len);
                for (pp = 0; pp < pattrib->pkt_len; pp++)
                        printk(" %02x ", pframe[pp]);
@@ -2486,6 +2488,7 @@ void issue_beacon(struct adapter *padapter, int timeout_ms)
                /* DBG_871X("ie len =%d\n", cur_network->IELength); */
                {
                        int len_diff;
+
                        memcpy(pframe, cur_network->IEs, cur_network->IELength);
                        len_diff = update_hidden_ssid(
                                pframe+_BEACON_IE_OFFSET_
@@ -2500,6 +2503,7 @@ void issue_beacon(struct adapter *padapter, int timeout_ms)
                        u8 *wps_ie;
                        uint wps_ielen;
                        u8 sr = 0;
+
                        wps_ie = rtw_get_wps_ie(pmgntframe->buf_addr+TXDESC_OFFSET+sizeof(struct ieee80211_hdr_3addr)+_BEACON_IE_OFFSET_,
                                pattrib->pktlen-sizeof(struct ieee80211_hdr_3addr)-_BEACON_IE_OFFSET_, NULL, &wps_ielen);
                        if (wps_ie && wps_ielen > 0) {
@@ -2700,6 +2704,7 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p
                        if (ssid_ie &&  cur_network->Ssid.SsidLength) {
                                uint remainder_ielen;
                                u8 *remainder_ie;
+
                                remainder_ie = ssid_ie+2;
                                remainder_ielen = (pframe-remainder_ie);
 
@@ -4280,6 +4285,7 @@ void site_survey(struct adapter *padapter)
 
        {
                struct rtw_ieee80211_channel *ch;
+
                if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) {
                        ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx];
                        survey_channel = ch->hw_value;
@@ -4323,6 +4329,7 @@ void site_survey(struct adapter *padapter)
                if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */
                        {
                                int i;
+
                                for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
                                        if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) {
                                                /* IOT issue, When wifi_spec is not set, send one probe req without WPS IE. */
@@ -4351,6 +4358,7 @@ void site_survey(struct adapter *padapter)
 #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR)
                {
                        struct noise_info info;
+
                        info.bPauseDIG = false;
                        info.IGIValue = 0;
                        info.max_time = channel_scan_time_ms/2;/* ms */
@@ -4518,6 +4526,7 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str
                p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset);
                if (p) {
                        struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2);
+
                        bssid->Configuration.DSConfig = HT_info->primary_channel;
                } else { /*  use current channel */
                        bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter);
@@ -4551,6 +4560,7 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str
                p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset);
                if (p && len > 0) {
                        struct HT_caps_element  *pHT_caps;
+
                        pHT_caps = (struct HT_caps_element      *)(p + 2);
 
                        if (le16_to_cpu(pHT_caps->u.HT_cap_element.HT_caps_info) & BIT(14))
@@ -4584,6 +4594,7 @@ void start_create_ibss(struct adapter *padapter)
        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));
+
        pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
        pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork);
 
@@ -5388,6 +5399,7 @@ static void rtw_mlmeext_disconnect(struct adapter *padapter)
        /* wakeup macid after disconnect. */
        {
                struct sta_info *psta;
+
                psta = rtw_get_stainfo(&padapter->stapriv, get_my_bssid(pnetwork));
                if (psta)
                        rtw_hal_macid_wakeup(padapter, psta->mac_id);
@@ -5425,6 +5437,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res)
        struct sta_priv         *pstapriv = &padapter->stapriv;
        u8 join_type;
        struct sta_info *psta;
+
        if (join_res < 0) {
                join_type = 1;
                rtw_hal_set_hwreg(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
@@ -6047,6 +6060,7 @@ u8 createbss_hdl(struct adapter *padapter, u8 *pbuf)
 
        if (pmlmeinfo->state == WIFI_FW_AP_STATE) {
                struct wlan_bssid_ex *network = &padapter->mlmepriv.cur_network.network;
+
                start_bss_network(padapter, (u8 *)network);
                return H2C_SUCCESS;
        }
@@ -6810,6 +6824,7 @@ u8 set_chplan_hdl(struct adapter *padapter, unsigned char *pbuf)
 
        if ((padapter->rtw_wdev != NULL) && (padapter->rtw_wdev->wiphy)) {
                struct regulatory_request request;
+
                request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
                rtw_reg_notifier(padapter->rtw_wdev->wiphy, &request);
        }
index 30137f0..6ac9184 100644 (file)
@@ -1193,7 +1193,7 @@ inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms)
 /*
 * rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
 * @adapter: pointer to struct adapter structure
-* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup
+* @ips_deffer_ms: the ms will prevent from falling into IPS after wakeup
 * Return _SUCCESS or _FAIL
 */
 
@@ -1390,10 +1390,5 @@ void rtw_ps_deny_cancel(struct adapter *padapter, enum PS_DENY_REASON reason)
  */
 u32 rtw_ps_deny_get(struct adapter *padapter)
 {
-       u32 deny;
-
-
-       deny = adapter_to_pwrctl(padapter)->ps_deny;
-
-       return deny;
+       return adapter_to_pwrctl(padapter)->ps_deny;
 }
index 7fa8c84..5245098 100644 (file)
@@ -1179,7 +1179,7 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_
 
                                        /* DBG_871X("after handling ps-poll, tim =%x\n", pstapriv->tim_bitmap); */
 
-                                       /* upate BCN for TIM IE */
+                                       /* update BCN for TIM IE */
                                        /* update_BCNTIM(padapter); */
                                        update_beacon(padapter, _TIM_IE_, NULL, true);
                                }
@@ -1205,7 +1205,7 @@ sint validate_recv_ctrl_frame(struct adapter *padapter, union recv_frame *precv_
 
                                        pstapriv->tim_bitmap &= ~BIT(psta->aid);
 
-                                       /* upate BCN for TIM IE */
+                                       /* update BCN for TIM IE */
                                        /* update_BCNTIM(padapter); */
                                        update_beacon(padapter, _TIM_IE_, NULL, true);
                                }
@@ -1953,7 +1953,7 @@ static int amsdu_to_msdu(struct adapter *padapter, union recv_frame *prframe)
        for (i = 0; i < nr_subframes; i++) {
                sub_pkt = subframes[i];
 
-               /* Indicat the packets to upper layer */
+               /* Indicate the packets to upper layer */
                if (sub_pkt) {
                        rtw_os_recv_indicate_pkt(padapter, sub_pkt, &prframe->u.hdr.attrib);
                }
@@ -2606,14 +2606,14 @@ static void rtw_signal_stat_timer_hdl(struct timer_list *t)
                if (recvpriv->signal_strength_data.update_req == 0) {/*  update_req is clear, means we got rx */
                        avg_signal_strength = recvpriv->signal_strength_data.avg_val;
                        num_signal_strength = recvpriv->signal_strength_data.total_num;
-                       /*  after avg_vals are accquired, we can re-stat the signal values */
+                       /*  after avg_vals are acquired, we can re-stat the signal values */
                        recvpriv->signal_strength_data.update_req = 1;
                }
 
                if (recvpriv->signal_qual_data.update_req == 0) {/*  update_req is clear, means we got rx */
                        avg_signal_qual = recvpriv->signal_qual_data.avg_val;
                        num_signal_qual = recvpriv->signal_qual_data.total_num;
-                       /*  after avg_vals are accquired, we can re-stat the signal values */
+                       /*  after avg_vals are acquired, we can re-stat the signal values */
                        recvpriv->signal_qual_data.update_req = 1;
                }
 
index 9c46071..5ebf691 100644 (file)
@@ -434,7 +434,6 @@ void rtw_seccalctkipmic(u8 *key, u8 *header, u8 *data, u32 data_len, u8 *mic_cod
                        rtw_secmicappend(&micdata, &header[16], 6);
                else
                        rtw_secmicappend(&micdata, &header[10], 6);
-
        }
        rtw_secmicappend(&micdata, &priority[0], 4);
 
@@ -723,7 +722,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe)
 
                        TKIP_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra);
                }
-
        }
        return res;
 }
@@ -829,11 +827,9 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe)
                        RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo == NULL!!!\n", __func__));
                        res = _FAIL;
                }
-
        }
 exit:
        return res;
-
 }
 
 
@@ -1219,7 +1215,6 @@ static void construct_mic_header2(
                if (!qc_exists && a4_exists) {
                        for (i = 0; i < 6; i++)
                                mic_header2[8+i] = mpdu[24+i];   /* A4 */
-
                }
 
                if (qc_exists && !a4_exists) {
@@ -1234,7 +1229,6 @@ static void construct_mic_header2(
                        mic_header2[14] = mpdu[30] & 0x0f;
                        mic_header2[15] = mpdu[31] & 0x00;
                }
-
 }
 
 /************************************************/
@@ -1413,7 +1407,6 @@ static sint aes_cipher(u8 *key, uint      hdrlen,
                }
                bitwise_xor(aes_out, padded_buffer, chain_buffer);
                aes128k128d(key, chain_buffer, aes_out);
-
        }
 
        for (j = 0 ; j < 8; j++)
@@ -1719,7 +1712,6 @@ static sint aes_decipher(u8 *key, uint    hdrlen,
                }
                bitwise_xor(aes_out, padded_buffer, chain_buffer);
                aes128k128d(key, chain_buffer, aes_out);
-
        }
 
        for (j = 0; j < 8; j++)
index 9590e6f..110338d 100644 (file)
@@ -326,20 +326,20 @@ inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch)
                dvobj->on_oper_ch_time = jiffies;
 
 #ifdef DBG_CH_SWITCH
-               cnt += snprintf(msg+cnt, len-cnt, "switch to ch %3u", ch);
+               cnt += scnprintf(msg+cnt, len-cnt, "switch to ch %3u", ch);
 
                for (i = 0; i < dvobj->iface_nums; i++) {
                        struct adapter *iface = dvobj->padapters[i];
-                       cnt += snprintf(msg+cnt, len-cnt, " ["ADPT_FMT":", ADPT_ARG(iface));
+                       cnt += scnprintf(msg+cnt, len-cnt, " ["ADPT_FMT":", ADPT_ARG(iface));
                        if (iface->mlmeextpriv.cur_channel == ch)
-                               cnt += snprintf(msg+cnt, len-cnt, "C");
+                               cnt += scnprintf(msg+cnt, len-cnt, "C");
                        else
-                               cnt += snprintf(msg+cnt, len-cnt, "_");
+                               cnt += scnprintf(msg+cnt, len-cnt, "_");
                        if (iface->wdinfo.listen_channel == ch && !rtw_p2p_chk_state(&iface->wdinfo, P2P_STATE_NONE))
-                               cnt += snprintf(msg+cnt, len-cnt, "L");
+                               cnt += scnprintf(msg+cnt, len-cnt, "L");
                        else
-                               cnt += snprintf(msg+cnt, len-cnt, "_");
-                       cnt += snprintf(msg+cnt, len-cnt, "]");
+                               cnt += scnprintf(msg+cnt, len-cnt, "_");
+                       cnt += scnprintf(msg+cnt, len-cnt, "]");
                }
 
                DBG_871X(FUNC_ADPT_FMT" %s\n", FUNC_ADPT_ARG(adapter), msg);
@@ -1503,7 +1503,7 @@ void update_beacon_info(struct adapter *padapter, u8 *pframe, uint pkt_len, stru
 
                switch (pIE->ElementID) {
                case _VENDOR_SPECIFIC_IE_:
-                       /* to update WMM paramter set while receiving beacon */
+                       /* to update WMM parameter set while receiving beacon */
                        if (!memcmp(pIE->data, WMM_PARA_OUI, 6) && pIE->Length == WLAN_WMM_LEN) /* WMM */
                                if (WMM_param_handler(padapter, pIE))
                                        report_wmm_edca_update(padapter);
index fdb585f..5713534 100644 (file)
@@ -1180,7 +1180,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram
                        mpdu_len -= pattrib->icv_len;
 
                if (bmcst) {
-                       /*  don't do fragment to broadcat/multicast packets */
+                       /*  don't do fragment to broadcast/multicast packets */
                        mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen);
                } else {
                        mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len);
@@ -2303,7 +2303,7 @@ sint xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fr
                                pstapriv->tim_bitmap |= BIT(psta->aid);
 
                                if (update_tim)
-                                       /* upate BCN for TIM IE */
+                                       /* update BCN for TIM IE */
                                        update_beacon(padapter, _TIM_IE_, NULL, true);
                        }
 
index ce02457..b9aca99 100644 (file)
 #define        IMR_BCNDMAINT3_8723B            BIT23   /*  Beacon DMA Interrupt 3 */
 #define        IMR_BCNDMAINT2_8723B            BIT22   /*  Beacon DMA Interrupt 2 */
 #define        IMR_BCNDMAINT1_8723B            BIT21   /*  Beacon DMA Interrupt 1 */
-#define        IMR_BCNDOK7_8723B               BIT20   /*  Beacon Queue DMA OK Interrup 7 */
-#define        IMR_BCNDOK6_8723B               BIT19   /*  Beacon Queue DMA OK Interrup 6 */
-#define        IMR_BCNDOK5_8723B               BIT18   /*  Beacon Queue DMA OK Interrup 5 */
-#define        IMR_BCNDOK4_8723B               BIT17   /*  Beacon Queue DMA OK Interrup 4 */
-#define        IMR_BCNDOK3_8723B               BIT16   /*  Beacon Queue DMA OK Interrup 3 */
-#define        IMR_BCNDOK2_8723B               BIT15   /*  Beacon Queue DMA OK Interrup 2 */
-#define        IMR_BCNDOK1_8723B               BIT14   /*  Beacon Queue DMA OK Interrup 1 */
+#define        IMR_BCNDOK7_8723B               BIT20   /*  Beacon Queue DMA OK Interrupt 7 */
+#define        IMR_BCNDOK6_8723B               BIT19   /*  Beacon Queue DMA OK Interrupt 6 */
+#define        IMR_BCNDOK5_8723B               BIT18   /*  Beacon Queue DMA OK Interrupt 5 */
+#define        IMR_BCNDOK4_8723B               BIT17   /*  Beacon Queue DMA OK Interrupt 4 */
+#define        IMR_BCNDOK3_8723B               BIT16   /*  Beacon Queue DMA OK Interrupt 3 */
+#define        IMR_BCNDOK2_8723B               BIT15   /*  Beacon Queue DMA OK Interrupt 2 */
+#define        IMR_BCNDOK1_8723B               BIT14   /*  Beacon Queue DMA OK Interrupt 1 */
 #define        IMR_ATIMEND_E_8723B             BIT13   /*  ATIM Window End Extension for Win7 */
 #define        IMR_TXERR_8723B                 BIT11   /*  Tx Error Flag Interrupt Status, write 1 clear. */
 #define        IMR_RXERR_8723B                 BIT10   /*  Rx Error Flag INT Status, Write 1 clear */
index dd349c5..c60e8c5 100644 (file)
@@ -1807,7 +1807,7 @@ static void halbtc8723b1ant_TdmaDurationAdjustForAcl(
                result = 0;
                WaitCount = 0;
        } else {
-               /* accquire the BT TRx retry count from BT_Info byte2 */
+               /* acquire the BT TRx retry count from BT_Info byte2 */
                retryCount = pCoexSta->btRetryCnt;
                btInfoExt = pCoexSta->btInfoExt;
                /* BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); */
index 02da0a8..2779dba 100644 (file)
@@ -1610,8 +1610,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
                                                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 {
@@ -1619,8 +1617,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
                                                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);
                                }
@@ -1630,8 +1626,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
                                                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 {
@@ -1639,8 +1633,6 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
                                                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);
                                }
@@ -1654,7 +1646,7 @@ static void halbtc8723b2ant_TdmaDurationAdjust(
                result = 0;
                WaitCount = 0;
        } else {
-               /* accquire the BT TRx retry count from BT_Info byte2 */
+               /* acquire the BT TRx retry count from BT_Info byte2 */
                retryCount = pCoexSta->btRetryCnt;
                BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount));
                BTC_PRINT(
index 7150d54..c758d14 100644 (file)
 #define BTC_ANT_WIFI_AT_CPL_MAIN       0
 #define BTC_ANT_WIFI_AT_CPL_AUX                1
 
-typedef enum _BTC_POWERSAVE_TYPE{
+typedef enum _BTC_POWERSAVE_TYPE {
        BTC_PS_WIFI_NATIVE      = 0,    /*  wifi original power save behavior */
        BTC_PS_LPS_ON           = 1,
        BTC_PS_LPS_OFF          = 2,
        BTC_PS_MAX
 } BTC_POWERSAVE_TYPE, *PBTC_POWERSAVE_TYPE;
 
-typedef enum _BTC_BT_REG_TYPE{
+typedef enum _BTC_BT_REG_TYPE {
        BTC_BT_REG_RF           = 0,
        BTC_BT_REG_MODEM        = 1,
        BTC_BT_REG_BLUEWIZE     = 2,
@@ -60,7 +60,7 @@ typedef enum _BTC_BT_REG_TYPE{
        BTC_BT_REG_MAX
 } BTC_BT_REG_TYPE, *PBTC_BT_REG_TYPE;
 
-typedef enum _BTC_CHIP_INTERFACE{
+typedef enum _BTC_CHIP_INTERFACE {
        BTC_INTF_UNKNOWN        = 0,
        BTC_INTF_PCI            = 1,
        BTC_INTF_USB            = 2,
index 357802d..7b43584 100644 (file)
@@ -92,7 +92,7 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
        u8 *deltaSwingTableIdx_TUP_B;
        u8 *deltaSwingTableIdx_TDOWN_B;
 
-       /* 4 2. Initilization (7 steps in total) */
+       /* 4 2. Initialization (7 steps in total) */
 
        ConfigureTxpowerTrack(pDM_Odm, &c);
 
@@ -213,7 +213,7 @@ void ODM_TXPowerTrackingCallback_ThermalMeter(struct adapter *Adapter)
 
        /* 3 7. If necessary, move the index of swing table to adjust Tx power. */
        if (delta > 0 && pDM_Odm->RFCalibrateInfo.TxPowerTrackControl) {
-               /* delta" here is used to record the absolute value of differrence. */
+               /* delta" here is used to record the absolute value of difference. */
                delta =
                        ThermalValue > pHalData->EEPROMThermalMeter ?
                        (ThermalValue - pHalData->EEPROMThermalMeter) :
index c241568..3b34a51 100644 (file)
@@ -118,7 +118,7 @@ u8 HalPwrSeqCmdParsing(
                                                &GET_PWR_CFG_MASK(PwrCfgCmd)
                                        );
 
-                                       /*  Write the value back to sytem register */
+                                       /*  Write the value back to system register */
                                        rtw_write8(padapter, offset, value);
                                }
                                break;
index 109bd85..02676da 100644 (file)
@@ -961,10 +961,7 @@ exit:
 
 u8 rtw_get_mgntframe_raid(struct adapter *adapter, unsigned char network_type)
 {
-
-       u8 raid;
-       raid = (network_type & WIRELESS_11B) ? RATEID_IDX_B : RATEID_IDX_G;
-       return raid;
+       return (network_type & WIRELESS_11B) ? RATEID_IDX_B : RATEID_IDX_G;
 }
 
 void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *psta)
index eb7de36..767e2a7 100644 (file)
@@ -1498,9 +1498,7 @@ s8 PHY_GetTxPowerByRate(
                return value;
        }
 
-       value = pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex];
-
-       return value;
+       return pHalData->TxPwrByRateOffset[Band][RFPath][TxNum][rateIndex];
 
 }
 
index 7d8f21f..23df729 100644 (file)
@@ -365,7 +365,7 @@ void rtw_hal_dm_watchdog_in_lps(struct adapter *padapter)
 {
        if (adapter_to_pwrctl(padapter)->bFwCurrentInPSMode == true) {
                if (padapter->HalFunc.hal_dm_watchdog_in_lps)
-                       padapter->HalFunc.hal_dm_watchdog_in_lps(padapter); /* this fuction caller is in interrupt context */
+                       padapter->HalFunc.hal_dm_watchdog_in_lps(padapter); /* this function caller is in interrupt context */
        }
 }
 
index fba3b9e..b77d1fe 100644 (file)
@@ -849,7 +849,7 @@ typedef struct _ODM_PATH_DIVERSITY_ {
        u32 PathB_Cnt[ODM_ASSOCIATE_ENTRY_NUM];
 } PATHDIV_T, *pPATHDIV_T;
 
-typedef enum _BASEBAND_CONFIG_PHY_REG_PG_VALUE_TYPE{
+typedef enum _BASEBAND_CONFIG_PHY_REG_PG_VALUE_TYPE {
        PHY_REG_PG_RELATIVE_VALUE = 0,
        PHY_REG_PG_EXACT_VALUE = 1
 } PHY_REG_PG_TYPE;
index 95edd14..3ea1972 100644 (file)
@@ -40,16 +40,11 @@ static void odm_SetCrystalCap(void *pDM_VOID, u8 CrystalCap)
 static u8 odm_GetDefaultCrytaltalCap(void *pDM_VOID)
 {
        PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
-       u8 CrystalCap = 0x20;
 
        struct adapter *Adapter = pDM_Odm->Adapter;
        struct hal_com_data *pHalData = GET_HAL_DATA(Adapter);
 
-       CrystalCap = pHalData->CrystalCap;
-
-       CrystalCap = CrystalCap & 0x3f;
-
-       return CrystalCap;
+       return pHalData->CrystalCap & 0x3f;
 }
 
 static void odm_SetATCStatus(void *pDM_VOID, bool ATCStatus)
@@ -303,7 +298,7 @@ void ODM_CfoTracking(void *pDM_VOID)
 void ODM_ParsingCFO(void *pDM_VOID, void *pPktinfo_VOID, s8 *pcfotail)
 {
        PDM_ODM_T pDM_Odm = (PDM_ODM_T)pDM_VOID;
-       struct odm_packet_info *pPktinfo = (struct odm_packet_info *)pPktinfo_VOID;
+       struct odm_packet_info *pPktinfo = pPktinfo_VOID;
        PCFO_TRACKING pCfoTrack = &pDM_Odm->DM_CfoTrack;
        u8 i;
 
index 71919a3..9c190b1 100644 (file)
@@ -103,10 +103,10 @@ static void odm_RxPhyStatus92CSeries_Parsing(
                pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK++;
                /*  */
                /*  (1)Hardware does not provide RSSI for CCK */
-               /*  (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
+               /*  (2)PWDB, Average PWDB calculated by hardware (for rate adaptive) */
                /*  */
 
-               cck_agc_rpt =  pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ;
+               cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a;
 
                /* 2011.11.28 LukeLee: 88E use different LNA & VGA gain table */
                /* The RSSI formula should be modified according to the gain table */
@@ -178,7 +178,7 @@ static void odm_RxPhyStatus92CSeries_Parsing(
 
 
                /*  */
-               /*  (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
+               /*  (2)PWDB, Average PWDB calculated by hardware (for rate adaptive) */
                /*  */
                rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1)&0x7f)-110;
 
index 3e58cb8..a738117 100644 (file)
@@ -13,7 +13,7 @@
 /* Define the debug levels */
 /*  */
 /* 1.  DBG_TRACE and DBG_LOUD are used for normal cases. */
-/* So that, they can help SW engineer to develope or trace states changed */
+/* So that, they can help SW engineer to developed or trace states changed */
 /* and also help HW enginner to trace every operation to and from HW, */
 /* e.g IO, Tx, Rx. */
 /*  */
@@ -34,7 +34,7 @@
 #define ODM_DBG_SERIOUS                                2
 
 /*  */
-/* Abnormal, rare, or unexpeted cases. */
+/* Abnormal, rare, or unexpected cases. */
 /* For example, */
 /* IRP/Packet/OID canceled, */
 /* device suprisely unremoved and so on. */
index 28f42c9..c79fc18 100644 (file)
@@ -28,7 +28,7 @@ typedef enum _HAL_STATUS {
 
 
 /*  */
-/*  Declare for ODM spin lock defintion temporarily fro compile pass. */
+/*  Declare for ODM spin lock definition temporarily from compile pass. */
 /*  */
 typedef enum _RT_SPINLOCK_TYPE {
        RT_TX_SPINLOCK = 1,
index 71b5a50..fd2b740 100644 (file)
@@ -146,7 +146,7 @@ static void ConstructBeacon(struct adapter *padapter, u8 *pframe, u32 *pLength)
        SetFrameSubType(pframe, WIFI_BEACON);
 
        pframe += sizeof(struct ieee80211_hdr_3addr);
-       pktlen = sizeof (struct ieee80211_hdr_3addr);
+       pktlen = sizeof(struct ieee80211_hdr_3addr);
 
        /* timestamp will be inserted by hardware */
        pframe += 8;
@@ -823,8 +823,11 @@ static void ConstructProbeRsp(struct adapter *padapter, u8 *pframe, u32 *pLength
 }
 #endif /*  CONFIG_AP_WOWLAN */
 
-/*  To check if reserved page content is destroyed by beacon beacuse beacon is too large. */
-/*  2010.06.23. Added by tynli. */
+/*
+ * To check if reserved page content is destroyed by beacon because beacon
+ * is too large.
+ */
+/* 2010.06.23. Added by tynli. */
 void CheckFwRsvdPageContent(struct adapter *Adapter)
 {
 }
@@ -1409,16 +1412,20 @@ void rtl8723b_set_ap_wowlan_cmd(struct adapter *padapter, u8 enable)
 }
 #endif /* CONFIG_AP_WOWLAN */
 
-/*  */
-/*  Description: Fill the reserved packets that FW will use to RSVD page. */
-/*                     Now we just send 4 types packet to rsvd page. */
-/*                     (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */
-/*     Input: */
-/*         bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */
-/*                                             so we need to set the packet length to total lengh. */
-/*                           true: At the second time, we should send the first packet (default:beacon) */
-/*                                             to Hw again and set the lengh in descriptor to the real beacon lengh. */
-/*  2009.10.15 by tynli. */
+/*
+ * Description: Fill the reserved packets that FW will use to RSVD page.
+ * Now we just send 4 types packet to rsvd page.
+ * (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp.
+ *
+ * Input:
+ *
+ * bDLFinished - false: At the first time we will send all the packets as
+ * a large packet to Hw, so we need to set the packet length to total length.
+ *
+ * true: At the second time, we should send the first packet (default:beacon)
+ * to Hw again and set the length in descriptor to the real beacon length.
+ */
+/* 2009.10.15 by tynli. */
 static void rtl8723b_set_FwRsvdPagePkt(
        struct adapter *padapter, bool bDLFinished
 )
@@ -1599,7 +1606,7 @@ static void rtl8723b_set_FwRsvdPagePkt(
 #ifdef CONFIG_GTK_OL
        BufIndex += (CurtPktPageNum*PageSize);
 
-       /* if the ap staion info. exists, get the kek, kck from staion info. */
+       /* if the ap station info. exists, get the kek, kck from station info. */
        psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
        if (!psta) {
                memset(kek, 0, RTW_KEK_LEN);
@@ -1652,7 +1659,7 @@ static void rtl8723b_set_FwRsvdPagePkt(
 
        TotalPacketLen = BufIndex-TxDescLen + 256; /* extension memory for FW */
 #else
-       TotalPacketLen = BufIndex-TxDescLen + sizeof (union pn48); /* IV len */
+       TotalPacketLen = BufIndex - TxDescLen + sizeof(union pn48); /* IV len */
 #endif /* CONFIG_GTK_OL */
        } else
 #endif /* CONFIG_WOWLAN */
@@ -1791,18 +1798,19 @@ error:
 }
 
 #ifdef CONFIG_AP_WOWLAN
-/*  */
-/* Description: Fill the reserved packets that FW will use to RSVD page. */
-/* Now we just send 2 types packet to rsvd page. (1)Beacon, (2)ProbeRsp. */
-/*  */
-/* Input: bDLFinished */
-/*  */
-/* false: At the first time we will send all the packets as a large packet to Hw, */
-/*      so we need to set the packet length to total lengh. */
-/*  */
-/* true: At the second time, we should send the first packet (default:beacon) */
-/*     to Hw again and set the lengh in descriptor to the real beacon lengh. */
-/*  2009.10.15 by tynli. */
+/*
+ * Description: Fill the reserved packets that FW will use to RSVD page.
+ * Now we just send 2 types packet to rsvd page. (1)Beacon, (2)ProbeRsp.
+ *
+ * Input: bDLFinished
+ *
+ * false: At the first time we will send all the packets as a large packet to
+ * Hw, so we need to set the packet length to total length.
+ *
+ * true: At the second time, we should send the first packet (default:beacon)
+ * to Hw again and set the length in descriptor to the real beacon length.
+ */
+/* 2009.10.15 by tynli. */
 static void rtl8723b_set_AP_FwRsvdPagePkt(
        struct adapter *padapter, bool bDLFinished
 )
index 1e8b614..c3051eb 100644 (file)
@@ -192,7 +192,7 @@ static inline union recv_frame *try_alloc_recvframe(struct recv_priv *precvpriv,
                rtw_enqueue_recvbuf_to_head(precvbuf,
                                            &precvpriv->recv_buf_pending_queue);
 
-               /*  The case of can't allocte recvframe should be temporary, */
+               /*  The case of can't allocate recvframe should be temporary, */
                /*  schedule again and hope recvframe is available next time. */
                tasklet_schedule(&precvpriv->recv_tasklet);
        }
@@ -480,10 +480,8 @@ initbuferror:
                precvpriv->precv_buf = NULL;
        }
 
-       if (precvpriv->pallocated_recv_buf) {
-               kfree(precvpriv->pallocated_recv_buf);
-               precvpriv->pallocated_recv_buf = NULL;
-       }
+       kfree(precvpriv->pallocated_recv_buf);
+       precvpriv->pallocated_recv_buf = NULL;
 
 exit:
        return res;
@@ -518,8 +516,6 @@ void rtl8723bs_free_recv_priv(struct adapter *padapter)
                precvpriv->precv_buf = NULL;
        }
 
-       if (precvpriv->pallocated_recv_buf) {
-               kfree(precvpriv->pallocated_recv_buf);
-               precvpriv->pallocated_recv_buf = NULL;
-       }
+       kfree(precvpriv->pallocated_recv_buf);
+       precvpriv->pallocated_recv_buf = NULL;
 }
index b6d56cf..44799c4 100644 (file)
@@ -282,7 +282,7 @@ static s32 xmit_xmitframes(struct adapter *padapter, struct xmit_priv *pxmitpriv
 
                                /*  check xmit_buf size enough or not */
                                txlen = txdesc_size + rtw_wlan_pkt_size(pxmitframe);
-                               if(     !pxmitbuf ||
+                               if (!pxmitbuf ||
                                        ((_RND(pxmitbuf->len, 8) + txlen) > max_xmit_len) ||
                                        (k >= (rtw_hal_sdio_max_txoqt_free_space(padapter) - 1))
                                ) {
index e813382..7853af5 100644 (file)
@@ -235,7 +235,7 @@ static void _InitQueueReservedPage(struct adapter *padapter)
        if (pHalData->OutEpQueueSel & TX_SELE_LQ)
                numLQ = bWiFiConfig ? WMM_NORMAL_PAGE_NUM_LPQ_8723B : NORMAL_PAGE_NUM_LPQ_8723B;
 
-       /*  NOTE: This step shall be proceed before writting REG_RQPN. */
+       /*  NOTE: This step shall be proceed before writing REG_RQPN. */
        if (pHalData->OutEpQueueSel & TX_SELE_NQ)
                numNQ = bWiFiConfig ? WMM_NORMAL_PAGE_NUM_NPQ_8723B : NORMAL_PAGE_NUM_NPQ_8723B;
 
@@ -551,18 +551,8 @@ static void HalRxAggr8723BSdio(struct adapter *padapter)
 
        pregistrypriv = &padapter->registrypriv;
 
-       if (pregistrypriv->wifi_spec) {
-               /*  2010.04.27 hpfan */
-               /*  Adjust RxAggrTimeout to close to zero disable RxAggr, suggested by designer */
-               /*  Timeout value is calculated by 34 / (2^n) */
-               valueDMATimeout = 0x06;
-               valueDMAPageCount = 0x06;
-       } else {
-               /*  20130530, Isaac@SD1 suggest 3 kinds of parameter */
-               /*  TX/RX Balance */
-               valueDMATimeout = 0x06;
-               valueDMAPageCount = 0x06;
-       }
+       valueDMATimeout = 0x06;
+       valueDMAPageCount = 0x06;
 
        rtw_write8(padapter, REG_RXDMA_AGG_PG_TH + 1, valueDMATimeout);
        rtw_write8(padapter, REG_RXDMA_AGG_PG_TH, valueDMAPageCount);
index 160f34e..c548fb1 100644 (file)
@@ -20,7 +20,7 @@ typedef enum tag_HAL_IC_Type_Definition
        CHIP_8821       =       7,
        CHIP_8723B      =       8,
        CHIP_8192E      =       9,
-}HAL_IC_TYPE_E;
+} HAL_IC_TYPE_E;
 
 /* HAL_CHIP_TYPE_E */
 typedef enum tag_HAL_CHIP_Type_Definition
@@ -28,7 +28,7 @@ typedef enum tag_HAL_CHIP_Type_Definition
        TEST_CHIP               =       0,
        NORMAL_CHIP     =       1,
        FPGA                    =       2,
-}HAL_CHIP_TYPE_E;
+} HAL_CHIP_TYPE_E;
 
 /* HAL_CUT_VERSION_E */
 typedef enum tag_HAL_Cut_Version_Definition
@@ -44,7 +44,7 @@ typedef enum tag_HAL_Cut_Version_Definition
        I_CUT_VERSION           =       8,
        J_CUT_VERSION           =       9,
        K_CUT_VERSION           =       10,
-}HAL_CUT_VERSION_E;
+} HAL_CUT_VERSION_E;
 
 /*  HAL_Manufacturer */
 typedef enum tag_HAL_Manufacturer_Version_Definition
@@ -52,7 +52,7 @@ typedef enum tag_HAL_Manufacturer_Version_Definition
        CHIP_VENDOR_TSMC        =       0,
        CHIP_VENDOR_UMC         =       1,
        CHIP_VENDOR_SMIC        =       2,
-}HAL_VENDOR_E;
+} HAL_VENDOR_E;
 
 typedef enum tag_HAL_RF_Type_Definition
 {
@@ -64,7 +64,7 @@ typedef enum tag_HAL_RF_Type_Definition
        RF_TYPE_3T3R    =       5,
        RF_TYPE_3T4R    =       6,
        RF_TYPE_4T4R    =       7,
-}HAL_RF_TYPE_E;
+} HAL_RF_TYPE_E;
 
 typedef        struct tag_HAL_VERSION
 {
@@ -74,14 +74,14 @@ typedef     struct tag_HAL_VERSION
        HAL_VENDOR_E            VendorType;
        HAL_RF_TYPE_E           RFType;
        u8                      ROMVer;
-}HAL_VERSION,*PHAL_VERSION;
+} HAL_VERSION, *PHAL_VERSION;
 
 /* VERSION_8192C                       VersionID; */
 /* HAL_VERSION                 VersionID; */
 
 /*  Get element */
-#define GET_CVID_IC_TYPE(version)                      ((HAL_IC_TYPE_E)((version).ICType)      )
-#define GET_CVID_CHIP_TYPE(version)                    ((HAL_CHIP_TYPE_E)((version).ChipType)  )
+#define GET_CVID_IC_TYPE(version)                      ((HAL_IC_TYPE_E)((version).ICType))
+#define GET_CVID_CHIP_TYPE(version)                    ((HAL_CHIP_TYPE_E)((version).ChipType))
 #define GET_CVID_RF_TYPE(version)                      ((HAL_RF_TYPE_E)((version).RFType))
 #define GET_CVID_MANUFACTUER(version)          ((HAL_VENDOR_E)((version).VendorType))
 #define GET_CVID_CUT_VERSION(version)          ((HAL_CUT_VERSION_E)((version).CUTVersion))
@@ -93,8 +93,8 @@ typedef       struct tag_HAL_VERSION
 /* HAL_VERSION VersionID */
 
 /* HAL_CHIP_TYPE_E */
-#define IS_TEST_CHIP(version)                  ((GET_CVID_CHIP_TYPE(version) ==TEST_CHIP)? true: false)
-#define IS_NORMAL_CHIP(version)                        ((GET_CVID_CHIP_TYPE(version) ==NORMAL_CHIP)? true: false)
+#define IS_TEST_CHIP(version)                  ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? true : false)
+#define IS_NORMAL_CHIP(version)                        ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false)
 
 /* HAL_CUT_VERSION_E */
 #define IS_A_CUT(version)                              ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? true : false)
@@ -107,13 +107,13 @@ typedef   struct tag_HAL_VERSION
 #define IS_K_CUT(version)                              ((GET_CVID_CUT_VERSION(version) == K_CUT_VERSION) ? true : false)
 
 /* HAL_VENDOR_E */
-#define IS_CHIP_VENDOR_TSMC(version)   ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC)? true: false)
-#define IS_CHIP_VENDOR_UMC(version)    ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC)? true: false)
-#define IS_CHIP_VENDOR_SMIC(version)   ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_SMIC)? true: false)
+#define IS_CHIP_VENDOR_TSMC(version)   ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version)    ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? true : false)
+#define IS_CHIP_VENDOR_SMIC(version)   ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_SMIC) ? true : false)
 
 /* HAL_RF_TYPE_E */
-#define IS_1T1R(version)                                       ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R)? true : false)
-#define IS_1T2R(version)                                       ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R)? true : false)
-#define IS_2T2R(version)                                       ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R)? true : false)
+#define IS_1T1R(version)                                       ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? true : false)
+#define IS_1T2R(version)                                       ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false)
+#define IS_2T2R(version)                                       ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false)
 
 #endif
index d3af9f4..5506f51 100644 (file)
@@ -10,8 +10,8 @@
 
 int rtw_init_cmd_priv(struct   cmd_priv *pcmdpriv);
 int rtw_init_evt_priv(struct evt_priv *pevtpriv);
-extern void _rtw_free_evt_priv (struct evt_priv *pevtpriv);
-extern void _rtw_free_cmd_priv (struct cmd_priv *pcmdpriv);
+extern void _rtw_free_evt_priv(struct  evt_priv *pevtpriv);
+extern void _rtw_free_cmd_priv(struct  cmd_priv *pcmdpriv);
 int _rtw_enqueue_cmd(struct __queue *queue, struct cmd_obj *obj);
 extern struct  cmd_obj *_rtw_dequeue_cmd(struct __queue *queue);
 
index 6ec9087..dba7521 100644 (file)
@@ -77,7 +77,7 @@ enum _NIC_VERSION {
 #define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4)
 #define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5)
 
-struct specific_device_id{
+struct specific_device_id {
 
        u32     flags;
 
@@ -151,8 +151,8 @@ struct registry_priv
 
        u8 lowrate_two_xmit;
 
-       u8 rf_config ;
-       u8 low_power ;
+       u8 rf_config;
+       u8 low_power;
 
        u8 wifi_spec;/*  !turbo_mode */
 
@@ -498,11 +498,11 @@ enum ADAPTER_TYPE {
        MAX_ADAPTER = 0xFF,
 };
 
-typedef enum _DRIVER_STATE{
+typedef enum _DRIVER_STATE {
        DRIVER_NORMAL = 0,
        DRIVER_DISAPPEAR = 1,
        DRIVER_REPLACE_DONGLE = 2,
-}DRIVER_STATE;
+} DRIVER_STATE;
 
 struct adapter {
        int     DriverState;/*  for disable driver using module, use dongle to replace module. */
index f5c3ce5..a46626d 100644 (file)
 #define DESC_RATEVHTSS4MCS9            0x53
 
 #define HDATA_RATE(rate)\
-(rate ==DESC_RATE1M)?"CCK_1M":\
-(rate ==DESC_RATE2M)?"CCK_2M":\
-(rate ==DESC_RATE5_5M)?"CCK5_5M":\
-(rate ==DESC_RATE11M)?"CCK_11M":\
-(rate ==DESC_RATE6M)?"OFDM_6M":\
-(rate ==DESC_RATE9M)?"OFDM_9M":\
-(rate ==DESC_RATE12M)?"OFDM_12M":\
-(rate ==DESC_RATE18M)?"OFDM_18M":\
-(rate ==DESC_RATE24M)?"OFDM_24M":\
-(rate ==DESC_RATE36M)?"OFDM_36M":\
-(rate ==DESC_RATE48M)?"OFDM_48M":\
-(rate ==DESC_RATE54M)?"OFDM_54M":\
-(rate ==DESC_RATEMCS0)?"MCS0":\
-(rate ==DESC_RATEMCS1)?"MCS1":\
-(rate ==DESC_RATEMCS2)?"MCS2":\
-(rate ==DESC_RATEMCS3)?"MCS3":\
-(rate ==DESC_RATEMCS4)?"MCS4":\
-(rate ==DESC_RATEMCS5)?"MCS5":\
-(rate ==DESC_RATEMCS6)?"MCS6":\
-(rate ==DESC_RATEMCS7)?"MCS7":\
-(rate ==DESC_RATEMCS8)?"MCS8":\
-(rate ==DESC_RATEMCS9)?"MCS9":\
-(rate ==DESC_RATEMCS10)?"MCS10":\
-(rate ==DESC_RATEMCS11)?"MCS11":\
-(rate ==DESC_RATEMCS12)?"MCS12":\
-(rate ==DESC_RATEMCS13)?"MCS13":\
-(rate ==DESC_RATEMCS14)?"MCS14":\
-(rate ==DESC_RATEMCS15)?"MCS15":\
-(rate ==DESC_RATEVHTSS1MCS0)?"VHTSS1MCS0":\
-(rate ==DESC_RATEVHTSS1MCS1)?"VHTSS1MCS1":\
-(rate ==DESC_RATEVHTSS1MCS2)?"VHTSS1MCS2":\
-(rate ==DESC_RATEVHTSS1MCS3)?"VHTSS1MCS3":\
-(rate ==DESC_RATEVHTSS1MCS4)?"VHTSS1MCS4":\
-(rate ==DESC_RATEVHTSS1MCS5)?"VHTSS1MCS5":\
-(rate ==DESC_RATEVHTSS1MCS6)?"VHTSS1MCS6":\
-(rate ==DESC_RATEVHTSS1MCS7)?"VHTSS1MCS7":\
-(rate ==DESC_RATEVHTSS1MCS8)?"VHTSS1MCS8":\
-(rate ==DESC_RATEVHTSS1MCS9)?"VHTSS1MCS9":\
-(rate ==DESC_RATEVHTSS2MCS0)?"VHTSS2MCS0":\
-(rate ==DESC_RATEVHTSS2MCS1)?"VHTSS2MCS1":\
-(rate ==DESC_RATEVHTSS2MCS2)?"VHTSS2MCS2":\
-(rate ==DESC_RATEVHTSS2MCS3)?"VHTSS2MCS3":\
-(rate ==DESC_RATEVHTSS2MCS4)?"VHTSS2MCS4":\
-(rate ==DESC_RATEVHTSS2MCS5)?"VHTSS2MCS5":\
-(rate ==DESC_RATEVHTSS2MCS6)?"VHTSS2MCS6":\
-(rate ==DESC_RATEVHTSS2MCS7)?"VHTSS2MCS7":\
-(rate ==DESC_RATEVHTSS2MCS8)?"VHTSS2MCS8":\
-(rate ==DESC_RATEVHTSS2MCS9)?"VHTSS2MCS9":"UNKNOW"
+(rate == DESC_RATE1M) ? "CCK_1M" : \
+(rate == DESC_RATE2M) ? "CCK_2M" : \
+(rate == DESC_RATE5_5M) ? "CCK5_5M" : \
+(rate == DESC_RATE11M) ? "CCK_11M" : \
+(rate == DESC_RATE6M) ? "OFDM_6M" : \
+(rate == DESC_RATE9M) ? "OFDM_9M" : \
+(rate == DESC_RATE12M) ? "OFDM_12M" : \
+(rate == DESC_RATE18M) ? "OFDM_18M" : \
+(rate == DESC_RATE24M) ? "OFDM_24M" : \
+(rate == DESC_RATE36M) ? "OFDM_36M" : \
+(rate == DESC_RATE48M) ? "OFDM_48M" : \
+(rate == DESC_RATE54M) ? "OFDM_54M" : \
+(rate == DESC_RATEMCS0) ? "MCS0" : \
+(rate == DESC_RATEMCS1) ? "MCS1" : \
+(rate == DESC_RATEMCS2) ? "MCS2" : \
+(rate == DESC_RATEMCS3) ? "MCS3" : \
+(rate == DESC_RATEMCS4) ? "MCS4" : \
+(rate == DESC_RATEMCS5) ? "MCS5" : \
+(rate == DESC_RATEMCS6) ? "MCS6" : \
+(rate == DESC_RATEMCS7) ? "MCS7" : \
+(rate == DESC_RATEMCS8) ? "MCS8" : \
+(rate == DESC_RATEMCS9) ? "MCS9" : \
+(rate == DESC_RATEMCS10) ? "MCS10" : \
+(rate == DESC_RATEMCS11) ? "MCS11" : \
+(rate == DESC_RATEMCS12) ? "MCS12" : \
+(rate == DESC_RATEMCS13) ? "MCS13" : \
+(rate == DESC_RATEMCS14) ? "MCS14" : \
+(rate == DESC_RATEMCS15) ? "MCS15" : \
+(rate == DESC_RATEVHTSS1MCS0) ? "VHTSS1MCS0" : \
+(rate == DESC_RATEVHTSS1MCS1) ? "VHTSS1MCS1" : \
+(rate == DESC_RATEVHTSS1MCS2) ? "VHTSS1MCS2" : \
+(rate == DESC_RATEVHTSS1MCS3) ? "VHTSS1MCS3" : \
+(rate == DESC_RATEVHTSS1MCS4) ? "VHTSS1MCS4" : \
+(rate == DESC_RATEVHTSS1MCS5) ? "VHTSS1MCS5" : \
+(rate == DESC_RATEVHTSS1MCS6) ? "VHTSS1MCS6" : \
+(rate == DESC_RATEVHTSS1MCS7) ? "VHTSS1MCS7" : \
+(rate == DESC_RATEVHTSS1MCS8) ? "VHTSS1MCS8" : \
+(rate == DESC_RATEVHTSS1MCS9) ? "VHTSS1MCS9" : \
+(rate == DESC_RATEVHTSS2MCS0) ? "VHTSS2MCS0" : \
+(rate == DESC_RATEVHTSS2MCS1) ? "VHTSS2MCS1" : \
+(rate == DESC_RATEVHTSS2MCS2) ? "VHTSS2MCS2" : \
+(rate == DESC_RATEVHTSS2MCS3) ? "VHTSS2MCS3" : \
+(rate == DESC_RATEVHTSS2MCS4) ? "VHTSS2MCS4" : \
+(rate == DESC_RATEVHTSS2MCS5) ? "VHTSS2MCS5" : \
+(rate == DESC_RATEVHTSS2MCS6) ? "VHTSS2MCS6" : \
+(rate == DESC_RATEVHTSS2MCS7) ? "VHTSS2MCS7" : \
+(rate == DESC_RATEVHTSS2MCS8) ? "VHTSS2MCS8" : \
+(rate == DESC_RATEVHTSS2MCS9) ? "VHTSS2MCS9" : "UNKNOW"
 
 
 enum{
@@ -235,7 +235,7 @@ s32 c2h_evt_read_88xx(struct adapter *adapter, u8 *buf);
 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);
 
-void hw_var_port_switch (struct adapter *adapter);
+void hw_var_port_switch(struct adapter *adapter);
 
 void SetHwReg(struct adapter *padapter, u8 variable, u8 *val);
 void GetHwReg(struct adapter *padapter, u8 variable, u8 *val);
index 7dbae5e..b951bc2 100644 (file)
@@ -11,7 +11,7 @@
 /*     H2C CMD DEFINITION    ------------------------------------------------ */
 /*  */
 /*  88e, 8723b, 8812, 8821, 92e use the same FW code base */
-enum h2c_cmd{
+enum h2c_cmd {
        /* Common Class: 000 */
        H2C_RSVD_PAGE = 0x00,
        H2C_MEDIA_STATUS_RPT = 0x01,
@@ -96,9 +96,9 @@ enum h2c_cmd{
 #define H2C_PROBERSP_RSVDPAGE_LEN      5
 
 #ifdef CONFIG_WOWLAN
-#define eqMacAddr(a, b)                (((a)[0]==(b)[0] && (a)[1]==(b)[1] && (a)[2]==(b)[2] && (a)[3]==(b)[3] && (a)[4]==(b)[4] && (a)[5]==(b)[5]) ? 1:0)
-#define cpMacAddr(des, src)    ((des)[0]=(src)[0], (des)[1]=(src)[1], (des)[2]=(src)[2], (des)[3]=(src)[3], (des)[4]=(src)[4], (des)[5]=(src)[5])
-#define cpIpAddr(des, src)     ((des)[0]=(src)[0], (des)[1]=(src)[1], (des)[2]=(src)[2], (des)[3]=(src)[3])
+#define eqMacAddr(a, b)                (((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] && (a)[3] == (b)[3] && (a)[4] == (b)[4] && (a)[5] == (b)[5]) ? 1 : 0)
+#define cpMacAddr(des, src)    ((des)[0] = (src)[0], (des)[1] = (src)[1], (des)[2] = (src)[2], (des)[3] = (src)[3], (des)[4] = (src)[4], (des)[5] = (src)[5])
+#define cpIpAddr(des, src)     ((des)[0] = (src)[0], (des)[1] = (src)[1], (des)[2] = (src)[2], (des)[3] = (src)[3])
 
 /*  */
 /*  ARP packet */
index e9a3006..9fff4aa 100644 (file)
@@ -177,7 +177,7 @@ u8          Channel,
        bool            *bIn24G
        );
 
-s8 phy_get_tx_pwr_lmt (struct adapter *adapter, u32 RegPwrTblSel,
+s8 phy_get_tx_pwr_lmt(struct adapter *adapter, u32 RegPwrTblSel,
                        enum BAND_TYPE Band, enum CHANNEL_WIDTH Bandwidth,
 u8             RfPath,
 u8             DataRate,
index 31a187b..37fa59a 100644 (file)
@@ -707,13 +707,13 @@ Default: 00b.
 
 
 /*  ALL CCK Rate */
-#define        RATE_ALL_CCK                            RATR_1M|RATR_2M|RATR_55M|RATR_11M
-#define        RATE_ALL_OFDM_AG                        RATR_6M|RATR_9M|RATR_12M|RATR_18M|RATR_24M|\
-                                               RATR_36M|RATR_48M|RATR_54M
-#define        RATE_ALL_OFDM_1SS                       RATR_MCS0|RATR_MCS1|RATR_MCS2|RATR_MCS3 |\
-                                               RATR_MCS4|RATR_MCS5|RATR_MCS6   |RATR_MCS7
-#define        RATE_ALL_OFDM_2SS                       RATR_MCS8|RATR_MCS9     |RATR_MCS10|RATR_MCS11|\
-                                               RATR_MCS12|RATR_MCS13|RATR_MCS14|RATR_MCS15
+#define        RATE_ALL_CCK                            RATR_1M | RATR_2M | RATR_55M | RATR_11M
+#define        RATE_ALL_OFDM_AG                        RATR_6M | RATR_9M | RATR_12M | RATR_18M | RATR_24M |\
+                                               RATR_36M | RATR_48M | RATR_54M
+#define        RATE_ALL_OFDM_1SS                       RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | RATR_MCS3 |\
+                                               RATR_MCS4 | RATR_MCS5 | RATR_MCS6 | RATR_MCS7
+#define        RATE_ALL_OFDM_2SS                       RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | RATR_MCS11 |\
+                                               RATR_MCS12 | RATR_MCS13 | RATR_MCS14 | RATR_MCS15
 
 #define RATE_BITMAP_ALL                        0xFFFFF
 
index 24926eb..1de5aca 100644 (file)
@@ -296,7 +296,7 @@ enum wowlan_subcode {
        WOWLAN_AP_DISABLE               = 13
 };
 
-struct wowlan_ioctl_param{
+struct wowlan_ioctl_param {
        unsigned int subcode;
        unsigned int subcode_value;
        unsigned int wakeup_reason;
index c6b9bf1..ed0caa0 100644 (file)
@@ -25,7 +25,7 @@
 #define        RF6052_MAX_REG_92C                      0x7F
 
 #define        RF6052_MAX_REG  \
-               (RF6052_MAX_REG_88E > RF6052_MAX_REG_92C) ? RF6052_MAX_REG_88E: RF6052_MAX_REG_92C
+               (RF6052_MAX_REG_88E > RF6052_MAX_REG_92C) ? RF6052_MAX_REG_88E : RF6052_MAX_REG_92C
 
 #define GET_RF6052_REAL_MAX_REG(_Adapter)      RF6052_MAX_REG_92C
 
index b40868b..419ddb0 100644 (file)
@@ -58,9 +58,9 @@ u32                   Data
        );
 
 /* MAC/BB/RF HAL config */
-int PHY_BBConfig8723B(struct adapter *Adapter  );
+int PHY_BBConfig8723B(struct adapter *Adapter);
 
-int PHY_RFConfig8723B(struct adapter *Adapter  );
+int PHY_RFConfig8723B(struct adapter *Adapter);
 
 s32 PHY_MACConfig8723B(struct adapter *padapter);
 
index 130a948..28aca04 100644 (file)
@@ -46,9 +46,9 @@
        {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/   \
        {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0}, /*0x00[5] = 1b'0 release analog Ips to digital , 1:isolation*/   \
        {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4|BIT3|BIT2), 0},/* disable SW LPS 0x04[10]= 0 and WLSUS_EN 0x04[11]= 0*/     \
-       {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , BIT0},/* Disable USB suspend */    \
+       {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* Disable USB suspend */     \
        {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1    power ready*/  \
-       {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0 , 0},/* Enable USB suspend */        \
+       {0x0075, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/* Enable USB suspend */ \
        {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset  0x04[16]= 1*/  \
        {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]= 0*/   \
        {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4|BIT3), 0},/* disable WL suspend*/   \
index 2110552..7243e65 100644 (file)
@@ -98,8 +98,8 @@ enum {
 
 
 #define WPA_SELECTOR_LEN 4
-extern u8 RTW_WPA_OUI_TYPE[] ;
-extern u16 RTW_WPA_VERSION ;
+extern u8 RTW_WPA_OUI_TYPE[];
+extern u16 RTW_WPA_VERSION;
 extern u8 WPA_AUTH_KEY_MGMT_NONE[];
 extern u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[];
 extern u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[];
@@ -139,7 +139,7 @@ typedef enum _RATEID_IDX_ {
        RATEID_IDX_VHT_1SS = 10,
 } RATEID_IDX, *PRATEID_IDX;
 
-typedef enum _RATR_TABLE_MODE{
+typedef enum _RATR_TABLE_MODE {
        RATR_INX_WIRELESS_NGB = 0,      /*  BGN 40 Mhz 2SS 1SS */
        RATR_INX_WIRELESS_NG = 1,               /*  GN or N */
        RATR_INX_WIRELESS_NB = 2,               /*  BGN 20 Mhz 2SS 1SS  or BN */
@@ -149,7 +149,7 @@ typedef enum _RATR_TABLE_MODE{
        RATR_INX_WIRELESS_B = 6,
        RATR_INX_WIRELESS_MC = 7,
        RATR_INX_WIRELESS_AC_N = 8,
-}RATR_TABLE_MODE, *PRATR_TABLE_MODE;
+} RATR_TABLE_MODE, *PRATR_TABLE_MODE;
 
 
 enum NETWORK_TYPE
@@ -248,7 +248,7 @@ struct ieee_param_ex {
        u8 data[0];
 };
 
-struct sta_data{
+struct sta_data {
        u16 aid;
        u16 capability;
        int flags;
@@ -439,7 +439,7 @@ struct ieee80211_snap_hdr {
 #define IEEE80211_OFDM_SHIFT_MASK_A         4
 
 
-enum MGN_RATE{
+enum MGN_RATE {
        MGN_1M          = 0x02,
        MGN_2M          = 0x04,
        MGN_5_5M        = 0x0B,
@@ -906,7 +906,7 @@ enum rtw_ieee80211_spectrum_mgmt_actioncode {
        RTW_WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5,
 };
 
-enum _PUBLIC_ACTION{
+enum _PUBLIC_ACTION {
        ACT_PUBLIC_BSSCOEXIST = 0, /*  20/40 BSS Coexistence */
        ACT_PUBLIC_DSE_ENABLE = 1,
        ACT_PUBLIC_DSE_DEENABLE = 2,
@@ -953,7 +953,7 @@ enum rtw_ieee80211_back_parties {
 };
 
 /* VHT features action code */
-enum rtw_ieee80211_vht_actioncode{
+enum rtw_ieee80211_vht_actioncode {
        RTW_WLAN_ACTION_VHT_COMPRESSED_BEAMFORMING = 0,
        RTW_WLAN_ACTION_VHT_GROUPID_MANAGEMENT = 1,
        RTW_WLAN_ACTION_VHT_OPMODE_NOTIFICATION = 2,
@@ -1128,7 +1128,7 @@ u8 *rtw_get_ie(u8*pbuf, sint index, sint *len, sint limit);
 u8 *rtw_get_ie_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen);
 int rtw_ies_remove_ie(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len);
 
-void rtw_set_supported_rate(u8 *SupportedRates, uint mode) ;
+void rtw_set_supported_rate(u8 *SupportedRates, uint mode);
 
 unsigned char *rtw_get_wpa_ie(unsigned char *pie, int *wpa_ie_len, int limit);
 unsigned char *rtw_get_wpa2_ie(unsigned char *pie, int *rsn_ie_len, int limit);
@@ -1142,8 +1142,8 @@ void rtw_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie
 
 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);
-u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_attr, u32 *len_attr);
-u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id , u8 *buf_content, uint *len_content);
+u8 *rtw_get_wps_attr(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_attr, u32 *len_attr);
+u8 *rtw_get_wps_attr_content(u8 *wps_ie, uint wps_ielen, u16 target_attr_id, u8 *buf_content, uint *len_content);
 
 /**
  * for_each_ie - iterate over continuous IEs
index fa16139..c59c138 100644 (file)
@@ -50,7 +50,7 @@ void rtw_reset_drv_sw(struct adapter *padapter);
 void rtw_dev_unload(struct adapter *padapter);
 
 u32 rtw_start_drv_threads(struct adapter *padapter);
-void rtw_stop_drv_threads (struct adapter *padapter);
+void rtw_stop_drv_threads(struct adapter *padapter);
 void rtw_cancel_all_timer(struct adapter *padapter);
 
 int rtw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
index a40cf7b..5f68189 100644 (file)
@@ -80,7 +80,7 @@ enum mstat_f {
 #define mstat_tf_idx(flags) ((flags)&0xff)
 #define mstat_ff_idx(flags) (((flags)&0xff00) >> 8)
 
-typedef enum mstat_status{
+typedef enum mstat_status {
        MSTAT_ALLOC_SUCCESS = 0,
        MSTAT_ALLOC_FAIL,
        MSTAT_FREE
@@ -117,7 +117,7 @@ static inline void thread_enter(char *name)
 
 static inline void flush_signals_thread(void)
 {
-       if (signal_pending (current))
+       if (signal_pending(current))
        {
                flush_signals(current);
        }
@@ -134,14 +134,14 @@ static inline int rtw_bug_check(void *parg1, void *parg2, void *parg3, void *par
 }
 
 #define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r))
-#define RND4(x)        (((x >> 2) + (((x & 3) == 0) ?  0: 1)) << 2)
+#define RND4(x)        (((x >> 2) + (((x & 3) == 0) ?  0 : 1)) << 2)
 
 static inline u32 _RND4(u32 sz)
 {
 
        u32 val;
 
-       val = ((sz >> 2) + ((sz & 3) ? 1: 0)) << 2;
+       val = ((sz >> 2) + ((sz & 3) ? 1 : 0)) << 2;
 
        return val;
 
@@ -152,7 +152,7 @@ static inline u32 _RND8(u32 sz)
 
        u32 val;
 
-       val = ((sz >> 3) + ((sz & 7) ? 1: 0)) << 3;
+       val = ((sz >> 3) + ((sz & 7) ? 1 : 0)) << 3;
 
        return val;
 
index a2d9de8..1710fa3 100644 (file)
@@ -80,7 +80,7 @@ static inline struct list_head        *get_list_head(struct __queue   *queue)
 
 static inline void _set_timer(_timer *ptimer, u32 delay_time)
 {
-       mod_timer(ptimer , (jiffies+(delay_time*HZ/1000)));
+       mod_timer(ptimer, (jiffies + (delay_time * HZ / 1000)));
 }
 
 static inline void _cancel_timer(_timer *ptimer, u8 *bcancelled)
index 1056f61..e85aafc 100644 (file)
@@ -9,7 +9,7 @@
 
 
 extern sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
-extern void _rtw_free_recv_priv (struct recv_priv *precvpriv);
+extern void _rtw_free_recv_priv(struct recv_priv *precvpriv);
 
 
 extern s32  rtw_recv_entry(union recv_frame *precv_frame);
@@ -19,7 +19,7 @@ extern void rtw_recv_returnpacket(_nic_hdl cnxt, _pkt *preturnedpkt);
 extern void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup);
 
 int    rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter);
-void rtw_free_recv_priv (struct recv_priv *precvpriv);
+void rtw_free_recv_priv(struct recv_priv *precvpriv);
 
 
 void rtw_os_recv_resource_alloc(struct adapter *padapter, union recv_frame *precvframe);
index ecfd2d3..3bfb0e9 100644 (file)
@@ -11,7 +11,7 @@
 /*     H2C CMD DEFINITION    ------------------------------------------------ */
 /*  */
 
-enum h2c_cmd_8723B{
+enum h2c_cmd_8723B {
        /* Common Class: 000 */
        H2C_8723B_RSVD_PAGE = 0x00,
        H2C_8723B_MEDIA_STATUS_RPT = 0x01,
index 987b9f1..d712c6d 100644 (file)
@@ -8,7 +8,7 @@
 #define __RTL8723B_RF_H__
 
 
-int    PHY_RF6052_Config8723B(struct adapter *Adapter  );
+int    PHY_RF6052_Config8723B(struct adapter *Adapter);
 
 void
 PHY_RF6052SetBandwidth8723B(struct adapter *Adapter,
index 23a6069..320ca65 100644 (file)
@@ -176,7 +176,7 @@ typedef struct txdesc_8723b
        u32 txbf_path:1;
        u32 seq:12;
        u32 final_data_rate:8;
-}TXDESC_8723B, *PTXDESC_8723B;
+} TXDESC_8723B, *PTXDESC_8723B;
 
 #ifndef __INC_HAL8723BDESC_H
 #define __INC_HAL8723BDESC_H
index f76fbfb..c3a65f9 100644 (file)
@@ -7,7 +7,7 @@
 #ifndef _RTL871X_BYTEORDER_H_
 #define _RTL871X_BYTEORDER_H_
 
-#if defined (__LITTLE_ENDIAN)
+#if defined(__LITTLE_ENDIAN)
 #include <linux/byteorder/little_endian.h>
 #else
 #  include <linux/byteorder/big_endian.h>
index b83824c..3e025a6 100644 (file)
@@ -75,7 +75,7 @@ do {\
        INIT_LIST_HEAD(&pcmd->list);\
        pcmd->cmdcode = code;\
        pcmd->parmbuf = (u8 *)(pparm);\
-       pcmd->cmdsz = sizeof (*pparm);\
+       pcmd->cmdsz = sizeof(*pparm);\
        pcmd->rsp = NULL;\
        pcmd->rspsz = 0;\
 } while (0)
@@ -129,9 +129,9 @@ extern void rtw_free_cmd_obj(struct cmd_obj *pcmd);
 void rtw_stop_cmd_thread(struct adapter *adapter);
 int rtw_cmd_thread(void *context);
 
-extern void rtw_free_cmd_priv (struct cmd_priv *pcmdpriv);
+extern void rtw_free_cmd_priv(struct cmd_priv *pcmdpriv);
 
-extern void rtw_free_evt_priv (struct evt_priv *pevtpriv);
+extern void rtw_free_evt_priv(struct evt_priv *pevtpriv);
 extern void rtw_evt_notify_isr(struct evt_priv *pevtpriv);
 
 enum rtw_drvextra_cmd_id
@@ -163,10 +163,10 @@ enum LPS_CTRL_TYPE
 {
        LPS_CTRL_SCAN = 0,
        LPS_CTRL_JOINBSS = 1,
-       LPS_CTRL_CONNECT =2,
-       LPS_CTRL_DISCONNECT =3,
-       LPS_CTRL_SPECIAL_PACKET =4,
-       LPS_CTRL_LEAVE =5,
+       LPS_CTRL_CONNECT = 2,
+       LPS_CTRL_DISCONNECT = 3,
+       LPS_CTRL_SPECIAL_PACKET = 4,
+       LPS_CTRL_LEAVE = 5,
        LPS_CTRL_TRAFFIC_BUSY = 6,
 };
 
@@ -692,40 +692,40 @@ struct getratable_rsp {
 
 
 /* to get TX, RX retry count */
-struct gettxretrycnt_parm{
+struct gettxretrycnt_parm {
        unsigned int rsvd;
 };
-struct gettxretrycnt_rsp{
+struct gettxretrycnt_rsp {
        unsigned long tx_retrycnt;
 };
 
-struct getrxretrycnt_parm{
+struct getrxretrycnt_parm {
        unsigned int rsvd;
 };
-struct getrxretrycnt_rsp{
+struct getrxretrycnt_rsp {
        unsigned long rx_retrycnt;
 };
 
 /* to get BCNOK, BCNERR count */
-struct getbcnokcnt_parm{
+struct getbcnokcnt_parm {
        unsigned int rsvd;
 };
-struct getbcnokcnt_rsp{
+struct getbcnokcnt_rsp {
        unsigned long  bcnokcnt;
 };
 
-struct getbcnerrcnt_parm{
+struct getbcnerrcnt_parm {
        unsigned int rsvd;
 };
-struct getbcnerrcnt_rsp{
+struct getbcnerrcnt_rsp {
        unsigned long bcnerrcnt;
 };
 
 /*  to get current TX power level */
-struct getcurtxpwrlevel_parm{
+struct getcurtxpwrlevel_parm {
        unsigned int rsvd;
 };
-struct getcurtxpwrlevel_rsp{
+struct getcurtxpwrlevel_rsp {
        unsigned short tx_power;
 };
 
@@ -883,56 +883,56 @@ struct _cmd_callback {
 
 enum rtw_h2c_cmd
 {
-       GEN_CMD_CODE(_Read_MACREG) ,    /*0*/
-       GEN_CMD_CODE(_Write_MACREG) ,
-       GEN_CMD_CODE(_Read_BBREG) ,
-       GEN_CMD_CODE(_Write_BBREG) ,
-       GEN_CMD_CODE(_Read_RFREG) ,
-       GEN_CMD_CODE(_Write_RFREG) , /*5*/
-       GEN_CMD_CODE(_Read_EEPROM) ,
-       GEN_CMD_CODE(_Write_EEPROM) ,
-       GEN_CMD_CODE(_Read_EFUSE) ,
-       GEN_CMD_CODE(_Write_EFUSE) ,
-
-       GEN_CMD_CODE(_Read_CAM) ,       /*10*/
-       GEN_CMD_CODE(_Write_CAM) ,
+       GEN_CMD_CODE(_Read_MACREG)    /*0*/
+       GEN_CMD_CODE(_Write_MACREG),
+       GEN_CMD_CODE(_Read_BBREG),
+       GEN_CMD_CODE(_Write_BBREG),
+       GEN_CMD_CODE(_Read_RFREG),
+       GEN_CMD_CODE(_Write_RFREG), /*5*/
+       GEN_CMD_CODE(_Read_EEPROM),
+       GEN_CMD_CODE(_Write_EEPROM),
+       GEN_CMD_CODE(_Read_EFUSE),
+       GEN_CMD_CODE(_Write_EFUSE),
+
+       GEN_CMD_CODE(_Read_CAM)       /*10*/
+       GEN_CMD_CODE(_Write_CAM),
        GEN_CMD_CODE(_setBCNITV),
        GEN_CMD_CODE(_setMBIDCFG),
        GEN_CMD_CODE(_JoinBss),   /*14*/
-       GEN_CMD_CODE(_DisConnect) , /*15*/
-       GEN_CMD_CODE(_CreateBss) ,
-       GEN_CMD_CODE(_SetOpMode) ,
+       GEN_CMD_CODE(_DisConnect), /*15*/
+       GEN_CMD_CODE(_CreateBss),
+       GEN_CMD_CODE(_SetOpMode),
        GEN_CMD_CODE(_SiteSurvey),  /*18*/
-       GEN_CMD_CODE(_SetAuth) ,
-
-       GEN_CMD_CODE(_SetKey) , /*20*/
-       GEN_CMD_CODE(_SetStaKey) ,
-       GEN_CMD_CODE(_SetAssocSta) ,
-       GEN_CMD_CODE(_DelAssocSta) ,
-       GEN_CMD_CODE(_SetStaPwrState) ,
-       GEN_CMD_CODE(_SetBasicRate) , /*25*/
-       GEN_CMD_CODE(_GetBasicRate) ,
-       GEN_CMD_CODE(_SetDataRate) ,
-       GEN_CMD_CODE(_GetDataRate) ,
-       GEN_CMD_CODE(_SetPhyInfo) ,
-
-       GEN_CMD_CODE(_GetPhyInfo) ,     /*30*/
-       GEN_CMD_CODE(_SetPhy) ,
-       GEN_CMD_CODE(_GetPhy) ,
-       GEN_CMD_CODE(_readRssi) ,
-       GEN_CMD_CODE(_readGain) ,
-       GEN_CMD_CODE(_SetAtim) , /*35*/
-       GEN_CMD_CODE(_SetPwrMode) ,
+       GEN_CMD_CODE(_SetAuth),
+
+       GEN_CMD_CODE(_SetKey) /*20*/
+       GEN_CMD_CODE(_SetStaKey),
+       GEN_CMD_CODE(_SetAssocSta),
+       GEN_CMD_CODE(_DelAssocSta),
+       GEN_CMD_CODE(_SetStaPwrState),
+       GEN_CMD_CODE(_SetBasicRate), /*25*/
+       GEN_CMD_CODE(_GetBasicRate),
+       GEN_CMD_CODE(_SetDataRate),
+       GEN_CMD_CODE(_GetDataRate),
+       GEN_CMD_CODE(_SetPhyInfo),
+
+       GEN_CMD_CODE(_GetPhyInfo)     /*30*/
+       GEN_CMD_CODE(_SetPhy),
+       GEN_CMD_CODE(_GetPhy),
+       GEN_CMD_CODE(_readRssi),
+       GEN_CMD_CODE(_readGain),
+       GEN_CMD_CODE(_SetAtim), /*35*/
+       GEN_CMD_CODE(_SetPwrMode),
        GEN_CMD_CODE(_JoinbssRpt),
-       GEN_CMD_CODE(_SetRaTable) ,
-       GEN_CMD_CODE(_GetRaTable) ,
+       GEN_CMD_CODE(_SetRaTable),
+       GEN_CMD_CODE(_GetRaTable),
 
        GEN_CMD_CODE(_GetCCXReport), /*40*/
        GEN_CMD_CODE(_GetDTMReport),
        GEN_CMD_CODE(_GetTXRateStatistics),
        GEN_CMD_CODE(_SetUsbSuspend),
        GEN_CMD_CODE(_SetH2cLbk),
-       GEN_CMD_CODE(_AddBAReq) , /*45*/
+       GEN_CMD_CODE(_AddBAReq), /*45*/
        GEN_CMD_CODE(_SetChannel), /*46*/
        GEN_CMD_CODE(_SetTxPower),
        GEN_CMD_CODE(_SwitchAntenna),
index 22fc5d7..c90adfb 100644 (file)
        #define _MODULE_DEFINE_ _module_efuse_
 #endif
 
-#define RT_TRACE(_Comp, _Level, Fmt) do{}while (0)
-#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) do{}while (0)
+#define RT_TRACE(_Comp, _Level, Fmt) do {} while (0)
+#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData, _HexDataLen) do {} while (0)
 
 #define DBG_871X(x, ...) do {} while (0)
 #define MSG_8192C(x, ...) do {} while (0)
-#define DBG_8192C(x,...) do {} while (0)
-#define DBG_871X_LEVEL(x,...) do {} while (0)
+#define DBG_8192C(x, ...) do {} while (0)
+#define DBG_871X_LEVEL(x, ...) do {} while (0)
 
 #undef _dbgdump
 
                                _dbgdump(DRIVER_PREFIX"ERROR " fmt, ##arg);\
                        else \
                                _dbgdump(DRIVER_PREFIX fmt, ##arg);\
-               }\
-       }while (0)
+               } \
+       } while (0)
 
 /* without driver-defined prefix */
 #undef _DBG_871X_LEVEL
                                _dbgdump("ERROR " fmt, ##arg);\
                        else \
                                _dbgdump(fmt, ##arg);\
-               }\
-       }while (0)
+               } \
+       } while (0)
 
 #define RTW_DBGDUMP NULL /* 'stream' for _dbgdump */
 
        #undef DBG_871X
        #define DBG_871X(...)     do {\
                _dbgdump(DRIVER_PREFIX __VA_ARGS__);\
-       }while (0)
+       } while (0)
 
        #undef MSG_8192C
        #define MSG_8192C(...)     do {\
                _dbgdump(DRIVER_PREFIX __VA_ARGS__);\
-       }while (0)
+       } while (0)
 
        #undef DBG_8192C
        #define DBG_8192C(...)     do {\
                _dbgdump(DRIVER_PREFIX __VA_ARGS__);\
-       }while (0)
+       } while (0)
 #endif /* defined(_dbgdump) */
 #endif /* DEBUG */
 
                if ((_Comp & GlobalDebugComponents) && (_Level <= GlobalDebugLevel)) {\
                        _dbgdump("%s [0x%08x,%d]", DRIVER_PREFIX, (unsigned int)_Comp, _Level);\
                        _dbgdump Fmt;\
-               }\
-       }while (0)
+               } \
+       } while (0)
 
 #endif /* defined(_dbgdump) && defined(_MODULE_DEFINE_) */
 
                        u8 *ptr = (u8 *)_HexData;                               \
                        _dbgdump("%s", DRIVER_PREFIX);                                          \
                        _dbgdump(_TitleString);                                         \
-                       for (__i = 0; __i<(int)_HexDataLen; __i++)                              \
+                       for (__i = 0; __i < (int)_HexDataLen; __i++)                            \
                        {                                                               \
                                _dbgdump("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?"  ":" ");  \
                                if (((__i + 1) % 16) == 0)      _dbgdump("\n");                 \
index 1fcd79f..704c646 100644 (file)
@@ -91,7 +91,7 @@ typedef enum _RT_CUSTOMER_ID
        RT_CID_819x_ALPHA_Dlink = 44,/* add by ylb 20121012 for customer led for alpha */
        RT_CID_WNC_NEC = 45,/* add by page for NEC */
        RT_CID_DNI_BUFFALO = 46,/* add by page for NEC */
-}RT_CUSTOMER_ID, *PRT_CUSTOMER_ID;
+} RT_CUSTOMER_ID, *PRT_CUSTOMER_ID;
 
 struct eeprom_priv
 {
index 9d9a5a3..4abcbbc 100644 (file)
@@ -57,15 +57,15 @@ enum _EFUSE_DEF_TYPE {
 #define                EFUSE_MAX_WORD_UNIT                     4
 
 /*------------------------------Define structure----------------------------*/
-typedef struct PG_PKT_STRUCT_A{
+typedef struct PG_PKT_STRUCT_A {
        u8 offset;
        u8 word_en;
        u8 data[8];
        u8 word_cnts;
-}PGPKT_STRUCT,*PPGPKT_STRUCT;
+} PGPKT_STRUCT, *PPGPKT_STRUCT;
 
 /*------------------------------Define structure----------------------------*/
-typedef struct _EFUSE_HAL{
+typedef struct _EFUSE_HAL {
        u8 fakeEfuseBank;
        u32 fakeEfuseUsedBytes;
        u8 fakeEfuseContent[EFUSE_MAX_HW_SIZE];
@@ -82,7 +82,7 @@ typedef struct _EFUSE_HAL{
        u8 fakeBTEfuseContent[EFUSE_MAX_BT_BANK][EFUSE_MAX_HW_SIZE];
        u8 fakeBTEfuseInitMap[EFUSE_BT_MAX_MAP_LEN];
        u8 fakeBTEfuseModifiedMap[EFUSE_BT_MAX_MAP_LEN];
-}EFUSE_HAL, *PEFUSE_HAL;
+} EFUSE_HAL, *PEFUSE_HAL;
 
 
 /*------------------------Export global variable----------------------------*/
index ee80aa2..aeaabab 100644 (file)
@@ -82,7 +82,7 @@ struct fwevent {
 
 #define C2HEVENT_SZ                    32
 
-struct event_node{
+struct event_node {
        unsigned char *node;
        unsigned char evt_code;
        unsigned short evt_sz;
index 952c804..4c224c1 100644 (file)
@@ -38,7 +38,7 @@ struct ht_priv
 
 };
 
-typedef enum AGGRE_SIZE{
+typedef enum AGGRE_SIZE {
        HT_AGG_SIZE_8K = 0,
        HT_AGG_SIZE_16K = 1,
        HT_AGG_SIZE_32K = 2,
@@ -47,9 +47,9 @@ typedef enum AGGRE_SIZE{
        VHT_AGG_SIZE_256K = 5,
        VHT_AGG_SIZE_512K = 6,
        VHT_AGG_SIZE_1024K = 7,
-}AGGRE_SIZE_E, *PAGGRE_SIZE_E;
+} AGGRE_SIZE_E, *PAGGRE_SIZE_E;
 
-typedef enum _RT_HT_INF0_CAP{
+typedef enum _RT_HT_INF0_CAP {
        RT_HT_CAP_USE_TURBO_AGGR = 0x01,
        RT_HT_CAP_USE_LONG_PREAMBLE = 0x02,
        RT_HT_CAP_USE_AMPDU = 0x04,
@@ -58,13 +58,13 @@ typedef enum _RT_HT_INF0_CAP{
        RT_HT_CAP_USE_92SE = 0x20,
        RT_HT_CAP_USE_88C_92C = 0x40,
        RT_HT_CAP_USE_AP_CLIENT_MODE = 0x80,    /*  AP team request to reserve this bit, by Emily */
-}RT_HT_INF0_CAPBILITY, *PRT_HT_INF0_CAPBILITY;
+} RT_HT_INF0_CAPBILITY, *PRT_HT_INF0_CAPBILITY;
 
-typedef enum _RT_HT_INF1_CAP{
+typedef enum _RT_HT_INF1_CAP {
        RT_HT_CAP_USE_VIDEO_CLIENT = 0x01,
        RT_HT_CAP_USE_JAGUAR_BCUT = 0x02,
        RT_HT_CAP_USE_JAGUAR_CCUT = 0x04,
-}RT_HT_INF1_CAPBILITY, *PRT_HT_INF1_CAPBILITY;
+} RT_HT_INF1_CAPBILITY, *PRT_HT_INF1_CAPBILITY;
 
 #define        LDPC_HT_ENABLE_RX                       BIT0
 #define        LDPC_HT_ENABLE_TX                       BIT1
index 99d104b..2581b51 100644 (file)
@@ -168,7 +168,7 @@ struct reg_protocol_rd {
 
        u32 Byte2Access : 1;
        u32 Byte1Access : 1;
-       u32 BurstMode :1 ;
+       u32 BurstMode :1;
        u32 FixOrContinuous : 1;
 
        u32 Reserved4 : 16;
@@ -224,7 +224,7 @@ struct reg_protocol_wt {
 
        u32 Byte2Access : 1;
        u32 Byte1Access : 1;
-       u32 BurstMode :1 ;
+       u32 BurstMode :1;
        u32 FixOrContinuous : 1;
 
        u32 Reserved4 : 16;
@@ -259,7 +259,7 @@ struct io_queue {
        struct  intf_hdl        intf;
 };
 
-struct io_priv{
+struct io_priv {
 
        struct adapter *padapter;
 
index 362737b..14e4bce 100644 (file)
@@ -85,7 +85,7 @@ typedef enum _RT_SCAN_TYPE {
        SCAN_PASSIVE,
        SCAN_ACTIVE,
        SCAN_MIX,
-}RT_SCAN_TYPE, *PRT_SCAN_TYPE;
+} RT_SCAN_TYPE, *PRT_SCAN_TYPE;
 
 enum  _BAND {
        GHZ24_50 = 0,
@@ -135,7 +135,7 @@ struct sitesurvey_ctrl {
        _timer  sitesurvey_ctrl_timer;
 };
 
-typedef struct _RT_LINK_DETECT_T{
+typedef struct _RT_LINK_DETECT_T {
        u32                     NumTxOkInPeriod;
        u32                     NumRxOkInPeriod;
        u32                     NumRxUnicastOkInPeriod;
@@ -148,62 +148,62 @@ typedef struct _RT_LINK_DETECT_T{
        /* u8 TrafficBusyState; */
        u8 TrafficTransitionCount;
        u32 LowPowerTransitionCount;
-}RT_LINK_DETECT_T, *PRT_LINK_DETECT_T;
+} RT_LINK_DETECT_T, *PRT_LINK_DETECT_T;
 
 struct profile_info {
        u8 ssidlen;
-       u8 ssid[ WLAN_SSID_MAXLEN ];
-       u8 peermac[ ETH_ALEN ];
+       u8 ssid[WLAN_SSID_MAXLEN];
+       u8 peermac[ETH_ALEN];
 };
 
-struct tx_invite_req_info{
+struct tx_invite_req_info {
        u8                      token;
        u8                      benable;
-       u8                      go_ssid[ WLAN_SSID_MAXLEN ];
+       u8                      go_ssid[WLAN_SSID_MAXLEN];
        u8                      ssidlen;
-       u8                      go_bssid[ ETH_ALEN ];
-       u8                      peer_macaddr[ ETH_ALEN ];
+       u8                      go_bssid[ETH_ALEN];
+       u8                      peer_macaddr[ETH_ALEN];
        u8                      operating_ch;   /*      This information will be set by using the p2p_set op_ch =x */
        u8                      peer_ch;                /*      The listen channel for peer P2P device */
 
 };
 
-struct tx_invite_resp_info{
+struct tx_invite_resp_info {
        u8                      token;  /*      Used to record the dialog token of p2p invitation request frame. */
 };
 
-struct tx_provdisc_req_info{
+struct tx_provdisc_req_info {
        u16                             wps_config_method_request;      /*      Used when sending the provisioning request frame */
        u16                             peer_channel_num[2];            /*      The channel number which the receiver stands. */
        struct ndis_802_11_ssid ssid;
-       u8                      peerDevAddr[ ETH_ALEN ];                /*      Peer device address */
-       u8                      peerIFAddr[ ETH_ALEN ];         /*      Peer interface address */
+       u8                      peerDevAddr[ETH_ALEN];          /*      Peer device address */
+       u8                      peerIFAddr[ETH_ALEN];           /*      Peer interface address */
        u8                      benable;                                        /*      This provision discovery request frame is trigger to send or not */
 };
 
-struct rx_provdisc_req_info  /* When peer device issue prov_disc_req first, we should store the following informations */
-       u8                      peerDevAddr[ ETH_ALEN ];                /*      Peer device address */
+struct rx_provdisc_req_info {  /* When peer device issue prov_disc_req first, we should store the following informations */
+       u8                      peerDevAddr[ETH_ALEN];          /*      Peer device address */
        u8                      strconfig_method_desc_of_prov_disc_req[4];      /*      description for the config method located in the provisioning discovery request frame. */
                                                                                                                                        /*      The UI must know this information to know which config method the remote p2p device is requiring. */
 };
 
-struct tx_nego_req_info{
+struct tx_nego_req_info {
        u16                             peer_channel_num[2];            /*      The channel number which the receiver stands. */
-       u8                      peerDevAddr[ ETH_ALEN ];                /*      Peer device address */
+       u8                      peerDevAddr[ETH_ALEN];          /*      Peer device address */
        u8                      benable;                                        /*      This negoitation request frame is trigger to send or not */
 };
 
-struct group_id_info{
-       u8                      go_device_addr[ ETH_ALEN ];     /*      The GO's device address of this P2P group */
-       u8                      ssid[ WLAN_SSID_MAXLEN ];       /*      The SSID of this P2P group */
+struct group_id_info {
+       u8                      go_device_addr[ETH_ALEN];       /*      The GO's device address of this P2P group */
+       u8                      ssid[WLAN_SSID_MAXLEN]; /*      The SSID of this P2P group */
 };
 
-struct scan_limit_info{
+struct scan_limit_info {
        u8                      scan_op_ch_only;                        /*      When this flag is set, the driver should just scan the operation channel */
        u8                      operation_ch[2];                                /*      Store the operation channel of invitation request frame */
 };
 
-struct cfg80211_wifidirect_info{
+struct cfg80211_wifidirect_info {
        _timer                                  remain_on_ch_timer;
        u8                              restore_channel;
        struct ieee80211_channel        remain_on_ch_channel;
@@ -213,7 +213,7 @@ struct cfg80211_wifidirect_info{
        unsigned long last_ro_ch_time; /* this will be updated at the beginning and end of ro_ch */
 };
 
-struct wifidirect_info{
+struct wifidirect_info {
        struct adapter *                        padapter;
        _timer                                  find_phase_timer;
        _timer                                  restore_p2p_state_timer;
@@ -225,7 +225,7 @@ struct wifidirect_info{
        struct tx_provdisc_req_info tx_prov_disc_info;
        struct rx_provdisc_req_info rx_prov_disc_info;
        struct tx_invite_req_info invitereq_info;
-       struct profile_info             profileinfo[ P2P_MAX_PERSISTENT_GROUP_NUM ];    /*      Store the profile information of persistent group */
+       struct profile_info             profileinfo[P2P_MAX_PERSISTENT_GROUP_NUM];      /*      Store the profile information of persistent group */
        struct tx_invite_resp_info inviteresp_info;
        struct tx_nego_req_info nego_req_info;
        struct group_id_info    groupid_info;   /*      Store the group id information when doing the group negotiation handshake. */
@@ -243,17 +243,17 @@ struct wifidirect_info{
        u8                              support_rate[8];
        u8                              p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN];
        u8                              intent;         /*      should only include the intent value. */
-       u8                              p2p_peer_interface_addr[ ETH_ALEN ];
-       u8                              p2p_peer_device_addr[ ETH_ALEN ];
+       u8                              p2p_peer_interface_addr[ETH_ALEN];
+       u8                              p2p_peer_device_addr[ETH_ALEN];
        u8                              peer_intent;    /*      Included the intent value and tie breaker value. */
-       u8                              device_name[ WPS_MAX_DEVICE_NAME_LEN ]; /*      Device name for displaying on searching device screen */
+       u8                              device_name[WPS_MAX_DEVICE_NAME_LEN];   /*      Device name for displaying on searching device screen */
        u8                              device_name_len;
        u8                              profileindex;   /*      Used to point to the index of profileinfo array */
        u8                              peer_operating_ch;
        u8                              find_phase_state_exchange_cnt;
        u16                                     device_password_id_for_nego;    /*      The device password ID for group negotation */
        u8                              negotiation_dialog_token;
-       u8                              nego_ssid[ WLAN_SSID_MAXLEN ];  /*      SSID information for group negotitation */
+       u8                              nego_ssid[WLAN_SSID_MAXLEN];    /*      SSID information for group negotitation */
        u8                              nego_ssidlen;
        u8                              p2p_group_ssid[WLAN_SSID_MAXLEN];
        u8                              p2p_group_ssid_len;
@@ -287,13 +287,13 @@ struct wifidirect_info{
        u8                              driver_interface;                       /*      Indicate DRIVER_WEXT or DRIVER_CFG80211 */
 };
 
-struct tdls_ss_record{ /* signal strength record */
+struct tdls_ss_record {        /* signal strength record */
        u8 macaddr[ETH_ALEN];
        u8 rx_pwd_ba11;
        u8 is_tdls_sta; /*  true: direct link sta, false: else */
 };
 
-struct tdls_info{
+struct tdls_info {
        u8                      ap_prohibited;
        u8                      link_established;
        u8                      sta_cnt;
@@ -489,7 +489,7 @@ int event_thread(void *context);
 extern void rtw_free_network_queue(struct adapter *adapter, u8 isfreeall);
 extern int rtw_init_mlme_priv(struct adapter *adapter);/*  (struct mlme_priv *pmlmepriv); */
 
-extern void rtw_free_mlme_priv (struct mlme_priv *pmlmepriv);
+extern void rtw_free_mlme_priv(struct mlme_priv *pmlmepriv);
 
 
 extern sint rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv);
@@ -526,7 +526,7 @@ static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state)
 {
        pmlmepriv->fw_state |= state;
        /* FOR HW integration */
-       if (_FW_UNDER_SURVEY ==state) {
+       if (_FW_UNDER_SURVEY == state) {
                pmlmepriv->bScanInProcess = true;
        }
 }
@@ -535,7 +535,7 @@ static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, sint state)
 {
        pmlmepriv->fw_state &= ~state;
        /* FOR HW integration */
-       if (_FW_UNDER_SURVEY ==state) {
+       if (_FW_UNDER_SURVEY == state) {
                pmlmepriv->bScanInProcess = false;
        }
 }
index 73e8ec0..6c1ed62 100644 (file)
@@ -182,7 +182,7 @@ typedef enum _RT_CHANNEL_DOMAIN
        /*  Add new channel plan above this line =============== */
        RT_CHANNEL_DOMAIN_MAX,
        RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F,
-}RT_CHANNEL_DOMAIN, *PRT_CHANNEL_DOMAIN;
+} RT_CHANNEL_DOMAIN, *PRT_CHANNEL_DOMAIN;
 
 typedef enum _RT_CHANNEL_DOMAIN_2G
 {
@@ -195,7 +195,7 @@ typedef enum _RT_CHANNEL_DOMAIN_2G
        RT_CHANNEL_DOMAIN_2G_NULL = 0x06,
        /*  Add new channel plan above this line =============== */
        RT_CHANNEL_DOMAIN_2G_MAX,
-}RT_CHANNEL_DOMAIN_2G, *PRT_CHANNEL_DOMAIN_2G;
+} RT_CHANNEL_DOMAIN_2G, *PRT_CHANNEL_DOMAIN_2G;
 
 typedef enum _RT_CHANNEL_DOMAIN_5G
 {
@@ -237,33 +237,33 @@ typedef enum _RT_CHANNEL_DOMAIN_5G
        RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS = 0x21,
        RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS = 0x22,
        RT_CHANNEL_DOMAIN_5G_MAX,
-}RT_CHANNEL_DOMAIN_5G, *PRT_CHANNEL_DOMAIN_5G;
+} RT_CHANNEL_DOMAIN_5G, *PRT_CHANNEL_DOMAIN_5G;
 
-#define rtw_is_channel_plan_valid(chplan) (chplan<RT_CHANNEL_DOMAIN_MAX || chplan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE)
+#define rtw_is_channel_plan_valid(chplan) (chplan < RT_CHANNEL_DOMAIN_MAX || chplan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE)
 
 typedef struct _RT_CHANNEL_PLAN
 {
        unsigned char Channel[MAX_CHANNEL_NUM];
        unsigned char Len;
-}RT_CHANNEL_PLAN, *PRT_CHANNEL_PLAN;
+} RT_CHANNEL_PLAN, *PRT_CHANNEL_PLAN;
 
 typedef struct _RT_CHANNEL_PLAN_2G
 {
        unsigned char Channel[MAX_CHANNEL_NUM_2G];
        unsigned char Len;
-}RT_CHANNEL_PLAN_2G, *PRT_CHANNEL_PLAN_2G;
+} RT_CHANNEL_PLAN_2G, *PRT_CHANNEL_PLAN_2G;
 
 typedef struct _RT_CHANNEL_PLAN_5G
 {
        unsigned char Channel[MAX_CHANNEL_NUM_5G];
        unsigned char Len;
-}RT_CHANNEL_PLAN_5G, *PRT_CHANNEL_PLAN_5G;
+} RT_CHANNEL_PLAN_5G, *PRT_CHANNEL_PLAN_5G;
 
 typedef struct _RT_CHANNEL_PLAN_MAP
 {
        unsigned char Index2G;
        unsigned char Index5G;
-}RT_CHANNEL_PLAN_MAP, *PRT_CHANNEL_PLAN_MAP;
+} RT_CHANNEL_PLAN_MAP, *PRT_CHANNEL_PLAN_MAP;
 
 enum Associated_AP
 {
@@ -299,7 +299,7 @@ typedef enum _HT_IOT_PEER
        HT_IOT_PEER_REALTEK_JAGUAR_BCUTAP = 16,
        HT_IOT_PEER_REALTEK_JAGUAR_CCUTAP = 17,
        HT_IOT_PEER_MAX                                 = 18
-}HT_IOT_PEER_E, *PHTIOT_PEER_E;
+} HT_IOT_PEER_E, *PHTIOT_PEER_E;
 
 
 enum SCAN_STATE
@@ -353,7 +353,7 @@ struct      ss_res
 #define        WIFI_FW_ASSOC_STATE                     0x00002000
 #define        WIFI_FW_ASSOC_SUCCESS           0x00004000
 
-#define        WIFI_FW_LINKING_STATE           (WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE | WIFI_FW_AUTH_SUCCESS |WIFI_FW_ASSOC_STATE)
+#define        WIFI_FW_LINKING_STATE           (WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE | WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE)
 
 struct FW_Sta_Info
 {
@@ -434,7 +434,7 @@ typedef struct _RT_CHANNEL_INFO
 {
        u8              ChannelNum;             /*  The channel number. */
        RT_SCAN_TYPE    ScanType;               /*  Scan type such as passive or active scan. */
-}RT_CHANNEL_INFO, *PRT_CHANNEL_INFO;
+} RT_CHANNEL_INFO, *PRT_CHANNEL_INFO;
 
 int rtw_ch_set_search_ch(RT_CHANNEL_INFO *ch_set, const u32 ch);
 bool rtw_mlme_band_check(struct adapter *adapter, const u32 ch);
@@ -537,7 +537,7 @@ struct mlme_ext_priv
 void init_mlme_default_rate_set(struct adapter *padapter);
 void init_mlme_ext_priv(struct adapter *padapter);
 int init_hw_mlme_ext(struct adapter *padapter);
-void free_mlme_ext_priv (struct mlme_ext_priv *pmlmeext);
+void free_mlme_ext_priv(struct mlme_ext_priv *pmlmeext);
 extern void init_mlme_ext_timer(struct adapter *padapter);
 extern void init_addba_retry_timer(struct adapter *padapter, struct sta_info *psta);
 extern struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv);
@@ -571,7 +571,7 @@ void SelectChannel(struct adapter *padapter, unsigned char channel);
 
 unsigned int decide_wait_for_beacon_timeout(unsigned int bcn_interval);
 
-void read_cam(struct adapter *padapter , u8 entry, u8 *get_key);
+void read_cam(struct adapter *padapter, u8 entry, u8 *get_key);
 
 /* modify HW only */
 void _write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key);
@@ -708,8 +708,8 @@ void linked_status_chk(struct adapter *padapter);
 
 void _linked_info_dump(struct adapter *padapter);
 
-void survey_timer_hdl (struct timer_list *t);
-void link_timer_hdl (struct timer_list *t);
+void survey_timer_hdl(struct timer_list *t);
+void link_timer_hdl(struct timer_list *t);
 void addba_timer_hdl(struct timer_list *t);
 void sa_query_timer_hdl(struct timer_list *t);
 /* void reauth_timer_hdl(struct adapter *padapter); */
@@ -802,8 +802,8 @@ struct C2HEvent_Header
        unsigned int rsvd;
 };
 
-void rtw_dummy_event_callback(struct adapter *adapter , u8 *pbuf);
-void rtw_fwdbg_event_callback(struct adapter *adapter , u8 *pbuf);
+void rtw_dummy_event_callback(struct adapter *adapter, u8 *pbuf);
+void rtw_fwdbg_event_callback(struct adapter *adapter, u8 *pbuf);
 
 enum rtw_c2h_event
 {
@@ -818,10 +818,10 @@ enum rtw_c2h_event
        GEN_EVT_CODE(_Survey),   /*8*/
        GEN_EVT_CODE(_SurveyDone),       /*9*/
 
-       GEN_EVT_CODE(_JoinBss) , /*10*/
+       GEN_EVT_CODE(_JoinBss), /*10*/
        GEN_EVT_CODE(_AddSTA),
        GEN_EVT_CODE(_DelSTA),
-       GEN_EVT_CODE(_AtimDone) ,
+       GEN_EVT_CODE(_AtimDone),
        GEN_EVT_CODE(_TX_Report),
        GEN_EVT_CODE(_CCX_Report),                      /*15*/
        GEN_EVT_CODE(_DTM_Report),
@@ -851,7 +851,7 @@ static struct fwevent wlanevents[] =
        {0, NULL},
        {0, NULL},
        {0, &rtw_survey_event_callback},                /*8*/
-       {sizeof (struct surveydone_event), &rtw_surveydone_event_callback},     /*9*/
+       {sizeof(struct surveydone_event), &rtw_surveydone_event_callback},      /*9*/
 
        {0, &rtw_joinbss_event_callback},               /*10*/
        {sizeof(struct stassoc_event), &rtw_stassoc_event_callback},
index bb3970d..e5a801b 100644 (file)
@@ -154,7 +154,7 @@ typedef struct _MPT_CONTEXT
        u32             mptOutLen;
     u8          mptOutBuf[100];
 
-}MPT_CONTEXT, *PMPT_CONTEXT;
+} MPT_CONTEXT, *PMPT_CONTEXT;
 /* endif */
 
 /* E-Fuse */
@@ -276,7 +276,7 @@ typedef struct _IOCMD_STRUCT_ {
        u8 cmdclass;
        u16 value;
        u8 index;
-}IOCMD_STRUCT;
+} IOCMD_STRUCT;
 
 struct rf_reg_param {
        u32 path;
@@ -315,7 +315,7 @@ extern u8 mpdatarate[NumRates];
 /* MP set force data rate base on the definition. */
 enum MPT_RATE_INDEX {
        /* CCK rate. */
-       MPT_RATE_1M = 0 ,       /* 0 */
+       MPT_RATE_1M = 0       /* 0 */
        MPT_RATE_2M,
        MPT_RATE_55M,
        MPT_RATE_11M,   /* 3 */
@@ -473,9 +473,9 @@ void Hal_SetBandwidth(struct adapter *padapter);
 
 void Hal_SetTxPower(struct adapter *padapter);
 void Hal_SetCarrierSuppressionTx(struct adapter *padapter, u8 bStart);
-void Hal_SetSingleToneTx (struct adapter *padapter , u8 bStart);
-void Hal_SetSingleCarrierTx (struct adapter *padapter, u8 bStart);
-void Hal_SetContinuousTx (struct adapter *padapter, u8 bStart);
+void Hal_SetSingleToneTx(struct adapter *padapter, u8 bStart);
+void Hal_SetSingleCarrierTx(struct adapter *padapter, u8 bStart);
+void Hal_SetContinuousTx(struct adapter *padapter, u8 bStart);
 void Hal_SetBandwidth(struct adapter *padapter);
 
 void Hal_SetDataRate(struct adapter *padapter);
@@ -494,8 +494,8 @@ void Hal_TriggerRFThermalMeter(struct adapter *padapter);
 u8 Hal_ReadRFThermalMeter(struct adapter *padapter);
 void Hal_SetCCKContinuousTx(struct adapter *padapter, u8 bStart);
 void Hal_SetOFDMContinuousTx(struct adapter *padapter, u8 bStart);
-void Hal_ProSetCrystalCap (struct adapter *padapter , u32 CrystalCapVal);
-void MP_PHY_SetRFPathSwitch(struct adapter *padapter , bool bMain);
+void Hal_ProSetCrystalCap(struct adapter *padapter, u32 CrystalCapVal);
+void MP_PHY_SetRFPathSwitch(struct adapter *padapter, bool bMain);
 u32 mpt_ProQueryCalTxPower(struct adapter *padapter, u8 RfPath);
 void MPT_PwrCtlDM(struct adapter *padapter, u32 bstart);
 u8 MptToMgntRate(u32 MptRateIdx);
index 012d8f5..98c3e92 100644 (file)
@@ -187,7 +187,7 @@ struct rx_pkt_attrib        {
 
 
 /* These definition is used for Rx packet reordering. */
-#define SN_LESS(a, b)          (((a-b)&0x800)!= 0)
+#define SN_LESS(a, b)          (((a - b) & 0x800) != 0)
 #define SN_EQUAL(a, b) (a == b)
 /* define REORDER_WIN_SIZE     128 */
 /* define REORDER_ENTRY_NUM    128 */
@@ -369,12 +369,12 @@ struct recv_frame_hdr
 };
 
 
-union recv_frame{
+union recv_frame {
        union{
                struct list_head list;
                struct recv_frame_hdr hdr;
                uint mem[RECVFRAME_HDR_ALIGN>>2];
-       }u;
+       } u;
 
        /* uint mem[MAX_RXSZ>>2]; */
 
@@ -388,8 +388,8 @@ enum RX_PACKET_TYPE {
        C2H_PACKET
 };
 
-extern union recv_frame *_rtw_alloc_recvframe (struct __queue *pfree_recv_queue);  /* get a free recv_frame from pfree_recv_queue */
-extern union recv_frame *rtw_alloc_recvframe (struct __queue *pfree_recv_queue);  /* get a free recv_frame from pfree_recv_queue */
+extern union recv_frame *_rtw_alloc_recvframe(struct __queue *pfree_recv_queue);  /* get a free recv_frame from pfree_recv_queue */
+extern union recv_frame *rtw_alloc_recvframe(struct __queue *pfree_recv_queue);  /* get a free recv_frame from pfree_recv_queue */
 extern int      rtw_free_recvframe(union recv_frame *precvframe, struct __queue *pfree_recv_queue);
 
 #define rtw_dequeue_recvframe(queue) rtw_alloc_recvframe(queue)
@@ -401,7 +401,7 @@ u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter);
 
 sint rtw_enqueue_recvbuf_to_head(struct recv_buf *precvbuf, struct __queue *queue);
 sint rtw_enqueue_recvbuf(struct recv_buf *precvbuf, struct __queue *queue);
-struct recv_buf *rtw_dequeue_recvbuf (struct __queue *queue);
+struct recv_buf *rtw_dequeue_recvbuf(struct __queue *queue);
 
 void rtw_reordering_ctrl_timeout_handler(struct timer_list *t);
 
@@ -444,7 +444,7 @@ static inline u8 *recvframe_pull(union recv_frame *precvframe, sint sz)
                return NULL;
        }
 
-       precvframe->u.hdr.len -=sz;
+       precvframe->u.hdr.len -= sz;
 
        return precvframe->u.hdr.rx_data;
 
@@ -471,7 +471,7 @@ static inline u8 *recvframe_put(union recv_frame *precvframe, sint sz)
                return NULL;
        }
 
-       precvframe->u.hdr.len +=sz;
+       precvframe->u.hdr.len += sz;
 
        return precvframe->u.hdr.rx_tail;
 
@@ -497,7 +497,7 @@ static inline u8 *recvframe_pull_tail(union recv_frame *precvframe, sint sz)
                return NULL;
        }
 
-       precvframe->u.hdr.len -=sz;
+       precvframe->u.hdr.len -= sz;
 
        return precvframe->u.hdr.rx_tail;
 
index bea1844..aa60b6f 100644 (file)
@@ -208,7 +208,7 @@ struct sha256_state {
 };
 
 #define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)\
-do{\
+do {\
        switch (psecuritypriv->dot11AuthAlgrthm)\
        {\
                case dot11AuthAlgrthm_Open:\
@@ -220,18 +220,18 @@ do{\
                        if (bmcst)\
                                encry_algo = (u8)psecuritypriv->dot118021XGrpPrivacy;\
                        else\
-                               encry_algo =(u8) psta->dot118021XPrivacy;\
+                               encry_algo = (u8)psta->dot118021XPrivacy;\
                        break;\
             case dot11AuthAlgrthm_WAPI:\
                     encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;\
                     break;\
-       }\
-}while (0)
+       } \
+} while (0)
 
 #define _AES_IV_LEN_ 8
 
 #define SET_ICE_IV_LEN(iv_len, icv_len, encrypt)\
-do{\
+do {\
        switch (encrypt)\
        {\
                case _WEP40_:\
@@ -255,19 +255,19 @@ do{\
                        iv_len = 0;\
                        icv_len = 0;\
                        break;\
-       }\
-}while (0)
+       } \
+} while (0)
 
 
 #define GET_TKIP_PN(iv, dot11txpn)\
-do{\
-       dot11txpn._byte_.TSC0 =iv[2];\
-       dot11txpn._byte_.TSC1 =iv[0];\
-       dot11txpn._byte_.TSC2 =iv[4];\
-       dot11txpn._byte_.TSC3 =iv[5];\
-       dot11txpn._byte_.TSC4 =iv[6];\
-       dot11txpn._byte_.TSC5 =iv[7];\
-}while (0)
+do {\
+       dot11txpn._byte_.TSC0 = iv[2];\
+       dot11txpn._byte_.TSC1 = iv[0];\
+       dot11txpn._byte_.TSC2 = iv[4];\
+       dot11txpn._byte_.TSC3 = iv[5];\
+       dot11txpn._byte_.TSC4 = iv[6];\
+       dot11txpn._byte_.TSC5 = iv[7];\
+} while (0)
 
 
 #define ROL32(A, n)    (((A) << (n)) | (((A)>>(32-(n)))  & ((1UL << (n)) - 1)))
index ea13960..cd2be00 100644 (file)
 #define HW_QUEUE_ENTRY 8
 
 #define WEP_IV(pattrib_iv, dot11txpn, keyidx)\
-do{\
+do {\
        pattrib_iv[0] = dot11txpn._byte_.TSC0;\
        pattrib_iv[1] = dot11txpn._byte_.TSC1;\
        pattrib_iv[2] = dot11txpn._byte_.TSC2;\
        pattrib_iv[3] = ((keyidx & 0x3)<<6);\
-       dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0: (dot11txpn.val+1);\
-}while (0)
+       dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0 : (dot11txpn.val + 1);\
+} while (0)
 
 
 #define TKIP_IV(pattrib_iv, dot11txpn, keyidx)\
-do{\
+do {\
        pattrib_iv[0] = dot11txpn._byte_.TSC1;\
        pattrib_iv[1] = (dot11txpn._byte_.TSC1 | 0x20) & 0x7f;\
        pattrib_iv[2] = dot11txpn._byte_.TSC0;\
@@ -59,11 +59,11 @@ do{\
        pattrib_iv[5] = dot11txpn._byte_.TSC3;\
        pattrib_iv[6] = dot11txpn._byte_.TSC4;\
        pattrib_iv[7] = dot11txpn._byte_.TSC5;\
-       dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0: (dot11txpn.val+1);\
-}while (0)
+       dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : (dot11txpn.val + 1);\
+} while (0)
 
 #define AES_IV(pattrib_iv, dot11txpn, keyidx)\
-do{\
+do {\
        pattrib_iv[0] = dot11txpn._byte_.TSC0;\
        pattrib_iv[1] = dot11txpn._byte_.TSC1;\
        pattrib_iv[2] = 0;\
@@ -72,8 +72,8 @@ do{\
        pattrib_iv[5] = dot11txpn._byte_.TSC3;\
        pattrib_iv[6] = dot11txpn._byte_.TSC4;\
        pattrib_iv[7] = dot11txpn._byte_.TSC5;\
-       dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0: (dot11txpn.val+1);\
-}while (0)
+       dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 : (dot11txpn.val + 1);\
+} while (0)
 
 
 #define HWXMIT_ENTRY   4
@@ -217,7 +217,7 @@ enum {
        XMITBUF_CMD = 2,
 };
 
-struct  submit_ctx{
+struct  submit_ctx {
        unsigned long submit_time; /* */
        u32 timeout_ms; /* <0: not synchronous, 0: wait forever, >0: up to ms waiting */
        int status; /* status for operation */
@@ -274,7 +274,7 @@ struct xmit_buf
        u8 pg_num;
        u8 agg_num;
 
-#if defined(DBG_XMIT_BUF)|| defined(DBG_XMIT_BUF_EXT)
+#if defined(DBG_XMIT_BUF) || defined(DBG_XMIT_BUF_EXT)
        u8 no;
 #endif
 
@@ -350,7 +350,7 @@ struct      hw_txqueue      {
        sint    ac_tag;
 };
 
-struct agg_pkt_info{
+struct agg_pkt_info {
        u16 offset;
        u16 pkt_len;
 };
@@ -484,7 +484,7 @@ void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry);
 
 
 s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter);
-void _rtw_free_xmit_priv (struct xmit_priv *pxmitpriv);
+void _rtw_free_xmit_priv(struct xmit_priv *pxmitpriv);
 
 
 s32 rtw_alloc_hwxmits(struct adapter *padapter);
index 3acce56..c9aa3b5 100644 (file)
@@ -31,13 +31,13 @@ struct wlan_acl_pool {
        struct __queue  acl_node_q;
 };
 
-typedef struct _RSSI_STA{
+typedef struct _RSSI_STA {
        s32     UndecoratedSmoothedPWDB;
        s32     UndecoratedSmoothedCCK;
        s32     UndecoratedSmoothedOFDM;
        u64     PacketMap;
        u8 ValidBit;
-}RSSI_STA, *PRSSI_STA;
+} RSSI_STA, *PRSSI_STA;
 
 struct stainfo_stats   {
 
@@ -304,7 +304,7 @@ struct sta_info {
 #define STA_RX_PKTS_DIFF_ARG(sta) \
        sta->sta_stats.rx_mgnt_pkts - sta->sta_stats.last_rx_mgnt_pkts \
        , sta->sta_stats.rx_ctrl_pkts - sta->sta_stats.last_rx_ctrl_pkts \
-       , sta->sta_stats.rx_data_pkts -sta->sta_stats.last_rx_data_pkts
+       , sta->sta_stats.rx_data_pkts - sta->sta_stats.last_rx_data_pkts
 
 #define STA_PKTS_FMT "(m:%llu, c:%llu, d:%llu)"
 
@@ -374,7 +374,7 @@ int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta);
 struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset);
 
 extern struct sta_info *rtw_alloc_stainfo(struct       sta_priv *pstapriv, u8 *hwaddr);
-extern u32 rtw_free_stainfo(struct adapter *padapter , struct sta_info *psta);
+extern u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta);
 extern void rtw_free_all_stainfo(struct adapter *padapter);
 extern struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr);
 extern u32 rtw_init_bcmc_stainfo(struct adapter *padapter);
index 2faf837..88a6e98 100644 (file)
@@ -707,7 +707,7 @@ struct HT_caps_element
                        unsigned char ASEL_caps;
                } HT_cap_element;
                unsigned char HT_cap[26];
-       }u;
+       } u;
 } __attribute__ ((packed));
 
 struct HT_info_element
@@ -1102,7 +1102,7 @@ enum P2P_PROTO_WK_ID
        P2P_PRE_TX_PROVDISC_PROCESS_WK = 2,
        P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3,
        P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4,
-       P2P_AP_P2P_CH_SWITCH_PROCESS_WK =5,
+       P2P_AP_P2P_CH_SWITCH_PROCESS_WK = 5,
        P2P_RO_CH_WK = 6,
 };
 
@@ -1126,8 +1126,8 @@ enum P2P_PROTO_WK_ID
 #define        WFD_DEVINFO_PC_TDLS                                     0x0080
 #define        WFD_DEVINFO_HDCP_SUPPORT                        0x0100
 
-#define IP_MCAST_MAC(mac)              ((mac[0]== 0x01) && (mac[1]== 0x00) && (mac[2]== 0x5e))
-#define ICMPV6_MCAST_MAC(mac)  ((mac[0]== 0x33) && (mac[1]== 0x33) && (mac[2]!= 0xff))
+#define IP_MCAST_MAC(mac)              ((mac[0] == 0x01) && (mac[1] == 0x00) && (mac[2] == 0x5e))
+#define ICMPV6_MCAST_MAC(mac)  ((mac[0] == 0x33) && (mac[1] == 0x33) && (mac[2] != 0xff))
 
 /* Regulatroy Domain */
 struct regd_pair_mapping {
index a61412b..e9ff274 100644 (file)
@@ -35,8 +35,8 @@ void rtw_os_xmit_resource_free(struct adapter *padapter, struct xmit_buf *pxmitb
 
 extern uint rtw_remainder_len(struct pkt_file *pfile);
 extern void _rtw_open_pktfile(_pkt *pkt, struct pkt_file *pfile);
-extern uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen);
-extern sint rtw_endofpktfile (struct pkt_file *pfile);
+extern uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen);
+extern sint rtw_endofpktfile(struct pkt_file *pfile);
 
 extern void rtw_os_pkt_complete(struct adapter *padapter, _pkt *pkt);
 extern void rtw_os_xmit_complete(struct adapter *padapter, struct xmit_frame *pxframe);
index 322cabb..1ba85a4 100644 (file)
@@ -254,7 +254,7 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl
 
        /* DBG_8192C("%s\n", __func__); */
 
-       bssinf_len = pnetwork->network.IELength+sizeof (struct ieee80211_hdr_3addr);
+       bssinf_len = pnetwork->network.IELength + sizeof(struct ieee80211_hdr_3addr);
        if (bssinf_len > MAX_BSSINFO_LEN) {
                DBG_871X("%s IE Length too long > %d byte\n", __func__, MAX_BSSINFO_LEN);
                goto exit;
@@ -263,7 +263,7 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl
        {
                u16 wapi_len = 0;
 
-               if (rtw_get_wapi_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &wapi_len)>0)
+               if (rtw_get_wapi_ie(pnetwork->network.IEs, pnetwork->network.IELength, NULL, &wapi_len) > 0)
                {
                        if (wapi_len > 0)
                        {
@@ -286,7 +286,7 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl
 
                wpsie = rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wpsielen);
 
-               if (wpsie && wpsielen>0)
+               if (wpsie && wpsielen > 0)
                        psr = rtw_get_wps_attr_content(wpsie,  wpsielen, WPS_ATTR_SELECTED_REGISTRAR, (u8 *)(&sr), NULL);
 
                if (sr != 0)
@@ -353,7 +353,7 @@ struct cfg80211_bss *rtw_cfg80211_inform_bss(struct adapter *padapter, struct wl
 
 
        pbuf += sizeof(struct ieee80211_hdr_3addr);
-       len = sizeof (struct ieee80211_hdr_3addr);
+       len = sizeof(struct ieee80211_hdr_3addr);
 
        memcpy(pbuf, pnetwork->network.IEs, pnetwork->network.IELength);
        len += pnetwork->network.IELength;
@@ -402,7 +402,7 @@ int rtw_cfg80211_check_bss(struct adapter *padapter)
 
        cfg80211_put_bss(padapter->rtw_wdev->wiphy, bss);
 
-       return  (bss!= NULL);
+       return  (bss != NULL);
 }
 
 void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter)
@@ -424,7 +424,7 @@ void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter)
                struct wlan_bssid_ex  *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network);
                struct wlan_network *scanned = pmlmepriv->cur_network_scanned;
 
-               if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ==true)
+               if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)
                {
 
                        memcpy(&cur_network->network, pnetwork, sizeof(struct wlan_bssid_ex));
@@ -579,7 +579,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
        struct sta_info *psta = NULL, *pbcmc_sta = NULL;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-       struct security_priv* psecuritypriv =&(padapter->securitypriv);
+       struct security_priv* psecuritypriv =  &(padapter->securitypriv);
        struct sta_priv *pstapriv = &padapter->stapriv;
 
        DBG_8192C("%s\n", __func__);
@@ -633,7 +633,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
 
                DBG_8192C("r871x_set_encryption, wep_key_idx =%d, len =%d\n", wep_key_idx, wep_key_len);
 
-               if ((wep_key_idx >= WEP_KEYS) || (wep_key_len<= 0))
+               if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0))
                {
                        ret = -EINVAL;
                        goto exit;
@@ -673,7 +673,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
        }
 
 
-       if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) /* group key */ 
+       if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) /* group key */
        {
                if (param->u.crypt.set_tx == 0) /* group key */
                {
@@ -681,7 +681,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
                        {
                                DBG_8192C("%s, set group_key, WEP\n", __func__);
 
-                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
                                if (param->u.crypt.key_len == 13)
@@ -696,7 +696,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
 
                                psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
 
-                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
                                /* set mic key */
@@ -712,7 +712,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
 
                                psecuritypriv->dot118021XGrpPrivacy = _AES_;
 
-                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
                        }
                        else
                        {
@@ -729,7 +729,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
 
                        rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
 
-                       pbcmc_sta =rtw_get_bcmc_stainfo(padapter);
+                       pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
                        if (pbcmc_sta)
                        {
                                pbcmc_sta->ieee8021x_blocked = false;
@@ -748,7 +748,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
                {
                        if (param->u.crypt.set_tx == 1) /* pairwise key */
                        {
-                               memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                               memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                if (strcmp(param->u.crypt.alg, "WEP") == 0)
                                {
@@ -799,7 +799,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
                        {
                                if (strcmp(param->u.crypt.alg, "WEP") == 0)
                                {
-                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                        psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
                                        if (param->u.crypt.key_len == 13)
@@ -811,7 +811,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
                                {
                                        psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
 
-                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                        /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
                                        /* set mic key */
@@ -825,7 +825,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
                                {
                                        psecuritypriv->dot118021XGrpPrivacy = _AES_;
 
-                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
                                }
                                else
                                {
@@ -840,7 +840,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa
 
                                rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
 
-                               pbcmc_sta =rtw_get_bcmc_stainfo(padapter);
+                               pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
                                if (pbcmc_sta)
                                {
                                        pbcmc_sta->ieee8021x_blocked = false;
@@ -940,7 +940,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
 
        if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) /*  802_1x */
        {
-               struct sta_info * psta,*pbcmc_sta;
+               struct sta_info * psta, *pbcmc_sta;
                struct sta_priv * pstapriv = &padapter->stapriv;
 
                /* DBG_8192C("%s, : dot11AuthAlgrthm == dot11AuthAlgrthm_8021X\n", __func__); */
@@ -959,7 +959,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
                                        psta->ieee8021x_blocked = false;
 
 
-                               if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)||
+                               if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
                                                (padapter->securitypriv.ndisencryptstatus ==  Ndis802_11Encryption3Enabled))
                                {
                                        psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
@@ -970,7 +970,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
 
                                        DBG_8192C("%s, : param->u.crypt.set_tx == 1\n", __func__);
 
-                                       memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                       memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                        if (strcmp(param->u.crypt.alg, "TKIP") == 0)/* set mic key */
                                        {
@@ -978,7 +978,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
                                                memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
                                                memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
 
-                                               padapter->securitypriv.busetkipkey =false;
+                                               padapter->securitypriv.busetkipkey = false;
                                                /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */
                                        }
 
@@ -991,21 +991,21 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
                                {
                                        if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0)
                                        {
-                                               memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
-                                               memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[16]), 8);
-                                               memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[24]), 8);
+                                               memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
+                                               memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+                                               memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
                                                padapter->securitypriv.binstallGrpkey = true;
                                                /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */
                                                DBG_871X(" ~~~~set sta key:groupkey\n");
 
                                                padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
-                                               rtw_set_key(padapter,&padapter->securitypriv, param->u.crypt.idx, 1, true);
+                                               rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, true);
                                        }
                                        else if (strcmp(param->u.crypt.alg, "BIP") == 0)
                                        {
                                                /* DBG_871X("BIP key_len =%d , index =%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */
                                                /* save the IGTK key, length 16 bytes */
-                                               memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                               memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
                                                /*DBG_871X("IGTK key below:\n");
                                                for (no = 0;no<16;no++)
                                                        printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]);
@@ -1017,7 +1017,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
                                }
                        }
 
-                       pbcmc_sta =rtw_get_bcmc_stainfo(padapter);
+                       pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
                        if (pbcmc_sta == NULL)
                        {
                                /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */
@@ -1028,7 +1028,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param
                                if (strcmp(param->u.crypt.alg, "none") != 0)
                                        pbcmc_sta->ieee8021x_blocked = false;
 
-                               if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)||
+                               if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
                                                (padapter->securitypriv.ndisencryptstatus ==  Ndis802_11Encryption3Enabled))
                                {
                                        pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
@@ -1270,8 +1270,8 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy,
 
        /* for Ad-Hoc/AP mode */
        if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)
                      ||check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)
                      ||check_fwstate(pmlmepriv, WIFI_AP_STATE))
|| check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)
|| check_fwstate(pmlmepriv, WIFI_AP_STATE))
                && check_fwstate(pmlmepriv, _FW_LINKED)
        )
        {
@@ -1346,7 +1346,7 @@ static int cfg80211_rtw_change_iface(struct wiphy *wiphy,
 
        rtw_wdev->iftype = type;
 
-       if (rtw_set_802_11_infrastructure_mode(padapter, networkType) ==false)
+       if (rtw_set_802_11_infrastructure_mode(padapter, networkType) == false)
        {
                rtw_wdev->iftype = old_type;
                ret = -EPERM;
@@ -1464,7 +1464,7 @@ static int rtw_cfg80211_set_probe_req_wpsp2pie(struct adapter *padapter, char *b
        DBG_8192C("%s, ielen =%d\n", __func__, len);
 #endif
 
-       if (len>0)
+       if (len > 0)
        {
                if ((wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen)))
                {
@@ -1503,8 +1503,8 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy
        int ret = 0;
        struct ndis_802_11_ssid *ssid = NULL;
        struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
-       u8 survey_times =3;
-       u8 survey_times_for_one_ch =6;
+       u8 survey_times = 3;
+       u8 survey_times_for_one_ch = 6;
        struct cfg80211_ssid *ssids = request->ssids;
        int j = 0;
        bool need_indicate_scan_done = false;
@@ -1556,7 +1556,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy
                goto check_need_indicate_scan_done;
        }
 
-       if (request->ie && request->ie_len>0)
+       if (request->ie && request->ie_len > 0)
        {
                rtw_cfg80211_set_probe_req_wpsp2pie(padapter, (u8 *)request->ie, request->ie_len);
        }
@@ -1610,7 +1610,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy
 
        /* parsing channels, n_channels */
        memset(ch, 0, sizeof(struct rtw_ieee80211_channel)*RTW_CHANNEL_SCAN_AMOUNT);
-       for (i = 0;i<request->n_channels && i<RTW_CHANNEL_SCAN_AMOUNT;i++) {
+       for (i = 0; i < request->n_channels && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
                #ifdef DEBUG_CFG80211
                DBG_871X(FUNC_ADPT_FMT CHAN_FMT"\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(request->channels[i]));
                #endif
@@ -1620,12 +1620,12 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy
 
        spin_lock_bh(&pmlmepriv->lock);
        if (request->n_channels == 1) {
-               for (i = 1;i<survey_times_for_one_ch;i++)
+               for (i = 1; i < survey_times_for_one_ch; i++)
                        memcpy(&ch[i], &ch[0], sizeof(struct rtw_ieee80211_channel));
                _status = rtw_sitesurvey_cmd(padapter, ssid, RTW_SSID_SCAN_AMOUNT, ch, survey_times_for_one_ch);
        } else if (request->n_channels <= 4) {
-               for (j =request->n_channels-1;j>= 0;j--)
-                       for (i = 0;i<survey_times;i++)
+               for (j = request->n_channels - 1; j >= 0; j--)
+                       for (i = 0; i < survey_times; i++)
                {
                        memcpy(&ch[j*survey_times+i], &ch[j], sizeof(struct rtw_ieee80211_channel));
                }
@@ -1699,7 +1699,7 @@ static int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv,
 
                psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
 
-               if (psecuritypriv->ndisauthtype>Ndis802_11AuthModeWPA)
+               if (psecuritypriv->ndisauthtype > Ndis802_11AuthModeWPA)
                        psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
 
                break;
@@ -1767,7 +1767,7 @@ static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, u32 ciph
                psecuritypriv->ndisencryptstatus = ndisencryptstatus;
 
                /* if (psecuritypriv->dot11PrivacyAlgrthm >= _AES_) */
-               /*      psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK; */
+               /*      psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK; */
        }
 
        return 0;
@@ -1799,7 +1799,7 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
        int wpa_ielen = 0;
        int wpa2_ielen = 0;
        u8 *pwpa, *pwpa2;
-       u8 null_addr[]= {0, 0, 0, 0, 0, 0};
+       u8 null_addr[] = {0, 0, 0, 0, 0, 0};
 
        if (pie == NULL || !ielen) {
                /* Treat this as normal case, but need to clear WIFI_UNDER_WPS */
@@ -1818,13 +1818,13 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
                goto exit;
        }
 
-       memcpy(buf, pie , ielen);
+       memcpy(buf, pie, ielen);
 
        /* dump */
        {
                int i;
                DBG_8192C("set wpa_ie(length:%zu):\n", ielen);
-               for (i = 0;i<ielen;i =i+8)
+               for (i = 0; i < ielen; i = i + 8)
                        DBG_8192C("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]);
        }
 
@@ -1835,12 +1835,12 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
        }
 
        pwpa = rtw_get_wpa_ie(buf, &wpa_ielen, ielen);
-       if (pwpa && wpa_ielen>0)
+       if (pwpa && wpa_ielen > 0)
        {
                if (rtw_parse_wpa_ie(pwpa, wpa_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS)
                {
                        padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
-                       padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPAPSK;
+                       padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK;
                        memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], wpa_ielen+2);
 
                        DBG_8192C("got wpa_ie, wpa_ielen:%u\n", wpa_ielen);
@@ -1848,12 +1848,12 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
        }
 
        pwpa2 = rtw_get_wpa2_ie(buf, &wpa2_ielen, ielen);
-       if (pwpa2 && wpa2_ielen>0)
+       if (pwpa2 && wpa2_ielen > 0)
        {
                if (rtw_parse_wpa2_ie(pwpa2, wpa2_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS)
                {
                        padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
-                       padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPA2PSK;
+                       padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK;
                        memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], wpa2_ielen+2);
 
                        DBG_8192C("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen);
@@ -1873,7 +1873,7 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
        {
                case WPA_CIPHER_NONE:
                        padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
-                       padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled;
+                       padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
                        break;
                case WPA_CIPHER_WEP40:
                        padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
@@ -1897,7 +1897,7 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
        {
                case WPA_CIPHER_NONE:
                        padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
-                       padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled;
+                       padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
                        break;
                case WPA_CIPHER_WEP40:
                        padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
@@ -1924,7 +1924,7 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel
                wps_ie = rtw_get_wps_ie(buf, ielen, NULL, &wps_ielen);
                if (wps_ie && wps_ielen > 0) {
                        DBG_8192C("got wps_ie, wps_ielen:%u\n", wps_ielen);
-                       padapter->securitypriv.wps_ie_len = wps_ielen<MAX_WPS_IE_LEN?wps_ielen:MAX_WPS_IE_LEN;
+                       padapter->securitypriv.wps_ie_len = wps_ielen < MAX_WPS_IE_LEN ? wps_ielen : MAX_WPS_IE_LEN;
                        memcpy(padapter->securitypriv.wps_ie, wps_ie, padapter->securitypriv.wps_ie_len);
                        set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
                } else {
@@ -2027,7 +2027,7 @@ static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
 
                rtw_wdev->iftype = NL80211_IFTYPE_STATION;
 
-               if (rtw_set_802_11_infrastructure_mode(padapter, Ndis802_11Infrastructure) ==false)
+               if (rtw_set_802_11_infrastructure_mode(padapter, Ndis802_11Infrastructure) == false)
                {
                        rtw_wdev->iftype = old_type;
                        ret = -EPERM;
@@ -2185,7 +2185,7 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev,
 
                if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL)
                {
-                       ret = -EOPNOTSUPP ;
+                       ret = -EOPNOTSUPP;
                }
 
                kfree(pwep);
@@ -2301,7 +2301,7 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy,
        u8 index, blInserted = false;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(ndev);
        struct security_priv *psecuritypriv = &padapter->securitypriv;
-       u8 strZeroMacAddress[ ETH_ALEN ] = { 0x00 };
+       u8 strZeroMacAddress[ETH_ALEN] = { 0x00 };
 
        DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
 
@@ -2313,7 +2313,7 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy,
        blInserted = false;
 
        /* overwrite PMKID */
-       for (index = 0 ; index<NUM_PMKID_CACHE; index++)
+       for (index = 0 ; index < NUM_PMKID_CACHE; index++)
        {
                if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN))
                { /*  BSSID is matched, the same AP => rewrite with new PMKID. */
@@ -2337,7 +2337,7 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy,
                memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, (u8 *)pmksa->pmkid, WLAN_PMKID_LEN);
 
                psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true;
-               psecuritypriv->PMKIDIndex++ ;
+               psecuritypriv->PMKIDIndex++;
                if (psecuritypriv->PMKIDIndex == 16)
                {
                        psecuritypriv->PMKIDIndex = 0;
@@ -2357,7 +2357,7 @@ static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy,
 
        DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
 
-       for (index = 0 ; index<NUM_PMKID_CACHE; index++)
+       for (index = 0 ; index < NUM_PMKID_CACHE; index++)
        {
                if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN))
                { /*  BSSID is matched, the same AP => Remove this PMKID information and reset it. */
@@ -2387,7 +2387,7 @@ static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy,
 
        DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
 
-       memset(&psecuritypriv->PMKIDList[ 0 ], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+       memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
        psecuritypriv->PMKIDIndex = 0;
 
        return 0;
@@ -2575,7 +2575,7 @@ static const struct net_device_ops rtw_cfg80211_monitor_if_ops = {
        .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)
+static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, struct net_device **ndev)
 {
        int ret = 0;
        struct net_device* mon_ndev = NULL;
@@ -2734,7 +2734,7 @@ static int rtw_add_beacon(struct adapter *adapter, const u8 *head, size_t head_l
        if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
                return -EINVAL;
 
-       if (head_len<24)
+       if (head_len < 24)
                return -EINVAL;
 
        pbuf = rtw_zmalloc(head_len+tail_len);
@@ -3276,7 +3276,7 @@ static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, enum
 
                ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7);
        }
-       else if ((rf_type == RF_1T2R) || (rf_type ==RF_2T2R))
+       else if ((rf_type == RF_1T2R) || (rf_type == RF_2T2R))
        {
                ht_cap->mcs.rx_mask[0] = 0xFF;
                ht_cap->mcs.rx_mask[1] = 0xFF;
index 9b9038e..5059b87 100644 (file)
@@ -59,7 +59,7 @@ void rtw_indicate_wx_assoc_event(struct adapter *padapter)
 
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
 
-       if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ==true)
+       if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)
                memcpy(wrqu.ap_addr.sa_data, pnetwork->MacAddress, ETH_ALEN);
        else
                memcpy(wrqu.ap_addr.sa_data, pmlmepriv->cur_network.network.MacAddress, ETH_ALEN);
@@ -86,11 +86,11 @@ static char *translate_scan(struct adapter *padapter,
        u32 ht_ielen = 0;
        char *custom = NULL;
        char *p;
-       u16 max_rate = 0, rate, ht_cap =false, vht_cap = false;
+       u16 max_rate = 0, rate, ht_cap = false, vht_cap = false;
        u32 i = 0;
        u8 bw_40MHz = 0, short_GI = 0;
        u16 mcs_rate = 0, vht_data_rate = 0;
-       u8 ie_offset = (pnetwork->network.Reserved[0] == 2? 0:12);
+       u8 ie_offset = (pnetwork->network.Reserved[0] == 2 ? 0 : 12);
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
        u8 ss, sq;
 
@@ -113,11 +113,11 @@ static char *translate_scan(struct adapter *padapter,
        } else {
                p = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength-12);
        }
-       if (p && ht_ielen>0) {
+       if (p && ht_ielen > 0) {
                struct rtw_ieee80211_ht_cap *pht_capie;
                ht_cap = true;
                pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2);
-               memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2);
+               memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
                bw_40MHz = (le16_to_cpu(pht_capie->cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
                short_GI = (le16_to_cpu(pht_capie->cap_info) & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) ? 1 : 0;
        }
@@ -163,7 +163,7 @@ static char *translate_scan(struct adapter *padapter,
                cap = le16_to_cpu(le_tmp);
        }
 
-       if (cap & (WLAN_CAPABILITY_IBSS |WLAN_CAPABILITY_BSS)) {
+       if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) {
                if (cap & WLAN_CAPABILITY_BSS)
                        iwe.u.mode = IW_MODE_MASTER;
                else
@@ -172,7 +172,7 @@ static char *translate_scan(struct adapter *padapter,
                start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);
        }
 
-       if (pnetwork->network.Configuration.DSConfig<1 /*|| pnetwork->network.Configuration.DSConfig>14*/)
+       if (pnetwork->network.Configuration.DSConfig < 1 /*|| pnetwork->network.Configuration.DSConfig > 14*/)
                pnetwork->network.Configuration.DSConfig = 1;
 
         /* Add frequency/channel */
@@ -197,12 +197,12 @@ static char *translate_scan(struct adapter *padapter,
        if (!custom)
                return start;
        p = custom;
-       p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
-       while (pnetwork->network.SupportedRates[i]!= 0) {
+       p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
+       while (pnetwork->network.SupportedRates[i] != 0) {
                rate = pnetwork->network.SupportedRates[i]&0x7F;
                if (rate > max_rate)
                        max_rate = rate;
-               p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+               p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
                              "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
                i++;
        }
@@ -239,7 +239,7 @@ static char *translate_scan(struct adapter *padapter,
                if (!buf)
                        return start;
                if (wpa_len > 0) {
-                       p =buf;
+                       p = buf;
                        p += sprintf(p, "wpa_ie =");
                        for (i = 0; i < wpa_len; i++)
                                p += sprintf(p, "%02x", wpa_ie[i]);
@@ -258,7 +258,7 @@ static char *translate_scan(struct adapter *padapter,
                        start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 
                        memset(&iwe, 0, sizeof(iwe));
-                       iwe.cmd =IWEVGENIE;
+                       iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = wpa_len;
                        start = iwe_stream_add_point(info, start, stop, &iwe, wpa_ie);
                }
@@ -274,7 +274,7 @@ static char *translate_scan(struct adapter *padapter,
                        start = iwe_stream_add_point(info, start, stop, &iwe, buf);
 
                        memset(&iwe, 0, sizeof(iwe));
-                       iwe.cmd =IWEVGENIE;
+                       iwe.cmd = IWEVGENIE;
                        iwe.u.data.length = rsn_len;
                        start = iwe_stream_add_point(info, start, stop, &iwe, rsn_ie);
                }
@@ -298,13 +298,13 @@ static char *translate_scan(struct adapter *padapter,
                }
 
                while (cnt < total_ielen) {
-                       if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen>2)) {
+                       if (rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen > 2)) {
                                wpsie_ptr = &ie_ptr[cnt];
-                               iwe.cmd =IWEVGENIE;
+                               iwe.cmd = IWEVGENIE;
                                iwe.u.data.length = (u16)wps_ielen;
                                start = iwe_stream_add_point(info, start, stop, &iwe, wpsie_ptr);
                        }
-                       cnt+=ie_ptr[cnt+1]+2; /* goto next */
+                       cnt += ie_ptr[cnt + 1] + 2; /* goto next */
                }
        }
 
@@ -352,8 +352,8 @@ static char *translate_scan(struct adapter *padapter,
        #if defined(CONFIG_SIGNAL_DISPLAY_DBM) && defined(CONFIG_BACKGROUND_NOISE_MONITOR)
        {
                s16 tmp_noise = 0;
-               rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&(pnetwork->network.Configuration.DSConfig), &(tmp_noise));
-               iwe.u.qual.noise = tmp_noise ;
+               rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &(pnetwork->network.Configuration.DSConfig), &(tmp_noise));
+               iwe.u.qual.noise = tmp_noise;
        }
        #else
        iwe.u.qual.noise = 0; /*  noise level */
@@ -500,7 +500,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
                        DBG_871X("wep, set_tx = 1\n");
 
                        if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL)
-                               ret = -EOPNOTSUPP ;
+                               ret = -EOPNOTSUPP;
                } else {
                        DBG_871X("wep, set_tx = 0\n");
 
@@ -508,12 +508,12 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
                        /* psecuritypriv->dot11PrivacyKeyIndex =keyid", but can rtw_set_key to fw/cam */
 
                        if (wep_key_idx >= WEP_KEYS) {
-                               ret = -EOPNOTSUPP ;
+                               ret = -EOPNOTSUPP;
                                goto exit;
                        }
 
                        memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
-                       psecuritypriv->dot11DefKeylen[wep_key_idx]=pwep->KeyLength;
+                       psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
                        rtw_set_key(padapter, psecuritypriv, wep_key_idx, 0, true);
                }
 
@@ -533,20 +533,20 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
                                if (strcmp(param->u.crypt.alg, "none") != 0)
                                        psta->ieee8021x_blocked = false;
 
-                               if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)||
+                               if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
                                                (padapter->securitypriv.ndisencryptstatus ==  Ndis802_11Encryption3Enabled)) {
                                        psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
                                }
 
                                if (param->u.crypt.set_tx == 1) { /* pairwise key */
-                                       memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                       memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                        if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */
                                                /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */
                                                memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
                                                memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);
 
-                                               padapter->securitypriv.busetkipkey =false;
+                                               padapter->securitypriv.busetkipkey = false;
                                                /* _set_timer(&padapter->securitypriv.tkip_timer, 50); */
                                        }
 
@@ -556,11 +556,11 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
                                        rtw_setstakey_cmd(padapter, psta, true, true);
                                } else { /* group key */
                                        if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) {
-                                               memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                               memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
                                                /* only TKIP group key need to install this */
                                                if (param->u.crypt.key_len > 16) {
-                                                       memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[16]), 8);
-                                                       memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[24]), 8);
+                                                       memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
+                                                       memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);
                                                }
                                                padapter->securitypriv.binstallGrpkey = true;
                                                /* DEBUG_ERR((" param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */
@@ -568,11 +568,11 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
 
                                                padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
 
-                                               rtw_set_key(padapter,&padapter->securitypriv, param->u.crypt.idx, 1, true);
+                                               rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, true);
                                        } else if (strcmp(param->u.crypt.alg, "BIP") == 0) {
                                                /* printk("BIP key_len =%d , index =%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx); */
                                                /* save the IGTK key, length 16 bytes */
-                                               memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                               memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
                                                /*printk("IGTK key below:\n");
                                                for (no = 0;no<16;no++)
                                                        printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]);
@@ -584,7 +584,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
                                }
                        }
 
-                       pbcmc_sta =rtw_get_bcmc_stainfo(padapter);
+                       pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
                        if (pbcmc_sta == NULL) {
                                /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */
                        } else {
@@ -592,7 +592,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param,
                                if (strcmp(param->u.crypt.alg, "none") != 0)
                                        pbcmc_sta->ieee8021x_blocked = false;
 
-                               if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)||
+                               if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) ||
                                                (padapter->securitypriv.ndisencryptstatus ==  Ndis802_11Encryption3Enabled)) {
                                        pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
                                }
@@ -613,7 +613,7 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
        u8 *buf = NULL;
        int group_cipher = 0, pairwise_cipher = 0;
        int ret = 0;
-       u8 null_addr[]= {0, 0, 0, 0, 0, 0};
+       u8 null_addr[] = {0, 0, 0, 0, 0, 0};
 
        if ((ielen > MAX_WPA_IE_LEN) || (pie == NULL)) {
                _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
@@ -630,13 +630,13 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
                        goto exit;
                }
 
-               memcpy(buf, pie , ielen);
+               memcpy(buf, pie, ielen);
 
                /* dump */
                {
                        int i;
                        DBG_871X("\n wpa_ie(length:%d):\n", ielen);
-                       for (i = 0;i<ielen;i =i+8)
+                       for (i = 0; i < ielen; i = i + 8)
                                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]);
                }
 
@@ -648,13 +648,13 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
 
                if (rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
                        padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
-                       padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPAPSK;
+                       padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK;
                        memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
                }
 
                if (rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
                        padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
-                       padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeWPA2PSK;
+                       padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK;
                        memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);
                }
 
@@ -666,7 +666,7 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
                switch (group_cipher) {
                        case WPA_CIPHER_NONE:
                                padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
-                               padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled;
+                               padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
                                break;
                        case WPA_CIPHER_WEP40:
                                padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
@@ -689,7 +689,7 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
                switch (pairwise_cipher) {
                        case WPA_CIPHER_NONE:
                                padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
-                               padapter->securitypriv.ndisencryptstatus =Ndis802_11EncryptionDisabled;
+                               padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
                                break;
                        case WPA_CIPHER_WEP40:
                                padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
@@ -712,7 +712,7 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie
                _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
                {/* set wps_ie */
                        u16 cnt = 0;
-                       u8 eid, wps_oui[4]={0x0, 0x50, 0xf2, 0x04};
+                       u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
 
                        while (cnt < ielen) {
                                eid = buf[cnt];
@@ -762,7 +762,7 @@ static int rtw_wx_get_name(struct net_device *dev,
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        u32 ht_ielen = 0;
        char *p;
-       u8 ht_cap =false, vht_cap =false;
+       u8 ht_cap = false, vht_cap = false;
        struct  mlme_priv *pmlmepriv = &(padapter->mlmepriv);
        struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
        NDIS_802_11_RATES_EX* prates = NULL;
@@ -772,7 +772,7 @@ static int rtw_wx_get_name(struct net_device *dev,
        if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true) {
                /* parsing HT_CAP_IE */
                p = rtw_get_ie(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pcur_bss->IELength-12);
-               if (p && ht_ielen>0)
+               if (p && ht_ielen > 0)
                        ht_cap = true;
 
                prates = &pcur_bss->SupportedRates;
@@ -846,7 +846,7 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
                             union iwreq_data *wrqu, char *b)
 {
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-       enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType ;
+       enum NDIS_802_11_NETWORK_INFRASTRUCTURE networkType;
        int ret = 0;
 
        if (_FAIL == rtw_pwr_wakeup(padapter)) {
@@ -878,7 +878,7 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
                        DBG_871X("set_mode = IW_MODE_INFRA\n");
                        break;
 
-               default :
+               default:
                        ret = -EINVAL;
                        RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("\n Mode: %s is not supported \n", iw_operation_mode[wrqu->mode]));
                        goto exit;
@@ -895,7 +895,7 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a,
        }
 */
 
-       if (rtw_set_802_11_infrastructure_mode(padapter, networkType) ==false) {
+       if (rtw_set_802_11_infrastructure_mode(padapter, networkType) == false) {
 
                ret = -EPERM;
                goto exit;
@@ -939,8 +939,8 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
        int         intReturn = false;
        struct security_priv *psecuritypriv = &padapter->securitypriv;
         struct iw_pmksa*  pPMK = (struct iw_pmksa *)extra;
-        u8     strZeroMacAddress[ ETH_ALEN ] = { 0x00 };
-        u8     strIssueBssid[ ETH_ALEN ] = { 0x00 };
+        u8     strZeroMacAddress[ETH_ALEN] = { 0x00 };
+        u8     strIssueBssid[ETH_ALEN] = { 0x00 };
 
        /*
         There are the BSSID information in the bssid.sa_data array.
@@ -960,13 +960,13 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
                blInserted = false;
 
                /* overwrite PMKID */
-               for (j = 0 ; j<NUM_PMKID_CACHE; j++) {
+               for (j = 0; j < NUM_PMKID_CACHE; j++) {
                        if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) {
                                /*  BSSID is matched, the same AP => rewrite with new PMKID. */
                                 DBG_871X("[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n");
 
                                memcpy(psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, IW_PMKID_LEN);
-                                psecuritypriv->PMKIDList[ j ].bUsed = true;
+                                psecuritypriv->PMKIDList[j].bUsed = true;
                                psecuritypriv->PMKIDIndex = j+1;
                                blInserted = true;
                                break;
@@ -981,25 +981,25 @@ static int rtw_wx_set_pmkid(struct net_device *dev,
                    memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN);
                    memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, IW_PMKID_LEN);
 
-                    psecuritypriv->PMKIDList[ psecuritypriv->PMKIDIndex ].bUsed = true;
-                   psecuritypriv->PMKIDIndex++ ;
+                    psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true;
+                   psecuritypriv->PMKIDIndex++;
                    if (psecuritypriv->PMKIDIndex == 16)
                        psecuritypriv->PMKIDIndex = 0;
                }
         } else if (pPMK->cmd == IW_PMKSA_REMOVE) {
                 DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n");
                 intReturn = true;
-               for (j = 0 ; j<NUM_PMKID_CACHE; j++) {
+               for (j = 0; j < NUM_PMKID_CACHE; j++) {
                        if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) {
                                /*  BSSID is matched, the same AP => Remove this PMKID information and reset it. */
                                 eth_zero_addr(psecuritypriv->PMKIDList[j].Bssid);
-                                psecuritypriv->PMKIDList[ j ].bUsed = false;
+                                psecuritypriv->PMKIDList[j].bUsed = false;
                                break;
                        }
                }
         } else if (pPMK->cmd == IW_PMKSA_FLUSH) {
             DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n");
-            memset(&psecuritypriv->PMKIDList[ 0 ], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+            memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
             psecuritypriv->PMKIDIndex = 0;
             intReturn = true;
         }
@@ -1093,7 +1093,7 @@ static int rtw_wx_get_range(struct net_device *dev,
 /*  Commented by Albert 2009/10/13 */
 /*  The following code will proivde the security capability to network manager. */
 /*  If the driver doesn't provide this capability to network manager, */
-/*  the WPA/WPA2 routers can't be choosen in the network manager. */
+/*  the WPA/WPA2 routers can't be chosen in the network manager. */
 
 /*
 #define IW_SCAN_CAPA_NONE              0x00
@@ -1106,11 +1106,11 @@ static int rtw_wx_get_range(struct net_device *dev,
 #define IW_SCAN_CAPA_TIME              0x40
 */
 
-       range->enc_capa = IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2|
-                         IW_ENC_CAPA_CIPHER_TKIP|IW_ENC_CAPA_CIPHER_CCMP;
+       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+                         IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
-       range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE |IW_SCAN_CAPA_BSSID|
-                                       IW_SCAN_CAPA_CHANNEL|IW_SCAN_CAPA_MODE|IW_SCAN_CAPA_RATE;
+       range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE | IW_SCAN_CAPA_BSSID |
+                                       IW_SCAN_CAPA_CHANNEL | IW_SCAN_CAPA_MODE | IW_SCAN_CAPA_RATE;
 
        return 0;
 }
@@ -1287,7 +1287,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
                goto exit;
        }
 
-       if (!padapter->hw_init_completed ) {
+       if (!padapter->hw_init_completed) {
                ret = -1;
                goto exit;
        }
@@ -1330,7 +1330,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
 
        } else if (wrqu->data.length >= WEXT_CSCAN_HEADER_SIZE
                && !memcmp(extra, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE)) {
-               int len = wrqu->data.length -WEXT_CSCAN_HEADER_SIZE;
+               int len = wrqu->data.length - WEXT_CSCAN_HEADER_SIZE;
                char *pos = extra+WEXT_CSCAN_HEADER_SIZE;
                char section;
                char sec_len;
@@ -1339,7 +1339,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
                /* DBG_871X("%s COMBO_SCAN header is recognized\n", __func__); */
 
                while (len >= 1) {
-                       section = *(pos++); len-= 1;
+                       section = *(pos++); len -= 1;
 
                        switch (section) {
                                case WEXT_CSCAN_SSID_SECTION:
@@ -1349,9 +1349,9 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
                                                break;
                                        }
 
-                                       sec_len = *(pos++); len-= 1;
+                                       sec_len = *(pos++); len -= 1;
 
-                                       if (sec_len>0 && sec_len<=len) {
+                                       if (sec_len > 0 && sec_len <= len) {
                                                ssid[ssid_index].SsidLength = sec_len;
                                                memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength);
                                                /* DBG_871X("%s COMBO_SCAN with specific ssid:%s, %d\n", __func__ */
@@ -1359,29 +1359,29 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
                                                ssid_index++;
                                        }
 
-                                       pos+=sec_len; len-=sec_len;
+                                       pos += sec_len; len -= sec_len;
                                        break;
 
 
                                case WEXT_CSCAN_CHANNEL_SECTION:
                                        /* DBG_871X("WEXT_CSCAN_CHANNEL_SECTION\n"); */
-                                       pos+= 1; len-= 1;
+                                       pos += 1; len -= 1;
                                        break;
                                case WEXT_CSCAN_ACTV_DWELL_SECTION:
                                        /* DBG_871X("WEXT_CSCAN_ACTV_DWELL_SECTION\n"); */
-                                       pos+=2; len-=2;
+                                       pos += 2; len -= 2;
                                        break;
                                case WEXT_CSCAN_PASV_DWELL_SECTION:
                                        /* DBG_871X("WEXT_CSCAN_PASV_DWELL_SECTION\n"); */
-                                       pos+=2; len-=2;
+                                       pos += 2; len -= 2;
                                        break;
                                case WEXT_CSCAN_HOME_DWELL_SECTION:
                                        /* DBG_871X("WEXT_CSCAN_HOME_DWELL_SECTION\n"); */
-                                       pos+=2; len-=2;
+                                       pos += 2; len -= 2;
                                        break;
                                case WEXT_CSCAN_TYPE_SECTION:
                                        /* DBG_871X("WEXT_CSCAN_TYPE_SECTION\n"); */
-                                       pos+= 1; len-= 1;
+                                       pos += 1; len -= 1;
                                        break;
                                default:
                                        /* DBG_871X("Unknown CSCAN section %c\n", section); */
@@ -1391,7 +1391,7 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a,
 
                }
 
-               /* jeff: it has still some scan paramater to parse, we only do this now... */
+               /* jeff: it has still some scan parameter to parse, we only do this now... */
                _status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT);
 
        } else {
@@ -1463,7 +1463,7 @@ static int rtw_wx_get_scan(struct net_device *dev, struct iw_request_info *a,
                        && rtw_mlme_band_check(padapter, pnetwork->network.Configuration.DSConfig) == true
                        && true == rtw_validate_ssid(&(pnetwork->network.Ssid))) {
 
-                       ev =translate_scan(padapter, a, pnetwork, ev, stop);
+                       ev = translate_scan(padapter, a, pnetwork, ev, stop);
                }
 
                plist = get_next(plist);
@@ -1481,7 +1481,7 @@ exit:
        DBG_871X("DBG_IOCTL %s:%d return %d\n", __func__, __LINE__, ret);
        #endif
 
-       return ret ;
+       return ret;
 
 }
 
@@ -1570,7 +1570,7 @@ static int rtw_wx_set_essid(struct net_device *dev,
                                  pnetwork->network.Ssid.Ssid));
 
                        if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength)) &&
-                               (pnetwork->network.Ssid.SsidLength ==ndis_ssid.SsidLength)) {
+                               (pnetwork->network.Ssid.SsidLength == ndis_ssid.SsidLength)) {
                                RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
                                         ("rtw_wx_set_essid: find match, set infra mode\n"));
 
@@ -1651,7 +1651,7 @@ static int rtw_wx_set_rate(struct net_device *dev,
        u32 target_rate = wrqu->bitrate.value;
        u32 fixed = wrqu->bitrate.fixed;
        u32 ratevalue = 0;
-       u8 mpdatarate[NumRates]={11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
+       u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
 
        RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, (" rtw_wx_set_rate\n"));
        RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, ("target_rate = %d, fixed = %d\n", target_rate, fixed));
@@ -1706,8 +1706,8 @@ static int rtw_wx_set_rate(struct net_device *dev,
 
 set_rate:
 
-       for (i = 0; i<NumRates; i++) {
-               if (ratevalue ==mpdatarate[i]) {
+       for (i = 0; i < NumRates; i++) {
+               if (ratevalue == mpdatarate[i]) {
                        datarates[i] = mpdatarate[i];
                        if (fixed == 0)
                                break;
@@ -1855,7 +1855,7 @@ static int rtw_wx_set_enc(struct net_device *dev,
                padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
                padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
                authmode = Ndis802_11AuthModeOpen;
-               padapter->securitypriv.ndisauthtype =authmode;
+               padapter->securitypriv.ndisauthtype = authmode;
 
                goto exit;
        }
@@ -1881,7 +1881,7 @@ static int rtw_wx_set_enc(struct net_device *dev,
                padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
                padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
                authmode = Ndis802_11AuthModeOpen;
-               padapter->securitypriv.ndisauthtype =authmode;
+               padapter->securitypriv.ndisauthtype = authmode;
        } else if (erq->flags & IW_ENCODE_RESTRICTED) {
                DBG_871X("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n");
                padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
@@ -1891,7 +1891,7 @@ static int rtw_wx_set_enc(struct net_device *dev,
                padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
                padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
                authmode = Ndis802_11AuthModeShared;
-               padapter->securitypriv.ndisauthtype =authmode;
+               padapter->securitypriv.ndisauthtype = authmode;
        } else {
                DBG_871X("rtw_wx_set_enc():erq->flags = 0x%x\n", erq->flags);
 
@@ -1900,7 +1900,7 @@ static int rtw_wx_set_enc(struct net_device *dev,
                padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
                padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
                authmode = Ndis802_11AuthModeOpen;
-               padapter->securitypriv.ndisauthtype =authmode;
+               padapter->securitypriv.ndisauthtype = authmode;
        }
 
        wep.KeyIndex = key;
@@ -1909,7 +1909,7 @@ static int rtw_wx_set_enc(struct net_device *dev,
 
                wep.Length = wep.KeyLength + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial);
        } else {
-               wep.KeyLength = 0 ;
+               wep.KeyLength = 0;
 
                if (keyindex_provided == 1) { /*  set key_id only, no given KeyMaterial(erq->length == 0). */
                        padapter->securitypriv.dot11PrivacyKeyIndex = key;
@@ -2093,7 +2093,7 @@ static int rtw_wx_set_auth(struct net_device *dev,
                        padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
                        padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
                        padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open; /* open system */
-                       padapter->securitypriv.ndisauthtype =Ndis802_11AuthModeOpen;
+                       padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
                }
 
                break;
@@ -2181,7 +2181,7 @@ static int rtw_wx_set_enc_ext(struct net_device *dev,
                param->u.crypt.set_tx = 0;
        }
 
-       param->u.crypt.idx = (pencoding->flags&0x00FF) -1 ;
+       param->u.crypt.idx = (pencoding->flags & 0x00FF) - 1;
 
        if (pext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
                memcpy(param->u.crypt.seq, pext->rx_seq, 8);
@@ -2459,7 +2459,7 @@ static int rtw_get_ap_info(struct net_device *dev,
 
        /* pdata->length = 0;? */
        pdata->flags = 0;
-       if (pdata->length>=32) {
+       if (pdata->length >= 32) {
                if (copy_from_user(data, pdata->pointer, 32)) {
                        ret = -EINVAL;
                        goto exit;
@@ -2492,13 +2492,13 @@ static int rtw_get_ap_info(struct net_device *dev,
                        DBG_871X("BSSID:" MAC_FMT "\n", MAC_ARG(bssid));
 
                        pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
-                       if (pbuf && (wpa_ielen>0)) {
+                       if (pbuf && (wpa_ielen > 0)) {
                                pdata->flags = 1;
                                break;
                        }
 
                        pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12);
-                       if (pbuf && (wpa_ielen>0)) {
+                       if (pbuf && (wpa_ielen > 0)) {
                                pdata->flags = 2;
                                break;
                        }
@@ -2510,7 +2510,7 @@ static int rtw_get_ap_info(struct net_device *dev,
 
        spin_unlock_bh(&(pmlmepriv->scanned_queue.lock));
 
-       if (pdata->length>=34) {
+       if (pdata->length >= 34) {
                if (copy_to_user((u8 __force __user *)pdata->pointer+32, (u8 *)&pdata->flags, 1)) {
                        ret = -EINVAL;
                        goto exit;
@@ -2541,7 +2541,7 @@ static int rtw_set_pid(struct net_device *dev,
        selector = *pdata;
        if (selector < 3 && selector >= 0) {
                padapter->pid[selector] = *(pdata+1);
-               DBG_871X("%s set pid[%d]=%d\n", __func__, selector , padapter->pid[selector]);
+               DBG_871X("%s set pid[%d]=%d\n", __func__, selector, padapter->pid[selector]);
        }
        else
                DBG_871X("%s selector %d error\n", __func__, selector);
@@ -2563,7 +2563,7 @@ static int rtw_wps_start(struct net_device *dev,
        u32   u32wps_start = 0;
         unsigned int uintRet = 0;
 
-       if ((true == padapter->bDriverStopped) ||(true ==padapter->bSurpriseRemoved) || (NULL == pdata)) {
+       if ((true == padapter->bDriverStopped) || (true == padapter->bSurpriseRemoved) || (NULL == pdata)) {
                ret = -EINVAL;
                goto exit;
        }
@@ -2733,8 +2733,8 @@ static int rtw_dbg_port(struct net_device *dev,
                                        break;
                                case 0x01: /* dbg mode */
                                        padapter->recvpriv.is_signal_dbg = 1;
-                                       extra_arg = extra_arg>100?100:extra_arg;
-                                       padapter->recvpriv.signal_strength_dbg =extra_arg;
+                                       extra_arg = extra_arg > 100 ? 100 : extra_arg;
+                                       padapter->recvpriv.signal_strength_dbg = extra_arg;
                                        break;
                        }
                        break;
@@ -2806,7 +2806,7 @@ static int rtw_dbg_port(struct net_device *dev,
                                                DBG_871X("ampdu_enable = %d\n", psta->htpriv.ampdu_enable);
                                                DBG_871X("agg_enable_bitmap =%x, candidate_tid_bitmap =%x\n", psta->htpriv.agg_enable_bitmap, psta->htpriv.candidate_tid_bitmap);
 
-                                               for (i = 0;i<16;i++) {
+                                               for (i = 0; i < 16; i++) {
                                                        preorder_ctrl = &psta->recvreorder_ctrl[i];
                                                        if (preorder_ctrl->enable)
                                                                DBG_871X("tid =%d, indicate_seq =%d\n", i, preorder_ctrl->indicate_seq);
@@ -2845,7 +2845,7 @@ static int rtw_dbg_port(struct net_device *dev,
 
                                                spin_lock_bh(&pstapriv->sta_hash_lock);
 
-                                               for (i = 0; i< NUM_STA; i++) {
+                                               for (i = 0; i < NUM_STA; i++) {
                                                        phead = &(pstapriv->sta_hash[i]);
                                                        plist = get_next(phead);
 
@@ -2872,7 +2872,7 @@ static int rtw_dbg_port(struct net_device *dev,
 
 
 
-                                                                       for (j = 0;j<16;j++) {
+                                                                       for (j = 0; j < 16; j++) {
                                                                                preorder_ctrl = &psta->recvreorder_ctrl[j];
                                                                                if (preorder_ctrl->enable)
                                                                                        DBG_871X("tid =%d, indicate_seq =%d\n", j, preorder_ctrl->indicate_seq);
@@ -2900,7 +2900,7 @@ static int rtw_dbg_port(struct net_device *dev,
                                                DBG_871X("enable driver ctrl vcs = %d\n", extra_arg);
                                                padapter->driver_vcs_en = 1;
 
-                                               if (extra_arg>2)
+                                               if (extra_arg > 2)
                                                        padapter->driver_vcs_type = 1;
                                                else
                                                        padapter->driver_vcs_type = extra_arg;
@@ -3048,7 +3048,7 @@ static int rtw_dbg_port(struct net_device *dev,
 
                                                        if (max_rx_rate < 0xc) { /*  max_rx_rate < MSC0 -> B or G -> disable HT */
                                                                pregistrypriv->ht_enable = 0;
-                                                               for (i = 0; i<NumRates; i++) {
+                                                               for (i = 0; i < NumRates; i++) {
                                                                        if (pmlmeext->datarate[i] > max_rx_rate)
                                                                                pmlmeext->datarate[i] = 0xff;
                                                                }
@@ -3057,7 +3057,7 @@ static int rtw_dbg_port(struct net_device *dev,
                                                        else if (max_rx_rate < 0x1c) { /*  mcs0~mcs15 */
                                                                u32 mcs_bitmap = 0x0;
 
-                                                               for (i = 0; i<((max_rx_rate+1)-0xc); i++)
+                                                               for (i = 0; i < ((max_rx_rate + 1) - 0xc); i++)
                                                                        mcs_bitmap |= BIT(i);
 
                                                                set_mcs_rate_by_mask(pmlmeext->default_supported_mcs_set, mcs_bitmap);
@@ -3129,9 +3129,9 @@ static int rtw_dbg_port(struct net_device *dev,
                                            */
 
                                            int value;
-                                           DBG_871X("Set GPIO Direction! arg = %d , extra_arg =%d\n", arg , extra_arg);
+                                           DBG_871X("Set GPIO Direction! arg = %d , extra_arg =%d\n", arg, extra_arg);
                                            value = rtw_config_gpio(dev, arg, extra_arg);
-                                           DBG_871X("Set GPIO Direction %s\n", (value ==-1)?"Fail!!!":"Success");
+                                           DBG_871X("Set GPIO Direction %s\n", (value == -1) ? "Fail!!!" : "Success");
                                            break;
                                        }
                                case 0x27: /* Set GPIO output direction value */
@@ -3142,15 +3142,15 @@ static int rtw_dbg_port(struct net_device *dev,
                                                */
 
                                                int value;
-                                               DBG_871X("Set GPIO Value! arg = %d , extra_arg =%d\n", arg , extra_arg);
+                                               DBG_871X("Set GPIO Value! arg = %d , extra_arg =%d\n", arg, extra_arg);
                                                value = rtw_set_gpio_output_value(dev, arg, extra_arg);
-                                               DBG_871X("Set GPIO Value %s\n", (value ==-1)?"Fail!!!":"Success");
+                                               DBG_871X("Set GPIO Value %s\n", (value == -1) ? "Fail!!!" : "Success");
                                                break;
                                        }
 #endif
                                case 0xaa:
                                        {
-                                               if ((extra_arg & 0x7F)> 0x3F) extra_arg = 0xFF;
+                                               if ((extra_arg & 0x7F) > 0x3F) extra_arg = 0xFF;
                                                DBG_871X("chang data rate to :0x%02x\n", extra_arg);
                                                padapter->fix_rate = extra_arg;
                                        }
@@ -3161,7 +3161,7 @@ static int rtw_dbg_port(struct net_device *dev,
                                                        mac_reg_dump(RTW_DBGDUMP, padapter);
                                                else if (extra_arg == 1)
                                                        bb_reg_dump(RTW_DBGDUMP, padapter);
-                                               else if (extra_arg ==2)
+                                               else if (extra_arg == 2)
                                                        rf_reg_dump(RTW_DBGDUMP, padapter);
                                        }
                                        break;
@@ -3170,8 +3170,8 @@ static int rtw_dbg_port(struct net_device *dev,
                                        {
                                                u32 odm_flag;
 
-                                               if (0xf ==extra_arg) {
-                                                       rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC,&odm_flag);
+                                               if (0xf == extra_arg) {
+                                                       rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag);
                                                        DBG_871X(" === DMFlag(0x%08x) ===\n", odm_flag);
                                                        DBG_871X("extra_arg = 0  - disable all dynamic func\n");
                                                        DBG_871X("extra_arg = 1  - disable DIG- BIT(0)\n");
@@ -3187,7 +3187,7 @@ static int rtw_dbg_port(struct net_device *dev,
                                                                extra_arg = 3  - turn on all dynamic func
                                                        */
                                                        rtw_hal_set_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &(extra_arg));
-                                                       rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC,&odm_flag);
+                                                       rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DM_FUNC, &odm_flag);
                                                        DBG_871X(" === DMFlag(0x%08x) ===\n", odm_flag);
                                                }
                                        }
@@ -3257,7 +3257,7 @@ static int wpa_set_param(struct net_device *dev, u8 name, u32 value)
                /* ret = ieee80211_wpa_enable(ieee, value); */
 
                switch ((value)&0xff) {
-               case 1 : /* WPA */
+               case 1: /* WPA */
                        padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; /* WPA_PSK */
                        padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
                        break;
@@ -3428,7 +3428,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
        struct sta_info *psta = NULL, *pbcmc_sta = NULL;
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-       struct security_priv* psecuritypriv =&(padapter->securitypriv);
+       struct security_priv* psecuritypriv = &(padapter->securitypriv);
        struct sta_priv *pstapriv = &padapter->stapriv;
 
        DBG_871X("%s\n", __func__);
@@ -3481,7 +3481,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
 
                DBG_871X("r871x_set_encryption, wep_key_idx =%d, len =%d\n", wep_key_idx, wep_key_len);
 
-               if ((wep_key_idx >= WEP_KEYS) || (wep_key_len<= 0)) {
+               if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
                        ret = -EINVAL;
                        goto exit;
                }
@@ -3523,7 +3523,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
 
                        memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);
 
-                       psecuritypriv->dot11DefKeylen[wep_key_idx]=pwep->KeyLength;
+                       psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;
 
                        rtw_ap_set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx, 1);
                } else {
@@ -3549,7 +3549,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
                        if (strcmp(param->u.crypt.alg, "WEP") == 0) {
                                DBG_871X("%s, set group_key, WEP\n", __func__);
 
-                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
                                if (param->u.crypt.key_len == 13)
@@ -3560,7 +3560,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
 
                                psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
 
-                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
                                /* set mic key */
@@ -3575,7 +3575,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
 
                                psecuritypriv->dot118021XGrpPrivacy = _AES_;
 
-                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                               memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
                        } else {
                                DBG_871X("%s, set group_key, none\n", __func__);
 
@@ -3590,7 +3590,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
 
                        rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
 
-                       pbcmc_sta =rtw_get_bcmc_stainfo(padapter);
+                       pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
                        if (pbcmc_sta) {
                                pbcmc_sta->ieee8021x_blocked = false;
                                pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */
@@ -3604,7 +3604,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
        if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /*  psk/802_1x */
                if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
                        if (param->u.crypt.set_tx == 1) {
-                               memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                               memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                if (strcmp(param->u.crypt.alg, "WEP") == 0) {
                                        DBG_871X("%s, set pairwise key, WEP\n", __func__);
@@ -3641,7 +3641,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
 
                        } else { /* group key??? */
                                if (strcmp(param->u.crypt.alg, "WEP") == 0) {
-                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                        psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
                                        if (param->u.crypt.key_len == 13)
@@ -3649,7 +3649,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
                                } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
                                        psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
 
-                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
 
                                        /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
                                        /* set mic key */
@@ -3661,7 +3661,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
                                } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
                                        psecuritypriv->dot118021XGrpPrivacy = _AES_;
 
-                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
+                                       memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len));
                                } else {
                                        psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
                                }
@@ -3674,7 +3674,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param,
 
                                rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);
 
-                               pbcmc_sta =rtw_get_bcmc_stainfo(padapter);
+                               pbcmc_sta = rtw_get_bcmc_stainfo(padapter);
                                if (pbcmc_sta) {
                                        pbcmc_sta->ieee8021x_blocked = false;
                                        pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */
@@ -3706,7 +3706,7 @@ static int rtw_set_beacon(struct net_device *dev, struct ieee_param *param, int
 
        memcpy(&pstapriv->max_num_sta, param->u.bcn_ie.reserved, 2);
 
-       if ((pstapriv->max_num_sta>NUM_STA) || (pstapriv->max_num_sta<= 0))
+       if ((pstapriv->max_num_sta > NUM_STA) || (pstapriv->max_num_sta <= 0))
                pstapriv->max_num_sta = NUM_STA;
 
 
@@ -3831,12 +3831,12 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param)
 
        psta = rtw_get_stainfo(pstapriv, param->sta_addr);
        if (psta) {
-               u8 updated =false;
+               u8 updated = false;
 
                /* DBG_871X("free psta =%p, aid =%d\n", psta, psta->aid); */
 
                spin_lock_bh(&pstapriv->asoc_list_lock);
-               if (list_empty(&psta->asoc_list) ==false) {
+               if (list_empty(&psta->asoc_list) == false) {
                        list_del_init(&psta->asoc_list);
                        pstapriv->asoc_list_cnt--;
                        updated = ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
@@ -3895,12 +3895,12 @@ static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *par
                ht_20mhz_set : BIT(5)
 */
 
-               psta_data->sta_set =((psta->nonerp_set) |
-                                                       (psta->no_short_slot_time_set <<1) |
-                                                       (psta->no_short_preamble_set <<2) |
-                                                       (psta->no_ht_gf_set <<3) |
-                                                       (psta->no_ht_set <<4) |
-                                                       (psta->ht_20mhz_set <<5));
+               psta_data->sta_set = ((psta->nonerp_set) |
+                                                        (psta->no_short_slot_time_set << 1) |
+                                                        (psta->no_short_preamble_set << 2) |
+                                                        (psta->no_ht_gf_set << 3) |
+                                                        (psta->no_ht_set << 4) |
+                                                        (psta->ht_20mhz_set << 5));
 
                psta_data->tx_supp_rates_len =  psta->bssratelen;
                memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen);
@@ -3969,7 +3969,7 @@ 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};
+       unsigned char wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
        struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
@@ -3986,7 +3986,7 @@ static int rtw_set_wps_beacon(struct net_device *dev, struct ieee_param *param,
        kfree(pmlmepriv->wps_beacon_ie);
        pmlmepriv->wps_beacon_ie = NULL;
 
-       if (ie_len>0) {
+       if (ie_len > 0) {
                pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len);
                pmlmepriv->wps_beacon_ie_len = ie_len;
                if (pmlmepriv->wps_beacon_ie == NULL) {
@@ -4024,7 +4024,7 @@ static int rtw_set_wps_probe_resp(struct net_device *dev, struct ieee_param *par
        kfree(pmlmepriv->wps_probe_resp_ie);
        pmlmepriv->wps_probe_resp_ie = NULL;
 
-       if (ie_len>0) {
+       if (ie_len > 0) {
                pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len);
                pmlmepriv->wps_probe_resp_ie_len = ie_len;
                if (pmlmepriv->wps_probe_resp_ie == NULL) {
@@ -4057,7 +4057,7 @@ static int rtw_set_wps_assoc_resp(struct net_device *dev, struct ieee_param *par
        kfree(pmlmepriv->wps_assoc_resp_ie);
        pmlmepriv->wps_assoc_resp_ie = NULL;
 
-       if (ie_len>0) {
+       if (ie_len > 0) {
                pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
                pmlmepriv->wps_assoc_resp_ie_len = ie_len;
                if (pmlmepriv->wps_assoc_resp_ie == NULL) {
@@ -4357,11 +4357,11 @@ static int rtw_wx_set_priv(struct net_device *dev,
                struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
                u8 *probereq_wpsie = ext;
                int probereq_wpsie_len = len;
-               u8 wps_oui[4]={0x0, 0x50, 0xf2, 0x04};
+               u8 wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
 
                if ((_VENDOR_SPECIFIC_IE_ == probereq_wpsie[0]) &&
                        (!memcmp(&probereq_wpsie[2], wps_oui, 4))) {
-                       cp_sz = probereq_wpsie_len>MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN:probereq_wpsie_len;
+                       cp_sz = probereq_wpsie_len > MAX_WPS_IE_LEN ? MAX_WPS_IE_LEN : probereq_wpsie_len;
 
                        if (pmlmepriv->wps_probe_req_ie) {
                                pmlmepriv->wps_probe_req_ie_len = 0;
@@ -4498,7 +4498,7 @@ static int rtw_test(
                ret = rtw_hal_fill_h2c_cmd(padapter, param[0], count-1, &param[1]);
 
                pos = sprintf(extra, "H2C ID = 0x%02x content =", param[0]);
-               for (i = 1; i<count; i++)
+               for (i = 1; i < count; i++)
                        pos += sprintf(extra+pos, "%02x,", param[i]);
                extra[pos] = 0;
                pos--;
@@ -4636,14 +4636,14 @@ static const struct iw_priv_args rtw_private_args[] = {
        },
        {
                SIOCIWFIRSTPRIV + 0x11,
-               IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK , "p2p_get"
+               IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "p2p_get"
        },
        {
                SIOCIWFIRSTPRIV + 0x12, 0, 0, "NULL"
        },
        {
                SIOCIWFIRSTPRIV + 0x13,
-               IW_PRIV_TYPE_CHAR | 64, IW_PRIV_TYPE_CHAR | 64 , "p2p_get2"
+               IW_PRIV_TYPE_CHAR | 64, IW_PRIV_TYPE_CHAR | 64, "p2p_get2"
        },
        {
                SIOCIWFIRSTPRIV + 0x14,
@@ -4651,14 +4651,14 @@ static const struct iw_priv_args rtw_private_args[] = {
        },
        {
                SIOCIWFIRSTPRIV + 0x15,
-               IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024 , "tdls_get"
+               IW_PRIV_TYPE_CHAR | 1024, IW_PRIV_TYPE_CHAR | 1024, "tdls_get"
        },
        {
                SIOCIWFIRSTPRIV + 0x16,
                IW_PRIV_TYPE_CHAR | 64, 0, "pm_set"
        },
 
-       {SIOCIWFIRSTPRIV + 0x18, IW_PRIV_TYPE_CHAR | IFNAMSIZ , 0 , "rereg_nd_name"},
+       {SIOCIWFIRSTPRIV + 0x18, IW_PRIV_TYPE_CHAR | IFNAMSIZ, 0, "rereg_nd_name"},
        {SIOCIWFIRSTPRIV + 0x1A, IW_PRIV_TYPE_CHAR | 1024, 0, "efuse_set"},
        {SIOCIWFIRSTPRIV + 0x1B, IW_PRIV_TYPE_CHAR | 128, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_MASK, "efuse_get"},
        {
@@ -4667,10 +4667,10 @@ static const struct iw_priv_args rtw_private_args[] = {
        },
 
 #ifdef CONFIG_WOWLAN
-               { MP_WOW_ENABLE , IW_PRIV_TYPE_CHAR | 1024, 0, "wow_mode" }, /* set */
+               { MP_WOW_ENABLE, IW_PRIV_TYPE_CHAR | 1024, 0, "wow_mode" }, /* set */
 #endif
 #ifdef CONFIG_AP_WOWLAN
-               { MP_AP_WOW_ENABLE , IW_PRIV_TYPE_CHAR | 1024, 0, "ap_wow_mode" }, /* set */
+               { MP_AP_WOW_ENABLE, IW_PRIV_TYPE_CHAR | 1024, 0, "ap_wow_mode" }, /* set */
 #endif
 };
 
@@ -4721,7 +4721,7 @@ static iw_handler rtw_private_handler[] = {
 static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev)
 {
        struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
-       struct iw_statistics *piwstats =&padapter->iwstats;
+       struct iw_statistics *piwstats = &padapter->iwstats;
        int tmp_level = 0;
        int tmp_qual = 0;
        int tmp_noise = 0;
@@ -4760,10 +4760,10 @@ static struct iw_statistics *rtw_get_wireless_stats(struct net_device *dev)
                        rtw_ps_deny(padapter, PS_DENY_IOCTL);
                        LeaveAllPowerSaveModeDirect(padapter);
 
-                       rtw_hal_set_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&info, false);
+                       rtw_hal_set_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &info, false);
                        /* ODM_InbandNoise_Monitor(podmpriv, true, 0x20, 100); */
                        rtw_ps_deny_cancel(padapter, PS_DENY_IOCTL);
-                       rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR,&(info.chan), &(padapter->recvpriv.noise));
+                       rtw_hal_get_odm_var(padapter, HAL_ODM_NOISE_MONITOR, &(info.chan), &(padapter->recvpriv.noise));
                        DBG_871X("chan:%d, noise_level:%d\n", info.chan, padapter->recvpriv.noise);
                }
 #endif
index 52a5b31..f121dbf 100644 (file)
@@ -64,7 +64,7 @@ void rtw_os_indicate_scan_done(struct adapter *padapter, bool aborted)
        indicate_wx_scan_complete_event(padapter);
 }
 
-static RT_PMKID_LIST   backupPMKIDList[ NUM_PMKID_CACHE ];
+static RT_PMKID_LIST   backupPMKIDList[NUM_PMKID_CACHE];
 void rtw_reset_securitypriv(struct adapter *adapter)
 {
        u8 backupPMKIDIndex = 0;
@@ -83,7 +83,7 @@ void rtw_reset_securitypriv(struct adapter *adapter)
                /*  Backup the btkip_countermeasure information. */
                /*  When the countermeasure is trigger, the driver have to disconnect with AP for 60 seconds. */
 
-               memcpy(&backupPMKIDList[ 0 ], &adapter->securitypriv.PMKIDList[ 0 ], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+               memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
                backupPMKIDIndex = adapter->securitypriv.PMKIDIndex;
                backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure;
                backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time;
@@ -95,7 +95,7 @@ void rtw_reset_securitypriv(struct adapter *adapter)
 
                /*  Added by Albert 2009/02/18 */
                /*  Restore the PMK information to securitypriv structure for the following connection. */
-               memcpy(&adapter->securitypriv.PMKIDList[ 0 ], &backupPMKIDList[ 0 ], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
+               memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0], sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE);
                adapter->securitypriv.PMKIDIndex = backupPMKIDIndex;
                adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure;
                adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time;
index 47e984d..d29f59b 100644 (file)
@@ -202,8 +202,8 @@ module_param(rtw_tx_pwr_by_rate, int, 0644);
 MODULE_PARM_DESC(rtw_tx_pwr_by_rate, "0:Disable, 1:Enable, 2: Depend on efuse");
 
 int _netdev_open(struct net_device *pnetdev);
-int netdev_open (struct net_device *pnetdev);
-static int netdev_close (struct net_device *pnetdev);
+int netdev_open(struct net_device *pnetdev);
+static int netdev_close(struct net_device *pnetdev);
 
 static void loadparam(struct adapter *padapter, _nic_hdl pnetdev)
 {
@@ -221,7 +221,7 @@ static void loadparam(struct adapter *padapter, _nic_hdl pnetdev)
        registry_par->channel = (u8)rtw_channel;
        registry_par->wireless_mode = (u8)rtw_wireless_mode;
 
-       registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense ;
+       registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense;
        registry_par->vcs_type = (u8)rtw_vcs_type;
        registry_par->rts_thresh = (u16)rtw_rts_thresh;
        registry_par->frag_thresh = (u16)rtw_frag_thresh;
@@ -554,7 +554,7 @@ u32 rtw_start_drv_threads(struct adapter *padapter)
        return _status;
 }
 
-void rtw_stop_drv_threads (struct adapter *padapter)
+void rtw_stop_drv_threads(struct adapter *padapter)
 {
        RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads\n"));
 
@@ -1154,7 +1154,7 @@ void rtw_dev_unload(struct adapter *padapter)
                                DBG_871X("stop cmdthd timeout\n");
                                break;
                        } else {
-                               cnt ++;
+                               cnt++;
                                DBG_871X("cmdthd is running(%d)\n", cnt);
                                msleep(10);
                        }
@@ -1274,7 +1274,7 @@ void rtw_suspend_wow(struct adapter *padapter)
                        padapter->intf_stop(padapter);
                }
 
-               /*  2.1 clean interupt */
+               /*  2.1 clean interrupt */
                if (padapter->HalFunc.clear_interrupt)
                        padapter->HalFunc.clear_interrupt(padapter);
 
@@ -1348,7 +1348,7 @@ void rtw_suspend_ap_wow(struct adapter *padapter)
        /*  2. disable interrupt */
        rtw_hal_disable_interrupt(padapter); /*  It need wait for leaving 32K. */
 
-       /*  2.1 clean interupt */
+       /*  2.1 clean interrupt */
        if (padapter->HalFunc.clear_interrupt)
                padapter->HalFunc.clear_interrupt(padapter);
 
@@ -1799,7 +1799,7 @@ int rtw_resume_common(struct adapter *padapter)
                pwrpriv->pno_in_resume = false;
        #endif
        }
-       DBG_871X_LEVEL(_drv_always_, "%s:%d in %d ms\n", __func__ , ret,
+       DBG_871X_LEVEL(_drv_always_, "%s:%d in %d ms\n", __func__, ret,
                jiffies_to_msecs(jiffies - start_time));
 
        return ret;
index f5614e5..4238209 100644 (file)
@@ -289,7 +289,7 @@ void *rtw_cbuf_pop(struct rtw_cbuf *cbuf)
 }
 
 /**
- * rtw_cbuf_alloc - allocte a rtw_cbuf with given size and do initialization
+ * rtw_cbuf_alloc - allocate a rtw_cbuf with given size and do initialization
  * @size: size of pointer
  *
  * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure
index 643cacc..60c35d9 100644 (file)
@@ -35,7 +35,8 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv)
 
        for (i = 0; i < NR_RECVFRAME; i++) {
                if (precvframe->u.hdr.pkt) {
-                       dev_kfree_skb_any(precvframe->u.hdr.pkt);/* free skb by driver */
+                       /* free skb by driver */
+                       dev_kfree_skb_any(precvframe->u.hdr.pkt);
                        precvframe->u.hdr.pkt = NULL;
                }
                precvframe++;
@@ -80,7 +81,10 @@ _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8
                ((!memcmp(sub_skb->data, rtw_rfc1042_header, SNAP_SIZE) &&
                  eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) ||
                 !memcmp(sub_skb->data, rtw_bridge_tunnel_header, SNAP_SIZE))) {
-               /* remove RFC1042 or Bridge-Tunnel encapsulation and replace EtherType */
+               /*
+                * remove RFC1042 or Bridge-Tunnel encapsulation and replace
+                * EtherType
+                */
                skb_pull(sub_skb, SNAP_SIZE);
                memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, ETH_ALEN);
                memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, ETH_ALEN);
@@ -101,7 +105,7 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
        struct mlme_priv*pmlmepriv = &padapter->mlmepriv;
        int ret;
 
-       /* Indicat the packets to upper layer */
+       /* Indicate the packets to upper layer */
        if (pkt) {
                if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
                        _pkt *pskb2 = NULL;
@@ -109,11 +113,7 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
                        struct sta_priv *pstapriv = &padapter->stapriv;
                        int bmcast = IS_MCAST(pattrib->dst);
 
-                       /* DBG_871X("bmcast =%d\n", bmcast); */
-
                        if (memcmp(pattrib->dst, myid(&padapter->eeprompriv), ETH_ALEN)) {
-                               /* DBG_871X("not ap psta =%p, addr =%pM\n", psta, pattrib->dst); */
-
                                if (bmcast) {
                                        psta = rtw_get_bcmc_stainfo(padapter);
                                        pskb2 = rtw_skb_clone(pkt);
@@ -123,9 +123,6 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt
 
                                if (psta) {
                                        struct net_device *pnetdev = (struct net_device*)padapter->pnetdev;
-
-                                       /* DBG_871X("directly forwarding to the rtw_xmit_entry\n"); */
-
                                        /* skb->ip_summed = CHECKSUM_NONE; */
                                        pkt->dev = pnetdev;
                                        skb_set_queue_mapping(pkt, rtw_recv_select_queue(pkt));
@@ -197,7 +194,7 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
                key_type |= NL80211_KEYTYPE_PAIRWISE;
        }
 
-       cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[ 0 ], key_type, -1,
+       cfg80211_michael_mic_failure(padapter->pnetdev, (u8 *)&pmlmepriv->assoc_bssid[0], key_type, -1,
                NULL, GFP_ATOMIC);
 
        memset(&ev, 0x00, sizeof(ev));
@@ -208,7 +205,7 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup)
        }
 
        ev.src_addr.sa_family = ARPHRD_ETHER;
-       memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       memcpy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0], ETH_ALEN);
 
        memset(&wrqu, 0x00, sizeof(wrqu));
        wrqu.data.length = sizeof(ev);
@@ -223,7 +220,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);
@@ -234,14 +231,10 @@ static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *prec
                if (rx_pid == psta->pid) {
                        int i;
                        u16 len = *(u16*)(skb->data+ETH_HLEN+2);
-                       /* u16 ctrl_type = *(u16*)(skb->data+ETH_HLEN+4); */
-
-                       /* DBG_871X("eth, RC: len = 0x%x, ctrl_type = 0x%x\n", len, ctrl_type); */
                        DBG_871X("eth, RC: len = 0x%x\n", len);
 
-                       for (i = 0;i<len;i++)
+                       for (i = 0; i < len; i++)
                                DBG_871X("0x%x\n", *(skb->data+ETH_HLEN+4+i));
-                               /* DBG_871X("0x%x\n", *(skb->data+ETH_HLEN+6+i)); */
 
                        DBG_871X("eth, RC-end\n");
                }
@@ -291,7 +284,8 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame
 
        rtw_os_recv_indicate_pkt(padapter, skb, pattrib);
 
-       precv_frame->u.hdr.pkt = NULL; /*  pointers to NULL before rtw_free_recvframe() */
+       /* pointers to NULL before rtw_free_recvframe() */
+       precv_frame->u.hdr.pkt = NULL;
 
        rtw_free_recvframe(precv_frame, pfree_recv_queue);
 
@@ -301,11 +295,11 @@ int rtw_recv_indicatepkt(struct adapter *padapter, union recv_frame *precv_frame
 
 _recv_indicatepkt_drop:
 
-        /* enqueue back to free_recv_queue */
-        rtw_free_recvframe(precv_frame, pfree_recv_queue);
+       /* enqueue back to free_recv_queue */
+       rtw_free_recvframe(precv_frame, pfree_recv_queue);
 
-        DBG_COUNTER(padapter->rx_logs.os_indicate_err);
-        return _FAIL;
+       DBG_COUNTER(padapter->rx_logs.os_indicate_err);
+       return _FAIL;
 }
 
 void rtw_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl)
index 859f4a0..b093b56 100644 (file)
@@ -108,7 +108,7 @@ static void sdio_free_irq(struct dvobj_priv *dvobj)
                        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);
+                               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);
@@ -324,7 +324,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct
        padapter->dvobj = dvobj;
        dvobj->if1 = padapter;
 
-       padapter->bDriverStopped =true;
+       padapter->bDriverStopped = true;
 
        dvobj->padapters = padapter;
        padapter->iface_id = 0;
@@ -430,7 +430,7 @@ static void rtw_sdio_if1_deinit(struct adapter *if1)
        rtw_cancel_all_timer(if1);
 
 #ifdef CONFIG_WOWLAN
-       adapter_to_pwrctl(if1)->wowlan_mode =false;
+       adapter_to_pwrctl(if1)->wowlan_mode = false;
        DBG_871X_LEVEL(_drv_always_, "%s wowlan_mode:%d\n", __func__, adapter_to_pwrctl(if1)->wowlan_mode);
 #endif /* CONFIG_WOWLAN */
 
@@ -500,7 +500,7 @@ free_dvobj:
        if (status != _SUCCESS)
                sdio_dvobj_deinit(func);
 exit:
-       return status == _SUCCESS?0:-ENODEV;
+       return status == _SUCCESS ? 0 : -ENODEV;
 }
 
 static void rtw_dev_remove(struct sdio_func *func)
@@ -548,7 +548,7 @@ extern int pm_netdev_close(struct net_device *pnetdev, u8 bnormal);
 
 static int rtw_sdio_suspend(struct device *dev)
 {
-       struct sdio_func *func =dev_to_sdio_func(dev);
+       struct sdio_func *func = dev_to_sdio_func(dev);
        struct dvobj_priv *psdpriv = sdio_get_drvdata(func);
        struct pwrctrl_priv *pwrpriv = dvobj_to_pwrctl(psdpriv);
        struct adapter *padapter = psdpriv->if1;
@@ -585,7 +585,7 @@ static int rtw_resume_process(struct adapter *padapter)
 
 static int rtw_sdio_resume(struct device *dev)
 {
-       struct sdio_func *func =dev_to_sdio_func(dev);
+       struct sdio_func *func = dev_to_sdio_func(dev);
        struct dvobj_priv *psdpriv = sdio_get_drvdata(func);
        struct adapter *padapter = psdpriv->if1;
        struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
index 4e81bc1..fec8a8c 100644 (file)
@@ -15,16 +15,16 @@ uint rtw_remainder_len(struct pkt_file *pfile)
        return (pfile->buf_len - ((SIZE_PTR)(pfile->cur_addr) - (SIZE_PTR)(pfile->buf_start)));
 }
 
-void _rtw_open_pktfile (_pkt *pktptr, struct pkt_file *pfile)
+void _rtw_open_pktfile(_pkt *pktptr, struct pkt_file *pfile)
 {
        pfile->pkt = pktptr;
        pfile->cur_addr = pfile->buf_start = pktptr->data;
        pfile->pkt_len = pfile->buf_len = pktptr->len;
 
-       pfile->cur_buffer = pfile->buf_start ;
+       pfile->cur_buffer = pfile->buf_start;
 }
 
-uint _rtw_pktfile_read (struct pkt_file *pfile, u8 *rmem, uint rlen)
+uint _rtw_pktfile_read(struct pkt_file *pfile, u8 *rmem, uint rlen)
 {
        uint    len = 0;
 
index 17c4131..c6f9375 100644 (file)
@@ -940,7 +940,8 @@ static void rtsx_monitor_aspm_config(struct rtsx_chip *chip)
                if (maybe_support_aspm)
                        chip->aspm_l0s_l1_en = 0x03;
 
-               dev_dbg(rtsx_dev(chip), "aspm_level[0] = 0x%02x, aspm_level[1] = 0x%02x\n",
+               dev_dbg(rtsx_dev(chip),
+                       "aspm_level[0] = 0x%02x, aspm_level[1] = 0x%02x\n",
                        chip->aspm_level[0], chip->aspm_level[1]);
 
                if (chip->aspm_l0s_l1_en) {
index 1cf3849..b89aa4c 100644 (file)
@@ -1,5 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_FB_SM750) += sm750fb.o
 
-sm750fb-objs           := sm750.o sm750_hw.o sm750_accel.o sm750_cursor.o ddk750_chip.o ddk750_power.o ddk750_mode.o
-sm750fb-objs           += ddk750_display.o ddk750_swi2c.o ddk750_sii164.o ddk750_dvi.o ddk750_hwi2c.o
+sm750fb-objs           := sm750.o sm750_hw.o sm750_accel.o sm750_cursor.o \
+                          ddk750_chip.o ddk750_power.o ddk750_mode.o \
+                          ddk750_display.o ddk750_swi2c.o ddk750_sii164.o \
+                          ddk750_dvi.o ddk750_hwi2c.o
index 5f1bda3..822ceac 100644 (file)
@@ -49,7 +49,7 @@ static int cur_item, nstates;
 static void build_key_data(void)
 {
        u_char *kp, counters[MAXFUNCS], ch, ch1;
-       u_short *p_key = key_data, key;
+       u_short *p_key, key;
        int i, offset = 1;
 
        nstates = (int)(state_tbl[-1]);
index 488f253..02471d9 100644 (file)
@@ -561,7 +561,7 @@ static u_long get_word(struct vc_data *vc)
                return 0;
        } else if (tmpx < vc->vc_cols - 2 &&
                   (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
-                  get_char(vc, (u_short *)&tmp_pos + 1, &temp) > SPACE) {
+                  get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
                tmp_pos += 2;
                tmpx++;
        } else {
@@ -2117,7 +2117,8 @@ speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
                        spk_keydown = 0;
                        goto out;
                }
-               value = spk_lastkey = pad_chars[value];
+               value = pad_chars[value];
+               spk_lastkey = value;
                spk_keydown++;
                spk_parked &= 0xfe;
                goto no_map;
index a8b4d0c..032f326 100644 (file)
@@ -51,9 +51,7 @@ static void __speakup_set_selection(struct work_struct *work)
                goto unref;
        }
 
-       console_lock();
        set_selection_kernel(&sel, tty);
-       console_unlock();
 
 unref:
        tty_kref_put(tty);
index 9d85a3a..28cedae 100644 (file)
@@ -388,7 +388,7 @@ static int softsynth_probe(struct spk_synth *synth)
        synthu_device.name = "softsynthu";
        synthu_device.fops = &softsynthu_fops;
        if (misc_register(&synthu_device)) {
-               pr_warn("Couldn't initialize miscdevice /dev/softsynth.\n");
+               pr_warn("Couldn't initialize miscdevice /dev/softsynthu.\n");
                return -ENODEV;
        }
 
index ac6a748..c75b408 100644 (file)
 #ifndef _SPEAKUP_PRIVATE_H
 #define _SPEAKUP_PRIVATE_H
 
+#include <linux/printk.h>
+
 #include "spk_types.h"
 #include "spk_priv_keyinfo.h"
 
-#ifndef pr_warn
-#define pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
-#endif
-
 #define V_LAST_VAR { MAXVARS }
 #define SPACE 0x20
 #define SYNTH_CHECK 20030716 /* today's date ought to do for check value */
index 5a9eff0..9b95f77 100644 (file)
@@ -51,7 +51,7 @@ static int spk_ttyio_ldisc_open(struct tty_struct *tty)
                return -EOPNOTSUPP;
        speakup_tty = tty;
 
-       ldisc_data = kmalloc(sizeof(struct spk_ldisc_data), GFP_KERNEL);
+       ldisc_data = kmalloc(sizeof(*ldisc_data), GFP_KERNEL);
        if (!ldisc_data)
                return -ENOMEM;
 
index a2fc72c..fc6a941 100644 (file)
@@ -189,7 +189,7 @@ struct spk_synth {
        void (*flush)(struct spk_synth *synth);
        int (*is_alive)(struct spk_synth *synth);
        int (*synth_adjust)(struct st_var_header *var);
-       void (*read_buff_add)(u_char);
+       void (*read_buff_add)(u_char c);
        unsigned char (*get_index)(struct spk_synth *synth);
        struct synth_indexing indexing;
        int alive;
index f8a4144..cf29f88 100644 (file)
@@ -15,12 +15,12 @@ normally be unsharable, specifically:
 * visorinput - keyboard and mouse
 
 These drivers conform to the standard Linux bus/device model described
-within Documentation/driver-api/driver-model/, and utilize a driver named visorbus to
-present the virtual busses involved. Drivers in the 'visor*' driver set are
-commonly referred to as "guest drivers" or "client drivers".  All drivers
-except visorbus expose a device of a specific usable class to the Linux guest
-environment (e.g., block, network, or input), and are collectively referred
-to as "function drivers".
+within Documentation/driver-api/driver-model/, and utilize a driver named
+visorbus to present the virtual busses involved. Drivers in the 'visor*'
+driver set are commonly referred to as "guest drivers" or "client drivers".
+All drivers except visorbus expose a device of a specific usable class to the
+Linux guest environment (e.g., block, network, or input), and are collectively
+referred to as "function drivers".
 
 The back-end for each device is owned and managed by a small,
 single-purpose service partition in the s-Par firmware, which communicates
index 9693fb5..6d202cb 100644 (file)
@@ -111,7 +111,7 @@ struct visorinput_devdata {
        /* size of following array */
        unsigned int keycode_table_bytes;
        /* for keyboard devices: visorkbd_keycode[] + visorkbd_ext_keycode[] */
-       unsigned char keycode_table[0];
+       unsigned char keycode_table[];
 };
 
 static const guid_t visor_keyboard_channel_guid = VISOR_KEYBOARD_CHANNEL_GUID;
diff --git a/drivers/staging/uwb/Kconfig b/drivers/staging/uwb/Kconfig
deleted file mode 100644 (file)
index 259e053..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# UWB device configuration
-#
-
-menuconfig UWB
-       tristate "Ultra Wideband devices"
-       default n
-       select GENERIC_NET_UTILS
-       help
-         UWB is a high-bandwidth, low-power, point-to-point radio
-         technology using a wide spectrum (3.1-10.6GHz). It is
-         optimized for in-room use (480Mbps at 2 meters, 110Mbps at
-         10m). It serves as the transport layer for other protocols,
-         such as Wireless USB (WUSB).
-
-         The topology is peer to peer; however, higher level
-         protocols (such as WUSB) might impose a master/slave
-         relationship.
-
-         Say Y here if your computer has UWB radio controllers (USB or PCI)
-         based. You will need to enable the radio controllers
-         below.  It is ok to select all of them, no harm done.
-
-         For more help check the UWB and WUSB related files in
-         <file:Documentation/usb/>.
-
-         To compile the UWB stack as a module, choose M here.
-
-if UWB
-
-config UWB_HWA
-       tristate "UWB Radio Control driver for WUSB-compliant USB dongles (HWA)"
-       depends on USB
-       help
-         This driver enables the radio controller for HWA USB
-         devices. HWA stands for Host Wire Adapter, and it is a UWB
-         Radio Controller connected to your system via USB. Most of
-         them come with a Wireless USB host controller also.
-
-         To compile this driver select Y (built in) or M (module). It
-         is safe to select any even if you do not have the hardware.
-
-config UWB_WHCI
-        tristate "UWB Radio Control driver for WHCI-compliant cards"
-        depends on PCI
-        help
-          This driver enables the radio controller for WHCI cards.
-
-          WHCI is a specification developed by Intel
-          (http://www.intel.com/technology/comms/wusb/whci.htm) much
-          in the spirit of USB's EHCI, but for UWB and Wireless USB
-          radio/host controllers connected via memory mapping (eg:
-          PCI). Most of these cards come also with a Wireless USB host
-          controller.
-
-          To compile this driver select Y (built in) or M (module). It
-          is safe to select any even if you do not have the hardware.
-
-config UWB_I1480U
-        tristate "Support for Intel Wireless UWB Link 1480 HWA"
-        depends on UWB_HWA
-        select FW_LOADER
-        help
-         This driver enables support for the i1480 when connected via
-         USB. It consists of a firmware uploader that will enable it
-         to behave as an HWA device.
-
-         To compile this driver select Y (built in) or M (module). It
-         is safe to select any even if you do not have the hardware.
-
-endif # UWB
diff --git a/drivers/staging/uwb/Makefile b/drivers/staging/uwb/Makefile
deleted file mode 100644 (file)
index 32f4de7..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_UWB)              += uwb.o
-obj-$(CONFIG_UWB_WHCI)         += umc.o whci.o whc-rc.o
-obj-$(CONFIG_UWB_HWA)          += hwa-rc.o
-obj-$(CONFIG_UWB_I1480U)       += i1480/
-
-uwb-objs :=            \
-       address.o       \
-       allocator.o     \
-       beacon.o        \
-       driver.o        \
-       drp.o           \
-       drp-avail.o     \
-       drp-ie.o        \
-       est.o           \
-       ie.o            \
-       ie-rcv.o        \
-       lc-dev.o        \
-       lc-rc.o         \
-       neh.o           \
-       pal.o           \
-       radio.o         \
-       reset.o         \
-       rsv.o           \
-       scan.o          \
-       uwb-debug.o     \
-       uwbd.o
-
-umc-objs :=            \
-       umc-bus.o       \
-       umc-dev.o       \
-       umc-drv.o
diff --git a/drivers/staging/uwb/TODO b/drivers/staging/uwb/TODO
deleted file mode 100644 (file)
index abae570..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-TODO: Remove in late 2019 unless there are users
-
-There seems to not be any real wireless USB devices anywhere in the wild
-anymore.  It turned out to be a failed technology :(
-
-This will be removed from the tree if no one objects.
-
-Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/staging/uwb/address.c b/drivers/staging/uwb/address.c
deleted file mode 100644 (file)
index 857d5cd..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Address management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/random.h>
-#include <linux/etherdevice.h>
-
-#include "uwb-internal.h"
-
-
-/** Device Address Management command */
-struct uwb_rc_cmd_dev_addr_mgmt {
-       struct uwb_rccb rccb;
-       u8 bmOperationType;
-       u8 baAddr[6];
-} __attribute__((packed));
-
-
-/**
- * Low level command for setting/getting UWB radio's addresses
- *
- * @hwarc:     HWA Radio Control interface instance
- * @bmOperationType:
- *             Set/get, MAC/DEV (see WUSB1.0[8.6.2.2])
- * @baAddr:    address buffer--assumed to have enough data to hold
- *              the address type requested.
- * @reply:     Pointer to reply buffer (can be stack allocated)
- * @returns:   0 if ok, < 0 errno code on error.
- *
- * @cmd has to be allocated because USB cannot grok USB or vmalloc
- * buffers depending on your combination of host architecture.
- */
-static
-int uwb_rc_dev_addr_mgmt(struct uwb_rc *rc,
-                        u8 bmOperationType, const u8 *baAddr,
-                        struct uwb_rc_evt_dev_addr_mgmt *reply)
-{
-       int result;
-       struct uwb_rc_cmd_dev_addr_mgmt *cmd;
-
-       result = -ENOMEM;
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               goto error_kzalloc;
-       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_DEV_ADDR_MGMT);
-       cmd->bmOperationType = bmOperationType;
-       if (baAddr) {
-               size_t size = 0;
-               switch (bmOperationType >> 1) {
-               case 0: size = 2; break;
-               case 1: size = 6; break;
-               default: BUG();
-               }
-               memcpy(cmd->baAddr, baAddr, size);
-       }
-       reply->rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply->rceb.wEvent = UWB_RC_CMD_DEV_ADDR_MGMT;
-       result = uwb_rc_cmd(rc, "DEV-ADDR-MGMT",
-                           &cmd->rccb, sizeof(*cmd),
-                           &reply->rceb, sizeof(*reply));
-       if (result < 0)
-               goto error_cmd;
-       if (result < sizeof(*reply)) {
-               dev_err(&rc->uwb_dev.dev,
-                       "DEV-ADDR-MGMT: not enough data replied: "
-                       "%d vs %zu bytes needed\n", result, sizeof(*reply));
-               result = -ENOMSG;
-       } else if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "DEV-ADDR-MGMT: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply->bResultCode),
-                       reply->bResultCode);
-               result = -EIO;
-       } else
-               result = 0;
-error_cmd:
-       kfree(cmd);
-error_kzalloc:
-       return result;
-}
-
-
-/**
- * Set the UWB RC MAC or device address.
- *
- * @rc:      UWB Radio Controller
- * @_addr:   Pointer to address to write [assumed to be either a
- *           'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *'].
- * @type:    Type of address to set (UWB_ADDR_DEV or UWB_ADDR_MAC).
- * @returns: 0 if ok, < 0 errno code on error.
- *
- * Some anal retentivity here: even if both 'struct
- * uwb_{dev,mac}_addr' have the actual byte array in the same offset
- * and I could just pass _addr to hwarc_cmd_dev_addr_mgmt(), I prefer
- * to use some syntatic sugar in case someday we decide to change the
- * format of the structs. The compiler will optimize it out anyway.
- */
-static int uwb_rc_addr_set(struct uwb_rc *rc,
-                   const void *_addr, enum uwb_addr_type type)
-{
-       int result;
-       u8 bmOperationType = 0x1;               /* Set address */
-       const struct uwb_dev_addr *dev_addr = _addr;
-       const struct uwb_mac_addr *mac_addr = _addr;
-       struct uwb_rc_evt_dev_addr_mgmt reply;
-       const u8 *baAddr;
-
-       result = -EINVAL;
-       switch (type) {
-       case UWB_ADDR_DEV:
-               baAddr = dev_addr->data;
-               break;
-       case UWB_ADDR_MAC:
-               baAddr = mac_addr->data;
-               bmOperationType |= 0x2;
-               break;
-       default:
-               return result;
-       }
-       return uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &reply);
-}
-
-
-/**
- * Get the UWB radio's MAC or device address.
- *
- * @rc:      UWB Radio Controller
- * @_addr:   Where to write the address data [assumed to be either a
- *           'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *'].
- * @type:    Type of address to get (UWB_ADDR_DEV or UWB_ADDR_MAC).
- * @returns: 0 if ok (and *_addr set), < 0 errno code on error.
- *
- * See comment in uwb_rc_addr_set() about anal retentivity in the
- * type handling of the address variables.
- */
-static int uwb_rc_addr_get(struct uwb_rc *rc,
-                   void *_addr, enum uwb_addr_type type)
-{
-       int result;
-       u8 bmOperationType = 0x0;               /* Get address */
-       struct uwb_rc_evt_dev_addr_mgmt evt;
-       struct uwb_dev_addr *dev_addr = _addr;
-       struct uwb_mac_addr *mac_addr = _addr;
-       u8 *baAddr;
-
-       result = -EINVAL;
-       switch (type) {
-       case UWB_ADDR_DEV:
-               baAddr = dev_addr->data;
-               break;
-       case UWB_ADDR_MAC:
-               bmOperationType |= 0x2;
-               baAddr = mac_addr->data;
-               break;
-       default:
-               return result;
-       }
-       result = uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &evt);
-       if (result == 0)
-               switch (type) {
-               case UWB_ADDR_DEV:
-                       memcpy(&dev_addr->data, evt.baAddr,
-                              sizeof(dev_addr->data));
-                       break;
-               case UWB_ADDR_MAC:
-                       memcpy(&mac_addr->data, evt.baAddr,
-                              sizeof(mac_addr->data));
-                       break;
-               default:                /* shut gcc up */
-                       BUG();
-               }
-       return result;
-}
-
-
-/** Get @rc's MAC address to @addr */
-int uwb_rc_mac_addr_get(struct uwb_rc *rc,
-                       struct uwb_mac_addr *addr) {
-       return uwb_rc_addr_get(rc, addr, UWB_ADDR_MAC);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_mac_addr_get);
-
-
-/** Get @rc's device address to @addr */
-int uwb_rc_dev_addr_get(struct uwb_rc *rc,
-                       struct uwb_dev_addr *addr) {
-       return uwb_rc_addr_get(rc, addr, UWB_ADDR_DEV);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_dev_addr_get);
-
-
-/** Set @rc's address to @addr */
-int uwb_rc_mac_addr_set(struct uwb_rc *rc,
-                       const struct uwb_mac_addr *addr)
-{
-       int result = -EINVAL;
-       mutex_lock(&rc->uwb_dev.mutex);
-       result = uwb_rc_addr_set(rc, addr, UWB_ADDR_MAC);
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return result;
-}
-
-
-/** Set @rc's address to @addr */
-int uwb_rc_dev_addr_set(struct uwb_rc *rc,
-                       const struct uwb_dev_addr *addr)
-{
-       int result = -EINVAL;
-       mutex_lock(&rc->uwb_dev.mutex);
-       result = uwb_rc_addr_set(rc, addr, UWB_ADDR_DEV);
-       rc->uwb_dev.dev_addr = *addr;
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return result;
-}
-
-/* Returns !0 if given address is already assigned to device. */
-int __uwb_mac_addr_assigned_check(struct device *dev, void *_addr)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_mac_addr *addr = _addr;
-
-       if (!uwb_mac_addr_cmp(addr, &uwb_dev->mac_addr))
-               return !0;
-       return 0;
-}
-
-/* Returns !0 if given address is already assigned to device. */
-int __uwb_dev_addr_assigned_check(struct device *dev, void *_addr)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_dev_addr *addr = _addr;
-       if (!uwb_dev_addr_cmp(addr, &uwb_dev->dev_addr))
-               return !0;
-       return 0;
-}
-
-/**
- * uwb_dev_addr_assign - assigned a generated DevAddr to a radio controller
- * @rc:      the (local) radio controller device requiring a new DevAddr
- *
- * A new DevAddr is required when:
- *    - first setting up a radio controller
- *    - if the hardware reports a DevAddr conflict
- *
- * The DevAddr is randomly generated in the generated DevAddr range
- * [0x100, 0xfeff]. The number of devices in a beacon group is limited
- * by mMaxBPLength (96) so this address space will never be exhausted.
- *
- * [ECMA-368] 17.1.1, 17.16.
- */
-int uwb_rc_dev_addr_assign(struct uwb_rc *rc)
-{
-       struct uwb_dev_addr new_addr;
-
-       do {
-               get_random_bytes(new_addr.data, sizeof(new_addr.data));
-       } while (new_addr.data[0] == 0x00 || new_addr.data[0] == 0xff
-                || __uwb_dev_addr_assigned(rc, &new_addr));
-
-       return uwb_rc_dev_addr_set(rc, &new_addr);
-}
-
-/**
- * uwbd_evt_handle_rc_dev_addr_conflict - handle a DEV_ADDR_CONFLICT event
- * @evt: the DEV_ADDR_CONFLICT notification from the radio controller
- *
- * A new (non-conflicting) DevAddr is assigned to the radio controller.
- *
- * [ECMA-368] 17.1.1.1.
- */
-int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt)
-{
-       struct uwb_rc *rc = evt->rc;
-
-       return uwb_rc_dev_addr_assign(rc);
-}
-
-/*
- * Print the 48-bit EUI MAC address of the radio controller when
- * reading /sys/class/uwb_rc/XX/mac_address
- */
-static ssize_t uwb_rc_mac_addr_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_rc *rc = uwb_dev->rc;
-       struct uwb_mac_addr addr;
-       ssize_t result;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       result = uwb_rc_addr_get(rc, &addr, UWB_ADDR_MAC);
-       mutex_unlock(&rc->uwb_dev.mutex);
-       if (result >= 0) {
-               result = uwb_mac_addr_print(buf, UWB_ADDR_STRSIZE, &addr);
-               buf[result++] = '\n';
-       }
-       return result;
-}
-
-/*
- * Parse a 48 bit address written to /sys/class/uwb_rc/XX/mac_address
- * and if correct, set it.
- */
-static ssize_t uwb_rc_mac_addr_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t size)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_rc *rc = uwb_dev->rc;
-       struct uwb_mac_addr addr;
-       ssize_t result;
-
-       if (!mac_pton(buf, addr.data))
-               return -EINVAL;
-       if (is_multicast_ether_addr(addr.data)) {
-               dev_err(&rc->uwb_dev.dev, "refusing to set multicast "
-                       "MAC address %s\n", buf);
-               return -EINVAL;
-       }
-       result = uwb_rc_mac_addr_set(rc, &addr);
-       if (result == 0)
-               rc->uwb_dev.mac_addr = addr;
-
-       return result < 0 ? result : size;
-}
-DEVICE_ATTR(mac_address, S_IRUGO | S_IWUSR, uwb_rc_mac_addr_show, uwb_rc_mac_addr_store);
-
-/** Print @addr to @buf, @return bytes written */
-size_t __uwb_addr_print(char *buf, size_t buf_size, const unsigned char *addr,
-                       int type)
-{
-       size_t result;
-       if (type)
-               result = scnprintf(buf, buf_size, "%pM", addr);
-       else
-               result = scnprintf(buf, buf_size, "%02x:%02x",
-                                 addr[1], addr[0]);
-       return result;
-}
-EXPORT_SYMBOL_GPL(__uwb_addr_print);
diff --git a/drivers/staging/uwb/allocator.c b/drivers/staging/uwb/allocator.c
deleted file mode 100644 (file)
index 1f429fb..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB reservation management.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include "uwb.h"
-
-#include "uwb-internal.h"
-
-static void uwb_rsv_fill_column_alloc(struct uwb_rsv_alloc_info *ai)
-{
-       int col, mas, safe_mas, unsafe_mas;
-       unsigned char *bm = ai->bm;
-       struct uwb_rsv_col_info *ci = ai->ci;
-       unsigned char c;
-
-       for (col = ci->csi.start_col; col < UWB_NUM_ZONES; col += ci->csi.interval) {
-    
-               safe_mas   = ci->csi.safe_mas_per_col;
-               unsafe_mas = ci->csi.unsafe_mas_per_col;
-    
-               for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++ ) {
-                       if (bm[col * UWB_MAS_PER_ZONE + mas] == 0) {
-       
-                               if (safe_mas > 0) {
-                                       safe_mas--;
-                                       c = UWB_RSV_MAS_SAFE;
-                               } else if (unsafe_mas > 0) {
-                                       unsafe_mas--;
-                                       c = UWB_RSV_MAS_UNSAFE;
-                               } else {
-                                       break;
-                               }
-                               bm[col * UWB_MAS_PER_ZONE + mas] = c;
-                       }
-               }
-       }
-}
-
-static void uwb_rsv_fill_row_alloc(struct uwb_rsv_alloc_info *ai)
-{
-       int mas, col, rows;
-       unsigned char *bm = ai->bm;
-       struct uwb_rsv_row_info *ri = &ai->ri;
-       unsigned char c;
-
-       rows = 1;
-       c = UWB_RSV_MAS_SAFE;
-       for (mas = UWB_MAS_PER_ZONE - 1; mas >= 0; mas--) {
-               if (ri->avail[mas] == 1) {
-      
-                       if (rows > ri->used_rows) {
-                               break;
-                       } else if (rows > 7) {
-                               c = UWB_RSV_MAS_UNSAFE;
-                       }
-
-                       for (col = 0; col < UWB_NUM_ZONES; col++) {
-                               if (bm[col * UWB_NUM_ZONES + mas] != UWB_RSV_MAS_NOT_AVAIL) {
-                                       bm[col * UWB_NUM_ZONES + mas] = c;
-                                       if(c == UWB_RSV_MAS_SAFE)
-                                               ai->safe_allocated_mases++;
-                                       else
-                                               ai->unsafe_allocated_mases++;
-                               }
-                       }
-                       rows++;
-               }
-       }
-       ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases;
-}
-
-/*
- * Find the best column set for a given availability, interval, num safe mas and
- * num unsafe mas.
- *
- * The different sets are tried in order as shown below, depending on the interval.
- *
- * interval = 16
- *     deep = 0
- *             set 1 ->  {  8 }
- *     deep = 1
- *             set 1 ->  {  4 }
- *             set 2 ->  { 12 }
- *     deep = 2
- *             set 1 ->  {  2 }
- *             set 2 ->  {  6 }
- *             set 3 ->  { 10 }
- *             set 4 ->  { 14 }
- *     deep = 3
- *             set 1 ->  {  1 }
- *             set 2 ->  {  3 }
- *             set 3 ->  {  5 }
- *             set 4 ->  {  7 }
- *             set 5 ->  {  9 }
- *             set 6 ->  { 11 }
- *             set 7 ->  { 13 }
- *             set 8 ->  { 15 }
- *
- * interval = 8
- *     deep = 0
- *             set 1 ->  {  4  12 }
- *     deep = 1
- *             set 1 ->  {  2  10 }
- *             set 2 ->  {  6  14 }
- *     deep = 2
- *             set 1 ->  {  1   9 }
- *             set 2 ->  {  3  11 }
- *             set 3 ->  {  5  13 }
- *             set 4 ->  {  7  15 }
- *
- * interval = 4
- *     deep = 0
- *             set 1 ->  {  2   6  10  14 }
- *     deep = 1
- *             set 1 ->  {  1   5   9  13 }
- *             set 2 ->  {  3   7  11  15 }
- *
- * interval = 2
- *     deep = 0
- *             set 1 ->  {  1   3   5   7   9  11  13  15 }
- */
-static int uwb_rsv_find_best_column_set(struct uwb_rsv_alloc_info *ai, int interval, 
-                                       int num_safe_mas, int num_unsafe_mas)
-{
-       struct uwb_rsv_col_info *ci = ai->ci;
-       struct uwb_rsv_col_set_info *csi = &ci->csi;
-       struct uwb_rsv_col_set_info tmp_csi;
-       int deep, set, col, start_col_deep, col_start_set;
-       int start_col, max_mas_in_set, lowest_max_mas_in_deep;
-       int n_mas;
-       int found = UWB_RSV_ALLOC_NOT_FOUND; 
-
-       tmp_csi.start_col = 0;
-       start_col_deep = interval;
-       n_mas = num_unsafe_mas + num_safe_mas;
-
-       for (deep = 0; ((interval >> deep) & 0x1) == 0; deep++) {
-               start_col_deep /= 2;
-               col_start_set = 0;
-               lowest_max_mas_in_deep = UWB_MAS_PER_ZONE;
-
-               for (set = 1; set <= (1 << deep); set++) {
-                       max_mas_in_set = 0;
-                       start_col = start_col_deep + col_start_set;
-                       for (col = start_col; col < UWB_NUM_ZONES; col += interval) {
-                
-                               if (ci[col].max_avail_safe >= num_safe_mas &&
-                                   ci[col].max_avail_unsafe >= n_mas) {
-                                       if (ci[col].highest_mas[n_mas] > max_mas_in_set)
-                                               max_mas_in_set = ci[col].highest_mas[n_mas];
-                               } else {
-                                       max_mas_in_set = 0;
-                                       break;
-                               }
-                       }
-                       if ((lowest_max_mas_in_deep > max_mas_in_set) && max_mas_in_set) {
-                               lowest_max_mas_in_deep = max_mas_in_set;
-
-                               tmp_csi.start_col = start_col;
-                       }
-                       col_start_set += (interval >> deep);
-               }
-
-               if (lowest_max_mas_in_deep < 8) {
-                       csi->start_col = tmp_csi.start_col;
-                       found = UWB_RSV_ALLOC_FOUND;
-                       break;
-               } else if ((lowest_max_mas_in_deep > 8) && 
-                          (lowest_max_mas_in_deep != UWB_MAS_PER_ZONE) &&
-                          (found == UWB_RSV_ALLOC_NOT_FOUND)) {
-                       csi->start_col = tmp_csi.start_col;
-                       found = UWB_RSV_ALLOC_FOUND;
-               }
-       }
-
-       if (found == UWB_RSV_ALLOC_FOUND) {
-               csi->interval = interval;
-               csi->safe_mas_per_col = num_safe_mas;
-               csi->unsafe_mas_per_col = num_unsafe_mas;
-
-               ai->safe_allocated_mases = (UWB_NUM_ZONES / interval) * num_safe_mas;
-               ai->unsafe_allocated_mases = (UWB_NUM_ZONES / interval) * num_unsafe_mas;
-               ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases;
-               ai->interval = interval;                
-       }
-       return found;
-}
-
-static void get_row_descriptors(struct uwb_rsv_alloc_info *ai)
-{
-       unsigned char *bm = ai->bm;
-       struct uwb_rsv_row_info *ri = &ai->ri;
-       int col, mas;
-  
-       ri->free_rows = 16;
-       for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) {
-               ri->avail[mas] = 1;
-               for (col = 1; col < UWB_NUM_ZONES; col++) {
-                       if (bm[col * UWB_NUM_ZONES + mas] == UWB_RSV_MAS_NOT_AVAIL) {
-                               ri->free_rows--;
-                               ri->avail[mas]=0;
-                               break;
-                       }
-               }
-       }
-}
-
-static void uwb_rsv_fill_column_info(unsigned char *bm, int column, struct uwb_rsv_col_info *rci)
-{
-       int mas;
-       int block_count = 0, start_block = 0; 
-       int previous_avail = 0;
-       int available = 0;
-       int safe_mas_in_row[UWB_MAS_PER_ZONE] = {
-               8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1,
-       };
-
-       rci->max_avail_safe = 0;
-
-       for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) {
-               if (!bm[column * UWB_NUM_ZONES + mas]) {
-                       available++;
-                       rci->max_avail_unsafe = available;
-
-                       rci->highest_mas[available] = mas;
-
-                       if (previous_avail) {
-                               block_count++;
-                               if ((block_count > safe_mas_in_row[start_block]) &&
-                                   (!rci->max_avail_safe))
-                                       rci->max_avail_safe = available - 1;
-                       } else {
-                               previous_avail = 1;
-                               start_block = mas;
-                               block_count = 1;
-                       }
-               } else {
-                       previous_avail = 0;
-               }
-       }
-       if (!rci->max_avail_safe)
-               rci->max_avail_safe = rci->max_avail_unsafe;
-}
-
-static void get_column_descriptors(struct uwb_rsv_alloc_info *ai)
-{
-       unsigned char *bm = ai->bm;
-       struct uwb_rsv_col_info *ci = ai->ci;
-       int col;
-
-       for (col = 1; col < UWB_NUM_ZONES; col++) {
-               uwb_rsv_fill_column_info(bm, col, &ci[col]);
-       }
-}
-
-static int uwb_rsv_find_best_row_alloc(struct uwb_rsv_alloc_info *ai)
-{
-       int n_rows;
-       int max_rows = ai->max_mas / UWB_USABLE_MAS_PER_ROW;
-       int min_rows = ai->min_mas / UWB_USABLE_MAS_PER_ROW;
-       if (ai->min_mas % UWB_USABLE_MAS_PER_ROW)
-               min_rows++;
-       for (n_rows = max_rows; n_rows >= min_rows; n_rows--) {
-               if (n_rows <= ai->ri.free_rows) {
-                       ai->ri.used_rows = n_rows;
-                       ai->interval = 1; /* row reservation */
-                       uwb_rsv_fill_row_alloc(ai);
-                       return UWB_RSV_ALLOC_FOUND;
-               }
-       }  
-       return UWB_RSV_ALLOC_NOT_FOUND;
-}
-
-static int uwb_rsv_find_best_col_alloc(struct uwb_rsv_alloc_info *ai, int interval)
-{
-       int n_safe, n_unsafe, n_mas;  
-       int n_column = UWB_NUM_ZONES / interval;
-       int max_per_zone = ai->max_mas / n_column;
-       int min_per_zone = ai->min_mas / n_column;
-
-       if (ai->min_mas % n_column)
-               min_per_zone++;
-
-       if (min_per_zone > UWB_MAS_PER_ZONE) {
-               return UWB_RSV_ALLOC_NOT_FOUND;
-       }
-    
-       if (max_per_zone > UWB_MAS_PER_ZONE) {
-               max_per_zone = UWB_MAS_PER_ZONE;
-       }
-    
-       for (n_mas = max_per_zone; n_mas >= min_per_zone; n_mas--) {
-               if (uwb_rsv_find_best_column_set(ai, interval, 0, n_mas) == UWB_RSV_ALLOC_NOT_FOUND)
-                       continue;
-               for (n_safe = n_mas; n_safe >= 0; n_safe--) {
-                       n_unsafe = n_mas - n_safe;
-                       if (uwb_rsv_find_best_column_set(ai, interval, n_safe, n_unsafe) == UWB_RSV_ALLOC_FOUND) {
-                               uwb_rsv_fill_column_alloc(ai);
-                               return UWB_RSV_ALLOC_FOUND;
-                       }
-               }
-       }
-       return UWB_RSV_ALLOC_NOT_FOUND;
-}
-
-int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *available, 
-                                struct uwb_mas_bm *result)
-{
-       struct uwb_rsv_alloc_info *ai;
-       int interval;
-       int bit_index;
-
-       ai = kzalloc(sizeof(struct uwb_rsv_alloc_info), GFP_KERNEL);
-       if (!ai)
-               return UWB_RSV_ALLOC_NOT_FOUND;
-       ai->min_mas = rsv->min_mas;
-       ai->max_mas = rsv->max_mas;
-       ai->max_interval = rsv->max_interval;
-
-
-       /* fill the not available vector from the available bm */
-       for_each_clear_bit(bit_index, available->bm, UWB_NUM_MAS)
-               ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL;
-
-       if (ai->max_interval == 1) {
-               get_row_descriptors(ai);
-               if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND)
-                       goto alloc_found;
-               else
-                       goto alloc_not_found;
-       }
-
-       get_column_descriptors(ai);
-        
-       for (interval = 16; interval >= 2; interval>>=1) {
-               if (interval > ai->max_interval)
-                       continue;
-               if (uwb_rsv_find_best_col_alloc(ai, interval) == UWB_RSV_ALLOC_FOUND)
-                       goto alloc_found;
-       }
-
-       /* try row reservation if no column is found */
-       get_row_descriptors(ai);
-       if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND)
-               goto alloc_found;
-       else
-               goto alloc_not_found;
-
-  alloc_found:
-       bitmap_zero(result->bm, UWB_NUM_MAS);
-       bitmap_zero(result->unsafe_bm, UWB_NUM_MAS);
-       /* fill the safe and unsafe bitmaps */
-       for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) {
-               if (ai->bm[bit_index] == UWB_RSV_MAS_SAFE)
-                       set_bit(bit_index, result->bm);
-               else if (ai->bm[bit_index] == UWB_RSV_MAS_UNSAFE)
-                       set_bit(bit_index, result->unsafe_bm);
-       }
-       bitmap_or(result->bm, result->bm, result->unsafe_bm, UWB_NUM_MAS);
-
-       result->safe   = ai->safe_allocated_mases;
-       result->unsafe = ai->unsafe_allocated_mases;
-       
-       kfree(ai);              
-       return UWB_RSV_ALLOC_FOUND;
-  
-  alloc_not_found:
-       kfree(ai);
-       return UWB_RSV_ALLOC_NOT_FOUND;
-}
diff --git a/drivers/staging/uwb/beacon.c b/drivers/staging/uwb/beacon.c
deleted file mode 100644 (file)
index c483c19..0000000
+++ /dev/null
@@ -1,595 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Beacon management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/kdev_t.h>
-#include <linux/slab.h>
-
-#include "uwb-internal.h"
-
-/* Start Beaconing command structure */
-struct uwb_rc_cmd_start_beacon {
-       struct uwb_rccb rccb;
-       __le16 wBPSTOffset;
-       u8 bChannelNumber;
-} __attribute__((packed));
-
-
-static int uwb_rc_start_beacon(struct uwb_rc *rc, u16 bpst_offset, u8 channel)
-{
-       int result;
-       struct uwb_rc_cmd_start_beacon *cmd;
-       struct uwb_rc_evt_confirm reply;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_START_BEACON);
-       cmd->wBPSTOffset = cpu_to_le16(bpst_offset);
-       cmd->bChannelNumber = channel;
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_START_BEACON;
-       result = uwb_rc_cmd(rc, "START-BEACON", &cmd->rccb, sizeof(*cmd),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "START-BEACON: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-       }
-error_cmd:
-       kfree(cmd);
-       return result;
-}
-
-static int uwb_rc_stop_beacon(struct uwb_rc *rc)
-{
-       int result;
-       struct uwb_rccb *cmd;
-       struct uwb_rc_evt_confirm reply;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-       cmd->bCommandType = UWB_RC_CET_GENERAL;
-       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_STOP_BEACON);
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_STOP_BEACON;
-       result = uwb_rc_cmd(rc, "STOP-BEACON", cmd, sizeof(*cmd),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "STOP-BEACON: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-       }
-error_cmd:
-       kfree(cmd);
-       return result;
-}
-
-/*
- * Start/stop beacons
- *
- * @rc:          UWB Radio Controller to operate on
- * @channel:     UWB channel on which to beacon (WUSB[table
- *               5-12]). If -1, stop beaconing.
- * @bpst_offset: Beacon Period Start Time offset; FIXME-do zero
- *
- * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
- * of a SET IE command after the device sent the first beacon that includes
- * the IEs specified in the SET IE command. So, after we start beaconing we
- * check if there is anything in the IE cache and call the SET IE command
- * if needed.
- */
-int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       dev_dbg(dev, "%s: channel = %d\n", __func__, channel);
-       if (channel < 0)
-               channel = -1;
-       if (channel == -1)
-               result = uwb_rc_stop_beacon(rc);
-       else {
-               /* channel >= 0...dah */
-               result = uwb_rc_start_beacon(rc, bpst_offset, channel);
-               if (result < 0) {
-                       dev_err(dev, "Cannot start beaconing: %d\n", result);
-                       return result;
-               }
-               if (le16_to_cpu(rc->ies->wIELength) > 0) {
-                       result = uwb_rc_set_ie(rc, rc->ies);
-                       if (result < 0) {
-                               dev_err(dev, "Cannot set new IE on device: "
-                                       "%d\n", result);
-                               result = uwb_rc_stop_beacon(rc);
-                               channel = -1;
-                               bpst_offset = 0;
-                       }
-               }
-       }
-
-       if (result >= 0)
-               rc->beaconing = channel;
-       return result;
-}
-
-/*
- * Beacon cache
- *
- * The purpose of this is to speed up the lookup of becon information
- * when a new beacon arrives. The UWB Daemon uses it also to keep a
- * tab of which devices are in radio distance and which not. When a
- * device's beacon stays present for more than a certain amount of
- * time, it is considered a new, usable device. When a beacon ceases
- * to be received for a certain amount of time, it is considered that
- * the device is gone.
- *
- * FIXME: use an allocator for the entries
- * FIXME: use something faster for search than a list
- */
-
-void uwb_bce_kfree(struct kref *_bce)
-{
-       struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt);
-
-       kfree(bce->be);
-       kfree(bce);
-}
-
-
-/* Find a beacon by dev addr in the cache */
-static
-struct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc,
-                                        const struct uwb_dev_addr *dev_addr)
-{
-       struct uwb_beca_e *bce, *next;
-       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
-               if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr)))
-                       goto out;
-       }
-       bce = NULL;
-out:
-       return bce;
-}
-
-/* Find a beacon by dev addr in the cache */
-static
-struct uwb_beca_e *__uwb_beca_find_bymac(struct uwb_rc *rc,
-                                        const struct uwb_mac_addr *mac_addr)
-{
-       struct uwb_beca_e *bce, *next;
-       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
-               if (!memcmp(bce->mac_addr, mac_addr->data,
-                           sizeof(struct uwb_mac_addr)))
-                       goto out;
-       }
-       bce = NULL;
-out:
-       return bce;
-}
-
-/**
- * uwb_dev_get_by_devaddr - get a UWB device with a specific DevAddr
- * @rc:      the radio controller that saw the device
- * @devaddr: DevAddr of the UWB device to find
- *
- * There may be more than one matching device (in the case of a
- * DevAddr conflict), but only the first one is returned.
- */
-struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
-                                      const struct uwb_dev_addr *devaddr)
-{
-       struct uwb_dev *found = NULL;
-       struct uwb_beca_e *bce;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       bce = __uwb_beca_find_bydev(rc, devaddr);
-       if (bce)
-               found = uwb_dev_try_get(rc, bce->uwb_dev);
-       mutex_unlock(&rc->uwb_beca.mutex);
-
-       return found;
-}
-
-/**
- * uwb_dev_get_by_macaddr - get a UWB device with a specific EUI-48
- * @rc:      the radio controller that saw the device
- * @devaddr: EUI-48 of the UWB device to find
- */
-struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
-                                      const struct uwb_mac_addr *macaddr)
-{
-       struct uwb_dev *found = NULL;
-       struct uwb_beca_e *bce;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       bce = __uwb_beca_find_bymac(rc, macaddr);
-       if (bce)
-               found = uwb_dev_try_get(rc, bce->uwb_dev);
-       mutex_unlock(&rc->uwb_beca.mutex);
-
-       return found;
-}
-
-/* Initialize a beacon cache entry */
-static void uwb_beca_e_init(struct uwb_beca_e *bce)
-{
-       mutex_init(&bce->mutex);
-       kref_init(&bce->refcnt);
-       stats_init(&bce->lqe_stats);
-       stats_init(&bce->rssi_stats);
-}
-
-/*
- * Add a beacon to the cache
- *
- * @be:         Beacon event information
- * @bf:         Beacon frame (part of b, really)
- * @ts_jiffies: Timestamp (in jiffies) when the beacon was received
- */
-static
-struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc,
-                                 struct uwb_rc_evt_beacon *be,
-                                 struct uwb_beacon_frame *bf,
-                                 unsigned long ts_jiffies)
-{
-       struct uwb_beca_e *bce;
-
-       bce = kzalloc(sizeof(*bce), GFP_KERNEL);
-       if (bce == NULL)
-               return NULL;
-       uwb_beca_e_init(bce);
-       bce->ts_jiffies = ts_jiffies;
-       bce->uwb_dev = NULL;
-       list_add(&bce->node, &rc->uwb_beca.list);
-       return bce;
-}
-
-/*
- * Wipe out beacon entries that became stale
- *
- * Remove associated devicest too.
- */
-void uwb_beca_purge(struct uwb_rc *rc)
-{
-       struct uwb_beca_e *bce, *next;
-       unsigned long expires;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
-               expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms);
-               if (time_after(jiffies, expires)) {
-                       uwbd_dev_offair(bce);
-               }
-       }
-       mutex_unlock(&rc->uwb_beca.mutex);
-}
-
-/* Clean up the whole beacon cache. Called on shutdown */
-void uwb_beca_release(struct uwb_rc *rc)
-{
-       struct uwb_beca_e *bce, *next;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
-               list_del(&bce->node);
-               uwb_bce_put(bce);
-       }
-       mutex_unlock(&rc->uwb_beca.mutex);
-}
-
-static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be,
-                            struct uwb_beacon_frame *bf)
-{
-       char macbuf[UWB_ADDR_STRSIZE];
-       char devbuf[UWB_ADDR_STRSIZE];
-       char dstbuf[UWB_ADDR_STRSIZE];
-
-       uwb_mac_addr_print(macbuf, sizeof(macbuf), &bf->Device_Identifier);
-       uwb_dev_addr_print(devbuf, sizeof(devbuf), &bf->hdr.SrcAddr);
-       uwb_dev_addr_print(dstbuf, sizeof(dstbuf), &bf->hdr.DestAddr);
-       dev_info(&rc->uwb_dev.dev,
-                "BEACON from %s to %s (ch%u offset %u slot %u MAC %s)\n",
-                devbuf, dstbuf, be->bChannelNumber, be->wBPSTOffset,
-                bf->Beacon_Slot_Number, macbuf);
-}
-
-/*
- * @bce: beacon cache entry, referenced
- */
-ssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce,
-                         char *buf, size_t size)
-{
-       ssize_t result = 0;
-       struct uwb_rc_evt_beacon *be;
-       struct uwb_beacon_frame *bf;
-       int ies_len;
-       struct uwb_ie_hdr *ies;
-
-       mutex_lock(&bce->mutex);
-
-       be = bce->be;
-       if (be) {
-               bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
-               ies_len = be->wBeaconInfoLength - sizeof(struct uwb_beacon_frame);
-               ies = (struct uwb_ie_hdr *)bf->IEData;
-
-               result = uwb_ie_dump_hex(ies, ies_len, buf, size);
-       }
-
-       mutex_unlock(&bce->mutex);
-
-       return result;
-}
-
-/*
- * Verify that the beacon event, frame and IEs are ok
- */
-static int uwb_verify_beacon(struct uwb_rc *rc, struct uwb_event *evt,
-                            struct uwb_rc_evt_beacon *be)
-{
-       int result = -EINVAL;
-       struct uwb_beacon_frame *bf;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       /* Is there enough data to decode a beacon frame? */
-       if (evt->notif.size < sizeof(*be) + sizeof(*bf)) {
-               dev_err(dev, "BEACON event: Not enough data to decode "
-                       "(%zu vs %zu bytes needed)\n", evt->notif.size,
-                       sizeof(*be) + sizeof(*bf));
-               goto error;
-       }
-       /* FIXME: make sure beacon frame IEs are fine and that the whole thing
-        * is consistent */
-       result = 0;
-error:
-       return result;
-}
-
-/*
- * Handle UWB_RC_EVT_BEACON events
- *
- * We check the beacon cache to see how the received beacon fares. If
- * is there already we refresh the timestamp. If not we create a new
- * entry.
- *
- * According to the WHCI and WUSB specs, only one beacon frame is
- * allowed per notification block, so we don't bother about scanning
- * for more.
- */
-int uwbd_evt_handle_rc_beacon(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct uwb_rc *rc;
-       struct uwb_rc_evt_beacon *be;
-       struct uwb_beacon_frame *bf;
-       struct uwb_beca_e *bce;
-
-       rc = evt->rc;
-       be = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon, rceb);
-       result = uwb_verify_beacon(rc, evt, be);
-       if (result < 0)
-               return result;
-
-       /* FIXME: handle alien beacons. */
-       if (be->bBeaconType == UWB_RC_BEACON_TYPE_OL_ALIEN ||
-           be->bBeaconType == UWB_RC_BEACON_TYPE_NOL_ALIEN) {
-               return -ENOSYS;
-       }
-
-       bf = (struct uwb_beacon_frame *) be->BeaconInfo;
-
-       /*
-        * Drop beacons from devices with a NULL EUI-48 -- they cannot
-        * be uniquely identified.
-        *
-        * It's expected that these will all be WUSB devices and they
-        * have a WUSB specific connection method so ignoring them
-        * here shouldn't be a problem.
-        */
-       if (uwb_mac_addr_bcast(&bf->Device_Identifier))
-               return 0;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       bce = __uwb_beca_find_bymac(rc, &bf->Device_Identifier);
-       if (bce == NULL) {
-               /* Not in there, a new device is pinging */
-               uwb_beacon_print(evt->rc, be, bf);
-               bce = __uwb_beca_add(rc, be, bf, evt->ts_jiffies);
-               if (bce == NULL) {
-                       mutex_unlock(&rc->uwb_beca.mutex);
-                       return -ENOMEM;
-               }
-       }
-       mutex_unlock(&rc->uwb_beca.mutex);
-
-       mutex_lock(&bce->mutex);
-       /* purge old beacon data */
-       kfree(bce->be);
-
-       /* Update commonly used fields */
-       bce->ts_jiffies = evt->ts_jiffies;
-       bce->be = be;
-       bce->dev_addr = bf->hdr.SrcAddr;
-       bce->mac_addr = &bf->Device_Identifier;
-       be->wBPSTOffset = le16_to_cpu(be->wBPSTOffset);
-       be->wBeaconInfoLength = le16_to_cpu(be->wBeaconInfoLength);
-       stats_add_sample(&bce->lqe_stats, be->bLQI - 7);
-       stats_add_sample(&bce->rssi_stats, be->bRSSI + 18);
-
-       /*
-        * This might be a beacon from a new device.
-        */
-       if (bce->uwb_dev == NULL)
-               uwbd_dev_onair(evt->rc, bce);
-
-       mutex_unlock(&bce->mutex);
-
-       return 1; /* we keep the event data */
-}
-
-/*
- * Handle UWB_RC_EVT_BEACON_SIZE events
- *
- * XXXXX
- */
-int uwbd_evt_handle_rc_beacon_size(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc_evt_beacon_size *bs;
-
-       /* Is there enough data to decode the event? */
-       if (evt->notif.size < sizeof(*bs)) {
-               dev_err(dev, "BEACON SIZE notification: Not enough data to "
-                       "decode (%zu vs %zu bytes needed)\n",
-                       evt->notif.size, sizeof(*bs));
-               goto error;
-       }
-       bs = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon_size, rceb);
-       if (0)
-               dev_info(dev, "Beacon size changed to %u bytes "
-                       "(FIXME: action?)\n", le16_to_cpu(bs->wNewBeaconSize));
-       else {
-               /* temporary hack until we do something with this message... */
-               static unsigned count;
-               if (++count % 1000 == 0)
-                       dev_info(dev, "Beacon size changed %u times "
-                               "(FIXME: action?)\n", count);
-       }
-       result = 0;
-error:
-       return result;
-}
-
-/**
- * uwbd_evt_handle_rc_bp_slot_change - handle a BP_SLOT_CHANGE event
- * @evt: the BP_SLOT_CHANGE notification from the radio controller
- *
- * If the event indicates that no beacon period slots were available
- * then radio controller has transitioned to a non-beaconing state.
- * Otherwise, simply save the current beacon slot.
- */
-int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *evt)
-{
-       struct uwb_rc *rc = evt->rc;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_evt_bp_slot_change *bpsc;
-
-       if (evt->notif.size < sizeof(*bpsc)) {
-               dev_err(dev, "BP SLOT CHANGE event: Not enough data\n");
-               return -EINVAL;
-       }
-       bpsc = container_of(evt->notif.rceb, struct uwb_rc_evt_bp_slot_change, rceb);
-
-       if (uwb_rc_evt_bp_slot_change_no_slot(bpsc)) {
-               dev_err(dev, "stopped beaconing: No free slots in BP\n");
-               mutex_lock(&rc->uwb_dev.mutex);
-               rc->beaconing = -1;
-               mutex_unlock(&rc->uwb_dev.mutex);
-       } else
-               rc->uwb_dev.beacon_slot = uwb_rc_evt_bp_slot_change_slot_num(bpsc);
-
-       return 0;
-}
-
-/**
- * Handle UWB_RC_EVT_BPOIE_CHANGE events
- *
- * XXXXX
- */
-struct uwb_ie_bpo {
-       struct uwb_ie_hdr hdr;
-       u8                bp_length;
-       u8                data[];
-} __attribute__((packed));
-
-int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc_evt_bpoie_change *bpoiec;
-       struct uwb_ie_bpo *bpoie;
-       static unsigned count;  /* FIXME: this is a temp hack */
-       size_t iesize;
-
-       /* Is there enough data to decode it? */
-       if (evt->notif.size < sizeof(*bpoiec)) {
-               dev_err(dev, "BPOIEC notification: Not enough data to "
-                       "decode (%zu vs %zu bytes needed)\n",
-                       evt->notif.size, sizeof(*bpoiec));
-               goto error;
-       }
-       bpoiec = container_of(evt->notif.rceb, struct uwb_rc_evt_bpoie_change, rceb);
-       iesize = le16_to_cpu(bpoiec->wBPOIELength);
-       if (iesize < sizeof(*bpoie)) {
-               dev_err(dev, "BPOIEC notification: Not enough IE data to "
-                       "decode (%zu vs %zu bytes needed)\n",
-                       iesize, sizeof(*bpoie));
-               goto error;
-       }
-       if (++count % 1000 == 0)        /* Lame placeholder */
-               dev_info(dev, "BPOIE: %u changes received\n", count);
-       /*
-        * FIXME: At this point we should go over all the IEs in the
-        *        bpoiec->BPOIE array and act on each.
-        */
-       result = 0;
-error:
-       return result;
-}
-
-/*
- * Print beaconing state.
- */
-static ssize_t uwb_rc_beacon_show(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_rc *rc = uwb_dev->rc;
-       ssize_t result;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       result = sprintf(buf, "%d\n", rc->beaconing);
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return result;
-}
-
-/*
- * Start beaconing on the specified channel, or stop beaconing.
- */
-static ssize_t uwb_rc_beacon_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_rc *rc = uwb_dev->rc;
-       int channel;
-       ssize_t result = -EINVAL;
-
-       result = sscanf(buf, "%d", &channel);
-       if (result >= 1)
-               result = uwb_radio_force_channel(rc, channel);
-
-       return result < 0 ? result : size;
-}
-DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, uwb_rc_beacon_show, uwb_rc_beacon_store);
diff --git a/drivers/staging/uwb/driver.c b/drivers/staging/uwb/driver.c
deleted file mode 100644 (file)
index 5755c2e..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Driver initialization, etc
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- *
- * Life cycle: FIXME: explain
- *
- *  UWB radio controller:
- *
- *    1. alloc a uwb_rc, zero it
- *    2. call uwb_rc_init() on it to set it up + ops (won't do any
- *       kind of allocation)
- *    3. register (now it is owned by the UWB stack--deregister before
- *       freeing/destroying).
- *    4. It lives on it's own now (UWB stack handles)--when it
- *       disconnects, call unregister()
- *    5. free it.
- *
- *    Make sure you have a reference to the uwb_rc before calling
- *    any of the UWB API functions.
- *
- * TODO:
- *
- * 1. Locking and life cycle management is crappy still. All entry
- *    points to the UWB HCD API assume you have a reference on the
- *    uwb_rc structure and that it won't go away. They mutex lock it
- *    before doing anything.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/kdev_t.h>
-#include <linux/random.h>
-
-#include "uwb-internal.h"
-
-
-/* UWB stack attributes (or 'global' constants) */
-
-
-/**
- * If a beacon disappears for longer than this, then we consider the
- * device who was represented by that beacon to be gone.
- *
- * ECMA-368[17.2.3, last para] establishes that a device must not
- * consider a device to be its neighbour if he doesn't receive a beacon
- * for more than mMaxLostBeacons. mMaxLostBeacons is defined in
- * ECMA-368[17.16] as 3; because we can get only one beacon per
- * superframe, that'd be 3 * 65ms = 195 ~ 200 ms. Let's give it time
- * for jitter and stuff and make it 500 ms.
- */
-unsigned long beacon_timeout_ms = 500;
-
-static
-ssize_t beacon_timeout_ms_show(struct class *class,
-                               struct class_attribute *attr,
-                               char *buf)
-{
-       return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms);
-}
-
-static
-ssize_t beacon_timeout_ms_store(struct class *class,
-                               struct class_attribute *attr,
-                               const char *buf, size_t size)
-{
-       unsigned long bt;
-       ssize_t result;
-       result = sscanf(buf, "%lu", &bt);
-       if (result != 1)
-               return -EINVAL;
-       beacon_timeout_ms = bt;
-       return size;
-}
-static CLASS_ATTR_RW(beacon_timeout_ms);
-
-static struct attribute *uwb_class_attrs[] = {
-       &class_attr_beacon_timeout_ms.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(uwb_class);
-
-/** Device model classes */
-struct class uwb_rc_class = {
-       .name        = "uwb_rc",
-       .class_groups = uwb_class_groups,
-};
-
-
-static int __init uwb_subsys_init(void)
-{
-       int result = 0;
-
-       result = uwb_est_create();
-       if (result < 0) {
-               printk(KERN_ERR "uwb: Can't initialize EST subsystem\n");
-               goto error_est_init;
-       }
-
-       result = class_register(&uwb_rc_class);
-       if (result < 0)
-               goto error_uwb_rc_class_register;
-
-       /* Register the UWB bus */
-       result = bus_register(&uwb_bus_type);
-       if (result) {
-               pr_err("%s - registering bus driver failed\n", __func__);
-               goto exit_bus;
-       }
-
-       uwb_dbg_init();
-       return 0;
-
-exit_bus:
-       class_unregister(&uwb_rc_class);
-error_uwb_rc_class_register:
-       uwb_est_destroy();
-error_est_init:
-       return result;
-}
-module_init(uwb_subsys_init);
-
-static void __exit uwb_subsys_exit(void)
-{
-       uwb_dbg_exit();
-       bus_unregister(&uwb_bus_type);
-       class_unregister(&uwb_rc_class);
-       uwb_est_destroy();
-       return;
-}
-module_exit(uwb_subsys_exit);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Ultra Wide Band core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/drp-avail.c b/drivers/staging/uwb/drp-avail.c
deleted file mode 100644 (file)
index 02392ab..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * DRP availability management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Reinette Chatre <reinette.chatre@intel.com>
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * Manage DRP Availability (the MAS available for DRP
- * reservations). Thus:
- *
- * - Handle DRP Availability Change notifications
- *
- * - Allow the reservation manager to indicate MAS reserved/released
- *   by local (owned by/targeted at the radio controller)
- *   reservations.
- *
- * - Based on the two sources above, generate a DRP Availability IE to
- *   be included in the beacon.
- *
- * See also the documentation for struct uwb_drp_avail.
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/bitmap.h>
-#include "uwb-internal.h"
-
-/**
- * uwb_drp_avail_init - initialize an RC's MAS availability
- *
- * All MAS are available initially.  The RC will inform use which
- * slots are used for the BP (it may change in size).
- */
-void uwb_drp_avail_init(struct uwb_rc *rc)
-{
-       bitmap_fill(rc->drp_avail.global, UWB_NUM_MAS);
-       bitmap_fill(rc->drp_avail.local, UWB_NUM_MAS);
-       bitmap_fill(rc->drp_avail.pending, UWB_NUM_MAS);
-}
-
-/*
- * Determine MAS available for new local reservations.
- *
- * avail = global & local & pending
- */
-void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail)
-{
-       bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
-       bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS);
-}
-
-/**
- * uwb_drp_avail_reserve_pending - reserve MAS for a new reservation
- * @rc: the radio controller
- * @mas: the MAS to reserve
- *
- * Returns 0 on success, or -EBUSY if the MAS requested aren't available.
- */
-int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas)
-{
-       struct uwb_mas_bm avail;
-
-       uwb_drp_available(rc, &avail);
-       if (!bitmap_subset(mas->bm, avail.bm, UWB_NUM_MAS))
-               return -EBUSY;
-
-       bitmap_andnot(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
-       return 0;
-}
-
-/**
- * uwb_drp_avail_reserve - reserve MAS for an established reservation
- * @rc: the radio controller
- * @mas: the MAS to reserve
- */
-void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas)
-{
-       bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
-       bitmap_andnot(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS);
-       rc->drp_avail.ie_valid = false;
-}
-
-/**
- * uwb_drp_avail_release - release MAS from a pending or established reservation
- * @rc: the radio controller
- * @mas: the MAS to release
- */
-void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas)
-{
-       bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS);
-       bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS);
-       rc->drp_avail.ie_valid = false;
-       uwb_rsv_handle_drp_avail_change(rc);
-}
-
-/**
- * uwb_drp_avail_ie_update - update the DRP Availability IE
- * @rc: the radio controller
- *
- * avail = global & local
- */
-void uwb_drp_avail_ie_update(struct uwb_rc *rc)
-{
-       struct uwb_mas_bm avail;
-
-       bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS);
-
-       rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY;
-       rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8;
-       uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail);
-       rc->drp_avail.ie_valid = true;
-}
-
-/**
- * Create an unsigned long from a buffer containing a byte stream.
- *
- * @array: pointer to buffer
- * @itr:   index of buffer from where we start
- * @len:   the buffer's remaining size may not be exact multiple of
- *         sizeof(unsigned long), @len is the length of buffer that needs
- *         to be converted. This will be sizeof(unsigned long) or smaller
- *         (BUG if not). If it is smaller then we will pad the remaining
- *         space of the result with zeroes.
- */
-static
-unsigned long get_val(u8 *array, size_t itr, size_t len)
-{
-       unsigned long val = 0;
-       size_t top = itr + len;
-
-       BUG_ON(len > sizeof(val));
-
-       while (itr < top) {
-               val <<= 8;
-               val |= array[top - 1];
-               top--;
-       }
-       val <<= 8 * (sizeof(val) - len); /* padding */
-       return val;
-}
-
-/**
- * Initialize bitmap from data buffer.
- *
- * The bitmap to be converted could come from a IE, for example a
- * DRP Availability IE.
- * From ECMA-368 1.0 [16.8.7]: "
- * octets: 1            1               N * (0 to 32)
- *         Element ID   Length (=N)     DRP Availability Bitmap
- *
- * The DRP Availability Bitmap field is up to 256 bits long, one
- * bit for each MAS in the superframe, where the least-significant
- * bit of the field corresponds to the first MAS in the superframe
- * and successive bits correspond to successive MASs."
- *
- * The DRP Availability bitmap is in octets from 0 to 32, so octet
- * 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32
- * octets, the bits in octets not included at the end of the bitmap are
- * treated as zero. In this case (when the bitmap is smaller than 32
- * octets) the MAS represented range from MAS 1 to MAS (size of bitmap)
- * with the last octet still containing bits for MAS 1-8, etc.
- *
- * For example:
- * F00F0102 03040506 0708090A 0B0C0D0E 0F010203
- * ^^^^
- * ||||
- * ||||
- * |||\LSB of byte is MAS 9
- * ||\MSB of byte is MAS 16
- * |\LSB of first byte is MAS 1
- * \ MSB of byte is MAS 8
- *
- * An example of this encoding can be found in ECMA-368 Annex-D [Table D.11]
- *
- * The resulting bitmap will have the following mapping:
- *     bit position 0 == MAS 1
- *     bit position 1 == MAS 2
- *     ...
- *     bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS
- *
- * @bmp_itr:   pointer to bitmap (can be declared with DECLARE_BITMAP)
- * @buffer:    pointer to buffer containing bitmap data in big endian
- *              format (MSB first)
- * @buffer_size:number of bytes with which bitmap should be initialized
- */
-static
-void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer,
-                  size_t buffer_size)
-{
-       u8 *buffer = _buffer;
-       size_t itr, len;
-       unsigned long val;
-
-       itr = 0;
-       while (itr < buffer_size) {
-               len = buffer_size - itr >= sizeof(val) ?
-                       sizeof(val) : buffer_size - itr;
-               val = get_val(buffer, itr, len);
-               bmp_itr[itr / sizeof(val)] = val;
-               itr += sizeof(val);
-       }
-}
-
-
-/**
- * Extract DRP Availability bitmap from the notification.
- *
- * The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes
- * We convert that to our internal representation.
- */
-static
-int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp)
-{
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc_evt_drp_avail *drp_evt;
-       int result = -EINVAL;
-
-       /* Is there enough data to decode the event? */
-       if (evt->notif.size < sizeof(*drp_evt)) {
-               dev_err(dev, "DRP Availability Change: Not enough "
-                       "data to decode event [%zu bytes, %zu "
-                       "needed]\n", evt->notif.size, sizeof(*drp_evt));
-               goto error;
-       }
-       drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb);
-       buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8);
-       result = 0;
-error:
-       return result;
-}
-
-
-/**
- * Process an incoming DRP Availability notification.
- *
- * @evt:       Event information (packs the actual event data, which
- *              radio controller it came to, etc).
- *
- * @returns:    0 on success (so uwbd() frees the event buffer), < 0
- *              on error.
- *
- * According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that
- * the MAS slot is available, bits set to ZERO indicate that the slot
- * is busy.
- *
- * So we clear available slots, we set used slots :)
- *
- * The notification only marks non-availability based on the BP and
- * received DRP IEs that are not for this radio controller.  A copy of
- * this bitmap is needed to generate the real availability (which
- * includes local and pending reservations).
- *
- * The DRP Availability IE that this radio controller emits will need
- * to be updated.
- */
-int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt)
-{
-       int result;
-       struct uwb_rc *rc = evt->rc;
-       DECLARE_BITMAP(bmp, UWB_NUM_MAS);
-
-       result = uwbd_evt_get_drp_avail(evt, bmp);
-       if (result < 0)
-               return result;
-
-       mutex_lock(&rc->rsvs_mutex);
-       bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS);
-       rc->drp_avail.ie_valid = false;
-       uwb_rsv_handle_drp_avail_change(rc);
-       mutex_unlock(&rc->rsvs_mutex);
-
-       uwb_rsv_sched_update(rc);
-
-       return 0;
-}
diff --git a/drivers/staging/uwb/drp-ie.c b/drivers/staging/uwb/drp-ie.c
deleted file mode 100644 (file)
index b2a862c..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB DRP IE management.
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-
-#include "uwb.h"
-#include "uwb-internal.h"
-
-
-/*
- * Return the reason code for a reservations's DRP IE.
- */
-static int uwb_rsv_reason_code(struct uwb_rsv *rsv)
-{
-       static const int reason_codes[] = {
-               [UWB_RSV_STATE_O_INITIATED]          = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_O_PENDING]            = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_O_MODIFIED]           = UWB_DRP_REASON_MODIFIED,
-               [UWB_RSV_STATE_O_ESTABLISHED]        = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_O_TO_BE_MOVED]        = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_O_MOVE_COMBINING]     = UWB_DRP_REASON_MODIFIED,
-               [UWB_RSV_STATE_O_MOVE_REDUCING]      = UWB_DRP_REASON_MODIFIED,
-               [UWB_RSV_STATE_O_MOVE_EXPANDING]     = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_T_ACCEPTED]           = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_T_CONFLICT]           = UWB_DRP_REASON_CONFLICT,
-               [UWB_RSV_STATE_T_PENDING]            = UWB_DRP_REASON_PENDING,
-               [UWB_RSV_STATE_T_DENIED]             = UWB_DRP_REASON_DENIED,
-               [UWB_RSV_STATE_T_RESIZED]            = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT,
-               [UWB_RSV_STATE_T_EXPANDING_PENDING]  = UWB_DRP_REASON_PENDING,
-               [UWB_RSV_STATE_T_EXPANDING_DENIED]   = UWB_DRP_REASON_DENIED,
-       };
-
-       return reason_codes[rsv->state];
-}
-
-/*
- * Return the reason code for a reservations's companion DRP IE .
- */
-static int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv)
-{
-       static const int companion_reason_codes[] = {
-               [UWB_RSV_STATE_O_MOVE_EXPANDING]     = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED,
-               [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT,
-               [UWB_RSV_STATE_T_EXPANDING_PENDING]  = UWB_DRP_REASON_PENDING,
-               [UWB_RSV_STATE_T_EXPANDING_DENIED]   = UWB_DRP_REASON_DENIED,
-       };
-
-       return companion_reason_codes[rsv->state];
-}
-
-/*
- * Return the status bit for a reservations's DRP IE.
- */
-int uwb_rsv_status(struct uwb_rsv *rsv)
-{
-       static const int statuses[] = {
-               [UWB_RSV_STATE_O_INITIATED]          = 0,
-               [UWB_RSV_STATE_O_PENDING]            = 0,
-               [UWB_RSV_STATE_O_MODIFIED]           = 1,
-               [UWB_RSV_STATE_O_ESTABLISHED]        = 1,
-               [UWB_RSV_STATE_O_TO_BE_MOVED]        = 0,
-               [UWB_RSV_STATE_O_MOVE_COMBINING]     = 1,
-               [UWB_RSV_STATE_O_MOVE_REDUCING]      = 1,
-               [UWB_RSV_STATE_O_MOVE_EXPANDING]     = 1,
-               [UWB_RSV_STATE_T_ACCEPTED]           = 1,
-               [UWB_RSV_STATE_T_CONFLICT]           = 0,
-               [UWB_RSV_STATE_T_PENDING]            = 0,
-               [UWB_RSV_STATE_T_DENIED]             = 0,
-               [UWB_RSV_STATE_T_RESIZED]            = 1,
-               [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1,
-               [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 1,
-               [UWB_RSV_STATE_T_EXPANDING_PENDING]  = 1,
-               [UWB_RSV_STATE_T_EXPANDING_DENIED]   = 1,
-
-       };
-
-       return statuses[rsv->state];
-}
-
-/*
- * Return the status bit for a reservations's companion DRP IE .
- */
-int uwb_rsv_companion_status(struct uwb_rsv *rsv)
-{
-       static const int companion_statuses[] = {
-               [UWB_RSV_STATE_O_MOVE_EXPANDING]     = 0,
-               [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1,
-               [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 0,
-               [UWB_RSV_STATE_T_EXPANDING_PENDING]  = 0,
-               [UWB_RSV_STATE_T_EXPANDING_DENIED]   = 0,
-       };
-
-       return companion_statuses[rsv->state];
-}
-
-/*
- * Allocate a DRP IE.
- *
- * To save having to free/allocate a DRP IE when its MAS changes,
- * enough memory is allocated for the maxiumum number of DRP
- * allocation fields.  This gives an overhead per reservation of up to
- * (UWB_NUM_ZONES - 1) * 4 = 60 octets.
- */
-static struct uwb_ie_drp *uwb_drp_ie_alloc(void)
-{
-       struct uwb_ie_drp *drp_ie;
-
-       drp_ie = kzalloc(struct_size(drp_ie, allocs, UWB_NUM_ZONES),
-                        GFP_KERNEL);
-       if (drp_ie)
-               drp_ie->hdr.element_id = UWB_IE_DRP;
-       return drp_ie;
-}
-
-
-/*
- * Fill a DRP IE's allocation fields from a MAS bitmap.
- */
-static void uwb_drp_ie_from_bm(struct uwb_ie_drp *drp_ie,
-                              struct uwb_mas_bm *mas)
-{
-       int z, i, num_fields = 0, next = 0;
-       struct uwb_drp_alloc *zones;
-       __le16 current_bmp;
-       DECLARE_BITMAP(tmp_bmp, UWB_NUM_MAS);
-       DECLARE_BITMAP(tmp_mas_bm, UWB_MAS_PER_ZONE);
-
-       zones = drp_ie->allocs;
-
-       bitmap_copy(tmp_bmp, mas->bm, UWB_NUM_MAS);
-
-       /* Determine unique MAS bitmaps in zones from bitmap. */
-       for (z = 0; z < UWB_NUM_ZONES; z++) {
-               bitmap_copy(tmp_mas_bm, tmp_bmp, UWB_MAS_PER_ZONE);
-               if (bitmap_weight(tmp_mas_bm, UWB_MAS_PER_ZONE) > 0) {
-                       bool found = false;
-                       current_bmp = (__le16) *tmp_mas_bm;
-                       for (i = 0; i < next; i++) {
-                               if (current_bmp == zones[i].mas_bm) {
-                                       zones[i].zone_bm |= 1 << z;
-                                       found = true;
-                                       break;
-                               }
-                       }
-                       if (!found)  {
-                               num_fields++;
-                               zones[next].zone_bm = 1 << z;
-                               zones[next].mas_bm = current_bmp;
-                               next++;
-                       }
-               }
-               bitmap_shift_right(tmp_bmp, tmp_bmp, UWB_MAS_PER_ZONE, UWB_NUM_MAS);
-       }
-
-       /* Store in format ready for transmission (le16). */
-       for (i = 0; i < num_fields; i++) {
-               drp_ie->allocs[i].zone_bm = cpu_to_le16(zones[i].zone_bm);
-               drp_ie->allocs[i].mas_bm = cpu_to_le16(zones[i].mas_bm);
-       }
-
-       drp_ie->hdr.length = sizeof(struct uwb_ie_drp) - sizeof(struct uwb_ie_hdr)
-               + num_fields * sizeof(struct uwb_drp_alloc);
-}
-
-/**
- * uwb_drp_ie_update - update a reservation's DRP IE
- * @rsv: the reservation
- */
-int uwb_drp_ie_update(struct uwb_rsv *rsv)
-{
-       struct uwb_ie_drp *drp_ie;
-       struct uwb_rsv_move *mv;
-       int unsafe;
-
-       if (rsv->state == UWB_RSV_STATE_NONE) {
-               kfree(rsv->drp_ie);
-               rsv->drp_ie = NULL;
-               return 0;
-       }
-
-       unsafe = rsv->mas.unsafe ? 1 : 0;
-
-       if (rsv->drp_ie == NULL) {
-               rsv->drp_ie = uwb_drp_ie_alloc();
-               if (rsv->drp_ie == NULL)
-                       return -ENOMEM;
-       }
-       drp_ie = rsv->drp_ie;
-
-       uwb_ie_drp_set_unsafe(drp_ie,       unsafe);
-       uwb_ie_drp_set_tiebreaker(drp_ie,   rsv->tiebreaker);
-       uwb_ie_drp_set_owner(drp_ie,        uwb_rsv_is_owner(rsv));
-       uwb_ie_drp_set_status(drp_ie,       uwb_rsv_status(rsv));
-       uwb_ie_drp_set_reason_code(drp_ie,  uwb_rsv_reason_code(rsv));
-       uwb_ie_drp_set_stream_index(drp_ie, rsv->stream);
-       uwb_ie_drp_set_type(drp_ie,         rsv->type);
-
-       if (uwb_rsv_is_owner(rsv)) {
-               switch (rsv->target.type) {
-               case UWB_RSV_TARGET_DEV:
-                       drp_ie->dev_addr = rsv->target.dev->dev_addr;
-                       break;
-               case UWB_RSV_TARGET_DEVADDR:
-                       drp_ie->dev_addr = rsv->target.devaddr;
-                       break;
-               }
-       } else
-               drp_ie->dev_addr = rsv->owner->dev_addr;
-
-       uwb_drp_ie_from_bm(drp_ie, &rsv->mas);
-
-       if (uwb_rsv_has_two_drp_ies(rsv)) {
-               mv = &rsv->mv;
-               if (mv->companion_drp_ie == NULL) {
-                       mv->companion_drp_ie = uwb_drp_ie_alloc();
-                       if (mv->companion_drp_ie == NULL)
-                               return -ENOMEM;
-               }
-               drp_ie = mv->companion_drp_ie;
-
-               /* keep all the same configuration of the main drp_ie */
-               memcpy(drp_ie, rsv->drp_ie, sizeof(struct uwb_ie_drp));
-
-
-               /* FIXME: handle properly the unsafe bit */
-               uwb_ie_drp_set_unsafe(drp_ie,       1);
-               uwb_ie_drp_set_status(drp_ie,       uwb_rsv_companion_status(rsv));
-               uwb_ie_drp_set_reason_code(drp_ie,  uwb_rsv_companion_reason_code(rsv));
-
-               uwb_drp_ie_from_bm(drp_ie, &mv->companion_mas);
-       }
-
-       rsv->ie_valid = true;
-       return 0;
-}
-
-/*
- * Set MAS bits from given MAS bitmap in a single zone of large bitmap.
- *
- * We are given a zone id and the MAS bitmap of bits that need to be set in
- * this zone. Note that this zone may already have bits set and this only
- * adds settings - we cannot simply assign the MAS bitmap contents to the
- * zone contents. We iterate over the the bits (MAS) in the zone and set the
- * bits that are set in the given MAS bitmap.
- */
-static
-void uwb_drp_ie_single_zone_to_bm(struct uwb_mas_bm *bm, u8 zone, u16 mas_bm)
-{
-       int mas;
-       u16 mas_mask;
-
-       for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++) {
-               mas_mask = 1 << mas;
-               if (mas_bm & mas_mask)
-                       set_bit(zone * UWB_NUM_ZONES + mas, bm->bm);
-       }
-}
-
-/**
- * uwb_drp_ie_zones_to_bm - convert DRP allocation fields to a bitmap
- * @mas:    MAS bitmap that will be populated to correspond to the
- *          allocation fields in the DRP IE
- * @drp_ie: the DRP IE that contains the allocation fields.
- *
- * The input format is an array of MAS allocation fields (16 bit Zone
- * bitmap, 16 bit MAS bitmap) as described in [ECMA-368] section
- * 16.8.6. The output is a full 256 bit MAS bitmap.
- *
- * We go over all the allocation fields, for each allocation field we
- * know which zones are impacted. We iterate over all the zones
- * impacted and call a function that will set the correct MAS bits in
- * each zone.
- */
-void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie)
-{
-       int numallocs = (drp_ie->hdr.length - 4) / 4;
-       const struct uwb_drp_alloc *alloc;
-       int cnt;
-       u16 zone_bm, mas_bm;
-       u8 zone;
-       u16 zone_mask;
-
-       bitmap_zero(bm->bm, UWB_NUM_MAS);
-
-       for (cnt = 0; cnt < numallocs; cnt++) {
-               alloc = &drp_ie->allocs[cnt];
-               zone_bm = le16_to_cpu(alloc->zone_bm);
-               mas_bm = le16_to_cpu(alloc->mas_bm);
-               for (zone = 0; zone < UWB_NUM_ZONES; zone++)   {
-                       zone_mask = 1 << zone;
-                       if (zone_bm & zone_mask)
-                               uwb_drp_ie_single_zone_to_bm(bm, zone, mas_bm);
-               }
-       }
-}
-
diff --git a/drivers/staging/uwb/drp.c b/drivers/staging/uwb/drp.c
deleted file mode 100644 (file)
index 869987b..0000000
+++ /dev/null
@@ -1,842 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Dynamic Reservation Protocol handling
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "uwb-internal.h"
-
-
-/* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */
-enum uwb_drp_conflict_action {
-       /* Reservation is maintained, no action needed */
-       UWB_DRP_CONFLICT_MANTAIN = 0,
-
-       /* the device shall not transmit frames in conflicting MASs in
-        * the following superframe. If the device is the reservation
-        * target, it shall also set the Reason Code in its DRP IE to
-        * Conflict in its beacon in the following superframe.
-        */
-       UWB_DRP_CONFLICT_ACT1,
-
-       /* the device shall not set the Reservation Status bit to ONE
-        * and shall not transmit frames in conflicting MASs. If the
-        * device is the reservation target, it shall also set the
-        * Reason Code in its DRP IE to Conflict.
-        */
-       UWB_DRP_CONFLICT_ACT2,
-
-       /* the device shall not transmit frames in conflicting MASs in
-        * the following superframe. It shall remove the conflicting
-        * MASs from the reservation or set the Reservation Status to
-        * ZERO in its beacon in the following superframe. If the
-        * device is the reservation target, it shall also set the
-        * Reason Code in its DRP IE to Conflict.
-        */
-       UWB_DRP_CONFLICT_ACT3,
-};
-
-
-static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg,
-                                   struct uwb_rceb *reply, ssize_t reply_size)
-{
-       struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply;
-       unsigned long flags;
-
-       if (r != NULL) {
-               if (r->bResultCode != UWB_RC_RES_SUCCESS)
-                       dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n",
-                               uwb_rc_strerror(r->bResultCode), r->bResultCode);
-       } else
-               dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n");
-
-       spin_lock_irqsave(&rc->rsvs_lock, flags);
-       if (rc->set_drp_ie_pending > 1) {
-               rc->set_drp_ie_pending = 0;
-               uwb_rsv_queue_update(rc);
-       } else {
-               rc->set_drp_ie_pending = 0;
-       }
-       spin_unlock_irqrestore(&rc->rsvs_lock, flags);
-}
-
-/**
- * Construct and send the SET DRP IE
- *
- * @rc:         UWB Host controller
- * @returns:    >= 0 number of bytes still available in the beacon
- *              < 0 errno code on error.
- *
- * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the
- * device to include in its beacon at the same time. We thus have to
- * traverse all reservations and include the DRP IEs of all PENDING
- * and NEGOTIATED reservations in a SET DRP command for transmission.
- *
- * A DRP Availability IE is appended.
- *
- * rc->rsvs_mutex is held
- *
- * FIXME We currently ignore the returned value indicating the remaining space
- * in beacon. This could be used to deny reservation requests earlier if
- * determined that they would cause the beacon space to be exceeded.
- */
-int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
-{
-       int result;
-       struct uwb_rc_cmd_set_drp_ie *cmd;
-       struct uwb_rsv *rsv;
-       struct uwb_rsv_move *mv;
-       int num_bytes = 0;
-       u8 *IEDataptr;
-
-       result = -ENOMEM;
-       /* First traverse all reservations to determine memory needed. */
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->drp_ie != NULL) {
-                       num_bytes += rsv->drp_ie->hdr.length + 2;
-                       if (uwb_rsv_has_two_drp_ies(rsv) &&
-                               (rsv->mv.companion_drp_ie != NULL)) {
-                               mv = &rsv->mv;
-                               num_bytes +=
-                                       mv->companion_drp_ie->hdr.length + 2;
-                       }
-               }
-       }
-       num_bytes += sizeof(rc->drp_avail.ie);
-       cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL);
-       if (cmd == NULL)
-               goto error;
-       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE);
-       cmd->wIELength = num_bytes;
-       IEDataptr = (u8 *)&cmd->IEData[0];
-
-       /* FIXME: DRV avail IE is not always needed */
-       /* put DRP avail IE first */
-       memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
-       IEDataptr += sizeof(struct uwb_ie_drp_avail);
-
-       /* Next traverse all reservations to place IEs in allocated memory. */
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->drp_ie != NULL) {
-                       memcpy(IEDataptr, rsv->drp_ie,
-                              rsv->drp_ie->hdr.length + 2);
-                       IEDataptr += rsv->drp_ie->hdr.length + 2;
-
-                       if (uwb_rsv_has_two_drp_ies(rsv) &&
-                               (rsv->mv.companion_drp_ie != NULL)) {
-                               mv = &rsv->mv;
-                               memcpy(IEDataptr, mv->companion_drp_ie,
-                                      mv->companion_drp_ie->hdr.length + 2);
-                               IEDataptr +=
-                                       mv->companion_drp_ie->hdr.length + 2;
-                       }
-               }
-       }
-
-       result = uwb_rc_cmd_async(rc, "SET-DRP-IE",
-                               &cmd->rccb, sizeof(*cmd) + num_bytes,
-                               UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE,
-                               uwb_rc_set_drp_cmd_done, NULL);
-
-       rc->set_drp_ie_pending = 1;
-
-       kfree(cmd);
-error:
-       return result;
-}
-
-/*
- * Evaluate the action to perform using conflict resolution rules
- *
- * Return a uwb_drp_conflict_action.
- */
-static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot,
-                                   struct uwb_rsv *rsv, int our_status)
-{
-       int our_tie_breaker = rsv->tiebreaker;
-       int our_type        = rsv->type;
-       int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot;
-
-       int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie);
-       int ext_status      = uwb_ie_drp_status(ext_drp_ie);
-       int ext_type        = uwb_ie_drp_type(ext_drp_ie);
-
-
-       /* [ECMA-368 2nd Edition] 17.4.6 */
-       if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-1 */
-       if (our_type == UWB_DRP_TYPE_ALIEN_BP) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-2 */
-       if (ext_type == UWB_DRP_TYPE_ALIEN_BP) {
-               /* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */
-               return UWB_DRP_CONFLICT_ACT1;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-3 */
-       if (our_status == 0 && ext_status == 1) {
-               return UWB_DRP_CONFLICT_ACT2;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-4 */
-       if (our_status == 1 && ext_status == 0) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-5a */
-       if (our_tie_breaker == ext_tie_breaker &&
-           our_beacon_slot <  ext_beacon_slot) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-5b */
-       if (our_tie_breaker != ext_tie_breaker &&
-           our_beacon_slot >  ext_beacon_slot) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       if (our_status == 0) {
-               if (our_tie_breaker == ext_tie_breaker) {
-                       /* [ECMA-368 2nd Edition] 17.4.6-6a */
-                       if (our_beacon_slot > ext_beacon_slot) {
-                               return UWB_DRP_CONFLICT_ACT2;
-                       }
-               } else  {
-                       /* [ECMA-368 2nd Edition] 17.4.6-6b */
-                       if (our_beacon_slot < ext_beacon_slot) {
-                               return UWB_DRP_CONFLICT_ACT2;
-                       }
-               }
-       } else {
-               if (our_tie_breaker == ext_tie_breaker) {
-                       /* [ECMA-368 2nd Edition] 17.4.6-7a */
-                       if (our_beacon_slot > ext_beacon_slot) {
-                               return UWB_DRP_CONFLICT_ACT3;
-                       }
-               } else {
-                       /* [ECMA-368 2nd Edition] 17.4.6-7b */
-                       if (our_beacon_slot < ext_beacon_slot) {
-                               return UWB_DRP_CONFLICT_ACT3;
-                       }
-               }
-       }
-       return UWB_DRP_CONFLICT_MANTAIN;
-}
-
-static void handle_conflict_normal(struct uwb_ie_drp *drp_ie,
-                                  int ext_beacon_slot,
-                                  struct uwb_rsv *rsv,
-                                  struct uwb_mas_bm *conflicting_mas)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct uwb_rsv_move *mv = &rsv->mv;
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       int action;
-
-       action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv));
-
-       if (uwb_rsv_is_owner(rsv)) {
-               switch(action) {
-               case UWB_DRP_CONFLICT_ACT2:
-                       /* try move */
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED);
-                       if (bow->can_reserve_extra_mases == false)
-                               uwb_rsv_backoff_win_increment(rc);
-
-                       break;
-               case UWB_DRP_CONFLICT_ACT3:
-                       uwb_rsv_backoff_win_increment(rc);
-                       /* drop some mases with reason modified */
-                       /* put in the companion the mases to be dropped */
-                       bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS);
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
-               default:
-                       break;
-               }
-       } else {
-               switch(action) {
-               case UWB_DRP_CONFLICT_ACT2:
-               case UWB_DRP_CONFLICT_ACT3:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
-               default:
-                       break;
-               }
-
-       }
-
-}
-
-static void handle_conflict_expanding(struct uwb_ie_drp *drp_ie, int ext_beacon_slot,
-                                     struct uwb_rsv *rsv, bool companion_only,
-                                     struct uwb_mas_bm *conflicting_mas)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       struct uwb_rsv_move *mv = &rsv->mv;
-       int action;
-
-       if (companion_only) {
-               /* status of companion is 0 at this point */
-               action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0);
-               if (uwb_rsv_is_owner(rsv)) {
-                       switch(action) {
-                       case UWB_DRP_CONFLICT_ACT2:
-                       case UWB_DRP_CONFLICT_ACT3:
-                               uwb_rsv_set_state(rsv,
-                                               UWB_RSV_STATE_O_ESTABLISHED);
-                               rsv->needs_release_companion_mas = false;
-                               if (bow->can_reserve_extra_mases == false)
-                                       uwb_rsv_backoff_win_increment(rc);
-                               uwb_drp_avail_release(rsv->rc,
-                                               &rsv->mv.companion_mas);
-                       }
-               } else { /* rsv is target */
-                       switch(action) {
-                       case UWB_DRP_CONFLICT_ACT2:
-                       case UWB_DRP_CONFLICT_ACT3:
-                               uwb_rsv_set_state(rsv,
-                                       UWB_RSV_STATE_T_EXPANDING_CONFLICT);
-                                /* send_drp_avail_ie = true; */
-                       }
-               }
-       } else { /* also base part of the reservation is conflicting */
-               if (uwb_rsv_is_owner(rsv)) {
-                       uwb_rsv_backoff_win_increment(rc);
-                       /* remove companion part */
-                       uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
-
-                       /* drop some mases with reason modified */
-
-                       /* put in the companion the mases to be dropped */
-                       bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm,
-                                       conflicting_mas->bm, UWB_NUM_MAS);
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
-               } else { /* it is a target rsv */
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
-                        /* send_drp_avail_ie = true; */
-               }
-       }
-}
-
-static void uwb_drp_handle_conflict_rsv(struct uwb_rc *rc, struct uwb_rsv *rsv,
-                                       struct uwb_rc_evt_drp *drp_evt,
-                                       struct uwb_ie_drp *drp_ie,
-                                       struct uwb_mas_bm *conflicting_mas)
-{
-       struct uwb_rsv_move *mv;
-
-       /* check if the conflicting reservation has two drp_ies */
-       if (uwb_rsv_has_two_drp_ies(rsv)) {
-               mv = &rsv->mv;
-               if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
-                                                               UWB_NUM_MAS)) {
-                       handle_conflict_expanding(drp_ie,
-                                               drp_evt->beacon_slot_number,
-                                               rsv, false, conflicting_mas);
-               } else {
-                       if (bitmap_intersects(mv->companion_mas.bm,
-                                       conflicting_mas->bm, UWB_NUM_MAS)) {
-                               handle_conflict_expanding(
-                                       drp_ie, drp_evt->beacon_slot_number,
-                                       rsv, true, conflicting_mas);
-                       }
-               }
-       } else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
-                                                       UWB_NUM_MAS)) {
-               handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number,
-                                       rsv, conflicting_mas);
-       }
-}
-
-static void uwb_drp_handle_all_conflict_rsv(struct uwb_rc *rc,
-                                           struct uwb_rc_evt_drp *drp_evt,
-                                           struct uwb_ie_drp *drp_ie,
-                                           struct uwb_mas_bm *conflicting_mas)
-{
-       struct uwb_rsv *rsv;
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie,
-                                                       conflicting_mas);
-       }
-}
-
-static void uwb_drp_process_target_accepted(struct uwb_rc *rc,
-       struct uwb_rsv *rsv, struct uwb_rc_evt_drp *drp_evt,
-       struct uwb_ie_drp *drp_ie, struct uwb_mas_bm *mas)
-{
-       struct uwb_rsv_move *mv = &rsv->mv;
-       int status;
-
-       status = uwb_ie_drp_status(drp_ie);
-
-       if (rsv->state == UWB_RSV_STATE_T_CONFLICT) {
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
-               return;
-       }
-
-       if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) {
-               /* drp_ie is companion */
-               if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
-                       /* stroke companion */
-                       uwb_rsv_set_state(rsv,
-                               UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
-               }
-       } else {
-               if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
-                       if (uwb_drp_avail_reserve_pending(rc, mas) == -EBUSY) {
-                               /* FIXME: there is a conflict, find
-                                * the conflicting reservations and
-                                * take a sensible action. Consider
-                                * that in drp_ie there is the
-                                * "neighbour" */
-                               uwb_drp_handle_all_conflict_rsv(rc, drp_evt,
-                                               drp_ie, mas);
-                       } else {
-                               /* accept the extra reservation */
-                               bitmap_copy(mv->companion_mas.bm, mas->bm,
-                                                               UWB_NUM_MAS);
-                               uwb_rsv_set_state(rsv,
-                                       UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
-                       }
-               } else {
-                       if (status) {
-                               uwb_rsv_set_state(rsv,
-                                               UWB_RSV_STATE_T_ACCEPTED);
-                       }
-               }
-
-       }
-}
-
-/*
- * Based on the DRP IE, transition a target reservation to a new
- * state.
- */
-static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
-                  struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rsv_move *mv = &rsv->mv;
-       int status;
-       enum uwb_drp_reason reason_code;
-       struct uwb_mas_bm mas;
-
-       status = uwb_ie_drp_status(drp_ie);
-       reason_code = uwb_ie_drp_reason_code(drp_ie);
-       uwb_drp_ie_to_bm(&mas, drp_ie);
-
-       switch (reason_code) {
-       case UWB_DRP_REASON_ACCEPTED:
-               uwb_drp_process_target_accepted(rc, rsv, drp_evt, drp_ie, &mas);
-               break;
-
-       case UWB_DRP_REASON_MODIFIED:
-               /* check to see if we have already modified the reservation */
-               if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
-                       break;
-               }
-
-               /* find if the owner wants to expand or reduce */
-               if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
-                       /* owner is reducing */
-                       bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm,
-                               UWB_NUM_MAS);
-                       uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
-               }
-
-               bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED);
-               break;
-       default:
-               dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
-                        reason_code, status);
-       }
-}
-
-static void uwb_drp_process_owner_accepted(struct uwb_rsv *rsv,
-                                               struct uwb_mas_bm *mas)
-{
-       struct uwb_rsv_move *mv = &rsv->mv;
-
-       switch (rsv->state) {
-       case UWB_RSV_STATE_O_PENDING:
-       case UWB_RSV_STATE_O_INITIATED:
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-               break;
-       case UWB_RSV_STATE_O_MODIFIED:
-               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-               else
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
-               break;
-
-       case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */
-               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-               else
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
-               break;
-       case UWB_RSV_STATE_O_MOVE_EXPANDING:
-               if (bitmap_equal(mas->bm, mv->companion_mas.bm, UWB_NUM_MAS)) {
-                       /* Companion reservation accepted */
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
-               } else {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
-               }
-               break;
-       case UWB_RSV_STATE_O_MOVE_COMBINING:
-               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
-               else
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
-               break;
-       default:
-               break;
-       }
-}
-/*
- * Based on the DRP IE, transition an owner reservation to a new
- * state.
- */
-static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
-                                 struct uwb_dev *src, struct uwb_ie_drp *drp_ie,
-                                 struct uwb_rc_evt_drp *drp_evt)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       int status;
-       enum uwb_drp_reason reason_code;
-       struct uwb_mas_bm mas;
-
-       status = uwb_ie_drp_status(drp_ie);
-       reason_code = uwb_ie_drp_reason_code(drp_ie);
-       uwb_drp_ie_to_bm(&mas, drp_ie);
-
-       if (status) {
-               switch (reason_code) {
-               case UWB_DRP_REASON_ACCEPTED:
-                       uwb_drp_process_owner_accepted(rsv, &mas);
-                       break;
-               default:
-                       dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
-                                reason_code, status);
-               }
-       } else {
-               switch (reason_code) {
-               case UWB_DRP_REASON_PENDING:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING);
-                       break;
-               case UWB_DRP_REASON_DENIED:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-                       break;
-               case UWB_DRP_REASON_CONFLICT:
-                       /* resolve the conflict */
-                       bitmap_complement(mas.bm, src->last_availability_bm,
-                                         UWB_NUM_MAS);
-                       uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas);
-                       break;
-               default:
-                       dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
-                                reason_code, status);
-               }
-       }
-}
-
-static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt)
-{
-       unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US;
-       mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us));
-}
-
-static void uwb_cnflt_update_work(struct work_struct *work)
-{
-       struct uwb_cnflt_alien *cnflt = container_of(work,
-                                                    struct uwb_cnflt_alien,
-                                                    cnflt_update_work);
-       struct uwb_cnflt_alien *c;
-       struct uwb_rc *rc = cnflt->rc;
-
-       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       list_del(&cnflt->rc_node);
-
-       /* update rc global conflicting alien bitmap */
-       bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
-
-       list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) {
-               bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm,
-                                               c->mas.bm, UWB_NUM_MAS);
-       }
-
-       queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work,
-                                       usecs_to_jiffies(delay_us));
-
-       kfree(cnflt);
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-static void uwb_cnflt_timer(struct timer_list *t)
-{
-       struct uwb_cnflt_alien *cnflt = from_timer(cnflt, t, timer);
-
-       queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work);
-}
-
-/*
- * We have received an DRP_IE of type Alien BP and we need to make
- * sure we do not transmit in conflicting MASs.
- */
-static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_mas_bm mas;
-       struct uwb_cnflt_alien *cnflt;
-       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
-
-       uwb_drp_ie_to_bm(&mas, drp_ie);
-
-       list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
-               if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
-                       /* Existing alien BP reservation conflicting
-                        * bitmap, just reset the timer */
-                       uwb_cnflt_alien_stroke_timer(cnflt);
-                       return;
-               }
-       }
-
-       /* New alien BP reservation conflicting bitmap */
-
-       /* alloc and initialize new uwb_cnflt_alien */
-       cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL);
-       if (!cnflt) {
-               dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n");
-               return;
-       }
-
-       INIT_LIST_HEAD(&cnflt->rc_node);
-       timer_setup(&cnflt->timer, uwb_cnflt_timer, 0);
-
-       cnflt->rc = rc;
-       INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work);
-
-       bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS);
-
-       list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list);
-
-       /* update rc global conflicting alien bitmap */
-       bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS);
-
-       queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us));
-
-       /* start the timer */
-       uwb_cnflt_alien_stroke_timer(cnflt);
-}
-
-static void uwb_drp_process_not_involved(struct uwb_rc *rc,
-                                        struct uwb_rc_evt_drp *drp_evt,
-                                        struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_mas_bm mas;
-
-       uwb_drp_ie_to_bm(&mas, drp_ie);
-       uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas);
-}
-
-static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src,
-                                    struct uwb_rc_evt_drp *drp_evt,
-                                    struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_rsv *rsv;
-
-       rsv = uwb_rsv_find(rc, src, drp_ie);
-       if (!rsv) {
-               /*
-                * No reservation? It's either for a recently
-                * terminated reservation; or the DRP IE couldn't be
-                * processed (e.g., an invalid IE or out of memory).
-                */
-               return;
-       }
-
-       /*
-        * Do nothing with DRP IEs for reservations that have been
-        * terminated.
-        */
-       if (rsv->state == UWB_RSV_STATE_NONE) {
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-               return;
-       }
-
-       if (uwb_ie_drp_owner(drp_ie))
-               uwb_drp_process_target(rc, rsv, drp_ie, drp_evt);
-       else
-               uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt);
-
-}
-
-
-static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
-{
-       return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0;
-}
-
-/*
- * Process a received DRP IE.
- */
-static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
-                           struct uwb_dev *src, struct uwb_ie_drp *drp_ie)
-{
-       if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP)
-               uwb_drp_handle_alien_drp(rc, drp_ie);
-       else if (uwb_drp_involves_us(rc, drp_ie))
-               uwb_drp_process_involved(rc, src, drp_evt, drp_ie);
-       else
-               uwb_drp_process_not_involved(rc, drp_evt, drp_ie);
-}
-
-/*
- * Process a received DRP Availability IE
- */
-static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src,
-                                        struct uwb_ie_drp_avail *drp_availability_ie)
-{
-       bitmap_copy(src->last_availability_bm,
-                   drp_availability_ie->bmp, UWB_NUM_MAS);
-}
-
-/*
- * Process all the DRP IEs (both DRP IEs and the DRP Availability IE)
- * from a device.
- */
-static
-void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
-                        size_t ielen, struct uwb_dev *src_dev)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_ie_hdr *ie_hdr;
-       void *ptr;
-
-       ptr = drp_evt->ie_data;
-       for (;;) {
-               ie_hdr = uwb_ie_next(&ptr, &ielen);
-               if (!ie_hdr)
-                       break;
-
-               switch (ie_hdr->element_id) {
-               case UWB_IE_DRP_AVAILABILITY:
-                       uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr);
-                       break;
-               case UWB_IE_DRP:
-                       uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr);
-                       break;
-               default:
-                       dev_warn(dev, "unexpected IE in DRP notification\n");
-                       break;
-               }
-       }
-
-       if (ielen > 0)
-               dev_warn(dev, "%d octets remaining in DRP notification\n",
-                        (int)ielen);
-}
-
-/**
- * uwbd_evt_handle_rc_drp - handle a DRP_IE event
- * @evt: the DRP_IE event from the radio controller
- *
- * This processes DRP notifications from the radio controller, either
- * initiating a new reservation or transitioning an existing
- * reservation into a different state.
- *
- * DRP notifications can occur for three different reasons:
- *
- * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as
- *   the target or source have been received.
- *
- *   These DRP IEs could be new or for an existing reservation.
- *
- *   If the DRP IE for an existing reservation ceases to be to
- *   received for at least mMaxLostBeacons, the reservation should be
- *   considered to be terminated.  Note that the TERMINATE reason (see
- *   below) may not always be signalled (e.g., the remote device has
- *   two or more reservations established with the RC).
- *
- * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon
- *   group conflict with the RC's reservations.
- *
- * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received
- *   from a device (i.e., it's terminated all reservations).
- *
- * Only the software state of the reservations is changed; the setting
- * of the radio controller's DRP IEs is done after all the events in
- * an event buffer are processed.  This saves waiting multiple times
- * for the SET_DRP_IE command to complete.
- */
-int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
-{
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc *rc = evt->rc;
-       struct uwb_rc_evt_drp *drp_evt;
-       size_t ielength, bytes_left;
-       struct uwb_dev_addr src_addr;
-       struct uwb_dev *src_dev;
-
-       /* Is there enough data to decode the event (and any IEs in
-          its payload)? */
-       if (evt->notif.size < sizeof(*drp_evt)) {
-               dev_err(dev, "DRP event: Not enough data to decode event "
-                       "[%zu bytes left, %zu needed]\n",
-                       evt->notif.size, sizeof(*drp_evt));
-               return 0;
-       }
-       bytes_left = evt->notif.size - sizeof(*drp_evt);
-       drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb);
-       ielength = le16_to_cpu(drp_evt->ie_length);
-       if (bytes_left != ielength) {
-               dev_err(dev, "DRP event: Not enough data in payload [%zu"
-                       "bytes left, %zu declared in the event]\n",
-                       bytes_left, ielength);
-               return 0;
-       }
-
-       memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr));
-       src_dev = uwb_dev_get_by_devaddr(rc, &src_addr);
-       if (!src_dev) {
-               /*
-                * A DRP notification from an unrecognized device.
-                *
-                * This is probably from a WUSB device that doesn't
-                * have an EUI-48 and therefore doesn't show up in the
-                * UWB device database.  It's safe to simply ignore
-                * these.
-                */
-               return 0;
-       }
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       /* We do not distinguish from the reason */
-       uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
-
-       mutex_unlock(&rc->rsvs_mutex);
-
-       uwb_dev_put(src_dev);
-       return 0;
-}
diff --git a/drivers/staging/uwb/est.c b/drivers/staging/uwb/est.c
deleted file mode 100644 (file)
index d4141ff..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band Radio Control
- * Event Size Tables management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- *
- * Infrastructure, code and data tables for guessing the size of
- * events received on the notification endpoints of UWB radio
- * controllers.
- *
- * You define a table of events and for each, its size and how to get
- * the extra size.
- *
- * ENTRY POINTS:
- *
- * uwb_est_{init/destroy}(): To initialize/release the EST subsystem.
- *
- * uwb_est_[u]register(): To un/register event size tables
- *   uwb_est_grow()
- *
- * uwb_est_find_size(): Get the size of an event
- *   uwb_est_get_size()
- */
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-struct uwb_est {
-       u16 type_event_high;
-       u16 vendor, product;
-       u8 entries;
-       const struct uwb_est_entry *entry;
-};
-
-static struct uwb_est *uwb_est;
-static u8 uwb_est_size;
-static u8 uwb_est_used;
-static DEFINE_RWLOCK(uwb_est_lock);
-
-/**
- * WUSB Standard Event Size Table, HWA-RC interface
- *
- * Sizes for events and notifications type 0 (general), high nibble 0.
- */
-static
-struct uwb_est_entry uwb_est_00_00xx[] = {
-       [UWB_RC_EVT_IE_RCV] = {
-               .size = sizeof(struct uwb_rc_evt_ie_rcv),
-               .offset = 1 + offsetof(struct uwb_rc_evt_ie_rcv, wIELength),
-       },
-       [UWB_RC_EVT_BEACON] = {
-               .size = sizeof(struct uwb_rc_evt_beacon),
-               .offset = 1 + offsetof(struct uwb_rc_evt_beacon, wBeaconInfoLength),
-       },
-       [UWB_RC_EVT_BEACON_SIZE] = {
-               .size = sizeof(struct uwb_rc_evt_beacon_size),
-       },
-       [UWB_RC_EVT_BPOIE_CHANGE] = {
-               .size = sizeof(struct uwb_rc_evt_bpoie_change),
-               .offset = 1 + offsetof(struct uwb_rc_evt_bpoie_change,
-                                      wBPOIELength),
-       },
-       [UWB_RC_EVT_BP_SLOT_CHANGE] = {
-               .size = sizeof(struct uwb_rc_evt_bp_slot_change),
-       },
-       [UWB_RC_EVT_BP_SWITCH_IE_RCV] = {
-               .size = sizeof(struct uwb_rc_evt_bp_switch_ie_rcv),
-               .offset = 1 + offsetof(struct uwb_rc_evt_bp_switch_ie_rcv, wIELength),
-       },
-       [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
-               .size = sizeof(struct uwb_rc_evt_dev_addr_conflict),
-       },
-       [UWB_RC_EVT_DRP_AVAIL] = {
-               .size = sizeof(struct uwb_rc_evt_drp_avail)
-       },
-       [UWB_RC_EVT_DRP] = {
-               .size = sizeof(struct uwb_rc_evt_drp),
-               .offset = 1 + offsetof(struct uwb_rc_evt_drp, ie_length),
-       },
-       [UWB_RC_EVT_BP_SWITCH_STATUS] = {
-               .size = sizeof(struct uwb_rc_evt_bp_switch_status),
-       },
-       [UWB_RC_EVT_CMD_FRAME_RCV] = {
-               .size = sizeof(struct uwb_rc_evt_cmd_frame_rcv),
-               .offset = 1 + offsetof(struct uwb_rc_evt_cmd_frame_rcv, dataLength),
-       },
-       [UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV] = {
-               .size = sizeof(struct uwb_rc_evt_channel_change_ie_rcv),
-               .offset = 1 + offsetof(struct uwb_rc_evt_channel_change_ie_rcv, wIELength),
-       },
-       [UWB_RC_CMD_CHANNEL_CHANGE] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_DEV_ADDR_MGMT] = {
-               .size = sizeof(struct uwb_rc_evt_dev_addr_mgmt) },
-       [UWB_RC_CMD_GET_IE] = {
-               .size = sizeof(struct uwb_rc_evt_get_ie),
-               .offset = 1 + offsetof(struct uwb_rc_evt_get_ie, wIELength),
-       },
-       [UWB_RC_CMD_RESET] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SCAN] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SET_BEACON_FILTER] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SET_DRP_IE] = {
-               .size = sizeof(struct uwb_rc_evt_set_drp_ie),
-       },
-       [UWB_RC_CMD_SET_IE] = {
-               .size = sizeof(struct uwb_rc_evt_set_ie),
-       },
-       [UWB_RC_CMD_SET_NOTIFICATION_FILTER] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SET_TX_POWER] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SLEEP] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_START_BEACON] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_STOP_BEACON] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_BP_MERGE] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SEND_COMMAND_FRAME] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SET_ASIE_NOTIF] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-};
-
-static
-struct uwb_est_entry uwb_est_01_00xx[] = {
-       [UWB_RC_DAA_ENERGY_DETECTED] = {
-               .size = sizeof(struct uwb_rc_evt_daa_energy_detected),
-       },
-       [UWB_RC_SET_DAA_ENERGY_MASK] = {
-               .size = sizeof(struct uwb_rc_evt_set_daa_energy_mask),
-       },
-       [UWB_RC_SET_NOTIFICATION_FILTER_EX] = {
-               .size = sizeof(struct uwb_rc_evt_set_notification_filter_ex),
-       },
-};
-
-/**
- * Initialize the EST subsystem
- *
- * Register the standard tables also.
- *
- * FIXME: tag init
- */
-int uwb_est_create(void)
-{
-       int result;
-
-       uwb_est_size = 2;
-       uwb_est_used = 0;
-       uwb_est = kcalloc(uwb_est_size, sizeof(uwb_est[0]), GFP_KERNEL);
-       if (uwb_est == NULL)
-               return -ENOMEM;
-
-       result = uwb_est_register(UWB_RC_CET_GENERAL, 0, 0xffff, 0xffff,
-                                 uwb_est_00_00xx, ARRAY_SIZE(uwb_est_00_00xx));
-       if (result < 0)
-               goto out;
-       result = uwb_est_register(UWB_RC_CET_EX_TYPE_1, 0, 0xffff, 0xffff,
-                                 uwb_est_01_00xx, ARRAY_SIZE(uwb_est_01_00xx));
-out:
-       return result;
-}
-
-
-/** Clean it up */
-void uwb_est_destroy(void)
-{
-       kfree(uwb_est);
-       uwb_est = NULL;
-       uwb_est_size = uwb_est_used = 0;
-}
-
-
-/**
- * Double the capacity of the EST table
- *
- * @returns 0 if ok, < 0 errno no error.
- */
-static
-int uwb_est_grow(void)
-{
-       size_t actual_size = uwb_est_size * sizeof(uwb_est[0]);
-       void *new = kmalloc_array(2, actual_size, GFP_ATOMIC);
-       if (new == NULL)
-               return -ENOMEM;
-       memcpy(new, uwb_est, actual_size);
-       memset(new + actual_size, 0, actual_size);
-       kfree(uwb_est);
-       uwb_est = new;
-       uwb_est_size *= 2;
-       return 0;
-}
-
-
-/**
- * Register an event size table
- *
- * Makes room for it if the table is full, and then inserts  it in the
- * right position (entries are sorted by type, event_high, vendor and
- * then product).
- *
- * @vendor:  vendor code for matching against the device (0x0000 and
- *           0xffff mean any); use 0x0000 to force all to match without
- *           checking possible vendor specific ones, 0xfffff to match
- *           after checking vendor specific ones.
- *
- * @product: product code from that vendor; same matching rules, use
- *           0x0000 for not allowing vendor specific matches, 0xffff
- *           for allowing.
- *
- * This arragement just makes the tables sort differenty. Because the
- * table is sorted by growing type-event_high-vendor-product, a zero
- * vendor will match before than a 0x456a vendor, that will match
- * before a 0xfffff vendor.
- *
- * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
- */
-/* FIXME: add bus type to vendor/product code */
-int uwb_est_register(u8 type, u8 event_high, u16 vendor, u16 product,
-                    const struct uwb_est_entry *entry, size_t entries)
-{
-       unsigned long flags;
-       unsigned itr;
-       int result = 0;
-
-       write_lock_irqsave(&uwb_est_lock, flags);
-       if (uwb_est_used == uwb_est_size) {
-               result = uwb_est_grow();
-               if (result < 0)
-                       goto out;
-       }
-       /* Find the right spot to insert it in */
-       for (itr = 0; itr < uwb_est_used; itr++)
-               if (uwb_est[itr].type_event_high < type
-                   && uwb_est[itr].vendor < vendor
-                   && uwb_est[itr].product < product)
-                       break;
-
-       /* Shift others to make room for the new one? */
-       if (itr < uwb_est_used)
-               memmove(&uwb_est[itr+1], &uwb_est[itr], uwb_est_used - itr);
-       uwb_est[itr].type_event_high = type << 8 | event_high;
-       uwb_est[itr].vendor = vendor;
-       uwb_est[itr].product = product;
-       uwb_est[itr].entry = entry;
-       uwb_est[itr].entries = entries;
-       uwb_est_used++;
-out:
-       write_unlock_irqrestore(&uwb_est_lock, flags);
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_est_register);
-
-
-/**
- * Unregister an event size table
- *
- * This just removes the specified entry and moves the ones after it
- * to fill in the gap. This is needed to keep the list sorted; no
- * reallocation is done to reduce the size of the table.
- *
- * We unregister by all the data we used to register instead of by
- * pointer to the @entry array because we might have used the same
- * table for a bunch of IDs (for example).
- *
- * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
- */
-int uwb_est_unregister(u8 type, u8 event_high, u16 vendor, u16 product,
-                      const struct uwb_est_entry *entry, size_t entries)
-{
-       unsigned long flags;
-       unsigned itr;
-       struct uwb_est est_cmp = {
-               .type_event_high = type << 8 | event_high,
-               .vendor = vendor,
-               .product = product,
-               .entry = entry,
-               .entries = entries
-       };
-       write_lock_irqsave(&uwb_est_lock, flags);
-       for (itr = 0; itr < uwb_est_used; itr++)
-               if (!memcmp(&uwb_est[itr], &est_cmp, sizeof(est_cmp)))
-                       goto found;
-       write_unlock_irqrestore(&uwb_est_lock, flags);
-       return -ENOENT;
-
-found:
-       if (itr < uwb_est_used - 1)     /* Not last one? move ones above */
-               memmove(&uwb_est[itr], &uwb_est[itr+1], uwb_est_used - itr - 1);
-       uwb_est_used--;
-       write_unlock_irqrestore(&uwb_est_lock, flags);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uwb_est_unregister);
-
-
-/**
- * Get the size of an event from a table
- *
- * @rceb: pointer to the buffer with the event
- * @rceb_size: size of the area pointed to by @rceb in bytes.
- * @returns: > 0      Size of the event
- *          -ENOSPC  An area big enough was not provided to look
- *                   ahead into the event's guts and guess the size.
- *          -EINVAL  Unknown event code (wEvent).
- *
- * This will look at the received RCEB and guess what is the total
- * size. For variable sized events, it will look further ahead into
- * their length field to see how much data should be read.
- *
- * Note this size is *not* final--the neh (Notification/Event Handle)
- * might specificy an extra size to add.
- */
-static
-ssize_t uwb_est_get_size(struct uwb_rc *uwb_rc, struct uwb_est *est,
-                        u8 event_low, const struct uwb_rceb *rceb,
-                        size_t rceb_size)
-{
-       unsigned offset;
-       ssize_t size;
-       struct device *dev = &uwb_rc->uwb_dev.dev;
-       const struct uwb_est_entry *entry;
-
-       size = -ENOENT;
-       if (event_low >= est->entries) {        /* in range? */
-               dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u out of range\n",
-                       est, est->type_event_high, est->vendor, est->product,
-                       est->entries, event_low);
-               goto out;
-       }
-       size = -ENOENT;
-       entry = &est->entry[event_low];
-       if (entry->size == 0 && entry->offset == 0) {   /* unknown? */
-               dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u unknown\n",
-                       est, est->type_event_high, est->vendor, est->product,
-                       est->entries, event_low);
-               goto out;
-       }
-       offset = entry->offset; /* extra fries with that? */
-       if (offset == 0)
-               size = entry->size;
-       else {
-               /* Ops, got an extra size field at 'offset'--read it */
-               const void *ptr = rceb;
-               size_t type_size = 0;
-               offset--;
-               size = -ENOSPC;                 /* enough data for more? */
-               switch (entry->type) {
-               case UWB_EST_16:  type_size = sizeof(__le16); break;
-               case UWB_EST_8:   type_size = sizeof(u8);     break;
-               default:         BUG();
-               }
-               if (offset + type_size > rceb_size) {
-                       dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: "
-                               "not enough data to read extra size\n",
-                               est, est->type_event_high, est->vendor,
-                               est->product, est->entries);
-                       goto out;
-               }
-               size = entry->size;
-               ptr += offset;
-               switch (entry->type) {
-               case UWB_EST_16:  size += le16_to_cpu(*(__le16 *)ptr); break;
-               case UWB_EST_8:   size += *(u8 *)ptr;                  break;
-               default:         BUG();
-               }
-       }
-out:
-       return size;
-}
-
-
-/**
- * Guesses the size of a WA event
- *
- * @rceb: pointer to the buffer with the event
- * @rceb_size: size of the area pointed to by @rceb in bytes.
- * @returns: > 0      Size of the event
- *          -ENOSPC  An area big enough was not provided to look
- *                   ahead into the event's guts and guess the size.
- *          -EINVAL  Unknown event code (wEvent).
- *
- * This will look at the received RCEB and guess what is the total
- * size by checking all the tables registered with
- * uwb_est_register(). For variable sized events, it will look further
- * ahead into their length field to see how much data should be read.
- *
- * Note this size is *not* final--the neh (Notification/Event Handle)
- * might specificy an extra size to add or replace.
- */
-ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
-                         size_t rceb_size)
-{
-       /* FIXME: add vendor/product data */
-       ssize_t size;
-       struct device *dev = &rc->uwb_dev.dev;
-       unsigned long flags;
-       unsigned itr;
-       u16 type_event_high, event;
-
-       read_lock_irqsave(&uwb_est_lock, flags);
-       size = -ENOSPC;
-       if (rceb_size < sizeof(*rceb))
-               goto out;
-       event = le16_to_cpu(rceb->wEvent);
-       type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8;
-       for (itr = 0; itr < uwb_est_used; itr++) {
-               if (uwb_est[itr].type_event_high != type_event_high)
-                       continue;
-               size = uwb_est_get_size(rc, &uwb_est[itr],
-                                       event & 0x00ff, rceb, rceb_size);
-               /* try more tables that might handle the same type */
-               if (size != -ENOENT)
-                       goto out;
-       }
-       dev_dbg(dev,
-               "event 0x%02x/%04x/%02x: no handlers available; RCEB %4ph\n",
-               (unsigned) rceb->bEventType,
-               (unsigned) le16_to_cpu(rceb->wEvent),
-               (unsigned) rceb->bEventContext,
-               rceb);
-       size = -ENOENT;
-out:
-       read_unlock_irqrestore(&uwb_est_lock, flags);
-       return size;
-}
-EXPORT_SYMBOL_GPL(uwb_est_find_size);
diff --git a/drivers/staging/uwb/hwa-rc.c b/drivers/staging/uwb/hwa-rc.c
deleted file mode 100644 (file)
index b6effad..0000000
+++ /dev/null
@@ -1,929 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * WUSB Host Wire Adapter: Radio Control Interface (WUSB[8.6])
- * Radio Control command/event transport
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Initialize the Radio Control interface Driver.
- *
- * For each device probed, creates an 'struct hwarc' which contains
- * just the representation of the UWB Radio Controller, and the logic
- * for reading notifications and passing them to the UWB Core.
- *
- * So we initialize all of those, register the UWB Radio Controller
- * and setup the notification/event handle to pipe the notifications
- * to the UWB management Daemon.
- *
- * Command and event filtering.
- *
- * This is the driver for the Radio Control Interface described in WUSB
- * 1.0. The core UWB module assumes that all drivers are compliant to the
- * WHCI 0.95 specification. We thus create a filter that parses all
- * incoming messages from the (WUSB 1.0) device and manipulate them to
- * conform to the WHCI 0.95 specification. Similarly, outgoing messages
- * are parsed and manipulated to conform to the WUSB 1.0 compliant messages
- * that the device expects. Only a few messages are affected:
- * Affected events:
- *    UWB_RC_EVT_BEACON
- *    UWB_RC_EVT_BP_SLOT_CHANGE
- *    UWB_RC_EVT_DRP_AVAIL
- *    UWB_RC_EVT_DRP
- * Affected commands:
- *    UWB_RC_CMD_SCAN
- *    UWB_RC_CMD_SET_DRP_IE
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include "../wusbcore/include/wusb.h"
-#include "../wusbcore/include/wusb-wa.h"
-#include "uwb.h"
-
-#include "uwb-internal.h"
-
-/* The device uses commands and events from the WHCI specification, although
- * reporting itself as WUSB compliant. */
-#define WUSB_QUIRK_WHCI_CMD_EVT                0x01
-
-/**
- * Descriptor for an instance of the UWB Radio Control Driver that
- * attaches to the RCI interface of the Host Wired Adapter.
- *
- * Unless there is a lock specific to the 'data members', all access
- * is protected by uwb_rc->mutex.
- *
- * The NEEP (Notification/Event EndPoint) URB (@neep_urb) writes to
- * @rd_buffer. Note there is no locking because it is perfectly (heh!)
- * serialized--probe() submits an URB, callback is called, processes
- * the data (synchronously), submits another URB, and so on. There is
- * no concurrent access to the buffer.
- */
-struct hwarc {
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-       struct uwb_rc *uwb_rc;          /* UWB host controller */
-       struct urb *neep_urb;           /* Notification endpoint handling */
-       struct edc neep_edc;
-       void *rd_buffer;                /* NEEP read buffer */
-};
-
-
-/* Beacon received notification (WUSB 1.0 [8.6.3.2]) */
-struct uwb_rc_evt_beacon_WUSB_0100 {
-       struct uwb_rceb rceb;
-       u8      bChannelNumber;
-       __le16  wBPSTOffset;
-       u8      bLQI;
-       u8      bRSSI;
-       __le16  wBeaconInfoLength;
-       u8      BeaconInfo[];
-} __attribute__((packed));
-
-/**
- * Filter WUSB 1.0 BEACON RCV notification to be WHCI 0.95
- *
- * @header: the incoming event
- * @buf_size: size of buffer containing incoming event
- * @new_size: size of event after filtering completed
- *
- * The WHCI 0.95 spec has a "Beacon Type" field. This value is unknown at
- * the time we receive the beacon from WUSB so we just set it to
- * UWB_RC_BEACON_TYPE_NEIGHBOR as a default.
- * The solution below allocates memory upon receipt of every beacon from a
- * WUSB device. This will deteriorate performance. What is the right way to
- * do this?
- */
-static
-int hwarc_filter_evt_beacon_WUSB_0100(struct uwb_rc *rc,
-                                     struct uwb_rceb **header,
-                                     const size_t buf_size,
-                                     size_t *new_size)
-{
-       struct uwb_rc_evt_beacon_WUSB_0100 *be;
-       struct uwb_rc_evt_beacon *newbe;
-       size_t bytes_left, ielength;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       be = container_of(*header, struct uwb_rc_evt_beacon_WUSB_0100, rceb);
-       bytes_left = buf_size;
-       if (bytes_left < sizeof(*be)) {
-               dev_err(dev, "Beacon Received Notification: Not enough data "
-                       "to decode for filtering (%zu vs %zu bytes needed)\n",
-                       bytes_left, sizeof(*be));
-               return -EINVAL;
-       }
-       bytes_left -= sizeof(*be);
-       ielength = le16_to_cpu(be->wBeaconInfoLength);
-       if (bytes_left < ielength) {
-               dev_err(dev, "Beacon Received Notification: Not enough data "
-                       "to decode IEs (%zu vs %zu bytes needed)\n",
-                       bytes_left, ielength);
-               return -EINVAL;
-       }
-       newbe = kzalloc(sizeof(*newbe) + ielength, GFP_ATOMIC);
-       if (newbe == NULL)
-               return -ENOMEM;
-       newbe->rceb = be->rceb;
-       newbe->bChannelNumber = be->bChannelNumber;
-       newbe->bBeaconType = UWB_RC_BEACON_TYPE_NEIGHBOR;
-       newbe->wBPSTOffset = be->wBPSTOffset;
-       newbe->bLQI = be->bLQI;
-       newbe->bRSSI = be->bRSSI;
-       newbe->wBeaconInfoLength = be->wBeaconInfoLength;
-       memcpy(newbe->BeaconInfo, be->BeaconInfo, ielength);
-       *header = &newbe->rceb;
-       *new_size = sizeof(*newbe) + ielength;
-       return 1;  /* calling function will free memory */
-}
-
-
-/* DRP Availability change notification (WUSB 1.0 [8.6.3.8]) */
-struct uwb_rc_evt_drp_avail_WUSB_0100 {
-       struct uwb_rceb rceb;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/**
- * Filter WUSB 1.0 DRP AVAILABILITY CHANGE notification to be WHCI 0.95
- *
- * @header: the incoming event
- * @buf_size: size of buffer containing incoming event
- * @new_size: size of event after filtering completed
- */
-static
-int hwarc_filter_evt_drp_avail_WUSB_0100(struct uwb_rc *rc,
-                                        struct uwb_rceb **header,
-                                        const size_t buf_size,
-                                        size_t *new_size)
-{
-       struct uwb_rc_evt_drp_avail_WUSB_0100 *da;
-       struct uwb_rc_evt_drp_avail *newda;
-       struct uwb_ie_hdr *ie_hdr;
-       size_t bytes_left, ielength;
-       struct device *dev = &rc->uwb_dev.dev;
-
-
-       da = container_of(*header, struct uwb_rc_evt_drp_avail_WUSB_0100, rceb);
-       bytes_left = buf_size;
-       if (bytes_left < sizeof(*da)) {
-               dev_err(dev, "Not enough data to decode DRP Avail "
-                       "Notification for filtering. Expected %zu, "
-                       "received %zu.\n", (size_t)sizeof(*da), bytes_left);
-               return -EINVAL;
-       }
-       bytes_left -= sizeof(*da);
-       ielength = le16_to_cpu(da->wIELength);
-       if (bytes_left < ielength) {
-               dev_err(dev, "DRP Avail Notification filter: IE length "
-                       "[%zu bytes] does not match actual length "
-                       "[%zu bytes].\n", ielength, bytes_left);
-               return -EINVAL;
-       }
-       if (ielength < sizeof(*ie_hdr)) {
-               dev_err(dev, "DRP Avail Notification filter: Not enough "
-                       "data to decode IE [%zu bytes, %zu needed]\n",
-                       ielength, sizeof(*ie_hdr));
-               return -EINVAL;
-       }
-       ie_hdr = (void *) da->IEData;
-       if (ie_hdr->length > 32) {
-               dev_err(dev, "DRP Availability Change event has unexpected "
-                       "length for filtering. Expected < 32 bytes, "
-                       "got %zu bytes.\n", (size_t)ie_hdr->length);
-               return -EINVAL;
-       }
-       newda = kzalloc(sizeof(*newda), GFP_ATOMIC);
-       if (newda == NULL)
-               return -ENOMEM;
-       newda->rceb = da->rceb;
-       memcpy(newda->bmp, (u8 *) ie_hdr + sizeof(*ie_hdr), ie_hdr->length);
-       *header = &newda->rceb;
-       *new_size = sizeof(*newda);
-       return 1; /* calling function will free memory */
-}
-
-
-/* DRP notification (WUSB 1.0 [8.6.3.9]) */
-struct uwb_rc_evt_drp_WUSB_0100 {
-       struct uwb_rceb rceb;
-       struct uwb_dev_addr wSrcAddr;
-       u8 bExplicit;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/**
- * Filter WUSB 1.0 DRP Notification to be WHCI 0.95
- *
- * @header: the incoming event
- * @buf_size: size of buffer containing incoming event
- * @new_size: size of event after filtering completed
- *
- * It is hard to manage DRP reservations without having a Reason code.
- * Unfortunately there is none in the WUSB spec. We just set the default to
- * DRP IE RECEIVED.
- * We do not currently use the bBeaconSlotNumber value, so we set this to
- * zero for now.
- */
-static
-int hwarc_filter_evt_drp_WUSB_0100(struct uwb_rc *rc,
-                                  struct uwb_rceb **header,
-                                  const size_t buf_size,
-                                  size_t *new_size)
-{
-       struct uwb_rc_evt_drp_WUSB_0100 *drpev;
-       struct uwb_rc_evt_drp *newdrpev;
-       size_t bytes_left, ielength;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       drpev = container_of(*header, struct uwb_rc_evt_drp_WUSB_0100, rceb);
-       bytes_left = buf_size;
-       if (bytes_left < sizeof(*drpev)) {
-               dev_err(dev, "Not enough data to decode DRP Notification "
-                       "for filtering. Expected %zu, received %zu.\n",
-                       (size_t)sizeof(*drpev), bytes_left);
-               return -EINVAL;
-       }
-       ielength = le16_to_cpu(drpev->wIELength);
-       bytes_left -= sizeof(*drpev);
-       if (bytes_left < ielength) {
-               dev_err(dev, "DRP Notification filter: header length [%zu "
-                       "bytes] does not match actual length [%zu "
-                       "bytes].\n", ielength, bytes_left);
-               return -EINVAL;
-       }
-       newdrpev = kzalloc(sizeof(*newdrpev) + ielength, GFP_ATOMIC);
-       if (newdrpev == NULL)
-               return -ENOMEM;
-       newdrpev->rceb = drpev->rceb;
-       newdrpev->src_addr = drpev->wSrcAddr;
-       newdrpev->reason = UWB_DRP_NOTIF_DRP_IE_RCVD;
-       newdrpev->beacon_slot_number = 0;
-       newdrpev->ie_length = drpev->wIELength;
-       memcpy(newdrpev->ie_data, drpev->IEData, ielength);
-       *header = &newdrpev->rceb;
-       *new_size = sizeof(*newdrpev) + ielength;
-       return 1; /* calling function will free memory */
-}
-
-
-/* Scan Command (WUSB 1.0 [8.6.2.5]) */
-struct uwb_rc_cmd_scan_WUSB_0100 {
-       struct uwb_rccb rccb;
-       u8 bChannelNumber;
-       u8 bScanState;
-} __attribute__((packed));
-
-/**
- * Filter WHCI 0.95 SCAN command to be WUSB 1.0 SCAN command
- *
- * @header:   command sent to device (compliant to WHCI 0.95)
- * @size:     size of command sent to device
- *
- * We only reduce the size by two bytes because the WUSB 1.0 scan command
- * does not have the last field (wStarttime). Also, make sure we don't send
- * the device an unexpected scan type.
- */
-static
-int hwarc_filter_cmd_scan_WUSB_0100(struct uwb_rc *rc,
-                                   struct uwb_rccb **header,
-                                   size_t *size)
-{
-       struct uwb_rc_cmd_scan *sc;
-
-       sc = container_of(*header, struct uwb_rc_cmd_scan, rccb);
-
-       if (sc->bScanState == UWB_SCAN_ONLY_STARTTIME)
-               sc->bScanState = UWB_SCAN_ONLY;
-       /* Don't send the last two bytes. */
-       *size -= 2;
-       return 0;
-}
-
-
-/* SET DRP IE command (WUSB 1.0 [8.6.2.7]) */
-struct uwb_rc_cmd_set_drp_ie_WUSB_0100 {
-       struct uwb_rccb rccb;
-       u8 bExplicit;
-       __le16 wIELength;
-       struct uwb_ie_drp IEData[];
-} __attribute__((packed));
-
-/**
- * Filter WHCI 0.95 SET DRP IE command to be WUSB 1.0 SET DRP IE command
- *
- * @header:   command sent to device (compliant to WHCI 0.95)
- * @size:     size of command sent to device
- *
- * WUSB has an extra bExplicit field - we assume always explicit
- * negotiation so this field is set. The command expected by the device is
- * thus larger than the one prepared by the driver so we need to
- * reallocate memory to accommodate this.
- * We trust the driver to send us the correct data so no checking is done
- * on incoming data - evn though it is variable length.
- */
-static
-int hwarc_filter_cmd_set_drp_ie_WUSB_0100(struct uwb_rc *rc,
-                                         struct uwb_rccb **header,
-                                         size_t *size)
-{
-       struct uwb_rc_cmd_set_drp_ie *orgcmd;
-       struct uwb_rc_cmd_set_drp_ie_WUSB_0100 *cmd;
-       size_t ielength;
-
-       orgcmd = container_of(*header, struct uwb_rc_cmd_set_drp_ie, rccb);
-       ielength = le16_to_cpu(orgcmd->wIELength);
-       cmd = kzalloc(sizeof(*cmd) + ielength, GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-       cmd->rccb = orgcmd->rccb;
-       cmd->bExplicit = 0;
-       cmd->wIELength = orgcmd->wIELength;
-       memcpy(cmd->IEData, orgcmd->IEData, ielength);
-       *header = &cmd->rccb;
-       *size = sizeof(*cmd) + ielength;
-       return 1; /* calling function will free memory */
-}
-
-
-/**
- * Filter data from WHCI driver to WUSB device
- *
- * @header: WHCI 0.95 compliant command from driver
- * @size:   length of command
- *
- * The routine managing commands to the device (uwb_rc_cmd()) will call the
- * filtering function pointer (if it exists) before it passes any data to
- * the device. At this time the command has been formatted according to
- * WHCI 0.95 and is ready to be sent to the device.
- *
- * The filter function will be provided with the current command and its
- * length. The function will manipulate the command if necessary and
- * potentially reallocate memory for a command that needed more memory that
- * the given command. If new memory was created the function will return 1
- * to indicate to the calling function that the memory need to be freed
- * when not needed any more. The size will contain the new length of the
- * command.
- * If memory has not been allocated we rely on the original mechanisms to
- * free the memory of the command - even when we reduce the value of size.
- */
-static
-int hwarc_filter_cmd_WUSB_0100(struct uwb_rc *rc, struct uwb_rccb **header,
-                              size_t *size)
-{
-       int result;
-       struct uwb_rccb *rccb = *header;
-       int cmd = le16_to_cpu(rccb->wCommand);
-       switch (cmd) {
-       case UWB_RC_CMD_SCAN:
-               result = hwarc_filter_cmd_scan_WUSB_0100(rc, header, size);
-               break;
-       case UWB_RC_CMD_SET_DRP_IE:
-               result = hwarc_filter_cmd_set_drp_ie_WUSB_0100(rc, header, size);
-               break;
-       default:
-               result = -ENOANO;
-               break;
-       }
-       return result;
-}
-
-
-/**
- * Filter data from WHCI driver to WUSB device
- *
- * @header: WHCI 0.95 compliant command from driver
- * @size:   length of command
- *
- * Filter commands based on which protocol the device supports. The WUSB
- * errata should be the same as WHCI 0.95 so we do not filter that here -
- * only WUSB 1.0.
- */
-static
-int hwarc_filter_cmd(struct uwb_rc *rc, struct uwb_rccb **header,
-                    size_t *size)
-{
-       int result = -ENOANO;
-       if (rc->version == 0x0100)
-               result = hwarc_filter_cmd_WUSB_0100(rc, header, size);
-       return result;
-}
-
-
-/**
- * Compute return value as sum of incoming value and value at given offset
- *
- * @rceb:      event for which we compute the size, it contains a variable
- *            length field.
- * @core_size: size of the "non variable" part of the event
- * @offset:    place in event where the length of the variable part is stored
- * @buf_size: total length of buffer in which event arrived - we need to make
- *            sure we read the offset in memory that is still part of the event
- */
-static
-ssize_t hwarc_get_event_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
-                            size_t core_size, size_t offset,
-                            const size_t buf_size)
-{
-       ssize_t size = -ENOSPC;
-       const void *ptr = rceb;
-       size_t type_size = sizeof(__le16);
-       struct device *dev = &rc->uwb_dev.dev;
-
-       if (offset + type_size >= buf_size) {
-               dev_err(dev, "Not enough data to read extra size of event "
-                       "0x%02x/%04x/%02x, only got %zu bytes.\n",
-                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                       rceb->bEventContext, buf_size);
-               goto out;
-       }
-       ptr += offset;
-       size = core_size + le16_to_cpu(*(__le16 *)ptr);
-out:
-       return size;
-}
-
-
-/* Beacon slot change notification (WUSB 1.0 [8.6.3.5]) */
-struct uwb_rc_evt_bp_slot_change_WUSB_0100 {
-       struct uwb_rceb rceb;
-       u8 bSlotNumber;
-} __attribute__((packed));
-
-
-/**
- * Filter data from WUSB device to WHCI driver
- *
- * @header:     incoming event
- * @buf_size:   size of buffer in which event arrived
- * @_event_size: actual size of event in the buffer
- * @new_size:   size of event after filtered
- *
- * We don't know how the buffer is constructed - there may be more than one
- * event in it so buffer length does not determine event length. We first
- * determine the expected size of the incoming event. This value is passed
- * back only if the actual filtering succeeded (so we know the computed
- * expected size is correct). This value will be zero if
- * the event did not need any filtering.
- *
- * WHCI interprets the BP Slot Change event's data differently than
- * WUSB. The event sizes are exactly the same. The data field
- * indicates the new beacon slot in which a RC is transmitting its
- * beacon. The maximum value of this is 96 (wMacBPLength ECMA-368
- * 17.16 (Table 117)). We thus know that the WUSB value will not set
- * the bit bNoSlot, so we don't really do anything (placeholder).
- */
-static
-int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header,
-                                const size_t buf_size, size_t *_real_size,
-                                size_t *_new_size)
-{
-       int result = -ENOANO;
-       struct uwb_rceb *rceb = *header;
-       int event = le16_to_cpu(rceb->wEvent);
-       ssize_t event_size;
-       size_t core_size, offset;
-
-       if (rceb->bEventType != UWB_RC_CET_GENERAL)
-               goto out;
-       switch (event) {
-       case UWB_RC_EVT_BEACON:
-               core_size = sizeof(struct uwb_rc_evt_beacon_WUSB_0100);
-               offset = offsetof(struct uwb_rc_evt_beacon_WUSB_0100,
-                                 wBeaconInfoLength);
-               event_size = hwarc_get_event_size(rc, rceb, core_size,
-                                                 offset, buf_size);
-               if (event_size < 0)
-                       goto out;
-               *_real_size = event_size;
-               result = hwarc_filter_evt_beacon_WUSB_0100(rc, header,
-                                                          buf_size, _new_size);
-               break;
-       case UWB_RC_EVT_BP_SLOT_CHANGE:
-               *_new_size = *_real_size =
-                       sizeof(struct uwb_rc_evt_bp_slot_change_WUSB_0100);
-               result = 0;
-               break;
-
-       case UWB_RC_EVT_DRP_AVAIL:
-               core_size = sizeof(struct uwb_rc_evt_drp_avail_WUSB_0100);
-               offset = offsetof(struct uwb_rc_evt_drp_avail_WUSB_0100,
-                                 wIELength);
-               event_size = hwarc_get_event_size(rc, rceb, core_size,
-                                                 offset, buf_size);
-               if (event_size < 0)
-                       goto out;
-               *_real_size = event_size;
-               result = hwarc_filter_evt_drp_avail_WUSB_0100(
-                       rc, header, buf_size, _new_size);
-               break;
-
-       case UWB_RC_EVT_DRP:
-               core_size = sizeof(struct uwb_rc_evt_drp_WUSB_0100);
-               offset = offsetof(struct uwb_rc_evt_drp_WUSB_0100, wIELength);
-               event_size = hwarc_get_event_size(rc, rceb, core_size,
-                                                 offset, buf_size);
-               if (event_size < 0)
-                       goto out;
-               *_real_size = event_size;
-               result = hwarc_filter_evt_drp_WUSB_0100(rc, header,
-                                                       buf_size, _new_size);
-               break;
-
-       default:
-               break;
-       }
-out:
-       return result;
-}
-
-/**
- * Filter data from WUSB device to WHCI driver
- *
- * @header:     incoming event
- * @buf_size:   size of buffer in which event arrived
- * @_event_size: actual size of event in the buffer
- * @_new_size:  size of event after filtered
- *
- * Filter events based on which protocol the device supports. The WUSB
- * errata should be the same as WHCI 0.95 so we do not filter that here -
- * only WUSB 1.0.
- *
- * If we don't handle it, we return -ENOANO (why the weird error code?
- * well, so if I get it, I can pinpoint in the code that raised
- * it...after all, not too many places use the higher error codes).
- */
-static
-int hwarc_filter_event(struct uwb_rc *rc, struct uwb_rceb **header,
-                      const size_t buf_size, size_t *_real_size,
-                      size_t *_new_size)
-{
-       int result = -ENOANO;
-       if (rc->version == 0x0100)
-               result =  hwarc_filter_event_WUSB_0100(
-                       rc, header, buf_size, _real_size, _new_size);
-       return result;
-}
-
-
-/**
- * Execute an UWB RC command on HWA
- *
- * @rc:              Instance of a Radio Controller that is a HWA
- * @cmd:      Buffer containing the RCCB and payload to execute
- * @cmd_size: Size of the command buffer.
- *
- * NOTE: rc's mutex has to be locked
- */
-static
-int hwarc_cmd(struct uwb_rc *uwb_rc, const struct uwb_rccb *cmd, size_t cmd_size)
-{
-       struct hwarc *hwarc = uwb_rc->priv;
-       return usb_control_msg(
-               hwarc->usb_dev, usb_sndctrlpipe(hwarc->usb_dev, 0),
-               WA_EXEC_RC_CMD, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, hwarc->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               (void *) cmd, cmd_size, 100 /* FIXME: this is totally arbitrary */);
-}
-
-static
-int hwarc_reset(struct uwb_rc *uwb_rc)
-{
-       struct hwarc *hwarc = uwb_rc->priv;
-       int result;
-
-       /* device lock must be held when calling usb_reset_device. */
-       result = usb_lock_device_for_reset(hwarc->usb_dev, NULL);
-       if (result >= 0) {
-               result = usb_reset_device(hwarc->usb_dev);
-               usb_unlock_device(hwarc->usb_dev);
-       }
-
-       return result;
-}
-
-/**
- * Callback for the notification and event endpoint
- *
- * Check's that everything is fine and then passes the read data to
- * the notification/event handling mechanism (neh).
- */
-static
-void hwarc_neep_cb(struct urb *urb)
-{
-       struct hwarc *hwarc = urb->context;
-       struct usb_interface *usb_iface = hwarc->usb_iface;
-       struct device *dev = &usb_iface->dev;
-       int result;
-
-       switch (result = urb->status) {
-       case 0:
-               uwb_rc_neh_grok(hwarc->uwb_rc, urb->transfer_buffer,
-                               urb->actual_length);
-               break;
-       case -ECONNRESET:       /* Not an error, but a controlled situation; */
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-               goto out;
-       case -ESHUTDOWN:        /* going away! */
-               goto out;
-       default:                /* On general errors, retry unless it gets ugly */
-               if (edc_inc(&hwarc->neep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME))
-                       goto error_exceeded;
-               dev_err(dev, "NEEP: URB error %d\n", urb->status);
-       }
-       result = usb_submit_urb(urb, GFP_ATOMIC);
-       if (result < 0 && result != -ENODEV && result != -EPERM) {
-               /* ignoring unrecoverable errors */
-               dev_err(dev, "NEEP: Can't resubmit URB (%d) resetting device\n",
-                       result);
-               goto error;
-       }
-out:
-       return;
-
-error_exceeded:
-       dev_err(dev, "NEEP: URB max acceptable errors "
-               "exceeded, resetting device\n");
-error:
-       uwb_rc_neh_error(hwarc->uwb_rc, result);
-       uwb_rc_reset_all(hwarc->uwb_rc);
-       return;
-}
-
-static void hwarc_init(struct hwarc *hwarc)
-{
-       edc_init(&hwarc->neep_edc);
-}
-
-/**
- * Initialize the notification/event endpoint stuff
- *
- * Note this is effectively a parallel thread; it knows that
- * hwarc->uwb_rc always exists because the existence of a 'hwarc'
- * means that there is a reverence on the hwarc->uwb_rc (see
- * _probe()), and thus _neep_cb() can execute safely.
- */
-static int hwarc_neep_init(struct uwb_rc *rc)
-{
-       struct hwarc *hwarc = rc->priv;
-       struct usb_interface *iface = hwarc->usb_iface;
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-       struct device *dev = &iface->dev;
-       int result;
-       struct usb_endpoint_descriptor *epd;
-
-       epd = &iface->cur_altsetting->endpoint[0].desc;
-       hwarc->rd_buffer = (void *) __get_free_page(GFP_KERNEL);
-       if (hwarc->rd_buffer == NULL) {
-               dev_err(dev, "Unable to allocate notification's read buffer\n");
-               goto error_rd_buffer;
-       }
-       hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (hwarc->neep_urb == NULL)
-               goto error_urb_alloc;
-       usb_fill_int_urb(hwarc->neep_urb, usb_dev,
-                        usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
-                        hwarc->rd_buffer, PAGE_SIZE,
-                        hwarc_neep_cb, hwarc, epd->bInterval);
-       result = usb_submit_urb(hwarc->neep_urb, GFP_ATOMIC);
-       if (result < 0) {
-               dev_err(dev, "Cannot submit notification URB: %d\n", result);
-               goto error_neep_submit;
-       }
-       return 0;
-
-error_neep_submit:
-       usb_free_urb(hwarc->neep_urb);
-       hwarc->neep_urb = NULL;
-error_urb_alloc:
-       free_page((unsigned long)hwarc->rd_buffer);
-       hwarc->rd_buffer = NULL;
-error_rd_buffer:
-       return -ENOMEM;
-}
-
-
-/** Clean up all the notification endpoint resources */
-static void hwarc_neep_release(struct uwb_rc *rc)
-{
-       struct hwarc *hwarc = rc->priv;
-
-       usb_kill_urb(hwarc->neep_urb);
-       usb_free_urb(hwarc->neep_urb);
-       hwarc->neep_urb = NULL;
-
-       free_page((unsigned long)hwarc->rd_buffer);
-       hwarc->rd_buffer = NULL;
-}
-
-/**
- * Get the version from class-specific descriptor
- *
- * NOTE: this descriptor comes with the big bundled configuration
- *      descriptor that includes the interfaces' and endpoints', so
- *      we just look for it in the cached copy kept by the USB stack.
- *
- * NOTE2: We convert LE fields to CPU order.
- */
-static int hwarc_get_version(struct uwb_rc *rc)
-{
-       int result;
-
-       struct hwarc *hwarc = rc->priv;
-       struct uwb_rc_control_intf_class_desc *descr;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct usb_device *usb_dev = hwarc->usb_dev;
-       char *itr;
-       struct usb_descriptor_header *hdr;
-       size_t itr_size, actconfig_idx;
-       u16 version;
-
-       actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
-               sizeof(usb_dev->config[0]);
-       itr = usb_dev->rawdescriptors[actconfig_idx];
-       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
-       while (itr_size >= sizeof(*hdr)) {
-               hdr = (struct usb_descriptor_header *) itr;
-               dev_dbg(dev, "Extra device descriptor: "
-                       "type %02x/%u bytes @ %zu (%zu left)\n",
-                       hdr->bDescriptorType, hdr->bLength,
-                       (itr - usb_dev->rawdescriptors[actconfig_idx]),
-                       itr_size);
-               if (hdr->bDescriptorType == USB_DT_CS_RADIO_CONTROL)
-                       goto found;
-               itr += hdr->bLength;
-               itr_size -= hdr->bLength;
-       }
-       dev_err(dev, "cannot find Radio Control Interface Class descriptor\n");
-       return -ENODEV;
-
-found:
-       result = -EINVAL;
-       if (hdr->bLength > itr_size) {  /* is it available? */
-               dev_err(dev, "incomplete Radio Control Interface Class "
-                       "descriptor (%zu bytes left, %u needed)\n",
-                       itr_size, hdr->bLength);
-               goto error;
-       }
-       if (hdr->bLength < sizeof(*descr)) {
-               dev_err(dev, "short Radio Control Interface Class "
-                       "descriptor\n");
-               goto error;
-       }
-       descr = (struct uwb_rc_control_intf_class_desc *) hdr;
-       /* Make LE fields CPU order */
-       version = __le16_to_cpu(descr->bcdRCIVersion);
-       if (version != 0x0100) {
-               dev_err(dev, "Device reports protocol version 0x%04x. We "
-                       "do not support that. \n", version);
-               result = -EINVAL;
-               goto error;
-       }
-       rc->version = version;
-       dev_dbg(dev, "Device supports WUSB protocol version 0x%04x \n", rc->version);
-       result = 0;
-error:
-       return result;
-}
-
-/*
- * By creating a 'uwb_rc', we have a reference on it -- that reference
- * is the one we drop when we disconnect.
- *
- * No need to switch altsettings; according to WUSB1.0[8.6.1.1], there
- * is only one altsetting allowed.
- */
-static int hwarc_probe(struct usb_interface *iface,
-                      const struct usb_device_id *id)
-{
-       int result;
-       struct uwb_rc *uwb_rc;
-       struct hwarc *hwarc;
-       struct device *dev = &iface->dev;
-
-       if (iface->cur_altsetting->desc.bNumEndpoints < 1)
-               return -ENODEV;
-       if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc))
-               return -ENODEV;
-
-       result = -ENOMEM;
-       uwb_rc = uwb_rc_alloc();
-       if (uwb_rc == NULL) {
-               dev_err(dev, "unable to allocate RC instance\n");
-               goto error_rc_alloc;
-       }
-       hwarc = kzalloc(sizeof(*hwarc), GFP_KERNEL);
-       if (hwarc == NULL) {
-               dev_err(dev, "unable to allocate HWA RC instance\n");
-               goto error_alloc;
-       }
-       hwarc_init(hwarc);
-       hwarc->usb_dev = usb_get_dev(interface_to_usbdev(iface));
-       hwarc->usb_iface = usb_get_intf(iface);
-       hwarc->uwb_rc = uwb_rc;
-
-       uwb_rc->owner = THIS_MODULE;
-       uwb_rc->start = hwarc_neep_init;
-       uwb_rc->stop  = hwarc_neep_release;
-       uwb_rc->cmd   = hwarc_cmd;
-       uwb_rc->reset = hwarc_reset;
-       if (id->driver_info & WUSB_QUIRK_WHCI_CMD_EVT) {
-               uwb_rc->filter_cmd   = NULL;
-               uwb_rc->filter_event = NULL;
-       } else {
-               uwb_rc->filter_cmd   = hwarc_filter_cmd;
-               uwb_rc->filter_event = hwarc_filter_event;
-       }
-
-       result = uwb_rc_add(uwb_rc, dev, hwarc);
-       if (result < 0)
-               goto error_rc_add;
-       result = hwarc_get_version(uwb_rc);
-       if (result < 0) {
-               dev_err(dev, "cannot retrieve version of RC \n");
-               goto error_get_version;
-       }
-       usb_set_intfdata(iface, hwarc);
-       return 0;
-
-error_get_version:
-       uwb_rc_rm(uwb_rc);
-error_rc_add:
-       usb_put_intf(iface);
-       usb_put_dev(hwarc->usb_dev);
-       kfree(hwarc);
-error_alloc:
-       uwb_rc_put(uwb_rc);
-error_rc_alloc:
-       return result;
-}
-
-static void hwarc_disconnect(struct usb_interface *iface)
-{
-       struct hwarc *hwarc = usb_get_intfdata(iface);
-       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
-
-       usb_set_intfdata(hwarc->usb_iface, NULL);
-       uwb_rc_rm(uwb_rc);
-       usb_put_intf(hwarc->usb_iface);
-       usb_put_dev(hwarc->usb_dev);
-       kfree(hwarc);
-       uwb_rc_put(uwb_rc);     /* when creating the device, refcount = 1 */
-}
-
-static int hwarc_pre_reset(struct usb_interface *iface)
-{
-       struct hwarc *hwarc = usb_get_intfdata(iface);
-       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
-
-       uwb_rc_pre_reset(uwb_rc);
-       return 0;
-}
-
-static int hwarc_post_reset(struct usb_interface *iface)
-{
-       struct hwarc *hwarc = usb_get_intfdata(iface);
-       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
-
-       return uwb_rc_post_reset(uwb_rc);
-}
-
-/** USB device ID's that we handle */
-static const struct usb_device_id hwarc_id_table[] = {
-       /* D-Link DUB-1210 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3d02, 0xe0, 0x01, 0x02),
-         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
-       /* Intel i1480 (using firmware 1.3PA2-20070828) */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x8086, 0x0c3b, 0xe0, 0x01, 0x02),
-         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
-       /* Alereon 5310 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x01, 0x02),
-         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
-       /* Alereon 5611 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x01, 0x02),
-         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
-       /* Generic match for the Radio Control interface */
-       { USB_INTERFACE_INFO(0xe0, 0x01, 0x02), },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, hwarc_id_table);
-
-static struct usb_driver hwarc_driver = {
-       .name =         "hwa-rc",
-       .id_table =     hwarc_id_table,
-       .probe =        hwarc_probe,
-       .disconnect =   hwarc_disconnect,
-       .pre_reset =    hwarc_pre_reset,
-       .post_reset =   hwarc_post_reset,
-};
-
-module_usb_driver(hwarc_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Host Wireless Adapter Radio Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/i1480/Makefile b/drivers/staging/uwb/i1480/Makefile
deleted file mode 100644 (file)
index d26fb9b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_UWB_I1480U)       += dfu/ i1480-est.o
diff --git a/drivers/staging/uwb/i1480/dfu/Makefile b/drivers/staging/uwb/i1480/dfu/Makefile
deleted file mode 100644 (file)
index 4739fda..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_UWB_I1480U)       += i1480-dfu-usb.o
-
-i1480-dfu-usb-objs := \
-       dfu.o   \
-       mac.o   \
-       phy.o   \
-       usb.o
-
-
diff --git a/drivers/staging/uwb/i1480/dfu/dfu.c b/drivers/staging/uwb/i1480/dfu/dfu.c
deleted file mode 100644 (file)
index 9d51ce8..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Wireless UWB Link 1480
- * Main driver
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Common code for firmware upload used by the USB and PCI version;
- * i1480_fw_upload() takes a device descriptor and uses the function
- * pointers it provides to upload firmware and prepare the PHY.
- *
- * As well, provides common functions used by the rest of the code.
- */
-#include "i1480-dfu.h"
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/device.h>
-#include <linux/random.h>
-#include <linux/export.h>
-#include "../../uwb.h"
-
-/*
- * i1480_rceb_check - Check RCEB for expected field values
- * @i1480: pointer to device for which RCEB is being checked
- * @rceb: RCEB being checked
- * @cmd: which command the RCEB is related to
- * @context: expected context
- * @expected_type: expected event type
- * @expected_event: expected event
- *
- * If @cmd is NULL, do not print error messages, but still return an error
- * code.
- *
- * Return 0 if @rceb matches the expected values, -EINVAL otherwise.
- */
-int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb,
-                    const char *cmd, u8 context, u8 expected_type,
-                    unsigned expected_event)
-{
-       int result = 0;
-       struct device *dev = i1480->dev;
-       if (rceb->bEventContext != context) {
-               if (cmd)
-                       dev_err(dev, "%s: unexpected context id 0x%02x "
-                               "(expected 0x%02x)\n", cmd,
-                               rceb->bEventContext, context);
-               result = -EINVAL;
-       }
-       if (rceb->bEventType != expected_type) {
-               if (cmd)
-                       dev_err(dev, "%s: unexpected event type 0x%02x "
-                               "(expected 0x%02x)\n", cmd,
-                               rceb->bEventType, expected_type);
-               result = -EINVAL;
-       }
-       if (le16_to_cpu(rceb->wEvent) != expected_event) {
-               if (cmd)
-                       dev_err(dev, "%s: unexpected event 0x%04x "
-                               "(expected 0x%04x)\n", cmd,
-                               le16_to_cpu(rceb->wEvent), expected_event);
-               result = -EINVAL;
-       }
-       return result;
-}
-EXPORT_SYMBOL_GPL(i1480_rceb_check);
-
-
-/*
- * Execute a Radio Control Command
- *
- * Command data has to be in i1480->cmd_buf.
- *
- * @returns size of the reply data filled in i1480->evt_buf or < 0 errno
- *          code on error.
- */
-ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size,
-                 size_t reply_size)
-{
-       ssize_t result;
-       struct uwb_rceb *reply = i1480->evt_buf;
-       struct uwb_rccb *cmd = i1480->cmd_buf;
-       u16 expected_event = reply->wEvent;
-       u8 expected_type = reply->bEventType;
-       u8 context;
-
-       init_completion(&i1480->evt_complete);
-       i1480->evt_result = -EINPROGRESS;
-       do {
-               get_random_bytes(&context, 1);
-       } while (context == 0x00 || context == 0xff);
-       cmd->bCommandContext = context;
-       result = i1480->cmd(i1480, cmd_name, cmd_size);
-       if (result < 0)
-               goto error;
-       /* wait for the callback to report a event was received */
-       result = wait_for_completion_interruptible_timeout(
-               &i1480->evt_complete, HZ);
-       if (result == 0) {
-               result = -ETIMEDOUT;
-               goto error;
-       }
-       if (result < 0)
-               goto error;
-       result = i1480->evt_result;
-       if (result < 0) {
-               dev_err(i1480->dev, "%s: command reply reception failed: %zd\n",
-                       cmd_name, result);
-               goto error;
-       }
-       /*
-        * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a
-        * spurious notification after firmware is downloaded. So check whether
-        * the receibed RCEB is such notification before assuming that the
-        * command has failed.
-        */
-       if (i1480_rceb_check(i1480, i1480->evt_buf, NULL,
-                            0, 0xfd, 0x0022) == 0) {
-               /* Now wait for the actual RCEB for this command. */
-               result = i1480->wait_init_done(i1480);
-               if (result < 0)
-                       goto error;
-               result = i1480->evt_result;
-       }
-       if (result != reply_size) {
-               dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n",
-                       cmd_name, result, reply_size);
-               result = -EINVAL;
-               goto error;
-       }
-       /* Verify we got the right event in response */
-       result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context,
-                                 expected_type, expected_event);
-error:
-       return result;
-}
-EXPORT_SYMBOL_GPL(i1480_cmd);
-
-
-static
-int i1480_print_state(struct i1480 *i1480)
-{
-       int result;
-       u32 *buf = (u32 *) i1480->cmd_buf;
-
-       result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf));
-       if (result < 0) {
-               dev_err(i1480->dev, "cannot read U & L states: %d\n", result);
-               goto error;
-       }
-       dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]);
-error:
-       return result;
-}
-
-
-/*
- * PCI probe, firmware uploader
- *
- * _mac_fw_upload() will call rc_setup(), which needs an rc_release().
- */
-int i1480_fw_upload(struct i1480 *i1480)
-{
-       int result;
-
-       result = i1480_pre_fw_upload(i1480);    /* PHY pre fw */
-       if (result < 0 && result != -ENOENT) {
-               i1480_print_state(i1480);
-               goto error;
-       }
-       result = i1480_mac_fw_upload(i1480);    /* MAC fw */
-       if (result < 0) {
-               if (result == -ENOENT)
-                       dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n",
-                               i1480->mac_fw_name);
-               else
-                       i1480_print_state(i1480);
-               goto error;
-       }
-       result = i1480_phy_fw_upload(i1480);    /* PHY fw */
-       if (result < 0 && result != -ENOENT) {
-               i1480_print_state(i1480);
-               goto error_rc_release;
-       }
-       /*
-        * FIXME: find some reliable way to check whether firmware is running
-        * properly. Maybe use some standard request that has no side effects?
-        */
-       dev_info(i1480->dev, "firmware uploaded successfully\n");
-error_rc_release:
-       if (i1480->rc_release)
-               i1480->rc_release(i1480);
-       result = 0;
-error:
-       return result;
-}
-EXPORT_SYMBOL_GPL(i1480_fw_upload);
diff --git a/drivers/staging/uwb/i1480/dfu/i1480-dfu.h b/drivers/staging/uwb/i1480/dfu/i1480-dfu.h
deleted file mode 100644 (file)
index b21d058..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * i1480 Device Firmware Upload
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This driver is the firmware uploader for the Intel Wireless UWB
- * Link 1480 device (both in the USB and PCI incarnations).
- *
- * The process is quite simple: we stop the device, write the firmware
- * to its memory and then restart it. Wait for the device to let us
- * know it is done booting firmware. Ready.
- *
- * We might have to upload before or after a phy firmware (which might
- * be done in two methods, using a normal firmware image or through
- * the MPI port).
- *
- * Because USB and PCI use common methods, we just make ops out of the
- * common operations (read, write, wait_init_done and cmd) and
- * implement them in usb.c and pci.c.
- *
- * The flow is (some parts omitted):
- *
- * i1480_{usb,pci}_probe()       On enumerate/discovery
- *   i1480_fw_upload()
- *     i1480_pre_fw_upload()
- *       __mac_fw_upload()
- *         fw_hdrs_load()
- *         mac_fw_hdrs_push()
- *           i1480->write()       [i1480_{usb,pci}_write()]
- *           i1480_fw_cmp()
- *             i1480->read()      [i1480_{usb,pci}_read()]
- *     i1480_mac_fw_upload()
- *       __mac_fw_upload()
- *       i1480->setup(()
- *       i1480->wait_init_done()
- *       i1480_cmd_reset()
- *         i1480->cmd()           [i1480_{usb,pci}_cmd()]
- *         ...
- *     i1480_phy_fw_upload()
- *       request_firmware()
- *       i1480_mpi_write()
- *         i1480->cmd()           [i1480_{usb,pci}_cmd()]
- *
- * Once the probe function enumerates the device and uploads the
- * firmware, we just exit with -ENODEV, as we don't really want to
- * attach to the device.
- */
-#ifndef __i1480_DFU_H__
-#define __i1480_DFU_H__
-
-#include <linux/types.h>
-#include <linux/completion.h>
-#include "../../include/spec.h"
-
-#define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018))
-
-#if i1480_FW > 0x00000302
-#define i1480_RCEB_EXTENDED
-#endif
-
-struct uwb_rccb;
-struct uwb_rceb;
-
-/*
- * Common firmware upload handlers
- *
- * Normally you embed this struct in another one specific to your hw.
- *
- * @write      Write to device's memory from buffer.
- * @read       Read from device's memory to i1480->evt_buf.
- * @setup      Setup device after basic firmware is uploaded
- * @wait_init_done
- *              Wait for the device to send a notification saying init
- *              is done.
- * @cmd         FOP for issuing the command to the hardware. The
- *              command data is contained in i1480->cmd_buf and the size
- *              is supplied as an argument. The command replied is put
- *              in i1480->evt_buf and the size in i1480->evt_result (or if
- *              an error, a < 0 errno code).
- *
- * @cmd_buf    Memory buffer used to send commands to the device.
- *              Allocated by the upper layers i1480_fw_upload().
- *              Size has to be @buf_size.
- * @evt_buf    Memory buffer used to place the async notifications
- *              received by the hw. Allocated by the upper layers
- *              i1480_fw_upload().
- *              Size has to be @buf_size.
- * @cmd_complete
- *              Low level driver uses this to notify code waiting afor
- *              an event that the event has arrived and data is in
- *              i1480->evt_buf (and size/result in i1480->evt_result).
- * @hw_rev
- *              Use this value to activate dfu code to support new revisions
- *              of hardware.  i1480_init() sets this to a default value.
- *              It should be updated by the USB and PCI code.
- */
-struct i1480 {
-       struct device *dev;
-
-       int (*write)(struct i1480 *, u32 addr, const void *, size_t);
-       int (*read)(struct i1480 *, u32 addr, size_t);
-       int (*rc_setup)(struct i1480 *);
-       void (*rc_release)(struct i1480 *);
-       int (*wait_init_done)(struct i1480 *);
-       int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size);
-       const char *pre_fw_name;
-       const char *mac_fw_name;
-       const char *mac_fw_name_deprecate;      /* FIXME: Will go away */
-       const char *phy_fw_name;
-       u8 hw_rev;
-
-       size_t buf_size;        /* size of both evt_buf and cmd_buf */
-       void *evt_buf, *cmd_buf;
-       ssize_t evt_result;
-       struct completion evt_complete;
-};
-
-static inline
-void i1480_init(struct i1480 *i1480)
-{
-       i1480->hw_rev = 1;
-       init_completion(&i1480->evt_complete);
-}
-
-extern int i1480_fw_upload(struct i1480 *);
-extern int i1480_pre_fw_upload(struct i1480 *);
-extern int i1480_mac_fw_upload(struct i1480 *);
-extern int i1480_phy_fw_upload(struct i1480 *);
-extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t);
-extern int i1480_rceb_check(const struct i1480 *,
-                           const struct uwb_rceb *, const char *, u8,
-                           u8, unsigned);
-
-enum {
-       /* Vendor specific command type */
-       i1480_CET_VS1 =                 0xfd,
-       /* i1480 commands */
-       i1480_CMD_SET_IP_MAS =          0x000e,
-       i1480_CMD_GET_MAC_PHY_INFO =    0x0003,
-       i1480_CMD_MPI_WRITE =           0x000f,
-       i1480_CMD_MPI_READ =            0x0010,
-       /* i1480 events */
-#if i1480_FW > 0x00000302
-       i1480_EVT_CONFIRM =             0x0002,
-       i1480_EVT_RM_INIT_DONE =        0x0101,
-       i1480_EVT_DEV_ADD =             0x0103,
-       i1480_EVT_DEV_RM =              0x0104,
-       i1480_EVT_DEV_ID_CHANGE =       0x0105,
-       i1480_EVT_GET_MAC_PHY_INFO =    i1480_CMD_GET_MAC_PHY_INFO,
-#else
-       i1480_EVT_CONFIRM =             0x0002,
-       i1480_EVT_RM_INIT_DONE =        0x0101,
-       i1480_EVT_DEV_ADD =             0x0103,
-       i1480_EVT_DEV_RM =              0x0104,
-       i1480_EVT_DEV_ID_CHANGE =       0x0105,
-       i1480_EVT_GET_MAC_PHY_INFO =    i1480_EVT_CONFIRM,
-#endif
-};
-
-
-struct i1480_evt_confirm {
-       struct uwb_rceb rceb;
-#ifdef i1480_RCEB_EXTENDED
-       __le16 wParamLength;
-#endif
-       u8 bResultCode;
-} __attribute__((packed));
-
-
-struct i1480_rceb {
-       struct uwb_rceb rceb;
-#ifdef i1480_RCEB_EXTENDED
-       __le16 wParamLength;
-#endif
-} __attribute__((packed));
-
-
-/**
- * Get MAC & PHY Information confirm event structure
- *
- * Confirm event returned by the command.
- */
-struct i1480_evt_confirm_GMPI {
-#if i1480_FW > 0x00000302
-       struct uwb_rceb rceb;
-       __le16 wParamLength;
-       __le16 status;
-       u8 mac_addr[6];         /* EUI-64 bit IEEE address [still 8 bytes?] */
-       u8 dev_addr[2];
-       __le16 mac_fw_rev;      /* major = v >> 8; minor = v & 0xff */
-       u8 hw_rev;
-       u8 phy_vendor;
-       u8 phy_rev;             /* major v = >> 8; minor = v & 0xff */
-       __le16 mac_caps;
-       u8 phy_caps[3];
-       u8 key_stores;
-       __le16 mcast_addr_stores;
-       u8 sec_mode_supported;
-#else
-       struct uwb_rceb rceb;
-       u8 status;
-       u8 mac_addr[8];         /* EUI-64 bit IEEE address [still 8 bytes?] */
-       u8 dev_addr[2];
-       __le16 mac_fw_rev;      /* major = v >> 8; minor = v & 0xff */
-       __le16 phy_fw_rev;      /* major v = >> 8; minor = v & 0xff */
-       __le16 mac_caps;
-       u8 phy_caps;
-       u8 key_stores;
-       __le16 mcast_addr_stores;
-       u8 sec_mode_supported;
-#endif
-} __attribute__((packed));
-
-
-struct i1480_cmd_mpi_write {
-       struct uwb_rccb rccb;
-       __le16 size;
-       u8 data[];
-};
-
-
-struct i1480_cmd_mpi_read {
-       struct uwb_rccb rccb;
-       __le16 size;
-       struct {
-               u8 page, offset;
-       } __attribute__((packed)) data[];
-} __attribute__((packed));
-
-
-struct i1480_evt_mpi_read {
-       struct uwb_rceb rceb;
-#ifdef i1480_RCEB_EXTENDED
-       __le16 wParamLength;
-#endif
-       u8 bResultCode;
-       __le16 size;
-       struct {
-               u8 page, offset, value;
-       } __attribute__((packed)) data[];
-} __attribute__((packed));
-
-
-#endif /* #ifndef __i1480_DFU_H__ */
diff --git a/drivers/staging/uwb/i1480/dfu/mac.c b/drivers/staging/uwb/i1480/dfu/mac.c
deleted file mode 100644 (file)
index 6e4d6c9..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Wireless UWB Link 1480
- * MAC Firmware upload implementation
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Implementation of the code for parsing the firmware file (extract
- * the headers and binary code chunks) in the fw_*() functions. The
- * code to upload pre and mac firmwares is the same, so it uses a
- * common entry point in __mac_fw_upload(), which uses the i1480
- * function pointers to push the firmware to the device.
- */
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include "../../uwb.h"
-#include "i1480-dfu.h"
-
-/*
- * Descriptor for a continuous segment of MAC fw data
- */
-struct fw_hdr {
-       unsigned long address;
-       size_t length;
-       const u32 *bin;
-       struct fw_hdr *next;
-};
-
-
-/* Free a chain of firmware headers */
-static
-void fw_hdrs_free(struct fw_hdr *hdr)
-{
-       struct fw_hdr *next;
-
-       while (hdr) {
-               next = hdr->next;
-               kfree(hdr);
-               hdr = next;
-       }
-}
-
-
-/* Fill a firmware header descriptor from a memory buffer */
-static
-int fw_hdr_load(struct i1480 *i1480, struct fw_hdr *hdr, unsigned hdr_cnt,
-               const char *_data, const u32 *data_itr, const u32 *data_top)
-{
-       size_t hdr_offset =  (const char *) data_itr - _data;
-       size_t remaining_size = (void *) data_top - (void *) data_itr;
-       if (data_itr + 2 > data_top) {
-               dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in header at "
-                      "offset %zu, limit %zu\n",
-                      hdr_cnt, hdr_offset,
-                      (const char *) data_itr + 2 - _data,
-                      (const char *) data_top - _data);
-               return -EINVAL;
-       }
-       hdr->next = NULL;
-       hdr->address = le32_to_cpu(*data_itr++);
-       hdr->length = le32_to_cpu(*data_itr++);
-       hdr->bin = data_itr;
-       if (hdr->length > remaining_size) {
-               dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in data; "
-                      "chunk too long (%zu bytes), only %zu left\n",
-                      hdr_cnt, hdr_offset, hdr->length, remaining_size);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-
-/**
- * Get a buffer where the firmware is supposed to be and create a
- * chain of headers linking them together.
- *
- * @phdr: where to place the pointer to the first header (headers link
- *        to the next via the @hdr->next ptr); need to free the whole
- *        chain when done.
- *
- * @_data: Pointer to the data buffer.
- *
- * @_data_size: Size of the data buffer (bytes); data size has to be a
- *              multiple of 4. Function will fail if not.
- *
- * Goes over the whole binary blob; reads the first chunk and creates
- * a fw hdr from it (which points to where the data is in @_data and
- * the length of the chunk); then goes on to the next chunk until
- * done. Each header is linked to the next.
- */
-static
-int fw_hdrs_load(struct i1480 *i1480, struct fw_hdr **phdr,
-                const char *_data, size_t data_size)
-{
-       int result;
-       unsigned hdr_cnt = 0;
-       u32 *data = (u32 *) _data, *data_itr, *data_top;
-       struct fw_hdr *hdr, **prev_hdr = phdr;
-
-       result = -EINVAL;
-       /* Check size is ok and pointer is aligned */
-       if (data_size % sizeof(u32) != 0)
-               goto error;
-       if ((unsigned long) _data % sizeof(u16) != 0)
-               goto error;
-       *phdr = NULL;
-       data_itr = data;
-       data_top = (u32 *) (_data + data_size);
-       while (data_itr < data_top) {
-               result = -ENOMEM;
-               hdr = kmalloc(sizeof(*hdr), GFP_KERNEL);
-               if (hdr == NULL) {
-                       dev_err(i1480->dev, "Cannot allocate fw header "
-                              "for chunk #%u\n", hdr_cnt);
-                       goto error_alloc;
-               }
-               result = fw_hdr_load(i1480, hdr, hdr_cnt,
-                                    _data, data_itr, data_top);
-               if (result < 0)
-                       goto error_load;
-               data_itr += 2 + hdr->length;
-               *prev_hdr = hdr;
-               prev_hdr = &hdr->next;
-               hdr_cnt++;
-       };
-       *prev_hdr = NULL;
-       return 0;
-
-error_load:
-       kfree(hdr);
-error_alloc:
-       fw_hdrs_free(*phdr);
-error:
-       return result;
-}
-
-
-/**
- * Compares a chunk of fw with one in the devices's memory
- *
- * @i1480:     Device instance
- * @hdr:     Pointer to the firmware chunk
- * @returns: 0 if equal, < 0 errno on error. If > 0, it is the offset
- *           where the difference was found (plus one).
- *
- * Kind of dirty and simplistic, but does the trick in both the PCI
- * and USB version. We do a quick[er] memcmp(), and if it fails, we do
- * a byte-by-byte to find the offset.
- */
-static
-ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr)
-{
-       ssize_t result = 0;
-       u32 src_itr = 0, cnt;
-       size_t size = hdr->length*sizeof(hdr->bin[0]);
-       size_t chunk_size;
-       u8 *bin = (u8 *) hdr->bin;
-
-       while (size > 0) {
-               chunk_size = size < i1480->buf_size ? size : i1480->buf_size;
-               result = i1480->read(i1480, hdr->address + src_itr, chunk_size);
-               if (result < 0) {
-                       dev_err(i1480->dev, "error reading for verification: "
-                               "%zd\n", result);
-                       goto error;
-               }
-               if (memcmp(i1480->cmd_buf, bin + src_itr, result)) {
-                       u8 *buf = i1480->cmd_buf;
-                       for (cnt = 0; cnt < result; cnt++)
-                               if (bin[src_itr + cnt] != buf[cnt]) {
-                                       dev_err(i1480->dev, "byte failed at "
-                                               "src_itr %u cnt %u [0x%02x "
-                                               "vs 0x%02x]\n", src_itr, cnt,
-                                               bin[src_itr + cnt], buf[cnt]);
-                                       result = src_itr + cnt + 1;
-                                       goto cmp_failed;
-                               }
-               }
-               src_itr += result;
-               size -= result;
-       }
-       result = 0;
-error:
-cmp_failed:
-       return result;
-}
-
-
-/**
- * Writes firmware headers to the device.
- *
- * @prd:     PRD instance
- * @hdr:     Processed firmware
- * @returns: 0 if ok, < 0 errno on error.
- */
-static
-int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr,
-                    const char *fw_name, const char *fw_tag)
-{
-       struct device *dev = i1480->dev;
-       ssize_t result = 0;
-       struct fw_hdr *hdr_itr;
-       int verif_retry_count;
-
-       /* Now, header by header, push them to the hw */
-       for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) {
-               verif_retry_count = 0;
-retry:
-               dev_dbg(dev, "fw chunk (%zu @ 0x%08lx)\n",
-                       hdr_itr->length * sizeof(hdr_itr->bin[0]),
-                       hdr_itr->address);
-               result = i1480->write(i1480, hdr_itr->address, hdr_itr->bin,
-                                   hdr_itr->length*sizeof(hdr_itr->bin[0]));
-               if (result < 0) {
-                       dev_err(dev, "%s fw '%s': write failed (%zuB @ 0x%lx):"
-                               " %zd\n", fw_tag, fw_name,
-                               hdr_itr->length * sizeof(hdr_itr->bin[0]),
-                               hdr_itr->address, result);
-                       break;
-               }
-               result = i1480_fw_cmp(i1480, hdr_itr);
-               if (result < 0) {
-                       dev_err(dev, "%s fw '%s': verification read "
-                               "failed (%zuB @ 0x%lx): %zd\n",
-                               fw_tag, fw_name,
-                               hdr_itr->length * sizeof(hdr_itr->bin[0]),
-                               hdr_itr->address, result);
-                       break;
-               }
-               if (result > 0) {       /* Offset where it failed + 1 */
-                       result--;
-                       dev_err(dev, "%s fw '%s': WARNING: verification "
-                               "failed at 0x%lx: retrying\n",
-                               fw_tag, fw_name, hdr_itr->address + result);
-                       if (++verif_retry_count < 3)
-                               goto retry;     /* write this block again! */
-                       dev_err(dev, "%s fw '%s': verification failed at 0x%lx: "
-                               "tried %d times\n", fw_tag, fw_name,
-                               hdr_itr->address + result, verif_retry_count);
-                       result = -EINVAL;
-                       break;
-               }
-       }
-       return result;
-}
-
-
-/** Puts the device in firmware upload mode.*/
-static
-int mac_fw_upload_enable(struct i1480 *i1480)
-{
-       int result;
-       u32 reg = 0x800000c0;
-       u32 *buffer = (u32 *)i1480->cmd_buf;
-
-       if (i1480->hw_rev > 1)
-               reg = 0x8000d0d4;
-       result = i1480->read(i1480, reg, sizeof(u32));
-       if (result < 0)
-               goto error_cmd;
-       *buffer &= ~i1480_FW_UPLOAD_MODE_MASK;
-       result = i1480->write(i1480, reg, buffer, sizeof(u32));
-       if (result < 0)
-               goto error_cmd;
-       return 0;
-error_cmd:
-       dev_err(i1480->dev, "can't enable fw upload mode: %d\n", result);
-       return result;
-}
-
-
-/** Gets the device out of firmware upload mode. */
-static
-int mac_fw_upload_disable(struct i1480 *i1480)
-{
-       int result;
-       u32 reg = 0x800000c0;
-       u32 *buffer = (u32 *)i1480->cmd_buf;
-
-       if (i1480->hw_rev > 1)
-               reg = 0x8000d0d4;
-       result = i1480->read(i1480, reg, sizeof(u32));
-       if (result < 0)
-               goto error_cmd;
-       *buffer |= i1480_FW_UPLOAD_MODE_MASK;
-       result = i1480->write(i1480, reg, buffer, sizeof(u32));
-       if (result < 0)
-               goto error_cmd;
-       return 0;
-error_cmd:
-       dev_err(i1480->dev, "can't disable fw upload mode: %d\n", result);
-       return result;
-}
-
-
-
-/**
- * Generic function for uploading a MAC firmware.
- *
- * @i1480:     Device instance
- * @fw_name: Name of firmware file to upload.
- * @fw_tag:  Name of the firmware type (for messages)
- *           [eg: MAC, PRE]
- * @do_wait: Wait for device to emit initialization done message (0
- *           for PRE fws, 1 for MAC fws).
- * @returns: 0 if ok, < 0 errno on error.
- */
-static
-int __mac_fw_upload(struct i1480 *i1480, const char *fw_name,
-                   const char *fw_tag)
-{
-       int result;
-       const struct firmware *fw;
-       struct fw_hdr *fw_hdrs;
-
-       result = request_firmware(&fw, fw_name, i1480->dev);
-       if (result < 0) /* Up to caller to complain on -ENOENT */
-               goto out;
-       result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size);
-       if (result < 0) {
-               dev_err(i1480->dev, "%s fw '%s': failed to parse firmware "
-                       "file: %d\n", fw_tag, fw_name, result);
-               goto out_release;
-       }
-       result = mac_fw_upload_enable(i1480);
-       if (result < 0)
-               goto out_hdrs_release;
-       result = mac_fw_hdrs_push(i1480, fw_hdrs, fw_name, fw_tag);
-       mac_fw_upload_disable(i1480);
-out_hdrs_release:
-       if (result >= 0)
-               dev_info(i1480->dev, "%s fw '%s': uploaded\n", fw_tag, fw_name);
-       else
-               dev_err(i1480->dev, "%s fw '%s': failed to upload (%d), "
-                       "power cycle device\n", fw_tag, fw_name, result);
-       fw_hdrs_free(fw_hdrs);
-out_release:
-       release_firmware(fw);
-out:
-       return result;
-}
-
-
-/**
- * Upload a pre-PHY firmware
- *
- */
-int i1480_pre_fw_upload(struct i1480 *i1480)
-{
-       int result;
-       result = __mac_fw_upload(i1480, i1480->pre_fw_name, "PRE");
-       if (result == 0)
-               msleep(400);
-       return result;
-}
-
-
-/**
- * Reset a the MAC and PHY
- *
- * @i1480:     Device's instance
- * @returns: 0 if ok, < 0 errno code on error
- *
- * We put the command on kmalloc'ed memory as some arches cannot do
- * USB from the stack. The reply event is copied from an stage buffer,
- * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
- *
- * We issue the reset to make sure the UWB controller reinits the PHY;
- * this way we can now if the PHY init went ok.
- */
-static
-int i1480_cmd_reset(struct i1480 *i1480)
-{
-       int result;
-       struct uwb_rccb *cmd = (void *) i1480->cmd_buf;
-       struct i1480_evt_reset {
-               struct uwb_rceb rceb;
-               u8 bResultCode;
-       } __attribute__((packed)) *reply = (void *) i1480->evt_buf;
-
-       result = -ENOMEM;
-       cmd->bCommandType = UWB_RC_CET_GENERAL;
-       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
-       reply->rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply->rceb.wEvent = UWB_RC_CMD_RESET;
-       result = i1480_cmd(i1480, "RESET", sizeof(*cmd), sizeof(*reply));
-       if (result < 0)
-               goto out;
-       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(i1480->dev, "RESET: command execution failed: %u\n",
-                       reply->bResultCode);
-               result = -EIO;
-       }
-out:
-       return result;
-
-}
-
-
-/* Wait for the MAC FW to start running */
-static
-int i1480_fw_is_running_q(struct i1480 *i1480)
-{
-       int cnt = 0;
-       int result;
-       u32 *val = (u32 *) i1480->cmd_buf;
-
-       for (cnt = 0; cnt < 10; cnt++) {
-               msleep(100);
-               result = i1480->read(i1480, 0x80080000, 4);
-               if (result < 0) {
-                       dev_err(i1480->dev, "Can't read 0x8008000: %d\n", result);
-                       goto out;
-               }
-               if (*val == 0x55555555UL)       /* fw running? cool */
-                       goto out;
-       }
-       dev_err(i1480->dev, "Timed out waiting for fw to start\n");
-       result = -ETIMEDOUT;
-out:
-       return result;
-
-}
-
-
-/**
- * Upload MAC firmware, wait for it to start
- *
- * @i1480:     Device instance
- * @fw_name: Name of the file that contains the firmware
- *
- * This has to be called after the pre fw has been uploaded (if
- * there is any).
- */
-int i1480_mac_fw_upload(struct i1480 *i1480)
-{
-       int result = 0, deprecated_name = 0;
-       struct i1480_rceb *rcebe = (void *) i1480->evt_buf;
-
-       result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC");
-       if (result == -ENOENT) {
-               result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate,
-                                        "MAC");
-               deprecated_name = 1;
-       }
-       if (result < 0)
-               return result;
-       if (deprecated_name == 1)
-               dev_warn(i1480->dev,
-                        "WARNING: firmware file name %s is deprecated, "
-                        "please rename to %s\n",
-                        i1480->mac_fw_name_deprecate, i1480->mac_fw_name);
-       result = i1480_fw_is_running_q(i1480);
-       if (result < 0)
-               goto error_fw_not_running;
-       result = i1480->rc_setup ? i1480->rc_setup(i1480) : 0;
-       if (result < 0) {
-               dev_err(i1480->dev, "Cannot setup after MAC fw upload: %d\n",
-                       result);
-               goto error_setup;
-       }
-       result = i1480->wait_init_done(i1480);  /* wait init'on */
-       if (result < 0) {
-               dev_err(i1480->dev, "MAC fw '%s': Initialization timed out "
-                       "(%d)\n", i1480->mac_fw_name, result);
-               goto error_init_timeout;
-       }
-       /* verify we got the right initialization done event */
-       if (i1480->evt_result != sizeof(*rcebe)) {
-               dev_err(i1480->dev, "MAC fw '%s': initialization event returns "
-                       "wrong size (%zu bytes vs %zu needed)\n",
-                       i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe));
-               goto error_size;
-       }
-       result = -EIO;
-       if (i1480_rceb_check(i1480, &rcebe->rceb, NULL, 0, i1480_CET_VS1,
-                            i1480_EVT_RM_INIT_DONE) < 0) {
-               dev_err(i1480->dev, "wrong initialization event 0x%02x/%04x/%02x "
-                       "received; expected 0x%02x/%04x/00\n",
-                       rcebe->rceb.bEventType, le16_to_cpu(rcebe->rceb.wEvent),
-                       rcebe->rceb.bEventContext, i1480_CET_VS1,
-                       i1480_EVT_RM_INIT_DONE);
-               goto error_init_timeout;
-       }
-       result = i1480_cmd_reset(i1480);
-       if (result < 0)
-               dev_err(i1480->dev, "MAC fw '%s': MBOA reset failed (%d)\n",
-                       i1480->mac_fw_name, result);
-error_fw_not_running:
-error_init_timeout:
-error_size:
-error_setup:
-       return result;
-}
diff --git a/drivers/staging/uwb/i1480/dfu/phy.c b/drivers/staging/uwb/i1480/dfu/phy.c
deleted file mode 100644 (file)
index 13512c7..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Wireless UWB Link 1480
- * PHY parameters upload
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Code for uploading the PHY parameters to the PHY through the UWB
- * Radio Control interface.
- *
- * We just send the data through the MPI interface using HWA-like
- * commands and then reset the PHY to make sure it is ok.
- */
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include "../../../wusbcore/include/wusb.h"
-#include "i1480-dfu.h"
-
-
-/**
- * Write a value array to an address of the MPI interface
- *
- * @i1480:     Device descriptor
- * @data:      Data array to write
- * @size:      Size of the data array
- * @returns:   0 if ok, < 0 errno code on error.
- *
- * The data array is organized into pairs:
- *
- * ADDRESS VALUE
- *
- * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has
- * to be a multiple of three.
- */
-static
-int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size)
-{
-       int result;
-       struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf;
-       struct i1480_evt_confirm *reply = i1480->evt_buf;
-
-       BUG_ON(size > 480);
-       result = -ENOMEM;
-       cmd->rccb.bCommandType = i1480_CET_VS1;
-       cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE);
-       cmd->size = cpu_to_le16(size);
-       memcpy(cmd->data, data, size);
-       reply->rceb.bEventType = i1480_CET_VS1;
-       reply->rceb.wEvent = i1480_CMD_MPI_WRITE;
-       result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply));
-       if (result < 0)
-               goto out;
-       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n",
-                       reply->bResultCode);
-               result = -EIO;
-       }
-out:
-       return result;
-}
-
-
-/**
- * Read a value array to from an address of the MPI interface
- *
- * @i1480:     Device descriptor
- * @data:      where to place the read array
- * @srcaddr:   Where to read from
- * @size:      Size of the data read array
- * @returns:   0 if ok, < 0 errno code on error.
- *
- * The command data array is organized into pairs ADDR0 ADDR1..., and
- * the returned data in ADDR0 VALUE0 ADDR1 VALUE1...
- *
- * We generate the command array to be a sequential read and then
- * rearrange the result.
- *
- * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply.
- *
- * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount
- * of values we can read is (512 - sizeof(*reply)) / 3
- */
-static
-int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size)
-{
-       int result;
-       struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf;
-       struct i1480_evt_mpi_read *reply = i1480->evt_buf;
-       unsigned cnt;
-
-       memset(i1480->cmd_buf, 0x69, 512);
-       memset(i1480->evt_buf, 0x69, 512);
-
-       BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3);
-       result = -ENOMEM;
-       cmd->rccb.bCommandType = i1480_CET_VS1;
-       cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ);
-       cmd->size = cpu_to_le16(3*size);
-       for (cnt = 0; cnt < size; cnt++) {
-               cmd->data[cnt].page = (srcaddr + cnt) >> 8;
-               cmd->data[cnt].offset = (srcaddr + cnt) & 0xff;
-       }
-       reply->rceb.bEventType = i1480_CET_VS1;
-       reply->rceb.wEvent = i1480_CMD_MPI_READ;
-       result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size,
-                       sizeof(*reply) + 3*size);
-       if (result < 0)
-               goto out;
-       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n",
-                       reply->bResultCode);
-               result = -EIO;
-               goto out;
-       }
-       for (cnt = 0; cnt < size; cnt++) {
-               if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
-                       dev_err(i1480->dev, "MPI-READ: page inconsistency at "
-                               "index %u: expected 0x%02x, got 0x%02x\n", cnt,
-                               (srcaddr + cnt) >> 8, reply->data[cnt].page);
-               if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
-                       dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
-                               "index %u: expected 0x%02x, got 0x%02x\n", cnt,
-                               (srcaddr + cnt) & 0x00ff,
-                               reply->data[cnt].offset);
-               data[cnt] = reply->data[cnt].value;
-       }
-       result = 0;
-out:
-       return result;
-}
-
-
-/**
- * Upload a PHY firmware, wait for it to start
- *
- * @i1480:     Device instance
- * @fw_name: Name of the file that contains the firmware
- *
- * We assume the MAC fw is up and running. This means we can use the
- * MPI interface to write the PHY firmware. Once done, we issue an
- * MBOA Reset, which will force the MAC to reset and reinitialize the
- * PHY. If that works, we are ready to go.
- *
- * Max packet size for the MPI write is 512, so the max buffer is 480
- * (which gives us 160 byte triads of MSB, LSB and VAL for the data).
- */
-int i1480_phy_fw_upload(struct i1480 *i1480)
-{
-       int result;
-       const struct firmware *fw;
-       const char *data_itr, *data_top;
-       const size_t MAX_BLK_SIZE = 480;        /* 160 triads */
-       size_t data_size;
-       u8 phy_stat;
-
-       result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
-       if (result < 0)
-               goto out;
-       /* Loop writing data in chunks as big as possible until done. */
-       for (data_itr = fw->data, data_top = data_itr + fw->size;
-            data_itr < data_top; data_itr += MAX_BLK_SIZE) {
-               data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
-               result = i1480_mpi_write(i1480, data_itr, data_size);
-               if (result < 0)
-                       goto error_mpi_write;
-       }
-       /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */
-       result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
-       if (result < 0) {
-               dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
-               goto error_mpi_status;
-       }
-       if (phy_stat != 0) {
-               result = -ENODEV;
-               dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
-               goto error_phy_status;
-       }
-       dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
-error_phy_status:
-error_mpi_status:
-error_mpi_write:
-       release_firmware(fw);
-       if (result < 0)
-               dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
-                       "power cycle device\n", i1480->phy_fw_name, result);
-out:
-       return result;
-}
diff --git a/drivers/staging/uwb/i1480/dfu/usb.c b/drivers/staging/uwb/i1480/dfu/usb.c
deleted file mode 100644 (file)
index d41086b..0000000
+++ /dev/null
@@ -1,448 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Wireless UWB Link 1480
- * USB SKU firmware upload implementation
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This driver will prepare the i1480 device to behave as a real
- * Wireless USB HWA adaptor by uploading the firmware.
- *
- * When the device is connected or driver is loaded, i1480_usb_probe()
- * is called--this will allocate and initialize the device structure,
- * fill in the pointers to the common functions (read, write,
- * wait_init_done and cmd for HWA command execution) and once that is
- * done, call the common firmware uploading routine. Then clean up and
- * return -ENODEV, as we don't attach to the device.
- *
- * The rest are the basic ops we implement that the fw upload code
- * uses to do its job. All the ops in the common code are i1480->NAME,
- * the functions are i1480_usb_NAME().
- */
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "../../uwb.h"
-#include "../../../wusbcore/include/wusb.h"
-#include "../../../wusbcore/include/wusb-wa.h"
-#include "i1480-dfu.h"
-
-struct i1480_usb {
-       struct i1480 i1480;
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-       struct urb *neep_urb;   /* URB for reading from EP1 */
-};
-
-
-static
-void i1480_usb_init(struct i1480_usb *i1480_usb)
-{
-       i1480_init(&i1480_usb->i1480);
-}
-
-
-static
-int i1480_usb_create(struct i1480_usb *i1480_usb, struct usb_interface *iface)
-{
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-       int result = -ENOMEM;
-
-       i1480_usb->usb_dev = usb_get_dev(usb_dev);      /* bind the USB device */
-       i1480_usb->usb_iface = usb_get_intf(iface);
-       usb_set_intfdata(iface, i1480_usb);             /* Bind the driver to iface0 */
-       i1480_usb->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (i1480_usb->neep_urb == NULL)
-               goto error;
-       return 0;
-
-error:
-       usb_set_intfdata(iface, NULL);
-       usb_put_intf(iface);
-       usb_put_dev(usb_dev);
-       return result;
-}
-
-
-static
-void i1480_usb_destroy(struct i1480_usb *i1480_usb)
-{
-       usb_kill_urb(i1480_usb->neep_urb);
-       usb_free_urb(i1480_usb->neep_urb);
-       usb_set_intfdata(i1480_usb->usb_iface, NULL);
-       usb_put_intf(i1480_usb->usb_iface);
-       usb_put_dev(i1480_usb->usb_dev);
-}
-
-
-/**
- * Write a buffer to a memory address in the i1480 device
- *
- * @i1480:  i1480 instance
- * @memory_address:
- *          Address where to write the data buffer to.
- * @buffer: Buffer to the data
- * @size:   Size of the buffer [has to be < 512].
- * @returns: 0 if ok, < 0 errno code on error.
- *
- * Data buffers to USB cannot be on the stack or in vmalloc'ed areas,
- * so we copy it to the local i1480 buffer before proceeding. In any
- * case, we have a max size we can send.
- */
-static
-int i1480_usb_write(struct i1480 *i1480, u32 memory_address,
-                   const void *buffer, size_t size)
-{
-       int result = 0;
-       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
-       size_t buffer_size, itr = 0;
-
-       BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
-       while (size > 0) {
-               buffer_size = size < i1480->buf_size ? size : i1480->buf_size;
-               memcpy(i1480->cmd_buf, buffer + itr, buffer_size);
-               result = usb_control_msg(
-                       i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
-                       0xf0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       memory_address, (memory_address >> 16),
-                       i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */);
-               if (result < 0)
-                       break;
-               itr += result;
-               memory_address += result;
-               size -= result;
-       }
-       return result;
-}
-
-
-/**
- * Read a block [max size 512] of the device's memory to @i1480's buffer.
- *
- * @i1480: i1480 instance
- * @memory_address:
- *         Address where to read from.
- * @size:  Size to read. Smaller than or equal to 512.
- * @returns: >= 0 number of bytes written if ok, < 0 errno code on error.
- *
- * NOTE: if the memory address or block is incorrect, you might get a
- *       stall or a different memory read. Caller has to verify the
- *       memory address and size passed back in the @neh structure.
- */
-static
-int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size)
-{
-       ssize_t result = 0, bytes = 0;
-       size_t itr, read_size = i1480->buf_size;
-       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
-
-       BUG_ON(size > i1480->buf_size);
-       BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
-       BUG_ON(read_size > 512);
-
-       if (addr >= 0x8000d200 && addr < 0x8000d400)    /* Yeah, HW quirk */
-               read_size = 4;
-
-       for (itr = 0; itr < size; itr += read_size) {
-               size_t itr_addr = addr + itr;
-               size_t itr_size = min(read_size, size - itr);
-               result = usb_control_msg(
-                       i1480_usb->usb_dev, usb_rcvctrlpipe(i1480_usb->usb_dev, 0),
-                       0xf0, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       itr_addr, (itr_addr >> 16),
-                       i1480->cmd_buf + itr, itr_size,
-                       100 /* FIXME: arbitrary */);
-               if (result < 0) {
-                       dev_err(i1480->dev, "%s: USB read error: %zd\n",
-                               __func__, result);
-                       goto out;
-               }
-               if (result != itr_size) {
-                       result = -EIO;
-                       dev_err(i1480->dev,
-                               "%s: partial read got only %zu bytes vs %zu expected\n",
-                               __func__, result, itr_size);
-                       goto out;
-               }
-               bytes += result;
-       }
-       result = bytes;
-out:
-       return result;
-}
-
-
-/**
- * Callback for reads on the notification/event endpoint
- *
- * Just enables the completion read handler.
- */
-static
-void i1480_usb_neep_cb(struct urb *urb)
-{
-       struct i1480 *i1480 = urb->context;
-       struct device *dev = i1480->dev;
-
-       switch (urb->status) {
-       case 0:
-               break;
-       case -ECONNRESET:       /* Not an error, but a controlled situation; */
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-               dev_dbg(dev, "NEEP: reset/noent %d\n", urb->status);
-               break;
-       case -ESHUTDOWN:        /* going away! */
-               dev_dbg(dev, "NEEP: down %d\n", urb->status);
-               break;
-       default:
-               dev_err(dev, "NEEP: unknown status %d\n", urb->status);
-               break;
-       }
-       i1480->evt_result = urb->actual_length;
-       complete(&i1480->evt_complete);
-       return;
-}
-
-
-/**
- * Wait for the MAC FW to initialize
- *
- * MAC FW sends a 0xfd/0101/00 notification to EP1 when done
- * initializing. Get that notification into i1480->evt_buf; upper layer
- * will verify it.
- *
- * Set i1480->evt_result with the result of getting the event or its
- * size (if successful).
- *
- * Delivers the data directly to i1480->evt_buf
- */
-static
-int i1480_usb_wait_init_done(struct i1480 *i1480)
-{
-       int result;
-       struct device *dev = i1480->dev;
-       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
-       struct usb_endpoint_descriptor *epd;
-
-       init_completion(&i1480->evt_complete);
-       i1480->evt_result = -EINPROGRESS;
-       epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
-       usb_fill_int_urb(i1480_usb->neep_urb, i1480_usb->usb_dev,
-                        usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
-                        i1480->evt_buf, i1480->buf_size,
-                        i1480_usb_neep_cb, i1480, epd->bInterval);
-       result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "init done: cannot submit NEEP read: %d\n",
-                       result);
-               goto error_submit;
-       }
-       /* Wait for the USB callback to get the data */
-       result = wait_for_completion_interruptible_timeout(
-               &i1480->evt_complete, HZ);
-       if (result <= 0) {
-               result = result == 0 ? -ETIMEDOUT : result;
-               goto error_wait;
-       }
-       usb_kill_urb(i1480_usb->neep_urb);
-       return 0;
-
-error_wait:
-       usb_kill_urb(i1480_usb->neep_urb);
-error_submit:
-       i1480->evt_result = result;
-       return result;
-}
-
-
-/**
- * Generic function for issuing commands to the i1480
- *
- * @i1480:      i1480 instance
- * @cmd_name:   Name of the command (for error messages)
- * @cmd:        Pointer to command buffer
- * @cmd_size:   Size of the command buffer
- * @reply:      Buffer for the reply event
- * @reply_size: Expected size back (including RCEB); the reply buffer
- *              is assumed to be as big as this.
- * @returns:    >= 0 size of the returned event data if ok,
- *              < 0 errno code on error.
- *
- * Arms the NE handle, issues the command to the device and checks the
- * basics of the reply event.
- */
-static
-int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size)
-{
-       int result;
-       struct device *dev = i1480->dev;
-       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
-       struct usb_endpoint_descriptor *epd;
-       struct uwb_rccb *cmd = i1480->cmd_buf;
-       u8 iface_no;
-
-       /* Post a read on the notification & event endpoint */
-       iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
-       usb_fill_int_urb(
-               i1480_usb->neep_urb, i1480_usb->usb_dev,
-               usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
-               i1480->evt_buf, i1480->buf_size,
-               i1480_usb_neep_cb, i1480, epd->bInterval);
-       result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "%s: cannot submit NEEP read: %d\n",
-                       cmd_name, result);
-               goto error_submit_ep1;
-       }
-       /* Now post the command on EP0 */
-       result = usb_control_msg(
-               i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
-               WA_EXEC_RC_CMD,
-               USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
-               0, iface_no,
-               cmd, cmd_size,
-               100 /* FIXME: this is totally arbitrary */);
-       if (result < 0) {
-               dev_err(dev, "%s: control request failed: %d\n",
-                       cmd_name, result);
-               goto error_submit_ep0;
-       }
-       return result;
-
-error_submit_ep0:
-       usb_kill_urb(i1480_usb->neep_urb);
-error_submit_ep1:
-       return result;
-}
-
-
-/*
- * Probe a i1480 device for uploading firmware.
- *
- * We attach only to interface #0, which is the radio control interface.
- */
-static
-int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(iface);
-       struct i1480_usb *i1480_usb;
-       struct i1480 *i1480;
-       struct device *dev = &iface->dev;
-       int result;
-
-       result = -ENODEV;
-       if (iface->cur_altsetting->desc.bInterfaceNumber != 0) {
-               dev_dbg(dev, "not attaching to iface %d\n",
-                       iface->cur_altsetting->desc.bInterfaceNumber);
-               goto error;
-       }
-       if (iface->num_altsetting > 1 &&
-                       le16_to_cpu(udev->descriptor.idProduct) == 0xbabe) {
-               /* Need altsetting #1 [HW QUIRK] or EP1 won't work */
-               result = usb_set_interface(interface_to_usbdev(iface), 0, 1);
-               if (result < 0)
-                       dev_warn(dev,
-                                "can't set altsetting 1 on iface 0: %d\n",
-                                result);
-       }
-
-       if (iface->cur_altsetting->desc.bNumEndpoints < 1)
-               return -ENODEV;
-
-       result = -ENOMEM;
-       i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
-       if (i1480_usb == NULL) {
-               dev_err(dev, "Unable to allocate instance\n");
-               goto error;
-       }
-       i1480_usb_init(i1480_usb);
-
-       i1480 = &i1480_usb->i1480;
-       i1480->buf_size = 512;
-       i1480->cmd_buf = kmalloc_array(2, i1480->buf_size, GFP_KERNEL);
-       if (i1480->cmd_buf == NULL) {
-               dev_err(dev, "Cannot allocate transfer buffers\n");
-               result = -ENOMEM;
-               goto error_buf_alloc;
-       }
-       i1480->evt_buf = i1480->cmd_buf + i1480->buf_size;
-
-       result = i1480_usb_create(i1480_usb, iface);
-       if (result < 0) {
-               dev_err(dev, "Cannot create instance: %d\n", result);
-               goto error_create;
-       }
-
-       /* setup the fops and upload the firmware */
-       i1480->pre_fw_name = "i1480-pre-phy-0.0.bin";
-       i1480->mac_fw_name = "i1480-usb-0.0.bin";
-       i1480->mac_fw_name_deprecate = "ptc-0.0.bin";
-       i1480->phy_fw_name = "i1480-phy-0.0.bin";
-       i1480->dev = &iface->dev;
-       i1480->write = i1480_usb_write;
-       i1480->read = i1480_usb_read;
-       i1480->rc_setup = NULL;
-       i1480->wait_init_done = i1480_usb_wait_init_done;
-       i1480->cmd = i1480_usb_cmd;
-
-       result = i1480_fw_upload(&i1480_usb->i1480);    /* the real thing */
-       if (result >= 0) {
-               usb_reset_device(i1480_usb->usb_dev);
-               result = -ENODEV;       /* we don't want to bind to the iface */
-       }
-       i1480_usb_destroy(i1480_usb);
-error_create:
-       kfree(i1480->cmd_buf);
-error_buf_alloc:
-       kfree(i1480_usb);
-error:
-       return result;
-}
-
-MODULE_FIRMWARE("i1480-pre-phy-0.0.bin");
-MODULE_FIRMWARE("i1480-usb-0.0.bin");
-MODULE_FIRMWARE("i1480-phy-0.0.bin");
-
-#define i1480_USB_DEV(v, p)                            \
-{                                                      \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE       \
-                | USB_DEVICE_ID_MATCH_DEV_INFO         \
-                | USB_DEVICE_ID_MATCH_INT_INFO,        \
-       .idVendor = (v),                                \
-       .idProduct = (p),                               \
-       .bDeviceClass = 0xff,                           \
-       .bDeviceSubClass = 0xff,                        \
-       .bDeviceProtocol = 0xff,                        \
-       .bInterfaceClass = 0xff,                        \
-       .bInterfaceSubClass = 0xff,                     \
-       .bInterfaceProtocol = 0xff,                     \
-}
-
-
-/** USB device ID's that we handle */
-static const struct usb_device_id i1480_usb_id_table[] = {
-       i1480_USB_DEV(0x8086, 0xdf3b),
-       i1480_USB_DEV(0x15a9, 0x0005),
-       i1480_USB_DEV(0x07d1, 0x3802),
-       i1480_USB_DEV(0x050d, 0x305a),
-       i1480_USB_DEV(0x3495, 0x3007),
-       {},
-};
-MODULE_DEVICE_TABLE(usb, i1480_usb_id_table);
-
-
-static struct usb_driver i1480_dfu_driver = {
-       .name =         "i1480-dfu-usb",
-       .id_table =     i1480_usb_id_table,
-       .probe =        i1480_usb_probe,
-       .disconnect =   NULL,
-};
-
-module_usb_driver(i1480_dfu_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Intel Wireless UWB Link 1480 firmware uploader for USB");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/i1480/i1480-est.c b/drivers/staging/uwb/i1480/i1480-est.c
deleted file mode 100644 (file)
index 106e0a4..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Wireless UWB Link 1480
- * Event Size tables for Wired Adaptors
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include "../uwb.h"
-#include "dfu/i1480-dfu.h"
-
-
-/** Event size table for wEvents 0x00XX */
-static struct uwb_est_entry i1480_est_fd00[] = {
-       /* Anybody expecting this response has to use
-        * neh->extra_size to specify the real size that will
-        * come back. */
-       [i1480_EVT_CONFIRM] = { .size = sizeof(struct i1480_evt_confirm) },
-       [i1480_CMD_SET_IP_MAS] = { .size = sizeof(struct i1480_evt_confirm) },
-#ifdef i1480_RCEB_EXTENDED
-       [0x09] = {
-               .size = sizeof(struct i1480_rceb),
-               .offset = 1 + offsetof(struct i1480_rceb, wParamLength),
-       },
-#endif
-};
-
-/** Event size table for wEvents 0x01XX */
-static struct uwb_est_entry i1480_est_fd01[] = {
-       [0xff & i1480_EVT_RM_INIT_DONE] = { .size = sizeof(struct i1480_rceb) },
-       [0xff & i1480_EVT_DEV_ADD] = { .size = sizeof(struct i1480_rceb) + 9 },
-       [0xff & i1480_EVT_DEV_RM] = { .size = sizeof(struct i1480_rceb) + 9 },
-       [0xff & i1480_EVT_DEV_ID_CHANGE] = {
-               .size = sizeof(struct i1480_rceb) + 2 },
-};
-
-static int __init i1480_est_init(void)
-{
-       int result = uwb_est_register(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
-                                     i1480_est_fd00,
-                                     ARRAY_SIZE(i1480_est_fd00));
-       if (result < 0) {
-               printk(KERN_ERR "Can't register EST table fd00: %d\n", result);
-               return result;
-       }
-       result = uwb_est_register(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b,
-                                 i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01));
-       if (result < 0) {
-               printk(KERN_ERR "Can't register EST table fd01: %d\n", result);
-               return result;
-       }
-       return 0;
-}
-module_init(i1480_est_init);
-
-static void __exit i1480_est_exit(void)
-{
-       uwb_est_unregister(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b,
-                          i1480_est_fd00, ARRAY_SIZE(i1480_est_fd00));
-       uwb_est_unregister(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b,
-                          i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01));
-}
-module_exit(i1480_est_exit);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("i1480's Vendor Specific Event Size Tables");
-MODULE_LICENSE("GPL");
-
-/**
- * USB device ID's that we handle
- *
- * [so we are loaded when this kind device is connected]
- */
-static struct usb_device_id __used i1480_est_id_table[] = {
-       { USB_DEVICE(0x8086, 0xdf3b), },
-       { USB_DEVICE(0x8086, 0x0c3b), },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, i1480_est_id_table);
diff --git a/drivers/staging/uwb/ie-rcv.c b/drivers/staging/uwb/ie-rcv.c
deleted file mode 100644 (file)
index 51a4706..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * IE Received notification handling.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/bitmap.h>
-#include "uwb-internal.h"
-
-/*
- * Process an incoming IE Received notification.
- */
-int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc_evt_ie_rcv *iercv;
-
-       /* Is there enough data to decode it? */
-       if (evt->notif.size < sizeof(*iercv)) {
-               dev_err(dev, "IE Received notification: Not enough data to "
-                       "decode (%zu vs %zu bytes needed)\n",
-                       evt->notif.size, sizeof(*iercv));
-               goto error;
-       }
-       iercv = container_of(evt->notif.rceb, struct uwb_rc_evt_ie_rcv, rceb);
-
-       dev_dbg(dev, "IE received, element ID=%d\n", iercv->IEData[0]);
-
-       if (iercv->IEData[0] == UWB_RELINQUISH_REQUEST_IE) {
-               dev_warn(dev, "unhandled Relinquish Request IE\n");
-       }
-
-       return 0;
-error:
-       return result;
-}
diff --git a/drivers/staging/uwb/ie.c b/drivers/staging/uwb/ie.c
deleted file mode 100644 (file)
index b11678d..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Information Element Handling
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * FIXME: docs
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-#include "uwb-internal.h"
-
-/**
- * uwb_ie_next - get the next IE in a buffer
- * @ptr: start of the buffer containing the IE data
- * @len: length of the buffer
- *
- * Both @ptr and @len are updated so subsequent calls to uwb_ie_next()
- * will get the next IE.
- *
- * NULL is returned (and @ptr and @len will not be updated) if there
- * are no more IEs in the buffer or the buffer is too short.
- */
-struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len)
-{
-       struct uwb_ie_hdr *hdr;
-       size_t ie_len;
-
-       if (*len < sizeof(struct uwb_ie_hdr))
-               return NULL;
-
-       hdr = *ptr;
-       ie_len = sizeof(struct uwb_ie_hdr) + hdr->length;
-
-       if (*len < ie_len)
-               return NULL;
-
-       *ptr += ie_len;
-       *len -= ie_len;
-
-       return hdr;
-}
-EXPORT_SYMBOL_GPL(uwb_ie_next);
-
-/**
- * uwb_ie_dump_hex - print IEs to a character buffer
- * @ies: the IEs to print.
- * @len: length of all the IEs.
- * @buf: the destination buffer.
- * @size: size of @buf.
- *
- * Returns the number of characters written.
- */
-int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len,
-                   char *buf, size_t size)
-{
-       void *ptr;
-       const struct uwb_ie_hdr *ie;
-       int r = 0;
-       u8 *d;
-
-       ptr = (void *)ies;
-       for (;;) {
-               ie = uwb_ie_next(&ptr, &len);
-               if (!ie)
-                       break;
-
-               r += scnprintf(buf + r, size - r, "%02x %02x",
-                              (unsigned)ie->element_id,
-                              (unsigned)ie->length);
-               d = (uint8_t *)ie + sizeof(struct uwb_ie_hdr);
-               while (d != ptr && r < size)
-                       r += scnprintf(buf + r, size - r, " %02x", (unsigned)*d++);
-               if (r < size)
-                       buf[r++] = '\n';
-       };
-
-       return r;
-}
-
-/**
- * Get the IEs that a radio controller is sending in its beacon
- *
- * @uwb_rc:  UWB Radio Controller
- * @returns: Size read from the system
- *
- * We don't need to lock the uwb_rc's mutex because we don't modify
- * anything. Once done with the iedata buffer, call
- * uwb_rc_ie_release(iedata). Don't call kfree on it.
- */
-static
-ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie)
-{
-       ssize_t result;
-       struct device *dev = &uwb_rc->uwb_dev.dev;
-       struct uwb_rccb *cmd = NULL;
-       struct uwb_rceb *reply = NULL;
-       struct uwb_rc_evt_get_ie *get_ie;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-
-       cmd->bCommandType = UWB_RC_CET_GENERAL;
-       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_GET_IE);
-       result = uwb_rc_vcmd(uwb_rc, "GET_IE", cmd, sizeof(*cmd),
-                            UWB_RC_CET_GENERAL, UWB_RC_CMD_GET_IE,
-                            &reply);
-       kfree(cmd);
-       if (result < 0)
-               return result;
-
-       get_ie = container_of(reply, struct uwb_rc_evt_get_ie, rceb);
-       if (result < sizeof(*get_ie)) {
-               dev_err(dev, "not enough data returned for decoding GET IE "
-                       "(%zu bytes received vs %zu needed)\n",
-                       result, sizeof(*get_ie));
-               return -EINVAL;
-       } else if (result < sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)) {
-               dev_err(dev, "not enough data returned for decoding GET IE "
-                       "payload (%zu bytes received vs %zu needed)\n", result,
-                       sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength));
-               return -EINVAL;
-       }
-
-       *pget_ie = get_ie;
-       return result;
-}
-
-
-/**
- * Replace all IEs currently being transmitted by a device
- *
- * @cmd:    pointer to the SET-IE command with the IEs to set
- * @size:   size of @buf
- */
-int uwb_rc_set_ie(struct uwb_rc *rc, struct uwb_rc_cmd_set_ie *cmd)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_evt_set_ie reply;
-
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_SET_IE;
-       result = uwb_rc_cmd(rc, "SET-IE", &cmd->rccb,
-                           sizeof(*cmd) + le16_to_cpu(cmd->wIELength),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       else if (result != sizeof(reply)) {
-               dev_err(dev, "SET-IE: not enough data to decode reply "
-                       "(%d bytes received vs %zu needed)\n",
-                       result, sizeof(reply));
-               result = -EIO;
-       } else if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(dev, "SET-IE: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-       } else
-               result = 0;
-error_cmd:
-       return result;
-}
-
-/* Cleanup the whole IE management subsystem */
-void uwb_rc_ie_init(struct uwb_rc *uwb_rc)
-{
-       mutex_init(&uwb_rc->ies_mutex);
-}
-
-
-/**
- * uwb_rc_ie_setup - setup a radio controller's IE manager
- * @uwb_rc: the radio controller.
- *
- * The current set of IEs are obtained from the hardware with a GET-IE
- * command (since the radio controller is not yet beaconing this will
- * be just the hardware's MAC and PHY Capability IEs).
- *
- * Returns 0 on success; -ve on an error.
- */
-int uwb_rc_ie_setup(struct uwb_rc *uwb_rc)
-{
-       struct uwb_rc_evt_get_ie *ie_info = NULL;
-       int capacity;
-
-       capacity = uwb_rc_get_ie(uwb_rc, &ie_info);
-       if (capacity < 0)
-               return capacity;
-
-       mutex_lock(&uwb_rc->ies_mutex);
-
-       uwb_rc->ies = (struct uwb_rc_cmd_set_ie *)ie_info;
-       uwb_rc->ies->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       uwb_rc->ies->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_IE);
-       uwb_rc->ies_capacity = capacity;
-
-       mutex_unlock(&uwb_rc->ies_mutex);
-
-       return 0;
-}
-
-
-/* Cleanup the whole IE management subsystem */
-void uwb_rc_ie_release(struct uwb_rc *uwb_rc)
-{
-       kfree(uwb_rc->ies);
-       uwb_rc->ies = NULL;
-       uwb_rc->ies_capacity = 0;
-}
-
-
-static int uwb_rc_ie_add_one(struct uwb_rc *rc, const struct uwb_ie_hdr *new_ie)
-{
-       struct uwb_rc_cmd_set_ie *new_ies;
-       void *ptr, *prev_ie;
-       struct uwb_ie_hdr *ie;
-       size_t length, new_ie_len, new_capacity, size, prev_size;
-
-       length = le16_to_cpu(rc->ies->wIELength);
-       new_ie_len = sizeof(struct uwb_ie_hdr) + new_ie->length;
-       new_capacity = sizeof(struct uwb_rc_cmd_set_ie) + length + new_ie_len;
-
-       if (new_capacity > rc->ies_capacity) {
-               new_ies = krealloc(rc->ies, new_capacity, GFP_KERNEL);
-               if (!new_ies)
-                       return -ENOMEM;
-               rc->ies = new_ies;
-       }
-
-       ptr = rc->ies->IEData;
-       size = length;
-       for (;;) {
-               prev_ie = ptr;
-               prev_size = size;
-               ie = uwb_ie_next(&ptr, &size);
-               if (!ie || ie->element_id > new_ie->element_id)
-                       break;
-       }
-
-       memmove(prev_ie + new_ie_len, prev_ie, prev_size);
-       memcpy(prev_ie, new_ie, new_ie_len);
-       rc->ies->wIELength = cpu_to_le16(length + new_ie_len);
-
-       return 0;
-}
-
-/**
- * uwb_rc_ie_add - add new IEs to the radio controller's beacon
- * @uwb_rc: the radio controller.
- * @ies: the buffer containing the new IE or IEs to be added to
- *       the device's beacon.
- * @size: length of all the IEs.
- *
- * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
- * after the device sent the first beacon that includes the IEs specified
- * in the SET IE command. We thus cannot send this command if the device is
- * not beaconing. Instead, a SET IE command will be sent later right after
- * we start beaconing.
- *
- * Setting an IE on the device will overwrite all current IEs in device. So
- * we take the current IEs being transmitted by the device, insert the
- * new one, and call SET IE with all the IEs needed.
- *
- * Returns 0 on success; or -ENOMEM.
- */
-int uwb_rc_ie_add(struct uwb_rc *uwb_rc,
-                 const struct uwb_ie_hdr *ies, size_t size)
-{
-       int result = 0;
-       void *ptr;
-       const struct uwb_ie_hdr *ie;
-
-       mutex_lock(&uwb_rc->ies_mutex);
-
-       ptr = (void *)ies;
-       for (;;) {
-               ie = uwb_ie_next(&ptr, &size);
-               if (!ie)
-                       break;
-
-               result = uwb_rc_ie_add_one(uwb_rc, ie);
-               if (result < 0)
-                       break;
-       }
-       if (result >= 0) {
-               if (size == 0) {
-                       if (uwb_rc->beaconing != -1)
-                               result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
-               } else
-                       result = -EINVAL;
-       }
-
-       mutex_unlock(&uwb_rc->ies_mutex);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_ie_add);
-
-
-/*
- * Remove an IE from internal cache
- *
- * We are dealing with our internal IE cache so no need to verify that the
- * IEs are valid (it has been done already).
- *
- * Should be called with ies_mutex held
- *
- * We do not break out once an IE is found in the cache. It is currently
- * possible to have more than one IE with the same ID included in the
- * beacon. We don't reallocate, we just mark the size smaller.
- */
-static
-void uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove)
-{
-       struct uwb_ie_hdr *ie;
-       size_t len = le16_to_cpu(uwb_rc->ies->wIELength);
-       void *ptr;
-       size_t size;
-
-       ptr = uwb_rc->ies->IEData;
-       size = len;
-       for (;;) {
-               ie = uwb_ie_next(&ptr, &size);
-               if (!ie)
-                       break;
-               if (ie->element_id == to_remove) {
-                       len -= sizeof(struct uwb_ie_hdr) + ie->length;
-                       memmove(ie, ptr, size);
-                       ptr = ie;
-               }
-       }
-       uwb_rc->ies->wIELength = cpu_to_le16(len);
-}
-
-
-/**
- * uwb_rc_ie_rm - remove an IE from the radio controller's beacon
- * @uwb_rc: the radio controller.
- * @element_id: the element ID of the IE to remove.
- *
- * Only IEs previously added with uwb_rc_ie_add() may be removed.
- *
- * Returns 0 on success; or -ve the SET-IE command to the radio
- * controller failed.
- */
-int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id)
-{
-       int result = 0;
-
-       mutex_lock(&uwb_rc->ies_mutex);
-
-       uwb_rc_ie_cache_rm(uwb_rc, element_id);
-
-       if (uwb_rc->beaconing != -1)
-               result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
-
-       mutex_unlock(&uwb_rc->ies_mutex);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_ie_rm);
diff --git a/drivers/staging/uwb/include/debug-cmd.h b/drivers/staging/uwb/include/debug-cmd.h
deleted file mode 100644 (file)
index f97db6c..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Ultra Wide Band
- * Debug interface commands
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#ifndef __LINUX__UWB__DEBUG_CMD_H__
-#define __LINUX__UWB__DEBUG_CMD_H__
-
-#include <linux/types.h>
-
-/*
- * Debug interface commands
- *
- * UWB_DBG_CMD_RSV_ESTABLISH: Establish a new unicast reservation.
- *
- * UWB_DBG_CMD_RSV_TERMINATE: Terminate the Nth reservation.
- */
-
-enum uwb_dbg_cmd_type {
-       UWB_DBG_CMD_RSV_ESTABLISH = 1,
-       UWB_DBG_CMD_RSV_TERMINATE = 2,
-       UWB_DBG_CMD_IE_ADD = 3,
-       UWB_DBG_CMD_IE_RM = 4,
-       UWB_DBG_CMD_RADIO_START = 5,
-       UWB_DBG_CMD_RADIO_STOP = 6,
-};
-
-struct uwb_dbg_cmd_rsv_establish {
-       __u8  target[6];
-       __u8  type;
-       __u16 max_mas;
-       __u16 min_mas;
-       __u8  max_interval;
-};
-
-struct uwb_dbg_cmd_rsv_terminate {
-       int index;
-};
-
-struct uwb_dbg_cmd_ie {
-       __u8 data[128];
-       int len;
-};
-
-struct uwb_dbg_cmd {
-       __u32 type;
-       union {
-               struct uwb_dbg_cmd_rsv_establish rsv_establish;
-               struct uwb_dbg_cmd_rsv_terminate rsv_terminate;
-               struct uwb_dbg_cmd_ie ie_add;
-               struct uwb_dbg_cmd_ie ie_rm;
-       };
-};
-
-#endif /* #ifndef __LINUX__UWB__DEBUG_CMD_H__ */
diff --git a/drivers/staging/uwb/include/spec.h b/drivers/staging/uwb/include/spec.h
deleted file mode 100644 (file)
index 5f75caf..0000000
+++ /dev/null
@@ -1,767 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Ultra Wide Band
- * UWB Standard definitions
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * All these definitions are based on the ECMA-368 standard.
- *
- * Note all definitions are Little Endian in the wire, and we will
- * convert them to host order before operating on the bitfields (that
- * yes, we use extensively).
- */
-
-#ifndef __LINUX__UWB_SPEC_H__
-#define __LINUX__UWB_SPEC_H__
-
-#include <linux/types.h>
-#include <linux/bitmap.h>
-#include <linux/if_ether.h>
-
-#define i1480_FW 0x00000303
-/* #define i1480_FW 0x00000302 */
-
-/**
- * Number of Medium Access Slots in a superframe.
- *
- * UWB divides time in SuperFrames, each one divided in 256 pieces, or
- * Medium Access Slots. See MBOA MAC[5.4.5] for details. The MAS is the
- * basic bandwidth allocation unit in UWB.
- */
-enum { UWB_NUM_MAS = 256 };
-
-/**
- * Number of Zones in superframe.
- *
- * UWB divides the superframe into zones with numbering starting from BPST.
- * See MBOA MAC[16.8.6]
- */
-enum { UWB_NUM_ZONES = 16 };
-
-/*
- * Number of MAS in a zone.
- */
-#define UWB_MAS_PER_ZONE (UWB_NUM_MAS / UWB_NUM_ZONES)
-
-/*
- * Number of MAS required before a row can be considered available.
- */
-#define UWB_USABLE_MAS_PER_ROW (UWB_NUM_ZONES - 1)
-
-/*
- * Number of streams per DRP reservation between a pair of devices.
- *
- * [ECMA-368] section 16.8.6.
- */
-enum { UWB_NUM_STREAMS = 8 };
-
-/*
- * mMasLength
- *
- * The length of a MAS in microseconds.
- *
- * [ECMA-368] section 17.16.
- */
-enum { UWB_MAS_LENGTH_US = 256 };
-
-/*
- * mBeaconSlotLength
- *
- * The length of the beacon slot in microseconds.
- *
- * [ECMA-368] section 17.16
- */
-enum { UWB_BEACON_SLOT_LENGTH_US = 85 };
-
-/*
- * mMaxLostBeacons
- *
- * The number beacons missing in consecutive superframes before a
- * device can be considered as unreachable.
- *
- * [ECMA-368] section 17.16
- */
-enum { UWB_MAX_LOST_BEACONS = 3 };
-
-/*
- * mDRPBackOffWinMin
- *
- * The minimum number of superframes to wait before trying to reserve
- * extra MAS.
- *
- * [ECMA-368] section 17.16
- */
-enum { UWB_DRP_BACKOFF_WIN_MIN = 2 };
-
-/*
- * mDRPBackOffWinMax
- *
- * The maximum number of superframes to wait before trying to reserve
- * extra MAS.
- *
- * [ECMA-368] section 17.16
- */
-enum { UWB_DRP_BACKOFF_WIN_MAX = 16 };
-
-/*
- * Length of a superframe in microseconds.
- */
-#define UWB_SUPERFRAME_LENGTH_US (UWB_MAS_LENGTH_US * UWB_NUM_MAS)
-
-/**
- * UWB MAC address
- *
- * It is *imperative* that this struct is exactly 6 packed bytes (as
- * it is also used to define headers sent down and up the wire/radio).
- */
-struct uwb_mac_addr {
-       u8 data[ETH_ALEN];
-} __attribute__((packed));
-
-
-/**
- * UWB device address
- *
- * It is *imperative* that this struct is exactly 6 packed bytes (as
- * it is also used to define headers sent down and up the wire/radio).
- */
-struct uwb_dev_addr {
-       u8 data[2];
-} __attribute__((packed));
-
-
-/**
- * Types of UWB addresses
- *
- * Order matters (by size).
- */
-enum uwb_addr_type {
-       UWB_ADDR_DEV = 0,
-       UWB_ADDR_MAC = 1,
-};
-
-
-/** Size of a char buffer for printing a MAC/device address */
-enum { UWB_ADDR_STRSIZE = 32 };
-
-
-/** UWB WiMedia protocol IDs. */
-enum uwb_prid {
-       UWB_PRID_WLP_RESERVED   = 0x0000,
-       UWB_PRID_WLP            = 0x0001,
-       UWB_PRID_WUSB_BOT       = 0x0010,
-       UWB_PRID_WUSB           = 0x0010,
-       UWB_PRID_WUSB_TOP       = 0x001F,
-};
-
-
-/** PHY Rate (MBOA MAC[7.8.12, Table 61]) */
-enum uwb_phy_rate {
-       UWB_PHY_RATE_53 = 0,
-       UWB_PHY_RATE_80,
-       UWB_PHY_RATE_106,
-       UWB_PHY_RATE_160,
-       UWB_PHY_RATE_200,
-       UWB_PHY_RATE_320,
-       UWB_PHY_RATE_400,
-       UWB_PHY_RATE_480,
-       UWB_PHY_RATE_INVALID
-};
-
-
-/**
- * Different ways to scan (MBOA MAC[6.2.2, Table 8], WUSB[Table 8-78])
- */
-enum uwb_scan_type {
-       UWB_SCAN_ONLY = 0,
-       UWB_SCAN_OUTSIDE_BP,
-       UWB_SCAN_WHILE_INACTIVE,
-       UWB_SCAN_DISABLED,
-       UWB_SCAN_ONLY_STARTTIME,
-       UWB_SCAN_TOP
-};
-
-
-/** ACK Policy types (MBOA MAC[7.2.1.3]) */
-enum uwb_ack_pol {
-       UWB_ACK_NO = 0,
-       UWB_ACK_INM = 1,
-       UWB_ACK_B = 2,
-       UWB_ACK_B_REQ = 3,
-};
-
-
-/** DRP reservation types ([ECMA-368 table 106) */
-enum uwb_drp_type {
-       UWB_DRP_TYPE_ALIEN_BP = 0,
-       UWB_DRP_TYPE_HARD,
-       UWB_DRP_TYPE_SOFT,
-       UWB_DRP_TYPE_PRIVATE,
-       UWB_DRP_TYPE_PCA,
-};
-
-
-/** DRP Reason Codes ([ECMA-368] table 107) */
-enum uwb_drp_reason {
-       UWB_DRP_REASON_ACCEPTED = 0,
-       UWB_DRP_REASON_CONFLICT,
-       UWB_DRP_REASON_PENDING,
-       UWB_DRP_REASON_DENIED,
-       UWB_DRP_REASON_MODIFIED,
-};
-
-/** Relinquish Request Reason Codes ([ECMA-368] table 113) */
-enum uwb_relinquish_req_reason {
-       UWB_RELINQUISH_REQ_REASON_NON_SPECIFIC = 0,
-       UWB_RELINQUISH_REQ_REASON_OVER_ALLOCATION,
-};
-
-/**
- *  DRP Notification Reason Codes (WHCI 0.95 [3.1.4.9])
- */
-enum uwb_drp_notif_reason {
-       UWB_DRP_NOTIF_DRP_IE_RCVD = 0,
-       UWB_DRP_NOTIF_CONFLICT,
-       UWB_DRP_NOTIF_TERMINATE,
-};
-
-
-/** Allocation of MAS slots in a DRP request MBOA MAC[7.8.7] */
-struct uwb_drp_alloc {
-       __le16 zone_bm;
-       __le16 mas_bm;
-} __attribute__((packed));
-
-
-/** General MAC Header format (ECMA-368[16.2]) */
-struct uwb_mac_frame_hdr {
-       __le16 Frame_Control;
-       struct uwb_dev_addr DestAddr;
-       struct uwb_dev_addr SrcAddr;
-       __le16 Sequence_Control;
-       __le16 Access_Information;
-} __attribute__((packed));
-
-
-/**
- * uwb_beacon_frame - a beacon frame including MAC headers
- *
- * [ECMA] section 16.3.
- */
-struct uwb_beacon_frame {
-       struct uwb_mac_frame_hdr hdr;
-       struct uwb_mac_addr Device_Identifier;  /* may be a NULL EUI-48 */
-       u8 Beacon_Slot_Number;
-       u8 Device_Control;
-       u8 IEData[];
-} __attribute__((packed));
-
-
-/** Information Element codes (MBOA MAC[T54]) */
-enum uwb_ie {
-       UWB_PCA_AVAILABILITY = 2,
-       UWB_IE_DRP_AVAILABILITY = 8,
-       UWB_IE_DRP = 9,
-       UWB_BP_SWITCH_IE = 11,
-       UWB_MAC_CAPABILITIES_IE = 12,
-       UWB_PHY_CAPABILITIES_IE = 13,
-       UWB_APP_SPEC_PROBE_IE = 15,
-       UWB_IDENTIFICATION_IE = 19,
-       UWB_MASTER_KEY_ID_IE = 20,
-       UWB_RELINQUISH_REQUEST_IE = 21,
-       UWB_IE_WLP = 250, /* WiMedia Logical Link Control Protocol WLP 0.99 */
-       UWB_APP_SPEC_IE = 255,
-};
-
-
-/**
- * Header common to all Information Elements (IEs)
- */
-struct uwb_ie_hdr {
-       u8 element_id;  /* enum uwb_ie */
-       u8 length;
-} __attribute__((packed));
-
-
-/** Dynamic Reservation Protocol IE (MBOA MAC[7.8.6]) */
-struct uwb_ie_drp {
-       struct uwb_ie_hdr       hdr;
-       __le16                  drp_control;
-       struct uwb_dev_addr     dev_addr;
-       struct uwb_drp_alloc    allocs[];
-} __attribute__((packed));
-
-static inline int uwb_ie_drp_type(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 0) & 0x7;
-}
-
-static inline int uwb_ie_drp_stream_index(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 3) & 0x7;
-}
-
-static inline int uwb_ie_drp_reason_code(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 6) & 0x7;
-}
-
-static inline int uwb_ie_drp_status(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 9) & 0x1;
-}
-
-static inline int uwb_ie_drp_owner(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 10) & 0x1;
-}
-
-static inline int uwb_ie_drp_tiebreaker(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 11) & 0x1;
-}
-
-static inline int uwb_ie_drp_unsafe(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 12) & 0x1;
-}
-
-static inline void uwb_ie_drp_set_type(struct uwb_ie_drp *ie, enum uwb_drp_type type)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x7 << 0)) | (type << 0);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_stream_index(struct uwb_ie_drp *ie, int stream_index)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x7 << 3)) | (stream_index << 3);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_reason_code(struct uwb_ie_drp *ie,
-                                      enum uwb_drp_reason reason_code)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (ie->drp_control & ~(0x7 << 6)) | (reason_code << 6);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_status(struct uwb_ie_drp *ie, int status)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x1 << 9)) | (status << 9);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_owner(struct uwb_ie_drp *ie, int owner)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x1 << 10)) | (owner << 10);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_tiebreaker(struct uwb_ie_drp *ie, int tiebreaker)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x1 << 11)) | (tiebreaker << 11);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_unsafe(struct uwb_ie_drp *ie, int unsafe)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x1 << 12)) | (unsafe << 12);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-/** Dynamic Reservation Protocol IE (MBOA MAC[7.8.7]) */
-struct uwb_ie_drp_avail {
-       struct uwb_ie_hdr       hdr;
-       DECLARE_BITMAP(bmp, UWB_NUM_MAS);
-} __attribute__((packed));
-
-/* Relinqish Request IE ([ECMA-368] section 16.8.19). */
-struct uwb_relinquish_request_ie {
-        struct uwb_ie_hdr       hdr;
-        __le16                  relinquish_req_control;
-        struct uwb_dev_addr     dev_addr;
-        struct uwb_drp_alloc    allocs[];
-} __attribute__((packed));
-
-static inline int uwb_ie_relinquish_req_reason_code(struct uwb_relinquish_request_ie *ie)
-{
-       return (le16_to_cpu(ie->relinquish_req_control) >> 0) & 0xf;
-}
-
-static inline void uwb_ie_relinquish_req_set_reason_code(struct uwb_relinquish_request_ie *ie,
-                                                        int reason_code)
-{
-       u16 ctrl = le16_to_cpu(ie->relinquish_req_control);
-       ctrl = (ctrl & ~(0xf << 0)) | (reason_code << 0);
-       ie->relinquish_req_control = cpu_to_le16(ctrl);
-}
-
-/**
- * The Vendor ID is set to an OUI that indicates the vendor of the device.
- * ECMA-368 [16.8.10]
- */
-struct uwb_vendor_id {
-       u8 data[3];
-} __attribute__((packed));
-
-/**
- * The device type ID
- * FIXME: clarify what this means
- * ECMA-368 [16.8.10]
- */
-struct uwb_device_type_id {
-       u8 data[3];
-} __attribute__((packed));
-
-
-/**
- * UWB device information types
- * ECMA-368 [16.8.10]
- */
-enum uwb_dev_info_type {
-       UWB_DEV_INFO_VENDOR_ID = 0,
-       UWB_DEV_INFO_VENDOR_TYPE,
-       UWB_DEV_INFO_NAME,
-};
-
-/**
- * UWB device information found in Identification IE
- * ECMA-368 [16.8.10]
- */
-struct uwb_dev_info {
-       u8 type;        /* enum uwb_dev_info_type */
-       u8 length;
-       u8 data[];
-} __attribute__((packed));
-
-/**
- * UWB Identification IE
- * ECMA-368 [16.8.10]
- */
-struct uwb_identification_ie {
-       struct uwb_ie_hdr hdr;
-       struct uwb_dev_info info[];
-} __attribute__((packed));
-
-/*
- * UWB Radio Controller
- *
- * These definitions are common to the Radio Control layers as
- * exported by the WUSB1.0 HWA and WHCI interfaces.
- */
-
-/** Radio Control Command Block (WUSB1.0[Table 8-65] and WHCI 0.95) */
-struct uwb_rccb {
-       u8 bCommandType;                /* enum hwa_cet */
-       __le16 wCommand;                /* Command code */
-       u8 bCommandContext;             /* Context ID */
-} __attribute__((packed));
-
-
-/** Radio Control Event Block (WUSB[table 8-66], WHCI 0.95) */
-struct uwb_rceb {
-       u8 bEventType;                  /* enum hwa_cet */
-       __le16 wEvent;                  /* Event code */
-       u8 bEventContext;               /* Context ID */
-} __attribute__((packed));
-
-
-enum {
-       UWB_RC_CET_GENERAL = 0,         /* General Command/Event type */
-       UWB_RC_CET_EX_TYPE_1 = 1,       /* Extended Type 1 Command/Event type */
-};
-
-/* Commands to the radio controller */
-enum uwb_rc_cmd {
-       UWB_RC_CMD_CHANNEL_CHANGE = 16,
-       UWB_RC_CMD_DEV_ADDR_MGMT = 17,  /* Device Address Management */
-       UWB_RC_CMD_GET_IE = 18,         /* GET Information Elements */
-       UWB_RC_CMD_RESET = 19,
-       UWB_RC_CMD_SCAN = 20,           /* Scan management  */
-       UWB_RC_CMD_SET_BEACON_FILTER = 21,
-       UWB_RC_CMD_SET_DRP_IE = 22,     /* Dynamic Reservation Protocol IEs */
-       UWB_RC_CMD_SET_IE = 23,         /* Information Element management */
-       UWB_RC_CMD_SET_NOTIFICATION_FILTER = 24,
-       UWB_RC_CMD_SET_TX_POWER = 25,
-       UWB_RC_CMD_SLEEP = 26,
-       UWB_RC_CMD_START_BEACON = 27,
-       UWB_RC_CMD_STOP_BEACON = 28,
-       UWB_RC_CMD_BP_MERGE = 29,
-       UWB_RC_CMD_SEND_COMMAND_FRAME = 30,
-       UWB_RC_CMD_SET_ASIE_NOTIF = 31,
-};
-
-/* Notifications from the radio controller */
-enum uwb_rc_evt {
-       UWB_RC_EVT_IE_RCV = 0,
-       UWB_RC_EVT_BEACON = 1,
-       UWB_RC_EVT_BEACON_SIZE = 2,
-       UWB_RC_EVT_BPOIE_CHANGE = 3,
-       UWB_RC_EVT_BP_SLOT_CHANGE = 4,
-       UWB_RC_EVT_BP_SWITCH_IE_RCV = 5,
-       UWB_RC_EVT_DEV_ADDR_CONFLICT = 6,
-       UWB_RC_EVT_DRP_AVAIL = 7,
-       UWB_RC_EVT_DRP = 8,
-       UWB_RC_EVT_BP_SWITCH_STATUS = 9,
-       UWB_RC_EVT_CMD_FRAME_RCV = 10,
-       UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV = 11,
-       /* Events (command responses) use the same code as the command */
-       UWB_RC_EVT_UNKNOWN_CMD_RCV = 65535,
-};
-
-enum uwb_rc_extended_type_1_cmd {
-       UWB_RC_SET_DAA_ENERGY_MASK = 32,
-       UWB_RC_SET_NOTIFICATION_FILTER_EX = 33,
-};
-
-enum uwb_rc_extended_type_1_evt {
-       UWB_RC_DAA_ENERGY_DETECTED = 0,
-};
-
-/* Radio Control Result Code. [WHCI] table 3-3. */
-enum {
-       UWB_RC_RES_SUCCESS = 0,
-       UWB_RC_RES_FAIL,
-       UWB_RC_RES_FAIL_HARDWARE,
-       UWB_RC_RES_FAIL_NO_SLOTS,
-       UWB_RC_RES_FAIL_BEACON_TOO_LARGE,
-       UWB_RC_RES_FAIL_INVALID_PARAMETER,
-       UWB_RC_RES_FAIL_UNSUPPORTED_PWR_LEVEL,
-       UWB_RC_RES_FAIL_INVALID_IE_DATA,
-       UWB_RC_RES_FAIL_BEACON_SIZE_EXCEEDED,
-       UWB_RC_RES_FAIL_CANCELLED,
-       UWB_RC_RES_FAIL_INVALID_STATE,
-       UWB_RC_RES_FAIL_INVALID_SIZE,
-       UWB_RC_RES_FAIL_ACK_NOT_RECEIVED,
-       UWB_RC_RES_FAIL_NO_MORE_ASIE_NOTIF,
-       UWB_RC_RES_FAIL_TIME_OUT = 255,
-};
-
-/* Confirm event. [WHCI] section 3.1.3.1 etc. */
-struct uwb_rc_evt_confirm {
-       struct uwb_rceb rceb;
-       u8 bResultCode;
-} __attribute__((packed));
-
-/* Device Address Management event. [WHCI] section 3.1.3.2. */
-struct uwb_rc_evt_dev_addr_mgmt {
-       struct uwb_rceb rceb;
-       u8 baAddr[ETH_ALEN];
-       u8 bResultCode;
-} __attribute__((packed));
-
-
-/* Get IE Event. [WHCI] section 3.1.3.3. */
-struct uwb_rc_evt_get_ie {
-       struct uwb_rceb rceb;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* Set DRP IE Event. [WHCI] section 3.1.3.7. */
-struct uwb_rc_evt_set_drp_ie {
-       struct uwb_rceb rceb;
-       __le16 wRemainingSpace;
-       u8 bResultCode;
-} __attribute__((packed));
-
-/* Set IE Event. [WHCI] section 3.1.3.8. */
-struct uwb_rc_evt_set_ie {
-       struct uwb_rceb rceb;
-       __le16 RemainingSpace;
-       u8 bResultCode;
-} __attribute__((packed));
-
-/* Scan command. [WHCI] 3.1.3.5. */
-struct uwb_rc_cmd_scan {
-       struct uwb_rccb rccb;
-       u8 bChannelNumber;
-       u8 bScanState;
-       __le16 wStartTime;
-} __attribute__((packed));
-
-/* Set DRP IE command. [WHCI] section 3.1.3.7. */
-struct uwb_rc_cmd_set_drp_ie {
-       struct uwb_rccb rccb;
-       __le16 wIELength;
-       struct uwb_ie_drp IEData[];
-} __attribute__((packed));
-
-/* Set IE command. [WHCI] section 3.1.3.8. */
-struct uwb_rc_cmd_set_ie {
-       struct uwb_rccb rccb;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* Set DAA Energy Mask event. [WHCI 0.96] section 3.1.3.17. */
-struct uwb_rc_evt_set_daa_energy_mask {
-       struct uwb_rceb rceb;
-       __le16 wLength;
-       u8 result;
-} __attribute__((packed));
-
-/* Set Notification Filter Extended event. [WHCI 0.96] section 3.1.3.18. */
-struct uwb_rc_evt_set_notification_filter_ex {
-       struct uwb_rceb rceb;
-       __le16 wLength;
-       u8 result;
-} __attribute__((packed));
-
-/* IE Received notification. [WHCI] section 3.1.4.1. */
-struct uwb_rc_evt_ie_rcv {
-       struct uwb_rceb rceb;
-       struct uwb_dev_addr SrcAddr;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* Type of the received beacon. [WHCI] section 3.1.4.2. */
-enum uwb_rc_beacon_type {
-       UWB_RC_BEACON_TYPE_SCAN = 0,
-       UWB_RC_BEACON_TYPE_NEIGHBOR,
-       UWB_RC_BEACON_TYPE_OL_ALIEN,
-       UWB_RC_BEACON_TYPE_NOL_ALIEN,
-};
-
-/* Beacon received notification. [WHCI] 3.1.4.2. */
-struct uwb_rc_evt_beacon {
-       struct uwb_rceb rceb;
-       u8      bChannelNumber;
-       u8      bBeaconType;
-       __le16  wBPSTOffset;
-       u8      bLQI;
-       u8      bRSSI;
-       __le16  wBeaconInfoLength;
-       u8      BeaconInfo[];
-} __attribute__((packed));
-
-
-/* Beacon Size Change notification. [WHCI] section 3.1.4.3 */
-struct uwb_rc_evt_beacon_size {
-       struct uwb_rceb rceb;
-       __le16 wNewBeaconSize;
-} __attribute__((packed));
-
-
-/* BPOIE Change notification. [WHCI] section 3.1.4.4. */
-struct uwb_rc_evt_bpoie_change {
-       struct uwb_rceb rceb;
-       __le16 wBPOIELength;
-       u8 BPOIE[];
-} __attribute__((packed));
-
-
-/* Beacon Slot Change notification. [WHCI] section 3.1.4.5. */
-struct uwb_rc_evt_bp_slot_change {
-       struct uwb_rceb rceb;
-       u8 slot_info;
-} __attribute__((packed));
-
-static inline int uwb_rc_evt_bp_slot_change_slot_num(
-       const struct uwb_rc_evt_bp_slot_change *evt)
-{
-       return evt->slot_info & 0x7f;
-}
-
-static inline int uwb_rc_evt_bp_slot_change_no_slot(
-       const struct uwb_rc_evt_bp_slot_change *evt)
-{
-       return (evt->slot_info & 0x80) >> 7;
-}
-
-/* BP Switch IE Received notification. [WHCI] section 3.1.4.6. */
-struct uwb_rc_evt_bp_switch_ie_rcv {
-       struct uwb_rceb rceb;
-       struct uwb_dev_addr wSrcAddr;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* DevAddr Conflict notification. [WHCI] section 3.1.4.7. */
-struct uwb_rc_evt_dev_addr_conflict {
-       struct uwb_rceb rceb;
-} __attribute__((packed));
-
-/* DRP notification. [WHCI] section 3.1.4.9. */
-struct uwb_rc_evt_drp {
-       struct uwb_rceb           rceb;
-       struct uwb_dev_addr       src_addr;
-       u8                        reason;
-       u8                        beacon_slot_number;
-       __le16                    ie_length;
-       u8                        ie_data[];
-} __attribute__((packed));
-
-static inline enum uwb_drp_notif_reason uwb_rc_evt_drp_reason(struct uwb_rc_evt_drp *evt)
-{
-       return evt->reason & 0x0f;
-}
-
-
-/* DRP Availability Change notification. [WHCI] section 3.1.4.8. */
-struct uwb_rc_evt_drp_avail {
-       struct uwb_rceb rceb;
-       DECLARE_BITMAP(bmp, UWB_NUM_MAS);
-} __attribute__((packed));
-
-/* BP switch status notification. [WHCI] section 3.1.4.10. */
-struct uwb_rc_evt_bp_switch_status {
-       struct uwb_rceb rceb;
-       u8 status;
-       u8 slot_offset;
-       __le16 bpst_offset;
-       u8 move_countdown;
-} __attribute__((packed));
-
-/* Command Frame Received notification. [WHCI] section 3.1.4.11. */
-struct uwb_rc_evt_cmd_frame_rcv {
-       struct uwb_rceb rceb;
-       __le16 receive_time;
-       struct uwb_dev_addr wSrcAddr;
-       struct uwb_dev_addr wDstAddr;
-       __le16 control;
-       __le16 reserved;
-       __le16 dataLength;
-       u8 data[];
-} __attribute__((packed));
-
-/* Channel Change IE Received notification. [WHCI] section 3.1.4.12. */
-struct uwb_rc_evt_channel_change_ie_rcv {
-       struct uwb_rceb rceb;
-       struct uwb_dev_addr wSrcAddr;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* DAA Energy Detected notification. [WHCI 0.96] section 3.1.4.14. */
-struct uwb_rc_evt_daa_energy_detected {
-       struct uwb_rceb rceb;
-       __le16 wLength;
-       u8 bandID;
-       u8 reserved;
-       u8 toneBmp[16];
-} __attribute__((packed));
-
-
-/**
- * Radio Control Interface Class Descriptor
- *
- *  WUSB 1.0 [8.6.1.2]
- */
-struct uwb_rc_control_intf_class_desc {
-       u8 bLength;
-       u8 bDescriptorType;
-       __le16 bcdRCIVersion;
-} __attribute__((packed));
-
-#endif /* #ifndef __LINUX__UWB_SPEC_H__ */
diff --git a/drivers/staging/uwb/include/umc.h b/drivers/staging/uwb/include/umc.h
deleted file mode 100644 (file)
index ddbceb3..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * UWB Multi-interface Controller support.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- *
- * UMC (UWB Multi-interface Controller) capabilities (e.g., radio
- * controller, host controller) are presented as devices on the "umc"
- * bus.
- *
- * The radio controller is not strictly a UMC capability but it's
- * useful to present it as such.
- *
- * References:
- *
- *   [WHCI] Wireless Host Controller Interface Specification for
- *          Certified Wireless Universal Serial Bus, revision 0.95.
- *
- * How this works is kind of convoluted but simple. The whci.ko driver
- * loads when WHCI devices are detected. These WHCI devices expose
- * many devices in the same PCI function (they couldn't have reused
- * functions, no), so for each PCI function that exposes these many
- * devices, whci ceates a umc_dev [whci_probe() -> whci_add_cap()]
- * with umc_device_create() and adds it to the bus with
- * umc_device_register().
- *
- * umc_device_register() calls device_register() which will push the
- * bus management code to load your UMC driver's somehting_probe()
- * that you have registered for that capability code.
- *
- * Now when the WHCI device is removed, whci_remove() will go over
- * each umc_dev assigned to each of the PCI function's capabilities
- * and through whci_del_cap() call umc_device_unregister() each
- * created umc_dev. Of course, if you are bound to the device, your
- * driver's something_remove() will be called.
- */
-
-#ifndef _LINUX_UWB_UMC_H_
-#define _LINUX_UWB_UMC_H_
-
-#include <linux/device.h>
-#include <linux/pci.h>
-
-/*
- * UMC capability IDs.
- *
- * 0x00 is reserved so use it for the radio controller device.
- *
- * [WHCI] table 2-8
- */
-#define UMC_CAP_ID_WHCI_RC      0x00 /* radio controller */
-#define UMC_CAP_ID_WHCI_WUSB_HC 0x01 /* WUSB host controller */
-
-/**
- * struct umc_dev - UMC capability device
- *
- * @version:  version of the specification this capability conforms to.
- * @cap_id:   capability ID.
- * @bar:      PCI Bar (64 bit) where the resource lies
- * @resource: register space resource.
- * @irq:      interrupt line.
- */
-struct umc_dev {
-       u16             version;
-       u8              cap_id;
-       u8              bar;
-       struct resource resource;
-       unsigned        irq;
-       struct device   dev;
-};
-
-#define to_umc_dev(d) container_of(d, struct umc_dev, dev)
-
-/**
- * struct umc_driver - UMC capability driver
- * @cap_id: supported capability ID.
- * @match: driver specific capability matching function.
- * @match_data: driver specific data for match() (e.g., a
- * table of pci_device_id's if umc_match_pci_id() is used).
- */
-struct umc_driver {
-       char *name;
-       u8 cap_id;
-       int (*match)(struct umc_driver *, struct umc_dev *);
-       const void *match_data;
-
-       int  (*probe)(struct umc_dev *);
-       void (*remove)(struct umc_dev *);
-       int  (*pre_reset)(struct umc_dev *);
-       int  (*post_reset)(struct umc_dev *);
-
-       struct device_driver driver;
-};
-
-#define to_umc_driver(d) container_of(d, struct umc_driver, driver)
-
-extern struct bus_type umc_bus_type;
-
-struct umc_dev *umc_device_create(struct device *parent, int n);
-int __must_check umc_device_register(struct umc_dev *umc);
-void umc_device_unregister(struct umc_dev *umc);
-
-int __must_check __umc_driver_register(struct umc_driver *umc_drv,
-                                      struct module *mod,
-                                      const char *mod_name);
-
-/**
- * umc_driver_register - register a UMC capabiltity driver.
- * @umc_drv:  pointer to the driver.
- */
-#define umc_driver_register(umc_drv) \
-       __umc_driver_register(umc_drv, THIS_MODULE, KBUILD_MODNAME)
-
-void umc_driver_unregister(struct umc_driver *umc_drv);
-
-/*
- * Utility function you can use to match (umc_driver->match) against a
- * null-terminated array of 'struct pci_device_id' in
- * umc_driver->match_data.
- */
-int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc);
-
-/**
- * umc_parent_pci_dev - return the UMC's parent PCI device or NULL if none
- * @umc_dev: UMC device whose parent PCI device we are looking for
- *
- * DIRTY!!! DON'T RELY ON THIS
- *
- * FIXME: This is as dirty as it gets, but we need some way to check
- * the correct type of umc_dev->parent (so that for example, we can
- * cast to pci_dev). Casting to pci_dev is necessary because at some
- * point we need to request resources from the device. Mapping is
- * easily over come (ioremap and stuff are bus agnostic), but hooking
- * up to some error handlers (such as pci error handlers) might need
- * this.
- *
- * THIS might (probably will) be removed in the future, so don't count
- * on it.
- */
-static inline struct pci_dev *umc_parent_pci_dev(struct umc_dev *umc_dev)
-{
-       struct pci_dev *pci_dev = NULL;
-       if (dev_is_pci(umc_dev->dev.parent))
-               pci_dev = to_pci_dev(umc_dev->dev.parent);
-       return pci_dev;
-}
-
-/**
- * umc_dev_get() - reference a UMC device.
- * @umc_dev: Pointer to UMC device.
- *
- * NOTE: we are assuming in this whole scheme that the parent device
- *       is referenced at _probe() time and unreferenced at _remove()
- *       time by the parent's subsystem.
- */
-static inline struct umc_dev *umc_dev_get(struct umc_dev *umc_dev)
-{
-       get_device(&umc_dev->dev);
-       return umc_dev;
-}
-
-/**
- * umc_dev_put() - unreference a UMC device.
- * @umc_dev: Pointer to UMC device.
- */
-static inline void umc_dev_put(struct umc_dev *umc_dev)
-{
-       put_device(&umc_dev->dev);
-}
-
-/**
- * umc_set_drvdata - set UMC device's driver data.
- * @umc_dev: Pointer to UMC device.
- * @data:    Data to set.
- */
-static inline void umc_set_drvdata(struct umc_dev *umc_dev, void *data)
-{
-       dev_set_drvdata(&umc_dev->dev, data);
-}
-
-/**
- * umc_get_drvdata - recover UMC device's driver data.
- * @umc_dev: Pointer to UMC device.
- */
-static inline void *umc_get_drvdata(struct umc_dev *umc_dev)
-{
-       return dev_get_drvdata(&umc_dev->dev);
-}
-
-int umc_controller_reset(struct umc_dev *umc);
-
-#endif /* #ifndef _LINUX_UWB_UMC_H_ */
diff --git a/drivers/staging/uwb/include/whci.h b/drivers/staging/uwb/include/whci.h
deleted file mode 100644 (file)
index 1a5c2cc..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Wireless Host Controller Interface for Ultra-Wide-Band and Wireless USB
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * References:
- *   [WHCI] Wireless Host Controller Interface Specification for
- *          Certified Wireless Universal Serial Bus, revision 0.95.
- */
-#ifndef _LINUX_UWB_WHCI_H_
-#define _LINUX_UWB_WHCI_H_
-
-#include <linux/pci.h>
-
-/*
- * UWB interface capability registers (offsets from UWBBASE)
- *
- * [WHCI] section 2.2
- */
-#define UWBCAPINFO     0x00 /* == UWBCAPDATA(0) */
-#  define UWBCAPINFO_TO_N_CAPS(c)      (((c) >> 0)  & 0xFull)
-#define UWBCAPDATA(n)  (8*(n))
-#  define UWBCAPDATA_TO_VERSION(c)     (((c) >> 32) & 0xFFFFull)
-#  define UWBCAPDATA_TO_OFFSET(c)      (((c) >> 18) & 0x3FFFull)
-#  define UWBCAPDATA_TO_BAR(c)         (((c) >> 16) & 0x3ull)
-#  define UWBCAPDATA_TO_SIZE(c)                ((((c) >> 8) & 0xFFull) * sizeof(u32))
-#  define UWBCAPDATA_TO_CAP_ID(c)      (((c) >> 0)  & 0xFFull)
-
-/* Size of the WHCI capability data (including the RC capability) for
-   a device with n capabilities. */
-#define UWBCAPDATA_SIZE(n) (8 + 8*(n))
-
-
-/*
- * URC registers (offsets from URCBASE)
- *
- * [WHCI] section 2.3
- */
-#define URCCMD         0x00
-#  define URCCMD_RESET         (1 << 31)  /* UMC Hardware reset */
-#  define URCCMD_RS            (1 << 30)  /* Run/Stop */
-#  define URCCMD_EARV          (1 << 29)  /* Event Address Register Valid */
-#  define URCCMD_ACTIVE                (1 << 15)  /* Command is active */
-#  define URCCMD_IWR           (1 << 14)  /* Interrupt When Ready */
-#  define URCCMD_SIZE_MASK     0x00000fff /* Command size mask */
-#define URCSTS         0x04
-#  define URCSTS_EPS           (1 << 17)  /* Event Processing Status */
-#  define URCSTS_HALTED                (1 << 16)  /* RC halted */
-#  define URCSTS_HSE           (1 << 10)  /* Host System Error...fried */
-#  define URCSTS_ER            (1 <<  9)  /* Event Ready */
-#  define URCSTS_RCI           (1 <<  8)  /* Ready for Command Interrupt */
-#  define URCSTS_INT_MASK      0x00000700 /* URC interrupt sources */
-#  define URCSTS_ISI           0x000000ff /* Interrupt Source Identification */
-#define URCINTR                0x08
-#  define URCINTR_EN_ALL       0x000007ff /* Enable all interrupt sources */
-#define URCCMDADDR     0x10
-#define URCEVTADDR     0x18
-#  define URCEVTADDR_OFFSET_MASK 0xfff    /* Event pointer offset mask */
-
-
-/** Write 32 bit @value to little endian register at @addr */
-static inline
-void le_writel(u32 value, void __iomem *addr)
-{
-       iowrite32(value, addr);
-}
-
-
-/** Read from 32 bit little endian register at @addr */
-static inline
-u32 le_readl(void __iomem *addr)
-{
-       return ioread32(addr);
-}
-
-
-/** Write 64 bit @value to little endian register at @addr */
-static inline
-void le_writeq(u64 value, void __iomem *addr)
-{
-       iowrite32(value, addr);
-       iowrite32(value >> 32, addr + 4);
-}
-
-
-/** Read from 64 bit little endian register at @addr */
-static inline
-u64 le_readq(void __iomem *addr)
-{
-       u64 value;
-       value  = ioread32(addr);
-       value |= (u64)ioread32(addr + 4) << 32;
-       return value;
-}
-
-extern int whci_wait_for(struct device *dev, u32 __iomem *reg,
-                        u32 mask, u32 result,
-                        unsigned long max_ms,  const char *tag);
-
-#endif /* #ifndef _LINUX_UWB_WHCI_H_ */
diff --git a/drivers/staging/uwb/lc-dev.c b/drivers/staging/uwb/lc-dev.c
deleted file mode 100644 (file)
index 3e5c07f..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Life cycle of devices
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/export.h>
-#include <linux/err.h>
-#include <linux/kdev_t.h>
-#include <linux/random.h>
-#include <linux/stat.h>
-#include "uwb-internal.h"
-
-/* We initialize addresses to 0xff (invalid, as it is bcast) */
-static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr)
-{
-       memset(&addr->data, 0xff, sizeof(addr->data));
-}
-
-static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr)
-{
-       memset(&addr->data, 0xff, sizeof(addr->data));
-}
-
-/*
- * Add callback @new to be called when an event occurs in @rc.
- */
-int uwb_notifs_register(struct uwb_rc *rc, struct uwb_notifs_handler *new)
-{
-       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
-               return -ERESTARTSYS;
-       list_add(&new->list_node, &rc->notifs_chain.list);
-       mutex_unlock(&rc->notifs_chain.mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uwb_notifs_register);
-
-/*
- * Remove event handler (callback)
- */
-int uwb_notifs_deregister(struct uwb_rc *rc, struct uwb_notifs_handler *entry)
-{
-       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
-               return -ERESTARTSYS;
-       list_del(&entry->list_node);
-       mutex_unlock(&rc->notifs_chain.mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uwb_notifs_deregister);
-
-/*
- * Notify all event handlers of a given event on @rc
- *
- * We are called with a valid reference to the device, or NULL if the
- * event is not for a particular event (e.g., a BG join event).
- */
-void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event)
-{
-       struct uwb_notifs_handler *handler;
-       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
-               return;
-       if (!list_empty(&rc->notifs_chain.list)) {
-               list_for_each_entry(handler, &rc->notifs_chain.list, list_node) {
-                       handler->cb(handler->data, uwb_dev, event);
-               }
-       }
-       mutex_unlock(&rc->notifs_chain.mutex);
-}
-
-/*
- * Release the backing device of a uwb_dev that has been dynamically allocated.
- */
-static void uwb_dev_sys_release(struct device *dev)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-
-       uwb_bce_put(uwb_dev->bce);
-       memset(uwb_dev, 0x69, sizeof(*uwb_dev));
-       kfree(uwb_dev);
-}
-
-/*
- * Initialize a UWB device instance
- *
- * Alloc, zero and call this function.
- */
-void uwb_dev_init(struct uwb_dev *uwb_dev)
-{
-       mutex_init(&uwb_dev->mutex);
-       device_initialize(&uwb_dev->dev);
-       uwb_dev->dev.release = uwb_dev_sys_release;
-       uwb_dev_addr_init(&uwb_dev->dev_addr);
-       uwb_mac_addr_init(&uwb_dev->mac_addr);
-       bitmap_fill(uwb_dev->streams, UWB_NUM_GLOBAL_STREAMS);
-}
-
-static ssize_t uwb_dev_EUI_48_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       char addr[UWB_ADDR_STRSIZE];
-
-       uwb_mac_addr_print(addr, sizeof(addr), &uwb_dev->mac_addr);
-       return sprintf(buf, "%s\n", addr);
-}
-static DEVICE_ATTR(EUI_48, S_IRUGO, uwb_dev_EUI_48_show, NULL);
-
-static ssize_t uwb_dev_DevAddr_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       char addr[UWB_ADDR_STRSIZE];
-
-       uwb_dev_addr_print(addr, sizeof(addr), &uwb_dev->dev_addr);
-       return sprintf(buf, "%s\n", addr);
-}
-static DEVICE_ATTR(DevAddr, S_IRUGO, uwb_dev_DevAddr_show, NULL);
-
-/*
- * Show the BPST of this device.
- *
- * Calculated from the receive time of the device's beacon and it's
- * slot number.
- */
-static ssize_t uwb_dev_BPST_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_beca_e *bce;
-       struct uwb_beacon_frame *bf;
-       u16 bpst;
-
-       bce = uwb_dev->bce;
-       mutex_lock(&bce->mutex);
-       bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
-       bpst = bce->be->wBPSTOffset
-               - (u16)(bf->Beacon_Slot_Number * UWB_BEACON_SLOT_LENGTH_US);
-       mutex_unlock(&bce->mutex);
-
-       return sprintf(buf, "%d\n", bpst);
-}
-static DEVICE_ATTR(BPST, S_IRUGO, uwb_dev_BPST_show, NULL);
-
-/*
- * Show the IEs a device is beaconing
- *
- * We need to access the beacon cache, so we just lock it really
- * quick, print the IEs and unlock.
- *
- * We have a reference on the cache entry, so that should be
- * quite safe.
- */
-static ssize_t uwb_dev_IEs_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-
-       return uwb_bce_print_IEs(uwb_dev, uwb_dev->bce, buf, PAGE_SIZE);
-}
-static DEVICE_ATTR(IEs, S_IRUGO | S_IWUSR, uwb_dev_IEs_show, NULL);
-
-static ssize_t uwb_dev_LQE_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_beca_e *bce = uwb_dev->bce;
-       size_t result;
-
-       mutex_lock(&bce->mutex);
-       result = stats_show(&uwb_dev->bce->lqe_stats, buf);
-       mutex_unlock(&bce->mutex);
-       return result;
-}
-
-static ssize_t uwb_dev_LQE_store(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t size)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_beca_e *bce = uwb_dev->bce;
-       ssize_t result;
-
-       mutex_lock(&bce->mutex);
-       result = stats_store(&uwb_dev->bce->lqe_stats, buf, size);
-       mutex_unlock(&bce->mutex);
-       return result;
-}
-static DEVICE_ATTR(LQE, S_IRUGO | S_IWUSR, uwb_dev_LQE_show, uwb_dev_LQE_store);
-
-static ssize_t uwb_dev_RSSI_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_beca_e *bce = uwb_dev->bce;
-       size_t result;
-
-       mutex_lock(&bce->mutex);
-       result = stats_show(&uwb_dev->bce->rssi_stats, buf);
-       mutex_unlock(&bce->mutex);
-       return result;
-}
-
-static ssize_t uwb_dev_RSSI_store(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t size)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_beca_e *bce = uwb_dev->bce;
-       ssize_t result;
-
-       mutex_lock(&bce->mutex);
-       result = stats_store(&uwb_dev->bce->rssi_stats, buf, size);
-       mutex_unlock(&bce->mutex);
-       return result;
-}
-static DEVICE_ATTR(RSSI, S_IRUGO | S_IWUSR, uwb_dev_RSSI_show, uwb_dev_RSSI_store);
-
-
-static struct attribute *uwb_dev_attrs[] = {
-       &dev_attr_EUI_48.attr,
-       &dev_attr_DevAddr.attr,
-       &dev_attr_BPST.attr,
-       &dev_attr_IEs.attr,
-       &dev_attr_LQE.attr,
-       &dev_attr_RSSI.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(uwb_dev);
-
-/* UWB bus type. */
-struct bus_type uwb_bus_type = {
-       .name =         "uwb",
-       .dev_groups =   uwb_dev_groups,
-};
-
-/**
- * Device SYSFS registration
- */
-static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev)
-{
-       struct device *dev;
-
-       dev = &uwb_dev->dev;
-       dev->parent = parent_dev;
-       dev_set_drvdata(dev, uwb_dev);
-
-       return device_add(dev);
-}
-
-
-static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev)
-{
-       dev_set_drvdata(&uwb_dev->dev, NULL);
-       device_del(&uwb_dev->dev);
-}
-
-
-/**
- * Register and initialize a new UWB device
- *
- * Did you call uwb_dev_init() on it?
- *
- * @parent_rc: is the parent radio controller who has the link to the
- *             device. When registering the UWB device that is a UWB
- *             Radio Controller, we point back to it.
- *
- * If registering the device that is part of a radio, caller has set
- * rc->uwb_dev->dev. Otherwise it is to be left NULL--a new one will
- * be allocated.
- */
-int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
-               struct uwb_rc *parent_rc)
-{
-       int result;
-       struct device *dev;
-
-       BUG_ON(uwb_dev == NULL);
-       BUG_ON(parent_dev == NULL);
-       BUG_ON(parent_rc == NULL);
-
-       mutex_lock(&uwb_dev->mutex);
-       dev = &uwb_dev->dev;
-       uwb_dev->rc = parent_rc;
-       result = __uwb_dev_sys_add(uwb_dev, parent_dev);
-       if (result < 0)
-               printk(KERN_ERR "UWB: unable to register dev %s with sysfs: %d\n",
-                      dev_name(dev), result);
-       mutex_unlock(&uwb_dev->mutex);
-       return result;
-}
-
-
-void uwb_dev_rm(struct uwb_dev *uwb_dev)
-{
-       mutex_lock(&uwb_dev->mutex);
-       __uwb_dev_sys_rm(uwb_dev);
-       mutex_unlock(&uwb_dev->mutex);
-}
-
-
-static
-int __uwb_dev_try_get(struct device *dev, void *__target_uwb_dev)
-{
-       struct uwb_dev *target_uwb_dev = __target_uwb_dev;
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       if (uwb_dev == target_uwb_dev) {
-               uwb_dev_get(uwb_dev);
-               return 1;
-       } else
-               return 0;
-}
-
-
-/**
- * Given a UWB device descriptor, validate and refcount it
- *
- * @returns NULL if the device does not exist or is quiescing; the ptr to
- *               it otherwise.
- */
-struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev)
-{
-       if (uwb_dev_for_each(rc, __uwb_dev_try_get, uwb_dev))
-               return uwb_dev;
-       else
-               return NULL;
-}
-EXPORT_SYMBOL_GPL(uwb_dev_try_get);
-
-
-/**
- * Remove a device from the system [grunt for other functions]
- */
-int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc)
-{
-       struct device *dev = &uwb_dev->dev;
-       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
-
-       uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr);
-       uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr);
-       dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n",
-                macbuf, devbuf,
-                uwb_dev->dev.bus->name,
-                rc ? dev_name(&(rc->uwb_dev.dev)) : "");
-       uwb_dev_rm(uwb_dev);
-       list_del(&uwb_dev->bce->node);
-       uwb_bce_put(uwb_dev->bce);
-       uwb_dev_put(uwb_dev);   /* for the creation in _onair() */
-
-       return 0;
-}
-
-
-/**
- * A device went off the air, clean up after it!
- *
- * This is called by the UWB Daemon (through the beacon purge function
- * uwb_bcn_cache_purge) when it is detected that a device has been in
- * radio silence for a while.
- *
- * If this device is actually a local radio controller we don't need
- * to go through the offair process, as it is not registered as that.
- *
- * NOTE: uwb_bcn_cache.mutex is held!
- */
-void uwbd_dev_offair(struct uwb_beca_e *bce)
-{
-       struct uwb_dev *uwb_dev;
-
-       uwb_dev = bce->uwb_dev;
-       if (uwb_dev) {
-               uwb_notify(uwb_dev->rc, uwb_dev, UWB_NOTIF_OFFAIR);
-               __uwb_dev_offair(uwb_dev, uwb_dev->rc);
-       }
-}
-
-
-/**
- * A device went on the air, start it up!
- *
- * This is called by the UWB Daemon when it is detected that a device
- * has popped up in the radio range of the radio controller.
- *
- * It will just create the freaking device, register the beacon and
- * stuff and yatla, done.
- *
- *
- * NOTE: uwb_beca.mutex is held, bce->mutex is held
- */
-void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_dev *uwb_dev;
-       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
-
-       uwb_mac_addr_print(macbuf, sizeof(macbuf), bce->mac_addr);
-       uwb_dev_addr_print(devbuf, sizeof(devbuf), &bce->dev_addr);
-       uwb_dev = kzalloc(sizeof(struct uwb_dev), GFP_KERNEL);
-       if (uwb_dev == NULL) {
-               dev_err(dev, "new device %s: Cannot allocate memory\n",
-                       macbuf);
-               return;
-       }
-       uwb_dev_init(uwb_dev);          /* This sets refcnt to one, we own it */
-       uwb_dev->dev.bus = &uwb_bus_type;
-       uwb_dev->mac_addr = *bce->mac_addr;
-       uwb_dev->dev_addr = bce->dev_addr;
-       dev_set_name(&uwb_dev->dev, "%s", macbuf);
-
-       /* plug the beacon cache */
-       bce->uwb_dev = uwb_dev;
-       uwb_dev->bce = bce;
-       uwb_bce_get(bce);               /* released in uwb_dev_sys_release() */
-
-       result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc);
-       if (result < 0) {
-               dev_err(dev, "new device %s: cannot instantiate device\n",
-                       macbuf);
-               goto error_dev_add;
-       }
-
-       dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n",
-                macbuf, devbuf, uwb_dev->dev.bus->name,
-                dev_name(&(rc->uwb_dev.dev)));
-       uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR);
-       return;
-
-error_dev_add:
-       bce->uwb_dev = NULL;
-       uwb_bce_put(bce);
-       kfree(uwb_dev);
-       return;
-}
-
-/**
- * Iterate over the list of UWB devices, calling a @function on each
- *
- * See docs for bus_for_each()....
- *
- * @rc:       radio controller for the devices.
- * @function: function to call.
- * @priv:     data to pass to @function.
- * @returns:  0 if no invocation of function() returned a value
- *            different to zero. That value otherwise.
- */
-int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f function, void *priv)
-{
-       return device_for_each_child(&rc->uwb_dev.dev, priv, function);
-}
-EXPORT_SYMBOL_GPL(uwb_dev_for_each);
diff --git a/drivers/staging/uwb/lc-rc.c b/drivers/staging/uwb/lc-rc.c
deleted file mode 100644 (file)
index ee31b22..0000000
+++ /dev/null
@@ -1,569 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Life cycle of radio controllers
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- *
- * A UWB radio controller is also a UWB device, so it embeds one...
- *
- * List of RCs comes from the 'struct class uwb_rc_class'.
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/random.h>
-#include <linux/kdev_t.h>
-#include <linux/etherdevice.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-static int uwb_rc_index_match(struct device *dev, const void *data)
-{
-       const int *index = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc->index == *index)
-               return 1;
-       return 0;
-}
-
-static struct uwb_rc *uwb_rc_find_by_index(int index)
-{
-       struct device *dev;
-       struct uwb_rc *rc = NULL;
-
-       dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match);
-       if (dev) {
-               rc = dev_get_drvdata(dev);
-               put_device(dev);
-       }
-
-       return rc;
-}
-
-static int uwb_rc_new_index(void)
-{
-       int index = 0;
-
-       for (;;) {
-               if (!uwb_rc_find_by_index(index))
-                       return index;
-               if (++index < 0)
-                       index = 0;
-       }
-}
-
-/**
- * Release the backing device of a uwb_rc that has been dynamically allocated.
- */
-static void uwb_rc_sys_release(struct device *dev)
-{
-       struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev);
-       struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev);
-
-       uwb_rc_ie_release(rc);
-       kfree(rc);
-}
-
-
-void uwb_rc_init(struct uwb_rc *rc)
-{
-       struct uwb_dev *uwb_dev = &rc->uwb_dev;
-
-       uwb_dev_init(uwb_dev);
-       rc->uwb_dev.dev.class = &uwb_rc_class;
-       rc->uwb_dev.dev.release = uwb_rc_sys_release;
-       uwb_rc_neh_create(rc);
-       rc->beaconing = -1;
-       rc->scan_type = UWB_SCAN_DISABLED;
-       INIT_LIST_HEAD(&rc->notifs_chain.list);
-       mutex_init(&rc->notifs_chain.mutex);
-       INIT_LIST_HEAD(&rc->uwb_beca.list);
-       mutex_init(&rc->uwb_beca.mutex);
-       uwb_drp_avail_init(rc);
-       uwb_rc_ie_init(rc);
-       uwb_rsv_init(rc);
-       uwb_rc_pal_init(rc);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_init);
-
-
-struct uwb_rc *uwb_rc_alloc(void)
-{
-       struct uwb_rc *rc;
-       rc = kzalloc(sizeof(*rc), GFP_KERNEL);
-       if (rc == NULL)
-               return NULL;
-       uwb_rc_init(rc);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_alloc);
-
-/*
- * Show the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
- */
-static ssize_t ASIE_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_rc *rc = uwb_dev->rc;
-       struct uwb_ie_hdr *ie;
-       void *ptr;
-       size_t len;
-       int result = 0;
-
-       /* init empty buffer. */
-       result = scnprintf(buf, PAGE_SIZE, "\n");
-       mutex_lock(&rc->ies_mutex);
-       /* walk IEData looking for an ASIE. */
-       ptr = rc->ies->IEData;
-       len = le16_to_cpu(rc->ies->wIELength);
-       for (;;) {
-               ie = uwb_ie_next(&ptr, &len);
-               if (!ie)
-                       break;
-               if (ie->element_id == UWB_APP_SPEC_IE) {
-                       result = uwb_ie_dump_hex(ie,
-                                       ie->length + sizeof(struct uwb_ie_hdr),
-                                       buf, PAGE_SIZE);
-                       break;
-               }
-       }
-       mutex_unlock(&rc->ies_mutex);
-
-       return result;
-}
-
-/*
- * Update the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
- */
-static ssize_t ASIE_store(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t size)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_rc *rc = uwb_dev->rc;
-       char ie_buf[255];
-       int result, ie_len = 0;
-       const char *cur_ptr = buf;
-       struct uwb_ie_hdr *ie;
-
-       /* empty string means clear the ASIE. */
-       if (strlen(buf) <= 1) {
-               uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
-               return size;
-       }
-
-       /* if non-empty string, convert string of hex chars to binary. */
-       while (ie_len < sizeof(ie_buf)) {
-               int char_count;
-
-               if (sscanf(cur_ptr, " %02hhX %n",
-                               &(ie_buf[ie_len]), &char_count) > 0) {
-                       ++ie_len;
-                       /* skip chars read from cur_ptr. */
-                       cur_ptr += char_count;
-               } else {
-                       break;
-               }
-       }
-
-       /* validate IE length and type. */
-       if (ie_len < sizeof(struct uwb_ie_hdr)) {
-               dev_err(dev, "%s: Invalid ASIE size %d.\n", __func__, ie_len);
-               return -EINVAL;
-       }
-
-       ie = (struct uwb_ie_hdr *)ie_buf;
-       if (ie->element_id != UWB_APP_SPEC_IE) {
-               dev_err(dev, "%s: Invalid IE element type size = 0x%02X.\n",
-                               __func__, ie->element_id);
-               return -EINVAL;
-       }
-
-       /* bounds check length field from user. */
-       if (ie->length > (ie_len - sizeof(struct uwb_ie_hdr)))
-               ie->length = ie_len - sizeof(struct uwb_ie_hdr);
-
-       /*
-        * Valid ASIE received. Remove current ASIE then add the new one using
-        * uwb_rc_ie_add.
-        */
-       uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
-
-       result = uwb_rc_ie_add(rc, ie, ie->length + sizeof(struct uwb_ie_hdr));
-
-       return result >= 0 ? size : result;
-}
-static DEVICE_ATTR_RW(ASIE);
-
-static struct attribute *rc_attrs[] = {
-               &dev_attr_mac_address.attr,
-               &dev_attr_scan.attr,
-               &dev_attr_beacon.attr,
-               &dev_attr_ASIE.attr,
-               NULL,
-};
-
-static const struct attribute_group rc_attr_group = {
-       .attrs = rc_attrs,
-};
-
-/*
- * Registration of sysfs specific stuff
- */
-static int uwb_rc_sys_add(struct uwb_rc *rc)
-{
-       return sysfs_create_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
-}
-
-
-static void __uwb_rc_sys_rm(struct uwb_rc *rc)
-{
-       sysfs_remove_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
-}
-
-/**
- * uwb_rc_mac_addr_setup - get an RC's EUI-48 address or set it
- * @rc:  the radio controller.
- *
- * If the EUI-48 address is 00:00:00:00:00:00 or FF:FF:FF:FF:FF:FF
- * then a random locally administered EUI-48 is generated and set on
- * the device.  The probability of address collisions is sufficiently
- * unlikely (1/2^40 = 9.1e-13) that they're not checked for.
- */
-static
-int uwb_rc_mac_addr_setup(struct uwb_rc *rc)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_dev *uwb_dev = &rc->uwb_dev;
-       char devname[UWB_ADDR_STRSIZE];
-       struct uwb_mac_addr addr;
-
-       result = uwb_rc_mac_addr_get(rc, &addr);
-       if (result < 0) {
-               dev_err(dev, "cannot retrieve UWB EUI-48 address: %d\n", result);
-               return result;
-       }
-
-       if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) {
-               addr.data[0] = 0x02; /* locally administered and unicast */
-               get_random_bytes(&addr.data[1], sizeof(addr.data)-1);
-
-               result = uwb_rc_mac_addr_set(rc, &addr);
-               if (result < 0) {
-                       uwb_mac_addr_print(devname, sizeof(devname), &addr);
-                       dev_err(dev, "cannot set EUI-48 address %s: %d\n",
-                               devname, result);
-                       return result;
-               }
-       }
-       uwb_dev->mac_addr = addr;
-       return 0;
-}
-
-
-
-static int uwb_rc_setup(struct uwb_rc *rc)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       result = uwb_radio_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup UWB radio: %d\n", result);
-               goto error;
-       }
-       result = uwb_rc_mac_addr_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup UWB MAC address: %d\n", result);
-               goto error;
-       }
-       result = uwb_rc_dev_addr_assign(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot assign UWB DevAddr: %d\n", result);
-               goto error;
-       }
-       result = uwb_rc_ie_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup IE subsystem: %d\n", result);
-               goto error_ie_setup;
-       }
-       result = uwb_rsv_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup reservation subsystem: %d\n", result);
-               goto error_rsv_setup;
-       }
-       uwb_dbg_add_rc(rc);
-       return 0;
-
-error_rsv_setup:
-       uwb_rc_ie_release(rc);
-error_ie_setup:
-error:
-       return result;
-}
-
-
-/**
- * Register a new UWB radio controller
- *
- * Did you call uwb_rc_init() on your rc?
- *
- * We assume that this is being called with a > 0 refcount on
- * it [through ops->{get|put}_device(). We'll take our own, though.
- *
- * @parent_dev is our real device, the one that provides the actual UWB device
- */
-int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv)
-{
-       int result;
-       struct device *dev;
-       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
-
-       rc->index = uwb_rc_new_index();
-
-       dev = &rc->uwb_dev.dev;
-       dev_set_name(dev, "uwb%d", rc->index);
-
-       rc->priv = priv;
-
-       init_waitqueue_head(&rc->uwbd.wq);
-       INIT_LIST_HEAD(&rc->uwbd.event_list);
-       spin_lock_init(&rc->uwbd.event_list_lock);
-
-       uwbd_start(rc);
-
-       result = rc->start(rc);
-       if (result < 0)
-               goto error_rc_start;
-
-       result = uwb_rc_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup UWB radio controller: %d\n", result);
-               goto error_rc_setup;
-       }
-
-       result = uwb_dev_add(&rc->uwb_dev, parent_dev, rc);
-       if (result < 0 && result != -EADDRNOTAVAIL)
-               goto error_dev_add;
-
-       result = uwb_rc_sys_add(rc);
-       if (result < 0) {
-               dev_err(parent_dev, "cannot register UWB radio controller "
-                       "dev attributes: %d\n", result);
-               goto error_sys_add;
-       }
-
-       uwb_mac_addr_print(macbuf, sizeof(macbuf), &rc->uwb_dev.mac_addr);
-       uwb_dev_addr_print(devbuf, sizeof(devbuf), &rc->uwb_dev.dev_addr);
-       dev_info(dev,
-                "new uwb radio controller (mac %s dev %s) on %s %s\n",
-                macbuf, devbuf, parent_dev->bus->name, dev_name(parent_dev));
-       rc->ready = 1;
-       return 0;
-
-error_sys_add:
-       uwb_dev_rm(&rc->uwb_dev);
-error_dev_add:
-error_rc_setup:
-       rc->stop(rc);
-error_rc_start:
-       uwbd_stop(rc);
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_add);
-
-
-static int uwb_dev_offair_helper(struct device *dev, void *priv)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-
-       return __uwb_dev_offair(uwb_dev, uwb_dev->rc);
-}
-
-/*
- * Remove a Radio Controller; stop beaconing/scanning, disconnect all children
- */
-void uwb_rc_rm(struct uwb_rc *rc)
-{
-       rc->ready = 0;
-
-       uwb_dbg_del_rc(rc);
-       uwb_rsv_remove_all(rc);
-       uwb_radio_shutdown(rc);
-
-       rc->stop(rc);
-
-       uwbd_stop(rc);
-       uwb_rc_neh_destroy(rc);
-
-       uwb_dev_lock(&rc->uwb_dev);
-       rc->priv = NULL;
-       rc->cmd = NULL;
-       uwb_dev_unlock(&rc->uwb_dev);
-       mutex_lock(&rc->uwb_beca.mutex);
-       uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL);
-       __uwb_rc_sys_rm(rc);
-       mutex_unlock(&rc->uwb_beca.mutex);
-       uwb_rsv_cleanup(rc);
-       uwb_beca_release(rc);
-       uwb_dev_rm(&rc->uwb_dev);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_rm);
-
-static int find_rc_try_get(struct device *dev, const void *data)
-{
-       const struct uwb_rc *target_rc = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc == NULL) {
-               WARN_ON(1);
-               return 0;
-       }
-       if (rc == target_rc) {
-               if (rc->ready == 0)
-                       return 0;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * Given a radio controller descriptor, validate and refcount it
- *
- * @returns NULL if the rc does not exist or is quiescing; the ptr to
- *               it otherwise.
- */
-struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc)
-{
-       struct device *dev;
-       struct uwb_rc *rc = NULL;
-
-       dev = class_find_device(&uwb_rc_class, NULL, target_rc,
-                               find_rc_try_get);
-       if (dev) {
-               rc = dev_get_drvdata(dev);
-               __uwb_rc_get(rc);
-               put_device(dev);
-       }
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(__uwb_rc_try_get);
-
-/*
- * RC get for external refcount acquirers...
- *
- * Increments the refcount of the device and it's backend modules
- */
-static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc)
-{
-       if (rc->ready == 0)
-               return NULL;
-       uwb_dev_get(&rc->uwb_dev);
-       return rc;
-}
-
-static int find_rc_grandpa(struct device *dev, const void *data)
-{
-       const struct device *grandpa_dev = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc->uwb_dev.dev.parent->parent == grandpa_dev) {
-               rc = uwb_rc_get(rc);
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * Locate and refcount a radio controller given a common grand-parent
- *
- * @grandpa_dev  Pointer to the 'grandparent' device structure.
- * @returns NULL If the rc does not exist or is quiescing; the ptr to
- *               it otherwise, properly referenced.
- *
- * The Radio Control interface (or the UWB Radio Controller) is always
- * an interface of a device. The parent is the interface, the
- * grandparent is the device that encapsulates the interface.
- *
- * There is no need to lock around as the "grandpa" would be
- * refcounted by the target, and to remove the referemes, the
- * uwb_rc_class->sem would have to be taken--we hold it, ergo we
- * should be safe.
- */
-struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
-{
-       struct device *dev;
-       struct uwb_rc *rc = NULL;
-
-       dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev,
-                               find_rc_grandpa);
-       if (dev) {
-               rc = dev_get_drvdata(dev);
-               put_device(dev);
-       }
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
-
-/**
- * Find a radio controller by device address
- *
- * @returns the pointer to the radio controller, properly referenced
- */
-static int find_rc_dev(struct device *dev, const void *data)
-{
-       const struct uwb_dev_addr *addr = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc == NULL) {
-               WARN_ON(1);
-               return 0;
-       }
-       if (!uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, addr)) {
-               rc = uwb_rc_get(rc);
-               return 1;
-       }
-       return 0;
-}
-
-struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
-{
-       struct device *dev;
-       struct uwb_rc *rc = NULL;
-
-       dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev);
-       if (dev) {
-               rc = dev_get_drvdata(dev);
-               put_device(dev);
-       }
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_get_by_dev);
-
-/**
- * Drop a reference on a radio controller
- *
- * This is the version that should be done by entities external to the
- * UWB Radio Control stack (ie: clients of the API).
- */
-void uwb_rc_put(struct uwb_rc *rc)
-{
-       __uwb_rc_put(rc);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_put);
diff --git a/drivers/staging/uwb/neh.c b/drivers/staging/uwb/neh.c
deleted file mode 100644 (file)
index 1695584..0000000
+++ /dev/null
@@ -1,606 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * WUSB Wire Adapter: Radio Control Interface (WUSB[8])
- * Notification and Event Handling
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * The RC interface of the Host Wire Adapter (USB dongle) or WHCI PCI
- * card delivers a stream of notifications and events to the
- * notification end event endpoint or area. This code takes care of
- * getting a buffer with that data, breaking it up in separate
- * notifications and events and then deliver those.
- *
- * Events are answers to commands and they carry a context ID that
- * associates them to the command. Notifications are that,
- * notifications, they come out of the blue and have a context ID of
- * zero. Think of the context ID kind of like a handler. The
- * uwb_rc_neh_* code deals with managing context IDs.
- *
- * This is why you require a handle to operate on a UWB host. When you
- * open a handle a context ID is assigned to you.
- *
- * So, as it is done is:
- *
- * 1. Add an event handler [uwb_rc_neh_add()] (assigns a ctx id)
- * 2. Issue command [rc->cmd(rc, ...)]
- * 3. Arm the timeout timer [uwb_rc_neh_arm()]
- * 4, Release the reference to the neh [uwb_rc_neh_put()]
- * 5. Wait for the callback
- * 6. Command result (RCEB) is passed to the callback
- *
- * If (2) fails, you should remove the handle [uwb_rc_neh_rm()]
- * instead of arming the timer.
- *
- * Handles are for using in *serialized* code, single thread.
- *
- * When the notification/event comes, the IRQ handler/endpoint
- * callback passes the data read to uwb_rc_neh_grok() which will break
- * it up in a discrete series of events, look up who is listening for
- * them and execute the pertinent callbacks.
- *
- * If the reader detects an error while reading the data stream, call
- * uwb_rc_neh_error().
- *
- * CONSTRAINTS/ASSUMPTIONS:
- *
- * - Most notifications/events are small (less thank .5k), copying
- *   around is ok.
- *
- * - Notifications/events are ALWAYS smaller than PAGE_SIZE
- *
- * - Notifications/events always come in a single piece (ie: a buffer
- *   will always contain entire notifications/events).
- *
- * - we cannot know in advance how long each event is (because they
- *   lack a length field in their header--smart move by the standards
- *   body, btw). So we need a facility to get the event size given the
- *   header. This is what the EST code does (notif/Event Size
- *   Tables), check nest.c--as well, you can associate the size to
- *   the handle [w/ neh->extra_size()].
- *
- * - Most notifications/events are fixed size; only a few are variable
- *   size (NEST takes care of that).
- *
- * - Listeners of events expect them, so they usually provide a
- *   buffer, as they know the size. Listeners to notifications don't,
- *   so we allocate their buffers dynamically.
- */
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-/*
- * UWB Radio Controller Notification/Event Handle
- *
- * Represents an entity waiting for an event coming from the UWB Radio
- * Controller with a given context id (context) and type (evt_type and
- * evt). On reception of the notification/event, the callback (cb) is
- * called with the event.
- *
- * If the timer expires before the event is received, the callback is
- * called with -ETIMEDOUT as the event size.
- */
-struct uwb_rc_neh {
-       struct kref kref;
-
-       struct uwb_rc *rc;
-       u8 evt_type;
-       __le16 evt;
-       u8 context;
-       u8 completed;
-       uwb_rc_cmd_cb_f cb;
-       void *arg;
-
-       struct timer_list timer;
-       struct list_head list_node;
-};
-
-static void uwb_rc_neh_timer(struct timer_list *t);
-
-static void uwb_rc_neh_release(struct kref *kref)
-{
-       struct uwb_rc_neh *neh = container_of(kref, struct uwb_rc_neh, kref);
-
-       kfree(neh);
-}
-
-static void uwb_rc_neh_get(struct uwb_rc_neh *neh)
-{
-       kref_get(&neh->kref);
-}
-
-/**
- * uwb_rc_neh_put - release reference to a neh
- * @neh: the neh
- */
-void uwb_rc_neh_put(struct uwb_rc_neh *neh)
-{
-       kref_put(&neh->kref, uwb_rc_neh_release);
-}
-
-
-/**
- * Assigns @neh a context id from @rc's pool
- *
- * @rc:            UWB Radio Controller descriptor; @rc->neh_lock taken
- * @neh:    Notification/Event Handle
- * @returns 0 if context id was assigned ok; < 0 errno on error (if
- *         all the context IDs are taken).
- *
- * (assumes @wa is locked).
- *
- * NOTE: WUSB spec reserves context ids 0x00 for notifications and
- *      0xff is invalid, so they must not be used. Initialization
- *      fills up those two in the bitmap so they are not allocated.
- *
- * We spread the allocation around to reduce the possibility of two
- * consecutive opened @neh's getting the same context ID assigned (to
- * avoid surprises with late events that timed out long time ago). So
- * first we search from where @rc->ctx_roll is, if not found, we
- * search from zero.
- */
-static
-int __uwb_rc_ctx_get(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       int result;
-       result = find_next_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX,
-                                   rc->ctx_roll++);
-       if (result < UWB_RC_CTX_MAX)
-               goto found;
-       result = find_first_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX);
-       if (result < UWB_RC_CTX_MAX)
-               goto found;
-       return -ENFILE;
-found:
-       set_bit(result, rc->ctx_bm);
-       neh->context = result;
-       return 0;
-}
-
-
-/** Releases @neh's context ID back to @rc (@rc->neh_lock is locked). */
-static
-void __uwb_rc_ctx_put(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       if (neh->context == 0)
-               return;
-       if (test_bit(neh->context, rc->ctx_bm) == 0) {
-               dev_err(dev, "context %u not set in bitmap\n",
-                       neh->context);
-               WARN_ON(1);
-       }
-       clear_bit(neh->context, rc->ctx_bm);
-       neh->context = 0;
-}
-
-/**
- * uwb_rc_neh_add - add a neh for a radio controller command
- * @rc:             the radio controller
- * @cmd:            the radio controller command
- * @expected_type:  the type of the expected response event
- * @expected_event: the expected event ID
- * @cb:             callback for when the event is received
- * @arg:            argument for the callback
- *
- * Creates a neh and adds it to the list of those waiting for an
- * event.  A context ID will be assigned to the command.
- */
-struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
-                                 u8 expected_type, u16 expected_event,
-                                 uwb_rc_cmd_cb_f cb, void *arg)
-{
-       int result;
-       unsigned long flags;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_neh *neh;
-
-       neh = kzalloc(sizeof(*neh), GFP_KERNEL);
-       if (neh == NULL) {
-               result = -ENOMEM;
-               goto error_kzalloc;
-       }
-
-       kref_init(&neh->kref);
-       INIT_LIST_HEAD(&neh->list_node);
-       timer_setup(&neh->timer, uwb_rc_neh_timer, 0);
-
-       neh->rc = rc;
-       neh->evt_type = expected_type;
-       neh->evt = cpu_to_le16(expected_event);
-       neh->cb = cb;
-       neh->arg = arg;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-       result = __uwb_rc_ctx_get(rc, neh);
-       if (result >= 0) {
-               cmd->bCommandContext = neh->context;
-               list_add_tail(&neh->list_node, &rc->neh_list);
-               uwb_rc_neh_get(neh);
-       }
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-       if (result < 0)
-               goto error_ctx_get;
-
-       return neh;
-
-error_ctx_get:
-       kfree(neh);
-error_kzalloc:
-       dev_err(dev, "cannot open handle to radio controller: %d\n", result);
-       return ERR_PTR(result);
-}
-
-static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       __uwb_rc_ctx_put(rc, neh);
-       list_del(&neh->list_node);
-}
-
-/**
- * uwb_rc_neh_rm - remove a neh.
- * @rc:  the radio controller
- * @neh: the neh to remove
- *
- * Remove an active neh immediately instead of waiting for the event
- * (or a time out).
- */
-void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-       __uwb_rc_neh_rm(rc, neh);
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-       del_timer_sync(&neh->timer);
-       uwb_rc_neh_put(neh);
-}
-
-/**
- * uwb_rc_neh_arm - arm an event handler timeout timer
- *
- * @rc:     UWB Radio Controller
- * @neh:    Notification/event handler for @rc
- *
- * The timer is only armed if the neh is active.
- */
-void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-       if (neh->context)
-               mod_timer(&neh->timer,
-                         jiffies + msecs_to_jiffies(UWB_RC_CMD_TIMEOUT_MS));
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-}
-
-static void uwb_rc_neh_cb(struct uwb_rc_neh *neh, struct uwb_rceb *rceb, size_t size)
-{
-       (*neh->cb)(neh->rc, neh->arg, rceb, size);
-       uwb_rc_neh_put(neh);
-}
-
-static bool uwb_rc_neh_match(struct uwb_rc_neh *neh, const struct uwb_rceb *rceb)
-{
-       return neh->evt_type == rceb->bEventType
-               && neh->evt == rceb->wEvent
-               && neh->context == rceb->bEventContext;
-}
-
-/**
- * Find the handle waiting for a RC Radio Control Event
- *
- * @rc:         UWB Radio Controller
- * @rceb:       Pointer to the RCEB buffer
- * @event_size: Pointer to the size of the RCEB buffer. Might be
- *              adjusted to take into account the @neh->extra_size
- *              settings.
- *
- * If the listener has no buffer (NULL buffer), one is allocated for
- * the right size (the amount of data received). @neh->ptr will point
- * to the event payload, which always starts with a 'struct
- * uwb_rceb'. kfree() it when done.
- */
-static
-struct uwb_rc_neh *uwb_rc_neh_lookup(struct uwb_rc *rc,
-                                    const struct uwb_rceb *rceb)
-{
-       struct uwb_rc_neh *neh = NULL, *h;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-
-       list_for_each_entry(h, &rc->neh_list, list_node) {
-               if (uwb_rc_neh_match(h, rceb)) {
-                       neh = h;
-                       break;
-               }
-       }
-
-       if (neh)
-               __uwb_rc_neh_rm(rc, neh);
-
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-       return neh;
-}
-
-
-/*
- * Process notifications coming from the radio control interface
- *
- * @rc:    UWB Radio Control Interface descriptor
- * @neh:   Notification/Event Handler @neh->ptr points to
- *         @uwb_evt->buffer.
- *
- * This function is called by the event/notif handling subsystem when
- * notifications arrive (hwarc_probe() arms a notification/event handle
- * that calls back this function for every received notification; this
- * function then will rearm itself).
- *
- * Notification data buffers are dynamically allocated by the NEH
- * handling code in neh.c [uwb_rc_neh_lookup()]. What is actually
- * allocated is space to contain the notification data.
- *
- * Buffers are prefixed with a Radio Control Event Block (RCEB) as
- * defined by the WUSB Wired-Adapter Radio Control interface. We
- * just use it for the notification code.
- *
- * On each case statement we just transcode endianess of the different
- * fields. We declare a pointer to a RCI definition of an event, and
- * then to a UWB definition of the same event (which are the same,
- * remember). Event if we use different pointers
- */
-static
-void uwb_rc_notif(struct uwb_rc *rc, struct uwb_rceb *rceb, ssize_t size)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_event *uwb_evt;
-
-       if (size == -ESHUTDOWN)
-               return;
-       if (size < 0) {
-               dev_err(dev, "ignoring event with error code %zu\n",
-                       size);
-               return;
-       }
-
-       uwb_evt = kzalloc(sizeof(*uwb_evt), GFP_ATOMIC);
-       if (unlikely(uwb_evt == NULL)) {
-               dev_err(dev, "no memory to queue event 0x%02x/%04x/%02x\n",
-                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                       rceb->bEventContext);
-               return;
-       }
-       uwb_evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */
-       uwb_evt->ts_jiffies = jiffies;
-       uwb_evt->type = UWB_EVT_TYPE_NOTIF;
-       uwb_evt->notif.size = size;
-       uwb_evt->notif.rceb = rceb;
-
-       uwbd_event_queue(uwb_evt);
-}
-
-static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size_t size)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_neh *neh;
-       struct uwb_rceb *notif;
-       unsigned long flags;
-
-       if (rceb->bEventContext == 0) {
-               notif = kmalloc(size, GFP_ATOMIC);
-               if (notif) {
-                       memcpy(notif, rceb, size);
-                       uwb_rc_notif(rc, notif, size);
-               } else
-                       dev_err(dev, "event 0x%02x/%04x/%02x (%zu bytes): no memory\n",
-                               rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                               rceb->bEventContext, size);
-       } else {
-               neh = uwb_rc_neh_lookup(rc, rceb);
-               if (neh) {
-                       spin_lock_irqsave(&rc->neh_lock, flags);
-                       /* to guard against a timeout */
-                       neh->completed = 1;
-                       del_timer(&neh->timer);
-                       spin_unlock_irqrestore(&rc->neh_lock, flags);
-                       uwb_rc_neh_cb(neh, rceb, size);
-               } else
-                       dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n",
-                                rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                                rceb->bEventContext, size);
-       }
-}
-
-/**
- * Given a buffer with one or more UWB RC events/notifications, break
- * them up and dispatch them.
- *
- * @rc:              UWB Radio Controller
- * @buf:      Buffer with the stream of notifications/events
- * @buf_size: Amount of data in the buffer
- *
- * Note each notification/event starts always with a 'struct
- * uwb_rceb', so the minimum size if 4 bytes.
- *
- * The device may pass us events formatted differently than expected.
- * These are first filtered, potentially creating a new event in a new
- * memory location. If a new event is created by the filter it is also
- * freed here.
- *
- * For each notif/event, tries to guess the size looking at the EST
- * tables, then looks for a neh that is waiting for that event and if
- * found, copies the payload to the neh's buffer and calls it back. If
- * not, the data is ignored.
- *
- * Note that if we can't find a size description in the EST tables, we
- * still might find a size in the 'neh' handle in uwb_rc_neh_lookup().
- *
- * Assumptions:
- *
- *   @rc->neh_lock is NOT taken
- *
- * We keep track of various sizes here:
- * size:      contains the size of the buffer that is processed for the
- *            incoming event. this buffer may contain events that are not
- *            formatted as WHCI.
- * real_size: the actual space taken by this event in the buffer.
- *            We need to keep track of the real size of an event to be able to
- *            advance the buffer correctly.
- * event_size: the size of the event as expected by the core layer
- *            [OR] the size of the event after filtering. if the filtering
- *            created a new event in a new memory location then this is
- *            effectively the size of a new event buffer
- */
-void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       void *itr;
-       struct uwb_rceb *rceb;
-       size_t size, real_size, event_size;
-       int needtofree;
-
-       itr = buf;
-       size = buf_size;
-       while (size > 0) {
-               if (size < sizeof(*rceb)) {
-                       dev_err(dev, "not enough data in event buffer to "
-                               "process incoming events (%zu left, minimum is "
-                               "%zu)\n", size, sizeof(*rceb));
-                       break;
-               }
-
-               rceb = itr;
-               if (rc->filter_event) {
-                       needtofree = rc->filter_event(rc, &rceb, size,
-                                                     &real_size, &event_size);
-                       if (needtofree < 0 && needtofree != -ENOANO) {
-                               dev_err(dev, "BUG: Unable to filter event "
-                                       "(0x%02x/%04x/%02x) from "
-                                       "device. \n", rceb->bEventType,
-                                       le16_to_cpu(rceb->wEvent),
-                                       rceb->bEventContext);
-                               break;
-                       }
-               } else
-                       needtofree = -ENOANO;
-               /* do real processing if there was no filtering or the
-                * filtering didn't act */
-               if (needtofree == -ENOANO) {
-                       ssize_t ret = uwb_est_find_size(rc, rceb, size);
-                       if (ret < 0)
-                               break;
-                       if (ret > size) {
-                               dev_err(dev, "BUG: hw sent incomplete event "
-                                       "0x%02x/%04x/%02x (%zd bytes), only got "
-                                       "%zu bytes. We don't handle that.\n",
-                                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                                       rceb->bEventContext, ret, size);
-                               break;
-                       }
-                       real_size = event_size = ret;
-               }
-               uwb_rc_neh_grok_event(rc, rceb, event_size);
-
-               if (needtofree == 1)
-                       kfree(rceb);
-
-               itr += real_size;
-               size -= real_size;
-       }
-}
-EXPORT_SYMBOL_GPL(uwb_rc_neh_grok);
-
-
-/**
- * The entity that reads from the device notification/event channel has
- * detected an error.
- *
- * @rc:    UWB Radio Controller
- * @error: Errno error code
- *
- */
-void uwb_rc_neh_error(struct uwb_rc *rc, int error)
-{
-       struct uwb_rc_neh *neh;
-       unsigned long flags;
-
-       for (;;) {
-               spin_lock_irqsave(&rc->neh_lock, flags);
-               if (list_empty(&rc->neh_list)) {
-                       spin_unlock_irqrestore(&rc->neh_lock, flags);
-                       break;
-               }
-               neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
-               __uwb_rc_neh_rm(rc, neh);
-               spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-               del_timer_sync(&neh->timer);
-               uwb_rc_neh_cb(neh, NULL, error);
-       }
-}
-EXPORT_SYMBOL_GPL(uwb_rc_neh_error);
-
-
-static void uwb_rc_neh_timer(struct timer_list *t)
-{
-       struct uwb_rc_neh *neh = from_timer(neh, t, timer);
-       struct uwb_rc *rc = neh->rc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-       if (neh->completed) {
-               spin_unlock_irqrestore(&rc->neh_lock, flags);
-               return;
-       }
-       if (neh->context)
-               __uwb_rc_neh_rm(rc, neh);
-       else
-               neh = NULL;
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-       if (neh)
-               uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT);
-}
-
-/** Initializes the @rc's neh subsystem
- */
-void uwb_rc_neh_create(struct uwb_rc *rc)
-{
-       spin_lock_init(&rc->neh_lock);
-       INIT_LIST_HEAD(&rc->neh_list);
-       set_bit(0, rc->ctx_bm);         /* 0 is reserved (see [WUSB] table 8-65) */
-       set_bit(0xff, rc->ctx_bm);      /* and 0xff is invalid */
-       rc->ctx_roll = 1;
-}
-
-
-/** Release's the @rc's neh subsystem */
-void uwb_rc_neh_destroy(struct uwb_rc *rc)
-{
-       unsigned long flags;
-       struct uwb_rc_neh *neh;
-
-       for (;;) {
-               spin_lock_irqsave(&rc->neh_lock, flags);
-               if (list_empty(&rc->neh_list)) {
-                       spin_unlock_irqrestore(&rc->neh_lock, flags);
-                       break;
-               }
-               neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
-               __uwb_rc_neh_rm(rc, neh);
-               spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-               del_timer_sync(&neh->timer);
-               uwb_rc_neh_put(neh);
-       }
-}
diff --git a/drivers/staging/uwb/pal.c b/drivers/staging/uwb/pal.c
deleted file mode 100644 (file)
index a541e64..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB PAL support.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/export.h>
-
-#include "uwb.h"
-#include "uwb-internal.h"
-
-/**
- * uwb_pal_init - initialize a UWB PAL
- * @pal: the PAL to initialize
- */
-void uwb_pal_init(struct uwb_pal *pal)
-{
-       INIT_LIST_HEAD(&pal->node);
-}
-EXPORT_SYMBOL_GPL(uwb_pal_init);
-
-/**
- * uwb_pal_register - register a UWB PAL
- * @pal: the PAL
- *
- * The PAL must be initialized with uwb_pal_init().
- */
-int uwb_pal_register(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-       int ret;
-
-       if (pal->device) {
-               /* create a link to the uwb_rc in the PAL device's directory. */
-               ret = sysfs_create_link(&pal->device->kobj,
-                                       &rc->uwb_dev.dev.kobj, "uwb_rc");
-               if (ret < 0)
-                       return ret;
-               /* create a link to the PAL in the UWB device's directory. */
-               ret = sysfs_create_link(&rc->uwb_dev.dev.kobj,
-                                       &pal->device->kobj, pal->name);
-               if (ret < 0) {
-                       sysfs_remove_link(&pal->device->kobj, "uwb_rc");
-                       return ret;
-               }
-       }
-
-       pal->debugfs_dir = uwb_dbg_create_pal_dir(pal);
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       list_add(&pal->node, &rc->pals);
-       mutex_unlock(&rc->uwb_dev.mutex);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uwb_pal_register);
-
-static int find_rc(struct device *dev, const void *data)
-{
-       const struct uwb_rc *target_rc = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc == NULL) {
-               WARN_ON(1);
-               return 0;
-       }
-       if (rc == target_rc) {
-               if (rc->ready == 0)
-                       return 0;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * Given a radio controller descriptor see if it is registered.
- *
- * @returns false if the rc does not exist or is quiescing; true otherwise.
- */
-static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc)
-{
-       struct device *dev;
-
-       dev = class_find_device(&uwb_rc_class, NULL, target_rc, find_rc);
-
-       put_device(dev);
-
-       return (dev != NULL);
-}
-
-/**
- * uwb_pal_unregister - unregister a UWB PAL
- * @pal: the PAL
- */
-void uwb_pal_unregister(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-
-       uwb_radio_stop(pal);
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       list_del(&pal->node);
-       mutex_unlock(&rc->uwb_dev.mutex);
-
-       debugfs_remove(pal->debugfs_dir);
-
-       if (pal->device) {
-               /* remove link to the PAL in the UWB device's directory. */
-               if (uwb_rc_class_device_exists(rc))
-                       sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
-
-               /* remove link to uwb_rc in the PAL device's directory. */
-               sysfs_remove_link(&pal->device->kobj, "uwb_rc");
-       }
-}
-EXPORT_SYMBOL_GPL(uwb_pal_unregister);
-
-/**
- * uwb_rc_pal_init - initialize the PAL related parts of a radio controller
- * @rc: the radio controller
- */
-void uwb_rc_pal_init(struct uwb_rc *rc)
-{
-       INIT_LIST_HEAD(&rc->pals);
-}
diff --git a/drivers/staging/uwb/radio.c b/drivers/staging/uwb/radio.c
deleted file mode 100644 (file)
index 6afb75c..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB radio (channel) management.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/export.h>
-
-#include "uwb.h"
-#include "uwb-internal.h"
-
-
-static int uwb_radio_select_channel(struct uwb_rc *rc)
-{
-       /*
-        * Default to channel 9 (BG1, TFC1) unless the user has
-        * selected a specific channel or there are no active PALs.
-        */
-       if (rc->active_pals == 0)
-               return -1;
-       if (rc->beaconing_forced)
-               return rc->beaconing_forced;
-       return 9;
-}
-
-
-/*
- * Notify all active PALs that the channel has changed.
- */
-static void uwb_radio_channel_changed(struct uwb_rc *rc, int channel)
-{
-       struct uwb_pal *pal;
-
-       list_for_each_entry(pal, &rc->pals, node) {
-               if (pal->channel && channel != pal->channel) {
-                       pal->channel = channel;
-                       if (pal->channel_changed)
-                               pal->channel_changed(pal, pal->channel);
-               }
-       }
-}
-
-/*
- * Change to a new channel and notify any active PALs of the new
- * channel.
- *
- * When stopping the radio, PALs need to be notified first so they can
- * terminate any active reservations.
- */
-static int uwb_radio_change_channel(struct uwb_rc *rc, int channel)
-{
-       int ret = 0;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       dev_dbg(dev, "%s: channel = %d, rc->beaconing = %d\n", __func__,
-               channel, rc->beaconing);
-
-       if (channel == -1)
-               uwb_radio_channel_changed(rc, channel);
-
-       if (channel != rc->beaconing) {
-               if (rc->beaconing != -1 && channel != -1) {
-                       /*
-                        * FIXME: should signal the channel change
-                        * with a Channel Change IE.
-                        */
-                       ret = uwb_radio_change_channel(rc, -1);
-                       if (ret < 0)
-                               return ret;
-               }
-               ret = uwb_rc_beacon(rc, channel, 0);
-       }
-
-       if (channel != -1)
-               uwb_radio_channel_changed(rc, rc->beaconing);
-
-       return ret;
-}
-
-/**
- * uwb_radio_start - request that the radio be started
- * @pal: the PAL making the request.
- *
- * If the radio is not already active, a suitable channel is selected
- * and beacons are started.
- */
-int uwb_radio_start(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-       int ret = 0;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-
-       if (!pal->channel) {
-               pal->channel = -1;
-               rc->active_pals++;
-               ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
-       }
-
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(uwb_radio_start);
-
-/**
- * uwb_radio_stop - request that the radio be stopped.
- * @pal: the PAL making the request.
- *
- * Stops the radio if no other PAL is making use of it.
- */
-void uwb_radio_stop(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-
-       if (pal->channel) {
-               rc->active_pals--;
-               uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
-               pal->channel = 0;
-       }
-
-       mutex_unlock(&rc->uwb_dev.mutex);
-}
-EXPORT_SYMBOL_GPL(uwb_radio_stop);
-
-/*
- * uwb_radio_force_channel - force a specific channel to be used
- * @rc: the radio controller.
- * @channel: the channel to use; -1 to force the radio to stop; 0 to
- *   use the default channel selection algorithm.
- */
-int uwb_radio_force_channel(struct uwb_rc *rc, int channel)
-{
-       int ret = 0;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-
-       rc->beaconing_forced = channel;
-       ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
-
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return ret;
-}
-
-/*
- * uwb_radio_setup - setup the radio manager
- * @rc: the radio controller.
- *
- * The radio controller is reset to ensure it's in a known state
- * before it's used.
- */
-int uwb_radio_setup(struct uwb_rc *rc)
-{
-       return uwb_rc_reset(rc);
-}
-
-/*
- * uwb_radio_reset_state - reset any radio manager state
- * @rc: the radio controller.
- *
- * All internal radio manager state is reset to values corresponding
- * to a reset radio controller.
- */
-void uwb_radio_reset_state(struct uwb_rc *rc)
-{
-       struct uwb_pal *pal;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-
-       list_for_each_entry(pal, &rc->pals, node) {
-               if (pal->channel) {
-                       pal->channel = -1;
-                       if (pal->channel_changed)
-                               pal->channel_changed(pal, -1);
-               }
-       }
-
-       rc->beaconing = -1;
-       rc->scanning = -1;
-
-       mutex_unlock(&rc->uwb_dev.mutex);
-}
-
-/*
- * uwb_radio_shutdown - shutdown the radio manager
- * @rc: the radio controller.
- *
- * The radio controller is reset.
- */
-void uwb_radio_shutdown(struct uwb_rc *rc)
-{
-       uwb_radio_reset_state(rc);
-       uwb_rc_reset(rc);
-}
diff --git a/drivers/staging/uwb/reset.c b/drivers/staging/uwb/reset.c
deleted file mode 100644 (file)
index 8fc7c14..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * UWB basic command support and radio reset
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME:
- *
- *  - docs
- *
- *  - Now we are serializing (using the uwb_dev->mutex) the command
- *    execution; it should be parallelized as much as possible some
- *    day.
- */
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-/**
- * Command result codes (WUSB1.0[T8-69])
- */
-static
-const char *__strerror[] = {
-       "success",
-       "failure",
-       "hardware failure",
-       "no more slots",
-       "beacon is too large",
-       "invalid parameter",
-       "unsupported power level",
-       "time out (wa) or invalid ie data (whci)",
-       "beacon size exceeded",
-       "cancelled",
-       "invalid state",
-       "invalid size",
-       "ack not received",
-       "no more asie notification",
-};
-
-
-/** Return a string matching the given error code */
-const char *uwb_rc_strerror(unsigned code)
-{
-       if (code == 255)
-               return "time out";
-       if (code >= ARRAY_SIZE(__strerror))
-               return "unknown error";
-       return __strerror[code];
-}
-
-int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
-                    struct uwb_rccb *cmd, size_t cmd_size,
-                    u8 expected_type, u16 expected_event,
-                    uwb_rc_cmd_cb_f cb, void *arg)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_neh *neh;
-       int needtofree = 0;
-       int result;
-
-       uwb_dev_lock(&rc->uwb_dev);     /* Protect against rc->priv being removed */
-       if (rc->priv == NULL) {
-               uwb_dev_unlock(&rc->uwb_dev);
-               return -ESHUTDOWN;
-       }
-
-       if (rc->filter_cmd) {
-               needtofree = rc->filter_cmd(rc, &cmd, &cmd_size);
-               if (needtofree < 0 && needtofree != -ENOANO) {
-                       dev_err(dev, "%s: filter error: %d\n",
-                               cmd_name, needtofree);
-                       uwb_dev_unlock(&rc->uwb_dev);
-                       return needtofree;
-               }
-       }
-
-       neh = uwb_rc_neh_add(rc, cmd, expected_type, expected_event, cb, arg);
-       if (IS_ERR(neh)) {
-               result = PTR_ERR(neh);
-               uwb_dev_unlock(&rc->uwb_dev);
-               goto out;
-       }
-
-       result = rc->cmd(rc, cmd, cmd_size);
-       uwb_dev_unlock(&rc->uwb_dev);
-       if (result < 0)
-               uwb_rc_neh_rm(rc, neh);
-       else
-               uwb_rc_neh_arm(rc, neh);
-       uwb_rc_neh_put(neh);
-out:
-       if (needtofree == 1)
-               kfree(cmd);
-       return result < 0 ? result : 0;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_cmd_async);
-
-struct uwb_rc_cmd_done_params {
-       struct completion completion;
-       struct uwb_rceb *reply;
-       ssize_t reply_size;
-};
-
-static void uwb_rc_cmd_done(struct uwb_rc *rc, void *arg,
-                           struct uwb_rceb *reply, ssize_t reply_size)
-{
-       struct uwb_rc_cmd_done_params *p = (struct uwb_rc_cmd_done_params *)arg;
-
-       if (reply_size > 0) {
-               if (p->reply)
-                       reply_size = min(p->reply_size, reply_size);
-               else
-                       p->reply = kmalloc(reply_size, GFP_ATOMIC);
-
-               if (p->reply)
-                       memcpy(p->reply, reply, reply_size);
-               else
-                       reply_size = -ENOMEM;
-       }
-       p->reply_size = reply_size;
-       complete(&p->completion);
-}
-
-
-/**
- * Generic function for issuing commands to the Radio Control Interface
- *
- * @rc:       UWB Radio Control descriptor
- * @cmd_name: Name of the command being issued (for error messages)
- * @cmd:      Pointer to rccb structure containing the command;
- *            normally you embed this structure as the first member of
- *            the full command structure.
- * @cmd_size: Size of the whole command buffer pointed to by @cmd.
- * @reply:    Pointer to where to store the reply
- * @reply_size: @reply's size
- * @expected_type: Expected type in the return event
- * @expected_event: Expected event code in the return event
- * @preply:   Here a pointer to where the event data is received will
- *            be stored. Once done with the data, free with kfree().
- *
- * This function is generic; it works for commands that return a fixed
- * and known size or for commands that return a variable amount of data.
- *
- * If a buffer is provided, that is used, although it could be chopped
- * to the maximum size of the buffer. If the buffer is NULL, then one
- * be allocated in *preply with the whole contents of the reply.
- *
- * @rc needs to be referenced
- */
-static
-ssize_t __uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
-                    struct uwb_rccb *cmd, size_t cmd_size,
-                    struct uwb_rceb *reply, size_t reply_size,
-                    u8 expected_type, u16 expected_event,
-                    struct uwb_rceb **preply)
-{
-       ssize_t result = 0;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_cmd_done_params params;
-
-       init_completion(&params.completion);
-       params.reply = reply;
-       params.reply_size = reply_size;
-
-       result = uwb_rc_cmd_async(rc, cmd_name, cmd, cmd_size,
-                                 expected_type, expected_event,
-                                 uwb_rc_cmd_done, &params);
-       if (result)
-               return result;
-
-       wait_for_completion(&params.completion);
-
-       if (preply)
-               *preply = params.reply;
-
-       if (params.reply_size < 0)
-               dev_err(dev, "%s: confirmation event 0x%02x/%04x/%02x "
-                       "reception failed: %d\n", cmd_name,
-                       expected_type, expected_event, cmd->bCommandContext,
-                       (int)params.reply_size);
-       return params.reply_size;
-}
-
-
-/**
- * Generic function for issuing commands to the Radio Control Interface
- *
- * @rc:       UWB Radio Control descriptor
- * @cmd_name: Name of the command being issued (for error messages)
- * @cmd:      Pointer to rccb structure containing the command;
- *            normally you embed this structure as the first member of
- *            the full command structure.
- * @cmd_size: Size of the whole command buffer pointed to by @cmd.
- * @reply:    Pointer to the beginning of the confirmation event
- *            buffer. Normally bigger than an 'struct hwarc_rceb'.
- *            You need to fill out reply->bEventType and reply->wEvent (in
- *            cpu order) as the function will use them to verify the
- *            confirmation event.
- * @reply_size: Size of the reply buffer
- *
- * The function checks that the length returned in the reply is at
- * least as big as @reply_size; if not, it will be deemed an error and
- * -EIO returned.
- *
- * @rc needs to be referenced
- */
-ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
-                  struct uwb_rccb *cmd, size_t cmd_size,
-                  struct uwb_rceb *reply, size_t reply_size)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       ssize_t result;
-
-       result = __uwb_rc_cmd(rc, cmd_name,
-                             cmd, cmd_size, reply, reply_size,
-                             reply->bEventType, reply->wEvent, NULL);
-
-       if (result > 0 && result < reply_size) {
-               dev_err(dev, "%s: not enough data returned for decoding reply "
-                       "(%zu bytes received vs at least %zu needed)\n",
-                       cmd_name, result, reply_size);
-               result = -EIO;
-       }
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_cmd);
-
-
-/**
- * Generic function for issuing commands to the Radio Control
- * Interface that return an unknown amount of data
- *
- * @rc:       UWB Radio Control descriptor
- * @cmd_name: Name of the command being issued (for error messages)
- * @cmd:      Pointer to rccb structure containing the command;
- *            normally you embed this structure as the first member of
- *            the full command structure.
- * @cmd_size: Size of the whole command buffer pointed to by @cmd.
- * @expected_type: Expected type in the return event
- * @expected_event: Expected event code in the return event
- * @preply:   Here a pointer to where the event data is received will
- *            be stored. Once done with the data, free with kfree().
- *
- * The function checks that the length returned in the reply is at
- * least as big as a 'struct uwb_rceb *'; if not, it will be deemed an
- * error and -EIO returned.
- *
- * @rc needs to be referenced
- */
-ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
-                   struct uwb_rccb *cmd, size_t cmd_size,
-                   u8 expected_type, u16 expected_event,
-                   struct uwb_rceb **preply)
-{
-       return __uwb_rc_cmd(rc, cmd_name, cmd, cmd_size, NULL, 0,
-                           expected_type, expected_event, preply);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_vcmd);
-
-
-/**
- * Reset a UWB Host Controller (and all radio settings)
- *
- * @rc:      Host Controller descriptor
- * @returns: 0 if ok, < 0 errno code on error
- *
- * We put the command on kmalloc'ed memory as some arches cannot do
- * USB from the stack. The reply event is copied from an stage buffer,
- * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
- */
-int uwb_rc_reset(struct uwb_rc *rc)
-{
-       int result = -ENOMEM;
-       struct uwb_rc_evt_confirm reply;
-       struct uwb_rccb *cmd;
-       size_t cmd_size = sizeof(*cmd);
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               goto error_kzalloc;
-       cmd->bCommandType = UWB_RC_CET_GENERAL;
-       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_RESET;
-       result = uwb_rc_cmd(rc, "RESET", cmd, cmd_size,
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "RESET: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-       }
-error_cmd:
-       kfree(cmd);
-error_kzalloc:
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return result;
-}
-
-int uwbd_msg_handle_reset(struct uwb_event *evt)
-{
-       struct uwb_rc *rc = evt->rc;
-       int ret;
-
-       dev_info(&rc->uwb_dev.dev, "resetting radio controller\n");
-       ret = rc->reset(rc);
-       if (ret < 0) {
-               dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret);
-               goto error;
-       }
-       return 0;
-error:
-       /* Nothing can be done except try the reset again. Wait a bit
-          to avoid reset loops during probe() or remove(). */
-       msleep(1000);
-       uwb_rc_reset_all(rc);
-       return ret;
-}
-
-/**
- * uwb_rc_reset_all - request a reset of the radio controller and PALs
- * @rc: the radio controller of the hardware device to be reset.
- *
- * The full hardware reset of the radio controller and all the PALs
- * will be scheduled.
- */
-void uwb_rc_reset_all(struct uwb_rc *rc)
-{
-       struct uwb_event *evt;
-
-       evt = kzalloc(sizeof(struct uwb_event), GFP_ATOMIC);
-       if (unlikely(evt == NULL))
-               return;
-
-       evt->rc = __uwb_rc_get(rc);     /* will be put by uwbd's uwbd_event_handle() */
-       evt->ts_jiffies = jiffies;
-       evt->type = UWB_EVT_TYPE_MSG;
-       evt->message = UWB_EVT_MSG_RESET;
-
-       uwbd_event_queue(evt);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_reset_all);
-
-void uwb_rc_pre_reset(struct uwb_rc *rc)
-{
-       rc->stop(rc);
-       uwbd_flush(rc);
-
-       uwb_radio_reset_state(rc);
-       uwb_rsv_remove_all(rc);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_pre_reset);
-
-int uwb_rc_post_reset(struct uwb_rc *rc)
-{
-       int ret;
-
-       ret = rc->start(rc);
-       if (ret)
-               goto out;
-       ret = uwb_rc_mac_addr_set(rc, &rc->uwb_dev.mac_addr);
-       if (ret)
-               goto out;
-       ret = uwb_rc_dev_addr_set(rc, &rc->uwb_dev.dev_addr);
-       if (ret)
-               goto out;
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_post_reset);
diff --git a/drivers/staging/uwb/rsv.c b/drivers/staging/uwb/rsv.c
deleted file mode 100644 (file)
index d593a41..0000000
+++ /dev/null
@@ -1,1000 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB reservation management.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/export.h>
-
-#include "uwb.h"
-#include "uwb-internal.h"
-
-static void uwb_rsv_timer(struct timer_list *t);
-
-static const char *rsv_states[] = {
-       [UWB_RSV_STATE_NONE]                 = "none            ",
-       [UWB_RSV_STATE_O_INITIATED]          = "o initiated     ",
-       [UWB_RSV_STATE_O_PENDING]            = "o pending       ",
-       [UWB_RSV_STATE_O_MODIFIED]           = "o modified      ",
-       [UWB_RSV_STATE_O_ESTABLISHED]        = "o established   ",
-       [UWB_RSV_STATE_O_TO_BE_MOVED]        = "o to be moved   ",
-       [UWB_RSV_STATE_O_MOVE_EXPANDING]     = "o move expanding",
-       [UWB_RSV_STATE_O_MOVE_COMBINING]     = "o move combining",
-       [UWB_RSV_STATE_O_MOVE_REDUCING]      = "o move reducing ",
-       [UWB_RSV_STATE_T_ACCEPTED]           = "t accepted      ",
-       [UWB_RSV_STATE_T_CONFLICT]           = "t conflict      ",
-       [UWB_RSV_STATE_T_PENDING]            = "t pending       ",
-       [UWB_RSV_STATE_T_DENIED]             = "t denied        ",
-       [UWB_RSV_STATE_T_RESIZED]            = "t resized       ",
-       [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = "t expanding acc ",
-       [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = "t expanding conf",
-       [UWB_RSV_STATE_T_EXPANDING_PENDING]  = "t expanding pend",
-       [UWB_RSV_STATE_T_EXPANDING_DENIED]   = "t expanding den ",
-};
-
-static const char *rsv_types[] = {
-       [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp",
-       [UWB_DRP_TYPE_HARD]     = "hard",
-       [UWB_DRP_TYPE_SOFT]     = "soft",
-       [UWB_DRP_TYPE_PRIVATE]  = "private",
-       [UWB_DRP_TYPE_PCA]      = "pca",
-};
-
-bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv)
-{
-       static const bool has_two_drp_ies[] = {
-               [UWB_RSV_STATE_O_INITIATED]               = false,
-               [UWB_RSV_STATE_O_PENDING]                 = false,
-               [UWB_RSV_STATE_O_MODIFIED]                = false,
-               [UWB_RSV_STATE_O_ESTABLISHED]             = false,
-               [UWB_RSV_STATE_O_TO_BE_MOVED]             = false,
-               [UWB_RSV_STATE_O_MOVE_COMBINING]          = false,
-               [UWB_RSV_STATE_O_MOVE_REDUCING]           = false,
-               [UWB_RSV_STATE_O_MOVE_EXPANDING]          = true,
-               [UWB_RSV_STATE_T_ACCEPTED]                = false,
-               [UWB_RSV_STATE_T_CONFLICT]                = false,
-               [UWB_RSV_STATE_T_PENDING]                 = false,
-               [UWB_RSV_STATE_T_DENIED]                  = false,
-               [UWB_RSV_STATE_T_RESIZED]                 = false,
-               [UWB_RSV_STATE_T_EXPANDING_ACCEPTED]      = true,
-               [UWB_RSV_STATE_T_EXPANDING_CONFLICT]      = true,
-               [UWB_RSV_STATE_T_EXPANDING_PENDING]       = true,
-               [UWB_RSV_STATE_T_EXPANDING_DENIED]        = true,
-       };
-
-       return has_two_drp_ies[rsv->state];
-}
-
-/**
- * uwb_rsv_state_str - return a string for a reservation state
- * @state: the reservation state.
- */
-const char *uwb_rsv_state_str(enum uwb_rsv_state state)
-{
-       if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST)
-               return "unknown";
-       return rsv_states[state];
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_state_str);
-
-/**
- * uwb_rsv_type_str - return a string for a reservation type
- * @type: the reservation type
- */
-const char *uwb_rsv_type_str(enum uwb_drp_type type)
-{
-       if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA)
-               return "invalid";
-       return rsv_types[type];
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_type_str);
-
-void uwb_rsv_dump(char *text, struct uwb_rsv *rsv)
-{
-       struct device *dev = &rsv->rc->uwb_dev.dev;
-       struct uwb_dev_addr devaddr;
-       char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
-
-       uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
-       if (rsv->target.type == UWB_RSV_TARGET_DEV)
-               devaddr = rsv->target.dev->dev_addr;
-       else
-               devaddr = rsv->target.devaddr;
-       uwb_dev_addr_print(target, sizeof(target), &devaddr);
-
-       dev_dbg(dev, "rsv %s %s -> %s: %s\n",
-               text, owner, target, uwb_rsv_state_str(rsv->state));
-}
-
-static void uwb_rsv_release(struct kref *kref)
-{
-       struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref);
-
-       kfree(rsv);
-}
-
-void uwb_rsv_get(struct uwb_rsv *rsv)
-{
-       kref_get(&rsv->kref);
-}
-
-void uwb_rsv_put(struct uwb_rsv *rsv)
-{
-       kref_put(&rsv->kref, uwb_rsv_release);
-}
-
-/*
- * Get a free stream index for a reservation.
- *
- * If the target is a DevAddr (e.g., a WUSB cluster reservation) then
- * the stream is allocated from a pool of per-RC stream indexes,
- * otherwise a unique stream index for the target is selected.
- */
-static int uwb_rsv_get_stream(struct uwb_rsv *rsv)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct device *dev = &rc->uwb_dev.dev;
-       unsigned long *streams_bm;
-       int stream;
-
-       switch (rsv->target.type) {
-       case UWB_RSV_TARGET_DEV:
-               streams_bm = rsv->target.dev->streams;
-               break;
-       case UWB_RSV_TARGET_DEVADDR:
-               streams_bm = rc->uwb_dev.streams;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS);
-       if (stream >= UWB_NUM_STREAMS) {
-               dev_err(dev, "%s: no available stream found\n", __func__);
-               return -EBUSY;
-       }
-
-       rsv->stream = stream;
-       set_bit(stream, streams_bm);
-
-       dev_dbg(dev, "get stream %d\n", rsv->stream);
-
-       return 0;
-}
-
-static void uwb_rsv_put_stream(struct uwb_rsv *rsv)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct device *dev = &rc->uwb_dev.dev;
-       unsigned long *streams_bm;
-
-       switch (rsv->target.type) {
-       case UWB_RSV_TARGET_DEV:
-               streams_bm = rsv->target.dev->streams;
-               break;
-       case UWB_RSV_TARGET_DEVADDR:
-               streams_bm = rc->uwb_dev.streams;
-               break;
-       default:
-               return;
-       }
-
-       clear_bit(rsv->stream, streams_bm);
-
-       dev_dbg(dev, "put stream %d\n", rsv->stream);
-}
-
-void uwb_rsv_backoff_win_timer(struct timer_list *t)
-{
-       struct uwb_drp_backoff_win *bow = from_timer(bow, t, timer);
-       struct uwb_rc *rc = container_of(bow, struct uwb_rc, bow);
-       struct device *dev = &rc->uwb_dev.dev;
-
-       bow->can_reserve_extra_mases = true;
-       if (bow->total_expired <= 4) {
-               bow->total_expired++;
-       } else {
-               /* after 4 backoff window has expired we can exit from
-                * the backoff procedure */
-               bow->total_expired = 0;
-               bow->window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
-       }
-       dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n", bow->total_expired, bow->n);
-
-       /* try to relocate all the "to be moved" relocations */
-       uwb_rsv_handle_drp_avail_change(rc);
-}
-
-void uwb_rsv_backoff_win_increment(struct uwb_rc *rc)
-{
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       struct device *dev = &rc->uwb_dev.dev;
-       unsigned timeout_us;
-
-       dev_dbg(dev, "backoff_win_increment: window=%d\n", bow->window);
-
-       bow->can_reserve_extra_mases = false;
-
-       if((bow->window << 1) == UWB_DRP_BACKOFF_WIN_MAX)
-               return;
-
-       bow->window <<= 1;
-       bow->n = prandom_u32() & (bow->window - 1);
-       dev_dbg(dev, "new_window=%d, n=%d\n", bow->window, bow->n);
-
-       /* reset the timer associated variables */
-       timeout_us = bow->n * UWB_SUPERFRAME_LENGTH_US;
-       bow->total_expired = 0;
-       mod_timer(&bow->timer, jiffies + usecs_to_jiffies(timeout_us));
-}
-
-static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv)
-{
-       int sframes = UWB_MAX_LOST_BEACONS;
-
-       /*
-        * Multicast reservations can become established within 1
-        * super frame and should not be terminated if no response is
-        * received.
-        */
-       if (rsv->state == UWB_RSV_STATE_NONE) {
-               sframes = 0;
-       } else if (rsv->is_multicast) {
-               if (rsv->state == UWB_RSV_STATE_O_INITIATED
-                   || rsv->state == UWB_RSV_STATE_O_MOVE_EXPANDING
-                   || rsv->state == UWB_RSV_STATE_O_MOVE_COMBINING
-                   || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING)
-                       sframes = 1;
-               if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED)
-                       sframes = 0;
-
-       }
-
-       if (sframes > 0) {
-               /*
-                * Add an additional 2 superframes to account for the
-                * time to send the SET DRP IE command.
-                */
-               unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US;
-               mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us));
-       } else
-               del_timer(&rsv->timer);
-}
-
-/*
- * Update a reservations state, and schedule an update of the
- * transmitted DRP IEs.
- */
-static void uwb_rsv_state_update(struct uwb_rsv *rsv,
-                                enum uwb_rsv_state new_state)
-{
-       rsv->state = new_state;
-       rsv->ie_valid = false;
-
-       uwb_rsv_dump("SU", rsv);
-
-       uwb_rsv_stroke_timer(rsv);
-       uwb_rsv_sched_update(rsv->rc);
-}
-
-static void uwb_rsv_callback(struct uwb_rsv *rsv)
-{
-       if (rsv->callback)
-               rsv->callback(rsv);
-}
-
-void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state)
-{
-       struct uwb_rsv_move *mv = &rsv->mv;
-
-       if (rsv->state == new_state) {
-               switch (rsv->state) {
-               case UWB_RSV_STATE_O_ESTABLISHED:
-               case UWB_RSV_STATE_O_MOVE_EXPANDING:
-               case UWB_RSV_STATE_O_MOVE_COMBINING:
-               case UWB_RSV_STATE_O_MOVE_REDUCING:
-               case UWB_RSV_STATE_T_ACCEPTED:
-               case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
-               case UWB_RSV_STATE_T_RESIZED:
-               case UWB_RSV_STATE_NONE:
-                       uwb_rsv_stroke_timer(rsv);
-                       break;
-               default:
-                       /* Expecting a state transition so leave timer
-                          as-is. */
-                       break;
-               }
-               return;
-       }
-
-       uwb_rsv_dump("SC", rsv);
-
-       switch (new_state) {
-       case UWB_RSV_STATE_NONE:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE);
-               uwb_rsv_remove(rsv);
-               uwb_rsv_callback(rsv);
-               break;
-       case UWB_RSV_STATE_O_INITIATED:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED);
-               break;
-       case UWB_RSV_STATE_O_PENDING:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING);
-               break;
-       case UWB_RSV_STATE_O_MODIFIED:
-               /* in the companion there are the MASes to drop */
-               bitmap_andnot(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MODIFIED);
-               break;
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               if (rsv->state == UWB_RSV_STATE_O_MODIFIED
-                   || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING) {
-                       uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
-                       rsv->needs_release_companion_mas = false;
-               }
-               uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-               uwb_rsv_callback(rsv);
-               break;
-       case UWB_RSV_STATE_O_MOVE_EXPANDING:
-               rsv->needs_release_companion_mas = true;
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
-               break;
-       case UWB_RSV_STATE_O_MOVE_COMBINING:
-               rsv->needs_release_companion_mas = false;
-               uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas);
-               bitmap_or(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS);
-               rsv->mas.safe   += mv->companion_mas.safe;
-               rsv->mas.unsafe += mv->companion_mas.unsafe;
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
-               break;
-       case UWB_RSV_STATE_O_MOVE_REDUCING:
-               bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS);
-               rsv->needs_release_companion_mas = true;
-               rsv->mas.safe   = mv->final_mas.safe;
-               rsv->mas.unsafe = mv->final_mas.unsafe;
-               bitmap_copy(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS);
-               bitmap_copy(rsv->mas.unsafe_bm, mv->final_mas.unsafe_bm, UWB_NUM_MAS);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
-               break;
-       case UWB_RSV_STATE_T_ACCEPTED:
-       case UWB_RSV_STATE_T_RESIZED:
-               rsv->needs_release_companion_mas = false;
-               uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED);
-               uwb_rsv_callback(rsv);
-               break;
-       case UWB_RSV_STATE_T_DENIED:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED);
-               break;
-       case UWB_RSV_STATE_T_CONFLICT:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_CONFLICT);
-               break;
-       case UWB_RSV_STATE_T_PENDING:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_PENDING);
-               break;
-       case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
-               rsv->needs_release_companion_mas = true;
-               uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
-               break;
-       default:
-               dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n",
-                       uwb_rsv_state_str(new_state), new_state);
-       }
-}
-
-static void uwb_rsv_handle_timeout_work(struct work_struct *work)
-{
-       struct uwb_rsv *rsv = container_of(work, struct uwb_rsv,
-                                          handle_timeout_work);
-       struct uwb_rc *rc = rsv->rc;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       uwb_rsv_dump("TO", rsv);
-
-       switch (rsv->state) {
-       case UWB_RSV_STATE_O_INITIATED:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-                       goto unlock;
-               }
-               break;
-       case UWB_RSV_STATE_O_MOVE_EXPANDING:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
-                       goto unlock;
-               }
-               break;
-       case UWB_RSV_STATE_O_MOVE_COMBINING:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
-                       goto unlock;
-               }
-               break;
-       case UWB_RSV_STATE_O_MOVE_REDUCING:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-                       goto unlock;
-               }
-               break;
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               if (rsv->is_multicast)
-                       goto unlock;
-               break;
-       case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
-               /*
-                * The time out could be for the main or of the
-                * companion DRP, assume it's for the companion and
-                * drop that first.  A further time out is required to
-                * drop the main.
-                */
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
-               uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
-               goto unlock;
-       case UWB_RSV_STATE_NONE:
-               goto unlock;
-       default:
-               break;
-       }
-
-       uwb_rsv_remove(rsv);
-
-unlock:
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
-{
-       struct uwb_rsv *rsv;
-
-       rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL);
-       if (!rsv)
-               return NULL;
-
-       INIT_LIST_HEAD(&rsv->rc_node);
-       INIT_LIST_HEAD(&rsv->pal_node);
-       kref_init(&rsv->kref);
-       timer_setup(&rsv->timer, uwb_rsv_timer, 0);
-
-       rsv->rc = rc;
-       INIT_WORK(&rsv->handle_timeout_work, uwb_rsv_handle_timeout_work);
-
-       return rsv;
-}
-
-/**
- * uwb_rsv_create - allocate and initialize a UWB reservation structure
- * @rc: the radio controller
- * @cb: callback to use when the reservation completes or terminates
- * @pal_priv: data private to the PAL to be passed in the callback
- *
- * The callback is called when the state of the reservation changes from:
- *
- *   - pending to accepted
- *   - pending to denined
- *   - accepted to terminated
- *   - pending to terminated
- */
-struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv)
-{
-       struct uwb_rsv *rsv;
-
-       rsv = uwb_rsv_alloc(rc);
-       if (!rsv)
-               return NULL;
-
-       rsv->callback = cb;
-       rsv->pal_priv = pal_priv;
-
-       return rsv;
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_create);
-
-void uwb_rsv_remove(struct uwb_rsv *rsv)
-{
-       uwb_rsv_dump("RM", rsv);
-
-       if (rsv->state != UWB_RSV_STATE_NONE)
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-
-       if (rsv->needs_release_companion_mas)
-               uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
-       uwb_drp_avail_release(rsv->rc, &rsv->mas);
-
-       if (uwb_rsv_is_owner(rsv))
-               uwb_rsv_put_stream(rsv);
-
-       uwb_dev_put(rsv->owner);
-       if (rsv->target.type == UWB_RSV_TARGET_DEV)
-               uwb_dev_put(rsv->target.dev);
-
-       list_del_init(&rsv->rc_node);
-       uwb_rsv_put(rsv);
-}
-
-/**
- * uwb_rsv_destroy - free a UWB reservation structure
- * @rsv: the reservation to free
- *
- * The reservation must already be terminated.
- */
-void uwb_rsv_destroy(struct uwb_rsv *rsv)
-{
-       uwb_rsv_put(rsv);
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
-
-/**
- * usb_rsv_establish - start a reservation establishment
- * @rsv: the reservation
- *
- * The PAL should fill in @rsv's owner, target, type, max_mas,
- * min_mas, max_interval and is_multicast fields.  If the target is a
- * uwb_dev it must be referenced.
- *
- * The reservation's callback will be called when the reservation is
- * accepted, denied or times out.
- */
-int uwb_rsv_establish(struct uwb_rsv *rsv)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct uwb_mas_bm available;
-       struct device *dev = &rc->uwb_dev.dev;
-       int ret;
-
-       mutex_lock(&rc->rsvs_mutex);
-       ret = uwb_rsv_get_stream(rsv);
-       if (ret) {
-               dev_err(dev, "%s: uwb_rsv_get_stream failed: %d\n",
-                       __func__, ret);
-               goto out;
-       }
-
-       rsv->tiebreaker = prandom_u32() & 1;
-       /* get available mas bitmap */
-       uwb_drp_available(rc, &available);
-
-       ret = uwb_rsv_find_best_allocation(rsv, &available, &rsv->mas);
-       if (ret == UWB_RSV_ALLOC_NOT_FOUND) {
-               ret = -EBUSY;
-               uwb_rsv_put_stream(rsv);
-               dev_err(dev, "%s: uwb_rsv_find_best_allocation failed: %d\n",
-                       __func__, ret);
-               goto out;
-       }
-
-       ret = uwb_drp_avail_reserve_pending(rc, &rsv->mas);
-       if (ret != 0) {
-               uwb_rsv_put_stream(rsv);
-               dev_err(dev, "%s: uwb_drp_avail_reserve_pending failed: %d\n",
-                       __func__, ret);
-               goto out;
-       }
-
-       uwb_rsv_get(rsv);
-       list_add_tail(&rsv->rc_node, &rc->reservations);
-       rsv->owner = &rc->uwb_dev;
-       uwb_dev_get(rsv->owner);
-       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED);
-out:
-       mutex_unlock(&rc->rsvs_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_establish);
-
-/**
- * uwb_rsv_modify - modify an already established reservation
- * @rsv: the reservation to modify
- * @max_mas: new maximum MAS to reserve
- * @min_mas: new minimum MAS to reserve
- * @max_interval: new max_interval to use
- *
- * FIXME: implement this once there are PALs that use it.
- */
-int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int max_interval)
-{
-       return -ENOSYS;
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_modify);
-
-/*
- * move an already established reservation (rc->rsvs_mutex must to be
- * taken when tis function is called)
- */
-int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rsv_move *mv;
-       int ret = 0;
-
-       if (!bow->can_reserve_extra_mases)
-               return -EBUSY;
-
-       mv = &rsv->mv;
-
-       if (uwb_rsv_find_best_allocation(rsv, available, &mv->final_mas) == UWB_RSV_ALLOC_FOUND) {
-
-               if (!bitmap_equal(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS)) {
-                       /* We want to move the reservation */
-                       bitmap_andnot(mv->companion_mas.bm, mv->final_mas.bm, rsv->mas.bm, UWB_NUM_MAS);
-                       uwb_drp_avail_reserve_pending(rc, &mv->companion_mas);
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
-               }
-       } else {
-               dev_dbg(dev, "new allocation not found\n");
-       }
-
-       return ret;
-}
-
-/* It will try to move every reservation in state O_ESTABLISHED giving
- * to the MAS allocator algorithm an availability that is the real one
- * plus the allocation already established from the reservation. */
-void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc)
-{
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       struct uwb_rsv *rsv;
-       struct uwb_mas_bm mas;
-
-       if (!bow->can_reserve_extra_mases)
-               return;
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED ||
-                   rsv->state == UWB_RSV_STATE_O_TO_BE_MOVED) {
-                       uwb_drp_available(rc, &mas);
-                       bitmap_or(mas.bm, mas.bm, rsv->mas.bm, UWB_NUM_MAS);
-                       uwb_rsv_try_move(rsv, &mas);
-               }
-       }
-
-}
-
-/**
- * uwb_rsv_terminate - terminate an established reservation
- * @rsv: the reservation to terminate
- *
- * A reservation is terminated by removing the DRP IE from the beacon,
- * the other end will consider the reservation to be terminated when
- * it does not see the DRP IE for at least mMaxLostBeacons.
- *
- * If applicable, the reference to the target uwb_dev will be released.
- */
-void uwb_rsv_terminate(struct uwb_rsv *rsv)
-{
-       struct uwb_rc *rc = rsv->rc;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       if (rsv->state != UWB_RSV_STATE_NONE)
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-
-       mutex_unlock(&rc->rsvs_mutex);
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_terminate);
-
-/**
- * uwb_rsv_accept - accept a new reservation from a peer
- * @rsv:      the reservation
- * @cb:       call back for reservation changes
- * @pal_priv: data to be passed in the above call back
- *
- * Reservation requests from peers are denied unless a PAL accepts it
- * by calling this function.
- *
- * The PAL call uwb_rsv_destroy() for all accepted reservations before
- * calling uwb_pal_unregister().
- */
-void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv)
-{
-       uwb_rsv_get(rsv);
-
-       rsv->callback = cb;
-       rsv->pal_priv = pal_priv;
-       rsv->state    = UWB_RSV_STATE_T_ACCEPTED;
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_accept);
-
-/*
- * Is a received DRP IE for this reservation?
- */
-static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src,
-                         struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_dev_addr *rsv_src;
-       int stream;
-
-       stream = uwb_ie_drp_stream_index(drp_ie);
-
-       if (rsv->stream != stream)
-               return false;
-
-       switch (rsv->target.type) {
-       case UWB_RSV_TARGET_DEVADDR:
-               return rsv->stream == stream;
-       case UWB_RSV_TARGET_DEV:
-               if (uwb_ie_drp_owner(drp_ie))
-                       rsv_src = &rsv->owner->dev_addr;
-               else
-                       rsv_src = &rsv->target.dev->dev_addr;
-               return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0;
-       }
-       return false;
-}
-
-static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc,
-                                         struct uwb_dev *src,
-                                         struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_rsv *rsv;
-       struct uwb_pal *pal;
-       enum uwb_rsv_state state;
-
-       rsv = uwb_rsv_alloc(rc);
-       if (!rsv)
-               return NULL;
-
-       rsv->rc          = rc;
-       rsv->owner       = src;
-       uwb_dev_get(rsv->owner);
-       rsv->target.type = UWB_RSV_TARGET_DEV;
-       rsv->target.dev  = &rc->uwb_dev;
-       uwb_dev_get(&rc->uwb_dev);
-       rsv->type        = uwb_ie_drp_type(drp_ie);
-       rsv->stream      = uwb_ie_drp_stream_index(drp_ie);
-       uwb_drp_ie_to_bm(&rsv->mas, drp_ie);
-
-       /*
-        * See if any PALs are interested in this reservation. If not,
-        * deny the request.
-        */
-       rsv->state = UWB_RSV_STATE_T_DENIED;
-       mutex_lock(&rc->uwb_dev.mutex);
-       list_for_each_entry(pal, &rc->pals, node) {
-               if (pal->new_rsv)
-                       pal->new_rsv(pal, rsv);
-               if (rsv->state == UWB_RSV_STATE_T_ACCEPTED)
-                       break;
-       }
-       mutex_unlock(&rc->uwb_dev.mutex);
-
-       list_add_tail(&rsv->rc_node, &rc->reservations);
-       state = rsv->state;
-       rsv->state = UWB_RSV_STATE_NONE;
-
-       /* FIXME: do something sensible here */
-       if (state == UWB_RSV_STATE_T_ACCEPTED
-           && uwb_drp_avail_reserve_pending(rc, &rsv->mas) == -EBUSY) {
-               /* FIXME: do something sensible here */
-       } else {
-               uwb_rsv_set_state(rsv, state);
-       }
-
-       return rsv;
-}
-
-/**
- * uwb_rsv_get_usable_mas - get the bitmap of the usable MAS of a reservations
- * @rsv: the reservation.
- * @mas: returns the available MAS.
- *
- * The usable MAS of a reservation may be less than the negotiated MAS
- * if alien BPs are present.
- */
-void uwb_rsv_get_usable_mas(struct uwb_rsv *rsv, struct uwb_mas_bm *mas)
-{
-       bitmap_zero(mas->bm, UWB_NUM_MAS);
-       bitmap_andnot(mas->bm, rsv->mas.bm, rsv->rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_get_usable_mas);
-
-/**
- * uwb_rsv_find - find a reservation for a received DRP IE.
- * @rc: the radio controller
- * @src: source of the DRP IE
- * @drp_ie: the DRP IE
- *
- * If the reservation cannot be found and the DRP IE is from a peer
- * attempting to establish a new reservation, create a new reservation
- * and add it to the list.
- */
-struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
-                            struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_rsv *rsv;
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (uwb_rsv_match(rsv, src, drp_ie))
-                       return rsv;
-       }
-
-       if (uwb_ie_drp_owner(drp_ie))
-               return uwb_rsv_new_target(rc, src, drp_ie);
-
-       return NULL;
-}
-
-/*
- * Go through all the reservations and check for timeouts and (if
- * necessary) update their DRP IEs.
- *
- * FIXME: look at building the SET_DRP_IE command here rather than
- * having to rescan the list in uwb_rc_send_all_drp_ie().
- */
-static bool uwb_rsv_update_all(struct uwb_rc *rc)
-{
-       struct uwb_rsv *rsv, *t;
-       bool ie_updated = false;
-
-       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
-               if (!rsv->ie_valid) {
-                       uwb_drp_ie_update(rsv);
-                       ie_updated = true;
-               }
-       }
-
-       return ie_updated;
-}
-
-void uwb_rsv_queue_update(struct uwb_rc *rc)
-{
-       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
-
-       queue_delayed_work(rc->rsv_workq, &rc->rsv_update_work, usecs_to_jiffies(delay_us));
-}
-
-/**
- * uwb_rsv_sched_update - schedule an update of the DRP IEs
- * @rc: the radio controller.
- *
- * To improve performance and ensure correctness with [ECMA-368] the
- * number of SET-DRP-IE commands that are done are limited.
- *
- * DRP IEs update come from two sources: DRP events from the hardware
- * which all occur at the beginning of the superframe ('syncronous'
- * events) and reservation establishment/termination requests from
- * PALs or timers ('asynchronous' events).
- *
- * A delayed work ensures that all the synchronous events result in
- * one SET-DRP-IE command.
- *
- * Additional logic (the set_drp_ie_pending and rsv_updated_postponed
- * flags) will prevent an asynchrous event starting a SET-DRP-IE
- * command if one is currently awaiting a response.
- *
- * FIXME: this does leave a window where an asynchrous event can delay
- * the SET-DRP-IE for a synchronous event by one superframe.
- */
-void uwb_rsv_sched_update(struct uwb_rc *rc)
-{
-       spin_lock_irq(&rc->rsvs_lock);
-       if (!delayed_work_pending(&rc->rsv_update_work)) {
-               if (rc->set_drp_ie_pending > 0) {
-                       rc->set_drp_ie_pending++;
-                       goto unlock;
-               }
-               uwb_rsv_queue_update(rc);
-       }
-unlock:
-       spin_unlock_irq(&rc->rsvs_lock);
-}
-
-/*
- * Update DRP IEs and, if necessary, the DRP Availability IE and send
- * the updated IEs to the radio controller.
- */
-static void uwb_rsv_update_work(struct work_struct *work)
-{
-       struct uwb_rc *rc = container_of(work, struct uwb_rc,
-                                        rsv_update_work.work);
-       bool ie_updated;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       ie_updated = uwb_rsv_update_all(rc);
-
-       if (!rc->drp_avail.ie_valid) {
-               uwb_drp_avail_ie_update(rc);
-               ie_updated = true;
-       }
-
-       if (ie_updated && (rc->set_drp_ie_pending == 0))
-               uwb_rc_send_all_drp_ie(rc);
-
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-static void uwb_rsv_alien_bp_work(struct work_struct *work)
-{
-       struct uwb_rc *rc = container_of(work, struct uwb_rc,
-                                        rsv_alien_bp_work.work);
-       struct uwb_rsv *rsv;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->type != UWB_DRP_TYPE_ALIEN_BP) {
-                       uwb_rsv_callback(rsv);
-               }
-       }
-
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-static void uwb_rsv_timer(struct timer_list *t)
-{
-       struct uwb_rsv *rsv = from_timer(rsv, t, timer);
-
-       queue_work(rsv->rc->rsv_workq, &rsv->handle_timeout_work);
-}
-
-/**
- * uwb_rsv_remove_all - remove all reservations
- * @rc: the radio controller
- *
- * A DRP IE update is not done.
- */
-void uwb_rsv_remove_all(struct uwb_rc *rc)
-{
-       struct uwb_rsv *rsv, *t;
-
-       mutex_lock(&rc->rsvs_mutex);
-       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
-               if (rsv->state != UWB_RSV_STATE_NONE)
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-               del_timer_sync(&rsv->timer);
-       }
-       /* Cancel any postponed update. */
-       rc->set_drp_ie_pending = 0;
-       mutex_unlock(&rc->rsvs_mutex);
-
-       cancel_delayed_work_sync(&rc->rsv_update_work);
-       flush_workqueue(rc->rsv_workq);
-
-       mutex_lock(&rc->rsvs_mutex);
-       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
-               uwb_rsv_remove(rsv);
-       }
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-void uwb_rsv_init(struct uwb_rc *rc)
-{
-       INIT_LIST_HEAD(&rc->reservations);
-       INIT_LIST_HEAD(&rc->cnflt_alien_list);
-       mutex_init(&rc->rsvs_mutex);
-       spin_lock_init(&rc->rsvs_lock);
-       INIT_DELAYED_WORK(&rc->rsv_update_work, uwb_rsv_update_work);
-       INIT_DELAYED_WORK(&rc->rsv_alien_bp_work, uwb_rsv_alien_bp_work);
-       rc->bow.can_reserve_extra_mases = true;
-       rc->bow.total_expired = 0;
-       rc->bow.window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
-       timer_setup(&rc->bow.timer, uwb_rsv_backoff_win_timer, 0);
-
-       bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS);
-}
-
-int uwb_rsv_setup(struct uwb_rc *rc)
-{
-       char name[16];
-
-       snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev));
-       rc->rsv_workq = create_singlethread_workqueue(name);
-       if (rc->rsv_workq == NULL)
-               return -ENOMEM;
-
-       return 0;
-}
-
-void uwb_rsv_cleanup(struct uwb_rc *rc)
-{
-       uwb_rsv_remove_all(rc);
-       destroy_workqueue(rc->rsv_workq);
-}
diff --git a/drivers/staging/uwb/scan.c b/drivers/staging/uwb/scan.c
deleted file mode 100644 (file)
index ffc3f45..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Scanning management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- * FIXME: there are issues here on how BEACON and SCAN on USB RCI deal
- *        with each other. Currently seems that START_BEACON while
- *        SCAN_ONLY will cancel the scan, so we need to update the
- *        state here. Clarification request sent by email on
- *        10/05/2005.
- *        10/28/2005 No clear answer heard--maybe we'll hack the API
- *                   so that when we start beaconing, if the HC is
- *                   scanning in a mode not compatible with beaconing
- *                   we just fail.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include "uwb-internal.h"
-
-
-/**
- * Start/stop scanning in a radio controller
- *
- * @rc:      UWB Radio Controller
- * @channel: Channel to scan; encodings in WUSB1.0[Table 5.12]
- * @type:    Type of scanning to do.
- * @bpst_offset: value at which to start scanning (if type ==
- *                UWB_SCAN_ONLY_STARTTIME)
- * @returns: 0 if ok, < 0 errno code on error
- *
- * We put the command on kmalloc'ed memory as some arches cannot do
- * USB from the stack. The reply event is copied from an stage buffer,
- * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
- */
-int uwb_rc_scan(struct uwb_rc *rc,
-               unsigned channel, enum uwb_scan_type type,
-               unsigned bpst_offset)
-{
-       int result;
-       struct uwb_rc_cmd_scan *cmd;
-       struct uwb_rc_evt_confirm reply;
-
-       result = -ENOMEM;
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               goto error_kzalloc;
-       mutex_lock(&rc->uwb_dev.mutex);
-       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SCAN);
-       cmd->bChannelNumber = channel;
-       cmd->bScanState = type;
-       cmd->wStartTime = cpu_to_le16(bpst_offset);
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_SCAN;
-       result = uwb_rc_cmd(rc, "SCAN", &cmd->rccb, sizeof(*cmd),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "SCAN: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-               goto error_cmd;
-       }
-       rc->scanning = channel;
-       rc->scan_type = type;
-error_cmd:
-       mutex_unlock(&rc->uwb_dev.mutex);
-       kfree(cmd);
-error_kzalloc:
-       return result;
-}
-
-/*
- * Print scanning state
- */
-static ssize_t uwb_rc_scan_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_rc *rc = uwb_dev->rc;
-       ssize_t result;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       result = sprintf(buf, "%d %d\n", rc->scanning, rc->scan_type);
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return result;
-}
-
-/*
- *
- */
-static ssize_t uwb_rc_scan_store(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t size)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_rc *rc = uwb_dev->rc;
-       unsigned channel;
-       unsigned type;
-       unsigned bpst_offset = 0;
-       ssize_t result = -EINVAL;
-
-       result = sscanf(buf, "%u %u %u\n", &channel, &type, &bpst_offset);
-       if (result >= 2 && type < UWB_SCAN_TOP)
-               result = uwb_rc_scan(rc, channel, type, bpst_offset);
-
-       return result < 0 ? result : size;
-}
-
-/** Radio Control sysfs interface (declaration) */
-DEVICE_ATTR(scan, S_IRUGO | S_IWUSR, uwb_rc_scan_show, uwb_rc_scan_store);
diff --git a/drivers/staging/uwb/umc-bus.c b/drivers/staging/uwb/umc-bus.c
deleted file mode 100644 (file)
index 8b931f6..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Bus for UWB Multi-interface Controller capabilities.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/sysfs.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include "include/umc.h"
-
-static int umc_bus_pre_reset_helper(struct device *dev, void *data)
-{
-       int ret = 0;
-
-       if (dev->driver) {
-               struct umc_dev *umc = to_umc_dev(dev);
-               struct umc_driver *umc_drv = to_umc_driver(dev->driver);
-
-               if (umc_drv->pre_reset)
-                       ret = umc_drv->pre_reset(umc);
-               else
-                       device_release_driver(dev);
-       }
-       return ret;
-}
-
-static int umc_bus_post_reset_helper(struct device *dev, void *data)
-{
-       int ret = 0;
-
-       if (dev->driver) {
-               struct umc_dev *umc = to_umc_dev(dev);
-               struct umc_driver *umc_drv = to_umc_driver(dev->driver);
-
-               if (umc_drv->post_reset)
-                       ret = umc_drv->post_reset(umc);
-       } else
-               ret = device_attach(dev);
-
-       return ret;
-}
-
-/**
- * umc_controller_reset - reset the whole UMC controller
- * @umc: the UMC device for the radio controller.
- *
- * Drivers or all capabilities of the controller will have their
- * pre_reset methods called or be unbound from their device.  Then all
- * post_reset methods will be called or the drivers will be rebound.
- *
- * Radio controllers must provide pre_reset and post_reset methods and
- * reset the hardware in their start method.
- *
- * If this is called while a probe() or remove() is in progress it
- * will return -EAGAIN and not perform the reset.
- */
-int umc_controller_reset(struct umc_dev *umc)
-{
-       struct device *parent = umc->dev.parent;
-       int ret = 0;
-
-       if (!device_trylock(parent))
-               return -EAGAIN;
-       ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper);
-       if (ret >= 0)
-               ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper);
-       device_unlock(parent);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(umc_controller_reset);
-
-/**
- * umc_match_pci_id - match a UMC driver to a UMC device's parent PCI device.
- * @umc_drv: umc driver with match_data pointing to a zero-terminated
- * table of pci_device_id's.
- * @umc: umc device whose parent is to be matched.
- */
-int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc)
-{
-       const struct pci_device_id *id_table = umc_drv->match_data;
-       struct pci_dev *pci;
-
-       if (!dev_is_pci(umc->dev.parent))
-               return 0;
-
-       pci = to_pci_dev(umc->dev.parent);
-       return pci_match_id(id_table, pci) != NULL;
-}
-EXPORT_SYMBOL_GPL(umc_match_pci_id);
-
-static int umc_bus_rescan_helper(struct device *dev, void *data)
-{
-       int ret = 0;
-
-       if (!dev->driver)
-               ret = device_attach(dev);
-
-       return ret;
-}
-
-static void umc_bus_rescan(struct device *parent)
-{
-       int err;
-
-       /*
-        * We can't use bus_rescan_devices() here as it deadlocks when
-        * it tries to retake the dev->parent semaphore.
-        */
-       err = device_for_each_child(parent, NULL, umc_bus_rescan_helper);
-       if (err < 0)
-               printk(KERN_WARNING "%s: rescan of bus failed: %d\n",
-                      KBUILD_MODNAME, err);
-}
-
-static int umc_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct umc_dev *umc = to_umc_dev(dev);
-       struct umc_driver *umc_driver = to_umc_driver(drv);
-
-       if (umc->cap_id == umc_driver->cap_id) {
-               if (umc_driver->match)
-                       return umc_driver->match(umc_driver, umc);
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-static int umc_device_probe(struct device *dev)
-{
-       struct umc_dev *umc;
-       struct umc_driver *umc_driver;
-       int err;
-
-       umc_driver = to_umc_driver(dev->driver);
-       umc = to_umc_dev(dev);
-
-       get_device(dev);
-       err = umc_driver->probe(umc);
-       if (err)
-               put_device(dev);
-       else
-               umc_bus_rescan(dev->parent);
-
-       return err;
-}
-
-static int umc_device_remove(struct device *dev)
-{
-       struct umc_dev *umc;
-       struct umc_driver *umc_driver;
-
-       umc_driver = to_umc_driver(dev->driver);
-       umc = to_umc_dev(dev);
-
-       umc_driver->remove(umc);
-       put_device(dev);
-       return 0;
-}
-
-static ssize_t capability_id_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct umc_dev *umc = to_umc_dev(dev);
-
-       return sprintf(buf, "0x%02x\n", umc->cap_id);
-}
-static DEVICE_ATTR_RO(capability_id);
-
-static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct umc_dev *umc = to_umc_dev(dev);
-
-       return sprintf(buf, "0x%04x\n", umc->version);
-}
-static DEVICE_ATTR_RO(version);
-
-static struct attribute *umc_dev_attrs[] = {
-       &dev_attr_capability_id.attr,
-       &dev_attr_version.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(umc_dev);
-
-struct bus_type umc_bus_type = {
-       .name           = "umc",
-       .match          = umc_bus_match,
-       .probe          = umc_device_probe,
-       .remove         = umc_device_remove,
-       .dev_groups     = umc_dev_groups,
-};
-EXPORT_SYMBOL_GPL(umc_bus_type);
-
-static int __init umc_bus_init(void)
-{
-       return bus_register(&umc_bus_type);
-}
-module_init(umc_bus_init);
-
-static void __exit umc_bus_exit(void)
-{
-       bus_unregister(&umc_bus_type);
-}
-module_exit(umc_bus_exit);
-
-MODULE_DESCRIPTION("UWB Multi-interface Controller capability bus");
-MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/umc-dev.c b/drivers/staging/uwb/umc-dev.c
deleted file mode 100644 (file)
index 0c71caa..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB Multi-interface Controller device management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include "include/umc.h"
-
-static void umc_device_release(struct device *dev)
-{
-       struct umc_dev *umc = to_umc_dev(dev);
-
-       kfree(umc);
-}
-
-/**
- * umc_device_create - allocate a child UMC device
- * @parent: parent of the new UMC device.
- * @n:      index of the new device.
- *
- * The new UMC device will have a bus ID of the parent with '-n'
- * appended.
- */
-struct umc_dev *umc_device_create(struct device *parent, int n)
-{
-       struct umc_dev *umc;
-
-       umc = kzalloc(sizeof(struct umc_dev), GFP_KERNEL);
-       if (umc) {
-               dev_set_name(&umc->dev, "%s-%d", dev_name(parent), n);
-               umc->dev.parent  = parent;
-               umc->dev.bus     = &umc_bus_type;
-               umc->dev.release = umc_device_release;
-
-               umc->dev.dma_mask = parent->dma_mask;
-       }
-       return umc;
-}
-EXPORT_SYMBOL_GPL(umc_device_create);
-
-/**
- * umc_device_register - register a UMC device
- * @umc: pointer to the UMC device
- *
- * The memory resource for the UMC device is acquired and the device
- * registered with the system.
- */
-int umc_device_register(struct umc_dev *umc)
-{
-       int err;
-
-       err = request_resource(umc->resource.parent, &umc->resource);
-       if (err < 0) {
-               dev_err(&umc->dev, "can't allocate resource range %pR: %d\n",
-                       &umc->resource, err);
-               goto error_request_resource;
-       }
-
-       err = device_register(&umc->dev);
-       if (err < 0)
-               goto error_device_register;
-       return 0;
-
-error_device_register:
-       put_device(&umc->dev);
-       release_resource(&umc->resource);
-error_request_resource:
-       return err;
-}
-EXPORT_SYMBOL_GPL(umc_device_register);
-
-/**
- * umc_device_unregister - unregister a UMC device
- * @umc: pointer to the UMC device
- *
- * First we unregister the device, make sure the driver can do it's
- * resource release thing and then we try to release any left over
- * resources. We take a ref to the device, to make sure it doesn't
- * disappear under our feet.
- */
-void umc_device_unregister(struct umc_dev *umc)
-{
-       struct device *dev;
-       if (!umc)
-               return;
-       dev = get_device(&umc->dev);
-       device_unregister(&umc->dev);
-       release_resource(&umc->resource);
-       put_device(dev);
-}
-EXPORT_SYMBOL_GPL(umc_device_unregister);
diff --git a/drivers/staging/uwb/umc-drv.c b/drivers/staging/uwb/umc-drv.c
deleted file mode 100644 (file)
index ed3bd22..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB Multi-interface Controller driver management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include "include/umc.h"
-
-int __umc_driver_register(struct umc_driver *umc_drv, struct module *module,
-                         const char *mod_name)
-{
-       umc_drv->driver.name     = umc_drv->name;
-       umc_drv->driver.owner    = module;
-       umc_drv->driver.mod_name = mod_name;
-       umc_drv->driver.bus      = &umc_bus_type;
-
-       return driver_register(&umc_drv->driver);
-}
-EXPORT_SYMBOL_GPL(__umc_driver_register);
-
-/**
- * umc_driver_register - unregister a UMC capabiltity driver.
- * @umc_drv:  pointer to the driver.
- */
-void umc_driver_unregister(struct umc_driver *umc_drv)
-{
-       driver_unregister(&umc_drv->driver);
-}
-EXPORT_SYMBOL_GPL(umc_driver_unregister);
diff --git a/drivers/staging/uwb/uwb-debug.c b/drivers/staging/uwb/uwb-debug.c
deleted file mode 100644 (file)
index dd14df2..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Debug support
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * FIXME: doc
- */
-
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-#include <linux/device.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/seq_file.h>
-
-#include "include/debug-cmd.h"
-#include "uwb-internal.h"
-
-/*
- * Debug interface
- *
- * Per radio controller debugfs files (in uwb/uwbN/):
- *
- * command: Flexible command interface (see <linux/uwb/debug-cmd.h>).
- *
- * reservations: information on reservations.
- *
- * accept: Set to true (Y or 1) to accept reservation requests from
- * peers.
- *
- * drp_avail: DRP availability information.
- */
-
-struct uwb_dbg {
-       struct uwb_pal pal;
-
-       bool accept;
-       struct list_head rsvs;
-
-       struct dentry *root_d;
-       struct dentry *command_f;
-       struct dentry *reservations_f;
-       struct dentry *accept_f;
-       struct dentry *drp_avail_f;
-       spinlock_t list_lock;
-};
-
-static struct dentry *root_dir;
-
-static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
-{
-       struct uwb_dbg *dbg = rsv->pal_priv;
-
-       uwb_rsv_dump("debug", rsv);
-
-       if (rsv->state == UWB_RSV_STATE_NONE) {
-               spin_lock(&dbg->list_lock);
-               list_del(&rsv->pal_node);
-               spin_unlock(&dbg->list_lock);
-               uwb_rsv_destroy(rsv);
-       }
-}
-
-static int cmd_rsv_establish(struct uwb_rc *rc,
-                            struct uwb_dbg_cmd_rsv_establish *cmd)
-{
-       struct uwb_mac_addr macaddr;
-       struct uwb_rsv *rsv;
-       struct uwb_dev *target;
-       int ret;
-
-       memcpy(&macaddr, cmd->target, sizeof(macaddr));
-       target = uwb_dev_get_by_macaddr(rc, &macaddr);
-       if (target == NULL)
-               return -ENODEV;
-
-       rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg);
-       if (rsv == NULL) {
-               uwb_dev_put(target);
-               return -ENOMEM;
-       }
-
-       rsv->target.type  = UWB_RSV_TARGET_DEV;
-       rsv->target.dev   = target;
-       rsv->type         = cmd->type;
-       rsv->max_mas      = cmd->max_mas;
-       rsv->min_mas      = cmd->min_mas;
-       rsv->max_interval = cmd->max_interval;
-
-       ret = uwb_rsv_establish(rsv);
-       if (ret)
-               uwb_rsv_destroy(rsv);
-       else {
-               spin_lock(&(rc->dbg)->list_lock);
-               list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
-               spin_unlock(&(rc->dbg)->list_lock);
-       }
-       return ret;
-}
-
-static int cmd_rsv_terminate(struct uwb_rc *rc,
-                            struct uwb_dbg_cmd_rsv_terminate *cmd)
-{
-       struct uwb_rsv *rsv, *found = NULL;
-       int i = 0;
-
-       spin_lock(&(rc->dbg)->list_lock);
-
-       list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
-               if (i == cmd->index) {
-                       found = rsv;
-                       uwb_rsv_get(found);
-                       break;
-               }
-               i++;
-       }
-
-       spin_unlock(&(rc->dbg)->list_lock);
-
-       if (!found)
-               return -EINVAL;
-
-       uwb_rsv_terminate(found);
-       uwb_rsv_put(found);
-
-       return 0;
-}
-
-static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add)
-{
-       return uwb_rc_ie_add(rc,
-                            (const struct uwb_ie_hdr *) ie_to_add->data,
-                            ie_to_add->len);
-}
-
-static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm)
-{
-       return uwb_rc_ie_rm(rc, ie_to_rm->data[0]);
-}
-
-static ssize_t command_write(struct file *file, const char __user *buf,
-                        size_t len, loff_t *off)
-{
-       struct uwb_rc *rc = file->private_data;
-       struct uwb_dbg_cmd cmd;
-       int ret = 0;
-       
-       if (len != sizeof(struct uwb_dbg_cmd))
-               return -EINVAL;
-
-       if (copy_from_user(&cmd, buf, len) != 0)
-               return -EFAULT;
-
-       switch (cmd.type) {
-       case UWB_DBG_CMD_RSV_ESTABLISH:
-               ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
-               break;
-       case UWB_DBG_CMD_RSV_TERMINATE:
-               ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
-               break;
-       case UWB_DBG_CMD_IE_ADD:
-               ret = cmd_ie_add(rc, &cmd.ie_add);
-               break;
-       case UWB_DBG_CMD_IE_RM:
-               ret = cmd_ie_rm(rc, &cmd.ie_rm);
-               break;
-       case UWB_DBG_CMD_RADIO_START:
-               ret = uwb_radio_start(&rc->dbg->pal);
-               break;
-       case UWB_DBG_CMD_RADIO_STOP:
-               uwb_radio_stop(&rc->dbg->pal);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return ret < 0 ? ret : len;
-}
-
-static const struct file_operations command_fops = {
-       .open   = simple_open,
-       .write  = command_write,
-       .read   = NULL,
-       .llseek = no_llseek,
-       .owner  = THIS_MODULE,
-};
-
-static int reservations_show(struct seq_file *s, void *p)
-{
-       struct uwb_rc *rc = s->private;
-       struct uwb_rsv *rsv;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               struct uwb_dev_addr devaddr;
-               char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
-               bool is_owner;
-
-               uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
-               if (rsv->target.type == UWB_RSV_TARGET_DEV) {
-                       devaddr = rsv->target.dev->dev_addr;
-                       is_owner = &rc->uwb_dev == rsv->owner;
-               } else {
-                       devaddr = rsv->target.devaddr;
-                       is_owner = true;
-               }
-               uwb_dev_addr_print(target, sizeof(target), &devaddr);
-
-               seq_printf(s, "%c %s -> %s: %s\n",
-                          is_owner ? 'O' : 'T',
-                          owner, target, uwb_rsv_state_str(rsv->state));
-               seq_printf(s, "  stream: %d  type: %s\n",
-                          rsv->stream, uwb_rsv_type_str(rsv->type));
-               seq_printf(s, "  %*pb\n", UWB_NUM_MAS, rsv->mas.bm);
-       }
-
-       mutex_unlock(&rc->rsvs_mutex);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(reservations);
-
-static int drp_avail_show(struct seq_file *s, void *p)
-{
-       struct uwb_rc *rc = s->private;
-
-       seq_printf(s, "global:  %*pb\n", UWB_NUM_MAS, rc->drp_avail.global);
-       seq_printf(s, "local:   %*pb\n", UWB_NUM_MAS, rc->drp_avail.local);
-       seq_printf(s, "pending: %*pb\n", UWB_NUM_MAS, rc->drp_avail.pending);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(drp_avail);
-
-static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
-{
-       struct device *dev = &pal->rc->uwb_dev.dev;
-
-       if (channel > 0)
-               dev_info(dev, "debug: channel %d started\n", channel);
-       else
-               dev_info(dev, "debug: channel stopped\n");
-}
-
-static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
-{
-       struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
-
-       if (dbg->accept) {
-               spin_lock(&dbg->list_lock);
-               list_add_tail(&rsv->pal_node, &dbg->rsvs);
-               spin_unlock(&dbg->list_lock);
-               uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg);
-       }
-}
-
-/**
- * uwb_dbg_add_rc - add a debug interface for a radio controller
- * @rc: the radio controller
- */
-void uwb_dbg_add_rc(struct uwb_rc *rc)
-{
-       rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
-       if (rc->dbg == NULL)
-               return;
-
-       INIT_LIST_HEAD(&rc->dbg->rsvs);
-       spin_lock_init(&(rc->dbg)->list_lock);
-
-       uwb_pal_init(&rc->dbg->pal);
-       rc->dbg->pal.rc = rc;
-       rc->dbg->pal.channel_changed = uwb_dbg_channel_changed;
-       rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
-       uwb_pal_register(&rc->dbg->pal);
-
-       if (root_dir) {
-               rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
-                                                    root_dir);
-               rc->dbg->command_f = debugfs_create_file("command", 0200,
-                                                        rc->dbg->root_d, rc,
-                                                        &command_fops);
-               rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
-                                                             rc->dbg->root_d, rc,
-                                                             &reservations_fops);
-               rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
-                                                       rc->dbg->root_d,
-                                                       &rc->dbg->accept);
-               rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
-                                                          rc->dbg->root_d, rc,
-                                                          &drp_avail_fops);
-       }
-}
-
-/**
- * uwb_dbg_del_rc - remove a radio controller's debug interface
- * @rc: the radio controller
- */
-void uwb_dbg_del_rc(struct uwb_rc *rc)
-{
-       struct uwb_rsv *rsv, *t;
-
-       if (rc->dbg == NULL)
-               return;
-
-       list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
-               uwb_rsv_terminate(rsv);
-       }
-
-       uwb_pal_unregister(&rc->dbg->pal);
-
-       if (root_dir) {
-               debugfs_remove(rc->dbg->drp_avail_f);
-               debugfs_remove(rc->dbg->accept_f);
-               debugfs_remove(rc->dbg->reservations_f);
-               debugfs_remove(rc->dbg->command_f);
-               debugfs_remove(rc->dbg->root_d);
-       }
-}
-
-/**
- * uwb_dbg_exit - initialize the debug interface sub-module
- */
-void uwb_dbg_init(void)
-{
-       root_dir = debugfs_create_dir("uwb", NULL);
-}
-
-/**
- * uwb_dbg_exit - clean-up the debug interface sub-module
- */
-void uwb_dbg_exit(void)
-{
-       debugfs_remove(root_dir);
-}
-
-/**
- * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL
- * @pal: The PAL.
- */
-struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-
-       if (root_dir && rc->dbg && rc->dbg->root_d && pal->name)
-               return debugfs_create_dir(pal->name, rc->dbg->root_d);
-       return NULL;
-}
diff --git a/drivers/staging/uwb/uwb-internal.h b/drivers/staging/uwb/uwb-internal.h
deleted file mode 100644 (file)
index 4c2fdac..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Ultra Wide Band
- * UWB internal API
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This contains most of the internal API for UWB. This is stuff used
- * across the stack that of course, is of no interest to the rest.
- *
- * Some parts might end up going public (like uwb_rc_*())...
- */
-
-#ifndef __UWB_INTERNAL_H__
-#define __UWB_INTERNAL_H__
-
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#include "uwb.h"
-
-struct uwb_beca_e;
-
-/* General device API */
-extern void uwb_dev_init(struct uwb_dev *uwb_dev);
-extern int __uwb_dev_offair(struct uwb_dev *, struct uwb_rc *);
-extern int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
-                      struct uwb_rc *parent_rc);
-extern void uwb_dev_rm(struct uwb_dev *uwb_dev);
-extern void uwbd_dev_onair(struct uwb_rc *, struct uwb_beca_e *);
-extern void uwbd_dev_offair(struct uwb_beca_e *);
-void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event);
-
-/* General UWB Radio Controller Internal API */
-extern struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *);
-static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc)
-{
-       uwb_dev_get(&rc->uwb_dev);
-       return rc;
-}
-
-static inline void __uwb_rc_put(struct uwb_rc *rc)
-{
-       if (rc)
-               uwb_dev_put(&rc->uwb_dev);
-}
-
-extern int uwb_rc_reset(struct uwb_rc *rc);
-extern int uwb_rc_beacon(struct uwb_rc *rc,
-                        int channel, unsigned bpst_offset);
-extern int uwb_rc_scan(struct uwb_rc *rc,
-                      unsigned channel, enum uwb_scan_type type,
-                      unsigned bpst_offset);
-extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc);
-
-void uwb_rc_ie_init(struct uwb_rc *);
-int uwb_rc_ie_setup(struct uwb_rc *);
-void uwb_rc_ie_release(struct uwb_rc *);
-int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len,
-                   char *buf, size_t size);
-int uwb_rc_set_ie(struct uwb_rc *, struct uwb_rc_cmd_set_ie *);
-
-
-extern const char *uwb_rc_strerror(unsigned code);
-
-/*
- * Time to wait for a response to an RC command.
- *
- * Some commands can take a long time to response. e.g., START_BEACON
- * may scan for several superframes before joining an existing beacon
- * group and this can take around 600 ms.
- */
-#define UWB_RC_CMD_TIMEOUT_MS 1000 /* ms */
-
-/*
- * Notification/Event Handlers
- */
-
-struct uwb_rc_neh;
-
-extern int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
-                           struct uwb_rccb *cmd, size_t cmd_size,
-                           u8 expected_type, u16 expected_event,
-                           uwb_rc_cmd_cb_f cb, void *arg);
-
-
-void uwb_rc_neh_create(struct uwb_rc *rc);
-void uwb_rc_neh_destroy(struct uwb_rc *rc);
-
-struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
-                                 u8 expected_type, u16 expected_event,
-                                 uwb_rc_cmd_cb_f cb, void *arg);
-void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
-void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
-void uwb_rc_neh_put(struct uwb_rc_neh *neh);
-
-/* Event size tables */
-extern int uwb_est_create(void);
-extern void uwb_est_destroy(void);
-
-/*
- * UWB conflicting alien reservations
- */
-struct uwb_cnflt_alien {
-       struct uwb_rc *rc;
-       struct list_head rc_node;
-       struct uwb_mas_bm mas;
-       struct timer_list timer;
-       struct work_struct cnflt_update_work;
-};
-
-enum uwb_uwb_rsv_alloc_result {
-       UWB_RSV_ALLOC_FOUND = 0,
-       UWB_RSV_ALLOC_NOT_FOUND,
-};
-
-enum uwb_rsv_mas_status {
-       UWB_RSV_MAS_NOT_AVAIL = 1,
-       UWB_RSV_MAS_SAFE,
-       UWB_RSV_MAS_UNSAFE,
-};
-
-struct uwb_rsv_col_set_info {
-       unsigned char start_col;
-       unsigned char interval;
-       unsigned char safe_mas_per_col;
-       unsigned char unsafe_mas_per_col;
-};
-
-struct uwb_rsv_col_info {
-       unsigned char max_avail_safe;
-       unsigned char max_avail_unsafe;
-       unsigned char highest_mas[UWB_MAS_PER_ZONE];
-       struct uwb_rsv_col_set_info csi;
-};
-
-struct uwb_rsv_row_info {
-       unsigned char avail[UWB_MAS_PER_ZONE];
-       unsigned char free_rows;
-       unsigned char used_rows;
-};
-
-/*
- * UWB find allocation
- */
-struct uwb_rsv_alloc_info {
-       unsigned char bm[UWB_MAS_PER_ZONE * UWB_NUM_ZONES];
-       struct uwb_rsv_col_info ci[UWB_NUM_ZONES];
-       struct uwb_rsv_row_info ri;
-       struct uwb_mas_bm *not_available;
-       struct uwb_mas_bm *result;
-       int min_mas;
-       int max_mas;
-       int max_interval;
-       int total_allocated_mases;
-       int safe_allocated_mases;
-       int unsafe_allocated_mases;
-       int interval;
-};
-
-int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv,
-                                struct uwb_mas_bm *available,
-                                struct uwb_mas_bm *result);
-void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc);
-/*
- * UWB Events & management daemon
- */
-
-/**
- * enum uwb_event_type - types of UWB management daemon events
- *
- * The UWB management daemon (uwbd) can receive two types of events:
- *   UWB_EVT_TYPE_NOTIF - notification from the radio controller.
- *   UWB_EVT_TYPE_MSG   - a simple message.
- */
-enum uwb_event_type {
-       UWB_EVT_TYPE_NOTIF,
-       UWB_EVT_TYPE_MSG,
-};
-
-/**
- * struct uwb_event_notif - an event for a radio controller notification
- * @size: Size of the buffer (ie: Guaranteed to contain at least
- *        a full 'struct uwb_rceb')
- * @rceb: Pointer to a kmalloced() event payload
- */
-struct uwb_event_notif {
-       size_t size;
-       struct uwb_rceb *rceb;
-};
-
-/**
- * enum uwb_event_message - an event for a message for asynchronous processing
- *
- * UWB_EVT_MSG_RESET - reset the radio controller and all PAL hardware.
- */
-enum uwb_event_message {
-       UWB_EVT_MSG_RESET,
-};
-
-/**
- * UWB Event
- * @rc:         Radio controller that emitted the event (referenced)
- * @ts_jiffies: Timestamp, when was it received
- * @type:       This event's type.
- */
-struct uwb_event {
-       struct list_head list_node;
-       struct uwb_rc *rc;
-       unsigned long ts_jiffies;
-       enum uwb_event_type type;
-       union {
-               struct uwb_event_notif notif;
-               enum uwb_event_message message;
-       };
-};
-
-extern void uwbd_start(struct uwb_rc *rc);
-extern void uwbd_stop(struct uwb_rc *rc);
-extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask);
-extern void uwbd_event_queue(struct uwb_event *);
-void uwbd_flush(struct uwb_rc *rc);
-
-/* UWB event handlers */
-extern int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *);
-extern int uwbd_evt_handle_rc_beacon(struct uwb_event *);
-extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *);
-extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *);
-extern int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *);
-extern int uwbd_evt_handle_rc_drp(struct uwb_event *);
-extern int uwbd_evt_handle_rc_drp_avail(struct uwb_event *);
-
-int uwbd_msg_handle_reset(struct uwb_event *evt);
-
-
-/*
- * Address management
- */
-int uwb_rc_dev_addr_assign(struct uwb_rc *rc);
-int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt);
-
-/*
- * UWB Beacon Cache
- *
- * Each beacon we received is kept in a cache--when we receive that
- * beacon consistently, that means there is a new device that we have
- * to add to the system.
- */
-
-extern unsigned long beacon_timeout_ms;
-
-/**
- * Beacon cache entry
- *
- * @jiffies_refresh: last time a beacon was  received that refreshed
- *                   this cache entry.
- * @uwb_dev: device connected to this beacon. This pointer is not
- *           safe, you need to get it with uwb_dev_try_get()
- *
- * @hits: how many time we have seen this beacon since last time we
- *        cleared it
- */
-struct uwb_beca_e {
-       struct mutex mutex;
-       struct kref refcnt;
-       struct list_head node;
-       struct uwb_mac_addr *mac_addr;
-       struct uwb_dev_addr dev_addr;
-       u8 hits;
-       unsigned long ts_jiffies;
-       struct uwb_dev *uwb_dev;
-       struct uwb_rc_evt_beacon *be;
-       struct stats lqe_stats, rssi_stats;     /* radio statistics */
-};
-struct uwb_beacon_frame;
-extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *,
-                                char *, size_t);
-
-extern void uwb_bce_kfree(struct kref *_bce);
-static inline void uwb_bce_get(struct uwb_beca_e *bce)
-{
-       kref_get(&bce->refcnt);
-}
-static inline void uwb_bce_put(struct uwb_beca_e *bce)
-{
-       kref_put(&bce->refcnt, uwb_bce_kfree);
-}
-extern void uwb_beca_purge(struct uwb_rc *rc);
-extern void uwb_beca_release(struct uwb_rc *rc);
-
-struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
-                                      const struct uwb_dev_addr *devaddr);
-struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
-                                      const struct uwb_mac_addr *macaddr);
-
-int uwb_radio_setup(struct uwb_rc *rc);
-void uwb_radio_reset_state(struct uwb_rc *rc);
-void uwb_radio_shutdown(struct uwb_rc *rc);
-int uwb_radio_force_channel(struct uwb_rc *rc, int channel);
-
-/* -- UWB Sysfs representation */
-extern struct class uwb_rc_class;
-extern struct bus_type uwb_bus_type;
-extern struct device_attribute dev_attr_mac_address;
-extern struct device_attribute dev_attr_beacon;
-extern struct device_attribute dev_attr_scan;
-
-/* -- DRP Bandwidth allocator: bandwidth allocations, reservations, DRP */
-void uwb_rsv_init(struct uwb_rc *rc);
-int uwb_rsv_setup(struct uwb_rc *rc);
-void uwb_rsv_cleanup(struct uwb_rc *rc);
-void uwb_rsv_remove_all(struct uwb_rc *rc);
-void uwb_rsv_get(struct uwb_rsv *rsv);
-void uwb_rsv_put(struct uwb_rsv *rsv);
-bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv);
-void uwb_rsv_dump(char *text, struct uwb_rsv *rsv);
-int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available);
-void uwb_rsv_backoff_win_timer(struct timer_list *t);
-void uwb_rsv_backoff_win_increment(struct uwb_rc *rc);
-int uwb_rsv_status(struct uwb_rsv *rsv);
-int uwb_rsv_companion_status(struct uwb_rsv *rsv);
-
-void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state);
-void uwb_rsv_remove(struct uwb_rsv *rsv);
-struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
-                            struct uwb_ie_drp *drp_ie);
-void uwb_rsv_sched_update(struct uwb_rc *rc);
-void uwb_rsv_queue_update(struct uwb_rc *rc);
-
-int uwb_drp_ie_update(struct uwb_rsv *rsv);
-void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie);
-
-void uwb_drp_avail_init(struct uwb_rc *rc);
-void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail);
-int  uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas);
-void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas);
-void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas);
-void uwb_drp_avail_ie_update(struct uwb_rc *rc);
-
-/* -- PAL support */
-void uwb_rc_pal_init(struct uwb_rc *rc);
-
-/* -- Misc */
-
-extern ssize_t uwb_mac_frame_hdr_print(char *, size_t,
-                                      const struct uwb_mac_frame_hdr *);
-
-/* -- Debug interface */
-void uwb_dbg_init(void);
-void uwb_dbg_exit(void);
-void uwb_dbg_add_rc(struct uwb_rc *rc);
-void uwb_dbg_del_rc(struct uwb_rc *rc);
-struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal);
-
-static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
-{
-       device_lock(&uwb_dev->dev);
-}
-
-static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev)
-{
-       device_unlock(&uwb_dev->dev);
-}
-
-#endif /* #ifndef __UWB_INTERNAL_H__ */
diff --git a/drivers/staging/uwb/uwb.h b/drivers/staging/uwb/uwb.h
deleted file mode 100644 (file)
index 6a59706..0000000
+++ /dev/null
@@ -1,817 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Ultra Wide Band
- * UWB API
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: doc: overview of the API, different parts and pointers
- */
-
-#ifndef __LINUX__UWB_H__
-#define __LINUX__UWB_H__
-
-#include <linux/limits.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <asm/page.h>
-#include "include/spec.h"
-
-struct uwb_dev;
-struct uwb_beca_e;
-struct uwb_rc;
-struct uwb_rsv;
-struct uwb_dbg;
-
-/**
- * struct uwb_dev - a UWB Device
- * @rc: UWB Radio Controller that discovered the device (kind of its
- *     parent).
- * @bce: a beacon cache entry for this device; or NULL if the device
- *     is a local radio controller.
- * @mac_addr: the EUI-48 address of this device.
- * @dev_addr: the current DevAddr used by this device.
- * @beacon_slot: the slot number the beacon is using.
- * @streams: bitmap of streams allocated to reservations targeted at
- *     this device.  For an RC, this is the streams allocated for
- *     reservations targeted at DevAddrs.
- *
- * A UWB device may either by a neighbor or part of a local radio
- * controller.
- */
-struct uwb_dev {
-       struct mutex mutex;
-       struct list_head list_node;
-       struct device dev;
-       struct uwb_rc *rc;              /* radio controller */
-       struct uwb_beca_e *bce;         /* Beacon Cache Entry */
-
-       struct uwb_mac_addr mac_addr;
-       struct uwb_dev_addr dev_addr;
-       int beacon_slot;
-       DECLARE_BITMAP(streams, UWB_NUM_STREAMS);
-       DECLARE_BITMAP(last_availability_bm, UWB_NUM_MAS);
-};
-#define to_uwb_dev(d) container_of(d, struct uwb_dev, dev)
-
-/**
- * UWB HWA/WHCI Radio Control {Command|Event} Block context IDs
- *
- * RC[CE]Bs have a 'context ID' field that matches the command with
- * the event received to confirm it.
- *
- * Maximum number of context IDs
- */
-enum { UWB_RC_CTX_MAX = 256 };
-
-
-/** Notification chain head for UWB generated events to listeners */
-struct uwb_notifs_chain {
-       struct list_head list;
-       struct mutex mutex;
-};
-
-/* Beacon cache list */
-struct uwb_beca {
-       struct list_head list;
-       size_t entries;
-       struct mutex mutex;
-};
-
-/* Event handling thread. */
-struct uwbd {
-       int pid;
-       struct task_struct *task;
-       wait_queue_head_t wq;
-       struct list_head event_list;
-       spinlock_t event_list_lock;
-};
-
-/**
- * struct uwb_mas_bm - a bitmap of all MAS in a superframe
- * @bm: a bitmap of length #UWB_NUM_MAS
- */
-struct uwb_mas_bm {
-       DECLARE_BITMAP(bm, UWB_NUM_MAS);
-       DECLARE_BITMAP(unsafe_bm, UWB_NUM_MAS);
-       int safe;
-       int unsafe;
-};
-
-/**
- * uwb_rsv_state - UWB Reservation state.
- *
- * NONE - reservation is not active (no DRP IE being transmitted).
- *
- * Owner reservation states:
- *
- * INITIATED - owner has sent an initial DRP request.
- * PENDING - target responded with pending Reason Code.
- * MODIFIED - reservation manager is modifying an established
- * reservation with a different MAS allocation.
- * ESTABLISHED - the reservation has been successfully negotiated.
- *
- * Target reservation states:
- *
- * DENIED - request is denied.
- * ACCEPTED - request is accepted.
- * PENDING - PAL has yet to make a decision to whether to accept or
- * deny.
- *
- * FIXME: further target states TBD.
- */
-enum uwb_rsv_state {
-       UWB_RSV_STATE_NONE = 0,
-       UWB_RSV_STATE_O_INITIATED,
-       UWB_RSV_STATE_O_PENDING,
-       UWB_RSV_STATE_O_MODIFIED,
-       UWB_RSV_STATE_O_ESTABLISHED,
-       UWB_RSV_STATE_O_TO_BE_MOVED,
-       UWB_RSV_STATE_O_MOVE_EXPANDING,
-       UWB_RSV_STATE_O_MOVE_COMBINING,
-       UWB_RSV_STATE_O_MOVE_REDUCING,
-       UWB_RSV_STATE_T_ACCEPTED,
-       UWB_RSV_STATE_T_DENIED,
-       UWB_RSV_STATE_T_CONFLICT,
-       UWB_RSV_STATE_T_PENDING,
-       UWB_RSV_STATE_T_EXPANDING_ACCEPTED,
-       UWB_RSV_STATE_T_EXPANDING_CONFLICT,
-       UWB_RSV_STATE_T_EXPANDING_PENDING,
-       UWB_RSV_STATE_T_EXPANDING_DENIED,
-       UWB_RSV_STATE_T_RESIZED,
-
-       UWB_RSV_STATE_LAST,
-};
-
-enum uwb_rsv_target_type {
-       UWB_RSV_TARGET_DEV,
-       UWB_RSV_TARGET_DEVADDR,
-};
-
-/**
- * struct uwb_rsv_target - the target of a reservation.
- *
- * Reservations unicast and targeted at a single device
- * (UWB_RSV_TARGET_DEV); or (e.g., in the case of WUSB) targeted at a
- * specific (private) DevAddr (UWB_RSV_TARGET_DEVADDR).
- */
-struct uwb_rsv_target {
-       enum uwb_rsv_target_type type;
-       union {
-               struct uwb_dev *dev;
-               struct uwb_dev_addr devaddr;
-       };
-};
-
-struct uwb_rsv_move {
-       struct uwb_mas_bm final_mas;
-       struct uwb_ie_drp *companion_drp_ie;
-       struct uwb_mas_bm companion_mas;
-};
-
-/*
- * Number of streams reserved for reservations targeted at DevAddrs.
- */
-#define UWB_NUM_GLOBAL_STREAMS 1
-
-typedef void (*uwb_rsv_cb_f)(struct uwb_rsv *rsv);
-
-/**
- * struct uwb_rsv - a DRP reservation
- *
- * Data structure management:
- *
- * @rc:             the radio controller this reservation is for
- *                  (as target or owner)
- * @rc_node:        a list node for the RC
- * @pal_node:       a list node for the PAL
- *
- * Owner and target parameters:
- *
- * @owner:          the UWB device owning this reservation
- * @target:         the target UWB device
- * @type:           reservation type
- *
- * Owner parameters:
- *
- * @max_mas:        maxiumum number of MAS
- * @min_mas:        minimum number of MAS
- * @sparsity:       owner selected sparsity
- * @is_multicast:   true iff multicast
- *
- * @callback:       callback function when the reservation completes
- * @pal_priv:       private data for the PAL making the reservation
- *
- * Reservation status:
- *
- * @status:         negotiation status
- * @stream:         stream index allocated for this reservation
- * @tiebreaker:     conflict tiebreaker for this reservation
- * @mas:            reserved MAS
- * @drp_ie:         the DRP IE
- * @ie_valid:       true iff the DRP IE matches the reservation parameters
- *
- * DRP reservations are uniquely identified by the owner, target and
- * stream index.  However, when using a DevAddr as a target (e.g., for
- * a WUSB cluster reservation) the responses may be received from
- * devices with different DevAddrs.  In this case, reservations are
- * uniquely identified by just the stream index.  A number of stream
- * indexes (UWB_NUM_GLOBAL_STREAMS) are reserved for this.
- */
-struct uwb_rsv {
-       struct uwb_rc *rc;
-       struct list_head rc_node;
-       struct list_head pal_node;
-       struct kref kref;
-
-       struct uwb_dev *owner;
-       struct uwb_rsv_target target;
-       enum uwb_drp_type type;
-       int max_mas;
-       int min_mas;
-       int max_interval;
-       bool is_multicast;
-
-       uwb_rsv_cb_f callback;
-       void *pal_priv;
-
-       enum uwb_rsv_state state;
-       bool needs_release_companion_mas;
-       u8 stream;
-       u8 tiebreaker;
-       struct uwb_mas_bm mas;
-       struct uwb_ie_drp *drp_ie;
-       struct uwb_rsv_move mv;
-       bool ie_valid;
-       struct timer_list timer;
-       struct work_struct handle_timeout_work;
-};
-
-static const
-struct uwb_mas_bm uwb_mas_bm_zero = { .bm = { 0 } };
-
-static inline void uwb_mas_bm_copy_le(void *dst, const struct uwb_mas_bm *mas)
-{
-       bitmap_copy_le(dst, mas->bm, UWB_NUM_MAS);
-}
-
-/**
- * struct uwb_drp_avail - a radio controller's view of MAS usage
- * @global:   MAS unused by neighbors (excluding reservations targeted
- *            or owned by the local radio controller) or the beaon period
- * @local:    MAS unused by local established reservations
- * @pending:  MAS unused by local pending reservations
- * @ie:       DRP Availability IE to be included in the beacon
- * @ie_valid: true iff @ie is valid and does not need to regenerated from
- *            @global and @local
- *
- * Each radio controller maintains a view of MAS usage or
- * availability. MAS available for a new reservation are determined
- * from the intersection of @global, @local, and @pending.
- *
- * The radio controller must transmit a DRP Availability IE that's the
- * intersection of @global and @local.
- *
- * A set bit indicates the MAS is unused and available.
- *
- * rc->rsvs_mutex should be held before accessing this data structure.
- *
- * [ECMA-368] section 17.4.3.
- */
-struct uwb_drp_avail {
-       DECLARE_BITMAP(global, UWB_NUM_MAS);
-       DECLARE_BITMAP(local, UWB_NUM_MAS);
-       DECLARE_BITMAP(pending, UWB_NUM_MAS);
-       struct uwb_ie_drp_avail ie;
-       bool ie_valid;
-};
-
-struct uwb_drp_backoff_win {
-       u8 window;
-       u8 n;
-       int total_expired;
-       struct timer_list timer;
-       bool can_reserve_extra_mases;
-};
-
-const char *uwb_rsv_state_str(enum uwb_rsv_state state);
-const char *uwb_rsv_type_str(enum uwb_drp_type type);
-
-struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb,
-                              void *pal_priv);
-void uwb_rsv_destroy(struct uwb_rsv *rsv);
-
-int uwb_rsv_establish(struct uwb_rsv *rsv);
-int uwb_rsv_modify(struct uwb_rsv *rsv,
-                  int max_mas, int min_mas, int sparsity);
-void uwb_rsv_terminate(struct uwb_rsv *rsv);
-
-void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv);
-
-void uwb_rsv_get_usable_mas(struct uwb_rsv *orig_rsv, struct uwb_mas_bm *mas);
-
-/**
- * Radio Control Interface instance
- *
- *
- * Life cycle rules: those of the UWB Device.
- *
- * @index:    an index number for this radio controller, as used in the
- *            device name.
- * @version:  version of protocol supported by this device
- * @priv:     Backend implementation; rw with uwb_dev.dev.sem taken.
- * @cmd:      Backend implementation to execute commands; rw and call
- *            only  with uwb_dev.dev.sem taken.
- * @reset:    Hardware reset of radio controller and any PAL controllers.
- * @filter:   Backend implementation to manipulate data to and from device
- *            to be compliant to specification assumed by driver (WHCI
- *            0.95).
- *
- *            uwb_dev.dev.mutex is used to execute commands and update
- *            the corresponding structures; can't use a spinlock
- *            because rc->cmd() can sleep.
- * @ies:         This is a dynamically allocated array cacheing the
- *               IEs (settable by the host) that the beacon of this
- *               radio controller is currently sending.
- *
- *               In reality, we store here the full command we set to
- *               the radio controller (which is basically a command
- *               prefix followed by all the IEs the beacon currently
- *               contains). This way we don't have to realloc and
- *               memcpy when setting it.
- *
- *               We set this up in uwb_rc_ie_setup(), where we alloc
- *               this struct, call get_ie() [so we know which IEs are
- *               currently being sent, if any].
- *
- * @ies_capacity:Amount of space (in bytes) allocated in @ies. The
- *               amount used is given by sizeof(*ies) plus ies->wIELength
- *               (which is a little endian quantity all the time).
- * @ies_mutex:   protect the IE cache
- * @dbg:         information for the debug interface
- */
-struct uwb_rc {
-       struct uwb_dev uwb_dev;
-       int index;
-       u16 version;
-
-       struct module *owner;
-       void *priv;
-       int (*start)(struct uwb_rc *rc);
-       void (*stop)(struct uwb_rc *rc);
-       int (*cmd)(struct uwb_rc *, const struct uwb_rccb *, size_t);
-       int (*reset)(struct uwb_rc *rc);
-       int (*filter_cmd)(struct uwb_rc *, struct uwb_rccb **, size_t *);
-       int (*filter_event)(struct uwb_rc *, struct uwb_rceb **, const size_t,
-                           size_t *, size_t *);
-
-       spinlock_t neh_lock;            /* protects neh_* and ctx_* */
-       struct list_head neh_list;      /* Open NE handles */
-       unsigned long ctx_bm[UWB_RC_CTX_MAX / 8 / sizeof(unsigned long)];
-       u8 ctx_roll;
-
-       int beaconing;                  /* Beaconing state [channel number] */
-       int beaconing_forced;
-       int scanning;
-       enum uwb_scan_type scan_type:3;
-       unsigned ready:1;
-       struct uwb_notifs_chain notifs_chain;
-       struct uwb_beca uwb_beca;
-
-       struct uwbd uwbd;
-
-       struct uwb_drp_backoff_win bow;
-       struct uwb_drp_avail drp_avail;
-       struct list_head reservations;
-       struct list_head cnflt_alien_list;
-       struct uwb_mas_bm cnflt_alien_bitmap;
-       struct mutex rsvs_mutex;
-       spinlock_t rsvs_lock;
-       struct workqueue_struct *rsv_workq;
-
-       struct delayed_work rsv_update_work;
-       struct delayed_work rsv_alien_bp_work;
-       int set_drp_ie_pending;
-       struct mutex ies_mutex;
-       struct uwb_rc_cmd_set_ie *ies;
-       size_t ies_capacity;
-
-       struct list_head pals;
-       int active_pals;
-
-       struct uwb_dbg *dbg;
-};
-
-
-/**
- * struct uwb_pal - a UWB PAL
- * @name:    descriptive name for this PAL (wusbhc, wlp, etc.).
- * @device:  a device for the PAL.  Used to link the PAL and the radio
- *           controller in sysfs.
- * @rc:      the radio controller the PAL uses.
- * @channel_changed: called when the channel used by the radio changes.
- *           A channel of -1 means the channel has been stopped.
- * @new_rsv: called when a peer requests a reservation (may be NULL if
- *           the PAL cannot accept reservation requests).
- * @channel: channel being used by the PAL; 0 if the PAL isn't using
- *           the radio; -1 if the PAL wishes to use the radio but
- *           cannot.
- * @debugfs_dir: a debugfs directory which the PAL can use for its own
- *           debugfs files.
- *
- * A Protocol Adaptation Layer (PAL) is a user of the WiMedia UWB
- * radio platform (e.g., WUSB, WLP or Bluetooth UWB AMP).
- *
- * The PALs using a radio controller must register themselves to
- * permit the UWB stack to coordinate usage of the radio between the
- * various PALs or to allow PALs to response to certain requests from
- * peers.
- *
- * A struct uwb_pal should be embedded in a containing structure
- * belonging to the PAL and initialized with uwb_pal_init()).  Fields
- * should be set appropriately by the PAL before registering the PAL
- * with uwb_pal_register().
- */
-struct uwb_pal {
-       struct list_head node;
-       const char *name;
-       struct device *device;
-       struct uwb_rc *rc;
-
-       void (*channel_changed)(struct uwb_pal *pal, int channel);
-       void (*new_rsv)(struct uwb_pal *pal, struct uwb_rsv *rsv);
-
-       int channel;
-       struct dentry *debugfs_dir;
-};
-
-void uwb_pal_init(struct uwb_pal *pal);
-int uwb_pal_register(struct uwb_pal *pal);
-void uwb_pal_unregister(struct uwb_pal *pal);
-
-int uwb_radio_start(struct uwb_pal *pal);
-void uwb_radio_stop(struct uwb_pal *pal);
-
-/*
- * General public API
- *
- * This API can be used by UWB device drivers or by those implementing
- * UWB Radio Controllers
- */
-struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
-                                      const struct uwb_dev_addr *devaddr);
-struct uwb_dev *uwb_dev_get_by_rc(struct uwb_dev *, struct uwb_rc *);
-static inline void uwb_dev_get(struct uwb_dev *uwb_dev)
-{
-       get_device(&uwb_dev->dev);
-}
-static inline void uwb_dev_put(struct uwb_dev *uwb_dev)
-{
-       put_device(&uwb_dev->dev);
-}
-struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev);
-
-/**
- * Callback function for 'uwb_{dev,rc}_foreach()'.
- *
- * @dev:  Linux device instance
- *        'uwb_dev = container_of(dev, struct uwb_dev, dev)'
- * @priv: Data passed by the caller to 'uwb_{dev,rc}_foreach()'.
- *
- * @returns: 0 to continue the iterations, any other val to stop
- *           iterating and return the value to the caller of
- *           _foreach().
- */
-typedef int (*uwb_dev_for_each_f)(struct device *dev, void *priv);
-int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f func, void *priv);
-
-struct uwb_rc *uwb_rc_alloc(void);
-struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *);
-struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *);
-void uwb_rc_put(struct uwb_rc *rc);
-
-typedef void (*uwb_rc_cmd_cb_f)(struct uwb_rc *rc, void *arg,
-                                struct uwb_rceb *reply, ssize_t reply_size);
-
-int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
-                    struct uwb_rccb *cmd, size_t cmd_size,
-                    u8 expected_type, u16 expected_event,
-                    uwb_rc_cmd_cb_f cb, void *arg);
-ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
-                  struct uwb_rccb *cmd, size_t cmd_size,
-                  struct uwb_rceb *reply, size_t reply_size);
-ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
-                   struct uwb_rccb *cmd, size_t cmd_size,
-                   u8 expected_type, u16 expected_event,
-                   struct uwb_rceb **preply);
-
-size_t __uwb_addr_print(char *, size_t, const unsigned char *, int);
-
-int uwb_rc_dev_addr_set(struct uwb_rc *, const struct uwb_dev_addr *);
-int uwb_rc_dev_addr_get(struct uwb_rc *, struct uwb_dev_addr *);
-int uwb_rc_mac_addr_set(struct uwb_rc *, const struct uwb_mac_addr *);
-int uwb_rc_mac_addr_get(struct uwb_rc *, struct uwb_mac_addr *);
-int __uwb_mac_addr_assigned_check(struct device *, void *);
-int __uwb_dev_addr_assigned_check(struct device *, void *);
-
-/* Print in @buf a pretty repr of @addr */
-static inline size_t uwb_dev_addr_print(char *buf, size_t buf_size,
-                                       const struct uwb_dev_addr *addr)
-{
-       return __uwb_addr_print(buf, buf_size, addr->data, 0);
-}
-
-/* Print in @buf a pretty repr of @addr */
-static inline size_t uwb_mac_addr_print(char *buf, size_t buf_size,
-                                       const struct uwb_mac_addr *addr)
-{
-       return __uwb_addr_print(buf, buf_size, addr->data, 1);
-}
-
-/* @returns 0 if device addresses @addr2 and @addr1 are equal */
-static inline int uwb_dev_addr_cmp(const struct uwb_dev_addr *addr1,
-                                  const struct uwb_dev_addr *addr2)
-{
-       return memcmp(addr1, addr2, sizeof(*addr1));
-}
-
-/* @returns 0 if MAC addresses @addr2 and @addr1 are equal */
-static inline int uwb_mac_addr_cmp(const struct uwb_mac_addr *addr1,
-                                  const struct uwb_mac_addr *addr2)
-{
-       return memcmp(addr1, addr2, sizeof(*addr1));
-}
-
-/* @returns !0 if a MAC @addr is a broadcast address */
-static inline int uwb_mac_addr_bcast(const struct uwb_mac_addr *addr)
-{
-       struct uwb_mac_addr bcast = {
-               .data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
-       };
-       return !uwb_mac_addr_cmp(addr, &bcast);
-}
-
-/* @returns !0 if a MAC @addr is all zeroes*/
-static inline int uwb_mac_addr_unset(const struct uwb_mac_addr *addr)
-{
-       struct uwb_mac_addr unset = {
-               .data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
-       };
-       return !uwb_mac_addr_cmp(addr, &unset);
-}
-
-/* @returns !0 if the address is in use. */
-static inline unsigned __uwb_dev_addr_assigned(struct uwb_rc *rc,
-                                              struct uwb_dev_addr *addr)
-{
-       return uwb_dev_for_each(rc, __uwb_dev_addr_assigned_check, addr);
-}
-
-/*
- * UWB Radio Controller API
- *
- * This API is used (in addition to the general API) to implement UWB
- * Radio Controllers.
- */
-void uwb_rc_init(struct uwb_rc *);
-int uwb_rc_add(struct uwb_rc *, struct device *dev, void *rc_priv);
-void uwb_rc_rm(struct uwb_rc *);
-void uwb_rc_neh_grok(struct uwb_rc *, void *, size_t);
-void uwb_rc_neh_error(struct uwb_rc *, int);
-void uwb_rc_reset_all(struct uwb_rc *rc);
-void uwb_rc_pre_reset(struct uwb_rc *rc);
-int uwb_rc_post_reset(struct uwb_rc *rc);
-
-/**
- * uwb_rsv_is_owner - is the owner of this reservation the RC?
- * @rsv: the reservation
- */
-static inline bool uwb_rsv_is_owner(struct uwb_rsv *rsv)
-{
-       return rsv->owner == &rsv->rc->uwb_dev;
-}
-
-/**
- * enum uwb_notifs - UWB events that can be passed to any listeners
- * @UWB_NOTIF_ONAIR: a new neighbour has joined the beacon group.
- * @UWB_NOTIF_OFFAIR: a neighbour has left the beacon group.
- *
- * Higher layers can register callback functions with the radio
- * controller using uwb_notifs_register(). The radio controller
- * maintains a list of all registered handlers and will notify all
- * nodes when an event occurs.
- */
-enum uwb_notifs {
-       UWB_NOTIF_ONAIR,
-       UWB_NOTIF_OFFAIR,
-};
-
-/* Callback function registered with UWB */
-struct uwb_notifs_handler {
-       struct list_head list_node;
-       void (*cb)(void *, struct uwb_dev *, enum uwb_notifs);
-       void *data;
-};
-
-int uwb_notifs_register(struct uwb_rc *, struct uwb_notifs_handler *);
-int uwb_notifs_deregister(struct uwb_rc *, struct uwb_notifs_handler *);
-
-
-/**
- * UWB radio controller Event Size Entry (for creating entry tables)
- *
- * WUSB and WHCI define events and notifications, and they might have
- * fixed or variable size.
- *
- * Each event/notification has a size which is not necessarily known
- * in advance based on the event code. As well, vendor specific
- * events/notifications will have a size impossible to determine
- * unless we know about the device's specific details.
- *
- * It was way too smart of the spec writers not to think that it would
- * be impossible for a generic driver to skip over vendor specific
- * events/notifications if there are no LENGTH fields in the HEADER of
- * each message...the transaction size cannot be counted on as the
- * spec does not forbid to pack more than one event in a single
- * transaction.
- *
- * Thus, we guess sizes with tables (or for events, when you know the
- * size ahead of time you can use uwb_rc_neh_extra_size*()). We
- * register tables with the known events and their sizes, and then we
- * traverse those tables. For those with variable length, we provide a
- * way to lookup the size inside the event/notification's
- * payload. This allows device-specific event size tables to be
- * registered.
- *
- * @size:   Size of the payload
- *
- * @offset: if != 0, at offset @offset-1 starts a field with a length
- *          that has to be added to @size. The format of the field is
- *          given by @type.
- *
- * @type:   Type and length of the offset field. Most common is LE 16
- *          bits (that's why that is zero); others are there mostly to
- *          cover for bugs and weirdos.
- */
-struct uwb_est_entry {
-       size_t size;
-       unsigned offset;
-       enum { UWB_EST_16 = 0, UWB_EST_8 = 1 } type;
-};
-
-int uwb_est_register(u8 type, u8 code_high, u16 vendor, u16 product,
-                    const struct uwb_est_entry *, size_t entries);
-int uwb_est_unregister(u8 type, u8 code_high, u16 vendor, u16 product,
-                      const struct uwb_est_entry *, size_t entries);
-ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
-                         size_t len);
-
-/* -- Misc */
-
-enum {
-       EDC_MAX_ERRORS = 10,
-       EDC_ERROR_TIMEFRAME = HZ,
-};
-
-/* error density counter */
-struct edc {
-       unsigned long timestart;
-       u16 errorcount;
-};
-
-static inline
-void edc_init(struct edc *edc)
-{
-       edc->timestart = jiffies;
-}
-
-/* Called when an error occurred.
- * This is way to determine if the number of acceptable errors per time
- * period has been exceeded. It is not accurate as there are cases in which
- * this scheme will not work, for example if there are periodic occurrences
- * of errors that straddle updates to the start time. This scheme is
- * sufficient for our usage.
- *
- * @returns 1 if maximum acceptable errors per timeframe has been exceeded.
- */
-static inline int edc_inc(struct edc *err_hist, u16 max_err, u16 timeframe)
-{
-       unsigned long now;
-
-       now = jiffies;
-       if (now - err_hist->timestart > timeframe) {
-               err_hist->errorcount = 1;
-               err_hist->timestart = now;
-       } else if (++err_hist->errorcount > max_err) {
-                       err_hist->errorcount = 0;
-                       err_hist->timestart = now;
-                       return 1;
-       }
-       return 0;
-}
-
-
-/* Information Element handling */
-
-struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len);
-int uwb_rc_ie_add(struct uwb_rc *uwb_rc, const struct uwb_ie_hdr *ies, size_t size);
-int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id);
-
-/*
- * Transmission statistics
- *
- * UWB uses LQI and RSSI (one byte values) for reporting radio signal
- * strength and line quality indication. We do quick and dirty
- * averages of those. They are signed values, btw.
- *
- * For 8 bit quantities, we keep the min, the max, an accumulator
- * (@sigma) and a # of samples. When @samples gets to 255, we compute
- * the average (@sigma / @samples), place it in @sigma and reset
- * @samples to 1 (so we use it as the first sample).
- *
- * Now, statistically speaking, probably I am kicking the kidneys of
- * some books I have in my shelves collecting dust, but I just want to
- * get an approx, not the Nobel.
- *
- * LOCKING: there is no locking per se, but we try to keep a lockless
- * schema. Only _add_samples() modifies the values--as long as you
- * have other locking on top that makes sure that no two calls of
- * _add_sample() happen at the same time, then we are fine. Now, for
- * resetting the values we just set @samples to 0 and that makes the
- * next _add_sample() to start with defaults. Reading the values in
- * _show() currently can race, so you need to make sure the calls are
- * under the same lock that protects calls to _add_sample(). FIXME:
- * currently unlocked (It is not ultraprecise but does the trick. Bite
- * me).
- */
-struct stats {
-       s8 min, max;
-       s16 sigma;
-       atomic_t samples;
-};
-
-static inline
-void stats_init(struct stats *stats)
-{
-       atomic_set(&stats->samples, 0);
-       wmb();
-}
-
-static inline
-void stats_add_sample(struct stats *stats, s8 sample)
-{
-       s8 min, max;
-       s16 sigma;
-       unsigned samples = atomic_read(&stats->samples);
-       if (samples == 0) {     /* it was zero before, so we initialize */
-               min = 127;
-               max = -128;
-               sigma = 0;
-       } else {
-               min = stats->min;
-               max = stats->max;
-               sigma = stats->sigma;
-       }
-
-       if (sample < min)       /* compute new values */
-               min = sample;
-       else if (sample > max)
-               max = sample;
-       sigma += sample;
-
-       stats->min = min;       /* commit */
-       stats->max = max;
-       stats->sigma = sigma;
-       if (atomic_add_return(1, &stats->samples) > 255) {
-               /* wrapped around! reset */
-               stats->sigma = sigma / 256;
-               atomic_set(&stats->samples, 1);
-       }
-}
-
-static inline ssize_t stats_show(struct stats *stats, char *buf)
-{
-       int min, max, avg;
-       int samples = atomic_read(&stats->samples);
-       if (samples == 0)
-               min = max = avg = 0;
-       else {
-               min = stats->min;
-               max = stats->max;
-               avg = stats->sigma / samples;
-       }
-       return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", min, max, avg);
-}
-
-static inline ssize_t stats_store(struct stats *stats, const char *buf,
-                                 size_t size)
-{
-       stats_init(stats);
-       return size;
-}
-
-#endif /* #ifndef __LINUX__UWB_H__ */
diff --git a/drivers/staging/uwb/uwbd.c b/drivers/staging/uwb/uwbd.c
deleted file mode 100644 (file)
index dc5c743..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Neighborhood Management Daemon
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This daemon takes care of maintaing information that describes the
- * UWB neighborhood that the radios in this machine can see. It also
- * keeps a tab of which devices are visible, makes sure each HC sits
- * on a different channel to avoid interfering, etc.
- *
- * Different drivers (radio controller, device, any API in general)
- * communicate with this daemon through an event queue. Daemon wakes
- * up, takes a list of events and handles them one by one; handling
- * function is extracted from a table based on the event's type and
- * subtype. Events are freed only if the handling function says so.
- *
- *   . Lock protecting the event list has to be an spinlock and locked
- *     with IRQSAVE because it might be called from an interrupt
- *     context (ie: when events arrive and the notification drops
- *     down from the ISR).
- *
- *   . UWB radio controller drivers queue events to the daemon using
- *     uwbd_event_queue(). They just get the event, chew it to make it
- *     look like UWBD likes it and pass it in a buffer allocated with
- *     uwb_event_alloc().
- *
- * EVENTS
- *
- * Events have a type, a subtype, a length, some other stuff and the
- * data blob, which depends on the event. The header is 'struct
- * uwb_event'; for payloads, see 'struct uwbd_evt_*'.
- *
- * EVENT HANDLER TABLES
- *
- * To find a handling function for an event, the type is used to index
- * a subtype-table in the type-table. The subtype-table is indexed
- * with the subtype to get the function that handles the event. Start
- * with the main type-table 'uwbd_evt_type_handler'.
- *
- * DEVICES
- *
- * Devices are created when a bunch of beacons have been received and
- * it is stablished that the device has stable radio presence. CREATED
- * only, not configured. Devices are ONLY configured when an
- * Application-Specific IE Probe is receieved, in which the device
- * declares which Protocol ID it groks. Then the device is CONFIGURED
- * (and the driver->probe() stuff of the device model is invoked).
- *
- * Devices are considered disconnected when a certain number of
- * beacons are not received in an amount of time.
- *
- * Handler functions are called normally uwbd_evt_handle_*().
- */
-#include <linux/kthread.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/freezer.h>
-
-#include "uwb-internal.h"
-
-/*
- * UWBD Event handler function signature
- *
- * Return !0 if the event needs not to be freed (ie the handler
- * takes/took care of it). 0 means the daemon code will free the
- * event.
- *
- * @evt->rc is already referenced and guaranteed to exist. See
- * uwb_evt_handle().
- */
-typedef int (*uwbd_evt_handler_f)(struct uwb_event *);
-
-/**
- * Properties of a UWBD event
- *
- * @handler:    the function that will handle this event
- * @name:       text name of event
- */
-struct uwbd_event {
-       uwbd_evt_handler_f handler;
-       const char *name;
-};
-
-/* Table of handlers for and properties of the UWBD Radio Control Events */
-static struct uwbd_event uwbd_urc_events[] = {
-       [UWB_RC_EVT_IE_RCV] = {
-               .handler = uwbd_evt_handle_rc_ie_rcv,
-               .name = "IE_RECEIVED"
-       },
-       [UWB_RC_EVT_BEACON] = {
-               .handler = uwbd_evt_handle_rc_beacon,
-               .name = "BEACON_RECEIVED"
-       },
-       [UWB_RC_EVT_BEACON_SIZE] = {
-               .handler = uwbd_evt_handle_rc_beacon_size,
-               .name = "BEACON_SIZE_CHANGE"
-       },
-       [UWB_RC_EVT_BPOIE_CHANGE] = {
-               .handler = uwbd_evt_handle_rc_bpoie_change,
-               .name = "BPOIE_CHANGE"
-       },
-       [UWB_RC_EVT_BP_SLOT_CHANGE] = {
-               .handler = uwbd_evt_handle_rc_bp_slot_change,
-               .name = "BP_SLOT_CHANGE"
-       },
-       [UWB_RC_EVT_DRP_AVAIL] = {
-               .handler = uwbd_evt_handle_rc_drp_avail,
-               .name = "DRP_AVAILABILITY_CHANGE"
-       },
-       [UWB_RC_EVT_DRP] = {
-               .handler = uwbd_evt_handle_rc_drp,
-               .name = "DRP"
-       },
-       [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
-               .handler = uwbd_evt_handle_rc_dev_addr_conflict,
-               .name = "DEV_ADDR_CONFLICT",
-       },
-};
-
-
-
-struct uwbd_evt_type_handler {
-       const char *name;
-       struct uwbd_event *uwbd_events;
-       size_t size;
-};
-
-/* Table of handlers for each UWBD Event type. */
-static struct uwbd_evt_type_handler uwbd_urc_evt_type_handlers[] = {
-       [UWB_RC_CET_GENERAL] = {
-               .name        = "URC",
-               .uwbd_events = uwbd_urc_events,
-               .size        = ARRAY_SIZE(uwbd_urc_events),
-       },
-};
-
-static const struct uwbd_event uwbd_message_handlers[] = {
-       [UWB_EVT_MSG_RESET] = {
-               .handler = uwbd_msg_handle_reset,
-               .name = "reset",
-       },
-};
-
-/*
- * Handle an URC event passed to the UWB Daemon
- *
- * @evt: the event to handle
- * @returns: 0 if the event can be kfreed, !0 on the contrary
- *           (somebody else took ownership) [coincidentally, returning
- *           a <0 errno code will free it :)].
- *
- * Looks up the two indirection tables (one for the type, one for the
- * subtype) to decide which function handles it and then calls the
- * handler.
- *
- * The event structure passed to the event handler has the radio
- * controller in @evt->rc referenced. The reference will be dropped
- * once the handler returns, so if it needs it for longer (async),
- * it'll need to take another one.
- */
-static
-int uwbd_event_handle_urc(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct uwbd_evt_type_handler *type_table;
-       uwbd_evt_handler_f handler;
-       u8 type, context;
-       u16 event;
-
-       type = evt->notif.rceb->bEventType;
-       event = le16_to_cpu(evt->notif.rceb->wEvent);
-       context = evt->notif.rceb->bEventContext;
-
-       if (type >= ARRAY_SIZE(uwbd_urc_evt_type_handlers))
-               goto out;
-       type_table = &uwbd_urc_evt_type_handlers[type];
-       if (type_table->uwbd_events == NULL)
-               goto out;
-       if (event >= type_table->size)
-               goto out;
-       handler = type_table->uwbd_events[event].handler;
-       if (handler == NULL)
-               goto out;
-
-       result = (*handler)(evt);
-out:
-       if (result < 0)
-               dev_err(&evt->rc->uwb_dev.dev,
-                       "UWBD: event 0x%02x/%04x/%02x, handling failed: %d\n",
-                       type, event, context, result);
-       return result;
-}
-
-static void uwbd_event_handle_message(struct uwb_event *evt)
-{
-       struct uwb_rc *rc;
-       int result;
-
-       rc = evt->rc;
-
-       if (evt->message < 0 || evt->message >= ARRAY_SIZE(uwbd_message_handlers)) {
-               dev_err(&rc->uwb_dev.dev, "UWBD: invalid message type %d\n", evt->message);
-               return;
-       }
-
-       result = uwbd_message_handlers[evt->message].handler(evt);
-       if (result < 0)
-               dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n",
-                       uwbd_message_handlers[evt->message].name, result);
-}
-
-static void uwbd_event_handle(struct uwb_event *evt)
-{
-       struct uwb_rc *rc;
-       int should_keep;
-
-       rc = evt->rc;
-
-       if (rc->ready) {
-               switch (evt->type) {
-               case UWB_EVT_TYPE_NOTIF:
-                       should_keep = uwbd_event_handle_urc(evt);
-                       if (should_keep <= 0)
-                               kfree(evt->notif.rceb);
-                       break;
-               case UWB_EVT_TYPE_MSG:
-                       uwbd_event_handle_message(evt);
-                       break;
-               default:
-                       dev_err(&rc->uwb_dev.dev, "UWBD: invalid event type %d\n", evt->type);
-                       break;
-               }
-       }
-
-       __uwb_rc_put(rc);       /* for the __uwb_rc_get() in uwb_rc_notif_cb() */
-}
-
-/**
- * UWB Daemon
- *
- * Listens to all UWB notifications and takes care to track the state
- * of the UWB neighbourhood for the kernel. When we do a run, we
- * spinlock, move the list to a private copy and release the
- * lock. Hold it as little as possible. Not a conflict: it is
- * guaranteed we own the events in the private list.
- *
- * FIXME: should change so we don't have a 1HZ timer all the time, but
- *        only if there are devices.
- */
-static int uwbd(void *param)
-{
-       struct uwb_rc *rc = param;
-       unsigned long flags;
-       struct uwb_event *evt;
-       int should_stop = 0;
-
-       while (1) {
-               wait_event_interruptible_timeout(
-                       rc->uwbd.wq,
-                       !list_empty(&rc->uwbd.event_list)
-                         || (should_stop = kthread_should_stop()),
-                       HZ);
-               if (should_stop)
-                       break;
-
-               spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
-               if (!list_empty(&rc->uwbd.event_list)) {
-                       evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node);
-                       list_del(&evt->list_node);
-               } else
-                       evt = NULL;
-               spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
-
-               if (evt) {
-                       uwbd_event_handle(evt);
-                       kfree(evt);
-               }
-
-               uwb_beca_purge(rc);     /* Purge devices that left */
-       }
-       return 0;
-}
-
-
-/** Start the UWB daemon */
-void uwbd_start(struct uwb_rc *rc)
-{
-       struct task_struct *task = kthread_run(uwbd, rc, "uwbd");
-       if (IS_ERR(task)) {
-               rc->uwbd.task = NULL;
-               printk(KERN_ERR "UWB: Cannot start management daemon; "
-                      "UWB won't work\n");
-       } else {
-               rc->uwbd.task = task;
-               rc->uwbd.pid = rc->uwbd.task->pid;
-       }
-}
-
-/* Stop the UWB daemon and free any unprocessed events */
-void uwbd_stop(struct uwb_rc *rc)
-{
-       if (rc->uwbd.task)
-               kthread_stop(rc->uwbd.task);
-       uwbd_flush(rc);
-}
-
-/*
- * Queue an event for the management daemon
- *
- * When some lower layer receives an event, it uses this function to
- * push it forward to the UWB daemon.
- *
- * Once you pass the event, you don't own it any more, but the daemon
- * does. It will uwb_event_free() it when done, so make sure you
- * uwb_event_alloc()ed it or bad things will happen.
- *
- * If the daemon is not running, we just free the event.
- */
-void uwbd_event_queue(struct uwb_event *evt)
-{
-       struct uwb_rc *rc = evt->rc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
-       if (rc->uwbd.pid != 0) {
-               list_add(&evt->list_node, &rc->uwbd.event_list);
-               wake_up_all(&rc->uwbd.wq);
-       } else {
-               __uwb_rc_put(evt->rc);
-               if (evt->type == UWB_EVT_TYPE_NOTIF)
-                       kfree(evt->notif.rceb);
-               kfree(evt);
-       }
-       spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
-       return;
-}
-
-void uwbd_flush(struct uwb_rc *rc)
-{
-       struct uwb_event *evt, *nxt;
-
-       spin_lock_irq(&rc->uwbd.event_list_lock);
-       list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) {
-               if (evt->rc == rc) {
-                       __uwb_rc_put(rc);
-                       list_del(&evt->list_node);
-                       if (evt->type == UWB_EVT_TYPE_NOTIF)
-                               kfree(evt->notif.rceb);
-                       kfree(evt);
-               }
-       }
-       spin_unlock_irq(&rc->uwbd.event_list_lock);
-}
diff --git a/drivers/staging/uwb/whc-rc.c b/drivers/staging/uwb/whc-rc.c
deleted file mode 100644 (file)
index a5ab255..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Wireless Host Controller: Radio Control Interface (WHCI v0.95[2.3])
- * Radio Control command/event transport to the UWB stack
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Initialize and hook up the Radio Control interface.
- *
- * For each device probed, creates an 'struct whcrc' which contains
- * just the representation of the UWB Radio Controller, and the logic
- * for reading notifications and passing them to the UWB Core.
- *
- * So we initialize all of those, register the UWB Radio Controller
- * and setup the notification/event handle to pipe the notifications
- * to the UWB management Daemon.
- *
- * Once uwb_rc_add() is called, the UWB stack takes control, resets
- * the radio and readies the device to take commands the UWB
- * API/user-space.
- *
- * Note this driver is just a transport driver; the commands are
- * formed at the UWB stack and given to this driver who will deliver
- * them to the hw and transfer the replies/notifications back to the
- * UWB stack through the UWB daemon (UWBD).
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include "uwb.h"
-#include "include/whci.h"
-#include "include/umc.h"
-
-#include "uwb-internal.h"
-
-/**
- * Descriptor for an instance of the UWB Radio Control Driver that
- * attaches to the URC interface of the WHCI PCI card.
- *
- * Unless there is a lock specific to the 'data members', all access
- * is protected by uwb_rc->mutex.
- */
-struct whcrc {
-       struct umc_dev *umc_dev;
-       struct uwb_rc *uwb_rc;          /* UWB host controller */
-
-       unsigned long area;
-       void __iomem *rc_base;
-       size_t rc_len;
-       spinlock_t irq_lock;
-
-       void *evt_buf, *cmd_buf;
-       dma_addr_t evt_dma_buf, cmd_dma_buf;
-       wait_queue_head_t cmd_wq;
-       struct work_struct event_work;
-};
-
-/**
- * Execute an UWB RC command on WHCI/RC
- *
- * @rc:       Instance of a Radio Controller that is a whcrc
- * @cmd:      Buffer containing the RCCB and payload to execute
- * @cmd_size: Size of the command buffer.
- *
- * We copy the command into whcrc->cmd_buf (as it is pretty and
- * aligned`and physically contiguous) and then press the right keys in
- * the controller's URCCMD register to get it to read it. We might
- * have to wait for the cmd_sem to be open to us.
- *
- * NOTE: rc's mutex has to be locked
- */
-static int whcrc_cmd(struct uwb_rc *uwb_rc,
-             const struct uwb_rccb *cmd, size_t cmd_size)
-{
-       int result = 0;
-       struct whcrc *whcrc = uwb_rc->priv;
-       struct device *dev = &whcrc->umc_dev->dev;
-       u32 urccmd;
-
-       if (cmd_size >= 4096)
-               return -EINVAL;
-
-       /*
-        * If the URC is halted, then the hardware has reset itself.
-        * Attempt to recover by restarting the device and then return
-        * an error as it's likely that the current command isn't
-        * valid for a newly started RC.
-        */
-       if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) {
-               dev_err(dev, "requesting reset of halted radio controller\n");
-               uwb_rc_reset_all(uwb_rc);
-               return -EIO;
-       }
-
-       result = wait_event_timeout(whcrc->cmd_wq,
-               !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2);
-       if (result == 0) {
-               dev_err(dev, "device is not ready to execute commands\n");
-               return -ETIMEDOUT;
-       }
-
-       memmove(whcrc->cmd_buf, cmd, cmd_size);
-       le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR);
-
-       spin_lock(&whcrc->irq_lock);
-       urccmd = le_readl(whcrc->rc_base + URCCMD);
-       urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK);
-       le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size,
-                 whcrc->rc_base + URCCMD);
-       spin_unlock(&whcrc->irq_lock);
-
-       return 0;
-}
-
-static int whcrc_reset(struct uwb_rc *rc)
-{
-       struct whcrc *whcrc = rc->priv;
-
-       return umc_controller_reset(whcrc->umc_dev);
-}
-
-/**
- * Reset event reception mechanism and tell hw we are ready to get more
- *
- * We have read all the events in the event buffer, so we are ready to
- * reset it to the beginning.
- *
- * This is only called during initialization or after an event buffer
- * has been retired.  This means we can be sure that event processing
- * is disabled and it's safe to update the URCEVTADDR register.
- *
- * There's no need to wait for the event processing to start as the
- * URC will not clear URCCMD_ACTIVE until (internal) event buffer
- * space is available.
- */
-static
-void whcrc_enable_events(struct whcrc *whcrc)
-{
-       u32 urccmd;
-
-       le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR);
-
-       spin_lock(&whcrc->irq_lock);
-       urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE;
-       le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD);
-       spin_unlock(&whcrc->irq_lock);
-}
-
-static void whcrc_event_work(struct work_struct *work)
-{
-       struct whcrc *whcrc = container_of(work, struct whcrc, event_work);
-       size_t size;
-       u64 urcevtaddr;
-
-       urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR);
-       size = urcevtaddr & URCEVTADDR_OFFSET_MASK;
-
-       uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size);
-       whcrc_enable_events(whcrc);
-}
-
-/**
- * Catch interrupts?
- *
- * We ack inmediately (and expect the hw to do the right thing and
- * raise another IRQ if things have changed :)
- */
-static
-irqreturn_t whcrc_irq_cb(int irq, void *_whcrc)
-{
-       struct whcrc *whcrc = _whcrc;
-       struct device *dev = &whcrc->umc_dev->dev;
-       u32 urcsts;
-
-       urcsts = le_readl(whcrc->rc_base + URCSTS);
-       if (!(urcsts & URCSTS_INT_MASK))
-               return IRQ_NONE;
-       le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS);
-
-       if (urcsts & URCSTS_HSE) {
-               dev_err(dev, "host system error -- hardware halted\n");
-               /* FIXME: do something sensible here */
-               goto out;
-       }
-       if (urcsts & URCSTS_ER)
-               schedule_work(&whcrc->event_work);
-       if (urcsts & URCSTS_RCI)
-               wake_up_all(&whcrc->cmd_wq);
-out:
-       return IRQ_HANDLED;
-}
-
-
-/**
- * Initialize a UMC RC interface: map regions, get (shared) IRQ
- */
-static
-int whcrc_setup_rc_umc(struct whcrc *whcrc)
-{
-       int result = 0;
-       struct device *dev = &whcrc->umc_dev->dev;
-       struct umc_dev *umc_dev = whcrc->umc_dev;
-
-       whcrc->area = umc_dev->resource.start;
-       whcrc->rc_len = resource_size(&umc_dev->resource);
-       result = -EBUSY;
-       if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) == NULL) {
-               dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n",
-                       whcrc->rc_len, whcrc->area, result);
-               goto error_request_region;
-       }
-
-       whcrc->rc_base = ioremap(whcrc->area, whcrc->rc_len);
-       if (whcrc->rc_base == NULL) {
-               dev_err(dev, "can't ioremap registers (%zu bytes @ 0x%lx): %d\n",
-                       whcrc->rc_len, whcrc->area, result);
-               goto error_ioremap;
-       }
-
-       result = request_irq(umc_dev->irq, whcrc_irq_cb, IRQF_SHARED,
-                            KBUILD_MODNAME, whcrc);
-       if (result < 0) {
-               dev_err(dev, "can't allocate IRQ %d: %d\n",
-                       umc_dev->irq, result);
-               goto error_request_irq;
-       }
-
-       result = -ENOMEM;
-       whcrc->cmd_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
-                                           &whcrc->cmd_dma_buf, GFP_KERNEL);
-       if (whcrc->cmd_buf == NULL) {
-               dev_err(dev, "Can't allocate cmd transfer buffer\n");
-               goto error_cmd_buffer;
-       }
-
-       whcrc->evt_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
-                                           &whcrc->evt_dma_buf, GFP_KERNEL);
-       if (whcrc->evt_buf == NULL) {
-               dev_err(dev, "Can't allocate evt transfer buffer\n");
-               goto error_evt_buffer;
-       }
-       return 0;
-
-error_evt_buffer:
-       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
-                         whcrc->cmd_dma_buf);
-error_cmd_buffer:
-       free_irq(umc_dev->irq, whcrc);
-error_request_irq:
-       iounmap(whcrc->rc_base);
-error_ioremap:
-       release_mem_region(whcrc->area, whcrc->rc_len);
-error_request_region:
-       return result;
-}
-
-
-/**
- * Release RC's UMC resources
- */
-static
-void whcrc_release_rc_umc(struct whcrc *whcrc)
-{
-       struct umc_dev *umc_dev = whcrc->umc_dev;
-
-       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->evt_buf,
-                         whcrc->evt_dma_buf);
-       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
-                         whcrc->cmd_dma_buf);
-       free_irq(umc_dev->irq, whcrc);
-       iounmap(whcrc->rc_base);
-       release_mem_region(whcrc->area, whcrc->rc_len);
-}
-
-
-/**
- * whcrc_start_rc - start a WHCI radio controller
- * @whcrc: the radio controller to start
- *
- * Reset the UMC device, start the radio controller, enable events and
- * finally enable interrupts.
- */
-static int whcrc_start_rc(struct uwb_rc *rc)
-{
-       struct whcrc *whcrc = rc->priv;
-       struct device *dev = &whcrc->umc_dev->dev;
-
-       /* Reset the thing */
-       le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD);
-       if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0,
-                         5000, "hardware reset") < 0)
-               return -EBUSY;
-
-       /* Set the event buffer, start the controller (enable IRQs later) */
-       le_writel(0, whcrc->rc_base + URCINTR);
-       le_writel(URCCMD_RS, whcrc->rc_base + URCCMD);
-       if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0,
-                         5000, "radio controller start") < 0)
-               return -ETIMEDOUT;
-       whcrc_enable_events(whcrc);
-       le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR);
-       return 0;
-}
-
-
-/**
- * whcrc_stop_rc - stop a WHCI radio controller
- * @whcrc: the radio controller to stop
- *
- * Disable interrupts and cancel any pending event processing work
- * before clearing the Run/Stop bit.
- */
-static
-void whcrc_stop_rc(struct uwb_rc *rc)
-{
-       struct whcrc *whcrc = rc->priv;
-       struct umc_dev *umc_dev = whcrc->umc_dev;
-
-       le_writel(0, whcrc->rc_base + URCINTR);
-       cancel_work_sync(&whcrc->event_work);
-
-       le_writel(0, whcrc->rc_base + URCCMD);
-       whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS,
-                     URCSTS_HALTED, URCSTS_HALTED, 100, "radio controller stop");
-}
-
-static void whcrc_init(struct whcrc *whcrc)
-{
-       spin_lock_init(&whcrc->irq_lock);
-       init_waitqueue_head(&whcrc->cmd_wq);
-       INIT_WORK(&whcrc->event_work, whcrc_event_work);
-}
-
-/**
- * Initialize the radio controller.
- *
- * NOTE: we setup whcrc->uwb_rc before calling uwb_rc_add(); in the
- *       IRQ handler we use that to determine if the hw is ready to
- *       handle events. Looks like a race condition, but it really is
- *       not.
- */
-static
-int whcrc_probe(struct umc_dev *umc_dev)
-{
-       int result;
-       struct uwb_rc *uwb_rc;
-       struct whcrc *whcrc;
-       struct device *dev = &umc_dev->dev;
-
-       result = -ENOMEM;
-       uwb_rc = uwb_rc_alloc();
-       if (uwb_rc == NULL) {
-               dev_err(dev, "unable to allocate RC instance\n");
-               goto error_rc_alloc;
-       }
-       whcrc = kzalloc(sizeof(*whcrc), GFP_KERNEL);
-       if (whcrc == NULL) {
-               dev_err(dev, "unable to allocate WHC-RC instance\n");
-               goto error_alloc;
-       }
-       whcrc_init(whcrc);
-       whcrc->umc_dev = umc_dev;
-
-       result = whcrc_setup_rc_umc(whcrc);
-       if (result < 0) {
-               dev_err(dev, "Can't setup RC UMC interface: %d\n", result);
-               goto error_setup_rc_umc;
-       }
-       whcrc->uwb_rc = uwb_rc;
-
-       uwb_rc->owner = THIS_MODULE;
-       uwb_rc->cmd   = whcrc_cmd;
-       uwb_rc->reset = whcrc_reset;
-       uwb_rc->start = whcrc_start_rc;
-       uwb_rc->stop  = whcrc_stop_rc;
-
-       result = uwb_rc_add(uwb_rc, dev, whcrc);
-       if (result < 0)
-               goto error_rc_add;
-       umc_set_drvdata(umc_dev, whcrc);
-       return 0;
-
-error_rc_add:
-       whcrc_release_rc_umc(whcrc);
-error_setup_rc_umc:
-       kfree(whcrc);
-error_alloc:
-       uwb_rc_put(uwb_rc);
-error_rc_alloc:
-       return result;
-}
-
-/**
- * Clean up the radio control resources
- *
- * When we up the command semaphore, everybody possibly held trying to
- * execute a command should be granted entry and then they'll see the
- * host is quiescing and up it (so it will chain to the next waiter).
- * This should not happen (in any case), as we can only remove when
- * there are no handles open...
- */
-static void whcrc_remove(struct umc_dev *umc_dev)
-{
-       struct whcrc *whcrc = umc_get_drvdata(umc_dev);
-       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
-
-       umc_set_drvdata(umc_dev, NULL);
-       uwb_rc_rm(uwb_rc);
-       whcrc_release_rc_umc(whcrc);
-       kfree(whcrc);
-       uwb_rc_put(uwb_rc);
-}
-
-static int whcrc_pre_reset(struct umc_dev *umc)
-{
-       struct whcrc *whcrc = umc_get_drvdata(umc);
-       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
-
-       uwb_rc_pre_reset(uwb_rc);
-       return 0;
-}
-
-static int whcrc_post_reset(struct umc_dev *umc)
-{
-       struct whcrc *whcrc = umc_get_drvdata(umc);
-       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
-
-       return uwb_rc_post_reset(uwb_rc);
-}
-
-/* PCI device ID's that we handle [so it gets loaded] */
-static struct pci_device_id __used whcrc_id_table[] = {
-       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
-       { /* empty last entry */ }
-};
-MODULE_DEVICE_TABLE(pci, whcrc_id_table);
-
-static struct umc_driver whcrc_driver = {
-       .name       = "whc-rc",
-       .cap_id     = UMC_CAP_ID_WHCI_RC,
-       .probe      = whcrc_probe,
-       .remove     = whcrc_remove,
-       .pre_reset  = whcrc_pre_reset,
-       .post_reset = whcrc_post_reset,
-};
-
-static int __init whcrc_driver_init(void)
-{
-       return umc_driver_register(&whcrc_driver);
-}
-module_init(whcrc_driver_init);
-
-static void __exit whcrc_driver_exit(void)
-{
-       umc_driver_unregister(&whcrc_driver);
-}
-module_exit(whcrc_driver_exit);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Wireless Host Controller Radio Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/whci.c b/drivers/staging/uwb/whci.c
deleted file mode 100644 (file)
index a8832f6..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * WHCI UWB Multi-interface Controller enumerator.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include "include/whci.h"
-#include "include/umc.h"
-
-struct whci_card {
-       struct pci_dev *pci;
-       void __iomem *uwbbase;
-       u8 n_caps;
-       struct umc_dev *devs[0];
-};
-
-
-/* Fix faulty HW :( */
-static
-u64 whci_capdata_quirks(struct whci_card *card, u64 capdata)
-{
-       u64 capdata_orig = capdata;
-       struct pci_dev *pci_dev = card->pci;
-       if (pci_dev->vendor == PCI_VENDOR_ID_INTEL
-           && (pci_dev->device == 0x0c3b || pci_dev->device == 0004)
-           && pci_dev->class == 0x0d1010) {
-               switch (UWBCAPDATA_TO_CAP_ID(capdata)) {
-                       /* WLP capability has 0x100 bytes of aperture */
-               case 0x80:
-                       capdata |= 0x40 << 8; break;
-                       /* WUSB capability has 0x80 bytes of aperture
-                        * and ID is 1 */
-               case 0x02:
-                       capdata &= ~0xffff;
-                       capdata |= 0x2001;
-                       break;
-               }
-       }
-       if (capdata_orig != capdata)
-               dev_warn(&pci_dev->dev,
-                        "PCI v%04x d%04x c%06x#%02x: "
-                        "corrected capdata from %016Lx to %016Lx\n",
-                        pci_dev->vendor, pci_dev->device, pci_dev->class,
-                        (unsigned)UWBCAPDATA_TO_CAP_ID(capdata),
-                        (unsigned long long)capdata_orig,
-                        (unsigned long long)capdata);
-       return capdata;
-}
-
-
-/**
- * whci_wait_for - wait for a WHCI register to be set
- *
- * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'.
- */
-int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result,
-       unsigned long max_ms, const char *tag)
-{
-       unsigned t = 0;
-       u32 val;
-       for (;;) {
-               val = le_readl(reg);
-               if ((val & mask) == result)
-                       break;
-               if (t >= max_ms) {
-                       dev_err(dev, "%s timed out\n", tag);
-                       return -ETIMEDOUT;
-               }
-               msleep(10);
-               t += 10;
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(whci_wait_for);
-
-
-/*
- * NOTE: the capinfo and capdata registers are slightly different
- *       (size and cap-id fields). So for cap #0, we need to fill
- *       in. Size comes from the size of the register block
- *       (statically calculated); cap_id comes from nowhere, we use
- *       zero, that is reserved, for the radio controller, because
- *       none was defined at the spec level.
- */
-static int whci_add_cap(struct whci_card *card, int n)
-{
-       struct umc_dev *umc;
-       u64 capdata;
-       int bar, err;
-
-       umc = umc_device_create(&card->pci->dev, n);
-       if (umc == NULL)
-               return -ENOMEM;
-
-       capdata = le_readq(card->uwbbase + UWBCAPDATA(n));
-
-       bar = UWBCAPDATA_TO_BAR(capdata) << 1;
-
-       capdata = whci_capdata_quirks(card, capdata);
-       /* Capability 0 is the radio controller. It's size is 32
-        * bytes (WHCI0.95[2.3, T2-9]). */
-       umc->version         = UWBCAPDATA_TO_VERSION(capdata);
-       umc->cap_id          = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata);
-       umc->bar             = bar;
-       umc->resource.start  = pci_resource_start(card->pci, bar)
-               + UWBCAPDATA_TO_OFFSET(capdata);
-       umc->resource.end    = umc->resource.start
-               + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1;
-       umc->resource.name   = dev_name(&umc->dev);
-       umc->resource.flags  = card->pci->resource[bar].flags;
-       umc->resource.parent = &card->pci->resource[bar];
-       umc->irq             = card->pci->irq;
-
-       err = umc_device_register(umc);
-       if (err < 0)
-               goto error;
-       card->devs[n] = umc;
-       return 0;
-
-error:
-       kfree(umc);
-       return err;
-}
-
-static void whci_del_cap(struct whci_card *card, int n)
-{
-       struct umc_dev *umc = card->devs[n];
-
-       umc_device_unregister(umc);
-}
-
-static int whci_n_caps(struct pci_dev *pci)
-{
-       void __iomem *uwbbase;
-       u64 capinfo;
-
-       uwbbase = pci_iomap(pci, 0, 8);
-       if (!uwbbase)
-               return -ENOMEM;
-       capinfo = le_readq(uwbbase + UWBCAPINFO);
-       pci_iounmap(pci, uwbbase);
-
-       return UWBCAPINFO_TO_N_CAPS(capinfo);
-}
-
-static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id)
-{
-       struct whci_card *card;
-       int err, n_caps, n;
-
-       err = pci_enable_device(pci);
-       if (err < 0)
-               goto error;
-       pci_enable_msi(pci);
-       pci_set_master(pci);
-       err = -ENXIO;
-       if (!pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
-               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
-       else if (!pci_set_dma_mask(pci, DMA_BIT_MASK(32)))
-               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
-       else
-               goto error_dma;
-
-       err = n_caps = whci_n_caps(pci);
-       if (n_caps < 0)
-               goto error_ncaps;
-
-       err = -ENOMEM;
-       card = kzalloc(sizeof(struct whci_card)
-                      + sizeof(struct umc_dev *) * (n_caps + 1),
-                      GFP_KERNEL);
-       if (card == NULL)
-               goto error_kzalloc;
-       card->pci = pci;
-       card->n_caps = n_caps;
-
-       err = -EBUSY;
-       if (!request_mem_region(pci_resource_start(pci, 0),
-                               UWBCAPDATA_SIZE(card->n_caps),
-                               "whci (capability data)"))
-               goto error_request_memregion;
-       err = -ENOMEM;
-       card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps));
-       if (!card->uwbbase)
-               goto error_iomap;
-
-       /* Add each capability. */
-       for (n = 0; n <= card->n_caps; n++) {
-               err = whci_add_cap(card, n);
-               if (err < 0 && n == 0) {
-                       dev_err(&pci->dev, "cannot bind UWB radio controller:"
-                               " %d\n", err);
-                       goto error_bind;
-               }
-               if (err < 0)
-                       dev_warn(&pci->dev, "warning: cannot bind capability "
-                                "#%u: %d\n", n, err);
-       }
-       pci_set_drvdata(pci, card);
-       return 0;
-
-error_bind:
-       pci_iounmap(pci, card->uwbbase);
-error_iomap:
-       release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
-error_request_memregion:
-       kfree(card);
-error_kzalloc:
-error_ncaps:
-error_dma:
-       pci_disable_msi(pci);
-       pci_disable_device(pci);
-error:
-       return err;
-}
-
-static void whci_remove(struct pci_dev *pci)
-{
-       struct whci_card *card = pci_get_drvdata(pci);
-       int n;
-
-       pci_set_drvdata(pci, NULL);
-       /* Unregister each capability in reverse (so the master device
-        * is unregistered last). */
-       for (n = card->n_caps; n >= 0 ; n--)
-               whci_del_cap(card, n);
-       pci_iounmap(pci, card->uwbbase);
-       release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
-       kfree(card);
-       pci_disable_msi(pci);
-       pci_disable_device(pci);
-}
-
-static struct pci_device_id whci_id_table[] = {
-       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
-       { 0 },
-};
-MODULE_DEVICE_TABLE(pci, whci_id_table);
-
-
-static struct pci_driver whci_driver = {
-       .name     = "whci",
-       .id_table = whci_id_table,
-       .probe    = whci_probe,
-       .remove   = whci_remove,
-};
-
-module_pci_driver(whci_driver);
-MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator");
-MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
-MODULE_LICENSE("GPL");
index 1ef31a9..597acef 100644 (file)
@@ -1776,7 +1776,7 @@ static int bm2835_mmal_init_device(struct bm2835_mmal_dev *dev,
        video_set_drvdata(vfd, dev);
 
        ret = video_register_device(vfd,
-                                   VFL_TYPE_GRABBER,
+                                   VFL_TYPE_VIDEO,
                                    video_nr[dev->camera_num]);
        if (ret < 0)
                return ret;
index 89786c2..5137fcf 100644 (file)
@@ -85,7 +85,6 @@ struct bm2835_mmal_v4l2_ctrl {
        const s64 *imenu; /* integer menu array */
        u32 mmal_id; /* mmal parameter id */
        bm2835_mmal_v4l2_ctrl_cb *setter;
-       bool ignore_errors;
 };
 
 struct v4l2_to_mmal_effects_setting {
@@ -912,8 +911,6 @@ static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl)
        if (ret)
                pr_warn("ctrl id:%d/MMAL param %08X- returned ret %d\n",
                        ctrl->id, mmal_ctrl->mmal_id, ret);
-       if (mmal_ctrl->ignore_errors)
-               ret = 0;
        return ret;
 }
 
@@ -923,239 +920,340 @@ static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = {
 
 static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
        {
-               V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD,
-               -100, 100, 0, 1, NULL,
-               MMAL_PARAMETER_SATURATION,
-               ctrl_set_rational,
-               false
+               .id = V4L2_CID_SATURATION,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = -100,
+               .max = 100,
+               .def = 0,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_SATURATION,
+               .setter = ctrl_set_rational,
        },
        {
-               V4L2_CID_SHARPNESS, MMAL_CONTROL_TYPE_STD,
-               -100, 100, 0, 1, NULL,
-               MMAL_PARAMETER_SHARPNESS,
-               ctrl_set_rational,
-               false
+               .id = V4L2_CID_SHARPNESS,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = -100,
+               .max = 100,
+               .def = 0,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_SHARPNESS,
+               .setter = ctrl_set_rational,
        },
        {
-               V4L2_CID_CONTRAST, MMAL_CONTROL_TYPE_STD,
-               -100, 100, 0, 1, NULL,
-               MMAL_PARAMETER_CONTRAST,
-               ctrl_set_rational,
-               false
+               .id = V4L2_CID_CONTRAST,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = -100,
+               .max = 100,
+               .def = 0,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_CONTRAST,
+               .setter = ctrl_set_rational,
        },
        {
-               V4L2_CID_BRIGHTNESS, MMAL_CONTROL_TYPE_STD,
-               0, 100, 50, 1, NULL,
-               MMAL_PARAMETER_BRIGHTNESS,
-               ctrl_set_rational,
-               false
+               .id = V4L2_CID_BRIGHTNESS,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 100,
+               .def = 50,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_BRIGHTNESS,
+               .setter = ctrl_set_rational,
        },
        {
-               V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU,
-               0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu,
-               MMAL_PARAMETER_ISO,
-               ctrl_set_iso,
-               false
+               .id = V4L2_CID_ISO_SENSITIVITY,
+               .type = MMAL_CONTROL_TYPE_INT_MENU,
+               .min = 0,
+               .max = ARRAY_SIZE(iso_qmenu) - 1,
+               .def = 0,
+               .step = 1,
+               .imenu = iso_qmenu,
+               .mmal_id = MMAL_PARAMETER_ISO,
+               .setter = ctrl_set_iso,
        },
        {
-               V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
-               0, V4L2_ISO_SENSITIVITY_AUTO, V4L2_ISO_SENSITIVITY_AUTO, 1,
-               NULL, MMAL_PARAMETER_ISO,
-               ctrl_set_iso,
-               false
+               .id = V4L2_CID_ISO_SENSITIVITY_AUTO,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = 0,
+               .max = V4L2_ISO_SENSITIVITY_AUTO,
+               .def = V4L2_ISO_SENSITIVITY_AUTO,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_ISO,
+               .setter = ctrl_set_iso,
        },
        {
-               V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD,
-               0, 1, 0, 1, NULL,
-               MMAL_PARAMETER_VIDEO_STABILISATION,
-               ctrl_set_value,
-               false
+               .id = V4L2_CID_IMAGE_STABILIZATION,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 1,
+               .def = 0,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_VIDEO_STABILISATION,
+               .setter = ctrl_set_value,
        },
        {
-               V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
-               ~0x03, V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO, 0,
-               NULL, MMAL_PARAMETER_EXPOSURE_MODE,
-               ctrl_set_exposure,
-               false
+               .id = V4L2_CID_EXPOSURE_AUTO,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = ~0x03,
+               .max = V4L2_EXPOSURE_APERTURE_PRIORITY,
+               .def = V4L2_EXPOSURE_AUTO,
+               .step = 0,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_EXPOSURE_MODE,
+               .setter = ctrl_set_exposure,
        },
        {
-               V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
+               .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+               .type = MMAL_CONTROL_TYPE_STD,
                /* Units of 100usecs */
-               1, 1 * 1000 * 10, 100 * 10, 1, NULL,
-               MMAL_PARAMETER_SHUTTER_SPEED,
-               ctrl_set_exposure,
-               false
+               .min = 1,
+               .max = 1 * 1000 * 10,
+               .def = 100 * 10,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_SHUTTER_SPEED,
+               .setter = ctrl_set_exposure,
        },
        {
-               V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU,
-               0, ARRAY_SIZE(ev_bias_qmenu) - 1,
-               (ARRAY_SIZE(ev_bias_qmenu) + 1) / 2 - 1, 0, ev_bias_qmenu,
-               MMAL_PARAMETER_EXPOSURE_COMP,
-               ctrl_set_value_ev,
-               false
+               .id = V4L2_CID_AUTO_EXPOSURE_BIAS,
+               .type = MMAL_CONTROL_TYPE_INT_MENU,
+               .min = 0,
+               .max = ARRAY_SIZE(ev_bias_qmenu) - 1,
+               .def = (ARRAY_SIZE(ev_bias_qmenu) + 1) / 2 - 1,
+               .step = 0,
+               .imenu = ev_bias_qmenu,
+               .mmal_id = MMAL_PARAMETER_EXPOSURE_COMP,
+               .setter = ctrl_set_value_ev,
        },
        {
-               V4L2_CID_EXPOSURE_AUTO_PRIORITY, MMAL_CONTROL_TYPE_STD,
-               0, 1,
-               0, 1, NULL,
-               0,      /* Dummy MMAL ID as it gets mapped into FPS range*/
-               ctrl_set_exposure,
-               false
+               .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 1,
+               .def = 0,
+               .step = 1,
+               .imenu = NULL,
+               /* Dummy MMAL ID as it gets mapped into FPS range */
+               .mmal_id = 0,
+               .setter = ctrl_set_exposure,
        },
        {
-               V4L2_CID_EXPOSURE_METERING,
-               MMAL_CONTROL_TYPE_STD_MENU,
-               ~0x7, V4L2_EXPOSURE_METERING_SPOT,
-               V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
-               MMAL_PARAMETER_EXP_METERING_MODE,
-               ctrl_set_metering_mode,
-               false
+               .id = V4L2_CID_EXPOSURE_METERING,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = ~0x7,
+               .max = V4L2_EXPOSURE_METERING_SPOT,
+               .def = V4L2_EXPOSURE_METERING_AVERAGE,
+               .step = 0,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_EXP_METERING_MODE,
+               .setter = ctrl_set_metering_mode,
        },
        {
-               V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
-               MMAL_CONTROL_TYPE_STD_MENU,
-               ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0,
-               NULL,
-               MMAL_PARAMETER_AWB_MODE,
-               ctrl_set_awb_mode,
-               false
+               .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = ~0x3ff,
+               .max = V4L2_WHITE_BALANCE_SHADE,
+               .def = V4L2_WHITE_BALANCE_AUTO,
+               .step = 0,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_AWB_MODE,
+               .setter = ctrl_set_awb_mode,
        },
        {
-               V4L2_CID_RED_BALANCE, MMAL_CONTROL_TYPE_STD,
-               1, 7999, 1000, 1, NULL,
-               MMAL_PARAMETER_CUSTOM_AWB_GAINS,
-               ctrl_set_awb_gains,
-               false
+               .id = V4L2_CID_RED_BALANCE,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 1,
+               .max = 7999,
+               .def = 1000,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_CUSTOM_AWB_GAINS,
+               .setter = ctrl_set_awb_gains,
        },
        {
-               V4L2_CID_BLUE_BALANCE, MMAL_CONTROL_TYPE_STD,
-               1, 7999, 1000, 1, NULL,
-               MMAL_PARAMETER_CUSTOM_AWB_GAINS,
-               ctrl_set_awb_gains,
-               false
+               .id = V4L2_CID_BLUE_BALANCE,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 1,
+               .max = 7999,
+               .def = 1000,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_CUSTOM_AWB_GAINS,
+               .setter = ctrl_set_awb_gains,
        },
        {
-               V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
-               0, V4L2_COLORFX_SET_CBCR, V4L2_COLORFX_NONE, 0, NULL,
-               MMAL_PARAMETER_IMAGE_EFFECT,
-               ctrl_set_image_effect,
-               false
+               .id = V4L2_CID_COLORFX,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = 0,
+               .max = V4L2_COLORFX_SET_CBCR,
+               .def = V4L2_COLORFX_NONE,
+               .step = 0,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_IMAGE_EFFECT,
+               .setter = ctrl_set_image_effect,
        },
        {
-               V4L2_CID_COLORFX_CBCR, MMAL_CONTROL_TYPE_STD,
-               0, 0xffff, 0x8080, 1, NULL,
-               MMAL_PARAMETER_COLOUR_EFFECT,
-               ctrl_set_colfx,
-               false
+               .id = V4L2_CID_COLORFX_CBCR,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 0xffff,
+               .def = 0x8080,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_COLOUR_EFFECT,
+               .setter = ctrl_set_colfx,
        },
        {
-               V4L2_CID_ROTATE, MMAL_CONTROL_TYPE_STD,
-               0, 360, 0, 90, NULL,
-               MMAL_PARAMETER_ROTATION,
-               ctrl_set_rotate,
-               false
+               .id = V4L2_CID_ROTATE,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 360,
+               .def = 0,
+               .step = 90,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_ROTATION,
+               .setter = ctrl_set_rotate,
        },
        {
-               V4L2_CID_HFLIP, MMAL_CONTROL_TYPE_STD,
-               0, 1, 0, 1, NULL,
-               MMAL_PARAMETER_MIRROR,
-               ctrl_set_flip,
-               false
+               .id = V4L2_CID_HFLIP,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 1,
+               .def = 0,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_MIRROR,
+               .setter = ctrl_set_flip,
        },
        {
-               V4L2_CID_VFLIP, MMAL_CONTROL_TYPE_STD,
-               0, 1, 0, 1, NULL,
-               MMAL_PARAMETER_MIRROR,
-               ctrl_set_flip,
-               false
+               .id = V4L2_CID_VFLIP,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 1,
+               .def = 0,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_MIRROR,
+               .setter = ctrl_set_flip,
        },
        {
-               V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-               0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
-               0, 0, NULL,
-               MMAL_PARAMETER_RATECONTROL,
-               ctrl_set_bitrate_mode,
-               false
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = 0,
+               .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+               .def = 0,
+               .step = 0,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_RATECONTROL,
+               .setter = ctrl_set_bitrate_mode,
        },
        {
-               V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD,
-               25 * 1000, 25 * 1000 * 1000, 10 * 1000 * 1000, 25 * 1000, NULL,
-               MMAL_PARAMETER_VIDEO_BIT_RATE,
-               ctrl_set_bitrate,
-               false
+               .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 25 * 1000,
+               .max = 25 * 1000 * 1000,
+               .def = 10 * 1000 * 1000,
+               .step = 25 * 1000,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_VIDEO_BIT_RATE,
+               .setter = ctrl_set_bitrate,
        },
        {
-               V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD,
-               1, 100,
-               30, 1, NULL,
-               MMAL_PARAMETER_JPEG_Q_FACTOR,
-               ctrl_set_image_encode_output,
-               false
+               .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 1,
+               .max = 100,
+               .def = 30,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_JPEG_Q_FACTOR,
+               .setter = ctrl_set_image_encode_output,
        },
        {
-               V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
-               0, V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
-               1, 1, NULL,
-               MMAL_PARAMETER_FLICKER_AVOID,
-               ctrl_set_flicker_avoidance,
-               false
+               .id = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = 0,
+               .max = V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+               .def = 1,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_FLICKER_AVOID,
+               .setter = ctrl_set_flicker_avoidance,
        },
        {
-               V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, MMAL_CONTROL_TYPE_STD,
-               0, 1,
-               0, 1, NULL,
-               MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
-               ctrl_set_video_encode_param_output,
-               false
+               .id = V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 1,
+               .def = 0,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
+               .setter = ctrl_set_video_encode_param_output,
        },
        {
-               V4L2_CID_MPEG_VIDEO_H264_PROFILE,
-               MMAL_CONTROL_TYPE_STD_MENU,
-               ~(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,
-               ctrl_set_video_encode_profile_level,
-               false
+               .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = ~(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)),
+               .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+               .def = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_PROFILE,
+               .setter = ctrl_set_video_encode_profile_level,
        },
        {
-               V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU,
-               ~(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,
-               ctrl_set_video_encode_profile_level,
-               false
+               .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               .min = ~(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)),
+               .max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
+               .def = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_PROFILE,
+               .setter = ctrl_set_video_encode_profile_level,
        },
        {
-               V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
-               -1,     /* Min (mask) is computed at runtime */
-               V4L2_SCENE_MODE_TEXT,
-               V4L2_SCENE_MODE_NONE, 1, NULL,
-               MMAL_PARAMETER_PROFILE,
-               ctrl_set_scene_mode,
-               false
+               .id = V4L2_CID_SCENE_MODE,
+               .type = MMAL_CONTROL_TYPE_STD_MENU,
+               /* mask is computed at runtime */
+               .min = -1,
+               .max = V4L2_SCENE_MODE_TEXT,
+               .def = V4L2_SCENE_MODE_NONE,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_PROFILE,
+               .setter = ctrl_set_scene_mode,
        },
        {
-               V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, MMAL_CONTROL_TYPE_STD,
-               0, 0x7FFFFFFF, 60, 1, NULL,
-               MMAL_PARAMETER_INTRAPERIOD,
-               ctrl_set_video_encode_param_output,
-               false
+               .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
+               .type = MMAL_CONTROL_TYPE_STD,
+               .min = 0,
+               .max = 0x7FFFFFFF,
+               .def = 60,
+               .step = 1,
+               .imenu = NULL,
+               .mmal_id = MMAL_PARAMETER_INTRAPERIOD,
+               .setter = ctrl_set_video_encode_param_output,
        },
 };
 
@@ -1168,7 +1266,7 @@ int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev)
                if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) {
                        ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c],
                                                   &v4l2_ctrls[c]);
-                       if (!v4l2_ctrls[c].ignore_errors && ret) {
+                       if (ret) {
                                v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
                                         "Failed when setting default values for ctrl %d\n",
                                         c);
index 141af16..7fc04e3 100644 (file)
@@ -33,10 +33,14 @@ enum vchi_crc_control {
 enum vchi_callback_reason {
        VCHI_CALLBACK_REASON_MIN,
 
-       //This indicates that there is data available
-       //handle is the msg id that was transmitted with the data
-       //    When a message is received and there was no FULL message available previously, send callback
-       //    Tasks get kicked by the callback, reset their event and try and read from the fifo until it fails
+       /*
+        * This indicates that there is data available handle is the msg id that
+        * was transmitted with the data
+        * When a message is received and there was no FULL message available
+        * previously, send callback
+        * Tasks get kicked by the callback, reset their event and try and read
+        * from the fifo until it fails
+        */
        VCHI_CALLBACK_MSG_AVAILABLE,
        VCHI_CALLBACK_MSG_SENT,
        VCHI_CALLBACK_MSG_SPACE_AVAILABLE, // XXX not yet implemented
@@ -51,9 +55,11 @@ enum vchi_callback_reason {
 
        VCHI_CALLBACK_SERVICE_CLOSED,
 
-       // this side has sent XOFF to peer due to lack of data consumption by service
-       // (suggests the service may need to take some recovery action if it has
-       // been deliberately holding off consuming data)
+       /*
+        * this side has sent XOFF to peer due to lack of data consumption by
+        * service (suggests the service may need to take some recovery action
+        * if it has been deliberately holding off consuming data)
+        */
        VCHI_CALLBACK_SENT_XOFF,
        VCHI_CALLBACK_SENT_XON,
 
@@ -112,12 +118,16 @@ struct vchi_msg_vector {
        int32_t vec_len;
 };
 
-// Iterator structure for reading ahead through received message queue. Allocated by client,
-// initialised by vchi_msg_look_ahead. Fields are for internal VCHI use only.
-// Iterates over messages in queue at the instant of the call to vchi_msg_lookahead -
-// will not proceed to messages received since. Behaviour is undefined if an iterator
-// is used again after messages for that service are removed/dequeued by any
-// means other than vchi_msg_iter_... calls on the iterator itself.
+/*
+ * Iterator structure for reading ahead through received message queue.
+ * Allocated by client, initialised by vchi_msg_look_ahead. Fields are for
+ * internal VCHI use only.
+ * Iterates over messages in queue at the instant of the call to
+ * vchi_msg_lookahead - will not proceed to messages received since.
+ * Behaviour is undefined if an iterator is used again after messages for that
+ * service are removed/dequeued by any means other than vchi_msg_iter_...
+ * calls on the iterator itself.
+ */
 struct vchi_msg_iter {
        struct opaque_vchi_service_t *service;
        void *last;
index ca30bfd..c18c6ca 100644 (file)
@@ -257,49 +257,6 @@ int vchiq_dump_platform_state(void *dump_context)
        return vchiq_dump(dump_context, buf, len + 1);
 }
 
-enum vchiq_status
-vchiq_platform_suspend(struct vchiq_state *state)
-{
-       return VCHIQ_ERROR;
-}
-
-enum vchiq_status
-vchiq_platform_resume(struct vchiq_state *state)
-{
-       return VCHIQ_SUCCESS;
-}
-
-void
-vchiq_platform_paused(struct vchiq_state *state)
-{
-}
-
-void
-vchiq_platform_resumed(struct vchiq_state *state)
-{
-}
-
-int
-vchiq_platform_videocore_wanted(struct vchiq_state *state)
-{
-       return 1; // autosuspend not supported - videocore always wanted
-}
-
-int
-vchiq_platform_use_suspend_timer(void)
-{
-       return 0;
-}
-void
-vchiq_dump_platform_use_state(struct vchiq_state *state)
-{
-       vchiq_log_info(vchiq_arm_log_level, "Suspend timer not in use");
-}
-void
-vchiq_platform_handle_timeout(struct vchiq_state *state)
-{
-       (void)state;
-}
 /*
  * Local functions
  */
index 4458c1e..a1ea977 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/compat.h>
 #include <linux/dma-mapping.h>
+#include <linux/rcupdate.h>
 #include <soc/bcm2835/raspberrypi-firmware.h>
 
 #include "vchiq_core.h"
 int vchiq_arm_log_level = VCHIQ_LOG_DEFAULT;
 int vchiq_susp_log_level = VCHIQ_LOG_ERROR;
 
-#define SUSPEND_TIMER_TIMEOUT_MS 100
-#define SUSPEND_RETRY_TIMER_TIMEOUT_MS 1000
-
-#define VC_SUSPEND_NUM_OFFSET 3 /* number of values before idle which are -ve */
-static const char *const suspend_state_names[] = {
-       "VC_SUSPEND_FORCE_CANCELED",
-       "VC_SUSPEND_REJECTED",
-       "VC_SUSPEND_FAILED",
-       "VC_SUSPEND_IDLE",
-       "VC_SUSPEND_REQUESTED",
-       "VC_SUSPEND_IN_PROGRESS",
-       "VC_SUSPEND_SUSPENDED"
-};
-#define VC_RESUME_NUM_OFFSET 1 /* number of values before idle which are -ve */
-static const char *const resume_state_names[] = {
-       "VC_RESUME_FAILED",
-       "VC_RESUME_IDLE",
-       "VC_RESUME_REQUESTED",
-       "VC_RESUME_IN_PROGRESS",
-       "VC_RESUME_RESUMED"
-};
-/* The number of times we allow force suspend to timeout before actually
-** _forcing_ suspend.  This is to cater for SW which fails to release vchiq
-** correctly - we don't want to prevent ARM suspend indefinitely in this case.
-*/
-#define FORCE_SUSPEND_FAIL_MAX 8
-
-/* The time in ms allowed for videocore to go idle when force suspend has been
- * requested */
-#define FORCE_SUSPEND_TIMEOUT_MS 200
-
-static void suspend_timer_callback(struct timer_list *t);
-
 struct user_service {
        struct vchiq_service *service;
        void *userdata;
@@ -2129,10 +2097,12 @@ int vchiq_dump_platform_instances(void *dump_context)
        /* There is no list of instances, so instead scan all services,
                marking those that have been dumped. */
 
+       rcu_read_lock();
        for (i = 0; i < state->unused_service; i++) {
-               struct vchiq_service *service = state->services[i];
+               struct vchiq_service *service;
                struct vchiq_instance *instance;
 
+               service = rcu_dereference(state->services[i]);
                if (!service || service->base.callback != service_callback)
                        continue;
 
@@ -2140,18 +2110,26 @@ int vchiq_dump_platform_instances(void *dump_context)
                if (instance)
                        instance->mark = 0;
        }
+       rcu_read_unlock();
 
        for (i = 0; i < state->unused_service; i++) {
-               struct vchiq_service *service = state->services[i];
+               struct vchiq_service *service;
                struct vchiq_instance *instance;
                int err;
 
-               if (!service || service->base.callback != service_callback)
+               rcu_read_lock();
+               service = rcu_dereference(state->services[i]);
+               if (!service || service->base.callback != service_callback) {
+                       rcu_read_unlock();
                        continue;
+               }
 
                instance = service->instance;
-               if (!instance || instance->mark)
+               if (!instance || instance->mark) {
+                       rcu_read_unlock();
                        continue;
+               }
+               rcu_read_unlock();
 
                len = snprintf(buf, sizeof(buf),
                               "Instance %pK: pid %d,%s completions %d/%d",
@@ -2161,7 +2139,6 @@ int vchiq_dump_platform_instances(void *dump_context)
                               instance->completion_insert -
                               instance->completion_remove,
                               MAX_COMPLETIONS);
-
                err = vchiq_dump(dump_context, buf, len + 1);
                if (err)
                        return err;
@@ -2184,17 +2161,17 @@ int vchiq_dump_platform_service_state(void *dump_context,
        char buf[80];
        int len;
 
-       len = snprintf(buf, sizeof(buf), "  instance %pK", service->instance);
+       len = scnprintf(buf, sizeof(buf), "  instance %pK", service->instance);
 
        if ((service->base.callback == service_callback) &&
                user_service->is_vchi) {
-               len += snprintf(buf + len, sizeof(buf) - len,
+               len += scnprintf(buf + len, sizeof(buf) - len,
                        ", %d/%d messages",
                        user_service->msg_insert - user_service->msg_remove,
                        MSG_QUEUE_SIZE);
 
                if (user_service->dequeue_pending)
-                       len += snprintf(buf + len, sizeof(buf) - len,
+                       len += scnprintf(buf + len, sizeof(buf) - len,
                                " (dequeue pending)");
        }
 
@@ -2258,27 +2235,6 @@ vchiq_fops = {
  * Autosuspend related functionality
  */
 
-int
-vchiq_videocore_wanted(struct vchiq_state *state)
-{
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-
-       if (!arm_state)
-               /* autosuspend not supported - always return wanted */
-               return 1;
-       else if (arm_state->blocked_count)
-               return 1;
-       else if (!arm_state->videocore_use_count)
-               /* usage count zero - check for override unless we're forcing */
-               if (arm_state->resume_blocked)
-                       return 0;
-               else
-                       return vchiq_platform_videocore_wanted(state);
-       else
-               /* non-zero usage count - videocore still required */
-               return 1;
-}
-
 static enum vchiq_status
 vchiq_keepalive_vchiq_callback(enum vchiq_reason reason,
        struct vchiq_header *header,
@@ -2382,317 +2338,13 @@ vchiq_arm_init_state(struct vchiq_state *state,
                atomic_set(&arm_state->ka_use_ack_count, 0);
                atomic_set(&arm_state->ka_release_count, 0);
 
-               init_completion(&arm_state->vc_suspend_complete);
-
-               init_completion(&arm_state->vc_resume_complete);
-               /* Initialise to 'done' state.  We only want to block on resume
-                * completion while videocore is suspended. */
-               set_resume_state(arm_state, VC_RESUME_RESUMED);
-
-               init_completion(&arm_state->resume_blocker);
-               /* Initialise to 'done' state.  We only want to block on this
-                * completion while resume is blocked */
-               complete_all(&arm_state->resume_blocker);
-
-               init_completion(&arm_state->blocked_blocker);
-               /* Initialise to 'done' state.  We only want to block on this
-                * completion while things are waiting on the resume blocker */
-               complete_all(&arm_state->blocked_blocker);
-
-               arm_state->suspend_timer_timeout = SUSPEND_TIMER_TIMEOUT_MS;
-               arm_state->suspend_timer_running = 0;
                arm_state->state = state;
-               timer_setup(&arm_state->suspend_timer, suspend_timer_callback,
-                           0);
-
                arm_state->first_connect = 0;
 
        }
        return VCHIQ_SUCCESS;
 }
 
-/*
-** Functions to modify the state variables;
-**     set_suspend_state
-**     set_resume_state
-**
-** There are more state variables than we might like, so ensure they remain in
-** step.  Suspend and resume state are maintained separately, since most of
-** these state machines can operate independently.  However, there are a few
-** states where state transitions in one state machine cause a reset to the
-** other state machine.  In addition, there are some completion events which
-** need to occur on state machine reset and end-state(s), so these are also
-** dealt with in these functions.
-**
-** In all states we set the state variable according to the input, but in some
-** cases we perform additional steps outlined below;
-**
-** VC_SUSPEND_IDLE - Initialise the suspend completion at the same time.
-**                     The suspend completion is completed after any suspend
-**                     attempt.  When we reset the state machine we also reset
-**                     the completion.  This reset occurs when videocore is
-**                     resumed, and also if we initiate suspend after a suspend
-**                     failure.
-**
-** VC_SUSPEND_IN_PROGRESS - This state is considered the point of no return for
-**                     suspend - ie from this point on we must try to suspend
-**                     before resuming can occur.  We therefore also reset the
-**                     resume state machine to VC_RESUME_IDLE in this state.
-**
-** VC_SUSPEND_SUSPENDED - Suspend has completed successfully. Also call
-**                     complete_all on the suspend completion to notify
-**                     anything waiting for suspend to happen.
-**
-** VC_SUSPEND_REJECTED - Videocore rejected suspend. Videocore will also
-**                     initiate resume, so no need to alter resume state.
-**                     We call complete_all on the suspend completion to notify
-**                     of suspend rejection.
-**
-** VC_SUSPEND_FAILED - We failed to initiate videocore suspend.  We notify the
-**                     suspend completion and reset the resume state machine.
-**
-** VC_RESUME_IDLE - Initialise the resume completion at the same time.  The
-**                     resume completion is in it's 'done' state whenever
-**                     videcore is running.  Therefore, the VC_RESUME_IDLE
-**                     state implies that videocore is suspended.
-**                     Hence, any thread which needs to wait until videocore is
-**                     running can wait on this completion - it will only block
-**                     if videocore is suspended.
-**
-** VC_RESUME_RESUMED - Resume has completed successfully.  Videocore is running.
-**                     Call complete_all on the resume completion to unblock
-**                     any threads waiting for resume.  Also reset the suspend
-**                     state machine to it's idle state.
-**
-** VC_RESUME_FAILED - Currently unused - no mechanism to fail resume exists.
-*/
-
-void
-set_suspend_state(struct vchiq_arm_state *arm_state,
-                 enum vc_suspend_status new_state)
-{
-       /* set the state in all cases */
-       arm_state->vc_suspend_state = new_state;
-
-       /* state specific additional actions */
-       switch (new_state) {
-       case VC_SUSPEND_FORCE_CANCELED:
-               complete_all(&arm_state->vc_suspend_complete);
-               break;
-       case VC_SUSPEND_REJECTED:
-               complete_all(&arm_state->vc_suspend_complete);
-               break;
-       case VC_SUSPEND_FAILED:
-               complete_all(&arm_state->vc_suspend_complete);
-               arm_state->vc_resume_state = VC_RESUME_RESUMED;
-               complete_all(&arm_state->vc_resume_complete);
-               break;
-       case VC_SUSPEND_IDLE:
-               reinit_completion(&arm_state->vc_suspend_complete);
-               break;
-       case VC_SUSPEND_REQUESTED:
-               break;
-       case VC_SUSPEND_IN_PROGRESS:
-               set_resume_state(arm_state, VC_RESUME_IDLE);
-               break;
-       case VC_SUSPEND_SUSPENDED:
-               complete_all(&arm_state->vc_suspend_complete);
-               break;
-       default:
-               BUG();
-               break;
-       }
-}
-
-void
-set_resume_state(struct vchiq_arm_state *arm_state,
-                enum vc_resume_status new_state)
-{
-       /* set the state in all cases */
-       arm_state->vc_resume_state = new_state;
-
-       /* state specific additional actions */
-       switch (new_state) {
-       case VC_RESUME_FAILED:
-               break;
-       case VC_RESUME_IDLE:
-               reinit_completion(&arm_state->vc_resume_complete);
-               break;
-       case VC_RESUME_REQUESTED:
-               break;
-       case VC_RESUME_IN_PROGRESS:
-               break;
-       case VC_RESUME_RESUMED:
-               complete_all(&arm_state->vc_resume_complete);
-               set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-               break;
-       default:
-               BUG();
-               break;
-       }
-}
-
-/* should be called with the write lock held */
-inline void
-start_suspend_timer(struct vchiq_arm_state *arm_state)
-{
-       del_timer(&arm_state->suspend_timer);
-       arm_state->suspend_timer.expires = jiffies +
-               msecs_to_jiffies(arm_state->suspend_timer_timeout);
-       add_timer(&arm_state->suspend_timer);
-       arm_state->suspend_timer_running = 1;
-}
-
-/* should be called with the write lock held */
-static inline void
-stop_suspend_timer(struct vchiq_arm_state *arm_state)
-{
-       if (arm_state->suspend_timer_running) {
-               del_timer(&arm_state->suspend_timer);
-               arm_state->suspend_timer_running = 0;
-       }
-}
-
-static inline int
-need_resume(struct vchiq_state *state)
-{
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-
-       return (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) &&
-                       (arm_state->vc_resume_state < VC_RESUME_REQUESTED) &&
-                       vchiq_videocore_wanted(state);
-}
-
-static inline void
-unblock_resume(struct vchiq_arm_state *arm_state)
-{
-       complete_all(&arm_state->resume_blocker);
-       arm_state->resume_blocked = 0;
-}
-
-/* Initiate suspend via slot handler. Should be called with the write lock
- * held */
-enum vchiq_status
-vchiq_arm_vcsuspend(struct vchiq_state *state)
-{
-       enum vchiq_status status = VCHIQ_ERROR;
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-
-       if (!arm_state)
-               goto out;
-
-       vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-       status = VCHIQ_SUCCESS;
-
-       switch (arm_state->vc_suspend_state) {
-       case VC_SUSPEND_REQUESTED:
-               vchiq_log_info(vchiq_susp_log_level, "%s: suspend already "
-                       "requested", __func__);
-               break;
-       case VC_SUSPEND_IN_PROGRESS:
-               vchiq_log_info(vchiq_susp_log_level, "%s: suspend already in "
-                       "progress", __func__);
-               break;
-
-       default:
-               /* We don't expect to be in other states, so log but continue
-                * anyway */
-               vchiq_log_error(vchiq_susp_log_level,
-                       "%s unexpected suspend state %s", __func__,
-                       suspend_state_names[arm_state->vc_suspend_state +
-                                               VC_SUSPEND_NUM_OFFSET]);
-               /* fall through */
-       case VC_SUSPEND_REJECTED:
-       case VC_SUSPEND_FAILED:
-               /* Ensure any idle state actions have been run */
-               set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-               /* fall through */
-       case VC_SUSPEND_IDLE:
-               vchiq_log_info(vchiq_susp_log_level,
-                       "%s: suspending", __func__);
-               set_suspend_state(arm_state, VC_SUSPEND_REQUESTED);
-               /* kick the slot handler thread to initiate suspend */
-               request_poll(state, NULL, 0);
-               break;
-       }
-
-out:
-       vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status);
-       return status;
-}
-
-void
-vchiq_platform_check_suspend(struct vchiq_state *state)
-{
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-       int susp = 0;
-
-       if (!arm_state)
-               goto out;
-
-       vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
-       write_lock_bh(&arm_state->susp_res_lock);
-       if (arm_state->vc_suspend_state == VC_SUSPEND_REQUESTED &&
-                       arm_state->vc_resume_state == VC_RESUME_RESUMED) {
-               set_suspend_state(arm_state, VC_SUSPEND_IN_PROGRESS);
-               susp = 1;
-       }
-       write_unlock_bh(&arm_state->susp_res_lock);
-
-       if (susp)
-               vchiq_platform_suspend(state);
-
-out:
-       vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-       return;
-}
-
-void
-vchiq_check_suspend(struct vchiq_state *state)
-{
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-
-       if (!arm_state)
-               goto out;
-
-       vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
-       write_lock_bh(&arm_state->susp_res_lock);
-       if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED &&
-                       arm_state->first_connect &&
-                       !vchiq_videocore_wanted(state)) {
-               vchiq_arm_vcsuspend(state);
-       }
-       write_unlock_bh(&arm_state->susp_res_lock);
-
-out:
-       vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-}
-
-/* This function should be called with the write lock held */
-int
-vchiq_check_resume(struct vchiq_state *state)
-{
-       struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state);
-       int resume = 0;
-
-       if (!arm_state)
-               goto out;
-
-       vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
-       if (need_resume(state)) {
-               set_resume_state(arm_state, VC_RESUME_REQUESTED);
-               request_poll(state, NULL, 0);
-               resume = 1;
-       }
-
-out:
-       vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
-       return resume;
-}
-
 enum vchiq_status
 vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
                   enum USE_TYPE_E use_type)
@@ -2724,88 +2376,15 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
        }
 
        write_lock_bh(&arm_state->susp_res_lock);
-       while (arm_state->resume_blocked) {
-               /* If we call 'use' while force suspend is waiting for suspend,
-                * then we're about to block the thread which the force is
-                * waiting to complete, so we're bound to just time out. In this
-                * case, set the suspend state such that the wait will be
-                * canceled, so we can complete as quickly as possible. */
-               if (arm_state->resume_blocked && arm_state->vc_suspend_state ==
-                               VC_SUSPEND_IDLE) {
-                       set_suspend_state(arm_state, VC_SUSPEND_FORCE_CANCELED);
-                       break;
-               }
-               /* If suspend is already in progress then we need to block */
-               if (!try_wait_for_completion(&arm_state->resume_blocker)) {
-                       /* Indicate that there are threads waiting on the resume
-                        * blocker.  These need to be allowed to complete before
-                        * a _second_ call to force suspend can complete,
-                        * otherwise low priority threads might never actually
-                        * continue */
-                       arm_state->blocked_count++;
-                       write_unlock_bh(&arm_state->susp_res_lock);
-                       vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
-                               "blocked - waiting...", __func__, entity);
-                       if (wait_for_completion_killable(
-                                       &arm_state->resume_blocker)) {
-                               vchiq_log_error(vchiq_susp_log_level, "%s %s "
-                                       "wait for resume blocker interrupted",
-                                       __func__, entity);
-                               ret = VCHIQ_ERROR;
-                               write_lock_bh(&arm_state->susp_res_lock);
-                               arm_state->blocked_count--;
-                               write_unlock_bh(&arm_state->susp_res_lock);
-                               goto out;
-                       }
-                       vchiq_log_info(vchiq_susp_log_level, "%s %s resume "
-                               "unblocked", __func__, entity);
-                       write_lock_bh(&arm_state->susp_res_lock);
-                       if (--arm_state->blocked_count == 0)
-                               complete_all(&arm_state->blocked_blocker);
-               }
-       }
-
-       stop_suspend_timer(arm_state);
-
        local_uc = ++arm_state->videocore_use_count;
        local_entity_uc = ++(*entity_uc);
 
-       /* If there's a pending request which hasn't yet been serviced then
-        * just clear it.  If we're past VC_SUSPEND_REQUESTED state then
-        * vc_resume_complete will block until we either resume or fail to
-        * suspend */
-       if (arm_state->vc_suspend_state <= VC_SUSPEND_REQUESTED)
-               set_suspend_state(arm_state, VC_SUSPEND_IDLE);
-
-       if ((use_type != USE_TYPE_SERVICE_NO_RESUME) && need_resume(state)) {
-               set_resume_state(arm_state, VC_RESUME_REQUESTED);
-               vchiq_log_info(vchiq_susp_log_level,
-                       "%s %s count %d, state count %d",
-                       __func__, entity, local_entity_uc, local_uc);
-               request_poll(state, NULL, 0);
-       } else
-               vchiq_log_trace(vchiq_susp_log_level,
-                       "%s %s count %d, state count %d",
-                       __func__, entity, *entity_uc, local_uc);
+       vchiq_log_trace(vchiq_susp_log_level,
+               "%s %s count %d, state count %d",
+               __func__, entity, *entity_uc, local_uc);
 
        write_unlock_bh(&arm_state->susp_res_lock);
 
-       /* Completion is in a done state when we're not suspended, so this won't
-        * block for the non-suspended case. */
-       if (!try_wait_for_completion(&arm_state->vc_resume_complete)) {
-               vchiq_log_info(vchiq_susp_log_level, "%s %s wait for resume",
-                       __func__, entity);
-               if (wait_for_completion_killable(
-                               &arm_state->vc_resume_complete)) {
-                       vchiq_log_error(vchiq_susp_log_level, "%s %s wait for "
-                               "resume interrupted", __func__, entity);
-                       ret = VCHIQ_ERROR;
-                       goto out;
-               }
-               vchiq_log_info(vchiq_susp_log_level, "%s %s resumed", __func__,
-                       entity);
-       }
-
        if (ret == VCHIQ_SUCCESS) {
                enum vchiq_status status = VCHIQ_SUCCESS;
                long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0);
@@ -2860,24 +2439,10 @@ vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service)
        --arm_state->videocore_use_count;
        --(*entity_uc);
 
-       if (!vchiq_videocore_wanted(state)) {
-               if (vchiq_platform_use_suspend_timer() &&
-                               !arm_state->resume_blocked) {
-                       /* Only use the timer if we're not trying to force
-                        * suspend (=> resume_blocked) */
-                       start_suspend_timer(arm_state);
-               } else {
-                       vchiq_log_info(vchiq_susp_log_level,
-                               "%s %s count %d, state count %d - suspending",
-                               __func__, entity, *entity_uc,
-                               arm_state->videocore_use_count);
-                       vchiq_arm_vcsuspend(state);
-               }
-       } else
-               vchiq_log_trace(vchiq_susp_log_level,
-                       "%s %s count %d, state count %d",
-                       __func__, entity, *entity_uc,
-                       arm_state->videocore_use_count);
+       vchiq_log_trace(vchiq_susp_log_level,
+               "%s %s count %d, state count %d",
+               __func__, entity, *entity_uc,
+               arm_state->videocore_use_count);
 
 unlock:
        write_unlock_bh(&arm_state->susp_res_lock);
@@ -2932,11 +2497,11 @@ vchiq_instance_get_use_count(struct vchiq_instance *instance)
        int use_count = 0, i;
 
        i = 0;
-       while ((service = next_service_by_instance(instance->state,
-               instance, &i))) {
+       rcu_read_lock();
+       while ((service = __next_service_by_instance(instance->state,
+                                                    instance, &i)))
                use_count += service->service_use_count;
-               unlock_service(service);
-       }
+       rcu_read_unlock();
        return use_count;
 }
 
@@ -2959,25 +2524,14 @@ vchiq_instance_set_trace(struct vchiq_instance *instance, int trace)
        int i;
 
        i = 0;
-       while ((service = next_service_by_instance(instance->state,
-               instance, &i))) {
+       rcu_read_lock();
+       while ((service = __next_service_by_instance(instance->state,
+                                                    instance, &i)))
                service->trace = trace;
-               unlock_service(service);
-       }
+       rcu_read_unlock();
        instance->trace = (trace != 0);
 }
 
-static void suspend_timer_callback(struct timer_list *t)
-{
-       struct vchiq_arm_state *arm_state =
-                                       from_timer(arm_state, t, suspend_timer);
-       struct vchiq_state *state = arm_state->state;
-
-       vchiq_log_info(vchiq_susp_log_level,
-               "%s - suspend timer expired - check suspend", __func__);
-       vchiq_check_suspend(state);
-}
-
 enum vchiq_status
 vchiq_use_service(unsigned int handle)
 {
@@ -3022,8 +2576,6 @@ vchiq_dump_service_use_state(struct vchiq_state *state)
        int only_nonzero = 0;
        static const char *nz = "<-- preventing suspend";
 
-       enum vc_suspend_status vc_suspend_state;
-       enum vc_resume_status  vc_resume_state;
        int peer_count;
        int vc_use_count;
        int active_services;
@@ -3037,16 +2589,16 @@ vchiq_dump_service_use_state(struct vchiq_state *state)
                return;
 
        read_lock_bh(&arm_state->susp_res_lock);
-       vc_suspend_state = arm_state->vc_suspend_state;
-       vc_resume_state  = arm_state->vc_resume_state;
        peer_count = arm_state->peer_use_count;
        vc_use_count = arm_state->videocore_use_count;
        active_services = state->unused_service;
        if (active_services > MAX_SERVICES)
                only_nonzero = 1;
 
+       rcu_read_lock();
        for (i = 0; i < active_services; i++) {
-               struct vchiq_service *service_ptr = state->services[i];
+               struct vchiq_service *service_ptr =
+                       rcu_dereference(state->services[i]);
 
                if (!service_ptr)
                        continue;
@@ -3064,16 +2616,10 @@ vchiq_dump_service_use_state(struct vchiq_state *state)
                if (found >= MAX_SERVICES)
                        break;
        }
+       rcu_read_unlock();
 
        read_unlock_bh(&arm_state->susp_res_lock);
 
-       vchiq_log_warning(vchiq_susp_log_level,
-               "-- Videcore suspend state: %s --",
-               suspend_state_names[vc_suspend_state + VC_SUSPEND_NUM_OFFSET]);
-       vchiq_log_warning(vchiq_susp_log_level,
-               "-- Videcore resume state: %s --",
-               resume_state_names[vc_resume_state + VC_RESUME_NUM_OFFSET]);
-
        if (only_nonzero)
                vchiq_log_warning(vchiq_susp_log_level, "Too many active "
                        "services (%d).  Only dumping up to first %d services "
@@ -3093,8 +2639,6 @@ vchiq_dump_service_use_state(struct vchiq_state *state)
                "--- Overall vchiq instance use count %d", vc_use_count);
 
        kfree(service_data);
-
-       vchiq_dump_platform_use_state(state);
 }
 
 enum vchiq_status
@@ -3118,24 +2662,16 @@ vchiq_check_service(struct vchiq_service *service)
        if (ret == VCHIQ_ERROR) {
                vchiq_log_error(vchiq_susp_log_level,
                        "%s ERROR - %c%c%c%c:%d service count %d, "
-                       "state count %d, videocore suspend state %s", __func__,
+                       "state count %d", __func__,
                        VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc),
                        service->client_id, service->service_use_count,
-                       arm_state->videocore_use_count,
-                       suspend_state_names[arm_state->vc_suspend_state +
-                                               VC_SUSPEND_NUM_OFFSET]);
+                       arm_state->videocore_use_count);
                vchiq_dump_service_use_state(service->state);
        }
 out:
        return ret;
 }
 
-/* stub functions */
-void vchiq_on_remote_use_active(struct vchiq_state *state)
-{
-       (void)state;
-}
-
 void vchiq_platform_conn_state_changed(struct vchiq_state *state,
                                       enum vchiq_connstate oldstate,
                                       enum vchiq_connstate newstate)
index 19d2a2e..0784c50 100644 (file)
 #include "vchiq_core.h"
 #include "vchiq_debugfs.h"
 
-enum vc_suspend_status {
-       VC_SUSPEND_FORCE_CANCELED = -3, /* Force suspend canceled, too busy */
-       VC_SUSPEND_REJECTED = -2,  /* Videocore rejected suspend request */
-       VC_SUSPEND_FAILED = -1,    /* Videocore suspend failed */
-       VC_SUSPEND_IDLE = 0,       /* VC active, no suspend actions */
-       VC_SUSPEND_REQUESTED,      /* User has requested suspend */
-       VC_SUSPEND_IN_PROGRESS,    /* Slot handler has recvd suspend request */
-       VC_SUSPEND_SUSPENDED       /* Videocore suspend succeeded */
-};
-
-enum vc_resume_status {
-       VC_RESUME_FAILED = -1, /* Videocore resume failed */
-       VC_RESUME_IDLE = 0,    /* VC suspended, no resume actions */
-       VC_RESUME_REQUESTED,   /* User has requested resume */
-       VC_RESUME_IN_PROGRESS, /* Slot handler has received resume request */
-       VC_RESUME_RESUMED      /* Videocore resumed successfully (active) */
-};
-
 enum USE_TYPE_E {
        USE_TYPE_SERVICE,
-       USE_TYPE_SERVICE_NO_RESUME,
        USE_TYPE_VCHIQ
 };
 
@@ -46,19 +27,9 @@ struct vchiq_arm_state {
        atomic_t ka_use_ack_count;
        atomic_t ka_release_count;
 
-       struct completion vc_suspend_complete;
-       struct completion vc_resume_complete;
-
        rwlock_t susp_res_lock;
-       enum vc_suspend_status vc_suspend_state;
-       enum vc_resume_status vc_resume_state;
-
-       unsigned int wake_address;
 
        struct vchiq_state *state;
-       struct timer_list suspend_timer;
-       int suspend_timer_timeout;
-       int suspend_timer_running;
 
        /* Global use count for videocore.
        ** This is equal to the sum of the use counts for all services.  When
@@ -72,27 +43,11 @@ struct vchiq_arm_state {
        */
        int peer_use_count;
 
-       /* Flag to indicate whether resume is blocked.  This happens when the
-       ** ARM is suspending
-       */
-       struct completion resume_blocker;
-       int resume_blocked;
-       struct completion blocked_blocker;
-       int blocked_count;
-
-       int autosuspend_override;
-
        /* Flag to indicate that the first vchiq connect has made it through.
        ** This means that both sides should be fully ready, and we should
        ** be able to suspend after this point.
        */
        int first_connect;
-
-       unsigned long long suspend_start_time;
-       unsigned long long sleep_start_time;
-       unsigned long long resume_start_time;
-       unsigned long long last_wake_time;
-
 };
 
 struct vchiq_drvdata {
@@ -110,18 +65,9 @@ extern struct vchiq_state *
 vchiq_get_state(void);
 
 extern enum vchiq_status
-vchiq_arm_vcsuspend(struct vchiq_state *state);
-
-extern enum vchiq_status
-vchiq_arm_vcresume(struct vchiq_state *state);
-
-extern enum vchiq_status
 vchiq_arm_init_state(struct vchiq_state *state,
                     struct vchiq_arm_state *arm_state);
 
-extern int
-vchiq_check_resume(struct vchiq_state *state);
-
 extern void
 vchiq_check_suspend(struct vchiq_state *state);
 enum vchiq_status
@@ -133,15 +79,6 @@ vchiq_release_service(unsigned int handle);
 extern enum vchiq_status
 vchiq_check_service(struct vchiq_service *service);
 
-extern enum vchiq_status
-vchiq_platform_suspend(struct vchiq_state *state);
-
-extern int
-vchiq_platform_videocore_wanted(struct vchiq_state *state);
-
-extern int
-vchiq_platform_use_suspend_timer(void);
-
 extern void
 vchiq_dump_platform_use_state(struct vchiq_state *state);
 
@@ -151,8 +88,6 @@ vchiq_dump_service_use_state(struct vchiq_state *state);
 extern struct vchiq_arm_state*
 vchiq_platform_get_arm_state(struct vchiq_state *state);
 
-extern int
-vchiq_videocore_wanted(struct vchiq_state *state);
 
 extern enum vchiq_status
 vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service,
@@ -176,15 +111,4 @@ vchiq_instance_get_trace(struct vchiq_instance *instance);
 extern void
 vchiq_instance_set_trace(struct vchiq_instance *instance, int trace);
 
-extern void
-set_suspend_state(struct vchiq_arm_state *arm_state,
-                 enum vc_suspend_status new_state);
-
-extern void
-set_resume_state(struct vchiq_arm_state *arm_state,
-                enum vc_resume_status new_state);
-
-extern void
-start_suspend_timer(struct vchiq_arm_state *arm_state);
-
 #endif /* VCHIQ_ARM_H */
index 7635107..edcd973 100644 (file)
@@ -1,6 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
 
+#include <linux/kref.h>
+#include <linux/rcupdate.h>
+
 #include "vchiq_core.h"
 
 #define VCHIQ_SLOT_HANDLER_STACK 8192
@@ -54,7 +57,6 @@ int vchiq_core_log_level = VCHIQ_LOG_DEFAULT;
 int vchiq_core_msg_log_level = VCHIQ_LOG_DEFAULT;
 int vchiq_sync_log_level = VCHIQ_LOG_DEFAULT;
 
-static DEFINE_SPINLOCK(service_spinlock);
 DEFINE_SPINLOCK(bulk_waiter_spinlock);
 static DEFINE_SPINLOCK(quota_spinlock);
 
@@ -136,44 +138,41 @@ find_service_by_handle(unsigned int handle)
 {
        struct vchiq_service *service;
 
-       spin_lock(&service_spinlock);
+       rcu_read_lock();
        service = handle_to_service(handle);
-       if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
-               (service->handle == handle)) {
-               WARN_ON(service->ref_count == 0);
-               service->ref_count++;
-       } else
-               service = NULL;
-       spin_unlock(&service_spinlock);
-
-       if (!service)
-               vchiq_log_info(vchiq_core_log_level,
-                       "Invalid service handle 0x%x", handle);
-
-       return service;
+       if (service && service->srvstate != VCHIQ_SRVSTATE_FREE &&
+           service->handle == handle &&
+           kref_get_unless_zero(&service->ref_count)) {
+               service = rcu_pointer_handoff(service);
+               rcu_read_unlock();
+               return service;
+       }
+       rcu_read_unlock();
+       vchiq_log_info(vchiq_core_log_level,
+                      "Invalid service handle 0x%x", handle);
+       return NULL;
 }
 
 struct vchiq_service *
 find_service_by_port(struct vchiq_state *state, int localport)
 {
-       struct vchiq_service *service = NULL;
 
        if ((unsigned int)localport <= VCHIQ_PORT_MAX) {
-               spin_lock(&service_spinlock);
-               service = state->services[localport];
-               if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE)) {
-                       WARN_ON(service->ref_count == 0);
-                       service->ref_count++;
-               } else
-                       service = NULL;
-               spin_unlock(&service_spinlock);
-       }
-
-       if (!service)
-               vchiq_log_info(vchiq_core_log_level,
-                       "Invalid port %d", localport);
+               struct vchiq_service *service;
 
-       return service;
+               rcu_read_lock();
+               service = rcu_dereference(state->services[localport]);
+               if (service && service->srvstate != VCHIQ_SRVSTATE_FREE &&
+                   kref_get_unless_zero(&service->ref_count)) {
+                       service = rcu_pointer_handoff(service);
+                       rcu_read_unlock();
+                       return service;
+               }
+               rcu_read_unlock();
+       }
+       vchiq_log_info(vchiq_core_log_level,
+                      "Invalid port %d", localport);
+       return NULL;
 }
 
 struct vchiq_service *
@@ -182,22 +181,20 @@ find_service_for_instance(struct vchiq_instance *instance,
 {
        struct vchiq_service *service;
 
-       spin_lock(&service_spinlock);
+       rcu_read_lock();
        service = handle_to_service(handle);
-       if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) &&
-               (service->handle == handle) &&
-               (service->instance == instance)) {
-               WARN_ON(service->ref_count == 0);
-               service->ref_count++;
-       } else
-               service = NULL;
-       spin_unlock(&service_spinlock);
-
-       if (!service)
-               vchiq_log_info(vchiq_core_log_level,
-                       "Invalid service handle 0x%x", handle);
-
-       return service;
+       if (service && service->srvstate != VCHIQ_SRVSTATE_FREE &&
+           service->handle == handle &&
+           service->instance == instance &&
+           kref_get_unless_zero(&service->ref_count)) {
+               service = rcu_pointer_handoff(service);
+               rcu_read_unlock();
+               return service;
+       }
+       rcu_read_unlock();
+       vchiq_log_info(vchiq_core_log_level,
+                      "Invalid service handle 0x%x", handle);
+       return NULL;
 }
 
 struct vchiq_service *
@@ -206,121 +203,125 @@ find_closed_service_for_instance(struct vchiq_instance *instance,
 {
        struct vchiq_service *service;
 
-       spin_lock(&service_spinlock);
+       rcu_read_lock();
        service = handle_to_service(handle);
        if (service &&
-               ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
-                (service->srvstate == VCHIQ_SRVSTATE_CLOSED)) &&
-               (service->handle == handle) &&
-               (service->instance == instance)) {
-               WARN_ON(service->ref_count == 0);
-               service->ref_count++;
-       } else
-               service = NULL;
-       spin_unlock(&service_spinlock);
-
-       if (!service)
-               vchiq_log_info(vchiq_core_log_level,
-                       "Invalid service handle 0x%x", handle);
-
+           (service->srvstate == VCHIQ_SRVSTATE_FREE ||
+            service->srvstate == VCHIQ_SRVSTATE_CLOSED) &&
+           service->handle == handle &&
+           service->instance == instance &&
+           kref_get_unless_zero(&service->ref_count)) {
+               service = rcu_pointer_handoff(service);
+               rcu_read_unlock();
+               return service;
+       }
+       rcu_read_unlock();
+       vchiq_log_info(vchiq_core_log_level,
+                      "Invalid service handle 0x%x", handle);
        return service;
 }
 
 struct vchiq_service *
-next_service_by_instance(struct vchiq_state *state, struct vchiq_instance *instance,
-                        int *pidx)
+__next_service_by_instance(struct vchiq_state *state,
+                          struct vchiq_instance *instance,
+                          int *pidx)
 {
        struct vchiq_service *service = NULL;
        int idx = *pidx;
 
-       spin_lock(&service_spinlock);
        while (idx < state->unused_service) {
-               struct vchiq_service *srv = state->services[idx++];
+               struct vchiq_service *srv;
 
-               if (srv && (srv->srvstate != VCHIQ_SRVSTATE_FREE) &&
-                       (srv->instance == instance)) {
+               srv = rcu_dereference(state->services[idx++]);
+               if (srv && srv->srvstate != VCHIQ_SRVSTATE_FREE &&
+                   srv->instance == instance) {
                        service = srv;
-                       WARN_ON(service->ref_count == 0);
-                       service->ref_count++;
                        break;
                }
        }
-       spin_unlock(&service_spinlock);
 
        *pidx = idx;
+       return service;
+}
+
+struct vchiq_service *
+next_service_by_instance(struct vchiq_state *state,
+                        struct vchiq_instance *instance,
+                        int *pidx)
+{
+       struct vchiq_service *service;
 
+       rcu_read_lock();
+       while (1) {
+               service = __next_service_by_instance(state, instance, pidx);
+               if (!service)
+                       break;
+               if (kref_get_unless_zero(&service->ref_count)) {
+                       service = rcu_pointer_handoff(service);
+                       break;
+               }
+       }
+       rcu_read_unlock();
        return service;
 }
 
 void
 lock_service(struct vchiq_service *service)
 {
-       spin_lock(&service_spinlock);
-       WARN_ON(!service);
-       if (service) {
-               WARN_ON(service->ref_count == 0);
-               service->ref_count++;
+       if (!service) {
+               WARN(1, "%s service is NULL\n", __func__);
+               return;
        }
-       spin_unlock(&service_spinlock);
+       kref_get(&service->ref_count);
+}
+
+static void service_release(struct kref *kref)
+{
+       struct vchiq_service *service =
+               container_of(kref, struct vchiq_service, ref_count);
+       struct vchiq_state *state = service->state;
+
+       WARN_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
+       rcu_assign_pointer(state->services[service->localport], NULL);
+       if (service->userdata_term)
+               service->userdata_term(service->base.userdata);
+       kfree_rcu(service, rcu);
 }
 
 void
 unlock_service(struct vchiq_service *service)
 {
-       spin_lock(&service_spinlock);
        if (!service) {
                WARN(1, "%s: service is NULL\n", __func__);
-               goto unlock;
-       }
-       if (!service->ref_count) {
-               WARN(1, "%s: ref_count is zero\n", __func__);
-               goto unlock;
-       }
-       service->ref_count--;
-       if (!service->ref_count) {
-               struct vchiq_state *state = service->state;
-
-               WARN_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
-               state->services[service->localport] = NULL;
-       } else {
-               service = NULL;
+               return;
        }
-unlock:
-       spin_unlock(&service_spinlock);
-
-       if (service && service->userdata_term)
-               service->userdata_term(service->base.userdata);
-
-       kfree(service);
+       kref_put(&service->ref_count, service_release);
 }
 
 int
 vchiq_get_client_id(unsigned int handle)
 {
-       struct vchiq_service *service = find_service_by_handle(handle);
+       struct vchiq_service *service;
        int id;
 
+       rcu_read_lock();
+       service = handle_to_service(handle);
        id = service ? service->client_id : 0;
-       if (service)
-               unlock_service(service);
-
+       rcu_read_unlock();
        return id;
 }
 
 void *
 vchiq_get_service_userdata(unsigned int handle)
 {
-       struct vchiq_service *service = handle_to_service(handle);
-
-       return service ? service->base.userdata : NULL;
-}
-
-int
-vchiq_get_service_fourcc(unsigned int handle)
-{
-       struct vchiq_service *service = handle_to_service(handle);
+       void *userdata;
+       struct vchiq_service *service;
 
-       return service ? service->base.fourcc : 0;
+       rcu_read_lock();
+       service = handle_to_service(handle);
+       userdata = service ? service->base.userdata : NULL;
+       rcu_read_unlock();
+       return userdata;
 }
 
 static void
@@ -468,19 +469,23 @@ get_listening_service(struct vchiq_state *state, int fourcc)
 
        WARN_ON(fourcc == VCHIQ_FOURCC_INVALID);
 
+       rcu_read_lock();
        for (i = 0; i < state->unused_service; i++) {
-               struct vchiq_service *service = state->services[i];
+               struct vchiq_service *service;
 
+               service = rcu_dereference(state->services[i]);
                if (service &&
-                       (service->public_fourcc == fourcc) &&
-                       ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) ||
-                       ((service->srvstate == VCHIQ_SRVSTATE_OPEN) &&
-                       (service->remoteport == VCHIQ_PORT_FREE)))) {
-                       lock_service(service);
+                   service->public_fourcc == fourcc &&
+                   (service->srvstate == VCHIQ_SRVSTATE_LISTENING ||
+                    (service->srvstate == VCHIQ_SRVSTATE_OPEN &&
+                     service->remoteport == VCHIQ_PORT_FREE)) &&
+                   kref_get_unless_zero(&service->ref_count)) {
+                       service = rcu_pointer_handoff(service);
+                       rcu_read_unlock();
                        return service;
                }
        }
-
+       rcu_read_unlock();
        return NULL;
 }
 
@@ -490,15 +495,20 @@ get_connected_service(struct vchiq_state *state, unsigned int port)
 {
        int i;
 
+       rcu_read_lock();
        for (i = 0; i < state->unused_service; i++) {
-               struct vchiq_service *service = state->services[i];
-
-               if (service && (service->srvstate == VCHIQ_SRVSTATE_OPEN)
-                       && (service->remoteport == port)) {
-                       lock_service(service);
+               struct vchiq_service *service =
+                       rcu_dereference(state->services[i]);
+
+               if (service && service->srvstate == VCHIQ_SRVSTATE_OPEN &&
+                   service->remoteport == port &&
+                   kref_get_unless_zero(&service->ref_count)) {
+                       service = rcu_pointer_handoff(service);
+                       rcu_read_unlock();
                        return service;
                }
        }
+       rcu_read_unlock();
        return NULL;
 }
 
@@ -1798,7 +1808,6 @@ parse_rx_slots(struct vchiq_state *state)
                        }
                        /* At this point slot_mutex is held */
                        vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED);
-                       vchiq_platform_paused(state);
                        break;
                case VCHIQ_MSG_RESUME:
                        vchiq_log_trace(vchiq_core_log_level,
@@ -1807,7 +1816,6 @@ parse_rx_slots(struct vchiq_state *state)
                        /* Release the slot mutex */
                        mutex_unlock(&state->slot_mutex);
                        vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
-                       vchiq_platform_resumed(state);
                        break;
 
                case VCHIQ_MSG_REMOTE_USE:
@@ -1817,7 +1825,6 @@ parse_rx_slots(struct vchiq_state *state)
                        vchiq_on_remote_release(state);
                        break;
                case VCHIQ_MSG_REMOTE_USE_ACTIVE:
-                       vchiq_on_remote_use_active(state);
                        break;
 
                default:
@@ -1869,9 +1876,6 @@ slot_handler_func(void *v)
 
                DEBUG_TRACE(SLOT_HANDLER_LINE);
                if (state->poll_needed) {
-                       /* Check if we need to suspend - may change our
-                        * conn_state */
-                       vchiq_platform_check_suspend(state);
 
                        state->poll_needed = 0;
 
@@ -1897,10 +1901,6 @@ slot_handler_func(void *v)
                                }
                                break;
 
-                       case VCHIQ_CONNSTATE_PAUSED:
-                               vchiq_platform_resume(state);
-                               break;
-
                        case VCHIQ_CONNSTATE_RESUMING:
                                if (queue_message(state, NULL,
                                        VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0),
@@ -1908,7 +1908,6 @@ slot_handler_func(void *v)
                                        != VCHIQ_RETRY) {
                                        vchiq_set_conn_state(state,
                                                VCHIQ_CONNSTATE_CONNECTED);
-                                       vchiq_platform_resumed(state);
                                } else {
                                        /* This should really be impossible,
                                        ** since the PAUSE should have flushed
@@ -1918,11 +1917,6 @@ slot_handler_func(void *v)
                                                "message");
                                }
                                break;
-
-                       case VCHIQ_CONNSTATE_PAUSE_TIMEOUT:
-                       case VCHIQ_CONNSTATE_RESUME_TIMEOUT:
-                               vchiq_platform_handle_timeout(state);
-                               break;
                        default:
                                break;
                        }
@@ -2284,7 +2278,7 @@ vchiq_add_service_internal(struct vchiq_state *state,
                           vchiq_userdata_term userdata_term)
 {
        struct vchiq_service *service;
-       struct vchiq_service **pservice = NULL;
+       struct vchiq_service __rcu **pservice = NULL;
        struct vchiq_service_quota *service_quota;
        int i;
 
@@ -2296,7 +2290,7 @@ vchiq_add_service_internal(struct vchiq_state *state,
        service->base.callback = params->callback;
        service->base.userdata = params->userdata;
        service->handle        = VCHIQ_SERVICE_HANDLE_INVALID;
-       service->ref_count     = 1;
+       kref_init(&service->ref_count);
        service->srvstate      = VCHIQ_SRVSTATE_FREE;
        service->userdata_term = userdata_term;
        service->localport     = VCHIQ_PORT_FREE;
@@ -2322,7 +2316,7 @@ vchiq_add_service_internal(struct vchiq_state *state,
        mutex_init(&service->bulk_mutex);
        memset(&service->stats, 0, sizeof(service->stats));
 
-       /* Although it is perfectly possible to use service_spinlock
+       /* Although it is perfectly possible to use spinlock
        ** to protect the creation of services, it is overkill as it
        ** disables interrupts while the array is searched.
        ** The only danger is of another thread trying to create a
@@ -2340,17 +2334,17 @@ vchiq_add_service_internal(struct vchiq_state *state,
 
        if (srvstate == VCHIQ_SRVSTATE_OPENING) {
                for (i = 0; i < state->unused_service; i++) {
-                       struct vchiq_service *srv = state->services[i];
-
-                       if (!srv) {
+                       if (!rcu_access_pointer(state->services[i])) {
                                pservice = &state->services[i];
                                break;
                        }
                }
        } else {
+               rcu_read_lock();
                for (i = (state->unused_service - 1); i >= 0; i--) {
-                       struct vchiq_service *srv = state->services[i];
+                       struct vchiq_service *srv;
 
+                       srv = rcu_dereference(state->services[i]);
                        if (!srv)
                                pservice = &state->services[i];
                        else if ((srv->public_fourcc == params->fourcc)
@@ -2363,6 +2357,7 @@ vchiq_add_service_internal(struct vchiq_state *state,
                                break;
                        }
                }
+               rcu_read_unlock();
        }
 
        if (pservice) {
@@ -2374,7 +2369,7 @@ vchiq_add_service_internal(struct vchiq_state *state,
                        (state->id * VCHIQ_MAX_SERVICES) |
                        service->localport;
                handle_seq += VCHIQ_MAX_STATES * VCHIQ_MAX_SERVICES;
-               *pservice = service;
+               rcu_assign_pointer(*pservice, service);
                if (pservice == &state->services[state->unused_service])
                        state->unused_service++;
        }
@@ -2437,13 +2432,13 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id)
                        status = VCHIQ_RETRY;
                        vchiq_release_service_internal(service);
                } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
-                       (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) {
+                          (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) {
                        if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT)
                                vchiq_log_error(vchiq_core_log_level,
-                                       "%d: osi - srvstate = %s (ref %d)",
-                                       service->state->id,
-                                       srvstate_names[service->srvstate],
-                                       service->ref_count);
+                                               "%d: osi - srvstate = %s (ref %u)",
+                                               service->state->id,
+                                               srvstate_names[service->srvstate],
+                                               kref_read(&service->ref_count));
                        status = VCHIQ_ERROR;
                        VCHIQ_SERVICE_STATS_INC(service, error_count);
                        vchiq_release_service_internal(service);
@@ -3449,10 +3444,13 @@ int vchiq_dump_service_state(void *dump_context, struct vchiq_service *service)
        char buf[80];
        int len;
        int err;
+       unsigned int ref_count;
 
+       /*Don't include the lock just taken*/
+       ref_count = kref_read(&service->ref_count) - 1;
        len = scnprintf(buf, sizeof(buf), "Service %u: %s (ref %u)",
-               service->localport, srvstate_names[service->srvstate],
-               service->ref_count - 1); /*Don't include the lock just taken*/
+                       service->localport, srvstate_names[service->srvstate],
+                       ref_count);
 
        if (service->srvstate != VCHIQ_SRVSTATE_FREE) {
                char remoteport[30];
index c31f953..cedd8e7 100644 (file)
@@ -7,6 +7,8 @@
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <linux/kthread.h>
+#include <linux/kref.h>
+#include <linux/rcupdate.h>
 #include <linux/wait.h>
 
 #include "vchiq_cfg.h"
@@ -251,7 +253,8 @@ struct vchiq_slot_info {
 struct vchiq_service {
        struct vchiq_service_base base;
        unsigned int handle;
-       unsigned int ref_count;
+       struct kref ref_count;
+       struct rcu_head rcu;
        int srvstate;
        vchiq_userdata_term userdata_term;
        unsigned int localport;
@@ -464,7 +467,7 @@ struct vchiq_state {
                int error_count;
        } stats;
 
-       struct vchiq_service *services[VCHIQ_MAX_SERVICES];
+       struct vchiq_service __rcu *services[VCHIQ_MAX_SERVICES];
        struct vchiq_service_quota service_quotas[VCHIQ_MAX_SERVICES];
        struct vchiq_slot_info slot_info[VCHIQ_MAX_SLOTS];
 
@@ -545,12 +548,13 @@ request_poll(struct vchiq_state *state, struct vchiq_service *service,
 static inline struct vchiq_service *
 handle_to_service(unsigned int handle)
 {
+       int idx = handle & (VCHIQ_MAX_SERVICES - 1);
        struct vchiq_state *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) &
                (VCHIQ_MAX_STATES - 1)];
+
        if (!state)
                return NULL;
-
-       return state->services[handle & (VCHIQ_MAX_SERVICES - 1)];
+       return rcu_dereference(state->services[idx]);
 }
 
 extern struct vchiq_service *
@@ -568,7 +572,13 @@ find_closed_service_for_instance(struct vchiq_instance *instance,
        unsigned int handle);
 
 extern struct vchiq_service *
-next_service_by_instance(struct vchiq_state *state, struct vchiq_instance *instance,
+__next_service_by_instance(struct vchiq_state *state,
+                          struct vchiq_instance *instance,
+                          int *pidx);
+
+extern struct vchiq_service *
+next_service_by_instance(struct vchiq_state *state,
+                        struct vchiq_instance *instance,
                         int *pidx);
 
 extern void
@@ -590,18 +600,6 @@ vchiq_complete_bulk(struct vchiq_bulk *bulk);
 extern void
 remote_event_signal(struct remote_event *event);
 
-void
-vchiq_platform_check_suspend(struct vchiq_state *state);
-
-extern void
-vchiq_platform_paused(struct vchiq_state *state);
-
-extern enum vchiq_status
-vchiq_platform_resume(struct vchiq_state *state);
-
-extern void
-vchiq_platform_resumed(struct vchiq_state *state);
-
 extern int
 vchiq_dump(void *dump_context, const char *str, int len);
 
@@ -648,9 +646,6 @@ vchiq_platform_conn_state_changed(struct vchiq_state *state,
                                  enum vchiq_connstate newstate);
 
 extern void
-vchiq_platform_handle_timeout(struct vchiq_state *state);
-
-extern void
 vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newstate);
 
 extern void
index 07c6a3d..39b77ea 100644 (file)
@@ -13,7 +13,6 @@
 #define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3) \
                        (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3))
 #define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service)
-#define VCHIQ_GET_SERVICE_FOURCC(service)   vchiq_get_service_fourcc(service)
 
 enum vchiq_reason {
        VCHIQ_SERVICE_OPENED,         /* service, -, -             */
@@ -128,7 +127,6 @@ extern enum vchiq_status vchiq_bulk_receive_handle(unsigned int service,
        enum vchiq_bulk_mode mode);
 extern int   vchiq_get_client_id(unsigned int service);
 extern void *vchiq_get_service_userdata(unsigned int service);
-extern int   vchiq_get_service_fourcc(unsigned int service);
 extern void vchiq_get_config(struct vchiq_config *config);
 extern enum vchiq_status vchiq_set_service_option(unsigned int service,
        enum vchiq_service_option option, int value);
index 25867cb..337266a 100644 (file)
@@ -63,6 +63,6 @@ bool CARDbSetPhyParameter(struct vnt_private *priv, u8 bb_type);
 bool CARDbUpdateTSF(struct vnt_private *priv, unsigned char byRxRate,
                    u64 qwBSSTimestamp);
 bool CARDbSetBeaconPeriod(struct vnt_private *priv,
-                          unsigned short wBeaconInterval);
+                         unsigned short wBeaconInterval);
 
 #endif /* __CARD_H__ */
index f69fc68..5c86cc6 100644 (file)
@@ -133,7 +133,8 @@ static int device_init_td1_ring(struct vnt_private *priv);
 static int  device_rx_srv(struct vnt_private *priv, unsigned int idx);
 static int  device_tx_srv(struct vnt_private *priv, unsigned int idx);
 static bool device_alloc_rx_buf(struct vnt_private *, struct vnt_rx_desc *);
-static void device_free_rx_buf(struct vnt_private *priv, struct vnt_rx_desc *rd);
+static void device_free_rx_buf(struct vnt_private *priv,
+                              struct vnt_rx_desc *rd);
 static void device_init_registers(struct vnt_private *priv);
 static void device_free_tx_buf(struct vnt_private *, struct vnt_tx_desc *);
 static void device_free_td0_ring(struct vnt_private *priv);
@@ -442,7 +443,10 @@ static bool device_init_rings(struct vnt_private *priv)
 
        /*allocate all RD/TD rings a single pool*/
        vir_pool = dma_alloc_coherent(&priv->pcid->dev,
-                                     priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) + priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) + priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) + priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc),
+                                     priv->opts.rx_descs0 * sizeof(struct vnt_rx_desc) +
+                                     priv->opts.rx_descs1 * sizeof(struct vnt_rx_desc) +
+                                     priv->opts.tx_descs[0] * sizeof(struct vnt_tx_desc) +
+                                     priv->opts.tx_descs[1] * sizeof(struct vnt_tx_desc),
                                      &priv->pool_dma, GFP_ATOMIC);
        if (!vir_pool) {
                dev_err(&priv->pcid->dev, "allocate desc dma memory failed\n");
index bfd598a..6b04076 100644 (file)
@@ -58,14 +58,11 @@ void PSvEnablePowerSaving(struct vnt_private *priv,
        if (priv->op_mode != NL80211_IFTYPE_ADHOC) {
                /* set AID */
                VNSvOutPortW(priv->PortOffset + MAC_REG_AIDATIM, wAID);
-       } else {
-               /* set ATIM Window */
-#if 0 /* TODO atim window */
-               MACvWriteATIMW(priv->PortOffset, pMgmt->wCurrATIMWindow);
-#endif
        }
+
        /* Set AutoSleep */
        MACvRegBitsOn(priv->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
+
        /* Set HWUTSF */
        MACvRegBitsOn(priv->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
 
@@ -101,10 +98,13 @@ void PSvDisablePowerSaving(struct vnt_private *priv)
 {
        /* disable power saving hw function */
        MACbPSWakeup(priv);
+
        /* clear AutoSleep */
        MACvRegBitsOff(priv->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
+
        /* clear HWUTSF */
        MACvRegBitsOff(priv->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
+
        /* set always listen beacon */
        MACvRegBitsOn(priv->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
 
index b64c0d8..375f54e 100644 (file)
@@ -9,13 +9,11 @@ vt6656_stage-y +=     main_usb.o \
                        baseband.o \
                        wcmd.o\
                        rxtx.o \
-                       dpc.o \
                        power.o \
                        key.o \
                        rf.o \
                        usbpipe.o \
                        channel.o \
-                       firmware.o \
-                       int.o
+                       firmware.o
 
 obj-$(CONFIG_VT6656) +=        vt6656_stage.o
index f18e059..a19a563 100644 (file)
@@ -22,6 +22,8 @@
  *
  */
 
+#include <linux/bits.h>
+#include <linux/kernel.h>
 #include "mac.h"
 #include "baseband.h"
 #include "rf.h"
@@ -132,7 +134,6 @@ unsigned int vnt_get_frame_time(u8 preamble_type, u8 pkt_type,
 {
        unsigned int frame_time;
        unsigned int preamble;
-       unsigned int tmp;
        unsigned int rate = 0;
 
        if (tx_rate > RATE_54M)
@@ -146,20 +147,11 @@ unsigned int vnt_get_frame_time(u8 preamble_type, u8 pkt_type,
                else
                        preamble = 192;
 
-               frame_time = (frame_length * 80) / rate;
-               tmp = (frame_time * rate) / 80;
-
-               if (frame_length != tmp)
-                       frame_time++;
-
+               frame_time = DIV_ROUND_UP(frame_length * 80, rate);
                return preamble + frame_time;
        }
-       frame_time = (frame_length * 8 + 22) / rate;
-       tmp = ((frame_time * rate) - 22) / 8;
-
-       if (frame_length != tmp)
-               frame_time++;
 
+       frame_time = DIV_ROUND_UP(frame_length * 8 + 22, rate);
        frame_time = frame_time * 4;
 
        if (pkt_type != PK_TYPE_11A)
@@ -213,11 +205,7 @@ void vnt_get_phy_field(struct vnt_private *priv, u32 frame_length,
 
                break;
        case RATE_5M:
-               count = (bit_count * 10) / 55;
-               tmp = (count * 55) / 10;
-
-               if (tmp != bit_count)
-                       count++;
+               count = DIV_ROUND_UP(bit_count * 10, 55);
 
                if (preamble_type == 1)
                        phy->signal = 0x0a;
@@ -367,9 +355,6 @@ int vnt_vt3184_init(struct vnt_private *priv)
        int ret = 0;
        u16 length;
        u8 *addr;
-       u8 *agc;
-       u16 length_agc;
-       u8 array[256];
        u8 data;
 
        ret = vnt_control_in(priv, MESSAGE_TYPE_READ, 0, MESSAGE_REQUEST_EEPROM,
@@ -386,8 +371,6 @@ int vnt_vt3184_init(struct vnt_private *priv)
                priv->bb_rx_conf = vnt_vt3184_al2230[10];
                length = sizeof(vnt_vt3184_al2230);
                addr = vnt_vt3184_al2230;
-               agc = vnt_vt3184_agc;
-               length_agc = sizeof(vnt_vt3184_agc);
 
                priv->bb_vga[0] = 0x1C;
                priv->bb_vga[1] = 0x10;
@@ -398,8 +381,6 @@ int vnt_vt3184_init(struct vnt_private *priv)
                priv->bb_rx_conf = vnt_vt3184_al2230[10];
                length = sizeof(vnt_vt3184_al2230);
                addr = vnt_vt3184_al2230;
-               agc = vnt_vt3184_agc;
-               length_agc = sizeof(vnt_vt3184_agc);
 
                addr[0xd7] = 0x06;
 
@@ -413,8 +394,6 @@ int vnt_vt3184_init(struct vnt_private *priv)
                priv->bb_rx_conf = vnt_vt3184_vt3226d0[10];
                length = sizeof(vnt_vt3184_vt3226d0);
                addr = vnt_vt3184_vt3226d0;
-               agc = vnt_vt3184_agc;
-               length_agc = sizeof(vnt_vt3184_agc);
 
                priv->bb_vga[0] = 0x20;
                priv->bb_vga[1] = 0x10;
@@ -430,8 +409,6 @@ int vnt_vt3184_init(struct vnt_private *priv)
                priv->bb_rx_conf = vnt_vt3184_vt3226d0[10];
                length = sizeof(vnt_vt3184_vt3226d0);
                addr = vnt_vt3184_vt3226d0;
-               agc = vnt_vt3184_agc;
-               length_agc = sizeof(vnt_vt3184_agc);
 
                priv->bb_vga[0] = 0x20;
                priv->bb_vga[1] = 0x10;
@@ -447,17 +424,14 @@ int vnt_vt3184_init(struct vnt_private *priv)
                goto end;
        }
 
-       memcpy(array, addr, length);
-
        ret = vnt_control_out_blocks(priv, VNT_REG_BLOCK_SIZE,
-                                    MESSAGE_REQUEST_BBREG, length, array);
+                                    MESSAGE_REQUEST_BBREG, length, addr);
        if (ret)
                goto end;
 
-       memcpy(array, agc, length_agc);
-
        ret = vnt_control_out(priv, MESSAGE_TYPE_WRITE, 0,
-                             MESSAGE_REQUEST_BBAGC, length_agc, array);
+                             MESSAGE_REQUEST_BBAGC,
+                             sizeof(vnt_vt3184_agc), vnt_vt3184_agc);
        if (ret)
                goto end;
 
@@ -468,7 +442,7 @@ int vnt_vt3184_init(struct vnt_private *priv)
                if (ret)
                        goto end;
 
-               ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+               ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, BIT(0));
                if (ret)
                        goto end;
        } else if (priv->rf_type == RF_VT3226D0) {
@@ -477,7 +451,7 @@ int vnt_vt3184_init(struct vnt_private *priv)
                if (ret)
                        goto end;
 
-               ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, 0x01);
+               ret = vnt_mac_reg_bits_on(priv, MAC_REG_PAPEDELAY, BIT(0));
                if (ret)
                        goto end;
        }
index 7958fc1..dc3ab10 100644 (file)
@@ -26,6 +26,7 @@
  *
  */
 
+#include <linux/bits.h>
 #include "device.h"
 #include "card.h"
 #include "baseband.h"
@@ -63,7 +64,8 @@ void vnt_set_channel(struct vnt_private *priv, u32 connection_channel)
        vnt_mac_reg_bits_on(priv, MAC_REG_MACCR, MACCR_CLRNAV);
 
        /* Set Channel[7] = 0 to tell H/W channel is changing now. */
-       vnt_mac_reg_bits_off(priv, MAC_REG_CHANNEL, 0xb0);
+       vnt_mac_reg_bits_off(priv, MAC_REG_CHANNEL,
+                            (BIT(7) | BIT(5) | BIT(4)));
 
        vnt_control_out(priv, MESSAGE_TYPE_SELECT_CHANNEL,
                        connection_channel, 0, 0, NULL);
index 3a83a9e..703597a 100644 (file)
@@ -18,6 +18,7 @@
 #ifndef __DESC_H__
 #define __DESC_H__
 
+#include <linux/bits.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 
 /*
  * bits in the RSR register
  */
-#define RSR_ADDRBROAD       0x80
-#define RSR_ADDRMULTI       0x40
+#define RSR_ADDRBROAD       BIT(7)
+#define RSR_ADDRMULTI       BIT(6)
 #define RSR_ADDRUNI         0x00
-#define RSR_IVLDTYP         0x20        /* invalid packet type */
-#define RSR_IVLDLEN         0x10        /* invalid len (> 2312 byte) */
-#define RSR_BSSIDOK         0x08
-#define RSR_CRCOK           0x04
-#define RSR_BCNSSIDOK       0x02
-#define RSR_ADDROK          0x01
+#define RSR_IVLDTYP         BIT(5)     /* invalid packet type */
+#define RSR_IVLDLEN         BIT(4)     /* invalid len (> 2312 byte) */
+#define RSR_BSSIDOK         BIT(3)
+#define RSR_CRCOK           BIT(2)
+#define RSR_BCNSSIDOK       BIT(1)
+#define RSR_ADDROK          BIT(0)
 
 /*
  * bits in the new RSR register
  */
-#define NEWRSR_DECRYPTOK    0x10
-#define NEWRSR_CFPIND       0x08
-#define NEWRSR_HWUTSF       0x04
-#define NEWRSR_BCNHITAID    0x02
-#define NEWRSR_BCNHITAID0   0x01
+#define NEWRSR_DECRYPTOK    BIT(4)
+#define NEWRSR_CFPIND       BIT(3)
+#define NEWRSR_HWUTSF       BIT(2)
+#define NEWRSR_BCNHITAID    BIT(1)
+#define NEWRSR_BCNHITAID0   BIT(0)
 
 /*
  * bits in the TSR register
  */
-#define TSR_RETRYTMO        0x08
-#define TSR_TMO             0x04
-#define TSR_ACKDATA         0x02
-#define TSR_VALID           0x01
+#define TSR_RETRYTMO        BIT(3)
+#define TSR_TMO             BIT(2)
+#define TSR_ACKDATA         BIT(1)
+#define TSR_VALID           BIT(0)
 
 #define FIFOCTL_AUTO_FB_1   0x1000
 #define FIFOCTL_AUTO_FB_0   0x0800
index fe6c112..e6ee941 100644 (file)
@@ -16,6 +16,7 @@
 #ifndef __DEVICE_H__
 #define __DEVICE_H__
 
+#include <linux/bits.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #define EEP_OFS_OFDMA_PWR_TBL  0x50
 
 /* Bits in EEP_OFS_ANTENNA */
-#define EEP_ANTENNA_MAIN       0x1
-#define EEP_ANTENNA_AUX                0x2
-#define EEP_ANTINV             0x4
+#define EEP_ANTENNA_MAIN       BIT(0)
+#define EEP_ANTENNA_AUX                BIT(1)
+#define EEP_ANTINV             BIT(2)
 
 /* Bits in EEP_OFS_RADIOCTL */
-#define EEP_RADIOCTL_ENABLE    0x80
+#define EEP_RADIOCTL_ENABLE    BIT(7)
 
 /* control commands */
 #define MESSAGE_TYPE_READ              0x1
@@ -227,7 +228,6 @@ struct vnt_rcb {
        void *priv;
        struct urb *urb;
        struct sk_buff *skb;
-       int in_use;
 };
 
 /* used to track bulk out irps */
@@ -244,7 +244,6 @@ struct vnt_usb_send_context {
        u8 pkt_no;
        u8 pkt_type;
        u8 need_ack;
-       u8 fb_option;
        bool in_use;
        unsigned char data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS];
 };
@@ -254,16 +253,6 @@ struct vnt_usb_send_context {
  */
 struct vnt_interrupt_buffer {
        u8 *data_buf;
-       bool in_use;
-};
-
-/*++ NDIS related */
-
-enum {
-       STATUS_SUCCESS = 0,
-       STATUS_FAILURE,
-       STATUS_RESOURCES,
-       STATUS_PENDING,
 };
 
 /* flags for options */
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
deleted file mode 100644 (file)
index a0b60e7..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
- * All rights reserved.
- *
- * File: dpc.c
- *
- * Purpose: handle dpc rx functions
- *
- * Author: Lyndon Chen
- *
- * Date: May 20, 2003
- *
- * Functions:
- *
- * Revision History:
- *
- */
-
-#include "dpc.h"
-#include "device.h"
-#include "mac.h"
-#include "baseband.h"
-#include "rf.h"
-
-int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb,
-               unsigned long bytes_received)
-{
-       struct ieee80211_hw *hw = priv->hw;
-       struct ieee80211_supported_band *sband;
-       struct sk_buff *skb;
-       struct ieee80211_rx_status *rx_status;
-       struct vnt_rx_header *head;
-       struct vnt_rx_tail *tail;
-       u32 frame_size;
-       int ii;
-       u16 rx_bitrate, pay_load_with_padding;
-       u8 rate_idx = 0;
-       long rx_dbm;
-
-       skb = ptr_rcb->skb;
-       rx_status = IEEE80211_SKB_RXCB(skb);
-
-       /* [31:16]RcvByteCount ( not include 4-byte Status ) */
-       head = (struct vnt_rx_header *)skb->data;
-       frame_size = head->wbk_status >> 16;
-       frame_size += 4;
-
-       if (bytes_received != frame_size) {
-               dev_dbg(&priv->usb->dev, "------- WRONG Length 1\n");
-               return false;
-       }
-
-       if ((bytes_received > 2372) || (bytes_received <= 40)) {
-               /* Frame Size error drop this packet.*/
-               dev_dbg(&priv->usb->dev, "------ WRONG Length 2\n");
-               return false;
-       }
-
-       /* real Frame Size = USBframe_size -4WbkStatus - 4RxStatus */
-       /* -8TSF - 4RSR - 4SQ3 - ?Padding */
-
-       /* if SQ3 the range is 24~27, if no SQ3 the range is 20~23 */
-
-       /*Fix hardware bug => PLCP_Length error */
-       if (((bytes_received - head->pay_load_len) > 27) ||
-           ((bytes_received - head->pay_load_len) < 24) ||
-           (bytes_received < head->pay_load_len)) {
-               dev_dbg(&priv->usb->dev, "Wrong PLCP Length %x\n",
-                       head->pay_load_len);
-               return false;
-       }
-
-       sband = hw->wiphy->bands[hw->conf.chandef.chan->band];
-       rx_bitrate = head->rx_rate * 5; /* rx_rate * 5 */
-
-       for (ii = 0; ii < sband->n_bitrates; ii++) {
-               if (sband->bitrates[ii].bitrate == rx_bitrate) {
-                       rate_idx = ii;
-                               break;
-               }
-       }
-
-       if (ii == sband->n_bitrates) {
-               dev_dbg(&priv->usb->dev, "Wrong Rx Bit Rate %d\n", rx_bitrate);
-               return false;
-       }
-
-       pay_load_with_padding = ((head->pay_load_len / 4) +
-               ((head->pay_load_len % 4) ? 1 : 0)) * 4;
-
-       tail = (struct vnt_rx_tail *)(skb->data +
-                                     sizeof(*head) + pay_load_with_padding);
-       priv->tsf_time = le64_to_cpu(tail->tsf_time);
-
-       if (tail->rsr & (RSR_IVLDTYP | RSR_IVLDLEN))
-               return false;
-
-       vnt_rf_rssi_to_dbm(priv, tail->rssi, &rx_dbm);
-
-       priv->bb_pre_ed_rssi = (u8)-rx_dbm + 1;
-       priv->current_rssi = priv->bb_pre_ed_rssi;
-
-       skb_pull(skb, sizeof(*head));
-       skb_trim(skb, head->pay_load_len);
-
-       rx_status->mactime = priv->tsf_time;
-       rx_status->band = hw->conf.chandef.chan->band;
-       rx_status->signal = rx_dbm;
-       rx_status->flag = 0;
-       rx_status->freq = hw->conf.chandef.chan->center_freq;
-
-       if (!(tail->rsr & RSR_CRCOK))
-               rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
-
-       rx_status->rate_idx = rate_idx;
-
-       if (tail->new_rsr & NEWRSR_DECRYPTOK)
-               rx_status->flag |= RX_FLAG_DECRYPTED;
-
-       ieee80211_rx_irqsafe(priv->hw, skb);
-
-       return true;
-}
diff --git a/drivers/staging/vt6656/dpc.h b/drivers/staging/vt6656/dpc.h
deleted file mode 100644 (file)
index e080add..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
- * All rights reserved.
- *
- * File: dpc.h
- *
- * Purpose:
- *
- * Author: Jerry Chen
- *
- * Date: Jun. 27, 2002
- *
- */
-
-#ifndef __DPC_H__
-#define __DPC_H__
-
-#include "device.h"
-
-int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb,
-               unsigned long bytes_received);
-
-#endif /* __RXTX_H__ */
diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c
deleted file mode 100644 (file)
index af21586..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
- * All rights reserved.
- *
- * File: int.c
- *
- * Purpose: Handle USB interrupt endpoint
- *
- * Author: Jerry Chen
- *
- * Date: Apr. 2, 2004
- *
- * Functions:
- *
- * Revision History:
- *      04-02-2004 Jerry Chen:  Initial release
- *
- */
-
-#include "int.h"
-#include "mac.h"
-#include "power.h"
-#include "usbpipe.h"
-
-static const u8 fallback_rate0[5][5] = {
-       {RATE_18M, RATE_18M, RATE_12M, RATE_12M, RATE_12M},
-       {RATE_24M, RATE_24M, RATE_18M, RATE_12M, RATE_12M},
-       {RATE_36M, RATE_36M, RATE_24M, RATE_18M, RATE_18M},
-       {RATE_48M, RATE_48M, RATE_36M, RATE_24M, RATE_24M},
-       {RATE_54M, RATE_54M, RATE_48M, RATE_36M, RATE_36M}
-};
-
-static const u8 fallback_rate1[5][5] = {
-       {RATE_18M, RATE_18M, RATE_12M, RATE_6M, RATE_6M},
-       {RATE_24M, RATE_24M, RATE_18M, RATE_6M, RATE_6M},
-       {RATE_36M, RATE_36M, RATE_24M, RATE_12M, RATE_12M},
-       {RATE_48M, RATE_48M, RATE_24M, RATE_12M, RATE_12M},
-       {RATE_54M, RATE_54M, RATE_36M, RATE_18M, RATE_18M}
-};
-
-int vnt_int_start_interrupt(struct vnt_private *priv)
-{
-       int ret = 0;
-       unsigned long flags;
-
-       dev_dbg(&priv->usb->dev, "---->Interrupt Polling Thread\n");
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       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)
-{
-       struct vnt_usb_send_context *context;
-       struct ieee80211_tx_info *info;
-       struct ieee80211_rate *rate;
-       u8 tx_retry = (tsr & 0xf0) >> 4;
-       s8 idx;
-
-       if (pkt_no >= priv->num_tx_context)
-               return -EINVAL;
-
-       context = priv->tx_context[pkt_no];
-
-       if (!context->skb)
-               return -EINVAL;
-
-       info = IEEE80211_SKB_CB(context->skb);
-       idx = info->control.rates[0].idx;
-
-       if (context->fb_option && !(tsr & (TSR_TMO | TSR_RETRYTMO))) {
-               u8 tx_rate;
-               u8 retry = tx_retry;
-
-               rate = ieee80211_get_tx_rate(priv->hw, info);
-               tx_rate = rate->hw_value - RATE_18M;
-
-               if (retry > 4)
-                       retry = 4;
-
-               if (context->fb_option == AUTO_FB_0)
-                       tx_rate = fallback_rate0[tx_rate][retry];
-               else if (context->fb_option == AUTO_FB_1)
-                       tx_rate = fallback_rate1[tx_rate][retry];
-
-               if (info->band == NL80211_BAND_5GHZ)
-                       idx = tx_rate - RATE_6M;
-               else
-                       idx = tx_rate;
-       }
-
-       ieee80211_tx_info_clear_status(info);
-
-       info->status.rates[0].count = tx_retry;
-
-       if (!(tsr & TSR_TMO)) {
-               info->status.rates[0].idx = idx;
-
-               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
-                       info->flags |= IEEE80211_TX_STAT_ACK;
-       }
-
-       ieee80211_tx_status_irqsafe(priv->hw, context->skb);
-
-       context->in_use = false;
-
-       return 0;
-}
-
-void vnt_int_process_data(struct vnt_private *priv)
-{
-       struct vnt_interrupt_data *int_data;
-       struct ieee80211_low_level_stats *low_stats = &priv->low_stats;
-
-       dev_dbg(&priv->usb->dev, "---->s_nsInterruptProcessData\n");
-
-       int_data = (struct vnt_interrupt_data *)priv->int_buf.data_buf;
-
-       if (int_data->tsr0 & TSR_VALID)
-               vnt_int_report_rate(priv, int_data->pkt0, int_data->tsr0);
-
-       if (int_data->tsr1 & TSR_VALID)
-               vnt_int_report_rate(priv, int_data->pkt1, int_data->tsr1);
-
-       if (int_data->tsr2 & TSR_VALID)
-               vnt_int_report_rate(priv, int_data->pkt2, int_data->tsr2);
-
-       if (int_data->tsr3 & TSR_VALID)
-               vnt_int_report_rate(priv, int_data->pkt3, int_data->tsr3);
-
-       if (int_data->isr0 != 0) {
-               if (int_data->isr0 & ISR_BNTX &&
-                   priv->op_mode == NL80211_IFTYPE_AP)
-                       vnt_schedule_command(priv, WLAN_CMD_BECON_SEND);
-
-               if (int_data->isr0 & ISR_TBTT &&
-                   priv->hw->conf.flags & IEEE80211_CONF_PS) {
-                       if (!priv->wake_up_count)
-                               priv->wake_up_count =
-                                       priv->hw->conf.listen_interval;
-
-                       --priv->wake_up_count;
-
-                       /* Turn on wake up to listen next beacon */
-                       if (priv->wake_up_count == 1)
-                               vnt_schedule_command(priv,
-                                                    WLAN_CMD_TBTT_WAKEUP);
-               }
-               priv->current_tsf = le64_to_cpu(int_data->tsf);
-
-               low_stats->dot11RTSSuccessCount += int_data->rts_success;
-               low_stats->dot11RTSFailureCount += int_data->rts_fail;
-               low_stats->dot11ACKFailureCount += int_data->ack_fail;
-               low_stats->dot11FCSErrorCount += int_data->fcs_err;
-       }
-
-       priv->int_buf.in_use = false;
-}
diff --git a/drivers/staging/vt6656/int.h b/drivers/staging/vt6656/int.h
deleted file mode 100644 (file)
index 8a6d605..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
- * All rights reserved.
- *
- * File: int.h
- *
- * Purpose:
- *
- * Author: Jerry Chen
- *
- * Date: Apr. 2, 2004
- *
- */
-
-#ifndef __INT_H__
-#define __INT_H__
-
-#include "device.h"
-
-struct vnt_interrupt_data {
-       u8 tsr0;
-       u8 pkt0;
-       u16 time0;
-       u8 tsr1;
-       u8 pkt1;
-       u16 time1;
-       u8 tsr2;
-       u8 pkt2;
-       u16 time2;
-       u8 tsr3;
-       u8 pkt3;
-       u16 time3;
-       __le64 tsf;
-       u8 isr0;
-       u8 isr1;
-       u8 rts_success;
-       u8 rts_fail;
-       u8 ack_fail;
-       u8 fcs_err;
-       u8 sw[2];
-} __packed;
-
-int vnt_int_start_interrupt(struct vnt_private *priv);
-void vnt_int_process_data(struct vnt_private *priv);
-
-#endif /* __INT_H__ */
index dcd933a..41b73f9 100644 (file)
@@ -144,11 +144,14 @@ int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
                break;
        case WLAN_CIPHER_SUITE_CCMP:
                if (priv->local_id <= MAC_REVISION_A1)
-                       return -EINVAL;
+                       return -EOPNOTSUPP;
 
                key_dec_mode = KEY_CTL_CCMP;
 
                key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+               break;
+       default:
+               return -EOPNOTSUPP;
        }
 
        if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
index 0a42308..c532b27 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef __MAC_H__
 #define __MAC_H__
 
+#include <linux/bits.h>
 #include "device.h"
 
 #define REV_ID_VT3253_A0       0x00
 #define MAC_REG_RSPINF_A_72    0xfc
 
 /* Bits in the I2MCFG EEPROM register */
-#define I2MCFG_BOUNDCTL                0x80
-#define I2MCFG_WAITCTL         0x20
-#define I2MCFG_SCLOECTL                0x10
-#define I2MCFG_WBUSYCTL                0x08
-#define I2MCFG_NORETRY         0x04
-#define I2MCFG_I2MLDSEQ                0x02
-#define I2MCFG_I2CMFAST                0x01
+#define I2MCFG_BOUNDCTL                BIT(7)
+#define I2MCFG_WAITCTL         BIT(5)
+#define I2MCFG_SCLOECTL                BIT(4)
+#define I2MCFG_WBUSYCTL                BIT(3)
+#define I2MCFG_NORETRY         BIT(2)
+#define I2MCFG_I2MLDSEQ                BIT(1)
+#define I2MCFG_I2CMFAST                BIT(0)
 
 /* Bits in the I2MCSR EEPROM register */
-#define I2MCSR_EEMW            0x80
-#define I2MCSR_EEMR            0x40
-#define I2MCSR_AUTOLD          0x08
-#define I2MCSR_NACK            0x02
-#define I2MCSR_DONE            0x01
+#define I2MCSR_EEMW            BIT(7)
+#define I2MCSR_EEMR            BIT(6)
+#define I2MCSR_AUTOLD          BIT(3)
+#define I2MCSR_NACK            BIT(1)
+#define I2MCSR_DONE            BIT(0)
 
 /* Bits in the TMCTL register */
-#define TMCTL_TSUSP            0x04
-#define TMCTL_TMD              0x02
-#define TMCTL_TE               0x01
+#define TMCTL_TSUSP            BIT(2)
+#define TMCTL_TMD              BIT(1)
+#define TMCTL_TE               BIT(0)
 
 /* Bits in the TFTCTL register */
-#define TFTCTL_HWUTSF          0x80
-#define TFTCTL_TBTTSYNC                0x40
-#define TFTCTL_HWUTSFEN                0x20
-#define TFTCTL_TSFCNTRRD       0x10
-#define TFTCTL_TBTTSYNCEN      0x08
-#define TFTCTL_TSFSYNCEN       0x04
-#define TFTCTL_TSFCNTRST       0x02
-#define TFTCTL_TSFCNTREN       0x01
+#define TFTCTL_HWUTSF          BIT(7)
+#define TFTCTL_TBTTSYNC                BIT(6)
+#define TFTCTL_HWUTSFEN                BIT(5)
+#define TFTCTL_TSFCNTRRD       BIT(4)
+#define TFTCTL_TBTTSYNCEN      BIT(3)
+#define TFTCTL_TSFSYNCEN       BIT(2)
+#define TFTCTL_TSFCNTRST       BIT(1)
+#define TFTCTL_TSFCNTREN       BIT(0)
 
 /* Bits in the EnhanceCFG_0 register */
 #define EnCFG_BBType_a         0x00
-#define EnCFG_BBType_b         0x01
-#define EnCFG_BBType_g         0x02
-#define EnCFG_BBType_MASK      0x03
-#define EnCFG_ProtectMd                0x20
+#define EnCFG_BBType_b         BIT(0)
+#define EnCFG_BBType_g         BIT(1)
+#define EnCFG_BBType_MASK      (BIT(0) | BIT(1))
+#define EnCFG_ProtectMd                BIT(5)
 
 /* Bits in the EnhanceCFG_1 register */
-#define EnCFG_BcnSusInd                0x01
-#define EnCFG_BcnSusClr                0x02
+#define EnCFG_BcnSusInd                BIT(0)
+#define EnCFG_BcnSusClr                BIT(1)
 
 /* Bits in the EnhanceCFG_2 register */
-#define EnCFG_NXTBTTCFPSTR     0x01
-#define EnCFG_BarkerPream      0x02
-#define EnCFG_PktBurstMode     0x04
+#define EnCFG_NXTBTTCFPSTR     BIT(0)
+#define EnCFG_BarkerPream      BIT(1)
+#define EnCFG_PktBurstMode     BIT(2)
 
 /* Bits in the CFG register */
-#define CFG_TKIPOPT            0x80
-#define CFG_RXDMAOPT           0x40
-#define CFG_TMOT_SW            0x20
-#define CFG_TMOT_HWLONG                0x10
+#define CFG_TKIPOPT            BIT(7)
+#define CFG_RXDMAOPT           BIT(6)
+#define CFG_TMOT_SW            BIT(5)
+#define CFG_TMOT_HWLONG                BIT(4)
 #define CFG_TMOT_HW            0x00
-#define CFG_CFPENDOPT          0x08
-#define CFG_BCNSUSEN           0x04
-#define CFG_NOTXTIMEOUT                0x02
-#define CFG_NOBUFOPT           0x01
+#define CFG_CFPENDOPT          BIT(3)
+#define CFG_BCNSUSEN           BIT(2)
+#define CFG_NOTXTIMEOUT                BIT(1)
+#define CFG_NOBUFOPT           BIT(0)
 
 /* Bits in the TEST register */
-#define TEST_LBEXT             0x80
-#define TEST_LBINT             0x40
+#define TEST_LBEXT             BIT(7)
+#define TEST_LBINT             BIT(6)
 #define TEST_LBNONE            0x00
-#define TEST_SOFTINT           0x20
-#define TEST_CONTTX            0x10
-#define TEST_TXPE              0x08
-#define TEST_NAVDIS            0x04
-#define TEST_NOCTS             0x02
-#define TEST_NOACK             0x01
+#define TEST_SOFTINT           BIT(5)
+#define TEST_CONTTX            BIT(4)
+#define TEST_TXPE              BIT(3)
+#define TEST_NAVDIS            BIT(2)
+#define TEST_NOCTS             BIT(1)
+#define TEST_NOACK             BIT(0)
 
 /* Bits in the HOSTCR register */
-#define HOSTCR_TXONST          0x80
-#define HOSTCR_RXONST          0x40
-#define HOSTCR_ADHOC           0x20
-#define HOSTCR_AP              0x10
-#define HOSTCR_TXON            0x08
-#define HOSTCR_RXON            0x04
-#define HOSTCR_MACEN           0x02
-#define HOSTCR_SOFTRST         0x01
+#define HOSTCR_TXONST          BIT(7)
+#define HOSTCR_RXONST          BIT(6)
+#define HOSTCR_ADHOC           BIT(5)
+#define HOSTCR_AP              BIT(4)
+#define HOSTCR_TXON            BIT(3)
+#define HOSTCR_RXON            BIT(2)
+#define HOSTCR_MACEN           BIT(1)
+#define HOSTCR_SOFTRST         BIT(0)
 
 /* Bits in the MACCR register */
-#define MACCR_SYNCFLUSHOK      0x04
-#define MACCR_SYNCFLUSH                0x02
-#define MACCR_CLRNAV           0x01
+#define MACCR_SYNCFLUSHOK      BIT(2)
+#define MACCR_SYNCFLUSH                BIT(1)
+#define MACCR_CLRNAV           BIT(0)
 
 /* Bits in the RCR register */
-#define RCR_SSID               0x80
-#define RCR_RXALLTYPE          0x40
-#define RCR_UNICAST            0x20
-#define RCR_BROADCAST          0x10
-#define RCR_MULTICAST          0x08
-#define RCR_WPAERR             0x04
-#define RCR_ERRCRC             0x02
-#define RCR_BSSID              0x01
+#define RCR_SSID               BIT(7)
+#define RCR_RXALLTYPE          BIT(6)
+#define RCR_UNICAST            BIT(5)
+#define RCR_BROADCAST          BIT(4)
+#define RCR_MULTICAST          BIT(3)
+#define RCR_WPAERR             BIT(2)
+#define RCR_ERRCRC             BIT(1)
+#define RCR_BSSID              BIT(0)
 
 /* Bits in the TCR register */
-#define TCR_SYNCDCFOPT         0x02
-#define TCR_AUTOBCNTX          0x01
+#define TCR_SYNCDCFOPT         BIT(1)
+#define TCR_AUTOBCNTX          BIT(0)
 
 /* ISR1 */
-#define ISR_GPIO3              0x40
-#define ISR_RXNOBUF            0x08
-#define ISR_MIBNEARFULL                0x04
-#define ISR_SOFTINT            0x02
-#define ISR_FETALERR           0x01
+#define ISR_GPIO3              BIT(6)
+#define ISR_RXNOBUF            BIT(3)
+#define ISR_MIBNEARFULL                BIT(2)
+#define ISR_SOFTINT            BIT(1)
+#define ISR_FETALERR           BIT(0)
 
 #define LEDSTS_STS             0x06
 #define LEDSTS_TMLEN           0x78
 #define LEDSTS_INTER           0x06
 
 /* ISR0 */
-#define ISR_WATCHDOG           0x80
-#define ISR_SOFTTIMER          0x40
-#define ISR_GPIO0              0x20
-#define ISR_TBTT               0x10
-#define ISR_RXDMA0             0x08
-#define ISR_BNTX               0x04
-#define ISR_ACTX               0x01
+#define ISR_WATCHDOG           BIT(7)
+#define ISR_SOFTTIMER          BIT(6)
+#define ISR_GPIO0              BIT(5)
+#define ISR_TBTT               BIT(4)
+#define ISR_RXDMA0             BIT(3)
+#define ISR_BNTX               BIT(2)
+#define ISR_ACTX               BIT(0)
 
 /* Bits in the PSCFG register */
-#define PSCFG_PHILIPMD         0x40
-#define PSCFG_WAKECALEN                0x20
-#define PSCFG_WAKETMREN                0x10
-#define PSCFG_BBPSPROG         0x08
-#define PSCFG_WAKESYN          0x04
-#define PSCFG_SLEEPSYN         0x02
-#define PSCFG_AUTOSLEEP                0x01
+#define PSCFG_PHILIPMD         BIT(6)
+#define PSCFG_WAKECALEN                BIT(5)
+#define PSCFG_WAKETMREN                BIT(4)
+#define PSCFG_BBPSPROG         BIT(3)
+#define PSCFG_WAKESYN          BIT(2)
+#define PSCFG_SLEEPSYN         BIT(1)
+#define PSCFG_AUTOSLEEP                BIT(0)
 
 /* Bits in the PSCTL register */
-#define PSCTL_WAKEDONE         0x20
-#define PSCTL_PS               0x10
-#define PSCTL_GO2DOZE          0x08
-#define PSCTL_LNBCN            0x04
-#define PSCTL_ALBCN            0x02
-#define PSCTL_PSEN             0x01
+#define PSCTL_WAKEDONE         BIT(5)
+#define PSCTL_PS               BIT(4)
+#define PSCTL_GO2DOZE          BIT(3)
+#define PSCTL_LNBCN            BIT(2)
+#define PSCTL_ALBCN            BIT(1)
+#define PSCTL_PSEN             BIT(0)
 
 /* Bits in the PSPWSIG register */
-#define PSSIG_WPE3             0x80
-#define PSSIG_WPE2             0x40
-#define PSSIG_WPE1             0x20
-#define PSSIG_WRADIOPE         0x10
-#define PSSIG_SPE3             0x08
-#define PSSIG_SPE2             0x04
-#define PSSIG_SPE1             0x02
-#define PSSIG_SRADIOPE         0x01
+#define PSSIG_WPE3             BIT(7)
+#define PSSIG_WPE2             BIT(6)
+#define PSSIG_WPE1             BIT(5)
+#define PSSIG_WRADIOPE         BIT(4)
+#define PSSIG_SPE3             BIT(3)
+#define PSSIG_SPE2             BIT(2)
+#define PSSIG_SPE1             BIT(1)
+#define PSSIG_SRADIOPE         BIT(0)
 
 /* Bits in the BBREGCTL register */
-#define BBREGCTL_DONE          0x04
-#define BBREGCTL_REGR          0x02
-#define BBREGCTL_REGW          0x01
+#define BBREGCTL_DONE          BIT(2)
+#define BBREGCTL_REGR          BIT(1)
+#define BBREGCTL_REGW          BIT(0)
 
 /* Bits in the IFREGCTL register */
-#define IFREGCTL_DONE          0x04
-#define IFREGCTL_IFRF          0x02
-#define IFREGCTL_REGW          0x01
+#define IFREGCTL_DONE          BIT(2)
+#define IFREGCTL_IFRF          BIT(1)
+#define IFREGCTL_REGW          BIT(0)
 
 /* Bits in the SOFTPWRCTL register */
-#define SOFTPWRCTL_RFLEOPT     0x08
-#define SOFTPWRCTL_TXPEINV     0x02
-#define SOFTPWRCTL_SWPECTI     0x01
-#define SOFTPWRCTL_SWPAPE      0x20
-#define SOFTPWRCTL_SWCALEN     0x10
-#define SOFTPWRCTL_SWRADIO_PE  0x08
-#define SOFTPWRCTL_SWPE2       0x04
-#define SOFTPWRCTL_SWPE1       0x02
-#define SOFTPWRCTL_SWPE3       0x01
+#define SOFTPWRCTL_RFLEOPT     BIT(3)
+#define SOFTPWRCTL_TXPEINV     BIT(1)
+#define SOFTPWRCTL_SWPECTI     BIT(0)
+#define SOFTPWRCTL_SWPAPE      BIT(5)
+#define SOFTPWRCTL_SWCALEN     BIT(4)
+#define SOFTPWRCTL_SWRADIO_PE  BIT(3)
+#define SOFTPWRCTL_SWPE2       BIT(2)
+#define SOFTPWRCTL_SWPE1       BIT(1)
+#define SOFTPWRCTL_SWPE3       BIT(0)
 
 /* Bits in the GPIOCTL1 register */
-#define GPIO3_MD               0x20
-#define GPIO3_DATA             0x40
-#define GPIO3_INTMD            0x80
+#define GPIO3_MD               BIT(5)
+#define GPIO3_DATA             BIT(6)
+#define GPIO3_INTMD            BIT(7)
 
 /* Bits in the MISCFFCTL register */
-#define MISCFFCTL_WRITE                0x0001
+#define MISCFFCTL_WRITE                BIT(0)
 
 /* Loopback mode */
-#define MAC_LB_EXT             0x02
-#define MAC_LB_INTERNAL                0x01
+#define MAC_LB_EXT             BIT(1)
+#define MAC_LB_INTERNAL                BIT(0)
 #define MAC_LB_NONE            0x00
 
 /* Ethernet address filter type */
 #define PKT_TYPE_NONE          0x00 /* turn off receiver */
-#define PKT_TYPE_ALL_MULTICAST 0x80
-#define PKT_TYPE_PROMISCUOUS   0x40
-#define PKT_TYPE_DIRECTED      0x20 /* obselete */
-#define PKT_TYPE_BROADCAST     0x10
-#define PKT_TYPE_MULTICAST     0x08
-#define PKT_TYPE_ERROR_WPA     0x04
-#define PKT_TYPE_ERROR_CRC     0x02
-#define PKT_TYPE_BSSID         0x01
+#define PKT_TYPE_ALL_MULTICAST BIT(7)
+#define PKT_TYPE_PROMISCUOUS   BIT(6)
+#define PKT_TYPE_DIRECTED      BIT(5)  /* obselete */
+#define PKT_TYPE_BROADCAST     BIT(4)
+#define PKT_TYPE_MULTICAST     BIT(3)
+#define PKT_TYPE_ERROR_WPA     BIT(2)
+#define PKT_TYPE_ERROR_CRC     BIT(1)
+#define PKT_TYPE_BSSID         BIT(0)
 
 #define Default_BI              0x200
 
index 5e48b3d..8e7269c 100644 (file)
  */
 #undef __NO_VERSION__
 
+#include <linux/bits.h>
 #include <linux/etherdevice.h>
 #include <linux/file.h>
+#include <linux/kernel.h>
 #include "device.h"
 #include "card.h"
 #include "baseband.h"
 #include "power.h"
 #include "wcmd.h"
 #include "rxtx.h"
-#include "dpc.h"
 #include "rf.h"
 #include "firmware.h"
 #include "usbpipe.h"
 #include "channel.h"
-#include "int.h"
 
 /*
  * define module options
@@ -99,7 +99,6 @@ static void vnt_set_options(struct vnt_private *priv)
        priv->op_mode = NL80211_IFTYPE_UNSPECIFIED;
        priv->bb_type = BBP_TYPE_DEF;
        priv->packet_type = priv->bb_type;
-       priv->auto_fb_ctrl = AUTO_FB_0;
        priv->preamble_type = 0;
        priv->exist_sw_net_addr = false;
 }
@@ -109,7 +108,7 @@ static void vnt_set_options(struct vnt_private *priv)
  */
 static int vnt_init_registers(struct vnt_private *priv)
 {
-       int ret = 0;
+       int ret;
        struct vnt_cmd_card_init *init_cmd = &priv->init_command;
        struct vnt_rsp_card_init *init_rsp = &priv->init_response;
        u8 antenna;
@@ -145,7 +144,7 @@ static int vnt_init_registers(struct vnt_private *priv)
 
        init_cmd->init_class = DEVICE_INIT_COLD;
        init_cmd->exist_sw_net_addr = priv->exist_sw_net_addr;
-       for (ii = 0; ii < 6; ii++)
+       for (ii = 0; ii < ARRAY_SIZE(init_cmd->sw_net_addr); ii++)
                init_cmd->sw_net_addr[ii] = priv->current_net_addr[ii];
        init_cmd->short_retry_limit = priv->short_retry_limit;
        init_cmd->long_retry_limit = priv->long_retry_limit;
@@ -184,7 +183,7 @@ static int vnt_init_registers(struct vnt_private *priv)
        priv->cck_pwr = priv->eeprom[EEP_OFS_PWR_CCK];
        priv->ofdm_pwr_g = priv->eeprom[EEP_OFS_PWR_OFDMG];
        /* load power table */
-       for (ii = 0; ii < 14; ii++) {
+       for (ii = 0; ii < ARRAY_SIZE(priv->cck_pwr_tbl); ii++) {
                priv->cck_pwr_tbl[ii] =
                        priv->eeprom[ii + EEP_OFS_CCK_PWR_TBL];
                if (priv->cck_pwr_tbl[ii] == 0)
@@ -200,7 +199,7 @@ static int vnt_init_registers(struct vnt_private *priv)
         * original zonetype is USA, but custom zonetype is Europe,
         * then need to recover 12, 13, 14 channels with 11 channel
         */
-       for (ii = 11; ii < 14; ii++) {
+       for (ii = 11; ii < ARRAY_SIZE(priv->cck_pwr_tbl); ii++) {
                priv->cck_pwr_tbl[ii] = priv->cck_pwr_tbl[10];
                priv->ofdm_pwr_tbl[ii] = priv->ofdm_pwr_tbl[10];
        }
@@ -261,9 +260,6 @@ static int vnt_init_registers(struct vnt_private *priv)
        if (ret)
                goto end;
 
-       /* get Auto Fall Back type */
-       priv->auto_fb_ctrl = AUTO_FB_0;
-
        /* default Auto Mode */
        priv->bb_type = BB_TYPE_11G;
 
@@ -370,7 +366,7 @@ static int vnt_init_registers(struct vnt_private *priv)
        if (ret)
                goto end;
 
-       ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, 0x01);
+       ret = vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL0, BIT(0));
        if (ret)
                goto end;
 
@@ -435,7 +431,7 @@ static void vnt_free_int_bufs(struct vnt_private *priv)
 
 static int vnt_alloc_bufs(struct vnt_private *priv)
 {
-       int ret = 0;
+       int ret;
        struct vnt_usb_send_context *tx_context;
        struct vnt_rcb *rcb;
        int ii;
@@ -484,9 +480,6 @@ static int vnt_alloc_bufs(struct vnt_private *priv)
                        ret = -ENOMEM;
                        goto free_rx_tx;
                }
-
-               rcb->in_use = false;
-
                /* submit rx urb */
                ret = vnt_submit_rx_urb(priv, rcb);
                if (ret)
@@ -528,7 +521,7 @@ static void vnt_tx_80211(struct ieee80211_hw *hw,
 
 static int vnt_start(struct ieee80211_hw *hw)
 {
-       int ret = 0;
+       int ret;
        struct vnt_private *priv = hw->priv;
 
        priv->rx_buf_sz = MAX_TOTAL_SIZE_WITH_ALL_HEADERS;
@@ -553,7 +546,7 @@ static int vnt_start(struct ieee80211_hw *hw)
 
        priv->int_interval = 1;  /* bInterval is set to 1 */
 
-       ret = vnt_int_start_interrupt(priv);
+       ret = vnt_start_interrupt_urb(priv);
        if (ret)
                goto free_all;
 
@@ -798,12 +791,11 @@ static u64 vnt_prepare_multicast(struct ieee80211_hw *hw,
        struct vnt_private *priv = hw->priv;
        struct netdev_hw_addr *ha;
        u64 mc_filter = 0;
-       u32 bit_nr = 0;
+       u32 bit_nr;
 
        netdev_hw_addr_list_for_each(ha, mc_list) {
                bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
-
-               mc_filter |= 1ULL << (bit_nr & 0x3f);
+               mc_filter |= BIT_ULL(bit_nr);
        }
 
        priv->mc_list_count = mc_list->count;
@@ -862,9 +854,7 @@ static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        switch (cmd) {
        case SET_KEY:
-               if (vnt_set_keys(hw, sta, vif, key))
-                       return -EOPNOTSUPP;
-               break;
+               return vnt_set_keys(hw, sta, vif, key);
        case DISABLE_KEY:
                if (test_bit(key->hw_key_idx, &priv->key_entry_inuse))
                        clear_bit(key->hw_key_idx, &priv->key_entry_inuse);
@@ -973,7 +963,7 @@ vt6656_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct vnt_private *priv;
        struct ieee80211_hw *hw;
        struct wiphy *wiphy;
-       int rc = 0;
+       int rc;
 
        udev = usb_get_dev(interface_to_usbdev(intf));
 
index 29caba7..9439d19 100644 (file)
@@ -13,7 +13,6 @@
  *
  * Functions:
  *      vnt_generate_tx_parameter - Generate tx dma required parameter.
- *      vnt_get_duration_le - get tx data required duration
  *      vnt_get_rtscts_duration_le- get rtx/cts required duration
  *      vnt_get_rtscts_rsvtime_le- get rts/cts reserved time
  *      vnt_get_rsvtime- get frame reserved time
@@ -39,30 +38,12 @@ static const u16 vnt_time_stampoff[2][MAX_RATE] = {
        {384, 192, 130, 113, 54, 43, 37, 31, 28, 25, 24, 23},
 };
 
-static const u16 vnt_fb_opt0[2][5] = {
-       {RATE_12M, RATE_18M, RATE_24M, RATE_36M, RATE_48M}, /* fallback_rate0 */
-       {RATE_12M, RATE_12M, RATE_18M, RATE_24M, RATE_36M}, /* fallback_rate1 */
-};
-
-static const u16 vnt_fb_opt1[2][5] = {
-       {RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, /* fallback_rate0 */
-       {RATE_6M,  RATE_6M,  RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */
-};
-
 #define RTSDUR_BB       0
 #define RTSDUR_BA       1
 #define RTSDUR_AA       2
 #define CTSDUR_BA       3
-#define RTSDUR_BA_F0    4
-#define RTSDUR_AA_F0    5
-#define RTSDUR_BA_F1    6
-#define RTSDUR_AA_F1    7
-#define CTSDUR_BA_F0    8
-#define CTSDUR_BA_F1    9
 #define DATADUR_B       10
 #define DATADUR_A       11
-#define DATADUR_A_F0    12
-#define DATADUR_A_F1    13
 
 static struct vnt_usb_send_context
        *vnt_get_free_context(struct vnt_private *priv)
@@ -184,27 +165,6 @@ static __le16 vnt_get_rtscts_rsvtime_le(struct vnt_private *priv, u8 rsv_type,
        return cpu_to_le16((u16)rrv_time);
 }
 
-static __le16 vnt_get_duration_le(struct vnt_private *priv, u8 pkt_type,
-                                 int need_ack)
-{
-       u32 ack_time = 0;
-
-       if (need_ack) {
-               if (pkt_type == PK_TYPE_11B)
-                       ack_time = vnt_get_frame_time(priv->preamble_type,
-                                                     pkt_type, 14,
-                                                     priv->top_cck_basic_rate);
-               else
-                       ack_time = vnt_get_frame_time(priv->preamble_type,
-                                                     pkt_type, 14,
-                                                     priv->top_ofdm_basic_rate);
-
-               return cpu_to_le16((u16)(priv->sifs + ack_time));
-       }
-
-       return 0;
-}
-
 static __le16 vnt_get_rtscts_duration_le(struct vnt_usb_send_context *context,
                                         u8 dur_type, u8 pkt_type, u16 rate)
 {
@@ -216,8 +176,6 @@ static __le16 vnt_get_rtscts_duration_le(struct vnt_usb_send_context *context,
        switch (dur_type) {
        case RTSDUR_BB:
        case RTSDUR_BA:
-       case RTSDUR_BA_F0:
-       case RTSDUR_BA_F1:
                cts_time = vnt_get_frame_time(priv->preamble_type, pkt_type,
                                              14, priv->top_cck_basic_rate);
                dur_time = cts_time + 2 * priv->sifs +
@@ -226,8 +184,6 @@ static __le16 vnt_get_rtscts_duration_le(struct vnt_usb_send_context *context,
                break;
 
        case RTSDUR_AA:
-       case RTSDUR_AA_F0:
-       case RTSDUR_AA_F1:
                cts_time = vnt_get_frame_time(priv->preamble_type, pkt_type,
                                              14, priv->top_ofdm_basic_rate);
                dur_time = cts_time + 2 * priv->sifs +
@@ -236,8 +192,6 @@ static __le16 vnt_get_rtscts_duration_le(struct vnt_usb_send_context *context,
                break;
 
        case CTSDUR_BA:
-       case CTSDUR_BA_F0:
-       case CTSDUR_BA_F1:
                dur_time = priv->sifs + vnt_get_rsvtime(priv,
                                pkt_type, frame_length, rate, need_ack);
                break;
@@ -270,7 +224,6 @@ static u16 vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context,
                                (struct ieee80211_hdr *)tx_context->skb->data;
        u32 frame_len = tx_context->frame_len;
        u16 rate = tx_context->tx_rate;
-       u8 need_ack = tx_context->need_ack;
 
        /* Get SignalField,ServiceField,Length */
        vnt_get_phy_field(priv, frame_len, rate, tx_context->pkt_type, &buf->a);
@@ -278,16 +231,8 @@ static u16 vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context,
                          PK_TYPE_11B, &buf->b);
 
        /* Get Duration and TimeStamp */
-       if (ieee80211_is_nullfunc(hdr->frame_control)) {
-               buf->duration_a = hdr->duration_id;
-               buf->duration_b = hdr->duration_id;
-       } else {
-               buf->duration_a = vnt_get_duration_le(priv,
-                                               tx_context->pkt_type, need_ack);
-               buf->duration_b = vnt_get_duration_le(priv,
-                                                     PK_TYPE_11B, need_ack);
-       }
-
+       buf->duration_a = hdr->duration_id;
+       buf->duration_b = hdr->duration_id;
        buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate);
        buf->time_stamp_off_b = vnt_time_stamp_off(priv,
                                                   priv->top_cck_basic_rate);
@@ -297,63 +242,6 @@ static u16 vnt_rxtx_datahead_g(struct vnt_usb_send_context *tx_context,
        return le16_to_cpu(buf->duration_a);
 }
 
-static u16 vnt_rxtx_datahead_g_fb(struct vnt_usb_send_context *tx_context,
-                                 struct vnt_tx_datahead_g_fb *buf)
-{
-       struct vnt_private *priv = tx_context->priv;
-       u32 frame_len = tx_context->frame_len;
-       u16 rate = tx_context->tx_rate;
-       u8 need_ack = tx_context->need_ack;
-
-       /* Get SignalField,ServiceField,Length */
-       vnt_get_phy_field(priv, frame_len, rate, tx_context->pkt_type, &buf->a);
-
-       vnt_get_phy_field(priv, frame_len, priv->top_cck_basic_rate,
-                         PK_TYPE_11B, &buf->b);
-
-       /* Get Duration and TimeStamp */
-       buf->duration_a = vnt_get_duration_le(priv, tx_context->pkt_type,
-                                             need_ack);
-       buf->duration_b = vnt_get_duration_le(priv, PK_TYPE_11B, need_ack);
-
-       buf->duration_a_f0 = vnt_get_duration_le(priv, tx_context->pkt_type,
-                                                need_ack);
-       buf->duration_a_f1 = vnt_get_duration_le(priv, tx_context->pkt_type,
-                                                need_ack);
-
-       buf->time_stamp_off_a = vnt_time_stamp_off(priv, rate);
-       buf->time_stamp_off_b = vnt_time_stamp_off(priv,
-                                                  priv->top_cck_basic_rate);
-
-       tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr);
-
-       return le16_to_cpu(buf->duration_a);
-}
-
-static u16 vnt_rxtx_datahead_a_fb(struct vnt_usb_send_context *tx_context,
-                                 struct vnt_tx_datahead_a_fb *buf)
-{
-       struct vnt_private *priv = tx_context->priv;
-       u16 rate = tx_context->tx_rate;
-       u8 pkt_type = tx_context->pkt_type;
-       u8 need_ack = tx_context->need_ack;
-       u32 frame_len = tx_context->frame_len;
-
-       /* Get SignalField,ServiceField,Length */
-       vnt_get_phy_field(priv, frame_len, rate, pkt_type, &buf->a);
-       /* Get Duration and TimeStampOff */
-       buf->duration = vnt_get_duration_le(priv, pkt_type, need_ack);
-
-       buf->duration_f0 = vnt_get_duration_le(priv, pkt_type, need_ack);
-       buf->duration_f1 = vnt_get_duration_le(priv, pkt_type, need_ack);
-
-       buf->time_stamp_off = vnt_time_stamp_off(priv, rate);
-
-       tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr);
-
-       return le16_to_cpu(buf->duration);
-}
-
 static u16 vnt_rxtx_datahead_ab(struct vnt_usb_send_context *tx_context,
                                struct vnt_tx_datahead_ab *buf)
 {
@@ -362,20 +250,13 @@ static u16 vnt_rxtx_datahead_ab(struct vnt_usb_send_context *tx_context,
                                (struct ieee80211_hdr *)tx_context->skb->data;
        u32 frame_len = tx_context->frame_len;
        u16 rate = tx_context->tx_rate;
-       u8 need_ack = tx_context->need_ack;
 
        /* Get SignalField,ServiceField,Length */
        vnt_get_phy_field(priv, frame_len, rate,
                          tx_context->pkt_type, &buf->ab);
 
        /* Get Duration and TimeStampOff */
-       if (ieee80211_is_nullfunc(hdr->frame_control)) {
-               buf->duration = hdr->duration_id;
-       } else {
-               buf->duration = vnt_get_duration_le(priv, tx_context->pkt_type,
-                                                   need_ack);
-       }
-
+       buf->duration = hdr->duration_id;
        buf->time_stamp_off = vnt_time_stamp_off(priv, rate);
 
        tx_context->tx_hdr_size = vnt_mac_hdr_pos(tx_context, &buf->hdr);
@@ -426,50 +307,6 @@ static u16 vnt_rxtx_rts_g_head(struct vnt_usb_send_context *tx_context,
        return vnt_rxtx_datahead_g(tx_context, &buf->data_head);
 }
 
-static u16 vnt_rxtx_rts_g_fb_head(struct vnt_usb_send_context *tx_context,
-                                 struct vnt_rts_g_fb *buf)
-{
-       struct vnt_private *priv = tx_context->priv;
-       u16 current_rate = tx_context->tx_rate;
-       u16 rts_frame_len = 20;
-
-       vnt_get_phy_field(priv, rts_frame_len, priv->top_cck_basic_rate,
-                         PK_TYPE_11B, &buf->b);
-       vnt_get_phy_field(priv, rts_frame_len, priv->top_ofdm_basic_rate,
-                         tx_context->pkt_type, &buf->a);
-
-       buf->duration_bb = vnt_get_rtscts_duration_le(tx_context, RTSDUR_BB,
-                                                     PK_TYPE_11B,
-                                                     priv->top_cck_basic_rate);
-       buf->duration_aa = vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA,
-                                                     tx_context->pkt_type,
-                                                     current_rate);
-       buf->duration_ba = vnt_get_rtscts_duration_le(tx_context, RTSDUR_BA,
-                                                     tx_context->pkt_type,
-                                                     current_rate);
-
-       buf->rts_duration_ba_f0 =
-               vnt_get_rtscts_duration_le(tx_context, RTSDUR_BA_F0,
-                                          tx_context->pkt_type,
-                                          priv->tx_rate_fb0);
-       buf->rts_duration_aa_f0 =
-               vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA_F0,
-                                          tx_context->pkt_type,
-                                          priv->tx_rate_fb0);
-       buf->rts_duration_ba_f1 =
-               vnt_get_rtscts_duration_le(tx_context, RTSDUR_BA_F1,
-                                          tx_context->pkt_type,
-                                          priv->tx_rate_fb1);
-       buf->rts_duration_aa_f1 =
-               vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA_F1,
-                                          tx_context->pkt_type,
-                                          priv->tx_rate_fb1);
-
-       vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration_aa);
-
-       return vnt_rxtx_datahead_g_fb(tx_context, &buf->data_head);
-}
-
 static u16 vnt_rxtx_rts_ab_head(struct vnt_usb_send_context *tx_context,
                                struct vnt_rts_ab *buf)
 {
@@ -489,71 +326,6 @@ static u16 vnt_rxtx_rts_ab_head(struct vnt_usb_send_context *tx_context,
        return vnt_rxtx_datahead_ab(tx_context, &buf->data_head);
 }
 
-static u16 vnt_rxtx_rts_a_fb_head(struct vnt_usb_send_context *tx_context,
-                                 struct vnt_rts_a_fb *buf)
-{
-       struct vnt_private *priv = tx_context->priv;
-       u16 current_rate = tx_context->tx_rate;
-       u16 rts_frame_len = 20;
-
-       vnt_get_phy_field(priv, rts_frame_len, priv->top_ofdm_basic_rate,
-                         tx_context->pkt_type, &buf->a);
-
-       buf->duration = vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA,
-                                                  tx_context->pkt_type,
-                                                  current_rate);
-
-       buf->rts_duration_f0 =
-               vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA_F0,
-                                          tx_context->pkt_type,
-                                          priv->tx_rate_fb0);
-
-       buf->rts_duration_f1 =
-               vnt_get_rtscts_duration_le(tx_context, RTSDUR_AA_F1,
-                                          tx_context->pkt_type,
-                                          priv->tx_rate_fb1);
-
-       vnt_fill_ieee80211_rts(tx_context, &buf->data, buf->duration);
-
-       return vnt_rxtx_datahead_a_fb(tx_context, &buf->data_head);
-}
-
-static u16 vnt_fill_cts_fb_head(struct vnt_usb_send_context *tx_context,
-                               union vnt_tx_data_head *head)
-{
-       struct vnt_private *priv = tx_context->priv;
-       struct vnt_cts_fb *buf = &head->cts_g_fb;
-       u32 cts_frame_len = 14;
-       u16 current_rate = tx_context->tx_rate;
-
-       /* Get SignalField,ServiceField,Length */
-       vnt_get_phy_field(priv, cts_frame_len, priv->top_cck_basic_rate,
-                         PK_TYPE_11B, &buf->b);
-
-       buf->duration_ba =
-               vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
-                                          tx_context->pkt_type,
-                                          current_rate);
-       /* Get CTSDuration_ba_f0 */
-       buf->cts_duration_ba_f0 =
-               vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F0,
-                                          tx_context->pkt_type,
-                                          priv->tx_rate_fb0);
-       /* Get CTSDuration_ba_f1 */
-       buf->cts_duration_ba_f1 =
-               vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F1,
-                                          tx_context->pkt_type,
-                                          priv->tx_rate_fb1);
-       /* Get CTS Frame body */
-       buf->data.duration = buf->duration_ba;
-       buf->data.frame_control =
-               cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
-
-       ether_addr_copy(buf->data.ra, priv->current_net_addr);
-
-       return vnt_rxtx_datahead_g_fb(tx_context, &buf->data_head);
-}
-
 static u16 vnt_fill_cts_head(struct vnt_usb_send_context *tx_context,
                             union vnt_tx_data_head *head)
 {
@@ -606,9 +378,6 @@ static u16 vnt_rxtx_rts(struct vnt_usb_send_context *tx_context,
        if (need_mic)
                head = &tx_head->tx_rts.tx.mic.head;
 
-       if (tx_context->fb_option)
-               return vnt_rxtx_rts_g_fb_head(tx_context, &head->rts_g_fb);
-
        return vnt_rxtx_rts_g_head(tx_context, &head->rts_g);
 }
 
@@ -633,10 +402,6 @@ static u16 vnt_rxtx_cts(struct vnt_usb_send_context *tx_context,
        if (need_mic)
                head = &tx_head->tx_cts.tx.mic.head;
 
-       /* Fill CTS */
-       if (tx_context->fb_option)
-               return vnt_fill_cts_fb_head(tx_context, head);
-
        return vnt_fill_cts_head(tx_context, head);
 }
 
@@ -664,18 +429,9 @@ static u16 vnt_rxtx_ab(struct vnt_usb_send_context *tx_context,
                        buf->rts_rrv_time = vnt_get_rtscts_rsvtime_le(priv, 2,
                                tx_context->pkt_type, frame_len, current_rate);
 
-               if (tx_context->fb_option &&
-                   tx_context->pkt_type == PK_TYPE_11A)
-                       return vnt_rxtx_rts_a_fb_head(tx_context,
-                                                     &head->rts_a_fb);
-
                return vnt_rxtx_rts_ab_head(tx_context, &head->rts_ab);
        }
 
-       if (tx_context->pkt_type == PK_TYPE_11A)
-               return vnt_rxtx_datahead_a_fb(tx_context,
-                                             &head->data_head_a_fb);
-
        return vnt_rxtx_datahead_ab(tx_context, &head->data_head_ab);
 }
 
@@ -792,7 +548,7 @@ int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
        struct vnt_usb_send_context *tx_context;
        unsigned long flags;
        u16 tx_bytes, tx_header_size, tx_body_size, current_rate, duration_id;
-       u8 pkt_type, fb_option = AUTO_FB_NONE;
+       u8 pkt_type;
        bool need_rts = false;
        bool need_mic = false;
 
@@ -912,33 +668,6 @@ int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        tx_buffer_head->current_rate = cpu_to_le16(current_rate);
 
-       /* legacy rates TODO use ieee80211_tx_rate */
-       if (current_rate >= RATE_18M && ieee80211_is_data(hdr->frame_control)) {
-               if (priv->auto_fb_ctrl == AUTO_FB_0) {
-                       tx_buffer_head->fifo_ctl |=
-                                               cpu_to_le16(FIFOCTL_AUTO_FB_0);
-
-                       priv->tx_rate_fb0 =
-                               vnt_fb_opt0[FB_RATE0][current_rate - RATE_18M];
-                       priv->tx_rate_fb1 =
-                               vnt_fb_opt0[FB_RATE1][current_rate - RATE_18M];
-
-                       fb_option = AUTO_FB_0;
-               } else if (priv->auto_fb_ctrl == AUTO_FB_1) {
-                       tx_buffer_head->fifo_ctl |=
-                                               cpu_to_le16(FIFOCTL_AUTO_FB_1);
-
-                       priv->tx_rate_fb0 =
-                               vnt_fb_opt1[FB_RATE0][current_rate - RATE_18M];
-                       priv->tx_rate_fb1 =
-                               vnt_fb_opt1[FB_RATE1][current_rate - RATE_18M];
-
-                       fb_option = AUTO_FB_1;
-               }
-       }
-
-       tx_context->fb_option = fb_option;
-
        duration_id = vnt_generate_tx_parameter(tx_context, tx_buffer, &mic_hdr,
                                                need_mic, need_rts);
 
@@ -954,8 +683,6 @@ int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        memcpy(tx_context->hdr, skb->data, tx_body_size);
 
-       hdr->duration_id = cpu_to_le16(duration_id);
-
        if (info->control.hw_key) {
                tx_key = info->control.hw_key;
                if (tx_key->keylen > 0)
@@ -977,7 +704,7 @@ int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (vnt_tx_context(priv, tx_context) != STATUS_PENDING) {
+       if (vnt_tx_context(priv, tx_context)) {
                spin_unlock_irqrestore(&priv->lock, flags);
                return -EIO;
        }
@@ -1021,9 +748,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, struct sk_buff *skb)
                vnt_get_phy_field(priv, frame_size, current_rate,
                                  PK_TYPE_11A, &short_head->ab);
 
-               /* Get Duration and TimeStampOff */
-               short_head->duration = vnt_get_duration_le(priv,
-                                                          PK_TYPE_11A, false);
+               /* Get TimeStampOff */
                short_head->time_stamp_off =
                                vnt_time_stamp_off(priv, current_rate);
        } else {
@@ -1034,9 +759,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, struct sk_buff *skb)
                vnt_get_phy_field(priv, frame_size, current_rate,
                                  PK_TYPE_11B, &short_head->ab);
 
-               /* Get Duration and TimeStampOff */
-               short_head->duration = vnt_get_duration_le(priv,
-                                                          PK_TYPE_11B, false);
+               /* Get TimeStampOff */
                short_head->time_stamp_off =
                        vnt_time_stamp_off(priv, current_rate);
        }
@@ -1045,6 +768,9 @@ static int vnt_beacon_xmit(struct vnt_private *priv, struct sk_buff *skb)
        mgmt_hdr = &beacon_buffer->mgmt_hdr;
        memcpy(mgmt_hdr, skb->data, skb->len);
 
+       /* Get Duration */
+       short_head->duration = mgmt_hdr->duration;
+
        /* time stamp always 0 */
        mgmt_hdr->u.beacon.timestamp = 0;
 
@@ -1071,7 +797,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, struct sk_buff *skb)
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       if (vnt_tx_context(priv, context) != STATUS_PENDING)
+       if (vnt_tx_context(priv, context))
                ieee80211_free_txskb(priv->hw, context->skb);
 
        spin_unlock_irqrestore(&priv->lock, flags);
index d528607..0e6226a 100644 (file)
@@ -73,18 +73,6 @@ struct vnt_tx_datahead_g {
        struct ieee80211_hdr hdr;
 } __packed;
 
-struct vnt_tx_datahead_g_fb {
-       struct vnt_phy_field b;
-       struct vnt_phy_field a;
-       __le16 duration_b;
-       __le16 duration_a;
-       __le16 duration_a_f0;
-       __le16 duration_a_f1;
-       __le16 time_stamp_off_b;
-       __le16 time_stamp_off_a;
-       struct ieee80211_hdr hdr;
-} __packed;
-
 struct vnt_tx_datahead_ab {
        struct vnt_phy_field ab;
        __le16 duration;
@@ -92,15 +80,6 @@ struct vnt_tx_datahead_ab {
        struct ieee80211_hdr hdr;
 } __packed;
 
-struct vnt_tx_datahead_a_fb {
-       struct vnt_phy_field a;
-       __le16 duration;
-       __le16 time_stamp_off;
-       __le16 duration_f0;
-       __le16 duration_f1;
-       struct ieee80211_hdr hdr;
-} __packed;
-
 /* RTS buffer header */
 struct vnt_rts_g {
        struct vnt_phy_field b;
@@ -113,21 +92,6 @@ struct vnt_rts_g {
        struct vnt_tx_datahead_g data_head;
 } __packed;
 
-struct vnt_rts_g_fb {
-       struct vnt_phy_field b;
-       struct vnt_phy_field a;
-       __le16 duration_ba;
-       __le16 duration_aa;
-       __le16 duration_bb;
-       u16 wReserved;
-       __le16 rts_duration_ba_f0;
-       __le16 rts_duration_aa_f0;
-       __le16 rts_duration_ba_f1;
-       __le16 rts_duration_aa_f1;
-       struct ieee80211_rts data;
-       struct vnt_tx_datahead_g_fb data_head;
-} __packed;
-
 struct vnt_rts_ab {
        struct vnt_phy_field ab;
        __le16 duration;
@@ -136,16 +100,6 @@ struct vnt_rts_ab {
        struct vnt_tx_datahead_ab data_head;
 } __packed;
 
-struct vnt_rts_a_fb {
-       struct vnt_phy_field a;
-       __le16 duration;
-       u16 wReserved;
-       __le16 rts_duration_f0;
-       __le16 rts_duration_f1;
-       struct ieee80211_rts data;
-       struct vnt_tx_datahead_a_fb data_head;
-} __packed;
-
 /* CTS buffer header */
 struct vnt_cts {
        struct vnt_phy_field b;
@@ -156,29 +110,14 @@ struct vnt_cts {
        struct vnt_tx_datahead_g data_head;
 } __packed;
 
-struct vnt_cts_fb {
-       struct vnt_phy_field b;
-       __le16 duration_ba;
-       u16 wReserved;
-       __le16 cts_duration_ba_f0;
-       __le16 cts_duration_ba_f1;
-       struct ieee80211_cts data;
-       u16 reserved2;
-       struct vnt_tx_datahead_g_fb data_head;
-} __packed;
-
 union vnt_tx_data_head {
        /* rts g */
        struct vnt_rts_g rts_g;
-       struct vnt_rts_g_fb rts_g_fb;
        /* rts a/b */
        struct vnt_rts_ab rts_ab;
-       struct vnt_rts_a_fb rts_a_fb;
        /* cts g */
        struct vnt_cts cts_g;
-       struct vnt_cts_fb cts_g_fb;
        /* no rts/cts */
-       struct vnt_tx_datahead_a_fb data_head_a_fb;
        struct vnt_tx_datahead_ab data_head_ab;
 };
 
index 7bfccc4..eae211e 100644 (file)
  *
  */
 
-#include "int.h"
 #include "rxtx.h"
-#include "dpc.h"
 #include "desc.h"
 #include "device.h"
 #include "usbpipe.h"
+#include "mac.h"
+#include "rf.h"
 
 #define USB_CTL_WAIT   500 /* ms */
 
@@ -139,6 +139,90 @@ int vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data)
                              reg_off, reg, sizeof(u8), data);
 }
 
+static int vnt_int_report_rate(struct vnt_private *priv, u8 pkt_no, u8 tsr)
+{
+       struct vnt_usb_send_context *context;
+       struct ieee80211_tx_info *info;
+       u8 tx_retry = (tsr & 0xf0) >> 4;
+       s8 idx;
+
+       if (pkt_no >= priv->num_tx_context)
+               return -EINVAL;
+
+       context = priv->tx_context[pkt_no];
+
+       if (!context->skb)
+               return -EINVAL;
+
+       info = IEEE80211_SKB_CB(context->skb);
+       idx = info->control.rates[0].idx;
+
+       ieee80211_tx_info_clear_status(info);
+
+       info->status.rates[0].count = tx_retry;
+
+       if (!(tsr & TSR_TMO)) {
+               info->status.rates[0].idx = idx;
+
+               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+                       info->flags |= IEEE80211_TX_STAT_ACK;
+       }
+
+       ieee80211_tx_status_irqsafe(priv->hw, context->skb);
+
+       context->in_use = false;
+
+       return 0;
+}
+
+static void vnt_int_process_data(struct vnt_private *priv)
+{
+       struct vnt_interrupt_data *int_data;
+       struct ieee80211_low_level_stats *low_stats = &priv->low_stats;
+
+       dev_dbg(&priv->usb->dev, "---->s_nsInterruptProcessData\n");
+
+       int_data = (struct vnt_interrupt_data *)priv->int_buf.data_buf;
+
+       if (int_data->tsr0 & TSR_VALID)
+               vnt_int_report_rate(priv, int_data->pkt0, int_data->tsr0);
+
+       if (int_data->tsr1 & TSR_VALID)
+               vnt_int_report_rate(priv, int_data->pkt1, int_data->tsr1);
+
+       if (int_data->tsr2 & TSR_VALID)
+               vnt_int_report_rate(priv, int_data->pkt2, int_data->tsr2);
+
+       if (int_data->tsr3 & TSR_VALID)
+               vnt_int_report_rate(priv, int_data->pkt3, int_data->tsr3);
+
+       if (int_data->isr0 != 0) {
+               if (int_data->isr0 & ISR_BNTX &&
+                   priv->op_mode == NL80211_IFTYPE_AP)
+                       vnt_schedule_command(priv, WLAN_CMD_BECON_SEND);
+
+               if (int_data->isr0 & ISR_TBTT &&
+                   priv->hw->conf.flags & IEEE80211_CONF_PS) {
+                       if (!priv->wake_up_count)
+                               priv->wake_up_count =
+                                       priv->hw->conf.listen_interval;
+
+                       --priv->wake_up_count;
+
+                       /* Turn on wake up to listen next beacon */
+                       if (priv->wake_up_count == 1)
+                               vnt_schedule_command(priv,
+                                                    WLAN_CMD_TBTT_WAKEUP);
+               }
+               priv->current_tsf = le64_to_cpu(int_data->tsf);
+
+               low_stats->dot11RTSSuccessCount += int_data->rts_success;
+               low_stats->dot11RTSFailureCount += int_data->rts_fail;
+               low_stats->dot11ACKFailureCount += int_data->ack_fail;
+               low_stats->dot11FCSErrorCount += int_data->fcs_err;
+       }
+}
+
 static void vnt_start_interrupt_urb_complete(struct urb *urb)
 {
        struct vnt_private *priv = urb->context;
@@ -151,37 +235,26 @@ static void vnt_start_interrupt_urb_complete(struct urb *urb)
        case -ECONNRESET:
        case -ENOENT:
        case -ESHUTDOWN:
-               priv->int_buf.in_use = false;
                return;
        default:
                break;
        }
 
-       if (status) {
-               priv->int_buf.in_use = false;
-
+       if (status)
                dev_dbg(&priv->usb->dev, "%s status = %d\n", __func__, status);
-       } else {
+       else
                vnt_int_process_data(priv);
-       }
 
        status = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
        if (status)
                dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", status);
-       else
-               priv->int_buf.in_use = true;
 }
 
 int vnt_start_interrupt_urb(struct vnt_private *priv)
 {
        int ret = 0;
 
-       if (priv->int_buf.in_use) {
-               ret = -EBUSY;
-               goto err;
-       }
-
-       priv->int_buf.in_use = true;
+       dev_dbg(&priv->usb->dev, "---->Interrupt Polling Thread\n");
 
        usb_fill_int_urb(priv->interrupt_urb,
                         priv->usb,
@@ -193,17 +266,110 @@ int vnt_start_interrupt_urb(struct vnt_private *priv)
                         priv->int_interval);
 
        ret = usb_submit_urb(priv->interrupt_urb, GFP_ATOMIC);
-       if (ret) {
+       if (ret)
                dev_dbg(&priv->usb->dev, "Submit int URB failed %d\n", ret);
-               goto err_submit;
+
+       return ret;
+}
+
+static int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb,
+                      unsigned long bytes_received)
+{
+       struct ieee80211_hw *hw = priv->hw;
+       struct ieee80211_supported_band *sband;
+       struct sk_buff *skb;
+       struct ieee80211_rx_status *rx_status;
+       struct vnt_rx_header *head;
+       struct vnt_rx_tail *tail;
+       u32 frame_size;
+       int ii;
+       u16 rx_bitrate, pay_load_with_padding;
+       u8 rate_idx = 0;
+       long rx_dbm;
+
+       skb = ptr_rcb->skb;
+       rx_status = IEEE80211_SKB_RXCB(skb);
+
+       /* [31:16]RcvByteCount ( not include 4-byte Status ) */
+       head = (struct vnt_rx_header *)skb->data;
+       frame_size = head->wbk_status >> 16;
+       frame_size += 4;
+
+       if (bytes_received != frame_size) {
+               dev_dbg(&priv->usb->dev, "------- WRONG Length 1\n");
+               return false;
        }
 
-       return 0;
+       if ((bytes_received > 2372) || (bytes_received <= 40)) {
+               /* Frame Size error drop this packet.*/
+               dev_dbg(&priv->usb->dev, "------ WRONG Length 2\n");
+               return false;
+       }
 
-err_submit:
-       priv->int_buf.in_use = false;
-err:
-       return ret;
+       /* real Frame Size = USBframe_size -4WbkStatus - 4RxStatus */
+       /* -8TSF - 4RSR - 4SQ3 - ?Padding */
+
+       /* if SQ3 the range is 24~27, if no SQ3 the range is 20~23 */
+
+       /*Fix hardware bug => PLCP_Length error */
+       if (((bytes_received - head->pay_load_len) > 27) ||
+           ((bytes_received - head->pay_load_len) < 24) ||
+           (bytes_received < head->pay_load_len)) {
+               dev_dbg(&priv->usb->dev, "Wrong PLCP Length %x\n",
+                       head->pay_load_len);
+               return false;
+       }
+
+       sband = hw->wiphy->bands[hw->conf.chandef.chan->band];
+       rx_bitrate = head->rx_rate * 5; /* rx_rate * 5 */
+
+       for (ii = 0; ii < sband->n_bitrates; ii++) {
+               if (sband->bitrates[ii].bitrate == rx_bitrate) {
+                       rate_idx = ii;
+                               break;
+               }
+       }
+
+       if (ii == sband->n_bitrates) {
+               dev_dbg(&priv->usb->dev, "Wrong Rx Bit Rate %d\n", rx_bitrate);
+               return false;
+       }
+
+       pay_load_with_padding = ((head->pay_load_len / 4) +
+               ((head->pay_load_len % 4) ? 1 : 0)) * 4;
+
+       tail = (struct vnt_rx_tail *)(skb->data +
+                                     sizeof(*head) + pay_load_with_padding);
+       priv->tsf_time = le64_to_cpu(tail->tsf_time);
+
+       if (tail->rsr & (RSR_IVLDTYP | RSR_IVLDLEN))
+               return false;
+
+       vnt_rf_rssi_to_dbm(priv, tail->rssi, &rx_dbm);
+
+       priv->bb_pre_ed_rssi = (u8)-rx_dbm + 1;
+       priv->current_rssi = priv->bb_pre_ed_rssi;
+
+       skb_pull(skb, sizeof(*head));
+       skb_trim(skb, head->pay_load_len);
+
+       rx_status->mactime = priv->tsf_time;
+       rx_status->band = hw->conf.chandef.chan->band;
+       rx_status->signal = rx_dbm;
+       rx_status->flag = 0;
+       rx_status->freq = hw->conf.chandef.chan->center_freq;
+
+       if (!(tail->rsr & RSR_CRCOK))
+               rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+       rx_status->rate_idx = rate_idx;
+
+       if (tail->new_rsr & NEWRSR_DECRYPTOK)
+               rx_status->flag |= RX_FLAG_DECRYPTED;
+
+       ieee80211_rx_irqsafe(priv->hw, skb);
+
+       return true;
 }
 
 static void vnt_submit_rx_urb_complete(struct urb *urb)
@@ -227,10 +393,8 @@ static void vnt_submit_rx_urb_complete(struct urb *urb)
        if (urb->actual_length) {
                if (vnt_rx_data(priv, rcb, urb->actual_length)) {
                        rcb->skb = dev_alloc_skb(priv->rx_buf_sz);
-                       if (!rcb->skb) {
-                               rcb->in_use = false;
+                       if (!rcb->skb)
                                return;
-                       }
                } else {
                        skb_push(rcb->skb, skb_headroom(rcb->skb));
                        skb_trim(rcb->skb, 0);
@@ -240,11 +404,8 @@ static void vnt_submit_rx_urb_complete(struct urb *urb)
                                               skb_tailroom(rcb->skb));
        }
 
-       if (usb_submit_urb(urb, GFP_ATOMIC)) {
+       if (usb_submit_urb(urb, GFP_ATOMIC))
                dev_dbg(&priv->usb->dev, "Failed to re submit rx skb\n");
-
-               rcb->in_use = false;
-       }
 }
 
 int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
@@ -267,13 +428,8 @@ int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb)
                          rcb);
 
        ret = usb_submit_urb(urb, GFP_ATOMIC);
-       if (ret) {
+       if (ret)
                dev_dbg(&priv->usb->dev, "Submit Rx URB failed %d\n", ret);
-               goto end;
-       }
-
-       rcb->in_use = true;
-
 end:
        return ret;
 }
@@ -317,7 +473,7 @@ int vnt_tx_context(struct vnt_private *priv,
 
        if (test_bit(DEVICE_FLAGS_DISCONNECTED, &priv->flags)) {
                context->in_use = false;
-               return STATUS_RESOURCES;
+               return -ENODEV;
        }
 
        usb_fill_bulk_urb(urb,
@@ -333,8 +489,7 @@ int vnt_tx_context(struct vnt_private *priv,
                dev_dbg(&priv->usb->dev, "Submit Tx URB failed %d\n", status);
 
                context->in_use = false;
-               return STATUS_FAILURE;
        }
 
-       return STATUS_PENDING;
+       return status;
 }
index 4e3341b..35697b5 100644 (file)
 
 #include "device.h"
 
+struct vnt_interrupt_data {
+       u8 tsr0;
+       u8 pkt0;
+       u16 time0;
+       u8 tsr1;
+       u8 pkt1;
+       u16 time1;
+       u8 tsr2;
+       u8 pkt2;
+       u16 time2;
+       u8 tsr3;
+       u8 pkt3;
+       u16 time3;
+       __le64 tsf;
+       u8 isr0;
+       u8 isr1;
+       u8 rts_success;
+       u8 rts_fail;
+       u8 ack_fail;
+       u8 fcs_err;
+       u8 sw[2];
+} __packed;
+
 #define VNT_REG_BLOCK_SIZE     64
 
 int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
index 26de676..17db675 100644 (file)
@@ -6,7 +6,7 @@ SPI
 You have to declare the WFxxx chip in your device tree.
 
 Required properties:
- - compatible: Should be "silabs,wfx-spi"
+ - compatible: Should be "silabs,wf200"
  - reg: Chip select address of device
  - spi-max-frequency: Maximum SPI clocking speed of device in Hz
  - interrupts-extended: Should contain interrupt line (interrupt-parent +
@@ -15,6 +15,7 @@ Required properties:
 Optional properties:
  - reset-gpios: phandle of gpio that will be used to reset chip during probe.
    Without this property, you may encounter issues with warm boot.
+   (Legacy: when compatible == "silabs,wfx-spi", the gpio is inverted.)
 
 Please consult Documentation/devicetree/bindings/spi/spi-bus.txt for optional
 SPI connection related properties,
@@ -23,12 +24,12 @@ Example:
 
 &spi1 {
        wfx {
-               compatible = "silabs,wfx-spi";
+               compatible = "silabs,wf200";
                pinctrl-names = "default";
                pinctrl-0 = <&wfx_irq &wfx_gpios>;
                interrupts-extended = <&gpio 16 IRQ_TYPE_EDGE_RISING>;
                wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>;
-               reset-gpios = <&gpio 13 GPIO_ACTIVE_HIGH>;
+               reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>;
                reg = <0>;
                spi-max-frequency = <42000000>;
        };
@@ -44,7 +45,7 @@ case. Thus declaring WFxxx chip in device tree is strongly recommended (and may
 become mandatory in the future).
 
 Required properties:
- - compatible: Should be "silabs,wfx-sdio"
+ - compatible: Should be "silabs,wf200"
  - reg: Should be 1
 
 In addition, it is recommended to declare a mmc-pwrseq on SDIO host above WFx.
@@ -70,7 +71,7 @@ Example:
        #size = <0>;
 
        mmc@1 {
-               compatible = "silabs,wfx-sdio";
+               compatible = "silabs,wf200";
                reg = <1>;
                pinctrl-names = "default";
                pinctrl-0 = <&wfx_wakeup>;
@@ -93,5 +94,5 @@ Some properties are recognized either by SPI and SDIO versions:
    Must contains 64 hexadecimal digits. Not supported in current version.
 
 WFx driver also supports `mac-address` and `local-mac-address` as described in
-Documentation/devicetree/binding/net/ethernet.txt
+Documentation/devicetree/bindings/net/ethernet.txt
 
index 983c41d..9fcab00 100644 (file)
@@ -20,13 +20,13 @@ static void device_wakeup(struct wfx_dev *wdev)
 {
        if (!wdev->pdata.gpio_wakeup)
                return;
-       if (gpiod_get_value(wdev->pdata.gpio_wakeup))
+       if (gpiod_get_value_cansleep(wdev->pdata.gpio_wakeup))
                return;
 
-       gpiod_set_value(wdev->pdata.gpio_wakeup, 1);
+       gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1);
        if (wfx_api_older_than(wdev, 1, 4)) {
                if (!completion_done(&wdev->hif.ctrl_ready))
-                       udelay(2000);
+                       usleep_range(2000, 2500);
        } else {
                // completion.h does not provide any function to wait
                // completion without consume it (a kind of
@@ -45,7 +45,7 @@ static void device_release(struct wfx_dev *wdev)
        if (!wdev->pdata.gpio_wakeup)
                return;
 
-       gpiod_set_value(wdev->pdata.gpio_wakeup, 0);
+       gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0);
 }
 
 static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf)
index f890116..dedc3ff 100644 (file)
@@ -200,25 +200,23 @@ static int wfx_sdio_probe(struct sdio_func *func,
        if (ret)
                goto err0;
 
-       ret = wfx_sdio_irq_subscribe(bus);
-       if (ret)
-               goto err1;
-
        bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata,
                                    &wfx_sdio_hwbus_ops, bus);
        if (!bus->core) {
                ret = -EIO;
-               goto err2;
+               goto err1;
        }
 
+       ret = wfx_sdio_irq_subscribe(bus);
+       if (ret)
+               goto err1;
+
        ret = wfx_probe(bus->core);
        if (ret)
-               goto err3;
+               goto err2;
 
        return 0;
 
-err3:
-       wfx_free_common(bus->core);
 err2:
        wfx_sdio_irq_unsubscribe(bus);
 err1:
@@ -234,7 +232,6 @@ static void wfx_sdio_remove(struct sdio_func *func)
        struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
 
        wfx_release(bus->core);
-       wfx_free_common(bus->core);
        wfx_sdio_irq_unsubscribe(bus);
        sdio_claim_host(func);
        sdio_disable_func(func);
@@ -254,6 +251,7 @@ MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids);
 #ifdef CONFIG_OF
 static const struct of_device_id wfx_sdio_of_match[] = {
        { .compatible = "silabs,wfx-sdio" },
+       { .compatible = "silabs,wf200" },
        { },
 };
 MODULE_DEVICE_TABLE(of, wfx_sdio_of_match);
index 40bc330..61e99b0 100644 (file)
@@ -27,6 +27,8 @@ MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for none.");
 #define SET_WRITE 0x7FFF        /* usage: and operation */
 #define SET_READ 0x8000         /* usage: or operation */
 
+#define WFX_RESET_INVERTED 1
+
 static const struct wfx_platform_data wfx_spi_pdata = {
        .file_fw = "wfm_wf200",
        .file_pds = "wf200.pds",
@@ -154,6 +156,11 @@ static void wfx_spi_request_rx(struct work_struct *work)
        wfx_bh_request_rx(bus->core);
 }
 
+static void wfx_flush_irq_work(void *w)
+{
+       flush_work(w);
+}
+
 static size_t wfx_spi_align_size(void *priv, size_t size)
 {
        // Most of SPI controllers avoid DMA if buffer size is not 32bit aligned
@@ -201,28 +208,31 @@ static int wfx_spi_probe(struct spi_device *func)
        if (!bus->gpio_reset) {
                dev_warn(&func->dev, "try to load firmware anyway\n");
        } else {
-               gpiod_set_value(bus->gpio_reset, 0);
-               udelay(100);
-               gpiod_set_value(bus->gpio_reset, 1);
-               udelay(2000);
+               if (spi_get_device_id(func)->driver_data & WFX_RESET_INVERTED)
+                       gpiod_toggle_active_low(bus->gpio_reset);
+               gpiod_set_value_cansleep(bus->gpio_reset, 1);
+               usleep_range(100, 150);
+               gpiod_set_value_cansleep(bus->gpio_reset, 0);
+               usleep_range(2000, 2500);
        }
 
-       ret = devm_request_irq(&func->dev, func->irq, wfx_spi_irq_handler,
-                              IRQF_TRIGGER_RISING, "wfx", bus);
-       if (ret)
-               return ret;
-
        INIT_WORK(&bus->request_rx, wfx_spi_request_rx);
        bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata,
                                    &wfx_spi_hwbus_ops, bus);
        if (!bus->core)
                return -EIO;
 
-       ret = wfx_probe(bus->core);
+       ret = devm_add_action_or_reset(&func->dev, wfx_flush_irq_work,
+                                      &bus->request_rx);
        if (ret)
-               wfx_free_common(bus->core);
+               return ret;
 
-       return ret;
+       ret = devm_request_irq(&func->dev, func->irq, wfx_spi_irq_handler,
+                              IRQF_TRIGGER_RISING, "wfx", bus);
+       if (ret)
+               return ret;
+
+       return wfx_probe(bus->core);
 }
 
 static int wfx_spi_remove(struct spi_device *func)
@@ -230,11 +240,6 @@ static int wfx_spi_remove(struct spi_device *func)
        struct wfx_spi_priv *bus = spi_get_drvdata(func);
 
        wfx_release(bus->core);
-       wfx_free_common(bus->core);
-       // A few IRQ will be sent during device release. Hopefully, no IRQ
-       // should happen after wdev/wvif are released.
-       devm_free_irq(&func->dev, func->irq, bus);
-       flush_work(&bus->request_rx);
        return 0;
 }
 
@@ -244,14 +249,16 @@ static int wfx_spi_remove(struct spi_device *func)
  * stripped.
  */
 static const struct spi_device_id wfx_spi_id[] = {
-       { "wfx-spi", 0 },
+       { "wfx-spi", WFX_RESET_INVERTED },
+       { "wf200", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(spi, wfx_spi_id);
 
 #ifdef CONFIG_OF
 static const struct of_device_id wfx_spi_of_match[] = {
-       { .compatible = "silabs,wfx-spi" },
+       { .compatible = "silabs,wfx-spi", .data = (void *)WFX_RESET_INVERTED },
+       { .compatible = "silabs,wf200" },
        { },
 };
 MODULE_DEVICE_TABLE(of, wfx_spi_of_match);
index 5d19845..c5b83fe 100644 (file)
@@ -17,7 +17,7 @@ static int wfx_drop_encrypt_data(struct wfx_dev *wdev,
                                 const struct hif_ind_rx *arg,
                                 struct sk_buff *skb)
 {
-       struct ieee80211_hdr *frame = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data;
        size_t hdrlen = ieee80211_hdrlen(frame->frame_control);
        size_t iv_len, icv_len;
 
@@ -62,7 +62,6 @@ static int wfx_drop_encrypt_data(struct wfx_dev *wdev,
        memmove(skb->data + iv_len, skb->data, hdrlen);
        skb_pull(skb, iv_len);
        return 0;
-
 }
 
 void wfx_rx_cb(struct wfx_vif *wvif,
index 20f4740..42183c7 100644 (file)
@@ -227,7 +227,7 @@ static int wfx_tx_policy_upload(struct wfx_vif *wvif)
                            memzcmp(policies[i].rates, sizeof(policies[i].rates)))
                                break;
                if (i < HIF_MIB_NUM_TX_RATE_RETRY_POLICIES) {
-                       policies[i].uploaded = 1;
+                       policies[i].uploaded = true;
                        memcpy(tmp_rates, policies[i].rates, sizeof(tmp_rates));
                        spin_unlock_bh(&wvif->tx_policy_cache.lock);
                        hif_set_tx_rate_retry_policy(wvif, i, tmp_rates);
@@ -300,11 +300,11 @@ static void wfx_tx_manage_pm(struct wfx_vif *wvif, struct ieee80211_hdr *hdr,
 }
 
 static u8 wfx_tx_get_raw_link_id(struct wfx_vif *wvif,
-                                     struct ieee80211_sta *sta,
-                                     struct ieee80211_hdr *hdr)
+                                struct ieee80211_sta *sta,
+                                struct ieee80211_hdr *hdr)
 {
        struct wfx_sta_priv *sta_priv =
-               sta ? (struct wfx_sta_priv *) &sta->drv_priv : NULL;
+               sta ? (struct wfx_sta_priv *)&sta->drv_priv : NULL;
        const u8 *da = ieee80211_get_DA(hdr);
 
        if (sta_priv && sta_priv->link_id)
@@ -368,7 +368,7 @@ static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates)
 }
 
 static u8 wfx_tx_get_rate_id(struct wfx_vif *wvif,
-                                 struct ieee80211_tx_info *tx_info)
+                            struct ieee80211_tx_info *tx_info)
 {
        bool tx_policy_renew = false;
        u8 rate_id;
@@ -430,7 +430,7 @@ static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta,
        struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        int queue_id = tx_info->hw_queue;
-       size_t offset = (size_t) skb->data & 3;
+       size_t offset = (size_t)skb->data & 3;
        int wmsg_len = sizeof(struct hif_msg) +
                        sizeof(struct hif_req_tx) + offset;
 
index 04b2147..c545dd7 100644 (file)
@@ -61,7 +61,7 @@ static inline struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb)
 static inline struct hif_req_tx *wfx_skb_txreq(struct sk_buff *skb)
 {
        struct hif_msg *hif = (struct hif_msg *)skb->data;
-       struct hif_req_tx *req = (struct hif_req_tx *) hif->body;
+       struct hif_req_tx *req = (struct hif_req_tx *)hif->body;
 
        return req;
 }
index 5554d6e..071b71e 100644 (file)
@@ -95,10 +95,6 @@ struct hif_req_reset {
        struct hif_reset_flags reset_flags;
 } __packed;
 
-struct hif_cnf_reset {
-       u32   status;
-} __packed;
-
 struct hif_req_read_mib {
        u16   mib_id;
        u16   reserved;
index 2428363..77bca43 100644 (file)
@@ -140,6 +140,7 @@ int hif_shutdown(struct wfx_dev *wdev)
        else
                control_reg_write(wdev, 0);
        mutex_unlock(&wdev->hif_cmd.lock);
+       mutex_unlock(&wdev->hif_cmd.key_renew_lock);
        kfree(hif);
        return ret;
 }
@@ -289,7 +290,7 @@ int hif_stop_scan(struct wfx_vif *wvif)
 }
 
 int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
-            const struct ieee80211_channel *channel, const u8 *ssidie)
+            struct ieee80211_channel *channel, const u8 *ssid, int ssidlen)
 {
        int ret;
        struct hif_msg *hif;
@@ -307,9 +308,9 @@ int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
        body->basic_rate_set =
                cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
        memcpy(body->bssid, conf->bssid, sizeof(body->bssid));
-       if (!conf->ibss_joined && ssidie) {
-               body->ssid_length = cpu_to_le32(ssidie[1]);
-               memcpy(body->ssid, &ssidie[2], ssidie[1]);
+       if (!conf->ibss_joined && ssid) {
+               body->ssid_length = cpu_to_le32(ssidlen);
+               memcpy(body->ssid, ssid, ssidlen);
        }
        wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body));
        ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false);
@@ -427,9 +428,9 @@ int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
        struct hif_msg *hif;
        struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif);
 
-       body->dtim_period = conf->dtim_period,
-       body->short_preamble = conf->use_short_preamble,
-       body->channel_number = cpu_to_le16(channel->hw_value),
+       body->dtim_period = conf->dtim_period;
+       body->short_preamble = conf->use_short_preamble;
+       body->channel_number = cpu_to_le16(channel->hw_value);
        body->beacon_interval = cpu_to_le32(conf->beacon_int);
        body->basic_rate_set =
                cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates));
index 20977e4..f8520a1 100644 (file)
@@ -46,7 +46,7 @@ int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211,
             int chan_start, int chan_num);
 int hif_stop_scan(struct wfx_vif *wvif);
 int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf,
-            const struct ieee80211_channel *channel, const u8 *ssidie);
+            struct ieee80211_channel *channel, const u8 *ssid, int ssidlen);
 int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout);
 int hif_set_bss_params(struct wfx_vif *wvif,
                       const struct hif_req_set_bss_params *arg);
index bf3769c..26b1406 100644 (file)
@@ -191,10 +191,10 @@ static inline int hif_set_block_ack_policy(struct wfx_vif *wvif,
 }
 
 static inline int hif_set_association_mode(struct wfx_vif *wvif,
-                                          struct ieee80211_bss_conf *info,
-                                          struct ieee80211_sta_ht_cap *ht_cap)
+                                          struct ieee80211_bss_conf *info)
 {
        int basic_rates = wfx_rate_mask_to_hw(wvif->wdev, info->basic_rates);
+       struct ieee80211_sta *sta = NULL;
        struct hif_mib_set_association_mode val = {
                .preambtype_use = 1,
                .mode = 1,
@@ -204,12 +204,17 @@ static inline int hif_set_association_mode(struct wfx_vif *wvif,
                .basic_rate_set = cpu_to_le32(basic_rates)
        };
 
+       rcu_read_lock(); // protect sta
+       if (info->bssid && !info->ibss_joined)
+               sta = ieee80211_find_sta(wvif->vif, info->bssid);
+
        // FIXME: it is strange to not retrieve all information from bss_info
-       if (ht_cap && ht_cap->ht_supported) {
-               val.mpdu_start_spacing = ht_cap->ampdu_density;
+       if (sta && sta->ht_cap.ht_supported) {
+               val.mpdu_start_spacing = sta->ht_cap.ampdu_density;
                if (!(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT))
-                       val.greenfield = !!(ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD);
+                       val.greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
        }
+       rcu_read_unlock();
 
        return hif_write_mib(wvif->wdev, wvif->id,
                             HIF_MIB_ID_SET_ASSOCIATION_MODE, &val, sizeof(val));
index 47e04c5..d3a141d 100644 (file)
@@ -142,7 +142,7 @@ static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf,
                        goto err;
                if (!(cfg & prefetch))
                        break;
-               udelay(200);
+               usleep_range(200, 250);
        }
        if (i == 20) {
                ret = -ETIMEDOUT;
index 84adad6..3c4c240 100644 (file)
@@ -262,6 +262,16 @@ static int wfx_send_pdata_pds(struct wfx_dev *wdev)
        return ret;
 }
 
+static void wfx_free_common(void *data)
+{
+       struct wfx_dev *wdev = data;
+
+       mutex_destroy(&wdev->rx_stats_lock);
+       mutex_destroy(&wdev->conf_mutex);
+       wfx_tx_queues_deinit(wdev);
+       ieee80211_free_hw(wdev->hw);
+}
+
 struct wfx_dev *wfx_init_common(struct device *dev,
                                const struct wfx_platform_data *pdata,
                                const struct hwbus_ops *hwbus_ops,
@@ -332,15 +342,10 @@ struct wfx_dev *wfx_init_common(struct device *dev,
        wfx_init_hif_cmd(&wdev->hif_cmd);
        wfx_tx_queues_init(wdev);
 
-       return wdev;
-}
+       if (devm_add_action_or_reset(dev, wfx_free_common, wdev))
+               return NULL;
 
-void wfx_free_common(struct wfx_dev *wdev)
-{
-       mutex_destroy(&wdev->rx_stats_lock);
-       mutex_destroy(&wdev->conf_mutex);
-       wfx_tx_queues_deinit(wdev);
-       ieee80211_free_hw(wdev->hw);
+       return wdev;
 }
 
 int wfx_probe(struct wfx_dev *wdev)
@@ -420,7 +425,7 @@ int wfx_probe(struct wfx_dev *wdev)
                        "enable 'quiescent' power mode with gpio %d and PDS file %s\n",
                        desc_to_gpio(wdev->pdata.gpio_wakeup),
                        wdev->pdata.file_pds);
-               gpiod_set_value(wdev->pdata.gpio_wakeup, 1);
+               gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1);
                control_reg_write(wdev, 0);
                hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT);
        } else {
index 875f8c2..9c94100 100644 (file)
@@ -34,7 +34,6 @@ struct wfx_dev *wfx_init_common(struct device *dev,
                                const struct wfx_platform_data *pdata,
                                const struct hwbus_ops *hwbus_ops,
                                void *hwbus_priv);
-void wfx_free_common(struct wfx_dev *wdev);
 
 int wfx_probe(struct wfx_dev *wdev);
 void wfx_release(struct wfx_dev *wdev);
index 0bcc61f..39d9127 100644 (file)
@@ -130,12 +130,12 @@ static void wfx_tx_queue_clear(struct wfx_dev *wdev, struct wfx_queue *queue,
        spin_lock_bh(&queue->queue.lock);
        while ((item = __skb_dequeue(&queue->queue)) != NULL)
                skb_queue_head(gc_list, item);
-       spin_lock_bh(&stats->pending.lock);
+       spin_lock_nested(&stats->pending.lock, 1);
        for (i = 0; i < ARRAY_SIZE(stats->link_map_cache); ++i) {
                stats->link_map_cache[i] -= queue->link_map_cache[i];
                queue->link_map_cache[i] = 0;
        }
-       spin_unlock_bh(&stats->pending.lock);
+       spin_unlock(&stats->pending.lock);
        spin_unlock_bh(&queue->queue.lock);
 }
 
@@ -207,9 +207,9 @@ void wfx_tx_queue_put(struct wfx_dev *wdev, struct wfx_queue *queue,
 
        ++queue->link_map_cache[tx_priv->link_id];
 
-       spin_lock_bh(&stats->pending.lock);
+       spin_lock_nested(&stats->pending.lock, 1);
        ++stats->link_map_cache[tx_priv->link_id];
-       spin_unlock_bh(&stats->pending.lock);
+       spin_unlock(&stats->pending.lock);
        spin_unlock_bh(&queue->queue.lock);
 }
 
@@ -237,11 +237,11 @@ static struct sk_buff *wfx_tx_queue_get(struct wfx_dev *wdev,
                __skb_unlink(skb, &queue->queue);
                --queue->link_map_cache[tx_priv->link_id];
 
-               spin_lock_bh(&stats->pending.lock);
+               spin_lock_nested(&stats->pending.lock, 1);
                __skb_queue_tail(&stats->pending, skb);
                if (!--stats->link_map_cache[tx_priv->link_id])
                        wakeup_stats = true;
-               spin_unlock_bh(&stats->pending.lock);
+               spin_unlock(&stats->pending.lock);
        }
        spin_unlock_bh(&queue->queue.lock);
        if (wakeup_stats)
@@ -259,10 +259,10 @@ int wfx_pending_requeue(struct wfx_dev *wdev, struct sk_buff *skb)
        spin_lock_bh(&queue->queue.lock);
        ++queue->link_map_cache[tx_priv->link_id];
 
-       spin_lock_bh(&stats->pending.lock);
+       spin_lock_nested(&stats->pending.lock, 1);
        ++stats->link_map_cache[tx_priv->link_id];
        __skb_unlink(skb, &stats->pending);
-       spin_unlock_bh(&stats->pending.lock);
+       spin_unlock(&stats->pending.lock);
        __skb_queue_tail(&queue->queue, skb);
        spin_unlock_bh(&queue->queue.lock);
        return 0;
@@ -481,7 +481,6 @@ struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
        struct wfx_queue *vif_queue = NULL;
        u32 tx_allowed_mask = 0;
        u32 vif_tx_allowed_mask = 0;
-       const struct wfx_tx_priv *tx_priv = NULL;
        struct wfx_vif *wvif;
        int not_found;
        int burst;
@@ -541,8 +540,7 @@ struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev)
                skb = wfx_tx_queue_get(wdev, queue, tx_allowed_mask);
                if (!skb)
                        continue;
-               tx_priv = wfx_skb_tx_priv(skb);
-               hif = (struct hif_msg *) skb->data;
+               hif = (struct hif_msg *)skb->data;
                wvif = wdev_to_wvif(wdev, hif->interface);
                WARN_ON(!wvif);
 
index 03d0f22..9d43034 100644 (file)
@@ -293,7 +293,6 @@ int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct wfx_dev *wdev = hw->priv;
        struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv;
        int old_uapsd = wvif->uapsd_mask;
-       int ret = 0;
 
        WARN_ON(queue >= hw->queues);
 
@@ -307,7 +306,7 @@ int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                wfx_update_pm(wvif);
        }
        mutex_unlock(&wdev->conf_mutex);
-       return ret;
+       return 0;
 }
 
 int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
@@ -491,9 +490,11 @@ static void wfx_set_mfp(struct wfx_vif *wvif,
 static void wfx_do_join(struct wfx_vif *wvif)
 {
        int ret;
-       const u8 *ssidie;
        struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf;
        struct cfg80211_bss *bss = NULL;
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+       const u8 *ssidie = NULL;
+       int ssidlen = 0;
 
        wfx_tx_lock_flush(wvif->wdev);
 
@@ -514,11 +515,14 @@ static void wfx_do_join(struct wfx_vif *wvif)
        if (!wvif->beacon_int)
                wvif->beacon_int = 1;
 
-       rcu_read_lock();
+       rcu_read_lock(); // protect ssidie
        if (!conf->ibss_joined)
                ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
-       else
-               ssidie = NULL;
+       if (ssidie) {
+               ssidlen = ssidie[1];
+               memcpy(ssid, &ssidie[2], ssidie[1]);
+       }
+       rcu_read_unlock();
 
        wfx_tx_flush(wvif->wdev);
 
@@ -527,10 +531,8 @@ static void wfx_do_join(struct wfx_vif *wvif)
 
        wfx_set_mfp(wvif, bss);
 
-       /* Perform actual join */
        wvif->wdev->tx_burst_idx = -1;
-       ret = hif_join(wvif, conf, wvif->channel, ssidie);
-       rcu_read_unlock();
+       ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen);
        if (ret) {
                ieee80211_connection_loss(wvif->vif);
                wvif->join_complete_status = -1;
@@ -605,7 +607,9 @@ int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        int i;
 
        for (i = 0; i < ARRAY_SIZE(sta_priv->buffered); i++)
-               WARN(sta_priv->buffered[i], "release station while Tx is in progress");
+               if (sta_priv->buffered[i])
+                       dev_warn(wvif->wdev->dev, "release station while %d pending frame on queue %d",
+                                sta_priv->buffered[i], i);
        // FIXME: see note in wfx_sta_add()
        if (vif->type == NL80211_IFTYPE_STATION)
                return 0;
@@ -689,6 +693,7 @@ static void wfx_join_finalize(struct wfx_vif *wvif,
                        wfx_rate_mask_to_hw(wvif->wdev, sta->supp_rates[wvif->channel->band]);
        else
                wvif->bss_params.operational_rate_set = -1;
+       rcu_read_unlock();
        if (sta &&
            info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)
                hif_dual_cts_protection(wvif, true);
@@ -701,8 +706,7 @@ static void wfx_join_finalize(struct wfx_vif *wvif,
        wvif->bss_params.beacon_lost_count = 20;
        wvif->bss_params.aid = info->aid;
 
-       hif_set_association_mode(wvif, info, sta ? &sta->ht_cap : NULL);
-       rcu_read_unlock();
+       hif_set_association_mode(wvif, info);
 
        if (!info->ibss_joined) {
                hif_keep_alive_period(wvif, 30 /* sec */);
@@ -904,7 +908,7 @@ static void wfx_update_tim_work(struct work_struct *work)
 int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
 {
        struct wfx_dev *wdev = hw->priv;
-       struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *) &sta->drv_priv;
+       struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *)&sta->drv_priv;
        struct wfx_vif *wvif = wdev_to_wvif(wdev, sta_dev->vif_id);
 
        schedule_work(&wvif->update_tim_work);
index 59e5855..80c92e8 100644 (file)
@@ -2,6 +2,10 @@
 config WILC1000
        tristate
        help
+         Add support for the Atmel WILC1000 802.11 b/g/n SoC.
+         This provides Wi-FI over an SDIO or SPI interface, and
+         is usually found in IoT devices.
+
          This module only support IEEE 802.11n WiFi.
 
 config WILC1000_SDIO
@@ -22,6 +26,7 @@ config WILC1000_SPI
        tristate "Atmel WILC1000 SPI (WiFi only)"
        depends on CFG80211 && INET && SPI
        select WILC1000
+       select CRC7
        help
          This module adds support for the SPI interface of adapters using
          WILC1000 chipset. The Atmel WILC1000 has a Serial Peripheral
index 4863e51..4bdcbc5 100644 (file)
@@ -6,29 +6,17 @@
 
 #include "cfg80211.h"
 
-#define FRAME_TYPE_ID                  0
-#define ACTION_CAT_ID                  24
-#define ACTION_SUBTYPE_ID              25
-#define P2P_PUB_ACTION_SUBTYPE         30
-
-#define ACTION_FRAME                   0xd0
-#define GO_INTENT_ATTR_ID              0x04
-#define CHANLIST_ATTR_ID               0x0b
-#define OPERCHAN_ATTR_ID               0x11
-#define PUB_ACTION_ATTR_ID             0x04
-#define P2PELEM_ATTR_ID                        0xdd
-
 #define GO_NEG_REQ                     0x00
 #define GO_NEG_RSP                     0x01
 #define GO_NEG_CONF                    0x02
 #define P2P_INV_REQ                    0x03
 #define P2P_INV_RSP                    0x04
-#define PUBLIC_ACT_VENDORSPEC          0x09
-#define GAS_INITIAL_REQ                        0x0a
-#define GAS_INITIAL_RSP                        0x0b
 
 #define WILC_INVALID_CHANNEL           0
 
+/* Operation at 2.4 GHz with channels 1-13 */
+#define WILC_WLAN_OPERATING_CLASS_2_4GHZ               0x51
+
 static const struct ieee80211_txrx_stypes
        wilc_wfi_cfg80211_mgmt_types[NUM_NL80211_IFTYPES] = {
        [NL80211_IFTYPE_STATION] = {
@@ -67,8 +55,50 @@ struct wilc_p2p_mgmt_data {
        u8 *buff;
 };
 
-static const u8 p2p_oui[] = {0x50, 0x6f, 0x9A, 0x09};
-static const u8 p2p_vendor_spec[] = {0xdd, 0x05, 0x00, 0x08, 0x40, 0x03};
+struct wilc_p2p_pub_act_frame {
+       u8 category;
+       u8 action;
+       u8 oui[3];
+       u8 oui_type;
+       u8 oui_subtype;
+       u8 dialog_token;
+       u8 elem[];
+} __packed;
+
+struct wilc_vendor_specific_ie {
+       u8 tag_number;
+       u8 tag_len;
+       u8 oui[3];
+       u8 oui_type;
+       u8 attr[];
+} __packed;
+
+struct wilc_attr_entry {
+       u8  attr_type;
+       __le16 attr_len;
+       u8 val[];
+} __packed;
+
+struct wilc_attr_oper_ch {
+       u8 attr_type;
+       __le16 attr_len;
+       u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+       u8 op_class;
+       u8 op_channel;
+} __packed;
+
+struct wilc_attr_ch_list {
+       u8 attr_type;
+       __le16 attr_len;
+       u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+       u8 elem[];
+} __packed;
+
+struct wilc_ch_list_elem {
+       u8 op_class;
+       u8 no_of_channels;
+       u8 ch_list[];
+} __packed;
 
 static void cfg_scan_result(enum scan_event scan_event,
                            struct wilc_rcvd_net_info *info, void *user_void)
@@ -172,9 +202,6 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status,
        } else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) {
                u16 reason = 0;
 
-               priv->p2p.local_random = 0x01;
-               priv->p2p.recv_random = 0x00;
-               priv->p2p.is_wilc_ie = false;
                eth_zero_addr(priv->associated_bss);
                wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
 
@@ -446,9 +473,6 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev,
                wilc->sta_ch = WILC_INVALID_CHANNEL;
        wilc_wlan_set_bssid(priv->dev, NULL, WILC_STATION_MODE);
 
-       priv->p2p.local_random = 0x01;
-       priv->p2p.recv_random = 0x00;
-       priv->p2p.is_wilc_ie = false;
        priv->hif_drv->p2p_timeout = 0;
 
        ret = wilc_disconnect(vif);
@@ -864,7 +888,6 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
                     struct cfg80211_pmksa *pmksa)
 {
        u32 i;
-       int ret = 0;
        struct wilc_vif *vif = netdev_priv(netdev);
        struct wilc_priv *priv = &vif->priv;
 
@@ -877,21 +900,20 @@ static int del_pmksa(struct wiphy *wiphy, struct net_device *netdev,
                }
        }
 
-       if (i < priv->pmkid_list.numpmkid && priv->pmkid_list.numpmkid > 0) {
-               for (; i < (priv->pmkid_list.numpmkid - 1); i++) {
-                       memcpy(priv->pmkid_list.pmkidlist[i].bssid,
-                              priv->pmkid_list.pmkidlist[i + 1].bssid,
-                              ETH_ALEN);
-                       memcpy(priv->pmkid_list.pmkidlist[i].pmkid,
-                              priv->pmkid_list.pmkidlist[i + 1].pmkid,
-                              WLAN_PMKID_LEN);
-               }
-               priv->pmkid_list.numpmkid--;
-       } else {
-               ret = -EINVAL;
+       if (i == priv->pmkid_list.numpmkid)
+               return -EINVAL;
+
+       for (; i < (priv->pmkid_list.numpmkid - 1); i++) {
+               memcpy(priv->pmkid_list.pmkidlist[i].bssid,
+                      priv->pmkid_list.pmkidlist[i + 1].bssid,
+                      ETH_ALEN);
+               memcpy(priv->pmkid_list.pmkidlist[i].pmkid,
+                      priv->pmkid_list.pmkidlist[i + 1].pmkid,
+                      WLAN_PMKID_LEN);
        }
+       priv->pmkid_list.numpmkid--;
 
-       return ret;
+       return 0;
 }
 
 static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
@@ -903,113 +925,50 @@ static int flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
        return 0;
 }
 
-static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u8 ch_list_attr_idx,
-                                             u8 op_ch_attr_idx, u8 sta_ch)
-{
-       int i = 0;
-       int j = 0;
-
-       if (ch_list_attr_idx) {
-               u8 limit = ch_list_attr_idx + 3 + buf[ch_list_attr_idx + 1];
-
-               for (i = ch_list_attr_idx + 3; i < limit; i++) {
-                       if (buf[i] == 0x51) {
-                               for (j = i + 2; j < ((i + 2) + buf[i + 1]); j++)
-                                       buf[j] = sta_ch;
-                               break;
-                       }
-               }
-       }
-
-       if (op_ch_attr_idx) {
-               buf[op_ch_attr_idx + 6] = 0x51;
-               buf[op_ch_attr_idx + 7] = sta_ch;
-       }
-}
-
-static void wilc_wfi_cfg_parse_rx_action(u8 *buf, u32 len, u8 sta_ch)
+static inline void wilc_wfi_cfg_parse_ch_attr(u8 *buf, u32 len, u8 sta_ch)
 {
+       struct wilc_attr_entry *e;
+       struct wilc_attr_ch_list *ch_list;
+       struct wilc_attr_oper_ch *op_ch;
        u32 index = 0;
-       u8 op_channel_attr_index = 0;
-       u8 channel_list_attr_index = 0;
-
-       while (index < len) {
-               if (buf[index] == GO_INTENT_ATTR_ID)
-                       buf[index + 3] = (buf[index + 3]  & 0x01) | (0x00 << 1);
-
-               if (buf[index] ==  CHANLIST_ATTR_ID)
-                       channel_list_attr_index = index;
-               else if (buf[index] ==  OPERCHAN_ATTR_ID)
-                       op_channel_attr_index = index;
-               index += buf[index + 1] + 3;
-       }
-       if (sta_ch != WILC_INVALID_CHANNEL)
-               wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
-                                          op_channel_attr_index, sta_ch);
-}
+       u8 ch_list_idx = 0;
+       u8 op_ch_idx = 0;
 
-static void wilc_wfi_cfg_parse_tx_action(u8 *buf, u32 len, bool oper_ch,
-                                        u8 iftype, u8 sta_ch)
-{
-       u32 index = 0;
-       u8 op_channel_attr_index = 0;
-       u8 channel_list_attr_index = 0;
-
-       while (index < len) {
-               if (buf[index] == GO_INTENT_ATTR_ID) {
-                       buf[index + 3] = (buf[index + 3]  & 0x01) | (0x0f << 1);
+       if (sta_ch == WILC_INVALID_CHANNEL)
+               return;
 
+       while (index + sizeof(*e) <= len) {
+               e = (struct wilc_attr_entry *)&buf[index];
+               if (e->attr_type == IEEE80211_P2P_ATTR_CHANNEL_LIST)
+                       ch_list_idx = index;
+               else if (e->attr_type == IEEE80211_P2P_ATTR_OPER_CHANNEL)
+                       op_ch_idx = index;
+               if (ch_list_idx && op_ch_idx)
                        break;
-               }
-
-               if (buf[index] ==  CHANLIST_ATTR_ID)
-                       channel_list_attr_index = index;
-               else if (buf[index] ==  OPERCHAN_ATTR_ID)
-                       op_channel_attr_index = index;
-               index += buf[index + 1] + 3;
+               index += le16_to_cpu(e->attr_len) + sizeof(*e);
        }
-       if (sta_ch != WILC_INVALID_CHANNEL && oper_ch)
-               wilc_wfi_cfg_parse_ch_attr(buf, channel_list_attr_index,
-                                          op_channel_attr_index, sta_ch);
-}
 
-static void wilc_wfi_cfg_parse_rx_vendor_spec(struct wilc_priv *priv, u8 *buff,
-                                             u32 size)
-{
-       int i;
-       u8 subtype;
-       struct wilc_vif *vif = netdev_priv(priv->dev);
-
-       subtype = buff[P2P_PUB_ACTION_SUBTYPE];
-       if ((subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) &&
-           !priv->p2p.is_wilc_ie) {
-               for (i = P2P_PUB_ACTION_SUBTYPE; i < size; i++) {
-                       if (!memcmp(p2p_vendor_spec, &buff[i], 6)) {
-                               priv->p2p.recv_random = buff[i + 6];
-                               priv->p2p.is_wilc_ie = true;
+       if (ch_list_idx) {
+               u16 attr_size;
+               struct wilc_ch_list_elem *e;
+               int i;
+
+               ch_list = (struct wilc_attr_ch_list *)&buf[ch_list_idx];
+               attr_size = le16_to_cpu(ch_list->attr_len);
+               for (i = 0; i < attr_size;) {
+                       e = (struct wilc_ch_list_elem *)(ch_list->elem + i);
+                       if (e->op_class == WILC_WLAN_OPERATING_CLASS_2_4GHZ) {
+                               memset(e->ch_list, sta_ch, e->no_of_channels);
                                break;
                        }
+                       i += e->no_of_channels;
                }
        }
 
-       if (priv->p2p.local_random <= priv->p2p.recv_random) {
-               netdev_dbg(vif->ndev,
-                          "PEER WILL BE GO LocaRand=%02x RecvRand %02x\n",
-                          priv->p2p.local_random, priv->p2p.recv_random);
-               return;
-       }
-
-       if (subtype == GO_NEG_REQ || subtype == GO_NEG_RSP ||
-           subtype == P2P_INV_REQ || subtype == P2P_INV_RSP) {
-               for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < size; i++) {
-                       if (buff[i] == P2PELEM_ATTR_ID &&
-                           !(memcmp(p2p_oui, &buff[i + 2], 4))) {
-                               wilc_wfi_cfg_parse_rx_action(&buff[i + 6],
-                                                            size - (i + 6),
-                                                            vif->wilc->sta_ch);
-                               break;
-                       }
-               }
+       if (op_ch_idx) {
+               op_ch = (struct wilc_attr_oper_ch *)&buf[op_ch_idx];
+               op_ch->op_class = WILC_WLAN_OPERATING_CLASS_2_4GHZ;
+               op_ch->op_channel = sta_ch;
        }
 }
 
@@ -1018,17 +977,22 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
        struct wilc *wl = vif->wilc;
        struct wilc_priv *priv = &vif->priv;
        struct host_if_drv *wfi_drv = priv->hif_drv;
+       struct ieee80211_mgmt *mgmt;
+       struct wilc_vendor_specific_ie *p;
+       struct wilc_p2p_pub_act_frame *d;
+       int ie_offset = offsetof(struct ieee80211_mgmt, u) + sizeof(*d);
+       const u8 *vendor_ie;
        u32 header, pkt_offset;
        s32 freq;
-       __le16 fc;
 
        header = get_unaligned_le32(buff - HOST_HDR_OFFSET);
-       pkt_offset = GET_PKT_OFFSET(header);
+       pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header);
 
        if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
                bool ack = false;
+               struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)buff;
 
-               if (buff[FRAME_TYPE_ID] == IEEE80211_STYPE_PROBE_RESP ||
+               if (ieee80211_is_probe_resp(hdr->frame_control) ||
                    pkt_offset & IS_MGMT_STATUS_SUCCES)
                        ack = true;
 
@@ -1039,44 +1003,33 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size)
 
        freq = ieee80211_channel_to_frequency(wl->op_ch, NL80211_BAND_2GHZ);
 
-       fc = ((struct ieee80211_hdr *)buff)->frame_control;
-       if (!ieee80211_is_action(fc)) {
-               cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
-               return;
-       }
+       mgmt = (struct ieee80211_mgmt *)buff;
+       if (!ieee80211_is_action(mgmt->frame_control))
+               goto out_rx_mgmt;
 
        if (priv->cfg_scanning &&
            time_after_eq(jiffies, (unsigned long)wfi_drv->p2p_timeout)) {
                netdev_dbg(vif->ndev, "Receiving action wrong ch\n");
                return;
        }
-       if (buff[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) {
-               u8 subtype = buff[P2P_PUB_ACTION_SUBTYPE];
 
-               switch (buff[ACTION_SUBTYPE_ID]) {
-               case GAS_INITIAL_REQ:
-               case GAS_INITIAL_RSP:
-                       break;
+       if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size))
+               goto out_rx_mgmt;
 
-               case PUBLIC_ACT_VENDORSPEC:
-                       if (!memcmp(p2p_oui, &buff[ACTION_SUBTYPE_ID + 1], 4))
-                               wilc_wfi_cfg_parse_rx_vendor_spec(priv, buff,
-                                                                 size);
+       d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
+       if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP &&
+           d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
+               goto out_rx_mgmt;
 
-                       if ((subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) &&
-                           priv->p2p.is_wilc_ie)
-                               size -= 7;
+       vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
+                                           buff + ie_offset, size - ie_offset);
+       if (!vendor_ie)
+               goto out_rx_mgmt;
 
-                       break;
-
-               default:
-                       netdev_dbg(vif->ndev,
-                                  "%s: Not handled action frame type:%x\n",
-                                  __func__, buff[ACTION_SUBTYPE_ID]);
-                       break;
-               }
-       }
+       p = (struct wilc_vendor_specific_ie *)vendor_ie;
+       wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch);
 
+out_rx_mgmt:
        cfg80211_rx_mgmt(&priv->wdev, freq, 0, buff, size, 0);
 }
 
@@ -1156,57 +1109,6 @@ static int cancel_remain_on_channel(struct wiphy *wiphy,
        return wilc_listen_state_expired(vif, cookie);
 }
 
-static void wilc_wfi_cfg_tx_vendor_spec(struct wilc_priv *priv,
-                                       struct wilc_p2p_mgmt_data *mgmt_tx,
-                                       struct cfg80211_mgmt_tx_params *params,
-                                       u8 iftype, u32 buf_len)
-{
-       const u8 *buf = params->buf;
-       size_t len = params->len;
-       u32 i;
-       u8 subtype = buf[P2P_PUB_ACTION_SUBTYPE];
-       struct wilc_vif *vif = netdev_priv(priv->dev);
-
-       if (subtype == GO_NEG_REQ || subtype == GO_NEG_RSP) {
-               if (priv->p2p.local_random == 1 &&
-                   priv->p2p.recv_random < priv->p2p.local_random) {
-                       get_random_bytes(&priv->p2p.local_random, 1);
-                       priv->p2p.local_random++;
-               }
-       }
-
-       if (priv->p2p.local_random <= priv->p2p.recv_random ||
-           !(subtype == GO_NEG_REQ || subtype == GO_NEG_RSP ||
-             subtype == P2P_INV_REQ || subtype == P2P_INV_RSP))
-               return;
-
-       for (i = P2P_PUB_ACTION_SUBTYPE + 2; i < len; i++) {
-               if (buf[i] == P2PELEM_ATTR_ID &&
-                   !memcmp(p2p_oui, &buf[i + 2], 4)) {
-                       bool oper_ch = false;
-                       u8 *tx_buff = &mgmt_tx->buff[i + 6];
-
-                       if (subtype == P2P_INV_REQ || subtype == P2P_INV_RSP)
-                               oper_ch = true;
-
-                       wilc_wfi_cfg_parse_tx_action(tx_buff, len - (i + 6),
-                                                    oper_ch, iftype,
-                                                    vif->wilc->sta_ch);
-
-                       break;
-               }
-       }
-
-       if (subtype != P2P_INV_REQ && subtype != P2P_INV_RSP) {
-               int vendor_spec_len = sizeof(p2p_vendor_spec);
-
-               memcpy(&mgmt_tx->buff[len], p2p_vendor_spec,
-                      vendor_spec_len);
-               mgmt_tx->buff[len + vendor_spec_len] = priv->p2p.local_random;
-               mgmt_tx->size = buf_len;
-       }
-}
-
 static int mgmt_tx(struct wiphy *wiphy,
                   struct wireless_dev *wdev,
                   struct cfg80211_mgmt_tx_params *params,
@@ -1221,8 +1123,10 @@ static int mgmt_tx(struct wiphy *wiphy,
        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);
+       struct wilc_vendor_specific_ie *p;
+       struct wilc_p2p_pub_act_frame *d;
+       int ie_offset = offsetof(struct ieee80211_mgmt, u) + sizeof(*d);
+       const u8 *vendor_ie;
        int ret = 0;
 
        *cookie = prandom_u32();
@@ -1238,14 +1142,13 @@ static int mgmt_tx(struct wiphy *wiphy,
                goto out;
        }
 
-       mgmt_tx->buff = kmalloc(buf_len, GFP_KERNEL);
+       mgmt_tx->buff = kmemdup(buf, len, GFP_KERNEL);
        if (!mgmt_tx->buff) {
                ret = -ENOMEM;
                kfree(mgmt_tx);
                goto out;
        }
 
-       memcpy(mgmt_tx->buff, buf, len);
        mgmt_tx->size = len;
 
        if (ieee80211_is_probe_resp(mgmt->frame_control)) {
@@ -1254,39 +1157,29 @@ static int mgmt_tx(struct wiphy *wiphy,
                goto out_txq_add_pkt;
        }
 
-       if (!ieee80211_is_action(mgmt->frame_control))
-               goto out_txq_add_pkt;
+       if (!ieee80211_is_public_action((struct ieee80211_hdr *)buf, len))
+               goto out_set_timeout;
 
-       if (buf[ACTION_CAT_ID] == PUB_ACTION_ATTR_ID) {
-               if (buf[ACTION_SUBTYPE_ID] != PUBLIC_ACT_VENDORSPEC ||
-                   buf[P2P_PUB_ACTION_SUBTYPE] != GO_NEG_CONF) {
-                       wilc_set_mac_chnl_num(vif, chan->hw_value);
-                       vif->wilc->op_ch = chan->hw_value;
-               }
-               switch (buf[ACTION_SUBTYPE_ID]) {
-               case GAS_INITIAL_REQ:
-               case GAS_INITIAL_RSP:
-                       break;
+       d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action);
+       if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P ||
+           d->oui_subtype != GO_NEG_CONF) {
+               wilc_set_mac_chnl_num(vif, chan->hw_value);
+               vif->wilc->op_ch = chan->hw_value;
+       }
 
-               case PUBLIC_ACT_VENDORSPEC:
-                       if (!memcmp(p2p_oui, &buf[ACTION_SUBTYPE_ID + 1], 4))
-                               wilc_wfi_cfg_tx_vendor_spec(priv, mgmt_tx,
-                                                           params, vif->iftype,
-                                                           buf_len);
-                       else
-                               netdev_dbg(vif->ndev,
-                                          "Not a P2P public action frame\n");
+       if (d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP)
+               goto out_set_timeout;
 
-                       break;
+       vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
+                                           mgmt_tx->buff + ie_offset,
+                                           len - ie_offset);
+       if (!vendor_ie)
+               goto out_set_timeout;
 
-               default:
-                       netdev_dbg(vif->ndev,
-                                  "%s: Not handled action frame type:%x\n",
-                                  __func__, buf[ACTION_SUBTYPE_ID]);
-                       break;
-               }
-       }
+       p = (struct wilc_vendor_specific_ie *)vendor_ie;
+       wilc_wfi_cfg_parse_ch_attr(p->attr, p->tag_len - 4, vif->wilc->sta_ch);
 
+out_set_timeout:
        wfi_drv->p2p_timeout = (jiffies + msecs_to_jiffies(wait));
 
 out_txq_add_pkt:
@@ -1400,10 +1293,6 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev,
        struct wilc_vif *vif = netdev_priv(dev);
        struct wilc_priv *priv = &vif->priv;
 
-       priv->p2p.local_random = 0x01;
-       priv->p2p.recv_random = 0x00;
-       priv->p2p.is_wilc_ie = false;
-
        switch (type) {
        case NL80211_IFTYPE_STATION:
                vif->connecting = false;
index 658790b..6c7de2f 100644 (file)
@@ -801,7 +801,7 @@ static void wilc_hif_pack_sta_param(u8 *cur_byte, const u8 *mac,
 
        if (params->ht_capa) {
                *cur_byte++ = true;
-               memcpy(cur_byte, &params->ht_capa,
+               memcpy(cur_byte, params->ht_capa,
                       sizeof(struct ieee80211_ht_cap));
        } else {
                *cur_byte++ = false;
@@ -861,9 +861,8 @@ static int wilc_handle_roc_expired(struct wilc_vif *vif, u64 cookie)
        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) {
+       if (vif->priv.p2p_listen_state) {
                remain_on_chan_flag = false;
                wid.id = WID_REMAIN_ON_CHAN;
                wid.type = WID_STR;
diff --git a/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt b/drivers/staging/wilc1000/microchip,wilc1000,sdio.txt
deleted file mode 100644 (file)
index da52359..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-* Microchip WILC wireless SDIO device
-
-The wilc1000 chips can be connected via SDIO. The node is used to specifiy
-child node to the SDIO controller that connects the device to the system.
-
-Required properties:
-- compatible   :       Should be "microchip,wilc1000-spi"
-- irq-gpios    :       Connect to a host IRQ
-- reg          :       Slot ID used in the controller
-
-Optional:
-- bus-width    :       Number of data lines wired up the slot. Default 1 bit.
-- rtc_clk      :       Clock connected on the rtc clock line. Must be assigned
-                       a frequency with assigned-clocks property, and must be
-                       connected to a clock provider.
-
-Examples:
-mmc1: mmc@fc000000 {
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3>;
-               non-removable;
-               vmmc-supply = <&vcc_mmc1_reg>;
-               vqmmc-supply = <&vcc_3v3_reg>;
-               status = "okay";
-
-               wilc_sdio@0 {
-                       compatible = "microchip,wilc1000-sdio";
-                       irq-gpios = <&pioC 27 0>;
-                       clocks = <&pck1>;
-                       clock-names = "rtc_clk";
-                       assigned-clocks = <&pck1>;
-                       assigned-clock-rates = <32768>;
-                       status = "okay";
-                       reg = <0>;
-                       bus-width = <4>;
-               }
-       };
-}
diff --git a/drivers/staging/wilc1000/microchip,wilc1000,spi.txt b/drivers/staging/wilc1000/microchip,wilc1000,spi.txt
deleted file mode 100644 (file)
index 3423693..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-* Microchip WILC wireless SPI device
-
-The wilc1000 chips can be connected via SPI. This document describes
-the binding for the SPI connected module.
-
-Required properties:
-- compatible           : Should be "microchip,wilc1000-spi"
-- spi-max-frequency    : Maximum SPI clocking speed of device in Hz
-- reg                  : Chip select address of device
-- irq-gpios            : Connect to a host IRQ
-
-Optional:
-- rtc_clk      :       Clock connected on the rtc clock line. Must be assigned
-                       a frequency with assigned-clocks property, and must be
-                       connected to a clock provider.
-
-Examples:
-
-spi1: spi@fc018000 {
-               cs-gpios = <&pioB 21 0>;
-               status = "okay";
-
-               wilc_spi@0 {
-                       compatible = "microchip,wilc1000-spi";
-                       spi-max-frequency = <48000000>;
-                       reg = <0>;
-                       irq-gpios = <&pioC 27 0>;
-                       clocks = <&pck1>;
-                       clock-names = "rtc_clk";
-                       assigned-clocks = <&pck1>;
-                       assigned-clock-rates = <32768>;
-                       status = "okay";
-               };
-};
diff --git a/drivers/staging/wilc1000/microchip,wilc1000.yaml b/drivers/staging/wilc1000/microchip,wilc1000.yaml
new file mode 100644 (file)
index 0000000..2c320eb
--- /dev/null
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/wireless/microchip,wilc1000.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip WILC wireless devicetree bindings
+
+maintainers:
+  - Adham Abozaeid <adham.abozaeid@microchip.com>
+  - Ajay Singh <ajay.kathat@microchip.com>
+
+description:
+  The wilc1000 chips can be connected via SPI or SDIO. This document
+  describes the binding to connect wilc devices.
+
+properties:
+  compatible:
+    const: microchip,wilc1000
+
+  spi-max-frequency: true
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    description: phandle to the clock connected on rtc clock line.
+    maxItems: 1
+
+  clock-names:
+    const: rtc
+
+required:
+  - compatible
+  - interrupts
+
+examples:
+  - |
+    spi {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      wifi@0 {
+        compatible = "microchip,wilc1000";
+        spi-max-frequency = <48000000>;
+        reg = <0>;
+        interrupt-parent = <&pioC>;
+        interrupts = <27 0>;
+        clocks = <&pck1>;
+        clock-names = "rtc";
+      };
+    };
+
+  - |
+    mmc {
+      #address-cells = <1>;
+      #size-cells = <0>;
+      pinctrl-names = "default";
+      pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3>;
+      non-removable;
+      vmmc-supply = <&vcc_mmc1_reg>;
+      vqmmc-supply = <&vcc_3v3_reg>;
+      bus-width = <4>;
+      wifi@0 {
+        compatible = "microchip,wilc1000";
+        reg = <0>;
+        interrupt-parent = <&pioC>;
+        interrupts = <27 0>;
+        clocks = <&pck1>;
+        clock-names = "rtc";
+      };
+    };
index 48ac33f..6033141 100644 (file)
@@ -40,7 +40,7 @@ void wilc_wfi_monitor_rx(struct net_device *mon_dev, u8 *buff, u32 size)
         * The packet offset field contain info about what type of management
         * the frame we are dealing with and ack status
         */
-       pkt_offset = GET_PKT_OFFSET(header);
+       pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header);
 
        if (pkt_offset & IS_MANAGMEMENT_CALLBACK) {
                /* hostapd callback mgmt frame */
index fce5bf2..f94a17b 100644 (file)
@@ -46,29 +46,21 @@ static irqreturn_t isr_bh_routine(int irq, void *userdata)
 
 static int init_irq(struct net_device *dev)
 {
-       int ret = 0;
        struct wilc_vif *vif = netdev_priv(dev);
        struct wilc *wl = vif->wilc;
-
-       ret = gpiod_direction_input(wl->gpio_irq);
-       if (ret) {
-               netdev_err(dev, "could not obtain gpio for WILC_INTR\n");
-               return ret;
-       }
-
-       wl->dev_irq_num = gpiod_to_irq(wl->gpio_irq);
+       int ret;
 
        ret = request_threaded_irq(wl->dev_irq_num, isr_uh_routine,
                                   isr_bh_routine,
                                   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                   "WILC_IRQ", dev);
-       if (ret < 0)
-               netdev_err(dev, "Failed to request IRQ\n");
-       else
-               netdev_dbg(dev, "IRQ request succeeded IRQ-NUM= %d\n",
-                          wl->dev_irq_num);
+       if (ret) {
+               netdev_err(dev, "Failed to request IRQ [%d]\n", ret);
+               return ret;
+       }
+       netdev_dbg(dev, "IRQ request succeeded IRQ-NUM= %d\n", wl->dev_irq_num);
 
-       return ret;
+       return 0;
 }
 
 static void deinit_irq(struct net_device *dev)
@@ -501,7 +493,7 @@ static int wilc_wlan_initialize(struct net_device *dev, struct wilc_vif *vif)
                if (ret)
                        goto fail_wilc_wlan;
 
-               if (wl->gpio_irq && init_irq(dev)) {
+               if (wl->dev_irq_num && init_irq(dev)) {
                        ret = -EIO;
                        goto fail_threads;
                }
@@ -577,7 +569,6 @@ static int wilc_mac_open(struct net_device *ndev)
 {
        struct wilc_vif *vif = netdev_priv(ndev);
        struct wilc *wl = vif->wilc;
-       struct wilc_priv *priv = wdev_priv(vif->ndev->ieee80211_ptr);
        unsigned char mac_add[ETH_ALEN] = {0};
        int ret = 0;
 
@@ -621,7 +612,6 @@ static int wilc_mac_open(struct net_device *ndev)
                                 vif->frame_reg[1].reg);
        netif_wake_queue(ndev);
        wl->open_ifcs++;
-       priv->p2p.local_random = 0x01;
        vif->mac_opened = 1;
        return 0;
 }
@@ -804,8 +794,10 @@ void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size)
                u16 type = le16_to_cpup((__le16 *)buff);
 
                if (vif->priv.p2p_listen_state &&
-                   ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) ||
-                    (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)))
+                   ((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);
 
                if (vif->monitor_flag)
index d5f7a60..61cbec6 100644 (file)
@@ -29,8 +29,6 @@
 #define TCP_ACK_FILTER_LINK_SPEED_THRESH       54
 #define DEFAULT_LINK_SPEED                     72
 
-#define GET_PKT_OFFSET(a) (((a) >> 22) & 0x1ff)
-
 struct wilc_wfi_stats {
        unsigned long rx_packets;
        unsigned long tx_packets;
@@ -66,12 +64,6 @@ struct wilc_wfi_p2p_listen_params {
        u64 listen_cookie;
 };
 
-struct wilc_p2p_var {
-       u8 local_random;
-       u8 recv_random;
-       bool is_wilc_ie;
-};
-
 static const u32 wilc_cipher_suites[] = {
        WLAN_CIPHER_SUITE_WEP40,
        WLAN_CIPHER_SUITE_WEP104,
@@ -155,7 +147,6 @@ struct wilc_priv {
        struct mutex scan_req_lock;
        bool p2p_listen_state;
        int scanned_cnt;
-       struct wilc_p2p_var p2p;
 
        u64 inc_roc_cookie;
 };
@@ -218,7 +209,6 @@ struct wilc {
        const struct wilc_hif_func *hif_func;
        int io_type;
        s8 mac_status;
-       struct gpio_desc *gpio_irq;
        struct clk *rtc_clk;
        bool initialized;
        int dev_irq_num;
index ca99335..36eb589 100644 (file)
@@ -7,6 +7,8 @@
 #include <linux/clk.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/sdio.h>
+#include <linux/of_irq.h>
 
 #include "netdev.h"
 #include "cfg80211.h"
@@ -26,9 +28,6 @@ static const struct sdio_device_id wilc_sdio_ids[] = {
 struct wilc_sdio {
        bool irq_gpio;
        u32 block_size;
-       int nint;
-/* Max num interrupts allowed in registers 0xf7, 0xf8 */
-#define MAX_NUN_INT_THRPT_ENH2 (5)
        int has_thrpt_enh3;
 };
 
@@ -124,35 +123,34 @@ static int wilc_sdio_probe(struct sdio_func *func,
 {
        struct wilc *wilc;
        int ret;
-       struct gpio_desc *gpio = NULL;
        struct wilc_sdio *sdio_priv;
 
        sdio_priv = kzalloc(sizeof(*sdio_priv), GFP_KERNEL);
        if (!sdio_priv)
                return -ENOMEM;
 
-       if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) {
-               gpio = gpiod_get(&func->dev, "irq", GPIOD_IN);
-               if (IS_ERR(gpio)) {
-                       /* get the GPIO descriptor from hardcode GPIO number */
-                       gpio = gpio_to_desc(GPIO_NUM);
-                       if (!gpio)
-                               dev_err(&func->dev, "failed to get irq gpio\n");
-               }
-       }
-
        ret = wilc_cfg80211_init(&wilc, &func->dev, WILC_HIF_SDIO,
                                 &wilc_hif_sdio);
        if (ret) {
                kfree(sdio_priv);
                return ret;
        }
+
+       if (IS_ENABLED(CONFIG_WILC1000_HW_OOB_INTR)) {
+               struct device_node *np = func->card->dev.of_node;
+               int irq_num = of_irq_get(np, 0);
+
+               if (irq_num > 0) {
+                       wilc->dev_irq_num = irq_num;
+                       sdio_priv->irq_gpio = true;
+               }
+       }
+
        sdio_set_drvdata(func, wilc);
        wilc->bus_data = sdio_priv;
        wilc->dev = &func->dev;
-       wilc->gpio_irq = gpio;
 
-       wilc->rtc_clk = devm_clk_get(&func->card->dev, "rtc_clk");
+       wilc->rtc_clk = devm_clk_get(&func->card->dev, "rtc");
        if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER)
                return -EPROBE_DEFER;
        else if (!IS_ERR(wilc->rtc_clk))
@@ -166,10 +164,6 @@ static void wilc_sdio_remove(struct sdio_func *func)
 {
        struct wilc *wilc = sdio_get_drvdata(func);
 
-       /* free the GPIO in module remove */
-       if (wilc->gpio_irq)
-               gpiod_put(wilc->gpio_irq);
-
        if (!IS_ERR(wilc->rtc_clk))
                clk_disable_unprepare(wilc->rtc_clk);
 
@@ -185,8 +179,8 @@ static int wilc_sdio_reset(struct wilc *wilc)
        cmd.read_write = 1;
        cmd.function = 0;
        cmd.raw = 0;
-       cmd.address = 0x6;
-       cmd.data = 0x8;
+       cmd.address = SDIO_CCCR_ABORT;
+       cmd.data = WILC_SDIO_CCCR_ABORT_RESET;
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
                dev_err(&func->dev, "Fail cmd 52, reset cmd ...\n");
@@ -268,34 +262,38 @@ static int wilc_sdio_set_func0_csa_address(struct wilc *wilc, u32 adr)
        cmd.read_write = 1;
        cmd.function = 0;
        cmd.raw = 0;
-       cmd.address = 0x10c;
+       cmd.address = WILC_SDIO_FBR_CSA_REG;
        cmd.data = (u8)adr;
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
-               dev_err(&func->dev, "Failed cmd52, set 0x10c data...\n");
+               dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
+                       cmd.address);
                return ret;
        }
 
-       cmd.address = 0x10d;
+       cmd.address = WILC_SDIO_FBR_CSA_REG + 1;
        cmd.data = (u8)(adr >> 8);
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
-               dev_err(&func->dev, "Failed cmd52, set 0x10d data...\n");
+               dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
+                       cmd.address);
                return ret;
        }
 
-       cmd.address = 0x10e;
+       cmd.address = WILC_SDIO_FBR_CSA_REG + 2;
        cmd.data = (u8)(adr >> 16);
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
-               dev_err(&func->dev, "Failed cmd52, set 0x10e data...\n");
+               dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
+                       cmd.address);
                return ret;
        }
 
        return 0;
 }
 
-static int wilc_sdio_set_func0_block_size(struct wilc *wilc, u32 block_size)
+static int wilc_sdio_set_block_size(struct wilc *wilc, u8 func_num,
+                                   u32 block_size)
 {
        struct sdio_func *func = dev_to_sdio_func(wilc->dev);
        struct sdio_cmd52 cmd;
@@ -304,52 +302,21 @@ static int wilc_sdio_set_func0_block_size(struct wilc *wilc, u32 block_size)
        cmd.read_write = 1;
        cmd.function = 0;
        cmd.raw = 0;
-       cmd.address = 0x10;
+       cmd.address = SDIO_FBR_BASE(func_num) + SDIO_CCCR_BLKSIZE;
        cmd.data = (u8)block_size;
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
-               dev_err(&func->dev, "Failed cmd52, set 0x10 data...\n");
+               dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
+                       cmd.address);
                return ret;
        }
 
-       cmd.address = 0x11;
-       cmd.data = (u8)(block_size >> 8);
-       ret = wilc_sdio_cmd52(wilc, &cmd);
-       if (ret) {
-               dev_err(&func->dev, "Failed cmd52, set 0x11 data...\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-/********************************************
- *
- *      Function 1
- *
- ********************************************/
-
-static int wilc_sdio_set_func1_block_size(struct wilc *wilc, u32 block_size)
-{
-       struct sdio_func *func = dev_to_sdio_func(wilc->dev);
-       struct sdio_cmd52 cmd;
-       int ret;
-
-       cmd.read_write = 1;
-       cmd.function = 0;
-       cmd.raw = 0;
-       cmd.address = 0x110;
-       cmd.data = (u8)block_size;
-       ret = wilc_sdio_cmd52(wilc, &cmd);
-       if (ret) {
-               dev_err(&func->dev, "Failed cmd52, set 0x110 data...\n");
-               return ret;
-       }
-       cmd.address = 0x111;
+       cmd.address = SDIO_FBR_BASE(func_num) + SDIO_CCCR_BLKSIZE +  1;
        cmd.data = (u8)(block_size >> 8);
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
-               dev_err(&func->dev, "Failed cmd52, set 0x111 data...\n");
+               dev_err(&func->dev, "Failed cmd52, set %04x data...\n",
+                       cmd.address);
                return ret;
        }
 
@@ -369,7 +336,7 @@ static int wilc_sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
 
        cpu_to_le32s(&data);
 
-       if (addr >= 0xf0 && addr <= 0xff) {
+       if (addr >= 0xf0 && addr <= 0xff) { /* only vendor specific registers */
                struct sdio_cmd52 cmd;
 
                cmd.read_write = 1;
@@ -393,7 +360,7 @@ static int wilc_sdio_write_reg(struct wilc *wilc, u32 addr, u32 data)
 
                cmd.read_write = 1;
                cmd.function = 0;
-               cmd.address = 0x10f;
+               cmd.address = WILC_SDIO_FBR_DATA_REG;
                cmd.block_mode = 0;
                cmd.increment = 1;
                cmd.count = 4;
@@ -419,34 +386,19 @@ static int wilc_sdio_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
        cmd.read_write = 1;
        if (addr > 0) {
                /**
-                *      has to be word aligned...
-                **/
-               if (size & 0x3) {
-                       size += 4;
-                       size &= ~0x3;
-               }
-
-               /**
                 *      func 0 access
                 **/
                cmd.function = 0;
-               cmd.address = 0x10f;
+               cmd.address = WILC_SDIO_FBR_DATA_REG;
        } else {
                /**
-                *      has to be word aligned...
-                **/
-               if (size & 0x3) {
-                       size += 4;
-                       size &= ~0x3;
-               }
-
-               /**
                 *      func 1 access
                 **/
                cmd.function = 1;
-               cmd.address = 0;
+               cmd.address = WILC_SDIO_F1_DATA_REG;
        }
 
+       size = ALIGN(size, 4);
        nblk = size / block_size;
        nleft = size % block_size;
 
@@ -502,7 +454,7 @@ static int wilc_sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
        struct wilc_sdio *sdio_priv = wilc->bus_data;
        int ret;
 
-       if (addr >= 0xf0 && addr <= 0xff) {
+       if (addr >= 0xf0 && addr <= 0xff) { /* only vendor specific registers */
                struct sdio_cmd52 cmd;
 
                cmd.read_write = 0;
@@ -525,7 +477,7 @@ static int wilc_sdio_read_reg(struct wilc *wilc, u32 addr, u32 *data)
 
                cmd.read_write = 0;
                cmd.function = 0;
-               cmd.address = 0x10f;
+               cmd.address = WILC_SDIO_FBR_DATA_REG;
                cmd.block_mode = 0;
                cmd.increment = 1;
                cmd.count = 4;
@@ -555,34 +507,19 @@ static int wilc_sdio_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
        cmd.read_write = 0;
        if (addr > 0) {
                /**
-                *      has to be word aligned...
-                **/
-               if (size & 0x3) {
-                       size += 4;
-                       size &= ~0x3;
-               }
-
-               /**
                 *      func 0 access
                 **/
                cmd.function = 0;
-               cmd.address = 0x10f;
+               cmd.address = WILC_SDIO_FBR_DATA_REG;
        } else {
                /**
-                *      has to be word aligned...
-                **/
-               if (size & 0x3) {
-                       size += 4;
-                       size &= ~0x3;
-               }
-
-               /**
                 *      func 1 access
                 **/
                cmd.function = 1;
-               cmd.address = 0;
+               cmd.address = WILC_SDIO_F1_DATA_REG;
        }
 
+       size = ALIGN(size, 4);
        nblk = size / block_size;
        nleft = size % block_size;
 
@@ -651,17 +588,14 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
        int loop, ret;
        u32 chipid;
 
-       if (!resume)
-               sdio_priv->irq_gpio = wilc->dev_irq_num;
-
        /**
         *      function 0 csa enable
         **/
        cmd.read_write = 1;
        cmd.function = 0;
        cmd.raw = 1;
-       cmd.address = 0x100;
-       cmd.data = 0x80;
+       cmd.address = SDIO_FBR_BASE(func->num);
+       cmd.data = SDIO_FBR_ENABLE_CSA;
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
                dev_err(&func->dev, "Fail cmd 52, enable csa...\n");
@@ -671,7 +605,7 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
        /**
         *      function 0 block size
         **/
-       ret = wilc_sdio_set_func0_block_size(wilc, WILC_SDIO_BLOCK_SIZE);
+       ret = wilc_sdio_set_block_size(wilc, 0, WILC_SDIO_BLOCK_SIZE);
        if (ret) {
                dev_err(&func->dev, "Fail cmd 52, set func 0 block size...\n");
                return ret;
@@ -684,8 +618,8 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
        cmd.read_write = 1;
        cmd.function = 0;
        cmd.raw = 1;
-       cmd.address = 0x2;
-       cmd.data = 0x2;
+       cmd.address = SDIO_CCCR_IOEx;
+       cmd.data = WILC_SDIO_CCCR_IO_EN_FUNC1;
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
                dev_err(&func->dev,
@@ -699,7 +633,7 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
        cmd.read_write = 0;
        cmd.function = 0;
        cmd.raw = 0;
-       cmd.address = 0x3;
+       cmd.address = SDIO_CCCR_IORx;
        loop = 3;
        do {
                cmd.data = 0;
@@ -709,7 +643,7 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
                                "Fail cmd 52, get IOR register...\n");
                        return ret;
                }
-               if (cmd.data == 0x2)
+               if (cmd.data == WILC_SDIO_CCCR_IO_EN_FUNC1)
                        break;
        } while (loop--);
 
@@ -721,7 +655,7 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
        /**
         *      func 1 is ready, set func 1 block size
         **/
-       ret = wilc_sdio_set_func1_block_size(wilc, WILC_SDIO_BLOCK_SIZE);
+       ret = wilc_sdio_set_block_size(wilc, 1, WILC_SDIO_BLOCK_SIZE);
        if (ret) {
                dev_err(&func->dev, "Fail set func 1 block size...\n");
                return ret;
@@ -733,8 +667,8 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
        cmd.read_write = 1;
        cmd.function = 0;
        cmd.raw = 1;
-       cmd.address = 0x4;
-       cmd.data = 0x3;
+       cmd.address = SDIO_CCCR_IENx;
+       cmd.data = WILC_SDIO_CCCR_IEN_MASTER | WILC_SDIO_CCCR_IEN_FUNC1;
        ret = wilc_sdio_cmd52(wilc, &cmd);
        if (ret) {
                dev_err(&func->dev, "Fail cmd 52, set IEN register...\n");
@@ -745,13 +679,16 @@ static int wilc_sdio_init(struct wilc *wilc, bool resume)
         *      make sure can read back chip id correctly
         **/
        if (!resume) {
-               ret = wilc_sdio_read_reg(wilc, 0x1000, &chipid);
+               int rev;
+
+               ret = wilc_sdio_read_reg(wilc, WILC_CHIPID, &chipid);
                if (ret) {
                        dev_err(&func->dev, "Fail cmd read chip id...\n");
                        return ret;
                }
                dev_err(&func->dev, "chipid (%08x)\n", chipid);
-               if ((chipid & 0xfff) > 0x2a0)
+               rev = FIELD_GET(WILC_CHIP_REV_FIELD, chipid);
+               if (rev > FIELD_GET(WILC_CHIP_REV_FIELD, WILC_1000_BASE_ID_2A))
                        sdio_priv->has_thrpt_enh3 = 1;
                else
                        sdio_priv->has_thrpt_enh3 = 0;
@@ -773,12 +710,12 @@ static int wilc_sdio_read_size(struct wilc *wilc, u32 *size)
        cmd.read_write = 0;
        cmd.function = 0;
        cmd.raw = 0;
-       cmd.address = 0xf2;
+       cmd.address = WILC_SDIO_INTERRUPT_DATA_SZ_REG;
        cmd.data = 0;
        wilc_sdio_cmd52(wilc, &cmd);
        tmp = cmd.data;
 
-       cmd.address = 0xf3;
+       cmd.address = WILC_SDIO_INTERRUPT_DATA_SZ_REG + 1;
        cmd.data = 0;
        wilc_sdio_cmd52(wilc, &cmd);
        tmp |= (cmd.data << 8);
@@ -792,6 +729,7 @@ static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status)
        struct sdio_func *func = dev_to_sdio_func(wilc->dev);
        struct wilc_sdio *sdio_priv = wilc->bus_data;
        u32 tmp;
+       u8 irq_flags;
        struct sdio_cmd52 cmd;
 
        wilc_sdio_read_size(wilc, &tmp);
@@ -800,46 +738,22 @@ static int wilc_sdio_read_int(struct wilc *wilc, u32 *int_status)
         *      Read IRQ flags
         **/
        if (!sdio_priv->irq_gpio) {
-               int i;
-
-               cmd.read_write = 0;
                cmd.function = 1;
-               cmd.address = 0x04;
-               cmd.data = 0;
-               wilc_sdio_cmd52(wilc, &cmd);
-
-               if (cmd.data & BIT(0))
-                       tmp |= INT_0;
-               if (cmd.data & BIT(2))
-                       tmp |= INT_1;
-               if (cmd.data & BIT(3))
-                       tmp |= INT_2;
-               if (cmd.data & BIT(4))
-                       tmp |= INT_3;
-               if (cmd.data & BIT(5))
-                       tmp |= INT_4;
-               if (cmd.data & BIT(6))
-                       tmp |= INT_5;
-               for (i = sdio_priv->nint; i < MAX_NUM_INT; i++) {
-                       if ((tmp >> (IRG_FLAGS_OFFSET + i)) & 0x1) {
-                               dev_err(&func->dev,
-                                       "Unexpected interrupt (1) : tmp=%x, data=%x\n",
-                                       tmp, cmd.data);
-                               break;
-                       }
-               }
+               cmd.address = WILC_SDIO_EXT_IRQ_FLAG_REG;
        } else {
-               u32 irq_flags;
-
-               cmd.read_write = 0;
                cmd.function = 0;
-               cmd.raw = 0;
-               cmd.address = 0xf7;
-               cmd.data = 0;
-               wilc_sdio_cmd52(wilc, &cmd);
-               irq_flags = cmd.data & 0x1f;
-               tmp |= ((irq_flags >> 0) << IRG_FLAGS_OFFSET);
+               cmd.address = WILC_SDIO_IRQ_FLAG_REG;
        }
+       cmd.raw = 0;
+       cmd.read_write = 0;
+       cmd.data = 0;
+       wilc_sdio_cmd52(wilc, &cmd);
+       irq_flags = cmd.data;
+       tmp |= FIELD_PREP(IRG_FLAGS_MASK, cmd.data);
+
+       if (FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags))
+               dev_err(&func->dev, "Unexpected interrupt (1) int=%lx\n",
+                       FIELD_GET(UNHANDLED_IRQ_MASK, irq_flags));
 
        *int_status = tmp;
 
@@ -854,16 +768,11 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val)
        int vmm_ctl;
 
        if (sdio_priv->has_thrpt_enh3) {
-               u32 reg;
+               u32 reg = 0;
 
-               if (sdio_priv->irq_gpio) {
-                       u32 flags;
+               if (sdio_priv->irq_gpio)
+                       reg = val & (BIT(MAX_NUM_INT) - 1);
 
-                       flags = val & (BIT(MAX_NUN_INT_THRPT_ENH2) - 1);
-                       reg = flags;
-               } else {
-                       reg = 0;
-               }
                /* select VMM table 0 */
                if (val & SEL_VMM_TBL0)
                        reg |= BIT(5);
@@ -879,14 +788,14 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val)
                        cmd.read_write = 1;
                        cmd.function = 0;
                        cmd.raw = 0;
-                       cmd.address = 0xf8;
+                       cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
                        cmd.data = reg;
 
                        ret = wilc_sdio_cmd52(wilc, &cmd);
                        if (ret) {
                                dev_err(&func->dev,
-                                       "Failed cmd52, set 0xf8 data (%d) ...\n",
-                                       __LINE__);
+                                       "Failed cmd52, set (%02x) data (%d) ...\n",
+                                       cmd.address, __LINE__);
                                return ret;
                        }
                }
@@ -899,38 +808,36 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val)
                 * Must clear each interrupt individually.
                 */
                u32 flags;
+               int i;
 
                flags = val & (BIT(MAX_NUM_INT) - 1);
-               if (flags) {
-                       int i;
-
-                       for (i = 0; i < sdio_priv->nint; i++) {
-                               if (flags & 1) {
-                                       struct sdio_cmd52 cmd;
-
-                                       cmd.read_write = 1;
-                                       cmd.function = 0;
-                                       cmd.raw = 0;
-                                       cmd.address = 0xf8;
-                                       cmd.data = BIT(i);
-
-                                       ret = wilc_sdio_cmd52(wilc, &cmd);
-                                       if (ret) {
-                                               dev_err(&func->dev,
-                                                       "Failed cmd52, set 0xf8 data (%d) ...\n",
-                                                       __LINE__);
-                                               return ret;
-                                       }
+               for (i = 0; i < NUM_INT_EXT && flags; i++) {
+                       if (flags & BIT(i)) {
+                               struct sdio_cmd52 cmd;
+
+                               cmd.read_write = 1;
+                               cmd.function = 0;
+                               cmd.raw = 0;
+                               cmd.address = WILC_SDIO_IRQ_CLEAR_FLAG_REG;
+                               cmd.data = BIT(i);
+
+                               ret = wilc_sdio_cmd52(wilc, &cmd);
+                               if (ret) {
+                                       dev_err(&func->dev,
+                                               "Failed cmd52, set (%02x) data (%d) ...\n",
+                                               cmd.address, __LINE__);
+                                       return ret;
                                }
-                               flags >>= 1;
+                               flags &= ~BIT(i);
                        }
+               }
 
-                       for (i = sdio_priv->nint; i < MAX_NUM_INT; i++) {
-                               if (flags & 1)
-                                       dev_err(&func->dev,
-                                               "Unexpected interrupt cleared %d...\n",
-                                               i);
-                               flags >>= 1;
+               for (i = NUM_INT_EXT; i < MAX_NUM_INT && flags; i++) {
+                       if (flags & BIT(i)) {
+                               dev_err(&func->dev,
+                                       "Unexpected interrupt cleared %d...\n",
+                                       i);
+                               flags &= ~BIT(i);
                        }
                }
        }
@@ -952,13 +859,13 @@ static int wilc_sdio_clear_int_ext(struct wilc *wilc, u32 val)
                cmd.read_write = 1;
                cmd.function = 0;
                cmd.raw = 0;
-               cmd.address = 0xf6;
+               cmd.address = WILC_SDIO_VMM_TBL_CTRL_REG;
                cmd.data = vmm_ctl;
                ret = wilc_sdio_cmd52(wilc, &cmd);
                if (ret) {
                        dev_err(&func->dev,
-                               "Failed cmd52, set 0xf6 data (%d) ...\n",
-                               __LINE__);
+                               "Failed cmd52, set (%02x) data (%d) ...\n",
+                               cmd.address, __LINE__);
                        return ret;
                }
        }
@@ -975,13 +882,6 @@ static int wilc_sdio_sync_ext(struct wilc *wilc, int nint)
                dev_err(&func->dev, "Too many interrupts (%d)...\n", nint);
                return -EINVAL;
        }
-       if (nint > MAX_NUN_INT_THRPT_ENH2) {
-               dev_err(&func->dev,
-                       "Cannot support more than 5 interrupts when has_thrpt_enh2=1.\n");
-               return -EINVAL;
-       }
-
-       sdio_priv->nint = nint;
 
        /**
         *      Disable power sequencer
@@ -1097,7 +997,7 @@ static int wilc_sdio_resume(struct device *dev)
 }
 
 static const struct of_device_id wilc_of_match[] = {
-       { .compatible = "microchip,wilc1000-sdio", },
+       { .compatible = "microchip,wilc1000", },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, wilc_of_match);
index 3ffc7b4..3f19e3f 100644 (file)
@@ -6,72 +6,19 @@
 
 #include <linux/clk.h>
 #include <linux/spi/spi.h>
+#include <linux/crc7.h>
 
 #include "netdev.h"
 #include "cfg80211.h"
 
 struct wilc_spi {
        int crc_off;
-       int nint;
 };
 
 static const struct wilc_hif_func wilc_hif_spi;
 
 /********************************************
  *
- *      Crc7
- *
- ********************************************/
-
-static const u8 crc7_syndrome_table[256] = {
-       0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
-       0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
-       0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
-       0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
-       0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
-       0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
-       0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
-       0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
-       0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
-       0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
-       0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
-       0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
-       0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
-       0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
-       0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
-       0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
-       0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
-       0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
-       0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
-       0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
-       0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
-       0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
-       0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
-       0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
-       0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
-       0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
-       0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
-       0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
-       0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
-       0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
-       0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
-       0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
-};
-
-static u8 crc7_byte(u8 crc, u8 data)
-{
-       return crc7_syndrome_table[(crc << 1) ^ data];
-}
-
-static u8 crc7(u8 crc, const u8 *buffer, u32 len)
-{
-       while (len--)
-               crc = crc7_byte(crc, *buffer++);
-       return crc;
-}
-
-/********************************************
- *
  *      Spi protocol Function
  *
  ********************************************/
@@ -97,25 +44,62 @@ static u8 crc7(u8 crc, const u8 *buffer, u32 len)
 
 #define USE_SPI_DMA                            0
 
+#define WILC_SPI_COMMAND_STAT_SUCCESS          0
+#define WILC_GET_RESP_HDR_START(h)             (((h) >> 4) & 0xf)
+
+struct wilc_spi_cmd {
+       u8 cmd_type;
+       union {
+               struct {
+                       u8 addr[3];
+                       u8 crc[];
+               } __packed simple_cmd;
+               struct {
+                       u8 addr[3];
+                       u8 size[2];
+                       u8 crc[];
+               } __packed dma_cmd;
+               struct {
+                       u8 addr[3];
+                       u8 size[3];
+                       u8 crc[];
+               } __packed dma_cmd_ext;
+               struct {
+                       u8 addr[2];
+                       __be32 data;
+                       u8 crc[];
+               } __packed internal_w_cmd;
+               struct {
+                       u8 addr[3];
+                       __be32 data;
+                       u8 crc[];
+               } __packed w_cmd;
+       } u;
+} __packed;
+
+struct wilc_spi_read_rsp_data {
+       u8 rsp_cmd_type;
+       u8 status;
+       u8 resp_header;
+       u8 resp_data[4];
+       u8 crc[];
+} __packed;
+
+struct wilc_spi_rsp_data {
+       u8 rsp_cmd_type;
+       u8 status;
+} __packed;
+
 static int wilc_bus_probe(struct spi_device *spi)
 {
        int ret;
        struct wilc *wilc;
-       struct gpio_desc *gpio;
        struct wilc_spi *spi_priv;
 
        spi_priv = kzalloc(sizeof(*spi_priv), GFP_KERNEL);
        if (!spi_priv)
                return -ENOMEM;
 
-       gpio = gpiod_get(&spi->dev, "irq", GPIOD_IN);
-       if (IS_ERR(gpio)) {
-               /* get the GPIO descriptor from hardcode GPIO number */
-               gpio = gpio_to_desc(GPIO_NUM);
-               if (!gpio)
-                       dev_err(&spi->dev, "failed to get the irq gpio\n");
-       }
-
        ret = wilc_cfg80211_init(&wilc, &spi->dev, WILC_HIF_SPI, &wilc_hif_spi);
        if (ret) {
                kfree(spi_priv);
@@ -125,7 +109,7 @@ static int wilc_bus_probe(struct spi_device *spi)
        spi_set_drvdata(spi, wilc);
        wilc->dev = &spi->dev;
        wilc->bus_data = spi_priv;
-       wilc->gpio_irq = gpio;
+       wilc->dev_irq_num = spi->irq;
 
        wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk");
        if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER)
@@ -140,10 +124,6 @@ static int wilc_bus_remove(struct spi_device *spi)
 {
        struct wilc *wilc = spi_get_drvdata(spi);
 
-       /* free the GPIO in module remove */
-       if (wilc->gpio_irq)
-               gpiod_put(wilc->gpio_irq);
-
        if (!IS_ERR(wilc->rtc_clk))
                clk_disable_unprepare(wilc->rtc_clk);
 
@@ -152,7 +132,7 @@ static int wilc_bus_remove(struct spi_device *spi)
 }
 
 static const struct of_device_id wilc_of_match[] = {
-       { .compatible = "microchip,wilc1000-spi", },
+       { .compatible = "microchip,wilc1000", },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, wilc_of_match);
@@ -178,7 +158,10 @@ static int wilc_spi_tx(struct wilc *wilc, u8 *b, u32 len)
                struct spi_transfer tr = {
                        .tx_buf = b,
                        .len = len,
-                       .delay_usecs = 0,
+                       .delay = {
+                               .value = 0,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
                };
                char *r_buffer = kzalloc(len, GFP_KERNEL);
 
@@ -219,7 +202,10 @@ static int wilc_spi_rx(struct wilc *wilc, u8 *rb, u32 rlen)
                struct spi_transfer tr = {
                        .rx_buf = rb,
                        .len = rlen,
-                       .delay_usecs = 0,
+                       .delay = {
+                               .value = 0,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
 
                };
                char *t_buffer = kzalloc(rlen, GFP_KERNEL);
@@ -261,7 +247,10 @@ static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen)
                        .tx_buf = wb,
                        .len = rlen,
                        .bits_per_word = 8,
-                       .delay_usecs = 0,
+                       .delay = {
+                               .value = 0,
+                               .unit = SPI_DELAY_UNIT_USECS
+                       },
 
                };
 
@@ -284,335 +273,6 @@ static int wilc_spi_tx_rx(struct wilc *wilc, u8 *wb, u8 *rb, u32 rlen)
        return ret;
 }
 
-static int spi_cmd_complete(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz,
-                           u8 clockless)
-{
-       struct spi_device *spi = to_spi_device(wilc->dev);
-       struct wilc_spi *spi_priv = wilc->bus_data;
-       u8 wb[32], rb[32];
-       u8 wix, rix;
-       u32 len2;
-       u8 rsp;
-       int len = 0;
-       int result = 0;
-       int retry;
-       u8 crc[2];
-
-       wb[0] = cmd;
-       switch (cmd) {
-       case CMD_SINGLE_READ: /* single word (4 bytes) read */
-               wb[1] = (u8)(adr >> 16);
-               wb[2] = (u8)(adr >> 8);
-               wb[3] = (u8)adr;
-               len = 5;
-               break;
-
-       case CMD_INTERNAL_READ: /* internal register read */
-               wb[1] = (u8)(adr >> 8);
-               if (clockless == 1)
-                       wb[1] |= BIT(7);
-               wb[2] = (u8)adr;
-               wb[3] = 0x00;
-               len = 5;
-               break;
-
-       case CMD_TERMINATE:
-               wb[1] = 0x00;
-               wb[2] = 0x00;
-               wb[3] = 0x00;
-               len = 5;
-               break;
-
-       case CMD_REPEAT:
-               wb[1] = 0x00;
-               wb[2] = 0x00;
-               wb[3] = 0x00;
-               len = 5;
-               break;
-
-       case CMD_RESET:
-               wb[1] = 0xff;
-               wb[2] = 0xff;
-               wb[3] = 0xff;
-               len = 5;
-               break;
-
-       case CMD_DMA_WRITE: /* dma write */
-       case CMD_DMA_READ:  /* dma read */
-               wb[1] = (u8)(adr >> 16);
-               wb[2] = (u8)(adr >> 8);
-               wb[3] = (u8)adr;
-               wb[4] = (u8)(sz >> 8);
-               wb[5] = (u8)(sz);
-               len = 7;
-               break;
-
-       case CMD_DMA_EXT_WRITE: /* dma extended write */
-       case CMD_DMA_EXT_READ:  /* dma extended read */
-               wb[1] = (u8)(adr >> 16);
-               wb[2] = (u8)(adr >> 8);
-               wb[3] = (u8)adr;
-               wb[4] = (u8)(sz >> 16);
-               wb[5] = (u8)(sz >> 8);
-               wb[6] = (u8)(sz);
-               len = 8;
-               break;
-
-       case CMD_INTERNAL_WRITE: /* internal register write */
-               wb[1] = (u8)(adr >> 8);
-               if (clockless == 1)
-                       wb[1] |= BIT(7);
-               wb[2] = (u8)(adr);
-               wb[3] = b[3];
-               wb[4] = b[2];
-               wb[5] = b[1];
-               wb[6] = b[0];
-               len = 8;
-               break;
-
-       case CMD_SINGLE_WRITE: /* single word write */
-               wb[1] = (u8)(adr >> 16);
-               wb[2] = (u8)(adr >> 8);
-               wb[3] = (u8)(adr);
-               wb[4] = b[3];
-               wb[5] = b[2];
-               wb[6] = b[1];
-               wb[7] = b[0];
-               len = 9;
-               break;
-
-       default:
-               result = -EINVAL;
-               break;
-       }
-
-       if (result)
-               return result;
-
-       if (!spi_priv->crc_off)
-               wb[len - 1] = (crc7(0x7f, (const u8 *)&wb[0], len - 1)) << 1;
-       else
-               len -= 1;
-
-#define NUM_SKIP_BYTES (1)
-#define NUM_RSP_BYTES (2)
-#define NUM_DATA_HDR_BYTES (1)
-#define NUM_DATA_BYTES (4)
-#define NUM_CRC_BYTES (2)
-#define NUM_DUMMY_BYTES (3)
-       if (cmd == CMD_RESET ||
-           cmd == CMD_TERMINATE ||
-           cmd == CMD_REPEAT) {
-               len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES);
-       } else if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
-               int tmp = NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES
-                       + NUM_DUMMY_BYTES;
-               if (!spi_priv->crc_off)
-                       len2 = len + tmp + NUM_CRC_BYTES;
-               else
-                       len2 = len + tmp;
-       } else {
-               len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES);
-       }
-#undef NUM_DUMMY_BYTES
-
-       if (len2 > ARRAY_SIZE(wb)) {
-               dev_err(&spi->dev, "spi buffer size too small (%d) (%zu)\n",
-                       len2, ARRAY_SIZE(wb));
-               return -EINVAL;
-       }
-       /* zero spi write buffers. */
-       for (wix = len; wix < len2; wix++)
-               wb[wix] = 0;
-       rix = len;
-
-       if (wilc_spi_tx_rx(wilc, wb, rb, len2)) {
-               dev_err(&spi->dev, "Failed cmd write, bus error...\n");
-               return -EINVAL;
-       }
-
-       /*
-        * Command/Control response
-        */
-       if (cmd == CMD_RESET || cmd == CMD_TERMINATE || cmd == CMD_REPEAT)
-               rix++; /* skip 1 byte */
-
-       rsp = rb[rix++];
-
-       if (rsp != cmd) {
-               dev_err(&spi->dev,
-                       "Failed cmd response, cmd (%02x), resp (%02x)\n",
-                       cmd, rsp);
-               return -EINVAL;
-       }
-
-       /*
-        * State response
-        */
-       rsp = rb[rix++];
-       if (rsp != 0x00) {
-               dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
-                       rsp);
-               return -EINVAL;
-       }
-
-       if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ ||
-           cmd == CMD_DMA_READ || cmd == CMD_DMA_EXT_READ) {
-               /*
-                * Data Respnose header
-                */
-               retry = 100;
-               do {
-                       /*
-                        * ensure there is room in buffer later
-                        * to read data and crc
-                        */
-                       if (rix < len2) {
-                               rsp = rb[rix++];
-                       } else {
-                               retry = 0;
-                               break;
-                       }
-                       if (((rsp >> 4) & 0xf) == 0xf)
-                               break;
-               } while (retry--);
-
-               if (retry <= 0) {
-                       dev_err(&spi->dev,
-                               "Error, data read response (%02x)\n", rsp);
-                       return -EAGAIN;
-               }
-       }
-
-       if (cmd == CMD_INTERNAL_READ || cmd == CMD_SINGLE_READ) {
-               /*
-                * Read bytes
-                */
-               if ((rix + 3) < len2) {
-                       b[0] = rb[rix++];
-                       b[1] = rb[rix++];
-                       b[2] = rb[rix++];
-                       b[3] = rb[rix++];
-               } else {
-                       dev_err(&spi->dev,
-                               "buffer overrun when reading data.\n");
-                       return -EINVAL;
-               }
-
-               if (!spi_priv->crc_off) {
-                       /*
-                        * Read Crc
-                        */
-                       if ((rix + 1) < len2) {
-                               crc[0] = rb[rix++];
-                               crc[1] = rb[rix++];
-                       } else {
-                               dev_err(&spi->dev,
-                                       "buffer overrun when reading crc.\n");
-                               return -EINVAL;
-                       }
-               }
-       } else if ((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) {
-               int ix;
-
-               /* some data may be read in response to dummy bytes. */
-               for (ix = 0; (rix < len2) && (ix < sz); )
-                       b[ix++] = rb[rix++];
-
-               sz -= ix;
-
-               if (sz > 0) {
-                       int nbytes;
-
-                       if (sz <= (DATA_PKT_SZ - ix))
-                               nbytes = sz;
-                       else
-                               nbytes = DATA_PKT_SZ - ix;
-
-                       /*
-                        * Read bytes
-                        */
-                       if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
-                               dev_err(&spi->dev,
-                                       "Failed block read, bus err\n");
-                               return -EINVAL;
-                       }
-
-                       /*
-                        * Read Crc
-                        */
-                       if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) {
-                               dev_err(&spi->dev,
-                                       "Failed block crc read, bus err\n");
-                               return -EINVAL;
-                       }
-
-                       ix += nbytes;
-                       sz -= nbytes;
-               }
-
-               /*
-                * if any data in left unread,
-                * then read the rest using normal DMA code.
-                */
-               while (sz > 0) {
-                       int nbytes;
-
-                       if (sz <= DATA_PKT_SZ)
-                               nbytes = sz;
-                       else
-                               nbytes = DATA_PKT_SZ;
-
-                       /*
-                        * read data response only on the next DMA cycles not
-                        * the first DMA since data response header is already
-                        * handled above for the first DMA.
-                        */
-                       /*
-                        * Data Respnose header
-                        */
-                       retry = 10;
-                       do {
-                               if (wilc_spi_rx(wilc, &rsp, 1)) {
-                                       dev_err(&spi->dev,
-                                               "Failed resp read, bus err\n");
-                                       result = -EINVAL;
-                                       break;
-                               }
-                               if (((rsp >> 4) & 0xf) == 0xf)
-                                       break;
-                       } while (retry--);
-
-                       if (result)
-                               break;
-
-                       /*
-                        * Read bytes
-                        */
-                       if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
-                               dev_err(&spi->dev,
-                                       "Failed block read, bus err\n");
-                               result = -EINVAL;
-                               break;
-                       }
-
-                       /*
-                        * Read Crc
-                        */
-                       if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) {
-                               dev_err(&spi->dev,
-                                       "Failed block crc read, bus err\n");
-                               result = -EINVAL;
-                               break;
-                       }
-
-                       ix += nbytes;
-                       sz -= nbytes;
-               }
-       }
-       return result;
-}
-
 static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
 {
        struct spi_device *spi = to_spi_device(wilc->dev);
@@ -686,19 +346,333 @@ static int spi_data_write(struct wilc *wilc, u8 *b, u32 sz)
  *      Spi Internal Read/Write Function
  *
  ********************************************/
+static u8 wilc_get_crc7(u8 *buffer, u32 len)
+{
+       return crc7_be(0xfe, buffer, len);
+}
+
+static int wilc_spi_single_read(struct wilc *wilc, u8 cmd, u32 adr, void *b,
+                               u8 clockless)
+{
+       struct spi_device *spi = to_spi_device(wilc->dev);
+       struct wilc_spi *spi_priv = wilc->bus_data;
+       u8 wb[32], rb[32];
+       int cmd_len, resp_len;
+       u8 crc[2];
+       struct wilc_spi_cmd *c;
+       struct wilc_spi_read_rsp_data *r;
+
+       memset(wb, 0x0, sizeof(wb));
+       memset(rb, 0x0, sizeof(rb));
+       c = (struct wilc_spi_cmd *)wb;
+       c->cmd_type = cmd;
+       if (cmd == CMD_SINGLE_READ) {
+               c->u.simple_cmd.addr[0] = adr >> 16;
+               c->u.simple_cmd.addr[1] = adr >> 8;
+               c->u.simple_cmd.addr[2] = adr;
+       } else if (cmd == CMD_INTERNAL_READ) {
+               c->u.simple_cmd.addr[0] = adr >> 8;
+               if (clockless == 1)
+                       c->u.simple_cmd.addr[0] |= BIT(7);
+               c->u.simple_cmd.addr[1] = adr;
+               c->u.simple_cmd.addr[2] = 0x0;
+       } else {
+               dev_err(&spi->dev, "cmd [%x] not supported\n", cmd);
+               return -EINVAL;
+       }
+
+       cmd_len = offsetof(struct wilc_spi_cmd, u.simple_cmd.crc);
+       resp_len = sizeof(*r);
+       if (!spi_priv->crc_off) {
+               c->u.simple_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
+               cmd_len += 1;
+               resp_len += 2;
+       }
+
+       if (cmd_len + resp_len > ARRAY_SIZE(wb)) {
+               dev_err(&spi->dev,
+                       "spi buffer size too small (%d) (%d) (%zu)\n",
+                       cmd_len, resp_len, ARRAY_SIZE(wb));
+               return -EINVAL;
+       }
+
+       if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) {
+               dev_err(&spi->dev, "Failed cmd write, bus error...\n");
+               return -EINVAL;
+       }
+
+       r = (struct wilc_spi_read_rsp_data *)&rb[cmd_len];
+       if (r->rsp_cmd_type != cmd) {
+               dev_err(&spi->dev,
+                       "Failed cmd response, cmd (%02x), resp (%02x)\n",
+                       cmd, r->rsp_cmd_type);
+               return -EINVAL;
+       }
+
+       if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) {
+               dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
+                       r->status);
+               return -EINVAL;
+       }
+
+       if (WILC_GET_RESP_HDR_START(r->resp_header) != 0xf) {
+               dev_err(&spi->dev, "Error, data read response (%02x)\n",
+                       r->resp_header);
+               return -EINVAL;
+       }
+
+       if (b)
+               memcpy(b, r->resp_data, 4);
+
+       if (!spi_priv->crc_off)
+               memcpy(crc, r->crc, 2);
+
+       return 0;
+}
+
+static int wilc_spi_write_cmd(struct wilc *wilc, u8 cmd, u32 adr, u32 data,
+                             u8 clockless)
+{
+       struct spi_device *spi = to_spi_device(wilc->dev);
+       struct wilc_spi *spi_priv = wilc->bus_data;
+       u8 wb[32], rb[32];
+       int cmd_len, resp_len;
+       struct wilc_spi_cmd *c;
+       struct wilc_spi_rsp_data *r;
+
+       memset(wb, 0x0, sizeof(wb));
+       memset(rb, 0x0, sizeof(rb));
+       c = (struct wilc_spi_cmd *)wb;
+       c->cmd_type = cmd;
+       if (cmd == CMD_INTERNAL_WRITE) {
+               c->u.internal_w_cmd.addr[0] = adr >> 8;
+               if (clockless == 1)
+                       c->u.internal_w_cmd.addr[0] |= BIT(7);
+
+               c->u.internal_w_cmd.addr[1] = adr;
+               c->u.internal_w_cmd.data = cpu_to_be32(data);
+               cmd_len = offsetof(struct wilc_spi_cmd, u.internal_w_cmd.crc);
+               if (!spi_priv->crc_off)
+                       c->u.internal_w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
+       } else if (cmd == CMD_SINGLE_WRITE) {
+               c->u.w_cmd.addr[0] = adr >> 16;
+               c->u.w_cmd.addr[1] = adr >> 8;
+               c->u.w_cmd.addr[2] = adr;
+               c->u.w_cmd.data = cpu_to_be32(data);
+               cmd_len = offsetof(struct wilc_spi_cmd, u.w_cmd.crc);
+               if (!spi_priv->crc_off)
+                       c->u.w_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
+       } else {
+               dev_err(&spi->dev, "write cmd [%x] not supported\n", cmd);
+               return -EINVAL;
+       }
+
+       if (!spi_priv->crc_off)
+               cmd_len += 1;
+
+       resp_len = sizeof(*r);
+
+       if (cmd_len + resp_len > ARRAY_SIZE(wb)) {
+               dev_err(&spi->dev,
+                       "spi buffer size too small (%d) (%d) (%zu)\n",
+                       cmd_len, resp_len, ARRAY_SIZE(wb));
+               return -EINVAL;
+       }
+
+       if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) {
+               dev_err(&spi->dev, "Failed cmd write, bus error...\n");
+               return -EINVAL;
+       }
+
+       r = (struct wilc_spi_rsp_data *)&rb[cmd_len];
+       if (r->rsp_cmd_type != cmd) {
+               dev_err(&spi->dev,
+                       "Failed cmd response, cmd (%02x), resp (%02x)\n",
+                       cmd, r->rsp_cmd_type);
+               return -EINVAL;
+       }
+
+       if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) {
+               dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
+                       r->status);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int wilc_spi_dma_rw(struct wilc *wilc, u8 cmd, u32 adr, u8 *b, u32 sz)
+{
+       struct spi_device *spi = to_spi_device(wilc->dev);
+       struct wilc_spi *spi_priv = wilc->bus_data;
+       u8 wb[32], rb[32];
+       int cmd_len, resp_len;
+       int retry, ix = 0;
+       u8 crc[2];
+       struct wilc_spi_cmd *c;
+       struct wilc_spi_rsp_data *r;
+
+       memset(wb, 0x0, sizeof(wb));
+       memset(rb, 0x0, sizeof(rb));
+       c = (struct wilc_spi_cmd *)wb;
+       c->cmd_type = cmd;
+       if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_READ) {
+               c->u.dma_cmd.addr[0] = adr >> 16;
+               c->u.dma_cmd.addr[1] = adr >> 8;
+               c->u.dma_cmd.addr[2] = adr;
+               c->u.dma_cmd.size[0] = sz >> 8;
+               c->u.dma_cmd.size[1] = sz;
+               cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd.crc);
+               if (!spi_priv->crc_off)
+                       c->u.dma_cmd.crc[0] = wilc_get_crc7(wb, cmd_len);
+       } else if (cmd == CMD_DMA_EXT_WRITE || cmd == CMD_DMA_EXT_READ) {
+               c->u.dma_cmd_ext.addr[0] = adr >> 16;
+               c->u.dma_cmd_ext.addr[1] = adr >> 8;
+               c->u.dma_cmd_ext.addr[2] = adr;
+               c->u.dma_cmd_ext.size[0] = sz >> 16;
+               c->u.dma_cmd_ext.size[1] = sz >> 8;
+               c->u.dma_cmd_ext.size[2] = sz;
+               cmd_len = offsetof(struct wilc_spi_cmd, u.dma_cmd_ext.crc);
+               if (!spi_priv->crc_off)
+                       c->u.dma_cmd_ext.crc[0] = wilc_get_crc7(wb, cmd_len);
+       } else {
+               dev_err(&spi->dev, "dma read write cmd [%x] not supported\n",
+                       cmd);
+               return -EINVAL;
+       }
+       if (!spi_priv->crc_off)
+               cmd_len += 1;
+
+       resp_len = sizeof(*r);
+
+       if (cmd_len + resp_len > ARRAY_SIZE(wb)) {
+               dev_err(&spi->dev, "spi buffer size too small (%d)(%d) (%zu)\n",
+                       cmd_len, resp_len, ARRAY_SIZE(wb));
+               return -EINVAL;
+       }
+
+       if (wilc_spi_tx_rx(wilc, wb, rb, cmd_len + resp_len)) {
+               dev_err(&spi->dev, "Failed cmd write, bus error...\n");
+               return -EINVAL;
+       }
+
+       r = (struct wilc_spi_rsp_data *)&rb[cmd_len];
+       if (r->rsp_cmd_type != cmd) {
+               dev_err(&spi->dev,
+                       "Failed cmd response, cmd (%02x), resp (%02x)\n",
+                       cmd, r->rsp_cmd_type);
+               return -EINVAL;
+       }
+
+       if (r->status != WILC_SPI_COMMAND_STAT_SUCCESS) {
+               dev_err(&spi->dev, "Failed cmd state response state (%02x)\n",
+                       r->status);
+               return -EINVAL;
+       }
+
+       if (cmd == CMD_DMA_WRITE || cmd == CMD_DMA_EXT_WRITE)
+               return 0;
+
+       while (sz > 0) {
+               int nbytes;
+               u8 rsp;
+
+               if (sz <= DATA_PKT_SZ)
+                       nbytes = sz;
+               else
+                       nbytes = DATA_PKT_SZ;
+
+               /*
+                * Data Response header
+                */
+               retry = 100;
+               do {
+                       if (wilc_spi_rx(wilc, &rsp, 1)) {
+                               dev_err(&spi->dev,
+                                       "Failed resp read, bus err\n");
+                               return -EINVAL;
+                       }
+                       if (WILC_GET_RESP_HDR_START(rsp) == 0xf)
+                               break;
+               } while (retry--);
+
+               /*
+                * Read bytes
+                */
+               if (wilc_spi_rx(wilc, &b[ix], nbytes)) {
+                       dev_err(&spi->dev,
+                               "Failed block read, bus err\n");
+                       return -EINVAL;
+               }
+
+               /*
+                * Read Crc
+                */
+               if (!spi_priv->crc_off && wilc_spi_rx(wilc, crc, 2)) {
+                       dev_err(&spi->dev,
+                               "Failed block crc read, bus err\n");
+                       return -EINVAL;
+               }
+
+               ix += nbytes;
+               sz -= nbytes;
+       }
+       return 0;
+}
+
+static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data)
+{
+       struct spi_device *spi = to_spi_device(wilc->dev);
+       int result;
+       u8 cmd = CMD_SINGLE_READ;
+       u8 clockless = 0;
+
+       if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) {
+               /* Clockless register */
+               cmd = CMD_INTERNAL_READ;
+               clockless = 1;
+       }
+
+       result = wilc_spi_single_read(wilc, cmd, addr, data, clockless);
+       if (result) {
+               dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr);
+               return result;
+       }
+
+       le32_to_cpus(data);
+
+       return 0;
+}
+
+static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
+{
+       struct spi_device *spi = to_spi_device(wilc->dev);
+       int result;
+
+       if (size <= 4)
+               return -EINVAL;
+
+       result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_READ, addr, buf, size);
+       if (result) {
+               dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr);
+               return result;
+       }
+
+       return 0;
+}
 
 static int spi_internal_write(struct wilc *wilc, u32 adr, u32 dat)
 {
        struct spi_device *spi = to_spi_device(wilc->dev);
        int result;
 
-       cpu_to_le32s(&dat);
-       result = spi_cmd_complete(wilc, CMD_INTERNAL_WRITE, adr, (u8 *)&dat, 4,
-                                 0);
-       if (result)
+       result = wilc_spi_write_cmd(wilc, CMD_INTERNAL_WRITE, adr, dat, 0);
+       if (result) {
                dev_err(&spi->dev, "Failed internal write cmd...\n");
+               return result;
+       }
 
-       return result;
+       return 0;
 }
 
 static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data)
@@ -706,8 +680,7 @@ static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data)
        struct spi_device *spi = to_spi_device(wilc->dev);
        int result;
 
-       result = spi_cmd_complete(wilc, CMD_INTERNAL_READ, adr, (u8 *)data, 4,
-                                 0);
+       result = wilc_spi_single_read(wilc, CMD_INTERNAL_READ, adr, data, 0);
        if (result) {
                dev_err(&spi->dev, "Failed internal read cmd...\n");
                return result;
@@ -715,7 +688,7 @@ static int spi_internal_read(struct wilc *wilc, u32 adr, u32 *data)
 
        le32_to_cpus(data);
 
-       return result;
+       return 0;
 }
 
 /********************************************
@@ -731,18 +704,19 @@ static int wilc_spi_write_reg(struct wilc *wilc, u32 addr, u32 data)
        u8 cmd = CMD_SINGLE_WRITE;
        u8 clockless = 0;
 
-       cpu_to_le32s(&data);
-       if (addr < 0x30) {
+       if (addr < WILC_SPI_CLOCKLESS_ADDR_LIMIT) {
                /* Clockless register */
                cmd = CMD_INTERNAL_WRITE;
                clockless = 1;
        }
 
-       result = spi_cmd_complete(wilc, cmd, addr, (u8 *)&data, 4, clockless);
-       if (result)
+       result = wilc_spi_write_cmd(wilc, cmd, addr, data, clockless);
+       if (result) {
                dev_err(&spi->dev, "Failed cmd, write reg (%08x)...\n", addr);
+               return result;
+       }
 
-       return result;
+       return 0;
 }
 
 static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
@@ -756,7 +730,7 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
        if (size <= 4)
                return -EINVAL;
 
-       result = spi_cmd_complete(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size, 0);
+       result = wilc_spi_dma_rw(wilc, CMD_DMA_EXT_WRITE, addr, NULL, size);
        if (result) {
                dev_err(&spi->dev,
                        "Failed cmd, write block (%08x)...\n", addr);
@@ -767,51 +741,14 @@ static int wilc_spi_write(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
         * Data
         */
        result = spi_data_write(wilc, buf, size);
-       if (result)
-               dev_err(&spi->dev, "Failed block data write...\n");
-
-       return result;
-}
-
-static int wilc_spi_read_reg(struct wilc *wilc, u32 addr, u32 *data)
-{
-       struct spi_device *spi = to_spi_device(wilc->dev);
-       int result;
-       u8 cmd = CMD_SINGLE_READ;
-       u8 clockless = 0;
-
-       if (addr < 0x30) {
-               /* Clockless register */
-               cmd = CMD_INTERNAL_READ;
-               clockless = 1;
-       }
-
-       result = spi_cmd_complete(wilc, cmd, addr, (u8 *)data, 4, clockless);
        if (result) {
-               dev_err(&spi->dev, "Failed cmd, read reg (%08x)...\n", addr);
+               dev_err(&spi->dev, "Failed block data write...\n");
                return result;
        }
 
-       le32_to_cpus(data);
-
        return 0;
 }
 
-static int wilc_spi_read(struct wilc *wilc, u32 addr, u8 *buf, u32 size)
-{
-       struct spi_device *spi = to_spi_device(wilc->dev);
-       int result;
-
-       if (size <= 4)
-               return -EINVAL;
-
-       result = spi_cmd_complete(wilc, CMD_DMA_EXT_READ, addr, buf, size, 0);
-       if (result)
-               dev_err(&spi->dev, "Failed cmd, read block (%08x)...\n", addr);
-
-       return result;
-}
-
 /********************************************
  *
  *      Bus interfaces
@@ -836,7 +773,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
        int ret;
 
        if (isinit) {
-               ret = wilc_spi_read_reg(wilc, 0x1000, &chipid);
+               ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid);
                if (ret)
                        dev_err(&spi->dev, "Fail cmd read chip id...\n");
 
@@ -888,7 +825,7 @@ static int wilc_spi_init(struct wilc *wilc, bool resume)
        /*
         * make sure can read back chip id correctly
         */
-       ret = wilc_spi_read_reg(wilc, 0x1000, &chipid);
+       ret = wilc_spi_read_reg(wilc, WILC_CHIPID, &chipid);
        if (ret) {
                dev_err(&spi->dev, "Fail cmd read chip id...\n");
                return ret;
@@ -903,26 +840,28 @@ static int wilc_spi_read_size(struct wilc *wilc, u32 *size)
 {
        int ret;
 
-       ret = spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE, size);
-       *size = *size & IRQ_DMA_WD_CNT_MASK;
+       ret = spi_internal_read(wilc,
+                               WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE, size);
+       *size = FIELD_GET(IRQ_DMA_WD_CNT_MASK, *size);
 
        return ret;
 }
 
 static int wilc_spi_read_int(struct wilc *wilc, u32 *int_status)
 {
-       return spi_internal_read(wilc, 0xe840 - WILC_SPI_REG_BASE, int_status);
+       return spi_internal_read(wilc, WILC_SPI_INT_STATUS - WILC_SPI_REG_BASE,
+                                int_status);
 }
 
 static int wilc_spi_clear_int_ext(struct wilc *wilc, u32 val)
 {
-       return spi_internal_write(wilc, 0xe844 - WILC_SPI_REG_BASE, val);
+       return spi_internal_write(wilc, WILC_SPI_INT_CLEAR - WILC_SPI_REG_BASE,
+                                 val);
 }
 
 static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
 {
        struct spi_device *spi = to_spi_device(wilc->dev);
-       struct wilc_spi *spi_priv = wilc->bus_data;
        u32 reg;
        int ret, i;
 
@@ -931,8 +870,6 @@ static int wilc_spi_sync_ext(struct wilc *wilc, int nint)
                return -EINVAL;
        }
 
-       spi_priv->nint = nint;
-
        /*
         * interrupt pin mux select
         */
index 601e4d1..6a82fb2 100644 (file)
@@ -11,7 +11,7 @@
 
 static inline bool is_wilc1000(u32 id)
 {
-       return (id & 0xfffff000) == 0x100000;
+       return (id & (~WILC_CHIP_REV_FIELD)) == WILC_1000_BASE_ID;
 }
 
 static inline void acquire_bus(struct wilc *wilc, enum bus_acquire acquire)
@@ -393,62 +393,67 @@ void chip_allow_sleep(struct wilc *wilc)
 {
        u32 reg = 0;
 
-       wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
+       wilc->hif_func->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, &reg);
 
-       wilc->hif_func->hif_write_reg(wilc, 0xf0, reg & ~BIT(0));
-       wilc->hif_func->hif_write_reg(wilc, 0xfa, 0);
+       wilc->hif_func->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG,
+                                     reg & ~WILC_SDIO_WAKEUP_BIT);
+       wilc->hif_func->hif_write_reg(wilc, WILC_SDIO_HOST_TO_FW_REG, 0);
 }
 EXPORT_SYMBOL_GPL(chip_allow_sleep);
 
 void chip_wakeup(struct wilc *wilc)
 {
        u32 reg, clk_status_reg;
+       const struct wilc_hif_func *h = wilc->hif_func;
 
-       if ((wilc->io_type & 0x1) == WILC_HIF_SPI) {
+       if (wilc->io_type == WILC_HIF_SPI) {
                do {
-                       wilc->hif_func->hif_read_reg(wilc, 1, &reg);
-                       wilc->hif_func->hif_write_reg(wilc, 1, reg | BIT(1));
-                       wilc->hif_func->hif_write_reg(wilc, 1, reg & ~BIT(1));
+                       h->hif_read_reg(wilc, WILC_SPI_WAKEUP_REG, &reg);
+                       h->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG,
+                                        reg | WILC_SPI_WAKEUP_BIT);
+                       h->hif_write_reg(wilc, WILC_SPI_WAKEUP_REG,
+                                        reg & ~WILC_SPI_WAKEUP_BIT);
 
                        do {
                                usleep_range(2000, 2500);
                                wilc_get_chipid(wilc, true);
                        } while (wilc_get_chipid(wilc, true) == 0);
                } while (wilc_get_chipid(wilc, true) == 0);
-       } else if ((wilc->io_type & 0x1) == WILC_HIF_SDIO) {
-               wilc->hif_func->hif_write_reg(wilc, 0xfa, 1);
+       } else if (wilc->io_type == WILC_HIF_SDIO) {
+               h->hif_write_reg(wilc, WILC_SDIO_HOST_TO_FW_REG,
+                                WILC_SDIO_HOST_TO_FW_BIT);
                usleep_range(200, 400);
-               wilc->hif_func->hif_read_reg(wilc, 0xf0, &reg);
+               h->hif_read_reg(wilc, WILC_SDIO_WAKEUP_REG, &reg);
                do {
-                       wilc->hif_func->hif_write_reg(wilc, 0xf0,
-                                                     reg | BIT(0));
-                       wilc->hif_func->hif_read_reg(wilc, 0xf1,
-                                                    &clk_status_reg);
+                       h->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG,
+                                        reg | WILC_SDIO_WAKEUP_BIT);
+                       h->hif_read_reg(wilc, WILC_SDIO_CLK_STATUS_REG,
+                                       &clk_status_reg);
 
-                       while ((clk_status_reg & 0x1) == 0) {
+                       while (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT)) {
                                usleep_range(2000, 2500);
 
-                               wilc->hif_func->hif_read_reg(wilc, 0xf1,
-                                                            &clk_status_reg);
+                               h->hif_read_reg(wilc, WILC_SDIO_CLK_STATUS_REG,
+                                               &clk_status_reg);
                        }
-                       if ((clk_status_reg & 0x1) == 0) {
-                               wilc->hif_func->hif_write_reg(wilc, 0xf0,
-                                                             reg & (~BIT(0)));
+                       if (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT)) {
+                               h->hif_write_reg(wilc, WILC_SDIO_WAKEUP_REG,
+                                                reg & ~WILC_SDIO_WAKEUP_BIT);
                        }
-               } while ((clk_status_reg & 0x1) == 0);
+               } while (!(clk_status_reg & WILC_SDIO_CLK_STATUS_BIT));
        }
 
        if (wilc->chip_ps_state == WILC_CHIP_SLEEPING_MANUAL) {
-               if (wilc_get_chipid(wilc, false) < 0x1002b0) {
+               if (wilc_get_chipid(wilc, false) < WILC_1000_BASE_ID_2B) {
                        u32 val32;
 
-                       wilc->hif_func->hif_read_reg(wilc, 0x1e1c, &val32);
+                       h->hif_read_reg(wilc, WILC_REG_4_TO_1_RX, &val32);
                        val32 |= BIT(6);
-                       wilc->hif_func->hif_write_reg(wilc, 0x1e1c, val32);
+                       h->hif_write_reg(wilc, WILC_REG_4_TO_1_RX, val32);
 
-                       wilc->hif_func->hif_read_reg(wilc, 0x1e9c, &val32);
+                       h->hif_read_reg(wilc, WILC_REG_4_TO_1_TX_BANK0, &val32);
                        val32 |= BIT(6);
-                       wilc->hif_func->hif_write_reg(wilc, 0x1e9c, val32);
+                       h->hif_write_reg(wilc, WILC_REG_4_TO_1_TX_BANK0, val32);
                }
        }
        wilc->chip_ps_state = WILC_CHIP_WAKEDUP;
@@ -458,7 +463,7 @@ EXPORT_SYMBOL_GPL(chip_wakeup);
 void host_wakeup_notify(struct wilc *wilc)
 {
        acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
-       wilc->hif_func->hif_write_reg(wilc, 0x10b0, 1);
+       wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_2, 1);
        release_bus(wilc, WILC_BUS_RELEASE_ONLY);
 }
 EXPORT_SYMBOL_GPL(host_wakeup_notify);
@@ -466,7 +471,7 @@ EXPORT_SYMBOL_GPL(host_wakeup_notify);
 void host_sleep_notify(struct wilc *wilc)
 {
        acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY);
-       wilc->hif_func->hif_write_reg(wilc, 0x10ac, 1);
+       wilc->hif_func->hif_write_reg(wilc, WILC_CORTUS_INTERRUPT_1, 1);
        release_bus(wilc, WILC_BUS_RELEASE_ONLY);
 }
 EXPORT_SYMBOL_GPL(host_sleep_notify);
@@ -508,9 +513,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
                        vmm_sz = HOST_HDR_OFFSET;
 
                vmm_sz += tqe->buffer_size;
-
-               if (vmm_sz & 0x3)
-                       vmm_sz = (vmm_sz + 4) & ~0x3;
+               vmm_sz = ALIGN(vmm_sz, 4);
 
                if ((sum + vmm_sz) > WILC_TX_BUFF_SIZE)
                        break;
@@ -568,11 +571,10 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
                        ret = func->hif_read_reg(wilc, WILC_HOST_VMM_CTL, &reg);
                        if (ret)
                                break;
-                       if ((reg >> 2) & 0x1) {
-                               entries = ((reg >> 3) & 0x3f);
+                       if (FIELD_GET(WILC_VMM_ENTRY_AVAILABLE, reg)) {
+                               entries = FIELD_GET(WILC_VMM_ENTRY_COUNT, reg);
                                break;
                        }
-                       release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP);
                } while (--timeout);
                if (timeout <= 0) {
                        ret = func->hif_write_reg(wilc, WILC_HOST_VMM_CTL, 0x0);
@@ -610,6 +612,7 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
        do {
                u32 header, buffer_offset;
                char *bssid;
+               u8 mgmt_ptk = 0;
 
                tqe = wilc_wlan_txq_remove_from_head(dev);
                if (!tqe)
@@ -620,15 +623,16 @@ int wilc_wlan_handle_txq(struct wilc *wilc, u32 *txq_count)
                        break;
 
                le32_to_cpus(&vmm_table[i]);
-               vmm_sz = (vmm_table[i] & 0x3ff);
+               vmm_sz = FIELD_GET(WILC_VMM_BUFFER_SIZE, vmm_table[i]);
                vmm_sz *= 4;
-               header = (tqe->type << 31) |
-                        (tqe->buffer_size << 15) |
-                        vmm_sz;
+
                if (tqe->type == WILC_MGMT_PKT)
-                       header |= BIT(30);
-               else
-                       header &= ~BIT(30);
+                       mgmt_ptk = 1;
+
+               header = (FIELD_PREP(WILC_VMM_HDR_TYPE, tqe->type) |
+                         FIELD_PREP(WILC_VMM_HDR_MGMT_FIELD, mgmt_ptk) |
+                         FIELD_PREP(WILC_VMM_HDR_PKT_SIZE, tqe->buffer_size) |
+                         FIELD_PREP(WILC_VMM_HDR_BUFF_SIZE, vmm_sz));
 
                cpu_to_le32s(&header);
                memcpy(&txb[offset], &header, 4);
@@ -686,10 +690,10 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
                buff_ptr = buffer + offset;
                header = get_unaligned_le32(buff_ptr);
 
-               is_cfg_packet = (header >> 31) & 0x1;
-               pkt_offset = (header >> 22) & 0x1ff;
-               tp_len = (header >> 11) & 0x7ff;
-               pkt_len = header & 0x7ff;
+               is_cfg_packet = FIELD_GET(WILC_PKT_HDR_CONFIG_FIELD, header);
+               pkt_offset = FIELD_GET(WILC_PKT_HDR_OFFSET_FIELD, header);
+               tp_len = FIELD_GET(WILC_PKT_HDR_TOTAL_LEN_FIELD, header);
+               pkt_len = FIELD_GET(WILC_PKT_HDR_LEN_FIELD, header);
 
                if (pkt_len == 0 || tp_len == 0)
                        break;
@@ -699,10 +703,8 @@ static void wilc_wlan_handle_rx_buff(struct wilc *wilc, u8 *buffer, int size)
                        wilc_wfi_mgmt_rx(wilc, buff_ptr, pkt_len);
                } else {
                        if (!is_cfg_packet) {
-                               if (pkt_len > 0) {
-                                       wilc_frmw_to_host(wilc, buff_ptr,
-                                                         pkt_len, pkt_offset);
-                               }
+                               wilc_frmw_to_host(wilc, buff_ptr, pkt_len,
+                                                 pkt_offset);
                        } else {
                                struct wilc_cfg_rsp rsp;
 
@@ -758,11 +760,11 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status)
        int ret = 0;
        struct rxq_entry_t *rqe;
 
-       size = (int_status & 0x7fff) << 2;
+       size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, int_status) << 2;
 
        while (!size && retries < 10) {
                wilc->hif_func->hif_read_size(wilc, &size);
-               size = (size & 0x7fff) << 2;
+               size = FIELD_GET(WILC_INTERRUPT_DATA_SIZE, size) << 2;
                retries++;
        }
 
@@ -887,7 +889,7 @@ int wilc_wlan_start(struct wilc *wilc)
 
        wilc->hif_func->hif_sync_ext(wilc, NUM_INT_EXT);
 
-       ret = wilc->hif_func->hif_read_reg(wilc, 0x1000, &chipid);
+       ret = wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &chipid);
        if (ret) {
                release_bus(wilc, WILC_BUS_RELEASE_ONLY);
                return ret;
@@ -1128,18 +1130,24 @@ static int init_chip(struct net_device *dev)
        chipid = wilc_get_chipid(wilc, true);
 
        if ((chipid & 0xfff) != 0xa0) {
-               ret = wilc->hif_func->hif_read_reg(wilc, 0x1118, &reg);
+               ret = wilc->hif_func->hif_read_reg(wilc,
+                                                  WILC_CORTUS_RESET_MUX_SEL,
+                                                  &reg);
                if (ret) {
                        netdev_err(dev, "fail read reg 0x1118\n");
                        goto release;
                }
                reg |= BIT(0);
-               ret = wilc->hif_func->hif_write_reg(wilc, 0x1118, reg);
+               ret = wilc->hif_func->hif_write_reg(wilc,
+                                                   WILC_CORTUS_RESET_MUX_SEL,
+                                                   reg);
                if (ret) {
                        netdev_err(dev, "fail write reg 0x1118\n");
                        goto release;
                }
-               ret = wilc->hif_func->hif_write_reg(wilc, 0xc0000, 0x71);
+               ret = wilc->hif_func->hif_write_reg(wilc,
+                                                   WILC_CORTUS_BOOT_REGISTER,
+                                                   WILC_CORTUS_BOOT_FROM_IRAM);
                if (ret) {
                        netdev_err(dev, "fail write reg 0xc0000\n");
                        goto release;
@@ -1159,20 +1167,21 @@ u32 wilc_get_chipid(struct wilc *wilc, bool update)
        u32 rfrevid = 0;
 
        if (chipid == 0 || update) {
-               wilc->hif_func->hif_read_reg(wilc, 0x1000, &tempchipid);
-               wilc->hif_func->hif_read_reg(wilc, 0x13f4, &rfrevid);
+               wilc->hif_func->hif_read_reg(wilc, WILC_CHIPID, &tempchipid);
+               wilc->hif_func->hif_read_reg(wilc, WILC_RF_REVISION_ID,
+                                            &rfrevid);
                if (!is_wilc1000(tempchipid)) {
                        chipid = 0;
                        return chipid;
                }
-               if (tempchipid == 0x1002a0) {
+               if (tempchipid == WILC_1000_BASE_ID_2A) { /* 0x1002A0 */
                        if (rfrevid != 0x1)
-                               tempchipid = 0x1002a1;
-               } else if (tempchipid == 0x1002b0) {
+                               tempchipid = WILC_1000_BASE_ID_2A_REV1;
+               } else if (tempchipid == WILC_1000_BASE_ID_2B) { /* 0x1002B0 */
                        if (rfrevid == 0x4)
-                               tempchipid = 0x1002b1;
+                               tempchipid = WILC_1000_BASE_ID_2B_REV1;
                        else if (rfrevid != 0x3)
-                               tempchipid = 0x1002b2;
+                               tempchipid = WILC_1000_BASE_ID_2B_REV2;
                }
 
                chipid = tempchipid;
index 8c46342..7689569 100644 (file)
@@ -8,6 +8,7 @@
 #define WILC_WLAN_H
 
 #include <linux/types.h>
+#include <linux/bitfield.h>
 
 /********************************************
  *
@@ -65,6 +66,8 @@
 #define WILC_INTR_CLEAR                        (WILC_INTR_REG_BASE + 0x30)
 #define WILC_INTR_STATUS               (WILC_INTR_REG_BASE + 0x40)
 
+#define WILC_RF_REVISION_ID            0x13f4
+
 #define WILC_VMM_TBL_SIZE              64
 #define WILC_VMM_TX_TBL_BASE           0x150400
 #define WILC_VMM_RX_TBL_BASE           0x150500
 #define WILC_SPI_TX_MODE               (WILC_SPI_REG_BASE + 0x20)
 #define WILC_SPI_PROTOCOL_CONFIG       (WILC_SPI_REG_BASE + 0x24)
 #define WILC_SPI_INTR_CTL              (WILC_SPI_REG_BASE + 0x2c)
+#define WILC_SPI_INT_STATUS            (WILC_SPI_REG_BASE + 0x40)
+#define WILC_SPI_INT_CLEAR             (WILC_SPI_REG_BASE + 0x44)
+
+#define WILC_SPI_WAKEUP_REG            0x1
+#define WILC_SPI_WAKEUP_BIT            BIT(1)
 
 #define WILC_SPI_PROTOCOL_OFFSET       (WILC_SPI_PROTOCOL_CONFIG - \
                                         WILC_SPI_REG_BASE)
 
+#define WILC_SPI_CLOCKLESS_ADDR_LIMIT  0x30
+
+/* Functions IO enables bits */
+#define WILC_SDIO_CCCR_IO_EN_FUNC1     BIT(1)
+
+/* Function/Interrupt enables bits */
+#define WILC_SDIO_CCCR_IEN_MASTER      BIT(0)
+#define WILC_SDIO_CCCR_IEN_FUNC1       BIT(1)
+
+/* Abort CCCR register bits */
+#define WILC_SDIO_CCCR_ABORT_RESET     BIT(3)
+
+/* Vendor specific CCCR registers */
+#define WILC_SDIO_WAKEUP_REG           0xf0
+#define WILC_SDIO_WAKEUP_BIT           BIT(0)
+
+#define WILC_SDIO_CLK_STATUS_REG       0xf1
+#define WILC_SDIO_CLK_STATUS_BIT       BIT(0)
+
+#define WILC_SDIO_INTERRUPT_DATA_SZ_REG        0xf2 /* Read size (2 bytes) */
+
+#define WILC_SDIO_VMM_TBL_CTRL_REG     0xf6
+#define WILC_SDIO_IRQ_FLAG_REG         0xf7
+#define WILC_SDIO_IRQ_CLEAR_FLAG_REG   0xf8
+
+#define WILC_SDIO_HOST_TO_FW_REG       0xfa
+#define WILC_SDIO_HOST_TO_FW_BIT       BIT(0)
+
+#define WILC_SDIO_FW_TO_HOST_REG       0xfc
+#define WILC_SDIO_FW_TO_HOST_BIT       BIT(0)
+
+/* Function 1 specific FBR register */
+#define WILC_SDIO_FBR_CSA_REG          0x10C /* CSA pointer (3 bytes) */
+#define WILC_SDIO_FBR_DATA_REG         0x10F
+
+#define WILC_SDIO_F1_DATA_REG          0x0
+#define WILC_SDIO_EXT_IRQ_FLAG_REG     0x4
+
 #define WILC_AHB_DATA_MEM_BASE         0x30000
 #define WILC_AHB_SHARE_MEM_BASE                0xd0000
 
 #define WILC_HAVE_DISABLE_WILC_UART    BIT(7)
 #define WILC_HAVE_USE_IRQ_AS_HOST_WAKE BIT(8)
 
+#define WILC_CORTUS_INTERRUPT_BASE     0x10A8
+#define WILC_CORTUS_INTERRUPT_1                (WILC_CORTUS_INTERRUPT_BASE + 0x4)
+#define WILC_CORTUS_INTERRUPT_2                (WILC_CORTUS_INTERRUPT_BASE + 0x8)
+
+/* tx control register 1 to 4 for RX */
+#define WILC_REG_4_TO_1_RX             0x1e1c
+
+/* tx control register 1 to 4 for TX Bank_0 */
+#define WILC_REG_4_TO_1_TX_BANK0       0x1e9c
+
+#define WILC_CORTUS_RESET_MUX_SEL      0x1118
+#define WILC_CORTUS_BOOT_REGISTER      0xc0000
+
+#define WILC_CORTUS_BOOT_FROM_IRAM     0x71
+
+#define WILC_1000_BASE_ID              0x100000
+
+#define WILC_1000_BASE_ID_2A           0x1002A0
+#define WILC_1000_BASE_ID_2A_REV1      (WILC_1000_BASE_ID_2A + 1)
+
+#define WILC_1000_BASE_ID_2B           0x1002B0
+#define WILC_1000_BASE_ID_2B_REV1      (WILC_1000_BASE_ID_2B + 1)
+#define WILC_1000_BASE_ID_2B_REV2      (WILC_1000_BASE_ID_2B + 2)
+
+#define WILC_CHIP_REV_FIELD            GENMASK(11, 0)
+
 /********************************************
  *
  *      Wlan Defines
 #define WILC_TX_BUFF_SIZE      (64 * 1024)
 
 #define MODALIAS               "WILC_SPI"
-#define GPIO_NUM               0x44
+
+#define WILC_PKT_HDR_CONFIG_FIELD      BIT(31)
+#define WILC_PKT_HDR_OFFSET_FIELD      GENMASK(30, 22)
+#define WILC_PKT_HDR_TOTAL_LEN_FIELD   GENMASK(21, 11)
+#define WILC_PKT_HDR_LEN_FIELD         GENMASK(10, 0)
+
+#define WILC_INTERRUPT_DATA_SIZE       GENMASK(14, 0)
+
+#define WILC_VMM_BUFFER_SIZE           GENMASK(9, 0)
+
+#define WILC_VMM_HDR_TYPE              BIT(31)
+#define WILC_VMM_HDR_MGMT_FIELD                BIT(30)
+#define WILC_VMM_HDR_PKT_SIZE          GENMASK(29, 15)
+#define WILC_VMM_HDR_BUFF_SIZE         GENMASK(14, 0)
+
+#define WILC_VMM_ENTRY_COUNT           GENMASK(8, 3)
+#define WILC_VMM_ENTRY_AVAILABLE       BIT(2)
 /*******************************************/
 /*        E0 and later Interrupt flags.    */
 /*******************************************/
 /* 21: INT5 flag                           */
 /*******************************************/
 #define IRG_FLAGS_OFFSET       16
-#define IRQ_DMA_WD_CNT_MASK    ((1ul << IRG_FLAGS_OFFSET) - 1)
+#define IRQ_DMA_WD_CNT_MASK    GENMASK(IRG_FLAGS_OFFSET - 1, 0)
 #define INT_0                  BIT(IRG_FLAGS_OFFSET)
 #define INT_1                  BIT(IRG_FLAGS_OFFSET + 1)
 #define INT_2                  BIT(IRG_FLAGS_OFFSET + 2)
 #define INT_3                  BIT(IRG_FLAGS_OFFSET + 3)
 #define INT_4                  BIT(IRG_FLAGS_OFFSET + 4)
 #define INT_5                  BIT(IRG_FLAGS_OFFSET + 5)
-#define MAX_NUM_INT            6
+#define MAX_NUM_INT            5
+#define IRG_FLAGS_MASK         GENMASK(IRG_FLAGS_OFFSET + MAX_NUM_INT, \
+                                       IRG_FLAGS_OFFSET)
 
 /*******************************************/
 /*        E0 and later Interrupt flags.    */
 #define DATA_INT_EXT           INT_0
 #define ALL_INT_EXT            DATA_INT_EXT
 #define NUM_INT_EXT            1
+#define UNHANDLED_IRQ_MASK     GENMASK(MAX_NUM_INT - 1, NUM_INT_EXT)
 
 #define DATA_INT_CLR           CLR_INT0
 
index bdd7f41..88e894d 100644 (file)
 /* Commonly used basic types */
 struct hfa384x_bytestr {
        __le16 len;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 struct hfa384x_bytestr32 {
@@ -421,7 +421,7 @@ struct hfa384x_authenticate_station_data {
 /*-- Configuration Record: WPAData       (data portion only) --*/
 struct hfa384x_wpa_data {
        __le16 datalen;
-       u8 data[0];             /* max 80 */
+       u8 data[];              /* max 80 */
 } __packed;
 
 /*--------------------------------------------------------------------
index b71756a..fa1bf8b 100644 (file)
@@ -3254,13 +3254,16 @@ static void hfa384x_usbin_rx(struct wlandevice *wlandev, struct sk_buff *skb)
        struct p80211_rxmeta *rxmeta;
        u16 data_len;
        u16 fc;
+       u16 status;
 
        /* Byte order convert once up front. */
        le16_to_cpus(&usbin->rxfrm.desc.status);
        le32_to_cpus(&usbin->rxfrm.desc.time);
 
        /* Now handle frame based on port# */
-       switch (HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status)) {
+       status = HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status);
+
+       switch (status) {
        case 0:
                fc = le16_to_cpu(usbin->rxfrm.desc.frame_control);
 
@@ -3317,8 +3320,9 @@ static void hfa384x_usbin_rx(struct wlandevice *wlandev, struct sk_buff *skb)
                break;
 
        default:
-               netdev_warn(hw->wlandev->netdev, "Received frame on unsupported port=%d\n",
-                           HFA384x_RXSTATUS_MACPORT_GET(usbin->rxfrm.desc.status));
+               netdev_warn(hw->wlandev->netdev,
+                           "Received frame on unsupported port=%d\n",
+                           status);
                break;
        }
 }
@@ -3372,6 +3376,8 @@ static void hfa384x_int_rxmonitor(struct wlandevice *wlandev,
             WLAN_HDR_A4_LEN + WLAN_DATA_MAXLEN + WLAN_CRC_LEN)) {
                pr_debug("overlen frm: len=%zd\n",
                         skblen - sizeof(struct p80211_caphdr));
+
+               return;
        }
 
        skb = dev_alloc_skb(skblen);
index ac25454..3dcdd02 100644 (file)
@@ -204,7 +204,7 @@ struct p80211pstr {
 
 struct p80211pstrd {
        u8 len;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 /* Maximum pascal string */
@@ -249,7 +249,7 @@ struct p80211itemd {
        u32 did;
        u16 status;
        u16 len;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 /* message data item for int, BOUNDEDINT, ENUMINT */
index 352556f..4689b21 100644 (file)
@@ -180,6 +180,7 @@ static void prism2sta_disconnect_usb(struct usb_interface *interface)
 
                cancel_work_sync(&hw->link_bh);
                cancel_work_sync(&hw->commsqual_bh);
+               cancel_work_sync(&hw->usb_work);
 
                /* Now we complete any outstanding commands
                 * and tell everyone who is waiting for their
diff --git a/drivers/staging/wusbcore/Documentation/wusb-cbaf b/drivers/staging/wusbcore/Documentation/wusb-cbaf
deleted file mode 100644 (file)
index 8b3d43e..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-#! /bin/bash
-#
-
-set -e
-
-progname=$(basename $0)
-function help
-{
-    cat <<EOF
-Usage: $progname COMMAND DEVICEs [ARGS]
-
-Command for manipulating the pairing/authentication credentials of a
-Wireless USB device that supports wired-mode Cable-Based-Association.
-
-Works in conjunction with the wusb-cba.ko driver from http://linuxuwb.org.
-
-
-DEVICE
-
- sysfs path to the device to authenticate; for example, both this
- guys are the same:
-
- /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.4/1-4.4:1.1
- /sys/bus/usb/drivers/wusb-cbaf/1-4.4:1.1
-
-COMMAND/ARGS are
-
- start
-
-   Start a WUSB host controller (by setting up a CHID)
-
- set-chid DEVICE HOST-CHID HOST-BANDGROUP HOST-NAME
-
-   Sets host information in the device; after this you can call the
-   get-cdid to see how does this device report itself to us.
-
- get-cdid DEVICE
-
-   Get the device ID associated to the HOST-CHID we sent with
-   'set-chid'. We might not know about it.
-
- set-cc DEVICE
-
-   If we allow the device to connect, set a random new CDID and CK
-   (connection key). Device saves them for the next time it wants to
-   connect wireless. We save them for that next time also so we can
-   authenticate the device (when we see the CDID he uses to id
-   itself) and the CK to crypto talk to it.
-
-CHID is always 16 hex bytes in 'XX YY ZZ...' form
-BANDGROUP is almost always 0001
-
-Examples:
-
-  You can default most arguments to '' to get a sane value:
-
-  $ $progname set-chid '' '' '' "My host name"
-
-  A full sequence:
-
-  $ $progname set-chid '' '' '' "My host name"
-  $ $progname get-cdid ''
-  $ $progname set-cc ''
-
-EOF
-}
-
-
-# Defaults
-# FIXME: CHID should come from a database :), band group from the host
-host_CHID="00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff"
-host_band_group="0001"
-host_name=$(hostname)
-
-devs="$(echo /sys/bus/usb/drivers/wusb-cbaf/[0-9]*)"
-hdevs="$(for h in /sys/class/uwb_rc/*/wusbhc; do readlink -f $h; done)"
-
-result=0
-case $1 in
-    start)
-        for dev in ${2:-$hdevs}
-          do
-          echo $host_CHID > $dev/wusb_chid
-          echo I: started host $(basename $dev) >&2
-        done
-        ;;
-    stop)
-        for dev in ${2:-$hdevs}
-          do
-          echo 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 > $dev/wusb_chid
-          echo I: stopped host $(basename $dev) >&2
-        done
-        ;;
-    set-chid)
-        shift
-        for dev in ${2:-$devs}; do
-            echo "${4:-$host_name}" > $dev/wusb_host_name
-            echo "${3:-$host_band_group}" > $dev/wusb_host_band_groups
-            echo ${2:-$host_CHID} > $dev/wusb_chid
-        done
-        ;;
-    get-cdid)
-        for dev in ${2:-$devs}
-          do
-          cat $dev/wusb_cdid
-        done
-        ;;
-    set-cc)
-        for dev in ${2:-$devs}; do
-            shift
-            CDID="$(head --bytes=16 /dev/urandom  | od -tx1 -An)"
-            CK="$(head --bytes=16 /dev/urandom  | od -tx1 -An)"
-            echo "$CDID" > $dev/wusb_cdid
-            echo "$CK" > $dev/wusb_ck
-
-            echo I: CC set >&2
-            echo "CHID: $(cat $dev/wusb_chid)"
-            echo "CDID:$CDID"
-            echo "CK:  $CK"
-        done
-        ;;
-    help|h|--help|-h)
-        help
-        ;;
-    *)
-        echo "E: Unknown usage" 1>&2
-        help 1>&2
-        result=1
-esac
-exit $result
diff --git a/drivers/staging/wusbcore/Documentation/wusb-design-overview.rst b/drivers/staging/wusbcore/Documentation/wusb-design-overview.rst
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/drivers/staging/wusbcore/Kconfig b/drivers/staging/wusbcore/Kconfig
deleted file mode 100644 (file)
index a559d02..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Wireless USB Core configuration
-#
-config USB_WUSB
-       tristate "Enable Wireless USB extensions"
-       depends on UWB && USB
-       select CRYPTO
-       select CRYPTO_AES
-       select CRYPTO_CCM
-       help
-         Enable the host-side support for Wireless USB.
-
-          To compile this support select Y (built in). It is safe to
-         select even if you don't have the hardware.
-
-config USB_WUSB_CBAF
-       tristate "Support WUSB Cable Based Association (CBA)"
-       depends on USB
-       help
-         Some WUSB devices support Cable Based Association. It's used to
-         enable the secure communication between the host and the
-         device.
-
-         Enable this option if your WUSB device must to be connected
-         via wired USB before establishing a wireless link.
-
-         It is safe to select even if you don't have a compatible
-         hardware.
-
-config USB_WUSB_CBAF_DEBUG
-       bool "Enable CBA debug messages"
-       depends on USB_WUSB_CBAF
-       help
-         Say Y here if you want the CBA to produce a bunch of debug messages
-         to the system log. Select this if you are having a problem with
-         CBA support and want to see more of what is going on.
-
-source "drivers/staging/wusbcore/host/Kconfig"
diff --git a/drivers/staging/wusbcore/Makefile b/drivers/staging/wusbcore/Makefile
deleted file mode 100644 (file)
index b47b874..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-ccflags-$(CONFIG_USB_WUSB_CBAF_DEBUG) := -DDEBUG
-
-obj-$(CONFIG_USB_WUSB)         += wusbcore.o
-obj-$(CONFIG_USB_HWA_HCD)      += wusb-wa.o
-obj-$(CONFIG_USB_WUSB_CBAF)    += wusb-cbaf.o
-
-
-wusbcore-y :=          \
-       crypto.o        \
-       devconnect.o    \
-       dev-sysfs.o     \
-       mmc.o           \
-       pal.o           \
-       rh.o            \
-       reservation.o   \
-       security.o      \
-       wusbhc.o
-
-wusb-cbaf-y := cbaf.o
-
-wusb-wa-y :=           \
-       wa-hc.o         \
-       wa-nep.o        \
-       wa-rpipe.o      \
-       wa-xfer.o
-
-obj-y  += host/
diff --git a/drivers/staging/wusbcore/TODO b/drivers/staging/wusbcore/TODO
deleted file mode 100644 (file)
index abae570..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-TODO: Remove in late 2019 unless there are users
-
-There seems to not be any real wireless USB devices anywhere in the wild
-anymore.  It turned out to be a failed technology :(
-
-This will be removed from the tree if no one objects.
-
-Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/staging/wusbcore/cbaf.c b/drivers/staging/wusbcore/cbaf.c
deleted file mode 100644 (file)
index 57062ea..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB - Cable Based Association
- *
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * WUSB devices have to be paired (associated in WUSB lingo) so
- * that they can connect to the system.
- *
- * One way of pairing is using CBA-Cable Based Association. First
- * time you plug the device with a cable, association is done between
- * host and device and subsequent times, you can connect wirelessly
- * without having to associate again. That's the idea.
- *
- * This driver does nothing Earth shattering. It just provides an
- * interface to chat with the wire-connected device so we can get a
- * CDID (device ID) that might have been previously associated to a
- * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet
- * (connection context), with the CK being the secret, or connection
- * key. This is the pairing data.
- *
- * When a device with the CBA capability connects, the probe routine
- * just creates a bunch of sysfs files that a user space enumeration
- * manager uses to allow it to connect wirelessly to the system or not.
- *
- * The process goes like this:
- *
- * 1. Device plugs, cbaf is loaded, notifications happen.
- *
- * 2. The connection manager (CM) sees a device with CBAF capability
- *    (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE).
- *
- * 3. The CM writes the host name, supported band groups, and the CHID
- *    (host ID) into the wusb_host_name, wusb_host_band_groups and
- *    wusb_chid files. These get sent to the device and the CDID (if
- *    any) for this host is requested.
- *
- * 4. The CM can verify that the device's supported band groups
- *    (wusb_device_band_groups) are compatible with the host.
- *
- * 5. The CM reads the wusb_cdid file.
- *
- * 6. The CM looks up its database
- *
- * 6.1 If it has a matching CHID,CDID entry, the device has been
- *     authorized before (paired) and nothing further needs to be
- *     done.
- *
- * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in
- *     its database), the device is assumed to be not known.  The CM
- *     may associate the host with device by: writing a randomly
- *     generated CDID to wusb_cdid and then a random CK to wusb_ck
- *     (this uploads the new CC to the device).
- *
- *     CMD may choose to prompt the user before associating with a new
- *     device.
- *
- * 7. Device is unplugged.
- *
- * When the device tries to connect wirelessly, it will present its
- * CDID to the WUSB host controller.  The CM will query the
- * database. If the CHID/CDID pair found, it will (with a 4-way
- * handshake) challenge the device to demonstrate it has the CK secret
- * key (from our database) without actually exchanging it. Once
- * satisfied, crypto keys are derived from the CK, the device is
- * connected and all communication is encrypted.
- *
- * References:
- *   [WUSB-AM] Association Models Supplement to the Certified Wireless
- *             Universal Serial Bus Specification, version 1.0.
- */
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/usb.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include "../uwb/uwb.h"
-#include "include/wusb.h"
-#include "include/association.h"
-
-#define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */
-
-/* An instance of a Cable-Based-Association-Framework device */
-struct cbaf {
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-       void *buffer;
-       size_t buffer_size;
-
-       struct wusb_ckhdid chid;
-       char host_name[CBA_NAME_LEN];
-       u16 host_band_groups;
-
-       struct wusb_ckhdid cdid;
-       char device_name[CBA_NAME_LEN];
-       u16 device_band_groups;
-
-       struct wusb_ckhdid ck;
-};
-
-/*
- * Verify that a CBAF USB-interface has what we need
- *
- * According to [WUSB-AM], CBA devices should provide at least two
- * interfaces:
- *  - RETRIEVE_HOST_INFO
- *  - ASSOCIATE
- *
- * If the device doesn't provide these interfaces, we do not know how
- * to deal with it.
- */
-static int cbaf_check(struct cbaf *cbaf)
-{
-       int result;
-       struct device *dev = &cbaf->usb_iface->dev;
-       struct wusb_cbaf_assoc_info *assoc_info;
-       struct wusb_cbaf_assoc_request *assoc_request;
-       size_t assoc_size;
-       void *itr, *top;
-       int ar_rhi = 0, ar_assoc = 0;
-
-       result = usb_control_msg(
-               cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
-               CBAF_REQ_GET_ASSOCIATION_INFORMATION,
-               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               cbaf->buffer, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Cannot get available association types: %d\n",
-                       result);
-               return result;
-       }
-
-       assoc_info = cbaf->buffer;
-       if (result < sizeof(*assoc_info)) {
-               dev_err(dev, "Not enough data to decode association info "
-                       "header (%zu vs %zu bytes required)\n",
-                       (size_t)result, sizeof(*assoc_info));
-               return result;
-       }
-
-       assoc_size = le16_to_cpu(assoc_info->Length);
-       if (result < assoc_size) {
-               dev_err(dev, "Not enough data to decode association info "
-                       "(%zu vs %zu bytes required)\n",
-                       (size_t)assoc_size, sizeof(*assoc_info));
-               return result;
-       }
-       /*
-        * From now on, we just verify, but won't error out unless we
-        * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE}
-        * types.
-        */
-       itr = cbaf->buffer + sizeof(*assoc_info);
-       top = cbaf->buffer + assoc_size;
-       dev_dbg(dev, "Found %u association requests (%zu bytes)\n",
-                assoc_info->NumAssociationRequests, assoc_size);
-
-       while (itr < top) {
-               u16 ar_type, ar_subtype;
-               u32 ar_size;
-               const char *ar_name;
-
-               assoc_request = itr;
-
-               if (top - itr < sizeof(*assoc_request)) {
-                       dev_err(dev, "Not enough data to decode association "
-                               "request (%zu vs %zu bytes needed)\n",
-                               top - itr, sizeof(*assoc_request));
-                       break;
-               }
-
-               ar_type = le16_to_cpu(assoc_request->AssociationTypeId);
-               ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId);
-               ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize);
-               ar_name = "unknown";
-
-               switch (ar_type) {
-               case AR_TYPE_WUSB:
-                       /* Verify we have what is mandated by [WUSB-AM]. */
-                       switch (ar_subtype) {
-                       case AR_TYPE_WUSB_RETRIEVE_HOST_INFO:
-                               ar_name = "RETRIEVE_HOST_INFO";
-                               ar_rhi = 1;
-                               break;
-                       case AR_TYPE_WUSB_ASSOCIATE:
-                               /* send assoc data */
-                               ar_name = "ASSOCIATE";
-                               ar_assoc = 1;
-                               break;
-                       }
-                       break;
-               }
-
-               dev_dbg(dev, "Association request #%02u: 0x%04x/%04x "
-                        "(%zu bytes): %s\n",
-                        assoc_request->AssociationDataIndex, ar_type,
-                        ar_subtype, (size_t)ar_size, ar_name);
-
-               itr += sizeof(*assoc_request);
-       }
-
-       if (!ar_rhi) {
-               dev_err(dev, "Missing RETRIEVE_HOST_INFO association "
-                       "request\n");
-               return -EINVAL;
-       }
-       if (!ar_assoc) {
-               dev_err(dev, "Missing ASSOCIATE association request\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static const struct wusb_cbaf_host_info cbaf_host_info_defaults = {
-       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
-       .AssociationTypeId        = cpu_to_le16(AR_TYPE_WUSB),
-       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
-       .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO),
-       .CHID_hdr                 = WUSB_AR_CHID,
-       .LangID_hdr               = WUSB_AR_LangID,
-       .HostFriendlyName_hdr     = WUSB_AR_HostFriendlyName,
-};
-
-/* Send WUSB host information (CHID and name) to a CBAF device */
-static int cbaf_send_host_info(struct cbaf *cbaf)
-{
-       struct wusb_cbaf_host_info *hi;
-       size_t name_len;
-       size_t hi_size;
-
-       hi = cbaf->buffer;
-       memset(hi, 0, sizeof(*hi));
-       *hi = cbaf_host_info_defaults;
-       hi->CHID = cbaf->chid;
-       hi->LangID = 0; /* FIXME: I guess... */
-       strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN);
-       name_len = strlen(cbaf->host_name);
-       hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len);
-       hi_size = sizeof(*hi) + name_len;
-
-       return usb_control_msg(cbaf->usb_dev,
-                       usb_sndctrlpipe(cbaf->usb_dev, 0),
-                       CBAF_REQ_SET_ASSOCIATION_RESPONSE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0x0101,
-                       cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       hi, hi_size, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Get device's information (CDID) associated to CHID
- *
- * The device will return it's information (CDID, name, bandgroups)
- * associated to the CHID we have set before, or 0 CDID and default
- * name and bandgroup if no CHID set or unknown.
- */
-static int cbaf_cdid_get(struct cbaf *cbaf)
-{
-       int result;
-       struct device *dev = &cbaf->usb_iface->dev;
-       struct wusb_cbaf_device_info *di;
-       size_t needed;
-
-       di = cbaf->buffer;
-       result = usb_control_msg(
-               cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
-               CBAF_REQ_GET_ASSOCIATION_REQUEST,
-               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               di, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Cannot request device information: %d\n",
-                       result);
-               return result;
-       }
-
-       needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length);
-       if (result < needed) {
-               dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs "
-                       "%zu bytes needed)\n", (size_t)result, needed);
-               return -ENOENT;
-       }
-
-       strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN);
-       cbaf->cdid = di->CDID;
-       cbaf->device_band_groups = le16_to_cpu(di->BandGroups);
-
-       return 0;
-}
-
-static ssize_t cbaf_wusb_chid_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return sprintf(buf, "%16ph\n", cbaf->chid.data);
-}
-
-static ssize_t cbaf_wusb_chid_store(struct device *dev,
-                                        struct device_attribute *attr,
-                                        const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx",
-                       &cbaf->chid.data[0] , &cbaf->chid.data[1],
-                       &cbaf->chid.data[2] , &cbaf->chid.data[3],
-                       &cbaf->chid.data[4] , &cbaf->chid.data[5],
-                       &cbaf->chid.data[6] , &cbaf->chid.data[7],
-                       &cbaf->chid.data[8] , &cbaf->chid.data[9],
-                       &cbaf->chid.data[10], &cbaf->chid.data[11],
-                       &cbaf->chid.data[12], &cbaf->chid.data[13],
-                       &cbaf->chid.data[14], &cbaf->chid.data[15]);
-
-       if (result != 16)
-               return -EINVAL;
-
-       result = cbaf_send_host_info(cbaf);
-       if (result < 0)
-               return result;
-       result = cbaf_cdid_get(cbaf);
-       if (result < 0)
-               return result;
-       return size;
-}
-static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store);
-
-static ssize_t cbaf_wusb_host_name_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name);
-}
-
-static ssize_t cbaf_wusb_host_name_store(struct device *dev,
-                                        struct device_attribute *attr,
-                                        const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       result = sscanf(buf, "%63s", cbaf->host_name);
-       if (result != 1)
-               return -EINVAL;
-
-       return size;
-}
-static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show,
-                                        cbaf_wusb_host_name_store);
-
-static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev,
-                                              struct device_attribute *attr,
-                                              char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups);
-}
-
-static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev,
-                                               struct device_attribute *attr,
-                                               const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-       u16 band_groups = 0;
-
-       result = sscanf(buf, "%04hx", &band_groups);
-       if (result != 1)
-               return -EINVAL;
-
-       cbaf->host_band_groups = band_groups;
-
-       return size;
-}
-
-static DEVICE_ATTR(wusb_host_band_groups, 0600,
-                  cbaf_wusb_host_band_groups_show,
-                  cbaf_wusb_host_band_groups_store);
-
-static const struct wusb_cbaf_device_info cbaf_device_info_defaults = {
-       .Length_hdr               = WUSB_AR_Length,
-       .CDID_hdr                 = WUSB_AR_CDID,
-       .BandGroups_hdr           = WUSB_AR_BandGroups,
-       .LangID_hdr               = WUSB_AR_LangID,
-       .DeviceFriendlyName_hdr   = WUSB_AR_DeviceFriendlyName,
-};
-
-static ssize_t cbaf_wusb_cdid_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return sprintf(buf, "%16ph\n", cbaf->cdid.data);
-}
-
-static ssize_t cbaf_wusb_cdid_store(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-       struct wusb_ckhdid cdid;
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx",
-                       &cdid.data[0] , &cdid.data[1],
-                       &cdid.data[2] , &cdid.data[3],
-                       &cdid.data[4] , &cdid.data[5],
-                       &cdid.data[6] , &cdid.data[7],
-                       &cdid.data[8] , &cdid.data[9],
-                       &cdid.data[10], &cdid.data[11],
-                       &cdid.data[12], &cdid.data[13],
-                       &cdid.data[14], &cdid.data[15]);
-       if (result != 16)
-               return -EINVAL;
-
-       cbaf->cdid = cdid;
-
-       return size;
-}
-static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store);
-
-static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev,
-                                                struct device_attribute *attr,
-                                                char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups);
-}
-
-static DEVICE_ATTR(wusb_device_band_groups, 0600,
-                  cbaf_wusb_device_band_groups_show,
-                  NULL);
-
-static ssize_t cbaf_wusb_device_name_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name);
-}
-static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL);
-
-static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = {
-       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
-       .AssociationTypeId        = cpu_to_le16(AR_TYPE_WUSB),
-       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
-       .AssociationSubTypeId     = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE),
-       .Length_hdr               = WUSB_AR_Length,
-       .Length         = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)),
-       .ConnectionContext_hdr    = WUSB_AR_ConnectionContext,
-       .BandGroups_hdr           = WUSB_AR_BandGroups,
-};
-
-static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = {
-       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
-       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
-       .Length_hdr               = WUSB_AR_Length,
-       .AssociationStatus_hdr    = WUSB_AR_AssociationStatus,
-};
-
-/*
- * Send a new CC to the device.
- */
-static int cbaf_cc_upload(struct cbaf *cbaf)
-{
-       int result;
-       struct device *dev = &cbaf->usb_iface->dev;
-       struct wusb_cbaf_cc_data *ccd;
-
-       ccd =  cbaf->buffer;
-       *ccd = cbaf_cc_data_defaults;
-       ccd->CHID = cbaf->chid;
-       ccd->CDID = cbaf->cdid;
-       ccd->CK = cbaf->ck;
-       ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups);
-
-       dev_dbg(dev, "Trying to upload CC:\n");
-       dev_dbg(dev, "  CHID       %16ph\n", ccd->CHID.data);
-       dev_dbg(dev, "  CDID       %16ph\n", ccd->CDID.data);
-       dev_dbg(dev, "  Bandgroups 0x%04x\n", cbaf->host_band_groups);
-
-       result = usb_control_msg(
-               cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0),
-               CBAF_REQ_SET_ASSOCIATION_RESPONSE,
-               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               ccd, sizeof(*ccd), USB_CTRL_SET_TIMEOUT);
-
-       return result;
-}
-
-static ssize_t cbaf_wusb_ck_store(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx",
-                       &cbaf->ck.data[0] , &cbaf->ck.data[1],
-                       &cbaf->ck.data[2] , &cbaf->ck.data[3],
-                       &cbaf->ck.data[4] , &cbaf->ck.data[5],
-                       &cbaf->ck.data[6] , &cbaf->ck.data[7],
-                       &cbaf->ck.data[8] , &cbaf->ck.data[9],
-                       &cbaf->ck.data[10], &cbaf->ck.data[11],
-                       &cbaf->ck.data[12], &cbaf->ck.data[13],
-                       &cbaf->ck.data[14], &cbaf->ck.data[15]);
-       if (result != 16)
-               return -EINVAL;
-
-       result = cbaf_cc_upload(cbaf);
-       if (result < 0)
-               return result;
-
-       return size;
-}
-static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store);
-
-static struct attribute *cbaf_dev_attrs[] = {
-       &dev_attr_wusb_host_name.attr,
-       &dev_attr_wusb_host_band_groups.attr,
-       &dev_attr_wusb_chid.attr,
-       &dev_attr_wusb_cdid.attr,
-       &dev_attr_wusb_device_name.attr,
-       &dev_attr_wusb_device_band_groups.attr,
-       &dev_attr_wusb_ck.attr,
-       NULL,
-};
-
-static const struct attribute_group cbaf_dev_attr_group = {
-       .name = NULL,   /* we want them in the same directory */
-       .attrs = cbaf_dev_attrs,
-};
-
-static int cbaf_probe(struct usb_interface *iface,
-                     const struct usb_device_id *id)
-{
-       struct cbaf *cbaf;
-       struct device *dev = &iface->dev;
-       int result = -ENOMEM;
-
-       cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL);
-       if (cbaf == NULL)
-               goto error_kzalloc;
-       cbaf->buffer = kmalloc(512, GFP_KERNEL);
-       if (cbaf->buffer == NULL)
-               goto error_kmalloc_buffer;
-
-       cbaf->buffer_size = 512;
-       cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface));
-       cbaf->usb_iface = usb_get_intf(iface);
-       result = cbaf_check(cbaf);
-       if (result < 0) {
-               dev_err(dev, "This device is not WUSB-CBAF compliant and is not supported yet.\n");
-               goto error_check;
-       }
-
-       result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group);
-       if (result < 0) {
-               dev_err(dev, "Can't register sysfs attr group: %d\n", result);
-               goto error_create_group;
-       }
-       usb_set_intfdata(iface, cbaf);
-       return 0;
-
-error_create_group:
-error_check:
-       usb_put_intf(iface);
-       usb_put_dev(cbaf->usb_dev);
-       kfree(cbaf->buffer);
-error_kmalloc_buffer:
-       kfree(cbaf);
-error_kzalloc:
-       return result;
-}
-
-static void cbaf_disconnect(struct usb_interface *iface)
-{
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-       struct device *dev = &iface->dev;
-       sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group);
-       usb_set_intfdata(iface, NULL);
-       usb_put_intf(iface);
-       usb_put_dev(cbaf->usb_dev);
-       kfree(cbaf->buffer);
-       /* paranoia: clean up crypto keys */
-       kzfree(cbaf);
-}
-
-static const struct usb_device_id cbaf_id_table[] = {
-       { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, cbaf_id_table);
-
-static struct usb_driver cbaf_driver = {
-       .name =         "wusb-cbaf",
-       .id_table =     cbaf_id_table,
-       .probe =        cbaf_probe,
-       .disconnect =   cbaf_disconnect,
-};
-
-module_usb_driver(cbaf_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Wireless USB Cable Based Association");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/crypto.c b/drivers/staging/wusbcore/crypto.c
deleted file mode 100644 (file)
index d7d55ed..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Ultra Wide Band
- * AES-128 CCM Encryption
- *
- * Copyright (C) 2007 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * We don't do any encryption here; we use the Linux Kernel's AES-128
- * crypto modules to construct keys and payload blocks in a way
- * defined by WUSB1.0[6]. Check the erratas, as typos are are patched
- * there.
- *
- * Thanks a zillion to John Keys for his help and clarifications over
- * the designed-by-a-committee text.
- *
- * So the idea is that there is this basic Pseudo-Random-Function
- * defined in WUSB1.0[6.5] which is the core of everything. It works
- * by tweaking some blocks, AES crypting them and then xoring
- * something else with them (this seems to be called CBC(AES) -- can
- * you tell I know jack about crypto?). So we just funnel it into the
- * Linux Crypto API.
- *
- * We leave a crypto test module so we can verify that vectors match,
- * every now and then.
- *
- * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I
- *             am learning a lot...
- *
- *             Conveniently, some data structures that need to be
- *             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>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/scatterlist.h>
-#include "../uwb/uwb.h"
-#include "include/wusb.h"
-
-static int debug_crypto_verify;
-
-module_param(debug_crypto_verify, int, 0);
-MODULE_PARM_DESC(debug_crypto_verify, "verify the key generation algorithms");
-
-static void wusb_key_dump(const void *buf, size_t len)
-{
-       print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_OFFSET, 16, 1,
-                      buf, len, 0);
-}
-
-/*
- * Block of data, as understood by AES-CCM
- *
- * The code assumes this structure is nothing but a 16 byte array
- * (packed in a struct to avoid common mess ups that I usually do with
- * arrays and enforcing type checking).
- */
-struct aes_ccm_block {
-       u8 data[16];
-} __attribute__((packed));
-
-/*
- * Counter-mode Blocks (WUSB1.0[6.4])
- *
- * According to CCM (or so it seems), for the purpose of calculating
- * the MIC, the message is broken in N counter-mode blocks, B0, B1,
- * ... BN.
- *
- * B0 contains flags, the CCM nonce and l(m).
- *
- * B1 contains l(a), the MAC header, the encryption offset and padding.
- *
- * If EO is nonzero, additional blocks are built from payload bytes
- * until EO is exhausted (FIXME: padding to 16 bytes, I guess). The
- * padding is not xmitted.
- */
-
-/* WUSB1.0[T6.4] */
-struct aes_ccm_b0 {
-       u8 flags;       /* 0x59, per CCM spec */
-       struct aes_ccm_nonce ccm_nonce;
-       __be16 lm;
-} __attribute__((packed));
-
-/* WUSB1.0[T6.5] */
-struct aes_ccm_b1 {
-       __be16 la;
-       u8 mac_header[10];
-       __le16 eo;
-       u8 security_reserved;   /* This is always zero */
-       u8 padding;             /* 0 */
-} __attribute__((packed));
-
-/*
- * Encryption Blocks (WUSB1.0[6.4.4])
- *
- * CCM uses Ax blocks to generate a keystream with which the MIC and
- * the message's payload are encoded. A0 always encrypts/decrypts the
- * MIC. Ax (x>0) are used for the successive payload blocks.
- *
- * The x is the counter, and is increased for each block.
- */
-struct aes_ccm_a {
-       u8 flags;       /* 0x01, per CCM spec */
-       struct aes_ccm_nonce ccm_nonce;
-       __be16 counter; /* Value of x */
-} __attribute__((packed));
-
-/* Scratch space for MAC calculations. */
-struct wusb_mac_scratch {
-       struct aes_ccm_b0 b0;
-       struct aes_ccm_b1 b1;
-       struct aes_ccm_a ax;
-};
-
-/*
- * CC-MAC function WUSB1.0[6.5]
- *
- * Take a data string and produce the encrypted CBC Counter-mode MIC
- *
- * Note the names for most function arguments are made to (more or
- * less) match those used in the pseudo-function definition given in
- * WUSB1.0[6.5].
- *
- * @tfm_cbc: CBC(AES) blkcipher handle (initialized)
- *
- * @tfm_aes: AES cipher handle (initialized)
- *
- * @mic: buffer for placing the computed MIC (Message Integrity
- *       Code). This is exactly 8 bytes, and we expect the buffer to
- *       be at least eight bytes in length.
- *
- * @key: 128 bit symmetric key
- *
- * @n: CCM nonce
- *
- * @a: ASCII string, 14 bytes long (I guess zero padded if needed;
- *     we use exactly 14 bytes).
- *
- * @b: data stream to be processed
- *
- * @blen: size of b...
- *
- * Still not very clear how this is done, but looks like this: we
- * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with
- * @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. 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
- *
- * (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}.
- *
- * NOTE: The definition of l(a) in WUSB1.0[6.5] vs the definition of
- *       l(m) is orthogonal, they bear no relationship, so it is not
- *       in conflict with the parameter's relation that
- *       WUSB1.0[6.4.2]) defines.
- *
- * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in
- *       first errata released on 2005/07.
- *
- * NOTE: we need to clean IV to zero at each invocation to make sure
- *       we start with a fresh empty Initial Vector, so that the CBC
- *       works ok.
- *
- * 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_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)
-{
-       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
-        */
-       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 */
-       scratch->b0.ccm_nonce = *n;
-       scratch->b0.lm = cpu_to_be16(0);        /* WUSB1.0[6.5] sez l(m) is 0 */
-
-       /* Setup B1
-        *
-        * The WUSB spec is anything but clear! WUSB1.0[6.5]
-        * says that to initialize B1 from A with 'l(a) = blen +
-        * 14'--after clarification, it means to use A's contents
-        * for MAC Header, EO, sec reserved and padding.
-        */
-       scratch->b1.la = cpu_to_be16(blen + 14);
-       memcpy(&scratch->b1.mac_header, a, sizeof(*a));
-
-       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.
-        */
-       scratch->ax.flags = 0x01;               /* as per WUSB 1.0 spec */
-       scratch->ax.ccm_nonce = *n;
-       scratch->ax.counter = 0;
-
-       /* 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;
-}
-
-/*
- * WUSB Pseudo Random Function (WUSB1.0[6.5])
- *
- * @b: buffer to the source data; cannot be a global or const local
- *     (will confuse the scatterlists)
- */
-ssize_t wusb_prf(void *out, size_t out_size,
-                const u8 key[16], const struct aes_ccm_nonce *_n,
-                const struct aes_ccm_label *a,
-                const void *b, size_t blen, size_t len)
-{
-       ssize_t result, bytes = 0, bitr;
-       struct aes_ccm_nonce n = *_n;
-       struct crypto_shash *tfm_cbcmac;
-       struct wusb_mac_scratch scratch;
-       u64 sfn = 0;
-       __le64 sfn_le;
-
-       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;
-       }
-
-       result = crypto_shash_setkey(tfm_cbcmac, key, AES_BLOCK_SIZE);
-       if (result < 0) {
-               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_cbcmac, &scratch, out + bytes,
-                                     &n, a, b, blen);
-               if (result < 0)
-                       goto error_ccm_mac;
-               bytes += result;
-       }
-       result = bytes;
-
-error_ccm_mac:
-error_setkey_cbcmac:
-       crypto_free_shash(tfm_cbcmac);
-error_alloc_cbcmac:
-       return result;
-}
-
-/* WUSB1.0[A.2] test vectors */
-static const u8 stv_hsmic_key[16] = {
-       0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
-       0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
-};
-
-static const struct aes_ccm_nonce stv_hsmic_n = {
-       .sfn = { 0 },
-       .tkid = { 0x76, 0x98, 0x01,  },
-       .dest_addr = { .data = { 0xbe, 0x00 } },
-               .src_addr = { .data = { 0x76, 0x98 } },
-};
-
-/*
- * Out-of-band MIC Generation verification code
- *
- */
-static int wusb_oob_mic_verify(void)
-{
-       int result;
-       u8 mic[8];
-       /* WUSB1.0[A.2] test vectors */
-       static const struct usb_handshake stv_hsmic_hs = {
-               .bMessageNumber = 2,
-               .bStatus        = 00,
-               .tTKID          = { 0x76, 0x98, 0x01 },
-               .bReserved      = 00,
-               .CDID           = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
-                                   0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
-                                   0x3c, 0x3d, 0x3e, 0x3f },
-               .nonce          = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
-                                   0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
-                                   0x2c, 0x2d, 0x2e, 0x2f },
-               .MIC            = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c,
-                                   0x14, 0x7b },
-       };
-       size_t hs_size;
-
-       result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs);
-       if (result < 0)
-               printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result);
-       else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) {
-               printk(KERN_ERR "E: OOB MIC test: "
-                      "mismatch between MIC result and WUSB1.0[A2]\n");
-               hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC);
-               printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size);
-               wusb_key_dump(&stv_hsmic_hs, hs_size);
-               printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n",
-                      sizeof(stv_hsmic_n));
-               wusb_key_dump(&stv_hsmic_n, sizeof(stv_hsmic_n));
-               printk(KERN_ERR "E: MIC out:\n");
-               wusb_key_dump(mic, sizeof(mic));
-               printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n");
-               wusb_key_dump(stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC));
-               result = -EINVAL;
-       } else
-               result = 0;
-       return result;
-}
-
-/*
- * Test vectors for Key derivation
- *
- * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1]
- * (errata corrected in 2005/07).
- */
-static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = {
-       0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
-       0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f
-};
-
-static const struct aes_ccm_nonce stv_keydvt_n_a1 = {
-       .sfn = { 0 },
-       .tkid = { 0x76, 0x98, 0x01,  },
-       .dest_addr = { .data = { 0xbe, 0x00 } },
-       .src_addr = { .data = { 0x76, 0x98 } },
-};
-
-static const struct wusb_keydvt_out stv_keydvt_out_a1 = {
-       .kck = {
-               0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
-               0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
-       },
-       .ptk = {
-               0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06,
-               0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d
-       }
-};
-
-/*
- * Performa a test to make sure we match the vectors defined in
- * WUSB1.0[A.1](Errata2006/12)
- */
-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 */
-       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
-               },
-               .dnonce = {
-                       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-                       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
-               }
-       };
-
-       result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1,
-                                &stv_keydvt_in_a1);
-       if (result < 0)
-               printk(KERN_ERR "E: WUSB key derivation test: "
-                      "derivation failed: %d\n", result);
-       if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) {
-               printk(KERN_ERR "E: WUSB key derivation test: "
-                      "mismatch between key derivation result "
-                      "and WUSB1.0[A1] Errata 2006/12\n");
-               printk(KERN_ERR "E: keydvt in: key\n");
-               wusb_key_dump(stv_key_a1, sizeof(stv_key_a1));
-               printk(KERN_ERR "E: keydvt in: nonce\n");
-               wusb_key_dump(&stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1));
-               printk(KERN_ERR "E: keydvt in: hnonce & dnonce\n");
-               wusb_key_dump(&stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1));
-               printk(KERN_ERR "E: keydvt out: KCK\n");
-               wusb_key_dump(&keydvt_out.kck, sizeof(keydvt_out.kck));
-               printk(KERN_ERR "E: keydvt out: PTK\n");
-               wusb_key_dump(&keydvt_out.ptk, sizeof(keydvt_out.ptk));
-               result = -EINVAL;
-       } else
-               result = 0;
-       return result;
-}
-
-/*
- * Initialize crypto system
- *
- * FIXME: we do nothing now, other than verifying. Later on we'll
- * cache the encryption stuff, so that's why we have a separate init.
- */
-int wusb_crypto_init(void)
-{
-       int result;
-
-       if (debug_crypto_verify) {
-               result = wusb_key_derive_verify();
-               if (result < 0)
-                       return result;
-               return wusb_oob_mic_verify();
-       }
-       return 0;
-}
-
-void wusb_crypto_exit(void)
-{
-       /* FIXME: free cached crypto transforms */
-}
diff --git a/drivers/staging/wusbcore/dev-sysfs.c b/drivers/staging/wusbcore/dev-sysfs.c
deleted file mode 100644 (file)
index 67b0a4c..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB devices
- * sysfs bindings
- *
- * Copyright (C) 2007 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Get them out of the way...
- */
-
-#include <linux/jiffies.h>
-#include <linux/ctype.h>
-#include <linux/workqueue.h>
-#include "wusbhc.h"
-
-static ssize_t wusb_disconnect_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t size)
-{
-       struct usb_device *usb_dev;
-       struct wusbhc *wusbhc;
-       unsigned command;
-       u8 port_idx;
-
-       if (sscanf(buf, "%u", &command) != 1)
-               return -EINVAL;
-       if (command == 0)
-               return size;
-       usb_dev = to_usb_device(dev);
-       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
-       if (wusbhc == NULL)
-               return -ENODEV;
-
-       mutex_lock(&wusbhc->mutex);
-       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
-       __wusbhc_dev_disable(wusbhc, port_idx);
-       mutex_unlock(&wusbhc->mutex);
-       wusbhc_put(wusbhc);
-       return size;
-}
-static DEVICE_ATTR_WO(wusb_disconnect);
-
-static ssize_t wusb_cdid_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       ssize_t result;
-       struct wusb_dev *wusb_dev;
-
-       wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev));
-       if (wusb_dev == NULL)
-               return -ENODEV;
-       result = sprintf(buf, "%16ph\n", wusb_dev->cdid.data);
-       wusb_dev_put(wusb_dev);
-       return result;
-}
-static DEVICE_ATTR_RO(wusb_cdid);
-
-static ssize_t wusb_ck_store(struct device *dev,
-                            struct device_attribute *attr,
-                            const char *buf, size_t size)
-{
-       int result;
-       struct usb_device *usb_dev;
-       struct wusbhc *wusbhc;
-       struct wusb_ckhdid ck;
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx\n",
-                       &ck.data[0] , &ck.data[1],
-                       &ck.data[2] , &ck.data[3],
-                       &ck.data[4] , &ck.data[5],
-                       &ck.data[6] , &ck.data[7],
-                       &ck.data[8] , &ck.data[9],
-                       &ck.data[10], &ck.data[11],
-                       &ck.data[12], &ck.data[13],
-                       &ck.data[14], &ck.data[15]);
-       if (result != 16)
-               return -EINVAL;
-
-       usb_dev = to_usb_device(dev);
-       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
-       if (wusbhc == NULL)
-               return -ENODEV;
-       result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck);
-       memzero_explicit(&ck, sizeof(ck));
-       wusbhc_put(wusbhc);
-       return result < 0 ? result : size;
-}
-static DEVICE_ATTR_WO(wusb_ck);
-
-static struct attribute *wusb_dev_attrs[] = {
-               &dev_attr_wusb_disconnect.attr,
-               &dev_attr_wusb_cdid.attr,
-               &dev_attr_wusb_ck.attr,
-               NULL,
-};
-
-static const struct attribute_group wusb_dev_attr_group = {
-       .name = NULL,   /* we want them in the same directory */
-       .attrs = wusb_dev_attrs,
-};
-
-int wusb_dev_sysfs_add(struct wusbhc *wusbhc, struct usb_device *usb_dev,
-                      struct wusb_dev *wusb_dev)
-{
-       int result = sysfs_create_group(&usb_dev->dev.kobj,
-                                       &wusb_dev_attr_group);
-       struct device *dev = &usb_dev->dev;
-       if (result < 0)
-               dev_err(dev, "Cannot register WUSB-dev attributes: %d\n",
-                       result);
-       return result;
-}
-
-void wusb_dev_sysfs_rm(struct wusb_dev *wusb_dev)
-{
-       struct usb_device *usb_dev = wusb_dev->usb_dev;
-       if (usb_dev)
-               sysfs_remove_group(&usb_dev->dev.kobj, &wusb_dev_attr_group);
-}
diff --git a/drivers/staging/wusbcore/devconnect.c b/drivers/staging/wusbcore/devconnect.c
deleted file mode 100644 (file)
index 1170f8b..0000000
+++ /dev/null
@@ -1,1085 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
- * Device Connect handling
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- * FIXME: this file needs to be broken up, it's grown too big
- *
- *
- * WUSB1.0[7.1, 7.5.1, ]
- *
- * WUSB device connection is kind of messy. Some background:
- *
- *     When a device wants to connect it scans the UWB radio channels
- *     looking for a WUSB Channel; a WUSB channel is defined by MMCs
- *     (Micro Managed Commands or something like that) [see
- *     Design-overview for more on this] .
- *
- * So, device scans the radio, finds MMCs and thus a host and checks
- * when the next DNTS is. It sends a Device Notification Connect
- * (DN_Connect); the host picks it up (through nep.c and notif.c, ends
- * up in wusb_devconnect_ack(), which creates a wusb_dev structure in
- * wusbhc->port[port_number].wusb_dev), assigns an unauth address
- * to the device (this means from 0x80 to 0xfe) and sends, in the MMC
- * a Connect Ack Information Element (ConnAck IE).
- *
- * So now the device now has a WUSB address. From now on, we use
- * that to talk to it in the RPipes.
- *
- * ASSUMPTIONS:
- *
- *  - We use the the as device address the port number where it is
- *    connected (port 0 doesn't exist). For unauth, it is 128 + that.
- *
- * ROADMAP:
- *
- *   This file contains the logic for doing that--entry points:
- *
- *   wusb_devconnect_ack()      Ack a device until _acked() called.
- *                              Called by notif.c:wusb_handle_dn_connect()
- *                              when a DN_Connect is received.
- *
- *     wusb_devconnect_acked()  Ack done, release resources.
- *
- *   wusb_handle_dn_alive()     Called by notif.c:wusb_handle_dn()
- *                              for processing a DN_Alive pong from a device.
- *
- *   wusb_handle_dn_disconnect()Called by notif.c:wusb_handle_dn() to
- *                              process a disconnect request from a
- *                              device.
- *
- *   __wusb_dev_disable()       Called by rh.c:wusbhc_rh_clear_port_feat() when
- *                              disabling a port.
- *
- *   wusb_devconnect_create()   Called when creating the host by
- *                              lc.c:wusbhc_create().
- *
- *   wusb_devconnect_destroy()  Cleanup called removing the host. Called
- *                              by lc.c:wusbhc_destroy().
- *
- *   Each Wireless USB host maintains a list of DN_Connect requests
- *   (actually we maintain a list of pending Connect Acks, the
- *   wusbhc->ca_list).
- *
- * LIFE CYCLE OF port->wusb_dev
- *
- *   Before the @wusbhc structure put()s the reference it owns for
- *   port->wusb_dev [and clean the wusb_dev pointer], it needs to
- *   lock @wusbhc->mutex.
- */
-
-#include <linux/jiffies.h>
-#include <linux/ctype.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/export.h>
-#include "wusbhc.h"
-
-static void wusbhc_devconnect_acked_work(struct work_struct *work);
-
-static void wusb_dev_free(struct wusb_dev *wusb_dev)
-{
-       kfree(wusb_dev);
-}
-
-static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
-{
-       struct wusb_dev *wusb_dev;
-
-       wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL);
-       if (wusb_dev == NULL)
-               goto err;
-
-       wusb_dev->wusbhc = wusbhc;
-
-       INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work);
-
-       return wusb_dev;
-err:
-       wusb_dev_free(wusb_dev);
-       return NULL;
-}
-
-
-/*
- * Using the Connect-Ack list, fill out the @wusbhc Connect-Ack WUSB IE
- * properly so that it can be added to the MMC.
- *
- * We just get the @wusbhc->ca_list and fill out the first four ones or
- * less (per-spec WUSB1.0[7.5, before T7-38). If the ConnectAck WUSB
- * IE is not allocated, we alloc it.
- *
- * @wusbhc->mutex must be taken
- */
-static void wusbhc_fill_cack_ie(struct wusbhc *wusbhc)
-{
-       unsigned cnt;
-       struct wusb_dev *dev_itr;
-       struct wuie_connect_ack *cack_ie;
-
-       cack_ie = &wusbhc->cack_ie;
-       cnt = 0;
-       list_for_each_entry(dev_itr, &wusbhc->cack_list, cack_node) {
-               cack_ie->blk[cnt].CDID = dev_itr->cdid;
-               cack_ie->blk[cnt].bDeviceAddress = dev_itr->addr;
-               if (++cnt >= WUIE_ELT_MAX)
-                       break;
-       }
-       cack_ie->hdr.bLength = sizeof(cack_ie->hdr)
-               + cnt * sizeof(cack_ie->blk[0]);
-}
-
-/*
- * Register a new device that wants to connect
- *
- * A new device wants to connect, so we add it to the Connect-Ack
- * list. We give it an address in the unauthorized range (bit 8 set);
- * user space will have to drive authorization further on.
- *
- * @dev_addr: address to use for the device (which is also the port
- *            number).
- *
- * @wusbhc->mutex must be taken
- */
-static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc,
-                                       struct wusb_dn_connect *dnc,
-                                       const char *pr_cdid, u8 port_idx)
-{
-       struct device *dev = wusbhc->dev;
-       struct wusb_dev *wusb_dev;
-       int new_connection = wusb_dn_connect_new_connection(dnc);
-       u8 dev_addr;
-       int result;
-
-       /* Is it registered already? */
-       list_for_each_entry(wusb_dev, &wusbhc->cack_list, cack_node)
-               if (!memcmp(&wusb_dev->cdid, &dnc->CDID,
-                           sizeof(wusb_dev->cdid)))
-                       return wusb_dev;
-       /* We don't have it, create an entry, register it */
-       wusb_dev = wusb_dev_alloc(wusbhc);
-       if (wusb_dev == NULL)
-               return NULL;
-       wusb_dev_init(wusb_dev);
-       wusb_dev->cdid = dnc->CDID;
-       wusb_dev->port_idx = port_idx;
-
-       /*
-        * Devices are always available within the cluster reservation
-        * and since the hardware will take the intersection of the
-        * per-device availability and the cluster reservation, the
-        * per-device availability can simply be set to always
-        * available.
-        */
-       bitmap_fill(wusb_dev->availability.bm, UWB_NUM_MAS);
-
-       /* FIXME: handle reconnects instead of assuming connects are
-          always new. */
-       if (1 && new_connection == 0)
-               new_connection = 1;
-       if (new_connection) {
-               dev_addr = (port_idx + 2) | WUSB_DEV_ADDR_UNAUTH;
-
-               dev_info(dev, "Connecting new WUSB device to address %u, "
-                       "port %u\n", dev_addr, port_idx);
-
-               result = wusb_set_dev_addr(wusbhc, wusb_dev, dev_addr);
-               if (result < 0)
-                       return NULL;
-       }
-       wusb_dev->entry_ts = jiffies;
-       list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list);
-       wusbhc->cack_count++;
-       wusbhc_fill_cack_ie(wusbhc);
-
-       return wusb_dev;
-}
-
-/*
- * Remove a Connect-Ack context entry from the HCs view
- *
- * @wusbhc->mutex must be taken
- */
-static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       list_del_init(&wusb_dev->cack_node);
-       wusbhc->cack_count--;
-       wusbhc_fill_cack_ie(wusbhc);
-}
-
-/*
- * @wusbhc->mutex must be taken */
-static
-void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       wusbhc_cack_rm(wusbhc, wusb_dev);
-       if (wusbhc->cack_count)
-               wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
-       else
-               wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr);
-}
-
-static void wusbhc_devconnect_acked_work(struct work_struct *work)
-{
-       struct wusb_dev *wusb_dev = container_of(work, struct wusb_dev,
-                                                devconnect_acked_work);
-       struct wusbhc *wusbhc = wusb_dev->wusbhc;
-
-       mutex_lock(&wusbhc->mutex);
-       wusbhc_devconnect_acked(wusbhc, wusb_dev);
-       mutex_unlock(&wusbhc->mutex);
-
-       wusb_dev_put(wusb_dev);
-}
-
-/*
- * Ack a device for connection
- *
- * FIXME: docs
- *
- * @pr_cdid:   Printable CDID...hex Use @dnc->cdid for the real deal.
- *
- * So we get the connect ack IE (may have been allocated already),
- * find an empty connect block, an empty virtual port, create an
- * address with it (see below), make it an unauth addr [bit 7 set] and
- * set the MMC.
- *
- * Addresses: because WUSB hosts have no downstream hubs, we can do a
- *            1:1 mapping between 'port number' and device
- *            address. This simplifies many things, as during this
- *            initial connect phase the USB stack has no knowledge of
- *            the device and hasn't assigned an address yet--we know
- *            USB's choose_address() will use the same heuristics we
- *            use here, so we can assume which address will be assigned.
- *
- *            USB stack always assigns address 1 to the root hub, so
- *            to the port number we add 2 (thus virtual port #0 is
- *            addr #2).
- *
- * @wusbhc shall be referenced
- */
-static
-void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,
-                          const char *pr_cdid)
-{
-       int result;
-       struct device *dev = wusbhc->dev;
-       struct wusb_dev *wusb_dev;
-       struct wusb_port *port;
-       unsigned idx;
-
-       mutex_lock(&wusbhc->mutex);
-
-       /* Check we are not handling it already */
-       for (idx = 0; idx < wusbhc->ports_max; idx++) {
-               port = wusb_port_by_idx(wusbhc, idx);
-               if (port->wusb_dev
-                   && memcmp(&dnc->CDID, &port->wusb_dev->cdid, sizeof(dnc->CDID)) == 0)
-                       goto error_unlock;
-       }
-       /* Look up those fake ports we have for a free one */
-       for (idx = 0; idx < wusbhc->ports_max; idx++) {
-               port = wusb_port_by_idx(wusbhc, idx);
-               if ((port->status & USB_PORT_STAT_POWER)
-                   && !(port->status & USB_PORT_STAT_CONNECTION))
-                       break;
-       }
-       if (idx >= wusbhc->ports_max) {
-               dev_err(dev, "Host controller can't connect more devices "
-                       "(%u already connected); device %s rejected\n",
-                       wusbhc->ports_max, pr_cdid);
-               /* NOTE: we could send a WUIE_Disconnect here, but we haven't
-                *       event acked, so the device will eventually timeout the
-                *       connection, right? */
-               goto error_unlock;
-       }
-
-       /* Make sure we are using no crypto on that "virtual port" */
-       wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0);
-
-       /* Grab a filled in Connect-Ack context, fill out the
-        * Connect-Ack Wireless USB IE, set the MMC */
-       wusb_dev = wusbhc_cack_add(wusbhc, dnc, pr_cdid, idx);
-       if (wusb_dev == NULL)
-               goto error_unlock;
-       result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
-       if (result < 0)
-               goto error_unlock;
-       /* Give the device at least 2ms (WUSB1.0[7.5.1p3]), let's do
-        * three for a good measure */
-       msleep(3);
-       port->wusb_dev = wusb_dev;
-       port->status |= USB_PORT_STAT_CONNECTION;
-       port->change |= USB_PORT_STAT_C_CONNECTION;
-       /* Now the port status changed to connected; hub_wq will
-        * pick the change up and try to reset the port to bring it to
-        * the enabled state--so this process returns up to the stack
-        * and it calls back into wusbhc_rh_port_reset().
-        */
-error_unlock:
-       mutex_unlock(&wusbhc->mutex);
-       return;
-
-}
-
-/*
- * Disconnect a Wireless USB device from its fake port
- *
- * Marks the port as disconnected so that hub_wq can pick up the change
- * and drops our knowledge about the device.
- *
- * Assumes there is a device connected
- *
- * @port_index: zero based port number
- *
- * NOTE: @wusbhc->mutex is locked
- *
- * WARNING: From here it is not very safe to access anything hanging off
- *         wusb_dev
- */
-static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc,
-                                   struct wusb_port *port)
-{
-       struct wusb_dev *wusb_dev = port->wusb_dev;
-
-       port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE
-                         | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET
-                         | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
-       port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE;
-       if (wusb_dev) {
-               dev_dbg(wusbhc->dev, "disconnecting device from port %d\n", wusb_dev->port_idx);
-               if (!list_empty(&wusb_dev->cack_node))
-                       list_del_init(&wusb_dev->cack_node);
-               /* For the one in cack_add() */
-               wusb_dev_put(wusb_dev);
-       }
-       port->wusb_dev = NULL;
-
-       /* After a device disconnects, change the GTK (see [WUSB]
-        * section 6.2.11.2). */
-       if (wusbhc->active)
-               wusbhc_gtk_rekey(wusbhc);
-
-       /* The Wireless USB part has forgotten about the device already; now
-        * hub_wq's timer will pick up the disconnection and remove the USB
-        * device from the system
-        */
-}
-
-/*
- * Refresh the list of keep alives to emit in the MMC
- *
- * We only publish the first four devices that have a coming timeout
- * condition. Then when we are done processing those, we go for the
- * next ones. We ignore the ones that have timed out already (they'll
- * be purged).
- *
- * This might cause the first devices to timeout the last devices in
- * the port array...FIXME: come up with a better algorithm?
- *
- * Note we can't do much about MMC's ops errors; we hope next refresh
- * will kind of handle it.
- *
- * NOTE: @wusbhc->mutex is locked
- */
-static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
-{
-       struct device *dev = wusbhc->dev;
-       unsigned cnt;
-       struct wusb_dev *wusb_dev;
-       struct wusb_port *wusb_port;
-       struct wuie_keep_alive *ie = &wusbhc->keep_alive_ie;
-       unsigned keep_alives, old_keep_alives;
-
-       old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr);
-       keep_alives = 0;
-       for (cnt = 0;
-            keep_alives < WUIE_ELT_MAX && cnt < wusbhc->ports_max;
-            cnt++) {
-               unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout);
-
-               wusb_port = wusb_port_by_idx(wusbhc, cnt);
-               wusb_dev = wusb_port->wusb_dev;
-
-               if (wusb_dev == NULL)
-                       continue;
-               if (wusb_dev->usb_dev == NULL)
-                       continue;
-
-               if (time_after(jiffies, wusb_dev->entry_ts + tt)) {
-                       dev_err(dev, "KEEPALIVE: device %u timed out\n",
-                               wusb_dev->addr);
-                       __wusbhc_dev_disconnect(wusbhc, wusb_port);
-               } else if (time_after(jiffies, wusb_dev->entry_ts + tt/3)) {
-                       /* Approaching timeout cut off, need to refresh */
-                       ie->bDeviceAddress[keep_alives++] = wusb_dev->addr;
-               }
-       }
-       if (keep_alives & 0x1)  /* pad to even number ([WUSB] section 7.5.9) */
-               ie->bDeviceAddress[keep_alives++] = 0x7f;
-       ie->hdr.bLength = sizeof(ie->hdr) +
-               keep_alives*sizeof(ie->bDeviceAddress[0]);
-       if (keep_alives > 0)
-               wusbhc_mmcie_set(wusbhc, 10, 5, &ie->hdr);
-       else if (old_keep_alives != 0)
-               wusbhc_mmcie_rm(wusbhc, &ie->hdr);
-}
-
-/*
- * Do a run through all devices checking for timeouts
- */
-static void wusbhc_keep_alive_run(struct work_struct *ws)
-{
-       struct delayed_work *dw = to_delayed_work(ws);
-       struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer);
-
-       mutex_lock(&wusbhc->mutex);
-       __wusbhc_keep_alive(wusbhc);
-       mutex_unlock(&wusbhc->mutex);
-
-       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
-                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
-}
-
-/*
- * Find the wusb_dev from its device address.
- *
- * The device can be found directly from the address (see
- * wusb_cack_add() for where the device address is set to port_idx
- * +2), except when the address is zero.
- */
-static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
-{
-       int p;
-
-       if (addr == 0xff) /* unconnected */
-               return NULL;
-
-       if (addr > 0) {
-               int port = (addr & ~0x80) - 2;
-               if (port < 0 || port >= wusbhc->ports_max)
-                       return NULL;
-               return wusb_port_by_idx(wusbhc, port)->wusb_dev;
-       }
-
-       /* Look for the device with address 0. */
-       for (p = 0; p < wusbhc->ports_max; p++) {
-               struct wusb_dev *wusb_dev = wusb_port_by_idx(wusbhc, p)->wusb_dev;
-               if (wusb_dev && wusb_dev->addr == addr)
-                       return wusb_dev;
-       }
-       return NULL;
-}
-
-/*
- * Handle a DN_Alive notification (WUSB1.0[7.6.1])
- *
- * This just updates the device activity timestamp and then refreshes
- * the keep alive IE.
- *
- * @wusbhc shall be referenced and unlocked
- */
-static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)
-{
-       struct wusb_dev *wusb_dev;
-
-       mutex_lock(&wusbhc->mutex);
-       wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
-       if (wusb_dev == NULL) {
-               dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n",
-                       srcaddr);
-       } else {
-               wusb_dev->entry_ts = jiffies;
-               __wusbhc_keep_alive(wusbhc);
-       }
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/*
- * Handle a DN_Connect notification (WUSB1.0[7.6.1])
- *
- * @wusbhc
- * @pkt_hdr
- * @size:    Size of the buffer where the notification resides; if the
- *           notification data suggests there should be more data than
- *           available, an error will be signaled and the whole buffer
- *           consumed.
- *
- * @wusbhc->mutex shall be held
- */
-static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
-                                    struct wusb_dn_hdr *dn_hdr,
-                                    size_t size)
-{
-       struct device *dev = wusbhc->dev;
-       struct wusb_dn_connect *dnc;
-       char pr_cdid[WUSB_CKHDID_STRSIZE];
-       static const char *beacon_behaviour[] = {
-               "reserved",
-               "self-beacon",
-               "directed-beacon",
-               "no-beacon"
-       };
-
-       if (size < sizeof(*dnc)) {
-               dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n",
-                       size, sizeof(*dnc));
-               return;
-       }
-
-       dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr);
-       sprintf(pr_cdid, "%16ph", dnc->CDID.data);
-       dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n",
-                pr_cdid,
-                wusb_dn_connect_prev_dev_addr(dnc),
-                beacon_behaviour[wusb_dn_connect_beacon_behavior(dnc)],
-                wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect");
-       /* ACK the connect */
-       wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid);
-}
-
-/*
- * Handle a DN_Disconnect notification (WUSB1.0[7.6.1])
- *
- * Device is going down -- do the disconnect.
- *
- * @wusbhc shall be referenced and unlocked
- */
-static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)
-{
-       struct device *dev = wusbhc->dev;
-       struct wusb_dev *wusb_dev;
-
-       mutex_lock(&wusbhc->mutex);
-       wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
-       if (wusb_dev == NULL) {
-               dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n",
-                       srcaddr);
-       } else {
-               dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n",
-                       wusb_dev->addr);
-               __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc,
-                       wusb_dev->port_idx));
-       }
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/*
- * Handle a Device Notification coming a host
- *
- * The Device Notification comes from a host (HWA, DWA or WHCI)
- * wrapped in a set of headers. Somebody else has peeled off those
- * headers for us and we just get one Device Notifications.
- *
- * Invalid DNs (e.g., too short) are discarded.
- *
- * @wusbhc shall be referenced
- *
- * FIXMES:
- *  - implement priorities as in WUSB1.0[Table 7-55]?
- */
-void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
-                     struct wusb_dn_hdr *dn_hdr, size_t size)
-{
-       struct device *dev = wusbhc->dev;
-
-       if (size < sizeof(struct wusb_dn_hdr)) {
-               dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
-                       (int)size, (int)sizeof(struct wusb_dn_hdr));
-               return;
-       }
-       switch (dn_hdr->bType) {
-       case WUSB_DN_CONNECT:
-               wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
-               break;
-       case WUSB_DN_ALIVE:
-               wusbhc_handle_dn_alive(wusbhc, srcaddr);
-               break;
-       case WUSB_DN_DISCONNECT:
-               wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
-               break;
-       case WUSB_DN_MASAVAILCHANGED:
-       case WUSB_DN_RWAKE:
-       case WUSB_DN_SLEEP:
-               /* FIXME: handle these DNs. */
-               break;
-       case WUSB_DN_EPRDY:
-               /* The hardware handles these. */
-               break;
-       default:
-               dev_warn(dev, "unknown DN %u (%d octets) from %u\n",
-                        dn_hdr->bType, (int)size, srcaddr);
-       }
-}
-EXPORT_SYMBOL_GPL(wusbhc_handle_dn);
-
-/*
- * Disconnect a WUSB device from a the cluster
- *
- * @wusbhc
- * @port     Fake port where the device is (wusbhc index, not USB port number).
- *
- * In Wireless USB, a disconnect is basically telling the device he is
- * being disconnected and forgetting about him.
- *
- * We send the device a Device Disconnect IE (WUSB1.0[7.5.11]) for 100
- * ms and then keep going.
- *
- * We don't do much in case of error; we always pretend we disabled
- * the port and disconnected the device. If physically the request
- * didn't get there (many things can fail in the way there), the stack
- * will reject the device's communication attempts.
- *
- * @wusbhc should be refcounted and locked
- */
-void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx)
-{
-       int result;
-       struct device *dev = wusbhc->dev;
-       struct wusb_dev *wusb_dev;
-       struct wuie_disconnect *ie;
-
-       wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
-       if (wusb_dev == NULL) {
-               /* reset no device? ignore */
-               dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n",
-                       port_idx);
-               return;
-       }
-       __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
-
-       ie = kzalloc(sizeof(*ie), GFP_KERNEL);
-       if (ie == NULL)
-               return;
-       ie->hdr.bLength = sizeof(*ie);
-       ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT;
-       ie->bDeviceAddress = wusb_dev->addr;
-       result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr);
-       if (result < 0)
-               dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result);
-       else {
-               /* At least 6 MMCs, assuming at least 1 MMC per zone. */
-               msleep(7*4);
-               wusbhc_mmcie_rm(wusbhc, &ie->hdr);
-       }
-       kfree(ie);
-}
-
-/*
- * Walk over the BOS descriptor, verify and grok it
- *
- * @usb_dev: referenced
- * @wusb_dev: referenced and unlocked
- *
- * The BOS descriptor is defined at WUSB1.0[7.4.1], and it defines a
- * "flexible" way to wrap all kinds of descriptors inside an standard
- * descriptor (wonder why they didn't use normal descriptors,
- * btw). Not like they lack code.
- *
- * At the end we go to look for the WUSB Device Capabilities
- * (WUSB1.0[7.4.1.1]) that is wrapped in a device capability descriptor
- * that is part of the BOS descriptor set. That tells us what does the
- * device support (dual role, beacon type, UWB PHY rates).
- */
-static int wusb_dev_bos_grok(struct usb_device *usb_dev,
-                            struct wusb_dev *wusb_dev,
-                            struct usb_bos_descriptor *bos, size_t desc_size)
-{
-       ssize_t result;
-       struct device *dev = &usb_dev->dev;
-       void *itr, *top;
-
-       /* Walk over BOS capabilities, verify them */
-       itr = (void *)bos + sizeof(*bos);
-       top = itr + desc_size - sizeof(*bos);
-       while (itr < top) {
-               struct usb_dev_cap_header *cap_hdr = itr;
-               size_t cap_size;
-               u8 cap_type;
-               if (top - itr < sizeof(*cap_hdr)) {
-                       dev_err(dev, "Device BUG? premature end of BOS header "
-                               "data [offset 0x%02x]: only %zu bytes left\n",
-                               (int)(itr - (void *)bos), top - itr);
-                       result = -ENOSPC;
-                       goto error_bad_cap;
-               }
-               cap_size = cap_hdr->bLength;
-               cap_type = cap_hdr->bDevCapabilityType;
-               if (cap_size == 0)
-                       break;
-               if (cap_size > top - itr) {
-                       dev_err(dev, "Device BUG? premature end of BOS data "
-                               "[offset 0x%02x cap %02x %zu bytes]: "
-                               "only %zu bytes left\n",
-                               (int)(itr - (void *)bos),
-                               cap_type, cap_size, top - itr);
-                       result = -EBADF;
-                       goto error_bad_cap;
-               }
-               switch (cap_type) {
-               case USB_CAP_TYPE_WIRELESS_USB:
-                       if (cap_size != sizeof(*wusb_dev->wusb_cap_descr))
-                               dev_err(dev, "Device BUG? WUSB Capability "
-                                       "descriptor is %zu bytes vs %zu "
-                                       "needed\n", cap_size,
-                                       sizeof(*wusb_dev->wusb_cap_descr));
-                       else
-                               wusb_dev->wusb_cap_descr = itr;
-                       break;
-               default:
-                       dev_err(dev, "BUG? Unknown BOS capability 0x%02x "
-                               "(%zu bytes) at offset 0x%02x\n", cap_type,
-                               cap_size, (int)(itr - (void *)bos));
-               }
-               itr += cap_size;
-       }
-       result = 0;
-error_bad_cap:
-       return result;
-}
-
-/*
- * Add information from the BOS descriptors to the device
- *
- * @usb_dev: referenced
- * @wusb_dev: referenced and unlocked
- *
- * So what we do is we alloc a space for the BOS descriptor of 64
- * bytes; read the first four bytes which include the wTotalLength
- * field (WUSB1.0[T7-26]) and if it fits in those 64 bytes, read the
- * whole thing. If not we realloc to that size.
- *
- * Then we call the groking function, that will fill up
- * wusb_dev->wusb_cap_descr, which is what we'll need later on.
- */
-static int wusb_dev_bos_add(struct usb_device *usb_dev,
-                           struct wusb_dev *wusb_dev)
-{
-       ssize_t result;
-       struct device *dev = &usb_dev->dev;
-       struct usb_bos_descriptor *bos;
-       size_t alloc_size = 32, desc_size = 4;
-
-       bos = kmalloc(alloc_size, GFP_KERNEL);
-       if (bos == NULL)
-               return -ENOMEM;
-       result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
-       if (result < 4) {
-               dev_err(dev, "Can't get BOS descriptor or too short: %zd\n",
-                       result);
-               goto error_get_descriptor;
-       }
-       desc_size = le16_to_cpu(bos->wTotalLength);
-       if (desc_size >= alloc_size) {
-               kfree(bos);
-               alloc_size = desc_size;
-               bos = kmalloc(alloc_size, GFP_KERNEL);
-               if (bos == NULL)
-                       return -ENOMEM;
-       }
-       result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
-       if (result < 0 || result != desc_size) {
-               dev_err(dev, "Can't get  BOS descriptor or too short (need "
-                       "%zu bytes): %zd\n", desc_size, result);
-               goto error_get_descriptor;
-       }
-       if (result < sizeof(*bos)
-           || le16_to_cpu(bos->wTotalLength) != desc_size) {
-               dev_err(dev, "Can't get  BOS descriptor or too short (need "
-                       "%zu bytes): %zd\n", desc_size, result);
-               goto error_get_descriptor;
-       }
-
-       result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result);
-       if (result < 0)
-               goto error_bad_bos;
-       wusb_dev->bos = bos;
-       return 0;
-
-error_bad_bos:
-error_get_descriptor:
-       kfree(bos);
-       wusb_dev->wusb_cap_descr = NULL;
-       return result;
-}
-
-static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev)
-{
-       kfree(wusb_dev->bos);
-       wusb_dev->wusb_cap_descr = NULL;
-};
-
-/*
- * USB stack's device addition Notifier Callback
- *
- * Called from drivers/usb/core/hub.c when a new device is added; we
- * use this hook to perform certain WUSB specific setup work on the
- * new device. As well, it is the first time we can connect the
- * wusb_dev and the usb_dev. So we note it down in wusb_dev and take a
- * reference that we'll drop.
- *
- * First we need to determine if the device is a WUSB device (else we
- * ignore it). For that we use the speed setting (USB_SPEED_WIRELESS)
- * [FIXME: maybe we'd need something more definitive]. If so, we track
- * it's usb_busd and from there, the WUSB HC.
- *
- * Because all WUSB HCs are contained in a 'struct wusbhc', voila, we
- * get the wusbhc for the device.
- *
- * We have a reference on @usb_dev (as we are called at the end of its
- * enumeration).
- *
- * NOTE: @usb_dev locked
- */
-static void wusb_dev_add_ncb(struct usb_device *usb_dev)
-{
-       int result = 0;
-       struct wusb_dev *wusb_dev;
-       struct wusbhc *wusbhc;
-       struct device *dev = &usb_dev->dev;
-       u8 port_idx;
-
-       if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
-               return;         /* skip non wusb and wusb RHs */
-
-       usb_set_device_state(usb_dev, USB_STATE_UNAUTHENTICATED);
-
-       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
-       if (wusbhc == NULL)
-               goto error_nodev;
-       mutex_lock(&wusbhc->mutex);
-       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
-       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
-       mutex_unlock(&wusbhc->mutex);
-       if (wusb_dev == NULL)
-               goto error_nodev;
-       wusb_dev->usb_dev = usb_get_dev(usb_dev);
-       usb_dev->wusb_dev = wusb_dev_get(wusb_dev);
-       result = wusb_dev_sec_add(wusbhc, usb_dev, wusb_dev);
-       if (result < 0) {
-               dev_err(dev, "Cannot enable security: %d\n", result);
-               goto error_sec_add;
-       }
-       /* Now query the device for it's BOS and attach it to wusb_dev */
-       result = wusb_dev_bos_add(usb_dev, wusb_dev);
-       if (result < 0) {
-               dev_err(dev, "Cannot get BOS descriptors: %d\n", result);
-               goto error_bos_add;
-       }
-       result = wusb_dev_sysfs_add(wusbhc, usb_dev, wusb_dev);
-       if (result < 0)
-               goto error_add_sysfs;
-out:
-       wusb_dev_put(wusb_dev);
-       wusbhc_put(wusbhc);
-error_nodev:
-       return;
-
-error_add_sysfs:
-       wusb_dev_bos_rm(wusb_dev);
-error_bos_add:
-       wusb_dev_sec_rm(wusb_dev);
-error_sec_add:
-       mutex_lock(&wusbhc->mutex);
-       __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
-       mutex_unlock(&wusbhc->mutex);
-       goto out;
-}
-
-/*
- * Undo all the steps done at connection by the notifier callback
- *
- * NOTE: @usb_dev locked
- */
-static void wusb_dev_rm_ncb(struct usb_device *usb_dev)
-{
-       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
-
-       if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
-               return;         /* skip non wusb and wusb RHs */
-
-       wusb_dev_sysfs_rm(wusb_dev);
-       wusb_dev_bos_rm(wusb_dev);
-       wusb_dev_sec_rm(wusb_dev);
-       wusb_dev->usb_dev = NULL;
-       usb_dev->wusb_dev = NULL;
-       wusb_dev_put(wusb_dev);
-       usb_put_dev(usb_dev);
-}
-
-/*
- * Handle notifications from the USB stack (notifier call back)
- *
- * This is called when the USB stack does a
- * usb_{bus,device}_{add,remove}() so we can do WUSB specific
- * handling. It is called with [for the case of
- * USB_DEVICE_{ADD,REMOVE} with the usb_dev locked.
- */
-int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
-                void *priv)
-{
-       int result = NOTIFY_OK;
-
-       switch (val) {
-       case USB_DEVICE_ADD:
-               wusb_dev_add_ncb(priv);
-               break;
-       case USB_DEVICE_REMOVE:
-               wusb_dev_rm_ncb(priv);
-               break;
-       case USB_BUS_ADD:
-               /* ignore (for now) */
-       case USB_BUS_REMOVE:
-               break;
-       default:
-               WARN_ON(1);
-               result = NOTIFY_BAD;
-       }
-       return result;
-}
-
-/*
- * Return a referenced wusb_dev given a @wusbhc and @usb_dev
- */
-struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *wusbhc,
-                                          struct usb_device *usb_dev)
-{
-       struct wusb_dev *wusb_dev;
-       u8 port_idx;
-
-       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
-       BUG_ON(port_idx > wusbhc->ports_max);
-       wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
-       if (wusb_dev != NULL)           /* ops, device is gone */
-               wusb_dev_get(wusb_dev);
-       return wusb_dev;
-}
-EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev);
-
-void wusb_dev_destroy(struct kref *_wusb_dev)
-{
-       struct wusb_dev *wusb_dev = container_of(_wusb_dev, struct wusb_dev, refcnt);
-
-       list_del_init(&wusb_dev->cack_node);
-       wusb_dev_free(wusb_dev);
-}
-EXPORT_SYMBOL_GPL(wusb_dev_destroy);
-
-/*
- * Create all the device connect handling infrastructure
- *
- * This is basically the device info array, Connect Acknowledgement
- * (cack) lists, keep-alive timers (and delayed work thread).
- */
-int wusbhc_devconnect_create(struct wusbhc *wusbhc)
-{
-       wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE;
-       wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr);
-       INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run);
-
-       wusbhc->cack_ie.hdr.bIEIdentifier = WUIE_ID_CONNECTACK;
-       wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr);
-       INIT_LIST_HEAD(&wusbhc->cack_list);
-
-       return 0;
-}
-
-/*
- * Release all resources taken by the devconnect stuff
- */
-void wusbhc_devconnect_destroy(struct wusbhc *wusbhc)
-{
-       /* no op */
-}
-
-/*
- * wusbhc_devconnect_start - start accepting device connections
- * @wusbhc: the WUSB HC
- *
- * Sets the Host Info IE to accept all new connections.
- *
- * FIXME: This also enables the keep alives but this is not necessary
- * until there are connected and authenticated devices.
- */
-int wusbhc_devconnect_start(struct wusbhc *wusbhc)
-{
-       struct device *dev = wusbhc->dev;
-       struct wuie_host_info *hi;
-       int result;
-
-       hi = kzalloc(sizeof(*hi), GFP_KERNEL);
-       if (hi == NULL)
-               return -ENOMEM;
-
-       hi->hdr.bLength       = sizeof(*hi);
-       hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO;
-       hi->attributes        = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL);
-       hi->CHID              = wusbhc->chid;
-       result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr);
-       if (result < 0) {
-               dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result);
-               goto error_mmcie_set;
-       }
-       wusbhc->wuie_host_info = hi;
-
-       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
-                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
-
-       return 0;
-
-error_mmcie_set:
-       kfree(hi);
-       return result;
-}
-
-/*
- * wusbhc_devconnect_stop - stop managing connected devices
- * @wusbhc: the WUSB HC
- *
- * Disconnects any devices still connected, stops the keep alives and
- * removes the Host Info IE.
- */
-void wusbhc_devconnect_stop(struct wusbhc *wusbhc)
-{
-       int i;
-
-       mutex_lock(&wusbhc->mutex);
-       for (i = 0; i < wusbhc->ports_max; i++) {
-               if (wusbhc->port[i].wusb_dev)
-                       __wusbhc_dev_disconnect(wusbhc, &wusbhc->port[i]);
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       cancel_delayed_work_sync(&wusbhc->keep_alive_timer);
-       wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr);
-       kfree(wusbhc->wuie_host_info);
-       wusbhc->wuie_host_info = NULL;
-}
-
-/*
- * wusb_set_dev_addr - set the WUSB device address used by the host
- * @wusbhc: the WUSB HC the device is connect to
- * @wusb_dev: the WUSB device
- * @addr: new device address
- */
-int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, u8 addr)
-{
-       int result;
-
-       wusb_dev->addr = addr;
-       result = wusbhc->dev_info_set(wusbhc, wusb_dev);
-       if (result < 0)
-               dev_err(wusbhc->dev, "device %d: failed to set device "
-                       "address\n", wusb_dev->port_idx);
-       else
-               dev_info(wusbhc->dev, "device %d: %s addr %u\n",
-                        wusb_dev->port_idx,
-                        (addr & WUSB_DEV_ADDR_UNAUTH) ? "unauth" : "auth",
-                        wusb_dev->addr);
-
-       return result;
-}
diff --git a/drivers/staging/wusbcore/host/Kconfig b/drivers/staging/wusbcore/host/Kconfig
deleted file mode 100644 (file)
index 9a73f93..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-config USB_WHCI_HCD
-       tristate "Wireless USB Host Controller Interface (WHCI) driver"
-       depends on USB_PCI && USB && UWB
-       select USB_WUSB
-       select UWB_WHCI
-       help
-         A driver for PCI-based Wireless USB Host Controllers that are
-         compliant with the WHCI specification.
-
-         To compile this driver a module, choose M here: the module
-         will be called "whci-hcd".
-
-config USB_HWA_HCD
-       tristate "Host Wire Adapter (HWA) driver"
-       depends on USB && UWB
-       select USB_WUSB
-       select UWB_HWA
-       help
-         This driver enables you to connect Wireless USB devices to
-         your system using a Host Wire Adaptor USB dongle. This is an
-         UWB Radio Controller and WUSB Host Controller connected to
-         your machine via USB (specified in WUSB1.0).
-
-         To compile this driver a module, choose M here: the module
-         will be called "hwa-hc".
-
diff --git a/drivers/staging/wusbcore/host/Makefile b/drivers/staging/wusbcore/host/Makefile
deleted file mode 100644 (file)
index d65ee8a..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_USB_WHCI_HCD)     += whci/
-obj-$(CONFIG_USB_HWA_HCD)      += hwa-hc.o
diff --git a/drivers/staging/wusbcore/host/hwa-hc.c b/drivers/staging/wusbcore/host/hwa-hc.c
deleted file mode 100644 (file)
index 8d959e9..0000000
+++ /dev/null
@@ -1,875 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Host Wire Adapter:
- * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * The HWA driver is a simple layer that forwards requests to the WAHC
- * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host
- * Controller) layers.
- *
- * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB
- * Host Controller that is connected to your system via USB (a USB
- * dongle that implements a USB host...). There is also a Device Wired
- * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for
- * transferring data (it is after all a USB host connected via
- * Wireless USB), we have a common layer called Wire Adapter Host
- * Controller that does all the hard work. The WUSBHC (Wireless USB
- * Host Controller) is the part common to WUSB Host Controllers, the
- * HWA and the PCI-based one, that is implemented following the WHCI
- * spec. All these layers are implemented in ../wusbcore.
- *
- * The main functions are hwahc_op_urb_{en,de}queue(), that pass the
- * job of converting a URB to a Wire Adapter
- *
- * Entry points:
- *
- *   hwahc_driver_*()   Driver initialization, registration and
- *                      teardown.
- *
- *   hwahc_probe()     New device came up, create an instance for
- *                      it [from device enumeration].
- *
- *   hwahc_disconnect()        Remove device instance [from device
- *                      enumeration].
- *
- *   [__]hwahc_op_*()   Host-Wire-Adaptor specific functions for
- *                      starting/stopping/etc (some might be made also
- *                      DWA).
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
-#include <linux/completion.h>
-#include "../wa-hc.h"
-#include "../wusbhc.h"
-
-struct hwahc {
-       struct wusbhc wusbhc;   /* has to be 1st */
-       struct wahc wa;
-};
-
-/*
- * FIXME should be wusbhc
- *
- * NOTE: we need to cache the Cluster ID because later...there is no
- *       way to get it :)
- */
-static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id)
-{
-       int result;
-       struct wusbhc *wusbhc = &hwahc->wusbhc;
-       struct wahc *wa = &hwahc->wa;
-       struct device *dev = &wa->usb_iface->dev;
-
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_CLUSTER_ID,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       cluster_id,
-                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n",
-                       cluster_id, result);
-       else
-               wusbhc->cluster_id = cluster_id;
-       dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id);
-       return result;
-}
-
-static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-
-       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_NUM_DNTS,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       interval << 8 | slots,
-                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Reset a WUSB host controller and wait for it to complete doing it.
- *
- * @usb_hcd:   Pointer to WUSB Host Controller instance.
- *
- */
-static int hwahc_op_reset(struct usb_hcd *usb_hcd)
-{
-       int result;
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct device *dev = &hwahc->wa.usb_iface->dev;
-
-       mutex_lock(&wusbhc->mutex);
-       wa_nep_disarm(&hwahc->wa);
-       result = __wa_set_feature(&hwahc->wa, WA_RESET);
-       if (result < 0) {
-               dev_err(dev, "error commanding HC to reset: %d\n", result);
-               goto error_unlock;
-       }
-       result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0);
-       if (result < 0) {
-               dev_err(dev, "error waiting for HC to reset: %d\n", result);
-               goto error_unlock;
-       }
-error_unlock:
-       mutex_unlock(&wusbhc->mutex);
-       return result;
-}
-
-/*
- * FIXME: break this function up
- */
-static int hwahc_op_start(struct usb_hcd *usb_hcd)
-{
-       u8 addr;
-       int result;
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       result = -ENOSPC;
-       mutex_lock(&wusbhc->mutex);
-       addr = wusb_cluster_id_get();
-       if (addr == 0)
-               goto error_cluster_id_get;
-       result = __hwahc_set_cluster_id(hwahc, addr);
-       if (result < 0)
-               goto error_set_cluster_id;
-
-       usb_hcd->uses_new_polling = 1;
-       set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
-       usb_hcd->state = HC_STATE_RUNNING;
-
-       /*
-        * prevent USB core from suspending the root hub since
-        * bus_suspend and bus_resume are not yet supported.
-        */
-       pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev);
-
-       result = 0;
-out:
-       mutex_unlock(&wusbhc->mutex);
-       return result;
-
-error_set_cluster_id:
-       wusb_cluster_id_put(addr);
-error_cluster_id_get:
-       goto out;
-
-}
-
-/*
- * No need to abort pipes, as when this is called, all the children
- * has been disconnected and that has done it [through
- * usb_disable_interface() -> usb_disable_endpoint() ->
- * hwahc_op_ep_disable() - >rpipe_ep_disable()].
- */
-static void hwahc_op_stop(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-
-       mutex_lock(&wusbhc->mutex);
-       wusb_cluster_id_put(wusbhc->cluster_id);
-       mutex_unlock(&wusbhc->mutex);
-}
-
-static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-
-       /*
-        * We cannot query the HWA for the WUSB time since that requires sending
-        * a synchronous URB and this function can be called in_interrupt.
-        * Instead, query the USB frame number for our parent and use that.
-        */
-       return usb_get_current_frame_number(wa->usb_dev);
-}
-
-static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
-                               gfp_t gfp)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp);
-}
-
-static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb,
-                               int status)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       return wa_urb_dequeue(&hwahc->wa, urb, status);
-}
-
-/*
- * Release resources allocated for an endpoint
- *
- * If there is an associated rpipe to this endpoint, go ahead and put it.
- */
-static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd,
-                                     struct usb_host_endpoint *ep)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       rpipe_ep_disable(&hwahc->wa, ep);
-}
-
-static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
-{
-       int result;
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct device *dev = &hwahc->wa.usb_iface->dev;
-
-       result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
-       if (result < 0) {
-               dev_err(dev, "error commanding HC to start: %d\n", result);
-               goto error_stop;
-       }
-       result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
-       if (result < 0) {
-               dev_err(dev, "error waiting for HC to start: %d\n", result);
-               goto error_stop;
-       }
-       result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "cannot listen to notifications: %d\n", result);
-               goto error_stop;
-       }
-       /*
-        * If WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS is set,
-        *  disable transfer notifications.
-        */
-       if (hwahc->wa.quirks &
-               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS) {
-               struct usb_host_interface *cur_altsetting =
-                       hwahc->wa.usb_iface->cur_altsetting;
-
-               result = usb_control_msg(hwahc->wa.usb_dev,
-                               usb_sndctrlpipe(hwahc->wa.usb_dev, 0),
-                               WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS,
-                               USB_DIR_OUT | USB_TYPE_VENDOR |
-                                       USB_RECIP_INTERFACE,
-                               WA_REQ_ALEREON_FEATURE_SET,
-                               cur_altsetting->desc.bInterfaceNumber,
-                               NULL, 0,
-                               USB_CTRL_SET_TIMEOUT);
-               /*
-                * If we successfully sent the control message, start DTI here
-                * because no transfer notifications will be received which is
-                * where DTI is normally started.
-                */
-               if (result == 0)
-                       result = wa_dti_start(&hwahc->wa);
-               else
-                       result = 0;     /* OK.  Continue normally. */
-
-               if (result < 0) {
-                       dev_err(dev, "cannot start DTI: %d\n", result);
-                       goto error_dti_start;
-               }
-       }
-
-       return result;
-
-error_dti_start:
-       wa_nep_disarm(&hwahc->wa);
-error_stop:
-       __wa_clear_feature(&hwahc->wa, WA_ENABLE);
-       return result;
-}
-
-static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       int ret;
-
-       ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                             WUSB_REQ_CHAN_STOP,
-                             USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                             delay * 1000,
-                             iface_no,
-                             NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (ret == 0)
-               msleep(delay);
-
-       wa_nep_disarm(&hwahc->wa);
-       __wa_stop(&hwahc->wa);
-}
-
-/*
- * Set the UWB MAS allocation for the WUSB cluster
- *
- * @stream_index: stream to use (-1 for cancelling the allocation)
- * @mas: mas bitmap to use
- */
-static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index,
-                             const struct uwb_mas_bm *mas)
-{
-       int result;
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       struct device *dev = &wa->usb_iface->dev;
-       u8 mas_le[UWB_NUM_MAS/8];
-
-       /* Set the stream index */
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_STREAM_IDX,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       stream_index,
-                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Cannot set WUSB stream index: %d\n", result);
-               goto out;
-       }
-       uwb_mas_bm_copy_le(mas_le, mas);
-       /* Set the MAS allocation */
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_WUSB_MAS,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       mas_le, 32, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result);
-out:
-       return result;
-}
-
-/*
- * Add an IE to the host's MMC
- *
- * @interval:    See WUSB1.0[8.5.3.1]
- * @repeat_cnt:  See WUSB1.0[8.5.3.1]
- * @handle:      See WUSB1.0[8.5.3.1]
- * @wuie:        Pointer to the header of the WUSB IE data to add.
- *               MUST BE allocated in a kmalloc buffer (no stack or
- *               vmalloc).
- *
- * NOTE: the format of the WUSB IEs for MMCs are different to the
- *       normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length +
- *       Id in WUSB IEs). Standards...you gotta love'em.
- */
-static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval,
-                               u8 repeat_cnt, u8 handle,
-                               struct wuie_hdr *wuie)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-
-       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_ADD_MMC_IE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       interval << 8 | repeat_cnt,
-                       handle << 8 | iface_no,
-                       wuie, wuie->bLength, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Remove an IE to the host's MMC
- *
- * @handle:      See WUSB1.0[8.5.3.1]
- */
-static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_REMOVE_MMC_IE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0, handle << 8 | iface_no,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Update device information for a given fake port
- *
- * @port_idx: Fake port to which device is connected (wusbhc index, not
- *            USB port number).
- */
-static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc,
-                                  struct wusb_dev *wusb_dev)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       struct hwa_dev_info *dev_info;
-       int ret;
-
-       /* fill out the Device Info buffer and send it */
-       dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL);
-       if (!dev_info)
-               return -ENOMEM;
-       uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability,
-                          &wusb_dev->availability);
-       dev_info->bDeviceAddress = wusb_dev->addr;
-
-       /*
-        * If the descriptors haven't been read yet, use a default PHY
-        * rate of 53.3 Mbit/s only.  The correct value will be used
-        * when this will be called again as part of the
-        * authentication process (which occurs after the descriptors
-        * have been read).
-        */
-       if (wusb_dev->wusb_cap_descr)
-               dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates;
-       else
-               dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53);
-
-       ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_DEV_INFO,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0, wusb_dev->port_idx << 8 | iface_no,
-                       dev_info, sizeof(struct hwa_dev_info),
-                       USB_CTRL_SET_TIMEOUT);
-       kfree(dev_info);
-       return ret;
-}
-
-/*
- * Set host's idea of which encryption (and key) method to use when
- * talking to ad evice on a given port.
- *
- * If key is NULL, it means disable encryption for that "virtual port"
- * (used when we disconnect).
- */
-static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
-                              const void *key, size_t key_size,
-                              u8 key_idx)
-{
-       int result = -ENOMEM;
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       struct usb_key_descriptor *keyd;
-       size_t keyd_len;
-
-       keyd_len = sizeof(*keyd) + key_size;
-       keyd = kzalloc(keyd_len, GFP_KERNEL);
-       if (keyd == NULL)
-               return -ENOMEM;
-
-       keyd->bLength = keyd_len;
-       keyd->bDescriptorType = USB_DT_KEY;
-       keyd->tTKID[0] = (tkid >>  0) & 0xff;
-       keyd->tTKID[1] = (tkid >>  8) & 0xff;
-       keyd->tTKID[2] = (tkid >> 16) & 0xff;
-       memcpy(keyd->bKeyData, key, key_size);
-
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       USB_REQ_SET_DESCRIPTOR,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       USB_DT_KEY << 8 | key_idx,
-                       port_idx << 8 | iface_no,
-                       keyd, keyd_len, USB_CTRL_SET_TIMEOUT);
-
-       kzfree(keyd); /* clear keys etc. */
-       return result;
-}
-
-/*
- * Set host's idea of which encryption (and key) method to use when
- * talking to ad evice on a given port.
- *
- * If key is NULL, it means disable encryption for that "virtual port"
- * (used when we disconnect).
- */
-static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
-                             const void *key, size_t key_size)
-{
-       int result = -ENOMEM;
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       u8 encryption_value;
-
-       /* Tell the host which key to use to talk to the device */
-       if (key) {
-               u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK,
-                                           WUSB_KEY_INDEX_ORIGINATOR_HOST);
-
-               result = __hwahc_dev_set_key(wusbhc, port_idx, tkid,
-                                            key, key_size, key_idx);
-               if (result < 0)
-                       goto error_set_key;
-               encryption_value = wusbhc->ccm1_etd->bEncryptionValue;
-       } else {
-               /* FIXME: this should come from wusbhc->etd[UNSECURE].value */
-               encryption_value = 0;
-       }
-
-       /* Set the encryption type for communicating with the device */
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       USB_REQ_SET_ENCRYPTION,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       encryption_value, port_idx << 8 | iface_no,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(wusbhc->dev, "Can't set host's WUSB encryption for "
-                       "port index %u to %s (value %d): %d\n", port_idx,
-                       wusb_et_name(wusbhc->ccm1_etd->bEncryptionType),
-                       wusbhc->ccm1_etd->bEncryptionValue, result);
-error_set_key:
-       return result;
-}
-
-/*
- * Set host's GTK key
- */
-static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid,
-                             const void *key, size_t key_size)
-{
-       u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK,
-                                   WUSB_KEY_INDEX_ORIGINATOR_HOST);
-
-       return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx);
-}
-
-/*
- * Get the Wire Adapter class-specific descriptor
- *
- * NOTE: this descriptor comes with the big bundled configuration
- *       descriptor that includes the interfaces' and endpoints', so
- *       we just look for it in the cached copy kept by the USB stack.
- *
- * NOTE2: We convert LE fields to CPU order.
- */
-static int wa_fill_descr(struct wahc *wa)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-       char *itr;
-       struct usb_device *usb_dev = wa->usb_dev;
-       struct usb_descriptor_header *hdr;
-       struct usb_wa_descriptor *wa_descr;
-       size_t itr_size, actconfig_idx;
-
-       actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
-                       sizeof(usb_dev->config[0]);
-       itr = usb_dev->rawdescriptors[actconfig_idx];
-       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
-       while (itr_size >= sizeof(*hdr)) {
-               hdr = (struct usb_descriptor_header *) itr;
-               dev_dbg(dev, "Extra device descriptor: "
-                       "type %02x/%u bytes @ %zu (%zu left)\n",
-                       hdr->bDescriptorType, hdr->bLength,
-                       (itr - usb_dev->rawdescriptors[actconfig_idx]),
-                       itr_size);
-               if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER)
-                       goto found;
-               itr += hdr->bLength;
-               itr_size -= hdr->bLength;
-       }
-       dev_err(dev, "cannot find Wire Adapter Class descriptor\n");
-       return -ENODEV;
-
-found:
-       result = -EINVAL;
-       if (hdr->bLength > itr_size) {  /* is it available? */
-               dev_err(dev, "incomplete Wire Adapter Class descriptor "
-                       "(%zu bytes left, %u needed)\n",
-                       itr_size, hdr->bLength);
-               goto error;
-       }
-       if (hdr->bLength < sizeof(*wa->wa_descr)) {
-               dev_err(dev, "short Wire Adapter Class descriptor\n");
-               goto error;
-       }
-       wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr;
-       if (le16_to_cpu(wa_descr->bcdWAVersion) > 0x0100)
-               dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n",
-                        (le16_to_cpu(wa_descr->bcdWAVersion) & 0xff00) >> 8,
-                        le16_to_cpu(wa_descr->bcdWAVersion) & 0x00ff);
-       result = 0;
-error:
-       return result;
-}
-
-static const struct hc_driver hwahc_hc_driver = {
-       .description = "hwa-hcd",
-       .product_desc = "Wireless USB HWA host controller",
-       .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd),
-       .irq = NULL,                    /* FIXME */
-       .flags = HCD_USB25,
-       .reset = hwahc_op_reset,
-       .start = hwahc_op_start,
-       .stop = hwahc_op_stop,
-       .get_frame_number = hwahc_op_get_frame_number,
-       .urb_enqueue = hwahc_op_urb_enqueue,
-       .urb_dequeue = hwahc_op_urb_dequeue,
-       .endpoint_disable = hwahc_op_endpoint_disable,
-
-       .hub_status_data = wusbhc_rh_status_data,
-       .hub_control = wusbhc_rh_control,
-       .start_port_reset = wusbhc_rh_start_port_reset,
-};
-
-static int hwahc_security_create(struct hwahc *hwahc)
-{
-       int result;
-       struct wusbhc *wusbhc = &hwahc->wusbhc;
-       struct usb_device *usb_dev = hwahc->wa.usb_dev;
-       struct device *dev = &usb_dev->dev;
-       struct usb_security_descriptor *secd;
-       struct usb_encryption_descriptor *etd;
-       void *itr, *top;
-       size_t itr_size, needed, bytes;
-       u8 index;
-       char buf[64];
-
-       /* Find the host's security descriptors in the config descr bundle */
-       index = (usb_dev->actconfig - usb_dev->config) /
-               sizeof(usb_dev->config[0]);
-       itr = usb_dev->rawdescriptors[index];
-       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
-       top = itr + itr_size;
-       result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
-                       le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
-                       USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
-       if (result == -1) {
-               dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
-               return 0;
-       }
-       needed = sizeof(*secd);
-       if (top - (void *)secd < needed) {
-               dev_err(dev, "BUG? Not enough data to process security "
-                       "descriptor header (%zu bytes left vs %zu needed)\n",
-                       top - (void *) secd, needed);
-               return 0;
-       }
-       needed = le16_to_cpu(secd->wTotalLength);
-       if (top - (void *)secd < needed) {
-               dev_err(dev, "BUG? Not enough data to process security "
-                       "descriptors (%zu bytes left vs %zu needed)\n",
-                       top - (void *) secd, needed);
-               return 0;
-       }
-       /* Walk over the sec descriptors and store CCM1's on wusbhc */
-       itr = (void *) secd + sizeof(*secd);
-       top = (void *) secd + le16_to_cpu(secd->wTotalLength);
-       index = 0;
-       bytes = 0;
-       while (itr < top) {
-               etd = itr;
-               if (top - itr < sizeof(*etd)) {
-                       dev_err(dev, "BUG: bad host security descriptor; "
-                               "not enough data (%zu vs %zu left)\n",
-                               top - itr, sizeof(*etd));
-                       break;
-               }
-               if (etd->bLength < sizeof(*etd)) {
-                       dev_err(dev, "BUG: bad host encryption descriptor; "
-                               "descriptor is too short "
-                               "(%zu vs %zu needed)\n",
-                               (size_t)etd->bLength, sizeof(*etd));
-                       break;
-               }
-               itr += etd->bLength;
-               bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
-                                 "%s (0x%02x) ",
-                                 wusb_et_name(etd->bEncryptionType),
-                                 etd->bEncryptionValue);
-               wusbhc->ccm1_etd = etd;
-       }
-       dev_info(dev, "supported encryption types: %s\n", buf);
-       if (wusbhc->ccm1_etd == NULL) {
-               dev_err(dev, "E: host doesn't support CCM-1 crypto\n");
-               return 0;
-       }
-       /* Pretty print what we support */
-       return 0;
-}
-
-static void hwahc_security_release(struct hwahc *hwahc)
-{
-       /* nothing to do here so far... */
-}
-
-static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface,
-       kernel_ulong_t quirks)
-{
-       int result;
-       struct device *dev = &iface->dev;
-       struct wusbhc *wusbhc = &hwahc->wusbhc;
-       struct wahc *wa = &hwahc->wa;
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-
-       wa->usb_dev = usb_get_dev(usb_dev);     /* bind the USB device */
-       wa->usb_iface = usb_get_intf(iface);
-       wusbhc->dev = dev;
-       /* defer getting the uwb_rc handle until it is needed since it
-        * may not have been registered by the hwa_rc driver yet. */
-       wusbhc->uwb_rc = NULL;
-       result = wa_fill_descr(wa);     /* Get the device descriptor */
-       if (result < 0)
-               goto error_fill_descriptor;
-       if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) {
-               dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB "
-                       "adapter (%u ports)\n", wa->wa_descr->bNumPorts);
-               wusbhc->ports_max = USB_MAXCHILDREN;
-       } else {
-               wusbhc->ports_max = wa->wa_descr->bNumPorts;
-       }
-       wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs;
-       wusbhc->start = __hwahc_op_wusbhc_start;
-       wusbhc->stop = __hwahc_op_wusbhc_stop;
-       wusbhc->mmcie_add = __hwahc_op_mmcie_add;
-       wusbhc->mmcie_rm = __hwahc_op_mmcie_rm;
-       wusbhc->dev_info_set = __hwahc_op_dev_info_set;
-       wusbhc->bwa_set = __hwahc_op_bwa_set;
-       wusbhc->set_num_dnts = __hwahc_op_set_num_dnts;
-       wusbhc->set_ptk = __hwahc_op_set_ptk;
-       wusbhc->set_gtk = __hwahc_op_set_gtk;
-       result = hwahc_security_create(hwahc);
-       if (result < 0) {
-               dev_err(dev, "Can't initialize security: %d\n", result);
-               goto error_security_create;
-       }
-       wa->wusb = wusbhc;      /* FIXME: ugly, need to fix */
-       result = wusbhc_create(&hwahc->wusbhc);
-       if (result < 0) {
-               dev_err(dev, "Can't create WUSB HC structures: %d\n", result);
-               goto error_wusbhc_create;
-       }
-       result = wa_create(&hwahc->wa, iface, quirks);
-       if (result < 0)
-               goto error_wa_create;
-       return 0;
-
-error_wa_create:
-       wusbhc_destroy(&hwahc->wusbhc);
-error_wusbhc_create:
-       /* WA Descr fill allocs no resources */
-error_security_create:
-error_fill_descriptor:
-       usb_put_intf(iface);
-       usb_put_dev(usb_dev);
-       return result;
-}
-
-static void hwahc_destroy(struct hwahc *hwahc)
-{
-       struct wusbhc *wusbhc = &hwahc->wusbhc;
-
-       mutex_lock(&wusbhc->mutex);
-       __wa_destroy(&hwahc->wa);
-       wusbhc_destroy(&hwahc->wusbhc);
-       hwahc_security_release(hwahc);
-       hwahc->wusbhc.dev = NULL;
-       uwb_rc_put(wusbhc->uwb_rc);
-       usb_put_intf(hwahc->wa.usb_iface);
-       usb_put_dev(hwahc->wa.usb_dev);
-       mutex_unlock(&wusbhc->mutex);
-}
-
-static void hwahc_init(struct hwahc *hwahc)
-{
-       wa_init(&hwahc->wa);
-}
-
-static int hwahc_probe(struct usb_interface *usb_iface,
-                      const struct usb_device_id *id)
-{
-       int result;
-       struct usb_hcd *usb_hcd;
-       struct wusbhc *wusbhc;
-       struct hwahc *hwahc;
-       struct device *dev = &usb_iface->dev;
-
-       result = -ENOMEM;
-       usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa");
-       if (usb_hcd == NULL) {
-               dev_err(dev, "unable to allocate instance\n");
-               goto error_alloc;
-       }
-       usb_hcd->wireless = 1;
-       usb_hcd->self.sg_tablesize = ~0;
-       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       hwahc_init(hwahc);
-       result = hwahc_create(hwahc, usb_iface, id->driver_info);
-       if (result < 0) {
-               dev_err(dev, "Cannot initialize internals: %d\n", result);
-               goto error_hwahc_create;
-       }
-       result = usb_add_hcd(usb_hcd, 0, 0);
-       if (result < 0) {
-               dev_err(dev, "Cannot add HCD: %d\n", result);
-               goto error_add_hcd;
-       }
-       device_wakeup_enable(usb_hcd->self.controller);
-       result = wusbhc_b_create(&hwahc->wusbhc);
-       if (result < 0) {
-               dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result);
-               goto error_wusbhc_b_create;
-       }
-       return 0;
-
-error_wusbhc_b_create:
-       usb_remove_hcd(usb_hcd);
-error_add_hcd:
-       hwahc_destroy(hwahc);
-error_hwahc_create:
-       usb_put_hcd(usb_hcd);
-error_alloc:
-       return result;
-}
-
-static void hwahc_disconnect(struct usb_interface *usb_iface)
-{
-       struct usb_hcd *usb_hcd;
-       struct wusbhc *wusbhc;
-       struct hwahc *hwahc;
-
-       usb_hcd = usb_get_intfdata(usb_iface);
-       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       wusbhc_b_destroy(&hwahc->wusbhc);
-       usb_remove_hcd(usb_hcd);
-       hwahc_destroy(hwahc);
-       usb_put_hcd(usb_hcd);
-}
-
-static const struct usb_device_id hwahc_id_table[] = {
-       /* Alereon 5310 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01),
-         .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
-               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
-       /* Alereon 5611 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01),
-         .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
-               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
-       /* FIXME: use class labels for this */
-       { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },
-       {},
-};
-MODULE_DEVICE_TABLE(usb, hwahc_id_table);
-
-static struct usb_driver hwahc_driver = {
-       .name =         "hwa-hc",
-       .probe =        hwahc_probe,
-       .disconnect =   hwahc_disconnect,
-       .id_table =     hwahc_id_table,
-};
-
-module_usb_driver(hwahc_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/host/whci/Makefile b/drivers/staging/wusbcore/host/whci/Makefile
deleted file mode 100644 (file)
index 859d200..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o
-
-whci-hcd-y := \
-       asl.o   \
-       debug.o \
-       hcd.o   \
-       hw.o    \
-       init.o  \
-       int.o   \
-       pzl.o   \
-       qset.o  \
-       wusb.o
diff --git a/drivers/staging/wusbcore/host/whci/asl.c b/drivers/staging/wusbcore/host/whci/asl.c
deleted file mode 100644 (file)
index a2b9a50..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) asynchronous schedule management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-#include <linux/usb.h>
-
-#include "../../../uwb/include/umc.h"
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset,
-                              struct whc_qset **next, struct whc_qset **prev)
-{
-       struct list_head *n, *p;
-
-       BUG_ON(list_empty(&whc->async_list));
-
-       n = qset->list_node.next;
-       if (n == &whc->async_list)
-               n = n->next;
-       p = qset->list_node.prev;
-       if (p == &whc->async_list)
-               p = p->prev;
-
-       *next = container_of(n, struct whc_qset, list_node);
-       *prev = container_of(p, struct whc_qset, list_node);
-
-}
-
-static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset)
-{
-       list_move(&qset->list_node, &whc->async_list);
-       qset->in_sw_list = true;
-}
-
-static void asl_qset_insert(struct whc *whc, struct whc_qset *qset)
-{
-       struct whc_qset *next, *prev;
-
-       qset_clear(whc, qset);
-
-       /* Link into ASL. */
-       qset_get_next_prev(whc, qset, &next, &prev);
-       whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma);
-       whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma);
-       qset->in_hw_list = true;
-}
-
-static void asl_qset_remove(struct whc *whc, struct whc_qset *qset)
-{
-       struct whc_qset *prev, *next;
-
-       qset_get_next_prev(whc, qset, &next, &prev);
-
-       list_move(&qset->list_node, &whc->async_removed_list);
-       qset->in_sw_list = false;
-
-       /*
-        * No more qsets in the ASL?  The caller must stop the ASL as
-        * it's no longer valid.
-        */
-       if (list_empty(&whc->async_list))
-               return;
-
-       /* Remove from ASL. */
-       whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma);
-       qset->in_hw_list = false;
-}
-
-/**
- * process_qset - process any recently inactivated or halted qTDs in a
- * qset.
- *
- * After inactive qTDs are removed, new qTDs can be added if the
- * urb queue still contains URBs.
- *
- * Returns any additional WUSBCMD bits for the ASL sync command (i.e.,
- * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed).
- */
-static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
-{
-       enum whc_update update = 0;
-       uint32_t status = 0;
-
-       while (qset->ntds) {
-               struct whc_qtd *td;
-
-               td = &qset->qtd[qset->td_start];
-               status = le32_to_cpu(td->status);
-
-               /*
-                * Nothing to do with a still active qTD.
-                */
-               if (status & QTD_STS_ACTIVE)
-                       break;
-
-               if (status & QTD_STS_HALTED) {
-                       /* Ug, an error. */
-                       process_halted_qtd(whc, qset, td);
-                       /* A halted qTD always triggers an update
-                          because the qset was either removed or
-                          reactivated. */
-                       update |= WHC_UPDATE_UPDATED;
-                       goto done;
-               }
-
-               /* Mmm, a completed qTD. */
-               process_inactive_qtd(whc, qset, td);
-       }
-
-       if (!qset->remove)
-               update |= qset_add_qtds(whc, qset);
-
-done:
-       /*
-        * Remove this qset from the ASL if requested, but only if has
-        * no qTDs.
-        */
-       if (qset->remove && qset->ntds == 0) {
-               asl_qset_remove(whc, qset);
-               update |= WHC_UPDATE_REMOVED;
-       }
-       return update;
-}
-
-void asl_start(struct whc *whc)
-{
-       struct whc_qset *qset;
-
-       qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
-
-       le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR);
-
-       whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED,
-                     1000, "start ASL");
-}
-
-void asl_stop(struct whc *whc)
-{
-       whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_ASYNC_SCHED, 0,
-                     1000, "stop ASL");
-}
-
-/**
- * asl_update - request an ASL update and wait for the hardware to be synced
- * @whc: the WHCI HC
- * @wusbcmd: WUSBCMD value to start the update.
- *
- * If the WUSB HC is inactive (i.e., the ASL is stopped) then the
- * update must be skipped as the hardware may not respond to update
- * requests.
- */
-void asl_update(struct whc *whc, uint32_t wusbcmd)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-       long t;
-
-       mutex_lock(&wusbhc->mutex);
-       if (wusbhc->active) {
-               whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
-               t = wait_event_timeout(
-                       whc->async_list_wq,
-                       (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0,
-                       msecs_to_jiffies(1000));
-               if (t == 0)
-                       whc_hw_error(whc, "ASL update timeout");
-       }
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/**
- * scan_async_work - scan the ASL for qsets to process.
- *
- * Process each qset in the ASL in turn and then signal the WHC that
- * the ASL has been updated.
- *
- * Then start, stop or update the asynchronous schedule as required.
- */
-void scan_async_work(struct work_struct *work)
-{
-       struct whc *whc = container_of(work, struct whc, async_work);
-       struct whc_qset *qset, *t;
-       enum whc_update update = 0;
-
-       spin_lock_irq(&whc->lock);
-
-       /*
-        * Transerve the software list backwards so new qsets can be
-        * safely inserted into the ASL without making it non-circular.
-        */
-       list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) {
-               if (!qset->in_hw_list) {
-                       asl_qset_insert(whc, qset);
-                       update |= WHC_UPDATE_ADDED;
-               }
-
-               update |= process_qset(whc, qset);
-       }
-
-       spin_unlock_irq(&whc->lock);
-
-       if (update) {
-               uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB;
-               if (update & WHC_UPDATE_REMOVED)
-                       wusbcmd |= WUSBCMD_ASYNC_QSET_RM;
-               asl_update(whc, wusbcmd);
-       }
-
-       /*
-        * Now that the ASL is updated, complete the removal of any
-        * removed qsets.
-        *
-        * If the qset was to be reset, do so and reinsert it into the
-        * ASL if it has pending transfers.
-        */
-       spin_lock_irq(&whc->lock);
-
-       list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
-               qset_remove_complete(whc, qset);
-               if (qset->reset) {
-                       qset_reset(whc, qset);
-                       if (!list_empty(&qset->stds)) {
-                               asl_qset_insert_begin(whc, qset);
-                               queue_work(whc->workqueue, &whc->async_work);
-                       }
-               }
-       }
-
-       spin_unlock_irq(&whc->lock);
-}
-
-/**
- * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL).
- * @whc: the WHCI host controller
- * @urb: the URB to enqueue
- * @mem_flags: flags for any memory allocations
- *
- * The qset for the endpoint is obtained and the urb queued on to it.
- *
- * Work is scheduled to update the hardware's view of the ASL.
- */
-int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
-{
-       struct whc_qset *qset;
-       int err;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
-       if (err < 0) {
-               spin_unlock_irqrestore(&whc->lock, flags);
-               return err;
-       }
-
-       qset = get_qset(whc, urb, GFP_ATOMIC);
-       if (qset == NULL)
-               err = -ENOMEM;
-       else
-               err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
-       if (!err) {
-               if (!qset->in_sw_list && !qset->remove)
-                       asl_qset_insert_begin(whc, qset);
-       } else
-               usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-
-       if (!err)
-               queue_work(whc->workqueue, &whc->async_work);
-
-       return err;
-}
-
-/**
- * asl_urb_dequeue - remove an URB (qset) from the async list.
- * @whc: the WHCI host controller
- * @urb: the URB to dequeue
- * @status: the current status of the URB
- *
- * URBs that do yet have qTDs can simply be removed from the software
- * queue, otherwise the qset must be removed from the ASL so the qTDs
- * can be removed.
- */
-int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
-{
-       struct whc_urb *wurb = urb->hcpriv;
-       struct whc_qset *qset = wurb->qset;
-       struct whc_std *std, *t;
-       bool has_qtd = false;
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
-       if (ret < 0)
-               goto out;
-
-       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb == urb) {
-                       if (std->qtd)
-                               has_qtd = true;
-                       qset_free_std(whc, std);
-               } else
-                       std->qtd = NULL; /* so this std is re-added when the qset is */
-       }
-
-       if (has_qtd) {
-               asl_qset_remove(whc, qset);
-               wurb->status = status;
-               wurb->is_async = true;
-               queue_work(whc->workqueue, &wurb->dequeue_work);
-       } else
-               qset_remove_urb(whc, qset, urb, status);
-out:
-       spin_unlock_irqrestore(&whc->lock, flags);
-
-       return ret;
-}
-
-/**
- * asl_qset_delete - delete a qset from the ASL
- */
-void asl_qset_delete(struct whc *whc, struct whc_qset *qset)
-{
-       qset->remove = 1;
-       queue_work(whc->workqueue, &whc->async_work);
-       qset_delete(whc, qset);
-}
-
-/**
- * asl_init - initialize the asynchronous schedule list
- *
- * A dummy qset with no qTDs is added to the ASL to simplify removing
- * qsets (no need to stop the ASL when the last qset is removed).
- */
-int asl_init(struct whc *whc)
-{
-       struct whc_qset *qset;
-
-       qset = qset_alloc(whc, GFP_KERNEL);
-       if (qset == NULL)
-               return -ENOMEM;
-
-       asl_qset_insert_begin(whc, qset);
-       asl_qset_insert(whc, qset);
-
-       return 0;
-}
-
-/**
- * asl_clean_up - free ASL resources
- *
- * The ASL is stopped and empty except for the dummy qset.
- */
-void asl_clean_up(struct whc *whc)
-{
-       struct whc_qset *qset;
-
-       if (!list_empty(&whc->async_list)) {
-               qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
-               list_del(&qset->list_node);
-               qset_free(whc, qset);
-       }
-}
diff --git a/drivers/staging/wusbcore/host/whci/debug.c b/drivers/staging/wusbcore/host/whci/debug.c
deleted file mode 100644 (file)
index 443da67..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) debug.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/export.h>
-
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-struct whc_dbg {
-       struct dentry *di_f;
-       struct dentry *asl_f;
-       struct dentry *pzl_f;
-};
-
-static void qset_print(struct seq_file *s, struct whc_qset *qset)
-{
-       static const char *qh_type[] = {
-               "ctrl", "isoc", "bulk", "intr", "rsvd", "rsvd", "rsvd", "lpintr", };
-       struct whc_std *std;
-       struct urb *urb = NULL;
-       int i;
-
-       seq_printf(s, "qset %08x", (u32)qset->qset_dma);
-       if (&qset->list_node == qset->whc->async_list.prev) {
-               seq_printf(s, " (dummy)\n");
-       } else {
-               seq_printf(s, " ep%d%s-%s maxpkt: %d\n",
-                          qset->qh.info1 & 0x0f,
-                          (qset->qh.info1 >> 4) & 0x1 ? "in" : "out",
-                          qh_type[(qset->qh.info1 >> 5) & 0x7],
-                          (qset->qh.info1 >> 16) & 0xffff);
-       }
-       seq_printf(s, "  -> %08x\n", (u32)qset->qh.link);
-       seq_printf(s, "  info: %08x %08x %08x\n",
-                  qset->qh.info1, qset->qh.info2,  qset->qh.info3);
-       seq_printf(s, "  sts: %04x errs: %d curwin: %08x\n",
-                  qset->qh.status, qset->qh.err_count, qset->qh.cur_window);
-       seq_printf(s, "  TD: sts: %08x opts: %08x\n",
-                  qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
-
-       for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
-               seq_printf(s, "  %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
-                       i == qset->td_start ? 'S' : ' ',
-                       i == qset->td_end ? 'E' : ' ',
-                       i, qset->qtd[i].status, qset->qtd[i].options,
-                       (u32)qset->qtd[i].page_list_ptr);
-       }
-       seq_printf(s, "  ntds: %d\n", qset->ntds);
-       list_for_each_entry(std, &qset->stds, list_node) {
-               if (urb != std->urb) {
-                       urb = std->urb;
-                       seq_printf(s, "  urb %p transferred: %d bytes\n", urb,
-                               urb->actual_length);
-               }
-               if (std->qtd)
-                       seq_printf(s, "    sTD[%td]: %zu bytes @ %08x\n",
-                               std->qtd - &qset->qtd[0],
-                               std->len, std->num_pointers ?
-                               (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
-               else
-                       seq_printf(s, "    sTD[-]: %zd bytes @ %08x\n",
-                               std->len, std->num_pointers ?
-                               (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
-       }
-}
-
-static int di_show(struct seq_file *s, void *p)
-{
-       struct whc *whc = s->private;
-       int d;
-
-       for (d = 0; d < whc->n_devices; d++) {
-               struct di_buf_entry *di = &whc->di_buf[d];
-
-               seq_printf(s, "DI[%d]\n", d);
-               seq_printf(s, "  availability: %*pb\n",
-                          UWB_NUM_MAS, (unsigned long *)di->availability_info);
-               seq_printf(s, "  %c%c key idx: %d dev addr: %d\n",
-                          (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
-                          (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
-                          (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
-                          (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
-       }
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(di);
-
-static int asl_show(struct seq_file *s, void *p)
-{
-       struct whc *whc = s->private;
-       struct whc_qset *qset;
-
-       list_for_each_entry(qset, &whc->async_list, list_node) {
-               qset_print(s, qset);
-       }
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(asl);
-
-static int pzl_show(struct seq_file *s, void *p)
-{
-       struct whc *whc = s->private;
-       struct whc_qset *qset;
-       int period;
-
-       for (period = 0; period < 5; period++) {
-               seq_printf(s, "Period %d\n", period);
-               list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
-                       qset_print(s, qset);
-               }
-       }
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(pzl);
-
-void whc_dbg_init(struct whc *whc)
-{
-       if (whc->wusbhc.pal.debugfs_dir == NULL)
-               return;
-
-       whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL);
-       if (whc->dbg == NULL)
-               return;
-
-       whc->dbg->di_f = debugfs_create_file("di", 0444,
-                                             whc->wusbhc.pal.debugfs_dir, whc,
-                                             &di_fops);
-       whc->dbg->asl_f = debugfs_create_file("asl", 0444,
-                                             whc->wusbhc.pal.debugfs_dir, whc,
-                                             &asl_fops);
-       whc->dbg->pzl_f = debugfs_create_file("pzl", 0444,
-                                             whc->wusbhc.pal.debugfs_dir, whc,
-                                             &pzl_fops);
-}
-
-void whc_dbg_clean_up(struct whc *whc)
-{
-       if (whc->dbg) {
-               debugfs_remove(whc->dbg->pzl_f);
-               debugfs_remove(whc->dbg->asl_f);
-               debugfs_remove(whc->dbg->di_f);
-               kfree(whc->dbg);
-       }
-}
diff --git a/drivers/staging/wusbcore/host/whci/hcd.c b/drivers/staging/wusbcore/host/whci/hcd.c
deleted file mode 100644 (file)
index bee1ff2..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) driver.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include "../../../uwb/include/umc.h"
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-/*
- * One time initialization.
- *
- * Nothing to do here.
- */
-static int whc_reset(struct usb_hcd *usb_hcd)
-{
-       return 0;
-}
-
-/*
- * Start the wireless host controller.
- *
- * Start device notification.
- *
- * Put hc into run state, set DNTS parameters.
- */
-static int whc_start(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u8 bcid;
-       int ret;
-
-       mutex_lock(&wusbhc->mutex);
-
-       le_writel(WUSBINTR_GEN_CMD_DONE
-                 | WUSBINTR_HOST_ERR
-                 | WUSBINTR_ASYNC_SCHED_SYNCED
-                 | WUSBINTR_DNTS_INT
-                 | WUSBINTR_ERR_INT
-                 | WUSBINTR_INT,
-                 whc->base + WUSBINTR);
-
-       /* set cluster ID */
-       bcid = wusb_cluster_id_get();
-       ret = whc_set_cluster_id(whc, bcid);
-       if (ret < 0)
-               goto out;
-       wusbhc->cluster_id = bcid;
-
-       /* start HC */
-       whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
-
-       usb_hcd->uses_new_polling = 1;
-       set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
-       usb_hcd->state = HC_STATE_RUNNING;
-
-out:
-       mutex_unlock(&wusbhc->mutex);
-       return ret;
-}
-
-
-/*
- * Stop the wireless host controller.
- *
- * Stop device notification.
- *
- * Wait for pending transfer to stop? Put hc into stop state?
- */
-static void whc_stop(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-
-       mutex_lock(&wusbhc->mutex);
-
-       /* stop HC */
-       le_writel(0, whc->base + WUSBINTR);
-       whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_HCHALTED, WUSBSTS_HCHALTED,
-                     100, "HC to halt");
-
-       wusb_cluster_id_put(wusbhc->cluster_id);
-
-       mutex_unlock(&wusbhc->mutex);
-}
-
-static int whc_get_frame_number(struct usb_hcd *usb_hcd)
-{
-       /* Frame numbers are not applicable to WUSB. */
-       return -ENOSYS;
-}
-
-
-/*
- * Queue an URB to the ASL or PZL
- */
-static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
-                          gfp_t mem_flags)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       int ret;
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_INTERRUPT:
-               ret = pzl_urb_enqueue(whc, urb, mem_flags);
-               break;
-       case PIPE_ISOCHRONOUS:
-               dev_err(&whc->umc->dev, "isochronous transfers unsupported\n");
-               ret = -ENOTSUPP;
-               break;
-       case PIPE_CONTROL:
-       case PIPE_BULK:
-       default:
-               ret = asl_urb_enqueue(whc, urb, mem_flags);
-               break;
-       }
-
-       return ret;
-}
-
-/*
- * Remove a queued URB from the ASL or PZL.
- */
-static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       int ret;
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_INTERRUPT:
-               ret = pzl_urb_dequeue(whc, urb, status);
-               break;
-       case PIPE_ISOCHRONOUS:
-               ret = -ENOTSUPP;
-               break;
-       case PIPE_CONTROL:
-       case PIPE_BULK:
-       default:
-               ret = asl_urb_dequeue(whc, urb, status);
-               break;
-       }
-
-       return ret;
-}
-
-/*
- * Wait for all URBs to the endpoint to be completed, then delete the
- * qset.
- */
-static void whc_endpoint_disable(struct usb_hcd *usb_hcd,
-                                struct usb_host_endpoint *ep)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       struct whc_qset *qset;
-
-       qset = ep->hcpriv;
-       if (qset) {
-               ep->hcpriv = NULL;
-               if (usb_endpoint_xfer_bulk(&ep->desc)
-                   || usb_endpoint_xfer_control(&ep->desc))
-                       asl_qset_delete(whc, qset);
-               else
-                       pzl_qset_delete(whc, qset);
-       }
-}
-
-static void whc_endpoint_reset(struct usb_hcd *usb_hcd,
-                              struct usb_host_endpoint *ep)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       struct whc_qset *qset;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       qset = ep->hcpriv;
-       if (qset) {
-               qset->remove = 1;
-               qset->reset = 1;
-
-               if (usb_endpoint_xfer_bulk(&ep->desc)
-                   || usb_endpoint_xfer_control(&ep->desc))
-                       queue_work(whc->workqueue, &whc->async_work);
-               else
-                       queue_work(whc->workqueue, &whc->periodic_work);
-       }
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-
-static const struct hc_driver whc_hc_driver = {
-       .description = "whci-hcd",
-       .product_desc = "Wireless host controller",
-       .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd),
-       .irq = whc_int_handler,
-       .flags = HCD_USB2,
-
-       .reset = whc_reset,
-       .start = whc_start,
-       .stop = whc_stop,
-       .get_frame_number = whc_get_frame_number,
-       .urb_enqueue = whc_urb_enqueue,
-       .urb_dequeue = whc_urb_dequeue,
-       .endpoint_disable = whc_endpoint_disable,
-       .endpoint_reset = whc_endpoint_reset,
-
-       .hub_status_data = wusbhc_rh_status_data,
-       .hub_control = wusbhc_rh_control,
-       .start_port_reset = wusbhc_rh_start_port_reset,
-};
-
-static int whc_probe(struct umc_dev *umc)
-{
-       int ret;
-       struct usb_hcd *usb_hcd;
-       struct wusbhc *wusbhc;
-       struct whc *whc;
-       struct device *dev = &umc->dev;
-
-       usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
-       if (usb_hcd == NULL) {
-               dev_err(dev, "unable to create hcd\n");
-               return -ENOMEM;
-       }
-
-       usb_hcd->wireless = 1;
-       usb_hcd->self.sg_tablesize = 2048; /* somewhat arbitrary */
-
-       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       whc = wusbhc_to_whc(wusbhc);
-       whc->umc = umc;
-
-       ret = whc_init(whc);
-       if (ret)
-               goto error_whc_init;
-
-       wusbhc->dev = dev;
-       wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
-       if (!wusbhc->uwb_rc) {
-               ret = -ENODEV;
-               dev_err(dev, "cannot get radio controller\n");
-               goto error_uwb_rc;
-       }
-
-       if (whc->n_devices > USB_MAXCHILDREN) {
-               dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n",
-                        whc->n_devices);
-               wusbhc->ports_max = USB_MAXCHILDREN;
-       } else
-               wusbhc->ports_max = whc->n_devices;
-       wusbhc->mmcies_max      = whc->n_mmc_ies;
-       wusbhc->start           = whc_wusbhc_start;
-       wusbhc->stop            = whc_wusbhc_stop;
-       wusbhc->mmcie_add       = whc_mmcie_add;
-       wusbhc->mmcie_rm        = whc_mmcie_rm;
-       wusbhc->dev_info_set    = whc_dev_info_set;
-       wusbhc->bwa_set         = whc_bwa_set;
-       wusbhc->set_num_dnts    = whc_set_num_dnts;
-       wusbhc->set_ptk         = whc_set_ptk;
-       wusbhc->set_gtk         = whc_set_gtk;
-
-       ret = wusbhc_create(wusbhc);
-       if (ret)
-               goto error_wusbhc_create;
-
-       ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED);
-       if (ret) {
-               dev_err(dev, "cannot add HCD: %d\n", ret);
-               goto error_usb_add_hcd;
-       }
-       device_wakeup_enable(usb_hcd->self.controller);
-
-       ret = wusbhc_b_create(wusbhc);
-       if (ret) {
-               dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret);
-               goto error_wusbhc_b_create;
-       }
-
-       whc_dbg_init(whc);
-
-       return 0;
-
-error_wusbhc_b_create:
-       usb_remove_hcd(usb_hcd);
-error_usb_add_hcd:
-       wusbhc_destroy(wusbhc);
-error_wusbhc_create:
-       uwb_rc_put(wusbhc->uwb_rc);
-error_uwb_rc:
-       whc_clean_up(whc);
-error_whc_init:
-       usb_put_hcd(usb_hcd);
-       return ret;
-}
-
-
-static void whc_remove(struct umc_dev *umc)
-{
-       struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev);
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-
-       if (usb_hcd) {
-               whc_dbg_clean_up(whc);
-               wusbhc_b_destroy(wusbhc);
-               usb_remove_hcd(usb_hcd);
-               wusbhc_destroy(wusbhc);
-               uwb_rc_put(wusbhc->uwb_rc);
-               whc_clean_up(whc);
-               usb_put_hcd(usb_hcd);
-       }
-}
-
-static struct umc_driver whci_hc_driver = {
-       .name =         "whci-hcd",
-       .cap_id =       UMC_CAP_ID_WHCI_WUSB_HC,
-       .probe =        whc_probe,
-       .remove =       whc_remove,
-};
-
-static int __init whci_hc_driver_init(void)
-{
-       return umc_driver_register(&whci_hc_driver);
-}
-module_init(whci_hc_driver_init);
-
-static void __exit whci_hc_driver_exit(void)
-{
-       umc_driver_unregister(&whci_hc_driver);
-}
-module_exit(whci_hc_driver_exit);
-
-/* PCI device ID's that we handle (so it gets loaded) */
-static struct pci_device_id __used whci_hcd_id_table[] = {
-       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
-       { /* empty last entry */ }
-};
-MODULE_DEVICE_TABLE(pci, whci_hcd_id_table);
-
-MODULE_DESCRIPTION("WHCI Wireless USB host controller driver");
-MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/host/whci/hw.c b/drivers/staging/wusbcore/host/whci/hw.c
deleted file mode 100644 (file)
index e4e8914..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) hardware access helpers.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-
-#include "../../../uwb/include/umc.h"
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val)
-{
-       unsigned long flags;
-       u32 cmd;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       cmd = le_readl(whc->base + WUSBCMD);
-       cmd = (cmd & ~mask) | val;
-       le_writel(cmd, whc->base + WUSBCMD);
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-/**
- * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register
- * @whc:    the WHCI HC
- * @cmd:    command to start.
- * @params: parameters for the command (the WUSBGENCMDPARAMS register value).
- * @addr:   pointer to any data for the command (may be NULL).
- * @len:    length of the data (if any).
- */
-int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
-{
-       unsigned long flags;
-       dma_addr_t dma_addr;
-       int t;
-       int ret = 0;
-
-       mutex_lock(&whc->mutex);
-
-       /* Wait for previous command to complete. */
-       t = wait_event_timeout(whc->cmd_wq,
-                              (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0,
-                              WHC_GENCMD_TIMEOUT_MS);
-       if (t == 0) {
-               dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n",
-                       le_readl(whc->base + WUSBGENCMDSTS),
-                       le_readl(whc->base + WUSBGENCMDPARAMS));
-               ret = -ETIMEDOUT;
-               goto out;
-       }
-
-       if (addr) {
-               memcpy(whc->gen_cmd_buf, addr, len);
-               dma_addr = whc->gen_cmd_buf_dma;
-       } else
-               dma_addr = 0;
-
-       /* Poke registers to start cmd. */
-       spin_lock_irqsave(&whc->lock, flags);
-
-       le_writel(params, whc->base + WUSBGENCMDPARAMS);
-       le_writeq(dma_addr, whc->base + WUSBGENADDR);
-
-       le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd,
-                 whc->base + WUSBGENCMDSTS);
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-out:
-       mutex_unlock(&whc->mutex);
-
-       return ret;
-}
-
-/**
- * whc_hw_error - recover from a hardware error
- * @whc:    the WHCI HC that broke.
- * @reason: a description of the failure.
- *
- * Recover from broken hardware with a full reset.
- */
-void whc_hw_error(struct whc *whc, const char *reason)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-
-       dev_err(&whc->umc->dev, "hardware error: %s\n", reason);
-       wusbhc_reset_all(wusbhc);
-}
diff --git a/drivers/staging/wusbcore/host/whci/init.c b/drivers/staging/wusbcore/host/whci/init.c
deleted file mode 100644 (file)
index 55fd458..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) initialization.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-
-#include "../../../uwb/include/umc.h"
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-/*
- * Reset the host controller.
- */
-static void whc_hw_reset(struct whc *whc)
-{
-       le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
-                     100, "reset");
-}
-
-static void whc_hw_init_di_buf(struct whc *whc)
-{
-       int d;
-
-       /* Disable all entries in the Device Information buffer. */
-       for (d = 0; d < whc->n_devices; d++)
-               whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
-
-       le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
-}
-
-static void whc_hw_init_dn_buf(struct whc *whc)
-{
-       /* Clear the Device Notification buffer to ensure the V (valid)
-        * bits are clear.  */
-       memset(whc->dn_buf, 0, 4096);
-
-       le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
-}
-
-int whc_init(struct whc *whc)
-{
-       u32 whcsparams;
-       int ret, i;
-       resource_size_t start, len;
-
-       spin_lock_init(&whc->lock);
-       mutex_init(&whc->mutex);
-       init_waitqueue_head(&whc->cmd_wq);
-       init_waitqueue_head(&whc->async_list_wq);
-       init_waitqueue_head(&whc->periodic_list_wq);
-       whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0);
-       if (whc->workqueue == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       INIT_WORK(&whc->dn_work, whc_dn_work);
-
-       INIT_WORK(&whc->async_work, scan_async_work);
-       INIT_LIST_HEAD(&whc->async_list);
-       INIT_LIST_HEAD(&whc->async_removed_list);
-
-       INIT_WORK(&whc->periodic_work, scan_periodic_work);
-       for (i = 0; i < 5; i++)
-               INIT_LIST_HEAD(&whc->periodic_list[i]);
-       INIT_LIST_HEAD(&whc->periodic_removed_list);
-
-       /* Map HC registers. */
-       start = whc->umc->resource.start;
-       len   = whc->umc->resource.end - start + 1;
-       if (!request_mem_region(start, len, "whci-hc")) {
-               dev_err(&whc->umc->dev, "can't request HC region\n");
-               ret = -EBUSY;
-               goto error;
-       }
-       whc->base_phys = start;
-       whc->base = ioremap(start, len);
-       if (!whc->base) {
-               dev_err(&whc->umc->dev, "ioremap\n");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       whc_hw_reset(whc);
-
-       /* Read maximum number of devices, keys and MMC IEs. */
-       whcsparams = le_readl(whc->base + WHCSPARAMS);
-       whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
-       whc->n_keys    = WHCSPARAMS_TO_N_KEYS(whcsparams);
-       whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
-
-       dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
-               whc->n_devices, whc->n_keys, whc->n_mmc_ies);
-
-       whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
-                                        sizeof(struct whc_qset), 64, 0);
-       if (whc->qset_pool == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       ret = asl_init(whc);
-       if (ret < 0)
-               goto error;
-       ret = pzl_init(whc);
-       if (ret < 0)
-               goto error;
-
-       /* Allocate and initialize a buffer for generic commands, the
-          Device Information buffer, and the Device Notification
-          buffer. */
-
-       whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
-                                             &whc->gen_cmd_buf_dma, GFP_KERNEL);
-       if (whc->gen_cmd_buf == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
-                                        sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
-                                        &whc->dn_buf_dma, GFP_KERNEL);
-       if (!whc->dn_buf) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       whc_hw_init_dn_buf(whc);
-
-       whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
-                                        sizeof(struct di_buf_entry) * whc->n_devices,
-                                        &whc->di_buf_dma, GFP_KERNEL);
-       if (!whc->di_buf) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       whc_hw_init_di_buf(whc);
-
-       return 0;
-
-error:
-       whc_clean_up(whc);
-       return ret;
-}
-
-void whc_clean_up(struct whc *whc)
-{
-       resource_size_t len;
-
-       if (whc->di_buf)
-               dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
-                                 whc->di_buf, whc->di_buf_dma);
-       if (whc->dn_buf)
-               dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
-                                 whc->dn_buf, whc->dn_buf_dma);
-       if (whc->gen_cmd_buf)
-               dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
-                                 whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
-
-       pzl_clean_up(whc);
-       asl_clean_up(whc);
-
-       dma_pool_destroy(whc->qset_pool);
-
-       len   = resource_size(&whc->umc->resource);
-       if (whc->base)
-               iounmap(whc->base);
-       if (whc->base_phys)
-               release_mem_region(whc->base_phys, len);
-
-       if (whc->workqueue)
-               destroy_workqueue(whc->workqueue);
-}
diff --git a/drivers/staging/wusbcore/host/whci/int.c b/drivers/staging/wusbcore/host/whci/int.c
deleted file mode 100644 (file)
index bdbe35e..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) interrupt handling.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-
-#include "../../../uwb/include/umc.h"
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-static void transfer_done(struct whc *whc)
-{
-       queue_work(whc->workqueue, &whc->async_work);
-       queue_work(whc->workqueue, &whc->periodic_work);
-}
-
-irqreturn_t whc_int_handler(struct usb_hcd *hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 sts;
-
-       sts = le_readl(whc->base + WUSBSTS);
-       if (!(sts & WUSBSTS_INT_MASK))
-               return IRQ_NONE;
-       le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);
-
-       if (sts & WUSBSTS_GEN_CMD_DONE)
-               wake_up(&whc->cmd_wq);
-
-       if (sts & WUSBSTS_HOST_ERR)
-               dev_err(&whc->umc->dev, "FIXME: host system error\n");
-
-       if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
-               wake_up(&whc->async_list_wq);
-
-       if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
-               wake_up(&whc->periodic_list_wq);
-
-       if (sts & WUSBSTS_DNTS_INT)
-               queue_work(whc->workqueue, &whc->dn_work);
-
-       /*
-        * A transfer completed (see [WHCI] section 4.7.1.2 for when
-        * this occurs).
-        */
-       if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
-               transfer_done(whc);
-
-       return IRQ_HANDLED;
-}
-
-static int process_dn_buf(struct whc *whc)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-       struct dn_buf_entry *dn;
-       int processed = 0;
-
-       for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) {
-               if (dn->status & WHC_DN_STATUS_VALID) {
-                       wusbhc_handle_dn(wusbhc, dn->src_addr,
-                                        (struct wusb_dn_hdr *)dn->dn_data,
-                                        dn->msg_size);
-                       dn->status &= ~WHC_DN_STATUS_VALID;
-                       processed++;
-               }
-       }
-       return processed;
-}
-
-void whc_dn_work(struct work_struct *work)
-{
-       struct whc *whc = container_of(work, struct whc, dn_work);
-       int processed;
-
-       do {
-               processed = process_dn_buf(whc);
-       } while (processed);
-}
diff --git a/drivers/staging/wusbcore/host/whci/pzl.c b/drivers/staging/wusbcore/host/whci/pzl.c
deleted file mode 100644 (file)
index 6dfc075..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) periodic schedule management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-#include <linux/usb.h>
-
-#include "../../../uwb/include/umc.h"
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-static void update_pzl_pointers(struct whc *whc, int period, u64 addr)
-{
-       switch (period) {
-       case 0:
-               whc_qset_set_link_ptr(&whc->pz_list[0], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[2], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[4], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[6], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[8], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[10], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[12], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[14], addr);
-               break;
-       case 1:
-               whc_qset_set_link_ptr(&whc->pz_list[1], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[5], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[9], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[13], addr);
-               break;
-       case 2:
-               whc_qset_set_link_ptr(&whc->pz_list[3], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[11], addr);
-               break;
-       case 3:
-               whc_qset_set_link_ptr(&whc->pz_list[7], addr);
-               break;
-       case 4:
-               whc_qset_set_link_ptr(&whc->pz_list[15], addr);
-               break;
-       }
-}
-
-/*
- * Return the 'period' to use for this qset.  The minimum interval for
- * the endpoint is used so whatever urbs are submitted the device is
- * polled often enough.
- */
-static int qset_get_period(struct whc *whc, struct whc_qset *qset)
-{
-       uint8_t bInterval = qset->ep->desc.bInterval;
-
-       if (bInterval < 6)
-               bInterval = 6;
-       if (bInterval > 10)
-               bInterval = 10;
-       return bInterval - 6;
-}
-
-static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset)
-{
-       int period;
-
-       period = qset_get_period(whc, qset);
-
-       qset_clear(whc, qset);
-       list_move(&qset->list_node, &whc->periodic_list[period]);
-       qset->in_sw_list = true;
-}
-
-static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset)
-{
-       list_move(&qset->list_node, &whc->periodic_removed_list);
-       qset->in_hw_list = false;
-       qset->in_sw_list = false;
-}
-
-/**
- * pzl_process_qset - process any recently inactivated or halted qTDs
- * in a qset.
- *
- * After inactive qTDs are removed, new qTDs can be added if the
- * urb queue still contains URBs.
- *
- * Returns the schedule updates required.
- */
-static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
-{
-       enum whc_update update = 0;
-       uint32_t status = 0;
-
-       while (qset->ntds) {
-               struct whc_qtd *td;
-
-               td = &qset->qtd[qset->td_start];
-               status = le32_to_cpu(td->status);
-
-               /*
-                * Nothing to do with a still active qTD.
-                */
-               if (status & QTD_STS_ACTIVE)
-                       break;
-
-               if (status & QTD_STS_HALTED) {
-                       /* Ug, an error. */
-                       process_halted_qtd(whc, qset, td);
-                       /* A halted qTD always triggers an update
-                          because the qset was either removed or
-                          reactivated. */
-                       update |= WHC_UPDATE_UPDATED;
-                       goto done;
-               }
-
-               /* Mmm, a completed qTD. */
-               process_inactive_qtd(whc, qset, td);
-       }
-
-       if (!qset->remove)
-               update |= qset_add_qtds(whc, qset);
-
-done:
-       /*
-        * If there are no qTDs in this qset, remove it from the PZL.
-        */
-       if (qset->remove && qset->ntds == 0) {
-               pzl_qset_remove(whc, qset);
-               update |= WHC_UPDATE_REMOVED;
-       }
-
-       return update;
-}
-
-/**
- * pzl_start - start the periodic schedule
- * @whc: the WHCI host controller
- *
- * The PZL must be valid (e.g., all entries in the list should have
- * the T bit set).
- */
-void pzl_start(struct whc *whc)
-{
-       le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
-
-       whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED,
-                     1000, "start PZL");
-}
-
-/**
- * pzl_stop - stop the periodic schedule
- * @whc: the WHCI host controller
- */
-void pzl_stop(struct whc *whc)
-{
-       whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_PERIODIC_SCHED, 0,
-                     1000, "stop PZL");
-}
-
-/**
- * pzl_update - request a PZL update and wait for the hardware to be synced
- * @whc: the WHCI HC
- * @wusbcmd: WUSBCMD value to start the update.
- *
- * If the WUSB HC is inactive (i.e., the PZL is stopped) then the
- * update must be skipped as the hardware may not respond to update
- * requests.
- */
-void pzl_update(struct whc *whc, uint32_t wusbcmd)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-       long t;
-
-       mutex_lock(&wusbhc->mutex);
-       if (wusbhc->active) {
-               whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
-               t = wait_event_timeout(
-                       whc->periodic_list_wq,
-                       (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0,
-                       msecs_to_jiffies(1000));
-               if (t == 0)
-                       whc_hw_error(whc, "PZL update timeout");
-       }
-       mutex_unlock(&wusbhc->mutex);
-}
-
-static void update_pzl_hw_view(struct whc *whc)
-{
-       struct whc_qset *qset, *t;
-       int period;
-       u64 tmp_qh = 0;
-
-       for (period = 0; period < 5; period++) {
-               list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
-                       whc_qset_set_link_ptr(&qset->qh.link, tmp_qh);
-                       tmp_qh = qset->qset_dma;
-                       qset->in_hw_list = true;
-               }
-               update_pzl_pointers(whc, period, tmp_qh);
-       }
-}
-
-/**
- * scan_periodic_work - scan the PZL for qsets to process.
- *
- * Process each qset in the PZL in turn and then signal the WHC that
- * the PZL has been updated.
- *
- * Then start, stop or update the periodic schedule as required.
- */
-void scan_periodic_work(struct work_struct *work)
-{
-       struct whc *whc = container_of(work, struct whc, periodic_work);
-       struct whc_qset *qset, *t;
-       enum whc_update update = 0;
-       int period;
-
-       spin_lock_irq(&whc->lock);
-
-       for (period = 4; period >= 0; period--) {
-               list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
-                       if (!qset->in_hw_list)
-                               update |= WHC_UPDATE_ADDED;
-                       update |= pzl_process_qset(whc, qset);
-               }
-       }
-
-       if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
-               update_pzl_hw_view(whc);
-
-       spin_unlock_irq(&whc->lock);
-
-       if (update) {
-               uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB;
-               if (update & WHC_UPDATE_REMOVED)
-                       wusbcmd |= WUSBCMD_PERIODIC_QSET_RM;
-               pzl_update(whc, wusbcmd);
-       }
-
-       /*
-        * Now that the PZL is updated, complete the removal of any
-        * removed qsets.
-        *
-        * If the qset was to be reset, do so and reinsert it into the
-        * PZL if it has pending transfers.
-        */
-       spin_lock_irq(&whc->lock);
-
-       list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
-               qset_remove_complete(whc, qset);
-               if (qset->reset) {
-                       qset_reset(whc, qset);
-                       if (!list_empty(&qset->stds)) {
-                               qset_insert_in_sw_list(whc, qset);
-                               queue_work(whc->workqueue, &whc->periodic_work);
-                       }
-               }
-       }
-
-       spin_unlock_irq(&whc->lock);
-}
-
-/**
- * pzl_urb_enqueue - queue an URB onto the periodic list (PZL)
- * @whc: the WHCI host controller
- * @urb: the URB to enqueue
- * @mem_flags: flags for any memory allocations
- *
- * The qset for the endpoint is obtained and the urb queued on to it.
- *
- * Work is scheduled to update the hardware's view of the PZL.
- */
-int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
-{
-       struct whc_qset *qset;
-       int err;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
-       if (err < 0) {
-               spin_unlock_irqrestore(&whc->lock, flags);
-               return err;
-       }
-
-       qset = get_qset(whc, urb, GFP_ATOMIC);
-       if (qset == NULL)
-               err = -ENOMEM;
-       else
-               err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
-       if (!err) {
-               if (!qset->in_sw_list && !qset->remove)
-                       qset_insert_in_sw_list(whc, qset);
-       } else
-               usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-
-       if (!err)
-               queue_work(whc->workqueue, &whc->periodic_work);
-
-       return err;
-}
-
-/**
- * pzl_urb_dequeue - remove an URB (qset) from the periodic list
- * @whc: the WHCI host controller
- * @urb: the URB to dequeue
- * @status: the current status of the URB
- *
- * URBs that do yet have qTDs can simply be removed from the software
- * queue, otherwise the qset must be removed so the qTDs can be safely
- * removed.
- */
-int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
-{
-       struct whc_urb *wurb = urb->hcpriv;
-       struct whc_qset *qset = wurb->qset;
-       struct whc_std *std, *t;
-       bool has_qtd = false;
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
-       if (ret < 0)
-               goto out;
-
-       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb == urb) {
-                       if (std->qtd)
-                               has_qtd = true;
-                       qset_free_std(whc, std);
-               } else
-                       std->qtd = NULL; /* so this std is re-added when the qset is */
-       }
-
-       if (has_qtd) {
-               pzl_qset_remove(whc, qset);
-               update_pzl_hw_view(whc);
-               wurb->status = status;
-               wurb->is_async = false;
-               queue_work(whc->workqueue, &wurb->dequeue_work);
-       } else
-               qset_remove_urb(whc, qset, urb, status);
-out:
-       spin_unlock_irqrestore(&whc->lock, flags);
-
-       return ret;
-}
-
-/**
- * pzl_qset_delete - delete a qset from the PZL
- */
-void pzl_qset_delete(struct whc *whc, struct whc_qset *qset)
-{
-       qset->remove = 1;
-       queue_work(whc->workqueue, &whc->periodic_work);
-       qset_delete(whc, qset);
-}
-
-/**
- * pzl_init - initialize the periodic zone list
- * @whc: the WHCI host controller
- */
-int pzl_init(struct whc *whc)
-{
-       int i;
-
-       whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16,
-                                         &whc->pz_list_dma, GFP_KERNEL);
-       if (whc->pz_list == NULL)
-               return -ENOMEM;
-
-       /* Set T bit on all elements in PZL. */
-       for (i = 0; i < 16; i++)
-               whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
-
-       le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
-
-       return 0;
-}
-
-/**
- * pzl_clean_up - free PZL resources
- * @whc: the WHCI host controller
- *
- * The PZL is stopped and empty.
- */
-void pzl_clean_up(struct whc *whc)
-{
-       if (whc->pz_list)
-               dma_free_coherent(&whc->umc->dev,  sizeof(u64) * 16, whc->pz_list,
-                                 whc->pz_list_dma);
-}
diff --git a/drivers/staging/wusbcore/host/whci/qset.c b/drivers/staging/wusbcore/host/whci/qset.c
deleted file mode 100644 (file)
index 66459b7..0000000
+++ /dev/null
@@ -1,831 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) qset management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include "../../../uwb/include/umc.h"
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags)
-{
-       struct whc_qset *qset;
-       dma_addr_t dma;
-
-       qset = dma_pool_zalloc(whc->qset_pool, mem_flags, &dma);
-       if (qset == NULL)
-               return NULL;
-
-       qset->qset_dma = dma;
-       qset->whc = whc;
-
-       INIT_LIST_HEAD(&qset->list_node);
-       INIT_LIST_HEAD(&qset->stds);
-
-       return qset;
-}
-
-/**
- * qset_fill_qh - fill the static endpoint state in a qset's QHead
- * @qset: the qset whose QH needs initializing with static endpoint
- *        state
- * @urb:  an urb for a transfer to this endpoint
- */
-static void qset_fill_qh(struct whc *whc, struct whc_qset *qset, struct urb *urb)
-{
-       struct usb_device *usb_dev = urb->dev;
-       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
-       struct usb_wireless_ep_comp_descriptor *epcd;
-       bool is_out;
-       uint8_t phy_rate;
-
-       is_out = usb_pipeout(urb->pipe);
-
-       qset->max_packet = le16_to_cpu(urb->ep->desc.wMaxPacketSize);
-
-       epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra;
-       if (epcd) {
-               qset->max_seq = epcd->bMaxSequence;
-               qset->max_burst = epcd->bMaxBurst;
-       } else {
-               qset->max_seq = 2;
-               qset->max_burst = 1;
-       }
-
-       /*
-        * Initial PHY rate is 53.3 Mbit/s for control endpoints or
-        * the maximum supported by the device for other endpoints
-        * (unless limited by the user).
-        */
-       if (usb_pipecontrol(urb->pipe))
-               phy_rate = UWB_PHY_RATE_53;
-       else {
-               uint16_t phy_rates;
-
-               phy_rates = le16_to_cpu(wusb_dev->wusb_cap_descr->wPHYRates);
-               phy_rate = fls(phy_rates) - 1;
-               if (phy_rate > whc->wusbhc.phy_rate)
-                       phy_rate = whc->wusbhc.phy_rate;
-       }
-
-       qset->qh.info1 = cpu_to_le32(
-               QH_INFO1_EP(usb_pipeendpoint(urb->pipe))
-               | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN)
-               | usb_pipe_to_qh_type(urb->pipe)
-               | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum))
-               | QH_INFO1_MAX_PKT_LEN(qset->max_packet)
-               );
-       qset->qh.info2 = cpu_to_le32(
-               QH_INFO2_BURST(qset->max_burst)
-               | QH_INFO2_DBP(0)
-               | QH_INFO2_MAX_COUNT(3)
-               | QH_INFO2_MAX_RETRY(3)
-               | QH_INFO2_MAX_SEQ(qset->max_seq - 1)
-               );
-       /* FIXME: where can we obtain these Tx parameters from?  Why
-        * doesn't the chip know what Tx power to use? It knows the Rx
-        * strength and can presumably guess the Tx power required
-        * from that? */
-       qset->qh.info3 = cpu_to_le32(
-               QH_INFO3_TX_RATE(phy_rate)
-               | QH_INFO3_TX_PWR(0) /* 0 == max power */
-               );
-
-       qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
-}
-
-/**
- * qset_clear - clear fields in a qset so it may be reinserted into a
- * schedule.
- *
- * The sequence number and current window are not cleared (see
- * qset_reset()).
- */
-void qset_clear(struct whc *whc, struct whc_qset *qset)
-{
-       qset->td_start = qset->td_end = qset->ntds = 0;
-
-       qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
-       qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
-       qset->qh.err_count = 0;
-       qset->qh.scratch[0] = 0;
-       qset->qh.scratch[1] = 0;
-       qset->qh.scratch[2] = 0;
-
-       memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay));
-
-       init_completion(&qset->remove_complete);
-}
-
-/**
- * qset_reset - reset endpoint state in a qset.
- *
- * Clears the sequence number and current window.  This qset must not
- * be in the ASL or PZL.
- */
-void qset_reset(struct whc *whc, struct whc_qset *qset)
-{
-       qset->reset = 0;
-
-       qset->qh.status &= ~QH_STATUS_SEQ_MASK;
-       qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
-}
-
-/**
- * get_qset - get the qset for an async endpoint
- *
- * A new qset is created if one does not already exist.
- */
-struct whc_qset *get_qset(struct whc *whc, struct urb *urb,
-                                gfp_t mem_flags)
-{
-       struct whc_qset *qset;
-
-       qset = urb->ep->hcpriv;
-       if (qset == NULL) {
-               qset = qset_alloc(whc, mem_flags);
-               if (qset == NULL)
-                       return NULL;
-
-               qset->ep = urb->ep;
-               urb->ep->hcpriv = qset;
-               qset_fill_qh(whc, qset, urb);
-       }
-       return qset;
-}
-
-void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
-{
-       qset->remove = 0;
-       list_del_init(&qset->list_node);
-       complete(&qset->remove_complete);
-}
-
-/**
- * qset_add_qtds - add qTDs for an URB to a qset
- *
- * Returns true if the list (ASL/PZL) must be updated because (for a
- * WHCI 0.95 controller) an activated qTD was pointed to be iCur.
- */
-enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset)
-{
-       struct whc_std *std;
-       enum whc_update update = 0;
-
-       list_for_each_entry(std, &qset->stds, list_node) {
-               struct whc_qtd *qtd;
-               uint32_t status;
-
-               if (qset->ntds >= WHCI_QSET_TD_MAX
-                   || (qset->pause_after_urb && std->urb != qset->pause_after_urb))
-                       break;
-
-               if (std->qtd)
-                       continue; /* already has a qTD */
-
-               qtd = std->qtd = &qset->qtd[qset->td_end];
-
-               /* Fill in setup bytes for control transfers. */
-               if (usb_pipecontrol(std->urb->pipe))
-                       memcpy(qtd->setup, std->urb->setup_packet, 8);
-
-               status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len);
-
-               if (whc_std_last(std) && usb_pipeout(std->urb->pipe))
-                       status |= QTD_STS_LAST_PKT;
-
-               /*
-                * For an IN transfer the iAlt field should be set so
-                * the h/w will automatically advance to the next
-                * transfer. However, if there are 8 or more TDs
-                * remaining in this transfer then iAlt cannot be set
-                * as it could point to somewhere in this transfer.
-                */
-               if (std->ntds_remaining < WHCI_QSET_TD_MAX) {
-                       int ialt;
-                       ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX;
-                       status |= QTD_STS_IALT(ialt);
-               } else if (usb_pipein(std->urb->pipe))
-                       qset->pause_after_urb = std->urb;
-
-               if (std->num_pointers)
-                       qtd->options = cpu_to_le32(QTD_OPT_IOC);
-               else
-                       qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL);
-               qtd->page_list_ptr = cpu_to_le64(std->dma_addr);
-
-               qtd->status = cpu_to_le32(status);
-
-               if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end)
-                       update = WHC_UPDATE_UPDATED;
-
-               if (++qset->td_end >= WHCI_QSET_TD_MAX)
-                       qset->td_end = 0;
-               qset->ntds++;
-       }
-
-       return update;
-}
-
-/**
- * qset_remove_qtd - remove the first qTD from a qset.
- *
- * The qTD might be still active (if it's part of a IN URB that
- * resulted in a short read) so ensure it's deactivated.
- */
-static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset)
-{
-       qset->qtd[qset->td_start].status = 0;
-
-       if (++qset->td_start >= WHCI_QSET_TD_MAX)
-               qset->td_start = 0;
-       qset->ntds--;
-}
-
-static void qset_copy_bounce_to_sg(struct whc *whc, struct whc_std *std)
-{
-       struct scatterlist *sg;
-       void *bounce;
-       size_t remaining, offset;
-
-       bounce = std->bounce_buf;
-       remaining = std->len;
-
-       sg = std->bounce_sg;
-       offset = std->bounce_offset;
-
-       while (remaining) {
-               size_t len;
-
-               len = min(sg->length - offset, remaining);
-               memcpy(sg_virt(sg) + offset, bounce, len);
-
-               bounce += len;
-               remaining -= len;
-
-               offset += len;
-               if (offset >= sg->length) {
-                       sg = sg_next(sg);
-                       offset = 0;
-               }
-       }
-
-}
-
-/**
- * qset_free_std - remove an sTD and free it.
- * @whc: the WHCI host controller
- * @std: the sTD to remove and free.
- */
-void qset_free_std(struct whc *whc, struct whc_std *std)
-{
-       list_del(&std->list_node);
-       if (std->bounce_buf) {
-               bool is_out = usb_pipeout(std->urb->pipe);
-               dma_addr_t dma_addr;
-
-               if (std->num_pointers)
-                       dma_addr = le64_to_cpu(std->pl_virt[0].buf_ptr);
-               else
-                       dma_addr = std->dma_addr;
-
-               dma_unmap_single(whc->wusbhc.dev, dma_addr,
-                                std->len, is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               if (!is_out)
-                       qset_copy_bounce_to_sg(whc, std);
-               kfree(std->bounce_buf);
-       }
-       if (std->pl_virt) {
-               if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
-                       dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
-                                        std->num_pointers * sizeof(struct whc_page_list_entry),
-                                        DMA_TO_DEVICE);
-               kfree(std->pl_virt);
-               std->pl_virt = NULL;
-       }
-       kfree(std);
-}
-
-/**
- * qset_remove_qtds - remove an URB's qTDs (and sTDs).
- */
-static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset,
-                            struct urb *urb)
-{
-       struct whc_std *std, *t;
-
-       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb != urb)
-                       break;
-               if (std->qtd != NULL)
-                       qset_remove_qtd(whc, qset);
-               qset_free_std(whc, std);
-       }
-}
-
-/**
- * qset_free_stds - free any remaining sTDs for an URB.
- */
-static void qset_free_stds(struct whc_qset *qset, struct urb *urb)
-{
-       struct whc_std *std, *t;
-
-       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb == urb)
-                       qset_free_std(qset->whc, std);
-       }
-}
-
-static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags)
-{
-       dma_addr_t dma_addr = std->dma_addr;
-       dma_addr_t sp, ep;
-       size_t pl_len;
-       int p;
-
-       /* Short buffers don't need a page list. */
-       if (std->len <= WHCI_PAGE_SIZE) {
-               std->num_pointers = 0;
-               return 0;
-       }
-
-       sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
-       ep = dma_addr + std->len;
-       std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
-
-       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
-       std->pl_virt = kmalloc(pl_len, mem_flags);
-       if (std->pl_virt == NULL)
-               return -ENOMEM;
-       std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE);
-       if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) {
-               kfree(std->pl_virt);
-               return -EFAULT;
-       }
-
-       for (p = 0; p < std->num_pointers; p++) {
-               std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
-               dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
-       }
-
-       return 0;
-}
-
-/**
- * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system.
- */
-static void urb_dequeue_work(struct work_struct *work)
-{
-       struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work);
-       struct whc_qset *qset = wurb->qset;
-       struct whc *whc = qset->whc;
-       unsigned long flags;
-
-       if (wurb->is_async)
-               asl_update(whc, WUSBCMD_ASYNC_UPDATED
-                          | WUSBCMD_ASYNC_SYNCED_DB
-                          | WUSBCMD_ASYNC_QSET_RM);
-       else
-               pzl_update(whc, WUSBCMD_PERIODIC_UPDATED
-                          | WUSBCMD_PERIODIC_SYNCED_DB
-                          | WUSBCMD_PERIODIC_QSET_RM);
-
-       spin_lock_irqsave(&whc->lock, flags);
-       qset_remove_urb(whc, qset, wurb->urb, wurb->status);
-       spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-static struct whc_std *qset_new_std(struct whc *whc, struct whc_qset *qset,
-                                   struct urb *urb, gfp_t mem_flags)
-{
-       struct whc_std *std;
-
-       std = kzalloc(sizeof(struct whc_std), mem_flags);
-       if (std == NULL)
-               return NULL;
-
-       std->urb = urb;
-       std->qtd = NULL;
-
-       INIT_LIST_HEAD(&std->list_node);
-       list_add_tail(&std->list_node, &qset->stds);
-
-       return std;
-}
-
-static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *urb,
-                          gfp_t mem_flags)
-{
-       size_t remaining;
-       struct scatterlist *sg;
-       int i;
-       int ntds = 0;
-       struct whc_std *std = NULL;
-       struct whc_page_list_entry *new_pl_virt;
-       dma_addr_t prev_end = 0;
-       size_t pl_len;
-       int p = 0;
-
-       remaining = urb->transfer_buffer_length;
-
-       for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
-               dma_addr_t dma_addr;
-               size_t dma_remaining;
-               dma_addr_t sp, ep;
-               int num_pointers;
-
-               if (remaining == 0) {
-                       break;
-               }
-
-               dma_addr = sg_dma_address(sg);
-               dma_remaining = min_t(size_t, sg_dma_len(sg), remaining);
-
-               while (dma_remaining) {
-                       size_t dma_len;
-
-                       /*
-                        * We can use the previous std (if it exists) provided that:
-                        * - the previous one ended on a page boundary.
-                        * - the current one begins on a page boundary.
-                        * - the previous one isn't full.
-                        *
-                        * If a new std is needed but the previous one
-                        * was not a whole number of packets then this
-                        * sg list cannot be mapped onto multiple
-                        * qTDs.  Return an error and let the caller
-                        * sort it out.
-                        */
-                       if (!std
-                           || (prev_end & (WHCI_PAGE_SIZE-1))
-                           || (dma_addr & (WHCI_PAGE_SIZE-1))
-                           || std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) {
-                               if (std && std->len % qset->max_packet != 0)
-                                       return -EINVAL;
-                               std = qset_new_std(whc, qset, urb, mem_flags);
-                               if (std == NULL) {
-                                       return -ENOMEM;
-                               }
-                               ntds++;
-                               p = 0;
-                       }
-
-                       dma_len = dma_remaining;
-
-                       /*
-                        * If the remainder of this element doesn't
-                        * fit in a single qTD, limit the qTD to a
-                        * whole number of packets.  This allows the
-                        * remainder to go into the next qTD.
-                        */
-                       if (std->len + dma_len > QTD_MAX_XFER_SIZE) {
-                               dma_len = (QTD_MAX_XFER_SIZE / qset->max_packet)
-                                       * qset->max_packet - std->len;
-                       }
-
-                       std->len += dma_len;
-                       std->ntds_remaining = -1; /* filled in later */
-
-                       sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
-                       ep = dma_addr + dma_len;
-                       num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
-                       std->num_pointers += num_pointers;
-
-                       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
-
-                       new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
-                       if (new_pl_virt == NULL) {
-                               kfree(std->pl_virt);
-                               std->pl_virt = NULL;
-                               return -ENOMEM;
-                       }
-                       std->pl_virt = new_pl_virt;
-
-                       for (;p < std->num_pointers; p++) {
-                               std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
-                               dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
-                       }
-
-                       prev_end = dma_addr = ep;
-                       dma_remaining -= dma_len;
-                       remaining -= dma_len;
-               }
-       }
-
-       /* Now the number of stds is know, go back and fill in
-          std->ntds_remaining. */
-       list_for_each_entry(std, &qset->stds, list_node) {
-               if (std->ntds_remaining == -1) {
-                       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
-                       std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt,
-                                                      pl_len, DMA_TO_DEVICE);
-                       if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
-                               return -EFAULT;
-                       std->ntds_remaining = ntds--;
-               }
-       }
-       return 0;
-}
-
-/**
- * qset_add_urb_sg_linearize - add an urb with sg list, copying the data
- *
- * If the URB contains an sg list whose elements cannot be directly
- * mapped to qTDs then the data must be transferred via bounce
- * buffers.
- */
-static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
-                                    struct urb *urb, gfp_t mem_flags)
-{
-       bool is_out = usb_pipeout(urb->pipe);
-       size_t max_std_len;
-       size_t remaining;
-       int ntds = 0;
-       struct whc_std *std = NULL;
-       void *bounce = NULL;
-       struct scatterlist *sg;
-       int i;
-
-       /* limit maximum bounce buffer to 16 * 3.5 KiB ~= 28 k */
-       max_std_len = qset->max_burst * qset->max_packet;
-
-       remaining = urb->transfer_buffer_length;
-
-       for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
-               size_t len;
-               size_t sg_remaining;
-               void *orig;
-
-               if (remaining == 0) {
-                       break;
-               }
-
-               sg_remaining = min_t(size_t, remaining, sg->length);
-               orig = sg_virt(sg);
-
-               while (sg_remaining) {
-                       if (!std || std->len == max_std_len) {
-                               std = qset_new_std(whc, qset, urb, mem_flags);
-                               if (std == NULL)
-                                       return -ENOMEM;
-                               std->bounce_buf = kmalloc(max_std_len, mem_flags);
-                               if (std->bounce_buf == NULL)
-                                       return -ENOMEM;
-                               std->bounce_sg = sg;
-                               std->bounce_offset = orig - sg_virt(sg);
-                               bounce = std->bounce_buf;
-                               ntds++;
-                       }
-
-                       len = min(sg_remaining, max_std_len - std->len);
-
-                       if (is_out)
-                               memcpy(bounce, orig, len);
-
-                       std->len += len;
-                       std->ntds_remaining = -1; /* filled in later */
-
-                       bounce += len;
-                       orig += len;
-                       sg_remaining -= len;
-                       remaining -= len;
-               }
-       }
-
-       /*
-        * For each of the new sTDs, map the bounce buffers, create
-        * page lists (if necessary), and fill in std->ntds_remaining.
-        */
-       list_for_each_entry(std, &qset->stds, list_node) {
-               if (std->ntds_remaining != -1)
-                       continue;
-
-               std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len,
-                                              is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               if (dma_mapping_error(&whc->umc->dev, std->dma_addr))
-                       return -EFAULT;
-
-               if (qset_fill_page_list(whc, std, mem_flags) < 0)
-                       return -ENOMEM;
-
-               std->ntds_remaining = ntds--;
-       }
-
-       return 0;
-}
-
-/**
- * qset_add_urb - add an urb to the qset's queue.
- *
- * The URB is chopped into sTDs, one for each qTD that will required.
- * At least one qTD (and sTD) is required even if the transfer has no
- * data (e.g., for some control transfers).
- */
-int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
-       gfp_t mem_flags)
-{
-       struct whc_urb *wurb;
-       int remaining = urb->transfer_buffer_length;
-       u64 transfer_dma = urb->transfer_dma;
-       int ntds_remaining;
-       int ret;
-
-       wurb = kzalloc(sizeof(struct whc_urb), mem_flags);
-       if (wurb == NULL)
-               goto err_no_mem;
-       urb->hcpriv = wurb;
-       wurb->qset = qset;
-       wurb->urb = urb;
-       INIT_WORK(&wurb->dequeue_work, urb_dequeue_work);
-
-       if (urb->num_sgs) {
-               ret = qset_add_urb_sg(whc, qset, urb, mem_flags);
-               if (ret == -EINVAL) {
-                       qset_free_stds(qset, urb);
-                       ret = qset_add_urb_sg_linearize(whc, qset, urb, mem_flags);
-               }
-               if (ret < 0)
-                       goto err_no_mem;
-               return 0;
-       }
-
-       ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE);
-       if (ntds_remaining == 0)
-               ntds_remaining = 1;
-
-       while (ntds_remaining) {
-               struct whc_std *std;
-               size_t std_len;
-
-               std_len = remaining;
-               if (std_len > QTD_MAX_XFER_SIZE)
-                       std_len = QTD_MAX_XFER_SIZE;
-
-               std = qset_new_std(whc, qset, urb, mem_flags);
-               if (std == NULL)
-                       goto err_no_mem;
-
-               std->dma_addr = transfer_dma;
-               std->len = std_len;
-               std->ntds_remaining = ntds_remaining;
-
-               if (qset_fill_page_list(whc, std, mem_flags) < 0)
-                       goto err_no_mem;
-
-               ntds_remaining--;
-               remaining -= std_len;
-               transfer_dma += std_len;
-       }
-
-       return 0;
-
-err_no_mem:
-       qset_free_stds(qset, urb);
-       return -ENOMEM;
-}
-
-/**
- * qset_remove_urb - remove an URB from the urb queue.
- *
- * The URB is returned to the USB subsystem.
- */
-void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
-                           struct urb *urb, int status)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-       struct whc_urb *wurb = urb->hcpriv;
-
-       usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb);
-       /* Drop the lock as urb->complete() may enqueue another urb. */
-       spin_unlock(&whc->lock);
-       wusbhc_giveback_urb(wusbhc, urb, status);
-       spin_lock(&whc->lock);
-
-       kfree(wurb);
-}
-
-/**
- * get_urb_status_from_qtd - get the completed urb status from qTD status
- * @urb:    completed urb
- * @status: qTD status
- */
-static int get_urb_status_from_qtd(struct urb *urb, u32 status)
-{
-       if (status & QTD_STS_HALTED) {
-               if (status & QTD_STS_DBE)
-                       return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM;
-               else if (status & QTD_STS_BABBLE)
-                       return -EOVERFLOW;
-               else if (status & QTD_STS_RCE)
-                       return -ETIME;
-               return -EPIPE;
-       }
-       if (usb_pipein(urb->pipe)
-           && (urb->transfer_flags & URB_SHORT_NOT_OK)
-           && urb->actual_length < urb->transfer_buffer_length)
-               return -EREMOTEIO;
-       return 0;
-}
-
-/**
- * process_inactive_qtd - process an inactive (but not halted) qTD.
- *
- * Update the urb with the transfer bytes from the qTD, if the urb is
- * completely transferred or (in the case of an IN only) the LPF is
- * set, then the transfer is complete and the urb should be returned
- * to the system.
- */
-void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
-                                struct whc_qtd *qtd)
-{
-       struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
-       struct urb *urb = std->urb;
-       uint32_t status;
-       bool complete;
-
-       status = le32_to_cpu(qtd->status);
-
-       urb->actual_length += std->len - QTD_STS_TO_LEN(status);
-
-       if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT))
-               complete = true;
-       else
-               complete = whc_std_last(std);
-
-       qset_remove_qtd(whc, qset);
-       qset_free_std(whc, std);
-
-       /*
-        * Transfers for this URB are complete?  Then return it to the
-        * USB subsystem.
-        */
-       if (complete) {
-               qset_remove_qtds(whc, qset, urb);
-               qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status));
-
-               /*
-                * If iAlt isn't valid then the hardware didn't
-                * advance iCur. Adjust the start and end pointers to
-                * match iCur.
-                */
-               if (!(status & QTD_STS_IALT_VALID))
-                       qset->td_start = qset->td_end
-                               = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status));
-               qset->pause_after_urb = NULL;
-       }
-}
-
-/**
- * process_halted_qtd - process a qset with a halted qtd
- *
- * Remove all the qTDs for the failed URB and return the failed URB to
- * the USB subsystem.  Then remove all other qTDs so the qset can be
- * removed.
- *
- * FIXME: this is the point where rate adaptation can be done.  If a
- * transfer failed because it exceeded the maximum number of retries
- * then it could be reactivated with a slower rate without having to
- * remove the qset.
- */
-void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
-                              struct whc_qtd *qtd)
-{
-       struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
-       struct urb *urb = std->urb;
-       int urb_status;
-
-       urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status));
-
-       qset_remove_qtds(whc, qset, urb);
-       qset_remove_urb(whc, qset, urb, urb_status);
-
-       list_for_each_entry(std, &qset->stds, list_node) {
-               if (qset->ntds == 0)
-                       break;
-               qset_remove_qtd(whc, qset);
-               std->qtd = NULL;
-       }
-
-       qset->remove = 1;
-}
-
-void qset_free(struct whc *whc, struct whc_qset *qset)
-{
-       dma_pool_free(whc->qset_pool, qset, qset->qset_dma);
-}
-
-/**
- * qset_delete - wait for a qset to be unused, then free it.
- */
-void qset_delete(struct whc *whc, struct whc_qset *qset)
-{
-       wait_for_completion(&qset->remove_complete);
-       qset_free(whc, qset);
-}
diff --git a/drivers/staging/wusbcore/host/whci/whcd.h b/drivers/staging/wusbcore/host/whci/whcd.h
deleted file mode 100644 (file)
index a442a25..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) private header.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#ifndef __WHCD_H
-#define __WHCD_H
-
-#include <linux/workqueue.h>
-
-#include "../../../uwb/include/whci.h"
-#include "../../../uwb/include/umc.h"
-#include "whci-hc.h"
-
-/* Generic command timeout. */
-#define WHC_GENCMD_TIMEOUT_MS 100
-
-struct whc_dbg;
-
-struct whc {
-       struct wusbhc wusbhc;
-       struct umc_dev *umc;
-
-       resource_size_t base_phys;
-       void __iomem *base;
-       int irq;
-
-       u8 n_devices;
-       u8 n_keys;
-       u8 n_mmc_ies;
-
-       u64 *pz_list;
-       struct dn_buf_entry *dn_buf;
-       struct di_buf_entry *di_buf;
-       dma_addr_t pz_list_dma;
-       dma_addr_t dn_buf_dma;
-       dma_addr_t di_buf_dma;
-
-       spinlock_t   lock;
-       struct mutex mutex;
-
-       void *            gen_cmd_buf;
-       dma_addr_t        gen_cmd_buf_dma;
-       wait_queue_head_t cmd_wq;
-
-       struct workqueue_struct *workqueue;
-       struct work_struct       dn_work;
-
-       struct dma_pool *qset_pool;
-
-       struct list_head async_list;
-       struct list_head async_removed_list;
-       wait_queue_head_t async_list_wq;
-       struct work_struct async_work;
-
-       struct list_head periodic_list[5];
-       struct list_head periodic_removed_list;
-       wait_queue_head_t periodic_list_wq;
-       struct work_struct periodic_work;
-
-       struct whc_dbg *dbg;
-};
-
-#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc))
-
-/**
- * struct whc_std - a software TD.
- * @urb: the URB this sTD is for.
- * @offset: start of the URB's data for this TD.
- * @len: the length of data in the associated TD.
- * @ntds_remaining: number of TDs (starting from this one) in this transfer.
- *
- * @bounce_buf: a bounce buffer if the std was from an urb with a sg
- * list that could not be mapped to qTDs directly.
- * @bounce_sg: the first scatterlist element bounce_buf is for.
- * @bounce_offset: the offset into bounce_sg for the start of bounce_buf.
- *
- * Queued URBs may require more TDs than are available in a qset so we
- * use a list of these "software TDs" (sTDs) to hold per-TD data.
- */
-struct whc_std {
-       struct urb *urb;
-       size_t len;
-       int    ntds_remaining;
-       struct whc_qtd *qtd;
-
-       struct list_head list_node;
-       int num_pointers;
-       dma_addr_t dma_addr;
-       struct whc_page_list_entry *pl_virt;
-
-       void *bounce_buf;
-       struct scatterlist *bounce_sg;
-       unsigned bounce_offset;
-};
-
-/**
- * struct whc_urb - per URB host controller structure.
- * @urb: the URB this struct is for.
- * @qset: the qset associated to the URB.
- * @dequeue_work: the work to remove the URB when dequeued.
- * @is_async: the URB belongs to async sheduler or not.
- * @status: the status to be returned when calling wusbhc_giveback_urb.
- */
-struct whc_urb {
-       struct urb *urb;
-       struct whc_qset *qset;
-       struct work_struct dequeue_work;
-       bool is_async;
-       int status;
-};
-
-/**
- * whc_std_last - is this sTD the URB's last?
- * @std: the sTD to check.
- */
-static inline bool whc_std_last(struct whc_std *std)
-{
-       return std->ntds_remaining <= 1;
-}
-
-enum whc_update {
-       WHC_UPDATE_ADDED   = 0x01,
-       WHC_UPDATE_REMOVED = 0x02,
-       WHC_UPDATE_UPDATED = 0x04,
-};
-
-/* init.c */
-int whc_init(struct whc *whc);
-void whc_clean_up(struct whc *whc);
-
-/* hw.c */
-void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val);
-int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
-void whc_hw_error(struct whc *whc, const char *reason);
-
-/* wusb.c */
-int whc_wusbhc_start(struct wusbhc *wusbhc);
-void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay);
-int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
-                 u8 handle, struct wuie_hdr *wuie);
-int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
-int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm);
-int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
-int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots);
-int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
-               const void *ptk, size_t key_size);
-int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
-               const void *gtk, size_t key_size);
-int whc_set_cluster_id(struct whc *whc, u8 bcid);
-
-/* int.c */
-irqreturn_t whc_int_handler(struct usb_hcd *hcd);
-void whc_dn_work(struct work_struct *work);
-
-/* asl.c */
-void asl_start(struct whc *whc);
-void asl_stop(struct whc *whc);
-int  asl_init(struct whc *whc);
-void asl_clean_up(struct whc *whc);
-int  asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-int  asl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
-void asl_qset_delete(struct whc *whc, struct whc_qset *qset);
-void scan_async_work(struct work_struct *work);
-
-/* pzl.c */
-int  pzl_init(struct whc *whc);
-void pzl_clean_up(struct whc *whc);
-void pzl_start(struct whc *whc);
-void pzl_stop(struct whc *whc);
-int  pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-int  pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
-void pzl_qset_delete(struct whc *whc, struct whc_qset *qset);
-void scan_periodic_work(struct work_struct *work);
-
-/* qset.c */
-struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags);
-void qset_free(struct whc *whc, struct whc_qset *qset);
-struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-void qset_delete(struct whc *whc, struct whc_qset *qset);
-void qset_clear(struct whc *whc, struct whc_qset *qset);
-void qset_reset(struct whc *whc, struct whc_qset *qset);
-int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
-                gfp_t mem_flags);
-void qset_free_std(struct whc *whc, struct whc_std *std);
-void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
-                           struct urb *urb, int status);
-void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
-                              struct whc_qtd *qtd);
-void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
-                                struct whc_qtd *qtd);
-enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset);
-void qset_remove_complete(struct whc *whc, struct whc_qset *qset);
-void pzl_update(struct whc *whc, uint32_t wusbcmd);
-void asl_update(struct whc *whc, uint32_t wusbcmd);
-
-/* debug.c */
-void whc_dbg_init(struct whc *whc);
-void whc_dbg_clean_up(struct whc *whc);
-
-#endif /* #ifndef __WHCD_H */
diff --git a/drivers/staging/wusbcore/host/whci/whci-hc.h b/drivers/staging/wusbcore/host/whci/whci-hc.h
deleted file mode 100644 (file)
index 5a86a57..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) data structures.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#ifndef _WHCI_WHCI_HC_H
-#define _WHCI_WHCI_HC_H
-
-#include <linux/list.h>
-
-/**
- * WHCI_PAGE_SIZE - page size use by WHCI
- *
- * WHCI assumes that host system uses pages of 4096 octets.
- */
-#define WHCI_PAGE_SIZE 4096
-
-
-/**
- * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single
- * qtd.
- *
- * This is 2^20 - 1.
- */
-#define QTD_MAX_XFER_SIZE 1048575
-
-
-/**
- * struct whc_qtd - Queue Element Transfer Descriptors (qTD)
- *
- * This describes the data for a bulk, control or interrupt transfer.
- *
- * [WHCI] section 3.2.4
- */
-struct whc_qtd {
-       __le32 status; /*< remaining transfer len and transfer status */
-       __le32 options;
-       __le64 page_list_ptr; /*< physical pointer to data buffer page list*/
-       __u8   setup[8];      /*< setup data for control transfers */
-} __attribute__((packed));
-
-#define QTD_STS_ACTIVE     (1 << 31)  /* enable execution of transaction */
-#define QTD_STS_HALTED     (1 << 30)  /* transfer halted */
-#define QTD_STS_DBE        (1 << 29)  /* data buffer error */
-#define QTD_STS_BABBLE     (1 << 28)  /* babble detected */
-#define QTD_STS_RCE        (1 << 27)  /* retry count exceeded */
-#define QTD_STS_LAST_PKT   (1 << 26)  /* set Last Packet Flag in WUSB header */
-#define QTD_STS_INACTIVE   (1 << 25)  /* queue set is marked inactive */
-#define QTD_STS_IALT_VALID (1 << 23)                          /* iAlt field is valid */
-#define QTD_STS_IALT(i)    (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */
-#define QTD_STS_LEN(l)     ((l) << 0) /* transfer length */
-#define QTD_STS_TO_LEN(s)  ((s) & 0x000fffff)
-
-#define QTD_OPT_IOC      (1 << 1) /* page_list_ptr points to buffer directly */
-#define QTD_OPT_SMALL    (1 << 0) /* interrupt on complete */
-
-/**
- * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD)
- *
- * This describes the data and other parameters for an isochronous
- * transfer.
- *
- * [WHCI] section 3.2.5
- */
-struct whc_itd {
-       __le16 presentation_time;    /*< presentation time for OUT transfers */
-       __u8   num_segments;         /*< number of data segments in segment list */
-       __u8   status;               /*< command execution status */
-       __le32 options;              /*< misc transfer options */
-       __le64 page_list_ptr;        /*< physical pointer to data buffer page list */
-       __le64 seg_list_ptr;         /*< physical pointer to segment list */
-} __attribute__((packed));
-
-#define ITD_STS_ACTIVE   (1 << 7) /* enable execution of transaction */
-#define ITD_STS_DBE      (1 << 5) /* data buffer error */
-#define ITD_STS_BABBLE   (1 << 4) /* babble detected */
-#define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */
-
-#define ITD_OPT_IOC      (1 << 1) /* interrupt on complete */
-#define ITD_OPT_SMALL    (1 << 0) /* page_list_ptr points to buffer directly */
-
-/**
- * Page list entry.
- *
- * A TD's page list must contain sufficient page list entries for the
- * total data length in the TD.
- *
- * [WHCI] section 3.2.4.3
- */
-struct whc_page_list_entry {
-       __le64 buf_ptr; /*< physical pointer to buffer */
-} __attribute__((packed));
-
-/**
- * struct whc_seg_list_entry - Segment list entry.
- *
- * Describes a portion of the data buffer described in the containing
- * qTD's page list.
- *
- * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr
- *           + qtd->seg_list_ptr[seg].offset;
- *
- * Segments can't cross page boundries.
- *
- * [WHCI] section 3.2.5.5
- */
-struct whc_seg_list_entry {
-       __le16 len;    /*< segment length */
-       __u8   idx;    /*< index into page list */
-       __u8   status; /*< segment status */
-       __le16 offset; /*< 12 bit offset into page */
-} __attribute__((packed));
-
-/**
- * struct whc_qhead - endpoint and status information for a qset.
- *
- * [WHCI] section 3.2.6
- */
-struct whc_qhead {
-       __le64 link; /*< next qset in list */
-       __le32 info1;
-       __le32 info2;
-       __le32 info3;
-       __le16 status;
-       __le16 err_count;  /*< transaction error count */
-       __le32 cur_window;
-       __le32 scratch[3]; /*< h/w scratch area */
-       union {
-               struct whc_qtd qtd;
-               struct whc_itd itd;
-       } overlay;
-} __attribute__((packed));
-
-#define QH_LINK_PTR_MASK (~0x03Full)
-#define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK)
-#define QH_LINK_IQS      (1 << 4) /* isochronous queue set */
-#define QH_LINK_NTDS(n)  (((n) - 1) << 1) /* number of TDs in queue set */
-#define QH_LINK_T        (1 << 0) /* last queue set in periodic schedule list */
-
-#define QH_INFO1_EP(e)           ((e) << 0)  /* endpoint number */
-#define QH_INFO1_DIR_IN          (1 << 4)    /* IN transfer */
-#define QH_INFO1_DIR_OUT         (0 << 4)    /* OUT transfer */
-#define QH_INFO1_TR_TYPE_CTRL    (0x0 << 5)  /* control transfer */
-#define QH_INFO1_TR_TYPE_ISOC    (0x1 << 5)  /* isochronous transfer */
-#define QH_INFO1_TR_TYPE_BULK    (0x2 << 5)  /* bulk transfer */
-#define QH_INFO1_TR_TYPE_INT     (0x3 << 5)  /* interrupt */
-#define QH_INFO1_TR_TYPE_LP_INT  (0x7 << 5)  /* low power interrupt */
-#define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8)  /* index into device info buffer */
-#define QH_INFO1_SET_INACTIVE    (1 << 15)   /* set inactive after transfer */
-#define QH_INFO1_MAX_PKT_LEN(l)  ((l) << 16) /* maximum packet length */
-
-#define QH_INFO2_BURST(b)        ((b) << 0)  /* maximum burst length */
-#define QH_INFO2_DBP(p)          ((p) << 5)  /* data burst policy (see [WUSB] table 5-7) */
-#define QH_INFO2_MAX_COUNT(c)    ((c) << 8)  /* max isoc/int pkts per zone */
-#define QH_INFO2_RQS             (1 << 15)   /* reactivate queue set */
-#define QH_INFO2_MAX_RETRY(r)    ((r) << 16) /* maximum transaction retries */
-#define QH_INFO2_MAX_SEQ(s)      ((s) << 20) /* maximum sequence number */
-#define QH_INFO3_MAX_DELAY(d)    ((d) << 0)  /* maximum stream delay in 125 us units (isoc only) */
-#define QH_INFO3_INTERVAL(i)     ((i) << 16) /* segment interval in 125 us units (isoc only) */
-
-#define QH_INFO3_TX_RATE(r)      ((r) << 24) /* PHY rate (see [ECMA-368] section 10.3.1.1) */
-#define QH_INFO3_TX_PWR(p)       ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */
-
-#define QH_STATUS_FLOW_CTRL      (1 << 15)
-#define QH_STATUS_ICUR(i)        ((i) << 5)
-#define QH_STATUS_TO_ICUR(s)     (((s) >> 5) & 0x7)
-#define QH_STATUS_SEQ_MASK       0x1f
-
-/**
- * usb_pipe_to_qh_type - USB core pipe type to QH transfer type
- *
- * Returns the QH type field for a USB core pipe type.
- */
-static inline unsigned usb_pipe_to_qh_type(unsigned pipe)
-{
-       static const unsigned type[] = {
-               [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC,
-               [PIPE_INTERRUPT]   = QH_INFO1_TR_TYPE_INT,
-               [PIPE_CONTROL]     = QH_INFO1_TR_TYPE_CTRL,
-               [PIPE_BULK]        = QH_INFO1_TR_TYPE_BULK,
-       };
-       return type[usb_pipetype(pipe)];
-}
-
-/**
- * Maxiumum number of TDs in a qset.
- */
-#define WHCI_QSET_TD_MAX 8
-
-/**
- * struct whc_qset - WUSB data transfers to a specific endpoint
- * @qh: the QHead of this qset
- * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt
- * transfers)
- * @itd: up to 8 iTDs (for qsets for isochronous transfers)
- * @qset_dma: DMA address for this qset
- * @whc: WHCI HC this qset is for
- * @ep: endpoint
- * @stds: list of sTDs queued to this qset
- * @ntds: number of qTDs queued (not necessarily the same as nTDs
- * field in the QH)
- * @td_start: index of the first qTD in the list
- * @td_end: index of next free qTD in the list (provided
- *          ntds < WHCI_QSET_TD_MAX)
- *
- * Queue Sets (qsets) are added to the asynchronous schedule list
- * (ASL) or the periodic zone list (PZL).
- *
- * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate).
- * Each TD may refer to at most 1 MiB of data. If a single transfer
- * has > 8MiB of data, TDs can be reused as they are completed since
- * the TD list is used as a circular buffer.  Similarly, several
- * (smaller) transfers may be queued in a qset.
- *
- * WHCI controllers may cache portions of the qsets in the ASL and
- * PZL, requiring the WHCD to inform the WHC that the lists have been
- * updated (fields changed or qsets inserted or removed).  For safe
- * insertion and removal of qsets from the lists the schedule must be
- * stopped to avoid races in updating the QH link pointers.
- *
- * Since the HC is free to execute qsets in any order, all transfers
- * to an endpoint should use the same qset to ensure transfers are
- * executed in the order they're submitted.
- *
- * [WHCI] section 3.2.3
- */
-struct whc_qset {
-       struct whc_qhead qh;
-       union {
-               struct whc_qtd qtd[WHCI_QSET_TD_MAX];
-               struct whc_itd itd[WHCI_QSET_TD_MAX];
-       };
-
-       /* private data for WHCD */
-       dma_addr_t qset_dma;
-       struct whc *whc;
-       struct usb_host_endpoint *ep;
-       struct list_head stds;
-       int ntds;
-       int td_start;
-       int td_end;
-       struct list_head list_node;
-       unsigned in_sw_list:1;
-       unsigned in_hw_list:1;
-       unsigned remove:1;
-       unsigned reset:1;
-       struct urb *pause_after_urb;
-       struct completion remove_complete;
-       uint16_t max_packet;
-       uint8_t max_burst;
-       uint8_t max_seq;
-};
-
-static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target)
-{
-       if (target)
-               *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target);
-       else
-               *ptr = QH_LINK_T;
-}
-
-/**
- * struct di_buf_entry - Device Information (DI) buffer entry.
- *
- * There's one of these per connected device.
- */
-struct di_buf_entry {
-       __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */
-       __le32 addr_sec_info;        /*< addressing and security info */
-       __le32 reserved[7];
-} __attribute__((packed));
-
-#define WHC_DI_SECURE           (1 << 31)
-#define WHC_DI_DISABLE          (1 << 30)
-#define WHC_DI_KEY_IDX(k)       ((k) << 8)
-#define WHC_DI_KEY_IDX_MASK     0x0000ff00
-#define WHC_DI_DEV_ADDR(a)      ((a) << 0)
-#define WHC_DI_DEV_ADDR_MASK    0x000000ff
-
-/**
- * struct dn_buf_entry - Device Notification (DN) buffer entry.
- *
- * [WHCI] section 3.2.8
- */
-struct dn_buf_entry {
-       __u8   msg_size;    /*< number of octets of valid DN data */
-       __u8   reserved1;
-       __u8   src_addr;    /*< source address */
-       __u8   status;      /*< buffer entry status */
-       __le32 tkid;        /*< TKID for source device, valid if secure bit is set */
-       __u8   dn_data[56]; /*< up to 56 octets of DN data */
-} __attribute__((packed));
-
-#define WHC_DN_STATUS_VALID  (1 << 7) /* buffer entry is valid */
-#define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */
-
-#define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry))
-
-/* The Add MMC IE WUSB Generic Command may take up to 256 bytes of
-   data. [WHCI] section 2.4.7. */
-#define WHC_GEN_CMD_DATA_LEN 256
-
-/*
- * HC registers.
- *
- * [WHCI] section 2.4
- */
-
-#define WHCIVERSION          0x00
-
-#define WHCSPARAMS           0x04
-#  define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff)
-#  define WHCSPARAMS_TO_N_KEYS(p)    (((p) >> 8) & 0xff)
-#  define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f)
-
-#define WUSBCMD              0x08
-#  define WUSBCMD_BCID(b)            ((b) << 16)
-#  define WUSBCMD_BCID_MASK          (0xff << 16)
-#  define WUSBCMD_ASYNC_QSET_RM      (1 << 12)
-#  define WUSBCMD_PERIODIC_QSET_RM   (1 << 11)
-#  define WUSBCMD_WUSBSI(s)          ((s) << 8)
-#  define WUSBCMD_WUSBSI_MASK        (0x7 << 8)
-#  define WUSBCMD_ASYNC_SYNCED_DB    (1 << 7)
-#  define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6)
-#  define WUSBCMD_ASYNC_UPDATED      (1 << 5)
-#  define WUSBCMD_PERIODIC_UPDATED   (1 << 4)
-#  define WUSBCMD_ASYNC_EN           (1 << 3)
-#  define WUSBCMD_PERIODIC_EN        (1 << 2)
-#  define WUSBCMD_WHCRESET           (1 << 1)
-#  define WUSBCMD_RUN                (1 << 0)
-
-#define WUSBSTS              0x0c
-#  define WUSBSTS_ASYNC_SCHED             (1 << 15)
-#  define WUSBSTS_PERIODIC_SCHED          (1 << 14)
-#  define WUSBSTS_DNTS_SCHED              (1 << 13)
-#  define WUSBSTS_HCHALTED                (1 << 12)
-#  define WUSBSTS_GEN_CMD_DONE            (1 << 9)
-#  define WUSBSTS_CHAN_TIME_ROLLOVER      (1 << 8)
-#  define WUSBSTS_DNTS_OVERFLOW           (1 << 7)
-#  define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6)
-#  define WUSBSTS_HOST_ERR                (1 << 5)
-#  define WUSBSTS_ASYNC_SCHED_SYNCED      (1 << 4)
-#  define WUSBSTS_PERIODIC_SCHED_SYNCED   (1 << 3)
-#  define WUSBSTS_DNTS_INT                (1 << 2)
-#  define WUSBSTS_ERR_INT                 (1 << 1)
-#  define WUSBSTS_INT                     (1 << 0)
-#  define WUSBSTS_INT_MASK                0x3ff
-
-#define WUSBINTR             0x10
-#  define WUSBINTR_GEN_CMD_DONE             (1 << 9)
-#  define WUSBINTR_CHAN_TIME_ROLLOVER       (1 << 8)
-#  define WUSBINTR_DNTS_OVERFLOW            (1 << 7)
-#  define WUSBINTR_BPST_ADJUSTMENT_CHANGED  (1 << 6)
-#  define WUSBINTR_HOST_ERR                 (1 << 5)
-#  define WUSBINTR_ASYNC_SCHED_SYNCED       (1 << 4)
-#  define WUSBINTR_PERIODIC_SCHED_SYNCED    (1 << 3)
-#  define WUSBINTR_DNTS_INT                 (1 << 2)
-#  define WUSBINTR_ERR_INT                  (1 << 1)
-#  define WUSBINTR_INT                      (1 << 0)
-#  define WUSBINTR_ALL 0x3ff
-
-#define WUSBGENCMDSTS        0x14
-#  define WUSBGENCMDSTS_ACTIVE (1 << 31)
-#  define WUSBGENCMDSTS_ERROR  (1 << 24)
-#  define WUSBGENCMDSTS_IOC    (1 << 23)
-#  define WUSBGENCMDSTS_MMCIE_ADD 0x01
-#  define WUSBGENCMDSTS_MMCIE_RM  0x02
-#  define WUSBGENCMDSTS_SET_MAS   0x03
-#  define WUSBGENCMDSTS_CHAN_STOP 0x04
-#  define WUSBGENCMDSTS_RWP_EN    0x05
-
-#define WUSBGENCMDPARAMS     0x18
-#define WUSBGENADDR          0x20
-#define WUSBASYNCLISTADDR    0x28
-#define WUSBDNTSBUFADDR      0x30
-#define WUSBDEVICEINFOADDR   0x38
-
-#define WUSBSETSECKEYCMD     0x40
-#  define WUSBSETSECKEYCMD_SET    (1 << 31)
-#  define WUSBSETSECKEYCMD_ERASE  (1 << 30)
-#  define WUSBSETSECKEYCMD_GTK    (1 << 8)
-#  define WUSBSETSECKEYCMD_IDX(i) ((i) << 0)
-
-#define WUSBTKID             0x44
-#define WUSBSECKEY           0x48
-#define WUSBPERIODICLISTBASE 0x58
-#define WUSBMASINDEX         0x60
-
-#define WUSBDNTSCTRL         0x64
-#  define WUSBDNTSCTRL_ACTIVE      (1 << 31)
-#  define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8)
-#  define WUSBDNTSCTRL_SLOTS(s)    ((s) << 0)
-
-#define WUSBTIME             0x68
-#  define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff
-
-#define WUSBBPST             0x6c
-#define WUSBDIBUPDATED       0x70
-
-#endif /* #ifndef _WHCI_WHCI_HC_H */
diff --git a/drivers/staging/wusbcore/host/whci/wusb.c b/drivers/staging/wusbcore/host/whci/wusb.c
deleted file mode 100644 (file)
index 6d0068a..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) WUSB operations.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-
-#include "../../../uwb/include/umc.h"
-#include "../../wusbhc.h"
-
-#include "whcd.h"
-
-static int whc_update_di(struct whc *whc, int idx)
-{
-       int offset = idx / 32;
-       u32 bit = 1 << (idx % 32);
-
-       le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
-
-       return whci_wait_for(&whc->umc->dev,
-                            whc->base + WUSBDIBUPDATED + offset, bit, 0,
-                            100, "DI update");
-}
-
-/*
- * WHCI starts MMCs based on there being a valid GTK so these need
- * only start/stop the asynchronous and periodic schedules and send a
- * channel stop command.
- */
-
-int whc_wusbhc_start(struct wusbhc *wusbhc)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-
-       asl_start(whc);
-       pzl_start(whc);
-
-       return 0;
-}
-
-void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 stop_time, now_time;
-       int ret;
-
-       pzl_stop(whc);
-       asl_stop(whc);
-
-       now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
-       stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
-       ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
-       if (ret == 0)
-               msleep(delay);
-}
-
-int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
-                 u8 handle, struct wuie_hdr *wuie)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 params;
-
-       params = (interval << 24)
-               | (repeat_cnt << 16)
-               | (wuie->bLength << 8)
-               | handle;
-
-       return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength);
-}
-
-int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 params;
-
-       params = handle;
-
-       return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0);
-}
-
-int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-
-       if (stream_index >= 0)
-               whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index));
-
-       return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm));
-}
-
-int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       int idx = wusb_dev->port_idx;
-       struct di_buf_entry *di = &whc->di_buf[idx];
-       int ret;
-
-       mutex_lock(&whc->mutex);
-
-       uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability);
-       di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK);
-       di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr);
-
-       ret = whc_update_di(whc, idx);
-
-       mutex_unlock(&whc->mutex);
-
-       return ret;
-}
-
-/*
- * Set the number of Device Notification Time Slots (DNTS) and enable
- * device notifications.
- */
-int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 dntsctrl;
-
-       dntsctrl = WUSBDNTSCTRL_ACTIVE
-               | WUSBDNTSCTRL_INTERVAL(interval)
-               | WUSBDNTSCTRL_SLOTS(slots);
-
-       le_writel(dntsctrl, whc->base + WUSBDNTSCTRL);
-
-       return 0;
-}
-
-static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid,
-                      const void *key, size_t key_size, bool is_gtk)
-{
-       uint32_t setkeycmd;
-       uint32_t seckey[4];
-       int i;
-       int ret;
-
-       memcpy(seckey, key, key_size);
-       setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index);
-       if (is_gtk)
-               setkeycmd |= WUSBSETSECKEYCMD_GTK;
-
-       le_writel(tkid, whc->base + WUSBTKID);
-       for (i = 0; i < 4; i++)
-               le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i);
-       le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD);
-
-       ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD,
-                           WUSBSETSECKEYCMD_SET, 0, 100, "set key");
-
-       return ret;
-}
-
-/**
- * whc_set_ptk - set the PTK to use for a device.
- *
- * The index into the key table for this PTK is the same as the
- * device's port index.
- */
-int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
-               const void *ptk, size_t key_size)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       struct di_buf_entry *di = &whc->di_buf[port_idx];
-       int ret;
-
-       mutex_lock(&whc->mutex);
-
-       if (ptk) {
-               ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false);
-               if (ret)
-                       goto out;
-
-               di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK;
-               di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx);
-       } else
-               di->addr_sec_info &= ~WHC_DI_SECURE;
-
-       ret = whc_update_di(whc, port_idx);
-out:
-       mutex_unlock(&whc->mutex);
-       return ret;
-}
-
-/**
- * whc_set_gtk - set the GTK for subsequent broadcast packets
- *
- * The GTK is stored in the last entry in the key table (the previous
- * N_DEVICES entries are for the per-device PTKs).
- */
-int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
-               const void *gtk, size_t key_size)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       int ret;
-
-       mutex_lock(&whc->mutex);
-
-       ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true);
-
-       mutex_unlock(&whc->mutex);
-
-       return ret;
-}
-
-int whc_set_cluster_id(struct whc *whc, u8 bcid)
-{
-       whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid));
-       return 0;
-}
diff --git a/drivers/staging/wusbcore/include/association.h b/drivers/staging/wusbcore/include/association.h
deleted file mode 100644 (file)
index d7f3cb9..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB - Cable Based Association
- *
- * Copyright (C) 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.
- *
- */
-#ifndef __LINUX_USB_ASSOCIATION_H
-#define __LINUX_USB_ASSOCIATION_H
-
-
-/*
- * Association attributes
- *
- * Association Models Supplement to WUSB 1.0 T[3-1]
- *
- * Each field in the structures has it's ID, it's length and then the
- * value. This is the actual definition of the field's ID and its
- * length.
- */
-struct wusb_am_attr {
-       __u8 id;
-       __u8 len;
-};
-
-/* Different fields defined by the spec */
-#define WUSB_AR_AssociationTypeId      { .id = cpu_to_le16(0x0000), .len = cpu_to_le16(2) }
-#define WUSB_AR_AssociationSubTypeId   { .id = cpu_to_le16(0x0001), .len = cpu_to_le16(2) }
-#define WUSB_AR_Length                 { .id = cpu_to_le16(0x0002), .len = cpu_to_le16(4) }
-#define WUSB_AR_AssociationStatus      { .id = cpu_to_le16(0x0004), .len = cpu_to_le16(4) }
-#define WUSB_AR_LangID                 { .id = cpu_to_le16(0x0008), .len = cpu_to_le16(2) }
-#define WUSB_AR_DeviceFriendlyName     { .id = cpu_to_le16(0x000b), .len = cpu_to_le16(64) } /* max */
-#define WUSB_AR_HostFriendlyName       { .id = cpu_to_le16(0x000c), .len = cpu_to_le16(64) } /* max */
-#define WUSB_AR_CHID                   { .id = cpu_to_le16(0x1000), .len = cpu_to_le16(16) }
-#define WUSB_AR_CDID                   { .id = cpu_to_le16(0x1001), .len = cpu_to_le16(16) }
-#define WUSB_AR_ConnectionContext      { .id = cpu_to_le16(0x1002), .len = cpu_to_le16(48) }
-#define WUSB_AR_BandGroups             { .id = cpu_to_le16(0x1004), .len = cpu_to_le16(2) }
-
-/* CBAF Control Requests (AMS1.0[T4-1] */
-enum {
-       CBAF_REQ_GET_ASSOCIATION_INFORMATION = 0x01,
-       CBAF_REQ_GET_ASSOCIATION_REQUEST,
-       CBAF_REQ_SET_ASSOCIATION_RESPONSE
-};
-
-/*
- * CBAF USB-interface defitions
- *
- * No altsettings, one optional interrupt endpoint.
- */
-enum {
-       CBAF_IFACECLASS    = 0xef,
-       CBAF_IFACESUBCLASS = 0x03,
-       CBAF_IFACEPROTOCOL = 0x01,
-};
-
-/* Association Information (AMS1.0[T4-3]) */
-struct wusb_cbaf_assoc_info {
-       __le16 Length;
-       __u8 NumAssociationRequests;
-       __le16 Flags;
-       __u8 AssociationRequestsArray[];
-} __attribute__((packed));
-
-/* Association Request (AMS1.0[T4-4]) */
-struct wusb_cbaf_assoc_request {
-       __u8 AssociationDataIndex;
-       __u8 Reserved;
-       __le16 AssociationTypeId;
-       __le16 AssociationSubTypeId;
-       __le32 AssociationTypeInfoSize;
-} __attribute__((packed));
-
-enum {
-       AR_TYPE_WUSB                    = 0x0001,
-       AR_TYPE_WUSB_RETRIEVE_HOST_INFO = 0x0000,
-       AR_TYPE_WUSB_ASSOCIATE          = 0x0001,
-};
-
-/* Association Attribute header (AMS1.0[3.8]) */
-struct wusb_cbaf_attr_hdr {
-       __le16 id;
-       __le16 len;
-} __attribute__((packed));
-
-/* Host Info (AMS1.0[T4-7]) (yeah, more headers and fields...) */
-struct wusb_cbaf_host_info {
-       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
-       __le16 AssociationTypeId;
-       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
-       __le16 AssociationSubTypeId;
-       struct wusb_cbaf_attr_hdr CHID_hdr;
-       struct wusb_ckhdid CHID;
-       struct wusb_cbaf_attr_hdr LangID_hdr;
-       __le16 LangID;
-       struct wusb_cbaf_attr_hdr HostFriendlyName_hdr;
-       __u8 HostFriendlyName[];
-} __attribute__((packed));
-
-/* Device Info (AMS1.0[T4-8])
- *
- * I still don't get this tag'n'header stuff for each goddamn
- * field...
- */
-struct wusb_cbaf_device_info {
-       struct wusb_cbaf_attr_hdr Length_hdr;
-       __le32 Length;
-       struct wusb_cbaf_attr_hdr CDID_hdr;
-       struct wusb_ckhdid CDID;
-       struct wusb_cbaf_attr_hdr BandGroups_hdr;
-       __le16 BandGroups;
-       struct wusb_cbaf_attr_hdr LangID_hdr;
-       __le16 LangID;
-       struct wusb_cbaf_attr_hdr DeviceFriendlyName_hdr;
-       __u8 DeviceFriendlyName[];
-} __attribute__((packed));
-
-/* Connection Context; CC_DATA - Success case (AMS1.0[T4-9]) */
-struct wusb_cbaf_cc_data {
-       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
-       __le16 AssociationTypeId;
-       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
-       __le16 AssociationSubTypeId;
-       struct wusb_cbaf_attr_hdr Length_hdr;
-       __le32 Length;
-       struct wusb_cbaf_attr_hdr ConnectionContext_hdr;
-       struct wusb_ckhdid CHID;
-       struct wusb_ckhdid CDID;
-       struct wusb_ckhdid CK;
-       struct wusb_cbaf_attr_hdr BandGroups_hdr;
-       __le16 BandGroups;
-} __attribute__((packed));
-
-/* CC_DATA - Failure case (AMS1.0[T4-10]) */
-struct wusb_cbaf_cc_data_fail {
-       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
-       __le16 AssociationTypeId;
-       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
-       __le16 AssociationSubTypeId;
-       struct wusb_cbaf_attr_hdr Length_hdr;
-       __le16 Length;
-       struct wusb_cbaf_attr_hdr AssociationStatus_hdr;
-       __u32 AssociationStatus;
-} __attribute__((packed));
-
-#endif /* __LINUX_USB_ASSOCIATION_H */
diff --git a/drivers/staging/wusbcore/include/wusb-wa.h b/drivers/staging/wusbcore/include/wusb-wa.h
deleted file mode 100644 (file)
index 64a840b..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Wire Adapter constants and structures.
- *
- * 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.
- *
- *
- * FIXME: docs
- * FIXME: organize properly, group logically
- *
- * All the event structures are defined in uwb/spec.h, as they are
- * common to the WHCI and WUSB radio control interfaces.
- *
- * References:
- *   [WUSB] Wireless Universal Serial Bus Specification, revision 1.0, ch8
- */
-#ifndef __LINUX_USB_WUSB_WA_H
-#define __LINUX_USB_WUSB_WA_H
-
-/**
- * Radio Command Request for the Radio Control Interface
- *
- * Radio Control Interface command and event codes are the same as
- * WHCI, and listed in include/linux/uwb.h:UWB_RC_{CMD,EVT}_*
- */
-enum {
-       WA_EXEC_RC_CMD = 40,    /* Radio Control command Request */
-};
-
-/* Wireless Adapter Requests ([WUSB] table 8-51) */
-enum {
-       WUSB_REQ_ADD_MMC_IE     = 20,
-       WUSB_REQ_REMOVE_MMC_IE  = 21,
-       WUSB_REQ_SET_NUM_DNTS   = 22,
-       WUSB_REQ_SET_CLUSTER_ID = 23,
-       WUSB_REQ_SET_DEV_INFO   = 24,
-       WUSB_REQ_GET_TIME       = 25,
-       WUSB_REQ_SET_STREAM_IDX = 26,
-       WUSB_REQ_SET_WUSB_MAS   = 27,
-       WUSB_REQ_CHAN_STOP      = 28,
-};
-
-
-/* Wireless Adapter WUSB Channel Time types ([WUSB] table 8-52) */
-enum {
-       WUSB_TIME_ADJ   = 0,
-       WUSB_TIME_BPST  = 1,
-       WUSB_TIME_WUSB  = 2,
-};
-
-enum {
-       WA_ENABLE = 0x01,
-       WA_RESET = 0x02,
-       RPIPE_PAUSE = 0x1,
-       RPIPE_STALL = 0x2,
-};
-
-/* Responses from Get Status request ([WUSB] section 8.3.1.6) */
-enum {
-       WA_STATUS_ENABLED = 0x01,
-       WA_STATUS_RESETTING = 0x02
-};
-
-enum rpipe_crs {
-       RPIPE_CRS_CTL = 0x01,
-       RPIPE_CRS_ISO = 0x02,
-       RPIPE_CRS_BULK = 0x04,
-       RPIPE_CRS_INTR = 0x08
-};
-
-/**
- * RPipe descriptor ([WUSB] section 8.5.2.11)
- *
- * FIXME: explain rpipes
- */
-struct usb_rpipe_descriptor {
-       u8      bLength;
-       u8      bDescriptorType;
-       __le16  wRPipeIndex;
-       __le16  wRequests;
-       __le16  wBlocks;                /* rw if 0 */
-       __le16  wMaxPacketSize;         /* rw */
-       union {
-               u8      dwa_bHSHubAddress;              /* rw: DWA. */
-               u8      hwa_bMaxBurst;                  /* rw: HWA. */
-       };
-       union {
-               u8      dwa_bHSHubPort;         /*  rw: DWA. */
-               u8      hwa_bDeviceInfoIndex;   /*  rw: HWA. */
-       };
-       u8      bSpeed;                 /* rw: xfer rate 'enum uwb_phy_rate' */
-       union {
-               u8 dwa_bDeviceAddress;  /* rw: DWA Target device address. */
-               u8 hwa_reserved;                /* rw: HWA. */
-       };
-       u8      bEndpointAddress;       /* rw: Target EP address */
-       u8      bDataSequence;          /* ro: Current Data sequence */
-       __le32  dwCurrentWindow;        /* ro */
-       u8      bMaxDataSequence;       /* ro?: max supported seq */
-       u8      bInterval;              /* rw:  */
-       u8      bOverTheAirInterval;    /* rw:  */
-       u8      bmAttribute;            /* ro?  */
-       u8      bmCharacteristics;      /* ro? enum rpipe_attr, supported xsactions */
-       u8      bmRetryOptions;         /* rw? */
-       __le16  wNumTransactionErrors;  /* rw */
-} __attribute__ ((packed));
-
-/**
- * Wire Adapter Notification types ([WUSB] sections 8.4.5 & 8.5.4)
- *
- * These are the notifications coming on the notification endpoint of
- * an HWA and a DWA.
- */
-enum wa_notif_type {
-       DWA_NOTIF_RWAKE = 0x91,
-       DWA_NOTIF_PORTSTATUS = 0x92,
-       WA_NOTIF_TRANSFER = 0x93,
-       HWA_NOTIF_BPST_ADJ = 0x94,
-       HWA_NOTIF_DN = 0x95,
-};
-
-/**
- * Wire Adapter notification header
- *
- * Notifications coming from a wire adapter use a common header
- * defined in [WUSB] sections 8.4.5 & 8.5.4.
- */
-struct wa_notif_hdr {
-       u8 bLength;
-       u8 bNotifyType;                 /* enum wa_notif_type */
-} __packed;
-
-/**
- * HWA DN Received notification [(WUSB] section 8.5.4.2)
- *
- * The DNData is specified in WUSB1.0[7.6]. For each device
- * notification we received, we just need to dispatch it.
- *
- * @dndata:  this is really an array of notifications, but all start
- *           with the same header.
- */
-struct hwa_notif_dn {
-       struct wa_notif_hdr hdr;
-       u8 bSourceDeviceAddr;           /* from errata 2005/07 */
-       u8 bmAttributes;
-       struct wusb_dn_hdr dndata[];
-} __packed;
-
-/* [WUSB] section 8.3.3 */
-enum wa_xfer_type {
-       WA_XFER_TYPE_CTL = 0x80,
-       WA_XFER_TYPE_BI = 0x81,         /* bulk/interrupt */
-       WA_XFER_TYPE_ISO = 0x82,
-       WA_XFER_RESULT = 0x83,
-       WA_XFER_ABORT = 0x84,
-       WA_XFER_ISO_PACKET_INFO = 0xA0,
-       WA_XFER_ISO_PACKET_STATUS = 0xA1,
-};
-
-/* [WUSB] section 8.3.3 */
-struct wa_xfer_hdr {
-       u8 bLength;                     /* 0x18 */
-       u8 bRequestType;                /* 0x80 WA_REQUEST_TYPE_CTL */
-       __le16 wRPipe;                  /* RPipe index */
-       __le32 dwTransferID;            /* Host-assigned ID */
-       __le32 dwTransferLength;        /* Length of data to xfer */
-       u8 bTransferSegment;
-} __packed;
-
-struct wa_xfer_ctl {
-       struct wa_xfer_hdr hdr;
-       u8 bmAttribute;
-       __le16 wReserved;
-       struct usb_ctrlrequest baSetupData;
-} __packed;
-
-struct wa_xfer_bi {
-       struct wa_xfer_hdr hdr;
-       u8 bReserved;
-       __le16 wReserved;
-} __packed;
-
-/* [WUSB] section 8.5.5 */
-struct wa_xfer_hwaiso {
-       struct wa_xfer_hdr hdr;
-       u8 bReserved;
-       __le16 wPresentationTime;
-       __le32 dwNumOfPackets;
-} __packed;
-
-struct wa_xfer_packet_info_hwaiso {
-       __le16 wLength;
-       u8 bPacketType;
-       u8 bReserved;
-       __le16 PacketLength[0];
-} __packed;
-
-struct wa_xfer_packet_status_len_hwaiso {
-       __le16 PacketLength;
-       __le16 PacketStatus;
-} __packed;
-
-struct wa_xfer_packet_status_hwaiso {
-       __le16 wLength;
-       u8 bPacketType;
-       u8 bReserved;
-       struct wa_xfer_packet_status_len_hwaiso PacketStatus[0];
-} __packed;
-
-/* [WUSB] section 8.3.3.5 */
-struct wa_xfer_abort {
-       u8 bLength;
-       u8 bRequestType;
-       __le16 wRPipe;                  /* RPipe index */
-       __le32 dwTransferID;            /* Host-assigned ID */
-} __packed;
-
-/**
- * WA Transfer Complete notification ([WUSB] section 8.3.3.3)
- *
- */
-struct wa_notif_xfer {
-       struct wa_notif_hdr hdr;
-       u8 bEndpoint;
-       u8 Reserved;
-} __packed;
-
-/** Transfer result basic codes [WUSB] table 8-15 */
-enum {
-       WA_XFER_STATUS_SUCCESS,
-       WA_XFER_STATUS_HALTED,
-       WA_XFER_STATUS_DATA_BUFFER_ERROR,
-       WA_XFER_STATUS_BABBLE,
-       WA_XFER_RESERVED,
-       WA_XFER_STATUS_NOT_FOUND,
-       WA_XFER_STATUS_INSUFFICIENT_RESOURCE,
-       WA_XFER_STATUS_TRANSACTION_ERROR,
-       WA_XFER_STATUS_ABORTED,
-       WA_XFER_STATUS_RPIPE_NOT_READY,
-       WA_XFER_INVALID_FORMAT,
-       WA_XFER_UNEXPECTED_SEGMENT_NUMBER,
-       WA_XFER_STATUS_RPIPE_TYPE_MISMATCH,
-};
-
-/** [WUSB] section 8.3.3.4 */
-struct wa_xfer_result {
-       struct wa_notif_hdr hdr;
-       __le32 dwTransferID;
-       __le32 dwTransferLength;
-       u8     bTransferSegment;
-       u8     bTransferStatus;
-       __le32 dwNumOfPackets;
-} __packed;
-
-/**
- * Wire Adapter Class Descriptor ([WUSB] section 8.5.2.7).
- *
- * NOTE: u16 fields are read Little Endian from the hardware.
- *
- * @bNumPorts is the original max number of devices that the host can
- *            connect; we might chop this so the stack can handle
- *            it. In case you need to access it, use wusbhc->ports_max
- *            if it is a Wireless USB WA.
- */
-struct usb_wa_descriptor {
-       u8      bLength;
-       u8      bDescriptorType;
-       __le16  bcdWAVersion;
-       u8      bNumPorts;              /* don't use!! */
-       u8      bmAttributes;           /* Reserved == 0 */
-       __le16  wNumRPipes;
-       __le16  wRPipeMaxBlock;
-       u8      bRPipeBlockSize;
-       u8      bPwrOn2PwrGood;
-       u8      bNumMMCIEs;
-       u8      DeviceRemovable;        /* FIXME: in DWA this is up to 16 bytes */
-} __packed;
-
-/**
- * HWA Device Information Buffer (WUSB1.0[T8.54])
- */
-struct hwa_dev_info {
-       u8      bmDeviceAvailability[32];       /* FIXME: ignored for now */
-       u8      bDeviceAddress;
-       __le16  wPHYRates;
-       u8      bmDeviceAttribute;
-} __packed;
-
-#endif /* #ifndef __LINUX_USB_WUSB_WA_H */
diff --git a/drivers/staging/wusbcore/include/wusb.h b/drivers/staging/wusbcore/include/wusb.h
deleted file mode 100644 (file)
index 09771d1..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Standard Definitions
- * Event Size Tables
- *
- * 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.
- *
- *
- * FIXME: docs
- * FIXME: organize properly, group logically
- *
- * All the event structures are defined in uwb/spec.h, as they are
- * common to the WHCI and WUSB radio control interfaces.
- */
-
-#ifndef __WUSB_H__
-#define __WUSB_H__
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/usb/ch9.h>
-#include <linux/param.h>
-#include "../../uwb/include/spec.h"
-
-/**
- * WUSB Information Element header
- *
- * I don't know why, they decided to make it different to the MBOA MAC
- * IE Header; beats me.
- */
-struct wuie_hdr {
-       u8 bLength;
-       u8 bIEIdentifier;
-} __attribute__((packed));
-
-enum {
-       WUIE_ID_WCTA = 0x80,
-       WUIE_ID_CONNECTACK,
-       WUIE_ID_HOST_INFO,
-       WUIE_ID_CHANGE_ANNOUNCE,
-       WUIE_ID_DEVICE_DISCONNECT,
-       WUIE_ID_HOST_DISCONNECT,
-       WUIE_ID_KEEP_ALIVE = 0x89,
-       WUIE_ID_ISOCH_DISCARD,
-       WUIE_ID_RESET_DEVICE,
-};
-
-/**
- * Maximum number of array elements in a WUSB IE.
- *
- * WUSB1.0[7.5 before table 7-38] says that in WUSB IEs that
- * are "arrays" have to limited to 4 elements. So we define it
- * like that to ease up and submit only the neeed size.
- */
-#define WUIE_ELT_MAX 4
-
-/**
- * Wrapper for the data that defines a CHID, a CDID or a CK
- *
- * WUSB defines that CHIDs, CDIDs and CKs are a 16 byte string of
- * data. In order to avoid confusion and enforce types, we wrap it.
- *
- * Make it packed, as we use it in some hw definitions.
- */
-struct wusb_ckhdid {
-       u8 data[16];
-} __attribute__((packed));
-
-static const struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } };
-
-#define WUSB_CKHDID_STRSIZE (3 * sizeof(struct wusb_ckhdid) + 1)
-
-/**
- * WUSB IE: Host Information (WUSB1.0[7.5.2])
- *
- * Used to provide information about the host to the Wireless USB
- * devices in range (CHID can be used as an ASCII string).
- */
-struct wuie_host_info {
-       struct wuie_hdr hdr;
-       __le16 attributes;
-       struct wusb_ckhdid CHID;
-} __attribute__((packed));
-
-/**
- * WUSB IE: Connect Ack (WUSB1.0[7.5.1])
- *
- * Used to acknowledge device connect requests. See note for
- * WUIE_ELT_MAX.
- */
-struct wuie_connect_ack {
-       struct wuie_hdr hdr;
-       struct {
-               struct wusb_ckhdid CDID;
-               u8 bDeviceAddress;      /* 0 means unused */
-               u8 bReserved;
-       } blk[WUIE_ELT_MAX];
-} __attribute__((packed));
-
-/**
- * WUSB IE Host Information Element, Connect Availability
- *
- * WUSB1.0[7.5.2], bmAttributes description
- */
-enum {
-       WUIE_HI_CAP_RECONNECT = 0,
-       WUIE_HI_CAP_LIMITED,
-       WUIE_HI_CAP_RESERVED,
-       WUIE_HI_CAP_ALL,
-};
-
-/**
- * WUSB IE: Channel Stop (WUSB1.0[7.5.8])
- *
- * Tells devices the host is going to stop sending MMCs and will disappear.
- */
-struct wuie_channel_stop {
-       struct wuie_hdr hdr;
-       u8 attributes;
-       u8 timestamp[3];
-} __attribute__((packed));
-
-/**
- * WUSB IE: Keepalive (WUSB1.0[7.5.9])
- *
- * Ask device(s) to send keepalives.
- */
-struct wuie_keep_alive {
-       struct wuie_hdr hdr;
-       u8 bDeviceAddress[WUIE_ELT_MAX];
-} __attribute__((packed));
-
-/**
- * WUSB IE: Reset device (WUSB1.0[7.5.11])
- *
- * Tell device to reset; in all truth, we can fit 4 CDIDs, but we only
- * use it for one at the time...
- *
- * In any case, this request is a wee bit silly: why don't they target
- * by address??
- */
-struct wuie_reset {
-       struct wuie_hdr hdr;
-       struct wusb_ckhdid CDID;
-} __attribute__((packed));
-
-/**
- * WUSB IE: Disconnect device (WUSB1.0[7.5.11])
- *
- * Tell device to disconnect; we can fit 4 addresses, but we only use
- * it for one at the time...
- */
-struct wuie_disconnect {
-       struct wuie_hdr hdr;
-       u8 bDeviceAddress;
-       u8 padding;
-} __attribute__((packed));
-
-/**
- * WUSB IE: Host disconnect ([WUSB] section 7.5.5)
- *
- * Tells all connected devices to disconnect.
- */
-struct wuie_host_disconnect {
-       struct wuie_hdr hdr;
-} __attribute__((packed));
-
-/**
- * WUSB Device Notification header (WUSB1.0[7.6])
- */
-struct wusb_dn_hdr {
-       u8 bType;
-       u8 notifdata[];
-} __attribute__((packed));
-
-/** Device Notification codes (WUSB1.0[Table 7-54]) */
-enum WUSB_DN {
-       WUSB_DN_CONNECT = 0x01,
-       WUSB_DN_DISCONNECT = 0x02,
-       WUSB_DN_EPRDY = 0x03,
-       WUSB_DN_MASAVAILCHANGED = 0x04,
-       WUSB_DN_RWAKE = 0x05,
-       WUSB_DN_SLEEP = 0x06,
-       WUSB_DN_ALIVE = 0x07,
-};
-
-/** WUSB Device Notification Connect */
-struct wusb_dn_connect {
-       struct wusb_dn_hdr hdr;
-       __le16 attributes;
-       struct wusb_ckhdid CDID;
-} __attribute__((packed));
-
-static inline int wusb_dn_connect_prev_dev_addr(const struct wusb_dn_connect *dn)
-{
-       return le16_to_cpu(dn->attributes) & 0xff;
-}
-
-static inline int wusb_dn_connect_new_connection(const struct wusb_dn_connect *dn)
-{
-       return (le16_to_cpu(dn->attributes) >> 8) & 0x1;
-}
-
-static inline int wusb_dn_connect_beacon_behavior(const struct wusb_dn_connect *dn)
-{
-       return (le16_to_cpu(dn->attributes) >> 9) & 0x03;
-}
-
-/** Device is alive (aka: pong) (WUSB1.0[7.6.7]) */
-struct wusb_dn_alive {
-       struct wusb_dn_hdr hdr;
-} __attribute__((packed));
-
-/** Device is disconnecting (WUSB1.0[7.6.2]) */
-struct wusb_dn_disconnect {
-       struct wusb_dn_hdr hdr;
-} __attribute__((packed));
-
-/* General constants */
-enum {
-       WUSB_TRUST_TIMEOUT_MS = 4000,   /* [WUSB] section 4.15.1 */
-};
-
-/*
- * WUSB Crypto stuff (WUSB1.0[6])
- */
-
-extern const char *wusb_et_name(u8);
-
-/**
- * WUSB key index WUSB1.0[7.3.2.4], for usage when setting keys for
- * the host or the device.
- */
-static inline u8 wusb_key_index(int index, int type, int originator)
-{
-       return (originator << 6) | (type << 4) | index;
-}
-
-#define WUSB_KEY_INDEX_TYPE_PTK                        0 /* for HWA only */
-#define WUSB_KEY_INDEX_TYPE_ASSOC              1
-#define WUSB_KEY_INDEX_TYPE_GTK                        2
-#define WUSB_KEY_INDEX_ORIGINATOR_HOST         0
-#define WUSB_KEY_INDEX_ORIGINATOR_DEVICE       1
-/* bits 0-3 used for the key index. */
-#define WUSB_KEY_INDEX_MAX                     15
-
-/* A CCM Nonce, defined in WUSB1.0[6.4.1] */
-struct aes_ccm_nonce {
-       u8 sfn[6];              /* Little Endian */
-       u8 tkid[3];             /* LE */
-       struct uwb_dev_addr dest_addr;
-       struct uwb_dev_addr src_addr;
-} __attribute__((packed));
-
-/* A CCM operation label, defined on WUSB1.0[6.5.x] */
-struct aes_ccm_label {
-       u8 data[14];
-} __attribute__((packed));
-
-/*
- * Input to the key derivation sequence defined in
- * WUSB1.0[6.5.1]. Rest of the data is in the CCM Nonce passed to the
- * PRF function.
- */
-struct wusb_keydvt_in {
-       u8 hnonce[16];
-       u8 dnonce[16];
-} __attribute__((packed));
-
-/*
- * Output from the key derivation sequence defined in
- * WUSB1.0[6.5.1].
- */
-struct wusb_keydvt_out {
-       u8 kck[16];
-       u8 ptk[16];
-} __attribute__((packed));
-
-/* Pseudo Random Function WUSB1.0[6.5] */
-extern int wusb_crypto_init(void);
-extern void wusb_crypto_exit(void);
-extern ssize_t wusb_prf(void *out, size_t out_size,
-                       const u8 key[16], const struct aes_ccm_nonce *_n,
-                       const struct aes_ccm_label *a,
-                       const void *b, size_t blen, size_t len);
-
-static inline int wusb_prf_64(void *out, size_t out_size, const u8 key[16],
-                             const struct aes_ccm_nonce *n,
-                             const struct aes_ccm_label *a,
-                             const void *b, size_t blen)
-{
-       return wusb_prf(out, out_size, key, n, a, b, blen, 64);
-}
-
-static inline int wusb_prf_128(void *out, size_t out_size, const u8 key[16],
-                              const struct aes_ccm_nonce *n,
-                              const struct aes_ccm_label *a,
-                              const void *b, size_t blen)
-{
-       return wusb_prf(out, out_size, key, n, a, b, blen, 128);
-}
-
-static inline int wusb_prf_256(void *out, size_t out_size, const u8 key[16],
-                              const struct aes_ccm_nonce *n,
-                              const struct aes_ccm_label *a,
-                              const void *b, size_t blen)
-{
-       return wusb_prf(out, out_size, key, n, a, b, blen, 256);
-}
-
-/* Key derivation WUSB1.0[6.5.1] */
-static inline int wusb_key_derive(struct wusb_keydvt_out *keydvt_out,
-                                 const u8 key[16],
-                                 const struct aes_ccm_nonce *n,
-                                 const struct wusb_keydvt_in *keydvt_in)
-{
-       const struct aes_ccm_label a = { .data = "Pair-wise keys" };
-       return wusb_prf_256(keydvt_out, sizeof(*keydvt_out), key, n, &a,
-                           keydvt_in, sizeof(*keydvt_in));
-}
-
-/*
- * Out-of-band MIC Generation WUSB1.0[6.5.2]
- *
- * Compute the MIC over @key, @n and @hs and place it in @mic_out.
- *
- * @mic_out:  Where to place the 8 byte MIC tag
- * @key:      KCK from the derivation process
- * @n:        CCM nonce, n->sfn == 0, TKID as established in the
- *            process.
- * @hs:       Handshake struct for phase 2 of the 4-way.
- *            hs->bStatus and hs->bReserved are zero.
- *            hs->bMessageNumber is 2 (WUSB1.0[7.3.2.5.2]
- *            hs->dest_addr is the device's USB address padded with 0
- *            hs->src_addr is the hosts's UWB device address
- *            hs->mic is ignored (as we compute that value).
- */
-static inline int wusb_oob_mic(u8 mic_out[8], const u8 key[16],
-                              const struct aes_ccm_nonce *n,
-                              const struct usb_handshake *hs)
-{
-       const struct aes_ccm_label a = { .data = "out-of-bandMIC" };
-       return wusb_prf_64(mic_out, 8, key, n, &a,
-                          hs, sizeof(*hs) - sizeof(hs->MIC));
-}
-
-#endif /* #ifndef __WUSB_H__ */
diff --git a/drivers/staging/wusbcore/mmc.c b/drivers/staging/wusbcore/mmc.c
deleted file mode 100644 (file)
index 881e1f2..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
- * MMC (Microscheduled Management Command) handling
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * WUIEs and MMC IEs...well, they are almost the same at the end. MMC
- * IEs are Wireless USB IEs that go into the MMC period...[what is
- * that? look in Design-overview.txt].
- *
- *
- * This is a simple subsystem to keep track of which IEs are being
- * sent by the host in the MMC period.
- *
- * For each WUIE we ask to send, we keep it in an array, so we can
- * request its removal later, or replace the content. They are tracked
- * by pointer, so be sure to use the same pointer if you want to
- * remove it or update the contents.
- *
- * FIXME:
- *  - add timers that autoremove intervalled IEs?
- */
-#include <linux/slab.h>
-#include <linux/export.h>
-#include "include/wusb.h"
-#include "wusbhc.h"
-
-/* Initialize the MMCIEs handling mechanism */
-int wusbhc_mmcie_create(struct wusbhc *wusbhc)
-{
-       u8 mmcies = wusbhc->mmcies_max;
-       wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL);
-       if (wusbhc->mmcie == NULL)
-               return -ENOMEM;
-       mutex_init(&wusbhc->mmcie_mutex);
-       return 0;
-}
-
-/* Release resources used by the MMCIEs handling mechanism */
-void wusbhc_mmcie_destroy(struct wusbhc *wusbhc)
-{
-       kfree(wusbhc->mmcie);
-}
-
-/*
- * Add or replace an MMC Wireless USB IE.
- *
- * @interval:    See WUSB1.0[8.5.3.1]
- * @repeat_cnt:  See WUSB1.0[8.5.3.1]
- * @handle:      See WUSB1.0[8.5.3.1]
- * @wuie:        Pointer to the header of the WUSB IE data to add.
- *               MUST BE allocated in a kmalloc buffer (no stack or
- *               vmalloc).
- *               THE CALLER ALWAYS OWNS THE POINTER (we don't free it
- *               on remove, we just forget about it).
- * @returns:     0 if ok, < 0 errno code on error.
- *
- * Goes over the *whole* @wusbhc->mmcie array looking for (a) the
- * first free spot and (b) if @wuie is already in the array (aka:
- * transmitted in the MMCs) the spot were it is.
- *
- * If present, we "overwrite it" (update).
- *
- *
- * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38.
- *       The host uses the handle as the 'sort' index. We
- *       allocate the last one always for the WUIE_ID_HOST_INFO, and
- *       the rest, first come first serve in inverse order.
- *
- *       Host software must make sure that it adds the other IEs in
- *       the right order... the host hardware is responsible for
- *       placing the WCTA IEs in the right place with the other IEs
- *       set by host software.
- *
- * NOTE: we can access wusbhc->wa_descr without locking because it is
- *       read only.
- */
-int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
-                    struct wuie_hdr *wuie)
-{
-       int result = -ENOBUFS;
-       unsigned handle, itr;
-
-       /* Search a handle, taking into account the ordering */
-       mutex_lock(&wusbhc->mmcie_mutex);
-       switch (wuie->bIEIdentifier) {
-       case WUIE_ID_HOST_INFO:
-               /* Always last */
-               handle = wusbhc->mmcies_max - 1;
-               break;
-       case WUIE_ID_ISOCH_DISCARD:
-               dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x "
-                       "unimplemented\n", wuie->bIEIdentifier);
-               result = -ENOSYS;
-               goto error_unlock;
-       default:
-               /* search for it or find the last empty slot */
-               handle = ~0;
-               for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) {
-                       if (wusbhc->mmcie[itr] == wuie) {
-                               handle = itr;
-                               break;
-                       }
-                       if (wusbhc->mmcie[itr] == NULL)
-                               handle = itr;
-               }
-               if (handle == ~0)
-                       goto error_unlock;
-       }
-       result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle,
-                                    wuie);
-       if (result >= 0)
-               wusbhc->mmcie[handle] = wuie;
-error_unlock:
-       mutex_unlock(&wusbhc->mmcie_mutex);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_mmcie_set);
-
-/*
- * Remove an MMC IE previously added with wusbhc_mmcie_set()
- *
- * @wuie       Pointer used to add the WUIE
- */
-void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie)
-{
-       int result;
-       unsigned handle, itr;
-
-       mutex_lock(&wusbhc->mmcie_mutex);
-       for (itr = 0; itr < wusbhc->mmcies_max; itr++) {
-               if (wusbhc->mmcie[itr] == wuie) {
-                       handle = itr;
-                       goto found;
-               }
-       }
-       mutex_unlock(&wusbhc->mmcie_mutex);
-       return;
-
-found:
-       result = (wusbhc->mmcie_rm)(wusbhc, handle);
-       if (result == 0)
-               wusbhc->mmcie[itr] = NULL;
-       mutex_unlock(&wusbhc->mmcie_mutex);
-}
-EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
-
-static int wusbhc_mmc_start(struct wusbhc *wusbhc)
-{
-       int ret;
-
-       mutex_lock(&wusbhc->mutex);
-       ret = wusbhc->start(wusbhc);
-       if (ret >= 0)
-               wusbhc->active = 1;
-       mutex_unlock(&wusbhc->mutex);
-
-       return ret;
-}
-
-static void wusbhc_mmc_stop(struct wusbhc *wusbhc)
-{
-       mutex_lock(&wusbhc->mutex);
-       wusbhc->active = 0;
-       wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/*
- * wusbhc_start - start transmitting MMCs and accepting connections
- * @wusbhc: the HC to start
- *
- * Establishes a cluster reservation, enables device connections, and
- * starts MMCs with appropriate DNTS parameters.
- */
-int wusbhc_start(struct wusbhc *wusbhc)
-{
-       int result;
-       struct device *dev = wusbhc->dev;
-
-       WARN_ON(wusbhc->wuie_host_info != NULL);
-       BUG_ON(wusbhc->uwb_rc == NULL);
-
-       result = wusbhc_rsv_establish(wusbhc);
-       if (result < 0) {
-               dev_err(dev, "cannot establish cluster reservation: %d\n",
-                       result);
-               goto error_rsv_establish;
-       }
-
-       result = wusbhc_devconnect_start(wusbhc);
-       if (result < 0) {
-               dev_err(dev, "error enabling device connections: %d\n",
-                       result);
-               goto error_devconnect_start;
-       }
-
-       result = wusbhc_sec_start(wusbhc);
-       if (result < 0) {
-               dev_err(dev, "error starting security in the HC: %d\n",
-                       result);
-               goto error_sec_start;
-       }
-
-       result = wusbhc->set_num_dnts(wusbhc, wusbhc->dnts_interval,
-               wusbhc->dnts_num_slots);
-       if (result < 0) {
-               dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
-               goto error_set_num_dnts;
-       }
-       result = wusbhc_mmc_start(wusbhc);
-       if (result < 0) {
-               dev_err(dev, "error starting wusbch: %d\n", result);
-               goto error_wusbhc_start;
-       }
-
-       return 0;
-
-error_wusbhc_start:
-       wusbhc_sec_stop(wusbhc);
-error_set_num_dnts:
-error_sec_start:
-       wusbhc_devconnect_stop(wusbhc);
-error_devconnect_start:
-       wusbhc_rsv_terminate(wusbhc);
-error_rsv_establish:
-       return result;
-}
-
-/*
- * wusbhc_stop - stop transmitting MMCs
- * @wusbhc: the HC to stop
- *
- * Stops the WUSB channel and removes the cluster reservation.
- */
-void wusbhc_stop(struct wusbhc *wusbhc)
-{
-       wusbhc_mmc_stop(wusbhc);
-       wusbhc_sec_stop(wusbhc);
-       wusbhc_devconnect_stop(wusbhc);
-       wusbhc_rsv_terminate(wusbhc);
-}
-
-/*
- * Set/reset/update a new CHID
- *
- * Depending on the previous state of the MMCs, start, stop or change
- * the sent MMC. This effectively switches the host controller on and
- * off (radio wise).
- */
-int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
-{
-       int result = 0;
-
-       if (memcmp(chid, &wusb_ckhdid_zero, sizeof(*chid)) == 0)
-               chid = NULL;
-
-       mutex_lock(&wusbhc->mutex);
-       if (chid) {
-               if (wusbhc->active) {
-                       mutex_unlock(&wusbhc->mutex);
-                       return -EBUSY;
-               }
-               wusbhc->chid = *chid;
-       }
-
-       /* register with UWB if we haven't already since we are about to start
-           the radio. */
-       if ((chid) && (wusbhc->uwb_rc == NULL)) {
-               wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent);
-               if (wusbhc->uwb_rc == NULL) {
-                       result = -ENODEV;
-                       dev_err(wusbhc->dev,
-                               "Cannot get associated UWB Host Controller\n");
-                       goto error_rc_get;
-               }
-
-               result = wusbhc_pal_register(wusbhc);
-               if (result < 0) {
-                       dev_err(wusbhc->dev, "Cannot register as a UWB PAL\n");
-                       goto error_pal_register;
-               }
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       if (chid)
-               result = uwb_radio_start(&wusbhc->pal);
-       else if (wusbhc->uwb_rc)
-               uwb_radio_stop(&wusbhc->pal);
-
-       return result;
-
-error_pal_register:
-       uwb_rc_put(wusbhc->uwb_rc);
-       wusbhc->uwb_rc = NULL;
-error_rc_get:
-       mutex_unlock(&wusbhc->mutex);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_chid_set);
diff --git a/drivers/staging/wusbcore/pal.c b/drivers/staging/wusbcore/pal.c
deleted file mode 100644 (file)
index 30f5691..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * UWB Protocol Adaptation Layer (PAL) glue.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include "wusbhc.h"
-
-static void wusbhc_channel_changed(struct uwb_pal *pal, int channel)
-{
-       struct wusbhc *wusbhc = container_of(pal, struct wusbhc, pal);
-
-       dev_dbg(wusbhc->dev, "%s: channel = %d\n", __func__, channel);
-       if (channel < 0)
-               wusbhc_stop(wusbhc);
-       else
-               wusbhc_start(wusbhc);
-}
-
-/**
- * wusbhc_pal_register - register the WUSB HC as a UWB PAL
- * @wusbhc: the WUSB HC
- */
-int wusbhc_pal_register(struct wusbhc *wusbhc)
-{
-       uwb_pal_init(&wusbhc->pal);
-
-       wusbhc->pal.name   = "wusbhc";
-       wusbhc->pal.device = wusbhc->usb_hcd.self.controller;
-       wusbhc->pal.rc     = wusbhc->uwb_rc;
-       wusbhc->pal.channel_changed = wusbhc_channel_changed;
-
-       return uwb_pal_register(&wusbhc->pal);
-}
-
-/**
- * wusbhc_pal_unregister - unregister the WUSB HC as a UWB PAL
- * @wusbhc: the WUSB HC
- */
-void wusbhc_pal_unregister(struct wusbhc *wusbhc)
-{
-       if (wusbhc->uwb_rc)
-               uwb_pal_unregister(&wusbhc->pal);
-}
diff --git a/drivers/staging/wusbcore/reservation.c b/drivers/staging/wusbcore/reservation.c
deleted file mode 100644 (file)
index b921faa..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB cluster reservation management
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-
-#include "../uwb/uwb.h"
-#include "wusbhc.h"
-
-/*
- * WUSB cluster reservations are multicast reservations with the
- * broadcast cluster ID (BCID) as the target DevAddr.
- *
- * FIXME: consider adjusting the reservation depending on what devices
- * are attached.
- */
-
-static int wusbhc_bwa_set(struct wusbhc *wusbhc, u8 stream,
-       const struct uwb_mas_bm *mas)
-{
-       if (mas == NULL)
-               mas = &uwb_mas_bm_zero;
-       return wusbhc->bwa_set(wusbhc, stream, mas);
-}
-
-/**
- * wusbhc_rsv_complete_cb - WUSB HC reservation complete callback
- * @rsv:    the reservation
- *
- * Either set or clear the HC's view of the reservation.
- *
- * FIXME: when a reservation is denied the HC should be stopped.
- */
-static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)
-{
-       struct wusbhc *wusbhc = rsv->pal_priv;
-       struct device *dev = wusbhc->dev;
-       struct uwb_mas_bm mas;
-
-       dev_dbg(dev, "%s: state = %d\n", __func__, rsv->state);
-       switch (rsv->state) {
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               uwb_rsv_get_usable_mas(rsv, &mas);
-               dev_dbg(dev, "established reservation: %*pb\n",
-                       UWB_NUM_MAS, mas.bm);
-               wusbhc_bwa_set(wusbhc, rsv->stream, &mas);
-               break;
-       case UWB_RSV_STATE_NONE:
-               dev_dbg(dev, "removed reservation\n");
-               wusbhc_bwa_set(wusbhc, 0, NULL);
-               break;
-       default:
-               dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state);
-               break;
-       }
-}
-
-
-/**
- * wusbhc_rsv_establish - establish a reservation for the cluster
- * @wusbhc: the WUSB HC requesting a bandwidth reservation
- */
-int wusbhc_rsv_establish(struct wusbhc *wusbhc)
-{
-       struct uwb_rc *rc = wusbhc->uwb_rc;
-       struct uwb_rsv *rsv;
-       struct uwb_dev_addr bcid;
-       int ret;
-
-       if (rc == NULL)
-               return -ENODEV;
-
-       rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);
-       if (rsv == NULL)
-               return -ENOMEM;
-
-       bcid.data[0] = wusbhc->cluster_id;
-       bcid.data[1] = 0;
-
-       rsv->target.type = UWB_RSV_TARGET_DEVADDR;
-       rsv->target.devaddr = bcid;
-       rsv->type = UWB_DRP_TYPE_PRIVATE;
-       rsv->max_mas = 256; /* try to get as much as possible */
-       rsv->min_mas = 15;  /* one MAS per zone */
-       rsv->max_interval = 1; /* max latency is one zone */
-       rsv->is_multicast = true;
-
-       ret = uwb_rsv_establish(rsv);
-       if (ret == 0)
-               wusbhc->rsv = rsv;
-       else
-               uwb_rsv_destroy(rsv);
-       return ret;
-}
-
-
-/**
- * wusbhc_rsv_terminate - terminate the cluster reservation
- * @wusbhc: the WUSB host whose reservation is to be terminated
- */
-void wusbhc_rsv_terminate(struct wusbhc *wusbhc)
-{
-       if (wusbhc->rsv) {
-               uwb_rsv_terminate(wusbhc->rsv);
-               uwb_rsv_destroy(wusbhc->rsv);
-               wusbhc->rsv = NULL;
-       }
-}
diff --git a/drivers/staging/wusbcore/rh.c b/drivers/staging/wusbcore/rh.c
deleted file mode 100644 (file)
index 20c08cd..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * Root Hub operations
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * We fake a root hub that has fake ports (as many as simultaneous
- * devices the Wireless USB Host Controller can deal with). For each
- * port we keep an state in @wusbhc->port[index] identical to the one
- * specified in the USB2.0[ch11] spec and some extra device
- * information that complements the one in 'struct usb_device' (as
- * this lacs a hcpriv pointer).
- *
- * Note this is common to WHCI and HWA host controllers.
- *
- * Through here we enable most of the state changes that the USB stack
- * will use to connect or disconnect devices. We need to do some
- * forced adaptation of Wireless USB device states vs. wired:
- *
- *        USB:                 WUSB:
- *
- * Port   Powered-off          port slot n/a
- *        Powered-on           port slot available
- *        Disconnected         port slot available
- *        Connected            port slot assigned device
- *                            device sent DN_Connect
- *                             device was authenticated
- *        Enabled              device is authenticated, transitioned
- *                             from unauth -> auth -> default address
- *                             -> enabled
- *        Reset                disconnect
- *        Disable              disconnect
- *
- * This maps the standard USB port states with the WUSB device states
- * so we can fake ports without having to modify the USB stack.
- *
- * FIXME: this process will change in the future
- *
- *
- * ENTRY POINTS
- *
- * Our entry points into here are, as in hcd.c, the USB stack root hub
- * ops defined in the usb_hcd struct:
- *
- * wusbhc_rh_status_data()     Provide hub and port status data bitmap
- *
- * wusbhc_rh_control()          Execution of all the major requests
- *                              you can do to a hub (Set|Clear
- *                              features, get descriptors, status, etc).
- *
- * wusbhc_rh_[suspend|resume]() That
- *
- * wusbhc_rh_start_port_reset() ??? unimplemented
- */
-#include <linux/slab.h>
-#include <linux/export.h>
-#include "wusbhc.h"
-
-/*
- * Reset a fake port
- *
- * Using a Reset Device IE is too heavyweight as it causes the device
- * to enter the UnConnected state and leave the cluster, this can mean
- * that when the device reconnects it is connected to a different fake
- * port.
- *
- * Instead, reset authenticated devices with a SetAddress(0), followed
- * by a SetAddresss(AuthAddr).
- *
- * For unauthenticated devices just pretend to reset but do nothing.
- * If the device initialization continues to fail it will eventually
- * time out after TrustTimeout and enter the UnConnected state.
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- *
- * Supposedly we are the only thread accesing @wusbhc->port; in any
- * case, maybe we should move the mutex locking from
- * wusbhc_devconnect_auth() to here.
- *
- * @port_idx refers to the wusbhc's port index, not the USB port number
- */
-static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
-{
-       int result = 0;
-       struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx);
-       struct wusb_dev *wusb_dev = port->wusb_dev;
-
-       if (wusb_dev == NULL)
-               return -ENOTCONN;
-
-       port->status |= USB_PORT_STAT_RESET;
-       port->change |= USB_PORT_STAT_C_RESET;
-
-       if (wusb_dev->addr & WUSB_DEV_ADDR_UNAUTH)
-               result = 0;
-       else
-               result = wusb_dev_update_address(wusbhc, wusb_dev);
-
-       port->status &= ~USB_PORT_STAT_RESET;
-       port->status |= USB_PORT_STAT_ENABLE;
-       port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE; 
-
-       return result;
-}
-
-/*
- * Return the hub change status bitmap
- *
- * The bits in the change status bitmap are cleared when a
- * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4].
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- *
- * WARNING!! This gets called from atomic context; we cannot get the
- *           mutex--the only race condition we can find is some bit
- *           changing just after we copy it, which shouldn't be too
- *           big of a problem [and we can't make it an spinlock
- *           because other parts need to take it and sleep] .
- *
- *           @usb_hcd is refcounted, so it won't disappear under us
- *           and before killing a host, the polling of the root hub
- *           would be stopped anyway.
- */
-int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       size_t cnt, size, bits_set = 0;
-
-       /* WE DON'T LOCK, see comment */
-       /* round up to bytes.  Hub bit is bit 0 so add 1. */
-       size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8);
-
-       /* clear the output buffer. */
-       memset(_buf, 0, size);
-       /* set the bit for each changed port. */
-       for (cnt = 0; cnt < wusbhc->ports_max; cnt++) {
-
-               if (wusb_port_by_idx(wusbhc, cnt)->change) {
-                       const int bitpos = cnt+1;
-
-                       _buf[bitpos/8] |= (1 << (bitpos % 8));
-                       bits_set++;
-               }
-       }
-
-       return bits_set ? size : 0;
-}
-EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
-
-/*
- * Return the hub's descriptor
- *
- * NOTE: almost cut and paste from ehci-hub.c
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked
- */
-static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue,
-                                  u16 wIndex,
-                                  struct usb_hub_descriptor *descr,
-                                  u16 wLength)
-{
-       u16 temp = 1 + (wusbhc->ports_max / 8);
-       u8 length = 7 + 2 * temp;
-
-       if (wLength < length)
-               return -ENOSPC;
-       descr->bDescLength = 7 + 2 * temp;
-       descr->bDescriptorType = USB_DT_HUB; /* HUB type */
-       descr->bNbrPorts = wusbhc->ports_max;
-       descr->wHubCharacteristics = cpu_to_le16(
-               HUB_CHAR_COMMON_LPSM    /* All ports power at once */
-               | 0x00                  /* not part of compound device */
-               | HUB_CHAR_NO_OCPM      /* No overcurrent protection */
-               | 0x00                  /* 8 FS think time FIXME ?? */
-               | 0x00);                /* No port indicators */
-       descr->bPwrOn2PwrGood = 0;
-       descr->bHubContrCurrent = 0;
-       /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
-       memset(&descr->u.hs.DeviceRemovable[0], 0, temp);
-       memset(&descr->u.hs.DeviceRemovable[temp], 0xff, temp);
-       return 0;
-}
-
-/*
- * Clear a hub feature
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- *
- * Nothing to do, so no locking needed ;)
- */
-static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature)
-{
-       int result;
-
-       switch (feature) {
-       case C_HUB_LOCAL_POWER:
-               /* FIXME: maybe plug bit 0 to the power input status,
-                * if any?
-                * see wusbhc_rh_get_hub_status() */
-       case C_HUB_OVER_CURRENT:
-               result = 0;
-               break;
-       default:
-               result = -EPIPE;
-       }
-       return result;
-}
-
-/*
- * Return hub status (it is always zero...)
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- *
- * Nothing to do, so no locking needed ;)
- */
-static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf,
-                                   u16 wLength)
-{
-       /* FIXME: maybe plug bit 0 to the power input status (if any)? */
-       *buf = 0;
-       return 0;
-}
-
-/*
- * Set a port feature
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- */
-static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature,
-                                  u8 selector, u8 port_idx)
-{
-       struct device *dev = wusbhc->dev;
-
-       if (port_idx > wusbhc->ports_max)
-               return -EINVAL;
-
-       switch (feature) {
-               /* According to USB2.0[11.24.2.13]p2, these features
-                * are not required to be implemented. */
-       case USB_PORT_FEAT_C_OVER_CURRENT:
-       case USB_PORT_FEAT_C_ENABLE:
-       case USB_PORT_FEAT_C_SUSPEND:
-       case USB_PORT_FEAT_C_CONNECTION:
-       case USB_PORT_FEAT_C_RESET:
-               return 0;
-       case USB_PORT_FEAT_POWER:
-               /* No such thing, but we fake it works */
-               mutex_lock(&wusbhc->mutex);
-               wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER;
-               mutex_unlock(&wusbhc->mutex);
-               return 0;
-       case USB_PORT_FEAT_RESET:
-               return wusbhc_rh_port_reset(wusbhc, port_idx);
-       case USB_PORT_FEAT_ENABLE:
-       case USB_PORT_FEAT_SUSPEND:
-               dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n",
-                       port_idx, feature, selector);
-               return -ENOSYS;
-       default:
-               dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n",
-                       port_idx, feature, selector);
-               return -EPIPE;
-       }
-
-       return 0;
-}
-
-/*
- * Clear a port feature...
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- */
-static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
-                                    u8 selector, u8 port_idx)
-{
-       int result = 0;
-       struct device *dev = wusbhc->dev;
-
-       if (port_idx > wusbhc->ports_max)
-               return -EINVAL;
-
-       mutex_lock(&wusbhc->mutex);
-       switch (feature) {
-       case USB_PORT_FEAT_POWER:       /* fake port always on */
-               /* According to USB2.0[11.24.2.7.1.4], no need to implement? */
-       case USB_PORT_FEAT_C_OVER_CURRENT:
-               break;
-       case USB_PORT_FEAT_C_RESET:
-               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET;
-               break;
-       case USB_PORT_FEAT_C_CONNECTION:
-               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION;
-               break;
-       case USB_PORT_FEAT_ENABLE:
-               __wusbhc_dev_disable(wusbhc, port_idx);
-               break;
-       case USB_PORT_FEAT_C_ENABLE:
-               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE;
-               break;
-       case USB_PORT_FEAT_SUSPEND:
-       case USB_PORT_FEAT_C_SUSPEND:
-               dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n",
-                       port_idx, feature, selector);
-               result = -ENOSYS;
-               break;
-       default:
-               dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n",
-                       port_idx, feature, selector);
-               result = -EPIPE;
-               break;
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       return result;
-}
-
-/*
- * Return the port's status
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- */
-static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx,
-                                    u32 *_buf, u16 wLength)
-{
-       __le16 *buf = (__le16 *)_buf;
-
-       if (port_idx > wusbhc->ports_max)
-               return -EINVAL;
-
-       mutex_lock(&wusbhc->mutex);
-       buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status);
-       buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change);
-       mutex_unlock(&wusbhc->mutex);
-
-       return 0;
-}
-
-/*
- * Entry point for Root Hub operations
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- */
-int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue,
-                     u16 wIndex, char *buf, u16 wLength)
-{
-       int result = -ENOSYS;
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-
-       switch (reqntype) {
-       case GetHubDescriptor:
-               result = wusbhc_rh_get_hub_descr(
-                       wusbhc, wValue, wIndex,
-                       (struct usb_hub_descriptor *) buf, wLength);
-               break;
-       case ClearHubFeature:
-               result = wusbhc_rh_clear_hub_feat(wusbhc, wValue);
-               break;
-       case GetHubStatus:
-               result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength);
-               break;
-
-       case SetPortFeature:
-               result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8,
-                                                (wIndex & 0xff) - 1);
-               break;
-       case ClearPortFeature:
-               result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8,
-                                                  (wIndex & 0xff) - 1);
-               break;
-       case GetPortStatus:
-               result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1,
-                                                  (u32 *)buf, wLength);
-               break;
-
-       case SetHubFeature:
-       default:
-               dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) "
-                       "UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype,
-                       wValue, wIndex, buf, wLength);
-               /* dump_stack(); */
-               result = -ENOSYS;
-       }
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_rh_control);
-
-int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n",
-               __func__, usb_hcd, wusbhc, port_idx);
-       WARN_ON(1);
-       return -ENOSYS;
-}
-EXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset);
-
-static void wusb_port_init(struct wusb_port *port)
-{
-       port->status |= USB_PORT_STAT_HIGH_SPEED;
-}
-
-/*
- * Alloc fake port specific fields and status.
- */
-int wusbhc_rh_create(struct wusbhc *wusbhc)
-{
-       int result = -ENOMEM;
-       size_t port_size, itr;
-       port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]);
-       wusbhc->port = kzalloc(port_size, GFP_KERNEL);
-       if (wusbhc->port == NULL)
-               goto error_port_alloc;
-       for (itr = 0; itr < wusbhc->ports_max; itr++)
-               wusb_port_init(&wusbhc->port[itr]);
-       result = 0;
-error_port_alloc:
-       return result;
-}
-
-void wusbhc_rh_destroy(struct wusbhc *wusbhc)
-{
-       kfree(wusbhc->port);
-}
diff --git a/drivers/staging/wusbcore/security.c b/drivers/staging/wusbcore/security.c
deleted file mode 100644 (file)
index 14ac8c9..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * Security support: encryption enablement, etc
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/usb/ch9.h>
-#include <linux/random.h>
-#include <linux/export.h>
-#include "wusbhc.h"
-#include <asm/unaligned.h>
-
-static void wusbhc_gtk_rekey_work(struct work_struct *work);
-
-int wusbhc_sec_create(struct wusbhc *wusbhc)
-{
-       /*
-        * WQ is singlethread because we need to serialize rekey operations.
-        * Use a separate workqueue for security operations instead of the
-        * wusbd workqueue because security operations may need to communicate
-        * directly with downstream wireless devices using synchronous URBs.
-        * If a device is not responding, this could block other host
-        * controller operations.
-        */
-       wusbhc->wq_security = create_singlethread_workqueue("wusbd_security");
-       if (wusbhc->wq_security == NULL) {
-               pr_err("WUSB-core: Cannot create wusbd_security workqueue\n");
-               return -ENOMEM;
-       }
-
-       wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) +
-               sizeof(wusbhc->gtk.data);
-       wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;
-       wusbhc->gtk.descr.bReserved = 0;
-       wusbhc->gtk_index = 0;
-
-       INIT_WORK(&wusbhc->gtk_rekey_work, wusbhc_gtk_rekey_work);
-
-       return 0;
-}
-
-
-/* Called when the HC is destroyed */
-void wusbhc_sec_destroy(struct wusbhc *wusbhc)
-{
-       destroy_workqueue(wusbhc->wq_security);
-}
-
-
-/**
- * wusbhc_next_tkid - generate a new, currently unused, TKID
- * @wusbhc:   the WUSB host controller
- * @wusb_dev: the device whose PTK the TKID is for
- *            (or NULL for a TKID for a GTK)
- *
- * The generated TKID consists of two parts: the device's authenticated
- * address (or 0 or a GTK); and an incrementing number.  This ensures
- * that TKIDs cannot be shared between devices and by the time the
- * incrementing number wraps around the older TKIDs will no longer be
- * in use (a maximum of two keys may be active at any one time).
- */
-static u32 wusbhc_next_tkid(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       u32 *tkid;
-       u32 addr;
-
-       if (wusb_dev == NULL) {
-               tkid = &wusbhc->gtk_tkid;
-               addr = 0;
-       } else {
-               tkid = &wusb_port_by_idx(wusbhc, wusb_dev->port_idx)->ptk_tkid;
-               addr = wusb_dev->addr & 0x7f;
-       }
-
-       *tkid = (addr << 8) | ((*tkid + 1) & 0xff);
-
-       return *tkid;
-}
-
-static void wusbhc_generate_gtk(struct wusbhc *wusbhc)
-{
-       const size_t key_size = sizeof(wusbhc->gtk.data);
-       u32 tkid;
-
-       tkid = wusbhc_next_tkid(wusbhc, NULL);
-
-       wusbhc->gtk.descr.tTKID[0] = (tkid >>  0) & 0xff;
-       wusbhc->gtk.descr.tTKID[1] = (tkid >>  8) & 0xff;
-       wusbhc->gtk.descr.tTKID[2] = (tkid >> 16) & 0xff;
-
-       get_random_bytes(wusbhc->gtk.descr.bKeyData, key_size);
-}
-
-/**
- * wusbhc_sec_start - start the security management process
- * @wusbhc: the WUSB host controller
- *
- * Generate and set an initial GTK on the host controller.
- *
- * Called when the HC is started.
- */
-int wusbhc_sec_start(struct wusbhc *wusbhc)
-{
-       const size_t key_size = sizeof(wusbhc->gtk.data);
-       int result;
-
-       wusbhc_generate_gtk(wusbhc);
-
-       result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
-                               &wusbhc->gtk.descr.bKeyData, key_size);
-       if (result < 0)
-               dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n",
-                       result);
-
-       return result;
-}
-
-/**
- * wusbhc_sec_stop - stop the security management process
- * @wusbhc: the WUSB host controller
- *
- * Wait for any pending GTK rekeys to stop.
- */
-void wusbhc_sec_stop(struct wusbhc *wusbhc)
-{
-       cancel_work_sync(&wusbhc->gtk_rekey_work);
-}
-
-
-/** @returns encryption type name */
-const char *wusb_et_name(u8 x)
-{
-       switch (x) {
-       case USB_ENC_TYPE_UNSECURE:     return "unsecure";
-       case USB_ENC_TYPE_WIRED:        return "wired";
-       case USB_ENC_TYPE_CCM_1:        return "CCM-1";
-       case USB_ENC_TYPE_RSA_1:        return "RSA-1";
-       default:                        return "unknown";
-       }
-}
-EXPORT_SYMBOL_GPL(wusb_et_name);
-
-/*
- * Set the device encryption method
- *
- * We tell the device which encryption method to use; we do this when
- * setting up the device's security.
- */
-static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)
-{
-       int result;
-       struct device *dev = &usb_dev->dev;
-       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
-
-       if (value) {
-               value = wusb_dev->ccm1_etd.bEncryptionValue;
-       } else {
-               /* FIXME: should be wusb_dev->etd[UNSECURE].bEncryptionValue */
-               value = 0;
-       }
-       /* Set device's */
-       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
-                       USB_REQ_SET_ENCRYPTION,
-                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-                       value, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(dev, "Can't set device's WUSB encryption to "
-                       "%s (value %d): %d\n",
-                       wusb_et_name(wusb_dev->ccm1_etd.bEncryptionType),
-                       wusb_dev->ccm1_etd.bEncryptionValue,  result);
-       return result;
-}
-
-/*
- * Set the GTK to be used by a device.
- *
- * The device must be authenticated.
- */
-static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       struct usb_device *usb_dev = wusb_dev->usb_dev;
-       u8 key_index = wusb_key_index(wusbhc->gtk_index,
-               WUSB_KEY_INDEX_TYPE_GTK, WUSB_KEY_INDEX_ORIGINATOR_HOST);
-
-       return usb_control_msg(
-               usb_dev, usb_sndctrlpipe(usb_dev, 0),
-               USB_REQ_SET_DESCRIPTOR,
-               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-               USB_DT_KEY << 8 | key_index, 0,
-               &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
-               USB_CTRL_SET_TIMEOUT);
-}
-
-
-/* FIXME: prototype for adding security */
-int wusb_dev_sec_add(struct wusbhc *wusbhc,
-                    struct usb_device *usb_dev, struct wusb_dev *wusb_dev)
-{
-       int result, bytes, secd_size;
-       struct device *dev = &usb_dev->dev;
-       struct usb_security_descriptor *secd, *new_secd;
-       const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
-       const void *itr, *top;
-       char buf[64];
-
-       secd = kmalloc(sizeof(*secd), GFP_KERNEL);
-       if (secd == NULL) {
-               result = -ENOMEM;
-               goto out;
-       }
-
-       result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
-                                   0, secd, sizeof(*secd));
-       if (result < (int)sizeof(*secd)) {
-               dev_err(dev, "Can't read security descriptor or "
-                       "not enough data: %d\n", result);
-               goto out;
-       }
-       secd_size = le16_to_cpu(secd->wTotalLength);
-       new_secd = krealloc(secd, secd_size, GFP_KERNEL);
-       if (new_secd == NULL) {
-               dev_err(dev,
-                       "Can't allocate space for security descriptors\n");
-               result = -ENOMEM;
-               goto out;
-       }
-       secd = new_secd;
-       result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
-                                   0, secd, secd_size);
-       if (result < secd_size) {
-               dev_err(dev, "Can't read security descriptor or "
-                       "not enough data: %d\n", result);
-               goto out;
-       }
-       bytes = 0;
-       itr = &secd[1];
-       top = (void *)secd + result;
-       while (itr < top) {
-               etd = itr;
-               if (top - itr < sizeof(*etd)) {
-                       dev_err(dev, "BUG: bad device security descriptor; "
-                               "not enough data (%zu vs %zu bytes left)\n",
-                               top - itr, sizeof(*etd));
-                       break;
-               }
-               if (etd->bLength < sizeof(*etd)) {
-                       dev_err(dev, "BUG: bad device encryption descriptor; "
-                               "descriptor is too short "
-                               "(%u vs %zu needed)\n",
-                               etd->bLength, sizeof(*etd));
-                       break;
-               }
-               itr += etd->bLength;
-               bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
-                                 "%s (0x%02x/%02x) ",
-                                 wusb_et_name(etd->bEncryptionType),
-                                 etd->bEncryptionValue, etd->bAuthKeyIndex);
-               if (etd->bEncryptionType == USB_ENC_TYPE_CCM_1)
-                       ccm1_etd = etd;
-       }
-       /* This code only supports CCM1 as of now. */
-       /* FIXME: user has to choose which sec mode to use?
-        * In theory we want CCM */
-       if (ccm1_etd == NULL) {
-               dev_err(dev, "WUSB device doesn't support CCM1 encryption, "
-                       "can't use!\n");
-               result = -EINVAL;
-               goto out;
-       }
-       wusb_dev->ccm1_etd = *ccm1_etd;
-       dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n",
-               buf, wusb_et_name(ccm1_etd->bEncryptionType),
-               ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex);
-       result = 0;
-out:
-       kfree(secd);
-       return result;
-}
-
-void wusb_dev_sec_rm(struct wusb_dev *wusb_dev)
-{
-       /* Nothing so far */
-}
-
-/**
- * Update the address of an unauthenticated WUSB device
- *
- * Once we have successfully authenticated, we take it to addr0 state
- * and then to a normal address.
- *
- * Before the device's address (as known by it) was usb_dev->devnum |
- * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum.
- */
-int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       int result = -ENOMEM;
-       struct usb_device *usb_dev = wusb_dev->usb_dev;
-       struct device *dev = &usb_dev->dev;
-       u8 new_address = wusb_dev->addr & 0x7F;
-
-       /* Set address 0 */
-       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
-                       USB_REQ_SET_ADDRESS,
-                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-                        0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "auth failed: can't set address 0: %d\n",
-                       result);
-               goto error_addr0;
-       }
-       result = wusb_set_dev_addr(wusbhc, wusb_dev, 0);
-       if (result < 0)
-               goto error_addr0;
-       usb_set_device_state(usb_dev, USB_STATE_DEFAULT);
-       usb_ep0_reinit(usb_dev);
-
-       /* Set new (authenticated) address. */
-       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
-                       USB_REQ_SET_ADDRESS,
-                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-                       new_address, 0, NULL, 0,
-                       USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "auth failed: can't set address %u: %d\n",
-                       new_address, result);
-               goto error_addr;
-       }
-       result = wusb_set_dev_addr(wusbhc, wusb_dev, new_address);
-       if (result < 0)
-               goto error_addr;
-       usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
-       usb_ep0_reinit(usb_dev);
-       usb_dev->authenticated = 1;
-error_addr:
-error_addr0:
-       return result;
-}
-
-/*
- *
- *
- */
-/* FIXME: split and cleanup */
-int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
-                           struct wusb_ckhdid *ck)
-{
-       int result = -ENOMEM;
-       struct usb_device *usb_dev = wusb_dev->usb_dev;
-       struct device *dev = &usb_dev->dev;
-       u32 tkid;
-       struct usb_handshake *hs;
-       struct aes_ccm_nonce ccm_n;
-       u8 mic[8];
-       struct wusb_keydvt_in keydvt_in;
-       struct wusb_keydvt_out keydvt_out;
-
-       hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL);
-       if (!hs)
-               goto error_kzalloc;
-
-       /* We need to turn encryption before beginning the 4way
-        * hshake (WUSB1.0[.3.2.2]) */
-       result = wusb_dev_set_encryption(usb_dev, 1);
-       if (result < 0)
-               goto error_dev_set_encryption;
-
-       tkid = wusbhc_next_tkid(wusbhc, wusb_dev);
-
-       hs[0].bMessageNumber = 1;
-       hs[0].bStatus = 0;
-       put_unaligned_le32(tkid, hs[0].tTKID);
-       hs[0].bReserved = 0;
-       memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID));
-       get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce));
-       memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */
-
-       result = usb_control_msg(
-               usb_dev, usb_sndctrlpipe(usb_dev, 0),
-               USB_REQ_SET_HANDSHAKE,
-               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-               1, 0, &hs[0], sizeof(hs[0]), USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Handshake1: request failed: %d\n", result);
-               goto error_hs1;
-       }
-
-       /* Handshake 2, from the device -- need to verify fields */
-       result = usb_control_msg(
-               usb_dev, usb_rcvctrlpipe(usb_dev, 0),
-               USB_REQ_GET_HANDSHAKE,
-               USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-               2, 0, &hs[1], sizeof(hs[1]), USB_CTRL_GET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Handshake2: request failed: %d\n", result);
-               goto error_hs2;
-       }
-
-       result = -EINVAL;
-       if (hs[1].bMessageNumber != 2) {
-               dev_err(dev, "Handshake2 failed: bad message number %u\n",
-                       hs[1].bMessageNumber);
-               goto error_hs2;
-       }
-       if (hs[1].bStatus != 0) {
-               dev_err(dev, "Handshake2 failed: bad status %u\n",
-                       hs[1].bStatus);
-               goto error_hs2;
-       }
-       if (memcmp(hs[0].tTKID, hs[1].tTKID, sizeof(hs[0].tTKID))) {
-               dev_err(dev, "Handshake2 failed: TKID mismatch "
-                       "(#1 0x%02x%02x%02x vs #2 0x%02x%02x%02x)\n",
-                       hs[0].tTKID[0], hs[0].tTKID[1], hs[0].tTKID[2],
-                       hs[1].tTKID[0], hs[1].tTKID[1], hs[1].tTKID[2]);
-               goto error_hs2;
-       }
-       if (memcmp(hs[0].CDID, hs[1].CDID, sizeof(hs[0].CDID))) {
-               dev_err(dev, "Handshake2 failed: CDID mismatch\n");
-               goto error_hs2;
-       }
-
-       /* Setup the CCM nonce */
-       memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */
-       put_unaligned_le32(tkid, ccm_n.tkid);
-       ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr;
-       ccm_n.dest_addr.data[0] = wusb_dev->addr;
-       ccm_n.dest_addr.data[1] = 0;
-
-       /* Derive the KCK and PTK from CK, the CCM, H and D nonces */
-       memcpy(keydvt_in.hnonce, hs[0].nonce, sizeof(keydvt_in.hnonce));
-       memcpy(keydvt_in.dnonce, hs[1].nonce, sizeof(keydvt_in.dnonce));
-       result = wusb_key_derive(&keydvt_out, ck->data, &ccm_n, &keydvt_in);
-       if (result < 0) {
-               dev_err(dev, "Handshake2 failed: cannot derive keys: %d\n",
-                       result);
-               goto error_hs2;
-       }
-
-       /* Compute MIC and verify it */
-       result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]);
-       if (result < 0) {
-               dev_err(dev, "Handshake2 failed: cannot compute MIC: %d\n",
-                       result);
-               goto error_hs2;
-       }
-
-       if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) {
-               dev_err(dev, "Handshake2 failed: MIC mismatch\n");
-               goto error_hs2;
-       }
-
-       /* Send Handshake3 */
-       hs[2].bMessageNumber = 3;
-       hs[2].bStatus = 0;
-       put_unaligned_le32(tkid, hs[2].tTKID);
-       hs[2].bReserved = 0;
-       memcpy(hs[2].CDID, &wusb_dev->cdid, sizeof(hs[2].CDID));
-       memcpy(hs[2].nonce, hs[0].nonce, sizeof(hs[2].nonce));
-       result = wusb_oob_mic(hs[2].MIC, keydvt_out.kck, &ccm_n, &hs[2]);
-       if (result < 0) {
-               dev_err(dev, "Handshake3 failed: cannot compute MIC: %d\n",
-                       result);
-               goto error_hs2;
-       }
-
-       result = usb_control_msg(
-               usb_dev, usb_sndctrlpipe(usb_dev, 0),
-               USB_REQ_SET_HANDSHAKE,
-               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-               3, 0, &hs[2], sizeof(hs[2]), USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Handshake3: request failed: %d\n", result);
-               goto error_hs3;
-       }
-
-       result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid,
-                                keydvt_out.ptk, sizeof(keydvt_out.ptk));
-       if (result < 0)
-               goto error_wusbhc_set_ptk;
-
-       result = wusb_dev_set_gtk(wusbhc, wusb_dev);
-       if (result < 0) {
-               dev_err(dev, "Set GTK for device: request failed: %d\n",
-                       result);
-               goto error_wusbhc_set_gtk;
-       }
-
-       /* Update the device's address from unauth to auth */
-       if (usb_dev->authenticated == 0) {
-               result = wusb_dev_update_address(wusbhc, wusb_dev);
-               if (result < 0)
-                       goto error_dev_update_address;
-       }
-       result = 0;
-       dev_info(dev, "device authenticated\n");
-
-error_dev_update_address:
-error_wusbhc_set_gtk:
-error_wusbhc_set_ptk:
-error_hs3:
-error_hs2:
-error_hs1:
-       memset(hs, 0, 3*sizeof(hs[0]));
-       memzero_explicit(&keydvt_out, sizeof(keydvt_out));
-       memzero_explicit(&keydvt_in, sizeof(keydvt_in));
-       memzero_explicit(&ccm_n, sizeof(ccm_n));
-       memzero_explicit(mic, sizeof(mic));
-       if (result < 0)
-               wusb_dev_set_encryption(usb_dev, 0);
-error_dev_set_encryption:
-       kfree(hs);
-error_kzalloc:
-       return result;
-}
-
-/*
- * Once all connected and authenticated devices have received the new
- * GTK, switch the host to using it.
- */
-static void wusbhc_gtk_rekey_work(struct work_struct *work)
-{
-       struct wusbhc *wusbhc = container_of(work,
-                                       struct wusbhc, gtk_rekey_work);
-       size_t key_size = sizeof(wusbhc->gtk.data);
-       int port_idx;
-       struct wusb_dev *wusb_dev, *wusb_dev_next;
-       LIST_HEAD(rekey_list);
-
-       mutex_lock(&wusbhc->mutex);
-       /* generate the new key */
-       wusbhc_generate_gtk(wusbhc);
-       /* roll the gtk index. */
-       wusbhc->gtk_index = (wusbhc->gtk_index + 1) % (WUSB_KEY_INDEX_MAX + 1);
-       /*
-        * Save all connected devices on a list while holding wusbhc->mutex and
-        * take a reference to each one.  Then submit the set key request to
-        * them after releasing the lock in order to avoid a deadlock.
-        */
-       for (port_idx = 0; port_idx < wusbhc->ports_max; port_idx++) {
-               wusb_dev = wusbhc->port[port_idx].wusb_dev;
-               if (!wusb_dev || !wusb_dev->usb_dev
-                       || !wusb_dev->usb_dev->authenticated)
-                       continue;
-
-               wusb_dev_get(wusb_dev);
-               list_add_tail(&wusb_dev->rekey_node, &rekey_list);
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       /* Submit the rekey requests without holding wusbhc->mutex. */
-       list_for_each_entry_safe(wusb_dev, wusb_dev_next, &rekey_list,
-               rekey_node) {
-               list_del_init(&wusb_dev->rekey_node);
-               dev_dbg(&wusb_dev->usb_dev->dev,
-                       "%s: rekey device at port %d\n",
-                       __func__, wusb_dev->port_idx);
-
-               if (wusb_dev_set_gtk(wusbhc, wusb_dev) < 0) {
-                       dev_err(&wusb_dev->usb_dev->dev,
-                               "%s: rekey device at port %d failed\n",
-                               __func__, wusb_dev->port_idx);
-               }
-               wusb_dev_put(wusb_dev);
-       }
-
-       /* Switch the host controller to use the new GTK. */
-       mutex_lock(&wusbhc->mutex);
-       wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
-               &wusbhc->gtk.descr.bKeyData, key_size);
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/**
- * wusbhc_gtk_rekey - generate and distribute a new GTK
- * @wusbhc: the WUSB host controller
- *
- * Generate a new GTK and distribute it to all connected and
- * authenticated devices.  When all devices have the new GTK, the host
- * starts using it.
- *
- * This must be called after every device disconnect (see [WUSB]
- * section 6.2.11.2).
- */
-void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
-{
-       /*
-        * We need to submit a URB to the downstream WUSB devices in order to
-        * change the group key.  This can't be done while holding the
-        * wusbhc->mutex since that is also taken in the urb_enqueue routine
-        * and will cause a deadlock.  Instead, queue a work item to do
-        * it when the lock is not held
-        */
-       queue_work(wusbhc->wq_security, &wusbhc->gtk_rekey_work);
-}
diff --git a/drivers/staging/wusbcore/wa-hc.c b/drivers/staging/wusbcore/wa-hc.c
deleted file mode 100644 (file)
index 6827075..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wire Adapter Host Controller Driver
- * Common items to HWA and DWA based HCDs
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include "wusbhc.h"
-#include "wa-hc.h"
-
-/**
- * Assumes
- *
- * wa->usb_dev and wa->usb_iface initialized and refcounted,
- * wa->wa_descr initialized.
- */
-int wa_create(struct wahc *wa, struct usb_interface *iface,
-       kernel_ulong_t quirks)
-{
-       int result;
-       struct device *dev = &iface->dev;
-
-       if (iface->cur_altsetting->desc.bNumEndpoints < 3)
-               return -ENODEV;
-
-       result = wa_rpipes_create(wa);
-       if (result < 0)
-               goto error_rpipes_create;
-       wa->quirks = quirks;
-       /* Fill up Data Transfer EP pointers */
-       wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;
-       wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
-       wa->dti_buf_size = usb_endpoint_maxp(wa->dti_epd);
-       wa->dti_buf = kmalloc(wa->dti_buf_size, GFP_KERNEL);
-       if (wa->dti_buf == NULL) {
-               result = -ENOMEM;
-               goto error_dti_buf_alloc;
-       }
-       result = wa_nep_create(wa, iface);
-       if (result < 0) {
-               dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n",
-                       result);
-               goto error_nep_create;
-       }
-       return 0;
-
-error_nep_create:
-       kfree(wa->dti_buf);
-error_dti_buf_alloc:
-       wa_rpipes_destroy(wa);
-error_rpipes_create:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wa_create);
-
-
-void __wa_destroy(struct wahc *wa)
-{
-       if (wa->dti_urb) {
-               usb_kill_urb(wa->dti_urb);
-               usb_put_urb(wa->dti_urb);
-       }
-       kfree(wa->dti_buf);
-       wa_nep_destroy(wa);
-       wa_rpipes_destroy(wa);
-}
-EXPORT_SYMBOL_GPL(__wa_destroy);
-
-/**
- * wa_reset_all - reset the WA device
- * @wa: the WA to be reset
- *
- * For HWAs the radio controller and all other PALs are also reset.
- */
-void wa_reset_all(struct wahc *wa)
-{
-       /* FIXME: assuming HWA. */
-       wusbhc_reset_all(wa->wusb);
-}
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Wireless USB Wire Adapter core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/wa-hc.h b/drivers/staging/wusbcore/wa-hc.h
deleted file mode 100644 (file)
index 5a38465..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * HWA Host Controller Driver
- * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8])
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This driver implements a USB Host Controller (struct usb_hcd) for a
- * Wireless USB Host Controller based on the Wireless USB 1.0
- * Host-Wire-Adapter specification (in layman terms, a USB-dongle that
- * implements a Wireless USB host).
- *
- * Check out the Design-overview.txt file in the source documentation
- * for other details on the implementation.
- *
- * Main blocks:
- *
- *  driver     glue with the driver API, workqueue daemon
- *
- *  lc         RC instance life cycle management (create, destroy...)
- *
- *  hcd        glue with the USB API Host Controller Interface API.
- *
- *  nep        Notification EndPoint management: collect notifications
- *             and queue them with the workqueue daemon.
- *
- *             Handle notifications as coming from the NEP. Sends them
- *             off others to their respective modules (eg: connect,
- *             disconnect and reset go to devconnect).
- *
- *  rpipe      Remote Pipe management; rpipe is what we use to write
- *             to an endpoint on a WUSB device that is connected to a
- *             HWA RC.
- *
- *  xfer       Transfer management -- this is all the code that gets a
- *             buffer and pushes it to a device (or viceversa). *
- *
- * Some day a lot of this code will be shared between this driver and
- * the drivers for DWA (xfer, rpipe).
- *
- * All starts at driver.c:hwahc_probe(), when one of this guys is
- * connected. hwahc_disconnect() stops it.
- *
- * During operation, the main driver is devices connecting or
- * disconnecting. They cause the HWA RC to send notifications into
- * nep.c:hwahc_nep_cb() that will dispatch them to
- * notif.c:wa_notif_dispatch(). From there they will fan to cause
- * device connects, disconnects, etc.
- *
- * Note much of the activity is difficult to follow. For example a
- * device connect goes to devconnect, which will cause the "fake" root
- * hub port to show a connect and stop there. Then hub_wq will notice
- * and call into the rh.c:hwahc_rc_port_reset() code to authenticate
- * the device (and this might require user intervention) and enable
- * the port.
- *
- * We also have a timer workqueue going from devconnect.c that
- * schedules in hwahc_devconnect_create().
- *
- * The rest of the traffic is in the usual entry points of a USB HCD,
- * which are hooked up in driver.c:hwahc_rc_driver, and defined in
- * hcd.c.
- */
-
-#ifndef __HWAHC_INTERNAL_H__
-#define __HWAHC_INTERNAL_H__
-
-#include <linux/completion.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
-#include "../uwb/uwb.h"
-#include "include/wusb.h"
-#include "include/wusb-wa.h"
-
-struct wusbhc;
-struct wahc;
-extern void wa_urb_enqueue_run(struct work_struct *ws);
-extern void wa_process_errored_transfers_run(struct work_struct *ws);
-
-/**
- * RPipe instance
- *
- * @descr's fields are kept in LE, as we need to send it back and
- * forth.
- *
- * @wa is referenced when set
- *
- * @segs_available is the number of requests segments that still can
- *                 be submitted to the controller without overloading
- *                 it. It is initialized to descr->wRequests when
- *                 aiming.
- *
- * A rpipe supports a max of descr->wRequests at the same time; before
- * submitting seg_lock has to be taken. If segs_avail > 0, then we can
- * submit; if not, we have to queue them.
- */
-struct wa_rpipe {
-       struct kref refcnt;
-       struct usb_rpipe_descriptor descr;
-       struct usb_host_endpoint *ep;
-       struct wahc *wa;
-       spinlock_t seg_lock;
-       struct list_head seg_list;
-       struct list_head list_node;
-       atomic_t segs_available;
-       u8 buffer[1];   /* For reads/writes on USB */
-};
-
-
-enum wa_dti_state {
-       WA_DTI_TRANSFER_RESULT_PENDING,
-       WA_DTI_ISOC_PACKET_STATUS_PENDING,
-       WA_DTI_BUF_IN_DATA_PENDING
-};
-
-enum wa_quirks {
-       /*
-        * The Alereon HWA expects the data frames in isochronous transfer
-        * requests to be concatenated and not sent as separate packets.
-        */
-       WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC      = 0x01,
-       /*
-        * The Alereon HWA can be instructed to not send transfer notifications
-        * as an optimization.
-        */
-       WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS       = 0x02,
-};
-
-enum wa_vendor_specific_requests {
-       WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C,
-       WA_REQ_ALEREON_FEATURE_SET = 0x01,
-       WA_REQ_ALEREON_FEATURE_CLEAR = 0x00,
-};
-
-#define WA_MAX_BUF_IN_URBS     4
-/**
- * Instance of a HWA Host Controller
- *
- * Except where a more specific lock/mutex applies or atomic, all
- * fields protected by @mutex.
- *
- * @wa_descr  Can be accessed without locking because it is in
- *            the same area where the device descriptors were
- *            read, so it is guaranteed to exist unmodified while
- *            the device exists.
- *
- *            Endianess has been converted to CPU's.
- *
- * @nep_* can be accessed without locking as its processing is
- *        serialized; we submit a NEP URB and it comes to
- *        hwahc_nep_cb(), which won't issue another URB until it is
- *        done processing it.
- *
- * @xfer_list:
- *
- *   List of active transfers to verify existence from a xfer id
- *   gotten from the xfer result message. Can't use urb->list because
- *   it goes by endpoint, and we don't know the endpoint at the time
- *   when we get the xfer result message. We can't really rely on the
- *   pointer (will have to change for 64 bits) as the xfer id is 32 bits.
- *
- * @xfer_delayed_list:   List of transfers that need to be started
- *                       (with a workqueue, because they were
- *                       submitted from an atomic context).
- *
- * FIXME: this needs to be layered up: a wusbhc layer (for sharing
- *        commonalities with WHCI), a wa layer (for sharing
- *        commonalities with DWA-RC).
- */
-struct wahc {
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-
-       /* HC to deliver notifications */
-       union {
-               struct wusbhc *wusb;
-               struct dwahc *dwa;
-       };
-
-       const struct usb_endpoint_descriptor *dto_epd, *dti_epd;
-       const struct usb_wa_descriptor *wa_descr;
-
-       struct urb *nep_urb;            /* Notification EndPoint [lockless] */
-       struct edc nep_edc;
-       void *nep_buffer;
-       size_t nep_buffer_size;
-
-       atomic_t notifs_queued;
-
-       u16 rpipes;
-       unsigned long *rpipe_bm;        /* rpipe usage bitmap */
-       struct list_head rpipe_delayed_list;    /* delayed RPIPES. */
-       spinlock_t rpipe_lock;  /* protect rpipe_bm and delayed list */
-       struct mutex rpipe_mutex;       /* assigning resources to endpoints */
-
-       /*
-        * dti_state is used to track the state of the dti_urb. When dti_state
-        * is WA_DTI_ISOC_PACKET_STATUS_PENDING, dti_isoc_xfer_in_progress and
-        * dti_isoc_xfer_seg identify which xfer the incoming isoc packet
-        * status refers to.
-        */
-       enum wa_dti_state dti_state;
-       u32 dti_isoc_xfer_in_progress;
-       u8  dti_isoc_xfer_seg;
-       struct urb *dti_urb;            /* URB for reading xfer results */
-                                       /* URBs for reading data in */
-       struct urb buf_in_urbs[WA_MAX_BUF_IN_URBS];
-       int active_buf_in_urbs;         /* number of buf_in_urbs active. */
-       struct edc dti_edc;             /* DTI error density counter */
-       void *dti_buf;
-       size_t dti_buf_size;
-
-       unsigned long dto_in_use;       /* protect dto endoint serialization */
-
-       s32 status;                     /* For reading status */
-
-       struct list_head xfer_list;
-       struct list_head xfer_delayed_list;
-       struct list_head xfer_errored_list;
-       /*
-        * lock for the above xfer lists.  Can be taken while a xfer->lock is
-        * held but not in the reverse order.
-        */
-       spinlock_t xfer_list_lock;
-       struct work_struct xfer_enqueue_work;
-       struct work_struct xfer_error_work;
-       atomic_t xfer_id_count;
-
-       kernel_ulong_t  quirks;
-};
-
-
-extern int wa_create(struct wahc *wa, struct usb_interface *iface,
-       kernel_ulong_t);
-extern void __wa_destroy(struct wahc *wa);
-extern int wa_dti_start(struct wahc *wa);
-void wa_reset_all(struct wahc *wa);
-
-
-/* Miscellaneous constants */
-enum {
-       /** Max number of EPROTO errors we tolerate on the NEP in a
-        * period of time */
-       HWAHC_EPROTO_MAX = 16,
-       /** Period of time for EPROTO errors (in jiffies) */
-       HWAHC_EPROTO_PERIOD = 4 * HZ,
-};
-
-
-/* Notification endpoint handling */
-extern int wa_nep_create(struct wahc *, struct usb_interface *);
-extern void wa_nep_destroy(struct wahc *);
-
-static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask)
-{
-       struct urb *urb = wa->nep_urb;
-       urb->transfer_buffer = wa->nep_buffer;
-       urb->transfer_buffer_length = wa->nep_buffer_size;
-       return usb_submit_urb(urb, gfp_mask);
-}
-
-static inline void wa_nep_disarm(struct wahc *wa)
-{
-       usb_kill_urb(wa->nep_urb);
-}
-
-
-/* RPipes */
-static inline void wa_rpipe_init(struct wahc *wa)
-{
-       INIT_LIST_HEAD(&wa->rpipe_delayed_list);
-       spin_lock_init(&wa->rpipe_lock);
-       mutex_init(&wa->rpipe_mutex);
-}
-
-static inline void wa_init(struct wahc *wa)
-{
-       int index;
-
-       edc_init(&wa->nep_edc);
-       atomic_set(&wa->notifs_queued, 0);
-       wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
-       wa_rpipe_init(wa);
-       edc_init(&wa->dti_edc);
-       INIT_LIST_HEAD(&wa->xfer_list);
-       INIT_LIST_HEAD(&wa->xfer_delayed_list);
-       INIT_LIST_HEAD(&wa->xfer_errored_list);
-       spin_lock_init(&wa->xfer_list_lock);
-       INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run);
-       INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run);
-       wa->dto_in_use = 0;
-       atomic_set(&wa->xfer_id_count, 1);
-       /* init the buf in URBs */
-       for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index)
-               usb_init_urb(&(wa->buf_in_urbs[index]));
-       wa->active_buf_in_urbs = 0;
-}
-
-/**
- * Destroy a pipe (when refcount drops to zero)
- *
- * Assumes it has been moved to the "QUIESCING" state.
- */
-struct wa_xfer;
-extern void rpipe_destroy(struct kref *_rpipe);
-static inline
-void __rpipe_get(struct wa_rpipe *rpipe)
-{
-       kref_get(&rpipe->refcnt);
-}
-extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *,
-                          struct urb *, gfp_t);
-static inline void rpipe_put(struct wa_rpipe *rpipe)
-{
-       kref_put(&rpipe->refcnt, rpipe_destroy);
-
-}
-extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *);
-extern void rpipe_clear_feature_stalled(struct wahc *,
-                       struct usb_host_endpoint *);
-extern int wa_rpipes_create(struct wahc *);
-extern void wa_rpipes_destroy(struct wahc *);
-static inline void rpipe_avail_dec(struct wa_rpipe *rpipe)
-{
-       atomic_dec(&rpipe->segs_available);
-}
-
-/**
- * Returns true if the rpipe is ready to submit more segments.
- */
-static inline int rpipe_avail_inc(struct wa_rpipe *rpipe)
-{
-       return atomic_inc_return(&rpipe->segs_available) > 0
-               && !list_empty(&rpipe->seg_list);
-}
-
-
-/* Transferring data */
-extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *,
-                         struct urb *, gfp_t);
-extern int wa_urb_dequeue(struct wahc *, struct urb *, int);
-extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *);
-
-
-/* Misc
- *
- * FIXME: Refcounting for the actual @hwahc object is not correct; I
- *        mean, this should be refcounting on the HCD underneath, but
- *        it is not. In any case, the semantics for HCD refcounting
- *        are *weird*...on refcount reaching zero it just frees
- *        it...no RC specific function is called...unless I miss
- *        something.
- *
- * FIXME: has to go away in favour of a 'struct' hcd based solution
- */
-static inline struct wahc *wa_get(struct wahc *wa)
-{
-       usb_get_intf(wa->usb_iface);
-       return wa;
-}
-
-static inline void wa_put(struct wahc *wa)
-{
-       usb_put_intf(wa->usb_iface);
-}
-
-
-static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature)
-{
-       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       feature,
-                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-
-static inline int __wa_set_feature(struct wahc *wa, u16 feature)
-{
-       return  __wa_feature(wa, 1, feature);
-}
-
-
-static inline int __wa_clear_feature(struct wahc *wa, u16 feature)
-{
-       return __wa_feature(wa, 0, feature);
-}
-
-
-/**
- * Return the status of a Wire Adapter
- *
- * @wa:                Wire Adapter instance
- * @returns     < 0 errno code on error, or status bitmap as described
- *              in WUSB1.0[8.3.1.6].
- *
- * NOTE: need malloc, some arches don't take USB from the stack
- */
-static inline
-s32 __wa_get_status(struct wahc *wa)
-{
-       s32 result;
-       result = usb_control_msg(
-               wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
-               USB_REQ_GET_STATUS,
-               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               &wa->status, sizeof(wa->status), USB_CTRL_GET_TIMEOUT);
-       if (result >= 0)
-               result = wa->status;
-       return result;
-}
-
-
-/**
- * Waits until the Wire Adapter's status matches @mask/@value
- *
- * @wa:                Wire Adapter instance.
- * @returns     < 0 errno code on error, otherwise status.
- *
- * Loop until the WAs status matches the mask and value (status & mask
- * == value). Timeout if it doesn't happen.
- *
- * FIXME: is there an official specification on how long status
- *        changes can take?
- */
-static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value)
-{
-       s32 result;
-       unsigned loops = 10;
-       do {
-               msleep(50);
-               result = __wa_get_status(wa);
-               if ((result & mask) == value)
-                       break;
-               if (loops-- == 0) {
-                       result = -ETIMEDOUT;
-                       break;
-               }
-       } while (result >= 0);
-       return result;
-}
-
-
-/** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */
-static inline int __wa_stop(struct wahc *wa)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-
-       result = __wa_clear_feature(wa, WA_ENABLE);
-       if (result < 0 && result != -ENODEV) {
-               dev_err(dev, "error commanding HC to stop: %d\n", result);
-               goto out;
-       }
-       result = __wa_wait_status(wa, WA_ENABLE, 0);
-       if (result < 0 && result != -ENODEV)
-               dev_err(dev, "error waiting for HC to stop: %d\n", result);
-out:
-       return 0;
-}
-
-
-#endif /* #ifndef __HWAHC_INTERNAL_H__ */
diff --git a/drivers/staging/wusbcore/wa-nep.c b/drivers/staging/wusbcore/wa-nep.c
deleted file mode 100644 (file)
index 5f0656d..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
- * Notification EndPoint support
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This part takes care of getting the notification from the hw
- * only and dispatching through wusbwad into
- * wa_notif_dispatch. Handling is done there.
- *
- * WA notifications are limited in size; most of them are three or
- * four bytes long, and the longest is the HWA Device Notification,
- * which would not exceed 38 bytes (DNs are limited in payload to 32
- * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA
- * header (WUSB1.0[8.5.4.2]).
- *
- * It is not clear if more than one Device Notification can be packed
- * in a HWA Notification, I assume no because of the wording in
- * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could
- * get is 256 bytes (as the bLength field is a byte).
- *
- * So what we do is we have this buffer and read into it; when a
- * notification arrives we schedule work to a specific, single thread
- * workqueue (so notifications are serialized) and copy the
- * notification data. After scheduling the work, we rearm the read from
- * the notification endpoint.
- *
- * Entry points here are:
- *
- * wa_nep_[create|destroy]()   To initialize/release this subsystem
- *
- * wa_nep_cb()                 Callback for the notification
- *                                endpoint; when data is ready, this
- *                                does the dispatching.
- */
-#include <linux/workqueue.h>
-#include <linux/ctype.h>
-#include <linux/slab.h>
-
-#include "wa-hc.h"
-#include "wusbhc.h"
-
-/* Structure for queueing notifications to the workqueue */
-struct wa_notif_work {
-       struct work_struct work;
-       struct wahc *wa;
-       size_t size;
-       u8 data[];
-};
-
-/*
- * Process incoming notifications from the WA's Notification EndPoint
- * [the wuswad daemon, basically]
- *
- * @_nw:       Pointer to a descriptor which has the pointer to the
- *             @wa, the size of the buffer and the work queue
- *             structure (so we can free all when done).
- * @returns     0 if ok, < 0 errno code on error.
- *
- * All notifications follow the same format; they need to start with a
- * 'struct wa_notif_hdr' header, so it is easy to parse through
- * them. We just break the buffer in individual notifications (the
- * standard doesn't say if it can be done or is forbidden, so we are
- * cautious) and dispatch each.
- *
- * So the handling layers are is:
- *
- *   WA specific notification (from NEP)
- *      Device Notification Received -> wa_handle_notif_dn()
- *        WUSB Device notification generic handling
- *      BPST Adjustment -> wa_handle_notif_bpst_adj()
- *      ... -> ...
- *
- * @wa has to be referenced
- */
-static void wa_notif_dispatch(struct work_struct *ws)
-{
-       void *itr;
-       u8 missing = 0;
-       struct wa_notif_work *nw = container_of(ws, struct wa_notif_work,
-                                               work);
-       struct wahc *wa = nw->wa;
-       struct wa_notif_hdr *notif_hdr;
-       size_t size;
-
-       struct device *dev = &wa->usb_iface->dev;
-
-#if 0
-       /* FIXME: need to check for this??? */
-       if (usb_hcd->state == HC_STATE_QUIESCING)       /* Going down? */
-               goto out;                               /* screw it */
-#endif
-       atomic_dec(&wa->notifs_queued);         /* Throttling ctl */
-       size = nw->size;
-       itr = nw->data;
-
-       while (size) {
-               if (size < sizeof(*notif_hdr)) {
-                       missing = sizeof(*notif_hdr) - size;
-                       goto exhausted_buffer;
-               }
-               notif_hdr = itr;
-               if (size < notif_hdr->bLength)
-                       goto exhausted_buffer;
-               itr += notif_hdr->bLength;
-               size -= notif_hdr->bLength;
-               /* Dispatch the notification [don't use itr or size!] */
-               switch (notif_hdr->bNotifyType) {
-               case HWA_NOTIF_DN: {
-                       struct hwa_notif_dn *hwa_dn;
-                       hwa_dn = container_of(notif_hdr, struct hwa_notif_dn,
-                                             hdr);
-                       wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr,
-                                        hwa_dn->dndata,
-                                        notif_hdr->bLength - sizeof(*hwa_dn));
-                       break;
-               }
-               case WA_NOTIF_TRANSFER:
-                       wa_handle_notif_xfer(wa, notif_hdr);
-                       break;
-               case HWA_NOTIF_BPST_ADJ:
-                       break; /* no action needed for BPST ADJ. */
-               case DWA_NOTIF_RWAKE:
-               case DWA_NOTIF_PORTSTATUS:
-                       /* FIXME: unimplemented WA NOTIFs */
-                       /* fallthru */
-               default:
-                       dev_err(dev, "HWA: unknown notification 0x%x, "
-                               "%zu bytes; discarding\n",
-                               notif_hdr->bNotifyType,
-                               (size_t)notif_hdr->bLength);
-                       break;
-               }
-       }
-out:
-       wa_put(wa);
-       kfree(nw);
-       return;
-
-       /* THIS SHOULD NOT HAPPEN
-        *
-        * Buffer exahusted with partial data remaining; just warn and
-        * discard the data, as this should not happen.
-        */
-exhausted_buffer:
-       dev_warn(dev, "HWA: device sent short notification, "
-                "%d bytes missing; discarding %d bytes.\n",
-                missing, (int)size);
-       goto out;
-}
-
-/*
- * Deliver incoming WA notifications to the wusbwa workqueue
- *
- * @wa:        Pointer the Wire Adapter Controller Data Streaming
- *              instance (part of an 'struct usb_hcd').
- * @size:       Size of the received buffer
- * @returns     0 if ok, < 0 errno code on error.
- *
- * The input buffer is @wa->nep_buffer, with @size bytes
- * (guaranteed to fit in the allocated space,
- * @wa->nep_buffer_size).
- */
-static int wa_nep_queue(struct wahc *wa, size_t size)
-{
-       int result = 0;
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_notif_work *nw;
-
-       /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */
-       BUG_ON(size > wa->nep_buffer_size);
-       if (size == 0)
-               goto out;
-       if (atomic_read(&wa->notifs_queued) > 200) {
-               if (printk_ratelimit())
-                       dev_err(dev, "Too many notifications queued, "
-                               "throttling back\n");
-               goto out;
-       }
-       nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC);
-       if (nw == NULL) {
-               if (printk_ratelimit())
-                       dev_err(dev, "No memory to queue notification\n");
-               result = -ENOMEM;
-               goto out;
-       }
-       INIT_WORK(&nw->work, wa_notif_dispatch);
-       nw->wa = wa_get(wa);
-       nw->size = size;
-       memcpy(nw->data, wa->nep_buffer, size);
-       atomic_inc(&wa->notifs_queued);         /* Throttling ctl */
-       queue_work(wusbd, &nw->work);
-out:
-       /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */
-       return result;
-}
-
-/*
- * Callback for the notification event endpoint
- *
- * Check's that everything is fine and then passes the data to be
- * queued to the workqueue.
- */
-static void wa_nep_cb(struct urb *urb)
-{
-       int result;
-       struct wahc *wa = urb->context;
-       struct device *dev = &wa->usb_iface->dev;
-
-       switch (result = urb->status) {
-       case 0:
-               result = wa_nep_queue(wa, urb->actual_length);
-               if (result < 0)
-                       dev_err(dev, "NEP: unable to process notification(s): "
-                               "%d\n", result);
-               break;
-       case -ECONNRESET:       /* Not an error, but a controlled situation; */
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-       case -ESHUTDOWN:
-               dev_dbg(dev, "NEP: going down %d\n", urb->status);
-               goto out;
-       default:        /* On general errors, we retry unless it gets ugly */
-               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)) {
-                       dev_err(dev, "NEP: URB max acceptable errors "
-                               "exceeded, resetting device\n");
-                       wa_reset_all(wa);
-                       goto out;
-               }
-               dev_err(dev, "NEP: URB error %d\n", urb->status);
-       }
-       result = wa_nep_arm(wa, GFP_ATOMIC);
-       if (result < 0) {
-               dev_err(dev, "NEP: cannot submit URB: %d\n", result);
-               wa_reset_all(wa);
-       }
-out:
-       return;
-}
-
-/*
- * Initialize @wa's notification and event's endpoint stuff
- *
- * This includes the allocating the read buffer, the context ID
- * allocation bitmap, the URB and submitting the URB.
- */
-int wa_nep_create(struct wahc *wa, struct usb_interface *iface)
-{
-       int result;
-       struct usb_endpoint_descriptor *epd;
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-       struct device *dev = &iface->dev;
-
-       edc_init(&wa->nep_edc);
-       epd = &iface->cur_altsetting->endpoint[0].desc;
-       wa->nep_buffer_size = 1024;
-       wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL);
-       if (!wa->nep_buffer)
-               goto error_nep_buffer;
-       wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (wa->nep_urb == NULL)
-               goto error_urb_alloc;
-       usb_fill_int_urb(wa->nep_urb, usb_dev,
-                        usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
-                        wa->nep_buffer, wa->nep_buffer_size,
-                        wa_nep_cb, wa, epd->bInterval);
-       result = wa_nep_arm(wa, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "Cannot submit notification URB: %d\n", result);
-               goto error_nep_arm;
-       }
-       return 0;
-
-error_nep_arm:
-       usb_free_urb(wa->nep_urb);
-error_urb_alloc:
-       kfree(wa->nep_buffer);
-error_nep_buffer:
-       return -ENOMEM;
-}
-
-void wa_nep_destroy(struct wahc *wa)
-{
-       wa_nep_disarm(wa);
-       usb_free_urb(wa->nep_urb);
-       kfree(wa->nep_buffer);
-}
diff --git a/drivers/staging/wusbcore/wa-rpipe.c b/drivers/staging/wusbcore/wa-rpipe.c
deleted file mode 100644 (file)
index a5734cb..0000000
+++ /dev/null
@@ -1,539 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter
- * rpipe management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- *
- * RPIPE
- *
- *   Targeted at different downstream endpoints
- *
- *   Descriptor: use to config the remote pipe.
- *
- *   The number of blocks could be dynamic (wBlocks in descriptor is
- *   0)--need to schedule them then.
- *
- * Each bit in wa->rpipe_bm represents if an rpipe is being used or
- * not. Rpipes are represented with a 'struct wa_rpipe' that is
- * attached to the hcpriv member of a 'struct usb_host_endpoint'.
- *
- * When you need to xfer data to an endpoint, you get an rpipe for it
- * with wa_ep_rpipe_get(), which gives you a reference to the rpipe
- * and keeps a single one (the first one) with the endpoint. When you
- * are done transferring, you drop that reference. At the end the
- * rpipe is always allocated and bound to the endpoint. There it might
- * be recycled when not used.
- *
- * Addresses:
- *
- *  We use a 1:1 mapping mechanism between port address (0 based
- *  index, actually) and the address. The USB stack knows about this.
- *
- *  USB Stack port number    4 (1 based)
- *  WUSB code port index     3 (0 based)
- *  USB Address             5 (2 based -- 0 is for default, 1 for root hub)
- *
- *  Now, because we don't use the concept as default address exactly
- *  like the (wired) USB code does, we need to kind of skip it. So we
- *  never take addresses from the urb->pipe, but from the
- *  urb->dev->devnum, to make sure that we always have the right
- *  destination address.
- */
-#include <linux/atomic.h>
-#include <linux/bitmap.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "wusbhc.h"
-#include "wa-hc.h"
-
-static int __rpipe_get_descr(struct wahc *wa,
-                            struct usb_rpipe_descriptor *descr, u16 index)
-{
-       ssize_t result;
-       struct device *dev = &wa->usb_iface->dev;
-
-       /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor()
-        * function because the arguments are different.
-        */
-       result = usb_control_msg(
-               wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
-               USB_REQ_GET_DESCRIPTOR,
-               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-               USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
-               USB_CTRL_GET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "rpipe %u: get descriptor failed: %d\n",
-                       index, (int)result);
-               goto error;
-       }
-       if (result < sizeof(*descr)) {
-               dev_err(dev, "rpipe %u: got short descriptor "
-                       "(%zd vs %zd bytes needed)\n",
-                       index, result, sizeof(*descr));
-               result = -EINVAL;
-               goto error;
-       }
-       result = 0;
-
-error:
-       return result;
-}
-
-/*
- *
- * The descriptor is assumed to be properly initialized (ie: you got
- * it through __rpipe_get_descr()).
- */
-static int __rpipe_set_descr(struct wahc *wa,
-                            struct usb_rpipe_descriptor *descr, u16 index)
-{
-       ssize_t result;
-       struct device *dev = &wa->usb_iface->dev;
-
-       /* we cannot use the usb_get_descriptor() function because the
-        * arguments are different.
-        */
-       result = usb_control_msg(
-               wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-               USB_REQ_SET_DESCRIPTOR,
-               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-               USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
-               USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "rpipe %u: set descriptor failed: %d\n",
-                       index, (int)result);
-               goto error;
-       }
-       if (result < sizeof(*descr)) {
-               dev_err(dev, "rpipe %u: sent short descriptor "
-                       "(%zd vs %zd bytes required)\n",
-                       index, result, sizeof(*descr));
-               result = -EINVAL;
-               goto error;
-       }
-       result = 0;
-
-error:
-       return result;
-
-}
-
-static void rpipe_init(struct wa_rpipe *rpipe)
-{
-       kref_init(&rpipe->refcnt);
-       spin_lock_init(&rpipe->seg_lock);
-       INIT_LIST_HEAD(&rpipe->seg_list);
-       INIT_LIST_HEAD(&rpipe->list_node);
-}
-
-static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&wa->rpipe_lock, flags);
-       rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx);
-       if (rpipe_idx < wa->rpipes)
-               set_bit(rpipe_idx, wa->rpipe_bm);
-       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
-
-       return rpipe_idx;
-}
-
-static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&wa->rpipe_lock, flags);
-       clear_bit(rpipe_idx, wa->rpipe_bm);
-       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
-}
-
-void rpipe_destroy(struct kref *_rpipe)
-{
-       struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt);
-       u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
-
-       if (rpipe->ep)
-               rpipe->ep->hcpriv = NULL;
-       rpipe_put_idx(rpipe->wa, index);
-       wa_put(rpipe->wa);
-       kfree(rpipe);
-}
-EXPORT_SYMBOL_GPL(rpipe_destroy);
-
-/*
- * Locate an idle rpipe, create an structure for it and return it
- *
- * @wa   is referenced and unlocked
- * @crs   enum rpipe_attr, required endpoint characteristics
- *
- * The rpipe can be used only sequentially (not in parallel).
- *
- * The rpipe is moved into the "ready" state.
- */
-static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs,
-                         gfp_t gfp)
-{
-       int result;
-       unsigned rpipe_idx;
-       struct wa_rpipe *rpipe;
-       struct device *dev = &wa->usb_iface->dev;
-
-       rpipe = kzalloc(sizeof(*rpipe), gfp);
-       if (rpipe == NULL)
-               return -ENOMEM;
-       rpipe_init(rpipe);
-
-       /* Look for an idle pipe */
-       for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) {
-               rpipe_idx = rpipe_get_idx(wa, rpipe_idx);
-               if (rpipe_idx >= wa->rpipes)    /* no more pipes :( */
-                       break;
-               result =  __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx);
-               if (result < 0)
-                       dev_err(dev, "Can't get descriptor for rpipe %u: %d\n",
-                               rpipe_idx, result);
-               else if ((rpipe->descr.bmCharacteristics & crs) != 0)
-                       goto found;
-               rpipe_put_idx(wa, rpipe_idx);
-       }
-       *prpipe = NULL;
-       kfree(rpipe);
-       return -ENXIO;
-
-found:
-       set_bit(rpipe_idx, wa->rpipe_bm);
-       rpipe->wa = wa_get(wa);
-       *prpipe = rpipe;
-       return 0;
-}
-
-static int __rpipe_reset(struct wahc *wa, unsigned index)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-
-       result = usb_control_msg(
-               wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-               USB_REQ_RPIPE_RESET,
-               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-               0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(dev, "rpipe %u: reset failed: %d\n",
-                       index, result);
-       return result;
-}
-
-/*
- * Fake companion descriptor for ep0
- *
- * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl
- */
-static struct usb_wireless_ep_comp_descriptor epc0 = {
-       .bLength = sizeof(epc0),
-       .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP,
-       .bMaxBurst = 1,
-       .bMaxSequence = 2,
-};
-
-/*
- * Look for EP companion descriptor
- *
- * Get there, look for Inara in the endpoint's extra descriptors
- */
-static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find(
-               struct device *dev, struct usb_host_endpoint *ep)
-{
-       void *itr;
-       size_t itr_size;
-       struct usb_descriptor_header *hdr;
-       struct usb_wireless_ep_comp_descriptor *epcd;
-
-       if (ep->desc.bEndpointAddress == 0) {
-               epcd = &epc0;
-               goto out;
-       }
-       itr = ep->extra;
-       itr_size = ep->extralen;
-       epcd = NULL;
-       while (itr_size > 0) {
-               if (itr_size < sizeof(*hdr)) {
-                       dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors "
-                               "at offset %zu: only %zu bytes left\n",
-                               ep->desc.bEndpointAddress,
-                               itr - (void *) ep->extra, itr_size);
-                       break;
-               }
-               hdr = itr;
-               if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) {
-                       epcd = itr;
-                       break;
-               }
-               if (hdr->bLength > itr_size) {
-                       dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor "
-                               "at offset %zu (type 0x%02x) "
-                               "length %d but only %zu bytes left\n",
-                               ep->desc.bEndpointAddress,
-                               itr - (void *) ep->extra, hdr->bDescriptorType,
-                               hdr->bLength, itr_size);
-                       break;
-               }
-               itr += hdr->bLength;
-               itr_size -= hdr->bLength;
-       }
-out:
-       return epcd;
-}
-
-/*
- * Aim an rpipe to its device & endpoint destination
- *
- * Make sure we change the address to unauthenticated if the device
- * is WUSB and it is not authenticated.
- */
-static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,
-                    struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp)
-{
-       int result = -ENOMSG;   /* better code for lack of companion? */
-       struct device *dev = &wa->usb_iface->dev;
-       struct usb_device *usb_dev = urb->dev;
-       struct usb_wireless_ep_comp_descriptor *epcd;
-       u32 ack_window, epcd_max_sequence;
-       u8 unauth;
-
-       epcd = rpipe_epc_find(dev, ep);
-       if (epcd == NULL) {
-               dev_err(dev, "ep 0x%02x: can't find companion descriptor\n",
-                       ep->desc.bEndpointAddress);
-               goto error;
-       }
-       unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0;
-       __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex));
-       atomic_set(&rpipe->segs_available,
-               le16_to_cpu(rpipe->descr.wRequests));
-       /* FIXME: block allocation system; request with queuing and timeout */
-       /* FIXME: compute so seg_size > ep->maxpktsize */
-       rpipe->descr.wBlocks = cpu_to_le16(16);         /* given */
-       /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */
-       if (usb_endpoint_xfer_isoc(&ep->desc))
-               rpipe->descr.wMaxPacketSize = epcd->wOverTheAirPacketSize;
-       else
-               rpipe->descr.wMaxPacketSize = ep->desc.wMaxPacketSize;
-
-       rpipe->descr.hwa_bMaxBurst = max(min_t(unsigned int,
-                               epcd->bMaxBurst, 16U), 1U);
-       rpipe->descr.hwa_bDeviceInfoIndex =
-                       wusb_port_no_to_idx(urb->dev->portnum);
-       /* FIXME: use maximum speed as supported or recommended by device */
-       rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ?
-               UWB_PHY_RATE_53 : UWB_PHY_RATE_200;
-
-       dev_dbg(dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n",
-               urb->dev->devnum, urb->dev->devnum | unauth,
-               le16_to_cpu(rpipe->descr.wRPipeIndex),
-               usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed);
-
-       rpipe->descr.hwa_reserved = 0;
-
-       rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress;
-       /* FIXME: bDataSequence */
-       rpipe->descr.bDataSequence = 0;
-
-       /* start with base window of hwa_bMaxBurst bits starting at 0. */
-       ack_window = 0xFFFFFFFF >> (32 - rpipe->descr.hwa_bMaxBurst);
-       rpipe->descr.dwCurrentWindow = cpu_to_le32(ack_window);
-       epcd_max_sequence = max(min_t(unsigned int,
-                       epcd->bMaxSequence, 32U), 2U);
-       rpipe->descr.bMaxDataSequence = epcd_max_sequence - 1;
-       rpipe->descr.bInterval = ep->desc.bInterval;
-       if (usb_endpoint_xfer_isoc(&ep->desc))
-               rpipe->descr.bOverTheAirInterval = epcd->bOverTheAirInterval;
-       else
-               rpipe->descr.bOverTheAirInterval = 0;   /* 0 if not isoc */
-       /* FIXME: xmit power & preamble blah blah */
-       rpipe->descr.bmAttribute = (ep->desc.bmAttributes &
-                                       USB_ENDPOINT_XFERTYPE_MASK);
-       /* rpipe->descr.bmCharacteristics RO */
-       rpipe->descr.bmRetryOptions = (wa->wusb->retry_count & 0xF);
-       /* FIXME: use for assessing link quality? */
-       rpipe->descr.wNumTransactionErrors = 0;
-       result = __rpipe_set_descr(wa, &rpipe->descr,
-                                  le16_to_cpu(rpipe->descr.wRPipeIndex));
-       if (result < 0) {
-               dev_err(dev, "Cannot aim rpipe: %d\n", result);
-               goto error;
-       }
-       result = 0;
-error:
-       return result;
-}
-
-/*
- * Check an aimed rpipe to make sure it points to where we want
- *
- * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth
- * space; when it is like that, we or 0x80 to make an unauth address.
- */
-static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa,
-                          const struct usb_host_endpoint *ep,
-                          const struct urb *urb, gfp_t gfp)
-{
-       int result = 0;
-       struct device *dev = &wa->usb_iface->dev;
-       u8 portnum = wusb_port_no_to_idx(urb->dev->portnum);
-
-#define AIM_CHECK(rdf, val, text)                                      \
-       do {                                                            \
-               if (rpipe->descr.rdf != (val)) {                        \
-                       dev_err(dev,                                    \
-                               "rpipe aim discrepancy: " #rdf " " text "\n", \
-                               rpipe->descr.rdf, (val));               \
-                       result = -EINVAL;                               \
-                       WARN_ON(1);                                     \
-               }                                                       \
-       } while (0)
-       AIM_CHECK(hwa_bDeviceInfoIndex, portnum, "(%u vs %u)");
-       AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ?
-                       UWB_PHY_RATE_53 : UWB_PHY_RATE_200,
-                 "(%u vs %u)");
-       AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)");
-       AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)");
-       AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)");
-#undef AIM_CHECK
-       return result;
-}
-
-#ifndef CONFIG_BUG
-#define CONFIG_BUG 0
-#endif
-
-/*
- * Make sure there is an rpipe allocated for an endpoint
- *
- * If already allocated, we just refcount it; if not, we get an
- * idle one, aim it to the right location and take it.
- *
- * Attaches to ep->hcpriv and rpipe->ep to ep.
- */
-int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep,
-                   struct urb *urb, gfp_t gfp)
-{
-       int result = 0;
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_rpipe *rpipe;
-       u8 eptype;
-
-       mutex_lock(&wa->rpipe_mutex);
-       rpipe = ep->hcpriv;
-       if (rpipe != NULL) {
-               if (CONFIG_BUG == 1) {
-                       result = rpipe_check_aim(rpipe, wa, ep, urb, gfp);
-                       if (result < 0)
-                               goto error;
-               }
-               __rpipe_get(rpipe);
-               dev_dbg(dev, "ep 0x%02x: reusing rpipe %u\n",
-                       ep->desc.bEndpointAddress,
-                       le16_to_cpu(rpipe->descr.wRPipeIndex));
-       } else {
-               /* hmm, assign idle rpipe, aim it */
-               result = -ENOBUFS;
-               eptype = ep->desc.bmAttributes & 0x03;
-               result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp);
-               if (result < 0)
-                       goto error;
-               result = rpipe_aim(rpipe, wa, ep, urb, gfp);
-               if (result < 0) {
-                       rpipe_put(rpipe);
-                       goto error;
-               }
-               ep->hcpriv = rpipe;
-               rpipe->ep = ep;
-               __rpipe_get(rpipe);     /* for caching into ep->hcpriv */
-               dev_dbg(dev, "ep 0x%02x: using rpipe %u\n",
-                       ep->desc.bEndpointAddress,
-                       le16_to_cpu(rpipe->descr.wRPipeIndex));
-       }
-error:
-       mutex_unlock(&wa->rpipe_mutex);
-       return result;
-}
-
-/*
- * Allocate the bitmap for each rpipe.
- */
-int wa_rpipes_create(struct wahc *wa)
-{
-       wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes);
-       wa->rpipe_bm = bitmap_zalloc(wa->rpipes, GFP_KERNEL);
-       if (wa->rpipe_bm == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-void wa_rpipes_destroy(struct wahc *wa)
-{
-       struct device *dev = &wa->usb_iface->dev;
-
-       if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) {
-               WARN_ON(1);
-               dev_err(dev, "BUG: pipes not released on exit: %*pb\n",
-                       wa->rpipes, wa->rpipe_bm);
-       }
-       bitmap_free(wa->rpipe_bm);
-}
-
-/*
- * Release resources allocated for an endpoint
- *
- * If there is an associated rpipe to this endpoint, Abort any pending
- * transfers and put it. If the rpipe ends up being destroyed,
- * __rpipe_destroy() will cleanup ep->hcpriv.
- *
- * This is called before calling hcd->stop(), so you don't need to do
- * anything else in there.
- */
-void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep)
-{
-       struct wa_rpipe *rpipe;
-
-       mutex_lock(&wa->rpipe_mutex);
-       rpipe = ep->hcpriv;
-       if (rpipe != NULL) {
-               u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
-
-               usb_control_msg(
-                       wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       USB_REQ_RPIPE_ABORT,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-                       0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
-               rpipe_put(rpipe);
-       }
-       mutex_unlock(&wa->rpipe_mutex);
-}
-EXPORT_SYMBOL_GPL(rpipe_ep_disable);
-
-/* Clear the stalled status of an RPIPE. */
-void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep)
-{
-       struct wa_rpipe *rpipe;
-
-       mutex_lock(&wa->rpipe_mutex);
-       rpipe = ep->hcpriv;
-       if (rpipe != NULL) {
-               u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
-
-               usb_control_msg(
-                       wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       USB_REQ_CLEAR_FEATURE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-                       RPIPE_STALL, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       }
-       mutex_unlock(&wa->rpipe_mutex);
-}
-EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled);
diff --git a/drivers/staging/wusbcore/wa-xfer.c b/drivers/staging/wusbcore/wa-xfer.c
deleted file mode 100644 (file)
index abf88ce..0000000
+++ /dev/null
@@ -1,2927 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter
- * Data transfer and URB enqueing
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * How transfers work: get a buffer, break it up in segments (segment
- * size is a multiple of the maxpacket size). For each segment issue a
- * segment request (struct wa_xfer_*), then send the data buffer if
- * out or nothing if in (all over the DTO endpoint).
- *
- * For each submitted segment request, a notification will come over
- * the NEP endpoint and a transfer result (struct xfer_result) will
- * arrive in the DTI URB. Read it, get the xfer ID, see if there is
- * data coming (inbound transfer), schedule a read and handle it.
- *
- * Sounds simple, it is a pain to implement.
- *
- *
- * ENTRY POINTS
- *
- *   FIXME
- *
- * LIFE CYCLE / STATE DIAGRAM
- *
- *   FIXME
- *
- * THIS CODE IS DISGUSTING
- *
- *   Warned you are; it's my second try and still not happy with it.
- *
- * NOTES:
- *
- *   - No iso
- *
- *   - Supports DMA xfers, control, bulk and maybe interrupt
- *
- *   - Does not recycle unused rpipes
- *
- *     An rpipe is assigned to an endpoint the first time it is used,
- *     and then it's there, assigned, until the endpoint is disabled
- *     (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the
- *     rpipe to the endpoint is done under the wa->rpipe_sem semaphore
- *     (should be a mutex).
- *
- *     Two methods it could be done:
- *
- *     (a) set up a timer every time an rpipe's use count drops to 1
- *         (which means unused) or when a transfer ends. Reset the
- *         timer when a xfer is queued. If the timer expires, release
- *         the rpipe [see rpipe_ep_disable()].
- *
- *     (b) when looking for free rpipes to attach [rpipe_get_by_ep()],
- *         when none are found go over the list, check their endpoint
- *         and their activity record (if no last-xfer-done-ts in the
- *         last x seconds) take it
- *
- *     However, due to the fact that we have a set of limited
- *     resources (max-segments-at-the-same-time per xfer,
- *     xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end
- *     we are going to have to rebuild all this based on an scheduler,
- *     to where we have a list of transactions to do and based on the
- *     availability of the different required components (blocks,
- *     rpipes, segment slots, etc), we go scheduling them. Painful.
- */
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/hash.h>
-#include <linux/ratelimit.h>
-#include <linux/export.h>
-#include <linux/scatterlist.h>
-
-#include "wa-hc.h"
-#include "wusbhc.h"
-
-enum {
-       /* [WUSB] section 8.3.3 allocates 7 bits for the segment index. */
-       WA_SEGS_MAX = 128,
-};
-
-enum wa_seg_status {
-       WA_SEG_NOTREADY,
-       WA_SEG_READY,
-       WA_SEG_DELAYED,
-       WA_SEG_SUBMITTED,
-       WA_SEG_PENDING,
-       WA_SEG_DTI_PENDING,
-       WA_SEG_DONE,
-       WA_SEG_ERROR,
-       WA_SEG_ABORTED,
-};
-
-static void wa_xfer_delayed_run(struct wa_rpipe *);
-static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting);
-
-/*
- * Life cycle governed by 'struct urb' (the refcount of the struct is
- * that of the 'struct urb' and usb_free_urb() would free the whole
- * struct).
- */
-struct wa_seg {
-       struct urb tr_urb;              /* transfer request urb. */
-       struct urb *isoc_pack_desc_urb; /* for isoc packet descriptor. */
-       struct urb *dto_urb;            /* for data output. */
-       struct list_head list_node;     /* for rpipe->req_list */
-       struct wa_xfer *xfer;           /* out xfer */
-       u8 index;                       /* which segment we are */
-       int isoc_frame_count;   /* number of isoc frames in this segment. */
-       int isoc_frame_offset;  /* starting frame offset in the xfer URB. */
-       /* Isoc frame that the current transfer buffer corresponds to. */
-       int isoc_frame_index;
-       int isoc_size;  /* size of all isoc frames sent by this seg. */
-       enum wa_seg_status status;
-       ssize_t result;                 /* bytes xfered or error */
-       struct wa_xfer_hdr xfer_hdr;
-};
-
-static inline void wa_seg_init(struct wa_seg *seg)
-{
-       usb_init_urb(&seg->tr_urb);
-
-       /* set the remaining memory to 0. */
-       memset(((void *)seg) + sizeof(seg->tr_urb), 0,
-               sizeof(*seg) - sizeof(seg->tr_urb));
-}
-
-/*
- * Protected by xfer->lock
- *
- */
-struct wa_xfer {
-       struct kref refcnt;
-       struct list_head list_node;
-       spinlock_t lock;
-       u32 id;
-
-       struct wahc *wa;                /* Wire adapter we are plugged to */
-       struct usb_host_endpoint *ep;
-       struct urb *urb;                /* URB we are transferring for */
-       struct wa_seg **seg;            /* transfer segments */
-       u8 segs, segs_submitted, segs_done;
-       unsigned is_inbound:1;
-       unsigned is_dma:1;
-       size_t seg_size;
-       int result;
-
-       gfp_t gfp;                      /* allocation mask */
-
-       struct wusb_dev *wusb_dev;      /* for activity timestamps */
-};
-
-static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
-       struct wa_seg *seg, int curr_iso_frame);
-static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
-               int starting_index, enum wa_seg_status status);
-
-static inline void wa_xfer_init(struct wa_xfer *xfer)
-{
-       kref_init(&xfer->refcnt);
-       INIT_LIST_HEAD(&xfer->list_node);
-       spin_lock_init(&xfer->lock);
-}
-
-/*
- * Destroy a transfer structure
- *
- * Note that freeing xfer->seg[cnt]->tr_urb will free the containing
- * xfer->seg[cnt] memory that was allocated by __wa_xfer_setup_segs.
- */
-static void wa_xfer_destroy(struct kref *_xfer)
-{
-       struct wa_xfer *xfer = container_of(_xfer, struct wa_xfer, refcnt);
-       if (xfer->seg) {
-               unsigned cnt;
-               for (cnt = 0; cnt < xfer->segs; cnt++) {
-                       struct wa_seg *seg = xfer->seg[cnt];
-                       if (seg) {
-                               usb_free_urb(seg->isoc_pack_desc_urb);
-                               if (seg->dto_urb) {
-                                       kfree(seg->dto_urb->sg);
-                                       usb_free_urb(seg->dto_urb);
-                               }
-                               usb_free_urb(&seg->tr_urb);
-                       }
-               }
-               kfree(xfer->seg);
-       }
-       kfree(xfer);
-}
-
-static void wa_xfer_get(struct wa_xfer *xfer)
-{
-       kref_get(&xfer->refcnt);
-}
-
-static void wa_xfer_put(struct wa_xfer *xfer)
-{
-       kref_put(&xfer->refcnt, wa_xfer_destroy);
-}
-
-/*
- * Try to get exclusive access to the DTO endpoint resource.  Return true
- * if successful.
- */
-static inline int __wa_dto_try_get(struct wahc *wa)
-{
-       return (test_and_set_bit(0, &wa->dto_in_use) == 0);
-}
-
-/* Release the DTO endpoint resource. */
-static inline void __wa_dto_put(struct wahc *wa)
-{
-       clear_bit_unlock(0, &wa->dto_in_use);
-}
-
-/* Service RPIPEs that are waiting on the DTO resource. */
-static void wa_check_for_delayed_rpipes(struct wahc *wa)
-{
-       unsigned long flags;
-       int dto_waiting = 0;
-       struct wa_rpipe *rpipe;
-
-       spin_lock_irqsave(&wa->rpipe_lock, flags);
-       while (!list_empty(&wa->rpipe_delayed_list) && !dto_waiting) {
-               rpipe = list_first_entry(&wa->rpipe_delayed_list,
-                               struct wa_rpipe, list_node);
-               __wa_xfer_delayed_run(rpipe, &dto_waiting);
-               /* remove this RPIPE from the list if it is not waiting. */
-               if (!dto_waiting) {
-                       pr_debug("%s: RPIPE %d serviced and removed from delayed list.\n",
-                               __func__,
-                               le16_to_cpu(rpipe->descr.wRPipeIndex));
-                       list_del_init(&rpipe->list_node);
-               }
-       }
-       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
-}
-
-/* add this RPIPE to the end of the delayed RPIPE list. */
-static void wa_add_delayed_rpipe(struct wahc *wa, struct wa_rpipe *rpipe)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&wa->rpipe_lock, flags);
-       /* add rpipe to the list if it is not already on it. */
-       if (list_empty(&rpipe->list_node)) {
-               pr_debug("%s: adding RPIPE %d to the delayed list.\n",
-                       __func__, le16_to_cpu(rpipe->descr.wRPipeIndex));
-               list_add_tail(&rpipe->list_node, &wa->rpipe_delayed_list);
-       }
-       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
-}
-
-/*
- * xfer is referenced
- *
- * xfer->lock has to be unlocked
- *
- * We take xfer->lock for setting the result; this is a barrier
- * against drivers/usb/core/hcd.c:unlink1() being called after we call
- * usb_hcd_giveback_urb() and wa_urb_dequeue() trying to get a
- * reference to the transfer.
- */
-static void wa_xfer_giveback(struct wa_xfer *xfer)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags);
-       list_del_init(&xfer->list_node);
-       usb_hcd_unlink_urb_from_ep(&(xfer->wa->wusb->usb_hcd), xfer->urb);
-       spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags);
-       /* FIXME: segmentation broken -- kills DWA */
-       wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result);
-       wa_put(xfer->wa);
-       wa_xfer_put(xfer);
-}
-
-/*
- * xfer is referenced
- *
- * xfer->lock has to be unlocked
- */
-static void wa_xfer_completion(struct wa_xfer *xfer)
-{
-       if (xfer->wusb_dev)
-               wusb_dev_put(xfer->wusb_dev);
-       rpipe_put(xfer->ep->hcpriv);
-       wa_xfer_giveback(xfer);
-}
-
-/*
- * Initialize a transfer's ID
- *
- * We need to use a sequential number; if we use the pointer or the
- * hash of the pointer, it can repeat over sequential transfers and
- * then it will confuse the HWA....wonder why in hell they put a 32
- * bit handle in there then.
- */
-static void wa_xfer_id_init(struct wa_xfer *xfer)
-{
-       xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count);
-}
-
-/* Return the xfer's ID. */
-static inline u32 wa_xfer_id(struct wa_xfer *xfer)
-{
-       return xfer->id;
-}
-
-/* Return the xfer's ID in transport format (little endian). */
-static inline __le32 wa_xfer_id_le32(struct wa_xfer *xfer)
-{
-       return cpu_to_le32(xfer->id);
-}
-
-/*
- * If transfer is done, wrap it up and return true
- *
- * xfer->lock has to be locked
- */
-static unsigned __wa_xfer_is_done(struct wa_xfer *xfer)
-{
-       struct device *dev = &xfer->wa->usb_iface->dev;
-       unsigned result, cnt;
-       struct wa_seg *seg;
-       struct urb *urb = xfer->urb;
-       unsigned found_short = 0;
-
-       result = xfer->segs_done == xfer->segs_submitted;
-       if (result == 0)
-               goto out;
-       urb->actual_length = 0;
-       for (cnt = 0; cnt < xfer->segs; cnt++) {
-               seg = xfer->seg[cnt];
-               switch (seg->status) {
-               case WA_SEG_DONE:
-                       if (found_short && seg->result > 0) {
-                               dev_dbg(dev, "xfer %p ID %08X#%u: bad short segments (%zu)\n",
-                                       xfer, wa_xfer_id(xfer), cnt,
-                                       seg->result);
-                               urb->status = -EINVAL;
-                               goto out;
-                       }
-                       urb->actual_length += seg->result;
-                       if (!(usb_pipeisoc(xfer->urb->pipe))
-                               && seg->result < xfer->seg_size
-                           && cnt != xfer->segs-1)
-                               found_short = 1;
-                       dev_dbg(dev, "xfer %p ID %08X#%u: DONE short %d "
-                               "result %zu urb->actual_length %d\n",
-                               xfer, wa_xfer_id(xfer), seg->index, found_short,
-                               seg->result, urb->actual_length);
-                       break;
-               case WA_SEG_ERROR:
-                       xfer->result = seg->result;
-                       dev_dbg(dev, "xfer %p ID %08X#%u: ERROR result %zi(0x%08zX)\n",
-                               xfer, wa_xfer_id(xfer), seg->index, seg->result,
-                               seg->result);
-                       goto out;
-               case WA_SEG_ABORTED:
-                       xfer->result = seg->result;
-                       dev_dbg(dev, "xfer %p ID %08X#%u: ABORTED result %zi(0x%08zX)\n",
-                               xfer, wa_xfer_id(xfer), seg->index, seg->result,
-                               seg->result);
-                       goto out;
-               default:
-                       dev_warn(dev, "xfer %p ID %08X#%u: is_done bad state %d\n",
-                                xfer, wa_xfer_id(xfer), cnt, seg->status);
-                       xfer->result = -EINVAL;
-                       goto out;
-               }
-       }
-       xfer->result = 0;
-out:
-       return result;
-}
-
-/*
- * Mark the given segment as done.  Return true if this completes the xfer.
- * This should only be called for segs that have been submitted to an RPIPE.
- * Delayed segs are not marked as submitted so they do not need to be marked
- * as done when cleaning up.
- *
- * xfer->lock has to be locked
- */
-static unsigned __wa_xfer_mark_seg_as_done(struct wa_xfer *xfer,
-       struct wa_seg *seg, enum wa_seg_status status)
-{
-       seg->status = status;
-       xfer->segs_done++;
-
-       /* check for done. */
-       return __wa_xfer_is_done(xfer);
-}
-
-/*
- * Search for a transfer list ID on the HCD's URB list
- *
- * For 32 bit architectures, we use the pointer itself; for 64 bits, a
- * 32-bit hash of the pointer.
- *
- * @returns NULL if not found.
- */
-static struct wa_xfer *wa_xfer_get_by_id(struct wahc *wa, u32 id)
-{
-       unsigned long flags;
-       struct wa_xfer *xfer_itr;
-       spin_lock_irqsave(&wa->xfer_list_lock, flags);
-       list_for_each_entry(xfer_itr, &wa->xfer_list, list_node) {
-               if (id == xfer_itr->id) {
-                       wa_xfer_get(xfer_itr);
-                       goto out;
-               }
-       }
-       xfer_itr = NULL;
-out:
-       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
-       return xfer_itr;
-}
-
-struct wa_xfer_abort_buffer {
-       struct urb urb;
-       struct wahc *wa;
-       struct wa_xfer_abort cmd;
-};
-
-static void __wa_xfer_abort_cb(struct urb *urb)
-{
-       struct wa_xfer_abort_buffer *b = urb->context;
-       struct wahc *wa = b->wa;
-
-       /*
-        * If the abort request URB failed, then the HWA did not get the abort
-        * command.  Forcibly clean up the xfer without waiting for a Transfer
-        * Result from the HWA.
-        */
-       if (urb->status < 0) {
-               struct wa_xfer *xfer;
-               struct device *dev = &wa->usb_iface->dev;
-
-               xfer = wa_xfer_get_by_id(wa, le32_to_cpu(b->cmd.dwTransferID));
-               dev_err(dev, "%s: Transfer Abort request failed. result: %d\n",
-                       __func__, urb->status);
-               if (xfer) {
-                       unsigned long flags;
-                       int done, seg_index = 0;
-                       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-
-                       dev_err(dev, "%s: cleaning up xfer %p ID 0x%08X.\n",
-                               __func__, xfer, wa_xfer_id(xfer));
-                       spin_lock_irqsave(&xfer->lock, flags);
-                       /* skip done segs. */
-                       while (seg_index < xfer->segs) {
-                               struct wa_seg *seg = xfer->seg[seg_index];
-
-                               if ((seg->status == WA_SEG_DONE) ||
-                                       (seg->status == WA_SEG_ERROR)) {
-                                       ++seg_index;
-                               } else {
-                                       break;
-                               }
-                       }
-                       /* mark remaining segs as aborted. */
-                       wa_complete_remaining_xfer_segs(xfer, seg_index,
-                               WA_SEG_ABORTED);
-                       done = __wa_xfer_is_done(xfer);
-                       spin_unlock_irqrestore(&xfer->lock, flags);
-                       if (done)
-                               wa_xfer_completion(xfer);
-                       wa_xfer_delayed_run(rpipe);
-                       wa_xfer_put(xfer);
-               } else {
-                       dev_err(dev, "%s: xfer ID 0x%08X already gone.\n",
-                                __func__, le32_to_cpu(b->cmd.dwTransferID));
-               }
-       }
-
-       wa_put(wa);     /* taken in __wa_xfer_abort */
-       usb_put_urb(&b->urb);
-}
-
-/*
- * Aborts an ongoing transaction
- *
- * Assumes the transfer is referenced and locked and in a submitted
- * state (mainly that there is an endpoint/rpipe assigned).
- *
- * The callback (see above) does nothing but freeing up the data by
- * putting the URB. Because the URB is allocated at the head of the
- * struct, the whole space we allocated is kfreed. *
- */
-static int __wa_xfer_abort(struct wa_xfer *xfer)
-{
-       int result = -ENOMEM;
-       struct device *dev = &xfer->wa->usb_iface->dev;
-       struct wa_xfer_abort_buffer *b;
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-
-       b = kmalloc(sizeof(*b), GFP_ATOMIC);
-       if (b == NULL)
-               goto error_kmalloc;
-       b->cmd.bLength =  sizeof(b->cmd);
-       b->cmd.bRequestType = WA_XFER_ABORT;
-       b->cmd.wRPipe = rpipe->descr.wRPipeIndex;
-       b->cmd.dwTransferID = wa_xfer_id_le32(xfer);
-       b->wa = wa_get(xfer->wa);
-
-       usb_init_urb(&b->urb);
-       usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev,
-               usb_sndbulkpipe(xfer->wa->usb_dev,
-                               xfer->wa->dto_epd->bEndpointAddress),
-               &b->cmd, sizeof(b->cmd), __wa_xfer_abort_cb, b);
-       result = usb_submit_urb(&b->urb, GFP_ATOMIC);
-       if (result < 0)
-               goto error_submit;
-       return result;                          /* callback frees! */
-
-
-error_submit:
-       wa_put(xfer->wa);
-       if (printk_ratelimit())
-               dev_err(dev, "xfer %p: Can't submit abort request: %d\n",
-                       xfer, result);
-       kfree(b);
-error_kmalloc:
-       return result;
-
-}
-
-/*
- * Calculate the number of isoc frames starting from isoc_frame_offset
- * that will fit a in transfer segment.
- */
-static int __wa_seg_calculate_isoc_frame_count(struct wa_xfer *xfer,
-       int isoc_frame_offset, int *total_size)
-{
-       int segment_size = 0, frame_count = 0;
-       int index = isoc_frame_offset;
-       struct usb_iso_packet_descriptor *iso_frame_desc =
-               xfer->urb->iso_frame_desc;
-
-       while ((index < xfer->urb->number_of_packets)
-               && ((segment_size + iso_frame_desc[index].length)
-                               <= xfer->seg_size)) {
-               /*
-                * For Alereon HWA devices, only include an isoc frame in an
-                * out segment if it is physically contiguous with the previous
-                * frame.  This is required because those devices expect
-                * the isoc frames to be sent as a single USB transaction as
-                * opposed to one transaction per frame with standard HWA.
-                */
-               if ((xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
-                       && (xfer->is_inbound == 0)
-                       && (index > isoc_frame_offset)
-                       && ((iso_frame_desc[index - 1].offset +
-                               iso_frame_desc[index - 1].length) !=
-                               iso_frame_desc[index].offset))
-                       break;
-
-               /* this frame fits. count it. */
-               ++frame_count;
-               segment_size += iso_frame_desc[index].length;
-
-               /* move to the next isoc frame. */
-               ++index;
-       }
-
-       *total_size = segment_size;
-       return frame_count;
-}
-
-/*
- *
- * @returns < 0 on error, transfer segment request size if ok
- */
-static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,
-                                    enum wa_xfer_type *pxfer_type)
-{
-       ssize_t result;
-       struct device *dev = &xfer->wa->usb_iface->dev;
-       size_t maxpktsize;
-       struct urb *urb = xfer->urb;
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-
-       switch (rpipe->descr.bmAttribute & 0x3) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               *pxfer_type = WA_XFER_TYPE_CTL;
-               result = sizeof(struct wa_xfer_ctl);
-               break;
-       case USB_ENDPOINT_XFER_INT:
-       case USB_ENDPOINT_XFER_BULK:
-               *pxfer_type = WA_XFER_TYPE_BI;
-               result = sizeof(struct wa_xfer_bi);
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               *pxfer_type = WA_XFER_TYPE_ISO;
-               result = sizeof(struct wa_xfer_hwaiso);
-               break;
-       default:
-               /* never happens */
-               BUG();
-               result = -EINVAL;       /* shut gcc up */
-       }
-       xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0;
-       xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0;
-
-       maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize);
-       xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks)
-               * 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1);
-       /* Compute the segment size and make sure it is a multiple of
-        * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of
-        * a check (FIXME) */
-       if (xfer->seg_size < maxpktsize) {
-               dev_err(dev,
-                       "HW BUG? seg_size %zu smaller than maxpktsize %zu\n",
-                       xfer->seg_size, maxpktsize);
-               result = -EINVAL;
-               goto error;
-       }
-       xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize;
-       if ((rpipe->descr.bmAttribute & 0x3) == USB_ENDPOINT_XFER_ISOC) {
-               int index = 0;
-
-               xfer->segs = 0;
-               /*
-                * loop over urb->number_of_packets to determine how many
-                * xfer segments will be needed to send the isoc frames.
-                */
-               while (index < urb->number_of_packets) {
-                       int seg_size; /* don't care. */
-                       index += __wa_seg_calculate_isoc_frame_count(xfer,
-                                       index, &seg_size);
-                       ++xfer->segs;
-               }
-       } else {
-               xfer->segs = DIV_ROUND_UP(urb->transfer_buffer_length,
-                                               xfer->seg_size);
-               if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL)
-                       xfer->segs = 1;
-       }
-
-       if (xfer->segs > WA_SEGS_MAX) {
-               dev_err(dev, "BUG? oops, number of segments %zu bigger than %d\n",
-                       (urb->transfer_buffer_length/xfer->seg_size),
-                       WA_SEGS_MAX);
-               result = -EINVAL;
-               goto error;
-       }
-error:
-       return result;
-}
-
-static void __wa_setup_isoc_packet_descr(
-               struct wa_xfer_packet_info_hwaiso *packet_desc,
-               struct wa_xfer *xfer,
-               struct wa_seg *seg) {
-       struct usb_iso_packet_descriptor *iso_frame_desc =
-               xfer->urb->iso_frame_desc;
-       int frame_index;
-
-       /* populate isoc packet descriptor. */
-       packet_desc->bPacketType = WA_XFER_ISO_PACKET_INFO;
-       packet_desc->wLength = cpu_to_le16(struct_size(packet_desc,
-                                          PacketLength,
-                                          seg->isoc_frame_count));
-       for (frame_index = 0; frame_index < seg->isoc_frame_count;
-               ++frame_index) {
-               int offset_index = frame_index + seg->isoc_frame_offset;
-               packet_desc->PacketLength[frame_index] =
-                       cpu_to_le16(iso_frame_desc[offset_index].length);
-       }
-}
-
-
-/* Fill in the common request header and xfer-type specific data. */
-static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,
-                                struct wa_xfer_hdr *xfer_hdr0,
-                                enum wa_xfer_type xfer_type,
-                                size_t xfer_hdr_size)
-{
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-       struct wa_seg *seg = xfer->seg[0];
-
-       xfer_hdr0 = &seg->xfer_hdr;
-       xfer_hdr0->bLength = xfer_hdr_size;
-       xfer_hdr0->bRequestType = xfer_type;
-       xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex;
-       xfer_hdr0->dwTransferID = wa_xfer_id_le32(xfer);
-       xfer_hdr0->bTransferSegment = 0;
-       switch (xfer_type) {
-       case WA_XFER_TYPE_CTL: {
-               struct wa_xfer_ctl *xfer_ctl =
-                       container_of(xfer_hdr0, struct wa_xfer_ctl, hdr);
-               xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0;
-               memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet,
-                      sizeof(xfer_ctl->baSetupData));
-               break;
-       }
-       case WA_XFER_TYPE_BI:
-               break;
-       case WA_XFER_TYPE_ISO: {
-               struct wa_xfer_hwaiso *xfer_iso =
-                       container_of(xfer_hdr0, struct wa_xfer_hwaiso, hdr);
-               struct wa_xfer_packet_info_hwaiso *packet_desc =
-                       ((void *)xfer_iso) + xfer_hdr_size;
-
-               /* populate the isoc section of the transfer request. */
-               xfer_iso->dwNumOfPackets = cpu_to_le32(seg->isoc_frame_count);
-               /* populate isoc packet descriptor. */
-               __wa_setup_isoc_packet_descr(packet_desc, xfer, seg);
-               break;
-       }
-       default:
-               BUG();
-       };
-}
-
-/*
- * Callback for the OUT data phase of the segment request
- *
- * Check wa_seg_tr_cb(); most comments also apply here because this
- * function does almost the same thing and they work closely
- * together.
- *
- * If the seg request has failed but this DTO phase has succeeded,
- * wa_seg_tr_cb() has already failed the segment and moved the
- * status to WA_SEG_ERROR, so this will go through 'case 0' and
- * effectively do nothing.
- */
-static void wa_seg_dto_cb(struct urb *urb)
-{
-       struct wa_seg *seg = urb->context;
-       struct wa_xfer *xfer = seg->xfer;
-       struct wahc *wa;
-       struct device *dev;
-       struct wa_rpipe *rpipe;
-       unsigned long flags;
-       unsigned rpipe_ready = 0;
-       int data_send_done = 1, release_dto = 0, holding_dto = 0;
-       u8 done = 0;
-       int result;
-
-       /* free the sg if it was used. */
-       kfree(urb->sg);
-       urb->sg = NULL;
-
-       spin_lock_irqsave(&xfer->lock, flags);
-       wa = xfer->wa;
-       dev = &wa->usb_iface->dev;
-       if (usb_pipeisoc(xfer->urb->pipe)) {
-               /* Alereon HWA sends all isoc frames in a single transfer. */
-               if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
-                       seg->isoc_frame_index += seg->isoc_frame_count;
-               else
-                       seg->isoc_frame_index += 1;
-               if (seg->isoc_frame_index < seg->isoc_frame_count) {
-                       data_send_done = 0;
-                       holding_dto = 1; /* checked in error cases. */
-                       /*
-                        * if this is the last isoc frame of the segment, we
-                        * can release DTO after sending this frame.
-                        */
-                       if ((seg->isoc_frame_index + 1) >=
-                               seg->isoc_frame_count)
-                               release_dto = 1;
-               }
-               dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n",
-                       wa_xfer_id(xfer), seg->index, seg->isoc_frame_index,
-                       holding_dto, release_dto);
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&xfer->lock, flags);
-               seg->result += urb->actual_length;
-               if (data_send_done) {
-                       dev_dbg(dev, "xfer 0x%08X#%u: data out done (%zu bytes)\n",
-                               wa_xfer_id(xfer), seg->index, seg->result);
-                       if (seg->status < WA_SEG_PENDING)
-                               seg->status = WA_SEG_PENDING;
-               } else {
-                       /* should only hit this for isoc xfers. */
-                       /*
-                        * Populate the dto URB with the next isoc frame buffer,
-                        * send the URB and release DTO if we no longer need it.
-                        */
-                        __wa_populate_dto_urb_isoc(xfer, seg,
-                               seg->isoc_frame_offset + seg->isoc_frame_index);
-
-                       /* resubmit the URB with the next isoc frame. */
-                       /* take a ref on resubmit. */
-                       wa_xfer_get(xfer);
-                       result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
-                       if (result < 0) {
-                               dev_err(dev, "xfer 0x%08X#%u: DTO submit failed: %d\n",
-                                      wa_xfer_id(xfer), seg->index, result);
-                               spin_unlock_irqrestore(&xfer->lock, flags);
-                               goto error_dto_submit;
-                       }
-               }
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (release_dto) {
-                       __wa_dto_put(wa);
-                       wa_check_for_delayed_rpipes(wa);
-               }
-               break;
-       case -ECONNRESET:       /* URB unlinked; no need to do anything */
-       case -ENOENT:           /* as it was done by the who unlinked us */
-               if (holding_dto) {
-                       __wa_dto_put(wa);
-                       wa_check_for_delayed_rpipes(wa);
-               }
-               break;
-       default:                /* Other errors ... */
-               dev_err(dev, "xfer 0x%08X#%u: data out error %d\n",
-                       wa_xfer_id(xfer), seg->index, urb->status);
-               goto error_default;
-       }
-
-       /* taken when this URB was submitted. */
-       wa_xfer_put(xfer);
-       return;
-
-error_dto_submit:
-       /* taken on resubmit attempt. */
-       wa_xfer_put(xfer);
-error_default:
-       spin_lock_irqsave(&xfer->lock, flags);
-       rpipe = xfer->ep->hcpriv;
-       if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                   EDC_ERROR_TIMEFRAME)){
-               dev_err(dev, "DTO: URB max acceptable errors exceeded, resetting device\n");
-               wa_reset_all(wa);
-       }
-       if (seg->status != WA_SEG_ERROR) {
-               seg->result = urb->status;
-               __wa_xfer_abort(xfer);
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (holding_dto) {
-               __wa_dto_put(wa);
-               wa_check_for_delayed_rpipes(wa);
-       }
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
-       /* taken when this URB was submitted. */
-       wa_xfer_put(xfer);
-}
-
-/*
- * Callback for the isoc packet descriptor phase of the segment request
- *
- * Check wa_seg_tr_cb(); most comments also apply here because this
- * function does almost the same thing and they work closely
- * together.
- *
- * If the seg request has failed but this phase has succeeded,
- * wa_seg_tr_cb() has already failed the segment and moved the
- * status to WA_SEG_ERROR, so this will go through 'case 0' and
- * effectively do nothing.
- */
-static void wa_seg_iso_pack_desc_cb(struct urb *urb)
-{
-       struct wa_seg *seg = urb->context;
-       struct wa_xfer *xfer = seg->xfer;
-       struct wahc *wa;
-       struct device *dev;
-       struct wa_rpipe *rpipe;
-       unsigned long flags;
-       unsigned rpipe_ready = 0;
-       u8 done = 0;
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&xfer->lock, flags);
-               wa = xfer->wa;
-               dev = &wa->usb_iface->dev;
-               dev_dbg(dev, "iso xfer %08X#%u: packet descriptor done\n",
-                       wa_xfer_id(xfer), seg->index);
-               if (xfer->is_inbound && seg->status < WA_SEG_PENDING)
-                       seg->status = WA_SEG_PENDING;
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               break;
-       case -ECONNRESET:       /* URB unlinked; no need to do anything */
-       case -ENOENT:           /* as it was done by the who unlinked us */
-               break;
-       default:                /* Other errors ... */
-               spin_lock_irqsave(&xfer->lock, flags);
-               wa = xfer->wa;
-               dev = &wa->usb_iface->dev;
-               rpipe = xfer->ep->hcpriv;
-               pr_err_ratelimited("iso xfer %08X#%u: packet descriptor error %d\n",
-                               wa_xfer_id(xfer), seg->index, urb->status);
-               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)){
-                       dev_err(dev, "iso xfer: URB max acceptable errors exceeded, resetting device\n");
-                       wa_reset_all(wa);
-               }
-               if (seg->status != WA_SEG_ERROR) {
-                       usb_unlink_urb(seg->dto_urb);
-                       seg->result = urb->status;
-                       __wa_xfer_abort(xfer);
-                       rpipe_ready = rpipe_avail_inc(rpipe);
-                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
-                                       WA_SEG_ERROR);
-               }
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-       }
-       /* taken when this URB was submitted. */
-       wa_xfer_put(xfer);
-}
-
-/*
- * Callback for the segment request
- *
- * If successful transition state (unless already transitioned or
- * outbound transfer); otherwise, take a note of the error, mark this
- * segment done and try completion.
- *
- * Note we don't access until we are sure that the transfer hasn't
- * been cancelled (ECONNRESET, ENOENT), which could mean that
- * seg->xfer could be already gone.
- *
- * We have to check before setting the status to WA_SEG_PENDING
- * because sometimes the xfer result callback arrives before this
- * callback (geeeeeeze), so it might happen that we are already in
- * another state. As well, we don't set it if the transfer is not inbound,
- * as in that case, wa_seg_dto_cb will do it when the OUT data phase
- * finishes.
- */
-static void wa_seg_tr_cb(struct urb *urb)
-{
-       struct wa_seg *seg = urb->context;
-       struct wa_xfer *xfer = seg->xfer;
-       struct wahc *wa;
-       struct device *dev;
-       struct wa_rpipe *rpipe;
-       unsigned long flags;
-       unsigned rpipe_ready;
-       u8 done = 0;
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&xfer->lock, flags);
-               wa = xfer->wa;
-               dev = &wa->usb_iface->dev;
-               dev_dbg(dev, "xfer %p ID 0x%08X#%u: request done\n",
-                       xfer, wa_xfer_id(xfer), seg->index);
-               if (xfer->is_inbound &&
-                       seg->status < WA_SEG_PENDING &&
-                       !(usb_pipeisoc(xfer->urb->pipe)))
-                       seg->status = WA_SEG_PENDING;
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               break;
-       case -ECONNRESET:       /* URB unlinked; no need to do anything */
-       case -ENOENT:           /* as it was done by the who unlinked us */
-               break;
-       default:                /* Other errors ... */
-               spin_lock_irqsave(&xfer->lock, flags);
-               wa = xfer->wa;
-               dev = &wa->usb_iface->dev;
-               rpipe = xfer->ep->hcpriv;
-               if (printk_ratelimit())
-                       dev_err(dev, "xfer %p ID 0x%08X#%u: request error %d\n",
-                               xfer, wa_xfer_id(xfer), seg->index,
-                               urb->status);
-               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)){
-                       dev_err(dev, "DTO: URB max acceptable errors "
-                               "exceeded, resetting device\n");
-                       wa_reset_all(wa);
-               }
-               usb_unlink_urb(seg->isoc_pack_desc_urb);
-               usb_unlink_urb(seg->dto_urb);
-               seg->result = urb->status;
-               __wa_xfer_abort(xfer);
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-       }
-       /* taken when this URB was submitted. */
-       wa_xfer_put(xfer);
-}
-
-/*
- * Allocate an SG list to store bytes_to_transfer bytes and copy the
- * subset of the in_sg that matches the buffer subset
- * we are about to transfer.
- */
-static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
-       const unsigned int bytes_transferred,
-       const unsigned int bytes_to_transfer, int *out_num_sgs)
-{
-       struct scatterlist *out_sg;
-       unsigned int bytes_processed = 0, offset_into_current_page_data = 0,
-               nents;
-       struct scatterlist *current_xfer_sg = in_sg;
-       struct scatterlist *current_seg_sg, *last_seg_sg;
-
-       /* skip previously transferred pages. */
-       while ((current_xfer_sg) &&
-                       (bytes_processed < bytes_transferred)) {
-               bytes_processed += current_xfer_sg->length;
-
-               /* advance the sg if current segment starts on or past the
-                       next page. */
-               if (bytes_processed <= bytes_transferred)
-                       current_xfer_sg = sg_next(current_xfer_sg);
-       }
-
-       /* the data for the current segment starts in current_xfer_sg.
-               calculate the offset. */
-       if (bytes_processed > bytes_transferred) {
-               offset_into_current_page_data = current_xfer_sg->length -
-                       (bytes_processed - bytes_transferred);
-       }
-
-       /* calculate the number of pages needed by this segment. */
-       nents = DIV_ROUND_UP((bytes_to_transfer +
-               offset_into_current_page_data +
-               current_xfer_sg->offset),
-               PAGE_SIZE);
-
-       out_sg = kmalloc((sizeof(struct scatterlist) * nents), GFP_ATOMIC);
-       if (out_sg) {
-               sg_init_table(out_sg, nents);
-
-               /* copy the portion of the incoming SG that correlates to the
-                * data to be transferred by this segment to the segment SG. */
-               last_seg_sg = current_seg_sg = out_sg;
-               bytes_processed = 0;
-
-               /* reset nents and calculate the actual number of sg entries
-                       needed. */
-               nents = 0;
-               while ((bytes_processed < bytes_to_transfer) &&
-                               current_seg_sg && current_xfer_sg) {
-                       unsigned int page_len = min((current_xfer_sg->length -
-                               offset_into_current_page_data),
-                               (bytes_to_transfer - bytes_processed));
-
-                       sg_set_page(current_seg_sg, sg_page(current_xfer_sg),
-                               page_len,
-                               current_xfer_sg->offset +
-                               offset_into_current_page_data);
-
-                       bytes_processed += page_len;
-
-                       last_seg_sg = current_seg_sg;
-                       current_seg_sg = sg_next(current_seg_sg);
-                       current_xfer_sg = sg_next(current_xfer_sg);
-
-                       /* only the first page may require additional offset. */
-                       offset_into_current_page_data = 0;
-                       nents++;
-               }
-
-               /* update num_sgs and terminate the list since we may have
-                *  concatenated pages. */
-               sg_mark_end(last_seg_sg);
-               *out_num_sgs = nents;
-       }
-
-       return out_sg;
-}
-
-/*
- * Populate DMA buffer info for the isoc dto urb.
- */
-static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
-       struct wa_seg *seg, int curr_iso_frame)
-{
-       seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-       seg->dto_urb->sg = NULL;
-       seg->dto_urb->num_sgs = 0;
-       /* dto urb buffer address pulled from iso_frame_desc. */
-       seg->dto_urb->transfer_dma = xfer->urb->transfer_dma +
-               xfer->urb->iso_frame_desc[curr_iso_frame].offset;
-       /* The Alereon HWA sends a single URB with all isoc segs. */
-       if (xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
-               seg->dto_urb->transfer_buffer_length = seg->isoc_size;
-       else
-               seg->dto_urb->transfer_buffer_length =
-                       xfer->urb->iso_frame_desc[curr_iso_frame].length;
-}
-
-/*
- * Populate buffer ptr and size, DMA buffer or SG list for the dto urb.
- */
-static int __wa_populate_dto_urb(struct wa_xfer *xfer,
-       struct wa_seg *seg, size_t buf_itr_offset, size_t buf_itr_size)
-{
-       int result = 0;
-
-       if (xfer->is_dma) {
-               seg->dto_urb->transfer_dma =
-                       xfer->urb->transfer_dma + buf_itr_offset;
-               seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-               seg->dto_urb->sg = NULL;
-               seg->dto_urb->num_sgs = 0;
-       } else {
-               /* do buffer or SG processing. */
-               seg->dto_urb->transfer_flags &=
-                       ~URB_NO_TRANSFER_DMA_MAP;
-               /* this should always be 0 before a resubmit. */
-               seg->dto_urb->num_mapped_sgs = 0;
-
-               if (xfer->urb->transfer_buffer) {
-                       seg->dto_urb->transfer_buffer =
-                               xfer->urb->transfer_buffer +
-                               buf_itr_offset;
-                       seg->dto_urb->sg = NULL;
-                       seg->dto_urb->num_sgs = 0;
-               } else {
-                       seg->dto_urb->transfer_buffer = NULL;
-
-                       /*
-                        * allocate an SG list to store seg_size bytes
-                        * and copy the subset of the xfer->urb->sg that
-                        * matches the buffer subset we are about to
-                        * read.
-                        */
-                       seg->dto_urb->sg = wa_xfer_create_subset_sg(
-                               xfer->urb->sg,
-                               buf_itr_offset, buf_itr_size,
-                               &(seg->dto_urb->num_sgs));
-                       if (!(seg->dto_urb->sg))
-                               result = -ENOMEM;
-               }
-       }
-       seg->dto_urb->transfer_buffer_length = buf_itr_size;
-
-       return result;
-}
-
-/*
- * Allocate the segs array and initialize each of them
- *
- * The segments are freed by wa_xfer_destroy() when the xfer use count
- * drops to zero; however, because each segment is given the same life
- * cycle as the USB URB it contains, it is actually freed by
- * usb_put_urb() on the contained USB URB (twisted, eh?).
- */
-static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
-{
-       int result, cnt, isoc_frame_offset = 0;
-       size_t alloc_size = sizeof(*xfer->seg[0])
-               - sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size;
-       struct usb_device *usb_dev = xfer->wa->usb_dev;
-       const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd;
-       struct wa_seg *seg;
-       size_t buf_itr, buf_size, buf_itr_size;
-
-       result = -ENOMEM;
-       xfer->seg = kcalloc(xfer->segs, sizeof(xfer->seg[0]), GFP_ATOMIC);
-       if (xfer->seg == NULL)
-               goto error_segs_kzalloc;
-       buf_itr = 0;
-       buf_size = xfer->urb->transfer_buffer_length;
-       for (cnt = 0; cnt < xfer->segs; cnt++) {
-               size_t iso_pkt_descr_size = 0;
-               int seg_isoc_frame_count = 0, seg_isoc_size = 0;
-
-               /*
-                * Adjust the size of the segment object to contain space for
-                * the isoc packet descriptor buffer.
-                */
-               if (usb_pipeisoc(xfer->urb->pipe)) {
-                       seg_isoc_frame_count =
-                               __wa_seg_calculate_isoc_frame_count(xfer,
-                                       isoc_frame_offset, &seg_isoc_size);
-
-                       iso_pkt_descr_size =
-                               sizeof(struct wa_xfer_packet_info_hwaiso) +
-                               (seg_isoc_frame_count * sizeof(__le16));
-               }
-               result = -ENOMEM;
-               seg = xfer->seg[cnt] = kmalloc(alloc_size + iso_pkt_descr_size,
-                                               GFP_ATOMIC);
-               if (seg == NULL)
-                       goto error_seg_kmalloc;
-               wa_seg_init(seg);
-               seg->xfer = xfer;
-               seg->index = cnt;
-               usb_fill_bulk_urb(&seg->tr_urb, usb_dev,
-                                 usb_sndbulkpipe(usb_dev,
-                                                 dto_epd->bEndpointAddress),
-                                 &seg->xfer_hdr, xfer_hdr_size,
-                                 wa_seg_tr_cb, seg);
-               buf_itr_size = min(buf_size, xfer->seg_size);
-
-               if (usb_pipeisoc(xfer->urb->pipe)) {
-                       seg->isoc_frame_count = seg_isoc_frame_count;
-                       seg->isoc_frame_offset = isoc_frame_offset;
-                       seg->isoc_size = seg_isoc_size;
-                       /* iso packet descriptor. */
-                       seg->isoc_pack_desc_urb =
-                                       usb_alloc_urb(0, GFP_ATOMIC);
-                       if (seg->isoc_pack_desc_urb == NULL)
-                               goto error_iso_pack_desc_alloc;
-                       /*
-                        * The buffer for the isoc packet descriptor starts
-                        * after the transfer request header in the
-                        * segment object memory buffer.
-                        */
-                       usb_fill_bulk_urb(
-                               seg->isoc_pack_desc_urb, usb_dev,
-                               usb_sndbulkpipe(usb_dev,
-                                       dto_epd->bEndpointAddress),
-                               (void *)(&seg->xfer_hdr) +
-                                       xfer_hdr_size,
-                               iso_pkt_descr_size,
-                               wa_seg_iso_pack_desc_cb, seg);
-
-                       /* adjust starting frame offset for next seg. */
-                       isoc_frame_offset += seg_isoc_frame_count;
-               }
-
-               if (xfer->is_inbound == 0 && buf_size > 0) {
-                       /* outbound data. */
-                       seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC);
-                       if (seg->dto_urb == NULL)
-                               goto error_dto_alloc;
-                       usb_fill_bulk_urb(
-                               seg->dto_urb, usb_dev,
-                               usb_sndbulkpipe(usb_dev,
-                                               dto_epd->bEndpointAddress),
-                               NULL, 0, wa_seg_dto_cb, seg);
-
-                       if (usb_pipeisoc(xfer->urb->pipe)) {
-                               /*
-                                * Fill in the xfer buffer information for the
-                                * first isoc frame.  Subsequent frames in this
-                                * segment will be filled in and sent from the
-                                * DTO completion routine, if needed.
-                                */
-                               __wa_populate_dto_urb_isoc(xfer, seg,
-                                       seg->isoc_frame_offset);
-                       } else {
-                               /* fill in the xfer buffer information. */
-                               result = __wa_populate_dto_urb(xfer, seg,
-                                                       buf_itr, buf_itr_size);
-                               if (result < 0)
-                                       goto error_seg_outbound_populate;
-
-                               buf_itr += buf_itr_size;
-                               buf_size -= buf_itr_size;
-                       }
-               }
-               seg->status = WA_SEG_READY;
-       }
-       return 0;
-
-       /*
-        * Free the memory for the current segment which failed to init.
-        * Use the fact that cnt is left at were it failed.  The remaining
-        * segments will be cleaned up by wa_xfer_destroy.
-        */
-error_seg_outbound_populate:
-       usb_free_urb(xfer->seg[cnt]->dto_urb);
-error_dto_alloc:
-       usb_free_urb(xfer->seg[cnt]->isoc_pack_desc_urb);
-error_iso_pack_desc_alloc:
-       kfree(xfer->seg[cnt]);
-       xfer->seg[cnt] = NULL;
-error_seg_kmalloc:
-error_segs_kzalloc:
-       return result;
-}
-
-/*
- * Allocates all the stuff needed to submit a transfer
- *
- * Breaks the whole data buffer in a list of segments, each one has a
- * structure allocated to it and linked in xfer->seg[index]
- *
- * FIXME: merge setup_segs() and the last part of this function, no
- *        need to do two for loops when we could run everything in a
- *        single one
- */
-static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb)
-{
-       int result;
-       struct device *dev = &xfer->wa->usb_iface->dev;
-       enum wa_xfer_type xfer_type = 0; /* shut up GCC */
-       size_t xfer_hdr_size, cnt, transfer_size;
-       struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr;
-
-       result = __wa_xfer_setup_sizes(xfer, &xfer_type);
-       if (result < 0)
-               goto error_setup_sizes;
-       xfer_hdr_size = result;
-       result = __wa_xfer_setup_segs(xfer, xfer_hdr_size);
-       if (result < 0) {
-               dev_err(dev, "xfer %p: Failed to allocate %d segments: %d\n",
-                       xfer, xfer->segs, result);
-               goto error_setup_segs;
-       }
-       /* Fill the first header */
-       xfer_hdr0 = &xfer->seg[0]->xfer_hdr;
-       wa_xfer_id_init(xfer);
-       __wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size);
-
-       /* Fill remaining headers */
-       xfer_hdr = xfer_hdr0;
-       if (xfer_type == WA_XFER_TYPE_ISO) {
-               xfer_hdr0->dwTransferLength =
-                       cpu_to_le32(xfer->seg[0]->isoc_size);
-               for (cnt = 1; cnt < xfer->segs; cnt++) {
-                       struct wa_xfer_packet_info_hwaiso *packet_desc;
-                       struct wa_seg *seg = xfer->seg[cnt];
-                       struct wa_xfer_hwaiso *xfer_iso;
-
-                       xfer_hdr = &seg->xfer_hdr;
-                       xfer_iso = container_of(xfer_hdr,
-                                               struct wa_xfer_hwaiso, hdr);
-                       packet_desc = ((void *)xfer_hdr) + xfer_hdr_size;
-                       /*
-                        * Copy values from the 0th header. Segment specific
-                        * values are set below.
-                        */
-                       memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
-                       xfer_hdr->bTransferSegment = cnt;
-                       xfer_hdr->dwTransferLength =
-                               cpu_to_le32(seg->isoc_size);
-                       xfer_iso->dwNumOfPackets =
-                                       cpu_to_le32(seg->isoc_frame_count);
-                       __wa_setup_isoc_packet_descr(packet_desc, xfer, seg);
-                       seg->status = WA_SEG_READY;
-               }
-       } else {
-               transfer_size = urb->transfer_buffer_length;
-               xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ?
-                       cpu_to_le32(xfer->seg_size) :
-                       cpu_to_le32(transfer_size);
-               transfer_size -=  xfer->seg_size;
-               for (cnt = 1; cnt < xfer->segs; cnt++) {
-                       xfer_hdr = &xfer->seg[cnt]->xfer_hdr;
-                       memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
-                       xfer_hdr->bTransferSegment = cnt;
-                       xfer_hdr->dwTransferLength =
-                               transfer_size > xfer->seg_size ?
-                                       cpu_to_le32(xfer->seg_size)
-                                       : cpu_to_le32(transfer_size);
-                       xfer->seg[cnt]->status = WA_SEG_READY;
-                       transfer_size -=  xfer->seg_size;
-               }
-       }
-       xfer_hdr->bTransferSegment |= 0x80;     /* this is the last segment */
-       result = 0;
-error_setup_segs:
-error_setup_sizes:
-       return result;
-}
-
-/*
- *
- *
- * rpipe->seg_lock is held!
- */
-static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
-                          struct wa_seg *seg, int *dto_done)
-{
-       int result;
-
-       /* default to done unless we encounter a multi-frame isoc segment. */
-       *dto_done = 1;
-
-       /*
-        * Take a ref for each segment urb so the xfer cannot disappear until
-        * all of the callbacks run.
-        */
-       wa_xfer_get(xfer);
-       /* submit the transfer request. */
-       seg->status = WA_SEG_SUBMITTED;
-       result = usb_submit_urb(&seg->tr_urb, GFP_ATOMIC);
-       if (result < 0) {
-               pr_err("%s: xfer %p#%u: REQ submit failed: %d\n",
-                      __func__, xfer, seg->index, result);
-               wa_xfer_put(xfer);
-               goto error_tr_submit;
-       }
-       /* submit the isoc packet descriptor if present. */
-       if (seg->isoc_pack_desc_urb) {
-               wa_xfer_get(xfer);
-               result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC);
-               seg->isoc_frame_index = 0;
-               if (result < 0) {
-                       pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n",
-                              __func__, xfer, seg->index, result);
-                       wa_xfer_put(xfer);
-                       goto error_iso_pack_desc_submit;
-               }
-       }
-       /* submit the out data if this is an out request. */
-       if (seg->dto_urb) {
-               struct wahc *wa = xfer->wa;
-               wa_xfer_get(xfer);
-               result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
-               if (result < 0) {
-                       pr_err("%s: xfer %p#%u: DTO submit failed: %d\n",
-                              __func__, xfer, seg->index, result);
-                       wa_xfer_put(xfer);
-                       goto error_dto_submit;
-               }
-               /*
-                * If this segment contains more than one isoc frame, hold
-                * onto the dto resource until we send all frames.
-                * Only applies to non-Alereon devices.
-                */
-               if (((wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) == 0)
-                       && (seg->isoc_frame_count > 1))
-                       *dto_done = 0;
-       }
-       rpipe_avail_dec(rpipe);
-       return 0;
-
-error_dto_submit:
-       usb_unlink_urb(seg->isoc_pack_desc_urb);
-error_iso_pack_desc_submit:
-       usb_unlink_urb(&seg->tr_urb);
-error_tr_submit:
-       seg->status = WA_SEG_ERROR;
-       seg->result = result;
-       *dto_done = 1;
-       return result;
-}
-
-/*
- * Execute more queued request segments until the maximum concurrent allowed.
- * Return true if the DTO resource was acquired and released.
- *
- * The ugly unlock/lock sequence on the error path is needed as the
- * xfer->lock normally nests the seg_lock and not viceversa.
- */
-static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting)
-{
-       int result, dto_acquired = 0, dto_done = 0;
-       struct device *dev = &rpipe->wa->usb_iface->dev;
-       struct wa_seg *seg;
-       struct wa_xfer *xfer;
-       unsigned long flags;
-
-       *dto_waiting = 0;
-
-       spin_lock_irqsave(&rpipe->seg_lock, flags);
-       while (atomic_read(&rpipe->segs_available) > 0
-             && !list_empty(&rpipe->seg_list)
-             && (dto_acquired = __wa_dto_try_get(rpipe->wa))) {
-               seg = list_first_entry(&(rpipe->seg_list), struct wa_seg,
-                                list_node);
-               list_del(&seg->list_node);
-               xfer = seg->xfer;
-               /*
-                * Get a reference to the xfer in case the callbacks for the
-                * URBs submitted by __wa_seg_submit attempt to complete
-                * the xfer before this function completes.
-                */
-               wa_xfer_get(xfer);
-               result = __wa_seg_submit(rpipe, xfer, seg, &dto_done);
-               /* release the dto resource if this RPIPE is done with it. */
-               if (dto_done)
-                       __wa_dto_put(rpipe->wa);
-               dev_dbg(dev, "xfer %p ID %08X#%u submitted from delayed [%d segments available] %d\n",
-                       xfer, wa_xfer_id(xfer), seg->index,
-                       atomic_read(&rpipe->segs_available), result);
-               if (unlikely(result < 0)) {
-                       int done;
-
-                       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
-                       spin_lock_irqsave(&xfer->lock, flags);
-                       __wa_xfer_abort(xfer);
-                       /*
-                        * This seg was marked as submitted when it was put on
-                        * the RPIPE seg_list.  Mark it done.
-                        */
-                       xfer->segs_done++;
-                       done = __wa_xfer_is_done(xfer);
-                       spin_unlock_irqrestore(&xfer->lock, flags);
-                       if (done)
-                               wa_xfer_completion(xfer);
-                       spin_lock_irqsave(&rpipe->seg_lock, flags);
-               }
-               wa_xfer_put(xfer);
-       }
-       /*
-        * Mark this RPIPE as waiting if dto was not acquired, there are
-        * delayed segs and no active transfers to wake us up later.
-        */
-       if (!dto_acquired && !list_empty(&rpipe->seg_list)
-               && (atomic_read(&rpipe->segs_available) ==
-                       le16_to_cpu(rpipe->descr.wRequests)))
-               *dto_waiting = 1;
-
-       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
-
-       return dto_done;
-}
-
-static void wa_xfer_delayed_run(struct wa_rpipe *rpipe)
-{
-       int dto_waiting;
-       int dto_done = __wa_xfer_delayed_run(rpipe, &dto_waiting);
-
-       /*
-        * If this RPIPE is waiting on the DTO resource, add it to the tail of
-        * the waiting list.
-        * Otherwise, if the WA DTO resource was acquired and released by
-        *  __wa_xfer_delayed_run, another RPIPE may have attempted to acquire
-        * DTO and failed during that time.  Check the delayed list and process
-        * any waiters.  Start searching from the next RPIPE index.
-        */
-       if (dto_waiting)
-               wa_add_delayed_rpipe(rpipe->wa, rpipe);
-       else if (dto_done)
-               wa_check_for_delayed_rpipes(rpipe->wa);
-}
-
-/*
- *
- * xfer->lock is taken
- *
- * On failure submitting we just stop submitting and return error;
- * wa_urb_enqueue_b() will execute the completion path
- */
-static int __wa_xfer_submit(struct wa_xfer *xfer)
-{
-       int result, dto_acquired = 0, dto_done = 0, dto_waiting = 0;
-       struct wahc *wa = xfer->wa;
-       struct device *dev = &wa->usb_iface->dev;
-       unsigned cnt;
-       struct wa_seg *seg;
-       unsigned long flags;
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-       size_t maxrequests = le16_to_cpu(rpipe->descr.wRequests);
-       u8 available;
-       u8 empty;
-
-       spin_lock_irqsave(&wa->xfer_list_lock, flags);
-       list_add_tail(&xfer->list_node, &wa->xfer_list);
-       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
-
-       BUG_ON(atomic_read(&rpipe->segs_available) > maxrequests);
-       result = 0;
-       spin_lock_irqsave(&rpipe->seg_lock, flags);
-       for (cnt = 0; cnt < xfer->segs; cnt++) {
-               int delay_seg = 1;
-
-               available = atomic_read(&rpipe->segs_available);
-               empty = list_empty(&rpipe->seg_list);
-               seg = xfer->seg[cnt];
-               if (available && empty) {
-                       /*
-                        * Only attempt to acquire DTO if we have a segment
-                        * to send.
-                        */
-                       dto_acquired = __wa_dto_try_get(rpipe->wa);
-                       if (dto_acquired) {
-                               delay_seg = 0;
-                               result = __wa_seg_submit(rpipe, xfer, seg,
-                                                       &dto_done);
-                               dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u submitted\n",
-                                       xfer, wa_xfer_id(xfer), cnt, available,
-                                       empty);
-                               if (dto_done)
-                                       __wa_dto_put(rpipe->wa);
-
-                               if (result < 0) {
-                                       __wa_xfer_abort(xfer);
-                                       goto error_seg_submit;
-                               }
-                       }
-               }
-
-               if (delay_seg) {
-                       dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u delayed\n",
-                               xfer, wa_xfer_id(xfer), cnt, available,  empty);
-                       seg->status = WA_SEG_DELAYED;
-                       list_add_tail(&seg->list_node, &rpipe->seg_list);
-               }
-               xfer->segs_submitted++;
-       }
-error_seg_submit:
-       /*
-        * Mark this RPIPE as waiting if dto was not acquired, there are
-        * delayed segs and no active transfers to wake us up later.
-        */
-       if (!dto_acquired && !list_empty(&rpipe->seg_list)
-               && (atomic_read(&rpipe->segs_available) ==
-                       le16_to_cpu(rpipe->descr.wRequests)))
-               dto_waiting = 1;
-       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
-
-       if (dto_waiting)
-               wa_add_delayed_rpipe(rpipe->wa, rpipe);
-       else if (dto_done)
-               wa_check_for_delayed_rpipes(rpipe->wa);
-
-       return result;
-}
-
-/*
- * Second part of a URB/transfer enqueuement
- *
- * Assumes this comes from wa_urb_enqueue() [maybe through
- * wa_urb_enqueue_run()]. At this point:
- *
- * xfer->wa    filled and refcounted
- * xfer->ep    filled with rpipe refcounted if
- *              delayed == 0
- * xfer->urb   filled and refcounted (this is the case when called
- *              from wa_urb_enqueue() as we come from usb_submit_urb()
- *              and when called by wa_urb_enqueue_run(), as we took an
- *              extra ref dropped by _run() after we return).
- * xfer->gfp   filled
- *
- * If we fail at __wa_xfer_submit(), then we just check if we are done
- * and if so, we run the completion procedure. However, if we are not
- * yet done, we do nothing and wait for the completion handlers from
- * the submitted URBs or from the xfer-result path to kick in. If xfer
- * result never kicks in, the xfer will timeout from the USB code and
- * dequeue() will be called.
- */
-static int wa_urb_enqueue_b(struct wa_xfer *xfer)
-{
-       int result;
-       unsigned long flags;
-       struct urb *urb = xfer->urb;
-       struct wahc *wa = xfer->wa;
-       struct wusbhc *wusbhc = wa->wusb;
-       struct wusb_dev *wusb_dev;
-       unsigned done;
-
-       result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp);
-       if (result < 0) {
-               pr_err("%s: error_rpipe_get\n", __func__);
-               goto error_rpipe_get;
-       }
-       result = -ENODEV;
-       /* FIXME: segmentation broken -- kills DWA */
-       mutex_lock(&wusbhc->mutex);             /* get a WUSB dev */
-       if (urb->dev == NULL) {
-               mutex_unlock(&wusbhc->mutex);
-               pr_err("%s: error usb dev gone\n", __func__);
-               goto error_dev_gone;
-       }
-       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev);
-       if (wusb_dev == NULL) {
-               mutex_unlock(&wusbhc->mutex);
-               dev_err(&(urb->dev->dev), "%s: error wusb dev gone\n",
-                       __func__);
-               goto error_dev_gone;
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       spin_lock_irqsave(&xfer->lock, flags);
-       xfer->wusb_dev = wusb_dev;
-       result = urb->status;
-       if (urb->status != -EINPROGRESS) {
-               dev_err(&(urb->dev->dev), "%s: error_dequeued\n", __func__);
-               goto error_dequeued;
-       }
-
-       result = __wa_xfer_setup(xfer, urb);
-       if (result < 0) {
-               dev_err(&(urb->dev->dev), "%s: error_xfer_setup\n", __func__);
-               goto error_xfer_setup;
-       }
-       /*
-        * Get a xfer reference since __wa_xfer_submit starts asynchronous
-        * operations that may try to complete the xfer before this function
-        * exits.
-        */
-       wa_xfer_get(xfer);
-       result = __wa_xfer_submit(xfer);
-       if (result < 0) {
-               dev_err(&(urb->dev->dev), "%s: error_xfer_submit\n", __func__);
-               goto error_xfer_submit;
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_xfer_put(xfer);
-       return 0;
-
-       /*
-        * this is basically wa_xfer_completion() broken up wa_xfer_giveback()
-        * does a wa_xfer_put() that will call wa_xfer_destroy() and undo
-        * setup().
-        */
-error_xfer_setup:
-error_dequeued:
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       /* FIXME: segmentation broken, kills DWA */
-       if (wusb_dev)
-               wusb_dev_put(wusb_dev);
-error_dev_gone:
-       rpipe_put(xfer->ep->hcpriv);
-error_rpipe_get:
-       xfer->result = result;
-       return result;
-
-error_xfer_submit:
-       done = __wa_xfer_is_done(xfer);
-       xfer->result = result;
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (done)
-               wa_xfer_completion(xfer);
-       wa_xfer_put(xfer);
-       /* return success since the completion routine will run. */
-       return 0;
-}
-
-/*
- * Execute the delayed transfers in the Wire Adapter @wa
- *
- * We need to be careful here, as dequeue() could be called in the
- * middle.  That's why we do the whole thing under the
- * wa->xfer_list_lock. If dequeue() jumps in, it first locks xfer->lock
- * and then checks the list -- so as we would be acquiring in inverse
- * order, we move the delayed list to a separate list while locked and then
- * submit them without the list lock held.
- */
-void wa_urb_enqueue_run(struct work_struct *ws)
-{
-       struct wahc *wa = container_of(ws, struct wahc, xfer_enqueue_work);
-       struct wa_xfer *xfer, *next;
-       struct urb *urb;
-       LIST_HEAD(tmp_list);
-
-       /* Create a copy of the wa->xfer_delayed_list while holding the lock */
-       spin_lock_irq(&wa->xfer_list_lock);
-       list_cut_position(&tmp_list, &wa->xfer_delayed_list,
-                       wa->xfer_delayed_list.prev);
-       spin_unlock_irq(&wa->xfer_list_lock);
-
-       /*
-        * enqueue from temp list without list lock held since wa_urb_enqueue_b
-        * can take xfer->lock as well as lock mutexes.
-        */
-       list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
-               list_del_init(&xfer->list_node);
-
-               urb = xfer->urb;
-               if (wa_urb_enqueue_b(xfer) < 0)
-                       wa_xfer_giveback(xfer);
-               usb_put_urb(urb);       /* taken when queuing */
-       }
-}
-EXPORT_SYMBOL_GPL(wa_urb_enqueue_run);
-
-/*
- * Process the errored transfers on the Wire Adapter outside of interrupt.
- */
-void wa_process_errored_transfers_run(struct work_struct *ws)
-{
-       struct wahc *wa = container_of(ws, struct wahc, xfer_error_work);
-       struct wa_xfer *xfer, *next;
-       LIST_HEAD(tmp_list);
-
-       pr_info("%s: Run delayed STALL processing.\n", __func__);
-
-       /* Create a copy of the wa->xfer_errored_list while holding the lock */
-       spin_lock_irq(&wa->xfer_list_lock);
-       list_cut_position(&tmp_list, &wa->xfer_errored_list,
-                       wa->xfer_errored_list.prev);
-       spin_unlock_irq(&wa->xfer_list_lock);
-
-       /*
-        * run rpipe_clear_feature_stalled from temp list without list lock
-        * held.
-        */
-       list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
-               struct usb_host_endpoint *ep;
-               unsigned long flags;
-               struct wa_rpipe *rpipe;
-
-               spin_lock_irqsave(&xfer->lock, flags);
-               ep = xfer->ep;
-               rpipe = ep->hcpriv;
-               spin_unlock_irqrestore(&xfer->lock, flags);
-
-               /* clear RPIPE feature stalled without holding a lock. */
-               rpipe_clear_feature_stalled(wa, ep);
-
-               /* complete the xfer. This removes it from the tmp list. */
-               wa_xfer_completion(xfer);
-
-               /* check for work. */
-               wa_xfer_delayed_run(rpipe);
-       }
-}
-EXPORT_SYMBOL_GPL(wa_process_errored_transfers_run);
-
-/*
- * Submit a transfer to the Wire Adapter in a delayed way
- *
- * The process of enqueuing involves possible sleeps() [see
- * enqueue_b(), for the rpipe_get() and the mutex_lock()]. If we are
- * in an atomic section, we defer the enqueue_b() call--else we call direct.
- *
- * @urb: We own a reference to it done by the HCI Linux USB stack that
- *       will be given up by calling usb_hcd_giveback_urb() or by
- *       returning error from this function -> ergo we don't have to
- *       refcount it.
- */
-int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,
-                  struct urb *urb, gfp_t gfp)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_xfer *xfer;
-       unsigned long my_flags;
-       unsigned cant_sleep = irqs_disabled() | in_atomic();
-
-       if ((urb->transfer_buffer == NULL)
-           && (urb->sg == NULL)
-           && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
-           && urb->transfer_buffer_length != 0) {
-               dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb);
-               dump_stack();
-       }
-
-       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
-       result = usb_hcd_link_urb_to_ep(&(wa->wusb->usb_hcd), urb);
-       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-       if (result < 0)
-               goto error_link_urb;
-
-       result = -ENOMEM;
-       xfer = kzalloc(sizeof(*xfer), gfp);
-       if (xfer == NULL)
-               goto error_kmalloc;
-
-       result = -ENOENT;
-       if (urb->status != -EINPROGRESS)        /* cancelled */
-               goto error_dequeued;            /* before starting? */
-       wa_xfer_init(xfer);
-       xfer->wa = wa_get(wa);
-       xfer->urb = urb;
-       xfer->gfp = gfp;
-       xfer->ep = ep;
-       urb->hcpriv = xfer;
-
-       dev_dbg(dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n",
-               xfer, urb, urb->pipe, urb->transfer_buffer_length,
-               urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma",
-               urb->pipe & USB_DIR_IN ? "inbound" : "outbound",
-               cant_sleep ? "deferred" : "inline");
-
-       if (cant_sleep) {
-               usb_get_urb(urb);
-               spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
-               list_add_tail(&xfer->list_node, &wa->xfer_delayed_list);
-               spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-               queue_work(wusbd, &wa->xfer_enqueue_work);
-       } else {
-               result = wa_urb_enqueue_b(xfer);
-               if (result < 0) {
-                       /*
-                        * URB submit/enqueue failed.  Clean up, return an
-                        * error and do not run the callback.  This avoids
-                        * an infinite submit/complete loop.
-                        */
-                       dev_err(dev, "%s: URB enqueue failed: %d\n",
-                          __func__, result);
-                       wa_put(xfer->wa);
-                       wa_xfer_put(xfer);
-                       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
-                       usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb);
-                       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-                       return result;
-               }
-       }
-       return 0;
-
-error_dequeued:
-       kfree(xfer);
-error_kmalloc:
-       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
-       usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb);
-       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-error_link_urb:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wa_urb_enqueue);
-
-/*
- * Dequeue a URB and make sure uwb_hcd_giveback_urb() [completion
- * handler] is called.
- *
- * Until a transfer goes successfully through wa_urb_enqueue() it
- * needs to be dequeued with completion calling; when stuck in delayed
- * or before wa_xfer_setup() is called, we need to do completion.
- *
- *  not setup  If there is no hcpriv yet, that means that that enqueue
- *             still had no time to set the xfer up. Because
- *             urb->status should be other than -EINPROGRESS,
- *             enqueue() will catch that and bail out.
- *
- * If the transfer has gone through setup, we just need to clean it
- * up. If it has gone through submit(), we have to abort it [with an
- * asynch request] and then make sure we cancel each segment.
- *
- */
-int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
-{
-       unsigned long flags;
-       struct wa_xfer *xfer;
-       struct wa_seg *seg;
-       struct wa_rpipe *rpipe;
-       unsigned cnt, done = 0, xfer_abort_pending;
-       unsigned rpipe_ready = 0;
-       int result;
-
-       /* check if it is safe to unlink. */
-       spin_lock_irqsave(&wa->xfer_list_lock, flags);
-       result = usb_hcd_check_unlink_urb(&(wa->wusb->usb_hcd), urb, status);
-       if ((result == 0) && urb->hcpriv) {
-               /*
-                * Get a xfer ref to prevent a race with wa_xfer_giveback
-                * cleaning up the xfer while we are working with it.
-                */
-               wa_xfer_get(urb->hcpriv);
-       }
-       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
-       if (result)
-               return result;
-
-       xfer = urb->hcpriv;
-       if (xfer == NULL)
-               return -ENOENT;
-       spin_lock_irqsave(&xfer->lock, flags);
-       pr_debug("%s: DEQUEUE xfer id 0x%08X\n", __func__, wa_xfer_id(xfer));
-       rpipe = xfer->ep->hcpriv;
-       if (rpipe == NULL) {
-               pr_debug("%s: xfer %p id 0x%08X has no RPIPE.  %s",
-                       __func__, xfer, wa_xfer_id(xfer),
-                       "Probably already aborted.\n" );
-               result = -ENOENT;
-               goto out_unlock;
-       }
-       /*
-        * Check for done to avoid racing with wa_xfer_giveback and completing
-        * twice.
-        */
-       if (__wa_xfer_is_done(xfer)) {
-               pr_debug("%s: xfer %p id 0x%08X already done.\n", __func__,
-                       xfer, wa_xfer_id(xfer));
-               result = -ENOENT;
-               goto out_unlock;
-       }
-       /* Check the delayed list -> if there, release and complete */
-       spin_lock(&wa->xfer_list_lock);
-       if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
-               goto dequeue_delayed;
-       spin_unlock(&wa->xfer_list_lock);
-       if (xfer->seg == NULL)          /* still hasn't reached */
-               goto out_unlock;        /* setup(), enqueue_b() completes */
-       /* Ok, the xfer is in flight already, it's been setup and submitted.*/
-       xfer_abort_pending = __wa_xfer_abort(xfer) >= 0;
-       /*
-        * grab the rpipe->seg_lock here to prevent racing with
-        * __wa_xfer_delayed_run.
-        */
-       spin_lock(&rpipe->seg_lock);
-       for (cnt = 0; cnt < xfer->segs; cnt++) {
-               seg = xfer->seg[cnt];
-               pr_debug("%s: xfer id 0x%08X#%d status = %d\n",
-                       __func__, wa_xfer_id(xfer), cnt, seg->status);
-               switch (seg->status) {
-               case WA_SEG_NOTREADY:
-               case WA_SEG_READY:
-                       printk(KERN_ERR "xfer %p#%u: dequeue bad state %u\n",
-                              xfer, cnt, seg->status);
-                       WARN_ON(1);
-                       break;
-               case WA_SEG_DELAYED:
-                       /*
-                        * delete from rpipe delayed list.  If no segments on
-                        * this xfer have been submitted, __wa_xfer_is_done will
-                        * trigger a giveback below.  Otherwise, the submitted
-                        * segments will be completed in the DTI interrupt.
-                        */
-                       seg->status = WA_SEG_ABORTED;
-                       seg->result = -ENOENT;
-                       list_del(&seg->list_node);
-                       xfer->segs_done++;
-                       break;
-               case WA_SEG_DONE:
-               case WA_SEG_ERROR:
-               case WA_SEG_ABORTED:
-                       break;
-                       /*
-                        * The buf_in data for a segment in the
-                        * WA_SEG_DTI_PENDING state is actively being read.
-                        * Let wa_buf_in_cb handle it since it will be called
-                        * and will increment xfer->segs_done.  Cleaning up
-                        * here could cause wa_buf_in_cb to access the xfer
-                        * after it has been completed/freed.
-                        */
-               case WA_SEG_DTI_PENDING:
-                       break;
-                       /*
-                        * In the states below, the HWA device already knows
-                        * about the transfer.  If an abort request was sent,
-                        * allow the HWA to process it and wait for the
-                        * results.  Otherwise, the DTI state and seg completed
-                        * counts can get out of sync.
-                        */
-               case WA_SEG_SUBMITTED:
-               case WA_SEG_PENDING:
-                       /*
-                        * Check if the abort was successfully sent.  This could
-                        * be false if the HWA has been removed but we haven't
-                        * gotten the disconnect notification yet.
-                        */
-                       if (!xfer_abort_pending) {
-                               seg->status = WA_SEG_ABORTED;
-                               rpipe_ready = rpipe_avail_inc(rpipe);
-                               xfer->segs_done++;
-                       }
-                       break;
-               }
-       }
-       spin_unlock(&rpipe->seg_lock);
-       xfer->result = urb->status;     /* -ENOENT or -ECONNRESET */
-       done = __wa_xfer_is_done(xfer);
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
-       wa_xfer_put(xfer);
-       return result;
-
-out_unlock:
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_xfer_put(xfer);
-       return result;
-
-dequeue_delayed:
-       list_del_init(&xfer->list_node);
-       spin_unlock(&wa->xfer_list_lock);
-       xfer->result = urb->status;
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_xfer_giveback(xfer);
-       wa_xfer_put(xfer);
-       usb_put_urb(urb);               /* we got a ref in enqueue() */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(wa_urb_dequeue);
-
-/*
- * Translation from WA status codes (WUSB1.0 Table 8.15) to errno
- * codes
- *
- * Positive errno values are internal inconsistencies and should be
- * flagged louder. Negative are to be passed up to the user in the
- * normal way.
- *
- * @status: USB WA status code -- high two bits are stripped.
- */
-static int wa_xfer_status_to_errno(u8 status)
-{
-       int errno;
-       u8 real_status = status;
-       static int xlat[] = {
-               [WA_XFER_STATUS_SUCCESS] =              0,
-               [WA_XFER_STATUS_HALTED] =               -EPIPE,
-               [WA_XFER_STATUS_DATA_BUFFER_ERROR] =    -ENOBUFS,
-               [WA_XFER_STATUS_BABBLE] =               -EOVERFLOW,
-               [WA_XFER_RESERVED] =                    EINVAL,
-               [WA_XFER_STATUS_NOT_FOUND] =            0,
-               [WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM,
-               [WA_XFER_STATUS_TRANSACTION_ERROR] =    -EILSEQ,
-               [WA_XFER_STATUS_ABORTED] =              -ENOENT,
-               [WA_XFER_STATUS_RPIPE_NOT_READY] =      EINVAL,
-               [WA_XFER_INVALID_FORMAT] =              EINVAL,
-               [WA_XFER_UNEXPECTED_SEGMENT_NUMBER] =   EINVAL,
-               [WA_XFER_STATUS_RPIPE_TYPE_MISMATCH] =  EINVAL,
-       };
-       status &= 0x3f;
-
-       if (status == 0)
-               return 0;
-       if (status >= ARRAY_SIZE(xlat)) {
-               printk_ratelimited(KERN_ERR "%s(): BUG? "
-                              "Unknown WA transfer status 0x%02x\n",
-                              __func__, real_status);
-               return -EINVAL;
-       }
-       errno = xlat[status];
-       if (unlikely(errno > 0)) {
-               printk_ratelimited(KERN_ERR "%s(): BUG? "
-                              "Inconsistent WA status: 0x%02x\n",
-                              __func__, real_status);
-               errno = -errno;
-       }
-       return errno;
-}
-
-/*
- * If a last segment flag and/or a transfer result error is encountered,
- * no other segment transfer results will be returned from the device.
- * Mark the remaining submitted or pending xfers as completed so that
- * the xfer will complete cleanly.
- *
- * xfer->lock must be held
- *
- */
-static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
-               int starting_index, enum wa_seg_status status)
-{
-       int index;
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-
-       for (index = starting_index; index < xfer->segs_submitted; index++) {
-               struct wa_seg *current_seg = xfer->seg[index];
-
-               BUG_ON(current_seg == NULL);
-
-               switch (current_seg->status) {
-               case WA_SEG_SUBMITTED:
-               case WA_SEG_PENDING:
-               case WA_SEG_DTI_PENDING:
-                       rpipe_avail_inc(rpipe);
-               /*
-                * do not increment RPIPE avail for the WA_SEG_DELAYED case
-                * since it has not been submitted to the RPIPE.
-                */
-               /* fall through */
-               case WA_SEG_DELAYED:
-                       xfer->segs_done++;
-                       current_seg->status = status;
-                       break;
-               case WA_SEG_ABORTED:
-                       break;
-               default:
-                       WARN(1, "%s: xfer 0x%08X#%d. bad seg status = %d\n",
-                               __func__, wa_xfer_id(xfer), index,
-                               current_seg->status);
-                       break;
-               }
-       }
-}
-
-/* Populate the given urb based on the current isoc transfer state. */
-static int __wa_populate_buf_in_urb_isoc(struct wahc *wa,
-       struct urb *buf_in_urb, struct wa_xfer *xfer, struct wa_seg *seg)
-{
-       int urb_start_frame = seg->isoc_frame_index + seg->isoc_frame_offset;
-       int seg_index, total_len = 0, urb_frame_index = urb_start_frame;
-       struct usb_iso_packet_descriptor *iso_frame_desc =
-                                               xfer->urb->iso_frame_desc;
-       const int dti_packet_size = usb_endpoint_maxp(wa->dti_epd);
-       int next_frame_contiguous;
-       struct usb_iso_packet_descriptor *iso_frame;
-
-       BUG_ON(buf_in_urb->status == -EINPROGRESS);
-
-       /*
-        * If the current frame actual_length is contiguous with the next frame
-        * and actual_length is a multiple of the DTI endpoint max packet size,
-        * combine the current frame with the next frame in a single URB.  This
-        * reduces the number of URBs that must be submitted in that case.
-        */
-       seg_index = seg->isoc_frame_index;
-       do {
-               next_frame_contiguous = 0;
-
-               iso_frame = &iso_frame_desc[urb_frame_index];
-               total_len += iso_frame->actual_length;
-               ++urb_frame_index;
-               ++seg_index;
-
-               if (seg_index < seg->isoc_frame_count) {
-                       struct usb_iso_packet_descriptor *next_iso_frame;
-
-                       next_iso_frame = &iso_frame_desc[urb_frame_index];
-
-                       if ((iso_frame->offset + iso_frame->actual_length) ==
-                               next_iso_frame->offset)
-                               next_frame_contiguous = 1;
-               }
-       } while (next_frame_contiguous
-                       && ((iso_frame->actual_length % dti_packet_size) == 0));
-
-       /* this should always be 0 before a resubmit. */
-       buf_in_urb->num_mapped_sgs      = 0;
-       buf_in_urb->transfer_dma = xfer->urb->transfer_dma +
-               iso_frame_desc[urb_start_frame].offset;
-       buf_in_urb->transfer_buffer_length = total_len;
-       buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-       buf_in_urb->transfer_buffer = NULL;
-       buf_in_urb->sg = NULL;
-       buf_in_urb->num_sgs = 0;
-       buf_in_urb->context = seg;
-
-       /* return the number of frames included in this URB. */
-       return seg_index - seg->isoc_frame_index;
-}
-
-/* Populate the given urb based on the current transfer state. */
-static int wa_populate_buf_in_urb(struct urb *buf_in_urb, struct wa_xfer *xfer,
-       unsigned int seg_idx, unsigned int bytes_transferred)
-{
-       int result = 0;
-       struct wa_seg *seg = xfer->seg[seg_idx];
-
-       BUG_ON(buf_in_urb->status == -EINPROGRESS);
-       /* this should always be 0 before a resubmit. */
-       buf_in_urb->num_mapped_sgs      = 0;
-
-       if (xfer->is_dma) {
-               buf_in_urb->transfer_dma = xfer->urb->transfer_dma
-                       + (seg_idx * xfer->seg_size);
-               buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-               buf_in_urb->transfer_buffer = NULL;
-               buf_in_urb->sg = NULL;
-               buf_in_urb->num_sgs = 0;
-       } else {
-               /* do buffer or SG processing. */
-               buf_in_urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
-
-               if (xfer->urb->transfer_buffer) {
-                       buf_in_urb->transfer_buffer =
-                               xfer->urb->transfer_buffer
-                               + (seg_idx * xfer->seg_size);
-                       buf_in_urb->sg = NULL;
-                       buf_in_urb->num_sgs = 0;
-               } else {
-                       /* allocate an SG list to store seg_size bytes
-                               and copy the subset of the xfer->urb->sg
-                               that matches the buffer subset we are
-                               about to read. */
-                       buf_in_urb->sg = wa_xfer_create_subset_sg(
-                               xfer->urb->sg,
-                               seg_idx * xfer->seg_size,
-                               bytes_transferred,
-                               &(buf_in_urb->num_sgs));
-
-                       if (!(buf_in_urb->sg)) {
-                               buf_in_urb->num_sgs     = 0;
-                               result = -ENOMEM;
-                       }
-                       buf_in_urb->transfer_buffer = NULL;
-               }
-       }
-       buf_in_urb->transfer_buffer_length = bytes_transferred;
-       buf_in_urb->context = seg;
-
-       return result;
-}
-
-/*
- * Process a xfer result completion message
- *
- * inbound transfers: need to schedule a buf_in_urb read
- *
- * FIXME: this function needs to be broken up in parts
- */
-static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer,
-               struct wa_xfer_result *xfer_result)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-       unsigned long flags;
-       unsigned int seg_idx;
-       struct wa_seg *seg;
-       struct wa_rpipe *rpipe;
-       unsigned done = 0;
-       u8 usb_status;
-       unsigned rpipe_ready = 0;
-       unsigned bytes_transferred = le32_to_cpu(xfer_result->dwTransferLength);
-       struct urb *buf_in_urb = &(wa->buf_in_urbs[0]);
-
-       spin_lock_irqsave(&xfer->lock, flags);
-       seg_idx = xfer_result->bTransferSegment & 0x7f;
-       if (unlikely(seg_idx >= xfer->segs))
-               goto error_bad_seg;
-       seg = xfer->seg[seg_idx];
-       rpipe = xfer->ep->hcpriv;
-       usb_status = xfer_result->bTransferStatus;
-       dev_dbg(dev, "xfer %p ID 0x%08X#%u: bTransferStatus 0x%02x (seg status %u)\n",
-               xfer, wa_xfer_id(xfer), seg_idx, usb_status, seg->status);
-       if (seg->status == WA_SEG_ABORTED
-           || seg->status == WA_SEG_ERROR)     /* already handled */
-               goto segment_aborted;
-       if (seg->status == WA_SEG_SUBMITTED)    /* ops, got here */
-               seg->status = WA_SEG_PENDING;   /* before wa_seg{_dto}_cb() */
-       if (seg->status != WA_SEG_PENDING) {
-               if (printk_ratelimit())
-                       dev_err(dev, "xfer %p#%u: Bad segment state %u\n",
-                               xfer, seg_idx, seg->status);
-               seg->status = WA_SEG_PENDING;   /* workaround/"fix" it */
-       }
-       if (usb_status & 0x80) {
-               seg->result = wa_xfer_status_to_errno(usb_status);
-               dev_err(dev, "DTI: xfer %p 0x%08X:#%u failed (0x%02x)\n",
-                       xfer, xfer->id, seg->index, usb_status);
-               seg->status = ((usb_status & 0x7F) == WA_XFER_STATUS_ABORTED) ?
-                       WA_SEG_ABORTED : WA_SEG_ERROR;
-               goto error_complete;
-       }
-       /* FIXME: we ignore warnings, tally them for stats */
-       if (usb_status & 0x40)          /* Warning?... */
-               usb_status = 0;         /* ... pass */
-       /*
-        * If the last segment bit is set, complete the remaining segments.
-        * When the current segment is completed, either in wa_buf_in_cb for
-        * transfers with data or below for no data, the xfer will complete.
-        */
-       if (xfer_result->bTransferSegment & 0x80)
-               wa_complete_remaining_xfer_segs(xfer, seg->index + 1,
-                       WA_SEG_DONE);
-       if (usb_pipeisoc(xfer->urb->pipe)
-               && (le32_to_cpu(xfer_result->dwNumOfPackets) > 0)) {
-               /* set up WA state to read the isoc packet status next. */
-               wa->dti_isoc_xfer_in_progress = wa_xfer_id(xfer);
-               wa->dti_isoc_xfer_seg = seg_idx;
-               wa->dti_state = WA_DTI_ISOC_PACKET_STATUS_PENDING;
-       } else if (xfer->is_inbound && !usb_pipeisoc(xfer->urb->pipe)
-                       && (bytes_transferred > 0)) {
-               /* IN data phase: read to buffer */
-               seg->status = WA_SEG_DTI_PENDING;
-               result = wa_populate_buf_in_urb(buf_in_urb, xfer, seg_idx,
-                       bytes_transferred);
-               if (result < 0)
-                       goto error_buf_in_populate;
-               ++(wa->active_buf_in_urbs);
-               result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
-               if (result < 0) {
-                       --(wa->active_buf_in_urbs);
-                       goto error_submit_buf_in;
-               }
-       } else {
-               /* OUT data phase or no data, complete it -- */
-               seg->result = bytes_transferred;
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
-       return;
-
-error_submit_buf_in:
-       if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
-               dev_err(dev, "DTI: URB max acceptable errors "
-                       "exceeded, resetting device\n");
-               wa_reset_all(wa);
-       }
-       if (printk_ratelimit())
-               dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",
-                       xfer, seg_idx, result);
-       seg->result = result;
-       kfree(buf_in_urb->sg);
-       buf_in_urb->sg = NULL;
-error_buf_in_populate:
-       __wa_xfer_abort(xfer);
-       seg->status = WA_SEG_ERROR;
-error_complete:
-       xfer->segs_done++;
-       rpipe_ready = rpipe_avail_inc(rpipe);
-       wa_complete_remaining_xfer_segs(xfer, seg->index + 1, seg->status);
-       done = __wa_xfer_is_done(xfer);
-       /*
-        * queue work item to clear STALL for control endpoints.
-        * Otherwise, let endpoint_reset take care of it.
-        */
-       if (((usb_status & 0x3f) == WA_XFER_STATUS_HALTED) &&
-               usb_endpoint_xfer_control(&xfer->ep->desc) &&
-               done) {
-
-               dev_info(dev, "Control EP stall.  Queue delayed work.\n");
-               spin_lock(&wa->xfer_list_lock);
-               /* move xfer from xfer_list to xfer_errored_list. */
-               list_move_tail(&xfer->list_node, &wa->xfer_errored_list);
-               spin_unlock(&wa->xfer_list_lock);
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               queue_work(wusbd, &wa->xfer_error_work);
-       } else {
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-       }
-
-       return;
-
-error_bad_seg:
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_urb_dequeue(wa, xfer->urb, -ENOENT);
-       if (printk_ratelimit())
-               dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx);
-       if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
-               dev_err(dev, "DTI: URB max acceptable errors "
-                       "exceeded, resetting device\n");
-               wa_reset_all(wa);
-       }
-       return;
-
-segment_aborted:
-       /* nothing to do, as the aborter did the completion */
-       spin_unlock_irqrestore(&xfer->lock, flags);
-}
-
-/*
- * Process a isochronous packet status message
- *
- * inbound transfers: need to schedule a buf_in_urb read
- */
-static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb)
-{
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_xfer_packet_status_hwaiso *packet_status;
-       struct wa_xfer_packet_status_len_hwaiso *status_array;
-       struct wa_xfer *xfer;
-       unsigned long flags;
-       struct wa_seg *seg;
-       struct wa_rpipe *rpipe;
-       unsigned done = 0, dti_busy = 0, data_frame_count = 0, seg_index;
-       unsigned first_frame_index = 0, rpipe_ready = 0;
-       size_t expected_size;
-
-       /* We have a xfer result buffer; check it */
-       dev_dbg(dev, "DTI: isoc packet status %d bytes at %p\n",
-               urb->actual_length, urb->transfer_buffer);
-       packet_status = (struct wa_xfer_packet_status_hwaiso *)(wa->dti_buf);
-       if (packet_status->bPacketType != WA_XFER_ISO_PACKET_STATUS) {
-               dev_err(dev, "DTI Error: isoc packet status--bad type 0x%02x\n",
-                       packet_status->bPacketType);
-               goto error_parse_buffer;
-       }
-       xfer = wa_xfer_get_by_id(wa, wa->dti_isoc_xfer_in_progress);
-       if (xfer == NULL) {
-               dev_err(dev, "DTI Error: isoc packet status--unknown xfer 0x%08x\n",
-                       wa->dti_isoc_xfer_in_progress);
-               goto error_parse_buffer;
-       }
-       spin_lock_irqsave(&xfer->lock, flags);
-       if (unlikely(wa->dti_isoc_xfer_seg >= xfer->segs))
-               goto error_bad_seg;
-       seg = xfer->seg[wa->dti_isoc_xfer_seg];
-       rpipe = xfer->ep->hcpriv;
-       expected_size = struct_size(packet_status, PacketStatus,
-                                   seg->isoc_frame_count);
-       if (urb->actual_length != expected_size) {
-               dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %zu needed)\n",
-                       urb->actual_length, expected_size);
-               goto error_bad_seg;
-       }
-       if (le16_to_cpu(packet_status->wLength) != expected_size) {
-               dev_err(dev, "DTI Error: isoc packet status--bad length %u\n",
-                       le16_to_cpu(packet_status->wLength));
-               goto error_bad_seg;
-       }
-       /* write isoc packet status and lengths back to the xfer urb. */
-       status_array = packet_status->PacketStatus;
-       xfer->urb->start_frame =
-               wa->wusb->usb_hcd.driver->get_frame_number(&wa->wusb->usb_hcd);
-       for (seg_index = 0; seg_index < seg->isoc_frame_count; ++seg_index) {
-               struct usb_iso_packet_descriptor *iso_frame_desc =
-                       xfer->urb->iso_frame_desc;
-               const int xfer_frame_index =
-                       seg->isoc_frame_offset + seg_index;
-
-               iso_frame_desc[xfer_frame_index].status =
-                       wa_xfer_status_to_errno(
-                       le16_to_cpu(status_array[seg_index].PacketStatus));
-               iso_frame_desc[xfer_frame_index].actual_length =
-                       le16_to_cpu(status_array[seg_index].PacketLength);
-               /* track the number of frames successfully transferred. */
-               if (iso_frame_desc[xfer_frame_index].actual_length > 0) {
-                       /* save the starting frame index for buf_in_urb. */
-                       if (!data_frame_count)
-                               first_frame_index = seg_index;
-                       ++data_frame_count;
-               }
-       }
-
-       if (xfer->is_inbound && data_frame_count) {
-               int result, total_frames_read = 0, urb_index = 0;
-               struct urb *buf_in_urb;
-
-               /* IN data phase: read to buffer */
-               seg->status = WA_SEG_DTI_PENDING;
-
-               /* start with the first frame with data. */
-               seg->isoc_frame_index = first_frame_index;
-               /* submit up to WA_MAX_BUF_IN_URBS read URBs. */
-               do {
-                       int urb_frame_index, urb_frame_count;
-                       struct usb_iso_packet_descriptor *iso_frame_desc;
-
-                       buf_in_urb = &(wa->buf_in_urbs[urb_index]);
-                       urb_frame_count = __wa_populate_buf_in_urb_isoc(wa,
-                               buf_in_urb, xfer, seg);
-                       /* advance frame index to start of next read URB. */
-                       seg->isoc_frame_index += urb_frame_count;
-                       total_frames_read += urb_frame_count;
-
-                       ++(wa->active_buf_in_urbs);
-                       result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
-
-                       /* skip 0-byte frames. */
-                       urb_frame_index =
-                               seg->isoc_frame_offset + seg->isoc_frame_index;
-                       iso_frame_desc =
-                               &(xfer->urb->iso_frame_desc[urb_frame_index]);
-                       while ((seg->isoc_frame_index <
-                                               seg->isoc_frame_count) &&
-                                (iso_frame_desc->actual_length == 0)) {
-                               ++(seg->isoc_frame_index);
-                               ++iso_frame_desc;
-                       }
-                       ++urb_index;
-
-               } while ((result == 0) && (urb_index < WA_MAX_BUF_IN_URBS)
-                               && (seg->isoc_frame_index <
-                                               seg->isoc_frame_count));
-
-               if (result < 0) {
-                       --(wa->active_buf_in_urbs);
-                       dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
-                               result);
-                       wa_reset_all(wa);
-               } else if (data_frame_count > total_frames_read)
-                       /* If we need to read more frames, set DTI busy. */
-                       dti_busy = 1;
-       } else {
-               /* OUT transfer or no more IN data, complete it -- */
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (dti_busy)
-               wa->dti_state = WA_DTI_BUF_IN_DATA_PENDING;
-       else
-               wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
-       wa_xfer_put(xfer);
-       return dti_busy;
-
-error_bad_seg:
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_xfer_put(xfer);
-error_parse_buffer:
-       return dti_busy;
-}
-
-/*
- * Callback for the IN data phase
- *
- * If successful transition state; otherwise, take a note of the
- * error, mark this segment done and try completion.
- *
- * Note we don't access until we are sure that the transfer hasn't
- * been cancelled (ECONNRESET, ENOENT), which could mean that
- * seg->xfer could be already gone.
- */
-static void wa_buf_in_cb(struct urb *urb)
-{
-       struct wa_seg *seg = urb->context;
-       struct wa_xfer *xfer = seg->xfer;
-       struct wahc *wa;
-       struct device *dev;
-       struct wa_rpipe *rpipe;
-       unsigned rpipe_ready = 0, isoc_data_frame_count = 0;
-       unsigned long flags;
-       int resubmit_dti = 0, active_buf_in_urbs;
-       u8 done = 0;
-
-       /* free the sg if it was used. */
-       kfree(urb->sg);
-       urb->sg = NULL;
-
-       spin_lock_irqsave(&xfer->lock, flags);
-       wa = xfer->wa;
-       dev = &wa->usb_iface->dev;
-       --(wa->active_buf_in_urbs);
-       active_buf_in_urbs = wa->active_buf_in_urbs;
-       rpipe = xfer->ep->hcpriv;
-
-       if (usb_pipeisoc(xfer->urb->pipe)) {
-               struct usb_iso_packet_descriptor *iso_frame_desc =
-                       xfer->urb->iso_frame_desc;
-               int     seg_index;
-
-               /*
-                * Find the next isoc frame with data and count how many
-                * frames with data remain.
-                */
-               seg_index = seg->isoc_frame_index;
-               while (seg_index < seg->isoc_frame_count) {
-                       const int urb_frame_index =
-                               seg->isoc_frame_offset + seg_index;
-
-                       if (iso_frame_desc[urb_frame_index].actual_length > 0) {
-                               /* save the index of the next frame with data */
-                               if (!isoc_data_frame_count)
-                                       seg->isoc_frame_index = seg_index;
-                               ++isoc_data_frame_count;
-                       }
-                       ++seg_index;
-               }
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&xfer->lock, flags);
-
-               seg->result += urb->actual_length;
-               if (isoc_data_frame_count > 0) {
-                       int result, urb_frame_count;
-
-                       /* submit a read URB for the next frame with data. */
-                       urb_frame_count = __wa_populate_buf_in_urb_isoc(wa, urb,
-                                xfer, seg);
-                       /* advance index to start of next read URB. */
-                       seg->isoc_frame_index += urb_frame_count;
-                       ++(wa->active_buf_in_urbs);
-                       result = usb_submit_urb(urb, GFP_ATOMIC);
-                       if (result < 0) {
-                               --(wa->active_buf_in_urbs);
-                               dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
-                                       result);
-                               wa_reset_all(wa);
-                       }
-                       /*
-                        * If we are in this callback and
-                        * isoc_data_frame_count > 0, it means that the dti_urb
-                        * submission was delayed in wa_dti_cb.  Once
-                        * we submit the last buf_in_urb, we can submit the
-                        * delayed dti_urb.
-                        */
-                         resubmit_dti = (isoc_data_frame_count ==
-                                                       urb_frame_count);
-               } else if (active_buf_in_urbs == 0) {
-                       dev_dbg(dev,
-                               "xfer %p 0x%08X#%u: data in done (%zu bytes)\n",
-                               xfer, wa_xfer_id(xfer), seg->index,
-                               seg->result);
-                       rpipe_ready = rpipe_avail_inc(rpipe);
-                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
-                                       WA_SEG_DONE);
-               }
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-               break;
-       case -ECONNRESET:       /* URB unlinked; no need to do anything */
-       case -ENOENT:           /* as it was done by the who unlinked us */
-               break;
-       default:                /* Other errors ... */
-               /*
-                * Error on data buf read.  Only resubmit DTI if it hasn't
-                * already been done by previously hitting this error or by a
-                * successful completion of the previous buf_in_urb.
-                */
-               resubmit_dti = wa->dti_state != WA_DTI_TRANSFER_RESULT_PENDING;
-               spin_lock_irqsave(&xfer->lock, flags);
-               if (printk_ratelimit())
-                       dev_err(dev, "xfer %p 0x%08X#%u: data in error %d\n",
-                               xfer, wa_xfer_id(xfer), seg->index,
-                               urb->status);
-               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)){
-                       dev_err(dev, "DTO: URB max acceptable errors "
-                               "exceeded, resetting device\n");
-                       wa_reset_all(wa);
-               }
-               seg->result = urb->status;
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               if (active_buf_in_urbs == 0)
-                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
-                               WA_SEG_ERROR);
-               else
-                       __wa_xfer_abort(xfer);
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-       }
-
-       if (resubmit_dti) {
-               int result;
-
-               wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
-
-               result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
-               if (result < 0) {
-                       dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
-                               result);
-                       wa_reset_all(wa);
-               }
-       }
-}
-
-/*
- * Handle an incoming transfer result buffer
- *
- * Given a transfer result buffer, it completes the transfer (possibly
- * scheduling and buffer in read) and then resubmits the DTI URB for a
- * new transfer result read.
- *
- *
- * The xfer_result DTI URB state machine
- *
- * States: OFF | RXR (Read-Xfer-Result) | RBI (Read-Buffer-In)
- *
- * We start in OFF mode, the first xfer_result notification [through
- * wa_handle_notif_xfer()] moves us to RXR by posting the DTI-URB to
- * read.
- *
- * We receive a buffer -- if it is not a xfer_result, we complain and
- * repost the DTI-URB. If it is a xfer_result then do the xfer seg
- * request accounting. If it is an IN segment, we move to RBI and post
- * a BUF-IN-URB to the right buffer. The BUF-IN-URB callback will
- * repost the DTI-URB and move to RXR state. if there was no IN
- * segment, it will repost the DTI-URB.
- *
- * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many
- * errors) in the URBs.
- */
-static void wa_dti_cb(struct urb *urb)
-{
-       int result, dti_busy = 0;
-       struct wahc *wa = urb->context;
-       struct device *dev = &wa->usb_iface->dev;
-       u32 xfer_id;
-       u8 usb_status;
-
-       BUG_ON(wa->dti_urb != urb);
-       switch (wa->dti_urb->status) {
-       case 0:
-               if (wa->dti_state == WA_DTI_TRANSFER_RESULT_PENDING) {
-                       struct wa_xfer_result *xfer_result;
-                       struct wa_xfer *xfer;
-
-                       /* We have a xfer result buffer; check it */
-                       dev_dbg(dev, "DTI: xfer result %d bytes at %p\n",
-                               urb->actual_length, urb->transfer_buffer);
-                       if (urb->actual_length != sizeof(*xfer_result)) {
-                               dev_err(dev, "DTI Error: xfer result--bad size xfer result (%d bytes vs %zu needed)\n",
-                                       urb->actual_length,
-                                       sizeof(*xfer_result));
-                               break;
-                       }
-                       xfer_result = (struct wa_xfer_result *)(wa->dti_buf);
-                       if (xfer_result->hdr.bLength != sizeof(*xfer_result)) {
-                               dev_err(dev, "DTI Error: xfer result--bad header length %u\n",
-                                       xfer_result->hdr.bLength);
-                               break;
-                       }
-                       if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) {
-                               dev_err(dev, "DTI Error: xfer result--bad header type 0x%02x\n",
-                                       xfer_result->hdr.bNotifyType);
-                               break;
-                       }
-                       xfer_id = le32_to_cpu(xfer_result->dwTransferID);
-                       usb_status = xfer_result->bTransferStatus & 0x3f;
-                       if (usb_status == WA_XFER_STATUS_NOT_FOUND) {
-                               /* taken care of already */
-                               dev_dbg(dev, "%s: xfer 0x%08X#%u not found.\n",
-                                       __func__, xfer_id,
-                                       xfer_result->bTransferSegment & 0x7f);
-                               break;
-                       }
-                       xfer = wa_xfer_get_by_id(wa, xfer_id);
-                       if (xfer == NULL) {
-                               /* FIXME: transaction not found. */
-                               dev_err(dev, "DTI Error: xfer result--unknown xfer 0x%08x (status 0x%02x)\n",
-                                       xfer_id, usb_status);
-                               break;
-                       }
-                       wa_xfer_result_chew(wa, xfer, xfer_result);
-                       wa_xfer_put(xfer);
-               } else if (wa->dti_state == WA_DTI_ISOC_PACKET_STATUS_PENDING) {
-                       dti_busy = wa_process_iso_packet_status(wa, urb);
-               } else {
-                       dev_err(dev, "DTI Error: unexpected EP state = %d\n",
-                               wa->dti_state);
-               }
-               break;
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-       case -ESHUTDOWN:        /* going away! */
-               dev_dbg(dev, "DTI: going down! %d\n", urb->status);
-               goto out;
-       default:
-               /* Unknown error */
-               if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)) {
-                       dev_err(dev, "DTI: URB max acceptable errors "
-                               "exceeded, resetting device\n");
-                       wa_reset_all(wa);
-                       goto out;
-               }
-               if (printk_ratelimit())
-                       dev_err(dev, "DTI: URB error %d\n", urb->status);
-               break;
-       }
-
-       /* Resubmit the DTI URB if we are not busy processing isoc in frames. */
-       if (!dti_busy) {
-               result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
-               if (result < 0) {
-                       dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
-                               result);
-                       wa_reset_all(wa);
-               }
-       }
-out:
-       return;
-}
-
-/*
- * Initialize the DTI URB for reading transfer result notifications and also
- * the buffer-in URB, for reading buffers. Then we just submit the DTI URB.
- */
-int wa_dti_start(struct wahc *wa)
-{
-       const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
-       struct device *dev = &wa->usb_iface->dev;
-       int result = -ENOMEM, index;
-
-       if (wa->dti_urb != NULL)        /* DTI URB already started */
-               goto out;
-
-       wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (wa->dti_urb == NULL)
-               goto error_dti_urb_alloc;
-       usb_fill_bulk_urb(
-               wa->dti_urb, wa->usb_dev,
-               usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress),
-               wa->dti_buf, wa->dti_buf_size,
-               wa_dti_cb, wa);
-
-       /* init the buf in URBs */
-       for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) {
-               usb_fill_bulk_urb(
-                       &(wa->buf_in_urbs[index]), wa->usb_dev,
-                       usb_rcvbulkpipe(wa->usb_dev,
-                               0x80 | dti_epd->bEndpointAddress),
-                       NULL, 0, wa_buf_in_cb, wa);
-       }
-       result = usb_submit_urb(wa->dti_urb, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "DTI Error: Could not submit DTI URB (%d) resetting\n",
-                       result);
-               goto error_dti_urb_submit;
-       }
-out:
-       return 0;
-
-error_dti_urb_submit:
-       usb_put_urb(wa->dti_urb);
-       wa->dti_urb = NULL;
-error_dti_urb_alloc:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wa_dti_start);
-/*
- * Transfer complete notification
- *
- * Called from the notif.c code. We get a notification on EP2 saying
- * that some endpoint has some transfer result data available. We are
- * about to read it.
- *
- * To speed up things, we always have a URB reading the DTI URB; we
- * don't really set it up and start it until the first xfer complete
- * notification arrives, which is what we do here.
- *
- * Follow up in wa_dti_cb(), as that's where the whole state
- * machine starts.
- *
- * @wa shall be referenced
- */
-void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
-{
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_notif_xfer *notif_xfer;
-       const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
-
-       notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr);
-       BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER);
-
-       if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) {
-               /* FIXME: hardcoded limitation, adapt */
-               dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n",
-                       notif_xfer->bEndpoint, dti_epd->bEndpointAddress);
-               goto error;
-       }
-
-       /* attempt to start the DTI ep processing. */
-       if (wa_dti_start(wa) < 0)
-               goto error;
-
-       return;
-
-error:
-       wa_reset_all(wa);
-}
diff --git a/drivers/staging/wusbcore/wusbhc.c b/drivers/staging/wusbcore/wusbhc.c
deleted file mode 100644 (file)
index d0b404d..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * sysfs glue, wusbcore module support and life cycle management
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Creation/destruction of wusbhc is split in two parts; that that
- * doesn't require the HCD to be added (wusbhc_{create,destroy}) and
- * the one that requires (phase B, wusbhc_b_{create,destroy}).
- *
- * This is so because usb_add_hcd() will start the HC, and thus, all
- * the HC specific stuff has to be already initialized (like sysfs
- * thingies).
- */
-#include <linux/device.h>
-#include <linux/module.h>
-#include "wusbhc.h"
-
-/**
- * Extract the wusbhc that corresponds to a USB Host Controller class device
- *
- * WARNING! Apply only if @dev is that of a
- *          wusbhc.usb_hcd.self->class_dev; otherwise, you loose.
- */
-static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev)
-{
-       struct usb_bus *usb_bus = dev_get_drvdata(dev);
-       struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus);
-       return usb_hcd_to_wusbhc(usb_hcd);
-}
-
-/*
- * Show & store the current WUSB trust timeout
- *
- * We don't do locking--it is an 'atomic' value.
- *
- * The units that we store/show are always MILLISECONDS. However, the
- * value of trust_timeout is jiffies.
- */
-static ssize_t wusb_trust_timeout_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout);
-}
-
-static ssize_t wusb_trust_timeout_store(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       ssize_t result = -ENOSYS;
-       unsigned trust_timeout;
-
-       result = sscanf(buf, "%u", &trust_timeout);
-       if (result != 1) {
-               result = -EINVAL;
-               goto out;
-       }
-       wusbhc->trust_timeout = min_t(unsigned, trust_timeout, 500);
-       cancel_delayed_work(&wusbhc->keep_alive_timer);
-       flush_workqueue(wusbd);
-       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
-                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
-out:
-       return result < 0 ? result : size;
-}
-static DEVICE_ATTR_RW(wusb_trust_timeout);
-
-/*
- * Show the current WUSB CHID.
- */
-static ssize_t wusb_chid_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       const struct wusb_ckhdid *chid;
-
-       if (wusbhc->wuie_host_info != NULL)
-               chid = &wusbhc->wuie_host_info->CHID;
-       else
-               chid = &wusb_ckhdid_zero;
-
-       return sprintf(buf, "%16ph\n", chid->data);
-}
-
-/*
- * Store a new CHID.
- *
- * - Write an all zeros CHID and it will stop the controller
- * - Write a non-zero CHID and it will start it.
- *
- * See wusbhc_chid_set() for more info.
- */
-static ssize_t wusb_chid_store(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       struct wusb_ckhdid chid;
-       ssize_t result;
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx\n",
-                       &chid.data[0] , &chid.data[1] ,
-                       &chid.data[2] , &chid.data[3] ,
-                       &chid.data[4] , &chid.data[5] ,
-                       &chid.data[6] , &chid.data[7] ,
-                       &chid.data[8] , &chid.data[9] ,
-                       &chid.data[10], &chid.data[11],
-                       &chid.data[12], &chid.data[13],
-                       &chid.data[14], &chid.data[15]);
-       if (result != 16) {
-               dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): "
-                       "%d\n", (int)result);
-               return -EINVAL;
-       }
-       result = wusbhc_chid_set(wusbhc, &chid);
-       return result < 0 ? result : size;
-}
-static DEVICE_ATTR_RW(wusb_chid);
-
-
-static ssize_t wusb_phy_rate_show(struct device *dev,
-                                 struct device_attribute *attr,
-                                 char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-
-       return sprintf(buf, "%d\n", wusbhc->phy_rate);
-}
-
-static ssize_t wusb_phy_rate_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       uint8_t phy_rate;
-       ssize_t result;
-
-       result = sscanf(buf, "%hhu", &phy_rate);
-       if (result != 1)
-               return -EINVAL;
-       if (phy_rate >= UWB_PHY_RATE_INVALID)
-               return -EINVAL;
-
-       wusbhc->phy_rate = phy_rate;
-       return size;
-}
-static DEVICE_ATTR_RW(wusb_phy_rate);
-
-static ssize_t wusb_dnts_show(struct device *dev,
-                                 struct device_attribute *attr,
-                                 char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-
-       return sprintf(buf, "num slots: %d\ninterval: %dms\n",
-                       wusbhc->dnts_num_slots, wusbhc->dnts_interval);
-}
-
-static ssize_t wusb_dnts_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       uint8_t num_slots, interval;
-       ssize_t result;
-
-       result = sscanf(buf, "%hhu %hhu", &num_slots, &interval);
-
-       if (result != 2)
-               return -EINVAL;
-
-       wusbhc->dnts_num_slots = num_slots;
-       wusbhc->dnts_interval = interval;
-
-       return size;
-}
-static DEVICE_ATTR_RW(wusb_dnts);
-
-static ssize_t wusb_retry_count_show(struct device *dev,
-                                 struct device_attribute *attr,
-                                 char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-
-       return sprintf(buf, "%d\n", wusbhc->retry_count);
-}
-
-static ssize_t wusb_retry_count_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       uint8_t retry_count;
-       ssize_t result;
-
-       result = sscanf(buf, "%hhu", &retry_count);
-
-       if (result != 1)
-               return -EINVAL;
-
-       wusbhc->retry_count = max_t(uint8_t, retry_count,
-                                       WUSB_RETRY_COUNT_MAX);
-
-       return size;
-}
-static DEVICE_ATTR_RW(wusb_retry_count);
-
-/* Group all the WUSBHC attributes */
-static struct attribute *wusbhc_attrs[] = {
-               &dev_attr_wusb_trust_timeout.attr,
-               &dev_attr_wusb_chid.attr,
-               &dev_attr_wusb_phy_rate.attr,
-               &dev_attr_wusb_dnts.attr,
-               &dev_attr_wusb_retry_count.attr,
-               NULL,
-};
-
-static const struct attribute_group wusbhc_attr_group = {
-       .name = NULL,   /* we want them in the same directory */
-       .attrs = wusbhc_attrs,
-};
-
-/*
- * Create a wusbhc instance
- *
- * NOTEs:
- *
- *  - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been
- *    initialized but not added.
- *
- *  - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling.
- *
- *  - fill out wusbhc->uwb_rc and refcount it before calling
- *  - fill out the wusbhc->sec_modes array
- */
-int wusbhc_create(struct wusbhc *wusbhc)
-{
-       int result = 0;
-
-       /* set defaults.  These can be overwritten using sysfs attributes. */
-       wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;
-       wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1;
-       wusbhc->dnts_num_slots = 4;
-       wusbhc->dnts_interval = 2;
-       wusbhc->retry_count = WUSB_RETRY_COUNT_INFINITE;
-
-       mutex_init(&wusbhc->mutex);
-       result = wusbhc_mmcie_create(wusbhc);
-       if (result < 0)
-               goto error_mmcie_create;
-       result = wusbhc_devconnect_create(wusbhc);
-       if (result < 0)
-               goto error_devconnect_create;
-       result = wusbhc_rh_create(wusbhc);
-       if (result < 0)
-               goto error_rh_create;
-       result = wusbhc_sec_create(wusbhc);
-       if (result < 0)
-               goto error_sec_create;
-       return 0;
-
-error_sec_create:
-       wusbhc_rh_destroy(wusbhc);
-error_rh_create:
-       wusbhc_devconnect_destroy(wusbhc);
-error_devconnect_create:
-       wusbhc_mmcie_destroy(wusbhc);
-error_mmcie_create:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_create);
-
-static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc)
-{
-       return &wusbhc->usb_hcd.self.controller->kobj;
-}
-
-/*
- * Phase B of a wusbhc instance creation
- *
- * Creates fields that depend on wusbhc->usb_hcd having been
- * added. This is where we create the sysfs files in
- * /sys/class/usb_host/usb_hostX/.
- *
- * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper
- *       layer (hwahc or whci)
- */
-int wusbhc_b_create(struct wusbhc *wusbhc)
-{
-       int result = 0;
-       struct device *dev = wusbhc->usb_hcd.self.controller;
-
-       result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
-       if (result < 0) {
-               dev_err(dev, "Cannot register WUSBHC attributes: %d\n",
-                       result);
-               goto error_create_attr_group;
-       }
-
-       return 0;
-error_create_attr_group:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_b_create);
-
-void wusbhc_b_destroy(struct wusbhc *wusbhc)
-{
-       wusbhc_pal_unregister(wusbhc);
-       sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
-}
-EXPORT_SYMBOL_GPL(wusbhc_b_destroy);
-
-void wusbhc_destroy(struct wusbhc *wusbhc)
-{
-       wusbhc_sec_destroy(wusbhc);
-       wusbhc_rh_destroy(wusbhc);
-       wusbhc_devconnect_destroy(wusbhc);
-       wusbhc_mmcie_destroy(wusbhc);
-}
-EXPORT_SYMBOL_GPL(wusbhc_destroy);
-
-struct workqueue_struct *wusbd;
-EXPORT_SYMBOL_GPL(wusbd);
-
-/*
- * WUSB Cluster ID allocation map
- *
- * Each WUSB bus in a channel is identified with a Cluster Id in the
- * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff
- * (that's space for 31 WUSB controllers, as 0xff can't be taken). We
- * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff).
- *
- * For each one we taken, we pin it in the bitap
- */
-#define CLUSTER_IDS 32
-static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS);
-static DEFINE_SPINLOCK(wusb_cluster_ids_lock);
-
-/*
- * Get a WUSB Cluster ID
- *
- * Need to release with wusb_cluster_id_put() when done w/ it.
- */
-/* FIXME: coordinate with the choose_addres() from the USB stack */
-/* we want to leave the top of the 128 range for cluster addresses and
- * the bottom for device addresses (as we map them one on one with
- * ports). */
-u8 wusb_cluster_id_get(void)
-{
-       u8 id;
-       spin_lock(&wusb_cluster_ids_lock);
-       id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS);
-       if (id >= CLUSTER_IDS) {
-               id = 0;
-               goto out;
-       }
-       set_bit(id, wusb_cluster_id_table);
-       id = (u8) 0xff - id;
-out:
-       spin_unlock(&wusb_cluster_ids_lock);
-       return id;
-
-}
-EXPORT_SYMBOL_GPL(wusb_cluster_id_get);
-
-/*
- * Release a WUSB Cluster ID
- *
- * Obtained it with wusb_cluster_id_get()
- */
-void wusb_cluster_id_put(u8 id)
-{
-       id = 0xff - id;
-       BUG_ON(id >= CLUSTER_IDS);
-       spin_lock(&wusb_cluster_ids_lock);
-       WARN_ON(!test_bit(id, wusb_cluster_id_table));
-       clear_bit(id, wusb_cluster_id_table);
-       spin_unlock(&wusb_cluster_ids_lock);
-}
-EXPORT_SYMBOL_GPL(wusb_cluster_id_put);
-
-/**
- * wusbhc_giveback_urb - return an URB to the USB core
- * @wusbhc: the host controller the URB is from.
- * @urb:    the URB.
- * @status: the URB's status.
- *
- * Return an URB to the USB core doing some additional WUSB specific
- * processing.
- *
- *  - After a successful transfer, update the trust timeout timestamp
- *    for the WUSB device.
- *
- *  - [WUSB] sections 4.13 and 7.5.1 specify the stop retransmission
- *    condition for the WCONNECTACK_IE is that the host has observed
- *    the associated device responding to a control transfer.
- */
-void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status)
-{
-       struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc,
-                                       urb->dev);
-
-       if (status == 0 && wusb_dev) {
-               wusb_dev->entry_ts = jiffies;
-
-               /* wusbhc_devconnect_acked() can't be called from
-                  atomic context so defer it to a work queue. */
-               if (!list_empty(&wusb_dev->cack_node))
-                       queue_work(wusbd, &wusb_dev->devconnect_acked_work);
-               else
-                       wusb_dev_put(wusb_dev);
-       }
-
-       usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status);
-}
-EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
-
-/**
- * wusbhc_reset_all - reset the HC hardware
- * @wusbhc: the host controller to reset.
- *
- * Request a full hardware reset of the chip.  This will also reset
- * the radio controller and any other PALs.
- */
-void wusbhc_reset_all(struct wusbhc *wusbhc)
-{
-       if (wusbhc->uwb_rc)
-               uwb_rc_reset_all(wusbhc->uwb_rc);
-}
-EXPORT_SYMBOL_GPL(wusbhc_reset_all);
-
-static struct notifier_block wusb_usb_notifier = {
-       .notifier_call = wusb_usb_ncb,
-       .priority = INT_MAX     /* Need to be called first of all */
-};
-
-static int __init wusbcore_init(void)
-{
-       int result;
-       result = wusb_crypto_init();
-       if (result < 0)
-               goto error_crypto_init;
-       /* WQ is singlethread because we need to serialize notifications */
-       wusbd = create_singlethread_workqueue("wusbd");
-       if (wusbd == NULL) {
-               result = -ENOMEM;
-               printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n");
-               goto error_wusbd_create;
-       }
-       usb_register_notify(&wusb_usb_notifier);
-       bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS);
-       set_bit(0, wusb_cluster_id_table);      /* reserve Cluster ID 0xff */
-       return 0;
-
-error_wusbd_create:
-       wusb_crypto_exit();
-error_crypto_init:
-       return result;
-
-}
-module_init(wusbcore_init);
-
-static void __exit wusbcore_exit(void)
-{
-       clear_bit(0, wusb_cluster_id_table);
-       if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) {
-               printk(KERN_ERR "BUG: WUSB Cluster IDs not released on exit: %*pb\n",
-                      CLUSTER_IDS, wusb_cluster_id_table);
-               WARN_ON(1);
-       }
-       usb_unregister_notify(&wusb_usb_notifier);
-       destroy_workqueue(wusbd);
-       wusb_crypto_exit();
-}
-module_exit(wusbcore_exit);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Wireless USB core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/wusbhc.h b/drivers/staging/wusbcore/wusbhc.h
deleted file mode 100644 (file)
index 716244a..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * Common infrastructure for WHCI and HWA WUSB-HC drivers
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This driver implements parts common to all Wireless USB Host
- * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used
- * by:
- *
- *   - hwahc: HWA, USB-dongle that implements a Wireless USB host
- *     controller, (Wireless USB 1.0 Host-Wire-Adapter specification).
- *
- *   - whci: WHCI, a PCI card with a wireless host controller
- *     (Wireless Host Controller Interface 1.0 specification).
- *
- * Check out the Design-overview.txt file in the source documentation
- * for other details on the implementation.
- *
- * Main blocks:
- *
- *  rh         Root Hub emulation (part of the HCD glue)
- *
- *  devconnect Handle all the issues related to device connection,
- *             authentication, disconnection, timeout, reseting,
- *             keepalives, etc.
- *
- *  mmc        MMC IE broadcasting handling
- *
- * A host controller driver just initializes its stuff and as part of
- * that, creates a 'struct wusbhc' instance that handles all the
- * common WUSB mechanisms. Links in the function ops that are specific
- * to it and then registers the host controller. Ready to run.
- */
-
-#ifndef __WUSBHC_H__
-#define __WUSBHC_H__
-
-#include <linux/usb.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/kref.h>
-#include <linux/workqueue.h>
-#include <linux/usb/hcd.h>
-#include "../uwb/uwb.h"
-#include "include/wusb.h"
-
-/*
- * Time from a WUSB channel stop request to the last transmitted MMC.
- *
- * This needs to be > 4.096 ms in case no MMCs can be transmitted in
- * zone 0.
- */
-#define WUSB_CHANNEL_STOP_DELAY_MS 8
-#define WUSB_RETRY_COUNT_MAX 15
-#define WUSB_RETRY_COUNT_INFINITE 0
-
-/**
- * Wireless USB device
- *
- * Describe a WUSB device connected to the cluster. This struct
- * belongs to the 'struct wusb_port' it is attached to and it is
- * responsible for putting and clearing the pointer to it.
- *
- * Note this "complements" the 'struct usb_device' that the usb_hcd
- * keeps for each connected USB device. However, it extends some
- * information that is not available (there is no hcpriv ptr in it!)
- * *and* most importantly, it's life cycle is different. It is created
- * as soon as we get a DN_Connect (connect request notification) from
- * the device through the WUSB host controller; the USB stack doesn't
- * create the device until we authenticate it. FIXME: this will
- * change.
- *
- * @bos:    This is allocated when the BOS descriptors are read from
- *          the device and freed upon the wusb_dev struct dying.
- * @wusb_cap_descr: points into @bos, and has been verified to be size
- *                  safe.
- */
-struct wusb_dev {
-       struct kref refcnt;
-       struct wusbhc *wusbhc;
-       struct list_head cack_node;     /* Connect-Ack list */
-       struct list_head rekey_node;    /* GTK rekey list */
-       u8 port_idx;
-       u8 addr;
-       u8 beacon_type:4;
-       struct usb_encryption_descriptor ccm1_etd;
-       struct wusb_ckhdid cdid;
-       unsigned long entry_ts;
-       struct usb_bos_descriptor *bos;
-       struct usb_wireless_cap_descriptor *wusb_cap_descr;
-       struct uwb_mas_bm availability;
-       struct work_struct devconnect_acked_work;
-       struct usb_device *usb_dev;
-};
-
-#define WUSB_DEV_ADDR_UNAUTH 0x80
-
-static inline void wusb_dev_init(struct wusb_dev *wusb_dev)
-{
-       kref_init(&wusb_dev->refcnt);
-       /* no need to init the cack_node */
-}
-
-extern void wusb_dev_destroy(struct kref *_wusb_dev);
-
-static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev)
-{
-       kref_get(&wusb_dev->refcnt);
-       return wusb_dev;
-}
-
-static inline void wusb_dev_put(struct wusb_dev *wusb_dev)
-{
-       kref_put(&wusb_dev->refcnt, wusb_dev_destroy);
-}
-
-/**
- * Wireless USB Host Controller root hub "fake" ports
- * (state and device information)
- *
- * Wireless USB is wireless, so there are no ports; but we
- * fake'em. Each RC can connect a max of devices at the same time
- * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's
- * caps), referred to in wusbhc->ports_max.
- *
- * See rh.c for more information.
- *
- * The @status and @change use the same bits as in USB2.0[11.24.2.7],
- * so we don't have to do much when getting the port's status.
- *
- * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10],
- * include/linux/usb_ch9.h (#define USB_PORT_STAT_*)
- */
-struct wusb_port {
-       u16 status;
-       u16 change;
-       struct wusb_dev *wusb_dev;      /* connected device's info */
-       u32 ptk_tkid;
-};
-
-/**
- * WUSB Host Controller specifics
- *
- * All fields that are common to all Wireless USB controller types
- * (HWA and WHCI) are grouped here. Host Controller
- * functions/operations that only deal with general Wireless USB HC
- * issues use this data type to refer to the host.
- *
- * @usb_hcd       Instantiation of a USB host controller
- *                 (initialized by upper layer [HWA=HC or WHCI].
- *
- * @dev                   Device that implements this; initialized by the
- *                 upper layer (HWA-HC, WHCI...); this device should
- *                 have a refcount.
- *
- * @trust_timeout  After this time without hearing for device
- *                 activity, we consider the device gone and we have to
- *                 re-authenticate.
- *
- *                 Can be accessed w/o locking--however, read to a
- *                 local variable then use.
- *
- * @chid           WUSB Cluster Host ID: this is supposed to be a
- *                 unique value that doesn't change across reboots (so
- *                 that your devices do not require re-association).
- *
- *                 Read/Write protected by @mutex
- *
- * @dev_info       This array has ports_max elements. It is used to
- *                 give the HC information about the WUSB devices (see
- *                 'struct wusb_dev_info').
- *
- *                For HWA we need to allocate it in heap; for WHCI it
- *                 needs to be permanently mapped, so we keep it for
- *                 both and make it easy. Call wusbhc->dev_info_set()
- *                 to update an entry.
- *
- * @ports_max     Number of simultaneous device connections (fake
- *                 ports) this HC will take. Read-only.
- *
- * @port          Array of port status for each fake root port. Guaranteed to
- *                 always be the same length during device existence
- *                 [this allows for some unlocked but referenced reading].
- *
- * @mmcies_max    Max number of Information Elements this HC can send
- *                 in its MMC. Read-only.
- *
- * @start          Start the WUSB channel.
- *
- * @stop           Stop the WUSB channel after the specified number of
- *                 milliseconds.  Channel Stop IEs should be transmitted
- *                 as required by [WUSB] 4.16.2.1.
- *
- * @mmcie_add     HC specific operation (WHCI or HWA) for adding an
- *                 MMCIE.
- *
- * @mmcie_rm      HC specific operation (WHCI or HWA) for removing an
- *                 MMCIE.
- *
- * @set_ptk:       Set the PTK and enable encryption for a device. Or, if
- *                 the supplied key is NULL, disable encryption for that
- *                 device.
- *
- * @set_gtk:       Set the GTK to be used for all future broadcast packets
- *                 (i.e., MMCs).  With some hardware, setting the GTK may start
- *                 MMC transmission.
- *
- * NOTE:
- *
- *  - If wusb_dev->usb_dev is not NULL, then usb_dev is valid
- *    (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev
- *    is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a
- *    refcount on it).
- *
- *    Most of the times when you need to use it, it will be non-NULL,
- *    so there is no real need to check for it (wusb_dev will
- *    disappear before usb_dev).
- *
- *  - The following fields need to be filled out before calling
- *    wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}.
- *
- *  - there is no wusbhc_init() method, we do everything in
- *    wusbhc_create().
- *
- *  - Creation is done in two phases, wusbhc_create() and
- *    wusbhc_create_b(); b are the parts that need to be called after
- *    calling usb_hcd_add(&wusbhc->usb_hcd).
- */
-struct wusbhc {
-       struct usb_hcd usb_hcd;         /* HAS TO BE 1st */
-       struct device *dev;
-       struct uwb_rc *uwb_rc;
-       struct uwb_pal pal;
-
-       unsigned trust_timeout;                 /* in jiffies */
-       struct wusb_ckhdid chid;
-       uint8_t phy_rate;
-       uint8_t dnts_num_slots;
-       uint8_t dnts_interval;
-       uint8_t retry_count;
-       struct wuie_host_info *wuie_host_info;
-
-       struct mutex mutex;                     /* locks everything else */
-       u16 cluster_id;                         /* Wireless USB Cluster ID */
-       struct wusb_port *port;                 /* Fake port status handling */
-       struct wusb_dev_info *dev_info;         /* for Set Device Info mgmt */
-       u8 ports_max;
-       unsigned active:1;                      /* currently xmit'ing MMCs */
-       struct wuie_keep_alive keep_alive_ie;   /* protected by mutex */
-       struct delayed_work keep_alive_timer;
-       struct list_head cack_list;             /* Connect acknowledging */
-       size_t cack_count;                      /* protected by 'mutex' */
-       struct wuie_connect_ack cack_ie;
-       struct uwb_rsv *rsv;            /* cluster bandwidth reservation */
-
-       struct mutex mmcie_mutex;               /* MMC WUIE handling */
-       struct wuie_hdr **mmcie;                /* WUIE array */
-       u8 mmcies_max;
-       /* FIXME: make wusbhc_ops? */
-       int (*start)(struct wusbhc *wusbhc);
-       void (*stop)(struct wusbhc *wusbhc, int delay);
-       int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
-                        u8 handle, struct wuie_hdr *wuie);
-       int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle);
-       int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev);
-       int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index,
-                      const struct uwb_mas_bm *);
-       int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx,
-                      u32 tkid, const void *key, size_t key_size);
-       int (*set_gtk)(struct wusbhc *wusbhc,
-                      u32 tkid, const void *key, size_t key_size);
-       int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots);
-
-       struct {
-               struct usb_key_descriptor descr;
-               u8 data[16];                            /* GTK key data */
-       } __attribute__((packed)) gtk;
-       u8 gtk_index;
-       u32 gtk_tkid;
-
-       /* workqueue for WUSB security related tasks. */
-       struct workqueue_struct *wq_security;
-       struct work_struct gtk_rekey_work;
-
-       struct usb_encryption_descriptor *ccm1_etd;
-};
-
-#define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd)
-
-
-extern int wusbhc_create(struct wusbhc *);
-extern int wusbhc_b_create(struct wusbhc *);
-extern void wusbhc_b_destroy(struct wusbhc *);
-extern void wusbhc_destroy(struct wusbhc *);
-extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *,
-                             struct wusb_dev *);
-extern void wusb_dev_sysfs_rm(struct wusb_dev *);
-extern int wusbhc_sec_create(struct wusbhc *);
-extern int wusbhc_sec_start(struct wusbhc *);
-extern void wusbhc_sec_stop(struct wusbhc *);
-extern void wusbhc_sec_destroy(struct wusbhc *);
-extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb,
-                               int status);
-void wusbhc_reset_all(struct wusbhc *wusbhc);
-
-int wusbhc_pal_register(struct wusbhc *wusbhc);
-void wusbhc_pal_unregister(struct wusbhc *wusbhc);
-
-/*
- * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone
- *
- * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
- *
- * This is a safe assumption as @usb_dev->bus is referenced all the
- * time during the @usb_dev life cycle.
- */
-static inline
-struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev)
-{
-       struct usb_hcd *usb_hcd;
-       usb_hcd = bus_to_hcd(usb_dev->bus);
-       return usb_get_hcd(usb_hcd);
-}
-
-/*
- * Increment the reference count on a wusbhc.
- *
- * @wusbhc's life cycle is identical to that of the underlying usb_hcd.
- */
-static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc)
-{
-       return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL;
-}
-
-/*
- * Return the wusbhc associated to a @usb_dev
- *
- * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
- *
- * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down.
- *           WARNING: referenced at the usb_hcd level, unlocked
- *
- * FIXME: move offline
- */
-static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev)
-{
-       struct wusbhc *wusbhc = NULL;
-       struct usb_hcd *usb_hcd;
-       if (usb_dev->devnum > 1 && !usb_dev->wusb) {
-               /* but root hubs */
-               dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum,
-                       usb_dev->wusb);
-               BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb);
-       }
-       usb_hcd = usb_hcd_get_by_usb_dev(usb_dev);
-       if (usb_hcd == NULL)
-               return NULL;
-       BUG_ON(usb_hcd->wireless == 0);
-       return wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-}
-
-
-static inline void wusbhc_put(struct wusbhc *wusbhc)
-{
-       usb_put_hcd(&wusbhc->usb_hcd);
-}
-
-int wusbhc_start(struct wusbhc *wusbhc);
-void wusbhc_stop(struct wusbhc *wusbhc);
-extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *);
-
-/* Device connect handling */
-extern int wusbhc_devconnect_create(struct wusbhc *);
-extern void wusbhc_devconnect_destroy(struct wusbhc *);
-extern int wusbhc_devconnect_start(struct wusbhc *wusbhc);
-extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc);
-extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr,
-                            struct wusb_dn_hdr *dn_hdr, size_t size);
-extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port);
-extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
-                       void *priv);
-extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
-                            u8 addr);
-
-/* Wireless USB fake Root Hub methods */
-extern int wusbhc_rh_create(struct wusbhc *);
-extern void wusbhc_rh_destroy(struct wusbhc *);
-
-extern int wusbhc_rh_status_data(struct usb_hcd *, char *);
-extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16);
-extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned);
-
-/* MMC handling */
-extern int wusbhc_mmcie_create(struct wusbhc *);
-extern void wusbhc_mmcie_destroy(struct wusbhc *);
-extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt,
-                           struct wuie_hdr *);
-extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *);
-
-/* Bandwidth reservation */
-int wusbhc_rsv_establish(struct wusbhc *wusbhc);
-void wusbhc_rsv_terminate(struct wusbhc *wusbhc);
-
-/*
- * I've always said
- * I wanted a wedding in a church...
- *
- * but lately I've been thinking about
- * the Botanical Gardens.
- *
- * We could do it by the tulips.
- * It'll be beautiful
- *
- * --Security!
- */
-extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *,
-                               struct wusb_dev *);
-extern void wusb_dev_sec_rm(struct wusb_dev *) ;
-extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *,
-                                  struct wusb_ckhdid *ck);
-void wusbhc_gtk_rekey(struct wusbhc *wusbhc);
-int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
-
-
-/* WUSB Cluster ID handling */
-extern u8 wusb_cluster_id_get(void);
-extern void wusb_cluster_id_put(u8);
-
-/*
- * wusb_port_by_idx - return the port associated to a zero-based port index
- *
- * NOTE: valid without locking as long as wusbhc is referenced (as the
- *       number of ports doesn't change). The data pointed to has to
- *       be verified though :)
- */
-static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc,
-                                                u8 port_idx)
-{
-       return &wusbhc->port[port_idx];
-}
-
-/*
- * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to
- * a port_idx.
- *
- * USB stack USB ports are 1 based!!
- *
- * NOTE: only valid for WUSB devices!!!
- */
-static inline u8 wusb_port_no_to_idx(u8 port_no)
-{
-       return port_no - 1;
-}
-
-extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *,
-                                                 struct usb_device *);
-
-/*
- * Return a referenced wusb_dev given a @usb_dev
- *
- * Returns NULL if the usb_dev is being torn down.
- *
- * FIXME: move offline
- */
-static inline
-struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev)
-{
-       struct wusbhc *wusbhc;
-       struct wusb_dev *wusb_dev;
-       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
-       if (wusbhc == NULL)
-               return NULL;
-       mutex_lock(&wusbhc->mutex);
-       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
-       mutex_unlock(&wusbhc->mutex);
-       wusbhc_put(wusbhc);
-       return wusb_dev;
-}
-
-/* Misc */
-
-extern struct workqueue_struct *wusbd;
-#endif /* #ifndef __WUSBHC_H__ */
index 4e32b64..191f971 100644 (file)
@@ -3,6 +3,6 @@
 config AMDTEE
        tristate "AMD-TEE"
        default m
-       depends on CRYPTO_DEV_SP_PSP
+       depends on CRYPTO_DEV_SP_PSP && CRYPTO_DEV_CCP_DD
        help
          This implements AMD's Trusted Execution Environment (TEE) driver.
index 6370bb5..27b4cd7 100644 (file)
@@ -139,6 +139,9 @@ static struct amdtee_session *find_session(struct amdtee_context_data *ctxdata,
        u32 index = get_session_index(session);
        struct amdtee_session *sess;
 
+       if (index >= TEE_NUM_SESSIONS)
+               return NULL;
+
        list_for_each_entry(sess, &ctxdata->sess_list, list_node)
                if (ta_handle == sess->ta_handle &&
                    test_bit(index, sess->sess_mask))
@@ -212,6 +215,19 @@ unlock:
        return rc;
 }
 
+static void destroy_session(struct kref *ref)
+{
+       struct amdtee_session *sess = container_of(ref, struct amdtee_session,
+                                                  refcount);
+
+       /* Unload the TA from TEE */
+       handle_unload_ta(sess->ta_handle);
+       mutex_lock(&session_list_mutex);
+       list_del(&sess->list_node);
+       mutex_unlock(&session_list_mutex);
+       kfree(sess);
+}
+
 int amdtee_open_session(struct tee_context *ctx,
                        struct tee_ioctl_open_session_arg *arg,
                        struct tee_param *param)
@@ -236,15 +252,13 @@ int amdtee_open_session(struct tee_context *ctx,
 
        /* Load the TA binary into TEE environment */
        handle_load_ta(ta, ta_size, arg);
-       if (arg->ret == TEEC_SUCCESS) {
-               mutex_lock(&session_list_mutex);
-               sess = alloc_session(ctxdata, arg->session);
-               mutex_unlock(&session_list_mutex);
-       }
-
        if (arg->ret != TEEC_SUCCESS)
                goto out;
 
+       mutex_lock(&session_list_mutex);
+       sess = alloc_session(ctxdata, arg->session);
+       mutex_unlock(&session_list_mutex);
+
        if (!sess) {
                rc = -ENOMEM;
                goto out;
@@ -259,40 +273,29 @@ int amdtee_open_session(struct tee_context *ctx,
 
        if (i >= TEE_NUM_SESSIONS) {
                pr_err("reached maximum session count %d\n", TEE_NUM_SESSIONS);
+               kref_put(&sess->refcount, destroy_session);
                rc = -ENOMEM;
                goto out;
        }
 
        /* Open session with loaded TA */
        handle_open_session(arg, &session_info, param);
-
-       if (arg->ret == TEEC_SUCCESS) {
-               sess->session_info[i] = session_info;
-               set_session_id(sess->ta_handle, i, &arg->session);
-       } else {
+       if (arg->ret != TEEC_SUCCESS) {
                pr_err("open_session failed %d\n", arg->ret);
                spin_lock(&sess->lock);
                clear_bit(i, sess->sess_mask);
                spin_unlock(&sess->lock);
+               kref_put(&sess->refcount, destroy_session);
+               goto out;
        }
+
+       sess->session_info[i] = session_info;
+       set_session_id(sess->ta_handle, i, &arg->session);
 out:
        free_pages((u64)ta, get_order(ta_size));
        return rc;
 }
 
-static void destroy_session(struct kref *ref)
-{
-       struct amdtee_session *sess = container_of(ref, struct amdtee_session,
-                                                  refcount);
-
-       /* Unload the TA from TEE */
-       handle_unload_ta(sess->ta_handle);
-       mutex_lock(&session_list_mutex);
-       list_del(&sess->list_node);
-       mutex_unlock(&session_list_mutex);
-       kfree(sess);
-}
-
 int amdtee_close_session(struct tee_context *ctx, u32 session)
 {
        struct amdtee_context_data *ctxdata = ctx->data;
index fe83d7a..4ae8c85 100644 (file)
@@ -431,6 +431,10 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
                                 unsigned long state)
 {
        struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
+       struct cpumask *cpus;
+       unsigned int frequency;
+       unsigned long max_capacity, capacity;
+       int ret;
 
        /* Request state should be less than max_level */
        if (WARN_ON(state > cpufreq_cdev->max_level))
@@ -442,8 +446,19 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
 
        cpufreq_cdev->cpufreq_state = state;
 
-       return freq_qos_update_request(&cpufreq_cdev->qos_req,
-                               get_state_freq(cpufreq_cdev, state));
+       frequency = get_state_freq(cpufreq_cdev, state);
+
+       ret = freq_qos_update_request(&cpufreq_cdev->qos_req, frequency);
+
+       if (ret > 0) {
+               cpus = cpufreq_cdev->policy->cpus;
+               max_capacity = arch_scale_cpu_capacity(cpumask_first(cpus));
+               capacity = frequency * max_capacity;
+               capacity /= cpufreq_cdev->policy->cpuinfo.max_freq;
+               arch_set_thermal_pressure(cpus, max_capacity - capacity);
+       }
+
+       return ret;
 }
 
 /* Bind cpufreq callbacks to thermal cooling device ops */
index 7130e90..a478cff 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/acpi.h>
 #include <linux/uaccess.h>
 #include <linux/miscdevice.h>
+#include <linux/fs.h>
 #include "acpi_thermal_rel.h"
 
 static acpi_handle acpi_thermal_rel_handle;
index 53216dc..f74b247 100644 (file)
@@ -651,7 +651,7 @@ static struct thermal_cooling_device_ops powerclamp_cooling_ops = {
 };
 
 static const struct x86_cpu_id __initconst intel_powerclamp_ids[] = {
-       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_MWAIT },
+       X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_MWAIT, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids);
index 5d33b35..d704fc1 100644 (file)
@@ -64,9 +64,6 @@
 #include <asm/cpu_device_id.h>
 #include <asm/iosf_mbi.h>
 
-#define X86_FAMILY_QUARK       0x5
-#define X86_MODEL_QUARK_X1000  0x9
-
 /* DTS reset is programmed via QRK_MBI_UNIT_SOC */
 #define QRK_DTS_REG_OFFSET_RESET       0x34
 #define QRK_DTS_RESET_BIT              BIT(0)
@@ -433,7 +430,7 @@ err_ret:
 }
 
 static const struct x86_cpu_id qrk_thermal_ids[] __initconst  = {
-       { X86_VENDOR_INTEL, X86_FAMILY_QUARK, X86_MODEL_QUARK_X1000 },
+       X86_MATCH_VENDOR_FAM_MODEL(INTEL, 5, INTEL_FAM5_QUARK_X1000, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, qrk_thermal_ids);
index f4be9c1..92e5c19 100644 (file)
@@ -36,8 +36,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data)
 }
 
 static const struct x86_cpu_id soc_thermal_ids[] = {
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT, 0,
-               BYT_SOC_DTS_APIC_IRQ},
+       X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, BYT_SOC_DTS_APIC_IRQ),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids);
index ddb4a97..a006b9f 100644 (file)
@@ -63,7 +63,7 @@ static int max_id __read_mostly;
 /* Array of zone pointers */
 static struct zone_device **zones;
 /* Serializes interrupt notification, work and hotplug */
-static DEFINE_SPINLOCK(pkg_temp_lock);
+static DEFINE_RAW_SPINLOCK(pkg_temp_lock);
 /* Protects zone operation in the work function against hotplug removal */
 static DEFINE_MUTEX(thermal_zone_mutex);
 
@@ -266,12 +266,12 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
        u64 msr_val, wr_val;
 
        mutex_lock(&thermal_zone_mutex);
-       spin_lock_irq(&pkg_temp_lock);
+       raw_spin_lock_irq(&pkg_temp_lock);
        ++pkg_work_cnt;
 
        zonedev = pkg_temp_thermal_get_dev(cpu);
        if (!zonedev) {
-               spin_unlock_irq(&pkg_temp_lock);
+               raw_spin_unlock_irq(&pkg_temp_lock);
                mutex_unlock(&thermal_zone_mutex);
                return;
        }
@@ -285,7 +285,7 @@ static void pkg_temp_thermal_threshold_work_fn(struct work_struct *work)
        }
 
        enable_pkg_thres_interrupt();
-       spin_unlock_irq(&pkg_temp_lock);
+       raw_spin_unlock_irq(&pkg_temp_lock);
 
        /*
         * If tzone is not NULL, then thermal_zone_mutex will prevent the
@@ -310,7 +310,7 @@ static int pkg_thermal_notify(u64 msr_val)
        struct zone_device *zonedev;
        unsigned long flags;
 
-       spin_lock_irqsave(&pkg_temp_lock, flags);
+       raw_spin_lock_irqsave(&pkg_temp_lock, flags);
        ++pkg_interrupt_cnt;
 
        disable_pkg_thres_interrupt();
@@ -322,7 +322,7 @@ static int pkg_thermal_notify(u64 msr_val)
                pkg_thermal_schedule_work(zonedev->cpu, &zonedev->work);
        }
 
-       spin_unlock_irqrestore(&pkg_temp_lock, flags);
+       raw_spin_unlock_irqrestore(&pkg_temp_lock, flags);
        return 0;
 }
 
@@ -368,9 +368,9 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
              zonedev->msr_pkg_therm_high);
 
        cpumask_set_cpu(cpu, &zonedev->cpumask);
-       spin_lock_irq(&pkg_temp_lock);
+       raw_spin_lock_irq(&pkg_temp_lock);
        zones[id] = zonedev;
-       spin_unlock_irq(&pkg_temp_lock);
+       raw_spin_unlock_irq(&pkg_temp_lock);
        return 0;
 }
 
@@ -407,7 +407,7 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
        }
 
        /* Protect against work and interrupts */
-       spin_lock_irq(&pkg_temp_lock);
+       raw_spin_lock_irq(&pkg_temp_lock);
 
        /*
         * Check whether this cpu was the current target and store the new
@@ -439,9 +439,9 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
                 * To cancel the work we need to drop the lock, otherwise
                 * we might deadlock if the work needs to be flushed.
                 */
-               spin_unlock_irq(&pkg_temp_lock);
+               raw_spin_unlock_irq(&pkg_temp_lock);
                cancel_delayed_work_sync(&zonedev->work);
-               spin_lock_irq(&pkg_temp_lock);
+               raw_spin_lock_irq(&pkg_temp_lock);
                /*
                 * If this is not the last cpu in the package and the work
                 * did not run after we dropped the lock above, then we
@@ -452,7 +452,7 @@ static int pkg_thermal_cpu_offline(unsigned int cpu)
                        pkg_thermal_schedule_work(target, &zonedev->work);
        }
 
-       spin_unlock_irq(&pkg_temp_lock);
+       raw_spin_unlock_irq(&pkg_temp_lock);
 
        /* Final cleanup if this is the last cpu */
        if (lastcpu)
@@ -478,7 +478,7 @@ static int pkg_thermal_cpu_online(unsigned int cpu)
 }
 
 static const struct x86_cpu_id __initconst pkg_temp_thermal_ids[] = {
-       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_PTS },
+       X86_MATCH_VENDOR_FEATURE(INTEL, X86_FEATURE_PTS, NULL),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, pkg_temp_thermal_ids);
index b7980c8..68c1b93 100644 (file)
@@ -147,10 +147,10 @@ static ssize_t boot_acl_show(struct device *dev, struct device_attribute *attr,
 
        for (ret = 0, i = 0; i < tb->nboot_acl; i++) {
                if (!uuid_is_null(&uuids[i]))
-                       ret += snprintf(buf + ret, PAGE_SIZE - ret, "%pUb",
+                       ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%pUb",
                                        &uuids[i]);
 
-               ret += snprintf(buf + ret, PAGE_SIZE - ret, "%s",
+               ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s",
                               i < tb->nboot_acl - 1 ? "," : "\n");
        }
 
index 921d164..b451a5a 100644 (file)
@@ -247,7 +247,7 @@ struct tb_drom_entry_header {
 
 struct tb_drom_entry_generic {
        struct tb_drom_entry_header header;
-       u8 data[0];
+       u8 data[];
 } __packed;
 
 struct tb_drom_entry_port {
index 13e8810..fbbe32c 100644 (file)
@@ -114,7 +114,7 @@ struct icm_notification {
 struct ep_name_entry {
        u8 len;
        u8 type;
-       u8 data[0];
+       u8 data[];
 };
 
 #define EP_NAME_INTEL_VSS      0x10
index 7d6ecc3..a2ce990 100644 (file)
@@ -954,7 +954,7 @@ static bool tb_port_is_width_supported(struct tb_port *port, int width)
        ret = tb_port_read(port, &phy, TB_CFG_PORT,
                           port->cap_phy + LANE_ADP_CS_0, 1);
        if (ret)
-               return ret;
+               return false;
 
        widths = (phy & LANE_ADP_CS_0_SUPPORTED_WIDTH_MASK) >>
                LANE_ADP_CS_0_SUPPORTED_WIDTH_SHIFT;
index b341fc6..3d084ce 100644 (file)
@@ -259,6 +259,7 @@ int usb4_switch_setup(struct tb_switch *sw)
 /**
  * usb4_switch_read_uid() - Read UID from USB4 router
  * @sw: USB4 router
+ * @uid: UID is stored here
  *
  * Reads 64-bit UID from USB4 router config space.
  */
@@ -296,6 +297,9 @@ static int usb4_switch_drom_read_block(struct tb_switch *sw,
 /**
  * usb4_switch_drom_read() - Read arbitrary bytes from USB4 router DROM
  * @sw: USB4 router
+ * @address: Byte address inside DROM to start reading
+ * @buf: Buffer where the DROM content is stored
+ * @size: Number of bytes to read from DROM
  *
  * Uses USB4 router operations to read router DROM. For devices this
  * should always work but for hosts it may return %-EOPNOTSUPP in which
index 42345e7..c5f0d93 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sched.h>
 #include <linux/serdev.h>
 #include <linux/slab.h>
+#include <linux/platform_data/x86/apple.h>
 
 static bool is_registered;
 static DEFINE_IDA(ctrl_ida);
@@ -631,6 +632,15 @@ static int acpi_serdev_check_resources(struct serdev_controller *ctrl,
        if (ret)
                return ret;
 
+       /*
+        * Apple machines provide an empty resource template, so on those
+        * machines just look for immediate children with a "baud" property
+        * (from the _DSM method) instead.
+        */
+       if (!lookup.controller_handle && x86_apple_machine &&
+           !acpi_dev_get_property(adev, "baud", ACPI_TYPE_BUFFER, NULL))
+               acpi_get_parent(adev->handle, &lookup.controller_handle);
+
        /* Make sure controller and ResourceSource handle match */
        if (ACPI_HANDLE(ctrl->dev.parent) != lookup.controller_handle)
                return -ENODEV;
index 91e9b07..d330da7 100644 (file)
 
 #include "8250.h"
 
+#define PCI_DEVICE_ID_ACCES_COM_2S             0x1052
+#define PCI_DEVICE_ID_ACCES_COM_4S             0x105d
+#define PCI_DEVICE_ID_ACCES_COM_8S             0x106c
+#define PCI_DEVICE_ID_ACCES_COM232_8           0x10a8
+#define PCI_DEVICE_ID_ACCES_COM_2SM            0x10d2
+#define PCI_DEVICE_ID_ACCES_COM_4SM            0x10db
+#define PCI_DEVICE_ID_ACCES_COM_8SM            0x10ea
+
 #define PCI_DEVICE_ID_COMMTECH_4224PCI335      0x0002
 #define PCI_DEVICE_ID_COMMTECH_4222PCI335      0x0004
 #define PCI_DEVICE_ID_COMMTECH_2324PCI335      0x000a
@@ -677,6 +685,22 @@ static int __maybe_unused exar_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(exar_pci_pm, exar_suspend, exar_resume);
 
+static const struct exar8250_board acces_com_2x = {
+       .num_ports      = 2,
+       .setup          = pci_xr17c154_setup,
+};
+
+static const struct exar8250_board acces_com_4x = {
+       .num_ports      = 4,
+       .setup          = pci_xr17c154_setup,
+};
+
+static const struct exar8250_board acces_com_8x = {
+       .num_ports      = 8,
+       .setup          = pci_xr17c154_setup,
+};
+
+
 static const struct exar8250_board pbn_fastcom335_2 = {
        .num_ports      = 2,
        .setup          = pci_fastcom335_setup,
@@ -745,6 +769,15 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
        }
 
 static const struct pci_device_id exar_pci_tbl[] = {
+       EXAR_DEVICE(ACCESSIO, ACCES_COM_2S, acces_com_2x),
+       EXAR_DEVICE(ACCESSIO, ACCES_COM_4S, acces_com_4x),
+       EXAR_DEVICE(ACCESSIO, ACCES_COM_8S, acces_com_8x),
+       EXAR_DEVICE(ACCESSIO, ACCES_COM232_8, acces_com_8x),
+       EXAR_DEVICE(ACCESSIO, ACCES_COM_2SM, acces_com_2x),
+       EXAR_DEVICE(ACCESSIO, ACCES_COM_4SM, acces_com_4x),
+       EXAR_DEVICE(ACCESSIO, ACCES_COM_8SM, acces_com_8x),
+
+
        CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect),
        CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect),
        CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect),
index 6f343ca..76fe72b 100644 (file)
@@ -569,7 +569,7 @@ static void omap8250_uart_qos_work(struct work_struct *work)
        struct omap8250_priv *priv;
 
        priv = container_of(work, struct omap8250_priv, qos_work);
-       pm_qos_update_request(&priv->pm_qos_request, priv->latency);
+       cpu_latency_qos_update_request(&priv->pm_qos_request, priv->latency);
 }
 
 #ifdef CONFIG_SERIAL_8250_DMA
@@ -1222,10 +1222,9 @@ static int omap8250_probe(struct platform_device *pdev)
                         DEFAULT_CLK_SPEED);
        }
 
-       priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
-       priv->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
-       pm_qos_add_request(&priv->pm_qos_request, PM_QOS_CPU_DMA_LATENCY,
-                          priv->latency);
+       priv->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
+       priv->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
+       cpu_latency_qos_add_request(&priv->pm_qos_request, priv->latency);
        INIT_WORK(&priv->qos_work, omap8250_uart_qos_work);
 
        spin_lock_init(&priv->rx_dma_lock);
@@ -1295,7 +1294,7 @@ static int omap8250_remove(struct platform_device *pdev)
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        serial8250_unregister_port(priv->line);
-       pm_qos_remove_request(&priv->pm_qos_request);
+       cpu_latency_qos_remove_request(&priv->pm_qos_request);
        device_init_wakeup(&pdev->dev, false);
        return 0;
 }
@@ -1445,7 +1444,7 @@ static int omap8250_runtime_suspend(struct device *dev)
        if (up->dma && up->dma->rxchan)
                omap_8250_rx_dma_flush(up);
 
-       priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
+       priv->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
        schedule_work(&priv->qos_work);
 
        return 0;
index 91e2805..c31b8f3 100644 (file)
@@ -264,6 +264,7 @@ struct lpuart_port {
        int                     rx_dma_rng_buf_len;
        unsigned int            dma_tx_nents;
        wait_queue_head_t       dma_wait;
+       bool                    id_allocated;
 };
 
 struct lpuart_soc_data {
@@ -2390,6 +2391,8 @@ static int __init lpuart32_imx_early_console_setup(struct earlycon_device *devic
 OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
 OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
 OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
+EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
+EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
 
 #define LPUART_CONSOLE (&lpuart_console)
 #define LPUART32_CONSOLE       (&lpuart32_console)
@@ -2420,19 +2423,6 @@ static int lpuart_probe(struct platform_device *pdev)
        if (!sport)
                return -ENOMEM;
 
-       ret = of_alias_get_id(np, "serial");
-       if (ret < 0) {
-               ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL);
-               if (ret < 0) {
-                       dev_err(&pdev->dev, "port line is full, add device failed\n");
-                       return ret;
-               }
-       }
-       if (ret >= ARRAY_SIZE(lpuart_ports)) {
-               dev_err(&pdev->dev, "serial%d out of range\n", ret);
-               return -EINVAL;
-       }
-       sport->port.line = ret;
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(sport->port.membase))
@@ -2477,9 +2467,25 @@ static int lpuart_probe(struct platform_device *pdev)
                }
        }
 
+       ret = of_alias_get_id(np, "serial");
+       if (ret < 0) {
+               ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "port line is full, add device failed\n");
+                       return ret;
+               }
+               sport->id_allocated = true;
+       }
+       if (ret >= ARRAY_SIZE(lpuart_ports)) {
+               dev_err(&pdev->dev, "serial%d out of range\n", ret);
+               ret = -EINVAL;
+               goto failed_out_of_range;
+       }
+       sport->port.line = ret;
+
        ret = lpuart_enable_clks(sport);
        if (ret)
-               return ret;
+               goto failed_clock_enable;
        sport->port.uartclk = lpuart_get_baud_clk_rate(sport);
 
        lpuart_ports[sport->port.line] = sport;
@@ -2529,6 +2535,10 @@ static int lpuart_probe(struct platform_device *pdev)
 failed_attach_port:
 failed_irq_request:
        lpuart_disable_clks(sport);
+failed_clock_enable:
+failed_out_of_range:
+       if (sport->id_allocated)
+               ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
        return ret;
 }
 
@@ -2538,7 +2548,8 @@ static int lpuart_remove(struct platform_device *pdev)
 
        uart_remove_one_port(&lpuart_reg, &sport->port);
 
-       ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
+       if (sport->id_allocated)
+               ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
 
        lpuart_disable_clks(sport);
 
index c12a125..4e9a590 100644 (file)
@@ -851,7 +851,7 @@ static int mvebu_uart_probe(struct platform_device *pdev)
 
        port->membase = devm_ioremap_resource(&pdev->dev, reg);
        if (IS_ERR(port->membase))
-               return -PTR_ERR(port->membase);
+               return PTR_ERR(port->membase);
 
        mvuart = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_uart),
                              GFP_KERNEL);
index 48017ce..e0b720a 100644 (file)
@@ -831,7 +831,7 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
        struct uart_omap_port *up = container_of(work, struct uart_omap_port,
                                                qos_work);
 
-       pm_qos_update_request(&up->pm_qos_request, up->latency);
+       cpu_latency_qos_update_request(&up->pm_qos_request, up->latency);
 }
 
 static void
@@ -1722,10 +1722,9 @@ static int serial_omap_probe(struct platform_device *pdev)
                         DEFAULT_CLK_SPEED);
        }
 
-       up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
-       up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
-       pm_qos_add_request(&up->pm_qos_request,
-               PM_QOS_CPU_DMA_LATENCY, up->latency);
+       up->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
+       up->calc_latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
+       cpu_latency_qos_add_request(&up->pm_qos_request, up->latency);
        INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
 
        platform_set_drvdata(pdev, up);
@@ -1759,7 +1758,7 @@ err_add_port:
        pm_runtime_dont_use_autosuspend(&pdev->dev);
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       pm_qos_remove_request(&up->pm_qos_request);
+       cpu_latency_qos_remove_request(&up->pm_qos_request);
        device_init_wakeup(up->dev, false);
 err_rs485:
 err_port_line:
@@ -1777,7 +1776,7 @@ static int serial_omap_remove(struct platform_device *dev)
        pm_runtime_dont_use_autosuspend(up->dev);
        pm_runtime_put_sync(up->dev);
        pm_runtime_disable(up->dev);
-       pm_qos_remove_request(&up->pm_qos_request);
+       cpu_latency_qos_remove_request(&up->pm_qos_request);
        device_init_wakeup(&dev->dev, false);
 
        return 0;
@@ -1869,7 +1868,7 @@ static int serial_omap_runtime_suspend(struct device *dev)
 
        serial_omap_enable_wakeup(up, true);
 
-       up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
+       up->latency = PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
        schedule_work(&up->qos_work);
 
        return 0;
index a1453fe..5a6f36b 100644 (file)
@@ -1589,9 +1589,7 @@ void tty_kclose(struct tty_struct *tty)
        tty_debug_hangup(tty, "freeing structure\n");
        /*
         * The release_tty function takes care of the details of clearing
-        * the slots and preserving the termios structure. The tty_unlock_pair
-        * should be safe as we keep a kref while the tty is locked (so the
-        * unlock never unlocks a freed tty).
+        * the slots and preserving the termios structure.
         */
        mutex_lock(&tty_mutex);
        tty_port_set_kopened(tty->port, 0);
@@ -1621,9 +1619,7 @@ void tty_release_struct(struct tty_struct *tty, int idx)
        tty_debug_hangup(tty, "freeing structure\n");
        /*
         * The release_tty function takes care of the details of clearing
-        * the slots and preserving the termios structure. The tty_unlock_pair
-        * should be safe as we keep a kref while the tty is locked (so the
-        * unlock never unlocks a freed tty).
+        * the slots and preserving the termios structure.
         */
        mutex_lock(&tty_mutex);
        release_tty(tty, idx);
@@ -2734,9 +2730,11 @@ static int compat_tty_tiocgserial(struct tty_struct *tty,
        struct serial_struct32 v32;
        struct serial_struct v;
        int err;
-       memset(&v, 0, sizeof(struct serial_struct));
 
-       if (!tty->ops->set_serial)
+       memset(&v, 0, sizeof(v));
+       memset(&v32, 0, sizeof(v32));
+
+       if (!tty->ops->get_serial)
                return -ENOTTY;
        err = tty->ops->get_serial(tty, &v);
        if (!err) {
index 0c50d74..d7d2e4b 100644 (file)
@@ -181,7 +181,7 @@ int set_selection_user(const struct tiocl_selection __user *sel,
        return set_selection_kernel(&v, tty);
 }
 
-int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
+static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
 {
        struct vc_data *vc = vc_cons[fg_console].d;
        int new_sel_start, new_sel_end, spc;
@@ -214,7 +214,6 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
        if (ps > pe)    /* make sel_start <= sel_end */
                swap(ps, pe);
 
-       mutex_lock(&sel_lock);
        if (sel_cons != vc_cons[fg_console].d) {
                clear_selection();
                sel_cons = vc_cons[fg_console].d;
@@ -260,10 +259,9 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
                        break;
                case TIOCL_SELPOINTER:
                        highlight_pointer(pe);
-                       goto unlock;
+                       return 0;
                default:
-                       ret = -EINVAL;
-                       goto unlock;
+                       return -EINVAL;
        }
 
        /* remove the pointer */
@@ -285,7 +283,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
        else if (new_sel_start == sel_start)
        {
                if (new_sel_end == sel_end)     /* no action required */
-                       goto unlock;
+                       return 0;
                else if (new_sel_end > sel_end) /* extend to right */
                        highlight(sel_end + 2, new_sel_end);
                else                            /* contract from right */
@@ -313,8 +311,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
        if (!bp) {
                printk(KERN_WARNING "selection: kmalloc() failed\n");
                clear_selection();
-               ret = -ENOMEM;
-               goto unlock;
+               return -ENOMEM;
        }
        kfree(sel_buffer);
        sel_buffer = bp;
@@ -339,8 +336,20 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
                }
        }
        sel_buffer_lth = bp - sel_buffer;
-unlock:
+
+       return ret;
+}
+
+int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty)
+{
+       int ret;
+
+       mutex_lock(&sel_lock);
+       console_lock();
+       ret = __set_selection_kernel(v, tty);
+       console_unlock();
        mutex_unlock(&sel_lock);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(set_selection_kernel);
index 0cfbb71..15d2769 100644 (file)
@@ -3046,10 +3046,8 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
        switch (type)
        {
                case TIOCL_SETSEL:
-                       console_lock();
                        ret = set_selection_user((struct tiocl_selection
                                                 __user *)(p+1), tty);
-                       console_unlock();
                        break;
                case TIOCL_PASTESEL:
                        ret = paste_selection(tty);
index 635cf04..e9fed9a 100644 (file)
@@ -350,7 +350,7 @@ struct l1_code {
        u8 string_header[E4_L1_STRING_HEADER];
        u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
        struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
-       u8 code[0];
+       u8 code[];
 } __packed;
 
 /* structures describing a block within a DSP page */
index d3bdc4c..d96658e 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 /******************************************************************************
  *  usbatm.h - Generic USB xDSL driver core
  *
@@ -164,7 +164,7 @@ struct usbatm_data {
        unsigned char *cell_buf;        /* holds partial rx cell */
        unsigned int buf_usage;
 
-       struct urb *urbs[0];
+       struct urb *urbs[];
 };
 
 static inline void *to_usbatm_driver_data(struct usb_interface *intf)
index 3b181d4..6b6b04a 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * c67x00-hcd.h: Cypress C67X00 USB HCD
  *
index 7ce1092..a4456d0 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * c67x00.h: Cypress C67X00 USB register and field definitions
  *
index b0a29ef..deeea61 100644 (file)
@@ -201,4 +201,4 @@ MODULE_DEVICE_TABLE(pci, cdns3_pci_ids);
 
 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
 MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Cadence USBSS PCI wrapperr");
+MODULE_DESCRIPTION("Cadence USBSS PCI wrapper");
index c6a79ca..5685ba1 100644 (file)
@@ -52,8 +52,8 @@ enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
 struct cdns_ti {
        struct device *dev;
        void __iomem *usbss;
-       int usb2_only:1;
-       int vbus_divider:1;
+       unsigned usb2_only:1;
+       unsigned vbus_divider:1;
        struct clk *usb2_refclk;
        struct clk *lpm_clk;
 };
index c2123ef..4aafba2 100644 (file)
@@ -330,9 +330,9 @@ exit:
  *
  * Returns role
  */
-static enum usb_role cdns3_role_get(struct device *dev)
+static enum usb_role cdns3_role_get(struct usb_role_switch *sw)
 {
-       struct cdns3 *cdns = dev_get_drvdata(dev);
+       struct cdns3 *cdns = usb_role_switch_get_drvdata(sw);
 
        return cdns->role;
 }
@@ -346,9 +346,9 @@ static enum usb_role cdns3_role_get(struct device *dev)
  * - Role switch for dual-role devices
  * - USB_ROLE_GADGET <--> USB_ROLE_NONE for peripheral-only devices
  */
-static int cdns3_role_set(struct device *dev, enum usb_role role)
+static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role)
 {
-       struct cdns3 *cdns = dev_get_drvdata(dev);
+       struct cdns3 *cdns = usb_role_switch_get_drvdata(sw);
        int ret = 0;
 
        pm_runtime_get_sync(cdns->dev);
@@ -423,12 +423,6 @@ pm_put:
        return ret;
 }
 
-static const struct usb_role_switch_desc cdns3_switch_desc = {
-       .set = cdns3_role_set,
-       .get = cdns3_role_get,
-       .allow_userspace_control = true,
-};
-
 /**
  * cdns3_probe - probe for cdns3 core device
  * @pdev: Pointer to cdns3 core platform device
@@ -437,6 +431,7 @@ static const struct usb_role_switch_desc cdns3_switch_desc = {
  */
 static int cdns3_probe(struct platform_device *pdev)
 {
+       struct usb_role_switch_desc sw_desc = { };
        struct device *dev = &pdev->dev;
        struct resource *res;
        struct cdns3 *cdns;
@@ -529,7 +524,12 @@ static int cdns3_probe(struct platform_device *pdev)
        if (ret)
                goto err3;
 
-       cdns->role_sw = usb_role_switch_register(dev, &cdns3_switch_desc);
+       sw_desc.set = cdns3_role_set;
+       sw_desc.get = cdns3_role_get;
+       sw_desc.allow_userspace_control = true;
+       sw_desc.driver_data = cdns;
+
+       cdns->role_sw = usb_role_switch_register(dev, &sw_desc);
        if (IS_ERR(cdns->role_sw)) {
                ret = PTR_ERR(cdns->role_sw);
                dev_warn(dev, "Unable to register Role Switch\n");
index 736b0c6..372460e 100644 (file)
@@ -1380,7 +1380,7 @@ static bool cdns3_request_handled(struct cdns3_endpoint *priv_ep,
                                  struct cdns3_request *priv_req)
 {
        struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
-       struct cdns3_trb *trb = priv_req->trb;
+       struct cdns3_trb *trb;
        int current_index = 0;
        int handled = 0;
        int doorbell;
@@ -2550,7 +2550,7 @@ found:
        /* Update ring only if removed request is on pending_req_list list */
        if (req_on_hw_ring) {
                link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma +
-                                             (priv_req->start_trb * TRB_SIZE));
+                       ((priv_req->end_trb + 1) * TRB_SIZE));
                link_trb->control = (link_trb->control & TRB_CYCLE) |
                                    TRB_TYPE(TRB_LINK) | TRB_CHAIN;
 
@@ -2595,11 +2595,21 @@ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep)
 {
        struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
        struct usb_request *request;
+       struct cdns3_request *priv_req;
+       struct cdns3_trb *trb = NULL;
        int ret;
        int val;
 
        trace_cdns3_halt(priv_ep, 0, 0);
 
+       request = cdns3_next_request(&priv_ep->pending_req_list);
+       if (request) {
+               priv_req = to_cdns3_request(request);
+               trb = priv_req->trb;
+               if (trb)
+                       trb->control = trb->control ^ TRB_CYCLE;
+       }
+
        writel(EP_CMD_CSTALL | EP_CMD_EPRST, &priv_dev->regs->ep_cmd);
 
        /* wait for EPRST cleared */
@@ -2610,10 +2620,11 @@ int __cdns3_gadget_ep_clear_halt(struct cdns3_endpoint *priv_ep)
 
        priv_ep->flags &= ~(EP_STALLED | EP_STALL_PENDING);
 
-       request = cdns3_next_request(&priv_ep->pending_req_list);
-
-       if (request)
+       if (request) {
+               if (trb)
+                       trb->control = trb->control ^ TRB_CYCLE;
                cdns3_rearm_transfer(priv_ep, 1);
+       }
 
        cdns3_start_all_request(priv_dev, priv_ep);
        return ret;
index f003a78..52765b0 100644 (file)
@@ -1199,7 +1199,7 @@ struct cdns3_aligned_buf {
        void                    *buf;
        dma_addr_t              dma;
        u32                     size;
-       int                     in_use:1;
+       unsigned                in_use:1;
        struct list_head        list;
 };
 
@@ -1308,8 +1308,8 @@ struct cdns3_device {
        unsigned                        u2_allowed:1;
        unsigned                        is_selfpowered:1;
        unsigned                        setup_pending:1;
-       int                             hw_configured_flag:1;
-       int                             wake_up_flag:1;
+       unsigned                        hw_configured_flag:1;
+       unsigned                        wake_up_flag:1;
        unsigned                        status_completion_no_call:1;
        unsigned                        using_streams:1;
        int                             out_mem_is_allocated;
index 98da995..b1540ce 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * bits.h - register bits of the ChipIdea USB IP core
  *
index d49d5e1..644ecae 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * ci.h - common structures, functions, and macros of the ChipIdea driver
  *
index d8e7eb2..a479af3 100644 (file)
@@ -393,8 +393,7 @@ 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);
+               cpu_latency_qos_add_request(&data->pm_qos_req, 0);
 
        ret = imx_get_clks(dev);
        if (ret)
@@ -478,7 +477,7 @@ disable_hsic_regulator:
                /* don't overwrite original ret (cf. EPROBE_DEFER) */
                regulator_disable(data->hsic_pad_regulator);
        if (pdata.flags & CI_HDRC_PMQOS)
-               pm_qos_remove_request(&data->pm_qos_req);
+               cpu_latency_qos_remove_request(&data->pm_qos_req);
        data->ci_pdev = NULL;
        return ret;
 }
@@ -499,7 +498,7 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
        if (data->ci_pdev) {
                imx_disable_unprepare_clks(&pdev->dev);
                if (data->plat_data->flags & CI_HDRC_PMQOS)
-                       pm_qos_remove_request(&data->pm_qos_req);
+                       cpu_latency_qos_remove_request(&data->pm_qos_req);
                if (data->hsic_pad_regulator)
                        regulator_disable(data->hsic_pad_regulator);
        }
@@ -527,7 +526,7 @@ 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);
+               cpu_latency_qos_remove_request(&data->pm_qos_req);
 
        data->in_lpm = true;
 
@@ -547,8 +546,7 @@ static int __maybe_unused imx_controller_resume(struct device *dev)
        }
 
        if (data->plat_data->flags & CI_HDRC_PMQOS)
-               pm_qos_add_request(&data->pm_qos_req,
-                       PM_QOS_CPU_DMA_LATENCY, 0);
+               cpu_latency_qos_add_request(&data->pm_qos_req, 0);
 
        ret = imx_prepare_enable_clks(dev);
        if (ret)
index de2aac9..c2051ae 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright 2012 Freescale Semiconductor, Inc.
  */
index 52139c2..ae0bdc0 100644 (file)
@@ -600,9 +600,9 @@ static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
        return NOTIFY_DONE;
 }
 
-static enum usb_role ci_usb_role_switch_get(struct device *dev)
+static enum usb_role ci_usb_role_switch_get(struct usb_role_switch *sw)
 {
-       struct ci_hdrc *ci = dev_get_drvdata(dev);
+       struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw);
        enum usb_role role;
        unsigned long flags;
 
@@ -613,9 +613,10 @@ static enum usb_role ci_usb_role_switch_get(struct device *dev)
        return role;
 }
 
-static int ci_usb_role_switch_set(struct device *dev, enum usb_role role)
+static int ci_usb_role_switch_set(struct usb_role_switch *sw,
+                                 enum usb_role role)
 {
-       struct ci_hdrc *ci = dev_get_drvdata(dev);
+       struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw);
        struct ci_hdrc_cable *cable = NULL;
        enum usb_role current_role = ci_role_to_usb_role(ci);
        enum ci_role ci_role = usb_role_to_ci_role(role);
@@ -1118,6 +1119,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
        }
 
        if (ci_role_switch.fwnode) {
+               ci_role_switch.driver_data = ci;
                ci->role_switch = usb_role_switch_register(dev,
                                        &ci_role_switch);
                if (IS_ERR(ci->role_switch)) {
index fbfb02e..be63924 100644 (file)
@@ -170,6 +170,13 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
                dev_dbg(ci->dev, "switching from %s to %s\n",
                        ci_role(ci)->name, ci->roles[role]->name);
 
+               if (ci->vbus_active && ci->role == CI_ROLE_GADGET)
+                       /*
+                        * vbus disconnect event is lost due to role
+                        * switch occurs during system suspend.
+                        */
+                       usb_gadget_vbus_disconnect(&ci->gadget);
+
                ci_role_stop(ci);
 
                if (role == CI_ROLE_GADGET &&
index 4f8b817..5e7a6e5 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2013-2014 Freescale Semiconductor, Inc.
  *
index 2b49d29..1f5c5ae 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Copyright (C) 2014 Freescale Semiconductor, Inc.
  *
index ffaf46f..921bcf1 100644 (file)
@@ -1530,18 +1530,19 @@ static const struct usb_ep_ops usb_ep_ops = {
 static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
 {
        struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
-       unsigned long flags;
 
        if (is_active) {
-               pm_runtime_get_sync(&_gadget->dev);
+               pm_runtime_get_sync(ci->dev);
                hw_device_reset(ci);
-               spin_lock_irqsave(&ci->lock, flags);
+               spin_lock_irq(&ci->lock);
                if (ci->driver) {
                        hw_device_state(ci, ci->ep0out->qh.dma);
                        usb_gadget_set_state(_gadget, USB_STATE_POWERED);
+                       spin_unlock_irq(&ci->lock);
                        usb_udc_vbus_handler(_gadget, true);
+               } else {
+                       spin_unlock_irq(&ci->lock);
                }
-               spin_unlock_irqrestore(&ci->lock, flags);
        } else {
                usb_udc_vbus_handler(_gadget, false);
                if (ci->driver)
@@ -1551,7 +1552,7 @@ static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active)
                        ci->platdata->notify_event(ci,
                        CI_HDRC_CONTROLLER_STOPPED_EVENT);
                _gadget_stop_activity(&ci->gadget);
-               pm_runtime_put_sync(&_gadget->dev);
+               pm_runtime_put_sync(ci->dev);
                usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);
        }
 }
@@ -1636,12 +1637,12 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
        if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST)
                return 0;
 
-       pm_runtime_get_sync(&ci->gadget.dev);
+       pm_runtime_get_sync(ci->dev);
        if (is_on)
                hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
        else
                hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
-       pm_runtime_put_sync(&ci->gadget.dev);
+       pm_runtime_put_sync(ci->dev);
 
        return 0;
 }
@@ -1839,7 +1840,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
                        CI_HDRC_CONTROLLER_STOPPED_EVENT);
                _gadget_stop_activity(&ci->gadget);
                spin_lock_irqsave(&ci->lock, flags);
-               pm_runtime_put(&ci->gadget.dev);
+               pm_runtime_put(ci->dev);
        }
 
        spin_unlock_irqrestore(&ci->lock, flags);
@@ -1970,9 +1971,6 @@ static int udc_start(struct ci_hdrc *ci)
        if (retval)
                goto destroy_eps;
 
-       pm_runtime_no_callbacks(&ci->gadget.dev);
-       pm_runtime_enable(&ci->gadget.dev);
-
        return retval;
 
 destroy_eps:
index e023735..ebb11b6 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * udc.h - ChipIdea UDC structures
  *
index 62f4fb9..84d6f7d 100644 (file)
@@ -896,10 +896,10 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss)
 
        ss->xmit_fifo_size = acm->writesize;
        ss->baud_base = le32_to_cpu(acm->line.dwDTERate);
-       ss->close_delay = acm->port.close_delay / 10;
+       ss->close_delay = jiffies_to_msecs(acm->port.close_delay) / 10;
        ss->closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
                                ASYNC_CLOSING_WAIT_NONE :
-                               acm->port.closing_wait / 10;
+                               jiffies_to_msecs(acm->port.closing_wait) / 10;
        return 0;
 }
 
@@ -907,17 +907,25 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss)
 {
        struct acm *acm = tty->driver_data;
        unsigned int closing_wait, close_delay;
+       unsigned int old_closing_wait, old_close_delay;
        int retval = 0;
 
-       close_delay = ss->close_delay * 10;
+       close_delay = msecs_to_jiffies(ss->close_delay * 10);
        closing_wait = ss->closing_wait == ASYNC_CLOSING_WAIT_NONE ?
-                       ASYNC_CLOSING_WAIT_NONE : ss->closing_wait * 10;
+                       ASYNC_CLOSING_WAIT_NONE :
+                       msecs_to_jiffies(ss->closing_wait * 10);
+
+       /* we must redo the rounding here, so that the values match */
+       old_close_delay = jiffies_to_msecs(acm->port.close_delay) / 10;
+       old_closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
+                               ASYNC_CLOSING_WAIT_NONE :
+                               jiffies_to_msecs(acm->port.closing_wait) / 10;
 
        mutex_lock(&acm->port.mutex);
 
        if (!capable(CAP_SYS_ADMIN)) {
-               if ((close_delay != acm->port.close_delay) ||
-                   (closing_wait != acm->port.closing_wait))
+               if ((ss->close_delay != old_close_delay) ||
+                   (ss->closing_wait != old_closing_wait))
                        retval = -EPERM;
                else
                        retval = -EOPNOTSUPP;
index 2b27d23..f81606c 100644 (file)
@@ -261,9 +261,19 @@ static int usb_probe_device(struct device *dev)
         */
        if (!udriver->supports_autosuspend)
                error = usb_autoresume_device(udev);
+       if (error)
+               return error;
 
-       if (!error)
-               error = udriver->probe(udev);
+       if (udriver->generic_subclass)
+               error = usb_generic_driver_probe(udev);
+       if (error)
+               return error;
+
+       error = udriver->probe(udev);
+       if (error == -ENODEV && udriver != &usb_generic_driver) {
+               udev->use_generic_driver = 1;
+               return -EPROBE_DEFER;
+       }
        return error;
 }
 
@@ -273,7 +283,10 @@ static int usb_unbind_device(struct device *dev)
        struct usb_device *udev = to_usb_device(dev);
        struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
 
-       udriver->disconnect(udev);
+       if (udriver->disconnect)
+               udriver->disconnect(udev);
+       if (udriver->generic_subclass)
+               usb_generic_driver_disconnect(udev);
        if (!udriver->supports_autosuspend)
                usb_autosuspend_device(udev);
        return 0;
@@ -790,17 +803,42 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
 }
 EXPORT_SYMBOL_GPL(usb_match_id);
 
+const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
+                               const struct usb_device_id *id)
+{
+       if (!id)
+               return NULL;
+
+       for (; id->idVendor || id->idProduct ; id++) {
+               if (usb_match_device(udev, id))
+                       return id;
+       }
+
+       return NULL;
+}
+
 static int usb_device_match(struct device *dev, struct device_driver *drv)
 {
        /* devices and interfaces are handled separately */
        if (is_usb_device(dev)) {
+               struct usb_device *udev;
+               struct usb_device_driver *udrv;
 
                /* interface drivers never match devices */
                if (!is_usb_device_driver(drv))
                        return 0;
 
-               /* TODO: Add real matching code */
-               return 1;
+               udev = to_usb_device(dev);
+               udrv = to_usb_device_driver(drv);
+
+               if (udrv->id_table &&
+                   usb_device_match_id(udev, udrv->id_table) != NULL) {
+                       return 1;
+               }
+
+               if (udrv->match)
+                       return udrv->match(udev);
+               return 0;
 
        } else if (is_usb_interface(dev)) {
                struct usb_interface *intf;
@@ -1149,7 +1187,10 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
                udev->do_remote_wakeup = 0;
                udriver = &usb_generic_driver;
        }
-       status = udriver->suspend(udev, msg);
+       if (udriver->suspend)
+               status = udriver->suspend(udev, msg);
+       if (status == 0 && udriver->generic_subclass)
+               status = usb_generic_driver_suspend(udev, msg);
 
  done:
        dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
@@ -1181,7 +1222,10 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
                udev->reset_resume = 1;
 
        udriver = to_usb_device_driver(udev->dev.driver);
-       status = udriver->resume(udev, msg);
+       if (udriver->generic_subclass)
+               status = usb_generic_driver_resume(udev, msg);
+       if (status == 0 && udriver->resume)
+               status = udriver->resume(udev, msg);
 
  done:
        dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
index 38f8b3e..4626227 100644 (file)
@@ -195,7 +195,38 @@ int usb_choose_configuration(struct usb_device *udev)
 }
 EXPORT_SYMBOL_GPL(usb_choose_configuration);
 
-static int generic_probe(struct usb_device *udev)
+static int __check_usb_generic(struct device_driver *drv, void *data)
+{
+       struct usb_device *udev = data;
+       struct usb_device_driver *udrv;
+
+       if (!is_usb_device_driver(drv))
+               return 0;
+       udrv = to_usb_device_driver(drv);
+       if (udrv == &usb_generic_driver)
+               return 0;
+       if (!udrv->id_table)
+               return 0;
+
+       return usb_device_match_id(udev, udrv->id_table) != NULL;
+}
+
+static bool usb_generic_driver_match(struct usb_device *udev)
+{
+       if (udev->use_generic_driver)
+               return true;
+
+       /*
+        * If any other driver wants the device, leave the device to this other
+        * driver.
+        */
+       if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_usb_generic))
+               return false;
+
+       return true;
+}
+
+int usb_generic_driver_probe(struct usb_device *udev)
 {
        int err, c;
 
@@ -222,7 +253,7 @@ static int generic_probe(struct usb_device *udev)
        return 0;
 }
 
-static void generic_disconnect(struct usb_device *udev)
+void usb_generic_driver_disconnect(struct usb_device *udev)
 {
        usb_notify_remove_device(udev);
 
@@ -234,7 +265,7 @@ static void generic_disconnect(struct usb_device *udev)
 
 #ifdef CONFIG_PM
 
-static int generic_suspend(struct usb_device *udev, pm_message_t msg)
+int usb_generic_driver_suspend(struct usb_device *udev, pm_message_t msg)
 {
        int rc;
 
@@ -262,7 +293,7 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
        return rc;
 }
 
-static int generic_resume(struct usb_device *udev, pm_message_t msg)
+int usb_generic_driver_resume(struct usb_device *udev, pm_message_t msg)
 {
        int rc;
 
@@ -285,11 +316,12 @@ static int generic_resume(struct usb_device *udev, pm_message_t msg)
 
 struct usb_device_driver usb_generic_driver = {
        .name = "usb",
-       .probe = generic_probe,
-       .disconnect = generic_disconnect,
+       .match = usb_generic_driver_match,
+       .probe = usb_generic_driver_probe,
+       .disconnect = usb_generic_driver_disconnect,
 #ifdef CONFIG_PM
-       .suspend = generic_suspend,
-       .resume = generic_resume,
+       .suspend = usb_generic_driver_suspend,
+       .resume = usb_generic_driver_resume,
 #endif
        .supports_autosuspend = 1,
 };
index 1d212f8..54cd8ef 100644 (file)
@@ -988,13 +988,17 @@ int usb_remove_device(struct usb_device *udev)
 {
        struct usb_hub *hub;
        struct usb_interface *intf;
+       int ret;
 
        if (!udev->parent)      /* Can't remove a root hub */
                return -EINVAL;
        hub = usb_hub_to_struct_hub(udev->parent);
        intf = to_usb_interface(hub->intfdev);
 
-       usb_autopm_get_interface(intf);
+       ret = usb_autopm_get_interface(intf);
+       if (ret < 0)
+               return ret;
+
        set_bit(udev->portnum, hub->removed_bits);
        hub_port_logical_disconnect(hub, udev->portnum);
        usb_autopm_put_interface(intf);
@@ -1866,7 +1870,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        if (id->driver_info & HUB_QUIRK_DISABLE_AUTOSUSPEND) {
                hub->quirk_disable_autosuspend = 1;
-               usb_autopm_get_interface(intf);
+               usb_autopm_get_interface_no_resume(intf);
        }
 
        if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
index 5adf489..d5f834f 100644 (file)
@@ -5,6 +5,7 @@
  * Released under the GPLv2 only.
  */
 
+#include <linux/acpi.h>
 #include <linux/pci.h> /* for scatterlist macros */
 #include <linux/usb.h>
 #include <linux/module.h>
@@ -1941,6 +1942,7 @@ free_interfaces:
                        intf->dev.of_node = usb_of_get_interface_node(dev,
                                        configuration, ifnum);
                }
+               ACPI_COMPANION_SET(&intf->dev, ACPI_COMPANION(&dev->dev));
                intf->dev.driver = NULL;
                intf->dev.bus = &usb_bus_type;
                intf->dev.type = &usb_if_device_type;
index bbbb35f..235a7c6 100644 (file)
@@ -213,7 +213,10 @@ static int usb_port_runtime_resume(struct device *dev)
        if (!port_dev->is_superspeed && peer)
                pm_runtime_get_sync(&peer->dev);
 
-       usb_autopm_get_interface(intf);
+       retval = usb_autopm_get_interface(intf);
+       if (retval < 0)
+               return retval;
+
        retval = usb_hub_set_port_power(hdev, hub, port1, true);
        msleep(hub_power_on_good_delay(hub));
        if (udev && !retval) {
@@ -266,7 +269,10 @@ static int usb_port_runtime_suspend(struct device *dev)
        if (usb_port_block_power_off)
                return -EBUSY;
 
-       usb_autopm_get_interface(intf);
+       retval = usb_autopm_get_interface(intf);
+       if (retval < 0)
+               return retval;
+
        retval = usb_hub_set_port_power(hdev, hub, port1, false);
        usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
        if (!port_dev->is_superspeed)
index 2b24336..da30b56 100644 (file)
@@ -231,6 +231,9 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Logitech PTZ Pro Camera */
        { USB_DEVICE(0x046d, 0x0853), .driver_info = USB_QUIRK_DELAY_INIT },
 
+       /* Logitech Screen Share */
+       { USB_DEVICE(0x046d, 0x086c), .driver_info = USB_QUIRK_NO_LPM },
+
        /* Logitech Quickcam Fusion */
        { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
 
@@ -375,6 +378,12 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x0b05, 0x17e0), .driver_info =
                        USB_QUIRK_IGNORE_REMOTE_WAKEUP },
 
+       /* Realtek hub in Dell WD19 (Type-C) */
+       { USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM },
+
+       /* Generic RTL8153 based ethernet adapters */
+       { USB_DEVICE(0x0bda, 0x8153), .driver_info = USB_QUIRK_NO_LPM },
+
        /* Action Semiconductor flash disk */
        { USB_DEVICE(0x10d6, 0x2200), .driver_info =
                        USB_QUIRK_STRING_FETCH_255 },
index f19694e..9f4320b 100644 (file)
@@ -849,7 +849,7 @@ static struct attribute *dev_string_attrs[] = {
 static umode_t dev_string_attrs_are_visible(struct kobject *kobj,
                struct attribute *a, int n)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct usb_device *udev = to_usb_device(dev);
 
        if (a == &dev_attr_manufacturer.attr) {
@@ -883,7 +883,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,
                struct bin_attribute *attr,
                char *buf, loff_t off, size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct usb_device *udev = to_usb_device(dev);
        size_t nleft = count;
        size_t srclen, n;
@@ -1233,7 +1233,7 @@ static struct attribute *intf_assoc_attrs[] = {
 static umode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
                struct attribute *a, int n)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct usb_interface *intf = to_usb_interface(dev);
 
        if (intf->intf_assoc == NULL)
index 9043d72..50b2fc7 100644 (file)
@@ -86,7 +86,7 @@ static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
 {
        enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *upc;
+       union acpi_object *upc = NULL;
        acpi_status status;
 
        /*
@@ -98,11 +98,12 @@ static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle,
         * no connectable, the port would be not used.
         */
        status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
+       if (ACPI_FAILURE(status))
+               goto out;
+
        upc = buffer.pointer;
-       if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
-               || upc->package.count != 4) {
+       if (!upc || (upc->type != ACPI_TYPE_PACKAGE) || upc->package.count != 4)
                goto out;
-       }
 
        if (upc->package.elements[0].integer.value)
                if (pld->user_visible)
@@ -186,7 +187,7 @@ usb_acpi_find_companion_for_port(struct usb_port *port_dev)
 
        handle = adev->handle;
        status = acpi_get_physical_device_location(handle, &pld);
-       if (!ACPI_FAILURE(status) && pld) {
+       if (ACPI_SUCCESS(status) && pld) {
                port_dev->location = USB_ACPI_LOCATION_VALID
                        | pld->group_token << 8 | pld->group_position;
                port_dev->connect_type = usb_acpi_get_connect_type(handle, pld);
index 3ad0ee5..64ed402 100644 (file)
@@ -50,6 +50,12 @@ extern void usb_release_bos_descriptor(struct usb_device *dev);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_choose_configuration(struct usb_device *udev);
+extern int usb_generic_driver_probe(struct usb_device *udev);
+extern void usb_generic_driver_disconnect(struct usb_device *udev);
+extern int usb_generic_driver_suspend(struct usb_device *udev,
+               pm_message_t msg);
+extern int usb_generic_driver_resume(struct usb_device *udev,
+               pm_message_t msg);
 
 static inline unsigned usb_get_max_power(struct usb_device *udev,
                struct usb_host_config *c)
@@ -66,6 +72,8 @@ extern int usb_match_one_id_intf(struct usb_device *dev,
                                 const struct usb_device_id *id);
 extern int usb_match_device(struct usb_device *dev,
                            const struct usb_device_id *id);
+extern const struct usb_device_id *usb_device_match_id(struct usb_device *udev,
+                               const struct usb_device_id *id);
 extern void usb_forced_unbind_intf(struct usb_interface *intf);
 extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev);
 
index 968e03b..99b0bdf 100644 (file)
@@ -411,6 +411,10 @@ enum dwc2_ep0_state {
  *                     register.
  *                     0 - Deactivate the transceiver (default)
  *                     1 - Activate the transceiver
+ * @activate_stm_id_vb_detection: Activate external ID pin and Vbus level
+ *                     detection using GGPIO register.
+ *                     0 - Deactivate the external level detection (default)
+ *                     1 - Activate the external level detection
  * @g_dma:              Enables gadget dma usage (default: autodetect).
  * @g_dma_desc:         Enables gadget descriptor DMA (default: autodetect).
  * @g_rx_fifo_size:    The periodic rx fifo size for the device, in
@@ -481,6 +485,7 @@ struct dwc2_core_params {
        bool service_interval;
        u8 hird_threshold;
        bool activate_stm_fs_transceiver;
+       bool activate_stm_id_vb_detection;
        bool ipg_isoc_en;
        u16 max_packet_count;
        u32 max_transfer_size;
@@ -874,6 +879,8 @@ struct dwc2_hregs_backup {
  *                      removed once all SoCs support usb transceiver.
  * @supplies:           Definition of USB power supplies
  * @vbus_supply:        Regulator supplying vbus.
+ * @usb33d:            Optional 3.3v regulator used on some stm32 devices to
+ *                     supply ID and VBUS detection hardware.
  * @lock:              Spinlock that protects all the driver data structures
  * @priv:              Stores a pointer to the struct usb_hcd
  * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth
@@ -1061,6 +1068,7 @@ struct dwc2_hsotg {
        struct dwc2_hsotg_plat *plat;
        struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
        struct regulator *vbus_supply;
+       struct regulator *usb33d;
 
        spinlock_t lock;
        void *priv;
index 92ed32e..12b98b4 100644 (file)
@@ -1646,7 +1646,8 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
 
        switch (ctrl->bRequestType & USB_RECIP_MASK) {
        case USB_RECIP_DEVICE:
-               status = 1 << USB_DEVICE_SELF_POWERED;
+               status = hsotg->gadget.is_selfpowered <<
+                        USB_DEVICE_SELF_POWERED;
                status |= hsotg->remote_wakeup_allowed <<
                          USB_DEVICE_REMOTE_WAKEUP;
                reply = cpu_to_le16(status);
@@ -4528,6 +4529,26 @@ static int dwc2_hsotg_gadget_getframe(struct usb_gadget *gadget)
 }
 
 /**
+ * dwc2_hsotg_set_selfpowered - set if device is self/bus powered
+ * @gadget: The usb gadget state
+ * @is_selfpowered: Whether the device is self-powered
+ *
+ * Set if the device is self or bus powered.
+ */
+static int dwc2_hsotg_set_selfpowered(struct usb_gadget *gadget,
+                                     int is_selfpowered)
+{
+       struct dwc2_hsotg *hsotg = to_hsotg(gadget);
+       unsigned long flags;
+
+       spin_lock_irqsave(&hsotg->lock, flags);
+       gadget->is_selfpowered = !!is_selfpowered;
+       spin_unlock_irqrestore(&hsotg->lock, flags);
+
+       return 0;
+}
+
+/**
  * dwc2_hsotg_pullup - connect/disconnect the USB PHY
  * @gadget: The usb gadget state
  * @is_on: Current state of the USB PHY
@@ -4618,6 +4639,7 @@ static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
 
 static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = {
        .get_frame      = dwc2_hsotg_gadget_getframe,
+       .set_selfpowered        = dwc2_hsotg_set_selfpowered,
        .udc_start              = dwc2_hsotg_udc_start,
        .udc_stop               = dwc2_hsotg_udc_stop,
        .pullup                 = dwc2_hsotg_pullup,
index 8ca6d12..1224fa9 100644 (file)
@@ -199,7 +199,7 @@ struct dwc2_hcd_urb {
        u32 flags;
        u16 interval;
        struct dwc2_hcd_pipe_info pipe_info;
-       struct dwc2_hcd_iso_packet_desc iso_descs[0];
+       struct dwc2_hcd_iso_packet_desc iso_descs[];
 };
 
 /* Phases for control transfers */
index 510e87e..c4027bb 100644 (file)
 #define GOTGCTL_HSTSETHNPEN            BIT(10)
 #define GOTGCTL_HNPREQ                 BIT(9)
 #define GOTGCTL_HSTNEGSCS              BIT(8)
+#define GOTGCTL_BVALOVAL               BIT(7)
+#define GOTGCTL_BVALOEN                        BIT(6)
+#define GOTGCTL_AVALOVAL               BIT(5)
+#define GOTGCTL_AVALOEN                        BIT(4)
+#define GOTGCTL_VBVALOVAL              BIT(3)
+#define GOTGCTL_VBVALOEN               BIT(2)
 #define GOTGCTL_SESREQ                 BIT(1)
 #define GOTGCTL_SESREQSCS              BIT(0)
 
 #define GPVNDCTL                       HSOTG_REG(0x0034)
 #define GGPIO                          HSOTG_REG(0x0038)
 #define GGPIO_STM32_OTG_GCCFG_PWRDWN   BIT(16)
+#define GGPIO_STM32_OTG_GCCFG_VBDEN    BIT(21)
+#define GGPIO_STM32_OTG_GCCFG_IDEN     BIT(22)
 
 #define GUID                           HSOTG_REG(0x003c)
 #define GSNPSID                                HSOTG_REG(0x0040)
index 31e090a..8ccc83f 100644 (file)
@@ -163,6 +163,35 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg)
        p->host_perio_tx_fifo_size = 256;
 }
 
+static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_core_params *p = &hsotg->params;
+
+       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->speed = DWC2_SPEED_PARAM_FULL;
+       p->host_rx_fifo_size = 128;
+       p->host_nperio_tx_fifo_size = 96;
+       p->host_perio_tx_fifo_size = 96;
+       p->max_packet_count = 256;
+       p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
+       p->i2c_enable = false;
+       p->activate_stm_fs_transceiver = true;
+       p->activate_stm_id_vb_detection = true;
+       p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
+}
+
+static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_core_params *p = &hsotg->params;
+
+       p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
+       p->activate_stm_id_vb_detection = true;
+       p->host_rx_fifo_size = 440;
+       p->host_nperio_tx_fifo_size = 256;
+       p->host_perio_tx_fifo_size = 256;
+       p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
+}
+
 const struct of_device_id dwc2_of_match_table[] = {
        { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
        { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params  },
@@ -186,6 +215,10 @@ const struct of_device_id dwc2_of_match_table[] = {
        { .compatible = "st,stm32f4x9-hsotg" },
        { .compatible = "st,stm32f7-hsotg",
          .data = dwc2_set_stm32f7_hsotg_params },
+       { .compatible = "st,stm32mp15-fsotg",
+         .data = dwc2_set_stm32mp15_fsotg_params },
+       { .compatible = "st,stm32mp15-hsotg",
+         .data = dwc2_set_stm32mp15_hsotg_params },
        {},
 };
 MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
index 3c6ce09..6997275 100644 (file)
@@ -285,7 +285,9 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
        ret = devm_regulator_bulk_get(hsotg->dev, ARRAY_SIZE(hsotg->supplies),
                                      hsotg->supplies);
        if (ret) {
-               dev_err(hsotg->dev, "failed to request supplies: %d\n", ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(hsotg->dev, "failed to request supplies: %d\n",
+                               ret);
                return ret;
        }
        return 0;
@@ -312,6 +314,9 @@ static int dwc2_driver_remove(struct platform_device *dev)
        if (hsotg->gadget_enabled)
                dwc2_hsotg_remove(hsotg);
 
+       if (hsotg->params.activate_stm_id_vb_detection)
+               regulator_disable(hsotg->usb33d);
+
        if (hsotg->ll_hw_enabled)
                dwc2_lowlevel_hw_disable(hsotg);
 
@@ -392,8 +397,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
                return retval;
        }
 
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       hsotg->regs = devm_ioremap_resource(&dev->dev, res);
+       hsotg->regs = devm_platform_get_and_ioremap_resource(dev, 0, &res);
        if (IS_ERR(hsotg->regs))
                return PTR_ERR(hsotg->regs);
 
@@ -464,10 +468,35 @@ static int dwc2_driver_probe(struct platform_device *dev)
        if (retval)
                goto error;
 
+       if (hsotg->params.activate_stm_id_vb_detection) {
+               u32 ggpio;
+
+               hsotg->usb33d = devm_regulator_get(hsotg->dev, "usb33d");
+               if (IS_ERR(hsotg->usb33d)) {
+                       retval = PTR_ERR(hsotg->usb33d);
+                       if (retval != -EPROBE_DEFER)
+                               dev_err(hsotg->dev,
+                                       "failed to request usb33d supply: %d\n",
+                                       retval);
+                       goto error;
+               }
+               retval = regulator_enable(hsotg->usb33d);
+               if (retval) {
+                       dev_err(hsotg->dev,
+                               "failed to enable usb33d supply: %d\n", retval);
+                       goto error;
+               }
+
+               ggpio = dwc2_readl(hsotg, GGPIO);
+               ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
+               ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
+               dwc2_writel(hsotg, ggpio, GGPIO);
+       }
+
        if (hsotg->dr_mode != USB_DR_MODE_HOST) {
                retval = dwc2_gadget_init(hsotg);
                if (retval)
-                       goto error;
+                       goto error_init;
                hsotg->gadget_enabled = 1;
        }
 
@@ -493,7 +522,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
                if (retval) {
                        if (hsotg->gadget_enabled)
                                dwc2_hsotg_remove(hsotg);
-                       goto error;
+                       goto error_init;
                }
                hsotg->hcd_enabled = 1;
        }
@@ -509,6 +538,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
 
        return 0;
 
+error_init:
+       if (hsotg->params.activate_stm_id_vb_detection)
+               regulator_disable(hsotg->usb33d);
 error:
        dwc2_lowlevel_hw_disable(hsotg);
        return retval;
@@ -523,6 +555,37 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
        if (is_device_mode)
                dwc2_hsotg_suspend(dwc2);
 
+       if (dwc2->params.activate_stm_id_vb_detection) {
+               unsigned long flags;
+               u32 ggpio, gotgctl;
+
+               /*
+                * Need to force the mode to the current mode to avoid Mode
+                * Mismatch Interrupt when ID detection will be disabled.
+                */
+               dwc2_force_mode(dwc2, !is_device_mode);
+
+               spin_lock_irqsave(&dwc2->lock, flags);
+               gotgctl = dwc2_readl(dwc2, GOTGCTL);
+               /* bypass debounce filter, enable overrides */
+               gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
+               gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN;
+               /* Force A / B session if needed */
+               if (gotgctl & GOTGCTL_ASESVLD)
+                       gotgctl |= GOTGCTL_AVALOVAL;
+               if (gotgctl & GOTGCTL_BSESVLD)
+                       gotgctl |= GOTGCTL_BVALOVAL;
+               dwc2_writel(dwc2, gotgctl, GOTGCTL);
+               spin_unlock_irqrestore(&dwc2->lock, flags);
+
+               ggpio = dwc2_readl(dwc2, GGPIO);
+               ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN;
+               ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN;
+               dwc2_writel(dwc2, ggpio, GGPIO);
+
+               regulator_disable(dwc2->usb33d);
+       }
+
        if (dwc2->ll_hw_enabled &&
            (is_device_mode || dwc2_host_can_poweroff_phy(dwc2))) {
                ret = __dwc2_lowlevel_hw_disable(dwc2);
@@ -544,6 +607,34 @@ static int __maybe_unused dwc2_resume(struct device *dev)
        }
        dwc2->phy_off_for_suspend = false;
 
+       if (dwc2->params.activate_stm_id_vb_detection) {
+               unsigned long flags;
+               u32 ggpio, gotgctl;
+
+               ret = regulator_enable(dwc2->usb33d);
+               if (ret)
+                       return ret;
+
+               ggpio = dwc2_readl(dwc2, GGPIO);
+               ggpio |= GGPIO_STM32_OTG_GCCFG_IDEN;
+               ggpio |= GGPIO_STM32_OTG_GCCFG_VBDEN;
+               dwc2_writel(dwc2, ggpio, GGPIO);
+
+               /* ID/VBUS detection startup time */
+               usleep_range(5000, 7000);
+
+               spin_lock_irqsave(&dwc2->lock, flags);
+               gotgctl = dwc2_readl(dwc2, GOTGCTL);
+               gotgctl &= ~GOTGCTL_DBNCE_FLTR_BYPASS;
+               gotgctl &= ~(GOTGCTL_BVALOEN | GOTGCTL_AVALOEN |
+                            GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL);
+               dwc2_writel(dwc2, gotgctl, GOTGCTL);
+               spin_unlock_irqrestore(&dwc2->lock, flags);
+       }
+
+       /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
+       dwc2_force_dr_mode(dwc2);
+
        if (dwc2_is_device_mode(dwc2))
                ret = dwc2_hsotg_resume(dwc2);
 
index 1d85c42..edc1715 100644 (file)
@@ -289,12 +289,6 @@ done:
        return 0;
 }
 
-static const struct clk_bulk_data dwc3_core_clks[] = {
-       { .id = "ref" },
-       { .id = "bus_early" },
-       { .id = "suspend" },
-};
-
 /*
  * dwc3_frame_length_adjustment - Adjusts frame length if required
  * @dwc3: Pointer to our controller context structure
@@ -1029,6 +1023,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
                if (dwc->dis_tx_ipgap_linecheck_quirk)
                        reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS;
 
+               if (dwc->parkmode_disable_ss_quirk)
+                       reg |= DWC3_GUCTL1_PARKMODE_DISABLE_SS;
+
                dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
        }
 
@@ -1342,6 +1339,8 @@ static void dwc3_get_properties(struct dwc3 *dwc)
                                "snps,dis-del-phy-power-chg-quirk");
        dwc->dis_tx_ipgap_linecheck_quirk = device_property_read_bool(dev,
                                "snps,dis-tx-ipgap-linecheck-quirk");
+       dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev,
+                               "snps,parkmode-disable-ss-quirk");
 
        dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
                                "snps,tx_de_emphasis_quirk");
@@ -1441,11 +1440,6 @@ static int dwc3_probe(struct platform_device *pdev)
        if (!dwc)
                return -ENOMEM;
 
-       dwc->clks = devm_kmemdup(dev, dwc3_core_clks, sizeof(dwc3_core_clks),
-                                GFP_KERNEL);
-       if (!dwc->clks)
-               return -ENOMEM;
-
        dwc->dev = dev;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1476,22 +1470,23 @@ static int dwc3_probe(struct platform_device *pdev)
 
        dwc3_get_properties(dwc);
 
-       dwc->reset = devm_reset_control_get_optional_shared(dev, NULL);
+       dwc->reset = devm_reset_control_array_get(dev, true, true);
        if (IS_ERR(dwc->reset))
                return PTR_ERR(dwc->reset);
 
        if (dev->of_node) {
-               dwc->num_clks = ARRAY_SIZE(dwc3_core_clks);
-
-               ret = devm_clk_bulk_get(dev, dwc->num_clks, dwc->clks);
+               ret = devm_clk_bulk_get_all(dev, &dwc->clks);
                if (ret == -EPROBE_DEFER)
                        return ret;
                /*
                 * Clocks are optional, but new DT platforms should support all
                 * clocks as required by the DT-binding.
                 */
-               if (ret)
+               if (ret < 0)
                        dwc->num_clks = 0;
+               else
+                       dwc->num_clks = ret;
+
        }
 
        ret = reset_control_deassert(dwc->reset);
@@ -1637,6 +1632,8 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
 
        switch (dwc->current_dr_role) {
        case DWC3_GCTL_PRTCAP_DEVICE:
+               if (pm_runtime_suspended(dwc->dev))
+                       break;
                spin_lock_irqsave(&dwc->lock, flags);
                dwc3_gadget_suspend(dwc);
                spin_unlock_irqrestore(&dwc->lock, flags);
index 77c4a9a..6846eb0 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/role.h>
 #include <linux/ulpi/interface.h>
 
 #include <linux/phy/phy.h>
 #define DWC3_GUCTL_HSTINAUTORETRY      BIT(14)
 
 /* Global User Control 1 Register */
+#define DWC3_GUCTL1_PARKMODE_DISABLE_SS        BIT(17)
 #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS     BIT(28)
 #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW  BIT(24)
 
@@ -953,6 +955,9 @@ struct dwc3_scratchpad_array {
  * @hsphy_mode: UTMI phy mode, one of following:
  *             - USBPHY_INTERFACE_MODE_UTMI
  *             - USBPHY_INTERFACE_MODE_UTMIW
+ * @role_sw: usb_role_switch handle
+ * @role_switch_default_mode: default operation mode of controller while
+ *                     usb role is USB_ROLE_NONE.
  * @usb2_phy: pointer to USB2 PHY
  * @usb3_phy: pointer to USB3 PHY
  * @usb2_generic_phy: pointer to USB2 PHY
@@ -1024,6 +1029,8 @@ struct dwc3_scratchpad_array {
  *                     change quirk.
  * @dis_tx_ipgap_linecheck_quirk: set if we disable u2mac linestate
  *                     check during HS transmit.
+ * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed
+ *                     instances in park mode.
  * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
  * @tx_de_emphasis: Tx de-emphasis value
  *     0       - -6dB de-emphasis
@@ -1086,6 +1093,8 @@ struct dwc3 {
        struct extcon_dev       *edev;
        struct notifier_block   edev_nb;
        enum usb_phy_interface  hsphy_mode;
+       struct usb_role_switch  *role_sw;
+       enum usb_dr_mode        role_switch_default_mode;
 
        u32                     fladj;
        u32                     irq_gadget;
@@ -1215,6 +1224,7 @@ struct dwc3 {
        unsigned                dis_u2_freeclk_exists_quirk:1;
        unsigned                dis_del_phy_power_chg_quirk:1;
        unsigned                dis_tx_ipgap_linecheck_quirk:1;
+       unsigned                parkmode_disable_ss_quirk:1;
 
        unsigned                tx_de_emphasis_quirk:1;
        unsigned                tx_de_emphasis:2;
index c946d64..7db1ffc 100644 (file)
@@ -476,6 +476,94 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
        return edev;
 }
 
+#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
+#define ROLE_SWITCH 1
+static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
+                                   enum usb_role role)
+{
+       struct dwc3 *dwc = usb_role_switch_get_drvdata(sw);
+       u32 mode;
+
+       switch (role) {
+       case USB_ROLE_HOST:
+               mode = DWC3_GCTL_PRTCAP_HOST;
+               break;
+       case USB_ROLE_DEVICE:
+               mode = DWC3_GCTL_PRTCAP_DEVICE;
+               break;
+       default:
+               if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
+                       mode = DWC3_GCTL_PRTCAP_HOST;
+               else
+                       mode = DWC3_GCTL_PRTCAP_DEVICE;
+               break;
+       }
+
+       dwc3_set_mode(dwc, mode);
+       return 0;
+}
+
+static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
+{
+       struct dwc3 *dwc = usb_role_switch_get_drvdata(sw);
+       unsigned long flags;
+       enum usb_role role;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       switch (dwc->current_dr_role) {
+       case DWC3_GCTL_PRTCAP_HOST:
+               role = USB_ROLE_HOST;
+               break;
+       case DWC3_GCTL_PRTCAP_DEVICE:
+               role = USB_ROLE_DEVICE;
+               break;
+       case DWC3_GCTL_PRTCAP_OTG:
+               role = dwc->current_otg_role;
+               break;
+       default:
+               if (dwc->role_switch_default_mode == USB_DR_MODE_HOST)
+                       role = USB_ROLE_HOST;
+               else
+                       role = USB_ROLE_DEVICE;
+               break;
+       }
+       spin_unlock_irqrestore(&dwc->lock, flags);
+       return role;
+}
+
+static int dwc3_setup_role_switch(struct dwc3 *dwc)
+{
+       struct usb_role_switch_desc dwc3_role_switch = {NULL};
+       const char *str;
+       u32 mode;
+       int ret;
+
+       ret = device_property_read_string(dwc->dev, "role-switch-default-mode",
+                                         &str);
+       if (ret >= 0  && !strncmp(str, "host", strlen("host"))) {
+               dwc->role_switch_default_mode = USB_DR_MODE_HOST;
+               mode = DWC3_GCTL_PRTCAP_HOST;
+       } else {
+               dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL;
+               mode = DWC3_GCTL_PRTCAP_DEVICE;
+       }
+
+       dwc3_role_switch.fwnode = dev_fwnode(dwc->dev);
+       dwc3_role_switch.set = dwc3_usb_role_switch_set;
+       dwc3_role_switch.get = dwc3_usb_role_switch_get;
+       dwc3_role_switch.driver_data = dwc;
+       dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch);
+       if (IS_ERR(dwc->role_sw))
+               return PTR_ERR(dwc->role_sw);
+
+       dwc3_set_mode(dwc, mode);
+       return 0;
+}
+#else
+#define ROLE_SWITCH 0
+#define dwc3_setup_role_switch(x) 0
+#endif
+
 int dwc3_drd_init(struct dwc3 *dwc)
 {
        int ret, irq;
@@ -484,7 +572,12 @@ int dwc3_drd_init(struct dwc3 *dwc)
        if (IS_ERR(dwc->edev))
                return PTR_ERR(dwc->edev);
 
-       if (dwc->edev) {
+       if (ROLE_SWITCH &&
+           device_property_read_bool(dwc->dev, "usb-role-switch")) {
+               ret = dwc3_setup_role_switch(dwc);
+               if (ret < 0)
+                       return ret;
+       } else if (dwc->edev) {
                dwc->edev_nb.notifier_call = dwc3_drd_notifier;
                ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
                                               &dwc->edev_nb);
@@ -531,6 +624,9 @@ void dwc3_drd_exit(struct dwc3 *dwc)
 {
        unsigned long flags;
 
+       if (dwc->role_sw)
+               usb_role_switch_unregister(dwc->role_sw);
+
        if (dwc->edev)
                extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
                                           &dwc->edev_nb);
index 90bb022..48b68b6 100644 (file)
@@ -162,6 +162,12 @@ static const struct dwc3_exynos_driverdata exynos5250_drvdata = {
        .suspend_clk_idx = -1,
 };
 
+static const struct dwc3_exynos_driverdata exynos5420_drvdata = {
+       .clk_names = { "usbdrd30", "usbdrd30_susp_clk"},
+       .num_clks = 2,
+       .suspend_clk_idx = 1,
+};
+
 static const struct dwc3_exynos_driverdata exynos5433_drvdata = {
        .clk_names = { "aclk", "susp_clk", "pipe_pclk", "phyclk" },
        .num_clks = 4,
@@ -179,6 +185,9 @@ static const struct of_device_id exynos_dwc3_match[] = {
                .compatible = "samsung,exynos5250-dwusb3",
                .data = &exynos5250_drvdata,
        }, {
+               .compatible = "samsung,exynos5420-dwusb3",
+               .data = &exynos5420_drvdata,
+       }, {
                .compatible = "samsung,exynos5433-dwusb3",
                .data = &exynos5433_drvdata,
        }, {
index 8a3ec1a..b81d085 100644 (file)
@@ -107,10 +107,37 @@ static const char *phy_names[PHY_COUNT] = {
        "usb2-phy0", "usb2-phy1", "usb3-phy0",
 };
 
+static struct clk_bulk_data meson_g12a_clocks[] = {
+       { .id = NULL },
+};
+
+static struct clk_bulk_data meson_a1_clocks[] = {
+       { .id = "usb_ctrl" },
+       { .id = "usb_bus" },
+       { .id = "xtal_usb_ctrl" },
+};
+
+struct dwc3_meson_g12a_drvdata {
+       bool otg_switch_supported;
+       struct clk_bulk_data *clks;
+       int num_clks;
+};
+
+static struct dwc3_meson_g12a_drvdata g12a_drvdata = {
+       .otg_switch_supported = true,
+       .clks = meson_g12a_clocks,
+       .num_clks = ARRAY_SIZE(meson_g12a_clocks),
+};
+
+static struct dwc3_meson_g12a_drvdata a1_drvdata = {
+       .otg_switch_supported = false,
+       .clks = meson_a1_clocks,
+       .num_clks = ARRAY_SIZE(meson_a1_clocks),
+};
+
 struct dwc3_meson_g12a {
        struct device           *dev;
        struct regmap           *regmap;
-       struct clk              *clk;
        struct reset_control    *reset;
        struct phy              *phys[PHY_COUNT];
        enum usb_dr_mode        otg_mode;
@@ -120,6 +147,7 @@ struct dwc3_meson_g12a {
        struct regulator        *vbus;
        struct usb_role_switch_desc switch_desc;
        struct usb_role_switch  *role_switch;
+       const struct dwc3_meson_g12a_drvdata *drvdata;
 };
 
 static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv,
@@ -151,7 +179,7 @@ static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv)
                                   U2P_R0_POWER_ON_RESET,
                                   U2P_R0_POWER_ON_RESET);
 
-               if (i == USB2_OTG_PHY) {
+               if (priv->drvdata->otg_switch_supported && i == USB2_OTG_PHY) {
                        regmap_update_bits(priv->regmap,
                                U2P_R0 + (U2P_REG_SIZE * i),
                                U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS,
@@ -295,7 +323,7 @@ static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv,
 {
        int ret;
 
-       if (!priv->phys[USB2_OTG_PHY])
+       if (!priv->drvdata->otg_switch_supported || !priv->phys[USB2_OTG_PHY])
                return -EINVAL;
 
        if (mode == PHY_MODE_USB_HOST)
@@ -321,9 +349,10 @@ static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv,
        return 0;
 }
 
-static int dwc3_meson_g12a_role_set(struct device *dev, enum usb_role role)
+static int dwc3_meson_g12a_role_set(struct usb_role_switch *sw,
+                                   enum usb_role role)
 {
-       struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
+       struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw);
        enum phy_mode mode;
 
        if (role == USB_ROLE_NONE)
@@ -338,9 +367,9 @@ static int dwc3_meson_g12a_role_set(struct device *dev, enum usb_role role)
        return dwc3_meson_g12a_otg_mode_set(priv, mode);
 }
 
-static enum usb_role dwc3_meson_g12a_role_get(struct device *dev)
+static enum usb_role dwc3_meson_g12a_role_get(struct usb_role_switch *sw)
 {
-       struct dwc3_meson_g12a *priv = dev_get_drvdata(dev);
+       struct dwc3_meson_g12a *priv = usb_role_switch_get_drvdata(sw);
 
        return priv->otg_phy_mode == PHY_MODE_USB_HOST ?
                USB_ROLE_HOST : USB_ROLE_DEVICE;
@@ -380,14 +409,61 @@ static struct device *dwc3_meson_g12_find_child(struct device *dev,
        return &pdev->dev;
 }
 
+static int dwc3_meson_g12a_otg_init(struct platform_device *pdev,
+                                   struct dwc3_meson_g12a *priv)
+{
+       enum phy_mode otg_id;
+       int ret, irq;
+       struct device *dev = &pdev->dev;
+
+       if (!priv->drvdata->otg_switch_supported)
+               return 0;
+
+       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;
+       }
+
+       /* Setup OTG mode corresponding to the ID pin */
+       if (priv->otg_mode == USB_DR_MODE_OTG) {
+               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(dev, "Failed to switch OTG mode\n");
+               }
+       }
+
+       /* Setup role switcher */
+       priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev,
+                                                               "snps,dwc3");
+       priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2");
+       priv->switch_desc.allow_userspace_control = true;
+       priv->switch_desc.set = dwc3_meson_g12a_role_set;
+       priv->switch_desc.get = dwc3_meson_g12a_role_get;
+       priv->switch_desc.driver_data = priv;
+
+       priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc);
+       if (IS_ERR(priv->role_switch))
+               dev_warn(dev, "Unable to register Role Switch\n");
+
+       return 0;
+}
+
 static int dwc3_meson_g12a_probe(struct platform_device *pdev)
 {
        struct dwc3_meson_g12a  *priv;
        struct device           *dev = &pdev->dev;
        struct device_node      *np = dev->of_node;
        void __iomem *base;
-       enum phy_mode otg_id;
-       int ret, i, irq;
+       int ret, i;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -409,17 +485,18 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
                priv->vbus = NULL;
        }
 
-       priv->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(priv->clk))
-               return PTR_ERR(priv->clk);
+       priv->drvdata = of_device_get_match_data(&pdev->dev);
 
-       ret = clk_prepare_enable(priv->clk);
+       ret = devm_clk_bulk_get(dev,
+                               priv->drvdata->num_clks,
+                               priv->drvdata->clks);
        if (ret)
                return ret;
 
-       devm_add_action_or_reset(dev,
-                                (void(*)(void *))clk_disable_unprepare,
-                                priv->clk);
+       ret = clk_bulk_prepare_enable(priv->drvdata->num_clks,
+                                     priv->drvdata->clks);
+       if (ret)
+               return ret;
 
        platform_set_drvdata(pdev, priv);
        priv->dev = dev;
@@ -433,41 +510,28 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
 
        ret = reset_control_reset(priv->reset);
        if (ret)
-               return ret;
+               goto err_disable_clks;
 
        ret = dwc3_meson_g12a_get_phys(priv);
        if (ret)
-               return ret;
+               goto err_disable_clks;
 
        if (priv->vbus) {
                ret = regulator_enable(priv->vbus);
                if (ret)
-                       return ret;
+                       goto err_disable_clks;
        }
 
        /* 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 */
        for (i = 0 ; i < PHY_COUNT ; ++i) {
                ret = phy_init(priv->phys[i]);
                if (ret)
-                       return ret;
+                       goto err_disable_clks;
        }
 
        /* Set PHY Power */
@@ -478,31 +542,12 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
        }
 
        ret = of_platform_populate(np, NULL, NULL, dev);
-       if (ret) {
-               clk_disable_unprepare(priv->clk);
+       if (ret)
                goto err_phys_power;
-       }
 
-       /* Setup OTG mode corresponding to the ID pin */
-       if (priv->otg_mode == USB_DR_MODE_OTG) {
-               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(dev, "Failed to switch OTG mode\n");
-               }
-       }
-
-       /* Setup role switcher */
-       priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev,
-                                                               "snps,dwc3");
-       priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2");
-       priv->switch_desc.allow_userspace_control = true;
-       priv->switch_desc.set = dwc3_meson_g12a_role_set;
-       priv->switch_desc.get = dwc3_meson_g12a_role_get;
-
-       priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc);
-       if (IS_ERR(priv->role_switch))
-               dev_warn(dev, "Unable to register Role Switch\n");
+       ret = dwc3_meson_g12a_otg_init(pdev, priv);
+       if (ret)
+               goto err_phys_power;
 
        pm_runtime_set_active(dev);
        pm_runtime_enable(dev);
@@ -518,6 +563,10 @@ err_phys_exit:
        for (i = 0 ; i < PHY_COUNT ; ++i)
                phy_exit(priv->phys[i]);
 
+err_disable_clks:
+       clk_bulk_disable_unprepare(priv->drvdata->num_clks,
+                                  priv->drvdata->clks);
+
        return ret;
 }
 
@@ -527,7 +576,8 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        int i;
 
-       usb_role_switch_unregister(priv->role_switch);
+       if (priv->drvdata->otg_switch_supported)
+               usb_role_switch_unregister(priv->role_switch);
 
        of_platform_depopulate(dev);
 
@@ -540,6 +590,9 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev)
        pm_runtime_put_noidle(dev);
        pm_runtime_set_suspended(dev);
 
+       clk_bulk_disable_unprepare(priv->drvdata->num_clks,
+                                  priv->drvdata->clks);
+
        return 0;
 }
 
@@ -547,7 +600,8 @@ static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev)
 {
        struct dwc3_meson_g12a  *priv = dev_get_drvdata(dev);
 
-       clk_disable(priv->clk);
+       clk_bulk_disable_unprepare(priv->drvdata->num_clks,
+                                  priv->drvdata->clks);
 
        return 0;
 }
@@ -556,7 +610,8 @@ static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev)
 {
        struct dwc3_meson_g12a  *priv = dev_get_drvdata(dev);
 
-       return clk_enable(priv->clk);
+       return clk_bulk_prepare_enable(priv->drvdata->num_clks,
+                                      priv->drvdata->clks);
 }
 
 static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev)
@@ -619,7 +674,14 @@ static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
 };
 
 static const struct of_device_id dwc3_meson_g12a_match[] = {
-       { .compatible = "amlogic,meson-g12a-usb-ctrl" },
+       {
+               .compatible = "amlogic,meson-g12a-usb-ctrl",
+               .data = &g12a_drvdata,
+       },
+       {
+               .compatible = "amlogic,meson-a1-usb-ctrl",
+               .data = &a1_drvdata,
+       },
        { /* Sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match);
index 261af9e..1dfd024 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/of.h>
 #include <linux/clk.h>
 #include <linux/irq.h>
-#include <linux/clk-provider.h>
+#include <linux/of_clk.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/extcon.h>
index 1b7d2f9..4d3c79d 100644 (file)
@@ -1071,7 +1071,14 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
                unsigned int rem = length % maxp;
                unsigned chain = true;
 
-               if (sg_is_last(s))
+               /*
+                * IOMMU driver is coalescing the list of sgs which shares a
+                * page boundary into one and giving it to USB driver. With
+                * this the number of sgs mapped is not equal to the number of
+                * sgs passed. So mark the chain bit to false if it isthe last
+                * mapped sg.
+                */
+               if (i == remaining - 1)
                        chain = false;
 
                if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) {
@@ -1514,7 +1521,7 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *r
        for (i = 0; i < req->num_trbs; i++) {
                struct dwc3_trb *trb;
 
-               trb = req->trb + i;
+               trb = &dep->trb_pool[dep->trb_dequeue];
                trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
                dwc3_ep_inc_deq(dep);
        }
@@ -2563,10 +2570,8 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
 
        dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
 
-       if (stop) {
+       if (stop)
                dwc3_stop_active_transfer(dep, true, true);
-               dep->flags = DWC3_EP_ENABLED;
-       }
 
        /*
         * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
index fa25287..86dbd01 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/**
+/*
  * host.c - DesignWare USB3 DRD Controller Host Glue
  *
  * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
@@ -7,6 +7,7 @@
  * Authors: Felipe Balbi <balbi@ti.com>,
  */
 
+#include <linux/acpi.h>
 #include <linux/platform_device.h>
 
 #include "core.h"
@@ -75,6 +76,7 @@ int dwc3_host_init(struct dwc3 *dwc)
        }
 
        xhci->dev.parent        = dwc->dev;
+       ACPI_COMPANION_SET(&xhci->dev, ACPI_COMPANION(dwc->dev));
 
        dwc->xhci = xhci;
 
index 9edff17..3054b89 100644 (file)
@@ -227,6 +227,8 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
                __field(u32, size)
                __field(u32, ctrl)
                __field(u32, type)
+               __field(u32, enqueue)
+               __field(u32, dequeue)
        ),
        TP_fast_assign(
                __assign_str(name, dep->name);
@@ -236,9 +238,12 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
                __entry->size = trb->size;
                __entry->ctrl = trb->ctrl;
                __entry->type = usb_endpoint_type(dep->endpoint.desc);
+               __entry->enqueue = dep->trb_enqueue;
+               __entry->dequeue = dep->trb_dequeue;
        ),
-       TP_printk("%s: trb %p buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)",
-               __get_str(name), __entry->trb, __entry->bph, __entry->bpl,
+       TP_printk("%s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x (%c%c%c%c:%c%c:%s)",
+               __get_str(name), __entry->trb, __entry->enqueue,
+               __entry->dequeue, __entry->bph, __entry->bpl,
                ({char *s;
                int pcm = ((__entry->size >> 24) & 3) + 1;
                switch (__entry->type) {
index 223f72d..cb4950c 100644 (file)
@@ -861,6 +861,11 @@ static int set_config(struct usb_composite_dev *cdev,
        else
                power = min(power, 900U);
 done:
+       if (power <= USB_SELF_POWER_VBUS_MAX_DRAW)
+               usb_gadget_set_selfpowered(gadget);
+       else
+               usb_gadget_clear_selfpowered(gadget);
+
        usb_gadget_vbus_draw(gadget, power);
        if (result >= 0 && cdev->delayed_status)
                result = USB_GADGET_DELAYED_STATUS;
@@ -2279,6 +2284,7 @@ void composite_suspend(struct usb_gadget *gadget)
 
        cdev->suspended = 1;
 
+       usb_gadget_set_selfpowered(gadget);
        usb_gadget_vbus_draw(gadget, 2);
 }
 
@@ -2307,6 +2313,9 @@ void composite_resume(struct usb_gadget *gadget)
                else
                        maxpower = min(maxpower, 900U);
 
+               if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW)
+                       usb_gadget_clear_selfpowered(gadget);
+
                usb_gadget_vbus_draw(gadget, maxpower);
        }
 
index 5719176..c81023b 100644 (file)
@@ -1120,6 +1120,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
 
                ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC);
                if (unlikely(ret)) {
+                       io_data->req = NULL;
                        usb_ep_free_request(ep->ep, req);
                        goto error_lock;
                }
@@ -1703,7 +1704,7 @@ static void ffs_data_put(struct ffs_data *ffs)
                pr_info("%s(): freeing\n", __func__);
                ffs_data_clear(ffs);
                BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
-                      waitqueue_active(&ffs->ep0req_completion.wait) ||
+                      swait_active(&ffs->ep0req_completion.wait) ||
                       waitqueue_active(&ffs->wait));
                destroy_workqueue(ffs->io_completion_wq);
                kfree(ffs->dev_name);
index 8b72b19..d7f6cc5 100644 (file)
@@ -48,7 +48,7 @@ struct f_phonet {
        struct usb_ep                   *in_ep, *out_ep;
 
        struct usb_request              *in_req;
-       struct usb_request              *out_reqv[0];
+       struct usb_request              *out_reqv[];
 };
 
 static int phonet_rxq_size = 17;
index 6677ae9..349deae 100644 (file)
@@ -752,8 +752,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
        audio->out_ep = ep;
        audio->out_ep->desc = &as_out_ep_desc;
 
-       status = -ENOMEM;
-
        /* copy descriptors, and track endpoint copies */
        status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL,
                                        NULL);
index fb0a892..0b97126 100644 (file)
@@ -428,7 +428,7 @@ uvc_register_video(struct uvc_device *uvc)
 
        video_set_drvdata(&uvc->vdev, uvc);
 
-       ret = video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&uvc->vdev, VFL_TYPE_VIDEO, -1);
        if (ret < 0)
                return ret;
 
index 6e7e1a9..f02c38b 100644 (file)
 # With help from a special transceiver and a "Mini-AB" jack, systems with
 # both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
 #
+# A Linux "Gadget Driver" talks to the USB Peripheral Controller
+# driver through the abstract "gadget" API.  Some other operating
+# systems call these "client" drivers, of which "class drivers"
+# are a subset (implementing a USB device class specification).
+# A gadget driver implements one or more USB functions using
+# the peripheral hardware.
+#
+# Gadget drivers are hardware-neutral, or "platform independent",
+# except that they sometimes must understand quirks or limitations
+# of the particular controllers they work with.  For example, when
+# a controller doesn't support alternate configurations or provide
+# enough of the right types of endpoints, the gadget driver might
+# not be able work with that controller, or might need to implement
+# a less common variant of a device class protocol.
+#
+# The available choices each represent a single precomposed USB
+# gadget configuration. In the device model, each option contains
+# both the device instantiation as a child for a USB gadget
+# controller, and the relevant drivers for each function declared
+# by the device.
 
-choice
-       tristate "USB Gadget precomposed configurations"
-       default USB_ETH
-       optional
-       help
-         A Linux "Gadget Driver" talks to the USB Peripheral Controller
-         driver through the abstract "gadget" API.  Some other operating
-         systems call these "client" drivers, of which "class drivers"
-         are a subset (implementing a USB device class specification).
-         A gadget driver implements one or more USB functions using
-         the peripheral hardware.
-
-         Gadget drivers are hardware-neutral, or "platform independent",
-         except that they sometimes must understand quirks or limitations
-         of the particular controllers they work with.  For example, when
-         a controller doesn't support alternate configurations or provide
-         enough of the right types of endpoints, the gadget driver might
-         not be able work with that controller, or might need to implement
-         a less common variant of a device class protocol.
-
-         The available choices each represent a single precomposed USB
-         gadget configuration. In the device model, each option contains
-         both the device instantiation as a child for a USB gadget
-         controller, and the relevant drivers for each function declared
-         by the device.
+menu "USB Gadget precomposed configurations"
 
 config USB_ZERO
        tristate "Gadget Zero (DEVELOPMENT)"
@@ -516,4 +512,15 @@ config USB_G_WEBCAM
          Say "y" to link the driver statically, or "m" to build a
          dynamically linked module called "g_webcam".
 
-endchoice
+config USB_RAW_GADGET
+       tristate "USB Raw Gadget"
+       help
+         USB Raw Gadget is a kernel module that provides a userspace interface
+         for the USB Gadget subsystem. Essentially it allows to emulate USB
+         devices from userspace. See Documentation/usb/raw-gadget.rst for
+         details.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "raw_gadget".
+
+endmenu
index abd0c3e..4d864bf 100644 (file)
@@ -43,3 +43,4 @@ obj-$(CONFIG_USB_G_WEBCAM)    += g_webcam.o
 obj-$(CONFIG_USB_G_NCM)                += g_ncm.o
 obj-$(CONFIG_USB_G_ACM_MS)     += g_acm_ms.o
 obj-$(CONFIG_USB_GADGET_TARGET)        += tcm_usb_gadget.o
+obj-$(CONFIG_USB_RAW_GADGET)   += raw_gadget.o
index 9eea2d1..265c392 100644 (file)
@@ -174,7 +174,7 @@ put:
 }
 
 static struct usb_composite_driver midi_driver = {
-       .name           = (char *) longname,
+       .name           = longname,
        .dev            = &device_desc,
        .strings        = dev_strings,
        .max_speed      = USB_SPEED_HIGH,
index b47938d..aa0de9e 100644 (file)
@@ -344,7 +344,7 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len)
        spin_unlock_irq (&epdata->dev->lock);
 
        if (likely (value == 0)) {
-               value = wait_event_interruptible (done.wait, done.done);
+               value = wait_for_completion_interruptible(&done);
                if (value != 0) {
                        spin_lock_irq (&epdata->dev->lock);
                        if (likely (epdata->ep != NULL)) {
@@ -353,7 +353,7 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len)
                                usb_ep_dequeue (epdata->ep, epdata->req);
                                spin_unlock_irq (&epdata->dev->lock);
 
-                               wait_event (done.wait, done.done);
+                               wait_for_completion(&done);
                                if (epdata->status == -ECONNRESET)
                                        epdata->status = -EINTR;
                        } else {
@@ -1736,7 +1736,7 @@ static struct usb_gadget_driver gadgetfs_driver = {
        .suspend        = gadgetfs_suspend,
 
        .driver = {
-               .name           = (char *) shortname,
+               .name           = shortname,
        },
 };
 
diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
new file mode 100644 (file)
index 0000000..7640634
--- /dev/null
@@ -0,0 +1,1078 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * USB Raw Gadget driver.
+ * See Documentation/usb/raw-gadget.rst for more details.
+ *
+ * Andrey Konovalov <andreyknvl@gmail.com>
+ */
+
+#include <linux/compiler.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/kref.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/semaphore.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/ch11.h>
+#include <linux/usb/gadget.h>
+
+#include <uapi/linux/usb/raw_gadget.h>
+
+#define        DRIVER_DESC "USB Raw Gadget"
+#define DRIVER_NAME "raw-gadget"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Andrey Konovalov");
+MODULE_LICENSE("GPL");
+
+/*----------------------------------------------------------------------*/
+
+#define RAW_EVENT_QUEUE_SIZE   16
+
+struct raw_event_queue {
+       /* See the comment in raw_event_queue_fetch() for locking details. */
+       spinlock_t              lock;
+       struct semaphore        sema;
+       struct usb_raw_event    *events[RAW_EVENT_QUEUE_SIZE];
+       int                     size;
+};
+
+static void raw_event_queue_init(struct raw_event_queue *queue)
+{
+       spin_lock_init(&queue->lock);
+       sema_init(&queue->sema, 0);
+       queue->size = 0;
+}
+
+static int raw_event_queue_add(struct raw_event_queue *queue,
+       enum usb_raw_event_type type, size_t length, const void *data)
+{
+       unsigned long flags;
+       struct usb_raw_event *event;
+
+       spin_lock_irqsave(&queue->lock, flags);
+       if (WARN_ON(queue->size >= RAW_EVENT_QUEUE_SIZE)) {
+               spin_unlock_irqrestore(&queue->lock, flags);
+               return -ENOMEM;
+       }
+       event = kmalloc(sizeof(*event) + length, GFP_ATOMIC);
+       if (!event) {
+               spin_unlock_irqrestore(&queue->lock, flags);
+               return -ENOMEM;
+       }
+       event->type = type;
+       event->length = length;
+       if (event->length)
+               memcpy(&event->data[0], data, length);
+       queue->events[queue->size] = event;
+       queue->size++;
+       up(&queue->sema);
+       spin_unlock_irqrestore(&queue->lock, flags);
+       return 0;
+}
+
+static struct usb_raw_event *raw_event_queue_fetch(
+                               struct raw_event_queue *queue)
+{
+       unsigned long flags;
+       struct usb_raw_event *event;
+
+       /*
+        * This function can be called concurrently. We first check that
+        * there's at least one event queued by decrementing the semaphore,
+        * and then take the lock to protect queue struct fields.
+        */
+       if (down_interruptible(&queue->sema))
+               return NULL;
+       spin_lock_irqsave(&queue->lock, flags);
+       if (WARN_ON(!queue->size))
+               return NULL;
+       event = queue->events[0];
+       queue->size--;
+       memmove(&queue->events[0], &queue->events[1],
+                       queue->size * sizeof(queue->events[0]));
+       spin_unlock_irqrestore(&queue->lock, flags);
+       return event;
+}
+
+static void raw_event_queue_destroy(struct raw_event_queue *queue)
+{
+       int i;
+
+       for (i = 0; i < queue->size; i++)
+               kfree(queue->events[i]);
+       queue->size = 0;
+}
+
+/*----------------------------------------------------------------------*/
+
+struct raw_dev;
+
+#define USB_RAW_MAX_ENDPOINTS 32
+
+enum ep_state {
+       STATE_EP_DISABLED,
+       STATE_EP_ENABLED,
+};
+
+struct raw_ep {
+       struct raw_dev          *dev;
+       enum ep_state           state;
+       struct usb_ep           *ep;
+       struct usb_request      *req;
+       bool                    urb_queued;
+       bool                    disabling;
+       ssize_t                 status;
+};
+
+enum dev_state {
+       STATE_DEV_INVALID = 0,
+       STATE_DEV_OPENED,
+       STATE_DEV_INITIALIZED,
+       STATE_DEV_RUNNING,
+       STATE_DEV_CLOSED,
+       STATE_DEV_FAILED
+};
+
+struct raw_dev {
+       struct kref                     count;
+       spinlock_t                      lock;
+
+       const char                      *udc_name;
+       struct usb_gadget_driver        driver;
+
+       /* Reference to misc device: */
+       struct device                   *dev;
+
+       /* Protected by lock: */
+       enum dev_state                  state;
+       bool                            gadget_registered;
+       struct usb_gadget               *gadget;
+       struct usb_request              *req;
+       bool                            ep0_in_pending;
+       bool                            ep0_out_pending;
+       bool                            ep0_urb_queued;
+       ssize_t                         ep0_status;
+       struct raw_ep                   eps[USB_RAW_MAX_ENDPOINTS];
+
+       struct completion               ep0_done;
+       struct raw_event_queue          queue;
+};
+
+static struct raw_dev *dev_new(void)
+{
+       struct raw_dev *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+       /* Matches kref_put() in raw_release(). */
+       kref_init(&dev->count);
+       spin_lock_init(&dev->lock);
+       init_completion(&dev->ep0_done);
+       raw_event_queue_init(&dev->queue);
+       return dev;
+}
+
+static void dev_free(struct kref *kref)
+{
+       struct raw_dev *dev = container_of(kref, struct raw_dev, count);
+       int i;
+
+       kfree(dev->udc_name);
+       kfree(dev->driver.udc_name);
+       if (dev->req) {
+               if (dev->ep0_urb_queued)
+                       usb_ep_dequeue(dev->gadget->ep0, dev->req);
+               usb_ep_free_request(dev->gadget->ep0, dev->req);
+       }
+       raw_event_queue_destroy(&dev->queue);
+       for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) {
+               if (dev->eps[i].state != STATE_EP_ENABLED)
+                       continue;
+               usb_ep_disable(dev->eps[i].ep);
+               usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+               kfree(dev->eps[i].ep->desc);
+               dev->eps[i].state = STATE_EP_DISABLED;
+       }
+       kfree(dev);
+}
+
+/*----------------------------------------------------------------------*/
+
+static int raw_queue_event(struct raw_dev *dev,
+       enum usb_raw_event_type type, size_t length, const void *data)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       ret = raw_event_queue_add(&dev->queue, type, length, data);
+       if (ret < 0) {
+               spin_lock_irqsave(&dev->lock, flags);
+               dev->state = STATE_DEV_FAILED;
+               spin_unlock_irqrestore(&dev->lock, flags);
+       }
+       return ret;
+}
+
+static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct raw_dev *dev = req->context;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (req->status)
+               dev->ep0_status = req->status;
+       else
+               dev->ep0_status = req->actual;
+       if (dev->ep0_in_pending)
+               dev->ep0_in_pending = false;
+       else
+               dev->ep0_out_pending = false;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       complete(&dev->ep0_done);
+}
+
+static int gadget_bind(struct usb_gadget *gadget,
+                       struct usb_gadget_driver *driver)
+{
+       int ret = 0;
+       struct raw_dev *dev = container_of(driver, struct raw_dev, driver);
+       struct usb_request *req;
+       unsigned long flags;
+
+       if (strcmp(gadget->name, dev->udc_name) != 0)
+               return -ENODEV;
+
+       set_gadget_data(gadget, dev);
+       req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+       if (!req) {
+               dev_err(&gadget->dev, "usb_ep_alloc_request failed\n");
+               set_gadget_data(gadget, NULL);
+               return -ENOMEM;
+       }
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->req = req;
+       dev->req->context = dev;
+       dev->req->complete = gadget_ep0_complete;
+       dev->gadget = gadget;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       /* Matches kref_put() in gadget_unbind(). */
+       kref_get(&dev->count);
+
+       ret = raw_queue_event(dev, USB_RAW_EVENT_CONNECT, 0, NULL);
+       if (ret < 0)
+               dev_err(&gadget->dev, "failed to queue event\n");
+
+       return ret;
+}
+
+static void gadget_unbind(struct usb_gadget *gadget)
+{
+       struct raw_dev *dev = get_gadget_data(gadget);
+
+       set_gadget_data(gadget, NULL);
+       /* Matches kref_get() in gadget_bind(). */
+       kref_put(&dev->count, dev_free);
+}
+
+static int gadget_setup(struct usb_gadget *gadget,
+                       const struct usb_ctrlrequest *ctrl)
+{
+       int ret = 0;
+       struct raw_dev *dev = get_gadget_data(gadget);
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_RUNNING) {
+               dev_err(&gadget->dev, "ignoring, device is not running\n");
+               ret = -ENODEV;
+               goto out_unlock;
+       }
+       if (dev->ep0_in_pending || dev->ep0_out_pending) {
+               dev_dbg(&gadget->dev, "stalling, request already pending\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if ((ctrl->bRequestType & USB_DIR_IN) && ctrl->wLength)
+               dev->ep0_in_pending = true;
+       else
+               dev->ep0_out_pending = true;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       ret = raw_queue_event(dev, USB_RAW_EVENT_CONTROL, sizeof(*ctrl), ctrl);
+       if (ret < 0)
+               dev_err(&gadget->dev, "failed to queue event\n");
+       goto out;
+
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+out:
+       return ret;
+}
+
+/* These are currently unused but present in case UDC driver requires them. */
+static void gadget_disconnect(struct usb_gadget *gadget) { }
+static void gadget_suspend(struct usb_gadget *gadget) { }
+static void gadget_resume(struct usb_gadget *gadget) { }
+static void gadget_reset(struct usb_gadget *gadget) { }
+
+/*----------------------------------------------------------------------*/
+
+static struct miscdevice raw_misc_device;
+
+static int raw_open(struct inode *inode, struct file *fd)
+{
+       struct raw_dev *dev;
+
+       /* Nonblocking I/O is not supported yet. */
+       if (fd->f_flags & O_NONBLOCK)
+               return -EINVAL;
+
+       dev = dev_new();
+       if (!dev)
+               return -ENOMEM;
+       fd->private_data = dev;
+       dev->state = STATE_DEV_OPENED;
+       dev->dev = raw_misc_device.this_device;
+       return 0;
+}
+
+static int raw_release(struct inode *inode, struct file *fd)
+{
+       int ret = 0;
+       struct raw_dev *dev = fd->private_data;
+       unsigned long flags;
+       bool unregister = false;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->state = STATE_DEV_CLOSED;
+       if (!dev->gadget) {
+               spin_unlock_irqrestore(&dev->lock, flags);
+               goto out_put;
+       }
+       if (dev->gadget_registered)
+               unregister = true;
+       dev->gadget_registered = false;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       if (unregister) {
+               ret = usb_gadget_unregister_driver(&dev->driver);
+               if (ret != 0)
+                       dev_err(dev->dev,
+                               "usb_gadget_unregister_driver() failed with %d\n",
+                               ret);
+               /* Matches kref_get() in raw_ioctl_run(). */
+               kref_put(&dev->count, dev_free);
+       }
+
+out_put:
+       /* Matches dev_new() in raw_open(). */
+       kref_put(&dev->count, dev_free);
+       return ret;
+}
+
+/*----------------------------------------------------------------------*/
+
+static int raw_ioctl_init(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       struct usb_raw_init arg;
+       char *udc_driver_name;
+       char *udc_device_name;
+       unsigned long flags;
+
+       ret = copy_from_user(&arg, (void __user *)value, sizeof(arg));
+       if (ret)
+               return ret;
+
+       switch (arg.speed) {
+       case USB_SPEED_UNKNOWN:
+               arg.speed = USB_SPEED_HIGH;
+               break;
+       case USB_SPEED_LOW:
+       case USB_SPEED_FULL:
+       case USB_SPEED_HIGH:
+       case USB_SPEED_SUPER:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       udc_driver_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
+       if (!udc_driver_name)
+               return -ENOMEM;
+       ret = strscpy(udc_driver_name, &arg.driver_name[0],
+                               UDC_NAME_LENGTH_MAX);
+       if (ret < 0) {
+               kfree(udc_driver_name);
+               return ret;
+       }
+       ret = 0;
+
+       udc_device_name = kmalloc(UDC_NAME_LENGTH_MAX, GFP_KERNEL);
+       if (!udc_device_name) {
+               kfree(udc_driver_name);
+               return -ENOMEM;
+       }
+       ret = strscpy(udc_device_name, &arg.device_name[0],
+                               UDC_NAME_LENGTH_MAX);
+       if (ret < 0) {
+               kfree(udc_driver_name);
+               kfree(udc_device_name);
+               return ret;
+       }
+       ret = 0;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_OPENED) {
+               dev_dbg(dev->dev, "fail, device is not opened\n");
+               kfree(udc_driver_name);
+               kfree(udc_device_name);
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       dev->udc_name = udc_driver_name;
+
+       dev->driver.function = DRIVER_DESC;
+       dev->driver.max_speed = arg.speed;
+       dev->driver.setup = gadget_setup;
+       dev->driver.disconnect = gadget_disconnect;
+       dev->driver.bind = gadget_bind;
+       dev->driver.unbind = gadget_unbind;
+       dev->driver.suspend = gadget_suspend;
+       dev->driver.resume = gadget_resume;
+       dev->driver.reset = gadget_reset;
+       dev->driver.driver.name = DRIVER_NAME;
+       dev->driver.udc_name = udc_device_name;
+       dev->driver.match_existing_only = 1;
+
+       dev->state = STATE_DEV_INITIALIZED;
+
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret;
+}
+
+static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       if (value)
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_INITIALIZED) {
+               dev_dbg(dev->dev, "fail, device is not initialized\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       ret = usb_gadget_probe_driver(&dev->driver);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (ret) {
+               dev_err(dev->dev,
+                       "fail, usb_gadget_probe_driver returned %d\n", ret);
+               dev->state = STATE_DEV_FAILED;
+               goto out_unlock;
+       }
+       dev->gadget_registered = true;
+       dev->state = STATE_DEV_RUNNING;
+       /* Matches kref_put() in raw_release(). */
+       kref_get(&dev->count);
+
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret;
+}
+
+static int raw_ioctl_event_fetch(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       struct usb_raw_event arg;
+       unsigned long flags;
+       struct usb_raw_event *event;
+       uint32_t length;
+
+       ret = copy_from_user(&arg, (void __user *)value, sizeof(arg));
+       if (ret)
+               return ret;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_RUNNING) {
+               dev_dbg(dev->dev, "fail, device is not running\n");
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return -EINVAL;
+       }
+       if (!dev->gadget) {
+               dev_dbg(dev->dev, "fail, gadget is not bound\n");
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return -EBUSY;
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       event = raw_event_queue_fetch(&dev->queue);
+       if (!event) {
+               dev_dbg(&dev->gadget->dev, "event fetching interrupted\n");
+               return -EINTR;
+       }
+       length = min(arg.length, event->length);
+       ret = copy_to_user((void __user *)value, event,
+                               sizeof(*event) + length);
+       return ret;
+}
+
+static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr,
+                               bool get_from_user)
+{
+       int ret;
+       void *data;
+
+       ret = copy_from_user(io, ptr, sizeof(*io));
+       if (ret)
+               return ERR_PTR(ret);
+       if (io->ep >= USB_RAW_MAX_ENDPOINTS)
+               return ERR_PTR(-EINVAL);
+       if (!usb_raw_io_flags_valid(io->flags))
+               return ERR_PTR(-EINVAL);
+       if (io->length > PAGE_SIZE)
+               return ERR_PTR(-EINVAL);
+       if (get_from_user)
+               data = memdup_user(ptr + sizeof(*io), io->length);
+       else {
+               data = kmalloc(io->length, GFP_KERNEL);
+               if (!data)
+                       data = ERR_PTR(-ENOMEM);
+       }
+       return data;
+}
+
+static int raw_process_ep0_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
+                               void *data, bool in)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_RUNNING) {
+               dev_dbg(dev->dev, "fail, device is not running\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       if (!dev->gadget) {
+               dev_dbg(dev->dev, "fail, gadget is not bound\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if (dev->ep0_urb_queued) {
+               dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if ((in && !dev->ep0_in_pending) ||
+                       (!in && !dev->ep0_out_pending)) {
+               dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if (WARN_ON(in && dev->ep0_out_pending)) {
+               ret = -ENODEV;
+               dev->state = STATE_DEV_FAILED;
+               goto out_done;
+       }
+       if (WARN_ON(!in && dev->ep0_in_pending)) {
+               ret = -ENODEV;
+               dev->state = STATE_DEV_FAILED;
+               goto out_done;
+       }
+
+       dev->req->buf = data;
+       dev->req->length = io->length;
+       dev->req->zero = usb_raw_io_flags_zero(io->flags);
+       dev->ep0_urb_queued = true;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       ret = usb_ep_queue(dev->gadget->ep0, dev->req, GFP_KERNEL);
+       if (ret) {
+               dev_err(&dev->gadget->dev,
+                               "fail, usb_ep_queue returned %d\n", ret);
+               spin_lock_irqsave(&dev->lock, flags);
+               dev->state = STATE_DEV_FAILED;
+               goto out_done;
+       }
+
+       ret = wait_for_completion_interruptible(&dev->ep0_done);
+       if (ret) {
+               dev_dbg(&dev->gadget->dev, "wait interrupted\n");
+               usb_ep_dequeue(dev->gadget->ep0, dev->req);
+               wait_for_completion(&dev->ep0_done);
+               spin_lock_irqsave(&dev->lock, flags);
+               goto out_done;
+       }
+
+       spin_lock_irqsave(&dev->lock, flags);
+       ret = dev->ep0_status;
+
+out_done:
+       dev->ep0_urb_queued = false;
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret;
+}
+
+static int raw_ioctl_ep0_write(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       void *data;
+       struct usb_raw_ep_io io;
+
+       data = raw_alloc_io_data(&io, (void __user *)value, true);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+       ret = raw_process_ep0_io(dev, &io, data, true);
+       kfree(data);
+       return ret;
+}
+
+static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       void *data;
+       struct usb_raw_ep_io io;
+       unsigned int length;
+
+       data = raw_alloc_io_data(&io, (void __user *)value, false);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+       ret = raw_process_ep0_io(dev, &io, data, false);
+       if (ret < 0) {
+               kfree(data);
+               return ret;
+       }
+       length = min(io.length, (unsigned int)ret);
+       ret = copy_to_user((void __user *)(value + sizeof(io)), data, length);
+       kfree(data);
+       return ret;
+}
+
+static bool check_ep_caps(struct usb_ep *ep,
+                               struct usb_endpoint_descriptor *desc)
+{
+       switch (usb_endpoint_type(desc)) {
+       case USB_ENDPOINT_XFER_ISOC:
+               if (!ep->caps.type_iso)
+                       return false;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               if (!ep->caps.type_bulk)
+                       return false;
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               if (!ep->caps.type_int)
+                       return false;
+               break;
+       default:
+               return false;
+       }
+
+       if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
+               return false;
+       if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out)
+               return false;
+
+       return true;
+}
+
+static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0, i;
+       unsigned long flags;
+       struct usb_endpoint_descriptor *desc;
+       struct usb_ep *ep = NULL;
+
+       desc = memdup_user((void __user *)value, sizeof(*desc));
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       /*
+        * Endpoints with a maxpacket length of 0 can cause crashes in UDC
+        * drivers.
+        */
+       if (usb_endpoint_maxp(desc) == 0) {
+               dev_dbg(dev->dev, "fail, bad endpoint maxpacket\n");
+               kfree(desc);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_RUNNING) {
+               dev_dbg(dev->dev, "fail, device is not running\n");
+               ret = -EINVAL;
+               goto out_free;
+       }
+       if (!dev->gadget) {
+               dev_dbg(dev->dev, "fail, gadget is not bound\n");
+               ret = -EBUSY;
+               goto out_free;
+       }
+
+       for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) {
+               if (dev->eps[i].state == STATE_EP_ENABLED)
+                       continue;
+               break;
+       }
+       if (i == USB_RAW_MAX_ENDPOINTS) {
+               dev_dbg(&dev->gadget->dev,
+                               "fail, no device endpoints available\n");
+               ret = -EBUSY;
+               goto out_free;
+       }
+
+       gadget_for_each_ep(ep, dev->gadget) {
+               if (ep->enabled)
+                       continue;
+               if (!check_ep_caps(ep, desc))
+                       continue;
+               ep->desc = desc;
+               ret = usb_ep_enable(ep);
+               if (ret < 0) {
+                       dev_err(&dev->gadget->dev,
+                               "fail, usb_ep_enable returned %d\n", ret);
+                       goto out_free;
+               }
+               dev->eps[i].req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+               if (!dev->eps[i].req) {
+                       dev_err(&dev->gadget->dev,
+                               "fail, usb_ep_alloc_request failed\n");
+                       usb_ep_disable(ep);
+                       ret = -ENOMEM;
+                       goto out_free;
+               }
+               dev->eps[i].ep = ep;
+               dev->eps[i].state = STATE_EP_ENABLED;
+               ep->driver_data = &dev->eps[i];
+               ret = i;
+               goto out_unlock;
+       }
+
+       dev_dbg(&dev->gadget->dev, "fail, no gadget endpoints available\n");
+       ret = -EBUSY;
+
+out_free:
+       kfree(desc);
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret;
+}
+
+static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0, i = value;
+       unsigned long flags;
+       const void *desc;
+
+       if (i < 0 || i >= USB_RAW_MAX_ENDPOINTS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_RUNNING) {
+               dev_dbg(dev->dev, "fail, device is not running\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       if (!dev->gadget) {
+               dev_dbg(dev->dev, "fail, gadget is not bound\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if (dev->eps[i].state != STATE_EP_ENABLED) {
+               dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       if (dev->eps[i].disabling) {
+               dev_dbg(&dev->gadget->dev,
+                               "fail, disable already in progress\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       if (dev->eps[i].urb_queued) {
+               dev_dbg(&dev->gadget->dev,
+                               "fail, waiting for urb completion\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       dev->eps[i].disabling = true;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       usb_ep_disable(dev->eps[i].ep);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req);
+       desc = dev->eps[i].ep->desc;
+       dev->eps[i].ep = NULL;
+       dev->eps[i].state = STATE_EP_DISABLED;
+       kfree(desc);
+       dev->eps[i].disabling = false;
+
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret;
+}
+
+static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct raw_ep *r_ep = (struct raw_ep *)ep->driver_data;
+       struct raw_dev *dev = r_ep->dev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (req->status)
+               r_ep->status = req->status;
+       else
+               r_ep->status = req->actual;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       complete((struct completion *)req->context);
+}
+
+static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io,
+                               void *data, bool in)
+{
+       int ret = 0;
+       unsigned long flags;
+       struct raw_ep *ep = &dev->eps[io->ep];
+       DECLARE_COMPLETION_ONSTACK(done);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_RUNNING) {
+               dev_dbg(dev->dev, "fail, device is not running\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       if (!dev->gadget) {
+               dev_dbg(dev->dev, "fail, gadget is not bound\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if (ep->state != STATE_EP_ENABLED) {
+               dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if (ep->disabling) {
+               dev_dbg(&dev->gadget->dev,
+                               "fail, endpoint is already being disabled\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if (ep->urb_queued) {
+               dev_dbg(&dev->gadget->dev, "fail, urb already queued\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       if ((in && !ep->ep->caps.dir_in) || (!in && ep->ep->caps.dir_in)) {
+               dev_dbg(&dev->gadget->dev, "fail, wrong direction\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       ep->dev = dev;
+       ep->req->context = &done;
+       ep->req->complete = gadget_ep_complete;
+       ep->req->buf = data;
+       ep->req->length = io->length;
+       ep->req->zero = usb_raw_io_flags_zero(io->flags);
+       ep->urb_queued = true;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       ret = usb_ep_queue(ep->ep, ep->req, GFP_KERNEL);
+       if (ret) {
+               dev_err(&dev->gadget->dev,
+                               "fail, usb_ep_queue returned %d\n", ret);
+               spin_lock_irqsave(&dev->lock, flags);
+               dev->state = STATE_DEV_FAILED;
+               goto out_done;
+       }
+
+       ret = wait_for_completion_interruptible(&done);
+       if (ret) {
+               dev_dbg(&dev->gadget->dev, "wait interrupted\n");
+               usb_ep_dequeue(ep->ep, ep->req);
+               wait_for_completion(&done);
+               spin_lock_irqsave(&dev->lock, flags);
+               goto out_done;
+       }
+
+       spin_lock_irqsave(&dev->lock, flags);
+       ret = ep->status;
+
+out_done:
+       ep->urb_queued = false;
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret;
+}
+
+static int raw_ioctl_ep_write(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       char *data;
+       struct usb_raw_ep_io io;
+
+       data = raw_alloc_io_data(&io, (void __user *)value, true);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+       ret = raw_process_ep_io(dev, &io, data, true);
+       kfree(data);
+       return ret;
+}
+
+static int raw_ioctl_ep_read(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       char *data;
+       struct usb_raw_ep_io io;
+       unsigned int length;
+
+       data = raw_alloc_io_data(&io, (void __user *)value, false);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+       ret = raw_process_ep_io(dev, &io, data, false);
+       if (ret < 0) {
+               kfree(data);
+               return ret;
+       }
+       length = min(io.length, (unsigned int)ret);
+       ret = copy_to_user((void __user *)(value + sizeof(io)), data, length);
+       kfree(data);
+       return ret;
+}
+
+static int raw_ioctl_configure(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       if (value)
+               return -EINVAL;
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_RUNNING) {
+               dev_dbg(dev->dev, "fail, device is not running\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       if (!dev->gadget) {
+               dev_dbg(dev->dev, "fail, gadget is not bound\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       usb_gadget_set_state(dev->gadget, USB_STATE_CONFIGURED);
+
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret;
+}
+
+static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value)
+{
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       if (dev->state != STATE_DEV_RUNNING) {
+               dev_dbg(dev->dev, "fail, device is not running\n");
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+       if (!dev->gadget) {
+               dev_dbg(dev->dev, "fail, gadget is not bound\n");
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       usb_gadget_vbus_draw(dev->gadget, 2 * value);
+
+out_unlock:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return ret;
+}
+
+static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value)
+{
+       struct raw_dev *dev = fd->private_data;
+       int ret = 0;
+
+       if (!dev)
+               return -EBUSY;
+
+       switch (cmd) {
+       case USB_RAW_IOCTL_INIT:
+               ret = raw_ioctl_init(dev, value);
+               break;
+       case USB_RAW_IOCTL_RUN:
+               ret = raw_ioctl_run(dev, value);
+               break;
+       case USB_RAW_IOCTL_EVENT_FETCH:
+               ret = raw_ioctl_event_fetch(dev, value);
+               break;
+       case USB_RAW_IOCTL_EP0_WRITE:
+               ret = raw_ioctl_ep0_write(dev, value);
+               break;
+       case USB_RAW_IOCTL_EP0_READ:
+               ret = raw_ioctl_ep0_read(dev, value);
+               break;
+       case USB_RAW_IOCTL_EP_ENABLE:
+               ret = raw_ioctl_ep_enable(dev, value);
+               break;
+       case USB_RAW_IOCTL_EP_DISABLE:
+               ret = raw_ioctl_ep_disable(dev, value);
+               break;
+       case USB_RAW_IOCTL_EP_WRITE:
+               ret = raw_ioctl_ep_write(dev, value);
+               break;
+       case USB_RAW_IOCTL_EP_READ:
+               ret = raw_ioctl_ep_read(dev, value);
+               break;
+       case USB_RAW_IOCTL_CONFIGURE:
+               ret = raw_ioctl_configure(dev, value);
+               break;
+       case USB_RAW_IOCTL_VBUS_DRAW:
+               ret = raw_ioctl_vbus_draw(dev, value);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+/*----------------------------------------------------------------------*/
+
+static const struct file_operations raw_fops = {
+       .open =                 raw_open,
+       .unlocked_ioctl =       raw_ioctl,
+       .compat_ioctl =         raw_ioctl,
+       .release =              raw_release,
+       .llseek =               no_llseek,
+};
+
+static struct miscdevice raw_misc_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = DRIVER_NAME,
+       .fops = &raw_fops,
+};
+
+module_misc_device(raw_misc_device);
index 797d6ac..3a7179e 100644 (file)
@@ -441,11 +441,20 @@ config USB_GADGET_XILINX
          dynamically linked module called "udc-xilinx" and force all
          gadget drivers to also be dynamically linked.
 
+config USB_MAX3420_UDC
+       tristate "MAX3420 (USB-over-SPI) support"
+       depends on SPI
+       help
+         The Maxim MAX3420 chip supports USB2.0 full-speed peripheral mode.
+         The MAX3420 is run by SPI interface, and hence the dependency.
+
+         To compile this driver as a module, choose M here: the module will
+         be called max3420_udc
+
 config USB_TEGRA_XUDC
        tristate "NVIDIA Tegra Superspeed USB 3.0 Device Controller"
        depends on ARCH_TEGRA || COMPILE_TEST
        depends on PHY_TEGRA_XUSB
-       select USB_ROLE_SWITCH
        help
         Enables NVIDIA Tegra USB 3.0 device mode controller driver.
 
index f6777e6..f5a7ce2 100644 (file)
@@ -42,3 +42,4 @@ obj-$(CONFIG_USB_GADGET_XILINX)       += udc-xilinx.o
 obj-$(CONFIG_USB_SNP_UDC_PLAT) += snps_udc_plat.o
 obj-$(CONFIG_USB_ASPEED_VHUB)  += aspeed-vhub/
 obj-$(CONFIG_USB_BDC_UDC)      += bdc/
+obj-$(CONFIG_USB_MAX3420_UDC)  += max3420_udc.o
index dfdef6a..0262383 100644 (file)
@@ -440,7 +440,7 @@ struct udc_ep_regs {
        /* endpoint data descriptor pointer */
        u32 desptr;
 
-       /* reserverd */
+       /* reserved */
        u32 reserved;
 
        /* write/read confirmation */
index bfd1c9e..80685e4 100644 (file)
@@ -202,7 +202,7 @@ MODULE_DEVICE_TABLE(pci, pci_id);
 
 /* PCI functions */
 static struct pci_driver udc_pci_driver = {
-       .name =         (char *) name,
+       .name =         name,
        .id_table =     pci_id,
        .probe =        udc_pci_probe,
        .remove =       udc_pci_remove,
index 83ba8a2..605500b 100644 (file)
@@ -4,5 +4,5 @@ config USB_ASPEED_VHUB
        depends on ARCH_ASPEED || COMPILE_TEST
        depends on USB_LIBCOMPOSITE
        help
-         USB peripheral controller for the Aspeed AST2500 family
-         SoCs supporting the "vHub" functionality and USB2.0
+         USB peripheral controller for the Aspeed AST2400, AST2500 and
+         AST2600 family SoCs supporting the "vHub" functionality and USB2.0
index 90b134d..f8d35dd 100644 (file)
@@ -99,7 +99,7 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
 {
        struct ast_vhub *vhub = data;
        irqreturn_t iret = IRQ_NONE;
-       u32 istat;
+       u32 i, istat;
 
        /* Stale interrupt while tearing down */
        if (!vhub->ep0_bufs)
@@ -121,10 +121,10 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
 
        /* Handle generic EPs first */
        if (istat & VHUB_IRQ_EP_POOL_ACK_STALL) {
-               u32 i, ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR);
+               u32 ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR);
                writel(ep_acks, vhub->regs + AST_VHUB_EP_ACK_ISR);
 
-               for (i = 0; ep_acks && i < AST_VHUB_NUM_GEN_EPs; i++) {
+               for (i = 0; ep_acks && i < vhub->max_epns; i++) {
                        u32 mask = VHUB_EP_IRQ(i);
                        if (ep_acks & mask) {
                                ast_vhub_epn_ack_irq(&vhub->epns[i]);
@@ -134,21 +134,11 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
        }
 
        /* Handle device interrupts */
-       if (istat & (VHUB_IRQ_DEVICE1 |
-                    VHUB_IRQ_DEVICE2 |
-                    VHUB_IRQ_DEVICE3 |
-                    VHUB_IRQ_DEVICE4 |
-                    VHUB_IRQ_DEVICE5)) {
-               if (istat & VHUB_IRQ_DEVICE1)
-                       ast_vhub_dev_irq(&vhub->ports[0].dev);
-               if (istat & VHUB_IRQ_DEVICE2)
-                       ast_vhub_dev_irq(&vhub->ports[1].dev);
-               if (istat & VHUB_IRQ_DEVICE3)
-                       ast_vhub_dev_irq(&vhub->ports[2].dev);
-               if (istat & VHUB_IRQ_DEVICE4)
-                       ast_vhub_dev_irq(&vhub->ports[3].dev);
-               if (istat & VHUB_IRQ_DEVICE5)
-                       ast_vhub_dev_irq(&vhub->ports[4].dev);
+       for (i = 0; i < vhub->max_ports; i++) {
+               u32 dev_mask = VHUB_IRQ_DEVICE1 << i;
+
+               if (istat & dev_mask)
+                       ast_vhub_dev_irq(&vhub->ports[i].dev);
        }
 
        /* Handle top-level vHub EP0 interrupts */
@@ -182,7 +172,7 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
 
 void ast_vhub_init_hw(struct ast_vhub *vhub)
 {
-       u32 ctrl;
+       u32 ctrl, port_mask, epn_mask;
 
        UDCDBG(vhub,"(Re)Starting HW ...\n");
 
@@ -222,15 +212,20 @@ void ast_vhub_init_hw(struct ast_vhub *vhub)
        }
 
        /* Reset all devices */
-       writel(VHUB_SW_RESET_ALL, vhub->regs + AST_VHUB_SW_RESET);
+       port_mask = GENMASK(vhub->max_ports, 1);
+       writel(VHUB_SW_RESET_ROOT_HUB |
+              VHUB_SW_RESET_DMA_CONTROLLER |
+              VHUB_SW_RESET_EP_POOL |
+              port_mask, vhub->regs + AST_VHUB_SW_RESET);
        udelay(1);
        writel(0, vhub->regs + AST_VHUB_SW_RESET);
 
        /* Disable and cleanup EP ACK/NACK interrupts */
+       epn_mask = GENMASK(vhub->max_epns - 1, 0);
        writel(0, vhub->regs + AST_VHUB_EP_ACK_IER);
        writel(0, vhub->regs + AST_VHUB_EP_NACK_IER);
-       writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_ACK_ISR);
-       writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_NACK_ISR);
+       writel(epn_mask, vhub->regs + AST_VHUB_EP_ACK_ISR);
+       writel(epn_mask, vhub->regs + AST_VHUB_EP_NACK_ISR);
 
        /* Default settings for EP0, enable HW hub EP1 */
        writel(0, vhub->regs + AST_VHUB_EP0_CTRL);
@@ -273,7 +268,7 @@ static int ast_vhub_remove(struct platform_device *pdev)
                return 0;
 
        /* Remove devices */
-       for (i = 0; i < AST_VHUB_NUM_PORTS; i++)
+       for (i = 0; i < vhub->max_ports; i++)
                ast_vhub_del_dev(&vhub->ports[i].dev);
 
        spin_lock_irqsave(&vhub->lock, flags);
@@ -295,7 +290,7 @@ static int ast_vhub_remove(struct platform_device *pdev)
        if (vhub->ep0_bufs)
                dma_free_coherent(&pdev->dev,
                                  AST_VHUB_EP0_MAX_PACKET *
-                                 (AST_VHUB_NUM_PORTS + 1),
+                                 (vhub->max_ports + 1),
                                  vhub->ep0_bufs,
                                  vhub->ep0_bufs_dma);
        vhub->ep0_bufs = NULL;
@@ -309,11 +304,32 @@ static int ast_vhub_probe(struct platform_device *pdev)
        struct ast_vhub *vhub;
        struct resource *res;
        int i, rc = 0;
+       const struct device_node *np = pdev->dev.of_node;
 
        vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL);
        if (!vhub)
                return -ENOMEM;
 
+       rc = of_property_read_u32(np, "aspeed,vhub-downstream-ports",
+                                 &vhub->max_ports);
+       if (rc < 0)
+               vhub->max_ports = AST_VHUB_NUM_PORTS;
+
+       vhub->ports = devm_kcalloc(&pdev->dev, vhub->max_ports,
+                                  sizeof(*vhub->ports), GFP_KERNEL);
+       if (!vhub->ports)
+               return -ENOMEM;
+
+       rc = of_property_read_u32(np, "aspeed,vhub-generic-endpoints",
+                                 &vhub->max_epns);
+       if (rc < 0)
+               vhub->max_epns = AST_VHUB_NUM_GEN_EPs;
+
+       vhub->epns = devm_kcalloc(&pdev->dev, vhub->max_epns,
+                                 sizeof(*vhub->epns), GFP_KERNEL);
+       if (!vhub->epns)
+               return -ENOMEM;
+
        spin_lock_init(&vhub->lock);
        vhub->pdev = pdev;
 
@@ -366,7 +382,7 @@ static int ast_vhub_probe(struct platform_device *pdev)
         */
        vhub->ep0_bufs = dma_alloc_coherent(&pdev->dev,
                                            AST_VHUB_EP0_MAX_PACKET *
-                                           (AST_VHUB_NUM_PORTS + 1),
+                                           (vhub->max_ports + 1),
                                            &vhub->ep0_bufs_dma, GFP_KERNEL);
        if (!vhub->ep0_bufs) {
                dev_err(&pdev->dev, "Failed to allocate EP0 DMA buffers\n");
@@ -380,7 +396,7 @@ static int ast_vhub_probe(struct platform_device *pdev)
        ast_vhub_init_ep0(vhub, &vhub->ep0, NULL);
 
        /* Init devices */
-       for (i = 0; i < AST_VHUB_NUM_PORTS && rc == 0; i++)
+       for (i = 0; i < vhub->max_ports && rc == 0; i++)
                rc = ast_vhub_init_dev(vhub, i);
        if (rc)
                goto err;
@@ -407,6 +423,9 @@ static const struct of_device_id ast_vhub_dt_ids[] = {
        {
                .compatible = "aspeed,ast2500-usb-vhub",
        },
+       {
+               .compatible = "aspeed,ast2600-usb-vhub",
+       },
        { }
 };
 MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids);
index 4008e7a..d268306 100644 (file)
@@ -77,7 +77,7 @@ static void ast_vhub_dev_enable(struct ast_vhub_dev *d)
        writel(d->ep0.buf_dma, d->regs + AST_VHUB_DEV_EP0_DATA);
 
        /* Clear stall on all EPs */
-       for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) {
+       for (i = 0; i < d->max_epns; i++) {
                struct ast_vhub_ep *ep = d->epns[i];
 
                if (ep && (ep->epn.stalled || ep->epn.wedged)) {
@@ -137,7 +137,7 @@ static int ast_vhub_ep_feature(struct ast_vhub_dev *d,
             is_set ? "SET" : "CLEAR", ep_num, wValue);
        if (ep_num == 0)
                return std_req_complete;
-       if (ep_num >= AST_VHUB_NUM_GEN_EPs || !d->epns[ep_num - 1])
+       if (ep_num >= d->max_epns || !d->epns[ep_num - 1])
                return std_req_stall;
        if (wValue != USB_ENDPOINT_HALT)
                return std_req_driver;
@@ -181,7 +181,7 @@ static int ast_vhub_ep_status(struct ast_vhub_dev *d,
 
        DDBG(d, "GET_STATUS(ep%d)\n", ep_num);
 
-       if (ep_num >= AST_VHUB_NUM_GEN_EPs)
+       if (ep_num >= d->max_epns)
                return std_req_stall;
        if (ep_num != 0) {
                ep = d->epns[ep_num - 1];
@@ -299,7 +299,7 @@ static void ast_vhub_dev_nuke(struct ast_vhub_dev *d)
 {
        unsigned int i;
 
-       for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) {
+       for (i = 0; i < d->max_epns; i++) {
                if (!d->epns[i])
                        continue;
                ast_vhub_nuke(d->epns[i], -ESHUTDOWN);
@@ -416,10 +416,10 @@ static struct usb_ep *ast_vhub_udc_match_ep(struct usb_gadget *gadget,
         * that will allow the generic code to use our
         * assigned address.
         */
-       for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++)
+       for (i = 0; i < d->max_epns; i++)
                if (d->epns[i] == NULL)
                        break;
-       if (i >= AST_VHUB_NUM_GEN_EPs)
+       if (i >= d->max_epns)
                return NULL;
        addr = i + 1;
 
@@ -526,6 +526,7 @@ void ast_vhub_del_dev(struct ast_vhub_dev *d)
 
        usb_del_gadget_udc(&d->gadget);
        device_unregister(d->port_dev);
+       kfree(d->epns);
 }
 
 static void ast_vhub_dev_release(struct device *dev)
@@ -547,13 +548,24 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
        ast_vhub_init_ep0(vhub, &d->ep0, d);
 
        /*
+        * A USB device can have up to 30 endpoints besides control
+        * endpoint 0.
+        */
+       d->max_epns = min_t(u32, vhub->max_epns, 30);
+       d->epns = kcalloc(d->max_epns, sizeof(*d->epns), GFP_KERNEL);
+       if (!d->epns)
+               return -ENOMEM;
+
+       /*
         * The UDC core really needs us to have separate and uniquely
         * named "parent" devices for each port so we create a sub device
         * here for that purpose
         */
        d->port_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
-       if (!d->port_dev)
-               return -ENOMEM;
+       if (!d->port_dev) {
+               rc = -ENOMEM;
+               goto fail_alloc;
+       }
        device_initialize(d->port_dev);
        d->port_dev->release = ast_vhub_dev_release;
        d->port_dev->parent = parent;
@@ -584,6 +596,8 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
        device_del(d->port_dev);
  fail_add:
        put_device(d->port_dev);
+ fail_alloc:
+       kfree(d->epns);
 
        return rc;
 }
index 7475c74..0bd6b20 100644 (file)
@@ -800,10 +800,10 @@ struct ast_vhub_ep *ast_vhub_alloc_epn(struct ast_vhub_dev *d, u8 addr)
 
        /* Find a free one (no device) */
        spin_lock_irqsave(&vhub->lock, flags);
-       for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++)
+       for (i = 0; i < vhub->max_epns; i++)
                if (vhub->epns[i].dev == NULL)
                        break;
-       if (i >= AST_VHUB_NUM_GEN_EPs) {
+       if (i >= vhub->max_epns) {
                spin_unlock_irqrestore(&vhub->lock, flags);
                return NULL;
        }
index 19b3517..6e565c3 100644 (file)
@@ -93,11 +93,7 @@ static void ast_vhub_patch_dev_desc_usb1(struct usb_device_descriptor *desc)
                                 USB_DT_INTERFACE_SIZE + \
                                 USB_DT_ENDPOINT_SIZE)
 
-static const struct ast_vhub_full_cdesc {
-       struct usb_config_descriptor    cfg;
-       struct usb_interface_descriptor intf;
-       struct usb_endpoint_descriptor  ep;
-} __attribute__ ((packed)) ast_vhub_conf_desc = {
+static const struct ast_vhub_full_cdesc ast_vhub_conf_desc = {
        .cfg = {
                .bLength                = USB_DT_CONFIG_SIZE,
                .bDescriptorType        = USB_DT_CONFIG,
@@ -266,6 +262,7 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep,
                             u8 desc_type, u16 len)
 {
        size_t dsize;
+       struct ast_vhub *vhub = ep->vhub;
 
        EPDBG(ep, "GET_DESCRIPTOR(type:%d)\n", desc_type);
 
@@ -281,20 +278,20 @@ static int ast_vhub_rep_desc(struct ast_vhub_ep *ep,
        switch(desc_type) {
        case USB_DT_DEVICE:
                dsize = USB_DT_DEVICE_SIZE;
-               memcpy(ep->buf, &ast_vhub_dev_desc, dsize);
-               BUILD_BUG_ON(dsize > sizeof(ast_vhub_dev_desc));
+               memcpy(ep->buf, &vhub->vhub_dev_desc, dsize);
+               BUILD_BUG_ON(dsize > sizeof(vhub->vhub_dev_desc));
                BUILD_BUG_ON(USB_DT_DEVICE_SIZE >= AST_VHUB_EP0_MAX_PACKET);
                break;
        case USB_DT_CONFIG:
                dsize = AST_VHUB_CONF_DESC_SIZE;
-               memcpy(ep->buf, &ast_vhub_conf_desc, dsize);
-               BUILD_BUG_ON(dsize > sizeof(ast_vhub_conf_desc));
+               memcpy(ep->buf, &vhub->vhub_conf_desc, dsize);
+               BUILD_BUG_ON(dsize > sizeof(vhub->vhub_conf_desc));
                BUILD_BUG_ON(AST_VHUB_CONF_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET);
                break;
        case USB_DT_HUB:
                dsize = AST_VHUB_HUB_DESC_SIZE;
-               memcpy(ep->buf, &ast_vhub_hub_desc, dsize);
-               BUILD_BUG_ON(dsize > sizeof(ast_vhub_hub_desc));
+               memcpy(ep->buf, &vhub->vhub_hub_desc, dsize);
+               BUILD_BUG_ON(dsize > sizeof(vhub->vhub_hub_desc));
                BUILD_BUG_ON(AST_VHUB_HUB_DESC_SIZE >= AST_VHUB_EP0_MAX_PACKET);
                break;
        default:
@@ -317,7 +314,8 @@ static int ast_vhub_rep_string(struct ast_vhub_ep *ep,
                               u8 string_id, u16 lang_id,
                               u16 len)
 {
-       int rc = usb_gadget_get_string (&ast_vhub_strings, string_id, ep->buf);
+       int rc = usb_gadget_get_string(&ep->vhub->vhub_str_desc,
+                                       string_id, ep->buf);
 
        /*
         * This should never happen unless we put too big strings in
@@ -504,7 +502,7 @@ static void ast_vhub_wake_work(struct work_struct *work)
         * we let the normal host wake path deal with it later.
         */
        spin_lock_irqsave(&vhub->lock, flags);
-       for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
+       for (i = 0; i < vhub->max_ports; i++) {
                struct ast_vhub_port *p = &vhub->ports[i];
 
                if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -587,7 +585,7 @@ static enum std_req_rc ast_vhub_set_port_feature(struct ast_vhub_ep *ep,
        struct ast_vhub *vhub = ep->vhub;
        struct ast_vhub_port *p;
 
-       if (port == 0 || port > AST_VHUB_NUM_PORTS)
+       if (port == 0 || port > vhub->max_ports)
                return std_req_stall;
        port--;
        p = &vhub->ports[port];
@@ -630,7 +628,7 @@ static enum std_req_rc ast_vhub_clr_port_feature(struct ast_vhub_ep *ep,
        struct ast_vhub *vhub = ep->vhub;
        struct ast_vhub_port *p;
 
-       if (port == 0 || port > AST_VHUB_NUM_PORTS)
+       if (port == 0 || port > vhub->max_ports)
                return std_req_stall;
        port--;
        p = &vhub->ports[port];
@@ -676,7 +674,7 @@ static enum std_req_rc ast_vhub_get_port_stat(struct ast_vhub_ep *ep,
        struct ast_vhub *vhub = ep->vhub;
        u16 stat, chg;
 
-       if (port == 0 || port > AST_VHUB_NUM_PORTS)
+       if (port == 0 || port > vhub->max_ports)
                return std_req_stall;
        port--;
 
@@ -757,7 +755,7 @@ void ast_vhub_hub_suspend(struct ast_vhub *vhub)
         * Forward to unsuspended ports without changing
         * their connection status.
         */
-       for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
+       for (i = 0; i < vhub->max_ports; i++) {
                struct ast_vhub_port *p = &vhub->ports[i];
 
                if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -780,7 +778,7 @@ void ast_vhub_hub_resume(struct ast_vhub *vhub)
         * Forward to unsuspended ports without changing
         * their connection status.
         */
-       for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
+       for (i = 0; i < vhub->max_ports; i++) {
                struct ast_vhub_port *p = &vhub->ports[i];
 
                if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -814,7 +812,7 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub)
         * Clear all port status, disable gadgets and "suspend"
         * them. They will be woken up by a port reset.
         */
-       for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
+       for (i = 0; i < vhub->max_ports; i++) {
                struct ast_vhub_port *p = &vhub->ports[i];
 
                /* Only keep the connected flag */
@@ -834,9 +832,31 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub)
        writel(0, vhub->regs + AST_VHUB_EP1_STS_CHG);
 }
 
+static void ast_vhub_init_desc(struct ast_vhub *vhub)
+{
+       /* Initialize vhub Device Descriptor. */
+       memcpy(&vhub->vhub_dev_desc, &ast_vhub_dev_desc,
+               sizeof(vhub->vhub_dev_desc));
+
+       /* Initialize vhub Configuration Descriptor. */
+       memcpy(&vhub->vhub_conf_desc, &ast_vhub_conf_desc,
+               sizeof(vhub->vhub_conf_desc));
+
+       /* Initialize vhub Hub Descriptor. */
+       memcpy(&vhub->vhub_hub_desc, &ast_vhub_hub_desc,
+               sizeof(vhub->vhub_hub_desc));
+       vhub->vhub_hub_desc.bNbrPorts = vhub->max_ports;
+
+       /* Initialize vhub String Descriptors. */
+       memcpy(&vhub->vhub_str_desc, &ast_vhub_strings,
+               sizeof(vhub->vhub_str_desc));
+}
+
 void ast_vhub_init_hub(struct ast_vhub *vhub)
 {
        vhub->speed = USB_SPEED_UNKNOWN;
        INIT_WORK(&vhub->wake_work, ast_vhub_wake_work);
+
+       ast_vhub_init_desc(vhub);
 }
 
index 761919e..fac79ef 100644 (file)
@@ -2,6 +2,9 @@
 #ifndef __ASPEED_VHUB_H
 #define __ASPEED_VHUB_H
 
+#include <linux/usb.h>
+#include <linux/usb/ch11.h>
+
 /*****************************
  *                           *
  * VHUB register definitions *
 #define VHUB_SW_RESET_DEVICE2                  (1 << 2)
 #define VHUB_SW_RESET_DEVICE1                  (1 << 1)
 #define VHUB_SW_RESET_ROOT_HUB                 (1 << 0)
-#define VHUB_SW_RESET_ALL                      (VHUB_SW_RESET_EP_POOL | \
-                                                VHUB_SW_RESET_DMA_CONTROLLER | \
-                                                VHUB_SW_RESET_DEVICE5 | \
-                                                VHUB_SW_RESET_DEVICE4 | \
-                                                VHUB_SW_RESET_DEVICE3 | \
-                                                VHUB_SW_RESET_DEVICE2 | \
-                                                VHUB_SW_RESET_DEVICE1 | \
-                                                VHUB_SW_RESET_ROOT_HUB)
+
 /* EP ACK/NACK IRQ masks */
 #define VHUB_EP_IRQ(n)                         (1 << (n))
-#define VHUB_EP_IRQ_ALL                                0x7fff  /* 15 EPs */
 
 /* USB status reg */
 #define VHUB_USBSTS_HISPEED                    (1 << 27)
  *                                      *
  ****************************************/
 
+/*
+ * AST_VHUB_NUM_GEN_EPs and AST_VHUB_NUM_PORTS are kept to avoid breaking
+ * existing AST2400/AST2500 platforms. AST2600 and future vhub revisions
+ * should define number of downstream ports and endpoints in device tree.
+ */
 #define AST_VHUB_NUM_GEN_EPs   15      /* Generic non-0 EPs */
 #define AST_VHUB_NUM_PORTS     5       /* vHub ports */
 #define AST_VHUB_EP0_MAX_PACKET        64      /* EP0's max packet size */
@@ -312,7 +312,7 @@ struct ast_vhub_ep {
                        /* Registers */
                        void __iomem            *regs;
 
-                       /* Index in global pool (0..14) */
+                       /* Index in global pool (zero-based) */
                        unsigned int            g_idx;
 
                        /* DMA Descriptors */
@@ -342,7 +342,7 @@ struct ast_vhub_dev {
        struct ast_vhub                 *vhub;
        void __iomem                    *regs;
 
-       /* Device index (0...4) and name string */
+       /* Device index (zero-based) and name string */
        unsigned int                    index;
        const char                      *name;
 
@@ -358,7 +358,8 @@ struct ast_vhub_dev {
 
        /* Endpoint structures */
        struct ast_vhub_ep              ep0;
-       struct ast_vhub_ep              *epns[AST_VHUB_NUM_GEN_EPs];
+       struct ast_vhub_ep              **epns;
+       u32                             max_epns;
 
 };
 #define to_ast_dev(__g) container_of(__g, struct ast_vhub_dev, gadget)
@@ -373,6 +374,12 @@ struct ast_vhub_port {
        struct ast_vhub_dev     dev;
 };
 
+struct ast_vhub_full_cdesc {
+       struct usb_config_descriptor    cfg;
+       struct usb_interface_descriptor intf;
+       struct usb_endpoint_descriptor  ep;
+} __packed;
+
 /* Global vhub structure */
 struct ast_vhub {
        struct platform_device          *pdev;
@@ -393,10 +400,12 @@ struct ast_vhub {
        bool                            ep1_stalled : 1;
 
        /* Per-port info */
-       struct ast_vhub_port            ports[AST_VHUB_NUM_PORTS];
+       struct ast_vhub_port            *ports;
+       u32                             max_ports;
 
        /* Generic EP data structures */
-       struct ast_vhub_ep              epns[AST_VHUB_NUM_GEN_EPs];
+       struct ast_vhub_ep              *epns;
+       u32                             max_epns;
 
        /* Upstream bus is suspended ? */
        bool                            suspended : 1;
@@ -409,6 +418,12 @@ struct ast_vhub {
 
        /* Upstream bus speed captured at bus reset */
        unsigned int                    speed;
+
+       /* Standard USB Descriptors of the vhub. */
+       struct usb_device_descriptor    vhub_dev_desc;
+       struct ast_vhub_full_cdesc      vhub_conf_desc;
+       struct usb_hub_descriptor       vhub_hub_desc;
+       struct usb_gadget_strings       vhub_str_desc;
 };
 
 /* Standard request handlers result codes */
index 1b2b548..eede5ce 100644 (file)
@@ -2021,7 +2021,7 @@ static struct platform_driver at91_udc_driver = {
        .suspend        = at91udc_suspend,
        .resume         = at91udc_resume,
        .driver         = {
-               .name   = (char *) driver_name,
+               .name   = driver_name,
                .of_match_table = at91_udc_dt_ids,
        },
 };
index 4c9d1e4..6e3e3eb 100644 (file)
@@ -1134,7 +1134,7 @@ static struct platform_driver dummy_udc_driver = {
        .suspend        = dummy_udc_suspend,
        .resume         = dummy_udc_resume,
        .driver         = {
-               .name   = (char *) gadget_name,
+               .name   = gadget_name,
        },
 };
 
@@ -2720,7 +2720,7 @@ static struct platform_driver dummy_hcd_driver = {
        .suspend        = dummy_hcd_suspend,
        .resume         = dummy_hcd_resume,
        .driver         = {
-               .name   = (char *) driver_name,
+               .name   = driver_name,
        },
 };
 
index 21f3e6c..d6ca50f 100644 (file)
@@ -1199,7 +1199,7 @@ err:
 
 static struct platform_driver fotg210_driver = {
        .driver         = {
-               .name = (char *)udc_name,
+               .name = udc_name,
        },
        .probe          = fotg210_udc_probe,
        .remove         = fotg210_udc_remove,
index ec6eda4..febabde 100644 (file)
@@ -53,7 +53,6 @@
 #define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
 
 static const char driver_name[] = "fsl-usb2-udc";
-static const char driver_desc[] = DRIVER_DESC;
 
 static struct usb_dr_device __iomem *dr_regs;
 
index 00e3f66..9af8b41 100644 (file)
@@ -1507,7 +1507,7 @@ clean_up:
 static struct platform_driver fusb300_driver = {
        .remove =       fusb300_remove,
        .driver         = {
-               .name = (char *) udc_name,
+               .name = udc_name,
        },
 };
 
index 4a46f66..91dcb19 100644 (file)
@@ -1844,7 +1844,7 @@ static const struct pci_device_id pci_ids[] = { {
 MODULE_DEVICE_TABLE (pci, pci_ids);
 
 static struct pci_driver goku_pci_driver = {
-       .name =         (char *) driver_name,
+       .name =         driver_name,
        .id_table =     pci_ids,
 
        .probe =        goku_probe,
index d14b2bb..cb997b8 100644 (file)
@@ -3267,7 +3267,7 @@ static struct platform_driver lpc32xx_udc_driver = {
        .suspend        = lpc32xx_udc_suspend,
        .resume         = lpc32xx_udc_resume,
        .driver         = {
-               .name   = (char *) driver_name,
+               .name   = driver_name,
                .of_match_table = of_match_ptr(lpc32xx_udc_of_match),
        },
 };
index a8288df..75d16a8 100644 (file)
@@ -1691,7 +1691,7 @@ clean_up:
 static struct platform_driver m66592_driver = {
        .remove =       m66592_remove,
        .driver         = {
-               .name = (char *) udc_name,
+               .name = udc_name,
        },
 };
 
diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c
new file mode 100644 (file)
index 0000000..8fbc083
--- /dev/null
@@ -0,0 +1,1331 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MAX3420 Device Controller driver for USB.
+ *
+ * Author: Jaswinder Singh Brar <jaswinder.singh@linaro.org>
+ * (C) Copyright 2019-2020 Linaro Ltd
+ *
+ * Based on:
+ *     o MAX3420E datasheet
+ *             http://datasheets.maximintegrated.com/en/ds/MAX3420E.pdf
+ *     o MAX342{0,1}E Programming Guides
+ *             https://pdfserv.maximintegrated.com/en/an/AN3598.pdf
+ *             https://pdfserv.maximintegrated.com/en/an/AN3785.pdf
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/bitfield.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/prefetch.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio/consumer.h>
+
+#define MAX3420_MAX_EPS                4
+#define MAX3420_EP_MAX_PACKET          64  /* Same for all Endpoints */
+#define MAX3420_EPNAME_SIZE            16  /* Buffer size for endpoint name */
+
+#define MAX3420_ACKSTAT                BIT(0)
+
+#define MAX3420_SPI_DIR_RD     0       /* read register from MAX3420 */
+#define MAX3420_SPI_DIR_WR     1       /* write register to MAX3420 */
+
+/* SPI commands: */
+#define MAX3420_SPI_DIR_SHIFT  1
+#define MAX3420_SPI_REG_SHIFT  3
+
+#define MAX3420_REG_EP0FIFO    0
+#define MAX3420_REG_EP1FIFO    1
+#define MAX3420_REG_EP2FIFO    2
+#define MAX3420_REG_EP3FIFO    3
+#define MAX3420_REG_SUDFIFO    4
+#define MAX3420_REG_EP0BC      5
+#define MAX3420_REG_EP1BC      6
+#define MAX3420_REG_EP2BC      7
+#define MAX3420_REG_EP3BC      8
+
+#define MAX3420_REG_EPSTALLS   9
+       #define ACKSTAT         BIT(6)
+       #define STLSTAT         BIT(5)
+       #define STLEP3IN        BIT(4)
+       #define STLEP2IN        BIT(3)
+       #define STLEP1OUT       BIT(2)
+       #define STLEP0OUT       BIT(1)
+       #define STLEP0IN        BIT(0)
+
+#define MAX3420_REG_CLRTOGS    10
+       #define EP3DISAB        BIT(7)
+       #define EP2DISAB        BIT(6)
+       #define EP1DISAB        BIT(5)
+       #define CTGEP3IN        BIT(4)
+       #define CTGEP2IN        BIT(3)
+       #define CTGEP1OUT       BIT(2)
+
+#define MAX3420_REG_EPIRQ      11
+#define MAX3420_REG_EPIEN      12
+       #define SUDAVIRQ        BIT(5)
+       #define IN3BAVIRQ       BIT(4)
+       #define IN2BAVIRQ       BIT(3)
+       #define OUT1DAVIRQ      BIT(2)
+       #define OUT0DAVIRQ      BIT(1)
+       #define IN0BAVIRQ       BIT(0)
+
+#define MAX3420_REG_USBIRQ     13
+#define MAX3420_REG_USBIEN     14
+       #define OSCOKIRQ        BIT(0)
+       #define RWUDNIRQ        BIT(1)
+       #define BUSACTIRQ       BIT(2)
+       #define URESIRQ         BIT(3)
+       #define SUSPIRQ         BIT(4)
+       #define NOVBUSIRQ       BIT(5)
+       #define VBUSIRQ         BIT(6)
+       #define URESDNIRQ       BIT(7)
+
+#define MAX3420_REG_USBCTL     15
+       #define HOSCSTEN        BIT(7)
+       #define VBGATE          BIT(6)
+       #define CHIPRES         BIT(5)
+       #define PWRDOWN         BIT(4)
+       #define CONNECT         BIT(3)
+       #define SIGRWU          BIT(2)
+
+#define MAX3420_REG_CPUCTL     16
+       #define IE              BIT(0)
+
+#define MAX3420_REG_PINCTL     17
+       #define EP3INAK         BIT(7)
+       #define EP2INAK         BIT(6)
+       #define EP0INAK         BIT(5)
+       #define FDUPSPI         BIT(4)
+       #define INTLEVEL        BIT(3)
+       #define POSINT          BIT(2)
+       #define GPXB            BIT(1)
+       #define GPXA            BIT(0)
+
+#define MAX3420_REG_REVISION   18
+
+#define MAX3420_REG_FNADDR     19
+       #define FNADDR_MASK     0x7f
+
+#define MAX3420_REG_IOPINS     20
+#define MAX3420_REG_IOPINS2    21
+#define MAX3420_REG_GPINIRQ    22
+#define MAX3420_REG_GPINIEN    23
+#define MAX3420_REG_GPINPOL    24
+#define MAX3420_REG_HIRQ       25
+#define MAX3420_REG_HIEN       26
+#define MAX3420_REG_MODE       27
+#define MAX3420_REG_PERADDR    28
+#define MAX3420_REG_HCTL       29
+#define MAX3420_REG_HXFR       30
+#define MAX3420_REG_HRSL       31
+
+#define ENABLE_IRQ     BIT(0)
+#define IOPIN_UPDATE   BIT(1)
+#define REMOTE_WAKEUP  BIT(2)
+#define CONNECT_HOST   GENMASK(4, 3)
+#define        HCONNECT        (1 << 3)
+#define        HDISCONNECT     (3 << 3)
+#define UDC_START      GENMASK(6, 5)
+#define        START           (1 << 5)
+#define        STOP            (3 << 5)
+#define ENABLE_EP      GENMASK(8, 7)
+#define        ENABLE          (1 << 7)
+#define        DISABLE         (3 << 7)
+#define STALL_EP       GENMASK(10, 9)
+#define        STALL           (1 << 9)
+#define        UNSTALL         (3 << 9)
+
+#define MAX3420_CMD(c)         FIELD_PREP(GENMASK(7, 3), c)
+#define MAX3420_SPI_CMD_RD(c)  (MAX3420_CMD(c) | (0 << 1))
+#define MAX3420_SPI_CMD_WR(c)  (MAX3420_CMD(c) | (1 << 1))
+
+struct max3420_req {
+       struct usb_request usb_req;
+       struct list_head queue;
+       struct max3420_ep *ep;
+};
+
+struct max3420_ep {
+       struct usb_ep ep_usb;
+       struct max3420_udc *udc;
+       struct list_head queue;
+       char name[MAX3420_EPNAME_SIZE];
+       unsigned int maxpacket;
+       spinlock_t lock;
+       int halted;
+       u32 todo;
+       int id;
+};
+
+struct max3420_udc {
+       struct usb_gadget gadget;
+       struct max3420_ep ep[MAX3420_MAX_EPS];
+       struct usb_gadget_driver *driver;
+       struct task_struct *thread_task;
+       int remote_wkp, is_selfpowered;
+       bool vbus_active, softconnect;
+       struct usb_ctrlrequest setup;
+       struct mutex spi_bus_mutex;
+       struct max3420_req ep0req;
+       struct spi_device *spi;
+       struct device *dev;
+       spinlock_t lock;
+       bool suspended;
+       u8 ep0buf[64];
+       u32 todo;
+};
+
+#define to_max3420_req(r)      container_of((r), struct max3420_req, usb_req)
+#define to_max3420_ep(e)       container_of((e), struct max3420_ep, ep_usb)
+#define to_udc(g)              container_of((g), struct max3420_udc, gadget)
+
+#define DRIVER_DESC     "MAX3420 USB Device-Mode Driver"
+static const char driver_name[] = "max3420-udc";
+
+/* Control endpoint configuration.*/
+static const struct usb_endpoint_descriptor ep0_desc = {
+       .bEndpointAddress       = USB_DIR_OUT,
+       .bmAttributes           = USB_ENDPOINT_XFER_CONTROL,
+       .wMaxPacketSize         = cpu_to_le16(MAX3420_EP_MAX_PACKET),
+};
+
+static void spi_ack_ctrl(struct max3420_udc *udc)
+{
+       struct spi_device *spi = udc->spi;
+       struct spi_transfer transfer;
+       struct spi_message msg;
+       u8 txdata[1];
+
+       memset(&transfer, 0, sizeof(transfer));
+
+       spi_message_init(&msg);
+
+       txdata[0] = MAX3420_ACKSTAT;
+       transfer.tx_buf = txdata;
+       transfer.len = 1;
+
+       spi_message_add_tail(&transfer, &msg);
+       spi_sync(spi, &msg);
+}
+
+static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int actstat)
+{
+       struct spi_device *spi = udc->spi;
+       struct spi_transfer transfer;
+       struct spi_message msg;
+       u8 txdata[2], rxdata[2];
+
+       memset(&transfer, 0, sizeof(transfer));
+
+       spi_message_init(&msg);
+
+       txdata[0] = MAX3420_SPI_CMD_RD(reg) | (actstat ? MAX3420_ACKSTAT : 0);
+       transfer.tx_buf = txdata;
+       transfer.rx_buf = rxdata;
+       transfer.len = 2;
+
+       spi_message_add_tail(&transfer, &msg);
+       spi_sync(spi, &msg);
+
+       return rxdata[1];
+}
+
+static u8 spi_rd8(struct max3420_udc *udc, u8 reg)
+{
+       return spi_rd8_ack(udc, reg, 0);
+}
+
+static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int actstat)
+{
+       struct spi_device *spi = udc->spi;
+       struct spi_transfer transfer;
+       struct spi_message msg;
+       u8 txdata[2];
+
+       memset(&transfer, 0, sizeof(transfer));
+
+       spi_message_init(&msg);
+
+       txdata[0] = MAX3420_SPI_CMD_WR(reg) | (actstat ? MAX3420_ACKSTAT : 0);
+       txdata[1] = val;
+
+       transfer.tx_buf = txdata;
+       transfer.len = 2;
+
+       spi_message_add_tail(&transfer, &msg);
+       spi_sync(spi, &msg);
+}
+
+static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val)
+{
+       spi_wr8_ack(udc, reg, val, 0);
+}
+
+static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
+{
+       struct spi_device *spi = udc->spi;
+       struct spi_transfer transfer;
+       struct spi_message msg;
+       u8 local_buf[MAX3420_EP_MAX_PACKET + 1] = {};
+
+       memset(&transfer, 0, sizeof(transfer));
+
+       spi_message_init(&msg);
+
+       local_buf[0] = MAX3420_SPI_CMD_RD(reg);
+       transfer.tx_buf = &local_buf[0];
+       transfer.rx_buf = &local_buf[0];
+       transfer.len = len + 1;
+
+       spi_message_add_tail(&transfer, &msg);
+       spi_sync(spi, &msg);
+
+       memcpy(buf, &local_buf[1], len);
+}
+
+static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len)
+{
+       struct spi_device *spi = udc->spi;
+       struct spi_transfer transfer;
+       struct spi_message msg;
+       u8 local_buf[MAX3420_EP_MAX_PACKET + 1] = {};
+
+       memset(&transfer, 0, sizeof(transfer));
+
+       spi_message_init(&msg);
+
+       local_buf[0] = MAX3420_SPI_CMD_WR(reg);
+       memcpy(&local_buf[1], buf, len);
+
+       transfer.tx_buf = local_buf;
+       transfer.len = len + 1;
+
+       spi_message_add_tail(&transfer, &msg);
+       spi_sync(spi, &msg);
+}
+
+static int spi_max3420_enable(struct max3420_ep *ep)
+{
+       struct max3420_udc *udc = ep->udc;
+       unsigned long flags;
+       u8 epdis, epien;
+       int todo;
+
+       spin_lock_irqsave(&ep->lock, flags);
+       todo = ep->todo & ENABLE_EP;
+       ep->todo &= ~ENABLE_EP;
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       if (!todo || ep->id == 0)
+               return false;
+
+       epien = spi_rd8(udc, MAX3420_REG_EPIEN);
+       epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS);
+
+       if (todo == ENABLE) {
+               epdis &= ~BIT(ep->id + 4);
+               epien |= BIT(ep->id + 1);
+       } else {
+               epdis |= BIT(ep->id + 4);
+               epien &= ~BIT(ep->id + 1);
+       }
+
+       spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis);
+       spi_wr8(udc, MAX3420_REG_EPIEN, epien);
+
+       return true;
+}
+
+static int spi_max3420_stall(struct max3420_ep *ep)
+{
+       struct max3420_udc *udc = ep->udc;
+       unsigned long flags;
+       u8 epstalls;
+       int todo;
+
+       spin_lock_irqsave(&ep->lock, flags);
+       todo = ep->todo & STALL_EP;
+       ep->todo &= ~STALL_EP;
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       if (!todo || ep->id == 0)
+               return false;
+
+       epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS);
+       if (todo == STALL) {
+               ep->halted = 1;
+               epstalls |= BIT(ep->id + 1);
+       } else {
+               u8 clrtogs;
+
+               ep->halted = 0;
+               epstalls &= ~BIT(ep->id + 1);
+               clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS);
+               clrtogs |= BIT(ep->id + 1);
+               spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs);
+       }
+       spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | ACKSTAT);
+
+       return true;
+}
+
+static int spi_max3420_rwkup(struct max3420_udc *udc)
+{
+       unsigned long flags;
+       int wake_remote;
+       u8 usbctl;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       wake_remote = udc->todo & REMOTE_WAKEUP;
+       udc->todo &= ~REMOTE_WAKEUP;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       if (!wake_remote || !udc->suspended)
+               return false;
+
+       /* Set Remote-WkUp Signal*/
+       usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
+       usbctl |= SIGRWU;
+       spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
+
+       msleep_interruptible(5);
+
+       /* Clear Remote-WkUp Signal*/
+       usbctl = spi_rd8(udc, MAX3420_REG_USBCTL);
+       usbctl &= ~SIGRWU;
+       spi_wr8(udc, MAX3420_REG_USBCTL, usbctl);
+
+       udc->suspended = false;
+
+       return true;
+}
+
+static void max3420_nuke(struct max3420_ep *ep, int status);
+static void __max3420_stop(struct max3420_udc *udc)
+{
+       u8 val;
+       int i;
+
+       /* clear all pending requests */
+       for (i = 1; i < MAX3420_MAX_EPS; i++)
+               max3420_nuke(&udc->ep[i], -ECONNRESET);
+
+       /* Disable IRQ to CPU */
+       spi_wr8(udc, MAX3420_REG_CPUCTL, 0);
+
+       val = spi_rd8(udc, MAX3420_REG_USBCTL);
+       val |= PWRDOWN;
+       if (udc->is_selfpowered)
+               val &= ~HOSCSTEN;
+       else
+               val |= HOSCSTEN;
+       spi_wr8(udc, MAX3420_REG_USBCTL, val);
+}
+
+static void __max3420_start(struct max3420_udc *udc)
+{
+       u8 val;
+
+       /* Need this delay if bus-powered,
+        * but even for self-powered it helps stability
+        */
+       msleep_interruptible(250);
+
+       /* configure SPI */
+       spi_wr8(udc, MAX3420_REG_PINCTL, FDUPSPI);
+
+       /* Chip Reset */
+       spi_wr8(udc, MAX3420_REG_USBCTL, CHIPRES);
+       msleep_interruptible(5);
+       spi_wr8(udc, MAX3420_REG_USBCTL, 0);
+
+       /* Poll for OSC to stabilize */
+       while (1) {
+               val = spi_rd8(udc, MAX3420_REG_USBIRQ);
+               if (val & OSCOKIRQ)
+                       break;
+               cond_resched();
+       }
+
+       /* Enable PULL-UP only when Vbus detected */
+       val = spi_rd8(udc, MAX3420_REG_USBCTL);
+       val |= VBGATE | CONNECT;
+       spi_wr8(udc, MAX3420_REG_USBCTL, val);
+
+       val = URESDNIRQ | URESIRQ;
+       if (udc->is_selfpowered)
+               val |= NOVBUSIRQ;
+       spi_wr8(udc, MAX3420_REG_USBIEN, val);
+
+       /* Enable only EP0 interrupts */
+       val = IN0BAVIRQ | OUT0DAVIRQ | SUDAVIRQ;
+       spi_wr8(udc, MAX3420_REG_EPIEN, val);
+
+       /* Enable IRQ to CPU */
+       spi_wr8(udc, MAX3420_REG_CPUCTL, IE);
+}
+
+static int max3420_start(struct max3420_udc *udc)
+{
+       unsigned long flags;
+       int todo;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       todo = udc->todo & UDC_START;
+       udc->todo &= ~UDC_START;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       if (!todo)
+               return false;
+
+       if (udc->vbus_active && udc->softconnect)
+               __max3420_start(udc);
+       else
+               __max3420_stop(udc);
+
+       return true;
+}
+
+static irqreturn_t max3420_vbus_handler(int irq, void *dev_id)
+{
+       struct max3420_udc *udc = dev_id;
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       /* its a vbus change interrupt */
+       udc->vbus_active = !udc->vbus_active;
+       udc->todo |= UDC_START;
+       usb_udc_vbus_handler(&udc->gadget, udc->vbus_active);
+       usb_gadget_set_state(&udc->gadget, udc->vbus_active
+                            ? USB_STATE_POWERED : USB_STATE_NOTATTACHED);
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       if (udc->thread_task &&
+           udc->thread_task->state != TASK_RUNNING)
+               wake_up_process(udc->thread_task);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t max3420_irq_handler(int irq, void *dev_id)
+{
+       struct max3420_udc *udc = dev_id;
+       struct spi_device *spi = udc->spi;
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       if ((udc->todo & ENABLE_IRQ) == 0) {
+               disable_irq_nosync(spi->irq);
+               udc->todo |= ENABLE_IRQ;
+       }
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       if (udc->thread_task &&
+           udc->thread_task->state != TASK_RUNNING)
+               wake_up_process(udc->thread_task);
+
+       return IRQ_HANDLED;
+}
+
+static void max3420_getstatus(struct max3420_udc *udc)
+{
+       struct max3420_ep *ep;
+       u16 status = 0;
+
+       switch (udc->setup.bRequestType & USB_RECIP_MASK) {
+       case USB_RECIP_DEVICE:
+               /* Get device status */
+               status = udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED;
+               status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP);
+               break;
+       case USB_RECIP_INTERFACE:
+               if (udc->driver->setup(&udc->gadget, &udc->setup) < 0)
+                       goto stall;
+               break;
+       case USB_RECIP_ENDPOINT:
+               ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK];
+               if (udc->setup.wIndex & USB_DIR_IN) {
+                       if (!ep->ep_usb.caps.dir_in)
+                               goto stall;
+               } else {
+                       if (!ep->ep_usb.caps.dir_out)
+                               goto stall;
+               }
+               if (ep->halted)
+                       status = 1 << USB_ENDPOINT_HALT;
+               break;
+       default:
+               goto stall;
+       }
+
+       status = cpu_to_le16(status);
+       spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2);
+       spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1);
+       return;
+stall:
+       dev_err(udc->dev, "Can't respond to getstatus request\n");
+       spi_wr8(udc, MAX3420_REG_EPSTALLS, STLEP0IN | STLEP0OUT | STLSTAT);
+}
+
+static void max3420_set_clear_feature(struct max3420_udc *udc)
+{
+       struct max3420_ep *ep;
+       int set = udc->setup.bRequest == USB_REQ_SET_FEATURE;
+       unsigned long flags;
+       int id;
+
+       switch (udc->setup.bRequestType) {
+       case USB_RECIP_DEVICE:
+               if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP)
+                       break;
+
+               if (udc->setup.bRequest == USB_REQ_SET_FEATURE)
+                       udc->remote_wkp = 1;
+               else
+                       udc->remote_wkp = 0;
+
+               return spi_ack_ctrl(udc);
+
+       case USB_RECIP_ENDPOINT:
+               if (udc->setup.wValue != USB_ENDPOINT_HALT)
+                       break;
+
+               id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK;
+               ep = &udc->ep[id];
+
+               spin_lock_irqsave(&ep->lock, flags);
+               ep->todo &= ~STALL_EP;
+               if (set)
+                       ep->todo |= STALL;
+               else
+                       ep->todo |= UNSTALL;
+               spin_unlock_irqrestore(&ep->lock, flags);
+
+               spi_max3420_stall(ep);
+               return;
+       default:
+               break;
+       }
+
+       dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n");
+       spi_wr8(udc, MAX3420_REG_EPSTALLS, STLEP0IN | STLEP0OUT | STLSTAT);
+}
+
+static void max3420_handle_setup(struct max3420_udc *udc)
+{
+       struct usb_ctrlrequest setup;
+       u8 addr;
+
+       spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8);
+
+       udc->setup = setup;
+       udc->setup.wValue = cpu_to_le16(setup.wValue);
+       udc->setup.wIndex = cpu_to_le16(setup.wIndex);
+       udc->setup.wLength = cpu_to_le16(setup.wLength);
+
+       switch (udc->setup.bRequest) {
+       case USB_REQ_GET_STATUS:
+               /* Data+Status phase form udc */
+               if ((udc->setup.bRequestType &
+                               (USB_DIR_IN | USB_TYPE_MASK)) !=
+                               (USB_DIR_IN | USB_TYPE_STANDARD)) {
+                       break;
+               }
+               return max3420_getstatus(udc);
+       case USB_REQ_SET_ADDRESS:
+               /* Status phase from udc */
+               if (udc->setup.bRequestType != (USB_DIR_OUT |
+                               USB_TYPE_STANDARD | USB_RECIP_DEVICE)) {
+                       break;
+               }
+               addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1);
+               dev_dbg(udc->dev, "Assigned Address=%d\n", udc->setup.wValue);
+               return;
+       case USB_REQ_CLEAR_FEATURE:
+       case USB_REQ_SET_FEATURE:
+               /* Requests with no data phase, status phase from udc */
+               if ((udc->setup.bRequestType & USB_TYPE_MASK)
+                               != USB_TYPE_STANDARD)
+                       break;
+               return max3420_set_clear_feature(udc);
+       default:
+               break;
+       }
+
+       if (udc->driver->setup(&udc->gadget, &setup) < 0) {
+               /* Stall EP0 */
+               spi_wr8(udc, MAX3420_REG_EPSTALLS,
+                       STLEP0IN | STLEP0OUT | STLSTAT);
+       }
+}
+
+static void max3420_req_done(struct max3420_req *req, int status)
+{
+       struct max3420_ep *ep = req->ep;
+       struct max3420_udc *udc = ep->udc;
+
+       if (req->usb_req.status == -EINPROGRESS)
+               req->usb_req.status = status;
+       else
+               status = req->usb_req.status;
+
+       if (status && status != -ESHUTDOWN)
+               dev_err(udc->dev, "%s done %p, status %d\n",
+                       ep->ep_usb.name, req, status);
+
+       if (req->usb_req.complete)
+               req->usb_req.complete(&ep->ep_usb, &req->usb_req);
+}
+
+static int max3420_do_data(struct max3420_udc *udc, int ep_id, int in)
+{
+       struct max3420_ep *ep = &udc->ep[ep_id];
+       struct max3420_req *req;
+       int done, length, psz;
+       void *buf;
+
+       if (list_empty(&ep->queue))
+               return false;
+
+       req = list_first_entry(&ep->queue, struct max3420_req, queue);
+       buf = req->usb_req.buf + req->usb_req.actual;
+
+       psz = ep->ep_usb.maxpacket;
+       length = req->usb_req.length - req->usb_req.actual;
+       length = min(length, psz);
+
+       if (length == 0) {
+               done = 1;
+               goto xfer_done;
+       }
+
+       done = 0;
+       if (in) {
+               prefetch(buf);
+               spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
+               spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length);
+               if (length < psz)
+                       done = 1;
+       } else {
+               psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id);
+               length = min(length, psz);
+               prefetchw(buf);
+               spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length);
+               if (length < ep->ep_usb.maxpacket)
+                       done = 1;
+       }
+
+       req->usb_req.actual += length;
+
+       if (req->usb_req.actual == req->usb_req.length)
+               done = 1;
+
+xfer_done:
+       if (done) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&ep->lock, flags);
+               list_del_init(&req->queue);
+               spin_unlock_irqrestore(&ep->lock, flags);
+
+               if (ep_id == 0)
+                       spi_ack_ctrl(udc);
+
+               max3420_req_done(req, 0);
+       }
+
+       return true;
+}
+
+static int max3420_handle_irqs(struct max3420_udc *udc)
+{
+       u8 epien, epirq, usbirq, usbien, reg[4];
+       bool ret = false;
+
+       spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4);
+       epirq = reg[0];
+       epien = reg[1];
+       usbirq = reg[2];
+       usbien = reg[3];
+
+       usbirq &= usbien;
+       epirq &= epien;
+
+       if (epirq & SUDAVIRQ) {
+               spi_wr8(udc, MAX3420_REG_EPIRQ, SUDAVIRQ);
+               max3420_handle_setup(udc);
+               return true;
+       }
+
+       if (usbirq & VBUSIRQ) {
+               spi_wr8(udc, MAX3420_REG_USBIRQ, VBUSIRQ);
+               dev_dbg(udc->dev, "Cable plugged in\n");
+               return true;
+       }
+
+       if (usbirq & NOVBUSIRQ) {
+               spi_wr8(udc, MAX3420_REG_USBIRQ, NOVBUSIRQ);
+               dev_dbg(udc->dev, "Cable pulled out\n");
+               return true;
+       }
+
+       if (usbirq & URESIRQ) {
+               spi_wr8(udc, MAX3420_REG_USBIRQ, URESIRQ);
+               dev_dbg(udc->dev, "USB Reset - Start\n");
+               return true;
+       }
+
+       if (usbirq & URESDNIRQ) {
+               spi_wr8(udc, MAX3420_REG_USBIRQ, URESDNIRQ);
+               dev_dbg(udc->dev, "USB Reset - END\n");
+               spi_wr8(udc, MAX3420_REG_USBIEN, URESDNIRQ | URESIRQ);
+               spi_wr8(udc, MAX3420_REG_EPIEN, SUDAVIRQ | IN0BAVIRQ
+                       | OUT0DAVIRQ);
+               return true;
+       }
+
+       if (usbirq & SUSPIRQ) {
+               spi_wr8(udc, MAX3420_REG_USBIRQ, SUSPIRQ);
+               dev_dbg(udc->dev, "USB Suspend - Enter\n");
+               udc->suspended = true;
+               return true;
+       }
+
+       if (usbirq & BUSACTIRQ) {
+               spi_wr8(udc, MAX3420_REG_USBIRQ, BUSACTIRQ);
+               dev_dbg(udc->dev, "USB Suspend - Exit\n");
+               udc->suspended = false;
+               return true;
+       }
+
+       if (usbirq & RWUDNIRQ) {
+               spi_wr8(udc, MAX3420_REG_USBIRQ, RWUDNIRQ);
+               dev_dbg(udc->dev, "Asked Host to wakeup\n");
+               return true;
+       }
+
+       if (usbirq & OSCOKIRQ) {
+               spi_wr8(udc, MAX3420_REG_USBIRQ, OSCOKIRQ);
+               dev_dbg(udc->dev, "Osc stabilized, start work\n");
+               return true;
+       }
+
+       if (epirq & OUT0DAVIRQ && max3420_do_data(udc, 0, 0)) {
+               spi_wr8_ack(udc, MAX3420_REG_EPIRQ, OUT0DAVIRQ, 1);
+               ret = true;
+       }
+
+       if (epirq & IN0BAVIRQ && max3420_do_data(udc, 0, 1))
+               ret = true;
+
+       if (epirq & OUT1DAVIRQ && max3420_do_data(udc, 1, 0)) {
+               spi_wr8_ack(udc, MAX3420_REG_EPIRQ, OUT1DAVIRQ, 1);
+               ret = true;
+       }
+
+       if (epirq & IN2BAVIRQ && max3420_do_data(udc, 2, 1))
+               ret = true;
+
+       if (epirq & IN3BAVIRQ && max3420_do_data(udc, 3, 1))
+               ret = true;
+
+       return ret;
+}
+
+static int max3420_thread(void *dev_id)
+{
+       struct max3420_udc *udc = dev_id;
+       struct spi_device *spi = udc->spi;
+       int i, loop_again = 1;
+       unsigned long flags;
+
+       while (!kthread_should_stop()) {
+               if (!loop_again) {
+                       ktime_t kt = ns_to_ktime(1000 * 1000 * 250); /* 250ms */
+
+                       set_current_state(TASK_INTERRUPTIBLE);
+
+                       spin_lock_irqsave(&udc->lock, flags);
+                       if (udc->todo & ENABLE_IRQ) {
+                               enable_irq(spi->irq);
+                               udc->todo &= ~ENABLE_IRQ;
+                       }
+                       spin_unlock_irqrestore(&udc->lock, flags);
+
+                       schedule_hrtimeout(&kt, HRTIMER_MODE_REL);
+               }
+               loop_again = 0;
+
+               mutex_lock(&udc->spi_bus_mutex);
+
+               /* If bus-vbus_active and disconnected */
+               if (!udc->vbus_active || !udc->softconnect)
+                       goto loop;
+
+               if (max3420_start(udc)) {
+                       loop_again = 1;
+                       goto loop;
+               }
+
+               if (max3420_handle_irqs(udc)) {
+                       loop_again = 1;
+                       goto loop;
+               }
+
+               if (spi_max3420_rwkup(udc)) {
+                       loop_again = 1;
+                       goto loop;
+               }
+
+               max3420_do_data(udc, 0, 1); /* get done with the EP0 ZLP */
+
+               for (i = 1; i < MAX3420_MAX_EPS; i++) {
+                       struct max3420_ep *ep = &udc->ep[i];
+
+                       if (spi_max3420_enable(ep))
+                               loop_again = 1;
+                       if (spi_max3420_stall(ep))
+                               loop_again = 1;
+               }
+loop:
+               mutex_unlock(&udc->spi_bus_mutex);
+       }
+
+       set_current_state(TASK_RUNNING);
+       dev_info(udc->dev, "SPI thread exiting");
+       return 0;
+}
+
+static int max3420_ep_set_halt(struct usb_ep *_ep, int stall)
+{
+       struct max3420_ep *ep = to_max3420_ep(_ep);
+       struct max3420_udc *udc = ep->udc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       ep->todo &= ~STALL_EP;
+       if (stall)
+               ep->todo |= STALL;
+       else
+               ep->todo |= UNSTALL;
+
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       wake_up_process(udc->thread_task);
+
+       dev_dbg(udc->dev, "%sStall %s\n", stall ? "" : "Un", ep->name);
+       return 0;
+}
+
+static int __max3420_ep_enable(struct max3420_ep *ep,
+                              const struct usb_endpoint_descriptor *desc)
+{
+       unsigned int maxp = usb_endpoint_maxp(desc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ep->lock, flags);
+       ep->ep_usb.desc = desc;
+       ep->ep_usb.maxpacket = maxp;
+
+       ep->todo &= ~ENABLE_EP;
+       ep->todo |= ENABLE;
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       return 0;
+}
+
+static int max3420_ep_enable(struct usb_ep *_ep,
+                            const struct usb_endpoint_descriptor *desc)
+{
+       struct max3420_ep *ep = to_max3420_ep(_ep);
+       struct max3420_udc *udc = ep->udc;
+
+       __max3420_ep_enable(ep, desc);
+
+       wake_up_process(udc->thread_task);
+
+       return 0;
+}
+
+static void max3420_nuke(struct max3420_ep *ep, int status)
+{
+       struct max3420_req *req, *r;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       list_for_each_entry_safe(req, r, &ep->queue, queue) {
+               list_del_init(&req->queue);
+
+               spin_unlock_irqrestore(&ep->lock, flags);
+               max3420_req_done(req, status);
+               spin_lock_irqsave(&ep->lock, flags);
+       }
+
+       spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void __max3420_ep_disable(struct max3420_ep *ep)
+{
+       struct max3420_udc *udc = ep->udc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       ep->ep_usb.desc = NULL;
+
+       ep->todo &= ~ENABLE_EP;
+       ep->todo |= DISABLE;
+
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       dev_dbg(udc->dev, "Disabled %s\n", ep->name);
+}
+
+static int max3420_ep_disable(struct usb_ep *_ep)
+{
+       struct max3420_ep *ep = to_max3420_ep(_ep);
+       struct max3420_udc *udc = ep->udc;
+
+       max3420_nuke(ep, -ESHUTDOWN);
+
+       __max3420_ep_disable(ep);
+
+       wake_up_process(udc->thread_task);
+
+       return 0;
+}
+
+static struct usb_request *max3420_alloc_request(struct usb_ep *_ep,
+                                                gfp_t gfp_flags)
+{
+       struct max3420_ep *ep = to_max3420_ep(_ep);
+       struct max3420_req *req;
+
+       req = kzalloc(sizeof(*req), gfp_flags);
+       if (!req)
+               return NULL;
+
+       req->ep = ep;
+
+       return &req->usb_req;
+}
+
+static void max3420_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+       kfree(to_max3420_req(_req));
+}
+
+static int max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+                           gfp_t ignored)
+{
+       struct max3420_req *req = to_max3420_req(_req);
+       struct max3420_ep *ep  = to_max3420_ep(_ep);
+       struct max3420_udc *udc = ep->udc;
+       unsigned long flags;
+
+       _req->status = -EINPROGRESS;
+       _req->actual = 0;
+
+       spin_lock_irqsave(&ep->lock, flags);
+       list_add_tail(&req->queue, &ep->queue);
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       wake_up_process(udc->thread_task);
+       return 0;
+}
+
+static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct max3420_req *t, *req = to_max3420_req(_req);
+       struct max3420_ep *ep = to_max3420_ep(_ep);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       /* Pluck the descriptor from queue */
+       list_for_each_entry(t, &ep->queue, queue)
+               if (t == req) {
+                       list_del_init(&req->queue);
+                       break;
+               }
+
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       if (t == req)
+               max3420_req_done(req, -ECONNRESET);
+
+       return 0;
+}
+
+static const struct usb_ep_ops max3420_ep_ops = {
+       .enable         = max3420_ep_enable,
+       .disable        = max3420_ep_disable,
+       .alloc_request  = max3420_alloc_request,
+       .free_request   = max3420_free_request,
+       .queue          = max3420_ep_queue,
+       .dequeue        = max3420_ep_dequeue,
+       .set_halt       = max3420_ep_set_halt,
+};
+
+static int max3420_wakeup(struct usb_gadget *gadget)
+{
+       struct max3420_udc *udc = to_udc(gadget);
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       /* Only if wakeup allowed by host */
+       if (udc->remote_wkp) {
+               udc->todo |= REMOTE_WAKEUP;
+               ret = 0;
+       }
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       if (udc->thread_task &&
+           udc->thread_task->state != TASK_RUNNING)
+               wake_up_process(udc->thread_task);
+       return ret;
+}
+
+static int max3420_udc_start(struct usb_gadget *gadget,
+                            struct usb_gadget_driver *driver)
+{
+       struct max3420_udc *udc = to_udc(gadget);
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       /* hook up the driver */
+       driver->driver.bus = NULL;
+       udc->driver = driver;
+       udc->gadget.speed = USB_SPEED_FULL;
+
+       udc->gadget.is_selfpowered = udc->is_selfpowered;
+       udc->remote_wkp = 0;
+       udc->softconnect = true;
+       udc->todo |= UDC_START;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       if (udc->thread_task &&
+           udc->thread_task->state != TASK_RUNNING)
+               wake_up_process(udc->thread_task);
+
+       return 0;
+}
+
+static int max3420_udc_stop(struct usb_gadget *gadget)
+{
+       struct max3420_udc *udc = to_udc(gadget);
+       unsigned long flags;
+
+       spin_lock_irqsave(&udc->lock, flags);
+       udc->is_selfpowered = udc->gadget.is_selfpowered;
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       udc->driver = NULL;
+       udc->softconnect = false;
+       udc->todo |= UDC_START;
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       if (udc->thread_task &&
+           udc->thread_task->state != TASK_RUNNING)
+               wake_up_process(udc->thread_task);
+
+       return 0;
+}
+
+static const struct usb_gadget_ops max3420_udc_ops = {
+       .udc_start      = max3420_udc_start,
+       .udc_stop       = max3420_udc_stop,
+       .wakeup         = max3420_wakeup,
+};
+
+static void max3420_eps_init(struct max3420_udc *udc)
+{
+       int idx;
+
+       INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+       for (idx = 0; idx < MAX3420_MAX_EPS; idx++) {
+               struct max3420_ep *ep = &udc->ep[idx];
+
+               spin_lock_init(&ep->lock);
+               INIT_LIST_HEAD(&ep->queue);
+
+               ep->udc = udc;
+               ep->id = idx;
+               ep->halted = 0;
+               ep->maxpacket = 0;
+               ep->ep_usb.name = ep->name;
+               ep->ep_usb.ops = &max3420_ep_ops;
+               usb_ep_set_maxpacket_limit(&ep->ep_usb, MAX3420_EP_MAX_PACKET);
+
+               if (idx == 0) { /* For EP0 */
+                       ep->ep_usb.desc = &ep0_desc;
+                       ep->ep_usb.maxpacket = usb_endpoint_maxp(&ep0_desc);
+                       ep->ep_usb.caps.type_control = true;
+                       ep->ep_usb.caps.dir_in = true;
+                       ep->ep_usb.caps.dir_out = true;
+                       snprintf(ep->name, MAX3420_EPNAME_SIZE, "ep0");
+                       continue;
+               }
+
+               if (idx == 1) { /* EP1 is OUT */
+                       ep->ep_usb.caps.dir_in = false;
+                       ep->ep_usb.caps.dir_out = true;
+                       snprintf(ep->name, MAX3420_EPNAME_SIZE, "ep1-bulk-out");
+               } else { /* EP2 & EP3 are IN */
+                       ep->ep_usb.caps.dir_in = true;
+                       ep->ep_usb.caps.dir_out = false;
+                       snprintf(ep->name, MAX3420_EPNAME_SIZE,
+                                "ep%d-bulk-in", idx);
+               }
+               ep->ep_usb.caps.type_iso = false;
+               ep->ep_usb.caps.type_int = false;
+               ep->ep_usb.caps.type_bulk = true;
+
+               list_add_tail(&ep->ep_usb.ep_list,
+                             &udc->gadget.ep_list);
+       }
+}
+
+static int max3420_probe(struct spi_device *spi)
+{
+       struct max3420_udc *udc;
+       int err, irq;
+       u8 reg[8];
+
+       if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
+               dev_err(&spi->dev, "UDC needs full duplex to work\n");
+               return -EINVAL;
+       }
+
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+
+       err = spi_setup(spi);
+       if (err) {
+               dev_err(&spi->dev, "Unable to setup SPI bus\n");
+               return -EFAULT;
+       }
+
+       udc = devm_kzalloc(&spi->dev, sizeof(*udc), GFP_KERNEL);
+       if (!udc)
+               return -ENOMEM;
+
+       udc->spi = spi;
+
+       udc->remote_wkp = 0;
+
+       /* Setup gadget structure */
+       udc->gadget.ops = &max3420_udc_ops;
+       udc->gadget.max_speed = USB_SPEED_FULL;
+       udc->gadget.speed = USB_SPEED_UNKNOWN;
+       udc->gadget.ep0 = &udc->ep[0].ep_usb;
+       udc->gadget.name = driver_name;
+
+       spin_lock_init(&udc->lock);
+       mutex_init(&udc->spi_bus_mutex);
+
+       udc->ep0req.ep = &udc->ep[0];
+       udc->ep0req.usb_req.buf = udc->ep0buf;
+       INIT_LIST_HEAD(&udc->ep0req.queue);
+
+       /* setup Endpoints */
+       max3420_eps_init(udc);
+
+       /* configure SPI */
+       spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8);
+       spi_wr8(udc, MAX3420_REG_PINCTL, FDUPSPI);
+
+       err = usb_add_gadget_udc(&spi->dev, &udc->gadget);
+       if (err)
+               return err;
+
+       udc->dev = &udc->gadget.dev;
+
+       spi_set_drvdata(spi, udc);
+
+       irq = of_irq_get_byname(spi->dev.of_node, "udc");
+       err = devm_request_irq(&spi->dev, irq, max3420_irq_handler, 0,
+                              "max3420", udc);
+       if (err < 0)
+               return err;
+
+       udc->thread_task = kthread_create(max3420_thread, udc,
+                                         "max3420-thread");
+       if (IS_ERR(udc->thread_task))
+               return PTR_ERR(udc->thread_task);
+
+       irq = of_irq_get_byname(spi->dev.of_node, "vbus");
+       if (irq <= 0) { /* no vbus irq implies self-powered design */
+               udc->is_selfpowered = 1;
+               udc->vbus_active = true;
+               udc->todo |= UDC_START;
+               usb_udc_vbus_handler(&udc->gadget, udc->vbus_active);
+               usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED);
+               max3420_start(udc);
+       } else {
+               udc->is_selfpowered = 0;
+               /* Detect current vbus status */
+               spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8);
+               if (reg[7] != 0xff)
+                       udc->vbus_active = true;
+
+               err = devm_request_irq(&spi->dev, irq,
+                                      max3420_vbus_handler, 0, "vbus", udc);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int max3420_remove(struct spi_device *spi)
+{
+       struct max3420_udc *udc = spi_get_drvdata(spi);
+       unsigned long flags;
+
+       usb_del_gadget_udc(&udc->gadget);
+
+       spin_lock_irqsave(&udc->lock, flags);
+
+       kthread_stop(udc->thread_task);
+
+       spin_unlock_irqrestore(&udc->lock, flags);
+
+       return 0;
+}
+
+static const struct of_device_id max3420_udc_of_match[] = {
+       { .compatible = "maxim,max3420-udc"},
+       { .compatible = "maxim,max3421-udc"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, max3420_udc_of_match);
+
+static struct spi_driver max3420_driver = {
+       .driver = {
+               .name = "max3420-udc",
+               .of_match_table = of_match_ptr(max3420_udc_of_match),
+       },
+       .probe = max3420_probe,
+       .remove = max3420_remove,
+};
+
+module_spi_driver(max3420_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
+MODULE_LICENSE("GPL");
index 1fd1b91..5eff85e 100644 (file)
@@ -2861,6 +2861,8 @@ static void ep_clear_seqnum(struct net2280_ep *ep)
 static void handle_stat0_irqs_superspeed(struct net2280 *dev,
                struct net2280_ep *ep, struct usb_ctrlrequest r)
 {
+       struct net2280_ep *e;
+       u16 status;
        int tmp = 0;
 
 #define        w_value         le16_to_cpu(r.wValue)
@@ -2868,9 +2870,6 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
 #define        w_length        le16_to_cpu(r.wLength)
 
        switch (r.bRequest) {
-               struct net2280_ep *e;
-               u16 status;
-
        case USB_REQ_SET_CONFIGURATION:
                dev->addressed_state = !w_value;
                goto usb3_delegate;
@@ -3857,7 +3856,7 @@ MODULE_DEVICE_TABLE(pci, pci_ids);
 
 /* pci driver glue; this is a "new style" PCI driver module */
 static struct pci_driver net2280_pci_driver = {
-       .name =         (char *) driver_name,
+       .name =         driver_name,
        .id_table =     pci_ids,
 
        .probe =        net2280_probe,
index bd12417..bf87c6c 100644 (file)
@@ -3001,7 +3001,7 @@ static struct platform_driver udc_driver = {
        .suspend        = omap_udc_suspend,
        .resume         = omap_udc_resume,
        .driver         = {
-               .name   = (char *) driver_name,
+               .name   = driver_name,
        },
 };
 
index 582a161..537094b 100644 (file)
@@ -1968,7 +1968,7 @@ clean_up2:
 static struct platform_driver r8a66597_driver = {
        .remove =       r8a66597_remove,
        .driver         = {
-               .name = (char *) udc_name,
+               .name = udc_name,
        },
 };
 
index c5c3c14..0c418ce 100644 (file)
@@ -2355,14 +2355,14 @@ static const struct usb_gadget_ops renesas_usb3_gadget_ops = {
        .set_selfpowered        = renesas_usb3_set_selfpowered,
 };
 
-static enum usb_role renesas_usb3_role_switch_get(struct device *dev)
+static enum usb_role renesas_usb3_role_switch_get(struct usb_role_switch *sw)
 {
-       struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+       struct renesas_usb3 *usb3 = usb_role_switch_get_drvdata(sw);
        enum usb_role cur_role;
 
-       pm_runtime_get_sync(dev);
+       pm_runtime_get_sync(usb3_to_dev(usb3));
        cur_role = usb3_is_host(usb3) ? USB_ROLE_HOST : USB_ROLE_DEVICE;
-       pm_runtime_put(dev);
+       pm_runtime_put(usb3_to_dev(usb3));
 
        return cur_role;
 }
@@ -2372,7 +2372,7 @@ static void handle_ext_role_switch_states(struct device *dev,
 {
        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);
+       enum usb_role cur_role = renesas_usb3_role_switch_get(usb3->role_sw);
 
        switch (role) {
        case USB_ROLE_NONE:
@@ -2424,7 +2424,7 @@ static void handle_role_switch_states(struct device *dev,
 {
        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);
+       enum usb_role cur_role = renesas_usb3_role_switch_get(usb3->role_sw);
 
        if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) {
                device_release_driver(host);
@@ -2438,19 +2438,19 @@ static void handle_role_switch_states(struct device *dev,
        }
 }
 
-static int renesas_usb3_role_switch_set(struct device *dev,
+static int renesas_usb3_role_switch_set(struct usb_role_switch *sw,
                                        enum usb_role role)
 {
-       struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+       struct renesas_usb3 *usb3 = usb_role_switch_get_drvdata(sw);
 
-       pm_runtime_get_sync(dev);
+       pm_runtime_get_sync(usb3_to_dev(usb3));
 
        if (usb3->role_sw_by_connector)
-               handle_ext_role_switch_states(dev, role);
+               handle_ext_role_switch_states(usb3_to_dev(usb3), role);
        else
-               handle_role_switch_states(dev, role);
+               handle_role_switch_states(usb3_to_dev(usb3), role);
 
-       pm_runtime_put(dev);
+       pm_runtime_put(usb3_to_dev(usb3));
 
        return 0;
 }
@@ -2831,6 +2831,8 @@ static int renesas_usb3_probe(struct platform_device *pdev)
                renesas_usb3_role_switch_desc.fwnode = dev_fwnode(&pdev->dev);
        }
 
+       renesas_usb3_role_switch_desc.driver_data = usb3;
+
        INIT_WORK(&usb3->role_work, renesas_usb3_role_work);
        usb3->role_sw = usb_role_switch_register(&pdev->dev,
                                        &renesas_usb3_role_switch_desc);
@@ -2906,7 +2908,7 @@ static struct platform_driver renesas_usb3_driver = {
        .probe          = renesas_usb3_probe,
        .remove         = renesas_usb3_remove,
        .driver         = {
-               .name = (char *)udc_name,
+               .name = udc_name,
                .pm             = &renesas_usb3_pm_ops,
                .of_match_table = of_match_ptr(usb3_of_match),
        },
index 21252fb..aaca1b0 100644 (file)
@@ -1285,7 +1285,8 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
                                 hsudc->supplies);
        if (ret != 0) {
-               dev_err(dev, "failed to request supplies: %d\n", ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to request supplies: %d\n", ret);
                goto err_supplies;
        }
 
index 634c2c1..52a6add 100644 (file)
@@ -26,7 +26,9 @@
 #include <linux/reset.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
 #include <linux/usb/role.h>
+#include <linux/usb/phy.h>
 #include <linux/workqueue.h>
 
 /* XUSB_DEV registers */
@@ -477,17 +479,21 @@ struct tegra_xudc {
 
        struct clk_bulk_data *clks;
 
-       enum usb_role device_mode;
-       struct usb_role_switch *usb_role_sw;
+       bool device_mode;
        struct work_struct usb_role_sw_work;
 
-       struct phy *usb3_phy;
-       struct phy *utmi_phy;
+       struct phy **usb3_phy;
+       struct phy *curr_usb3_phy;
+       struct phy **utmi_phy;
+       struct phy *curr_utmi_phy;
 
        struct tegra_xudc_save_regs saved_regs;
        bool suspended;
        bool powergated;
 
+       struct usb_phy **usbphy;
+       struct notifier_block vbus_nb;
+
        struct completion disconnect_complete;
 
        bool selfpowered;
@@ -517,6 +523,7 @@ struct tegra_xudc_soc {
        unsigned int num_supplies;
        const char * const *clock_names;
        unsigned int num_clks;
+       unsigned int num_phys;
        bool u1_enable;
        bool u2_enable;
        bool lpm_enable;
@@ -598,19 +605,18 @@ static void tegra_xudc_device_mode_on(struct tegra_xudc *xudc)
 
        pm_runtime_get_sync(xudc->dev);
 
-       err = phy_power_on(xudc->utmi_phy);
+       err = phy_power_on(xudc->curr_utmi_phy);
        if (err < 0)
                dev_err(xudc->dev, "utmi power on failed %d\n", err);
 
-       err = phy_power_on(xudc->usb3_phy);
+       err = phy_power_on(xudc->curr_usb3_phy);
        if (err < 0)
                dev_err(xudc->dev, "usb3 phy power on failed %d\n", err);
 
        dev_dbg(xudc->dev, "device mode on\n");
 
-       tegra_xusb_padctl_set_vbus_override(xudc->padctl, true);
-
-       xudc->device_mode = USB_ROLE_DEVICE;
+       phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG,
+                        USB_ROLE_DEVICE);
 }
 
 static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
@@ -625,7 +631,7 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
 
        reinit_completion(&xudc->disconnect_complete);
 
-       tegra_xusb_padctl_set_vbus_override(xudc->padctl, false);
+       phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG, USB_ROLE_NONE);
 
        pls = (xudc_readl(xudc, PORTSC) & PORTSC_PLS_MASK) >>
                PORTSC_PLS_SHIFT;
@@ -643,8 +649,6 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
                xudc_writel(xudc, val, PORTSC);
        }
 
-       xudc->device_mode = USB_ROLE_NONE;
-
        /* Wait for disconnect event. */
        if (connected)
                wait_for_completion(&xudc->disconnect_complete);
@@ -652,11 +656,11 @@ static void tegra_xudc_device_mode_off(struct tegra_xudc *xudc)
        /* Make sure interrupt handler has completed before powergating. */
        synchronize_irq(xudc->irq);
 
-       err = phy_power_off(xudc->utmi_phy);
+       err = phy_power_off(xudc->curr_utmi_phy);
        if (err < 0)
                dev_err(xudc->dev, "utmi_phy power off failed %d\n", err);
 
-       err = phy_power_off(xudc->usb3_phy);
+       err = phy_power_off(xudc->curr_usb3_phy);
        if (err < 0)
                dev_err(xudc->dev, "usb3_phy power off failed %d\n", err);
 
@@ -668,29 +672,57 @@ static void tegra_xudc_usb_role_sw_work(struct work_struct *work)
        struct tegra_xudc *xudc = container_of(work, struct tegra_xudc,
                                               usb_role_sw_work);
 
-       if (!xudc->usb_role_sw ||
-               usb_role_switch_get_role(xudc->usb_role_sw) == USB_ROLE_DEVICE)
+       if (xudc->device_mode)
                tegra_xudc_device_mode_on(xudc);
        else
                tegra_xudc_device_mode_off(xudc);
+}
+
+static int tegra_xudc_get_phy_index(struct tegra_xudc *xudc,
+                                             struct usb_phy *usbphy)
+{
+       unsigned int i;
 
+       for (i = 0; i < xudc->soc->num_phys; i++) {
+               if (xudc->usbphy[i] && usbphy == xudc->usbphy[i])
+                       return i;
+       }
+
+       dev_info(xudc->dev, "phy index could not be found for shared USB PHY");
+       return -1;
 }
 
-static int tegra_xudc_usb_role_sw_set(struct device *dev, enum usb_role role)
+static int tegra_xudc_vbus_notify(struct notifier_block *nb,
+                                        unsigned long action, void *data)
 {
-       struct tegra_xudc *xudc = dev_get_drvdata(dev);
-       unsigned long flags;
+       struct tegra_xudc *xudc = container_of(nb, struct tegra_xudc,
+                                              vbus_nb);
+       struct usb_phy *usbphy = (struct usb_phy *)data;
+       int phy_index;
 
-       dev_dbg(dev, "%s role is %d\n", __func__, role);
+       dev_dbg(xudc->dev, "%s(): event is %d\n", __func__, usbphy->last_event);
 
-       spin_lock_irqsave(&xudc->lock, flags);
+       if ((xudc->device_mode && usbphy->last_event == USB_EVENT_VBUS) ||
+           (!xudc->device_mode && usbphy->last_event != USB_EVENT_VBUS)) {
+               dev_dbg(xudc->dev, "Same role(%d) received. Ignore",
+                       xudc->device_mode);
+               return NOTIFY_OK;
+       }
 
-       if (!xudc->suspended)
-               schedule_work(&xudc->usb_role_sw_work);
+       xudc->device_mode = (usbphy->last_event == USB_EVENT_VBUS) ? true :
+                                                                    false;
 
-       spin_unlock_irqrestore(&xudc->lock, flags);
+       phy_index = tegra_xudc_get_phy_index(xudc, usbphy);
+       dev_dbg(xudc->dev, "%s(): current phy index is %d\n", __func__,
+               phy_index);
 
-       return 0;
+       if (!xudc->suspended && phy_index != -1) {
+               xudc->curr_utmi_phy = xudc->utmi_phy[phy_index];
+               xudc->curr_usb3_phy = xudc->usb3_phy[phy_index];
+               schedule_work(&xudc->usb_role_sw_work);
+       }
+
+       return NOTIFY_OK;
 }
 
 static void tegra_xudc_plc_reset_work(struct work_struct *work)
@@ -708,9 +740,11 @@ static void tegra_xudc_plc_reset_work(struct work_struct *work)
 
                if (pls == PORTSC_PLS_INACTIVE) {
                        dev_info(xudc->dev, "PLS = Inactive. Toggle VBUS\n");
-                       tegra_xusb_padctl_set_vbus_override(xudc->padctl,
-                                                             false);
-                       tegra_xusb_padctl_set_vbus_override(xudc->padctl, true);
+                       phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG,
+                                        USB_ROLE_NONE);
+                       phy_set_mode_ext(xudc->curr_utmi_phy, PHY_MODE_USB_OTG,
+                                        USB_ROLE_DEVICE);
+
                        xudc->wait_csc = false;
                }
        }
@@ -729,8 +763,7 @@ static void tegra_xudc_port_reset_war_work(struct work_struct *work)
 
        spin_lock_irqsave(&xudc->lock, flags);
 
-       if ((xudc->device_mode == USB_ROLE_DEVICE)
-                             && xudc->wait_for_sec_prc) {
+       if (xudc->device_mode && xudc->wait_for_sec_prc) {
                pls = (xudc_readl(xudc, PORTSC) & PORTSC_PLS_MASK) >>
                        PORTSC_PLS_SHIFT;
                dev_dbg(xudc->dev, "pls = %x\n", pls);
@@ -738,7 +771,8 @@ static void tegra_xudc_port_reset_war_work(struct work_struct *work)
                if (pls == PORTSC_PLS_DISABLED) {
                        dev_dbg(xudc->dev, "toggle vbus\n");
                        /* PRC doesn't complete in 100ms, toggle the vbus */
-                       ret = tegra_phy_xusb_utmi_port_reset(xudc->utmi_phy);
+                       ret = tegra_phy_xusb_utmi_port_reset(
+                               xudc->curr_utmi_phy);
                        if (ret == 1)
                                xudc->wait_for_sec_prc = 0;
                }
@@ -1927,6 +1961,7 @@ static int tegra_xudc_gadget_start(struct usb_gadget *gadget,
        unsigned long flags;
        u32 val;
        int ret;
+       unsigned int i;
 
        if (!driver)
                return -EINVAL;
@@ -1962,6 +1997,10 @@ static int tegra_xudc_gadget_start(struct usb_gadget *gadget,
                xudc_writel(xudc, val, CTRL);
        }
 
+       for (i = 0; i < xudc->soc->num_phys; i++)
+               if (xudc->usbphy[i])
+                       otg_set_peripheral(xudc->usbphy[i]->otg, gadget);
+
        xudc->driver = driver;
 unlock:
        dev_dbg(xudc->dev, "%s: ret value is %d", __func__, ret);
@@ -1977,11 +2016,16 @@ static int tegra_xudc_gadget_stop(struct usb_gadget *gadget)
        struct tegra_xudc *xudc = to_xudc(gadget);
        unsigned long flags;
        u32 val;
+       unsigned int i;
 
        pm_runtime_get_sync(xudc->dev);
 
        spin_lock_irqsave(&xudc->lock, flags);
 
+       for (i = 0; i < xudc->soc->num_phys; i++)
+               if (xudc->usbphy[i])
+                       otg_set_peripheral(xudc->usbphy[i]->otg, NULL);
+
        val = xudc_readl(xudc, CTRL);
        val &= ~(CTRL_IE | CTRL_ENABLE);
        xudc_writel(xudc, val, CTRL);
@@ -3314,33 +3358,120 @@ static void tegra_xudc_device_params_init(struct tegra_xudc *xudc)
        xudc_writel(xudc, val, CFG_DEV_SSPI_XFER);
 }
 
-static int tegra_xudc_phy_init(struct tegra_xudc *xudc)
+static int tegra_xudc_phy_get(struct tegra_xudc *xudc)
 {
-       int err;
+       int err = 0, usb3;
+       unsigned int i;
 
-       err = phy_init(xudc->utmi_phy);
-       if (err < 0) {
-               dev_err(xudc->dev, "utmi phy init failed: %d\n", err);
-               return err;
-       }
+       xudc->utmi_phy = devm_kcalloc(xudc->dev, xudc->soc->num_phys,
+                                          sizeof(*xudc->utmi_phy), GFP_KERNEL);
+       if (!xudc->utmi_phy)
+               return -ENOMEM;
 
-       err = phy_init(xudc->usb3_phy);
-       if (err < 0) {
-               dev_err(xudc->dev, "usb3 phy init failed: %d\n", err);
-               goto exit_utmi_phy;
+       xudc->usb3_phy = devm_kcalloc(xudc->dev, xudc->soc->num_phys,
+                                          sizeof(*xudc->usb3_phy), GFP_KERNEL);
+       if (!xudc->usb3_phy)
+               return -ENOMEM;
+
+       xudc->usbphy = devm_kcalloc(xudc->dev, xudc->soc->num_phys,
+                                          sizeof(*xudc->usbphy), GFP_KERNEL);
+       if (!xudc->usbphy)
+               return -ENOMEM;
+
+       xudc->vbus_nb.notifier_call = tegra_xudc_vbus_notify;
+
+       for (i = 0; i < xudc->soc->num_phys; i++) {
+               char phy_name[] = "usb.-.";
+
+               /* Get USB2 phy */
+               snprintf(phy_name, sizeof(phy_name), "usb2-%d", i);
+               xudc->utmi_phy[i] = devm_phy_optional_get(xudc->dev, phy_name);
+               if (IS_ERR(xudc->utmi_phy[i])) {
+                       err = PTR_ERR(xudc->utmi_phy[i]);
+                       if (err != -EPROBE_DEFER)
+                               dev_err(xudc->dev, "failed to get usb2-%d phy: %d\n",
+                                       i, err);
+
+                       goto clean_up;
+               } else if (xudc->utmi_phy[i]) {
+                       /* Get usb-phy, if utmi phy is available */
+                       xudc->usbphy[i] = devm_usb_get_phy_by_node(xudc->dev,
+                                               xudc->utmi_phy[i]->dev.of_node,
+                                               &xudc->vbus_nb);
+                       if (IS_ERR(xudc->usbphy[i])) {
+                               err = PTR_ERR(xudc->usbphy[i]);
+                               dev_err(xudc->dev, "failed to get usbphy-%d: %d\n",
+                                       i, err);
+                               goto clean_up;
+                       }
+               } else if (!xudc->utmi_phy[i]) {
+                       /* if utmi phy is not available, ignore USB3 phy get */
+                       continue;
+               }
+
+               /* Get USB3 phy */
+               usb3 = tegra_xusb_padctl_get_usb3_companion(xudc->padctl, i);
+               if (usb3 < 0)
+                       continue;
+
+               snprintf(phy_name, sizeof(phy_name), "usb3-%d", usb3);
+               xudc->usb3_phy[i] = devm_phy_optional_get(xudc->dev, phy_name);
+               if (IS_ERR(xudc->usb3_phy[i])) {
+                       err = PTR_ERR(xudc->usb3_phy[i]);
+                       if (err != -EPROBE_DEFER)
+                               dev_err(xudc->dev, "failed to get usb3-%d phy: %d\n",
+                                       usb3, err);
+
+                       goto clean_up;
+               } else if (xudc->usb3_phy[i])
+                       dev_dbg(xudc->dev, "usb3_phy-%d registered", usb3);
        }
 
-       return 0;
+       return err;
+
+clean_up:
+       for (i = 0; i < xudc->soc->num_phys; i++) {
+               xudc->usb3_phy[i] = NULL;
+               xudc->utmi_phy[i] = NULL;
+               xudc->usbphy[i] = NULL;
+       }
 
-exit_utmi_phy:
-       phy_exit(xudc->utmi_phy);
        return err;
 }
 
 static void tegra_xudc_phy_exit(struct tegra_xudc *xudc)
 {
-       phy_exit(xudc->usb3_phy);
-       phy_exit(xudc->utmi_phy);
+       unsigned int i;
+
+       for (i = 0; i < xudc->soc->num_phys; i++) {
+               phy_exit(xudc->usb3_phy[i]);
+               phy_exit(xudc->utmi_phy[i]);
+       }
+}
+
+static int tegra_xudc_phy_init(struct tegra_xudc *xudc)
+{
+       int err;
+       unsigned int i;
+
+       for (i = 0; i < xudc->soc->num_phys; i++) {
+               err = phy_init(xudc->utmi_phy[i]);
+               if (err < 0) {
+                       dev_err(xudc->dev, "utmi phy init failed: %d\n", err);
+                       goto exit_phy;
+               }
+
+               err = phy_init(xudc->usb3_phy[i]);
+               if (err < 0) {
+                       dev_err(xudc->dev, "usb3 phy init failed: %d\n", err);
+                       goto exit_phy;
+               }
+       }
+       return 0;
+
+exit_phy:
+       tegra_xudc_phy_exit(xudc);
+       return err;
 }
 
 static const char * const tegra210_xudc_supply_names[] = {
@@ -3368,6 +3499,7 @@ static struct tegra_xudc_soc tegra210_xudc_soc_data = {
        .num_supplies = ARRAY_SIZE(tegra210_xudc_supply_names),
        .clock_names = tegra210_xudc_clock_names,
        .num_clks = ARRAY_SIZE(tegra210_xudc_clock_names),
+       .num_phys = 4,
        .u1_enable = false,
        .u2_enable = true,
        .lpm_enable = false,
@@ -3380,6 +3512,7 @@ static struct tegra_xudc_soc tegra210_xudc_soc_data = {
 static struct tegra_xudc_soc tegra186_xudc_soc_data = {
        .clock_names = tegra186_xudc_clock_names,
        .num_clks = ARRAY_SIZE(tegra186_xudc_clock_names),
+       .num_phys = 4,
        .u1_enable = true,
        .u2_enable = true,
        .lpm_enable = false,
@@ -3457,7 +3590,6 @@ static int tegra_xudc_probe(struct platform_device *pdev)
 {
        struct tegra_xudc *xudc;
        struct resource *res;
-       struct usb_role_switch_desc role_sx_desc = { 0 };
        unsigned int i;
        int err;
 
@@ -3492,11 +3624,8 @@ static int tegra_xudc_probe(struct platform_device *pdev)
        }
 
        xudc->irq = platform_get_irq(pdev, 0);
-       if (xudc->irq < 0) {
-               dev_err(xudc->dev, "failed to get IRQ: %d\n",
-                               xudc->irq);
+       if (xudc->irq < 0)
                return xudc->irq;
-       }
 
        err = devm_request_irq(&pdev->dev, xudc->irq, tegra_xudc_irq, 0,
                               dev_name(&pdev->dev), xudc);
@@ -3546,19 +3675,9 @@ static int tegra_xudc_probe(struct platform_device *pdev)
                goto put_padctl;
        }
 
-       xudc->usb3_phy = devm_phy_optional_get(&pdev->dev, "usb3");
-       if (IS_ERR(xudc->usb3_phy)) {
-               err = PTR_ERR(xudc->usb3_phy);
-               dev_err(xudc->dev, "failed to get usb3 phy: %d\n", err);
-               goto disable_regulator;
-       }
-
-       xudc->utmi_phy = devm_phy_optional_get(&pdev->dev, "usb2");
-       if (IS_ERR(xudc->utmi_phy)) {
-               err = PTR_ERR(xudc->utmi_phy);
-               dev_err(xudc->dev, "failed to get usb2 phy: %d\n", err);
+       err = tegra_xudc_phy_get(xudc);
+       if (err)
                goto disable_regulator;
-       }
 
        err = tegra_xudc_powerdomain_init(xudc);
        if (err)
@@ -3587,24 +3706,6 @@ static int tegra_xudc_probe(struct platform_device *pdev)
        INIT_DELAYED_WORK(&xudc->port_reset_war_work,
                                tegra_xudc_port_reset_war_work);
 
-       if (of_property_read_bool(xudc->dev->of_node, "usb-role-switch")) {
-               role_sx_desc.set = tegra_xudc_usb_role_sw_set;
-               role_sx_desc.fwnode = dev_fwnode(xudc->dev);
-
-               xudc->usb_role_sw = usb_role_switch_register(xudc->dev,
-                                                       &role_sx_desc);
-               if (IS_ERR(xudc->usb_role_sw)) {
-                       err = PTR_ERR(xudc->usb_role_sw);
-                       dev_err(xudc->dev, "Failed to register USB role SW: %d",
-                                          err);
-                       goto free_eps;
-               }
-       } else {
-               /* Set the mode as device mode and this keeps phy always ON */
-               dev_info(xudc->dev, "Set usb role to device mode always");
-               schedule_work(&xudc->usb_role_sw_work);
-       }
-
        pm_runtime_enable(&pdev->dev);
 
        xudc->gadget.ops = &tegra_xudc_gadget_ops;
@@ -3639,15 +3740,12 @@ put_padctl:
 static int tegra_xudc_remove(struct platform_device *pdev)
 {
        struct tegra_xudc *xudc = platform_get_drvdata(pdev);
+       unsigned int i;
 
        pm_runtime_get_sync(xudc->dev);
 
        cancel_delayed_work(&xudc->plc_reset_work);
-
-       if (xudc->usb_role_sw) {
-               usb_role_switch_unregister(xudc->usb_role_sw);
-               cancel_work_sync(&xudc->usb_role_sw_work);
-       }
+       cancel_work_sync(&xudc->usb_role_sw_work);
 
        usb_del_gadget_udc(&xudc->gadget);
 
@@ -3658,8 +3756,10 @@ static int tegra_xudc_remove(struct platform_device *pdev)
 
        regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies);
 
-       phy_power_off(xudc->utmi_phy);
-       phy_power_off(xudc->usb3_phy);
+       for (i = 0; i < xudc->soc->num_phys; i++) {
+               phy_power_off(xudc->utmi_phy[i]);
+               phy_power_off(xudc->usb3_phy[i]);
+       }
 
        tegra_xudc_phy_exit(xudc);
 
index bd4f6ef..1300c45 100644 (file)
@@ -110,11 +110,12 @@ static int mv_ehci_probe(struct platform_device *pdev)
        struct resource *r;
        int retval = -ENODEV;
        u32 offset;
+       u32 status;
 
        if (usb_disabled())
                return -ENODEV;
 
-       hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, "mv ehci");
+       hcd = usb_create_hcd(&ehci_platform_hc_driver, &pdev->dev, dev_name(&pdev->dev));
        if (!hcd)
                return -ENOMEM;
 
@@ -213,6 +214,14 @@ static int mv_ehci_probe(struct platform_device *pdev)
                device_wakeup_enable(hcd->self.controller);
        }
 
+       if (of_usb_get_phy_mode(pdev->dev.of_node) == USBPHY_INTERFACE_MODE_HSIC) {
+               status = ehci_readl(ehci, &ehci->regs->port_status[0]);
+               /* These "reserved" bits actually enable HSIC mode. */
+               status |= BIT(25);
+               status &= ~GENMASK(31, 30);
+               ehci_writel(ehci, status, &ehci->regs->port_status[0]);
+       }
+
        dev_info(&pdev->dev,
                 "successful find EHCI device with regs 0x%p irq %d"
                 " working in %s mode\n", hcd->regs, hcd->irq,
index b0882c1..1a48ab1 100644 (file)
@@ -384,7 +384,7 @@ MODULE_DEVICE_TABLE(pci, pci_ids);
 
 /* pci driver glue; this is a "new style" PCI driver module */
 static struct pci_driver ehci_pci_driver = {
-       .name =         (char *) hcd_name,
+       .name =         hcd_name,
        .id_table =     pci_ids,
 
        .probe =        ehci_pci_probe,
index 769749c..e4fc3f6 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/reset.h>
+#include <linux/sys_soc.h>
+#include <linux/timer.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
 #include <linux/usb/ehci_pdriver.h>
@@ -44,6 +46,9 @@ struct ehci_platform_priv {
        struct clk *clks[EHCI_MAX_CLKS];
        struct reset_control *rsts;
        bool reset_on_resume;
+       bool quirk_poll;
+       struct timer_list poll_timer;
+       struct delayed_work poll_work;
 };
 
 static const char hcd_name[] = "ehci-platform";
@@ -118,6 +123,111 @@ static struct usb_ehci_pdata ehci_platform_defaults = {
        .power_off =            ehci_platform_power_off,
 };
 
+/**
+ * quirk_poll_check_port_status - Poll port_status if the device sticks
+ * @ehci: the ehci hcd pointer
+ *
+ * Since EHCI/OHCI controllers on R-Car Gen3 SoCs are possible to be getting
+ * stuck very rarely after a full/low usb device was disconnected. To
+ * detect such a situation, the controllers require a special way which poll
+ * the EHCI PORTSC register.
+ *
+ * Return: true if the controller's port_status indicated getting stuck
+ */
+static bool quirk_poll_check_port_status(struct ehci_hcd *ehci)
+{
+       u32 port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
+
+       if (!(port_status & PORT_OWNER) &&
+            (port_status & PORT_POWER) &&
+           !(port_status & PORT_CONNECT) &&
+            (port_status & PORT_LS_MASK))
+               return true;
+
+       return false;
+}
+
+/**
+ * quirk_poll_rebind_companion - rebind comanion device to recover
+ * @ehci: the ehci hcd pointer
+ *
+ * Since EHCI/OHCI controllers on R-Car Gen3 SoCs are possible to be getting
+ * stuck very rarely after a full/low usb device was disconnected. To
+ * recover from such a situation, the controllers require changing the OHCI
+ * functional state.
+ */
+static void quirk_poll_rebind_companion(struct ehci_hcd *ehci)
+{
+       struct device *companion_dev;
+       struct usb_hcd *hcd = ehci_to_hcd(ehci);
+
+       companion_dev = usb_of_get_companion_dev(hcd->self.controller);
+       if (!companion_dev)
+               return;
+
+       device_release_driver(companion_dev);
+       if (device_attach(companion_dev) < 0)
+               ehci_err(ehci, "%s: failed\n", __func__);
+
+       put_device(companion_dev);
+}
+
+static void quirk_poll_work(struct work_struct *work)
+{
+       struct ehci_platform_priv *priv =
+               container_of(to_delayed_work(work), struct ehci_platform_priv,
+                            poll_work);
+       struct ehci_hcd *ehci = container_of((void *)priv, struct ehci_hcd,
+                                            priv);
+
+       /* check the status twice to reduce misdetection rate */
+       if (!quirk_poll_check_port_status(ehci))
+               return;
+       udelay(10);
+       if (!quirk_poll_check_port_status(ehci))
+               return;
+
+       ehci_dbg(ehci, "%s: detected getting stuck. rebind now!\n", __func__);
+       quirk_poll_rebind_companion(ehci);
+}
+
+static void quirk_poll_timer(struct timer_list *t)
+{
+       struct ehci_platform_priv *priv = from_timer(priv, t, poll_timer);
+       struct ehci_hcd *ehci = container_of((void *)priv, struct ehci_hcd,
+                                            priv);
+
+       if (quirk_poll_check_port_status(ehci)) {
+               /*
+                * Now scheduling the work for testing the port more. Note that
+                * updating the status is possible to be delayed when
+                * reconnection. So, this uses delayed work with 5 ms delay
+                * to avoid misdetection.
+                */
+               schedule_delayed_work(&priv->poll_work, msecs_to_jiffies(5));
+       }
+
+       mod_timer(&priv->poll_timer, jiffies + HZ);
+}
+
+static void quirk_poll_init(struct ehci_platform_priv *priv)
+{
+       INIT_DELAYED_WORK(&priv->poll_work, quirk_poll_work);
+       timer_setup(&priv->poll_timer, quirk_poll_timer, 0);
+       mod_timer(&priv->poll_timer, jiffies + HZ);
+}
+
+static void quirk_poll_end(struct ehci_platform_priv *priv)
+{
+       del_timer_sync(&priv->poll_timer);
+       cancel_delayed_work(&priv->poll_work);
+}
+
+static const struct soc_device_attribute quirk_poll_match[] = {
+       { .family = "R-Car Gen3" },
+       { /* sentinel*/ }
+};
+
 static int ehci_platform_probe(struct platform_device *dev)
 {
        struct usb_hcd *hcd;
@@ -176,6 +286,9 @@ static int ehci_platform_probe(struct platform_device *dev)
                                          "has-transaction-translator"))
                        hcd->has_tt = 1;
 
+               if (soc_device_match(quirk_poll_match))
+                       priv->quirk_poll = true;
+
                for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
                        priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
                        if (IS_ERR(priv->clks[clk])) {
@@ -247,6 +360,9 @@ static int ehci_platform_probe(struct platform_device *dev)
        device_enable_async_suspend(hcd->self.controller);
        platform_set_drvdata(dev, hcd);
 
+       if (priv->quirk_poll)
+               quirk_poll_init(priv);
+
        return err;
 
 err_power:
@@ -273,6 +389,9 @@ static int ehci_platform_remove(struct platform_device *dev)
        struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
        int clk;
 
+       if (priv->quirk_poll)
+               quirk_poll_end(priv);
+
        usb_remove_hcd(hcd);
 
        if (pdata->power_off)
@@ -297,9 +416,13 @@ static int ehci_platform_suspend(struct device *dev)
        struct usb_hcd *hcd = dev_get_drvdata(dev);
        struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
        struct platform_device *pdev = to_platform_device(dev);
+       struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
        bool do_wakeup = device_may_wakeup(dev);
        int ret;
 
+       if (priv->quirk_poll)
+               quirk_poll_end(priv);
+
        ret = ehci_suspend(hcd, do_wakeup);
        if (ret)
                return ret;
@@ -331,6 +454,10 @@ static int ehci_platform_resume(struct device *dev)
        }
 
        ehci_resume(hcd, priv->reset_on_resume);
+
+       if (priv->quirk_poll)
+               quirk_poll_init(priv);
+
        return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
index d6433f2..10d51da 100644 (file)
@@ -282,7 +282,7 @@ done:
 struct dma_aligned_buffer {
        void *kmalloc_ptr;
        void *old_xfer_buffer;
-       u8 data[0];
+       u8 data[];
 };
 
 static void free_dma_aligned_buffer(struct urb *urb)
index ac5e967..229b3de 100644 (file)
@@ -255,7 +255,7 @@ struct ehci_hcd {                   /* one per controller */
        struct list_head        tt_list;
 
        /* platform-specific data -- must come last */
-       unsigned long           priv[0] __aligned(sizeof(s64));
+       unsigned long           priv[] __aligned(sizeof(s64));
 };
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */
@@ -460,7 +460,7 @@ struct ehci_iso_sched {
        struct list_head        td_list;
        unsigned                span;
        unsigned                first_packet;
-       struct ehci_iso_packet  packet[0];
+       struct ehci_iso_packet  packet[];
 };
 
 /*
index 0473387..a8e1048 100644 (file)
@@ -396,6 +396,7 @@ static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
        case PIPE_CONTROL:
                /* 1 td fro setup,1 for ack */
                size = 2;
+               fallthrough;
        case PIPE_BULK:
                /* one td for every 4096 bytes(can be up to 8k) */
                size += urb->transfer_buffer_length / 4096;
index 1b4db95..6cee40e 100644 (file)
@@ -490,7 +490,7 @@ struct fotg210_iso_packet {
 struct fotg210_iso_sched {
        struct list_head        td_list;
        unsigned                span;
-       struct fotg210_iso_packet       packet[0];
+       struct fotg210_iso_packet       packet[];
 };
 
 /*
index f4e13a3..22117a6 100644 (file)
@@ -288,7 +288,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
 
 /* pci driver glue; this is a "new style" PCI driver module */
 static struct pci_driver ohci_pci_driver = {
-       .name =         (char *) hcd_name,
+       .name =         hcd_name,
        .id_table =     pci_ids,
 
        .probe =        usb_hcd_pci_probe,
index b015b00..27c26ca 100644 (file)
@@ -337,7 +337,7 @@ typedef struct urb_priv {
        u16                     length;         // # tds in this request
        u16                     td_cnt;         // tds already serviced
        struct list_head        pending;
-       struct td               *td [0];        // all TDs in this request
+       struct td               *td[];          // all TDs in this request
 
 } urb_priv_t;
 
@@ -435,7 +435,7 @@ struct ohci_hcd {
        struct dentry           *debug_dir;
 
        /* platform-specific data -- must come last */
-       unsigned long           priv[0] __aligned(sizeof(s64));
+       unsigned long           priv[] __aligned(sizeof(s64));
 
 };
 
index 72a34a1..adaf406 100644 (file)
@@ -1792,7 +1792,7 @@ struct platform_driver sl811h_driver = {
        .suspend =      sl811h_suspend,
        .resume =       sl811h_resume,
        .driver = {
-               .name = (char *) hcd_name,
+               .name = hcd_name,
        },
 };
 EXPORT_SYMBOL(sl811h_driver);
index 0fa3d72..957c87e 100644 (file)
@@ -294,7 +294,7 @@ static const struct pci_device_id uhci_pci_ids[] = { {
 MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
 
 static struct pci_driver uhci_pci_driver = {
-       .name =         (char *)hcd_name,
+       .name =         hcd_name,
        .id_table =     uhci_pci_ids,
 
        .probe =        usb_hcd_pci_probe,
index 3c4abb5..5546e7e 100644 (file)
@@ -219,8 +219,7 @@ static int xhci_histb_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       histb->ctrl = devm_ioremap_resource(&pdev->dev, res);
+       histb->ctrl = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(histb->ctrl))
                return PTR_ERR(histb->ctrl);
 
index af92b25..9eca1fe 100644 (file)
@@ -567,6 +567,7 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd)
  */
 static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
                                u16 index, bool on, unsigned long *flags)
+       __must_hold(&xhci->lock)
 {
        struct xhci_hub *rhub;
        struct xhci_port *port;
@@ -617,6 +618,7 @@ static void xhci_port_set_test_mode(struct xhci_hcd *xhci,
 
 static int xhci_enter_test_mode(struct xhci_hcd *xhci,
                                u16 test_mode, u16 wIndex, unsigned long *flags)
+       __must_hold(&xhci->lock)
 {
        int i, retval;
 
@@ -1306,7 +1308,47 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                         wIndex, link_state);
                                goto error;
                        }
+
+                       /*
+                        * set link to U0, steps depend on current link state.
+                        * U3: set link to U0 and wait for u3exit completion.
+                        * U1/U2:  no PLC complete event, only set link to U0.
+                        * Resume/Recovery: device initiated U0, only wait for
+                        * completion
+                        */
+                       if (link_state == USB_SS_PORT_LS_U0) {
+                               u32 pls = temp & PORT_PLS_MASK;
+                               bool wait_u0 = false;
+
+                               /* already in U0 */
+                               if (pls == XDEV_U0)
+                                       break;
+                               if (pls == XDEV_U3 ||
+                                   pls == XDEV_RESUME ||
+                                   pls == XDEV_RECOVERY) {
+                                       wait_u0 = true;
+                                       reinit_completion(&bus_state->u3exit_done[wIndex]);
+                               }
+                               if (pls <= XDEV_U3) /* U1, U2, U3 */
+                                       xhci_set_link_state(xhci, ports[wIndex],
+                                                           USB_SS_PORT_LS_U0);
+                               if (!wait_u0) {
+                                       if (pls > XDEV_U3)
+                                               goto error;
+                                       break;
+                               }
+                               spin_unlock_irqrestore(&xhci->lock, flags);
+                               if (!wait_for_completion_timeout(&bus_state->u3exit_done[wIndex],
+                                                                msecs_to_jiffies(100)))
+                                       xhci_dbg(xhci, "missing U0 port change event for port %d\n",
+                                                wIndex);
+                               spin_lock_irqsave(&xhci->lock, flags);
+                               temp = readl(ports[wIndex]->addr);
+                               break;
+                       }
+
                        if (link_state == USB_SS_PORT_LS_U3) {
+                               int retries = 16;
                                slot_id = xhci_find_slot_id_by_port(hcd, xhci,
                                                wIndex + 1);
                                if (slot_id) {
@@ -1317,17 +1359,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                        xhci_stop_device(xhci, slot_id, 1);
                                        spin_lock_irqsave(&xhci->lock, flags);
                                }
-                       }
-
-                       xhci_set_link_state(xhci, ports[wIndex], link_state);
-
-                       spin_unlock_irqrestore(&xhci->lock, flags);
-                       msleep(20); /* wait device to enter */
-                       spin_lock_irqsave(&xhci->lock, flags);
-
-                       temp = readl(ports[wIndex]->addr);
-                       if (link_state == USB_SS_PORT_LS_U3)
+                               xhci_set_link_state(xhci, ports[wIndex], USB_SS_PORT_LS_U3);
+                               spin_unlock_irqrestore(&xhci->lock, flags);
+                               while (retries--) {
+                                       usleep_range(4000, 8000);
+                                       temp = readl(ports[wIndex]->addr);
+                                       if ((temp & PORT_PLS_MASK) == XDEV_U3)
+                                               break;
+                               }
+                               spin_lock_irqsave(&xhci->lock, flags);
+                               temp = readl(ports[wIndex]->addr);
                                bus_state->suspended_ports |= 1 << wIndex;
+                       }
                        break;
                case USB_PORT_FEAT_POWER:
                        /*
index 884c601..9764122 100644 (file)
@@ -2552,6 +2552,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
                xhci->usb3_rhub.bus_state.resume_done[i] = 0;
                /* Only the USB 2.0 completions will ever be used. */
                init_completion(&xhci->usb2_rhub.bus_state.rexit_done[i]);
+               init_completion(&xhci->usb3_rhub.bus_state.u3exit_done[i]);
        }
 
        if (scratchpad_alloc(xhci, flags))
index 5ac458b..acd5651 100644 (file)
@@ -95,7 +95,7 @@ struct mu3h_sch_ep_info {
        u32 pkts;
        u32 cs_count;
        u32 burst_mode;
-       u32 bw_budget_table[0];
+       u32 bw_budget_table[];
 };
 
 #define MU3C_U3_PORT_MAX 4
index 5e9b537..766b747 100644 (file)
@@ -50,6 +50,7 @@
 #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI                0x15f0
 #define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI              0x8a13
 #define PCI_DEVICE_ID_INTEL_CML_XHCI                   0xa3af
+#define PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI            0x9a13
 
 #define PCI_DEVICE_ID_AMD_PROMONTORYA_4                        0x43b9
 #define PCI_DEVICE_ID_AMD_PROMONTORYA_3                        0x43ba
@@ -136,7 +137,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_AMD_PLL_FIX;
 
        if (pdev->vendor == PCI_VENDOR_ID_AMD &&
-               (pdev->device == 0x15e0 ||
+               (pdev->device == 0x145c ||
+                pdev->device == 0x15e0 ||
                 pdev->device == 0x15e1 ||
                 pdev->device == 0x43bb))
                xhci->quirks |= XHCI_SUSPEND_DELAY;
@@ -216,7 +218,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
             pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI ||
             pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI ||
             pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI ||
-            pdev->device == PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI))
+            pdev->device == PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI ||
+            pdev->device == PCI_DEVICE_ID_INTEL_TIGER_LAKE_XHCI))
                xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
 
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
@@ -243,6 +246,9 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                        pdev->device == 0x3432)
                xhci->quirks |= XHCI_BROKEN_STREAMS;
 
+       if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483)
+               xhci->quirks |= XHCI_LPM_SUPPORT;
+
        if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
                        pdev->device == 0x1042)
                xhci->quirks |= XHCI_BROKEN_STREAMS;
@@ -549,7 +555,7 @@ MODULE_DEVICE_TABLE(pci, pci_ids);
 
 /* pci driver glue; this is a "new style" PCI driver module */
 static struct pci_driver xhci_pci_driver = {
-       .name =         (char *) hcd_name,
+       .name =         hcd_name,
        .id_table =     pci_ids,
 
        .probe =        xhci_pci_probe,
index d90cd5e..1d4f6f8 100644 (file)
@@ -219,8 +219,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
                goto disable_runtime;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+       hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
        if (IS_ERR(hcd->regs)) {
                ret = PTR_ERR(hcd->regs);
                goto put_hcd;
@@ -445,6 +444,7 @@ MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match);
 static struct platform_driver usb_xhci_driver = {
        .probe  = xhci_plat_probe,
        .remove = xhci_plat_remove,
+       .shutdown = usb_hcd_platform_shutdown,
        .driver = {
                .name = "xhci-hcd",
                .pm = &xhci_plat_pm_ops,
index d23f740..a78787b 100644 (file)
@@ -955,6 +955,7 @@ void xhci_stop_endpoint_command_watchdog(struct timer_list *t)
        struct xhci_virt_ep *ep = from_timer(ep, t, stop_cmd_timer);
        struct xhci_hcd *xhci = ep->xhci;
        unsigned long flags;
+       u32 usbsts;
 
        spin_lock_irqsave(&xhci->lock, flags);
 
@@ -965,8 +966,11 @@ void xhci_stop_endpoint_command_watchdog(struct timer_list *t)
                xhci_dbg(xhci, "Stop EP timer raced with cmd completion, exit");
                return;
        }
+       usbsts = readl(&xhci->op_regs->status);
 
        xhci_warn(xhci, "xHCI host not responding to stop endpoint command.\n");
+       xhci_warn(xhci, "USBSTS:%s\n", xhci_decode_usbsts(usbsts));
+
        ep->ep_state &= ~EP_STOP_CMD_PENDING;
 
        xhci_halt(xhci);
@@ -1677,6 +1681,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
             (portsc & PORT_PLS_MASK) == XDEV_U1 ||
             (portsc & PORT_PLS_MASK) == XDEV_U2)) {
                xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
+               complete(&bus_state->u3exit_done[hcd_portnum]);
                /* We've just brought the device into U0/1/2 through either the
                 * Resume state after a device remote wakeup, or through the
                 * U3Exit state after a host-initiated resume.  If it's a device
@@ -2413,6 +2418,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                status = -EPIPE;
                break;
        case COMP_SPLIT_TRANSACTION_ERROR:
+               xhci_dbg(xhci, "Split transaction error for slot %u ep %u\n",
+                        slot_id, ep_index);
+               status = -EPROTO;
+               break;
        case COMP_USB_TRANSACTION_ERROR:
                xhci_dbg(xhci, "Transfer error for slot %u ep %u on endpoint\n",
                         slot_id, ep_index);
index 8163aef..2eaf5c0 100644 (file)
@@ -24,6 +24,9 @@
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/phy.h>
+#include <linux/usb/role.h>
 #include <soc/tegra/pmc.h>
 
 #include "xhci.h"
@@ -203,6 +206,8 @@ struct tegra_xusb_soc {
 
        bool scale_ss_clock;
        bool has_ipfs;
+       bool lpm_support;
+       bool otg_reset_sspi;
 };
 
 struct tegra_xusb_context {
@@ -250,6 +255,14 @@ struct tegra_xusb {
        struct phy **phys;
        unsigned int num_phys;
 
+       struct usb_phy **usbphy;
+       unsigned int num_usb_phys;
+       int otg_usb2_port;
+       int otg_usb3_port;
+       bool host_mode;
+       struct notifier_block id_nb;
+       struct work_struct id_work;
+
        /* Firmware loading related */
        struct {
                size_t size;
@@ -1081,6 +1094,205 @@ static int tegra_xusb_enable_firmware_messages(struct tegra_xusb *tegra)
        return err;
 }
 
+static void tegra_xhci_set_port_power(struct tegra_xusb *tegra, bool main,
+                                                bool set)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+       struct usb_hcd *hcd = main ?  xhci->main_hcd : xhci->shared_hcd;
+       unsigned int wait = (!main && !set) ? 1000 : 10;
+       u16 typeReq = set ? SetPortFeature : ClearPortFeature;
+       u16 wIndex = main ? tegra->otg_usb2_port + 1 : tegra->otg_usb3_port + 1;
+       u32 status;
+       u32 stat_power = main ? USB_PORT_STAT_POWER : USB_SS_PORT_STAT_POWER;
+       u32 status_val = set ? stat_power : 0;
+
+       dev_dbg(tegra->dev, "%s():%s %s port power\n", __func__,
+               set ? "set" : "clear", main ? "HS" : "SS");
+
+       hcd->driver->hub_control(hcd, typeReq, USB_PORT_FEAT_POWER, wIndex,
+                                NULL, 0);
+
+       do {
+               tegra_xhci_hc_driver.hub_control(hcd, GetPortStatus, 0, wIndex,
+                                       (char *) &status, sizeof(status));
+               if (status_val == (status & stat_power))
+                       break;
+
+               if (!main && !set)
+                       usleep_range(600, 700);
+               else
+                       usleep_range(10, 20);
+       } while (--wait > 0);
+
+       if (status_val != (status & stat_power))
+               dev_info(tegra->dev, "failed to %s %s PP %d\n",
+                                               set ? "set" : "clear",
+                                               main ? "HS" : "SS", status);
+}
+
+static struct phy *tegra_xusb_get_phy(struct tegra_xusb *tegra, char *name,
+                                                               int port)
+{
+       unsigned int i, phy_count = 0;
+
+       for (i = 0; i < tegra->soc->num_types; i++) {
+               if (!strncmp(tegra->soc->phy_types[i].name, "usb2",
+                                                           strlen(name)))
+                       return tegra->phys[phy_count+port];
+
+               phy_count += tegra->soc->phy_types[i].num;
+       }
+
+       return NULL;
+}
+
+static void tegra_xhci_id_work(struct work_struct *work)
+{
+       struct tegra_xusb *tegra = container_of(work, struct tegra_xusb,
+                                               id_work);
+       struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
+       struct tegra_xusb_mbox_msg msg;
+       struct phy *phy = tegra_xusb_get_phy(tegra, "usb2",
+                                                   tegra->otg_usb2_port);
+       u32 status;
+       int ret;
+
+       dev_dbg(tegra->dev, "host mode %s\n", tegra->host_mode ? "on" : "off");
+
+       mutex_lock(&tegra->lock);
+
+       if (tegra->host_mode)
+               phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_HOST);
+       else
+               phy_set_mode_ext(phy, PHY_MODE_USB_OTG, USB_ROLE_NONE);
+
+       mutex_unlock(&tegra->lock);
+
+       if (tegra->host_mode) {
+               /* switch to host mode */
+               if (tegra->otg_usb3_port >= 0) {
+                       if (tegra->soc->otg_reset_sspi) {
+                               /* set PP=0 */
+                               tegra_xhci_hc_driver.hub_control(
+                                       xhci->shared_hcd, GetPortStatus,
+                                       0, tegra->otg_usb3_port+1,
+                                       (char *) &status, sizeof(status));
+                               if (status & USB_SS_PORT_STAT_POWER)
+                                       tegra_xhci_set_port_power(tegra, false,
+                                                                 false);
+
+                               /* reset OTG port SSPI */
+                               msg.cmd = MBOX_CMD_RESET_SSPI;
+                               msg.data = tegra->otg_usb3_port+1;
+
+                               ret = tegra_xusb_mbox_send(tegra, &msg);
+                               if (ret < 0) {
+                                       dev_info(tegra->dev,
+                                               "failed to RESET_SSPI %d\n",
+                                               ret);
+                               }
+                       }
+
+                       tegra_xhci_set_port_power(tegra, false, true);
+               }
+
+               tegra_xhci_set_port_power(tegra, true, true);
+
+       } else {
+               if (tegra->otg_usb3_port >= 0)
+                       tegra_xhci_set_port_power(tegra, false, false);
+
+               tegra_xhci_set_port_power(tegra, true, false);
+       }
+}
+
+static int tegra_xusb_get_usb2_port(struct tegra_xusb *tegra,
+                                             struct usb_phy *usbphy)
+{
+       unsigned int i;
+
+       for (i = 0; i < tegra->num_usb_phys; i++) {
+               if (tegra->usbphy[i] && usbphy == tegra->usbphy[i])
+                       return i;
+       }
+
+       return -1;
+}
+
+static int tegra_xhci_id_notify(struct notifier_block *nb,
+                                        unsigned long action, void *data)
+{
+       struct tegra_xusb *tegra = container_of(nb, struct tegra_xusb,
+                                                   id_nb);
+       struct usb_phy *usbphy = (struct usb_phy *)data;
+
+       dev_dbg(tegra->dev, "%s(): action is %d", __func__, usbphy->last_event);
+
+       if ((tegra->host_mode && usbphy->last_event == USB_EVENT_ID) ||
+               (!tegra->host_mode && usbphy->last_event != USB_EVENT_ID)) {
+               dev_dbg(tegra->dev, "Same role(%d) received. Ignore",
+                       tegra->host_mode);
+               return NOTIFY_OK;
+       }
+
+       tegra->otg_usb2_port = tegra_xusb_get_usb2_port(tegra, usbphy);
+       tegra->otg_usb3_port = tegra_xusb_padctl_get_usb3_companion(
+                                                       tegra->padctl,
+                                                       tegra->otg_usb2_port);
+
+       tegra->host_mode = (usbphy->last_event == USB_EVENT_ID) ? true : false;
+
+       schedule_work(&tegra->id_work);
+
+       return NOTIFY_OK;
+}
+
+static int tegra_xusb_init_usb_phy(struct tegra_xusb *tegra)
+{
+       unsigned int i;
+
+       tegra->usbphy = devm_kcalloc(tegra->dev, tegra->num_usb_phys,
+                                  sizeof(*tegra->usbphy), GFP_KERNEL);
+       if (!tegra->usbphy)
+               return -ENOMEM;
+
+       INIT_WORK(&tegra->id_work, tegra_xhci_id_work);
+       tegra->id_nb.notifier_call = tegra_xhci_id_notify;
+
+       for (i = 0; i < tegra->num_usb_phys; i++) {
+               struct phy *phy = tegra_xusb_get_phy(tegra, "usb2", i);
+
+               if (!phy)
+                       continue;
+
+               tegra->usbphy[i] = devm_usb_get_phy_by_node(tegra->dev,
+                                                       phy->dev.of_node,
+                                                       &tegra->id_nb);
+               if (!IS_ERR(tegra->usbphy[i])) {
+                       dev_dbg(tegra->dev, "usbphy-%d registered", i);
+                       otg_set_host(tegra->usbphy[i]->otg, &tegra->hcd->self);
+               } else {
+                       /*
+                        * usb-phy is optional, continue if its not available.
+                        */
+                       tegra->usbphy[i] = NULL;
+               }
+       }
+
+       return 0;
+}
+
+static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra)
+{
+       unsigned int i;
+
+       cancel_work_sync(&tegra->id_work);
+
+       for (i = 0; i < tegra->num_usb_phys; i++)
+               if (tegra->usbphy[i])
+                       otg_set_host(tegra->usbphy[i]->otg, NULL);
+}
+
 static int tegra_xusb_probe(struct platform_device *pdev)
 {
        struct tegra_xusb *tegra;
@@ -1254,8 +1466,11 @@ static int tegra_xusb_probe(struct platform_device *pdev)
                goto put_powerdomains;
        }
 
-       for (i = 0; i < tegra->soc->num_types; i++)
+       for (i = 0; i < tegra->soc->num_types; i++) {
+               if (!strncmp(tegra->soc->phy_types[i].name, "usb2", 4))
+                       tegra->num_usb_phys = tegra->soc->phy_types[i].num;
                tegra->num_phys += tegra->soc->phy_types[i].num;
+       }
 
        tegra->phys = devm_kcalloc(&pdev->dev, tegra->num_phys,
                                   sizeof(*tegra->phys), GFP_KERNEL);
@@ -1384,6 +1599,12 @@ static int tegra_xusb_probe(struct platform_device *pdev)
                goto remove_usb3;
        }
 
+       err = tegra_xusb_init_usb_phy(tegra);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to init USB PHY: %d\n", err);
+               goto remove_usb3;
+       }
+
        return 0;
 
 remove_usb3:
@@ -1420,6 +1641,8 @@ static int tegra_xusb_remove(struct platform_device *pdev)
        struct tegra_xusb *tegra = platform_get_drvdata(pdev);
        struct xhci_hcd *xhci = hcd_to_xhci(tegra->hcd);
 
+       tegra_xusb_deinit_usb_phy(tegra);
+
        usb_remove_hcd(xhci->shared_hcd);
        usb_put_hcd(xhci->shared_hcd);
        xhci->shared_hcd = NULL;
@@ -1694,6 +1917,7 @@ static const struct tegra_xusb_soc tegra124_soc = {
        },
        .scale_ss_clock = true,
        .has_ipfs = true,
+       .otg_reset_sspi = false,
        .mbox = {
                .cmd = 0xe4,
                .data_in = 0xe8,
@@ -1733,6 +1957,7 @@ static const struct tegra_xusb_soc tegra210_soc = {
        },
        .scale_ss_clock = false,
        .has_ipfs = true,
+       .otg_reset_sspi = true,
        .mbox = {
                .cmd = 0xe4,
                .data_in = 0xe8,
@@ -1773,12 +1998,14 @@ static const struct tegra_xusb_soc tegra186_soc = {
        },
        .scale_ss_clock = false,
        .has_ipfs = false,
+       .otg_reset_sspi = false,
        .mbox = {
                .cmd = 0xe4,
                .data_in = 0xe8,
                .data_out = 0xec,
                .owner = 0xf0,
        },
+       .lpm_support = true,
 };
 
 static const char * const tegra194_supply_names[] = {
@@ -1802,12 +2029,14 @@ static const struct tegra_xusb_soc tegra194_soc = {
        },
        .scale_ss_clock = false,
        .has_ipfs = false,
+       .otg_reset_sspi = false,
        .mbox = {
                .cmd = 0x68,
                .data_in = 0x6c,
                .data_out = 0x70,
                .owner = 0x74,
        },
+       .lpm_support = true,
 };
 MODULE_FIRMWARE("nvidia/tegra194/xusb.bin");
 
@@ -1832,7 +2061,11 @@ static struct platform_driver tegra_xusb_driver = {
 
 static void tegra_xhci_quirks(struct device *dev, struct xhci_hcd *xhci)
 {
+       struct tegra_xusb *tegra = dev_get_drvdata(dev);
+
        xhci->quirks |= XHCI_PLAT;
+       if (tegra && tegra->soc->lpm_support)
+               xhci->quirks |= XHCI_LPM_SUPPORT;
 }
 
 static int tegra_xhci_setup(struct usb_hcd *hcd)
index 56eb867..b19582b 100644 (file)
@@ -289,23 +289,12 @@ DECLARE_EVENT_CLASS(xhci_log_urb,
        ),
        TP_printk("ep%d%s-%s: urb %p pipe %u slot %d length %d/%d sgs %d/%d stream %d flags %08x",
                        __entry->epnum, __entry->dir_in ? "in" : "out",
-                       ({ char *s;
-                       switch (__entry->type) {
-                       case USB_ENDPOINT_XFER_INT:
-                               s = "intr";
-                               break;
-                       case USB_ENDPOINT_XFER_CONTROL:
-                               s = "control";
-                               break;
-                       case USB_ENDPOINT_XFER_BULK:
-                               s = "bulk";
-                               break;
-                       case USB_ENDPOINT_XFER_ISOC:
-                               s = "isoc";
-                               break;
-                       default:
-                               s = "UNKNOWN";
-                       } s; }), __entry->urb, __entry->pipe, __entry->slot_id,
+                       __print_symbolic(__entry->type,
+                                  { USB_ENDPOINT_XFER_INT,     "intr" },
+                                  { USB_ENDPOINT_XFER_CONTROL, "control" },
+                                  { USB_ENDPOINT_XFER_BULK,    "bulk" },
+                                  { USB_ENDPOINT_XFER_ISOC,    "isoc" }),
+                       __entry->urb, __entry->pipe, __entry->slot_id,
                        __entry->actual, __entry->length, __entry->num_mapped_sgs,
                        __entry->num_sgs, __entry->stream, __entry->flags
                )
index dbac0fa..fe38275 100644 (file)
@@ -1157,8 +1157,10 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
                xhci_dbg(xhci, "Stop HCD\n");
                xhci_halt(xhci);
                xhci_zero_64b_regs(xhci);
-               xhci_reset(xhci);
+               retval = xhci_reset(xhci);
                spin_unlock_irq(&xhci->lock);
+               if (retval)
+                       return retval;
                xhci_cleanup_msix(xhci);
 
                xhci_dbg(xhci, "// Disabling event ring interrupts\n");
index 3ecee10..3289bb5 100644 (file)
@@ -1642,7 +1642,7 @@ struct xhci_scratchpad {
 struct urb_priv {
        int     num_tds;
        int     num_tds_done;
-       struct  xhci_td td[0];
+       struct  xhci_td td[];
 };
 
 /*
@@ -1694,6 +1694,7 @@ struct xhci_bus_state {
        /* Which ports are waiting on RExit to U0 transition. */
        unsigned long           rexit_ports;
        struct completion       rexit_done[USB_MAXCHILDREN];
+       struct completion       u3exit_done[USB_MAXCHILDREN];
 };
 
 
@@ -1901,7 +1902,7 @@ struct xhci_hcd {
 
        void                    *dbc;
        /* platform-specific data -- must come last */
-       unsigned long           priv[0] __aligned(sizeof(s64));
+       unsigned long           priv[] __aligned(sizeof(s64));
 };
 
 /* Platform specific overrides to generic XHCI hc_driver ops */
@@ -2589,6 +2590,35 @@ static inline const char *xhci_decode_portsc(u32 portsc)
        return str;
 }
 
+static inline const char *xhci_decode_usbsts(u32 usbsts)
+{
+       static char str[256];
+       int ret = 0;
+
+       if (usbsts == ~(u32)0)
+               return " 0xffffffff";
+       if (usbsts & STS_HALT)
+               ret += sprintf(str + ret, " HCHalted");
+       if (usbsts & STS_FATAL)
+               ret += sprintf(str + ret, " HSE");
+       if (usbsts & STS_EINT)
+               ret += sprintf(str + ret, " EINT");
+       if (usbsts & STS_PORT)
+               ret += sprintf(str + ret, " PCD");
+       if (usbsts & STS_SAVE)
+               ret += sprintf(str + ret, " SSS");
+       if (usbsts & STS_RESTORE)
+               ret += sprintf(str + ret, " RSS");
+       if (usbsts & STS_SRE)
+               ret += sprintf(str + ret, " SRE");
+       if (usbsts & STS_CNR)
+               ret += sprintf(str + ret, " CNR");
+       if (usbsts & STS_HCE)
+               ret += sprintf(str + ret, " HCE");
+
+       return str;
+}
+
 static inline const char *xhci_decode_doorbell(u32 slot, u32 doorbell)
 {
        static char str[256];
index 834b249..833a460 100644 (file)
@@ -137,6 +137,16 @@ config USB_APPLEDISPLAY
          Say Y here if you want to control the backlight of Apple Cinema
          Displays over USB. This driver provides a sysfs interface.
 
+config APPLE_MFI_FASTCHARGE
+       tristate "Fast charge control for iOS devices"
+       select POWER_SUPPLY
+       help
+         Say Y here if you want to control whether iOS devices will
+         fast charge from the USB interface, as implemented in "MFi"
+         chargers.
+
+         It is safe to say M here.
+
 source "drivers/usb/misc/sisusbvga/Kconfig"
 
 config USB_LD
index 0d416eb..da39bdd 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_USB_EMI26)                       += emi26.o
 obj-$(CONFIG_USB_EMI62)                        += emi62.o
 obj-$(CONFIG_USB_EZUSB_FX2)            += ezusb.o
 obj-$(CONFIG_USB_FTDI_ELAN)            += ftdi-elan.o
+obj-$(CONFIG_APPLE_MFI_FASTCHARGE)     += apple-mfi-fastcharge.o
 obj-$(CONFIG_USB_IDMOUSE)              += idmouse.o
 obj-$(CONFIG_USB_IOWARRIOR)            += iowarrior.o
 obj-$(CONFIG_USB_ISIGHTFW)             += isight_firmware.o
diff --git a/drivers/usb/misc/apple-mfi-fastcharge.c b/drivers/usb/misc/apple-mfi-fastcharge.c
new file mode 100644 (file)
index 0000000..b403094
--- /dev/null
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Fast-charge control for Apple "MFi" devices
+ *
+ * Copyright (C) 2019 Bastien Nocera <hadess@hadess.net>
+ */
+
+/* Standard include files */
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
+MODULE_DESCRIPTION("Fast-charge control for Apple \"MFi\" devices");
+MODULE_LICENSE("GPL");
+
+#define TRICKLE_CURRENT_MA             0
+#define FAST_CURRENT_MA                        2500
+
+#define APPLE_VENDOR_ID                        0x05ac  /* Apple */
+
+/* The product ID is defined as starting with 0x12nn, as per the
+ * "Choosing an Apple Device USB Configuration" section in
+ * release R9 (2012) of the "MFi Accessory Hardware Specification"
+ *
+ * To distinguish an Apple device, a USB host can check the device
+ * descriptor of attached USB devices for the following fields:
+ * ■ Vendor ID: 0x05AC
+ * ■ Product ID: 0x12nn
+ *
+ * Those checks will be done in .match() and .probe().
+ */
+
+static const struct usb_device_id mfi_fc_id_table[] = {
+       { .idVendor = APPLE_VENDOR_ID,
+         .match_flags = USB_DEVICE_ID_MATCH_VENDOR },
+       {},
+};
+
+MODULE_DEVICE_TABLE(usb, mfi_fc_id_table);
+
+/* Driver-local specific stuff */
+struct mfi_device {
+       struct usb_device *udev;
+       struct power_supply *battery;
+       int charge_type;
+};
+
+static int apple_mfi_fc_set_charge_type(struct mfi_device *mfi,
+                                       const union power_supply_propval *val)
+{
+       int current_ma;
+       int retval;
+       __u8 request_type;
+
+       if (mfi->charge_type == val->intval) {
+               dev_dbg(&mfi->udev->dev, "charge type %d already set\n",
+                               mfi->charge_type);
+               return 0;
+       }
+
+       switch (val->intval) {
+       case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
+               current_ma = TRICKLE_CURRENT_MA;
+               break;
+       case POWER_SUPPLY_CHARGE_TYPE_FAST:
+               current_ma = FAST_CURRENT_MA;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       request_type = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+       retval = usb_control_msg(mfi->udev, usb_sndctrlpipe(mfi->udev, 0),
+                                0x40, /* Vendor‐defined power request */
+                                request_type,
+                                current_ma, /* wValue, current offset */
+                                current_ma, /* wIndex, current offset */
+                                NULL, 0, USB_CTRL_GET_TIMEOUT);
+       if (retval) {
+               dev_dbg(&mfi->udev->dev, "retval = %d\n", retval);
+               return retval;
+       }
+
+       mfi->charge_type = val->intval;
+
+       return 0;
+}
+
+static int apple_mfi_fc_get_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               union power_supply_propval *val)
+{
+       struct mfi_device *mfi = power_supply_get_drvdata(psy);
+
+       dev_dbg(&mfi->udev->dev, "prop: %d\n", psp);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_TYPE:
+               val->intval = mfi->charge_type;
+               break;
+       case POWER_SUPPLY_PROP_SCOPE:
+               val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+               break;
+       default:
+               return -ENODATA;
+       }
+
+       return 0;
+}
+
+static int apple_mfi_fc_set_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               const union power_supply_propval *val)
+{
+       struct mfi_device *mfi = power_supply_get_drvdata(psy);
+       int ret;
+
+       dev_dbg(&mfi->udev->dev, "prop: %d\n", psp);
+
+       ret = pm_runtime_get_sync(&mfi->udev->dev);
+       if (ret < 0)
+               return ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_TYPE:
+               ret = apple_mfi_fc_set_charge_type(mfi, val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       pm_runtime_mark_last_busy(&mfi->udev->dev);
+       pm_runtime_put_autosuspend(&mfi->udev->dev);
+
+       return ret;
+}
+
+static int apple_mfi_fc_property_is_writeable(struct power_supply *psy,
+                                             enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_TYPE:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static enum power_supply_property apple_mfi_fc_properties[] = {
+       POWER_SUPPLY_PROP_CHARGE_TYPE,
+       POWER_SUPPLY_PROP_SCOPE
+};
+
+static const struct power_supply_desc apple_mfi_fc_desc = {
+       .name                   = "apple_mfi_fastcharge",
+       .type                   = POWER_SUPPLY_TYPE_BATTERY,
+       .properties             = apple_mfi_fc_properties,
+       .num_properties         = ARRAY_SIZE(apple_mfi_fc_properties),
+       .get_property           = apple_mfi_fc_get_property,
+       .set_property           = apple_mfi_fc_set_property,
+       .property_is_writeable  = apple_mfi_fc_property_is_writeable
+};
+
+static int mfi_fc_probe(struct usb_device *udev)
+{
+       struct power_supply_config battery_cfg = {};
+       struct mfi_device *mfi = NULL;
+       int err, idProduct;
+
+       idProduct = le16_to_cpu(udev->descriptor.idProduct);
+       /* See comment above mfi_fc_id_table[] */
+       if (idProduct < 0x1200 || idProduct > 0x12ff) {
+               return -ENODEV;
+       }
+
+       mfi = kzalloc(sizeof(struct mfi_device), GFP_KERNEL);
+       if (!mfi) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       battery_cfg.drv_data = mfi;
+
+       mfi->charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+       mfi->battery = power_supply_register(&udev->dev,
+                                               &apple_mfi_fc_desc,
+                                               &battery_cfg);
+       if (IS_ERR(mfi->battery)) {
+               dev_err(&udev->dev, "Can't register battery\n");
+               err = PTR_ERR(mfi->battery);
+               goto error;
+       }
+
+       mfi->udev = usb_get_dev(udev);
+       dev_set_drvdata(&udev->dev, mfi);
+
+       return 0;
+
+error:
+       kfree(mfi);
+       return err;
+}
+
+static void mfi_fc_disconnect(struct usb_device *udev)
+{
+       struct mfi_device *mfi;
+
+       mfi = dev_get_drvdata(&udev->dev);
+       if (mfi->battery)
+               power_supply_unregister(mfi->battery);
+       dev_set_drvdata(&udev->dev, NULL);
+       usb_put_dev(mfi->udev);
+       kfree(mfi);
+}
+
+static struct usb_device_driver mfi_fc_driver = {
+       .name =         "apple-mfi-fastcharge",
+       .probe =        mfi_fc_probe,
+       .disconnect =   mfi_fc_disconnect,
+       .id_table =     mfi_fc_id_table,
+       .generic_subclass = 1,
+};
+
+static int __init mfi_fc_driver_init(void)
+{
+       return usb_register_device_driver(&mfi_fc_driver, THIS_MODULE);
+}
+
+static void __exit mfi_fc_driver_exit(void)
+{
+       usb_deregister_device_driver(&mfi_fc_driver);
+}
+
+module_init(mfi_fc_driver_init);
+module_exit(mfi_fc_driver_exit);
index 10c9e7f..29fe577 100644 (file)
@@ -424,10 +424,6 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
                return err;
        }
 
-       hub->vdd = devm_regulator_get(dev, "vdd");
-       if (IS_ERR(hub->vdd))
-               return PTR_ERR(hub->vdd);
-
        if (of_property_read_u16_array(np, "vendor-id", &hub->vendor_id, 1))
                hub->vendor_id = USB251XB_DEF_VENDOR_ID;
 
@@ -640,6 +636,13 @@ static int usb251xb_get_ofdata(struct usb251xb *hub,
 }
 #endif /* CONFIG_OF */
 
+static void usb251xb_regulator_disable_action(void *data)
+{
+       struct usb251xb *hub = data;
+
+       regulator_disable(hub->vdd);
+}
+
 static int usb251xb_probe(struct usb251xb *hub)
 {
        struct device *dev = hub->dev;
@@ -676,10 +679,19 @@ static int usb251xb_probe(struct usb251xb *hub)
        if (err)
                return err;
 
+       hub->vdd = devm_regulator_get(dev, "vdd");
+       if (IS_ERR(hub->vdd))
+               return PTR_ERR(hub->vdd);
+
        err = regulator_enable(hub->vdd);
        if (err)
                return err;
 
+       err = devm_add_action_or_reset(dev,
+                                      usb251xb_regulator_disable_action, hub);
+       if (err)
+               return err;
+
        err = usb251xb_connect(hub);
        if (err) {
                dev_err(dev, "Failed to connect hub (%d)\n", err);
index bc5ecd5..39cb141 100644 (file)
@@ -414,7 +414,7 @@ static ssize_t mon_text_read_t(struct file *file, char __user *buf,
 
                mon_text_read_head_t(rp, &ptr, ep);
                mon_text_read_statset(rp, &ptr, ep);
-               ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+               ptr.cnt += scnprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
                    " %d", ep->length);
                mon_text_read_data(rp, &ptr, ep);
 
@@ -462,7 +462,7 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
                } else {
                        mon_text_read_statset(rp, &ptr, ep);
                }
-               ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+               ptr.cnt += scnprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
                    " %d", ep->length);
                mon_text_read_data(rp, &ptr, ep);
 
@@ -520,7 +520,7 @@ static void mon_text_read_head_t(struct mon_reader_text *rp,
        case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
        default: /* PIPE_BULK */  utype = 'B';
        }
-       p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+       p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
            "%lx %u %c %c%c:%03u:%02u",
            ep->id, ep->tstamp, ep->type,
            utype, udir, ep->devnum, ep->epnum);
@@ -538,7 +538,7 @@ static void mon_text_read_head_u(struct mon_reader_text *rp,
        case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
        default: /* PIPE_BULK */  utype = 'B';
        }
-       p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+       p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
            "%lx %u %c %c%c:%d:%03u:%u",
            ep->id, ep->tstamp, ep->type,
            utype, udir, ep->busnum, ep->devnum, ep->epnum);
@@ -549,7 +549,7 @@ static void mon_text_read_statset(struct mon_reader_text *rp,
 {
 
        if (ep->setup_flag == 0) {   /* Setup packet is present and captured */
-               p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+               p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                    " s %02x %02x %04x %04x %04x",
                    ep->setup[0],
                    ep->setup[1],
@@ -557,10 +557,10 @@ static void mon_text_read_statset(struct mon_reader_text *rp,
                    (ep->setup[5] << 8) | ep->setup[4],
                    (ep->setup[7] << 8) | ep->setup[6]);
        } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */
-               p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+               p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                    " %c __ __ ____ ____ ____", ep->setup_flag);
        } else {                     /* No setup for this kind of URB */
-               p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+               p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                    " %d", ep->status);
        }
 }
@@ -568,7 +568,7 @@ static void mon_text_read_statset(struct mon_reader_text *rp,
 static void mon_text_read_intstat(struct mon_reader_text *rp,
        struct mon_text_ptr *p, const struct mon_event_text *ep)
 {
-       p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+       p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
            " %d:%d", ep->status, ep->interval);
 }
 
@@ -576,10 +576,10 @@ static void mon_text_read_isostat(struct mon_reader_text *rp,
        struct mon_text_ptr *p, const struct mon_event_text *ep)
 {
        if (ep->type == 'S') {
-               p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+               p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                    " %d:%d:%d", ep->status, ep->interval, ep->start_frame);
        } else {
-               p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+               p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                    " %d:%d:%d:%d",
                    ep->status, ep->interval, ep->start_frame, ep->error_count);
        }
@@ -592,7 +592,7 @@ static void mon_text_read_isodesc(struct mon_reader_text *rp,
        int i;
        const struct mon_iso_desc *dp;
 
-       p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+       p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
            " %d", ep->numdesc);
        ndesc = ep->numdesc;
        if (ndesc > ISODESC_MAX)
@@ -601,7 +601,7 @@ static void mon_text_read_isodesc(struct mon_reader_text *rp,
                ndesc = 0;
        dp = ep->isodesc;
        for (i = 0; i < ndesc; i++) {
-               p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+               p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                    " %d:%u:%u", dp->status, dp->offset, dp->length);
                dp++;
        }
@@ -614,28 +614,28 @@ static void mon_text_read_data(struct mon_reader_text *rp,
 
        if ((data_len = ep->length) > 0) {
                if (ep->data_flag == 0) {
-                       p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+                       p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                            " =");
                        if (data_len >= DATA_MAX)
                                data_len = DATA_MAX;
                        for (i = 0; i < data_len; i++) {
                                if (i % 4 == 0) {
-                                       p->cnt += snprintf(p->pbuf + p->cnt,
+                                       p->cnt += scnprintf(p->pbuf + p->cnt,
                                            p->limit - p->cnt,
                                            " ");
                                }
-                               p->cnt += snprintf(p->pbuf + p->cnt,
+                               p->cnt += scnprintf(p->pbuf + p->cnt,
                                    p->limit - p->cnt,
                                    "%02x", ep->data[i]);
                        }
-                       p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+                       p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                            "\n");
                } else {
-                       p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
+                       p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt,
                            " %c\n", ep->data_flag);
                }
        } else {
-               p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n");
+               p->cnt += scnprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n");
        }
 }
 
index 08e1844..04f666e 100644 (file)
@@ -320,9 +320,9 @@ void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
        mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
 }
 
-static int ssusb_role_sw_set(struct device *dev, enum usb_role role)
+static int ssusb_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
 {
-       struct ssusb_mtk *ssusb = dev_get_drvdata(dev);
+       struct ssusb_mtk *ssusb = usb_role_switch_get_drvdata(sw);
        bool to_host = false;
 
        if (role == USB_ROLE_HOST)
@@ -334,9 +334,9 @@ static int ssusb_role_sw_set(struct device *dev, enum usb_role role)
        return 0;
 }
 
-static enum usb_role ssusb_role_sw_get(struct device *dev)
+static enum usb_role ssusb_role_sw_get(struct usb_role_switch *sw)
 {
-       struct ssusb_mtk *ssusb = dev_get_drvdata(dev);
+       struct ssusb_mtk *ssusb = usb_role_switch_get_drvdata(sw);
        enum usb_role role;
 
        role = ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
@@ -356,6 +356,7 @@ static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx)
        role_sx_desc.set = ssusb_role_sw_set;
        role_sx_desc.get = ssusb_role_sw_get;
        role_sx_desc.fwnode = dev_fwnode(ssusb->dev);
+       role_sx_desc.driver_data = ssusb;
        otg_sx->role_sw = usb_role_switch_register(ssusb->dev, &role_sx_desc);
 
        return PTR_ERR_OR_ZERO(otg_sx->role_sw);
index eb2ded1..3b0d1c2 100644 (file)
@@ -110,9 +110,11 @@ config USB_MUSB_UX500
 
 config USB_MUSB_JZ4740
        tristate "JZ4740"
+       depends on OF
        depends on MIPS || COMPILE_TEST
        depends on USB_MUSB_GADGET
        depends on USB=n || USB_OTG_BLACKLIST_HUB
+       select USB_ROLE_SWITCH
 
 config USB_MUSB_MEDIATEK
        tristate "MediaTek platforms"
@@ -144,7 +146,7 @@ config USB_UX500_DMA
 
 config USB_INVENTRA_DMA
        bool 'Inventra'
-       depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK
+       depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK || USB_MUSB_JZ4740
        help
          Enable DMA transfers using Mentor's engine.
 
index bc0109f..e64dd30 100644 (file)
 #include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/usb/role.h>
 #include <linux/usb/usb_phy_generic.h>
 
 #include "musb_core.h"
 
 struct jz4740_glue {
        struct platform_device  *pdev;
+       struct musb             *musb;
        struct clk              *clk;
+       struct usb_role_switch  *role_sw;
 };
 
 static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
 {
        unsigned long   flags;
-       irqreturn_t     retval = IRQ_NONE;
+       irqreturn_t     retval = IRQ_NONE, retval_dma = IRQ_NONE;
        struct musb     *musb = __hci;
 
        spin_lock_irqsave(&musb->lock, flags);
 
+       if (IS_ENABLED(CONFIG_USB_INVENTRA_DMA) && musb->dma_controller)
+               retval_dma = dma_controller_irq(irq, musb->dma_controller);
+
        musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
        musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
        musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
@@ -46,7 +52,10 @@ static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci)
 
        spin_unlock_irqrestore(&musb->lock, flags);
 
-       return retval;
+       if (retval == IRQ_HANDLED || retval_dma == IRQ_HANDLED)
+               return IRQ_HANDLED;
+
+       return IRQ_NONE;
 }
 
 static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = {
@@ -66,11 +75,40 @@ static const struct musb_hdrc_config jz4740_musb_config = {
        .fifo_cfg_size  = ARRAY_SIZE(jz4740_musb_fifo_cfg),
 };
 
+static int jz4740_musb_role_switch_set(struct usb_role_switch *sw,
+                                      enum usb_role role)
+{
+       struct jz4740_glue *glue = usb_role_switch_get_drvdata(sw);
+       struct usb_phy *phy = glue->musb->xceiv;
+
+       switch (role) {
+       case USB_ROLE_NONE:
+               atomic_notifier_call_chain(&phy->notifier, USB_EVENT_NONE, phy);
+               break;
+       case USB_ROLE_DEVICE:
+               atomic_notifier_call_chain(&phy->notifier, USB_EVENT_VBUS, phy);
+               break;
+       case USB_ROLE_HOST:
+               atomic_notifier_call_chain(&phy->notifier, USB_EVENT_ID, phy);
+               break;
+       }
+
+       return 0;
+}
+
 static int jz4740_musb_init(struct musb *musb)
 {
        struct device *dev = musb->controller->parent;
+       struct jz4740_glue *glue = dev_get_drvdata(dev);
+       struct usb_role_switch_desc role_sw_desc = {
+               .set = jz4740_musb_role_switch_set,
+               .driver_data = glue,
+               .fwnode = dev_fwnode(dev),
+       };
        int err;
 
+       glue->musb = musb;
+
        if (dev->of_node)
                musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
        else
@@ -82,6 +120,12 @@ static int jz4740_musb_init(struct musb *musb)
                return err;
        }
 
+       glue->role_sw = usb_role_switch_register(dev, &role_sw_desc);
+       if (IS_ERR(glue->role_sw)) {
+               dev_err(dev, "Failed to register USB role switch");
+               return PTR_ERR(glue->role_sw);
+       }
+
        /*
         * Silicon does not implement ConfigData register.
         * Set dyn_fifo to avoid reading EP config from hardware.
@@ -93,14 +137,24 @@ static int jz4740_musb_init(struct musb *musb)
        return 0;
 }
 
-/*
- * DMA has not been confirmed to work with CONFIG_USB_INVENTRA_DMA,
- * so let's not set up the dma function pointers yet.
- */
+static int jz4740_musb_exit(struct musb *musb)
+{
+       struct jz4740_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+       usb_role_switch_unregister(glue->role_sw);
+
+       return 0;
+}
+
 static const struct musb_platform_ops jz4740_musb_ops = {
        .quirks         = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP,
        .fifo_mode      = 2,
        .init           = jz4740_musb_init,
+       .exit           = jz4740_musb_exit,
+#ifdef CONFIG_USB_INVENTRA_DMA
+       .dma_init       = musbhs_dma_controller_create_noirq,
+       .dma_exit       = musbhs_dma_controller_destroy,
+#endif
 };
 
 static const struct musb_hdrc_platform_data jz4740_musb_pdata = {
@@ -109,10 +163,37 @@ static const struct musb_hdrc_platform_data jz4740_musb_pdata = {
        .platform_ops   = &jz4740_musb_ops,
 };
 
+static struct musb_fifo_cfg jz4770_musb_fifo_cfg[] = {
+       { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
+       { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
+       { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
+       { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, },
+       { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, },
+       { .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, },
+       { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, },
+       { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, },
+       { .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, },
+       { .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, },
+};
+
+static struct musb_hdrc_config jz4770_musb_config = {
+       .multipoint     = 1,
+       .num_eps        = 11,
+       .ram_bits       = 11,
+       .fifo_cfg       = jz4770_musb_fifo_cfg,
+       .fifo_cfg_size  = ARRAY_SIZE(jz4770_musb_fifo_cfg),
+};
+
+static const struct musb_hdrc_platform_data jz4770_musb_pdata = {
+       .mode           = MUSB_PERIPHERAL, /* TODO: support OTG */
+       .config         = &jz4770_musb_config,
+       .platform_ops   = &jz4740_musb_ops,
+};
+
 static int jz4740_probe(struct platform_device *pdev)
 {
        struct device                   *dev = &pdev->dev;
-       const struct musb_hdrc_platform_data *pdata = &jz4740_musb_pdata;
+       const struct musb_hdrc_platform_data *pdata;
        struct platform_device          *musb;
        struct jz4740_glue              *glue;
        struct clk                      *clk;
@@ -122,6 +203,12 @@ static int jz4740_probe(struct platform_device *pdev)
        if (!glue)
                return -ENOMEM;
 
+       pdata = of_device_get_match_data(dev);
+       if (!pdata) {
+               dev_err(dev, "missing platform data");
+               return -EINVAL;
+       }
+
        musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
        if (!musb) {
                dev_err(dev, "failed to allocate musb device");
@@ -142,6 +229,8 @@ static int jz4740_probe(struct platform_device *pdev)
        }
 
        musb->dev.parent                = dev;
+       musb->dev.dma_mask              = &musb->dev.coherent_dma_mask;
+       musb->dev.coherent_dma_mask     = DMA_BIT_MASK(32);
 
        glue->pdev                      = musb;
        glue->clk                       = clk;
@@ -186,20 +275,19 @@ static int jz4740_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_OF
 static const struct of_device_id jz4740_musb_of_match[] = {
-       { .compatible = "ingenic,jz4740-musb" },
+       { .compatible = "ingenic,jz4740-musb", .data = &jz4740_musb_pdata },
+       { .compatible = "ingenic,jz4770-musb", .data = &jz4770_musb_pdata },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, jz4740_musb_of_match);
-#endif
 
 static struct platform_driver jz4740_driver = {
        .probe          = jz4740_probe,
        .remove         = jz4740_remove,
        .driver         = {
                .name   = "musb-jz4740",
-               .of_match_table = of_match_ptr(jz4740_musb_of_match),
+               .of_match_table = jz4740_musb_of_match,
        },
 };
 
index 6b88c2f..6196b0e 100644 (file)
@@ -115,9 +115,8 @@ static void mtk_musb_clks_disable(struct mtk_glue *glue)
        clk_disable_unprepare(glue->main);
 }
 
-static int musb_usb_role_sx_set(struct device *dev, enum usb_role role)
+static int mtk_otg_switch_set(struct mtk_glue *glue, enum usb_role role)
 {
-       struct mtk_glue *glue = dev_get_drvdata(dev);
        struct musb *musb = glue->musb;
        u8 devctl = readb(musb->mregs + MUSB_DEVCTL);
        enum usb_role new_role;
@@ -168,9 +167,14 @@ static int musb_usb_role_sx_set(struct device *dev, enum usb_role role)
        return 0;
 }
 
-static enum usb_role musb_usb_role_sx_get(struct device *dev)
+static int musb_usb_role_sx_set(struct usb_role_switch *sw, enum usb_role role)
 {
-       struct mtk_glue *glue = dev_get_drvdata(dev);
+       return mtk_otg_switch_set(usb_role_switch_get_drvdata(sw), role);
+}
+
+static enum usb_role musb_usb_role_sx_get(struct usb_role_switch *sw)
+{
+       struct mtk_glue *glue = usb_role_switch_get_drvdata(sw);
 
        return glue->role;
 }
@@ -182,6 +186,7 @@ static int mtk_otg_switch_init(struct mtk_glue *glue)
        role_sx_desc.set = musb_usb_role_sx_set;
        role_sx_desc.get = musb_usb_role_sx_get;
        role_sx_desc.fwnode = dev_fwnode(glue->dev);
+       role_sx_desc.driver_data = glue;
        glue->role_sw = usb_role_switch_register(glue->dev, &role_sx_desc);
 
        return PTR_ERR_OR_ZERO(glue->role_sw);
@@ -288,8 +293,7 @@ static int mtk_musb_set_mode(struct musb *musb, u8 mode)
                return -EINVAL;
        }
 
-       glue->role = new_role;
-       musb_usb_role_sx_set(dev, glue->role);
+       mtk_otg_switch_set(glue, new_role);
        return 0;
 }
 
@@ -444,7 +448,7 @@ static int mtk_musb_probe(struct platform_device *pdev)
        struct platform_device_info pinfo;
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
-       int ret = -ENOMEM;
+       int ret;
 
        glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
        if (!glue)
index f616fb4..d590110 100644 (file)
@@ -2945,7 +2945,7 @@ static const struct dev_pm_ops musb_dev_pm_ops = {
 
 static struct platform_driver musb_driver = {
        .driver = {
-               .name           = (char *)musb_driver_name,
+               .name           = musb_driver_name,
                .bus            = &platform_bus_type,
                .pm             = MUSB_DEV_PM_OPS,
                .dev_groups     = musb_groups,
index 886c9b6..8736f42 100644 (file)
@@ -1436,10 +1436,7 @@ done:
         * We need to map sg if the transfer_buffer is
         * NULL.
         */
-       if (!urb->transfer_buffer)
-               qh->use_sg = true;
-
-       if (qh->use_sg) {
+       if (!urb->transfer_buffer) {
                /* sg_miter_start is already done in musb_ep_program */
                if (!sg_miter_next(&qh->sg_miter)) {
                        dev_err(musb->controller, "error: sg list empty\n");
@@ -1447,9 +1444,8 @@ done:
                        status = -EINVAL;
                        goto done;
                }
-               urb->transfer_buffer = qh->sg_miter.addr;
                length = min_t(u32, length, qh->sg_miter.length);
-               musb_write_fifo(hw_ep, length, urb->transfer_buffer);
+               musb_write_fifo(hw_ep, length, qh->sg_miter.addr);
                qh->sg_miter.consumed = length;
                sg_miter_stop(&qh->sg_miter);
        } else {
@@ -1458,11 +1454,6 @@ done:
 
        qh->segsize = length;
 
-       if (qh->use_sg) {
-               if (offset + length >= urb->transfer_buffer_length)
-                       qh->use_sg = false;
-       }
-
        musb_ep_select(mbase, epnum);
        musb_writew(epio, MUSB_TXCSR,
                        MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1977,8 +1968,10 @@ finish:
        urb->actual_length += xfer_len;
        qh->offset += xfer_len;
        if (done) {
-               if (qh->use_sg)
+               if (qh->use_sg) {
                        qh->use_sg = false;
+                       urb->transfer_buffer = NULL;
+               }
 
                if (urb->status == -EINPROGRESS)
                        urb->status = status;
@@ -2550,7 +2543,7 @@ static int musb_bus_resume(struct usb_hcd *hcd)
 struct musb_temp_buffer {
        void *kmalloc_ptr;
        void *old_xfer_buffer;
-       u8 data[0];
+       u8 data[];
 };
 
 static void musb_free_temp_buffer(struct urb *urb)
index 5d44908..99890d1 100644 (file)
@@ -156,7 +156,7 @@ static u8 tusb_readb(void __iomem *addr, u32 offset)
        return val;
 }
 
-static void tusb_writeb(void __iomem *addr, unsigned offset, u8 data)
+static void tusb_writeb(void __iomem *addr, u32 offset, u8 data)
 {
        u16 tmp;
 
index ff24fca..4b3fa78 100644 (file)
@@ -184,4 +184,12 @@ config USB_ULPI_VIEWPORT
          Provides read/write operations to the ULPI phy register set for
          controllers with a viewport register (e.g. Chipidea/ARC controllers).
 
+config JZ4770_PHY
+       tristate "Ingenic JZ4770 Transceiver Driver"
+       depends on MIPS || COMPILE_TEST
+       select USB_PHY
+       help
+         This driver provides PHY support for the USB controller found
+         on the JZ4770 SoC from Ingenic.
+
 endmenu
index df1d990..b352bdb 100644 (file)
@@ -24,3 +24,4 @@ obj-$(CONFIG_USB_MXS_PHY)             += phy-mxs-usb.o
 obj-$(CONFIG_USB_ULPI)                 += phy-ulpi.o
 obj-$(CONFIG_USB_ULPI_VIEWPORT)                += phy-ulpi-viewport.o
 obj-$(CONFIG_KEYSTONE_USB_PHY)         += phy-keystone.o
+obj-$(CONFIG_JZ4770_PHY)               += phy-jz4770.o
diff --git a/drivers/usb/phy/phy-jz4770.c b/drivers/usb/phy/phy-jz4770.c
new file mode 100644 (file)
index 0000000..3ea1f5b
--- /dev/null
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ingenic JZ4770 USB PHY driver
+ * Copyright (c) Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/phy.h>
+
+#define REG_USBPCR_OFFSET      0x00
+#define REG_USBRDT_OFFSET      0x04
+#define REG_USBVBFIL_OFFSET    0x08
+#define REG_USBPCR1_OFFSET     0x0c
+
+/* USBPCR */
+#define USBPCR_USB_MODE                BIT(31)
+#define USBPCR_AVLD_REG                BIT(30)
+#define USBPCR_INCRM           BIT(27)
+#define USBPCR_CLK12_EN                BIT(26)
+#define USBPCR_COMMONONN       BIT(25)
+#define USBPCR_VBUSVLDEXT      BIT(24)
+#define USBPCR_VBUSVLDEXTSEL   BIT(23)
+#define USBPCR_POR             BIT(22)
+#define USBPCR_SIDDQ           BIT(21)
+#define USBPCR_OTG_DISABLE     BIT(20)
+#define USBPCR_TXPREEMPHTUNE   BIT(6)
+
+#define USBPCR_IDPULLUP_LSB    28
+#define USBPCR_IDPULLUP_MASK   GENMASK(29, USBPCR_IDPULLUP_LSB)
+#define USBPCR_IDPULLUP_ALWAYS (3 << USBPCR_IDPULLUP_LSB)
+#define USBPCR_IDPULLUP_SUSPEND        (1 << USBPCR_IDPULLUP_LSB)
+#define USBPCR_IDPULLUP_OTG    (0 << USBPCR_IDPULLUP_LSB)
+
+#define USBPCR_COMPDISTUNE_LSB 17
+#define USBPCR_COMPDISTUNE_MASK        GENMASK(19, USBPCR_COMPDISTUNE_LSB)
+#define USBPCR_COMPDISTUNE_DFT 4
+
+#define USBPCR_OTGTUNE_LSB     14
+#define USBPCR_OTGTUNE_MASK    GENMASK(16, USBPCR_OTGTUNE_LSB)
+#define USBPCR_OTGTUNE_DFT     4
+
+#define USBPCR_SQRXTUNE_LSB    11
+#define USBPCR_SQRXTUNE_MASK   GENMASK(13, USBPCR_SQRXTUNE_LSB)
+#define USBPCR_SQRXTUNE_DFT    3
+
+#define USBPCR_TXFSLSTUNE_LSB  7
+#define USBPCR_TXFSLSTUNE_MASK GENMASK(10, USBPCR_TXFSLSTUNE_LSB)
+#define USBPCR_TXFSLSTUNE_DFT  3
+
+#define USBPCR_TXRISETUNE_LSB  4
+#define USBPCR_TXRISETUNE_MASK GENMASK(5, USBPCR_TXRISETUNE_LSB)
+#define USBPCR_TXRISETUNE_DFT  3
+
+#define USBPCR_TXVREFTUNE_LSB  0
+#define USBPCR_TXVREFTUNE_MASK GENMASK(3, USBPCR_TXVREFTUNE_LSB)
+#define USBPCR_TXVREFTUNE_DFT  5
+
+/* USBRDT */
+#define USBRDT_VBFIL_LD_EN     BIT(25)
+#define USBRDT_IDDIG_EN                BIT(24)
+#define USBRDT_IDDIG_REG       BIT(23)
+
+#define USBRDT_USBRDT_LSB      0
+#define USBRDT_USBRDT_MASK     GENMASK(22, USBRDT_USBRDT_LSB)
+
+/* USBPCR1 */
+#define USBPCR1_UHC_POWON      BIT(5)
+
+struct jz4770_phy {
+       struct usb_phy phy;
+       struct usb_otg otg;
+       struct device *dev;
+       void __iomem *base;
+       struct clk *clk;
+       struct regulator *vcc_supply;
+};
+
+static inline struct jz4770_phy *otg_to_jz4770_phy(struct usb_otg *otg)
+{
+       return container_of(otg, struct jz4770_phy, otg);
+}
+
+static inline struct jz4770_phy *phy_to_jz4770_phy(struct usb_phy *phy)
+{
+       return container_of(phy, struct jz4770_phy, phy);
+}
+
+static int jz4770_phy_set_peripheral(struct usb_otg *otg,
+                                    struct usb_gadget *gadget)
+{
+       struct jz4770_phy *priv = otg_to_jz4770_phy(otg);
+       u32 reg;
+
+       reg = readl(priv->base + REG_USBPCR_OFFSET);
+       reg &= ~USBPCR_USB_MODE;
+       reg |= USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | USBPCR_OTG_DISABLE;
+       writel(reg, priv->base + REG_USBPCR_OFFSET);
+
+       return 0;
+}
+
+static int jz4770_phy_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+       struct jz4770_phy *priv = otg_to_jz4770_phy(otg);
+       u32 reg;
+
+       reg = readl(priv->base + REG_USBPCR_OFFSET);
+       reg &= ~(USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | USBPCR_OTG_DISABLE);
+       reg |= USBPCR_USB_MODE;
+       writel(reg, priv->base + REG_USBPCR_OFFSET);
+
+       return 0;
+}
+
+static int jz4770_phy_init(struct usb_phy *phy)
+{
+       struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
+       int err;
+       u32 reg;
+
+       err = regulator_enable(priv->vcc_supply);
+       if (err) {
+               dev_err(priv->dev, "Unable to enable VCC: %d", err);
+               return err;
+       }
+
+       err = clk_prepare_enable(priv->clk);
+       if (err) {
+               dev_err(priv->dev, "Unable to start clock: %d", err);
+               return err;
+       }
+
+       reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_IDPULLUP_ALWAYS |
+               (USBPCR_COMPDISTUNE_DFT << USBPCR_COMPDISTUNE_LSB) |
+               (USBPCR_OTGTUNE_DFT << USBPCR_OTGTUNE_LSB) |
+               (USBPCR_SQRXTUNE_DFT << USBPCR_SQRXTUNE_LSB) |
+               (USBPCR_TXFSLSTUNE_DFT << USBPCR_TXFSLSTUNE_LSB) |
+               (USBPCR_TXRISETUNE_DFT << USBPCR_TXRISETUNE_LSB) |
+               (USBPCR_TXVREFTUNE_DFT << USBPCR_TXVREFTUNE_LSB) |
+               USBPCR_POR;
+       writel(reg, priv->base + REG_USBPCR_OFFSET);
+
+       /* Wait for PHY to reset */
+       usleep_range(30, 300);
+       writel(reg & ~USBPCR_POR, priv->base + REG_USBPCR_OFFSET);
+       usleep_range(300, 1000);
+
+       return 0;
+}
+
+static void jz4770_phy_shutdown(struct usb_phy *phy)
+{
+       struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
+
+       clk_disable_unprepare(priv->clk);
+       regulator_disable(priv->vcc_supply);
+}
+
+static void jz4770_phy_remove(void *phy)
+{
+       usb_remove_phy(phy);
+}
+
+static int jz4770_phy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct jz4770_phy *priv;
+       int err;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, priv);
+       priv->dev = dev;
+       priv->phy.dev = dev;
+       priv->phy.otg = &priv->otg;
+       priv->phy.label = "jz4770-phy";
+       priv->phy.init = jz4770_phy_init;
+       priv->phy.shutdown = jz4770_phy_shutdown;
+
+       priv->otg.state = OTG_STATE_UNDEFINED;
+       priv->otg.usb_phy = &priv->phy;
+       priv->otg.set_host = jz4770_phy_set_host;
+       priv->otg.set_peripheral = jz4770_phy_set_peripheral;
+
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->base)) {
+               dev_err(dev, "Failed to map registers");
+               return PTR_ERR(priv->base);
+       }
+
+       priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               err = PTR_ERR(priv->clk);
+               if (err != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get clock");
+               return err;
+       }
+
+       priv->vcc_supply = devm_regulator_get(dev, "vcc");
+       if (IS_ERR(priv->vcc_supply)) {
+               err = PTR_ERR(priv->vcc_supply);
+               if (err != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get regulator");
+               return err;
+       }
+
+       err = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2);
+       if (err) {
+               if (err != -EPROBE_DEFER)
+                       dev_err(dev, "Unable to register PHY");
+               return err;
+       }
+
+       return devm_add_action_or_reset(dev, jz4770_phy_remove, &priv->phy);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id jz4770_phy_of_matches[] = {
+       { .compatible = "ingenic,jz4770-phy" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, jz4770_phy_of_matches);
+#endif
+
+static struct platform_driver jz4770_phy_driver = {
+       .probe          = jz4770_phy_probe,
+       .driver         = {
+               .name   = "jz4770-phy",
+               .of_match_table = of_match_ptr(jz4770_phy_of_matches),
+       },
+};
+module_platform_driver(jz4770_phy_driver);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("Ingenic JZ4770 USB PHY driver");
+MODULE_LICENSE("GPL");
index 6153cc3..cffe2ac 100644 (file)
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/export.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/resource.h>
 #include <linux/slab.h>
index 63a00ff..5b17709 100644 (file)
@@ -48,7 +48,7 @@ int usb_role_switch_set_role(struct usb_role_switch *sw, enum usb_role role)
 
        mutex_lock(&sw->lock);
 
-       ret = sw->set(sw->dev.parent, role);
+       ret = sw->set(sw, role);
        if (!ret)
                sw->role = role;
 
@@ -75,7 +75,7 @@ enum usb_role usb_role_switch_get_role(struct usb_role_switch *sw)
        mutex_lock(&sw->lock);
 
        if (sw->get)
-               role = sw->get(sw->dev.parent);
+               role = sw->get(sw);
        else
                role = sw->role;
 
@@ -199,7 +199,7 @@ EXPORT_SYMBOL_GPL(usb_role_switch_find_by_fwnode);
 static umode_t
 usb_role_switch_is_visible(struct kobject *kobj, struct attribute *attr, int n)
 {
-       struct device *dev = container_of(kobj, typeof(*dev), kobj);
+       struct device *dev = kobj_to_dev(kobj);
        struct usb_role_switch *sw = to_role_switch(dev);
 
        if (sw->allow_userspace_control)
@@ -329,7 +329,9 @@ usb_role_switch_register(struct device *parent,
        sw->dev.fwnode = desc->fwnode;
        sw->dev.class = role_class;
        sw->dev.type = &usb_role_dev_type;
-       dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent));
+       dev_set_drvdata(&sw->dev, desc->driver_data);
+       dev_set_name(&sw->dev, "%s-role-switch",
+                    desc->name ? desc->name : dev_name(parent));
 
        ret = device_register(&sw->dev);
        if (ret) {
@@ -356,6 +358,27 @@ void usb_role_switch_unregister(struct usb_role_switch *sw)
 }
 EXPORT_SYMBOL_GPL(usb_role_switch_unregister);
 
+/**
+ * usb_role_switch_set_drvdata - Assign private data pointer to a switch
+ * @sw: USB Role Switch
+ * @data: Private data pointer
+ */
+void usb_role_switch_set_drvdata(struct usb_role_switch *sw, void *data)
+{
+       dev_set_drvdata(&sw->dev, data);
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_set_drvdata);
+
+/**
+ * usb_role_switch_get_drvdata - Get the private data pointer of a switch
+ * @sw: USB Role Switch
+ */
+void *usb_role_switch_get_drvdata(struct usb_role_switch *sw)
+{
+       return dev_get_drvdata(&sw->dev);
+}
+EXPORT_SYMBOL_GPL(usb_role_switch_get_drvdata);
+
 static int __init usb_roles_init(void)
 {
        role_class = class_create(THIS_MODULE, "usb_role");
index 80d6559..5c96e92 100644 (file)
@@ -42,6 +42,7 @@
 #define DRV_NAME                       "intel_xhci_usb_sw"
 
 struct intel_xhci_usb_data {
+       struct device *dev;
        struct usb_role_switch *role_sw;
        void __iomem *base;
        bool enable_sw_switch;
@@ -51,9 +52,10 @@ static const struct software_node intel_xhci_usb_node = {
        "intel-xhci-usb-sw",
 };
 
-static int intel_xhci_usb_set_role(struct device *dev, enum usb_role role)
+static int intel_xhci_usb_set_role(struct usb_role_switch *sw,
+                                  enum usb_role role)
 {
-       struct intel_xhci_usb_data *data = dev_get_drvdata(dev);
+       struct intel_xhci_usb_data *data = usb_role_switch_get_drvdata(sw);
        unsigned long timeout;
        acpi_status status;
        u32 glk, val;
@@ -66,11 +68,11 @@ static int intel_xhci_usb_set_role(struct device *dev, enum usb_role role)
         */
        status = acpi_acquire_global_lock(ACPI_WAIT_FOREVER, &glk);
        if (ACPI_FAILURE(status) && status != AE_NOT_CONFIGURED) {
-               dev_err(dev, "Error could not acquire lock\n");
+               dev_err(data->dev, "Error could not acquire lock\n");
                return -EIO;
        }
 
-       pm_runtime_get_sync(dev);
+       pm_runtime_get_sync(data->dev);
 
        /*
         * Set idpin value as requested.
@@ -112,7 +114,7 @@ static int intel_xhci_usb_set_role(struct device *dev, enum usb_role role)
        do {
                val = readl(data->base + DUAL_ROLE_CFG1);
                if (!!(val & HOST_MODE) == (role == USB_ROLE_HOST)) {
-                       pm_runtime_put(dev);
+                       pm_runtime_put(data->dev);
                        return 0;
                }
 
@@ -120,21 +122,21 @@ static int intel_xhci_usb_set_role(struct device *dev, enum usb_role role)
                usleep_range(5000, 10000);
        } while (time_before(jiffies, timeout));
 
-       pm_runtime_put(dev);
+       pm_runtime_put(data->dev);
 
-       dev_warn(dev, "Timeout waiting for role-switch\n");
+       dev_warn(data->dev, "Timeout waiting for role-switch\n");
        return -ETIMEDOUT;
 }
 
-static enum usb_role intel_xhci_usb_get_role(struct device *dev)
+static enum usb_role intel_xhci_usb_get_role(struct usb_role_switch *sw)
 {
-       struct intel_xhci_usb_data *data = dev_get_drvdata(dev);
+       struct intel_xhci_usb_data *data = usb_role_switch_get_drvdata(sw);
        enum usb_role role;
        u32 val;
 
-       pm_runtime_get_sync(dev);
+       pm_runtime_get_sync(data->dev);
        val = readl(data->base + DUAL_ROLE_CFG0);
-       pm_runtime_put(dev);
+       pm_runtime_put(data->dev);
 
        if (!(val & SW_IDPIN))
                role = USB_ROLE_HOST;
@@ -175,7 +177,9 @@ static int intel_xhci_usb_probe(struct platform_device *pdev)
        sw_desc.get = intel_xhci_usb_get_role,
        sw_desc.allow_userspace_control = true,
        sw_desc.fwnode = software_node_fwnode(&intel_xhci_usb_node);
+       sw_desc.driver_data = data;
 
+       data->dev = dev;
        data->enable_sw_switch = !device_property_read_bool(dev,
                                                "sw_switch_disable");
 
index 578ebdd..91055a1 100644 (file)
@@ -1472,7 +1472,7 @@ static int digi_read_oob_callback(struct urb *urb)
        struct usb_serial_port *port = urb->context;
        struct usb_serial *serial = port->serial;
        struct tty_struct *tty;
-       struct digi_port *priv = usb_get_serial_port_data(port);
+       struct digi_port *priv;
        unsigned char *buf = urb->transfer_buffer;
        int opcode, line, status, val;
        unsigned long flags;
index 43fa1f0..dcda7fb 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
  * Fintek F81232 USB to serial adaptor driver
+ * Fintek F81532A/534A/535/536 USB to 2/4/8/12 serial adaptor driver
  *
  * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org)
  * Copyright (C) 2012 Linux Foundation
 #include <linux/usb/serial.h>
 #include <linux/serial_reg.h>
 
-static const struct usb_device_id id_table[] = {
-       { USB_DEVICE(0x1934, 0x0706) },
+#define F81232_ID              \
+       { USB_DEVICE(0x1934, 0x0706) }  /* 1 port UART device */
+
+#define F81534A_SERIES_ID      \
+       { USB_DEVICE(0x2c42, 0x1602) }, /* In-Box 2 port UART device */ \
+       { USB_DEVICE(0x2c42, 0x1604) }, /* In-Box 4 port UART device */ \
+       { USB_DEVICE(0x2c42, 0x1605) }, /* In-Box 8 port UART device */ \
+       { USB_DEVICE(0x2c42, 0x1606) }, /* In-Box 12 port UART device */ \
+       { USB_DEVICE(0x2c42, 0x1608) }, /* Non-Flash type */ \
+       { USB_DEVICE(0x2c42, 0x1632) }, /* 2 port UART device */ \
+       { USB_DEVICE(0x2c42, 0x1634) }, /* 4 port UART device */ \
+       { USB_DEVICE(0x2c42, 0x1635) }, /* 8 port UART device */ \
+       { USB_DEVICE(0x2c42, 0x1636) }  /* 12 port UART device */
+
+#define F81534A_CTRL_ID                \
+       { USB_DEVICE(0x2c42, 0x16f8) }  /* Global control device */
+
+static const struct usb_device_id f81232_id_table[] = {
+       F81232_ID,
        { }                                     /* Terminating entry */
 };
-MODULE_DEVICE_TABLE(usb, id_table);
+
+static const struct usb_device_id f81534a_id_table[] = {
+       F81534A_SERIES_ID,
+       { }                                     /* Terminating entry */
+};
+
+static const struct usb_device_id f81534a_ctrl_id_table[] = {
+       F81534A_CTRL_ID,
+       { }                                     /* Terminating entry */
+};
+
+static const struct usb_device_id combined_id_table[] = {
+       F81232_ID,
+       F81534A_SERIES_ID,
+       F81534A_CTRL_ID,
+       { }                                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, combined_id_table);
 
 /* Maximum baudrate for F81232 */
 #define F81232_MAX_BAUDRATE            1500000
@@ -35,6 +70,7 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_REGISTER_REQUEST                0xa0
 #define F81232_GET_REGISTER            0xc0
 #define F81232_SET_REGISTER            0x40
+#define F81534A_ACCESS_REG_RETRY       2
 
 #define SERIAL_BASE_ADDRESS            0x0120
 #define RECEIVE_BUFFER_REGISTER                (0x00 + SERIAL_BASE_ADDRESS)
@@ -61,6 +97,22 @@ MODULE_DEVICE_TABLE(usb, id_table);
 #define F81232_CLK_14_77_MHZ           (BIT(1) | BIT(0))
 #define F81232_CLK_MASK                        GENMASK(1, 0)
 
+#define F81534A_MODE_REG               0x107
+#define F81534A_TRIGGER_MASK           GENMASK(3, 2)
+#define F81534A_TRIGGER_MULTIPLE_4X    BIT(3)
+#define F81534A_FIFO_128BYTE           (BIT(1) | BIT(0))
+
+/* Serial port self GPIO control, 2bytes [control&output data][input data] */
+#define F81534A_GPIO_REG               0x10e
+#define F81534A_GPIO_MODE2_DIR         BIT(6) /* 1: input, 0: output */
+#define F81534A_GPIO_MODE1_DIR         BIT(5)
+#define F81534A_GPIO_MODE0_DIR         BIT(4)
+#define F81534A_GPIO_MODE2_OUTPUT      BIT(2)
+#define F81534A_GPIO_MODE1_OUTPUT      BIT(1)
+#define F81534A_GPIO_MODE0_OUTPUT      BIT(0)
+
+#define F81534A_CTRL_CMD_ENABLE_PORT   0x116
+
 struct f81232_private {
        struct mutex lock;
        u8 modem_control;
@@ -322,10 +374,38 @@ exit:
                        __func__, retval);
 }
 
+static char f81232_handle_lsr(struct usb_serial_port *port, u8 lsr)
+{
+       struct f81232_private *priv = usb_get_serial_port_data(port);
+       char tty_flag = TTY_NORMAL;
+
+       if (!(lsr & UART_LSR_BRK_ERROR_BITS))
+               return tty_flag;
+
+       if (lsr & UART_LSR_BI) {
+               tty_flag = TTY_BREAK;
+               port->icount.brk++;
+               usb_serial_handle_break(port);
+       } else if (lsr & UART_LSR_PE) {
+               tty_flag = TTY_PARITY;
+               port->icount.parity++;
+       } else if (lsr & UART_LSR_FE) {
+               tty_flag = TTY_FRAME;
+               port->icount.frame++;
+       }
+
+       if (lsr & UART_LSR_OE) {
+               port->icount.overrun++;
+               schedule_work(&priv->lsr_work);
+               tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);
+       }
+
+       return tty_flag;
+}
+
 static void f81232_process_read_urb(struct urb *urb)
 {
        struct usb_serial_port *port = urb->context;
-       struct f81232_private *priv = usb_get_serial_port_data(port);
        unsigned char *data = urb->transfer_buffer;
        char tty_flag;
        unsigned int i;
@@ -341,29 +421,8 @@ static void f81232_process_read_urb(struct urb *urb)
        /* bulk-in data: [LSR(1Byte)+DATA(1Byte)][LSR(1Byte)+DATA(1Byte)]... */
 
        for (i = 0; i < urb->actual_length; i += 2) {
-               tty_flag = TTY_NORMAL;
                lsr = data[i];
-
-               if (lsr & UART_LSR_BRK_ERROR_BITS) {
-                       if (lsr & UART_LSR_BI) {
-                               tty_flag = TTY_BREAK;
-                               port->icount.brk++;
-                               usb_serial_handle_break(port);
-                       } else if (lsr & UART_LSR_PE) {
-                               tty_flag = TTY_PARITY;
-                               port->icount.parity++;
-                       } else if (lsr & UART_LSR_FE) {
-                               tty_flag = TTY_FRAME;
-                               port->icount.frame++;
-                       }
-
-                       if (lsr & UART_LSR_OE) {
-                               port->icount.overrun++;
-                               schedule_work(&priv->lsr_work);
-                               tty_insert_flip_char(&port->port, 0,
-                                               TTY_OVERRUN);
-                       }
-               }
+               tty_flag = f81232_handle_lsr(port, lsr);
 
                if (port->port.console && port->sysrq) {
                        if (usb_serial_handle_sysrq_char(port, data[i + 1]))
@@ -376,6 +435,47 @@ static void f81232_process_read_urb(struct urb *urb)
        tty_flip_buffer_push(&port->port);
 }
 
+static void f81534a_process_read_urb(struct urb *urb)
+{
+       struct usb_serial_port *port = urb->context;
+       unsigned char *data = urb->transfer_buffer;
+       char tty_flag;
+       unsigned int i;
+       u8 lsr;
+       u8 len;
+
+       if (urb->actual_length < 3) {
+               dev_err(&port->dev, "short message received: %d\n",
+                               urb->actual_length);
+               return;
+       }
+
+       len = data[0];
+       if (len != urb->actual_length) {
+               dev_err(&port->dev, "malformed message received: %d (%d)\n",
+                               urb->actual_length, len);
+               return;
+       }
+
+       /* bulk-in data: [LEN][Data.....][LSR] */
+       lsr = data[len - 1];
+       tty_flag = f81232_handle_lsr(port, lsr);
+
+       if (port->port.console && port->sysrq) {
+               for (i = 1; i < len - 1; ++i) {
+                       if (!usb_serial_handle_sysrq_char(port, data[i])) {
+                               tty_insert_flip_char(&port->port, data[i],
+                                               tty_flag);
+                       }
+               }
+       } else {
+               tty_insert_flip_string_fixed_flag(&port->port, &data[1],
+                                                       tty_flag, len - 2);
+       }
+
+       tty_flip_buffer_push(&port->port);
+}
+
 static void f81232_break_ctl(struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = tty->driver_data;
@@ -659,6 +759,24 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
        return 0;
 }
 
+static int f81534a_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+       int status;
+       u8 mask;
+       u8 val;
+
+       val = F81534A_TRIGGER_MULTIPLE_4X | F81534A_FIFO_128BYTE;
+       mask = F81534A_TRIGGER_MASK | F81534A_FIFO_128BYTE;
+
+       status = f81232_set_mask_register(port, F81534A_MODE_REG, mask, val);
+       if (status) {
+               dev_err(&port->dev, "failed to set MODE_REG: %d\n", status);
+               return status;
+       }
+
+       return f81232_open(tty, port);
+}
+
 static void f81232_close(struct usb_serial_port *port)
 {
        struct f81232_private *port_priv = usb_get_serial_port_data(port);
@@ -678,6 +796,20 @@ static void f81232_dtr_rts(struct usb_serial_port *port, int on)
                f81232_set_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS);
 }
 
+static bool f81232_tx_empty(struct usb_serial_port *port)
+{
+       int status;
+       u8 tmp;
+
+       status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp);
+       if (!status) {
+               if ((tmp & UART_LSR_TEMT) != UART_LSR_TEMT)
+                       return false;
+       }
+
+       return true;
+}
+
 static int f81232_carrier_raised(struct usb_serial_port *port)
 {
        u8 msr;
@@ -728,11 +860,98 @@ static void f81232_lsr_worker(struct work_struct *work)
                dev_warn(&port->dev, "read LSR failed: %d\n", status);
 }
 
+static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg,
+                                       u16 size, void *val)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       int retry = F81534A_ACCESS_REG_RETRY;
+       int status;
+       u8 *tmp;
+
+       tmp = kmemdup(val, size, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       while (retry--) {
+               status = usb_control_msg(dev,
+                                       usb_sndctrlpipe(dev, 0),
+                                       F81232_REGISTER_REQUEST,
+                                       F81232_SET_REGISTER,
+                                       reg,
+                                       0,
+                                       tmp,
+                                       size,
+                                       USB_CTRL_SET_TIMEOUT);
+               if (status < 0) {
+                       status = usb_translate_errors(status);
+                       if (status == -EIO)
+                               continue;
+               } else if (status != size) {
+                       /* Retry on short transfers */
+                       status = -EIO;
+                       continue;
+               } else {
+                       status = 0;
+               }
+
+               break;
+       }
+
+       if (status) {
+               dev_err(&intf->dev, "failed to set register 0x%x: %d\n",
+                               reg, status);
+       }
+
+       kfree(tmp);
+       return status;
+}
+
+static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf, bool en)
+{
+       unsigned char enable[2] = {0};
+       int status;
+
+       /*
+        * Enable all available serial ports, define as following:
+        * bit 15       : Reset behavior (when HUB got soft reset)
+        *                      0: maintain all serial port enabled state.
+        *                      1: disable all serial port.
+        * bit 0~11     : Serial port enable bit.
+        */
+       if (en) {
+               enable[0] = 0xff;
+               enable[1] = 0x8f;
+       }
+
+       status = f81534a_ctrl_set_register(intf, F81534A_CTRL_CMD_ENABLE_PORT,
+                       sizeof(enable), enable);
+       if (status)
+               dev_err(&intf->dev, "failed to enable ports: %d\n", status);
+
+       return status;
+}
+
+static int f81534a_ctrl_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       return f81534a_ctrl_enable_all_ports(intf, true);
+}
+
+static void f81534a_ctrl_disconnect(struct usb_interface *intf)
+{
+       f81534a_ctrl_enable_all_ports(intf, false);
+}
+
+static int f81534a_ctrl_resume(struct usb_interface *intf)
+{
+       return f81534a_ctrl_enable_all_ports(intf, true);
+}
+
 static int f81232_port_probe(struct usb_serial_port *port)
 {
        struct f81232_private *priv;
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(&port->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -748,14 +967,17 @@ static int f81232_port_probe(struct usb_serial_port *port)
        return 0;
 }
 
-static int f81232_port_remove(struct usb_serial_port *port)
+static int f81534a_port_probe(struct usb_serial_port *port)
 {
-       struct f81232_private *priv;
+       int status;
 
-       priv = usb_get_serial_port_data(port);
-       kfree(priv);
+       /* tri-state with pull-high, default RS232 Mode */
+       status = f81232_set_register(port, F81534A_GPIO_REG,
+                                       F81534A_GPIO_MODE2_DIR);
+       if (status)
+               return status;
 
-       return 0;
+       return f81232_port_probe(port);
 }
 
 static int f81232_suspend(struct usb_serial *serial, pm_message_t message)
@@ -799,7 +1021,7 @@ static struct usb_serial_driver f81232_device = {
                .owner =        THIS_MODULE,
                .name =         "f81232",
        },
-       .id_table =             id_table,
+       .id_table =             f81232_id_table,
        .num_ports =            1,
        .bulk_in_size =         256,
        .bulk_out_size =        256,
@@ -813,22 +1035,82 @@ static struct usb_serial_driver f81232_device = {
        .tiocmget =             f81232_tiocmget,
        .tiocmset =             f81232_tiocmset,
        .tiocmiwait =           usb_serial_generic_tiocmiwait,
+       .tx_empty =             f81232_tx_empty,
        .process_read_urb =     f81232_process_read_urb,
        .read_int_callback =    f81232_read_int_callback,
        .port_probe =           f81232_port_probe,
-       .port_remove =          f81232_port_remove,
+       .suspend =              f81232_suspend,
+       .resume =               f81232_resume,
+};
+
+static struct usb_serial_driver f81534a_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "f81534a",
+       },
+       .id_table =             f81534a_id_table,
+       .num_ports =            1,
+       .open =                 f81534a_open,
+       .close =                f81232_close,
+       .dtr_rts =              f81232_dtr_rts,
+       .carrier_raised =       f81232_carrier_raised,
+       .get_serial =           f81232_get_serial_info,
+       .break_ctl =            f81232_break_ctl,
+       .set_termios =          f81232_set_termios,
+       .tiocmget =             f81232_tiocmget,
+       .tiocmset =             f81232_tiocmset,
+       .tiocmiwait =           usb_serial_generic_tiocmiwait,
+       .tx_empty =             f81232_tx_empty,
+       .process_read_urb =     f81534a_process_read_urb,
+       .read_int_callback =    f81232_read_int_callback,
+       .port_probe =           f81534a_port_probe,
        .suspend =              f81232_suspend,
        .resume =               f81232_resume,
 };
 
 static struct usb_serial_driver * const serial_drivers[] = {
        &f81232_device,
+       &f81534a_device,
        NULL,
 };
 
-module_usb_serial_driver(serial_drivers, id_table);
+static struct usb_driver f81534a_ctrl_driver = {
+       .name =         "f81534a_ctrl",
+       .id_table =     f81534a_ctrl_id_table,
+       .probe =        f81534a_ctrl_probe,
+       .disconnect =   f81534a_ctrl_disconnect,
+       .resume =       f81534a_ctrl_resume,
+};
+
+static int __init f81232_init(void)
+{
+       int status;
+
+       status = usb_register_driver(&f81534a_ctrl_driver, THIS_MODULE,
+                       KBUILD_MODNAME);
+       if (status)
+               return status;
+
+       status = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME,
+                       combined_id_table);
+       if (status) {
+               usb_deregister(&f81534a_ctrl_driver);
+               return status;
+       }
+
+       return 0;
+}
+
+static void __exit f81232_exit(void)
+{
+       usb_serial_deregister_drivers(serial_drivers);
+       usb_deregister(&f81534a_ctrl_driver);
+}
+
+module_init(f81232_init);
+module_exit(f81232_exit);
 
-MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
+MODULE_DESCRIPTION("Fintek F81232/532A/534A/535/536 USB to serial driver");
 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
 MODULE_AUTHOR("Peter Hong <peter_hong@fintek.com.tw>");
 MODULE_LICENSE("GPL v2");
index 1be8bea..5cdf180 100644 (file)
@@ -417,7 +417,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
        /*
         * Make sure URB is marked as free before checking the throttled flag
         * to avoid racing with unthrottle() on another CPU. Matches the
-        * smp_mb() in unthrottle().
+        * smp_mb__after_atomic() in unthrottle().
         */
        smp_mb__after_atomic();
 
@@ -489,7 +489,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
         * Matches the smp_mb__after_atomic() in
         * usb_serial_generic_read_bulk_callback().
         */
-       smp_mb();
+       smp_mb__after_atomic();
 
        usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
 }
@@ -609,12 +609,10 @@ EXPORT_SYMBOL_GPL(usb_serial_handle_break);
  * @tty: tty for the port
  * @status: new carrier detect status, nonzero if active
  */
-void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
+void usb_serial_handle_dcd_change(struct usb_serial_port *port,
                                struct tty_struct *tty, unsigned int status)
 {
-       struct tty_port *port = &usb_port->port;
-
-       dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status);
+       dev_dbg(&port->dev, "%s - status %d\n", __func__, status);
 
        if (tty) {
                struct tty_ldisc *ld = tty_ldisc_ref(tty);
@@ -627,7 +625,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
        }
 
        if (status)
-               wake_up_interruptible(&port->open_wait);
+               wake_up_interruptible(&port->port.open_wait);
        else if (tty && !C_CLOCAL(tty))
                tty_hangup(tty);
 }
index 5737add..4cca0b8 100644 (file)
@@ -710,7 +710,7 @@ static void edge_interrupt_callback(struct urb *urb)
                /* grab the txcredits for the ports if available */
                position = 2;
                portNumber = 0;
-               while ((position < length) &&
+               while ((position < length - 1) &&
                                (portNumber < edge_serial->serial->num_ports)) {
                        txCredits = data[position] | (data[position+1] << 8);
                        if (txCredits) {
index c38e87a..0d1a5bb 100644 (file)
@@ -593,7 +593,7 @@ struct ti_i2c_desc {
        __u8    Type;                   // Type of descriptor
        __le16  Size;                   // Size of data only not including header
        __u8    CheckSum;               // Checksum (8 bit sum of data only)
-       __u8    Data[0];                // Data starts here
+       __u8    Data[];         // Data starts here
 } __attribute__((packed));
 
 // for 5152 devices only (type 2 record)
@@ -601,7 +601,7 @@ struct ti_i2c_desc {
 struct ti_i2c_firmware_rec {
        __u8    Ver_Major;              // Firmware Major version number
        __u8    Ver_Minor;              // Firmware Minor version number
-       __u8    Data[0];                // Download starts here
+       __u8    Data[];         // Download starts here
 } __attribute__((packed));
 
 
index 084cc2f..8bfffca 100644 (file)
@@ -1183,6 +1183,8 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = NCTRL(0) },
        { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110a, 0xff),    /* Telit ME910G1 */
          .driver_info = NCTRL(0) | RSVD(3) },
+       { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110b, 0xff),    /* Telit ME910G1 (ECM) */
+         .driver_info = NCTRL(0) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
          .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
        { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
@@ -1990,8 +1992,14 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) },    /* D-Link DWM-152/C1 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) },    /* D-Link DWM-156/C1 */
        { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x7e11, 0xff, 0xff, 0xff) },    /* D-Link DWM-156/A3 */
+       { USB_DEVICE_INTERFACE_CLASS(0x1435, 0xd191, 0xff),                     /* Wistron Neweb D19Q1 */
+         .driver_info = RSVD(1) | RSVD(4) },
+       { USB_DEVICE_INTERFACE_CLASS(0x1690, 0x7588, 0xff),                     /* ASKEY WWHC050 */
+         .driver_info = RSVD(1) | RSVD(4) },
        { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2031, 0xff),                     /* Olicard 600 */
          .driver_info = RSVD(4) },
+       { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2033, 0xff),                     /* BroadMobi BM806U */
+         .driver_info = RSVD(4) },
        { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x2060, 0xff),                     /* BroadMobi BM818 */
          .driver_info = RSVD(4) },
        { USB_DEVICE_INTERFACE_CLASS(0x2020, 0x4000, 0xff) },                   /* OLICARD300 - MT6225 */
index aab737e..c5a2995 100644 (file)
@@ -99,6 +99,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
        { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
        { USB_DEVICE(HP_VENDOR_ID, HP_LD220TA_PRODUCT_ID) },
+       { USB_DEVICE(HP_VENDOR_ID, HP_LD381_PRODUCT_ID) },
        { USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) },
        { USB_DEVICE(HP_VENDOR_ID, HP_LD960TA_PRODUCT_ID) },
        { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) },
index a019ea7..52db551 100644 (file)
 #define HP_LM920_PRODUCT_ID    0x026b
 #define HP_TD620_PRODUCT_ID    0x0956
 #define HP_LD960_PRODUCT_ID    0x0b39
+#define HP_LD381_PRODUCT_ID    0x0f7f
 #define HP_LCM220_PRODUCT_ID   0x3139
 #define HP_LCM960_PRODUCT_ID   0x3239
 #define HP_LD220_PRODUCT_ID    0x3524
index ef23acc..73075b9 100644 (file)
@@ -219,7 +219,7 @@ struct ti_write_data_bytes {
        u8      bDataCounter;
        __be16  wBaseAddrHi;
        __be16  wBaseAddrLo;
-       u8      bData[0];
+       u8      bData[];
 } __packed;
 
 struct ti_read_data_request {
@@ -234,7 +234,7 @@ struct ti_read_data_bytes {
        __u8    bCmdCode;
        __u8    bModuleId;
        __u8    bErrorCode;
-       __u8    bData[0];
+       __u8    bData[];
 } __packed;
 
 /* Interrupt struct */
index dc7a65b..27e3bb5 100644 (file)
@@ -288,7 +288,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
 
 /**
  * serial_cleanup - free resources post close/hangup
- * @port: port to free up
+ * @tty: tty to clean up
  *
  * Do the resource freeing and refcount dropping for the port.
  * Avoid freeing the console.
index 1cd9b63..1880f3e 100644 (file)
@@ -1258,6 +1258,12 @@ UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999,
                USB_SC_RBC, USB_PR_BULK, NULL,
                0 ),
 
+UNUSUAL_DEV(0x090c, 0x1000, 0x1100, 0x1100,
+               "Samsung",
+               "Flash Drive FIT",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_MAX_SECTORS_64),
+
 /* aeb */
 UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
                "Feiya",
index 9a79cd9..94a6472 100644 (file)
@@ -121,12 +121,12 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
        .initFunction = init_function,  \
 }
 
-static struct us_unusual_dev us_unusual_dev_list[] = {
+static const struct us_unusual_dev us_unusual_dev_list[] = {
 #      include "unusual_devs.h"
        { }             /* Terminating entry */
 };
 
-static struct us_unusual_dev for_dynamic_ids =
+static const struct us_unusual_dev for_dynamic_ids =
                USUAL_DEV(USB_SC_SCSI, USB_PR_BULK);
 
 #undef UNUSUAL_DEV
@@ -583,7 +583,7 @@ EXPORT_SYMBOL_GPL(usb_stor_adjust_quirks);
 
 /* Get the unusual_devs entries and the string descriptors */
 static int get_device_info(struct us_data *us, const struct usb_device_id *id,
-               struct us_unusual_dev *unusual_dev)
+               const struct us_unusual_dev *unusual_dev)
 {
        struct usb_device *dev = us->pusb_dev;
        struct usb_interface_descriptor *idesc =
@@ -933,7 +933,7 @@ static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf)
 int usb_stor_probe1(struct us_data **pus,
                struct usb_interface *intf,
                const struct usb_device_id *id,
-               struct us_unusual_dev *unusual_dev,
+               const struct us_unusual_dev *unusual_dev,
                struct scsi_host_template *sht)
 {
        struct Scsi_Host *host;
@@ -1092,7 +1092,7 @@ static struct scsi_host_template usb_stor_host_template;
 static int storage_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
-       struct us_unusual_dev *unusual_dev;
+       const struct us_unusual_dev *unusual_dev;
        struct us_data *us;
        int result;
        int size;
index 85052cd..5850d62 100644 (file)
@@ -93,7 +93,8 @@ struct us_data {
        struct mutex            dev_mutex;       /* protect pusb_dev */
        struct usb_device       *pusb_dev;       /* this usb_device */
        struct usb_interface    *pusb_intf;      /* this interface */
-       struct us_unusual_dev   *unusual_dev;    /* device-filter entry     */
+       const struct us_unusual_dev   *unusual_dev;
+                                               /* device-filter entry     */
        unsigned long           fflags;          /* fixed flags from filter */
        unsigned long           dflags;          /* dynamic atomic bitflags */
        unsigned int            send_bulk_pipe;  /* cached pipe values */
@@ -185,7 +186,7 @@ extern int usb_stor_post_reset(struct usb_interface *iface);
 extern int usb_stor_probe1(struct us_data **pus,
                struct usb_interface *intf,
                const struct usb_device_id *id,
-               struct us_unusual_dev *unusual_dev,
+               const struct us_unusual_dev *unusual_dev,
                struct scsi_host_template *sht);
 extern int usb_stor_probe2(struct us_data *us);
 extern void usb_stor_disconnect(struct usb_interface *intf);
index cfd12e5..5295128 100644 (file)
@@ -40,7 +40,7 @@
        .driver_info = (flags) \
 }
 
-struct usb_device_id usb_storage_usb_ids[] = {
+const struct usb_device_id usb_storage_usb_ids[] = {
 #      include "unusual_devs.h"
        { }             /* Terminating entry */
 };
@@ -68,7 +68,7 @@ struct ignore_entry {
        .bcdmax = bcdDeviceMax,         \
 }
 
-static struct ignore_entry ignore_ids[] = {
+static const struct ignore_entry ignore_ids[] = {
 #      include "unusual_alauda.h"
 #      include "unusual_cypress.h"
 #      include "unusual_datafab.h"
@@ -92,7 +92,7 @@ int usb_usual_ignore_device(struct usb_interface *intf)
 {
        struct usb_device *udev;
        unsigned vid, pid, bcd;
-       struct ignore_entry *p;
+       const struct ignore_entry *p;
 
        udev = interface_to_usbdev(intf);
        vid = le16_to_cpu(udev->descriptor.idVendor);
index 2e45eb4..c823122 100644 (file)
@@ -30,17 +30,10 @@ static int typec_altmode_set_state(struct typec_altmode *adev,
 {
        bool is_port = is_typec_port(adev->dev.parent);
        struct altmode *port_altmode;
-       int ret;
 
        port_altmode = is_port ? to_altmode(adev) : to_altmode(adev)->partner;
 
-       ret = typec_altmode_set_mux(port_altmode, conf, data);
-       if (ret)
-               return ret;
-
-       blocking_notifier_call_chain(&port_altmode->nh, conf, NULL);
-
-       return 0;
+       return typec_altmode_set_mux(port_altmode, conf, data);
 }
 
 /* -------------------------------------------------------------------------- */
@@ -82,9 +75,6 @@ int typec_altmode_notify(struct typec_altmode *adev,
        if (ret)
                return ret;
 
-       blocking_notifier_call_chain(is_port ? &altmode->nh : &partner->nh,
-                                    conf, data);
-
        if (partner->adev.ops && partner->adev.ops->notify)
                return partner->adev.ops->notify(&partner->adev, conf, data);
 
index 0c9661c..8ba8112 100644 (file)
@@ -22,8 +22,6 @@ struct altmode {
 
        struct altmode                  *partner;
        struct altmode                  *plug[2];
-
-       struct blocking_notifier_head   nh;
 };
 
 #define to_altmode(d) container_of(d, struct altmode, adev)
index 7c44e93..8d894bd 100644 (file)
@@ -206,69 +206,6 @@ static void typec_altmode_put_partner(struct altmode *altmode)
        put_device(&adev->dev);
 }
 
-static void *typec_port_match(struct device_connection *con, int ep, void *data)
-{
-       struct device *dev;
-
-       /*
-        * FIXME: Check does the fwnode supports the requested SVID. If it does
-        * we need to return ERR_PTR(-PROBE_DEFER) when there is no device.
-        */
-       if (con->fwnode)
-               return class_find_device_by_fwnode(typec_class, con->fwnode);
-
-       dev = class_find_device_by_name(typec_class, con->endpoint[ep]);
-
-       return dev ? dev : ERR_PTR(-EPROBE_DEFER);
-}
-
-struct typec_altmode *
-typec_altmode_register_notifier(struct device *dev, u16 svid, u8 mode,
-                               struct notifier_block *nb)
-{
-       struct typec_device_id id = { svid, mode, };
-       struct device *altmode_dev;
-       struct device *port_dev;
-       struct altmode *altmode;
-       int ret;
-
-       /* Find the port linked to the caller */
-       port_dev = device_connection_find_match(dev, NULL, NULL,
-                                               typec_port_match);
-       if (IS_ERR_OR_NULL(port_dev))
-               return port_dev ? ERR_CAST(port_dev) : ERR_PTR(-ENODEV);
-
-       /* Find the altmode with matching svid */
-       altmode_dev = device_find_child(port_dev, &id, altmode_match);
-
-       put_device(port_dev);
-
-       if (!altmode_dev)
-               return ERR_PTR(-ENODEV);
-
-       altmode = to_altmode(to_typec_altmode(altmode_dev));
-
-       /* Register notifier */
-       ret = blocking_notifier_chain_register(&altmode->nh, nb);
-       if (ret) {
-               put_device(altmode_dev);
-               return ERR_PTR(ret);
-       }
-
-       return &altmode->adev;
-}
-EXPORT_SYMBOL_GPL(typec_altmode_register_notifier);
-
-void typec_altmode_unregister_notifier(struct typec_altmode *adev,
-                                      struct notifier_block *nb)
-{
-       struct altmode *altmode = to_altmode(adev);
-
-       blocking_notifier_chain_unregister(&altmode->nh, nb);
-       put_device(&adev->dev);
-}
-EXPORT_SYMBOL_GPL(typec_altmode_unregister_notifier);
-
 /**
  * typec_altmode_update_active - Report Enter/Exit mode
  * @adev: Handle to the alternate mode
@@ -432,7 +369,28 @@ static struct attribute *typec_altmode_attrs[] = {
        &dev_attr_vdo.attr,
        NULL
 };
-ATTRIBUTE_GROUPS(typec_altmode);
+
+static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
+                                            struct attribute *attr, int n)
+{
+       struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
+
+       if (attr == &dev_attr_active.attr)
+               if (!adev->ops || !adev->ops->activate)
+                       return 0444;
+
+       return attr->mode;
+}
+
+static struct attribute_group typec_altmode_group = {
+       .is_visible = typec_altmode_attr_is_visible,
+       .attrs = typec_altmode_attrs,
+};
+
+static const struct attribute_group *typec_altmode_groups[] = {
+       &typec_altmode_group,
+       NULL
+};
 
 static int altmode_id_get(struct device *dev)
 {
@@ -517,9 +475,7 @@ typec_register_altmode(struct device *parent,
        dev_set_name(&alt->adev.dev, "%s.%u", dev_name(parent), id);
 
        /* Link partners and plugs with the ports */
-       if (is_port)
-               BLOCKING_INIT_NOTIFIER_HEAD(&alt->nh);
-       else
+       if (!is_port)
                typec_altmode_set_partner(alt);
 
        /* The partners are bind to drivers */
@@ -859,7 +815,7 @@ struct typec_cable *typec_cable_get(struct typec_port *port)
 EXPORT_SYMBOL_GPL(typec_cable_get);
 
 /**
- * typec_cable_get - Decrement the reference count on USB Type-C cable
+ * typec_cable_put - Decrement the reference count on USB Type-C cable
  * @cable: The USB Type-C cable
  */
 void typec_cable_put(struct typec_cable *cable)
@@ -1091,11 +1047,6 @@ static ssize_t power_role_store(struct device *dev,
        struct typec_port *port = to_typec_port(dev);
        int ret;
 
-       if (!port->cap->pd_revision) {
-               dev_dbg(dev, "USB Power Delivery not supported\n");
-               return -EOPNOTSUPP;
-       }
-
        if (!port->ops || !port->ops->pr_set) {
                dev_dbg(dev, "power role swapping not supported\n");
                return -EOPNOTSUPP;
@@ -1293,6 +1244,25 @@ static ssize_t usb_power_delivery_revision_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(usb_power_delivery_revision);
 
+static ssize_t orientation_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct typec_port *p = to_typec_port(dev);
+       enum typec_orientation orientation = typec_get_orientation(p);
+
+       switch (orientation) {
+       case TYPEC_ORIENTATION_NORMAL:
+               return sprintf(buf, "%s\n", "normal");
+       case TYPEC_ORIENTATION_REVERSE:
+               return sprintf(buf, "%s\n", "reverse");
+       case TYPEC_ORIENTATION_NONE:
+       default:
+               return sprintf(buf, "%s\n", "unknown");
+       }
+}
+static DEVICE_ATTR_RO(orientation);
+
 static struct attribute *typec_attrs[] = {
        &dev_attr_data_role.attr,
        &dev_attr_power_operation_mode.attr,
@@ -1303,9 +1273,54 @@ static struct attribute *typec_attrs[] = {
        &dev_attr_usb_typec_revision.attr,
        &dev_attr_vconn_source.attr,
        &dev_attr_port_type.attr,
+       &dev_attr_orientation.attr,
        NULL,
 };
-ATTRIBUTE_GROUPS(typec);
+
+static umode_t typec_attr_is_visible(struct kobject *kobj,
+                                    struct attribute *attr, int n)
+{
+       struct typec_port *port = to_typec_port(kobj_to_dev(kobj));
+
+       if (attr == &dev_attr_data_role.attr) {
+               if (port->cap->data != TYPEC_PORT_DRD ||
+                   !port->ops || !port->ops->dr_set)
+                       return 0444;
+       } else if (attr == &dev_attr_power_role.attr) {
+               if (port->cap->type != TYPEC_PORT_DRP ||
+                   !port->ops || !port->ops->pr_set)
+                       return 0444;
+       } else if (attr == &dev_attr_vconn_source.attr) {
+               if (!port->cap->pd_revision ||
+                   !port->ops || !port->ops->vconn_set)
+                       return 0444;
+       } else if (attr == &dev_attr_preferred_role.attr) {
+               if (port->cap->type != TYPEC_PORT_DRP ||
+                   !port->ops || !port->ops->try_role)
+                       return 0444;
+       } else if (attr == &dev_attr_port_type.attr) {
+               if (!port->ops || !port->ops->port_type_set)
+                       return 0;
+               if (port->cap->type != TYPEC_PORT_DRP)
+                       return 0444;
+       } else if (attr == &dev_attr_orientation.attr) {
+               if (port->cap->orientation_aware)
+                       return 0444;
+               return 0;
+       }
+
+       return attr->mode;
+}
+
+static struct attribute_group typec_group = {
+       .is_visible = typec_attr_is_visible,
+       .attrs = typec_attrs,
+};
+
+static const struct attribute_group *typec_groups[] = {
+       &typec_group,
+       NULL
+};
 
 static int typec_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
@@ -1495,13 +1510,13 @@ int typec_set_orientation(struct typec_port *port,
 {
        int ret;
 
-       if (port->sw) {
-               ret = port->sw->set(port->sw, orientation);
-               if (ret)
-                       return ret;
-       }
+       ret = typec_switch_set(port->sw, orientation);
+       if (ret)
+               return ret;
 
        port->orientation = orientation;
+       sysfs_notify(&port->dev.kobj, NULL, "orientation");
+       kobject_uevent(&port->dev.kobj, KOBJ_CHANGE);
 
        return 0;
 }
@@ -1533,7 +1548,7 @@ int typec_set_mode(struct typec_port *port, int mode)
 
        state.mode = mode;
 
-       return port->mux ? port->mux->set(port->mux, &state) : 0;
+       return typec_mux_set(port->mux, &state);
 }
 EXPORT_SYMBOL_GPL(typec_set_mode);
 
index 5baf0f4..52ad277 100644 (file)
 
 #include "bus.h"
 
-static int name_match(struct device *dev, const void *name)
-{
-       return !strcmp((const char *)name, dev_name(dev));
-}
-
 static bool dev_name_ends_with(struct device *dev, const char *suffix)
 {
        const char *name = dev_name(dev);
@@ -44,41 +39,36 @@ static void *typec_switch_match(struct device_connection *con, int ep,
 {
        struct device *dev;
 
-       if (con->fwnode) {
-               if (con->id && !fwnode_property_present(con->fwnode, con->id))
-                       return NULL;
+       if (con->id && !fwnode_property_present(con->fwnode, con->id))
+               return NULL;
 
-               dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
-                                       switch_fwnode_match);
-       } else {
-               dev = class_find_device(&typec_mux_class, NULL,
-                                       con->endpoint[ep], name_match);
-       }
+       dev = class_find_device(&typec_mux_class, NULL, con->fwnode,
+                               switch_fwnode_match);
 
        return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
 }
 
 /**
- * typec_switch_get - Find USB Type-C orientation switch
- * @dev: The caller device
+ * fwnode_typec_switch_get - Find USB Type-C orientation switch
+ * @fwnode: The caller device node
  *
  * Finds a switch linked with @dev. Returns a reference to the switch on
  * success, NULL if no matching connection was found, or
  * ERR_PTR(-EPROBE_DEFER) when a connection was found but the switch
  * has not been enumerated yet.
  */
-struct typec_switch *typec_switch_get(struct device *dev)
+struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode)
 {
        struct typec_switch *sw;
 
-       sw = device_connection_find_match(dev, "orientation-switch", NULL,
+       sw = fwnode_connection_find_match(fwnode, "orientation-switch", NULL,
                                          typec_switch_match);
        if (!IS_ERR_OR_NULL(sw))
                WARN_ON(!try_module_get(sw->dev.parent->driver->owner));
 
        return sw;
 }
-EXPORT_SYMBOL_GPL(typec_switch_get);
+EXPORT_SYMBOL_GPL(fwnode_typec_switch_get);
 
 /**
  * typec_put_switch - Release USB Type-C orientation switch
@@ -137,7 +127,8 @@ typec_switch_register(struct device *parent,
        sw->dev.class = &typec_mux_class;
        sw->dev.type = &typec_switch_dev_type;
        sw->dev.driver_data = desc->drvdata;
-       dev_set_name(&sw->dev, "%s-switch", dev_name(parent));
+       dev_set_name(&sw->dev, "%s-switch",
+                    desc->name ? desc->name : dev_name(parent));
 
        ret = device_add(&sw->dev);
        if (ret) {
@@ -150,6 +141,16 @@ typec_switch_register(struct device *parent,
 }
 EXPORT_SYMBOL_GPL(typec_switch_register);
 
+int typec_switch_set(struct typec_switch *sw,
+                    enum typec_orientation orientation)
+{
+       if (IS_ERR_OR_NULL(sw))
+               return 0;
+
+       return sw->set(sw, orientation);
+}
+EXPORT_SYMBOL_GPL(typec_switch_set);
+
 /**
  * typec_switch_unregister - Unregister USB Type-C orientation switch
  * @sw: USB Type-C orientation switch
@@ -191,13 +192,6 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
        u16 *val;
        int i;
 
-       if (!con->fwnode) {
-               dev = class_find_device(&typec_mux_class, NULL,
-                                       con->endpoint[ep], name_match);
-
-               return dev ? to_typec_switch(dev) : ERR_PTR(-EPROBE_DEFER);
-       }
-
        /*
         * Check has the identifier already been "consumed". If it
         * has, no need to do any extra connection identification.
@@ -247,8 +241,8 @@ find_mux:
 }
 
 /**
- * typec_mux_get - Find USB Type-C Multiplexer
- * @dev: The caller device
+ * fwnode_typec_mux_get - Find USB Type-C Multiplexer
+ * @fwnode: The caller device node
  * @desc: Alt Mode description
  *
  * Finds a mux linked to the caller. This function is primarily meant for the
@@ -256,19 +250,19 @@ find_mux:
  * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection
  * was found but the mux has not been enumerated yet.
  */
-struct typec_mux *typec_mux_get(struct device *dev,
-                               const struct typec_altmode_desc *desc)
+struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode,
+                                      const struct typec_altmode_desc *desc)
 {
        struct typec_mux *mux;
 
-       mux = device_connection_find_match(dev, "mode-switch", (void *)desc,
+       mux = fwnode_connection_find_match(fwnode, "mode-switch", (void *)desc,
                                           typec_mux_match);
        if (!IS_ERR_OR_NULL(mux))
                WARN_ON(!try_module_get(mux->dev.parent->driver->owner));
 
        return mux;
 }
-EXPORT_SYMBOL_GPL(typec_mux_get);
+EXPORT_SYMBOL_GPL(fwnode_typec_mux_get);
 
 /**
  * typec_mux_put - Release handle to a Multiplexer
@@ -285,6 +279,15 @@ void typec_mux_put(struct typec_mux *mux)
 }
 EXPORT_SYMBOL_GPL(typec_mux_put);
 
+int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
+{
+       if (IS_ERR_OR_NULL(mux))
+               return 0;
+
+       return mux->set(mux, state);
+}
+EXPORT_SYMBOL_GPL(typec_mux_set);
+
 static void typec_mux_release(struct device *dev)
 {
        kfree(to_typec_mux(dev));
@@ -326,7 +329,8 @@ typec_mux_register(struct device *parent, const struct typec_mux_desc *desc)
        mux->dev.class = &typec_mux_class;
        mux->dev.type = &typec_mux_dev_type;
        mux->dev.driver_data = desc->drvdata;
-       dev_set_name(&mux->dev, "%s-mux", dev_name(parent));
+       dev_set_name(&mux->dev, "%s-mux",
+                    desc->name ? desc->name : dev_name(parent));
 
        ret = device_add(&mux->dev);
        if (ret) {
index 01ed0d5..77eb97b 100644 (file)
@@ -9,4 +9,13 @@ config TYPEC_MUX_PI3USB30532
          Say Y or M if your system has a Pericom PI3USB30532 Type-C cross
          switch / mux chip found on some devices with a Type-C port.
 
+config TYPEC_MUX_INTEL_PMC
+       tristate "Intel PMC mux control"
+       depends on INTEL_PMC_IPC
+       select USB_ROLE_SWITCH
+       help
+         Driver for USB muxes controlled by Intel PMC FW. Intel PMC FW can
+         control the USB role switch and also the multiplexer/demultiplexer
+         switches used with USB Type-C Alternate Modes.
+
 endmenu
index 1332e46..280a6f5 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_TYPEC_MUX_PI3USB30532)    += pi3usb30532.o
+obj-$(CONFIG_TYPEC_MUX_INTEL_PMC)      += intel_pmc_mux.o
diff --git a/drivers/usb/typec/mux/intel_pmc_mux.c b/drivers/usb/typec/mux/intel_pmc_mux.c
new file mode 100644 (file)
index 0000000..f5c5e0a
--- /dev/null
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Intel PMC USB mux control
+ *
+ * Copyright (C) 2020 Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/usb/role.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_tbt.h>
+
+#include <asm/intel_pmc_ipc.h>
+
+#define PMC_USBC_CMD           0xa7
+
+/* "Usage" OOB Message field values */
+enum {
+       PMC_USB_CONNECT,
+       PMC_USB_DISCONNECT,
+       PMC_USB_SAFE_MODE,
+       PMC_USB_ALT_MODE,
+       PMC_USB_DP_HPD,
+};
+
+#define PMC_USB_MSG_USB2_PORT_SHIFT    0
+#define PMC_USB_MSG_USB3_PORT_SHIFT    4
+#define PMC_USB_MSG_UFP_SHIFT          4
+#define PMC_USB_MSG_ORI_HSL_SHIFT      5
+#define PMC_USB_MSG_ORI_AUX_SHIFT      6
+
+/* Alt Mode Request */
+struct altmode_req {
+       u8 usage;
+       u8 mode_type;
+       u8 mode_id;
+       u8 reserved;
+       u32 mode_data;
+} __packed;
+
+#define PMC_USB_MODE_TYPE_SHIFT                4
+
+enum {
+       PMC_USB_MODE_TYPE_USB,
+       PMC_USB_MODE_TYPE_DP,
+       PMC_USB_MODE_TYPE_TBT,
+};
+
+/* Common Mode Data bits */
+#define PMC_USB_ALTMODE_ACTIVE_CABLE   BIT(2)
+
+#define PMC_USB_ALTMODE_ORI_SHIFT      1
+#define PMC_USB_ALTMODE_UFP_SHIFT      3
+#define PMC_USB_ALTMODE_ORI_AUX_SHIFT  4
+#define PMC_USB_ALTMODE_ORI_HSL_SHIFT  5
+
+/* DP specific Mode Data bits */
+#define PMC_USB_ALTMODE_DP_MODE_SHIFT  8
+
+/* TBT specific Mode Data bits */
+#define PMC_USB_ALTMODE_TBT_TYPE       BIT(17)
+#define PMC_USB_ALTMODE_CABLE_TYPE     BIT(18)
+#define PMC_USB_ALTMODE_ACTIVE_LINK    BIT(20)
+#define PMC_USB_ALTMODE_FORCE_LSR      BIT(23)
+#define PMC_USB_ALTMODE_CABLE_SPD(_s_) (((_s_) & GENMASK(2, 0)) << 25)
+#define   PMC_USB_ALTMODE_CABLE_USB31  1
+#define   PMC_USB_ALTMODE_CABLE_10GPS  2
+#define   PMC_USB_ALTMODE_CABLE_20GPS  3
+#define PMC_USB_ALTMODE_TBT_GEN(_g_)   (((_g_) & GENMASK(1, 0)) << 28)
+
+/* Display HPD Request bits */
+#define PMC_USB_DP_HPD_IRQ             BIT(5)
+#define PMC_USB_DP_HPD_LVL             BIT(6)
+
+struct pmc_usb;
+
+struct pmc_usb_port {
+       int num;
+       struct pmc_usb *pmc;
+       struct typec_mux *typec_mux;
+       struct typec_switch *typec_sw;
+       struct usb_role_switch *usb_sw;
+
+       enum typec_orientation orientation;
+       enum usb_role role;
+
+       u8 usb2_port;
+       u8 usb3_port;
+};
+
+struct pmc_usb {
+       u8 num_ports;
+       struct device *dev;
+       struct pmc_usb_port *port;
+};
+
+static int pmc_usb_command(struct pmc_usb_port *port, u8 *msg, u32 len)
+{
+       u8 response[4];
+
+       /*
+        * Error bit will always be 0 with the USBC command.
+        * Status can be checked from the response message.
+        */
+       intel_pmc_ipc_command(PMC_USBC_CMD, 0, msg, len,
+                             (void *)response, 1);
+
+       if (response[2]) {
+               if (response[2] & BIT(1))
+                       return -EIO;
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int
+pmc_usb_mux_dp_hpd(struct pmc_usb_port *port, struct typec_mux_state *state)
+{
+       struct typec_displayport_data *data = state->data;
+       u8 msg[2] = { };
+
+       msg[0] = PMC_USB_DP_HPD;
+       msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
+
+       msg[1] = PMC_USB_DP_HPD_IRQ;
+
+       if (data->status & DP_STATUS_HPD_STATE)
+               msg[1] |= PMC_USB_DP_HPD_LVL;
+
+       return pmc_usb_command(port, msg, sizeof(msg));
+}
+
+static int
+pmc_usb_mux_dp(struct pmc_usb_port *port, struct typec_mux_state *state)
+{
+       struct typec_displayport_data *data = state->data;
+       struct altmode_req req = { };
+
+       if (data->status & DP_STATUS_IRQ_HPD)
+               return pmc_usb_mux_dp_hpd(port, state);
+
+       req.usage = PMC_USB_ALT_MODE;
+       req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
+       req.mode_type = PMC_USB_MODE_TYPE_DP << PMC_USB_MODE_TYPE_SHIFT;
+
+       req.mode_data = (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT;
+       req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT;
+       req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_AUX_SHIFT;
+       req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_HSL_SHIFT;
+
+       req.mode_data |= (state->mode - TYPEC_STATE_MODAL) <<
+                        PMC_USB_ALTMODE_DP_MODE_SHIFT;
+
+       return pmc_usb_command(port, (void *)&req, sizeof(req));
+}
+
+static int
+pmc_usb_mux_tbt(struct pmc_usb_port *port, struct typec_mux_state *state)
+{
+       struct typec_thunderbolt_data *data = state->data;
+       u8 cable_speed = TBT_CABLE_SPEED(data->cable_mode);
+       struct altmode_req req = { };
+
+       req.usage = PMC_USB_ALT_MODE;
+       req.usage |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
+       req.mode_type = PMC_USB_MODE_TYPE_TBT << PMC_USB_MODE_TYPE_SHIFT;
+
+       req.mode_data = (port->orientation - 1) << PMC_USB_ALTMODE_ORI_SHIFT;
+       req.mode_data |= (port->role - 1) << PMC_USB_ALTMODE_UFP_SHIFT;
+       req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_AUX_SHIFT;
+       req.mode_data |= (port->orientation - 1) << PMC_USB_ALTMODE_ORI_HSL_SHIFT;
+
+       if (TBT_ADAPTER(data->device_mode) == TBT_ADAPTER_TBT3)
+               req.mode_data |= PMC_USB_ALTMODE_TBT_TYPE;
+
+       if (data->cable_mode & TBT_CABLE_OPTICAL)
+               req.mode_data |= PMC_USB_ALTMODE_CABLE_TYPE;
+
+       if (data->cable_mode & TBT_CABLE_LINK_TRAINING)
+               req.mode_data |= PMC_USB_ALTMODE_ACTIVE_LINK;
+
+       if (data->enter_vdo & TBT_ENTER_MODE_ACTIVE_CABLE)
+               req.mode_data |= PMC_USB_ALTMODE_ACTIVE_CABLE;
+
+       req.mode_data |= PMC_USB_ALTMODE_CABLE_SPD(cable_speed);
+
+       return pmc_usb_command(port, (void *)&req, sizeof(req));
+}
+
+static int pmc_usb_mux_safe_state(struct pmc_usb_port *port)
+{
+       u8 msg;
+
+       msg = PMC_USB_SAFE_MODE;
+       msg |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
+
+       return pmc_usb_command(port, &msg, sizeof(msg));
+}
+
+static int pmc_usb_connect(struct pmc_usb_port *port)
+{
+       u8 msg[2];
+
+       msg[0] = PMC_USB_CONNECT;
+       msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
+
+       msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT;
+       msg[1] |= (port->orientation - 1) << PMC_USB_MSG_ORI_HSL_SHIFT;
+       msg[1] |= (port->orientation - 1) << PMC_USB_MSG_ORI_AUX_SHIFT;
+
+       return pmc_usb_command(port, msg, sizeof(msg));
+}
+
+static int pmc_usb_disconnect(struct pmc_usb_port *port)
+{
+       u8 msg[2];
+
+       msg[0] = PMC_USB_DISCONNECT;
+       msg[0] |= port->usb3_port << PMC_USB_MSG_USB3_PORT_SHIFT;
+
+       msg[1] = port->usb2_port << PMC_USB_MSG_USB2_PORT_SHIFT;
+
+       return pmc_usb_command(port, msg, sizeof(msg));
+}
+
+static int
+pmc_usb_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
+{
+       struct pmc_usb_port *port = typec_mux_get_drvdata(mux);
+
+       if (!state->alt)
+               return 0;
+
+       if (state->mode == TYPEC_STATE_SAFE)
+               return pmc_usb_mux_safe_state(port);
+
+       switch (state->alt->svid) {
+       case USB_TYPEC_TBT_SID:
+               return pmc_usb_mux_tbt(port, state);
+       case USB_TYPEC_DP_SID:
+               return pmc_usb_mux_dp(port, state);
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static int pmc_usb_set_orientation(struct typec_switch *sw,
+                                  enum typec_orientation orientation)
+{
+       struct pmc_usb_port *port = typec_switch_get_drvdata(sw);
+
+       if (port->orientation == orientation)
+               return 0;
+
+       port->orientation = orientation;
+
+       if (port->role) {
+               if (orientation == TYPEC_ORIENTATION_NONE)
+                       return pmc_usb_disconnect(port);
+               else
+                       return pmc_usb_connect(port);
+       }
+
+       return 0;
+}
+
+static int pmc_usb_set_role(struct usb_role_switch *sw, enum usb_role role)
+{
+       struct pmc_usb_port *port = usb_role_switch_get_drvdata(sw);
+
+       if (port->role == role)
+               return 0;
+
+       port->role = role;
+
+       if (port->orientation) {
+               if (role == USB_ROLE_NONE)
+                       return pmc_usb_disconnect(port);
+               else
+                       return pmc_usb_connect(port);
+       }
+
+       return 0;
+}
+
+static int pmc_usb_register_port(struct pmc_usb *pmc, int index,
+                                struct fwnode_handle *fwnode)
+{
+       struct pmc_usb_port *port = &pmc->port[index];
+       struct usb_role_switch_desc desc = { };
+       struct typec_switch_desc sw_desc = { };
+       struct typec_mux_desc mux_desc = { };
+       int ret;
+
+       ret = fwnode_property_read_u8(fwnode, "usb2-port", &port->usb2_port);
+       if (ret)
+               return ret;
+
+       ret = fwnode_property_read_u8(fwnode, "usb3-port", &port->usb3_port);
+       if (ret)
+               return ret;
+
+       port->num = index;
+       port->pmc = pmc;
+
+       sw_desc.fwnode = fwnode;
+       sw_desc.drvdata = port;
+       sw_desc.name = fwnode_get_name(fwnode);
+       sw_desc.set = pmc_usb_set_orientation;
+
+       port->typec_sw = typec_switch_register(pmc->dev, &sw_desc);
+       if (IS_ERR(port->typec_sw))
+               return PTR_ERR(port->typec_sw);
+
+       mux_desc.fwnode = fwnode;
+       mux_desc.drvdata = port;
+       mux_desc.name = fwnode_get_name(fwnode);
+       mux_desc.set = pmc_usb_mux_set;
+
+       port->typec_mux = typec_mux_register(pmc->dev, &mux_desc);
+       if (IS_ERR(port->typec_mux)) {
+               ret = PTR_ERR(port->typec_mux);
+               goto err_unregister_switch;
+       }
+
+       desc.fwnode = fwnode;
+       desc.driver_data = port;
+       desc.name = fwnode_get_name(fwnode);
+       desc.set = pmc_usb_set_role;
+
+       port->usb_sw = usb_role_switch_register(pmc->dev, &desc);
+       if (IS_ERR(port->usb_sw)) {
+               ret = PTR_ERR(port->usb_sw);
+               goto err_unregister_mux;
+       }
+
+       return 0;
+
+err_unregister_mux:
+       typec_mux_unregister(port->typec_mux);
+
+err_unregister_switch:
+       typec_switch_unregister(port->typec_sw);
+
+       return ret;
+}
+
+static int pmc_usb_probe(struct platform_device *pdev)
+{
+       struct fwnode_handle *fwnode = NULL;
+       struct pmc_usb *pmc;
+       int i = 0;
+       int ret;
+
+       pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL);
+       if (!pmc)
+               return -ENOMEM;
+
+       device_for_each_child_node(&pdev->dev, fwnode)
+               pmc->num_ports++;
+
+       pmc->port = devm_kcalloc(&pdev->dev, pmc->num_ports,
+                                sizeof(struct pmc_usb_port), GFP_KERNEL);
+       if (!pmc->port)
+               return -ENOMEM;
+
+       pmc->dev = &pdev->dev;
+
+       /*
+        * For every physical USB connector (USB2 and USB3 combo) there is a
+        * child ACPI device node under the PMC mux ACPI device object.
+        */
+       for (i = 0; i < pmc->num_ports; i++) {
+               fwnode = device_get_next_child_node(pmc->dev, fwnode);
+               if (!fwnode)
+                       break;
+
+               ret = pmc_usb_register_port(pmc, i, fwnode);
+               if (ret)
+                       goto err_remove_ports;
+       }
+
+       platform_set_drvdata(pdev, pmc);
+
+       return 0;
+
+err_remove_ports:
+       for (i = 0; i < pmc->num_ports; i++) {
+               typec_switch_unregister(pmc->port[i].typec_sw);
+               typec_mux_unregister(pmc->port[i].typec_mux);
+       }
+
+       return ret;
+}
+
+static int pmc_usb_remove(struct platform_device *pdev)
+{
+       struct pmc_usb *pmc = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < pmc->num_ports; i++) {
+               typec_switch_unregister(pmc->port[i].typec_sw);
+               typec_mux_unregister(pmc->port[i].typec_mux);
+       }
+
+       return 0;
+}
+
+static const struct acpi_device_id pmc_usb_acpi_ids[] = {
+       { "INTC105C", },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, pmc_usb_acpi_ids);
+
+static struct platform_driver pmc_usb_driver = {
+       .driver = {
+               .name = "intel_pmc_usb",
+               .acpi_match_table = ACPI_PTR(pmc_usb_acpi_ids),
+       },
+       .probe = pmc_usb_probe,
+       .remove = pmc_usb_remove,
+};
+
+module_platform_driver(pmc_usb_driver);
+
+MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel PMC USB mux control");
index f3087ef..de3576e 100644 (file)
@@ -373,6 +373,14 @@ struct pd_rx_event {
        ((port)->try_src_count == 0 && (port)->try_role == TYPEC_SOURCE && \
        (port)->port_type == TYPEC_PORT_DRP)
 
+#define tcpm_data_role_for_source(port) \
+       ((port)->typec_caps.data == TYPEC_PORT_UFP ? \
+       TYPEC_DEVICE : TYPEC_HOST)
+
+#define tcpm_data_role_for_sink(port) \
+       ((port)->typec_caps.data == TYPEC_PORT_DFP ? \
+       TYPEC_HOST : TYPEC_DEVICE)
+
 static enum tcpm_state tcpm_default_state(struct tcpm_port *port)
 {
        if (port->port_type == TYPEC_PORT_DRP) {
@@ -788,10 +796,30 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
        else
                orientation = TYPEC_ORIENTATION_REVERSE;
 
-       if (data == TYPEC_HOST)
-               usb_role = USB_ROLE_HOST;
-       else
-               usb_role = USB_ROLE_DEVICE;
+       if (port->typec_caps.data == TYPEC_PORT_DRD) {
+               if (data == TYPEC_HOST)
+                       usb_role = USB_ROLE_HOST;
+               else
+                       usb_role = USB_ROLE_DEVICE;
+       } else if (port->typec_caps.data == TYPEC_PORT_DFP) {
+               if (data == TYPEC_HOST) {
+                       if (role == TYPEC_SOURCE)
+                               usb_role = USB_ROLE_HOST;
+                       else
+                               usb_role = USB_ROLE_NONE;
+               } else {
+                       return -ENOTSUPP;
+               }
+       } else {
+               if (data == TYPEC_DEVICE) {
+                       if (role == TYPEC_SINK)
+                               usb_role = USB_ROLE_DEVICE;
+                       else
+                               usb_role = USB_ROLE_NONE;
+               } else {
+                       return -ENOTSUPP;
+               }
+       }
 
        ret = tcpm_mux_set(port, TYPEC_STATE_USB, usb_role, orientation);
        if (ret < 0)
@@ -1817,7 +1845,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port,
                tcpm_set_state(port, SOFT_RESET, 0);
                break;
        case PD_CTRL_DR_SWAP:
-               if (port->port_type != TYPEC_PORT_DRP) {
+               if (port->typec_caps.data != TYPEC_PORT_DRD) {
                        tcpm_queue_message(port, PD_MSG_CTRL_REJECT);
                        break;
                }
@@ -2618,7 +2646,8 @@ static int tcpm_src_attach(struct tcpm_port *port)
        if (ret < 0)
                return ret;
 
-       ret = tcpm_set_roles(port, true, TYPEC_SOURCE, TYPEC_HOST);
+       ret = tcpm_set_roles(port, true, TYPEC_SOURCE,
+                            tcpm_data_role_for_source(port));
        if (ret < 0)
                return ret;
 
@@ -2740,7 +2769,8 @@ static int tcpm_snk_attach(struct tcpm_port *port)
        if (ret < 0)
                return ret;
 
-       ret = tcpm_set_roles(port, true, TYPEC_SINK, TYPEC_DEVICE);
+       ret = tcpm_set_roles(port, true, TYPEC_SINK,
+                            tcpm_data_role_for_sink(port));
        if (ret < 0)
                return ret;
 
@@ -2766,7 +2796,8 @@ static int tcpm_acc_attach(struct tcpm_port *port)
        if (port->attached)
                return 0;
 
-       ret = tcpm_set_roles(port, true, TYPEC_SOURCE, TYPEC_HOST);
+       ret = tcpm_set_roles(port, true, TYPEC_SOURCE,
+                            tcpm_data_role_for_source(port));
        if (ret < 0)
                return ret;
 
@@ -3293,7 +3324,7 @@ static void run_state_machine(struct tcpm_port *port)
                tcpm_set_vconn(port, true);
                tcpm_set_vbus(port, false);
                tcpm_set_roles(port, port->self_powered, TYPEC_SOURCE,
-                              TYPEC_HOST);
+                              tcpm_data_role_for_source(port));
                tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
                break;
        case SRC_HARD_RESET_VBUS_ON:
@@ -3308,7 +3339,7 @@ static void run_state_machine(struct tcpm_port *port)
                if (port->pd_capable)
                        tcpm_set_charge(port, false);
                tcpm_set_roles(port, port->self_powered, TYPEC_SINK,
-                              TYPEC_DEVICE);
+                              tcpm_data_role_for_sink(port));
                /*
                 * VBUS may or may not toggle, depending on the adapter.
                 * If it doesn't toggle, transition to SNK_HARD_RESET_SINK_ON
@@ -3649,8 +3680,12 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
        case SRC_SEND_CAPABILITIES:
        case SRC_READY:
                if (tcpm_port_is_disconnected(port) ||
-                   !tcpm_port_is_source(port))
-                       tcpm_set_state(port, SRC_UNATTACHED, 0);
+                   !tcpm_port_is_source(port)) {
+                       if (port->port_type == TYPEC_PORT_SRC)
+                               tcpm_set_state(port, SRC_UNATTACHED, 0);
+                       else
+                               tcpm_set_state(port, SNK_UNATTACHED, 0);
+               }
                break;
        case SNK_UNATTACHED:
                if (tcpm_port_is_sink(port))
@@ -3969,7 +4004,7 @@ static int tcpm_dr_set(struct typec_port *p, enum typec_data_role data)
        mutex_lock(&port->swap_lock);
        mutex_lock(&port->lock);
 
-       if (port->port_type != TYPEC_PORT_DRP) {
+       if (port->typec_caps.data != TYPEC_PORT_DRD) {
                ret = -EINVAL;
                goto port_unlock;
        }
@@ -4711,6 +4746,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
        port->typec_caps.pd_revision = 0x0300;  /* USB-PD spec release 3.0 */
        port->typec_caps.driver_data = port;
        port->typec_caps.ops = &tcpm_ops;
+       port->typec_caps.orientation_aware = 1;
 
        port->partner_desc.identity = &port->partner_ident;
        port->port_type = port->typec_caps.type;
index 0f1273a..048381c 100644 (file)
@@ -271,6 +271,9 @@ void ucsi_displayport_remove_partner(struct typec_altmode *alt)
                return;
 
        dp = typec_altmode_get_drvdata(alt);
+       if (!dp)
+               return;
+
        dp->data.conf = 0;
        dp->data.status = 0;
        dp->initialized = false;
@@ -285,6 +288,8 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
        struct typec_altmode *alt;
        struct ucsi_dp *dp;
 
+       mutex_lock(&con->lock);
+
        /* We can't rely on the firmware with the capabilities. */
        desc->vdo |= DP_CAP_DP_SIGNALING | DP_CAP_RECEPTACLE;
 
@@ -293,12 +298,15 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
        desc->vdo |= all_assignments << 16;
 
        alt = typec_port_register_altmode(con->port, desc);
-       if (IS_ERR(alt))
+       if (IS_ERR(alt)) {
+               mutex_unlock(&con->lock);
                return alt;
+       }
 
        dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
        if (!dp) {
                typec_unregister_altmode(alt);
+               mutex_unlock(&con->lock);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -311,5 +319,7 @@ struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con,
        alt->ops = &ucsi_displayport_ops;
        typec_altmode_set_drvdata(alt, dp);
 
+       mutex_unlock(&con->lock);
+
        return alt;
 }
index d5a6aac..ddf2ad3 100644 (file)
@@ -270,9 +270,16 @@ static int ucsi_register_altmode(struct ucsi_connector *con,
 
                switch (desc->svid) {
                case USB_TYPEC_DP_SID:
-               case USB_TYPEC_NVIDIA_VLINK_SID:
                        alt = ucsi_register_displayport(con, override, i, desc);
                        break;
+               case USB_TYPEC_NVIDIA_VLINK_SID:
+                       if (desc->vdo == USB_TYPEC_NVIDIA_VLINK_DBG_VDO)
+                               alt = typec_port_register_altmode(con->port,
+                                                                 desc);
+                       else
+                               alt = ucsi_register_displayport(con, override,
+                                                               i, desc);
+                       break;
                default:
                        alt = typec_port_register_altmode(con->port, desc);
                        break;
@@ -400,7 +407,7 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient)
        struct typec_altmode_desc desc;
        struct ucsi_altmode alt[2];
        u64 command;
-       int num = 1;
+       int num;
        int ret;
        int len;
        int j;
@@ -475,7 +482,8 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient)
        while (adev[i]) {
                if (recipient == UCSI_RECIPIENT_SOP &&
                    (adev[i]->svid == USB_TYPEC_DP_SID ||
-                       adev[i]->svid == USB_TYPEC_NVIDIA_VLINK_SID)) {
+                       (adev[i]->svid == USB_TYPEC_NVIDIA_VLINK_SID &&
+                       adev[i]->vdo != USB_TYPEC_NVIDIA_VLINK_DBG_VDO))) {
                        pdev = typec_altmode_get_partner(adev[i]);
                        ucsi_displayport_remove_partner((void *)pdev);
                }
index e434b9c..8e83110 100644 (file)
@@ -119,12 +119,14 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
 #define UCSI_SET_PDR_ACCEPT_ROLE_SWAPS         BIT(25)
 
 /* GET_ALTERNATE_MODES command bits */
+#define UCSI_ALTMODE_RECIPIENT(_r_)            (((_r_) >> 16) & 0x7)
 #define UCSI_GET_ALTMODE_RECIPIENT(_r_)                ((u64)(_r_) << 16)
 #define   UCSI_RECIPIENT_CON                   0
 #define   UCSI_RECIPIENT_SOP                   1
 #define   UCSI_RECIPIENT_SOP_P                 2
 #define   UCSI_RECIPIENT_SOP_PP                        3
 #define UCSI_GET_ALTMODE_CONNECTOR_NUMBER(_r_) ((u64)(_r_) << 24)
+#define UCSI_ALTMODE_OFFSET(_r_)               (((_r_) >> 32) & 0xff)
 #define UCSI_GET_ALTMODE_OFFSET(_r_)           ((u64)(_r_) << 32)
 #define UCSI_GET_ALTMODE_NUM_ALTMODES(_r_)     ((u64)(_r_) << 40)
 
@@ -340,4 +342,11 @@ static inline void
 ucsi_displayport_remove_partner(struct typec_altmode *adev) { }
 #endif /* CONFIG_TYPEC_DP_ALTMODE */
 
+/*
+ * NVIDIA VirtualLink (svid 0x955) has two altmode. VirtualLink
+ * DP mode with vdo=0x1 and NVIDIA test mode with vdo=0x3
+ */
+#define USB_TYPEC_NVIDIA_VLINK_DP_VDO  0x1
+#define USB_TYPEC_NVIDIA_VLINK_DBG_VDO 0x3
+
 #endif /* __DRIVER_USB_TYPEC_UCSI_H */
index a5b8530..bff96d6 100644 (file)
@@ -125,6 +125,10 @@ struct version_format {
 #define CCG_FW_BUILD_NVIDIA    (('n' << 8) | 'v')
 #define CCG_OLD_FW_VERSION     (CCG_VERSION(0x31) | CCG_VERSION_PATCH(10))
 
+/* Altmode offset for NVIDIA Function Test Board (FTB) */
+#define NVIDIA_FTB_DP_OFFSET   (2)
+#define NVIDIA_FTB_DBG_OFFSET  (3)
+
 struct version_info {
        struct version_format base;
        struct version_format app;
@@ -477,24 +481,65 @@ static void ucsi_ccg_update_set_new_cam_cmd(struct ucsi_ccg *uc,
        *cmd |= UCSI_SET_NEW_CAM_SET_AM(cam);
 }
 
+/*
+ * Change the order of vdo values of NVIDIA test device FTB
+ * (Function Test Board) which reports altmode list with vdo=0x3
+ * first and then vdo=0x. Current logic to assign mode value is
+ * based on order in altmode list and it causes a mismatch of CON
+ * and SOP altmodes since NVIDIA GPU connector has order of vdo=0x1
+ * first and then vdo=0x3
+ */
+static void ucsi_ccg_nvidia_altmode(struct ucsi_ccg *uc,
+                                   struct ucsi_altmode *alt)
+{
+       switch (UCSI_ALTMODE_OFFSET(uc->last_cmd_sent)) {
+       case NVIDIA_FTB_DP_OFFSET:
+               if (alt[0].mid == USB_TYPEC_NVIDIA_VLINK_DBG_VDO)
+                       alt[0].mid = USB_TYPEC_NVIDIA_VLINK_DP_VDO |
+                               DP_CAP_DP_SIGNALING | DP_CAP_USB |
+                               DP_CONF_SET_PIN_ASSIGN(BIT(DP_PIN_ASSIGN_E));
+               break;
+       case NVIDIA_FTB_DBG_OFFSET:
+               if (alt[0].mid == USB_TYPEC_NVIDIA_VLINK_DP_VDO)
+                       alt[0].mid = USB_TYPEC_NVIDIA_VLINK_DBG_VDO;
+               break;
+       default:
+               break;
+       }
+}
+
 static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset,
                         void *val, size_t val_len)
 {
        struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi);
-       int ret;
        u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset);
+       struct ucsi_altmode *alt;
+       int ret;
 
        ret = ccg_read(uc, reg, val, val_len);
        if (ret)
                return ret;
 
-       if (offset == UCSI_MESSAGE_IN) {
-               if (UCSI_COMMAND(uc->last_cmd_sent) == UCSI_GET_CURRENT_CAM &&
-                   uc->has_multiple_dp) {
+       if (offset != UCSI_MESSAGE_IN)
+               return ret;
+
+       switch (UCSI_COMMAND(uc->last_cmd_sent)) {
+       case UCSI_GET_CURRENT_CAM:
+               if (uc->has_multiple_dp)
                        ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)val);
+               break;
+       case UCSI_GET_ALTERNATE_MODES:
+               if (UCSI_ALTMODE_RECIPIENT(uc->last_cmd_sent) ==
+                   UCSI_RECIPIENT_SOP) {
+                       alt = val;
+                       if (alt[0].svid == USB_TYPEC_NVIDIA_VLINK_SID)
+                               ucsi_ccg_nvidia_altmode(uc, alt);
                }
-               uc->last_cmd_sent = 0;
+               break;
+       default:
+               break;
        }
+       uc->last_cmd_sent = 0;
 
        return ret;
 }
@@ -1219,6 +1264,7 @@ static int ccg_restart(struct ucsi_ccg *uc)
                return status;
        }
 
+       pm_runtime_enable(uc->dev);
        return 0;
 }
 
@@ -1234,6 +1280,7 @@ static void ccg_update_firmware(struct work_struct *work)
 
        if (flash_mode != FLASH_NOT_NEEDED) {
                ucsi_unregister(uc->ucsi);
+               pm_runtime_disable(uc->dev);
                free_irq(uc->irq, uc);
 
                ccg_fw_update(uc, flash_mode);
index e158159..18e205e 100644 (file)
@@ -1414,10 +1414,6 @@ static int vhost_net_release(struct inode *inode, struct file *f)
 
 static struct socket *get_raw_socket(int fd)
 {
-       struct {
-               struct sockaddr_ll sa;
-               char  buf[MAX_ADDR_LEN];
-       } uaddr;
        int r;
        struct socket *sock = sockfd_lookup(fd, &r);
 
@@ -1430,11 +1426,7 @@ static struct socket *get_raw_socket(int fd)
                goto err;
        }
 
-       r = sock->ops->getname(sock, (struct sockaddr *)&uaddr.sa, 0);
-       if (r < 0)
-               goto err;
-
-       if (uaddr.sa.sll_family != AF_PACKET) {
+       if (sock->sk->sk_family != AF_PACKET) {
                r = -EPFNOSUPPORT;
                goto err;
        }
index 403707a..0093bbd 100644 (file)
@@ -456,6 +456,13 @@ config BACKLIGHT_RAVE_SP
        help
          Support for backlight control on RAVE SP device.
 
+config BACKLIGHT_LED
+       tristate "Generic LED based Backlight Driver"
+       depends on LEDS_CLASS && OF
+       help
+         If you have a LCD backlight adjustable by LED class driver, say Y
+         to enable this driver.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endmenu
index 6f87770..0c1a152 100644 (file)
@@ -57,3 +57,4 @@ obj-$(CONFIG_BACKLIGHT_TPS65217)      += tps65217_bl.o
 obj-$(CONFIG_BACKLIGHT_WM831X)         += wm831x_bl.o
 obj-$(CONFIG_BACKLIGHT_ARCXCNN)        += arcxcnn_bl.o
 obj-$(CONFIG_BACKLIGHT_RAVE_SP)                += rave-sp-backlight.o
+obj-$(CONFIG_BACKLIGHT_LED)            += led_bl.o
diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c
new file mode 100644 (file)
index 0000000..3f66549
--- /dev/null
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2015-2019 Texas Instruments Incorporated -  http://www.ti.com/
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ *
+ * Based on pwm_bl.c
+ */
+
+#include <linux/backlight.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+struct led_bl_data {
+       struct device           *dev;
+       struct backlight_device *bl_dev;
+       struct led_classdev     **leds;
+       bool                    enabled;
+       int                     nb_leds;
+       unsigned int            *levels;
+       unsigned int            default_brightness;
+       unsigned int            max_brightness;
+};
+
+static void led_bl_set_brightness(struct led_bl_data *priv, int level)
+{
+       int i;
+       int bkl_brightness;
+
+       if (priv->levels)
+               bkl_brightness = priv->levels[level];
+       else
+               bkl_brightness = level;
+
+       for (i = 0; i < priv->nb_leds; i++)
+               led_set_brightness(priv->leds[i], bkl_brightness);
+
+       priv->enabled = true;
+}
+
+static void led_bl_power_off(struct led_bl_data *priv)
+{
+       int i;
+
+       if (!priv->enabled)
+               return;
+
+       for (i = 0; i < priv->nb_leds; i++)
+               led_set_brightness(priv->leds[i], LED_OFF);
+
+       priv->enabled = false;
+}
+
+static int led_bl_update_status(struct backlight_device *bl)
+{
+       struct led_bl_data *priv = bl_get_data(bl);
+       int brightness = bl->props.brightness;
+
+       if (bl->props.power != FB_BLANK_UNBLANK ||
+           bl->props.fb_blank != FB_BLANK_UNBLANK ||
+           bl->props.state & BL_CORE_FBBLANK)
+               brightness = 0;
+
+       if (brightness > 0)
+               led_bl_set_brightness(priv, brightness);
+       else
+               led_bl_power_off(priv);
+
+       return 0;
+}
+
+static const struct backlight_ops led_bl_ops = {
+       .update_status  = led_bl_update_status,
+};
+
+static int led_bl_get_leds(struct device *dev,
+                          struct led_bl_data *priv)
+{
+       int i, nb_leds, ret;
+       struct device_node *node = dev->of_node;
+       struct led_classdev **leds;
+       unsigned int max_brightness;
+       unsigned int default_brightness;
+
+       ret = of_count_phandle_with_args(node, "leds", NULL);
+       if (ret < 0) {
+               dev_err(dev, "Unable to get led count\n");
+               return -EINVAL;
+       }
+
+       nb_leds = ret;
+       if (nb_leds < 1) {
+               dev_err(dev, "At least one LED must be specified!\n");
+               return -EINVAL;
+       }
+
+       leds = devm_kzalloc(dev, sizeof(struct led_classdev *) * nb_leds,
+                           GFP_KERNEL);
+       if (!leds)
+               return -ENOMEM;
+
+       for (i = 0; i < nb_leds; i++) {
+               leds[i] = devm_of_led_get(dev, i);
+               if (IS_ERR(leds[i]))
+                       return PTR_ERR(leds[i]);
+       }
+
+       /* check that the LEDs all have the same brightness range */
+       max_brightness = leds[0]->max_brightness;
+       for (i = 1; i < nb_leds; i++) {
+               if (max_brightness != leds[i]->max_brightness) {
+                       dev_err(dev, "LEDs must have identical ranges\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* get the default brightness from the first LED from the list */
+       default_brightness = leds[0]->brightness;
+
+       priv->nb_leds = nb_leds;
+       priv->leds = leds;
+       priv->max_brightness = max_brightness;
+       priv->default_brightness = default_brightness;
+
+       return 0;
+}
+
+static int led_bl_parse_levels(struct device *dev,
+                          struct led_bl_data *priv)
+{
+       struct device_node *node = dev->of_node;
+       int num_levels;
+       u32 value;
+       int ret;
+
+       if (!node)
+               return -ENODEV;
+
+       num_levels = of_property_count_u32_elems(node, "brightness-levels");
+       if (num_levels > 1) {
+               int i;
+               unsigned int db;
+               u32 *levels = NULL;
+
+               levels = devm_kzalloc(dev, sizeof(u32) * num_levels,
+                                     GFP_KERNEL);
+               if (!levels)
+                       return -ENOMEM;
+
+               ret = of_property_read_u32_array(node, "brightness-levels",
+                                               levels,
+                                               num_levels);
+               if (ret < 0)
+                       return ret;
+
+               /*
+                * Try to map actual LED brightness to backlight brightness
+                * level
+                */
+               db = priv->default_brightness;
+               for (i = 0 ; i < num_levels; i++) {
+                       if ((i && db > levels[i-1]) && db <= levels[i])
+                               break;
+               }
+               priv->default_brightness = i;
+               priv->max_brightness = num_levels - 1;
+               priv->levels = levels;
+       } else if (num_levels >= 0)
+               dev_warn(dev, "Not enough levels defined\n");
+
+       ret = of_property_read_u32(node, "default-brightness-level", &value);
+       if (!ret && value <= priv->max_brightness)
+               priv->default_brightness = value;
+       else if (!ret  && value > priv->max_brightness)
+               dev_warn(dev, "Invalid default brightness. Ignoring it\n");
+
+       return 0;
+}
+
+static int led_bl_probe(struct platform_device *pdev)
+{
+       struct backlight_properties props;
+       struct led_bl_data *priv;
+       int ret, i;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, priv);
+
+       priv->dev = &pdev->dev;
+
+       ret = led_bl_get_leds(&pdev->dev, priv);
+       if (ret)
+               return ret;
+
+       ret = led_bl_parse_levels(&pdev->dev, priv);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to parse DT data\n");
+               return ret;
+       }
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_RAW;
+       props.max_brightness = priv->max_brightness;
+       props.brightness = priv->default_brightness;
+       props.power = (priv->default_brightness > 0) ? FB_BLANK_POWERDOWN :
+                     FB_BLANK_UNBLANK;
+       priv->bl_dev = backlight_device_register(dev_name(&pdev->dev),
+                       &pdev->dev, priv, &led_bl_ops, &props);
+       if (IS_ERR(priv->bl_dev)) {
+               dev_err(&pdev->dev, "Failed to register backlight\n");
+               return PTR_ERR(priv->bl_dev);
+       }
+
+       for (i = 0; i < priv->nb_leds; i++)
+               led_sysfs_disable(priv->leds[i]);
+
+       backlight_update_status(priv->bl_dev);
+
+       return 0;
+}
+
+static int led_bl_remove(struct platform_device *pdev)
+{
+       struct led_bl_data *priv = platform_get_drvdata(pdev);
+       struct backlight_device *bl = priv->bl_dev;
+       int i;
+
+       backlight_device_unregister(bl);
+
+       led_bl_power_off(priv);
+       for (i = 0; i < priv->nb_leds; i++)
+               led_sysfs_enable(priv->leds[i]);
+
+       return 0;
+}
+
+static const struct of_device_id led_bl_of_match[] = {
+       { .compatible = "led-backlight" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, led_bl_of_match);
+
+static struct platform_driver led_bl_driver = {
+       .driver         = {
+               .name           = "led-backlight",
+               .of_match_table = of_match_ptr(led_bl_of_match),
+       },
+       .probe          = led_bl_probe,
+       .remove         = led_bl_remove,
+};
+
+module_platform_driver(led_bl_driver);
+
+MODULE_DESCRIPTION("LED based Backlight Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:led-backlight");
index de7b838..998b0de 100644 (file)
@@ -1316,6 +1316,9 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font)
 static int vgacon_resize(struct vc_data *c, unsigned int width,
                         unsigned int height, unsigned int user)
 {
+       if ((width << 1) * height > vga_vram_size)
+               return -EINVAL;
+
        if (width % 2 || width > screen_info.orig_video_cols ||
            height > (screen_info.orig_video_lines * vga_default_font_height)/
            c->vc_font.height)
index 45a6d89..cf5f1eb 100644 (file)
@@ -12,6 +12,8 @@
  *  for more details.
  */
 
+#include <linux/build_bug.h>
+
 
     /*
      *  Basic transpose step
@@ -27,8 +29,6 @@ static inline void _transp(u32 d[], unsigned int i1, unsigned int i2,
 }
 
 
-extern void c2p_unsupported(void);
-
 static __always_inline u32 get_mask(unsigned int n)
 {
        switch (n) {
@@ -48,7 +48,7 @@ static __always_inline u32 get_mask(unsigned int n)
                return 0x0000ffff;
        }
 
-       c2p_unsupported();
+       BUILD_BUG();
        return 0;
 }
 
@@ -91,7 +91,7 @@ static __always_inline void transp8(u32 d[], unsigned int n, unsigned int m)
                return;
        }
 
-       c2p_unsupported();
+       BUILD_BUG();
 }
 
 
@@ -118,7 +118,7 @@ static __always_inline void transp4(u32 d[], unsigned int n, unsigned int m)
                return;
        }
 
-       c2p_unsupported();
+       BUILD_BUG();
 }
 
 
@@ -138,7 +138,7 @@ static __always_inline void transp4x(u32 d[], unsigned int n, unsigned int m)
                return;
        }
 
-       c2p_unsupported();
+       BUILD_BUG();
 }
 
 
index 845b79d..05837a3 100644 (file)
@@ -108,7 +108,6 @@ static int g364fb_pan_display(struct fb_var_screeninfo *var,
 static int g364fb_setcolreg(u_int regno, u_int red, u_int green,
                            u_int blue, u_int transp,
                            struct fb_info *info);
-static int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor);
 static int g364fb_blank(int blank, struct fb_info *info);
 
 static const struct fb_ops g364fb_ops = {
@@ -119,28 +118,8 @@ static const struct fb_ops g364fb_ops = {
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
-       .fb_cursor      = g364fb_cursor,
 };
 
-int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
-{
-       
-       switch (cursor->enable) {
-       case CM_ERASE:
-               *(unsigned int *) CTLA_REG |= CURS_TOGGLE;
-               break;
-
-       case CM_MOVE:
-       case CM_DRAW:
-               *(unsigned int *) CTLA_REG &= ~CURS_TOGGLE;
-               *(unsigned int *) CURS_POS_REG =
-                   ((x * fontwidth(p)) << 12) | ((y * fontheight(p)) -
-                                                 info->var.yoffset);
-               break;
-       }
-       return 0;
-}
-
 /*
  *  Pan or Wrap the Display
  *
@@ -194,11 +173,9 @@ static int g364fb_setcolreg(u_int regno, u_int red, u_int green,
  */
 int __init g364fb_init(void)
 {
-       volatile unsigned int *pal_ptr =
-           (volatile unsigned int *) CLR_PAL_REG;
        volatile unsigned int *curs_pal_ptr =
            (volatile unsigned int *) CURS_PAL_REG;
-       int mem, i, j;
+       int mem, i;
 
        if (fb_get_options("g364fb", NULL))
                return -ENODEV;
@@ -230,8 +207,8 @@ int __init g364fb_init(void)
         */
        *(unsigned short *) (CURS_PAT_REG + 14 * 64) = 0xffff;
        *(unsigned short *) (CURS_PAT_REG + 15 * 64) = 0xffff;
-       fb_var.xres_virtual = fbvar.xres;
-       fb_fix.line_length = (xres / 8) * fb_var.bits_per_pixel;
+       fb_var.xres_virtual = fb_var.xres;
+       fb_fix.line_length = fb_var.xres_virtual * fb_var.bits_per_pixel / 8;
        fb_fix.smem_start = 0x40000000; /* physical address */
        /* get size of video memory; this is special for the JAZZ hardware */
        mem = (r4030_read_reg32(JAZZ_R4030_CONFIG) >> 8) & 3;
index 7bfe365..341458f 100644 (file)
@@ -959,8 +959,8 @@ out_iput:
        iput(vb->vb_dev_info.inode);
 out_kern_unmount:
        kern_unmount(balloon_mnt);
-#endif
 out_del_vqs:
+#endif
        vdev->config->del_vqs(vdev);
 out_free_vb:
        kfree(vb);
index 867c7eb..58b96ba 100644 (file)
@@ -2203,10 +2203,10 @@ void vring_del_virtqueue(struct virtqueue *_vq)
                                         vq->split.queue_size_in_bytes,
                                         vq->split.vring.desc,
                                         vq->split.queue_dma_addr);
-
-                       kfree(vq->split.desc_state);
                }
        }
+       if (!vq->packed_ring)
+               kfree(vq->split.desc_state);
        list_del(&_vq->list);
        kfree(vq);
 }
index 0f7373b..69e92e6 100644 (file)
@@ -1,10 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 /* iTCO Vendor Specific Support hooks */
 #ifdef CONFIG_ITCO_VENDOR_SUPPORT
+extern int iTCO_vendorsupport;
 extern void iTCO_vendor_pre_start(struct resource *, unsigned int);
 extern void iTCO_vendor_pre_stop(struct resource *);
 extern int iTCO_vendor_check_noreboot_on(void);
 #else
+#define iTCO_vendorsupport                             0
 #define iTCO_vendor_pre_start(acpibase, heartbeat)     {}
 #define iTCO_vendor_pre_stop(acpibase)                 {}
 #define iTCO_vendor_check_noreboot_on()                        1
index 4f1b96f..cf0eaa0 100644 (file)
 /* Broken BIOS */
 #define BROKEN_BIOS            911
 
-static int vendorsupport;
-module_param(vendorsupport, int, 0);
+int iTCO_vendorsupport;
+EXPORT_SYMBOL(iTCO_vendorsupport);
+
+module_param_named(vendorsupport, iTCO_vendorsupport, int, 0);
 MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
                        "0 (none), 1=SuperMicro Pent3, 911=Broken SMI BIOS");
 
@@ -152,7 +154,7 @@ static void broken_bios_stop(struct resource *smires)
 void iTCO_vendor_pre_start(struct resource *smires,
                           unsigned int heartbeat)
 {
-       switch (vendorsupport) {
+       switch (iTCO_vendorsupport) {
        case SUPERMICRO_OLD_BOARD:
                supermicro_old_pre_start(smires);
                break;
@@ -165,7 +167,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_start);
 
 void iTCO_vendor_pre_stop(struct resource *smires)
 {
-       switch (vendorsupport) {
+       switch (iTCO_vendorsupport) {
        case SUPERMICRO_OLD_BOARD:
                supermicro_old_pre_stop(smires);
                break;
@@ -178,7 +180,7 @@ EXPORT_SYMBOL(iTCO_vendor_pre_stop);
 
 int iTCO_vendor_check_noreboot_on(void)
 {
-       switch (vendorsupport) {
+       switch (iTCO_vendorsupport) {
        case SUPERMICRO_OLD_BOARD:
                return 0;
        default:
@@ -189,13 +191,13 @@ EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
 
 static int __init iTCO_vendor_init_module(void)
 {
-       if (vendorsupport == SUPERMICRO_NEW_BOARD) {
+       if (iTCO_vendorsupport == SUPERMICRO_NEW_BOARD) {
                pr_warn("Option vendorsupport=%d is no longer supported, "
                        "please use the w83627hf_wdt driver instead\n",
                        SUPERMICRO_NEW_BOARD);
                return -EINVAL;
        }
-       pr_info("vendor-support=%d\n", vendorsupport);
+       pr_info("vendor-support=%d\n", iTCO_vendorsupport);
        return 0;
 }
 
index 156360e..e707c47 100644 (file)
@@ -459,13 +459,25 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
        if (!p->tco_res)
                return -ENODEV;
 
-       p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI);
-       if (!p->smi_res)
-               return -ENODEV;
-
        p->iTCO_version = pdata->version;
        p->pci_dev = to_pci_dev(dev->parent);
 
+       p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI);
+       if (p->smi_res) {
+               /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
+               if (!devm_request_region(dev, p->smi_res->start,
+                                        resource_size(p->smi_res),
+                                        pdev->name)) {
+                       pr_err("I/O address 0x%04llx already in use, device disabled\n",
+                              (u64)SMI_EN(p));
+                       return -EBUSY;
+               }
+       } else if (iTCO_vendorsupport ||
+                  turn_SMI_watchdog_clear_off >= p->iTCO_version) {
+               pr_err("SMI I/O resource is missing\n");
+               return -ENODEV;
+       }
+
        iTCO_wdt_no_reboot_bit_setup(p, pdata);
 
        /*
@@ -492,14 +504,6 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
        /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
        p->update_no_reboot_bit(p->no_reboot_priv, true);
 
-       /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
-       if (!devm_request_region(dev, p->smi_res->start,
-                                resource_size(p->smi_res),
-                                pdev->name)) {
-               pr_err("I/O address 0x%04llx already in use, device disabled\n",
-                      (u64)SMI_EN(p));
-               return -EBUSY;
-       }
        if (turn_SMI_watchdog_clear_off >= p->iTCO_version) {
                /*
                 * Bit 13: TCO_EN -> 0
index b069349..3065dd6 100644 (file)
@@ -54,6 +54,13 @@ module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+#define WDAT_DEFAULT_TIMEOUT   30
+
+static int timeout = WDAT_DEFAULT_TIMEOUT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
+                __MODULE_STRING(WDAT_DEFAULT_TIMEOUT) ")");
+
 static int wdat_wdt_read(struct wdat_wdt *wdat,
         const struct wdat_instruction *instr, u32 *value)
 {
@@ -389,7 +396,7 @@ static int wdat_wdt_probe(struct platform_device *pdev)
 
                memset(&r, 0, sizeof(r));
                r.start = gas->address;
-               r.end = r.start + gas->access_width - 1;
+               r.end = r.start + ACPI_ACCESS_BYTE_WIDTH(gas->access_width) - 1;
                if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
                        r.flags = IORESOURCE_MEM;
                } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
@@ -438,6 +445,22 @@ static int wdat_wdt_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wdat);
 
+       /*
+        * Set initial timeout so that userspace has time to configure the
+        * watchdog properly after it has opened the device. In some cases
+        * the BIOS default is too short and causes immediate reboot.
+        */
+       if (timeout * 1000 < wdat->wdd.min_hw_heartbeat_ms ||
+           timeout * 1000 > wdat->wdd.max_hw_heartbeat_ms) {
+               dev_warn(dev, "Invalid timeout %d given, using %d\n",
+                        timeout, WDAT_DEFAULT_TIMEOUT);
+               timeout = WDAT_DEFAULT_TIMEOUT;
+       }
+
+       ret = wdat_wdt_set_timeout(&wdat->wdd, timeout);
+       if (ret)
+               return ret;
+
        watchdog_set_nowayout(&wdat->wdd, nowayout);
        return devm_watchdog_register_device(dev, &wdat->wdd);
 }
index f192b6f..ec975de 100644 (file)
@@ -94,7 +94,7 @@ static int setup_cpu_watcher(struct notifier_block *notifier,
 
        for_each_possible_cpu(cpu) {
                if (vcpu_online(cpu) == 0) {
-                       (void)cpu_down(cpu);
+                       device_offline(get_cpu_device(cpu));
                        set_cpu_present(cpu, false);
                }
        }
index ce1077e..7c95516 100644 (file)
@@ -52,7 +52,7 @@ struct xen_pcibk_dev_data {
        unsigned int ack_intr:1; /* .. and ACK-ing */
        unsigned long handled;
        unsigned int irq; /* Saved in case device transitions to MSI/MSI-X */
-       char irq_name[0]; /* xen-pcibk[000:04:00.0] */
+       char irq_name[]; /* xen-pcibk[000:04:00.0] */
 };
 
 /* Used by XenBus and xen_pcibk_ops.c */
index d239fc3..eb5151f 100644 (file)
@@ -313,6 +313,8 @@ static int process_msg(void)
                        req->msg.type = state.msg.type;
                        req->msg.len = state.msg.len;
                        req->body = state.body;
+                       /* write body, then update state */
+                       virt_wmb();
                        req->state = xb_req_state_got_reply;
                        req->cb(req);
                } else
@@ -395,6 +397,8 @@ static int process_writes(void)
        if (state.req->state == xb_req_state_aborted)
                kfree(state.req);
        else {
+               /* write err, then update state */
+               virt_wmb();
                state.req->state = xb_req_state_got_reply;
                wake_up(&state.req->wq);
        }
index 66975da..8c4d05b 100644 (file)
@@ -239,9 +239,9 @@ int xenbus_dev_probe(struct device *_dev)
                goto fail;
        }
 
-       spin_lock(&dev->reclaim_lock);
+       down(&dev->reclaim_sem);
        err = drv->probe(dev, id);
-       spin_unlock(&dev->reclaim_lock);
+       up(&dev->reclaim_sem);
        if (err)
                goto fail_put;
 
@@ -271,9 +271,9 @@ int xenbus_dev_remove(struct device *_dev)
        free_otherend_watch(dev);
 
        if (drv->remove) {
-               spin_lock(&dev->reclaim_lock);
+               down(&dev->reclaim_sem);
                drv->remove(dev);
-               spin_unlock(&dev->reclaim_lock);
+               up(&dev->reclaim_sem);
        }
 
        module_put(drv->driver.owner);
@@ -473,7 +473,7 @@ int xenbus_probe_node(struct xen_bus_type *bus,
                goto fail;
 
        dev_set_name(&xendev->dev, "%s", devname);
-       spin_lock_init(&xendev->reclaim_lock);
+       sema_init(&xendev->reclaim_sem, 1);
 
        /* Register with generic device framework. */
        err = device_register(&xendev->dev);
index 791f6fe..9b2fbe6 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/mm.h>
 #include <linux/notifier.h>
 #include <linux/export.h>
+#include <linux/semaphore.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -257,10 +258,10 @@ static int backend_reclaim_memory(struct device *dev, void *data)
        drv = to_xenbus_driver(dev->driver);
        if (drv && drv->reclaim_memory) {
                xdev = to_xenbus_device(dev);
-               if (!spin_trylock(&xdev->reclaim_lock))
+               if (down_trylock(&xdev->reclaim_sem))
                        return 0;
                drv->reclaim_memory(xdev);
-               spin_unlock(&xdev->reclaim_lock);
+               up(&xdev->reclaim_sem);
        }
        return 0;
 }
index ddc18da..3a06eb6 100644 (file)
@@ -191,8 +191,11 @@ static bool xenbus_ok(void)
 
 static bool test_reply(struct xb_req_data *req)
 {
-       if (req->state == xb_req_state_got_reply || !xenbus_ok())
+       if (req->state == xb_req_state_got_reply || !xenbus_ok()) {
+               /* read req->state before all other fields */
+               virt_rmb();
                return true;
+       }
 
        /* Make sure to reread req->state each time. */
        barrier();
@@ -202,7 +205,7 @@ static bool test_reply(struct xb_req_data *req)
 
 static void *read_reply(struct xb_req_data *req)
 {
-       while (req->state != xb_req_state_got_reply) {
+       do {
                wait_event(req->wq, test_reply(req));
 
                if (!xenbus_ok())
@@ -216,7 +219,7 @@ static void *read_reply(struct xb_req_data *req)
                if (req->err)
                        return ERR_PTR(req->err);
 
-       }
+       } while (req->state != xb_req_state_got_reply);
 
        return req->body;
 }
index fa23b73..0dd7cbc 100644 (file)
@@ -28,7 +28,7 @@
      *  zorro_device_id structure or %NULL if there is no match.
      */
 
-const struct zorro_device_id *
+static const struct zorro_device_id *
 zorro_match_device(const struct zorro_device_id *ids,
                   const struct zorro_dev *z)
 {
@@ -39,7 +39,6 @@ zorro_match_device(const struct zorro_device_id *ids,
        }
        return NULL;
 }
-EXPORT_SYMBOL(zorro_match_device);
 
 
 static int zorro_device_probe(struct device *dev)
@@ -120,9 +119,9 @@ EXPORT_SYMBOL(zorro_unregister_driver);
      *  @ids: array of Zorro device id structures to search in
      *  @dev: the Zorro device structure to match against
      *
-     *  Used by a driver to check whether a Zorro device present in the
-     *  system is in its list of supported devices.Returns the matching
-     *  zorro_device_id structure or %NULL if there is no match.
+     *  Used by the driver core to check whether a Zorro device present in the
+     *  system is in a driver's list of supported devices.  Returns 1 if
+     *  supported, and 0 if there is no match.
      */
 
 static int zorro_bus_match(struct device *dev, struct device_driver *drv)
@@ -134,12 +133,7 @@ static int zorro_bus_match(struct device *dev, struct device_driver *drv)
        if (!ids)
                return 0;
 
-       while (ids->id) {
-               if (ids->id == ZORRO_WILDCARD || ids->id == z->id)
-                       return 1;
-               ids++;
-       }
-       return 0;
+       return !!zorro_match_device(ids, z);
 }
 
 static int zorro_uevent(struct device *dev, struct kobj_uevent_env *env)
index 8eeb84c..47c7338 100644 (file)
@@ -41,7 +41,7 @@ struct zorro_dev *zorro_autocon;
 
 struct zorro_bus {
        struct device dev;
-       struct zorro_dev devices[0];
+       struct zorro_dev devices[];
 };
 
 
index ac0bab3..f84df9f 100644 (file)
@@ -1,5 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 
+    /*
+     *  Zorro bus
+     */
+
+extern struct bus_type zorro_bus_type;
+
+
 #ifdef CONFIG_ZORRO_NAMES
 extern void zorro_name_device(struct zorro_dev *z);
 #else
index df415c0..de1ae0b 100644 (file)
@@ -19,7 +19,7 @@
 void afs_put_addrlist(struct afs_addr_list *alist)
 {
        if (alist && refcount_dec_and_test(&alist->usage))
-               call_rcu(&alist->rcu, (rcu_callback_t)kfree);
+               kfree_rcu(alist, rcu);
 }
 
 /*
index ff3994a..6765949 100644 (file)
@@ -244,6 +244,17 @@ static void afs_cm_destructor(struct afs_call *call)
 }
 
 /*
+ * Abort a service call from within an action function.
+ */
+static void afs_abort_service_call(struct afs_call *call, u32 abort_code, int error,
+                                  const char *why)
+{
+       rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
+                               abort_code, error, why);
+       afs_set_call_complete(call, error, 0);
+}
+
+/*
  * The server supplied a list of callbacks that it wanted to break.
  */
 static void SRXAFSCB_CallBack(struct work_struct *work)
@@ -510,8 +521,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)
        if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0)
                afs_send_empty_reply(call);
        else
-               rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
-                                       1, 1, "K-1");
+               afs_abort_service_call(call, 1, 1, "K-1");
 
        afs_put_call(call);
        _leave("");
index cfe62b1..e1b9ed6 100644 (file)
@@ -145,6 +145,7 @@ static int afs_do_probe_fileserver(struct afs_net *net,
        read_lock(&server->fs_lock);
        ac.alist = rcu_dereference_protected(server->addresses,
                                             lockdep_is_held(&server->fs_lock));
+       afs_get_addrlist(ac.alist);
        read_unlock(&server->fs_lock);
 
        atomic_set(&server->probe_outstanding, ac.alist->nr_addrs);
@@ -163,6 +164,7 @@ static int afs_do_probe_fileserver(struct afs_net *net,
 
        if (!in_progress)
                afs_fs_probe_done(server);
+       afs_put_addrlist(ac.alist);
        return in_progress;
 }
 
index 1d81fc4..ef732dd 100644 (file)
@@ -81,7 +81,7 @@ enum afs_call_state {
  * List of server addresses.
  */
 struct afs_addr_list {
-       struct rcu_head         rcu;            /* Must be first */
+       struct rcu_head         rcu;
        refcount_t              usage;
        u32                     version;        /* Version */
        unsigned char           max_addrs;
@@ -154,7 +154,7 @@ struct afs_call {
        };
        unsigned char           unmarshall;     /* unmarshalling phase */
        unsigned char           addr_ix;        /* Address in ->alist */
-       bool                    incoming;       /* T if incoming call */
+       bool                    drop_ref;       /* T if need to drop ref for incoming call */
        bool                    send_pages;     /* T if data from mapping should be sent */
        bool                    need_attention; /* T if RxRPC poked us */
        bool                    async;          /* T if asynchronous */
@@ -1209,8 +1209,16 @@ static inline void afs_set_call_complete(struct afs_call *call,
                ok = true;
        }
        spin_unlock_bh(&call->state_lock);
-       if (ok)
+       if (ok) {
                trace_afs_call_done(call);
+
+               /* Asynchronous calls have two refs to release - one from the alloc and
+                * one queued with the work item - and we can't just deallocate the
+                * call because the work item may be queued again.
+                */
+               if (call->drop_ref)
+                       afs_put_call(call);
+       }
 }
 
 /*
index 58d3965..1ecc67d 100644 (file)
@@ -18,7 +18,6 @@ struct workqueue_struct *afs_async_calls;
 
 static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long);
 static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long);
-static void afs_delete_async_call(struct work_struct *);
 static void afs_process_async_call(struct work_struct *);
 static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long);
 static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long);
@@ -169,7 +168,7 @@ void afs_put_call(struct afs_call *call)
        int n = atomic_dec_return(&call->usage);
        int o = atomic_read(&net->nr_outstanding_calls);
 
-       trace_afs_call(call, afs_call_trace_put, n + 1, o,
+       trace_afs_call(call, afs_call_trace_put, n, o,
                       __builtin_return_address(0));
 
        ASSERTCMP(n, >=, 0);
@@ -402,8 +401,10 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
        /* If the call is going to be asynchronous, we need an extra ref for
         * the call to hold itself so the caller need not hang on to its ref.
         */
-       if (call->async)
+       if (call->async) {
                afs_get_call(call, afs_call_trace_get);
+               call->drop_ref = true;
+       }
 
        /* create a call */
        rxcall = rxrpc_kernel_begin_call(call->net->socket, srx, call->key,
@@ -413,7 +414,8 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
                                          afs_wake_up_async_call :
                                          afs_wake_up_call_waiter),
                                         call->upgrade,
-                                        call->intr,
+                                        (call->intr ? RXRPC_PREINTERRUPTIBLE :
+                                         RXRPC_UNINTERRUPTIBLE),
                                         call->debug_id);
        if (IS_ERR(rxcall)) {
                ret = PTR_ERR(rxcall);
@@ -584,8 +586,6 @@ static void afs_deliver_to_call(struct afs_call *call)
 done:
        if (call->type->done)
                call->type->done(call);
-       if (state == AFS_CALL_COMPLETE && call->incoming)
-               afs_put_call(call);
 out:
        _leave("");
        return;
@@ -604,11 +604,7 @@ call_complete:
 long afs_wait_for_call_to_complete(struct afs_call *call,
                                   struct afs_addr_cursor *ac)
 {
-       signed long rtt2, timeout;
        long ret;
-       bool stalled = false;
-       u64 rtt;
-       u32 life, last_life;
        bool rxrpc_complete = false;
 
        DECLARE_WAITQUEUE(myself, current);
@@ -619,14 +615,6 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
        if (ret < 0)
                goto out;
 
-       rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall);
-       rtt2 = nsecs_to_jiffies64(rtt) * 2;
-       if (rtt2 < 2)
-               rtt2 = 2;
-
-       timeout = rtt2;
-       rxrpc_kernel_check_life(call->net->socket, call->rxcall, &last_life);
-
        add_wait_queue(&call->waitq, &myself);
        for (;;) {
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -637,37 +625,19 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
                        call->need_attention = false;
                        __set_current_state(TASK_RUNNING);
                        afs_deliver_to_call(call);
-                       timeout = rtt2;
                        continue;
                }
 
                if (afs_check_call_state(call, AFS_CALL_COMPLETE))
                        break;
 
-               if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall, &life)) {
+               if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall)) {
                        /* rxrpc terminated the call. */
                        rxrpc_complete = true;
                        break;
                }
 
-               if (call->intr && timeout == 0 &&
-                   life == last_life && signal_pending(current)) {
-                       if (stalled)
-                               break;
-                       __set_current_state(TASK_RUNNING);
-                       rxrpc_kernel_probe_life(call->net->socket, call->rxcall);
-                       timeout = rtt2;
-                       stalled = true;
-                       continue;
-               }
-
-               if (life != last_life) {
-                       timeout = rtt2;
-                       last_life = life;
-                       stalled = false;
-               }
-
-               timeout = schedule_timeout(timeout);
+               schedule();
        }
 
        remove_wait_queue(&call->waitq, &myself);
@@ -735,7 +705,7 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
 
        u = atomic_fetch_add_unless(&call->usage, 1, 0);
        if (u != 0) {
-               trace_afs_call(call, afs_call_trace_wake, u,
+               trace_afs_call(call, afs_call_trace_wake, u + 1,
                               atomic_read(&call->net->nr_outstanding_calls),
                               __builtin_return_address(0));
 
@@ -745,21 +715,6 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
 }
 
 /*
- * Delete an asynchronous call.  The work item carries a ref to the call struct
- * that we need to release.
- */
-static void afs_delete_async_call(struct work_struct *work)
-{
-       struct afs_call *call = container_of(work, struct afs_call, async_work);
-
-       _enter("");
-
-       afs_put_call(call);
-
-       _leave("");
-}
-
-/*
  * Perform I/O processing on an asynchronous call.  The work item carries a ref
  * to the call struct that we either need to release or to pass on.
  */
@@ -774,16 +729,6 @@ static void afs_process_async_call(struct work_struct *work)
                afs_deliver_to_call(call);
        }
 
-       if (call->state == AFS_CALL_COMPLETE) {
-               /* We have two refs to release - one from the alloc and one
-                * queued with the work item - and we can't just deallocate the
-                * call because the work item may be queued again.
-                */
-               call->async_work.func = afs_delete_async_call;
-               if (!queue_work(afs_async_calls, &call->async_work))
-                       afs_put_call(call);
-       }
-
        afs_put_call(call);
        _leave("");
 }
@@ -810,6 +755,7 @@ void afs_charge_preallocation(struct work_struct *work)
                        if (!call)
                                break;
 
+                       call->drop_ref = true;
                        call->async = true;
                        call->state = AFS_CALL_SV_AWAIT_OP_ID;
                        init_waitqueue_head(&call->waitq);
index 69bf2fb..9501880 100644 (file)
@@ -1520,10 +1520,22 @@ rescan:
        if (ret)
                return ret;
 
-       if (invalidate)
-               set_capacity(disk, 0);
-       else if (disk->fops->revalidate_disk)
-               disk->fops->revalidate_disk(disk);
+       /*
+        * Historically we only set the capacity to zero for devices that
+        * support partitions (independ of actually having partitions created).
+        * Doing that is rather inconsistent, but changing it broke legacy
+        * udisks polling for legacy ide-cdrom devices.  Use the crude check
+        * below to get the sane behavior for most device while not breaking
+        * userspace for this particular setup.
+        */
+       if (invalidate) {
+               if (disk_part_scan_enabled(disk) ||
+                   !(disk->flags & GENHD_FL_REMOVABLE))
+                       set_capacity(disk, 0);
+       } else {
+               if (disk->fops->revalidate_disk)
+                       disk->fops->revalidate_disk(disk);
+       }
 
        check_disk_size_change(disk, bdev, !invalidate);
 
index 404e050..7f09147 100644 (file)
@@ -856,9 +856,9 @@ static void clear_incompat_bg_bits(struct btrfs_fs_info *fs_info, u64 flags)
                                found_raid1c34 = true;
                        up_read(&sinfo->groups_sem);
                }
-               if (found_raid56)
+               if (!found_raid56)
                        btrfs_clear_fs_incompat(fs_info, RAID56);
-               if (found_raid1c34)
+               if (!found_raid1c34)
                        btrfs_clear_fs_incompat(fs_info, RAID1C34);
        }
 }
index 1ccb3f8..d267eb5 100644 (file)
@@ -7783,6 +7783,7 @@ static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,
 {
        struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
        struct btrfs_io_bio *orig_io_bio = btrfs_io_bio(dip->orig_bio);
+       u16 csum_size;
        blk_status_t ret;
 
        /*
@@ -7802,7 +7803,8 @@ static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,
 
        file_offset -= dip->logical_offset;
        file_offset >>= inode->i_sb->s_blocksize_bits;
-       io_bio->csum = (u8 *)(((u32 *)orig_io_bio->csum) + file_offset);
+       csum_size = btrfs_super_csum_size(btrfs_sb(inode->i_sb)->super_copy);
+       io_bio->csum = orig_io_bio->csum + csum_size * file_offset;
 
        return 0;
 }
@@ -9494,6 +9496,10 @@ out_fail:
                ret = btrfs_sync_log(trans, BTRFS_I(old_inode)->root, &ctx);
                if (ret)
                        commit_transaction = true;
+       } else if (sync_log) {
+               mutex_lock(&root->log_mutex);
+               list_del(&ctx.list);
+               mutex_unlock(&root->log_mutex);
        }
        if (commit_transaction) {
                ret = btrfs_commit_transaction(trans);
index b8d2837..f73276d 100644 (file)
@@ -274,8 +274,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
         * decide that the page is now completely done.
         */
        first = page_buffers(page);
-       local_irq_save(flags);
-       bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
+       spin_lock_irqsave(&first->b_uptodate_lock, flags);
        clear_buffer_async_read(bh);
        unlock_buffer(bh);
        tmp = bh;
@@ -288,8 +287,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
                }
                tmp = tmp->b_this_page;
        } while (tmp != bh);
-       bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
 
        /*
         * If none of the buffers had errors and they are all
@@ -301,8 +299,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
        return;
 
 still_busy:
-       bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
        return;
 }
 
@@ -371,8 +368,7 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
        }
 
        first = page_buffers(page);
-       local_irq_save(flags);
-       bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
+       spin_lock_irqsave(&first->b_uptodate_lock, flags);
 
        clear_buffer_async_write(bh);
        unlock_buffer(bh);
@@ -384,14 +380,12 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
                }
                tmp = tmp->b_this_page;
        }
-       bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
        end_page_writeback(page);
        return;
 
 still_busy:
-       bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
        return;
 }
 EXPORT_SYMBOL(end_buffer_async_write);
@@ -3019,49 +3013,6 @@ static void end_bio_bh_io_sync(struct bio *bio)
        bio_put(bio);
 }
 
-/*
- * This allows us to do IO even on the odd last sectors
- * of a device, even if the block size is some multiple
- * of the physical sector size.
- *
- * We'll just truncate the bio to the size of the device,
- * and clear the end of the buffer head manually.
- *
- * Truly out-of-range accesses will turn into actual IO
- * errors, this only handles the "we need to be able to
- * do IO at the final sector" case.
- */
-void guard_bio_eod(struct bio *bio)
-{
-       sector_t maxsector;
-       struct hd_struct *part;
-
-       rcu_read_lock();
-       part = __disk_get_part(bio->bi_disk, bio->bi_partno);
-       if (part)
-               maxsector = part_nr_sects_read(part);
-       else
-               maxsector = get_capacity(bio->bi_disk);
-       rcu_read_unlock();
-
-       if (!maxsector)
-               return;
-
-       /*
-        * If the *whole* IO is past the end of the device,
-        * let it through, and the IO layer will turn it into
-        * an EIO.
-        */
-       if (unlikely(bio->bi_iter.bi_sector >= maxsector))
-               return;
-
-       maxsector -= bio->bi_iter.bi_sector;
-       if (likely((bio->bi_iter.bi_size >> 9) <= maxsector))
-               return;
-
-       bio_truncate(bio, maxsector << 9);
-}
-
 static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
                         enum rw_hint write_hint, struct writeback_control *wbc)
 {
@@ -3385,6 +3336,7 @@ struct buffer_head *alloc_buffer_head(gfp_t gfp_flags)
        struct buffer_head *ret = kmem_cache_zalloc(bh_cachep, gfp_flags);
        if (ret) {
                INIT_LIST_HEAD(&ret->b_assoc_buffers);
+               spin_lock_init(&ret->b_uptodate_lock);
                preempt_disable();
                __this_cpu_inc(bh_accounting.nr);
                recalc_bh_state();
index 7e0190b..5a478cd 100644 (file)
@@ -1415,10 +1415,13 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
        struct inode *inode = file_inode(file);
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
+       struct ceph_osd_client *osdc = &fsc->client->osdc;
        struct ceph_cap_flush *prealloc_cf;
        ssize_t count, written = 0;
        int err, want, got;
        bool direct_lock = false;
+       u32 map_flags;
+       u64 pool_flags;
        loff_t pos;
        loff_t limit = max(i_size_read(inode), fsc->max_file_size);
 
@@ -1481,8 +1484,12 @@ retry_snap:
                        goto out;
        }
 
-       /* FIXME: not complete since it doesn't account for being at quota */
-       if (ceph_osdmap_flag(&fsc->client->osdc, CEPH_OSDMAP_FULL)) {
+       down_read(&osdc->lock);
+       map_flags = osdc->osdmap->flags;
+       pool_flags = ceph_pg_pool_flags(osdc->osdmap, ci->i_layout.pool_id);
+       up_read(&osdc->lock);
+       if ((map_flags & CEPH_OSDMAP_FULL) ||
+           (pool_flags & CEPH_POOL_FLAG_FULL)) {
                err = -ENOSPC;
                goto out;
        }
@@ -1575,7 +1582,8 @@ retry_snap:
        }
 
        if (written >= 0) {
-               if (ceph_osdmap_flag(&fsc->client->osdc, CEPH_OSDMAP_NEARFULL))
+               if ((map_flags & CEPH_OSDMAP_NEARFULL) ||
+                   (pool_flags & CEPH_POOL_FLAG_NEARFULL))
                        iocb->ki_flags |= IOCB_DSYNC;
                written = generic_write_sync(iocb, written);
        }
index ccfcc66..923be93 100644 (file)
@@ -1155,5 +1155,6 @@ void ceph_cleanup_snapid_map(struct ceph_mds_client *mdsc)
                        pr_err("snapid map %llx -> %x still in use\n",
                               sm->snap, sm->dev);
                }
+               kfree(sm);
        }
 }
index 606f26d..cc3ada1 100644 (file)
@@ -324,6 +324,8 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
        if (full_path == NULL)
                goto cdda_exit;
 
+       convert_delimiter(full_path, '\\');
+
        cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
 
        if (!cifs_sb_master_tlink(cifs_sb)) {
index 46ebaf3..fa77fe5 100644 (file)
@@ -530,6 +530,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
 
        if (tcon->seal)
                seq_puts(s, ",seal");
+       else if (tcon->ses->server->ignore_signature)
+               seq_puts(s, ",signloosely");
        if (tcon->nocase)
                seq_puts(s, ",nocase");
        if (tcon->local_lease)
index de82cfa..0d95636 100644 (file)
@@ -1281,6 +1281,7 @@ struct cifs_fid {
        __u64 volatile_fid;     /* volatile file id for smb2 */
        __u8 lease_key[SMB2_LEASE_KEY_SIZE];    /* lease key for smb2 */
        __u8 create_guid[16];
+       __u32 access;
        struct cifs_pending_open *pending_open;
        unsigned int epoch;
 #ifdef CONFIG_CIFS_DEBUG2
@@ -1741,6 +1742,12 @@ static inline bool is_retryable_error(int error)
        return false;
 }
 
+
+/* cifs_get_writable_file() flags */
+#define FIND_WR_ANY         0
+#define FIND_WR_FSUID_ONLY  1
+#define FIND_WR_WITH_DELETE 2
+
 #define   MID_FREE 0
 #define   MID_REQUEST_ALLOCATED 1
 #define   MID_REQUEST_SUBMITTED 2
index 89eaaf4..e5cb681 100644 (file)
@@ -134,11 +134,12 @@ extern bool backup_cred(struct cifs_sb_info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
 extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
                            unsigned int bytes_written);
-extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
+extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, int);
 extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
-                                 bool fsuid_only,
+                                 int flags,
                                  struct cifsFileInfo **ret_file);
 extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
+                                 int flags,
                                  struct cifsFileInfo **ret_file);
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
 extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
index 3c89569..6f6fb36 100644 (file)
@@ -1492,6 +1492,7 @@ openRetry:
        *oplock = rsp->OplockLevel;
        /* cifs fid stays in le */
        oparms->fid->netfid = rsp->Fid;
+       oparms->fid->access = desired_access;
 
        /* Let caller know file was created so we can set the mode. */
        /* Do we care about the CreateAction in any other cases? */
@@ -2115,7 +2116,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
                wdata2->tailsz = tailsz;
                wdata2->bytes = cur_len;
 
-               rc = cifs_get_writable_file(CIFS_I(inode), false,
+               rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
                                            &wdata2->cfile);
                if (!wdata2->cfile) {
                        cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
index 0ef0994..36e7b2f 100644 (file)
@@ -555,7 +555,6 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
                if (server->ops->close)
                        server->ops->close(xid, tcon, &fid);
                cifs_del_pending_open(&open);
-               fput(file);
                rc = -ENOMEM;
        }
 
index bc9516a..8f9d849 100644 (file)
@@ -1169,7 +1169,8 @@ try_again:
        rc = posix_lock_file(file, flock, NULL);
        up_write(&cinode->lock_sem);
        if (rc == FILE_LOCK_DEFERRED) {
-               rc = wait_event_interruptible(flock->fl_wait, !flock->fl_blocker);
+               rc = wait_event_interruptible(flock->fl_wait,
+                                       list_empty(&flock->fl_blocked_member));
                if (!rc)
                        goto try_again;
                locks_delete_block(flock);
@@ -1958,7 +1959,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
 
 /* Return -EBADF if no handle is found and general rc otherwise */
 int
-cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
+cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
                       struct cifsFileInfo **ret_file)
 {
        struct cifsFileInfo *open_file, *inv_file = NULL;
@@ -1966,7 +1967,8 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
        bool any_available = false;
        int rc = -EBADF;
        unsigned int refind = 0;
-
+       bool fsuid_only = flags & FIND_WR_FSUID_ONLY;
+       bool with_delete = flags & FIND_WR_WITH_DELETE;
        *ret_file = NULL;
 
        /*
@@ -1998,6 +2000,8 @@ refind_writable:
                        continue;
                if (fsuid_only && !uid_eq(open_file->uid, current_fsuid()))
                        continue;
+               if (with_delete && !(open_file->fid.access & DELETE))
+                       continue;
                if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
                        if (!open_file->invalidHandle) {
                                /* found a good writable file */
@@ -2045,12 +2049,12 @@ refind_writable:
 }
 
 struct cifsFileInfo *
-find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only)
+find_writable_file(struct cifsInodeInfo *cifs_inode, int flags)
 {
        struct cifsFileInfo *cfile;
        int rc;
 
-       rc = cifs_get_writable_file(cifs_inode, fsuid_only, &cfile);
+       rc = cifs_get_writable_file(cifs_inode, flags, &cfile);
        if (rc)
                cifs_dbg(FYI, "couldn't find writable handle rc=%d", rc);
 
@@ -2059,6 +2063,7 @@ find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only)
 
 int
 cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
+                      int flags,
                       struct cifsFileInfo **ret_file)
 {
        struct list_head *tmp;
@@ -2085,7 +2090,7 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
                kfree(full_path);
                cinode = CIFS_I(d_inode(cfile->dentry));
                spin_unlock(&tcon->open_file_lock);
-               return cifs_get_writable_file(cinode, 0, ret_file);
+               return cifs_get_writable_file(cinode, flags, ret_file);
        }
 
        spin_unlock(&tcon->open_file_lock);
@@ -2162,7 +2167,8 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
        if (mapping->host->i_size - offset < (loff_t)to)
                to = (unsigned)(mapping->host->i_size - offset);
 
-       rc = cifs_get_writable_file(CIFS_I(mapping->host), false, &open_file);
+       rc = cifs_get_writable_file(CIFS_I(mapping->host), FIND_WR_ANY,
+                                   &open_file);
        if (!rc) {
                bytes_written = cifs_write(open_file, open_file->pid,
                                           write_data, to - from, &offset);
@@ -2355,7 +2361,7 @@ retry:
                if (cfile)
                        cifsFileInfo_put(cfile);
 
-               rc = cifs_get_writable_file(CIFS_I(inode), false, &cfile);
+               rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY, &cfile);
 
                /* in case of an error store it to return later */
                if (rc)
index b5e6635..b16f8d2 100644 (file)
@@ -653,8 +653,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                 */
                if ((fattr->cf_nlink < 1) && !tcon->unix_ext &&
                    !info->DeletePending) {
-                       cifs_dbg(1, "bogus file nlink value %u\n",
-                               fattr->cf_nlink);
+                       cifs_dbg(VFS, "bogus file nlink value %u\n",
+                                fattr->cf_nlink);
                        fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
                }
        }
@@ -2073,6 +2073,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
        struct inode *inode = d_inode(dentry);
        struct super_block *sb = dentry->d_sb;
        char *full_path = NULL;
+       int count = 0;
 
        if (inode == NULL)
                return -ENOENT;
@@ -2094,15 +2095,18 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
                 full_path, inode, inode->i_count.counter,
                 dentry, cifs_get_time(dentry), jiffies);
 
+again:
        if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
                rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
        else
                rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
                                         xid, NULL);
-
+       if (rc == -EAGAIN && count++ < 10)
+               goto again;
 out:
        kfree(full_path);
        free_xid(xid);
+
        return rc;
 }
 
@@ -2187,7 +2191,7 @@ int cifs_getattr(const struct path *path, struct kstat *stat,
                if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID))
                        stat->gid = current_fsgid();
        }
-       return rc;
+       return 0;
 }
 
 int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
@@ -2278,7 +2282,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
         * writebehind data than the SMB timeout for the SetPathInfo
         * request would allow
         */
-       open_file = find_writable_file(cifsInode, true);
+       open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
        if (open_file) {
                tcon = tlink_tcon(open_file->tlink);
                server = tcon->ses->server;
@@ -2428,7 +2432,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
                args->ctime = NO_CHANGE_64;
 
        args->device = 0;
-       open_file = find_writable_file(cifsInode, true);
+       open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
        if (open_file) {
                u16 nfid = open_file->fid.netfid;
                u32 npid = open_file->pid;
@@ -2531,7 +2535,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
        rc = 0;
 
        if (attrs->ia_valid & ATTR_MTIME) {
-               rc = cifs_get_writable_file(cifsInode, false, &wfile);
+               rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile);
                if (!rc) {
                        tcon = tlink_tcon(wfile->tlink);
                        rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
index eb994e3..b130efa 100644 (file)
@@ -766,7 +766,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
        struct cifs_tcon *tcon;
 
        /* if the file is already open for write, just use that fileid */
-       open_file = find_writable_file(cinode, true);
+       open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY);
        if (open_file) {
                fid.netfid = open_file->fid.netfid;
                netpid = open_file->pid;
index 1cf2075..a8c301a 100644 (file)
@@ -521,7 +521,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
        cifs_i = CIFS_I(inode);
        dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
        data.Attributes = cpu_to_le32(dosattrs);
-       cifs_get_writable_path(tcon, name, &cfile);
+       cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
        tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
                                 FILE_WRITE_ATTRIBUTES, FILE_CREATE,
                                 CREATE_NOT_FILE, ACL_NO_MODE,
@@ -577,7 +577,7 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
 {
        struct cifsFileInfo *cfile;
 
-       cifs_get_writable_path(tcon, from_name, &cfile);
+       cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
 
        return smb2_set_path_attr(xid, tcon, from_name, to_name,
                                  cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
index e47190c..cfe9b80 100644 (file)
@@ -1364,6 +1364,7 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
 
        cfile->fid.persistent_fid = fid->persistent_fid;
        cfile->fid.volatile_fid = fid->volatile_fid;
+       cfile->fid.access = fid->access;
 #ifdef CONFIG_CIFS_DEBUG2
        cfile->fid.mid = fid->mid;
 #endif /* CIFS_DEBUG2 */
@@ -2221,6 +2222,8 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
                goto qdf_free;
        }
 
+       atomic_inc(&tcon->num_remote_opens);
+
        qd_rsp = (struct smb2_query_directory_rsp *)rsp_iov[1].iov_base;
        if (qd_rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) {
                trace_smb3_query_dir_done(xid, fid->persistent_fid,
@@ -3327,7 +3330,7 @@ static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offs
         * some servers (Windows2016) will not reflect recent writes in
         * QUERY_ALLOCATED_RANGES until SMB2_flush is called.
         */
-       wrcfile = find_writable_file(cifsi, false);
+       wrcfile = find_writable_file(cifsi, FIND_WR_ANY);
        if (wrcfile) {
                filemap_write_and_wait(inode->i_mapping);
                smb2_flush_file(xid, tcon, &wrcfile->fid);
@@ -3416,7 +3419,7 @@ static int smb3_fiemap(struct cifs_tcon *tcon,
        if (rc)
                goto out;
 
-       if (out_data_len < sizeof(struct file_allocated_range_buffer)) {
+       if (out_data_len && out_data_len < sizeof(struct file_allocated_range_buffer)) {
                rc = -EINVAL;
                goto out;
        }
index 1234f9c..28c0be5 100644 (file)
@@ -2771,6 +2771,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        atomic_inc(&tcon->num_remote_opens);
        oparms->fid->persistent_fid = rsp->PersistentFileId;
        oparms->fid->volatile_fid = rsp->VolatileFileId;
+       oparms->fid->access = oparms->desired_access;
 #ifdef CONFIG_CIFS_DEBUG2
        oparms->fid->mid = le64_to_cpu(rsp->sync_hdr.MessageId);
 #endif /* CIFS_DEBUG2 */
index 65cb09f..08c9f21 100644 (file)
@@ -539,6 +539,15 @@ int fscrypt_drop_inode(struct inode *inode)
        mk = ci->ci_master_key->payload.data[0];
 
        /*
+        * With proper, non-racy use of FS_IOC_REMOVE_ENCRYPTION_KEY, all inodes
+        * protected by the key were cleaned by sync_filesystem().  But if
+        * userspace is still using the files, inodes can be dirtied between
+        * then and now.  We mustn't lose any writes, so skip dirty inodes here.
+        */
+       if (inode->i_state & I_DIRTY_ALL)
+               return 0;
+
+       /*
         * Note: since we aren't holding ->mk_secret_sem, the result here can
         * immediately become outdated.  But there's no correctness problem with
         * unnecessarily evicting.  Nor is there a correctness problem with not
index 634b09d..f34757e 100644 (file)
@@ -175,8 +175,13 @@ static int open_proxy_open(struct inode *inode, struct file *filp)
        if (r)
                goto out;
 
-       real_fops = fops_get(real_fops);
-       if (!real_fops) {
+       if (!fops_get(real_fops)) {
+#ifdef MODULE
+               if (real_fops->owner &&
+                   real_fops->owner->state == MODULE_STATE_GOING)
+                       goto out;
+#endif
+
                /* Huh? Module did not clean up after itself at exit? */
                WARN(1, "debugfs file owner did not clean up at exit: %pd",
                        dentry);
@@ -305,8 +310,13 @@ static int full_proxy_open(struct inode *inode, struct file *filp)
        if (r)
                goto out;
 
-       real_fops = fops_get(real_fops);
-       if (!real_fops) {
+       if (!fops_get(real_fops)) {
+#ifdef MODULE
+               if (real_fops->owner &&
+                   real_fops->owner->state == MODULE_STATE_GOING)
+                       goto out;
+#endif
+
                /* Huh? Module did not cleanup after itself at exit? */
                WARN(1, "debugfs file owner did not clean up at exit: %pd",
                        dentry);
@@ -1090,21 +1100,12 @@ static const struct file_operations fops_regset32 = {
  * This function creates a file in debugfs with the given name that reports
  * the names and values of a set of 32-bit registers. If the @mode variable
  * is so set it can be read from. Writing is not supported.
- *
- * This function will return a pointer to a dentry if it succeeds.  This
- * pointer must be passed to the debugfs_remove() function when the file is
- * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, ERR_PTR(-ERROR) will be
- * returned.
- *
- * If debugfs is not enabled in the kernel, the value ERR_PTR(-ENODEV) will
- * be returned.
  */
-struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
-                                      struct dentry *parent,
-                                      struct debugfs_regset32 *regset)
+void debugfs_create_regset32(const char *name, umode_t mode,
+                            struct dentry *parent,
+                            struct debugfs_regset32 *regset)
 {
-       return debugfs_create_file(name, mode, parent, regset, &fops_regset32);
+       debugfs_create_file(name, mode, parent, regset, &fops_regset32);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_regset32);
 
index e742dfc..b7f2e97 100644 (file)
@@ -501,26 +501,16 @@ EXPORT_SYMBOL_GPL(debugfs_create_file_unsafe);
  * wide range of flexibility in creating a file, or a directory (if you want
  * to create a directory, the debugfs_create_dir() function is
  * recommended to be used instead.)
- *
- * This function will return a pointer to a dentry if it succeeds.  This
- * pointer must be passed to the debugfs_remove() function when the file is
- * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, ERR_PTR(-ERROR) will be
- * returned.
- *
- * If debugfs is not enabled in the kernel, the value -%ENODEV will be
- * returned.
  */
-struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
-                                       struct dentry *parent, void *data,
-                                       const struct file_operations *fops,
-                                       loff_t file_size)
+void debugfs_create_file_size(const char *name, umode_t mode,
+                             struct dentry *parent, void *data,
+                             const struct file_operations *fops,
+                             loff_t file_size)
 {
        struct dentry *de = debugfs_create_file(name, mode, parent, data, fops);
 
        if (de)
                d_inode(de)->i_size = file_size;
-       return de;
 }
 EXPORT_SYMBOL_GPL(debugfs_create_file_size);
 
index fa4f644..12c66f5 100644 (file)
@@ -252,7 +252,7 @@ static struct file_system_type efivarfs_type = {
 
 static __init int efivarfs_init(void)
 {
-       if (!efi_enabled(EFI_RUNTIME_SERVICES))
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
                return -ENODEV;
 
        if (!efivars_kobject())
index 5779a15..5d2d819 100644 (file)
@@ -157,17 +157,27 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq, u8 *out)
                }
        }
 
-       ret = LZ4_decompress_safe_partial(src + inputmargin, out,
-                                         inlen, rq->outputsize,
-                                         rq->outputsize);
-       if (ret < 0) {
-               erofs_err(rq->sb, "failed to decompress, in[%u, %u] out[%u]",
-                         inlen, inputmargin, rq->outputsize);
+       /* legacy format could compress extra data in a pcluster. */
+       if (rq->partial_decoding || !support_0padding)
+               ret = LZ4_decompress_safe_partial(src + inputmargin, out,
+                                                 inlen, rq->outputsize,
+                                                 rq->outputsize);
+       else
+               ret = LZ4_decompress_safe(src + inputmargin, out,
+                                         inlen, rq->outputsize);
+
+       if (ret != rq->outputsize) {
+               erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
+                         ret, inlen, inputmargin, 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);
+
+               if (ret >= 0)
+                       memset(out + ret, 0, rq->outputsize - ret);
                ret = -EIO;
        }
 
index c4c6dcd..5eead7f 100644 (file)
@@ -52,8 +52,8 @@ struct erofs_sb_info {
        struct list_head list;
        struct mutex umount_mutex;
 
-       /* the dedicated workstation for compression */
-       struct radix_tree_root workstn_tree;
+       /* managed XArray arranged in physical block number */
+       struct xarray managed_pslots;
 
        /* threshold for decompression synchronously */
        unsigned int max_sync_decompress_pages;
@@ -402,8 +402,8 @@ static inline void *erofs_get_pcpubuf(unsigned int pagenr)
 int erofs_workgroup_put(struct erofs_workgroup *grp);
 struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
                                             pgoff_t index);
-int erofs_register_workgroup(struct super_block *sb,
-                            struct erofs_workgroup *grp);
+struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb,
+                                              struct erofs_workgroup *grp);
 void erofs_workgroup_free_rcu(struct erofs_workgroup *grp);
 void erofs_shrinker_register(struct super_block *sb);
 void erofs_shrinker_unregister(struct super_block *sb);
index 057e6d7..b514c67 100644 (file)
@@ -425,7 +425,7 @@ static int erofs_fill_super(struct super_block *sb, void *data, int silent)
                sb->s_flags &= ~SB_POSIXACL;
 
 #ifdef CONFIG_EROFS_FS_ZIP
-       INIT_RADIX_TREE(&sbi->workstn_tree, GFP_ATOMIC);
+       xa_init(&sbi->managed_pslots);
 #endif
 
        /* get the root inode */
index fddc505..52d0be1 100644 (file)
@@ -37,9 +37,6 @@ void *erofs_get_pcpubuf(unsigned int pagenr)
 /* global shrink count (for all mounted EROFS instances) */
 static atomic_long_t erofs_global_shrink_cnt;
 
-#define __erofs_workgroup_get(grp)     atomic_inc(&(grp)->refcount)
-#define __erofs_workgroup_put(grp)     atomic_dec(&(grp)->refcount)
-
 static int erofs_workgroup_get(struct erofs_workgroup *grp)
 {
        int o;
@@ -66,7 +63,7 @@ struct erofs_workgroup *erofs_find_workgroup(struct super_block *sb,
 
 repeat:
        rcu_read_lock();
-       grp = radix_tree_lookup(&sbi->workstn_tree, index);
+       grp = xa_load(&sbi->managed_pslots, index);
        if (grp) {
                if (erofs_workgroup_get(grp)) {
                        /* prefer to relax rcu read side */
@@ -80,43 +77,37 @@ repeat:
        return grp;
 }
 
-int erofs_register_workgroup(struct super_block *sb,
-                            struct erofs_workgroup *grp)
+struct erofs_workgroup *erofs_insert_workgroup(struct super_block *sb,
+                                              struct erofs_workgroup *grp)
 {
-       struct erofs_sb_info *sbi;
-       int err;
-
-       /* grp shouldn't be broken or used before */
-       if (atomic_read(&grp->refcount) != 1) {
-               DBG_BUGON(1);
-               return -EINVAL;
-       }
-
-       err = radix_tree_preload(GFP_NOFS);
-       if (err)
-               return err;
-
-       sbi = EROFS_SB(sb);
-       xa_lock(&sbi->workstn_tree);
+       struct erofs_sb_info *const sbi = EROFS_SB(sb);
+       struct erofs_workgroup *pre;
 
        /*
-        * Bump up reference count before making this workgroup
-        * visible to other users in order to avoid potential UAF
-        * without serialized by workstn_lock.
+        * Bump up a reference count before making this visible
+        * to others for the XArray in order to avoid potential
+        * UAF without serialized by xa_lock.
         */
-       __erofs_workgroup_get(grp);
-
-       err = radix_tree_insert(&sbi->workstn_tree, grp->index, grp);
-       if (err)
-               /*
-                * it's safe to decrease since the workgroup isn't visible
-                * and refcount >= 2 (cannot be freezed).
-                */
-               __erofs_workgroup_put(grp);
+       atomic_inc(&grp->refcount);
 
-       xa_unlock(&sbi->workstn_tree);
-       radix_tree_preload_end();
-       return err;
+repeat:
+       xa_lock(&sbi->managed_pslots);
+       pre = __xa_cmpxchg(&sbi->managed_pslots, grp->index,
+                          NULL, grp, GFP_NOFS);
+       if (pre) {
+               if (xa_is_err(pre)) {
+                       pre = ERR_PTR(xa_err(pre));
+               } else if (erofs_workgroup_get(pre)) {
+                       /* try to legitimize the current in-tree one */
+                       xa_unlock(&sbi->managed_pslots);
+                       cond_resched();
+                       goto repeat;
+               }
+               atomic_dec(&grp->refcount);
+               grp = pre;
+       }
+       xa_unlock(&sbi->managed_pslots);
+       return grp;
 }
 
 static void  __erofs_workgroup_free(struct erofs_workgroup *grp)
@@ -155,7 +146,7 @@ static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
 
        /*
         * Note that all cached pages should be unattached
-        * before deleted from the radix tree. Otherwise some
+        * before deleted from the XArray. Otherwise some
         * cached pages could be still attached to the orphan
         * old workgroup when the new one is available in the tree.
         */
@@ -169,7 +160,7 @@ static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
         * however in order to avoid some race conditions, add a
         * DBG_BUGON to observe this in advance.
         */
-       DBG_BUGON(radix_tree_delete(&sbi->workstn_tree, grp->index) != grp);
+       DBG_BUGON(xa_erase(&sbi->managed_pslots, grp->index) != grp);
 
        /*
         * If managed cache is on, last refcount should indicate
@@ -182,22 +173,11 @@ static bool erofs_try_to_release_workgroup(struct erofs_sb_info *sbi,
 static unsigned long erofs_shrink_workstation(struct erofs_sb_info *sbi,
                                              unsigned long nr_shrink)
 {
-       pgoff_t first_index = 0;
-       void *batch[PAGEVEC_SIZE];
+       struct erofs_workgroup *grp;
        unsigned int freed = 0;
+       unsigned long index;
 
-       int i, found;
-repeat:
-       xa_lock(&sbi->workstn_tree);
-
-       found = radix_tree_gang_lookup(&sbi->workstn_tree,
-                                      batch, first_index, PAGEVEC_SIZE);
-
-       for (i = 0; i < found; ++i) {
-               struct erofs_workgroup *grp = batch[i];
-
-               first_index = grp->index + 1;
-
+       xa_for_each(&sbi->managed_pslots, index, grp) {
                /* try to shrink each valid workgroup */
                if (!erofs_try_to_release_workgroup(sbi, grp))
                        continue;
@@ -206,10 +186,6 @@ repeat:
                if (!--nr_shrink)
                        break;
        }
-       xa_unlock(&sbi->workstn_tree);
-
-       if (i && nr_shrink)
-               goto repeat;
        return freed;
 }
 
@@ -286,7 +262,7 @@ static unsigned long erofs_shrink_scan(struct shrinker *shrink,
                spin_unlock(&erofs_sb_list_lock);
                sbi->shrinker_run_no = run_no;
 
-               freed += erofs_shrink_workstation(sbi, nr);
+               freed += erofs_shrink_workstation(sbi, nr - freed);
 
                spin_lock(&erofs_sb_list_lock);
                /* Get the next list element before we move this one */
index 80e47f0..c4b6c9a 100644 (file)
@@ -67,16 +67,6 @@ static void z_erofs_pcluster_init_once(void *ptr)
                pcl->compressed_pages[i] = NULL;
 }
 
-static void z_erofs_pcluster_init_always(struct z_erofs_pcluster *pcl)
-{
-       struct z_erofs_collection *cl = z_erofs_primarycollection(pcl);
-
-       atomic_set(&pcl->obj.refcount, 1);
-
-       DBG_BUGON(cl->nr_pages);
-       DBG_BUGON(cl->vcnt);
-}
-
 int __init z_erofs_init_zip_subsystem(void)
 {
        pcluster_cachep = kmem_cache_create("erofs_compress",
@@ -341,26 +331,19 @@ static int z_erofs_lookup_collection(struct z_erofs_collector *clt,
                                     struct inode *inode,
                                     struct erofs_map_blocks *map)
 {
-       struct erofs_workgroup *grp;
-       struct z_erofs_pcluster *pcl;
+       struct z_erofs_pcluster *pcl = clt->pcl;
        struct z_erofs_collection *cl;
        unsigned int length;
 
-       grp = erofs_find_workgroup(inode->i_sb, map->m_pa >> PAGE_SHIFT);
-       if (!grp)
-               return -ENOENT;
-
-       pcl = container_of(grp, struct z_erofs_pcluster, obj);
+       /* to avoid unexpected loop formed by corrupted images */
        if (clt->owned_head == &pcl->next || pcl == clt->tailpcl) {
                DBG_BUGON(1);
-               erofs_workgroup_put(grp);
                return -EFSCORRUPTED;
        }
 
        cl = z_erofs_primarycollection(pcl);
        if (cl->pageofs != (map->m_la & ~PAGE_MASK)) {
                DBG_BUGON(1);
-               erofs_workgroup_put(grp);
                return -EFSCORRUPTED;
        }
 
@@ -368,7 +351,6 @@ static int z_erofs_lookup_collection(struct z_erofs_collector *clt,
        if (length & Z_EROFS_PCLUSTER_FULL_LENGTH) {
                if ((map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) > length) {
                        DBG_BUGON(1);
-                       erofs_workgroup_put(grp);
                        return -EFSCORRUPTED;
                }
        } else {
@@ -391,7 +373,6 @@ static int z_erofs_lookup_collection(struct z_erofs_collector *clt,
        /* clean tailpcl if the current owned_head is Z_EROFS_PCLUSTER_TAIL */
        if (clt->owned_head == Z_EROFS_PCLUSTER_TAIL)
                clt->tailpcl = NULL;
-       clt->pcl = pcl;
        clt->cl = cl;
        return 0;
 }
@@ -402,6 +383,7 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
 {
        struct z_erofs_pcluster *pcl;
        struct z_erofs_collection *cl;
+       struct erofs_workgroup *grp;
        int err;
 
        /* no available workgroup, let's allocate one */
@@ -409,7 +391,7 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
        if (!pcl)
                return -ENOMEM;
 
-       z_erofs_pcluster_init_always(pcl);
+       atomic_set(&pcl->obj.refcount, 1);
        pcl->obj.index = map->m_pa >> PAGE_SHIFT;
 
        pcl->length = (map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) |
@@ -429,19 +411,29 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
        clt->mode = COLLECT_PRIMARY_FOLLOWED;
 
        cl = z_erofs_primarycollection(pcl);
+
+       /* must be cleaned before freeing to slab */
+       DBG_BUGON(cl->nr_pages);
+       DBG_BUGON(cl->vcnt);
+
        cl->pageofs = map->m_la & ~PAGE_MASK;
 
        /*
         * lock all primary followed works before visible to others
         * and mutex_trylock *never* fails for a new pcluster.
         */
-       mutex_trylock(&cl->lock);
+       DBG_BUGON(!mutex_trylock(&cl->lock));
 
-       err = erofs_register_workgroup(inode->i_sb, &pcl->obj);
-       if (err) {
-               mutex_unlock(&cl->lock);
-               kmem_cache_free(pcluster_cachep, pcl);
-               return -EAGAIN;
+       grp = erofs_insert_workgroup(inode->i_sb, &pcl->obj);
+       if (IS_ERR(grp)) {
+               err = PTR_ERR(grp);
+               goto err_out;
+       }
+
+       if (grp != &pcl->obj) {
+               clt->pcl = container_of(grp, struct z_erofs_pcluster, obj);
+               err = -EEXIST;
+               goto err_out;
        }
        /* used to check tail merging loop due to corrupted images */
        if (clt->owned_head == Z_EROFS_PCLUSTER_TAIL)
@@ -450,12 +442,18 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt,
        clt->pcl = pcl;
        clt->cl = cl;
        return 0;
+
+err_out:
+       mutex_unlock(&cl->lock);
+       kmem_cache_free(pcluster_cachep, pcl);
+       return err;
 }
 
 static int z_erofs_collector_begin(struct z_erofs_collector *clt,
                                   struct inode *inode,
                                   struct erofs_map_blocks *map)
 {
+       struct erofs_workgroup *grp;
        int ret;
 
        DBG_BUGON(clt->cl);
@@ -469,21 +467,25 @@ static int z_erofs_collector_begin(struct z_erofs_collector *clt,
                return -EINVAL;
        }
 
-repeat:
-       ret = z_erofs_lookup_collection(clt, inode, map);
-       if (ret == -ENOENT) {
+       grp = erofs_find_workgroup(inode->i_sb, map->m_pa >> PAGE_SHIFT);
+       if (grp) {
+               clt->pcl = container_of(grp, struct z_erofs_pcluster, obj);
+       } else {
                ret = z_erofs_register_collection(clt, inode, map);
 
-               /* someone registered at the same time, give another try */
-               if (ret == -EAGAIN) {
-                       cond_resched();
-                       goto repeat;
-               }
+               if (!ret)
+                       goto out;
+               if (ret != -EEXIST)
+                       return ret;
        }
 
-       if (ret)
+       ret = z_erofs_lookup_collection(clt, inode, map);
+       if (ret) {
+               erofs_workgroup_put(&clt->pcl->obj);
                return ret;
+       }
 
+out:
        z_erofs_pagevec_ctor_init(&clt->vector, Z_EROFS_NR_INLINE_PAGEVECS,
                                  clt->cl->pagevec, clt->cl->vcnt);
 
index b041b66..eee3c92 100644 (file)
@@ -1854,9 +1854,9 @@ fetch_events:
                waiter = true;
                init_waitqueue_entry(&wait, current);
 
-               spin_lock_irq(&ep->wq.lock);
+               write_lock_irq(&ep->lock);
                __add_wait_queue_exclusive(&ep->wq, &wait);
-               spin_unlock_irq(&ep->wq.lock);
+               write_unlock_irq(&ep->lock);
        }
 
        for (;;) {
@@ -1904,9 +1904,9 @@ send_events:
                goto fetch_events;
 
        if (waiter) {
-               spin_lock_irq(&ep->wq.lock);
+               write_lock_irq(&ep->lock);
                __remove_wait_queue(&ep->wq, &wait);
-               spin_unlock_irq(&ep->wq.lock);
+               write_unlock_irq(&ep->lock);
        }
 
        return res;
index db17be5..688c824 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -985,6 +985,32 @@ int kernel_read_file_from_path(const char *path, void **buf, loff_t *size,
 }
 EXPORT_SYMBOL_GPL(kernel_read_file_from_path);
 
+int kernel_read_file_from_path_initns(const char *path, void **buf,
+                                     loff_t *size, loff_t max_size,
+                                     enum kernel_read_file_id id)
+{
+       struct file *file;
+       struct path root;
+       int ret;
+
+       if (!path || !*path)
+               return -EINVAL;
+
+       task_lock(&init_task);
+       get_fs_root(init_task.fs, &root);
+       task_unlock(&init_task);
+
+       file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0);
+       path_put(&root);
+       if (IS_ERR(file))
+               return PTR_ERR(file);
+
+       ret = kernel_read_file(file, buf, size, max_size, id);
+       fput(file);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(kernel_read_file_from_path_initns);
+
 int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size,
                             enum kernel_read_file_id id)
 {
index 68b39e7..de6fe96 100644 (file)
@@ -125,11 +125,10 @@ static void ext4_finish_bio(struct bio *bio)
                }
                bh = head = page_buffers(page);
                /*
-                * We check all buffers in the page under BH_Uptodate_Lock
+                * We check all buffers in the page under b_uptodate_lock
                 * to avoid races with other end io clearing async_write flags
                 */
-               local_irq_save(flags);
-               bit_spin_lock(BH_Uptodate_Lock, &head->b_state);
+               spin_lock_irqsave(&head->b_uptodate_lock, flags);
                do {
                        if (bh_offset(bh) < bio_start ||
                            bh_offset(bh) + bh->b_size > bio_end) {
@@ -141,8 +140,7 @@ static void ext4_finish_bio(struct bio *bio)
                        if (bio->bi_status)
                                buffer_io_error(bh);
                } while ((bh = bh->b_this_page) != head);
-               bit_spin_unlock(BH_Uptodate_Lock, &head->b_state);
-               local_irq_restore(flags);
+               spin_unlock_irqrestore(&head->b_uptodate_lock, flags);
                if (!under_io) {
                        fscrypt_free_bounce_page(bounce_page);
                        end_page_writeback(page);
index ff1b764..c8dff4c 100644 (file)
@@ -43,7 +43,7 @@
 #include <linux/uaccess.h>
 #include <linux/iversion.h>
 #include <linux/unicode.h>
-
+#include <linux/part_stat.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
@@ -927,7 +927,6 @@ void ext4_update_dynamic_rev(struct super_block *sb)
 static struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb)
 {
        struct block_device *bdev;
-       char b[BDEVNAME_SIZE];
 
        bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb);
        if (IS_ERR(bdev))
@@ -935,8 +934,9 @@ static struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb)
        return bdev;
 
 fail:
-       ext4_msg(sb, KERN_ERR, "failed to open journal device %s: %ld",
-                       __bdevname(dev, b), PTR_ERR(bdev));
+       ext4_msg(sb, KERN_ERR,
+                "failed to open journal device unknown-block(%u,%u) %ld",
+                MAJOR(dev), MINOR(dev), PTR_ERR(bdev));
        return NULL;
 }
 
@@ -2391,7 +2391,7 @@ int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        struct flex_groups **old_groups, **new_groups;
-       int size, i;
+       int size, i, j;
 
        if (!sbi->s_log_groups_per_flex)
                return 0;
@@ -2412,8 +2412,8 @@ int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
                                         sizeof(struct flex_groups)),
                                         GFP_KERNEL);
                if (!new_groups[i]) {
-                       for (i--; i >= sbi->s_flex_groups_allocated; i--)
-                               kvfree(new_groups[i]);
+                       for (j = sbi->s_flex_groups_allocated; j < i; j++)
+                               kvfree(new_groups[j]);
                        kvfree(new_groups);
                        ext4_msg(sb, KERN_ERR,
                                 "not enough memory for %d flex groups", size);
index d218ebd..04bfaf6 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
+#include <linux/part_stat.h>
 
 #include "ext4.h"
 #include "ext4_jbd2.h"
index 5355be6..088c3e7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/bio.h>
 #include <linux/blkdev.h>
 #include <linux/quotaops.h>
+#include <linux/part_stat.h>
 #include <crypto/hash.h>
 
 #include <linux/fscrypt.h>
index 65a7a43..d398b2d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/sysfs.h>
 #include <linux/quota.h>
 #include <linux/unicode.h>
+#include <linux/part_stat.h>
 
 #include "f2fs.h"
 #include "node.h"
index 594b05a..71946da 100644 (file)
@@ -750,6 +750,13 @@ static struct inode *fat_alloc_inode(struct super_block *sb)
                return NULL;
 
        init_rwsem(&ei->truncate_lock);
+       /* Zeroing to allow iput() even if partial initialized inode. */
+       ei->mmu_private = 0;
+       ei->i_start = 0;
+       ei->i_logstart = 0;
+       ei->i_attrs = 0;
+       ei->i_pos = 0;
+
        return &ei->vfs_inode;
 }
 
@@ -1374,16 +1381,6 @@ out:
        return 0;
 }
 
-static void fat_dummy_inode_init(struct inode *inode)
-{
-       /* Initialize this dummy inode to work as no-op. */
-       MSDOS_I(inode)->mmu_private = 0;
-       MSDOS_I(inode)->i_start = 0;
-       MSDOS_I(inode)->i_logstart = 0;
-       MSDOS_I(inode)->i_attrs = 0;
-       MSDOS_I(inode)->i_pos = 0;
-}
-
 static int fat_read_root(struct inode *inode)
 {
        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
@@ -1844,13 +1841,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
        fat_inode = new_inode(sb);
        if (!fat_inode)
                goto out_fail;
-       fat_dummy_inode_init(fat_inode);
        sbi->fat_inode = fat_inode;
 
        fsinfo_inode = new_inode(sb);
        if (!fsinfo_inode)
                goto out_fail;
-       fat_dummy_inode_init(fsinfo_inode);
        fsinfo_inode->i_ino = MSDOS_FSINFO_INO;
        sbi->fsinfo_inode = fsinfo_inode;
        insert_inode_hash(fsinfo_inode);
index 9bc1675..2e4c0fa 100644 (file)
@@ -735,8 +735,9 @@ static void send_sigio_to_task(struct task_struct *p,
                return;
 
        switch (signum) {
-               kernel_siginfo_t si;
-               default:
+               default: {
+                       kernel_siginfo_t si;
+
                        /* Queue a rt signal with the appropriate fd as its
                           value.  We use SI_SIGIO as the source, not 
                           SI_KERNEL, since kernel signals always get 
@@ -769,6 +770,7 @@ static void send_sigio_to_task(struct task_struct *p,
                        si.si_fd    = fd;
                        if (!do_send_sig_info(signum, &si, p, type))
                                break;
+               }
                /* fall-through - fall back on the old plain SIGIO signal */
                case 0:
                        do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, type);
index a364e1a..c8a4e4c 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -540,9 +540,14 @@ static int alloc_fd(unsigned start, unsigned flags)
        return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
 }
 
+int __get_unused_fd_flags(unsigned flags, unsigned long nofile)
+{
+       return __alloc_fd(current->files, 0, nofile, flags);
+}
+
 int get_unused_fd_flags(unsigned flags)
 {
-       return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
+       return __get_unused_fd_flags(flags, rlimit(RLIMIT_NOFILE));
 }
 EXPORT_SYMBOL(get_unused_fd_flags);
 
index 8e02d76..97eec75 100644 (file)
@@ -276,12 +276,10 @@ static void flush_bg_queue(struct fuse_conn *fc)
 void fuse_request_end(struct fuse_conn *fc, struct fuse_req *req)
 {
        struct fuse_iqueue *fiq = &fc->iq;
-       bool async;
 
        if (test_and_set_bit(FR_FINISHED, &req->flags))
                goto put_request;
 
-       async = req->args->end;
        /*
         * test_and_set_bit() implies smp_mb() between bit
         * changing and below intr_entry check. Pairs with
@@ -324,7 +322,7 @@ void fuse_request_end(struct fuse_conn *fc, struct fuse_req *req)
                wake_up(&req->waitq);
        }
 
-       if (async)
+       if (test_bit(FR_ASYNC, &req->flags))
                req->args->end(fc, req->args, req->out.h.error);
 put_request:
        fuse_put_request(fc, req);
@@ -471,6 +469,8 @@ static void fuse_args_to_req(struct fuse_req *req, struct fuse_args *args)
        req->in.h.opcode = args->opcode;
        req->in.h.nodeid = args->nodeid;
        req->args = args;
+       if (args->end)
+               __set_bit(FR_ASYNC, &req->flags);
 }
 
 ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
index aa75e23..ca344bf 100644 (file)
@@ -301,6 +301,7 @@ struct fuse_io_priv {
  * FR_SENT:            request is in userspace, waiting for an answer
  * FR_FINISHED:                request is finished
  * FR_PRIVATE:         request is on private list
+ * FR_ASYNC:           request is asynchronous
  */
 enum fuse_req_flag {
        FR_ISREPLY,
@@ -314,6 +315,7 @@ enum fuse_req_flag {
        FR_SENT,
        FR_FINISHED,
        FR_PRIVATE,
+       FR_ASYNC,
 };
 
 /**
index 2716d56..8294851 100644 (file)
@@ -1248,7 +1248,7 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
                if (!(file->f_mode & FMODE_OPENED))
                        return finish_no_open(file, d);
                dput(d);
-               return 0;
+               return excl && (flags & O_CREAT) ? -EEXIST : 0;
        }
 
        BUG_ON(d != NULL);
index 7d57068..93d9252 100644 (file)
@@ -138,6 +138,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
        inode->i_sb = sb;
        inode->i_blkbits = sb->s_blocksize_bits;
        inode->i_flags = 0;
+       atomic64_set(&inode->i_sequence, 0);
        atomic_set(&inode->i_count, 1);
        inode->i_op = &empty_iops;
        inode->i_fop = &no_open_fops;
index f3f280b..4d37912 100644 (file)
@@ -38,7 +38,6 @@ static inline int __sync_blockdev(struct block_device *bdev, int wait)
 /*
  * buffer.c
  */
-extern void guard_bio_eod(struct bio *bio);
 extern int __block_write_begin_int(struct page *page, loff_t pos, unsigned len,
                get_block_t *get_block, struct iomap *iomap);
 
index 0a5ab1a..cc5cf22 100644 (file)
@@ -69,6 +69,8 @@ struct io_worker {
 #define IO_WQ_HASH_ORDER       5
 #endif
 
+#define IO_WQ_NR_HASH_BUCKETS  (1u << IO_WQ_HASH_ORDER)
+
 struct io_wqe_acct {
        unsigned nr_workers;
        unsigned max_workers;
@@ -98,6 +100,7 @@ struct io_wqe {
        struct list_head all_list;
 
        struct io_wq *wq;
+       struct io_wq_work *hash_tail[IO_WQ_NR_HASH_BUCKETS];
 };
 
 /*
@@ -107,8 +110,7 @@ struct io_wq {
        struct io_wqe **wqes;
        unsigned long state;
 
-       get_work_fn *get_work;
-       put_work_fn *put_work;
+       free_work_fn *free_work;
 
        struct task_struct *manager;
        struct user_struct *user;
@@ -376,26 +378,35 @@ static bool __io_worker_idle(struct io_wqe *wqe, struct io_worker *worker)
        return __io_worker_unuse(wqe, worker);
 }
 
-static struct io_wq_work *io_get_next_work(struct io_wqe *wqe, unsigned *hash)
+static inline unsigned int io_get_work_hash(struct io_wq_work *work)
+{
+       return work->flags >> IO_WQ_HASH_SHIFT;
+}
+
+static struct io_wq_work *io_get_next_work(struct io_wqe *wqe)
        __must_hold(wqe->lock)
 {
        struct io_wq_work_node *node, *prev;
-       struct io_wq_work *work;
+       struct io_wq_work *work, *tail;
+       unsigned int hash;
 
        wq_list_for_each(node, prev, &wqe->work_list) {
                work = container_of(node, struct io_wq_work, list);
 
                /* not hashed, can run anytime */
-               if (!(work->flags & IO_WQ_WORK_HASHED)) {
-                       wq_node_del(&wqe->work_list, node, prev);
+               if (!io_wq_is_hashed(work)) {
+                       wq_list_del(&wqe->work_list, node, prev);
                        return work;
                }
 
                /* hashed, can run if not already running */
-               *hash = work->flags >> IO_WQ_HASH_SHIFT;
-               if (!(wqe->hash_map & BIT_ULL(*hash))) {
-                       wqe->hash_map |= BIT_ULL(*hash);
-                       wq_node_del(&wqe->work_list, node, prev);
+               hash = io_get_work_hash(work);
+               if (!(wqe->hash_map & BIT(hash))) {
+                       wqe->hash_map |= BIT(hash);
+                       /* all items with this hash lie in [work, tail] */
+                       tail = wqe->hash_tail[hash];
+                       wqe->hash_tail[hash] = NULL;
+                       wq_list_cut(&wqe->work_list, &tail->list, prev);
                        return work;
                }
        }
@@ -440,16 +451,49 @@ static void io_wq_switch_creds(struct io_worker *worker,
                worker->saved_creds = old_creds;
 }
 
+static void io_impersonate_work(struct io_worker *worker,
+                               struct io_wq_work *work)
+{
+       if (work->files && current->files != work->files) {
+               task_lock(current);
+               current->files = work->files;
+               task_unlock(current);
+       }
+       if (work->fs && current->fs != work->fs)
+               current->fs = work->fs;
+       if (work->mm != worker->mm)
+               io_wq_switch_mm(worker, work);
+       if (worker->cur_creds != work->creds)
+               io_wq_switch_creds(worker, work);
+}
+
+static void io_assign_current_work(struct io_worker *worker,
+                                  struct io_wq_work *work)
+{
+       if (work) {
+               /* flush pending signals before assigning new work */
+               if (signal_pending(current))
+                       flush_signals(current);
+               cond_resched();
+       }
+
+       spin_lock_irq(&worker->lock);
+       worker->cur_work = work;
+       spin_unlock_irq(&worker->lock);
+}
+
+static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work);
+
 static void io_worker_handle_work(struct io_worker *worker)
        __releases(wqe->lock)
 {
-       struct io_wq_work *work, *old_work = NULL, *put_work = NULL;
        struct io_wqe *wqe = worker->wqe;
        struct io_wq *wq = wqe->wq;
 
        do {
-               unsigned hash = -1U;
-
+               struct io_wq_work *work;
+               unsigned int hash;
+get_next:
                /*
                 * If we got some work, mark us as busy. If we didn't, but
                 * the list isn't empty, it means we stalled on hashed work.
@@ -457,120 +501,80 @@ static void io_worker_handle_work(struct io_worker *worker)
                 * can't make progress, any work completion or insertion will
                 * clear the stalled flag.
                 */
-               work = io_get_next_work(wqe, &hash);
+               work = io_get_next_work(wqe);
                if (work)
                        __io_worker_busy(wqe, worker, work);
                else if (!wq_list_empty(&wqe->work_list))
                        wqe->flags |= IO_WQE_FLAG_STALLED;
 
                spin_unlock_irq(&wqe->lock);
-               if (put_work && wq->put_work)
-                       wq->put_work(old_work);
                if (!work)
                        break;
-next:
-               /* flush any pending signals before assigning new work */
-               if (signal_pending(current))
-                       flush_signals(current);
-
-               cond_resched();
-
-               spin_lock_irq(&worker->lock);
-               worker->cur_work = work;
-               spin_unlock_irq(&worker->lock);
-
-               if (work->flags & IO_WQ_WORK_CB)
-                       work->func(&work);
-
-               if (work->files && current->files != work->files) {
-                       task_lock(current);
-                       current->files = work->files;
-                       task_unlock(current);
-               }
-               if (work->fs && current->fs != work->fs)
-                       current->fs = work->fs;
-               if (work->mm != worker->mm)
-                       io_wq_switch_mm(worker, work);
-               if (worker->cur_creds != work->creds)
-                       io_wq_switch_creds(worker, work);
-               /*
-                * OK to set IO_WQ_WORK_CANCEL even for uncancellable work,
-                * the worker function will do the right thing.
-                */
-               if (test_bit(IO_WQ_BIT_CANCEL, &wq->state))
-                       work->flags |= IO_WQ_WORK_CANCEL;
-               if (worker->mm)
-                       work->flags |= IO_WQ_WORK_HAS_MM;
-
-               if (wq->get_work && !(work->flags & IO_WQ_WORK_INTERNAL)) {
-                       put_work = work;
-                       wq->get_work(work);
-               }
-
-               old_work = work;
-               work->func(&work);
-
-               spin_lock_irq(&worker->lock);
-               worker->cur_work = NULL;
-               spin_unlock_irq(&worker->lock);
-
-               spin_lock_irq(&wqe->lock);
-
-               if (hash != -1U) {
-                       wqe->hash_map &= ~BIT_ULL(hash);
-                       wqe->flags &= ~IO_WQE_FLAG_STALLED;
-               }
-               if (work && work != old_work) {
-                       spin_unlock_irq(&wqe->lock);
-
-                       if (put_work && wq->put_work) {
-                               wq->put_work(put_work);
-                               put_work = NULL;
+               io_assign_current_work(worker, work);
+
+               /* handle a whole dependent link */
+               do {
+                       struct io_wq_work *old_work, *next_hashed, *linked;
+
+                       next_hashed = wq_next_work(work);
+                       io_impersonate_work(worker, work);
+                       /*
+                        * OK to set IO_WQ_WORK_CANCEL even for uncancellable
+                        * work, the worker function will do the right thing.
+                        */
+                       if (test_bit(IO_WQ_BIT_CANCEL, &wq->state))
+                               work->flags |= IO_WQ_WORK_CANCEL;
+
+                       hash = io_get_work_hash(work);
+                       linked = old_work = work;
+                       linked->func(&linked);
+                       linked = (old_work == linked) ? NULL : linked;
+
+                       work = next_hashed;
+                       if (!work && linked && !io_wq_is_hashed(linked)) {
+                               work = linked;
+                               linked = NULL;
                        }
+                       io_assign_current_work(worker, work);
+                       wq->free_work(old_work);
+
+                       if (linked)
+                               io_wqe_enqueue(wqe, linked);
+
+                       if (hash != -1U && !next_hashed) {
+                               spin_lock_irq(&wqe->lock);
+                               wqe->hash_map &= ~BIT_ULL(hash);
+                               wqe->flags &= ~IO_WQE_FLAG_STALLED;
+                               /* dependent work is not hashed */
+                               hash = -1U;
+                               /* skip unnecessary unlock-lock wqe->lock */
+                               if (!work)
+                                       goto get_next;
+                               spin_unlock_irq(&wqe->lock);
+                       }
+               } while (work);
 
-                       /* dependent work not hashed */
-                       hash = -1U;
-                       goto next;
-               }
+               spin_lock_irq(&wqe->lock);
        } while (1);
 }
 
-static inline void io_worker_spin_for_work(struct io_wqe *wqe)
-{
-       int i = 0;
-
-       while (++i < 1000) {
-               if (io_wqe_run_queue(wqe))
-                       break;
-               if (need_resched())
-                       break;
-               cpu_relax();
-       }
-}
-
 static int io_wqe_worker(void *data)
 {
        struct io_worker *worker = data;
        struct io_wqe *wqe = worker->wqe;
        struct io_wq *wq = wqe->wq;
-       bool did_work;
 
        io_worker_start(wqe, worker);
 
-       did_work = false;
        while (!test_bit(IO_WQ_BIT_EXIT, &wq->state)) {
                set_current_state(TASK_INTERRUPTIBLE);
 loop:
-               if (did_work)
-                       io_worker_spin_for_work(wqe);
                spin_lock_irq(&wqe->lock);
                if (io_wqe_run_queue(wqe)) {
                        __set_current_state(TASK_RUNNING);
                        io_worker_handle_work(worker);
-                       did_work = true;
                        goto loop;
                }
-               did_work = false;
                /* drops the lock on success, retry */
                if (__io_worker_idle(wqe, worker)) {
                        __release(&wqe->lock);
@@ -766,6 +770,40 @@ static bool io_wq_can_queue(struct io_wqe *wqe, struct io_wqe_acct *acct,
        return true;
 }
 
+static void io_run_cancel(struct io_wq_work *work, struct io_wqe *wqe)
+{
+       struct io_wq *wq = wqe->wq;
+
+       do {
+               struct io_wq_work *old_work = work;
+
+               work->flags |= IO_WQ_WORK_CANCEL;
+               work->func(&work);
+               work = (work == old_work) ? NULL : work;
+               wq->free_work(old_work);
+       } while (work);
+}
+
+static void io_wqe_insert_work(struct io_wqe *wqe, struct io_wq_work *work)
+{
+       unsigned int hash;
+       struct io_wq_work *tail;
+
+       if (!io_wq_is_hashed(work)) {
+append:
+               wq_list_add_tail(&work->list, &wqe->work_list);
+               return;
+       }
+
+       hash = io_get_work_hash(work);
+       tail = wqe->hash_tail[hash];
+       wqe->hash_tail[hash] = work;
+       if (!tail)
+               goto append;
+
+       wq_list_add_after(&work->list, &tail->list, &wqe->work_list);
+}
+
 static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work)
 {
        struct io_wqe_acct *acct = io_work_get_acct(wqe, work);
@@ -779,14 +817,13 @@ static void io_wqe_enqueue(struct io_wqe *wqe, struct io_wq_work *work)
         * It's close enough to not be an issue, fork() has the same delay.
         */
        if (unlikely(!io_wq_can_queue(wqe, acct, work))) {
-               work->flags |= IO_WQ_WORK_CANCEL;
-               work->func(&work);
+               io_run_cancel(work, wqe);
                return;
        }
 
        work_flags = work->flags;
        spin_lock_irqsave(&wqe->lock, flags);
-       wq_list_add_tail(&work->list, &wqe->work_list);
+       io_wqe_insert_work(wqe, work);
        wqe->flags &= ~IO_WQE_FLAG_STALLED;
        spin_unlock_irqrestore(&wqe->lock, flags);
 
@@ -803,19 +840,15 @@ void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work)
 }
 
 /*
- * Enqueue work, hashed by some key. Work items that hash to the same value
- * will not be done in parallel. Used to limit concurrent writes, generally
- * hashed by inode.
+ * Work items that hash to the same value will not be done in parallel.
+ * Used to limit concurrent writes, generally hashed by inode.
  */
-void io_wq_enqueue_hashed(struct io_wq *wq, struct io_wq_work *work, void *val)
+void io_wq_hash_work(struct io_wq_work *work, void *val)
 {
-       struct io_wqe *wqe = wq->wqes[numa_node_id()];
-       unsigned bit;
-
+       unsigned int bit;
 
        bit = hash_ptr(val, IO_WQ_HASH_ORDER);
        work->flags |= (IO_WQ_WORK_HASHED | (bit << IO_WQ_HASH_SHIFT));
-       io_wqe_enqueue(wqe, work);
 }
 
 static bool io_wqe_worker_send_sig(struct io_worker *worker, void *data)
@@ -865,14 +898,13 @@ void io_wq_cancel_all(struct io_wq *wq)
 }
 
 struct io_cb_cancel_data {
-       struct io_wqe *wqe;
-       work_cancel_fn *cancel;
-       void *caller_data;
+       work_cancel_fn *fn;
+       void *data;
 };
 
-static bool io_work_cancel(struct io_worker *worker, void *cancel_data)
+static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
 {
-       struct io_cb_cancel_data *data = cancel_data;
+       struct io_cb_cancel_data *match = data;
        unsigned long flags;
        bool ret = false;
 
@@ -883,84 +915,7 @@ static bool io_work_cancel(struct io_worker *worker, void *cancel_data)
        spin_lock_irqsave(&worker->lock, flags);
        if (worker->cur_work &&
            !(worker->cur_work->flags & IO_WQ_WORK_NO_CANCEL) &&
-           data->cancel(worker->cur_work, data->caller_data)) {
-               send_sig(SIGINT, worker->task, 1);
-               ret = true;
-       }
-       spin_unlock_irqrestore(&worker->lock, flags);
-
-       return ret;
-}
-
-static enum io_wq_cancel io_wqe_cancel_cb_work(struct io_wqe *wqe,
-                                              work_cancel_fn *cancel,
-                                              void *cancel_data)
-{
-       struct io_cb_cancel_data data = {
-               .wqe = wqe,
-               .cancel = cancel,
-               .caller_data = cancel_data,
-       };
-       struct io_wq_work_node *node, *prev;
-       struct io_wq_work *work;
-       unsigned long flags;
-       bool found = false;
-
-       spin_lock_irqsave(&wqe->lock, flags);
-       wq_list_for_each(node, prev, &wqe->work_list) {
-               work = container_of(node, struct io_wq_work, list);
-
-               if (cancel(work, cancel_data)) {
-                       wq_node_del(&wqe->work_list, node, prev);
-                       found = true;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&wqe->lock, flags);
-
-       if (found) {
-               work->flags |= IO_WQ_WORK_CANCEL;
-               work->func(&work);
-               return IO_WQ_CANCEL_OK;
-       }
-
-       rcu_read_lock();
-       found = io_wq_for_each_worker(wqe, io_work_cancel, &data);
-       rcu_read_unlock();
-       return found ? IO_WQ_CANCEL_RUNNING : IO_WQ_CANCEL_NOTFOUND;
-}
-
-enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel,
-                                 void *data)
-{
-       enum io_wq_cancel ret = IO_WQ_CANCEL_NOTFOUND;
-       int node;
-
-       for_each_node(node) {
-               struct io_wqe *wqe = wq->wqes[node];
-
-               ret = io_wqe_cancel_cb_work(wqe, cancel, data);
-               if (ret != IO_WQ_CANCEL_NOTFOUND)
-                       break;
-       }
-
-       return ret;
-}
-
-struct work_match {
-       bool (*fn)(struct io_wq_work *, void *data);
-       void *data;
-};
-
-static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
-{
-       struct work_match *match = data;
-       unsigned long flags;
-       bool ret = false;
-
-       spin_lock_irqsave(&worker->lock, flags);
-       if (match->fn(worker->cur_work, match->data) &&
-           !(worker->cur_work->flags & IO_WQ_WORK_NO_CANCEL)) {
+           match->fn(worker->cur_work, match->data)) {
                send_sig(SIGINT, worker->task, 1);
                ret = true;
        }
@@ -970,7 +925,7 @@ static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
 }
 
 static enum io_wq_cancel io_wqe_cancel_work(struct io_wqe *wqe,
-                                           struct work_match *match)
+                                           struct io_cb_cancel_data *match)
 {
        struct io_wq_work_node *node, *prev;
        struct io_wq_work *work;
@@ -987,7 +942,7 @@ static enum io_wq_cancel io_wqe_cancel_work(struct io_wqe *wqe,
                work = container_of(node, struct io_wq_work, list);
 
                if (match->fn(work, match->data)) {
-                       wq_node_del(&wqe->work_list, node, prev);
+                       wq_list_del(&wqe->work_list, node, prev);
                        found = true;
                        break;
                }
@@ -995,8 +950,7 @@ static enum io_wq_cancel io_wqe_cancel_work(struct io_wqe *wqe,
        spin_unlock_irqrestore(&wqe->lock, flags);
 
        if (found) {
-               work->flags |= IO_WQ_WORK_CANCEL;
-               work->func(&work);
+               io_run_cancel(work, wqe);
                return IO_WQ_CANCEL_OK;
        }
 
@@ -1012,22 +966,16 @@ static enum io_wq_cancel io_wqe_cancel_work(struct io_wqe *wqe,
        return found ? IO_WQ_CANCEL_RUNNING : IO_WQ_CANCEL_NOTFOUND;
 }
 
-static bool io_wq_work_match(struct io_wq_work *work, void *data)
-{
-       return work == data;
-}
-
-enum io_wq_cancel io_wq_cancel_work(struct io_wq *wq, struct io_wq_work *cwork)
+enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel,
+                                 void *data)
 {
-       struct work_match match = {
-               .fn     = io_wq_work_match,
-               .data   = cwork
+       struct io_cb_cancel_data match = {
+               .fn     = cancel,
+               .data   = data,
        };
        enum io_wq_cancel ret = IO_WQ_CANCEL_NOTFOUND;
        int node;
 
-       cwork->flags |= IO_WQ_WORK_CANCEL;
-
        for_each_node(node) {
                struct io_wqe *wqe = wq->wqes[node];
 
@@ -1039,69 +987,28 @@ enum io_wq_cancel io_wq_cancel_work(struct io_wq *wq, struct io_wq_work *cwork)
        return ret;
 }
 
-static bool io_wq_pid_match(struct io_wq_work *work, void *data)
+static bool io_wq_io_cb_cancel_data(struct io_wq_work *work, void *data)
 {
-       pid_t pid = (pid_t) (unsigned long) data;
-
-       if (work)
-               return work->task_pid == pid;
-       return false;
+       return work == data;
 }
 
-enum io_wq_cancel io_wq_cancel_pid(struct io_wq *wq, pid_t pid)
+enum io_wq_cancel io_wq_cancel_work(struct io_wq *wq, struct io_wq_work *cwork)
 {
-       struct work_match match = {
-               .fn     = io_wq_pid_match,
-               .data   = (void *) (unsigned long) pid
-       };
-       enum io_wq_cancel ret = IO_WQ_CANCEL_NOTFOUND;
-       int node;
-
-       for_each_node(node) {
-               struct io_wqe *wqe = wq->wqes[node];
-
-               ret = io_wqe_cancel_work(wqe, &match);
-               if (ret != IO_WQ_CANCEL_NOTFOUND)
-                       break;
-       }
-
-       return ret;
+       return io_wq_cancel_cb(wq, io_wq_io_cb_cancel_data, (void *)cwork);
 }
 
-struct io_wq_flush_data {
-       struct io_wq_work work;
-       struct completion done;
-};
-
-static void io_wq_flush_func(struct io_wq_work **workptr)
+static bool io_wq_pid_match(struct io_wq_work *work, void *data)
 {
-       struct io_wq_work *work = *workptr;
-       struct io_wq_flush_data *data;
+       pid_t pid = (pid_t) (unsigned long) data;
 
-       data = container_of(work, struct io_wq_flush_data, work);
-       complete(&data->done);
+       return work->task_pid == pid;
 }
 
-/*
- * Doesn't wait for previously queued work to finish. When this completes,
- * it just means that previously queued work was started.
- */
-void io_wq_flush(struct io_wq *wq)
+enum io_wq_cancel io_wq_cancel_pid(struct io_wq *wq, pid_t pid)
 {
-       struct io_wq_flush_data data;
-       int node;
+       void *data = (void *) (unsigned long) pid;
 
-       for_each_node(node) {
-               struct io_wqe *wqe = wq->wqes[node];
-
-               if (!node_online(node))
-                       continue;
-               init_completion(&data.done);
-               INIT_IO_WORK(&data.work, io_wq_flush_func);
-               data.work.flags |= IO_WQ_WORK_INTERNAL;
-               io_wqe_enqueue(wqe, &data.work);
-               wait_for_completion(&data.done);
-       }
+       return io_wq_cancel_cb(wq, io_wq_pid_match, data);
 }
 
 struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
@@ -1109,6 +1016,9 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
        int ret = -ENOMEM, node;
        struct io_wq *wq;
 
+       if (WARN_ON_ONCE(!data->free_work))
+               return ERR_PTR(-EINVAL);
+
        wq = kzalloc(sizeof(*wq), GFP_KERNEL);
        if (!wq)
                return ERR_PTR(-ENOMEM);
@@ -1119,8 +1029,7 @@ struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data)
                return ERR_PTR(-ENOMEM);
        }
 
-       wq->get_work = data->get_work;
-       wq->put_work = data->put_work;
+       wq->free_work = data->free_work;
 
        /* caller must already hold a reference to this */
        wq->user = data->user;
@@ -1177,7 +1086,7 @@ err:
 
 bool io_wq_get(struct io_wq *wq, struct io_wq_data *data)
 {
-       if (data->get_work != wq->get_work || data->put_work != wq->put_work)
+       if (data->free_work != wq->free_work)
                return false;
 
        return refcount_inc_not_zero(&wq->use_refs);
index ccc7d84..3ee7356 100644 (file)
@@ -5,11 +5,8 @@ struct io_wq;
 
 enum {
        IO_WQ_WORK_CANCEL       = 1,
-       IO_WQ_WORK_HAS_MM       = 2,
        IO_WQ_WORK_HASHED       = 4,
        IO_WQ_WORK_UNBOUND      = 32,
-       IO_WQ_WORK_INTERNAL     = 64,
-       IO_WQ_WORK_CB           = 128,
        IO_WQ_WORK_NO_CANCEL    = 256,
        IO_WQ_WORK_CONCURRENT   = 512,
 
@@ -31,6 +28,18 @@ struct io_wq_work_list {
        struct io_wq_work_node *last;
 };
 
+static inline void wq_list_add_after(struct io_wq_work_node *node,
+                                    struct io_wq_work_node *pos,
+                                    struct io_wq_work_list *list)
+{
+       struct io_wq_work_node *next = pos->next;
+
+       pos->next = node;
+       node->next = next;
+       if (!next)
+               list->last = node;
+}
+
 static inline void wq_list_add_tail(struct io_wq_work_node *node,
                                    struct io_wq_work_list *list)
 {
@@ -43,17 +52,26 @@ static inline void wq_list_add_tail(struct io_wq_work_node *node,
        }
 }
 
-static inline void wq_node_del(struct io_wq_work_list *list,
-                              struct io_wq_work_node *node,
+static inline void wq_list_cut(struct io_wq_work_list *list,
+                              struct io_wq_work_node *last,
                               struct io_wq_work_node *prev)
 {
-       if (node == list->first)
-               WRITE_ONCE(list->first, node->next);
-       if (node == list->last)
+       /* first in the list, if prev==NULL */
+       if (!prev)
+               WRITE_ONCE(list->first, last->next);
+       else
+               prev->next = last->next;
+
+       if (last == list->last)
                list->last = prev;
-       if (prev)
-               prev->next = node->next;
-       node->next = NULL;
+       last->next = NULL;
+}
+
+static inline void wq_list_del(struct io_wq_work_list *list,
+                              struct io_wq_work_node *node,
+                              struct io_wq_work_node *prev)
+{
+       wq_list_cut(list, node, prev);
 }
 
 #define wq_list_for_each(pos, prv, head)                       \
@@ -66,10 +84,7 @@ static inline void wq_node_del(struct io_wq_work_list *list,
 } while (0)
 
 struct io_wq_work {
-       union {
-               struct io_wq_work_node list;
-               void *data;
-       };
+       struct io_wq_work_node list;
        void (*func)(struct io_wq_work **);
        struct files_struct *files;
        struct mm_struct *mm;
@@ -79,25 +94,25 @@ struct io_wq_work {
        pid_t task_pid;
 };
 
-#define INIT_IO_WORK(work, _func)                      \
-       do {                                            \
-               (work)->list.next = NULL;               \
-               (work)->func = _func;                   \
-               (work)->files = NULL;                   \
-               (work)->mm = NULL;                      \
-               (work)->creds = NULL;                   \
-               (work)->fs = NULL;                      \
-               (work)->flags = 0;                      \
-       } while (0)                                     \
+#define INIT_IO_WORK(work, _func)                              \
+       do {                                                    \
+               *(work) = (struct io_wq_work){ .func = _func }; \
+       } while (0)                                             \
 
-typedef void (get_work_fn)(struct io_wq_work *);
-typedef void (put_work_fn)(struct io_wq_work *);
+static inline struct io_wq_work *wq_next_work(struct io_wq_work *work)
+{
+       if (!work->list.next)
+               return NULL;
+
+       return container_of(work->list.next, struct io_wq_work, list);
+}
+
+typedef void (free_work_fn)(struct io_wq_work *);
 
 struct io_wq_data {
        struct user_struct *user;
 
-       get_work_fn *get_work;
-       put_work_fn *put_work;
+       free_work_fn *free_work;
 };
 
 struct io_wq *io_wq_create(unsigned bounded, struct io_wq_data *data);
@@ -105,8 +120,12 @@ bool io_wq_get(struct io_wq *wq, struct io_wq_data *data);
 void io_wq_destroy(struct io_wq *wq);
 
 void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work);
-void io_wq_enqueue_hashed(struct io_wq *wq, struct io_wq_work *work, void *val);
-void io_wq_flush(struct io_wq *wq);
+void io_wq_hash_work(struct io_wq_work *work, void *val);
+
+static inline bool io_wq_is_hashed(struct io_wq_work *work)
+{
+       return work->flags & IO_WQ_WORK_HASHED;
+}
 
 void io_wq_cancel_all(struct io_wq *wq);
 enum io_wq_cancel io_wq_cancel_work(struct io_wq *wq, struct io_wq_work *cwork);
index de650df..358f97b 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/errno.h>
 #include <linux/syscalls.h>
 #include <linux/compat.h>
+#include <net/compat.h>
 #include <linux/refcount.h>
 #include <linux/uio.h>
 #include <linux/bits.h>
@@ -76,6 +77,8 @@
 #include <linux/fadvise.h>
 #include <linux/eventpoll.h>
 #include <linux/fs_struct.h>
+#include <linux/splice.h>
+#include <linux/task_work.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/io_uring.h>
@@ -183,21 +186,23 @@ struct fixed_file_table {
        struct file             **files;
 };
 
-enum {
-       FFD_F_ATOMIC,
-};
-
 struct fixed_file_data {
        struct fixed_file_table         *table;
        struct io_ring_ctx              *ctx;
 
        struct percpu_ref               refs;
        struct llist_head               put_llist;
-       unsigned long                   state;
        struct work_struct              ref_work;
        struct completion               done;
 };
 
+struct io_buffer {
+       struct list_head list;
+       __u64 addr;
+       __s32 len;
+       __u16 bid;
+};
+
 struct io_ring_ctx {
        struct {
                struct percpu_ref       refs;
@@ -275,6 +280,8 @@ struct io_ring_ctx {
        struct socket           *ring_sock;
 #endif
 
+       struct idr              io_buffer_idr;
+
        struct idr              personality_idr;
 
        struct {
@@ -295,7 +302,6 @@ struct io_ring_ctx {
 
        struct {
                spinlock_t              completion_lock;
-               struct llist_head       poll_llist;
 
                /*
                 * ->poll_list is protected by the ctx->uring_lock for
@@ -348,6 +354,7 @@ struct io_accept {
        struct sockaddr __user          *addr;
        int __user                      *addr_len;
        int                             flags;
+       unsigned long                   nofile;
 };
 
 struct io_sync {
@@ -390,7 +397,9 @@ struct io_sr_msg {
                void __user             *buf;
        };
        int                             msg_flags;
+       int                             bgid;
        size_t                          len;
+       struct io_buffer                *kbuf;
 };
 
 struct io_open {
@@ -402,6 +411,7 @@ struct io_open {
        struct filename                 *filename;
        struct statx __user             *buffer;
        struct open_how                 how;
+       unsigned long                   nofile;
 };
 
 struct io_files_update {
@@ -433,6 +443,24 @@ struct io_epoll {
        struct epoll_event              event;
 };
 
+struct io_splice {
+       struct file                     *file_out;
+       struct file                     *file_in;
+       loff_t                          off_out;
+       loff_t                          off_in;
+       u64                             len;
+       unsigned int                    flags;
+};
+
+struct io_provide_buf {
+       struct file                     *file;
+       __u64                           addr;
+       __s32                           len;
+       __u32                           bgid;
+       __u16                           nbufs;
+       __u16                           bid;
+};
+
 struct io_async_connect {
        struct sockaddr_storage         address;
 };
@@ -467,6 +495,7 @@ enum {
        REQ_F_LINK_BIT          = IOSQE_IO_LINK_BIT,
        REQ_F_HARDLINK_BIT      = IOSQE_IO_HARDLINK_BIT,
        REQ_F_FORCE_ASYNC_BIT   = IOSQE_ASYNC_BIT,
+       REQ_F_BUFFER_SELECT_BIT = IOSQE_BUFFER_SELECT_BIT,
 
        REQ_F_LINK_NEXT_BIT,
        REQ_F_FAIL_LINK_BIT,
@@ -482,6 +511,11 @@ enum {
        REQ_F_COMP_LOCKED_BIT,
        REQ_F_NEED_CLEANUP_BIT,
        REQ_F_OVERFLOW_BIT,
+       REQ_F_POLLED_BIT,
+       REQ_F_BUFFER_SELECTED_BIT,
+
+       /* not a real bit, just to check we're not overflowing the space */
+       __REQ_F_LAST_BIT,
 };
 
 enum {
@@ -495,6 +529,8 @@ enum {
        REQ_F_HARDLINK          = BIT(REQ_F_HARDLINK_BIT),
        /* IOSQE_ASYNC */
        REQ_F_FORCE_ASYNC       = BIT(REQ_F_FORCE_ASYNC_BIT),
+       /* IOSQE_BUFFER_SELECT */
+       REQ_F_BUFFER_SELECT     = BIT(REQ_F_BUFFER_SELECT_BIT),
 
        /* already grabbed next link */
        REQ_F_LINK_NEXT         = BIT(REQ_F_LINK_NEXT_BIT),
@@ -524,6 +560,15 @@ enum {
        REQ_F_NEED_CLEANUP      = BIT(REQ_F_NEED_CLEANUP_BIT),
        /* in overflow list */
        REQ_F_OVERFLOW          = BIT(REQ_F_OVERFLOW_BIT),
+       /* already went through poll handler */
+       REQ_F_POLLED            = BIT(REQ_F_POLLED_BIT),
+       /* buffer already selected */
+       REQ_F_BUFFER_SELECTED   = BIT(REQ_F_BUFFER_SELECTED_BIT),
+};
+
+struct async_poll {
+       struct io_poll_iocb     poll;
+       struct io_wq_work       work;
 };
 
 /*
@@ -549,32 +594,45 @@ struct io_kiocb {
                struct io_fadvise       fadvise;
                struct io_madvise       madvise;
                struct io_epoll         epoll;
+               struct io_splice        splice;
+               struct io_provide_buf   pbuf;
        };
 
        struct io_async_ctx             *io;
-       /*
-        * llist_node is only used for poll deferred completions
-        */
-       struct llist_node               llist_node;
-       bool                            in_async;
        bool                            needs_fixed_file;
        u8                              opcode;
 
        struct io_ring_ctx      *ctx;
-       union {
-               struct list_head        list;
-               struct hlist_node       hash_node;
-       };
-       struct list_head        link_list;
+       struct list_head        list;
        unsigned int            flags;
        refcount_t              refs;
+       union {
+               struct task_struct      *task;
+               unsigned long           fsize;
+       };
        u64                     user_data;
        u32                     result;
        u32                     sequence;
 
+       struct list_head        link_list;
+
        struct list_head        inflight_entry;
 
-       struct io_wq_work       work;
+       union {
+               /*
+                * Only commands that never go async can use the below fields,
+                * obviously. Right now only IORING_OP_POLL_ADD uses them, and
+                * async armed poll handlers for regular commands. The latter
+                * restore the work, if needed.
+                */
+               struct {
+                       struct callback_head    task_work;
+                       struct hlist_node       hash_node;
+                       struct async_poll       *apoll;
+                       int                     cflags;
+               };
+               struct io_wq_work       work;
+       };
 };
 
 #define IO_PLUG_THRESHOLD              2
@@ -618,6 +676,11 @@ struct io_op_def {
        unsigned                file_table : 1;
        /* needs ->fs */
        unsigned                needs_fs : 1;
+       /* set if opcode supports polled "wait" */
+       unsigned                pollin : 1;
+       unsigned                pollout : 1;
+       /* op supports buffer selection */
+       unsigned                buffer_select : 1;
 };
 
 static const struct io_op_def io_op_defs[] = {
@@ -627,6 +690,8 @@ static const struct io_op_def io_op_defs[] = {
                .needs_mm               = 1,
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .buffer_select          = 1,
        },
        [IORING_OP_WRITEV] = {
                .async_ctx              = 1,
@@ -634,6 +699,7 @@ static const struct io_op_def io_op_defs[] = {
                .needs_file             = 1,
                .hash_reg_file          = 1,
                .unbound_nonreg_file    = 1,
+               .pollout                = 1,
        },
        [IORING_OP_FSYNC] = {
                .needs_file             = 1,
@@ -641,11 +707,13 @@ static const struct io_op_def io_op_defs[] = {
        [IORING_OP_READ_FIXED] = {
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
        },
        [IORING_OP_WRITE_FIXED] = {
                .needs_file             = 1,
                .hash_reg_file          = 1,
                .unbound_nonreg_file    = 1,
+               .pollout                = 1,
        },
        [IORING_OP_POLL_ADD] = {
                .needs_file             = 1,
@@ -661,6 +729,7 @@ static const struct io_op_def io_op_defs[] = {
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
                .needs_fs               = 1,
+               .pollout                = 1,
        },
        [IORING_OP_RECVMSG] = {
                .async_ctx              = 1,
@@ -668,6 +737,8 @@ static const struct io_op_def io_op_defs[] = {
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
                .needs_fs               = 1,
+               .pollin                 = 1,
+               .buffer_select          = 1,
        },
        [IORING_OP_TIMEOUT] = {
                .async_ctx              = 1,
@@ -679,6 +750,7 @@ static const struct io_op_def io_op_defs[] = {
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
                .file_table             = 1,
+               .pollin                 = 1,
        },
        [IORING_OP_ASYNC_CANCEL] = {},
        [IORING_OP_LINK_TIMEOUT] = {
@@ -690,6 +762,7 @@ static const struct io_op_def io_op_defs[] = {
                .needs_mm               = 1,
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
+               .pollout                = 1,
        },
        [IORING_OP_FALLOCATE] = {
                .needs_file             = 1,
@@ -718,11 +791,14 @@ static const struct io_op_def io_op_defs[] = {
                .needs_mm               = 1,
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .buffer_select          = 1,
        },
        [IORING_OP_WRITE] = {
                .needs_mm               = 1,
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
+               .pollout                = 1,
        },
        [IORING_OP_FADVISE] = {
                .needs_file             = 1,
@@ -734,11 +810,14 @@ static const struct io_op_def io_op_defs[] = {
                .needs_mm               = 1,
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
+               .pollout                = 1,
        },
        [IORING_OP_RECV] = {
                .needs_mm               = 1,
                .needs_file             = 1,
                .unbound_nonreg_file    = 1,
+               .pollin                 = 1,
+               .buffer_select          = 1,
        },
        [IORING_OP_OPENAT2] = {
                .needs_file             = 1,
@@ -750,6 +829,13 @@ static const struct io_op_def io_op_defs[] = {
                .unbound_nonreg_file    = 1,
                .file_table             = 1,
        },
+       [IORING_OP_SPLICE] = {
+               .needs_file             = 1,
+               .hash_reg_file          = 1,
+               .unbound_nonreg_file    = 1,
+       },
+       [IORING_OP_PROVIDE_BUFFERS] = {},
+       [IORING_OP_REMOVE_BUFFERS] = {},
 };
 
 static void io_wq_submit_work(struct io_wq_work **workptr);
@@ -764,6 +850,10 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
 static int io_grab_files(struct io_kiocb *req);
 static void io_ring_file_ref_flush(struct fixed_file_data *data);
 static void io_cleanup_req(struct io_kiocb *req);
+static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
+                      int fd, struct file **out_file, bool fixed);
+static void __io_queue_sqe(struct io_kiocb *req,
+                          const struct io_uring_sqe *sqe);
 
 static struct kmem_cache *req_cachep;
 
@@ -830,11 +920,11 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
        INIT_LIST_HEAD(&ctx->cq_overflow_list);
        init_completion(&ctx->completions[0]);
        init_completion(&ctx->completions[1]);
+       idr_init(&ctx->io_buffer_idr);
        idr_init(&ctx->personality_idr);
        mutex_init(&ctx->uring_lock);
        init_waitqueue_head(&ctx->wait);
        spin_lock_init(&ctx->completion_lock);
-       init_llist_head(&ctx->poll_llist);
        INIT_LIST_HEAD(&ctx->poll_list);
        INIT_LIST_HEAD(&ctx->defer_list);
        INIT_LIST_HEAD(&ctx->timeout_list);
@@ -955,15 +1045,14 @@ static inline void io_req_work_drop_env(struct io_kiocb *req)
        }
 }
 
-static inline bool io_prep_async_work(struct io_kiocb *req,
+static inline void io_prep_async_work(struct io_kiocb *req,
                                      struct io_kiocb **link)
 {
        const struct io_op_def *def = &io_op_defs[req->opcode];
-       bool do_hashed = false;
 
        if (req->flags & REQ_F_ISREG) {
                if (def->hash_reg_file)
-                       do_hashed = true;
+                       io_wq_hash_work(&req->work, file_inode(req->file));
        } else {
                if (def->unbound_nonreg_file)
                        req->work.flags |= IO_WQ_WORK_UNBOUND;
@@ -972,25 +1061,18 @@ static inline bool io_prep_async_work(struct io_kiocb *req,
        io_req_work_grab_env(req, def);
 
        *link = io_prep_linked_timeout(req);
-       return do_hashed;
 }
 
 static inline void io_queue_async_work(struct io_kiocb *req)
 {
        struct io_ring_ctx *ctx = req->ctx;
        struct io_kiocb *link;
-       bool do_hashed;
 
-       do_hashed = io_prep_async_work(req, &link);
+       io_prep_async_work(req, &link);
 
-       trace_io_uring_queue_async_work(ctx, do_hashed, req, &req->work,
-                                       req->flags);
-       if (!do_hashed) {
-               io_wq_enqueue(ctx->io_wq, &req->work);
-       } else {
-               io_wq_enqueue_hashed(ctx->io_wq, &req->work,
-                                       file_inode(req->file));
-       }
+       trace_io_uring_queue_async_work(ctx, io_wq_is_hashed(&req->work), req,
+                                       &req->work, req->flags);
+       io_wq_enqueue(ctx->io_wq, &req->work);
 
        if (link)
                io_queue_linked_timeout(link);
@@ -1004,6 +1086,7 @@ static void io_kill_timeout(struct io_kiocb *req)
        if (ret != -1) {
                atomic_inc(&req->ctx->cq_timeouts);
                list_del_init(&req->list);
+               req->flags |= REQ_F_COMP_LOCKED;
                io_cqring_fill_event(req, 0);
                io_put_req(req);
        }
@@ -1056,24 +1139,19 @@ static inline bool io_should_trigger_evfd(struct io_ring_ctx *ctx)
                return false;
        if (!ctx->eventfd_async)
                return true;
-       return io_wq_current_is_worker() || in_interrupt();
+       return io_wq_current_is_worker();
 }
 
-static void __io_cqring_ev_posted(struct io_ring_ctx *ctx, bool trigger_ev)
+static void io_cqring_ev_posted(struct io_ring_ctx *ctx)
 {
        if (waitqueue_active(&ctx->wait))
                wake_up(&ctx->wait);
        if (waitqueue_active(&ctx->sqo_wait))
                wake_up(&ctx->sqo_wait);
-       if (trigger_ev)
+       if (io_should_trigger_evfd(ctx))
                eventfd_signal(ctx->cq_ev_fd, 1);
 }
 
-static void io_cqring_ev_posted(struct io_ring_ctx *ctx)
-{
-       __io_cqring_ev_posted(ctx, io_should_trigger_evfd(ctx));
-}
-
 /* Returns true if there are no backlogged entries after the flush */
 static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
 {
@@ -1110,7 +1188,7 @@ static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
                if (cqe) {
                        WRITE_ONCE(cqe->user_data, req->user_data);
                        WRITE_ONCE(cqe->res, req->result);
-                       WRITE_ONCE(cqe->flags, 0);
+                       WRITE_ONCE(cqe->flags, req->cflags);
                } else {
                        WRITE_ONCE(ctx->rings->cq_overflow,
                                atomic_inc_return(&ctx->cached_cq_overflow));
@@ -1134,7 +1212,7 @@ static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
        return cqe != NULL;
 }
 
-static void io_cqring_fill_event(struct io_kiocb *req, long res)
+static void __io_cqring_fill_event(struct io_kiocb *req, long res, long cflags)
 {
        struct io_ring_ctx *ctx = req->ctx;
        struct io_uring_cqe *cqe;
@@ -1150,7 +1228,7 @@ static void io_cqring_fill_event(struct io_kiocb *req, long res)
        if (likely(cqe)) {
                WRITE_ONCE(cqe->user_data, req->user_data);
                WRITE_ONCE(cqe->res, res);
-               WRITE_ONCE(cqe->flags, 0);
+               WRITE_ONCE(cqe->flags, cflags);
        } else if (ctx->cq_overflow_flushed) {
                WRITE_ONCE(ctx->rings->cq_overflow,
                                atomic_inc_return(&ctx->cached_cq_overflow));
@@ -1162,23 +1240,34 @@ static void io_cqring_fill_event(struct io_kiocb *req, long res)
                req->flags |= REQ_F_OVERFLOW;
                refcount_inc(&req->refs);
                req->result = res;
+               req->cflags = cflags;
                list_add_tail(&req->list, &ctx->cq_overflow_list);
        }
 }
 
-static void io_cqring_add_event(struct io_kiocb *req, long res)
+static void io_cqring_fill_event(struct io_kiocb *req, long res)
+{
+       __io_cqring_fill_event(req, res, 0);
+}
+
+static void __io_cqring_add_event(struct io_kiocb *req, long res, long cflags)
 {
        struct io_ring_ctx *ctx = req->ctx;
        unsigned long flags;
 
        spin_lock_irqsave(&ctx->completion_lock, flags);
-       io_cqring_fill_event(req, res);
+       __io_cqring_fill_event(req, res, cflags);
        io_commit_cqring(ctx);
        spin_unlock_irqrestore(&ctx->completion_lock, flags);
 
        io_cqring_ev_posted(ctx);
 }
 
+static void io_cqring_add_event(struct io_kiocb *req, long res)
+{
+       __io_cqring_add_event(req, res, 0);
+}
+
 static inline bool io_is_fallback_req(struct io_kiocb *req)
 {
        return req == (struct io_kiocb *)
@@ -1248,6 +1337,15 @@ fallback:
        return NULL;
 }
 
+static inline void io_put_file(struct io_kiocb *req, struct file *file,
+                         bool fixed)
+{
+       if (fixed)
+               percpu_ref_put(&req->ctx->file_data->refs);
+       else
+               fput(file);
+}
+
 static void __io_req_do_free(struct io_kiocb *req)
 {
        if (likely(!io_is_fallback_req(req)))
@@ -1258,18 +1356,12 @@ static void __io_req_do_free(struct io_kiocb *req)
 
 static void __io_req_aux_free(struct io_kiocb *req)
 {
-       struct io_ring_ctx *ctx = req->ctx;
-
        if (req->flags & REQ_F_NEED_CLEANUP)
                io_cleanup_req(req);
 
        kfree(req->io);
-       if (req->file) {
-               if (req->flags & REQ_F_FIXED_FILE)
-                       percpu_ref_put(&ctx->file_data->refs);
-               else
-                       fput(req->file);
-       }
+       if (req->file)
+               io_put_file(req, req->file, (req->flags & REQ_F_FIXED_FILE));
 
        io_req_work_drop_env(req);
 }
@@ -1476,6 +1568,30 @@ static void io_free_req(struct io_kiocb *req)
                io_queue_async_work(nxt);
 }
 
+static void io_link_work_cb(struct io_wq_work **workptr)
+{
+       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
+       struct io_kiocb *link;
+
+       link = list_first_entry(&req->link_list, struct io_kiocb, link_list);
+       io_queue_linked_timeout(link);
+       io_wq_submit_work(workptr);
+}
+
+static void io_wq_assign_next(struct io_wq_work **workptr, struct io_kiocb *nxt)
+{
+       struct io_kiocb *link;
+       const struct io_op_def *def = &io_op_defs[nxt->opcode];
+
+       if ((nxt->flags & REQ_F_ISREG) && def->hash_reg_file)
+               io_wq_hash_work(&nxt->work, file_inode(nxt->file));
+
+       *workptr = &nxt->work;
+       link = io_prep_linked_timeout(nxt);
+       if (link)
+               nxt->work.func = io_link_work_cb;
+}
+
 /*
  * Drop reference to request, return next in chain (if there is one) if this
  * was the last reference to this request.
@@ -1483,10 +1599,10 @@ static void io_free_req(struct io_kiocb *req)
 __attribute__((nonnull))
 static void io_put_req_find_next(struct io_kiocb *req, struct io_kiocb **nxtptr)
 {
-       io_req_find_next(req, nxtptr);
-
-       if (refcount_dec_and_test(&req->refs))
+       if (refcount_dec_and_test(&req->refs)) {
+               io_req_find_next(req, nxtptr);
                __io_free_req(req);
+       }
 }
 
 static void io_put_req(struct io_kiocb *req)
@@ -1495,6 +1611,26 @@ static void io_put_req(struct io_kiocb *req)
                io_free_req(req);
 }
 
+static void io_steal_work(struct io_kiocb *req,
+                         struct io_wq_work **workptr)
+{
+       /*
+        * It's in an io-wq worker, so there always should be at least
+        * one reference, which will be dropped in io_put_work() just
+        * after the current handler returns.
+        *
+        * It also means, that if the counter dropped to 1, then there is
+        * no asynchronous users left, so it's safe to steal the next work.
+        */
+       if (refcount_read(&req->refs) == 1) {
+               struct io_kiocb *nxt = NULL;
+
+               io_req_find_next(req, &nxt);
+               if (nxt)
+                       io_wq_assign_next(workptr, nxt);
+       }
+}
+
 /*
  * Must only be used if we don't need to care about links, usually from
  * within the completion handling itself.
@@ -1556,6 +1692,19 @@ static inline bool io_req_multi_free(struct req_batch *rb, struct io_kiocb *req)
        return true;
 }
 
+static int io_put_kbuf(struct io_kiocb *req)
+{
+       struct io_buffer *kbuf;
+       int cflags;
+
+       kbuf = (struct io_buffer *) (unsigned long) req->rw.addr;
+       cflags = kbuf->bid << IORING_CQE_BUFFER_SHIFT;
+       cflags |= IORING_CQE_F_BUFFER;
+       req->rw.addr = 0;
+       kfree(kbuf);
+       return cflags;
+}
+
 /*
  * Find and free completed poll iocbs
  */
@@ -1567,10 +1716,15 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
 
        rb.to_free = rb.need_iter = 0;
        while (!list_empty(done)) {
+               int cflags = 0;
+
                req = list_first_entry(done, struct io_kiocb, list);
                list_del(&req->list);
 
-               io_cqring_fill_event(req, req->result);
+               if (req->flags & REQ_F_BUFFER_SELECTED)
+                       cflags = io_put_kbuf(req);
+
+               __io_cqring_fill_event(req, req->result, cflags);
                (*nr_events)++;
 
                if (refcount_dec_and_test(&req->refs) &&
@@ -1579,6 +1733,8 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,
        }
 
        io_commit_cqring(ctx);
+       if (ctx->flags & IORING_SETUP_SQPOLL)
+               io_cqring_ev_posted(ctx);
        io_free_req_many(ctx, &rb);
 }
 
@@ -1745,13 +1901,16 @@ static inline void req_set_fail_links(struct io_kiocb *req)
 static void io_complete_rw_common(struct kiocb *kiocb, long res)
 {
        struct io_kiocb *req = container_of(kiocb, struct io_kiocb, rw.kiocb);
+       int cflags = 0;
 
        if (kiocb->ki_flags & IOCB_WRITE)
                kiocb_end_write(req);
 
        if (res != req->result)
                req_set_fail_links(req);
-       io_cqring_add_event(req, res);
+       if (req->flags & REQ_F_BUFFER_SELECTED)
+               cflags = io_put_kbuf(req);
+       __io_cqring_add_event(req, res, cflags);
 }
 
 static void io_complete_rw(struct kiocb *kiocb, long res, long res2)
@@ -1762,17 +1921,6 @@ static void io_complete_rw(struct kiocb *kiocb, long res, long res2)
        io_put_req(req);
 }
 
-static struct io_kiocb *__io_complete_rw(struct kiocb *kiocb, long res)
-{
-       struct io_kiocb *req = container_of(kiocb, struct io_kiocb, rw.kiocb);
-       struct io_kiocb *nxt = NULL;
-
-       io_complete_rw_common(kiocb, res);
-       io_put_req_find_next(req, &nxt);
-
-       return nxt;
-}
-
 static void io_complete_rw_iopoll(struct kiocb *kiocb, long res, long res2)
 {
        struct io_kiocb *req = container_of(kiocb, struct io_kiocb, rw.kiocb);
@@ -1821,6 +1969,10 @@ static void io_iopoll_req_issued(struct io_kiocb *req)
                list_add(&req->list, &ctx->poll_list);
        else
                list_add_tail(&req->list, &ctx->poll_list);
+
+       if ((ctx->flags & IORING_SETUP_SQPOLL) &&
+           wq_has_sleeper(&ctx->sqo_wait))
+               wake_up(&ctx->sqo_wait);
 }
 
 static void io_file_put(struct io_submit_state *state)
@@ -1839,7 +1991,7 @@ static void io_file_put(struct io_submit_state *state)
  * assuming most submissions are for one file, or at least that each file
  * has more than one submission.
  */
-static struct file *io_file_get(struct io_submit_state *state, int fd)
+static struct file *__io_file_get(struct io_submit_state *state, int fd)
 {
        if (!state)
                return fget(fd);
@@ -1936,7 +2088,7 @@ static int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe,
 
        req->rw.addr = READ_ONCE(sqe->addr);
        req->rw.len = READ_ONCE(sqe->len);
-       /* we own ->private, reuse it for the buffer index */
+       /* we own ->private, reuse it for the buffer index  / buffer ID */
        req->rw.kiocb.private = (void *) (unsigned long)
                                        READ_ONCE(sqe->buf_index);
        return 0;
@@ -1963,15 +2115,14 @@ static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
        }
 }
 
-static void kiocb_done(struct kiocb *kiocb, ssize_t ret, struct io_kiocb **nxt,
-                      bool in_async)
+static void kiocb_done(struct kiocb *kiocb, ssize_t ret)
 {
        struct io_kiocb *req = container_of(kiocb, struct io_kiocb, rw.kiocb);
 
        if (req->flags & REQ_F_CUR_POS)
                req->file->f_pos = kiocb->ki_pos;
-       if (in_async && ret >= 0 && kiocb->ki_complete == io_complete_rw)
-               *nxt = __io_complete_rw(kiocb, ret);
+       if (ret >= 0 && kiocb->ki_complete == io_complete_rw)
+               io_complete_rw(kiocb, ret, 0);
        else
                io_rw_done(kiocb, ret);
 }
@@ -2050,11 +2201,147 @@ static ssize_t io_import_fixed(struct io_kiocb *req, int rw,
        return len;
 }
 
+static void io_ring_submit_unlock(struct io_ring_ctx *ctx, bool needs_lock)
+{
+       if (needs_lock)
+               mutex_unlock(&ctx->uring_lock);
+}
+
+static void io_ring_submit_lock(struct io_ring_ctx *ctx, bool needs_lock)
+{
+       /*
+        * "Normal" inline submissions always hold the uring_lock, since we
+        * grab it from the system call. Same is true for the SQPOLL offload.
+        * The only exception is when we've detached the request and issue it
+        * from an async worker thread, grab the lock for that case.
+        */
+       if (needs_lock)
+               mutex_lock(&ctx->uring_lock);
+}
+
+static struct io_buffer *io_buffer_select(struct io_kiocb *req, size_t *len,
+                                         int bgid, struct io_buffer *kbuf,
+                                         bool needs_lock)
+{
+       struct io_buffer *head;
+
+       if (req->flags & REQ_F_BUFFER_SELECTED)
+               return kbuf;
+
+       io_ring_submit_lock(req->ctx, needs_lock);
+
+       lockdep_assert_held(&req->ctx->uring_lock);
+
+       head = idr_find(&req->ctx->io_buffer_idr, bgid);
+       if (head) {
+               if (!list_empty(&head->list)) {
+                       kbuf = list_last_entry(&head->list, struct io_buffer,
+                                                       list);
+                       list_del(&kbuf->list);
+               } else {
+                       kbuf = head;
+                       idr_remove(&req->ctx->io_buffer_idr, bgid);
+               }
+               if (*len > kbuf->len)
+                       *len = kbuf->len;
+       } else {
+               kbuf = ERR_PTR(-ENOBUFS);
+       }
+
+       io_ring_submit_unlock(req->ctx, needs_lock);
+
+       return kbuf;
+}
+
+static void __user *io_rw_buffer_select(struct io_kiocb *req, size_t *len,
+                                       bool needs_lock)
+{
+       struct io_buffer *kbuf;
+       int bgid;
+
+       kbuf = (struct io_buffer *) (unsigned long) req->rw.addr;
+       bgid = (int) (unsigned long) req->rw.kiocb.private;
+       kbuf = io_buffer_select(req, len, bgid, kbuf, needs_lock);
+       if (IS_ERR(kbuf))
+               return kbuf;
+       req->rw.addr = (u64) (unsigned long) kbuf;
+       req->flags |= REQ_F_BUFFER_SELECTED;
+       return u64_to_user_ptr(kbuf->addr);
+}
+
+#ifdef CONFIG_COMPAT
+static ssize_t io_compat_import(struct io_kiocb *req, struct iovec *iov,
+                               bool needs_lock)
+{
+       struct compat_iovec __user *uiov;
+       compat_ssize_t clen;
+       void __user *buf;
+       ssize_t len;
+
+       uiov = u64_to_user_ptr(req->rw.addr);
+       if (!access_ok(uiov, sizeof(*uiov)))
+               return -EFAULT;
+       if (__get_user(clen, &uiov->iov_len))
+               return -EFAULT;
+       if (clen < 0)
+               return -EINVAL;
+
+       len = clen;
+       buf = io_rw_buffer_select(req, &len, needs_lock);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+       iov[0].iov_base = buf;
+       iov[0].iov_len = (compat_size_t) len;
+       return 0;
+}
+#endif
+
+static ssize_t __io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
+                                     bool needs_lock)
+{
+       struct iovec __user *uiov = u64_to_user_ptr(req->rw.addr);
+       void __user *buf;
+       ssize_t len;
+
+       if (copy_from_user(iov, uiov, sizeof(*uiov)))
+               return -EFAULT;
+
+       len = iov[0].iov_len;
+       if (len < 0)
+               return -EINVAL;
+       buf = io_rw_buffer_select(req, &len, needs_lock);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+       iov[0].iov_base = buf;
+       iov[0].iov_len = len;
+       return 0;
+}
+
+static ssize_t io_iov_buffer_select(struct io_kiocb *req, struct iovec *iov,
+                                   bool needs_lock)
+{
+       if (req->flags & REQ_F_BUFFER_SELECTED)
+               return 0;
+       if (!req->rw.len)
+               return 0;
+       else if (req->rw.len > 1)
+               return -EINVAL;
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               return io_compat_import(req, iov, needs_lock);
+#endif
+
+       return __io_iov_buffer_select(req, iov, needs_lock);
+}
+
 static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
-                              struct iovec **iovec, struct iov_iter *iter)
+                              struct iovec **iovec, struct iov_iter *iter,
+                              bool needs_lock)
 {
        void __user *buf = u64_to_user_ptr(req->rw.addr);
        size_t sqe_len = req->rw.len;
+       ssize_t ret;
        u8 opcode;
 
        opcode = req->opcode;
@@ -2063,15 +2350,23 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
                return io_import_fixed(req, rw, iter);
        }
 
-       /* buffer index only valid with fixed read/write */
-       if (req->rw.kiocb.private)
+       /* buffer index only valid with fixed read/write, or buffer select  */
+       if (req->rw.kiocb.private && !(req->flags & REQ_F_BUFFER_SELECT))
                return -EINVAL;
 
        if (opcode == IORING_OP_READ || opcode == IORING_OP_WRITE) {
-               ssize_t ret;
+               if (req->flags & REQ_F_BUFFER_SELECT) {
+                       buf = io_rw_buffer_select(req, &sqe_len, needs_lock);
+                       if (IS_ERR(buf)) {
+                               *iovec = NULL;
+                               return PTR_ERR(buf);
+                       }
+                       req->rw.len = sqe_len;
+               }
+
                ret = import_single_range(rw, buf, sqe_len, *iovec, iter);
                *iovec = NULL;
-               return ret;
+               return ret < 0 ? ret : sqe_len;
        }
 
        if (req->io) {
@@ -2084,6 +2379,16 @@ static ssize_t io_import_iovec(int rw, struct io_kiocb *req,
                return iorw->size;
        }
 
+       if (req->flags & REQ_F_BUFFER_SELECT) {
+               ret = io_iov_buffer_select(req, *iovec, needs_lock);
+               if (!ret) {
+                       ret = (*iovec)->iov_len;
+                       iov_iter_init(iter, rw, *iovec, 1, ret);
+               }
+               *iovec = NULL;
+               return ret;
+       }
+
 #ifdef CONFIG_COMPAT
        if (req->ctx->compat)
                return compat_import_iovec(rw, buf, sqe_len, UIO_FASTIOV,
@@ -2167,12 +2472,18 @@ static void io_req_map_rw(struct io_kiocb *req, ssize_t io_size,
        }
 }
 
+static inline int __io_alloc_async_ctx(struct io_kiocb *req)
+{
+       req->io = kmalloc(sizeof(*req->io), GFP_KERNEL);
+       return req->io == NULL;
+}
+
 static int io_alloc_async_ctx(struct io_kiocb *req)
 {
        if (!io_op_defs[req->opcode].async_ctx)
                return 0;
-       req->io = kmalloc(sizeof(*req->io), GFP_KERNEL);
-       return req->io == NULL;
+
+       return  __io_alloc_async_ctx(req);
 }
 
 static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
@@ -2182,7 +2493,7 @@ static int io_setup_async_rw(struct io_kiocb *req, ssize_t io_size,
        if (!io_op_defs[req->opcode].async_ctx)
                return 0;
        if (!req->io) {
-               if (io_alloc_async_ctx(req))
+               if (__io_alloc_async_ctx(req))
                        return -ENOMEM;
 
                io_req_map_rw(req, io_size, iovec, fast_iov, iter);
@@ -2211,7 +2522,7 @@ static int io_read_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe,
        io = req->io;
        io->rw.iov = io->rw.fast_iov;
        req->io = NULL;
-       ret = io_import_iovec(READ, req, &io->rw.iov, &iter);
+       ret = io_import_iovec(READ, req, &io->rw.iov, &iter, !force_nonblock);
        req->io = io;
        if (ret < 0)
                return ret;
@@ -2220,8 +2531,7 @@ static int io_read_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe,
        return 0;
 }
 
-static int io_read(struct io_kiocb *req, struct io_kiocb **nxt,
-                  bool force_nonblock)
+static int io_read(struct io_kiocb *req, bool force_nonblock)
 {
        struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
        struct kiocb *kiocb = &req->rw.kiocb;
@@ -2229,13 +2539,13 @@ static int io_read(struct io_kiocb *req, struct io_kiocb **nxt,
        size_t iov_count;
        ssize_t io_size, ret;
 
-       ret = io_import_iovec(READ, req, &iovec, &iter);
+       ret = io_import_iovec(READ, req, &iovec, &iter, !force_nonblock);
        if (ret < 0)
                return ret;
 
        /* Ensure we clear previously set non-block flag */
        if (!force_nonblock)
-               req->rw.kiocb.ki_flags &= ~IOCB_NOWAIT;
+               kiocb->ki_flags &= ~IOCB_NOWAIT;
 
        req->result = 0;
        io_size = ret;
@@ -2246,10 +2556,8 @@ static int io_read(struct io_kiocb *req, struct io_kiocb **nxt,
         * If the file doesn't support async, mark it as REQ_F_MUST_PUNT so
         * we know to async punt it even if it was opened O_NONBLOCK
         */
-       if (force_nonblock && !io_file_supports_async(req->file)) {
-               req->flags |= REQ_F_MUST_PUNT;
+       if (force_nonblock && !io_file_supports_async(req->file))
                goto copy_iov;
-       }
 
        iov_count = iov_iter_count(&iter);
        ret = rw_verify_area(READ, req->file, &kiocb->ki_pos, iov_count);
@@ -2263,13 +2571,16 @@ static int io_read(struct io_kiocb *req, struct io_kiocb **nxt,
 
                /* Catch -EAGAIN return for forced non-blocking submission */
                if (!force_nonblock || ret2 != -EAGAIN) {
-                       kiocb_done(kiocb, ret2, nxt, req->in_async);
+                       kiocb_done(kiocb, ret2);
                } else {
 copy_iov:
                        ret = io_setup_async_rw(req, io_size, iovec,
                                                inline_vecs, &iter);
                        if (ret)
                                goto out_free;
+                       /* any defer here is final, must blocking retry */
+                       if (!(req->flags & REQ_F_NOWAIT))
+                               req->flags |= REQ_F_MUST_PUNT;
                        return -EAGAIN;
                }
        }
@@ -2293,6 +2604,8 @@ static int io_write_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe,
        if (unlikely(!(req->file->f_mode & FMODE_WRITE)))
                return -EBADF;
 
+       req->fsize = rlimit(RLIMIT_FSIZE);
+
        /* either don't need iovec imported or already have it */
        if (!req->io || req->flags & REQ_F_NEED_CLEANUP)
                return 0;
@@ -2300,7 +2613,7 @@ static int io_write_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe,
        io = req->io;
        io->rw.iov = io->rw.fast_iov;
        req->io = NULL;
-       ret = io_import_iovec(WRITE, req, &io->rw.iov, &iter);
+       ret = io_import_iovec(WRITE, req, &io->rw.iov, &iter, !force_nonblock);
        req->io = io;
        if (ret < 0)
                return ret;
@@ -2309,8 +2622,7 @@ static int io_write_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe,
        return 0;
 }
 
-static int io_write(struct io_kiocb *req, struct io_kiocb **nxt,
-                   bool force_nonblock)
+static int io_write(struct io_kiocb *req, bool force_nonblock)
 {
        struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
        struct kiocb *kiocb = &req->rw.kiocb;
@@ -2318,7 +2630,7 @@ static int io_write(struct io_kiocb *req, struct io_kiocb **nxt,
        size_t iov_count;
        ssize_t ret, io_size;
 
-       ret = io_import_iovec(WRITE, req, &iovec, &iter);
+       ret = io_import_iovec(WRITE, req, &iovec, &iter, !force_nonblock);
        if (ret < 0)
                return ret;
 
@@ -2335,10 +2647,8 @@ static int io_write(struct io_kiocb *req, struct io_kiocb **nxt,
         * If the file doesn't support async, mark it as REQ_F_MUST_PUNT so
         * we know to async punt it even if it was opened O_NONBLOCK
         */
-       if (force_nonblock && !io_file_supports_async(req->file)) {
-               req->flags |= REQ_F_MUST_PUNT;
+       if (force_nonblock && !io_file_supports_async(req->file))
                goto copy_iov;
-       }
 
        /* file path doesn't support NOWAIT for non-direct_IO */
        if (force_nonblock && !(kiocb->ki_flags & IOCB_DIRECT) &&
@@ -2365,24 +2675,33 @@ static int io_write(struct io_kiocb *req, struct io_kiocb **nxt,
                }
                kiocb->ki_flags |= IOCB_WRITE;
 
+               if (!force_nonblock)
+                       current->signal->rlim[RLIMIT_FSIZE].rlim_cur = req->fsize;
+
                if (req->file->f_op->write_iter)
                        ret2 = call_write_iter(req->file, kiocb, &iter);
                else
                        ret2 = loop_rw_iter(WRITE, req->file, kiocb, &iter);
+
+               if (!force_nonblock)
+                       current->signal->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
+
                /*
-                * Raw bdev writes will -EOPNOTSUPP for IOCB_NOWAIT. Just
+                * Raw bdev writes will return -EOPNOTSUPP for IOCB_NOWAIT. Just
                 * retry them without IOCB_NOWAIT.
                 */
                if (ret2 == -EOPNOTSUPP && (kiocb->ki_flags & IOCB_NOWAIT))
                        ret2 = -EAGAIN;
                if (!force_nonblock || ret2 != -EAGAIN) {
-                       kiocb_done(kiocb, ret2, nxt, req->in_async);
+                       kiocb_done(kiocb, ret2);
                } else {
 copy_iov:
                        ret = io_setup_async_rw(req, io_size, iovec,
                                                inline_vecs, &iter);
                        if (ret)
                                goto out_free;
+                       /* any defer here is final, must blocking retry */
+                       req->flags |= REQ_F_MUST_PUNT;
                        return -EAGAIN;
                }
        }
@@ -2392,6 +2711,76 @@ out_free:
        return ret;
 }
 
+static int io_splice_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       struct io_splice* sp = &req->splice;
+       unsigned int valid_flags = SPLICE_F_FD_IN_FIXED | SPLICE_F_ALL;
+       int ret;
+
+       if (req->flags & REQ_F_NEED_CLEANUP)
+               return 0;
+
+       sp->file_in = NULL;
+       sp->off_in = READ_ONCE(sqe->splice_off_in);
+       sp->off_out = READ_ONCE(sqe->off);
+       sp->len = READ_ONCE(sqe->len);
+       sp->flags = READ_ONCE(sqe->splice_flags);
+
+       if (unlikely(sp->flags & ~valid_flags))
+               return -EINVAL;
+
+       ret = io_file_get(NULL, req, READ_ONCE(sqe->splice_fd_in), &sp->file_in,
+                         (sp->flags & SPLICE_F_FD_IN_FIXED));
+       if (ret)
+               return ret;
+       req->flags |= REQ_F_NEED_CLEANUP;
+
+       if (!S_ISREG(file_inode(sp->file_in)->i_mode))
+               req->work.flags |= IO_WQ_WORK_UNBOUND;
+
+       return 0;
+}
+
+static bool io_splice_punt(struct file *file)
+{
+       if (get_pipe_info(file))
+               return false;
+       if (!io_file_supports_async(file))
+               return true;
+       return !(file->f_mode & O_NONBLOCK);
+}
+
+static int io_splice(struct io_kiocb *req, bool force_nonblock)
+{
+       struct io_splice *sp = &req->splice;
+       struct file *in = sp->file_in;
+       struct file *out = sp->file_out;
+       unsigned int flags = sp->flags & ~SPLICE_F_FD_IN_FIXED;
+       loff_t *poff_in, *poff_out;
+       long ret;
+
+       if (force_nonblock) {
+               if (io_splice_punt(in) || io_splice_punt(out))
+                       return -EAGAIN;
+               flags |= SPLICE_F_NONBLOCK;
+       }
+
+       poff_in = (sp->off_in == -1) ? NULL : &sp->off_in;
+       poff_out = (sp->off_out == -1) ? NULL : &sp->off_out;
+       ret = do_splice(in, poff_in, out, poff_out, sp->len, flags);
+       if (force_nonblock && ret == -EAGAIN)
+               return -EAGAIN;
+
+       io_put_file(req, in, (sp->flags & SPLICE_F_FD_IN_FIXED));
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+
+       io_cqring_add_event(req, ret);
+       if (ret != sp->len)
+               req_set_fail_links(req);
+       io_put_req(req);
+       return 0;
+}
+
 /*
  * IORING_OP_NOP just posts a completion event, nothing else.
  */
@@ -2440,85 +2829,63 @@ static bool io_req_cancelled(struct io_kiocb *req)
        return false;
 }
 
-static void io_link_work_cb(struct io_wq_work **workptr)
-{
-       struct io_wq_work *work = *workptr;
-       struct io_kiocb *link = work->data;
-
-       io_queue_linked_timeout(link);
-       work->func = io_wq_submit_work;
-}
-
-static void io_wq_assign_next(struct io_wq_work **workptr, struct io_kiocb *nxt)
-{
-       struct io_kiocb *link;
-
-       io_prep_async_work(nxt, &link);
-       *workptr = &nxt->work;
-       if (link) {
-               nxt->work.flags |= IO_WQ_WORK_CB;
-               nxt->work.func = io_link_work_cb;
-               nxt->work.data = link;
-       }
-}
-
-static void io_fsync_finish(struct io_wq_work **workptr)
+static void __io_fsync(struct io_kiocb *req)
 {
-       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
        loff_t end = req->sync.off + req->sync.len;
-       struct io_kiocb *nxt = NULL;
        int ret;
 
-       if (io_req_cancelled(req))
-               return;
-
        ret = vfs_fsync_range(req->file, req->sync.off,
                                end > 0 ? end : LLONG_MAX,
                                req->sync.flags & IORING_FSYNC_DATASYNC);
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, &nxt);
-       if (nxt)
-               io_wq_assign_next(workptr, nxt);
+       io_put_req(req);
 }
 
-static int io_fsync(struct io_kiocb *req, struct io_kiocb **nxt,
-                   bool force_nonblock)
+static void io_fsync_finish(struct io_wq_work **workptr)
 {
-       struct io_wq_work *work, *old_work;
+       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
+
+       if (io_req_cancelled(req))
+               return;
+       __io_fsync(req);
+       io_steal_work(req, workptr);
+}
 
+static int io_fsync(struct io_kiocb *req, bool force_nonblock)
+{
        /* fsync always requires a blocking context */
        if (force_nonblock) {
-               io_put_req(req);
                req->work.func = io_fsync_finish;
                return -EAGAIN;
        }
-
-       work = old_work = &req->work;
-       io_fsync_finish(&work);
-       if (work && work != old_work)
-               *nxt = container_of(work, struct io_kiocb, work);
+       __io_fsync(req);
        return 0;
 }
 
-static void io_fallocate_finish(struct io_wq_work **workptr)
+static void __io_fallocate(struct io_kiocb *req)
 {
-       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
-       struct io_kiocb *nxt = NULL;
        int ret;
 
-       if (io_req_cancelled(req))
-               return;
-
+       current->signal->rlim[RLIMIT_FSIZE].rlim_cur = req->fsize;
        ret = vfs_fallocate(req->file, req->sync.mode, req->sync.off,
                                req->sync.len);
+       current->signal->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, &nxt);
-       if (nxt)
-               io_wq_assign_next(workptr, nxt);
+       io_put_req(req);
+}
+
+static void io_fallocate_finish(struct io_wq_work **workptr)
+{
+       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
+
+       if (io_req_cancelled(req))
+               return;
+       __io_fallocate(req);
+       io_steal_work(req, workptr);
 }
 
 static int io_fallocate_prep(struct io_kiocb *req,
@@ -2530,26 +2897,19 @@ static int io_fallocate_prep(struct io_kiocb *req,
        req->sync.off = READ_ONCE(sqe->off);
        req->sync.len = READ_ONCE(sqe->addr);
        req->sync.mode = READ_ONCE(sqe->len);
+       req->fsize = rlimit(RLIMIT_FSIZE);
        return 0;
 }
 
-static int io_fallocate(struct io_kiocb *req, struct io_kiocb **nxt,
-                       bool force_nonblock)
+static int io_fallocate(struct io_kiocb *req, bool force_nonblock)
 {
-       struct io_wq_work *work, *old_work;
-
        /* fallocate always requiring blocking context */
        if (force_nonblock) {
-               io_put_req(req);
                req->work.func = io_fallocate_finish;
                return -EAGAIN;
        }
 
-       work = old_work = &req->work;
-       io_fallocate_finish(&work);
-       if (work && work != old_work)
-               *nxt = container_of(work, struct io_kiocb, work);
-
+       __io_fallocate(req);
        return 0;
 }
 
@@ -2577,6 +2937,7 @@ static int io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                return ret;
        }
 
+       req->open.nofile = rlimit(RLIMIT_NOFILE);
        req->flags |= REQ_F_NEED_CLEANUP;
        return 0;
 }
@@ -2618,12 +2979,12 @@ static int io_openat2_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
                return ret;
        }
 
+       req->open.nofile = rlimit(RLIMIT_NOFILE);
        req->flags |= REQ_F_NEED_CLEANUP;
        return 0;
 }
 
-static int io_openat2(struct io_kiocb *req, struct io_kiocb **nxt,
-                     bool force_nonblock)
+static int io_openat2(struct io_kiocb *req, bool force_nonblock)
 {
        struct open_flags op;
        struct file *file;
@@ -2636,7 +2997,7 @@ static int io_openat2(struct io_kiocb *req, struct io_kiocb **nxt,
        if (ret)
                goto err;
 
-       ret = get_unused_fd_flags(req->open.how.flags);
+       ret = __get_unused_fd_flags(req->open.how.flags, req->open.nofile);
        if (ret < 0)
                goto err;
 
@@ -2654,15 +3015,171 @@ err:
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
 }
 
-static int io_openat(struct io_kiocb *req, struct io_kiocb **nxt,
-                    bool force_nonblock)
+static int io_openat(struct io_kiocb *req, bool force_nonblock)
 {
        req->open.how = build_open_how(req->open.how.flags, req->open.how.mode);
-       return io_openat2(req, nxt, force_nonblock);
+       return io_openat2(req, force_nonblock);
+}
+
+static int io_remove_buffers_prep(struct io_kiocb *req,
+                                 const struct io_uring_sqe *sqe)
+{
+       struct io_provide_buf *p = &req->pbuf;
+       u64 tmp;
+
+       if (sqe->ioprio || sqe->rw_flags || sqe->addr || sqe->len || sqe->off)
+               return -EINVAL;
+
+       tmp = READ_ONCE(sqe->fd);
+       if (!tmp || tmp > USHRT_MAX)
+               return -EINVAL;
+
+       memset(p, 0, sizeof(*p));
+       p->nbufs = tmp;
+       p->bgid = READ_ONCE(sqe->buf_group);
+       return 0;
+}
+
+static int __io_remove_buffers(struct io_ring_ctx *ctx, struct io_buffer *buf,
+                              int bgid, unsigned nbufs)
+{
+       unsigned i = 0;
+
+       /* shouldn't happen */
+       if (!nbufs)
+               return 0;
+
+       /* the head kbuf is the list itself */
+       while (!list_empty(&buf->list)) {
+               struct io_buffer *nxt;
+
+               nxt = list_first_entry(&buf->list, struct io_buffer, list);
+               list_del(&nxt->list);
+               kfree(nxt);
+               if (++i == nbufs)
+                       return i;
+       }
+       i++;
+       kfree(buf);
+       idr_remove(&ctx->io_buffer_idr, bgid);
+
+       return i;
+}
+
+static int io_remove_buffers(struct io_kiocb *req, bool force_nonblock)
+{
+       struct io_provide_buf *p = &req->pbuf;
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_buffer *head;
+       int ret = 0;
+
+       io_ring_submit_lock(ctx, !force_nonblock);
+
+       lockdep_assert_held(&ctx->uring_lock);
+
+       ret = -ENOENT;
+       head = idr_find(&ctx->io_buffer_idr, p->bgid);
+       if (head)
+               ret = __io_remove_buffers(ctx, head, p->bgid, p->nbufs);
+
+       io_ring_submit_lock(ctx, !force_nonblock);
+       if (ret < 0)
+               req_set_fail_links(req);
+       io_cqring_add_event(req, ret);
+       io_put_req(req);
+       return 0;
+}
+
+static int io_provide_buffers_prep(struct io_kiocb *req,
+                                  const struct io_uring_sqe *sqe)
+{
+       struct io_provide_buf *p = &req->pbuf;
+       u64 tmp;
+
+       if (sqe->ioprio || sqe->rw_flags)
+               return -EINVAL;
+
+       tmp = READ_ONCE(sqe->fd);
+       if (!tmp || tmp > USHRT_MAX)
+               return -E2BIG;
+       p->nbufs = tmp;
+       p->addr = READ_ONCE(sqe->addr);
+       p->len = READ_ONCE(sqe->len);
+
+       if (!access_ok(u64_to_user_ptr(p->addr), p->len))
+               return -EFAULT;
+
+       p->bgid = READ_ONCE(sqe->buf_group);
+       tmp = READ_ONCE(sqe->off);
+       if (tmp > USHRT_MAX)
+               return -E2BIG;
+       p->bid = tmp;
+       return 0;
+}
+
+static int io_add_buffers(struct io_provide_buf *pbuf, struct io_buffer **head)
+{
+       struct io_buffer *buf;
+       u64 addr = pbuf->addr;
+       int i, bid = pbuf->bid;
+
+       for (i = 0; i < pbuf->nbufs; i++) {
+               buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+               if (!buf)
+                       break;
+
+               buf->addr = addr;
+               buf->len = pbuf->len;
+               buf->bid = bid;
+               addr += pbuf->len;
+               bid++;
+               if (!*head) {
+                       INIT_LIST_HEAD(&buf->list);
+                       *head = buf;
+               } else {
+                       list_add_tail(&buf->list, &(*head)->list);
+               }
+       }
+
+       return i ? i : -ENOMEM;
+}
+
+static int io_provide_buffers(struct io_kiocb *req, bool force_nonblock)
+{
+       struct io_provide_buf *p = &req->pbuf;
+       struct io_ring_ctx *ctx = req->ctx;
+       struct io_buffer *head, *list;
+       int ret = 0;
+
+       io_ring_submit_lock(ctx, !force_nonblock);
+
+       lockdep_assert_held(&ctx->uring_lock);
+
+       list = head = idr_find(&ctx->io_buffer_idr, p->bgid);
+
+       ret = io_add_buffers(p, &head);
+       if (ret < 0)
+               goto out;
+
+       if (!list) {
+               ret = idr_alloc(&ctx->io_buffer_idr, head, p->bgid, p->bgid + 1,
+                                       GFP_KERNEL);
+               if (ret < 0) {
+                       __io_remove_buffers(ctx, head, p->bgid, -1U);
+                       goto out;
+               }
+       }
+out:
+       io_ring_submit_unlock(ctx, !force_nonblock);
+       if (ret < 0)
+               req_set_fail_links(req);
+       io_cqring_add_event(req, ret);
+       io_put_req(req);
+       return 0;
 }
 
 static int io_epoll_ctl_prep(struct io_kiocb *req,
@@ -2690,8 +3207,7 @@ static int io_epoll_ctl_prep(struct io_kiocb *req,
 #endif
 }
 
-static int io_epoll_ctl(struct io_kiocb *req, struct io_kiocb **nxt,
-                       bool force_nonblock)
+static int io_epoll_ctl(struct io_kiocb *req, bool force_nonblock)
 {
 #if defined(CONFIG_EPOLL)
        struct io_epoll *ie = &req->epoll;
@@ -2704,7 +3220,7 @@ static int io_epoll_ctl(struct io_kiocb *req, struct io_kiocb **nxt,
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
 #else
        return -EOPNOTSUPP;
@@ -2726,8 +3242,7 @@ static int io_madvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 #endif
 }
 
-static int io_madvise(struct io_kiocb *req, struct io_kiocb **nxt,
-                     bool force_nonblock)
+static int io_madvise(struct io_kiocb *req, bool force_nonblock)
 {
 #if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU)
        struct io_madvise *ma = &req->madvise;
@@ -2740,7 +3255,7 @@ static int io_madvise(struct io_kiocb *req, struct io_kiocb **nxt,
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
 #else
        return -EOPNOTSUPP;
@@ -2758,8 +3273,7 @@ static int io_fadvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        return 0;
 }
 
-static int io_fadvise(struct io_kiocb *req, struct io_kiocb **nxt,
-                     bool force_nonblock)
+static int io_fadvise(struct io_kiocb *req, bool force_nonblock)
 {
        struct io_fadvise *fa = &req->fadvise;
        int ret;
@@ -2779,7 +3293,7 @@ static int io_fadvise(struct io_kiocb *req, struct io_kiocb **nxt,
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
 }
 
@@ -2816,8 +3330,7 @@ static int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        return 0;
 }
 
-static int io_statx(struct io_kiocb *req, struct io_kiocb **nxt,
-                   bool force_nonblock)
+static int io_statx(struct io_kiocb *req, bool force_nonblock)
 {
        struct io_open *ctx = &req->open;
        unsigned lookup_flags;
@@ -2854,7 +3367,7 @@ err:
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
 }
 
@@ -2881,7 +3394,7 @@ static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 }
 
 /* only called when __close_fd_get_file() is done */
-static void __io_close_finish(struct io_kiocb *req, struct io_kiocb **nxt)
+static void __io_close_finish(struct io_kiocb *req)
 {
        int ret;
 
@@ -2890,22 +3403,19 @@ static void __io_close_finish(struct io_kiocb *req, struct io_kiocb **nxt)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
        fput(req->close.put_file);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
 }
 
 static void io_close_finish(struct io_wq_work **workptr)
 {
        struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
-       struct io_kiocb *nxt = NULL;
 
        /* not cancellable, don't do io_req_cancelled() */
-       __io_close_finish(req, &nxt);
-       if (nxt)
-               io_wq_assign_next(workptr, nxt);
+       __io_close_finish(req);
+       io_steal_work(req, workptr);
 }
 
-static int io_close(struct io_kiocb *req, struct io_kiocb **nxt,
-                   bool force_nonblock)
+static int io_close(struct io_kiocb *req, bool force_nonblock)
 {
        int ret;
 
@@ -2915,23 +3425,25 @@ static int io_close(struct io_kiocb *req, struct io_kiocb **nxt,
                return ret;
 
        /* if the file has a flush method, be safe and punt to async */
-       if (req->close.put_file->f_op->flush && !io_wq_current_is_worker())
-               goto eagain;
+       if (req->close.put_file->f_op->flush && force_nonblock) {
+               /* submission ref will be dropped, take it for async */
+               refcount_inc(&req->refs);
+
+               req->work.func = io_close_finish;
+               /*
+                * Do manual async queue here to avoid grabbing files - we don't
+                * need the files, and it'll cause io_close_finish() to close
+                * the file again and cause a double CQE entry for this request
+                */
+               io_queue_async_work(req);
+               return 0;
+       }
 
        /*
         * No ->flush(), safely close from here and just punt the
         * fput() to async context.
         */
-       __io_close_finish(req, nxt);
-       return 0;
-eagain:
-       req->work.func = io_close_finish;
-       /*
-        * Do manual async queue here to avoid grabbing files - we don't
-        * need the files, and it'll cause io_close_finish() to close
-        * the file again and cause a double CQE entry for this request
-        */
-       io_queue_async_work(req);
+       __io_close_finish(req);
        return 0;
 }
 
@@ -2953,47 +3465,62 @@ static int io_prep_sfr(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        return 0;
 }
 
-static void io_sync_file_range_finish(struct io_wq_work **workptr)
+static void __io_sync_file_range(struct io_kiocb *req)
 {
-       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
-       struct io_kiocb *nxt = NULL;
        int ret;
 
-       if (io_req_cancelled(req))
-               return;
-
        ret = sync_file_range(req->file, req->sync.off, req->sync.len,
                                req->sync.flags);
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, &nxt);
+       io_put_req(req);
+}
+
+
+static void io_sync_file_range_finish(struct io_wq_work **workptr)
+{
+       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
+       struct io_kiocb *nxt = NULL;
+
+       if (io_req_cancelled(req))
+               return;
+       __io_sync_file_range(req);
+       io_put_req(req); /* put submission ref */
        if (nxt)
                io_wq_assign_next(workptr, nxt);
 }
 
-static int io_sync_file_range(struct io_kiocb *req, struct io_kiocb **nxt,
-                             bool force_nonblock)
+static int io_sync_file_range(struct io_kiocb *req, bool force_nonblock)
 {
-       struct io_wq_work *work, *old_work;
-
        /* sync_file_range always requires a blocking context */
        if (force_nonblock) {
-               io_put_req(req);
                req->work.func = io_sync_file_range_finish;
                return -EAGAIN;
        }
 
-       work = old_work = &req->work;
-       io_sync_file_range_finish(&work);
-       if (work && work != old_work)
-               *nxt = container_of(work, struct io_kiocb, work);
+       __io_sync_file_range(req);
        return 0;
 }
 
+#if defined(CONFIG_NET)
+static int io_setup_async_msg(struct io_kiocb *req,
+                             struct io_async_msghdr *kmsg)
+{
+       if (req->io)
+               return -EAGAIN;
+       if (io_alloc_async_ctx(req)) {
+               if (kmsg->iov != kmsg->fast_iov)
+                       kfree(kmsg->iov);
+               return -ENOMEM;
+       }
+       req->flags |= REQ_F_NEED_CLEANUP;
+       memcpy(&req->io->msg, kmsg, sizeof(*kmsg));
+       return -EAGAIN;
+}
+
 static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
-#if defined(CONFIG_NET)
        struct io_sr_msg *sr = &req->sr_msg;
        struct io_async_ctx *io = req->io;
        int ret;
@@ -3002,6 +3529,11 @@ static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        sr->msg = u64_to_user_ptr(READ_ONCE(sqe->addr));
        sr->len = READ_ONCE(sqe->len);
 
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               sr->msg_flags |= MSG_CMSG_COMPAT;
+#endif
+
        if (!io || req->opcode == IORING_OP_SEND)
                return 0;
        /* iovec is already imported */
@@ -3014,15 +3546,10 @@ static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        if (!ret)
                req->flags |= REQ_F_NEED_CLEANUP;
        return ret;
-#else
-       return -EOPNOTSUPP;
-#endif
 }
 
-static int io_sendmsg(struct io_kiocb *req, struct io_kiocb **nxt,
-                     bool force_nonblock)
+static int io_sendmsg(struct io_kiocb *req, bool force_nonblock)
 {
-#if defined(CONFIG_NET)
        struct io_async_msghdr *kmsg = NULL;
        struct socket *sock;
        int ret;
@@ -3062,18 +3589,8 @@ static int io_sendmsg(struct io_kiocb *req, struct io_kiocb **nxt,
                        flags |= MSG_DONTWAIT;
 
                ret = __sys_sendmsg_sock(sock, &kmsg->msg, flags);
-               if (force_nonblock && ret == -EAGAIN) {
-                       if (req->io)
-                               return -EAGAIN;
-                       if (io_alloc_async_ctx(req)) {
-                               if (kmsg->iov != kmsg->fast_iov)
-                                       kfree(kmsg->iov);
-                               return -ENOMEM;
-                       }
-                       req->flags |= REQ_F_NEED_CLEANUP;
-                       memcpy(&req->io->msg, &io.msg, sizeof(io.msg));
-                       return -EAGAIN;
-               }
+               if (force_nonblock && ret == -EAGAIN)
+                       return io_setup_async_msg(req, kmsg);
                if (ret == -ERESTARTSYS)
                        ret = -EINTR;
        }
@@ -3084,17 +3601,12 @@ static int io_sendmsg(struct io_kiocb *req, struct io_kiocb **nxt,
        io_cqring_add_event(req, ret);
        if (ret < 0)
                req_set_fail_links(req);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
 }
 
-static int io_send(struct io_kiocb *req, struct io_kiocb **nxt,
-                  bool force_nonblock)
+static int io_send(struct io_kiocb *req, bool force_nonblock)
 {
-#if defined(CONFIG_NET)
        struct socket *sock;
        int ret;
 
@@ -3135,17 +3647,120 @@ static int io_send(struct io_kiocb *req, struct io_kiocb **nxt,
        io_cqring_add_event(req, ret);
        if (ret < 0)
                req_set_fail_links(req);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
-#else
-       return -EOPNOTSUPP;
+}
+
+static int __io_recvmsg_copy_hdr(struct io_kiocb *req, struct io_async_ctx *io)
+{
+       struct io_sr_msg *sr = &req->sr_msg;
+       struct iovec __user *uiov;
+       size_t iov_len;
+       int ret;
+
+       ret = __copy_msghdr_from_user(&io->msg.msg, sr->msg, &io->msg.uaddr,
+                                       &uiov, &iov_len);
+       if (ret)
+               return ret;
+
+       if (req->flags & REQ_F_BUFFER_SELECT) {
+               if (iov_len > 1)
+                       return -EINVAL;
+               if (copy_from_user(io->msg.iov, uiov, sizeof(*uiov)))
+                       return -EFAULT;
+               sr->len = io->msg.iov[0].iov_len;
+               iov_iter_init(&io->msg.msg.msg_iter, READ, io->msg.iov, 1,
+                               sr->len);
+               io->msg.iov = NULL;
+       } else {
+               ret = import_iovec(READ, uiov, iov_len, UIO_FASTIOV,
+                                       &io->msg.iov, &io->msg.msg.msg_iter);
+               if (ret > 0)
+                       ret = 0;
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static int __io_compat_recvmsg_copy_hdr(struct io_kiocb *req,
+                                       struct io_async_ctx *io)
+{
+       struct compat_msghdr __user *msg_compat;
+       struct io_sr_msg *sr = &req->sr_msg;
+       struct compat_iovec __user *uiov;
+       compat_uptr_t ptr;
+       compat_size_t len;
+       int ret;
+
+       msg_compat = (struct compat_msghdr __user *) sr->msg;
+       ret = __get_compat_msghdr(&io->msg.msg, msg_compat, &io->msg.uaddr,
+                                       &ptr, &len);
+       if (ret)
+               return ret;
+
+       uiov = compat_ptr(ptr);
+       if (req->flags & REQ_F_BUFFER_SELECT) {
+               compat_ssize_t clen;
+
+               if (len > 1)
+                       return -EINVAL;
+               if (!access_ok(uiov, sizeof(*uiov)))
+                       return -EFAULT;
+               if (__get_user(clen, &uiov->iov_len))
+                       return -EFAULT;
+               if (clen < 0)
+                       return -EINVAL;
+               sr->len = io->msg.iov[0].iov_len;
+               io->msg.iov = NULL;
+       } else {
+               ret = compat_import_iovec(READ, uiov, len, UIO_FASTIOV,
+                                               &io->msg.iov,
+                                               &io->msg.msg.msg_iter);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+#endif
+
+static int io_recvmsg_copy_hdr(struct io_kiocb *req, struct io_async_ctx *io)
+{
+       io->msg.iov = io->msg.fast_iov;
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               return __io_compat_recvmsg_copy_hdr(req, io);
 #endif
+
+       return __io_recvmsg_copy_hdr(req, io);
+}
+
+static struct io_buffer *io_recv_buffer_select(struct io_kiocb *req,
+                                              int *cflags, bool needs_lock)
+{
+       struct io_sr_msg *sr = &req->sr_msg;
+       struct io_buffer *kbuf;
+
+       if (!(req->flags & REQ_F_BUFFER_SELECT))
+               return NULL;
+
+       kbuf = io_buffer_select(req, &sr->len, sr->bgid, sr->kbuf, needs_lock);
+       if (IS_ERR(kbuf))
+               return kbuf;
+
+       sr->kbuf = kbuf;
+       req->flags |= REQ_F_BUFFER_SELECTED;
+
+       *cflags = kbuf->bid << IORING_CQE_BUFFER_SHIFT;
+       *cflags |= IORING_CQE_F_BUFFER;
+       return kbuf;
 }
 
 static int io_recvmsg_prep(struct io_kiocb *req,
                           const struct io_uring_sqe *sqe)
 {
-#if defined(CONFIG_NET)
        struct io_sr_msg *sr = &req->sr_msg;
        struct io_async_ctx *io = req->io;
        int ret;
@@ -3153,6 +3768,12 @@ static int io_recvmsg_prep(struct io_kiocb *req,
        sr->msg_flags = READ_ONCE(sqe->msg_flags);
        sr->msg = u64_to_user_ptr(READ_ONCE(sqe->addr));
        sr->len = READ_ONCE(sqe->len);
+       sr->bgid = READ_ONCE(sqe->buf_group);
+
+#ifdef CONFIG_COMPAT
+       if (req->ctx->compat)
+               sr->msg_flags |= MSG_CMSG_COMPAT;
+#endif
 
        if (!io || req->opcode == IORING_OP_RECV)
                return 0;
@@ -3160,30 +3781,24 @@ static int io_recvmsg_prep(struct io_kiocb *req,
        if (req->flags & REQ_F_NEED_CLEANUP)
                return 0;
 
-       io->msg.iov = io->msg.fast_iov;
-       ret = recvmsg_copy_msghdr(&io->msg.msg, sr->msg, sr->msg_flags,
-                                       &io->msg.uaddr, &io->msg.iov);
+       ret = io_recvmsg_copy_hdr(req, io);
        if (!ret)
                req->flags |= REQ_F_NEED_CLEANUP;
        return ret;
-#else
-       return -EOPNOTSUPP;
-#endif
 }
 
-static int io_recvmsg(struct io_kiocb *req, struct io_kiocb **nxt,
-                     bool force_nonblock)
+static int io_recvmsg(struct io_kiocb *req, bool force_nonblock)
 {
-#if defined(CONFIG_NET)
        struct io_async_msghdr *kmsg = NULL;
        struct socket *sock;
-       int ret;
+       int ret, cflags = 0;
 
        if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
                return -EINVAL;
 
        sock = sock_from_file(req->file, &ret);
        if (sock) {
+               struct io_buffer *kbuf;
                struct io_async_ctx io;
                unsigned flags;
 
@@ -3195,19 +3810,23 @@ static int io_recvmsg(struct io_kiocb *req, struct io_kiocb **nxt,
                                kmsg->iov = kmsg->fast_iov;
                        kmsg->msg.msg_iter.iov = kmsg->iov;
                } else {
-                       struct io_sr_msg *sr = &req->sr_msg;
-
                        kmsg = &io.msg;
                        kmsg->msg.msg_name = &io.msg.addr;
 
-                       io.msg.iov = io.msg.fast_iov;
-                       ret = recvmsg_copy_msghdr(&io.msg.msg, sr->msg,
-                                       sr->msg_flags, &io.msg.uaddr,
-                                       &io.msg.iov);
+                       ret = io_recvmsg_copy_hdr(req, &io);
                        if (ret)
                                return ret;
                }
 
+               kbuf = io_recv_buffer_select(req, &cflags, !force_nonblock);
+               if (IS_ERR(kbuf)) {
+                       return PTR_ERR(kbuf);
+               } else if (kbuf) {
+                       kmsg->fast_iov[0].iov_base = u64_to_user_ptr(kbuf->addr);
+                       iov_iter_init(&kmsg->msg.msg_iter, READ, kmsg->iov,
+                                       1, req->sr_msg.len);
+               }
+
                flags = req->sr_msg.msg_flags;
                if (flags & MSG_DONTWAIT)
                        req->flags |= REQ_F_NOWAIT;
@@ -3216,18 +3835,8 @@ static int io_recvmsg(struct io_kiocb *req, struct io_kiocb **nxt,
 
                ret = __sys_recvmsg_sock(sock, &kmsg->msg, req->sr_msg.msg,
                                                kmsg->uaddr, flags);
-               if (force_nonblock && ret == -EAGAIN) {
-                       if (req->io)
-                               return -EAGAIN;
-                       if (io_alloc_async_ctx(req)) {
-                               if (kmsg->iov != kmsg->fast_iov)
-                                       kfree(kmsg->iov);
-                               return -ENOMEM;
-                       }
-                       memcpy(&req->io->msg, &io.msg, sizeof(io.msg));
-                       req->flags |= REQ_F_NEED_CLEANUP;
-                       return -EAGAIN;
-               }
+               if (force_nonblock && ret == -EAGAIN)
+                       return io_setup_async_msg(req, kmsg);
                if (ret == -ERESTARTSYS)
                        ret = -EINTR;
        }
@@ -3235,22 +3844,18 @@ static int io_recvmsg(struct io_kiocb *req, struct io_kiocb **nxt,
        if (kmsg && kmsg->iov != kmsg->fast_iov)
                kfree(kmsg->iov);
        req->flags &= ~REQ_F_NEED_CLEANUP;
-       io_cqring_add_event(req, ret);
+       __io_cqring_add_event(req, ret, cflags);
        if (ret < 0)
                req_set_fail_links(req);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
 }
 
-static int io_recv(struct io_kiocb *req, struct io_kiocb **nxt,
-                  bool force_nonblock)
+static int io_recv(struct io_kiocb *req, bool force_nonblock)
 {
-#if defined(CONFIG_NET)
+       struct io_buffer *kbuf = NULL;
        struct socket *sock;
-       int ret;
+       int ret, cflags = 0;
 
        if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
                return -EINVAL;
@@ -3258,15 +3863,25 @@ static int io_recv(struct io_kiocb *req, struct io_kiocb **nxt,
        sock = sock_from_file(req->file, &ret);
        if (sock) {
                struct io_sr_msg *sr = &req->sr_msg;
+               void __user *buf = sr->buf;
                struct msghdr msg;
                struct iovec iov;
                unsigned flags;
 
-               ret = import_single_range(READ, sr->buf, sr->len, &iov,
+               kbuf = io_recv_buffer_select(req, &cflags, !force_nonblock);
+               if (IS_ERR(kbuf))
+                       return PTR_ERR(kbuf);
+               else if (kbuf)
+                       buf = u64_to_user_ptr(kbuf->addr);
+
+               ret = import_single_range(READ, buf, sr->len, &iov,
                                                &msg.msg_iter);
-               if (ret)
+               if (ret) {
+                       kfree(kbuf);
                        return ret;
+               }
 
+               req->flags |= REQ_F_NEED_CLEANUP;
                msg.msg_name = NULL;
                msg.msg_control = NULL;
                msg.msg_controllen = 0;
@@ -3287,20 +3902,17 @@ static int io_recv(struct io_kiocb *req, struct io_kiocb **nxt,
                        ret = -EINTR;
        }
 
-       io_cqring_add_event(req, ret);
+       kfree(kbuf);
+       req->flags &= ~REQ_F_NEED_CLEANUP;
+       __io_cqring_add_event(req, ret, cflags);
        if (ret < 0)
                req_set_fail_links(req);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
 }
 
-
 static int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
-#if defined(CONFIG_NET)
        struct io_accept *accept = &req->accept;
 
        if (unlikely(req->ctx->flags & (IORING_SETUP_IOPOLL|IORING_SETUP_SQPOLL)))
@@ -3311,15 +3923,11 @@ static int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
        accept->addr = u64_to_user_ptr(READ_ONCE(sqe->addr));
        accept->addr_len = u64_to_user_ptr(READ_ONCE(sqe->addr2));
        accept->flags = READ_ONCE(sqe->accept_flags);
+       accept->nofile = rlimit(RLIMIT_NOFILE);
        return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
 }
 
-#if defined(CONFIG_NET)
-static int __io_accept(struct io_kiocb *req, struct io_kiocb **nxt,
-                      bool force_nonblock)
+static int __io_accept(struct io_kiocb *req, bool force_nonblock)
 {
        struct io_accept *accept = &req->accept;
        unsigned file_flags;
@@ -3327,7 +3935,8 @@ static int __io_accept(struct io_kiocb *req, struct io_kiocb **nxt,
 
        file_flags = force_nonblock ? O_NONBLOCK : 0;
        ret = __sys_accept4_file(req->file, file_flags, accept->addr,
-                                       accept->addr_len, accept->flags);
+                                       accept->addr_len, accept->flags,
+                                       accept->nofile);
        if (ret == -EAGAIN && force_nonblock)
                return -EAGAIN;
        if (ret == -ERESTARTSYS)
@@ -3335,44 +3944,34 @@ static int __io_accept(struct io_kiocb *req, struct io_kiocb **nxt,
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
 }
 
 static void io_accept_finish(struct io_wq_work **workptr)
 {
        struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
-       struct io_kiocb *nxt = NULL;
 
        if (io_req_cancelled(req))
                return;
-       __io_accept(req, &nxt, false);
-       if (nxt)
-               io_wq_assign_next(workptr, nxt);
+       __io_accept(req, false);
+       io_steal_work(req, workptr);
 }
-#endif
 
-static int io_accept(struct io_kiocb *req, struct io_kiocb **nxt,
-                    bool force_nonblock)
+static int io_accept(struct io_kiocb *req, bool force_nonblock)
 {
-#if defined(CONFIG_NET)
        int ret;
 
-       ret = __io_accept(req, nxt, force_nonblock);
+       ret = __io_accept(req, force_nonblock);
        if (ret == -EAGAIN && force_nonblock) {
                req->work.func = io_accept_finish;
-               io_put_req(req);
                return -EAGAIN;
        }
        return 0;
-#else
-       return -EOPNOTSUPP;
-#endif
 }
 
 static int io_connect_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
-#if defined(CONFIG_NET)
        struct io_connect *conn = &req->connect;
        struct io_async_ctx *io = req->io;
 
@@ -3389,15 +3988,10 @@ static int io_connect_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 
        return move_addr_to_kernel(conn->addr, conn->addr_len,
                                        &io->connect.address);
-#else
-       return -EOPNOTSUPP;
-#endif
 }
 
-static int io_connect(struct io_kiocb *req, struct io_kiocb **nxt,
-                     bool force_nonblock)
+static int io_connect(struct io_kiocb *req, bool force_nonblock)
 {
-#if defined(CONFIG_NET)
        struct io_async_ctx __io, *io;
        unsigned file_flags;
        int ret;
@@ -3433,25 +4027,301 @@ out:
        if (ret < 0)
                req_set_fail_links(req);
        io_cqring_add_event(req, ret);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
        return 0;
-#else
+}
+#else /* !CONFIG_NET */
+static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
        return -EOPNOTSUPP;
-#endif
 }
 
-static void io_poll_remove_one(struct io_kiocb *req)
+static int io_sendmsg(struct io_kiocb *req, bool force_nonblock)
 {
-       struct io_poll_iocb *poll = &req->poll;
+       return -EOPNOTSUPP;
+}
+
+static int io_send(struct io_kiocb *req, bool force_nonblock)
+{
+       return -EOPNOTSUPP;
+}
+
+static int io_recvmsg_prep(struct io_kiocb *req,
+                          const struct io_uring_sqe *sqe)
+{
+       return -EOPNOTSUPP;
+}
+
+static int io_recvmsg(struct io_kiocb *req, bool force_nonblock)
+{
+       return -EOPNOTSUPP;
+}
+
+static int io_recv(struct io_kiocb *req, bool force_nonblock)
+{
+       return -EOPNOTSUPP;
+}
+
+static int io_accept_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       return -EOPNOTSUPP;
+}
+
+static int io_accept(struct io_kiocb *req, bool force_nonblock)
+{
+       return -EOPNOTSUPP;
+}
+
+static int io_connect_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
+{
+       return -EOPNOTSUPP;
+}
+
+static int io_connect(struct io_kiocb *req, bool force_nonblock)
+{
+       return -EOPNOTSUPP;
+}
+#endif /* CONFIG_NET */
+
+struct io_poll_table {
+       struct poll_table_struct pt;
+       struct io_kiocb *req;
+       int error;
+};
+
+static void __io_queue_proc(struct io_poll_iocb *poll, struct io_poll_table *pt,
+                           struct wait_queue_head *head)
+{
+       if (unlikely(poll->head)) {
+               pt->error = -EINVAL;
+               return;
+       }
+
+       pt->error = 0;
+       poll->head = head;
+       add_wait_queue(head, &poll->wait);
+}
+
+static void io_async_queue_proc(struct file *file, struct wait_queue_head *head,
+                              struct poll_table_struct *p)
+{
+       struct io_poll_table *pt = container_of(p, struct io_poll_table, pt);
+
+       __io_queue_proc(&pt->req->apoll->poll, pt, head);
+}
+
+static int __io_async_wake(struct io_kiocb *req, struct io_poll_iocb *poll,
+                          __poll_t mask, task_work_func_t func)
+{
+       struct task_struct *tsk;
+
+       /* for instances that support it check for an event match first: */
+       if (mask && !(mask & poll->events))
+               return 0;
+
+       trace_io_uring_task_add(req->ctx, req->opcode, req->user_data, mask);
+
+       list_del_init(&poll->wait.entry);
+
+       tsk = req->task;
+       req->result = mask;
+       init_task_work(&req->task_work, func);
+       /*
+        * If this fails, then the task is exiting. If that is the case, then
+        * the exit check will ultimately cancel these work items. Hence we
+        * don't need to check here and handle it specifically.
+        */
+       task_work_add(tsk, &req->task_work, true);
+       wake_up_process(tsk);
+       return 1;
+}
+
+static void io_async_task_func(struct callback_head *cb)
+{
+       struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work);
+       struct async_poll *apoll = req->apoll;
+       struct io_ring_ctx *ctx = req->ctx;
+
+       trace_io_uring_task_run(req->ctx, req->opcode, req->user_data);
+
+       WARN_ON_ONCE(!list_empty(&req->apoll->poll.wait.entry));
+
+       if (hash_hashed(&req->hash_node)) {
+               spin_lock_irq(&ctx->completion_lock);
+               hash_del(&req->hash_node);
+               spin_unlock_irq(&ctx->completion_lock);
+       }
+
+       /* restore ->work in case we need to retry again */
+       memcpy(&req->work, &apoll->work, sizeof(req->work));
+
+       __set_current_state(TASK_RUNNING);
+       mutex_lock(&ctx->uring_lock);
+       __io_queue_sqe(req, NULL);
+       mutex_unlock(&ctx->uring_lock);
+
+       kfree(apoll);
+}
+
+static int io_async_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
+                       void *key)
+{
+       struct io_kiocb *req = wait->private;
+       struct io_poll_iocb *poll = &req->apoll->poll;
+
+       trace_io_uring_poll_wake(req->ctx, req->opcode, req->user_data,
+                                       key_to_poll(key));
+
+       return __io_async_wake(req, poll, key_to_poll(key), io_async_task_func);
+}
+
+static void io_poll_req_insert(struct io_kiocb *req)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       struct hlist_head *list;
+
+       list = &ctx->cancel_hash[hash_long(req->user_data, ctx->cancel_hash_bits)];
+       hlist_add_head(&req->hash_node, list);
+}
+
+static __poll_t __io_arm_poll_handler(struct io_kiocb *req,
+                                     struct io_poll_iocb *poll,
+                                     struct io_poll_table *ipt, __poll_t mask,
+                                     wait_queue_func_t wake_func)
+       __acquires(&ctx->completion_lock)
+{
+       struct io_ring_ctx *ctx = req->ctx;
+       bool cancel = false;
+
+       poll->file = req->file;
+       poll->head = NULL;
+       poll->done = poll->canceled = false;
+       poll->events = mask;
+
+       ipt->pt._key = mask;
+       ipt->req = req;
+       ipt->error = -EINVAL;
+
+       INIT_LIST_HEAD(&poll->wait.entry);
+       init_waitqueue_func_entry(&poll->wait, wake_func);
+       poll->wait.private = req;
+
+       mask = vfs_poll(req->file, &ipt->pt) & poll->events;
+
+       spin_lock_irq(&ctx->completion_lock);
+       if (likely(poll->head)) {
+               spin_lock(&poll->head->lock);
+               if (unlikely(list_empty(&poll->wait.entry))) {
+                       if (ipt->error)
+                               cancel = true;
+                       ipt->error = 0;
+                       mask = 0;
+               }
+               if (mask || ipt->error)
+                       list_del_init(&poll->wait.entry);
+               else if (cancel)
+                       WRITE_ONCE(poll->canceled, true);
+               else if (!poll->done) /* actually waiting for an event */
+                       io_poll_req_insert(req);
+               spin_unlock(&poll->head->lock);
+       }
+
+       return mask;
+}
+
+static bool io_arm_poll_handler(struct io_kiocb *req)
+{
+       const struct io_op_def *def = &io_op_defs[req->opcode];
+       struct io_ring_ctx *ctx = req->ctx;
+       struct async_poll *apoll;
+       struct io_poll_table ipt;
+       __poll_t mask, ret;
+
+       if (!req->file || !file_can_poll(req->file))
+               return false;
+       if (req->flags & (REQ_F_MUST_PUNT | REQ_F_POLLED))
+               return false;
+       if (!def->pollin && !def->pollout)
+               return false;
+
+       apoll = kmalloc(sizeof(*apoll), GFP_ATOMIC);
+       if (unlikely(!apoll))
+               return false;
+
+       req->flags |= REQ_F_POLLED;
+       memcpy(&apoll->work, &req->work, sizeof(req->work));
+
+       /*
+        * Don't need a reference here, as we're adding it to the task
+        * task_works list. If the task exits, the list is pruned.
+        */
+       req->task = current;
+       req->apoll = apoll;
+       INIT_HLIST_NODE(&req->hash_node);
+
+       mask = 0;
+       if (def->pollin)
+               mask |= POLLIN | POLLRDNORM;
+       if (def->pollout)
+               mask |= POLLOUT | POLLWRNORM;
+       mask |= POLLERR | POLLPRI;
+
+       ipt.pt._qproc = io_async_queue_proc;
+
+       ret = __io_arm_poll_handler(req, &apoll->poll, &ipt, mask,
+                                       io_async_wake);
+       if (ret) {
+               ipt.error = 0;
+               apoll->poll.done = true;
+               spin_unlock_irq(&ctx->completion_lock);
+               memcpy(&req->work, &apoll->work, sizeof(req->work));
+               kfree(apoll);
+               return false;
+       }
+       spin_unlock_irq(&ctx->completion_lock);
+       trace_io_uring_poll_arm(ctx, req->opcode, req->user_data, mask,
+                                       apoll->poll.events);
+       return true;
+}
+
+static bool __io_poll_remove_one(struct io_kiocb *req,
+                                struct io_poll_iocb *poll)
+{
+       bool do_complete = false;
 
        spin_lock(&poll->head->lock);
        WRITE_ONCE(poll->canceled, true);
        if (!list_empty(&poll->wait.entry)) {
                list_del_init(&poll->wait.entry);
-               io_queue_async_work(req);
+               do_complete = true;
        }
        spin_unlock(&poll->head->lock);
+       return do_complete;
+}
+
+static bool io_poll_remove_one(struct io_kiocb *req)
+{
+       bool do_complete;
+
+       if (req->opcode == IORING_OP_POLL_ADD) {
+               do_complete = __io_poll_remove_one(req, &req->poll);
+       } else {
+               /* non-poll requests have submit ref still */
+               do_complete = __io_poll_remove_one(req, &req->apoll->poll);
+               if (do_complete)
+                       io_put_req(req);
+       }
+
        hash_del(&req->hash_node);
+
+       if (do_complete) {
+               io_cqring_fill_event(req, -ECANCELED);
+               io_commit_cqring(req->ctx);
+               req->flags |= REQ_F_COMP_LOCKED;
+               io_put_req(req);
+       }
+
+       return do_complete;
 }
 
 static void io_poll_remove_all(struct io_ring_ctx *ctx)
@@ -3469,6 +4339,8 @@ static void io_poll_remove_all(struct io_ring_ctx *ctx)
                        io_poll_remove_one(req);
        }
        spin_unlock_irq(&ctx->completion_lock);
+
+       io_cqring_ev_posted(ctx);
 }
 
 static int io_poll_cancel(struct io_ring_ctx *ctx, __u64 sqe_addr)
@@ -3478,10 +4350,11 @@ static int io_poll_cancel(struct io_ring_ctx *ctx, __u64 sqe_addr)
 
        list = &ctx->cancel_hash[hash_long(sqe_addr, ctx->cancel_hash_bits)];
        hlist_for_each_entry(req, list, hash_node) {
-               if (sqe_addr == req->user_data) {
-                       io_poll_remove_one(req);
+               if (sqe_addr != req->user_data)
+                       continue;
+               if (io_poll_remove_one(req))
                        return 0;
-               }
+               return -EALREADY;
        }
 
        return -ENOENT;
@@ -3522,191 +4395,59 @@ static int io_poll_remove(struct io_kiocb *req)
        return 0;
 }
 
-static void io_poll_complete(struct io_kiocb *req, __poll_t mask, int error)
-{
-       struct io_ring_ctx *ctx = req->ctx;
-
-       req->poll.done = true;
-       if (error)
-               io_cqring_fill_event(req, error);
-       else
-               io_cqring_fill_event(req, mangle_poll(mask));
-       io_commit_cqring(ctx);
-}
-
-static void io_poll_complete_work(struct io_wq_work **workptr)
-{
-       struct io_wq_work *work = *workptr;
-       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
-       struct io_poll_iocb *poll = &req->poll;
-       struct poll_table_struct pt = { ._key = poll->events };
-       struct io_ring_ctx *ctx = req->ctx;
-       struct io_kiocb *nxt = NULL;
-       __poll_t mask = 0;
-       int ret = 0;
-
-       if (work->flags & IO_WQ_WORK_CANCEL) {
-               WRITE_ONCE(poll->canceled, true);
-               ret = -ECANCELED;
-       } else if (READ_ONCE(poll->canceled)) {
-               ret = -ECANCELED;
-       }
-
-       if (ret != -ECANCELED)
-               mask = vfs_poll(poll->file, &pt) & poll->events;
-
-       /*
-        * Note that ->ki_cancel callers also delete iocb from active_reqs after
-        * calling ->ki_cancel.  We need the ctx_lock roundtrip here to
-        * synchronize with them.  In the cancellation case the list_del_init
-        * itself is not actually needed, but harmless so we keep it in to
-        * avoid further branches in the fast path.
-        */
-       spin_lock_irq(&ctx->completion_lock);
-       if (!mask && ret != -ECANCELED) {
-               add_wait_queue(poll->head, &poll->wait);
-               spin_unlock_irq(&ctx->completion_lock);
-               return;
-       }
-       hash_del(&req->hash_node);
-       io_poll_complete(req, mask, ret);
-       spin_unlock_irq(&ctx->completion_lock);
-
-       io_cqring_ev_posted(ctx);
-
-       if (ret < 0)
-               req_set_fail_links(req);
-       io_put_req_find_next(req, &nxt);
-       if (nxt)
-               io_wq_assign_next(workptr, nxt);
-}
-
-static void __io_poll_flush(struct io_ring_ctx *ctx, struct llist_node *nodes)
-{
-       struct io_kiocb *req, *tmp;
-       struct req_batch rb;
-
-       rb.to_free = rb.need_iter = 0;
-       spin_lock_irq(&ctx->completion_lock);
-       llist_for_each_entry_safe(req, tmp, nodes, llist_node) {
-               hash_del(&req->hash_node);
-               io_poll_complete(req, req->result, 0);
-
-               if (refcount_dec_and_test(&req->refs) &&
-                   !io_req_multi_free(&rb, req)) {
-                       req->flags |= REQ_F_COMP_LOCKED;
-                       io_free_req(req);
-               }
-       }
-       spin_unlock_irq(&ctx->completion_lock);
-
-       io_cqring_ev_posted(ctx);
-       io_free_req_many(ctx, &rb);
-}
-
-static void io_poll_flush(struct io_wq_work **workptr)
-{
-       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
-       struct llist_node *nodes;
-
-       nodes = llist_del_all(&req->ctx->poll_llist);
-       if (nodes)
-               __io_poll_flush(req->ctx, nodes);
-}
-
-static void io_poll_trigger_evfd(struct io_wq_work **workptr)
+static void io_poll_complete(struct io_kiocb *req, __poll_t mask, int error)
 {
-       struct io_kiocb *req = container_of(*workptr, struct io_kiocb, work);
+       struct io_ring_ctx *ctx = req->ctx;
 
-       eventfd_signal(req->ctx->cq_ev_fd, 1);
-       io_put_req(req);
+       req->poll.done = true;
+       io_cqring_fill_event(req, error ? error : mangle_poll(mask));
+       io_commit_cqring(ctx);
 }
 
-static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
-                       void *key)
+static void io_poll_task_handler(struct io_kiocb *req, struct io_kiocb **nxt)
 {
-       struct io_poll_iocb *poll = wait->private;
-       struct io_kiocb *req = container_of(poll, struct io_kiocb, poll);
        struct io_ring_ctx *ctx = req->ctx;
-       __poll_t mask = key_to_poll(key);
 
-       /* for instances that support it check for an event match first: */
-       if (mask && !(mask & poll->events))
-               return 0;
-
-       list_del_init(&poll->wait.entry);
+       spin_lock_irq(&ctx->completion_lock);
+       hash_del(&req->hash_node);
+       io_poll_complete(req, req->result, 0);
+       req->flags |= REQ_F_COMP_LOCKED;
+       io_put_req_find_next(req, nxt);
+       spin_unlock_irq(&ctx->completion_lock);
 
-       /*
-        * Run completion inline if we can. We're using trylock here because
-        * we are violating the completion_lock -> poll wq lock ordering.
-        * If we have a link timeout we're going to need the completion_lock
-        * for finalizing the request, mark us as having grabbed that already.
-        */
-       if (mask) {
-               unsigned long flags;
+       io_cqring_ev_posted(ctx);
+}
 
-               if (llist_empty(&ctx->poll_llist) &&
-                   spin_trylock_irqsave(&ctx->completion_lock, flags)) {
-                       bool trigger_ev;
+static void io_poll_task_func(struct callback_head *cb)
+{
+       struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work);
+       struct io_kiocb *nxt = NULL;
 
-                       hash_del(&req->hash_node);
-                       io_poll_complete(req, mask, 0);
+       io_poll_task_handler(req, &nxt);
+       if (nxt) {
+               struct io_ring_ctx *ctx = nxt->ctx;
 
-                       trigger_ev = io_should_trigger_evfd(ctx);
-                       if (trigger_ev && eventfd_signal_count()) {
-                               trigger_ev = false;
-                               req->work.func = io_poll_trigger_evfd;
-                       } else {
-                               req->flags |= REQ_F_COMP_LOCKED;
-                               io_put_req(req);
-                               req = NULL;
-                       }
-                       spin_unlock_irqrestore(&ctx->completion_lock, flags);
-                       __io_cqring_ev_posted(ctx, trigger_ev);
-               } else {
-                       req->result = mask;
-                       req->llist_node.next = NULL;
-                       /* if the list wasn't empty, we're done */
-                       if (!llist_add(&req->llist_node, &ctx->poll_llist))
-                               req = NULL;
-                       else
-                               req->work.func = io_poll_flush;
-               }
+               mutex_lock(&ctx->uring_lock);
+               __io_queue_sqe(nxt, NULL);
+               mutex_unlock(&ctx->uring_lock);
        }
-       if (req)
-               io_queue_async_work(req);
-
-       return 1;
 }
 
-struct io_poll_table {
-       struct poll_table_struct pt;
-       struct io_kiocb *req;
-       int error;
-};
-
-static void io_poll_queue_proc(struct file *file, struct wait_queue_head *head,
-                              struct poll_table_struct *p)
+static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync,
+                       void *key)
 {
-       struct io_poll_table *pt = container_of(p, struct io_poll_table, pt);
-
-       if (unlikely(pt->req->poll.head)) {
-               pt->error = -EINVAL;
-               return;
-       }
+       struct io_kiocb *req = wait->private;
+       struct io_poll_iocb *poll = &req->poll;
 
-       pt->error = 0;
-       pt->req->poll.head = head;
-       add_wait_queue(head, &pt->req->poll.wait);
+       return __io_async_wake(req, poll, key_to_poll(key), io_poll_task_func);
 }
 
-static void io_poll_req_insert(struct io_kiocb *req)
+static void io_poll_queue_proc(struct file *file, struct wait_queue_head *head,
+                              struct poll_table_struct *p)
 {
-       struct io_ring_ctx *ctx = req->ctx;
-       struct hlist_head *list;
+       struct io_poll_table *pt = container_of(p, struct io_poll_table, pt);
 
-       list = &ctx->cancel_hash[hash_long(req->user_data, ctx->cancel_hash_bits)];
-       hlist_add_head(&req->hash_node, list);
+       __io_queue_proc(&pt->req->poll, pt, head);
 }
 
 static int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
@@ -3723,55 +4464,29 @@ static int io_poll_add_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe
 
        events = READ_ONCE(sqe->poll_events);
        poll->events = demangle_poll(events) | EPOLLERR | EPOLLHUP;
+
+       /*
+        * Don't need a reference here, as we're adding it to the task
+        * task_works list. If the task exits, the list is pruned.
+        */
+       req->task = current;
        return 0;
 }
 
-static int io_poll_add(struct io_kiocb *req, struct io_kiocb **nxt)
+static int io_poll_add(struct io_kiocb *req)
 {
        struct io_poll_iocb *poll = &req->poll;
        struct io_ring_ctx *ctx = req->ctx;
        struct io_poll_table ipt;
-       bool cancel = false;
        __poll_t mask;
 
-       INIT_IO_WORK(&req->work, io_poll_complete_work);
        INIT_HLIST_NODE(&req->hash_node);
-
-       poll->head = NULL;
-       poll->done = false;
-       poll->canceled = false;
-
-       ipt.pt._qproc = io_poll_queue_proc;
-       ipt.pt._key = poll->events;
-       ipt.req = req;
-       ipt.error = -EINVAL; /* same as no support for IOCB_CMD_POLL */
-
-       /* initialized the list so that we can do list_empty checks */
-       INIT_LIST_HEAD(&poll->wait.entry);
-       init_waitqueue_func_entry(&poll->wait, io_poll_wake);
-       poll->wait.private = poll;
-
        INIT_LIST_HEAD(&req->list);
+       ipt.pt._qproc = io_poll_queue_proc;
 
-       mask = vfs_poll(poll->file, &ipt.pt) & poll->events;
+       mask = __io_arm_poll_handler(req, &req->poll, &ipt, poll->events,
+                                       io_poll_wake);
 
-       spin_lock_irq(&ctx->completion_lock);
-       if (likely(poll->head)) {
-               spin_lock(&poll->head->lock);
-               if (unlikely(list_empty(&poll->wait.entry))) {
-                       if (ipt.error)
-                               cancel = true;
-                       ipt.error = 0;
-                       mask = 0;
-               }
-               if (mask || ipt.error)
-                       list_del_init(&poll->wait.entry);
-               else if (cancel)
-                       WRITE_ONCE(poll->canceled, true);
-               else if (!poll->done) /* actually waiting for an event */
-                       io_poll_req_insert(req);
-               spin_unlock(&poll->head->lock);
-       }
        if (mask) { /* no async, we'd stolen it */
                ipt.error = 0;
                io_poll_complete(req, mask, 0);
@@ -3780,7 +4495,7 @@ static int io_poll_add(struct io_kiocb *req, struct io_kiocb **nxt)
 
        if (mask) {
                io_cqring_ev_posted(ctx);
-               io_put_req_find_next(req, nxt);
+               io_put_req(req);
        }
        return ipt.error;
 }
@@ -4029,7 +4744,7 @@ static int io_async_cancel_one(struct io_ring_ctx *ctx, void *sqe_addr)
 
 static void io_async_find_and_cancel(struct io_ring_ctx *ctx,
                                     struct io_kiocb *req, __u64 sqe_addr,
-                                    struct io_kiocb **nxt, int success_ret)
+                                    int success_ret)
 {
        unsigned long flags;
        int ret;
@@ -4055,7 +4770,7 @@ done:
 
        if (ret < 0)
                req_set_fail_links(req);
-       io_put_req_find_next(req, nxt);
+       io_put_req(req);
 }
 
 static int io_async_cancel_prep(struct io_kiocb *req,
@@ -4071,11 +4786,11 @@ static int io_async_cancel_prep(struct io_kiocb *req,
        return 0;
 }
 
-static int io_async_cancel(struct io_kiocb *req, struct io_kiocb **nxt)
+static int io_async_cancel(struct io_kiocb *req)
 {
        struct io_ring_ctx *ctx = req->ctx;
 
-       io_async_find_and_cancel(ctx, req, req->cancel.addr, nxt, 0);
+       io_async_find_and_cancel(ctx, req, req->cancel.addr, 0);
        return 0;
 }
 
@@ -4121,6 +4836,9 @@ static int io_req_defer_prep(struct io_kiocb *req,
 {
        ssize_t ret = 0;
 
+       if (!sqe)
+               return 0;
+
        if (io_op_defs[req->opcode].file_table) {
                ret = io_grab_files(req);
                if (unlikely(ret))
@@ -4207,6 +4925,15 @@ static int io_req_defer_prep(struct io_kiocb *req,
        case IORING_OP_EPOLL_CTL:
                ret = io_epoll_ctl_prep(req, sqe);
                break;
+       case IORING_OP_SPLICE:
+               ret = io_splice_prep(req, sqe);
+               break;
+       case IORING_OP_PROVIDE_BUFFERS:
+               ret = io_provide_buffers_prep(req, sqe);
+               break;
+       case IORING_OP_REMOVE_BUFFERS:
+               ret = io_remove_buffers_prep(req, sqe);
+               break;
        default:
                printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
                                req->opcode);
@@ -4253,29 +4980,43 @@ static void io_cleanup_req(struct io_kiocb *req)
        case IORING_OP_READV:
        case IORING_OP_READ_FIXED:
        case IORING_OP_READ:
+               if (req->flags & REQ_F_BUFFER_SELECTED)
+                       kfree((void *)(unsigned long)req->rw.addr);
+               /* fallthrough */
        case IORING_OP_WRITEV:
        case IORING_OP_WRITE_FIXED:
        case IORING_OP_WRITE:
                if (io->rw.iov != io->rw.fast_iov)
                        kfree(io->rw.iov);
                break;
-       case IORING_OP_SENDMSG:
        case IORING_OP_RECVMSG:
+               if (req->flags & REQ_F_BUFFER_SELECTED)
+                       kfree(req->sr_msg.kbuf);
+               /* fallthrough */
+       case IORING_OP_SENDMSG:
                if (io->msg.iov != io->msg.fast_iov)
                        kfree(io->msg.iov);
                break;
+       case IORING_OP_RECV:
+               if (req->flags & REQ_F_BUFFER_SELECTED)
+                       kfree(req->sr_msg.kbuf);
+               break;
        case IORING_OP_OPENAT:
        case IORING_OP_OPENAT2:
        case IORING_OP_STATX:
                putname(req->open.filename);
                break;
+       case IORING_OP_SPLICE:
+               io_put_file(req, req->splice.file_in,
+                           (req->splice.flags & SPLICE_F_FD_IN_FIXED));
+               break;
        }
 
        req->flags &= ~REQ_F_NEED_CLEANUP;
 }
 
 static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
-                       struct io_kiocb **nxt, bool force_nonblock)
+                       bool force_nonblock)
 {
        struct io_ring_ctx *ctx = req->ctx;
        int ret;
@@ -4292,7 +5033,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret < 0)
                                break;
                }
-               ret = io_read(req, nxt, force_nonblock);
+               ret = io_read(req, force_nonblock);
                break;
        case IORING_OP_WRITEV:
        case IORING_OP_WRITE_FIXED:
@@ -4302,7 +5043,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret < 0)
                                break;
                }
-               ret = io_write(req, nxt, force_nonblock);
+               ret = io_write(req, force_nonblock);
                break;
        case IORING_OP_FSYNC:
                if (sqe) {
@@ -4310,7 +5051,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret < 0)
                                break;
                }
-               ret = io_fsync(req, nxt, force_nonblock);
+               ret = io_fsync(req, force_nonblock);
                break;
        case IORING_OP_POLL_ADD:
                if (sqe) {
@@ -4318,7 +5059,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_poll_add(req, nxt);
+               ret = io_poll_add(req);
                break;
        case IORING_OP_POLL_REMOVE:
                if (sqe) {
@@ -4334,7 +5075,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret < 0)
                                break;
                }
-               ret = io_sync_file_range(req, nxt, force_nonblock);
+               ret = io_sync_file_range(req, force_nonblock);
                break;
        case IORING_OP_SENDMSG:
        case IORING_OP_SEND:
@@ -4344,9 +5085,9 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                                break;
                }
                if (req->opcode == IORING_OP_SENDMSG)
-                       ret = io_sendmsg(req, nxt, force_nonblock);
+                       ret = io_sendmsg(req, force_nonblock);
                else
-                       ret = io_send(req, nxt, force_nonblock);
+                       ret = io_send(req, force_nonblock);
                break;
        case IORING_OP_RECVMSG:
        case IORING_OP_RECV:
@@ -4356,9 +5097,9 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                                break;
                }
                if (req->opcode == IORING_OP_RECVMSG)
-                       ret = io_recvmsg(req, nxt, force_nonblock);
+                       ret = io_recvmsg(req, force_nonblock);
                else
-                       ret = io_recv(req, nxt, force_nonblock);
+                       ret = io_recv(req, force_nonblock);
                break;
        case IORING_OP_TIMEOUT:
                if (sqe) {
@@ -4382,7 +5123,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_accept(req, nxt, force_nonblock);
+               ret = io_accept(req, force_nonblock);
                break;
        case IORING_OP_CONNECT:
                if (sqe) {
@@ -4390,7 +5131,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_connect(req, nxt, force_nonblock);
+               ret = io_connect(req, force_nonblock);
                break;
        case IORING_OP_ASYNC_CANCEL:
                if (sqe) {
@@ -4398,7 +5139,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_async_cancel(req, nxt);
+               ret = io_async_cancel(req);
                break;
        case IORING_OP_FALLOCATE:
                if (sqe) {
@@ -4406,7 +5147,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_fallocate(req, nxt, force_nonblock);
+               ret = io_fallocate(req, force_nonblock);
                break;
        case IORING_OP_OPENAT:
                if (sqe) {
@@ -4414,7 +5155,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_openat(req, nxt, force_nonblock);
+               ret = io_openat(req, force_nonblock);
                break;
        case IORING_OP_CLOSE:
                if (sqe) {
@@ -4422,7 +5163,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_close(req, nxt, force_nonblock);
+               ret = io_close(req, force_nonblock);
                break;
        case IORING_OP_FILES_UPDATE:
                if (sqe) {
@@ -4438,7 +5179,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_statx(req, nxt, force_nonblock);
+               ret = io_statx(req, force_nonblock);
                break;
        case IORING_OP_FADVISE:
                if (sqe) {
@@ -4446,7 +5187,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_fadvise(req, nxt, force_nonblock);
+               ret = io_fadvise(req, force_nonblock);
                break;
        case IORING_OP_MADVISE:
                if (sqe) {
@@ -4454,7 +5195,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_madvise(req, nxt, force_nonblock);
+               ret = io_madvise(req, force_nonblock);
                break;
        case IORING_OP_OPENAT2:
                if (sqe) {
@@ -4462,7 +5203,7 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_openat2(req, nxt, force_nonblock);
+               ret = io_openat2(req, force_nonblock);
                break;
        case IORING_OP_EPOLL_CTL:
                if (sqe) {
@@ -4470,7 +5211,31 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                        if (ret)
                                break;
                }
-               ret = io_epoll_ctl(req, nxt, force_nonblock);
+               ret = io_epoll_ctl(req, force_nonblock);
+               break;
+       case IORING_OP_SPLICE:
+               if (sqe) {
+                       ret = io_splice_prep(req, sqe);
+                       if (ret < 0)
+                               break;
+               }
+               ret = io_splice(req, force_nonblock);
+               break;
+       case IORING_OP_PROVIDE_BUFFERS:
+               if (sqe) {
+                       ret = io_provide_buffers_prep(req, sqe);
+                       if (ret)
+                               break;
+               }
+               ret = io_provide_buffers(req, force_nonblock);
+               break;
+       case IORING_OP_REMOVE_BUFFERS:
+               if (sqe) {
+                       ret = io_remove_buffers_prep(req, sqe);
+                       if (ret)
+                               break;
+               }
+               ret = io_remove_buffers(req, force_nonblock);
                break;
        default:
                ret = -EINVAL;
@@ -4503,7 +5268,6 @@ static void io_wq_submit_work(struct io_wq_work **workptr)
 {
        struct io_wq_work *work = *workptr;
        struct io_kiocb *req = container_of(work, struct io_kiocb, work);
-       struct io_kiocb *nxt = NULL;
        int ret = 0;
 
        /* if NO_CANCEL is set, we must still run the work */
@@ -4513,9 +5277,8 @@ static void io_wq_submit_work(struct io_wq_work **workptr)
        }
 
        if (!ret) {
-               req->in_async = true;
                do {
-                       ret = io_issue_sqe(req, NULL, &nxt, false);
+                       ret = io_issue_sqe(req, NULL, false);
                        /*
                         * We can get EAGAIN for polled IO even though we're
                         * forcing a sync submission from here, since we can't
@@ -4527,18 +5290,13 @@ static void io_wq_submit_work(struct io_wq_work **workptr)
                } while (1);
        }
 
-       /* drop submission reference */
-       io_put_req(req);
-
        if (ret) {
                req_set_fail_links(req);
                io_cqring_add_event(req, ret);
                io_put_req(req);
        }
 
-       /* if a dependent link is ready, pass it back */
-       if (!ret && nxt)
-               io_wq_assign_next(workptr, nxt);
+       io_steal_work(req, workptr);
 }
 
 static int io_req_needs_file(struct io_kiocb *req, int fd)
@@ -4559,41 +5317,52 @@ static inline struct file *io_file_from_index(struct io_ring_ctx *ctx,
        return table->files[index & IORING_FILE_TABLE_MASK];;
 }
 
-static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req,
-                          const struct io_uring_sqe *sqe)
+static int io_file_get(struct io_submit_state *state, struct io_kiocb *req,
+                       int fd, struct file **out_file, bool fixed)
 {
        struct io_ring_ctx *ctx = req->ctx;
-       unsigned flags;
-       int fd;
-
-       flags = READ_ONCE(sqe->flags);
-       fd = READ_ONCE(sqe->fd);
-
-       if (!io_req_needs_file(req, fd))
-               return 0;
+       struct file *file;
 
-       if (flags & IOSQE_FIXED_FILE) {
+       if (fixed) {
                if (unlikely(!ctx->file_data ||
                    (unsigned) fd >= ctx->nr_user_files))
                        return -EBADF;
                fd = array_index_nospec(fd, ctx->nr_user_files);
-               req->file = io_file_from_index(ctx, fd);
-               if (!req->file)
+               file = io_file_from_index(ctx, fd);
+               if (!file)
                        return -EBADF;
-               req->flags |= REQ_F_FIXED_FILE;
                percpu_ref_get(&ctx->file_data->refs);
        } else {
-               if (req->needs_fixed_file)
-                       return -EBADF;
                trace_io_uring_file_get(ctx, fd);
-               req->file = io_file_get(state, fd);
-               if (unlikely(!req->file))
+               file = __io_file_get(state, fd);
+               if (unlikely(!file))
                        return -EBADF;
        }
 
+       *out_file = file;
        return 0;
 }
 
+static int io_req_set_file(struct io_submit_state *state, struct io_kiocb *req,
+                          const struct io_uring_sqe *sqe)
+{
+       unsigned flags;
+       int fd;
+       bool fixed;
+
+       flags = READ_ONCE(sqe->flags);
+       fd = READ_ONCE(sqe->fd);
+
+       if (!io_req_needs_file(req, fd))
+               return 0;
+
+       fixed = (flags & IOSQE_FIXED_FILE);
+       if (unlikely(!fixed && req->needs_fixed_file))
+               return -EBADF;
+
+       return io_file_get(state, req, fd, &req->file, fixed);
+}
+
 static int io_grab_files(struct io_kiocb *req)
 {
        int ret = -EBADF;
@@ -4653,8 +5422,7 @@ static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer)
 
        if (prev) {
                req_set_fail_links(prev);
-               io_async_find_and_cancel(ctx, req, prev->user_data, NULL,
-                                               -ETIME);
+               io_async_find_and_cancel(ctx, req, prev->user_data, -ETIME);
                io_put_req(prev);
        } else {
                io_cqring_add_event(req, -ETIME);
@@ -4691,6 +5459,9 @@ static struct io_kiocb *io_prep_linked_timeout(struct io_kiocb *req)
 
        if (!(req->flags & REQ_F_LINK))
                return NULL;
+       /* for polled retry, if flag is set, we already went through here */
+       if (req->flags & REQ_F_POLLED)
+               return NULL;
 
        nxt = list_first_entry_or_null(&req->link_list, struct io_kiocb,
                                        link_list);
@@ -4704,13 +5475,23 @@ static struct io_kiocb *io_prep_linked_timeout(struct io_kiocb *req)
 static void __io_queue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_kiocb *linked_timeout;
-       struct io_kiocb *nxt = NULL;
+       struct io_kiocb *nxt;
+       const struct cred *old_creds = NULL;
        int ret;
 
 again:
        linked_timeout = io_prep_linked_timeout(req);
 
-       ret = io_issue_sqe(req, sqe, &nxt, true);
+       if (req->work.creds && req->work.creds != current_cred()) {
+               if (old_creds)
+                       revert_creds(old_creds);
+               if (old_creds == req->work.creds)
+                       old_creds = NULL; /* restored original creds */
+               else
+                       old_creds = override_creds(req->work.creds);
+       }
+
+       ret = io_issue_sqe(req, sqe, true);
 
        /*
         * We async punt it if the file wasn't marked NOWAIT, or if the file
@@ -4718,6 +5499,11 @@ again:
         */
        if (ret == -EAGAIN && (!(req->flags & REQ_F_NOWAIT) ||
            (req->flags & REQ_F_MUST_PUNT))) {
+               if (io_arm_poll_handler(req)) {
+                       if (linked_timeout)
+                               io_queue_linked_timeout(linked_timeout);
+                       goto exit;
+               }
 punt:
                if (io_op_defs[req->opcode].file_table) {
                        ret = io_grab_files(req);
@@ -4730,12 +5516,13 @@ punt:
                 * submit reference when the iocb is actually submitted.
                 */
                io_queue_async_work(req);
-               goto done_req;
+               goto exit;
        }
 
 err:
+       nxt = NULL;
        /* drop submission reference */
-       io_put_req(req);
+       io_put_req_find_next(req, &nxt);
 
        if (linked_timeout) {
                if (!ret)
@@ -4750,15 +5537,16 @@ err:
                req_set_fail_links(req);
                io_put_req(req);
        }
-done_req:
        if (nxt) {
                req = nxt;
-               nxt = NULL;
 
                if (req->flags & REQ_F_FORCE_ASYNC)
                        goto punt;
                goto again;
        }
+exit:
+       if (old_creds)
+               revert_creds(old_creds);
 }
 
 static void io_queue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe)
@@ -4798,12 +5586,12 @@ static inline void io_queue_link_head(struct io_kiocb *req)
 }
 
 #define SQE_VALID_FLAGS        (IOSQE_FIXED_FILE|IOSQE_IO_DRAIN|IOSQE_IO_LINK| \
-                               IOSQE_IO_HARDLINK | IOSQE_ASYNC)
+                               IOSQE_IO_HARDLINK | IOSQE_ASYNC | \
+                               IOSQE_BUFFER_SELECT)
 
 static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                          struct io_submit_state *state, struct io_kiocb **link)
 {
-       const struct cred *old_creds = NULL;
        struct io_ring_ctx *ctx = req->ctx;
        unsigned int sqe_flags;
        int ret, id;
@@ -4816,29 +5604,32 @@ static bool io_submit_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
                goto err_req;
        }
 
+       if ((sqe_flags & IOSQE_BUFFER_SELECT) &&
+           !io_op_defs[req->opcode].buffer_select) {
+               ret = -EOPNOTSUPP;
+               goto err_req;
+       }
+
        id = READ_ONCE(sqe->personality);
        if (id) {
-               const struct cred *personality_creds;
-
-               personality_creds = idr_find(&ctx->personality_idr, id);
-               if (unlikely(!personality_creds)) {
+               req->work.creds = idr_find(&ctx->personality_idr, id);
+               if (unlikely(!req->work.creds)) {
                        ret = -EINVAL;
                        goto err_req;
                }
-               old_creds = override_creds(personality_creds);
+               get_cred(req->work.creds);
        }
 
        /* same numerical values with corresponding REQ_F_*, safe to copy */
-       req->flags |= sqe_flags & (IOSQE_IO_DRAIN|IOSQE_IO_HARDLINK|
-                                       IOSQE_ASYNC);
+       req->flags |= sqe_flags & (IOSQE_IO_DRAIN | IOSQE_IO_HARDLINK |
+                                       IOSQE_ASYNC | IOSQE_FIXED_FILE |
+                                       IOSQE_BUFFER_SELECT);
 
        ret = io_req_set_file(state, req, sqe);
        if (unlikely(ret)) {
 err_req:
                io_cqring_add_event(req, ret);
                io_double_put_req(req);
-               if (old_creds)
-                       revert_creds(old_creds);
                return false;
        }
 
@@ -4890,6 +5681,11 @@ err_req:
                if (sqe_flags & (IOSQE_IO_LINK|IOSQE_IO_HARDLINK)) {
                        req->flags |= REQ_F_LINK;
                        INIT_LIST_HEAD(&req->link_list);
+
+                       if (io_alloc_async_ctx(req)) {
+                               ret = -EAGAIN;
+                               goto err_req;
+                       }
                        ret = io_req_defer_prep(req, sqe);
                        if (ret)
                                req->flags |= REQ_F_FAIL_LINK;
@@ -4899,8 +5695,6 @@ err_req:
                }
        }
 
-       if (old_creds)
-               revert_creds(old_creds);
        return true;
 }
 
@@ -5050,7 +5844,6 @@ fail_req:
                        *mm = ctx->sqo_mm;
                }
 
-               req->in_async = async;
                req->needs_fixed_file = async;
                trace_io_uring_submit_sqe(ctx, req->opcode, req->user_data,
                                                true, async);
@@ -5081,9 +5874,8 @@ static int io_sq_thread(void *data)
        const struct cred *old_cred;
        mm_segment_t old_fs;
        DEFINE_WAIT(wait);
-       unsigned inflight;
        unsigned long timeout;
-       int ret;
+       int ret = 0;
 
        complete(&ctx->completions[1]);
 
@@ -5091,39 +5883,19 @@ static int io_sq_thread(void *data)
        set_fs(USER_DS);
        old_cred = override_creds(ctx->creds);
 
-       ret = timeout = inflight = 0;
+       timeout = jiffies + ctx->sq_thread_idle;
        while (!kthread_should_park()) {
                unsigned int to_submit;
 
-               if (inflight) {
+               if (!list_empty(&ctx->poll_list)) {
                        unsigned nr_events = 0;
 
-                       if (ctx->flags & IORING_SETUP_IOPOLL) {
-                               /*
-                                * inflight is the count of the maximum possible
-                                * entries we submitted, but it can be smaller
-                                * if we dropped some of them. If we don't have
-                                * poll entries available, then we know that we
-                                * have nothing left to poll for. Reset the
-                                * inflight count to zero in that case.
-                                */
-                               mutex_lock(&ctx->uring_lock);
-                               if (!list_empty(&ctx->poll_list))
-                                       io_iopoll_getevents(ctx, &nr_events, 0);
-                               else
-                                       inflight = 0;
-                               mutex_unlock(&ctx->uring_lock);
-                       } else {
-                               /*
-                                * Normal IO, just pretend everything completed.
-                                * We don't have to poll completions for that.
-                                */
-                               nr_events = inflight;
-                       }
-
-                       inflight -= nr_events;
-                       if (!inflight)
+                       mutex_lock(&ctx->uring_lock);
+                       if (!list_empty(&ctx->poll_list))
+                               io_iopoll_getevents(ctx, &nr_events, 0);
+                       else
                                timeout = jiffies + ctx->sq_thread_idle;
+                       mutex_unlock(&ctx->uring_lock);
                }
 
                to_submit = io_sqring_entries(ctx);
@@ -5152,9 +5924,11 @@ static int io_sq_thread(void *data)
                         * more IO, we should wait for the application to
                         * reap events and wake us up.
                         */
-                       if (inflight ||
+                       if (!list_empty(&ctx->poll_list) ||
                            (!time_after(jiffies, timeout) && ret != -EBUSY &&
                            !percpu_ref_is_dying(&ctx->refs))) {
+                               if (current->task_works)
+                                       task_work_run();
                                cond_resched();
                                continue;
                        }
@@ -5162,6 +5936,19 @@ static int io_sq_thread(void *data)
                        prepare_to_wait(&ctx->sqo_wait, &wait,
                                                TASK_INTERRUPTIBLE);
 
+                       /*
+                        * While doing polled IO, before going to sleep, we need
+                        * to check if there are new reqs added to poll_list, it
+                        * is because reqs may have been punted to io worker and
+                        * will be added to poll_list later, hence check the
+                        * poll_list again.
+                        */
+                       if ((ctx->flags & IORING_SETUP_IOPOLL) &&
+                           !list_empty_careful(&ctx->poll_list)) {
+                               finish_wait(&ctx->sqo_wait, &wait);
+                               continue;
+                       }
+
                        /* Tell userspace we may need a wakeup call */
                        ctx->rings->sq_flags |= IORING_SQ_NEED_WAKEUP;
                        /* make sure to read SQ tail after writing flags */
@@ -5173,6 +5960,10 @@ static int io_sq_thread(void *data)
                                        finish_wait(&ctx->sqo_wait, &wait);
                                        break;
                                }
+                               if (current->task_works) {
+                                       task_work_run();
+                                       continue;
+                               }
                                if (signal_pending(current))
                                        flush_signals(current);
                                schedule();
@@ -5189,10 +5980,12 @@ static int io_sq_thread(void *data)
                mutex_lock(&ctx->uring_lock);
                ret = io_submit_sqes(ctx, to_submit, NULL, -1, &cur_mm, true);
                mutex_unlock(&ctx->uring_lock);
-               if (ret > 0)
-                       inflight += ret;
+               timeout = jiffies + ctx->sq_thread_idle;
        }
 
+       if (current->task_works)
+               task_work_run();
+
        set_fs(old_fs);
        if (cur_mm) {
                unuse_mm(cur_mm);
@@ -5257,8 +6050,13 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
        struct io_rings *rings = ctx->rings;
        int ret = 0;
 
-       if (io_cqring_events(ctx, false) >= min_events)
-               return 0;
+       do {
+               if (io_cqring_events(ctx, false) >= min_events)
+                       return 0;
+               if (!current->task_works)
+                       break;
+               task_work_run();
+       } while (1);
 
        if (sig) {
 #ifdef CONFIG_COMPAT
@@ -5278,6 +6076,8 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events,
        do {
                prepare_to_wait_exclusive(&ctx->wait, &iowq.wq,
                                                TASK_INTERRUPTIBLE);
+               if (current->task_works)
+                       task_work_run();
                if (io_should_wake(&iowq, false))
                        break;
                schedule();
@@ -5324,6 +6124,23 @@ static void io_file_ref_kill(struct percpu_ref *ref)
        complete(&data->done);
 }
 
+static void io_file_ref_exit_and_free(struct work_struct *work)
+{
+       struct fixed_file_data *data;
+
+       data = container_of(work, struct fixed_file_data, ref_work);
+
+       /*
+        * Ensure any percpu-ref atomic switch callback has run, it could have
+        * been in progress when the files were being unregistered. Once
+        * that's done, we can safely exit and free the ref and containing
+        * data structure.
+        */
+       rcu_barrier();
+       percpu_ref_exit(&data->refs);
+       kfree(data);
+}
+
 static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
 {
        struct fixed_file_data *data = ctx->file_data;
@@ -5336,14 +6153,14 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
        flush_work(&data->ref_work);
        wait_for_completion(&data->done);
        io_ring_file_ref_flush(data);
-       percpu_ref_exit(&data->refs);
 
        __io_sqe_files_unregister(ctx);
        nr_tables = DIV_ROUND_UP(ctx->nr_user_files, IORING_MAX_FILES_TABLE);
        for (i = 0; i < nr_tables; i++)
                kfree(data->table[i].files);
        kfree(data->table);
-       kfree(data);
+       INIT_WORK(&data->ref_work, io_file_ref_exit_and_free);
+       queue_work(system_wq, &data->ref_work);
        ctx->file_data = NULL;
        ctx->nr_user_files = 0;
        return 0;
@@ -5570,7 +6387,6 @@ static void io_ring_file_put(struct io_ring_ctx *ctx, struct file *file)
 struct io_file_put {
        struct llist_node llist;
        struct file *file;
-       struct completion *done;
 };
 
 static void io_ring_file_ref_flush(struct fixed_file_data *data)
@@ -5581,10 +6397,7 @@ static void io_ring_file_ref_flush(struct fixed_file_data *data)
        while ((node = llist_del_all(&data->put_llist)) != NULL) {
                llist_for_each_entry_safe(pfile, tmp, node, llist) {
                        io_ring_file_put(data->ctx, pfile->file);
-                       if (pfile->done)
-                               complete(pfile->done);
-                       else
-                               kfree(pfile);
+                       kfree(pfile);
                }
        }
 }
@@ -5595,7 +6408,6 @@ static void io_ring_file_ref_switch(struct work_struct *work)
 
        data = container_of(work, struct fixed_file_data, ref_work);
        io_ring_file_ref_flush(data);
-       percpu_ref_get(&data->refs);
        percpu_ref_switch_to_percpu(&data->refs);
 }
 
@@ -5771,41 +6583,27 @@ static void io_atomic_switch(struct percpu_ref *ref)
 {
        struct fixed_file_data *data;
 
+       /*
+        * Juggle reference to ensure we hit zero, if needed, so we can
+        * switch back to percpu mode
+        */
        data = container_of(ref, struct fixed_file_data, refs);
-       clear_bit(FFD_F_ATOMIC, &data->state);
+       percpu_ref_put(&data->refs);
+       percpu_ref_get(&data->refs);
 }
 
-static bool io_queue_file_removal(struct fixed_file_data *data,
+static int io_queue_file_removal(struct fixed_file_data *data,
                                  struct file *file)
 {
-       struct io_file_put *pfile, pfile_stack;
-       DECLARE_COMPLETION_ONSTACK(done);
+       struct io_file_put *pfile;
 
-       /*
-        * If we fail allocating the struct we need for doing async reomval
-        * of this file, just punt to sync and wait for it.
-        */
        pfile = kzalloc(sizeof(*pfile), GFP_KERNEL);
-       if (!pfile) {
-               pfile = &pfile_stack;
-               pfile->done = &done;
-       }
+       if (!pfile)
+               return -ENOMEM;
 
        pfile->file = file;
        llist_add(&pfile->llist, &data->put_llist);
-
-       if (pfile == &pfile_stack) {
-               if (!test_and_set_bit(FFD_F_ATOMIC, &data->state)) {
-                       percpu_ref_put(&data->refs);
-                       percpu_ref_switch_to_atomic(&data->refs,
-                                                       io_atomic_switch);
-               }
-               wait_for_completion(&done);
-               flush_work(&data->ref_work);
-               return false;
-       }
-
-       return true;
+       return 0;
 }
 
 static int __io_sqe_files_update(struct io_ring_ctx *ctx,
@@ -5840,9 +6638,11 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                index = i & IORING_FILE_TABLE_MASK;
                if (table->files[index]) {
                        file = io_file_from_index(ctx, index);
+                       err = io_queue_file_removal(data, file);
+                       if (err)
+                               break;
                        table->files[index] = NULL;
-                       if (io_queue_file_removal(data, file))
-                               ref_switch = true;
+                       ref_switch = true;
                }
                if (fd != -1) {
                        file = fget(fd);
@@ -5873,10 +6673,8 @@ static int __io_sqe_files_update(struct io_ring_ctx *ctx,
                up->offset++;
        }
 
-       if (ref_switch && !test_and_set_bit(FFD_F_ATOMIC, &data->state)) {
-               percpu_ref_put(&data->refs);
+       if (ref_switch)
                percpu_ref_switch_to_atomic(&data->refs, io_atomic_switch);
-       }
 
        return done ? done : err;
 }
@@ -5897,20 +6695,14 @@ static int io_sqe_files_update(struct io_ring_ctx *ctx, void __user *arg,
        return __io_sqe_files_update(ctx, &up, nr_args);
 }
 
-static void io_put_work(struct io_wq_work *work)
+static void io_free_work(struct io_wq_work *work)
 {
        struct io_kiocb *req = container_of(work, struct io_kiocb, work);
 
+       /* Consider that io_steal_work() relies on this ref */
        io_put_req(req);
 }
 
-static void io_get_work(struct io_wq_work *work)
-{
-       struct io_kiocb *req = container_of(work, struct io_kiocb, work);
-
-       refcount_inc(&req->refs);
-}
-
 static int io_init_wq_offload(struct io_ring_ctx *ctx,
                              struct io_uring_params *p)
 {
@@ -5921,8 +6713,7 @@ static int io_init_wq_offload(struct io_ring_ctx *ctx,
        int ret = 0;
 
        data.user = ctx->user;
-       data.get_work = io_get_work;
-       data.put_work = io_put_work;
+       data.free_work = io_free_work;
 
        if (!(p->flags & IORING_SETUP_ATTACH_WQ)) {
                /* Do QD, or 4 * CPUS, whatever is smallest */
@@ -6324,6 +7115,21 @@ static int io_eventfd_unregister(struct io_ring_ctx *ctx)
        return -ENXIO;
 }
 
+static int __io_destroy_buffers(int id, void *p, void *data)
+{
+       struct io_ring_ctx *ctx = data;
+       struct io_buffer *buf = p;
+
+       __io_remove_buffers(ctx, buf, id, -1U);
+       return 0;
+}
+
+static void io_destroy_buffers(struct io_ring_ctx *ctx)
+{
+       idr_for_each(&ctx->io_buffer_idr, __io_destroy_buffers, ctx);
+       idr_destroy(&ctx->io_buffer_idr);
+}
+
 static void io_ring_ctx_free(struct io_ring_ctx *ctx)
 {
        io_finish_async(ctx);
@@ -6334,6 +7140,8 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx)
        io_sqe_buffer_unregister(ctx);
        io_sqe_files_unregister(ctx);
        io_eventfd_unregister(ctx);
+       io_destroy_buffers(ctx);
+       idr_destroy(&ctx->personality_idr);
 
 #if defined(CONFIG_UNIX)
        if (ctx->ring_sock) {
@@ -6587,6 +7395,9 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
        int submitted = 0;
        struct fd f;
 
+       if (current->task_works)
+               task_work_run();
+
        if (flags & ~(IORING_ENTER_GETEVENTS | IORING_ENTER_SQ_WAKEUP))
                return -EINVAL;
 
@@ -6633,7 +7444,14 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
 
                min_complete = min(min_complete, ctx->cq_entries);
 
-               if (ctx->flags & IORING_SETUP_IOPOLL) {
+               /*
+                * When SETUP_IOPOLL and SETUP_SQPOLL are both enabled, user
+                * space applications don't need to do io completion events
+                * polling again, they can rely on io_sq_thread to do polling
+                * work, which can reduce cpu usage and uring_lock contention.
+                */
+               if (ctx->flags & IORING_SETUP_IOPOLL &&
+                   !(ctx->flags & IORING_SETUP_SQPOLL)) {
                        ret = io_iopoll_check(ctx, &nr_events, min_complete);
                } else {
                        ret = io_cqring_wait(ctx, min_complete, sig, sigsz);
@@ -6647,6 +7465,7 @@ out_fput:
        return submitted ? submitted : ret;
 }
 
+#ifdef CONFIG_PROC_FS
 static int io_uring_show_cred(int id, void *p, void *data)
 {
        const struct cred *cred = p;
@@ -6708,6 +7527,17 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
                seq_printf(m, "Personalities:\n");
                idr_for_each(&ctx->personality_idr, io_uring_show_cred, m);
        }
+       seq_printf(m, "PollList:\n");
+       spin_lock_irq(&ctx->completion_lock);
+       for (i = 0; i < (1U << ctx->cancel_hash_bits); i++) {
+               struct hlist_head *list = &ctx->cancel_hash[i];
+               struct io_kiocb *req;
+
+               hlist_for_each_entry(req, list, hash_node)
+                       seq_printf(m, "  op=%d, task_works=%d\n", req->opcode,
+                                       req->task->task_works != NULL);
+       }
+       spin_unlock_irq(&ctx->completion_lock);
        mutex_unlock(&ctx->uring_lock);
 }
 
@@ -6720,6 +7550,7 @@ static void io_uring_show_fdinfo(struct seq_file *m, struct file *f)
                percpu_ref_put(&ctx->refs);
        }
 }
+#endif
 
 static const struct file_operations io_uring_fops = {
        .release        = io_uring_release,
@@ -6731,7 +7562,9 @@ static const struct file_operations io_uring_fops = {
 #endif
        .poll           = io_uring_poll,
        .fasync         = io_uring_fasync,
+#ifdef CONFIG_PROC_FS
        .show_fdinfo    = io_uring_show_fdinfo,
+#endif
 };
 
 static int io_allocate_scq_urings(struct io_ring_ctx *ctx,
@@ -6921,7 +7754,7 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p)
 
        p->features = IORING_FEAT_SINGLE_MMAP | IORING_FEAT_NODROP |
                        IORING_FEAT_SUBMIT_STABLE | IORING_FEAT_RW_CUR_POS |
-                       IORING_FEAT_CUR_PERSONALITY;
+                       IORING_FEAT_CUR_PERSONALITY | IORING_FEAT_FAST_POLL;
        trace_io_uring_create(ret, ctx, p->sq_entries, p->cq_entries, p->flags);
        return ret;
 err:
@@ -7199,6 +8032,7 @@ static int __init io_uring_init(void)
        BUILD_BUG_SQE_ELEM(8,  __u64,  off);
        BUILD_BUG_SQE_ELEM(8,  __u64,  addr2);
        BUILD_BUG_SQE_ELEM(16, __u64,  addr);
+       BUILD_BUG_SQE_ELEM(16, __u64,  splice_off_in);
        BUILD_BUG_SQE_ELEM(24, __u32,  len);
        BUILD_BUG_SQE_ELEM(28,     __kernel_rwf_t, rw_flags);
        BUILD_BUG_SQE_ELEM(28, /* compat */   int, rw_flags);
@@ -7213,11 +8047,14 @@ static int __init io_uring_init(void)
        BUILD_BUG_SQE_ELEM(28, __u32,  open_flags);
        BUILD_BUG_SQE_ELEM(28, __u32,  statx_flags);
        BUILD_BUG_SQE_ELEM(28, __u32,  fadvise_advice);
+       BUILD_BUG_SQE_ELEM(28, __u32,  splice_flags);
        BUILD_BUG_SQE_ELEM(32, __u64,  user_data);
        BUILD_BUG_SQE_ELEM(40, __u16,  buf_index);
        BUILD_BUG_SQE_ELEM(42, __u16,  personality);
+       BUILD_BUG_SQE_ELEM(44, __s32,  splice_fd_in);
 
        BUILD_BUG_ON(ARRAY_SIZE(io_op_defs) != IORING_OP_LAST);
+       BUILD_BUG_ON(__REQ_F_LAST_BIT >= 8 * sizeof(int));
        req_cachep = KMEM_CACHE(io_kiocb, SLAB_HWCACHE_ALIGN | SLAB_PANIC);
        return 0;
 };
index d181948..3dccc23 100644 (file)
@@ -1150,8 +1150,8 @@ static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh,
        /* For undo access buffer must have data copied */
        if (undo && !jh->b_committed_data)
                goto out;
-       if (jh->b_transaction != handle->h_transaction &&
-           jh->b_next_transaction != handle->h_transaction)
+       if (READ_ONCE(jh->b_transaction) != handle->h_transaction &&
+           READ_ONCE(jh->b_next_transaction) != handle->h_transaction)
                goto out;
        /*
         * There are two reasons for the barrier here:
@@ -2569,8 +2569,8 @@ bool __jbd2_journal_refile_buffer(struct journal_head *jh)
         * our jh reference and thus __jbd2_journal_file_buffer() must not
         * take a new one.
         */
-       jh->b_transaction = jh->b_next_transaction;
-       jh->b_next_transaction = NULL;
+       WRITE_ONCE(jh->b_transaction, jh->b_next_transaction);
+       WRITE_ONCE(jh->b_next_transaction, NULL);
        if (buffer_freed(bh))
                jlist = BJ_Forget;
        else if (jh->b_modified)
index c686bd9..3759fba 100644 (file)
@@ -891,7 +891,7 @@ int simple_attr_open(struct inode *inode, struct file *file,
 {
        struct simple_attr *attr;
 
-       attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+       attr = kzalloc(sizeof(*attr), GFP_KERNEL);
        if (!attr)
                return -ENOMEM;
 
@@ -931,9 +931,11 @@ ssize_t simple_attr_read(struct file *file, char __user *buf,
        if (ret)
                return ret;
 
-       if (*ppos) {            /* continued read */
+       if (*ppos && attr->get_buf[0]) {
+               /* continued read */
                size = strlen(attr->get_buf);
-       } else {                /* first read */
+       } else {
+               /* first read */
                u64 val;
                ret = attr->get(attr->data, &val);
                if (ret)
index 44b6da0..b8a31c1 100644 (file)
@@ -725,7 +725,6 @@ static void __locks_delete_block(struct file_lock *waiter)
 {
        locks_delete_global_blocked(waiter);
        list_del_init(&waiter->fl_blocked_member);
-       waiter->fl_blocker = NULL;
 }
 
 static void __locks_wake_up_blocks(struct file_lock *blocker)
@@ -740,6 +739,13 @@ static void __locks_wake_up_blocks(struct file_lock *blocker)
                        waiter->fl_lmops->lm_notify(waiter);
                else
                        wake_up(&waiter->fl_wait);
+
+               /*
+                * The setting of fl_blocker to NULL marks the "done"
+                * point in deleting a block. Paired with acquire at the top
+                * of locks_delete_block().
+                */
+               smp_store_release(&waiter->fl_blocker, NULL);
        }
 }
 
@@ -754,24 +760,41 @@ int locks_delete_block(struct file_lock *waiter)
        int status = -ENOENT;
 
        /*
-        * If fl_blocker is NULL, it won't be set again as this thread
-        * "owns" the lock and is the only one that might try to claim
-        * the lock.  So it is safe to test fl_blocker locklessly.
-        * Also if fl_blocker is NULL, this waiter is not listed on
-        * fl_blocked_requests for some lock, so no other request can
-        * be added to the list of fl_blocked_requests for this
-        * request.  So if fl_blocker is NULL, it is safe to
-        * locklessly check if fl_blocked_requests is empty.  If both
-        * of these checks succeed, there is no need to take the lock.
+        * If fl_blocker is NULL, it won't be set again as this thread "owns"
+        * the lock and is the only one that might try to claim the lock.
+        *
+        * We use acquire/release to manage fl_blocker so that we can
+        * optimize away taking the blocked_lock_lock in many cases.
+        *
+        * The smp_load_acquire guarantees two things:
+        *
+        * 1/ that fl_blocked_requests can be tested locklessly. If something
+        * was recently added to that list it must have been in a locked region
+        * *before* the locked region when fl_blocker was set to NULL.
+        *
+        * 2/ that no other thread is accessing 'waiter', so it is safe to free
+        * it.  __locks_wake_up_blocks is careful not to touch waiter after
+        * fl_blocker is released.
+        *
+        * If a lockless check of fl_blocker shows it to be NULL, we know that
+        * no new locks can be inserted into its fl_blocked_requests list, and
+        * can avoid doing anything further if the list is empty.
         */
-       if (waiter->fl_blocker == NULL &&
+       if (!smp_load_acquire(&waiter->fl_blocker) &&
            list_empty(&waiter->fl_blocked_requests))
                return status;
+
        spin_lock(&blocked_lock_lock);
        if (waiter->fl_blocker)
                status = 0;
        __locks_wake_up_blocks(waiter);
        __locks_delete_block(waiter);
+
+       /*
+        * The setting of fl_blocker to NULL marks the "done" point in deleting
+        * a block. Paired with acquire at the top of this function.
+        */
+       smp_store_release(&waiter->fl_blocker, NULL);
        spin_unlock(&blocked_lock_lock);
        return status;
 }
@@ -1364,7 +1387,8 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
                error = posix_lock_inode(inode, fl, NULL);
                if (error != FILE_LOCK_DEFERRED)
                        break;
-               error = wait_event_interruptible(fl->fl_wait, !fl->fl_blocker);
+               error = wait_event_interruptible(fl->fl_wait,
+                                       list_empty(&fl->fl_blocked_member));
                if (error)
                        break;
        }
@@ -1449,7 +1473,8 @@ int locks_mandatory_area(struct inode *inode, struct file *filp, loff_t start,
                error = posix_lock_inode(inode, &fl, NULL);
                if (error != FILE_LOCK_DEFERRED)
                        break;
-               error = wait_event_interruptible(fl.fl_wait, !fl.fl_blocker);
+               error = wait_event_interruptible(fl.fl_wait,
+                                       list_empty(&fl.fl_blocked_member));
                if (!error) {
                        /*
                         * If we've been sleeping someone might have
@@ -1652,7 +1677,8 @@ restart:
 
        locks_dispose_list(&dispose);
        error = wait_event_interruptible_timeout(new_fl->fl_wait,
-                                               !new_fl->fl_blocker, break_time);
+                                       list_empty(&new_fl->fl_blocked_member),
+                                       break_time);
 
        percpu_down_read(&file_rwsem);
        spin_lock(&ctx->flc_lock);
@@ -2136,7 +2162,8 @@ static int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
                error = flock_lock_inode(inode, fl);
                if (error != FILE_LOCK_DEFERRED)
                        break;
-               error = wait_event_interruptible(fl->fl_wait, !fl->fl_blocker);
+               error = wait_event_interruptible(fl->fl_wait,
+                               list_empty(&fl->fl_blocked_member));
                if (error)
                        break;
        }
@@ -2413,7 +2440,8 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd,
                error = vfs_lock_file(filp, cmd, fl, NULL);
                if (error != FILE_LOCK_DEFERRED)
                        break;
-               error = wait_event_interruptible(fl->fl_wait, !fl->fl_blocker);
+               error = wait_event_interruptible(fl->fl_wait,
+                                       list_empty(&fl->fl_blocked_member));
                if (error)
                        break;
        }
index 40b6c5a..88e1763 100644 (file)
@@ -164,7 +164,7 @@ config ROOT_NFS
          If you want your system to mount its root file system via NFS,
          choose Y here.  This is common practice for managing systems
          without local permanent storage.  For details, read
-         <file:Documentation/filesystems/nfs/nfsroot.txt>.
+         <file:Documentation/admin-guide/nfs/nfsroot.rst>.
 
          Most people say N here.
 
index 989c30c..f1ff307 100644 (file)
@@ -153,6 +153,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
        if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
                goto error_0;
 
+       clp->cl_minorversion = cl_init->minorversion;
        clp->cl_nfs_mod = cl_init->nfs_mod;
        if (!try_module_get(clp->cl_nfs_mod->owner))
                goto error_dealloc;
index 193d6fb..d4b839b 100644 (file)
@@ -2489,7 +2489,7 @@ static int nfs_access_get_cached_rcu(struct inode *inode, const struct cred *cre
        rcu_read_lock();
        if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)
                goto out;
-       lh = rcu_dereference(nfsi->access_cache_entry_lru.prev);
+       lh = rcu_dereference(list_tail_rcu(&nfsi->access_cache_entry_lru));
        cache = list_entry(lh, struct nfs_access_entry, lru);
        if (lh == &nfsi->access_cache_entry_lru ||
            cred_fscmp(cred, cache->cred) != 0)
index e1b9384..e113fcb 100644 (file)
@@ -832,6 +832,8 @@ static int nfs_parse_source(struct fs_context *fc,
        if (len > maxnamlen)
                goto out_hostname;
 
+       kfree(ctx->nfs_server.hostname);
+
        /* N.B. caller will free nfs_server.hostname in all cases */
        ctx->nfs_server.hostname = kmemdup_nul(dev_name, len, GFP_KERNEL);
        if (!ctx->nfs_server.hostname)
@@ -1240,6 +1242,13 @@ static int nfs_fs_context_validate(struct fs_context *fc)
                }
                ctx->nfs_mod = nfs_mod;
        }
+
+       /* Ensure the filesystem context has the correct fs_type */
+       if (fc->fs_type != ctx->nfs_mod->nfs_fs) {
+               module_put(fc->fs_type->owner);
+               __module_get(ctx->nfs_mod->nfs_fs->owner);
+               fc->fs_type = ctx->nfs_mod->nfs_fs;
+       }
        return 0;
 
 out_no_device_name:
index 52270bf..1abf126 100644 (file)
@@ -31,6 +31,7 @@ static DEFINE_SPINLOCK(nfs_fscache_keys_lock);
 struct nfs_server_key {
        struct {
                uint16_t        nfsversion;             /* NFS protocol version */
+               uint32_t        minorversion;           /* NFSv4 minor version */
                uint16_t        family;                 /* address family */
                __be16          port;                   /* IP port */
        } hdr;
@@ -55,6 +56,7 @@ void nfs_fscache_get_client_cookie(struct nfs_client *clp)
 
        memset(&key, 0, sizeof(key));
        key.hdr.nfsversion = clp->rpc_ops->version;
+       key.hdr.minorversion = clp->cl_minorversion;
        key.hdr.family = clp->cl_addr.ss_family;
 
        switch (clp->cl_addr.ss_family) {
index ad60774..f3ece8e 100644 (file)
@@ -153,7 +153,7 @@ struct vfsmount *nfs_d_automount(struct path *path)
        /* Open a new filesystem context, transferring parameters from the
         * parent superblock, including the network namespace.
         */
-       fc = fs_context_for_submount(&nfs_fs_type, path->dentry);
+       fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, path->dentry);
        if (IS_ERR(fc))
                return ERR_CAST(fc);
 
index 0cd767e..0bd77cc 100644 (file)
@@ -216,7 +216,6 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
        INIT_LIST_HEAD(&clp->cl_ds_clients);
        rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
        clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
-       clp->cl_minorversion = cl_init->minorversion;
        clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
        clp->cl_mig_gen = 1;
 #if IS_ENABLED(CONFIG_NFS_V4_1)
index 7202a1e..554b744 100644 (file)
@@ -92,8 +92,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
                                "0x%llx.", (unsigned long long)bh->b_blocknr);
        }
        first = page_buffers(page);
-       local_irq_save(flags);
-       bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
+       spin_lock_irqsave(&first->b_uptodate_lock, flags);
        clear_buffer_async_read(bh);
        unlock_buffer(bh);
        tmp = bh;
@@ -108,8 +107,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
                }
                tmp = tmp->b_this_page;
        } while (tmp != bh);
-       bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
        /*
         * If none of the buffers had errors then we can set the page uptodate,
         * but we first have to perform the post read mst fixups, if the
@@ -142,8 +140,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
        unlock_page(page);
        return;
 still_busy:
-       bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&first->b_uptodate_lock, flags);
        return;
 }
 
index 0788b37..b69d6ee 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -860,9 +860,6 @@ cleanup_file:
  * the return value of d_splice_alias(), then the caller needs to perform dput()
  * on it after finish_open().
  *
- * On successful return @file is a fully instantiated open file.  After this, if
- * an error occurs in ->atomic_open(), it needs to clean up with fput().
- *
  * Returns zero on success or -errno if the open failed.
  */
 int finish_open(struct file *file, struct dentry *dentry,
index 444e2da..714c14c 100644 (file)
@@ -93,6 +93,7 @@ config OVERLAY_FS_XINO_AUTO
        bool "Overlayfs: auto enable inode number mapping"
        default n
        depends on OVERLAY_FS
+       depends on 64BIT
        help
          If this config option is enabled then overlay filesystems will use
          unused high bits in undelying filesystem inode numbers to map all
index a531721..87c362f 100644 (file)
@@ -244,6 +244,9 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
        if (iocb->ki_flags & IOCB_WRITE) {
                struct inode *inode = file_inode(orig_iocb->ki_filp);
 
+               /* Actually acquired in ovl_write_iter() */
+               __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb,
+                                     SB_FREEZE_WRITE);
                file_end_write(iocb->ki_filp);
                ovl_copyattr(ovl_inode_real(inode), inode);
        }
@@ -346,6 +349,9 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
                        goto out;
 
                file_start_write(real.file);
+               /* Pacify lockdep, same trick as done in aio_write() */
+               __sb_writers_release(file_inode(real.file)->i_sb,
+                                    SB_FREEZE_WRITE);
                aio_req->fd = real;
                real.flags = 0;
                aio_req->orig_iocb = iocb;
index 3623d28..3d3f2b8 100644 (file)
@@ -318,7 +318,12 @@ static inline unsigned int ovl_xino_bits(struct super_block *sb)
        return ovl_same_dev(sb) ? OVL_FS(sb)->xino_mode : 0;
 }
 
-static inline int ovl_inode_lock(struct inode *inode)
+static inline void ovl_inode_lock(struct inode *inode)
+{
+       mutex_lock(&OVL_I(inode)->lock);
+}
+
+static inline int ovl_inode_lock_interruptible(struct inode *inode)
 {
        return mutex_lock_interruptible(&OVL_I(inode)->lock);
 }
index 319fe0d..ac967f1 100644 (file)
@@ -1411,6 +1411,8 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
                if (ofs->config.xino == OVL_XINO_ON)
                        pr_info("\"xino=on\" is useless with all layers on same fs, ignore.\n");
                ofs->xino_mode = 0;
+       } else if (ofs->config.xino == OVL_XINO_OFF) {
+               ofs->xino_mode = -1;
        } else if (ofs->config.xino == OVL_XINO_ON && ofs->xino_mode < 0) {
                /*
                 * This is a roundup of number of bits needed for encoding
@@ -1623,8 +1625,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_stack_depth = 0;
        sb->s_maxbytes = MAX_LFS_FILESIZE;
        /* Assume underlaying fs uses 32bit inodes unless proven otherwise */
-       if (ofs->config.xino != OVL_XINO_OFF)
+       if (ofs->config.xino != OVL_XINO_OFF) {
                ofs->xino_mode = BITS_PER_LONG - 32;
+               if (!ofs->xino_mode) {
+                       pr_warn("xino not supported on 32bit kernel, falling back to xino=off.\n");
+                       ofs->config.xino = OVL_XINO_OFF;
+               }
+       }
 
        /* alloc/destroy_inode needed for setting up traps in inode cache */
        sb->s_op = &ovl_super_operations;
index ea00508..042f7eb 100644 (file)
@@ -509,7 +509,7 @@ int ovl_copy_up_start(struct dentry *dentry, int flags)
        struct inode *inode = d_inode(dentry);
        int err;
 
-       err = ovl_inode_lock(inode);
+       err = ovl_inode_lock_interruptible(inode);
        if (!err && ovl_already_copied_up_locked(dentry, flags)) {
                err = 1; /* Already copied up */
                ovl_inode_unlock(inode);
@@ -764,7 +764,7 @@ int ovl_nlink_start(struct dentry *dentry)
                        return err;
        }
 
-       err = ovl_inode_lock(inode);
+       err = ovl_inode_lock_interruptible(inode);
        if (err)
                return err;
 
index 7fbe8f0..d99b5d3 100644 (file)
@@ -87,11 +87,11 @@ static void *pstore_ftrace_seq_next(struct seq_file *s, void *v, loff_t *pos)
        struct pstore_private *ps = s->private;
        struct pstore_ftrace_seq_data *data = v;
 
+       (*pos)++;
        data->off += REC_SIZE;
        if (data->off + REC_SIZE > ps->total_size)
                return NULL;
 
-       (*pos)++;
        return data;
 }
 
@@ -101,6 +101,9 @@ static int pstore_ftrace_seq_show(struct seq_file *s, void *v)
        struct pstore_ftrace_seq_data *data = v;
        struct pstore_ftrace_record *rec;
 
+       if (!data)
+               return 0;
+
        rec = (struct pstore_ftrace_record *)(ps->record->buf + data->off);
 
        seq_printf(s, "CPU:%d ts:%llu %08lx  %08lx  %ps <- %pS\n",
index d896457..408277e 100644 (file)
@@ -823,9 +823,9 @@ static int __init pstore_init(void)
 
        ret = pstore_init_fs();
        if (ret)
-               return ret;
+               free_buf_for_compression();
 
-       return 0;
+       return ret;
 }
 late_initcall(pstore_init);
 
index 013486b..7956221 100644 (file)
@@ -963,7 +963,6 @@ static void __init ramoops_register_dummy(void)
                pr_info("could not create platform device: %ld\n",
                        PTR_ERR(dummy));
                dummy = NULL;
-               ramoops_unregister_dummy();
        }
 }
 
index 1f4d8c0..c917c19 100644 (file)
@@ -34,7 +34,7 @@ struct persistent_ram_buffer {
        uint32_t    sig;
        atomic_t    start;
        atomic_t    size;
-       uint8_t     data[0];
+       uint8_t     data[];
 };
 
 #define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
index 072156c..5c76633 100644 (file)
@@ -2599,7 +2599,6 @@ static int journal_init_dev(struct super_block *super,
        int result;
        dev_t jdev;
        fmode_t blkdev_mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
-       char b[BDEVNAME_SIZE];
 
        result = 0;
 
@@ -2621,8 +2620,8 @@ static int journal_init_dev(struct super_block *super,
                        result = PTR_ERR(journal->j_dev_bd);
                        journal->j_dev_bd = NULL;
                        reiserfs_warning(super, "sh-458",
-                                        "cannot init journal device '%s': %i",
-                                        __bdevname(jdev, b), result);
+                                        "cannot init journal device unknown-block(%u,%u): %i",
+                                        MAJOR(jdev), MINOR(jdev), result);
                        return result;
                } else if (jdev != super->s_dev)
                        set_blocksize(journal->j_dev_bd, super->s_blocksize);
index d671936..4735def 100644 (file)
@@ -1109,9 +1109,9 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
 /*
  * Determine where to splice to/from.
  */
-static long do_splice(struct file *in, loff_t __user *off_in,
-                     struct file *out, loff_t __user *off_out,
-                     size_t len, unsigned int flags)
+long do_splice(struct file *in, loff_t __user *off_in,
+               struct file *out, loff_t __user *off_out,
+               size_t len, unsigned int flags)
 {
        struct pipe_inode_info *ipipe;
        struct pipe_inode_info *opipe;
index fb87ad3..ef2697b 100644 (file)
@@ -2,6 +2,7 @@ config ZONEFS_FS
        tristate "zonefs filesystem support"
        depends on BLOCK
        depends on BLK_DEV_ZONED
+       select FS_IOMAP
        help
          zonefs is a simple file system which exposes zones of a zoned block
          device (e.g. host-managed or host-aware SMR disk drives) as files.
index 8bc6ef8..3ce9829 100644 (file)
@@ -178,7 +178,8 @@ static void zonefs_update_stats(struct inode *inode, loff_t new_isize)
  * amount of readable data in the zone.
  */
 static loff_t zonefs_check_zone_condition(struct inode *inode,
-                                         struct blk_zone *zone, bool warn)
+                                         struct blk_zone *zone, bool warn,
+                                         bool mount)
 {
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
 
@@ -196,13 +197,26 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
                zone->wp = zone->start;
                return 0;
        case BLK_ZONE_COND_READONLY:
-               /* Do not allow writes in read-only zones */
+               /*
+                * The write pointer of read-only zones is invalid. If such a
+                * zone is found during mount, the file size cannot be retrieved
+                * so we treat the zone as offline (mount == true case).
+                * Otherwise, keep the file size as it was when last updated
+                * so that the user can recover data. In both cases, writes are
+                * always disabled for the zone.
+                */
                if (warn)
                        zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
                                    inode->i_ino);
                inode->i_flags |= S_IMMUTABLE;
+               if (mount) {
+                       zone->cond = BLK_ZONE_COND_OFFLINE;
+                       inode->i_mode &= ~0777;
+                       zone->wp = zone->start;
+                       return 0;
+               }
                inode->i_mode &= ~0222;
-               /* fallthrough */
+               return i_size_read(inode);
        default:
                if (zi->i_ztype == ZONEFS_ZTYPE_CNV)
                        return zi->i_max_size;
@@ -231,7 +245,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
         * as there is no inconsistency between the inode size and the amount of
         * data writen in the zone (data_size).
         */
-       data_size = zonefs_check_zone_condition(inode, zone, true);
+       data_size = zonefs_check_zone_condition(inode, zone, true, false);
        isize = i_size_read(inode);
        if (zone->cond != BLK_ZONE_COND_OFFLINE &&
            zone->cond != BLK_ZONE_COND_READONLY &&
@@ -274,7 +288,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
                if (zone->cond != BLK_ZONE_COND_OFFLINE) {
                        zone->cond = BLK_ZONE_COND_OFFLINE;
                        data_size = zonefs_check_zone_condition(inode, zone,
-                                                               false);
+                                                               false, false);
                }
        } else if (zone->cond == BLK_ZONE_COND_READONLY ||
                   sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO) {
@@ -283,7 +297,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
                if (zone->cond != BLK_ZONE_COND_READONLY) {
                        zone->cond = BLK_ZONE_COND_READONLY;
                        data_size = zonefs_check_zone_condition(inode, zone,
-                                                               false);
+                                                               false, false);
                }
        }
 
@@ -601,13 +615,13 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
        ssize_t ret;
 
        /*
-        * For async direct IOs to sequential zone files, ignore IOCB_NOWAIT
+        * For async direct IOs to sequential zone files, refuse IOCB_NOWAIT
         * as this can cause write reordering (e.g. the first aio gets EAGAIN
         * on the inode lock but the second goes through but is now unaligned).
         */
-       if (zi->i_ztype == ZONEFS_ZTYPE_SEQ && !is_sync_kiocb(iocb)
-           && (iocb->ki_flags & IOCB_NOWAIT))
-               iocb->ki_flags &= ~IOCB_NOWAIT;
+       if (zi->i_ztype == ZONEFS_ZTYPE_SEQ && !is_sync_kiocb(iocb) &&
+           (iocb->ki_flags & IOCB_NOWAIT))
+               return -EOPNOTSUPP;
 
        if (iocb->ki_flags & IOCB_NOWAIT) {
                if (!inode_trylock(inode))
@@ -975,7 +989,7 @@ static void zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
        zi->i_zsector = zone->start;
        zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE,
                               zone->len << SECTOR_SHIFT);
-       zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true);
+       zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true, true);
 
        inode->i_uid = sbi->s_uid;
        inode->i_gid = sbi->s_gid;
index 0c23fd0..a92bea7 100644 (file)
@@ -80,7 +80,7 @@ bool acpi_dev_present(const char *hid, const char *uid, s64 hrv);
 
 #ifdef CONFIG_ACPI
 
-#include <linux/proc_fs.h>
+struct proc_dir_entry;
 
 #define ACPI_BUS_FILE_ROOT     "acpi"
 extern struct proc_dir_entry *acpi_root_dir;
index 8e8be98..87fc14e 100644 (file)
@@ -12,7 +12,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20200110
+#define ACPI_CA_VERSION                 0x20200214
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
@@ -752,7 +752,7 @@ ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u3
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void))
-ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_gpe_status_set(void))
+ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_gpe_status_set(u32 gpe_skip_number))
 ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_any_fixed_event_status_set(void))
 
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
index 02d06b7..4354954 100644 (file)
@@ -862,7 +862,7 @@ enum acpi_erst_instructions {
 /* Command status return values */
 
 enum acpi_erst_command_status {
-       ACPI_ERST_SUCESS = 0,
+       ACPI_ERST_SUCCESS = 0,
        ACPI_ERST_NO_SPACE = 1,
        ACPI_ERST_NOT_AVAILABLE = 2,
        ACPI_ERST_FAILURE = 3,
index a2583c2..4defed5 100644 (file)
@@ -532,11 +532,12 @@ typedef u64 acpi_integer;
         strnlen (a, ACPI_NAMESEG_SIZE) == ACPI_NAMESEG_SIZE)
 
 /*
- * Algorithm to obtain access bit width.
+ * Algorithm to obtain access bit or byte width.
  * Can be used with access_width of struct acpi_generic_address and access_size of
  * struct acpi_resource_generic_register.
  */
 #define ACPI_ACCESS_BIT_WIDTH(size)     (1 << ((size) + 2))
+#define ACPI_ACCESS_BYTE_WIDTH(size)    (1 << ((size) - 1))
 
 /*******************************************************************************
  *
index 340da77..af2fce5 100644 (file)
@@ -2,6 +2,10 @@
 #ifndef ACPI_BUTTON_H
 #define ACPI_BUTTON_H
 
+#define ACPI_BUTTON_HID_POWER  "PNP0C0C"
+#define ACPI_BUTTON_HID_LID    "PNP0C0D"
+#define ACPI_BUTTON_HID_SLEEP  "PNP0C0E"
+
 #if IS_ENABLED(CONFIG_ACPI_BUTTON)
 extern int acpi_lid_open(void);
 #else
index bfc96bf..df9b5bc 100644 (file)
@@ -4,8 +4,9 @@
 
 /*
  * For the benefit of those who are trying to port Linux to another
- * architecture, here are some C-language equivalents.  You should
- * recode these in the native assembly language, if at all possible.
+ * architecture, here are some C-language equivalents.  They should
+ * generate reasonable code, so take a look at what your compiler spits
+ * out before rolling your own buggy implementation in assembly language.
  *
  * C language equivalents written by Theodore Ts'o, 9/26/92
  */
index 02970b1..f4c3470 100644 (file)
@@ -34,7 +34,6 @@ arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
        u32 tmp;
 
        preempt_disable();
-       pagefault_disable();
 
        ret = -EFAULT;
        if (unlikely(get_user(oldval, uaddr) != 0))
@@ -67,7 +66,6 @@ arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
                ret = -EFAULT;
 
 out_pagefault_enable:
-       pagefault_enable();
        preempt_enable();
 
        if (ret == 0)
index cec543d..c835607 100644 (file)
@@ -11,20 +11,6 @@ static __always_inline struct vdso_data *__arch_get_k_vdso_data(void)
 }
 #endif /* __arch_get_k_vdso_data */
 
-#ifndef __arch_update_vdso_data
-static __always_inline bool __arch_update_vdso_data(void)
-{
-       return true;
-}
-#endif /* __arch_update_vdso_data */
-
-#ifndef __arch_get_clock_mode
-static __always_inline int __arch_get_clock_mode(struct timekeeper *tk)
-{
-       return 0;
-}
-#endif /* __arch_get_clock_mode */
-
 #ifndef __arch_update_vsyscall
 static __always_inline void __arch_update_vsyscall(struct vdso_data *vdata,
                                                   struct timekeeper *tk)
index 7d9598d..25f0523 100644 (file)
@@ -105,17 +105,17 @@ struct omap_dm_timer {
        void __iomem    *pend;          /* write pending */
        void __iomem    *func_base;     /* function register base */
 
+       atomic_t enabled;
        unsigned long rate;
        unsigned reserved:1;
        unsigned posted:1;
        struct timer_regs context;
-       int (*get_context_loss_count)(struct device *);
-       int ctx_loss_count;
        int revision;
        u32 capability;
        u32 errata;
        struct platform_device *pdev;
        struct list_head node;
+       struct notifier_block nb;
 };
 
 int omap_dm_timer_reserve_systimer(int id);
index 4e6dc84..9ecb3c1 100644 (file)
@@ -33,7 +33,8 @@ bool __must_check curve25519(u8 mypublic[CURVE25519_KEY_SIZE],
                             const u8 secret[CURVE25519_KEY_SIZE],
                             const u8 basepoint[CURVE25519_KEY_SIZE])
 {
-       if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
+       if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519) &&
+           (!IS_ENABLED(CONFIG_CRYPTO_CURVE25519_X86) || IS_ENABLED(CONFIG_AS_ADX)))
                curve25519_arch(mypublic, secret, basepoint);
        else
                curve25519_generic(mypublic, secret, basepoint);
@@ -49,7 +50,8 @@ __must_check curve25519_generate_public(u8 pub[CURVE25519_KEY_SIZE],
                                    CURVE25519_KEY_SIZE)))
                return false;
 
-       if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519))
+       if (IS_ENABLED(CONFIG_CRYPTO_ARCH_HAVE_LIB_CURVE25519) &&
+           (!IS_ENABLED(CONFIG_CRYPTO_CURVE25519_X86) || IS_ENABLED(CONFIG_AS_ADX)))
                curve25519_base_arch(pub, secret);
        else
                curve25519_generic(pub, secret, curve25519_base_point);
index bcb39da..41725d8 100644 (file)
@@ -81,7 +81,7 @@ struct drm_dp_vcpi {
  * &drm_dp_mst_topology_mgr.base.lock.
  * @num_sdp_stream_sinks: Number of stream sinks. Protected by
  * &drm_dp_mst_topology_mgr.base.lock.
- * @available_pbn: Available bandwidth for this port. Protected by
+ * @full_pbn: Max possible bandwidth for this port. Protected by
  * &drm_dp_mst_topology_mgr.base.lock.
  * @next: link to next port on this branch device
  * @aux: i2c aux transport to talk to device connected to this port, protected
@@ -126,7 +126,7 @@ struct drm_dp_mst_port {
        u8 dpcd_rev;
        u8 num_sdp_streams;
        u8 num_sdp_stream_sinks;
-       uint16_t available_pbn;
+       uint16_t full_pbn;
        struct list_head next;
        /**
         * @mstb: the branch device connected to this port, if there is one.
index e34a7b7..294b293 100644 (file)
@@ -96,6 +96,11 @@ struct drm_gem_shmem_object {
         * The address are un-mapped when the count reaches zero.
         */
        unsigned int vmap_use_count;
+
+       /**
+        * @map_cached: map object cached (instead of using writecombine).
+        */
+       bool map_cached;
 };
 
 #define to_drm_gem_shmem_obj(obj) \
index 0f2b842..65ac6eb 100644 (file)
 #define IMX8MN_CLK_I2C1                                105
 #define IMX8MN_CLK_I2C2                                106
 #define IMX8MN_CLK_I2C3                                107
-#define IMX8MN_CLK_I2C4                                118
-#define IMX8MN_CLK_UART1                       119
+#define IMX8MN_CLK_I2C4                                108
+#define IMX8MN_CLK_UART1                       109
 #define IMX8MN_CLK_UART2                       110
 #define IMX8MN_CLK_UART3                       111
 #define IMX8MN_CLK_UART4                       112
diff --git a/include/dt-bindings/display/sdtv-standards.h b/include/dt-bindings/display/sdtv-standards.h
new file mode 100644 (file)
index 0000000..fbc1a3d
--- /dev/null
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only or X11 */
+/*
+ * Copyright 2019 Pengutronix, Marco Felsch <kernel@pengutronix.de>
+ */
+
+#ifndef _DT_BINDINGS_DISPLAY_SDTV_STDS_H
+#define _DT_BINDINGS_DISPLAY_SDTV_STDS_H
+
+/*
+ * Attention: Keep the SDTV_STD_* bit definitions in sync with
+ * include/uapi/linux/videodev2.h V4L2_STD_* bit definitions.
+ */
+/* One bit for each standard */
+#define SDTV_STD_PAL_B         0x00000001
+#define SDTV_STD_PAL_B1                0x00000002
+#define SDTV_STD_PAL_G         0x00000004
+#define SDTV_STD_PAL_H         0x00000008
+#define SDTV_STD_PAL_I         0x00000010
+#define SDTV_STD_PAL_D         0x00000020
+#define SDTV_STD_PAL_D1                0x00000040
+#define SDTV_STD_PAL_K         0x00000080
+
+#define SDTV_STD_PAL           (SDTV_STD_PAL_B         | \
+                                SDTV_STD_PAL_B1        | \
+                                SDTV_STD_PAL_G         | \
+                                SDTV_STD_PAL_H         | \
+                                SDTV_STD_PAL_I         | \
+                                SDTV_STD_PAL_D         | \
+                                SDTV_STD_PAL_D1        | \
+                                SDTV_STD_PAL_K)
+
+#define SDTV_STD_PAL_M         0x00000100
+#define SDTV_STD_PAL_N         0x00000200
+#define SDTV_STD_PAL_Nc                0x00000400
+#define SDTV_STD_PAL_60                0x00000800
+
+#define SDTV_STD_NTSC_M                0x00001000      /* BTSC */
+#define SDTV_STD_NTSC_M_JP     0x00002000      /* EIA-J */
+#define SDTV_STD_NTSC_443      0x00004000
+#define SDTV_STD_NTSC_M_KR     0x00008000      /* FM A2 */
+
+#define SDTV_STD_NTSC          (SDTV_STD_NTSC_M        | \
+                                SDTV_STD_NTSC_M_JP     | \
+                                SDTV_STD_NTSC_M_KR)
+
+#define SDTV_STD_SECAM_B       0x00010000
+#define SDTV_STD_SECAM_D       0x00020000
+#define SDTV_STD_SECAM_G       0x00040000
+#define SDTV_STD_SECAM_H       0x00080000
+#define SDTV_STD_SECAM_K       0x00100000
+#define SDTV_STD_SECAM_K1      0x00200000
+#define SDTV_STD_SECAM_L       0x00400000
+#define SDTV_STD_SECAM_LC      0x00800000
+
+#define SDTV_STD_SECAM         (SDTV_STD_SECAM_B       | \
+                                SDTV_STD_SECAM_D       | \
+                                SDTV_STD_SECAM_G       | \
+                                SDTV_STD_SECAM_H       | \
+                                SDTV_STD_SECAM_K       | \
+                                SDTV_STD_SECAM_K1      | \
+                                SDTV_STD_SECAM_L       | \
+                                SDTV_STD_SECAM_LC)
+
+/* Standards for Countries with 60Hz Line frequency */
+#define SDTV_STD_525_60                (SDTV_STD_PAL_M         | \
+                                SDTV_STD_PAL_60        | \
+                                SDTV_STD_NTSC          | \
+                                SDTV_STD_NTSC_443)
+
+/* Standards for Countries with 50Hz Line frequency */
+#define SDTV_STD_625_50                (SDTV_STD_PAL           | \
+                                SDTV_STD_PAL_N         | \
+                                SDTV_STD_PAL_Nc        | \
+                                SDTV_STD_SECAM)
+
+#endif /* _DT_BINDINGS_DISPLAY_SDTV_STDS_H */
index 01eedf4..dda00c0 100644 (file)
@@ -14,8 +14,6 @@
 #define TVP5150_COMPOSITE1 1
 #define TVP5150_SVIDEO     2
 
-#define TVP5150_INPUT_NUM  3
-
 /* TVP5150 HW outputs */
 #define TVP5150_NORMAL       0
 #define TVP5150_BLACK_SCREEN 1
index 9d53f54..6345790 100644 (file)
@@ -70,6 +70,7 @@ struct vgic_global {
 
        /* Hardware has GICv4? */
        bool                    has_gicv4;
+       bool                    has_gicv4_1;
 
        /* GIC system register CPU interface */
        struct static_key_false gicv3_cpuif;
index 3015ecb..0566cb3 100644 (file)
@@ -16,9 +16,7 @@ bool topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu);
 
 DECLARE_PER_CPU(unsigned long, cpu_scale);
 
-struct sched_domain;
-static inline
-unsigned long topology_get_cpu_scale(int cpu)
+static inline unsigned long topology_get_cpu_scale(int cpu)
 {
        return per_cpu(cpu_scale, cpu);
 }
@@ -27,12 +25,23 @@ void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity);
 
 DECLARE_PER_CPU(unsigned long, freq_scale);
 
-static inline
-unsigned long topology_get_freq_scale(int cpu)
+static inline unsigned long topology_get_freq_scale(int cpu)
 {
        return per_cpu(freq_scale, cpu);
 }
 
+bool arch_freq_counters_available(struct cpumask *cpus);
+
+DECLARE_PER_CPU(unsigned long, thermal_pressure);
+
+static inline unsigned long topology_get_thermal_pressure(int cpu)
+{
+       return per_cpu(thermal_pressure, cpu);
+}
+
+void arch_set_thermal_pressure(struct cpumask *cpus,
+                              unsigned long th_pressure);
+
 struct cpu_topology {
        int thread_id;
        int core_id;
diff --git a/include/linux/atmel-isc-media.h b/include/linux/atmel-isc-media.h
new file mode 100644 (file)
index 0000000..79a320f
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries
+ *
+ * Author: Eugen Hristev <eugen.hristev@microchip.com>
+ */
+
+#ifndef __LINUX_ATMEL_ISC_MEDIA_H__
+#define __LINUX_ATMEL_ISC_MEDIA_H__
+
+/*
+ * There are 8 controls available:
+ * 4 gain controls, sliders, for each of the BAYER components: R, B, GR, GB.
+ * These gains are multipliers for each component, in format unsigned 0:4:9 with
+ * a default value of 512 (1.0 multiplier).
+ * 4 offset controls, sliders, for each of the BAYER components: R, B, GR, GB.
+ * These offsets are added/substracted from each component, in format signed
+ * 1:12:0 with a default value of 0 (+/- 0)
+ *
+ * To expose this to userspace, added 8 custom controls, in an auto cluster.
+ *
+ * To summarize the functionality:
+ * The auto cluster switch is the auto white balance control, and it works
+ * like this:
+ * AWB == 1: autowhitebalance is on, the do_white_balance button is inactive,
+ * the gains/offsets are inactive, but volatile and readable.
+ * Thus, the results of the whitebalance algorithm are available to userspace to
+ * read at any time.
+ * AWB == 0: autowhitebalance is off, cluster is in manual mode, user can
+ * configure the gain/offsets directly.
+ * More than that, if the do_white_balance button is
+ * pressed, the driver will perform one-time-adjustment, (preferably with color
+ * checker card) and the userspace can read again the new values.
+ *
+ * With this feature, the userspace can save the coefficients and reinstall them
+ * for example after reboot or reprobing the driver.
+ */
+
+enum atmel_isc_ctrl_id {
+       /* Red component gain control */
+       ISC_CID_R_GAIN = (V4L2_CID_USER_ATMEL_ISC_BASE + 0),
+       /* Blue component gain control */
+       ISC_CID_B_GAIN,
+       /* Green Red component gain control */
+       ISC_CID_GR_GAIN,
+       /* Green Blue gain control */
+       ISC_CID_GB_GAIN,
+       /* Red component offset control */
+       ISC_CID_R_OFFSET,
+       /* Blue component offset control */
+       ISC_CID_B_OFFSET,
+       /* Green Red component offset control */
+       ISC_CID_GR_OFFSET,
+       /* Green Blue component offset control */
+       ISC_CID_GB_OFFSET,
+};
+
+#endif
index 853d92c..c1c0f9e 100644 (file)
@@ -441,14 +441,6 @@ void __bio_add_page(struct bio *bio, struct page *page,
                unsigned int len, unsigned int off);
 int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter);
 void bio_release_pages(struct bio *bio, bool mark_dirty);
-struct rq_map_data;
-extern struct bio *bio_map_user_iov(struct request_queue *,
-                                   struct iov_iter *, gfp_t);
-extern void bio_unmap_user(struct bio *);
-extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
-                               gfp_t);
-extern struct bio *bio_copy_kern(struct request_queue *, void *, unsigned int,
-                                gfp_t, int);
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
 
@@ -463,14 +455,9 @@ extern void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter,
 extern void bio_copy_data(struct bio *dst, struct bio *src);
 extern void bio_list_copy_data(struct bio *dst, struct bio *src);
 extern void bio_free_pages(struct bio *bio);
-
-extern struct bio *bio_copy_user_iov(struct request_queue *,
-                                    struct rq_map_data *,
-                                    struct iov_iter *,
-                                    gfp_t);
-extern int bio_uncopy_user(struct bio *);
 void zero_fill_bio_iter(struct bio *bio, struct bvec_iter iter);
 void bio_truncate(struct bio *bio, unsigned new_size);
+void guard_bio_eod(struct bio *bio);
 
 static inline void zero_fill_bio(struct bio *bio)
 {
index 669d694..a740bbc 100644 (file)
@@ -3,9 +3,9 @@
 #define __LINUX_BITS_H
 
 #include <linux/const.h>
+#include <vdso/bits.h>
 #include <asm/bitsperlong.h>
 
-#define BIT(nr)                        (UL(1) << (nr))
 #define BIT_ULL(nr)            (ULL(1) << (nr))
 #define BIT_MASK(nr)           (UL(1) << ((nr) % BITS_PER_LONG))
 #define BIT_WORD(nr)           ((nr) / BITS_PER_LONG)
index 11cfd64..f389d7c 100644 (file)
@@ -162,7 +162,10 @@ struct blk_mq_hw_ctx {
        struct dentry           *sched_debugfs_dir;
 #endif
 
-       /** @hctx_list: List of all hardware queues. */
+       /**
+        * @hctx_list: if this hctx is not in use, this is an entry in
+        * q->unused_hctx_list.
+        */
        struct list_head        hctx_list;
 
        /**
@@ -409,6 +412,8 @@ enum {
                << BLK_MQ_F_ALLOC_POLICY_START_BIT)
 
 struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *);
+struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set,
+               void *queuedata);
 struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
                                                  struct request_queue *q,
                                                  bool elevator_init);
index 053ea4b..32868fb 100644 (file)
@@ -524,7 +524,7 @@ struct request_queue {
        unsigned int            sg_reserved_size;
        int                     node;
 #ifdef CONFIG_BLK_DEV_IO_TRACE
-       struct blk_trace        *blk_trace;
+       struct blk_trace __rcu  *blk_trace;
        struct mutex            blk_trace_mutex;
 #endif
        /*
@@ -952,6 +952,10 @@ static inline unsigned int blk_rq_stats_sectors(const struct request *rq)
 }
 
 #ifdef CONFIG_BLK_DEV_ZONED
+
+/* Helper to convert BLK_ZONE_ZONE_XXX to its string format XXX */
+const char *blk_zone_cond_str(enum blk_zone_cond zone_cond);
+
 static inline unsigned int blk_rq_zone_no(struct request *rq)
 {
        return blk_queue_zone_no(rq->q, blk_rq_pos(rq));
@@ -1063,7 +1067,6 @@ extern void blk_abort_request(struct request *);
  * Access functions for manipulating queue properties
  */
 extern void blk_cleanup_queue(struct request_queue *);
-extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
 extern void blk_queue_bounce_limit(struct request_queue *, u64);
 extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
 extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int);
@@ -1140,8 +1143,7 @@ extern void blk_dump_rq_flags(struct request *, char *);
 extern long nr_blockdev_pages(void);
 
 bool __must_check blk_get_queue(struct request_queue *);
-struct request_queue *blk_alloc_queue(gfp_t);
-struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id);
+struct request_queue *blk_alloc_queue(make_request_fn make_request, int node_id);
 extern void blk_put_queue(struct request_queue *);
 extern void blk_set_queue_dying(struct request_queue *);
 
@@ -1484,17 +1486,7 @@ static inline unsigned int block_size(struct block_device *bdev)
        return bdev->bd_block_size;
 }
 
-typedef struct {struct page *v;} Sector;
-
-unsigned char *read_dev_sector(struct block_device *, sector_t, Sector *);
-
-static inline void put_dev_sector(Sector p)
-{
-       put_page(p.v);
-}
-
 int kblockd_schedule_work(struct work_struct *work);
-int kblockd_schedule_work_on(int cpu, struct work_struct *work);
 int kblockd_mod_delayed_work_on(int cpu, struct delayed_work *dwork, unsigned long delay);
 
 #define MODULE_ALIAS_BLOCKDEV(major,minor) \
@@ -1707,6 +1699,7 @@ struct block_device_operations {
        void (*swap_slot_free_notify) (struct block_device *, unsigned long);
        int (*report_zones)(struct gendisk *, sector_t sector,
                        unsigned int nr_zones, report_zones_cb cb, void *data);
+       char *(*devnode)(struct gendisk *disk, umode_t *mode);
        struct module *owner;
        const struct pr_ops *pr_ops;
 };
index 7bb2d8d..3b6ff59 100644 (file)
@@ -51,9 +51,13 @@ void __trace_note_message(struct blk_trace *, struct blkcg *blkcg, const char *f
  **/
 #define blk_add_cgroup_trace_msg(q, cg, fmt, ...)                      \
        do {                                                            \
-               struct blk_trace *bt = (q)->blk_trace;                  \
+               struct blk_trace *bt;                                   \
+                                                                       \
+               rcu_read_lock();                                        \
+               bt = rcu_dereference((q)->blk_trace);                   \
                if (unlikely(bt))                                       \
                        __trace_note_message(bt, cg, fmt, ##__VA_ARGS__);\
+               rcu_read_unlock();                                      \
        } while (0)
 #define blk_add_trace_msg(q, fmt, ...)                                 \
        blk_add_cgroup_trace_msg(q, NULL, fmt, ##__VA_ARGS__)
@@ -61,10 +65,14 @@ void __trace_note_message(struct blk_trace *, struct blkcg *blkcg, const char *f
 
 static inline bool blk_trace_note_message_enabled(struct request_queue *q)
 {
-       struct blk_trace *bt = q->blk_trace;
-       if (likely(!bt))
-               return false;
-       return bt->act_mask & BLK_TC_NOTIFY;
+       struct blk_trace *bt;
+       bool ret;
+
+       rcu_read_lock();
+       bt = rcu_dereference(q->blk_trace);
+       ret = bt && (bt->act_mask & BLK_TC_NOTIFY);
+       rcu_read_unlock();
+       return ret;
 }
 
 extern void blk_add_driver_data(struct request_queue *q, struct request *rq,
index 7e18c93..d11e183 100644 (file)
@@ -10,6 +10,9 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 
+#define BOOTCONFIG_MAGIC       "#BOOTCONFIG\n"
+#define BOOTCONFIG_MAGIC_LEN   12
+
 /* XBC tree node */
 struct xbc_node {
        u16 next;
index 49b1a70..212991f 100644 (file)
@@ -160,6 +160,7 @@ static inline void copy_map_value(struct bpf_map *map, void *dst, void *src)
 }
 void copy_map_value_locked(struct bpf_map *map, void *dst, void *src,
                           bool lock_src);
+int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size);
 
 struct bpf_offload_dev;
 struct bpf_offloaded_map;
index 7b73ef7..e0b020e 100644 (file)
@@ -22,9 +22,6 @@ enum bh_state_bits {
        BH_Dirty,       /* Is dirty */
        BH_Lock,        /* Is locked */
        BH_Req,         /* Has been submitted for I/O */
-       BH_Uptodate_Lock,/* Used by the first bh in a page, to serialise
-                         * IO completion of other buffers in the page
-                         */
 
        BH_Mapped,      /* Has a disk mapping */
        BH_New,         /* Disk mapping was newly created by get_block */
@@ -76,6 +73,9 @@ struct buffer_head {
        struct address_space *b_assoc_map;      /* mapping this buffer is
                                                   associated with */
        atomic_t b_count;               /* users using this buffer_head */
+       spinlock_t b_uptodate_lock;     /* Used by the first bh in a page, to
+                                        * serialise IO completion of other
+                                        * buffers in the page */
 };
 
 /*
index c4458dc..76371aa 100644 (file)
@@ -175,9 +175,10 @@ struct ceph_msg_data {
 #endif /* CONFIG_BLOCK */
                struct ceph_bvec_iter   bvec_pos;
                struct {
-                       struct page     **pages;        /* NOT OWNER. */
+                       struct page     **pages;
                        size_t          length;         /* total # bytes */
                        unsigned int    alignment;      /* first page */
+                       bool            own_pages;
                };
                struct ceph_pagelist    *pagelist;
        };
@@ -356,8 +357,8 @@ extern void ceph_con_keepalive(struct ceph_connection *con);
 extern bool ceph_con_keepalive_expired(struct ceph_connection *con,
                                       unsigned long interval);
 
-extern void ceph_msg_data_add_pages(struct ceph_msg *msg, struct page **pages,
-                               size_t length, size_t alignment);
+void ceph_msg_data_add_pages(struct ceph_msg *msg, struct page **pages,
+                            size_t length, size_t alignment, bool own_pages);
 extern void ceph_msg_data_add_pagelist(struct ceph_msg *msg,
                                struct ceph_pagelist *pagelist);
 #ifdef CONFIG_BLOCK
index e081b56..5e60197 100644 (file)
@@ -37,6 +37,9 @@ int ceph_spg_compare(const struct ceph_spg *lhs, const struct ceph_spg *rhs);
 #define CEPH_POOL_FLAG_HASHPSPOOL      (1ULL << 0) /* hash pg seed and pool id
                                                       together */
 #define CEPH_POOL_FLAG_FULL            (1ULL << 1) /* pool is full */
+#define CEPH_POOL_FLAG_FULL_QUOTA      (1ULL << 10) /* pool ran out of quota,
+                                                       will set FULL too */
+#define CEPH_POOL_FLAG_NEARFULL                (1ULL << 11) /* pool is nearfull */
 
 struct ceph_pg_pool_info {
        struct rb_node node;
@@ -304,5 +307,6 @@ extern struct ceph_pg_pool_info *ceph_pg_pool_by_id(struct ceph_osdmap *map,
 
 extern const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id);
 extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name);
+u64 ceph_pg_pool_flags(struct ceph_osdmap *map, u64 id);
 
 #endif
index 59bdfd4..88ed3c5 100644 (file)
@@ -143,8 +143,10 @@ extern const char *ceph_osd_state_name(int s);
 /*
  * osd map flag bits
  */
-#define CEPH_OSDMAP_NEARFULL (1<<0)  /* sync writes (near ENOSPC) */
-#define CEPH_OSDMAP_FULL     (1<<1)  /* no data writes (ENOSPC) */
+#define CEPH_OSDMAP_NEARFULL (1<<0)  /* sync writes (near ENOSPC),
+                                       not set since ~luminous */
+#define CEPH_OSDMAP_FULL     (1<<1)  /* no data writes (ENOSPC),
+                                       not set since ~luminous */
 #define CEPH_OSDMAP_PAUSERD  (1<<2)  /* pause all reads */
 #define CEPH_OSDMAP_PAUSEWR  (1<<3)  /* pause all writes */
 #define CEPH_OSDMAP_PAUSEREC (1<<4)  /* pause recovery */
index d7ddebd..e75d219 100644 (file)
@@ -62,6 +62,7 @@ struct css_task_iter {
        struct list_head                *mg_tasks_head;
        struct list_head                *dying_tasks_head;
 
+       struct list_head                *cur_tasks_head;
        struct css_set                  *cur_cset;
        struct css_set                  *cur_dcset;
        struct task_struct              *cur_task;
index 952ac03..bd1ee90 100644 (file)
@@ -522,9 +522,9 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-#define clk_hw_register_gate_parent_hw(dev, name, parent_name, flags, reg,    \
+#define clk_hw_register_gate_parent_hw(dev, name, parent_hw, flags, reg,      \
                                       bit_idx, clk_gate_flags, lock)         \
-       __clk_hw_register_gate((dev), NULL, (name), (parent_name), NULL,      \
+       __clk_hw_register_gate((dev), NULL, (name), NULL, (parent_hw),        \
                               NULL, (flags), (reg), (bit_idx),               \
                               (clk_gate_flags), (lock))
 /**
@@ -539,10 +539,10 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-#define clk_hw_register_gate_parent_data(dev, name, parent_name, flags, reg,  \
+#define clk_hw_register_gate_parent_data(dev, name, parent_data, flags, reg,  \
                                       bit_idx, clk_gate_flags, lock)         \
-       __clk_hw_register_gate((dev), NULL, (name), (parent_name), NULL,      \
-                              NULL, (flags), (reg), (bit_idx),               \
+       __clk_hw_register_gate((dev), NULL, (name), NULL, NULL, (parent_data), \
+                              (flags), (reg), (bit_idx),                     \
                               (clk_gate_flags), (lock))
 void clk_unregister_gate(struct clk *clk);
 void clk_hw_unregister_gate(struct clk_hw *hw);
index b21db53..86d143d 100644 (file)
 struct clocksource;
 struct module;
 
-#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
+#if defined(CONFIG_ARCH_CLOCKSOURCE_DATA) || \
+    defined(CONFIG_GENERIC_GETTIMEOFDAY)
 #include <asm/clocksource.h>
 #endif
 
+#include <vdso/clocksource.h>
+
 /**
  * struct clocksource - hardware abstraction for a free running counter
  *     Provides mostly state-free accessors to the underlying hardware.
  *     This is the structure used for system time.
  *
- * @name:              ptr to clocksource name
- * @list:              list head for registration
- * @rating:            rating value for selection (higher is better)
+ * @read:              Returns a cycle value, passes clocksource as argument
+ * @mask:              Bitmask for two's complement
+ *                     subtraction of non 64 bit counters
+ * @mult:              Cycle to nanosecond multiplier
+ * @shift:             Cycle to nanosecond divisor (power of two)
+ * @max_idle_ns:       Maximum idle time permitted by the clocksource (nsecs)
+ * @maxadj:            Maximum adjustment value to mult (~11%)
+ * @archdata:          Optional arch-specific data
+ * @max_cycles:                Maximum safe cycle value which won't overflow on
+ *                     multiplication
+ * @name:              Pointer to clocksource name
+ * @list:              List head for registration (internal)
+ * @rating:            Rating value for selection (higher is better)
  *                     To avoid rating inflation the following
  *                     list should give you a guide as to how
  *                     to assign your clocksource a rating
@@ -49,27 +62,23 @@ struct module;
  *                     400-499: Perfect
  *                             The ideal clocksource. A must-use where
  *                             available.
- * @read:              returns a cycle value, passes clocksource as argument
- * @enable:            optional function to enable the clocksource
- * @disable:           optional function to disable the clocksource
- * @mask:              bitmask for two's complement
- *                     subtraction of non 64 bit counters
- * @mult:              cycle to nanosecond multiplier
- * @shift:             cycle to nanosecond divisor (power of two)
- * @max_idle_ns:       max idle time permitted by the clocksource (nsecs)
- * @maxadj:            maximum adjustment value to mult (~11%)
- * @max_cycles:                maximum safe cycle value which won't overflow on multiplication
- * @flags:             flags describing special properties
- * @archdata:          arch-specific data
- * @suspend:           suspend function for the clocksource, if necessary
- * @resume:            resume function for the clocksource, if necessary
+ * @flags:             Flags describing special properties
+ * @enable:            Optional function to enable the clocksource
+ * @disable:           Optional function to disable the clocksource
+ * @suspend:           Optional suspend function for the clocksource
+ * @resume:            Optional resume function for the clocksource
  * @mark_unstable:     Optional function to inform the clocksource driver that
  *                     the watchdog marked the clocksource unstable
- * @owner:             module reference, must be set by clocksource in modules
+ * @tick_stable:        Optional function called periodically from the watchdog
+ *                     code to provide stable syncrhonization points
+ * @wd_list:           List head to enqueue into the watchdog list (internal)
+ * @cs_last:           Last clocksource value for clocksource watchdog
+ * @wd_last:           Last watchdog value corresponding to @cs_last
+ * @owner:             Module reference, must be set by clocksource in modules
  *
  * Note: This struct is not used in hotpathes of the timekeeping code
  * because the timekeeper caches the hot path fields in its own data
- * structure, so no line cache alignment is required,
+ * structure, so no cache line alignment is required,
  *
  * The pointer to the clocksource itself is handed to the read
  * callback. If you need extra information there you can wrap struct
@@ -78,35 +87,37 @@ struct module;
  * structure.
  */
 struct clocksource {
-       u64 (*read)(struct clocksource *cs);
-       u64 mask;
-       u32 mult;
-       u32 shift;
-       u64 max_idle_ns;
-       u32 maxadj;
+       u64                     (*read)(struct clocksource *cs);
+       u64                     mask;
+       u32                     mult;
+       u32                     shift;
+       u64                     max_idle_ns;
+       u32                     maxadj;
 #ifdef CONFIG_ARCH_CLOCKSOURCE_DATA
        struct arch_clocksource_data archdata;
 #endif
-       u64 max_cycles;
-       const char *name;
-       struct list_head list;
-       int rating;
-       int (*enable)(struct clocksource *cs);
-       void (*disable)(struct clocksource *cs);
-       unsigned long flags;
-       void (*suspend)(struct clocksource *cs);
-       void (*resume)(struct clocksource *cs);
-       void (*mark_unstable)(struct clocksource *cs);
-       void (*tick_stable)(struct clocksource *cs);
+       u64                     max_cycles;
+       const char              *name;
+       struct list_head        list;
+       int                     rating;
+       enum vdso_clock_mode    vdso_clock_mode;
+       unsigned long           flags;
+
+       int                     (*enable)(struct clocksource *cs);
+       void                    (*disable)(struct clocksource *cs);
+       void                    (*suspend)(struct clocksource *cs);
+       void                    (*resume)(struct clocksource *cs);
+       void                    (*mark_unstable)(struct clocksource *cs);
+       void                    (*tick_stable)(struct clocksource *cs);
 
        /* private: */
 #ifdef CONFIG_CLOCKSOURCE_WATCHDOG
        /* Watchdog related data, used by the framework */
-       struct list_head wd_list;
-       u64 cs_last;
-       u64 wd_last;
+       struct list_head        wd_list;
+       u64                     cs_last;
+       u64                     wd_last;
 #endif
-       struct module *owner;
+       struct module           *owner;
 };
 
 /*
index 519e949..bf8e770 100644 (file)
@@ -9,7 +9,7 @@
  * See kernel/sched/completion.c for details.
  */
 
-#include <linux/wait.h>
+#include <linux/swait.h>
 
 /*
  * struct completion - structure used to maintain state for a "completion"
@@ -25,7 +25,7 @@
  */
 struct completion {
        unsigned int done;
-       wait_queue_head_t wait;
+       struct swait_queue_head wait;
 };
 
 #define init_completion_map(x, m) __init_completion(x)
@@ -34,7 +34,7 @@ static inline void complete_acquire(struct completion *x) {}
 static inline void complete_release(struct completion *x) {}
 
 #define COMPLETION_INITIALIZER(work) \
-       { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
+       { 0, __SWAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
 
 #define COMPLETION_INITIALIZER_ONSTACK_MAP(work, map) \
        (*({ init_completion_map(&(work), &(map)); &(work); }))
@@ -85,7 +85,7 @@ static inline void complete_release(struct completion *x) {}
 static inline void __init_completion(struct completion *x)
 {
        x->done = 0;
-       init_waitqueue_head(&x->wait);
+       init_swait_queue_head(&x->wait);
 }
 
 /**
index 7b55a55..81b8aae 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef _LINUX_CONST_H
 #define _LINUX_CONST_H
 
-#include <uapi/linux/const.h>
-
-#define UL(x)          (_UL(x))
-#define ULL(x)         (_ULL(x))
+#include <vdso/const.h>
 
 #endif /* _LINUX_CONST_H */
index 1ca2baf..beaed2d 100644 (file)
@@ -88,10 +88,13 @@ extern ssize_t arch_cpu_release(const char *, size_t);
 
 #ifdef CONFIG_SMP
 extern bool cpuhp_tasks_frozen;
-int cpu_up(unsigned int cpu);
+int add_cpu(unsigned int cpu);
+int cpu_device_up(struct device *dev);
 void notify_cpu_starting(unsigned int cpu);
 extern void cpu_maps_update_begin(void);
 extern void cpu_maps_update_done(void);
+int bringup_hibernate_cpu(unsigned int sleep_cpu);
+void bringup_nonboot_cpus(unsigned int setup_max_cpus);
 
 #else  /* CONFIG_SMP */
 #define cpuhp_tasks_frozen     0
@@ -117,7 +120,9 @@ extern void lockdep_assert_cpus_held(void);
 extern void cpu_hotplug_disable(void);
 extern void cpu_hotplug_enable(void);
 void clear_tasks_mm_cpumask(int cpu);
-int cpu_down(unsigned int cpu);
+int remove_cpu(unsigned int cpu);
+int cpu_device_down(struct device *dev);
+extern void smp_shutdown_nonboot_cpus(unsigned int primary_cpu);
 
 #else /* CONFIG_HOTPLUG_CPU */
 
@@ -129,6 +134,7 @@ static inline int  cpus_read_trylock(void) { return true; }
 static inline void lockdep_assert_cpus_held(void) { }
 static inline void cpu_hotplug_disable(void) { }
 static inline void cpu_hotplug_enable(void) { }
+static inline void smp_shutdown_nonboot_cpus(unsigned int primary_cpu) { }
 #endif /* !CONFIG_HOTPLUG_CPU */
 
 /* Wrappers which go away once all code is converted */
@@ -138,12 +144,18 @@ static inline void get_online_cpus(void) { cpus_read_lock(); }
 static inline void put_online_cpus(void) { cpus_read_unlock(); }
 
 #ifdef CONFIG_PM_SLEEP_SMP
-extern int freeze_secondary_cpus(int primary);
+int __freeze_secondary_cpus(int primary, bool suspend);
+static inline int freeze_secondary_cpus(int primary)
+{
+       return __freeze_secondary_cpus(primary, true);
+}
+
 static inline int disable_nonboot_cpus(void)
 {
-       return freeze_secondary_cpus(0);
+       return __freeze_secondary_cpus(0, false);
 }
-extern void enable_nonboot_cpus(void);
+
+void enable_nonboot_cpus(void);
 
 static inline int suspend_disable_secondary_cpus(void)
 {
index 0fb561d..f724025 100644 (file)
@@ -205,6 +205,7 @@ static inline bool policy_is_shared(struct cpufreq_policy *policy)
 unsigned int cpufreq_get(unsigned int cpu);
 unsigned int cpufreq_quick_get(unsigned int cpu);
 unsigned int cpufreq_quick_get_max(unsigned int cpu);
+unsigned int cpufreq_get_hw_max_freq(unsigned int cpu);
 void disable_cpufreq(void);
 
 u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
@@ -232,6 +233,10 @@ static inline unsigned int cpufreq_quick_get_max(unsigned int cpu)
 {
        return 0;
 }
+static inline unsigned int cpufreq_get_hw_max_freq(unsigned int cpu)
+{
+       return 0;
+}
 static inline void disable_cpufreq(void) { }
 #endif
 
index d37c17e..77d70b6 100644 (file)
@@ -102,6 +102,7 @@ enum cpuhp_state {
        CPUHP_AP_IRQ_ARMADA_XP_STARTING,
        CPUHP_AP_IRQ_BCM2836_STARTING,
        CPUHP_AP_IRQ_MIPS_GIC_STARTING,
+       CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
        CPUHP_AP_ARM_MVEBU_COHERENCY,
        CPUHP_AP_MICROCODE_LOADER,
        CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
index d5cc885..f0d895d 100644 (file)
@@ -194,6 +194,11 @@ static inline unsigned int cpumask_local_spread(unsigned int i, int node)
        return 0;
 }
 
+static inline int cpumask_any_and_distribute(const struct cpumask *src1p,
+                                            const struct cpumask *src2p) {
+       return cpumask_next_and(-1, src1p, src2p);
+}
+
 #define for_each_cpu(cpu, mask)                        \
        for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
 #define for_each_cpu_not(cpu, mask)            \
@@ -245,6 +250,8 @@ static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp)
 int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *);
 int cpumask_any_but(const struct cpumask *mask, unsigned int cpu);
 unsigned int cpumask_local_spread(unsigned int i, int node);
+int cpumask_any_and_distribute(const struct cpumask *src1p,
+                              const struct cpumask *src2p);
 
 /**
  * for_each_cpu - iterate over every cpu in a mask
index 3d013de..d672b7d 100644 (file)
@@ -67,10 +67,10 @@ struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops);
 
-struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
-                                       struct dentry *parent, void *data,
-                                       const struct file_operations *fops,
-                                       loff_t file_size);
+void debugfs_create_file_size(const char *name, umode_t mode,
+                             struct dentry *parent, void *data,
+                             const struct file_operations *fops,
+                             loff_t file_size);
 
 struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
 
@@ -127,9 +127,9 @@ struct dentry *debugfs_create_blob(const char *name, umode_t mode,
                                  struct dentry *parent,
                                  struct debugfs_blob_wrapper *blob);
 
-struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
-                                    struct dentry *parent,
-                                    struct debugfs_regset32 *regset);
+void debugfs_create_regset32(const char *name, umode_t mode,
+                            struct dentry *parent,
+                            struct debugfs_regset32 *regset);
 
 void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
                          int nregs, void __iomem *base, char *prefix);
@@ -181,13 +181,11 @@ static inline struct dentry *debugfs_create_file_unsafe(const char *name,
        return ERR_PTR(-ENODEV);
 }
 
-static inline struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
-                                       struct dentry *parent, void *data,
-                                       const struct file_operations *fops,
-                                       loff_t file_size)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_file_size(const char *name, umode_t mode,
+                                           struct dentry *parent, void *data,
+                                           const struct file_operations *fops,
+                                           loff_t file_size)
+{ }
 
 static inline struct dentry *debugfs_create_dir(const char *name,
                                                struct dentry *parent)
@@ -304,11 +302,10 @@ static inline struct dentry *debugfs_create_blob(const char *name, umode_t mode,
        return ERR_PTR(-ENODEV);
 }
 
-static inline struct dentry *debugfs_create_regset32(const char *name,
-                                  umode_t mode, struct dentry *parent,
-                                  struct debugfs_regset32 *regset)
+static inline void debugfs_create_regset32(const char *name, umode_t mode,
+                                          struct dentry *parent,
+                                          struct debugfs_regset32 *regset)
 {
-       return ERR_PTR(-ENODEV);
 }
 
 static inline void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
index c6f82d4..57e871a 100644 (file)
@@ -158,7 +158,7 @@ struct devfreq_stats {
  * functions except for the context of callbacks defined in struct
  * devfreq_governor, the governor should protect its access with the
  * struct mutex lock in struct devfreq. A governor may use this mutex
- * to protect its own private data in void *data as well.
+ * to protect its own private data in ``void *data`` as well.
  */
 struct devfreq {
        struct list_head node;
@@ -201,24 +201,23 @@ struct devfreq_freqs {
 };
 
 #if defined(CONFIG_PM_DEVFREQ)
-extern struct devfreq *devfreq_add_device(struct device *dev,
-                                 struct devfreq_dev_profile *profile,
-                                 const char *governor_name,
-                                 void *data);
-extern int devfreq_remove_device(struct devfreq *devfreq);
-extern struct devfreq *devm_devfreq_add_device(struct device *dev,
-                                 struct devfreq_dev_profile *profile,
-                                 const char *governor_name,
-                                 void *data);
-extern void devm_devfreq_remove_device(struct device *dev,
-                                 struct devfreq *devfreq);
+struct devfreq *devfreq_add_device(struct device *dev,
+                               struct devfreq_dev_profile *profile,
+                               const char *governor_name,
+                               void *data);
+int devfreq_remove_device(struct devfreq *devfreq);
+struct devfreq *devm_devfreq_add_device(struct device *dev,
+                               struct devfreq_dev_profile *profile,
+                               const char *governor_name,
+                               void *data);
+void devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq);
 
 /* Supposed to be called by PM callbacks */
-extern int devfreq_suspend_device(struct devfreq *devfreq);
-extern int devfreq_resume_device(struct devfreq *devfreq);
+int devfreq_suspend_device(struct devfreq *devfreq);
+int devfreq_resume_device(struct devfreq *devfreq);
 
-extern void devfreq_suspend(void);
-extern void devfreq_resume(void);
+void devfreq_suspend(void);
+void devfreq_resume(void);
 
 /**
  * update_devfreq() - Reevaluate the device and configure frequency
@@ -226,39 +225,38 @@ extern void devfreq_resume(void);
  *
  * Note: devfreq->lock must be held
  */
-extern int update_devfreq(struct devfreq *devfreq);
+int update_devfreq(struct devfreq *devfreq);
 
 /* Helper functions for devfreq user device driver with OPP. */
-extern struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
-                                          unsigned long *freq, u32 flags);
-extern int devfreq_register_opp_notifier(struct device *dev,
-                                        struct devfreq *devfreq);
-extern int devfreq_unregister_opp_notifier(struct device *dev,
-                                          struct devfreq *devfreq);
-extern int devm_devfreq_register_opp_notifier(struct device *dev,
-                                             struct devfreq *devfreq);
-extern void devm_devfreq_unregister_opp_notifier(struct device *dev,
-                                               struct devfreq *devfreq);
-extern int devfreq_register_notifier(struct devfreq *devfreq,
-                                       struct notifier_block *nb,
-                                       unsigned int list);
-extern int devfreq_unregister_notifier(struct devfreq *devfreq,
-                                       struct notifier_block *nb,
-                                       unsigned int list);
-extern int devm_devfreq_register_notifier(struct device *dev,
+struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
+                               unsigned long *freq, u32 flags);
+int devfreq_register_opp_notifier(struct device *dev,
+                               struct devfreq *devfreq);
+int devfreq_unregister_opp_notifier(struct device *dev,
+                               struct devfreq *devfreq);
+int devm_devfreq_register_opp_notifier(struct device *dev,
+                               struct devfreq *devfreq);
+void devm_devfreq_unregister_opp_notifier(struct device *dev,
+                               struct devfreq *devfreq);
+int devfreq_register_notifier(struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list);
+int devfreq_unregister_notifier(struct devfreq *devfreq,
+                               struct notifier_block *nb,
+                               unsigned int list);
+int devm_devfreq_register_notifier(struct device *dev,
                                struct devfreq *devfreq,
                                struct notifier_block *nb,
                                unsigned int list);
-extern void devm_devfreq_unregister_notifier(struct device *dev,
+void devm_devfreq_unregister_notifier(struct device *dev,
                                struct devfreq *devfreq,
                                struct notifier_block *nb,
                                unsigned int list);
-extern struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
-                                               int index);
+struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index);
 
 #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
 /**
- * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
+ * struct devfreq_simple_ondemand_data - ``void *data`` fed to struct devfreq
  *     and devfreq_add_device
  * @upthreshold:       If the load is over this value, the frequency jumps.
  *                     Specify 0 to use the default. Valid value = 0 to 100.
@@ -278,7 +276,7 @@ struct devfreq_simple_ondemand_data {
 
 #if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
 /**
- * struct devfreq_passive_data - void *data fed to struct devfreq
+ * struct devfreq_passive_data - ``void *data`` fed to struct devfreq
  *     and devfreq_add_device
  * @parent:    the devfreq instance of parent device.
  * @get_target_freq:   Optional callback, Returns desired operating frequency
@@ -311,9 +309,9 @@ struct devfreq_passive_data {
 
 #else /* !CONFIG_PM_DEVFREQ */
 static inline struct devfreq *devfreq_add_device(struct device *dev,
-                                         struct devfreq_dev_profile *profile,
-                                         const char *governor_name,
-                                         void *data)
+                                       struct devfreq_dev_profile *profile,
+                                       const char *governor_name,
+                                       void *data)
 {
        return ERR_PTR(-ENOSYS);
 }
@@ -350,31 +348,31 @@ static inline void devfreq_suspend(void) {}
 static inline void devfreq_resume(void) {}
 
 static inline struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
-                                          unsigned long *freq, u32 flags)
+                                       unsigned long *freq, u32 flags)
 {
        return ERR_PTR(-EINVAL);
 }
 
 static inline int devfreq_register_opp_notifier(struct device *dev,
-                                        struct devfreq *devfreq)
+                                       struct devfreq *devfreq)
 {
        return -EINVAL;
 }
 
 static inline int devfreq_unregister_opp_notifier(struct device *dev,
-                                          struct devfreq *devfreq)
+                                       struct devfreq *devfreq)
 {
        return -EINVAL;
 }
 
 static inline int devm_devfreq_register_opp_notifier(struct device *dev,
-                                                    struct devfreq *devfreq)
+                                       struct devfreq *devfreq)
 {
        return -EINVAL;
 }
 
 static inline void devm_devfreq_unregister_opp_notifier(struct device *dev,
-                                                       struct devfreq *devfreq)
+                                       struct devfreq *devfreq)
 {
 }
 
@@ -393,22 +391,22 @@ static inline int devfreq_unregister_notifier(struct devfreq *devfreq,
 }
 
 static inline int devm_devfreq_register_notifier(struct device *dev,
-                               struct devfreq *devfreq,
-                               struct notifier_block *nb,
-                               unsigned int list)
+                                       struct devfreq *devfreq,
+                                       struct notifier_block *nb,
+                                       unsigned int list)
 {
        return 0;
 }
 
 static inline void devm_devfreq_unregister_notifier(struct device *dev,
-                               struct devfreq *devfreq,
-                               struct notifier_block *nb,
-                               unsigned int list)
+                                       struct devfreq *devfreq,
+                                       struct notifier_block *nb,
+                                       unsigned int list)
 {
 }
 
 static inline struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
-                                                       int index)
+                                       int index)
 {
        return ERR_PTR(-ENODEV);
 }
index 0cd7c64..fa04dfd 100644 (file)
@@ -798,6 +798,17 @@ static inline struct device_node *dev_of_node(struct device *dev)
        return dev->of_node;
 }
 
+static inline bool dev_has_sync_state(struct device *dev)
+{
+       if (!dev)
+               return false;
+       if (dev->driver && dev->driver->sync_state)
+               return true;
+       if (dev->bus && dev->bus->sync_state)
+               return true;
+       return false;
+}
+
 /*
  * High level routines for use by the bus drivers
  */
index 1188260..ee7ba5b 100644 (file)
@@ -236,9 +236,9 @@ driver_find_device_by_acpi_dev(struct device_driver *drv, const void *adev)
 }
 #endif
 
+extern int driver_deferred_probe_timeout;
 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);
 void driver_init(void);
 
 /**
index 1470d1d..5abd073 100644 (file)
@@ -247,11 +247,6 @@ extern int dio_create_sysfs_dev_files(struct dio_dev *);
 /* New-style probing */
 extern int dio_register_driver(struct dio_driver *);
 extern void dio_unregister_driver(struct dio_driver *);
-extern const struct dio_device_id *dio_match_device(const struct dio_device_id *ids, const struct dio_dev *z);
-static inline struct dio_driver *dio_dev_driver(const struct dio_dev *d)
-{
-    return d->driver;
-}
 
 #define dio_resource_start(d) ((d)->resource.start)
 #define dio_resource_end(d)   ((d)->resource.end)
index f64ca27..d7bf029 100644 (file)
@@ -69,19 +69,23 @@ struct dmar_pci_notify_info {
 extern struct rw_semaphore dmar_global_lock;
 extern struct list_head dmar_drhd_units;
 
-#define for_each_drhd_unit(drhd) \
-       list_for_each_entry_rcu(drhd, &dmar_drhd_units, list)
+#define for_each_drhd_unit(drhd)                                       \
+       list_for_each_entry_rcu(drhd, &dmar_drhd_units, list,           \
+                               dmar_rcu_check())
 
 #define for_each_active_drhd_unit(drhd)                                        \
-       list_for_each_entry_rcu(drhd, &dmar_drhd_units, list)           \
+       list_for_each_entry_rcu(drhd, &dmar_drhd_units, list,           \
+                               dmar_rcu_check())                       \
                if (drhd->ignored) {} else
 
 #define for_each_active_iommu(i, drhd)                                 \
-       list_for_each_entry_rcu(drhd, &dmar_drhd_units, list)           \
+       list_for_each_entry_rcu(drhd, &dmar_drhd_units, list,           \
+                               dmar_rcu_check())                       \
                if (i=drhd->iommu, drhd->ignored) {} else
 
 #define for_each_iommu(i, drhd)                                                \
-       list_for_each_entry_rcu(drhd, &dmar_drhd_units, list)           \
+       list_for_each_entry_rcu(drhd, &dmar_drhd_units, list,           \
+                               dmar_rcu_check())                       \
                if (i=drhd->iommu, 0) {} else 
 
 static inline bool dmar_rcu_check(void)
index 0aa803c..c620d91 100644 (file)
@@ -28,8 +28,6 @@ int dsa_8021q_rx_switch_id(u16 vid);
 
 int dsa_8021q_rx_source_port(u16 vid);
 
-struct sk_buff *dsa_8021q_remove_header(struct sk_buff *skb);
-
 #else
 
 int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index,
@@ -64,11 +62,6 @@ int dsa_8021q_rx_source_port(u16 vid)
        return 0;
 }
 
-struct sk_buff *dsa_8021q_remove_header(struct sk_buff *skb)
-{
-       return NULL;
-}
-
 #endif /* IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q) */
 
 #endif /* _NET_DSA_8021Q_H */
index 14f072e..82ebf92 100644 (file)
@@ -25,7 +25,6 @@ struct dw_apb_timer {
 struct dw_apb_clock_event_device {
        struct clock_event_device               ced;
        struct dw_apb_timer                     timer;
-       struct irqaction                        irqaction;
        void                                    (*eoi)(struct dw_apb_timer *);
 };
 
index cc31b97..0f20b98 100644 (file)
@@ -383,6 +383,9 @@ struct dimm_info {
        unsigned int csrow, cschannel;  /* Points to the old API data */
 
        u16 smbios_handle;              /* Handle for SMBIOS type 17 */
+
+       u32 ce_count;
+       u32 ue_count;
 };
 
 /**
@@ -442,6 +445,7 @@ struct errcount_attribute_data {
  * struct edac_raw_error_desc - Raw error report structure
  * @grain:                     minimum granularity for an error report, in bytes
  * @error_count:               number of errors of the same type
+ * @type:                      severity of the error (CE/UE/Fatal)
  * @top_layer:                 top layer of the error (layer[0])
  * @mid_layer:                 middle layer of the error (layer[1])
  * @low_layer:                 low layer of the error (layer[2])
@@ -453,8 +457,6 @@ struct errcount_attribute_data {
  * @location:                  location of the error
  * @label:                     label of the affected DIMM(s)
  * @other_detail:              other driver-specific detail about the error
- * @enable_per_layer_report:   if false, the error affects all layers
- *                             (typically, a memory controller error)
  */
 struct edac_raw_error_desc {
        char location[LOCATION_SIZE];
@@ -462,6 +464,7 @@ struct edac_raw_error_desc {
        long grain;
 
        u16 error_count;
+       enum hw_event_mc_err_type type;
        int top_layer;
        int mid_layer;
        int low_layer;
@@ -470,7 +473,6 @@ struct edac_raw_error_desc {
        unsigned long syndrome;
        const char *msg;
        const char *other_detail;
-       bool enable_per_layer_report;
 };
 
 /* MEMORY controller information structure
@@ -560,7 +562,6 @@ struct mem_ctl_info {
         */
        u32 ce_noinfo_count, ue_noinfo_count;
        u32 ue_mc, ce_mc;
-       u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 
        struct completion complete;
 
index 7efd707..abfc98e 100644 (file)
@@ -56,19 +56,6 @@ typedef void *efi_handle_t;
 #define __efiapi
 #endif
 
-#define efi_get_handle_at(array, idx)                                  \
-       (efi_is_native() ? (array)[idx]                                 \
-               : (efi_handle_t)(unsigned long)((u32 *)(array))[idx])
-
-#define efi_get_handle_num(size)                                       \
-       ((size) / (efi_is_native() ? sizeof(efi_handle_t) : sizeof(u32)))
-
-#define for_each_efi_handle(handle, array, size, i)                    \
-       for (i = 0;                                                     \
-            i < efi_get_handle_num(size) &&                            \
-               ((handle = efi_get_handle_at((array), i)) || true);     \
-            i++)
-
 /*
  * The UEFI spec and EDK2 reference implementation both define EFI_GUID as
  * struct { u32 a; u16; b; u16 c; u8 d[8]; }; and so the implied alignment
@@ -157,15 +144,6 @@ typedef struct {
        u32 imagesize;
 } efi_capsule_header_t;
 
-struct efi_boot_memmap {
-       efi_memory_desc_t       **map;
-       unsigned long           *map_size;
-       unsigned long           *desc_size;
-       u32                     *desc_ver;
-       unsigned long           *key_ptr;
-       unsigned long           *buff_size;
-};
-
 /*
  * EFI capsule flags
  */
@@ -187,14 +165,6 @@ struct capsule_info {
 
 int __efi_capsule_setup_info(struct capsule_info *cap_info);
 
-/*
- * Allocation types for calls to boottime->allocate_pages.
- */
-#define EFI_ALLOCATE_ANY_PAGES         0
-#define EFI_ALLOCATE_MAX_ADDRESS       1
-#define EFI_ALLOCATE_ADDRESS           2
-#define EFI_MAX_ALLOCATE_TYPE          3
-
 typedef int (*efi_freemem_callback_t) (u64 start, u64 end, void *arg);
 
 /*
@@ -224,291 +194,7 @@ typedef struct {
        u8 sets_to_zero;
 } efi_time_cap_t;
 
-typedef struct {
-       efi_table_hdr_t hdr;
-       u32 raise_tpl;
-       u32 restore_tpl;
-       u32 allocate_pages;
-       u32 free_pages;
-       u32 get_memory_map;
-       u32 allocate_pool;
-       u32 free_pool;
-       u32 create_event;
-       u32 set_timer;
-       u32 wait_for_event;
-       u32 signal_event;
-       u32 close_event;
-       u32 check_event;
-       u32 install_protocol_interface;
-       u32 reinstall_protocol_interface;
-       u32 uninstall_protocol_interface;
-       u32 handle_protocol;
-       u32 __reserved;
-       u32 register_protocol_notify;
-       u32 locate_handle;
-       u32 locate_device_path;
-       u32 install_configuration_table;
-       u32 load_image;
-       u32 start_image;
-       u32 exit;
-       u32 unload_image;
-       u32 exit_boot_services;
-       u32 get_next_monotonic_count;
-       u32 stall;
-       u32 set_watchdog_timer;
-       u32 connect_controller;
-       u32 disconnect_controller;
-       u32 open_protocol;
-       u32 close_protocol;
-       u32 open_protocol_information;
-       u32 protocols_per_handle;
-       u32 locate_handle_buffer;
-       u32 locate_protocol;
-       u32 install_multiple_protocol_interfaces;
-       u32 uninstall_multiple_protocol_interfaces;
-       u32 calculate_crc32;
-       u32 copy_mem;
-       u32 set_mem;
-       u32 create_event_ex;
-} __packed efi_boot_services_32_t;
-
-/*
- * EFI Boot Services table
- */
-typedef union {
-       struct {
-               efi_table_hdr_t hdr;
-               void *raise_tpl;
-               void *restore_tpl;
-               efi_status_t (__efiapi *allocate_pages)(int, int, unsigned long,
-                                                       efi_physical_addr_t *);
-               efi_status_t (__efiapi *free_pages)(efi_physical_addr_t,
-                                                   unsigned long);
-               efi_status_t (__efiapi *get_memory_map)(unsigned long *, void *,
-                                                       unsigned long *,
-                                                       unsigned long *, u32 *);
-               efi_status_t (__efiapi *allocate_pool)(int, unsigned long,
-                                                      void **);
-               efi_status_t (__efiapi *free_pool)(void *);
-               void *create_event;
-               void *set_timer;
-               void *wait_for_event;
-               void *signal_event;
-               void *close_event;
-               void *check_event;
-               void *install_protocol_interface;
-               void *reinstall_protocol_interface;
-               void *uninstall_protocol_interface;
-               efi_status_t (__efiapi *handle_protocol)(efi_handle_t,
-                                                        efi_guid_t *, void **);
-               void *__reserved;
-               void *register_protocol_notify;
-               efi_status_t (__efiapi *locate_handle)(int, efi_guid_t *,
-                                                      void *, unsigned long *,
-                                                      efi_handle_t *);
-               void *locate_device_path;
-               efi_status_t (__efiapi *install_configuration_table)(efi_guid_t *,
-                                                                    void *);
-               void *load_image;
-               void *start_image;
-               void *exit;
-               void *unload_image;
-               efi_status_t (__efiapi *exit_boot_services)(efi_handle_t,
-                                                           unsigned long);
-               void *get_next_monotonic_count;
-               void *stall;
-               void *set_watchdog_timer;
-               void *connect_controller;
-               efi_status_t (__efiapi *disconnect_controller)(efi_handle_t,
-                                                              efi_handle_t,
-                                                              efi_handle_t);
-               void *open_protocol;
-               void *close_protocol;
-               void *open_protocol_information;
-               void *protocols_per_handle;
-               void *locate_handle_buffer;
-               efi_status_t (__efiapi *locate_protocol)(efi_guid_t *, void *,
-                                                        void **);
-               void *install_multiple_protocol_interfaces;
-               void *uninstall_multiple_protocol_interfaces;
-               void *calculate_crc32;
-               void *copy_mem;
-               void *set_mem;
-               void *create_event_ex;
-       };
-       efi_boot_services_32_t mixed_mode;
-} efi_boot_services_t;
-
-typedef enum {
-       EfiPciIoWidthUint8,
-       EfiPciIoWidthUint16,
-       EfiPciIoWidthUint32,
-       EfiPciIoWidthUint64,
-       EfiPciIoWidthFifoUint8,
-       EfiPciIoWidthFifoUint16,
-       EfiPciIoWidthFifoUint32,
-       EfiPciIoWidthFifoUint64,
-       EfiPciIoWidthFillUint8,
-       EfiPciIoWidthFillUint16,
-       EfiPciIoWidthFillUint32,
-       EfiPciIoWidthFillUint64,
-       EfiPciIoWidthMaximum
-} EFI_PCI_IO_PROTOCOL_WIDTH;
-
-typedef enum {
-       EfiPciIoAttributeOperationGet,
-       EfiPciIoAttributeOperationSet,
-       EfiPciIoAttributeOperationEnable,
-       EfiPciIoAttributeOperationDisable,
-       EfiPciIoAttributeOperationSupported,
-    EfiPciIoAttributeOperationMaximum
-} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION;
-
-typedef struct {
-       u32 read;
-       u32 write;
-} efi_pci_io_protocol_access_32_t;
-
-typedef union efi_pci_io_protocol efi_pci_io_protocol_t;
-
-typedef
-efi_status_t (__efiapi *efi_pci_io_protocol_cfg_t)(efi_pci_io_protocol_t *,
-                                                  EFI_PCI_IO_PROTOCOL_WIDTH,
-                                                  u32 offset,
-                                                  unsigned long count,
-                                                  void *buffer);
-
-typedef struct {
-       void *read;
-       void *write;
-} efi_pci_io_protocol_access_t;
-
-typedef struct {
-       efi_pci_io_protocol_cfg_t read;
-       efi_pci_io_protocol_cfg_t write;
-} efi_pci_io_protocol_config_access_t;
-
-union efi_pci_io_protocol {
-       struct {
-               void *poll_mem;
-               void *poll_io;
-               efi_pci_io_protocol_access_t mem;
-               efi_pci_io_protocol_access_t io;
-               efi_pci_io_protocol_config_access_t pci;
-               void *copy_mem;
-               void *map;
-               void *unmap;
-               void *allocate_buffer;
-               void *free_buffer;
-               void *flush;
-               efi_status_t (__efiapi *get_location)(efi_pci_io_protocol_t *,
-                                                     unsigned long *segment_nr,
-                                                     unsigned long *bus_nr,
-                                                     unsigned long *device_nr,
-                                                     unsigned long *func_nr);
-               void *attributes;
-               void *get_bar_attributes;
-               void *set_bar_attributes;
-               uint64_t romsize;
-               void *romimage;
-       };
-       struct {
-               u32 poll_mem;
-               u32 poll_io;
-               efi_pci_io_protocol_access_32_t mem;
-               efi_pci_io_protocol_access_32_t io;
-               efi_pci_io_protocol_access_32_t pci;
-               u32 copy_mem;
-               u32 map;
-               u32 unmap;
-               u32 allocate_buffer;
-               u32 free_buffer;
-               u32 flush;
-               u32 get_location;
-               u32 attributes;
-               u32 get_bar_attributes;
-               u32 set_bar_attributes;
-               u64 romsize;
-               u32 romimage;
-       } mixed_mode;
-};
-
-#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
-#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002
-#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004
-#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008
-#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010
-#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
-#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
-#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
-#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100
-#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200
-#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400
-#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800
-#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000
-#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000
-#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000
-#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
-#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000
-#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000
-#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000
-
-struct efi_dev_path;
-
-typedef union apple_properties_protocol apple_properties_protocol_t;
-
-union apple_properties_protocol {
-       struct {
-               unsigned long version;
-               efi_status_t (__efiapi *get)(apple_properties_protocol_t *,
-                                            struct efi_dev_path *,
-                                            efi_char16_t *, void *, u32 *);
-               efi_status_t (__efiapi *set)(apple_properties_protocol_t *,
-                                            struct efi_dev_path *,
-                                            efi_char16_t *, void *, u32);
-               efi_status_t (__efiapi *del)(apple_properties_protocol_t *,
-                                            struct efi_dev_path *,
-                                            efi_char16_t *);
-               efi_status_t (__efiapi *get_all)(apple_properties_protocol_t *,
-                                                void *buffer, u32 *);
-       };
-       struct {
-               u32 version;
-               u32 get;
-               u32 set;
-               u32 del;
-               u32 get_all;
-       } mixed_mode;
-};
-
-typedef u32 efi_tcg2_event_log_format;
-
-typedef union efi_tcg2_protocol efi_tcg2_protocol_t;
-
-union efi_tcg2_protocol {
-       struct {
-               void *get_capability;
-               efi_status_t (__efiapi *get_event_log)(efi_handle_t,
-                                                      efi_tcg2_event_log_format,
-                                                      efi_physical_addr_t *,
-                                                      efi_physical_addr_t *,
-                                                      efi_bool_t *);
-               void *hash_log_extend_event;
-               void *submit_command;
-               void *get_active_pcr_banks;
-               void *set_active_pcr_banks;
-               void *get_result_of_set_active_pcr_banks;
-       };
-       struct {
-               u32 get_capability;
-               u32 get_event_log;
-               u32 hash_log_extend_event;
-               u32 submit_command;
-               u32 get_active_pcr_banks;
-               u32 set_active_pcr_banks;
-               u32 get_result_of_set_active_pcr_banks;
-       } mixed_mode;
-};
+typedef union efi_boot_services efi_boot_services_t;
 
 /*
  * Types and defines for EFI ResetSystem
@@ -646,6 +332,9 @@ void efi_native_runtime_setup(void);
 #define EFI_CONSOLE_OUT_DEVICE_GUID            EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4,  0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 #define APPLE_PROPERTIES_PROTOCOL_GUID         EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb,  0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
 #define EFI_TCG2_PROTOCOL_GUID                 EFI_GUID(0x607f766c, 0x7455, 0x42be,  0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
+#define EFI_LOAD_FILE_PROTOCOL_GUID            EFI_GUID(0x56ec3091, 0x954c, 0x11d2,  0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define EFI_LOAD_FILE2_PROTOCOL_GUID           EFI_GUID(0x4006c0c1, 0xfcb3, 0x403e,  0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d)
+#define EFI_RT_PROPERTIES_TABLE_GUID           EFI_GUID(0xeb66918a, 0x7eef, 0x402a,  0x84, 0x2e, 0x93, 0x1d, 0x21, 0xc3, 0x8a, 0xe9)
 
 #define EFI_IMAGE_SECURITY_DATABASE_GUID       EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596,  0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
 #define EFI_SHIM_LOCK_GUID                     EFI_GUID(0x605dab50, 0xe046, 0x4300,  0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
@@ -665,6 +354,7 @@ void efi_native_runtime_setup(void);
 #define LINUX_EFI_TPM_EVENT_LOG_GUID           EFI_GUID(0xb7799cb0, 0xeca2, 0x4943,  0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
 #define LINUX_EFI_TPM_FINAL_LOG_GUID           EFI_GUID(0x1e2ed096, 0x30e2, 0x4254,  0xbd, 0x89, 0x86, 0x3b, 0xbe, 0xf8, 0x23, 0x25)
 #define LINUX_EFI_MEMRESERVE_TABLE_GUID                EFI_GUID(0x888eb0c6, 0x8ede, 0x4ff5,  0xa8, 0xf0, 0x9a, 0xee, 0x5c, 0xb9, 0x77, 0xc2)
+#define LINUX_EFI_INITRD_MEDIA_GUID            EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
 
 /* OEM GUIDs */
 #define DELLEMC_EFI_RCI2_TABLE_GUID            EFI_GUID(0x2d9f28a2, 0xa886, 0x456a,  0x97, 0xa8, 0xf1, 0x1e, 0xf2, 0x4f, 0xf4, 0x55)
@@ -788,74 +478,6 @@ struct efi_mem_range {
        u64 attribute;
 };
 
-struct efi_fdt_params {
-       u64 system_table;
-       u64 mmap;
-       u32 mmap_size;
-       u32 desc_size;
-       u32 desc_ver;
-};
-
-typedef struct {
-       u32 revision;
-       efi_handle_t parent_handle;
-       efi_system_table_t *system_table;
-       efi_handle_t device_handle;
-       void *file_path;
-       void *reserved;
-       u32 load_options_size;
-       void *load_options;
-       void *image_base;
-       __aligned_u64 image_size;
-       unsigned int image_code_type;
-       unsigned int image_data_type;
-       efi_status_t ( __efiapi *unload)(efi_handle_t image_handle);
-} efi_loaded_image_t;
-
-typedef struct {
-       u64 size;
-       u64 file_size;
-       u64 phys_size;
-       efi_time_t create_time;
-       efi_time_t last_access_time;
-       efi_time_t modification_time;
-       __aligned_u64 attribute;
-       efi_char16_t filename[1];
-} efi_file_info_t;
-
-typedef struct efi_file_handle efi_file_handle_t;
-
-struct efi_file_handle {
-       u64 revision;
-       efi_status_t (__efiapi *open)(efi_file_handle_t *,
-                                     efi_file_handle_t **,
-                                     efi_char16_t *, u64, u64);
-       efi_status_t (__efiapi *close)(efi_file_handle_t *);
-       void *delete;
-       efi_status_t (__efiapi *read)(efi_file_handle_t *,
-                                     unsigned long *, void *);
-       void *write;
-       void *get_position;
-       void *set_position;
-       efi_status_t (__efiapi *get_info)(efi_file_handle_t *,
-                                         efi_guid_t *, unsigned long *,
-                                         void *);
-       void *set_info;
-       void *flush;
-};
-
-typedef struct efi_file_io_interface efi_file_io_interface_t;
-
-struct efi_file_io_interface {
-       u64 revision;
-       int (__efiapi *open_volume)(efi_file_io_interface_t *,
-                                   efi_file_handle_t **);
-};
-
-#define EFI_FILE_MODE_READ     0x0000000000000001
-#define EFI_FILE_MODE_WRITE    0x0000000000000002
-#define EFI_FILE_MODE_CREATE   0x8000000000000000
-
 typedef struct {
        u32 version;
        u32 length;
@@ -865,6 +487,14 @@ typedef struct {
 #define EFI_PROPERTIES_TABLE_VERSION   0x00010000
 #define EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA        0x1
 
+typedef struct {
+       u16 version;
+       u16 length;
+       u32 runtime_services_supported;
+} efi_rt_properties_table_t;
+
+#define EFI_RT_PROPERTIES_TABLE_VERSION        0x1
+
 #define EFI_INVALID_TABLE_ADDR         (~0UL)
 
 typedef struct {
@@ -896,48 +526,63 @@ typedef struct {
        efi_time_t time_of_revocation;
 } efi_cert_x509_sha256_t;
 
+extern unsigned long __ro_after_init efi_rng_seed;             /* RNG Seed table */
+
 /*
  * All runtime access to EFI goes through this structure:
  */
 extern struct efi {
-       efi_system_table_t *systab;     /* EFI system table */
-       unsigned int runtime_version;   /* Runtime services version */
-       unsigned long mps;              /* MPS table */
-       unsigned long acpi;             /* ACPI table  (IA64 ext 0.71) */
-       unsigned long acpi20;           /* ACPI table  (ACPI 2.0) */
-       unsigned long smbios;           /* SMBIOS table (32 bit entry point) */
-       unsigned long smbios3;          /* SMBIOS table (64 bit entry point) */
-       unsigned long boot_info;        /* boot info table */
-       unsigned long hcdp;             /* HCDP table */
-       unsigned long uga;              /* UGA table */
-       unsigned long fw_vendor;        /* fw_vendor */
-       unsigned long runtime;          /* runtime table */
-       unsigned long config_table;     /* config tables */
-       unsigned long esrt;             /* ESRT table */
-       unsigned long properties_table; /* properties table */
-       unsigned long mem_attr_table;   /* memory attributes table */
-       unsigned long rng_seed;         /* UEFI firmware random seed */
-       unsigned long tpm_log;          /* TPM2 Event Log table */
-       unsigned long tpm_final_log;    /* TPM2 Final Events Log table */
-       unsigned long mem_reserve;      /* Linux EFI memreserve table */
-       efi_get_time_t *get_time;
-       efi_set_time_t *set_time;
-       efi_get_wakeup_time_t *get_wakeup_time;
-       efi_set_wakeup_time_t *set_wakeup_time;
-       efi_get_variable_t *get_variable;
-       efi_get_next_variable_t *get_next_variable;
-       efi_set_variable_t *set_variable;
-       efi_set_variable_t *set_variable_nonblocking;
-       efi_query_variable_info_t *query_variable_info;
-       efi_query_variable_info_t *query_variable_info_nonblocking;
-       efi_update_capsule_t *update_capsule;
-       efi_query_capsule_caps_t *query_capsule_caps;
-       efi_get_next_high_mono_count_t *get_next_high_mono_count;
-       efi_reset_system_t *reset_system;
-       struct efi_memory_map memmap;
-       unsigned long flags;
+       const efi_runtime_services_t    *runtime;               /* EFI runtime services table */
+       unsigned int                    runtime_version;        /* Runtime services version */
+       unsigned int                    runtime_supported_mask;
+
+       unsigned long                   acpi;                   /* ACPI table  (IA64 ext 0.71) */
+       unsigned long                   acpi20;                 /* ACPI table  (ACPI 2.0) */
+       unsigned long                   smbios;                 /* SMBIOS table (32 bit entry point) */
+       unsigned long                   smbios3;                /* SMBIOS table (64 bit entry point) */
+       unsigned long                   esrt;                   /* ESRT table */
+       unsigned long                   tpm_log;                /* TPM2 Event Log table */
+       unsigned long                   tpm_final_log;          /* TPM2 Final Events Log table */
+
+       efi_get_time_t                  *get_time;
+       efi_set_time_t                  *set_time;
+       efi_get_wakeup_time_t           *get_wakeup_time;
+       efi_set_wakeup_time_t           *set_wakeup_time;
+       efi_get_variable_t              *get_variable;
+       efi_get_next_variable_t         *get_next_variable;
+       efi_set_variable_t              *set_variable;
+       efi_set_variable_t              *set_variable_nonblocking;
+       efi_query_variable_info_t       *query_variable_info;
+       efi_query_variable_info_t       *query_variable_info_nonblocking;
+       efi_update_capsule_t            *update_capsule;
+       efi_query_capsule_caps_t        *query_capsule_caps;
+       efi_get_next_high_mono_count_t  *get_next_high_mono_count;
+       efi_reset_system_t              *reset_system;
+
+       struct efi_memory_map           memmap;
+       unsigned long                   flags;
 } efi;
 
+#define EFI_RT_SUPPORTED_GET_TIME                              0x0001
+#define EFI_RT_SUPPORTED_SET_TIME                              0x0002
+#define EFI_RT_SUPPORTED_GET_WAKEUP_TIME                       0x0004
+#define EFI_RT_SUPPORTED_SET_WAKEUP_TIME                       0x0008
+#define EFI_RT_SUPPORTED_GET_VARIABLE                          0x0010
+#define EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME                        0x0020
+#define EFI_RT_SUPPORTED_SET_VARIABLE                          0x0040
+#define EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP               0x0080
+#define EFI_RT_SUPPORTED_CONVERT_POINTER                       0x0100
+#define EFI_RT_SUPPORTED_GET_NEXT_HIGH_MONOTONIC_COUNT         0x0200
+#define EFI_RT_SUPPORTED_RESET_SYSTEM                          0x0400
+#define EFI_RT_SUPPORTED_UPDATE_CAPSULE                                0x0800
+#define EFI_RT_SUPPORTED_QUERY_CAPSULE_CAPABILITIES            0x1000
+#define EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO                   0x2000
+
+#define EFI_RT_SUPPORTED_ALL                                   0x3fff
+
+#define EFI_RT_SUPPORTED_TIME_SERVICES                         0x000f
+#define EFI_RT_SUPPORTED_VARIABLE_SERVICES                     0x0070
+
 extern struct mm_struct efi_mm;
 
 static inline int
@@ -987,14 +632,18 @@ extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
 extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
                                     void *buf, struct efi_mem_range *mem);
 
-extern int efi_config_init(efi_config_table_type_t *arch_tables);
 #ifdef CONFIG_EFI_ESRT
 extern void __init efi_esrt_init(void);
 #else
 static inline void efi_esrt_init(void) { }
 #endif
-extern int efi_config_parse_tables(void *config_tables, int count, int sz,
-                                  efi_config_table_type_t *arch_tables);
+extern int efi_config_parse_tables(const efi_config_table_t *config_tables,
+                                  int count,
+                                  const efi_config_table_type_t *arch_tables);
+extern int efi_systab_check_header(const efi_table_hdr_t *systab_hdr,
+                                  int min_major_version);
+extern void efi_systab_report_header(const efi_table_hdr_t *systab_hdr,
+                                    unsigned long fw_vendor);
 extern u64 efi_get_iobase (void);
 extern int efi_mem_type(unsigned long phys_addr);
 extern u64 efi_mem_attributes (unsigned long phys_addr);
@@ -1006,7 +655,7 @@ extern void efi_mem_reserve(phys_addr_t addr, u64 size);
 extern int efi_mem_reserve_persistent(phys_addr_t addr, u64 size);
 extern void efi_initialize_iomem_resources(struct resource *code_resource,
                struct resource *data_resource, struct resource *bss_resource);
-extern int efi_get_fdt_params(struct efi_fdt_params *params);
+extern u64 efi_get_fdt_params(struct efi_memory_map_data *data);
 extern struct kobject *efi_kobj;
 
 extern int efi_reboot_quirk_mode;
@@ -1018,6 +667,8 @@ extern void __init efi_fake_memmap(void);
 static inline void efi_fake_memmap(void) { }
 #endif
 
+extern unsigned long efi_mem_attr_table;
+
 /*
  * efi_memattr_perm_setter - arch specific callback function passed into
  *                           efi_memattr_apply_permissions() that updates the
@@ -1124,6 +775,7 @@ extern int __init efi_setup_pcdp_console(char *);
 #define EFI_NX_PE_DATA         9       /* Can runtime data regions be mapped non-executable? */
 #define EFI_MEM_ATTR           10      /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */
 #define EFI_MEM_NO_SOFT_RESERVE        11      /* Is the kernel configured to ignore soft reservations? */
+#define EFI_PRESERVE_BS_REGIONS        12      /* Are EFI boot-services memory segments available? */
 
 #ifdef CONFIG_EFI
 /*
@@ -1142,6 +794,11 @@ static inline bool __pure efi_soft_reserve_enabled(void)
        return IS_ENABLED(CONFIG_EFI_SOFT_RESERVE)
                && __efi_soft_reserve_enabled();
 }
+
+static inline bool efi_rt_services_supported(unsigned int mask)
+{
+       return (efi.runtime_supported_mask & mask) == mask;
+}
 #else
 static inline bool efi_enabled(int feature)
 {
@@ -1160,6 +817,11 @@ static inline bool efi_soft_reserve_enabled(void)
 {
        return false;
 }
+
+static inline bool efi_rt_services_supported(unsigned int mask)
+{
+       return false;
+}
 #endif
 
 extern int efi_status_to_err(efi_status_t status);
@@ -1189,13 +851,6 @@ extern int efi_status_to_err(efi_status_t status);
 #define EFI_VARIABLE_GUID_LEN  UUID_STRING_LEN
 
 /*
- * The type of search to perform when calling boottime->locate_handle
- */
-#define EFI_LOCATE_ALL_HANDLES                 0
-#define EFI_LOCATE_BY_REGISTER_NOTIFY          1
-#define EFI_LOCATE_BY_PROTOCOL                 2
-
-/*
  * EFI Device Path information
  */
 #define EFI_DEV_HW                     0x01
@@ -1234,30 +889,40 @@ extern int efi_status_to_err(efi_status_t status);
 #define   EFI_DEV_END_ENTIRE                   0xFF
 
 struct efi_generic_dev_path {
-       u8 type;
-       u8 sub_type;
-       u16 length;
-} __attribute ((packed));
+       u8                              type;
+       u8                              sub_type;
+       u16                             length;
+} __packed;
+
+struct efi_acpi_dev_path {
+       struct efi_generic_dev_path     header;
+       u32                             hid;
+       u32                             uid;
+} __packed;
+
+struct efi_pci_dev_path {
+       struct efi_generic_dev_path     header;
+       u8                              fn;
+       u8                              dev;
+} __packed;
+
+struct efi_vendor_dev_path {
+       struct efi_generic_dev_path     header;
+       efi_guid_t                      vendorguid;
+       u8                              vendordata[];
+} __packed;
 
 struct efi_dev_path {
-       u8 type;        /* can be replaced with unnamed */
-       u8 sub_type;    /* struct efi_generic_dev_path; */
-       u16 length;     /* once we've moved to -std=c11 */
        union {
-               struct {
-                       u32 hid;
-                       u32 uid;
-               } acpi;
-               struct {
-                       u8 fn;
-                       u8 dev;
-               } pci;
+               struct efi_generic_dev_path     header;
+               struct efi_acpi_dev_path        acpi;
+               struct efi_pci_dev_path         pci;
+               struct efi_vendor_dev_path      vendor;
        };
-} __attribute ((packed));
+} __packed;
 
-#if IS_ENABLED(CONFIG_EFI_DEV_PATH_PARSER)
-struct device *efi_get_device_by_path(struct efi_dev_path **node, size_t *len);
-#endif
+struct device *efi_get_device_by_path(const struct efi_dev_path **node,
+                                     size_t *len);
 
 static inline void memrange_efi_to_native(u64 *addr, u64 *npages)
 {
@@ -1312,80 +977,6 @@ struct efivar_entry {
        bool deleting;
 };
 
-union efi_simple_text_output_protocol {
-       struct {
-               void *reset;
-               efi_status_t (__efiapi *output_string)(efi_simple_text_output_protocol_t *,
-                                                      efi_char16_t *);
-               void *test_string;
-       };
-       struct {
-               u32 reset;
-               u32 output_string;
-               u32 test_string;
-       } mixed_mode;
-};
-
-#define PIXEL_RGB_RESERVED_8BIT_PER_COLOR              0
-#define PIXEL_BGR_RESERVED_8BIT_PER_COLOR              1
-#define PIXEL_BIT_MASK                                 2
-#define PIXEL_BLT_ONLY                                 3
-#define PIXEL_FORMAT_MAX                               4
-
-typedef struct {
-       u32 red_mask;
-       u32 green_mask;
-       u32 blue_mask;
-       u32 reserved_mask;
-} efi_pixel_bitmask_t;
-
-typedef struct {
-       u32 version;
-       u32 horizontal_resolution;
-       u32 vertical_resolution;
-       int pixel_format;
-       efi_pixel_bitmask_t pixel_information;
-       u32 pixels_per_scan_line;
-} efi_graphics_output_mode_info_t;
-
-typedef union efi_graphics_output_protocol_mode efi_graphics_output_protocol_mode_t;
-
-union efi_graphics_output_protocol_mode {
-       struct {
-               u32 max_mode;
-               u32 mode;
-               efi_graphics_output_mode_info_t *info;
-               unsigned long size_of_info;
-               efi_physical_addr_t frame_buffer_base;
-               unsigned long frame_buffer_size;
-       };
-       struct {
-               u32 max_mode;
-               u32 mode;
-               u32 info;
-               u32 size_of_info;
-               u64 frame_buffer_base;
-               u32 frame_buffer_size;
-       } mixed_mode;
-};
-
-typedef union efi_graphics_output_protocol efi_graphics_output_protocol_t;
-
-union efi_graphics_output_protocol {
-       struct {
-               void *query_mode;
-               void *set_mode;
-               void *blt;
-               efi_graphics_output_protocol_mode_t *mode;
-       };
-       struct {
-               u32 query_mode;
-               u32 set_mode;
-               u32 blt;
-               u32 mode;
-       } mixed_mode;
-};
-
 extern struct list_head efivar_sysfs_list;
 
 static inline void
@@ -1483,52 +1074,6 @@ static inline int efi_runtime_map_copy(void *buf, size_t bufsz)
 
 #endif
 
-/* prototypes shared between arch specific and generic stub code */
-
-void efi_printk(char *str);
-
-void efi_free(unsigned long size, unsigned long addr);
-
-char *efi_convert_cmdline(efi_loaded_image_t *image, int *cmd_line_len);
-
-efi_status_t efi_get_memory_map(struct efi_boot_memmap *map);
-
-efi_status_t efi_low_alloc_above(unsigned long size, unsigned long align,
-                                unsigned long *addr, unsigned long min);
-
-static inline
-efi_status_t efi_low_alloc(unsigned long size, unsigned long align,
-                          unsigned long *addr)
-{
-       /*
-        * Don't allocate at 0x0. It will confuse code that
-        * checks pointers against NULL. Skip the first 8
-        * bytes so we start at a nice even number.
-        */
-       return efi_low_alloc_above(size, align, addr, 0x8);
-}
-
-efi_status_t efi_high_alloc(unsigned long size, unsigned long align,
-                           unsigned long *addr, unsigned long max);
-
-efi_status_t efi_relocate_kernel(unsigned long *image_addr,
-                                unsigned long image_size,
-                                unsigned long alloc_size,
-                                unsigned long preferred_addr,
-                                unsigned long alignment,
-                                unsigned long min_addr);
-
-efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
-                                 char *cmd_line, char *option_string,
-                                 unsigned long max_addr,
-                                 unsigned long *load_addr,
-                                 unsigned long *load_size);
-
-efi_status_t efi_parse_options(char const *cmdline);
-
-efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
-                          unsigned long size);
-
 #ifdef CONFIG_EFI
 extern bool efi_runtime_disabled(void);
 #else
@@ -1553,6 +1098,12 @@ static inline void
 efi_enable_reset_attack_mitigation(void) { }
 #endif
 
+#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
+void efi_check_for_embedded_firmwares(void);
+#else
+static inline void efi_check_for_embedded_firmwares(void) { }
+#endif
+
 efi_status_t efi_random_get_seed(void);
 
 void efi_retrieve_tpm2_eventlog(void);
@@ -1606,15 +1157,6 @@ void efi_retrieve_tpm2_eventlog(void);
        arch_efi_call_virt_teardown();                                  \
 })
 
-typedef efi_status_t (*efi_exit_boot_map_processing)(
-       struct efi_boot_memmap *map,
-       void *priv);
-
-efi_status_t efi_exit_boot_services(void *handle,
-                                   struct efi_boot_memmap *map,
-                                   void *priv,
-                                   efi_exit_boot_map_processing priv_func);
-
 #define EFI_RANDOM_SEED_SIZE           64U
 
 struct linux_efi_random_seed {
@@ -1701,6 +1243,4 @@ struct linux_efi_memreserve {
 #define EFI_MEMRESERVE_COUNT(size) (((size) - sizeof(struct linux_efi_memreserve)) \
        / sizeof(((struct linux_efi_memreserve *)0)->entry[0]))
 
-void efi_pci_disable_bridge_busmaster(void);
-
 #endif /* _LINUX_EFI_H */
diff --git a/include/linux/efi_embedded_fw.h b/include/linux/efi_embedded_fw.h
new file mode 100644 (file)
index 0000000..57eac52
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_EFI_EMBEDDED_FW_H
+#define _LINUX_EFI_EMBEDDED_FW_H
+
+#include <linux/list.h>
+#include <linux/mod_devicetable.h>
+
+#define EFI_EMBEDDED_FW_PREFIX_LEN             8
+
+/*
+ * This struct and efi_embedded_fw_list are private to the efi-embedded fw
+ * implementation they are in this header for use by lib/test_firmware.c only!
+ */
+struct efi_embedded_fw {
+       struct list_head list;
+       const char *name;
+       const u8 *data;
+       size_t length;
+};
+
+extern struct list_head efi_embedded_fw_list;
+
+/**
+ * struct efi_embedded_fw_desc - This struct is used by the EFI embedded-fw
+ *                               code to search for embedded firmwares.
+ *
+ * @name:   Name to register the firmware with if found
+ * @prefix: First 8 bytes of the firmware
+ * @length: Length of the firmware in bytes including prefix
+ * @sha256: SHA256 of the firmware
+ */
+struct efi_embedded_fw_desc {
+       const char *name;
+       u8 prefix[EFI_EMBEDDED_FW_PREFIX_LEN];
+       u32 length;
+       u8 sha256[32];
+};
+
+extern const struct dmi_system_id touchscreen_dmi_table[];
+
+int efi_get_embedded_fw(const char *name, const u8 **dat, size_t *sz);
+
+#endif
index f236f5b..594d4e7 100644 (file)
@@ -59,7 +59,7 @@
        ELFNOTE_END
 
 #else  /* !__ASSEMBLER__ */
-#include <linux/elf.h>
+#include <uapi/linux/elf.h>
 /*
  * Use an anonymous structure which matches the shape of
  * Elf{32,64}_Nhdr, but includes the name and desc data.  The size and
index c6c7b24..142d102 100644 (file)
@@ -85,6 +85,7 @@ extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
 extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
 extern void set_close_on_exec(unsigned int fd, int flag);
 extern bool get_close_on_exec(unsigned int fd);
+extern int __get_unused_fd_flags(unsigned flags, unsigned long nofile);
 extern int get_unused_fd_flags(unsigned flags);
 extern void put_unused_fd(unsigned int fd);
 
index 2dd566c..4bbd0af 100644 (file)
@@ -44,6 +44,8 @@ int request_firmware(const struct firmware **fw, const char *name,
                     struct device *device);
 int firmware_request_nowarn(const struct firmware **fw, const char *name,
                            struct device *device);
+int firmware_request_platform(const struct firmware **fw, const char *name,
+                             struct device *device);
 int request_firmware_nowait(
        struct module *module, bool uevent,
        const char *name, struct device *device, gfp_t gfp, void *context,
@@ -69,6 +71,13 @@ static inline int firmware_request_nowarn(const struct firmware **fw,
        return -EINVAL;
 }
 
+static inline int firmware_request_platform(const struct firmware **fw,
+                                           const char *name,
+                                           struct device *device)
+{
+       return -EINVAL;
+}
+
 static inline int request_firmware_nowait(
        struct module *module, bool uevent,
        const char *name, struct device *device, gfp_t gfp, void *context,
index 3cd4fe6..3d69de6 100644 (file)
@@ -698,6 +698,7 @@ struct inode {
                struct rcu_head         i_rcu;
        };
        atomic64_t              i_version;
+       atomic64_t              i_sequence; /* see futex */
        atomic_t                i_count;
        atomic_t                i_dio_count;
        atomic_t                i_writecount;
@@ -2699,7 +2700,6 @@ static inline void unregister_chrdev(unsigned int major, const char *name)
 
 #ifdef CONFIG_BLOCK
 #define BLKDEV_MAJOR_MAX       512
-extern const char *__bdevname(dev_t, char *buffer);
 extern const char *bdevname(struct block_device *bdev, char *buffer);
 extern struct block_device *lookup_bdev(const char *);
 extern void blkdev_show(struct seq_file *,off_t);
@@ -2982,6 +2982,7 @@ extern int do_pipe_flags(int *, int);
        id(UNKNOWN, unknown)            \
        id(FIRMWARE, firmware)          \
        id(FIRMWARE_PREALLOC_BUFFER, firmware)  \
+       id(FIRMWARE_EFI_EMBEDDED, firmware)     \
        id(MODULE, kernel-module)               \
        id(KEXEC_IMAGE, kexec-image)            \
        id(KEXEC_INITRAMFS, kexec-initramfs)    \
@@ -3012,6 +3013,8 @@ extern int kernel_read_file(struct file *, void **, loff_t *, loff_t,
                            enum kernel_read_file_id);
 extern int kernel_read_file_from_path(const char *, void **, loff_t *, loff_t,
                                      enum kernel_read_file_id);
+extern int kernel_read_file_from_path_initns(const char *, void **, loff_t *, loff_t,
+                                            enum kernel_read_file_id);
 extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t,
                                    enum kernel_read_file_id);
 extern ssize_t kernel_read(struct file *, void *, size_t, loff_t *);
index 5cc3fed..b70df27 100644 (file)
@@ -31,23 +31,26 @@ struct task_struct;
 
 union futex_key {
        struct {
+               u64 i_seq;
                unsigned long pgoff;
-               struct inode *inode;
-               int offset;
+               unsigned int offset;
        } shared;
        struct {
+               union {
+                       struct mm_struct *mm;
+                       u64 __tmp;
+               };
                unsigned long address;
-               struct mm_struct *mm;
-               int offset;
+               unsigned int offset;
        } private;
        struct {
+               u64 ptr;
                unsigned long word;
-               void *ptr;
-               int offset;
+               unsigned int offset;
        } both;
 };
 
-#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } }
+#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = 0ULL } }
 
 #ifdef CONFIG_FUTEX
 enum {
index 8feeb94..e0abafb 100644 (file)
@@ -170,4 +170,6 @@ struct fwnode_operations {
        } while (false)
 #define get_dev_from_fwnode(fwnode)    get_device((fwnode)->dev)
 
+extern u32 fw_devlink_get_flags(void);
+
 #endif
index 6fbe585..9b3fffd 100644 (file)
 #define part_to_dev(part)      (&((part)->__dev))
 
 extern struct device_type part_type;
-extern struct kobject *block_depr;
 extern struct class block_class;
 
-enum {
-/* These three have identical behaviour; use the second one if DOS FDISK gets
-   confused about extended/logical partitions starting past cylinder 1023. */
-       DOS_EXTENDED_PARTITION = 5,
-       LINUX_EXTENDED_PARTITION = 0x85,
-       WIN98_EXTENDED_PARTITION = 0x0f,
-
-       SUN_WHOLE_DISK = DOS_EXTENDED_PARTITION,
-
-       LINUX_SWAP_PARTITION = 0x82,
-       LINUX_DATA_PARTITION = 0x83,
-       LINUX_LVM_PARTITION = 0x8e,
-       LINUX_RAID_PARTITION = 0xfd,    /* autodetect RAID partition */
-
-       SOLARIS_X86_PARTITION = LINUX_SWAP_PARTITION,
-       NEW_SOLARIS_X86_PARTITION = 0xbf,
-
-       DM6_AUX1PARTITION = 0x51,       /* no DDO:  use xlated geom */
-       DM6_AUX3PARTITION = 0x53,       /* no DDO:  use xlated geom */
-       DM6_PARTITION = 0x54,           /* has DDO: use xlated geom & offset */
-       EZD_PARTITION = 0x55,           /* EZ-DRIVE */
-
-       FREEBSD_PARTITION = 0xa5,       /* FreeBSD Partition ID */
-       OPENBSD_PARTITION = 0xa6,       /* OpenBSD Partition ID */
-       NETBSD_PARTITION = 0xa9,        /* NetBSD Partition ID */
-       BSDI_PARTITION = 0xb7,          /* BSDI Partition ID */
-       MINIX_PARTITION = 0x81,         /* Minix Partition ID */
-       UNIXWARE_PARTITION = 0x63,      /* Same as GNU_HURD and SCO Unix */
-};
-
 #define DISK_MAX_PARTS                 256
 #define DISK_NAME_LEN                  32
 
@@ -70,26 +39,12 @@ enum {
 #include <linux/fs.h>
 #include <linux/workqueue.h>
 
-struct partition {
-       unsigned char boot_ind;         /* 0x80 - active */
-       unsigned char head;             /* starting head */
-       unsigned char sector;           /* starting sector */
-       unsigned char cyl;              /* starting cylinder */
-       unsigned char sys_ind;          /* What partition type */
-       unsigned char end_head;         /* end head */
-       unsigned char end_sector;       /* end sector */
-       unsigned char end_cyl;          /* end cylinder */
-       __le32 start_sect;      /* starting sector counting from 0 */
-       __le32 nr_sects;                /* nr of sectors in partition */
-} __attribute__((packed));
-
 struct disk_stats {
        u64 nsecs[NR_STAT_GROUPS];
        unsigned long sectors[NR_STAT_GROUPS];
        unsigned long ios[NR_STAT_GROUPS];
        unsigned long merges[NR_STAT_GROUPS];
        unsigned long io_ticks;
-       unsigned long time_in_queue;
        local_t in_flight[2];
 };
 
@@ -133,17 +88,64 @@ struct hd_struct {
        struct rcu_work rcu_work;
 };
 
-#define GENHD_FL_REMOVABLE                     1
-/* 2 is unused */
-#define GENHD_FL_MEDIA_CHANGE_NOTIFY           4
-#define GENHD_FL_CD                            8
-#define GENHD_FL_UP                            16
-#define GENHD_FL_SUPPRESS_PARTITION_INFO       32
-#define GENHD_FL_EXT_DEVT                      64 /* allow extended devt */
-#define GENHD_FL_NATIVE_CAPACITY               128
-#define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE    256
-#define GENHD_FL_NO_PART_SCAN                  512
-#define GENHD_FL_HIDDEN                                1024
+/**
+ * DOC: genhd capability flags
+ *
+ * ``GENHD_FL_REMOVABLE`` (0x0001): indicates that the block device
+ * gives access to removable media.
+ * When set, the device remains present even when media is not
+ * inserted.
+ * Must not be set for devices which are removed entirely when the
+ * media is removed.
+ *
+ * ``GENHD_FL_CD`` (0x0008): the block device is a CD-ROM-style
+ * device.
+ * Affects responses to the ``CDROM_GET_CAPABILITY`` ioctl.
+ *
+ * ``GENHD_FL_UP`` (0x0010): indicates that the block device is "up",
+ * with a similar meaning to network interfaces.
+ *
+ * ``GENHD_FL_SUPPRESS_PARTITION_INFO`` (0x0020): don't include
+ * partition information in ``/proc/partitions`` or in the output of
+ * printk_all_partitions().
+ * Used for the null block device and some MMC devices.
+ *
+ * ``GENHD_FL_EXT_DEVT`` (0x0040): the driver supports extended
+ * dynamic ``dev_t``, i.e. it wants extended device numbers
+ * (``BLOCK_EXT_MAJOR``).
+ * This affects the maximum number of partitions.
+ *
+ * ``GENHD_FL_NATIVE_CAPACITY`` (0x0080): based on information in the
+ * partition table, the device's capacity has been extended to its
+ * native capacity; i.e. the device has hidden capacity used by one
+ * of the partitions (this is a flag used so that native capacity is
+ * only ever unlocked once).
+ *
+ * ``GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE`` (0x0100): event polling is
+ * blocked whenever a writer holds an exclusive lock.
+ *
+ * ``GENHD_FL_NO_PART_SCAN`` (0x0200): partition scanning is disabled.
+ * Used for loop devices in their default settings and some MMC
+ * devices.
+ *
+ * ``GENHD_FL_HIDDEN`` (0x0400): the block device is hidden; it
+ * doesn't produce events, doesn't appear in sysfs, and doesn't have
+ * an associated ``bdev``.
+ * Implies ``GENHD_FL_SUPPRESS_PARTITION_INFO`` and
+ * ``GENHD_FL_NO_PART_SCAN``.
+ * Used for multipath devices.
+ */
+#define GENHD_FL_REMOVABLE                     0x0001
+/* 2 is unused (used to be GENHD_FL_DRIVERFS) */
+/* 4 is unused (used to be GENHD_FL_MEDIA_CHANGE_NOTIFY) */
+#define GENHD_FL_CD                            0x0008
+#define GENHD_FL_UP                            0x0010
+#define GENHD_FL_SUPPRESS_PARTITION_INFO       0x0020
+#define GENHD_FL_EXT_DEVT                      0x0040
+#define GENHD_FL_NATIVE_CAPACITY               0x0080
+#define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE    0x0100
+#define GENHD_FL_NO_PART_SCAN                  0x0200
+#define GENHD_FL_HIDDEN                                0x0400
 
 enum {
        DISK_EVENT_MEDIA_CHANGE                 = 1 << 0, /* media changed */
@@ -189,7 +191,6 @@ struct gendisk {
                                          * disks that can't be partitioned. */
 
        char disk_name[DISK_NAME_LEN];  /* name of major driver */
-       char *(*devnode)(struct gendisk *gd, umode_t *mode);
 
        unsigned short events;          /* supported events */
        unsigned short event_flags;     /* flags related to event processing */
@@ -245,18 +246,6 @@ static inline bool disk_part_scan_enabled(struct gendisk *disk)
                !(disk->flags & GENHD_FL_NO_PART_SCAN);
 }
 
-static inline bool disk_has_partitions(struct gendisk *disk)
-{
-       bool ret = false;
-
-       rcu_read_lock();
-       if (rcu_dereference(disk->part_tbl)->len > 1)
-               ret = true;
-       rcu_read_unlock();
-
-       return ret;
-}
-
 static inline dev_t disk_devt(struct gendisk *disk)
 {
        return MKDEV(disk->major, disk->first_minor);
@@ -295,143 +284,7 @@ extern void disk_part_iter_init(struct disk_part_iter *piter,
                                 struct gendisk *disk, unsigned int flags);
 extern struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter);
 extern void disk_part_iter_exit(struct disk_part_iter *piter);
-
-extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk,
-                                            sector_t sector);
-
-/*
- * Macros to operate on percpu disk statistics:
- *
- * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
- * and should be called between disk_stat_lock() and
- * disk_stat_unlock().
- *
- * part_stat_read() can be called at any time.
- *
- * part_stat_{add|set_all}() and {init|free}_part_stats are for
- * internal use only.
- */
-#ifdef CONFIG_SMP
-#define part_stat_lock()       ({ rcu_read_lock(); get_cpu(); })
-#define part_stat_unlock()     do { put_cpu(); rcu_read_unlock(); } while (0)
-
-#define part_stat_get_cpu(part, field, cpu)                                    \
-       (per_cpu_ptr((part)->dkstats, (cpu))->field)
-
-#define part_stat_get(part, field)                                     \
-       part_stat_get_cpu(part, field, smp_processor_id())
-
-#define part_stat_read(part, field)                                    \
-({                                                                     \
-       typeof((part)->dkstats->field) res = 0;                         \
-       unsigned int _cpu;                                              \
-       for_each_possible_cpu(_cpu)                                     \
-               res += per_cpu_ptr((part)->dkstats, _cpu)->field;       \
-       res;                                                            \
-})
-
-static inline void part_stat_set_all(struct hd_struct *part, int value)
-{
-       int i;
-
-       for_each_possible_cpu(i)
-               memset(per_cpu_ptr(part->dkstats, i), value,
-                               sizeof(struct disk_stats));
-}
-
-static inline int init_part_stats(struct hd_struct *part)
-{
-       part->dkstats = alloc_percpu(struct disk_stats);
-       if (!part->dkstats)
-               return 0;
-       return 1;
-}
-
-static inline void free_part_stats(struct hd_struct *part)
-{
-       free_percpu(part->dkstats);
-}
-
-#else /* !CONFIG_SMP */
-#define part_stat_lock()       ({ rcu_read_lock(); 0; })
-#define part_stat_unlock()     rcu_read_unlock()
-
-#define part_stat_get(part, field)             ((part)->dkstats.field)
-#define part_stat_get_cpu(part, field, cpu)    part_stat_get(part, field)
-#define part_stat_read(part, field)            part_stat_get(part, field)
-
-static inline void part_stat_set_all(struct hd_struct *part, int value)
-{
-       memset(&part->dkstats, value, sizeof(struct disk_stats));
-}
-
-static inline int init_part_stats(struct hd_struct *part)
-{
-       return 1;
-}
-
-static inline void free_part_stats(struct hd_struct *part)
-{
-}
-
-#endif /* CONFIG_SMP */
-
-#define part_stat_read_msecs(part, which)                              \
-       div_u64(part_stat_read(part, nsecs[which]), NSEC_PER_MSEC)
-
-#define part_stat_read_accum(part, field)                              \
-       (part_stat_read(part, field[STAT_READ]) +                       \
-        part_stat_read(part, field[STAT_WRITE]) +                      \
-        part_stat_read(part, field[STAT_DISCARD]))
-
-#define __part_stat_add(part, field, addnd)                            \
-       (part_stat_get(part, field) += (addnd))
-
-#define part_stat_add(part, field, addnd)      do {                    \
-       __part_stat_add((part), field, addnd);                          \
-       if ((part)->partno)                                             \
-               __part_stat_add(&part_to_disk((part))->part0,           \
-                               field, addnd);                          \
-} while (0)
-
-#define part_stat_dec(gendiskp, field)                                 \
-       part_stat_add(gendiskp, field, -1)
-#define part_stat_inc(gendiskp, field)                                 \
-       part_stat_add(gendiskp, field, 1)
-#define part_stat_sub(gendiskp, field, subnd)                          \
-       part_stat_add(gendiskp, field, -subnd)
-
-#define part_stat_local_dec(gendiskp, field)                           \
-       local_dec(&(part_stat_get(gendiskp, field)))
-#define part_stat_local_inc(gendiskp, field)                           \
-       local_inc(&(part_stat_get(gendiskp, field)))
-#define part_stat_local_read(gendiskp, field)                          \
-       local_read(&(part_stat_get(gendiskp, field)))
-#define part_stat_local_read_cpu(gendiskp, field, cpu)                 \
-       local_read(&(part_stat_get_cpu(gendiskp, field, cpu)))
-
-unsigned int part_in_flight(struct request_queue *q, struct hd_struct *part);
-void part_in_flight_rw(struct request_queue *q, struct hd_struct *part,
-                      unsigned int inflight[2]);
-void part_dec_in_flight(struct request_queue *q, struct hd_struct *part,
-                       int rw);
-void part_inc_in_flight(struct request_queue *q, struct hd_struct *part,
-                       int rw);
-
-static inline struct partition_meta_info *alloc_part_info(struct gendisk *disk)
-{
-       if (disk)
-               return kzalloc_node(sizeof(struct partition_meta_info),
-                                   GFP_KERNEL, disk->node_id);
-       return kzalloc(sizeof(struct partition_meta_info), GFP_KERNEL);
-}
-
-static inline void free_part_info(struct hd_struct *part)
-{
-       kfree(part->info);
-}
-
-void update_io_ticks(struct hd_struct *part, unsigned long now);
+extern bool disk_has_partitions(struct gendisk *disk);
 
 /* block/genhd.c */
 extern void device_add_disk(struct device *parent, struct gendisk *disk,
@@ -461,6 +314,8 @@ static inline int get_disk_ro(struct gendisk *disk)
 extern void disk_block_events(struct gendisk *disk);
 extern void disk_unblock_events(struct gendisk *disk);
 extern void disk_flush_events(struct gendisk *disk, unsigned int mask);
+extern void set_capacity_revalidate_and_notify(struct gendisk *disk,
+                       sector_t size, bool revalidate);
 extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask);
 
 /* drivers/char/random.c */
@@ -480,170 +335,11 @@ static inline void set_capacity(struct gendisk *disk, sector_t size)
        disk->part0.nr_sects = size;
 }
 
-#ifdef CONFIG_SOLARIS_X86_PARTITION
-
-#define SOLARIS_X86_NUMSLICE   16
-#define SOLARIS_X86_VTOC_SANE  (0x600DDEEEUL)
-
-struct solaris_x86_slice {
-       __le16 s_tag;           /* ID tag of partition */
-       __le16 s_flag;          /* permission flags */
-       __le32 s_start;         /* start sector no of partition */
-       __le32 s_size;          /* # of blocks in partition */
-};
-
-struct solaris_x86_vtoc {
-       unsigned int v_bootinfo[3];     /* info needed by mboot (unsupported) */
-       __le32 v_sanity;                /* to verify vtoc sanity */
-       __le32 v_version;               /* layout version */
-       char    v_volume[8];            /* volume name */
-       __le16  v_sectorsz;             /* sector size in bytes */
-       __le16  v_nparts;               /* number of partitions */
-       unsigned int v_reserved[10];    /* free space */
-       struct solaris_x86_slice
-               v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */
-       unsigned int timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */
-       char    v_asciilabel[128];      /* for compatibility */
-};
-
-#endif /* CONFIG_SOLARIS_X86_PARTITION */
-
-#ifdef CONFIG_BSD_DISKLABEL
-/*
- * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
- * updated by Marc Espie <Marc.Espie@openbsd.org>
- */
-
-/* check against BSD src/sys/sys/disklabel.h for consistency */
-
-#define BSD_DISKMAGIC  (0x82564557UL)  /* The disk magic number */
-#define BSD_MAXPARTITIONS      16
-#define OPENBSD_MAXPARTITIONS  16
-#define BSD_FS_UNUSED          0       /* disklabel unused partition entry ID */
-struct bsd_disklabel {
-       __le32  d_magic;                /* the magic number */
-       __s16   d_type;                 /* drive type */
-       __s16   d_subtype;              /* controller/d_type specific */
-       char    d_typename[16];         /* type name, e.g. "eagle" */
-       char    d_packname[16];                 /* pack identifier */ 
-       __u32   d_secsize;              /* # of bytes per sector */
-       __u32   d_nsectors;             /* # of data sectors per track */
-       __u32   d_ntracks;              /* # of tracks per cylinder */
-       __u32   d_ncylinders;           /* # of data cylinders per unit */
-       __u32   d_secpercyl;            /* # of data sectors per cylinder */
-       __u32   d_secperunit;           /* # of data sectors per unit */
-       __u16   d_sparespertrack;       /* # of spare sectors per track */
-       __u16   d_sparespercyl;         /* # of spare sectors per cylinder */
-       __u32   d_acylinders;           /* # of alt. cylinders per unit */
-       __u16   d_rpm;                  /* rotational speed */
-       __u16   d_interleave;           /* hardware sector interleave */
-       __u16   d_trackskew;            /* sector 0 skew, per track */
-       __u16   d_cylskew;              /* sector 0 skew, per cylinder */
-       __u32   d_headswitch;           /* head switch time, usec */
-       __u32   d_trkseek;              /* track-to-track seek, usec */
-       __u32   d_flags;                /* generic flags */
-#define NDDATA 5
-       __u32   d_drivedata[NDDATA];    /* drive-type specific information */
-#define NSPARE 5
-       __u32   d_spare[NSPARE];        /* reserved for future use */
-       __le32  d_magic2;               /* the magic number (again) */
-       __le16  d_checksum;             /* xor of data incl. partitions */
-
-                       /* filesystem and partition information: */
-       __le16  d_npartitions;          /* number of partitions in following */
-       __le32  d_bbsize;               /* size of boot area at sn0, bytes */
-       __le32  d_sbsize;               /* max size of fs superblock, bytes */
-       struct  bsd_partition {         /* the partition table */
-               __le32  p_size;         /* number of sectors in partition */
-               __le32  p_offset;       /* starting sector */
-               __le32  p_fsize;        /* filesystem basic fragment size */
-               __u8    p_fstype;       /* filesystem type, see below */
-               __u8    p_frag;         /* filesystem fragments per block */
-               __le16  p_cpg;          /* filesystem cylinders per group */
-       } d_partitions[BSD_MAXPARTITIONS];      /* actually may be more */
-};
-
-#endif /* CONFIG_BSD_DISKLABEL */
-
-#ifdef CONFIG_UNIXWARE_DISKLABEL
-/*
- * Unixware slices support by Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
- * and Krzysztof G. Baranowski <kgb@knm.org.pl>
- */
-
-#define UNIXWARE_DISKMAGIC     (0xCA5E600DUL)  /* The disk magic number */
-#define UNIXWARE_DISKMAGIC2    (0x600DDEEEUL)  /* The slice table magic nr */
-#define UNIXWARE_NUMSLICE      16
-#define UNIXWARE_FS_UNUSED     0               /* Unused slice entry ID */
-
-struct unixware_slice {
-       __le16   s_label;       /* label */
-       __le16   s_flags;       /* permission flags */
-       __le32   start_sect;    /* starting sector */
-       __le32   nr_sects;      /* number of sectors in slice */
-};
-
-struct unixware_disklabel {
-       __le32   d_type;                /* drive type */
-       __le32   d_magic;                /* the magic number */
-       __le32   d_version;              /* version number */
-       char    d_serial[12];           /* serial number of the device */
-       __le32   d_ncylinders;           /* # of data cylinders per device */
-       __le32   d_ntracks;              /* # of tracks per cylinder */
-       __le32   d_nsectors;             /* # of data sectors per track */
-       __le32   d_secsize;              /* # of bytes per sector */
-       __le32   d_part_start;           /* # of first sector of this partition */
-       __le32   d_unknown1[12];         /* ? */
-       __le32  d_alt_tbl;              /* byte offset of alternate table */
-       __le32  d_alt_len;              /* byte length of alternate table */
-       __le32  d_phys_cyl;             /* # of physical cylinders per device */
-       __le32  d_phys_trk;             /* # of physical tracks per cylinder */
-       __le32  d_phys_sec;             /* # of physical sectors per track */
-       __le32  d_phys_bytes;           /* # of physical bytes per sector */
-       __le32  d_unknown2;             /* ? */
-       __le32   d_unknown3;             /* ? */
-       __le32  d_pad[8];               /* pad */
-
-       struct unixware_vtoc {
-               __le32  v_magic;                /* the magic number */
-               __le32  v_version;              /* version number */
-               char    v_name[8];              /* volume name */
-               __le16  v_nslices;              /* # of slices */
-               __le16  v_unknown1;             /* ? */
-               __le32  v_reserved[10];         /* reserved */
-               struct unixware_slice
-                       v_slice[UNIXWARE_NUMSLICE];     /* slice headers */
-       } vtoc;
-
-};  /* 408 */
-
-#endif /* CONFIG_UNIXWARE_DISKLABEL */
-
-#ifdef CONFIG_MINIX_SUBPARTITION
-#   define MINIX_NR_SUBPARTITIONS  4
-#endif /* CONFIG_MINIX_SUBPARTITION */
-
-#define ADDPART_FLAG_NONE      0
-#define ADDPART_FLAG_RAID      1
-#define ADDPART_FLAG_WHOLEDISK 2
-
-extern int blk_alloc_devt(struct hd_struct *part, dev_t *devt);
-extern void blk_free_devt(dev_t devt);
-extern void blk_invalidate_devt(dev_t devt);
 extern dev_t blk_lookup_devt(const char *name, int partno);
-extern char *disk_name (struct gendisk *hd, int partno, char *buf);
 
 int bdev_disk_changed(struct block_device *bdev, bool invalidate);
 int blk_add_partitions(struct gendisk *disk, struct block_device *bdev);
 int blk_drop_partitions(struct gendisk *disk, struct block_device *bdev);
-extern int disk_expand_part_tbl(struct gendisk *disk, int target);
-extern struct hd_struct * __must_check add_partition(struct gendisk *disk,
-                                                    int partno, sector_t start,
-                                                    sector_t len, int flags,
-                                                    struct partition_meta_info
-                                                      *info);
-extern void __delete_partition(struct percpu_ref *);
-extern void delete_partition(struct gendisk *, int);
 extern void printk_all_partitions(void);
 
 extern struct gendisk *__alloc_disk_node(int minors, int node_id);
@@ -657,20 +353,6 @@ extern void blk_register_region(dev_t devt, unsigned long range,
                        void *data);
 extern void blk_unregister_region(dev_t devt, unsigned long range);
 
-extern ssize_t part_size_show(struct device *dev,
-                             struct device_attribute *attr, char *buf);
-extern ssize_t part_stat_show(struct device *dev,
-                             struct device_attribute *attr, char *buf);
-extern ssize_t part_inflight_show(struct device *dev,
-                             struct device_attribute *attr, char *buf);
-#ifdef CONFIG_FAIL_MAKE_REQUEST
-extern ssize_t part_fail_show(struct device *dev,
-                             struct device_attribute *attr, char *buf);
-extern ssize_t part_fail_store(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t count);
-#endif /* CONFIG_FAIL_MAKE_REQUEST */
-
 #define alloc_disk_node(minors, node_id)                               \
 ({                                                                     \
        static struct lock_class_key __key;                             \
@@ -689,100 +371,6 @@ extern ssize_t part_fail_store(struct device *dev,
 
 #define alloc_disk(minors) alloc_disk_node(minors, NUMA_NO_NODE)
 
-static inline int hd_ref_init(struct hd_struct *part)
-{
-       if (percpu_ref_init(&part->ref, __delete_partition, 0,
-                               GFP_KERNEL))
-               return -ENOMEM;
-       return 0;
-}
-
-static inline void hd_struct_get(struct hd_struct *part)
-{
-       percpu_ref_get(&part->ref);
-}
-
-static inline int hd_struct_try_get(struct hd_struct *part)
-{
-       return percpu_ref_tryget_live(&part->ref);
-}
-
-static inline void hd_struct_put(struct hd_struct *part)
-{
-       percpu_ref_put(&part->ref);
-}
-
-static inline void hd_struct_kill(struct hd_struct *part)
-{
-       percpu_ref_kill(&part->ref);
-}
-
-static inline void hd_free_part(struct hd_struct *part)
-{
-       free_part_stats(part);
-       free_part_info(part);
-       percpu_ref_exit(&part->ref);
-}
-
-/*
- * Any access of part->nr_sects which is not protected by partition
- * bd_mutex or gendisk bdev bd_mutex, should be done using this
- * accessor function.
- *
- * Code written along the lines of i_size_read() and i_size_write().
- * CONFIG_PREEMPTION case optimizes the case of UP kernel with preemption
- * on.
- */
-static inline sector_t part_nr_sects_read(struct hd_struct *part)
-{
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
-       sector_t nr_sects;
-       unsigned seq;
-       do {
-               seq = read_seqcount_begin(&part->nr_sects_seq);
-               nr_sects = part->nr_sects;
-       } while (read_seqcount_retry(&part->nr_sects_seq, seq));
-       return nr_sects;
-#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
-       sector_t nr_sects;
-
-       preempt_disable();
-       nr_sects = part->nr_sects;
-       preempt_enable();
-       return nr_sects;
-#else
-       return part->nr_sects;
-#endif
-}
-
-/*
- * Should be called with mutex lock held (typically bd_mutex) of partition
- * to provide mutual exlusion among writers otherwise seqcount might be
- * left in wrong state leaving the readers spinning infinitely.
- */
-static inline void part_nr_sects_write(struct hd_struct *part, sector_t size)
-{
-#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
-       write_seqcount_begin(&part->nr_sects_seq);
-       part->nr_sects = size;
-       write_seqcount_end(&part->nr_sects_seq);
-#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
-       preempt_disable();
-       part->nr_sects = size;
-       preempt_enable();
-#else
-       part->nr_sects = size;
-#endif
-}
-
-#if defined(CONFIG_BLK_DEV_INTEGRITY)
-extern void blk_integrity_add(struct gendisk *);
-extern void blk_integrity_del(struct gendisk *);
-#else  /* CONFIG_BLK_DEV_INTEGRITY */
-static inline void blk_integrity_add(struct gendisk *disk) { }
-static inline void blk_integrity_del(struct gendisk *disk) { }
-#endif /* CONFIG_BLK_DEV_INTEGRITY */
-
 #else /* CONFIG_BLOCK */
 
 static inline void printk_all_partitions(void) { }
index da0af63..7c8b82f 100644 (file)
@@ -37,7 +37,7 @@ extern void rcu_nmi_exit(void);
        do {                                            \
                account_irq_enter_time(current);        \
                preempt_count_add(HARDIRQ_OFFSET);      \
-               trace_hardirq_enter();                  \
+               lockdep_hardirq_enter();                \
        } while (0)
 
 /*
@@ -50,7 +50,7 @@ extern void irq_enter(void);
  */
 #define __irq_exit()                                   \
        do {                                            \
-               trace_hardirq_exit();                   \
+               lockdep_hardirq_exit();                 \
                account_irq_exit_time(current);         \
                preempt_count_sub(HARDIRQ_OFFSET);      \
        } while (0)
@@ -74,12 +74,12 @@ extern void irq_exit(void);
                BUG_ON(in_nmi());                               \
                preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
                rcu_nmi_enter();                                \
-               trace_hardirq_enter();                          \
+               lockdep_hardirq_enter();                        \
        } while (0)
 
 #define nmi_exit()                                             \
        do {                                                    \
-               trace_hardirq_exit();                           \
+               lockdep_hardirq_exit();                         \
                rcu_nmi_exit();                                 \
                BUG_ON(!in_nmi());                              \
                preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
index cd41f20..875f711 100644 (file)
@@ -492,7 +492,7 @@ struct hid_report_enum {
 };
 
 #define HID_MIN_BUFFER_SIZE    64              /* make sure there is at least a packet size of space */
-#define HID_MAX_BUFFER_SIZE    4096            /* 4kb */
+#define HID_MAX_BUFFER_SIZE    8192            /* 8kb */
 #define HID_CONTROL_FIFO_SIZE  256             /* to init devices with >100 reports */
 #define HID_OUTPUT_FIFO_SIZE   64
 
index f834687..f6b9421 100644 (file)
@@ -506,7 +506,7 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info,
  * @smbus_xfer_atomic: same as @smbus_xfer. Yet, only using atomic context
  *   so e.g. PMICs can be accessed very late before shutdown. Optional.
  * @functionality: Return the flags that this algorithm/adapter pair supports
- *   from the I2C_FUNC_* flags.
+ *   from the ``I2C_FUNC_*`` flags.
  * @reg_slave: Register given client to I2C slave mode of this adapter
  * @unreg_slave: Unregister given client from I2C slave mode of this adapter
  *
@@ -515,7 +515,7 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info,
  * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
  * to name two of the most common.
  *
- * The return codes from the @master_xfer{_atomic} fields should indicate the
+ * The return codes from the ``master_xfer{_atomic}`` fields should indicate the
  * type of error code that occurred during the transfer, as documented in the
  * Kernel Documentation file Documentation/i2c/fault-codes.rst.
  */
index 93338fd..33d3796 100644 (file)
@@ -22,19 +22,23 @@ extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn);
 int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
                               unsigned int data_len);
 
+#if IS_ENABLED(CONFIG_NF_NAT)
+void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info);
+#else
+#define icmpv6_ndo_send icmpv6_send
+#endif
+
 #else
 
 static inline void icmpv6_send(struct sk_buff *skb,
                               u8 type, u8 code, __u32 info)
 {
-
 }
-#endif
 
-#if IS_ENABLED(CONFIG_NF_NAT)
-void icmpv6_ndo_send(struct sk_buff *skb_in, u8 type, u8 code, __u32 info);
-#else
-#define icmpv6_ndo_send icmpv6_send
+static inline void icmpv6_ndo_send(struct sk_buff *skb,
+                                  u8 type, u8 code, __u32 info)
+{
+}
 #endif
 
 extern int                             icmpv6_init(void);
index 7d3f2ce..73c66a3 100644 (file)
@@ -2102,14 +2102,14 @@ ieee80211_he_spr_size(const u8 *he_spr_ie)
 {
        struct ieee80211_he_spr *he_spr = (void *)he_spr_ie;
        u8 spr_len = sizeof(struct ieee80211_he_spr);
-       u32 he_spr_params;
+       u8 he_spr_params;
 
        /* Make sure the input is not NULL */
        if (!he_spr_ie)
                return 0;
 
        /* Calc required length */
-       he_spr_params = le32_to_cpu(he_spr->he_sr_control);
+       he_spr_params = he_spr->he_sr_control;
        if (he_spr_params & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
                spr_len++;
        if (he_spr_params & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT)
index 862ce00..eed58ed 100644 (file)
@@ -568,6 +568,8 @@ struct iio_dev {
 #if defined(CONFIG_DEBUG_FS)
        struct dentry                   *debugfs_dentry;
        unsigned                        cached_reg_addr;
+       char                            read_buf[20];
+       unsigned int                    read_buf_len;
 #endif
 };
 
index d2fcf45..dd82191 100644 (file)
@@ -41,9 +41,16 @@ struct adis_timeout {
  * @glob_cmd_reg: Register address of the GLOB_CMD register
  * @msc_ctrl_reg: Register address of the MSC_CTRL register
  * @diag_stat_reg: Register address of the DIAG_STAT register
+ * @prod_id_reg: Register address of the PROD_ID register
+ * @prod_id: Product ID code that should be expected when reading @prod_id_reg
+ * @self_test_mask: Bitmask of supported self-test operations
+ * @self_test_reg: Register address to request self test command
+ * @self_test_no_autoclear: True if device's self-test needs clear of ctrl reg
  * @status_error_msgs: Array of error messgaes
- * @status_error_mask:
+ * @status_error_mask: Bitmask of errors supported by the device
  * @timeouts: Chip specific delays
+ * @enable_irq: Hook for ADIS devices that have a special IRQ enable/disable
+ * @has_paging: True if ADIS device has paged registers
  */
 struct adis_data {
        unsigned int read_delay;
@@ -53,8 +60,12 @@ struct adis_data {
        unsigned int glob_cmd_reg;
        unsigned int msc_ctrl_reg;
        unsigned int diag_stat_reg;
+       unsigned int prod_id_reg;
+
+       unsigned int prod_id;
 
        unsigned int self_test_mask;
+       unsigned int self_test_reg;
        bool self_test_no_autoclear;
        const struct adis_timeout *timeouts;
 
@@ -66,6 +77,20 @@ struct adis_data {
        bool has_paging;
 };
 
+/**
+ * struct adis - ADIS device instance data
+ * @spi: Reference to SPI device which owns this ADIS IIO device
+ * @trig: IIO trigger object data
+ * @data: ADIS chip variant specific data
+ * @burst: ADIS burst transfer information
+ * @state_lock: Lock used by the device to protect state
+ * @msg: SPI message object
+ * @xfer: SPI transfer objects to be used for a @msg
+ * @current_page: Some ADIS devices have registers, this selects current page
+ * @buffer: Data buffer for information read from the device
+ * @tx: DMA safe TX buffer for SPI transfers
+ * @rx: DMA safe RX buffer for SPI transfers
+ */
 struct adis {
        struct spi_device       *spi;
        struct iio_trigger      *trig;
@@ -73,6 +98,17 @@ struct adis {
        const struct adis_data  *data;
        struct adis_burst       *burst;
 
+       /**
+        * The state_lock is meant to be used during operations that require
+        * a sequence of SPI R/W in order to protect the SPI transfer
+        * information (fields 'xfer', 'msg' & 'current_page') between
+        * potential concurrent accesses.
+        * This lock is used by all "adis_{functions}" that have to read/write
+        * registers. These functions also have unlocked variants
+        * (see "__adis_{functions}"), which don't hold this lock.
+        * This allows users of the ADIS library to group SPI R/W into
+        * the drivers, but they also must manage this lock themselves.
+        */
        struct mutex            state_lock;
        struct spi_message      msg;
        struct spi_transfer     *xfer;
@@ -297,6 +333,7 @@ static inline int adis_read_reg_32(struct adis *adis, unsigned int reg,
 
 int adis_enable_irq(struct adis *adis, bool enable);
 int __adis_check_status(struct adis *adis);
+int __adis_initial_startup(struct adis *adis);
 
 static inline int adis_check_status(struct adis *adis)
 {
@@ -309,7 +346,17 @@ static inline int adis_check_status(struct adis *adis)
        return ret;
 }
 
-int adis_initial_startup(struct adis *adis);
+/* locked version of __adis_initial_startup() */
+static inline int adis_initial_startup(struct adis *adis)
+{
+       int ret;
+
+       mutex_lock(&adis->state_lock);
+       ret = __adis_initial_startup(adis);
+       mutex_unlock(&adis->state_lock);
+
+       return ret;
+}
 
 int adis_single_conversion(struct iio_dev *indio_dev,
        const struct iio_chan_spec *chan, unsigned int error_mask,
index 39faaaf..c91cf2d 100644 (file)
@@ -2,15 +2,10 @@
 #ifndef _INET_DIAG_H_
 #define _INET_DIAG_H_ 1
 
+#include <net/netlink.h>
 #include <uapi/linux/inet_diag.h>
 
-struct net;
-struct sock;
 struct inet_hashinfo;
-struct nlattr;
-struct nlmsghdr;
-struct sk_buff;
-struct netlink_callback;
 
 struct inet_diag_handler {
        void            (*dump)(struct sk_buff *skb,
@@ -62,6 +57,17 @@ int inet_diag_bc_sk(const struct nlattr *_bc, struct sock *sk);
 
 void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk);
 
+static inline size_t inet_diag_msg_attrs_size(void)
+{
+       return    nla_total_size(1)  /* INET_DIAG_SHUTDOWN */
+               + nla_total_size(1)  /* INET_DIAG_TOS */
+#if IS_ENABLED(CONFIG_IPV6)
+               + nla_total_size(1)  /* INET_DIAG_TCLASS */
+               + nla_total_size(1)  /* INET_DIAG_SKV6ONLY */
+#endif
+               + nla_total_size(4)  /* INET_DIAG_MARK */
+               + nla_total_size(4); /* INET_DIAG_CLASS_ID */
+}
 int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
                             struct inet_diag_msg *r, int ext,
                             struct user_namespace *user_ns, bool net_admin);
index 4a16b39..980234a 100644 (file)
 
 #define dmar_readq(a) readq(a)
 #define dmar_writeq(a,v) writeq(v,a)
+#define dmar_readl(a) readl(a)
+#define dmar_writel(a, v) writel(v, a)
 
 #define DMAR_VER_MAJOR(v)              (((v) & 0xf0) >> 4)
 #define DMAR_VER_MINOR(v)              ((v) & 0x0f)
index c5fe60e..80f637c 100644 (file)
@@ -248,6 +248,8 @@ extern void enable_percpu_nmi(unsigned int irq, unsigned int type);
 extern int prepare_percpu_nmi(unsigned int irq);
 extern void teardown_percpu_nmi(unsigned int irq);
 
+extern int irq_inject_interrupt(unsigned int irq);
+
 /* The following three functions are for the core kernel use only. */
 extern void suspend_device_irqs(void);
 extern void resume_device_irqs(void);
index 837058b..b336622 100644 (file)
@@ -16,7 +16,7 @@
  * The io_mapping mechanism provides an abstraction for mapping
  * individual pages from an io device to the CPU in an efficient fashion.
  *
- * See Documentation/io-mapping.txt
+ * See Documentation/driver-api/io-mapping.rst
  */
 
 struct io_mapping {
diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h
deleted file mode 100644 (file)
index 38b286e..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org>
- */
-
-#ifndef _LINUX_IOC3_H
-#define _LINUX_IOC3_H
-
-#include <asm/sn/ioc3.h>
-
-#define IOC3_MAX_SUBMODULES    32
-
-#define IOC3_CLASS_NONE                0
-#define IOC3_CLASS_BASE_IP27   1
-#define IOC3_CLASS_BASE_IP30   2
-#define IOC3_CLASS_MENET_123   3
-#define IOC3_CLASS_MENET_4     4
-#define IOC3_CLASS_CADDUO      5
-#define IOC3_CLASS_SERIAL      6
-
-/* One of these per IOC3 */
-struct ioc3_driver_data {
-       struct list_head list;
-       int id;                         /* IOC3 sequence number */
-       /* PCI mapping */
-       unsigned long pma;              /* physical address */
-       struct ioc3 __iomem *vma;       /* pointer to registers */
-       struct pci_dev *pdev;           /* PCI device */
-       /* IRQ stuff */
-       int dual_irq;                   /* set if separate IRQs are used */
-       int irq_io, irq_eth;            /* IRQ numbers */
-       /* GPIO magic */
-       spinlock_t gpio_lock;
-       unsigned int gpdr_shadow;
-       /* NIC identifiers */
-       char nic_part[32];
-       char nic_serial[16];
-       char nic_mac[6];
-       /* submodule set */
-       int class;
-       void *data[IOC3_MAX_SUBMODULES];        /* for submodule use */
-       int active[IOC3_MAX_SUBMODULES];        /* set if probe succeeds */
-       /* is_ir_lock must be held while
-        * modifying sio_ie values, so
-        * we can be sure that sio_ie is
-        * not changing when we read it
-        * along with sio_ir.
-        */
-       spinlock_t ir_lock;     /* SIO_IE[SC] mod lock */
-};
-
-/* One per submodule */
-struct ioc3_submodule {
-       char *name;             /* descriptive submodule name */
-       struct module *owner;   /* owning kernel module */
-       int ethernet;           /* set for ethernet drivers */
-       int (*probe) (struct ioc3_submodule *, struct ioc3_driver_data *);
-       int (*remove) (struct ioc3_submodule *, struct ioc3_driver_data *);
-       int id;                 /* assigned by IOC3, index for the "data" array */
-       /* IRQ stuff */
-       unsigned int irq_mask;  /* IOC3 IRQ mask, leave clear for Ethernet */
-       int reset_mask;         /* non-zero if you want the ioc3.c module to reset interrupts */
-       int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
-       /* private submodule data */
-       void *data;             /* assigned by submodule */
-};
-
-/**********************************
- * Functions needed by submodules *
- **********************************/
-
-#define IOC3_W_IES             0
-#define IOC3_W_IEC             1
-
-/* registers a submodule for all existing and future IOC3 chips */
-extern int ioc3_register_submodule(struct ioc3_submodule *);
-/* unregisters a submodule */
-extern void ioc3_unregister_submodule(struct ioc3_submodule *);
-/* enables IRQs indicated by irq_mask for a specified IOC3 chip */
-extern void ioc3_enable(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
-/* ackowledges specified IRQs */
-extern void ioc3_ack(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
-/* disables IRQs indicated by irq_mask for a specified IOC3 chip */
-extern void ioc3_disable(struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
-/* atomically sets GPCR bits */
-extern void ioc3_gpcr_set(struct ioc3_driver_data *, unsigned int);
-/* general ireg writer */
-extern void ioc3_write_ireg(struct ioc3_driver_data *idd, uint32_t value, int reg);
-
-#endif
index dba15ca..1dcd919 100644 (file)
@@ -8,6 +8,7 @@
 
 enum {
        ICQ_EXITED              = 1 << 2,
+       ICQ_DESTROYED           = 1 << 3,
 };
 
 /*
index 3ed5a05..9315fbb 100644 (file)
@@ -211,6 +211,8 @@ struct irq_data {
  * IRQD_CAN_RESERVE            - Can use reservation mode
  * IRQD_MSI_NOMASK_QUIRK       - Non-maskable MSI quirk for affinity change
  *                               required
+ * IRQD_HANDLE_ENFORCE_IRQCTX  - Enforce that handle_irq_*() is only invoked
+ *                               from actual interrupt context.
  */
 enum {
        IRQD_TRIGGER_MASK               = 0xf,
@@ -234,6 +236,7 @@ enum {
        IRQD_DEFAULT_TRIGGER_SET        = (1 << 25),
        IRQD_CAN_RESERVE                = (1 << 26),
        IRQD_MSI_NOMASK_QUIRK           = (1 << 27),
+       IRQD_HANDLE_ENFORCE_IRQCTX      = (1 << 28),
 };
 
 #define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -303,6 +306,16 @@ static inline bool irqd_is_single_target(struct irq_data *d)
        return __irqd_to_state(d) & IRQD_SINGLE_TARGET;
 }
 
+static inline void irqd_set_handle_enforce_irqctx(struct irq_data *d)
+{
+       __irqd_to_state(d) |= IRQD_HANDLE_ENFORCE_IRQCTX;
+}
+
+static inline bool irqd_is_handle_enforce_irqctx(struct irq_data *d)
+{
+       return __irqd_to_state(d) & IRQD_HANDLE_ENFORCE_IRQCTX;
+}
+
 static inline bool irqd_is_wakeup_set(struct irq_data *d)
 {
        return __irqd_to_state(d) & IRQD_WAKEUP_STATE;
index 02da997..3b752e8 100644 (file)
@@ -18,6 +18,8 @@
 
 /* Doesn't want IPI, wait for tick: */
 #define IRQ_WORK_LAZY          BIT(2)
+/* Run hard IRQ context, even on RT */
+#define IRQ_WORK_HARD_IRQ      BIT(3)
 
 #define IRQ_WORK_CLAIMED       (IRQ_WORK_PENDING | IRQ_WORK_BUSY)
 
index b9850f5..fa8c045 100644 (file)
@@ -32,6 +32,8 @@ struct gic_kvm_info {
        struct resource vctrl;
        /* vlpi support */
        bool            has_v4;
+       /* rvpeid support */
+       bool            has_v4_1;
 };
 
 const struct gic_kvm_info *gic_get_kvm_info(void);
index 83439bf..765d9b7 100644 (file)
@@ -57,6 +57,7 @@
 #define GICD_SPENDSGIR                 0x0F20
 
 #define GICD_CTLR_RWP                  (1U << 31)
+#define GICD_CTLR_nASSGIreq            (1U << 8)
 #define GICD_CTLR_DS                   (1U << 6)
 #define GICD_CTLR_ARE_NS               (1U << 4)
 #define GICD_CTLR_ENABLE_G1A           (1U << 1)
@@ -90,6 +91,7 @@
 #define GICD_TYPER_ESPIS(typer)                                                \
        (((typer) & GICD_TYPER_ESPI) ? GICD_TYPER_SPIS((typer) >> 27) : 0)
 
+#define GICD_TYPER2_nASSGIcap          (1U << 8)
 #define GICD_TYPER2_VIL                        (1U << 7)
 #define GICD_TYPER2_VID                        GENMASK(4, 0)
 
 #define GICR_VPENDBASER_NonShareable                                   \
        GIC_BASER_SHAREABILITY(GICR_VPENDBASER, NonShareable)
 
+#define GICR_VPENDBASER_InnerShareable                                 \
+       GIC_BASER_SHAREABILITY(GICR_VPENDBASER, InnerShareable)
+
 #define GICR_VPENDBASER_nCnB   GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, nCnB)
 #define GICR_VPENDBASER_nC     GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, nC)
 #define GICR_VPENDBASER_RaWt   GIC_BASER_CACHEABILITY(GICR_VPENDBASER, INNER, RaWt)
 #define GICR_VPENDBASER_4_1_VGRP1EN    (1ULL << 58)
 #define GICR_VPENDBASER_4_1_VPEID      GENMASK_ULL(15, 0)
 
+#define GICR_VSGIR                     0x0080
+
+#define GICR_VSGIR_VPEID               GENMASK(15, 0)
+
+#define GICR_VSGIPENDR                 0x0088
+
+#define GICR_VSGIPENDR_BUSY            (1U << 31)
+#define GICR_VSGIPENDR_PENDING         GENMASK(15, 0)
+
 /*
  * ITS registers, offsets from ITS_base
  */
 
 #define GITS_TRANSLATER                        0x10040
 
+#define GITS_SGIR                      0x20020
+
+#define GITS_SGIR_VPEID                        GENMASK_ULL(47, 32)
+#define GITS_SGIR_VINTID               GENMASK_ULL(3, 0)
+
 #define GITS_CTLR_ENABLE               (1U << 0)
 #define GITS_CTLR_ImDe                 (1U << 1)
 #define        GITS_CTLR_ITS_NUMBER_SHIFT      4
 #define GITS_CMD_VMAPTI                        GITS_CMD_GICv4(GITS_CMD_MAPTI)
 #define GITS_CMD_VMOVI                 GITS_CMD_GICv4(GITS_CMD_MOVI)
 #define GITS_CMD_VSYNC                 GITS_CMD_GICv4(GITS_CMD_SYNC)
-/* VMOVP and INVDB are the odd ones, as they dont have a physical counterpart */
+/* VMOVP, VSGI and INVDB are the odd ones, as they dont have a physical counterpart */
 #define GITS_CMD_VMOVP                 GITS_CMD_GICv4(2)
+#define GITS_CMD_VSGI                  GITS_CMD_GICv4(3)
 #define GITS_CMD_INVDB                 GITS_CMD_GICv4(0xe)
 
 /*
 
 struct rdists {
        struct {
+               raw_spinlock_t  rd_lock;
                void __iomem    *rd_base;
                struct page     *pend_page;
                phys_addr_t     phys_base;
index d9c3496..6976b83 100644 (file)
@@ -49,11 +49,23 @@ struct its_vpe {
                };
                /* GICv4.1 implementations */
                struct {
+                       struct fwnode_handle    *fwnode;
+                       struct irq_domain       *sgi_domain;
+                       struct {
+                               u8      priority;
+                               bool    enabled;
+                               bool    group;
+                       }                       sgi_config[16];
                        atomic_t vmapp_count;
                };
        };
 
        /*
+        * Ensures mutual exclusion between affinity setting of the
+        * vPE and vLPI operations using vpe->col_idx.
+        */
+       raw_spinlock_t          vpe_lock;
+       /*
         * This collection ID is used to indirect the target
         * redistributor for this VPE. The ID itself isn't involved in
         * programming of the ITS.
@@ -93,6 +105,7 @@ enum its_vcpu_info_cmd_type {
        SCHEDULE_VPE,
        DESCHEDULE_VPE,
        INVALL_VPE,
+       PROP_UPDATE_VSGI,
 };
 
 struct its_cmd_info {
@@ -105,19 +118,27 @@ struct its_cmd_info {
                        bool            g0en;
                        bool            g1en;
                };
+               struct {
+                       u8              priority;
+                       bool            group;
+               };
        };
 };
 
 int its_alloc_vcpu_irqs(struct its_vm *vm);
 void its_free_vcpu_irqs(struct its_vm *vm);
-int its_schedule_vpe(struct its_vpe *vpe, bool on);
+int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en);
+int its_make_vpe_non_resident(struct its_vpe *vpe, bool db);
 int its_invall_vpe(struct its_vpe *vpe);
 int its_map_vlpi(int irq, struct its_vlpi_map *map);
 int its_get_vlpi(int irq, struct its_vlpi_map *map);
 int its_unmap_vlpi(int irq);
 int its_prop_update_vlpi(int irq, u8 config, bool inv);
+int its_prop_update_vsgi(int irq, u8 priority, bool group);
 
 struct irq_domain_ops;
-int its_init_v4(struct irq_domain *domain, const struct irq_domain_ops *ops);
+int its_init_v4(struct irq_domain *domain,
+               const struct irq_domain_ops *vpe_ops,
+               const struct irq_domain_ops *sgi_ops);
 
 #endif
index 21619c9..ceca42d 100644 (file)
 #include <linux/typecheck.h>
 #include <asm/irqflags.h>
 
-/* Currently trace_softirqs_on/off is used only by lockdep */
+/* Currently lockdep_softirqs_on/off is used only by lockdep */
 #ifdef CONFIG_PROVE_LOCKING
-  extern void trace_softirqs_on(unsigned long ip);
-  extern void trace_softirqs_off(unsigned long ip);
+  extern void lockdep_softirqs_on(unsigned long ip);
+  extern void lockdep_softirqs_off(unsigned long ip);
   extern void lockdep_hardirqs_on(unsigned long ip);
   extern void lockdep_hardirqs_off(unsigned long ip);
 #else
-  static inline void trace_softirqs_on(unsigned long ip) { }
-  static inline void trace_softirqs_off(unsigned long ip) { }
+  static inline void lockdep_softirqs_on(unsigned long ip) { }
+  static inline void lockdep_softirqs_off(unsigned long ip) { }
   static inline void lockdep_hardirqs_on(unsigned long ip) { }
   static inline void lockdep_hardirqs_off(unsigned long ip) { }
 #endif
 #ifdef CONFIG_TRACE_IRQFLAGS
   extern void trace_hardirqs_on(void);
   extern void trace_hardirqs_off(void);
-# define trace_hardirq_context(p)      ((p)->hardirq_context)
-# define trace_softirq_context(p)      ((p)->softirq_context)
-# define trace_hardirqs_enabled(p)     ((p)->hardirqs_enabled)
-# define trace_softirqs_enabled(p)     ((p)->softirqs_enabled)
-# define trace_hardirq_enter()                 \
+# define lockdep_hardirq_context(p)    ((p)->hardirq_context)
+# define lockdep_softirq_context(p)    ((p)->softirq_context)
+# define lockdep_hardirqs_enabled(p)   ((p)->hardirqs_enabled)
+# define lockdep_softirqs_enabled(p)   ((p)->softirqs_enabled)
+# define lockdep_hardirq_enter()               \
 do {                                           \
-       current->hardirq_context++;             \
+       if (!current->hardirq_context++)        \
+               current->hardirq_threaded = 0;  \
 } while (0)
-# define trace_hardirq_exit()                  \
+# define lockdep_hardirq_threaded()            \
+do {                                           \
+       current->hardirq_threaded = 1;          \
+} while (0)
+# define lockdep_hardirq_exit()                        \
 do {                                           \
        current->hardirq_context--;             \
 } while (0)
@@ -51,17 +56,58 @@ do {                                                \
 do {                                           \
        current->softirq_context--;             \
 } while (0)
+
+# define lockdep_hrtimer_enter(__hrtimer)              \
+         do {                                          \
+                 if (!__hrtimer->is_hard)              \
+                       current->irq_config = 1;        \
+         } while (0)
+
+# define lockdep_hrtimer_exit(__hrtimer)               \
+         do {                                          \
+                 if (!__hrtimer->is_hard)              \
+                       current->irq_config = 0;        \
+         } while (0)
+
+# define lockdep_posixtimer_enter()                            \
+         do {                                                  \
+                 current->irq_config = 1;                      \
+         } while (0)
+
+# define lockdep_posixtimer_exit()                             \
+         do {                                                  \
+                 current->irq_config = 0;                      \
+         } while (0)
+
+# define lockdep_irq_work_enter(__work)                                        \
+         do {                                                          \
+                 if (!(atomic_read(&__work->flags) & IRQ_WORK_HARD_IRQ))\
+                       current->irq_config = 1;                        \
+         } while (0)
+# define lockdep_irq_work_exit(__work)                                 \
+         do {                                                          \
+                 if (!(atomic_read(&__work->flags) & IRQ_WORK_HARD_IRQ))\
+                       current->irq_config = 0;                        \
+         } while (0)
+
 #else
 # define trace_hardirqs_on()           do { } while (0)
 # define trace_hardirqs_off()          do { } while (0)
-# define trace_hardirq_context(p)      0
-# define trace_softirq_context(p)      0
-# define trace_hardirqs_enabled(p)     0
-# define trace_softirqs_enabled(p)     0
-# define trace_hardirq_enter()         do { } while (0)
-# define trace_hardirq_exit()          do { } while (0)
+# define lockdep_hardirq_context(p)    0
+# define lockdep_softirq_context(p)    0
+# define lockdep_hardirqs_enabled(p)   0
+# define lockdep_softirqs_enabled(p)   0
+# define lockdep_hardirq_enter()       do { } while (0)
+# define lockdep_hardirq_threaded()    do { } while (0)
+# define lockdep_hardirq_exit()                do { } while (0)
 # define lockdep_softirq_enter()       do { } while (0)
 # define lockdep_softirq_exit()                do { } while (0)
+# define lockdep_hrtimer_enter(__hrtimer)              do { } while (0)
+# define lockdep_hrtimer_exit(__hrtimer)               do { } while (0)
+# define lockdep_posixtimer_enter()            do { } while (0)
+# define lockdep_posixtimer_exit()             do { } while (0)
+# define lockdep_irq_work_enter(__work)                do { } while (0)
+# define lockdep_irq_work_exit(__work)         do { } while (0)
 #endif
 
 #if defined(CONFIG_IRQSOFF_TRACER) || \
index e3279ef..fed6ba9 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/types.h>
 #include <linux/time.h>
 #include <linux/timex.h>
+#include <vdso/jiffies.h>
 #include <asm/param.h>                 /* for HZ */
 #include <generated/timeconst.h>
 
@@ -59,9 +60,6 @@
 
 extern int register_refined_jiffies(long clock_tick_rate);
 
-/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */
-#define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ)
-
 /* TICK_USEC is the time between ticks in usec assuming SHIFTED_HZ */
 #define TICK_USEC ((USEC_PER_SEC + HZ/2) / HZ)
 
index 0d9db2a..9b7a8d7 100644 (file)
@@ -257,6 +257,13 @@ extern void __cant_sleep(const char *file, int line, int preempt_offset);
 
 #define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0)
 
+#ifndef CONFIG_PREEMPT_RT
+# define cant_migrate()                cant_sleep()
+#else
+  /* Placeholder for now */
+# define cant_migrate()                do { } while (0)
+#endif
+
 /**
  * abs - return absolute value of an argument
  * @x: the value.  If it is unsigned type, it is converted to signed type first.
index d1fb051..42d2e6a 100644 (file)
@@ -216,14 +216,7 @@ static inline __must_check bool ktime_to_timespec64_cond(const ktime_t kt,
        }
 }
 
-/*
- * The resolution of the clocks. The resolution value is returned in
- * the clock_getres() system call to give application programmers an
- * idea of the (in)accuracy of timers. Timer values are rounded up to
- * this resolution values.
- */
-#define LOW_RES_NSEC           TICK_NSEC
-#define KTIME_LOW_RES          (LOW_RES_NSEC)
+#include <vdso/ktime.h>
 
 static inline ktime_t ns_to_ktime(u64 ns)
 {
index e89eb67..bcb9b2a 100644 (file)
@@ -889,6 +889,8 @@ 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);
 bool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu);
+int kvm_arch_post_init_vm(struct kvm *kvm);
+void kvm_arch_pre_destroy_vm(struct kvm *kvm);
 
 #ifndef __KVM_HAVE_ARCH_VM_ALLOC
 /*
@@ -1342,7 +1344,7 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
 #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
 
 struct kvm_vcpu *kvm_get_running_vcpu(void);
-struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
+struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void);
 
 #ifdef CONFIG_HAVE_KVM_IRQ_BYPASS
 bool kvm_arch_has_irq_bypass(void);
index 2ca9b70..cffa471 100644 (file)
@@ -57,8 +57,6 @@
 #define VPRINTK(fmt, args...)
 #endif /* ATA_DEBUG */
 
-#define BPRINTK(fmt, args...) if (ap->flags & ATA_FLAG_DEBUGMSG) printk(KERN_ERR "%s: " fmt, __func__, ## args)
-
 #define ata_print_version_once(dev, version)                   \
 ({                                                             \
        static bool __print_once;                               \
@@ -176,6 +174,7 @@ enum {
        ATA_DEV_NONE            = 11,   /* no device */
 
        /* struct ata_link flags */
+       /* NOTE: struct ata_force_param currently stores lflags in u16 */
        ATA_LFLAG_NO_HRST       = (1 << 1), /* avoid hardreset */
        ATA_LFLAG_NO_SRST       = (1 << 2), /* avoid softreset */
        ATA_LFLAG_ASSUME_ATA    = (1 << 3), /* assume ATA class */
@@ -531,12 +530,14 @@ typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes,
                              unsigned long deadline);
 typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes);
 
-extern struct device_attribute dev_attr_link_power_management_policy;
 extern struct device_attribute dev_attr_unload_heads;
+#ifdef CONFIG_SATA_HOST
+extern struct device_attribute dev_attr_link_power_management_policy;
 extern struct device_attribute dev_attr_ncq_prio_enable;
 extern struct device_attribute dev_attr_em_message_type;
 extern struct device_attribute dev_attr_em_message;
 extern struct device_attribute dev_attr_sw_activity;
+#endif
 
 enum sw_activity {
        OFF,
@@ -1020,10 +1021,6 @@ struct ata_timing {
 /*
  * Core layer - drivers/ata/libata-core.c
  */
-extern const unsigned long sata_deb_timing_normal[];
-extern const unsigned long sata_deb_timing_hotplug[];
-extern const unsigned long sata_deb_timing_long[];
-
 extern struct ata_port_operations ata_dummy_port_ops;
 extern const struct ata_port_info ata_dummy_port_info;
 
@@ -1061,33 +1058,14 @@ static inline int is_multi_taskfile(struct ata_taskfile *tf)
               (tf->command == ATA_CMD_WRITE_MULTI_FUA_EXT);
 }
 
-static inline const unsigned long *
-sata_ehc_deb_timing(struct ata_eh_context *ehc)
-{
-       if (ehc->i.flags & ATA_EHI_HOTPLUGGED)
-               return sata_deb_timing_hotplug;
-       else
-               return sata_deb_timing_normal;
-}
-
 static inline int ata_port_is_dummy(struct ata_port *ap)
 {
        return ap->ops == &ata_dummy_port_ops;
 }
 
-extern int sata_set_spd(struct ata_link *link);
 extern int ata_std_prereset(struct ata_link *link, unsigned long deadline);
 extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
                                int (*check_ready)(struct ata_link *link));
-extern int sata_link_debounce(struct ata_link *link,
-                       const unsigned long *params, unsigned long deadline);
-extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
-                           unsigned long deadline);
-extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
-                            bool spm_wakeup);
-extern int sata_link_hardreset(struct ata_link *link,
-                       const unsigned long *timing, unsigned long deadline,
-                       bool *online, int (*check_ready)(struct ata_link *));
 extern int sata_std_hardreset(struct ata_link *link, unsigned int *class,
                              unsigned long deadline);
 extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
@@ -1095,7 +1073,6 @@ extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
 extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
 extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
                        const struct ata_port_info * const * ppi, int n_ports);
-extern int ata_slave_link_init(struct ata_port *ap);
 extern void ata_host_get(struct ata_host *host);
 extern void ata_host_put(struct ata_host *host);
 extern int ata_host_start(struct ata_host *host);
@@ -1117,22 +1094,6 @@ extern int ata_scsi_ioctl(struct scsi_device *dev, unsigned int cmd,
 extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 extern int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *dev,
                            unsigned int cmd, void __user *arg);
-extern void ata_sas_port_destroy(struct ata_port *);
-extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
-                                          struct ata_port_info *, struct Scsi_Host *);
-extern void ata_sas_async_probe(struct ata_port *ap);
-extern int ata_sas_sync_probe(struct ata_port *ap);
-extern int ata_sas_port_init(struct ata_port *);
-extern int ata_sas_port_start(struct ata_port *ap);
-extern int ata_sas_tport_add(struct device *parent, struct ata_port *ap);
-extern void ata_sas_tport_delete(struct ata_port *ap);
-extern void ata_sas_port_stop(struct ata_port *ap);
-extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *);
-extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap);
-extern int sata_scr_valid(struct ata_link *link);
-extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
-extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
-extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
 extern bool ata_link_online(struct ata_link *link);
 extern bool ata_link_offline(struct ata_link *link);
 #ifdef CONFIG_PM
@@ -1153,9 +1114,6 @@ extern void ata_msleep(struct ata_port *ap, unsigned int msecs);
 extern u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask,
                        u32 val, unsigned long interval, unsigned long timeout);
 extern int atapi_cmd_type(u8 opcode);
-extern void ata_tf_to_fis(const struct ata_taskfile *tf,
-                         u8 pmp, int is_cmd, u8 *fis);
-extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
 extern unsigned long ata_pack_xfermask(unsigned long pio_mask,
                        unsigned long mwdma_mask, unsigned long udma_mask);
 extern void ata_unpack_xfermask(unsigned long xfer_mask,
@@ -1179,7 +1137,6 @@ extern void ata_id_c_string(const u16 *id, unsigned char *s,
 extern unsigned int ata_do_dev_read_id(struct ata_device *dev,
                                        struct ata_taskfile *tf, u16 *id);
 extern void ata_qc_complete(struct ata_queued_cmd *qc);
-extern int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active);
 extern u64 ata_qc_get_active(struct ata_port *ap);
 extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd);
 extern int ata_std_bios_param(struct scsi_device *sdev,
@@ -1196,7 +1153,96 @@ extern struct ata_device *ata_dev_pair(struct ata_device *adev);
 extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
 extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q);
+
+/*
+ * SATA specific code - drivers/ata/libata-sata.c
+ */
+#ifdef CONFIG_SATA_HOST
+extern const unsigned long sata_deb_timing_normal[];
+extern const unsigned long sata_deb_timing_hotplug[];
+extern const unsigned long sata_deb_timing_long[];
+
+static inline const unsigned long *
+sata_ehc_deb_timing(struct ata_eh_context *ehc)
+{
+       if (ehc->i.flags & ATA_EHI_HOTPLUGGED)
+               return sata_deb_timing_hotplug;
+       else
+               return sata_deb_timing_normal;
+}
+
+extern int sata_scr_valid(struct ata_link *link);
+extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
+extern int sata_set_spd(struct ata_link *link);
+extern int sata_link_hardreset(struct ata_link *link,
+                       const unsigned long *timing, unsigned long deadline,
+                       bool *online, int (*check_ready)(struct ata_link *));
+extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
+                           unsigned long deadline);
+extern void ata_eh_analyze_ncq_error(struct ata_link *link);
+#else
+static inline const unsigned long *
+sata_ehc_deb_timing(struct ata_eh_context *ehc)
+{
+       return NULL;
+}
+static inline int sata_scr_valid(struct ata_link *link) { return 0; }
+static inline int sata_scr_read(struct ata_link *link, int reg, u32 *val)
+{
+       return -EOPNOTSUPP;
+}
+static inline int sata_scr_write(struct ata_link *link, int reg, u32 val)
+{
+       return -EOPNOTSUPP;
+}
+static inline int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
+{
+       return -EOPNOTSUPP;
+}
+static inline int sata_set_spd(struct ata_link *link) { return -EOPNOTSUPP; }
+static inline int sata_link_hardreset(struct ata_link *link,
+                                     const unsigned long *timing,
+                                     unsigned long deadline,
+                                     bool *online,
+                                     int (*check_ready)(struct ata_link *))
+{
+       if (online)
+               *online = false;
+       return -EOPNOTSUPP;
+}
+static inline int sata_link_resume(struct ata_link *link,
+                                  const unsigned long *params,
+                                  unsigned long deadline)
+{
+       return -EOPNOTSUPP;
+}
+static inline void ata_eh_analyze_ncq_error(struct ata_link *link) { }
+#endif
+extern int sata_link_debounce(struct ata_link *link,
+                       const unsigned long *params, unsigned long deadline);
+extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                            bool spm_wakeup);
+extern int ata_slave_link_init(struct ata_port *ap);
+extern void ata_sas_port_destroy(struct ata_port *);
+extern struct ata_port *ata_sas_port_alloc(struct ata_host *,
+                                          struct ata_port_info *, struct Scsi_Host *);
+extern void ata_sas_async_probe(struct ata_port *ap);
+extern int ata_sas_sync_probe(struct ata_port *ap);
+extern int ata_sas_port_init(struct ata_port *);
+extern int ata_sas_port_start(struct ata_port *ap);
+extern int ata_sas_tport_add(struct device *parent, struct ata_port *ap);
+extern void ata_sas_tport_delete(struct ata_port *ap);
+extern void ata_sas_port_stop(struct ata_port *ap);
+extern int ata_sas_slave_configure(struct scsi_device *, struct ata_port *);
+extern int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap);
+extern void ata_tf_to_fis(const struct ata_taskfile *tf,
+                         u8 pmp, int is_cmd, u8 *fis);
+extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
+extern int ata_qc_complete_multiple(struct ata_port *ap, u64 qc_active);
 extern bool sata_lpm_ignore_phy_events(struct ata_link *link);
+extern int sata_async_notification(struct ata_port *ap);
 
 extern int ata_cable_40wire(struct ata_port *ap);
 extern int ata_cable_80wire(struct ata_port *ap);
@@ -1206,12 +1252,6 @@ extern int ata_cable_unknown(struct ata_port *ap);
 
 /* Timing helpers */
 extern unsigned int ata_pio_need_iordy(const struct ata_device *);
-extern const struct ata_timing *ata_timing_find_mode(u8 xfer_mode);
-extern int ata_timing_compute(struct ata_device *, unsigned short,
-                             struct ata_timing *, int, int);
-extern void ata_timing_merge(const struct ata_timing *,
-                            const struct ata_timing *, struct ata_timing *,
-                            unsigned int);
 extern u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle);
 
 /* PCI */
@@ -1295,14 +1335,12 @@ extern void ata_port_wait_eh(struct ata_port *ap);
 extern int ata_link_abort(struct ata_link *link);
 extern int ata_port_abort(struct ata_port *ap);
 extern int ata_port_freeze(struct ata_port *ap);
-extern int sata_async_notification(struct ata_port *ap);
 
 extern void ata_eh_freeze_port(struct ata_port *ap);
 extern void ata_eh_thaw_port(struct ata_port *ap);
 
 extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
 extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
-extern void ata_eh_analyze_ncq_error(struct ata_link *link);
 
 extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
                      ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
@@ -1343,7 +1381,7 @@ extern struct device_attribute *ata_common_sdev_attrs[];
  * edge driver's module reference, otherwise the driver can be unloaded
  * even if the scsi_device is being accessed.
  */
-#define ATA_BASE_SHT(drv_name)                                 \
+#define __ATA_BASE_SHT(drv_name)                               \
        .module                 = THIS_MODULE,                  \
        .name                   = drv_name,                     \
        .ioctl                  = ata_scsi_ioctl,               \
@@ -1357,12 +1395,20 @@ extern struct device_attribute *ata_common_sdev_attrs[];
        .slave_configure        = ata_scsi_slave_config,        \
        .slave_destroy          = ata_scsi_slave_destroy,       \
        .bios_param             = ata_std_bios_param,           \
-       .unlock_native_capacity = ata_scsi_unlock_native_capacity, \
+       .unlock_native_capacity = ata_scsi_unlock_native_capacity
+
+#define ATA_BASE_SHT(drv_name)                                 \
+       __ATA_BASE_SHT(drv_name),                               \
        .sdev_attrs             = ata_common_sdev_attrs
 
+#ifdef CONFIG_SATA_HOST
+extern struct device_attribute *ata_ncq_sdev_attrs[];
+
 #define ATA_NCQ_SHT(drv_name)                                  \
-       ATA_BASE_SHT(drv_name),                                 \
+       __ATA_BASE_SHT(drv_name),                               \
+       .sdev_attrs             = ata_ncq_sdev_attrs,           \
        .change_queue_depth     = ata_scsi_change_queue_depth
+#endif
 
 /*
  * PMP helpers
@@ -1635,6 +1681,8 @@ extern struct ata_device *ata_dev_next(struct ata_device *dev,
  */
 static inline int ata_ncq_enabled(struct ata_device *dev)
 {
+       if (!IS_ENABLED(CONFIG_SATA_HOST))
+               return 0;
        return (dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
                              ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ;
 }
@@ -1804,6 +1852,16 @@ static inline int ata_dma_enabled(struct ata_device *adev)
 }
 
 /**************************************************************************
+ * PATA timings - drivers/ata/libata-pata-timings.c
+ */
+extern const struct ata_timing *ata_timing_find_mode(u8 xfer_mode);
+extern int ata_timing_compute(struct ata_device *, unsigned short,
+                             struct ata_timing *, int, int);
+extern void ata_timing_merge(const struct ata_timing *,
+                            const struct ata_timing *, struct ata_timing *,
+                            unsigned int);
+
+/**************************************************************************
  * PMP - drivers/ata/libata-pmp.c
  */
 #ifdef CONFIG_SATA_PMP
index 76afcd2..7fc497e 100644 (file)
@@ -4,19 +4,8 @@
 
 #include <uapi/linux/limits.h>
 #include <linux/types.h>
+#include <vdso/limits.h>
 
-#define USHRT_MAX      ((unsigned short)~0U)
-#define SHRT_MAX       ((short)(USHRT_MAX >> 1))
-#define SHRT_MIN       ((short)(-SHRT_MAX - 1))
-#define INT_MAX                ((int)(~0U >> 1))
-#define INT_MIN                (-INT_MAX - 1)
-#define UINT_MAX       (~0U)
-#define LONG_MAX       ((long)(~0UL >> 1))
-#define LONG_MIN       (-LONG_MAX - 1)
-#define ULONG_MAX      (~0UL)
-#define LLONG_MAX      ((long long)(~0ULL >> 1))
-#define LLONG_MIN      (-LLONG_MAX - 1)
-#define ULLONG_MAX     (~0ULL)
 #define SIZE_MAX       (~(size_t)0)
 #define PHYS_ADDR_MAX  (~(phys_addr_t)0)
 
index 664f52c..206774a 100644 (file)
@@ -21,6 +21,22 @@ extern int lock_stat;
 
 #include <linux/types.h>
 
+enum lockdep_wait_type {
+       LD_WAIT_INV = 0,        /* not checked, catch all */
+
+       LD_WAIT_FREE,           /* wait free, rcu etc.. */
+       LD_WAIT_SPIN,           /* spin loops, raw_spinlock_t etc.. */
+
+#ifdef CONFIG_PROVE_RAW_LOCK_NESTING
+       LD_WAIT_CONFIG,         /* CONFIG_PREEMPT_LOCK, spinlock_t etc.. */
+#else
+       LD_WAIT_CONFIG = LD_WAIT_SPIN,
+#endif
+       LD_WAIT_SLEEP,          /* sleeping locks, mutex_t etc.. */
+
+       LD_WAIT_MAX,            /* must be last */
+};
+
 #ifdef CONFIG_LOCKDEP
 
 #include <linux/linkage.h>
@@ -111,6 +127,9 @@ struct lock_class {
        int                             name_version;
        const char                      *name;
 
+       short                           wait_type_inner;
+       short                           wait_type_outer;
+
 #ifdef CONFIG_LOCK_STAT
        unsigned long                   contention_point[LOCKSTAT_POINTS];
        unsigned long                   contending_point[LOCKSTAT_POINTS];
@@ -158,6 +177,8 @@ struct lockdep_map {
        struct lock_class_key           *key;
        struct lock_class               *class_cache[NR_LOCKDEP_CACHING_CLASSES];
        const char                      *name;
+       short                           wait_type_outer; /* can be taken in this context */
+       short                           wait_type_inner; /* presents this context */
 #ifdef CONFIG_LOCK_STAT
        int                             cpu;
        unsigned long                   ip;
@@ -299,8 +320,21 @@ extern void lockdep_unregister_key(struct lock_class_key *key);
  * to lockdep:
  */
 
-extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
-                            struct lock_class_key *key, int subclass);
+extern void lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
+       struct lock_class_key *key, int subclass, short inner, short outer);
+
+static inline void
+lockdep_init_map_wait(struct lockdep_map *lock, const char *name,
+                     struct lock_class_key *key, int subclass, short inner)
+{
+       lockdep_init_map_waits(lock, name, key, subclass, inner, LD_WAIT_INV);
+}
+
+static inline void lockdep_init_map(struct lockdep_map *lock, const char *name,
+                            struct lock_class_key *key, int subclass)
+{
+       lockdep_init_map_wait(lock, name, key, subclass, LD_WAIT_INV);
+}
 
 /*
  * Reinitialize a lock key - for cases where there is special locking or
@@ -308,18 +342,29 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
  * of dependencies wrong: they are either too broad (they need a class-split)
  * or they are too narrow (they suffer from a false class-split):
  */
-#define lockdep_set_class(lock, key) \
-               lockdep_init_map(&(lock)->dep_map, #key, key, 0)
-#define lockdep_set_class_and_name(lock, key, name) \
-               lockdep_init_map(&(lock)->dep_map, name, key, 0)
-#define lockdep_set_class_and_subclass(lock, key, sub) \
-               lockdep_init_map(&(lock)->dep_map, #key, key, sub)
-#define lockdep_set_subclass(lock, sub)        \
-               lockdep_init_map(&(lock)->dep_map, #lock, \
-                                (lock)->dep_map.key, sub)
+#define lockdep_set_class(lock, key)                           \
+       lockdep_init_map_waits(&(lock)->dep_map, #key, key, 0,  \
+                              (lock)->dep_map.wait_type_inner, \
+                              (lock)->dep_map.wait_type_outer)
+
+#define lockdep_set_class_and_name(lock, key, name)            \
+       lockdep_init_map_waits(&(lock)->dep_map, name, key, 0,  \
+                              (lock)->dep_map.wait_type_inner, \
+                              (lock)->dep_map.wait_type_outer)
+
+#define lockdep_set_class_and_subclass(lock, key, sub)         \
+       lockdep_init_map_waits(&(lock)->dep_map, #key, key, sub,\
+                              (lock)->dep_map.wait_type_inner, \
+                              (lock)->dep_map.wait_type_outer)
+
+#define lockdep_set_subclass(lock, sub)                                        \
+       lockdep_init_map_waits(&(lock)->dep_map, #lock, (lock)->dep_map.key, sub,\
+                              (lock)->dep_map.wait_type_inner,         \
+                              (lock)->dep_map.wait_type_outer)
 
 #define lockdep_set_novalidate_class(lock) \
        lockdep_set_class_and_name(lock, &__lockdep_no_validate__, #lock)
+
 /*
  * Compare locking classes
  */
@@ -432,6 +477,10 @@ static inline void lockdep_set_selftest_task(struct task_struct *task)
 # define lock_set_class(l, n, k, s, i)         do { } while (0)
 # define lock_set_subclass(l, s, i)            do { } while (0)
 # define lockdep_init()                                do { } while (0)
+# define lockdep_init_map_waits(lock, name, key, sub, inner, outer) \
+               do { (void)(name); (void)(key); } while (0)
+# define lockdep_init_map_wait(lock, name, key, sub, inner) \
+               do { (void)(name); (void)(key); } while (0)
 # define lockdep_init_map(lock, name, key, sub) \
                do { (void)(name); (void)(key); } while (0)
 # define lockdep_set_class(lock, key)          do { (void)(key); } while (0)
@@ -662,6 +711,21 @@ do {                                                                       \
 # define lockdep_assert_in_irq() do { } while (0)
 #endif
 
+#ifdef CONFIG_PROVE_RAW_LOCK_NESTING
+
+# define lockdep_assert_RT_in_threaded_ctx() do {                      \
+               WARN_ONCE(debug_locks && !current->lockdep_recursion && \
+                         current->hardirq_context &&                   \
+                         !(current->hardirq_threaded || current->irq_config),  \
+                         "Not in threaded context on PREEMPT_RT as expected\n");       \
+} while (0)
+
+#else
+
+# define lockdep_assert_RT_in_threaded_ctx() do { } while (0)
+
+#endif
+
 #ifdef CONFIG_LOCKDEP
 void lockdep_rcu_suspicious(const char *file, const int line, const char *s);
 #else
index 65bef21..11a2674 100644 (file)
@@ -3,6 +3,7 @@
 #define _LINUX_MATH64_H
 
 #include <linux/types.h>
+#include <vdso/math64.h>
 #include <asm/div64.h>
 
 #if BITS_PER_LONG == 64
@@ -142,25 +143,6 @@ static inline s64 div_s64(s64 dividend, s32 divisor)
 
 u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder);
 
-static __always_inline u32
-__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
-{
-       u32 ret = 0;
-
-       while (dividend >= divisor) {
-               /* The following asm() prevents the compiler from
-                  optimising this loop into a modulo operation.  */
-               asm("" : "+rm"(dividend));
-
-               dividend -= divisor;
-               ret++;
-       }
-
-       *remainder = dividend;
-
-       return ret;
-}
-
 #ifndef mul_u32_u32
 /*
  * Many a GCC version messes this up and generates a 64x64 mult :-(
index a7a0a1a..e9ba013 100644 (file)
@@ -695,6 +695,7 @@ static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,
 void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,
                        int val);
 void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val);
+void mod_memcg_obj_state(void *p, int idx, int val);
 
 static inline void mod_lruvec_state(struct lruvec *lruvec,
                                    enum node_stat_item idx, int val)
@@ -1123,6 +1124,10 @@ static inline void __mod_lruvec_slab_state(void *p, enum node_stat_item idx,
        __mod_node_page_state(page_pgdat(page), idx, val);
 }
 
+static inline void mod_memcg_obj_state(void *p, int idx, int val)
+{
+}
+
 static inline
 unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
                                            gfp_t gfp_mask,
@@ -1427,6 +1432,8 @@ static inline int memcg_cache_id(struct mem_cgroup *memcg)
        return memcg ? memcg->kmemcg_id : -1;
 }
 
+struct mem_cgroup *mem_cgroup_from_obj(void *p);
+
 #else
 
 static inline int memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
@@ -1468,6 +1475,11 @@ static inline void memcg_put_cache_ids(void)
 {
 }
 
+static inline struct mem_cgroup *mem_cgroup_from_obj(void *p)
+{
+       return NULL;
+}
+
 #endif /* CONFIG_MEMCG_KMEM */
 
 #endif /* _LINUX_MEMCONTROL_H */
diff --git a/include/linux/min_heap.h b/include/linux/min_heap.h
new file mode 100644 (file)
index 0000000..4407783
--- /dev/null
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MIN_HEAP_H
+#define _LINUX_MIN_HEAP_H
+
+#include <linux/bug.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+/**
+ * struct min_heap - Data structure to hold a min-heap.
+ * @data: Start of array holding the heap elements.
+ * @nr: Number of elements currently in the heap.
+ * @size: Maximum number of elements that can be held in current storage.
+ */
+struct min_heap {
+       void *data;
+       int nr;
+       int size;
+};
+
+/**
+ * struct min_heap_callbacks - Data/functions to customise the min_heap.
+ * @elem_size: The nr of each element in bytes.
+ * @less: Partial order function for this heap.
+ * @swp: Swap elements function.
+ */
+struct min_heap_callbacks {
+       int elem_size;
+       bool (*less)(const void *lhs, const void *rhs);
+       void (*swp)(void *lhs, void *rhs);
+};
+
+/* Sift the element at pos down the heap. */
+static __always_inline
+void min_heapify(struct min_heap *heap, int pos,
+               const struct min_heap_callbacks *func)
+{
+       void *left, *right, *parent, *smallest;
+       void *data = heap->data;
+
+       for (;;) {
+               if (pos * 2 + 1 >= heap->nr)
+                       break;
+
+               left = data + ((pos * 2 + 1) * func->elem_size);
+               parent = data + (pos * func->elem_size);
+               smallest = parent;
+               if (func->less(left, smallest))
+                       smallest = left;
+
+               if (pos * 2 + 2 < heap->nr) {
+                       right = data + ((pos * 2 + 2) * func->elem_size);
+                       if (func->less(right, smallest))
+                               smallest = right;
+               }
+               if (smallest == parent)
+                       break;
+               func->swp(smallest, parent);
+               if (smallest == left)
+                       pos = (pos * 2) + 1;
+               else
+                       pos = (pos * 2) + 2;
+       }
+}
+
+/* Floyd's approach to heapification that is O(nr). */
+static __always_inline
+void min_heapify_all(struct min_heap *heap,
+               const struct min_heap_callbacks *func)
+{
+       int i;
+
+       for (i = heap->nr / 2; i >= 0; i--)
+               min_heapify(heap, i, func);
+}
+
+/* Remove minimum element from the heap, O(log2(nr)). */
+static __always_inline
+void min_heap_pop(struct min_heap *heap,
+               const struct min_heap_callbacks *func)
+{
+       void *data = heap->data;
+
+       if (WARN_ONCE(heap->nr <= 0, "Popping an empty heap"))
+               return;
+
+       /* Place last element at the root (position 0) and then sift down. */
+       heap->nr--;
+       memcpy(data, data + (heap->nr * func->elem_size), func->elem_size);
+       min_heapify(heap, 0, func);
+}
+
+/*
+ * Remove the minimum element and then push the given element. The
+ * implementation performs 1 sift (O(log2(nr))) and is therefore more
+ * efficient than a pop followed by a push that does 2.
+ */
+static __always_inline
+void min_heap_pop_push(struct min_heap *heap,
+               const void *element,
+               const struct min_heap_callbacks *func)
+{
+       memcpy(heap->data, element, func->elem_size);
+       min_heapify(heap, 0, func);
+}
+
+/* Push an element on to the heap, O(log2(nr)). */
+static __always_inline
+void min_heap_push(struct min_heap *heap, const void *element,
+               const struct min_heap_callbacks *func)
+{
+       void *data = heap->data;
+       void *child, *parent;
+       int pos;
+
+       if (WARN_ONCE(heap->nr >= heap->size, "Pushing on a full heap"))
+               return;
+
+       /* Place at the end of data. */
+       pos = heap->nr;
+       memcpy(data + (pos * func->elem_size), element, func->elem_size);
+       heap->nr++;
+
+       /* Sift child at pos up. */
+       for (; pos > 0; pos = (pos - 1) / 2) {
+               child = data + (pos * func->elem_size);
+               parent = data + ((pos - 1) / 2) * func->elem_size;
+               if (func->less(parent, child))
+                       break;
+               func->swp(parent, child);
+       }
+}
+
+#endif /* _LINUX_MIN_HEAP_H */
index 52269e5..c54fb96 100644 (file)
@@ -2715,6 +2715,10 @@ static inline bool debug_pagealloc_enabled_static(void)
 #if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP)
 extern void __kernel_map_pages(struct page *page, int numpages, int enable);
 
+/*
+ * When called in DEBUG_PAGEALLOC context, the call should most likely be
+ * guarded by debug_pagealloc_enabled() or debug_pagealloc_enabled_static()
+ */
 static inline void
 kernel_map_pages(struct page *page, int numpages, int enable)
 {
index ba70338..4c5eb3a 100644 (file)
@@ -333,6 +333,7 @@ struct mmc_host {
                                 MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | \
                                 MMC_CAP_UHS_DDR50)
 #define MMC_CAP_SYNC_RUNTIME_PM        (1 << 21)       /* Synced runtime PM suspends. */
+#define MMC_CAP_NEED_RSP_BUSY  (1 << 22)       /* Commands with R1B can't use R1. */
 #define MMC_CAP_DRIVER_TYPE_A  (1 << 23)       /* Host supports Driver Type A */
 #define MMC_CAP_DRIVER_TYPE_C  (1 << 24)       /* Host supports Driver Type C */
 #define MMC_CAP_DRIVER_TYPE_D  (1 << 25)       /* Host supports Driver Type D */
index e3596db..f8b66d4 100644 (file)
@@ -667,9 +667,7 @@ struct x86_cpu_id {
        kernel_ulong_t driver_data;
 };
 
-#define X86_FEATURE_MATCH(x) \
-       { X86_VENDOR_ANY, X86_FAMILY_ANY, X86_MODEL_ANY, x }
-
+/* Wild cards for x86_cpu_id::vendor, family, model and feature */
 #define X86_VENDOR_ANY 0xffff
 #define X86_FAMILY_ANY 0
 #define X86_MODEL_ANY  0
diff --git a/include/linux/msdos_partition.h b/include/linux/msdos_partition.h
new file mode 100644 (file)
index 0000000..2cb82db
--- /dev/null
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MSDOS_PARTITION_H
+#define _LINUX_MSDOS_PARTITION_H
+
+#define MSDOS_LABEL_MAGIC              0xAA55
+
+struct msdos_partition {
+       u8 boot_ind;            /* 0x80 - active */
+       u8 head;                /* starting head */
+       u8 sector;              /* starting sector */
+       u8 cyl;                 /* starting cylinder */
+       u8 sys_ind;             /* What partition type */
+       u8 end_head;            /* end head */
+       u8 end_sector;          /* end sector */
+       u8 end_cyl;             /* end cylinder */
+       __le32 start_sect;      /* starting sector counting from 0 */
+       __le32 nr_sects;        /* nr of sectors in partition */
+} __packed;
+
+enum msdos_sys_ind {
+       /*
+        * These three have identical behaviour; use the second one if DOS FDISK
+        * gets confused about extended/logical partitions starting past
+        * cylinder 1023.
+        */
+       DOS_EXTENDED_PARTITION = 5,
+       LINUX_EXTENDED_PARTITION = 0x85,
+       WIN98_EXTENDED_PARTITION = 0x0f,
+
+       LINUX_DATA_PARTITION = 0x83,
+       LINUX_LVM_PARTITION = 0x8e,
+       LINUX_RAID_PARTITION = 0xfd,    /* autodetect RAID partition */
+
+       SOLARIS_X86_PARTITION = 0x82,   /* also Linux swap partitions */
+       NEW_SOLARIS_X86_PARTITION = 0xbf,
+
+       DM6_AUX1PARTITION = 0x51,       /* no DDO:  use xlated geom */
+       DM6_AUX3PARTITION = 0x53,       /* no DDO:  use xlated geom */
+       DM6_PARTITION = 0x54,           /* has DDO: use xlated geom & offset */
+       EZD_PARTITION = 0x55,           /* EZ-DRIVE */
+
+       FREEBSD_PARTITION = 0xa5,       /* FreeBSD Partition ID */
+       OPENBSD_PARTITION = 0xa6,       /* OpenBSD Partition ID */
+       NETBSD_PARTITION = 0xa9,        /* NetBSD Partition ID */
+       BSDI_PARTITION = 0xb7,          /* BSDI Partition ID */
+       MINIX_PARTITION = 0x81,         /* Minix Partition ID */
+       UNIXWARE_PARTITION = 0x63,      /* Same as GNU_HURD and SCO Unix */
+};
+
+#endif /* LINUX_MSDOS_PARTITION_H */
index aca8f36..ae197cc 100644 (file)
@@ -109,8 +109,11 @@ do {                                                                       \
 } while (0)
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __DEP_MAP_MUTEX_INITIALIZER(lockname) \
-               , .dep_map = { .name = #lockname }
+# define __DEP_MAP_MUTEX_INITIALIZER(lockname)                 \
+               , .dep_map = {                                  \
+                       .name = #lockname,                      \
+                       .wait_type_inner = LD_WAIT_SLEEP,       \
+               }
 #else
 # define __DEP_MAP_MUTEX_INITIALIZER(lockname)
 #endif
index 908d38d..5448c8b 100644 (file)
@@ -121,6 +121,7 @@ struct ip_set_ext {
        u32 timeout;
        u8 packets_op;
        u8 bytes_op;
+       bool target;
 };
 
 struct ip_set;
@@ -187,6 +188,14 @@ struct ip_set_type_variant {
        /* Return true if "b" set is the same as "a"
         * according to the create set parameters */
        bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
+       /* Region-locking is used */
+       bool region_lock;
+};
+
+struct ip_set_region {
+       spinlock_t lock;        /* Region lock */
+       size_t ext_size;        /* Size of the dynamic extensions */
+       u32 elements;           /* Number of elements vs timeout */
 };
 
 /* The core set type structure */
@@ -501,7 +510,7 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo,
 }
 
 #define IP_SET_INIT_KEXT(skb, opt, set)                        \
-       { .bytes = (skb)->len, .packets = 1,            \
+       { .bytes = (skb)->len, .packets = 1, .target = true,\
          .timeout = ip_set_adt_opt_timeout(opt, set) }
 
 #define IP_SET_INIT_UEXT(set)                          \
index 205fa7b..60739d0 100644 (file)
@@ -115,6 +115,19 @@ static inline void nl_set_extack_cookie_u64(struct netlink_ext_ack *extack,
 {
        u64 __cookie = cookie;
 
+       if (!extack)
+               return;
+       memcpy(extack->cookie, &__cookie, sizeof(__cookie));
+       extack->cookie_len = sizeof(__cookie);
+}
+
+static inline void nl_set_extack_cookie_u32(struct netlink_ext_ack *extack,
+                                           u32 cookie)
+{
+       u32 __cookie = cookie;
+
+       if (!extack)
+               return;
        memcpy(extack->cookie, &__cookie, sizeof(__cookie));
        extack->cookie_len = sizeof(__cookie);
 }
index c86fcad..31b73a0 100644 (file)
@@ -11,17 +11,17 @@ struct of_device_id;
 
 #if defined(CONFIG_COMMON_CLK) && defined(CONFIG_OF)
 
-unsigned int of_clk_get_parent_count(struct device_node *np);
-const char *of_clk_get_parent_name(struct device_node *np, int index);
+unsigned int of_clk_get_parent_count(const struct device_node *np);
+const char *of_clk_get_parent_name(const struct device_node *np, int index);
 void of_clk_init(const struct of_device_id *matches);
 
 #else /* !CONFIG_COMMON_CLK || !CONFIG_OF */
 
-static inline unsigned int of_clk_get_parent_count(struct device_node *np)
+static inline unsigned int of_clk_get_parent_count(const struct device_node *np)
 {
        return 0;
 }
-static inline const char *of_clk_get_parent_name(struct device_node *np,
+static inline const char *of_clk_get_parent_name(const struct device_node *np,
                                                 int index)
 {
        return NULL;
index 1bf83c8..77de28b 100644 (file)
@@ -311,7 +311,7 @@ static inline int TestClearPage##uname(struct page *page) { return 0; }
 
 __PAGEFLAG(Locked, locked, PF_NO_TAIL)
 PAGEFLAG(Waiters, waiters, PF_ONLY_HEAD) __CLEARPAGEFLAG(Waiters, waiters, PF_ONLY_HEAD)
-PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND)
+PAGEFLAG(Error, error, PF_NO_TAIL) TESTCLEARFLAG(Error, error, PF_NO_TAIL)
 PAGEFLAG(Referenced, referenced, PF_HEAD)
        TESTCLEARFLAG(Referenced, referenced, PF_HEAD)
        __SETPAGEFLAG(Referenced, referenced, PF_HEAD)
diff --git a/include/linux/part_stat.h b/include/linux/part_stat.h
new file mode 100644 (file)
index 0000000..ece6076
--- /dev/null
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_PART_STAT_H
+#define _LINUX_PART_STAT_H
+
+#include <linux/genhd.h>
+
+/*
+ * Macros to operate on percpu disk statistics:
+ *
+ * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters
+ * and should be called between disk_stat_lock() and
+ * disk_stat_unlock().
+ *
+ * part_stat_read() can be called at any time.
+ *
+ * part_stat_{add|set_all}() and {init|free}_part_stats are for
+ * internal use only.
+ */
+#ifdef CONFIG_SMP
+#define part_stat_lock()       ({ rcu_read_lock(); get_cpu(); })
+#define part_stat_unlock()     do { put_cpu(); rcu_read_unlock(); } while (0)
+
+#define part_stat_get_cpu(part, field, cpu)                            \
+       (per_cpu_ptr((part)->dkstats, (cpu))->field)
+
+#define part_stat_get(part, field)                                     \
+       part_stat_get_cpu(part, field, smp_processor_id())
+
+#define part_stat_read(part, field)                                    \
+({                                                                     \
+       typeof((part)->dkstats->field) res = 0;                         \
+       unsigned int _cpu;                                              \
+       for_each_possible_cpu(_cpu)                                     \
+               res += per_cpu_ptr((part)->dkstats, _cpu)->field;       \
+       res;                                                            \
+})
+
+static inline void part_stat_set_all(struct hd_struct *part, int value)
+{
+       int i;
+
+       for_each_possible_cpu(i)
+               memset(per_cpu_ptr(part->dkstats, i), value,
+                               sizeof(struct disk_stats));
+}
+
+static inline int init_part_stats(struct hd_struct *part)
+{
+       part->dkstats = alloc_percpu(struct disk_stats);
+       if (!part->dkstats)
+               return 0;
+       return 1;
+}
+
+static inline void free_part_stats(struct hd_struct *part)
+{
+       free_percpu(part->dkstats);
+}
+
+#else /* !CONFIG_SMP */
+#define part_stat_lock()       ({ rcu_read_lock(); 0; })
+#define part_stat_unlock()     rcu_read_unlock()
+
+#define part_stat_get(part, field)             ((part)->dkstats.field)
+#define part_stat_get_cpu(part, field, cpu)    part_stat_get(part, field)
+#define part_stat_read(part, field)            part_stat_get(part, field)
+
+static inline void part_stat_set_all(struct hd_struct *part, int value)
+{
+       memset(&part->dkstats, value, sizeof(struct disk_stats));
+}
+
+static inline int init_part_stats(struct hd_struct *part)
+{
+       return 1;
+}
+
+static inline void free_part_stats(struct hd_struct *part)
+{
+}
+
+#endif /* CONFIG_SMP */
+
+#define part_stat_read_accum(part, field)                              \
+       (part_stat_read(part, field[STAT_READ]) +                       \
+        part_stat_read(part, field[STAT_WRITE]) +                      \
+        part_stat_read(part, field[STAT_DISCARD]))
+
+#define __part_stat_add(part, field, addnd)                            \
+       (part_stat_get(part, field) += (addnd))
+
+#define part_stat_add(part, field, addnd)      do {                    \
+       __part_stat_add((part), field, addnd);                          \
+       if ((part)->partno)                                             \
+               __part_stat_add(&part_to_disk((part))->part0,           \
+                               field, addnd);                          \
+} while (0)
+
+#define part_stat_dec(gendiskp, field)                                 \
+       part_stat_add(gendiskp, field, -1)
+#define part_stat_inc(gendiskp, field)                                 \
+       part_stat_add(gendiskp, field, 1)
+#define part_stat_sub(gendiskp, field, subnd)                          \
+       part_stat_add(gendiskp, field, -subnd)
+
+#define part_stat_local_dec(gendiskp, field)                           \
+       local_dec(&(part_stat_get(gendiskp, field)))
+#define part_stat_local_inc(gendiskp, field)                           \
+       local_inc(&(part_stat_get(gendiskp, field)))
+#define part_stat_local_read(gendiskp, field)                          \
+       local_read(&(part_stat_get(gendiskp, field)))
+#define part_stat_local_read_cpu(gendiskp, field, cpu)                 \
+       local_read(&(part_stat_get_cpu(gendiskp, field, cpu)))
+
+#endif /* _LINUX_PART_STAT_H */
index 352c0d7..977e668 100644 (file)
 
 /* Vendors and devices.  Sort key: vendor first, device next. */
 
+#define PCI_VENDOR_ID_LOONGSON         0x0014
+
 #define PCI_VENDOR_ID_TTTECH           0x0357
 #define PCI_DEVICE_ID_TTTECH_MC322     0x000a
 
index c86bd3a..8ad71d7 100644 (file)
 
 #include <linux/types.h>
 
+/*
+ * Linux EFI stub v1.0 adds the following functionality:
+ * - Loading initrd from the LINUX_EFI_INITRD_MEDIA_GUID device path,
+ * - Loading/starting the kernel from firmware that targets a different
+ *   machine type, via the entrypoint exposed in the .compat PE/COFF section.
+ *
+ * The recommended way of loading and starting v1.0 or later kernels is to use
+ * the LoadImage() and StartImage() EFI boot services, and expose the initrd
+ * via the LINUX_EFI_INITRD_MEDIA_GUID device path.
+ *
+ * Versions older than v1.0 support initrd loading via the image load options
+ * (using initrd=, limited to the volume from which the kernel itself was
+ * loaded), or via arch specific means (bootparams, DT, etc).
+ *
+ * On x86, LoadImage() and StartImage() can be omitted if the EFI handover
+ * protocol is implemented, which can be inferred from the version,
+ * handover_offset and xloadflags fields in the bootparams structure.
+ */
+#define LINUX_EFISTUB_MAJOR_VERSION            0x1
+#define LINUX_EFISTUB_MINOR_VERSION            0x0
+
 #define MZ_MAGIC       0x5a4d  /* "MZ" */
 
 #define PE_MAGIC               0x00004550      /* "PE\0\0" */
index ad2ca2a..5e033fe 100644 (file)
@@ -3,41 +3,52 @@
 #define _LINUX_PERCPU_RWSEM_H
 
 #include <linux/atomic.h>
-#include <linux/rwsem.h>
 #include <linux/percpu.h>
 #include <linux/rcuwait.h>
+#include <linux/wait.h>
 #include <linux/rcu_sync.h>
 #include <linux/lockdep.h>
 
 struct percpu_rw_semaphore {
        struct rcu_sync         rss;
        unsigned int __percpu   *read_count;
-       struct rw_semaphore     rw_sem; /* slowpath */
-       struct rcuwait          writer; /* blocked writer */
-       int                     readers_block;
+       struct rcuwait          writer;
+       wait_queue_head_t       waiters;
+       atomic_t                block;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map      dep_map;
+#endif
 };
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#define __PERCPU_RWSEM_DEP_MAP_INIT(lockname)  .dep_map = { .name = #lockname },
+#else
+#define __PERCPU_RWSEM_DEP_MAP_INIT(lockname)
+#endif
+
 #define __DEFINE_PERCPU_RWSEM(name, is_static)                         \
 static DEFINE_PER_CPU(unsigned int, __percpu_rwsem_rc_##name);         \
 is_static struct percpu_rw_semaphore name = {                          \
        .rss = __RCU_SYNC_INITIALIZER(name.rss),                        \
        .read_count = &__percpu_rwsem_rc_##name,                        \
-       .rw_sem = __RWSEM_INITIALIZER(name.rw_sem),                     \
        .writer = __RCUWAIT_INITIALIZER(name.writer),                   \
+       .waiters = __WAIT_QUEUE_HEAD_INITIALIZER(name.waiters),         \
+       .block = ATOMIC_INIT(0),                                        \
+       __PERCPU_RWSEM_DEP_MAP_INIT(name)                               \
 }
+
 #define DEFINE_PERCPU_RWSEM(name)              \
        __DEFINE_PERCPU_RWSEM(name, /* not static */)
 #define DEFINE_STATIC_PERCPU_RWSEM(name)       \
        __DEFINE_PERCPU_RWSEM(name, static)
 
-extern int __percpu_down_read(struct percpu_rw_semaphore *, int);
-extern void __percpu_up_read(struct percpu_rw_semaphore *);
+extern bool __percpu_down_read(struct percpu_rw_semaphore *, bool);
 
 static inline void percpu_down_read(struct percpu_rw_semaphore *sem)
 {
        might_sleep();
 
-       rwsem_acquire_read(&sem->rw_sem.dep_map, 0, 0, _RET_IP_);
+       rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
 
        preempt_disable();
        /*
@@ -48,8 +59,9 @@ static inline void percpu_down_read(struct percpu_rw_semaphore *sem)
         * and that once the synchronize_rcu() is done, the writer will see
         * anything we did within this RCU-sched read-size critical section.
         */
-       __this_cpu_inc(*sem->read_count);
-       if (unlikely(!rcu_sync_is_idle(&sem->rss)))
+       if (likely(rcu_sync_is_idle(&sem->rss)))
+               __this_cpu_inc(*sem->read_count);
+       else
                __percpu_down_read(sem, false); /* Unconditional memory barrier */
        /*
         * The preempt_enable() prevents the compiler from
@@ -58,16 +70,17 @@ static inline void percpu_down_read(struct percpu_rw_semaphore *sem)
        preempt_enable();
 }
 
-static inline int percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
+static inline bool percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
 {
-       int ret = 1;
+       bool ret = true;
 
        preempt_disable();
        /*
         * Same as in percpu_down_read().
         */
-       __this_cpu_inc(*sem->read_count);
-       if (unlikely(!rcu_sync_is_idle(&sem->rss)))
+       if (likely(rcu_sync_is_idle(&sem->rss)))
+               __this_cpu_inc(*sem->read_count);
+       else
                ret = __percpu_down_read(sem, true); /* Unconditional memory barrier */
        preempt_enable();
        /*
@@ -76,24 +89,36 @@ static inline int percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
         */
 
        if (ret)
-               rwsem_acquire_read(&sem->rw_sem.dep_map, 0, 1, _RET_IP_);
+               rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_);
 
        return ret;
 }
 
 static inline void percpu_up_read(struct percpu_rw_semaphore *sem)
 {
+       rwsem_release(&sem->dep_map, _RET_IP_);
+
        preempt_disable();
        /*
         * Same as in percpu_down_read().
         */
-       if (likely(rcu_sync_is_idle(&sem->rss)))
+       if (likely(rcu_sync_is_idle(&sem->rss))) {
                __this_cpu_dec(*sem->read_count);
-       else
-               __percpu_up_read(sem); /* Unconditional memory barrier */
+       } else {
+               /*
+                * slowpath; reader will only ever wake a single blocked
+                * writer.
+                */
+               smp_mb(); /* B matches C */
+               /*
+                * In other words, if they see our decrement (presumably to
+                * aggregate zero, as that is the only time it matters) they
+                * will also see our critical section.
+                */
+               __this_cpu_dec(*sem->read_count);
+               rcuwait_wake_up(&sem->writer);
+       }
        preempt_enable();
-
-       rwsem_release(&sem->rw_sem.dep_map, _RET_IP_);
 }
 
 extern void percpu_down_write(struct percpu_rw_semaphore *);
@@ -110,29 +135,19 @@ extern void percpu_free_rwsem(struct percpu_rw_semaphore *);
        __percpu_init_rwsem(sem, #sem, &rwsem_key);             \
 })
 
-#define percpu_rwsem_is_held(sem) lockdep_is_held(&(sem)->rw_sem)
-
-#define percpu_rwsem_assert_held(sem)                          \
-       lockdep_assert_held(&(sem)->rw_sem)
+#define percpu_rwsem_is_held(sem)      lockdep_is_held(sem)
+#define percpu_rwsem_assert_held(sem)  lockdep_assert_held(sem)
 
 static inline void percpu_rwsem_release(struct percpu_rw_semaphore *sem,
                                        bool read, unsigned long ip)
 {
-       lock_release(&sem->rw_sem.dep_map, ip);
-#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
-       if (!read)
-               atomic_long_set(&sem->rw_sem.owner, RWSEM_OWNER_UNKNOWN);
-#endif
+       lock_release(&sem->dep_map, ip);
 }
 
 static inline void percpu_rwsem_acquire(struct percpu_rw_semaphore *sem,
                                        bool read, unsigned long ip)
 {
-       lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip);
-#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
-       if (!read)
-               atomic_long_set(&sem->rw_sem.owner, (long)current);
-#endif
+       lock_acquire(&sem->dep_map, 0, 1, read, 1, NULL, ip);
 }
 
 #endif
index 71f525a..5b616dd 100644 (file)
@@ -80,6 +80,7 @@ struct arm_pmu {
        struct pmu      pmu;
        cpumask_t       supported_cpus;
        char            *name;
+       int             pmuver;
        irqreturn_t     (*handle_irq)(struct arm_pmu *pmu);
        void            (*enable)(struct perf_event *event);
        void            (*disable)(struct perf_event *event);
index 547773f..8768a39 100644 (file)
@@ -93,14 +93,26 @@ struct perf_raw_record {
 /*
  * branch stack layout:
  *  nr: number of taken branches stored in entries[]
+ *  hw_idx: The low level index of raw branch records
+ *          for the most recent branch.
+ *          -1ULL means invalid/unknown.
  *
  * Note that nr can vary from sample to sample
  * branches (to, from) are stored from most recent
  * to least recent, i.e., entries[0] contains the most
  * recent branch.
+ * The entries[] is an abstraction of raw branch records,
+ * which may not be stored in age order in HW, e.g. Intel LBR.
+ * The hw_idx is to expose the low level index of raw
+ * branch record for the most recent branch aka entries[0].
+ * The hw_idx index is between -1 (unknown) and max depth,
+ * which can be retrieved in /sys/devices/cpu/caps/branches.
+ * For the architectures whose raw branch records are
+ * already stored in age order, the hw_idx should be 0.
  */
 struct perf_branch_stack {
        __u64                           nr;
+       __u64                           hw_idx;
        struct perf_branch_entry        entries[0];
 };
 
@@ -850,6 +862,13 @@ struct perf_cpu_context {
        int                             sched_cb_usage;
 
        int                             online;
+       /*
+        * Per-CPU storage for iterators used in visit_groups_merge. The default
+        * storage is of size 2 to hold the CPU and any CPU event iterators.
+        */
+       int                             heap_size;
+       struct perf_event               **heap;
+       struct perf_event               *heap_default[2];
 };
 
 struct perf_output_handle {
index c570e16..452e8ba 100644 (file)
@@ -357,6 +357,7 @@ struct macsec_ops;
  * is_gigabit_capable: Set to true if PHY supports 1000Mbps
  * has_fixups: Set to true if this phy has fixups/quirks.
  * suspended: Set to true if this phy has been suspended successfully.
+ * suspended_by_mdio_bus: Set to true if this phy was suspended by MDIO bus.
  * sysfs_links: Internal boolean tracking sysfs symbolic links setup/removal.
  * loopback_enabled: Set true if this phy has been loopbacked successfully.
  * state: state of the PHY for management purposes
@@ -396,6 +397,7 @@ struct phy_device {
        unsigned is_gigabit_capable:1;
        unsigned has_fixups:1;
        unsigned suspended:1;
+       unsigned suspended_by_mdio_bus:1;
        unsigned sysfs_links:1;
        unsigned loopback_enabled:1;
 
@@ -557,6 +559,7 @@ struct phy_driver {
        /*
         * Checks if the PHY generated an interrupt.
         * For multi-PHY devices with shared PHY interrupt pin
+        * Set interrupt bits have to be cleared.
         */
        int (*did_interrupt)(struct phy_device *phydev);
 
index 1235865..71d9569 100644 (file)
@@ -21,4 +21,6 @@ int tegra_xusb_padctl_usb3_set_lfps_detect(struct tegra_xusb_padctl *padctl,
 int tegra_xusb_padctl_set_vbus_override(struct tegra_xusb_padctl *padctl,
                                        bool val);
 int tegra_phy_xusb_utmi_port_reset(struct phy *phy);
+int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl,
+                                        unsigned int port);
 #endif /* PHY_TEGRA_XUSB_H */
index bdaaf53..95d852a 100644 (file)
@@ -30,12 +30,12 @@ struct omap_dm_timer_ops {
        int     (*stop)(struct omap_dm_timer *timer);
        int     (*set_source)(struct omap_dm_timer *timer, int source);
 
-       int     (*set_load)(struct omap_dm_timer *timer, int autoreload,
-                           unsigned int value);
+       int     (*set_load)(struct omap_dm_timer *timer, unsigned int value);
        int     (*set_match)(struct omap_dm_timer *timer, int enable,
                             unsigned int match);
        int     (*set_pwm)(struct omap_dm_timer *timer, int def_on,
-                          int toggle, int trigger);
+                          int toggle, int trigger, int autoreload);
+       int     (*get_pwm_status)(struct omap_dm_timer *timer);
        int     (*set_prescaler)(struct omap_dm_timer *timer, int prescaler);
 
        unsigned int (*read_counter)(struct omap_dm_timer *timer);
index 0bf9fdd..3b400b1 100644 (file)
@@ -11,6 +11,7 @@ struct omap2_mcspi_platform_config {
        unsigned short  num_cs;
        unsigned int regs_offset;
        unsigned int pin_dir:1;
+       size_t max_xfer_len;
 };
 
 struct omap2_mcspi_device_config {
index 276a03c..bdc3575 100644 (file)
@@ -24,7 +24,7 @@ struct platform_device {
        int             id;
        bool            id_auto;
        struct device   dev;
-       u64             dma_mask;
+       u64             platform_dma_mask;
        u32             num_resources;
        struct resource *resource;
 
@@ -55,6 +55,9 @@ extern struct device *
 platform_find_device_by_driver(struct device *start,
                               const struct device_driver *drv);
 extern void __iomem *
+devm_platform_get_and_ioremap_resource(struct platform_device *pdev,
+                               unsigned int index, struct resource **res);
+extern void __iomem *
 devm_platform_ioremap_resource(struct platform_device *pdev,
                               unsigned int index);
 extern void __iomem *
@@ -89,7 +92,7 @@ struct platform_device_info {
                size_t size_data;
                u64 dma_mask;
 
-               struct property_entry *properties;
+               const struct property_entry *properties;
 };
 extern struct platform_device *platform_device_register_full(
                const struct platform_device_info *pdevinfo);
index 19eafca..4a69d4a 100644 (file)
@@ -1,22 +1,20 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LINUX_PM_QOS_H
-#define _LINUX_PM_QOS_H
-/* interface for the pm_qos_power infrastructure of the linux kernel.
+/*
+ * Definitions related to Power Management Quality of Service (PM QoS).
  *
- * Mark Gross <mgross@linux.intel.com>
+ * Copyright (C) 2020 Intel Corporation
+ *
+ * Authors:
+ *     Mark Gross <mgross@linux.intel.com>
+ *     Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  */
+
+#ifndef _LINUX_PM_QOS_H
+#define _LINUX_PM_QOS_H
+
 #include <linux/plist.h>
 #include <linux/notifier.h>
 #include <linux/device.h>
-#include <linux/workqueue.h>
-
-enum {
-       PM_QOS_RESERVED = 0,
-       PM_QOS_CPU_DMA_LATENCY,
-
-       /* insert new class ID */
-       PM_QOS_NUM_CLASSES,
-};
 
 enum pm_qos_flags_status {
        PM_QOS_FLAGS_UNDEFINED = -1,
@@ -29,7 +27,7 @@ enum pm_qos_flags_status {
 #define PM_QOS_LATENCY_ANY     S32_MAX
 #define PM_QOS_LATENCY_ANY_NS  ((s64)PM_QOS_LATENCY_ANY * NSEC_PER_USEC)
 
-#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
+#define PM_QOS_CPU_LATENCY_DEFAULT_VALUE       (2000 * USEC_PER_SEC)
 #define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE    PM_QOS_LATENCY_ANY
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT    PM_QOS_LATENCY_ANY
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS
@@ -40,22 +38,10 @@ enum pm_qos_flags_status {
 
 #define PM_QOS_FLAG_NO_POWER_OFF       (1 << 0)
 
-struct pm_qos_request {
-       struct plist_node node;
-       int pm_qos_class;
-       struct delayed_work work; /* for pm_qos_update_request_timeout */
-};
-
-struct pm_qos_flags_request {
-       struct list_head node;
-       s32 flags;      /* Do not change to 64 bit */
-};
-
 enum pm_qos_type {
        PM_QOS_UNITIALIZED,
        PM_QOS_MAX,             /* return the largest value */
        PM_QOS_MIN,             /* return the smallest value */
-       PM_QOS_SUM              /* return the sum */
 };
 
 /*
@@ -72,6 +58,16 @@ struct pm_qos_constraints {
        struct blocking_notifier_head *notifiers;
 };
 
+struct pm_qos_request {
+       struct plist_node node;
+       struct pm_qos_constraints *qos;
+};
+
+struct pm_qos_flags_request {
+       struct list_head node;
+       s32 flags;      /* Do not change to 64 bit */
+};
+
 struct pm_qos_flags {
        struct list_head list;
        s32 effective_flags;    /* Do not change to 64 bit */
@@ -140,24 +136,31 @@ static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req)
        return req->dev != NULL;
 }
 
+s32 pm_qos_read_value(struct pm_qos_constraints *c);
 int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
                         enum pm_qos_req_action action, int value);
 bool pm_qos_update_flags(struct pm_qos_flags *pqf,
                         struct pm_qos_flags_request *req,
                         enum pm_qos_req_action action, s32 val);
-void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class,
-                       s32 value);
-void pm_qos_update_request(struct pm_qos_request *req,
-                          s32 new_value);
-void pm_qos_update_request_timeout(struct pm_qos_request *req,
-                                  s32 new_value, unsigned long timeout_us);
-void pm_qos_remove_request(struct pm_qos_request *req);
-
-int pm_qos_request(int pm_qos_class);
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier);
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier);
-int pm_qos_request_active(struct pm_qos_request *req);
-s32 pm_qos_read_value(struct pm_qos_constraints *c);
+
+#ifdef CONFIG_CPU_IDLE
+s32 cpu_latency_qos_limit(void);
+bool cpu_latency_qos_request_active(struct pm_qos_request *req);
+void cpu_latency_qos_add_request(struct pm_qos_request *req, s32 value);
+void cpu_latency_qos_update_request(struct pm_qos_request *req, s32 new_value);
+void cpu_latency_qos_remove_request(struct pm_qos_request *req);
+#else
+static inline s32 cpu_latency_qos_limit(void) { return INT_MAX; }
+static inline bool cpu_latency_qos_request_active(struct pm_qos_request *req)
+{
+       return false;
+}
+static inline void cpu_latency_qos_add_request(struct pm_qos_request *req,
+                                              s32 value) {}
+static inline void cpu_latency_qos_update_request(struct pm_qos_request *req,
+                                                 s32 new_value) {}
+static inline void cpu_latency_qos_remove_request(struct pm_qos_request *req) {}
+#endif
 
 #ifdef CONFIG_PM
 enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask);
index 22af69d..3bdcbce 100644 (file)
@@ -38,7 +38,7 @@ extern int pm_runtime_force_resume(struct device *dev);
 extern int __pm_runtime_idle(struct device *dev, int rpmflags);
 extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
 extern int __pm_runtime_resume(struct device *dev, int rpmflags);
-extern int pm_runtime_get_if_in_use(struct device *dev);
+extern int pm_runtime_get_if_active(struct device *dev, bool ign_usage_count);
 extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
 extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
 extern int pm_runtime_barrier(struct device *dev);
@@ -60,6 +60,11 @@ extern void pm_runtime_put_suppliers(struct device *dev);
 extern void pm_runtime_new_link(struct device *dev);
 extern void pm_runtime_drop_link(struct device *dev);
 
+static inline int pm_runtime_get_if_in_use(struct device *dev)
+{
+       return pm_runtime_get_if_active(dev, false);
+}
+
 static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
 {
        dev->power.ignore_children = enable;
@@ -143,6 +148,11 @@ static inline int pm_runtime_get_if_in_use(struct device *dev)
 {
        return -EINVAL;
 }
+static inline int pm_runtime_get_if_active(struct device *dev,
+                                          bool ign_usage_count)
+{
+       return -EINVAL;
+}
 static inline int __pm_runtime_set_status(struct device *dev,
                                            unsigned int status) { return 0; }
 static inline int pm_runtime_barrier(struct device *dev) { return 0; }
index 3b12fd2..b18dca6 100644 (file)
@@ -379,7 +379,7 @@ struct pnp_id {
 };
 
 struct pnp_driver {
-       char *name;
+       const char *name;
        const struct pnp_device_id *id_table;
        unsigned int flags;
        int (*probe) (struct pnp_dev *dev, const struct pnp_device_id *dev_id);
index 3d10c84..e3f0f85 100644 (file)
@@ -69,7 +69,7 @@ static inline int clockid_to_fd(const clockid_t clk)
 struct cpu_timer {
        struct timerqueue_node  node;
        struct timerqueue_head  *head;
-       struct task_struct      *task;
+       struct pid              *pid;
        struct list_head        elist;
        int                     firing;
 };
index bbb68db..bc3f1ae 100644 (file)
@@ -322,4 +322,34 @@ static inline void preempt_notifier_init(struct preempt_notifier *notifier,
 
 #endif
 
+/**
+ * migrate_disable - Prevent migration of the current task
+ *
+ * Maps to preempt_disable() which also disables preemption. Use
+ * migrate_disable() to annotate that the intent is to prevent migration,
+ * but not necessarily preemption.
+ *
+ * Can be invoked nested like preempt_disable() and needs the corresponding
+ * number of migrate_enable() invocations.
+ */
+static __always_inline void migrate_disable(void)
+{
+       preempt_disable();
+}
+
+/**
+ * migrate_enable - Allow migration of the current task
+ *
+ * Counterpart to migrate_disable().
+ *
+ * As migrate_disable() can be invoked nested, only the outermost invocation
+ * reenables migration.
+ *
+ * Currently mapped to preempt_enable().
+ */
+static __always_inline void migrate_enable(void)
+{
+       preempt_enable();
+}
+
 #endif /* __LINUX_PREEMPT_H */
index 7b3de73..7361023 100644 (file)
@@ -17,6 +17,8 @@ extern struct psi_group psi_system;
 void psi_init(void);
 
 void psi_task_change(struct task_struct *task, int clear, int set);
+void psi_task_switch(struct task_struct *prev, struct task_struct *next,
+                    bool sleep);
 
 void psi_memstall_tick(struct task_struct *task, int cpu);
 void psi_memstall_enter(unsigned long *flags);
index 07aaf9b..4b72584 100644 (file)
@@ -14,13 +14,21 @@ enum psi_task_count {
        NR_IOWAIT,
        NR_MEMSTALL,
        NR_RUNNING,
-       NR_PSI_TASK_COUNTS = 3,
+       /*
+        * This can't have values other than 0 or 1 and could be
+        * implemented as a bit flag. But for now we still have room
+        * in the first cacheline of psi_group_cpu, and this way we
+        * don't have to special case any state tracking for it.
+        */
+       NR_ONCPU,
+       NR_PSI_TASK_COUNTS = 4,
 };
 
 /* Task state bitmasks */
 #define TSK_IOWAIT     (1 << NR_IOWAIT)
 #define TSK_MEMSTALL   (1 << NR_MEMSTALL)
 #define TSK_RUNNING    (1 << NR_RUNNING)
+#define TSK_ONCPU      (1 << NR_ONCPU)
 
 /* Resources that workloads could be stalled on */
 enum psi_res {
diff --git a/include/linux/raid/detect.h b/include/linux/raid/detect.h
new file mode 100644 (file)
index 0000000..37dd3f4
--- /dev/null
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+void md_autodetect_dev(dev_t dev);
index 9f313e4..8214cdc 100644 (file)
@@ -60,9 +60,9 @@ static inline void INIT_LIST_HEAD_RCU(struct list_head *list)
 #define __list_check_rcu(dummy, cond, extra...)                                \
        ({                                                              \
        check_arg_count_one(extra);                                     \
-       RCU_LOCKDEP_WARN(!cond && !rcu_read_lock_any_held(),            \
+       RCU_LOCKDEP_WARN(!(cond) && !rcu_read_lock_any_held(),          \
                         "RCU-list traversed in non-reader section!");  \
-        })
+       })
 #else
 #define __list_check_rcu(dummy, cond, extra...)                                \
        ({ check_arg_count_one(extra); })
index b2b2dc9..045c28b 100644 (file)
@@ -83,6 +83,7 @@ void rcu_scheduler_starting(void);
 static inline void rcu_scheduler_starting(void) { }
 #endif /* #else #ifndef CONFIG_SRCU */
 static inline void rcu_end_inkernel_boot(void) { }
+static inline bool rcu_inkernel_boot_has_ended(void) { return true; }
 static inline bool rcu_is_watching(void) { return true; }
 static inline void rcu_momentary_dyntick_idle(void) { }
 static inline void kfree_rcu_scheduler_running(void) { }
index 2f787b9..45f3f66 100644 (file)
@@ -54,6 +54,7 @@ void exit_rcu(void);
 void rcu_scheduler_starting(void);
 extern int rcu_scheduler_active __read_mostly;
 void rcu_end_inkernel_boot(void);
+bool rcu_inkernel_boot_has_ended(void);
 bool rcu_is_watching(void);
 #ifndef CONFIG_PREEMPTION
 void rcu_all_qs(void);
index 75c97e4..2ffe1ee 100644 (file)
@@ -3,6 +3,7 @@
 #define _LINUX_RCUWAIT_H_
 
 #include <linux/rcupdate.h>
+#include <linux/sched/signal.h>
 
 /*
  * rcuwait provides a way of blocking and waking up a single
@@ -30,23 +31,30 @@ extern void rcuwait_wake_up(struct rcuwait *w);
  * The caller is responsible for locking around rcuwait_wait_event(),
  * such that writes to @task are properly serialized.
  */
-#define rcuwait_wait_event(w, condition)                               \
+#define rcuwait_wait_event(w, condition, state)                                \
 ({                                                                     \
+       int __ret = 0;                                                  \
        rcu_assign_pointer((w)->task, current);                         \
        for (;;) {                                                      \
                /*                                                      \
                 * Implicit barrier (A) pairs with (B) in               \
                 * rcuwait_wake_up().                                   \
                 */                                                     \
-               set_current_state(TASK_UNINTERRUPTIBLE);                \
+               set_current_state(state);                               \
                if (condition)                                          \
                        break;                                          \
                                                                        \
+               if (signal_pending_state(state, current)) {             \
+                       __ret = -EINTR;                                 \
+                       break;                                          \
+               }                                                       \
+                                                                       \
                schedule();                                             \
        }                                                               \
                                                                        \
        WRITE_ONCE((w)->task, NULL);                                    \
        __set_current_state(TASK_RUNNING);                              \
+       __ret;                                                          \
 })
 
 #endif /* _LINUX_RCUWAIT_H_ */
index f0a092a..40b0716 100644 (file)
@@ -461,8 +461,8 @@ struct regmap_config {
  * @range_max: Address of the highest register in virtual range.
  *
  * @selector_reg: Register with selector field.
- * @selector_mask: Bit shift for selector value.
- * @selector_shift: Bit mask for selector value.
+ * @selector_mask: Bit mask for selector value.
+ * @selector_shift: Bit shift for selector value.
  *
  * @window_start: Address of first (lowest) register in data window.
  * @window_len: Number of registers in data window.
index 9a911bb..29d9205 100644 (file)
@@ -277,9 +277,9 @@ enum regulator_type {
  * @curr_table: Current limit mapping table (if table based mapping)
  *
  * @vsel_range_reg: Register for range selector when using pickable ranges
- *                 and regulator_regmap_X_voltage_X_pickable functions.
+ *                 and ``regulator_map_*_voltage_*_pickable`` functions.
  * @vsel_range_mask: Mask for register bitfield used for range selector
- * @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
+ * @vsel_reg: Register for selector when using ``regulator_map_*_voltage_*``
  * @vsel_mask: Mask for register bitfield used for selector
  * @vsel_step: Specify the resolution of selector stepping when setting
  *            voltage. If 0, then no stepping is done (requested selector is
index beb9a9d..70ebef8 100644 (file)
@@ -972,9 +972,9 @@ static inline int rhashtable_lookup_insert_key(
 /**
  * rhashtable_lookup_get_insert_key - lookup and insert object into hash table
  * @ht:                hash table
+ * @key:       key
  * @obj:       pointer to hash head inside object
  * @params:    hash table parameters
- * @data:      pointer to element data already in hashes
  *
  * Just like rhashtable_lookup_insert_key(), but this function returns the
  * object if it exists, NULL if it does not and the insertion was successful,
index 857a72c..3bd03e1 100644 (file)
@@ -22,7 +22,11 @@ typedef struct {
 #define RWLOCK_MAGIC           0xdeaf1eed
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define RW_DEP_MAP_INIT(lockname)     .dep_map = { .name = #lockname }
+# define RW_DEP_MAP_INIT(lockname)                                     \
+       .dep_map = {                                                    \
+               .name = #lockname,                                      \
+               .wait_type_inner = LD_WAIT_CONFIG,                      \
+       }
 #else
 # define RW_DEP_MAP_INIT(lockname)
 #endif
index 00d6054..7e5b2a4 100644 (file)
@@ -53,12 +53,6 @@ struct rw_semaphore {
 #endif
 };
 
-/*
- * Setting all bits of the owner field except bit 0 will indicate
- * that the rwsem is writer-owned with an unknown owner.
- */
-#define RWSEM_OWNER_UNKNOWN    (-2L)
-
 /* In all implementations count != 0 means locked */
 static inline int rwsem_is_locked(struct rw_semaphore *sem)
 {
@@ -71,7 +65,11 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem)
 /* Common initializer macros and functions */
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
+# define __RWSEM_DEP_MAP_INIT(lockname)                        \
+       , .dep_map = {                                  \
+               .name = #lockname,                      \
+               .wait_type_inner = LD_WAIT_SLEEP,       \
+       }
 #else
 # define __RWSEM_DEP_MAP_INIT(lockname)
 #endif
index 0427849..5d0d2fc 100644 (file)
@@ -356,28 +356,30 @@ struct util_est {
 } __attribute__((__aligned__(sizeof(u64))));
 
 /*
- * The load_avg/util_avg accumulates an infinite geometric series
- * (see __update_load_avg() in kernel/sched/fair.c).
+ * The load/runnable/util_avg accumulates an infinite geometric series
+ * (see __update_load_avg_cfs_rq() in kernel/sched/pelt.c).
  *
  * [load_avg definition]
  *
  *   load_avg = runnable% * scale_load_down(load)
  *
- * where runnable% is the time ratio that a sched_entity is runnable.
- * For cfs_rq, it is the aggregated load_avg of all runnable and
- * blocked sched_entities.
+ * [runnable_avg definition]
+ *
+ *   runnable_avg = runnable% * SCHED_CAPACITY_SCALE
  *
  * [util_avg definition]
  *
  *   util_avg = running% * SCHED_CAPACITY_SCALE
  *
- * where running% is the time ratio that a sched_entity is running on
- * a CPU. For cfs_rq, it is the aggregated util_avg of all runnable
- * and blocked sched_entities.
+ * where runnable% is the time ratio that a sched_entity is runnable and
+ * running% the time ratio that a sched_entity is running.
+ *
+ * For cfs_rq, they are the aggregated values of all runnable and blocked
+ * sched_entities.
  *
- * load_avg and util_avg don't direcly factor frequency scaling and CPU
- * capacity scaling. The scaling is done through the rq_clock_pelt that
- * is used for computing those signals (see update_rq_clock_pelt())
+ * The load/runnable/util_avg doesn't direcly factor frequency scaling and CPU
+ * capacity scaling. The scaling is done through the rq_clock_pelt that is used
+ * for computing those signals (see update_rq_clock_pelt())
  *
  * N.B., the above ratios (runnable% and running%) themselves are in the
  * range of [0, 1]. To do fixed point arithmetics, we therefore scale them
@@ -401,11 +403,11 @@ struct util_est {
 struct sched_avg {
        u64                             last_update_time;
        u64                             load_sum;
-       u64                             runnable_load_sum;
+       u64                             runnable_sum;
        u32                             util_sum;
        u32                             period_contrib;
        unsigned long                   load_avg;
-       unsigned long                   runnable_load_avg;
+       unsigned long                   runnable_avg;
        unsigned long                   util_avg;
        struct util_est                 util_est;
 } ____cacheline_aligned;
@@ -449,7 +451,6 @@ struct sched_statistics {
 struct sched_entity {
        /* For load-balancing: */
        struct load_weight              load;
-       unsigned long                   runnable_weight;
        struct rb_node                  run_node;
        struct list_head                group_node;
        unsigned int                    on_rq;
@@ -470,6 +471,8 @@ struct sched_entity {
        struct cfs_rq                   *cfs_rq;
        /* rq "owned" by this entity/group: */
        struct cfs_rq                   *my_q;
+       /* cached value of my_q->h_nr_running */
+       unsigned long                   runnable_weight;
 #endif
 
 #ifdef CONFIG_SMP
@@ -782,9 +785,12 @@ struct task_struct {
        unsigned                        frozen:1;
 #endif
 #ifdef CONFIG_BLK_CGROUP
-       /* to be used once the psi infrastructure lands upstream. */
        unsigned                        use_memdelay:1;
 #endif
+#ifdef CONFIG_PSI
+       /* Stalled due to lack of memory */
+       unsigned                        in_memstall:1;
+#endif
 
        unsigned long                   atomic_flags; /* Flags requiring atomic access. */
 
@@ -970,6 +976,7 @@ struct task_struct {
 
 #ifdef CONFIG_TRACE_IRQFLAGS
        unsigned int                    irq_events;
+       unsigned int                    hardirq_threaded;
        unsigned long                   hardirq_enable_ip;
        unsigned long                   hardirq_disable_ip;
        unsigned int                    hardirq_enable_event;
@@ -982,6 +989,7 @@ struct task_struct {
        unsigned int                    softirq_enable_event;
        int                             softirqs_enabled;
        int                             softirq_context;
+       int                             irq_config;
 #endif
 
 #ifdef CONFIG_LOCKDEP
@@ -1477,7 +1485,6 @@ extern struct pid *cad_pid;
 #define PF_KTHREAD             0x00200000      /* I am a kernel thread */
 #define PF_RANDOMIZE           0x00400000      /* Randomize virtual address space */
 #define PF_SWAPWRITE           0x00800000      /* Allowed to write to swap */
-#define PF_MEMSTALL            0x01000000      /* Stalled due to lack of memory */
 #define PF_UMH                 0x02000000      /* I'm an Usermodehelper process */
 #define PF_NO_SETAFFINITY      0x04000000      /* Userland is not allowed to meddle with cpus_mask */
 #define PF_MCE_EARLY           0x08000000      /* Early kill for mce process policy */
index f341163..af9319e 100644 (file)
@@ -225,6 +225,14 @@ unsigned long arch_scale_cpu_capacity(int cpu)
 }
 #endif
 
+#ifndef arch_scale_thermal_pressure
+static __always_inline
+unsigned long arch_scale_thermal_pressure(int cpu)
+{
+       return 0;
+}
+#endif
+
 static inline int task_node(const struct task_struct *p)
 {
        return cpu_to_node(task_cpu(p));
index 03583b6..4192369 100644 (file)
@@ -7,7 +7,8 @@
 #define SECCOMP_FILTER_FLAG_MASK       (SECCOMP_FILTER_FLAG_TSYNC | \
                                         SECCOMP_FILTER_FLAG_LOG | \
                                         SECCOMP_FILTER_FLAG_SPEC_ALLOW | \
-                                        SECCOMP_FILTER_FLAG_NEW_LISTENER)
+                                        SECCOMP_FILTER_FLAG_NEW_LISTENER | \
+                                        SECCOMP_FILTER_FLAG_TSYNC_ESRCH)
 
 #ifdef CONFIG_SECCOMP
 
index 5b50278..e596202 100644 (file)
@@ -645,8 +645,8 @@ typedef unsigned char *sk_buff_data_t;
  *     @offload_l3_fwd_mark: Packet was L3-forwarded in hardware
  *     @tc_skip_classify: do not classify packet. set by IFB device
  *     @tc_at_ingress: used within tc_classify to distinguish in/egress
- *     @tc_redirected: packet was redirected by a tc action
- *     @tc_from_ingress: if tc_redirected, tc_at_ingress at time of redirect
+ *     @redirected: packet was redirected by packet classifier
+ *     @from_ingress: packet was redirected from the ingress path
  *     @peeked: this packet has been seen already, so stats have been
  *             done for it, don't do them again
  *     @nf_trace: netfilter packet trace flag
@@ -848,8 +848,10 @@ struct sk_buff {
 #ifdef CONFIG_NET_CLS_ACT
        __u8                    tc_skip_classify:1;
        __u8                    tc_at_ingress:1;
-       __u8                    tc_redirected:1;
-       __u8                    tc_from_ingress:1;
+#endif
+#ifdef CONFIG_NET_REDIRECT
+       __u8                    redirected:1;
+       __u8                    from_ingress:1;
 #endif
 #ifdef CONFIG_TLS_DEVICE
        __u8                    decrypted:1;
@@ -4579,5 +4581,31 @@ static inline __wsum lco_csum(struct sk_buff *skb)
        return csum_partial(l4_hdr, csum_start - l4_hdr, partial);
 }
 
+static inline bool skb_is_redirected(const struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_REDIRECT
+       return skb->redirected;
+#else
+       return false;
+#endif
+}
+
+static inline void skb_set_redirected(struct sk_buff *skb, bool from_ingress)
+{
+#ifdef CONFIG_NET_REDIRECT
+       skb->redirected = 1;
+       skb->from_ingress = from_ingress;
+       if (skb->from_ingress)
+               skb->tstamp = 0;
+#endif
+}
+
+static inline void skb_reset_redirect(struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_REDIRECT
+       skb->redirected = 0;
+#endif
+}
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SKBUFF_H */
index 9e4fdd8..da304ce 100644 (file)
@@ -10,6 +10,7 @@ struct qcom_smd_rpm;
 /*
  * Constants used for addressing resources in the RPM.
  */
+#define QCOM_SMD_RPM_BBYB      0x62796262
 #define QCOM_SMD_RPM_BOBB      0x62626f62
 #define QCOM_SMD_RPM_BOOST     0x61747362
 #define QCOM_SMD_RPM_BUS_CLK   0x316b6c63
index 2d23134..54338fa 100644 (file)
@@ -391,6 +391,10 @@ extern int recvmsg_copy_msghdr(struct msghdr *msg,
                               struct user_msghdr __user *umsg, unsigned flags,
                               struct sockaddr __user **uaddr,
                               struct iovec **iov);
+extern int __copy_msghdr_from_user(struct msghdr *kmsg,
+                                  struct user_msghdr __user *umsg,
+                                  struct sockaddr __user **save_addr,
+                                  struct iovec __user **uiov, size_t *nsegs);
 
 /* helpers which do the actual work for syscalls */
 extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size,
@@ -401,7 +405,8 @@ extern int __sys_sendto(int fd, void __user *buff, size_t len,
                        int addr_len);
 extern int __sys_accept4_file(struct file *file, unsigned file_flags,
                        struct sockaddr __user *upeer_sockaddr,
-                        int __user *upeer_addrlen, int flags);
+                        int __user *upeer_addrlen, int flags,
+                        unsigned long nofile);
 extern int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
                         int __user *upeer_addrlen, int flags);
 extern int __sys_socket(int family, int type, int protocol);
index 6d16ba0..38286de 100644 (file)
@@ -135,6 +135,8 @@ extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
  * @modalias: Name of the driver to use with this device, or an alias
  *     for that name.  This appears in the sysfs "modalias" attribute
  *     for driver coldplugging, and in uevents used for hotplugging
+ * @driver_override: If the name of a driver is written to this attribute, then
+ *     the device will bind to the named driver and only the named driver.
  * @cs_gpio: LEGACY: gpio number of the chipselect line (optional, -ENOENT when
  *     not using a GPIO line) use cs_gpiod in new drivers by opting in on
  *     the spi_master.
@@ -443,6 +445,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  *     @spi_transfer->ptp_sts_word_post were transmitted.
  *     If the driver does not set this, the SPI core takes the snapshot as
  *     close to the driver hand-over as possible.
+ * @irq_flags: Interrupt enable state during PTP system timestamping
  *
  * Each SPI controller can communicate with one or more @spi_device
  * children.  These make a small bus, sharing MOSI, MISO and SCK signals
@@ -481,6 +484,9 @@ struct spi_controller {
        /* spi_device.mode flags understood by this controller driver */
        u32                     mode_bits;
 
+       /* spi_device.mode flags override flags for this controller */
+       u32                     buswidth_override_bits;
+
        /* bitmask of supported bits_per_word for transfers */
        u32                     bits_per_word_mask;
 #define SPI_BPW_MASK(bits) BIT((bits) - 1)
@@ -930,8 +936,7 @@ struct spi_transfer {
 
        struct ptp_system_timestamp *ptp_sts;
 
-       bool            timestamped_pre;
-       bool            timestamped_post;
+       bool            timestamped;
 
        struct list_head transfer_list;
 };
index 031ce86..d3770b3 100644 (file)
 
 #ifdef CONFIG_DEBUG_SPINLOCK
   extern void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
-                                  struct lock_class_key *key);
-# define raw_spin_lock_init(lock)                              \
-do {                                                           \
-       static struct lock_class_key __key;                     \
-                                                               \
-       __raw_spin_lock_init((lock), #lock, &__key);            \
+                                  struct lock_class_key *key, short inner);
+
+# define raw_spin_lock_init(lock)                                      \
+do {                                                                   \
+       static struct lock_class_key __key;                             \
+                                                                       \
+       __raw_spin_lock_init((lock), #lock, &__key, LD_WAIT_SPIN);      \
 } while (0)
 
 #else
@@ -327,12 +328,26 @@ static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock)
        return &lock->rlock;
 }
 
-#define spin_lock_init(_lock)                          \
-do {                                                   \
-       spinlock_check(_lock);                          \
-       raw_spin_lock_init(&(_lock)->rlock);            \
+#ifdef CONFIG_DEBUG_SPINLOCK
+
+# define spin_lock_init(lock)                                  \
+do {                                                           \
+       static struct lock_class_key __key;                     \
+                                                               \
+       __raw_spin_lock_init(spinlock_check(lock),              \
+                            #lock, &__key, LD_WAIT_CONFIG);    \
+} while (0)
+
+#else
+
+# define spin_lock_init(_lock)                 \
+do {                                           \
+       spinlock_check(_lock);                  \
+       *(_lock) = __SPIN_LOCK_UNLOCKED(_lock); \
 } while (0)
 
+#endif
+
 static __always_inline void spin_lock(spinlock_t *lock)
 {
        raw_spin_lock(&lock->rlock);
index 24b4e6f..6102e6b 100644 (file)
@@ -33,8 +33,18 @@ typedef struct raw_spinlock {
 #define SPINLOCK_OWNER_INIT    ((void *)-1L)
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
-# define SPIN_DEP_MAP_INIT(lockname)   .dep_map = { .name = #lockname }
+# define RAW_SPIN_DEP_MAP_INIT(lockname)               \
+       .dep_map = {                                    \
+               .name = #lockname,                      \
+               .wait_type_inner = LD_WAIT_SPIN,        \
+       }
+# define SPIN_DEP_MAP_INIT(lockname)                   \
+       .dep_map = {                                    \
+               .name = #lockname,                      \
+               .wait_type_inner = LD_WAIT_CONFIG,      \
+       }
 #else
+# define RAW_SPIN_DEP_MAP_INIT(lockname)
 # define SPIN_DEP_MAP_INIT(lockname)
 #endif
 
@@ -51,7 +61,7 @@ typedef struct raw_spinlock {
        {                                       \
        .raw_lock = __ARCH_SPIN_LOCK_UNLOCKED,  \
        SPIN_DEBUG_INIT(lockname)               \
-       SPIN_DEP_MAP_INIT(lockname) }
+       RAW_SPIN_DEP_MAP_INIT(lockname) }
 
 #define __RAW_SPIN_LOCK_UNLOCKED(lockname)     \
        (raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)
@@ -72,11 +82,17 @@ typedef struct spinlock {
        };
 } spinlock_t;
 
+#define ___SPIN_LOCK_INITIALIZER(lockname)     \
+       {                                       \
+       .raw_lock = __ARCH_SPIN_LOCK_UNLOCKED,  \
+       SPIN_DEBUG_INIT(lockname)               \
+       SPIN_DEP_MAP_INIT(lockname) }
+
 #define __SPIN_LOCK_INITIALIZER(lockname) \
-       { { .rlock = __RAW_SPIN_LOCK_INITIALIZER(lockname) } }
+       { { .rlock = ___SPIN_LOCK_INITIALIZER(lockname) } }
 
 #define __SPIN_LOCK_UNLOCKED(lockname) \
-       (spinlock_t ) __SPIN_LOCK_INITIALIZER(lockname)
+       (spinlock_t) __SPIN_LOCK_INITIALIZER(lockname)
 
 #define DEFINE_SPINLOCK(x)     spinlock_t x = __SPIN_LOCK_UNLOCKED(x)
 
index 74b4911..ebbbfea 100644 (file)
@@ -78,6 +78,9 @@ extern ssize_t add_to_pipe(struct pipe_inode_info *,
                              struct pipe_buffer *);
 extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
                                      splice_direct_actor *);
+extern long do_splice(struct file *in, loff_t __user *off_in,
+                     struct file *out, loff_t __user *off_out,
+                     size_t len, unsigned int flags);
 
 /*
  * for dynamic pipe sizing
index 6b792d0..4c678c4 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/sched.h>
 #include <linux/random.h>
 
-#ifdef CONFIG_STACKPROTECTOR
+#if defined(CONFIG_STACKPROTECTOR) || defined(CONFIG_ARM64_PTR_AUTH)
 # include <asm/stackprotector.h>
 #else
 static inline void boot_init_stack_canary(void)
index 3086dba..18d5a74 100644 (file)
@@ -29,7 +29,7 @@
 
 /*
  * A maximum of 4 million PIDs should be enough for a while.
- * [NOTE: PID/TIDs are limited to 2^29 ~= 500+ million, see futex.h.]
+ * [NOTE: PID/TIDs are limited to 2^30 ~= 1 billion, see FUTEX_TID_MASK.]
  */
 #define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \
        (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))
index 8ef5e5c..4c325bf 100644 (file)
@@ -111,9 +111,6 @@ static inline bool itimerspec64_valid(const struct itimerspec64 *its)
  */
 #define time_between32(t, l, h) ((u32)(h) - (u32)(l) >= (u32)(t) - (u32)(l))
 
-struct timens_offset {
-       s64     sec;
-       u64     nsec;
-};
+# include <vdso/time.h>
 
 #endif
index cf9320c..83a400b 100644 (file)
 #include <linux/time64.h>
 #include <linux/timex.h>
 
-typedef s32            old_time32_t;
-
-struct old_timespec32 {
-       old_time32_t    tv_sec;
-       s32             tv_nsec;
-};
-
-struct old_timeval32 {
-       old_time32_t    tv_sec;
-       s32             tv_usec;
-};
+#include <vdso/time32.h>
 
 struct old_itimerspec32 {
        struct old_timespec32 it_interval;
index 1912548..c9dcb3e 100644 (file)
@@ -3,6 +3,7 @@
 #define _LINUX_TIME64_H
 
 #include <linux/math64.h>
+#include <vdso/time64.h>
 
 typedef __s64 time64_t;
 typedef __u64 timeu64_t;
@@ -19,15 +20,6 @@ struct itimerspec64 {
        struct timespec64 it_value;
 };
 
-/* Parameters used to convert the timespec values: */
-#define MSEC_PER_SEC   1000L
-#define USEC_PER_MSEC  1000L
-#define NSEC_PER_USEC  1000L
-#define NSEC_PER_MSEC  1000000L
-#define USEC_PER_SEC   1000000L
-#define NSEC_PER_SEC   1000000000L
-#define FSEC_PER_SEC   1000000000000000LL
-
 /* Located here for timespec[64]_valid_strict */
 #define TIME64_MAX                     ((s64)~((u64)1 << 63))
 #define TIME64_MIN                     (-TIME64_MAX - 1)
index 1e6650e..0dc19a8 100644 (file)
@@ -164,7 +164,7 @@ static inline void destroy_timer_on_stack(struct timer_list *timer) { }
  */
 static inline int timer_pending(const struct timer_list * timer)
 {
-       return timer->entry.pprev != NULL;
+       return !hlist_unhashed_lockless(&timer->entry);
 }
 
 extern void add_timer_on(struct timer_list *timer, int cpu);
index e656e7b..9f3c721 100644 (file)
@@ -325,7 +325,7 @@ struct usb_interface_cache {
 
        /* variable-length array of alternate settings for this interface,
         * stored in no particular order */
-       struct usb_host_interface altsetting[0];
+       struct usb_host_interface altsetting[];
 };
 #define        ref_to_usb_interface_cache(r) \
                container_of(r, struct usb_interface_cache, ref)
@@ -708,6 +708,7 @@ struct usb_device {
        unsigned lpm_disable_count;
 
        u16 hub_delay;
+       unsigned use_generic_driver:1;
 };
 #define        to_usb_device(d) container_of(d, struct usb_device, dev)
 
@@ -1228,12 +1229,16 @@ struct usb_driver {
  * @drvwrap: Driver-model core structure wrapper.
  * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
  *     for devices bound to this driver.
+ * @generic_subclass: if set to 1, the generic USB driver's probe, disconnect,
+ *     resume and suspend functions will be called in addition to the driver's
+ *     own, so this part of the setup does not need to be replicated.
  *
  * USB drivers must provide all the fields listed above except drvwrap.
  */
 struct usb_device_driver {
        const char *name;
 
+       bool (*match) (struct usb_device *udev);
        int (*probe) (struct usb_device *udev);
        void (*disconnect) (struct usb_device *udev);
 
@@ -1241,7 +1246,9 @@ struct usb_device_driver {
        int (*resume) (struct usb_device *udev, pm_message_t message);
        const struct attribute_group **dev_groups;
        struct usbdrv_wrap drvwrap;
+       const struct usb_device_id *id_table;
        unsigned int supports_autosuspend:1;
+       unsigned int generic_subclass:1;
 };
 #define        to_usb_device_driver(d) container_of(d, struct usb_device_driver, \
                drvwrap.driver)
@@ -1582,7 +1589,7 @@ struct urb {
        int error_count;                /* (return) number of ISO errors */
        void *context;                  /* (in) context for completion */
        usb_complete_t complete;        /* (in) completion routine */
-       struct usb_iso_packet_descriptor iso_frame_desc[0];
+       struct usb_iso_packet_descriptor iso_frame_desc[];
                                        /* (in) ISO ONLY */
 };
 
index ba4b3e3..5e31740 100644 (file)
@@ -153,7 +153,7 @@ struct uac2_feature_unit_descriptor {
        __u8 bSourceID;
        /* bmaControls is actually u32,
         * but u8 is needed for the hybrid parser */
-       __u8 bmaControls[0]; /* variable length */
+       __u8 bmaControls[]; /* variable length */
 } __attribute__((packed));
 
 /* 4.9.2 Class-Specific AS Interface Descriptor */
index 6b70843..c69a6f2 100644 (file)
@@ -109,7 +109,7 @@ struct uac3_feature_unit_descriptor {
        __u8 bSourceID;
        /* bmaControls is actually u32,
         * but u8 is needed for the hybrid parser */
-       __u8 bmaControls[0]; /* variable length */
+       __u8 bmaControls[]; /* variable length */
        /* wFeatureDescrStr omitted */
 } __attribute__((packed));
 
index a15ce99..78e0063 100644 (file)
@@ -151,7 +151,7 @@ struct ehci_regs {
 #define PORT_OWNER     (1<<13)         /* true: companion hc owns this port */
 #define PORT_POWER     (1<<12)         /* true: has power (see PPC) */
 #define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))       /* USB 1.1 device */
-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+#define PORT_LS_MASK   (3<<10)         /* Link status (SE0, K or J */
 /* 9 reserved */
 #define PORT_LPM       (1<<9)          /* LPM transaction */
 #define PORT_RESET     (1<<8)          /* reset port */
index 124462d..9411c08 100644 (file)
@@ -767,7 +767,7 @@ struct usb_gadget_strings {
 
 struct usb_gadget_string_container {
        struct list_head        list;
-       u8                      *stash[0];
+       u8                      *stash[];
 };
 
 /* put descriptor for string with that id into buf (buflen >= 256) */
index 712b2a6..e12105e 100644 (file)
@@ -228,7 +228,7 @@ struct usb_hcd {
        /* The HC driver's private data is stored at the end of
         * this structure.
         */
-       unsigned long hcd_priv[0]
+       unsigned long hcd_priv[]
                        __attribute__ ((aligned(sizeof(s64))));
 };
 
index efac3af..0164fed 100644 (file)
@@ -13,8 +13,9 @@ enum usb_role {
        USB_ROLE_DEVICE,
 };
 
-typedef int (*usb_role_switch_set_t)(struct device *dev, enum usb_role role);
-typedef enum usb_role (*usb_role_switch_get_t)(struct device *dev);
+typedef int (*usb_role_switch_set_t)(struct usb_role_switch *sw,
+                                    enum usb_role role);
+typedef enum usb_role (*usb_role_switch_get_t)(struct usb_role_switch *sw);
 
 /**
  * struct usb_role_switch_desc - USB Role Switch Descriptor
@@ -25,6 +26,8 @@ typedef enum usb_role (*usb_role_switch_get_t)(struct device *dev);
  * @set: Callback for setting the role
  * @get: Callback for getting the role (optional)
  * @allow_userspace_control: If true userspace may change the role through sysfs
+ * @driver_data: Private data pointer
+ * @name: Name for the switch (optional)
  *
  * @usb2_port and @usb3_port will point to the USB host port and @udc to the USB
  * device controller behind the USB connector with the role switch. If
@@ -40,6 +43,8 @@ struct usb_role_switch_desc {
        usb_role_switch_set_t set;
        usb_role_switch_get_t get;
        bool allow_userspace_control;
+       void *driver_data;
+       const char *name;
 };
 
 
@@ -57,6 +62,9 @@ struct usb_role_switch *
 usb_role_switch_register(struct device *parent,
                         const struct usb_role_switch_desc *desc);
 void usb_role_switch_unregister(struct usb_role_switch *sw);
+
+void usb_role_switch_set_drvdata(struct usb_role_switch *sw, void *data);
+void *usb_role_switch_get_drvdata(struct usb_role_switch *sw);
 #else
 static inline int usb_role_switch_set_role(struct usb_role_switch *sw,
                enum usb_role role)
@@ -90,6 +98,17 @@ usb_role_switch_register(struct device *parent,
 }
 
 static inline void usb_role_switch_unregister(struct usb_role_switch *sw) { }
+
+static inline void
+usb_role_switch_set_drvdata(struct usb_role_switch *sw, void *data)
+{
+}
+
+static inline void *usb_role_switch_get_drvdata(struct usb_role_switch *sw)
+{
+       return NULL;
+}
+
 #endif
 
 #endif /* __LINUX_USB_ROLE_H */
index c358b3f..b00a264 100644 (file)
@@ -198,8 +198,6 @@ struct typec_operations {
  * @pd_revision: USB Power Delivery Specification revision if supported
  * @prefer_role: Initial role preference (DRP ports).
  * @accessory: Supported Accessory Modes
- * @sw: Cable plug orientation switch
- * @mux: Multiplexer switch for Alternate/Accessory Modes
  * @fwnode: Optional fwnode of the port
  * @driver_data: Private pointer for driver specific info
  * @ops: Port operations vector
@@ -213,6 +211,7 @@ struct typec_capability {
        u16                     pd_revision; /* 0300H = "3.0" */
        int                     prefer_role;
        enum typec_accessory    accessory[TYPEC_MAX_ACCESSORY];
+       unsigned int            orientation_aware:1;
 
        struct fwnode_handle    *fwnode;
        void                    *driver_data;
index 923ff3a..d834e23 100644 (file)
@@ -126,13 +126,6 @@ void typec_altmode_put_plug(struct typec_altmode *plug);
 struct typec_altmode *typec_match_altmode(struct typec_altmode **altmodes,
                                          size_t n, u16 svid, u8 mode);
 
-struct typec_altmode *
-typec_altmode_register_notifier(struct device *dev, u16 svid, u8 mode,
-                               struct notifier_block *nb);
-
-void typec_altmode_unregister_notifier(struct typec_altmode *adev,
-                                      struct notifier_block *nb);
-
 /**
  * typec_altmode_get_orientation - Get cable plug orientation
  * altmode: Handle to the alternate mode
index be7292c..a9d9957 100644 (file)
@@ -3,6 +3,7 @@
 #ifndef __USB_TYPEC_MUX
 #define __USB_TYPEC_MUX
 
+#include <linux/property.h>
 #include <linux/usb/typec.h>
 
 struct device;
@@ -17,11 +18,20 @@ typedef int (*typec_switch_set_fn_t)(struct typec_switch *sw,
 struct typec_switch_desc {
        struct fwnode_handle *fwnode;
        typec_switch_set_fn_t set;
+       const char *name;
        void *drvdata;
 };
 
-struct typec_switch *typec_switch_get(struct device *dev);
+struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode);
 void typec_switch_put(struct typec_switch *sw);
+int typec_switch_set(struct typec_switch *sw,
+                    enum typec_orientation orientation);
+
+static inline struct typec_switch *typec_switch_get(struct device *dev)
+{
+       return fwnode_typec_switch_get(dev_fwnode(dev));
+}
+
 struct typec_switch *
 typec_switch_register(struct device *parent,
                      const struct typec_switch_desc *desc);
@@ -42,12 +52,21 @@ typedef int (*typec_mux_set_fn_t)(struct typec_mux *mux,
 struct typec_mux_desc {
        struct fwnode_handle *fwnode;
        typec_mux_set_fn_t set;
+       const char *name;
        void *drvdata;
 };
 
-struct typec_mux *
-typec_mux_get(struct device *dev, const struct typec_altmode_desc *desc);
+struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode,
+                                      const struct typec_altmode_desc *desc);
 void typec_mux_put(struct typec_mux *mux);
+int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state);
+
+static inline struct typec_mux *
+typec_mux_get(struct device *dev, const struct typec_altmode_desc *desc)
+{
+       return fwnode_typec_mux_get(dev_fwnode(dev), desc);
+}
+
 struct typec_mux *
 typec_mux_register(struct device *parent, const struct typec_mux_desc *desc);
 void typec_mux_unregister(struct typec_mux *mux);
diff --git a/include/linux/usb/typec_tbt.h b/include/linux/usb/typec_tbt.h
new file mode 100644 (file)
index 0000000..47c2d50
--- /dev/null
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __USB_TYPEC_TBT_H
+#define __USB_TYPEC_TBT_H
+
+#include <linux/usb/typec_altmode.h>
+
+#define USB_TYPEC_VENDOR_INTEL         0x8087
+/* Alias for convenience */
+#define USB_TYPEC_TBT_SID              USB_TYPEC_VENDOR_INTEL
+
+/* Connector state for Thunderbolt3 */
+#define TYPEC_TBT_MODE                 TYPEC_STATE_MODAL
+
+/**
+ * struct typec_thunderbolt_data - Thundebolt3 Alt Mode specific data
+ * @device_mode: Device Discover Mode VDO
+ * @cable_mode: Cable Discover Mode VDO
+ * @enter_vdo: Enter Mode VDO
+ */
+struct typec_thunderbolt_data {
+       u32 device_mode;
+       u32 cable_mode;
+       u32 enter_vdo;
+};
+
+/* TBT3 Device Discover Mode VDO bits */
+#define TBT_MODE                       BIT(0)
+#define TBT_ADAPTER(_vdo_)             (((_vdo_) & BIT(16)) >> 16)
+#define   TBT_ADAPTER_LEGACY           0
+#define   TBT_ADAPTER_TBT3             1
+#define TBT_INTEL_SPECIFIC_B0          BIT(26)
+#define TBT_VENDOR_SPECIFIC_B0         BIT(30)
+#define TBT_VENDOR_SPECIFIC_B1         BIT(31)
+
+#define TBT_SET_ADAPTER(a)             (((a) & 1) << 16)
+
+/* TBT3 Cable Discover Mode VDO bits */
+#define TBT_CABLE_SPEED(_vdo_)         (((_vdo_) & GENMASK(18, 16)) >> 16)
+#define   TBT_CABLE_USB3_GEN1          1
+#define   TBT_CABLE_USB3_PASSIVE       2
+#define   TBT_CABLE_10_AND_20GBPS      3
+#define TBT_CABLE_ROUNDED              BIT(19)
+#define TBT_CABLE_OPTICAL              BIT(21)
+#define TBT_CABLE_RETIMER              BIT(22)
+#define TBT_CABLE_LINK_TRAINING                BIT(23)
+
+#define TBT_SET_CABLE_SPEED(_s_)       (((_s_) & GENMASK(2, 0)) << 16)
+
+/* TBT3 Device Enter Mode VDO bits */
+#define TBT_ENTER_MODE_CABLE_SPEED(s)  TBT_SET_CABLE_SPEED(s)
+#define TBT_ENTER_MODE_ACTIVE_CABLE    BIT(24)
+
+#endif /* __USB_TYPEC_TBT_H */
index 000a595..4a19ac3 100644 (file)
@@ -92,6 +92,6 @@ enum { US_DO_ALL_FLAGS };
 #include <linux/usb/storage.h>
 
 extern int usb_usual_ignore_device(struct usb_interface *intf);
-extern struct usb_device_id usb_storage_usb_ids[];
+extern const struct usb_device_id usb_storage_usb_ids[];
 
 #endif /* __LINUX_USB_USUAL_H */
index 79aab00..14ea197 100644 (file)
@@ -69,7 +69,7 @@ struct usbdevfs_urb32 {
        compat_int_t error_count;
        compat_uint_t signr;
        compat_caddr_t usercontext; /* unused */
-       struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+       struct usbdevfs_iso_packet_desc iso_frame_desc[];
 };
 
 struct usbdevfs_ioctl32 {
index ec38132..0507a16 100644 (file)
@@ -141,8 +141,9 @@ extern int remap_vmalloc_range_partial(struct vm_area_struct *vma,
 
 extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
                                                        unsigned long pgoff);
-void vmalloc_sync_all(void);
+void vmalloc_sync_mappings(void);
+void vmalloc_sync_unmappings(void);
+
 /*
  *     Lowlevel-APIs (not for driver use!)
  */
index 3283c8d..feeb6be 100644 (file)
@@ -20,6 +20,7 @@ int default_wake_function(struct wait_queue_entry *wq_entry, unsigned mode, int
 #define WQ_FLAG_EXCLUSIVE      0x01
 #define WQ_FLAG_WOKEN          0x02
 #define WQ_FLAG_BOOKMARK       0x04
+#define WQ_FLAG_CUSTOM         0x08
 
 /*
  * A single wait-queue entry structure:
index 4261d1c..e48554e 100644 (file)
@@ -487,6 +487,19 @@ extern void wq_worker_comm(char *buf, size_t size, struct task_struct *task);
  *
  * We queue the work to the CPU on which it was submitted, but if the CPU dies
  * it can be processed by another CPU.
+ *
+ * Memory-ordering properties:  If it returns %true, guarantees that all stores
+ * preceding the call to queue_work() in the program order will be visible from
+ * the CPU which will execute @work by the time such work executes, e.g.,
+ *
+ * { x is initially 0 }
+ *
+ *   CPU0                              CPU1
+ *
+ *   WRITE_ONCE(x, 1);                 [ @work is being executed ]
+ *   r0 = queue_work(wq, work);                  r1 = READ_ONCE(x);
+ *
+ * Forbids: r0 == true && r1 == 0
  */
 static inline bool queue_work(struct workqueue_struct *wq,
                              struct work_struct *work)
@@ -546,6 +559,9 @@ static inline bool schedule_work_on(int cpu, struct work_struct *work)
  * This puts a job in the kernel-global workqueue if it was not already
  * queued and leaves it in the same position on the kernel-global
  * workqueue otherwise.
+ *
+ * Shares the same memory-ordering properties of queue_work(), cf. the
+ * DocBook header of queue_work().
  */
 static inline bool schedule_work(struct work_struct *work)
 {
index 63fbba0..e2e4de1 100644 (file)
@@ -41,13 +41,6 @@ struct zorro_dev {
 
 
     /*
-     *  Zorro bus
-     */
-
-extern struct bus_type zorro_bus_type;
-
-
-    /*
      *  Zorro device drivers
      */
 
@@ -70,11 +63,6 @@ struct zorro_driver {
 /* New-style probing */
 extern int zorro_register_driver(struct zorro_driver *);
 extern void zorro_unregister_driver(struct zorro_driver *);
-extern const struct zorro_device_id *zorro_match_device(const struct zorro_device_id *ids, const struct zorro_dev *z);
-static inline struct zorro_driver *zorro_dev_driver(const struct zorro_dev *z)
-{
-    return z->driver;
-}
 
 
 extern unsigned int zorro_num_autocon; /* # of autoconfig devices found */
index 139e93b..3895696 100644 (file)
@@ -20,31 +20,14 @@ struct cec_notifier;
 #if IS_REACHABLE(CONFIG_CEC_CORE) && IS_ENABLED(CONFIG_CEC_NOTIFIER)
 
 /**
- * cec_notifier_get_conn - find or create a new cec_notifier for the given
- * device and connector tuple.
- * @dev: device that sends the events.
- * @conn: the connector name from which the event occurs
- *
- * If a notifier for device @dev already exists, then increase the refcount
- * and return that notifier.
- *
- * If it doesn't exist, then allocate a new notifier struct and return a
- * pointer to that new struct.
- *
- * Return NULL if the memory could not be allocated.
- */
-struct cec_notifier *cec_notifier_get_conn(struct device *dev,
-                                          const char *conn);
-
-/**
  * cec_notifier_conn_register - find or create a new cec_notifier for the given
  * HDMI device and connector tuple.
  * @hdmi_dev: HDMI device that sends the events.
- * @conn_name: the connector name from which the event occurs. May be NULL
+ * @port_name: the connector name from which the event occurs. May be NULL
  * if there is always only one HDMI connector created by the HDMI device.
  * @conn_info: the connector info from which the event occurs (may be NULL)
  *
- * If a notifier for device @dev and connector @conn_name already exists, then
+ * If a notifier for device @dev and connector @port_name already exists, then
  * increase the refcount and return that notifier.
  *
  * If it doesn't exist, then allocate a new notifier struct and return a
@@ -53,7 +36,7 @@ struct cec_notifier *cec_notifier_get_conn(struct device *dev,
  * Return NULL if the memory could not be allocated.
  */
 struct cec_notifier *
-cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name,
+cec_notifier_conn_register(struct device *hdmi_dev, const char *port_name,
                           const struct cec_connector_info *conn_info);
 
 /**
@@ -67,11 +50,11 @@ void cec_notifier_conn_unregister(struct cec_notifier *n);
  * cec_notifier_cec_adap_register - find or create a new cec_notifier for the
  * given device.
  * @hdmi_dev: HDMI device that sends the events.
- * @conn_name: the connector name from which the event occurs. May be NULL
+ * @port_name: the connector name from which the event occurs. May be NULL
  * if there is always only one HDMI connector created by the HDMI device.
  * @adap: the cec adapter that registered this notifier.
  *
- * If a notifier for device @dev and connector @conn_name already exists, then
+ * If a notifier for device @dev and connector @port_name already exists, then
  * increase the refcount and return that notifier.
  *
  * If it doesn't exist, then allocate a new notifier struct and return a
@@ -80,7 +63,7 @@ void cec_notifier_conn_unregister(struct cec_notifier *n);
  * Return NULL if the memory could not be allocated.
  */
 struct cec_notifier *
-cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name,
+cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *port_name,
                               struct cec_adapter *adap);
 
 /**
@@ -125,15 +108,9 @@ void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n,
 struct device *cec_notifier_parse_hdmi_phandle(struct device *dev);
 
 #else
-static inline struct cec_notifier *cec_notifier_get_conn(struct device *dev,
-                                                        const char *conn)
-{
-       /* A non-NULL pointer is expected on success */
-       return (struct cec_notifier *)0xdeadfeed;
-}
 
 static inline struct cec_notifier *
-cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name,
+cec_notifier_conn_register(struct device *hdmi_dev, const char *port_name,
                           const struct cec_connector_info *conn_info)
 {
        /* A non-NULL pointer is expected on success */
@@ -145,7 +122,7 @@ static inline void cec_notifier_conn_unregister(struct cec_notifier *n)
 }
 
 static inline struct cec_notifier *
-cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name,
+cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *port_name,
                               struct cec_adapter *adap)
 {
        /* A non-NULL pointer is expected on success */
index e877bf1..1c6ff7d 100644 (file)
@@ -185,6 +185,8 @@ struct v4l2_ctrl_h264_slice_params {
 #define V4L2_H264_DPB_ENTRY_FLAG_VALID         0x01
 #define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE                0x02
 #define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM     0x04
+#define V4L2_H264_DPB_ENTRY_FLAG_FIELD         0x08
+#define V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD  0x10
 
 struct v4l2_h264_dpb_entry {
        __u64 reference_ts;
diff --git a/include/media/i2c/smiapp.h b/include/media/i2c/smiapp.h
deleted file mode 100644 (file)
index 80f8251..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * include/media/i2c/smiapp.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@iki.fi>
- */
-
-#ifndef __SMIAPP_H_
-#define __SMIAPP_H_
-
-#include <media/v4l2-subdev.h>
-
-#define SMIAPP_NAME            "smiapp"
-
-#define SMIAPP_DFL_I2C_ADDR    (0x20 >> 1) /* Default I2C Address */
-#define SMIAPP_ALT_I2C_ADDR    (0x6e >> 1) /* Alternate I2C Address */
-
-#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK     0
-#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE    1
-#define SMIAPP_CSI_SIGNALLING_MODE_CSI2                        2
-
-/*
- * Sometimes due to board layout considerations the camera module can be
- * mounted rotated. The typical rotation used is 180 degrees which can be
- * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
- * FIXME: rotation also changes the bayer pattern.
- */
-enum smiapp_module_board_orient {
-       SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
-       SMIAPP_MODULE_BOARD_ORIENT_180,
-};
-
-struct smiapp_flash_strobe_parms {
-       u8 mode;
-       u32 strobe_width_high_us;
-       u16 strobe_delay;
-       u16 stobe_start_point;
-       u8 trigger;
-};
-
-struct smiapp_hwconfig {
-       /*
-        * Change the cci address if i2c_addr_alt is set.
-        * Both default and alternate cci addr need to be present
-        */
-       unsigned short i2c_addr_dfl;    /* Default i2c addr */
-       unsigned short i2c_addr_alt;    /* Alternate i2c addr */
-
-       uint32_t ext_clk;               /* sensor external clk */
-
-       unsigned int lanes;             /* Number of CSI-2 lanes */
-       uint32_t csi_signalling_mode;   /* SMIAPP_CSI_SIGNALLING_MODE_* */
-       uint64_t *op_sys_clock;
-
-       enum smiapp_module_board_orient module_board_orient;
-
-       struct smiapp_flash_strobe_parms *strobe_setup;
-};
-
-#endif /* __SMIAPP_H_  */
index 1f695d9..d3f85df 100644 (file)
@@ -192,7 +192,7 @@ struct rc_dev {
        struct timer_list               timer_repeat;
        u32                             last_keycode;
        enum rc_proto                   last_protocol;
-       u32                             last_scancode;
+       u64                             last_scancode;
        u8                              last_toggle;
        u32                             timeout;
        u32                             min_timeout;
@@ -284,12 +284,12 @@ int devm_rc_register_device(struct device *parent, struct rc_dev *dev);
 void rc_unregister_device(struct rc_dev *dev);
 
 void rc_repeat(struct rc_dev *dev);
-void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode,
+void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u64 scancode,
                u8 toggle);
 void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol,
-                         u32 scancode, u8 toggle);
+                         u64 scancode, u8 toggle);
 void rc_keyup(struct rc_dev *dev);
-u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode);
+u32 rc_g_keycode_from_table(struct rc_dev *dev, u64 scancode);
 
 /*
  * From rc-raw.c
index f99575a..0ce896f 100644 (file)
 /**
  * struct rc_map_table - represents a scancode/keycode pair
  *
- * @scancode: scan code (u32)
+ * @scancode: scan code (u64)
  * @keycode: Linux input keycode
  */
 struct rc_map_table {
-       u32     scancode;
+       u64     scancode;
        u32     keycode;
 };
 
@@ -274,6 +274,7 @@ struct rc_map *rc_map_get(const char *name);
 #define RC_MAP_VIDEOMATE_K100            "rc-videomate-k100"
 #define RC_MAP_VIDEOMATE_S350            "rc-videomate-s350"
 #define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
+#define RC_MAP_KII_PRO                   "rc-videostrong-kii-pro"
 #define RC_MAP_WETEK_HUB                 "rc-wetek-hub"
 #define RC_MAP_WETEK_PLAY2               "rc-wetek-play2"
 #define RC_MAP_WINFAST                   "rc-winfast"
index 48531e5..4602c15 100644 (file)
@@ -24,7 +24,7 @@
 /**
  * enum vfl_devnode_type - type of V4L2 device node
  *
- * @VFL_TYPE_GRABBER:  for video input/output devices
+ * @VFL_TYPE_VIDEO:    for video input/output devices
  * @VFL_TYPE_VBI:      for vertical blank data (i.e. closed captions, teletext)
  * @VFL_TYPE_RADIO:    for radio tuners
  * @VFL_TYPE_SUBDEV:   for V4L2 subdevices
@@ -33,7 +33,7 @@
  * @VFL_TYPE_MAX:      number of VFL types, must always be last in the enum
  */
 enum vfl_devnode_type {
-       VFL_TYPE_GRABBER        = 0,
+       VFL_TYPE_VIDEO,
        VFL_TYPE_VBI,
        VFL_TYPE_RADIO,
        VFL_TYPE_SUBDEV,
index 95353ae..7c912b7 100644 (file)
@@ -240,7 +240,7 @@ static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)
  * @f: operation function that will be called if @cond matches.
  *     The operation functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Ignore any errors.
  *
@@ -265,7 +265,7 @@ static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)
  * @f: operation function that will be called if @cond matches.
  *     The operation functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Ignore any errors.
  *
@@ -293,7 +293,7 @@ static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)
  * @f: operation function that will be called if @cond matches.
  *     The operation functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Return:
  *
@@ -328,7 +328,7 @@ static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)
  * @f: operation function that will be called if @cond matches.
  *     The operation functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Return:
  *
@@ -359,7 +359,7 @@ static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)
  * @f: operation function that will be called if @cond matches.
  *     The operation functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Ignore any errors.
  *
@@ -388,7 +388,7 @@ static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)
  * @f: operation function that will be called if @cond matches.
  *     The operation functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Return:
  *
@@ -419,7 +419,7 @@ static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)
  * @f: operation function that will be called if @cond matches.
  *     The operation functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Ignore any errors.
  *
@@ -447,7 +447,7 @@ static inline bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)
  * @f: operation function that will be called if @cond matches.
  *     The operation functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Return:
  *
index f6a7bcd..dd82d6d 100644 (file)
@@ -113,14 +113,75 @@ struct v4l2_fwnode_endpoint {
  * struct v4l2_fwnode_link - a link between two endpoints
  * @local_node: pointer to device_node of this endpoint
  * @local_port: identifier of the port this endpoint belongs to
+ * @local_id: identifier of the id this endpoint belongs to
  * @remote_node: pointer to device_node of the remote endpoint
  * @remote_port: identifier of the port the remote endpoint belongs to
+ * @remote_id: identifier of the id the remote endpoint belongs to
  */
 struct v4l2_fwnode_link {
        struct fwnode_handle *local_node;
        unsigned int local_port;
+       unsigned int local_id;
        struct fwnode_handle *remote_node;
        unsigned int remote_port;
+       unsigned int remote_id;
+};
+
+/**
+ * enum v4l2_connector_type - connector type
+ * @V4L2_CONN_UNKNOWN:   unknown connector type, no V4L2 connector configuration
+ * @V4L2_CONN_COMPOSITE: analog composite connector
+ * @V4L2_CONN_SVIDEO:    analog svideo connector
+ */
+enum v4l2_connector_type {
+       V4L2_CONN_UNKNOWN,
+       V4L2_CONN_COMPOSITE,
+       V4L2_CONN_SVIDEO,
+};
+
+/**
+ * struct v4l2_connector_link - connector link data structure
+ * @head: structure to be used to add the link to the
+ *        &struct v4l2_fwnode_connector
+ * @fwnode_link: &struct v4l2_fwnode_link link between the connector and the
+ *               device the connector belongs to.
+ */
+struct v4l2_connector_link {
+       struct list_head head;
+       struct v4l2_fwnode_link fwnode_link;
+};
+
+/**
+ * struct v4l2_fwnode_connector_analog - analog connector data structure
+ * @sdtv_stds: sdtv standards this connector supports, set to V4L2_STD_ALL
+ *             if no restrictions are specified.
+ */
+struct v4l2_fwnode_connector_analog {
+       v4l2_std_id sdtv_stds;
+};
+
+/**
+ * struct v4l2_fwnode_connector - the connector data structure
+ * @name: the connector device name
+ * @label: optional connector label
+ * @type: connector type
+ * @links: list of all connector &struct v4l2_connector_link links
+ * @nr_of_links: total number of links
+ * @connector: connector configuration
+ * @connector.analog: analog connector configuration
+ *                    &struct v4l2_fwnode_connector_analog
+ */
+struct v4l2_fwnode_connector {
+       const char *name;
+       const char *label;
+       enum v4l2_connector_type type;
+       struct list_head links;
+       unsigned int nr_of_links;
+
+       union {
+               struct v4l2_fwnode_connector_analog analog;
+               /* future connectors */
+       } connector;
 };
 
 /**
@@ -234,6 +295,66 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
 
 /**
+ * v4l2_fwnode_connector_free() - free the V4L2 connector acquired memory
+ * @connector: the V4L2 connector resources of which are to be released
+ *
+ * Free all allocated memory and put all links acquired by
+ * v4l2_fwnode_connector_parse() and v4l2_fwnode_connector_add_link().
+ *
+ * It is safe to call this function with NULL argument or on a V4L2 connector
+ * the parsing of which failed.
+ */
+void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector);
+
+/**
+ * v4l2_fwnode_connector_parse() - initialize the 'struct v4l2_fwnode_connector'
+ * @fwnode: pointer to the subdev endpoint's fwnode handle where the connector
+ *         is connected to or to the connector endpoint fwnode handle.
+ * @connector: pointer to the V4L2 fwnode connector data structure
+ *
+ * Fill the &struct v4l2_fwnode_connector with the connector type, label and
+ * all &enum v4l2_connector_type specific connector data. The label is optional
+ * so it is set to %NULL if no one was found. The function initialize the links
+ * to zero. Adding links to the connector is done by calling
+ * v4l2_fwnode_connector_add_link().
+ *
+ * The memory allocated for the label must be freed when no longer needed.
+ * Freeing the memory is done by v4l2_fwnode_connector_free().
+ *
+ * Return:
+ * * %0 on success or a negative error code on failure:
+ * * %-EINVAL if @fwnode is invalid
+ * * %-ENOTCONN if connector type is unknown or connector device can't be found
+ */
+int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode,
+                               struct v4l2_fwnode_connector *connector);
+
+/**
+ * v4l2_fwnode_connector_add_link - add a link between a connector node and
+ *                                 a v4l2-subdev node.
+ * @fwnode: pointer to the subdev endpoint's fwnode handle where the connector
+ *          is connected to
+ * @connector: pointer to the V4L2 fwnode connector data structure
+ *
+ * Add a new &struct v4l2_connector_link link to the
+ * &struct v4l2_fwnode_connector connector links list. The link local_node
+ * points to the connector node, the remote_node to the host v4l2 (sub)dev.
+ *
+ * The taken references to remote_node and local_node must be dropped and the
+ * allocated memory must be freed when no longer needed. Both is done by calling
+ * v4l2_fwnode_connector_free().
+ *
+ * Return:
+ * * %0 on success or a negative error code on failure:
+ * * %-EINVAL if @fwnode or @connector is invalid or @connector type is unknown
+ * * %-ENOMEM on link memory allocation failure
+ * * %-ENOTCONN if remote connector device can't be found
+ * * %-ENOLINK if link parsing between v4l2 (sub)dev and connector fails
+ */
+int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
+                                  struct v4l2_fwnode_connector *connector);
+
+/**
  * typedef parse_endpoint_func - Driver's callback function to be called on
  *     each V4L2 fwnode endpoint.
  *
@@ -406,4 +527,26 @@ v4l2_async_register_fwnode_subdev(struct v4l2_subdev *sd,
                                  unsigned int num_ports,
                                  parse_endpoint_func parse_endpoint);
 
+/* Helper macros to access the connector links. */
+
+/** v4l2_connector_last_link - Helper macro to get the first
+ *                             &struct v4l2_fwnode_connector link
+ * @v4l2c: &struct v4l2_fwnode_connector owning the connector links
+ *
+ * This marco returns the first added &struct v4l2_connector_link connector
+ * link or @NULL if the connector has no links.
+ */
+#define v4l2_connector_first_link(v4l2c)                                      \
+       list_first_entry_or_null(&(v4l2c)->links,                              \
+                                struct v4l2_connector_link, head)
+
+/** v4l2_connector_last_link - Helper macro to get the last
+ *                             &struct v4l2_fwnode_connector link
+ * @v4l2c: &struct v4l2_fwnode_connector owning the connector links
+ *
+ * This marco returns the last &struct v4l2_connector_link added connector link.
+ */
+#define v4l2_connector_last_link(v4l2c)                                               \
+       list_last_entry(&(v4l2c)->links, struct v4l2_connector_link, head)
+
 #endif /* _V4L2_FWNODE_H */
index 3849602..5e73eb8 100644 (file)
@@ -86,23 +86,30 @@ int v4l_vb2q_enable_media_source(struct vb2_queue *q);
 
 
 /**
- * v4l2_pipeline_pm_use - Update the use count of an entity
- * @entity: The entity
- * @use: Use (1) or stop using (0) the entity
+ * v4l2_pipeline_pm_get - Increase the use count of a pipeline
+ * @entity: The root entity of a pipeline
  *
- * Update the use count of all entities in the pipeline and power entities on or
- * off accordingly.
+ * Update the use count of all entities in the pipeline and power entities on.
  *
- * This function is intended to be called in video node open (use ==
- * 1) and release (use == 0). It uses struct media_entity.use_count to
- * track the power status. The use of this function should be paired
- * with v4l2_pipeline_link_notify().
+ * This function is intended to be called in video node open. It uses
+ * struct media_entity.use_count to track the power status. The use
+ * of this function should be paired with v4l2_pipeline_link_notify().
  *
- * Return 0 on success or a negative error code on failure. Powering entities
- * off is assumed to never fail. No failure can occur when the use parameter is
- * set to 0.
+ * Return 0 on success or a negative error code on failure.
  */
-int v4l2_pipeline_pm_use(struct media_entity *entity, int use);
+int v4l2_pipeline_pm_get(struct media_entity *entity);
+
+/**
+ * v4l2_pipeline_pm_put - Decrease the use count of a pipeline
+ * @entity: The root entity of a pipeline
+ *
+ * Update the use count of all entities in the pipeline and power entities off.
+ *
+ * This function is intended to be called in video node release. It uses
+ * struct media_entity.use_count to track the power status. The use
+ * of this function should be paired with v4l2_pipeline_link_notify().
+ */
+void v4l2_pipeline_pm_put(struct media_entity *entity);
 
 
 /**
@@ -114,7 +121,7 @@ int v4l2_pipeline_pm_use(struct media_entity *entity, int use);
  * React to link management on powered pipelines by updating the use count of
  * all entities in the source and sink sides of the link. Entities are powered
  * on or off accordingly. The use of this function should be paired
- * with v4l2_pipeline_pm_use().
+ * with v4l2_pipeline_pm_{get,put}().
  *
  * Return 0 on success or a negative error code on failure. Powering entities
  * off is assumed to never fail. This function will not fail for disconnection
@@ -144,11 +151,14 @@ static inline int v4l_vb2q_enable_media_source(struct vb2_queue *q)
        return 0;
 }
 
-static inline int v4l2_pipeline_pm_use(struct media_entity *entity, int use)
+static inline int v4l2_pipeline_pm_get(struct media_entity *entity)
 {
        return 0;
 }
 
+static inline void v4l2_pipeline_pm_put(struct media_entity *entity)
+{}
+
 static inline int v4l2_pipeline_link_notify(struct media_link *link, u32 flags,
                                            unsigned int notification)
 {
index 1d85e24..98753f0 100644 (file)
@@ -80,6 +80,10 @@ struct v4l2_m2m_queue_ctx {
  *             for an existing frame. This is always true unless
  *             V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF is set, which
  *             indicates slicing support.
+ * @is_draining: indicates device is in draining phase
+ * @last_src_buf: indicate the last source buffer for draining
+ * @next_buf_last: next capture queud buffer will be tagged as last
+ * @has_stopped: indicate the device has been stopped
  * @m2m_dev: opaque pointer to the internal data to handle M2M context
  * @cap_q_ctx: Capture (output to memory) queue context
  * @out_q_ctx: Output (input from memory) queue context
@@ -98,6 +102,11 @@ struct v4l2_m2m_ctx {
 
        bool                            new_frame;
 
+       bool                            is_draining;
+       struct vb2_v4l2_buffer          *last_src_buf;
+       bool                            next_buf_last;
+       bool                            has_stopped;
+
        /* internal use only */
        struct v4l2_m2m_dev             *m2m_dev;
 
@@ -216,6 +225,86 @@ v4l2_m2m_buf_done(struct vb2_v4l2_buffer *buf, enum vb2_buffer_state state)
 }
 
 /**
+ * v4l2_m2m_clear_state() - clear encoding/decoding state
+ *
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ */
+static inline void
+v4l2_m2m_clear_state(struct v4l2_m2m_ctx *m2m_ctx)
+{
+       m2m_ctx->next_buf_last = false;
+       m2m_ctx->is_draining = false;
+       m2m_ctx->has_stopped = false;
+}
+
+/**
+ * v4l2_m2m_mark_stopped() - set current encoding/decoding state as stopped
+ *
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ */
+static inline void
+v4l2_m2m_mark_stopped(struct v4l2_m2m_ctx *m2m_ctx)
+{
+       m2m_ctx->next_buf_last = false;
+       m2m_ctx->is_draining = false;
+       m2m_ctx->has_stopped = true;
+}
+
+/**
+ * v4l2_m2m_dst_buf_is_last() - return the current encoding/decoding session
+ * draining management state of next queued capture buffer
+ *
+ * This last capture buffer should be tagged with V4L2_BUF_FLAG_LAST to notify
+ * the end of the capture session.
+ *
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ */
+static inline bool
+v4l2_m2m_dst_buf_is_last(struct v4l2_m2m_ctx *m2m_ctx)
+{
+       return m2m_ctx->is_draining && m2m_ctx->next_buf_last;
+}
+
+/**
+ * v4l2_m2m_has_stopped() - return the current encoding/decoding session
+ * stopped state
+ *
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ */
+static inline bool
+v4l2_m2m_has_stopped(struct v4l2_m2m_ctx *m2m_ctx)
+{
+       return m2m_ctx->has_stopped;
+}
+
+/**
+ * v4l2_m2m_is_last_draining_src_buf() - return the output buffer draining
+ * state in the current encoding/decoding session
+ *
+ * This will identify the last output buffer queued before a session stop
+ * was required, leading to an actual encoding/decoding session stop state
+ * in the encoding/decoding process after being processed.
+ *
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ * @vbuf: pointer to struct &v4l2_buffer
+ */
+static inline bool
+v4l2_m2m_is_last_draining_src_buf(struct v4l2_m2m_ctx *m2m_ctx,
+                                 struct vb2_v4l2_buffer *vbuf)
+{
+       return m2m_ctx->is_draining && vbuf == m2m_ctx->last_src_buf;
+}
+
+/**
+ * v4l2_m2m_last_buffer_done() - marks the buffer with LAST flag and DONE
+ *
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ * @vbuf: pointer to struct &v4l2_buffer
+ */
+void v4l2_m2m_last_buffer_done(struct v4l2_m2m_ctx *m2m_ctx,
+                              struct vb2_v4l2_buffer *vbuf);
+
+/**
  * v4l2_m2m_reqbufs() - multi-queue-aware REQBUFS multiplexer
  *
  * @file: pointer to struct &file
@@ -313,6 +402,46 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
                       enum v4l2_buf_type type);
 
 /**
+ * v4l2_m2m_update_start_streaming_state() - update the encoding/decoding
+ * session state when a start of streaming of a video queue is requested
+ *
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ * @q: queue
+ */
+void v4l2_m2m_update_start_streaming_state(struct v4l2_m2m_ctx *m2m_ctx,
+                                          struct vb2_queue *q);
+
+/**
+ * v4l2_m2m_update_stop_streaming_state() -  update the encoding/decoding
+ * session state when a stop of streaming of a video queue is requested
+ *
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ * @q: queue
+ */
+void v4l2_m2m_update_stop_streaming_state(struct v4l2_m2m_ctx *m2m_ctx,
+                                         struct vb2_queue *q);
+
+/**
+ * v4l2_m2m_encoder_cmd() - execute an encoder command
+ *
+ * @file: pointer to struct &file
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ * @ec: pointer to the encoder command
+ */
+int v4l2_m2m_encoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+                        struct v4l2_encoder_cmd *ec);
+
+/**
+ * v4l2_m2m_decoder_cmd() - execute a decoder command
+ *
+ * @file: pointer to struct &file
+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
+ * @dc: pointer to the decoder command
+ */
+int v4l2_m2m_decoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
+                        struct v4l2_decoder_cmd *dc);
+
+/**
  * v4l2_m2m_poll() - poll replacement, for destination buffers only
  *
  * @file: pointer to struct &file
@@ -704,6 +833,10 @@ int v4l2_m2m_ioctl_streamon(struct file *file, void *fh,
                                enum v4l2_buf_type type);
 int v4l2_m2m_ioctl_streamoff(struct file *file, void *fh,
                                enum v4l2_buf_type type);
+int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *fh,
+                              struct v4l2_encoder_cmd *ec);
+int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *fh,
+                              struct v4l2_decoder_cmd *dc);
 int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh,
                                   struct v4l2_encoder_cmd *ec);
 int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh,
index 761aa83..a4848de 100644 (file)
@@ -1093,7 +1093,7 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers;
  * @f: callback function to be called.
  *     The callback functions are defined in groups, according to
  *     each element at &struct v4l2_subdev_ops.
- * @args...: arguments for @f.
+ * @args: arguments for @f.
  *
  * Example: err = v4l2_subdev_call(sd, video, s_std, norm);
  */
index a2b2208..f11b965 100644 (file)
@@ -509,8 +509,11 @@ struct vb2_buf_ops {
  *             by the vb2 core.
  * @buf_struct_size: size of the driver-specific buffer structure;
  *             "0" indicates the driver doesn't want to use a custom buffer
- *             structure type. for example, ``sizeof(struct vb2_v4l2_buffer)``
- *             will be used for v4l2.
+ *             structure type. In that case a subsystem-specific struct
+ *             will be used (in the case of V4L2 that is
+ *             ``sizeof(struct vb2_v4l2_buffer)``). The first field of the
+ *             driver-specific buffer structure must be the subsystem-specific
+ *             struct (vb2_v4l2_buffer in the case of V4L2).
  * @timestamp_flags: Timestamp flags; ``V4L2_BUF_FLAG_TIMESTAMP_*`` and
  *             ``V4L2_BUF_FLAG_TSTAMP_SRC_*``
  * @gfp_flags: additional gfp flags used when allocating the buffers.
index 1abae3c..04e97ba 100644 (file)
@@ -16,6 +16,12 @@ struct sock;
 struct socket;
 struct rxrpc_call;
 
+enum rxrpc_interruptibility {
+       RXRPC_INTERRUPTIBLE,    /* Call is interruptible */
+       RXRPC_PREINTERRUPTIBLE, /* Call can be cancelled whilst waiting for a slot */
+       RXRPC_UNINTERRUPTIBLE,  /* Call should not be interruptible at all */
+};
+
 /*
  * Debug ID counter for tracing.
  */
@@ -41,7 +47,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *,
                                           gfp_t,
                                           rxrpc_notify_rx_t,
                                           bool,
-                                          bool,
+                                          enum rxrpc_interruptibility,
                                           unsigned int);
 int rxrpc_kernel_send_data(struct socket *, struct rxrpc_call *,
                           struct msghdr *, size_t,
@@ -58,9 +64,7 @@ int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,
                               rxrpc_user_attach_call_t, unsigned long, gfp_t,
                               unsigned int);
 void rxrpc_kernel_set_tx_length(struct socket *, struct rxrpc_call *, s64);
-bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *,
-                            u32 *);
-void rxrpc_kernel_probe_life(struct socket *, struct rxrpc_call *);
+bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *);
 u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *);
 bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *,
                                 ktime_t *);
index f277653..e341260 100644 (file)
@@ -38,6 +38,9 @@ struct compat_cmsghdr {
 #define compat_mmsghdr mmsghdr
 #endif /* defined(CONFIG_COMPAT) */
 
+int __get_compat_msghdr(struct msghdr *kmsg, struct compat_msghdr __user *umsg,
+                       struct sockaddr __user **save_addr, compat_uptr_t *ptr,
+                       compat_size_t *len);
 int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *,
                      struct sockaddr __user **, struct iovec **);
 struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval);
index 54e227e..a259050 100644 (file)
@@ -108,6 +108,7 @@ struct fib_rule_notifier_info {
        [FRA_OIFNAME]   = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \
        [FRA_PRIORITY]  = { .type = NLA_U32 }, \
        [FRA_FWMARK]    = { .type = NLA_U32 }, \
+       [FRA_TUN_ID]    = { .type = NLA_U64 }, \
        [FRA_FWMASK]    = { .type = NLA_U32 }, \
        [FRA_TABLE]     = { .type = NLA_U32 }, \
        [FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \
index 1512087..c30f914 100644 (file)
@@ -675,22 +675,6 @@ void __qdisc_calculate_pkt_len(struct sk_buff *skb,
                               const struct qdisc_size_table *stab);
 int skb_do_redirect(struct sk_buff *);
 
-static inline void skb_reset_tc(struct sk_buff *skb)
-{
-#ifdef CONFIG_NET_CLS_ACT
-       skb->tc_redirected = 0;
-#endif
-}
-
-static inline bool skb_is_tc_redirected(const struct sk_buff *skb)
-{
-#ifdef CONFIG_NET_CLS_ACT
-       return skb->tc_redirected;
-#else
-       return false;
-#endif
-}
-
 static inline bool skb_at_tc_ingress(const struct sk_buff *skb)
 {
 #ifdef CONFIG_NET_CLS_ACT
index 57c7292..08edd60 100644 (file)
@@ -13,8 +13,7 @@
 
 #ifndef SCSICAM_H
 #define SCSICAM_H
-extern int scsicam_bios_param (struct block_device *bdev, sector_t capacity, int *ip);
-extern int scsi_partsize(unsigned char *buf, unsigned long capacity,
-           unsigned int  *cyls, unsigned int *hds, unsigned int *secs);
-extern unsigned char *scsi_bios_ptable(struct block_device *bdev);
+int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip);
+bool scsi_partsize(struct block_device *bdev, sector_t capacity, int geom[3]);
+unsigned char *scsi_bios_ptable(struct block_device *bdev);
 #endif /* def SCSICAM_H */
index 0a50d53..7c08437 100644 (file)
@@ -74,7 +74,7 @@
 #define DEV_MAC_TAGS_CFG_TAG_ID_M                         GENMASK(31, 16)
 #define DEV_MAC_TAGS_CFG_TAG_ID_X(x)                      (((x) & GENMASK(31, 16)) >> 16)
 #define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA                 BIT(2)
-#define DEV_MAC_TAGS_CFG_PB_ENA                           BIT(1)
+#define DEV_MAC_TAGS_CFG_VLAN_DBL_AWR_ENA                 BIT(1)
 #define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA                     BIT(0)
 
 #define DEV_MAC_ADV_CHK_CFG                               0x2c
index f0e4f36..8a22666 100644 (file)
@@ -1157,7 +1157,7 @@ struct snd_soc_pcm_runtime {
             ((i) < rtd->num_codecs) && ((dai) = rtd->codec_dais[i]); \
             (i)++)
 #define for_each_rtd_codec_dai_rollback(rtd, i, dai)           \
-       for (; ((--i) >= 0) && ((dai) = rtd->codec_dais[i]);)
+       for (; (--(i) >= 0) && ((dai) = rtd->codec_dais[i]);)
 
 void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd);
 
index 564ba1b..c612cab 100644 (file)
@@ -233,7 +233,7 @@ enum afs_cb_break_reason {
        EM(afs_call_trace_get,                  "GET  ") \
        EM(afs_call_trace_put,                  "PUT  ") \
        EM(afs_call_trace_wake,                 "WAKE ") \
-       E_(afs_call_trace_work,                 "WORK ")
+       E_(afs_call_trace_work,                 "QUEUE")
 
 #define afs_server_traces \
        EM(afs_server_trace_alloc,              "ALLOC    ") \
index 27bd9e4..9f0d3b7 100644 (file)
@@ -357,6 +357,109 @@ TRACE_EVENT(io_uring_submit_sqe,
                          __entry->force_nonblock, __entry->sq_thread)
 );
 
+TRACE_EVENT(io_uring_poll_arm,
+
+       TP_PROTO(void *ctx, u8 opcode, u64 user_data, int mask, int events),
+
+       TP_ARGS(ctx, opcode, user_data, mask, events),
+
+       TP_STRUCT__entry (
+               __field(  void *,       ctx             )
+               __field(  u8,           opcode          )
+               __field(  u64,          user_data       )
+               __field(  int,          mask            )
+               __field(  int,          events          )
+       ),
+
+       TP_fast_assign(
+               __entry->ctx            = ctx;
+               __entry->opcode         = opcode;
+               __entry->user_data      = user_data;
+               __entry->mask           = mask;
+               __entry->events         = events;
+       ),
+
+       TP_printk("ring %p, op %d, data 0x%llx, mask 0x%x, events 0x%x",
+                         __entry->ctx, __entry->opcode,
+                         (unsigned long long) __entry->user_data,
+                         __entry->mask, __entry->events)
+);
+
+TRACE_EVENT(io_uring_poll_wake,
+
+       TP_PROTO(void *ctx, u8 opcode, u64 user_data, int mask),
+
+       TP_ARGS(ctx, opcode, user_data, mask),
+
+       TP_STRUCT__entry (
+               __field(  void *,       ctx             )
+               __field(  u8,           opcode          )
+               __field(  u64,          user_data       )
+               __field(  int,          mask            )
+       ),
+
+       TP_fast_assign(
+               __entry->ctx            = ctx;
+               __entry->opcode         = opcode;
+               __entry->user_data      = user_data;
+               __entry->mask           = mask;
+       ),
+
+       TP_printk("ring %p, op %d, data 0x%llx, mask 0x%x",
+                         __entry->ctx, __entry->opcode,
+                         (unsigned long long) __entry->user_data,
+                         __entry->mask)
+);
+
+TRACE_EVENT(io_uring_task_add,
+
+       TP_PROTO(void *ctx, u8 opcode, u64 user_data, int mask),
+
+       TP_ARGS(ctx, opcode, user_data, mask),
+
+       TP_STRUCT__entry (
+               __field(  void *,       ctx             )
+               __field(  u8,           opcode          )
+               __field(  u64,          user_data       )
+               __field(  int,          mask            )
+       ),
+
+       TP_fast_assign(
+               __entry->ctx            = ctx;
+               __entry->opcode         = opcode;
+               __entry->user_data      = user_data;
+               __entry->mask           = mask;
+       ),
+
+       TP_printk("ring %p, op %d, data 0x%llx, mask %x",
+                         __entry->ctx, __entry->opcode,
+                         (unsigned long long) __entry->user_data,
+                         __entry->mask)
+);
+
+TRACE_EVENT(io_uring_task_run,
+
+       TP_PROTO(void *ctx, u8 opcode, u64 user_data),
+
+       TP_ARGS(ctx, opcode, user_data),
+
+       TP_STRUCT__entry (
+               __field(  void *,       ctx             )
+               __field(  u8,           opcode          )
+               __field(  u64,          user_data       )
+       ),
+
+       TP_fast_assign(
+               __entry->ctx            = ctx;
+               __entry->opcode         = opcode;
+               __entry->user_data      = user_data;
+       ),
+
+       TP_printk("ring %p, op %d, data 0x%llx",
+                         __entry->ctx, __entry->opcode,
+                         (unsigned long long) __entry->user_data)
+);
+
 #endif /* _TRACE_IO_URING_H */
 
 /* This part must be outside protection */
index 7457e23..af5018a 100644 (file)
@@ -359,75 +359,50 @@ DEFINE_EVENT(power_domain, power_domain_target,
 );
 
 /*
- * The pm qos events are used for pm qos update
+ * CPU latency QoS events used for global CPU latency QoS list updates
  */
-DECLARE_EVENT_CLASS(pm_qos_request,
+DECLARE_EVENT_CLASS(cpu_latency_qos_request,
 
-       TP_PROTO(int pm_qos_class, s32 value),
+       TP_PROTO(s32 value),
 
-       TP_ARGS(pm_qos_class, value),
+       TP_ARGS(value),
 
        TP_STRUCT__entry(
-               __field( int,                    pm_qos_class   )
                __field( s32,                    value          )
        ),
 
        TP_fast_assign(
-               __entry->pm_qos_class = pm_qos_class;
                __entry->value = value;
        ),
 
-       TP_printk("pm_qos_class=%s value=%d",
-                 __print_symbolic(__entry->pm_qos_class,
-                       { PM_QOS_CPU_DMA_LATENCY,       "CPU_DMA_LATENCY" }),
+       TP_printk("CPU_DMA_LATENCY value=%d",
                  __entry->value)
 );
 
-DEFINE_EVENT(pm_qos_request, pm_qos_add_request,
+DEFINE_EVENT(cpu_latency_qos_request, pm_qos_add_request,
 
-       TP_PROTO(int pm_qos_class, s32 value),
+       TP_PROTO(s32 value),
 
-       TP_ARGS(pm_qos_class, value)
+       TP_ARGS(value)
 );
 
-DEFINE_EVENT(pm_qos_request, pm_qos_update_request,
+DEFINE_EVENT(cpu_latency_qos_request, pm_qos_update_request,
 
-       TP_PROTO(int pm_qos_class, s32 value),
+       TP_PROTO(s32 value),
 
-       TP_ARGS(pm_qos_class, value)
+       TP_ARGS(value)
 );
 
-DEFINE_EVENT(pm_qos_request, pm_qos_remove_request,
+DEFINE_EVENT(cpu_latency_qos_request, pm_qos_remove_request,
 
-       TP_PROTO(int pm_qos_class, s32 value),
+       TP_PROTO(s32 value),
 
-       TP_ARGS(pm_qos_class, value)
-);
-
-TRACE_EVENT(pm_qos_update_request_timeout,
-
-       TP_PROTO(int pm_qos_class, s32 value, unsigned long timeout_us),
-
-       TP_ARGS(pm_qos_class, value, timeout_us),
-
-       TP_STRUCT__entry(
-               __field( int,                    pm_qos_class   )
-               __field( s32,                    value          )
-               __field( unsigned long,          timeout_us     )
-       ),
-
-       TP_fast_assign(
-               __entry->pm_qos_class = pm_qos_class;
-               __entry->value = value;
-               __entry->timeout_us = timeout_us;
-       ),
-
-       TP_printk("pm_qos_class=%s value=%d, timeout_us=%ld",
-                 __print_symbolic(__entry->pm_qos_class,
-                       { PM_QOS_CPU_DMA_LATENCY,       "CPU_DMA_LATENCY" }),
-                 __entry->value, __entry->timeout_us)
+       TP_ARGS(value)
 );
 
+/*
+ * General PM QoS events used for updates of PM QoS request lists
+ */
 DECLARE_EVENT_CLASS(pm_qos_update,
 
        TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value),
index 5e49b06..f9a7811 100644 (file)
@@ -624,6 +624,34 @@ TRACE_EVENT_RCU(rcu_invoke_kfree_callback,
 );
 
 /*
+ * Tracepoint for the invocation of a single RCU callback of the special
+ * kfree_bulk() form. The first argument is the RCU flavor, the second
+ * argument is a number of elements in array to free, the third is an
+ * address of the array holding nr_records entries.
+ */
+TRACE_EVENT_RCU(rcu_invoke_kfree_bulk_callback,
+
+       TP_PROTO(const char *rcuname, unsigned long nr_records, void **p),
+
+       TP_ARGS(rcuname, nr_records, p),
+
+       TP_STRUCT__entry(
+               __field(const char *, rcuname)
+               __field(unsigned long, nr_records)
+               __field(void **, p)
+       ),
+
+       TP_fast_assign(
+               __entry->rcuname = rcuname;
+               __entry->nr_records = nr_records;
+               __entry->p = p;
+       ),
+
+       TP_printk("%s bulk=0x%p nr_records=%lu",
+               __entry->rcuname, __entry->p, __entry->nr_records)
+);
+
+/*
  * Tracepoint for exiting rcu_do_batch after RCU callbacks have been
  * invoked.  The first argument is the name of the RCU flavor,
  * the second argument is number of callbacks actually invoked,
@@ -712,6 +740,7 @@ TRACE_EVENT_RCU(rcu_torture_read,
  *     "Begin": rcu_barrier() started.
  *     "EarlyExit": rcu_barrier() piggybacked, thus early exit.
  *     "Inc1": rcu_barrier() piggyback check counter incremented.
+ *     "OfflineNoCBQ": rcu_barrier() found offline no-CBs CPU with callbacks.
  *     "OnlineQ": rcu_barrier() found online CPU with callbacks.
  *     "OnlineNQ": rcu_barrier() found online CPU, no callbacks.
  *     "IRQ": An rcu_barrier_callback() callback posted on remote CPU.
index 420e80e..ed168b0 100644 (file)
@@ -487,7 +487,11 @@ TRACE_EVENT(sched_process_hang,
 );
 #endif /* CONFIG_DETECT_HUNG_TASK */
 
-DECLARE_EVENT_CLASS(sched_move_task_template,
+/*
+ * Tracks migration of tasks from one runqueue to another. Can be used to
+ * detect if automatic NUMA balancing is bouncing between nodes.
+ */
+TRACE_EVENT(sched_move_numa,
 
        TP_PROTO(struct task_struct *tsk, int src_cpu, int dst_cpu),
 
@@ -519,23 +523,7 @@ DECLARE_EVENT_CLASS(sched_move_task_template,
                        __entry->dst_cpu, __entry->dst_nid)
 );
 
-/*
- * Tracks migration of tasks from one runqueue to another. Can be used to
- * detect if automatic NUMA balancing is bouncing between nodes
- */
-DEFINE_EVENT(sched_move_task_template, sched_move_numa,
-       TP_PROTO(struct task_struct *tsk, int src_cpu, int dst_cpu),
-
-       TP_ARGS(tsk, src_cpu, dst_cpu)
-);
-
-DEFINE_EVENT(sched_move_task_template, sched_stick_numa,
-       TP_PROTO(struct task_struct *tsk, int src_cpu, int dst_cpu),
-
-       TP_ARGS(tsk, src_cpu, dst_cpu)
-);
-
-TRACE_EVENT(sched_swap_numa,
+DECLARE_EVENT_CLASS(sched_numa_pair_template,
 
        TP_PROTO(struct task_struct *src_tsk, int src_cpu,
                 struct task_struct *dst_tsk, int dst_cpu),
@@ -561,11 +549,11 @@ TRACE_EVENT(sched_swap_numa,
                __entry->src_ngid       = task_numa_group_id(src_tsk);
                __entry->src_cpu        = src_cpu;
                __entry->src_nid        = cpu_to_node(src_cpu);
-               __entry->dst_pid        = task_pid_nr(dst_tsk);
-               __entry->dst_tgid       = task_tgid_nr(dst_tsk);
-               __entry->dst_ngid       = task_numa_group_id(dst_tsk);
+               __entry->dst_pid        = dst_tsk ? task_pid_nr(dst_tsk) : 0;
+               __entry->dst_tgid       = dst_tsk ? task_tgid_nr(dst_tsk) : 0;
+               __entry->dst_ngid       = dst_tsk ? task_numa_group_id(dst_tsk) : 0;
                __entry->dst_cpu        = dst_cpu;
-               __entry->dst_nid        = cpu_to_node(dst_cpu);
+               __entry->dst_nid        = dst_cpu >= 0 ? cpu_to_node(dst_cpu) : -1;
        ),
 
        TP_printk("src_pid=%d src_tgid=%d src_ngid=%d src_cpu=%d src_nid=%d dst_pid=%d dst_tgid=%d dst_ngid=%d dst_cpu=%d dst_nid=%d",
@@ -575,6 +563,23 @@ TRACE_EVENT(sched_swap_numa,
                        __entry->dst_cpu, __entry->dst_nid)
 );
 
+DEFINE_EVENT(sched_numa_pair_template, sched_stick_numa,
+
+       TP_PROTO(struct task_struct *src_tsk, int src_cpu,
+                struct task_struct *dst_tsk, int dst_cpu),
+
+       TP_ARGS(src_tsk, src_cpu, dst_tsk, dst_cpu)
+);
+
+DEFINE_EVENT(sched_numa_pair_template, sched_swap_numa,
+
+       TP_PROTO(struct task_struct *src_tsk, int src_cpu,
+                struct task_struct *dst_tsk, int dst_cpu),
+
+       TP_ARGS(src_tsk, src_cpu, dst_tsk, dst_cpu)
+);
+
+
 /*
  * Tracepoint for waking a polling cpu without an IPI.
  */
@@ -613,6 +618,10 @@ DECLARE_TRACE(pelt_dl_tp,
        TP_PROTO(struct rq *rq),
        TP_ARGS(rq));
 
+DECLARE_TRACE(pelt_thermal_tp,
+       TP_PROTO(struct rq *rq),
+       TP_ARGS(rq));
+
 DECLARE_TRACE(pelt_irq_tp,
        TP_PROTO(struct rq *rq),
        TP_ARGS(rq));
index 2df8cec..6622912 100644 (file)
@@ -272,9 +272,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       41
+#define DM_VERSION_MINOR       42
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2019-09-16)"
+#define DM_VERSION_EXTRA       "-ioctl (2020-02-27)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
index 5e2981d..1318881 100644 (file)
@@ -7,26 +7,18 @@
  * Handbook", Sanches and Canton.
  */
 
-#ifdef FDPATCHES
-#define FD_IOPORT fdc_state[fdc].address
-#else
-/* It would be a lot saner just to force fdc_state[fdc].address to always
-   be set ! FIXME */
-#define FD_IOPORT 0x3f0
-#endif
-
 /* Fd controller regs. S&C, about page 340 */
-#define FD_STATUS      (4 + FD_IOPORT )
-#define FD_DATA                (5 + FD_IOPORT )
+#define FD_STATUS      4
+#define FD_DATA                5
 
 /* Digital Output Register */
-#define FD_DOR         (2 + FD_IOPORT )
+#define FD_DOR         2
 
 /* Digital Input Register (read) */
-#define FD_DIR         (7 + FD_IOPORT )
+#define FD_DIR         7
 
 /* Diskette Control Register (write)*/
-#define FD_DCR         (7 + FD_IOPORT )
+#define FD_DCR         7
 
 /* Bits of main status register */
 #define STATUS_BUSYMASK        0x0F            /* drive busy mask */
index 1521073..8533bf0 100644 (file)
@@ -74,6 +74,8 @@ enum {
 #define IPPROTO_UDPLITE                IPPROTO_UDPLITE
   IPPROTO_MPLS = 137,          /* MPLS in IP (RFC 4023)                */
 #define IPPROTO_MPLS           IPPROTO_MPLS
+  IPPROTO_ETHERNET = 143,      /* Ethernet-within-IPv6 Encapsulation   */
+#define IPPROTO_ETHERNET       IPPROTO_ETHERNET
   IPPROTO_RAW = 255,           /* Raw IP packets                       */
 #define IPPROTO_RAW            IPPROTO_RAW
   IPPROTO_MPTCP = 262,         /* Multipath TCP connection             */
index 0f1db1c..6923dc7 100644 (file)
 /* Electronic privacy screen control */
 #define KEY_PRIVACY_SCREEN_TOGGLE      0x279
 
+/* Select an area of screen to be copied */
+#define KEY_SELECTIVE_SCREENSHOT       0x27a
+
 /*
  * Some keyboards have keys which do not have a defined meaning, these keys
  * are intended to be programmed / bound to macros by the user. For most
index 3f7961c..e48d746 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */
 /*
  * Header file for the io_uring interface.
  *
@@ -23,7 +23,10 @@ struct io_uring_sqe {
                __u64   off;    /* offset into file */
                __u64   addr2;
        };
-       __u64   addr;           /* pointer to buffer or iovecs */
+       union {
+               __u64   addr;   /* pointer to buffer or iovecs */
+               __u64   splice_off_in;
+       };
        __u32   len;            /* buffer size or number of iovecs */
        union {
                __kernel_rwf_t  rw_flags;
@@ -37,14 +40,21 @@ struct io_uring_sqe {
                __u32           open_flags;
                __u32           statx_flags;
                __u32           fadvise_advice;
+               __u32           splice_flags;
        };
        __u64   user_data;      /* data to be passed back at completion time */
        union {
                struct {
-                       /* index into fixed buffers, if used */
-                       __u16   buf_index;
+                       /* pack this to avoid bogus arm OABI complaints */
+                       union {
+                               /* index into fixed buffers, if used */
+                               __u16   buf_index;
+                               /* for grouped buffer selection */
+                               __u16   buf_group;
+                       } __attribute__((packed));
                        /* personality to use, if used */
                        __u16   personality;
+                       __s32   splice_fd_in;
                };
                __u64   __pad2[3];
        };
@@ -56,6 +66,7 @@ enum {
        IOSQE_IO_LINK_BIT,
        IOSQE_IO_HARDLINK_BIT,
        IOSQE_ASYNC_BIT,
+       IOSQE_BUFFER_SELECT_BIT,
 };
 
 /*
@@ -71,6 +82,8 @@ enum {
 #define IOSQE_IO_HARDLINK      (1U << IOSQE_IO_HARDLINK_BIT)
 /* always go async */
 #define IOSQE_ASYNC            (1U << IOSQE_ASYNC_BIT)
+/* select buffer from sqe->buf_group */
+#define IOSQE_BUFFER_SELECT    (1U << IOSQE_BUFFER_SELECT_BIT)
 
 /*
  * io_uring_setup() flags
@@ -113,6 +126,9 @@ enum {
        IORING_OP_RECV,
        IORING_OP_OPENAT2,
        IORING_OP_EPOLL_CTL,
+       IORING_OP_SPLICE,
+       IORING_OP_PROVIDE_BUFFERS,
+       IORING_OP_REMOVE_BUFFERS,
 
        /* this goes last, obviously */
        IORING_OP_LAST,
@@ -129,6 +145,12 @@ enum {
 #define IORING_TIMEOUT_ABS     (1U << 0)
 
 /*
+ * sqe->splice_flags
+ * extends splice(2) flags
+ */
+#define SPLICE_F_FD_IN_FIXED   (1U << 31) /* the last bit of __u32 */
+
+/*
  * IO completion data structure (Completion Queue Entry)
  */
 struct io_uring_cqe {
@@ -138,6 +160,17 @@ struct io_uring_cqe {
 };
 
 /*
+ * cqe->flags
+ *
+ * IORING_CQE_F_BUFFER If set, the upper 16 bits are the buffer ID
+ */
+#define IORING_CQE_F_BUFFER            (1U << 0)
+
+enum {
+       IORING_CQE_BUFFER_SHIFT         = 16,
+};
+
+/*
  * Magic offsets for the application to mmap the data it needs
  */
 #define IORING_OFF_SQ_RING             0ULL
@@ -204,6 +237,7 @@ struct io_uring_params {
 #define IORING_FEAT_SUBMIT_STABLE      (1U << 2)
 #define IORING_FEAT_RW_CUR_POS         (1U << 3)
 #define IORING_FEAT_CUR_PERSONALITY    (1U << 4)
+#define IORING_FEAT_FAST_POLL          (1U << 5)
 
 /*
  * io_uring_register(2) opcodes and arguments
index 16c1fa2..84fa53f 100644 (file)
@@ -64,7 +64,7 @@
 #define MEDIA_BUS_FMT_RGB121212_1X36           0x1019
 #define MEDIA_BUS_FMT_RGB161616_1X48           0x101a
 
-/* YUV (including grey) - next is      0x202d */
+/* YUV (including grey) - next is      0x202e */
 #define MEDIA_BUS_FMT_Y8_1X8                   0x2001
 #define MEDIA_BUS_FMT_UV8_1X8                  0x2015
 #define MEDIA_BUS_FMT_UYVY8_1_5X8              0x2002
@@ -86,6 +86,7 @@
 #define MEDIA_BUS_FMT_VYUY12_2X12              0x201d
 #define MEDIA_BUS_FMT_YUYV12_2X12              0x201e
 #define MEDIA_BUS_FMT_YVYU12_2X12              0x201f
+#define MEDIA_BUS_FMT_Y14_1X14                 0x202d
 #define MEDIA_BUS_FMT_UYVY8_1X16               0x200f
 #define MEDIA_BUS_FMT_VYUY8_1X16               0x2010
 #define MEDIA_BUS_FMT_YUYV8_1X16               0x2011
index 377d794..397cfd6 100644 (file)
@@ -181,6 +181,8 @@ enum perf_branch_sample_type_shift {
 
        PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT      = 16, /* save branch type */
 
+       PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT       = 17, /* save low level index of raw branch records */
+
        PERF_SAMPLE_BRANCH_MAX_SHIFT            /* non-ABI */
 };
 
@@ -208,6 +210,8 @@ enum perf_branch_sample_type {
        PERF_SAMPLE_BRANCH_TYPE_SAVE    =
                1U << PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT,
 
+       PERF_SAMPLE_BRANCH_HW_INDEX     = 1U << PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT,
+
        PERF_SAMPLE_BRANCH_MAX          = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
 };
 
@@ -853,7 +857,9 @@ enum perf_event_type {
         *        char                  data[size];}&& PERF_SAMPLE_RAW
         *
         *      { u64                   nr;
-        *        { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+        *        { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX
+        *        { u64 from, to, flags } lbr[nr];
+        *      } && PERF_SAMPLE_BRANCH_STACK
         *
         *      { u64                   abi; # enum perf_sample_regs_abi
         *        u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
index be84d87..c173545 100644 (file)
@@ -22,6 +22,7 @@
 #define SECCOMP_FILTER_FLAG_LOG                        (1UL << 1)
 #define SECCOMP_FILTER_FLAG_SPEC_ALLOW         (1UL << 2)
 #define SECCOMP_FILTER_FLAG_NEW_LISTENER       (1UL << 3)
+#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH                (1UL << 4)
 
 /*
  * All BPF programs must return a 32-bit value.
index 50e9919..ed2a96f 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef _UAPI_SERIO_H
 #define _UAPI_SERIO_H
 
-
+#include <linux/const.h>
 #include <linux/ioctl.h>
 
 #define SPIOCSTYPE     _IOW('q', 0x01, unsigned long)
 /*
  * bit masks for use in "interrupt" flags (3rd argument)
  */
-#define SERIO_TIMEOUT  BIT(0)
-#define SERIO_PARITY   BIT(1)
-#define SERIO_FRAME    BIT(2)
-#define SERIO_OOB_DATA BIT(3)
+#define SERIO_TIMEOUT  _BITUL(0)
+#define SERIO_PARITY   _BITUL(1)
+#define SERIO_FRAME    _BITUL(2)
+#define SERIO_OOB_DATA _BITUL(3)
 
 /*
  * Serio types
diff --git a/include/uapi/linux/usb/raw_gadget.h b/include/uapi/linux/usb/raw_gadget.h
new file mode 100644 (file)
index 0000000..ea37508
--- /dev/null
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * USB Raw Gadget driver.
+ *
+ * See Documentation/usb/raw-gadget.rst for more details.
+ */
+
+#ifndef _UAPI__LINUX_USB_RAW_GADGET_H
+#define _UAPI__LINUX_USB_RAW_GADGET_H
+
+#include <asm/ioctl.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+
+/* Maximum length of driver_name/device_name in the usb_raw_init struct. */
+#define UDC_NAME_LENGTH_MAX 128
+
+/*
+ * struct usb_raw_init - argument for USB_RAW_IOCTL_INIT ioctl.
+ * @speed: The speed of the emulated USB device, takes the same values as
+ *     the usb_device_speed enum: USB_SPEED_FULL, USB_SPEED_HIGH, etc.
+ * @driver_name: The name of the UDC driver.
+ * @device_name: The name of a UDC instance.
+ *
+ * The last two fields identify a UDC the gadget driver should bind to.
+ * For example, Dummy UDC has "dummy_udc" as its driver_name and "dummy_udc.N"
+ * as its device_name, where N in the index of the Dummy UDC instance.
+ * At the same time the dwc2 driver that is used on Raspberry Pi Zero, has
+ * "20980000.usb" as both driver_name and device_name.
+ */
+struct usb_raw_init {
+       __u8    driver_name[UDC_NAME_LENGTH_MAX];
+       __u8    device_name[UDC_NAME_LENGTH_MAX];
+       __u8    speed;
+};
+
+/* The type of event fetched with the USB_RAW_IOCTL_EVENT_FETCH ioctl. */
+enum usb_raw_event_type {
+       USB_RAW_EVENT_INVALID = 0,
+
+       /* This event is queued when the driver has bound to a UDC. */
+       USB_RAW_EVENT_CONNECT = 1,
+
+       /* This event is queued when a new control request arrived to ep0. */
+       USB_RAW_EVENT_CONTROL = 2,
+
+       /* The list might grow in the future. */
+};
+
+/*
+ * struct usb_raw_event - argument for USB_RAW_IOCTL_EVENT_FETCH ioctl.
+ * @type: The type of the fetched event.
+ * @length: Length of the data buffer. Updated by the driver and set to the
+ *     actual length of the fetched event data.
+ * @data: A buffer to store the fetched event data.
+ *
+ * Currently the fetched data buffer is empty for USB_RAW_EVENT_CONNECT,
+ * and contains struct usb_ctrlrequest for USB_RAW_EVENT_CONTROL.
+ */
+struct usb_raw_event {
+       __u32           type;
+       __u32           length;
+       __u8            data[0];
+};
+
+#define USB_RAW_IO_FLAGS_ZERO  0x0001
+#define USB_RAW_IO_FLAGS_MASK  0x0001
+
+static inline int usb_raw_io_flags_valid(__u16 flags)
+{
+       return (flags & ~USB_RAW_IO_FLAGS_MASK) == 0;
+}
+
+static inline int usb_raw_io_flags_zero(__u16 flags)
+{
+       return (flags & USB_RAW_IO_FLAGS_ZERO);
+}
+
+/*
+ * struct usb_raw_ep_io - argument for USB_RAW_IOCTL_EP0/EP_WRITE/READ ioctls.
+ * @ep: Endpoint handle as returned by USB_RAW_IOCTL_EP_ENABLE for
+ *     USB_RAW_IOCTL_EP_WRITE/READ. Ignored for USB_RAW_IOCTL_EP0_WRITE/READ.
+ * @flags: When USB_RAW_IO_FLAGS_ZERO is specified, the zero flag is set on
+ *     the submitted USB request, see include/linux/usb/gadget.h for details.
+ * @length: Length of data.
+ * @data: Data to send for USB_RAW_IOCTL_EP0/EP_WRITE. Buffer to store received
+ *     data for USB_RAW_IOCTL_EP0/EP_READ.
+ */
+struct usb_raw_ep_io {
+       __u16           ep;
+       __u16           flags;
+       __u32           length;
+       __u8            data[0];
+};
+
+/*
+ * Initializes a Raw Gadget instance.
+ * Accepts a pointer to the usb_raw_init struct as an argument.
+ * Returns 0 on success or negative error code on failure.
+ */
+#define USB_RAW_IOCTL_INIT             _IOW('U', 0, struct usb_raw_init)
+
+/*
+ * Instructs Raw Gadget to bind to a UDC and start emulating a USB device.
+ * Returns 0 on success or negative error code on failure.
+ */
+#define USB_RAW_IOCTL_RUN              _IO('U', 1)
+
+/*
+ * A blocking ioctl that waits for an event and returns fetched event data to
+ * the user.
+ * Accepts a pointer to the usb_raw_event struct.
+ * Returns 0 on success or negative error code on failure.
+ */
+#define USB_RAW_IOCTL_EVENT_FETCH      _IOR('U', 2, struct usb_raw_event)
+
+/*
+ * Queues an IN (OUT for READ) urb as a response to the last control request
+ * received on endpoint 0, provided that was an IN (OUT for READ) request and
+ * waits until the urb is completed. Copies received data to user for READ.
+ * Accepts a pointer to the usb_raw_ep_io struct as an argument.
+ * Returns length of trasferred data on success or negative error code on
+ * failure.
+ */
+#define USB_RAW_IOCTL_EP0_WRITE                _IOW('U', 3, struct usb_raw_ep_io)
+#define USB_RAW_IOCTL_EP0_READ         _IOWR('U', 4, struct usb_raw_ep_io)
+
+/*
+ * Finds an endpoint that supports the transfer type specified in the
+ * descriptor and enables it.
+ * Accepts a pointer to the usb_endpoint_descriptor struct as an argument.
+ * Returns enabled endpoint handle on success or negative error code on failure.
+ */
+#define USB_RAW_IOCTL_EP_ENABLE                _IOW('U', 5, struct usb_endpoint_descriptor)
+
+/* Disables specified endpoint.
+ * Accepts endpoint handle as an argument.
+ * Returns 0 on success or negative error code on failure.
+ */
+#define USB_RAW_IOCTL_EP_DISABLE       _IOW('U', 6, __u32)
+
+/*
+ * Queues an IN (OUT for READ) urb as a response to the last control request
+ * received on endpoint usb_raw_ep_io.ep, provided that was an IN (OUT for READ)
+ * request and waits until the urb is completed. Copies received data to user
+ * for READ.
+ * Accepts a pointer to the usb_raw_ep_io struct as an argument.
+ * Returns length of trasferred data on success or negative error code on
+ * failure.
+ */
+#define USB_RAW_IOCTL_EP_WRITE         _IOW('U', 7, struct usb_raw_ep_io)
+#define USB_RAW_IOCTL_EP_READ          _IOWR('U', 8, struct usb_raw_ep_io)
+
+/*
+ * Switches the gadget into the configured state.
+ * Returns 0 on success or negative error code on failure.
+ */
+#define USB_RAW_IOCTL_CONFIGURE                _IO('U', 9)
+
+/*
+ * Constrains UDC VBUS power usage.
+ * Accepts current limit in 2 mA units as an argument.
+ * Returns 0 on success or negative error code on failure.
+ */
+#define USB_RAW_IOCTL_VBUS_DRAW                _IOW('U', 10, __u32)
+
+#endif /* _UAPI__LINUX_USB_RAW_GADGET_H */
index 5a7bede..1a58d7c 100644 (file)
@@ -192,6 +192,12 @@ enum v4l2_colorfx {
  * We reserve 16 controls for this driver. */
 #define V4L2_CID_USER_IMX_BASE                 (V4L2_CID_USER_BASE + 0x10b0)
 
+/*
+ * The base for the atmel isc driver controls.
+ * We reserve 32 controls for this driver.
+ */
+#define V4L2_CID_USER_ATMEL_ISC_BASE           (V4L2_CID_USER_BASE + 0x10c0)
+
 /* MPEG-class control IDs */
 /* The MPEG controls are applicable to all codec controls
  * and the 'MPEG' part of the define is historical */
index 5f9357d..9817b7e 100644 (file)
@@ -565,6 +565,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_Y6      v4l2_fourcc('Y', '0', '6', ' ') /*  6  Greyscale     */
 #define V4L2_PIX_FMT_Y10     v4l2_fourcc('Y', '1', '0', ' ') /* 10  Greyscale     */
 #define V4L2_PIX_FMT_Y12     v4l2_fourcc('Y', '1', '2', ' ') /* 12  Greyscale     */
+#define V4L2_PIX_FMT_Y14     v4l2_fourcc('Y', '1', '4', ' ') /* 14  Greyscale     */
 #define V4L2_PIX_FMT_Y16     v4l2_fourcc('Y', '1', '6', ' ') /* 16  Greyscale     */
 #define V4L2_PIX_FMT_Y16_BE  v4l2_fourcc_be('Y', '1', '6', ' ') /* 16  Greyscale BE  */
 
@@ -662,6 +663,10 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_SGBRG12P v4l2_fourcc('p', 'G', 'C', 'C')
 #define V4L2_PIX_FMT_SGRBG12P v4l2_fourcc('p', 'g', 'C', 'C')
 #define V4L2_PIX_FMT_SRGGB12P v4l2_fourcc('p', 'R', 'C', 'C')
+#define V4L2_PIX_FMT_SBGGR14 v4l2_fourcc('B', 'G', '1', '4') /* 14  BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG14 v4l2_fourcc('G', 'B', '1', '4') /* 14  GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG14 v4l2_fourcc('G', 'R', '1', '4') /* 14  GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB14 v4l2_fourcc('R', 'G', '1', '4') /* 14  RGRG.. GBGB.. */
        /* 14bit raw bayer packed, 7 bytes for every 4 pixels */
 #define V4L2_PIX_FMT_SBGGR14P v4l2_fourcc('p', 'B', 'E', 'E')
 #define V4L2_PIX_FMT_SGBRG14P v4l2_fourcc('p', 'G', 'E', 'E')
@@ -1242,6 +1247,10 @@ struct v4l2_selection {
 
 typedef __u64 v4l2_std_id;
 
+/*
+ * Attention: Keep the V4L2_STD_* bit definitions in sync with
+ * include/dt-bindings/display/sdtv-standards.h SDTV_STD_* bit definitions.
+ */
 /* one bit for each */
 #define V4L2_STD_PAL_B          ((v4l2_std_id)0x00000001)
 #define V4L2_STD_PAL_B1         ((v4l2_std_id)0x00000002)
diff --git a/include/vdso/bits.h b/include/vdso/bits.h
new file mode 100644 (file)
index 0000000..6d005a1
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_BITS_H
+#define __VDSO_BITS_H
+
+#include <vdso/const.h>
+
+#define BIT(nr)                        (UL(1) << (nr))
+
+#endif /* __VDSO_BITS_H */
diff --git a/include/vdso/clocksource.h b/include/vdso/clocksource.h
new file mode 100644 (file)
index 0000000..c682e7c
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_CLOCKSOURCE_H
+#define __VDSO_CLOCKSOURCE_H
+
+#include <vdso/limits.h>
+
+#ifdef CONFIG_GENERIC_GETTIMEOFDAY
+#include <asm/vdso/clocksource.h>
+#endif /* CONFIG_GENERIC_GETTIMEOFDAY */
+
+enum vdso_clock_mode {
+       VDSO_CLOCKMODE_NONE,
+#ifdef CONFIG_GENERIC_GETTIMEOFDAY
+       VDSO_ARCH_CLOCKMODES,
+#endif
+       VDSO_CLOCKMODE_MAX,
+
+       /* Indicator for time namespace VDSO */
+       VDSO_CLOCKMODE_TIMENS = INT_MAX
+};
+
+#endif /* __VDSO_CLOCKSOURCE_H */
diff --git a/include/vdso/const.h b/include/vdso/const.h
new file mode 100644 (file)
index 0000000..94b385a
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_CONST_H
+#define __VDSO_CONST_H
+
+#include <uapi/linux/const.h>
+
+#define UL(x)          (_UL(x))
+#define ULL(x)         (_ULL(x))
+
+#endif /* __VDSO_CONST_H */
index c5f347c..5cbc9fc 100644 (file)
@@ -4,9 +4,20 @@
 
 #ifndef __ASSEMBLY__
 
-#include <linux/bits.h>
-#include <linux/time.h>
-#include <linux/types.h>
+#include <linux/compiler.h>
+#include <uapi/linux/time.h>
+#include <uapi/linux/types.h>
+#include <uapi/asm-generic/errno-base.h>
+
+#include <vdso/bits.h>
+#include <vdso/clocksource.h>
+#include <vdso/ktime.h>
+#include <vdso/limits.h>
+#include <vdso/math64.h>
+#include <vdso/processor.h>
+#include <vdso/time.h>
+#include <vdso/time32.h>
+#include <vdso/time64.h>
 
 #define VDSO_BASES     (CLOCK_TAI + 1)
 #define VDSO_HRES      (BIT(CLOCK_REALTIME)            | \
@@ -21,8 +32,6 @@
 #define CS_RAW         1
 #define CS_BASES       (CS_RAW + 1)
 
-#define VCLOCK_TIMENS  UINT_MAX
-
 /**
  * struct vdso_timestamp - basetime per clock_id
  * @sec:       seconds
@@ -101,6 +110,22 @@ struct vdso_data {
  */
 extern struct vdso_data _vdso_data[CS_BASES] __attribute__((visibility("hidden")));
 
+/*
+ * The generic vDSO implementation requires that gettimeofday.h
+ * provides:
+ * - __arch_get_vdso_data(): to get the vdso datapage.
+ * - __arch_get_hw_counter(): to get the hw counter based on the
+ *   clock_mode.
+ * - gettimeofday_fallback(): fallback for gettimeofday.
+ * - clock_gettime_fallback(): fallback for clock_gettime.
+ * - clock_getres_fallback(): fallback for clock_getres.
+ */
+#ifdef ENABLE_COMPAT_VDSO
+#include <asm/vdso/compat_gettimeofday.h>
+#else
+#include <asm/vdso/gettimeofday.h>
+#endif /* ENABLE_COMPAT_VDSO */
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __VDSO_DATAPAGE_H */
diff --git a/include/vdso/jiffies.h b/include/vdso/jiffies.h
new file mode 100644 (file)
index 0000000..2f9d596
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_JIFFIES_H
+#define __VDSO_JIFFIES_H
+
+#include <asm/param.h>                 /* for HZ */
+#include <vdso/time64.h>
+
+/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */
+#define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ)
+
+#endif /* __VDSO_JIFFIES_H */
diff --git a/include/vdso/ktime.h b/include/vdso/ktime.h
new file mode 100644 (file)
index 0000000..a0fd072
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_KTIME_H
+#define __VDSO_KTIME_H
+
+#include <vdso/jiffies.h>
+
+/*
+ * The resolution of the clocks. The resolution value is returned in
+ * the clock_getres() system call to give application programmers an
+ * idea of the (in)accuracy of timers. Timer values are rounded up to
+ * this resolution values.
+ */
+#define LOW_RES_NSEC           TICK_NSEC
+#define KTIME_LOW_RES          (LOW_RES_NSEC)
+
+#endif /* __VDSO_KTIME_H */
diff --git a/include/vdso/limits.h b/include/vdso/limits.h
new file mode 100644 (file)
index 0000000..0197888
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_LIMITS_H
+#define __VDSO_LIMITS_H
+
+#define USHRT_MAX      ((unsigned short)~0U)
+#define SHRT_MAX       ((short)(USHRT_MAX >> 1))
+#define SHRT_MIN       ((short)(-SHRT_MAX - 1))
+#define INT_MAX                ((int)(~0U >> 1))
+#define INT_MIN                (-INT_MAX - 1)
+#define UINT_MAX       (~0U)
+#define LONG_MAX       ((long)(~0UL >> 1))
+#define LONG_MIN       (-LONG_MAX - 1)
+#define ULONG_MAX      (~0UL)
+#define LLONG_MAX      ((long long)(~0ULL >> 1))
+#define LLONG_MIN      (-LLONG_MAX - 1)
+#define ULLONG_MAX     (~0ULL)
+#define UINTPTR_MAX    ULONG_MAX
+
+#endif /* __VDSO_LIMITS_H */
diff --git a/include/vdso/math64.h b/include/vdso/math64.h
new file mode 100644 (file)
index 0000000..7da703e
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_MATH64_H
+#define __VDSO_MATH64_H
+
+static __always_inline u32
+__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
+{
+       u32 ret = 0;
+
+       while (dividend >= divisor) {
+               /* The following asm() prevents the compiler from
+                  optimising this loop into a modulo operation.  */
+               asm("" : "+rm"(dividend));
+
+               dividend -= divisor;
+               ret++;
+       }
+
+       *remainder = dividend;
+
+       return ret;
+}
+
+#endif /* __VDSO_MATH64_H */
diff --git a/include/vdso/processor.h b/include/vdso/processor.h
new file mode 100644 (file)
index 0000000..fbe8265
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 ARM Ltd.
+ */
+#ifndef __VDSO_PROCESSOR_H
+#define __VDSO_PROCESSOR_H
+
+#ifndef __ASSEMBLY__
+
+#include <asm/vdso/processor.h>
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __VDSO_PROCESSOR_H */
diff --git a/include/vdso/time.h b/include/vdso/time.h
new file mode 100644 (file)
index 0000000..739f53c
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_TIME_H
+#define __VDSO_TIME_H
+
+#include <uapi/linux/types.h>
+
+struct timens_offset {
+       s64     sec;
+       u64     nsec;
+};
+
+#endif /* __VDSO_TIME_H */
diff --git a/include/vdso/time32.h b/include/vdso/time32.h
new file mode 100644 (file)
index 0000000..fdf56f9
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_TIME32_H
+#define __VDSO_TIME32_H
+
+typedef s32            old_time32_t;
+
+struct old_timespec32 {
+       old_time32_t    tv_sec;
+       s32             tv_nsec;
+};
+
+struct old_timeval32 {
+       old_time32_t    tv_sec;
+       s32             tv_usec;
+};
+
+#endif /* __VDSO_TIME32_H */
diff --git a/include/vdso/time64.h b/include/vdso/time64.h
new file mode 100644 (file)
index 0000000..9d43c3f
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __VDSO_TIME64_H
+#define __VDSO_TIME64_H
+
+/* Parameters used to convert the timespec values: */
+#define MSEC_PER_SEC   1000L
+#define USEC_PER_MSEC  1000L
+#define NSEC_PER_USEC  1000L
+#define NSEC_PER_MSEC  1000000L
+#define USEC_PER_SEC   1000000L
+#define NSEC_PER_SEC   1000000000L
+#define FSEC_PER_SEC   1000000000000000LL
+
+#endif /* __VDSO_TIME64_H */
index 28e7dcd..f8aa8ba 100644 (file)
@@ -46,7 +46,7 @@ struct vtpm_shared_page {
        uint8_t pad;
 
        uint8_t nr_extra_pages;  /* extra pages for long packets; may be zero */
-       uint32_t extra_pages[0]; /* grant IDs; length in nr_extra_pages */
+       uint32_t extra_pages[]; /* grant IDs; length in nr_extra_pages */
 };
 
 #endif
index 89a8895..850a43b 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/completion.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/semaphore.h>
 #include <xen/interface/xen.h>
 #include <xen/interface/grant_table.h>
 #include <xen/interface/io/xenbus.h>
@@ -76,7 +77,7 @@ struct xenbus_device {
        enum xenbus_state state;
        struct completion down;
        struct work_struct work;
-       spinlock_t reclaim_lock;
+       struct semaphore reclaim_sem;
 };
 
 static inline struct xenbus_device *to_xenbus_device(struct device *dev)
index 452bc18..697d109 100644 (file)
@@ -451,6 +451,10 @@ config HAVE_SCHED_AVG_IRQ
        depends on IRQ_TIME_ACCOUNTING || PARAVIRT_TIME_ACCOUNTING
        depends on SMP
 
+config SCHED_THERMAL_PRESSURE
+       bool "Enable periodic averaging of thermal pressure"
+       depends on SMP
+
 config BSD_PROCESS_ACCT
        bool "BSD Process Accounting"
        depends on MULTIUSER
@@ -767,8 +771,7 @@ config ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
        bool
 
 config CC_HAS_INT128
-       def_bool y
-       depends on !$(cc-option,-D__SIZEOF_INT128__=0)
+       def_bool !$(cc-option,$(m64-flag) -D__SIZEOF_INT128__=0) && 64BIT
 
 #
 # For architectures that know their GCC __int128 support is sound
@@ -1226,13 +1229,12 @@ endif
 
 config BOOT_CONFIG
        bool "Boot config support"
-       depends on BLK_DEV_INITRD
-       default y
+       select BLK_DEV_INITRD
        help
          Extra boot config allows system admin to pass a config file as
          complemental extension of kernel cmdline when booting.
          The boot config file must be attached at the end of initramfs
-         with checksum and size.
+         with checksum, size and magic word.
          See <file:Documentation/admin-guide/bootconfig.rst> for details.
 
          If unsure, say Y.
index 0ae9cc2..29d326b 100644 (file)
@@ -429,12 +429,10 @@ void __init mount_block_root(char *name, int flags)
        struct page *page = alloc_page(GFP_KERNEL);
        char *fs_names = page_address(page);
        char *p;
-#ifdef CONFIG_BLOCK
        char b[BDEVNAME_SIZE];
-#else
-       const char *b = name;
-#endif
 
+       scnprintf(b, BDEVNAME_SIZE, "unknown-block(%u,%u)",
+                 MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
        get_fs_names(fs_names);
 retry:
        for (p = fs_names; *p; p += strlen(p)+1) {
@@ -451,9 +449,6 @@ retry:
                 * and bad superblock on root device.
                 * and give them a list of the available devices
                 */
-#ifdef CONFIG_BLOCK
-               __bdevname(ROOT_DEV, b);
-#endif
                printk("VFS: Cannot open root device \"%s\" or %s: error %d\n",
                                root_device_name, b, err);
                printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
@@ -476,9 +471,6 @@ retry:
        for (p = fs_names; *p; p += strlen(p)+1)
                printk(" %s", p);
        printk("\n");
-#ifdef CONFIG_BLOCK
-       __bdevname(ROOT_DEV, b);
-#endif
        panic("VFS: Unable to mount root fs on %s", b);
 out:
        put_page(page);
index f95b014..ee4947a 100644 (file)
@@ -268,7 +268,6 @@ static int __init xbc_snprint_cmdline(char *buf, size_t size,
 {
        struct xbc_node *knode, *vnode;
        char *end = buf + size;
-       char c = '\"';
        const char *val;
        int ret;
 
@@ -279,25 +278,20 @@ static int __init xbc_snprint_cmdline(char *buf, size_t size,
                        return ret;
 
                vnode = xbc_node_get_child(knode);
-               ret = snprintf(buf, rest(buf, end), "%s%c", xbc_namebuf,
-                               vnode ? '=' : ' ');
-               if (ret < 0)
-                       return ret;
-               buf += ret;
-               if (!vnode)
+               if (!vnode) {
+                       ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
+                       if (ret < 0)
+                               return ret;
+                       buf += ret;
                        continue;
-
-               c = '\"';
+               }
                xbc_array_for_each_value(vnode, val) {
-                       ret = snprintf(buf, rest(buf, end), "%c%s", c, val);
+                       ret = snprintf(buf, rest(buf, end), "%s=\"%s\" ",
+                                      xbc_namebuf, val);
                        if (ret < 0)
                                return ret;
                        buf += ret;
-                       c = ',';
                }
-               if (rest(buf, end) > 2)
-                       strcpy(buf, "\" ");
-               buf += 2;
        }
 
        return buf - (end - size);
@@ -335,7 +329,7 @@ static char * __init xbc_make_cmdline(const char *key)
        return new_cmdline;
 }
 
-u32 boot_config_checksum(unsigned char *p, u32 size)
+static u32 boot_config_checksum(unsigned char *p, u32 size)
 {
        u32 ret = 0;
 
@@ -374,7 +368,11 @@ static void __init setup_boot_config(const char *cmdline)
        if (!initrd_end)
                goto not_found;
 
-       hdr = (u32 *)(initrd_end - 8);
+       data = (char *)initrd_end - BOOTCONFIG_MAGIC_LEN;
+       if (memcmp(data, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN))
+               goto not_found;
+
+       hdr = (u32 *)(data - 8);
        size = hdr[0];
        csum = hdr[1];
 
@@ -418,6 +416,14 @@ not_found:
 }
 #else
 #define setup_boot_config(cmdline)     do { } while (0)
+
+static int __init warn_bootconfig(char *str)
+{
+       pr_warn("WARNING: 'bootconfig' found on the kernel command line but CONFIG_BOOTCONFIG is not set.\n");
+       return 0;
+}
+early_param("bootconfig", warn_bootconfig);
+
 #endif
 
 /* Change NUL term back to "=", to make "param" the whole string. */
index 17b0d52..9ddfe2a 100644 (file)
@@ -1101,13 +1101,11 @@ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature
        audit_log_end(ab);
 }
 
-static int audit_set_feature(struct sk_buff *skb)
+static int audit_set_feature(struct audit_features *uaf)
 {
-       struct audit_features *uaf;
        int i;
 
        BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > ARRAY_SIZE(audit_feature_names));
-       uaf = nlmsg_data(nlmsg_hdr(skb));
 
        /* if there is ever a version 2 we should handle that here */
 
@@ -1175,6 +1173,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        u32                     seq;
        void                    *data;
+       int                     data_len;
        int                     err;
        struct audit_buffer     *ab;
        u16                     msg_type = nlh->nlmsg_type;
@@ -1188,6 +1187,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
        seq  = nlh->nlmsg_seq;
        data = nlmsg_data(nlh);
+       data_len = nlmsg_len(nlh);
 
        switch (msg_type) {
        case AUDIT_GET: {
@@ -1211,7 +1211,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                struct audit_status     s;
                memset(&s, 0, sizeof(s));
                /* guard against past and future API changes */
-               memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
+               memcpy(&s, data, min_t(size_t, sizeof(s), data_len));
                if (s.mask & AUDIT_STATUS_ENABLED) {
                        err = audit_set_enabled(s.enabled);
                        if (err < 0)
@@ -1315,7 +1315,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        return err;
                break;
        case AUDIT_SET_FEATURE:
-               err = audit_set_feature(skb);
+               if (data_len < sizeof(struct audit_features))
+                       return -EINVAL;
+               err = audit_set_feature(data);
                if (err)
                        return err;
                break;
@@ -1327,6 +1329,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
                err = audit_filter(msg_type, AUDIT_FILTER_USER);
                if (err == 1) { /* match or error */
+                       char *str = data;
+
                        err = 0;
                        if (msg_type == AUDIT_USER_TTY) {
                                err = tty_audit_push();
@@ -1334,26 +1338,24 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                        break;
                        }
                        audit_log_user_recv_msg(&ab, msg_type);
-                       if (msg_type != AUDIT_USER_TTY)
+                       if (msg_type != AUDIT_USER_TTY) {
+                               /* ensure NULL termination */
+                               str[data_len - 1] = '\0';
                                audit_log_format(ab, " msg='%.*s'",
                                                 AUDIT_MESSAGE_TEXT_MAX,
-                                                (char *)data);
-                       else {
-                               int size;
-
+                                                str);
+                       } else {
                                audit_log_format(ab, " data=");
-                               size = nlmsg_len(nlh);
-                               if (size > 0 &&
-                                   ((unsigned char *)data)[size - 1] == '\0')
-                                       size--;
-                               audit_log_n_untrustedstring(ab, data, size);
+                               if (data_len > 0 && str[data_len - 1] == '\0')
+                                       data_len--;
+                               audit_log_n_untrustedstring(ab, str, data_len);
                        }
                        audit_log_end(ab);
                }
                break;
        case AUDIT_ADD_RULE:
        case AUDIT_DEL_RULE:
-               if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
+               if (data_len < sizeof(struct audit_rule_data))
                        return -EINVAL;
                if (audit_enabled == AUDIT_LOCKED) {
                        audit_log_common_recv_msg(audit_context(), &ab,
@@ -1365,7 +1367,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        audit_log_end(ab);
                        return -EPERM;
                }
-               err = audit_rule_change(msg_type, seq, data, nlmsg_len(nlh));
+               err = audit_rule_change(msg_type, seq, data, data_len);
                break;
        case AUDIT_LIST_RULES:
                err = audit_list_rules_send(skb, seq);
@@ -1380,7 +1382,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        case AUDIT_MAKE_EQUIV: {
                void *bufp = data;
                u32 sizes[2];
-               size_t msglen = nlmsg_len(nlh);
+               size_t msglen = data_len;
                char *old, *new;
 
                err = -EINVAL;
@@ -1456,7 +1458,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
                memset(&s, 0, sizeof(s));
                /* guard against past and future API changes */
-               memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
+               memcpy(&s, data, min_t(size_t, sizeof(s), data_len));
                /* check if new data is valid */
                if ((s.enabled != 0 && s.enabled != 1) ||
                    (s.log_passwd != 0 && s.log_passwd != 1))
index b0126e9..026e34d 100644 (file)
@@ -456,6 +456,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
        bufp = data->buf;
        for (i = 0; i < data->field_count; i++) {
                struct audit_field *f = &entry->rule.fields[i];
+               u32 f_val;
 
                err = -EINVAL;
 
@@ -464,12 +465,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                        goto exit_free;
 
                f->type = data->fields[i];
-               f->val = data->values[i];
+               f_val = data->values[i];
 
                /* Support legacy tests for a valid loginuid */
-               if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
+               if ((f->type == AUDIT_LOGINUID) && (f_val == AUDIT_UID_UNSET)) {
                        f->type = AUDIT_LOGINUID_SET;
-                       f->val = 0;
+                       f_val = 0;
                        entry->rule.pflags |= AUDIT_LOGINUID_LEGACY;
                }
 
@@ -485,7 +486,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                case AUDIT_SUID:
                case AUDIT_FSUID:
                case AUDIT_OBJ_UID:
-                       f->uid = make_kuid(current_user_ns(), f->val);
+                       f->uid = make_kuid(current_user_ns(), f_val);
                        if (!uid_valid(f->uid))
                                goto exit_free;
                        break;
@@ -494,11 +495,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                case AUDIT_SGID:
                case AUDIT_FSGID:
                case AUDIT_OBJ_GID:
-                       f->gid = make_kgid(current_user_ns(), f->val);
+                       f->gid = make_kgid(current_user_ns(), f_val);
                        if (!gid_valid(f->gid))
                                goto exit_free;
                        break;
                case AUDIT_ARCH:
+                       f->val = f_val;
                        entry->rule.arch_f = f;
                        break;
                case AUDIT_SUBJ_USER:
@@ -511,11 +513,13 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                case AUDIT_OBJ_TYPE:
                case AUDIT_OBJ_LEV_LOW:
                case AUDIT_OBJ_LEV_HIGH:
-                       str = audit_unpack_string(&bufp, &remain, f->val);
-                       if (IS_ERR(str))
+                       str = audit_unpack_string(&bufp, &remain, f_val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
                                goto exit_free;
-                       entry->rule.buflen += f->val;
-
+                       }
+                       entry->rule.buflen += f_val;
+                       f->lsm_str = str;
                        err = security_audit_rule_init(f->type, f->op, str,
                                                       (void **)&f->lsm_rule);
                        /* Keep currently invalid fields around in case they
@@ -524,68 +528,71 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                                pr_warn("audit rule for LSM \'%s\' is invalid\n",
                                        str);
                                err = 0;
-                       }
-                       if (err) {
-                               kfree(str);
+                       } else if (err)
                                goto exit_free;
-                       } else
-                               f->lsm_str = str;
                        break;
                case AUDIT_WATCH:
-                       str = audit_unpack_string(&bufp, &remain, f->val);
-                       if (IS_ERR(str))
+                       str = audit_unpack_string(&bufp, &remain, f_val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
                                goto exit_free;
-                       entry->rule.buflen += f->val;
-
-                       err = audit_to_watch(&entry->rule, str, f->val, f->op);
+                       }
+                       err = audit_to_watch(&entry->rule, str, f_val, f->op);
                        if (err) {
                                kfree(str);
                                goto exit_free;
                        }
+                       entry->rule.buflen += f_val;
                        break;
                case AUDIT_DIR:
-                       str = audit_unpack_string(&bufp, &remain, f->val);
-                       if (IS_ERR(str))
+                       str = audit_unpack_string(&bufp, &remain, f_val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
                                goto exit_free;
-                       entry->rule.buflen += f->val;
-
+                       }
                        err = audit_make_tree(&entry->rule, str, f->op);
                        kfree(str);
                        if (err)
                                goto exit_free;
+                       entry->rule.buflen += f_val;
                        break;
                case AUDIT_INODE:
+                       f->val = f_val;
                        err = audit_to_inode(&entry->rule, f);
                        if (err)
                                goto exit_free;
                        break;
                case AUDIT_FILTERKEY:
-                       if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
+                       if (entry->rule.filterkey || f_val > AUDIT_MAX_KEY_LEN)
                                goto exit_free;
-                       str = audit_unpack_string(&bufp, &remain, f->val);
-                       if (IS_ERR(str))
+                       str = audit_unpack_string(&bufp, &remain, f_val);
+                       if (IS_ERR(str)) {
+                               err = PTR_ERR(str);
                                goto exit_free;
-                       entry->rule.buflen += f->val;
+                       }
+                       entry->rule.buflen += f_val;
                        entry->rule.filterkey = str;
                        break;
                case AUDIT_EXE:
-                       if (entry->rule.exe || f->val > PATH_MAX)
+                       if (entry->rule.exe || f_val > PATH_MAX)
                                goto exit_free;
-                       str = audit_unpack_string(&bufp, &remain, f->val);
+                       str = audit_unpack_string(&bufp, &remain, f_val);
                        if (IS_ERR(str)) {
                                err = PTR_ERR(str);
                                goto exit_free;
                        }
-                       entry->rule.buflen += f->val;
-
-                       audit_mark = audit_alloc_mark(&entry->rule, str, f->val);
+                       audit_mark = audit_alloc_mark(&entry->rule, str, f_val);
                        if (IS_ERR(audit_mark)) {
                                kfree(str);
                                err = PTR_ERR(audit_mark);
                                goto exit_free;
                        }
+                       entry->rule.buflen += f_val;
                        entry->rule.exe = audit_mark;
                        break;
+               default:
+                       f->val = f_val;
+                       break;
                }
        }
 
index 042f955..68a89a9 100644 (file)
@@ -482,13 +482,21 @@ static int bpf_struct_ops_map_delete_elem(struct bpf_map *map, void *key)
        prev_state = cmpxchg(&st_map->kvalue.state,
                             BPF_STRUCT_OPS_STATE_INUSE,
                             BPF_STRUCT_OPS_STATE_TOBEFREE);
-       if (prev_state == BPF_STRUCT_OPS_STATE_INUSE) {
+       switch (prev_state) {
+       case BPF_STRUCT_OPS_STATE_INUSE:
                st_map->st_ops->unreg(&st_map->kvalue.data);
                if (refcount_dec_and_test(&st_map->kvalue.refcnt))
                        bpf_map_put(map);
+               return 0;
+       case BPF_STRUCT_OPS_STATE_TOBEFREE:
+               return -EINPROGRESS;
+       case BPF_STRUCT_OPS_STATE_INIT:
+               return -ENOENT;
+       default:
+               WARN_ON_ONCE(1);
+               /* Should never happen.  Treat it as not found. */
+               return -ENOENT;
        }
-
-       return 0;
 }
 
 static void bpf_struct_ops_map_seq_show_elem(struct bpf_map *map, void *key,
index 7871400..7787bdc 100644 (file)
@@ -2418,7 +2418,7 @@ static int btf_enum_check_member(struct btf_verifier_env *env,
 
        struct_size = struct_type->size;
        bytes_offset = BITS_ROUNDDOWN_BYTES(struct_bits_off);
-       if (struct_size - bytes_offset < sizeof(int)) {
+       if (struct_size - bytes_offset < member_type->size) {
                btf_verifier_log_member(env, struct_type, member,
                                        "Member exceeds struct_size");
                return -EINVAL;
@@ -4564,7 +4564,7 @@ int btf_get_info_by_fd(const struct btf *btf,
                       union bpf_attr __user *uattr)
 {
        struct bpf_btf_info __user *uinfo;
-       struct bpf_btf_info info = {};
+       struct bpf_btf_info info;
        u32 info_copy, btf_copy;
        void __user *ubtf;
        u32 uinfo_len;
@@ -4573,6 +4573,7 @@ int btf_get_info_by_fd(const struct btf *btf,
        uinfo_len = attr->info.info_len;
 
        info_copy = min_t(u32, uinfo_len, sizeof(info));
+       memset(&info, 0, sizeof(info));
        if (copy_from_user(&info, uinfo, info_copy))
                return -EFAULT;
 
index 9a500fa..4f14724 100644 (file)
@@ -227,6 +227,9 @@ cleanup:
        for (i = 0; i < NR; i++)
                bpf_prog_array_free(arrays[i]);
 
+       for (p = cgroup_parent(cgrp); p; p = cgroup_parent(p))
+               cgroup_bpf_put(p);
+
        percpu_ref_exit(&cgrp->bpf.refcnt);
 
        return -ENOMEM;
@@ -302,8 +305,8 @@ int __cgroup_bpf_attach(struct cgroup *cgrp, struct bpf_prog *prog,
        u32 saved_flags = (flags & (BPF_F_ALLOW_OVERRIDE | BPF_F_ALLOW_MULTI));
        struct list_head *progs = &cgrp->bpf.progs[type];
        struct bpf_prog *old_prog = NULL;
-       struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE],
-               *old_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {NULL};
+       struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {};
+       struct bpf_cgroup_storage *old_storage[MAX_BPF_CGROUP_STORAGE_TYPE] = {};
        struct bpf_prog_list *pl, *replace_pl = NULL;
        enum bpf_cgroup_storage_type stype;
        int err;
index a91ad51..966b7b3 100644 (file)
@@ -696,14 +696,15 @@ int bpf_get_file_flag(int flags)
                   offsetof(union bpf_attr, CMD##_LAST_FIELD) - \
                   sizeof(attr->CMD##_LAST_FIELD)) != NULL
 
-/* dst and src must have at least BPF_OBJ_NAME_LEN number of bytes.
- * Return 0 on success and < 0 on error.
+/* dst and src must have at least "size" number of bytes.
+ * Return strlen on success and < 0 on error.
  */
-static int bpf_obj_name_cpy(char *dst, const char *src)
+int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size)
 {
-       const char *end = src + BPF_OBJ_NAME_LEN;
+       const char *end = src + size;
+       const char *orig_src = src;
 
-       memset(dst, 0, BPF_OBJ_NAME_LEN);
+       memset(dst, 0, size);
        /* Copy all isalnum(), '_' and '.' chars. */
        while (src < end && *src) {
                if (!isalnum(*src) &&
@@ -712,11 +713,11 @@ static int bpf_obj_name_cpy(char *dst, const char *src)
                *dst++ = *src++;
        }
 
-       /* No '\0' found in BPF_OBJ_NAME_LEN number of bytes */
+       /* No '\0' found in "size" number of bytes */
        if (src == end)
                return -EINVAL;
 
-       return 0;
+       return src - orig_src;
 }
 
 int map_check_no_btf(const struct bpf_map *map,
@@ -810,8 +811,9 @@ static int map_create(union bpf_attr *attr)
        if (IS_ERR(map))
                return PTR_ERR(map);
 
-       err = bpf_obj_name_cpy(map->name, attr->map_name);
-       if (err)
+       err = bpf_obj_name_cpy(map->name, attr->map_name,
+                              sizeof(attr->map_name));
+       if (err < 0)
                goto free_map;
 
        atomic64_set(&map->refcnt, 1);
@@ -1510,6 +1512,11 @@ static int map_freeze(const union bpf_attr *attr)
        if (IS_ERR(map))
                return PTR_ERR(map);
 
+       if (map->map_type == BPF_MAP_TYPE_STRUCT_OPS) {
+               fdput(f);
+               return -ENOTSUPP;
+       }
+
        mutex_lock(&map->freeze_mutex);
 
        if (map->writecnt) {
@@ -2093,8 +2100,9 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
                goto free_prog;
 
        prog->aux->load_time = ktime_get_boottime_ns();
-       err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name);
-       if (err)
+       err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name,
+                              sizeof(attr->prog_name));
+       if (err < 0)
                goto free_prog;
 
        /* run eBPF verifier */
@@ -2787,7 +2795,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
                                   union bpf_attr __user *uattr)
 {
        struct bpf_prog_info __user *uinfo = u64_to_user_ptr(attr->info.info);
-       struct bpf_prog_info info = {};
+       struct bpf_prog_info info;
        u32 info_len = attr->info.info_len;
        struct bpf_prog_stats stats;
        char __user *uinsns;
@@ -2799,6 +2807,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
                return err;
        info_len = min_t(u32, sizeof(info), info_len);
 
+       memset(&info, 0, sizeof(info));
        if (copy_from_user(&info, uinfo, info_len))
                return -EFAULT;
 
@@ -3062,7 +3071,7 @@ static int bpf_map_get_info_by_fd(struct bpf_map *map,
                                  union bpf_attr __user *uattr)
 {
        struct bpf_map_info __user *uinfo = u64_to_user_ptr(attr->info.info);
-       struct bpf_map_info info = {};
+       struct bpf_map_info info;
        u32 info_len = attr->info.info_len;
        int err;
 
@@ -3071,6 +3080,7 @@ static int bpf_map_get_info_by_fd(struct bpf_map *map,
                return err;
        info_len = min_t(u32, sizeof(info), info_len);
 
+       memset(&info, 0, sizeof(info));
        info.type = map->map_type;
        info.id = map->id;
        info.key_size = map->key_size;
@@ -3354,7 +3364,7 @@ err_put:
 
 SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
 {
-       union bpf_attr attr = {};
+       union bpf_attr attr;
        int err;
 
        if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN))
@@ -3366,6 +3376,7 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
        size = min_t(u32, size, sizeof(attr));
 
        /* copy attributes from user space, may be less than sizeof(bpf_attr) */
+       memset(&attr, 0, sizeof(attr));
        if (copy_from_user(&attr, uattr, size) != 0)
                return -EFAULT;
 
index be1a1c8..f2d7cea 100644 (file)
@@ -471,6 +471,7 @@ static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos)
         */
        p++;
        if (p >= end) {
+               (*pos)++;
                return NULL;
        } else {
                *pos = *p;
@@ -782,7 +783,7 @@ void cgroup1_release_agent(struct work_struct *work)
 
        pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
        agentbuf = kstrdup(cgrp->root->release_agent_path, GFP_KERNEL);
-       if (!pathbuf || !agentbuf)
+       if (!pathbuf || !agentbuf || !strlen(agentbuf))
                goto out;
 
        spin_lock_irq(&css_set_lock);
index 75f6873..3dead04 100644 (file)
@@ -3542,21 +3542,21 @@ static int cpu_stat_show(struct seq_file *seq, void *v)
 static int cgroup_io_pressure_show(struct seq_file *seq, void *v)
 {
        struct cgroup *cgrp = seq_css(seq)->cgroup;
-       struct psi_group *psi = cgroup_id(cgrp) == 1 ? &psi_system : &cgrp->psi;
+       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
 
        return psi_show(seq, psi, PSI_IO);
 }
 static int cgroup_memory_pressure_show(struct seq_file *seq, void *v)
 {
        struct cgroup *cgrp = seq_css(seq)->cgroup;
-       struct psi_group *psi = cgroup_id(cgrp) == 1 ? &psi_system : &cgrp->psi;
+       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
 
        return psi_show(seq, psi, PSI_MEM);
 }
 static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)
 {
        struct cgroup *cgrp = seq_css(seq)->cgroup;
-       struct psi_group *psi = cgroup_id(cgrp) == 1 ? &psi_system : &cgrp->psi;
+       struct psi_group *psi = cgroup_ino(cgrp) == 1 ? &psi_system : &cgrp->psi;
 
        return psi_show(seq, psi, PSI_CPU);
 }
@@ -4400,12 +4400,16 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it)
                }
        } while (!css_set_populated(cset) && list_empty(&cset->dying_tasks));
 
-       if (!list_empty(&cset->tasks))
+       if (!list_empty(&cset->tasks)) {
                it->task_pos = cset->tasks.next;
-       else if (!list_empty(&cset->mg_tasks))
+               it->cur_tasks_head = &cset->tasks;
+       } else if (!list_empty(&cset->mg_tasks)) {
                it->task_pos = cset->mg_tasks.next;
-       else
+               it->cur_tasks_head = &cset->mg_tasks;
+       } else {
                it->task_pos = cset->dying_tasks.next;
+               it->cur_tasks_head = &cset->dying_tasks;
+       }
 
        it->tasks_head = &cset->tasks;
        it->mg_tasks_head = &cset->mg_tasks;
@@ -4463,10 +4467,14 @@ repeat:
                else
                        it->task_pos = it->task_pos->next;
 
-               if (it->task_pos == it->tasks_head)
+               if (it->task_pos == it->tasks_head) {
                        it->task_pos = it->mg_tasks_head->next;
-               if (it->task_pos == it->mg_tasks_head)
+                       it->cur_tasks_head = it->mg_tasks_head;
+               }
+               if (it->task_pos == it->mg_tasks_head) {
                        it->task_pos = it->dying_tasks_head->next;
+                       it->cur_tasks_head = it->dying_tasks_head;
+               }
                if (it->task_pos == it->dying_tasks_head)
                        css_task_iter_advance_css_set(it);
        } else {
@@ -4485,11 +4493,12 @@ repeat:
                        goto repeat;
 
                /* and dying leaders w/o live member threads */
-               if (!atomic_read(&task->signal->live))
+               if (it->cur_tasks_head == it->dying_tasks_head &&
+                   !atomic_read(&task->signal->live))
                        goto repeat;
        } else {
                /* skip all dying ones */
-               if (task->flags & PF_EXITING)
+               if (it->cur_tasks_head == it->dying_tasks_head)
                        goto repeat;
        }
 }
@@ -4595,6 +4604,9 @@ static void *cgroup_procs_next(struct seq_file *s, void *v, loff_t *pos)
        struct kernfs_open_file *of = s->private;
        struct css_task_iter *it = of->priv;
 
+       if (pos)
+               (*pos)++;
+
        return css_task_iter_next(it);
 }
 
@@ -4610,7 +4622,7 @@ static void *__cgroup_procs_start(struct seq_file *s, loff_t *pos,
         * from position 0, so we can simply keep iterating on !0 *pos.
         */
        if (!it) {
-               if (WARN_ON_ONCE((*pos)++))
+               if (WARN_ON_ONCE((*pos)))
                        return ERR_PTR(-EINVAL);
 
                it = kzalloc(sizeof(*it), GFP_KERNEL);
@@ -4618,10 +4630,11 @@ static void *__cgroup_procs_start(struct seq_file *s, loff_t *pos,
                        return ERR_PTR(-ENOMEM);
                of->priv = it;
                css_task_iter_start(&cgrp->self, iter_flags, it);
-       } else if (!(*pos)++) {
+       } else if (!(*pos)) {
                css_task_iter_end(it);
                css_task_iter_start(&cgrp->self, iter_flags, it);
-       }
+       } else
+               return it->cur_task;
 
        return cgroup_procs_next(s, NULL, NULL);
 }
@@ -6258,6 +6271,10 @@ void cgroup_sk_alloc(struct sock_cgroup_data *skcd)
                return;
        }
 
+       /* Don't associate the sock with unrelated interrupted task's cgroup. */
+       if (in_interrupt())
+               return;
+
        rcu_read_lock();
 
        while (true) {
index 0296b4b..ce43088 100644 (file)
@@ -198,11 +198,13 @@ void __init context_tracking_cpu_set(int cpu)
        if (initialized)
                return;
 
+#ifdef CONFIG_HAVE_TIF_NOHZ
        /*
         * Set TIF_NOHZ to init/0 and let it propagate to all tasks through fork
         * This assumes that init is the only task at this early boot stage.
         */
        set_tsk_thread_flag(&init_task, TIF_NOHZ);
+#endif
        WARN_ON_ONCE(!tasklist_empty());
 
        initialized = true;
index 9c706af..2371292 100644 (file)
@@ -331,12 +331,12 @@ void lockdep_assert_cpus_held(void)
 
 static void lockdep_acquire_cpus_lock(void)
 {
-       rwsem_acquire(&cpu_hotplug_lock.rw_sem.dep_map, 0, 0, _THIS_IP_);
+       rwsem_acquire(&cpu_hotplug_lock.dep_map, 0, 0, _THIS_IP_);
 }
 
 static void lockdep_release_cpus_lock(void)
 {
-       rwsem_release(&cpu_hotplug_lock.rw_sem.dep_map, _THIS_IP_);
+       rwsem_release(&cpu_hotplug_lock.dep_map, _THIS_IP_);
 }
 
 /*
@@ -1041,7 +1041,7 @@ static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target)
        return _cpu_down(cpu, 0, target);
 }
 
-static int do_cpu_down(unsigned int cpu, enum cpuhp_state target)
+static int cpu_down(unsigned int cpu, enum cpuhp_state target)
 {
        int err;
 
@@ -1051,11 +1051,72 @@ static int do_cpu_down(unsigned int cpu, enum cpuhp_state target)
        return err;
 }
 
-int cpu_down(unsigned int cpu)
+/**
+ * cpu_device_down - Bring down a cpu device
+ * @dev: Pointer to the cpu device to offline
+ *
+ * This function is meant to be used by device core cpu subsystem only.
+ *
+ * Other subsystems should use remove_cpu() instead.
+ */
+int cpu_device_down(struct device *dev)
 {
-       return do_cpu_down(cpu, CPUHP_OFFLINE);
+       return cpu_down(dev->id, CPUHP_OFFLINE);
+}
+
+int remove_cpu(unsigned int cpu)
+{
+       int ret;
+
+       lock_device_hotplug();
+       ret = device_offline(get_cpu_device(cpu));
+       unlock_device_hotplug();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(remove_cpu);
+
+void smp_shutdown_nonboot_cpus(unsigned int primary_cpu)
+{
+       unsigned int cpu;
+       int error;
+
+       cpu_maps_update_begin();
+
+       /*
+        * Make certain the cpu I'm about to reboot on is online.
+        *
+        * This is inline to what migrate_to_reboot_cpu() already do.
+        */
+       if (!cpu_online(primary_cpu))
+               primary_cpu = cpumask_first(cpu_online_mask);
+
+       for_each_online_cpu(cpu) {
+               if (cpu == primary_cpu)
+                       continue;
+
+               error = cpu_down_maps_locked(cpu, CPUHP_OFFLINE);
+               if (error) {
+                       pr_err("Failed to offline CPU%d - error=%d",
+                               cpu, error);
+                       break;
+               }
+       }
+
+       /*
+        * Ensure all but the reboot CPU are offline.
+        */
+       BUG_ON(num_online_cpus() > 1);
+
+       /*
+        * Make sure the CPUs won't be enabled by someone else after this
+        * point. Kexec will reboot to a new kernel shortly resetting
+        * everything along the way.
+        */
+       cpu_hotplug_disabled++;
+
+       cpu_maps_update_done();
 }
-EXPORT_SYMBOL(cpu_down);
 
 #else
 #define takedown_cpu           NULL
@@ -1124,8 +1185,8 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
        }
 
        /*
-        * The caller of do_cpu_up might have raced with another
-        * caller. Ignore it for now.
+        * The caller of cpu_up() might have raced with another
+        * caller. Nothing to do.
         */
        if (st->state >= target)
                goto out;
@@ -1169,7 +1230,7 @@ out:
        return ret;
 }
 
-static int do_cpu_up(unsigned int cpu, enum cpuhp_state target)
+static int cpu_up(unsigned int cpu, enum cpuhp_state target)
 {
        int err = 0;
 
@@ -1203,16 +1264,70 @@ out:
        return err;
 }
 
-int cpu_up(unsigned int cpu)
+/**
+ * cpu_device_up - Bring up a cpu device
+ * @dev: Pointer to the cpu device to online
+ *
+ * This function is meant to be used by device core cpu subsystem only.
+ *
+ * Other subsystems should use add_cpu() instead.
+ */
+int cpu_device_up(struct device *dev)
+{
+       return cpu_up(dev->id, CPUHP_ONLINE);
+}
+
+int add_cpu(unsigned int cpu)
+{
+       int ret;
+
+       lock_device_hotplug();
+       ret = device_online(get_cpu_device(cpu));
+       unlock_device_hotplug();
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(add_cpu);
+
+/**
+ * bringup_hibernate_cpu - Bring up the CPU that we hibernated on
+ * @sleep_cpu: The cpu we hibernated on and should be brought up.
+ *
+ * On some architectures like arm64, we can hibernate on any CPU, but on
+ * wake up the CPU we hibernated on might be offline as a side effect of
+ * using maxcpus= for example.
+ */
+int bringup_hibernate_cpu(unsigned int sleep_cpu)
 {
-       return do_cpu_up(cpu, CPUHP_ONLINE);
+       int ret;
+
+       if (!cpu_online(sleep_cpu)) {
+               pr_info("Hibernated on a CPU that is offline! Bringing CPU up.\n");
+               ret = cpu_up(sleep_cpu, CPUHP_ONLINE);
+               if (ret) {
+                       pr_err("Failed to bring hibernate-CPU up!\n");
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+void bringup_nonboot_cpus(unsigned int setup_max_cpus)
+{
+       unsigned int cpu;
+
+       for_each_present_cpu(cpu) {
+               if (num_online_cpus() >= setup_max_cpus)
+                       break;
+               if (!cpu_online(cpu))
+                       cpu_up(cpu, CPUHP_ONLINE);
+       }
 }
-EXPORT_SYMBOL_GPL(cpu_up);
 
 #ifdef CONFIG_PM_SLEEP_SMP
 static cpumask_var_t frozen_cpus;
 
-int freeze_secondary_cpus(int primary)
+int __freeze_secondary_cpus(int primary, bool suspend)
 {
        int cpu, error = 0;
 
@@ -1237,7 +1352,7 @@ int freeze_secondary_cpus(int primary)
                if (cpu == primary)
                        continue;
 
-               if (pm_wakeup_pending()) {
+               if (suspend && pm_wakeup_pending()) {
                        pr_info("Wakeup pending. Abort CPU freeze\n");
                        error = -EBUSY;
                        break;
@@ -2028,9 +2143,9 @@ static ssize_t write_cpuhp_target(struct device *dev,
                goto out;
 
        if (st->state < target)
-               ret = do_cpu_up(dev->id, target);
+               ret = cpu_up(dev->id, target);
        else
-               ret = do_cpu_down(dev->id, target);
+               ret = cpu_down(dev->id, target);
 out:
        unlock_device_hotplug();
        return ret ? ret : count;
index e453589..d22e4ba 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/sched/mm.h>
 #include <linux/proc_ns.h>
 #include <linux/mount.h>
+#include <linux/min_heap.h>
 
 #include "internal.h"
 
@@ -891,6 +892,47 @@ static inline void perf_cgroup_sched_in(struct task_struct *prev,
        rcu_read_unlock();
 }
 
+static int perf_cgroup_ensure_storage(struct perf_event *event,
+                               struct cgroup_subsys_state *css)
+{
+       struct perf_cpu_context *cpuctx;
+       struct perf_event **storage;
+       int cpu, heap_size, ret = 0;
+
+       /*
+        * Allow storage to have sufficent space for an iterator for each
+        * possibly nested cgroup plus an iterator for events with no cgroup.
+        */
+       for (heap_size = 1; css; css = css->parent)
+               heap_size++;
+
+       for_each_possible_cpu(cpu) {
+               cpuctx = per_cpu_ptr(event->pmu->pmu_cpu_context, cpu);
+               if (heap_size <= cpuctx->heap_size)
+                       continue;
+
+               storage = kmalloc_node(heap_size * sizeof(struct perf_event *),
+                                      GFP_KERNEL, cpu_to_node(cpu));
+               if (!storage) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               raw_spin_lock_irq(&cpuctx->ctx.lock);
+               if (cpuctx->heap_size < heap_size) {
+                       swap(cpuctx->heap, storage);
+                       if (storage == cpuctx->heap_default)
+                               storage = NULL;
+                       cpuctx->heap_size = heap_size;
+               }
+               raw_spin_unlock_irq(&cpuctx->ctx.lock);
+
+               kfree(storage);
+       }
+
+       return ret;
+}
+
 static inline int perf_cgroup_connect(int fd, struct perf_event *event,
                                      struct perf_event_attr *attr,
                                      struct perf_event *group_leader)
@@ -910,6 +952,10 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
                goto out;
        }
 
+       ret = perf_cgroup_ensure_storage(event, css);
+       if (ret)
+               goto out;
+
        cgrp = container_of(css, struct perf_cgroup, css);
        event->cgrp = cgrp;
 
@@ -1531,6 +1577,30 @@ perf_event_groups_less(struct perf_event *left, struct perf_event *right)
        if (left->cpu > right->cpu)
                return false;
 
+#ifdef CONFIG_CGROUP_PERF
+       if (left->cgrp != right->cgrp) {
+               if (!left->cgrp || !left->cgrp->css.cgroup) {
+                       /*
+                        * Left has no cgroup but right does, no cgroups come
+                        * first.
+                        */
+                       return true;
+               }
+               if (!right->cgrp || !right->cgrp->css.cgroup) {
+                       /*
+                        * Right has no cgroup but left does, no cgroups come
+                        * first.
+                        */
+                       return false;
+               }
+               /* Two dissimilar cgroups, order by id. */
+               if (left->cgrp->css.cgroup->kn->id < right->cgrp->css.cgroup->kn->id)
+                       return true;
+
+               return false;
+       }
+#endif
+
        if (left->group_index < right->group_index)
                return true;
        if (left->group_index > right->group_index)
@@ -1610,25 +1680,48 @@ del_event_from_groups(struct perf_event *event, struct perf_event_context *ctx)
 }
 
 /*
- * Get the leftmost event in the @cpu subtree.
+ * Get the leftmost event in the cpu/cgroup subtree.
  */
 static struct perf_event *
-perf_event_groups_first(struct perf_event_groups *groups, int cpu)
+perf_event_groups_first(struct perf_event_groups *groups, int cpu,
+                       struct cgroup *cgrp)
 {
        struct perf_event *node_event = NULL, *match = NULL;
        struct rb_node *node = groups->tree.rb_node;
+#ifdef CONFIG_CGROUP_PERF
+       u64 node_cgrp_id, cgrp_id = 0;
+
+       if (cgrp)
+               cgrp_id = cgrp->kn->id;
+#endif
 
        while (node) {
                node_event = container_of(node, struct perf_event, group_node);
 
                if (cpu < node_event->cpu) {
                        node = node->rb_left;
-               } else if (cpu > node_event->cpu) {
+                       continue;
+               }
+               if (cpu > node_event->cpu) {
                        node = node->rb_right;
-               } else {
-                       match = node_event;
+                       continue;
+               }
+#ifdef CONFIG_CGROUP_PERF
+               node_cgrp_id = 0;
+               if (node_event->cgrp && node_event->cgrp->css.cgroup)
+                       node_cgrp_id = node_event->cgrp->css.cgroup->kn->id;
+
+               if (cgrp_id < node_cgrp_id) {
                        node = node->rb_left;
+                       continue;
+               }
+               if (cgrp_id > node_cgrp_id) {
+                       node = node->rb_right;
+                       continue;
                }
+#endif
+               match = node_event;
+               node = node->rb_left;
        }
 
        return match;
@@ -1641,12 +1734,26 @@ static struct perf_event *
 perf_event_groups_next(struct perf_event *event)
 {
        struct perf_event *next;
+#ifdef CONFIG_CGROUP_PERF
+       u64 curr_cgrp_id = 0;
+       u64 next_cgrp_id = 0;
+#endif
 
        next = rb_entry_safe(rb_next(&event->group_node), typeof(*event), group_node);
-       if (next && next->cpu == event->cpu)
-               return next;
+       if (next == NULL || next->cpu != event->cpu)
+               return NULL;
 
-       return NULL;
+#ifdef CONFIG_CGROUP_PERF
+       if (event->cgrp && event->cgrp->css.cgroup)
+               curr_cgrp_id = event->cgrp->css.cgroup->kn->id;
+
+       if (next->cgrp && next->cgrp->css.cgroup)
+               next_cgrp_id = next->cgrp->css.cgroup->kn->id;
+
+       if (curr_cgrp_id != next_cgrp_id)
+               return NULL;
+#endif
+       return next;
 }
 
 /*
@@ -1986,6 +2093,12 @@ static int perf_get_aux_event(struct perf_event *event,
        return 1;
 }
 
+static inline struct list_head *get_event_list(struct perf_event *event)
+{
+       struct perf_event_context *ctx = event->ctx;
+       return event->attr.pinned ? &ctx->pinned_active : &ctx->flexible_active;
+}
+
 static void perf_group_detach(struct perf_event *event)
 {
        struct perf_event *sibling, *tmp;
@@ -2028,12 +2141,8 @@ static void perf_group_detach(struct perf_event *event)
                if (!RB_EMPTY_NODE(&event->group_node)) {
                        add_event_to_groups(sibling, event->ctx);
 
-                       if (sibling->state == PERF_EVENT_STATE_ACTIVE) {
-                               struct list_head *list = sibling->attr.pinned ?
-                                       &ctx->pinned_active : &ctx->flexible_active;
-
-                               list_add_tail(&sibling->active_list, list);
-                       }
+                       if (sibling->state == PERF_EVENT_STATE_ACTIVE)
+                               list_add_tail(&sibling->active_list, get_event_list(sibling));
                }
 
                WARN_ON_ONCE(sibling->ctx != event->ctx);
@@ -2182,6 +2291,7 @@ __perf_remove_from_context(struct perf_event *event,
 
        if (!ctx->nr_events && ctx->is_active) {
                ctx->is_active = 0;
+               ctx->rotate_necessary = 0;
                if (ctx->task) {
                        WARN_ON_ONCE(cpuctx->task_ctx != ctx);
                        cpuctx->task_ctx = NULL;
@@ -2350,6 +2460,8 @@ event_sched_in(struct perf_event *event,
 {
        int ret = 0;
 
+       WARN_ON_ONCE(event->ctx != ctx);
+
        lockdep_assert_held(&ctx->lock);
 
        if (event->state <= PERF_EVENT_STATE_OFF)
@@ -3077,12 +3189,6 @@ static void ctx_sched_out(struct perf_event_context *ctx,
        if (!ctx->nr_active || !(is_active & EVENT_ALL))
                return;
 
-       /*
-        * If we had been multiplexing, no rotations are necessary, now no events
-        * are active.
-        */
-       ctx->rotate_necessary = 0;
-
        perf_pmu_disable(ctx->pmu);
        if (is_active & EVENT_PINNED) {
                list_for_each_entry_safe(event, tmp, &ctx->pinned_active, active_list)
@@ -3092,6 +3198,13 @@ static void ctx_sched_out(struct perf_event_context *ctx,
        if (is_active & EVENT_FLEXIBLE) {
                list_for_each_entry_safe(event, tmp, &ctx->flexible_active, active_list)
                        group_sched_out(event, cpuctx, ctx);
+
+               /*
+                * Since we cleared EVENT_FLEXIBLE, also clear
+                * rotate_necessary, is will be reset by
+                * ctx_flexible_sched_in() when needed.
+                */
+               ctx->rotate_necessary = 0;
        }
        perf_pmu_enable(ctx->pmu);
 }
@@ -3388,71 +3501,103 @@ static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx,
        ctx_sched_out(&cpuctx->ctx, cpuctx, event_type);
 }
 
-static int visit_groups_merge(struct perf_event_groups *groups, int cpu,
-                             int (*func)(struct perf_event *, void *), void *data)
+static bool perf_less_group_idx(const void *l, const void *r)
 {
-       struct perf_event **evt, *evt1, *evt2;
-       int ret;
-
-       evt1 = perf_event_groups_first(groups, -1);
-       evt2 = perf_event_groups_first(groups, cpu);
-
-       while (evt1 || evt2) {
-               if (evt1 && evt2) {
-                       if (evt1->group_index < evt2->group_index)
-                               evt = &evt1;
-                       else
-                               evt = &evt2;
-               } else if (evt1) {
-                       evt = &evt1;
-               } else {
-                       evt = &evt2;
-               }
+       const struct perf_event *le = l, *re = r;
 
-               ret = func(*evt, data);
-               if (ret)
-                       return ret;
+       return le->group_index < re->group_index;
+}
 
-               *evt = perf_event_groups_next(*evt);
-       }
+static void swap_ptr(void *l, void *r)
+{
+       void **lp = l, **rp = r;
 
-       return 0;
+       swap(*lp, *rp);
 }
 
-struct sched_in_data {
-       struct perf_event_context *ctx;
-       struct perf_cpu_context *cpuctx;
-       int can_add_hw;
+static const struct min_heap_callbacks perf_min_heap = {
+       .elem_size = sizeof(struct perf_event *),
+       .less = perf_less_group_idx,
+       .swp = swap_ptr,
 };
 
-static int pinned_sched_in(struct perf_event *event, void *data)
+static void __heap_add(struct min_heap *heap, struct perf_event *event)
 {
-       struct sched_in_data *sid = data;
+       struct perf_event **itrs = heap->data;
 
-       if (event->state <= PERF_EVENT_STATE_OFF)
-               return 0;
+       if (event) {
+               itrs[heap->nr] = event;
+               heap->nr++;
+       }
+}
 
-       if (!event_filter_match(event))
-               return 0;
+static noinline int visit_groups_merge(struct perf_cpu_context *cpuctx,
+                               struct perf_event_groups *groups, int cpu,
+                               int (*func)(struct perf_event *, void *),
+                               void *data)
+{
+#ifdef CONFIG_CGROUP_PERF
+       struct cgroup_subsys_state *css = NULL;
+#endif
+       /* Space for per CPU and/or any CPU event iterators. */
+       struct perf_event *itrs[2];
+       struct min_heap event_heap;
+       struct perf_event **evt;
+       int ret;
+
+       if (cpuctx) {
+               event_heap = (struct min_heap){
+                       .data = cpuctx->heap,
+                       .nr = 0,
+                       .size = cpuctx->heap_size,
+               };
+
+               lockdep_assert_held(&cpuctx->ctx.lock);
 
-       if (group_can_go_on(event, sid->cpuctx, sid->can_add_hw)) {
-               if (!group_sched_in(event, sid->cpuctx, sid->ctx))
-                       list_add_tail(&event->active_list, &sid->ctx->pinned_active);
+#ifdef CONFIG_CGROUP_PERF
+               if (cpuctx->cgrp)
+                       css = &cpuctx->cgrp->css;
+#endif
+       } else {
+               event_heap = (struct min_heap){
+                       .data = itrs,
+                       .nr = 0,
+                       .size = ARRAY_SIZE(itrs),
+               };
+               /* Events not within a CPU context may be on any CPU. */
+               __heap_add(&event_heap, perf_event_groups_first(groups, -1, NULL));
        }
+       evt = event_heap.data;
 
-       /*
-        * If this pinned group hasn't been scheduled,
-        * put it in error state.
-        */
-       if (event->state == PERF_EVENT_STATE_INACTIVE)
-               perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
+       __heap_add(&event_heap, perf_event_groups_first(groups, cpu, NULL));
+
+#ifdef CONFIG_CGROUP_PERF
+       for (; css; css = css->parent)
+               __heap_add(&event_heap, perf_event_groups_first(groups, cpu, css->cgroup));
+#endif
+
+       min_heapify_all(&event_heap, &perf_min_heap);
+
+       while (event_heap.nr) {
+               ret = func(*evt, data);
+               if (ret)
+                       return ret;
+
+               *evt = perf_event_groups_next(*evt);
+               if (*evt)
+                       min_heapify(&event_heap, 0, &perf_min_heap);
+               else
+                       min_heap_pop(&event_heap, &perf_min_heap);
+       }
 
        return 0;
 }
 
-static int flexible_sched_in(struct perf_event *event, void *data)
+static int merge_sched_in(struct perf_event *event, void *data)
 {
-       struct sched_in_data *sid = data;
+       struct perf_event_context *ctx = event->ctx;
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+       int *can_add_hw = data;
 
        if (event->state <= PERF_EVENT_STATE_OFF)
                return 0;
@@ -3460,14 +3605,17 @@ static int flexible_sched_in(struct perf_event *event, void *data)
        if (!event_filter_match(event))
                return 0;
 
-       if (group_can_go_on(event, sid->cpuctx, sid->can_add_hw)) {
-               int ret = group_sched_in(event, sid->cpuctx, sid->ctx);
-               if (ret) {
-                       sid->can_add_hw = 0;
-                       sid->ctx->rotate_necessary = 1;
-                       return 0;
-               }
-               list_add_tail(&event->active_list, &sid->ctx->flexible_active);
+       if (group_can_go_on(event, cpuctx, *can_add_hw)) {
+               if (!group_sched_in(event, cpuctx, ctx))
+                       list_add_tail(&event->active_list, get_event_list(event));
+       }
+
+       if (event->state == PERF_EVENT_STATE_INACTIVE) {
+               if (event->attr.pinned)
+                       perf_event_set_state(event, PERF_EVENT_STATE_ERROR);
+
+               *can_add_hw = 0;
+               ctx->rotate_necessary = 1;
        }
 
        return 0;
@@ -3477,30 +3625,28 @@ static void
 ctx_pinned_sched_in(struct perf_event_context *ctx,
                    struct perf_cpu_context *cpuctx)
 {
-       struct sched_in_data sid = {
-               .ctx = ctx,
-               .cpuctx = cpuctx,
-               .can_add_hw = 1,
-       };
+       int can_add_hw = 1;
 
-       visit_groups_merge(&ctx->pinned_groups,
+       if (ctx != &cpuctx->ctx)
+               cpuctx = NULL;
+
+       visit_groups_merge(cpuctx, &ctx->pinned_groups,
                           smp_processor_id(),
-                          pinned_sched_in, &sid);
+                          merge_sched_in, &can_add_hw);
 }
 
 static void
 ctx_flexible_sched_in(struct perf_event_context *ctx,
                      struct perf_cpu_context *cpuctx)
 {
-       struct sched_in_data sid = {
-               .ctx = ctx,
-               .cpuctx = cpuctx,
-               .can_add_hw = 1,
-       };
+       int can_add_hw = 1;
 
-       visit_groups_merge(&ctx->flexible_groups,
+       if (ctx != &cpuctx->ctx)
+               cpuctx = NULL;
+
+       visit_groups_merge(cpuctx, &ctx->flexible_groups,
                           smp_processor_id(),
-                          flexible_sched_in, &sid);
+                          merge_sched_in, &can_add_hw);
 }
 
 static void
@@ -3841,6 +3987,12 @@ ctx_event_to_rotate(struct perf_event_context *ctx)
                                      typeof(*event), group_node);
        }
 
+       /*
+        * Unconditionally clear rotate_necessary; if ctx_flexible_sched_in()
+        * finds there are unschedulable events, it will set it again.
+        */
+       ctx->rotate_necessary = 0;
+
        return event;
 }
 
@@ -6555,6 +6707,11 @@ static void perf_output_read(struct perf_output_handle *handle,
                perf_output_read_one(handle, event, enabled, running);
 }
 
+static inline bool perf_sample_save_hw_index(struct perf_event *event)
+{
+       return event->attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX;
+}
+
 void perf_output_sample(struct perf_output_handle *handle,
                        struct perf_event_header *header,
                        struct perf_sample_data *data,
@@ -6643,6 +6800,8 @@ void perf_output_sample(struct perf_output_handle *handle,
                             * sizeof(struct perf_branch_entry);
 
                        perf_output_put(handle, data->br_stack->nr);
+                       if (perf_sample_save_hw_index(event))
+                               perf_output_put(handle, data->br_stack->hw_idx);
                        perf_output_copy(handle, data->br_stack->entries, size);
                } else {
                        /*
@@ -6836,6 +6995,9 @@ void perf_prepare_sample(struct perf_event_header *header,
        if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
                int size = sizeof(u64); /* nr */
                if (data->br_stack) {
+                       if (perf_sample_save_hw_index(event))
+                               size += sizeof(u64);
+
                        size += data->br_stack->nr
                              * sizeof(struct perf_branch_entry);
                }
@@ -10349,6 +10511,9 @@ skip_type:
                cpuctx->online = cpumask_test_cpu(cpu, perf_online_mask);
 
                __perf_mux_hrtimer_init(cpuctx, cpu);
+
+               cpuctx->heap_size = ARRAY_SIZE(cpuctx->heap_default);
+               cpuctx->heap = cpuctx->heap_default;
        }
 
 got_cpu_context:
@@ -10794,12 +10959,6 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
        if (!has_branch_stack(event))
                event->attr.branch_sample_type = 0;
 
-       if (cgroup_fd != -1) {
-               err = perf_cgroup_connect(cgroup_fd, event, attr, group_leader);
-               if (err)
-                       goto err_ns;
-       }
-
        pmu = perf_init_event(event);
        if (IS_ERR(pmu)) {
                err = PTR_ERR(pmu);
@@ -10821,6 +10980,12 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
                goto err_pmu;
        }
 
+       if (cgroup_fd != -1) {
+               err = perf_cgroup_connect(cgroup_fd, event, attr, group_leader);
+               if (err)
+                       goto err_pmu;
+       }
+
        err = exclusive_event_init(event);
        if (err)
                goto err_pmu;
@@ -10881,12 +11046,12 @@ err_per_task:
        exclusive_event_destroy(event);
 
 err_pmu:
+       if (is_cgroup_event(event))
+               perf_detach_cgroup(event);
        if (event->destroy)
                event->destroy(event);
        module_put(pmu->module);
 err_ns:
-       if (is_cgroup_event(event))
-               perf_detach_cgroup(event);
        if (event->ns)
                put_pid_ns(event->ns);
        if (event->hw.target)
index 2833ffb..d70d471 100644 (file)
@@ -103,17 +103,8 @@ static void __exit_signal(struct task_struct *tsk)
 
 #ifdef CONFIG_POSIX_TIMERS
        posix_cpu_timers_exit(tsk);
-       if (group_dead) {
+       if (group_dead)
                posix_cpu_timers_exit_group(tsk);
-       } else {
-               /*
-                * This can only happen if the caller is de_thread().
-                * FIXME: this is the temporary hack, we should teach
-                * posix-cpu-timers to handle this case correctly.
-                */
-               if (unlikely(has_group_leader_pid(tsk)))
-                       posix_cpu_timers_exit_group(tsk);
-       }
 #endif
 
        if (group_dead) {
@@ -258,6 +249,7 @@ void rcuwait_wake_up(struct rcuwait *w)
                wake_up_process(task);
        rcu_read_unlock();
 }
+EXPORT_SYMBOL_GPL(rcuwait_wake_up);
 
 /*
  * Determine if a process group is "orphaned", according to the POSIX
@@ -619,8 +611,8 @@ static void forget_original_parent(struct task_struct *father,
        reaper = find_new_reaper(father, reaper);
        list_for_each_entry(p, &father->children, sibling) {
                for_each_thread(p, t) {
-                       t->real_parent = reaper;
-                       BUG_ON((!t->ptrace) != (t->parent == father));
+                       RCU_INIT_POINTER(t->real_parent, reaper);
+                       BUG_ON((!t->ptrace) != (rcu_access_pointer(t->parent) == father));
                        if (likely(!t->ptrace))
                                t->parent = t->real_parent;
                        if (t->pdeath_signal)
index 60a1295..d90af13 100644 (file)
@@ -397,8 +397,8 @@ static void account_kernel_stack(struct task_struct *tsk, int account)
                mod_zone_page_state(page_zone(first_page), NR_KERNEL_STACK_KB,
                                    THREAD_SIZE / 1024 * account);
 
-               mod_memcg_page_state(first_page, MEMCG_KERNEL_STACK_KB,
-                                    account * (THREAD_SIZE / 1024));
+               mod_memcg_obj_state(stack, MEMCG_KERNEL_STACK_KB,
+                                   account * (THREAD_SIZE / 1024));
        }
 }
 
@@ -1508,7 +1508,7 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
                return 0;
        }
        sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);
-       rcu_assign_pointer(tsk->sighand, sig);
+       RCU_INIT_POINTER(tsk->sighand, sig);
        if (!sig)
                return -ENOMEM;
 
index 0cf84c8..b595328 100644 (file)
  *
  * Where (A) orders the waiters increment and the futex value read through
  * atomic operations (see hb_waiters_inc) and where (B) orders the write
- * to futex and the waiters read -- this is done by the barriers for both
- * shared and private futexes in get_futex_key_refs().
+ * to futex and the waiters read (see hb_waiters_pending()).
  *
  * This yields the following case (where X:=waiters, Y:=futex):
  *
@@ -331,17 +330,6 @@ static void compat_exit_robust_list(struct task_struct *curr);
 static inline void compat_exit_robust_list(struct task_struct *curr) { }
 #endif
 
-static inline void futex_get_mm(union futex_key *key)
-{
-       mmgrab(key->private.mm);
-       /*
-        * Ensure futex_get_mm() implies a full barrier such that
-        * get_futex_key() implies a full barrier. This is relied upon
-        * as smp_mb(); (B), see the ordering comment above.
-        */
-       smp_mb__after_atomic();
-}
-
 /*
  * Reflects a new waiter being added to the waitqueue.
  */
@@ -370,6 +358,10 @@ static inline void hb_waiters_dec(struct futex_hash_bucket *hb)
 static inline int hb_waiters_pending(struct futex_hash_bucket *hb)
 {
 #ifdef CONFIG_SMP
+       /*
+        * Full barrier (B), see the ordering comment above.
+        */
+       smp_mb();
        return atomic_read(&hb->waiters);
 #else
        return 1;
@@ -385,9 +377,9 @@ static inline int hb_waiters_pending(struct futex_hash_bucket *hb)
  */
 static struct futex_hash_bucket *hash_futex(union futex_key *key)
 {
-       u32 hash = jhash2((u32*)&key->both.word,
-                         (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
+       u32 hash = jhash2((u32 *)key, offsetof(typeof(*key), both.offset) / 4,
                          key->both.offset);
+
        return &futex_queues[hash & (futex_hashsize - 1)];
 }
 
@@ -407,70 +399,6 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
                && key1->both.offset == key2->both.offset);
 }
 
-/*
- * Take a reference to the resource addressed by a key.
- * Can be called while holding spinlocks.
- *
- */
-static void get_futex_key_refs(union futex_key *key)
-{
-       if (!key->both.ptr)
-               return;
-
-       /*
-        * On MMU less systems futexes are always "private" as there is no per
-        * process address space. We need the smp wmb nevertheless - yes,
-        * arch/blackfin has MMU less SMP ...
-        */
-       if (!IS_ENABLED(CONFIG_MMU)) {
-               smp_mb(); /* explicit smp_mb(); (B) */
-               return;
-       }
-
-       switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
-       case FUT_OFF_INODE:
-               ihold(key->shared.inode); /* implies smp_mb(); (B) */
-               break;
-       case FUT_OFF_MMSHARED:
-               futex_get_mm(key); /* implies smp_mb(); (B) */
-               break;
-       default:
-               /*
-                * Private futexes do not hold reference on an inode or
-                * mm, therefore the only purpose of calling get_futex_key_refs
-                * is because we need the barrier for the lockless waiter check.
-                */
-               smp_mb(); /* explicit smp_mb(); (B) */
-       }
-}
-
-/*
- * Drop a reference to the resource addressed by a key.
- * The hash bucket spinlock must not be held. This is
- * a no-op for private futexes, see comment in the get
- * counterpart.
- */
-static void drop_futex_key_refs(union futex_key *key)
-{
-       if (!key->both.ptr) {
-               /* If we're here then we tried to put a key we failed to get */
-               WARN_ON_ONCE(1);
-               return;
-       }
-
-       if (!IS_ENABLED(CONFIG_MMU))
-               return;
-
-       switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
-       case FUT_OFF_INODE:
-               iput(key->shared.inode);
-               break;
-       case FUT_OFF_MMSHARED:
-               mmdrop(key->private.mm);
-               break;
-       }
-}
-
 enum futex_access {
        FUTEX_READ,
        FUTEX_WRITE
@@ -505,6 +433,46 @@ futex_setup_timer(ktime_t *time, struct hrtimer_sleeper *timeout,
        return timeout;
 }
 
+/*
+ * Generate a machine wide unique identifier for this inode.
+ *
+ * This relies on u64 not wrapping in the life-time of the machine; which with
+ * 1ns resolution means almost 585 years.
+ *
+ * This further relies on the fact that a well formed program will not unmap
+ * the file while it has a (shared) futex waiting on it. This mapping will have
+ * a file reference which pins the mount and inode.
+ *
+ * If for some reason an inode gets evicted and read back in again, it will get
+ * a new sequence number and will _NOT_ match, even though it is the exact same
+ * file.
+ *
+ * It is important that match_futex() will never have a false-positive, esp.
+ * for PI futexes that can mess up the state. The above argues that false-negatives
+ * are only possible for malformed programs.
+ */
+static u64 get_inode_sequence_number(struct inode *inode)
+{
+       static atomic64_t i_seq;
+       u64 old;
+
+       /* Does the inode already have a sequence number? */
+       old = atomic64_read(&inode->i_sequence);
+       if (likely(old))
+               return old;
+
+       for (;;) {
+               u64 new = atomic64_add_return(1, &i_seq);
+               if (WARN_ON_ONCE(!new))
+                       continue;
+
+               old = atomic64_cmpxchg_relaxed(&inode->i_sequence, 0, new);
+               if (old)
+                       return old;
+               return new;
+       }
+}
+
 /**
  * get_futex_key() - Get parameters which are the keys for a futex
  * @uaddr:     virtual address of the futex
@@ -517,9 +485,15 @@ futex_setup_timer(ktime_t *time, struct hrtimer_sleeper *timeout,
  *
  * The key words are stored in @key on success.
  *
- * For shared mappings, it's (page->index, file_inode(vma->vm_file),
- * offset_within_page).  For private mappings, it's (uaddr, current->mm).
- * We can usually work out the index without swapping in the page.
+ * For shared mappings (when @fshared), the key is:
+ *   ( inode->i_sequence, page->index, offset_within_page )
+ * [ also see get_inode_sequence_number() ]
+ *
+ * For private mappings (or when !@fshared), the key is:
+ *   ( current->mm, address, 0 )
+ *
+ * This allows (cross process, where applicable) identification of the futex
+ * without keeping the page pinned for the duration of the FUTEX_WAIT.
  *
  * lock_page() might sleep, the caller should not hold a spinlock.
  */
@@ -556,7 +530,6 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, enum futex_a
        if (!fshared) {
                key->private.mm = mm;
                key->private.address = address;
-               get_futex_key_refs(key);  /* implies smp_mb(); (B) */
                return 0;
        }
 
@@ -659,8 +632,6 @@ again:
                key->private.mm = mm;
                key->private.address = address;
 
-               get_futex_key_refs(key); /* implies smp_mb(); (B) */
-
        } else {
                struct inode *inode;
 
@@ -692,36 +663,8 @@ again:
                        goto again;
                }
 
-               /*
-                * Take a reference unless it is about to be freed. Previously
-                * this reference was taken by ihold under the page lock
-                * pinning the inode in place so i_lock was unnecessary. The
-                * only way for this check to fail is if the inode was
-                * truncated in parallel which is almost certainly an
-                * application bug. In such a case, just retry.
-                *
-                * We are not calling into get_futex_key_refs() in file-backed
-                * cases, therefore a successful atomic_inc return below will
-                * guarantee that get_futex_key() will still imply smp_mb(); (B).
-                */
-               if (!atomic_inc_not_zero(&inode->i_count)) {
-                       rcu_read_unlock();
-                       put_page(page);
-
-                       goto again;
-               }
-
-               /* Should be impossible but lets be paranoid for now */
-               if (WARN_ON_ONCE(inode->i_mapping != mapping)) {
-                       err = -EFAULT;
-                       rcu_read_unlock();
-                       iput(inode);
-
-                       goto out;
-               }
-
                key->both.offset |= FUT_OFF_INODE; /* inode-based key */
-               key->shared.inode = inode;
+               key->shared.i_seq = get_inode_sequence_number(inode);
                key->shared.pgoff = basepage_index(tail);
                rcu_read_unlock();
        }
@@ -733,7 +676,6 @@ out:
 
 static inline void put_futex_key(union futex_key *key)
 {
-       drop_futex_key_refs(key);
 }
 
 /**
@@ -1723,10 +1665,9 @@ static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr)
                oparg = 1 << oparg;
        }
 
-       if (!access_ok(uaddr, sizeof(u32)))
-               return -EFAULT;
-
+       pagefault_disable();
        ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr);
+       pagefault_enable();
        if (ret)
                return ret;
 
@@ -1868,7 +1809,6 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
                plist_add(&q->list, &hb2->chain);
                q->lock_ptr = &hb2->lock;
        }
-       get_futex_key_refs(key2);
        q->key = *key2;
 }
 
@@ -1890,7 +1830,6 @@ static inline
 void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
                           struct futex_hash_bucket *hb)
 {
-       get_futex_key_refs(key);
        q->key = *key;
 
        __unqueue_futex(q);
@@ -2001,7 +1940,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
                         u32 *cmpval, int requeue_pi)
 {
        union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
-       int drop_count = 0, task_count = 0, ret;
+       int task_count = 0, ret;
        struct futex_pi_state *pi_state = NULL;
        struct futex_hash_bucket *hb1, *hb2;
        struct futex_q *this, *next;
@@ -2122,7 +2061,6 @@ retry_private:
                 */
                if (ret > 0) {
                        WARN_ON(pi_state);
-                       drop_count++;
                        task_count++;
                        /*
                         * If we acquired the lock, then the user space value
@@ -2242,7 +2180,6 @@ retry_private:
                                 * doing so.
                                 */
                                requeue_pi_wake_futex(this, &key2, hb2);
-                               drop_count++;
                                continue;
                        } else if (ret) {
                                /*
@@ -2263,7 +2200,6 @@ retry_private:
                        }
                }
                requeue_futex(this, hb1, hb2, &key2);
-               drop_count++;
        }
 
        /*
@@ -2278,15 +2214,6 @@ out_unlock:
        wake_up_q(&wake_q);
        hb_waiters_dec(hb2);
 
-       /*
-        * drop_futex_key_refs() must be called outside the spinlocks. During
-        * the requeue we moved futex_q's from the hash bucket at key1 to the
-        * one at key2 and updated their key pointer.  We no longer need to
-        * hold the references to key1.
-        */
-       while (--drop_count >= 0)
-               drop_futex_key_refs(&key1);
-
 out_put_keys:
        put_futex_key(&key2);
 out_put_key1:
@@ -2416,7 +2343,6 @@ retry:
                ret = 1;
        }
 
-       drop_futex_key_refs(&q->key);
        return ret;
 }
 
index f92d9a6..20d501a 100644 (file)
@@ -43,6 +43,10 @@ config GENERIC_IRQ_MIGRATION
 config AUTO_IRQ_AFFINITY
        bool
 
+# Interrupt injection mechanism
+config GENERIC_IRQ_INJECTION
+       bool
+
 # Tasklet based software resend for pending interrupts on enable_irq()
 config HARDIRQS_SW_RESEND
        bool
@@ -127,6 +131,7 @@ config SPARSE_IRQ
 config GENERIC_IRQ_DEBUGFS
        bool "Expose irq internals in debugfs"
        depends on DEBUG_FS
+       select GENERIC_IRQ_INJECTION
        default n
        ---help---
 
index b3fa2d8..41e7e37 100644 (file)
@@ -278,7 +278,7 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force)
                }
        }
        if (resend)
-               check_irq_resend(desc);
+               check_irq_resend(desc, false);
 
        return ret;
 }
index a949bd3..4f9f844 100644 (file)
@@ -190,33 +190,7 @@ static ssize_t irq_debug_write(struct file *file, const char __user *user_buf,
                return -EFAULT;
 
        if (!strncmp(buf, "trigger", size)) {
-               unsigned long flags;
-               int err;
-
-               /* Try the HW interface first */
-               err = irq_set_irqchip_state(irq_desc_get_irq(desc),
-                                           IRQCHIP_STATE_PENDING, true);
-               if (!err)
-                       return count;
-
-               /*
-                * Otherwise, try to inject via the resend interface,
-                * which may or may not succeed.
-                */
-               chip_bus_lock(desc);
-               raw_spin_lock_irqsave(&desc->lock, flags);
-
-               if (irq_settings_is_level(desc) || desc->istate & IRQS_NMI) {
-                       /* Can't do level nor NMIs, sorry */
-                       err = -EINVAL;
-               } else {
-                       desc->istate |= IRQS_PENDING;
-                       check_irq_resend(desc);
-                       err = 0;
-               }
-
-               raw_spin_unlock_irqrestore(&desc->lock, flags);
-               chip_bus_sync_unlock(desc);
+               int err = irq_inject_interrupt(irq_desc_get_irq(desc));
 
                return err ? err : count;
        }
index a4ace61..a8e14c8 100644 (file)
@@ -145,6 +145,13 @@ irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags
        for_each_action_of_desc(desc, action) {
                irqreturn_t res;
 
+               /*
+                * If this IRQ would be threaded under force_irqthreads, mark it so.
+                */
+               if (irq_settings_can_thread(desc) &&
+                   !(action->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT)))
+                       lockdep_hardirq_threaded();
+
                trace_irq_handler_entry(irq, action);
                res = action->handler(irq, action->dev_id);
                trace_irq_handler_exit(irq, action, res);
index c9d8eb7..7db284b 100644 (file)
@@ -108,7 +108,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc);
 irqreturn_t handle_irq_event(struct irq_desc *desc);
 
 /* Resending of interrupts :*/
-void check_irq_resend(struct irq_desc *desc);
+int check_irq_resend(struct irq_desc *desc, bool inject);
 bool irq_wait_for_poll(struct irq_desc *desc);
 void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action);
 
@@ -425,6 +425,10 @@ static inline struct cpumask *irq_desc_get_pending_mask(struct irq_desc *desc)
 {
        return desc->pending_mask;
 }
+static inline bool handle_enforce_irqctx(struct irq_data *data)
+{
+       return irqd_is_handle_enforce_irqctx(data);
+}
 bool irq_fixup_move_pending(struct irq_desc *desc, bool force_clear);
 #else /* CONFIG_GENERIC_PENDING_IRQ */
 static inline bool irq_can_move_pcntxt(struct irq_data *data)
@@ -451,6 +455,10 @@ static inline bool irq_fixup_move_pending(struct irq_desc *desc, bool fclear)
 {
        return false;
 }
+static inline bool handle_enforce_irqctx(struct irq_data *data)
+{
+       return false;
+}
 #endif /* !CONFIG_GENERIC_PENDING_IRQ */
 
 #if !defined(CONFIG_IRQ_DOMAIN) || !defined(CONFIG_IRQ_DOMAIN_HIERARCHY)
index 98a5f10..1a77236 100644 (file)
@@ -638,9 +638,15 @@ void irq_init_desc(unsigned int irq)
 int generic_handle_irq(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_data *data;
 
        if (!desc)
                return -EINVAL;
+
+       data = irq_desc_get_irq_data(desc);
+       if (WARN_ON_ONCE(!in_irq() && handle_enforce_irqctx(data)))
+               return -EPERM;
+
        generic_handle_irq_desc(desc);
        return 0;
 }
index 7527e5e..35b8d97 100644 (file)
@@ -46,11 +46,11 @@ const struct fwnode_operations irqchip_fwnode_ops;
 EXPORT_SYMBOL_GPL(irqchip_fwnode_ops);
 
 /**
- * irq_domain_alloc_fwnode - Allocate a fwnode_handle suitable for
+ * __irq_domain_alloc_fwnode - Allocate a fwnode_handle suitable for
  *                           identifying an irq domain
  * @type:      Type of irqchip_fwnode. See linux/irqdomain.h
- * @name:      Optional user provided domain name
  * @id:                Optional user provided id if name != NULL
+ * @name:      Optional user provided domain name
  * @pa:                Optional user-provided physical address
  *
  * Allocate a struct irqchip_fwid, and return a poiner to the embedded
@@ -1310,6 +1310,11 @@ int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain,
                                    unsigned int irq_base,
                                    unsigned int nr_irqs, void *arg)
 {
+       if (!domain->ops->alloc) {
+               pr_debug("domain->ops->alloc() is NULL\n");
+               return -ENOSYS;
+       }
+
        return domain->ops->alloc(domain, irq_base, nr_irqs, arg);
 }
 
@@ -1347,11 +1352,6 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
                        return -EINVAL;
        }
 
-       if (!domain->ops->alloc) {
-               pr_debug("domain->ops->alloc() is NULL\n");
-               return -ENOSYS;
-       }
-
        if (realloc && irq_base >= 0) {
                virq = irq_base;
        } else {
index 7eee98c..fe40c65 100644 (file)
@@ -323,7 +323,11 @@ int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask,
 
        if (desc->affinity_notify) {
                kref_get(&desc->affinity_notify->kref);
-               schedule_work(&desc->affinity_notify->work);
+               if (!schedule_work(&desc->affinity_notify->work)) {
+                       /* Work was already scheduled, drop our extra ref */
+                       kref_put(&desc->affinity_notify->kref,
+                                desc->affinity_notify->release);
+               }
        }
        irqd_set(data, IRQD_AFFINITY_SET);
 
@@ -423,7 +427,10 @@ irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 
        if (old_notify) {
-               cancel_work_sync(&old_notify->work);
+               if (cancel_work_sync(&old_notify->work)) {
+                       /* Pending work had a ref, put that one too */
+                       kref_put(&old_notify->kref, old_notify->release);
+               }
                kref_put(&old_notify->kref, old_notify->release);
        }
 
index 98c04ca..27634f4 100644 (file)
@@ -47,6 +47,43 @@ static void resend_irqs(unsigned long arg)
 /* Tasklet to handle resend: */
 static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);
 
+static int irq_sw_resend(struct irq_desc *desc)
+{
+       unsigned int irq = irq_desc_get_irq(desc);
+
+       /*
+        * Validate whether this interrupt can be safely injected from
+        * non interrupt context
+        */
+       if (handle_enforce_irqctx(&desc->irq_data))
+               return -EINVAL;
+
+       /*
+        * If the interrupt is running in the thread context of the parent
+        * irq we need to be careful, because we cannot trigger it
+        * directly.
+        */
+       if (irq_settings_is_nested_thread(desc)) {
+               /*
+                * If the parent_irq is valid, we retrigger the parent,
+                * otherwise we do nothing.
+                */
+               if (!desc->parent_irq)
+                       return -EINVAL;
+               irq = desc->parent_irq;
+       }
+
+       /* Set it pending and activate the softirq: */
+       set_bit(irq, irqs_resend);
+       tasklet_schedule(&resend_tasklet);
+       return 0;
+}
+
+#else
+static int irq_sw_resend(struct irq_desc *desc)
+{
+       return -EINVAL;
+}
 #endif
 
 /*
@@ -54,49 +91,83 @@ static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0);
  *
  * Is called with interrupts disabled and desc->lock held.
  */
-void check_irq_resend(struct irq_desc *desc)
+int check_irq_resend(struct irq_desc *desc, bool inject)
 {
+       int err = 0;
+
        /*
-        * We do not resend level type interrupts. Level type
-        * interrupts are resent by hardware when they are still
-        * active. Clear the pending bit so suspend/resume does not
-        * get confused.
+        * We do not resend level type interrupts. Level type interrupts
+        * are resent by hardware when they are still active. Clear the
+        * pending bit so suspend/resume does not get confused.
         */
        if (irq_settings_is_level(desc)) {
                desc->istate &= ~IRQS_PENDING;
-               return;
+               return -EINVAL;
        }
+
        if (desc->istate & IRQS_REPLAY)
-               return;
-       if (desc->istate & IRQS_PENDING) {
-               desc->istate &= ~IRQS_PENDING;
+               return -EBUSY;
+
+       if (!(desc->istate & IRQS_PENDING) && !inject)
+               return 0;
+
+       desc->istate &= ~IRQS_PENDING;
+
+       if (!desc->irq_data.chip->irq_retrigger ||
+           !desc->irq_data.chip->irq_retrigger(&desc->irq_data))
+               err = irq_sw_resend(desc);
+
+       /* If the retrigger was successfull, mark it with the REPLAY bit */
+       if (!err)
                desc->istate |= IRQS_REPLAY;
+       return err;
+}
 
-               if (!desc->irq_data.chip->irq_retrigger ||
-                   !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
-#ifdef CONFIG_HARDIRQS_SW_RESEND
-                       unsigned int irq = irq_desc_get_irq(desc);
-
-                       /*
-                        * If the interrupt is running in the thread
-                        * context of the parent irq we need to be
-                        * careful, because we cannot trigger it
-                        * directly.
-                        */
-                       if (irq_settings_is_nested_thread(desc)) {
-                               /*
-                                * If the parent_irq is valid, we
-                                * retrigger the parent, otherwise we
-                                * do nothing.
-                                */
-                               if (!desc->parent_irq)
-                                       return;
-                               irq = desc->parent_irq;
-                       }
-                       /* Set it pending and activate the softirq: */
-                       set_bit(irq, irqs_resend);
-                       tasklet_schedule(&resend_tasklet);
-#endif
-               }
-       }
+#ifdef CONFIG_GENERIC_IRQ_INJECTION
+/**
+ * irq_inject_interrupt - Inject an interrupt for testing/error injection
+ * @irq:       The interrupt number
+ *
+ * This function must only be used for debug and testing purposes!
+ *
+ * Especially on x86 this can cause a premature completion of an interrupt
+ * affinity change causing the interrupt line to become stale. Very
+ * unlikely, but possible.
+ *
+ * The injection can fail for various reasons:
+ * - Interrupt is not activated
+ * - Interrupt is NMI type or currently replaying
+ * - Interrupt is level type
+ * - Interrupt does not support hardware retrigger and software resend is
+ *   either not enabled or not possible for the interrupt.
+ */
+int irq_inject_interrupt(unsigned int irq)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+       int err;
+
+       /* Try the state injection hardware interface first */
+       if (!irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, true))
+               return 0;
+
+       /* That failed, try via the resend mechanism */
+       desc = irq_get_desc_buslock(irq, &flags, 0);
+       if (!desc)
+               return -EINVAL;
+
+       /*
+        * Only try to inject when the interrupt is:
+        *  - not NMI type
+        *  - activated
+        */
+       if ((desc->istate & IRQS_NMI) || !irqd_is_activated(&desc->irq_data))
+               err = -EINVAL;
+       else
+               err = check_irq_resend(desc, true);
+
+       irq_put_desc_busunlock(desc, flags);
+       return err;
 }
+EXPORT_SYMBOL_GPL(irq_inject_interrupt);
+#endif
index 828cc30..48b5d1b 100644 (file)
@@ -153,7 +153,9 @@ static void irq_work_run_list(struct llist_head *list)
                 */
                flags = atomic_fetch_andnot(IRQ_WORK_PENDING, &work->flags);
 
+               lockdep_irq_work_enter(work);
                work->func(work);
+               lockdep_irq_work_exit(work);
                /*
                 * Clear the BUSY bit and return to the free state if
                 * no-one else claimed it meanwhile.
index b262f47..bfbfa48 100644 (file)
@@ -199,8 +199,15 @@ static void __kthread_parkme(struct kthread *self)
                if (!test_bit(KTHREAD_SHOULD_PARK, &self->flags))
                        break;
 
+               /*
+                * Thread is going to call schedule(), do not preempt it,
+                * or the caller of kthread_park() may spend more time in
+                * wait_task_inactive().
+                */
+               preempt_disable();
                complete(&self->parked);
-               schedule();
+               schedule_preempt_disabled();
+               preempt_enable();
        }
        __set_current_state(TASK_RUNNING);
 }
@@ -245,8 +252,14 @@ static int kthread(void *_create)
        /* OK, tell user we're spawned, wait for stop or wakeup */
        __set_current_state(TASK_UNINTERRUPTIBLE);
        create->result = current;
+       /*
+        * Thread is going to call schedule(), do not preempt it,
+        * or the creator may spend more time in wait_task_inactive().
+        */
+       preempt_disable();
        complete(done);
-       schedule();
+       schedule_preempt_disabled();
+       preempt_enable();
 
        ret = -EINTR;
        if (!test_bit(KTHREAD_SHOULD_STOP, &self->flags)) {
index 32406ef..1511690 100644 (file)
@@ -84,12 +84,39 @@ module_param(lock_stat, int, 0644);
  * to use a raw spinlock - we really dont want the spinlock
  * code to recurse back into the lockdep code...
  */
-static arch_spinlock_t lockdep_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
+static arch_spinlock_t __lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
+static struct task_struct *__owner;
+
+static inline void lockdep_lock(void)
+{
+       DEBUG_LOCKS_WARN_ON(!irqs_disabled());
+
+       arch_spin_lock(&__lock);
+       __owner = current;
+       current->lockdep_recursion++;
+}
+
+static inline void lockdep_unlock(void)
+{
+       if (debug_locks && DEBUG_LOCKS_WARN_ON(__owner != current))
+               return;
+
+       current->lockdep_recursion--;
+       __owner = NULL;
+       arch_spin_unlock(&__lock);
+}
+
+static inline bool lockdep_assert_locked(void)
+{
+       return DEBUG_LOCKS_WARN_ON(__owner != current);
+}
+
 static struct task_struct *lockdep_selftest_task_struct;
 
+
 static int graph_lock(void)
 {
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        /*
         * Make sure that if another CPU detected a bug while
         * walking the graph we dont change it (while the other
@@ -97,27 +124,15 @@ static int graph_lock(void)
         * dropped already)
         */
        if (!debug_locks) {
-               arch_spin_unlock(&lockdep_lock);
+               lockdep_unlock();
                return 0;
        }
-       /* prevent any recursions within lockdep from causing deadlocks */
-       current->lockdep_recursion++;
        return 1;
 }
 
-static inline int graph_unlock(void)
+static inline void graph_unlock(void)
 {
-       if (debug_locks && !arch_spin_is_locked(&lockdep_lock)) {
-               /*
-                * The lockdep graph lock isn't locked while we expect it to
-                * be, we're confused now, bye!
-                */
-               return DEBUG_LOCKS_WARN_ON(1);
-       }
-
-       current->lockdep_recursion--;
-       arch_spin_unlock(&lockdep_lock);
-       return 0;
+       lockdep_unlock();
 }
 
 /*
@@ -128,7 +143,7 @@ static inline int debug_locks_off_graph_unlock(void)
 {
        int ret = debug_locks_off();
 
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
 
        return ret;
 }
@@ -147,6 +162,7 @@ static DECLARE_BITMAP(list_entries_in_use, MAX_LOCKDEP_ENTRIES);
 #define KEYHASH_SIZE           (1UL << KEYHASH_BITS)
 static struct hlist_head lock_keys_hash[KEYHASH_SIZE];
 unsigned long nr_lock_classes;
+unsigned long nr_zapped_classes;
 #ifndef CONFIG_DEBUG_LOCKDEP
 static
 #endif
@@ -377,18 +393,31 @@ void lockdep_init_task(struct task_struct *task)
        task->lockdep_recursion = 0;
 }
 
+/*
+ * Split the recrursion counter in two to readily detect 'off' vs recursion.
+ */
+#define LOCKDEP_RECURSION_BITS 16
+#define LOCKDEP_OFF            (1U << LOCKDEP_RECURSION_BITS)
+#define LOCKDEP_RECURSION_MASK (LOCKDEP_OFF - 1)
+
 void lockdep_off(void)
 {
-       current->lockdep_recursion++;
+       current->lockdep_recursion += LOCKDEP_OFF;
 }
 EXPORT_SYMBOL(lockdep_off);
 
 void lockdep_on(void)
 {
-       current->lockdep_recursion--;
+       current->lockdep_recursion -= LOCKDEP_OFF;
 }
 EXPORT_SYMBOL(lockdep_on);
 
+static inline void lockdep_recursion_finish(void)
+{
+       if (WARN_ON_ONCE(--current->lockdep_recursion))
+               current->lockdep_recursion = 0;
+}
+
 void lockdep_set_selftest_task(struct task_struct *task)
 {
        lockdep_selftest_task_struct = task;
@@ -575,6 +604,7 @@ static const char *usage_str[] =
 #include "lockdep_states.h"
 #undef LOCKDEP_STATE
        [LOCK_USED] = "INITIAL USE",
+       [LOCK_USAGE_STATES] = "IN-NMI",
 };
 #endif
 
@@ -653,7 +683,9 @@ static void print_lock_name(struct lock_class *class)
 
        printk(KERN_CONT " (");
        __print_lock_name(class);
-       printk(KERN_CONT "){%s}", usage);
+       printk(KERN_CONT "){%s}-{%hd:%hd}", usage,
+                       class->wait_type_outer ?: class->wait_type_inner,
+                       class->wait_type_inner);
 }
 
 static void print_lockdep_cache(struct lockdep_map *lock)
@@ -787,6 +819,7 @@ static int count_matching_names(struct lock_class *new_class)
        return count + 1;
 }
 
+/* used from NMI context -- must be lockless */
 static inline struct lock_class *
 look_up_lock_class(const struct lockdep_map *lock, unsigned int subclass)
 {
@@ -1070,13 +1103,15 @@ static inline void check_data_structures(void) { }
 
 #endif /* CONFIG_DEBUG_LOCKDEP */
 
+static void init_chain_block_buckets(void);
+
 /*
  * Initialize the lock_classes[] array elements, the free_lock_classes list
  * and also the delayed_free structure.
  */
 static void init_data_structures_once(void)
 {
-       static bool ds_initialized, rcu_head_initialized;
+       static bool __read_mostly ds_initialized, rcu_head_initialized;
        int i;
 
        if (likely(rcu_head_initialized))
@@ -1100,6 +1135,7 @@ static void init_data_structures_once(void)
                INIT_LIST_HEAD(&lock_classes[i].locks_after);
                INIT_LIST_HEAD(&lock_classes[i].locks_before);
        }
+       init_chain_block_buckets();
 }
 
 static inline struct hlist_head *keyhashentry(const struct lock_class_key *key)
@@ -1230,6 +1266,8 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
        WARN_ON_ONCE(!list_empty(&class->locks_before));
        WARN_ON_ONCE(!list_empty(&class->locks_after));
        class->name_version = count_matching_names(class);
+       class->wait_type_inner = lock->wait_type_inner;
+       class->wait_type_outer = lock->wait_type_outer;
        /*
         * We use RCU's safe list-add method to make
         * parallel walking of the hash-list safe:
@@ -1469,6 +1507,8 @@ static int __bfs(struct lock_list *source_entry,
        struct circular_queue *cq = &lock_cq;
        int ret = 1;
 
+       lockdep_assert_locked();
+
        if (match(source_entry, data)) {
                *target_entry = source_entry;
                ret = 0;
@@ -1491,8 +1531,6 @@ static int __bfs(struct lock_list *source_entry,
 
                head = get_dep_list(lock, offset);
 
-               DEBUG_LOCKS_WARN_ON(!irqs_disabled());
-
                list_for_each_entry_rcu(entry, head, entry) {
                        if (!lock_accessed(entry)) {
                                unsigned int cq_depth;
@@ -1719,9 +1757,9 @@ unsigned long lockdep_count_forward_deps(struct lock_class *class)
        this.class = class;
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        ret = __lockdep_count_forward_deps(&this);
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 
        return ret;
@@ -1746,9 +1784,9 @@ unsigned long lockdep_count_backward_deps(struct lock_class *class)
        this.class = class;
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        ret = __lockdep_count_backward_deps(&this);
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 
        return ret;
@@ -2298,18 +2336,6 @@ static int check_irq_usage(struct task_struct *curr, struct held_lock *prev,
        return 0;
 }
 
-static void inc_chains(void)
-{
-       if (current->hardirq_context)
-               nr_hardirq_chains++;
-       else {
-               if (current->softirq_context)
-                       nr_softirq_chains++;
-               else
-                       nr_process_chains++;
-       }
-}
-
 #else
 
 static inline int check_irq_usage(struct task_struct *curr,
@@ -2317,13 +2343,27 @@ static inline int check_irq_usage(struct task_struct *curr,
 {
        return 1;
 }
+#endif /* CONFIG_TRACE_IRQFLAGS */
 
-static inline void inc_chains(void)
+static void inc_chains(int irq_context)
 {
-       nr_process_chains++;
+       if (irq_context & LOCK_CHAIN_HARDIRQ_CONTEXT)
+               nr_hardirq_chains++;
+       else if (irq_context & LOCK_CHAIN_SOFTIRQ_CONTEXT)
+               nr_softirq_chains++;
+       else
+               nr_process_chains++;
 }
 
-#endif /* CONFIG_TRACE_IRQFLAGS */
+static void dec_chains(int irq_context)
+{
+       if (irq_context & LOCK_CHAIN_HARDIRQ_CONTEXT)
+               nr_hardirq_chains--;
+       else if (irq_context & LOCK_CHAIN_SOFTIRQ_CONTEXT)
+               nr_softirq_chains--;
+       else
+               nr_process_chains--;
+}
 
 static void
 print_deadlock_scenario(struct held_lock *nxt, struct held_lock *prv)
@@ -2622,8 +2662,235 @@ out_bug:
 
 struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];
 static DECLARE_BITMAP(lock_chains_in_use, MAX_LOCKDEP_CHAINS);
-int nr_chain_hlocks;
 static u16 chain_hlocks[MAX_LOCKDEP_CHAIN_HLOCKS];
+unsigned long nr_zapped_lock_chains;
+unsigned int nr_free_chain_hlocks;     /* Free chain_hlocks in buckets */
+unsigned int nr_lost_chain_hlocks;     /* Lost chain_hlocks */
+unsigned int nr_large_chain_blocks;    /* size > MAX_CHAIN_BUCKETS */
+
+/*
+ * The first 2 chain_hlocks entries in the chain block in the bucket
+ * list contains the following meta data:
+ *
+ *   entry[0]:
+ *     Bit    15 - always set to 1 (it is not a class index)
+ *     Bits 0-14 - upper 15 bits of the next block index
+ *   entry[1]    - lower 16 bits of next block index
+ *
+ * A next block index of all 1 bits means it is the end of the list.
+ *
+ * On the unsized bucket (bucket-0), the 3rd and 4th entries contain
+ * the chain block size:
+ *
+ *   entry[2] - upper 16 bits of the chain block size
+ *   entry[3] - lower 16 bits of the chain block size
+ */
+#define MAX_CHAIN_BUCKETS      16
+#define CHAIN_BLK_FLAG         (1U << 15)
+#define CHAIN_BLK_LIST_END     0xFFFFU
+
+static int chain_block_buckets[MAX_CHAIN_BUCKETS];
+
+static inline int size_to_bucket(int size)
+{
+       if (size > MAX_CHAIN_BUCKETS)
+               return 0;
+
+       return size - 1;
+}
+
+/*
+ * Iterate all the chain blocks in a bucket.
+ */
+#define for_each_chain_block(bucket, prev, curr)               \
+       for ((prev) = -1, (curr) = chain_block_buckets[bucket]; \
+            (curr) >= 0;                                       \
+            (prev) = (curr), (curr) = chain_block_next(curr))
+
+/*
+ * next block or -1
+ */
+static inline int chain_block_next(int offset)
+{
+       int next = chain_hlocks[offset];
+
+       WARN_ON_ONCE(!(next & CHAIN_BLK_FLAG));
+
+       if (next == CHAIN_BLK_LIST_END)
+               return -1;
+
+       next &= ~CHAIN_BLK_FLAG;
+       next <<= 16;
+       next |= chain_hlocks[offset + 1];
+
+       return next;
+}
+
+/*
+ * bucket-0 only
+ */
+static inline int chain_block_size(int offset)
+{
+       return (chain_hlocks[offset + 2] << 16) | chain_hlocks[offset + 3];
+}
+
+static inline void init_chain_block(int offset, int next, int bucket, int size)
+{
+       chain_hlocks[offset] = (next >> 16) | CHAIN_BLK_FLAG;
+       chain_hlocks[offset + 1] = (u16)next;
+
+       if (size && !bucket) {
+               chain_hlocks[offset + 2] = size >> 16;
+               chain_hlocks[offset + 3] = (u16)size;
+       }
+}
+
+static inline void add_chain_block(int offset, int size)
+{
+       int bucket = size_to_bucket(size);
+       int next = chain_block_buckets[bucket];
+       int prev, curr;
+
+       if (unlikely(size < 2)) {
+               /*
+                * We can't store single entries on the freelist. Leak them.
+                *
+                * One possible way out would be to uniquely mark them, other
+                * than with CHAIN_BLK_FLAG, such that we can recover them when
+                * the block before it is re-added.
+                */
+               if (size)
+                       nr_lost_chain_hlocks++;
+               return;
+       }
+
+       nr_free_chain_hlocks += size;
+       if (!bucket) {
+               nr_large_chain_blocks++;
+
+               /*
+                * Variable sized, sort large to small.
+                */
+               for_each_chain_block(0, prev, curr) {
+                       if (size >= chain_block_size(curr))
+                               break;
+               }
+               init_chain_block(offset, curr, 0, size);
+               if (prev < 0)
+                       chain_block_buckets[0] = offset;
+               else
+                       init_chain_block(prev, offset, 0, 0);
+               return;
+       }
+       /*
+        * Fixed size, add to head.
+        */
+       init_chain_block(offset, next, bucket, size);
+       chain_block_buckets[bucket] = offset;
+}
+
+/*
+ * Only the first block in the list can be deleted.
+ *
+ * For the variable size bucket[0], the first block (the largest one) is
+ * returned, broken up and put back into the pool. So if a chain block of
+ * length > MAX_CHAIN_BUCKETS is ever used and zapped, it will just be
+ * queued up after the primordial chain block and never be used until the
+ * hlock entries in the primordial chain block is almost used up. That
+ * causes fragmentation and reduce allocation efficiency. That can be
+ * monitored by looking at the "large chain blocks" number in lockdep_stats.
+ */
+static inline void del_chain_block(int bucket, int size, int next)
+{
+       nr_free_chain_hlocks -= size;
+       chain_block_buckets[bucket] = next;
+
+       if (!bucket)
+               nr_large_chain_blocks--;
+}
+
+static void init_chain_block_buckets(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHAIN_BUCKETS; i++)
+               chain_block_buckets[i] = -1;
+
+       add_chain_block(0, ARRAY_SIZE(chain_hlocks));
+}
+
+/*
+ * Return offset of a chain block of the right size or -1 if not found.
+ *
+ * Fairly simple worst-fit allocator with the addition of a number of size
+ * specific free lists.
+ */
+static int alloc_chain_hlocks(int req)
+{
+       int bucket, curr, size;
+
+       /*
+        * We rely on the MSB to act as an escape bit to denote freelist
+        * pointers. Make sure this bit isn't set in 'normal' class_idx usage.
+        */
+       BUILD_BUG_ON((MAX_LOCKDEP_KEYS-1) & CHAIN_BLK_FLAG);
+
+       init_data_structures_once();
+
+       if (nr_free_chain_hlocks < req)
+               return -1;
+
+       /*
+        * We require a minimum of 2 (u16) entries to encode a freelist
+        * 'pointer'.
+        */
+       req = max(req, 2);
+       bucket = size_to_bucket(req);
+       curr = chain_block_buckets[bucket];
+
+       if (bucket) {
+               if (curr >= 0) {
+                       del_chain_block(bucket, req, chain_block_next(curr));
+                       return curr;
+               }
+               /* Try bucket 0 */
+               curr = chain_block_buckets[0];
+       }
+
+       /*
+        * The variable sized freelist is sorted by size; the first entry is
+        * the largest. Use it if it fits.
+        */
+       if (curr >= 0) {
+               size = chain_block_size(curr);
+               if (likely(size >= req)) {
+                       del_chain_block(0, size, chain_block_next(curr));
+                       add_chain_block(curr + req, size - req);
+                       return curr;
+               }
+       }
+
+       /*
+        * Last resort, split a block in a larger sized bucket.
+        */
+       for (size = MAX_CHAIN_BUCKETS; size > req; size--) {
+               bucket = size_to_bucket(size);
+               curr = chain_block_buckets[bucket];
+               if (curr < 0)
+                       continue;
+
+               del_chain_block(bucket, size, chain_block_next(curr));
+               add_chain_block(curr + req, size - req);
+               return curr;
+       }
+
+       return -1;
+}
+
+static inline void free_chain_hlocks(int base, int size)
+{
+       add_chain_block(base, max(size, 2));
+}
 
 struct lock_class *lock_chain_get_class(struct lock_chain *chain, int i)
 {
@@ -2803,7 +3070,7 @@ static inline int add_chain_cache(struct task_struct *curr,
         * disabled to make this an IRQ-safe lock.. for recursion reasons
         * lockdep won't complain about its own locking errors.
         */
-       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+       if (lockdep_assert_locked())
                return 0;
 
        chain = alloc_lock_chain();
@@ -2824,15 +3091,8 @@ static inline int add_chain_cache(struct task_struct *curr,
        BUILD_BUG_ON((1UL << 6)  <= ARRAY_SIZE(curr->held_locks));
        BUILD_BUG_ON((1UL << 8*sizeof(chain_hlocks[0])) <= ARRAY_SIZE(lock_classes));
 
-       if (likely(nr_chain_hlocks + chain->depth <= MAX_LOCKDEP_CHAIN_HLOCKS)) {
-               chain->base = nr_chain_hlocks;
-               for (j = 0; j < chain->depth - 1; j++, i++) {
-                       int lock_id = curr->held_locks[i].class_idx;
-                       chain_hlocks[chain->base + j] = lock_id;
-               }
-               chain_hlocks[chain->base + j] = class - lock_classes;
-               nr_chain_hlocks += chain->depth;
-       } else {
+       j = alloc_chain_hlocks(chain->depth);
+       if (j < 0) {
                if (!debug_locks_off_graph_unlock())
                        return 0;
 
@@ -2841,9 +3101,16 @@ static inline int add_chain_cache(struct task_struct *curr,
                return 0;
        }
 
+       chain->base = j;
+       for (j = 0; j < chain->depth - 1; j++, i++) {
+               int lock_id = curr->held_locks[i].class_idx;
+
+               chain_hlocks[chain->base + j] = lock_id;
+       }
+       chain_hlocks[chain->base + j] = class - lock_classes;
        hlist_add_head_rcu(&chain->entry, hash_head);
        debug_atomic_inc(chain_lookup_misses);
-       inc_chains();
+       inc_chains(chain->irq_context);
 
        return 1;
 }
@@ -2987,6 +3254,8 @@ static inline int validate_chain(struct task_struct *curr,
 {
        return 1;
 }
+
+static void init_chain_block_buckets(void)     { }
 #endif /* CONFIG_PROVE_LOCKING */
 
 /*
@@ -3081,10 +3350,10 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
 
        pr_warn("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] takes:\n",
                curr->comm, task_pid_nr(curr),
-               trace_hardirq_context(curr), hardirq_count() >> HARDIRQ_SHIFT,
-               trace_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
-               trace_hardirqs_enabled(curr),
-               trace_softirqs_enabled(curr));
+               lockdep_hardirq_context(curr), hardirq_count() >> HARDIRQ_SHIFT,
+               lockdep_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
+               lockdep_hardirqs_enabled(curr),
+               lockdep_softirqs_enabled(curr));
        print_lock(this);
 
        pr_warn("{%s} state was registered at:\n", usage_str[prev_bit]);
@@ -3429,9 +3698,9 @@ void lockdep_hardirqs_on(unsigned long ip)
        if (DEBUG_LOCKS_WARN_ON(current->hardirq_context))
                return;
 
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        __trace_hardirqs_on_caller(ip);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
 }
 NOKPROBE_SYMBOL(lockdep_hardirqs_on);
 
@@ -3468,7 +3737,7 @@ NOKPROBE_SYMBOL(lockdep_hardirqs_off);
 /*
  * Softirqs will be enabled:
  */
-void trace_softirqs_on(unsigned long ip)
+void lockdep_softirqs_on(unsigned long ip)
 {
        struct task_struct *curr = current;
 
@@ -3487,7 +3756,7 @@ void trace_softirqs_on(unsigned long ip)
                return;
        }
 
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        /*
         * We'll do an OFF -> ON transition:
         */
@@ -3502,13 +3771,13 @@ void trace_softirqs_on(unsigned long ip)
         */
        if (curr->hardirqs_enabled)
                mark_held_locks(curr, LOCK_ENABLED_SOFTIRQ);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
 }
 
 /*
  * Softirqs were disabled:
  */
-void trace_softirqs_off(unsigned long ip)
+void lockdep_softirqs_off(unsigned long ip)
 {
        struct task_struct *curr = current;
 
@@ -3596,7 +3865,8 @@ lock_used:
 
 static inline unsigned int task_irq_context(struct task_struct *task)
 {
-       return 2 * !!task->hardirq_context + !!task->softirq_context;
+       return LOCK_CHAIN_HARDIRQ_CONTEXT * !!task->hardirq_context +
+              LOCK_CHAIN_SOFTIRQ_CONTEXT * !!task->softirq_context;
 }
 
 static int separate_irq_context(struct task_struct *curr,
@@ -3682,6 +3952,113 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
        return ret;
 }
 
+static int
+print_lock_invalid_wait_context(struct task_struct *curr,
+                               struct held_lock *hlock)
+{
+       if (!debug_locks_off())
+               return 0;
+       if (debug_locks_silent)
+               return 0;
+
+       pr_warn("\n");
+       pr_warn("=============================\n");
+       pr_warn("[ BUG: Invalid wait context ]\n");
+       print_kernel_ident();
+       pr_warn("-----------------------------\n");
+
+       pr_warn("%s/%d is trying to lock:\n", curr->comm, task_pid_nr(curr));
+       print_lock(hlock);
+
+       pr_warn("other info that might help us debug this:\n");
+       lockdep_print_held_locks(curr);
+
+       pr_warn("stack backtrace:\n");
+       dump_stack();
+
+       return 0;
+}
+
+/*
+ * Verify the wait_type context.
+ *
+ * This check validates we takes locks in the right wait-type order; that is it
+ * ensures that we do not take mutexes inside spinlocks and do not attempt to
+ * acquire spinlocks inside raw_spinlocks and the sort.
+ *
+ * The entire thing is slightly more complex because of RCU, RCU is a lock that
+ * can be taken from (pretty much) any context but also has constraints.
+ * However when taken in a stricter environment the RCU lock does not loosen
+ * the constraints.
+ *
+ * Therefore we must look for the strictest environment in the lock stack and
+ * compare that to the lock we're trying to acquire.
+ */
+static int check_wait_context(struct task_struct *curr, struct held_lock *next)
+{
+       short next_inner = hlock_class(next)->wait_type_inner;
+       short next_outer = hlock_class(next)->wait_type_outer;
+       short curr_inner;
+       int depth;
+
+       if (!curr->lockdep_depth || !next_inner || next->trylock)
+               return 0;
+
+       if (!next_outer)
+               next_outer = next_inner;
+
+       /*
+        * Find start of current irq_context..
+        */
+       for (depth = curr->lockdep_depth - 1; depth >= 0; depth--) {
+               struct held_lock *prev = curr->held_locks + depth;
+               if (prev->irq_context != next->irq_context)
+                       break;
+       }
+       depth++;
+
+       /*
+        * Set appropriate wait type for the context; for IRQs we have to take
+        * into account force_irqthread as that is implied by PREEMPT_RT.
+        */
+       if (curr->hardirq_context) {
+               /*
+                * Check if force_irqthreads will run us threaded.
+                */
+               if (curr->hardirq_threaded || curr->irq_config)
+                       curr_inner = LD_WAIT_CONFIG;
+               else
+                       curr_inner = LD_WAIT_SPIN;
+       } else if (curr->softirq_context) {
+               /*
+                * Softirqs are always threaded.
+                */
+               curr_inner = LD_WAIT_CONFIG;
+       } else {
+               curr_inner = LD_WAIT_MAX;
+       }
+
+       for (; depth < curr->lockdep_depth; depth++) {
+               struct held_lock *prev = curr->held_locks + depth;
+               short prev_inner = hlock_class(prev)->wait_type_inner;
+
+               if (prev_inner) {
+                       /*
+                        * We can have a bigger inner than a previous one
+                        * when outer is smaller than inner, as with RCU.
+                        *
+                        * Also due to trylocks.
+                        */
+                       curr_inner = min(curr_inner, prev_inner);
+               }
+       }
+
+       if (next_outer > curr_inner)
+               return print_lock_invalid_wait_context(curr, next);
+
+       return 0;
+}
+
 #else /* CONFIG_PROVE_LOCKING */
 
 static inline int
@@ -3701,13 +4078,20 @@ static inline int separate_irq_context(struct task_struct *curr,
        return 0;
 }
 
+static inline int check_wait_context(struct task_struct *curr,
+                                    struct held_lock *next)
+{
+       return 0;
+}
+
 #endif /* CONFIG_PROVE_LOCKING */
 
 /*
  * Initialize a lock instance's lock-class mapping info:
  */
-void lockdep_init_map(struct lockdep_map *lock, const char *name,
-                     struct lock_class_key *key, int subclass)
+void lockdep_init_map_waits(struct lockdep_map *lock, const char *name,
+                           struct lock_class_key *key, int subclass,
+                           short inner, short outer)
 {
        int i;
 
@@ -3728,6 +4112,9 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
 
        lock->name = name;
 
+       lock->wait_type_outer = outer;
+       lock->wait_type_inner = inner;
+
        /*
         * No key, no joy, we need to hash something.
         */
@@ -3755,13 +4142,13 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
                        return;
 
                raw_local_irq_save(flags);
-               current->lockdep_recursion = 1;
+               current->lockdep_recursion++;
                register_lock_class(lock, subclass, 1);
-               current->lockdep_recursion = 0;
+               lockdep_recursion_finish();
                raw_local_irq_restore(flags);
        }
 }
-EXPORT_SYMBOL_GPL(lockdep_init_map);
+EXPORT_SYMBOL_GPL(lockdep_init_map_waits);
 
 struct lock_class_key __lockdep_no_validate__;
 EXPORT_SYMBOL_GPL(__lockdep_no_validate__);
@@ -3862,7 +4249,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 
        class_idx = class - lock_classes;
 
-       if (depth) {
+       if (depth) { /* we're holding locks */
                hlock = curr->held_locks + depth - 1;
                if (hlock->class_idx == class_idx && nest_lock) {
                        if (!references)
@@ -3904,6 +4291,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 #endif
        hlock->pin_count = pin_count;
 
+       if (check_wait_context(curr, hlock))
+               return 0;
+
        /* Initialize the lock usage bit */
        if (!mark_usage(curr, hlock, check))
                return 0;
@@ -4139,7 +4529,9 @@ __lock_set_class(struct lockdep_map *lock, const char *name,
                return 0;
        }
 
-       lockdep_init_map(lock, name, key, 0);
+       lockdep_init_map_waits(lock, name, key, 0,
+                              lock->wait_type_inner,
+                              lock->wait_type_outer);
        class = register_lock_class(lock, subclass, 0);
        hlock->class_idx = class - lock_classes;
 
@@ -4437,11 +4829,11 @@ void lock_set_class(struct lockdep_map *lock, const char *name,
                return;
 
        raw_local_irq_save(flags);
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        check_flags(flags);
        if (__lock_set_class(lock, name, key, subclass, ip))
                check_chain_key(current);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_set_class);
@@ -4454,15 +4846,45 @@ void lock_downgrade(struct lockdep_map *lock, unsigned long ip)
                return;
 
        raw_local_irq_save(flags);
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        check_flags(flags);
        if (__lock_downgrade(lock, ip))
                check_chain_key(current);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_downgrade);
 
+/* NMI context !!! */
+static void verify_lock_unused(struct lockdep_map *lock, struct held_lock *hlock, int subclass)
+{
+#ifdef CONFIG_PROVE_LOCKING
+       struct lock_class *class = look_up_lock_class(lock, subclass);
+
+       /* if it doesn't have a class (yet), it certainly hasn't been used yet */
+       if (!class)
+               return;
+
+       if (!(class->usage_mask & LOCK_USED))
+               return;
+
+       hlock->class_idx = class - lock_classes;
+
+       print_usage_bug(current, hlock, LOCK_USED, LOCK_USAGE_STATES);
+#endif
+}
+
+static bool lockdep_nmi(void)
+{
+       if (current->lockdep_recursion & LOCKDEP_RECURSION_MASK)
+               return false;
+
+       if (!in_nmi())
+               return false;
+
+       return true;
+}
+
 /*
  * We are not always called with irqs disabled - do that here,
  * and also avoid lockdep recursion:
@@ -4473,17 +4895,34 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 {
        unsigned long flags;
 
-       if (unlikely(current->lockdep_recursion))
+       if (unlikely(current->lockdep_recursion)) {
+               /* XXX allow trylock from NMI ?!? */
+               if (lockdep_nmi() && !trylock) {
+                       struct held_lock hlock;
+
+                       hlock.acquire_ip = ip;
+                       hlock.instance = lock;
+                       hlock.nest_lock = nest_lock;
+                       hlock.irq_context = 2; // XXX
+                       hlock.trylock = trylock;
+                       hlock.read = read;
+                       hlock.check = check;
+                       hlock.hardirqs_off = true;
+                       hlock.references = 0;
+
+                       verify_lock_unused(lock, &hlock, subclass);
+               }
                return;
+       }
 
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        trace_lock_acquire(lock, subclass, trylock, read, check, nest_lock, ip);
        __lock_acquire(lock, subclass, trylock, read, check,
                       irqs_disabled_flags(flags), nest_lock, ip, 0, 0);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_acquire);
@@ -4497,11 +4936,11 @@ void lock_release(struct lockdep_map *lock, unsigned long ip)
 
        raw_local_irq_save(flags);
        check_flags(flags);
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        trace_lock_release(lock, ip);
        if (__lock_release(lock, ip))
                check_chain_key(current);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_release);
@@ -4517,9 +4956,9 @@ int lock_is_held_type(const struct lockdep_map *lock, int read)
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        ret = __lock_is_held(lock, read);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 
        return ret;
@@ -4538,9 +4977,9 @@ struct pin_cookie lock_pin_lock(struct lockdep_map *lock)
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        cookie = __lock_pin_lock(lock);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 
        return cookie;
@@ -4557,9 +4996,9 @@ void lock_repin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        __lock_repin_lock(lock, cookie);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_repin_lock);
@@ -4574,9 +5013,9 @@ void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
        raw_local_irq_save(flags);
        check_flags(flags);
 
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        __lock_unpin_lock(lock, cookie);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_unpin_lock);
@@ -4712,10 +5151,10 @@ void lock_contended(struct lockdep_map *lock, unsigned long ip)
 
        raw_local_irq_save(flags);
        check_flags(flags);
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        trace_lock_contended(lock, ip);
        __lock_contended(lock, ip);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_contended);
@@ -4732,9 +5171,9 @@ void lock_acquired(struct lockdep_map *lock, unsigned long ip)
 
        raw_local_irq_save(flags);
        check_flags(flags);
-       current->lockdep_recursion = 1;
+       current->lockdep_recursion++;
        __lock_acquired(lock, ip);
-       current->lockdep_recursion = 0;
+       lockdep_recursion_finish();
        raw_local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(lock_acquired);
@@ -4768,57 +5207,33 @@ static void remove_class_from_lock_chain(struct pending_free *pf,
                                         struct lock_class *class)
 {
 #ifdef CONFIG_PROVE_LOCKING
-       struct lock_chain *new_chain;
-       u64 chain_key;
        int i;
 
        for (i = chain->base; i < chain->base + chain->depth; i++) {
                if (chain_hlocks[i] != class - lock_classes)
                        continue;
-               /* The code below leaks one chain_hlock[] entry. */
-               if (--chain->depth > 0) {
-                       memmove(&chain_hlocks[i], &chain_hlocks[i + 1],
-                               (chain->base + chain->depth - i) *
-                               sizeof(chain_hlocks[0]));
-               }
                /*
                 * Each lock class occurs at most once in a lock chain so once
                 * we found a match we can break out of this loop.
                 */
-               goto recalc;
+               goto free_lock_chain;
        }
        /* Since the chain has not been modified, return. */
        return;
 
-recalc:
-       chain_key = INITIAL_CHAIN_KEY;
-       for (i = chain->base; i < chain->base + chain->depth; i++)
-               chain_key = iterate_chain_key(chain_key, chain_hlocks[i]);
-       if (chain->depth && chain->chain_key == chain_key)
-               return;
+free_lock_chain:
+       free_chain_hlocks(chain->base, chain->depth);
        /* Overwrite the chain key for concurrent RCU readers. */
-       WRITE_ONCE(chain->chain_key, chain_key);
+       WRITE_ONCE(chain->chain_key, INITIAL_CHAIN_KEY);
+       dec_chains(chain->irq_context);
+
        /*
         * Note: calling hlist_del_rcu() from inside a
         * hlist_for_each_entry_rcu() loop is safe.
         */
        hlist_del_rcu(&chain->entry);
        __set_bit(chain - lock_chains, pf->lock_chains_being_freed);
-       if (chain->depth == 0)
-               return;
-       /*
-        * If the modified lock chain matches an existing lock chain, drop
-        * the modified lock chain.
-        */
-       if (lookup_chain_cache(chain_key))
-               return;
-       new_chain = alloc_lock_chain();
-       if (WARN_ON_ONCE(!new_chain)) {
-               debug_locks_off();
-               return;
-       }
-       *new_chain = *chain;
-       hlist_add_head_rcu(&new_chain->entry, chainhashentry(chain_key));
+       nr_zapped_lock_chains++;
 #endif
 }
 
@@ -4874,6 +5289,7 @@ static void zap_class(struct pending_free *pf, struct lock_class *class)
        }
 
        remove_class_from_lock_chains(pf, class);
+       nr_zapped_classes++;
 }
 
 static void reinit_class(struct lock_class *class)
@@ -4958,8 +5374,7 @@ static void free_zapped_rcu(struct rcu_head *ch)
                return;
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
-       current->lockdep_recursion = 1;
+       lockdep_lock();
 
        /* closed head */
        pf = delayed_free.pf + (delayed_free.index ^ 1);
@@ -4971,8 +5386,7 @@ static void free_zapped_rcu(struct rcu_head *ch)
         */
        call_rcu_zapped(delayed_free.pf + delayed_free.index);
 
-       current->lockdep_recursion = 0;
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 }
 
@@ -5017,13 +5431,11 @@ static void lockdep_free_key_range_reg(void *start, unsigned long size)
        init_data_structures_once();
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
-       current->lockdep_recursion = 1;
+       lockdep_lock();
        pf = get_pending_free();
        __lockdep_free_key_range(pf, start, size);
        call_rcu_zapped(pf);
-       current->lockdep_recursion = 0;
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 
        /*
@@ -5045,10 +5457,10 @@ static void lockdep_free_key_range_imm(void *start, unsigned long size)
        init_data_structures_once();
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        __lockdep_free_key_range(pf, start, size);
        __free_zapped_classes(pf);
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 }
 
@@ -5144,10 +5556,10 @@ static void lockdep_reset_lock_imm(struct lockdep_map *lock)
        unsigned long flags;
 
        raw_local_irq_save(flags);
-       arch_spin_lock(&lockdep_lock);
+       lockdep_lock();
        __lockdep_reset_lock(pf, lock);
        __free_zapped_classes(pf);
-       arch_spin_unlock(&lockdep_lock);
+       lockdep_unlock();
        raw_local_irq_restore(flags);
 }
 
index 18d85ae..baca699 100644 (file)
@@ -106,6 +106,12 @@ static const unsigned long LOCKF_USED_IN_IRQ_READ =
 #define STACK_TRACE_HASH_SIZE  16384
 #endif
 
+/*
+ * Bit definitions for lock_chain.irq_context
+ */
+#define LOCK_CHAIN_SOFTIRQ_CONTEXT     (1 << 0)
+#define LOCK_CHAIN_HARDIRQ_CONTEXT     (1 << 1)
+
 #define MAX_LOCKDEP_CHAINS     (1UL << MAX_LOCKDEP_CHAINS_BITS)
 
 #define MAX_LOCKDEP_CHAIN_HLOCKS (MAX_LOCKDEP_CHAINS*5)
@@ -124,17 +130,21 @@ extern const char *__get_key_name(const struct lockdep_subclass_key *key,
 struct lock_class *lock_chain_get_class(struct lock_chain *chain, int i);
 
 extern unsigned long nr_lock_classes;
+extern unsigned long nr_zapped_classes;
+extern unsigned long nr_zapped_lock_chains;
 extern unsigned long nr_list_entries;
 long lockdep_next_lockchain(long i);
 unsigned long lock_chain_count(void);
-extern int nr_chain_hlocks;
 extern unsigned long nr_stack_trace_entries;
 
 extern unsigned int nr_hardirq_chains;
 extern unsigned int nr_softirq_chains;
 extern unsigned int nr_process_chains;
-extern unsigned int max_lockdep_depth;
+extern unsigned int nr_free_chain_hlocks;
+extern unsigned int nr_lost_chain_hlocks;
+extern unsigned int nr_large_chain_blocks;
 
+extern unsigned int max_lockdep_depth;
 extern unsigned int max_bfs_queue_depth;
 
 #ifdef CONFIG_PROVE_LOCKING
index 231684c..5525cd3 100644 (file)
@@ -128,15 +128,22 @@ static int lc_show(struct seq_file *m, void *v)
        struct lock_chain *chain = v;
        struct lock_class *class;
        int i;
+       static const char * const irq_strs[] = {
+               [0]                          = "0",
+               [LOCK_CHAIN_HARDIRQ_CONTEXT] = "hardirq",
+               [LOCK_CHAIN_SOFTIRQ_CONTEXT] = "softirq",
+               [LOCK_CHAIN_SOFTIRQ_CONTEXT|
+                LOCK_CHAIN_HARDIRQ_CONTEXT] = "hardirq|softirq",
+       };
 
        if (v == SEQ_START_TOKEN) {
-               if (nr_chain_hlocks > MAX_LOCKDEP_CHAIN_HLOCKS)
+               if (!nr_free_chain_hlocks)
                        seq_printf(m, "(buggered) ");
                seq_printf(m, "all lock chains:\n");
                return 0;
        }
 
-       seq_printf(m, "irq_context: %d\n", chain->irq_context);
+       seq_printf(m, "irq_context: %s\n", irq_strs[chain->irq_context]);
 
        for (i = 0; i < chain->depth; i++) {
                class = lock_chain_get_class(chain, i);
@@ -271,8 +278,12 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
 #ifdef CONFIG_PROVE_LOCKING
        seq_printf(m, " dependency chains:             %11lu [max: %lu]\n",
                        lock_chain_count(), MAX_LOCKDEP_CHAINS);
-       seq_printf(m, " dependency chain hlocks:       %11d [max: %lu]\n",
-                       nr_chain_hlocks, MAX_LOCKDEP_CHAIN_HLOCKS);
+       seq_printf(m, " dependency chain hlocks used:  %11lu [max: %lu]\n",
+                       MAX_LOCKDEP_CHAIN_HLOCKS -
+                       (nr_free_chain_hlocks + nr_lost_chain_hlocks),
+                       MAX_LOCKDEP_CHAIN_HLOCKS);
+       seq_printf(m, " dependency chain hlocks lost:  %11u\n",
+                       nr_lost_chain_hlocks);
 #endif
 
 #ifdef CONFIG_TRACE_IRQFLAGS
@@ -336,6 +347,18 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
        seq_printf(m, " debug_locks:                   %11u\n",
                        debug_locks);
 
+       /*
+        * Zappped classes and lockdep data buffers reuse statistics.
+        */
+       seq_puts(m, "\n");
+       seq_printf(m, " zapped classes:                %11lu\n",
+                       nr_zapped_classes);
+#ifdef CONFIG_PROVE_LOCKING
+       seq_printf(m, " zapped lock chains:            %11lu\n",
+                       nr_zapped_lock_chains);
+       seq_printf(m, " large chain blocks:            %11u\n",
+                       nr_large_chain_blocks);
+#endif
        return 0;
 }
 
index 99475a6..5efbfc6 100644 (file)
@@ -618,7 +618,7 @@ static struct lock_torture_ops percpu_rwsem_lock_ops = {
 static int lock_torture_writer(void *arg)
 {
        struct lock_stress_stats *lwsp = arg;
-       static DEFINE_TORTURE_RANDOM(rand);
+       DEFINE_TORTURE_RANDOM(rand);
 
        VERBOSE_TOROUT_STRING("lock_torture_writer task started");
        set_user_nice(current, MAX_NICE);
@@ -655,7 +655,7 @@ static int lock_torture_writer(void *arg)
 static int lock_torture_reader(void *arg)
 {
        struct lock_stress_stats *lrsp = arg;
-       static DEFINE_TORTURE_RANDOM(rand);
+       DEFINE_TORTURE_RANDOM(rand);
 
        VERBOSE_TOROUT_STRING("lock_torture_reader task started");
        set_user_nice(current, MAX_NICE);
@@ -696,15 +696,16 @@ static void __torture_print_stats(char *page,
                if (statp[i].n_lock_fail)
                        fail = true;
                sum += statp[i].n_lock_acquired;
-               if (max < statp[i].n_lock_fail)
-                       max = statp[i].n_lock_fail;
-               if (min > statp[i].n_lock_fail)
-                       min = statp[i].n_lock_fail;
+               if (max < statp[i].n_lock_acquired)
+                       max = statp[i].n_lock_acquired;
+               if (min > statp[i].n_lock_acquired)
+                       min = statp[i].n_lock_acquired;
        }
        page += sprintf(page,
                        "%s:  Total: %lld  Max/Min: %ld/%ld %s  Fail: %d %s\n",
                        write ? "Writes" : "Reads ",
-                       sum, max, min, max / 2 > min ? "???" : "",
+                       sum, max, min,
+                       !onoff_interval && max / 2 > min ? "???" : "",
                        fail, fail ? "!!!" : "");
        if (fail)
                atomic_inc(&cxt.n_lock_torture_errors);
index 771d4ca..a7276aa 100644 (file)
@@ -85,7 +85,7 @@ void debug_mutex_init(struct mutex *lock, const char *name,
         * Make sure we are not reinitializing a held lock:
         */
        debug_check_no_locks_freed((void *)lock, sizeof(*lock));
-       lockdep_init_map(&lock->dep_map, name, key, 0);
+       lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_SLEEP);
 #endif
        lock->magic = lock;
 }
index 364d38a..a008a1b 100644 (file)
@@ -1,27 +1,29 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <linux/atomic.h>
-#include <linux/rwsem.h>
 #include <linux/percpu.h>
+#include <linux/wait.h>
 #include <linux/lockdep.h>
 #include <linux/percpu-rwsem.h>
 #include <linux/rcupdate.h>
 #include <linux/sched.h>
+#include <linux/sched/task.h>
 #include <linux/errno.h>
 
-#include "rwsem.h"
-
 int __percpu_init_rwsem(struct percpu_rw_semaphore *sem,
-                       const char *name, struct lock_class_key *rwsem_key)
+                       const char *name, struct lock_class_key *key)
 {
        sem->read_count = alloc_percpu(int);
        if (unlikely(!sem->read_count))
                return -ENOMEM;
 
-       /* ->rw_sem represents the whole percpu_rw_semaphore for lockdep */
        rcu_sync_init(&sem->rss);
-       __init_rwsem(&sem->rw_sem, name, rwsem_key);
        rcuwait_init(&sem->writer);
-       sem->readers_block = 0;
+       init_waitqueue_head(&sem->waiters);
+       atomic_set(&sem->block, 0);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       debug_check_no_locks_freed((void *)sem, sizeof(*sem));
+       lockdep_init_map(&sem->dep_map, name, key, 0);
+#endif
        return 0;
 }
 EXPORT_SYMBOL_GPL(__percpu_init_rwsem);
@@ -41,73 +43,139 @@ void percpu_free_rwsem(struct percpu_rw_semaphore *sem)
 }
 EXPORT_SYMBOL_GPL(percpu_free_rwsem);
 
-int __percpu_down_read(struct percpu_rw_semaphore *sem, int try)
+static bool __percpu_down_read_trylock(struct percpu_rw_semaphore *sem)
 {
+       __this_cpu_inc(*sem->read_count);
+
        /*
         * Due to having preemption disabled the decrement happens on
         * the same CPU as the increment, avoiding the
         * increment-on-one-CPU-and-decrement-on-another problem.
         *
-        * If the reader misses the writer's assignment of readers_block, then
-        * the writer is guaranteed to see the reader's increment.
+        * If the reader misses the writer's assignment of sem->block, then the
+        * writer is guaranteed to see the reader's increment.
         *
         * Conversely, any readers that increment their sem->read_count after
-        * the writer looks are guaranteed to see the readers_block value,
-        * which in turn means that they are guaranteed to immediately
-        * decrement their sem->read_count, so that it doesn't matter that the
-        * writer missed them.
+        * the writer looks are guaranteed to see the sem->block value, which
+        * in turn means that they are guaranteed to immediately decrement
+        * their sem->read_count, so that it doesn't matter that the writer
+        * missed them.
         */
 
        smp_mb(); /* A matches D */
 
        /*
-        * If !readers_block the critical section starts here, matched by the
+        * If !sem->block the critical section starts here, matched by the
         * release in percpu_up_write().
         */
-       if (likely(!smp_load_acquire(&sem->readers_block)))
+       if (likely(!atomic_read_acquire(&sem->block)))
+               return true;
+
+       __this_cpu_dec(*sem->read_count);
+
+       /* Prod writer to re-evaluate readers_active_check() */
+       rcuwait_wake_up(&sem->writer);
+
+       return false;
+}
+
+static inline bool __percpu_down_write_trylock(struct percpu_rw_semaphore *sem)
+{
+       if (atomic_read(&sem->block))
+               return false;
+
+       return atomic_xchg(&sem->block, 1) == 0;
+}
+
+static bool __percpu_rwsem_trylock(struct percpu_rw_semaphore *sem, bool reader)
+{
+       if (reader) {
+               bool ret;
+
+               preempt_disable();
+               ret = __percpu_down_read_trylock(sem);
+               preempt_enable();
+
+               return ret;
+       }
+       return __percpu_down_write_trylock(sem);
+}
+
+/*
+ * The return value of wait_queue_entry::func means:
+ *
+ *  <0 - error, wakeup is terminated and the error is returned
+ *   0 - no wakeup, a next waiter is tried
+ *  >0 - woken, if EXCLUSIVE, counted towards @nr_exclusive.
+ *
+ * We use EXCLUSIVE for both readers and writers to preserve FIFO order,
+ * and play games with the return value to allow waking multiple readers.
+ *
+ * Specifically, we wake readers until we've woken a single writer, or until a
+ * trylock fails.
+ */
+static int percpu_rwsem_wake_function(struct wait_queue_entry *wq_entry,
+                                     unsigned int mode, int wake_flags,
+                                     void *key)
+{
+       struct task_struct *p = get_task_struct(wq_entry->private);
+       bool reader = wq_entry->flags & WQ_FLAG_CUSTOM;
+       struct percpu_rw_semaphore *sem = key;
+
+       /* concurrent against percpu_down_write(), can get stolen */
+       if (!__percpu_rwsem_trylock(sem, reader))
                return 1;
 
-       /*
-        * Per the above comment; we still have preemption disabled and
-        * will thus decrement on the same CPU as we incremented.
-        */
-       __percpu_up_read(sem);
+       list_del_init(&wq_entry->entry);
+       smp_store_release(&wq_entry->private, NULL);
 
-       if (try)
-               return 0;
+       wake_up_process(p);
+       put_task_struct(p);
 
-       /*
-        * We either call schedule() in the wait, or we'll fall through
-        * and reschedule on the preempt_enable() in percpu_down_read().
-        */
-       preempt_enable_no_resched();
+       return !reader; /* wake (readers until) 1 writer */
+}
+
+static void percpu_rwsem_wait(struct percpu_rw_semaphore *sem, bool reader)
+{
+       DEFINE_WAIT_FUNC(wq_entry, percpu_rwsem_wake_function);
+       bool wait;
 
+       spin_lock_irq(&sem->waiters.lock);
        /*
-        * Avoid lockdep for the down/up_read() we already have them.
+        * Serialize against the wakeup in percpu_up_write(), if we fail
+        * the trylock, the wakeup must see us on the list.
         */
-       __down_read(&sem->rw_sem);
-       this_cpu_inc(*sem->read_count);
-       __up_read(&sem->rw_sem);
+       wait = !__percpu_rwsem_trylock(sem, reader);
+       if (wait) {
+               wq_entry.flags |= WQ_FLAG_EXCLUSIVE | reader * WQ_FLAG_CUSTOM;
+               __add_wait_queue_entry_tail(&sem->waiters, &wq_entry);
+       }
+       spin_unlock_irq(&sem->waiters.lock);
 
-       preempt_disable();
-       return 1;
+       while (wait) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               if (!smp_load_acquire(&wq_entry.private))
+                       break;
+               schedule();
+       }
+       __set_current_state(TASK_RUNNING);
 }
-EXPORT_SYMBOL_GPL(__percpu_down_read);
 
-void __percpu_up_read(struct percpu_rw_semaphore *sem)
+bool __percpu_down_read(struct percpu_rw_semaphore *sem, bool try)
 {
-       smp_mb(); /* B matches C */
-       /*
-        * In other words, if they see our decrement (presumably to aggregate
-        * zero, as that is the only time it matters) they will also see our
-        * critical section.
-        */
-       __this_cpu_dec(*sem->read_count);
+       if (__percpu_down_read_trylock(sem))
+               return true;
 
-       /* Prod writer to recheck readers_active */
-       rcuwait_wake_up(&sem->writer);
+       if (try)
+               return false;
+
+       preempt_enable();
+       percpu_rwsem_wait(sem, /* .reader = */ true);
+       preempt_disable();
+
+       return true;
 }
-EXPORT_SYMBOL_GPL(__percpu_up_read);
+EXPORT_SYMBOL_GPL(__percpu_down_read);
 
 #define per_cpu_sum(var)                                               \
 ({                                                                     \
@@ -124,6 +192,8 @@ EXPORT_SYMBOL_GPL(__percpu_up_read);
  * zero.  If this sum is zero, then it is stable due to the fact that if any
  * newly arriving readers increment a given counter, they will immediately
  * decrement that same counter.
+ *
+ * Assumes sem->block is set.
  */
 static bool readers_active_check(struct percpu_rw_semaphore *sem)
 {
@@ -142,32 +212,36 @@ static bool readers_active_check(struct percpu_rw_semaphore *sem)
 
 void percpu_down_write(struct percpu_rw_semaphore *sem)
 {
+       might_sleep();
+       rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
+
        /* Notify readers to take the slow path. */
        rcu_sync_enter(&sem->rss);
 
-       down_write(&sem->rw_sem);
-
        /*
-        * Notify new readers to block; up until now, and thus throughout the
-        * longish rcu_sync_enter() above, new readers could still come in.
+        * Try set sem->block; this provides writer-writer exclusion.
+        * Having sem->block set makes new readers block.
         */
-       WRITE_ONCE(sem->readers_block, 1);
+       if (!__percpu_down_write_trylock(sem))
+               percpu_rwsem_wait(sem, /* .reader = */ false);
 
-       smp_mb(); /* D matches A */
+       /* smp_mb() implied by __percpu_down_write_trylock() on success -- D matches A */
 
        /*
-        * If they don't see our writer of readers_block, then we are
-        * guaranteed to see their sem->read_count increment, and therefore
-        * will wait for them.
+        * If they don't see our store of sem->block, then we are guaranteed to
+        * see their sem->read_count increment, and therefore will wait for
+        * them.
         */
 
-       /* Wait for all now active readers to complete. */
-       rcuwait_wait_event(&sem->writer, readers_active_check(sem));
+       /* Wait for all active readers to complete. */
+       rcuwait_wait_event(&sem->writer, readers_active_check(sem), TASK_UNINTERRUPTIBLE);
 }
 EXPORT_SYMBOL_GPL(percpu_down_write);
 
 void percpu_up_write(struct percpu_rw_semaphore *sem)
 {
+       rwsem_release(&sem->dep_map, _RET_IP_);
+
        /*
         * Signal the writer is done, no fast path yet.
         *
@@ -178,12 +252,12 @@ void percpu_up_write(struct percpu_rw_semaphore *sem)
         * Therefore we force it through the slow path which guarantees an
         * acquire and thereby guarantees the critical section's consistency.
         */
-       smp_store_release(&sem->readers_block, 0);
+       atomic_set_release(&sem->block, 0);
 
        /*
-        * Release the write lock, this will allow readers back in the game.
+        * Prod any pending reader/writer to make progress.
         */
-       up_write(&sem->rw_sem);
+       __wake_up(&sem->waiters, TASK_NORMAL, 1, sem);
 
        /*
         * Once this completes (at least one RCU-sched grace period hence) the
index 851bbb1..c9f090d 100644 (file)
@@ -57,7 +57,7 @@ rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner)
        if (rt_mutex_has_waiters(lock))
                val |= RT_MUTEX_HAS_WAITERS;
 
-       lock->owner = (struct task_struct *)val;
+       WRITE_ONCE(lock->owner, (struct task_struct *)val);
 }
 
 static inline void clear_rt_mutex_waiters(struct rt_mutex *lock)
index 0d9b6be..f11b9bd 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/rwsem.h>
 #include <linux/atomic.h>
 
-#include "rwsem.h"
 #include "lock_events.h"
 
 /*
@@ -329,7 +328,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name,
         * Make sure we are not reinitializing a held semaphore:
         */
        debug_check_no_locks_freed((void *)sem, sizeof(*sem));
-       lockdep_init_map(&sem->dep_map, name, key, 0);
+       lockdep_init_map_wait(&sem->dep_map, name, key, 0, LD_WAIT_SLEEP);
 #endif
 #ifdef CONFIG_DEBUG_RWSEMS
        sem->magic = sem;
@@ -660,8 +659,6 @@ static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem,
        unsigned long flags;
        bool ret = true;
 
-       BUILD_BUG_ON(!(RWSEM_OWNER_UNKNOWN & RWSEM_NONSPINNABLE));
-
        if (need_resched()) {
                lockevent_inc(rwsem_opt_fail);
                return false;
@@ -1338,7 +1335,7 @@ static struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem)
 /*
  * lock for reading
  */
-inline void __down_read(struct rw_semaphore *sem)
+static inline void __down_read(struct rw_semaphore *sem)
 {
        if (!rwsem_read_trylock(sem)) {
                rwsem_down_read_slowpath(sem, TASK_UNINTERRUPTIBLE);
@@ -1426,7 +1423,7 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
 /*
  * unlock after reading
  */
-inline void __up_read(struct rw_semaphore *sem)
+static inline void __up_read(struct rw_semaphore *sem)
 {
        long tmp;
 
index 2534ce4..e69de29 100644 (file)
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef __INTERNAL_RWSEM_H
-#define __INTERNAL_RWSEM_H
-#include <linux/rwsem.h>
-
-extern void __down_read(struct rw_semaphore *sem);
-extern void __up_read(struct rw_semaphore *sem);
-
-#endif /* __INTERNAL_RWSEM_H */
index 472dd46..b9d9308 100644 (file)
 #include <linux/export.h>
 
 void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
-                         struct lock_class_key *key)
+                         struct lock_class_key *key, short inner)
 {
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
        /*
         * Make sure we are not reinitializing a held lock:
         */
        debug_check_no_locks_freed((void *)lock, sizeof(*lock));
-       lockdep_init_map(&lock->dep_map, name, key, 0);
+       lockdep_init_map_wait(&lock->dep_map, name, key, 0, inner);
 #endif
        lock->raw_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
        lock->magic = SPINLOCK_MAGIC;
@@ -39,7 +39,7 @@ void __rwlock_init(rwlock_t *lock, const char *name,
         * Make sure we are not reinitializing a held lock:
         */
        debug_check_no_locks_freed((void *)lock, sizeof(*lock));
-       lockdep_init_map(&lock->dep_map, name, key, 0);
+       lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_CONFIG);
 #endif
        lock->raw_lock = (arch_rwlock_t) __ARCH_RW_LOCK_UNLOCKED;
        lock->magic = RWLOCK_MAGIC;
index 63d7501..5989bbb 100644 (file)
@@ -519,7 +519,7 @@ NOKPROBE_SYMBOL(notify_die);
 
 int register_die_notifier(struct notifier_block *nb)
 {
-       vmalloc_sync_all();
+       vmalloc_sync_mappings();
        return atomic_notifier_chain_register(&die_chain, nb);
 }
 EXPORT_SYMBOL_GPL(register_die_notifier);
index 0f4ecb5..647b4bb 100644 (file)
@@ -247,6 +247,16 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *set_tid,
                tmp = tmp->parent;
        }
 
+       /*
+        * ENOMEM is not the most obvious choice especially for the case
+        * where the child subreaper has already exited and the pid
+        * namespace denies the creation of any new processes. But ENOMEM
+        * is what we have exposed to userspace for a long time and it is
+        * documented behavior for pid namespaces. So we can't easily
+        * change it even if there were an error code better suited.
+        */
+       retval = -ENOMEM;
+
        if (unlikely(is_child_reaper(pid))) {
                if (pid_ns_prepare_proc(ns))
                        goto out_free;
index 83edf86..db0bed2 100644 (file)
@@ -1,31 +1,21 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * This module exposes the interface to kernel space for specifying
- * QoS dependencies.  It provides infrastructure for registration of:
+ * Power Management Quality of Service (PM QoS) support base.
  *
- * Dependents on a QoS value : register requests
- * Watchers of QoS value : get notified when target QoS value changes
+ * Copyright (C) 2020 Intel Corporation
  *
- * This QoS design is best effort based.  Dependents register their QoS needs.
- * Watchers register to keep track of the current QoS needs of the system.
+ * Authors:
+ *     Mark Gross <mgross@linux.intel.com>
+ *     Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  *
- * There are 3 basic classes of QoS parameter: latency, timeout, throughput
- * each have defined units:
- * latency: usec
- * timeout: usec <-- currently not used.
- * throughput: kbs (kilo byte / sec)
+ * Provided here is an interface for specifying PM QoS dependencies.  It allows
+ * entities depending on QoS constraints to register their requests which are
+ * aggregated as appropriate to produce effective constraints (target values)
+ * that can be monitored by entities needing to respect them, either by polling
+ * or through a built-in notification mechanism.
  *
- * There are lists of pm_qos_objects each one wrapping requests, notifiers
- *
- * User mode requests on a QOS parameter register themselves to the
- * subsystem by opening the device node /dev/... and writing there request to
- * the node.  As long as the process holds a file handle open to the node the
- * client continues to be accounted for.  Upon file release the usermode
- * request is removed and a new qos target is computed.  This way when the
- * request that the application has is cleaned up when closes the file
- * pointer or exits the pm_qos_object will get an opportunity to clean up.
- *
- * Mark Gross <mgross@linux.intel.com>
+ * In addition to the basic functionality, more specific interfaces for managing
+ * global CPU latency QoS requests and frequency QoS requests are provided.
  */
 
 /*#define DEBUG*/
  * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock
  * held, taken with _irqsave.  One lock to rule them all
  */
-struct pm_qos_object {
-       struct pm_qos_constraints *constraints;
-       struct miscdevice pm_qos_power_miscdev;
-       char *name;
-};
-
 static DEFINE_SPINLOCK(pm_qos_lock);
 
-static struct pm_qos_object null_pm_qos;
-
-static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier);
-static struct pm_qos_constraints cpu_dma_constraints = {
-       .list = PLIST_HEAD_INIT(cpu_dma_constraints.list),
-       .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-       .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-       .no_constraint_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE,
-       .type = PM_QOS_MIN,
-       .notifiers = &cpu_dma_lat_notifier,
-};
-static struct pm_qos_object cpu_dma_pm_qos = {
-       .constraints = &cpu_dma_constraints,
-       .name = "cpu_dma_latency",
-};
-
-static struct pm_qos_object *pm_qos_array[] = {
-       &null_pm_qos,
-       &cpu_dma_pm_qos,
-};
-
-static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
-               size_t count, loff_t *f_pos);
-static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
-               size_t count, loff_t *f_pos);
-static int pm_qos_power_open(struct inode *inode, struct file *filp);
-static int pm_qos_power_release(struct inode *inode, struct file *filp);
-
-static const struct file_operations pm_qos_power_fops = {
-       .write = pm_qos_power_write,
-       .read = pm_qos_power_read,
-       .open = pm_qos_power_open,
-       .release = pm_qos_power_release,
-       .llseek = noop_llseek,
-};
-
-/* unlocked internal variant */
-static inline int pm_qos_get_value(struct pm_qos_constraints *c)
+/**
+ * pm_qos_read_value - Return the current effective constraint value.
+ * @c: List of PM QoS constraint requests.
+ */
+s32 pm_qos_read_value(struct pm_qos_constraints *c)
 {
-       struct plist_node *node;
-       int total_value = 0;
+       return READ_ONCE(c->target_value);
+}
 
+static int pm_qos_get_value(struct pm_qos_constraints *c)
+{
        if (plist_head_empty(&c->list))
                return c->no_constraint_value;
 
@@ -114,111 +67,42 @@ static inline int pm_qos_get_value(struct pm_qos_constraints *c)
        case PM_QOS_MAX:
                return plist_last(&c->list)->prio;
 
-       case PM_QOS_SUM:
-               plist_for_each(node, &c->list)
-                       total_value += node->prio;
-
-               return total_value;
-
        default:
-               /* runtime check for not using enum */
-               BUG();
+               WARN(1, "Unknown PM QoS type in %s\n", __func__);
                return PM_QOS_DEFAULT_VALUE;
        }
 }
 
-s32 pm_qos_read_value(struct pm_qos_constraints *c)
-{
-       return c->target_value;
-}
-
-static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
+static void pm_qos_set_value(struct pm_qos_constraints *c, s32 value)
 {
-       c->target_value = value;
+       WRITE_ONCE(c->target_value, value);
 }
 
-static int pm_qos_debug_show(struct seq_file *s, void *unused)
-{
-       struct pm_qos_object *qos = (struct pm_qos_object *)s->private;
-       struct pm_qos_constraints *c;
-       struct pm_qos_request *req;
-       char *type;
-       unsigned long flags;
-       int tot_reqs = 0;
-       int active_reqs = 0;
-
-       if (IS_ERR_OR_NULL(qos)) {
-               pr_err("%s: bad qos param!\n", __func__);
-               return -EINVAL;
-       }
-       c = qos->constraints;
-       if (IS_ERR_OR_NULL(c)) {
-               pr_err("%s: Bad constraints on qos?\n", __func__);
-               return -EINVAL;
-       }
-
-       /* Lock to ensure we have a snapshot */
-       spin_lock_irqsave(&pm_qos_lock, flags);
-       if (plist_head_empty(&c->list)) {
-               seq_puts(s, "Empty!\n");
-               goto out;
-       }
-
-       switch (c->type) {
-       case PM_QOS_MIN:
-               type = "Minimum";
-               break;
-       case PM_QOS_MAX:
-               type = "Maximum";
-               break;
-       case PM_QOS_SUM:
-               type = "Sum";
-               break;
-       default:
-               type = "Unknown";
-       }
-
-       plist_for_each_entry(req, &c->list, node) {
-               char *state = "Default";
-
-               if ((req->node).prio != c->default_value) {
-                       active_reqs++;
-                       state = "Active";
-               }
-               tot_reqs++;
-               seq_printf(s, "%d: %d: %s\n", tot_reqs,
-                          (req->node).prio, state);
-       }
-
-       seq_printf(s, "Type=%s, Value=%d, Requests: active=%d / total=%d\n",
-                  type, pm_qos_get_value(c), active_reqs, tot_reqs);
-
-out:
-       spin_unlock_irqrestore(&pm_qos_lock, flags);
-       return 0;
-}
-
-DEFINE_SHOW_ATTRIBUTE(pm_qos_debug);
-
 /**
- * pm_qos_update_target - manages the constraints list and calls the notifiers
- *  if needed
- * @c: constraints data struct
- * @node: request to add to the list, to update or to remove
- * @action: action to take on the constraints list
- * @value: value of the request to add or update
+ * pm_qos_update_target - Update a list of PM QoS constraint requests.
+ * @c: List of PM QoS requests.
+ * @node: Target list entry.
+ * @action: Action to carry out (add, update or remove).
+ * @value: New request value for the target list entry.
  *
- * This function returns 1 if the aggregated constraint value has changed, 0
- *  otherwise.
+ * Update the given list of PM QoS constraint requests, @c, by carrying an
+ * @action involving the @node list entry and @value on it.
+ *
+ * The recognized values of @action are PM_QOS_ADD_REQ (store @value in @node
+ * and add it to the list), PM_QOS_UPDATE_REQ (remove @node from the list, store
+ * @value in it and add it to the list again), and PM_QOS_REMOVE_REQ (remove
+ * @node from the list, ignore @value).
+ *
+ * Return: 1 if the aggregate constraint value has changed, 0  otherwise.
  */
 int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
                         enum pm_qos_req_action action, int value)
 {
-       unsigned long flags;
        int prev_value, curr_value, new_value;
-       int ret;
+       unsigned long flags;
 
        spin_lock_irqsave(&pm_qos_lock, flags);
+
        prev_value = pm_qos_get_value(c);
        if (value == PM_QOS_DEFAULT_VALUE)
                new_value = c->default_value;
@@ -231,9 +115,8 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
                break;
        case PM_QOS_UPDATE_REQ:
                /*
-                * to change the list, we atomically remove, reinit
-                * with new value and add, then see if the extremal
-                * changed
+                * To change the list, atomically remove, reinit with new value
+                * and add, then see if the aggregate has changed.
                 */
                plist_del(node, &c->list);
                /* fall through */
@@ -252,16 +135,14 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,
        spin_unlock_irqrestore(&pm_qos_lock, flags);
 
        trace_pm_qos_update_target(action, prev_value, curr_value);
-       if (prev_value != curr_value) {
-               ret = 1;
-               if (c->notifiers)
-                       blocking_notifier_call_chain(c->notifiers,
-                                                    (unsigned long)curr_value,
-                                                    NULL);
-       } else {
-               ret = 0;
-       }
-       return ret;
+
+       if (prev_value == curr_value)
+               return 0;
+
+       if (c->notifiers)
+               blocking_notifier_call_chain(c->notifiers, curr_value, NULL);
+
+       return 1;
 }
 
 /**
@@ -283,14 +164,12 @@ static void pm_qos_flags_remove_req(struct pm_qos_flags *pqf,
 
 /**
  * pm_qos_update_flags - Update a set of PM QoS flags.
- * @pqf: Set of flags to update.
+ * @pqf: Set of PM QoS flags to update.
  * @req: Request to add to the set, to modify, or to remove from the set.
  * @action: Action to take on the set.
  * @val: Value of the request to add or modify.
  *
- * Update the given set of PM QoS flags and call notifiers if the aggregate
- * value has changed.  Returns 1 if the aggregate constraint value has changed,
- * 0 otherwise.
+ * Return: 1 if the aggregate constraint value has changed, 0 otherwise.
  */
 bool pm_qos_update_flags(struct pm_qos_flags *pqf,
                         struct pm_qos_flags_request *req,
@@ -326,288 +205,180 @@ bool pm_qos_update_flags(struct pm_qos_flags *pqf,
        spin_unlock_irqrestore(&pm_qos_lock, irqflags);
 
        trace_pm_qos_update_flags(action, prev_value, curr_value);
-       return prev_value != curr_value;
-}
 
-/**
- * pm_qos_request - returns current system wide qos expectation
- * @pm_qos_class: identification of which qos value is requested
- *
- * This function returns the current target value.
- */
-int pm_qos_request(int pm_qos_class)
-{
-       return pm_qos_read_value(pm_qos_array[pm_qos_class]->constraints);
-}
-EXPORT_SYMBOL_GPL(pm_qos_request);
-
-int pm_qos_request_active(struct pm_qos_request *req)
-{
-       return req->pm_qos_class != 0;
+       return prev_value != curr_value;
 }
-EXPORT_SYMBOL_GPL(pm_qos_request_active);
 
-static void __pm_qos_update_request(struct pm_qos_request *req,
-                          s32 new_value)
-{
-       trace_pm_qos_update_request(req->pm_qos_class, new_value);
+#ifdef CONFIG_CPU_IDLE
+/* Definitions related to the CPU latency QoS. */
 
-       if (new_value != req->node.prio)
-               pm_qos_update_target(
-                       pm_qos_array[req->pm_qos_class]->constraints,
-                       &req->node, PM_QOS_UPDATE_REQ, new_value);
-}
+static struct pm_qos_constraints cpu_latency_constraints = {
+       .list = PLIST_HEAD_INIT(cpu_latency_constraints.list),
+       .target_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
+       .default_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
+       .no_constraint_value = PM_QOS_CPU_LATENCY_DEFAULT_VALUE,
+       .type = PM_QOS_MIN,
+};
 
 /**
- * pm_qos_work_fn - the timeout handler of pm_qos_update_request_timeout
- * @work: work struct for the delayed work (timeout)
- *
- * This cancels the timeout request by falling back to the default at timeout.
+ * cpu_latency_qos_limit - Return current system-wide CPU latency QoS limit.
  */
-static void pm_qos_work_fn(struct work_struct *work)
+s32 cpu_latency_qos_limit(void)
 {
-       struct pm_qos_request *req = container_of(to_delayed_work(work),
-                                                 struct pm_qos_request,
-                                                 work);
-
-       __pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
+       return pm_qos_read_value(&cpu_latency_constraints);
 }
 
 /**
- * pm_qos_add_request - inserts new qos request into the list
- * @req: pointer to a preallocated handle
- * @pm_qos_class: identifies which list of qos request to use
- * @value: defines the qos request
+ * cpu_latency_qos_request_active - Check the given PM QoS request.
+ * @req: PM QoS request to check.
  *
- * This function inserts a new entry in the pm_qos_class list of requested qos
- * performance characteristics.  It recomputes the aggregate QoS expectations
- * for the pm_qos_class of parameters and initializes the pm_qos_request
- * handle.  Caller needs to save this handle for later use in updates and
- * removal.
+ * Return: 'true' if @req has been added to the CPU latency QoS list, 'false'
+ * otherwise.
  */
-
-void pm_qos_add_request(struct pm_qos_request *req,
-                       int pm_qos_class, s32 value)
+bool cpu_latency_qos_request_active(struct pm_qos_request *req)
 {
-       if (!req) /*guard against callers passing in null */
-               return;
+       return req->qos == &cpu_latency_constraints;
+}
+EXPORT_SYMBOL_GPL(cpu_latency_qos_request_active);
 
-       if (pm_qos_request_active(req)) {
-               WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n");
-               return;
-       }
-       req->pm_qos_class = pm_qos_class;
-       INIT_DELAYED_WORK(&req->work, pm_qos_work_fn);
-       trace_pm_qos_add_request(pm_qos_class, value);
-       pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints,
-                            &req->node, PM_QOS_ADD_REQ, value);
+static void cpu_latency_qos_apply(struct pm_qos_request *req,
+                                 enum pm_qos_req_action action, s32 value)
+{
+       int ret = pm_qos_update_target(req->qos, &req->node, action, value);
+       if (ret > 0)
+               wake_up_all_idle_cpus();
 }
-EXPORT_SYMBOL_GPL(pm_qos_add_request);
 
 /**
- * pm_qos_update_request - modifies an existing qos request
- * @req : handle to list element holding a pm_qos request to use
- * @value: defines the qos request
+ * cpu_latency_qos_add_request - Add new CPU latency QoS request.
+ * @req: Pointer to a preallocated handle.
+ * @value: Requested constraint value.
  *
- * Updates an existing qos request for the pm_qos_class of parameters along
- * with updating the target pm_qos_class value.
+ * Use @value to initialize the request handle pointed to by @req, insert it as
+ * a new entry to the CPU latency QoS list and recompute the effective QoS
+ * constraint for that list.
  *
- * Attempts are made to make this code callable on hot code paths.
+ * Callers need to save the handle for later use in updates and removal of the
+ * QoS request represented by it.
  */
-void pm_qos_update_request(struct pm_qos_request *req,
-                          s32 new_value)
+void cpu_latency_qos_add_request(struct pm_qos_request *req, s32 value)
 {
-       if (!req) /*guard against callers passing in null */
+       if (!req)
                return;
 
-       if (!pm_qos_request_active(req)) {
-               WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n");
+       if (cpu_latency_qos_request_active(req)) {
+               WARN(1, KERN_ERR "%s called for already added request\n", __func__);
                return;
        }
 
-       cancel_delayed_work_sync(&req->work);
-       __pm_qos_update_request(req, new_value);
+       trace_pm_qos_add_request(value);
+
+       req->qos = &cpu_latency_constraints;
+       cpu_latency_qos_apply(req, PM_QOS_ADD_REQ, value);
 }
-EXPORT_SYMBOL_GPL(pm_qos_update_request);
+EXPORT_SYMBOL_GPL(cpu_latency_qos_add_request);
 
 /**
- * pm_qos_update_request_timeout - modifies an existing qos request temporarily.
- * @req : handle to list element holding a pm_qos request to use
- * @new_value: defines the temporal qos request
- * @timeout_us: the effective duration of this qos request in usecs.
+ * cpu_latency_qos_update_request - Modify existing CPU latency QoS request.
+ * @req : QoS request to update.
+ * @new_value: New requested constraint value.
  *
- * After timeout_us, this qos request is cancelled automatically.
+ * Use @new_value to update the QoS request represented by @req in the CPU
+ * latency QoS list along with updating the effective constraint value for that
+ * list.
  */
-void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value,
-                                  unsigned long timeout_us)
+void cpu_latency_qos_update_request(struct pm_qos_request *req, s32 new_value)
 {
        if (!req)
                return;
-       if (WARN(!pm_qos_request_active(req),
-                "%s called for unknown object.", __func__))
+
+       if (!cpu_latency_qos_request_active(req)) {
+               WARN(1, KERN_ERR "%s called for unknown object\n", __func__);
                return;
+       }
 
-       cancel_delayed_work_sync(&req->work);
+       trace_pm_qos_update_request(new_value);
 
-       trace_pm_qos_update_request_timeout(req->pm_qos_class,
-                                           new_value, timeout_us);
-       if (new_value != req->node.prio)
-               pm_qos_update_target(
-                       pm_qos_array[req->pm_qos_class]->constraints,
-                       &req->node, PM_QOS_UPDATE_REQ, new_value);
+       if (new_value == req->node.prio)
+               return;
 
-       schedule_delayed_work(&req->work, usecs_to_jiffies(timeout_us));
+       cpu_latency_qos_apply(req, PM_QOS_UPDATE_REQ, new_value);
 }
+EXPORT_SYMBOL_GPL(cpu_latency_qos_update_request);
 
 /**
- * pm_qos_remove_request - modifies an existing qos request
- * @req: handle to request list element
+ * cpu_latency_qos_remove_request - Remove existing CPU latency QoS request.
+ * @req: QoS request to remove.
  *
- * Will remove pm qos request from the list of constraints and
- * recompute the current target value for the pm_qos_class.  Call this
- * on slow code paths.
+ * Remove the CPU latency QoS request represented by @req from the CPU latency
+ * QoS list along with updating the effective constraint value for that list.
  */
-void pm_qos_remove_request(struct pm_qos_request *req)
+void cpu_latency_qos_remove_request(struct pm_qos_request *req)
 {
-       if (!req) /*guard against callers passing in null */
+       if (!req)
                return;
-               /* silent return to keep pcm code cleaner */
 
-       if (!pm_qos_request_active(req)) {
-               WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
+       if (!cpu_latency_qos_request_active(req)) {
+               WARN(1, KERN_ERR "%s called for unknown object\n", __func__);
                return;
        }
 
-       cancel_delayed_work_sync(&req->work);
+       trace_pm_qos_remove_request(PM_QOS_DEFAULT_VALUE);
 
-       trace_pm_qos_remove_request(req->pm_qos_class, PM_QOS_DEFAULT_VALUE);
-       pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
-                            &req->node, PM_QOS_REMOVE_REQ,
-                            PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_apply(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
        memset(req, 0, sizeof(*req));
 }
-EXPORT_SYMBOL_GPL(pm_qos_remove_request);
-
-/**
- * pm_qos_add_notifier - sets notification entry for changes to target value
- * @pm_qos_class: identifies which qos target changes should be notified.
- * @notifier: notifier block managed by caller.
- *
- * will register the notifier into a notification chain that gets called
- * upon changes to the pm_qos_class target value.
- */
-int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier)
-{
-       int retval;
-
-       retval = blocking_notifier_chain_register(
-                       pm_qos_array[pm_qos_class]->constraints->notifiers,
-                       notifier);
-
-       return retval;
-}
-EXPORT_SYMBOL_GPL(pm_qos_add_notifier);
-
-/**
- * pm_qos_remove_notifier - deletes notification entry from chain.
- * @pm_qos_class: identifies which qos target changes are notified.
- * @notifier: notifier block to be removed.
- *
- * will remove the notifier from the notification chain that gets called
- * upon changes to the pm_qos_class target value.
- */
-int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier)
-{
-       int retval;
+EXPORT_SYMBOL_GPL(cpu_latency_qos_remove_request);
 
-       retval = blocking_notifier_chain_unregister(
-                       pm_qos_array[pm_qos_class]->constraints->notifiers,
-                       notifier);
+/* User space interface to the CPU latency QoS via misc device. */
 
-       return retval;
-}
-EXPORT_SYMBOL_GPL(pm_qos_remove_notifier);
-
-/* User space interface to PM QoS classes via misc devices */
-static int register_pm_qos_misc(struct pm_qos_object *qos, struct dentry *d)
+static int cpu_latency_qos_open(struct inode *inode, struct file *filp)
 {
-       qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR;
-       qos->pm_qos_power_miscdev.name = qos->name;
-       qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops;
-
-       debugfs_create_file(qos->name, S_IRUGO, d, (void *)qos,
-                           &pm_qos_debug_fops);
+       struct pm_qos_request *req;
 
-       return misc_register(&qos->pm_qos_power_miscdev);
-}
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req)
+               return -ENOMEM;
 
-static int find_pm_qos_object_by_minor(int minor)
-{
-       int pm_qos_class;
+       cpu_latency_qos_add_request(req, PM_QOS_DEFAULT_VALUE);
+       filp->private_data = req;
 
-       for (pm_qos_class = PM_QOS_CPU_DMA_LATENCY;
-               pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) {
-               if (minor ==
-                       pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor)
-                       return pm_qos_class;
-       }
-       return -1;
+       return 0;
 }
 
-static int pm_qos_power_open(struct inode *inode, struct file *filp)
+static int cpu_latency_qos_release(struct inode *inode, struct file *filp)
 {
-       long pm_qos_class;
-
-       pm_qos_class = find_pm_qos_object_by_minor(iminor(inode));
-       if (pm_qos_class >= PM_QOS_CPU_DMA_LATENCY) {
-               struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL);
-               if (!req)
-                       return -ENOMEM;
-
-               pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE);
-               filp->private_data = req;
-
-               return 0;
-       }
-       return -EPERM;
-}
+       struct pm_qos_request *req = filp->private_data;
 
-static int pm_qos_power_release(struct inode *inode, struct file *filp)
-{
-       struct pm_qos_request *req;
+       filp->private_data = NULL;
 
-       req = filp->private_data;
-       pm_qos_remove_request(req);
+       cpu_latency_qos_remove_request(req);
        kfree(req);
 
        return 0;
 }
 
-
-static ssize_t pm_qos_power_read(struct file *filp, char __user *buf,
-               size_t count, loff_t *f_pos)
+static ssize_t cpu_latency_qos_read(struct file *filp, char __user *buf,
+                                   size_t count, loff_t *f_pos)
 {
-       s32 value;
-       unsigned long flags;
        struct pm_qos_request *req = filp->private_data;
+       unsigned long flags;
+       s32 value;
 
-       if (!req)
-               return -EINVAL;
-       if (!pm_qos_request_active(req))
+       if (!req || !cpu_latency_qos_request_active(req))
                return -EINVAL;
 
        spin_lock_irqsave(&pm_qos_lock, flags);
-       value = pm_qos_get_value(pm_qos_array[req->pm_qos_class]->constraints);
+       value = pm_qos_get_value(&cpu_latency_constraints);
        spin_unlock_irqrestore(&pm_qos_lock, flags);
 
        return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32));
 }
 
-static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
-               size_t count, loff_t *f_pos)
+static ssize_t cpu_latency_qos_write(struct file *filp, const char __user *buf,
+                                    size_t count, loff_t *f_pos)
 {
        s32 value;
-       struct pm_qos_request *req;
 
        if (count == sizeof(s32)) {
                if (copy_from_user(&value, buf, sizeof(s32)))
@@ -620,36 +391,38 @@ static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf,
                        return ret;
        }
 
-       req = filp->private_data;
-       pm_qos_update_request(req, value);
+       cpu_latency_qos_update_request(filp->private_data, value);
 
        return count;
 }
 
+static const struct file_operations cpu_latency_qos_fops = {
+       .write = cpu_latency_qos_write,
+       .read = cpu_latency_qos_read,
+       .open = cpu_latency_qos_open,
+       .release = cpu_latency_qos_release,
+       .llseek = noop_llseek,
+};
 
-static int __init pm_qos_power_init(void)
-{
-       int ret = 0;
-       int i;
-       struct dentry *d;
-
-       BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES);
+static struct miscdevice cpu_latency_qos_miscdev = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "cpu_dma_latency",
+       .fops = &cpu_latency_qos_fops,
+};
 
-       d = debugfs_create_dir("pm_qos", NULL);
+static int __init cpu_latency_qos_init(void)
+{
+       int ret;
 
-       for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) {
-               ret = register_pm_qos_misc(pm_qos_array[i], d);
-               if (ret < 0) {
-                       pr_err("%s: %s setup failed\n",
-                              __func__, pm_qos_array[i]->name);
-                       return ret;
-               }
-       }
+       ret = misc_register(&cpu_latency_qos_miscdev);
+       if (ret < 0)
+               pr_err("%s: %s setup failed\n", __func__,
+                      cpu_latency_qos_miscdev.name);
 
        return ret;
 }
-
-late_initcall(pm_qos_power_init);
+late_initcall(cpu_latency_qos_init);
+#endif /* CONFIG_CPU_IDLE */
 
 /* Definitions related to the frequency QoS below. */
 
index ddade80..d82b7b8 100644 (file)
@@ -1681,7 +1681,7 @@ static unsigned long minimum_image_size(unsigned long saveable)
  * hibernation for allocations made while saving the image and for device
  * drivers, in case they need to allocate memory from their hibernation
  * callbacks (these two numbers are given by PAGES_FOR_IO (which is a rough
- * estimate) and reserverd_size divided by PAGE_SIZE (which is tunable through
+ * estimate) and reserved_size divided by PAGE_SIZE (which is tunable through
  * /sys/power/reserved_size, respectively).  To make this happen, we compute the
  * total number of available page frames and allocate at least
  *
index 7743895..58ed947 100644 (file)
@@ -409,21 +409,7 @@ snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        switch (cmd) {
        case SNAPSHOT_GET_IMAGE_SIZE:
        case SNAPSHOT_AVAIL_SWAP_SIZE:
-       case SNAPSHOT_ALLOC_SWAP_PAGE: {
-               compat_loff_t __user *uoffset = compat_ptr(arg);
-               loff_t offset;
-               mm_segment_t old_fs;
-               int err;
-
-               old_fs = get_fs();
-               set_fs(KERNEL_DS);
-               err = snapshot_ioctl(file, cmd, (unsigned long) &offset);
-               set_fs(old_fs);
-               if (!err && put_user(offset, uoffset))
-                       err = -EFAULT;
-               return err;
-       }
-
+       case SNAPSHOT_ALLOC_SWAP_PAGE:
        case SNAPSHOT_CREATE_IMAGE:
                return snapshot_ioctl(file, cmd,
                                      (unsigned long) compat_ptr(arg));
index 82d5fba..f91f2c2 100644 (file)
@@ -3,6 +3,10 @@
 # and is generally not a function of system call inputs.
 KCOV_INSTRUMENT := n
 
+ifeq ($(CONFIG_KCSAN),y)
+KBUILD_CFLAGS += -g -fno-omit-frame-pointer
+endif
+
 obj-y += update.o sync.o
 obj-$(CONFIG_TREE_SRCU) += srcutree.o
 obj-$(CONFIG_TINY_SRCU) += srcutiny.o
index 05f936e..00ddc92 100644 (file)
@@ -198,6 +198,13 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head)
 }
 #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
+extern int rcu_cpu_stall_suppress_at_boot;
+
+static inline bool rcu_stall_is_suppressed_at_boot(void)
+{
+       return rcu_cpu_stall_suppress_at_boot && !rcu_inkernel_boot_has_ended();
+}
+
 #ifdef CONFIG_RCU_STALL_COMMON
 
 extern int rcu_cpu_stall_ftrace_dump;
@@ -205,6 +212,11 @@ extern int rcu_cpu_stall_suppress;
 extern int rcu_cpu_stall_timeout;
 int rcu_jiffies_till_stall_check(void);
 
+static inline bool rcu_stall_is_suppressed(void)
+{
+       return rcu_stall_is_suppressed_at_boot() || rcu_cpu_stall_suppress;
+}
+
 #define rcu_ftrace_dump_stall_suppress() \
 do { \
        if (!rcu_cpu_stall_suppress) \
@@ -218,6 +230,11 @@ do { \
 } while (0)
 
 #else /* #endif #ifdef CONFIG_RCU_STALL_COMMON */
+
+static inline bool rcu_stall_is_suppressed(void)
+{
+       return rcu_stall_is_suppressed_at_boot();
+}
 #define rcu_ftrace_dump_stall_suppress()
 #define rcu_ftrace_dump_stall_unsuppress()
 #endif /* #ifdef CONFIG_RCU_STALL_COMMON */
@@ -325,7 +342,8 @@ static inline void rcu_init_levelspread(int *levelspread, const int *levelcnt)
  * Iterate over all possible CPUs in a leaf RCU node.
  */
 #define for_each_leaf_node_possible_cpu(rnp, cpu) \
-       for ((cpu) = cpumask_next((rnp)->grplo - 1, cpu_possible_mask); \
+       for (WARN_ON_ONCE(!rcu_is_leaf_node(rnp)), \
+            (cpu) = cpumask_next((rnp)->grplo - 1, cpu_possible_mask); \
             (cpu) <= rnp->grphi; \
             (cpu) = cpumask_next((cpu), cpu_possible_mask))
 
@@ -335,7 +353,8 @@ static inline void rcu_init_levelspread(int *levelspread, const int *levelcnt)
 #define rcu_find_next_bit(rnp, cpu, mask) \
        ((rnp)->grplo + find_next_bit(&(mask), BITS_PER_LONG, (cpu)))
 #define for_each_leaf_node_cpu_mask(rnp, cpu, mask) \
-       for ((cpu) = rcu_find_next_bit((rnp), 0, (mask)); \
+       for (WARN_ON_ONCE(!rcu_is_leaf_node(rnp)), \
+            (cpu) = rcu_find_next_bit((rnp), 0, (mask)); \
             (cpu) <= rnp->grphi; \
             (cpu) = rcu_find_next_bit((rnp), (cpu) + 1 - (rnp->grplo), (mask)))
 
index 5f4fd3b..9a0f661 100644 (file)
@@ -182,7 +182,7 @@ void rcu_segcblist_offload(struct rcu_segcblist *rsclp)
 bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp)
 {
        return rcu_segcblist_is_enabled(rsclp) &&
-              &rsclp->head != rsclp->tails[RCU_DONE_TAIL];
+              &rsclp->head != READ_ONCE(rsclp->tails[RCU_DONE_TAIL]);
 }
 
 /*
@@ -381,8 +381,6 @@ void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp,
                return; /* Nothing to do. */
        WRITE_ONCE(*rsclp->tails[RCU_NEXT_TAIL], rclp->head);
        WRITE_ONCE(rsclp->tails[RCU_NEXT_TAIL], rclp->tail);
-       rclp->head = NULL;
-       rclp->tail = &rclp->head;
 }
 
 /*
index da94b89..a4a8d09 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/err.h>
@@ -611,6 +612,7 @@ kfree_perf_thread(void *arg)
        long me = (long)arg;
        struct kfree_obj *alloc_ptr;
        u64 start_time, end_time;
+       long long mem_begin, mem_during = 0;
 
        VERBOSE_PERFOUT_STRING("kfree_perf_thread task started");
        set_cpus_allowed_ptr(current, cpumask_of(me % nr_cpu_ids));
@@ -626,6 +628,12 @@ kfree_perf_thread(void *arg)
        }
 
        do {
+               if (!mem_during) {
+                       mem_during = mem_begin = si_mem_available();
+               } else if (loop % (kfree_loops / 4) == 0) {
+                       mem_during = (mem_during + si_mem_available()) / 2;
+               }
+
                for (i = 0; i < kfree_alloc_num; i++) {
                        alloc_ptr = kmalloc(sizeof(struct kfree_obj), GFP_KERNEL);
                        if (!alloc_ptr)
@@ -645,9 +653,11 @@ kfree_perf_thread(void *arg)
                else
                        b_rcu_gp_test_finished = cur_ops->get_gp_seq();
 
-               pr_alert("Total time taken by all kfree'ers: %llu ns, loops: %d, batches: %ld\n",
+               pr_alert("Total time taken by all kfree'ers: %llu ns, loops: %d, batches: %ld, memory footprint: %lldMB\n",
                       (unsigned long long)(end_time - start_time), kfree_loops,
-                      rcuperf_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started));
+                      rcuperf_seq_diff(b_rcu_gp_test_finished, b_rcu_gp_test_started),
+                      (mem_begin - mem_during) >> (20 - PAGE_SHIFT));
+
                if (shutdown) {
                        smp_mb(); /* Assign before wake. */
                        wake_up(&shutdown_wq);
index 1aeecc1..5453bd5 100644 (file)
@@ -339,7 +339,7 @@ rcu_read_delay(struct torture_random_state *rrsp, struct rt_read_seg *rtrsp)
         * period, and we want a long delay occasionally to trigger
         * force_quiescent_state. */
 
-       if (!rcu_fwd_cb_nodelay &&
+       if (!READ_ONCE(rcu_fwd_cb_nodelay) &&
            !(torture_random(rrsp) % (nrealreaders * 2000 * longdelay_ms))) {
                started = cur_ops->get_gp_seq();
                ts = rcu_trace_clock_local();
@@ -375,11 +375,12 @@ rcu_torture_pipe_update_one(struct rcu_torture *rp)
 {
        int i;
 
-       i = rp->rtort_pipe_count;
+       i = READ_ONCE(rp->rtort_pipe_count);
        if (i > RCU_TORTURE_PIPE_LEN)
                i = RCU_TORTURE_PIPE_LEN;
        atomic_inc(&rcu_torture_wcount[i]);
-       if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
+       WRITE_ONCE(rp->rtort_pipe_count, i + 1);
+       if (rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
                rp->rtort_mbtest = 0;
                return true;
        }
@@ -1015,7 +1016,8 @@ rcu_torture_writer(void *arg)
                        if (i > RCU_TORTURE_PIPE_LEN)
                                i = RCU_TORTURE_PIPE_LEN;
                        atomic_inc(&rcu_torture_wcount[i]);
-                       old_rp->rtort_pipe_count++;
+                       WRITE_ONCE(old_rp->rtort_pipe_count,
+                                  old_rp->rtort_pipe_count + 1);
                        switch (synctype[torture_random(&rand) % nsynctypes]) {
                        case RTWS_DEF_FREE:
                                rcu_torture_writer_state = RTWS_DEF_FREE;
@@ -1067,7 +1069,8 @@ rcu_torture_writer(void *arg)
                if (stutter_wait("rcu_torture_writer") &&
                    !READ_ONCE(rcu_fwd_cb_nodelay) &&
                    !cur_ops->slow_gps &&
-                   !torture_must_stop())
+                   !torture_must_stop() &&
+                   rcu_inkernel_boot_has_ended())
                        for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++)
                                if (list_empty(&rcu_tortures[i].rtort_free) &&
                                    rcu_access_pointer(rcu_torture_current) !=
@@ -1290,7 +1293,7 @@ static bool rcu_torture_one_read(struct torture_random_state *trsp)
                atomic_inc(&n_rcu_torture_mberror);
        rtrsp = rcutorture_loop_extend(&readstate, trsp, rtrsp);
        preempt_disable();
-       pipe_count = p->rtort_pipe_count;
+       pipe_count = READ_ONCE(p->rtort_pipe_count);
        if (pipe_count > RCU_TORTURE_PIPE_LEN) {
                /* Should not happen, but... */
                pipe_count = RCU_TORTURE_PIPE_LEN;
@@ -1404,14 +1407,15 @@ rcu_torture_stats_print(void)
        int i;
        long pipesummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
        long batchsummary[RCU_TORTURE_PIPE_LEN + 1] = { 0 };
+       struct rcu_torture *rtcp;
        static unsigned long rtcv_snap = ULONG_MAX;
        static bool splatted;
        struct task_struct *wtp;
 
        for_each_possible_cpu(cpu) {
                for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) {
-                       pipesummary[i] += per_cpu(rcu_torture_count, cpu)[i];
-                       batchsummary[i] += per_cpu(rcu_torture_batch, cpu)[i];
+                       pipesummary[i] += READ_ONCE(per_cpu(rcu_torture_count, cpu)[i]);
+                       batchsummary[i] += READ_ONCE(per_cpu(rcu_torture_batch, cpu)[i]);
                }
        }
        for (i = RCU_TORTURE_PIPE_LEN - 1; i >= 0; i--) {
@@ -1420,9 +1424,10 @@ rcu_torture_stats_print(void)
        }
 
        pr_alert("%s%s ", torture_type, TORTURE_FLAG);
+       rtcp = rcu_access_pointer(rcu_torture_current);
        pr_cont("rtc: %p %s: %lu tfle: %d rta: %d rtaf: %d rtf: %d ",
-               rcu_torture_current,
-               rcu_torture_current ? "ver" : "VER",
+               rtcp,
+               rtcp && !rcu_stall_is_suppressed_at_boot() ? "ver" : "VER",
                rcu_torture_current_version,
                list_empty(&rcu_torture_freelist),
                atomic_read(&n_rcu_torture_alloc),
@@ -1478,7 +1483,8 @@ rcu_torture_stats_print(void)
        if (cur_ops->stats)
                cur_ops->stats();
        if (rtcv_snap == rcu_torture_current_version &&
-           rcu_torture_current != NULL) {
+           rcu_access_pointer(rcu_torture_current) &&
+           !rcu_stall_is_suppressed()) {
                int __maybe_unused flags = 0;
                unsigned long __maybe_unused gp_seq = 0;
 
@@ -1993,8 +1999,11 @@ static int rcu_torture_fwd_prog(void *args)
                schedule_timeout_interruptible(fwd_progress_holdoff * HZ);
                WRITE_ONCE(rcu_fwd_emergency_stop, false);
                register_oom_notifier(&rcutorture_oom_nb);
-               rcu_torture_fwd_prog_nr(rfp, &tested, &tested_tries);
-               rcu_torture_fwd_prog_cr(rfp);
+               if (!IS_ENABLED(CONFIG_TINY_RCU) ||
+                   rcu_inkernel_boot_has_ended())
+                       rcu_torture_fwd_prog_nr(rfp, &tested, &tested_tries);
+               if (rcu_inkernel_boot_has_ended())
+                       rcu_torture_fwd_prog_cr(rfp);
                unregister_oom_notifier(&rcutorture_oom_nb);
 
                /* Avoid slow periods, better to test when busy. */
@@ -2044,6 +2053,14 @@ static void rcu_torture_barrier_cbf(struct rcu_head *rcu)
        atomic_inc(&barrier_cbs_invoked);
 }
 
+/* IPI handler to get callback posted on desired CPU, if online. */
+static void rcu_torture_barrier1cb(void *rcu_void)
+{
+       struct rcu_head *rhp = rcu_void;
+
+       cur_ops->call(rhp, rcu_torture_barrier_cbf);
+}
+
 /* kthread function to register callbacks used to test RCU barriers. */
 static int rcu_torture_barrier_cbs(void *arg)
 {
@@ -2067,9 +2084,11 @@ static int rcu_torture_barrier_cbs(void *arg)
                 * The above smp_load_acquire() ensures barrier_phase load
                 * is ordered before the following ->call().
                 */
-               local_irq_disable(); /* Just to test no-irq call_rcu(). */
-               cur_ops->call(&rcu, rcu_torture_barrier_cbf);
-               local_irq_enable();
+               if (smp_call_function_single(myid, rcu_torture_barrier1cb,
+                                            &rcu, 1)) {
+                       // IPI failed, so use direct call from current CPU.
+                       cur_ops->call(&rcu, rcu_torture_barrier_cbf);
+               }
                if (atomic_dec_and_test(&barrier_cbs_count))
                        wake_up(&barrier_wq);
        } while (!torture_must_stop());
@@ -2105,7 +2124,21 @@ static int rcu_torture_barrier(void *arg)
                        pr_err("barrier_cbs_invoked = %d, n_barrier_cbs = %d\n",
                               atomic_read(&barrier_cbs_invoked),
                               n_barrier_cbs);
-                       WARN_ON_ONCE(1);
+                       WARN_ON(1);
+                       // Wait manually for the remaining callbacks
+                       i = 0;
+                       do {
+                               if (WARN_ON(i++ > HZ))
+                                       i = INT_MIN;
+                               schedule_timeout_interruptible(1);
+                               cur_ops->cb_barrier();
+                       } while (atomic_read(&barrier_cbs_invoked) !=
+                                n_barrier_cbs &&
+                                !torture_must_stop());
+                       smp_mb(); // Can't trust ordering if broken.
+                       if (!torture_must_stop())
+                               pr_err("Recovered: barrier_cbs_invoked = %d\n",
+                                      atomic_read(&barrier_cbs_invoked));
                } else {
                        n_barrier_successes++;
                }
index 657e6a7..0c71505 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) IBM Corporation, 2006
  * Copyright (C) Fujitsu, 2012
  *
- * Author: Paul McKenney <paulmck@linux.ibm.com>
+ * Authors: Paul McKenney <paulmck@linux.ibm.com>
  *        Lai Jiangshan <laijs@cn.fujitsu.com>
  *
  * For detailed explanation of Read-Copy Update mechanism see -
@@ -450,7 +450,7 @@ static void srcu_gp_start(struct srcu_struct *ssp)
        spin_unlock_rcu_node(sdp);  /* Interrupts remain disabled. */
        smp_mb(); /* Order prior store to ->srcu_gp_seq_needed vs. GP start. */
        rcu_seq_start(&ssp->srcu_gp_seq);
-       state = rcu_seq_state(READ_ONCE(ssp->srcu_gp_seq));
+       state = rcu_seq_state(ssp->srcu_gp_seq);
        WARN_ON_ONCE(state != SRCU_STATE_SCAN1);
 }
 
@@ -534,7 +534,7 @@ static void srcu_gp_end(struct srcu_struct *ssp)
        rcu_seq_end(&ssp->srcu_gp_seq);
        gpseq = rcu_seq_current(&ssp->srcu_gp_seq);
        if (ULONG_CMP_LT(ssp->srcu_gp_seq_needed_exp, gpseq))
-               ssp->srcu_gp_seq_needed_exp = gpseq;
+               WRITE_ONCE(ssp->srcu_gp_seq_needed_exp, gpseq);
        spin_unlock_irq_rcu_node(ssp);
        mutex_unlock(&ssp->srcu_gp_mutex);
        /* A new grace period can start at this point.  But only one. */
@@ -550,7 +550,7 @@ static void srcu_gp_end(struct srcu_struct *ssp)
                snp->srcu_have_cbs[idx] = gpseq;
                rcu_seq_set_state(&snp->srcu_have_cbs[idx], 1);
                if (ULONG_CMP_LT(snp->srcu_gp_seq_needed_exp, gpseq))
-                       snp->srcu_gp_seq_needed_exp = gpseq;
+                       WRITE_ONCE(snp->srcu_gp_seq_needed_exp, gpseq);
                mask = snp->srcu_data_have_cbs[idx];
                snp->srcu_data_have_cbs[idx] = 0;
                spin_unlock_irq_rcu_node(snp);
@@ -614,7 +614,7 @@ static void srcu_funnel_exp_start(struct srcu_struct *ssp, struct srcu_node *snp
        }
        spin_lock_irqsave_rcu_node(ssp, flags);
        if (ULONG_CMP_LT(ssp->srcu_gp_seq_needed_exp, s))
-               ssp->srcu_gp_seq_needed_exp = s;
+               WRITE_ONCE(ssp->srcu_gp_seq_needed_exp, s);
        spin_unlock_irqrestore_rcu_node(ssp, flags);
 }
 
@@ -660,7 +660,7 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp,
                if (snp == sdp->mynode)
                        snp->srcu_data_have_cbs[idx] |= sdp->grpmask;
                if (!do_norm && ULONG_CMP_LT(snp->srcu_gp_seq_needed_exp, s))
-                       snp->srcu_gp_seq_needed_exp = s;
+                       WRITE_ONCE(snp->srcu_gp_seq_needed_exp, s);
                spin_unlock_irqrestore_rcu_node(snp, flags);
        }
 
@@ -674,7 +674,7 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp,
                smp_store_release(&ssp->srcu_gp_seq_needed, s); /*^^^*/
        }
        if (!do_norm && ULONG_CMP_LT(ssp->srcu_gp_seq_needed_exp, s))
-               ssp->srcu_gp_seq_needed_exp = s;
+               WRITE_ONCE(ssp->srcu_gp_seq_needed_exp, s);
 
        /* If grace period not already done and none in progress, start it. */
        if (!rcu_seq_done(&ssp->srcu_gp_seq, s) &&
@@ -1079,7 +1079,7 @@ EXPORT_SYMBOL_GPL(srcu_barrier);
  */
 unsigned long srcu_batches_completed(struct srcu_struct *ssp)
 {
-       return ssp->srcu_idx;
+       return READ_ONCE(ssp->srcu_idx);
 }
 EXPORT_SYMBOL_GPL(srcu_batches_completed);
 
@@ -1130,7 +1130,9 @@ static void srcu_advance_state(struct srcu_struct *ssp)
                        return; /* readers present, retry later. */
                }
                srcu_flip(ssp);
+               spin_lock_irq_rcu_node(ssp);
                rcu_seq_set_state(&ssp->srcu_gp_seq, SRCU_STATE_SCAN2);
+               spin_unlock_irq_rcu_node(ssp);
        }
 
        if (rcu_seq_state(READ_ONCE(ssp->srcu_gp_seq)) == SRCU_STATE_SCAN2) {
index d91c915..06548e2 100644 (file)
@@ -1,12 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Read-Copy Update mechanism for mutual exclusion
+ * Read-Copy Update mechanism for mutual exclusion (tree-based version)
  *
  * Copyright IBM Corporation, 2008
  *
  * Authors: Dipankar Sarma <dipankar@in.ibm.com>
  *         Manfred Spraul <manfred@colorfullife.com>
- *         Paul E. McKenney <paulmck@linux.ibm.com> Hierarchical version
+ *         Paul E. McKenney <paulmck@linux.ibm.com>
  *
  * Based on the original work by Paul McKenney <paulmck@linux.ibm.com>
  * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
@@ -150,6 +150,7 @@ static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu)
 static void invoke_rcu_core(void);
 static void rcu_report_exp_rdp(struct rcu_data *rdp);
 static void sync_sched_exp_online_cleanup(int cpu);
+static void check_cb_ovld_locked(struct rcu_data *rdp, struct rcu_node *rnp);
 
 /* rcuc/rcub kthread realtime priority */
 static int kthread_prio = IS_ENABLED(CONFIG_RCU_BOOST) ? 1 : 0;
@@ -342,14 +343,17 @@ bool rcu_eqs_special_set(int cpu)
 {
        int old;
        int new;
+       int new_old;
        struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
 
+       new_old = atomic_read(&rdp->dynticks);
        do {
-               old = atomic_read(&rdp->dynticks);
+               old = new_old;
                if (old & RCU_DYNTICK_CTRL_CTR)
                        return false;
                new = old | RCU_DYNTICK_CTRL_MASK;
-       } while (atomic_cmpxchg(&rdp->dynticks, old, new) != old);
+               new_old = atomic_cmpxchg(&rdp->dynticks, old, new);
+       } while (new_old != old);
        return true;
 }
 
@@ -410,10 +414,15 @@ static long blimit = DEFAULT_RCU_BLIMIT;
 static long qhimark = DEFAULT_RCU_QHIMARK;
 #define DEFAULT_RCU_QLOMARK 100   /* Once only this many pending, use blimit. */
 static long qlowmark = DEFAULT_RCU_QLOMARK;
+#define DEFAULT_RCU_QOVLD_MULT 2
+#define DEFAULT_RCU_QOVLD (DEFAULT_RCU_QOVLD_MULT * DEFAULT_RCU_QHIMARK)
+static long qovld = DEFAULT_RCU_QOVLD; /* If this many pending, hammer QS. */
+static long qovld_calc = -1;     /* No pre-initialization lock acquisitions! */
 
 module_param(blimit, long, 0444);
 module_param(qhimark, long, 0444);
 module_param(qlowmark, long, 0444);
+module_param(qovld, long, 0444);
 
 static ulong jiffies_till_first_fqs = ULONG_MAX;
 static ulong jiffies_till_next_fqs = ULONG_MAX;
@@ -818,11 +827,12 @@ static __always_inline void rcu_nmi_enter_common(bool irq)
                incby = 1;
        } else if (tick_nohz_full_cpu(rdp->cpu) &&
                   rdp->dynticks_nmi_nesting == DYNTICK_IRQ_NONIDLE &&
-                  READ_ONCE(rdp->rcu_urgent_qs) && !rdp->rcu_forced_tick) {
+                  READ_ONCE(rdp->rcu_urgent_qs) &&
+                  !READ_ONCE(rdp->rcu_forced_tick)) {
                raw_spin_lock_rcu_node(rdp->mynode);
                // Recheck under lock.
                if (rdp->rcu_urgent_qs && !rdp->rcu_forced_tick) {
-                       rdp->rcu_forced_tick = true;
+                       WRITE_ONCE(rdp->rcu_forced_tick, true);
                        tick_dep_set_cpu(rdp->cpu, TICK_DEP_BIT_RCU);
                }
                raw_spin_unlock_rcu_node(rdp->mynode);
@@ -899,7 +909,7 @@ static void rcu_disable_urgency_upon_qs(struct rcu_data *rdp)
        WRITE_ONCE(rdp->rcu_need_heavy_qs, false);
        if (tick_nohz_full_cpu(rdp->cpu) && rdp->rcu_forced_tick) {
                tick_dep_clear_cpu(rdp->cpu, TICK_DEP_BIT_RCU);
-               rdp->rcu_forced_tick = false;
+               WRITE_ONCE(rdp->rcu_forced_tick, false);
        }
 }
 
@@ -1072,7 +1082,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
        rnhqp = &per_cpu(rcu_data.rcu_need_heavy_qs, rdp->cpu);
        if (!READ_ONCE(*rnhqp) &&
            (time_after(jiffies, rcu_state.gp_start + jtsq * 2) ||
-            time_after(jiffies, rcu_state.jiffies_resched))) {
+            time_after(jiffies, rcu_state.jiffies_resched) ||
+            rcu_state.cbovld)) {
                WRITE_ONCE(*rnhqp, true);
                /* Store rcu_need_heavy_qs before rcu_urgent_qs. */
                smp_store_release(ruqp, true);
@@ -1089,8 +1100,8 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
         * So hit them over the head with the resched_cpu() hammer!
         */
        if (tick_nohz_full_cpu(rdp->cpu) &&
-                  time_after(jiffies,
-                             READ_ONCE(rdp->last_fqs_resched) + jtsq * 3)) {
+           (time_after(jiffies, READ_ONCE(rdp->last_fqs_resched) + jtsq * 3) ||
+            rcu_state.cbovld)) {
                WRITE_ONCE(*ruqp, true);
                resched_cpu(rdp->cpu);
                WRITE_ONCE(rdp->last_fqs_resched, jiffies);
@@ -1113,6 +1124,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
                    !rdp->rcu_iw_pending && rdp->rcu_iw_gp_seq != rnp->gp_seq &&
                    (rnp->ffmask & rdp->grpmask)) {
                        init_irq_work(&rdp->rcu_iw, rcu_iw_handler);
+                       atomic_set(&rdp->rcu_iw.flags, IRQ_WORK_HARD_IRQ);
                        rdp->rcu_iw_pending = true;
                        rdp->rcu_iw_gp_seq = rnp->gp_seq;
                        irq_work_queue_on(&rdp->rcu_iw, rdp->cpu);
@@ -1126,8 +1138,9 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 static void trace_rcu_this_gp(struct rcu_node *rnp, struct rcu_data *rdp,
                              unsigned long gp_seq_req, const char *s)
 {
-       trace_rcu_future_grace_period(rcu_state.name, rnp->gp_seq, gp_seq_req,
-                                     rnp->level, rnp->grplo, rnp->grphi, s);
+       trace_rcu_future_grace_period(rcu_state.name, READ_ONCE(rnp->gp_seq),
+                                     gp_seq_req, rnp->level,
+                                     rnp->grplo, rnp->grphi, s);
 }
 
 /*
@@ -1174,7 +1187,7 @@ static bool rcu_start_this_gp(struct rcu_node *rnp_start, struct rcu_data *rdp,
                                          TPS("Prestarted"));
                        goto unlock_out;
                }
-               rnp->gp_seq_needed = gp_seq_req;
+               WRITE_ONCE(rnp->gp_seq_needed, gp_seq_req);
                if (rcu_seq_state(rcu_seq_current(&rnp->gp_seq))) {
                        /*
                         * We just marked the leaf or internal node, and a
@@ -1199,18 +1212,18 @@ static bool rcu_start_this_gp(struct rcu_node *rnp_start, struct rcu_data *rdp,
        }
        trace_rcu_this_gp(rnp, rdp, gp_seq_req, TPS("Startedroot"));
        WRITE_ONCE(rcu_state.gp_flags, rcu_state.gp_flags | RCU_GP_FLAG_INIT);
-       rcu_state.gp_req_activity = jiffies;
-       if (!rcu_state.gp_kthread) {
+       WRITE_ONCE(rcu_state.gp_req_activity, jiffies);
+       if (!READ_ONCE(rcu_state.gp_kthread)) {
                trace_rcu_this_gp(rnp, rdp, gp_seq_req, TPS("NoGPkthread"));
                goto unlock_out;
        }
-       trace_rcu_grace_period(rcu_state.name, READ_ONCE(rcu_state.gp_seq), TPS("newreq"));
+       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq, TPS("newreq"));
        ret = true;  /* Caller must wake GP kthread. */
 unlock_out:
        /* Push furthest requested GP to leaf node and rcu_data structure. */
        if (ULONG_CMP_LT(gp_seq_req, rnp->gp_seq_needed)) {
-               rnp_start->gp_seq_needed = rnp->gp_seq_needed;
-               rdp->gp_seq_needed = rnp->gp_seq_needed;
+               WRITE_ONCE(rnp_start->gp_seq_needed, rnp->gp_seq_needed);
+               WRITE_ONCE(rdp->gp_seq_needed, rnp->gp_seq_needed);
        }
        if (rnp != rnp_start)
                raw_spin_unlock_rcu_node(rnp);
@@ -1235,12 +1248,13 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp)
 }
 
 /*
- * Awaken the grace-period kthread.  Don't do a self-awaken (unless in
- * an interrupt or softirq handler), and don't bother awakening when there
- * is nothing for the grace-period kthread to do (as in several CPUs raced
- * to awaken, and we lost), and finally don't try to awaken a kthread that
- * has not yet been created.  If all those checks are passed, track some
- * debug information and awaken.
+ * Awaken the grace-period kthread.  Don't do a self-awaken (unless in an
+ * interrupt or softirq handler, in which case we just might immediately
+ * sleep upon return, resulting in a grace-period hang), and don't bother
+ * awakening when there is nothing for the grace-period kthread to do
+ * (as in several CPUs raced to awaken, we lost), and finally don't try
+ * to awaken a kthread that has not yet been created.  If all those checks
+ * are passed, track some debug information and awaken.
  *
  * So why do the self-wakeup when in an interrupt or softirq handler
  * in the grace-period kthread's context?  Because the kthread might have
@@ -1250,10 +1264,10 @@ static bool rcu_future_gp_cleanup(struct rcu_node *rnp)
  */
 static void rcu_gp_kthread_wake(void)
 {
-       if ((current == rcu_state.gp_kthread &&
-            !in_irq() && !in_serving_softirq()) ||
-           !READ_ONCE(rcu_state.gp_flags) ||
-           !rcu_state.gp_kthread)
+       struct task_struct *t = READ_ONCE(rcu_state.gp_kthread);
+
+       if ((current == t && !in_irq() && !in_serving_softirq()) ||
+           !READ_ONCE(rcu_state.gp_flags) || !t)
                return;
        WRITE_ONCE(rcu_state.gp_wake_time, jiffies);
        WRITE_ONCE(rcu_state.gp_wake_seq, READ_ONCE(rcu_state.gp_seq));
@@ -1321,7 +1335,7 @@ static void rcu_accelerate_cbs_unlocked(struct rcu_node *rnp,
 
        rcu_lockdep_assert_cblist_protected(rdp);
        c = rcu_seq_snap(&rcu_state.gp_seq);
-       if (!rdp->gpwrap && ULONG_CMP_GE(rdp->gp_seq_needed, c)) {
+       if (!READ_ONCE(rdp->gpwrap) && ULONG_CMP_GE(rdp->gp_seq_needed, c)) {
                /* Old request still live, so mark recent callbacks. */
                (void)rcu_segcblist_accelerate(&rdp->cblist, c);
                return;
@@ -1386,7 +1400,7 @@ static void __maybe_unused rcu_advance_cbs_nowake(struct rcu_node *rnp,
 static bool __note_gp_changes(struct rcu_node *rnp, struct rcu_data *rdp)
 {
        bool ret = false;
-       bool need_gp;
+       bool need_qs;
        const bool offloaded = IS_ENABLED(CONFIG_RCU_NOCB_CPU) &&
                               rcu_segcblist_is_offloaded(&rdp->cblist);
 
@@ -1400,10 +1414,13 @@ static bool __note_gp_changes(struct rcu_node *rnp, struct rcu_data *rdp)
            unlikely(READ_ONCE(rdp->gpwrap))) {
                if (!offloaded)
                        ret = rcu_advance_cbs(rnp, rdp); /* Advance CBs. */
+               rdp->core_needs_qs = false;
                trace_rcu_grace_period(rcu_state.name, rdp->gp_seq, TPS("cpuend"));
        } else {
                if (!offloaded)
                        ret = rcu_accelerate_cbs(rnp, rdp); /* Recent CBs. */
+               if (rdp->core_needs_qs)
+                       rdp->core_needs_qs = !!(rnp->qsmask & rdp->grpmask);
        }
 
        /* Now handle the beginnings of any new-to-this-CPU grace periods. */
@@ -1415,14 +1432,14 @@ static bool __note_gp_changes(struct rcu_node *rnp, struct rcu_data *rdp)
                 * go looking for one.
                 */
                trace_rcu_grace_period(rcu_state.name, rnp->gp_seq, TPS("cpustart"));
-               need_gp = !!(rnp->qsmask & rdp->grpmask);
-               rdp->cpu_no_qs.b.norm = need_gp;
-               rdp->core_needs_qs = need_gp;
+               need_qs = !!(rnp->qsmask & rdp->grpmask);
+               rdp->cpu_no_qs.b.norm = need_qs;
+               rdp->core_needs_qs = need_qs;
                zero_cpu_stall_ticks(rdp);
        }
        rdp->gp_seq = rnp->gp_seq;  /* Remember new grace-period state. */
        if (ULONG_CMP_LT(rdp->gp_seq_needed, rnp->gp_seq_needed) || rdp->gpwrap)
-               rdp->gp_seq_needed = rnp->gp_seq_needed;
+               WRITE_ONCE(rdp->gp_seq_needed, rnp->gp_seq_needed);
        WRITE_ONCE(rdp->gpwrap, false);
        rcu_gpnum_ovf(rnp, rdp);
        return ret;
@@ -1651,8 +1668,7 @@ static void rcu_gp_fqs_loop(void)
                        WRITE_ONCE(rcu_state.jiffies_kick_kthreads,
                                   jiffies + (j ? 3 * j : 2));
                }
-               trace_rcu_grace_period(rcu_state.name,
-                                      READ_ONCE(rcu_state.gp_seq),
+               trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                       TPS("fqswait"));
                rcu_state.gp_state = RCU_GP_WAIT_FQS;
                ret = swait_event_idle_timeout_exclusive(
@@ -1666,13 +1682,11 @@ static void rcu_gp_fqs_loop(void)
                /* If time for quiescent-state forcing, do it. */
                if (ULONG_CMP_GE(jiffies, rcu_state.jiffies_force_qs) ||
                    (gf & RCU_GP_FLAG_FQS)) {
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("fqsstart"));
                        rcu_gp_fqs(first_gp_fqs);
                        first_gp_fqs = false;
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("fqsend"));
                        cond_resched_tasks_rcu_qs();
                        WRITE_ONCE(rcu_state.gp_activity, jiffies);
@@ -1683,8 +1697,7 @@ static void rcu_gp_fqs_loop(void)
                        cond_resched_tasks_rcu_qs();
                        WRITE_ONCE(rcu_state.gp_activity, jiffies);
                        WARN_ON(signal_pending(current));
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("fqswaitsig"));
                        ret = 1; /* Keep old FQS timing. */
                        j = jiffies;
@@ -1701,8 +1714,9 @@ static void rcu_gp_fqs_loop(void)
  */
 static void rcu_gp_cleanup(void)
 {
-       unsigned long gp_duration;
+       int cpu;
        bool needgp = false;
+       unsigned long gp_duration;
        unsigned long new_gp_seq;
        bool offloaded;
        struct rcu_data *rdp;
@@ -1748,6 +1762,12 @@ static void rcu_gp_cleanup(void)
                        needgp = __note_gp_changes(rnp, rdp) || needgp;
                /* smp_mb() provided by prior unlock-lock pair. */
                needgp = rcu_future_gp_cleanup(rnp) || needgp;
+               // Reset overload indication for CPUs no longer overloaded
+               if (rcu_is_leaf_node(rnp))
+                       for_each_leaf_node_cpu_mask(rnp, cpu, rnp->cbovldmask) {
+                               rdp = per_cpu_ptr(&rcu_data, cpu);
+                               check_cb_ovld_locked(rdp, rnp);
+                       }
                sq = rcu_nocb_gp_get(rnp);
                raw_spin_unlock_irq_rcu_node(rnp);
                rcu_nocb_gp_cleanup(sq);
@@ -1774,9 +1794,9 @@ static void rcu_gp_cleanup(void)
                    rcu_segcblist_is_offloaded(&rdp->cblist);
        if ((offloaded || !rcu_accelerate_cbs(rnp, rdp)) && needgp) {
                WRITE_ONCE(rcu_state.gp_flags, RCU_GP_FLAG_INIT);
-               rcu_state.gp_req_activity = jiffies;
+               WRITE_ONCE(rcu_state.gp_req_activity, jiffies);
                trace_rcu_grace_period(rcu_state.name,
-                                      READ_ONCE(rcu_state.gp_seq),
+                                      rcu_state.gp_seq,
                                       TPS("newreq"));
        } else {
                WRITE_ONCE(rcu_state.gp_flags,
@@ -1795,8 +1815,7 @@ static int __noreturn rcu_gp_kthread(void *unused)
 
                /* Handle grace-period start. */
                for (;;) {
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("reqwait"));
                        rcu_state.gp_state = RCU_GP_WAIT_GPS;
                        swait_event_idle_exclusive(rcu_state.gp_wq,
@@ -1809,8 +1828,7 @@ static int __noreturn rcu_gp_kthread(void *unused)
                        cond_resched_tasks_rcu_qs();
                        WRITE_ONCE(rcu_state.gp_activity, jiffies);
                        WARN_ON(signal_pending(current));
-                       trace_rcu_grace_period(rcu_state.name,
-                                              READ_ONCE(rcu_state.gp_seq),
+                       trace_rcu_grace_period(rcu_state.name, rcu_state.gp_seq,
                                               TPS("reqwaitsig"));
                }
 
@@ -1881,7 +1899,7 @@ static void rcu_report_qs_rnp(unsigned long mask, struct rcu_node *rnp,
                WARN_ON_ONCE(oldmask); /* Any child must be all zeroed! */
                WARN_ON_ONCE(!rcu_is_leaf_node(rnp) &&
                             rcu_preempt_blocked_readers_cgp(rnp));
-               rnp->qsmask &= ~mask;
+               WRITE_ONCE(rnp->qsmask, rnp->qsmask & ~mask);
                trace_rcu_quiescent_state_report(rcu_state.name, rnp->gp_seq,
                                                 mask, rnp->qsmask, rnp->level,
                                                 rnp->grplo, rnp->grphi,
@@ -1904,7 +1922,7 @@ static void rcu_report_qs_rnp(unsigned long mask, struct rcu_node *rnp,
                rnp_c = rnp;
                rnp = rnp->parent;
                raw_spin_lock_irqsave_rcu_node(rnp, flags);
-               oldmask = rnp_c->qsmask;
+               oldmask = READ_ONCE(rnp_c->qsmask);
        }
 
        /*
@@ -1987,6 +2005,8 @@ rcu_report_qs_rdp(int cpu, struct rcu_data *rdp)
                return;
        }
        mask = rdp->grpmask;
+       if (rdp->cpu == smp_processor_id())
+               rdp->core_needs_qs = false;
        if ((rnp->qsmask & mask) == 0) {
                raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
        } else {
@@ -2052,7 +2072,7 @@ int rcutree_dying_cpu(unsigned int cpu)
                return 0;
 
        blkd = !!(rnp->qsmask & rdp->grpmask);
-       trace_rcu_grace_period(rcu_state.name, rnp->gp_seq,
+       trace_rcu_grace_period(rcu_state.name, READ_ONCE(rnp->gp_seq),
                               blkd ? TPS("cpuofl") : TPS("cpuofl-bgp"));
        return 0;
 }
@@ -2294,10 +2314,13 @@ static void force_qs_rnp(int (*f)(struct rcu_data *rdp))
        struct rcu_data *rdp;
        struct rcu_node *rnp;
 
+       rcu_state.cbovld = rcu_state.cbovldnext;
+       rcu_state.cbovldnext = false;
        rcu_for_each_leaf_node(rnp) {
                cond_resched_tasks_rcu_qs();
                mask = 0;
                raw_spin_lock_irqsave_rcu_node(rnp, flags);
+               rcu_state.cbovldnext |= !!rnp->cbovldmask;
                if (rnp->qsmask == 0) {
                        if (!IS_ENABLED(CONFIG_PREEMPT_RCU) ||
                            rcu_preempt_blocked_readers_cgp(rnp)) {
@@ -2579,11 +2602,48 @@ static void rcu_leak_callback(struct rcu_head *rhp)
 }
 
 /*
- * Helper function for call_rcu() and friends.  The cpu argument will
- * normally be -1, indicating "currently running CPU".  It may specify
- * a CPU only if that CPU is a no-CBs CPU.  Currently, only rcu_barrier()
- * is expected to specify a CPU.
+ * Check and if necessary update the leaf rcu_node structure's
+ * ->cbovldmask bit corresponding to the current CPU based on that CPU's
+ * number of queued RCU callbacks.  The caller must hold the leaf rcu_node
+ * structure's ->lock.
  */
+static void check_cb_ovld_locked(struct rcu_data *rdp, struct rcu_node *rnp)
+{
+       raw_lockdep_assert_held_rcu_node(rnp);
+       if (qovld_calc <= 0)
+               return; // Early boot and wildcard value set.
+       if (rcu_segcblist_n_cbs(&rdp->cblist) >= qovld_calc)
+               WRITE_ONCE(rnp->cbovldmask, rnp->cbovldmask | rdp->grpmask);
+       else
+               WRITE_ONCE(rnp->cbovldmask, rnp->cbovldmask & ~rdp->grpmask);
+}
+
+/*
+ * Check and if necessary update the leaf rcu_node structure's
+ * ->cbovldmask bit corresponding to the current CPU based on that CPU's
+ * number of queued RCU callbacks.  No locks need be held, but the
+ * caller must have disabled interrupts.
+ *
+ * Note that this function ignores the possibility that there are a lot
+ * of callbacks all of which have already seen the end of their respective
+ * grace periods.  This omission is due to the need for no-CBs CPUs to
+ * be holding ->nocb_lock to do this check, which is too heavy for a
+ * common-case operation.
+ */
+static void check_cb_ovld(struct rcu_data *rdp)
+{
+       struct rcu_node *const rnp = rdp->mynode;
+
+       if (qovld_calc <= 0 ||
+           ((rcu_segcblist_n_cbs(&rdp->cblist) >= qovld_calc) ==
+            !!(READ_ONCE(rnp->cbovldmask) & rdp->grpmask)))
+               return; // Early boot wildcard value or already set correctly.
+       raw_spin_lock_rcu_node(rnp);
+       check_cb_ovld_locked(rdp, rnp);
+       raw_spin_unlock_rcu_node(rnp);
+}
+
+/* Helper function for call_rcu() and friends.  */
 static void
 __call_rcu(struct rcu_head *head, rcu_callback_t func)
 {
@@ -2621,9 +2681,10 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func)
                        rcu_segcblist_init(&rdp->cblist);
        }
 
+       check_cb_ovld(rdp);
        if (rcu_nocb_try_bypass(rdp, head, &was_alldone, flags))
                return; // Enqueued onto ->nocb_bypass, so just leave.
-       /* If we get here, rcu_nocb_try_bypass() acquired ->nocb_lock. */
+       // If no-CBs CPU gets here, rcu_nocb_try_bypass() acquired ->nocb_lock.
        rcu_segcblist_enqueue(&rdp->cblist, head);
        if (__is_kfree_rcu_offset((unsigned long)func))
                trace_rcu_kfree_callback(rcu_state.name, head,
@@ -2689,22 +2750,47 @@ EXPORT_SYMBOL_GPL(call_rcu);
 #define KFREE_DRAIN_JIFFIES (HZ / 50)
 #define KFREE_N_BATCHES 2
 
+/*
+ * This macro defines how many entries the "records" array
+ * will contain. It is based on the fact that the size of
+ * kfree_rcu_bulk_data structure becomes exactly one page.
+ */
+#define KFREE_BULK_MAX_ENTR ((PAGE_SIZE / sizeof(void *)) - 3)
+
+/**
+ * struct kfree_rcu_bulk_data - single block to store kfree_rcu() pointers
+ * @nr_records: Number of active pointers in the array
+ * @records: Array of the kfree_rcu() pointers
+ * @next: Next bulk object in the block chain
+ * @head_free_debug: For debug, when CONFIG_DEBUG_OBJECTS_RCU_HEAD is set
+ */
+struct kfree_rcu_bulk_data {
+       unsigned long nr_records;
+       void *records[KFREE_BULK_MAX_ENTR];
+       struct kfree_rcu_bulk_data *next;
+       struct rcu_head *head_free_debug;
+};
+
 /**
  * struct kfree_rcu_cpu_work - single batch of kfree_rcu() requests
  * @rcu_work: Let queue_rcu_work() invoke workqueue handler after grace period
  * @head_free: List of kfree_rcu() objects waiting for a grace period
+ * @bhead_free: Bulk-List of kfree_rcu() objects waiting for a grace period
  * @krcp: Pointer to @kfree_rcu_cpu structure
  */
 
 struct kfree_rcu_cpu_work {
        struct rcu_work rcu_work;
        struct rcu_head *head_free;
+       struct kfree_rcu_bulk_data *bhead_free;
        struct kfree_rcu_cpu *krcp;
 };
 
 /**
  * struct kfree_rcu_cpu - batch up kfree_rcu() requests for RCU grace period
  * @head: List of kfree_rcu() objects not yet waiting for a grace period
+ * @bhead: Bulk-List of kfree_rcu() objects not yet waiting for a grace period
+ * @bcached: Keeps at most one object for later reuse when build chain blocks
  * @krw_arr: Array of batches of kfree_rcu() objects waiting for a grace period
  * @lock: Synchronize access to this structure
  * @monitor_work: Promote @head to @head_free after KFREE_DRAIN_JIFFIES
@@ -2718,6 +2804,8 @@ struct kfree_rcu_cpu_work {
  */
 struct kfree_rcu_cpu {
        struct rcu_head *head;
+       struct kfree_rcu_bulk_data *bhead;
+       struct kfree_rcu_bulk_data *bcached;
        struct kfree_rcu_cpu_work krw_arr[KFREE_N_BATCHES];
        spinlock_t lock;
        struct delayed_work monitor_work;
@@ -2727,14 +2815,24 @@ struct kfree_rcu_cpu {
 
 static DEFINE_PER_CPU(struct kfree_rcu_cpu, krc);
 
+static __always_inline void
+debug_rcu_head_unqueue_bulk(struct rcu_head *head)
+{
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+       for (; head; head = head->next)
+               debug_rcu_head_unqueue(head);
+#endif
+}
+
 /*
  * This function is invoked in workqueue context after a grace period.
- * It frees all the objects queued on ->head_free.
+ * It frees all the objects queued on ->bhead_free or ->head_free.
  */
 static void kfree_rcu_work(struct work_struct *work)
 {
        unsigned long flags;
        struct rcu_head *head, *next;
+       struct kfree_rcu_bulk_data *bhead, *bnext;
        struct kfree_rcu_cpu *krcp;
        struct kfree_rcu_cpu_work *krwp;
 
@@ -2744,22 +2842,44 @@ static void kfree_rcu_work(struct work_struct *work)
        spin_lock_irqsave(&krcp->lock, flags);
        head = krwp->head_free;
        krwp->head_free = NULL;
+       bhead = krwp->bhead_free;
+       krwp->bhead_free = NULL;
        spin_unlock_irqrestore(&krcp->lock, flags);
 
-       // List "head" is now private, so traverse locklessly.
+       /* "bhead" is now private, so traverse locklessly. */
+       for (; bhead; bhead = bnext) {
+               bnext = bhead->next;
+
+               debug_rcu_head_unqueue_bulk(bhead->head_free_debug);
+
+               rcu_lock_acquire(&rcu_callback_map);
+               trace_rcu_invoke_kfree_bulk_callback(rcu_state.name,
+                       bhead->nr_records, bhead->records);
+
+               kfree_bulk(bhead->nr_records, bhead->records);
+               rcu_lock_release(&rcu_callback_map);
+
+               if (cmpxchg(&krcp->bcached, NULL, bhead))
+                       free_page((unsigned long) bhead);
+
+               cond_resched_tasks_rcu_qs();
+       }
+
+       /*
+        * Emergency case only. It can happen under low memory
+        * condition when an allocation gets failed, so the "bulk"
+        * path can not be temporary maintained.
+        */
        for (; head; head = next) {
                unsigned long offset = (unsigned long)head->func;
 
                next = head->next;
-               // Potentially optimize with kfree_bulk in future.
                debug_rcu_head_unqueue(head);
                rcu_lock_acquire(&rcu_callback_map);
                trace_rcu_invoke_kfree_callback(rcu_state.name, head, offset);
 
-               if (!WARN_ON_ONCE(!__is_kfree_rcu_offset(offset))) {
-                       /* Could be optimized with kfree_bulk() in future. */
+               if (!WARN_ON_ONCE(!__is_kfree_rcu_offset(offset)))
                        kfree((void *)head - offset);
-               }
 
                rcu_lock_release(&rcu_callback_map);
                cond_resched_tasks_rcu_qs();
@@ -2774,26 +2894,48 @@ static void kfree_rcu_work(struct work_struct *work)
  */
 static inline bool queue_kfree_rcu_work(struct kfree_rcu_cpu *krcp)
 {
+       struct kfree_rcu_cpu_work *krwp;
+       bool queued = false;
        int i;
-       struct kfree_rcu_cpu_work *krwp = NULL;
 
        lockdep_assert_held(&krcp->lock);
-       for (i = 0; i < KFREE_N_BATCHES; i++)
-               if (!krcp->krw_arr[i].head_free) {
-                       krwp = &(krcp->krw_arr[i]);
-                       break;
-               }
 
-       // If a previous RCU batch is in progress, we cannot immediately
-       // queue another one, so return false to tell caller to retry.
-       if (!krwp)
-               return false;
+       for (i = 0; i < KFREE_N_BATCHES; i++) {
+               krwp = &(krcp->krw_arr[i]);
 
-       krwp->head_free = krcp->head;
-       krcp->head = NULL;
-       INIT_RCU_WORK(&krwp->rcu_work, kfree_rcu_work);
-       queue_rcu_work(system_wq, &krwp->rcu_work);
-       return true;
+               /*
+                * Try to detach bhead or head and attach it over any
+                * available corresponding free channel. It can be that
+                * a previous RCU batch is in progress, it means that
+                * immediately to queue another one is not possible so
+                * return false to tell caller to retry.
+                */
+               if ((krcp->bhead && !krwp->bhead_free) ||
+                               (krcp->head && !krwp->head_free)) {
+                       /* Channel 1. */
+                       if (!krwp->bhead_free) {
+                               krwp->bhead_free = krcp->bhead;
+                               krcp->bhead = NULL;
+                       }
+
+                       /* Channel 2. */
+                       if (!krwp->head_free) {
+                               krwp->head_free = krcp->head;
+                               krcp->head = NULL;
+                       }
+
+                       /*
+                        * One work is per one batch, so there are two "free channels",
+                        * "bhead_free" and "head_free" the batch can handle. It can be
+                        * that the work is in the pending state when two channels have
+                        * been detached following each other, one by one.
+                        */
+                       queue_rcu_work(system_wq, &krwp->rcu_work);
+                       queued = true;
+               }
+       }
+
+       return queued;
 }
 
 static inline void kfree_rcu_drain_unlock(struct kfree_rcu_cpu *krcp,
@@ -2830,19 +2972,65 @@ static void kfree_rcu_monitor(struct work_struct *work)
                spin_unlock_irqrestore(&krcp->lock, flags);
 }
 
+static inline bool
+kfree_call_rcu_add_ptr_to_bulk(struct kfree_rcu_cpu *krcp,
+       struct rcu_head *head, rcu_callback_t func)
+{
+       struct kfree_rcu_bulk_data *bnode;
+
+       if (unlikely(!krcp->initialized))
+               return false;
+
+       lockdep_assert_held(&krcp->lock);
+
+       /* Check if a new block is required. */
+       if (!krcp->bhead ||
+                       krcp->bhead->nr_records == KFREE_BULK_MAX_ENTR) {
+               bnode = xchg(&krcp->bcached, NULL);
+               if (!bnode) {
+                       WARN_ON_ONCE(sizeof(struct kfree_rcu_bulk_data) > PAGE_SIZE);
+
+                       bnode = (struct kfree_rcu_bulk_data *)
+                               __get_free_page(GFP_NOWAIT | __GFP_NOWARN);
+               }
+
+               /* Switch to emergency path. */
+               if (unlikely(!bnode))
+                       return false;
+
+               /* Initialize the new block. */
+               bnode->nr_records = 0;
+               bnode->next = krcp->bhead;
+               bnode->head_free_debug = NULL;
+
+               /* Attach it to the head. */
+               krcp->bhead = bnode;
+       }
+
+#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
+       head->func = func;
+       head->next = krcp->bhead->head_free_debug;
+       krcp->bhead->head_free_debug = head;
+#endif
+
+       /* Finally insert. */
+       krcp->bhead->records[krcp->bhead->nr_records++] =
+               (void *) head - (unsigned long) func;
+
+       return true;
+}
+
 /*
- * Queue a request for lazy invocation of kfree() after a grace period.
+ * Queue a request for lazy invocation of kfree_bulk()/kfree() after a grace
+ * period. Please note there are two paths are maintained, one is the main one
+ * that uses kfree_bulk() interface and second one is emergency one, that is
+ * used only when the main path can not be maintained temporary, due to memory
+ * pressure.
  *
  * Each kfree_call_rcu() request is added to a batch. The batch will be drained
- * every KFREE_DRAIN_JIFFIES number of jiffies. All the objects in the batch
- * will be kfree'd in workqueue context. This allows us to:
- *
- * 1.  Batch requests together to reduce the number of grace periods during
- *     heavy kfree_rcu() load.
- *
- * 2.  It makes it possible to use kfree_bulk() on a large number of
- *     kfree_rcu() requests thus reducing cache misses and the per-object
- *     overhead of kfree().
+ * every KFREE_DRAIN_JIFFIES number of jiffies. All the objects in the batch will
+ * be free'd in workqueue context. This allows us to: batch requests together to
+ * reduce the number of grace periods during heavy kfree_rcu() load.
  */
 void kfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
 {
@@ -2861,9 +3049,16 @@ void kfree_call_rcu(struct rcu_head *head, rcu_callback_t func)
                          __func__, head);
                goto unlock_return;
        }
-       head->func = func;
-       head->next = krcp->head;
-       krcp->head = head;
+
+       /*
+        * Under high memory pressure GFP_NOWAIT can fail,
+        * in that case the emergency path is maintained.
+        */
+       if (unlikely(!kfree_call_rcu_add_ptr_to_bulk(krcp, head, func))) {
+               head->func = func;
+               head->next = krcp->head;
+               krcp->head = head;
+       }
 
        // Set timer to drain after KFREE_DRAIN_JIFFIES.
        if (rcu_scheduler_active == RCU_SCHEDULER_RUNNING &&
@@ -3075,24 +3270,32 @@ static void rcu_barrier_trace(const char *s, int cpu, unsigned long done)
 /*
  * RCU callback function for rcu_barrier().  If we are last, wake
  * up the task executing rcu_barrier().
+ *
+ * Note that the value of rcu_state.barrier_sequence must be captured
+ * before the atomic_dec_and_test().  Otherwise, if this CPU is not last,
+ * other CPUs might count the value down to zero before this CPU gets
+ * around to invoking rcu_barrier_trace(), which might result in bogus
+ * data from the next instance of rcu_barrier().
  */
 static void rcu_barrier_callback(struct rcu_head *rhp)
 {
+       unsigned long __maybe_unused s = rcu_state.barrier_sequence;
+
        if (atomic_dec_and_test(&rcu_state.barrier_cpu_count)) {
-               rcu_barrier_trace(TPS("LastCB"), -1,
-                                 rcu_state.barrier_sequence);
+               rcu_barrier_trace(TPS("LastCB"), -1, s);
                complete(&rcu_state.barrier_completion);
        } else {
-               rcu_barrier_trace(TPS("CB"), -1, rcu_state.barrier_sequence);
+               rcu_barrier_trace(TPS("CB"), -1, s);
        }
 }
 
 /*
  * Called with preemption disabled, and from cross-cpu IRQ context.
  */
-static void rcu_barrier_func(void *unused)
+static void rcu_barrier_func(void *cpu_in)
 {
-       struct rcu_data *rdp = raw_cpu_ptr(&rcu_data);
+       uintptr_t cpu = (uintptr_t)cpu_in;
+       struct rcu_data *rdp = per_cpu_ptr(&rcu_data, cpu);
 
        rcu_barrier_trace(TPS("IRQ"), -1, rcu_state.barrier_sequence);
        rdp->barrier_head.func = rcu_barrier_callback;
@@ -3119,7 +3322,7 @@ static void rcu_barrier_func(void *unused)
  */
 void rcu_barrier(void)
 {
-       int cpu;
+       uintptr_t cpu;
        struct rcu_data *rdp;
        unsigned long s = rcu_seq_snap(&rcu_state.barrier_sequence);
 
@@ -3142,13 +3345,14 @@ void rcu_barrier(void)
        rcu_barrier_trace(TPS("Inc1"), -1, rcu_state.barrier_sequence);
 
        /*
-        * Initialize the count to one rather than to zero in order to
-        * avoid a too-soon return to zero in case of a short grace period
-        * (or preemption of this task).  Exclude CPU-hotplug operations
-        * to ensure that no offline CPU has callbacks queued.
+        * Initialize the count to two rather than to zero in order
+        * to avoid a too-soon return to zero in case of an immediate
+        * invocation of the just-enqueued callback (or preemption of
+        * this task).  Exclude CPU-hotplug operations to ensure that no
+        * offline non-offloaded CPU has callbacks queued.
         */
        init_completion(&rcu_state.barrier_completion);
-       atomic_set(&rcu_state.barrier_cpu_count, 1);
+       atomic_set(&rcu_state.barrier_cpu_count, 2);
        get_online_cpus();
 
        /*
@@ -3158,13 +3362,23 @@ void rcu_barrier(void)
         */
        for_each_possible_cpu(cpu) {
                rdp = per_cpu_ptr(&rcu_data, cpu);
-               if (!cpu_online(cpu) &&
+               if (cpu_is_offline(cpu) &&
                    !rcu_segcblist_is_offloaded(&rdp->cblist))
                        continue;
-               if (rcu_segcblist_n_cbs(&rdp->cblist)) {
+               if (rcu_segcblist_n_cbs(&rdp->cblist) && cpu_online(cpu)) {
                        rcu_barrier_trace(TPS("OnlineQ"), cpu,
                                          rcu_state.barrier_sequence);
-                       smp_call_function_single(cpu, rcu_barrier_func, NULL, 1);
+                       smp_call_function_single(cpu, rcu_barrier_func, (void *)cpu, 1);
+               } else if (rcu_segcblist_n_cbs(&rdp->cblist) &&
+                          cpu_is_offline(cpu)) {
+                       rcu_barrier_trace(TPS("OfflineNoCBQ"), cpu,
+                                         rcu_state.barrier_sequence);
+                       local_irq_disable();
+                       rcu_barrier_func((void *)cpu);
+                       local_irq_enable();
+               } else if (cpu_is_offline(cpu)) {
+                       rcu_barrier_trace(TPS("OfflineNoCBNoQ"), cpu,
+                                         rcu_state.barrier_sequence);
                } else {
                        rcu_barrier_trace(TPS("OnlineNQ"), cpu,
                                          rcu_state.barrier_sequence);
@@ -3176,7 +3390,7 @@ void rcu_barrier(void)
         * Now that we have an rcu_barrier_callback() callback on each
         * CPU, and thus each counted, remove the initial count.
         */
-       if (atomic_dec_and_test(&rcu_state.barrier_cpu_count))
+       if (atomic_sub_and_test(2, &rcu_state.barrier_cpu_count))
                complete(&rcu_state.barrier_completion);
 
        /* Wait for all rcu_barrier_callback() callbacks to be invoked. */
@@ -3275,12 +3489,12 @@ int rcutree_prepare_cpu(unsigned int cpu)
        rnp = rdp->mynode;
        raw_spin_lock_rcu_node(rnp);            /* irqs already disabled. */
        rdp->beenonline = true;  /* We have now been online. */
-       rdp->gp_seq = rnp->gp_seq;
-       rdp->gp_seq_needed = rnp->gp_seq;
+       rdp->gp_seq = READ_ONCE(rnp->gp_seq);
+       rdp->gp_seq_needed = rdp->gp_seq;
        rdp->cpu_no_qs.b.norm = true;
        rdp->core_needs_qs = false;
        rdp->rcu_iw_pending = false;
-       rdp->rcu_iw_gp_seq = rnp->gp_seq - 1;
+       rdp->rcu_iw_gp_seq = rdp->gp_seq - 1;
        trace_rcu_grace_period(rcu_state.name, rdp->gp_seq, TPS("cpuonl"));
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
        rcu_prepare_kthreads(cpu);
@@ -3378,7 +3592,7 @@ void rcu_cpu_starting(unsigned int cpu)
        rnp = rdp->mynode;
        mask = rdp->grpmask;
        raw_spin_lock_irqsave_rcu_node(rnp, flags);
-       rnp->qsmaskinitnext |= mask;
+       WRITE_ONCE(rnp->qsmaskinitnext, rnp->qsmaskinitnext | mask);
        oldmask = rnp->expmaskinitnext;
        rnp->expmaskinitnext |= mask;
        oldmask ^= rnp->expmaskinitnext;
@@ -3431,7 +3645,7 @@ void rcu_report_dead(unsigned int cpu)
                rcu_report_qs_rnp(mask, rnp, rnp->gp_seq, flags);
                raw_spin_lock_irqsave_rcu_node(rnp, flags);
        }
-       rnp->qsmaskinitnext &= ~mask;
+       WRITE_ONCE(rnp->qsmaskinitnext, rnp->qsmaskinitnext & ~mask);
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
        raw_spin_unlock(&rcu_state.ofl_lock);
 
@@ -3545,7 +3759,10 @@ static int __init rcu_spawn_gp_kthread(void)
        }
        rnp = rcu_get_root();
        raw_spin_lock_irqsave_rcu_node(rnp, flags);
-       rcu_state.gp_kthread = t;
+       WRITE_ONCE(rcu_state.gp_activity, jiffies);
+       WRITE_ONCE(rcu_state.gp_req_activity, jiffies);
+       // Reset .gp_activity and .gp_req_activity before setting .gp_kthread.
+       smp_store_release(&rcu_state.gp_kthread, t);  /* ^^^ */
        raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
        wake_up_process(t);
        rcu_spawn_nocb_kthreads();
@@ -3769,8 +3986,11 @@ static void __init kfree_rcu_batch_init(void)
                struct kfree_rcu_cpu *krcp = per_cpu_ptr(&krc, cpu);
 
                spin_lock_init(&krcp->lock);
-               for (i = 0; i < KFREE_N_BATCHES; i++)
+               for (i = 0; i < KFREE_N_BATCHES; i++) {
+                       INIT_RCU_WORK(&krcp->krw_arr[i].rcu_work, kfree_rcu_work);
                        krcp->krw_arr[i].krcp = krcp;
+               }
+
                INIT_DELAYED_WORK(&krcp->monitor_work, kfree_rcu_monitor);
                krcp->initialized = true;
        }
@@ -3809,6 +4029,13 @@ void __init rcu_init(void)
        rcu_par_gp_wq = alloc_workqueue("rcu_par_gp", WQ_MEM_RECLAIM, 0);
        WARN_ON(!rcu_par_gp_wq);
        srcu_init();
+
+       /* Fill in default value for rcutree.qovld boot parameter. */
+       /* -After- the rcu_node ->lock fields are initialized! */
+       if (qovld < 0)
+               qovld_calc = DEFAULT_RCU_QOVLD_MULT * qhimark;
+       else
+               qovld_calc = qovld;
 }
 
 #include "tree_stall.h"
index 0c87e4c..9dc2ec0 100644 (file)
@@ -68,6 +68,8 @@ struct rcu_node {
                                /* Online CPUs for next expedited GP. */
                                /*  Any CPU that has ever been online will */
                                /*  have its bit set. */
+       unsigned long cbovldmask;
+                               /* CPUs experiencing callback overload. */
        unsigned long ffmask;   /* Fully functional CPUs. */
        unsigned long grpmask;  /* Mask to apply to parent qsmask. */
                                /*  Only one bit will be set in this mask. */
@@ -321,6 +323,8 @@ struct rcu_state {
        atomic_t expedited_need_qs;             /* # CPUs left to check in. */
        struct swait_queue_head expedited_wq;   /* Wait for check-ins. */
        int ncpus_snap;                         /* # CPUs seen last time. */
+       u8 cbovld;                              /* Callback overload now? */
+       u8 cbovldnext;                          /* ^        ^  next time? */
 
        unsigned long jiffies_force_qs;         /* Time at which to invoke */
                                                /*  force_quiescent_state(). */
index dcbd757..1a617b9 100644 (file)
@@ -314,7 +314,7 @@ static bool exp_funnel_lock(unsigned long s)
                                   sync_exp_work_done(s));
                        return true;
                }
-               rnp->exp_seq_rq = s; /* Followers can wait on us. */
+               WRITE_ONCE(rnp->exp_seq_rq, s); /* Followers can wait on us. */
                spin_unlock(&rnp->exp_lock);
                trace_rcu_exp_funnel_lock(rcu_state.name, rnp->level,
                                          rnp->grplo, rnp->grphi, TPS("nxtlvl"));
@@ -485,6 +485,7 @@ static bool synchronize_rcu_expedited_wait_once(long tlimit)
 static void synchronize_rcu_expedited_wait(void)
 {
        int cpu;
+       unsigned long j;
        unsigned long jiffies_stall;
        unsigned long jiffies_start;
        unsigned long mask;
@@ -496,7 +497,7 @@ static void synchronize_rcu_expedited_wait(void)
        trace_rcu_exp_grace_period(rcu_state.name, rcu_exp_gp_seq_endval(), TPS("startwait"));
        jiffies_stall = rcu_jiffies_till_stall_check();
        jiffies_start = jiffies;
-       if (IS_ENABLED(CONFIG_NO_HZ_FULL)) {
+       if (tick_nohz_full_enabled() && rcu_inkernel_boot_has_ended()) {
                if (synchronize_rcu_expedited_wait_once(1))
                        return;
                rcu_for_each_leaf_node(rnp) {
@@ -508,12 +509,16 @@ static void synchronize_rcu_expedited_wait(void)
                                tick_dep_set_cpu(cpu, TICK_DEP_BIT_RCU_EXP);
                        }
                }
+               j = READ_ONCE(jiffies_till_first_fqs);
+               if (synchronize_rcu_expedited_wait_once(j + HZ))
+                       return;
+               WARN_ON_ONCE(IS_ENABLED(CONFIG_PREEMPT_RT));
        }
 
        for (;;) {
                if (synchronize_rcu_expedited_wait_once(jiffies_stall))
                        return;
-               if (rcu_cpu_stall_suppress)
+               if (rcu_stall_is_suppressed())
                        continue;
                panic_on_rcu_stall();
                pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {",
@@ -589,7 +594,7 @@ static void rcu_exp_wait_wake(unsigned long s)
                        spin_lock(&rnp->exp_lock);
                        /* Recheck, avoid hang in case someone just arrived. */
                        if (ULONG_CMP_LT(rnp->exp_seq_rq, s))
-                               rnp->exp_seq_rq = s;
+                               WRITE_ONCE(rnp->exp_seq_rq, s);
                        spin_unlock(&rnp->exp_lock);
                }
                smp_mb(); /* All above changes before wakeup. */
index c6ea81c..097635c 100644 (file)
@@ -56,6 +56,8 @@ static void __init rcu_bootup_announce_oddness(void)
                pr_info("\tBoot-time adjustment of callback high-water mark to %ld.\n", qhimark);
        if (qlowmark != DEFAULT_RCU_QLOMARK)
                pr_info("\tBoot-time adjustment of callback low-water mark to %ld.\n", qlowmark);
+       if (qovld != DEFAULT_RCU_QOVLD)
+               pr_info("\tBoot-time adjustment of callback overload level to %ld.\n", qovld);
        if (jiffies_till_first_fqs != ULONG_MAX)
                pr_info("\tBoot-time adjustment of first FQS scan delay to %ld jiffies.\n", jiffies_till_first_fqs);
        if (jiffies_till_next_fqs != ULONG_MAX)
@@ -753,7 +755,7 @@ dump_blkd_tasks(struct rcu_node *rnp, int ncheck)
        raw_lockdep_assert_held_rcu_node(rnp);
        pr_info("%s: grp: %d-%d level: %d ->gp_seq %ld ->completedqs %ld\n",
                __func__, rnp->grplo, rnp->grphi, rnp->level,
-               (long)rnp->gp_seq, (long)rnp->completedqs);
+               (long)READ_ONCE(rnp->gp_seq), (long)rnp->completedqs);
        for (rnp1 = rnp; rnp1; rnp1 = rnp1->parent)
                pr_info("%s: %d:%d ->qsmask %#lx ->qsmaskinit %#lx ->qsmaskinitnext %#lx\n",
                        __func__, rnp1->grplo, rnp1->grphi, rnp1->qsmask, rnp1->qsmaskinit, rnp1->qsmaskinitnext);
@@ -1032,18 +1034,18 @@ static int rcu_boost_kthread(void *arg)
 
        trace_rcu_utilization(TPS("Start boost kthread@init"));
        for (;;) {
-               rnp->boost_kthread_status = RCU_KTHREAD_WAITING;
+               WRITE_ONCE(rnp->boost_kthread_status, RCU_KTHREAD_WAITING);
                trace_rcu_utilization(TPS("End boost kthread@rcu_wait"));
                rcu_wait(rnp->boost_tasks || rnp->exp_tasks);
                trace_rcu_utilization(TPS("Start boost kthread@rcu_wait"));
-               rnp->boost_kthread_status = RCU_KTHREAD_RUNNING;
+               WRITE_ONCE(rnp->boost_kthread_status, RCU_KTHREAD_RUNNING);
                more2boost = rcu_boost(rnp);
                if (more2boost)
                        spincnt++;
                else
                        spincnt = 0;
                if (spincnt > 10) {
-                       rnp->boost_kthread_status = RCU_KTHREAD_YIELDING;
+                       WRITE_ONCE(rnp->boost_kthread_status, RCU_KTHREAD_YIELDING);
                        trace_rcu_utilization(TPS("End boost kthread@rcu_yield"));
                        schedule_timeout_interruptible(2);
                        trace_rcu_utilization(TPS("Start boost kthread@rcu_yield"));
@@ -1077,12 +1079,12 @@ static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
            (rnp->gp_tasks != NULL &&
             rnp->boost_tasks == NULL &&
             rnp->qsmask == 0 &&
-            ULONG_CMP_GE(jiffies, rnp->boost_time))) {
+            (ULONG_CMP_GE(jiffies, rnp->boost_time) || rcu_state.cbovld))) {
                if (rnp->exp_tasks == NULL)
                        rnp->boost_tasks = rnp->gp_tasks;
                raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
                rcu_wake_cond(rnp->boost_kthread_task,
-                             rnp->boost_kthread_status);
+                             READ_ONCE(rnp->boost_kthread_status));
        } else {
                raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
        }
@@ -1486,6 +1488,7 @@ module_param(nocb_nobypass_lim_per_jiffy, int, 0);
  * flag the contention.
  */
 static void rcu_nocb_bypass_lock(struct rcu_data *rdp)
+       __acquires(&rdp->nocb_bypass_lock)
 {
        lockdep_assert_irqs_disabled();
        if (raw_spin_trylock(&rdp->nocb_bypass_lock))
@@ -1529,6 +1532,7 @@ static bool rcu_nocb_bypass_trylock(struct rcu_data *rdp)
  * Release the specified rcu_data structure's ->nocb_bypass_lock.
  */
 static void rcu_nocb_bypass_unlock(struct rcu_data *rdp)
+       __releases(&rdp->nocb_bypass_lock)
 {
        lockdep_assert_irqs_disabled();
        raw_spin_unlock(&rdp->nocb_bypass_lock);
@@ -1577,8 +1581,7 @@ static void rcu_nocb_unlock_irqrestore(struct rcu_data *rdp,
 static void rcu_lockdep_assert_cblist_protected(struct rcu_data *rdp)
 {
        lockdep_assert_irqs_disabled();
-       if (rcu_segcblist_is_offloaded(&rdp->cblist) &&
-           cpu_online(rdp->cpu))
+       if (rcu_segcblist_is_offloaded(&rdp->cblist))
                lockdep_assert_held(&rdp->nocb_lock);
 }
 
@@ -1930,6 +1933,7 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
        struct rcu_data *rdp;
        struct rcu_node *rnp;
        unsigned long wait_gp_seq = 0; // Suppress "use uninitialized" warning.
+       bool wasempty = false;
 
        /*
         * Each pass through the following loop checks for CBs and for the
@@ -1969,10 +1973,13 @@ static void nocb_gp_wait(struct rcu_data *my_rdp)
                     rcu_seq_done(&rnp->gp_seq, cur_gp_seq))) {
                        raw_spin_lock_rcu_node(rnp); /* irqs disabled. */
                        needwake_gp = rcu_advance_cbs(rnp, rdp);
+                       wasempty = rcu_segcblist_restempty(&rdp->cblist,
+                                                          RCU_NEXT_READY_TAIL);
                        raw_spin_unlock_rcu_node(rnp); /* irqs disabled. */
                }
                // Need to wait on some grace period?
-               WARN_ON_ONCE(!rcu_segcblist_restempty(&rdp->cblist,
+               WARN_ON_ONCE(wasempty &&
+                            !rcu_segcblist_restempty(&rdp->cblist,
                                                      RCU_NEXT_READY_TAIL));
                if (rcu_segcblist_nextgp(&rdp->cblist, &cur_gp_seq)) {
                        if (!needwait_gp ||
index 55f9b84..119ed6a 100644 (file)
@@ -102,7 +102,7 @@ static void record_gp_stall_check_time(void)
        unsigned long j = jiffies;
        unsigned long j1;
 
-       rcu_state.gp_start = j;
+       WRITE_ONCE(rcu_state.gp_start, j);
        j1 = rcu_jiffies_till_stall_check();
        /* Record ->gp_start before ->jiffies_stall. */
        smp_store_release(&rcu_state.jiffies_stall, j + j1); /* ^^^ */
@@ -383,7 +383,7 @@ static void print_other_cpu_stall(unsigned long gp_seq)
 
        /* Kick and suppress, if so configured. */
        rcu_stall_kick_kthreads();
-       if (rcu_cpu_stall_suppress)
+       if (rcu_stall_is_suppressed())
                return;
 
        /*
@@ -452,7 +452,7 @@ static void print_cpu_stall(void)
 
        /* Kick and suppress, if so configured. */
        rcu_stall_kick_kthreads();
-       if (rcu_cpu_stall_suppress)
+       if (rcu_stall_is_suppressed())
                return;
 
        /*
@@ -504,7 +504,7 @@ static void check_cpu_stall(struct rcu_data *rdp)
        unsigned long js;
        struct rcu_node *rnp;
 
-       if ((rcu_cpu_stall_suppress && !rcu_kick_kthreads) ||
+       if ((rcu_stall_is_suppressed() && !rcu_kick_kthreads) ||
            !rcu_gp_in_progress())
                return;
        rcu_stall_kick_kthreads();
@@ -578,6 +578,7 @@ void show_rcu_gp_kthreads(void)
        unsigned long jw;
        struct rcu_data *rdp;
        struct rcu_node *rnp;
+       struct task_struct *t = READ_ONCE(rcu_state.gp_kthread);
 
        j = jiffies;
        ja = j - READ_ONCE(rcu_state.gp_activity);
@@ -585,28 +586,28 @@ void show_rcu_gp_kthreads(void)
        jw = j - READ_ONCE(rcu_state.gp_wake_time);
        pr_info("%s: wait state: %s(%d) ->state: %#lx delta ->gp_activity %lu ->gp_req_activity %lu ->gp_wake_time %lu ->gp_wake_seq %ld ->gp_seq %ld ->gp_seq_needed %ld ->gp_flags %#x\n",
                rcu_state.name, gp_state_getname(rcu_state.gp_state),
-               rcu_state.gp_state,
-               rcu_state.gp_kthread ? rcu_state.gp_kthread->state : 0x1ffffL,
+               rcu_state.gp_state, t ? t->state : 0x1ffffL,
                ja, jr, jw, (long)READ_ONCE(rcu_state.gp_wake_seq),
                (long)READ_ONCE(rcu_state.gp_seq),
                (long)READ_ONCE(rcu_get_root()->gp_seq_needed),
                READ_ONCE(rcu_state.gp_flags));
        rcu_for_each_node_breadth_first(rnp) {
-               if (ULONG_CMP_GE(rcu_state.gp_seq, rnp->gp_seq_needed))
+               if (ULONG_CMP_GE(READ_ONCE(rcu_state.gp_seq),
+                                READ_ONCE(rnp->gp_seq_needed)))
                        continue;
                pr_info("\trcu_node %d:%d ->gp_seq %ld ->gp_seq_needed %ld\n",
-                       rnp->grplo, rnp->grphi, (long)rnp->gp_seq,
-                       (long)rnp->gp_seq_needed);
+                       rnp->grplo, rnp->grphi, (long)READ_ONCE(rnp->gp_seq),
+                       (long)READ_ONCE(rnp->gp_seq_needed));
                if (!rcu_is_leaf_node(rnp))
                        continue;
                for_each_leaf_node_possible_cpu(rnp, cpu) {
                        rdp = per_cpu_ptr(&rcu_data, cpu);
-                       if (rdp->gpwrap ||
-                           ULONG_CMP_GE(rcu_state.gp_seq,
-                                        rdp->gp_seq_needed))
+                       if (READ_ONCE(rdp->gpwrap) ||
+                           ULONG_CMP_GE(READ_ONCE(rcu_state.gp_seq),
+                                        READ_ONCE(rdp->gp_seq_needed)))
                                continue;
                        pr_info("\tcpu %d ->gp_seq_needed %ld\n",
-                               cpu, (long)rdp->gp_seq_needed);
+                               cpu, (long)READ_ONCE(rdp->gp_seq_needed));
                }
        }
        for_each_possible_cpu(cpu) {
@@ -631,7 +632,9 @@ static void rcu_check_gp_start_stall(struct rcu_node *rnp, struct rcu_data *rdp,
        static atomic_t warned = ATOMIC_INIT(0);
 
        if (!IS_ENABLED(CONFIG_PROVE_RCU) || rcu_gp_in_progress() ||
-           ULONG_CMP_GE(rnp_root->gp_seq, rnp_root->gp_seq_needed))
+           ULONG_CMP_GE(READ_ONCE(rnp_root->gp_seq),
+                        READ_ONCE(rnp_root->gp_seq_needed)) ||
+           !smp_load_acquire(&rcu_state.gp_kthread)) // Get stable kthread.
                return;
        j = jiffies; /* Expensive access, and in common case don't get here. */
        if (time_before(j, READ_ONCE(rcu_state.gp_req_activity) + gpssdelay) ||
@@ -642,7 +645,8 @@ static void rcu_check_gp_start_stall(struct rcu_node *rnp, struct rcu_data *rdp,
        raw_spin_lock_irqsave_rcu_node(rnp, flags);
        j = jiffies;
        if (rcu_gp_in_progress() ||
-           ULONG_CMP_GE(rnp_root->gp_seq, rnp_root->gp_seq_needed) ||
+           ULONG_CMP_GE(READ_ONCE(rnp_root->gp_seq),
+                        READ_ONCE(rnp_root->gp_seq_needed)) ||
            time_before(j, READ_ONCE(rcu_state.gp_req_activity) + gpssdelay) ||
            time_before(j, READ_ONCE(rcu_state.gp_activity) + gpssdelay) ||
            atomic_read(&warned)) {
@@ -655,9 +659,10 @@ static void rcu_check_gp_start_stall(struct rcu_node *rnp, struct rcu_data *rdp,
                raw_spin_lock_rcu_node(rnp_root); /* irqs already disabled. */
        j = jiffies;
        if (rcu_gp_in_progress() ||
-           ULONG_CMP_GE(rnp_root->gp_seq, rnp_root->gp_seq_needed) ||
-           time_before(j, rcu_state.gp_req_activity + gpssdelay) ||
-           time_before(j, rcu_state.gp_activity + gpssdelay) ||
+           ULONG_CMP_GE(READ_ONCE(rnp_root->gp_seq),
+                        READ_ONCE(rnp_root->gp_seq_needed)) ||
+           time_before(j, READ_ONCE(rcu_state.gp_req_activity) + gpssdelay) ||
+           time_before(j, READ_ONCE(rcu_state.gp_activity) + gpssdelay) ||
            atomic_xchg(&warned, 1)) {
                if (rnp_root != rnp)
                        /* irqs remain disabled. */
index 6c4b862..28a8bdc 100644 (file)
@@ -183,6 +183,8 @@ void rcu_unexpedite_gp(void)
 }
 EXPORT_SYMBOL_GPL(rcu_unexpedite_gp);
 
+static bool rcu_boot_ended __read_mostly;
+
 /*
  * Inform RCU of the end of the in-kernel boot sequence.
  */
@@ -191,7 +193,17 @@ void rcu_end_inkernel_boot(void)
        rcu_unexpedite_gp();
        if (rcu_normal_after_boot)
                WRITE_ONCE(rcu_normal, 1);
+       rcu_boot_ended = 1;
+}
+
+/*
+ * Let rcutorture know when it is OK to turn it up to eleven.
+ */
+bool rcu_inkernel_boot_has_ended(void)
+{
+       return rcu_boot_ended;
 }
+EXPORT_SYMBOL_GPL(rcu_inkernel_boot_has_ended);
 
 #endif /* #ifndef CONFIG_TINY_RCU */
 
@@ -227,18 +239,30 @@ core_initcall(rcu_set_runtime_mode);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key rcu_lock_key;
-struct lockdep_map rcu_lock_map =
-       STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
+struct lockdep_map rcu_lock_map = {
+       .name = "rcu_read_lock",
+       .key = &rcu_lock_key,
+       .wait_type_outer = LD_WAIT_FREE,
+       .wait_type_inner = LD_WAIT_CONFIG, /* XXX PREEMPT_RCU ? */
+};
 EXPORT_SYMBOL_GPL(rcu_lock_map);
 
 static struct lock_class_key rcu_bh_lock_key;
-struct lockdep_map rcu_bh_lock_map =
-       STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_bh", &rcu_bh_lock_key);
+struct lockdep_map rcu_bh_lock_map = {
+       .name = "rcu_read_lock_bh",
+       .key = &rcu_bh_lock_key,
+       .wait_type_outer = LD_WAIT_FREE,
+       .wait_type_inner = LD_WAIT_CONFIG, /* PREEMPT_LOCK also makes BH preemptible */
+};
 EXPORT_SYMBOL_GPL(rcu_bh_lock_map);
 
 static struct lock_class_key rcu_sched_lock_key;
-struct lockdep_map rcu_sched_lock_map =
-       STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_sched", &rcu_sched_lock_key);
+struct lockdep_map rcu_sched_lock_map = {
+       .name = "rcu_read_lock_sched",
+       .key = &rcu_sched_lock_key,
+       .wait_type_outer = LD_WAIT_FREE,
+       .wait_type_inner = LD_WAIT_SPIN,
+};
 EXPORT_SYMBOL_GPL(rcu_sched_lock_map);
 
 static struct lock_class_key rcu_callback_key;
@@ -464,13 +488,19 @@ EXPORT_SYMBOL_GPL(rcutorture_sched_setaffinity);
 #ifdef CONFIG_RCU_STALL_COMMON
 int rcu_cpu_stall_ftrace_dump __read_mostly;
 module_param(rcu_cpu_stall_ftrace_dump, int, 0644);
-int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */
+int rcu_cpu_stall_suppress __read_mostly; // !0 = suppress stall warnings.
 EXPORT_SYMBOL_GPL(rcu_cpu_stall_suppress);
 module_param(rcu_cpu_stall_suppress, int, 0644);
 int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
 module_param(rcu_cpu_stall_timeout, int, 0644);
 #endif /* #ifdef CONFIG_RCU_STALL_COMMON */
 
+// Suppress boot-time RCU CPU stall warnings and rcutorture writer stall
+// warnings.  Also used by rcutorture even if stall warnings are excluded.
+int rcu_cpu_stall_suppress_at_boot __read_mostly; // !0 = suppress boot stalls.
+EXPORT_SYMBOL_GPL(rcu_cpu_stall_suppress_at_boot);
+module_param(rcu_cpu_stall_suppress_at_boot, int, 0444);
+
 #ifdef CONFIG_TASKS_RCU
 
 /*
@@ -528,7 +558,7 @@ void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func)
        rhp->func = func;
        raw_spin_lock_irqsave(&rcu_tasks_cbs_lock, flags);
        needwake = !rcu_tasks_cbs_head;
-       *rcu_tasks_cbs_tail = rhp;
+       WRITE_ONCE(*rcu_tasks_cbs_tail, rhp);
        rcu_tasks_cbs_tail = &rhp->next;
        raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags);
        /* We can't create the thread unless interrupts are enabled. */
@@ -658,7 +688,7 @@ static int __noreturn rcu_tasks_kthread(void *arg)
                /* If there were none, wait a bit and start over. */
                if (!list) {
                        wait_event_interruptible(rcu_tasks_cbs_wq,
-                                                rcu_tasks_cbs_head);
+                                                READ_ONCE(rcu_tasks_cbs_head));
                        if (!rcu_tasks_cbs_head) {
                                WARN_ON(signal_pending(current));
                                schedule_timeout_interruptible(HZ/10);
@@ -801,7 +831,7 @@ static int __init rcu_spawn_tasks_kthread(void)
 core_initcall(rcu_spawn_tasks_kthread);
 
 /* Do the srcu_read_lock() for the above synchronize_srcu().  */
-void exit_tasks_rcu_start(void)
+void exit_tasks_rcu_start(void) __acquires(&tasks_rcu_exit_srcu)
 {
        preempt_disable();
        current->rcu_tasks_idx = __srcu_read_lock(&tasks_rcu_exit_srcu);
@@ -809,7 +839,7 @@ void exit_tasks_rcu_start(void)
 }
 
 /* Do the srcu_read_unlock() for the above synchronize_srcu().  */
-void exit_tasks_rcu_finish(void)
+void exit_tasks_rcu_finish(void) __releases(&tasks_rcu_exit_srcu)
 {
        preempt_disable();
        __srcu_read_unlock(&tasks_rcu_exit_srcu, current->rcu_tasks_idx);
index a1ad5b7..a778554 100644 (file)
@@ -29,12 +29,12 @@ void complete(struct completion *x)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&x->wait.lock, flags);
+       raw_spin_lock_irqsave(&x->wait.lock, flags);
 
        if (x->done != UINT_MAX)
                x->done++;
-       __wake_up_locked(&x->wait, TASK_NORMAL, 1);
-       spin_unlock_irqrestore(&x->wait.lock, flags);
+       swake_up_locked(&x->wait);
+       raw_spin_unlock_irqrestore(&x->wait.lock, flags);
 }
 EXPORT_SYMBOL(complete);
 
@@ -58,10 +58,12 @@ void complete_all(struct completion *x)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&x->wait.lock, flags);
+       lockdep_assert_RT_in_threaded_ctx();
+
+       raw_spin_lock_irqsave(&x->wait.lock, flags);
        x->done = UINT_MAX;
-       __wake_up_locked(&x->wait, TASK_NORMAL, 0);
-       spin_unlock_irqrestore(&x->wait.lock, flags);
+       swake_up_all_locked(&x->wait);
+       raw_spin_unlock_irqrestore(&x->wait.lock, flags);
 }
 EXPORT_SYMBOL(complete_all);
 
@@ -70,20 +72,20 @@ do_wait_for_common(struct completion *x,
                   long (*action)(long), long timeout, int state)
 {
        if (!x->done) {
-               DECLARE_WAITQUEUE(wait, current);
+               DECLARE_SWAITQUEUE(wait);
 
-               __add_wait_queue_entry_tail_exclusive(&x->wait, &wait);
                do {
                        if (signal_pending_state(state, current)) {
                                timeout = -ERESTARTSYS;
                                break;
                        }
+                       __prepare_to_swait(&x->wait, &wait);
                        __set_current_state(state);
-                       spin_unlock_irq(&x->wait.lock);
+                       raw_spin_unlock_irq(&x->wait.lock);
                        timeout = action(timeout);
-                       spin_lock_irq(&x->wait.lock);
+                       raw_spin_lock_irq(&x->wait.lock);
                } while (!x->done && timeout);
-               __remove_wait_queue(&x->wait, &wait);
+               __finish_swait(&x->wait, &wait);
                if (!x->done)
                        return timeout;
        }
@@ -100,9 +102,9 @@ __wait_for_common(struct completion *x,
 
        complete_acquire(x);
 
-       spin_lock_irq(&x->wait.lock);
+       raw_spin_lock_irq(&x->wait.lock);
        timeout = do_wait_for_common(x, action, timeout, state);
-       spin_unlock_irq(&x->wait.lock);
+       raw_spin_unlock_irq(&x->wait.lock);
 
        complete_release(x);
 
@@ -291,12 +293,12 @@ bool try_wait_for_completion(struct completion *x)
        if (!READ_ONCE(x->done))
                return false;
 
-       spin_lock_irqsave(&x->wait.lock, flags);
+       raw_spin_lock_irqsave(&x->wait.lock, flags);
        if (!x->done)
                ret = false;
        else if (x->done != UINT_MAX)
                x->done--;
-       spin_unlock_irqrestore(&x->wait.lock, flags);
+       raw_spin_unlock_irqrestore(&x->wait.lock, flags);
        return ret;
 }
 EXPORT_SYMBOL(try_wait_for_completion);
@@ -322,8 +324,8 @@ bool completion_done(struct completion *x)
         * otherwise we can end up freeing the completion before complete()
         * is done referencing it.
         */
-       spin_lock_irqsave(&x->wait.lock, flags);
-       spin_unlock_irqrestore(&x->wait.lock, flags);
+       raw_spin_lock_irqsave(&x->wait.lock, flags);
+       raw_spin_unlock_irqrestore(&x->wait.lock, flags);
        return true;
 }
 EXPORT_SYMBOL(completion_done);
index 1a9983d..a2694ba 100644 (file)
@@ -269,7 +269,6 @@ static void __hrtick_start(void *arg)
 
        rq_lock(rq, &rf);
        __hrtick_restart(rq);
-       rq->hrtick_csd_pending = 0;
        rq_unlock(rq, &rf);
 }
 
@@ -293,12 +292,10 @@ void hrtick_start(struct rq *rq, u64 delay)
 
        hrtimer_set_expires(timer, time);
 
-       if (rq == this_rq()) {
+       if (rq == this_rq())
                __hrtick_restart(rq);
-       } else if (!rq->hrtick_csd_pending) {
+       else
                smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
-               rq->hrtick_csd_pending = 1;
-       }
 }
 
 #else
@@ -322,8 +319,6 @@ void hrtick_start(struct rq *rq, u64 delay)
 static void hrtick_rq_init(struct rq *rq)
 {
 #ifdef CONFIG_SMP
-       rq->hrtick_csd_pending = 0;
-
        rq->hrtick_csd.flags = 0;
        rq->hrtick_csd.func = __hrtick_start;
        rq->hrtick_csd.info = rq;
@@ -761,7 +756,6 @@ static void set_load_weight(struct task_struct *p, bool update_load)
        if (task_has_idle_policy(p)) {
                load->weight = scale_load(WEIGHT_IDLEPRIO);
                load->inv_weight = WMULT_IDLEPRIO;
-               p->se.runnable_weight = load->weight;
                return;
        }
 
@@ -774,7 +768,6 @@ static void set_load_weight(struct task_struct *p, bool update_load)
        } else {
                load->weight = scale_load(sched_prio_to_weight[prio]);
                load->inv_weight = sched_prio_to_wmult[prio];
-               p->se.runnable_weight = load->weight;
        }
 }
 
@@ -1652,7 +1645,12 @@ static int __set_cpus_allowed_ptr(struct task_struct *p,
        if (cpumask_equal(p->cpus_ptr, new_mask))
                goto out;
 
-       dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask);
+       /*
+        * Picking a ~random cpu helps in cases where we are changing affinity
+        * for groups of tasks (ie. cpuset), so that load balancing is not
+        * immediately required to distribute the tasks within their new mask.
+        */
+       dest_cpu = cpumask_any_and_distribute(cpu_valid_mask, new_mask);
        if (dest_cpu >= nr_cpu_ids) {
                ret = -EINVAL;
                goto out;
@@ -3578,6 +3576,17 @@ unsigned long long task_sched_runtime(struct task_struct *p)
        return ns;
 }
 
+DEFINE_PER_CPU(unsigned long, thermal_pressure);
+
+void arch_set_thermal_pressure(struct cpumask *cpus,
+                              unsigned long th_pressure)
+{
+       int cpu;
+
+       for_each_cpu(cpu, cpus)
+               WRITE_ONCE(per_cpu(thermal_pressure, cpu), th_pressure);
+}
+
 /*
  * This function gets called by the timer code, with HZ frequency.
  * We call it with interrupts disabled.
@@ -3588,12 +3597,16 @@ void scheduler_tick(void)
        struct rq *rq = cpu_rq(cpu);
        struct task_struct *curr = rq->curr;
        struct rq_flags rf;
+       unsigned long thermal_pressure;
 
+       arch_scale_freq_tick();
        sched_clock_tick();
 
        rq_lock(rq, &rf);
 
        update_rq_clock(rq);
+       thermal_pressure = arch_scale_thermal_pressure(cpu_of(rq));
+       update_thermal_load_avg(rq_clock_thermal(rq), rq, thermal_pressure);
        curr->sched_class->task_tick(rq, curr, 0);
        calc_global_load_tick(rq);
        psi_task_tick(rq);
@@ -3671,7 +3684,6 @@ static void sched_tick_remote(struct work_struct *work)
        if (cpu_is_offline(cpu))
                goto out_unlock;
 
-       curr = rq->curr;
        update_rq_clock(rq);
 
        if (!is_idle_task(curr)) {
@@ -4074,6 +4086,8 @@ static void __sched notrace __schedule(bool preempt)
                 */
                ++*switch_count;
 
+               psi_sched_switch(prev, next, !task_on_rq_queued(prev));
+
                trace_sched_switch(preempt, prev, next);
 
                /* Also unlocks the rq: */
index 1a2719e..0033731 100644 (file)
@@ -41,8 +41,67 @@ static int convert_prio(int prio)
        return cpupri;
 }
 
+static inline int __cpupri_find(struct cpupri *cp, struct task_struct *p,
+                               struct cpumask *lowest_mask, int idx)
+{
+       struct cpupri_vec *vec  = &cp->pri_to_cpu[idx];
+       int skip = 0;
+
+       if (!atomic_read(&(vec)->count))
+               skip = 1;
+       /*
+        * When looking at the vector, we need to read the counter,
+        * do a memory barrier, then read the mask.
+        *
+        * Note: This is still all racey, but we can deal with it.
+        *  Ideally, we only want to look at masks that are set.
+        *
+        *  If a mask is not set, then the only thing wrong is that we
+        *  did a little more work than necessary.
+        *
+        *  If we read a zero count but the mask is set, because of the
+        *  memory barriers, that can only happen when the highest prio
+        *  task for a run queue has left the run queue, in which case,
+        *  it will be followed by a pull. If the task we are processing
+        *  fails to find a proper place to go, that pull request will
+        *  pull this task if the run queue is running at a lower
+        *  priority.
+        */
+       smp_rmb();
+
+       /* Need to do the rmb for every iteration */
+       if (skip)
+               return 0;
+
+       if (cpumask_any_and(p->cpus_ptr, vec->mask) >= nr_cpu_ids)
+               return 0;
+
+       if (lowest_mask) {
+               cpumask_and(lowest_mask, p->cpus_ptr, vec->mask);
+
+               /*
+                * We have to ensure that we have at least one bit
+                * still set in the array, since the map could have
+                * been concurrently emptied between the first and
+                * second reads of vec->mask.  If we hit this
+                * condition, simply act as though we never hit this
+                * priority level and continue on.
+                */
+               if (cpumask_empty(lowest_mask))
+                       return 0;
+       }
+
+       return 1;
+}
+
+int cpupri_find(struct cpupri *cp, struct task_struct *p,
+               struct cpumask *lowest_mask)
+{
+       return cpupri_find_fitness(cp, p, lowest_mask, NULL);
+}
+
 /**
- * cpupri_find - find the best (lowest-pri) CPU in the system
+ * cpupri_find_fitness - find the best (lowest-pri) CPU in the system
  * @cp: The cpupri context
  * @p: The task
  * @lowest_mask: A mask to fill in with selected CPUs (or NULL)
@@ -58,84 +117,59 @@ static int convert_prio(int prio)
  *
  * Return: (int)bool - CPUs were found
  */
-int cpupri_find(struct cpupri *cp, struct task_struct *p,
+int cpupri_find_fitness(struct cpupri *cp, struct task_struct *p,
                struct cpumask *lowest_mask,
                bool (*fitness_fn)(struct task_struct *p, int cpu))
 {
-       int idx = 0;
        int task_pri = convert_prio(p->prio);
+       int idx, cpu;
 
        BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES);
 
        for (idx = 0; idx < task_pri; idx++) {
-               struct cpupri_vec *vec  = &cp->pri_to_cpu[idx];
-               int skip = 0;
-
-               if (!atomic_read(&(vec)->count))
-                       skip = 1;
-               /*
-                * When looking at the vector, we need to read the counter,
-                * do a memory barrier, then read the mask.
-                *
-                * Note: This is still all racey, but we can deal with it.
-                *  Ideally, we only want to look at masks that are set.
-                *
-                *  If a mask is not set, then the only thing wrong is that we
-                *  did a little more work than necessary.
-                *
-                *  If we read a zero count but the mask is set, because of the
-                *  memory barriers, that can only happen when the highest prio
-                *  task for a run queue has left the run queue, in which case,
-                *  it will be followed by a pull. If the task we are processing
-                *  fails to find a proper place to go, that pull request will
-                *  pull this task if the run queue is running at a lower
-                *  priority.
-                */
-               smp_rmb();
 
-               /* Need to do the rmb for every iteration */
-               if (skip)
+               if (!__cpupri_find(cp, p, lowest_mask, idx))
                        continue;
 
-               if (cpumask_any_and(p->cpus_ptr, vec->mask) >= nr_cpu_ids)
-                       continue;
+               if (!lowest_mask || !fitness_fn)
+                       return 1;
 
-               if (lowest_mask) {
-                       int cpu;
-
-                       cpumask_and(lowest_mask, p->cpus_ptr, vec->mask);
-
-                       /*
-                        * We have to ensure that we have at least one bit
-                        * still set in the array, since the map could have
-                        * been concurrently emptied between the first and
-                        * second reads of vec->mask.  If we hit this
-                        * condition, simply act as though we never hit this
-                        * priority level and continue on.
-                        */
-                       if (cpumask_empty(lowest_mask))
-                               continue;
-
-                       if (!fitness_fn)
-                               return 1;
-
-                       /* Ensure the capacity of the CPUs fit the task */
-                       for_each_cpu(cpu, lowest_mask) {
-                               if (!fitness_fn(p, cpu))
-                                       cpumask_clear_cpu(cpu, lowest_mask);
-                       }
-
-                       /*
-                        * If no CPU at the current priority can fit the task
-                        * continue looking
-                        */
-                       if (cpumask_empty(lowest_mask))
-                               continue;
+               /* Ensure the capacity of the CPUs fit the task */
+               for_each_cpu(cpu, lowest_mask) {
+                       if (!fitness_fn(p, cpu))
+                               cpumask_clear_cpu(cpu, lowest_mask);
                }
 
+               /*
+                * If no CPU at the current priority can fit the task
+                * continue looking
+                */
+               if (cpumask_empty(lowest_mask))
+                       continue;
+
                return 1;
        }
 
+       /*
+        * If we failed to find a fitting lowest_mask, kick off a new search
+        * but without taking into account any fitness criteria this time.
+        *
+        * This rule favours honouring priority over fitting the task in the
+        * correct CPU (Capacity Awareness being the only user now).
+        * The idea is that if a higher priority task can run, then it should
+        * run even if this ends up being on unfitting CPU.
+        *
+        * The cost of this trade-off is not entirely clear and will probably
+        * be good for some workloads and bad for others.
+        *
+        * The main idea here is that if some CPUs were overcommitted, we try
+        * to spread which is what the scheduler traditionally did. Sys admins
+        * must do proper RT planning to avoid overloading the system if they
+        * really care.
+        */
+       if (fitness_fn)
+               return cpupri_find(cp, p, lowest_mask);
+
        return 0;
 }
 
index 32dd520..efbb492 100644 (file)
@@ -19,8 +19,10 @@ struct cpupri {
 
 #ifdef CONFIG_SMP
 int  cpupri_find(struct cpupri *cp, struct task_struct *p,
-                struct cpumask *lowest_mask,
-                bool (*fitness_fn)(struct task_struct *p, int cpu));
+                struct cpumask *lowest_mask);
+int  cpupri_find_fitness(struct cpupri *cp, struct task_struct *p,
+                        struct cpumask *lowest_mask,
+                        bool (*fitness_fn)(struct task_struct *p, int cpu));
 void cpupri_set(struct cpupri *cp, int cpu, int pri);
 int  cpupri_init(struct cpupri *cp);
 void cpupri_cleanup(struct cpupri *cp);
index cff3e65..dac9104 100644 (file)
@@ -909,8 +909,10 @@ void task_cputime(struct task_struct *t, u64 *utime, u64 *stime)
        } while (read_seqcount_retry(&vtime->seqcount, seq));
 }
 
-static int vtime_state_check(struct vtime *vtime, int cpu)
+static int vtime_state_fetch(struct vtime *vtime, int cpu)
 {
+       int state = READ_ONCE(vtime->state);
+
        /*
         * We raced against a context switch, fetch the
         * kcpustat task again.
@@ -927,10 +929,10 @@ static int vtime_state_check(struct vtime *vtime, int cpu)
         *
         * Case 1) is ok but 2) is not. So wait for a safe VTIME state.
         */
-       if (vtime->state == VTIME_INACTIVE)
+       if (state == VTIME_INACTIVE)
                return -EAGAIN;
 
-       return 0;
+       return state;
 }
 
 static u64 kcpustat_user_vtime(struct vtime *vtime)
@@ -949,14 +951,15 @@ static int kcpustat_field_vtime(u64 *cpustat,
 {
        struct vtime *vtime = &tsk->vtime;
        unsigned int seq;
-       int err;
 
        do {
+               int state;
+
                seq = read_seqcount_begin(&vtime->seqcount);
 
-               err = vtime_state_check(vtime, cpu);
-               if (err < 0)
-                       return err;
+               state = vtime_state_fetch(vtime, cpu);
+               if (state < 0)
+                       return state;
 
                *val = cpustat[usage];
 
@@ -969,7 +972,7 @@ static int kcpustat_field_vtime(u64 *cpustat,
                 */
                switch (usage) {
                case CPUTIME_SYSTEM:
-                       if (vtime->state == VTIME_SYS)
+                       if (state == VTIME_SYS)
                                *val += vtime->stime + vtime_delta(vtime);
                        break;
                case CPUTIME_USER:
@@ -981,11 +984,11 @@ static int kcpustat_field_vtime(u64 *cpustat,
                                *val += kcpustat_user_vtime(vtime);
                        break;
                case CPUTIME_GUEST:
-                       if (vtime->state == VTIME_GUEST && task_nice(tsk) <= 0)
+                       if (state == VTIME_GUEST && task_nice(tsk) <= 0)
                                *val += vtime->gtime + vtime_delta(vtime);
                        break;
                case CPUTIME_GUEST_NICE:
-                       if (vtime->state == VTIME_GUEST && task_nice(tsk) > 0)
+                       if (state == VTIME_GUEST && task_nice(tsk) > 0)
                                *val += vtime->gtime + vtime_delta(vtime);
                        break;
                default:
@@ -1036,23 +1039,23 @@ static int kcpustat_cpu_fetch_vtime(struct kernel_cpustat *dst,
 {
        struct vtime *vtime = &tsk->vtime;
        unsigned int seq;
-       int err;
 
        do {
                u64 *cpustat;
                u64 delta;
+               int state;
 
                seq = read_seqcount_begin(&vtime->seqcount);
 
-               err = vtime_state_check(vtime, cpu);
-               if (err < 0)
-                       return err;
+               state = vtime_state_fetch(vtime, cpu);
+               if (state < 0)
+                       return state;
 
                *dst = *src;
                cpustat = dst->cpustat;
 
                /* Task is sleeping, dead or idle, nothing to add */
-               if (vtime->state < VTIME_SYS)
+               if (state < VTIME_SYS)
                        continue;
 
                delta = vtime_delta(vtime);
@@ -1061,15 +1064,15 @@ static int kcpustat_cpu_fetch_vtime(struct kernel_cpustat *dst,
                 * Task runs either in user (including guest) or kernel space,
                 * add pending nohz time to the right place.
                 */
-               if (vtime->state == VTIME_SYS) {
+               if (state == VTIME_SYS) {
                        cpustat[CPUTIME_SYSTEM] += vtime->stime + delta;
-               } else if (vtime->state == VTIME_USER) {
+               } else if (state == VTIME_USER) {
                        if (task_nice(tsk) > 0)
                                cpustat[CPUTIME_NICE] += vtime->utime + delta;
                        else
                                cpustat[CPUTIME_USER] += vtime->utime + delta;
                } else {
-                       WARN_ON_ONCE(vtime->state != VTIME_GUEST);
+                       WARN_ON_ONCE(state != VTIME_GUEST);
                        if (task_nice(tsk) > 0) {
                                cpustat[CPUTIME_GUEST_NICE] += vtime->gtime + delta;
                                cpustat[CPUTIME_NICE] += vtime->gtime + delta;
@@ -1080,7 +1083,7 @@ static int kcpustat_cpu_fetch_vtime(struct kernel_cpustat *dst,
                }
        } while (read_seqcount_retry(&vtime->seqcount, seq));
 
-       return err;
+       return 0;
 }
 
 void kcpustat_cpu_fetch(struct kernel_cpustat *dst, int cpu)
index 43323f8..504d2f5 100644 (file)
@@ -153,7 +153,7 @@ void sub_running_bw(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
                __sub_running_bw(dl_se->dl_bw, dl_rq);
 }
 
-void dl_change_utilization(struct task_struct *p, u64 new_bw)
+static void dl_change_utilization(struct task_struct *p, u64 new_bw)
 {
        struct rq *rq;
 
@@ -334,6 +334,8 @@ static inline int is_leftmost(struct task_struct *p, struct dl_rq *dl_rq)
        return dl_rq->root.rb_leftmost == &dl_se->rb_node;
 }
 
+static void init_dl_rq_bw_ratio(struct dl_rq *dl_rq);
+
 void init_dl_bandwidth(struct dl_bandwidth *dl_b, u64 period, u64 runtime)
 {
        raw_spin_lock_init(&dl_b->dl_runtime_lock);
@@ -2496,7 +2498,7 @@ int sched_dl_global_validate(void)
        return ret;
 }
 
-void init_dl_rq_bw_ratio(struct dl_rq *dl_rq)
+static void init_dl_rq_bw_ratio(struct dl_rq *dl_rq)
 {
        if (global_rt_runtime() == RUNTIME_INF) {
                dl_rq->bw_ratio = 1 << RATIO_SHIFT;
index 879d3cc..8331bc0 100644 (file)
@@ -402,11 +402,10 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group
        }
 
        P(se->load.weight);
-       P(se->runnable_weight);
 #ifdef CONFIG_SMP
        P(se->avg.load_avg);
        P(se->avg.util_avg);
-       P(se->avg.runnable_load_avg);
+       P(se->avg.runnable_avg);
 #endif
 
 #undef PN_SCHEDSTAT
@@ -524,11 +523,10 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
        SEQ_printf(m, "  .%-30s: %d\n", "nr_running", cfs_rq->nr_running);
        SEQ_printf(m, "  .%-30s: %ld\n", "load", cfs_rq->load.weight);
 #ifdef CONFIG_SMP
-       SEQ_printf(m, "  .%-30s: %ld\n", "runnable_weight", cfs_rq->runnable_weight);
        SEQ_printf(m, "  .%-30s: %lu\n", "load_avg",
                        cfs_rq->avg.load_avg);
-       SEQ_printf(m, "  .%-30s: %lu\n", "runnable_load_avg",
-                       cfs_rq->avg.runnable_load_avg);
+       SEQ_printf(m, "  .%-30s: %lu\n", "runnable_avg",
+                       cfs_rq->avg.runnable_avg);
        SEQ_printf(m, "  .%-30s: %lu\n", "util_avg",
                        cfs_rq->avg.util_avg);
        SEQ_printf(m, "  .%-30s: %u\n", "util_est_enqueued",
@@ -537,8 +535,8 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
                        cfs_rq->removed.load_avg);
        SEQ_printf(m, "  .%-30s: %ld\n", "removed.util_avg",
                        cfs_rq->removed.util_avg);
-       SEQ_printf(m, "  .%-30s: %ld\n", "removed.runnable_sum",
-                       cfs_rq->removed.runnable_sum);
+       SEQ_printf(m, "  .%-30s: %ld\n", "removed.runnable_avg",
+                       cfs_rq->removed.runnable_avg);
 #ifdef CONFIG_FAIR_GROUP_SCHED
        SEQ_printf(m, "  .%-30s: %lu\n", "tg_load_avg_contrib",
                        cfs_rq->tg_load_avg_contrib);
@@ -947,13 +945,12 @@ void proc_sched_show_task(struct task_struct *p, struct pid_namespace *ns,
                   "nr_involuntary_switches", (long long)p->nivcsw);
 
        P(se.load.weight);
-       P(se.runnable_weight);
 #ifdef CONFIG_SMP
        P(se.avg.load_sum);
-       P(se.avg.runnable_load_sum);
+       P(se.avg.runnable_sum);
        P(se.avg.util_sum);
        P(se.avg.load_avg);
-       P(se.avg.runnable_load_avg);
+       P(se.avg.runnable_avg);
        P(se.avg.util_avg);
        P(se.avg.last_update_time);
        P(se.avg.util_est.ewma);
index 3c8a379..d7fb20a 100644 (file)
@@ -86,6 +86,19 @@ static unsigned int normalized_sysctl_sched_wakeup_granularity       = 1000000UL;
 
 const_debug unsigned int sysctl_sched_migration_cost   = 500000UL;
 
+int sched_thermal_decay_shift;
+static int __init setup_sched_thermal_decay_shift(char *str)
+{
+       int _shift = 0;
+
+       if (kstrtoint(str, 0, &_shift))
+               pr_warn("Unable to set scheduler thermal pressure decay shift parameter\n");
+
+       sched_thermal_decay_shift = clamp(_shift, 0, 10);
+       return 1;
+}
+__setup("sched_thermal_decay_shift=", setup_sched_thermal_decay_shift);
+
 #ifdef CONFIG_SMP
 /*
  * For asym packing, by default the lower numbered CPU has higher priority.
@@ -741,9 +754,7 @@ void init_entity_runnable_average(struct sched_entity *se)
         * nothing has been attached to the task group yet.
         */
        if (entity_is_task(se))
-               sa->runnable_load_avg = sa->load_avg = scale_load_down(se->load.weight);
-
-       se->runnable_weight = se->load.weight;
+               sa->load_avg = scale_load_down(se->load.weight);
 
        /* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */
 }
@@ -796,6 +807,8 @@ void post_init_entity_util_avg(struct task_struct *p)
                }
        }
 
+       sa->runnable_avg = cpu_scale;
+
        if (p->sched_class != &fair_sched_class) {
                /*
                 * For !fair tasks do:
@@ -1473,36 +1486,51 @@ bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
               group_faults_cpu(ng, src_nid) * group_faults(p, dst_nid) * 4;
 }
 
-static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq);
-
-static unsigned long cpu_runnable_load(struct rq *rq)
-{
-       return cfs_rq_runnable_load_avg(&rq->cfs);
-}
+/*
+ * 'numa_type' describes the node at the moment of load balancing.
+ */
+enum numa_type {
+       /* The node has spare capacity that can be used to run more tasks.  */
+       node_has_spare = 0,
+       /*
+        * The node is fully used and the tasks don't compete for more CPU
+        * cycles. Nevertheless, some tasks might wait before running.
+        */
+       node_fully_busy,
+       /*
+        * The node is overloaded and can't provide expected CPU cycles to all
+        * tasks.
+        */
+       node_overloaded
+};
 
 /* Cached statistics for all CPUs within a node */
 struct numa_stats {
        unsigned long load;
-
+       unsigned long util;
        /* Total compute capacity of CPUs on a node */
        unsigned long compute_capacity;
+       unsigned int nr_running;
+       unsigned int weight;
+       enum numa_type node_type;
+       int idle_cpu;
 };
 
-/*
- * XXX borrowed from update_sg_lb_stats
- */
-static void update_numa_stats(struct numa_stats *ns, int nid)
+static inline bool is_core_idle(int cpu)
 {
-       int cpu;
+#ifdef CONFIG_SCHED_SMT
+       int sibling;
 
-       memset(ns, 0, sizeof(*ns));
-       for_each_cpu(cpu, cpumask_of_node(nid)) {
-               struct rq *rq = cpu_rq(cpu);
+       for_each_cpu(sibling, cpu_smt_mask(cpu)) {
+               if (cpu == sibling)
+                       continue;
 
-               ns->load += cpu_runnable_load(rq);
-               ns->compute_capacity += capacity_of(cpu);
+               if (!idle_cpu(cpu))
+                       return false;
        }
+#endif
 
+       return true;
 }
 
 struct task_numa_env {
@@ -1521,20 +1549,128 @@ struct task_numa_env {
        int best_cpu;
 };
 
+static unsigned long cpu_load(struct rq *rq);
+static unsigned long cpu_util(int cpu);
+static inline long adjust_numa_imbalance(int imbalance, int src_nr_running);
+
+static inline enum
+numa_type numa_classify(unsigned int imbalance_pct,
+                        struct numa_stats *ns)
+{
+       if ((ns->nr_running > ns->weight) &&
+           ((ns->compute_capacity * 100) < (ns->util * imbalance_pct)))
+               return node_overloaded;
+
+       if ((ns->nr_running < ns->weight) ||
+           ((ns->compute_capacity * 100) > (ns->util * imbalance_pct)))
+               return node_has_spare;
+
+       return node_fully_busy;
+}
+
+#ifdef CONFIG_SCHED_SMT
+/* Forward declarations of select_idle_sibling helpers */
+static inline bool test_idle_cores(int cpu, bool def);
+static inline int numa_idle_core(int idle_core, int cpu)
+{
+       if (!static_branch_likely(&sched_smt_present) ||
+           idle_core >= 0 || !test_idle_cores(cpu, false))
+               return idle_core;
+
+       /*
+        * Prefer cores instead of packing HT siblings
+        * and triggering future load balancing.
+        */
+       if (is_core_idle(cpu))
+               idle_core = cpu;
+
+       return idle_core;
+}
+#else
+static inline int numa_idle_core(int idle_core, int cpu)
+{
+       return idle_core;
+}
+#endif
+
+/*
+ * Gather all necessary information to make NUMA balancing placement
+ * decisions that are compatible with standard load balancer. This
+ * borrows code and logic from update_sg_lb_stats but sharing a
+ * common implementation is impractical.
+ */
+static void update_numa_stats(struct task_numa_env *env,
+                             struct numa_stats *ns, int nid,
+                             bool find_idle)
+{
+       int cpu, idle_core = -1;
+
+       memset(ns, 0, sizeof(*ns));
+       ns->idle_cpu = -1;
+
+       rcu_read_lock();
+       for_each_cpu(cpu, cpumask_of_node(nid)) {
+               struct rq *rq = cpu_rq(cpu);
+
+               ns->load += cpu_load(rq);
+               ns->util += cpu_util(cpu);
+               ns->nr_running += rq->cfs.h_nr_running;
+               ns->compute_capacity += capacity_of(cpu);
+
+               if (find_idle && !rq->nr_running && idle_cpu(cpu)) {
+                       if (READ_ONCE(rq->numa_migrate_on) ||
+                           !cpumask_test_cpu(cpu, env->p->cpus_ptr))
+                               continue;
+
+                       if (ns->idle_cpu == -1)
+                               ns->idle_cpu = cpu;
+
+                       idle_core = numa_idle_core(idle_core, cpu);
+               }
+       }
+       rcu_read_unlock();
+
+       ns->weight = cpumask_weight(cpumask_of_node(nid));
+
+       ns->node_type = numa_classify(env->imbalance_pct, ns);
+
+       if (idle_core >= 0)
+               ns->idle_cpu = idle_core;
+}
+
 static void task_numa_assign(struct task_numa_env *env,
                             struct task_struct *p, long imp)
 {
        struct rq *rq = cpu_rq(env->dst_cpu);
 
-       /* Bail out if run-queue part of active NUMA balance. */
-       if (xchg(&rq->numa_migrate_on, 1))
+       /* Check if run-queue part of active NUMA balance. */
+       if (env->best_cpu != env->dst_cpu && xchg(&rq->numa_migrate_on, 1)) {
+               int cpu;
+               int start = env->dst_cpu;
+
+               /* Find alternative idle CPU. */
+               for_each_cpu_wrap(cpu, cpumask_of_node(env->dst_nid), start) {
+                       if (cpu == env->best_cpu || !idle_cpu(cpu) ||
+                           !cpumask_test_cpu(cpu, env->p->cpus_ptr)) {
+                               continue;
+                       }
+
+                       env->dst_cpu = cpu;
+                       rq = cpu_rq(env->dst_cpu);
+                       if (!xchg(&rq->numa_migrate_on, 1))
+                               goto assign;
+               }
+
+               /* Failed to find an alternative idle CPU */
                return;
+       }
 
+assign:
        /*
         * Clear previous best_cpu/rq numa-migrate flag, since task now
         * found a better CPU to move/swap.
         */
-       if (env->best_cpu != -1) {
+       if (env->best_cpu != -1 && env->best_cpu != env->dst_cpu) {
                rq = cpu_rq(env->best_cpu);
                WRITE_ONCE(rq->numa_migrate_on, 0);
        }
@@ -1590,7 +1726,7 @@ static bool load_too_imbalanced(long src_load, long dst_load,
  * into account that it might be best if task running on the dst_cpu should
  * be exchanged with the source task
  */
-static void task_numa_compare(struct task_numa_env *env,
+static bool task_numa_compare(struct task_numa_env *env,
                              long taskimp, long groupimp, bool maymove)
 {
        struct numa_group *cur_ng, *p_ng = deref_curr_numa_group(env->p);
@@ -1601,9 +1737,10 @@ static void task_numa_compare(struct task_numa_env *env,
        int dist = env->dist;
        long moveimp = imp;
        long load;
+       bool stopsearch = false;
 
        if (READ_ONCE(dst_rq->numa_migrate_on))
-               return;
+               return false;
 
        rcu_read_lock();
        cur = rcu_dereference(dst_rq->curr);
@@ -1614,8 +1751,10 @@ static void task_numa_compare(struct task_numa_env *env,
         * Because we have preemption enabled we can get migrated around and
         * end try selecting ourselves (current == env->p) as a swap candidate.
         */
-       if (cur == env->p)
+       if (cur == env->p) {
+               stopsearch = true;
                goto unlock;
+       }
 
        if (!cur) {
                if (maymove && moveimp >= env->best_imp)
@@ -1624,18 +1763,27 @@ static void task_numa_compare(struct task_numa_env *env,
                        goto unlock;
        }
 
+       /* Skip this swap candidate if cannot move to the source cpu. */
+       if (!cpumask_test_cpu(env->src_cpu, cur->cpus_ptr))
+               goto unlock;
+
+       /*
+        * Skip this swap candidate if it is not moving to its preferred
+        * node and the best task is.
+        */
+       if (env->best_task &&
+           env->best_task->numa_preferred_nid == env->src_nid &&
+           cur->numa_preferred_nid != env->src_nid) {
+               goto unlock;
+       }
+
        /*
         * "imp" is the fault differential for the source task between the
         * source and destination node. Calculate the total differential for
         * the source task and potential destination task. The more negative
         * the value is, the more remote accesses that would be expected to
         * be incurred if the tasks were swapped.
-        */
-       /* Skip this swap candidate if cannot move to the source cpu */
-       if (!cpumask_test_cpu(env->src_cpu, cur->cpus_ptr))
-               goto unlock;
-
-       /*
+        *
         * If dst and source tasks are in the same NUMA group, or not
         * in any group then look only at task weights.
         */
@@ -1662,6 +1810,19 @@ static void task_numa_compare(struct task_numa_env *env,
                               task_weight(cur, env->dst_nid, dist);
        }
 
+       /* Discourage picking a task already on its preferred node */
+       if (cur->numa_preferred_nid == env->dst_nid)
+               imp -= imp / 16;
+
+       /*
+        * Encourage picking a task that moves to its preferred node.
+        * This potentially makes imp larger than it's maximum of
+        * 1998 (see SMALLIMP and task_weight for why) but in this
+        * case, it does not matter.
+        */
+       if (cur->numa_preferred_nid == env->src_nid)
+               imp += imp / 8;
+
        if (maymove && moveimp > imp && moveimp > env->best_imp) {
                imp = moveimp;
                cur = NULL;
@@ -1669,6 +1830,15 @@ static void task_numa_compare(struct task_numa_env *env,
        }
 
        /*
+        * Prefer swapping with a task moving to its preferred node over a
+        * task that is not.
+        */
+       if (env->best_task && cur->numa_preferred_nid == env->src_nid &&
+           env->best_task->numa_preferred_nid != env->src_nid) {
+               goto assign;
+       }
+
+       /*
         * If the NUMA importance is less than SMALLIMP,
         * task migration might only result in ping pong
         * of tasks and also hurt performance due to cache
@@ -1691,42 +1861,95 @@ static void task_numa_compare(struct task_numa_env *env,
                goto unlock;
 
 assign:
-       /*
-        * One idle CPU per node is evaluated for a task numa move.
-        * Call select_idle_sibling to maybe find a better one.
-        */
+       /* Evaluate an idle CPU for a task numa move. */
        if (!cur) {
+               int cpu = env->dst_stats.idle_cpu;
+
+               /* Nothing cached so current CPU went idle since the search. */
+               if (cpu < 0)
+                       cpu = env->dst_cpu;
+
                /*
-                * select_idle_siblings() uses an per-CPU cpumask that
-                * can be used from IRQ context.
+                * If the CPU is no longer truly idle and the previous best CPU
+                * is, keep using it.
                 */
-               local_irq_disable();
-               env->dst_cpu = select_idle_sibling(env->p, env->src_cpu,
-                                                  env->dst_cpu);
-               local_irq_enable();
+               if (!idle_cpu(cpu) && env->best_cpu >= 0 &&
+                   idle_cpu(env->best_cpu)) {
+                       cpu = env->best_cpu;
+               }
+
+               env->dst_cpu = cpu;
        }
 
        task_numa_assign(env, cur, imp);
+
+       /*
+        * If a move to idle is allowed because there is capacity or load
+        * balance improves then stop the search. While a better swap
+        * candidate may exist, a search is not free.
+        */
+       if (maymove && !cur && env->best_cpu >= 0 && idle_cpu(env->best_cpu))
+               stopsearch = true;
+
+       /*
+        * If a swap candidate must be identified and the current best task
+        * moves its preferred node then stop the search.
+        */
+       if (!maymove && env->best_task &&
+           env->best_task->numa_preferred_nid == env->src_nid) {
+               stopsearch = true;
+       }
 unlock:
        rcu_read_unlock();
+
+       return stopsearch;
 }
 
 static void task_numa_find_cpu(struct task_numa_env *env,
                                long taskimp, long groupimp)
 {
-       long src_load, dst_load, load;
        bool maymove = false;
        int cpu;
 
-       load = task_h_load(env->p);
-       dst_load = env->dst_stats.load + load;
-       src_load = env->src_stats.load - load;
-
        /*
-        * If the improvement from just moving env->p direction is better
-        * than swapping tasks around, check if a move is possible.
+        * If dst node has spare capacity, then check if there is an
+        * imbalance that would be overruled by the load balancer.
         */
-       maymove = !load_too_imbalanced(src_load, dst_load, env);
+       if (env->dst_stats.node_type == node_has_spare) {
+               unsigned int imbalance;
+               int src_running, dst_running;
+
+               /*
+                * Would movement cause an imbalance? Note that if src has
+                * more running tasks that the imbalance is ignored as the
+                * move improves the imbalance from the perspective of the
+                * CPU load balancer.
+                * */
+               src_running = env->src_stats.nr_running - 1;
+               dst_running = env->dst_stats.nr_running + 1;
+               imbalance = max(0, dst_running - src_running);
+               imbalance = adjust_numa_imbalance(imbalance, src_running);
+
+               /* Use idle CPU if there is no imbalance */
+               if (!imbalance) {
+                       maymove = true;
+                       if (env->dst_stats.idle_cpu >= 0) {
+                               env->dst_cpu = env->dst_stats.idle_cpu;
+                               task_numa_assign(env, NULL, 0);
+                               return;
+                       }
+               }
+       } else {
+               long src_load, dst_load, load;
+               /*
+                * If the improvement from just moving env->p direction is better
+                * than swapping tasks around, check if a move is possible.
+                */
+               load = task_h_load(env->p);
+               dst_load = env->dst_stats.load + load;
+               src_load = env->src_stats.load - load;
+               maymove = !load_too_imbalanced(src_load, dst_load, env);
+       }
 
        for_each_cpu(cpu, cpumask_of_node(env->dst_nid)) {
                /* Skip this CPU if the source task cannot migrate */
@@ -1734,7 +1957,8 @@ static void task_numa_find_cpu(struct task_numa_env *env,
                        continue;
 
                env->dst_cpu = cpu;
-               task_numa_compare(env, taskimp, groupimp, maymove);
+               if (task_numa_compare(env, taskimp, groupimp, maymove))
+                       break;
        }
 }
 
@@ -1788,10 +2012,10 @@ static int task_numa_migrate(struct task_struct *p)
        dist = env.dist = node_distance(env.src_nid, env.dst_nid);
        taskweight = task_weight(p, env.src_nid, dist);
        groupweight = group_weight(p, env.src_nid, dist);
-       update_numa_stats(&env.src_stats, env.src_nid);
+       update_numa_stats(&env, &env.src_stats, env.src_nid, false);
        taskimp = task_weight(p, env.dst_nid, dist) - taskweight;
        groupimp = group_weight(p, env.dst_nid, dist) - groupweight;
-       update_numa_stats(&env.dst_stats, env.dst_nid);
+       update_numa_stats(&env, &env.dst_stats, env.dst_nid, true);
 
        /* Try to find a spot on the preferred nid. */
        task_numa_find_cpu(&env, taskimp, groupimp);
@@ -1824,7 +2048,7 @@ static int task_numa_migrate(struct task_struct *p)
 
                        env.dist = dist;
                        env.dst_nid = nid;
-                       update_numa_stats(&env.dst_stats, env.dst_nid);
+                       update_numa_stats(&env, &env.dst_stats, env.dst_nid, true);
                        task_numa_find_cpu(&env, taskimp, groupimp);
                }
        }
@@ -1848,15 +2072,17 @@ static int task_numa_migrate(struct task_struct *p)
        }
 
        /* No better CPU than the current one was found. */
-       if (env.best_cpu == -1)
+       if (env.best_cpu == -1) {
+               trace_sched_stick_numa(p, env.src_cpu, NULL, -1);
                return -EAGAIN;
+       }
 
        best_rq = cpu_rq(env.best_cpu);
        if (env.best_task == NULL) {
                ret = migrate_task_to(p, env.best_cpu);
                WRITE_ONCE(best_rq->numa_migrate_on, 0);
                if (ret != 0)
-                       trace_sched_stick_numa(p, env.src_cpu, env.best_cpu);
+                       trace_sched_stick_numa(p, env.src_cpu, NULL, env.best_cpu);
                return ret;
        }
 
@@ -1864,7 +2090,7 @@ static int task_numa_migrate(struct task_struct *p)
        WRITE_ONCE(best_rq->numa_migrate_on, 0);
 
        if (ret != 0)
-               trace_sched_stick_numa(p, env.src_cpu, task_cpu(env.best_task));
+               trace_sched_stick_numa(p, env.src_cpu, env.best_task, env.best_cpu);
        put_task_struct(env.best_task);
        return ret;
 }
@@ -2835,25 +3061,6 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 
 #ifdef CONFIG_SMP
 static inline void
-enqueue_runnable_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-       cfs_rq->runnable_weight += se->runnable_weight;
-
-       cfs_rq->avg.runnable_load_avg += se->avg.runnable_load_avg;
-       cfs_rq->avg.runnable_load_sum += se_runnable(se) * se->avg.runnable_load_sum;
-}
-
-static inline void
-dequeue_runnable_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-       cfs_rq->runnable_weight -= se->runnable_weight;
-
-       sub_positive(&cfs_rq->avg.runnable_load_avg, se->avg.runnable_load_avg);
-       sub_positive(&cfs_rq->avg.runnable_load_sum,
-                    se_runnable(se) * se->avg.runnable_load_sum);
-}
-
-static inline void
 enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
        cfs_rq->avg.load_avg += se->avg.load_avg;
@@ -2868,28 +3075,22 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 }
 #else
 static inline void
-enqueue_runnable_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
-static inline void
-dequeue_runnable_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
-static inline void
 enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
 static inline void
 dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
 #endif
 
 static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
-                           unsigned long weight, unsigned long runnable)
+                           unsigned long weight)
 {
        if (se->on_rq) {
                /* commit outstanding execution time */
                if (cfs_rq->curr == se)
                        update_curr(cfs_rq);
                account_entity_dequeue(cfs_rq, se);
-               dequeue_runnable_load_avg(cfs_rq, se);
        }
        dequeue_load_avg(cfs_rq, se);
 
-       se->runnable_weight = runnable;
        update_load_set(&se->load, weight);
 
 #ifdef CONFIG_SMP
@@ -2897,16 +3098,13 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
                u32 divider = LOAD_AVG_MAX - 1024 + se->avg.period_contrib;
 
                se->avg.load_avg = div_u64(se_weight(se) * se->avg.load_sum, divider);
-               se->avg.runnable_load_avg =
-                       div_u64(se_runnable(se) * se->avg.runnable_load_sum, divider);
        } while (0);
 #endif
 
        enqueue_load_avg(cfs_rq, se);
-       if (se->on_rq) {
+       if (se->on_rq)
                account_entity_enqueue(cfs_rq, se);
-               enqueue_runnable_load_avg(cfs_rq, se);
-       }
+
 }
 
 void reweight_task(struct task_struct *p, int prio)
@@ -2916,7 +3114,7 @@ void reweight_task(struct task_struct *p, int prio)
        struct load_weight *load = &se->load;
        unsigned long weight = scale_load(sched_prio_to_weight[prio]);
 
-       reweight_entity(cfs_rq, se, weight, weight);
+       reweight_entity(cfs_rq, se, weight);
        load->inv_weight = sched_prio_to_wmult[prio];
 }
 
@@ -3028,50 +3226,6 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
         */
        return clamp_t(long, shares, MIN_SHARES, tg_shares);
 }
-
-/*
- * This calculates the effective runnable weight for a group entity based on
- * the group entity weight calculated above.
- *
- * Because of the above approximation (2), our group entity weight is
- * an load_avg based ratio (3). This means that it includes blocked load and
- * does not represent the runnable weight.
- *
- * Approximate the group entity's runnable weight per ratio from the group
- * runqueue:
- *
- *                                          grq->avg.runnable_load_avg
- *   ge->runnable_weight = ge->load.weight * -------------------------- (7)
- *                                              grq->avg.load_avg
- *
- * However, analogous to above, since the avg numbers are slow, this leads to
- * transients in the from-idle case. Instead we use:
- *
- *   ge->runnable_weight = ge->load.weight *
- *
- *             max(grq->avg.runnable_load_avg, grq->runnable_weight)
- *             -----------------------------------------------------   (8)
- *                   max(grq->avg.load_avg, grq->load.weight)
- *
- * Where these max() serve both to use the 'instant' values to fix the slow
- * from-idle and avoid the /0 on to-idle, similar to (6).
- */
-static long calc_group_runnable(struct cfs_rq *cfs_rq, long shares)
-{
-       long runnable, load_avg;
-
-       load_avg = max(cfs_rq->avg.load_avg,
-                      scale_load_down(cfs_rq->load.weight));
-
-       runnable = max(cfs_rq->avg.runnable_load_avg,
-                      scale_load_down(cfs_rq->runnable_weight));
-
-       runnable *= shares;
-       if (load_avg)
-               runnable /= load_avg;
-
-       return clamp_t(long, runnable, MIN_SHARES, shares);
-}
 #endif /* CONFIG_SMP */
 
 static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
@@ -3083,7 +3237,7 @@ static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
 static void update_cfs_group(struct sched_entity *se)
 {
        struct cfs_rq *gcfs_rq = group_cfs_rq(se);
-       long shares, runnable;
+       long shares;
 
        if (!gcfs_rq)
                return;
@@ -3092,16 +3246,15 @@ static void update_cfs_group(struct sched_entity *se)
                return;
 
 #ifndef CONFIG_SMP
-       runnable = shares = READ_ONCE(gcfs_rq->tg->shares);
+       shares = READ_ONCE(gcfs_rq->tg->shares);
 
        if (likely(se->load.weight == shares))
                return;
 #else
        shares   = calc_group_shares(gcfs_rq);
-       runnable = calc_group_runnable(gcfs_rq, shares);
 #endif
 
-       reweight_entity(cfs_rq_of(se), se, shares, runnable);
+       reweight_entity(cfs_rq_of(se), se, shares);
 }
 
 #else /* CONFIG_FAIR_GROUP_SCHED */
@@ -3226,11 +3379,11 @@ void set_task_rq_fair(struct sched_entity *se,
  * _IFF_ we look at the pure running and runnable sums. Because they
  * represent the very same entity, just at different points in the hierarchy.
  *
- * Per the above update_tg_cfs_util() is trivial and simply copies the running
- * sum over (but still wrong, because the group entity and group rq do not have
- * their PELT windows aligned).
+ * Per the above update_tg_cfs_util() and update_tg_cfs_runnable() are trivial
+ * and simply copies the running/runnable sum over (but still wrong, because
+ * the group entity and group rq do not have their PELT windows aligned).
  *
- * However, update_tg_cfs_runnable() is more complex. So we have:
+ * However, update_tg_cfs_load() is more complex. So we have:
  *
  *   ge->avg.load_avg = ge->load.weight * ge->avg.runnable_avg         (2)
  *
@@ -3313,9 +3466,35 @@ update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
 static inline void
 update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
 {
+       long delta = gcfs_rq->avg.runnable_avg - se->avg.runnable_avg;
+
+       /* Nothing to update */
+       if (!delta)
+               return;
+
+       /*
+        * The relation between sum and avg is:
+        *
+        *   LOAD_AVG_MAX - 1024 + sa->period_contrib
+        *
+        * however, the PELT windows are not aligned between grq and gse.
+        */
+
+       /* Set new sched_entity's runnable */
+       se->avg.runnable_avg = gcfs_rq->avg.runnable_avg;
+       se->avg.runnable_sum = se->avg.runnable_avg * LOAD_AVG_MAX;
+
+       /* Update parent cfs_rq runnable */
+       add_positive(&cfs_rq->avg.runnable_avg, delta);
+       cfs_rq->avg.runnable_sum = cfs_rq->avg.runnable_avg * LOAD_AVG_MAX;
+}
+
+static inline void
+update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq *gcfs_rq)
+{
        long delta_avg, running_sum, runnable_sum = gcfs_rq->prop_runnable_sum;
-       unsigned long runnable_load_avg, load_avg;
-       u64 runnable_load_sum, load_sum = 0;
+       unsigned long load_avg;
+       u64 load_sum = 0;
        s64 delta_sum;
 
        if (!runnable_sum)
@@ -3363,20 +3542,6 @@ update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cf
        se->avg.load_avg = load_avg;
        add_positive(&cfs_rq->avg.load_avg, delta_avg);
        add_positive(&cfs_rq->avg.load_sum, delta_sum);
-
-       runnable_load_sum = (s64)se_runnable(se) * runnable_sum;
-       runnable_load_avg = div_s64(runnable_load_sum, LOAD_AVG_MAX);
-
-       if (se->on_rq) {
-               delta_sum = runnable_load_sum -
-                               se_weight(se) * se->avg.runnable_load_sum;
-               delta_avg = runnable_load_avg - se->avg.runnable_load_avg;
-               add_positive(&cfs_rq->avg.runnable_load_avg, delta_avg);
-               add_positive(&cfs_rq->avg.runnable_load_sum, delta_sum);
-       }
-
-       se->avg.runnable_load_sum = runnable_sum;
-       se->avg.runnable_load_avg = runnable_load_avg;
 }
 
 static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum)
@@ -3405,6 +3570,7 @@ static inline int propagate_entity_load_avg(struct sched_entity *se)
 
        update_tg_cfs_util(cfs_rq, se, gcfs_rq);
        update_tg_cfs_runnable(cfs_rq, se, gcfs_rq);
+       update_tg_cfs_load(cfs_rq, se, gcfs_rq);
 
        trace_pelt_cfs_tp(cfs_rq);
        trace_pelt_se_tp(se);
@@ -3474,7 +3640,7 @@ static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum
 static inline int
 update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
 {
-       unsigned long removed_load = 0, removed_util = 0, removed_runnable_sum = 0;
+       unsigned long removed_load = 0, removed_util = 0, removed_runnable = 0;
        struct sched_avg *sa = &cfs_rq->avg;
        int decayed = 0;
 
@@ -3485,7 +3651,7 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
                raw_spin_lock(&cfs_rq->removed.lock);
                swap(cfs_rq->removed.util_avg, removed_util);
                swap(cfs_rq->removed.load_avg, removed_load);
-               swap(cfs_rq->removed.runnable_sum, removed_runnable_sum);
+               swap(cfs_rq->removed.runnable_avg, removed_runnable);
                cfs_rq->removed.nr = 0;
                raw_spin_unlock(&cfs_rq->removed.lock);
 
@@ -3497,7 +3663,16 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
                sub_positive(&sa->util_avg, r);
                sub_positive(&sa->util_sum, r * divider);
 
-               add_tg_cfs_propagate(cfs_rq, -(long)removed_runnable_sum);
+               r = removed_runnable;
+               sub_positive(&sa->runnable_avg, r);
+               sub_positive(&sa->runnable_sum, r * divider);
+
+               /*
+                * removed_runnable is the unweighted version of removed_load so we
+                * can use it to estimate removed_load_sum.
+                */
+               add_tg_cfs_propagate(cfs_rq,
+                       -(long)(removed_runnable * divider) >> SCHED_CAPACITY_SHIFT);
 
                decayed = 1;
        }
@@ -3542,17 +3717,19 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
         */
        se->avg.util_sum = se->avg.util_avg * divider;
 
+       se->avg.runnable_sum = se->avg.runnable_avg * divider;
+
        se->avg.load_sum = divider;
        if (se_weight(se)) {
                se->avg.load_sum =
                        div_u64(se->avg.load_avg * se->avg.load_sum, se_weight(se));
        }
 
-       se->avg.runnable_load_sum = se->avg.load_sum;
-
        enqueue_load_avg(cfs_rq, se);
        cfs_rq->avg.util_avg += se->avg.util_avg;
        cfs_rq->avg.util_sum += se->avg.util_sum;
+       cfs_rq->avg.runnable_avg += se->avg.runnable_avg;
+       cfs_rq->avg.runnable_sum += se->avg.runnable_sum;
 
        add_tg_cfs_propagate(cfs_rq, se->avg.load_sum);
 
@@ -3574,6 +3751,8 @@ static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
        dequeue_load_avg(cfs_rq, se);
        sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg);
        sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum);
+       sub_positive(&cfs_rq->avg.runnable_avg, se->avg.runnable_avg);
+       sub_positive(&cfs_rq->avg.runnable_sum, se->avg.runnable_sum);
 
        add_tg_cfs_propagate(cfs_rq, -se->avg.load_sum);
 
@@ -3680,13 +3859,13 @@ static void remove_entity_load_avg(struct sched_entity *se)
        ++cfs_rq->removed.nr;
        cfs_rq->removed.util_avg        += se->avg.util_avg;
        cfs_rq->removed.load_avg        += se->avg.load_avg;
-       cfs_rq->removed.runnable_sum    += se->avg.load_sum; /* == runnable_sum */
+       cfs_rq->removed.runnable_avg    += se->avg.runnable_avg;
        raw_spin_unlock_irqrestore(&cfs_rq->removed.lock, flags);
 }
 
-static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq)
+static inline unsigned long cfs_rq_runnable_avg(struct cfs_rq *cfs_rq)
 {
-       return cfs_rq->avg.runnable_load_avg;
+       return cfs_rq->avg.runnable_avg;
 }
 
 static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq)
@@ -3957,6 +4136,7 @@ static inline void check_schedstat_required(void)
 #endif
 }
 
+static inline bool cfs_bandwidth_used(void);
 
 /*
  * MIGRATION
@@ -4021,8 +4201,8 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
         *   - Add its new weight to cfs_rq->load.weight
         */
        update_load_avg(cfs_rq, se, UPDATE_TG | DO_ATTACH);
+       se_update_runnable(se);
        update_cfs_group(se);
-       enqueue_runnable_load_avg(cfs_rq, se);
        account_entity_enqueue(cfs_rq, se);
 
        if (flags & ENQUEUE_WAKEUP)
@@ -4035,10 +4215,16 @@ enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
                __enqueue_entity(cfs_rq, se);
        se->on_rq = 1;
 
-       if (cfs_rq->nr_running == 1) {
+       /*
+        * When bandwidth control is enabled, cfs might have been removed
+        * because of a parent been throttled but cfs->nr_running > 1. Try to
+        * add it unconditionnally.
+        */
+       if (cfs_rq->nr_running == 1 || cfs_bandwidth_used())
                list_add_leaf_cfs_rq(cfs_rq);
+
+       if (cfs_rq->nr_running == 1)
                check_enqueue_throttle(cfs_rq);
-       }
 }
 
 static void __clear_buddies_last(struct sched_entity *se)
@@ -4105,7 +4291,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
         *     of its group cfs_rq.
         */
        update_load_avg(cfs_rq, se, UPDATE_TG);
-       dequeue_runnable_load_avg(cfs_rq, se);
+       se_update_runnable(se);
 
        update_stats_dequeue(cfs_rq, se, flags);
 
@@ -4541,8 +4727,13 @@ static void throttle_cfs_rq(struct cfs_rq *cfs_rq)
                if (!se->on_rq)
                        break;
 
-               if (dequeue)
+               if (dequeue) {
                        dequeue_entity(qcfs_rq, se, DEQUEUE_SLEEP);
+               } else {
+                       update_load_avg(qcfs_rq, se, 0);
+                       se_update_runnable(se);
+               }
+
                qcfs_rq->h_nr_running -= task_delta;
                qcfs_rq->idle_h_nr_running -= idle_task_delta;
 
@@ -4610,8 +4801,13 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
                        enqueue = 0;
 
                cfs_rq = cfs_rq_of(se);
-               if (enqueue)
+               if (enqueue) {
                        enqueue_entity(cfs_rq, se, ENQUEUE_WAKEUP);
+               } else {
+                       update_load_avg(cfs_rq, se, 0);
+                       se_update_runnable(se);
+               }
+
                cfs_rq->h_nr_running += task_delta;
                cfs_rq->idle_h_nr_running += idle_task_delta;
 
@@ -4619,11 +4815,22 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
                        break;
        }
 
-       assert_list_leaf_cfs_rq(rq);
-
        if (!se)
                add_nr_running(rq, task_delta);
 
+       /*
+        * The cfs_rq_throttled() breaks in the above iteration can result in
+        * incomplete leaf list maintenance, resulting in triggering the
+        * assertion below.
+        */
+       for_each_sched_entity(se) {
+               cfs_rq = cfs_rq_of(se);
+
+               list_add_leaf_cfs_rq(cfs_rq);
+       }
+
+       assert_list_leaf_cfs_rq(rq);
+
        /* Determine whether we need to wake up potentially idle CPU: */
        if (rq->curr == rq->idle && rq->cfs.nr_running)
                resched_curr(rq);
@@ -5258,32 +5465,32 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                cfs_rq = cfs_rq_of(se);
                enqueue_entity(cfs_rq, se, flags);
 
-               /*
-                * end evaluation on encountering a throttled cfs_rq
-                *
-                * note: in the case of encountering a throttled cfs_rq we will
-                * post the final h_nr_running increment below.
-                */
-               if (cfs_rq_throttled(cfs_rq))
-                       break;
                cfs_rq->h_nr_running++;
                cfs_rq->idle_h_nr_running += idle_h_nr_running;
 
+               /* end evaluation on encountering a throttled cfs_rq */
+               if (cfs_rq_throttled(cfs_rq))
+                       goto enqueue_throttle;
+
                flags = ENQUEUE_WAKEUP;
        }
 
        for_each_sched_entity(se) {
                cfs_rq = cfs_rq_of(se);
+
+               update_load_avg(cfs_rq, se, UPDATE_TG);
+               se_update_runnable(se);
+               update_cfs_group(se);
+
                cfs_rq->h_nr_running++;
                cfs_rq->idle_h_nr_running += idle_h_nr_running;
 
+               /* end evaluation on encountering a throttled cfs_rq */
                if (cfs_rq_throttled(cfs_rq))
-                       break;
-
-               update_load_avg(cfs_rq, se, UPDATE_TG);
-               update_cfs_group(se);
+                       goto enqueue_throttle;
        }
 
+enqueue_throttle:
        if (!se) {
                add_nr_running(rq, 1);
                /*
@@ -5344,17 +5551,13 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
                cfs_rq = cfs_rq_of(se);
                dequeue_entity(cfs_rq, se, flags);
 
-               /*
-                * end evaluation on encountering a throttled cfs_rq
-                *
-                * note: in the case of encountering a throttled cfs_rq we will
-                * post the final h_nr_running decrement below.
-               */
-               if (cfs_rq_throttled(cfs_rq))
-                       break;
                cfs_rq->h_nr_running--;
                cfs_rq->idle_h_nr_running -= idle_h_nr_running;
 
+               /* end evaluation on encountering a throttled cfs_rq */
+               if (cfs_rq_throttled(cfs_rq))
+                       goto dequeue_throttle;
+
                /* Don't dequeue parent if it has other entities besides us */
                if (cfs_rq->load.weight) {
                        /* Avoid re-evaluating load for this entity: */
@@ -5372,16 +5575,21 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
 
        for_each_sched_entity(se) {
                cfs_rq = cfs_rq_of(se);
+
+               update_load_avg(cfs_rq, se, UPDATE_TG);
+               se_update_runnable(se);
+               update_cfs_group(se);
+
                cfs_rq->h_nr_running--;
                cfs_rq->idle_h_nr_running -= idle_h_nr_running;
 
+               /* end evaluation on encountering a throttled cfs_rq */
                if (cfs_rq_throttled(cfs_rq))
-                       break;
+                       goto dequeue_throttle;
 
-               update_load_avg(cfs_rq, se, UPDATE_TG);
-               update_cfs_group(se);
        }
 
+dequeue_throttle:
        if (!se)
                sub_nr_running(rq, 1);
 
@@ -5447,6 +5655,29 @@ static unsigned long cpu_load_without(struct rq *rq, struct task_struct *p)
        return load;
 }
 
+static unsigned long cpu_runnable(struct rq *rq)
+{
+       return cfs_rq_runnable_avg(&rq->cfs);
+}
+
+static unsigned long cpu_runnable_without(struct rq *rq, struct task_struct *p)
+{
+       struct cfs_rq *cfs_rq;
+       unsigned int runnable;
+
+       /* Task has no contribution or is new */
+       if (cpu_of(rq) != task_cpu(p) || !READ_ONCE(p->se.avg.last_update_time))
+               return cpu_runnable(rq);
+
+       cfs_rq = &rq->cfs;
+       runnable = READ_ONCE(cfs_rq->avg.runnable_avg);
+
+       /* Discount task's runnable from CPU's runnable */
+       lsub_positive(&runnable, p->se.avg.runnable_avg);
+
+       return runnable;
+}
+
 static unsigned long capacity_of(int cpu)
 {
        return cpu_rq(cpu)->cpu_capacity;
@@ -5786,10 +6017,12 @@ static int select_idle_core(struct task_struct *p, struct sched_domain *sd, int
                bool idle = true;
 
                for_each_cpu(cpu, cpu_smt_mask(core)) {
-                       __cpumask_clear_cpu(cpu, cpus);
-                       if (!available_idle_cpu(cpu))
+                       if (!available_idle_cpu(cpu)) {
                                idle = false;
+                               break;
+                       }
                }
+               cpumask_andnot(cpus, cpus, cpu_smt_mask(core));
 
                if (idle)
                        return core;
@@ -5894,6 +6127,40 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int t
 }
 
 /*
+ * Scan the asym_capacity domain for idle CPUs; pick the first idle one on which
+ * the task fits. If no CPU is big enough, but there are idle ones, try to
+ * maximize capacity.
+ */
+static int
+select_idle_capacity(struct task_struct *p, struct sched_domain *sd, int target)
+{
+       unsigned long best_cap = 0;
+       int cpu, best_cpu = -1;
+       struct cpumask *cpus;
+
+       sync_entity_load_avg(&p->se);
+
+       cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
+       cpumask_and(cpus, sched_domain_span(sd), p->cpus_ptr);
+
+       for_each_cpu_wrap(cpu, cpus, target) {
+               unsigned long cpu_cap = capacity_of(cpu);
+
+               if (!available_idle_cpu(cpu) && !sched_idle_cpu(cpu))
+                       continue;
+               if (task_fits_capacity(p, cpu_cap))
+                       return cpu;
+
+               if (cpu_cap > best_cap) {
+                       best_cap = cpu_cap;
+                       best_cpu = cpu;
+               }
+       }
+
+       return best_cpu;
+}
+
+/*
  * Try and locate an idle core/thread in the LLC cache domain.
  */
 static int select_idle_sibling(struct task_struct *p, int prev, int target)
@@ -5901,6 +6168,28 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)
        struct sched_domain *sd;
        int i, recent_used_cpu;
 
+       /*
+        * For asymmetric CPU capacity systems, our domain of interest is
+        * sd_asym_cpucapacity rather than sd_llc.
+        */
+       if (static_branch_unlikely(&sched_asym_cpucapacity)) {
+               sd = rcu_dereference(per_cpu(sd_asym_cpucapacity, target));
+               /*
+                * On an asymmetric CPU capacity system where an exclusive
+                * cpuset defines a symmetric island (i.e. one unique
+                * capacity_orig value through the cpuset), the key will be set
+                * but the CPUs within that cpuset will not have a domain with
+                * SD_ASYM_CPUCAPACITY. These should follow the usual symmetric
+                * capacity path.
+                */
+               if (!sd)
+                       goto symmetric;
+
+               i = select_idle_capacity(p, sd, target);
+               return ((unsigned)i < nr_cpumask_bits) ? i : target;
+       }
+
+symmetric:
        if (available_idle_cpu(target) || sched_idle_cpu(target))
                return target;
 
@@ -6101,33 +6390,6 @@ static unsigned long cpu_util_without(int cpu, struct task_struct *p)
 }
 
 /*
- * Disable WAKE_AFFINE in the case where task @p doesn't fit in the
- * capacity of either the waking CPU @cpu or the previous CPU @prev_cpu.
- *
- * In that case WAKE_AFFINE doesn't make sense and we'll let
- * BALANCE_WAKE sort things out.
- */
-static int wake_cap(struct task_struct *p, int cpu, int prev_cpu)
-{
-       long min_cap, max_cap;
-
-       if (!static_branch_unlikely(&sched_asym_cpucapacity))
-               return 0;
-
-       min_cap = min(capacity_orig_of(prev_cpu), capacity_orig_of(cpu));
-       max_cap = cpu_rq(cpu)->rd->max_cpu_capacity;
-
-       /* Minimum capacity is close to max, no need to abort wake_affine */
-       if (max_cap - min_cap < max_cap >> 3)
-               return 0;
-
-       /* Bring task utilization in sync with prev_cpu */
-       sync_entity_load_avg(&p->se);
-
-       return !task_fits_capacity(p, min_cap);
-}
-
-/*
  * Predicts what cpu_util(@cpu) would return if @p was migrated (and enqueued)
  * to @dst_cpu.
  */
@@ -6391,8 +6653,7 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
                        new_cpu = prev_cpu;
                }
 
-               want_affine = !wake_wide(p) && !wake_cap(p, cpu, prev_cpu) &&
-                             cpumask_test_cpu(cpu, p->cpus_ptr);
+               want_affine = !wake_wide(p) && cpumask_test_cpu(cpu, p->cpus_ptr);
        }
 
        rcu_read_lock();
@@ -7506,6 +7767,9 @@ static inline bool others_have_blocked(struct rq *rq)
        if (READ_ONCE(rq->avg_dl.util_avg))
                return true;
 
+       if (thermal_load_avg(rq))
+               return true;
+
 #ifdef CONFIG_HAVE_SCHED_AVG_IRQ
        if (READ_ONCE(rq->avg_irq.util_avg))
                return true;
@@ -7531,6 +7795,7 @@ static bool __update_blocked_others(struct rq *rq, bool *done)
 {
        const struct sched_class *curr_class;
        u64 now = rq_clock_pelt(rq);
+       unsigned long thermal_pressure;
        bool decayed;
 
        /*
@@ -7539,8 +7804,11 @@ static bool __update_blocked_others(struct rq *rq, bool *done)
         */
        curr_class = rq->curr->sched_class;
 
+       thermal_pressure = arch_scale_thermal_pressure(cpu_of(rq));
+
        decayed = update_rt_rq_load_avg(now, rq, curr_class == &rt_sched_class) |
                  update_dl_rq_load_avg(now, rq, curr_class == &dl_sched_class) |
+                 update_thermal_load_avg(rq_clock_thermal(rq), rq, thermal_pressure) |
                  update_irq_load_avg(rq, 0);
 
        if (others_have_blocked(rq))
@@ -7562,7 +7830,7 @@ static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
        if (cfs_rq->avg.util_sum)
                return false;
 
-       if (cfs_rq->avg.runnable_load_sum)
+       if (cfs_rq->avg.runnable_sum)
                return false;
 
        return true;
@@ -7700,7 +7968,8 @@ struct sg_lb_stats {
        unsigned long avg_load; /*Avg load across the CPUs of the group */
        unsigned long group_load; /* Total load over the CPUs of the group */
        unsigned long group_capacity;
-       unsigned long group_util; /* Total utilization of the group */
+       unsigned long group_util; /* Total utilization over the CPUs of the group */
+       unsigned long group_runnable; /* Total runnable time over the CPUs of the group */
        unsigned int sum_nr_running; /* Nr of tasks running in the group */
        unsigned int sum_h_nr_running; /* Nr of CFS tasks running in the group */
        unsigned int idle_cpus;
@@ -7763,8 +8032,15 @@ static unsigned long scale_rt_capacity(struct sched_domain *sd, int cpu)
        if (unlikely(irq >= max))
                return 1;
 
+       /*
+        * avg_rt.util_avg and avg_dl.util_avg track binary signals
+        * (running and not running) with weights 0 and 1024 respectively.
+        * avg_thermal.load_avg tracks thermal pressure and the weighted
+        * average uses the actual delta max capacity(load).
+        */
        used = READ_ONCE(rq->avg_rt.util_avg);
        used += READ_ONCE(rq->avg_dl.util_avg);
+       used += thermal_load_avg(rq);
 
        if (unlikely(used >= max))
                return 1;
@@ -7921,6 +8197,10 @@ group_has_capacity(unsigned int imbalance_pct, struct sg_lb_stats *sgs)
        if (sgs->sum_nr_running < sgs->group_weight)
                return true;
 
+       if ((sgs->group_capacity * imbalance_pct) <
+                       (sgs->group_runnable * 100))
+               return false;
+
        if ((sgs->group_capacity * 100) >
                        (sgs->group_util * imbalance_pct))
                return true;
@@ -7946,6 +8226,10 @@ group_is_overloaded(unsigned int imbalance_pct, struct sg_lb_stats *sgs)
                        (sgs->group_util * imbalance_pct))
                return true;
 
+       if ((sgs->group_capacity * imbalance_pct) <
+                       (sgs->group_runnable * 100))
+               return true;
+
        return false;
 }
 
@@ -8040,6 +8324,7 @@ static inline void update_sg_lb_stats(struct lb_env *env,
 
                sgs->group_load += cpu_load(rq);
                sgs->group_util += cpu_util(i);
+               sgs->group_runnable += cpu_runnable(rq);
                sgs->sum_h_nr_running += rq->cfs.h_nr_running;
 
                nr_running = rq->nr_running;
@@ -8315,6 +8600,7 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd,
 
                sgs->group_load += cpu_load_without(rq, p);
                sgs->group_util += cpu_util_without(i, p);
+               sgs->group_runnable += cpu_runnable_without(rq, p);
                local = task_running_on_cpu(i, p);
                sgs->sum_h_nr_running += rq->cfs.h_nr_running - local;
 
@@ -8337,13 +8623,16 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd,
 
        sgs->group_capacity = group->sgc->capacity;
 
+       sgs->group_weight = group->group_weight;
+
        sgs->group_type = group_classify(sd->imbalance_pct, group, sgs);
 
        /*
         * Computing avg_load makes sense only when group is fully busy or
         * overloaded
         */
-       if (sgs->group_type < group_fully_busy)
+       if (sgs->group_type == group_fully_busy ||
+               sgs->group_type == group_overloaded)
                sgs->avg_load = (sgs->group_load * SCHED_CAPACITY_SCALE) /
                                sgs->group_capacity;
 }
@@ -8626,6 +8915,21 @@ next_group:
        }
 }
 
+static inline long adjust_numa_imbalance(int imbalance, int src_nr_running)
+{
+       unsigned int imbalance_min;
+
+       /*
+        * Allow a small imbalance based on a simple pair of communicating
+        * tasks that remain local when the source domain is almost idle.
+        */
+       imbalance_min = 2;
+       if (src_nr_running <= imbalance_min)
+               return 0;
+
+       return imbalance;
+}
+
 /**
  * calculate_imbalance - Calculate the amount of imbalance present within the
  *                      groups of a given sched_domain during load balance.
@@ -8722,24 +9026,9 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
                }
 
                /* Consider allowing a small imbalance between NUMA groups */
-               if (env->sd->flags & SD_NUMA) {
-                       unsigned int imbalance_min;
-
-                       /*
-                        * Compute an allowed imbalance based on a simple
-                        * pair of communicating tasks that should remain
-                        * local and ignore them.
-                        *
-                        * NOTE: Generally this would have been based on
-                        * the domain size and this was evaluated. However,
-                        * the benefit is similar across a range of workloads
-                        * and machines but scaling by the domain size adds
-                        * the risk that lower domains have to be rebalanced.
-                        */
-                       imbalance_min = 2;
-                       if (busiest->sum_nr_running <= imbalance_min)
-                               env->imbalance = 0;
-               }
+               if (env->sd->flags & SD_NUMA)
+                       env->imbalance = adjust_numa_imbalance(env->imbalance,
+                                               busiest->sum_nr_running);
 
                return;
        }
@@ -9025,6 +9314,14 @@ static struct rq *find_busiest_queue(struct lb_env *env,
                case migrate_util:
                        util = cpu_util(cpu_of(rq));
 
+                       /*
+                        * Don't try to pull utilization from a CPU with one
+                        * running task. Whatever its utilization, we will fail
+                        * detach the task.
+                        */
+                       if (nr_running <= 1)
+                               continue;
+
                        if (busiest_util < util) {
                                busiest_util = util;
                                busiest = rq;
index bd006b7..b647d04 100644 (file)
@@ -121,8 +121,8 @@ accumulate_sum(u64 delta, struct sched_avg *sa,
         */
        if (periods) {
                sa->load_sum = decay_load(sa->load_sum, periods);
-               sa->runnable_load_sum =
-                       decay_load(sa->runnable_load_sum, periods);
+               sa->runnable_sum =
+                       decay_load(sa->runnable_sum, periods);
                sa->util_sum = decay_load((u64)(sa->util_sum), periods);
 
                /*
@@ -149,7 +149,7 @@ accumulate_sum(u64 delta, struct sched_avg *sa,
        if (load)
                sa->load_sum += load * contrib;
        if (runnable)
-               sa->runnable_load_sum += runnable * contrib;
+               sa->runnable_sum += runnable * contrib << SCHED_CAPACITY_SHIFT;
        if (running)
                sa->util_sum += contrib << SCHED_CAPACITY_SHIFT;
 
@@ -238,7 +238,7 @@ ___update_load_sum(u64 now, struct sched_avg *sa,
 }
 
 static __always_inline void
-___update_load_avg(struct sched_avg *sa, unsigned long load, unsigned long runnable)
+___update_load_avg(struct sched_avg *sa, unsigned long load)
 {
        u32 divider = LOAD_AVG_MAX - 1024 + sa->period_contrib;
 
@@ -246,7 +246,7 @@ ___update_load_avg(struct sched_avg *sa, unsigned long load, unsigned long runna
         * Step 2: update *_avg.
         */
        sa->load_avg = div_u64(load * sa->load_sum, divider);
-       sa->runnable_load_avg = div_u64(runnable * sa->runnable_load_sum, divider);
+       sa->runnable_avg = div_u64(sa->runnable_sum, divider);
        WRITE_ONCE(sa->util_avg, sa->util_sum / divider);
 }
 
@@ -254,33 +254,32 @@ ___update_load_avg(struct sched_avg *sa, unsigned long load, unsigned long runna
  * sched_entity:
  *
  *   task:
- *     se_runnable() == se_weight()
+ *     se_weight()   = se->load.weight
+ *     se_runnable() = !!on_rq
  *
  *   group: [ see update_cfs_group() ]
  *     se_weight()   = tg->weight * grq->load_avg / tg->load_avg
- *     se_runnable() = se_weight(se) * grq->runnable_load_avg / grq->load_avg
+ *     se_runnable() = grq->h_nr_running
  *
- *   load_sum := runnable_sum
- *   load_avg = se_weight(se) * runnable_avg
+ *   runnable_sum = se_runnable() * runnable = grq->runnable_sum
+ *   runnable_avg = runnable_sum
  *
- *   runnable_load_sum := runnable_sum
- *   runnable_load_avg = se_runnable(se) * runnable_avg
- *
- * XXX collapse load_sum and runnable_load_sum
+ *   load_sum := runnable
+ *   load_avg = se_weight(se) * load_sum
  *
  * cfq_rq:
  *
+ *   runnable_sum = \Sum se->avg.runnable_sum
+ *   runnable_avg = \Sum se->avg.runnable_avg
+ *
  *   load_sum = \Sum se_weight(se) * se->avg.load_sum
  *   load_avg = \Sum se->avg.load_avg
- *
- *   runnable_load_sum = \Sum se_runnable(se) * se->avg.runnable_load_sum
- *   runnable_load_avg = \Sum se->avg.runable_load_avg
  */
 
 int __update_load_avg_blocked_se(u64 now, struct sched_entity *se)
 {
        if (___update_load_sum(now, &se->avg, 0, 0, 0)) {
-               ___update_load_avg(&se->avg, se_weight(se), se_runnable(se));
+               ___update_load_avg(&se->avg, se_weight(se));
                trace_pelt_se_tp(se);
                return 1;
        }
@@ -290,10 +289,10 @@ int __update_load_avg_blocked_se(u64 now, struct sched_entity *se)
 
 int __update_load_avg_se(u64 now, struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
-       if (___update_load_sum(now, &se->avg, !!se->on_rq, !!se->on_rq,
+       if (___update_load_sum(now, &se->avg, !!se->on_rq, se_runnable(se),
                                cfs_rq->curr == se)) {
 
-               ___update_load_avg(&se->avg, se_weight(se), se_runnable(se));
+               ___update_load_avg(&se->avg, se_weight(se));
                cfs_se_util_change(&se->avg);
                trace_pelt_se_tp(se);
                return 1;
@@ -306,10 +305,10 @@ int __update_load_avg_cfs_rq(u64 now, struct cfs_rq *cfs_rq)
 {
        if (___update_load_sum(now, &cfs_rq->avg,
                                scale_load_down(cfs_rq->load.weight),
-                               scale_load_down(cfs_rq->runnable_weight),
+                               cfs_rq->h_nr_running,
                                cfs_rq->curr != NULL)) {
 
-               ___update_load_avg(&cfs_rq->avg, 1, 1);
+               ___update_load_avg(&cfs_rq->avg, 1);
                trace_pelt_cfs_tp(cfs_rq);
                return 1;
        }
@@ -322,9 +321,9 @@ int __update_load_avg_cfs_rq(u64 now, struct cfs_rq *cfs_rq)
  *
  *   util_sum = \Sum se->avg.util_sum but se->avg.util_sum is not tracked
  *   util_sum = cpu_scale * load_sum
- *   runnable_load_sum = load_sum
+ *   runnable_sum = util_sum
  *
- *   load_avg and runnable_load_avg are not supported and meaningless.
+ *   load_avg and runnable_avg are not supported and meaningless.
  *
  */
 
@@ -335,7 +334,7 @@ int update_rt_rq_load_avg(u64 now, struct rq *rq, int running)
                                running,
                                running)) {
 
-               ___update_load_avg(&rq->avg_rt, 1, 1);
+               ___update_load_avg(&rq->avg_rt, 1);
                trace_pelt_rt_tp(rq);
                return 1;
        }
@@ -348,7 +347,9 @@ int update_rt_rq_load_avg(u64 now, struct rq *rq, int running)
  *
  *   util_sum = \Sum se->avg.util_sum but se->avg.util_sum is not tracked
  *   util_sum = cpu_scale * load_sum
- *   runnable_load_sum = load_sum
+ *   runnable_sum = util_sum
+ *
+ *   load_avg and runnable_avg are not supported and meaningless.
  *
  */
 
@@ -359,7 +360,7 @@ int update_dl_rq_load_avg(u64 now, struct rq *rq, int running)
                                running,
                                running)) {
 
-               ___update_load_avg(&rq->avg_dl, 1, 1);
+               ___update_load_avg(&rq->avg_dl, 1);
                trace_pelt_dl_tp(rq);
                return 1;
        }
@@ -367,13 +368,46 @@ int update_dl_rq_load_avg(u64 now, struct rq *rq, int running)
        return 0;
 }
 
+#ifdef CONFIG_SCHED_THERMAL_PRESSURE
+/*
+ * thermal:
+ *
+ *   load_sum = \Sum se->avg.load_sum but se->avg.load_sum is not tracked
+ *
+ *   util_avg and runnable_load_avg are not supported and meaningless.
+ *
+ * Unlike rt/dl utilization tracking that track time spent by a cpu
+ * running a rt/dl task through util_avg, the average thermal pressure is
+ * tracked through load_avg. This is because thermal pressure signal is
+ * time weighted "delta" capacity unlike util_avg which is binary.
+ * "delta capacity" =  actual capacity  -
+ *                     capped capacity a cpu due to a thermal event.
+ */
+
+int update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity)
+{
+       if (___update_load_sum(now, &rq->avg_thermal,
+                              capacity,
+                              capacity,
+                              capacity)) {
+               ___update_load_avg(&rq->avg_thermal, 1);
+               trace_pelt_thermal_tp(rq);
+               return 1;
+       }
+
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_HAVE_SCHED_AVG_IRQ
 /*
  * irq:
  *
  *   util_sum = \Sum se->avg.util_sum but se->avg.util_sum is not tracked
  *   util_sum = cpu_scale * load_sum
- *   runnable_load_sum = load_sum
+ *   runnable_sum = util_sum
+ *
+ *   load_avg and runnable_avg are not supported and meaningless.
  *
  */
 
@@ -410,7 +444,7 @@ int update_irq_load_avg(struct rq *rq, u64 running)
                                1);
 
        if (ret) {
-               ___update_load_avg(&rq->avg_irq, 1, 1);
+               ___update_load_avg(&rq->avg_irq, 1);
                trace_pelt_irq_tp(rq);
        }
 
index afff644..eb034d9 100644 (file)
@@ -7,6 +7,26 @@ int __update_load_avg_cfs_rq(u64 now, struct cfs_rq *cfs_rq);
 int update_rt_rq_load_avg(u64 now, struct rq *rq, int running);
 int update_dl_rq_load_avg(u64 now, struct rq *rq, int running);
 
+#ifdef CONFIG_SCHED_THERMAL_PRESSURE
+int update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity);
+
+static inline u64 thermal_load_avg(struct rq *rq)
+{
+       return READ_ONCE(rq->avg_thermal.load_avg);
+}
+#else
+static inline int
+update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity)
+{
+       return 0;
+}
+
+static inline u64 thermal_load_avg(struct rq *rq)
+{
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_HAVE_SCHED_AVG_IRQ
 int update_irq_load_avg(struct rq *rq, u64 running);
 #else
@@ -159,6 +179,17 @@ update_dl_rq_load_avg(u64 now, struct rq *rq, int running)
 }
 
 static inline int
+update_thermal_load_avg(u64 now, struct rq *rq, u64 capacity)
+{
+       return 0;
+}
+
+static inline u64 thermal_load_avg(struct rq *rq)
+{
+       return 0;
+}
+
+static inline int
 update_irq_load_avg(struct rq *rq, u64 running)
 {
        return 0;
index 0285207..8f45cdb 100644 (file)
@@ -225,7 +225,7 @@ static bool test_state(unsigned int *tasks, enum psi_states state)
        case PSI_MEM_FULL:
                return tasks[NR_MEMSTALL] && !tasks[NR_RUNNING];
        case PSI_CPU_SOME:
-               return tasks[NR_RUNNING] > 1;
+               return tasks[NR_RUNNING] > tasks[NR_ONCPU];
        case PSI_NONIDLE:
                return tasks[NR_IOWAIT] || tasks[NR_MEMSTALL] ||
                        tasks[NR_RUNNING];
@@ -669,13 +669,14 @@ static void record_times(struct psi_group_cpu *groupc, int cpu,
                groupc->times[PSI_NONIDLE] += delta;
 }
 
-static u32 psi_group_change(struct psi_group *group, int cpu,
-                           unsigned int clear, unsigned int set)
+static void psi_group_change(struct psi_group *group, int cpu,
+                            unsigned int clear, unsigned int set,
+                            bool wake_clock)
 {
        struct psi_group_cpu *groupc;
+       u32 state_mask = 0;
        unsigned int t, m;
        enum psi_states s;
-       u32 state_mask = 0;
 
        groupc = per_cpu_ptr(group->pcpu, cpu);
 
@@ -695,10 +696,10 @@ static u32 psi_group_change(struct psi_group *group, int cpu,
                if (!(m & (1 << t)))
                        continue;
                if (groupc->tasks[t] == 0 && !psi_bug) {
-                       printk_deferred(KERN_ERR "psi: task underflow! cpu=%d t=%d tasks=[%u %u %u] clear=%x set=%x\n",
+                       printk_deferred(KERN_ERR "psi: task underflow! cpu=%d t=%d tasks=[%u %u %u %u] clear=%x set=%x\n",
                                        cpu, t, groupc->tasks[0],
                                        groupc->tasks[1], groupc->tasks[2],
-                                       clear, set);
+                                       groupc->tasks[3], clear, set);
                        psi_bug = 1;
                }
                groupc->tasks[t]--;
@@ -717,7 +718,11 @@ static u32 psi_group_change(struct psi_group *group, int cpu,
 
        write_seqcount_end(&groupc->seq);
 
-       return state_mask;
+       if (state_mask & group->poll_states)
+               psi_schedule_poll_work(group, 1);
+
+       if (wake_clock && !delayed_work_pending(&group->avgs_work))
+               schedule_delayed_work(&group->avgs_work, PSI_FREQ);
 }
 
 static struct psi_group *iterate_groups(struct task_struct *task, void **iter)
@@ -744,27 +749,32 @@ static struct psi_group *iterate_groups(struct task_struct *task, void **iter)
        return &psi_system;
 }
 
-void psi_task_change(struct task_struct *task, int clear, int set)
+static void psi_flags_change(struct task_struct *task, int clear, int set)
 {
-       int cpu = task_cpu(task);
-       struct psi_group *group;
-       bool wake_clock = true;
-       void *iter = NULL;
-
-       if (!task->pid)
-               return;
-
        if (((task->psi_flags & set) ||
             (task->psi_flags & clear) != clear) &&
            !psi_bug) {
                printk_deferred(KERN_ERR "psi: inconsistent task state! task=%d:%s cpu=%d psi_flags=%x clear=%x set=%x\n",
-                               task->pid, task->comm, cpu,
+                               task->pid, task->comm, task_cpu(task),
                                task->psi_flags, clear, set);
                psi_bug = 1;
        }
 
        task->psi_flags &= ~clear;
        task->psi_flags |= set;
+}
+
+void psi_task_change(struct task_struct *task, int clear, int set)
+{
+       int cpu = task_cpu(task);
+       struct psi_group *group;
+       bool wake_clock = true;
+       void *iter = NULL;
+
+       if (!task->pid)
+               return;
+
+       psi_flags_change(task, clear, set);
 
        /*
         * Periodic aggregation shuts off if there is a period of no
@@ -777,14 +787,51 @@ void psi_task_change(struct task_struct *task, int clear, int set)
                     wq_worker_last_func(task) == psi_avgs_work))
                wake_clock = false;
 
-       while ((group = iterate_groups(task, &iter))) {
-               u32 state_mask = psi_group_change(group, cpu, clear, set);
+       while ((group = iterate_groups(task, &iter)))
+               psi_group_change(group, cpu, clear, set, wake_clock);
+}
+
+void psi_task_switch(struct task_struct *prev, struct task_struct *next,
+                    bool sleep)
+{
+       struct psi_group *group, *common = NULL;
+       int cpu = task_cpu(prev);
+       void *iter;
+
+       if (next->pid) {
+               psi_flags_change(next, 0, TSK_ONCPU);
+               /*
+                * When moving state between tasks, the group that
+                * contains them both does not change: we can stop
+                * updating the tree once we reach the first common
+                * ancestor. Iterate @next's ancestors until we
+                * encounter @prev's state.
+                */
+               iter = NULL;
+               while ((group = iterate_groups(next, &iter))) {
+                       if (per_cpu_ptr(group->pcpu, cpu)->tasks[NR_ONCPU]) {
+                               common = group;
+                               break;
+                       }
+
+                       psi_group_change(group, cpu, 0, TSK_ONCPU, true);
+               }
+       }
+
+       /*
+        * If this is a voluntary sleep, dequeue will have taken care
+        * of the outgoing TSK_ONCPU alongside TSK_RUNNING already. We
+        * only need to deal with it during preemption.
+        */
+       if (sleep)
+               return;
 
-               if (state_mask & group->poll_states)
-                       psi_schedule_poll_work(group, 1);
+       if (prev->pid) {
+               psi_flags_change(prev, TSK_ONCPU, 0);
 
-               if (wake_clock && !delayed_work_pending(&group->avgs_work))
-                       schedule_delayed_work(&group->avgs_work, PSI_FREQ);
+               iter = NULL;
+               while ((group = iterate_groups(prev, &iter)) && group != common)
+                       psi_group_change(group, cpu, TSK_ONCPU, 0, true);
        }
 }
 
@@ -818,17 +865,17 @@ void psi_memstall_enter(unsigned long *flags)
        if (static_branch_likely(&psi_disabled))
                return;
 
-       *flags = current->flags & PF_MEMSTALL;
+       *flags = current->in_memstall;
        if (*flags)
                return;
        /*
-        * PF_MEMSTALL setting & accounting needs to be atomic wrt
+        * in_memstall setting & accounting needs to be atomic wrt
         * changes to the task's scheduling state, otherwise we can
         * race with CPU migration.
         */
        rq = this_rq_lock_irq(&rf);
 
-       current->flags |= PF_MEMSTALL;
+       current->in_memstall = 1;
        psi_task_change(current, 0, TSK_MEMSTALL);
 
        rq_unlock_irq(rq, &rf);
@@ -851,13 +898,13 @@ void psi_memstall_leave(unsigned long *flags)
        if (*flags)
                return;
        /*
-        * PF_MEMSTALL clearing & accounting needs to be atomic wrt
+        * in_memstall clearing & accounting needs to be atomic wrt
         * changes to the task's scheduling state, otherwise we could
         * race with CPU migration.
         */
        rq = this_rq_lock_irq(&rf);
 
-       current->flags &= ~PF_MEMSTALL;
+       current->in_memstall = 0;
        psi_task_change(current, TSK_MEMSTALL, 0);
 
        rq_unlock_irq(rq, &rf);
@@ -916,12 +963,14 @@ void cgroup_move_task(struct task_struct *task, struct css_set *to)
 
        rq = task_rq_lock(task, &rf);
 
-       if (task_on_rq_queued(task))
+       if (task_on_rq_queued(task)) {
                task_flags = TSK_RUNNING;
-       else if (task->in_iowait)
+               if (task_current(rq, task))
+                       task_flags |= TSK_ONCPU;
+       } else if (task->in_iowait)
                task_flags = TSK_IOWAIT;
 
-       if (task->flags & PF_MEMSTALL)
+       if (task->in_memstall)
                task_flags |= TSK_MEMSTALL;
 
        if (task_flags)
index 4043abe..df11d88 100644 (file)
@@ -1475,6 +1475,13 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
                int target = find_lowest_rq(p);
 
                /*
+                * Bail out if we were forcing a migration to find a better
+                * fitting CPU but our search failed.
+                */
+               if (!test && target != -1 && !rt_task_fits_capacity(p, target))
+                       goto out_unlock;
+
+               /*
                 * Don't bother moving it if the destination CPU is
                 * not running a lower priority task.
                 */
@@ -1482,6 +1489,8 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
                    p->prio < cpu_rq(target)->rt.highest_prio.curr)
                        cpu = target;
        }
+
+out_unlock:
        rcu_read_unlock();
 
 out:
@@ -1495,7 +1504,7 @@ static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p)
         * let's hope p can move out.
         */
        if (rq->curr->nr_cpus_allowed == 1 ||
-           !cpupri_find(&rq->rd->cpupri, rq->curr, NULL, NULL))
+           !cpupri_find(&rq->rd->cpupri, rq->curr, NULL))
                return;
 
        /*
@@ -1503,7 +1512,7 @@ static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p)
         * see if it is pushed or pulled somewhere else.
         */
        if (p->nr_cpus_allowed != 1 &&
-           cpupri_find(&rq->rd->cpupri, p, NULL, NULL))
+           cpupri_find(&rq->rd->cpupri, p, NULL))
                return;
 
        /*
@@ -1647,8 +1656,7 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
 static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu)
 {
        if (!task_running(rq, p) &&
-           cpumask_test_cpu(cpu, p->cpus_ptr) &&
-           rt_task_fits_capacity(p, cpu))
+           cpumask_test_cpu(cpu, p->cpus_ptr))
                return 1;
 
        return 0;
@@ -1682,6 +1690,7 @@ static int find_lowest_rq(struct task_struct *task)
        struct cpumask *lowest_mask = this_cpu_cpumask_var_ptr(local_cpu_mask);
        int this_cpu = smp_processor_id();
        int cpu      = task_cpu(task);
+       int ret;
 
        /* Make sure the mask is initialized first */
        if (unlikely(!lowest_mask))
@@ -1690,8 +1699,22 @@ static int find_lowest_rq(struct task_struct *task)
        if (task->nr_cpus_allowed == 1)
                return -1; /* No other targets possible */
 
-       if (!cpupri_find(&task_rq(task)->rd->cpupri, task, lowest_mask,
-                        rt_task_fits_capacity))
+       /*
+        * If we're on asym system ensure we consider the different capacities
+        * of the CPUs when searching for the lowest_mask.
+        */
+       if (static_branch_unlikely(&sched_asym_cpucapacity)) {
+
+               ret = cpupri_find_fitness(&task_rq(task)->rd->cpupri,
+                                         task, lowest_mask,
+                                         rt_task_fits_capacity);
+       } else {
+
+               ret = cpupri_find(&task_rq(task)->rd->cpupri,
+                                 task, lowest_mask);
+       }
+
+       if (!ret)
                return -1; /* No targets found */
 
        /*
@@ -2202,7 +2225,7 @@ static void task_woken_rt(struct rq *rq, struct task_struct *p)
                            (rq->curr->nr_cpus_allowed < 2 ||
                             rq->curr->prio <= p->prio);
 
-       if (need_to_push || !rt_task_fits_capacity(p, cpu_of(rq)))
+       if (need_to_push)
                push_rt_tasks(rq);
 }
 
@@ -2274,10 +2297,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p)
         */
        if (task_on_rq_queued(p) && rq->curr != p) {
 #ifdef CONFIG_SMP
-               bool need_to_push = rq->rt.overloaded ||
-                                   !rt_task_fits_capacity(p, cpu_of(rq));
-
-               if (p->nr_cpus_allowed > 1 && need_to_push)
+               if (p->nr_cpus_allowed > 1 && rq->rt.overloaded)
                        rt_queue_push_tasks(rq);
 #endif /* CONFIG_SMP */
                if (p->prio < rq->curr->prio && cpu_online(cpu_of(rq)))
@@ -2449,10 +2469,11 @@ const struct sched_class rt_sched_class = {
  */
 static DEFINE_MUTEX(rt_constraints_mutex);
 
-/* Must be called with tasklist_lock held */
 static inline int tg_has_rt_tasks(struct task_group *tg)
 {
-       struct task_struct *g, *p;
+       struct task_struct *task;
+       struct css_task_iter it;
+       int ret = 0;
 
        /*
         * Autogroups do not have RT tasks; see autogroup_create().
@@ -2460,12 +2481,12 @@ static inline int tg_has_rt_tasks(struct task_group *tg)
        if (task_group_is_autogroup(tg))
                return 0;
 
-       for_each_process_thread(g, p) {
-               if (rt_task(p) && task_group(p) == tg)
-                       return 1;
-       }
+       css_task_iter_start(&tg->css, 0, &it);
+       while (!ret && (task = css_task_iter_next(&it)))
+               ret |= rt_task(task);
+       css_task_iter_end(&it);
 
-       return 0;
+       return ret;
 }
 
 struct rt_schedulable_data {
@@ -2496,9 +2517,10 @@ static int tg_rt_schedulable(struct task_group *tg, void *data)
                return -EINVAL;
 
        /*
-        * Ensure we don't starve existing RT tasks.
+        * Ensure we don't starve existing RT tasks if runtime turns zero.
         */
-       if (rt_bandwidth_enabled() && !runtime && tg_has_rt_tasks(tg))
+       if (rt_bandwidth_enabled() && !runtime &&
+           tg->rt_bandwidth.rt_runtime && tg_has_rt_tasks(tg))
                return -EBUSY;
 
        total = to_ratio(period, runtime);
@@ -2564,7 +2586,6 @@ static int tg_set_rt_bandwidth(struct task_group *tg,
                return -EINVAL;
 
        mutex_lock(&rt_constraints_mutex);
-       read_lock(&tasklist_lock);
        err = __rt_schedulable(tg, rt_period, rt_runtime);
        if (err)
                goto unlock;
@@ -2582,7 +2603,6 @@ static int tg_set_rt_bandwidth(struct task_group *tg,
        }
        raw_spin_unlock_irq(&tg->rt_bandwidth.rt_runtime_lock);
 unlock:
-       read_unlock(&tasklist_lock);
        mutex_unlock(&rt_constraints_mutex);
 
        return err;
@@ -2641,9 +2661,7 @@ static int sched_rt_global_constraints(void)
        int ret = 0;
 
        mutex_lock(&rt_constraints_mutex);
-       read_lock(&tasklist_lock);
        ret = __rt_schedulable(NULL, 0, 0);
-       read_unlock(&tasklist_lock);
        mutex_unlock(&rt_constraints_mutex);
 
        return ret;
index 9ea6478..0f616bf 100644 (file)
@@ -118,7 +118,13 @@ extern long calc_load_fold_active(struct rq *this_rq, long adjust);
 #ifdef CONFIG_64BIT
 # define NICE_0_LOAD_SHIFT     (SCHED_FIXEDPOINT_SHIFT + SCHED_FIXEDPOINT_SHIFT)
 # define scale_load(w)         ((w) << SCHED_FIXEDPOINT_SHIFT)
-# define scale_load_down(w)    ((w) >> SCHED_FIXEDPOINT_SHIFT)
+# define scale_load_down(w) \
+({ \
+       unsigned long __w = (w); \
+       if (__w) \
+               __w = max(2UL, __w >> SCHED_FIXEDPOINT_SHIFT); \
+       __w; \
+})
 #else
 # define NICE_0_LOAD_SHIFT     (SCHED_FIXEDPOINT_SHIFT)
 # define scale_load(w)         (w)
@@ -305,7 +311,6 @@ bool __dl_overflow(struct dl_bw *dl_b, int cpus, u64 old_bw, u64 new_bw)
               dl_b->bw * cpus < dl_b->total_bw - old_bw + new_bw;
 }
 
-extern void dl_change_utilization(struct task_struct *p, u64 new_bw);
 extern void init_dl_bw(struct dl_bw *dl_b);
 extern int  sched_dl_global_validate(void);
 extern void sched_dl_do_global(void);
@@ -489,7 +494,6 @@ struct cfs_bandwidth { };
 /* CFS-related fields in a runqueue */
 struct cfs_rq {
        struct load_weight      load;
-       unsigned long           runnable_weight;
        unsigned int            nr_running;
        unsigned int            h_nr_running;      /* SCHED_{NORMAL,BATCH,IDLE} */
        unsigned int            idle_h_nr_running; /* SCHED_IDLE */
@@ -528,7 +532,7 @@ struct cfs_rq {
                int             nr;
                unsigned long   load_avg;
                unsigned long   util_avg;
-               unsigned long   runnable_sum;
+               unsigned long   runnable_avg;
        } removed;
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
@@ -688,8 +692,30 @@ struct dl_rq {
 #ifdef CONFIG_FAIR_GROUP_SCHED
 /* An entity is a task if it doesn't "own" a runqueue */
 #define entity_is_task(se)     (!se->my_q)
+
+static inline void se_update_runnable(struct sched_entity *se)
+{
+       if (!entity_is_task(se))
+               se->runnable_weight = se->my_q->h_nr_running;
+}
+
+static inline long se_runnable(struct sched_entity *se)
+{
+       if (entity_is_task(se))
+               return !!se->on_rq;
+       else
+               return se->runnable_weight;
+}
+
 #else
 #define entity_is_task(se)     1
+
+static inline void se_update_runnable(struct sched_entity *se) {}
+
+static inline long se_runnable(struct sched_entity *se)
+{
+       return !!se->on_rq;
+}
 #endif
 
 #ifdef CONFIG_SMP
@@ -701,10 +727,6 @@ static inline long se_weight(struct sched_entity *se)
        return scale_load_down(se->load.weight);
 }
 
-static inline long se_runnable(struct sched_entity *se)
-{
-       return scale_load_down(se->runnable_weight);
-}
 
 static inline bool sched_asym_prefer(int a, int b)
 {
@@ -944,6 +966,9 @@ struct rq {
 #ifdef CONFIG_HAVE_SCHED_AVG_IRQ
        struct sched_avg        avg_irq;
 #endif
+#ifdef CONFIG_SCHED_THERMAL_PRESSURE
+       struct sched_avg        avg_thermal;
+#endif
        u64                     idle_stamp;
        u64                     avg_idle;
 
@@ -967,7 +992,6 @@ struct rq {
 
 #ifdef CONFIG_SCHED_HRTICK
 #ifdef CONFIG_SMP
-       int                     hrtick_csd_pending;
        call_single_data_t      hrtick_csd;
 #endif
        struct hrtimer          hrtick_timer;
@@ -1107,6 +1131,24 @@ static inline u64 rq_clock_task(struct rq *rq)
        return rq->clock_task;
 }
 
+/**
+ * By default the decay is the default pelt decay period.
+ * The decay shift can change the decay period in
+ * multiples of 32.
+ *  Decay shift                Decay period(ms)
+ *     0                       32
+ *     1                       64
+ *     2                       128
+ *     3                       256
+ *     4                       512
+ */
+extern int sched_thermal_decay_shift;
+
+static inline u64 rq_clock_thermal(struct rq *rq)
+{
+       return rq_clock_task(rq) >> sched_thermal_decay_shift;
+}
+
 static inline void rq_clock_skip_update(struct rq *rq)
 {
        lockdep_assert_held(&rq->lock);
@@ -1337,8 +1379,6 @@ extern void sched_ttwu_pending(void);
        for (__sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd); \
                        __sd; __sd = __sd->parent)
 
-#define for_each_lower_domain(sd) for (; sd; sd = sd->child)
-
 /**
  * highest_flag_domain - Return highest sched_domain containing flag.
  * @cpu:       The CPU whose highest level of sched domain is to
@@ -1869,7 +1909,6 @@ extern struct dl_bandwidth def_dl_bandwidth;
 extern void init_dl_bandwidth(struct dl_bandwidth *dl_b, u64 period, u64 runtime);
 extern void init_dl_task_timer(struct sched_dl_entity *dl_se);
 extern void init_dl_inactive_task_timer(struct sched_dl_entity *dl_se);
-extern void init_dl_rq_bw_ratio(struct dl_rq *dl_rq);
 
 #define BW_SHIFT               20
 #define BW_UNIT                        (1 << BW_SHIFT)
@@ -1968,6 +2007,13 @@ static inline int hrtick_enabled(struct rq *rq)
 
 #endif /* CONFIG_SCHED_HRTICK */
 
+#ifndef arch_scale_freq_tick
+static __always_inline
+void arch_scale_freq_tick(void)
+{
+}
+#endif
+
 #ifndef arch_scale_freq_capacity
 static __always_inline
 unsigned long arch_scale_freq_capacity(int cpu)
@@ -2492,3 +2538,6 @@ static inline bool is_per_cpu_kthread(struct task_struct *p)
        return true;
 }
 #endif
+
+void swake_up_all_locked(struct swait_queue_head *q);
+void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait);
index ba683fe..33d0daf 100644 (file)
@@ -70,7 +70,7 @@ static inline void psi_enqueue(struct task_struct *p, bool wakeup)
                return;
 
        if (!wakeup || p->sched_psi_wake_requeue) {
-               if (p->flags & PF_MEMSTALL)
+               if (p->in_memstall)
                        set |= TSK_MEMSTALL;
                if (p->sched_psi_wake_requeue)
                        p->sched_psi_wake_requeue = 0;
@@ -90,9 +90,17 @@ static inline void psi_dequeue(struct task_struct *p, bool sleep)
                return;
 
        if (!sleep) {
-               if (p->flags & PF_MEMSTALL)
+               if (p->in_memstall)
                        clear |= TSK_MEMSTALL;
        } else {
+               /*
+                * When a task sleeps, schedule() dequeues it before
+                * switching to the next one. Merge the clearing of
+                * TSK_RUNNING and TSK_ONCPU to save an unnecessary
+                * psi_task_change() call in psi_sched_switch().
+                */
+               clear |= TSK_ONCPU;
+
                if (p->in_iowait)
                        set |= TSK_IOWAIT;
        }
@@ -109,14 +117,14 @@ static inline void psi_ttwu_dequeue(struct task_struct *p)
         * deregister its sleep-persistent psi states from the old
         * queue, and let psi_enqueue() know it has to requeue.
         */
-       if (unlikely(p->in_iowait || (p->flags & PF_MEMSTALL))) {
+       if (unlikely(p->in_iowait || p->in_memstall)) {
                struct rq_flags rf;
                struct rq *rq;
                int clear = 0;
 
                if (p->in_iowait)
                        clear |= TSK_IOWAIT;
-               if (p->flags & PF_MEMSTALL)
+               if (p->in_memstall)
                        clear |= TSK_MEMSTALL;
 
                rq = __task_rq_lock(p, &rf);
@@ -126,18 +134,31 @@ static inline void psi_ttwu_dequeue(struct task_struct *p)
        }
 }
 
+static inline void psi_sched_switch(struct task_struct *prev,
+                                   struct task_struct *next,
+                                   bool sleep)
+{
+       if (static_branch_likely(&psi_disabled))
+               return;
+
+       psi_task_switch(prev, next, sleep);
+}
+
 static inline void psi_task_tick(struct rq *rq)
 {
        if (static_branch_likely(&psi_disabled))
                return;
 
-       if (unlikely(rq->curr->flags & PF_MEMSTALL))
+       if (unlikely(rq->curr->in_memstall))
                psi_memstall_tick(rq->curr, cpu_of(rq));
 }
 #else /* CONFIG_PSI */
 static inline void psi_enqueue(struct task_struct *p, bool wakeup) {}
 static inline void psi_dequeue(struct task_struct *p, bool sleep) {}
 static inline void psi_ttwu_dequeue(struct task_struct *p) {}
+static inline void psi_sched_switch(struct task_struct *prev,
+                                   struct task_struct *next,
+                                   bool sleep) {}
 static inline void psi_task_tick(struct rq *rq) {}
 #endif /* CONFIG_PSI */
 
index e83a3f8..e1c655f 100644 (file)
@@ -32,6 +32,19 @@ void swake_up_locked(struct swait_queue_head *q)
 }
 EXPORT_SYMBOL(swake_up_locked);
 
+/*
+ * Wake up all waiters. This is an interface which is solely exposed for
+ * completions and not for general usage.
+ *
+ * It is intentionally different from swake_up_all() to allow usage from
+ * hard interrupt context and interrupt disabled regions.
+ */
+void swake_up_all_locked(struct swait_queue_head *q)
+{
+       while (!list_empty(&q->task_list))
+               swake_up_locked(q);
+}
+
 void swake_up_one(struct swait_queue_head *q)
 {
        unsigned long flags;
@@ -69,7 +82,7 @@ void swake_up_all(struct swait_queue_head *q)
 }
 EXPORT_SYMBOL(swake_up_all);
 
-static void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait)
+void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait)
 {
        wait->task = current;
        if (list_empty(&wait->task_list))
index dfb64c0..8344757 100644 (file)
@@ -317,8 +317,9 @@ static void sched_energy_set(bool has_eas)
  * EAS can be used on a root domain if it meets all the following conditions:
  *    1. an Energy Model (EM) is available;
  *    2. the SD_ASYM_CPUCAPACITY flag is set in the sched_domain hierarchy.
- *    3. the EM complexity is low enough to keep scheduling overheads low;
- *    4. schedutil is driving the frequency of all CPUs of the rd;
+ *    3. no SMT is detected.
+ *    4. the EM complexity is low enough to keep scheduling overheads low;
+ *    5. schedutil is driving the frequency of all CPUs of the rd;
  *
  * The complexity of the Energy Model is defined as:
  *
@@ -360,6 +361,13 @@ static bool build_perf_domains(const struct cpumask *cpu_map)
                goto free;
        }
 
+       /* EAS definitely does *not* handle SMT */
+       if (sched_smt_active()) {
+               pr_warn("rd %*pbl: Disabling EAS, SMT is not supported\n",
+                       cpumask_pr_args(cpu_map));
+               goto free;
+       }
+
        for_each_cpu(i, cpu_map) {
                /* Skip already covered CPUs. */
                if (find_pd(pd, i))
@@ -1374,18 +1382,9 @@ sd_init(struct sched_domain_topology_level *tl,
         * Convert topological properties into behaviour.
         */
 
-       if (sd->flags & SD_ASYM_CPUCAPACITY) {
-               struct sched_domain *t = sd;
-
-               /*
-                * Don't attempt to spread across CPUs of different capacities.
-                */
-               if (sd->child)
-                       sd->child->flags &= ~SD_PREFER_SIBLING;
-
-               for_each_lower_domain(t)
-                       t->flags |= SD_BALANCE_WAKE;
-       }
+       /* Don't attempt to spread across CPUs of different capacities. */
+       if ((sd->flags & SD_ASYM_CPUCAPACITY) && sd->child)
+               sd->child->flags &= ~SD_PREFER_SIBLING;
 
        if (sd->flags & SD_SHARE_CPUCAPACITY) {
                sd->imbalance_pct = 110;
index b6ea3dc..ec5c606 100644 (file)
@@ -528,8 +528,12 @@ static long seccomp_attach_filter(unsigned int flags,
                int ret;
 
                ret = seccomp_can_sync_threads();
-               if (ret)
-                       return ret;
+               if (ret) {
+                       if (flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH)
+                               return -ESRCH;
+                       else
+                               return ret;
+               }
        }
 
        /* Set log flag, if present. */
@@ -1221,6 +1225,7 @@ static const struct file_operations seccomp_notify_ops = {
        .poll = seccomp_notify_poll,
        .release = seccomp_notify_release,
        .unlocked_ioctl = seccomp_notify_ioctl,
+       .compat_ioctl = seccomp_notify_ioctl,
 };
 
 static struct file *init_listener(struct seccomp_filter *filter)
@@ -1288,10 +1293,12 @@ static long seccomp_set_mode_filter(unsigned int flags,
         * In the successful case, NEW_LISTENER returns the new listener fd.
         * But in the failure case, TSYNC returns the thread that died. If you
         * combine these two flags, there's no way to tell whether something
-        * succeeded or failed. So, let's disallow this combination.
+        * succeeded or failed. So, let's disallow this combination if the user
+        * has not explicitly requested no errors from TSYNC.
         */
        if ((flags & SECCOMP_FILTER_FLAG_TSYNC) &&
-           (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER))
+           (flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) &&
+           ((flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH) == 0))
                return -EINVAL;
 
        /* Prepare the new filter before holding any locks. */
index 9ad8dea..5b23963 100644 (file)
@@ -413,27 +413,32 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi
 {
        struct sigqueue *q = NULL;
        struct user_struct *user;
+       int sigpending;
 
        /*
         * Protect access to @t credentials. This can go away when all
         * callers hold rcu read lock.
+        *
+        * NOTE! A pending signal will hold on to the user refcount,
+        * and we get/put the refcount only when the sigpending count
+        * changes from/to zero.
         */
        rcu_read_lock();
-       user = get_uid(__task_cred(t)->user);
-       atomic_inc(&user->sigpending);
+       user = __task_cred(t)->user;
+       sigpending = atomic_inc_return(&user->sigpending);
+       if (sigpending == 1)
+               get_uid(user);
        rcu_read_unlock();
 
-       if (override_rlimit ||
-           atomic_read(&user->sigpending) <=
-                       task_rlimit(t, RLIMIT_SIGPENDING)) {
+       if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
                q = kmem_cache_alloc(sigqueue_cachep, flags);
        } else {
                print_dropped_signal(sig);
        }
 
        if (unlikely(q == NULL)) {
-               atomic_dec(&user->sigpending);
-               free_uid(user);
+               if (atomic_dec_and_test(&user->sigpending))
+                       free_uid(user);
        } else {
                INIT_LIST_HEAD(&q->list);
                q->flags = 0;
@@ -447,8 +452,8 @@ static void __sigqueue_free(struct sigqueue *q)
 {
        if (q->flags & SIGQUEUE_PREALLOC)
                return;
-       atomic_dec(&q->user->sigpending);
-       free_uid(q->user);
+       if (atomic_dec_and_test(&q->user->sigpending))
+               free_uid(q->user);
        kmem_cache_free(sigqueue_cachep, q);
 }
 
index d0ada39..786092a 100644 (file)
@@ -329,6 +329,11 @@ EXPORT_SYMBOL(smp_call_function_single);
  * (ie: embedded in an object) and is responsible for synchronizing it
  * such that the IPIs performed on the @csd are strictly serialized.
  *
+ * If the function is called with one csd which has not yet been
+ * processed by previous call to smp_call_function_single_async(), the
+ * function will return immediately with -EBUSY showing that the csd
+ * object is still in progress.
+ *
  * NOTE: Be careful, there is unfortunately no current debugging facility to
  * validate the correctness of this serialization.
  */
@@ -338,14 +343,17 @@ int smp_call_function_single_async(int cpu, call_single_data_t *csd)
 
        preempt_disable();
 
-       /* We could deadlock if we have to wait here with interrupts disabled! */
-       if (WARN_ON_ONCE(csd->flags & CSD_FLAG_LOCK))
-               csd_lock_wait(csd);
+       if (csd->flags & CSD_FLAG_LOCK) {
+               err = -EBUSY;
+               goto out;
+       }
 
        csd->flags = CSD_FLAG_LOCK;
        smp_wmb();
 
        err = generic_exec_single(cpu, csd, csd->func, csd->info);
+
+out:
        preempt_enable();
 
        return err;
@@ -589,20 +597,13 @@ void __init setup_nr_cpu_ids(void)
 void __init smp_init(void)
 {
        int num_nodes, num_cpus;
-       unsigned int cpu;
 
        idle_threads_init();
        cpuhp_threads_init();
 
        pr_info("Bringing up secondary CPUs ...\n");
 
-       /* FIXME: This should be done in userspace --RR */
-       for_each_present_cpu(cpu) {
-               if (num_online_cpus() >= setup_max_cpus)
-                       break;
-               if (!cpu_online(cpu))
-                       cpu_up(cpu);
-       }
+       bringup_nonboot_cpus(setup_max_cpus);
 
        num_nodes = num_online_nodes();
        num_cpus  = num_online_cpus();
index 0427a86..a47c6dd 100644 (file)
@@ -126,7 +126,7 @@ void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
         * Were softirqs turned off above:
         */
        if (softirq_count() == (cnt & SOFTIRQ_MASK))
-               trace_softirqs_off(ip);
+               lockdep_softirqs_off(ip);
        raw_local_irq_restore(flags);
 
        if (preempt_count() == cnt) {
@@ -147,7 +147,7 @@ static void __local_bh_enable(unsigned int cnt)
                trace_preempt_on(CALLER_ADDR0, get_lock_parent_ip());
 
        if (softirq_count() == (cnt & SOFTIRQ_MASK))
-               trace_softirqs_on(_RET_IP_);
+               lockdep_softirqs_on(_RET_IP_);
 
        __preempt_count_sub(cnt);
 }
@@ -174,7 +174,7 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
         * Are softirqs going to be turned on now:
         */
        if (softirq_count() == SOFTIRQ_DISABLE_OFFSET)
-               trace_softirqs_on(ip);
+               lockdep_softirqs_on(ip);
        /*
         * Keep preemption disabled until we are done with
         * softirq processing:
@@ -224,9 +224,9 @@ static inline bool lockdep_softirq_start(void)
 {
        bool in_hardirq = false;
 
-       if (trace_hardirq_context(current)) {
+       if (lockdep_hardirq_context(current)) {
                in_hardirq = true;
-               trace_hardirq_exit();
+               lockdep_hardirq_exit();
        }
 
        lockdep_softirq_enter();
@@ -239,7 +239,7 @@ static inline void lockdep_softirq_end(bool in_hardirq)
        lockdep_softirq_exit();
 
        if (in_hardirq)
-               trace_hardirq_enter();
+               lockdep_hardirq_enter();
 }
 #else
 static inline bool lockdep_softirq_start(void) { return false; }
@@ -414,7 +414,8 @@ void irq_exit(void)
 
        tick_irq_exit();
        rcu_irq_exit();
-       trace_hardirq_exit(); /* must be last! */
+        /* must be last! */
+       lockdep_hardirq_exit();
 }
 
 /*
index f9bc5c3..d325f3a 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/syscalls.h>
 #include <linux/kprobes.h>
 #include <linux/user_namespace.h>
+#include <linux/time_namespace.h>
 #include <linux/binfmts.h>
 
 #include <linux/sched.h>
@@ -2546,6 +2547,7 @@ static int do_sysinfo(struct sysinfo *info)
        memset(info, 0, sizeof(struct sysinfo));
 
        ktime_get_boottime_ts64(&tp);
+       timens_add_boottime(&tp);
        info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0);
 
        get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT);
index 0fef395..825f282 100644 (file)
@@ -97,16 +97,26 @@ void task_work_run(void)
                 * work->func() can do task_work_add(), do not set
                 * work_exited unless the list is empty.
                 */
-               raw_spin_lock_irq(&task->pi_lock);
                do {
+                       head = NULL;
                        work = READ_ONCE(task->task_works);
-                       head = !work && (task->flags & PF_EXITING) ?
-                               &work_exited : NULL;
+                       if (!work) {
+                               if (task->flags & PF_EXITING)
+                                       head = &work_exited;
+                               else
+                                       break;
+                       }
                } while (cmpxchg(&task->task_works, work, head) != work);
-               raw_spin_unlock_irq(&task->pi_lock);
 
                if (!work)
                        break;
+               /*
+                * Synchronize with task_work_cancel(). It can not remove
+                * the first entry == work, cmpxchg(task_works) must fail.
+                * But it can remove another entry from the ->next list.
+                */
+               raw_spin_lock_irq(&task->pi_lock);
+               raw_spin_unlock_irq(&task->pi_lock);
 
                do {
                        next = work->next;
index 428beb6..7cb09c4 100644 (file)
@@ -928,6 +928,15 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
 
        clocksource_arch_init(cs);
 
+#ifdef CONFIG_GENERIC_VDSO_CLOCK_MODE
+       if (cs->vdso_clock_mode < 0 ||
+           cs->vdso_clock_mode >= VDSO_CLOCKMODE_MAX) {
+               pr_warn("clocksource %s registered with invalid VDSO mode %d. Disabling VDSO support.\n",
+                       cs->name, cs->vdso_clock_mode);
+               cs->vdso_clock_mode = VDSO_CLOCKMODE_NONE;
+       }
+#endif
+
        /* Initialize mult/shift and max_idle_ns */
        __clocksource_update_freq_scale(cs, scale, freq);
 
index 3a609e7..d0a5ba3 100644 (file)
@@ -311,7 +311,7 @@ s64 __ktime_divns(const ktime_t kt, s64 div)
                div >>= 1;
        }
        tmp >>= sft;
-       do_div(tmp, (unsigned long) div);
+       do_div(tmp, (u32) div);
        return dclc < 0 ? -tmp : tmp;
 }
 EXPORT_SYMBOL_GPL(__ktime_divns);
@@ -1404,7 +1404,7 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
        base = softtimer ? HRTIMER_MAX_CLOCK_BASES / 2 : 0;
        base += hrtimer_clockid_to_base(clock_id);
        timer->is_soft = softtimer;
-       timer->is_hard = !softtimer;
+       timer->is_hard = !!(mode & HRTIMER_MODE_HARD);
        timer->base = &cpu_base->clock_base[base];
        timerqueue_init(&timer->node);
 }
@@ -1514,7 +1514,11 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
         */
        raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
        trace_hrtimer_expire_entry(timer, now);
+       lockdep_hrtimer_enter(timer);
+
        restart = fn(timer);
+
+       lockdep_hrtimer_exit(timer);
        trace_hrtimer_expire_exit(timer);
        raw_spin_lock_irq(&cpu_base->lock);
 
index d23b434..eddcf49 100644 (file)
@@ -58,7 +58,8 @@ static struct clocksource clocksource_jiffies = {
        .max_cycles     = 10,
 };
 
-__cacheline_aligned_in_smp DEFINE_SEQLOCK(jiffies_lock);
+__cacheline_aligned_in_smp DEFINE_RAW_SPINLOCK(jiffies_lock);
+__cacheline_aligned_in_smp seqcount_t jiffies_seq;
 
 #if (BITS_PER_LONG < 64)
 u64 get_jiffies_64(void)
@@ -67,9 +68,9 @@ u64 get_jiffies_64(void)
        u64 ret;
 
        do {
-               seq = read_seqbegin(&jiffies_lock);
+               seq = read_seqcount_begin(&jiffies_seq);
                ret = jiffies_64;
-       } while (read_seqretry(&jiffies_lock, seq));
+       } while (read_seqcount_retry(&jiffies_seq, seq));
        return ret;
 }
 EXPORT_SYMBOL(get_jiffies_64);
index 1285850..e6ba064 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/user_namespace.h>
 #include <linux/sched/signal.h>
 #include <linux/sched/task.h>
+#include <linux/clocksource.h>
 #include <linux/seq_file.h>
 #include <linux/proc_ns.h>
 #include <linux/export.h>
@@ -172,8 +173,8 @@ static struct timens_offset offset_from_ts(struct timespec64 off)
  * for vdso_data->clock_mode is a non-issue. The task is spin waiting for the
  * update to finish and for 'seq' to become even anyway.
  *
- * Timens page has vdso_data->clock_mode set to VCLOCK_TIMENS which enforces
- * the time namespace handling path.
+ * Timens page has vdso_data->clock_mode set to VDSO_CLOCKMODE_TIMENS which
+ * enforces the time namespace handling path.
  */
 static void timens_setup_vdso_data(struct vdso_data *vdata,
                                   struct time_namespace *ns)
@@ -183,7 +184,7 @@ static void timens_setup_vdso_data(struct vdso_data *vdata,
        struct timens_offset boottime = offset_from_ts(ns->offsets.boottime);
 
        vdata->seq                      = 1;
-       vdata->clock_mode               = VCLOCK_TIMENS;
+       vdata->clock_mode               = VDSO_CLOCKMODE_TIMENS;
        offset[CLOCK_MONOTONIC]         = monotonic;
        offset[CLOCK_MONOTONIC_RAW]     = monotonic;
        offset[CLOCK_MONOTONIC_COARSE]  = monotonic;
index 8ff6da7..2fd3b3f 100644 (file)
@@ -118,6 +118,16 @@ static inline int validate_clock_permissions(const clockid_t clock)
        return __get_task_for_clock(clock, false, false) ? 0 : -EINVAL;
 }
 
+static inline enum pid_type cpu_timer_pid_type(struct k_itimer *timer)
+{
+       return CPUCLOCK_PERTHREAD(timer->it_clock) ? PIDTYPE_PID : PIDTYPE_TGID;
+}
+
+static inline struct task_struct *cpu_timer_task_rcu(struct k_itimer *timer)
+{
+       return pid_task(timer->it.cpu.pid, cpu_timer_pid_type(timer));
+}
+
 /*
  * Update expiry time from increment, and increase overrun count,
  * given the current clock sample.
@@ -336,9 +346,7 @@ static void __thread_group_cputime(struct task_struct *tsk, u64 *samples)
 /*
  * Sample a process (thread group) clock for the given task clkid. If the
  * group's cputime accounting is already enabled, read the atomic
- * store. Otherwise a full update is required.  Task's sighand lock must be
- * held to protect the task traversal on a full update. clkid is already
- * validated.
+ * store. Otherwise a full update is required.  clkid is already validated.
  */
 static u64 cpu_clock_sample_group(const clockid_t clkid, struct task_struct *p,
                                  bool start)
@@ -393,7 +401,12 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer)
 
        new_timer->kclock = &clock_posix_cpu;
        timerqueue_init(&new_timer->it.cpu.node);
-       new_timer->it.cpu.task = p;
+       new_timer->it.cpu.pid = get_task_pid(p, cpu_timer_pid_type(new_timer));
+       /*
+        * get_task_for_clock() took a reference on @p. Drop it as the timer
+        * holds a reference on the pid of @p.
+        */
+       put_task_struct(p);
        return 0;
 }
 
@@ -406,13 +419,15 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer)
 static int posix_cpu_timer_del(struct k_itimer *timer)
 {
        struct cpu_timer *ctmr = &timer->it.cpu;
-       struct task_struct *p = ctmr->task;
        struct sighand_struct *sighand;
+       struct task_struct *p;
        unsigned long flags;
        int ret = 0;
 
-       if (WARN_ON_ONCE(!p))
-               return -EINVAL;
+       rcu_read_lock();
+       p = cpu_timer_task_rcu(timer);
+       if (!p)
+               goto out;
 
        /*
         * Protect against sighand release/switch in exit/exec and process/
@@ -434,8 +449,10 @@ static int posix_cpu_timer_del(struct k_itimer *timer)
                unlock_task_sighand(p, &flags);
        }
 
+out:
+       rcu_read_unlock();
        if (!ret)
-               put_task_struct(p);
+               put_pid(ctmr->pid);
 
        return ret;
 }
@@ -484,12 +501,11 @@ void posix_cpu_timers_exit_group(struct task_struct *tsk)
  * Insert the timer on the appropriate list before any timers that
  * expire later.  This must be called with the sighand lock held.
  */
-static void arm_timer(struct k_itimer *timer)
+static void arm_timer(struct k_itimer *timer, struct task_struct *p)
 {
        int clkidx = CPUCLOCK_WHICH(timer->it_clock);
        struct cpu_timer *ctmr = &timer->it.cpu;
        u64 newexp = cpu_timer_getexpires(ctmr);
-       struct task_struct *p = ctmr->task;
        struct posix_cputimer_base *base;
 
        if (CPUCLOCK_PERTHREAD(timer->it_clock))
@@ -564,13 +580,21 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
        clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
        u64 old_expires, new_expires, old_incr, val;
        struct cpu_timer *ctmr = &timer->it.cpu;
-       struct task_struct *p = ctmr->task;
        struct sighand_struct *sighand;
+       struct task_struct *p;
        unsigned long flags;
        int ret = 0;
 
-       if (WARN_ON_ONCE(!p))
-               return -EINVAL;
+       rcu_read_lock();
+       p = cpu_timer_task_rcu(timer);
+       if (!p) {
+               /*
+                * If p has just been reaped, we can no
+                * longer get any information about it at all.
+                */
+               rcu_read_unlock();
+               return -ESRCH;
+       }
 
        /*
         * Use the to_ktime conversion because that clamps the maximum
@@ -587,8 +611,10 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
         * If p has just been reaped, we can no
         * longer get any information about it at all.
         */
-       if (unlikely(sighand == NULL))
+       if (unlikely(sighand == NULL)) {
+               rcu_read_unlock();
                return -ESRCH;
+       }
 
        /*
         * Disarm any old timer after extracting its expiry time.
@@ -662,7 +688,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
         */
        cpu_timer_setexpires(ctmr, new_expires);
        if (new_expires != 0 && val < new_expires) {
-               arm_timer(timer);
+               arm_timer(timer, p);
        }
 
        unlock_task_sighand(p, &flags);
@@ -693,6 +719,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
 
        ret = 0;
  out:
+       rcu_read_unlock();
        if (old)
                old->it_interval = ns_to_timespec64(old_incr);
 
@@ -704,10 +731,12 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp
        clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
        struct cpu_timer *ctmr = &timer->it.cpu;
        u64 now, expires = cpu_timer_getexpires(ctmr);
-       struct task_struct *p = ctmr->task;
+       struct task_struct *p;
 
-       if (WARN_ON_ONCE(!p))
-               return;
+       rcu_read_lock();
+       p = cpu_timer_task_rcu(timer);
+       if (!p)
+               goto out;
 
        /*
         * Easy part: convert the reload time.
@@ -715,36 +744,15 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp
        itp->it_interval = ktime_to_timespec64(timer->it_interval);
 
        if (!expires)
-               return;
+               goto out;
 
        /*
         * Sample the clock to take the difference with the expiry time.
         */
-       if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+       if (CPUCLOCK_PERTHREAD(timer->it_clock))
                now = cpu_clock_sample(clkid, p);
-       } else {
-               struct sighand_struct *sighand;
-               unsigned long flags;
-
-               /*
-                * Protect against sighand release/switch in exit/exec and
-                * also make timer sampling safe if it ends up calling
-                * thread_group_cputime().
-                */
-               sighand = lock_task_sighand(p, &flags);
-               if (unlikely(sighand == NULL)) {
-                       /*
-                        * The process has been reaped.
-                        * We can't even collect a sample any more.
-                        * Disarm the timer, nothing else to do.
-                        */
-                       cpu_timer_setexpires(ctmr, 0);
-                       return;
-               } else {
-                       now = cpu_clock_sample_group(clkid, p, false);
-                       unlock_task_sighand(p, &flags);
-               }
-       }
+       else
+               now = cpu_clock_sample_group(clkid, p, false);
 
        if (now < expires) {
                itp->it_value = ns_to_timespec64(expires - now);
@@ -756,6 +764,8 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp
                itp->it_value.tv_nsec = 1;
                itp->it_value.tv_sec = 0;
        }
+out:
+       rcu_read_unlock();
 }
 
 #define MAX_COLLECTED  20
@@ -976,56 +986,38 @@ static void check_process_timers(struct task_struct *tsk,
 static void posix_cpu_timer_rearm(struct k_itimer *timer)
 {
        clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
-       struct cpu_timer *ctmr = &timer->it.cpu;
-       struct task_struct *p = ctmr->task;
+       struct task_struct *p;
        struct sighand_struct *sighand;
        unsigned long flags;
        u64 now;
 
-       if (WARN_ON_ONCE(!p))
-               return;
+       rcu_read_lock();
+       p = cpu_timer_task_rcu(timer);
+       if (!p)
+               goto out;
 
        /*
         * Fetch the current sample and update the timer's expiry time.
         */
-       if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
+       if (CPUCLOCK_PERTHREAD(timer->it_clock))
                now = cpu_clock_sample(clkid, p);
-               bump_cpu_timer(timer, now);
-               if (unlikely(p->exit_state))
-                       return;
-
-               /* Protect timer list r/w in arm_timer() */
-               sighand = lock_task_sighand(p, &flags);
-               if (!sighand)
-                       return;
-       } else {
-               /*
-                * Protect arm_timer() and timer sampling in case of call to
-                * thread_group_cputime().
-                */
-               sighand = lock_task_sighand(p, &flags);
-               if (unlikely(sighand == NULL)) {
-                       /*
-                        * The process has been reaped.
-                        * We can't even collect a sample any more.
-                        */
-                       cpu_timer_setexpires(ctmr, 0);
-                       return;
-               } else if (unlikely(p->exit_state) && thread_group_empty(p)) {
-                       /* If the process is dying, no need to rearm */
-                       goto unlock;
-               }
+       else
                now = cpu_clock_sample_group(clkid, p, true);
-               bump_cpu_timer(timer, now);
-               /* Leave the sighand locked for the call below.  */
-       }
+
+       bump_cpu_timer(timer, now);
+
+       /* Protect timer list r/w in arm_timer() */
+       sighand = lock_task_sighand(p, &flags);
+       if (unlikely(sighand == NULL))
+               goto out;
 
        /*
         * Now re-arm for the new expiry time.
         */
-       arm_timer(timer);
-unlock:
+       arm_timer(timer, p);
        unlock_task_sighand(p, &flags);
+out:
+       rcu_read_unlock();
 }
 
 /**
@@ -1126,8 +1118,11 @@ void run_posix_cpu_timers(void)
        if (!fastpath_timer_check(tsk))
                return;
 
-       if (!lock_task_sighand(tsk, &flags))
+       lockdep_posixtimer_enter();
+       if (!lock_task_sighand(tsk, &flags)) {
+               lockdep_posixtimer_exit();
                return;
+       }
        /*
         * Here we take off tsk->signal->cpu_timers[N] and
         * tsk->cpu_timers[N] all the timers that are firing, and
@@ -1169,6 +1164,7 @@ void run_posix_cpu_timers(void)
                        cpu_timer_fire(timer);
                spin_unlock(&timer->it_lock);
        }
+       lockdep_posixtimer_exit();
 }
 
 /*
index ff0eb30..07709ac 100644 (file)
@@ -121,7 +121,8 @@ static struct k_itimer *__posix_timers_find(struct hlist_head *head,
 {
        struct k_itimer *timer;
 
-       hlist_for_each_entry_rcu(timer, head, t_hash) {
+       hlist_for_each_entry_rcu(timer, head, t_hash,
+                                lockdep_is_held(&hash_lock)) {
                if ((timer->it_signal == sig) && (timer->it_id == id))
                        return timer;
        }
index e4332e3..fa3f800 100644 (file)
@@ -208,7 +208,8 @@ sched_clock_register(u64 (*read)(void), int bits, unsigned long rate)
 
        if (sched_clock_timer.function != NULL) {
                /* update timeout for clock wrap */
-               hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
+               hrtimer_start(&sched_clock_timer, cd.wrap_kt,
+                             HRTIMER_MODE_REL_HARD);
        }
 
        r = rate;
@@ -254,9 +255,9 @@ void __init generic_sched_clock_init(void)
         * Start the timer to keep sched_clock() properly updated and
         * sets the initial epoch.
         */
-       hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
        sched_clock_timer.function = sched_clock_poll;
-       hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
+       hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD);
 }
 
 /*
@@ -293,7 +294,7 @@ void sched_clock_resume(void)
        struct clock_read_data *rd = &cd.read_data[0];
 
        rd->epoch_cyc = cd.actual_read_sched_clock();
-       hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
+       hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD);
        rd->read_sched_clock = cd.actual_read_sched_clock;
 }
 
index 7e5d352..6c9c342 100644 (file)
@@ -84,13 +84,15 @@ int tick_is_oneshot_available(void)
 static void tick_periodic(int cpu)
 {
        if (tick_do_timer_cpu == cpu) {
-               write_seqlock(&jiffies_lock);
+               raw_spin_lock(&jiffies_lock);
+               write_seqcount_begin(&jiffies_seq);
 
                /* Keep track of the next tick event */
                tick_next_period = ktime_add(tick_next_period, tick_period);
 
                do_timer(1);
-               write_sequnlock(&jiffies_lock);
+               write_seqcount_end(&jiffies_seq);
+               raw_spin_unlock(&jiffies_lock);
                update_wall_time();
        }
 
@@ -162,9 +164,9 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
                ktime_t next;
 
                do {
-                       seq = read_seqbegin(&jiffies_lock);
+                       seq = read_seqcount_begin(&jiffies_seq);
                        next = tick_next_period;
-               } while (read_seqretry(&jiffies_lock, seq));
+               } while (read_seqcount_retry(&jiffies_seq, seq));
 
                clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
 
index a792d21..3e2dc9b 100644 (file)
@@ -65,7 +65,8 @@ static void tick_do_update_jiffies64(ktime_t now)
                return;
 
        /* Reevaluate with jiffies_lock held */
-       write_seqlock(&jiffies_lock);
+       raw_spin_lock(&jiffies_lock);
+       write_seqcount_begin(&jiffies_seq);
 
        delta = ktime_sub(now, last_jiffies_update);
        if (delta >= tick_period) {
@@ -91,10 +92,12 @@ static void tick_do_update_jiffies64(ktime_t now)
                /* Keep the tick_next_period variable up to date */
                tick_next_period = ktime_add(last_jiffies_update, tick_period);
        } else {
-               write_sequnlock(&jiffies_lock);
+               write_seqcount_end(&jiffies_seq);
+               raw_spin_unlock(&jiffies_lock);
                return;
        }
-       write_sequnlock(&jiffies_lock);
+       write_seqcount_end(&jiffies_seq);
+       raw_spin_unlock(&jiffies_lock);
        update_wall_time();
 }
 
@@ -105,12 +108,14 @@ static ktime_t tick_init_jiffy_update(void)
 {
        ktime_t period;
 
-       write_seqlock(&jiffies_lock);
+       raw_spin_lock(&jiffies_lock);
+       write_seqcount_begin(&jiffies_seq);
        /* Did we start the jiffies update yet ? */
        if (last_jiffies_update == 0)
                last_jiffies_update = tick_next_period;
        period = last_jiffies_update;
-       write_sequnlock(&jiffies_lock);
+       write_seqcount_end(&jiffies_seq);
+       raw_spin_unlock(&jiffies_lock);
        return period;
 }
 
@@ -240,6 +245,7 @@ static void nohz_full_kick_func(struct irq_work *work)
 
 static DEFINE_PER_CPU(struct irq_work, nohz_full_kick_work) = {
        .func = nohz_full_kick_func,
+       .flags = ATOMIC_INIT(IRQ_WORK_HARD_IRQ),
 };
 
 /*
@@ -676,10 +682,10 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
 
        /* Read jiffies and the time when jiffies were updated last */
        do {
-               seq = read_seqbegin(&jiffies_lock);
+               seq = read_seqcount_begin(&jiffies_seq);
                basemono = last_jiffies_update;
                basejiff = jiffies;
-       } while (read_seqretry(&jiffies_lock, seq));
+       } while (read_seqcount_retry(&jiffies_seq, seq));
        ts->last_jiffies = basejiff;
        ts->timer_expires_base = basemono;
 
index ca69290..9ebaab1 100644 (file)
@@ -1005,9 +1005,8 @@ static int scale64_check_overflow(u64 mult, u64 div, u64 *base)
            ((int)sizeof(u64)*8 - fls64(mult) < fls64(rem)))
                return -EOVERFLOW;
        tmp *= mult;
-       rem *= mult;
 
-       do_div(rem, div);
+       rem = div64_u64(rem * mult, div);
        *base = tmp + rem;
        return 0;
 }
@@ -2397,8 +2396,10 @@ EXPORT_SYMBOL(hardpps);
  */
 void xtime_update(unsigned long ticks)
 {
-       write_seqlock(&jiffies_lock);
+       raw_spin_lock(&jiffies_lock);
+       write_seqcount_begin(&jiffies_seq);
        do_timer(ticks);
-       write_sequnlock(&jiffies_lock);
+       write_seqcount_end(&jiffies_seq);
+       raw_spin_unlock(&jiffies_lock);
        update_wall_time();
 }
index 141ab3a..099737f 100644 (file)
@@ -25,7 +25,8 @@ static inline void sched_clock_resume(void) { }
 extern void do_timer(unsigned long ticks);
 extern void update_wall_time(void);
 
-extern seqlock_t jiffies_lock;
+extern raw_spinlock_t jiffies_lock;
+extern seqcount_t jiffies_seq;
 
 #define CS_NAME_LEN    32
 
index 4820823..a5221ab 100644 (file)
@@ -944,6 +944,7 @@ static struct timer_base *lock_timer_base(struct timer_list *timer,
 
 #define MOD_TIMER_PENDING_ONLY         0x01
 #define MOD_TIMER_REDUCE               0x02
+#define MOD_TIMER_NOTPENDING           0x04
 
 static inline int
 __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int options)
@@ -960,7 +961,7 @@ __mod_timer(struct timer_list *timer, unsigned long expires, unsigned int option
         * the timer is re-modified to have the same timeout or ends up in the
         * same array bucket then just return:
         */
-       if (timer_pending(timer)) {
+       if (!(options & MOD_TIMER_NOTPENDING) && timer_pending(timer)) {
                /*
                 * The downside of this optimization is that it can result in
                 * larger granularity than you would get from adding a new
@@ -1133,7 +1134,7 @@ EXPORT_SYMBOL(timer_reduce);
 void add_timer(struct timer_list *timer)
 {
        BUG_ON(timer_pending(timer));
-       mod_timer(timer, timer->expires);
+       __mod_timer(timer, timer->expires, MOD_TIMER_NOTPENDING);
 }
 EXPORT_SYMBOL(add_timer);
 
@@ -1828,21 +1829,23 @@ static void process_timeout(struct timer_list *t)
  * schedule_timeout - sleep until timeout
  * @timeout: timeout value in jiffies
  *
- * Make the current task sleep until @timeout jiffies have
- * elapsed. The routine will return immediately unless
- * the current task state has been set (see set_current_state()).
+ * Make the current task sleep until @timeout jiffies have elapsed.
+ * The function behavior depends on the current task state
+ * (see also set_current_state() description):
  *
- * You can set the task state as follows -
+ * %TASK_RUNNING - the scheduler is called, but the task does not sleep
+ * at all. That happens because sched_submit_work() does nothing for
+ * tasks in %TASK_RUNNING state.
  *
  * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to
  * pass before the routine returns unless the current task is explicitly
- * woken up, (e.g. by wake_up_process())".
+ * woken up, (e.g. by wake_up_process()).
  *
  * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
  * delivered to the current task or the current task is explicitly woken
  * up.
  *
- * The current task state is guaranteed to be TASK_RUNNING when this
+ * The current task state is guaranteed to be %TASK_RUNNING when this
  * routine returns.
  *
  * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule
@@ -1850,7 +1853,7 @@ static void process_timeout(struct timer_list *t)
  * value will be %MAX_SCHEDULE_TIMEOUT.
  *
  * Returns 0 when the timer has expired otherwise the remaining time in
- * jiffies will be returned.  In all cases the return value is guaranteed
+ * jiffies will be returned. In all cases the return value is guaranteed
  * to be non-negative.
  */
 signed long __sched schedule_timeout(signed long timeout)
@@ -1891,7 +1894,7 @@ signed long __sched schedule_timeout(signed long timeout)
 
        timer.task = current;
        timer_setup_on_stack(&timer.timer, process_timeout, 0);
-       __mod_timer(&timer.timer, expire, 0);
+       __mod_timer(&timer.timer, expire, MOD_TIMER_NOTPENDING);
        schedule();
        del_singleshot_timer_sync(&timer.timer);
 
index 9577c89..54ce6eb 100644 (file)
@@ -71,13 +71,15 @@ void update_vsyscall(struct timekeeper *tk)
 {
        struct vdso_data *vdata = __arch_get_k_vdso_data();
        struct vdso_timestamp *vdso_ts;
+       s32 clock_mode;
        u64 nsec;
 
        /* copy vsyscall data */
        vdso_write_begin(vdata);
 
-       vdata[CS_HRES_COARSE].clock_mode        = __arch_get_clock_mode(tk);
-       vdata[CS_RAW].clock_mode                = __arch_get_clock_mode(tk);
+       clock_mode = tk->tkr_mono.clock->vdso_clock_mode;
+       vdata[CS_HRES_COARSE].clock_mode        = clock_mode;
+       vdata[CS_RAW].clock_mode                = clock_mode;
 
        /* CLOCK_REALTIME also required for time() */
        vdso_ts         = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME];
@@ -103,10 +105,10 @@ void update_vsyscall(struct timekeeper *tk)
        WRITE_ONCE(vdata[CS_HRES_COARSE].hrtimer_res, hrtimer_resolution);
 
        /*
-        * Architectures can opt out of updating the high resolution part
-        * of the VDSO.
+        * If the current clocksource is not VDSO capable, then spare the
+        * update of the high reolution parts.
         */
-       if (__arch_update_vdso_data())
+       if (clock_mode != VDSO_CLOCKMODE_NONE)
                update_vdso_data(vdata, tk);
 
        __arch_update_vsyscall(vdata, tk);
index 7c13f55..a1a4148 100644 (file)
@@ -42,6 +42,9 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Paul E. McKenney <paulmck@linux.ibm.com>");
 
+static bool disable_onoff_at_boot;
+module_param(disable_onoff_at_boot, bool, 0444);
+
 static char *torture_type;
 static int verbose;
 
@@ -84,6 +87,7 @@ bool torture_offline(int cpu, long *n_offl_attempts, long *n_offl_successes,
 {
        unsigned long delta;
        int ret;
+       char *s;
        unsigned long starttime;
 
        if (!cpu_online(cpu) || !cpu_is_hotpluggable(cpu))
@@ -97,12 +101,18 @@ bool torture_offline(int cpu, long *n_offl_attempts, long *n_offl_successes,
                         torture_type, cpu);
        starttime = jiffies;
        (*n_offl_attempts)++;
-       ret = cpu_down(cpu);
+       ret = remove_cpu(cpu);
        if (ret) {
+               s = "";
+               if (!rcu_inkernel_boot_has_ended() && ret == -EBUSY) {
+                       // PCI probe frequently disables hotplug during boot.
+                       (*n_offl_attempts)--;
+                       s = " (-EBUSY forgiven during boot)";
+               }
                if (verbose)
                        pr_alert("%s" TORTURE_FLAG
-                                "torture_onoff task: offline %d failed: errno %d\n",
-                                torture_type, cpu, ret);
+                                "torture_onoff task: offline %d failed%s: errno %d\n",
+                                torture_type, cpu, s, ret);
        } else {
                if (verbose > 1)
                        pr_alert("%s" TORTURE_FLAG
@@ -137,6 +147,7 @@ bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes,
 {
        unsigned long delta;
        int ret;
+       char *s;
        unsigned long starttime;
 
        if (cpu_online(cpu) || !cpu_is_hotpluggable(cpu))
@@ -148,12 +159,18 @@ bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes,
                         torture_type, cpu);
        starttime = jiffies;
        (*n_onl_attempts)++;
-       ret = cpu_up(cpu);
+       ret = add_cpu(cpu);
        if (ret) {
+               s = "";
+               if (!rcu_inkernel_boot_has_ended() && ret == -EBUSY) {
+                       // PCI probe frequently disables hotplug during boot.
+                       (*n_onl_attempts)--;
+                       s = " (-EBUSY forgiven during boot)";
+               }
                if (verbose)
                        pr_alert("%s" TORTURE_FLAG
-                                "torture_onoff task: online %d failed: errno %d\n",
-                                torture_type, cpu, ret);
+                                "torture_onoff task: online %d failed%s: errno %d\n",
+                                torture_type, cpu, s, ret);
        } else {
                if (verbose > 1)
                        pr_alert("%s" TORTURE_FLAG
@@ -192,17 +209,18 @@ torture_onoff(void *arg)
        for_each_online_cpu(cpu)
                maxcpu = cpu;
        WARN_ON(maxcpu < 0);
-       if (!IS_MODULE(CONFIG_TORTURE_TEST))
+       if (!IS_MODULE(CONFIG_TORTURE_TEST)) {
                for_each_possible_cpu(cpu) {
                        if (cpu_online(cpu))
                                continue;
-                       ret = cpu_up(cpu);
+                       ret = add_cpu(cpu);
                        if (ret && verbose) {
                                pr_alert("%s" TORTURE_FLAG
                                         "%s: Initial online %d: errno %d\n",
                                         __func__, torture_type, cpu, ret);
                        }
                }
+       }
 
        if (maxcpu == 0) {
                VERBOSE_TOROUT_STRING("Only one CPU, so CPU-hotplug testing is disabled");
@@ -215,6 +233,10 @@ torture_onoff(void *arg)
                VERBOSE_TOROUT_STRING("torture_onoff end holdoff");
        }
        while (!torture_must_stop()) {
+               if (disable_onoff_at_boot && !rcu_inkernel_boot_has_ended()) {
+                       schedule_timeout_interruptible(HZ / 10);
+                       continue;
+               }
                cpu = (torture_random(&rand) >> 4) % (maxcpu + 1);
                if (!torture_offline(cpu,
                                     &n_offline_attempts, &n_offline_successes,
index 91e8851..402eef8 100644 (file)
@@ -143,8 +143,8 @@ if FTRACE
 
 config BOOTTIME_TRACING
        bool "Boot-time Tracing support"
-       depends on BOOT_CONFIG && TRACING
-       default y
+       depends on TRACING
+       select BOOT_CONFIG
        help
          Enable developer to setup ftrace subsystem via supplemental
          kernel cmdline at boot time for debugging (tracing) driver
index 0735ae8..ca39dc3 100644 (file)
@@ -335,6 +335,7 @@ static void put_probe_ref(void)
 
 static void blk_trace_cleanup(struct blk_trace *bt)
 {
+       synchronize_rcu();
        blk_trace_free(bt);
        put_probe_ref();
 }
@@ -629,8 +630,10 @@ static int compat_blk_trace_setup(struct request_queue *q, char *name,
 static int __blk_trace_startstop(struct request_queue *q, int start)
 {
        int ret;
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
 
+       bt = rcu_dereference_protected(q->blk_trace,
+                                      lockdep_is_held(&q->blk_trace_mutex));
        if (bt == NULL)
                return -EINVAL;
 
@@ -740,8 +743,8 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
 void blk_trace_shutdown(struct request_queue *q)
 {
        mutex_lock(&q->blk_trace_mutex);
-
-       if (q->blk_trace) {
+       if (rcu_dereference_protected(q->blk_trace,
+                                     lockdep_is_held(&q->blk_trace_mutex))) {
                __blk_trace_startstop(q, 0);
                __blk_trace_remove(q);
        }
@@ -752,8 +755,10 @@ void blk_trace_shutdown(struct request_queue *q)
 #ifdef CONFIG_BLK_CGROUP
 static u64 blk_trace_bio_get_cgid(struct request_queue *q, struct bio *bio)
 {
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
 
+       /* We don't use the 'bt' value here except as an optimization... */
+       bt = rcu_dereference_protected(q->blk_trace, 1);
        if (!bt || !(blk_tracer_flags.val & TRACE_BLK_OPT_CGROUP))
                return 0;
 
@@ -796,10 +801,14 @@ blk_trace_request_get_cgid(struct request_queue *q, struct request *rq)
 static void blk_add_trace_rq(struct request *rq, int error,
                             unsigned int nr_bytes, u32 what, u64 cgid)
 {
-       struct blk_trace *bt = rq->q->blk_trace;
+       struct blk_trace *bt;
 
-       if (likely(!bt))
+       rcu_read_lock();
+       bt = rcu_dereference(rq->q->blk_trace);
+       if (likely(!bt)) {
+               rcu_read_unlock();
                return;
+       }
 
        if (blk_rq_is_passthrough(rq))
                what |= BLK_TC_ACT(BLK_TC_PC);
@@ -808,6 +817,7 @@ static void blk_add_trace_rq(struct request *rq, int error,
 
        __blk_add_trace(bt, blk_rq_trace_sector(rq), nr_bytes, req_op(rq),
                        rq->cmd_flags, what, error, 0, NULL, cgid);
+       rcu_read_unlock();
 }
 
 static void blk_add_trace_rq_insert(void *ignore,
@@ -853,14 +863,19 @@ static void blk_add_trace_rq_complete(void *ignore, struct request *rq,
 static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
                              u32 what, int error)
 {
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
 
-       if (likely(!bt))
+       rcu_read_lock();
+       bt = rcu_dereference(q->blk_trace);
+       if (likely(!bt)) {
+               rcu_read_unlock();
                return;
+       }
 
        __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
                        bio_op(bio), bio->bi_opf, what, error, 0, NULL,
                        blk_trace_bio_get_cgid(q, bio));
+       rcu_read_unlock();
 }
 
 static void blk_add_trace_bio_bounce(void *ignore,
@@ -905,11 +920,14 @@ static void blk_add_trace_getrq(void *ignore,
        if (bio)
                blk_add_trace_bio(q, bio, BLK_TA_GETRQ, 0);
        else {
-               struct blk_trace *bt = q->blk_trace;
+               struct blk_trace *bt;
 
+               rcu_read_lock();
+               bt = rcu_dereference(q->blk_trace);
                if (bt)
                        __blk_add_trace(bt, 0, 0, rw, 0, BLK_TA_GETRQ, 0, 0,
                                        NULL, 0);
+               rcu_read_unlock();
        }
 }
 
@@ -921,27 +939,35 @@ static void blk_add_trace_sleeprq(void *ignore,
        if (bio)
                blk_add_trace_bio(q, bio, BLK_TA_SLEEPRQ, 0);
        else {
-               struct blk_trace *bt = q->blk_trace;
+               struct blk_trace *bt;
 
+               rcu_read_lock();
+               bt = rcu_dereference(q->blk_trace);
                if (bt)
                        __blk_add_trace(bt, 0, 0, rw, 0, BLK_TA_SLEEPRQ,
                                        0, 0, NULL, 0);
+               rcu_read_unlock();
        }
 }
 
 static void blk_add_trace_plug(void *ignore, struct request_queue *q)
 {
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
 
+       rcu_read_lock();
+       bt = rcu_dereference(q->blk_trace);
        if (bt)
                __blk_add_trace(bt, 0, 0, 0, 0, BLK_TA_PLUG, 0, 0, NULL, 0);
+       rcu_read_unlock();
 }
 
 static void blk_add_trace_unplug(void *ignore, struct request_queue *q,
                                    unsigned int depth, bool explicit)
 {
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
 
+       rcu_read_lock();
+       bt = rcu_dereference(q->blk_trace);
        if (bt) {
                __be64 rpdu = cpu_to_be64(depth);
                u32 what;
@@ -953,14 +979,17 @@ static void blk_add_trace_unplug(void *ignore, struct request_queue *q,
 
                __blk_add_trace(bt, 0, 0, 0, 0, what, 0, sizeof(rpdu), &rpdu, 0);
        }
+       rcu_read_unlock();
 }
 
 static void blk_add_trace_split(void *ignore,
                                struct request_queue *q, struct bio *bio,
                                unsigned int pdu)
 {
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
 
+       rcu_read_lock();
+       bt = rcu_dereference(q->blk_trace);
        if (bt) {
                __be64 rpdu = cpu_to_be64(pdu);
 
@@ -969,6 +998,7 @@ static void blk_add_trace_split(void *ignore,
                                BLK_TA_SPLIT, bio->bi_status, sizeof(rpdu),
                                &rpdu, blk_trace_bio_get_cgid(q, bio));
        }
+       rcu_read_unlock();
 }
 
 /**
@@ -988,11 +1018,15 @@ static void blk_add_trace_bio_remap(void *ignore,
                                    struct request_queue *q, struct bio *bio,
                                    dev_t dev, sector_t from)
 {
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
        struct blk_io_trace_remap r;
 
-       if (likely(!bt))
+       rcu_read_lock();
+       bt = rcu_dereference(q->blk_trace);
+       if (likely(!bt)) {
+               rcu_read_unlock();
                return;
+       }
 
        r.device_from = cpu_to_be32(dev);
        r.device_to   = cpu_to_be32(bio_dev(bio));
@@ -1001,6 +1035,7 @@ static void blk_add_trace_bio_remap(void *ignore,
        __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
                        bio_op(bio), bio->bi_opf, BLK_TA_REMAP, bio->bi_status,
                        sizeof(r), &r, blk_trace_bio_get_cgid(q, bio));
+       rcu_read_unlock();
 }
 
 /**
@@ -1021,11 +1056,15 @@ static void blk_add_trace_rq_remap(void *ignore,
                                   struct request *rq, dev_t dev,
                                   sector_t from)
 {
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
        struct blk_io_trace_remap r;
 
-       if (likely(!bt))
+       rcu_read_lock();
+       bt = rcu_dereference(q->blk_trace);
+       if (likely(!bt)) {
+               rcu_read_unlock();
                return;
+       }
 
        r.device_from = cpu_to_be32(dev);
        r.device_to   = cpu_to_be32(disk_devt(rq->rq_disk));
@@ -1034,6 +1073,7 @@ static void blk_add_trace_rq_remap(void *ignore,
        __blk_add_trace(bt, blk_rq_pos(rq), blk_rq_bytes(rq),
                        rq_data_dir(rq), 0, BLK_TA_REMAP, 0,
                        sizeof(r), &r, blk_trace_request_get_cgid(q, rq));
+       rcu_read_unlock();
 }
 
 /**
@@ -1051,14 +1091,19 @@ void blk_add_driver_data(struct request_queue *q,
                         struct request *rq,
                         void *data, size_t len)
 {
-       struct blk_trace *bt = q->blk_trace;
+       struct blk_trace *bt;
 
-       if (likely(!bt))
+       rcu_read_lock();
+       bt = rcu_dereference(q->blk_trace);
+       if (likely(!bt)) {
+               rcu_read_unlock();
                return;
+       }
 
        __blk_add_trace(bt, blk_rq_trace_sector(rq), blk_rq_bytes(rq), 0, 0,
                                BLK_TA_DRV_DATA, 0, len, data,
                                blk_trace_request_get_cgid(q, rq));
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL_GPL(blk_add_driver_data);
 
@@ -1597,6 +1642,7 @@ static int blk_trace_remove_queue(struct request_queue *q)
                return -EINVAL;
 
        put_probe_ref();
+       synchronize_rcu();
        blk_trace_free(bt);
        return 0;
 }
@@ -1758,6 +1804,7 @@ static ssize_t sysfs_blk_trace_attr_show(struct device *dev,
        struct hd_struct *p = dev_to_part(dev);
        struct request_queue *q;
        struct block_device *bdev;
+       struct blk_trace *bt;
        ssize_t ret = -ENXIO;
 
        bdev = bdget(part_devt(p));
@@ -1770,21 +1817,23 @@ static ssize_t sysfs_blk_trace_attr_show(struct device *dev,
 
        mutex_lock(&q->blk_trace_mutex);
 
+       bt = rcu_dereference_protected(q->blk_trace,
+                                      lockdep_is_held(&q->blk_trace_mutex));
        if (attr == &dev_attr_enable) {
-               ret = sprintf(buf, "%u\n", !!q->blk_trace);
+               ret = sprintf(buf, "%u\n", !!bt);
                goto out_unlock_bdev;
        }
 
-       if (q->blk_trace == NULL)
+       if (bt == NULL)
                ret = sprintf(buf, "disabled\n");
        else if (attr == &dev_attr_act_mask)
-               ret = blk_trace_mask2str(buf, q->blk_trace->act_mask);
+               ret = blk_trace_mask2str(buf, bt->act_mask);
        else if (attr == &dev_attr_pid)
-               ret = sprintf(buf, "%u\n", q->blk_trace->pid);
+               ret = sprintf(buf, "%u\n", bt->pid);
        else if (attr == &dev_attr_start_lba)
-               ret = sprintf(buf, "%llu\n", q->blk_trace->start_lba);
+               ret = sprintf(buf, "%llu\n", bt->start_lba);
        else if (attr == &dev_attr_end_lba)
-               ret = sprintf(buf, "%llu\n", q->blk_trace->end_lba);
+               ret = sprintf(buf, "%llu\n", bt->end_lba);
 
 out_unlock_bdev:
        mutex_unlock(&q->blk_trace_mutex);
@@ -1801,6 +1850,7 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
        struct block_device *bdev;
        struct request_queue *q;
        struct hd_struct *p;
+       struct blk_trace *bt;
        u64 value;
        ssize_t ret = -EINVAL;
 
@@ -1831,8 +1881,10 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
 
        mutex_lock(&q->blk_trace_mutex);
 
+       bt = rcu_dereference_protected(q->blk_trace,
+                                      lockdep_is_held(&q->blk_trace_mutex));
        if (attr == &dev_attr_enable) {
-               if (!!value == !!q->blk_trace) {
+               if (!!value == !!bt) {
                        ret = 0;
                        goto out_unlock_bdev;
                }
@@ -1844,18 +1896,21 @@ static ssize_t sysfs_blk_trace_attr_store(struct device *dev,
        }
 
        ret = 0;
-       if (q->blk_trace == NULL)
+       if (bt == NULL) {
                ret = blk_trace_setup_queue(q, bdev);
+               bt = rcu_dereference_protected(q->blk_trace,
+                               lockdep_is_held(&q->blk_trace_mutex));
+       }
 
        if (ret == 0) {
                if (attr == &dev_attr_act_mask)
-                       q->blk_trace->act_mask = value;
+                       bt->act_mask = value;
                else if (attr == &dev_attr_pid)
-                       q->blk_trace->pid = value;
+                       bt->pid = value;
                else if (attr == &dev_attr_start_lba)
-                       q->blk_trace->start_lba = value;
+                       bt->start_lba = value;
                else if (attr == &dev_attr_end_lba)
-                       q->blk_trace->end_lba = value;
+                       bt->end_lba = value;
        }
 
 out_unlock_bdev:
index 19e793a..68250d4 100644 (file)
@@ -732,7 +732,7 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type)
        if (unlikely(!nmi_uaccess_okay()))
                return -EPERM;
 
-       if (in_nmi()) {
+       if (irqs_disabled()) {
                /* Do an early check on signal validity. Otherwise,
                 * the error is lost in deferred irq_work.
                 */
index 3f7ee10..fd81c7d 100644 (file)
@@ -1547,6 +1547,8 @@ static struct dyn_ftrace *lookup_rec(unsigned long start, unsigned long end)
                rec = bsearch(&key, pg->records, pg->index,
                              sizeof(struct dyn_ftrace),
                              ftrace_cmp_recs);
+               if (rec)
+                       break;
        }
        return rec;
 }
index 4aefe00..7d56d62 100644 (file)
@@ -111,11 +111,11 @@ static int __init test_gen_synth_cmd(void)
        /* Create some bogus values just for testing */
 
        vals[0] = 777;                  /* next_pid_field */
-       vals[1] = (u64)"hula hoops";    /* next_comm_field */
+       vals[1] = (u64)(long)"hula hoops";      /* next_comm_field */
        vals[2] = 1000000;              /* ts_ns */
        vals[3] = 1000;                 /* ts_ms */
-       vals[4] = smp_processor_id();   /* cpu */
-       vals[5] = (u64)"thneed";        /* my_string_field */
+       vals[4] = raw_smp_processor_id(); /* cpu */
+       vals[5] = (u64)(long)"thneed";  /* my_string_field */
        vals[6] = 598;                  /* my_int_field */
 
        /* Now generate a gen_synth_test event */
@@ -218,11 +218,11 @@ static int __init test_empty_synth_event(void)
        /* Create some bogus values just for testing */
 
        vals[0] = 777;                  /* next_pid_field */
-       vals[1] = (u64)"tiddlywinks";   /* next_comm_field */
+       vals[1] = (u64)(long)"tiddlywinks";     /* next_comm_field */
        vals[2] = 1000000;              /* ts_ns */
        vals[3] = 1000;                 /* ts_ms */
-       vals[4] = smp_processor_id();   /* cpu */
-       vals[5] = (u64)"thneed_2.0";    /* my_string_field */
+       vals[4] = raw_smp_processor_id(); /* cpu */
+       vals[5] = (u64)(long)"thneed_2.0";      /* my_string_field */
        vals[6] = 399;                  /* my_int_field */
 
        /* Now trace an empty_synth_test event */
@@ -290,11 +290,11 @@ static int __init test_create_synth_event(void)
        /* Create some bogus values just for testing */
 
        vals[0] = 777;                  /* next_pid_field */
-       vals[1] = (u64)"tiddlywinks";   /* next_comm_field */
+       vals[1] = (u64)(long)"tiddlywinks";     /* next_comm_field */
        vals[2] = 1000000;              /* ts_ns */
        vals[3] = 1000;                 /* ts_ms */
-       vals[4] = smp_processor_id();   /* cpu */
-       vals[5] = (u64)"thneed";        /* my_string_field */
+       vals[4] = raw_smp_processor_id(); /* cpu */
+       vals[5] = (u64)(long)"thneed";  /* my_string_field */
        vals[6] = 398;                  /* my_int_field */
 
        /* Now generate a create_synth_test event */
@@ -330,7 +330,7 @@ static int __init test_add_next_synth_val(void)
                goto out;
 
        /* next_comm_field */
-       ret = synth_event_add_next_val((u64)"slinky", &trace_state);
+       ret = synth_event_add_next_val((u64)(long)"slinky", &trace_state);
        if (ret)
                goto out;
 
@@ -345,12 +345,12 @@ static int __init test_add_next_synth_val(void)
                goto out;
 
        /* cpu */
-       ret = synth_event_add_next_val(smp_processor_id(), &trace_state);
+       ret = synth_event_add_next_val(raw_smp_processor_id(), &trace_state);
        if (ret)
                goto out;
 
        /* my_string_field */
-       ret = synth_event_add_next_val((u64)"thneed_2.01", &trace_state);
+       ret = synth_event_add_next_val((u64)(long)"thneed_2.01", &trace_state);
        if (ret)
                goto out;
 
@@ -388,7 +388,7 @@ static int __init test_add_synth_val(void)
        if (ret)
                goto out;
 
-       ret = synth_event_add_val("cpu", smp_processor_id(), &trace_state);
+       ret = synth_event_add_val("cpu", raw_smp_processor_id(), &trace_state);
        if (ret)
                goto out;
 
@@ -396,12 +396,12 @@ static int __init test_add_synth_val(void)
        if (ret)
                goto out;
 
-       ret = synth_event_add_val("next_comm_field", (u64)"silly putty",
+       ret = synth_event_add_val("next_comm_field", (u64)(long)"silly putty",
                                  &trace_state);
        if (ret)
                goto out;
 
-       ret = synth_event_add_val("my_string_field", (u64)"thneed_9",
+       ret = synth_event_add_val("my_string_field", (u64)(long)"thneed_9",
                                  &trace_state);
        if (ret)
                goto out;
@@ -423,13 +423,13 @@ static int __init test_trace_synth_event(void)
 
        /* Trace some bogus values just for testing */
        ret = synth_event_trace(create_synth_test, 7,   /* number of values */
-                               444,                    /* next_pid_field */
-                               (u64)"clackers",        /* next_comm_field */
-                               1000000,                /* ts_ns */
-                               1000,                   /* ts_ms */
-                               smp_processor_id(),     /* cpu */
-                               (u64)"Thneed",          /* my_string_field */
-                               999);                   /* my_int_field */
+                               (u64)444,               /* next_pid_field */
+                               (u64)(long)"clackers",  /* next_comm_field */
+                               (u64)1000000,           /* ts_ns */
+                               (u64)1000,              /* ts_ms */
+                               (u64)raw_smp_processor_id(), /* cpu */
+                               (u64)(long)"Thneed",    /* my_string_field */
+                               (u64)999);              /* my_int_field */
        return ret;
 }
 
index c797a15..6b11e4e 100644 (file)
@@ -1837,6 +1837,7 @@ static __init int init_trace_selftests(void)
 
        pr_info("Running postponed tracer tests:\n");
 
+       tracing_selftest_running = true;
        list_for_each_entry_safe(p, n, &postponed_selftests, list) {
                /* This loop can take minutes when sanitizers are enabled, so
                 * lets make sure we allow RCU processing.
@@ -1859,6 +1860,7 @@ static __init int init_trace_selftests(void)
                list_del(&p->list);
                kfree(p);
        }
+       tracing_selftest_running = false;
 
  out:
        mutex_unlock(&trace_types_lock);
index 483b3fd..5f6834a 100644 (file)
@@ -821,6 +821,29 @@ static const char *synth_field_fmt(char *type)
        return fmt;
 }
 
+static void print_synth_event_num_val(struct trace_seq *s,
+                                     char *print_fmt, char *name,
+                                     int size, u64 val, char *space)
+{
+       switch (size) {
+       case 1:
+               trace_seq_printf(s, print_fmt, name, (u8)val, space);
+               break;
+
+       case 2:
+               trace_seq_printf(s, print_fmt, name, (u16)val, space);
+               break;
+
+       case 4:
+               trace_seq_printf(s, print_fmt, name, (u32)val, space);
+               break;
+
+       default:
+               trace_seq_printf(s, print_fmt, name, val, space);
+               break;
+       }
+}
+
 static enum print_line_t print_synth_event(struct trace_iterator *iter,
                                           int flags,
                                           struct trace_event *event)
@@ -859,10 +882,13 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter,
                } else {
                        struct trace_print_flags __flags[] = {
                            __def_gfpflag_names, {-1, NULL} };
+                       char *space = (i == se->n_fields - 1 ? "" : " ");
 
-                       trace_seq_printf(s, print_fmt, se->fields[i]->name,
-                                        entry->fields[n_u64],
-                                        i == se->n_fields - 1 ? "" : " ");
+                       print_synth_event_num_val(s, print_fmt,
+                                                 se->fields[i]->name,
+                                                 se->fields[i]->size,
+                                                 entry->fields[n_u64],
+                                                 space);
 
                        if (strcmp(se->fields[i]->type, "gfp_t") == 0) {
                                trace_seq_puts(s, " (");
@@ -1805,6 +1831,8 @@ __synth_event_trace_start(struct trace_event_file *file,
        int entry_size, fields_size = 0;
        int ret = 0;
 
+       memset(trace_state, '\0', sizeof(*trace_state));
+
        /*
         * Normal event tracing doesn't get called at all unless the
         * ENABLED bit is set (which attaches the probe thus allowing
@@ -1885,6 +1913,11 @@ int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...)
                return ret;
        }
 
+       if (n_vals != state.event->n_fields) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        va_start(args, n_vals);
        for (i = 0, n_u64 = 0; i < state.event->n_fields; i++) {
                u64 val;
@@ -1898,12 +1931,30 @@ int synth_event_trace(struct trace_event_file *file, unsigned int n_vals, ...)
                        strscpy(str_field, str_val, STR_VAR_LEN_MAX);
                        n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
                } else {
-                       state.entry->fields[n_u64] = val;
+                       struct synth_field *field = state.event->fields[i];
+
+                       switch (field->size) {
+                       case 1:
+                               *(u8 *)&state.entry->fields[n_u64] = (u8)val;
+                               break;
+
+                       case 2:
+                               *(u16 *)&state.entry->fields[n_u64] = (u16)val;
+                               break;
+
+                       case 4:
+                               *(u32 *)&state.entry->fields[n_u64] = (u32)val;
+                               break;
+
+                       default:
+                               state.entry->fields[n_u64] = val;
+                               break;
+                       }
                        n_u64++;
                }
        }
        va_end(args);
-
+out:
        __synth_event_trace_end(&state);
 
        return ret;
@@ -1942,6 +1993,11 @@ int synth_event_trace_array(struct trace_event_file *file, u64 *vals,
                return ret;
        }
 
+       if (n_vals != state.event->n_fields) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        for (i = 0, n_u64 = 0; i < state.event->n_fields; i++) {
                if (state.event->fields[i]->is_string) {
                        char *str_val = (char *)(long)vals[i];
@@ -1950,11 +2006,30 @@ int synth_event_trace_array(struct trace_event_file *file, u64 *vals,
                        strscpy(str_field, str_val, STR_VAR_LEN_MAX);
                        n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
                } else {
-                       state.entry->fields[n_u64] = vals[i];
+                       struct synth_field *field = state.event->fields[i];
+                       u64 val = vals[i];
+
+                       switch (field->size) {
+                       case 1:
+                               *(u8 *)&state.entry->fields[n_u64] = (u8)val;
+                               break;
+
+                       case 2:
+                               *(u16 *)&state.entry->fields[n_u64] = (u16)val;
+                               break;
+
+                       case 4:
+                               *(u32 *)&state.entry->fields[n_u64] = (u32)val;
+                               break;
+
+                       default:
+                               state.entry->fields[n_u64] = val;
+                               break;
+                       }
                        n_u64++;
                }
        }
-
+out:
        __synth_event_trace_end(&state);
 
        return ret;
@@ -1997,8 +2072,6 @@ int synth_event_trace_start(struct trace_event_file *file,
        if (!trace_state)
                return -EINVAL;
 
-       memset(trace_state, '\0', sizeof(*trace_state));
-
        ret = __synth_event_trace_start(file, trace_state);
        if (ret == -ENOENT)
                ret = 0; /* just disabled, not really an error */
@@ -2069,8 +2142,25 @@ static int __synth_event_add_val(const char *field_name, u64 val,
 
                str_field = (char *)&entry->fields[field->offset];
                strscpy(str_field, str_val, STR_VAR_LEN_MAX);
-       } else
-               entry->fields[field->offset] = val;
+       } else {
+               switch (field->size) {
+               case 1:
+                       *(u8 *)&trace_state->entry->fields[field->offset] = (u8)val;
+                       break;
+
+               case 2:
+                       *(u16 *)&trace_state->entry->fields[field->offset] = (u16)val;
+                       break;
+
+               case 4:
+                       *(u32 *)&trace_state->entry->fields[field->offset] = (u32)val;
+                       break;
+
+               default:
+                       trace_state->entry->fields[field->offset] = val;
+                       break;
+               }
+       }
  out:
        return ret;
 }
index 301db44..4e01c44 100644 (file)
@@ -1411,14 +1411,16 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
                return;
        rcu_read_lock();
 retry:
-       if (req_cpu == WORK_CPU_UNBOUND)
-               cpu = wq_select_unbound_cpu(raw_smp_processor_id());
-
        /* pwq which will be used unless @work is executing elsewhere */
-       if (!(wq->flags & WQ_UNBOUND))
-               pwq = per_cpu_ptr(wq->cpu_pwqs, cpu);
-       else
+       if (wq->flags & WQ_UNBOUND) {
+               if (req_cpu == WORK_CPU_UNBOUND)
+                       cpu = wq_select_unbound_cpu(raw_smp_processor_id());
                pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu));
+       } else {
+               if (req_cpu == WORK_CPU_UNBOUND)
+                       cpu = raw_smp_processor_id();
+               pwq = per_cpu_ptr(wq->cpu_pwqs, cpu);
+       }
 
        /*
         * If @work was previously on a different pool, it might still be
index 69def4a..5c31566 100644 (file)
@@ -1086,6 +1086,23 @@ config PROVE_LOCKING
 
         For more details, see Documentation/locking/lockdep-design.rst.
 
+config PROVE_RAW_LOCK_NESTING
+       bool "Enable raw_spinlock - spinlock nesting checks"
+       depends on PROVE_LOCKING
+       default n
+       help
+        Enable the raw_spinlock vs. spinlock nesting checks which ensure
+        that the lock nesting rules for PREEMPT_RT enabled kernels are
+        not violated.
+
+        NOTE: There are known nesting problems. So if you enable this
+        option expect lockdep splats until these problems have been fully
+        addressed which is work in progress. This config switch allows to
+        identify and analyze these problems. It will be removed and the
+        check permanentely enabled once the main issues have been fixed.
+
+        If unsure, select N.
+
 config LOCK_STAT
        bool "Lock usage statistics"
        depends on DEBUG_KERNEL && LOCK_DEBUGGING_SUPPORT
@@ -1769,6 +1786,16 @@ config TEST_LIST_SORT
 
          If unsure, say N.
 
+config TEST_MIN_HEAP
+       tristate "Min heap test"
+       depends on DEBUG_KERNEL || m
+       help
+         Enable this to turn on min heap function tests. This test is
+         executed only once during system boot (so affects only boot time),
+         or at module load time.
+
+         If unsure, say N.
+
 config TEST_SORT
        tristate "Array-based sort test"
        depends on DEBUG_KERNEL || m
index 611872c..09a8acb 100644 (file)
@@ -67,6 +67,7 @@ CFLAGS_test_ubsan.o += $(call cc-disable-warning, vla)
 UBSAN_SANITIZE_test_ubsan.o := y
 obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
 obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o
+obj-$(CONFIG_TEST_MIN_HEAP) += test_min_heap.o
 obj-$(CONFIG_TEST_LKM) += test_module.o
 obj-$(CONFIG_TEST_VMALLOC) += test_vmalloc.o
 obj-$(CONFIG_TEST_OVERFLOW) += test_overflow.o
index 3ea601a..ec3ce7f 100644 (file)
@@ -533,7 +533,7 @@ struct xbc_node *find_match_node(struct xbc_node *node, char *k)
 
 static int __init __xbc_add_key(char *k)
 {
-       struct xbc_node *node;
+       struct xbc_node *node, *child;
 
        if (!xbc_valid_keyword(k))
                return xbc_parse_error("Invalid keyword", k);
@@ -543,8 +543,12 @@ static int __init __xbc_add_key(char *k)
 
        if (!last_parent)       /* the first level */
                node = find_match_node(xbc_nodes, k);
-       else
-               node = find_match_node(xbc_node_get_child(last_parent), k);
+       else {
+               child = xbc_node_get_child(last_parent);
+               if (child && xbc_node_is_value(child))
+                       return xbc_parse_error("Subkey is mixed with value", k);
+               node = find_match_node(child, k);
+       }
 
        if (node)
                last_parent = node;
@@ -574,10 +578,10 @@ static int __init __xbc_parse_keys(char *k)
        return __xbc_add_key(k);
 }
 
-static int __init xbc_parse_kv(char **k, char *v)
+static int __init xbc_parse_kv(char **k, char *v, int op)
 {
        struct xbc_node *prev_parent = last_parent;
-       struct xbc_node *node;
+       struct xbc_node *child;
        char *next;
        int c, ret;
 
@@ -585,12 +589,19 @@ static int __init xbc_parse_kv(char **k, char *v)
        if (ret)
                return ret;
 
+       child = xbc_node_get_child(last_parent);
+       if (child) {
+               if (xbc_node_is_key(child))
+                       return xbc_parse_error("Value is mixed with subkey", v);
+               else if (op == '=')
+                       return xbc_parse_error("Value is redefined", v);
+       }
+
        c = __xbc_parse_value(&v, &next);
        if (c < 0)
                return c;
 
-       node = xbc_add_sibling(v, XBC_VALUE);
-       if (!node)
+       if (!xbc_add_sibling(v, XBC_VALUE))
                return -ENOMEM;
 
        if (c == ',') { /* Array */
@@ -763,7 +774,7 @@ int __init xbc_init(char *buf)
 
        p = buf;
        do {
-               q = strpbrk(p, "{}=;\n#");
+               q = strpbrk(p, "{}=+;\n#");
                if (!q) {
                        p = skip_spaces(p);
                        if (*p != '\0')
@@ -774,8 +785,15 @@ int __init xbc_init(char *buf)
                c = *q;
                *q++ = '\0';
                switch (c) {
+               case '+':
+                       if (*q++ != '=') {
+                               ret = xbc_parse_error("Wrong '+' operator",
+                                                       q - 2);
+                               break;
+                       }
+                       /* Fall through */
                case '=':
-                       ret = xbc_parse_kv(&p, q);
+                       ret = xbc_parse_kv(&p, q, c);
                        break;
                case '{':
                        ret = xbc_open_brace(&p, q);
index 0cb672e..fb22fb2 100644 (file)
@@ -232,3 +232,32 @@ unsigned int cpumask_local_spread(unsigned int i, int node)
        BUG();
 }
 EXPORT_SYMBOL(cpumask_local_spread);
+
+static DEFINE_PER_CPU(int, distribute_cpu_mask_prev);
+
+/**
+ * Returns an arbitrary cpu within srcp1 & srcp2.
+ *
+ * Iterated calls using the same srcp1 and srcp2 will be distributed within
+ * their intersection.
+ *
+ * Returns >= nr_cpu_ids if the intersection is empty.
+ */
+int cpumask_any_and_distribute(const struct cpumask *src1p,
+                              const struct cpumask *src2p)
+{
+       int next, prev;
+
+       /* NOTE: our first selection will skip 0. */
+       prev = __this_cpu_read(distribute_cpu_mask_prev);
+
+       next = cpumask_next_and(prev, src1p, src2p);
+       if (next >= nr_cpu_ids)
+               next = cpumask_first_and(src1p, src2p);
+
+       if (next < nr_cpu_ids)
+               __this_cpu_write(distribute_cpu_mask_prev, next);
+
+       return next;
+}
+EXPORT_SYMBOL(cpumask_any_and_distribute);
index c391a91..fa43ded 100644 (file)
@@ -9028,10 +9028,15 @@ bool __init chacha20poly1305_selftest(void)
             && total_len <= 1 << 10; ++total_len) {
                for (i = 0; i <= total_len; ++i) {
                        for (j = i; j <= total_len; ++j) {
+                               k = 0;
                                sg_init_table(sg_src, 3);
-                               sg_set_buf(&sg_src[0], input, i);
-                               sg_set_buf(&sg_src[1], input + i, j - i);
-                               sg_set_buf(&sg_src[2], input + j, total_len - j);
+                               if (i)
+                                       sg_set_buf(&sg_src[k++], input, i);
+                               if (j - i)
+                                       sg_set_buf(&sg_src[k++], input + i, j - i);
+                               if (total_len - j)
+                                       sg_set_buf(&sg_src[k++], input + j, total_len - j);
+                               sg_init_marker(sg_src, k);
                                memset(computed_output, 0, total_len);
                                memset(input, 0, total_len);
 
index 6d83caf..ad0699c 100644 (file)
@@ -235,6 +235,9 @@ bool chacha20poly1305_crypt_sg_inplace(struct scatterlist *src,
                __le64 lens[2];
        } b __aligned(16);
 
+       if (WARN_ON(src_len > INT_MAX))
+               return false;
+
        chacha_load_key(b.k, key);
 
        b.iv[0] = 0;
index 251213c..0c7fbcf 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/vmalloc.h>
+#include <linux/efi_embedded_fw.h>
 
 #define TEST_FIRMWARE_NAME     "test-firmware.bin"
 #define TEST_FIRMWARE_NUM_REQS 4
@@ -507,6 +508,57 @@ out:
 }
 static DEVICE_ATTR_WO(trigger_request);
 
+#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
+static ssize_t trigger_request_platform_store(struct device *dev,
+                                             struct device_attribute *attr,
+                                             const char *buf, size_t count)
+{
+       static const u8 test_data[] = {
+               0x55, 0xaa, 0x55, 0xaa, 0x01, 0x02, 0x03, 0x04,
+               0x55, 0xaa, 0x55, 0xaa, 0x05, 0x06, 0x07, 0x08,
+               0x55, 0xaa, 0x55, 0xaa, 0x10, 0x20, 0x30, 0x40,
+               0x55, 0xaa, 0x55, 0xaa, 0x50, 0x60, 0x70, 0x80
+       };
+       struct efi_embedded_fw efi_embedded_fw;
+       const struct firmware *firmware = NULL;
+       char *name;
+       int rc;
+
+       name = kstrndup(buf, count, GFP_KERNEL);
+       if (!name)
+               return -ENOSPC;
+
+       pr_info("inserting test platform fw '%s'\n", name);
+       efi_embedded_fw.name = name;
+       efi_embedded_fw.data = (void *)test_data;
+       efi_embedded_fw.length = sizeof(test_data);
+       list_add(&efi_embedded_fw.list, &efi_embedded_fw_list);
+
+       pr_info("loading '%s'\n", name);
+       rc = firmware_request_platform(&firmware, name, dev);
+       if (rc) {
+               pr_info("load of '%s' failed: %d\n", name, rc);
+               goto out;
+       }
+       if (firmware->size != sizeof(test_data) ||
+           memcmp(firmware->data, test_data, sizeof(test_data)) != 0) {
+               pr_info("firmware contents mismatch for '%s'\n", name);
+               rc = -EINVAL;
+               goto out;
+       }
+       pr_info("loaded: %zu\n", firmware->size);
+       rc = count;
+
+out:
+       release_firmware(firmware);
+       list_del(&efi_embedded_fw.list);
+       kfree(name);
+
+       return rc;
+}
+static DEVICE_ATTR_WO(trigger_request_platform);
+#endif
+
 static DECLARE_COMPLETION(async_fw_done);
 
 static void trigger_async_request_cb(const struct firmware *fw, void *context)
@@ -903,6 +955,9 @@ static struct attribute *test_dev_attrs[] = {
        TEST_FW_DEV_ATTR(trigger_request),
        TEST_FW_DEV_ATTR(trigger_async_request),
        TEST_FW_DEV_ATTR(trigger_custom_fallback),
+#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE
+       TEST_FW_DEV_ATTR(trigger_request_platform),
+#endif
 
        /* These use the config and can use the test_result */
        TEST_FW_DEV_ATTR(trigger_batched_requests),
diff --git a/lib/test_min_heap.c b/lib/test_min_heap.c
new file mode 100644 (file)
index 0000000..d19c808
--- /dev/null
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#define pr_fmt(fmt) "min_heap_test: " fmt
+
+/*
+ * Test cases for the min max heap.
+ */
+
+#include <linux/log2.h>
+#include <linux/min_heap.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/random.h>
+
+static __init bool less_than(const void *lhs, const void *rhs)
+{
+       return *(int *)lhs < *(int *)rhs;
+}
+
+static __init bool greater_than(const void *lhs, const void *rhs)
+{
+       return *(int *)lhs > *(int *)rhs;
+}
+
+static __init void swap_ints(void *lhs, void *rhs)
+{
+       int temp = *(int *)lhs;
+
+       *(int *)lhs = *(int *)rhs;
+       *(int *)rhs = temp;
+}
+
+static __init int pop_verify_heap(bool min_heap,
+                               struct min_heap *heap,
+                               const struct min_heap_callbacks *funcs)
+{
+       int *values = heap->data;
+       int err = 0;
+       int last;
+
+       last = values[0];
+       min_heap_pop(heap, funcs);
+       while (heap->nr > 0) {
+               if (min_heap) {
+                       if (last > values[0]) {
+                               pr_err("error: expected %d <= %d\n", last,
+                                       values[0]);
+                               err++;
+                       }
+               } else {
+                       if (last < values[0]) {
+                               pr_err("error: expected %d >= %d\n", last,
+                                       values[0]);
+                               err++;
+                       }
+               }
+               last = values[0];
+               min_heap_pop(heap, funcs);
+       }
+       return err;
+}
+
+static __init int test_heapify_all(bool min_heap)
+{
+       int values[] = { 3, 1, 2, 4, 0x8000000, 0x7FFFFFF, 0,
+                        -3, -1, -2, -4, 0x8000000, 0x7FFFFFF };
+       struct min_heap heap = {
+               .data = values,
+               .nr = ARRAY_SIZE(values),
+               .size =  ARRAY_SIZE(values),
+       };
+       struct min_heap_callbacks funcs = {
+               .elem_size = sizeof(int),
+               .less = min_heap ? less_than : greater_than,
+               .swp = swap_ints,
+       };
+       int i, err;
+
+       /* Test with known set of values. */
+       min_heapify_all(&heap, &funcs);
+       err = pop_verify_heap(min_heap, &heap, &funcs);
+
+
+       /* Test with randomly generated values. */
+       heap.nr = ARRAY_SIZE(values);
+       for (i = 0; i < heap.nr; i++)
+               values[i] = get_random_int();
+
+       min_heapify_all(&heap, &funcs);
+       err += pop_verify_heap(min_heap, &heap, &funcs);
+
+       return err;
+}
+
+static __init int test_heap_push(bool min_heap)
+{
+       const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0,
+                            -3, -1, -2, -4, 0x80000000, 0x7FFFFFFF };
+       int values[ARRAY_SIZE(data)];
+       struct min_heap heap = {
+               .data = values,
+               .nr = 0,
+               .size =  ARRAY_SIZE(values),
+       };
+       struct min_heap_callbacks funcs = {
+               .elem_size = sizeof(int),
+               .less = min_heap ? less_than : greater_than,
+               .swp = swap_ints,
+       };
+       int i, temp, err;
+
+       /* Test with known set of values copied from data. */
+       for (i = 0; i < ARRAY_SIZE(data); i++)
+               min_heap_push(&heap, &data[i], &funcs);
+
+       err = pop_verify_heap(min_heap, &heap, &funcs);
+
+       /* Test with randomly generated values. */
+       while (heap.nr < heap.size) {
+               temp = get_random_int();
+               min_heap_push(&heap, &temp, &funcs);
+       }
+       err += pop_verify_heap(min_heap, &heap, &funcs);
+
+       return err;
+}
+
+static __init int test_heap_pop_push(bool min_heap)
+{
+       const int data[] = { 3, 1, 2, 4, 0x80000000, 0x7FFFFFFF, 0,
+                            -3, -1, -2, -4, 0x80000000, 0x7FFFFFFF };
+       int values[ARRAY_SIZE(data)];
+       struct min_heap heap = {
+               .data = values,
+               .nr = 0,
+               .size =  ARRAY_SIZE(values),
+       };
+       struct min_heap_callbacks funcs = {
+               .elem_size = sizeof(int),
+               .less = min_heap ? less_than : greater_than,
+               .swp = swap_ints,
+       };
+       int i, temp, err;
+
+       /* Fill values with data to pop and replace. */
+       temp = min_heap ? 0x80000000 : 0x7FFFFFFF;
+       for (i = 0; i < ARRAY_SIZE(data); i++)
+               min_heap_push(&heap, &temp, &funcs);
+
+       /* Test with known set of values copied from data. */
+       for (i = 0; i < ARRAY_SIZE(data); i++)
+               min_heap_pop_push(&heap, &data[i], &funcs);
+
+       err = pop_verify_heap(min_heap, &heap, &funcs);
+
+       heap.nr = 0;
+       for (i = 0; i < ARRAY_SIZE(data); i++)
+               min_heap_push(&heap, &temp, &funcs);
+
+       /* Test with randomly generated values. */
+       for (i = 0; i < ARRAY_SIZE(data); i++) {
+               temp = get_random_int();
+               min_heap_pop_push(&heap, &temp, &funcs);
+       }
+       err += pop_verify_heap(min_heap, &heap, &funcs);
+
+       return err;
+}
+
+static int __init test_min_heap_init(void)
+{
+       int err = 0;
+
+       err += test_heapify_all(true);
+       err += test_heapify_all(false);
+       err += test_heap_push(true);
+       err += test_heap_push(false);
+       err += test_heap_pop_push(true);
+       err += test_heap_pop_push(false);
+       if (err) {
+               pr_err("test failed with %d errors\n", err);
+               return -EINVAL;
+       }
+       pr_info("test passed\n");
+       return 0;
+}
+module_init(test_min_heap_init);
+
+static void __exit test_min_heap_exit(void)
+{
+       /* do nothing */
+}
+module_exit(test_min_heap_exit);
+
+MODULE_LICENSE("GPL");
index f8b8ec5..a2909af 100644 (file)
@@ -2,30 +2,9 @@
 /*
  * Generic userspace implementations of gettimeofday() and similar.
  */
-#include <linux/compiler.h>
-#include <linux/math64.h>
-#include <linux/time.h>
-#include <linux/kernel.h>
-#include <linux/hrtimer_defs.h>
 #include <vdso/datapage.h>
 #include <vdso/helpers.h>
 
-/*
- * The generic vDSO implementation requires that gettimeofday.h
- * provides:
- * - __arch_get_vdso_data(): to get the vdso datapage.
- * - __arch_get_hw_counter(): to get the hw counter based on the
- *   clock_mode.
- * - gettimeofday_fallback(): fallback for gettimeofday.
- * - clock_gettime_fallback(): fallback for clock_gettime.
- * - clock_getres_fallback(): fallback for clock_getres.
- */
-#ifdef ENABLE_COMPAT_VDSO
-#include <asm/vdso/compat_gettimeofday.h>
-#else
-#include <asm/vdso/gettimeofday.h>
-#endif /* ENABLE_COMPAT_VDSO */
-
 #ifndef vdso_calc_delta
 /*
  * Default implementation which works for all sane clocksources. That
@@ -38,6 +17,27 @@ u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult)
 }
 #endif
 
+#ifndef vdso_shift_ns
+static __always_inline u64 vdso_shift_ns(u64 ns, u32 shift)
+{
+       return ns >> shift;
+}
+#endif
+
+#ifndef __arch_vdso_hres_capable
+static inline bool __arch_vdso_hres_capable(void)
+{
+       return true;
+}
+#endif
+
+#ifndef vdso_clocksource_ok
+static inline bool vdso_clocksource_ok(const struct vdso_data *vd)
+{
+       return vd->clock_mode != VDSO_CLOCKMODE_NONE;
+}
+#endif
+
 #ifdef CONFIG_TIME_NS
 static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
                          struct __kernel_timespec *ts)
@@ -57,14 +57,15 @@ static int do_hres_timens(const struct vdso_data *vdns, clockid_t clk,
 
        do {
                seq = vdso_read_begin(vd);
+
+               if (unlikely(!vdso_clocksource_ok(vd)))
+                       return -1;
+
                cycles = __arch_get_hw_counter(vd->clock_mode);
                ns = vdso_ts->nsec;
                last = vd->cycle_last;
-               if (unlikely((s64)cycles < 0))
-                       return -1;
-
                ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
-               ns >>= vd->shift;
+               ns = vdso_shift_ns(ns, vd->shift);
                sec = vdso_ts->sec;
        } while (unlikely(vdso_read_retry(vd, seq)));
 
@@ -101,12 +102,16 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk,
        u64 cycles, last, sec, ns;
        u32 seq;
 
+       /* Allows to compile the high resolution parts out */
+       if (!__arch_vdso_hres_capable())
+               return -1;
+
        do {
                /*
-                * Open coded to handle VCLOCK_TIMENS. Time namespace
+                * Open coded to handle VDSO_CLOCKMODE_TIMENS. Time namespace
                 * enabled tasks have a special VVAR page installed which
                 * has vd->seq set to 1 and vd->clock_mode set to
-                * VCLOCK_TIMENS. For non time namespace affected tasks
+                * VDSO_CLOCKMODE_TIMENS. For non time namespace affected tasks
                 * this does not affect performance because if vd->seq is
                 * odd, i.e. a concurrent update is in progress the extra
                 * check for vd->clock_mode is just a few extra
@@ -115,20 +120,20 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk,
                 */
                while (unlikely((seq = READ_ONCE(vd->seq)) & 1)) {
                        if (IS_ENABLED(CONFIG_TIME_NS) &&
-                           vd->clock_mode == VCLOCK_TIMENS)
+                           vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
                                return do_hres_timens(vd, clk, ts);
                        cpu_relax();
                }
                smp_rmb();
 
+               if (unlikely(!vdso_clocksource_ok(vd)))
+                       return -1;
+
                cycles = __arch_get_hw_counter(vd->clock_mode);
                ns = vdso_ts->nsec;
                last = vd->cycle_last;
-               if (unlikely((s64)cycles < 0))
-                       return -1;
-
                ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
-               ns >>= vd->shift;
+               ns = vdso_shift_ns(ns, vd->shift);
                sec = vdso_ts->sec;
        } while (unlikely(vdso_read_retry(vd, seq)));
 
@@ -187,12 +192,12 @@ static __always_inline int do_coarse(const struct vdso_data *vd, clockid_t clk,
 
        do {
                /*
-                * Open coded to handle VCLOCK_TIMENS. See comment in
+                * Open coded to handle VDSO_CLOCK_TIMENS. See comment in
                 * do_hres().
                 */
                while ((seq = READ_ONCE(vd->seq)) & 1) {
                        if (IS_ENABLED(CONFIG_TIME_NS) &&
-                           vd->clock_mode == VCLOCK_TIMENS)
+                           vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
                                return do_coarse_timens(vd, clk, ts);
                        cpu_relax();
                }
@@ -206,9 +211,9 @@ static __always_inline int do_coarse(const struct vdso_data *vd, clockid_t clk,
 }
 
 static __maybe_unused int
-__cvdso_clock_gettime_common(clockid_t clock, struct __kernel_timespec *ts)
+__cvdso_clock_gettime_common(const struct vdso_data *vd, clockid_t clock,
+                            struct __kernel_timespec *ts)
 {
-       const struct vdso_data *vd = __arch_get_vdso_data();
        u32 msk;
 
        /* Check for negative values or invalid clocks */
@@ -233,23 +238,31 @@ __cvdso_clock_gettime_common(clockid_t clock, struct __kernel_timespec *ts)
 }
 
 static __maybe_unused int
-__cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
+__cvdso_clock_gettime_data(const struct vdso_data *vd, clockid_t clock,
+                          struct __kernel_timespec *ts)
 {
-       int ret = __cvdso_clock_gettime_common(clock, ts);
+       int ret = __cvdso_clock_gettime_common(vd, clock, ts);
 
        if (unlikely(ret))
                return clock_gettime_fallback(clock, ts);
        return 0;
 }
 
+static __maybe_unused int
+__cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts)
+{
+       return __cvdso_clock_gettime_data(__arch_get_vdso_data(), clock, ts);
+}
+
 #ifdef BUILD_VDSO32
 static __maybe_unused int
-__cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res)
+__cvdso_clock_gettime32_data(const struct vdso_data *vd, clockid_t clock,
+                            struct old_timespec32 *res)
 {
        struct __kernel_timespec ts;
        int ret;
 
-       ret = __cvdso_clock_gettime_common(clock, &ts);
+       ret = __cvdso_clock_gettime_common(vd, clock, &ts);
 
        if (unlikely(ret))
                return clock_gettime32_fallback(clock, res);
@@ -260,12 +273,18 @@ __cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res)
 
        return ret;
 }
+
+static __maybe_unused int
+__cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res)
+{
+       return __cvdso_clock_gettime32_data(__arch_get_vdso_data(), clock, res);
+}
 #endif /* BUILD_VDSO32 */
 
 static __maybe_unused int
-__cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
+__cvdso_gettimeofday_data(const struct vdso_data *vd,
+                         struct __kernel_old_timeval *tv, struct timezone *tz)
 {
-       const struct vdso_data *vd = __arch_get_vdso_data();
 
        if (likely(tv != NULL)) {
                struct __kernel_timespec ts;
@@ -279,7 +298,7 @@ __cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
 
        if (unlikely(tz != NULL)) {
                if (IS_ENABLED(CONFIG_TIME_NS) &&
-                   vd->clock_mode == VCLOCK_TIMENS)
+                   vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
                        vd = __arch_get_timens_vdso_data();
 
                tz->tz_minuteswest = vd[CS_HRES_COARSE].tz_minuteswest;
@@ -289,13 +308,20 @@ __cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
        return 0;
 }
 
+static __maybe_unused int
+__cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz)
+{
+       return __cvdso_gettimeofday_data(__arch_get_vdso_data(), tv, tz);
+}
+
 #ifdef VDSO_HAS_TIME
-static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time)
+static __maybe_unused __kernel_old_time_t
+__cvdso_time_data(const struct vdso_data *vd, __kernel_old_time_t *time)
 {
-       const struct vdso_data *vd = __arch_get_vdso_data();
        __kernel_old_time_t t;
 
-       if (IS_ENABLED(CONFIG_TIME_NS) && vd->clock_mode == VCLOCK_TIMENS)
+       if (IS_ENABLED(CONFIG_TIME_NS) &&
+           vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
                vd = __arch_get_timens_vdso_data();
 
        t = READ_ONCE(vd[CS_HRES_COARSE].basetime[CLOCK_REALTIME].sec);
@@ -305,13 +331,18 @@ static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time
 
        return t;
 }
+
+static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time)
+{
+       return __cvdso_time_data(__arch_get_vdso_data(), time);
+}
 #endif /* VDSO_HAS_TIME */
 
 #ifdef VDSO_HAS_CLOCK_GETRES
 static __maybe_unused
-int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res)
+int __cvdso_clock_getres_common(const struct vdso_data *vd, clockid_t clock,
+                               struct __kernel_timespec *res)
 {
-       const struct vdso_data *vd = __arch_get_vdso_data();
        u32 msk;
        u64 ns;
 
@@ -319,7 +350,8 @@ int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res)
        if (unlikely((u32) clock >= MAX_CLOCKS))
                return -1;
 
-       if (IS_ENABLED(CONFIG_TIME_NS) && vd->clock_mode == VCLOCK_TIMENS)
+       if (IS_ENABLED(CONFIG_TIME_NS) &&
+           vd->clock_mode == VDSO_CLOCKMODE_TIMENS)
                vd = __arch_get_timens_vdso_data();
 
        /*
@@ -349,23 +381,31 @@ int __cvdso_clock_getres_common(clockid_t clock, struct __kernel_timespec *res)
 }
 
 static __maybe_unused
-int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res)
+int __cvdso_clock_getres_data(const struct vdso_data *vd, clockid_t clock,
+                             struct __kernel_timespec *res)
 {
-       int ret = __cvdso_clock_getres_common(clock, res);
+       int ret = __cvdso_clock_getres_common(vd, clock, res);
 
        if (unlikely(ret))
                return clock_getres_fallback(clock, res);
        return 0;
 }
 
+static __maybe_unused
+int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res)
+{
+       return __cvdso_clock_getres_data(__arch_get_vdso_data(), clock, res);
+}
+
 #ifdef BUILD_VDSO32
 static __maybe_unused int
-__cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res)
+__cvdso_clock_getres_time32_data(const struct vdso_data *vd, clockid_t clock,
+                                struct old_timespec32 *res)
 {
        struct __kernel_timespec ts;
        int ret;
 
-       ret = __cvdso_clock_getres_common(clock, &ts);
+       ret = __cvdso_clock_getres_common(vd, clock, &ts);
 
        if (unlikely(ret))
                return clock_getres32_fallback(clock, res);
@@ -376,5 +416,12 @@ __cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res)
        }
        return ret;
 }
+
+static __maybe_unused int
+__cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res)
+{
+       return __cvdso_clock_getres_time32_data(__arch_get_vdso_data(),
+                                               clock, res);
+}
 #endif /* BUILD_VDSO32 */
 #endif /* VDSO_HAS_CLOCK_GETRES */
index b08b199..24ad53b 100644 (file)
@@ -3043,8 +3043,7 @@ void set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
                return;
 
        flush_cache_range(vma, address, address + HPAGE_PMD_SIZE);
-       pmdval = *pvmw->pmd;
-       pmdp_invalidate(vma, address, pvmw->pmd);
+       pmdval = pmdp_invalidate(vma, address, pvmw->pmd);
        if (pmd_dirty(pmdval))
                set_page_dirty(page);
        entry = make_migration_entry(page, pmd_write(pmdval));
index e434b05..5280bcf 100644 (file)
@@ -240,8 +240,7 @@ again:
        if (!page_counter_try_charge(&h_cg->hugepage[idx], nr_pages,
                                     &counter)) {
                ret = -ENOMEM;
-               hugetlb_event(hugetlb_cgroup_from_counter(counter, idx), idx,
-                             HUGETLB_MAX);
+               hugetlb_event(h_cg, idx, HUGETLB_MAX);
        }
        css_put(&h_cg->css);
 done:
index 43b47d3..4bb30ed 100644 (file)
@@ -335,12 +335,14 @@ static int madvise_cold_or_pageout_pte_range(pmd_t *pmd,
                }
 
                page = pmd_page(orig_pmd);
+
+               /* Do not interfere with other mappings of this page */
+               if (page_mapcount(page) != 1)
+                       goto huge_unlock;
+
                if (next - addr != HPAGE_PMD_SIZE) {
                        int err;
 
-                       if (page_mapcount(page) != 1)
-                               goto huge_unlock;
-
                        get_page(page);
                        spin_unlock(ptl);
                        lock_page(page);
@@ -426,6 +428,10 @@ regular_page:
                        continue;
                }
 
+               /* Do not interfere with other mappings of this page */
+               if (page_mapcount(page) != 1)
+                       continue;
+
                VM_BUG_ON_PAGE(PageTransCompound(page), page);
 
                if (pte_young(ptent)) {
index d09776c..7ddf91c 100644 (file)
@@ -777,6 +777,17 @@ void __mod_lruvec_slab_state(void *p, enum node_stat_item idx, int val)
        rcu_read_unlock();
 }
 
+void mod_memcg_obj_state(void *p, int idx, int val)
+{
+       struct mem_cgroup *memcg;
+
+       rcu_read_lock();
+       memcg = mem_cgroup_from_obj(p);
+       if (memcg)
+               mod_memcg_state(memcg, idx, val);
+       rcu_read_unlock();
+}
+
 /**
  * __count_memcg_events - account VM events in a cgroup
  * @memcg: the memory cgroup
@@ -2297,28 +2308,41 @@ static void high_work_func(struct work_struct *work)
  #define MEMCG_DELAY_SCALING_SHIFT 14
 
 /*
- * Scheduled by try_charge() to be executed from the userland return path
- * and reclaims memory over the high limit.
+ * Get the number of jiffies that we should penalise a mischievous cgroup which
+ * is exceeding its memory.high by checking both it and its ancestors.
  */
-void mem_cgroup_handle_over_high(void)
+static unsigned long calculate_high_delay(struct mem_cgroup *memcg,
+                                         unsigned int nr_pages)
 {
-       unsigned long usage, high, clamped_high;
-       unsigned long pflags;
-       unsigned long penalty_jiffies, overage;
-       unsigned int nr_pages = current->memcg_nr_pages_over_high;
-       struct mem_cgroup *memcg;
+       unsigned long penalty_jiffies;
+       u64 max_overage = 0;
 
-       if (likely(!nr_pages))
-               return;
+       do {
+               unsigned long usage, high;
+               u64 overage;
 
-       memcg = get_mem_cgroup_from_mm(current->mm);
-       reclaim_high(memcg, nr_pages, GFP_KERNEL);
-       current->memcg_nr_pages_over_high = 0;
+               usage = page_counter_read(&memcg->memory);
+               high = READ_ONCE(memcg->high);
+
+               /*
+                * Prevent division by 0 in overage calculation by acting as if
+                * it was a threshold of 1 page
+                */
+               high = max(high, 1UL);
+
+               overage = usage - high;
+               overage <<= MEMCG_DELAY_PRECISION_SHIFT;
+               overage = div64_u64(overage, high);
+
+               if (overage > max_overage)
+                       max_overage = overage;
+       } while ((memcg = parent_mem_cgroup(memcg)) &&
+                !mem_cgroup_is_root(memcg));
+
+       if (!max_overage)
+               return 0;
 
        /*
-        * memory.high is breached and reclaim is unable to keep up. Throttle
-        * allocators proactively to slow down excessive growth.
-        *
         * We use overage compared to memory.high to calculate the number of
         * jiffies to sleep (penalty_jiffies). Ideally this value should be
         * fairly lenient on small overages, and increasingly harsh when the
@@ -2326,24 +2350,9 @@ void mem_cgroup_handle_over_high(void)
         * its crazy behaviour, so we exponentially increase the delay based on
         * overage amount.
         */
-
-       usage = page_counter_read(&memcg->memory);
-       high = READ_ONCE(memcg->high);
-
-       if (usage <= high)
-               goto out;
-
-       /*
-        * Prevent division by 0 in overage calculation by acting as if it was a
-        * threshold of 1 page
-        */
-       clamped_high = max(high, 1UL);
-
-       overage = div_u64((u64)(usage - high) << MEMCG_DELAY_PRECISION_SHIFT,
-                         clamped_high);
-
-       penalty_jiffies = ((u64)overage * overage * HZ)
-               >> (MEMCG_DELAY_PRECISION_SHIFT + MEMCG_DELAY_SCALING_SHIFT);
+       penalty_jiffies = max_overage * max_overage * HZ;
+       penalty_jiffies >>= MEMCG_DELAY_PRECISION_SHIFT;
+       penalty_jiffies >>= MEMCG_DELAY_SCALING_SHIFT;
 
        /*
         * Factor in the task's own contribution to the overage, such that four
@@ -2360,7 +2369,32 @@ void mem_cgroup_handle_over_high(void)
         * application moving forwards and also permit diagnostics, albeit
         * extremely slowly.
         */
-       penalty_jiffies = min(penalty_jiffies, MEMCG_MAX_HIGH_DELAY_JIFFIES);
+       return min(penalty_jiffies, MEMCG_MAX_HIGH_DELAY_JIFFIES);
+}
+
+/*
+ * Scheduled by try_charge() to be executed from the userland return path
+ * and reclaims memory over the high limit.
+ */
+void mem_cgroup_handle_over_high(void)
+{
+       unsigned long penalty_jiffies;
+       unsigned long pflags;
+       unsigned int nr_pages = current->memcg_nr_pages_over_high;
+       struct mem_cgroup *memcg;
+
+       if (likely(!nr_pages))
+               return;
+
+       memcg = get_mem_cgroup_from_mm(current->mm);
+       reclaim_high(memcg, nr_pages, GFP_KERNEL);
+       current->memcg_nr_pages_over_high = 0;
+
+       /*
+        * memory.high is breached and reclaim is unable to keep up. Throttle
+        * allocators proactively to slow down excessive growth.
+        */
+       penalty_jiffies = calculate_high_delay(memcg, nr_pages);
 
        /*
         * Don't sleep if the amount of jiffies this memcg owes us is so low
@@ -2638,6 +2672,33 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg,
 }
 
 #ifdef CONFIG_MEMCG_KMEM
+/*
+ * Returns a pointer to the memory cgroup to which the kernel object is charged.
+ *
+ * The caller must ensure the memcg lifetime, e.g. by taking rcu_read_lock(),
+ * cgroup_mutex, etc.
+ */
+struct mem_cgroup *mem_cgroup_from_obj(void *p)
+{
+       struct page *page;
+
+       if (mem_cgroup_disabled())
+               return NULL;
+
+       page = virt_to_head_page(p);
+
+       /*
+        * Slab pages don't have page->mem_cgroup set because corresponding
+        * kmem caches can be reparented during the lifetime. That's why
+        * memcg_from_slab_page() should be used instead.
+        */
+       if (PageSlab(page))
+               return memcg_from_slab_page(page);
+
+       /* All other pages use page->mem_cgroup */
+       return page->mem_cgroup;
+}
+
 static int memcg_alloc_cache_id(void)
 {
        int id, size;
@@ -4027,7 +4088,7 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg,
        struct mem_cgroup_thresholds *thresholds;
        struct mem_cgroup_threshold_ary *new;
        unsigned long usage;
-       int i, j, size;
+       int i, j, size, entries;
 
        mutex_lock(&memcg->thresholds_lock);
 
@@ -4047,14 +4108,20 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg,
        __mem_cgroup_threshold(memcg, type == _MEMSWAP);
 
        /* Calculate new number of threshold */
-       size = 0;
+       size = entries = 0;
        for (i = 0; i < thresholds->primary->size; i++) {
                if (thresholds->primary->entries[i].eventfd != eventfd)
                        size++;
+               else
+                       entries++;
        }
 
        new = thresholds->spare;
 
+       /* If no items related to eventfd have been cleared, nothing to do */
+       if (!entries)
+               goto unlock;
+
        /* Set thresholds array to NULL if we don't have thresholds */
        if (!size) {
                kfree(new);
@@ -6682,19 +6749,9 @@ void mem_cgroup_sk_alloc(struct sock *sk)
        if (!mem_cgroup_sockets_enabled)
                return;
 
-       /*
-        * Socket cloning can throw us here with sk_memcg already
-        * filled. It won't however, necessarily happen from
-        * process context. So the test for root memcg given
-        * the current task's memcg won't help us in this case.
-        *
-        * Respecting the original socket's memcg is a better
-        * decision in this case.
-        */
-       if (sk->sk_memcg) {
-               css_get(&sk->sk_memcg->css);
+       /* Do not associate the sock with unrelated interrupted task's memcg. */
+       if (in_interrupt())
                return;
-       }
 
        rcu_read_lock();
        memcg = mem_cgroup_from_task(current);
index 0bccc62..e8bfdf0 100644 (file)
@@ -2257,7 +2257,7 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
        bool ret;
        void *kaddr;
        void __user *uaddr;
-       bool force_mkyoung;
+       bool locked = false;
        struct vm_area_struct *vma = vmf->vma;
        struct mm_struct *mm = vma->vm_mm;
        unsigned long addr = vmf->address;
@@ -2282,11 +2282,11 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
         * On architectures with software "accessed" bits, we would
         * take a double page fault, so mark it accessed here.
         */
-       force_mkyoung = arch_faults_on_old_pte() && !pte_young(vmf->orig_pte);
-       if (force_mkyoung) {
+       if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) {
                pte_t entry;
 
                vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl);
+               locked = true;
                if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) {
                        /*
                         * Other thread has already handled the fault
@@ -2310,18 +2310,37 @@ static inline bool cow_user_page(struct page *dst, struct page *src,
         * zeroes.
         */
        if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
+               if (locked)
+                       goto warn;
+
+               /* Re-validate under PTL if the page is still mapped */
+               vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl);
+               locked = true;
+               if (!likely(pte_same(*vmf->pte, vmf->orig_pte))) {
+                       /* The PTE changed under us. Retry page fault. */
+                       ret = false;
+                       goto pte_unlock;
+               }
+
                /*
-                * Give a warn in case there can be some obscure
-                * use-case
+                * The same page can be mapped back since last copy attampt.
+                * Try to copy again under PTL.
                 */
-               WARN_ON_ONCE(1);
-               clear_page(kaddr);
+               if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE)) {
+                       /*
+                        * Give a warn in case there can be some obscure
+                        * use-case
+                        */
+warn:
+                       WARN_ON_ONCE(1);
+                       clear_page(kaddr);
+               }
        }
 
        ret = true;
 
 pte_unlock:
-       if (force_mkyoung)
+       if (locked)
                pte_unmap_unlock(vmf->pte, vmf->ptl);
        kunmap_atomic(kaddr);
        flush_dcache_page(dst);
index 0a54ffa..19389cd 100644 (file)
@@ -574,7 +574,13 @@ EXPORT_SYMBOL_GPL(restore_online_page_callback);
 
 void generic_online_page(struct page *page, unsigned int order)
 {
-       kernel_map_pages(page, 1 << order, 1);
+       /*
+        * Freeing the page with debug_pagealloc enabled will try to unmap it,
+        * so we should map it first. This is better than introducing a special
+        * case in page freeing fast path.
+        */
+       if (debug_pagealloc_enabled_static())
+               kernel_map_pages(page, 1 << order, 1);
        __free_pages_core(page, order);
        totalram_pages_add(1UL << order);
 #ifdef CONFIG_HIGHMEM
index ef3973a..06852b8 100644 (file)
@@ -307,7 +307,8 @@ static void mn_hlist_release(struct mmu_notifier_subscriptions *subscriptions,
         * ->release returns.
         */
        id = srcu_read_lock(&srcu);
-       hlist_for_each_entry_rcu(subscription, &subscriptions->list, hlist)
+       hlist_for_each_entry_rcu(subscription, &subscriptions->list, hlist,
+                                srcu_read_lock_held(&srcu))
                /*
                 * If ->release runs before mmu_notifier_unregister it must be
                 * handled, as it's the only way for the driver to flush all
@@ -370,7 +371,8 @@ int __mmu_notifier_clear_flush_young(struct mm_struct *mm,
 
        id = srcu_read_lock(&srcu);
        hlist_for_each_entry_rcu(subscription,
-                                &mm->notifier_subscriptions->list, hlist) {
+                                &mm->notifier_subscriptions->list, hlist,
+                                srcu_read_lock_held(&srcu)) {
                if (subscription->ops->clear_flush_young)
                        young |= subscription->ops->clear_flush_young(
                                subscription, mm, start, end);
@@ -389,7 +391,8 @@ int __mmu_notifier_clear_young(struct mm_struct *mm,
 
        id = srcu_read_lock(&srcu);
        hlist_for_each_entry_rcu(subscription,
-                                &mm->notifier_subscriptions->list, hlist) {
+                                &mm->notifier_subscriptions->list, hlist,
+                                srcu_read_lock_held(&srcu)) {
                if (subscription->ops->clear_young)
                        young |= subscription->ops->clear_young(subscription,
                                                                mm, start, end);
@@ -407,7 +410,8 @@ int __mmu_notifier_test_young(struct mm_struct *mm,
 
        id = srcu_read_lock(&srcu);
        hlist_for_each_entry_rcu(subscription,
-                                &mm->notifier_subscriptions->list, hlist) {
+                                &mm->notifier_subscriptions->list, hlist,
+                                srcu_read_lock_held(&srcu)) {
                if (subscription->ops->test_young) {
                        young = subscription->ops->test_young(subscription, mm,
                                                              address);
@@ -428,7 +432,8 @@ void __mmu_notifier_change_pte(struct mm_struct *mm, unsigned long address,
 
        id = srcu_read_lock(&srcu);
        hlist_for_each_entry_rcu(subscription,
-                                &mm->notifier_subscriptions->list, hlist) {
+                                &mm->notifier_subscriptions->list, hlist,
+                                srcu_read_lock_held(&srcu)) {
                if (subscription->ops->change_pte)
                        subscription->ops->change_pte(subscription, mm, address,
                                                      pte);
@@ -476,7 +481,8 @@ static int mn_hlist_invalidate_range_start(
        int id;
 
        id = srcu_read_lock(&srcu);
-       hlist_for_each_entry_rcu(subscription, &subscriptions->list, hlist) {
+       hlist_for_each_entry_rcu(subscription, &subscriptions->list, hlist,
+                                srcu_read_lock_held(&srcu)) {
                const struct mmu_notifier_ops *ops = subscription->ops;
 
                if (ops->invalidate_range_start) {
@@ -528,7 +534,8 @@ mn_hlist_invalidate_end(struct mmu_notifier_subscriptions *subscriptions,
        int id;
 
        id = srcu_read_lock(&srcu);
-       hlist_for_each_entry_rcu(subscription, &subscriptions->list, hlist) {
+       hlist_for_each_entry_rcu(subscription, &subscriptions->list, hlist,
+                                srcu_read_lock_held(&srcu)) {
                /*
                 * Call invalidate_range here too to avoid the need for the
                 * subsystem of having to register an invalidate_range_end
@@ -582,7 +589,8 @@ void __mmu_notifier_invalidate_range(struct mm_struct *mm,
 
        id = srcu_read_lock(&srcu);
        hlist_for_each_entry_rcu(subscription,
-                                &mm->notifier_subscriptions->list, hlist) {
+                                &mm->notifier_subscriptions->list, hlist,
+                                srcu_read_lock_held(&srcu)) {
                if (subscription->ops->invalidate_range)
                        subscription->ops->invalidate_range(subscription, mm,
                                                            start, end);
@@ -714,7 +722,8 @@ find_get_mmu_notifier(struct mm_struct *mm, const struct mmu_notifier_ops *ops)
 
        spin_lock(&mm->notifier_subscriptions->lock);
        hlist_for_each_entry_rcu(subscription,
-                                &mm->notifier_subscriptions->list, hlist) {
+                                &mm->notifier_subscriptions->list, hlist,
+                                lockdep_is_held(&mm->notifier_subscriptions->lock)) {
                if (subscription->ops != ops)
                        continue;
 
index 7a8e84f..311c0da 100644 (file)
@@ -161,6 +161,31 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
        return pages;
 }
 
+/*
+ * Used when setting automatic NUMA hinting protection where it is
+ * critical that a numa hinting PMD is not confused with a bad PMD.
+ */
+static inline int pmd_none_or_clear_bad_unless_trans_huge(pmd_t *pmd)
+{
+       pmd_t pmdval = pmd_read_atomic(pmd);
+
+       /* See pmd_none_or_trans_huge_or_clear_bad for info on barrier */
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+       barrier();
+#endif
+
+       if (pmd_none(pmdval))
+               return 1;
+       if (pmd_trans_huge(pmdval))
+               return 0;
+       if (unlikely(pmd_bad(pmdval))) {
+               pmd_clear_bad(pmd);
+               return 1;
+       }
+
+       return 0;
+}
+
 static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
                pud_t *pud, unsigned long addr, unsigned long end,
                pgprot_t newprot, int dirty_accountable, int prot_numa)
@@ -178,8 +203,17 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
                unsigned long this_pages;
 
                next = pmd_addr_end(addr, end);
-               if (!is_swap_pmd(*pmd) && !pmd_trans_huge(*pmd) && !pmd_devmap(*pmd)
-                               && pmd_none_or_clear_bad(pmd))
+
+               /*
+                * Automatic NUMA balancing walks the tables with mmap_sem
+                * held for read. It's possible a parallel update to occur
+                * between pmd_trans_huge() and a pmd_none_or_clear_bad()
+                * check leading to a false positive and clearing.
+                * Hence, it's necessary to atomically read the PMD value
+                * for all the checks.
+                */
+               if (!is_swap_pmd(*pmd) && !pmd_devmap(*pmd) &&
+                    pmd_none_or_clear_bad_unless_trans_huge(pmd))
                        goto next;
 
                /* invoke the mmu notifier if the pmd is populated */
index af36306..d28f08a 100644 (file)
@@ -606,6 +606,16 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len,
        LIST_HEAD(uf_unmap_early);
        LIST_HEAD(uf_unmap);
 
+       /*
+        * There is a deliberate asymmetry here: we strip the pointer tag
+        * from the old address but leave the new address alone. This is
+        * for consistency with mmap(), where we prevent the creation of
+        * aliasing mappings in userspace by leaving the tag bits of the
+        * mapping address intact. A non-zero tag will cause the subsequent
+        * range checks to reject the address as invalid.
+        *
+        * See Documentation/arm64/tagged-address-abi.rst for more information.
+        */
        addr = untagged_addr(addr);
 
        if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
index bd2b4e5..318df4e 100644 (file)
@@ -370,10 +370,14 @@ void vm_unmap_aliases(void)
 EXPORT_SYMBOL_GPL(vm_unmap_aliases);
 
 /*
- * Implement a stub for vmalloc_sync_all() if the architecture chose not to
- * have one.
+ * Implement a stub for vmalloc_sync_[un]mapping() if the architecture
+ * chose not to have one.
  */
-void __weak vmalloc_sync_all(void)
+void __weak vmalloc_sync_mappings(void)
+{
+}
+
+void __weak vmalloc_sync_unmappings(void)
 {
 }
 
index c8f7540..aad3ba7 100644 (file)
@@ -3386,8 +3386,6 @@ static const struct constant_table shmem_param_enums_huge[] = {
        {"always",      SHMEM_HUGE_ALWAYS },
        {"within_size", SHMEM_HUGE_WITHIN_SIZE },
        {"advise",      SHMEM_HUGE_ADVISE },
-       {"deny",        SHMEM_HUGE_DENY },
-       {"force",       SHMEM_HUGE_FORCE },
        {}
 };
 
index 17dc00e..6589b41 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1973,8 +1973,6 @@ static void *get_partial(struct kmem_cache *s, gfp_t flags, int node,
 
        if (node == NUMA_NO_NODE)
                searchnode = numa_mem_id();
-       else if (!node_present_pages(node))
-               searchnode = node_to_mem_node(node);
 
        object = get_partial_node(s, get_node(s, searchnode), c, flags);
        if (object || node != NUMA_NO_NODE)
@@ -2563,17 +2561,27 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
        struct page *page;
 
        page = c->page;
-       if (!page)
+       if (!page) {
+               /*
+                * if the node is not online or has no normal memory, just
+                * ignore the node constraint
+                */
+               if (unlikely(node != NUMA_NO_NODE &&
+                            !node_state(node, N_NORMAL_MEMORY)))
+                       node = NUMA_NO_NODE;
                goto new_slab;
+       }
 redo:
 
        if (unlikely(!node_match(page, node))) {
-               int searchnode = node;
-
-               if (node != NUMA_NO_NODE && !node_present_pages(node))
-                       searchnode = node_to_mem_node(node);
-
-               if (unlikely(!node_match(page, searchnode))) {
+               /*
+                * same as above but node_match() being false already
+                * implies node != NUMA_NO_NODE
+                */
+               if (!node_state(node, N_NORMAL_MEMORY)) {
+                       node = NUMA_NO_NODE;
+                       goto redo;
+               } else {
                        stat(s, ALLOC_NODE_MISMATCH);
                        deactivate_slab(s, page, c->freelist, c);
                        goto new_slab;
@@ -2997,11 +3005,13 @@ redo:
        barrier();
 
        if (likely(page == c->page)) {
-               set_freepointer(s, tail_obj, c->freelist);
+               void **freelist = READ_ONCE(c->freelist);
+
+               set_freepointer(s, tail_obj, freelist);
 
                if (unlikely(!this_cpu_cmpxchg_double(
                                s->cpu_slab->freelist, s->cpu_slab->tid,
-                               c->freelist, tid,
+                               freelist, tid,
                                head, next_tid(tid)))) {
 
                        note_cmpxchg_failure("slab_free", s, tid);
@@ -3175,6 +3185,15 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
 
                if (unlikely(!object)) {
                        /*
+                        * We may have removed an object from c->freelist using
+                        * the fastpath in the previous iteration; in that case,
+                        * c->tid has not been bumped yet.
+                        * Since ___slab_alloc() may reenable interrupts while
+                        * allocating memory, we should bump c->tid now.
+                        */
+                       c->tid = next_tid(c->tid);
+
+                       /*
                         * Invoking slow path likely have side-effect
                         * of re-populating per CPU c->freelist
                         */
index 596b2a4..65599e8 100644 (file)
@@ -734,6 +734,7 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
        struct mem_section *ms = __pfn_to_section(pfn);
        bool section_is_early = early_section(ms);
        struct page *memmap = NULL;
+       bool empty;
        unsigned long *subsection_map = ms->usage
                ? &ms->usage->subsection_map[0] : NULL;
 
@@ -764,7 +765,8 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
         * For 2/ and 3/ the SPARSEMEM_VMEMMAP={y,n} cases are unified
         */
        bitmap_xor(subsection_map, map, subsection_map, SUBSECTIONS_PER_SECTION);
-       if (bitmap_empty(subsection_map, SUBSECTIONS_PER_SECTION)) {
+       empty = bitmap_empty(subsection_map, SUBSECTIONS_PER_SECTION);
+       if (empty) {
                unsigned long section_nr = pfn_to_section_nr(pfn);
 
                /*
@@ -779,13 +781,21 @@ static void section_deactivate(unsigned long pfn, unsigned long nr_pages,
                        ms->usage = NULL;
                }
                memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
-               ms->section_mem_map = (unsigned long)NULL;
+               /*
+                * Mark the section invalid so that valid_section()
+                * return false. This prevents code from dereferencing
+                * ms->usage array.
+                */
+               ms->section_mem_map &= ~SECTION_HAS_MEM_MAP;
        }
 
        if (section_is_early && memmap)
                free_map_bootmem(memmap);
        else
                depopulate_section_memmap(pfn, nr_pages, altmap);
+
+       if (empty)
+               ms->section_mem_map = (unsigned long)NULL;
 }
 
 static struct page * __meminit section_activate(int nid, unsigned long pfn,
index b2a2e45..be33e61 100644 (file)
@@ -2899,10 +2899,6 @@ static int claim_swapfile(struct swap_info_struct *p, struct inode *inode)
                p->bdev = inode->i_sb->s_bdev;
        }
 
-       inode_lock(inode);
-       if (IS_SWAPFILE(inode))
-               return -EBUSY;
-
        return 0;
 }
 
@@ -3157,36 +3153,41 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        mapping = swap_file->f_mapping;
        inode = mapping->host;
 
-       /* will take i_rwsem; */
        error = claim_swapfile(p, inode);
        if (unlikely(error))
                goto bad_swap;
 
+       inode_lock(inode);
+       if (IS_SWAPFILE(inode)) {
+               error = -EBUSY;
+               goto bad_swap_unlock_inode;
+       }
+
        /*
         * Read the swap header.
         */
        if (!mapping->a_ops->readpage) {
                error = -EINVAL;
-               goto bad_swap;
+               goto bad_swap_unlock_inode;
        }
        page = read_mapping_page(mapping, 0, swap_file);
        if (IS_ERR(page)) {
                error = PTR_ERR(page);
-               goto bad_swap;
+               goto bad_swap_unlock_inode;
        }
        swap_header = kmap(page);
 
        maxpages = read_swap_header(p, swap_header, inode);
        if (unlikely(!maxpages)) {
                error = -EINVAL;
-               goto bad_swap;
+               goto bad_swap_unlock_inode;
        }
 
        /* OK, set up the swap map and apply the bad block list */
        swap_map = vzalloc(maxpages);
        if (!swap_map) {
                error = -ENOMEM;
-               goto bad_swap;
+               goto bad_swap_unlock_inode;
        }
 
        if (bdi_cap_stable_pages_required(inode_to_bdi(inode)))
@@ -3211,7 +3212,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
                                        GFP_KERNEL);
                if (!cluster_info) {
                        error = -ENOMEM;
-                       goto bad_swap;
+                       goto bad_swap_unlock_inode;
                }
 
                for (ci = 0; ci < nr_cluster; ci++)
@@ -3220,7 +3221,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
                p->percpu_cluster = alloc_percpu(struct percpu_cluster);
                if (!p->percpu_cluster) {
                        error = -ENOMEM;
-                       goto bad_swap;
+                       goto bad_swap_unlock_inode;
                }
                for_each_possible_cpu(cpu) {
                        struct percpu_cluster *cluster;
@@ -3234,13 +3235,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
 
        error = swap_cgroup_swapon(p->type, maxpages);
        if (error)
-               goto bad_swap;
+               goto bad_swap_unlock_inode;
 
        nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map,
                cluster_info, maxpages, &span);
        if (unlikely(nr_extents < 0)) {
                error = nr_extents;
-               goto bad_swap;
+               goto bad_swap_unlock_inode;
        }
        /* frontswap enabled? set up bit-per-page map for frontswap */
        if (IS_ENABLED(CONFIG_FRONTSWAP))
@@ -3280,7 +3281,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
 
        error = init_swap_address_space(p->type, maxpages);
        if (error)
-               goto bad_swap;
+               goto bad_swap_unlock_inode;
 
        /*
         * Flush any pending IO and dirty mappings before we start using this
@@ -3290,7 +3291,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        error = inode_drain_writes(inode);
        if (error) {
                inode->i_flags &= ~S_SWAPFILE;
-               goto bad_swap;
+               goto bad_swap_unlock_inode;
        }
 
        mutex_lock(&swapon_mutex);
@@ -3315,6 +3316,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
 
        error = 0;
        goto out;
+bad_swap_unlock_inode:
+       inode_unlock(inode);
 bad_swap:
        free_percpu(p->percpu_cluster);
        p->percpu_cluster = NULL;
@@ -3322,6 +3325,7 @@ bad_swap:
                set_blocksize(p->bdev, p->old_block_size);
                blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
        }
+       inode = NULL;
        destroy_swap_extents(p);
        swap_cgroup_swapoff(p->type);
        spin_lock(&swap_lock);
@@ -3333,13 +3337,8 @@ bad_swap:
        kvfree(frontswap_map);
        if (inced_nr_rotate_swap)
                atomic_dec(&nr_rotate_swap);
-       if (swap_file) {
-               if (inode) {
-                       inode_unlock(inode);
-                       inode = NULL;
-               }
+       if (swap_file)
                filp_close(swap_file, NULL);
-       }
 out:
        if (page && !IS_ERR(page)) {
                kunmap(page);
index 1f46c3b..6b8eeb0 100644 (file)
@@ -1295,7 +1295,7 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
         * First make sure the mappings are removed from all page-tables
         * before they are freed.
         */
-       vmalloc_sync_all();
+       vmalloc_sync_unmappings();
 
        /*
         * TODO: to calculate a flush range without looping.
@@ -3128,16 +3128,19 @@ int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
 EXPORT_SYMBOL(remap_vmalloc_range);
 
 /*
- * Implement a stub for vmalloc_sync_all() if the architecture chose not to
- * have one.
+ * Implement stubs for vmalloc_sync_[un]mappings () if the architecture chose
+ * not to have one.
  *
  * The purpose of this function is to make sure the vmalloc area
  * mappings are identical in all page-tables in the system.
  */
-void __weak vmalloc_sync_all(void)
+void __weak vmalloc_sync_mappings(void)
 {
 }
 
+void __weak vmalloc_sync_unmappings(void)
+{
+}
 
 static int f(pte_t *pte, unsigned long addr, void *data)
 {
index 43754d8..42f31c4 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-#include <linux/rwlock.h>
 #include <linux/zpool.h>
 #include <linux/magic.h>
 
index 2eeb0e5..df8d8c9 100644 (file)
@@ -52,6 +52,9 @@ config NET_INGRESS
 config NET_EGRESS
        bool
 
+config NET_REDIRECT
+       bool
+
 config SKB_EXTENSIONS
        bool
 
index f020950..a7c8dd7 100644 (file)
@@ -789,6 +789,10 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
 
        lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
 
+       /* interface already disabled by batadv_iv_ogm_iface_disable */
+       if (!*ogm_buff)
+               return;
+
        /* the interface gets activated here to avoid race conditions between
         * the moment of activating the interface in
         * hardif_activate_interface() where the originator mac is set and
index 77396a0..efea487 100644 (file)
@@ -10,7 +10,7 @@
 #include <asm/unistd.h>
 #include "msgfmt.h"
 
-int debug_fd;
+FILE *debug_f;
 
 static int handle_get_cmd(struct mbox_request *cmd)
 {
@@ -35,9 +35,10 @@ static void loop(void)
                struct mbox_reply reply;
                int n;
 
+               fprintf(debug_f, "testing the buffer\n");
                n = read(0, &req, sizeof(req));
                if (n != sizeof(req)) {
-                       dprintf(debug_fd, "invalid request %d\n", n);
+                       fprintf(debug_f, "invalid request %d\n", n);
                        return;
                }
 
@@ -47,7 +48,7 @@ static void loop(void)
 
                n = write(1, &reply, sizeof(reply));
                if (n != sizeof(reply)) {
-                       dprintf(debug_fd, "reply failed %d\n", n);
+                       fprintf(debug_f, "reply failed %d\n", n);
                        return;
                }
        }
@@ -55,9 +56,10 @@ static void loop(void)
 
 int main(void)
 {
-       debug_fd = open("/dev/kmsg", 00000002);
-       dprintf(debug_fd, "Started bpfilter\n");
+       debug_f = fopen("/dev/kmsg", "w");
+       setvbuf(debug_f, 0, _IOLBF, 0);
+       fprintf(debug_f, "Started bpfilter\n");
        loop();
-       close(debug_fd);
+       fclose(debug_f);
        return 0;
 }
index dc3d2c1..0e3dbc5 100644 (file)
@@ -34,7 +34,6 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        const struct nf_br_ops *nf_ops;
        u8 state = BR_STATE_FORWARDING;
        const unsigned char *dest;
-       struct ethhdr *eth;
        u16 vid = 0;
 
        rcu_read_lock();
@@ -54,15 +53,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        BR_INPUT_SKB_CB(skb)->frag_max_size = 0;
 
        skb_reset_mac_header(skb);
-       eth = eth_hdr(skb);
        skb_pull(skb, ETH_HLEN);
 
        if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid, &state))
                goto out;
 
        if (IS_ENABLED(CONFIG_INET) &&
-           (eth->h_proto == htons(ETH_P_ARP) ||
-            eth->h_proto == htons(ETH_P_RARP)) &&
+           (eth_hdr(skb)->h_proto == htons(ETH_P_ARP) ||
+            eth_hdr(skb)->h_proto == htons(ETH_P_RARP)) &&
            br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) {
                br_do_proxy_suppress_arp(skb, br, vid, NULL);
        } else if (IS_ENABLED(CONFIG_IPV6) &&
index 03c7cdd..195d2d6 100644 (file)
@@ -112,7 +112,8 @@ static struct caif_device_entry *caif_get(struct net_device *dev)
            caif_device_list(dev_net(dev));
        struct caif_device_entry *caifd;
 
-       list_for_each_entry_rcu(caifd, &caifdevs->list, list) {
+       list_for_each_entry_rcu(caifd, &caifdevs->list, list,
+                               lockdep_rtnl_is_held()) {
                if (caifd->netdev == dev)
                        return caifd;
        }
index 5b4bd82..f8ca5ed 100644 (file)
@@ -3248,12 +3248,16 @@ static struct ceph_msg_data *ceph_msg_data_add(struct ceph_msg *msg)
 
 static void ceph_msg_data_destroy(struct ceph_msg_data *data)
 {
-       if (data->type == CEPH_MSG_DATA_PAGELIST)
+       if (data->type == CEPH_MSG_DATA_PAGES && data->own_pages) {
+               int num_pages = calc_pages_for(data->alignment, data->length);
+               ceph_release_page_vector(data->pages, num_pages);
+       } else if (data->type == CEPH_MSG_DATA_PAGELIST) {
                ceph_pagelist_release(data->pagelist);
+       }
 }
 
 void ceph_msg_data_add_pages(struct ceph_msg *msg, struct page **pages,
-               size_t length, size_t alignment)
+                            size_t length, size_t alignment, bool own_pages)
 {
        struct ceph_msg_data *data;
 
@@ -3265,6 +3269,7 @@ void ceph_msg_data_add_pages(struct ceph_msg *msg, struct page **pages,
        data->pages = pages;
        data->length = length;
        data->alignment = alignment & ~PAGE_MASK;
+       data->own_pages = own_pages;
 
        msg->data_length += length;
 }
index b68b376..af868d3 100644 (file)
@@ -962,7 +962,7 @@ static void ceph_osdc_msg_data_add(struct ceph_msg *msg,
                BUG_ON(length > (u64) SIZE_MAX);
                if (length)
                        ceph_msg_data_add_pages(msg, osd_data->pages,
-                                       length, osd_data->alignment);
+                                       length, osd_data->alignment, false);
        } else if (osd_data->type == CEPH_OSD_DATA_TYPE_PAGELIST) {
                BUG_ON(!length);
                ceph_msg_data_add_pagelist(msg, osd_data->pagelist);
@@ -4436,9 +4436,7 @@ static void handle_watch_notify(struct ceph_osd_client *osdc,
                                                        CEPH_MSG_DATA_PAGES);
                                        *lreq->preply_pages = data->pages;
                                        *lreq->preply_len = data->length;
-                               } else {
-                                       ceph_release_page_vector(data->pages,
-                                              calc_pages_for(0, data->length));
+                                       data->own_pages = false;
                                }
                        }
                        lreq->notify_finish_error = return_code;
@@ -5506,9 +5504,6 @@ out_unlock_osdc:
        return m;
 }
 
-/*
- * TODO: switch to a msg-owned pagelist
- */
 static struct ceph_msg *alloc_msg_with_page_vector(struct ceph_msg_header *hdr)
 {
        struct ceph_msg *m;
@@ -5522,7 +5517,6 @@ static struct ceph_msg *alloc_msg_with_page_vector(struct ceph_msg_header *hdr)
 
        if (data_len) {
                struct page **pages;
-               struct ceph_osd_data osd_data;
 
                pages = ceph_alloc_page_vector(calc_pages_for(0, data_len),
                                               GFP_NOIO);
@@ -5531,9 +5525,7 @@ static struct ceph_msg *alloc_msg_with_page_vector(struct ceph_msg_header *hdr)
                        return NULL;
                }
 
-               ceph_osd_data_pages_init(&osd_data, pages, data_len, 0, false,
-                                        false);
-               ceph_osdc_msg_data_add(m, &osd_data);
+               ceph_msg_data_add_pages(m, pages, data_len, 0, true);
        }
 
        return m;
index 4e0de14..2a6e63a 100644 (file)
@@ -710,6 +710,15 @@ int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name)
 }
 EXPORT_SYMBOL(ceph_pg_poolid_by_name);
 
+u64 ceph_pg_pool_flags(struct ceph_osdmap *map, u64 id)
+{
+       struct ceph_pg_pool_info *pi;
+
+       pi = __lookup_pg_pool(&map->pg_pools, id);
+       return pi ? pi->flags : 0;
+}
+EXPORT_SYMBOL(ceph_pg_pool_flags);
+
 static void __remove_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *pi)
 {
        rb_erase(&pi->node, root);
index 47d99c7..4bed96e 100644 (file)
 #include <linux/uaccess.h>
 #include <net/compat.h>
 
-int get_compat_msghdr(struct msghdr *kmsg,
-                     struct compat_msghdr __user *umsg,
-                     struct sockaddr __user **save_addr,
-                     struct iovec **iov)
+int __get_compat_msghdr(struct msghdr *kmsg,
+                       struct compat_msghdr __user *umsg,
+                       struct sockaddr __user **save_addr,
+                       compat_uptr_t *ptr, compat_size_t *len)
 {
        struct compat_msghdr msg;
        ssize_t err;
@@ -79,10 +79,26 @@ int get_compat_msghdr(struct msghdr *kmsg,
                return -EMSGSIZE;
 
        kmsg->msg_iocb = NULL;
+       *ptr = msg.msg_iov;
+       *len = msg.msg_iovlen;
+       return 0;
+}
+
+int get_compat_msghdr(struct msghdr *kmsg,
+                     struct compat_msghdr __user *umsg,
+                     struct sockaddr __user **save_addr,
+                     struct iovec **iov)
+{
+       compat_uptr_t ptr;
+       compat_size_t len;
+       ssize_t err;
+
+       err = __get_compat_msghdr(kmsg, umsg, save_addr, &ptr, &len);
+       if (err)
+               return err;
 
-       err = compat_import_iovec(save_addr ? READ : WRITE,
-                                  compat_ptr(msg.msg_iov), msg.msg_iovlen,
-                                  UIO_FASTIOV, iov, &kmsg->msg_iter);
+       err = compat_import_iovec(save_addr ? READ : WRITE, compat_ptr(ptr),
+                                  len, UIO_FASTIOV, iov, &kmsg->msg_iter);
        return err < 0 ? err : 0;
 }
 
index e10bd68..500bba8 100644 (file)
@@ -3076,6 +3076,8 @@ static u16 skb_tx_hash(const struct net_device *dev,
 
        if (skb_rx_queue_recorded(skb)) {
                hash = skb_get_rx_queue(skb);
+               if (hash >= qoffset)
+                       hash -= qoffset;
                while (unlikely(hash >= qcount))
                        hash -= qcount;
                return hash + qoffset;
@@ -4514,7 +4516,7 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
        /* Reinjected packets coming from act_mirred or similar should
         * not get XDP generic processing.
         */
-       if (skb_is_tc_redirected(skb))
+       if (skb_is_redirected(skb))
                return XDP_PASS;
 
        /* XDP packets must be linear and must have sufficient headroom
@@ -5061,7 +5063,7 @@ skip_taps:
                        goto out;
        }
 #endif
-       skb_reset_tc(skb);
+       skb_reset_redirect(skb);
 skip_classify:
        if (pfmemalloc && !skb_pfmemalloc_protocol(skb))
                goto drop;
@@ -5193,7 +5195,7 @@ static int __netif_receive_skb_one_core(struct sk_buff *skb, bool pfmemalloc)
  *
  *     More direct receive version of netif_receive_skb().  It should
  *     only be used by callers that have a need to skip RPS and Generic XDP.
- *     Caller must also take care of handling if (page_is_)pfmemalloc.
+ *     Caller must also take care of handling if ``(page_is_)pfmemalloc``.
  *
  *     This function may only be called from softirq context and interrupts
  *     should be enabled.
index 549ee56..b831c55 100644 (file)
@@ -2103,11 +2103,11 @@ err_action_values_put:
 
 static struct devlink_dpipe_table *
 devlink_dpipe_table_find(struct list_head *dpipe_tables,
-                        const char *table_name)
+                        const char *table_name, struct devlink *devlink)
 {
        struct devlink_dpipe_table *table;
-
-       list_for_each_entry_rcu(table, dpipe_tables, list) {
+       list_for_each_entry_rcu(table, dpipe_tables, list,
+                               lockdep_is_held(&devlink->lock)) {
                if (!strcmp(table->name, table_name))
                        return table;
        }
@@ -2226,7 +2226,7 @@ static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
 
        table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        if (!table)
                return -EINVAL;
 
@@ -2382,7 +2382,7 @@ static int devlink_dpipe_table_counters_set(struct devlink *devlink,
        struct devlink_dpipe_table *table;
 
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        if (!table)
                return -EINVAL;
 
@@ -3352,34 +3352,41 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
                                  struct genl_info *info,
                                  union devlink_param_value *value)
 {
+       struct nlattr *param_data;
        int len;
 
-       if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
-           !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
+       param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
+
+       if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
                return -EINVAL;
 
        switch (param->type) {
        case DEVLINK_PARAM_TYPE_U8:
-               value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
+               if (nla_len(param_data) != sizeof(u8))
+                       return -EINVAL;
+               value->vu8 = nla_get_u8(param_data);
                break;
        case DEVLINK_PARAM_TYPE_U16:
-               value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
+               if (nla_len(param_data) != sizeof(u16))
+                       return -EINVAL;
+               value->vu16 = nla_get_u16(param_data);
                break;
        case DEVLINK_PARAM_TYPE_U32:
-               value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
+               if (nla_len(param_data) != sizeof(u32))
+                       return -EINVAL;
+               value->vu32 = nla_get_u32(param_data);
                break;
        case DEVLINK_PARAM_TYPE_STRING:
-               len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
-                             nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
-               if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
+               len = strnlen(nla_data(param_data), nla_len(param_data));
+               if (len == nla_len(param_data) ||
                    len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
                        return -EINVAL;
-               strcpy(value->vstr,
-                      nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
+               strcpy(value->vstr, nla_data(param_data));
                break;
        case DEVLINK_PARAM_TYPE_BOOL:
-               value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
-                              true : false;
+               if (param_data && nla_len(param_data))
+                       return -EINVAL;
+               value->vbool = nla_get_flag(param_data);
                break;
        }
        return 0;
@@ -5951,6 +5958,8 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
        [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
        [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
        [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
+       [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
+       [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
        [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
        [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
        [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
@@ -6854,7 +6863,7 @@ bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
 
        rcu_read_lock();
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        enabled = false;
        if (table)
                enabled = table->counters_enabled;
@@ -6878,26 +6887,34 @@ int devlink_dpipe_table_register(struct devlink *devlink,
                                 void *priv, bool counter_control_extern)
 {
        struct devlink_dpipe_table *table;
-
-       if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
-               return -EEXIST;
+       int err = 0;
 
        if (WARN_ON(!table_ops->size_get))
                return -EINVAL;
 
+       mutex_lock(&devlink->lock);
+
+       if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
+                                    devlink)) {
+               err = -EEXIST;
+               goto unlock;
+       }
+
        table = kzalloc(sizeof(*table), GFP_KERNEL);
-       if (!table)
-               return -ENOMEM;
+       if (!table) {
+               err = -ENOMEM;
+               goto unlock;
+       }
 
        table->name = table_name;
        table->table_ops = table_ops;
        table->priv = priv;
        table->counter_control_extern = counter_control_extern;
 
-       mutex_lock(&devlink->lock);
        list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
+unlock:
        mutex_unlock(&devlink->lock);
-       return 0;
+       return err;
 }
 EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
 
@@ -6914,7 +6931,7 @@ void devlink_dpipe_table_unregister(struct devlink *devlink,
 
        mutex_lock(&devlink->lock);
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        if (!table)
                goto unlock;
        list_del_rcu(&table->list);
@@ -7071,7 +7088,7 @@ int devlink_dpipe_table_resource_set(struct devlink *devlink,
 
        mutex_lock(&devlink->lock);
        table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
-                                        table_name);
+                                        table_name, devlink);
        if (!table) {
                err = -EINVAL;
                goto out;
index 0642f91..b4c87fe 100644 (file)
@@ -53,30 +53,60 @@ static void cgrp_css_free(struct cgroup_subsys_state *css)
        kfree(css_cls_state(css));
 }
 
+/*
+ * To avoid freezing of sockets creation for tasks with big number of threads
+ * and opened sockets lets release file_lock every 1000 iterated descriptors.
+ * New sockets will already have been created with new classid.
+ */
+
+struct update_classid_context {
+       u32 classid;
+       unsigned int batch;
+};
+
+#define UPDATE_CLASSID_BATCH 1000
+
 static int update_classid_sock(const void *v, struct file *file, unsigned n)
 {
        int err;
+       struct update_classid_context *ctx = (void *)v;
        struct socket *sock = sock_from_file(file, &err);
 
        if (sock) {
                spin_lock(&cgroup_sk_update_lock);
-               sock_cgroup_set_classid(&sock->sk->sk_cgrp_data,
-                                       (unsigned long)v);
+               sock_cgroup_set_classid(&sock->sk->sk_cgrp_data, ctx->classid);
                spin_unlock(&cgroup_sk_update_lock);
        }
+       if (--ctx->batch == 0) {
+               ctx->batch = UPDATE_CLASSID_BATCH;
+               return n + 1;
+       }
        return 0;
 }
 
+static void update_classid_task(struct task_struct *p, u32 classid)
+{
+       struct update_classid_context ctx = {
+               .classid = classid,
+               .batch = UPDATE_CLASSID_BATCH
+       };
+       unsigned int fd = 0;
+
+       do {
+               task_lock(p);
+               fd = iterate_fd(p->files, fd, update_classid_sock, &ctx);
+               task_unlock(p);
+               cond_resched();
+       } while (fd);
+}
+
 static void cgrp_attach(struct cgroup_taskset *tset)
 {
        struct cgroup_subsys_state *css;
        struct task_struct *p;
 
        cgroup_taskset_for_each(p, css, tset) {
-               task_lock(p);
-               iterate_fd(p->files, 0, update_classid_sock,
-                          (void *)(unsigned long)css_cls_state(css)->classid);
-               task_unlock(p);
+               update_classid_task(p, css_cls_state(css)->classid);
        }
 }
 
@@ -98,10 +128,7 @@ static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
 
        css_task_iter_start(css, 0, &it);
        while ((p = css_task_iter_next(&it))) {
-               task_lock(p);
-               iterate_fd(p->files, 0, update_classid_sock,
-                          (void *)(unsigned long)cs->classid);
-               task_unlock(p);
+               update_classid_task(p, cs->classid);
                cond_resched();
        }
        css_task_iter_end(&it);
index acc849d..d0641bb 100644 (file)
@@ -3362,7 +3362,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
                        /* skb was 'freed' by stack, so clean few
                         * bits and reuse it
                         */
-                       skb_reset_tc(skb);
+                       skb_reset_redirect(skb);
                } while (--burst > 0);
                goto out; /* Skips xmit_mode M_START_XMIT */
        } else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) {
index a4c8fac..8f71684 100644 (file)
@@ -1830,7 +1830,10 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
                atomic_set(&newsk->sk_zckey, 0);
 
                sock_reset_flag(newsk, SOCK_DONE);
-               mem_cgroup_sk_alloc(newsk);
+
+               /* sk->sk_memcg will be populated at accept() time */
+               newsk->sk_memcg = NULL;
+
                cgroup_sk_alloc(&newsk->sk_cgrp_data);
 
                rcu_read_lock();
index 085cef5..b70c844 100644 (file)
@@ -233,8 +233,11 @@ static void sock_map_free(struct bpf_map *map)
        struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
        int i;
 
+       /* After the sync no updates or deletes will be in-flight so it
+        * is safe to walk map and remove entries without risking a race
+        * in EEXIST update case.
+        */
        synchronize_rcu();
-       raw_spin_lock_bh(&stab->lock);
        for (i = 0; i < stab->map.max_entries; i++) {
                struct sock **psk = &stab->sks[i];
                struct sock *sk;
@@ -248,7 +251,6 @@ static void sock_map_free(struct bpf_map *map)
                        release_sock(sk);
                }
        }
-       raw_spin_unlock_bh(&stab->lock);
 
        /* wait for psock readers accessing its map link */
        synchronize_rcu();
@@ -863,10 +865,13 @@ static void sock_hash_free(struct bpf_map *map)
        struct hlist_node *node;
        int i;
 
+       /* After the sync no updates or deletes will be in-flight so it
+        * is safe to walk map and remove entries without risking a race
+        * in EEXIST update case.
+        */
        synchronize_rcu();
        for (i = 0; i < htab->buckets_num; i++) {
                bucket = sock_hash_select_bucket(htab, i);
-               raw_spin_lock_bh(&bucket->lock);
                hlist_for_each_entry_safe(elem, node, &bucket->head, node) {
                        hlist_del_rcu(&elem->node);
                        lock_sock(elem->sk);
@@ -875,7 +880,6 @@ static void sock_hash_free(struct bpf_map *map)
                        rcu_read_unlock();
                        release_sock(elem->sk);
                }
-               raw_spin_unlock_bh(&bucket->lock);
        }
 
        /* wait for psock readers accessing its map link */
index a7662e7..760e6ea 100644 (file)
@@ -117,7 +117,9 @@ static inline struct net_device *dsa_master_find_slave(struct net_device *dev,
 /* port.c */
 int dsa_port_set_state(struct dsa_port *dp, u8 state,
                       struct switchdev_trans *trans);
+int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy);
 int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy);
+void dsa_port_disable_rt(struct dsa_port *dp);
 void dsa_port_disable(struct dsa_port *dp);
 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
 void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
index 774facb..ec13dc6 100644 (file)
@@ -63,7 +63,7 @@ static void dsa_port_set_state_now(struct dsa_port *dp, u8 state)
                pr_err("DSA: failed to set STP state %u (%d)\n", state, err);
 }
 
-int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy)
+int dsa_port_enable_rt(struct dsa_port *dp, struct phy_device *phy)
 {
        struct dsa_switch *ds = dp->ds;
        int port = dp->index;
@@ -78,14 +78,31 @@ int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy)
        if (!dp->bridge_dev)
                dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
 
+       if (dp->pl)
+               phylink_start(dp->pl);
+
        return 0;
 }
 
-void dsa_port_disable(struct dsa_port *dp)
+int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy)
+{
+       int err;
+
+       rtnl_lock();
+       err = dsa_port_enable_rt(dp, phy);
+       rtnl_unlock();
+
+       return err;
+}
+
+void dsa_port_disable_rt(struct dsa_port *dp)
 {
        struct dsa_switch *ds = dp->ds;
        int port = dp->index;
 
+       if (dp->pl)
+               phylink_stop(dp->pl);
+
        if (!dp->bridge_dev)
                dsa_port_set_state_now(dp, BR_STATE_DISABLED);
 
@@ -93,6 +110,13 @@ void dsa_port_disable(struct dsa_port *dp)
                ds->ops->port_disable(ds, port);
 }
 
+void dsa_port_disable(struct dsa_port *dp)
+{
+       rtnl_lock();
+       dsa_port_disable_rt(dp);
+       rtnl_unlock();
+}
+
 int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br)
 {
        struct dsa_notifier_bridge_info info = {
@@ -614,10 +638,6 @@ static int dsa_port_phylink_register(struct dsa_port *dp)
                goto err_phy_connect;
        }
 
-       rtnl_lock();
-       phylink_start(dp->pl);
-       rtnl_unlock();
-
        return 0;
 
 err_phy_connect:
@@ -628,9 +648,14 @@ err_phy_connect:
 int dsa_port_link_register_of(struct dsa_port *dp)
 {
        struct dsa_switch *ds = dp->ds;
+       struct device_node *phy_np;
 
-       if (!ds->ops->adjust_link)
-               return dsa_port_phylink_register(dp);
+       if (!ds->ops->adjust_link) {
+               phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
+               if (of_phy_is_fixed_link(dp->dn) || phy_np)
+                       return dsa_port_phylink_register(dp);
+               return 0;
+       }
 
        dev_warn(ds->dev,
                 "Using legacy PHYLIB callbacks. Please migrate to PHYLINK!\n");
@@ -645,11 +670,12 @@ void dsa_port_link_unregister_of(struct dsa_port *dp)
 {
        struct dsa_switch *ds = dp->ds;
 
-       if (!ds->ops->adjust_link) {
+       if (!ds->ops->adjust_link && dp->pl) {
                rtnl_lock();
                phylink_disconnect_phy(dp->pl);
                rtnl_unlock();
                phylink_destroy(dp->pl);
+               dp->pl = NULL;
                return;
        }
 
index 088c886..ddc0f92 100644 (file)
@@ -88,12 +88,10 @@ static int dsa_slave_open(struct net_device *dev)
                        goto clear_allmulti;
        }
 
-       err = dsa_port_enable(dp, dev->phydev);
+       err = dsa_port_enable_rt(dp, dev->phydev);
        if (err)
                goto clear_promisc;
 
-       phylink_start(dp->pl);
-
        return 0;
 
 clear_promisc:
@@ -114,9 +112,7 @@ static int dsa_slave_close(struct net_device *dev)
        struct net_device *master = dsa_slave_to_master(dev);
        struct dsa_port *dp = dsa_slave_to_port(dev);
 
-       phylink_stop(dp->pl);
-
-       dsa_port_disable(dp);
+       dsa_port_disable_rt(dp);
 
        dev_mc_unsync(master, dev);
        dev_uc_unsync(master, dev);
index 2fb6c26..b97ad93 100644 (file)
@@ -298,47 +298,4 @@ struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
 }
 EXPORT_SYMBOL_GPL(dsa_8021q_xmit);
 
-/* In the DSA packet_type handler, skb->data points in the middle of the VLAN
- * tag, after tpid and before tci. This is because so far, ETH_HLEN
- * (DMAC, SMAC, EtherType) bytes were pulled.
- * There are 2 bytes of VLAN tag left in skb->data, and upper
- * layers expect the 'real' EtherType to be consumed as well.
- * Coincidentally, a VLAN header is also of the same size as
- * the number of bytes that need to be pulled.
- *
- * skb_mac_header                                      skb->data
- * |                                                       |
- * v                                                       v
- * |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
- * +-----------------------+-----------------------+-------+-------+-------+
- * |    Destination MAC    |      Source MAC       |  TPID |  TCI  | EType |
- * +-----------------------+-----------------------+-------+-------+-------+
- * ^                                               |               |
- * |<--VLAN_HLEN-->to                              <---VLAN_HLEN--->
- * from            |
- *       >>>>>>>   v
- *       >>>>>>>   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
- *       >>>>>>>   +-----------------------+-----------------------+-------+
- *       >>>>>>>   |    Destination MAC    |      Source MAC       | EType |
- *                 +-----------------------+-----------------------+-------+
- *                 ^                                                       ^
- * (now part of    |                                                       |
- *  skb->head)     skb_mac_header                                  skb->data
- */
-struct sk_buff *dsa_8021q_remove_header(struct sk_buff *skb)
-{
-       u8 *from = skb_mac_header(skb);
-       u8 *dest = from + VLAN_HLEN;
-
-       memmove(dest, from, ETH_HLEN - VLAN_HLEN);
-       skb_pull(skb, VLAN_HLEN);
-       skb_push(skb, ETH_HLEN);
-       skb_reset_mac_header(skb);
-       skb_reset_mac_len(skb);
-       skb_pull_rcsum(skb, ETH_HLEN);
-
-       return skb;
-}
-EXPORT_SYMBOL_GPL(dsa_8021q_remove_header);
-
 MODULE_LICENSE("GPL v2");
index 9c31141..9169b63 100644 (file)
@@ -140,6 +140,8 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
        /* Remove Broadcom tag and update checksum */
        skb_pull_rcsum(skb, BRCM_TAG_LEN);
 
+       skb->offload_fwd_mark = 1;
+
        return skb;
 }
 #endif
index 5366ea4..d553bf3 100644 (file)
@@ -250,14 +250,14 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
 {
        struct sja1105_meta meta = {0};
        int source_port, switch_id;
-       struct vlan_ethhdr *hdr;
+       struct ethhdr *hdr;
        u16 tpid, vid, tci;
        bool is_link_local;
        bool is_tagged;
        bool is_meta;
 
-       hdr = vlan_eth_hdr(skb);
-       tpid = ntohs(hdr->h_vlan_proto);
+       hdr = eth_hdr(skb);
+       tpid = ntohs(hdr->h_proto);
        is_tagged = (tpid == ETH_P_SJA1105);
        is_link_local = sja1105_is_link_local(skb);
        is_meta = sja1105_is_meta_frame(skb);
@@ -266,7 +266,12 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
 
        if (is_tagged) {
                /* Normal traffic path. */
-               tci = ntohs(hdr->h_vlan_TCI);
+               skb_push_rcsum(skb, ETH_HLEN);
+               __skb_vlan_pop(skb, &tci);
+               skb_pull_rcsum(skb, ETH_HLEN);
+               skb_reset_network_header(skb);
+               skb_reset_transport_header(skb);
+
                vid = tci & VLAN_VID_MASK;
                source_port = dsa_8021q_rx_source_port(vid);
                switch_id = dsa_8021q_rx_switch_id(vid);
@@ -295,12 +300,6 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
                return NULL;
        }
 
-       /* Delete/overwrite fake VLAN header, DSA expects to not find
-        * it there, see dsa_switch_rcv: skb_push(skb, ETH_HLEN).
-        */
-       if (is_tagged)
-               skb = dsa_8021q_remove_header(skb);
-
        return sja1105_rcv_meta_state_machine(skb, &meta, is_link_local,
                                              is_meta);
 }
index 8977fe1..ef91975 100644 (file)
@@ -305,7 +305,8 @@ nla_put_failure:
 static const struct nla_policy bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = {
        [ETHTOOL_A_BITSET_UNSPEC]       = { .type = NLA_REJECT },
        [ETHTOOL_A_BITSET_NOMASK]       = { .type = NLA_FLAG },
-       [ETHTOOL_A_BITSET_SIZE]         = { .type = NLA_U32 },
+       [ETHTOOL_A_BITSET_SIZE]         = NLA_POLICY_MAX(NLA_U32,
+                                                        ETHNL_MAX_BITSET_SIZE),
        [ETHTOOL_A_BITSET_BITS]         = { .type = NLA_NESTED },
        [ETHTOOL_A_BITSET_VALUE]        = { .type = NLA_BINARY },
        [ETHTOOL_A_BITSET_MASK]         = { .type = NLA_BINARY },
index b8247e3..b849f9d 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef _NET_ETHTOOL_BITSET_H
 #define _NET_ETHTOOL_BITSET_H
 
+#define ETHNL_MAX_BITSET_SIZE S16_MAX
+
 typedef const char (*const ethnl_string_array_t)[ETH_GSTRING_LEN];
 
 int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact);
index aaef484..92599ad 100644 (file)
@@ -107,8 +107,9 @@ int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info)
        if (ret < 0)
                return ret;
        dev = req_info.dev;
+       ret = -EOPNOTSUPP;
        if (!dev->ethtool_ops->get_msglevel || !dev->ethtool_ops->set_msglevel)
-               return -EOPNOTSUPP;
+               goto out_dev;
 
        rtnl_lock();
        ret = ethnl_ops_begin(dev);
@@ -129,6 +130,7 @@ out_ops:
        ethnl_ops_complete(dev);
 out_rtnl:
        rtnl_unlock();
+out_dev:
        dev_put(dev);
        return ret;
 }
index 5d16cb4..6e9e0b5 100644 (file)
@@ -126,9 +126,10 @@ int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info)
        if (ret < 0)
                return ret;
        dev = req_info.dev;
+       ret = -EOPNOTSUPP;
        if (!dev->ethtool_ops->get_link_ksettings ||
            !dev->ethtool_ops->set_link_ksettings)
-               return -EOPNOTSUPP;
+               goto out_dev;
 
        rtnl_lock();
        ret = ethnl_ops_begin(dev);
@@ -162,6 +163,7 @@ out_ops:
        ethnl_ops_complete(dev);
 out_rtnl:
        rtnl_unlock();
+out_dev:
        dev_put(dev);
        return ret;
 }
index 96f20be..18cc37b 100644 (file)
@@ -338,9 +338,10 @@ int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info)
        if (ret < 0)
                return ret;
        dev = req_info.dev;
+       ret = -EOPNOTSUPP;
        if (!dev->ethtool_ops->get_link_ksettings ||
            !dev->ethtool_ops->set_link_ksettings)
-               return -EOPNOTSUPP;
+               goto out_dev;
 
        rtnl_lock();
        ret = ethnl_ops_begin(dev);
@@ -370,6 +371,7 @@ out_ops:
        ethnl_ops_complete(dev);
 out_rtnl:
        rtnl_unlock();
+out_dev:
        dev_put(dev);
        return ret;
 }
index 180c194..fc9e0b8 100644 (file)
@@ -40,6 +40,7 @@ int ethnl_parse_header(struct ethnl_req_info *req_info,
        struct nlattr *tb[ETHTOOL_A_HEADER_MAX + 1];
        const struct nlattr *devname_attr;
        struct net_device *dev = NULL;
+       u32 flags = 0;
        int ret;
 
        if (!header) {
@@ -50,8 +51,17 @@ int ethnl_parse_header(struct ethnl_req_info *req_info,
                               ethnl_header_policy, extack);
        if (ret < 0)
                return ret;
-       devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME];
+       if (tb[ETHTOOL_A_HEADER_FLAGS]) {
+               flags = nla_get_u32(tb[ETHTOOL_A_HEADER_FLAGS]);
+               if (flags & ~ETHTOOL_FLAG_ALL) {
+                       NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_HEADER_FLAGS],
+                                           "unrecognized request flags");
+                       nl_set_extack_cookie_u32(extack, ETHTOOL_FLAG_ALL);
+                       return -EOPNOTSUPP;
+               }
+       }
 
+       devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME];
        if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) {
                u32 ifindex = nla_get_u32(tb[ETHTOOL_A_HEADER_DEV_INDEX]);
 
@@ -90,9 +100,7 @@ int ethnl_parse_header(struct ethnl_req_info *req_info,
        }
 
        req_info->dev = dev;
-       if (tb[ETHTOOL_A_HEADER_FLAGS])
-               req_info->flags = nla_get_u32(tb[ETHTOOL_A_HEADER_FLAGS]);
-
+       req_info->flags = flags;
        return 0;
 }
 
index e1b8a65..55e1eca 100644 (file)
@@ -128,8 +128,9 @@ int ethnl_set_wol(struct sk_buff *skb, struct genl_info *info)
        if (ret < 0)
                return ret;
        dev = req_info.dev;
+       ret = -EOPNOTSUPP;
        if (!dev->ethtool_ops->get_wol || !dev->ethtool_ops->set_wol)
-               return -EOPNOTSUPP;
+               goto out_dev;
 
        rtnl_lock();
        ret = ethnl_ops_begin(dev);
@@ -172,6 +173,7 @@ out_ops:
        ethnl_ops_complete(dev);
 out_rtnl:
        rtnl_unlock();
+out_dev:
        dev_put(dev);
        return ret;
 }
index 3ba7f61..a64bb64 100644 (file)
@@ -482,12 +482,9 @@ int hsr_get_node_data(struct hsr_priv *hsr,
        struct hsr_port *port;
        unsigned long tdiff;
 
-       rcu_read_lock();
        node = find_node_by_addr_A(&hsr->node_db, addr);
-       if (!node) {
-               rcu_read_unlock();
-               return -ENOENT; /* No such entry */
-       }
+       if (!node)
+               return -ENOENT;
 
        ether_addr_copy(addr_b, node->macaddress_B);
 
@@ -522,7 +519,5 @@ int hsr_get_node_data(struct hsr_priv *hsr,
                *addr_b_ifindex = -1;
        }
 
-       rcu_read_unlock();
-
        return 0;
 }
index 8dc0547..fae21c8 100644 (file)
@@ -251,15 +251,16 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
        if (!na)
                goto invalid;
 
-       hsr_dev = __dev_get_by_index(genl_info_net(info),
-                                    nla_get_u32(info->attrs[HSR_A_IFINDEX]));
+       rcu_read_lock();
+       hsr_dev = dev_get_by_index_rcu(genl_info_net(info),
+                                      nla_get_u32(info->attrs[HSR_A_IFINDEX]));
        if (!hsr_dev)
-               goto invalid;
+               goto rcu_unlock;
        if (!is_hsr_master(hsr_dev))
-               goto invalid;
+               goto rcu_unlock;
 
        /* Send reply */
-       skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
        if (!skb_out) {
                res = -ENOMEM;
                goto fail;
@@ -313,12 +314,10 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
        res = nla_put_u16(skb_out, HSR_A_IF1_SEQ, hsr_node_if1_seq);
        if (res < 0)
                goto nla_put_failure;
-       rcu_read_lock();
        port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_A);
        if (port)
                res = nla_put_u32(skb_out, HSR_A_IF1_IFINDEX,
                                  port->dev->ifindex);
-       rcu_read_unlock();
        if (res < 0)
                goto nla_put_failure;
 
@@ -328,20 +327,22 @@ static int hsr_get_node_status(struct sk_buff *skb_in, struct genl_info *info)
        res = nla_put_u16(skb_out, HSR_A_IF2_SEQ, hsr_node_if2_seq);
        if (res < 0)
                goto nla_put_failure;
-       rcu_read_lock();
        port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
        if (port)
                res = nla_put_u32(skb_out, HSR_A_IF2_IFINDEX,
                                  port->dev->ifindex);
-       rcu_read_unlock();
        if (res < 0)
                goto nla_put_failure;
 
+       rcu_read_unlock();
+
        genlmsg_end(skb_out, msg_head);
        genlmsg_unicast(genl_info_net(info), skb_out, info->snd_portid);
 
        return 0;
 
+rcu_unlock:
+       rcu_read_unlock();
 invalid:
        netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
        return 0;
@@ -351,6 +352,7 @@ nla_put_failure:
        /* Fall through */
 
 fail:
+       rcu_read_unlock();
        return res;
 }
 
@@ -358,16 +360,14 @@ fail:
  */
 static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
 {
-       /* For receiving */
-       struct nlattr *na;
+       unsigned char addr[ETH_ALEN];
        struct net_device *hsr_dev;
-
-       /* For sending */
        struct sk_buff *skb_out;
-       void *msg_head;
        struct hsr_priv *hsr;
-       void *pos;
-       unsigned char addr[ETH_ALEN];
+       bool restart = false;
+       struct nlattr *na;
+       void *pos = NULL;
+       void *msg_head;
        int res;
 
        if (!info)
@@ -377,15 +377,17 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
        if (!na)
                goto invalid;
 
-       hsr_dev = __dev_get_by_index(genl_info_net(info),
-                                    nla_get_u32(info->attrs[HSR_A_IFINDEX]));
+       rcu_read_lock();
+       hsr_dev = dev_get_by_index_rcu(genl_info_net(info),
+                                      nla_get_u32(info->attrs[HSR_A_IFINDEX]));
        if (!hsr_dev)
-               goto invalid;
+               goto rcu_unlock;
        if (!is_hsr_master(hsr_dev))
-               goto invalid;
+               goto rcu_unlock;
 
+restart:
        /* Send reply */
-       skb_out = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       skb_out = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_ATOMIC);
        if (!skb_out) {
                res = -ENOMEM;
                goto fail;
@@ -399,18 +401,26 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
                goto nla_put_failure;
        }
 
-       res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex);
-       if (res < 0)
-               goto nla_put_failure;
+       if (!restart) {
+               res = nla_put_u32(skb_out, HSR_A_IFINDEX, hsr_dev->ifindex);
+               if (res < 0)
+                       goto nla_put_failure;
+       }
 
        hsr = netdev_priv(hsr_dev);
 
-       rcu_read_lock();
-       pos = hsr_get_next_node(hsr, NULL, addr);
+       if (!pos)
+               pos = hsr_get_next_node(hsr, NULL, addr);
        while (pos) {
                res = nla_put(skb_out, HSR_A_NODE_ADDR, ETH_ALEN, addr);
                if (res < 0) {
-                       rcu_read_unlock();
+                       if (res == -EMSGSIZE) {
+                               genlmsg_end(skb_out, msg_head);
+                               genlmsg_unicast(genl_info_net(info), skb_out,
+                                               info->snd_portid);
+                               restart = true;
+                               goto restart;
+                       }
                        goto nla_put_failure;
                }
                pos = hsr_get_next_node(hsr, pos, addr);
@@ -422,15 +432,18 @@ static int hsr_get_node_list(struct sk_buff *skb_in, struct genl_info *info)
 
        return 0;
 
+rcu_unlock:
+       rcu_read_unlock();
 invalid:
        netlink_ack(skb_in, nlmsg_hdr(skb_in), -EINVAL, NULL);
        return 0;
 
 nla_put_failure:
-       kfree_skb(skb_out);
+       nlmsg_free(skb_out);
        /* Fall through */
 
 fail:
+       rcu_read_unlock();
        return res;
 }
 
@@ -457,6 +470,7 @@ static struct genl_family hsr_genl_family __ro_after_init = {
        .version = 1,
        .maxattr = HSR_A_MAX,
        .policy = hsr_genl_policy,
+       .netnsok = true,
        .module = THIS_MODULE,
        .ops = hsr_ops,
        .n_ops = ARRAY_SIZE(hsr_ops),
index fbfd0db..a9104d4 100644 (file)
@@ -145,16 +145,16 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev,
        if (!port)
                return -ENOMEM;
 
+       port->hsr = hsr;
+       port->dev = dev;
+       port->type = type;
+
        if (type != HSR_PT_MASTER) {
                res = hsr_portdev_setup(dev, port);
                if (res)
                        goto fail_dev_setup;
        }
 
-       port->hsr = hsr;
-       port->dev = dev;
-       port->type = type;
-
        list_add_tail_rcu(&port->port_list, &hsr->ports);
        synchronize_rcu();
 
index 2c7a38d..0672b2f 100644 (file)
@@ -21,7 +21,13 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
        [IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, },
        [IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, },
        [IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_BCN_ORD] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_SF_ORD] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_PAN_COORD] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_BAT_EXT] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_COORD_REALIGN] = { .type = NLA_U8, },
        [IEEE802154_ATTR_PAGE] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_DEV_TYPE] = { .type = NLA_U8, },
        [IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, },
        [IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, },
        [IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, },
index f96bd48..25a8888 100644 (file)
@@ -129,7 +129,7 @@ config IP_PNP_DHCP
 
          If unsure, say Y. Note that if you want to use DHCP, a DHCP server
          must be operating on your network.  Read
-         <file:Documentation/filesystems/nfs/nfsroot.txt> for details.
+         <file:Documentation/admin-guide/nfs/nfsroot.rst> for details.
 
 config IP_PNP_BOOTP
        bool "IP: BOOTP support"
@@ -144,7 +144,7 @@ config IP_PNP_BOOTP
          does BOOTP itself, providing all necessary information on the kernel
          command line, you can say N here. If unsure, say Y. Note that if you
          want to use BOOTP, a BOOTP server must be operating on your network.
-         Read <file:Documentation/filesystems/nfs/nfsroot.txt> for details.
+         Read <file:Documentation/admin-guide/nfs/nfsroot.rst> for details.
 
 config IP_PNP_RARP
        bool "IP: RARP support"
@@ -157,7 +157,7 @@ config IP_PNP_RARP
          older protocol which is being obsoleted by BOOTP and DHCP), say Y
          here. Note that if you want to use RARP, a RARP server must be
          operating on your network. Read
-         <file:Documentation/filesystems/nfs/nfsroot.txt> for details.
+         <file:Documentation/admin-guide/nfs/nfsroot.rst> for details.
 
 config NET_IPIP
        tristate "IP: tunneling"
@@ -303,6 +303,7 @@ config SYN_COOKIES
 
 config NET_IPVTI
        tristate "Virtual (secure) IP: tunneling"
+       depends on IPV6 || IPV6=n
        select INET_TUNNEL
        select NET_IP_TUNNEL
        select XFRM
index 574972b..2bf3abe 100644 (file)
@@ -184,7 +184,6 @@ static int bpf_tcp_ca_init_member(const struct btf_type *t,
 {
        const struct tcp_congestion_ops *utcp_ca;
        struct tcp_congestion_ops *tcp_ca;
-       size_t tcp_ca_name_len;
        int prog_fd;
        u32 moff;
 
@@ -199,13 +198,11 @@ static int bpf_tcp_ca_init_member(const struct btf_type *t,
                tcp_ca->flags = utcp_ca->flags;
                return 1;
        case offsetof(struct tcp_congestion_ops, name):
-               tcp_ca_name_len = strnlen(utcp_ca->name, sizeof(utcp_ca->name));
-               if (!tcp_ca_name_len ||
-                   tcp_ca_name_len == sizeof(utcp_ca->name))
+               if (bpf_obj_name_cpy(tcp_ca->name, utcp_ca->name,
+                                    sizeof(tcp_ca->name)) <= 0)
                        return -EINVAL;
                if (tcp_ca_find(utcp_ca->name))
                        return -EEXIST;
-               memcpy(tcp_ca->name, utcp_ca->name, sizeof(tcp_ca->name));
                return 1;
        }
 
index 3768822..0bd10a1 100644 (file)
@@ -1724,6 +1724,7 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 {
        unsigned char optbuf[sizeof(struct ip_options) + 40];
        struct ip_options *opt = (struct ip_options *)optbuf;
+       int res;
 
        if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)
                return;
@@ -1735,7 +1736,11 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
 
        memset(opt, 0, sizeof(struct ip_options));
        opt->optlen = ip_hdr(skb)->ihl*4 - sizeof(struct iphdr);
-       if (__ip_options_compile(dev_net(skb->dev), opt, skb, NULL))
+       rcu_read_lock();
+       res = __ip_options_compile(dev_net(skb->dev), opt, skb, NULL);
+       rcu_read_unlock();
+
+       if (res)
                return;
 
        if (gateway)
index 577db1d..213be9c 100644 (file)
@@ -997,7 +997,9 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
                        return -ENOENT;
                }
 
+               rcu_read_lock();
                err = fib_table_dump(tb, skb, cb, &filter);
+               rcu_read_unlock();
                return skb->len ? : err;
        }
 
index 5fd6e8e..66fdbfe 100644 (file)
@@ -56,7 +56,9 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version)
 }
 EXPORT_SYMBOL_GPL(gre_del_protocol);
 
-/* Fills in tpi and returns header length to be pulled. */
+/* Fills in tpi and returns header length to be pulled.
+ * Note that caller must use pskb_may_pull() before pulling GRE header.
+ */
 int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
                     bool *csum_err, __be16 proto, int nhs)
 {
@@ -110,8 +112,14 @@ int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
         * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
         */
        if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
+               u8 _val, *val;
+
+               val = skb_header_pointer(skb, nhs + hdr_len,
+                                        sizeof(_val), &_val);
+               if (!val)
+                       return -EINVAL;
                tpi->proto = proto;
-               if ((*(u8 *)options & 0xF0) != 0x40)
+               if ((*val & 0xF0) != 0x40)
                        hdr_len += 4;
        }
        tpi->hdr_len = hdr_len;
index a4db79b..d545fb9 100644 (file)
@@ -482,8 +482,28 @@ struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern)
                }
                spin_unlock_bh(&queue->fastopenq.lock);
        }
+
 out:
        release_sock(sk);
+       if (newsk && mem_cgroup_sockets_enabled) {
+               int amt;
+
+               /* atomically get the memory usage, set and charge the
+                * newsk->sk_memcg.
+                */
+               lock_sock(newsk);
+
+               /* The socket has not been accepted yet, no need to look at
+                * newsk->sk_wmem_queued.
+                */
+               amt = sk_mem_pages(newsk->sk_forward_alloc +
+                                  atomic_read(&newsk->sk_rmem_alloc));
+               mem_cgroup_sk_alloc(newsk);
+               if (newsk->sk_memcg && amt)
+                       mem_cgroup_charge_skmem(newsk->sk_memcg, amt);
+
+               release_sock(newsk);
+       }
        if (req)
                reqsk_put(req);
        return newsk;
index f11e997..8c83775 100644 (file)
@@ -100,13 +100,9 @@ static size_t inet_sk_attr_size(struct sock *sk,
                aux = handler->idiag_get_aux_size(sk, net_admin);
 
        return    nla_total_size(sizeof(struct tcp_info))
-               + nla_total_size(1) /* INET_DIAG_SHUTDOWN */
-               + nla_total_size(1) /* INET_DIAG_TOS */
-               + nla_total_size(1) /* INET_DIAG_TCLASS */
-               + nla_total_size(4) /* INET_DIAG_MARK */
-               + nla_total_size(4) /* INET_DIAG_CLASS_ID */
-               + nla_total_size(sizeof(struct inet_diag_meminfo))
                + nla_total_size(sizeof(struct inet_diag_msg))
+               + inet_diag_msg_attrs_size()
+               + nla_total_size(sizeof(struct inet_diag_meminfo))
                + nla_total_size(SK_MEMINFO_VARS * sizeof(u32))
                + nla_total_size(TCP_CA_NAME_MAX)
                + nla_total_size(sizeof(struct tcpvegas_info))
@@ -147,6 +143,24 @@ int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb,
        if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark))
                goto errout;
 
+       if (ext & (1 << (INET_DIAG_CLASS_ID - 1)) ||
+           ext & (1 << (INET_DIAG_TCLASS - 1))) {
+               u32 classid = 0;
+
+#ifdef CONFIG_SOCK_CGROUP_DATA
+               classid = sock_cgroup_classid(&sk->sk_cgrp_data);
+#endif
+               /* Fallback to socket priority if class id isn't set.
+                * Classful qdiscs use it as direct reference to class.
+                * For cgroup2 classid is always zero.
+                */
+               if (!classid)
+                       classid = sk->sk_priority;
+
+               if (nla_put_u32(skb, INET_DIAG_CLASS_ID, classid))
+                       goto errout;
+       }
+
        r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk));
        r->idiag_inode = sock_i_ino(sk);
 
@@ -284,24 +298,6 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
                        goto errout;
        }
 
-       if (ext & (1 << (INET_DIAG_CLASS_ID - 1)) ||
-           ext & (1 << (INET_DIAG_TCLASS - 1))) {
-               u32 classid = 0;
-
-#ifdef CONFIG_SOCK_CGROUP_DATA
-               classid = sock_cgroup_classid(&sk->sk_cgrp_data);
-#endif
-               /* Fallback to socket priority if class id isn't set.
-                * Classful qdiscs use it as direct reference to class.
-                * For cgroup2 classid is always zero.
-                */
-               if (!classid)
-                       classid = sk->sk_priority;
-
-               if (nla_put_u32(skb, INET_DIAG_CLASS_ID, classid))
-                       goto errout;
-       }
-
 out:
        nlmsg_end(skb, nlh);
        return 0;
index 8274f98..029b24e 100644 (file)
@@ -1153,6 +1153,24 @@ static int ipgre_netlink_parms(struct net_device *dev,
        if (data[IFLA_GRE_FWMARK])
                *fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]);
 
+       return 0;
+}
+
+static int erspan_netlink_parms(struct net_device *dev,
+                               struct nlattr *data[],
+                               struct nlattr *tb[],
+                               struct ip_tunnel_parm *parms,
+                               __u32 *fwmark)
+{
+       struct ip_tunnel *t = netdev_priv(dev);
+       int err;
+
+       err = ipgre_netlink_parms(dev, data, tb, parms, fwmark);
+       if (err)
+               return err;
+       if (!data)
+               return 0;
+
        if (data[IFLA_GRE_ERSPAN_VER]) {
                t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
 
@@ -1276,45 +1294,70 @@ static void ipgre_tap_setup(struct net_device *dev)
        ip_tunnel_setup(dev, gre_tap_net_id);
 }
 
-static int ipgre_newlink(struct net *src_net, struct net_device *dev,
-                        struct nlattr *tb[], struct nlattr *data[],
-                        struct netlink_ext_ack *extack)
+static int
+ipgre_newlink_encap_setup(struct net_device *dev, struct nlattr *data[])
 {
-       struct ip_tunnel_parm p;
        struct ip_tunnel_encap ipencap;
-       __u32 fwmark = 0;
-       int err;
 
        if (ipgre_netlink_encap_parms(data, &ipencap)) {
                struct ip_tunnel *t = netdev_priv(dev);
-               err = ip_tunnel_encap_setup(t, &ipencap);
+               int err = ip_tunnel_encap_setup(t, &ipencap);
 
                if (err < 0)
                        return err;
        }
 
+       return 0;
+}
+
+static int ipgre_newlink(struct net *src_net, struct net_device *dev,
+                        struct nlattr *tb[], struct nlattr *data[],
+                        struct netlink_ext_ack *extack)
+{
+       struct ip_tunnel_parm p;
+       __u32 fwmark = 0;
+       int err;
+
+       err = ipgre_newlink_encap_setup(dev, data);
+       if (err)
+               return err;
+
        err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
        if (err < 0)
                return err;
        return ip_tunnel_newlink(dev, tb, &p, fwmark);
 }
 
+static int erspan_newlink(struct net *src_net, struct net_device *dev,
+                         struct nlattr *tb[], struct nlattr *data[],
+                         struct netlink_ext_ack *extack)
+{
+       struct ip_tunnel_parm p;
+       __u32 fwmark = 0;
+       int err;
+
+       err = ipgre_newlink_encap_setup(dev, data);
+       if (err)
+               return err;
+
+       err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
+       if (err)
+               return err;
+       return ip_tunnel_newlink(dev, tb, &p, fwmark);
+}
+
 static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
                            struct nlattr *data[],
                            struct netlink_ext_ack *extack)
 {
        struct ip_tunnel *t = netdev_priv(dev);
-       struct ip_tunnel_encap ipencap;
        __u32 fwmark = t->fwmark;
        struct ip_tunnel_parm p;
        int err;
 
-       if (ipgre_netlink_encap_parms(data, &ipencap)) {
-               err = ip_tunnel_encap_setup(t, &ipencap);
-
-               if (err < 0)
-                       return err;
-       }
+       err = ipgre_newlink_encap_setup(dev, data);
+       if (err)
+               return err;
 
        err = ipgre_netlink_parms(dev, data, tb, &p, &fwmark);
        if (err < 0)
@@ -1327,8 +1370,34 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[],
        t->parms.i_flags = p.i_flags;
        t->parms.o_flags = p.o_flags;
 
-       if (strcmp(dev->rtnl_link_ops->kind, "erspan"))
-               ipgre_link_update(dev, !tb[IFLA_MTU]);
+       ipgre_link_update(dev, !tb[IFLA_MTU]);
+
+       return 0;
+}
+
+static int erspan_changelink(struct net_device *dev, struct nlattr *tb[],
+                            struct nlattr *data[],
+                            struct netlink_ext_ack *extack)
+{
+       struct ip_tunnel *t = netdev_priv(dev);
+       __u32 fwmark = t->fwmark;
+       struct ip_tunnel_parm p;
+       int err;
+
+       err = ipgre_newlink_encap_setup(dev, data);
+       if (err)
+               return err;
+
+       err = erspan_netlink_parms(dev, data, tb, &p, &fwmark);
+       if (err < 0)
+               return err;
+
+       err = ip_tunnel_changelink(dev, tb, &p, fwmark);
+       if (err < 0)
+               return err;
+
+       t->parms.i_flags = p.i_flags;
+       t->parms.o_flags = p.o_flags;
 
        return 0;
 }
@@ -1519,8 +1588,8 @@ static struct rtnl_link_ops erspan_link_ops __read_mostly = {
        .priv_size      = sizeof(struct ip_tunnel),
        .setup          = erspan_setup,
        .validate       = erspan_validate,
-       .newlink        = ipgre_newlink,
-       .changelink     = ipgre_changelink,
+       .newlink        = erspan_newlink,
+       .changelink     = erspan_changelink,
        .dellink        = ip_tunnel_dellink,
        .get_size       = ipgre_get_size,
        .fill_info      = ipgre_fill_info,
index 37cddd1..1b4e6f2 100644 (file)
@@ -187,17 +187,39 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
        int mtu;
 
        if (!dst) {
-               struct rtable *rt;
-
-               fl->u.ip4.flowi4_oif = dev->ifindex;
-               fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
-               rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
-               if (IS_ERR(rt)) {
+               switch (skb->protocol) {
+               case htons(ETH_P_IP): {
+                       struct rtable *rt;
+
+                       fl->u.ip4.flowi4_oif = dev->ifindex;
+                       fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
+                       rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
+                       if (IS_ERR(rt)) {
+                               dev->stats.tx_carrier_errors++;
+                               goto tx_error_icmp;
+                       }
+                       dst = &rt->dst;
+                       skb_dst_set(skb, dst);
+                       break;
+               }
+#if IS_ENABLED(CONFIG_IPV6)
+               case htons(ETH_P_IPV6):
+                       fl->u.ip6.flowi6_oif = dev->ifindex;
+                       fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
+                       dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
+                       if (dst->error) {
+                               dst_release(dst);
+                               dst = NULL;
+                               dev->stats.tx_carrier_errors++;
+                               goto tx_error_icmp;
+                       }
+                       skb_dst_set(skb, dst);
+                       break;
+#endif
+               default:
                        dev->stats.tx_carrier_errors++;
                        goto tx_error_icmp;
                }
-               dst = &rt->dst;
-               skb_dst_set(skb, dst);
        }
 
        dst_hold(dst);
index 4438f6b..561f15b 100644 (file)
@@ -1621,7 +1621,7 @@ late_initcall(ip_auto_config);
 
 /*
  *  Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel
- *  command line parameter.  See Documentation/filesystems/nfs/nfsroot.txt.
+ *  command line parameter.  See Documentation/admin-guide/nfs/nfsroot.rst.
  */
 static int __init ic_proto_name(char *name)
 {
index e35736b..a93e7d1 100644 (file)
@@ -100,8 +100,9 @@ static int raw_diag_dump_one(struct sk_buff *in_skb,
        if (IS_ERR(sk))
                return PTR_ERR(sk);
 
-       rep = nlmsg_new(sizeof(struct inet_diag_msg) +
-                       sizeof(struct inet_diag_meminfo) + 64,
+       rep = nlmsg_new(nla_total_size(sizeof(struct inet_diag_msg)) +
+                       inet_diag_msg_attrs_size() +
+                       nla_total_size(sizeof(struct inet_diag_meminfo)) + 64,
                        GFP_KERNEL);
        if (!rep) {
                sock_put(sk);
index eb2d805..dc77c30 100644 (file)
@@ -2948,8 +2948,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                        err = -EPERM;
                else if (tp->repair_queue == TCP_SEND_QUEUE)
                        WRITE_ONCE(tp->write_seq, val);
-               else if (tp->repair_queue == TCP_RECV_QUEUE)
+               else if (tp->repair_queue == TCP_RECV_QUEUE) {
                        WRITE_ONCE(tp->rcv_nxt, val);
+                       WRITE_ONCE(tp->copied_seq, val);
+               }
                else
                        err = -EINVAL;
                break;
index 316ebdf..6b6b570 100644 (file)
@@ -6124,7 +6124,11 @@ static void tcp_rcv_synrecv_state_fastopen(struct sock *sk)
 {
        struct request_sock *req;
 
-       tcp_try_undo_loss(sk, false);
+       /* If we are still handling the SYNACK RTO, see if timestamp ECR allows
+        * undo. If peer SACKs triggered fast recovery, we can't undo here.
+        */
+       if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss)
+               tcp_try_undo_loss(sk, false);
 
        /* Reset rtx states to prevent spurious retransmits_timed_out() */
        tcp_sk(sk)->retrans_stamp = 0;
index 306e25d..2f45cde 100644 (file)
@@ -1109,6 +1109,10 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
 
                if (unlikely(!skb))
                        return -ENOBUFS;
+               /* retransmit skbs might have a non zero value in skb->dev
+                * because skb->dev is aliased with skb->rbnode.rb_left
+                */
+               skb->dev = NULL;
        }
 
        inet = inet_sk(sk);
@@ -3037,8 +3041,12 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
 
                tcp_skb_tsorted_save(skb) {
                        nskb = __pskb_copy(skb, MAX_TCP_HEADER, GFP_ATOMIC);
-                       err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
-                                    -ENOBUFS;
+                       if (nskb) {
+                               nskb->dev = NULL;
+                               err = tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC);
+                       } else {
+                               err = -ENOBUFS;
+                       }
                } tcp_skb_tsorted_restore(skb);
 
                if (!err) {
index 910555a..dccd228 100644 (file)
@@ -64,8 +64,9 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
                goto out;
 
        err = -ENOMEM;
-       rep = nlmsg_new(sizeof(struct inet_diag_msg) +
-                       sizeof(struct inet_diag_meminfo) + 64,
+       rep = nlmsg_new(nla_total_size(sizeof(struct inet_diag_msg)) +
+                       inet_diag_msg_attrs_size() +
+                       nla_total_size(sizeof(struct inet_diag_meminfo)) + 64,
                        GFP_KERNEL);
        if (!rep)
                goto out;
index cb493e1..46d614b 100644 (file)
@@ -1226,11 +1226,13 @@ check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires)
 }
 
 static void
-cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt)
+cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires,
+                    bool del_rt, bool del_peer)
 {
        struct fib6_info *f6i;
 
-       f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len,
+       f6i = addrconf_get_prefix_route(del_peer ? &ifp->peer_addr : &ifp->addr,
+                                       ifp->prefix_len,
                                        ifp->idev->dev, 0, RTF_DEFAULT, true);
        if (f6i) {
                if (del_rt)
@@ -1293,7 +1295,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 
        if (action != CLEANUP_PREFIX_RT_NOP) {
                cleanup_prefix_route(ifp, expires,
-                       action == CLEANUP_PREFIX_RT_DEL);
+                       action == CLEANUP_PREFIX_RT_DEL, false);
        }
 
        /* clean up prefsrc entries */
@@ -3345,6 +3347,10 @@ static void addrconf_dev_config(struct net_device *dev)
            (dev->type != ARPHRD_NONE) &&
            (dev->type != ARPHRD_RAWIP)) {
                /* Alas, we support only Ethernet autoconfiguration. */
+               idev = __in6_dev_get(dev);
+               if (!IS_ERR_OR_NULL(idev) && dev->flags & IFF_UP &&
+                   dev->flags & IFF_MULTICAST)
+                       ipv6_mc_up(idev);
                return;
        }
 
@@ -4586,12 +4592,14 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh,
 }
 
 static int modify_prefix_route(struct inet6_ifaddr *ifp,
-                              unsigned long expires, u32 flags)
+                              unsigned long expires, u32 flags,
+                              bool modify_peer)
 {
        struct fib6_info *f6i;
        u32 prio;
 
-       f6i = addrconf_get_prefix_route(&ifp->addr, ifp->prefix_len,
+       f6i = addrconf_get_prefix_route(modify_peer ? &ifp->peer_addr : &ifp->addr,
+                                       ifp->prefix_len,
                                        ifp->idev->dev, 0, RTF_DEFAULT, true);
        if (!f6i)
                return -ENOENT;
@@ -4602,7 +4610,8 @@ static int modify_prefix_route(struct inet6_ifaddr *ifp,
                ip6_del_rt(dev_net(ifp->idev->dev), f6i);
 
                /* add new one */
-               addrconf_prefix_route(&ifp->addr, ifp->prefix_len,
+               addrconf_prefix_route(modify_peer ? &ifp->peer_addr : &ifp->addr,
+                                     ifp->prefix_len,
                                      ifp->rt_priority, ifp->idev->dev,
                                      expires, flags, GFP_KERNEL);
        } else {
@@ -4624,6 +4633,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
        unsigned long timeout;
        bool was_managetempaddr;
        bool had_prefixroute;
+       bool new_peer = false;
 
        ASSERT_RTNL();
 
@@ -4655,6 +4665,13 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
                cfg->preferred_lft = timeout;
        }
 
+       if (cfg->peer_pfx &&
+           memcmp(&ifp->peer_addr, cfg->peer_pfx, sizeof(struct in6_addr))) {
+               if (!ipv6_addr_any(&ifp->peer_addr))
+                       cleanup_prefix_route(ifp, expires, true, true);
+               new_peer = true;
+       }
+
        spin_lock_bh(&ifp->lock);
        was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR;
        had_prefixroute = ifp->flags & IFA_F_PERMANENT &&
@@ -4670,6 +4687,9 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
        if (cfg->rt_priority && cfg->rt_priority != ifp->rt_priority)
                ifp->rt_priority = cfg->rt_priority;
 
+       if (new_peer)
+               ifp->peer_addr = *cfg->peer_pfx;
+
        spin_unlock_bh(&ifp->lock);
        if (!(ifp->flags&IFA_F_TENTATIVE))
                ipv6_ifa_notify(0, ifp);
@@ -4678,7 +4698,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
                int rc = -ENOENT;
 
                if (had_prefixroute)
-                       rc = modify_prefix_route(ifp, expires, flags);
+                       rc = modify_prefix_route(ifp, expires, flags, false);
 
                /* prefix route could have been deleted; if so restore it */
                if (rc == -ENOENT) {
@@ -4686,6 +4706,15 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
                                              ifp->rt_priority, ifp->idev->dev,
                                              expires, flags, GFP_KERNEL);
                }
+
+               if (had_prefixroute && !ipv6_addr_any(&ifp->peer_addr))
+                       rc = modify_prefix_route(ifp, expires, flags, true);
+
+               if (rc == -ENOENT && !ipv6_addr_any(&ifp->peer_addr)) {
+                       addrconf_prefix_route(&ifp->peer_addr, ifp->prefix_len,
+                                             ifp->rt_priority, ifp->idev->dev,
+                                             expires, flags, GFP_KERNEL);
+               }
        } else if (had_prefixroute) {
                enum cleanup_prefix_rt_t action;
                unsigned long rt_expires;
@@ -4696,7 +4725,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
 
                if (action != CLEANUP_PREFIX_RT_NOP) {
                        cleanup_prefix_route(ifp, rt_expires,
-                               action == CLEANUP_PREFIX_RT_DEL);
+                               action == CLEANUP_PREFIX_RT_DEL, false);
                }
        }
 
@@ -5983,9 +6012,9 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
                if (ifp->idev->cnf.forwarding)
                        addrconf_join_anycast(ifp);
                if (!ipv6_addr_any(&ifp->peer_addr))
-                       addrconf_prefix_route(&ifp->peer_addr, 128, 0,
-                                             ifp->idev->dev, 0, 0,
-                                             GFP_ATOMIC);
+                       addrconf_prefix_route(&ifp->peer_addr, 128,
+                                             ifp->rt_priority, ifp->idev->dev,
+                                             0, 0, GFP_ATOMIC);
                break;
        case RTM_DELADDR:
                if (ifp->idev->cnf.forwarding)
index 524006a..cc6180e 100644 (file)
@@ -311,7 +311,7 @@ static int vti6_rcv(struct sk_buff *skb)
 
                if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
                        rcu_read_unlock();
-                       return 0;
+                       goto discard;
                }
 
                ipv6h = ipv6_hdr(skb);
@@ -450,15 +450,33 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        int mtu;
 
        if (!dst) {
-               fl->u.ip6.flowi6_oif = dev->ifindex;
-               fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
-               dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
-               if (dst->error) {
-                       dst_release(dst);
-                       dst = NULL;
+               switch (skb->protocol) {
+               case htons(ETH_P_IP): {
+                       struct rtable *rt;
+
+                       fl->u.ip4.flowi4_oif = dev->ifindex;
+                       fl->u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
+                       rt = __ip_route_output_key(dev_net(dev), &fl->u.ip4);
+                       if (IS_ERR(rt))
+                               goto tx_err_link_failure;
+                       dst = &rt->dst;
+                       skb_dst_set(skb, dst);
+                       break;
+               }
+               case htons(ETH_P_IPV6):
+                       fl->u.ip6.flowi6_oif = dev->ifindex;
+                       fl->u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
+                       dst = ip6_route_output(dev_net(dev), NULL, &fl->u.ip6);
+                       if (dst->error) {
+                               dst_release(dst);
+                               dst = NULL;
+                               goto tx_err_link_failure;
+                       }
+                       skb_dst_set(skb, dst);
+                       break;
+               default:
                        goto tx_err_link_failure;
                }
-               skb_dst_set(skb, dst);
        }
 
        dst_hold(dst);
index 79fc012..debdaeb 100644 (file)
@@ -183,9 +183,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                                        retv = -EBUSY;
                                        break;
                                }
-                       } else if (sk->sk_protocol != IPPROTO_TCP)
+                       } else if (sk->sk_protocol == IPPROTO_TCP) {
+                               if (sk->sk_prot != &tcpv6_prot) {
+                                       retv = -EBUSY;
+                                       break;
+                               }
                                break;
-
+                       } else {
+                               break;
+                       }
                        if (sk->sk_state != TCP_ESTABLISHED) {
                                retv = -ENOTCONN;
                                break;
index ab7f124..8c52efe 100644 (file)
@@ -268,7 +268,7 @@ static int seg6_do_srh(struct sk_buff *skb)
                skb_mac_header_rebuild(skb);
                skb_push(skb, skb->mac_len);
 
-               err = seg6_do_srh_encap(skb, tinfo->srh, NEXTHDR_NONE);
+               err = seg6_do_srh_encap(skb, tinfo->srh, IPPROTO_ETHERNET);
                if (err)
                        return err;
 
index 7cbc197..8165802 100644 (file)
@@ -282,7 +282,7 @@ static int input_action_end_dx2(struct sk_buff *skb,
        struct net_device *odev;
        struct ethhdr *eth;
 
-       if (!decap_and_validate(skb, NEXTHDR_NONE))
+       if (!decap_and_validate(skb, IPPROTO_ETHERNET))
                goto drop;
 
        if (!pskb_may_pull(skb, ETH_HLEN))
index e11bdb0..25b7ebd 100644 (file)
@@ -78,7 +78,7 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, const
 
        hlist_for_each_entry_rcu(x6spi,
                             &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
-                            list_byaddr) {
+                            list_byaddr, lockdep_is_held(&xfrm6_tunnel_spi_lock)) {
                if (xfrm6_addr_equal(&x6spi->addr, saddr))
                        return x6spi;
        }
index c80b1e1..3419ed6 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright(c) 2016 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2018 - 2020 Intel Corporation
  */
 
 #include <linux/debugfs.h>
@@ -78,6 +78,7 @@ static const char * const sta_flag_names[] = {
        FLAG(MPSP_OWNER),
        FLAG(MPSP_RECIPIENT),
        FLAG(PS_DELIVER),
+       FLAG(USES_ENCRYPTION),
 #undef FLAG
 };
 
index 0f889b9..efc1acc 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright 2015-2017 Intel Deutschland GmbH
- * Copyright 2018-2019  Intel Corporation
+ * Copyright 2018-2020  Intel Corporation
  */
 
 #include <linux/if_ether.h>
@@ -262,22 +262,29 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                          sta ? sta->sta.addr : bcast_addr, ret);
 }
 
-int ieee80211_set_tx_key(struct ieee80211_key *key)
+static int _ieee80211_set_tx_key(struct ieee80211_key *key, bool force)
 {
        struct sta_info *sta = key->sta;
        struct ieee80211_local *local = key->local;
 
        assert_key_lock(local);
 
+       set_sta_flag(sta, WLAN_STA_USES_ENCRYPTION);
+
        sta->ptk_idx = key->conf.keyidx;
 
-       if (!ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT))
+       if (force || !ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT))
                clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
        ieee80211_check_fast_xmit(sta);
 
        return 0;
 }
 
+int ieee80211_set_tx_key(struct ieee80211_key *key)
+{
+       return _ieee80211_set_tx_key(key, false);
+}
+
 static void ieee80211_pairwise_rekey(struct ieee80211_key *old,
                                     struct ieee80211_key *new)
 {
@@ -441,11 +448,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
                if (pairwise) {
                        rcu_assign_pointer(sta->ptk[idx], new);
                        if (new &&
-                           !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) {
-                               sta->ptk_idx = idx;
-                               clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
-                               ieee80211_check_fast_xmit(sta);
-                       }
+                           !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX))
+                               _ieee80211_set_tx_key(new, true);
                } else {
                        rcu_assign_pointer(sta->gtk[idx], new);
                }
index d699833..38a0383 100644 (file)
@@ -1152,7 +1152,8 @@ int mesh_nexthop_resolve(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       if (!(mpath->flags & MESH_PATH_RESOLVING))
+       if (!(mpath->flags & MESH_PATH_RESOLVING) &&
+           mesh_path_sel_is_hwmp(sdata))
                mesh_queue_preq(mpath, PREQ_Q_F_START);
 
        if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
index e041af2..88d7a69 100644 (file)
@@ -2959,7 +2959,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
            (auth_transaction == 2 &&
             ifmgd->auth_data->expected_transaction == 2)) {
                if (!ieee80211_mark_sta_auth(sdata, bssid))
-                       goto out_err;
+                       return; /* ignore frame -- wait for timeout */
        } else if (ifmgd->auth_data->algorithm == WLAN_AUTH_SAE &&
                   auth_transaction == 2) {
                sdata_info(sdata, "SAE peer confirmed\n");
@@ -2967,10 +2967,6 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
        }
 
        cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
-       return;
- out_err:
-       mutex_unlock(&sdata->local->sta_mtx);
-       /* ignore frame -- wait for timeout */
 }
 
 #define case_WLAN(type) \
index 0e05ff0..0ba98ad 100644 (file)
@@ -4114,7 +4114,7 @@ void __ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata)
 
        lockdep_assert_held(&local->sta_mtx);
 
-       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+       list_for_each_entry(sta, &local->sta_list, list) {
                if (sdata != sta->sdata &&
                    (!sta->sdata->bss || sta->sdata->bss != sdata->bss))
                        continue;
index 0f5f406..e3572be 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright (C) 2015 - 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2019 Intel Corporation
+ * Copyright (C) 2018-2020 Intel Corporation
  */
 
 #include <linux/module.h>
@@ -1049,6 +1049,11 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
        might_sleep();
        lockdep_assert_held(&local->sta_mtx);
 
+       while (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
+               ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+               WARN_ON_ONCE(ret);
+       }
+
        /* now keys can no longer be reached */
        ieee80211_free_sta_keys(local, sta);
 
index c00e285..552eed3 100644 (file)
@@ -98,6 +98,7 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_MPSP_OWNER,
        WLAN_STA_MPSP_RECIPIENT,
        WLAN_STA_PS_DELIVER,
+       WLAN_STA_USES_ENCRYPTION,
 
        NUM_WLAN_STA_FLAGS,
 };
index 87def9c..d9cca6d 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2007      Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018, 2020 Intel Corporation
  *
  * Transmit and frame generation functions.
  */
@@ -590,10 +590,13 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 
-       if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT))
+       if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) {
                tx->key = NULL;
-       else if (tx->sta &&
-                (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
+               return TX_CONTINUE;
+       }
+
+       if (tx->sta &&
+           (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx])))
                tx->key = key;
        else if (ieee80211_is_group_privacy_action(tx->skb) &&
                (key = rcu_dereference(tx->sdata->default_multicast_key)))
@@ -654,6 +657,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
                if (!skip_hw && tx->key &&
                    tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
                        info->control.hw_key = &tx->key->conf;
+       } else if (!ieee80211_is_mgmt(hdr->frame_control) && tx->sta &&
+                  test_sta_flag(tx->sta, WLAN_STA_USES_ENCRYPTION)) {
+               return TX_DROP;
        }
 
        return TX_CONTINUE;
@@ -3598,8 +3604,25 @@ begin:
        tx.skb = skb;
        tx.sdata = vif_to_sdata(info->control.vif);
 
-       if (txq->sta)
+       if (txq->sta) {
                tx.sta = container_of(txq->sta, struct sta_info, sta);
+               /*
+                * Drop unicast frames to unauthorised stations unless they are
+                * EAPOL frames from the local station.
+                */
+               if (unlikely(!ieee80211_vif_is_mesh(&tx.sdata->vif) &&
+                            tx.sdata->vif.type != NL80211_IFTYPE_OCB &&
+                            !is_multicast_ether_addr(hdr->addr1) &&
+                            !test_sta_flag(tx.sta, WLAN_STA_AUTHORIZED) &&
+                            (!(info->control.flags &
+                               IEEE80211_TX_CTRL_PORT_CTRL_PROTO) ||
+                             !ether_addr_equal(tx.sdata->vif.addr,
+                                               hdr->addr2)))) {
+                       I802_DEBUG_INC(local->tx_handlers_drop_unauth_port);
+                       ieee80211_free_txskb(&local->hw, skb);
+                       goto begin;
+               }
+       }
 
        /*
         * The key can be removed while the packet was queued, so need to call
@@ -5126,6 +5149,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ethhdr *ehdr;
+       u32 ctrl_flags = 0;
        u32 flags;
 
        /* Only accept CONTROL_PORT_PROTOCOL configured in CONNECT/ASSOCIATE
@@ -5135,6 +5159,9 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
            proto != cpu_to_be16(ETH_P_PREAUTH))
                return -EINVAL;
 
+       if (proto == sdata->control_port_protocol)
+               ctrl_flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
+
        if (unencrypted)
                flags = IEEE80211_TX_INTFL_DONT_ENCRYPT;
        else
@@ -5160,7 +5187,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev,
        skb_reset_mac_header(skb);
 
        local_bh_disable();
-       __ieee80211_subif_start_xmit(skb, skb->dev, flags, 0);
+       __ieee80211_subif_start_xmit(skb, skb->dev, flags, ctrl_flags);
        local_bh_enable();
 
        return 0;
index 45acd87..fd2c315 100644 (file)
@@ -334,6 +334,8 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
        struct mptcp_sock *msk;
        unsigned int ack_size;
        bool ret = false;
+       bool can_ack;
+       u64 ack_seq;
        u8 tcp_fin;
 
        if (skb) {
@@ -360,9 +362,22 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
                ret = true;
        }
 
+       /* passive sockets msk will set the 'can_ack' after accept(), even
+        * if the first subflow may have the already the remote key handy
+        */
+       can_ack = true;
        opts->ext_copy.use_ack = 0;
        msk = mptcp_sk(subflow->conn);
-       if (!msk || !READ_ONCE(msk->can_ack)) {
+       if (likely(msk && READ_ONCE(msk->can_ack))) {
+               ack_seq = msk->ack_seq;
+       } else if (subflow->can_ack) {
+               mptcp_crypto_key_sha(subflow->remote_key, NULL, &ack_seq);
+               ack_seq++;
+       } else {
+               can_ack = false;
+       }
+
+       if (unlikely(!can_ack)) {
                *size = ALIGN(dss_size, 4);
                return ret;
        }
@@ -375,7 +390,7 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
 
        dss_size += ack_size;
 
-       opts->ext_copy.data_ack = msk->ack_seq;
+       opts->ext_copy.data_ack = ack_seq;
        opts->ext_copy.ack64 = 1;
        opts->ext_copy.use_ack = 1;
 
index e9aa680..3c19a8e 100644 (file)
@@ -543,6 +543,11 @@ static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,
        }
 }
 
+static unsigned int mptcp_sync_mss(struct sock *sk, u32 pmtu)
+{
+       return 0;
+}
+
 static int __mptcp_init_sock(struct sock *sk)
 {
        struct mptcp_sock *msk = mptcp_sk(sk);
@@ -551,6 +556,7 @@ static int __mptcp_init_sock(struct sock *sk)
        __set_bit(MPTCP_SEND_SPACE, &msk->flags);
 
        msk->first = NULL;
+       inet_csk(sk)->icsk_sync_mss = mptcp_sync_mss;
 
        return 0;
 }
index 69c107f..8dd1758 100644 (file)
@@ -723,6 +723,20 @@ ip_set_rcu_get(struct net *net, ip_set_id_t index)
        return set;
 }
 
+static inline void
+ip_set_lock(struct ip_set *set)
+{
+       if (!set->variant->region_lock)
+               spin_lock_bh(&set->lock);
+}
+
+static inline void
+ip_set_unlock(struct ip_set *set)
+{
+       if (!set->variant->region_lock)
+               spin_unlock_bh(&set->lock);
+}
+
 int
 ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
            const struct xt_action_param *par, struct ip_set_adt_opt *opt)
@@ -744,9 +758,9 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
        if (ret == -EAGAIN) {
                /* Type requests element to be completed */
                pr_debug("element must be completed, ADD is triggered\n");
-               spin_lock_bh(&set->lock);
+               ip_set_lock(set);
                set->variant->kadt(set, skb, par, IPSET_ADD, opt);
-               spin_unlock_bh(&set->lock);
+               ip_set_unlock(set);
                ret = 1;
        } else {
                /* --return-nomatch: invert matched element */
@@ -775,9 +789,9 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
            !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
                return -IPSET_ERR_TYPE_MISMATCH;
 
-       spin_lock_bh(&set->lock);
+       ip_set_lock(set);
        ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
-       spin_unlock_bh(&set->lock);
+       ip_set_unlock(set);
 
        return ret;
 }
@@ -797,9 +811,9 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
            !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
                return -IPSET_ERR_TYPE_MISMATCH;
 
-       spin_lock_bh(&set->lock);
+       ip_set_lock(set);
        ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
-       spin_unlock_bh(&set->lock);
+       ip_set_unlock(set);
 
        return ret;
 }
@@ -1264,9 +1278,9 @@ ip_set_flush_set(struct ip_set *set)
 {
        pr_debug("set: %s\n",  set->name);
 
-       spin_lock_bh(&set->lock);
+       ip_set_lock(set);
        set->variant->flush(set);
-       spin_unlock_bh(&set->lock);
+       ip_set_unlock(set);
 }
 
 static int ip_set_flush(struct net *net, struct sock *ctnl, struct sk_buff *skb,
@@ -1713,9 +1727,9 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
        bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
 
        do {
-               spin_lock_bh(&set->lock);
+               ip_set_lock(set);
                ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
-               spin_unlock_bh(&set->lock);
+               ip_set_unlock(set);
                retried = true;
        } while (ret == -EAGAIN &&
                 set->variant->resize &&
index 7480ce5..e52d7b7 100644 (file)
@@ -7,13 +7,21 @@
 #include <linux/rcupdate.h>
 #include <linux/jhash.h>
 #include <linux/types.h>
+#include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/ipset/ip_set.h>
 
-#define __ipset_dereference_protected(p, c)    rcu_dereference_protected(p, c)
-#define ipset_dereference_protected(p, set) \
-       __ipset_dereference_protected(p, lockdep_is_held(&(set)->lock))
-
-#define rcu_dereference_bh_nfnl(p)     rcu_dereference_bh_check(p, 1)
+#define __ipset_dereference(p)         \
+       rcu_dereference_protected(p, 1)
+#define ipset_dereference_nfnl(p)      \
+       rcu_dereference_protected(p,    \
+               lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET))
+#define ipset_dereference_set(p, set)  \
+       rcu_dereference_protected(p,    \
+               lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET) || \
+               lockdep_is_held(&(set)->lock))
+#define ipset_dereference_bh_nfnl(p)   \
+       rcu_dereference_bh_check(p,     \
+               lockdep_nfnl_is_held(NFNL_SUBSYS_IPSET))
 
 /* Hashing which uses arrays to resolve clashing. The hash table is resized
  * (doubled) when searching becomes too long.
@@ -72,11 +80,35 @@ struct hbucket {
                __aligned(__alignof__(u64));
 };
 
+/* Region size for locking == 2^HTABLE_REGION_BITS */
+#define HTABLE_REGION_BITS     10
+#define ahash_numof_locks(htable_bits)         \
+       ((htable_bits) < HTABLE_REGION_BITS ? 1 \
+               : jhash_size((htable_bits) - HTABLE_REGION_BITS))
+#define ahash_sizeof_regions(htable_bits)              \
+       (ahash_numof_locks(htable_bits) * sizeof(struct ip_set_region))
+#define ahash_region(n, htable_bits)           \
+       ((n) % ahash_numof_locks(htable_bits))
+#define ahash_bucket_start(h,  htable_bits)    \
+       ((htable_bits) < HTABLE_REGION_BITS ? 0 \
+               : (h) * jhash_size(HTABLE_REGION_BITS))
+#define ahash_bucket_end(h,  htable_bits)      \
+       ((htable_bits) < HTABLE_REGION_BITS ? jhash_size(htable_bits)   \
+               : ((h) + 1) * jhash_size(HTABLE_REGION_BITS))
+
+struct htable_gc {
+       struct delayed_work dwork;
+       struct ip_set *set;     /* Set the gc belongs to */
+       u32 region;             /* Last gc run position */
+};
+
 /* The hash table: the table size stored here in order to make resizing easy */
 struct htable {
        atomic_t ref;           /* References for resizing */
-       atomic_t uref;          /* References for dumping */
+       atomic_t uref;          /* References for dumping and gc */
        u8 htable_bits;         /* size of hash table == 2^htable_bits */
+       u32 maxelem;            /* Maxelem per region */
+       struct ip_set_region *hregion;  /* Region locks and ext sizes */
        struct hbucket __rcu *bucket[0]; /* hashtable buckets */
 };
 
@@ -162,6 +194,10 @@ htable_bits(u32 hashsize)
 #define NLEN                   0
 #endif /* IP_SET_HASH_WITH_NETS */
 
+#define SET_ELEM_EXPIRED(set, d)       \
+       (SET_WITH_TIMEOUT(set) &&       \
+        ip_set_timeout_expired(ext_timeout(d, set)))
+
 #endif /* _IP_SET_HASH_GEN_H */
 
 #ifndef MTYPE
@@ -205,10 +241,12 @@ htable_bits(u32 hashsize)
 #undef mtype_test_cidrs
 #undef mtype_test
 #undef mtype_uref
-#undef mtype_expire
 #undef mtype_resize
+#undef mtype_ext_size
+#undef mtype_resize_ad
 #undef mtype_head
 #undef mtype_list
+#undef mtype_gc_do
 #undef mtype_gc
 #undef mtype_gc_init
 #undef mtype_variant
@@ -247,10 +285,12 @@ htable_bits(u32 hashsize)
 #define mtype_test_cidrs       IPSET_TOKEN(MTYPE, _test_cidrs)
 #define mtype_test             IPSET_TOKEN(MTYPE, _test)
 #define mtype_uref             IPSET_TOKEN(MTYPE, _uref)
-#define mtype_expire           IPSET_TOKEN(MTYPE, _expire)
 #define mtype_resize           IPSET_TOKEN(MTYPE, _resize)
+#define mtype_ext_size         IPSET_TOKEN(MTYPE, _ext_size)
+#define mtype_resize_ad                IPSET_TOKEN(MTYPE, _resize_ad)
 #define mtype_head             IPSET_TOKEN(MTYPE, _head)
 #define mtype_list             IPSET_TOKEN(MTYPE, _list)
+#define mtype_gc_do            IPSET_TOKEN(MTYPE, _gc_do)
 #define mtype_gc               IPSET_TOKEN(MTYPE, _gc)
 #define mtype_gc_init          IPSET_TOKEN(MTYPE, _gc_init)
 #define mtype_variant          IPSET_TOKEN(MTYPE, _variant)
@@ -275,8 +315,7 @@ htable_bits(u32 hashsize)
 /* The generic hash structure */
 struct htype {
        struct htable __rcu *table; /* the hash table */
-       struct timer_list gc;   /* garbage collection when timeout enabled */
-       struct ip_set *set;     /* attached to this ip_set */
+       struct htable_gc gc;    /* gc workqueue */
        u32 maxelem;            /* max elements in the hash */
        u32 initval;            /* random jhash init value */
 #ifdef IP_SET_HASH_WITH_MARKMASK
@@ -288,21 +327,33 @@ struct htype {
 #ifdef IP_SET_HASH_WITH_NETMASK
        u8 netmask;             /* netmask value for subnets to store */
 #endif
+       struct list_head ad;    /* Resize add|del backlist */
        struct mtype_elem next; /* temporary storage for uadd */
 #ifdef IP_SET_HASH_WITH_NETS
        struct net_prefixes nets[NLEN]; /* book-keeping of prefixes */
 #endif
 };
 
+/* ADD|DEL entries saved during resize */
+struct mtype_resize_ad {
+       struct list_head list;
+       enum ipset_adt ad;      /* ADD|DEL element */
+       struct mtype_elem d;    /* Element value */
+       struct ip_set_ext ext;  /* Extensions for ADD */
+       struct ip_set_ext mext; /* Target extensions for ADD */
+       u32 flags;              /* Flags for ADD */
+};
+
 #ifdef IP_SET_HASH_WITH_NETS
 /* Network cidr size book keeping when the hash stores different
  * sized networks. cidr == real cidr + 1 to support /0.
  */
 static void
-mtype_add_cidr(struct htype *h, u8 cidr, u8 n)
+mtype_add_cidr(struct ip_set *set, struct htype *h, u8 cidr, u8 n)
 {
        int i, j;
 
+       spin_lock_bh(&set->lock);
        /* Add in increasing prefix order, so larger cidr first */
        for (i = 0, j = -1; i < NLEN && h->nets[i].cidr[n]; i++) {
                if (j != -1) {
@@ -311,7 +362,7 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 n)
                        j = i;
                } else if (h->nets[i].cidr[n] == cidr) {
                        h->nets[CIDR_POS(cidr)].nets[n]++;
-                       return;
+                       goto unlock;
                }
        }
        if (j != -1) {
@@ -320,24 +371,29 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 n)
        }
        h->nets[i].cidr[n] = cidr;
        h->nets[CIDR_POS(cidr)].nets[n] = 1;
+unlock:
+       spin_unlock_bh(&set->lock);
 }
 
 static void
-mtype_del_cidr(struct htype *h, u8 cidr, u8 n)
+mtype_del_cidr(struct ip_set *set, struct htype *h, u8 cidr, u8 n)
 {
        u8 i, j, net_end = NLEN - 1;
 
+       spin_lock_bh(&set->lock);
        for (i = 0; i < NLEN; i++) {
                if (h->nets[i].cidr[n] != cidr)
                        continue;
                h->nets[CIDR_POS(cidr)].nets[n]--;
                if (h->nets[CIDR_POS(cidr)].nets[n] > 0)
-                       return;
+                       goto unlock;
                for (j = i; j < net_end && h->nets[j].cidr[n]; j++)
                        h->nets[j].cidr[n] = h->nets[j + 1].cidr[n];
                h->nets[j].cidr[n] = 0;
-               return;
+               goto unlock;
        }
+unlock:
+       spin_unlock_bh(&set->lock);
 }
 #endif
 
@@ -345,7 +401,7 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 n)
 static size_t
 mtype_ahash_memsize(const struct htype *h, const struct htable *t)
 {
-       return sizeof(*h) + sizeof(*t);
+       return sizeof(*h) + sizeof(*t) + ahash_sizeof_regions(t->htable_bits);
 }
 
 /* Get the ith element from the array block n */
@@ -369,24 +425,29 @@ mtype_flush(struct ip_set *set)
        struct htype *h = set->data;
        struct htable *t;
        struct hbucket *n;
-       u32 i;
-
-       t = ipset_dereference_protected(h->table, set);
-       for (i = 0; i < jhash_size(t->htable_bits); i++) {
-               n = __ipset_dereference_protected(hbucket(t, i), 1);
-               if (!n)
-                       continue;
-               if (set->extensions & IPSET_EXT_DESTROY)
-                       mtype_ext_cleanup(set, n);
-               /* FIXME: use slab cache */
-               rcu_assign_pointer(hbucket(t, i), NULL);
-               kfree_rcu(n, rcu);
+       u32 r, i;
+
+       t = ipset_dereference_nfnl(h->table);
+       for (r = 0; r < ahash_numof_locks(t->htable_bits); r++) {
+               spin_lock_bh(&t->hregion[r].lock);
+               for (i = ahash_bucket_start(r, t->htable_bits);
+                    i < ahash_bucket_end(r, t->htable_bits); i++) {
+                       n = __ipset_dereference(hbucket(t, i));
+                       if (!n)
+                               continue;
+                       if (set->extensions & IPSET_EXT_DESTROY)
+                               mtype_ext_cleanup(set, n);
+                       /* FIXME: use slab cache */
+                       rcu_assign_pointer(hbucket(t, i), NULL);
+                       kfree_rcu(n, rcu);
+               }
+               t->hregion[r].ext_size = 0;
+               t->hregion[r].elements = 0;
+               spin_unlock_bh(&t->hregion[r].lock);
        }
 #ifdef IP_SET_HASH_WITH_NETS
        memset(h->nets, 0, sizeof(h->nets));
 #endif
-       set->elements = 0;
-       set->ext_size = 0;
 }
 
 /* Destroy the hashtable part of the set */
@@ -397,7 +458,7 @@ mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy)
        u32 i;
 
        for (i = 0; i < jhash_size(t->htable_bits); i++) {
-               n = __ipset_dereference_protected(hbucket(t, i), 1);
+               n = __ipset_dereference(hbucket(t, i));
                if (!n)
                        continue;
                if (set->extensions & IPSET_EXT_DESTROY && ext_destroy)
@@ -406,6 +467,7 @@ mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy)
                kfree(n);
        }
 
+       ip_set_free(t->hregion);
        ip_set_free(t);
 }
 
@@ -414,28 +476,21 @@ static void
 mtype_destroy(struct ip_set *set)
 {
        struct htype *h = set->data;
+       struct list_head *l, *lt;
 
        if (SET_WITH_TIMEOUT(set))
-               del_timer_sync(&h->gc);
+               cancel_delayed_work_sync(&h->gc.dwork);
 
-       mtype_ahash_destroy(set,
-                           __ipset_dereference_protected(h->table, 1), true);
+       mtype_ahash_destroy(set, ipset_dereference_nfnl(h->table), true);
+       list_for_each_safe(l, lt, &h->ad) {
+               list_del(l);
+               kfree(l);
+       }
        kfree(h);
 
        set->data = NULL;
 }
 
-static void
-mtype_gc_init(struct ip_set *set, void (*gc)(struct timer_list *t))
-{
-       struct htype *h = set->data;
-
-       timer_setup(&h->gc, gc, 0);
-       mod_timer(&h->gc, jiffies + IPSET_GC_PERIOD(set->timeout) * HZ);
-       pr_debug("gc initialized, run in every %u\n",
-                IPSET_GC_PERIOD(set->timeout));
-}
-
 static bool
 mtype_same_set(const struct ip_set *a, const struct ip_set *b)
 {
@@ -454,11 +509,9 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)
               a->extensions == b->extensions;
 }
 
-/* Delete expired elements from the hashtable */
 static void
-mtype_expire(struct ip_set *set, struct htype *h)
+mtype_gc_do(struct ip_set *set, struct htype *h, struct htable *t, u32 r)
 {
-       struct htable *t;
        struct hbucket *n, *tmp;
        struct mtype_elem *data;
        u32 i, j, d;
@@ -466,10 +519,12 @@ mtype_expire(struct ip_set *set, struct htype *h)
 #ifdef IP_SET_HASH_WITH_NETS
        u8 k;
 #endif
+       u8 htable_bits = t->htable_bits;
 
-       t = ipset_dereference_protected(h->table, set);
-       for (i = 0; i < jhash_size(t->htable_bits); i++) {
-               n = __ipset_dereference_protected(hbucket(t, i), 1);
+       spin_lock_bh(&t->hregion[r].lock);
+       for (i = ahash_bucket_start(r, htable_bits);
+            i < ahash_bucket_end(r, htable_bits); i++) {
+               n = __ipset_dereference(hbucket(t, i));
                if (!n)
                        continue;
                for (j = 0, d = 0; j < n->pos; j++) {
@@ -485,58 +540,100 @@ mtype_expire(struct ip_set *set, struct htype *h)
                        smp_mb__after_atomic();
 #ifdef IP_SET_HASH_WITH_NETS
                        for (k = 0; k < IPSET_NET_COUNT; k++)
-                               mtype_del_cidr(h,
+                               mtype_del_cidr(set, h,
                                        NCIDR_PUT(DCIDR_GET(data->cidr, k)),
                                        k);
 #endif
+                       t->hregion[r].elements--;
                        ip_set_ext_destroy(set, data);
-                       set->elements--;
                        d++;
                }
                if (d >= AHASH_INIT_SIZE) {
                        if (d >= n->size) {
+                               t->hregion[r].ext_size -=
+                                       ext_size(n->size, dsize);
                                rcu_assign_pointer(hbucket(t, i), NULL);
                                kfree_rcu(n, rcu);
                                continue;
                        }
                        tmp = kzalloc(sizeof(*tmp) +
-                                     (n->size - AHASH_INIT_SIZE) * dsize,
-                                     GFP_ATOMIC);
+                               (n->size - AHASH_INIT_SIZE) * dsize,
+                               GFP_ATOMIC);
                        if (!tmp)
-                               /* Still try to delete expired elements */
+                               /* Still try to delete expired elements. */
                                continue;
                        tmp->size = n->size - AHASH_INIT_SIZE;
                        for (j = 0, d = 0; j < n->pos; j++) {
                                if (!test_bit(j, n->used))
                                        continue;
                                data = ahash_data(n, j, dsize);
-                               memcpy(tmp->value + d * dsize, data, dsize);
+                               memcpy(tmp->value + d * dsize,
+                                      data, dsize);
                                set_bit(d, tmp->used);
                                d++;
                        }
                        tmp->pos = d;
-                       set->ext_size -= ext_size(AHASH_INIT_SIZE, dsize);
+                       t->hregion[r].ext_size -=
+                               ext_size(AHASH_INIT_SIZE, dsize);
                        rcu_assign_pointer(hbucket(t, i), tmp);
                        kfree_rcu(n, rcu);
                }
        }
+       spin_unlock_bh(&t->hregion[r].lock);
 }
 
 static void
-mtype_gc(struct timer_list *t)
+mtype_gc(struct work_struct *work)
 {
-       struct htype *h = from_timer(h, t, gc);
-       struct ip_set *set = h->set;
+       struct htable_gc *gc;
+       struct ip_set *set;
+       struct htype *h;
+       struct htable *t;
+       u32 r, numof_locks;
+       unsigned int next_run;
+
+       gc = container_of(work, struct htable_gc, dwork.work);
+       set = gc->set;
+       h = set->data;
 
-       pr_debug("called\n");
        spin_lock_bh(&set->lock);
-       mtype_expire(set, h);
+       t = ipset_dereference_set(h->table, set);
+       atomic_inc(&t->uref);
+       numof_locks = ahash_numof_locks(t->htable_bits);
+       r = gc->region++;
+       if (r >= numof_locks) {
+               r = gc->region = 0;
+       }
+       next_run = (IPSET_GC_PERIOD(set->timeout) * HZ) / numof_locks;
+       if (next_run < HZ/10)
+               next_run = HZ/10;
        spin_unlock_bh(&set->lock);
 
-       h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
-       add_timer(&h->gc);
+       mtype_gc_do(set, h, t, r);
+
+       if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+               pr_debug("Table destroy after resize by expire: %p\n", t);
+               mtype_ahash_destroy(set, t, false);
+       }
+
+       queue_delayed_work(system_power_efficient_wq, &gc->dwork, next_run);
+
+}
+
+static void
+mtype_gc_init(struct htable_gc *gc)
+{
+       INIT_DEFERRABLE_WORK(&gc->dwork, mtype_gc);
+       queue_delayed_work(system_power_efficient_wq, &gc->dwork, HZ);
 }
 
+static int
+mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+         struct ip_set_ext *mext, u32 flags);
+static int
+mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
+         struct ip_set_ext *mext, u32 flags);
+
 /* Resize a hash: create a new hash table with doubling the hashsize
  * and inserting the elements to it. Repeat until we succeed or
  * fail due to memory pressures.
@@ -547,7 +644,7 @@ mtype_resize(struct ip_set *set, bool retried)
        struct htype *h = set->data;
        struct htable *t, *orig;
        u8 htable_bits;
-       size_t extsize, dsize = set->dsize;
+       size_t dsize = set->dsize;
 #ifdef IP_SET_HASH_WITH_NETS
        u8 flags;
        struct mtype_elem *tmp;
@@ -555,7 +652,9 @@ mtype_resize(struct ip_set *set, bool retried)
        struct mtype_elem *data;
        struct mtype_elem *d;
        struct hbucket *n, *m;
-       u32 i, j, key;
+       struct list_head *l, *lt;
+       struct mtype_resize_ad *x;
+       u32 i, j, r, nr, key;
        int ret;
 
 #ifdef IP_SET_HASH_WITH_NETS
@@ -563,10 +662,8 @@ mtype_resize(struct ip_set *set, bool retried)
        if (!tmp)
                return -ENOMEM;
 #endif
-       rcu_read_lock_bh();
-       orig = rcu_dereference_bh_nfnl(h->table);
+       orig = ipset_dereference_bh_nfnl(h->table);
        htable_bits = orig->htable_bits;
-       rcu_read_unlock_bh();
 
 retry:
        ret = 0;
@@ -583,88 +680,124 @@ retry:
                ret = -ENOMEM;
                goto out;
        }
+       t->hregion = ip_set_alloc(ahash_sizeof_regions(htable_bits));
+       if (!t->hregion) {
+               kfree(t);
+               ret = -ENOMEM;
+               goto out;
+       }
        t->htable_bits = htable_bits;
+       t->maxelem = h->maxelem / ahash_numof_locks(htable_bits);
+       for (i = 0; i < ahash_numof_locks(htable_bits); i++)
+               spin_lock_init(&t->hregion[i].lock);
 
-       spin_lock_bh(&set->lock);
-       orig = __ipset_dereference_protected(h->table, 1);
-       /* There can't be another parallel resizing, but dumping is possible */
+       /* There can't be another parallel resizing,
+        * but dumping, gc, kernel side add/del are possible
+        */
+       orig = ipset_dereference_bh_nfnl(h->table);
        atomic_set(&orig->ref, 1);
        atomic_inc(&orig->uref);
-       extsize = 0;
        pr_debug("attempt to resize set %s from %u to %u, t %p\n",
                 set->name, orig->htable_bits, htable_bits, orig);
-       for (i = 0; i < jhash_size(orig->htable_bits); i++) {
-               n = __ipset_dereference_protected(hbucket(orig, i), 1);
-               if (!n)
-                       continue;
-               for (j = 0; j < n->pos; j++) {
-                       if (!test_bit(j, n->used))
+       for (r = 0; r < ahash_numof_locks(orig->htable_bits); r++) {
+               /* Expire may replace a hbucket with another one */
+               rcu_read_lock_bh();
+               for (i = ahash_bucket_start(r, orig->htable_bits);
+                    i < ahash_bucket_end(r, orig->htable_bits); i++) {
+                       n = __ipset_dereference(hbucket(orig, i));
+                       if (!n)
                                continue;
-                       data = ahash_data(n, j, dsize);
+                       for (j = 0; j < n->pos; j++) {
+                               if (!test_bit(j, n->used))
+                                       continue;
+                               data = ahash_data(n, j, dsize);
+                               if (SET_ELEM_EXPIRED(set, data))
+                                       continue;
 #ifdef IP_SET_HASH_WITH_NETS
-                       /* We have readers running parallel with us,
-                        * so the live data cannot be modified.
-                        */
-                       flags = 0;
-                       memcpy(tmp, data, dsize);
-                       data = tmp;
-                       mtype_data_reset_flags(data, &flags);
+                               /* We have readers running parallel with us,
+                                * so the live data cannot be modified.
+                                */
+                               flags = 0;
+                               memcpy(tmp, data, dsize);
+                               data = tmp;
+                               mtype_data_reset_flags(data, &flags);
 #endif
-                       key = HKEY(data, h->initval, htable_bits);
-                       m = __ipset_dereference_protected(hbucket(t, key), 1);
-                       if (!m) {
-                               m = kzalloc(sizeof(*m) +
+                               key = HKEY(data, h->initval, htable_bits);
+                               m = __ipset_dereference(hbucket(t, key));
+                               nr = ahash_region(key, htable_bits);
+                               if (!m) {
+                                       m = kzalloc(sizeof(*m) +
                                            AHASH_INIT_SIZE * dsize,
                                            GFP_ATOMIC);
-                               if (!m) {
-                                       ret = -ENOMEM;
-                                       goto cleanup;
-                               }
-                               m->size = AHASH_INIT_SIZE;
-                               extsize += ext_size(AHASH_INIT_SIZE, dsize);
-                               RCU_INIT_POINTER(hbucket(t, key), m);
-                       } else if (m->pos >= m->size) {
-                               struct hbucket *ht;
-
-                               if (m->size >= AHASH_MAX(h)) {
-                                       ret = -EAGAIN;
-                               } else {
-                                       ht = kzalloc(sizeof(*ht) +
+                                       if (!m) {
+                                               ret = -ENOMEM;
+                                               goto cleanup;
+                                       }
+                                       m->size = AHASH_INIT_SIZE;
+                                       t->hregion[nr].ext_size +=
+                                               ext_size(AHASH_INIT_SIZE,
+                                                        dsize);
+                                       RCU_INIT_POINTER(hbucket(t, key), m);
+                               } else if (m->pos >= m->size) {
+                                       struct hbucket *ht;
+
+                                       if (m->size >= AHASH_MAX(h)) {
+                                               ret = -EAGAIN;
+                                       } else {
+                                               ht = kzalloc(sizeof(*ht) +
                                                (m->size + AHASH_INIT_SIZE)
                                                * dsize,
                                                GFP_ATOMIC);
-                                       if (!ht)
-                                               ret = -ENOMEM;
+                                               if (!ht)
+                                                       ret = -ENOMEM;
+                                       }
+                                       if (ret < 0)
+                                               goto cleanup;
+                                       memcpy(ht, m, sizeof(struct hbucket) +
+                                              m->size * dsize);
+                                       ht->size = m->size + AHASH_INIT_SIZE;
+                                       t->hregion[nr].ext_size +=
+                                               ext_size(AHASH_INIT_SIZE,
+                                                        dsize);
+                                       kfree(m);
+                                       m = ht;
+                                       RCU_INIT_POINTER(hbucket(t, key), ht);
                                }
-                               if (ret < 0)
-                                       goto cleanup;
-                               memcpy(ht, m, sizeof(struct hbucket) +
-                                             m->size * dsize);
-                               ht->size = m->size + AHASH_INIT_SIZE;
-                               extsize += ext_size(AHASH_INIT_SIZE, dsize);
-                               kfree(m);
-                               m = ht;
-                               RCU_INIT_POINTER(hbucket(t, key), ht);
-                       }
-                       d = ahash_data(m, m->pos, dsize);
-                       memcpy(d, data, dsize);
-                       set_bit(m->pos++, m->used);
+                               d = ahash_data(m, m->pos, dsize);
+                               memcpy(d, data, dsize);
+                               set_bit(m->pos++, m->used);
+                               t->hregion[nr].elements++;
 #ifdef IP_SET_HASH_WITH_NETS
-                       mtype_data_reset_flags(d, &flags);
+                               mtype_data_reset_flags(d, &flags);
 #endif
+                       }
                }
+               rcu_read_unlock_bh();
        }
-       rcu_assign_pointer(h->table, t);
-       set->ext_size = extsize;
 
-       spin_unlock_bh(&set->lock);
+       /* There can't be any other writer. */
+       rcu_assign_pointer(h->table, t);
 
        /* Give time to other readers of the set */
        synchronize_rcu();
 
        pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
                 orig->htable_bits, orig, t->htable_bits, t);
-       /* If there's nobody else dumping the table, destroy it */
+       /* Add/delete elements processed by the SET target during resize.
+        * Kernel-side add cannot trigger a resize and userspace actions
+        * are serialized by the mutex.
+        */
+       list_for_each_safe(l, lt, &h->ad) {
+               x = list_entry(l, struct mtype_resize_ad, list);
+               if (x->ad == IPSET_ADD) {
+                       mtype_add(set, &x->d, &x->ext, &x->mext, x->flags);
+               } else {
+                       mtype_del(set, &x->d, NULL, NULL, 0);
+               }
+               list_del(l);
+               kfree(l);
+       }
+       /* If there's nobody else using the table, destroy it */
        if (atomic_dec_and_test(&orig->uref)) {
                pr_debug("Table destroy by resize %p\n", orig);
                mtype_ahash_destroy(set, orig, false);
@@ -677,15 +810,44 @@ out:
        return ret;
 
 cleanup:
+       rcu_read_unlock_bh();
        atomic_set(&orig->ref, 0);
        atomic_dec(&orig->uref);
-       spin_unlock_bh(&set->lock);
        mtype_ahash_destroy(set, t, false);
        if (ret == -EAGAIN)
                goto retry;
        goto out;
 }
 
+/* Get the current number of elements and ext_size in the set  */
+static void
+mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size)
+{
+       struct htype *h = set->data;
+       const struct htable *t;
+       u32 i, j, r;
+       struct hbucket *n;
+       struct mtype_elem *data;
+
+       t = rcu_dereference_bh(h->table);
+       for (r = 0; r < ahash_numof_locks(t->htable_bits); r++) {
+               for (i = ahash_bucket_start(r, t->htable_bits);
+                    i < ahash_bucket_end(r, t->htable_bits); i++) {
+                       n = rcu_dereference_bh(hbucket(t, i));
+                       if (!n)
+                               continue;
+                       for (j = 0; j < n->pos; j++) {
+                               if (!test_bit(j, n->used))
+                                       continue;
+                               data = ahash_data(n, j, set->dsize);
+                               if (!SET_ELEM_EXPIRED(set, data))
+                                       (*elements)++;
+                       }
+               }
+               *ext_size += t->hregion[r].ext_size;
+       }
+}
+
 /* Add an element to a hash and update the internal counters when succeeded,
  * otherwise report the proper error code.
  */
@@ -698,32 +860,49 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        const struct mtype_elem *d = value;
        struct mtype_elem *data;
        struct hbucket *n, *old = ERR_PTR(-ENOENT);
-       int i, j = -1;
+       int i, j = -1, ret;
        bool flag_exist = flags & IPSET_FLAG_EXIST;
        bool deleted = false, forceadd = false, reuse = false;
-       u32 key, multi = 0;
+       u32 r, key, multi = 0, elements, maxelem;
 
-       if (set->elements >= h->maxelem) {
-               if (SET_WITH_TIMEOUT(set))
-                       /* FIXME: when set is full, we slow down here */
-                       mtype_expire(set, h);
-               if (set->elements >= h->maxelem && SET_WITH_FORCEADD(set))
+       rcu_read_lock_bh();
+       t = rcu_dereference_bh(h->table);
+       key = HKEY(value, h->initval, t->htable_bits);
+       r = ahash_region(key, t->htable_bits);
+       atomic_inc(&t->uref);
+       elements = t->hregion[r].elements;
+       maxelem = t->maxelem;
+       if (elements >= maxelem) {
+               u32 e;
+               if (SET_WITH_TIMEOUT(set)) {
+                       rcu_read_unlock_bh();
+                       mtype_gc_do(set, h, t, r);
+                       rcu_read_lock_bh();
+               }
+               maxelem = h->maxelem;
+               elements = 0;
+               for (e = 0; e < ahash_numof_locks(t->htable_bits); e++)
+                       elements += t->hregion[e].elements;
+               if (elements >= maxelem && SET_WITH_FORCEADD(set))
                        forceadd = true;
        }
+       rcu_read_unlock_bh();
 
-       t = ipset_dereference_protected(h->table, set);
-       key = HKEY(value, h->initval, t->htable_bits);
-       n = __ipset_dereference_protected(hbucket(t, key), 1);
+       spin_lock_bh(&t->hregion[r].lock);
+       n = rcu_dereference_bh(hbucket(t, key));
        if (!n) {
-               if (forceadd || set->elements >= h->maxelem)
+               if (forceadd || elements >= maxelem)
                        goto set_full;
                old = NULL;
                n = kzalloc(sizeof(*n) + AHASH_INIT_SIZE * set->dsize,
                            GFP_ATOMIC);
-               if (!n)
-                       return -ENOMEM;
+               if (!n) {
+                       ret = -ENOMEM;
+                       goto unlock;
+               }
                n->size = AHASH_INIT_SIZE;
-               set->ext_size += ext_size(AHASH_INIT_SIZE, set->dsize);
+               t->hregion[r].ext_size +=
+                       ext_size(AHASH_INIT_SIZE, set->dsize);
                goto copy_elem;
        }
        for (i = 0; i < n->pos; i++) {
@@ -737,38 +916,37 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                }
                data = ahash_data(n, i, set->dsize);
                if (mtype_data_equal(data, d, &multi)) {
-                       if (flag_exist ||
-                           (SET_WITH_TIMEOUT(set) &&
-                            ip_set_timeout_expired(ext_timeout(data, set)))) {
+                       if (flag_exist || SET_ELEM_EXPIRED(set, data)) {
                                /* Just the extensions could be overwritten */
                                j = i;
                                goto overwrite_extensions;
                        }
-                       return -IPSET_ERR_EXIST;
+                       ret = -IPSET_ERR_EXIST;
+                       goto unlock;
                }
                /* Reuse first timed out entry */
-               if (SET_WITH_TIMEOUT(set) &&
-                   ip_set_timeout_expired(ext_timeout(data, set)) &&
-                   j == -1) {
+               if (SET_ELEM_EXPIRED(set, data) && j == -1) {
                        j = i;
                        reuse = true;
                }
        }
        if (reuse || forceadd) {
+               if (j == -1)
+                       j = 0;
                data = ahash_data(n, j, set->dsize);
                if (!deleted) {
 #ifdef IP_SET_HASH_WITH_NETS
                        for (i = 0; i < IPSET_NET_COUNT; i++)
-                               mtype_del_cidr(h,
+                               mtype_del_cidr(set, h,
                                        NCIDR_PUT(DCIDR_GET(data->cidr, i)),
                                        i);
 #endif
                        ip_set_ext_destroy(set, data);
-                       set->elements--;
+                       t->hregion[r].elements--;
                }
                goto copy_data;
        }
-       if (set->elements >= h->maxelem)
+       if (elements >= maxelem)
                goto set_full;
        /* Create a new slot */
        if (n->pos >= n->size) {
@@ -776,28 +954,32 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                if (n->size >= AHASH_MAX(h)) {
                        /* Trigger rehashing */
                        mtype_data_next(&h->next, d);
-                       return -EAGAIN;
+                       ret = -EAGAIN;
+                       goto resize;
                }
                old = n;
                n = kzalloc(sizeof(*n) +
                            (old->size + AHASH_INIT_SIZE) * set->dsize,
                            GFP_ATOMIC);
-               if (!n)
-                       return -ENOMEM;
+               if (!n) {
+                       ret = -ENOMEM;
+                       goto unlock;
+               }
                memcpy(n, old, sizeof(struct hbucket) +
                       old->size * set->dsize);
                n->size = old->size + AHASH_INIT_SIZE;
-               set->ext_size += ext_size(AHASH_INIT_SIZE, set->dsize);
+               t->hregion[r].ext_size +=
+                       ext_size(AHASH_INIT_SIZE, set->dsize);
        }
 
 copy_elem:
        j = n->pos++;
        data = ahash_data(n, j, set->dsize);
 copy_data:
-       set->elements++;
+       t->hregion[r].elements++;
 #ifdef IP_SET_HASH_WITH_NETS
        for (i = 0; i < IPSET_NET_COUNT; i++)
-               mtype_add_cidr(h, NCIDR_PUT(DCIDR_GET(d->cidr, i)), i);
+               mtype_add_cidr(set, h, NCIDR_PUT(DCIDR_GET(d->cidr, i)), i);
 #endif
        memcpy(data, d, sizeof(struct mtype_elem));
 overwrite_extensions:
@@ -820,13 +1002,41 @@ overwrite_extensions:
                if (old)
                        kfree_rcu(old, rcu);
        }
+       ret = 0;
+resize:
+       spin_unlock_bh(&t->hregion[r].lock);
+       if (atomic_read(&t->ref) && ext->target) {
+               /* Resize is in process and kernel side add, save values */
+               struct mtype_resize_ad *x;
+
+               x = kzalloc(sizeof(struct mtype_resize_ad), GFP_ATOMIC);
+               if (!x)
+                       /* Don't bother */
+                       goto out;
+               x->ad = IPSET_ADD;
+               memcpy(&x->d, value, sizeof(struct mtype_elem));
+               memcpy(&x->ext, ext, sizeof(struct ip_set_ext));
+               memcpy(&x->mext, mext, sizeof(struct ip_set_ext));
+               x->flags = flags;
+               spin_lock_bh(&set->lock);
+               list_add_tail(&x->list, &h->ad);
+               spin_unlock_bh(&set->lock);
+       }
+       goto out;
 
-       return 0;
 set_full:
        if (net_ratelimit())
                pr_warn("Set %s is full, maxelem %u reached\n",
-                       set->name, h->maxelem);
-       return -IPSET_ERR_HASH_FULL;
+                       set->name, maxelem);
+       ret = -IPSET_ERR_HASH_FULL;
+unlock:
+       spin_unlock_bh(&t->hregion[r].lock);
+out:
+       if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+               pr_debug("Table destroy after resize by add: %p\n", t);
+               mtype_ahash_destroy(set, t, false);
+       }
+       return ret;
 }
 
 /* Delete an element from the hash and free up space if possible.
@@ -840,13 +1050,23 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        const struct mtype_elem *d = value;
        struct mtype_elem *data;
        struct hbucket *n;
-       int i, j, k, ret = -IPSET_ERR_EXIST;
+       struct mtype_resize_ad *x = NULL;
+       int i, j, k, r, ret = -IPSET_ERR_EXIST;
        u32 key, multi = 0;
        size_t dsize = set->dsize;
 
-       t = ipset_dereference_protected(h->table, set);
+       /* Userspace add and resize is excluded by the mutex.
+        * Kernespace add does not trigger resize.
+        */
+       rcu_read_lock_bh();
+       t = rcu_dereference_bh(h->table);
        key = HKEY(value, h->initval, t->htable_bits);
-       n = __ipset_dereference_protected(hbucket(t, key), 1);
+       r = ahash_region(key, t->htable_bits);
+       atomic_inc(&t->uref);
+       rcu_read_unlock_bh();
+
+       spin_lock_bh(&t->hregion[r].lock);
+       n = rcu_dereference_bh(hbucket(t, key));
        if (!n)
                goto out;
        for (i = 0, k = 0; i < n->pos; i++) {
@@ -857,8 +1077,7 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                data = ahash_data(n, i, dsize);
                if (!mtype_data_equal(data, d, &multi))
                        continue;
-               if (SET_WITH_TIMEOUT(set) &&
-                   ip_set_timeout_expired(ext_timeout(data, set)))
+               if (SET_ELEM_EXPIRED(set, data))
                        goto out;
 
                ret = 0;
@@ -866,20 +1085,33 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                smp_mb__after_atomic();
                if (i + 1 == n->pos)
                        n->pos--;
-               set->elements--;
+               t->hregion[r].elements--;
 #ifdef IP_SET_HASH_WITH_NETS
                for (j = 0; j < IPSET_NET_COUNT; j++)
-                       mtype_del_cidr(h, NCIDR_PUT(DCIDR_GET(d->cidr, j)),
-                                      j);
+                       mtype_del_cidr(set, h,
+                                      NCIDR_PUT(DCIDR_GET(d->cidr, j)), j);
 #endif
                ip_set_ext_destroy(set, data);
 
+               if (atomic_read(&t->ref) && ext->target) {
+                       /* Resize is in process and kernel side del,
+                        * save values
+                        */
+                       x = kzalloc(sizeof(struct mtype_resize_ad),
+                                   GFP_ATOMIC);
+                       if (x) {
+                               x->ad = IPSET_DEL;
+                               memcpy(&x->d, value,
+                                      sizeof(struct mtype_elem));
+                               x->flags = flags;
+                       }
+               }
                for (; i < n->pos; i++) {
                        if (!test_bit(i, n->used))
                                k++;
                }
                if (n->pos == 0 && k == 0) {
-                       set->ext_size -= ext_size(n->size, dsize);
+                       t->hregion[r].ext_size -= ext_size(n->size, dsize);
                        rcu_assign_pointer(hbucket(t, key), NULL);
                        kfree_rcu(n, rcu);
                } else if (k >= AHASH_INIT_SIZE) {
@@ -898,7 +1130,8 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                                k++;
                        }
                        tmp->pos = k;
-                       set->ext_size -= ext_size(AHASH_INIT_SIZE, dsize);
+                       t->hregion[r].ext_size -=
+                               ext_size(AHASH_INIT_SIZE, dsize);
                        rcu_assign_pointer(hbucket(t, key), tmp);
                        kfree_rcu(n, rcu);
                }
@@ -906,6 +1139,16 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        }
 
 out:
+       spin_unlock_bh(&t->hregion[r].lock);
+       if (x) {
+               spin_lock_bh(&set->lock);
+               list_add(&x->list, &h->ad);
+               spin_unlock_bh(&set->lock);
+       }
+       if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
+               pr_debug("Table destroy after resize by del: %p\n", t);
+               mtype_ahash_destroy(set, t, false);
+       }
        return ret;
 }
 
@@ -991,6 +1234,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        int i, ret = 0;
        u32 key, multi = 0;
 
+       rcu_read_lock_bh();
        t = rcu_dereference_bh(h->table);
 #ifdef IP_SET_HASH_WITH_NETS
        /* If we test an IP address and not a network address,
@@ -1022,6 +1266,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
                        goto out;
        }
 out:
+       rcu_read_unlock_bh();
        return ret;
 }
 
@@ -1033,23 +1278,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
        const struct htable *t;
        struct nlattr *nested;
        size_t memsize;
+       u32 elements = 0;
+       size_t ext_size = 0;
        u8 htable_bits;
 
-       /* If any members have expired, set->elements will be wrong
-        * mytype_expire function will update it with the right count.
-        * we do not hold set->lock here, so grab it first.
-        * set->elements can still be incorrect in the case of a huge set,
-        * because elements might time out during the listing.
-        */
-       if (SET_WITH_TIMEOUT(set)) {
-               spin_lock_bh(&set->lock);
-               mtype_expire(set, h);
-               spin_unlock_bh(&set->lock);
-       }
-
        rcu_read_lock_bh();
-       t = rcu_dereference_bh_nfnl(h->table);
-       memsize = mtype_ahash_memsize(h, t) + set->ext_size;
+       t = rcu_dereference_bh(h->table);
+       mtype_ext_size(set, &elements, &ext_size);
+       memsize = mtype_ahash_memsize(h, t) + ext_size + set->ext_size;
        htable_bits = t->htable_bits;
        rcu_read_unlock_bh();
 
@@ -1071,7 +1307,7 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
 #endif
        if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref)) ||
            nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
-           nla_put_net32(skb, IPSET_ATTR_ELEMENTS, htonl(set->elements)))
+           nla_put_net32(skb, IPSET_ATTR_ELEMENTS, htonl(elements)))
                goto nla_put_failure;
        if (unlikely(ip_set_put_flags(skb, set)))
                goto nla_put_failure;
@@ -1091,15 +1327,15 @@ mtype_uref(struct ip_set *set, struct netlink_callback *cb, bool start)
 
        if (start) {
                rcu_read_lock_bh();
-               t = rcu_dereference_bh_nfnl(h->table);
+               t = ipset_dereference_bh_nfnl(h->table);
                atomic_inc(&t->uref);
                cb->args[IPSET_CB_PRIVATE] = (unsigned long)t;
                rcu_read_unlock_bh();
        } else if (cb->args[IPSET_CB_PRIVATE]) {
                t = (struct htable *)cb->args[IPSET_CB_PRIVATE];
                if (atomic_dec_and_test(&t->uref) && atomic_read(&t->ref)) {
-                       /* Resizing didn't destroy the hash table */
-                       pr_debug("Table destroy by dump: %p\n", t);
+                       pr_debug("Table destroy after resize "
+                                " by dump: %p\n", t);
                        mtype_ahash_destroy(set, t, false);
                }
                cb->args[IPSET_CB_PRIVATE] = 0;
@@ -1141,8 +1377,7 @@ mtype_list(const struct ip_set *set,
                        if (!test_bit(i, n->used))
                                continue;
                        e = ahash_data(n, i, set->dsize);
-                       if (SET_WITH_TIMEOUT(set) &&
-                           ip_set_timeout_expired(ext_timeout(e, set)))
+                       if (SET_ELEM_EXPIRED(set, e))
                                continue;
                        pr_debug("list hash %lu hbucket %p i %u, data %p\n",
                                 cb->args[IPSET_CB_ARG0], n, i, e);
@@ -1208,6 +1443,7 @@ static const struct ip_set_type_variant mtype_variant = {
        .uref   = mtype_uref,
        .resize = mtype_resize,
        .same_set = mtype_same_set,
+       .region_lock = true,
 };
 
 #ifdef IP_SET_EMIT_CREATE
@@ -1226,6 +1462,7 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
        size_t hsize;
        struct htype *h;
        struct htable *t;
+       u32 i;
 
        pr_debug("Create set %s with family %s\n",
                 set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
@@ -1294,6 +1531,15 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
                kfree(h);
                return -ENOMEM;
        }
+       t->hregion = ip_set_alloc(ahash_sizeof_regions(hbits));
+       if (!t->hregion) {
+               kfree(t);
+               kfree(h);
+               return -ENOMEM;
+       }
+       h->gc.set = set;
+       for (i = 0; i < ahash_numof_locks(hbits); i++)
+               spin_lock_init(&t->hregion[i].lock);
        h->maxelem = maxelem;
 #ifdef IP_SET_HASH_WITH_NETMASK
        h->netmask = netmask;
@@ -1304,9 +1550,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
        get_random_bytes(&h->initval, sizeof(h->initval));
 
        t->htable_bits = hbits;
+       t->maxelem = h->maxelem / ahash_numof_locks(hbits);
        RCU_INIT_POINTER(h->table, t);
 
-       h->set = set;
+       INIT_LIST_HEAD(&h->ad);
        set->data = h;
 #ifndef IP_SET_PROTO_UNDEF
        if (set->family == NFPROTO_IPV4) {
@@ -1329,12 +1576,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 #ifndef IP_SET_PROTO_UNDEF
                if (set->family == NFPROTO_IPV4)
 #endif
-                       IPSET_TOKEN(HTYPE, 4_gc_init)(set,
-                               IPSET_TOKEN(HTYPE, 4_gc));
+                       IPSET_TOKEN(HTYPE, 4_gc_init)(&h->gc);
 #ifndef IP_SET_PROTO_UNDEF
                else
-                       IPSET_TOKEN(HTYPE, 6_gc_init)(set,
-                               IPSET_TOKEN(HTYPE, 6_gc));
+                       IPSET_TOKEN(HTYPE, 6_gc_init)(&h->gc);
 #endif
        }
        pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
index 410809c..4912069 100644 (file)
@@ -411,7 +411,7 @@ static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                *pos = cpu + 1;
                return per_cpu_ptr(net->ct.stat, cpu);
        }
-
+       (*pos)++;
        return NULL;
 }
 
index 8af28e1..70ebeba 100644 (file)
@@ -554,6 +554,9 @@ void nf_flow_table_free(struct nf_flowtable *flow_table)
        nf_flow_table_iterate(flow_table, nf_flow_table_do_cleanup, NULL);
        nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step, flow_table);
        nf_flow_table_offload_flush(flow_table);
+       if (nf_flowtable_hw_offload(flow_table))
+               nf_flow_table_iterate(flow_table, nf_flow_offload_gc_step,
+                                     flow_table);
        rhashtable_destroy(&flow_table->rhashtable);
 }
 EXPORT_SYMBOL_GPL(nf_flow_table_free);
index 9e563fd..ba775ae 100644 (file)
@@ -146,11 +146,13 @@ static int nf_flow_nat_ip(const struct flow_offload *flow, struct sk_buff *skb,
 
        if (test_bit(NF_FLOW_SNAT, &flow->flags) &&
            (nf_flow_snat_port(flow, skb, thoff, iph->protocol, dir) < 0 ||
-            nf_flow_snat_ip(flow, skb, iph, thoff, dir) < 0))
+            nf_flow_snat_ip(flow, skb, ip_hdr(skb), thoff, dir) < 0))
                return -1;
+
+       iph = ip_hdr(skb);
        if (test_bit(NF_FLOW_DNAT, &flow->flags) &&
            (nf_flow_dnat_port(flow, skb, thoff, iph->protocol, dir) < 0 ||
-            nf_flow_dnat_ip(flow, skb, iph, thoff, dir) < 0))
+            nf_flow_dnat_ip(flow, skb, ip_hdr(skb), thoff, dir) < 0))
                return -1;
 
        return 0;
@@ -189,6 +191,7 @@ static int nf_flow_tuple_ip(struct sk_buff *skb, const struct net_device *dev,
        if (!pskb_may_pull(skb, thoff + sizeof(*ports)))
                return -1;
 
+       iph = ip_hdr(skb);
        ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
 
        tuple->src_v4.s_addr    = iph->saddr;
@@ -426,11 +429,13 @@ static int nf_flow_nat_ipv6(const struct flow_offload *flow,
 
        if (test_bit(NF_FLOW_SNAT, &flow->flags) &&
            (nf_flow_snat_port(flow, skb, thoff, ip6h->nexthdr, dir) < 0 ||
-            nf_flow_snat_ipv6(flow, skb, ip6h, thoff, dir) < 0))
+            nf_flow_snat_ipv6(flow, skb, ipv6_hdr(skb), thoff, dir) < 0))
                return -1;
+
+       ip6h = ipv6_hdr(skb);
        if (test_bit(NF_FLOW_DNAT, &flow->flags) &&
            (nf_flow_dnat_port(flow, skb, thoff, ip6h->nexthdr, dir) < 0 ||
-            nf_flow_dnat_ipv6(flow, skb, ip6h, thoff, dir) < 0))
+            nf_flow_dnat_ipv6(flow, skb, ipv6_hdr(skb), thoff, dir) < 0))
                return -1;
 
        return 0;
@@ -459,6 +464,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
        if (!pskb_may_pull(skb, thoff + sizeof(*ports)))
                return -1;
 
+       ip6h = ipv6_hdr(skb);
        ports = (struct flow_ports *)(skb_network_header(skb) + thoff);
 
        tuple->src_v6           = ip6h->saddr;
index 06f00cd..f2c22c6 100644 (file)
@@ -87,6 +87,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
        default:
                return -EOPNOTSUPP;
        }
+       mask->control.addr_type = 0xffff;
        match->dissector.used_keys |= BIT(key->control.addr_type);
        mask->basic.n_proto = 0xffff;
 
index b0930d4..b9cbe1e 100644 (file)
@@ -267,7 +267,7 @@ static void *synproxy_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
                *pos = cpu + 1;
                return per_cpu_ptr(snet->stats, cpu);
        }
-
+       (*pos)++;
        return NULL;
 }
 
index d1318bd..d11f1a7 100644 (file)
@@ -1405,6 +1405,11 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
                                              lockdep_commit_lock_is_held(net));
                if (nft_dump_stats(skb, stats))
                        goto nla_put_failure;
+
+               if ((chain->flags & NFT_CHAIN_HW_OFFLOAD) &&
+                   nla_put_be32(skb, NFTA_CHAIN_FLAGS,
+                                htonl(NFT_CHAIN_HW_OFFLOAD)))
+                       goto nla_put_failure;
        }
 
        if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
@@ -5077,6 +5082,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                                err = -EBUSY;
                        else if (!(nlmsg_flags & NLM_F_EXCL))
                                err = 0;
+               } else if (err == -ENOTEMPTY) {
+                       /* ENOTEMPTY reports overlapping between this element
+                        * and an existing one.
+                        */
+                       err = -EEXIST;
                }
                goto err_element_clash;
        }
@@ -6300,8 +6310,13 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
                goto err4;
 
        err = nft_register_flowtable_net_hooks(ctx.net, table, flowtable);
-       if (err < 0)
+       if (err < 0) {
+               list_for_each_entry_safe(hook, next, &flowtable->hook_list, list) {
+                       list_del_rcu(&hook->list);
+                       kfree_rcu(hook, rcu);
+               }
                goto err4;
+       }
 
        err = nft_trans_flowtable_add(&ctx, NFT_MSG_NEWFLOWTABLE, flowtable);
        if (err < 0)
@@ -7378,13 +7393,8 @@ static void nf_tables_module_autoload(struct net *net)
        list_splice_init(&net->nft.module_list, &module_list);
        mutex_unlock(&net->nft.commit_mutex);
        list_for_each_entry_safe(req, next, &module_list, list) {
-               if (req->done) {
-                       list_del(&req->list);
-                       kfree(req);
-               } else {
-                       request_module("%s", req->module);
-                       req->done = true;
-               }
+               request_module("%s", req->module);
+               req->done = true;
        }
        mutex_lock(&net->nft.commit_mutex);
        list_splice(&module_list, &net->nft.module_list);
@@ -8167,6 +8177,7 @@ static void __net_exit nf_tables_exit_net(struct net *net)
        __nft_release_tables(net);
        mutex_unlock(&net->nft.commit_mutex);
        WARN_ON_ONCE(!list_empty(&net->nft.tables));
+       WARN_ON_ONCE(!list_empty(&net->nft.module_list));
 }
 
 static struct pernet_operations nf_tables_net_ops = {
index de3a959..a5f294a 100644 (file)
@@ -742,6 +742,8 @@ static const struct nla_policy nfnl_cthelper_policy[NFCTH_MAX+1] = {
        [NFCTH_NAME] = { .type = NLA_NUL_STRING,
                         .len = NF_CT_HELPER_NAME_LEN-1 },
        [NFCTH_QUEUE_NUM] = { .type = NLA_U32, },
+       [NFCTH_PRIV_DATA_LEN] = { .type = NLA_U32, },
+       [NFCTH_STATUS] = { .type = NLA_U32, },
 };
 
 static const struct nfnl_callback nfnl_cthelper_cb[NFNL_MSG_CTHELPER_MAX] = {
index ff9ac8a..eac4a90 100644 (file)
@@ -89,6 +89,7 @@ static const struct nft_chain_type nft_chain_nat_inet = {
        .name           = "nat",
        .type           = NFT_CHAIN_T_NAT,
        .family         = NFPROTO_INET,
+       .owner          = THIS_MODULE,
        .hook_mask      = (1 << NF_INET_PRE_ROUTING) |
                          (1 << NF_INET_LOCAL_IN) |
                          (1 << NF_INET_LOCAL_OUT) |
index aba11c2..3087e23 100644 (file)
@@ -28,6 +28,9 @@ static void nft_fwd_netdev_eval(const struct nft_expr *expr,
        struct nft_fwd_netdev *priv = nft_expr_priv(expr);
        int oif = regs->data[priv->sreg_dev];
 
+       /* This is used by ifb only. */
+       skb_set_redirected(pkt->skb, true);
+
        nf_fwd_netdev_egress(pkt, oif);
        regs->verdict.code = NF_STOLEN;
 }
@@ -190,6 +193,13 @@ nla_put_failure:
        return -1;
 }
 
+static int nft_fwd_validate(const struct nft_ctx *ctx,
+                           const struct nft_expr *expr,
+                           const struct nft_data **data)
+{
+       return nft_chain_validate_hooks(ctx->chain, (1 << NF_NETDEV_INGRESS));
+}
+
 static struct nft_expr_type nft_fwd_netdev_type;
 static const struct nft_expr_ops nft_fwd_neigh_netdev_ops = {
        .type           = &nft_fwd_netdev_type,
@@ -197,6 +207,7 @@ static const struct nft_expr_ops nft_fwd_neigh_netdev_ops = {
        .eval           = nft_fwd_neigh_eval,
        .init           = nft_fwd_neigh_init,
        .dump           = nft_fwd_neigh_dump,
+       .validate       = nft_fwd_validate,
 };
 
 static const struct nft_expr_ops nft_fwd_netdev_ops = {
@@ -205,6 +216,7 @@ static const struct nft_expr_ops nft_fwd_netdev_ops = {
        .eval           = nft_fwd_netdev_eval,
        .init           = nft_fwd_netdev_init,
        .dump           = nft_fwd_netdev_dump,
+       .validate       = nft_fwd_validate,
        .offload        = nft_fwd_netdev_offload,
 };
 
index 1993af3..a7de3a5 100644 (file)
@@ -129,6 +129,7 @@ static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = {
        [NFTA_PAYLOAD_LEN]              = { .type = NLA_U32 },
        [NFTA_PAYLOAD_CSUM_TYPE]        = { .type = NLA_U32 },
        [NFTA_PAYLOAD_CSUM_OFFSET]      = { .type = NLA_U32 },
+       [NFTA_PAYLOAD_CSUM_FLAGS]       = { .type = NLA_U32 },
 };
 
 static int nft_payload_init(const struct nft_ctx *ctx,
index feac855..ef7e8ad 100644 (file)
@@ -1098,21 +1098,41 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
        struct nft_pipapo_field *f;
        int i, bsize_max, err = 0;
 
+       if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
+               end = (const u8 *)nft_set_ext_key_end(ext)->data;
+       else
+               end = start;
+
        dup = pipapo_get(net, set, start, genmask);
-       if (PTR_ERR(dup) == -ENOENT) {
-               if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END)) {
-                       end = (const u8 *)nft_set_ext_key_end(ext)->data;
-                       dup = pipapo_get(net, set, end, nft_genmask_next(net));
-               } else {
-                       end = start;
+       if (!IS_ERR(dup)) {
+               /* Check if we already have the same exact entry */
+               const struct nft_data *dup_key, *dup_end;
+
+               dup_key = nft_set_ext_key(&dup->ext);
+               if (nft_set_ext_exists(&dup->ext, NFT_SET_EXT_KEY_END))
+                       dup_end = nft_set_ext_key_end(&dup->ext);
+               else
+                       dup_end = dup_key;
+
+               if (!memcmp(start, dup_key->data, sizeof(*dup_key->data)) &&
+                   !memcmp(end, dup_end->data, sizeof(*dup_end->data))) {
+                       *ext2 = &dup->ext;
+                       return -EEXIST;
                }
+
+               return -ENOTEMPTY;
+       }
+
+       if (PTR_ERR(dup) == -ENOENT) {
+               /* Look for partially overlapping entries */
+               dup = pipapo_get(net, set, end, nft_genmask_next(net));
        }
 
        if (PTR_ERR(dup) != -ENOENT) {
                if (IS_ERR(dup))
                        return PTR_ERR(dup);
                *ext2 = &dup->ext;
-               return -EEXIST;
+               return -ENOTEMPTY;
        }
 
        /* Validate */
@@ -1766,11 +1786,13 @@ static bool pipapo_match_field(struct nft_pipapo_field *f,
 static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
                              const struct nft_set_elem *elem)
 {
-       const u8 *data = (const u8 *)elem->key.val.data;
        struct nft_pipapo *priv = nft_set_priv(set);
        struct nft_pipapo_match *m = priv->clone;
+       struct nft_pipapo_elem *e = elem->priv;
        int rules_f0, first_rule = 0;
-       struct nft_pipapo_elem *e;
+       const u8 *data;
+
+       data = (const u8 *)nft_set_ext_key(&e->ext);
 
        e = pipapo_get(net, set, data, 0);
        if (IS_ERR(e))
index 5000b93..8617fc1 100644 (file)
@@ -33,6 +33,11 @@ static bool nft_rbtree_interval_end(const struct nft_rbtree_elem *rbe)
               (*nft_set_ext_flags(&rbe->ext) & NFT_SET_ELEM_INTERVAL_END);
 }
 
+static bool nft_rbtree_interval_start(const struct nft_rbtree_elem *rbe)
+{
+       return !nft_rbtree_interval_end(rbe);
+}
+
 static bool nft_rbtree_equal(const struct nft_set *set, const void *this,
                             const struct nft_rbtree_elem *interval)
 {
@@ -64,7 +69,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
                        if (interval &&
                            nft_rbtree_equal(set, this, interval) &&
                            nft_rbtree_interval_end(rbe) &&
-                           !nft_rbtree_interval_end(interval))
+                           nft_rbtree_interval_start(interval))
                                continue;
                        interval = rbe;
                } else if (d > 0)
@@ -89,7 +94,7 @@ static bool __nft_rbtree_lookup(const struct net *net, const struct nft_set *set
 
        if (set->flags & NFT_SET_INTERVAL && interval != NULL &&
            nft_set_elem_active(&interval->ext, genmask) &&
-           !nft_rbtree_interval_end(interval)) {
+           nft_rbtree_interval_start(interval)) {
                *ext = &interval->ext;
                return true;
        }
@@ -208,8 +213,43 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
        u8 genmask = nft_genmask_next(net);
        struct nft_rbtree_elem *rbe;
        struct rb_node *parent, **p;
+       bool overlap = false;
        int d;
 
+       /* Detect overlaps as we descend the tree. Set the flag in these cases:
+        *
+        * a1. |__ _ _?  >|__ _ _  (insert start after existing start)
+        * a2. _ _ __>|  ?_ _ __|  (insert end before existing end)
+        * a3. _ _ ___|  ?_ _ _>|  (insert end after existing end)
+        * a4. >|__ _ _   _ _ __|  (insert start before existing end)
+        *
+        * and clear it later on, as we eventually reach the points indicated by
+        * '?' above, in the cases described below. We'll always meet these
+        * later, locally, due to tree ordering, and overlaps for the intervals
+        * that are the closest together are always evaluated last.
+        *
+        * b1. |__ _ _!  >|__ _ _  (insert start after existing end)
+        * b2. _ _ __>|  !_ _ __|  (insert end before existing start)
+        * b3. !_____>|            (insert end after existing start)
+        *
+        * Case a4. resolves to b1.:
+        * - if the inserted start element is the leftmost, because the '0'
+        *   element in the tree serves as end element
+        * - otherwise, if an existing end is found. Note that end elements are
+        *   always inserted after corresponding start elements.
+        *
+        * For a new, rightmost pair of elements, we'll hit cases b1. and b3.,
+        * in that order.
+        *
+        * The flag is also cleared in two special cases:
+        *
+        * b4. |__ _ _!|<_ _ _   (insert start right before existing end)
+        * b5. |__ _ >|!__ _ _   (insert end right after existing start)
+        *
+        * which always happen as last step and imply that no further
+        * overlapping is possible.
+        */
+
        parent = NULL;
        p = &priv->root.rb_node;
        while (*p != NULL) {
@@ -218,17 +258,42 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                d = memcmp(nft_set_ext_key(&rbe->ext),
                           nft_set_ext_key(&new->ext),
                           set->klen);
-               if (d < 0)
+               if (d < 0) {
                        p = &parent->rb_left;
-               else if (d > 0)
+
+                       if (nft_rbtree_interval_start(new)) {
+                               overlap = nft_rbtree_interval_start(rbe) &&
+                                         nft_set_elem_active(&rbe->ext,
+                                                             genmask);
+                       } else {
+                               overlap = nft_rbtree_interval_end(rbe) &&
+                                         nft_set_elem_active(&rbe->ext,
+                                                             genmask);
+                       }
+               } else if (d > 0) {
                        p = &parent->rb_right;
-               else {
+
+                       if (nft_rbtree_interval_end(new)) {
+                               overlap = nft_rbtree_interval_end(rbe) &&
+                                         nft_set_elem_active(&rbe->ext,
+                                                             genmask);
+                       } else if (nft_rbtree_interval_end(rbe) &&
+                                  nft_set_elem_active(&rbe->ext, genmask)) {
+                               overlap = true;
+                       }
+               } else {
                        if (nft_rbtree_interval_end(rbe) &&
-                           !nft_rbtree_interval_end(new)) {
+                           nft_rbtree_interval_start(new)) {
                                p = &parent->rb_left;
-                       } else if (!nft_rbtree_interval_end(rbe) &&
+
+                               if (nft_set_elem_active(&rbe->ext, genmask))
+                                       overlap = false;
+                       } else if (nft_rbtree_interval_start(rbe) &&
                                   nft_rbtree_interval_end(new)) {
                                p = &parent->rb_right;
+
+                               if (nft_set_elem_active(&rbe->ext, genmask))
+                                       overlap = false;
                        } else if (nft_set_elem_active(&rbe->ext, genmask)) {
                                *ext = &rbe->ext;
                                return -EEXIST;
@@ -237,6 +302,10 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                        }
                }
        }
+
+       if (overlap)
+               return -ENOTEMPTY;
+
        rb_link_node_rcu(&new->node, parent, p);
        rb_insert_color(&new->node, &priv->root);
        return 0;
@@ -317,10 +386,10 @@ static void *nft_rbtree_deactivate(const struct net *net,
                        parent = parent->rb_right;
                else {
                        if (nft_rbtree_interval_end(rbe) &&
-                           !nft_rbtree_interval_end(this)) {
+                           nft_rbtree_interval_start(this)) {
                                parent = parent->rb_left;
                                continue;
-                       } else if (!nft_rbtree_interval_end(rbe) &&
+                       } else if (nft_rbtree_interval_start(rbe) &&
                                   nft_rbtree_interval_end(this)) {
                                parent = parent->rb_right;
                                continue;
index 4c3f2e2..764e886 100644 (file)
@@ -339,6 +339,8 @@ static const struct nla_policy nft_tunnel_key_policy[NFTA_TUNNEL_KEY_MAX + 1] =
        [NFTA_TUNNEL_KEY_FLAGS] = { .type = NLA_U32, },
        [NFTA_TUNNEL_KEY_TOS]   = { .type = NLA_U8, },
        [NFTA_TUNNEL_KEY_TTL]   = { .type = NLA_U8, },
+       [NFTA_TUNNEL_KEY_SPORT] = { .type = NLA_U16, },
+       [NFTA_TUNNEL_KEY_DPORT] = { .type = NLA_U16, },
        [NFTA_TUNNEL_KEY_OPTS]  = { .type = NLA_NESTED, },
 };
 
index e27c6c5..cd2b034 100644 (file)
@@ -1551,6 +1551,9 @@ static void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos,
        uint8_t nfproto = (unsigned long)PDE_DATA(file_inode(seq->file));
        struct nf_mttg_trav *trav = seq->private;
 
+       if (ppos != NULL)
+               ++(*ppos);
+
        switch (trav->class) {
        case MTTG_TRAV_INIT:
                trav->class = MTTG_TRAV_NFP_UNSPEC;
@@ -1576,9 +1579,6 @@ static void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos,
        default:
                return NULL;
        }
-
-       if (ppos != NULL)
-               ++*ppos;
        return trav;
 }
 
index 7a2c4b8..8c835ad 100644 (file)
@@ -402,15 +402,6 @@ static void htable_remove_proc_entry(struct xt_hashlimit_htable *hinfo)
                remove_proc_entry(hinfo->name, parent);
 }
 
-static void htable_destroy(struct xt_hashlimit_htable *hinfo)
-{
-       cancel_delayed_work_sync(&hinfo->gc_work);
-       htable_remove_proc_entry(hinfo);
-       htable_selective_cleanup(hinfo, true);
-       kfree(hinfo->name);
-       vfree(hinfo);
-}
-
 static struct xt_hashlimit_htable *htable_find_get(struct net *net,
                                                   const char *name,
                                                   u_int8_t family)
@@ -432,8 +423,13 @@ static void htable_put(struct xt_hashlimit_htable *hinfo)
 {
        if (refcount_dec_and_mutex_lock(&hinfo->use, &hashlimit_mutex)) {
                hlist_del(&hinfo->node);
+               htable_remove_proc_entry(hinfo);
                mutex_unlock(&hashlimit_mutex);
-               htable_destroy(hinfo);
+
+               cancel_delayed_work_sync(&hinfo->gc_work);
+               htable_selective_cleanup(hinfo, true);
+               kfree(hinfo->name);
+               vfree(hinfo);
        }
 }
 
index 0a97080..225a7ab 100644 (file)
@@ -492,12 +492,12 @@ static void *recent_seq_next(struct seq_file *seq, void *v, loff_t *pos)
        const struct recent_entry *e = v;
        const struct list_head *head = e->list.next;
 
+       (*pos)++;
        while (head == &t->iphash[st->bucket]) {
                if (++st->bucket >= ip_list_hash_size)
                        return NULL;
                head = t->iphash[st->bucket].next;
        }
-       (*pos)++;
        return list_entry(head, struct recent_entry, list);
 }
 
index edf3e28..2f23479 100644 (file)
@@ -2392,19 +2392,14 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
        if (nlk_has_extack && extack && extack->_msg)
                tlvlen += nla_total_size(strlen(extack->_msg) + 1);
 
-       if (err) {
-               if (!(nlk->flags & NETLINK_F_CAP_ACK))
-                       payload += nlmsg_len(nlh);
-               else
-                       flags |= NLM_F_CAPPED;
-               if (nlk_has_extack && extack && extack->bad_attr)
-                       tlvlen += nla_total_size(sizeof(u32));
-       } else {
+       if (err && !(nlk->flags & NETLINK_F_CAP_ACK))
+               payload += nlmsg_len(nlh);
+       else
                flags |= NLM_F_CAPPED;
-
-               if (nlk_has_extack && extack && extack->cookie_len)
-                       tlvlen += nla_total_size(extack->cookie_len);
-       }
+       if (err && nlk_has_extack && extack && extack->bad_attr)
+               tlvlen += nla_total_size(sizeof(u32));
+       if (nlk_has_extack && extack && extack->cookie_len)
+               tlvlen += nla_total_size(extack->cookie_len);
 
        if (tlvlen)
                flags |= NLM_F_ACK_TLVS;
@@ -2427,20 +2422,16 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
                        WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG,
                                               extack->_msg));
                }
-               if (err) {
-                       if (extack->bad_attr &&
-                           !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
-                                    (u8 *)extack->bad_attr >= in_skb->data +
-                                                              in_skb->len))
-                               WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
-                                                   (u8 *)extack->bad_attr -
-                                                   in_skb->data));
-               } else {
-                       if (extack->cookie_len)
-                               WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
-                                               extack->cookie_len,
-                                               extack->cookie));
-               }
+               if (err && extack->bad_attr &&
+                   !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
+                            (u8 *)extack->bad_attr >= in_skb->data +
+                                                      in_skb->len))
+                       WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
+                                           (u8 *)extack->bad_attr -
+                                           (u8 *)nlh));
+               if (extack->cookie_len)
+                       WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
+                                       extack->cookie_len, extack->cookie));
        }
 
        nlmsg_end(skb, rep);
index 0522b2b..9f357aa 100644 (file)
@@ -497,8 +497,9 @@ genl_family_rcv_msg_attrs_parse(const struct genl_family *family,
 
        err = __nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr,
                            family->policy, validate, extack);
-       if (err && parallel) {
-               kfree(attrbuf);
+       if (err) {
+               if (parallel)
+                       kfree(attrbuf);
                return ERR_PTR(err);
        }
        return attrbuf;
index 6f1b096..43811b5 100644 (file)
@@ -181,13 +181,20 @@ exit:
 void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
                          struct sk_buff *skb)
 {
-       u8 gate = hdev->pipes[pipe].gate;
        u8 status = NFC_HCI_ANY_OK;
        struct hci_create_pipe_resp *create_info;
        struct hci_delete_pipe_noti *delete_info;
        struct hci_all_pipe_cleared_noti *cleared_info;
+       u8 gate;
 
-       pr_debug("from gate %x pipe %x cmd %x\n", gate, pipe, cmd);
+       pr_debug("from pipe %x cmd %x\n", pipe, cmd);
+
+       if (pipe >= NFC_HCI_MAX_PIPES) {
+               status = NFC_HCI_ANY_E_NOK;
+               goto exit;
+       }
+
+       gate = hdev->pipes[pipe].gate;
 
        switch (cmd) {
        case NFC_HCI_ADM_NOTIFY_PIPE_CREATED:
@@ -375,8 +382,14 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
                            struct sk_buff *skb)
 {
        int r = 0;
-       u8 gate = hdev->pipes[pipe].gate;
+       u8 gate;
+
+       if (pipe >= NFC_HCI_MAX_PIPES) {
+               pr_err("Discarded event %x to invalid pipe %x\n", event, pipe);
+               goto exit;
+       }
 
+       gate = hdev->pipes[pipe].gate;
        if (gate == NFC_HCI_INVALID_GATE) {
                pr_err("Discarded event %x to unopened pipe %x\n", event, pipe);
                goto exit;
index eee0ddd..e894254 100644 (file)
@@ -32,6 +32,7 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
        [NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING,
                                .len = NFC_DEVICE_NAME_MAXSIZE },
        [NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 },
+       [NFC_ATTR_TARGET_INDEX] = { .type = NLA_U32 },
        [NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
        [NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
        [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
@@ -43,7 +44,10 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
        [NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED },
        [NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING,
                                     .len = NFC_FIRMWARE_NAME_MAXSIZE },
+       [NFC_ATTR_SE_INDEX] = { .type = NLA_U32 },
        [NFC_ATTR_SE_APDU] = { .type = NLA_BINARY },
+       [NFC_ATTR_VENDOR_ID] = { .type = NLA_U32 },
+       [NFC_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
        [NFC_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
 
 };
index c047afd..07a7dd1 100644 (file)
@@ -645,6 +645,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
        [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
        [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG },
        [OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 },
+       [OVS_PACKET_ATTR_HASH] = { .type = NLA_U64 },
 };
 
 static const struct genl_ops dp_packet_genl_ops[] = {
index 30c6879..29bd405 100644 (file)
@@ -2173,6 +2173,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        struct timespec64 ts;
        __u32 ts_status;
        bool is_drop_n_account = false;
+       unsigned int slot_id = 0;
        bool do_vnet = false;
 
        /* struct tpacket{2,3}_hdr is aligned to a multiple of TPACKET_ALIGNMENT.
@@ -2274,6 +2275,20 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                                        TP_STATUS_KERNEL, (macoff+snaplen));
        if (!h.raw)
                goto drop_n_account;
+
+       if (po->tp_version <= TPACKET_V2) {
+               slot_id = po->rx_ring.head;
+               if (test_bit(slot_id, po->rx_ring.rx_owner_map))
+                       goto drop_n_account;
+               __set_bit(slot_id, po->rx_ring.rx_owner_map);
+       }
+
+       if (do_vnet &&
+           virtio_net_hdr_from_skb(skb, h.raw + macoff -
+                                   sizeof(struct virtio_net_hdr),
+                                   vio_le(), true, 0))
+               goto drop_n_account;
+
        if (po->tp_version <= TPACKET_V2) {
                packet_increment_rx_head(po, &po->rx_ring);
        /*
@@ -2286,12 +2301,6 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                        status |= TP_STATUS_LOSING;
        }
 
-       if (do_vnet &&
-           virtio_net_hdr_from_skb(skb, h.raw + macoff -
-                                   sizeof(struct virtio_net_hdr),
-                                   vio_le(), true, 0))
-               goto drop_n_account;
-
        po->stats.stats1.tp_packets++;
        if (copy_skb) {
                status |= TP_STATUS_COPY;
@@ -2379,7 +2388,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
 #endif
 
        if (po->tp_version <= TPACKET_V2) {
+               spin_lock(&sk->sk_receive_queue.lock);
                __packet_set_status(po, h.raw, status);
+               __clear_bit(slot_id, po->rx_ring.rx_owner_map);
+               spin_unlock(&sk->sk_receive_queue.lock);
                sk->sk_data_ready(sk);
        } else {
                prb_clear_blk_fill_status(&po->rx_ring);
@@ -4276,6 +4288,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 {
        struct pgv *pg_vec = NULL;
        struct packet_sock *po = pkt_sk(sk);
+       unsigned long *rx_owner_map = NULL;
        int was_running, order = 0;
        struct packet_ring_buffer *rb;
        struct sk_buff_head *rb_queue;
@@ -4361,6 +4374,12 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                        }
                        break;
                default:
+                       if (!tx_ring) {
+                               rx_owner_map = bitmap_alloc(req->tp_frame_nr,
+                                       GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO);
+                               if (!rx_owner_map)
+                                       goto out_free_pg_vec;
+                       }
                        break;
                }
        }
@@ -4390,6 +4409,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                err = 0;
                spin_lock_bh(&rb_queue->lock);
                swap(rb->pg_vec, pg_vec);
+               if (po->tp_version <= TPACKET_V2)
+                       swap(rb->rx_owner_map, rx_owner_map);
                rb->frame_max = (req->tp_frame_nr - 1);
                rb->head = 0;
                rb->frame_size = req->tp_frame_size;
@@ -4421,6 +4442,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
        }
 
 out_free_pg_vec:
+       bitmap_free(rx_owner_map);
        if (pg_vec)
                free_pg_vec(pg_vec, order, req->tp_block_nr);
 out:
index 82fb2b1..907f4cd 100644 (file)
@@ -70,7 +70,10 @@ struct packet_ring_buffer {
 
        unsigned int __percpu   *pending_refcnt;
 
-       struct tpacket_kbdq_core        prb_bdqc;
+       union {
+               unsigned long                   *rx_owner_map;
+               struct tpacket_kbdq_core        prb_bdqc;
+       };
 };
 
 extern struct mutex fanout_mutex;
index fe42f98..15ee92d 100644 (file)
@@ -285,7 +285,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
                                           gfp_t gfp,
                                           rxrpc_notify_rx_t notify_rx,
                                           bool upgrade,
-                                          bool intr,
+                                          enum rxrpc_interruptibility interruptibility,
                                           unsigned int debug_id)
 {
        struct rxrpc_conn_parameters cp;
@@ -310,7 +310,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
        memset(&p, 0, sizeof(p));
        p.user_call_ID = user_call_ID;
        p.tx_total_len = tx_total_len;
-       p.intr = intr;
+       p.interruptibility = interruptibility;
 
        memset(&cp, 0, sizeof(cp));
        cp.local                = rx->local;
@@ -371,45 +371,18 @@ EXPORT_SYMBOL(rxrpc_kernel_end_call);
  * rxrpc_kernel_check_life - Check to see whether a call is still alive
  * @sock: The socket the call is on
  * @call: The call to check
- * @_life: Where to store the life value
  *
- * Allow a kernel service to find out whether a call is still alive - ie. we're
- * getting ACKs from the server.  Passes back in *_life a number representing
- * the life state which can be compared to that returned by a previous call and
- * return true if the call is still alive.
- *
- * If the life state stalls, rxrpc_kernel_probe_life() should be called and
- * then 2RTT waited.
+ * Allow a kernel service to find out whether a call is still alive -
+ * ie. whether it has completed.
  */
 bool rxrpc_kernel_check_life(const struct socket *sock,
-                            const struct rxrpc_call *call,
-                            u32 *_life)
+                            const struct rxrpc_call *call)
 {
-       *_life = call->acks_latest;
        return call->state != RXRPC_CALL_COMPLETE;
 }
 EXPORT_SYMBOL(rxrpc_kernel_check_life);
 
 /**
- * rxrpc_kernel_probe_life - Poke the peer to see if it's still alive
- * @sock: The socket the call is on
- * @call: The call to check
- *
- * In conjunction with rxrpc_kernel_check_life(), allow a kernel service to
- * find out whether a call is still alive by pinging it.  This should cause the
- * life state to be bumped in about 2*RTT.
- *
- * The must be called in TASK_RUNNING state on pain of might_sleep() objecting.
- */
-void rxrpc_kernel_probe_life(struct socket *sock, struct rxrpc_call *call)
-{
-       rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false,
-                         rxrpc_propose_ack_ping_for_check_life);
-       rxrpc_send_ack_packet(call, true, NULL);
-}
-EXPORT_SYMBOL(rxrpc_kernel_probe_life);
-
-/**
  * rxrpc_kernel_get_epoch - Retrieve the epoch value from a call.
  * @sock: The socket the call is on
  * @call: The call to query
index 7d730c4..3eb1ab4 100644 (file)
@@ -489,7 +489,6 @@ enum rxrpc_call_flag {
        RXRPC_CALL_BEGAN_RX_TIMER,      /* We began the expect_rx_by timer */
        RXRPC_CALL_RX_HEARD,            /* The peer responded at least once to this call */
        RXRPC_CALL_RX_UNDERRUN,         /* Got data underrun */
-       RXRPC_CALL_IS_INTR,             /* The call is interruptible */
        RXRPC_CALL_DISCONNECTED,        /* The call has been disconnected */
 };
 
@@ -598,6 +597,7 @@ struct rxrpc_call {
        atomic_t                usage;
        u16                     service_id;     /* service ID */
        u8                      security_ix;    /* Security type */
+       enum rxrpc_interruptibility interruptibility; /* At what point call may be interrupted */
        u32                     call_id;        /* call ID on connection  */
        u32                     cid;            /* connection ID plus channel index */
        int                     debug_id;       /* debug ID for printks */
@@ -675,7 +675,6 @@ struct rxrpc_call {
 
        /* transmission-phase ACK management */
        ktime_t                 acks_latest_ts; /* Timestamp of latest ACK received */
-       rxrpc_serial_t          acks_latest;    /* serial number of latest ACK received */
        rxrpc_seq_t             acks_lowest_nak; /* Lowest NACK in the buffer (or ==tx_hard_ack) */
        rxrpc_seq_t             acks_lost_top;  /* tx_top at the time lost-ack ping sent */
        rxrpc_serial_t          acks_lost_ping; /* Serial number of probe ACK */
@@ -721,7 +720,7 @@ struct rxrpc_call_params {
                u32             normal;         /* Max time since last call packet (msec) */
        } timeouts;
        u8                      nr_timeouts;    /* Number of timeouts specified */
-       bool                    intr;           /* The call is interruptible */
+       enum rxrpc_interruptibility interruptibility; /* How is interruptible is the call? */
 };
 
 struct rxrpc_send_params {
index c9f34b0..f079702 100644 (file)
@@ -237,8 +237,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
                return call;
        }
 
-       if (p->intr)
-               __set_bit(RXRPC_CALL_IS_INTR, &call->flags);
+       call->interruptibility = p->interruptibility;
        call->tx_total_len = p->tx_total_len;
        trace_rxrpc_call(call->debug_id, rxrpc_call_new_client,
                         atomic_read(&call->usage),
index ea7d4c2..f2a1a5d 100644 (file)
@@ -655,13 +655,20 @@ static int rxrpc_wait_for_channel(struct rxrpc_call *call, gfp_t gfp)
 
                add_wait_queue_exclusive(&call->waitq, &myself);
                for (;;) {
-                       if (test_bit(RXRPC_CALL_IS_INTR, &call->flags))
+                       switch (call->interruptibility) {
+                       case RXRPC_INTERRUPTIBLE:
+                       case RXRPC_PREINTERRUPTIBLE:
                                set_current_state(TASK_INTERRUPTIBLE);
-                       else
+                               break;
+                       case RXRPC_UNINTERRUPTIBLE:
+                       default:
                                set_current_state(TASK_UNINTERRUPTIBLE);
+                               break;
+                       }
                        if (call->call_id)
                                break;
-                       if (test_bit(RXRPC_CALL_IS_INTR, &call->flags) &&
+                       if ((call->interruptibility == RXRPC_INTERRUPTIBLE ||
+                            call->interruptibility == RXRPC_PREINTERRUPTIBLE) &&
                            signal_pending(current)) {
                                ret = -ERESTARTSYS;
                                break;
index ef10fbf..69e09d6 100644 (file)
@@ -882,7 +882,6 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
            before(prev_pkt, call->ackr_prev_seq))
                goto out;
        call->acks_latest_ts = skb->tstamp;
-       call->acks_latest = sp->hdr.serial;
 
        call->ackr_first_seq = first_soft_ack;
        call->ackr_prev_seq = prev_pkt;
index 813fd68..0fcf157 100644 (file)
 #include "ar-internal.h"
 
 /*
+ * Return true if there's sufficient Tx queue space.
+ */
+static bool rxrpc_check_tx_space(struct rxrpc_call *call, rxrpc_seq_t *_tx_win)
+{
+       unsigned int win_size =
+               min_t(unsigned int, call->tx_winsize,
+                     call->cong_cwnd + call->cong_extra);
+       rxrpc_seq_t tx_win = READ_ONCE(call->tx_hard_ack);
+
+       if (_tx_win)
+               *_tx_win = tx_win;
+       return call->tx_top - tx_win < win_size;
+}
+
+/*
  * Wait for space to appear in the Tx queue or a signal to occur.
  */
 static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx,
@@ -26,9 +41,7 @@ static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx,
 {
        for (;;) {
                set_current_state(TASK_INTERRUPTIBLE);
-               if (call->tx_top - call->tx_hard_ack <
-                   min_t(unsigned int, call->tx_winsize,
-                         call->cong_cwnd + call->cong_extra))
+               if (rxrpc_check_tx_space(call, NULL))
                        return 0;
 
                if (call->state >= RXRPC_CALL_COMPLETE)
@@ -49,7 +62,7 @@ static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx,
  * Wait for space to appear in the Tx queue uninterruptibly, but with
  * a timeout of 2*RTT if no progress was made and a signal occurred.
  */
-static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
+static int rxrpc_wait_for_tx_window_waitall(struct rxrpc_sock *rx,
                                            struct rxrpc_call *call)
 {
        rxrpc_seq_t tx_start, tx_win;
@@ -58,8 +71,8 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
 
        rtt = READ_ONCE(call->peer->rtt);
        rtt2 = nsecs_to_jiffies64(rtt) * 2;
-       if (rtt2 < 1)
-               rtt2 = 1;
+       if (rtt2 < 2)
+               rtt2 = 2;
 
        timeout = rtt2;
        tx_start = READ_ONCE(call->tx_hard_ack);
@@ -68,16 +81,13 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
                set_current_state(TASK_UNINTERRUPTIBLE);
 
                tx_win = READ_ONCE(call->tx_hard_ack);
-               if (call->tx_top - tx_win <
-                   min_t(unsigned int, call->tx_winsize,
-                         call->cong_cwnd + call->cong_extra))
+               if (rxrpc_check_tx_space(call, &tx_win))
                        return 0;
 
                if (call->state >= RXRPC_CALL_COMPLETE)
                        return call->error;
 
-               if (test_bit(RXRPC_CALL_IS_INTR, &call->flags) &&
-                   timeout == 0 &&
+               if (timeout == 0 &&
                    tx_win == tx_start && signal_pending(current))
                        return -EINTR;
 
@@ -92,6 +102,26 @@ static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
 }
 
 /*
+ * Wait for space to appear in the Tx queue uninterruptibly.
+ */
+static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
+                                           struct rxrpc_call *call,
+                                           long *timeo)
+{
+       for (;;) {
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               if (rxrpc_check_tx_space(call, NULL))
+                       return 0;
+
+               if (call->state >= RXRPC_CALL_COMPLETE)
+                       return call->error;
+
+               trace_rxrpc_transmit(call, rxrpc_transmit_wait);
+               *timeo = schedule_timeout(*timeo);
+       }
+}
+
+/*
  * wait for space to appear in the transmit/ACK window
  * - caller holds the socket locked
  */
@@ -108,10 +138,19 @@ static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx,
 
        add_wait_queue(&call->waitq, &myself);
 
-       if (waitall)
-               ret = rxrpc_wait_for_tx_window_nonintr(rx, call);
-       else
-               ret = rxrpc_wait_for_tx_window_intr(rx, call, timeo);
+       switch (call->interruptibility) {
+       case RXRPC_INTERRUPTIBLE:
+               if (waitall)
+                       ret = rxrpc_wait_for_tx_window_waitall(rx, call);
+               else
+                       ret = rxrpc_wait_for_tx_window_intr(rx, call, timeo);
+               break;
+       case RXRPC_PREINTERRUPTIBLE:
+       case RXRPC_UNINTERRUPTIBLE:
+       default:
+               ret = rxrpc_wait_for_tx_window_nonintr(rx, call, timeo);
+               break;
+       }
 
        remove_wait_queue(&call->waitq, &myself);
        set_current_state(TASK_RUNNING);
@@ -302,9 +341,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
 
                        _debug("alloc");
 
-                       if (call->tx_top - call->tx_hard_ack >=
-                           min_t(unsigned int, call->tx_winsize,
-                                 call->cong_cwnd + call->cong_extra)) {
+                       if (!rxrpc_check_tx_space(call, NULL)) {
                                ret = -EAGAIN;
                                if (msg->msg_flags & MSG_DONTWAIT)
                                        goto maybe_error;
@@ -619,7 +656,7 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, size_t len)
                .call.tx_total_len      = -1,
                .call.user_call_ID      = 0,
                .call.nr_timeouts       = 0,
-               .call.intr              = true,
+               .call.interruptibility  = RXRPC_INTERRUPTIBLE,
                .abort_code             = 0,
                .command                = RXRPC_CMD_SEND_DATA,
                .exclusive              = false,
index 90a31b1..8c466a7 100644 (file)
@@ -186,6 +186,7 @@ static size_t tcf_action_shared_attrs_size(const struct tc_action *act)
                + nla_total_size(IFNAMSIZ) /* TCA_ACT_KIND */
                + cookie_len /* TCA_ACT_COOKIE */
                + nla_total_size(0) /* TCA_ACT_STATS nested */
+               + nla_total_size(sizeof(struct nla_bitfield32)) /* TCA_ACT_FLAGS */
                /* TCA_STATS_BASIC */
                + nla_total_size_64bit(sizeof(struct gnet_stats_basic))
                /* TCA_STATS_PKT64 */
index f685c0d..41114b4 100644 (file)
@@ -739,7 +739,7 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
        if (goto_ch)
                tcf_chain_put_by_act(goto_ch);
        if (params)
-               kfree_rcu(params, rcu);
+               call_rcu(&params->rcu, tcf_ct_params_free);
        if (res == ACT_P_CREATED)
                tcf_idr_insert(tn, *a);
 
index 1ad300e..83dd82f 100644 (file)
@@ -284,10 +284,8 @@ static int tcf_mirred_act(struct sk_buff *skb, const struct tc_action *a,
 
        /* mirror is always swallowed */
        if (is_redirect) {
-               skb2->tc_redirected = 1;
-               skb2->tc_from_ingress = skb2->tc_at_ingress;
-               if (skb2->tc_from_ingress)
-                       skb2->tstamp = 0;
+               skb_set_redirected(skb2, skb2->tc_at_ingress);
+
                /* let's the caller reinsert the packet, if possible */
                if (use_reinsert) {
                        res->ingress = want_ingress;
index 6f8786b..5efa3e7 100644 (file)
@@ -534,8 +534,8 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
                        fp = &b->ht[h];
                        for (pfp = rtnl_dereference(*fp); pfp;
                             fp = &pfp->next, pfp = rtnl_dereference(*fp)) {
-                               if (pfp == f) {
-                                       *fp = f->next;
+                               if (pfp == fold) {
+                                       rcu_assign_pointer(*fp, fold->next);
                                        break;
                                }
                        }
index 09b7dc5..9904299 100644 (file)
@@ -261,8 +261,10 @@ static void tcindex_partial_destroy_work(struct work_struct *work)
                                              struct tcindex_data,
                                              rwork);
 
+       rtnl_lock();
        kfree(p->perfect);
        kfree(p);
+       rtnl_unlock();
 }
 
 static void tcindex_free_perfect_hash(struct tcindex_data *cp)
@@ -357,6 +359,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
 
                if (tcindex_alloc_perfect_hash(net, cp) < 0)
                        goto errout;
+               cp->alloc_hash = cp->hash;
                for (i = 0; i < min(cp->hash, p->hash); i++)
                        cp->perfect[i].res = p->perfect[i].res;
                balloc = 1;
index b2905b0..2eaac2f 100644 (file)
@@ -181,6 +181,11 @@ static struct sk_buff *cbs_dequeue_soft(struct Qdisc *sch)
        s64 credits;
        int len;
 
+       /* The previous packet is still being sent */
+       if (now < q->last) {
+               qdisc_watchdog_schedule_ns(&q->watchdog, q->last);
+               return NULL;
+       }
        if (q->credits < 0) {
                credits = timediff_to_credits(now - q->last, q->idleslope);
 
@@ -212,7 +217,12 @@ static struct sk_buff *cbs_dequeue_soft(struct Qdisc *sch)
        credits += q->credits;
 
        q->credits = max_t(s64, credits, q->locredit);
-       q->last = now;
+       /* Estimate of the transmission of the last byte of the packet in ns */
+       if (unlikely(atomic64_read(&q->port_rate) == 0))
+               q->last = now;
+       else
+               q->last = now + div64_s64(len * NSEC_PER_SEC,
+                                         atomic64_read(&q->port_rate));
 
        return skb;
 }
index a5a2954..371ad84 100644 (file)
@@ -744,6 +744,7 @@ static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = {
        [TCA_FQ_FLOW_MAX_RATE]          = { .type = NLA_U32 },
        [TCA_FQ_BUCKETS_LOG]            = { .type = NLA_U32 },
        [TCA_FQ_FLOW_REFILL_DELAY]      = { .type = NLA_U32 },
+       [TCA_FQ_ORPHAN_MASK]            = { .type = NLA_U32 },
        [TCA_FQ_LOW_RATE_THRESHOLD]     = { .type = NLA_U32 },
        [TCA_FQ_CE_THRESHOLD]           = { .type = NLA_U32 },
 };
index 660fc45..b1eb12d 100644 (file)
@@ -564,8 +564,10 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch)
                prio = skb->priority;
                tc = netdev_get_prio_tc_map(dev, prio);
 
-               if (!(gate_mask & BIT(tc)))
+               if (!(gate_mask & BIT(tc))) {
+                       skb = NULL;
                        continue;
+               }
 
                len = qdisc_pkt_len(skb);
                guard = ktime_add_ns(taprio_get_time(q),
@@ -575,13 +577,17 @@ static struct sk_buff *taprio_dequeue_soft(struct Qdisc *sch)
                 * guard band ...
                 */
                if (gate_mask != TAPRIO_ALL_GATES_OPEN &&
-                   ktime_after(guard, entry->close_time))
+                   ktime_after(guard, entry->close_time)) {
+                       skb = NULL;
                        continue;
+               }
 
                /* ... and no budget. */
                if (gate_mask != TAPRIO_ALL_GATES_OPEN &&
-                   atomic_sub_return(len, &entry->budget) < 0)
+                   atomic_sub_return(len, &entry->budget) < 0) {
+                       skb = NULL;
                        continue;
+               }
 
                skb = child->ops->dequeue(child);
                if (unlikely(!skb))
@@ -768,6 +774,7 @@ static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = {
        [TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME]           = { .type = NLA_S64 },
        [TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME_EXTENSION] = { .type = NLA_S64 },
        [TCA_TAPRIO_ATTR_FLAGS]                      = { .type = NLA_U32 },
+       [TCA_TAPRIO_ATTR_TXTIME_DELAY]               = { .type = NLA_U32 },
 };
 
 static int fill_sched_entry(struct nlattr **tb, struct sched_entry *entry,
index 8a15146..1069d7a 100644 (file)
@@ -237,15 +237,11 @@ static size_t inet_assoc_attr_size(struct sctp_association *asoc)
                addrcnt++;
 
        return    nla_total_size(sizeof(struct sctp_info))
-               + nla_total_size(1) /* INET_DIAG_SHUTDOWN */
-               + nla_total_size(1) /* INET_DIAG_TOS */
-               + nla_total_size(1) /* INET_DIAG_TCLASS */
-               + nla_total_size(4) /* INET_DIAG_MARK */
-               + nla_total_size(4) /* INET_DIAG_CLASS_ID */
                + nla_total_size(addrlen * asoc->peer.transport_count)
                + nla_total_size(addrlen * addrcnt)
-               + nla_total_size(sizeof(struct inet_diag_meminfo))
                + nla_total_size(sizeof(struct inet_diag_msg))
+               + inet_diag_msg_attrs_size()
+               + nla_total_size(sizeof(struct inet_diag_meminfo))
                + 64;
 }
 
index 90988a5..6fd44bd 100644 (file)
@@ -512,15 +512,18 @@ static int smc_connect_decline_fallback(struct smc_sock *smc, int reason_code)
 static int smc_connect_abort(struct smc_sock *smc, int reason_code,
                             int local_contact)
 {
+       bool is_smcd = smc->conn.lgr->is_smcd;
+
        if (local_contact == SMC_FIRST_CONTACT)
-               smc_lgr_forget(smc->conn.lgr);
-       if (smc->conn.lgr->is_smcd)
+               smc_lgr_cleanup_early(&smc->conn);
+       else
+               smc_conn_free(&smc->conn);
+       if (is_smcd)
                /* there is only one lgr role for SMC-D; use server lock */
                mutex_unlock(&smc_server_lgr_pending);
        else
                mutex_unlock(&smc_client_lgr_pending);
 
-       smc_conn_free(&smc->conn);
        smc->connect_nonblock = 0;
        return reason_code;
 }
@@ -1091,7 +1094,6 @@ static void smc_listen_out_err(struct smc_sock *new_smc)
        if (newsmcsk->sk_state == SMC_INIT)
                sock_put(&new_smc->sk); /* passive closing */
        newsmcsk->sk_state = SMC_CLOSED;
-       smc_conn_free(&new_smc->conn);
 
        smc_listen_out(new_smc);
 }
@@ -1102,12 +1104,13 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code,
 {
        /* RDMA setup failed, switch back to TCP */
        if (local_contact == SMC_FIRST_CONTACT)
-               smc_lgr_forget(new_smc->conn.lgr);
+               smc_lgr_cleanup_early(&new_smc->conn);
+       else
+               smc_conn_free(&new_smc->conn);
        if (reason_code < 0) { /* error, no fallback possible */
                smc_listen_out_err(new_smc);
                return;
        }
-       smc_conn_free(&new_smc->conn);
        smc_switch_to_fallback(new_smc);
        new_smc->fallback_rsn = reason_code;
        if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) {
@@ -1170,16 +1173,18 @@ static int smc_listen_ism_init(struct smc_sock *new_smc,
                            new_smc->conn.lgr->vlan_id,
                            new_smc->conn.lgr->smcd)) {
                if (ini->cln_first_contact == SMC_FIRST_CONTACT)
-                       smc_lgr_forget(new_smc->conn.lgr);
-               smc_conn_free(&new_smc->conn);
+                       smc_lgr_cleanup_early(&new_smc->conn);
+               else
+                       smc_conn_free(&new_smc->conn);
                return SMC_CLC_DECL_SMCDNOTALK;
        }
 
        /* Create send and receive buffers */
        if (smc_buf_create(new_smc, true)) {
                if (ini->cln_first_contact == SMC_FIRST_CONTACT)
-                       smc_lgr_forget(new_smc->conn.lgr);
-               smc_conn_free(&new_smc->conn);
+                       smc_lgr_cleanup_early(&new_smc->conn);
+               else
+                       smc_conn_free(&new_smc->conn);
                return SMC_CLC_DECL_MEM;
        }
 
index 2249de5..5b085ef 100644 (file)
@@ -162,6 +162,18 @@ static void smc_lgr_unregister_conn(struct smc_connection *conn)
        conn->lgr = NULL;
 }
 
+void smc_lgr_cleanup_early(struct smc_connection *conn)
+{
+       struct smc_link_group *lgr = conn->lgr;
+
+       if (!lgr)
+               return;
+
+       smc_conn_free(conn);
+       smc_lgr_forget(lgr);
+       smc_lgr_schedule_free_work_fast(lgr);
+}
+
 /* Send delete link, either as client to request the initiation
  * of the DELETE LINK sequence from server; or as server to
  * initiate the delete processing. See smc_llc_rx_delete_link().
index c472e12..234ae25 100644 (file)
@@ -296,6 +296,7 @@ struct smc_clc_msg_accept_confirm;
 struct smc_clc_msg_local;
 
 void smc_lgr_forget(struct smc_link_group *lgr);
+void smc_lgr_cleanup_early(struct smc_connection *conn);
 void smc_lgr_terminate(struct smc_link_group *lgr, bool soft);
 void smc_port_terminate(struct smc_ib_device *smcibdev, u8 ibport);
 void smc_smcd_terminate(struct smcd_dev *dev, u64 peer_gid,
@@ -316,7 +317,6 @@ int smc_vlan_by_tcpsk(struct socket *clcsock, struct smc_init_info *ini);
 
 void smc_conn_free(struct smc_connection *conn);
 int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini);
-void smcd_conn_free(struct smc_connection *conn);
 void smc_lgr_schedule_free_work_fast(struct smc_link_group *lgr);
 int smc_core_init(void);
 void smc_core_exit(void);
index 5486326..05b825b 100644 (file)
@@ -573,6 +573,8 @@ static void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data)
        struct smc_ib_device *smcibdev;
 
        smcibdev = ib_get_client_data(ibdev, &smc_ib_client);
+       if (!smcibdev || smcibdev->ibdev != ibdev)
+               return;
        ib_set_client_data(ibdev, &smc_ib_client, NULL);
        spin_lock(&smc_ib_devices.lock);
        list_del_init(&smcibdev->list); /* remove from smc_ib_devices */
@@ -580,6 +582,7 @@ static void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data)
        smc_smcr_terminate_all(smcibdev);
        smc_ib_cleanup_per_ibdev(smcibdev);
        ib_unregister_event_handler(&smcibdev->event_handler);
+       cancel_work_sync(&smcibdev->port_event_work);
        kfree(smcibdev);
 }
 
index b79a05d..2dd739f 100644 (file)
@@ -1707,7 +1707,8 @@ SYSCALL_DEFINE2(listen, int, fd, int, backlog)
 
 int __sys_accept4_file(struct file *file, unsigned file_flags,
                       struct sockaddr __user *upeer_sockaddr,
-                      int __user *upeer_addrlen, int flags)
+                      int __user *upeer_addrlen, int flags,
+                      unsigned long nofile)
 {
        struct socket *sock, *newsock;
        struct file *newfile;
@@ -1738,7 +1739,7 @@ int __sys_accept4_file(struct file *file, unsigned file_flags,
         */
        __module_get(newsock->ops->owner);
 
-       newfd = get_unused_fd_flags(flags);
+       newfd = __get_unused_fd_flags(flags, nofile);
        if (unlikely(newfd < 0)) {
                err = newfd;
                sock_release(newsock);
@@ -1807,7 +1808,8 @@ int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr,
        f = fdget(fd);
        if (f.file) {
                ret = __sys_accept4_file(f.file, 0, upeer_sockaddr,
-                                               upeer_addrlen, flags);
+                                               upeer_addrlen, flags,
+                                               rlimit(RLIMIT_NOFILE));
                if (f.flags)
                        fput(f.file);
        }
@@ -2226,10 +2228,10 @@ struct used_address {
        unsigned int name_len;
 };
 
-static int copy_msghdr_from_user(struct msghdr *kmsg,
-                                struct user_msghdr __user *umsg,
-                                struct sockaddr __user **save_addr,
-                                struct iovec **iov)
+int __copy_msghdr_from_user(struct msghdr *kmsg,
+                           struct user_msghdr __user *umsg,
+                           struct sockaddr __user **save_addr,
+                           struct iovec __user **uiov, size_t *nsegs)
 {
        struct user_msghdr msg;
        ssize_t err;
@@ -2271,6 +2273,23 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
                return -EMSGSIZE;
 
        kmsg->msg_iocb = NULL;
+       *uiov = msg.msg_iov;
+       *nsegs = msg.msg_iovlen;
+       return 0;
+}
+
+static int copy_msghdr_from_user(struct msghdr *kmsg,
+                                struct user_msghdr __user *umsg,
+                                struct sockaddr __user **save_addr,
+                                struct iovec **iov)
+{
+       struct user_msghdr msg;
+       ssize_t err;
+
+       err = __copy_msghdr_from_user(kmsg, umsg, save_addr, &msg.msg_iov,
+                                       &msg.msg_iovlen);
+       if (err)
+               return err;
 
        err = import_iovec(save_addr ? READ : WRITE,
                            msg.msg_iov, msg.msg_iovlen,
index 7c35094..bb98624 100644 (file)
@@ -116,6 +116,7 @@ const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
        [TIPC_NLA_PROP_PRIO]            = { .type = NLA_U32 },
        [TIPC_NLA_PROP_TOL]             = { .type = NLA_U32 },
        [TIPC_NLA_PROP_WIN]             = { .type = NLA_U32 },
+       [TIPC_NLA_PROP_MTU]             = { .type = NLA_U32 },
        [TIPC_NLA_PROP_BROADCAST]       = { .type = NLA_U32 },
        [TIPC_NLA_PROP_BROADCAST_RATIO] = { .type = NLA_U32 }
 };
index 62c12cb..68debcb 100644 (file)
@@ -682,6 +682,7 @@ static int unix_set_peek_off(struct sock *sk, int val)
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
 static void unix_show_fdinfo(struct seq_file *m, struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -692,6 +693,9 @@ static void unix_show_fdinfo(struct seq_file *m, struct socket *sock)
                seq_printf(m, "scm_fds: %u\n", READ_ONCE(u->scm_stat.nr_fds));
        }
 }
+#else
+#define unix_show_fdinfo NULL
+#endif
 
 static const struct proto_ops unix_stream_ops = {
        .family =       PF_UNIX,
index 9c5b2a9..a5f2870 100644 (file)
@@ -451,6 +451,12 @@ int vsock_assign_transport(struct vsock_sock *vsk, struct vsock_sock *psk)
                if (vsk->transport == new_transport)
                        return 0;
 
+               /* transport->release() must be called with sock lock acquired.
+                * This path can only be taken during vsock_stream_connect(),
+                * where we have already held the sock lock.
+                * In the other cases, this function is called on a new socket
+                * which is not assigned to any transport.
+                */
                vsk->transport->release(vsk);
                vsock_deassign_transport(vsk);
        }
@@ -753,20 +759,18 @@ static void __vsock_release(struct sock *sk, int level)
                vsk = vsock_sk(sk);
                pending = NULL; /* Compiler warning. */
 
-               /* The release call is supposed to use lock_sock_nested()
-                * rather than lock_sock(), if a sock lock should be acquired.
-                */
-               if (vsk->transport)
-                       vsk->transport->release(vsk);
-               else if (sk->sk_type == SOCK_STREAM)
-                       vsock_remove_sock(vsk);
-
                /* When "level" is SINGLE_DEPTH_NESTING, use the nested
                 * version to avoid the warning "possible recursive locking
                 * detected". When "level" is 0, lock_sock_nested(sk, level)
                 * is the same as lock_sock(sk).
                 */
                lock_sock_nested(sk, level);
+
+               if (vsk->transport)
+                       vsk->transport->release(vsk);
+               else if (sk->sk_type == SOCK_STREAM)
+                       vsock_remove_sock(vsk);
+
                sock_orphan(sk);
                sk->sk_shutdown = SHUTDOWN_MASK;
 
index 3492c02..630b851 100644 (file)
@@ -526,12 +526,9 @@ static bool hvs_close_lock_held(struct vsock_sock *vsk)
 
 static void hvs_release(struct vsock_sock *vsk)
 {
-       struct sock *sk = sk_vsock(vsk);
        bool remove_sock;
 
-       lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
        remove_sock = hvs_close_lock_held(vsk);
-       release_sock(sk);
        if (remove_sock)
                vsock_remove_sock(vsk);
 }
index d9f0c9c..f3c4bab 100644 (file)
@@ -829,7 +829,6 @@ void virtio_transport_release(struct vsock_sock *vsk)
        struct sock *sk = &vsk->sk;
        bool remove_sock = true;
 
-       lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
        if (sk->sk_type == SOCK_STREAM)
                remove_sock = virtio_transport_close(vsk);
 
@@ -837,7 +836,6 @@ void virtio_transport_release(struct vsock_sock *vsk)
                list_del(&pkt->list);
                virtio_transport_free_pkt(pkt);
        }
-       release_sock(sk);
 
        if (remove_sock)
                vsock_remove_sock(vsk);
index cedf17d..f0af23c 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/netlink.h>
 #include <linux/nospec.h>
 #include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
 #include <net/net_namespace.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
@@ -469,6 +470,8 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
        [NL80211_ATTR_STA_PLINK_STATE] =
                NLA_POLICY_MAX(NLA_U8, NUM_NL80211_PLINK_STATES - 1),
+       [NL80211_ATTR_MEASUREMENT_DURATION] = { .type = NLA_U16 },
+       [NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY] = { .type = NLA_FLAG },
        [NL80211_ATTR_MESH_PEER_AID] =
                NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
        [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
@@ -530,6 +533,8 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_MDID] = { .type = NLA_U16 },
        [NL80211_ATTR_IE_RIC] = { .type = NLA_BINARY,
                                  .len = IEEE80211_MAX_DATA_LEN },
+       [NL80211_ATTR_CRIT_PROT_ID] = { .type = NLA_U16 },
+       [NL80211_ATTR_MAX_CRIT_PROT_DURATION] = { .type = NLA_U16 },
        [NL80211_ATTR_PEER_AID] =
                NLA_POLICY_RANGE(NLA_U16, 1, IEEE80211_MAX_AID),
        [NL80211_ATTR_CH_SWITCH_COUNT] = { .type = NLA_U32 },
@@ -560,6 +565,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
                NLA_POLICY_MAX(NLA_U8, IEEE80211_NUM_UPS - 1),
        [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
        [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
+       [NL80211_ATTR_OPER_CLASS] = { .type = NLA_U8 },
        [NL80211_ATTR_MAC_MASK] = {
                .type = NLA_EXACT_LEN_WARN,
                .len = ETH_ALEN
@@ -4800,8 +4806,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
                err = nl80211_parse_he_obss_pd(
                                        info->attrs[NL80211_ATTR_HE_OBSS_PD],
                                        &params.he_obss_pd);
-               if (err)
-                       return err;
+               goto out;
        }
 
        nl80211_calculate_ap_params(&params);
@@ -4823,6 +4828,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        }
        wdev_unlock(wdev);
 
+out:
        kfree(params.acl);
 
        return err;
@@ -16410,7 +16416,7 @@ void cfg80211_sta_opmode_change_notify(struct net_device *dev, const u8 *mac,
                goto nla_put_failure;
 
        if ((sta_opmode->changed & STA_OPMODE_MAX_BW_CHANGED) &&
-           nla_put_u8(msg, NL80211_ATTR_CHANNEL_WIDTH, sta_opmode->bw))
+           nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, sta_opmode->bw))
                goto nla_put_failure;
 
        if ((sta_opmode->changed & STA_OPMODE_N_SS_CHANGED) &&
index fff9a74..1a8218f 100644 (file)
@@ -2276,7 +2276,7 @@ static void handle_channel_custom(struct wiphy *wiphy,
                        break;
        }
 
-       if (IS_ERR(reg_rule)) {
+       if (IS_ERR_OR_NULL(reg_rule)) {
                pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
                         chan->center_freq);
                if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
index aef240f..328402a 100644 (file)
@@ -2022,7 +2022,11 @@ void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev,
 
        spin_lock_bh(&rdev->bss_lock);
 
-       if (WARN_ON(cbss->pub.channel == chan))
+       /*
+        * Some APs use CSA also for bandwidth changes, i.e., without actually
+        * changing the control channel, so no need to update in such a case.
+        */
+       if (cbss->pub.channel == chan)
                goto done;
 
        /* use transmitting bss */
index 50f567a..e2db468 100644 (file)
@@ -78,8 +78,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
        int err;
        unsigned long flags;
        struct xfrm_state *x;
-       struct sk_buff *skb2, *nskb;
        struct softnet_data *sd;
+       struct sk_buff *skb2, *nskb, *pskb = NULL;
        netdev_features_t esp_features = features;
        struct xfrm_offload *xo = xfrm_offload(skb);
        struct sec_path *sp;
@@ -168,14 +168,14 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur
                } else {
                        if (skb == skb2)
                                skb = nskb;
-
-                       if (!skb)
-                               return NULL;
+                       else
+                               pskb->next = nskb;
 
                        continue;
                }
 
                skb_push(skb2, skb2->data - skb_mac_header(skb2));
+               pskb = skb2;
        }
 
        return skb;
@@ -383,6 +383,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void
                return xfrm_dev_feat_change(dev);
 
        case NETDEV_DOWN:
+       case NETDEV_UNREGISTER:
                return xfrm_dev_down(dev);
        }
        return NOTIFY_DONE;
index dbda08e..8a4af86 100644 (file)
@@ -434,7 +434,9 @@ EXPORT_SYMBOL(xfrm_policy_destroy);
 
 static void xfrm_policy_kill(struct xfrm_policy *policy)
 {
+       write_lock_bh(&policy->lock);
        policy->walk.dead = 1;
+       write_unlock_bh(&policy->lock);
 
        atomic_inc(&policy->genid);
 
index b88ba45..e6cfaa6 100644 (file)
@@ -110,7 +110,8 @@ static inline int verify_sec_ctx_len(struct nlattr **attrs)
                return 0;
 
        uctx = nla_data(rt);
-       if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
+       if (uctx->len > nla_len(rt) ||
+           uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
                return -EINVAL;
 
        return 0;
@@ -2275,6 +2276,9 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
        err = verify_newpolicy_info(&ua->policy);
        if (err)
                goto free_state;
+       err = verify_sec_ctx_len(attrs);
+       if (err)
+               goto free_state;
 
        /*   build an XP */
        xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
index f6a551b..3fa6582 100644 (file)
@@ -879,7 +879,7 @@ static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        vdev->tvnorms = SKEL_TVNORMS;
        video_set_drvdata(vdev, skel);
 
-       ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
        if (ret)
                goto free_hdl;
 
index 85334dc..8074f14 100644 (file)
@@ -31,6 +31,12 @@ cc-option = $(success,$(CC) -Werror $(CLANG_FLAGS) $(1) -S -x c /dev/null -o /de
 # Return y if the linker supports <flag>, n otherwise
 ld-option = $(success,$(LD) -v $(1))
 
+# $(as-option,<flag>)
+# /dev/zero is used as output instead of /dev/null as some assembler cribs when
+# both input and output are same. Also both of them have same write behaviour so
+# can be easily substituted.
+as-option = $(success, $(CC) $(CLANG_FLAGS) $(1) -c -x assembler /dev/null -o /dev/zero)
+
 # $(as-instr,<instr>)
 # Return y if the assembler supports <instr>, n otherwise
 as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler -o /dev/null -)
@@ -44,3 +50,10 @@ $(error-if,$(success, $(LD) -v | grep -q gold), gold linker '$(LD)' not supporte
 
 # gcc version including patch level
 gcc-version := $(shell,$(srctree)/scripts/gcc-version.sh $(CC))
+
+# machine bit flags
+#  $(m32-flag): -m32 if the compiler supports it, or an empty string otherwise.
+#  $(m64-flag): -m64 if the compiler supports it, or an empty string otherwise.
+cc-option-bit = $(if-success,$(CC) -Werror $(1) -E -x c /dev/null -o /dev/null,$(1))
+m32-flag := $(cc-option-bit,-m32)
+m64-flag := $(cc-option-bit,-m64)
index ecddf83..ca08f2f 100644 (file)
@@ -48,6 +48,7 @@ KBUILD_CFLAGS += -Wno-initializer-overrides
 KBUILD_CFLAGS += -Wno-format
 KBUILD_CFLAGS += -Wno-sign-compare
 KBUILD_CFLAGS += -Wno-format-zero-length
+KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast)
 endif
 
 endif
index bae6254..752ff0a 100644 (file)
@@ -300,15 +300,15 @@ DT_BINDING_DIR := Documentation/devicetree/bindings
 DT_TMP_SCHEMA := $(objtree)/$(DT_BINDING_DIR)/processed-schema.yaml
 
 quiet_cmd_dtb_check =  CHECK   $@
-      cmd_dtb_check =  $(DT_CHECKER) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@ ;
+      cmd_dtb_check =  $(DT_CHECKER) -u $(srctree)/$(DT_BINDING_DIR) -p $(DT_TMP_SCHEMA) $@
 
-define rule_dtc_dt_yaml
+define rule_dtc
        $(call cmd_and_fixdep,dtc,yaml)
        $(call cmd,dtb_check)
 endef
 
 $(obj)/%.dt.yaml: $(src)/%.dts $(DTC) $(DT_TMP_SCHEMA) FORCE
-       $(call if_changed_rule,dtc_dt_yaml)
+       $(call if_changed_rule,dtc)
 
 dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
 
diff --git a/scripts/check-sysctl-docs b/scripts/check-sysctl-docs
new file mode 100755 (executable)
index 0000000..8bcb9e2
--- /dev/null
@@ -0,0 +1,181 @@
+#!/usr/bin/gawk -f
+# SPDX-License-Identifier: GPL-2.0
+
+# Script to check sysctl documentation against source files
+#
+# Copyright (c) 2020 Stephen Kitt
+
+# Example invocation:
+#      scripts/check-sysctl-docs -vtable="kernel" \
+#              Documentation/admin-guide/sysctl/kernel.rst \
+#              $(git grep -l register_sysctl_)
+#
+# Specify -vdebug=1 to see debugging information
+
+BEGIN {
+    if (!table) {
+       print "Please specify the table to look for using the table variable" > "/dev/stderr"
+       exit 1
+    }
+}
+
+# The following globals are used:
+# children: maps ctl_table names and procnames to child ctl_table names
+# documented: maps documented entries (each key is an entry)
+# entries: maps ctl_table names and procnames to counts (so
+#          enumerating the subkeys for a given ctl_table lists its
+#          procnames)
+# files: maps procnames to source file names
+# paths: maps ctl_path names to paths
+# curpath: the name of the current ctl_path struct
+# curtable: the name of the current ctl_table struct
+# curentry: the name of the current proc entry (procname when parsing
+#           a ctl_table, constructed path when parsing a ctl_path)
+
+
+# Remove punctuation from the given value
+function trimpunct(value) {
+    while (value ~ /^["&]/) {
+       value = substr(value, 2)
+    }
+    while (value ~ /[]["&,}]$/) {
+       value = substr(value, 1, length(value) - 1)
+    }
+    return value
+}
+
+# Print the information for the given entry
+function printentry(entry) {
+    seen[entry]++
+    printf "* %s from %s", entry, file[entry]
+    if (documented[entry]) {
+       printf " (documented)"
+    }
+    print ""
+}
+
+
+# Stage 1: build the list of documented entries
+FNR == NR && /^=+$/ {
+    if (prevline ~ /Documentation for/) {
+       # This is the main title
+       next
+    }
+
+    # The previous line is a section title, parse it
+    $0 = prevline
+    if (debug) print "Parsing " $0
+    inbrackets = 0
+    for (i = 1; i <= NF; i++) {
+       if (length($i) == 0) {
+           continue
+       }
+       if (!inbrackets && substr($i, 1, 1) == "(") {
+           inbrackets = 1
+       }
+       if (!inbrackets) {
+           token = trimpunct($i)
+           if (length(token) > 0 && token != "and") {
+               if (debug) print trimpunct($i)
+               documented[trimpunct($i)]++
+           }
+       }
+       if (inbrackets && substr($i, length($i), 1) == ")") {
+           inbrackets = 0
+       }
+    }
+}
+
+FNR == NR {
+    prevline = $0
+    next
+}
+
+
+# Stage 2: process each file and find all sysctl tables
+BEGINFILE {
+    delete children
+    delete entries
+    delete paths
+    curpath = ""
+    curtable = ""
+    curentry = ""
+    if (debug) print "Processing file " FILENAME
+}
+
+/^static struct ctl_path/ {
+    match($0, /static struct ctl_path ([^][]+)/, tables)
+    curpath = tables[1]
+    if (debug) print "Processing path " curpath
+}
+
+/^static struct ctl_table/ {
+    match($0, /static struct ctl_table ([^][]+)/, tables)
+    curtable = tables[1]
+    if (debug) print "Processing table " curtable
+}
+
+/^};$/ {
+    curpath = ""
+    curtable = ""
+    curentry = ""
+}
+
+curpath && /\.procname[\t ]*=[\t ]*".+"/ {
+    match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names)
+    if (curentry) {
+       curentry = curentry "/" names[1]
+    } else {
+       curentry = names[1]
+    }
+    if (debug) print "Setting path " curpath " to " curentry
+    paths[curpath] = curentry
+}
+
+curtable && /\.procname[\t ]*=[\t ]*".+"/ {
+    match($0, /.procname[\t ]*=[\t ]*"([^"]+)"/, names)
+    curentry = names[1]
+    if (debug) print "Adding entry " curentry " to table " curtable
+    entries[curtable][curentry]++
+    file[curentry] = FILENAME
+}
+
+/\.child[\t ]*=/ {
+    child = trimpunct($NF)
+    if (debug) print "Linking child " child " to table " curtable " entry " curentry
+    children[curtable][curentry] = child
+}
+
+/register_sysctl_table\(.*\)/ {
+    match($0, /register_sysctl_table\(([^)]+)\)/, tables)
+    if (debug) print "Registering table " tables[1]
+    if (children[tables[1]][table]) {
+       for (entry in entries[children[tables[1]][table]]) {
+           printentry(entry)
+       }
+    }
+}
+
+/register_sysctl_paths\(.*\)/ {
+    match($0, /register_sysctl_paths\(([^)]+), ([^)]+)\)/, tables)
+    if (debug) print "Attaching table " tables[2] " to path " tables[1]
+    if (paths[tables[1]] == table) {
+       for (entry in entries[tables[2]]) {
+           printentry(entry)
+       }
+    }
+    split(paths[tables[1]], components, "/")
+    if (length(components) > 1 && components[1] == table) {
+       # Count the first subdirectory as seen
+       seen[components[2]]++
+    }
+}
+
+
+END {
+    for (entry in documented) {
+       if (!seen[entry]) {
+           print "No implementation for " entry
+       }
+    }
+}
index 7784c54..997202a 100755 (executable)
@@ -51,7 +51,9 @@ open IN, "git grep ':doc:\`' Documentation/|"
      or die "Failed to run git grep";
 while (<IN>) {
        next if (!m,^([^:]+):.*\:doc\:\`([^\`]+)\`,);
+       next if (m,sphinx/,);
 
+       my $file = $1;
        my $d = $1;
        my $doc_ref = $2;
 
@@ -60,7 +62,12 @@ while (<IN>) {
        $d =~ s,(.*/).*,$1,;
        $f =~ s,.*\<([^\>]+)\>,$1,;
 
-       $f ="$d$f.rst";
+       if ($f =~ m,^/,) {
+               $f = "$f.rst";
+               $f =~ s,^/,Documentation/,;
+       } else {
+               $f = "$d$f.rst";
+       }
 
        next if (grep -e, glob("$f"));
 
@@ -69,7 +76,7 @@ while (<IN>) {
        }
        $doc_fix++;
 
-       print STDERR "$f: :doc:`$doc_ref`\n";
+       print STDERR "$file: :doc:`$doc_ref`\n";
 }
 close IN;
 
index 5c6c3fd..b3b7270 100644 (file)
@@ -23,7 +23,6 @@ LINECOMMENT   "//".*\n
 #include "srcpos.h"
 #include "dtc-parser.tab.h"
 
-YYLTYPE yylloc;
 extern bool treesource_error;
 
 /* CAUTION: this will stop working if we ever use yyless() or yyunput() */
index 548330e..feb3d55 100755 (executable)
@@ -94,7 +94,7 @@ if (defined $opt{'o'}) {
 #
 while ( <$module_symvers> ) {
        chomp;
-       my (undef, $symbol, $namespace, $module, $gpl) = split('\t');
+       my (undef, $symbol, $module, $gpl, $namespace) = split('\t');
        $SYMBOL { $symbol } =  [ $module , "0" , $symbol, $gpl];
 }
 close($module_symvers);
index e356954..f8ca236 100644 (file)
@@ -23,7 +23,7 @@ menuconfig GCC_PLUGINS
          GCC plugins are loadable modules that provide extra features to the
          compiler. They are useful for runtime instrumentation and static analysis.
 
-         See Documentation/core-api/gcc-plugins.rst for details.
+         See Documentation/kbuild/gcc-plugins.rst for details.
 
 if GCC_PLUGINS
 
index 0133dfa..3e8dea6 100644 (file)
@@ -195,13 +195,13 @@ static struct sym_entry *read_symbol(FILE *in)
                return NULL;
        }
 
-       if (is_ignored_symbol(name, type))
-               return NULL;
-
-       /* Ignore most absolute/undefined (?) symbols. */
        if (strcmp(name, "_text") == 0)
                _text = addr;
 
+       /* Ignore most absolute/undefined (?) symbols. */
+       if (is_ignored_symbol(name, type))
+               return NULL;
+
        check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges));
        check_symbol_range(name, addr, &percpu_range, 1);
 
index 054405b..d3c237b 100644 (file)
@@ -145,6 +145,13 @@ int main(void)
        DEVID(i2c_device_id);
        DEVID_FIELD(i2c_device_id, name);
 
+       DEVID(i3c_device_id);
+       DEVID_FIELD(i3c_device_id, match_flags);
+       DEVID_FIELD(i3c_device_id, dcr);
+       DEVID_FIELD(i3c_device_id, manuf_id);
+       DEVID_FIELD(i3c_device_id, part_id);
+       DEVID_FIELD(i3c_device_id, extra_info);
+
        DEVID(spi_device_id);
        DEVID_FIELD(spi_device_id, name);
 
index c91eba7..f81cbe0 100644 (file)
@@ -919,6 +919,24 @@ static int do_i2c_entry(const char *filename, void *symval,
        return 1;
 }
 
+static int do_i3c_entry(const char *filename, void *symval,
+                       char *alias)
+{
+       DEF_FIELD(symval, i3c_device_id, match_flags);
+       DEF_FIELD(symval, i3c_device_id, dcr);
+       DEF_FIELD(symval, i3c_device_id, manuf_id);
+       DEF_FIELD(symval, i3c_device_id, part_id);
+       DEF_FIELD(symval, i3c_device_id, extra_info);
+
+       strcpy(alias, "i3c:");
+       ADD(alias, "dcr", match_flags & I3C_MATCH_DCR, dcr);
+       ADD(alias, "manuf", match_flags & I3C_MATCH_MANUF, manuf_id);
+       ADD(alias, "part", match_flags & I3C_MATCH_PART, part_id);
+       ADD(alias, "ext", match_flags & I3C_MATCH_EXTRA_INFO, extra_info);
+
+       return 1;
+}
+
 /* Looks like: spi:S */
 static int do_spi_entry(const char *filename, void *symval,
                        char *alias)
@@ -1386,6 +1404,7 @@ static const struct devtable devtable[] = {
        {"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry},
        {"rpmsg", SIZE_rpmsg_device_id, do_rpmsg_entry},
        {"i2c", SIZE_i2c_device_id, do_i2c_entry},
+       {"i3c", SIZE_i3c_device_id, do_i3c_entry},
        {"spi", SIZE_spi_device_id, do_spi_entry},
        {"dmi", SIZE_dmi_system_id, do_dmi_entry},
        {"platform", SIZE_platform_device_id, do_platform_entry},
index 7edfdb2..acf0a69 100644 (file)
@@ -308,7 +308,8 @@ static const char *sec_name(struct elf_info *elf, int secindex)
 
 static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
 {
-       Elf_Shdr *sechdr = &info->sechdrs[sym->st_shndx];
+       unsigned int secindex = get_secindex(info, sym);
+       Elf_Shdr *sechdr = &info->sechdrs[secindex];
        unsigned long offset;
 
        offset = sym->st_value;
@@ -2251,8 +2252,12 @@ static int check_modname_len(struct module *mod)
  **/
 static void add_header(struct buffer *b, struct module *mod)
 {
-       buf_printf(b, "#include <linux/build-salt.h>\n");
        buf_printf(b, "#include <linux/module.h>\n");
+       /*
+        * Include build-salt.h after module.h in order to
+        * inherit the definitions.
+        */
+       buf_printf(b, "#include <linux/build-salt.h>\n");
        buf_printf(b, "#include <linux/vermagic.h>\n");
        buf_printf(b, "#include <linux/compiler.h>\n");
        buf_printf(b, "\n");
@@ -2427,7 +2432,7 @@ static void write_if_changed(struct buffer *b, const char *fname)
 }
 
 /* parse Module.symvers file. line format:
- * 0x12345678<tab>symbol<tab>module[[<tab>export]<tab>something]
+ * 0x12345678<tab>symbol<tab>module<tab>export<tab>namespace
  **/
 static void read_dump(const char *fname, unsigned int kernel)
 {
@@ -2440,7 +2445,7 @@ static void read_dump(const char *fname, unsigned int kernel)
                return;
 
        while ((line = get_next_line(&pos, file, size))) {
-               char *symname, *namespace, *modname, *d, *export, *end;
+               char *symname, *namespace, *modname, *d, *export;
                unsigned int crc;
                struct module *mod;
                struct symbol *s;
@@ -2448,16 +2453,16 @@ static void read_dump(const char *fname, unsigned int kernel)
                if (!(symname = strchr(line, '\t')))
                        goto fail;
                *symname++ = '\0';
-               if (!(namespace = strchr(symname, '\t')))
-                       goto fail;
-               *namespace++ = '\0';
-               if (!(modname = strchr(namespace, '\t')))
+               if (!(modname = strchr(symname, '\t')))
                        goto fail;
                *modname++ = '\0';
-               if ((export = strchr(modname, '\t')) != NULL)
-                       *export++ = '\0';
-               if (export && ((end = strchr(export, '\t')) != NULL))
-                       *end = '\0';
+               if (!(export = strchr(modname, '\t')))
+                       goto fail;
+               *export++ = '\0';
+               if (!(namespace = strchr(export, '\t')))
+                       goto fail;
+               *namespace++ = '\0';
+
                crc = strtoul(line, &d, 16);
                if (*symname == '\0' || *modname == '\0' || *d != '\0')
                        goto fail;
@@ -2508,9 +2513,9 @@ static void write_dump(const char *fname)
                                namespace = symbol->namespace;
                                buf_printf(&buf, "0x%08x\t%s\t%s\t%s\t%s\n",
                                           symbol->crc, symbol->name,
-                                          namespace ? namespace : "",
                                           symbol->module->name,
-                                          export_str(symbol->export));
+                                          export_str(symbol->export),
+                                          namespace ? namespace : "");
                        }
                        symbol = symbol->next;
                }
old mode 100644 (file)
new mode 100755 (executable)
index 255cef1..2ca4eb3
@@ -8,13 +8,14 @@ my $input_file = "MAINTAINERS";
 my $output_file = "MAINTAINERS.new";
 my $output_section = "SECTION.new";
 my $help = 0;
-
+my $order = 0;
 my $P = $0;
 
 if (!GetOptions(
                'input=s' => \$input_file,
                'output=s' => \$output_file,
                'section=s' => \$output_section,
+               'order!' => \$order,
                'h|help|usage' => \$help,
            )) {
     die "$P: invalid argument - use --help if necessary\n";
@@ -32,6 +33,22 @@ usage: $P [options] <pattern matching regexes>
   --input => MAINTAINERS file to read (default: MAINTAINERS)
   --output => sorted MAINTAINERS file to write (default: MAINTAINERS.new)
   --section => new sorted MAINTAINERS file to write to (default: SECTION.new)
+  --order => Use the preferred section content output ordering (default: 0)
+    Preferred ordering of section output is:
+      M:  Person acting as a maintainer
+      R:  Person acting as a patch reviewer
+      L:  Mailing list where patches should be sent
+      S:  Maintenance status
+      W:  URI for general information
+      Q:  URI for patchwork tracking
+      B:  URI for bug tracking/submission
+      C:  URI for chat
+      P:  URI or file for subsystem specific coding styles
+      T:  SCM tree type and location
+      F:  File and directory pattern
+      X:  File and directory exclusion pattern
+      N:  File glob
+      K:  Keyword - patch content regex
 
 If <pattern match regexes> exist, then the sections that match the
 regexes are not written to the output file but are written to the
@@ -56,7 +73,7 @@ sub by_category($$) {
 
 sub by_pattern($$) {
     my ($a, $b) = @_;
-    my $preferred_order = 'MRPLSWTQBCFXNK';
+    my $preferred_order = 'MRLSWQBCPTFXNK';
 
     my $a1 = uc(substr($a, 0, 1));
     my $b1 = uc(substr($b, 0, 1));
@@ -105,8 +122,14 @@ sub alpha_output {
                print $file $separator;
            }
            print $file $key . "\n";
-           foreach my $pattern (sort by_pattern split('\n', %$hashref{$key})) {
-               print $file ($pattern . "\n");
+           if ($order) {
+               foreach my $pattern (sort by_pattern split('\n', %$hashref{$key})) {
+                   print $file ($pattern . "\n");
+               }
+           } else {
+               foreach my $pattern (split('\n', %$hashref{$key})) {
+                   print $file ($pattern . "\n");
+               }
            }
        }
     }
index a8f0c00..fa3fb05 100755 (executable)
@@ -701,11 +701,26 @@ sub check_needs()
                } else {
                        my $rec_activate = "$virtenv_dir/bin/activate";
                        my $virtualenv = findprog("virtualenv-3");
+                       my $rec_python3 = "";
                        $virtualenv = findprog("virtualenv-3.5") if (!$virtualenv);
                        $virtualenv = findprog("virtualenv") if (!$virtualenv);
                        $virtualenv = "virtualenv" if (!$virtualenv);
 
-                       printf "\t$virtualenv $virtenv_dir\n";
+                       my $rel = "";
+                       if (index($system_release, "Ubuntu") != -1) {
+                               $rel = $1 if ($system_release =~ /Ubuntu\s+(\d+)[.]/);
+                               if ($rel && $rel >= 16) {
+                                       $rec_python3 = " -p python3";
+                               }
+                       }
+                       if (index($system_release, "Debian") != -1) {
+                               $rel = $1 if ($system_release =~ /Debian\s+(\d+)/);
+                               if ($rel && $rel >= 7) {
+                                       $rec_python3 = " -p python3";
+                               }
+                       }
+
+                       printf "\t$virtualenv$rec_python3 $virtenv_dir\n";
                        printf "\t. $rec_activate\n";
                        printf "\tpip install -r $requirement_file\n";
                        deactivate_help();
index f0c9082..253fb9a 100644 (file)
@@ -79,7 +79,7 @@ static int __init load_uefi_certs(void)
        efi_status_t status;
        int rc = 0;
 
-       if (!efi.get_variable)
+       if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
                return false;
 
        /* Get db, MokListRT, and dbx.  They might not exist, so it isn't
index 718bf72..e959b3c 100644 (file)
@@ -382,7 +382,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
                spin_lock(&key->user->lock);
 
                if (delta > 0 &&
-                   (key->user->qnbytes + delta >= maxbytes ||
+                   (key->user->qnbytes + delta > maxbytes ||
                     key->user->qnbytes + delta < key->user->qnbytes)) {
                        ret = -EDQUOT;
                }
index 9b898c9..d1a3dea 100644 (file)
@@ -937,8 +937,8 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
                                key_quota_root_maxbytes : key_quota_maxbytes;
 
                        spin_lock(&newowner->lock);
-                       if (newowner->qnkeys + 1 >= maxkeys ||
-                           newowner->qnbytes + key->quotalen >= maxbytes ||
+                       if (newowner->qnkeys + 1 > maxkeys ||
+                           newowner->qnbytes + key->quotalen > maxbytes ||
                            newowner->qnbytes + key->quotalen <
                            newowner->qnbytes)
                                goto quota_overrun;
index 240e470..752d078 100644 (file)
@@ -111,7 +111,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
                while (plugin->next) {
                        if (plugin->dst_frames)
                                frames = plugin->dst_frames(plugin, frames);
-                       if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0))
+                       if ((snd_pcm_sframes_t)frames <= 0)
                                return -ENXIO;
                        plugin = plugin->next;
                        err = snd_pcm_plugin_alloc(plugin, frames);
@@ -123,7 +123,7 @@ int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames)
                while (plugin->prev) {
                        if (plugin->src_frames)
                                frames = plugin->src_frames(plugin, frames);
-                       if (snd_BUG_ON((snd_pcm_sframes_t)frames <= 0))
+                       if ((snd_pcm_sframes_t)frames <= 0)
                                return -ENXIO;
                        plugin = plugin->prev;
                        err = snd_pcm_plugin_alloc(plugin, frames);
@@ -209,6 +209,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                plugin = snd_pcm_plug_last(plug);
                while (plugin && drv_frames > 0) {
+                       if (drv_frames > plugin->buf_frames)
+                               drv_frames = plugin->buf_frames;
                        plugin_prev = plugin->prev;
                        if (plugin->src_frames)
                                drv_frames = plugin->src_frames(plugin, drv_frames);
@@ -220,6 +222,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *plug, snd_p
                        plugin_next = plugin->next;
                        if (plugin->dst_frames)
                                drv_frames = plugin->dst_frames(plugin, drv_frames);
+                       if (drv_frames > plugin->buf_frames)
+                               drv_frames = plugin->buf_frames;
                        plugin = plugin_next;
                }
        } else
@@ -248,11 +252,15 @@ snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *plug, snd_pc
                                if (frames < 0)
                                        return frames;
                        }
+                       if (frames > plugin->buf_frames)
+                               frames = plugin->buf_frames;
                        plugin = plugin_next;
                }
        } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
                plugin = snd_pcm_plug_last(plug);
                while (plugin) {
+                       if (frames > plugin->buf_frames)
+                               frames = plugin->buf_frames;
                        plugin_prev = plugin->prev;
                        if (plugin->src_frames) {
                                frames = plugin->src_frames(plugin, frames);
index d5443ee..cbdf061 100644 (file)
@@ -748,11 +748,11 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_timer_resolution_change(substream);
        snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
 
-       if (pm_qos_request_active(&substream->latency_pm_qos_req))
-               pm_qos_remove_request(&substream->latency_pm_qos_req);
+       if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req))
+               cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
        if ((usecs = period_to_usecs(runtime)) >= 0)
-               pm_qos_add_request(&substream->latency_pm_qos_req,
-                                  PM_QOS_CPU_DMA_LATENCY, usecs);
+               cpu_latency_qos_add_request(&substream->latency_pm_qos_req,
+                                           usecs);
        return 0;
  _error:
        /* hardware might be unusable from this time,
@@ -821,7 +821,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
                return -EBADFD;
        result = do_hw_free(substream);
        snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
-       pm_qos_remove_request(&substream->latency_pm_qos_req);
+       cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
        return result;
 }
 
@@ -2599,8 +2599,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
                substream->ops->close(substream);
                substream->hw_opened = 0;
        }
-       if (pm_qos_request_active(&substream->latency_pm_qos_req))
-               pm_qos_remove_request(&substream->latency_pm_qos_req);
+       if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req))
+               cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
        if (substream->pcm_release) {
                substream->pcm_release(substream);
                substream->pcm_release = NULL;
index a88c235..2ddfe22 100644 (file)
@@ -602,6 +602,7 @@ send_midi_event(struct seq_oss_devinfo *dp, struct snd_seq_event *ev, struct seq
                len = snd_seq_oss_timer_start(dp->timer);
        if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
                snd_seq_oss_readq_sysex(dp->readq, mdev->seq_device, ev);
+               snd_midi_event_reset_decode(mdev->coder);
        } else {
                len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
                if (len > 0)
index 626d87c..77d7037 100644 (file)
@@ -81,6 +81,7 @@ static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
                        if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
                                continue;
                        snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream);
+                       snd_midi_event_reset_decode(vmidi->parser);
                } else {
                        len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
                        if (len > 0)
index 9f60a50..5bf1ea1 100644 (file)
@@ -649,8 +649,6 @@ snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream)
 static const struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
        .open =        snd_sgio2audio_playback1_open,
        .close =       snd_sgio2audio_pcm_close,
-       .hw_params =   snd_sgio2audio_pcm_hw_params,
-       .hw_free =     snd_sgio2audio_pcm_hw_free,
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
@@ -659,8 +657,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback1_ops = {
 static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
        .open =        snd_sgio2audio_playback2_open,
        .close =       snd_sgio2audio_pcm_close,
-       .hw_params =   snd_sgio2audio_pcm_hw_params,
-       .hw_free =     snd_sgio2audio_pcm_hw_free,
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
@@ -669,8 +665,6 @@ static const struct snd_pcm_ops snd_sgio2audio_playback2_ops = {
 static const struct snd_pcm_ops snd_sgio2audio_capture_ops = {
        .open =        snd_sgio2audio_capture_open,
        .close =       snd_sgio2audio_pcm_close,
-       .hw_params =   snd_sgio2audio_pcm_hw_params,
-       .hw_free =     snd_sgio2audio_pcm_hw_free,
        .prepare =     snd_sgio2audio_pcm_prepare,
        .trigger =     snd_sgio2audio_pcm_trigger,
        .pointer =     snd_sgio2audio_pcm_pointer,
index 477589e..63e1a56 100644 (file)
@@ -2447,6 +2447,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
        SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
        SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
        SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
@@ -5920,7 +5921,8 @@ enum {
        ALC289_FIXUP_DUAL_SPK,
        ALC294_FIXUP_SPK2_TO_DAC1,
        ALC294_FIXUP_ASUS_DUAL_SPK,
-
+       ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+       ALC294_FIXUP_ASUS_HPE,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -6684,6 +6686,8 @@ static const struct hda_fixup alc269_fixups[] = {
        [ALC285_FIXUP_SPEAKER2_TO_DAC1] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
        },
        [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
                .type = HDA_FIXUP_PINS,
@@ -7040,7 +7044,23 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC294_FIXUP_SPK2_TO_DAC1
        },
-
+       [ALC285_FIXUP_THINKPAD_HEADSET_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_jack,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_SPEAKER2_TO_DAC1
+       },
+       [ALC294_FIXUP_ASUS_HPE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Set EAPD high */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0f },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x7774 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -7115,6 +7135,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
        SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
        SND_PCI_QUIRK(0x1028, 0x097d, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x098d, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x09bf, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -7204,6 +7226,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
        SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x19ce, "ASUS B9450FA", ALC294_FIXUP_ASUS_HPE),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x1043, 0x1a30, "ASUS X705UD", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
@@ -7274,8 +7297,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Yoga 7th", ALC285_FIXUP_SPEAKER2_TO_DAC1),
-       SND_PCI_QUIRK(0x17aa, 0x2293, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_SPEAKER2_TO_DAC1),
+       SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Yoga 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
+       SND_PCI_QUIRK(0x17aa, 0x2293, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
@@ -8028,6 +8051,8 @@ static int patch_alc269(struct hda_codec *codec)
                spec->gen.mixer_nid = 0;
                break;
        case 0x10ec0225:
+               codec->power_save_node = 1;
+               /* fall through */
        case 0x10ec0295:
        case 0x10ec0299:
                spec->codec_variant = ALC269_TYPE_ALC225;
@@ -8587,6 +8612,8 @@ enum {
        ALC669_FIXUP_ACER_ASPIRE_ETHOS,
        ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
        ALC671_FIXUP_HP_HEADSET_MIC2,
+       ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
+       ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -8932,6 +8959,25 @@ static const struct hda_fixup alc662_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc671_fixup_hp_headset_mic2,
        },
+       [ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_USI_FUNC
+       },
+       [ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
+                       { 0x1b, 0x0221144f },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_USI_FUNC
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -8943,6 +8989,8 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
+       SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
        SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
index 7e90f5d..ea91243 100644 (file)
@@ -1406,7 +1406,7 @@ config SND_SOC_WM8737
        depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8741
-       tristate "Wolfson Microelectronics WM8737 DAC"
+       tristate "Wolfson Microelectronics WM8741 DAC"
        depends on SND_SOC_I2C_AND_SPI
 
 config SND_SOC_WM8750
index 861210f..4cbef9a 100644 (file)
@@ -1564,13 +1564,15 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
        }
 
        pcm512x->sclk = devm_clk_get(dev, NULL);
-       if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
+       if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) {
+               ret = -EPROBE_DEFER;
+               goto err;
+       }
        if (!IS_ERR(pcm512x->sclk)) {
                ret = clk_prepare_enable(pcm512x->sclk);
                if (ret != 0) {
                        dev_err(dev, "Failed to enable SCLK: %d\n", ret);
-                       return ret;
+                       goto err;
                }
        }
 
index 6d490e2..66eb55b 100644 (file)
@@ -664,7 +664,7 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream,
        snd_soc_component_update_bits(component, RT1015_TDM_MASTER,
                RT1015_I2S_DL_MASK, val_len);
        snd_soc_component_update_bits(component, RT1015_CLK2,
-               RT1015_FS_PD_MASK, pre_div);
+               RT1015_FS_PD_MASK, pre_div << RT1015_FS_PD_SFT);
 
        return 0;
 }
@@ -857,6 +857,7 @@ struct snd_soc_dai_driver rt1015_dai[] = {
                        .rates = RT1015_STEREO_RATES,
                        .formats = RT1015_FORMATS,
                },
+               .ops = &rt1015_aif_dai_ops,
        }
 };
 
index 729acd8..be52886 100644 (file)
@@ -215,7 +215,8 @@ static int tas2562_set_bitwidth(struct tas2562_data *tas2562, int bitwidth)
                break;
 
        default:
-               dev_info(tas2562->dev, "Not supported params format\n");
+               dev_info(tas2562->dev, "Unsupported bitwidth format\n");
+               return -EINVAL;
        }
 
        ret = snd_soc_component_update_bits(tas2562->component,
@@ -251,7 +252,7 @@ static int tas2562_hw_params(struct snd_pcm_substream *substream,
 
        ret = tas2562_set_samplerate(tas2562, params_rate(params));
        if (ret)
-               dev_err(tas2562->dev, "set bitwidth failed, %d\n", ret);
+               dev_err(tas2562->dev, "set sample rate failed, %d\n", ret);
 
        return ret;
 }
index 68bcec5..d656398 100644 (file)
@@ -325,8 +325,7 @@ int sst_context_init(struct intel_sst_drv *ctx)
                ret = -ENOMEM;
                goto do_free_mem;
        }
-       pm_qos_add_request(ctx->qos, PM_QOS_CPU_DMA_LATENCY,
-                               PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_add_request(ctx->qos, PM_QOS_DEFAULT_VALUE);
 
        dev_dbg(ctx->dev, "Requesting FW %s now...\n", ctx->firmware_name);
        ret = request_firmware_nowait(THIS_MODULE, true, ctx->firmware_name,
@@ -364,7 +363,7 @@ void sst_context_cleanup(struct intel_sst_drv *ctx)
        sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group);
        flush_scheduled_work();
        destroy_workqueue(ctx->post_msg_wq);
-       pm_qos_remove_request(ctx->qos);
+       cpu_latency_qos_remove_request(ctx->qos);
        kfree(ctx->fw_sg_list.src);
        kfree(ctx->fw_sg_list.dst);
        ctx->fw_sg_list.list_len = 0;
index ce11c36..9b0e373 100644 (file)
@@ -412,7 +412,7 @@ int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
                return -ENOMEM;
 
        /* Prevent C-states beyond C6 */
-       pm_qos_update_request(sst_drv_ctx->qos, 0);
+       cpu_latency_qos_update_request(sst_drv_ctx->qos, 0);
 
        sst_drv_ctx->sst_state = SST_FW_LOADING;
 
@@ -442,7 +442,7 @@ int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
 
 restore:
        /* Re-enable Deeper C-states beyond C6 */
-       pm_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE);
+       cpu_latency_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE);
        sst_free_block(sst_drv_ctx, block);
        dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n");
 
index 863a477..a917615 100644 (file)
 #include <asm/intel-family.h>
 #include <asm/iosf_mbi.h>
 
-#define ICPU(model)    { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
-
 #define SOC_INTEL_IS_CPU(soc, type)                            \
 static inline bool soc_intel_is_##soc(void)                    \
 {                                                              \
        static const struct x86_cpu_id soc##_cpu_ids[] = {      \
-               ICPU(type),                                     \
+               X86_MATCH_INTEL_FAM6_MODEL(type, NULL),         \
                {}                                              \
        };                                                      \
        const struct x86_cpu_id *id;                            \
@@ -32,11 +30,11 @@ static inline bool soc_intel_is_##soc(void)                 \
        return false;                                           \
 }
 
-SOC_INTEL_IS_CPU(byt, INTEL_FAM6_ATOM_SILVERMONT);
-SOC_INTEL_IS_CPU(cht, INTEL_FAM6_ATOM_AIRMONT);
-SOC_INTEL_IS_CPU(apl, INTEL_FAM6_ATOM_GOLDMONT);
-SOC_INTEL_IS_CPU(glk, INTEL_FAM6_ATOM_GOLDMONT_PLUS);
-SOC_INTEL_IS_CPU(cml, INTEL_FAM6_KABYLAKE_L);
+SOC_INTEL_IS_CPU(byt, ATOM_SILVERMONT);
+SOC_INTEL_IS_CPU(cht, ATOM_AIRMONT);
+SOC_INTEL_IS_CPU(apl, ATOM_GOLDMONT);
+SOC_INTEL_IS_CPU(glk, ATOM_GOLDMONT_PLUS);
+SOC_INTEL_IS_CPU(cml, KABYLAKE_L);
 
 static inline bool soc_intel_is_byt_cr(struct platform_device *pdev)
 {
index 3466675..a15aa2f 100644 (file)
@@ -34,8 +34,8 @@ static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf,
        int i;
        ssize_t ret = 0;
 
-       for (i = 0; i < max_pin; i++)
-               ret += snprintf(buf + size, MOD_BUF - size,
+       for (i = 0; i < max_pin; i++) {
+               ret += scnprintf(buf + size, MOD_BUF - size,
                                "%s %d\n\tModule %d\n\tInstance %d\n\t"
                                "In-used %s\n\tType %s\n"
                                "\tState %d\n\tIndex %d\n",
@@ -45,13 +45,15 @@ static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf,
                                m_pin[i].in_use ? "Used" : "Unused",
                                m_pin[i].is_dynamic ? "Dynamic" : "Static",
                                m_pin[i].pin_state, i);
+               size += ret;
+       }
        return ret;
 }
 
 static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf,
                                        ssize_t size, bool direction)
 {
-       return snprintf(buf + size, MOD_BUF - size,
+       return scnprintf(buf + size, MOD_BUF - size,
                        "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t"
                        "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t"
                        "Sample Type %d\n\tCh Map %#x\n",
@@ -75,16 +77,16 @@ static ssize_t module_read(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
-       ret = snprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n"
+       ret = scnprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n"
                        "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid,
                        mconfig->id.module_id, mconfig->id.instance_id,
                        mconfig->id.pvt_id);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Resources:\n\tCPC %#x\n\tIBS %#x\n\tOBS %#x\t\n",
                        res->cpc, res->ibs, res->obs);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Module data:\n\tCore %d\n\tIn queue %d\n\t"
                        "Out queue %d\n\tType %s\n",
                        mconfig->core_id, mconfig->max_in_queue,
@@ -94,38 +96,38 @@ static ssize_t module_read(struct file *file, char __user *user_buf,
        ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true);
        ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Fixup:\n\tParams %#x\n\tConverter %#x\n",
                        mconfig->params_fixup, mconfig->converter);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n",
                        mconfig->dev_type, mconfig->vbus_id,
                        mconfig->hw_conn_type, mconfig->time_slot);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t"
                        "Pages %#x\n", mconfig->pipe->ppl_id,
                        mconfig->pipe->pipe_priority, mconfig->pipe->conn_type,
                        mconfig->pipe->memory_pages);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n",
                        mconfig->pipe->p_params->host_dma_id,
                        mconfig->pipe->p_params->link_dma_id);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n",
                        mconfig->pipe->p_params->ch,
                        mconfig->pipe->p_params->s_freq,
                        mconfig->pipe->p_params->s_fmt);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "\tLink %#x\n\tStream %#x\n",
                        mconfig->pipe->p_params->linktype,
                        mconfig->pipe->p_params->stream);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "\tState %d\n\tPassthru %s\n",
                        mconfig->pipe->state,
                        mconfig->pipe->passthru ? "true" : "false");
@@ -135,7 +137,7 @@ static ssize_t module_read(struct file *file, char __user *user_buf,
        ret += skl_print_pins(mconfig->m_out_pin, buf,
                        mconfig->max_out_queue, ret, false);
 
-       ret += snprintf(buf + ret, MOD_BUF - ret,
+       ret += scnprintf(buf + ret, MOD_BUF - ret,
                        "Other:\n\tDomain %d\n\tHomogeneous Input %s\n\t"
                        "Homogeneous Output %s\n\tIn Queue Mask %d\n\t"
                        "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t"
@@ -191,7 +193,7 @@ static ssize_t fw_softreg_read(struct file *file, char __user *user_buf,
                __ioread32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2);
 
        for (offset = 0; offset < FW_REG_SIZE; offset += 16) {
-               ret += snprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset);
+               ret += scnprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset);
                hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4,
                                   tmp + ret, FW_REG_BUF - ret, 0);
                ret += strlen(tmp + ret);
index 1c0e522..bd43885 100644 (file)
@@ -384,9 +384,11 @@ static int skl_clk_dev_probe(struct platform_device *pdev)
                                &clks[i], clk_pdata, i);
 
                if (IS_ERR(data->clk[data->avail_clk_cnt])) {
-                       ret = PTR_ERR(data->clk[data->avail_clk_cnt++]);
+                       ret = PTR_ERR(data->clk[data->avail_clk_cnt]);
                        goto err_unreg_skl_clk;
                }
+
+               data->avail_clk_cnt++;
        }
 
        platform_set_drvdata(pdev, data);
index 9cfbd34..8a0db28 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
+#include <linux/reset.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
 
@@ -378,6 +379,11 @@ static int g12a_tohdmitx_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        void __iomem *regs;
        struct regmap *map;
+       int ret;
+
+       ret = device_reset(dev);
+       if (ret)
+               return ret;
 
        regs = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(regs))
index 14e175c..785a038 100644 (file)
@@ -451,7 +451,7 @@ int snd_soc_pcm_component_sync_stop(struct snd_pcm_substream *substream)
        int i, ret;
 
        for_each_rtd_components(rtd, i, component) {
-               if (component->driver->ioctl) {
+               if (component->driver->sync_stop) {
                        ret = component->driver->sync_stop(component,
                                                           substream);
                        if (ret < 0)
index 223cd04..392a1c5 100644 (file)
@@ -299,7 +299,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
        for_each_dpcm_be(fe, stream, dpcm)
                dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
 
-       snd_soc_dapm_stream_stop(fe, stream);
+       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
        fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
index 9b13056..9fb54e6 100644 (file)
@@ -4772,7 +4772,7 @@ static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm)
                        continue;
                if (w->power) {
                        dapm_seq_insert(w, &down_list, false);
-                       w->power = 0;
+                       w->new_power = 0;
                        powerdown = 1;
                }
        }
index ff1b7c7..2c59b36 100644 (file)
@@ -2006,7 +2006,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
        soc_pcm_close(substream);
 
        /* run the stream event for each BE */
-       snd_soc_dapm_stream_stop(fe, stream);
+       dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
 
        fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
        dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
@@ -3171,16 +3171,16 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
        unsigned long flags;
 
        /* FE state */
-       offset += snprintf(buf + offset, size - offset,
+       offset += scnprintf(buf + offset, size - offset,
                        "[%s - %s]\n", fe->dai_link->name,
                        stream ? "Capture" : "Playback");
 
-       offset += snprintf(buf + offset, size - offset, "State: %s\n",
+       offset += scnprintf(buf + offset, size - offset, "State: %s\n",
                        dpcm_state_string(fe->dpcm[stream].state));
 
        if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
            (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
-               offset += snprintf(buf + offset, size - offset,
+               offset += scnprintf(buf + offset, size - offset,
                                "Hardware Params: "
                                "Format = %s, Channels = %d, Rate = %d\n",
                                snd_pcm_format_name(params_format(params)),
@@ -3188,10 +3188,10 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
                                params_rate(params));
 
        /* BEs state */
-       offset += snprintf(buf + offset, size - offset, "Backends:\n");
+       offset += scnprintf(buf + offset, size - offset, "Backends:\n");
 
        if (list_empty(&fe->dpcm[stream].be_clients)) {
-               offset += snprintf(buf + offset, size - offset,
+               offset += scnprintf(buf + offset, size - offset,
                                " No active DSP links\n");
                goto out;
        }
@@ -3201,16 +3201,16 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
                struct snd_soc_pcm_runtime *be = dpcm->be;
                params = &dpcm->hw_params;
 
-               offset += snprintf(buf + offset, size - offset,
+               offset += scnprintf(buf + offset, size - offset,
                                "- %s\n", be->dai_link->name);
 
-               offset += snprintf(buf + offset, size - offset,
+               offset += scnprintf(buf + offset, size - offset,
                                "   State: %s\n",
                                dpcm_state_string(be->dpcm[stream].state));
 
                if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
                    (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
-                       offset += snprintf(buf + offset, size - offset,
+                       offset += scnprintf(buf + offset, size - offset,
                                "   Hardware Params: "
                                "Format = %s, Channels = %d, Rate = %d\n",
                                snd_pcm_format_name(params_format(params)),
index d2ee6ad..575da6a 100644 (file)
@@ -2377,8 +2377,11 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg,
                }
 
                ret = soc_tplg_link_config(tplg, _link);
-               if (ret < 0)
+               if (ret < 0) {
+                       if (!abi_match)
+                               kfree(_link);
                        return ret;
+               }
 
                /* offset by version-specific struct size and
                 * real priv data size
@@ -2542,7 +2545,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
 {
        struct snd_soc_tplg_manifest *manifest, *_manifest;
        bool abi_match;
-       int err;
+       int ret = 0;
 
        if (tplg->pass != SOC_TPLG_PASS_MANIFEST)
                return 0;
@@ -2555,19 +2558,19 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg,
                _manifest = manifest;
        } else {
                abi_match = false;
-               err = manifest_new_ver(tplg, manifest, &_manifest);
-               if (err < 0)
-                       return err;
+               ret = manifest_new_ver(tplg, manifest, &_manifest);
+               if (ret < 0)
+                       return ret;
        }
 
        /* pass control to component driver for optional further init */
        if (tplg->comp && tplg->ops && tplg->ops->manifest)
-               return tplg->ops->manifest(tplg->comp, tplg->index, _manifest);
+               ret = tplg->ops->manifest(tplg->comp, tplg->index, _manifest);
 
        if (!abi_match) /* free the duplicated one */
                kfree(_manifest);
 
-       return 0;
+       return ret;
 }
 
 /* validate header magic, size and type */
index b63fc52..78aa1da 100644 (file)
@@ -499,7 +499,7 @@ int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp,
 
        /* send IPC to the DSP */
        err = sof_ipc_tx_message(sdev->ipc,
-                                stream.hdr.cmd, &stream, sizeof(stream), &posn,
+                                stream.hdr.cmd, &stream, sizeof(stream), posn,
                                 sizeof(*posn));
        if (err < 0) {
                dev_err(sdev->dev, "error: failed to get stream %d position\n",
index 30bcd5d..10eb4b8 100644 (file)
@@ -1543,20 +1543,20 @@ static int stm32_sai_sub_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = devm_snd_soc_register_component(&pdev->dev, &stm32_component,
-                                             &sai->cpu_dai_drv, 1);
+       ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not register pcm dma\n");
+               return ret;
+       }
+
+       ret = snd_soc_register_component(&pdev->dev, &stm32_component,
+                                        &sai->cpu_dai_drv, 1);
        if (ret)
                return ret;
 
        if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
                conf = &stm32_sai_pcm_config_spdif;
 
-       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
-       if (ret) {
-               dev_err(&pdev->dev, "Could not register pcm dma\n");
-               return ret;
-       }
-
        return 0;
 }
 
@@ -1565,6 +1565,8 @@ static int stm32_sai_sub_remove(struct platform_device *pdev)
        struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev);
 
        clk_unprepare(sai->pdata->pclk);
+       snd_dmaengine_pcm_unregister(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        return 0;
 }
index 3f226be..913579c 100644 (file)
@@ -112,7 +112,7 @@ static void omap_dmic_dai_shutdown(struct snd_pcm_substream *substream,
 
        mutex_lock(&dmic->mutex);
 
-       pm_qos_remove_request(&dmic->pm_qos_req);
+       cpu_latency_qos_remove_request(&dmic->pm_qos_req);
 
        if (!dai->active)
                dmic->active = 0;
@@ -230,8 +230,9 @@ static int omap_dmic_dai_prepare(struct snd_pcm_substream *substream,
        struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
        u32 ctrl;
 
-       if (pm_qos_request_active(&dmic->pm_qos_req))
-               pm_qos_update_request(&dmic->pm_qos_req, dmic->latency);
+       if (cpu_latency_qos_request_active(&dmic->pm_qos_req))
+               cpu_latency_qos_update_request(&dmic->pm_qos_req,
+                                              dmic->latency);
 
        /* Configure uplink threshold */
        omap_dmic_write(dmic, OMAP_DMIC_FIFO_CTRL_REG, dmic->threshold);
index 26b503b..302d5c4 100644 (file)
@@ -836,10 +836,10 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
        int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
 
        if (mcbsp->latency[stream2])
-               pm_qos_update_request(&mcbsp->pm_qos_req,
-                                     mcbsp->latency[stream2]);
+               cpu_latency_qos_update_request(&mcbsp->pm_qos_req,
+                                              mcbsp->latency[stream2]);
        else if (mcbsp->latency[stream1])
-               pm_qos_remove_request(&mcbsp->pm_qos_req);
+               cpu_latency_qos_remove_request(&mcbsp->pm_qos_req);
 
        mcbsp->latency[stream1] = 0;
 
@@ -863,10 +863,10 @@ static int omap_mcbsp_dai_prepare(struct snd_pcm_substream *substream,
        if (!latency || mcbsp->latency[stream1] < latency)
                latency = mcbsp->latency[stream1];
 
-       if (pm_qos_request_active(pm_qos_req))
-               pm_qos_update_request(pm_qos_req, latency);
+       if (cpu_latency_qos_request_active(pm_qos_req))
+               cpu_latency_qos_update_request(pm_qos_req, latency);
        else if (latency)
-               pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
+               cpu_latency_qos_add_request(pm_qos_req, latency);
 
        return 0;
 }
@@ -1434,8 +1434,8 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
        if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
                mcbsp->pdata->ops->free(mcbsp->id);
 
-       if (pm_qos_request_active(&mcbsp->pm_qos_req))
-               pm_qos_remove_request(&mcbsp->pm_qos_req);
+       if (cpu_latency_qos_request_active(&mcbsp->pm_qos_req))
+               cpu_latency_qos_remove_request(&mcbsp->pm_qos_req);
 
        if (mcbsp->pdata->buffer_size)
                sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
index a726cd7..d7ac4df 100644 (file)
@@ -281,10 +281,10 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
        }
 
        if (mcpdm->latency[stream2])
-               pm_qos_update_request(&mcpdm->pm_qos_req,
-                                     mcpdm->latency[stream2]);
+               cpu_latency_qos_update_request(&mcpdm->pm_qos_req,
+                                              mcpdm->latency[stream2]);
        else if (mcpdm->latency[stream1])
-               pm_qos_remove_request(&mcpdm->pm_qos_req);
+               cpu_latency_qos_remove_request(&mcpdm->pm_qos_req);
 
        mcpdm->latency[stream1] = 0;
 
@@ -386,10 +386,10 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
        if (!latency || mcpdm->latency[stream1] < latency)
                latency = mcpdm->latency[stream1];
 
-       if (pm_qos_request_active(pm_qos_req))
-               pm_qos_update_request(pm_qos_req, latency);
+       if (cpu_latency_qos_request_active(pm_qos_req))
+               cpu_latency_qos_update_request(pm_qos_req, latency);
        else if (latency)
-               pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
+               cpu_latency_qos_add_request(pm_qos_req, latency);
 
        if (!omap_mcpdm_active(mcpdm)) {
                omap_mcpdm_start(mcpdm);
@@ -451,8 +451,8 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
        free_irq(mcpdm->irq, (void *)mcpdm);
        pm_runtime_disable(mcpdm->dev);
 
-       if (pm_qos_request_active(&mcpdm->pm_qos_req))
-               pm_qos_remove_request(&mcpdm->pm_qos_req);
+       if (cpu_latency_qos_request_active(&mcpdm->pm_qos_req))
+               cpu_latency_qos_remove_request(&mcpdm->pm_qos_req);
 
        return 0;
 }
index b5a3f75..4f09668 100644 (file)
@@ -305,7 +305,7 @@ static void line6_data_received(struct urb *urb)
                                line6_midibuf_read(mb, line6->buffer_message,
                                                LINE6_MIDI_MESSAGE_MAXLEN);
 
-                       if (done == 0)
+                       if (done <= 0)
                                break;
 
                        line6->message_length = done;
index 8d6eefa..6a70463 100644 (file)
@@ -159,7 +159,7 @@ int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
                        int midi_length_prev =
                            midibuf_message_length(this->command_prev);
 
-                       if (midi_length_prev > 0) {
+                       if (midi_length_prev > 1) {
                                midi_length = midi_length_prev - 1;
                                repeat = 1;
                        } else
index ebe1685..d5e517d 100644 (file)
 #define MSR_K7_HWCR                    0xc0010015
 #define MSR_K7_HWCR_SMMLOCK_BIT                0
 #define MSR_K7_HWCR_SMMLOCK            BIT_ULL(MSR_K7_HWCR_SMMLOCK_BIT)
+#define MSR_K7_HWCR_IRPERF_EN_BIT      30
+#define MSR_K7_HWCR_IRPERF_EN          BIT_ULL(MSR_K7_HWCR_IRPERF_EN_BIT)
 #define MSR_K7_FID_VID_CTL             0xc0010041
 #define MSR_K7_FID_VID_STATUS          0xc0010042
 
index 503d3f4..3f3f780 100644 (file)
@@ -390,6 +390,7 @@ struct kvm_sync_regs {
 #define KVM_STATE_NESTED_GUEST_MODE    0x00000001
 #define KVM_STATE_NESTED_RUN_PENDING   0x00000002
 #define KVM_STATE_NESTED_EVMCS         0x00000004
+#define KVM_STATE_NESTED_MTF_PENDING   0x00000008
 
 #define KVM_STATE_NESTED_SMM_GUEST_MODE        0x00000001
 #define KVM_STATE_NESTED_SMM_VMXON     0x00000002
index e978a63..036e667 100644 (file)
@@ -4,10 +4,7 @@
 
 #include <stdio.h>
 
-/* controllable printf */
-extern int pr_output;
-#define printk(fmt, ...)       \
-       (pr_output ? printf(fmt, ##__VA_ARGS__) : 0)
+#define printk(fmt, ...) printf(fmt, ##__VA_ARGS__)
 
 #define pr_err printk
 #define pr_warn        printk
index e18eeb0..a9b9781 100644 (file)
@@ -14,8 +14,6 @@
 #include <linux/kernel.h>
 #include <linux/bootconfig.h>
 
-int pr_output = 1;
-
 static int xbc_show_array(struct xbc_node *node)
 {
        const char *val;
@@ -131,15 +129,26 @@ int load_xbc_from_initrd(int fd, char **buf)
        struct stat stat;
        int ret;
        u32 size = 0, csum = 0, rcsum;
+       char magic[BOOTCONFIG_MAGIC_LEN];
 
        ret = fstat(fd, &stat);
        if (ret < 0)
                return -errno;
 
-       if (stat.st_size < 8)
+       if (stat.st_size < 8 + BOOTCONFIG_MAGIC_LEN)
+               return 0;
+
+       if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) {
+               pr_err("Failed to lseek: %d\n", -errno);
+               return -errno;
+       }
+       if (read(fd, magic, BOOTCONFIG_MAGIC_LEN) < 0)
+               return -errno;
+       /* Check the bootconfig magic bytes */
+       if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0)
                return 0;
 
-       if (lseek(fd, -8, SEEK_END) < 0) {
+       if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0) {
                pr_err("Failed to lseek: %d\n", -errno);
                return -errno;
        }
@@ -150,11 +159,14 @@ int load_xbc_from_initrd(int fd, char **buf)
        if (read(fd, &csum, sizeof(u32)) < 0)
                return -errno;
 
-       /* Wrong size, maybe no boot config here */
-       if (stat.st_size < size + 8)
-               return 0;
+       /* Wrong size error  */
+       if (stat.st_size < size + 8 + BOOTCONFIG_MAGIC_LEN) {
+               pr_err("bootconfig size is too big\n");
+               return -E2BIG;
+       }
 
-       if (lseek(fd, stat.st_size - 8 - size, SEEK_SET) < 0) {
+       if (lseek(fd, stat.st_size - (size + 8 + BOOTCONFIG_MAGIC_LEN),
+                 SEEK_SET) < 0) {
                pr_err("Failed to lseek: %d\n", -errno);
                return -errno;
        }
@@ -163,17 +175,17 @@ int load_xbc_from_initrd(int fd, char **buf)
        if (ret < 0)
                return ret;
 
-       /* Wrong Checksum, maybe no boot config here */
+       /* Wrong Checksum */
        rcsum = checksum((unsigned char *)*buf, size);
        if (csum != rcsum) {
                pr_err("checksum error: %d != %d\n", csum, rcsum);
-               return 0;
+               return -EINVAL;
        }
 
        ret = xbc_init(*buf);
-       /* Wrong data, maybe no boot config here */
+       /* Wrong data */
        if (ret < 0)
-               return 0;
+               return ret;
 
        return size;
 }
@@ -213,20 +225,15 @@ int delete_xbc(const char *path)
                return -errno;
        }
 
-       /*
-        * Suppress error messages in xbc_init() because it can be just a
-        * data which concidentally matches the size and checksum footer.
-        */
-       pr_output = 0;
        size = load_xbc_from_initrd(fd, &buf);
-       pr_output = 1;
        if (size < 0) {
                ret = size;
                pr_err("Failed to load a boot config from initrd: %d\n", ret);
        } else if (size > 0) {
                ret = fstat(fd, &stat);
                if (!ret)
-                       ret = ftruncate(fd, stat.st_size - size - 8);
+                       ret = ftruncate(fd, stat.st_size
+                                       - size - 8 - BOOTCONFIG_MAGIC_LEN);
                if (ret)
                        ret = -errno;
        } /* Ignore if there is no boot config in initrd */
@@ -295,6 +302,12 @@ int apply_xbc(const char *path, const char *xbc_path)
                pr_err("Failed to apply a boot config: %d\n", ret);
                return ret;
        }
+       /* Write a magic word of the bootconfig */
+       ret = write(fd, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN);
+       if (ret < 0) {
+               pr_err("Failed to apply a boot config magic: %d\n", ret);
+               return ret;
+       }
        close(fd);
        free(data);
 
diff --git a/tools/bootconfig/samples/bad-mixed-kv1.bconf b/tools/bootconfig/samples/bad-mixed-kv1.bconf
new file mode 100644 (file)
index 0000000..1761547
--- /dev/null
@@ -0,0 +1,3 @@
+# value -> subkey pattern
+key = value
+key.subkey = another-value
diff --git a/tools/bootconfig/samples/bad-mixed-kv2.bconf b/tools/bootconfig/samples/bad-mixed-kv2.bconf
new file mode 100644 (file)
index 0000000..6b32e0c
--- /dev/null
@@ -0,0 +1,3 @@
+# subkey -> value pattern
+key.subkey = value
+key = another-value
diff --git a/tools/bootconfig/samples/bad-samekey.bconf b/tools/bootconfig/samples/bad-samekey.bconf
new file mode 100644 (file)
index 0000000..e8d983a
--- /dev/null
@@ -0,0 +1,6 @@
+# Same key value is not allowed
+key {
+       foo = value
+       bar = value2
+}
+key.foo = value
index 1de06de..1411f4c 100755 (executable)
@@ -9,7 +9,7 @@ TEMPCONF=`mktemp temp-XXXX.bconf`
 NG=0
 
 cleanup() {
-  rm -f $INITRD $TEMPCONF
+  rm -f $INITRD $TEMPCONF $OUTFILE
   exit $NG
 }
 
@@ -49,7 +49,7 @@ xpass $BOOTCONF -a $TEMPCONF $INITRD
 new_size=$(stat -c %s $INITRD)
 
 echo "File size check"
-xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9)
+xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9 + 12)
 
 echo "Apply command repeat test"
 xpass $BOOTCONF -a $TEMPCONF $INITRD
@@ -71,7 +71,6 @@ printf " \0\0\0 \0\0\0" >> $INITRD
 $BOOTCONF -a $TEMPCONF $INITRD > $OUTFILE 2>&1
 xfail grep -i "failed" $OUTFILE
 xfail grep -i "error" $OUTFILE
-rm $OUTFILE
 
 echo "Max node number check"
 
@@ -96,6 +95,19 @@ truncate -s 32764 $TEMPCONF
 echo "\"" >> $TEMPCONF # add 2 bytes + terminal ('\"\n\0')
 xpass $BOOTCONF -a $TEMPCONF $INITRD
 
+echo "Adding same-key values"
+cat > $TEMPCONF << EOF
+key = bar, baz
+key += qux
+EOF
+echo > $INITRD
+
+xpass $BOOTCONF -a $TEMPCONF $INITRD
+$BOOTCONF $INITRD > $OUTFILE
+xpass grep -q "bar" $OUTFILE
+xpass grep -q "baz" $OUTFILE
+xpass grep -q "qux" $OUTFILE
+
 echo "=== expected failure cases ==="
 for i in samples/bad-* ; do
   xfail $BOOTCONF -a $i $INITRD
similarity index 100%
rename from Documentation/EDID/edid.S
rename to tools/edid/edid.S
similarity index 100%
rename from Documentation/EDID/hex
rename to tools/edid/hex
index e734da3..67e01bb 100644 (file)
@@ -2,12 +2,12 @@
 #ifndef _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
 #define _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_
 
-# define trace_hardirq_context(p)      0
-# define trace_softirq_context(p)      0
-# define trace_hardirqs_enabled(p)     0
-# define trace_softirqs_enabled(p)     0
-# define trace_hardirq_enter()         do { } while (0)
-# define trace_hardirq_exit()          do { } while (0)
+# define lockdep_hardirq_context(p)    0
+# define lockdep_softirq_context(p)    0
+# define lockdep_hardirqs_enabled(p)   0
+# define lockdep_softirqs_enabled(p)   0
+# define lockdep_hardirq_enter()       do { } while (0)
+# define lockdep_hardirq_exit()                do { } while (0)
 # define lockdep_softirq_enter()       do { } while (0)
 # define lockdep_softirq_exit()                do { } while (0)
 # define INIT_TRACE_IRQFLAGS
index ce3c594..637189e 100644 (file)
@@ -1,18 +1,18 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #if defined(__i386__) || defined(__x86_64__)
-#include "../../arch/x86/include/uapi/asm/errno.h"
+#include "../../../arch/x86/include/uapi/asm/errno.h"
 #elif defined(__powerpc__)
-#include "../../arch/powerpc/include/uapi/asm/errno.h"
+#include "../../../arch/powerpc/include/uapi/asm/errno.h"
 #elif defined(__sparc__)
-#include "../../arch/sparc/include/uapi/asm/errno.h"
+#include "../../../arch/sparc/include/uapi/asm/errno.h"
 #elif defined(__alpha__)
-#include "../../arch/alpha/include/uapi/asm/errno.h"
+#include "../../../arch/alpha/include/uapi/asm/errno.h"
 #elif defined(__mips__)
-#include "../../arch/mips/include/uapi/asm/errno.h"
+#include "../../../arch/mips/include/uapi/asm/errno.h"
 #elif defined(__ia64__)
-#include "../../arch/ia64/include/uapi/asm/errno.h"
+#include "../../../arch/ia64/include/uapi/asm/errno.h"
 #elif defined(__xtensa__)
-#include "../../arch/xtensa/include/uapi/asm/errno.h"
+#include "../../../arch/xtensa/include/uapi/asm/errno.h"
 #else
 #include <asm-generic/errno.h>
 #endif
index 1521073..8533bf0 100644 (file)
@@ -74,6 +74,8 @@ enum {
 #define IPPROTO_UDPLITE                IPPROTO_UDPLITE
   IPPROTO_MPLS = 137,          /* MPLS in IP (RFC 4023)                */
 #define IPPROTO_MPLS           IPPROTO_MPLS
+  IPPROTO_ETHERNET = 143,      /* Ethernet-within-IPv6 Encapsulation   */
+#define IPPROTO_ETHERNET       IPPROTO_ETHERNET
   IPPROTO_RAW = 255,           /* Raw IP packets                       */
 #define IPPROTO_RAW            IPPROTO_RAW
   IPPROTO_MPTCP = 262,         /* Multipath TCP connection             */
index 377d794..397cfd6 100644 (file)
@@ -181,6 +181,8 @@ enum perf_branch_sample_type_shift {
 
        PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT      = 16, /* save branch type */
 
+       PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT       = 17, /* save low level index of raw branch records */
+
        PERF_SAMPLE_BRANCH_MAX_SHIFT            /* non-ABI */
 };
 
@@ -208,6 +210,8 @@ enum perf_branch_sample_type {
        PERF_SAMPLE_BRANCH_TYPE_SAVE    =
                1U << PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT,
 
+       PERF_SAMPLE_BRANCH_HW_INDEX     = 1U << PERF_SAMPLE_BRANCH_HW_INDEX_SHIFT,
+
        PERF_SAMPLE_BRANCH_MAX          = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
 };
 
@@ -853,7 +857,9 @@ enum perf_event_type {
         *        char                  data[size];}&& PERF_SAMPLE_RAW
         *
         *      { u64                   nr;
-        *        { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK
+        *        { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX
+        *        { u64 from, to, flags } lbr[nr];
+        *      } && PERF_SAMPLE_BRANCH_STACK
         *
         *      { u64                   abi; # enum perf_sample_regs_abi
         *        u64                   regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
index f4ed962..0f75b28 100644 (file)
@@ -1,2 +1,3 @@
 libapi-y += fs.o
 libapi-y += tracing_path.o
+libapi-y += cgroup.o
diff --git a/tools/lib/api/fs/cgroup.c b/tools/lib/api/fs/cgroup.c
new file mode 100644 (file)
index 0000000..889a6eb
--- /dev/null
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/stringify.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fs.h"
+
+int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys)
+{
+       FILE *fp;
+       char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
+       char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path;
+       char *token, *saved_ptr = NULL;
+
+       fp = fopen("/proc/mounts", "r");
+       if (!fp)
+               return -1;
+
+       /*
+        * in order to handle split hierarchy, we need to scan /proc/mounts
+        * and inspect every cgroupfs mount point to find one that has
+        * perf_event subsystem
+        */
+       path_v1[0] = '\0';
+       path_v2[0] = '\0';
+
+       while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %"
+                               __stringify(PATH_MAX)"s %*d %*d\n",
+                               mountpoint, type, tokens) == 3) {
+
+               if (!path_v1[0] && !strcmp(type, "cgroup")) {
+
+                       token = strtok_r(tokens, ",", &saved_ptr);
+
+                       while (token != NULL) {
+                               if (subsys && !strcmp(token, subsys)) {
+                                       strcpy(path_v1, mountpoint);
+                                       break;
+                               }
+                               token = strtok_r(NULL, ",", &saved_ptr);
+                       }
+               }
+
+               if (!path_v2[0] && !strcmp(type, "cgroup2"))
+                       strcpy(path_v2, mountpoint);
+
+               if (path_v1[0] && path_v2[0])
+                       break;
+       }
+       fclose(fp);
+
+       if (path_v1[0])
+               path = path_v1;
+       else if (path_v2[0])
+               path = path_v2;
+       else
+               return -1;
+
+       if (strlen(path) < maxlen) {
+               strcpy(buf, path);
+               return 0;
+       }
+       return -1;
+}
index 92d03b8..936edb9 100644 (file)
@@ -28,6 +28,8 @@ FS(bpf_fs)
 #undef FS
 
 
+int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys);
+
 int filename__read_int(const char *filename, int *value);
 int filename__read_ull(const char *filename, unsigned long long *value);
 int filename__read_xll(const char *filename, unsigned long long *value);
diff --git a/tools/lib/perf/Documentation/examples/counting.c b/tools/lib/perf/Documentation/examples/counting.c
new file mode 100644 (file)
index 0000000..6085693
--- /dev/null
@@ -0,0 +1,83 @@
+#include <linux/perf_event.h>
+#include <perf/evlist.h>
+#include <perf/evsel.h>
+#include <perf/cpumap.h>
+#include <perf/threadmap.h>
+#include <perf/mmap.h>
+#include <perf/core.h>
+#include <perf/event.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int libperf_print(enum libperf_print_level level,
+                         const char *fmt, va_list ap)
+{
+       return vfprintf(stderr, fmt, ap);
+}
+
+int main(int argc, char **argv)
+{
+       int count = 100000, err = 0;
+       struct perf_evlist *evlist;
+       struct perf_evsel *evsel;
+       struct perf_thread_map *threads;
+       struct perf_counts_values counts;
+
+       struct perf_event_attr attr1 = {
+               .type        = PERF_TYPE_SOFTWARE,
+               .config      = PERF_COUNT_SW_CPU_CLOCK,
+               .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING,
+               .disabled    = 1,
+       };
+       struct perf_event_attr attr2 = {
+               .type        = PERF_TYPE_SOFTWARE,
+               .config      = PERF_COUNT_SW_TASK_CLOCK,
+               .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING,
+               .disabled    = 1,
+       };
+
+       libperf_init(libperf_print);
+       threads = perf_thread_map__new_dummy();
+       if (!threads) {
+               fprintf(stderr, "failed to create threads\n");
+               return -1;
+       }
+       perf_thread_map__set_pid(threads, 0, 0);
+       evlist = perf_evlist__new();
+       if (!evlist) {
+               fprintf(stderr, "failed to create evlist\n");
+               goto out_threads;
+       }
+       evsel = perf_evsel__new(&attr1);
+       if (!evsel) {
+               fprintf(stderr, "failed to create evsel1\n");
+               goto out_evlist;
+       }
+       perf_evlist__add(evlist, evsel);
+       evsel = perf_evsel__new(&attr2);
+       if (!evsel) {
+               fprintf(stderr, "failed to create evsel2\n");
+               goto out_evlist;
+       }
+       perf_evlist__add(evlist, evsel);
+       perf_evlist__set_maps(evlist, NULL, threads);
+       err = perf_evlist__open(evlist);
+       if (err) {
+               fprintf(stderr, "failed to open evsel\n");
+               goto out_evlist;
+       }
+       perf_evlist__enable(evlist);
+       while (count--);
+       perf_evlist__disable(evlist);
+       perf_evlist__for_each_evsel(evlist, evsel) {
+               perf_evsel__read(evsel, 0, 0, &counts);
+               fprintf(stdout, "count %llu, enabled %llu, run %llu\n",
+                               counts.val, counts.ena, counts.run);
+       }
+       perf_evlist__close(evlist);
+out_evlist:
+       perf_evlist__delete(evlist);
+out_threads:
+       perf_thread_map__put(threads);
+       return err;
+}
index beaa8b8..e1bd2a9 100644 (file)
@@ -5541,7 +5541,7 @@ static void print_event_time(struct tep_handle *tep, struct trace_seq *s,
        if (p10 > 1 && p10 < time)
                trace_seq_printf(s, "%5llu.%0*llu", time / p10, prec, time % p10);
        else
-               trace_seq_printf(s, "%12llu\n", time);
+               trace_seq_printf(s, "%12llu", time);
 }
 
 struct print_event_type {
index 8dc4f08..66f44f5 100644 (file)
@@ -11,6 +11,7 @@ objtool-y += objtool.o
 objtool-y += libstring.o
 objtool-y += libctype.o
 objtool-y += str_error_r.o
+objtool-y += librbtree.o
 
 CFLAGS += -I$(srctree)/tools/lib
 
@@ -25,3 +26,7 @@ $(OUTPUT)libctype.o: ../lib/ctype.c FORCE
 $(OUTPUT)str_error_r.o: ../lib/str_error_r.c FORCE
        $(call rule_mkdir)
        $(call if_changed_dep,cc_o_c)
+
+$(OUTPUT)librbtree.o: ../lib/rbtree.c FORCE
+       $(call rule_mkdir)
+       $(call if_changed_dep,cc_o_c)
index c807984..10fbe75 100644 (file)
@@ -17,7 +17,7 @@
 #include "builtin.h"
 #include "check.h"
 
-bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess;
+bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats;
 
 static const char * const check_usage[] = {
        "objtool check [<options>] file.o",
@@ -31,6 +31,7 @@ const struct option check_options[] = {
        OPT_BOOLEAN('m', "module", &module, "Indicates the object will be part of a kernel module"),
        OPT_BOOLEAN('b', "backtrace", &backtrace, "unwind on error"),
        OPT_BOOLEAN('a', "uaccess", &uaccess, "enable uaccess checking"),
+       OPT_BOOLEAN('s', "stats", &stats, "print statistics"),
        OPT_END(),
 };
 
index a32736f..0b90790 100644 (file)
@@ -8,7 +8,7 @@
 #include <subcmd/parse-options.h>
 
 extern const struct option check_options[];
-extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess;
+extern bool no_fp, no_unreachable, retpoline, module, backtrace, uaccess, stats;
 
 extern int cmd_check(int argc, const char **argv);
 extern int cmd_orc(int argc, const char **argv);
index 4768d91..8dd01f9 100644 (file)
@@ -72,22 +72,22 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
        return find_insn(file, func->cfunc->sec, func->cfunc->offset);
 }
 
-#define func_for_each_insn_all(file, func, insn)                       \
+#define func_for_each_insn(file, func, insn)                           \
        for (insn = find_insn(file, func->sec, func->offset);           \
             insn;                                                      \
             insn = next_insn_same_func(file, insn))
 
-#define func_for_each_insn(file, func, insn)                           \
-       for (insn = find_insn(file, func->sec, func->offset);           \
+#define sym_for_each_insn(file, sym, insn)                             \
+       for (insn = find_insn(file, sym->sec, sym->offset);             \
             insn && &insn->list != &file->insn_list &&                 \
-               insn->sec == func->sec &&                               \
-               insn->offset < func->offset + func->len;                \
+               insn->sec == sym->sec &&                                \
+               insn->offset < sym->offset + sym->len;                  \
             insn = list_next_entry(insn, list))
 
-#define func_for_each_insn_continue_reverse(file, func, insn)          \
+#define sym_for_each_insn_continue_reverse(file, sym, insn)            \
        for (insn = list_prev_entry(insn, list);                        \
             &insn->list != &file->insn_list &&                         \
-               insn->sec == func->sec && insn->offset >= func->offset; \
+               insn->sec == sym->sec && insn->offset >= sym->offset;   \
             insn = list_prev_entry(insn, list))
 
 #define sec_for_each_insn_from(file, insn)                             \
@@ -97,14 +97,19 @@ static struct instruction *next_insn_same_func(struct objtool_file *file,
        for (insn = next_insn_same_sec(file, insn); insn;               \
             insn = next_insn_same_sec(file, insn))
 
+static bool is_static_jump(struct instruction *insn)
+{
+       return insn->type == INSN_JUMP_CONDITIONAL ||
+              insn->type == INSN_JUMP_UNCONDITIONAL;
+}
+
 static bool is_sibling_call(struct instruction *insn)
 {
        /* An indirect jump is either a sibling call or a jump to a table. */
        if (insn->type == INSN_JUMP_DYNAMIC)
                return list_empty(&insn->alts);
 
-       if (insn->type != INSN_JUMP_CONDITIONAL &&
-           insn->type != INSN_JUMP_UNCONDITIONAL)
+       if (!is_static_jump(insn))
                return false;
 
        /* add_jump_destinations() sets insn->call_dest for sibling calls. */
@@ -165,7 +170,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
        if (!insn->func)
                return false;
 
-       func_for_each_insn_all(file, func, insn) {
+       func_for_each_insn(file, func, insn) {
                empty = false;
 
                if (insn->type == INSN_RETURN)
@@ -180,7 +185,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func,
         * case, the function's dead-end status depends on whether the target
         * of the sibling call returns.
         */
-       func_for_each_insn_all(file, func, insn) {
+       func_for_each_insn(file, func, insn) {
                if (is_sibling_call(insn)) {
                        struct instruction *dest = insn->jump_dest;
 
@@ -234,6 +239,7 @@ static int decode_instructions(struct objtool_file *file)
        struct symbol *func;
        unsigned long offset;
        struct instruction *insn;
+       unsigned long nr_insns = 0;
        int ret;
 
        for_each_sec(file, sec) {
@@ -269,6 +275,7 @@ static int decode_instructions(struct objtool_file *file)
 
                        hash_add(file->insn_hash, &insn->hash, insn->offset);
                        list_add_tail(&insn->list, &file->insn_list);
+                       nr_insns++;
                }
 
                list_for_each_entry(func, &sec->symbol_list, list) {
@@ -281,11 +288,14 @@ static int decode_instructions(struct objtool_file *file)
                                return -1;
                        }
 
-                       func_for_each_insn(file, func, insn)
+                       sym_for_each_insn(file, func, insn)
                                insn->func = func;
                }
        }
 
+       if (stats)
+               printf("nr_insns: %lu\n", nr_insns);
+
        return 0;
 
 err:
@@ -415,8 +425,8 @@ static void add_ignores(struct objtool_file *file)
                        break;
 
                case STT_SECTION:
-                       func = find_symbol_by_offset(rela->sym->sec, rela->addend);
-                       if (!func || func->type != STT_FUNC)
+                       func = find_func_by_offset(rela->sym->sec, rela->addend);
+                       if (!func)
                                continue;
                        break;
 
@@ -425,7 +435,7 @@ static void add_ignores(struct objtool_file *file)
                        continue;
                }
 
-               func_for_each_insn_all(file, func, insn)
+               func_for_each_insn(file, func, insn)
                        insn->ignore = true;
        }
 }
@@ -478,6 +488,7 @@ static const char *uaccess_safe_builtin[] = {
        "__sanitizer_cov_trace_cmp2",
        "__sanitizer_cov_trace_cmp4",
        "__sanitizer_cov_trace_cmp8",
+       "__sanitizer_cov_trace_switch",
        /* UBSAN */
        "ubsan_type_mismatch_common",
        "__ubsan_handle_type_mismatch",
@@ -553,15 +564,14 @@ static int add_jump_destinations(struct objtool_file *file)
        unsigned long dest_off;
 
        for_each_insn(file, insn) {
-               if (insn->type != INSN_JUMP_CONDITIONAL &&
-                   insn->type != INSN_JUMP_UNCONDITIONAL)
+               if (!is_static_jump(insn))
                        continue;
 
                if (insn->ignore || insn->offset == FAKE_JUMP_OFFSET)
                        continue;
 
-               rela = find_rela_by_dest_range(insn->sec, insn->offset,
-                                              insn->len);
+               rela = find_rela_by_dest_range(file->elf, insn->sec,
+                                              insn->offset, insn->len);
                if (!rela) {
                        dest_sec = insn->sec;
                        dest_off = insn->offset + insn->len + insn->immediate;
@@ -657,14 +667,18 @@ static int add_call_destinations(struct objtool_file *file)
                if (insn->type != INSN_CALL)
                        continue;
 
-               rela = find_rela_by_dest_range(insn->sec, insn->offset,
-                                              insn->len);
+               rela = find_rela_by_dest_range(file->elf, insn->sec,
+                                              insn->offset, insn->len);
                if (!rela) {
                        dest_off = insn->offset + insn->len + insn->immediate;
-                       insn->call_dest = find_symbol_by_offset(insn->sec,
-                                                               dest_off);
+                       insn->call_dest = find_func_by_offset(insn->sec, dest_off);
+                       if (!insn->call_dest)
+                               insn->call_dest = find_symbol_by_offset(insn->sec, dest_off);
 
-                       if (!insn->call_dest && !insn->ignore) {
+                       if (insn->ignore)
+                               continue;
+
+                       if (!insn->call_dest) {
                                WARN_FUNC("unsupported intra-function call",
                                          insn->sec, insn->offset);
                                if (retpoline)
@@ -672,11 +686,16 @@ static int add_call_destinations(struct objtool_file *file)
                                return -1;
                        }
 
+                       if (insn->func && insn->call_dest->type != STT_FUNC) {
+                               WARN_FUNC("unsupported call to non-function",
+                                         insn->sec, insn->offset);
+                               return -1;
+                       }
+
                } else if (rela->sym->type == STT_SECTION) {
-                       insn->call_dest = find_symbol_by_offset(rela->sym->sec,
-                                                               rela->addend+4);
-                       if (!insn->call_dest ||
-                           insn->call_dest->type != STT_FUNC) {
+                       insn->call_dest = find_func_by_offset(rela->sym->sec,
+                                                             rela->addend+4);
+                       if (!insn->call_dest) {
                                WARN_FUNC("can't find call dest symbol at %s+0x%x",
                                          insn->sec, insn->offset,
                                          rela->sym->sec->name,
@@ -764,8 +783,28 @@ static int handle_group_alt(struct objtool_file *file,
                insn->ignore = orig_insn->ignore_alts;
                insn->func = orig_insn->func;
 
-               if (insn->type != INSN_JUMP_CONDITIONAL &&
-                   insn->type != INSN_JUMP_UNCONDITIONAL)
+               /*
+                * Since alternative replacement code is copy/pasted by the
+                * kernel after applying relocations, generally such code can't
+                * have relative-address relocation references to outside the
+                * .altinstr_replacement section, unless the arch's
+                * alternatives code can adjust the relative offsets
+                * accordingly.
+                *
+                * The x86 alternatives code adjusts the offsets only when it
+                * encounters a branch instruction at the very beginning of the
+                * replacement group.
+                */
+               if ((insn->offset != special_alt->new_off ||
+                   (insn->type != INSN_CALL && !is_static_jump(insn))) &&
+                   find_rela_by_dest_range(file->elf, insn->sec, insn->offset, insn->len)) {
+
+                       WARN_FUNC("unsupported relocation in alternatives section",
+                                 insn->sec, insn->offset);
+                       return -1;
+               }
+
+               if (!is_static_jump(insn))
                        continue;
 
                if (!insn->immediate)
@@ -1001,7 +1040,7 @@ static struct rela *find_jump_table(struct objtool_file *file,
                                      struct instruction *insn)
 {
        struct rela *text_rela, *table_rela;
-       struct instruction *orig_insn = insn;
+       struct instruction *dest_insn, *orig_insn = insn;
        struct section *table_sec;
        unsigned long table_offset;
 
@@ -1028,8 +1067,8 @@ static struct rela *find_jump_table(struct objtool_file *file,
                    break;
 
                /* look for a relocation which references .rodata */
-               text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
-                                                   insn->len);
+               text_rela = find_rela_by_dest_range(file->elf, insn->sec,
+                                                   insn->offset, insn->len);
                if (!text_rela || text_rela->sym->type != STT_SECTION ||
                    !text_rela->sym->sec->rodata)
                        continue;
@@ -1053,10 +1092,17 @@ static struct rela *find_jump_table(struct objtool_file *file,
                    strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
                        continue;
 
-               /* Each table entry has a rela associated with it. */
-               table_rela = find_rela_by_dest(table_sec, table_offset);
+               /*
+                * Each table entry has a rela associated with it.  The rela
+                * should reference text in the same function as the original
+                * instruction.
+                */
+               table_rela = find_rela_by_dest(file->elf, table_sec, table_offset);
                if (!table_rela)
                        continue;
+               dest_insn = find_insn(file, table_rela->sym->sec, table_rela->addend);
+               if (!dest_insn || !dest_insn->func || dest_insn->func->pfunc != func)
+                       continue;
 
                /*
                 * Use of RIP-relative switch jumps is quite rare, and
@@ -1082,7 +1128,7 @@ static void mark_func_jump_tables(struct objtool_file *file,
        struct instruction *insn, *last = NULL;
        struct rela *rela;
 
-       func_for_each_insn_all(file, func, insn) {
+       func_for_each_insn(file, func, insn) {
                if (!last)
                        last = insn;
 
@@ -1117,7 +1163,7 @@ static int add_func_jump_tables(struct objtool_file *file,
        struct instruction *insn;
        int ret;
 
-       func_for_each_insn_all(file, func, insn) {
+       func_for_each_insn(file, func, insn) {
                if (!insn->jump_table)
                        continue;
 
@@ -1187,7 +1233,7 @@ static int read_unwind_hints(struct objtool_file *file)
        for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) {
                hint = (struct unwind_hint *)sec->data->d_buf + i;
 
-               rela = find_rela_by_dest(sec, i * sizeof(*hint));
+               rela = find_rela_by_dest(file->elf, sec, i * sizeof(*hint));
                if (!rela) {
                        WARN("can't find rela for unwind_hints[%d]", i);
                        return -1;
@@ -1935,6 +1981,41 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
        return validate_call(insn, state);
 }
 
+static int validate_return(struct symbol *func, struct instruction *insn, struct insn_state *state)
+{
+       if (state->uaccess && !func_uaccess_safe(func)) {
+               WARN_FUNC("return with UACCESS enabled",
+                         insn->sec, insn->offset);
+               return 1;
+       }
+
+       if (!state->uaccess && func_uaccess_safe(func)) {
+               WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function",
+                         insn->sec, insn->offset);
+               return 1;
+       }
+
+       if (state->df) {
+               WARN_FUNC("return with DF set",
+                         insn->sec, insn->offset);
+               return 1;
+       }
+
+       if (func && has_modified_stack_frame(state)) {
+               WARN_FUNC("return with modified stack frame",
+                         insn->sec, insn->offset);
+               return 1;
+       }
+
+       if (state->bp_scratch) {
+               WARN("%s uses BP as a scratch register",
+                    func->name);
+               return 1;
+       }
+
+       return 0;
+}
+
 /*
  * Follow the branch starting at the given instruction, and recursively follow
  * any other branches (jumps).  Meanwhile, track the frame pointer state at
@@ -1989,7 +2070,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 
                                i = insn;
                                save_insn = NULL;
-                               func_for_each_insn_continue_reverse(file, func, i) {
+                               sym_for_each_insn_continue_reverse(file, func, i) {
                                        if (i->save) {
                                                save_insn = i;
                                                break;
@@ -2050,34 +2131,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                switch (insn->type) {
 
                case INSN_RETURN:
-                       if (state.uaccess && !func_uaccess_safe(func)) {
-                               WARN_FUNC("return with UACCESS enabled", sec, insn->offset);
-                               return 1;
-                       }
-
-                       if (!state.uaccess && func_uaccess_safe(func)) {
-                               WARN_FUNC("return with UACCESS disabled from a UACCESS-safe function", sec, insn->offset);
-                               return 1;
-                       }
-
-                       if (state.df) {
-                               WARN_FUNC("return with DF set", sec, insn->offset);
-                               return 1;
-                       }
-
-                       if (func && has_modified_stack_frame(&state)) {
-                               WARN_FUNC("return with modified stack frame",
-                                         sec, insn->offset);
-                               return 1;
-                       }
-
-                       if (state.bp_scratch) {
-                               WARN("%s uses BP as a scratch register",
-                                    func->name);
-                               return 1;
-                       }
-
-                       return 0;
+                       return validate_return(func, insn, &state);
 
                case INSN_CALL:
                case INSN_CALL_DYNAMIC:
@@ -2342,9 +2396,8 @@ static bool ignore_unreachable_insn(struct instruction *insn)
        return false;
 }
 
-static int validate_functions(struct objtool_file *file)
+static int validate_section(struct objtool_file *file, struct section *sec)
 {
-       struct section *sec;
        struct symbol *func;
        struct instruction *insn;
        struct insn_state state;
@@ -2357,36 +2410,45 @@ static int validate_functions(struct objtool_file *file)
               CFI_NUM_REGS * sizeof(struct cfi_reg));
        state.stack_size = initial_func_cfi.cfa.offset;
 
-       for_each_sec(file, sec) {
-               list_for_each_entry(func, &sec->symbol_list, list) {
-                       if (func->type != STT_FUNC)
-                               continue;
+       list_for_each_entry(func, &sec->symbol_list, list) {
+               if (func->type != STT_FUNC)
+                       continue;
 
-                       if (!func->len) {
-                               WARN("%s() is missing an ELF size annotation",
-                                    func->name);
-                               warnings++;
-                       }
+               if (!func->len) {
+                       WARN("%s() is missing an ELF size annotation",
+                            func->name);
+                       warnings++;
+               }
 
-                       if (func->pfunc != func || func->alias != func)
-                               continue;
+               if (func->pfunc != func || func->alias != func)
+                       continue;
 
-                       insn = find_insn(file, sec, func->offset);
-                       if (!insn || insn->ignore || insn->visited)
-                               continue;
+               insn = find_insn(file, sec, func->offset);
+               if (!insn || insn->ignore || insn->visited)
+                       continue;
 
-                       state.uaccess = func->uaccess_safe;
+               state.uaccess = func->uaccess_safe;
 
-                       ret = validate_branch(file, func, insn, state);
-                       if (ret && backtrace)
-                               BT_FUNC("<=== (func)", insn);
-                       warnings += ret;
-               }
+               ret = validate_branch(file, func, insn, state);
+               if (ret && backtrace)
+                       BT_FUNC("<=== (func)", insn);
+               warnings += ret;
        }
 
        return warnings;
 }
 
+static int validate_functions(struct objtool_file *file)
+{
+       struct section *sec;
+       int warnings = 0;
+
+       for_each_sec(file, sec)
+               warnings += validate_section(file, sec);
+
+       return warnings;
+}
+
 static int validate_reachable_instructions(struct objtool_file *file)
 {
        struct instruction *insn;
@@ -2405,23 +2467,6 @@ static int validate_reachable_instructions(struct objtool_file *file)
        return 0;
 }
 
-static void cleanup(struct objtool_file *file)
-{
-       struct instruction *insn, *tmpinsn;
-       struct alternative *alt, *tmpalt;
-
-       list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) {
-               list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) {
-                       list_del(&alt->list);
-                       free(alt);
-               }
-               list_del(&insn->list);
-               hash_del(&insn->hash);
-               free(insn);
-       }
-       elf_close(file->elf);
-}
-
 static struct objtool_file file;
 
 int check(const char *_objname, bool orc)
@@ -2489,10 +2534,14 @@ int check(const char *_objname, bool orc)
        }
 
 out:
-       cleanup(&file);
+       if (ret < 0) {
+               /*
+                *  Fatal error.  The binary is corrupt or otherwise broken in
+                *  some way, or objtool itself is broken.  Fail the kernel
+                *  build.
+                */
+               return ret;
+       }
 
-       /* ignore warnings for now until we get all the code cleaned up */
-       if (ret || warnings)
-               return 0;
        return 0;
 }
index 6d875ca..f0ce8ff 100644 (file)
@@ -50,7 +50,7 @@ struct instruction {
 struct objtool_file {
        struct elf *elf;
        struct list_head insn_list;
-       DECLARE_HASHTABLE(insn_hash, 16);
+       DECLARE_HASHTABLE(insn_hash, 20);
        bool ignore_unreachables, c_file, hints, rodata;
 };
 
index edba474..09ddc8f 100644 (file)
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
+#include "builtin.h"
 
 #include "elf.h"
 #include "warn.h"
 
 #define MAX_NAME_LEN 128
 
+static inline u32 str_hash(const char *str)
+{
+       return jhash(str, strlen(str), 0);
+}
+
+static void rb_add(struct rb_root *tree, struct rb_node *node,
+                  int (*cmp)(struct rb_node *, const struct rb_node *))
+{
+       struct rb_node **link = &tree->rb_node;
+       struct rb_node *parent = NULL;
+
+       while (*link) {
+               parent = *link;
+               if (cmp(node, parent) < 0)
+                       link = &parent->rb_left;
+               else
+                       link = &parent->rb_right;
+       }
+
+       rb_link_node(node, parent, link);
+       rb_insert_color(node, tree);
+}
+
+static struct rb_node *rb_find_first(struct rb_root *tree, const void *key,
+                              int (*cmp)(const void *key, const struct rb_node *))
+{
+       struct rb_node *node = tree->rb_node;
+       struct rb_node *match = NULL;
+
+       while (node) {
+               int c = cmp(key, node);
+               if (c <= 0) {
+                       if (!c)
+                               match = node;
+                       node = node->rb_left;
+               } else if (c > 0) {
+                       node = node->rb_right;
+               }
+       }
+
+       return match;
+}
+
+static struct rb_node *rb_next_match(struct rb_node *node, const void *key,
+                                   int (*cmp)(const void *key, const struct rb_node *))
+{
+       node = rb_next(node);
+       if (node && cmp(key, node))
+               node = NULL;
+       return node;
+}
+
+#define rb_for_each(tree, node, key, cmp) \
+       for ((node) = rb_find_first((tree), (key), (cmp)); \
+            (node); (node) = rb_next_match((node), (key), (cmp)))
+
+static int symbol_to_offset(struct rb_node *a, const struct rb_node *b)
+{
+       struct symbol *sa = rb_entry(a, struct symbol, node);
+       struct symbol *sb = rb_entry(b, struct symbol, node);
+
+       if (sa->offset < sb->offset)
+               return -1;
+       if (sa->offset > sb->offset)
+               return 1;
+
+       if (sa->len < sb->len)
+               return -1;
+       if (sa->len > sb->len)
+               return 1;
+
+       sa->alias = sb;
+
+       return 0;
+}
+
+static int symbol_by_offset(const void *key, const struct rb_node *node)
+{
+       const struct symbol *s = rb_entry(node, struct symbol, node);
+       const unsigned long *o = key;
+
+       if (*o < s->offset)
+               return -1;
+       if (*o > s->offset + s->len)
+               return 1;
+
+       return 0;
+}
+
 struct section *find_section_by_name(struct elf *elf, const char *name)
 {
        struct section *sec;
 
-       list_for_each_entry(sec, &elf->sections, list)
+       hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
                if (!strcmp(sec->name, name))
                        return sec;
 
@@ -37,7 +127,7 @@ static struct section *find_section_by_index(struct elf *elf,
 {
        struct section *sec;
 
-       list_for_each_entry(sec, &elf->sections, list)
+       hash_for_each_possible(elf->section_hash, sec, hash, idx)
                if (sec->idx == idx)
                        return sec;
 
@@ -46,88 +136,116 @@ static struct section *find_section_by_index(struct elf *elf,
 
 static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
 {
-       struct section *sec;
        struct symbol *sym;
 
-       list_for_each_entry(sec, &elf->sections, list)
-               hash_for_each_possible(sec->symbol_hash, sym, hash, idx)
-                       if (sym->idx == idx)
-                               return sym;
+       hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
+               if (sym->idx == idx)
+                       return sym;
 
        return NULL;
 }
 
 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)
 {
-       struct symbol *sym;
+       struct rb_node *node;
 
-       list_for_each_entry(sym, &sec->symbol_list, list)
-               if (sym->type != STT_SECTION &&
-                   sym->offset == offset)
-                       return sym;
+       rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
+               struct symbol *s = rb_entry(node, struct symbol, node);
+
+               if (s->offset == offset && s->type != STT_SECTION)
+                       return s;
+       }
 
        return NULL;
 }
 
-struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
+struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)
 {
-       struct section *sec;
-       struct symbol *sym;
+       struct rb_node *node;
 
-       list_for_each_entry(sec, &elf->sections, list)
-               list_for_each_entry(sym, &sec->symbol_list, list)
-                       if (!strcmp(sym->name, name))
-                               return sym;
+       rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
+               struct symbol *s = rb_entry(node, struct symbol, node);
+
+               if (s->offset == offset && s->type == STT_FUNC)
+                       return s;
+       }
 
        return NULL;
 }
 
 struct symbol *find_symbol_containing(struct section *sec, unsigned long offset)
 {
-       struct symbol *sym;
+       struct rb_node *node;
 
-       list_for_each_entry(sym, &sec->symbol_list, list)
-               if (sym->type != STT_SECTION &&
-                   offset >= sym->offset && offset < sym->offset + sym->len)
-                       return sym;
+       rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
+               struct symbol *s = rb_entry(node, struct symbol, node);
+
+               if (s->type != STT_SECTION)
+                       return s;
+       }
 
        return NULL;
 }
 
-struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
-                                    unsigned int len)
+struct symbol *find_func_containing(struct section *sec, unsigned long offset)
 {
-       struct rela *rela;
-       unsigned long o;
+       struct rb_node *node;
 
-       if (!sec->rela)
-               return NULL;
+       rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
+               struct symbol *s = rb_entry(node, struct symbol, node);
 
-       for (o = offset; o < offset + len; o++)
-               hash_for_each_possible(sec->rela->rela_hash, rela, hash, o)
-                       if (rela->offset == o)
-                               return rela;
+               if (s->type == STT_FUNC)
+                       return s;
+       }
 
        return NULL;
 }
 
-struct rela *find_rela_by_dest(struct section *sec, unsigned long offset)
+struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
 {
-       return find_rela_by_dest_range(sec, offset, 1);
+       struct symbol *sym;
+
+       hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
+               if (!strcmp(sym->name, name))
+                       return sym;
+
+       return NULL;
 }
 
-struct symbol *find_containing_func(struct section *sec, unsigned long offset)
+struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
+                                    unsigned long offset, unsigned int len)
 {
-       struct symbol *func;
+       struct rela *rela, *r = NULL;
+       unsigned long o;
+
+       if (!sec->rela)
+               return NULL;
 
-       list_for_each_entry(func, &sec->symbol_list, list)
-               if (func->type == STT_FUNC && offset >= func->offset &&
-                   offset < func->offset + func->len)
-                       return func;
+       sec = sec->rela;
+
+       for_offset_range(o, offset, offset + len) {
+               hash_for_each_possible(elf->rela_hash, rela, hash,
+                                      sec_offset_hash(sec, o)) {
+                       if (rela->sec != sec)
+                               continue;
+
+                       if (rela->offset >= offset && rela->offset < offset + len) {
+                               if (!r || rela->offset < r->offset)
+                                       r = rela;
+                       }
+               }
+               if (r)
+                       return r;
+       }
 
        return NULL;
 }
 
+struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset)
+{
+       return find_rela_by_dest_range(elf, sec, offset, 1);
+}
+
 static int read_sections(struct elf *elf)
 {
        Elf_Scn *s = NULL;
@@ -155,10 +273,6 @@ static int read_sections(struct elf *elf)
 
                INIT_LIST_HEAD(&sec->symbol_list);
                INIT_LIST_HEAD(&sec->rela_list);
-               hash_init(sec->rela_hash);
-               hash_init(sec->symbol_hash);
-
-               list_add_tail(&sec->list, &elf->sections);
 
                s = elf_getscn(elf->elf, i);
                if (!s) {
@@ -193,8 +307,15 @@ static int read_sections(struct elf *elf)
                        }
                }
                sec->len = sec->sh.sh_size;
+
+               list_add_tail(&sec->list, &elf->sections);
+               hash_add(elf->section_hash, &sec->hash, sec->idx);
+               hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
        }
 
+       if (stats)
+               printf("nr_sections: %lu\n", (unsigned long)sections_nr);
+
        /* sanity check, one more call to elf_nextscn() should return NULL */
        if (elf_nextscn(elf->elf, s)) {
                WARN("section entry mismatch");
@@ -207,8 +328,9 @@ static int read_sections(struct elf *elf)
 static int read_symbols(struct elf *elf)
 {
        struct section *symtab, *sec;
-       struct symbol *sym, *pfunc, *alias;
-       struct list_head *entry, *tmp;
+       struct symbol *sym, *pfunc;
+       struct list_head *entry;
+       struct rb_node *pnode;
        int symbols_nr, i;
        char *coldstr;
 
@@ -227,7 +349,7 @@ static int read_symbols(struct elf *elf)
                        return -1;
                }
                memset(sym, 0, sizeof(*sym));
-               alias = sym;
+               sym->alias = sym;
 
                sym->idx = i;
 
@@ -265,33 +387,20 @@ static int read_symbols(struct elf *elf)
                sym->offset = sym->sym.st_value;
                sym->len = sym->sym.st_size;
 
-               /* sorted insert into a per-section list */
-               entry = &sym->sec->symbol_list;
-               list_for_each_prev(tmp, &sym->sec->symbol_list) {
-                       struct symbol *s;
-
-                       s = list_entry(tmp, struct symbol, list);
-
-                       if (sym->offset > s->offset) {
-                               entry = tmp;
-                               break;
-                       }
-
-                       if (sym->offset == s->offset) {
-                               if (sym->len && sym->len == s->len && alias == sym)
-                                       alias = s;
-
-                               if (sym->len >= s->len) {
-                                       entry = tmp;
-                                       break;
-                               }
-                       }
-               }
-               sym->alias = alias;
+               rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset);
+               pnode = rb_prev(&sym->node);
+               if (pnode)
+                       entry = &rb_entry(pnode, struct symbol, node)->list;
+               else
+                       entry = &sym->sec->symbol_list;
                list_add(&sym->list, entry);
-               hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx);
+               hash_add(elf->symbol_hash, &sym->hash, sym->idx);
+               hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
        }
 
+       if (stats)
+               printf("nr_symbols: %lu\n", (unsigned long)symbols_nr);
+
        /* Create parent/child links for any cold subfunctions */
        list_for_each_entry(sec, &elf->sections, list) {
                list_for_each_entry(sym, &sec->symbol_list, list) {
@@ -353,6 +462,7 @@ static int read_relas(struct elf *elf)
        struct rela *rela;
        int i;
        unsigned int symndx;
+       unsigned long nr_rela, max_rela = 0, tot_rela = 0;
 
        list_for_each_entry(sec, &elf->sections, list) {
                if (sec->sh.sh_type != SHT_RELA)
@@ -367,6 +477,7 @@ static int read_relas(struct elf *elf)
 
                sec->base->rela = sec;
 
+               nr_rela = 0;
                for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
                        rela = malloc(sizeof(*rela));
                        if (!rela) {
@@ -393,9 +504,16 @@ static int read_relas(struct elf *elf)
                        }
 
                        list_add_tail(&rela->list, &sec->rela_list);
-                       hash_add(sec->rela_hash, &rela->hash, rela->offset);
-
+                       hash_add(elf->rela_hash, &rela->hash, rela_hash(rela));
+                       nr_rela++;
                }
+               max_rela = max(max_rela, nr_rela);
+               tot_rela += nr_rela;
+       }
+
+       if (stats) {
+               printf("max_rela: %lu\n", max_rela);
+               printf("tot_rela: %lu\n", tot_rela);
        }
 
        return 0;
@@ -415,6 +533,11 @@ struct elf *elf_read(const char *name, int flags)
        }
        memset(elf, 0, sizeof(*elf));
 
+       hash_init(elf->symbol_hash);
+       hash_init(elf->symbol_name_hash);
+       hash_init(elf->section_hash);
+       hash_init(elf->section_name_hash);
+       hash_init(elf->rela_hash);
        INIT_LIST_HEAD(&elf->sections);
 
        elf->fd = open(name, flags);
@@ -475,10 +598,6 @@ struct section *elf_create_section(struct elf *elf, const char *name,
 
        INIT_LIST_HEAD(&sec->symbol_list);
        INIT_LIST_HEAD(&sec->rela_list);
-       hash_init(sec->rela_hash);
-       hash_init(sec->symbol_hash);
-
-       list_add_tail(&sec->list, &elf->sections);
 
        s = elf_newscn(elf->elf);
        if (!s) {
@@ -556,6 +675,10 @@ struct section *elf_create_section(struct elf *elf, const char *name,
        shstrtab->len += strlen(name) + 1;
        shstrtab->changed = true;
 
+       list_add_tail(&sec->list, &elf->sections);
+       hash_add(elf->section_hash, &sec->hash, sec->idx);
+       hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
+
        return sec;
 }
 
index 4415020..ebbb10c 100644 (file)
@@ -10,6 +10,8 @@
 #include <gelf.h>
 #include <linux/list.h>
 #include <linux/hashtable.h>
+#include <linux/rbtree.h>
+#include <linux/jhash.h>
 
 #ifdef LIBELF_USE_DEPRECATED
 # define elf_getshdrnum    elf_getshnum
 
 struct section {
        struct list_head list;
+       struct hlist_node hash;
+       struct hlist_node name_hash;
        GElf_Shdr sh;
+       struct rb_root symbol_tree;
        struct list_head symbol_list;
-       DECLARE_HASHTABLE(symbol_hash, 8);
        struct list_head rela_list;
-       DECLARE_HASHTABLE(rela_hash, 16);
        struct section *base, *rela;
        struct symbol *sym;
        Elf_Data *data;
@@ -41,7 +44,9 @@ struct section {
 
 struct symbol {
        struct list_head list;
+       struct rb_node node;
        struct hlist_node hash;
+       struct hlist_node name_hash;
        GElf_Sym sym;
        struct section *sec;
        char *name;
@@ -71,19 +76,51 @@ struct elf {
        int fd;
        char *name;
        struct list_head sections;
-       DECLARE_HASHTABLE(rela_hash, 16);
+       DECLARE_HASHTABLE(symbol_hash, 20);
+       DECLARE_HASHTABLE(symbol_name_hash, 20);
+       DECLARE_HASHTABLE(section_hash, 16);
+       DECLARE_HASHTABLE(section_name_hash, 16);
+       DECLARE_HASHTABLE(rela_hash, 20);
 };
 
+#define OFFSET_STRIDE_BITS     4
+#define OFFSET_STRIDE          (1UL << OFFSET_STRIDE_BITS)
+#define OFFSET_STRIDE_MASK     (~(OFFSET_STRIDE - 1))
+
+#define for_offset_range(_offset, _start, _end)                \
+       for (_offset = ((_start) & OFFSET_STRIDE_MASK); \
+            _offset <= ((_end) & OFFSET_STRIDE_MASK);  \
+            _offset += OFFSET_STRIDE)
+
+static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
+{
+       u32 ol, oh, idx = sec->idx;
+
+       offset &= OFFSET_STRIDE_MASK;
+
+       ol = offset;
+       oh = offset >> 32;
+
+       __jhash_mix(ol, oh, idx);
+
+       return ol;
+}
+
+static inline u32 rela_hash(struct rela *rela)
+{
+       return sec_offset_hash(rela->sec, rela->offset);
+}
 
 struct elf *elf_read(const char *name, int flags);
 struct section *find_section_by_name(struct elf *elf, const char *name);
+struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
 struct symbol *find_symbol_by_name(struct elf *elf, const char *name);
 struct symbol *find_symbol_containing(struct section *sec, unsigned long offset);
-struct rela *find_rela_by_dest(struct section *sec, unsigned long offset);
-struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
-                                    unsigned int len);
-struct symbol *find_containing_func(struct section *sec, unsigned long offset);
+struct rela *find_rela_by_dest(struct elf *elf, struct section *sec, unsigned long offset);
+struct rela *find_rela_by_dest_range(struct elf *elf, struct section *sec,
+                                    unsigned long offset, unsigned int len);
+struct symbol *find_func_containing(struct section *sec, unsigned long offset);
 struct section *elf_create_section(struct elf *elf, const char *name, size_t
                                   entsize, int nr);
 struct section *elf_create_rela_section(struct elf *elf, struct section *base);
index 27a4112..41e4a27 100644 (file)
@@ -81,7 +81,7 @@ int create_orc(struct objtool_file *file)
        return 0;
 }
 
-static int create_orc_entry(struct section *u_sec, struct section *ip_relasec,
+static int create_orc_entry(struct elf *elf, struct section *u_sec, struct section *ip_relasec,
                                unsigned int idx, struct section *insn_sec,
                                unsigned long insn_off, struct orc_entry *o)
 {
@@ -109,9 +109,10 @@ static int create_orc_entry(struct section *u_sec, struct section *ip_relasec,
        rela->addend = insn_off;
        rela->type = R_X86_64_PC32;
        rela->offset = idx * sizeof(int);
+       rela->sec = ip_relasec;
 
        list_add_tail(&rela->list, &ip_relasec->rela_list);
-       hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset);
+       hash_add(elf->rela_hash, &rela->hash, rela_hash(rela));
 
        return 0;
 }
@@ -182,7 +183,7 @@ int create_orc_sections(struct objtool_file *file)
                        if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc,
                                                 sizeof(struct orc_entry))) {
 
-                               if (create_orc_entry(u_sec, ip_relasec, idx,
+                               if (create_orc_entry(file->elf, u_sec, ip_relasec, idx,
                                                     insn->sec, insn->offset,
                                                     &insn->orc))
                                        return -1;
@@ -194,7 +195,7 @@ int create_orc_sections(struct objtool_file *file)
 
                /* section terminator */
                if (prev_insn) {
-                       if (create_orc_entry(u_sec, ip_relasec, idx,
+                       if (create_orc_entry(file->elf, u_sec, ip_relasec, idx,
                                             prev_insn->sec,
                                             prev_insn->offset + prev_insn->len,
                                             &empty))
index fdbaa61..e74e018 100644 (file)
@@ -118,7 +118,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
                }
        }
 
-       orig_rela = find_rela_by_dest(sec, offset + entry->orig);
+       orig_rela = find_rela_by_dest(elf, sec, offset + entry->orig);
        if (!orig_rela) {
                WARN_FUNC("can't find orig rela", sec, offset + entry->orig);
                return -1;
@@ -133,7 +133,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
        alt->orig_off = orig_rela->addend;
 
        if (!entry->group || alt->new_len) {
-               new_rela = find_rela_by_dest(sec, offset + entry->new);
+               new_rela = find_rela_by_dest(elf, sec, offset + entry->new);
                if (!new_rela) {
                        WARN_FUNC("can't find new rela",
                                  sec, offset + entry->new);
index cbb0a02..7799f60 100644 (file)
@@ -21,7 +21,7 @@ static inline char *offstr(struct section *sec, unsigned long offset)
        char *name, *str;
        unsigned long name_off;
 
-       func = find_containing_func(sec, offset);
+       func = find_func_containing(sec, offset);
        if (func) {
                name = func->name;
                name_off = offset - func->offset;
index adc5a7e..31824d5 100644 (file)
@@ -295,7 +295,10 @@ $(OUTPUT)%.1 $(OUTPUT)%.5 $(OUTPUT)%.7 : $(OUTPUT)%.xml
 $(OUTPUT)%.xml : %.txt
        $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
        $(ASCIIDOC) -b docbook -d manpage \
-               $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) -o $@+ $< && \
+               $(ASCIIDOC_EXTRA) -aperf_version=$(PERF_VERSION) \
+               -aperf_date=$(shell git log -1 --pretty="format:%cd" \
+                               --date=short $<) \
+               -o $@+ $< && \
        mv $@+ $@
 
 XSLT = docbook.xsl
index 2cf2d9e..fd9241a 100644 (file)
@@ -1,991 +1 @@
-Intel Processor Trace
-=====================
-
-Overview
-========
-
-Intel Processor Trace (Intel PT) is an extension of Intel Architecture that
-collects information about software execution such as control flow, execution
-modes and timings and formats it into highly compressed binary packets.
-Technical details are documented in the Intel 64 and IA-32 Architectures
-Software Developer Manuals, Chapter 36 Intel Processor Trace.
-
-Intel PT is first supported in Intel Core M and 5th generation Intel Core
-processors that are based on the Intel micro-architecture code name Broadwell.
-
-Trace data is collected by 'perf record' and stored within the perf.data file.
-See below for options to 'perf record'.
-
-Trace data must be 'decoded' which involves walking the object code and matching
-the trace data packets. For example a TNT packet only tells whether a
-conditional branch was taken or not taken, so to make use of that packet the
-decoder must know precisely which instruction was being executed.
-
-Decoding is done on-the-fly.  The decoder outputs samples in the same format as
-samples output by perf hardware events, for example as though the "instructions"
-or "branches" events had been recorded.  Presently 3 tools support this:
-'perf script', 'perf report' and 'perf inject'.  See below for more information
-on using those tools.
-
-The main distinguishing feature of Intel PT is that the decoder can determine
-the exact flow of software execution.  Intel PT can be used to understand why
-and how did software get to a certain point, or behave a certain way.  The
-software does not have to be recompiled, so Intel PT works with debug or release
-builds, however the executed images are needed - which makes use in JIT-compiled
-environments, or with self-modified code, a challenge.  Also symbols need to be
-provided to make sense of addresses.
-
-A limitation of Intel PT is that it produces huge amounts of trace data
-(hundreds of megabytes per second per core) which takes a long time to decode,
-for example two or three orders of magnitude longer than it took to collect.
-Another limitation is the performance impact of tracing, something that will
-vary depending on the use-case and architecture.
-
-
-Quickstart
-==========
-
-It is important to start small.  That is because it is easy to capture vastly
-more data than can possibly be processed.
-
-The simplest thing to do with Intel PT is userspace profiling of small programs.
-Data is captured with 'perf record' e.g. to trace 'ls' userspace-only:
-
-       perf record -e intel_pt//u ls
-
-And profiled with 'perf report' e.g.
-
-       perf report
-
-To also trace kernel space presents a problem, namely kernel self-modifying
-code.  A fairly good kernel image is available in /proc/kcore but to get an
-accurate image a copy of /proc/kcore needs to be made under the same conditions
-as the data capture.  A script perf-with-kcore can do that, but beware that the
-script makes use of 'sudo' to copy /proc/kcore.  If you have perf installed
-locally from the source tree you can do:
-
-       ~/libexec/perf-core/perf-with-kcore record pt_ls -e intel_pt// -- ls
-
-which will create a directory named 'pt_ls' and put the perf.data file and
-copies of /proc/kcore, /proc/kallsyms and /proc/modules into it.  Then to use
-'perf report' becomes:
-
-       ~/libexec/perf-core/perf-with-kcore report pt_ls
-
-Because samples are synthesized after-the-fact, the sampling period can be
-selected for reporting. e.g. sample every microsecond
-
-       ~/libexec/perf-core/perf-with-kcore report pt_ls --itrace=i1usge
-
-See the sections below for more information about the --itrace option.
-
-Beware the smaller the period, the more samples that are produced, and the
-longer it takes to process them.
-
-Also note that the coarseness of Intel PT timing information will start to
-distort the statistical value of the sampling as the sampling period becomes
-smaller.
-
-To represent software control flow, "branches" samples are produced.  By default
-a branch sample is synthesized for every single branch.  To get an idea what
-data is available you can use the 'perf script' tool with all itrace sampling
-options, which will list all the samples.
-
-       perf record -e intel_pt//u ls
-       perf script --itrace=ibxwpe
-
-An interesting field that is not printed by default is 'flags' which can be
-displayed as follows:
-
-       perf script --itrace=ibxwpe -F+flags
-
-The flags are "bcrosyiABEx" which stand for branch, call, return, conditional,
-system, asynchronous, interrupt, transaction abort, trace begin, trace end, and
-in transaction, respectively.
-
-Another interesting field that is not printed by default is 'ipc' which can be
-displayed as follows:
-
-       perf script --itrace=be -F+ipc
-
-There are two ways that instructions-per-cycle (IPC) can be calculated depending
-on the recording.
-
-If the 'cyc' config term (see config terms section below) was used, then IPC is
-calculated using the cycle count from CYC packets, otherwise MTC packets are
-used - refer to the 'mtc' config term.  When MTC is used, however, the values
-are less accurate because the timing is less accurate.
-
-Because Intel PT does not update the cycle count on every branch or instruction,
-the values will often be zero.  When there are values, they will be the number
-of instructions and number of cycles since the last update, and thus represent
-the average IPC since the last IPC for that event type.  Note IPC for "branches"
-events is calculated separately from IPC for "instructions" events.
-
-Also note that the IPC instruction count may or may not include the current
-instruction.  If the cycle count is associated with an asynchronous branch
-(e.g. page fault or interrupt), then the instruction count does not include the
-current instruction, otherwise it does.  That is consistent with whether or not
-that instruction has retired when the cycle count is updated.
-
-Another note, in the case of "branches" events, non-taken branches are not
-presently sampled, so IPC values for them do not appear e.g. a CYC packet with a
-TNT packet that starts with a non-taken branch.  To see every possible IPC
-value, "instructions" events can be used e.g. --itrace=i0ns
-
-While it is possible to create scripts to analyze the data, an alternative
-approach is available to export the data to a sqlite or postgresql database.
-Refer to script export-to-sqlite.py or export-to-postgresql.py for more details,
-and to script exported-sql-viewer.py for an example of using the database.
-
-There is also script intel-pt-events.py which provides an example of how to
-unpack the raw data for power events and PTWRITE.
-
-As mentioned above, it is easy to capture too much data.  One way to limit the
-data captured is to use 'snapshot' mode which is explained further below.
-Refer to 'new snapshot option' and 'Intel PT modes of operation' further below.
-
-Another problem that will be experienced is decoder errors.  They can be caused
-by inability to access the executed image, self-modified or JIT-ed code, or the
-inability to match side-band information (such as context switches and mmaps)
-which results in the decoder not knowing what code was executed.
-
-There is also the problem of perf not being able to copy the data fast enough,
-resulting in data lost because the buffer was full.  See 'Buffer handling' below
-for more details.
-
-
-perf record
-===========
-
-new event
----------
-
-The Intel PT kernel driver creates a new PMU for Intel PT.  PMU events are
-selected by providing the PMU name followed by the "config" separated by slashes.
-An enhancement has been made to allow default "config" e.g. the option
-
-       -e intel_pt//
-
-will use a default config value.  Currently that is the same as
-
-       -e intel_pt/tsc,noretcomp=0/
-
-which is the same as
-
-       -e intel_pt/tsc=1,noretcomp=0/
-
-Note there are now new config terms - see section 'config terms' further below.
-
-The config terms are listed in /sys/devices/intel_pt/format.  They are bit
-fields within the config member of the struct perf_event_attr which is
-passed to the kernel by the perf_event_open system call.  They correspond to bit
-fields in the IA32_RTIT_CTL MSR.  Here is a list of them and their definitions:
-
-       $ grep -H . /sys/bus/event_source/devices/intel_pt/format/*
-       /sys/bus/event_source/devices/intel_pt/format/cyc:config:1
-       /sys/bus/event_source/devices/intel_pt/format/cyc_thresh:config:19-22
-       /sys/bus/event_source/devices/intel_pt/format/mtc:config:9
-       /sys/bus/event_source/devices/intel_pt/format/mtc_period:config:14-17
-       /sys/bus/event_source/devices/intel_pt/format/noretcomp:config:11
-       /sys/bus/event_source/devices/intel_pt/format/psb_period:config:24-27
-       /sys/bus/event_source/devices/intel_pt/format/tsc:config:10
-
-Note that the default config must be overridden for each term i.e.
-
-       -e intel_pt/noretcomp=0/
-
-is the same as:
-
-       -e intel_pt/tsc=1,noretcomp=0/
-
-So, to disable TSC packets use:
-
-       -e intel_pt/tsc=0/
-
-It is also possible to specify the config value explicitly:
-
-       -e intel_pt/config=0x400/
-
-Note that, as with all events, the event is suffixed with event modifiers:
-
-       u       userspace
-       k       kernel
-       h       hypervisor
-       G       guest
-       H       host
-       p       precise ip
-
-'h', 'G' and 'H' are for virtualization which is not supported by Intel PT.
-'p' is also not relevant to Intel PT.  So only options 'u' and 'k' are
-meaningful for Intel PT.
-
-perf_event_attr is displayed if the -vv option is used e.g.
-
-       ------------------------------------------------------------
-       perf_event_attr:
-       type                             6
-       size                             112
-       config                           0x400
-       { sample_period, sample_freq }   1
-       sample_type                      IP|TID|TIME|CPU|IDENTIFIER
-       read_format                      ID
-       disabled                         1
-       inherit                          1
-       exclude_kernel                   1
-       exclude_hv                       1
-       enable_on_exec                   1
-       sample_id_all                    1
-       ------------------------------------------------------------
-       sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
-       ------------------------------------------------------------
-
-
-config terms
-------------
-
-The June 2015 version of Intel 64 and IA-32 Architectures Software Developer
-Manuals, Chapter 36 Intel Processor Trace, defined new Intel PT features.
-Some of the features are reflect in new config terms.  All the config terms are
-described below.
-
-tsc            Always supported.  Produces TSC timestamp packets to provide
-               timing information.  In some cases it is possible to decode
-               without timing information, for example a per-thread context
-               that does not overlap executable memory maps.
-
-               The default config selects tsc (i.e. tsc=1).
-
-noretcomp      Always supported.  Disables "return compression" so a TIP packet
-               is produced when a function returns.  Causes more packets to be
-               produced but might make decoding more reliable.
-
-               The default config does not select noretcomp (i.e. noretcomp=0).
-
-psb_period     Allows the frequency of PSB packets to be specified.
-
-               The PSB packet is a synchronization packet that provides a
-               starting point for decoding or recovery from errors.
-
-               Support for psb_period is indicated by:
-
-                       /sys/bus/event_source/devices/intel_pt/caps/psb_cyc
-
-               which contains "1" if the feature is supported and "0"
-               otherwise.
-
-               Valid values are given by:
-
-                       /sys/bus/event_source/devices/intel_pt/caps/psb_periods
-
-               which contains a hexadecimal value, the bits of which represent
-               valid values e.g. bit 2 set means value 2 is valid.
-
-               The psb_period value is converted to the approximate number of
-               trace bytes between PSB packets as:
-
-                       2 ^ (value + 11)
-
-               e.g. value 3 means 16KiB bytes between PSBs
-
-               If an invalid value is entered, the error message
-               will give a list of valid values e.g.
-
-                       $ perf record -e intel_pt/psb_period=15/u uname
-                       Invalid psb_period for intel_pt. Valid values are: 0-5
-
-               If MTC packets are selected, the default config selects a value
-               of 3 (i.e. psb_period=3) or the nearest lower value that is
-               supported (0 is always supported).  Otherwise the default is 0.
-
-               If decoding is expected to be reliable and the buffer is large
-               then a large PSB period can be used.
-
-               Because a TSC packet is produced with PSB, the PSB period can
-               also affect the granularity to timing information in the absence
-               of MTC or CYC.
-
-mtc            Produces MTC timing packets.
-
-               MTC packets provide finer grain timestamp information than TSC
-               packets.  MTC packets record time using the hardware crystal
-               clock (CTC) which is related to TSC packets using a TMA packet.
-
-               Support for this feature is indicated by:
-
-                       /sys/bus/event_source/devices/intel_pt/caps/mtc
-
-               which contains "1" if the feature is supported and
-               "0" otherwise.
-
-               The frequency of MTC packets can also be specified - see
-               mtc_period below.
-
-mtc_period     Specifies how frequently MTC packets are produced - see mtc
-               above for how to determine if MTC packets are supported.
-
-               Valid values are given by:
-
-                       /sys/bus/event_source/devices/intel_pt/caps/mtc_periods
-
-               which contains a hexadecimal value, the bits of which represent
-               valid values e.g. bit 2 set means value 2 is valid.
-
-               The mtc_period value is converted to the MTC frequency as:
-
-                       CTC-frequency / (2 ^ value)
-
-               e.g. value 3 means one eighth of CTC-frequency
-
-               Where CTC is the hardware crystal clock, the frequency of which
-               can be related to TSC via values provided in cpuid leaf 0x15.
-
-               If an invalid value is entered, the error message
-               will give a list of valid values e.g.
-
-                       $ perf record -e intel_pt/mtc_period=15/u uname
-                       Invalid mtc_period for intel_pt. Valid values are: 0,3,6,9
-
-               The default value is 3 or the nearest lower value
-               that is supported (0 is always supported).
-
-cyc            Produces CYC timing packets.
-
-               CYC packets provide even finer grain timestamp information than
-               MTC and TSC packets.  A CYC packet contains the number of CPU
-               cycles since the last CYC packet. Unlike MTC and TSC packets,
-               CYC packets are only sent when another packet is also sent.
-
-               Support for this feature is indicated by:
-
-                       /sys/bus/event_source/devices/intel_pt/caps/psb_cyc
-
-               which contains "1" if the feature is supported and
-               "0" otherwise.
-
-               The number of CYC packets produced can be reduced by specifying
-               a threshold - see cyc_thresh below.
-
-cyc_thresh     Specifies how frequently CYC packets are produced - see cyc
-               above for how to determine if CYC packets are supported.
-
-               Valid cyc_thresh values are given by:
-
-                       /sys/bus/event_source/devices/intel_pt/caps/cycle_thresholds
-
-               which contains a hexadecimal value, the bits of which represent
-               valid values e.g. bit 2 set means value 2 is valid.
-
-               The cyc_thresh value represents the minimum number of CPU cycles
-               that must have passed before a CYC packet can be sent.  The
-               number of CPU cycles is:
-
-                       2 ^ (value - 1)
-
-               e.g. value 4 means 8 CPU cycles must pass before a CYC packet
-               can be sent.  Note a CYC packet is still only sent when another
-               packet is sent, not at, e.g. every 8 CPU cycles.
-
-               If an invalid value is entered, the error message
-               will give a list of valid values e.g.
-
-                       $ perf record -e intel_pt/cyc,cyc_thresh=15/u uname
-                       Invalid cyc_thresh for intel_pt. Valid values are: 0-12
-
-               CYC packets are not requested by default.
-
-pt             Specifies pass-through which enables the 'branch' config term.
-
-               The default config selects 'pt' if it is available, so a user will
-               never need to specify this term.
-
-branch         Enable branch tracing.  Branch tracing is enabled by default so to
-               disable branch tracing use 'branch=0'.
-
-               The default config selects 'branch' if it is available.
-
-ptw            Enable PTWRITE packets which are produced when a ptwrite instruction
-               is executed.
-
-               Support for this feature is indicated by:
-
-                       /sys/bus/event_source/devices/intel_pt/caps/ptwrite
-
-               which contains "1" if the feature is supported and
-               "0" otherwise.
-
-fup_on_ptw     Enable a FUP packet to follow the PTWRITE packet.  The FUP packet
-               provides the address of the ptwrite instruction.  In the absence of
-               fup_on_ptw, the decoder will use the address of the previous branch
-               if branch tracing is enabled, otherwise the address will be zero.
-               Note that fup_on_ptw will work even when branch tracing is disabled.
-
-pwr_evt                Enable power events.  The power events provide information about
-               changes to the CPU C-state.
-
-               Support for this feature is indicated by:
-
-                       /sys/bus/event_source/devices/intel_pt/caps/power_event_trace
-
-               which contains "1" if the feature is supported and
-               "0" otherwise.
-
-
-AUX area sampling option
-------------------------
-
-To select Intel PT "sampling" the AUX area sampling option can be used:
-
-       --aux-sample
-
-Optionally it can be followed by the sample size in bytes e.g.
-
-       --aux-sample=8192
-
-In addition, the Intel PT event to sample must be defined e.g.
-
-       -e intel_pt//u
-
-Samples on other events will be created containing Intel PT data e.g. the
-following will create Intel PT samples on the branch-misses event, note the
-events must be grouped using {}:
-
-       perf record --aux-sample -e '{intel_pt//u,branch-misses:u}'
-
-An alternative to '--aux-sample' is to add the config term 'aux-sample-size' to
-events.  In this case, the grouping is implied e.g.
-
-       perf record -e intel_pt//u -e branch-misses/aux-sample-size=8192/u
-
-is the same as:
-
-       perf record -e '{intel_pt//u,branch-misses/aux-sample-size=8192/u}'
-
-but allows for also using an address filter e.g.:
-
-       perf record -e intel_pt//u --filter 'filter * @/bin/ls' -e branch-misses/aux-sample-size=8192/u -- ls
-
-It is important to select a sample size that is big enough to contain at least
-one PSB packet.  If not a warning will be displayed:
-
-       Intel PT sample size (%zu) may be too small for PSB period (%zu)
-
-The calculation used for that is: if sample_size <= psb_period + 256 display the
-warning.  When sampling is used, psb_period defaults to 0 (2KiB).
-
-The default sample size is 4KiB.
-
-The sample size is passed in aux_sample_size in struct perf_event_attr.  The
-sample size is limited by the maximum event size which is 64KiB.  It is
-difficult to know how big the event might be without the trace sample attached,
-but the tool validates that the sample size is not greater than 60KiB.
-
-
-new snapshot option
--------------------
-
-The difference between full trace and snapshot from the kernel's perspective is
-that in full trace we don't overwrite trace data that the user hasn't collected
-yet (and indicated that by advancing aux_tail), whereas in snapshot mode we let
-the trace run and overwrite older data in the buffer so that whenever something
-interesting happens, we can stop it and grab a snapshot of what was going on
-around that interesting moment.
-
-To select snapshot mode a new option has been added:
-
-       -S
-
-Optionally it can be followed by the snapshot size e.g.
-
-       -S0x100000
-
-The default snapshot size is the auxtrace mmap size.  If neither auxtrace mmap size
-nor snapshot size is specified, then the default is 4MiB for privileged users
-(or if /proc/sys/kernel/perf_event_paranoid < 0), 128KiB for unprivileged users.
-If an unprivileged user does not specify mmap pages, the mmap pages will be
-reduced as described in the 'new auxtrace mmap size option' section below.
-
-The snapshot size is displayed if the option -vv is used e.g.
-
-       Intel PT snapshot size: %zu
-
-
-new auxtrace mmap size option
----------------------------
-
-Intel PT buffer size is specified by an addition to the -m option e.g.
-
-       -m,16
-
-selects a buffer size of 16 pages i.e. 64KiB.
-
-Note that the existing functionality of -m is unchanged.  The auxtrace mmap size
-is specified by the optional addition of a comma and the value.
-
-The default auxtrace mmap size for Intel PT is 4MiB/page_size for privileged users
-(or if /proc/sys/kernel/perf_event_paranoid < 0), 128KiB for unprivileged users.
-If an unprivileged user does not specify mmap pages, the mmap pages will be
-reduced from the default 512KiB/page_size to 256KiB/page_size, otherwise the
-user is likely to get an error as they exceed their mlock limit (Max locked
-memory as shown in /proc/self/limits).  Note that perf does not count the first
-512KiB (actually /proc/sys/kernel/perf_event_mlock_kb minus 1 page) per cpu
-against the mlock limit so an unprivileged user is allowed 512KiB per cpu plus
-their mlock limit (which defaults to 64KiB but is not multiplied by the number
-of cpus).
-
-In full-trace mode, powers of two are allowed for buffer size, with a minimum
-size of 2 pages.  In snapshot mode or sampling mode, it is the same but the
-minimum size is 1 page.
-
-The mmap size and auxtrace mmap size are displayed if the -vv option is used e.g.
-
-       mmap length 528384
-       auxtrace mmap length 4198400
-
-
-Intel PT modes of operation
----------------------------
-
-Intel PT can be used in 2 modes:
-       full-trace mode
-       sample mode
-       snapshot mode
-
-Full-trace mode traces continuously e.g.
-
-       perf record -e intel_pt//u uname
-
-Sample mode attaches a Intel PT sample to other events e.g.
-
-       perf record --aux-sample -e intel_pt//u -e branch-misses:u
-
-Snapshot mode captures the available data when a signal is sent e.g.
-
-       perf record -v -e intel_pt//u -S ./loopy 1000000000 &
-       [1] 11435
-       kill -USR2 11435
-       Recording AUX area tracing snapshot
-
-Note that the signal sent is SIGUSR2.
-Note that "Recording AUX area tracing snapshot" is displayed because the -v
-option is used.
-
-The 2 modes cannot be used together.
-
-
-Buffer handling
----------------
-
-There may be buffer limitations (i.e. single ToPa entry) which means that actual
-buffer sizes are limited to powers of 2 up to 4MiB (MAX_ORDER).  In order to
-provide other sizes, and in particular an arbitrarily large size, multiple
-buffers are logically concatenated.  However an interrupt must be used to switch
-between buffers.  That has two potential problems:
-       a) the interrupt may not be handled in time so that the current buffer
-       becomes full and some trace data is lost.
-       b) the interrupts may slow the system and affect the performance
-       results.
-
-If trace data is lost, the driver sets 'truncated' in the PERF_RECORD_AUX event
-which the tools report as an error.
-
-In full-trace mode, the driver waits for data to be copied out before allowing
-the (logical) buffer to wrap-around.  If data is not copied out quickly enough,
-again 'truncated' is set in the PERF_RECORD_AUX event.  If the driver has to
-wait, the intel_pt event gets disabled.  Because it is difficult to know when
-that happens, perf tools always re-enable the intel_pt event after copying out
-data.
-
-
-Intel PT and build ids
-----------------------
-
-By default "perf record" post-processes the event stream to find all build ids
-for executables for all addresses sampled.  Deliberately, Intel PT is not
-decoded for that purpose (it would take too long).  Instead the build ids for
-all executables encountered (due to mmap, comm or task events) are included
-in the perf.data file.
-
-To see buildids included in the perf.data file use the command:
-
-       perf buildid-list
-
-If the perf.data file contains Intel PT data, that is the same as:
-
-       perf buildid-list --with-hits
-
-
-Snapshot mode and event disabling
----------------------------------
-
-In order to make a snapshot, the intel_pt event is disabled using an IOCTL,
-namely PERF_EVENT_IOC_DISABLE.  However doing that can also disable the
-collection of side-band information.  In order to prevent that,  a dummy
-software event has been introduced that permits tracking events (like mmaps) to
-continue to be recorded while intel_pt is disabled.  That is important to ensure
-there is complete side-band information to allow the decoding of subsequent
-snapshots.
-
-A test has been created for that.  To find the test:
-
-       perf test list
-       ...
-       23: Test using a dummy software event to keep tracking
-
-To run the test:
-
-       perf test 23
-       23: Test using a dummy software event to keep tracking     : Ok
-
-
-perf record modes (nothing new here)
-------------------------------------
-
-perf record essentially operates in one of three modes:
-       per thread
-       per cpu
-       workload only
-
-"per thread" mode is selected by -t or by --per-thread (with -p or -u or just a
-workload).
-"per cpu" is selected by -C or -a.
-"workload only" mode is selected by not using the other options but providing a
-command to run (i.e. the workload).
-
-In per-thread mode an exact list of threads is traced.  There is no inheritance.
-Each thread has its own event buffer.
-
-In per-cpu mode all processes (or processes from the selected cgroup i.e. -G
-option, or processes selected with -p or -u) are traced.  Each cpu has its own
-buffer. Inheritance is allowed.
-
-In workload-only mode, the workload is traced but with per-cpu buffers.
-Inheritance is allowed.  Note that you can now trace a workload in per-thread
-mode by using the --per-thread option.
-
-
-Privileged vs non-privileged users
-----------------------------------
-
-Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users
-have memory limits imposed upon them.  That affects what buffer sizes they can
-have as outlined above.
-
-The v4.2 kernel introduced support for a context switch metadata event,
-PERF_RECORD_SWITCH, which allows unprivileged users to see when their processes
-are scheduled out and in, just not by whom, which is left for the
-PERF_RECORD_SWITCH_CPU_WIDE, that is only accessible in system wide context,
-which in turn requires CAP_SYS_ADMIN.
-
-Please see the 45ac1403f564 ("perf: Add PERF_RECORD_SWITCH to indicate context
-switches") commit, that introduces these metadata events for further info.
-
-When working with kernels < v4.2, the following considerations must be taken,
-as the sched:sched_switch tracepoints will be used to receive such information:
-
-Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users are
-not permitted to use tracepoints which means there is insufficient side-band
-information to decode Intel PT in per-cpu mode, and potentially workload-only
-mode too if the workload creates new processes.
-
-Note also, that to use tracepoints, read-access to debugfs is required.  So if
-debugfs is not mounted or the user does not have read-access, it will again not
-be possible to decode Intel PT in per-cpu mode.
-
-
-sched_switch tracepoint
------------------------
-
-The sched_switch tracepoint is used to provide side-band data for Intel PT
-decoding in kernels where the PERF_RECORD_SWITCH metadata event isn't
-available.
-
-The sched_switch events are automatically added. e.g. the second event shown
-below:
-
-       $ perf record -vv -e intel_pt//u uname
-       ------------------------------------------------------------
-       perf_event_attr:
-       type                             6
-       size                             112
-       config                           0x400
-       { sample_period, sample_freq }   1
-       sample_type                      IP|TID|TIME|CPU|IDENTIFIER
-       read_format                      ID
-       disabled                         1
-       inherit                          1
-       exclude_kernel                   1
-       exclude_hv                       1
-       enable_on_exec                   1
-       sample_id_all                    1
-       ------------------------------------------------------------
-       sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
-       ------------------------------------------------------------
-       perf_event_attr:
-       type                             2
-       size                             112
-       config                           0x108
-       { sample_period, sample_freq }   1
-       sample_type                      IP|TID|TIME|CPU|PERIOD|RAW|IDENTIFIER
-       read_format                      ID
-       inherit                          1
-       sample_id_all                    1
-       exclude_guest                    1
-       ------------------------------------------------------------
-       sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8
-       sys_perf_event_open: pid -1  cpu 1  group_fd -1  flags 0x8
-       sys_perf_event_open: pid -1  cpu 2  group_fd -1  flags 0x8
-       sys_perf_event_open: pid -1  cpu 3  group_fd -1  flags 0x8
-       ------------------------------------------------------------
-       perf_event_attr:
-       type                             1
-       size                             112
-       config                           0x9
-       { sample_period, sample_freq }   1
-       sample_type                      IP|TID|TIME|IDENTIFIER
-       read_format                      ID
-       disabled                         1
-       inherit                          1
-       exclude_kernel                   1
-       exclude_hv                       1
-       mmap                             1
-       comm                             1
-       enable_on_exec                   1
-       task                             1
-       sample_id_all                    1
-       mmap2                            1
-       comm_exec                        1
-       ------------------------------------------------------------
-       sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
-       sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
-       mmap size 528384B
-       AUX area mmap length 4194304
-       perf event ring buffer mmapped per cpu
-       Synthesizing auxtrace information
-       Linux
-       [ perf record: Woken up 1 times to write data ]
-       [ perf record: Captured and wrote 0.042 MB perf.data ]
-
-Note, the sched_switch event is only added if the user is permitted to use it
-and only in per-cpu mode.
-
-Note also, the sched_switch event is only added if TSC packets are requested.
-That is because, in the absence of timing information, the sched_switch events
-cannot be matched against the Intel PT trace.
-
-
-perf script
-===========
-
-By default, perf script will decode trace data found in the perf.data file.
-This can be further controlled by new option --itrace.
-
-
-New --itrace option
--------------------
-
-Having no option is the same as
-
-       --itrace
-
-which, in turn, is the same as
-
-       --itrace=cepwx
-
-The letters are:
-
-       i       synthesize "instructions" events
-       b       synthesize "branches" events
-       x       synthesize "transactions" events
-       w       synthesize "ptwrite" events
-       p       synthesize "power" events
-       c       synthesize branches events (calls only)
-       r       synthesize branches events (returns only)
-       e       synthesize tracing error events
-       d       create a debug log
-       g       synthesize a call chain (use with i or x)
-       l       synthesize last branch entries (use with i or x)
-       s       skip initial number of events
-
-"Instructions" events look like they were recorded by "perf record -e
-instructions".
-
-"Branches" events look like they were recorded by "perf record -e branches". "c"
-and "r" can be combined to get calls and returns.
-
-"Transactions" events correspond to the start or end of transactions. The
-'flags' field can be used in perf script to determine whether the event is a
-tranasaction start, commit or abort.
-
-Note that "instructions", "branches" and "transactions" events depend on code
-flow packets which can be disabled by using the config term "branch=0".  Refer
-to the config terms section above.
-
-"ptwrite" events record the payload of the ptwrite instruction and whether
-"fup_on_ptw" was used.  "ptwrite" events depend on PTWRITE packets which are
-recorded only if the "ptw" config term was used.  Refer to the config terms
-section above.  perf script "synth" field displays "ptwrite" information like
-this: "ip: 0 payload: 0x123456789abcdef0"  where "ip" is 1 if "fup_on_ptw" was
-used.
-
-"Power" events correspond to power event packets and CBR (core-to-bus ratio)
-packets.  While CBR packets are always recorded when tracing is enabled, power
-event packets are recorded only if the "pwr_evt" config term was used.  Refer to
-the config terms section above.  The power events record information about
-C-state changes, whereas CBR is indicative of CPU frequency.  perf script
-"event,synth" fields display information like this:
-       cbr:  cbr: 22 freq: 2189 MHz (200%)
-       mwait:  hints: 0x60 extensions: 0x1
-       pwre:  hw: 0 cstate: 2 sub-cstate: 0
-       exstop:  ip: 1
-       pwrx:  deepest cstate: 2 last cstate: 2 wake reason: 0x4
-Where:
-       "cbr" includes the frequency and the percentage of maximum non-turbo
-       "mwait" shows mwait hints and extensions
-       "pwre" shows C-state transitions (to a C-state deeper than C0) and
-       whether initiated by hardware
-       "exstop" indicates execution stopped and whether the IP was recorded
-       exactly,
-       "pwrx" indicates return to C0
-For more details refer to the Intel 64 and IA-32 Architectures Software
-Developer Manuals.
-
-Error events show where the decoder lost the trace.  Error events
-are quite important.  Users must know if what they are seeing is a complete
-picture or not.
-
-The "d" option will cause the creation of a file "intel_pt.log" containing all
-decoded packets and instructions.  Note that this option slows down the decoder
-and that the resulting file may be very large.
-
-In addition, the period of the "instructions" event can be specified. e.g.
-
-       --itrace=i10us
-
-sets the period to 10us i.e. one  instruction sample is synthesized for each 10
-microseconds of trace.  Alternatives to "us" are "ms" (milliseconds),
-"ns" (nanoseconds), "t" (TSC ticks) or "i" (instructions).
-
-"ms", "us" and "ns" are converted to TSC ticks.
-
-The timing information included with Intel PT does not give the time of every
-instruction.  Consequently, for the purpose of sampling, the decoder estimates
-the time since the last timing packet based on 1 tick per instruction.  The time
-on the sample is *not* adjusted and reflects the last known value of TSC.
-
-For Intel PT, the default period is 100us.
-
-Setting it to a zero period means "as often as possible".
-
-In the case of Intel PT that is the same as a period of 1 and a unit of
-'instructions' (i.e. --itrace=i1i).
-
-Also the call chain size (default 16, max. 1024) for instructions or
-transactions events can be specified. e.g.
-
-       --itrace=ig32
-       --itrace=xg32
-
-Also the number of last branch entries (default 64, max. 1024) for instructions or
-transactions events can be specified. e.g.
-
-       --itrace=il10
-       --itrace=xl10
-
-Note that last branch entries are cleared for each sample, so there is no overlap
-from one sample to the next.
-
-To disable trace decoding entirely, use the option --no-itrace.
-
-It is also possible to skip events generated (instructions, branches, transactions)
-at the beginning. This is useful to ignore initialization code.
-
-       --itrace=i0nss1000000
-
-skips the first million instructions.
-
-dump option
------------
-
-perf script has an option (-D) to "dump" the events i.e. display the binary
-data.
-
-When -D is used, Intel PT packets are displayed.  The packet decoder does not
-pay attention to PSB packets, but just decodes the bytes - so the packets seen
-by the actual decoder may not be identical in places where the data is corrupt.
-One example of that would be when the buffer-switching interrupt has been too
-slow, and the buffer has been filled completely.  In that case, the last packet
-in the buffer might be truncated and immediately followed by a PSB as the trace
-continues in the next buffer.
-
-To disable the display of Intel PT packets, combine the -D option with
---no-itrace.
-
-
-perf report
-===========
-
-By default, perf report will decode trace data found in the perf.data file.
-This can be further controlled by new option --itrace exactly the same as
-perf script, with the exception that the default is --itrace=igxe.
-
-
-perf inject
-===========
-
-perf inject also accepts the --itrace option in which case tracing data is
-removed and replaced with the synthesized events. e.g.
-
-       perf inject --itrace -i perf.data -o perf.data.new
-
-Below is an example of using Intel PT with autofdo.  It requires autofdo
-(https://github.com/google/autofdo) and gcc version 5.  The bubble
-sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial)
-amended to take the number of elements as a parameter.
-
-       $ gcc-5 -O3 sort.c -o sort_optimized
-       $ ./sort_optimized 30000
-       Bubble sorting array of 30000 elements
-       2254 ms
-
-       $ cat ~/.perfconfig
-       [intel-pt]
-               mispred-all = on
-
-       $ perf record -e intel_pt//u ./sort 3000
-       Bubble sorting array of 3000 elements
-       58 ms
-       [ perf record: Woken up 2 times to write data ]
-       [ perf record: Captured and wrote 3.939 MB perf.data ]
-       $ perf inject -i perf.data -o inj --itrace=i100usle --strip
-       $ ./create_gcov --binary=./sort --profile=inj --gcov=sort.gcov -gcov_version=1
-       $ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo
-       $ ./sort_autofdo 30000
-       Bubble sorting array of 30000 elements
-       2155 ms
-
-Note there is currently no advantage to using Intel PT instead of LBR, but
-that may change in the future if greater use is made of the data.
-
-
-PEBS via Intel PT
-=================
-
-Some hardware has the feature to redirect PEBS records to the Intel PT trace.
-Recording is selected by using the aux-output config term e.g.
-
-       perf record -c 10000 -e '{intel_pt/branch=0/,cycles/aux-output/ppp}' uname
-
-Note that currently, software only supports redirecting at most one PEBS event.
-
-To display PEBS events from the Intel PT trace, use the itrace 'o' option e.g.
-
-       perf script --itrace=oe
+Documentation for support for Intel Processor Trace within perf tools' has moved to file perf-intel-pt.txt
index c4dd23c..8ead555 100644 (file)
@@ -239,7 +239,6 @@ buildid.*::
                set buildid.dir to /dev/null. The default is $HOME/.debug
 
 annotate.*::
-       These options work only for TUI.
        These are in control of addresses, jump function, source code
        in lines of assembly code from a specific program.
 
@@ -269,6 +268,8 @@ annotate.*::
                │        mov    (%rdi),%rdx
                │              return n;
 
+               This option works with tui, stdio2 browsers.
+
         annotate.use_offset::
                Basing on a first address of a loaded function, offset can be used.
                Instead of using original addresses of assembly code,
@@ -287,6 +288,8 @@ annotate.*::
 
                             368:│  mov    0x8(%r14),%rdi
 
+               This option works with tui, stdio2 browsers.
+
        annotate.jump_arrows::
                There can be jump instruction among assembly code.
                Depending on a boolean value of jump_arrows,
@@ -306,6 +309,8 @@ annotate.*::
                │1330:   mov    %r15,%r10
                │1333:   cmp    %r15,%r14
 
+               This option works with tui browser.
+
         annotate.show_linenr::
                When showing source code if this option is 'true',
                line numbers are printed as below.
@@ -325,6 +330,8 @@ annotate.*::
                │                     array++;
                │             }
 
+               This option works with tui, stdio2 browsers.
+
         annotate.show_nr_jumps::
                Let's see a part of assembly code.
 
@@ -335,6 +342,8 @@ annotate.*::
 
                │1 1382:   movb   $0x1,-0x270(%rbp)
 
+               This option works with tui, stdio2 browsers.
+
         annotate.show_total_period::
                To compare two records on an instruction base, with this option
                provided, display total number of samples that belong to a line
@@ -348,11 +357,30 @@ annotate.*::
 
                99.93 │      mov    %eax,%eax
 
+               This option works with tui, stdio2, stdio browsers.
+
+       annotate.show_nr_samples::
+               By default perf annotate shows percentage of samples. This option
+               can be used to print absolute number of samples. Ex, when set as
+               false:
+
+               Percent│
+                74.03 │      mov    %fs:0x28,%rax
+
+               When set as true:
+
+               Samples│
+                    6 │      mov    %fs:0x28,%rax
+
+               This option works with tui, stdio2, stdio browsers.
+
        annotate.offset_level::
                Default is '1', meaning just jump targets will have offsets show right beside
                the instruction. When set to '2' 'call' instructions will also have its offsets
                shown, 3 or higher will show offsets for all instructions.
 
+               This option works with tui, stdio2 browsers.
+
 hist.*::
        hist.percentage::
                This option control the way to calculate overhead of filtered entries -
@@ -490,6 +518,12 @@ top.*::
                column by default.
                The default is 'true'.
 
+       top.call-graph::
+               This is identical to 'call-graph.record-mode', except it is
+               applicable only for 'top' subcommand. This option ONLY setup
+               the unwind method. To enable 'perf top' to actually use it,
+               the command line option -g must be specified.
+
 man.*::
        man.viewer::
                This option can assign a tool to view manual pages when 'help'
@@ -517,6 +551,16 @@ record.*::
                But if this option is 'no-cache', it will not update the build-id cache.
                'skip' skips post-processing and does not update the cache.
 
+       record.call-graph::
+               This is identical to 'call-graph.record-mode', except it is
+               applicable only for 'record' subcommand. This option ONLY setup
+               the unwind method. To enable 'perf record' to actually use it,
+               the command line option -g must be specified.
+
+       record.aio::
+               Use 'n' control blocks in asynchronous (Posix AIO) trace writing
+               mode ('n' default: 1, max: 4).
+
 diff.*::
        diff.order::
                This option sets the number of columns to sort the result.
@@ -566,6 +610,11 @@ trace.*::
                "libbeauty", the default, to use the same argument beautifiers used in the
                strace-like sys_enter+sys_exit lines.
 
+ftrace.*::
+       ftrace.tracer::
+               Can be used to select the default tracer. Possible values are
+               'function' and 'function_graph'.
+
 llvm.*::
        llvm.clang-path::
                Path to clang. If omit, search it from $PATH.
@@ -610,6 +659,29 @@ scripts.*::
        The script gets the same options passed as a full perf script,
        in particular -i perfdata file, --cpu, --tid
 
+convert.*::
+
+       convert.queue-size::
+               Limit the size of ordered_events queue, so we could control
+               allocation size of perf data files without proper finished
+               round events.
+
+intel-pt.*::
+
+       intel-pt.cache-divisor::
+
+       intel-pt.mispred-all::
+               If set, Intel PT decoder will set the mispred flag on all
+               branches.
+
+auxtrace.*::
+
+       auxtrace.dumpdir::
+               s390 only. The directory to save the auxiliary trace buffer
+               can be changed using this option. Ex, auxtrace.dumpdir=/tmp.
+               If the directory does not exist or has the wrong file type,
+               the current directory is used.
+
 SEE ALSO
 --------
 linkperf:perf[1]
index a64d658..70969ea 100644 (file)
@@ -66,4 +66,5 @@ include::itrace.txt[]
 
 SEE ALSO
 --------
-linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
+linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1],
+linkperf:perf-intel-pt[1]
diff --git a/tools/perf/Documentation/perf-intel-pt.txt b/tools/perf/Documentation/perf-intel-pt.txt
new file mode 100644 (file)
index 0000000..456fdcb
--- /dev/null
@@ -0,0 +1,1007 @@
+perf-intel-pt(1)
+================
+
+NAME
+----
+perf-intel-pt - Support for Intel Processor Trace within perf tools
+
+SYNOPSIS
+--------
+[verse]
+'perf record' -e intel_pt//
+
+DESCRIPTION
+-----------
+
+Intel Processor Trace (Intel PT) is an extension of Intel Architecture that
+collects information about software execution such as control flow, execution
+modes and timings and formats it into highly compressed binary packets.
+Technical details are documented in the Intel 64 and IA-32 Architectures
+Software Developer Manuals, Chapter 36 Intel Processor Trace.
+
+Intel PT is first supported in Intel Core M and 5th generation Intel Core
+processors that are based on the Intel micro-architecture code name Broadwell.
+
+Trace data is collected by 'perf record' and stored within the perf.data file.
+See below for options to 'perf record'.
+
+Trace data must be 'decoded' which involves walking the object code and matching
+the trace data packets. For example a TNT packet only tells whether a
+conditional branch was taken or not taken, so to make use of that packet the
+decoder must know precisely which instruction was being executed.
+
+Decoding is done on-the-fly.  The decoder outputs samples in the same format as
+samples output by perf hardware events, for example as though the "instructions"
+or "branches" events had been recorded.  Presently 3 tools support this:
+'perf script', 'perf report' and 'perf inject'.  See below for more information
+on using those tools.
+
+The main distinguishing feature of Intel PT is that the decoder can determine
+the exact flow of software execution.  Intel PT can be used to understand why
+and how did software get to a certain point, or behave a certain way.  The
+software does not have to be recompiled, so Intel PT works with debug or release
+builds, however the executed images are needed - which makes use in JIT-compiled
+environments, or with self-modified code, a challenge.  Also symbols need to be
+provided to make sense of addresses.
+
+A limitation of Intel PT is that it produces huge amounts of trace data
+(hundreds of megabytes per second per core) which takes a long time to decode,
+for example two or three orders of magnitude longer than it took to collect.
+Another limitation is the performance impact of tracing, something that will
+vary depending on the use-case and architecture.
+
+
+Quickstart
+----------
+
+It is important to start small.  That is because it is easy to capture vastly
+more data than can possibly be processed.
+
+The simplest thing to do with Intel PT is userspace profiling of small programs.
+Data is captured with 'perf record' e.g. to trace 'ls' userspace-only:
+
+       perf record -e intel_pt//u ls
+
+And profiled with 'perf report' e.g.
+
+       perf report
+
+To also trace kernel space presents a problem, namely kernel self-modifying
+code.  A fairly good kernel image is available in /proc/kcore but to get an
+accurate image a copy of /proc/kcore needs to be made under the same conditions
+as the data capture.  A script perf-with-kcore can do that, but beware that the
+script makes use of 'sudo' to copy /proc/kcore.  If you have perf installed
+locally from the source tree you can do:
+
+       ~/libexec/perf-core/perf-with-kcore record pt_ls -e intel_pt// -- ls
+
+which will create a directory named 'pt_ls' and put the perf.data file and
+copies of /proc/kcore, /proc/kallsyms and /proc/modules into it.  Then to use
+'perf report' becomes:
+
+       ~/libexec/perf-core/perf-with-kcore report pt_ls
+
+Because samples are synthesized after-the-fact, the sampling period can be
+selected for reporting. e.g. sample every microsecond
+
+       ~/libexec/perf-core/perf-with-kcore report pt_ls --itrace=i1usge
+
+See the sections below for more information about the --itrace option.
+
+Beware the smaller the period, the more samples that are produced, and the
+longer it takes to process them.
+
+Also note that the coarseness of Intel PT timing information will start to
+distort the statistical value of the sampling as the sampling period becomes
+smaller.
+
+To represent software control flow, "branches" samples are produced.  By default
+a branch sample is synthesized for every single branch.  To get an idea what
+data is available you can use the 'perf script' tool with all itrace sampling
+options, which will list all the samples.
+
+       perf record -e intel_pt//u ls
+       perf script --itrace=ibxwpe
+
+An interesting field that is not printed by default is 'flags' which can be
+displayed as follows:
+
+       perf script --itrace=ibxwpe -F+flags
+
+The flags are "bcrosyiABEx" which stand for branch, call, return, conditional,
+system, asynchronous, interrupt, transaction abort, trace begin, trace end, and
+in transaction, respectively.
+
+Another interesting field that is not printed by default is 'ipc' which can be
+displayed as follows:
+
+       perf script --itrace=be -F+ipc
+
+There are two ways that instructions-per-cycle (IPC) can be calculated depending
+on the recording.
+
+If the 'cyc' config term (see config terms section below) was used, then IPC is
+calculated using the cycle count from CYC packets, otherwise MTC packets are
+used - refer to the 'mtc' config term.  When MTC is used, however, the values
+are less accurate because the timing is less accurate.
+
+Because Intel PT does not update the cycle count on every branch or instruction,
+the values will often be zero.  When there are values, they will be the number
+of instructions and number of cycles since the last update, and thus represent
+the average IPC since the last IPC for that event type.  Note IPC for "branches"
+events is calculated separately from IPC for "instructions" events.
+
+Also note that the IPC instruction count may or may not include the current
+instruction.  If the cycle count is associated with an asynchronous branch
+(e.g. page fault or interrupt), then the instruction count does not include the
+current instruction, otherwise it does.  That is consistent with whether or not
+that instruction has retired when the cycle count is updated.
+
+Another note, in the case of "branches" events, non-taken branches are not
+presently sampled, so IPC values for them do not appear e.g. a CYC packet with a
+TNT packet that starts with a non-taken branch.  To see every possible IPC
+value, "instructions" events can be used e.g. --itrace=i0ns
+
+While it is possible to create scripts to analyze the data, an alternative
+approach is available to export the data to a sqlite or postgresql database.
+Refer to script export-to-sqlite.py or export-to-postgresql.py for more details,
+and to script exported-sql-viewer.py for an example of using the database.
+
+There is also script intel-pt-events.py which provides an example of how to
+unpack the raw data for power events and PTWRITE.
+
+As mentioned above, it is easy to capture too much data.  One way to limit the
+data captured is to use 'snapshot' mode which is explained further below.
+Refer to 'new snapshot option' and 'Intel PT modes of operation' further below.
+
+Another problem that will be experienced is decoder errors.  They can be caused
+by inability to access the executed image, self-modified or JIT-ed code, or the
+inability to match side-band information (such as context switches and mmaps)
+which results in the decoder not knowing what code was executed.
+
+There is also the problem of perf not being able to copy the data fast enough,
+resulting in data lost because the buffer was full.  See 'Buffer handling' below
+for more details.
+
+
+perf record
+-----------
+
+new event
+~~~~~~~~~
+
+The Intel PT kernel driver creates a new PMU for Intel PT.  PMU events are
+selected by providing the PMU name followed by the "config" separated by slashes.
+An enhancement has been made to allow default "config" e.g. the option
+
+       -e intel_pt//
+
+will use a default config value.  Currently that is the same as
+
+       -e intel_pt/tsc,noretcomp=0/
+
+which is the same as
+
+       -e intel_pt/tsc=1,noretcomp=0/
+
+Note there are now new config terms - see section 'config terms' further below.
+
+The config terms are listed in /sys/devices/intel_pt/format.  They are bit
+fields within the config member of the struct perf_event_attr which is
+passed to the kernel by the perf_event_open system call.  They correspond to bit
+fields in the IA32_RTIT_CTL MSR.  Here is a list of them and their definitions:
+
+       $ grep -H . /sys/bus/event_source/devices/intel_pt/format/*
+       /sys/bus/event_source/devices/intel_pt/format/cyc:config:1
+       /sys/bus/event_source/devices/intel_pt/format/cyc_thresh:config:19-22
+       /sys/bus/event_source/devices/intel_pt/format/mtc:config:9
+       /sys/bus/event_source/devices/intel_pt/format/mtc_period:config:14-17
+       /sys/bus/event_source/devices/intel_pt/format/noretcomp:config:11
+       /sys/bus/event_source/devices/intel_pt/format/psb_period:config:24-27
+       /sys/bus/event_source/devices/intel_pt/format/tsc:config:10
+
+Note that the default config must be overridden for each term i.e.
+
+       -e intel_pt/noretcomp=0/
+
+is the same as:
+
+       -e intel_pt/tsc=1,noretcomp=0/
+
+So, to disable TSC packets use:
+
+       -e intel_pt/tsc=0/
+
+It is also possible to specify the config value explicitly:
+
+       -e intel_pt/config=0x400/
+
+Note that, as with all events, the event is suffixed with event modifiers:
+
+       u       userspace
+       k       kernel
+       h       hypervisor
+       G       guest
+       H       host
+       p       precise ip
+
+'h', 'G' and 'H' are for virtualization which is not supported by Intel PT.
+'p' is also not relevant to Intel PT.  So only options 'u' and 'k' are
+meaningful for Intel PT.
+
+perf_event_attr is displayed if the -vv option is used e.g.
+
+       ------------------------------------------------------------
+       perf_event_attr:
+       type                             6
+       size                             112
+       config                           0x400
+       { sample_period, sample_freq }   1
+       sample_type                      IP|TID|TIME|CPU|IDENTIFIER
+       read_format                      ID
+       disabled                         1
+       inherit                          1
+       exclude_kernel                   1
+       exclude_hv                       1
+       enable_on_exec                   1
+       sample_id_all                    1
+       ------------------------------------------------------------
+       sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
+       ------------------------------------------------------------
+
+
+config terms
+~~~~~~~~~~~~
+
+The June 2015 version of Intel 64 and IA-32 Architectures Software Developer
+Manuals, Chapter 36 Intel Processor Trace, defined new Intel PT features.
+Some of the features are reflect in new config terms.  All the config terms are
+described below.
+
+tsc            Always supported.  Produces TSC timestamp packets to provide
+               timing information.  In some cases it is possible to decode
+               without timing information, for example a per-thread context
+               that does not overlap executable memory maps.
+
+               The default config selects tsc (i.e. tsc=1).
+
+noretcomp      Always supported.  Disables "return compression" so a TIP packet
+               is produced when a function returns.  Causes more packets to be
+               produced but might make decoding more reliable.
+
+               The default config does not select noretcomp (i.e. noretcomp=0).
+
+psb_period     Allows the frequency of PSB packets to be specified.
+
+               The PSB packet is a synchronization packet that provides a
+               starting point for decoding or recovery from errors.
+
+               Support for psb_period is indicated by:
+
+                       /sys/bus/event_source/devices/intel_pt/caps/psb_cyc
+
+               which contains "1" if the feature is supported and "0"
+               otherwise.
+
+               Valid values are given by:
+
+                       /sys/bus/event_source/devices/intel_pt/caps/psb_periods
+
+               which contains a hexadecimal value, the bits of which represent
+               valid values e.g. bit 2 set means value 2 is valid.
+
+               The psb_period value is converted to the approximate number of
+               trace bytes between PSB packets as:
+
+                       2 ^ (value + 11)
+
+               e.g. value 3 means 16KiB bytes between PSBs
+
+               If an invalid value is entered, the error message
+               will give a list of valid values e.g.
+
+                       $ perf record -e intel_pt/psb_period=15/u uname
+                       Invalid psb_period for intel_pt. Valid values are: 0-5
+
+               If MTC packets are selected, the default config selects a value
+               of 3 (i.e. psb_period=3) or the nearest lower value that is
+               supported (0 is always supported).  Otherwise the default is 0.
+
+               If decoding is expected to be reliable and the buffer is large
+               then a large PSB period can be used.
+
+               Because a TSC packet is produced with PSB, the PSB period can
+               also affect the granularity to timing information in the absence
+               of MTC or CYC.
+
+mtc            Produces MTC timing packets.
+
+               MTC packets provide finer grain timestamp information than TSC
+               packets.  MTC packets record time using the hardware crystal
+               clock (CTC) which is related to TSC packets using a TMA packet.
+
+               Support for this feature is indicated by:
+
+                       /sys/bus/event_source/devices/intel_pt/caps/mtc
+
+               which contains "1" if the feature is supported and
+               "0" otherwise.
+
+               The frequency of MTC packets can also be specified - see
+               mtc_period below.
+
+mtc_period     Specifies how frequently MTC packets are produced - see mtc
+               above for how to determine if MTC packets are supported.
+
+               Valid values are given by:
+
+                       /sys/bus/event_source/devices/intel_pt/caps/mtc_periods
+
+               which contains a hexadecimal value, the bits of which represent
+               valid values e.g. bit 2 set means value 2 is valid.
+
+               The mtc_period value is converted to the MTC frequency as:
+
+                       CTC-frequency / (2 ^ value)
+
+               e.g. value 3 means one eighth of CTC-frequency
+
+               Where CTC is the hardware crystal clock, the frequency of which
+               can be related to TSC via values provided in cpuid leaf 0x15.
+
+               If an invalid value is entered, the error message
+               will give a list of valid values e.g.
+
+                       $ perf record -e intel_pt/mtc_period=15/u uname
+                       Invalid mtc_period for intel_pt. Valid values are: 0,3,6,9
+
+               The default value is 3 or the nearest lower value
+               that is supported (0 is always supported).
+
+cyc            Produces CYC timing packets.
+
+               CYC packets provide even finer grain timestamp information than
+               MTC and TSC packets.  A CYC packet contains the number of CPU
+               cycles since the last CYC packet. Unlike MTC and TSC packets,
+               CYC packets are only sent when another packet is also sent.
+
+               Support for this feature is indicated by:
+
+                       /sys/bus/event_source/devices/intel_pt/caps/psb_cyc
+
+               which contains "1" if the feature is supported and
+               "0" otherwise.
+
+               The number of CYC packets produced can be reduced by specifying
+               a threshold - see cyc_thresh below.
+
+cyc_thresh     Specifies how frequently CYC packets are produced - see cyc
+               above for how to determine if CYC packets are supported.
+
+               Valid cyc_thresh values are given by:
+
+                       /sys/bus/event_source/devices/intel_pt/caps/cycle_thresholds
+
+               which contains a hexadecimal value, the bits of which represent
+               valid values e.g. bit 2 set means value 2 is valid.
+
+               The cyc_thresh value represents the minimum number of CPU cycles
+               that must have passed before a CYC packet can be sent.  The
+               number of CPU cycles is:
+
+                       2 ^ (value - 1)
+
+               e.g. value 4 means 8 CPU cycles must pass before a CYC packet
+               can be sent.  Note a CYC packet is still only sent when another
+               packet is sent, not at, e.g. every 8 CPU cycles.
+
+               If an invalid value is entered, the error message
+               will give a list of valid values e.g.
+
+                       $ perf record -e intel_pt/cyc,cyc_thresh=15/u uname
+                       Invalid cyc_thresh for intel_pt. Valid values are: 0-12
+
+               CYC packets are not requested by default.
+
+pt             Specifies pass-through which enables the 'branch' config term.
+
+               The default config selects 'pt' if it is available, so a user will
+               never need to specify this term.
+
+branch         Enable branch tracing.  Branch tracing is enabled by default so to
+               disable branch tracing use 'branch=0'.
+
+               The default config selects 'branch' if it is available.
+
+ptw            Enable PTWRITE packets which are produced when a ptwrite instruction
+               is executed.
+
+               Support for this feature is indicated by:
+
+                       /sys/bus/event_source/devices/intel_pt/caps/ptwrite
+
+               which contains "1" if the feature is supported and
+               "0" otherwise.
+
+fup_on_ptw     Enable a FUP packet to follow the PTWRITE packet.  The FUP packet
+               provides the address of the ptwrite instruction.  In the absence of
+               fup_on_ptw, the decoder will use the address of the previous branch
+               if branch tracing is enabled, otherwise the address will be zero.
+               Note that fup_on_ptw will work even when branch tracing is disabled.
+
+pwr_evt                Enable power events.  The power events provide information about
+               changes to the CPU C-state.
+
+               Support for this feature is indicated by:
+
+                       /sys/bus/event_source/devices/intel_pt/caps/power_event_trace
+
+               which contains "1" if the feature is supported and
+               "0" otherwise.
+
+
+AUX area sampling option
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+To select Intel PT "sampling" the AUX area sampling option can be used:
+
+       --aux-sample
+
+Optionally it can be followed by the sample size in bytes e.g.
+
+       --aux-sample=8192
+
+In addition, the Intel PT event to sample must be defined e.g.
+
+       -e intel_pt//u
+
+Samples on other events will be created containing Intel PT data e.g. the
+following will create Intel PT samples on the branch-misses event, note the
+events must be grouped using {}:
+
+       perf record --aux-sample -e '{intel_pt//u,branch-misses:u}'
+
+An alternative to '--aux-sample' is to add the config term 'aux-sample-size' to
+events.  In this case, the grouping is implied e.g.
+
+       perf record -e intel_pt//u -e branch-misses/aux-sample-size=8192/u
+
+is the same as:
+
+       perf record -e '{intel_pt//u,branch-misses/aux-sample-size=8192/u}'
+
+but allows for also using an address filter e.g.:
+
+       perf record -e intel_pt//u --filter 'filter * @/bin/ls' -e branch-misses/aux-sample-size=8192/u -- ls
+
+It is important to select a sample size that is big enough to contain at least
+one PSB packet.  If not a warning will be displayed:
+
+       Intel PT sample size (%zu) may be too small for PSB period (%zu)
+
+The calculation used for that is: if sample_size <= psb_period + 256 display the
+warning.  When sampling is used, psb_period defaults to 0 (2KiB).
+
+The default sample size is 4KiB.
+
+The sample size is passed in aux_sample_size in struct perf_event_attr.  The
+sample size is limited by the maximum event size which is 64KiB.  It is
+difficult to know how big the event might be without the trace sample attached,
+but the tool validates that the sample size is not greater than 60KiB.
+
+
+new snapshot option
+~~~~~~~~~~~~~~~~~~~
+
+The difference between full trace and snapshot from the kernel's perspective is
+that in full trace we don't overwrite trace data that the user hasn't collected
+yet (and indicated that by advancing aux_tail), whereas in snapshot mode we let
+the trace run and overwrite older data in the buffer so that whenever something
+interesting happens, we can stop it and grab a snapshot of what was going on
+around that interesting moment.
+
+To select snapshot mode a new option has been added:
+
+       -S
+
+Optionally it can be followed by the snapshot size e.g.
+
+       -S0x100000
+
+The default snapshot size is the auxtrace mmap size.  If neither auxtrace mmap size
+nor snapshot size is specified, then the default is 4MiB for privileged users
+(or if /proc/sys/kernel/perf_event_paranoid < 0), 128KiB for unprivileged users.
+If an unprivileged user does not specify mmap pages, the mmap pages will be
+reduced as described in the 'new auxtrace mmap size option' section below.
+
+The snapshot size is displayed if the option -vv is used e.g.
+
+       Intel PT snapshot size: %zu
+
+
+new auxtrace mmap size option
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Intel PT buffer size is specified by an addition to the -m option e.g.
+
+       -m,16
+
+selects a buffer size of 16 pages i.e. 64KiB.
+
+Note that the existing functionality of -m is unchanged.  The auxtrace mmap size
+is specified by the optional addition of a comma and the value.
+
+The default auxtrace mmap size for Intel PT is 4MiB/page_size for privileged users
+(or if /proc/sys/kernel/perf_event_paranoid < 0), 128KiB for unprivileged users.
+If an unprivileged user does not specify mmap pages, the mmap pages will be
+reduced from the default 512KiB/page_size to 256KiB/page_size, otherwise the
+user is likely to get an error as they exceed their mlock limit (Max locked
+memory as shown in /proc/self/limits).  Note that perf does not count the first
+512KiB (actually /proc/sys/kernel/perf_event_mlock_kb minus 1 page) per cpu
+against the mlock limit so an unprivileged user is allowed 512KiB per cpu plus
+their mlock limit (which defaults to 64KiB but is not multiplied by the number
+of cpus).
+
+In full-trace mode, powers of two are allowed for buffer size, with a minimum
+size of 2 pages.  In snapshot mode or sampling mode, it is the same but the
+minimum size is 1 page.
+
+The mmap size and auxtrace mmap size are displayed if the -vv option is used e.g.
+
+       mmap length 528384
+       auxtrace mmap length 4198400
+
+
+Intel PT modes of operation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Intel PT can be used in 2 modes:
+       full-trace mode
+       sample mode
+       snapshot mode
+
+Full-trace mode traces continuously e.g.
+
+       perf record -e intel_pt//u uname
+
+Sample mode attaches a Intel PT sample to other events e.g.
+
+       perf record --aux-sample -e intel_pt//u -e branch-misses:u
+
+Snapshot mode captures the available data when a signal is sent e.g.
+
+       perf record -v -e intel_pt//u -S ./loopy 1000000000 &
+       [1] 11435
+       kill -USR2 11435
+       Recording AUX area tracing snapshot
+
+Note that the signal sent is SIGUSR2.
+Note that "Recording AUX area tracing snapshot" is displayed because the -v
+option is used.
+
+The 2 modes cannot be used together.
+
+
+Buffer handling
+~~~~~~~~~~~~~~~
+
+There may be buffer limitations (i.e. single ToPa entry) which means that actual
+buffer sizes are limited to powers of 2 up to 4MiB (MAX_ORDER).  In order to
+provide other sizes, and in particular an arbitrarily large size, multiple
+buffers are logically concatenated.  However an interrupt must be used to switch
+between buffers.  That has two potential problems:
+       a) the interrupt may not be handled in time so that the current buffer
+       becomes full and some trace data is lost.
+       b) the interrupts may slow the system and affect the performance
+       results.
+
+If trace data is lost, the driver sets 'truncated' in the PERF_RECORD_AUX event
+which the tools report as an error.
+
+In full-trace mode, the driver waits for data to be copied out before allowing
+the (logical) buffer to wrap-around.  If data is not copied out quickly enough,
+again 'truncated' is set in the PERF_RECORD_AUX event.  If the driver has to
+wait, the intel_pt event gets disabled.  Because it is difficult to know when
+that happens, perf tools always re-enable the intel_pt event after copying out
+data.
+
+
+Intel PT and build ids
+~~~~~~~~~~~~~~~~~~~~~~
+
+By default "perf record" post-processes the event stream to find all build ids
+for executables for all addresses sampled.  Deliberately, Intel PT is not
+decoded for that purpose (it would take too long).  Instead the build ids for
+all executables encountered (due to mmap, comm or task events) are included
+in the perf.data file.
+
+To see buildids included in the perf.data file use the command:
+
+       perf buildid-list
+
+If the perf.data file contains Intel PT data, that is the same as:
+
+       perf buildid-list --with-hits
+
+
+Snapshot mode and event disabling
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to make a snapshot, the intel_pt event is disabled using an IOCTL,
+namely PERF_EVENT_IOC_DISABLE.  However doing that can also disable the
+collection of side-band information.  In order to prevent that,  a dummy
+software event has been introduced that permits tracking events (like mmaps) to
+continue to be recorded while intel_pt is disabled.  That is important to ensure
+there is complete side-band information to allow the decoding of subsequent
+snapshots.
+
+A test has been created for that.  To find the test:
+
+       perf test list
+       ...
+       23: Test using a dummy software event to keep tracking
+
+To run the test:
+
+       perf test 23
+       23: Test using a dummy software event to keep tracking     : Ok
+
+
+perf record modes (nothing new here)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+perf record essentially operates in one of three modes:
+       per thread
+       per cpu
+       workload only
+
+"per thread" mode is selected by -t or by --per-thread (with -p or -u or just a
+workload).
+"per cpu" is selected by -C or -a.
+"workload only" mode is selected by not using the other options but providing a
+command to run (i.e. the workload).
+
+In per-thread mode an exact list of threads is traced.  There is no inheritance.
+Each thread has its own event buffer.
+
+In per-cpu mode all processes (or processes from the selected cgroup i.e. -G
+option, or processes selected with -p or -u) are traced.  Each cpu has its own
+buffer. Inheritance is allowed.
+
+In workload-only mode, the workload is traced but with per-cpu buffers.
+Inheritance is allowed.  Note that you can now trace a workload in per-thread
+mode by using the --per-thread option.
+
+
+Privileged vs non-privileged users
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users
+have memory limits imposed upon them.  That affects what buffer sizes they can
+have as outlined above.
+
+The v4.2 kernel introduced support for a context switch metadata event,
+PERF_RECORD_SWITCH, which allows unprivileged users to see when their processes
+are scheduled out and in, just not by whom, which is left for the
+PERF_RECORD_SWITCH_CPU_WIDE, that is only accessible in system wide context,
+which in turn requires CAP_SYS_ADMIN.
+
+Please see the 45ac1403f564 ("perf: Add PERF_RECORD_SWITCH to indicate context
+switches") commit, that introduces these metadata events for further info.
+
+When working with kernels < v4.2, the following considerations must be taken,
+as the sched:sched_switch tracepoints will be used to receive such information:
+
+Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users are
+not permitted to use tracepoints which means there is insufficient side-band
+information to decode Intel PT in per-cpu mode, and potentially workload-only
+mode too if the workload creates new processes.
+
+Note also, that to use tracepoints, read-access to debugfs is required.  So if
+debugfs is not mounted or the user does not have read-access, it will again not
+be possible to decode Intel PT in per-cpu mode.
+
+
+sched_switch tracepoint
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The sched_switch tracepoint is used to provide side-band data for Intel PT
+decoding in kernels where the PERF_RECORD_SWITCH metadata event isn't
+available.
+
+The sched_switch events are automatically added. e.g. the second event shown
+below:
+
+       $ perf record -vv -e intel_pt//u uname
+       ------------------------------------------------------------
+       perf_event_attr:
+       type                             6
+       size                             112
+       config                           0x400
+       { sample_period, sample_freq }   1
+       sample_type                      IP|TID|TIME|CPU|IDENTIFIER
+       read_format                      ID
+       disabled                         1
+       inherit                          1
+       exclude_kernel                   1
+       exclude_hv                       1
+       enable_on_exec                   1
+       sample_id_all                    1
+       ------------------------------------------------------------
+       sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
+       ------------------------------------------------------------
+       perf_event_attr:
+       type                             2
+       size                             112
+       config                           0x108
+       { sample_period, sample_freq }   1
+       sample_type                      IP|TID|TIME|CPU|PERIOD|RAW|IDENTIFIER
+       read_format                      ID
+       inherit                          1
+       sample_id_all                    1
+       exclude_guest                    1
+       ------------------------------------------------------------
+       sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8
+       sys_perf_event_open: pid -1  cpu 1  group_fd -1  flags 0x8
+       sys_perf_event_open: pid -1  cpu 2  group_fd -1  flags 0x8
+       sys_perf_event_open: pid -1  cpu 3  group_fd -1  flags 0x8
+       ------------------------------------------------------------
+       perf_event_attr:
+       type                             1
+       size                             112
+       config                           0x9
+       { sample_period, sample_freq }   1
+       sample_type                      IP|TID|TIME|IDENTIFIER
+       read_format                      ID
+       disabled                         1
+       inherit                          1
+       exclude_kernel                   1
+       exclude_hv                       1
+       mmap                             1
+       comm                             1
+       enable_on_exec                   1
+       task                             1
+       sample_id_all                    1
+       mmap2                            1
+       comm_exec                        1
+       ------------------------------------------------------------
+       sys_perf_event_open: pid 31104  cpu 0  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 1  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 2  group_fd -1  flags 0x8
+       sys_perf_event_open: pid 31104  cpu 3  group_fd -1  flags 0x8
+       mmap size 528384B
+       AUX area mmap length 4194304
+       perf event ring buffer mmapped per cpu
+       Synthesizing auxtrace information
+       Linux
+       [ perf record: Woken up 1 times to write data ]
+       [ perf record: Captured and wrote 0.042 MB perf.data ]
+
+Note, the sched_switch event is only added if the user is permitted to use it
+and only in per-cpu mode.
+
+Note also, the sched_switch event is only added if TSC packets are requested.
+That is because, in the absence of timing information, the sched_switch events
+cannot be matched against the Intel PT trace.
+
+
+perf script
+-----------
+
+By default, perf script will decode trace data found in the perf.data file.
+This can be further controlled by new option --itrace.
+
+
+New --itrace option
+~~~~~~~~~~~~~~~~~~~
+
+Having no option is the same as
+
+       --itrace
+
+which, in turn, is the same as
+
+       --itrace=cepwx
+
+The letters are:
+
+       i       synthesize "instructions" events
+       b       synthesize "branches" events
+       x       synthesize "transactions" events
+       w       synthesize "ptwrite" events
+       p       synthesize "power" events
+       c       synthesize branches events (calls only)
+       r       synthesize branches events (returns only)
+       e       synthesize tracing error events
+       d       create a debug log
+       g       synthesize a call chain (use with i or x)
+       l       synthesize last branch entries (use with i or x)
+       s       skip initial number of events
+
+"Instructions" events look like they were recorded by "perf record -e
+instructions".
+
+"Branches" events look like they were recorded by "perf record -e branches". "c"
+and "r" can be combined to get calls and returns.
+
+"Transactions" events correspond to the start or end of transactions. The
+'flags' field can be used in perf script to determine whether the event is a
+tranasaction start, commit or abort.
+
+Note that "instructions", "branches" and "transactions" events depend on code
+flow packets which can be disabled by using the config term "branch=0".  Refer
+to the config terms section above.
+
+"ptwrite" events record the payload of the ptwrite instruction and whether
+"fup_on_ptw" was used.  "ptwrite" events depend on PTWRITE packets which are
+recorded only if the "ptw" config term was used.  Refer to the config terms
+section above.  perf script "synth" field displays "ptwrite" information like
+this: "ip: 0 payload: 0x123456789abcdef0"  where "ip" is 1 if "fup_on_ptw" was
+used.
+
+"Power" events correspond to power event packets and CBR (core-to-bus ratio)
+packets.  While CBR packets are always recorded when tracing is enabled, power
+event packets are recorded only if the "pwr_evt" config term was used.  Refer to
+the config terms section above.  The power events record information about
+C-state changes, whereas CBR is indicative of CPU frequency.  perf script
+"event,synth" fields display information like this:
+       cbr:  cbr: 22 freq: 2189 MHz (200%)
+       mwait:  hints: 0x60 extensions: 0x1
+       pwre:  hw: 0 cstate: 2 sub-cstate: 0
+       exstop:  ip: 1
+       pwrx:  deepest cstate: 2 last cstate: 2 wake reason: 0x4
+Where:
+       "cbr" includes the frequency and the percentage of maximum non-turbo
+       "mwait" shows mwait hints and extensions
+       "pwre" shows C-state transitions (to a C-state deeper than C0) and
+       whether initiated by hardware
+       "exstop" indicates execution stopped and whether the IP was recorded
+       exactly,
+       "pwrx" indicates return to C0
+For more details refer to the Intel 64 and IA-32 Architectures Software
+Developer Manuals.
+
+Error events show where the decoder lost the trace.  Error events
+are quite important.  Users must know if what they are seeing is a complete
+picture or not.
+
+The "d" option will cause the creation of a file "intel_pt.log" containing all
+decoded packets and instructions.  Note that this option slows down the decoder
+and that the resulting file may be very large.
+
+In addition, the period of the "instructions" event can be specified. e.g.
+
+       --itrace=i10us
+
+sets the period to 10us i.e. one  instruction sample is synthesized for each 10
+microseconds of trace.  Alternatives to "us" are "ms" (milliseconds),
+"ns" (nanoseconds), "t" (TSC ticks) or "i" (instructions).
+
+"ms", "us" and "ns" are converted to TSC ticks.
+
+The timing information included with Intel PT does not give the time of every
+instruction.  Consequently, for the purpose of sampling, the decoder estimates
+the time since the last timing packet based on 1 tick per instruction.  The time
+on the sample is *not* adjusted and reflects the last known value of TSC.
+
+For Intel PT, the default period is 100us.
+
+Setting it to a zero period means "as often as possible".
+
+In the case of Intel PT that is the same as a period of 1 and a unit of
+'instructions' (i.e. --itrace=i1i).
+
+Also the call chain size (default 16, max. 1024) for instructions or
+transactions events can be specified. e.g.
+
+       --itrace=ig32
+       --itrace=xg32
+
+Also the number of last branch entries (default 64, max. 1024) for instructions or
+transactions events can be specified. e.g.
+
+       --itrace=il10
+       --itrace=xl10
+
+Note that last branch entries are cleared for each sample, so there is no overlap
+from one sample to the next.
+
+To disable trace decoding entirely, use the option --no-itrace.
+
+It is also possible to skip events generated (instructions, branches, transactions)
+at the beginning. This is useful to ignore initialization code.
+
+       --itrace=i0nss1000000
+
+skips the first million instructions.
+
+dump option
+~~~~~~~~~~~
+
+perf script has an option (-D) to "dump" the events i.e. display the binary
+data.
+
+When -D is used, Intel PT packets are displayed.  The packet decoder does not
+pay attention to PSB packets, but just decodes the bytes - so the packets seen
+by the actual decoder may not be identical in places where the data is corrupt.
+One example of that would be when the buffer-switching interrupt has been too
+slow, and the buffer has been filled completely.  In that case, the last packet
+in the buffer might be truncated and immediately followed by a PSB as the trace
+continues in the next buffer.
+
+To disable the display of Intel PT packets, combine the -D option with
+--no-itrace.
+
+
+perf report
+-----------
+
+By default, perf report will decode trace data found in the perf.data file.
+This can be further controlled by new option --itrace exactly the same as
+perf script, with the exception that the default is --itrace=igxe.
+
+
+perf inject
+-----------
+
+perf inject also accepts the --itrace option in which case tracing data is
+removed and replaced with the synthesized events. e.g.
+
+       perf inject --itrace -i perf.data -o perf.data.new
+
+Below is an example of using Intel PT with autofdo.  It requires autofdo
+(https://github.com/google/autofdo) and gcc version 5.  The bubble
+sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial)
+amended to take the number of elements as a parameter.
+
+       $ gcc-5 -O3 sort.c -o sort_optimized
+       $ ./sort_optimized 30000
+       Bubble sorting array of 30000 elements
+       2254 ms
+
+       $ cat ~/.perfconfig
+       [intel-pt]
+               mispred-all = on
+
+       $ perf record -e intel_pt//u ./sort 3000
+       Bubble sorting array of 3000 elements
+       58 ms
+       [ perf record: Woken up 2 times to write data ]
+       [ perf record: Captured and wrote 3.939 MB perf.data ]
+       $ perf inject -i perf.data -o inj --itrace=i100usle --strip
+       $ ./create_gcov --binary=./sort --profile=inj --gcov=sort.gcov -gcov_version=1
+       $ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo
+       $ ./sort_autofdo 30000
+       Bubble sorting array of 30000 elements
+       2155 ms
+
+Note there is currently no advantage to using Intel PT instead of LBR, but
+that may change in the future if greater use is made of the data.
+
+
+PEBS via Intel PT
+-----------------
+
+Some hardware has the feature to redirect PEBS records to the Intel PT trace.
+Recording is selected by using the aux-output config term e.g.
+
+       perf record -c 10000 -e '{intel_pt/branch=0/,cycles/aux-output/ppp}' uname
+
+Note that currently, software only supports redirecting at most one PEBS event.
+
+To display PEBS events from the Intel PT trace, use the itrace 'o' option e.g.
+
+       perf script --itrace=oe
+
+
+SEE ALSO
+--------
+
+linkperf:perf-record[1], linkperf:perf-script[1], linkperf:perf-report[1],
+linkperf:perf-inject[1]
index b23a401..7f4db75 100644 (file)
@@ -589,4 +589,4 @@ appended unit character - B/K/M/G
 
 SEE ALSO
 --------
-linkperf:perf-stat[1], linkperf:perf-list[1]
+linkperf:perf-stat[1], linkperf:perf-list[1], linkperf:perf-intel-pt[1]
index db61f16..bd0a029 100644 (file)
@@ -546,4 +546,5 @@ include::callchain-overhead-calculation.txt[]
 
 SEE ALSO
 --------
-linkperf:perf-stat[1], linkperf:perf-annotate[1], linkperf:perf-record[1]
+linkperf:perf-stat[1], linkperf:perf-annotate[1], linkperf:perf-record[1],
+linkperf:perf-intel-pt[1]
index 2599b05..db6a36a 100644 (file)
@@ -429,4 +429,4 @@ include::itrace.txt[]
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-script-perl[1],
-linkperf:perf-script-python[1]
+linkperf:perf-script-python[1], linkperf:perf-intel-pt[1]
index 9431b80..4d56586 100644 (file)
@@ -334,6 +334,15 @@ Configure all used events to run in kernel space.
 --all-user::
 Configure all used events to run in user space.
 
+--percore-show-thread::
+The event modifier "percore" has supported to sum up the event counts
+for all hardware threads in a core and show the counts per core.
+
+This option with event modifier "percore" enabled also sums up the event
+counts for all hardware threads in a core but show the sum counts per
+hardware thread. This is essentially a replacement for the any bit and
+convenient for post processing.
+
 EXAMPLES
 --------
 
index 7902a56..b8fc7d9 100644 (file)
@@ -35,7 +35,7 @@ endif
 # Only pass canonical directory names as the output directory:
 #
 ifneq ($(O),)
-  FULL_O := $(shell readlink -f $(O) || echo $(O))
+  FULL_O := $(shell cd $(PWD); readlink -f $(O) || echo $(O))
 endif
 
 #
index 2898cfd..941f814 100644 (file)
@@ -858,21 +858,6 @@ static void cs_etm_recording_free(struct auxtrace_record *itr)
        free(ptr);
 }
 
-static int cs_etm_read_finish(struct auxtrace_record *itr, int idx)
-{
-       struct cs_etm_recording *ptr =
-                       container_of(itr, struct cs_etm_recording, itr);
-       struct evsel *evsel;
-
-       evlist__for_each_entry(ptr->evlist, evsel) {
-               if (evsel->core.attr.type == ptr->cs_etm_pmu->type)
-                       return perf_evlist__enable_event_idx(ptr->evlist,
-                                                            evsel, idx);
-       }
-
-       return -EINVAL;
-}
-
 struct auxtrace_record *cs_etm_record_init(int *err)
 {
        struct perf_pmu *cs_etm_pmu;
@@ -892,6 +877,7 @@ struct auxtrace_record *cs_etm_record_init(int *err)
        }
 
        ptr->cs_etm_pmu                 = cs_etm_pmu;
+       ptr->itr.pmu                    = cs_etm_pmu;
        ptr->itr.parse_snapshot_options = cs_etm_parse_snapshot_options;
        ptr->itr.recording_options      = cs_etm_recording_options;
        ptr->itr.info_priv_size         = cs_etm_info_priv_size;
@@ -901,7 +887,7 @@ struct auxtrace_record *cs_etm_record_init(int *err)
        ptr->itr.snapshot_finish        = cs_etm_snapshot_finish;
        ptr->itr.reference              = cs_etm_reference;
        ptr->itr.free                   = cs_etm_recording_free;
-       ptr->itr.read_finish            = cs_etm_read_finish;
+       ptr->itr.read_finish            = auxtrace_record__read_finish;
 
        *err = 0;
        return &ptr->itr;
index eba6541..27653be 100644 (file)
 #include <linux/zalloc.h>
 #include <time.h>
 
-#include "../../util/cpumap.h"
-#include "../../util/event.h"
-#include "../../util/evsel.h"
-#include "../../util/evlist.h"
-#include "../../util/session.h"
+#include "../../../util/cpumap.h"
+#include "../../../util/event.h"
+#include "../../../util/evsel.h"
+#include "../../../util/evlist.h"
+#include "../../../util/session.h"
 #include <internal/lib.h> // page_size
-#include "../../util/pmu.h"
-#include "../../util/debug.h"
-#include "../../util/auxtrace.h"
-#include "../../util/record.h"
-#include "../../util/arm-spe.h"
+#include "../../../util/pmu.h"
+#include "../../../util/debug.h"
+#include "../../../util/auxtrace.h"
+#include "../../../util/record.h"
+#include "../../../util/arm-spe.h"
 
 #define KiB(x) ((x) * 1024)
 #define MiB(x) ((x) * 1024 * 1024)
@@ -158,20 +158,6 @@ static void arm_spe_recording_free(struct auxtrace_record *itr)
        free(sper);
 }
 
-static int arm_spe_read_finish(struct auxtrace_record *itr, int idx)
-{
-       struct arm_spe_recording *sper =
-                       container_of(itr, struct arm_spe_recording, itr);
-       struct evsel *evsel;
-
-       evlist__for_each_entry(sper->evlist, evsel) {
-               if (evsel->core.attr.type == sper->arm_spe_pmu->type)
-                       return perf_evlist__enable_event_idx(sper->evlist,
-                                                            evsel, idx);
-       }
-       return -EINVAL;
-}
-
 struct auxtrace_record *arm_spe_recording_init(int *err,
                                               struct perf_pmu *arm_spe_pmu)
 {
@@ -189,12 +175,13 @@ struct auxtrace_record *arm_spe_recording_init(int *err,
        }
 
        sper->arm_spe_pmu = arm_spe_pmu;
+       sper->itr.pmu = arm_spe_pmu;
        sper->itr.recording_options = arm_spe_recording_options;
        sper->itr.info_priv_size = arm_spe_info_priv_size;
        sper->itr.info_fill = arm_spe_info_fill;
        sper->itr.free = arm_spe_recording_free;
        sper->itr.reference = arm_spe_reference;
-       sper->itr.read_finish = arm_spe_read_finish;
+       sper->itr.read_finish = auxtrace_record__read_finish;
        sper->itr.alignment = 0;
 
        *err = 0;
index 2864e2e..2833e10 100644 (file)
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-#include "../../util/perf_regs.h"
+#include "../../../util/perf_regs.h"
 
 const struct sample_reg sample_reg_masks[] = {
        SMPL_REG_END
index 43f736e..35b61bf 100644 (file)
 433    common  fspick                          sys_fspick
 434    common  pidfd_open                      sys_pidfd_open
 435    nospu   clone3                          ppc_clone3
+437    common  openat2                         sys_openat2
+438    common  pidfd_getfd                     sys_pidfd_getfd
index e9c436e..0a52429 100644 (file)
@@ -4,8 +4,8 @@
 #include <regex.h>
 #include <linux/zalloc.h>
 
-#include "../../util/perf_regs.h"
-#include "../../util/debug.h"
+#include "../../../util/perf_regs.h"
+#include "../../../util/debug.h"
 
 #include <linux/kernel.h>
 
index 7abc9fd..3da506e 100644 (file)
@@ -7,13 +7,13 @@
 #include <errno.h>
 #include <stdbool.h>
 
-#include "../../util/header.h"
-#include "../../util/debug.h"
-#include "../../util/pmu.h"
-#include "../../util/auxtrace.h"
-#include "../../util/intel-pt.h"
-#include "../../util/intel-bts.h"
-#include "../../util/evlist.h"
+#include "../../../util/header.h"
+#include "../../../util/debug.h"
+#include "../../../util/pmu.h"
+#include "../../../util/auxtrace.h"
+#include "../../../util/intel-pt.h"
+#include "../../../util/intel-bts.h"
+#include "../../../util/evlist.h"
 
 static
 struct auxtrace_record *auxtrace_record__init_intel(struct evlist *evlist,
index ac45015..047dc00 100644 (file)
@@ -3,12 +3,12 @@
 #include <linux/string.h>
 #include <linux/zalloc.h>
 
-#include "../../util/event.h"
-#include "../../util/synthetic-events.h"
-#include "../../util/machine.h"
-#include "../../util/tool.h"
-#include "../../util/map.h"
-#include "../../util/debug.h"
+#include "../../../util/event.h"
+#include "../../../util/synthetic-events.h"
+#include "../../../util/machine.h"
+#include "../../../util/tool.h"
+#include "../../../util/map.h"
+#include "../../../util/debug.h"
 
 #if defined(__x86_64__)
 
index aa6deb4..578c8c5 100644 (file)
@@ -7,8 +7,8 @@
 #include <string.h>
 #include <regex.h>
 
-#include "../../util/debug.h"
-#include "../../util/header.h"
+#include "../../../util/debug.h"
+#include "../../../util/header.h"
 
 static inline void
 cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
index 27d9e21..09f9380 100644 (file)
 #include <linux/log2.h>
 #include <linux/zalloc.h>
 
-#include "../../util/cpumap.h"
-#include "../../util/event.h"
-#include "../../util/evsel.h"
-#include "../../util/evlist.h"
-#include "../../util/mmap.h"
-#include "../../util/session.h"
-#include "../../util/pmu.h"
-#include "../../util/debug.h"
-#include "../../util/record.h"
-#include "../../util/tsc.h"
-#include "../../util/auxtrace.h"
-#include "../../util/intel-bts.h"
+#include "../../../util/cpumap.h"
+#include "../../../util/event.h"
+#include "../../../util/evsel.h"
+#include "../../../util/evlist.h"
+#include "../../../util/mmap.h"
+#include "../../../util/session.h"
+#include "../../../util/pmu.h"
+#include "../../../util/debug.h"
+#include "../../../util/record.h"
+#include "../../../util/tsc.h"
+#include "../../../util/auxtrace.h"
+#include "../../../util/intel-bts.h"
 #include <internal/lib.h> // page_size
 
 #define KiB(x) ((x) * 1024)
@@ -413,20 +413,6 @@ out_err:
        return err;
 }
 
-static int intel_bts_read_finish(struct auxtrace_record *itr, int idx)
-{
-       struct intel_bts_recording *btsr =
-                       container_of(itr, struct intel_bts_recording, itr);
-       struct evsel *evsel;
-
-       evlist__for_each_entry(btsr->evlist, evsel) {
-               if (evsel->core.attr.type == btsr->intel_bts_pmu->type)
-                       return perf_evlist__enable_event_idx(btsr->evlist,
-                                                            evsel, idx);
-       }
-       return -EINVAL;
-}
-
 struct auxtrace_record *intel_bts_recording_init(int *err)
 {
        struct perf_pmu *intel_bts_pmu = perf_pmu__find(INTEL_BTS_PMU_NAME);
@@ -447,6 +433,7 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
        }
 
        btsr->intel_bts_pmu = intel_bts_pmu;
+       btsr->itr.pmu = intel_bts_pmu;
        btsr->itr.recording_options = intel_bts_recording_options;
        btsr->itr.info_priv_size = intel_bts_info_priv_size;
        btsr->itr.info_fill = intel_bts_info_fill;
@@ -456,7 +443,7 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
        btsr->itr.find_snapshot = intel_bts_find_snapshot;
        btsr->itr.parse_snapshot_options = intel_bts_parse_snapshot_options;
        btsr->itr.reference = intel_bts_reference;
-       btsr->itr.read_finish = intel_bts_read_finish;
+       btsr->itr.read_finish = auxtrace_record__read_finish;
        btsr->itr.alignment = sizeof(struct branch);
        return &btsr->itr;
 }
index 20df442..1643aed 100644 (file)
 #include <linux/zalloc.h>
 #include <cpuid.h>
 
-#include "../../util/session.h"
-#include "../../util/event.h"
-#include "../../util/evlist.h"
-#include "../../util/evsel.h"
-#include "../../util/evsel_config.h"
-#include "../../util/cpumap.h"
-#include "../../util/mmap.h"
+#include "../../../util/session.h"
+#include "../../../util/event.h"
+#include "../../../util/evlist.h"
+#include "../../../util/evsel.h"
+#include "../../../util/evsel_config.h"
+#include "../../../util/cpumap.h"
+#include "../../../util/mmap.h"
 #include <subcmd/parse-options.h>
-#include "../../util/parse-events.h"
-#include "../../util/pmu.h"
-#include "../../util/debug.h"
-#include "../../util/auxtrace.h"
-#include "../../util/record.h"
-#include "../../util/target.h"
-#include "../../util/tsc.h"
+#include "../../../util/parse-events.h"
+#include "../../../util/pmu.h"
+#include "../../../util/debug.h"
+#include "../../../util/auxtrace.h"
+#include "../../../util/record.h"
+#include "../../../util/target.h"
+#include "../../../util/tsc.h"
 #include <internal/lib.h> // page_size
-#include "../../util/intel-pt.h"
+#include "../../../util/intel-pt.h"
 
 #define KiB(x) ((x) * 1024)
 #define MiB(x) ((x) * 1024 * 1024)
@@ -1166,20 +1166,6 @@ static u64 intel_pt_reference(struct auxtrace_record *itr __maybe_unused)
        return rdtsc();
 }
 
-static int intel_pt_read_finish(struct auxtrace_record *itr, int idx)
-{
-       struct intel_pt_recording *ptr =
-                       container_of(itr, struct intel_pt_recording, itr);
-       struct evsel *evsel;
-
-       evlist__for_each_entry(ptr->evlist, evsel) {
-               if (evsel->core.attr.type == ptr->intel_pt_pmu->type)
-                       return perf_evlist__enable_event_idx(ptr->evlist, evsel,
-                                                            idx);
-       }
-       return -EINVAL;
-}
-
 struct auxtrace_record *intel_pt_recording_init(int *err)
 {
        struct perf_pmu *intel_pt_pmu = perf_pmu__find(INTEL_PT_PMU_NAME);
@@ -1200,6 +1186,7 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
        }
 
        ptr->intel_pt_pmu = intel_pt_pmu;
+       ptr->itr.pmu = intel_pt_pmu;
        ptr->itr.recording_options = intel_pt_recording_options;
        ptr->itr.info_priv_size = intel_pt_info_priv_size;
        ptr->itr.info_fill = intel_pt_info_fill;
@@ -1209,7 +1196,7 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
        ptr->itr.find_snapshot = intel_pt_find_snapshot;
        ptr->itr.parse_snapshot_options = intel_pt_parse_snapshot_options;
        ptr->itr.reference = intel_pt_reference;
-       ptr->itr.read_finish = intel_pt_read_finish;
+       ptr->itr.read_finish = auxtrace_record__read_finish;
        /*
         * Decoding starts at a PSB packet. Minimum PSB period is 2K so 4K
         * should give at least 1 PSB per sample.
index e17e080..31679c3 100644 (file)
@@ -5,9 +5,9 @@
 #include <stdlib.h>
 
 #include <internal/lib.h> // page_size
-#include "../../util/machine.h"
-#include "../../util/map.h"
-#include "../../util/symbol.h"
+#include "../../../util/machine.h"
+#include "../../../util/map.h"
+#include "../../../util/symbol.h"
 #include <linux/ctype.h>
 
 #include <symbol/kallsyms.h>
index c218b83..fca81b3 100644 (file)
@@ -5,10 +5,10 @@
 #include <linux/kernel.h>
 #include <linux/zalloc.h>
 
-#include "../../perf-sys.h"
-#include "../../util/perf_regs.h"
-#include "../../util/debug.h"
-#include "../../util/event.h"
+#include "../../../perf-sys.h"
+#include "../../../util/perf_regs.h"
+#include "../../../util/debug.h"
+#include "../../../util/event.h"
 
 const struct sample_reg sample_reg_masks[] = {
        SMPL_REG(AX, PERF_REG_X86_AX),
index e33ef5b..d48d608 100644 (file)
@@ -4,9 +4,9 @@
 #include <linux/stddef.h>
 #include <linux/perf_event.h>
 
-#include "../../util/intel-pt.h"
-#include "../../util/intel-bts.h"
-#include "../../util/pmu.h"
+#include "../../../util/intel-pt.h"
+#include "../../../util/intel-bts.h"
+#include "../../../util/pmu.h"
 
 struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
 {
index fddb3ce..4aa6de1 100644 (file)
@@ -2,6 +2,10 @@
 #ifndef BENCH_H
 #define BENCH_H
 
+#include <sys/time.h>
+
+extern struct timeval bench__start, bench__end, bench__runtime;
+
 /*
  * The madvise transparent hugepage constants were added in glibc
  * 2.13. For compatibility with older versions of glibc, define these
index bb617e5..cadc18d 100644 (file)
@@ -35,7 +35,6 @@
 
 static unsigned int nthreads = 0;
 static unsigned int nsecs    = 8;
-struct timeval start, end, runtime;
 static bool done, __verbose, randomize;
 
 /*
@@ -94,8 +93,8 @@ static void toggle_done(int sig __maybe_unused,
 {
        /* inform all threads that we're done for the day */
        done = true;
-       gettimeofday(&end, NULL);
-       timersub(&end, &start, &runtime);
+       gettimeofday(&bench__end, NULL);
+       timersub(&bench__end, &bench__start, &bench__runtime);
 }
 
 static void nest_epollfd(void)
@@ -313,6 +312,7 @@ int bench_epoll_ctl(int argc, const char **argv)
                exit(EXIT_FAILURE);
        }
 
+       memset(&act, 0, sizeof(act));
        sigfillset(&act.sa_mask);
        act.sa_sigaction = toggle_done;
        sigaction(SIGINT, &act, NULL);
@@ -361,7 +361,7 @@ int bench_epoll_ctl(int argc, const char **argv)
 
        threads_starting = nthreads;
 
-       gettimeofday(&start, NULL);
+       gettimeofday(&bench__start, NULL);
 
        do_threads(worker, cpu);
 
index 7af6944..f938c58 100644 (file)
@@ -90,7 +90,6 @@
 
 static unsigned int nthreads = 0;
 static unsigned int nsecs    = 8;
-struct timeval start, end, runtime;
 static bool wdone, done, __verbose, randomize, nonblocking;
 
 /*
@@ -276,8 +275,8 @@ static void toggle_done(int sig __maybe_unused,
 {
        /* inform all threads that we're done for the day */
        done = true;
-       gettimeofday(&end, NULL);
-       timersub(&end, &start, &runtime);
+       gettimeofday(&bench__end, NULL);
+       timersub(&bench__end, &bench__start, &bench__runtime);
 }
 
 static void print_summary(void)
@@ -287,7 +286,7 @@ static void print_summary(void)
 
        printf("\nAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
               avg, rel_stddev_stats(stddev, avg),
-              (int) runtime.tv_sec);
+              (int)bench__runtime.tv_sec);
 }
 
 static int do_threads(struct worker *worker, struct perf_cpu_map *cpu)
@@ -427,6 +426,7 @@ int bench_epoll_wait(int argc, const char **argv)
                exit(EXIT_FAILURE);
        }
 
+       memset(&act, 0, sizeof(act));
        sigfillset(&act.sa_mask);
        act.sa_sigaction = toggle_done;
        sigaction(SIGINT, &act, NULL);
@@ -479,7 +479,7 @@ int bench_epoll_wait(int argc, const char **argv)
 
        threads_starting = nthreads;
 
-       gettimeofday(&start, NULL);
+       gettimeofday(&bench__start, NULL);
 
        do_threads(worker, cpu);
 
@@ -519,7 +519,7 @@ int bench_epoll_wait(int argc, const char **argv)
                qsort(worker, nthreads, sizeof(struct worker), cmpworker);
 
        for (i = 0; i < nthreads; i++) {
-               unsigned long t = worker[i].ops/runtime.tv_sec;
+               unsigned long t = worker[i].ops / bench__runtime.tv_sec;
 
                update_stats(&throughput_stats, t);
 
index 8ba0c33..65eebe0 100644 (file)
@@ -37,7 +37,7 @@ static unsigned int nfutexes = 1024;
 static bool fshared = false, done = false, silent = false;
 static int futex_flag = 0;
 
-struct timeval start, end, runtime;
+struct timeval bench__start, bench__end, bench__runtime;
 static pthread_mutex_t thread_lock;
 static unsigned int threads_starting;
 static struct stats throughput_stats;
@@ -103,8 +103,8 @@ static void toggle_done(int sig __maybe_unused,
 {
        /* inform all threads that we're done for the day */
        done = true;
-       gettimeofday(&end, NULL);
-       timersub(&end, &start, &runtime);
+       gettimeofday(&bench__end, NULL);
+       timersub(&bench__end, &bench__start, &bench__runtime);
 }
 
 static void print_summary(void)
@@ -114,7 +114,7 @@ static void print_summary(void)
 
        printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
               !silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
-              (int) runtime.tv_sec);
+              (int)bench__runtime.tv_sec);
 }
 
 int bench_futex_hash(int argc, const char **argv)
@@ -137,6 +137,7 @@ int bench_futex_hash(int argc, const char **argv)
        if (!cpu)
                goto errmem;
 
+       memset(&act, 0, sizeof(act));
        sigfillset(&act.sa_mask);
        act.sa_sigaction = toggle_done;
        sigaction(SIGINT, &act, NULL);
@@ -161,7 +162,7 @@ int bench_futex_hash(int argc, const char **argv)
 
        threads_starting = nthreads;
        pthread_attr_init(&thread_attr);
-       gettimeofday(&start, NULL);
+       gettimeofday(&bench__start, NULL);
        for (i = 0; i < nthreads; i++) {
                worker[i].tid = i;
                worker[i].futex = calloc(nfutexes, sizeof(*worker[i].futex));
@@ -204,7 +205,7 @@ int bench_futex_hash(int argc, const char **argv)
        pthread_mutex_destroy(&thread_lock);
 
        for (i = 0; i < nthreads; i++) {
-               unsigned long t = worker[i].ops/runtime.tv_sec;
+               unsigned long t = worker[i].ops / bench__runtime.tv_sec;
                update_stats(&throughput_stats, t);
                if (!silent) {
                        if (nfutexes == 1)
index d0cae81..89fd8f3 100644 (file)
@@ -37,7 +37,6 @@ static bool silent = false, multi = false;
 static bool done = false, fshared = false;
 static unsigned int nthreads = 0;
 static int futex_flag = 0;
-struct timeval start, end, runtime;
 static pthread_mutex_t thread_lock;
 static unsigned int threads_starting;
 static struct stats throughput_stats;
@@ -64,7 +63,7 @@ static void print_summary(void)
 
        printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
               !silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
-              (int) runtime.tv_sec);
+              (int)bench__runtime.tv_sec);
 }
 
 static void toggle_done(int sig __maybe_unused,
@@ -73,8 +72,8 @@ static void toggle_done(int sig __maybe_unused,
 {
        /* inform all threads that we're done for the day */
        done = true;
-       gettimeofday(&end, NULL);
-       timersub(&end, &start, &runtime);
+       gettimeofday(&bench__end, NULL);
+       timersub(&bench__end, &bench__start, &bench__runtime);
 }
 
 static void *workerfn(void *arg)
@@ -161,6 +160,7 @@ int bench_futex_lock_pi(int argc, const char **argv)
        if (!cpu)
                err(EXIT_FAILURE, "calloc");
 
+       memset(&act, 0, sizeof(act));
        sigfillset(&act.sa_mask);
        act.sa_sigaction = toggle_done;
        sigaction(SIGINT, &act, NULL);
@@ -185,7 +185,7 @@ int bench_futex_lock_pi(int argc, const char **argv)
 
        threads_starting = nthreads;
        pthread_attr_init(&thread_attr);
-       gettimeofday(&start, NULL);
+       gettimeofday(&bench__start, NULL);
 
        create_threads(worker, thread_attr, cpu);
        pthread_attr_destroy(&thread_attr);
@@ -211,7 +211,7 @@ int bench_futex_lock_pi(int argc, const char **argv)
        pthread_mutex_destroy(&thread_lock);
 
        for (i = 0; i < nthreads; i++) {
-               unsigned long t = worker[i].ops/runtime.tv_sec;
+               unsigned long t = worker[i].ops / bench__runtime.tv_sec;
 
                update_stats(&throughput_stats, t);
                if (!silent)
index a00a689..7a15c2e 100644 (file)
@@ -128,6 +128,7 @@ int bench_futex_requeue(int argc, const char **argv)
        if (!cpu)
                err(EXIT_FAILURE, "cpu_map__new");
 
+       memset(&act, 0, sizeof(act));
        sigfillset(&act.sa_mask);
        act.sa_sigaction = toggle_done;
        sigaction(SIGINT, &act, NULL);
index a053cf2..cd2b81a 100644 (file)
@@ -234,6 +234,7 @@ int bench_futex_wake_parallel(int argc, const char **argv)
                exit(EXIT_FAILURE);
        }
 
+       memset(&act, 0, sizeof(act));
        sigfillset(&act.sa_mask);
        act.sa_sigaction = toggle_done;
        sigaction(SIGINT, &act, NULL);
index df81009..2dfcef3 100644 (file)
@@ -43,7 +43,7 @@ static bool done = false, silent = false, fshared = false;
 static pthread_mutex_t thread_lock;
 static pthread_cond_t thread_parent, thread_worker;
 static struct stats waketime_stats, wakeup_stats;
-static unsigned int ncpus, threads_starting, nthreads = 0;
+static unsigned int threads_starting, nthreads = 0;
 static int futex_flag = 0;
 
 static const struct option options[] = {
@@ -136,12 +136,13 @@ int bench_futex_wake(int argc, const char **argv)
        if (!cpu)
                err(EXIT_FAILURE, "calloc");
 
+       memset(&act, 0, sizeof(act));
        sigfillset(&act.sa_mask);
        act.sa_sigaction = toggle_done;
        sigaction(SIGINT, &act, NULL);
 
        if (!nthreads)
-               nthreads = ncpus;
+               nthreads = cpu->nr;
 
        worker = calloc(nthreads, sizeof(*worker));
        if (!worker)
index ff61795..6c0a041 100644 (file)
@@ -566,6 +566,8 @@ int cmd_annotate(int argc, const char **argv)
        if (ret < 0)
                return ret;
 
+       annotation_config__init(&annotate.opts);
+
        argc = parse_options(argc, argv, options, annotate_usage, 0);
        if (argc) {
                /*
@@ -605,8 +607,6 @@ int cmd_annotate(int argc, const char **argv)
        if (ret < 0)
                goto out_delete;
 
-       annotation_config__init();
-
        symbol_conf.try_vmlinux_path = true;
 
        ret = symbol__init(&annotate.session->header.env);
index f8b6ae5..5e697cd 100644 (file)
@@ -572,29 +572,12 @@ static void init_block_hist(struct block_hist *bh)
        bh->valid = true;
 }
 
-static int block_pair_cmp(struct hist_entry *a, struct hist_entry *b)
-{
-       struct block_info *bi_a = a->block_info;
-       struct block_info *bi_b = b->block_info;
-       int cmp;
-
-       if (!bi_a->sym || !bi_b->sym)
-               return -1;
-
-       cmp = strcmp(bi_a->sym->name, bi_b->sym->name);
-
-       if ((!cmp) && (bi_a->start == bi_b->start) && (bi_a->end == bi_b->end))
-               return 0;
-
-       return -1;
-}
-
 static struct hist_entry *get_block_pair(struct hist_entry *he,
                                         struct hists *hists_pair)
 {
        struct rb_root_cached *root = hists_pair->entries_in;
        struct rb_node *next = rb_first_cached(root);
-       int cmp;
+       int64_t cmp;
 
        while (next != NULL) {
                struct hist_entry *he_pair = rb_entry(next, struct hist_entry,
@@ -602,7 +585,7 @@ static struct hist_entry *get_block_pair(struct hist_entry *he,
 
                next = rb_next(&he_pair->rb_node_in);
 
-               cmp = block_pair_cmp(he_pair, he);
+               cmp = __block_info__cmp(he_pair, he);
                if (!cmp)
                        return he_pair;
        }
@@ -1312,7 +1295,8 @@ static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
        end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
                                he->ms.sym);
 
-       if ((start_line != SRCLINE_UNKNOWN) && (end_line != SRCLINE_UNKNOWN)) {
+       if ((strncmp(start_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) &&
+           (strncmp(end_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0)) {
                scnprintf(buf, sizeof(buf), "[%s -> %s] %4ld",
                          start_line, end_line, block_he->diff.cycles);
        } else {
index 26bc592..70548df 100644 (file)
@@ -449,7 +449,8 @@ static int perf_del_probe_events(struct strfilter *filter)
                ret = probe_file__del_strlist(kfd, klist);
                if (ret < 0)
                        goto error;
-       }
+       } else if (ret == -ENOMEM)
+               goto error;
 
        ret2 = probe_file__get_events(ufd, filter, ulist);
        if (ret2 == 0) {
@@ -459,7 +460,8 @@ static int perf_del_probe_events(struct strfilter *filter)
                ret2 = probe_file__del_strlist(ufd, ulist);
                if (ret2 < 0)
                        goto error;
-       }
+       } else if (ret2 == -ENOMEM)
+               goto error;
 
        if (ret == -ENOENT && ret2 == -ENOENT)
                pr_warning("\"%s\" does not hit any event.\n", str);
index 9483b3f..5f4045d 100644 (file)
@@ -104,6 +104,7 @@ struct report {
        bool                    symbol_ipc;
        bool                    total_cycles_mode;
        struct block_report     *block_reports;
+       int                     nr_block_reports;
 };
 
 static int report__config(const char *var, const char *value, void *cb)
@@ -185,24 +186,23 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter,
 {
        struct hist_entry *he = iter->he;
        struct report *rep = arg;
-       struct branch_info *bi;
+       struct branch_info *bi = he->branch_info;
        struct perf_sample *sample = iter->sample;
        struct evsel *evsel = iter->evsel;
        int err;
 
+       branch_type_count(&rep->brtype_stat, &bi->flags,
+                         bi->from.addr, bi->to.addr);
+
        if (!ui__has_annotation() && !rep->symbol_ipc)
                return 0;
 
-       bi = he->branch_info;
        err = addr_map_symbol__inc_samples(&bi->from, sample, evsel);
        if (err)
                goto out;
 
        err = addr_map_symbol__inc_samples(&bi->to, sample, evsel);
 
-       branch_type_count(&rep->brtype_stat, &bi->flags,
-                         bi->from.addr, bi->to.addr);
-
 out:
        return err;
 }
@@ -966,8 +966,19 @@ static int __cmd_report(struct report *rep)
        report__output_resort(rep);
 
        if (rep->total_cycles_mode) {
+               int block_hpps[6] = {
+                       PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT,
+                       PERF_HPP_REPORT__BLOCK_LBR_CYCLES,
+                       PERF_HPP_REPORT__BLOCK_CYCLES_PCT,
+                       PERF_HPP_REPORT__BLOCK_AVG_CYCLES,
+                       PERF_HPP_REPORT__BLOCK_RANGE,
+                       PERF_HPP_REPORT__BLOCK_DSO,
+               };
+
                rep->block_reports = block_info__create_report(session->evlist,
-                                                              rep->total_cycles);
+                                                              rep->total_cycles,
+                                                              block_hpps, 6,
+                                                              &rep->nr_block_reports);
                if (!rep->block_reports)
                        return -1;
        }
@@ -1507,7 +1518,7 @@ repeat:
                        symbol_conf.priv_size += sizeof(u32);
                        symbol_conf.sort_by_name = true;
                }
-               annotation_config__init();
+               annotation_config__init(&report.annotation_opts);
        }
 
        if (symbol__init(&session->header.env) < 0)
@@ -1551,8 +1562,11 @@ error:
                zfree(&report.ptime_range);
        }
 
-       if (report.block_reports)
-               zfree(&report.block_reports);
+       if (report.block_reports) {
+               block_info__free_report(report.block_reports,
+                                       report.nr_block_reports);
+               report.block_reports = NULL;
+       }
 
        zstd_fini(&(session->zstd_data));
        perf_session__delete(session);
index e2406b2..656b347 100644 (file)
@@ -735,6 +735,7 @@ static int perf_sample__fprintf_brstack(struct perf_sample *sample,
                                        struct perf_event_attr *attr, FILE *fp)
 {
        struct branch_stack *br = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        struct addr_location alf, alt;
        u64 i, from, to;
        int printed = 0;
@@ -743,8 +744,8 @@ static int perf_sample__fprintf_brstack(struct perf_sample *sample,
                return 0;
 
        for (i = 0; i < br->nr; i++) {
-               from = br->entries[i].from;
-               to   = br->entries[i].to;
+               from = entries[i].from;
+               to   = entries[i].to;
 
                if (PRINT_FIELD(DSO)) {
                        memset(&alf, 0, sizeof(alf));
@@ -768,10 +769,10 @@ static int perf_sample__fprintf_brstack(struct perf_sample *sample,
                }
 
                printed += fprintf(fp, "/%c/%c/%c/%d ",
-                       mispred_str( br->entries + i),
-                       br->entries[i].flags.in_tx? 'X' : '-',
-                       br->entries[i].flags.abort? 'A' : '-',
-                       br->entries[i].flags.cycles);
+                       mispred_str(entries + i),
+                       entries[i].flags.in_tx ? 'X' : '-',
+                       entries[i].flags.abort ? 'A' : '-',
+                       entries[i].flags.cycles);
        }
 
        return printed;
@@ -782,6 +783,7 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
                                           struct perf_event_attr *attr, FILE *fp)
 {
        struct branch_stack *br = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        struct addr_location alf, alt;
        u64 i, from, to;
        int printed = 0;
@@ -793,8 +795,8 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
 
                memset(&alf, 0, sizeof(alf));
                memset(&alt, 0, sizeof(alt));
-               from = br->entries[i].from;
-               to   = br->entries[i].to;
+               from = entries[i].from;
+               to   = entries[i].to;
 
                thread__find_symbol_fb(thread, sample->cpumode, from, &alf);
                thread__find_symbol_fb(thread, sample->cpumode, to, &alt);
@@ -813,10 +815,10 @@ static int perf_sample__fprintf_brstacksym(struct perf_sample *sample,
                        printed += fprintf(fp, ")");
                }
                printed += fprintf(fp, "/%c/%c/%c/%d ",
-                       mispred_str( br->entries + i),
-                       br->entries[i].flags.in_tx? 'X' : '-',
-                       br->entries[i].flags.abort? 'A' : '-',
-                       br->entries[i].flags.cycles);
+                       mispred_str(entries + i),
+                       entries[i].flags.in_tx ? 'X' : '-',
+                       entries[i].flags.abort ? 'A' : '-',
+                       entries[i].flags.cycles);
        }
 
        return printed;
@@ -827,6 +829,7 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
                                           struct perf_event_attr *attr, FILE *fp)
 {
        struct branch_stack *br = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        struct addr_location alf, alt;
        u64 i, from, to;
        int printed = 0;
@@ -838,8 +841,8 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
 
                memset(&alf, 0, sizeof(alf));
                memset(&alt, 0, sizeof(alt));
-               from = br->entries[i].from;
-               to   = br->entries[i].to;
+               from = entries[i].from;
+               to   = entries[i].to;
 
                if (thread__find_map_fb(thread, sample->cpumode, from, &alf) &&
                    !alf.map->dso->adjust_symbols)
@@ -862,10 +865,10 @@ static int perf_sample__fprintf_brstackoff(struct perf_sample *sample,
                        printed += fprintf(fp, ")");
                }
                printed += fprintf(fp, "/%c/%c/%c/%d ",
-                       mispred_str(br->entries + i),
-                       br->entries[i].flags.in_tx ? 'X' : '-',
-                       br->entries[i].flags.abort ? 'A' : '-',
-                       br->entries[i].flags.cycles);
+                       mispred_str(entries + i),
+                       entries[i].flags.in_tx ? 'X' : '-',
+                       entries[i].flags.abort ? 'A' : '-',
+                       entries[i].flags.cycles);
        }
 
        return printed;
@@ -1053,6 +1056,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
                                            struct machine *machine, FILE *fp)
 {
        struct branch_stack *br = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        u64 start, end;
        int i, insn, len, nr, ilen, printed = 0;
        struct perf_insn x;
@@ -1073,31 +1077,31 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
        printed += fprintf(fp, "%c", '\n');
 
        /* Handle first from jump, of which we don't know the entry. */
-       len = grab_bb(buffer, br->entries[nr-1].from,
-                       br->entries[nr-1].from,
+       len = grab_bb(buffer, entries[nr-1].from,
+                       entries[nr-1].from,
                        machine, thread, &x.is64bit, &x.cpumode, false);
        if (len > 0) {
-               printed += ip__fprintf_sym(br->entries[nr - 1].from, thread,
+               printed += ip__fprintf_sym(entries[nr - 1].from, thread,
                                           x.cpumode, x.cpu, &lastsym, attr, fp);
-               printed += ip__fprintf_jump(br->entries[nr - 1].from, &br->entries[nr - 1],
+               printed += ip__fprintf_jump(entries[nr - 1].from, &entries[nr - 1],
                                            &x, buffer, len, 0, fp, &total_cycles);
                if (PRINT_FIELD(SRCCODE))
-                       printed += print_srccode(thread, x.cpumode, br->entries[nr - 1].from);
+                       printed += print_srccode(thread, x.cpumode, entries[nr - 1].from);
        }
 
        /* Print all blocks */
        for (i = nr - 2; i >= 0; i--) {
-               if (br->entries[i].from || br->entries[i].to)
+               if (entries[i].from || entries[i].to)
                        pr_debug("%d: %" PRIx64 "-%" PRIx64 "\n", i,
-                                br->entries[i].from,
-                                br->entries[i].to);
-               start = br->entries[i + 1].to;
-               end   = br->entries[i].from;
+                                entries[i].from,
+                                entries[i].to);
+               start = entries[i + 1].to;
+               end   = entries[i].from;
 
                len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false);
                /* Patch up missing kernel transfers due to ring filters */
                if (len == -ENXIO && i > 0) {
-                       end = br->entries[--i].from;
+                       end = entries[--i].from;
                        pr_debug("\tpatching up to %" PRIx64 "-%" PRIx64 "\n", start, end);
                        len = grab_bb(buffer, start, end, machine, thread, &x.is64bit, &x.cpumode, false);
                }
@@ -1110,7 +1114,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
 
                        printed += ip__fprintf_sym(ip, thread, x.cpumode, x.cpu, &lastsym, attr, fp);
                        if (ip == end) {
-                               printed += ip__fprintf_jump(ip, &br->entries[i], &x, buffer + off, len - off, ++insn, fp,
+                               printed += ip__fprintf_jump(ip, &entries[i], &x, buffer + off, len - off, ++insn, fp,
                                                            &total_cycles);
                                if (PRINT_FIELD(SRCCODE))
                                        printed += print_srccode(thread, x.cpumode, ip);
@@ -1134,9 +1138,9 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
         * Hit the branch? In this case we are already done, and the target
         * has not been executed yet.
         */
-       if (br->entries[0].from == sample->ip)
+       if (entries[0].from == sample->ip)
                goto out;
-       if (br->entries[0].flags.abort)
+       if (entries[0].flags.abort)
                goto out;
 
        /*
@@ -1147,7 +1151,7 @@ static int perf_sample__fprintf_brstackinsn(struct perf_sample *sample,
         * between final branch and sample. When this happens just
         * continue walking after the last TO until we hit a branch.
         */
-       start = br->entries[0].to;
+       start = entries[0].to;
        end = sample->ip;
        if (end < start) {
                /* Missing jump. Scan 128 bytes for the next branch */
index a098c2e..ec053dc 100644 (file)
@@ -929,6 +929,10 @@ static struct option stat_options[] = {
        OPT_BOOLEAN_FLAG(0, "all-user", &stat_config.all_user,
                         "Configure all used events to run in user space.",
                         PARSE_OPT_EXCLUSIVE),
+       OPT_BOOLEAN(0, "percore-show-thread", &stat_config.percore_show_thread,
+                   "Use with 'percore' event qualifier to show the event "
+                   "counts of one hardware thread by sum up total hardware "
+                   "threads of same physical core"),
        OPT_END()
 };
 
index 8affcab..d2539b7 100644 (file)
@@ -143,7 +143,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
                return err;
        }
 
-       err = symbol__annotate(&he->ms, evsel, 0, &top->annotation_opts, NULL);
+       err = symbol__annotate(&he->ms, evsel, &top->annotation_opts, NULL);
        if (err == 0) {
                top->sym_filter_entry = he;
        } else {
@@ -684,7 +684,9 @@ repeat:
        delay_msecs = top->delay_secs * MSEC_PER_SEC;
        set_term_quiet_input(&save);
        /* trash return*/
-       getc(stdin);
+       clearerr(stdin);
+       if (poll(&stdin_poll, 1, 0) > 0)
+               getc(stdin);
 
        while (!done) {
                perf_top__print_sym_table(top);
@@ -1683,7 +1685,7 @@ int cmd_top(int argc, const char **argv)
        if (status < 0)
                goto out_delete_evlist;
 
-       annotation_config__init();
+       annotation_config__init(&top.annotation_opts);
 
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
        status = symbol__init(NULL);
index 607189a..6e61c4b 100644 (file)
@@ -3,7 +3,7 @@
 #ifndef _PERF_BPF_PID_FILTER_
 #define _PERF_BPF_PID_FILTER_
 
-#include <bpf/bpf.h>
+#include <bpf.h>
 
 #define pid_filter(name) pid_map(name, bool)
 
index 7ca6fa5..316af5b 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 
-#include <bpf/bpf.h>
+#include <bpf.h>
 
 struct bpf_map SEC("maps") __bpf_stdout__ = {
        .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
index d1a35b6..ca7877f 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: LGPL-2.1
 
-#include <bpf/bpf.h>
+#include <bpf.h>
 
 static int (*bpf_get_current_pid_tgid)(void) = (void *)BPF_FUNC_get_current_pid_tgid;
 
index 5e36bc2..c998e4f 100644 (file)
@@ -4,27 +4,27 @@
                "EventCode": "80",
                "EventName": "ECC_FUNCTION_COUNT",
                "BriefDescription": "ECC Function Count",
-               "PublicDescription": "Long ECC function Count"
+               "PublicDescription": "This counter counts the total number of the elliptic-curve cryptography (ECC) functions issued by the CPU."
        },
        {
                "Unit": "CPU-M-CF",
                "EventCode": "81",
                "EventName": "ECC_CYCLES_COUNT",
                "BriefDescription": "ECC Cycles Count",
-               "PublicDescription": "Long ECC Function cycles count"
+               "PublicDescription": "This counter counts the total number of CPU cycles when the ECC coprocessor is busy performing the elliptic-curve cryptography (ECC) functions issued by the CPU."
        },
        {
                "Unit": "CPU-M-CF",
                "EventCode": "82",
                "EventName": "ECC_BLOCKED_FUNCTION_COUNT",
                "BriefDescription": "Ecc Blocked Function Count",
-               "PublicDescription": "Long ECC blocked function count"
+               "PublicDescription": "This counter counts the total number of the elliptic-curve cryptography (ECC) functions that are issued by the CPU and are blocked because the ECC coprocessor is busy performing a function issued by another CPU."
        },
        {
                "Unit": "CPU-M-CF",
                "EventCode": "83",
                "EventName": "ECC_BLOCKED_CYCLES_COUNT",
                "BriefDescription": "ECC Blocked Cycles Count",
-               "PublicDescription": "Long ECC blocked cycles count"
+               "PublicDescription": "This counter counts the total number of CPU cycles blocked for the elliptic-curve cryptography (ECC) functions issued by the CPU because the ECC coprocessor is busy performing a function issued by another CPU."
        },
 ]
index 89e0707..2df2e23 100644 (file)
@@ -25,7 +25,7 @@
                "EventCode": "131",
                "EventName": "DTLB2_HPAGE_WRITES",
                "BriefDescription": "DTLB2 One-Megabyte Page Writes",
-               "PublicDescription": "A translation entry was written into the Combined Region and Segment Table Entry array in the Level-2 TLB for a one-megabyte page or a Last Host Translation was done"
+               "PublicDescription": "A translation entry was written into the Combined Region and Segment Table Entry array in the Level-2 TLB for a one-megabyte page"
        },
        {
                "Unit": "CPU-M-CF",
        },
        {
                "Unit": "CPU-M-CF",
+               "EventCode": "247",
+               "EventName": "DFLT_ACCESS",
+               "BriefDescription": "Cycles CPU spent obtaining access to Deflate unit",
+               "PublicDescription": "Cycles CPU spent obtaining access to Deflate unit"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "252",
+               "EventName": "DFLT_CYCLES",
+               "BriefDescription": "Cycles CPU is using Deflate unit",
+               "PublicDescription": "Cycles CPU is using Deflate unit"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "264",
+               "EventName": "DFLT_CC",
+               "BriefDescription": "Increments by one for every DEFLATE CONVERSION CALL instruction executed",
+               "PublicDescription": "Increments by one for every DEFLATE CONVERSION CALL instruction executed"
+       },
+       {
+               "Unit": "CPU-M-CF",
+               "EventCode": "265",
+               "EventName": "DFLT_CCERROR",
+               "BriefDescription": "Increments by one for every DEFLATE CONVERSION CALL instruction executed that ended in Condition Codes 0, 1 or 2",
+               "PublicDescription": "Increments by one for every DEFLATE CONVERSION CALL instruction executed that ended in Condition Codes 0, 1 or 2"
+       },
+       {
+               "Unit": "CPU-M-CF",
                "EventCode": "448",
                "EventName": "MT_DIAG_CYCLES_ONE_THR_ACTIVE",
                "BriefDescription": "Cycle count with one thread active",
index f946532..a728c6e 100644 (file)
         "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
         "MetricExpr": "( ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_PENDING + DTLB_STORE_MISSES.WALK_PENDING + EPT.WALK_PENDING ) / ( 2 * cycles )",
         "MetricGroup": "TLB",
-        "MetricName": "Page_Walks_Utilization"
+        "MetricName": "Page_Walks_Utilization",
+        "MetricConstraint": "NO_NMI_WATCHDOG"
     },
     {
         "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
index e7feb60..f97e831 100644 (file)
         "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
         "MetricExpr": "( ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_PENDING + DTLB_STORE_MISSES.WALK_PENDING + EPT.WALK_PENDING ) / ( 2 * cycles )",
         "MetricGroup": "TLB",
-        "MetricName": "Page_Walks_Utilization"
+        "MetricName": "Page_Walks_Utilization",
+        "MetricConstraint": "NO_NMI_WATCHDOG"
     },
     {
         "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
index 21d7a0c..35f5db1 100644 (file)
         "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
         "MetricExpr": "( ITLB_MISSES.WALK_PENDING + DTLB_LOAD_MISSES.WALK_PENDING + DTLB_STORE_MISSES.WALK_PENDING + EPT.WALK_PENDING ) / ( 2 * cycles )",
         "MetricGroup": "TLB",
-        "MetricName": "Page_Walks_Utilization"
+        "MetricName": "Page_Walks_Utilization",
+        "MetricConstraint": "NO_NMI_WATCHDOG"
     },
     {
         "BriefDescription": "Utilization of the core's Page Walker(s) serving STLB misses triggered by instruction/Load/Store accesses",
index 079c77b..3c4236a 100644 (file)
@@ -323,7 +323,7 @@ static int print_events_table_entry(void *data, char *name, char *event,
                                    char *pmu, char *unit, char *perpkg,
                                    char *metric_expr,
                                    char *metric_name, char *metric_group,
-                                   char *deprecated)
+                                   char *deprecated, char *metric_constraint)
 {
        struct perf_entry_data *pd = data;
        FILE *outfp = pd->outfp;
@@ -357,6 +357,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
                fprintf(outfp, "\t.metric_group = \"%s\",\n", metric_group);
        if (deprecated)
                fprintf(outfp, "\t.deprecated = \"%s\",\n", deprecated);
+       if (metric_constraint)
+               fprintf(outfp, "\t.metric_constraint = \"%s\",\n", metric_constraint);
        fprintf(outfp, "},\n");
 
        return 0;
@@ -375,6 +377,7 @@ struct event_struct {
        char *metric_name;
        char *metric_group;
        char *deprecated;
+       char *metric_constraint;
 };
 
 #define ADD_EVENT_FIELD(field) do { if (field) {               \
@@ -422,7 +425,7 @@ static int save_arch_std_events(void *data, char *name, char *event,
                                char *desc, char *long_desc, char *pmu,
                                char *unit, char *perpkg, char *metric_expr,
                                char *metric_name, char *metric_group,
-                               char *deprecated)
+                               char *deprecated, char *metric_constraint)
 {
        struct event_struct *es;
 
@@ -486,7 +489,7 @@ try_fixup(const char *fn, char *arch_std, char **event, char **desc,
          char **name, char **long_desc, char **pmu, char **filter,
          char **perpkg, char **unit, char **metric_expr, char **metric_name,
          char **metric_group, unsigned long long eventcode,
-         char **deprecated)
+         char **deprecated, char **metric_constraint)
 {
        /* try to find matching event from arch standard values */
        struct event_struct *es;
@@ -515,7 +518,7 @@ int json_events(const char *fn,
                      char *pmu, char *unit, char *perpkg,
                      char *metric_expr,
                      char *metric_name, char *metric_group,
-                     char *deprecated),
+                     char *deprecated, char *metric_constraint),
          void *data)
 {
        int err;
@@ -545,6 +548,7 @@ int json_events(const char *fn,
                char *metric_name = NULL;
                char *metric_group = NULL;
                char *deprecated = NULL;
+               char *metric_constraint = NULL;
                char *arch_std = NULL;
                unsigned long long eventcode = 0;
                struct msrmap *msr = NULL;
@@ -629,6 +633,8 @@ int json_events(const char *fn,
                                addfield(map, &metric_name, "", "", val);
                        } else if (json_streq(map, field, "MetricGroup")) {
                                addfield(map, &metric_group, "", "", val);
+                       } else if (json_streq(map, field, "MetricConstraint")) {
+                               addfield(map, &metric_constraint, "", "", val);
                        } else if (json_streq(map, field, "MetricExpr")) {
                                addfield(map, &metric_expr, "", "", val);
                                for (s = metric_expr; *s; s++)
@@ -670,13 +676,13 @@ int json_events(const char *fn,
                                        &long_desc, &pmu, &filter, &perpkg,
                                        &unit, &metric_expr, &metric_name,
                                        &metric_group, eventcode,
-                                       &deprecated);
+                                       &deprecated, &metric_constraint);
                        if (err)
                                goto free_strings;
                }
                err = func(data, name, real_event(name, event), desc, long_desc,
                           pmu, unit, perpkg, metric_expr, metric_name,
-                          metric_group, deprecated);
+                          metric_group, deprecated, metric_constraint);
 free_strings:
                free(event);
                free(desc);
@@ -691,6 +697,7 @@ free_strings:
                free(metric_expr);
                free(metric_name);
                free(metric_group);
+               free(metric_constraint);
                free(arch_std);
 
                if (err)
@@ -1082,10 +1089,9 @@ static int process_one_file(const char *fpath, const struct stat *sb,
  */
 int main(int argc, char *argv[])
 {
-       int rc;
+       int rc, ret = 0;
        int maxfds;
        char ldirname[PATH_MAX];
-
        const char *arch;
        const char *output_file;
        const char *start_dirname;
@@ -1156,7 +1162,8 @@ int main(int argc, char *argv[])
                /* Make build fail */
                fclose(eventsfp);
                free_arch_std_events();
-               return 1;
+               ret = 1;
+               goto out_free_mapfile;
        } else if (rc) {
                goto empty_map;
        }
@@ -1174,14 +1181,17 @@ int main(int argc, char *argv[])
                /* Make build fail */
                fclose(eventsfp);
                free_arch_std_events();
-               return 1;
+               ret = 1;
        }
 
-       return 0;
+
+       goto out_free_mapfile;
 
 empty_map:
        fclose(eventsfp);
        create_empty_mapping(output_file);
        free_arch_std_events();
-       return 0;
+out_free_mapfile:
+       free(mapfile);
+       return ret;
 }
index 5cda49a..2afc830 100644 (file)
@@ -8,7 +8,7 @@ int json_events(const char *fn,
                                char *pmu,
                                char *unit, char *perpkg, char *metric_expr,
                                char *metric_name, char *metric_group,
-                               char *deprecated),
+                               char *deprecated, char *metric_constraint),
                void *data);
 char *get_cpu_str(void);
 
index caeb577..53e76d5 100644 (file)
@@ -18,6 +18,7 @@ struct pmu_event {
        const char *metric_name;
        const char *metric_group;
        const char *deprecated;
+       const char *metric_constraint;
 };
 
 /*
index 4e7076c..d307ce8 100644 (file)
@@ -28,7 +28,7 @@ sub trace_end
 sub irq::softirq_entry
 {
        my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-           $common_pid, $common_comm,
+           $common_pid, $common_comm, $common_callchain,
            $vec) = @_;
 
        print_header($event_name, $common_cpu, $common_secs, $common_nsecs,
@@ -43,7 +43,7 @@ sub irq::softirq_entry
 sub kmem::kmalloc
 {
        my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-           $common_pid, $common_comm,
+           $common_pid, $common_comm, $common_callchain,
            $call_site, $ptr, $bytes_req, $bytes_alloc,
            $gfp_flags) = @_;
 
@@ -92,7 +92,7 @@ sub print_unhandled
 sub trace_unhandled
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm) = @_;
+       $common_pid, $common_comm, $common_callchain) = @_;
 
     $unhandled{$event_name}++;
 }
index 55e7ae4..05954a8 100644 (file)
@@ -18,7 +18,7 @@ my %failed_syscalls;
 sub raw_syscalls::sys_exit
 {
        my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-           $common_pid, $common_comm,
+           $common_pid, $common_comm, $common_callchain,
            $id, $ret) = @_;
 
        if ($ret < 0) {
index 168fa5e..92a750b 100644 (file)
@@ -28,7 +28,7 @@ my %writes;
 sub syscalls::sys_enter_read
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
+       $common_pid, $common_comm, $common_callchain, $nr, $fd, $buf, $count) = @_;
 
     if ($common_comm eq $for_comm) {
        $reads{$fd}{bytes_requested} += $count;
@@ -39,7 +39,7 @@ sub syscalls::sys_enter_read
 sub syscalls::sys_enter_write
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm, $nr, $fd, $buf, $count) = @_;
+       $common_pid, $common_comm, $common_callchain, $nr, $fd, $buf, $count) = @_;
 
     if ($common_comm eq $for_comm) {
        $writes{$fd}{bytes_written} += $count;
@@ -98,7 +98,7 @@ sub print_unhandled
 sub trace_unhandled
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm) = @_;
+       $common_pid, $common_comm, $common_callchain) = @_;
 
     $unhandled{$event_name}++;
 }
index 4956982..d789fe3 100644 (file)
@@ -24,7 +24,7 @@ my %writes;
 sub syscalls::sys_exit_read
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $nr, $ret) = @_;
 
     if ($ret > 0) {
@@ -40,7 +40,7 @@ sub syscalls::sys_exit_read
 sub syscalls::sys_enter_read
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $nr, $fd, $buf, $count) = @_;
 
     $reads{$common_pid}{bytes_requested} += $count;
@@ -51,7 +51,7 @@ sub syscalls::sys_enter_read
 sub syscalls::sys_exit_write
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $nr, $ret) = @_;
 
     if ($ret <= 0) {
@@ -62,7 +62,7 @@ sub syscalls::sys_exit_write
 sub syscalls::sys_enter_write
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $nr, $fd, $buf, $count) = @_;
 
     $writes{$common_pid}{bytes_written} += $count;
@@ -178,7 +178,7 @@ sub print_unhandled
 sub trace_unhandled
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm) = @_;
+       $common_pid, $common_comm, $common_callchain) = @_;
 
     $unhandled{$event_name}++;
 }
index 6473442..eba4df6 100644 (file)
@@ -35,7 +35,7 @@ if (!$interval) {
 sub syscalls::sys_exit_read
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $nr, $ret) = @_;
 
     print_check();
@@ -53,7 +53,7 @@ sub syscalls::sys_exit_read
 sub syscalls::sys_enter_read
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $nr, $fd, $buf, $count) = @_;
 
     print_check();
@@ -66,7 +66,7 @@ sub syscalls::sys_enter_read
 sub syscalls::sys_exit_write
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $nr, $ret) = @_;
 
     print_check();
@@ -79,7 +79,7 @@ sub syscalls::sys_exit_write
 sub syscalls::sys_enter_write
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $nr, $fd, $buf, $count) = @_;
 
     print_check();
@@ -197,7 +197,7 @@ sub print_unhandled
 sub trace_unhandled
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm) = @_;
+       $common_pid, $common_comm, $common_callchain) = @_;
 
     $unhandled{$event_name}++;
 }
index efcfec5..53444ff 100644 (file)
@@ -28,7 +28,7 @@ my $total_wakeups = 0;
 sub sched::sched_switch
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $prev_comm, $prev_pid, $prev_prio, $prev_state, $next_comm, $next_pid,
        $next_prio) = @_;
 
@@ -51,7 +51,7 @@ sub sched::sched_switch
 sub sched::sched_wakeup
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm,
+       $common_pid, $common_comm, $common_callchain,
        $comm, $pid, $prio, $success, $target_cpu) = @_;
 
     $last_wakeup{$target_cpu}{ts} = nsecs($common_secs, $common_nsecs);
@@ -101,7 +101,7 @@ sub print_unhandled
 sub trace_unhandled
 {
     my ($event_name, $context, $common_cpu, $common_secs, $common_nsecs,
-       $common_pid, $common_comm) = @_;
+       $common_pid, $common_comm, $common_callchain) = @_;
 
     $unhandled{$event_name}++;
 }
index d0b9353..489b506 100644 (file)
@@ -19,7 +19,7 @@
 #include "../perf-sys.h"
 #include "cloexec.h"
 
-volatile long the_var;
+static volatile long the_var;
 
 static noinline int test_function(void)
 {
index 5f05db7..54d9516 100644 (file)
@@ -543,8 +543,11 @@ static int run_shell_tests(int argc, const char *argv[], int i, int width)
                return -1;
 
        dir = opendir(st.dir);
-       if (!dir)
+       if (!dir) {
+               pr_err("failed to open shell test directory: %s\n",
+                       st.dir);
                return -1;
+       }
 
        for_each_shell_test(dir, st.dir, ent) {
                int curr = i++;
index 87843af..28313e5 100644 (file)
@@ -10,7 +10,7 @@ static int test(struct parse_ctx *ctx, const char *e, double val2)
 {
        double val;
 
-       if (expr__parse(&val, ctx, &e))
+       if (expr__parse(&val, ctx, e))
                TEST_ASSERT_VAL("parse test failed", 0);
        TEST_ASSERT_VAL("unexpected value", val == val2);
        return 0;
@@ -44,12 +44,12 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused)
                return ret;
 
        p = "FOO/0";
-       ret = expr__parse(&val, &ctx, &p);
-       TEST_ASSERT_VAL("division by zero", ret == 1);
+       ret = expr__parse(&val, &ctx, p);
+       TEST_ASSERT_VAL("division by zero", ret == -1);
 
        p = "BAR/";
-       ret = expr__parse(&val, &ctx, &p);
-       TEST_ASSERT_VAL("missing operand", ret == 1);
+       ret = expr__parse(&val, &ctx, p);
+       TEST_ASSERT_VAL("missing operand", ret == -1);
 
        TEST_ASSERT_VAL("find other",
                        expr__find_other("FOO + BAR + BAZ + BOZO", "FOO", &other, &num_other) == 0);
index 2762e11..14239e4 100644 (file)
@@ -99,6 +99,7 @@ static bool samples_same(const struct perf_sample *s1,
 
        if (type & PERF_SAMPLE_BRANCH_STACK) {
                COMP(branch_stack->nr);
+               COMP(branch_stack->hw_idx);
                for (i = 0; i < s1->branch_stack->nr; i++)
                        MCOMP(branch_stack->entries[i]);
        }
@@ -186,7 +187,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
                u64 data[64];
        } branch_stack = {
                /* 1 branch_entry */
-               .data = {1, 211, 212, 213},
+               .data = {1, -1ULL, 211, 212, 213},
        };
        u64 regs[64];
        const u64 raw_data[] = {0x123456780a0b0c0dULL, 0x1102030405060708ULL};
@@ -208,6 +209,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
                .transaction    = 112,
                .raw_data       = (void *)raw_data,
                .callchain      = &callchain.callchain,
+               .no_hw_idx      = false,
                .branch_stack   = &branch_stack.branch_stack,
                .user_regs      = {
                        .abi    = PERF_SAMPLE_REGS_ABI_64,
@@ -244,6 +246,9 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
        if (sample_type & PERF_SAMPLE_REGS_INTR)
                evsel.core.attr.sample_regs_intr = sample_regs;
 
+       if (sample_type & PERF_SAMPLE_BRANCH_STACK)
+               evsel.core.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
+
        for (i = 0; i < sizeof(regs); i++)
                *(i + (u8 *)regs) = i & 0xfe;
 
index 7cb99b4..c2cc42d 100644 (file)
@@ -14,7 +14,7 @@ add_probe_vfs_getname() {
        if [ $had_vfs_getname -eq 1 ] ; then
                line=$(perf probe -L getname_flags 2>&1 | egrep 'result.*=.*filename;' | sed -r 's/[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*/\1/')
                perf probe -q       "vfs_getname=getname_flags:${line} pathname=result->name:string" || \
-               perf probe $verbose "vfs_getname=getname_flags:${line} pathname=filename:string"
+               perf probe $verbose "vfs_getname=getname_flags:${line} pathname=filename:ustring"
        fi
 }
 
index badbddb..9023267 100644 (file)
@@ -754,10 +754,9 @@ static int annotate_browser__run(struct annotate_browser *browser,
                "?             Search string backwards\n");
                        continue;
                case 'r':
-                       {
-                               script_browse(NULL, NULL);
-                               continue;
-                       }
+                       script_browse(NULL, NULL);
+                       annotate_browser__show(&browser->b, title, help);
+                       continue;
                case 'k':
                        notes->options->show_linenr = !notes->options->show_linenr;
                        break;
@@ -834,13 +833,13 @@ show_sup_ins:
                        map_symbol__annotation_dump(ms, evsel, browser->opts);
                        continue;
                case 't':
-                       if (notes->options->show_total_period) {
-                               notes->options->show_total_period = false;
-                               notes->options->show_nr_samples = true;
-                       } else if (notes->options->show_nr_samples)
-                               notes->options->show_nr_samples = false;
+                       if (symbol_conf.show_total_period) {
+                               symbol_conf.show_total_period = false;
+                               symbol_conf.show_nr_samples = true;
+                       } else if (symbol_conf.show_nr_samples)
+                               symbol_conf.show_nr_samples = false;
                        else
-                               notes->options->show_total_period = true;
+                               symbol_conf.show_total_period = true;
                        annotation__update_column_widths(notes);
                        continue;
                case 'c':
index 22cc240..35f9641 100644 (file)
@@ -174,7 +174,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
        if (ms->map->dso->annotate_warned)
                return -1;
 
-       err = symbol__annotate(ms, evsel, 0, &annotation__default_options, NULL);
+       err = symbol__annotate(ms, evsel, &annotation__default_options, NULL);
        if (err) {
                char msg[BUFSIZ];
                symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
index 07da6c7..c0cf8df 100644 (file)
@@ -121,7 +121,9 @@ perf-y += mem-events.o
 perf-y += vsprintf.o
 perf-y += units.o
 perf-y += time-utils.o
+perf-y += expr-flex.o
 perf-y += expr-bison.o
+perf-y += expr.o
 perf-y += branch.o
 perf-y += mem2node.o
 
@@ -189,9 +191,13 @@ $(OUTPUT)util/parse-events-bison.c: util/parse-events.y
        $(call rule_mkdir)
        $(Q)$(call echo-cmd,bison)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $@ -p parse_events_
 
+$(OUTPUT)util/expr-flex.c: util/expr.l $(OUTPUT)util/expr-bison.c
+       $(call rule_mkdir)
+       $(Q)$(call echo-cmd,flex)$(FLEX) -o $@ --header-file=$(OUTPUT)util/expr-flex.h $(PARSER_DEBUG_FLEX) util/expr.l
+
 $(OUTPUT)util/expr-bison.c: util/expr.y
        $(call rule_mkdir)
-       $(Q)$(call echo-cmd,bison)$(BISON) -v util/expr.y -d $(PARSER_DEBUG_BISON) -o $@ -p expr__
+       $(Q)$(call echo-cmd,bison)$(BISON) -v util/expr.y -d $(PARSER_DEBUG_BISON) -o $@ -p expr_
 
 $(OUTPUT)util/pmu-flex.c: util/pmu.l $(OUTPUT)util/pmu-bison.c
        $(call rule_mkdir)
@@ -203,12 +209,14 @@ $(OUTPUT)util/pmu-bison.c: util/pmu.y
 
 CFLAGS_parse-events-flex.o  += -w
 CFLAGS_pmu-flex.o           += -w
+CFLAGS_expr-flex.o          += -w
 CFLAGS_parse-events-bison.o += -DYYENABLE_NLS=0 -w
 CFLAGS_pmu-bison.o          += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
 CFLAGS_expr-bison.o         += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
 
 $(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
 $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
+$(OUTPUT)util/expr.o: $(OUTPUT)util/expr-flex.c $(OUTPUT)util/expr-bison.c
 
 CFLAGS_bitmap.o        += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_find_bit.o      += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
@@ -216,6 +224,7 @@ CFLAGS_rbtree.o        += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ET
 CFLAGS_libstring.o     += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_hweight.o       += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
 CFLAGS_parse-events.o  += -Wno-redundant-decls
+CFLAGS_expr.o          += -Wno-redundant-decls
 CFLAGS_header.o        += -include $(OUTPUT)PERF-VERSION-FILE
 
 $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
index ca73fb7..f1ea0d6 100644 (file)
@@ -1143,93 +1143,70 @@ out:
 }
 
 struct annotate_args {
-       size_t                   privsize;
-       struct arch             *arch;
-       struct map_symbol        ms;
-       struct evsel    *evsel;
+       struct arch               *arch;
+       struct map_symbol         ms;
+       struct evsel              *evsel;
        struct annotation_options *options;
-       s64                      offset;
-       char                    *line;
-       int                      line_nr;
+       s64                       offset;
+       char                      *line;
+       int                       line_nr;
 };
 
-static void annotation_line__delete(struct annotation_line *al)
+static void annotation_line__init(struct annotation_line *al,
+                                 struct annotate_args *args,
+                                 int nr)
 {
-       void *ptr = (void *) al - al->privsize;
+       al->offset = args->offset;
+       al->line = strdup(args->line);
+       al->line_nr = args->line_nr;
+       al->data_nr = nr;
+}
 
+static void annotation_line__exit(struct annotation_line *al)
+{
        free_srcline(al->path);
        zfree(&al->line);
-       free(ptr);
 }
 
-/*
- * Allocating the annotation line data with following
- * structure:
- *
- *    --------------------------------------
- *    private space | struct annotation_line
- *    --------------------------------------
- *
- * Size of the private space is stored in 'struct annotation_line'.
- *
- */
-static struct annotation_line *
-annotation_line__new(struct annotate_args *args, size_t privsize)
+static size_t disasm_line_size(int nr)
 {
        struct annotation_line *al;
-       struct evsel *evsel = args->evsel;
-       size_t size = privsize + sizeof(*al);
-       int nr = 1;
-
-       if (perf_evsel__is_group_event(evsel))
-               nr = evsel->core.nr_members;
 
-       size += sizeof(al->data[0]) * nr;
-
-       al = zalloc(size);
-       if (al) {
-               al = (void *) al + privsize;
-               al->privsize   = privsize;
-               al->offset     = args->offset;
-               al->line       = strdup(args->line);
-               al->line_nr    = args->line_nr;
-               al->data_nr    = nr;
-       }
-
-       return al;
+       return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr));
 }
 
 /*
  * Allocating the disasm annotation line data with
  * following structure:
  *
- *    ------------------------------------------------------------
- *    privsize space | struct disasm_line | struct annotation_line
- *    ------------------------------------------------------------
+ *    -------------------------------------------
+ *    struct disasm_line | struct annotation_line
+ *    -------------------------------------------
  *
  * We have 'struct annotation_line' member as last member
  * of 'struct disasm_line' to have an easy access.
- *
  */
 static struct disasm_line *disasm_line__new(struct annotate_args *args)
 {
        struct disasm_line *dl = NULL;
-       struct annotation_line *al;
-       size_t privsize = args->privsize + offsetof(struct disasm_line, al);
+       int nr = 1;
 
-       al = annotation_line__new(args, privsize);
-       if (al != NULL) {
-               dl = disasm_line(al);
+       if (perf_evsel__is_group_event(args->evsel))
+               nr = args->evsel->core.nr_members;
 
-               if (dl->al.line == NULL)
-                       goto out_delete;
+       dl = zalloc(disasm_line_size(nr));
+       if (!dl)
+               return NULL;
 
-               if (args->offset != -1) {
-                       if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
-                               goto out_free_line;
+       annotation_line__init(&dl->al, args, nr);
+       if (dl->al.line == NULL)
+               goto out_delete;
 
-                       disasm_line__init_ins(dl, args->arch, &args->ms);
-               }
+       if (args->offset != -1) {
+               if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
+                       goto out_free_line;
+
+               disasm_line__init_ins(dl, args->arch, &args->ms);
        }
 
        return dl;
@@ -1248,7 +1225,8 @@ void disasm_line__free(struct disasm_line *dl)
        else
                ins__delete(&dl->ops);
        zfree(&dl->ins.name);
-       annotation_line__delete(&dl->al);
+       annotation_line__exit(&dl->al);
+       free(dl);
 }
 
 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name)
@@ -2149,13 +2127,12 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel)
        annotation__calc_percent(notes, evsel, symbol__size(sym));
 }
 
-int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, size_t privsize,
+int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
                     struct annotation_options *options, struct arch **parch)
 {
        struct symbol *sym = ms->sym;
        struct annotation *notes = symbol__annotation(sym);
        struct annotate_args args = {
-               .privsize       = privsize,
                .evsel          = evsel,
                .options        = options,
        };
@@ -2634,8 +2611,6 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym)
 
                if (++al->jump_sources > notes->max_jump_sources)
                        notes->max_jump_sources = al->jump_sources;
-
-               ++notes->nr_jumps;
        }
 }
 
@@ -2644,6 +2619,8 @@ void annotation__set_offsets(struct annotation *notes, s64 size)
        struct annotation_line *al;
 
        notes->max_line_len = 0;
+       notes->nr_entries = 0;
+       notes->nr_asm_entries = 0;
 
        list_for_each_entry(al, &notes->src->source, node) {
                size_t line_len = strlen(al->line);
@@ -2790,7 +2767,7 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
        struct symbol *sym = ms->sym;
        struct rb_root source_line = RB_ROOT;
 
-       if (symbol__annotate(ms, evsel, 0, opts, NULL) < 0)
+       if (symbol__annotate(ms, evsel, opts, NULL) < 0)
                return -1;
 
        symbol__calc_percent(sym, evsel);
@@ -2915,9 +2892,9 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
                        percent = annotation_data__percent(&al->data[i], percent_type);
 
                        obj__set_percent_color(obj, percent, current_entry);
-                       if (notes->options->show_total_period) {
+                       if (symbol_conf.show_total_period) {
                                obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
-                       } else if (notes->options->show_nr_samples) {
+                       } else if (symbol_conf.show_nr_samples) {
                                obj__printf(obj, "%6" PRIu64 " ",
                                                   al->data[i].he.nr_samples);
                        } else {
@@ -2931,8 +2908,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
                        obj__printf(obj, "%-*s", pcnt_width, " ");
                else {
                        obj__printf(obj, "%-*s", pcnt_width,
-                                          notes->options->show_total_period ? "Period" :
-                                          notes->options->show_nr_samples ? "Samples" : "Percent");
+                                          symbol_conf.show_total_period ? "Period" :
+                                          symbol_conf.show_nr_samples ? "Samples" : "Percent");
                }
        }
 
@@ -3070,7 +3047,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
        if (perf_evsel__is_group_event(evsel))
                nr_pcnt = evsel->core.nr_members;
 
-       err = symbol__annotate(ms, evsel, 0, options, parch);
+       err = symbol__annotate(ms, evsel, options, parch);
        if (err)
                goto out_free_offsets;
 
@@ -3094,69 +3071,46 @@ out_free_offsets:
        return err;
 }
 
-#define ANNOTATION__CFG(n) \
-       { .name = #n, .value = &annotation__default_options.n, }
-
-/*
- * Keep the entries sorted, they are bsearch'ed
- */
-static struct annotation_config {
-       const char *name;
-       void *value;
-} annotation__configs[] = {
-       ANNOTATION__CFG(hide_src_code),
-       ANNOTATION__CFG(jump_arrows),
-       ANNOTATION__CFG(offset_level),
-       ANNOTATION__CFG(show_linenr),
-       ANNOTATION__CFG(show_nr_jumps),
-       ANNOTATION__CFG(show_nr_samples),
-       ANNOTATION__CFG(show_total_period),
-       ANNOTATION__CFG(use_offset),
-};
-
-#undef ANNOTATION__CFG
-
-static int annotation_config__cmp(const void *name, const void *cfgp)
+static int annotation__config(const char *var, const char *value, void *data)
 {
-       const struct annotation_config *cfg = cfgp;
-
-       return strcmp(name, cfg->name);
-}
-
-static int annotation__config(const char *var, const char *value,
-                           void *data __maybe_unused)
-{
-       struct annotation_config *cfg;
-       const char *name;
+       struct annotation_options *opt = data;
 
        if (!strstarts(var, "annotate."))
                return 0;
 
-       name = var + 9;
-       cfg = bsearch(name, annotation__configs, ARRAY_SIZE(annotation__configs),
-                     sizeof(struct annotation_config), annotation_config__cmp);
-
-       if (cfg == NULL)
-               pr_debug("%s variable unknown, ignoring...", var);
-       else if (strcmp(var, "annotate.offset_level") == 0) {
-               perf_config_int(cfg->value, name, value);
-
-               if (*(int *)cfg->value > ANNOTATION__MAX_OFFSET_LEVEL)
-                       *(int *)cfg->value = ANNOTATION__MAX_OFFSET_LEVEL;
-               else if (*(int *)cfg->value < ANNOTATION__MIN_OFFSET_LEVEL)
-                       *(int *)cfg->value = ANNOTATION__MIN_OFFSET_LEVEL;
+       if (!strcmp(var, "annotate.offset_level")) {
+               perf_config_u8(&opt->offset_level, "offset_level", value);
+
+               if (opt->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
+                       opt->offset_level = ANNOTATION__MAX_OFFSET_LEVEL;
+               else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL)
+                       opt->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
+       } else if (!strcmp(var, "annotate.hide_src_code")) {
+               opt->hide_src_code = perf_config_bool("hide_src_code", value);
+       } else if (!strcmp(var, "annotate.jump_arrows")) {
+               opt->jump_arrows = perf_config_bool("jump_arrows", value);
+       } else if (!strcmp(var, "annotate.show_linenr")) {
+               opt->show_linenr = perf_config_bool("show_linenr", value);
+       } else if (!strcmp(var, "annotate.show_nr_jumps")) {
+               opt->show_nr_jumps = perf_config_bool("show_nr_jumps", value);
+       } else if (!strcmp(var, "annotate.show_nr_samples")) {
+               symbol_conf.show_nr_samples = perf_config_bool("show_nr_samples",
+                                                               value);
+       } else if (!strcmp(var, "annotate.show_total_period")) {
+               symbol_conf.show_total_period = perf_config_bool("show_total_period",
+                                                               value);
+       } else if (!strcmp(var, "annotate.use_offset")) {
+               opt->use_offset = perf_config_bool("use_offset", value);
        } else {
-               *(bool *)cfg->value = perf_config_bool(name, value);
+               pr_debug("%s variable unknown, ignoring...", var);
        }
+
        return 0;
 }
 
-void annotation_config__init(void)
+void annotation_config__init(struct annotation_options *opt)
 {
-       perf_config(annotation__config, NULL);
-
-       annotation__default_options.show_total_period = symbol_conf.show_total_period;
-       annotation__default_options.show_nr_samples   = symbol_conf.show_nr_samples;
+       perf_config(annotation__config, opt);
 }
 
 static unsigned int parse_percent_type(char *str1, char *str2)
index 455403e..07c7759 100644 (file)
@@ -83,8 +83,6 @@ struct annotation_options {
             full_path,
             show_linenr,
             show_nr_jumps,
-            show_nr_samples,
-            show_total_period,
             show_minmax_cycle,
             show_asm_raw,
             annotate_src;
@@ -141,7 +139,6 @@ struct annotation_line {
        u64                      cycles;
        u64                      cycles_max;
        u64                      cycles_min;
-       size_t                   privsize;
        char                    *path;
        u32                      idx;
        int                      idx_asm;
@@ -282,7 +279,6 @@ struct annotation {
        struct annotation_options *options;
        struct annotation_line  **offsets;
        int                     nr_events;
-       int                     nr_jumps;
        int                     max_jump_sources;
        int                     nr_entries;
        int                     nr_asm_entries;
@@ -309,7 +305,7 @@ static inline int annotation__cycles_width(struct annotation *notes)
 
 static inline int annotation__pcnt_width(struct annotation *notes)
 {
-       return (notes->options->show_total_period ? 12 : 7) * notes->nr_events;
+       return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events;
 }
 
 static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
@@ -352,7 +348,7 @@ struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists);
 void symbol__annotate_zero_histograms(struct symbol *sym);
 
 int symbol__annotate(struct map_symbol *ms,
-                    struct evsel *evsel, size_t privsize,
+                    struct evsel *evsel,
                     struct annotation_options *options,
                     struct arch **parch);
 int symbol__annotate2(struct map_symbol *ms,
@@ -413,7 +409,7 @@ static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
 }
 #endif
 
-void annotation_config__init(void);
+void annotation_config__init(struct annotation_options *opt);
 
 int annotate_parse_percent_type(const struct option *opt, const char *_str,
                                int unset);
index eb087e7..3571ce7 100644 (file)
@@ -629,8 +629,10 @@ int auxtrace_record__options(struct auxtrace_record *itr,
                             struct evlist *evlist,
                             struct record_opts *opts)
 {
-       if (itr)
+       if (itr) {
+               itr->evlist = evlist;
                return itr->recording_options(itr, evlist, opts);
+       }
        return 0;
 }
 
@@ -664,6 +666,24 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
        return -EINVAL;
 }
 
+int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx)
+{
+       struct evsel *evsel;
+
+       if (!itr->evlist || !itr->pmu)
+               return -EINVAL;
+
+       evlist__for_each_entry(itr->evlist, evsel) {
+               if (evsel->core.attr.type == itr->pmu->type) {
+                       if (evsel->disabled)
+                               return 0;
+                       return perf_evlist__enable_event_idx(itr->evlist, evsel,
+                                                            idx);
+               }
+       }
+       return -EINVAL;
+}
+
 /*
  * Event record size is 16-bit which results in a maximum size of about 64KiB.
  * Allow about 4KiB for the rest of the sample record, to give a maximum
index 749d72c..e58ef16 100644 (file)
@@ -29,6 +29,7 @@ struct record_opts;
 struct perf_record_auxtrace_error;
 struct perf_record_auxtrace_info;
 struct events_stats;
+struct perf_pmu;
 
 enum auxtrace_error_type {
        PERF_AUXTRACE_ERROR_ITRACE  = 1,
@@ -322,6 +323,8 @@ struct auxtrace_mmap_params {
  * @read_finish: called after reading from an auxtrace mmap
  * @alignment: alignment (if any) for AUX area data
  * @default_aux_sample_size: default sample size for --aux sample option
+ * @pmu: associated pmu
+ * @evlist: selected events list
  */
 struct auxtrace_record {
        int (*recording_options)(struct auxtrace_record *itr,
@@ -346,6 +349,8 @@ struct auxtrace_record {
        int (*read_finish)(struct auxtrace_record *itr, int idx);
        unsigned int alignment;
        unsigned int default_aux_sample_size;
+       struct perf_pmu *pmu;
+       struct evlist *evlist;
 };
 
 /**
@@ -537,6 +542,7 @@ int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
                                   struct auxtrace_mmap *mm,
                                   unsigned char *data, u64 *head, u64 *old);
 u64 auxtrace_record__reference(struct auxtrace_record *itr);
+int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx);
 
 int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event,
                                   off_t file_offset);
index c4b030b..423ec69 100644 (file)
@@ -65,8 +65,7 @@ struct block_info *block_info__new(void)
        return bi;
 }
 
-int64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused,
-                       struct hist_entry *left, struct hist_entry *right)
+int64_t __block_info__cmp(struct hist_entry *left, struct hist_entry *right)
 {
        struct block_info *bi_l = left->block_info;
        struct block_info *bi_r = right->block_info;
@@ -74,30 +73,27 @@ int64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused,
 
        if (!bi_l->sym || !bi_r->sym) {
                if (!bi_l->sym && !bi_r->sym)
-                       return 0;
+                       return -1;
                else if (!bi_l->sym)
                        return -1;
                else
                        return 1;
        }
 
-       if (bi_l->sym == bi_r->sym) {
-               if (bi_l->start == bi_r->start) {
-                       if (bi_l->end == bi_r->end)
-                               return 0;
-                       else
-                               return (int64_t)(bi_r->end - bi_l->end);
-               } else
-                       return (int64_t)(bi_r->start - bi_l->start);
-       } else {
-               cmp = strcmp(bi_l->sym->name, bi_r->sym->name);
+       cmp = strcmp(bi_l->sym->name, bi_r->sym->name);
+       if (cmp)
                return cmp;
-       }
 
-       if (bi_l->sym->start != bi_r->sym->start)
-               return (int64_t)(bi_r->sym->start - bi_l->sym->start);
+       if (bi_l->start != bi_r->start)
+               return (int64_t)(bi_r->start - bi_l->start);
 
-       return (int64_t)(bi_r->sym->end - bi_l->sym->end);
+       return (int64_t)(bi_r->end - bi_l->end);
+}
+
+int64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused,
+                       struct hist_entry *left, struct hist_entry *right)
+{
+       return __block_info__cmp(left, right);
 }
 
 static void init_block_info(struct block_info *bi, struct symbol *sym,
@@ -185,6 +181,17 @@ static int block_column_width(struct perf_hpp_fmt *fmt,
        return block_fmt->width;
 }
 
+static int color_pct(struct perf_hpp *hpp, int width, double pct)
+{
+#ifdef HAVE_SLANG_SUPPORT
+       if (use_browser) {
+               return __hpp__slsmg_color_printf(hpp, "%*.2f%%",
+                                                width - 1, pct);
+       }
+#endif
+       return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, pct);
+}
+
 static int block_total_cycles_pct_entry(struct perf_hpp_fmt *fmt,
                                        struct perf_hpp *hpp,
                                        struct hist_entry *he)
@@ -192,14 +199,11 @@ static int block_total_cycles_pct_entry(struct perf_hpp_fmt *fmt,
        struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
        struct block_info *bi = he->block_info;
        double ratio = 0.0;
-       char buf[16];
 
        if (block_fmt->total_cycles)
                ratio = (double)bi->cycles / (double)block_fmt->total_cycles;
 
-       sprintf(buf, "%.2f%%", 100.0 * ratio);
-
-       return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, buf);
+       return color_pct(hpp, block_fmt->width, 100.0 * ratio);
 }
 
 static int64_t block_total_cycles_pct_sort(struct perf_hpp_fmt *fmt,
@@ -252,16 +256,13 @@ static int block_cycles_pct_entry(struct perf_hpp_fmt *fmt,
        struct block_info *bi = he->block_info;
        double ratio = 0.0;
        u64 avg;
-       char buf[16];
 
        if (block_fmt->block_cycles && bi->num_aggr) {
                avg = bi->cycles_aggr / bi->num_aggr;
                ratio = (double)avg / (double)block_fmt->block_cycles;
        }
 
-       sprintf(buf, "%.2f%%", 100.0 * ratio);
-
-       return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, buf);
+       return color_pct(hpp, block_fmt->width, 100.0 * ratio);
 }
 
 static int block_avg_cycles_entry(struct perf_hpp_fmt *fmt,
@@ -295,7 +296,8 @@ static int block_range_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
        end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
                                he->ms.sym);
 
-       if ((start_line != SRCLINE_UNKNOWN) && (end_line != SRCLINE_UNKNOWN)) {
+       if ((strncmp(start_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) &&
+           (strncmp(end_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0)) {
                scnprintf(buf, sizeof(buf), "[%s -> %s]",
                          start_line, end_line);
        } else {
@@ -348,7 +350,7 @@ static void hpp_register(struct block_fmt *block_fmt, int idx,
 
        switch (idx) {
        case PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT:
-               fmt->entry = block_total_cycles_pct_entry;
+               fmt->color = block_total_cycles_pct_entry;
                fmt->cmp = block_info__cmp;
                fmt->sort = block_total_cycles_pct_sort;
                break;
@@ -356,7 +358,7 @@ static void hpp_register(struct block_fmt *block_fmt, int idx,
                fmt->entry = block_cycles_lbr_entry;
                break;
        case PERF_HPP_REPORT__BLOCK_CYCLES_PCT:
-               fmt->entry = block_cycles_pct_entry;
+               fmt->color = block_cycles_pct_entry;
                break;
        case PERF_HPP_REPORT__BLOCK_AVG_CYCLES:
                fmt->entry = block_avg_cycles_entry;
@@ -376,33 +378,41 @@ static void hpp_register(struct block_fmt *block_fmt, int idx,
 }
 
 static void register_block_columns(struct perf_hpp_list *hpp_list,
-                                  struct block_fmt *block_fmts)
+                                  struct block_fmt *block_fmts,
+                                  int *block_hpps, int nr_hpps)
 {
-       for (int i = 0; i < PERF_HPP_REPORT__BLOCK_MAX_INDEX; i++)
-               hpp_register(&block_fmts[i], i, hpp_list);
+       for (int i = 0; i < nr_hpps; i++)
+               hpp_register(&block_fmts[i], block_hpps[i], hpp_list);
 }
 
-static void init_block_hist(struct block_hist *bh, struct block_fmt *block_fmts)
+static void init_block_hist(struct block_hist *bh, struct block_fmt *block_fmts,
+                           int *block_hpps, int nr_hpps)
 {
        __hists__init(&bh->block_hists, &bh->block_list);
        perf_hpp_list__init(&bh->block_list);
        bh->block_list.nr_header_lines = 1;
 
-       register_block_columns(&bh->block_list, block_fmts);
+       register_block_columns(&bh->block_list, block_fmts,
+                              block_hpps, nr_hpps);
 
-       perf_hpp_list__register_sort_field(&bh->block_list,
-               &block_fmts[PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT].fmt);
+       /* Sort by the first fmt */
+       perf_hpp_list__register_sort_field(&bh->block_list, &block_fmts[0].fmt);
 }
 
-static void process_block_report(struct hists *hists,
-                                struct block_report *block_report,
-                                u64 total_cycles)
+static int process_block_report(struct hists *hists,
+                               struct block_report *block_report,
+                               u64 total_cycles, int *block_hpps,
+                               int nr_hpps)
 {
        struct rb_node *next = rb_first_cached(&hists->entries);
        struct block_hist *bh = &block_report->hist;
        struct hist_entry *he;
 
-       init_block_hist(bh, block_report->fmts);
+       if (nr_hpps > PERF_HPP_REPORT__BLOCK_MAX_INDEX)
+               return -1;
+
+       block_report->nr_fmts = nr_hpps;
+       init_block_hist(bh, block_report->fmts, block_hpps, nr_hpps);
 
        while (next) {
                he = rb_entry(next, struct hist_entry, rb_node);
@@ -411,16 +421,19 @@ static void process_block_report(struct hists *hists,
                next = rb_next(&he->rb_node);
        }
 
-       for (int i = 0; i < PERF_HPP_REPORT__BLOCK_MAX_INDEX; i++) {
+       for (int i = 0; i < nr_hpps; i++) {
                block_report->fmts[i].total_cycles = total_cycles;
                block_report->fmts[i].block_cycles = block_report->cycles;
        }
 
        hists__output_resort(&bh->block_hists, NULL);
+       return 0;
 }
 
 struct block_report *block_info__create_report(struct evlist *evlist,
-                                              u64 total_cycles)
+                                              u64 total_cycles,
+                                              int *block_hpps, int nr_hpps,
+                                              int *nr_reps)
 {
        struct block_report *block_reports;
        int nr_hists = evlist->core.nr_entries, i = 0;
@@ -433,13 +446,23 @@ struct block_report *block_info__create_report(struct evlist *evlist,
        evlist__for_each_entry(evlist, pos) {
                struct hists *hists = evsel__hists(pos);
 
-               process_block_report(hists, &block_reports[i], total_cycles);
+               process_block_report(hists, &block_reports[i], total_cycles,
+                                    block_hpps, nr_hpps);
                i++;
        }
 
+       *nr_reps = nr_hists;
        return block_reports;
 }
 
+void block_info__free_report(struct block_report *reps, int nr_reps)
+{
+       for (int i = 0; i < nr_reps; i++)
+               hists__delete_entries(&reps[i].hist.block_hists);
+
+       free(reps);
+}
+
 int report__browse_block_hists(struct block_hist *bh, float min_percent,
                               struct evsel *evsel, struct perf_env *env,
                               struct annotation_options *annotation_opts)
@@ -451,13 +474,11 @@ int report__browse_block_hists(struct block_hist *bh, float min_percent,
                symbol_conf.report_individual_block = true;
                hists__fprintf(&bh->block_hists, true, 0, 0, min_percent,
                               stdout, true);
-               hists__delete_entries(&bh->block_hists);
                return 0;
        case 1:
                symbol_conf.report_individual_block = true;
                ret = block_hists_tui_browse(bh, evsel, min_percent,
                                             env, annotation_opts);
-               hists__delete_entries(&bh->block_hists);
                return ret;
        default:
                return -1;
index bef0d75..42e9dcc 100644 (file)
@@ -45,6 +45,7 @@ struct block_report {
        struct block_hist       hist;
        u64                     cycles;
        struct block_fmt        fmts[PERF_HPP_REPORT__BLOCK_MAX_INDEX];
+       int                     nr_fmts;
 };
 
 struct block_hist;
@@ -61,6 +62,8 @@ static inline void __block_info__zput(struct block_info **bi)
 
 #define block_info__zput(bi) __block_info__zput(&bi)
 
+int64_t __block_info__cmp(struct hist_entry *left, struct hist_entry *right);
+
 int64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused,
                        struct hist_entry *left, struct hist_entry *right);
 
@@ -68,7 +71,11 @@ int block_info__process_sym(struct hist_entry *he, struct block_hist *bh,
                            u64 *block_cycles_aggr, u64 total_cycles);
 
 struct block_report *block_info__create_report(struct evlist *evlist,
-                                              u64 total_cycles);
+                                              u64 total_cycles,
+                                              int *block_hpps, int nr_hpps,
+                                              int *nr_reps);
+
+void block_info__free_report(struct block_report *reps, int nr_reps);
 
 int report__browse_block_hists(struct block_hist *bh, float min_percent,
                               struct evsel *evsel, struct perf_env *env,
index 88e00d2..154a05c 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/stddef.h>
 #include <linux/perf_event.h>
 #include <linux/types.h>
+#include "event.h"
 
 struct branch_flags {
        u64 mispred:1;
@@ -39,9 +40,30 @@ struct branch_entry {
 
 struct branch_stack {
        u64                     nr;
+       u64                     hw_idx;
        struct branch_entry     entries[0];
 };
 
+/*
+ * The hw_idx is only available when PERF_SAMPLE_BRANCH_HW_INDEX is applied.
+ * Otherwise, the output format of a sample with branch stack is
+ * struct branch_stack {
+ *     u64                     nr;
+ *     struct branch_entry     entries[0];
+ * }
+ * Check whether the hw_idx is available,
+ * and return the corresponding pointer of entries[0].
+ */
+static inline struct branch_entry *perf_sample__branch_entries(struct perf_sample *sample)
+{
+       u64 *entry = (u64 *)sample->branch_stack;
+
+       entry++;
+       if (sample->no_hw_idx)
+               return (struct branch_entry *)entry;
+       return (struct branch_entry *)(++entry);
+}
+
 struct branch_type_stat {
        bool    branch_to;
        u64     counts[PERF_BR_MAX];
index 4881d4a..5bc9d3b 100644 (file)
@@ -3,75 +3,16 @@
 #include "evsel.h"
 #include "cgroup.h"
 #include "evlist.h"
-#include <linux/stringify.h>
 #include <linux/zalloc.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#include <api/fs/fs.h>
 
 int nr_cgroups;
 
-static int
-cgroupfs_find_mountpoint(char *buf, size_t maxlen)
-{
-       FILE *fp;
-       char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1];
-       char path_v1[PATH_MAX + 1], path_v2[PATH_MAX + 2], *path;
-       char *token, *saved_ptr = NULL;
-
-       fp = fopen("/proc/mounts", "r");
-       if (!fp)
-               return -1;
-
-       /*
-        * in order to handle split hierarchy, we need to scan /proc/mounts
-        * and inspect every cgroupfs mount point to find one that has
-        * perf_event subsystem
-        */
-       path_v1[0] = '\0';
-       path_v2[0] = '\0';
-
-       while (fscanf(fp, "%*s %"__stringify(PATH_MAX)"s %"__stringify(PATH_MAX)"s %"
-                               __stringify(PATH_MAX)"s %*d %*d\n",
-                               mountpoint, type, tokens) == 3) {
-
-               if (!path_v1[0] && !strcmp(type, "cgroup")) {
-
-                       token = strtok_r(tokens, ",", &saved_ptr);
-
-                       while (token != NULL) {
-                               if (!strcmp(token, "perf_event")) {
-                                       strcpy(path_v1, mountpoint);
-                                       break;
-                               }
-                               token = strtok_r(NULL, ",", &saved_ptr);
-                       }
-               }
-
-               if (!path_v2[0] && !strcmp(type, "cgroup2"))
-                       strcpy(path_v2, mountpoint);
-
-               if (path_v1[0] && path_v2[0])
-                       break;
-       }
-       fclose(fp);
-
-       if (path_v1[0])
-               path = path_v1;
-       else if (path_v2[0])
-               path = path_v2;
-       else
-               return -1;
-
-       if (strlen(path) < maxlen) {
-               strcpy(buf, path);
-               return 0;
-       }
-       return -1;
-}
-
 static int open_cgroup(const char *name)
 {
        char path[PATH_MAX + 1];
@@ -79,7 +20,7 @@ static int open_cgroup(const char *name)
        int fd;
 
 
-       if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1))
+       if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1, "perf_event"))
                return -1;
 
        scnprintf(path, PATH_MAX, "%s/%s", mnt, name);
index 0bc9c4d..ef38eba 100644 (file)
@@ -374,6 +374,18 @@ int perf_config_int(int *dest, const char *name, const char *value)
        return 0;
 }
 
+int perf_config_u8(u8 *dest, const char *name, const char *value)
+{
+       long ret = 0;
+
+       if (!perf_parse_long(value, &ret)) {
+               bad_config(name);
+               return -1;
+       }
+       *dest = ret;
+       return 0;
+}
+
 static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
 {
        int ret;
index bd0a589..c10b66d 100644 (file)
@@ -29,6 +29,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
 int perf_default_config(const char *, const char *, void *);
 int perf_config(config_fn_t fn, void *);
 int perf_config_int(int *dest, const char *, const char *);
+int perf_config_u8(u8 *dest, const char *name, const char *value);
 int perf_config_u64(u64 *dest, const char *, const char *);
 int perf_config_bool(const char *, const char *);
 int config_error_nonbool(const char *);
index 5471045..62d2f9b 100644 (file)
@@ -363,6 +363,23 @@ struct cs_etm_packet_queue
        return NULL;
 }
 
+static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
+                               struct cs_etm_traceid_queue *tidq)
+{
+       struct cs_etm_packet *tmp;
+
+       if (etm->sample_branches || etm->synth_opts.last_branch ||
+           etm->sample_instructions) {
+               /*
+                * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
+                * the next incoming packet.
+                */
+               tmp = tidq->packet;
+               tidq->packet = tidq->prev_packet;
+               tidq->prev_packet = tmp;
+       }
+}
+
 static void cs_etm__packet_dump(const char *pkt_string)
 {
        const char *color = PERF_COLOR_BLUE;
@@ -945,7 +962,7 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
        if (packet->isa == CS_ETM_ISA_T32) {
                u64 addr = packet->start_addr;
 
-               while (offset > 0) {
+               while (offset) {
                        addr += cs_etm__t32_instr_size(etmq,
                                                       trace_chan_id, addr);
                        offset--;
@@ -1134,10 +1151,8 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
 
        cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->packet, &sample);
 
-       if (etm->synth_opts.last_branch) {
-               cs_etm__copy_last_branch_rb(etmq, tidq);
+       if (etm->synth_opts.last_branch)
                sample.branch_stack = tidq->last_branch;
-       }
 
        if (etm->synth_opts.inject) {
                ret = cs_etm__inject_event(event, &sample,
@@ -1153,9 +1168,6 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
                        "CS ETM Trace: failed to deliver instruction event, error %d\n",
                        ret);
 
-       if (etm->synth_opts.last_branch)
-               cs_etm__reset_last_branch_rb(tidq);
-
        return ret;
 }
 
@@ -1172,6 +1184,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
        union perf_event *event = tidq->event_buf;
        struct dummy_branch_stack {
                u64                     nr;
+               u64                     hw_idx;
                struct branch_entry     entries;
        } dummy_bs;
        u64 ip;
@@ -1202,6 +1215,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
        if (etm->synth_opts.last_branch) {
                dummy_bs = (struct dummy_branch_stack){
                        .nr = 1,
+                       .hw_idx = -1ULL,
                        .entries = {
                                .from = sample.ip,
                                .to = sample.addr,
@@ -1340,12 +1354,14 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
                          struct cs_etm_traceid_queue *tidq)
 {
        struct cs_etm_auxtrace *etm = etmq->etm;
-       struct cs_etm_packet *tmp;
        int ret;
        u8 trace_chan_id = tidq->trace_chan_id;
-       u64 instrs_executed = tidq->packet->instr_count;
+       u64 instrs_prev;
+
+       /* Get instructions remainder from previous packet */
+       instrs_prev = tidq->period_instructions;
 
-       tidq->period_instructions += instrs_executed;
+       tidq->period_instructions += tidq->packet->instr_count;
 
        /*
         * Record a branch when the last instruction in
@@ -1363,26 +1379,80 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
                 * TODO: allow period to be defined in cycles and clock time
                 */
 
-               /* Get number of instructions executed after the sample point */
-               u64 instrs_over = tidq->period_instructions -
-                       etm->instructions_sample_period;
+               /*
+                * Below diagram demonstrates the instruction samples
+                * generation flows:
+                *
+                *    Instrs     Instrs       Instrs       Instrs
+                *   Sample(n)  Sample(n+1)  Sample(n+2)  Sample(n+3)
+                *    |            |            |            |
+                *    V            V            V            V
+                *   --------------------------------------------------
+                *            ^                                  ^
+                *            |                                  |
+                *         Period                             Period
+                *    instructions(Pi)                   instructions(Pi')
+                *
+                *            |                                  |
+                *            \---------------- -----------------/
+                *                             V
+                *                 tidq->packet->instr_count
+                *
+                * Instrs Sample(n...) are the synthesised samples occurring
+                * every etm->instructions_sample_period instructions - as
+                * defined on the perf command line.  Sample(n) is being the
+                * last sample before the current etm packet, n+1 to n+3
+                * samples are generated from the current etm packet.
+                *
+                * tidq->packet->instr_count represents the number of
+                * instructions in the current etm packet.
+                *
+                * Period instructions (Pi) contains the the number of
+                * instructions executed after the sample point(n) from the
+                * previous etm packet.  This will always be less than
+                * etm->instructions_sample_period.
+                *
+                * When generate new samples, it combines with two parts
+                * instructions, one is the tail of the old packet and another
+                * is the head of the new coming packet, to generate
+                * sample(n+1); sample(n+2) and sample(n+3) consume the
+                * instructions with sample period.  After sample(n+3), the rest
+                * instructions will be used by later packet and it is assigned
+                * to tidq->period_instructions for next round calculation.
+                */
 
                /*
-                * Calculate the address of the sampled instruction (-1 as
-                * sample is reported as though instruction has just been
-                * executed, but PC has not advanced to next instruction)
+                * Get the initial offset into the current packet instructions;
+                * entry conditions ensure that instrs_prev is less than
+                * etm->instructions_sample_period.
                 */
-               u64 offset = (instrs_executed - instrs_over - 1);
-               u64 addr = cs_etm__instr_addr(etmq, trace_chan_id,
-                                             tidq->packet, offset);
+               u64 offset = etm->instructions_sample_period - instrs_prev;
+               u64 addr;
 
-               ret = cs_etm__synth_instruction_sample(
-                       etmq, tidq, addr, etm->instructions_sample_period);
-               if (ret)
-                       return ret;
+               /* Prepare last branches for instruction sample */
+               if (etm->synth_opts.last_branch)
+                       cs_etm__copy_last_branch_rb(etmq, tidq);
 
-               /* Carry remaining instructions into next sample period */
-               tidq->period_instructions = instrs_over;
+               while (tidq->period_instructions >=
+                               etm->instructions_sample_period) {
+                       /*
+                        * Calculate the address of the sampled instruction (-1
+                        * as sample is reported as though instruction has just
+                        * been executed, but PC has not advanced to next
+                        * instruction)
+                        */
+                       addr = cs_etm__instr_addr(etmq, trace_chan_id,
+                                                 tidq->packet, offset - 1);
+                       ret = cs_etm__synth_instruction_sample(
+                               etmq, tidq, addr,
+                               etm->instructions_sample_period);
+                       if (ret)
+                               return ret;
+
+                       offset += etm->instructions_sample_period;
+                       tidq->period_instructions -=
+                               etm->instructions_sample_period;
+               }
        }
 
        if (etm->sample_branches) {
@@ -1404,15 +1474,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
                }
        }
 
-       if (etm->sample_branches || etm->synth_opts.last_branch) {
-               /*
-                * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
-                * the next incoming packet.
-                */
-               tmp = tidq->packet;
-               tidq->packet = tidq->prev_packet;
-               tidq->prev_packet = tmp;
-       }
+       cs_etm__packet_swap(etm, tidq);
 
        return 0;
 }
@@ -1441,7 +1503,6 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
 {
        int err = 0;
        struct cs_etm_auxtrace *etm = etmq->etm;
-       struct cs_etm_packet *tmp;
 
        /* Handle start tracing packet */
        if (tidq->prev_packet->sample_type == CS_ETM_EMPTY)
@@ -1449,6 +1510,11 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
 
        if (etmq->etm->synth_opts.last_branch &&
            tidq->prev_packet->sample_type == CS_ETM_RANGE) {
+               u64 addr;
+
+               /* Prepare last branches for instruction sample */
+               cs_etm__copy_last_branch_rb(etmq, tidq);
+
                /*
                 * Generate a last branch event for the branches left in the
                 * circular buffer at the end of the trace.
@@ -1456,7 +1522,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
                 * Use the address of the end of the last reported execution
                 * range
                 */
-               u64 addr = cs_etm__last_executed_instr(tidq->prev_packet);
+               addr = cs_etm__last_executed_instr(tidq->prev_packet);
 
                err = cs_etm__synth_instruction_sample(
                        etmq, tidq, addr,
@@ -1476,15 +1542,11 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
        }
 
 swap_packet:
-       if (etm->sample_branches || etm->synth_opts.last_branch) {
-               /*
-                * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
-                * the next incoming packet.
-                */
-               tmp = tidq->packet;
-               tidq->packet = tidq->prev_packet;
-               tidq->prev_packet = tmp;
-       }
+       cs_etm__packet_swap(etm, tidq);
+
+       /* Reset last branches after flush the trace */
+       if (etm->synth_opts.last_branch)
+               cs_etm__reset_last_branch_rb(tidq);
 
        return err;
 }
@@ -1505,11 +1567,16 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
         */
        if (etmq->etm->synth_opts.last_branch &&
            tidq->prev_packet->sample_type == CS_ETM_RANGE) {
+               u64 addr;
+
+               /* Prepare last branches for instruction sample */
+               cs_etm__copy_last_branch_rb(etmq, tidq);
+
                /*
                 * Use the address of the end of the last reported execution
                 * range.
                 */
-               u64 addr = cs_etm__last_executed_instr(tidq->prev_packet);
+               addr = cs_etm__last_executed_instr(tidq->prev_packet);
 
                err = cs_etm__synth_instruction_sample(
                        etmq, tidq, addr,
index 6242a92..4154f94 100644 (file)
@@ -343,11 +343,11 @@ static const char *normalize_arch(char *arch)
 
 const char *perf_env__arch(struct perf_env *env)
 {
-       struct utsname uts;
        char *arch_name;
 
        if (!env || !env->arch) { /* Assume local operation */
-               if (uname(&uts) < 0)
+               static struct utsname uts = { .machine[0] = '\0', };
+               if (uts.machine[0] == '\0' && uname(&uts) < 0)
                        return NULL;
                arch_name = uts.machine;
        } else
index 8522315..3cda40a 100644 (file)
@@ -139,6 +139,7 @@ struct perf_sample {
        u16 insn_len;
        u8  cpumode;
        u16 misc;
+       bool no_hw_idx;         /* No hw_idx collected in branch_stack */
        char insn[MAX_INSN];
        void *raw_data;
        struct ip_callchain *callchain;
index c8dc445..816d930 100644 (file)
@@ -712,7 +712,8 @@ static void __perf_evsel__config_callchain(struct evsel *evsel,
                                attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER |
                                                        PERF_SAMPLE_BRANCH_CALL_STACK |
                                                        PERF_SAMPLE_BRANCH_NO_CYCLES |
-                                                       PERF_SAMPLE_BRANCH_NO_FLAGS;
+                                                       PERF_SAMPLE_BRANCH_NO_FLAGS |
+                                                       PERF_SAMPLE_BRANCH_HW_INDEX;
                        }
                } else
                         pr_warning("Cannot use LBR callstack with branch stack. "
@@ -763,7 +764,8 @@ perf_evsel__reset_callgraph(struct evsel *evsel,
        if (param->record_mode == CALLCHAIN_LBR) {
                perf_evsel__reset_sample_bit(evsel, BRANCH_STACK);
                attr->branch_sample_type &= ~(PERF_SAMPLE_BRANCH_USER |
-                                             PERF_SAMPLE_BRANCH_CALL_STACK);
+                                             PERF_SAMPLE_BRANCH_CALL_STACK |
+                                             PERF_SAMPLE_BRANCH_HW_INDEX);
        }
        if (param->record_mode == CALLCHAIN_DWARF) {
                perf_evsel__reset_sample_bit(evsel, REGS_USER);
@@ -1673,6 +1675,8 @@ fallback_missing_features:
                evsel->core.attr.ksymbol = 0;
        if (perf_missing_features.bpf)
                evsel->core.attr.bpf_event = 0;
+       if (perf_missing_features.branch_hw_idx)
+               evsel->core.attr.branch_sample_type &= ~PERF_SAMPLE_BRANCH_HW_INDEX;
 retry_sample_id:
        if (perf_missing_features.sample_id_all)
                evsel->core.attr.sample_id_all = 0;
@@ -1784,7 +1788,12 @@ try_fallback:
         * Must probe features in the order they were added to the
         * perf_event_attr interface.
         */
-       if (!perf_missing_features.aux_output && evsel->core.attr.aux_output) {
+       if (!perf_missing_features.branch_hw_idx &&
+           (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX)) {
+               perf_missing_features.branch_hw_idx = true;
+               pr_debug2("switching off branch HW index support\n");
+               goto fallback_missing_features;
+       } else if (!perf_missing_features.aux_output && evsel->core.attr.aux_output) {
                perf_missing_features.aux_output = true;
                pr_debug2_peo("Kernel has no attr.aux_output support, bailing out\n");
                goto out_close;
@@ -2169,7 +2178,12 @@ int perf_evsel__parse_sample(struct evsel *evsel, union perf_event *event,
 
                if (data->branch_stack->nr > max_branch_nr)
                        return -EFAULT;
+
                sz = data->branch_stack->nr * sizeof(struct branch_entry);
+               if (perf_evsel__has_branch_hw_idx(evsel))
+                       sz += sizeof(u64);
+               else
+                       data->no_hw_idx = true;
                OVERFLOW_CHECK(array, sz, max_size);
                array = (void *)array + sz;
        }
index dc14f4a..3380474 100644 (file)
@@ -119,6 +119,7 @@ struct perf_missing_features {
        bool ksymbol;
        bool bpf;
        bool aux_output;
+       bool branch_hw_idx;
 };
 
 extern struct perf_missing_features perf_missing_features;
@@ -389,6 +390,11 @@ static inline bool perf_evsel__has_branch_callstack(const struct evsel *evsel)
        return evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK;
 }
 
+static inline bool perf_evsel__has_branch_hw_idx(const struct evsel *evsel)
+{
+       return evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX;
+}
+
 static inline bool evsel__has_callchain(const struct evsel *evsel)
 {
        return (evsel->core.attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0;
diff --git a/tools/perf/util/expr.c b/tools/perf/util/expr.c
new file mode 100644 (file)
index 0000000..fd192dd
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdbool.h>
+#include <assert.h>
+#include "expr.h"
+#include "expr-bison.h"
+#define YY_EXTRA_TYPE int
+#include "expr-flex.h"
+
+#ifdef PARSER_DEBUG
+extern int expr_debug;
+#endif
+
+/* Caller must make sure id is allocated */
+void expr__add_id(struct parse_ctx *ctx, const char *name, double val)
+{
+       int idx;
+
+       assert(ctx->num_ids < MAX_PARSE_ID);
+       idx = ctx->num_ids++;
+       ctx->ids[idx].name = name;
+       ctx->ids[idx].val = val;
+}
+
+void expr__ctx_init(struct parse_ctx *ctx)
+{
+       ctx->num_ids = 0;
+}
+
+static int
+__expr__parse(double *val, struct parse_ctx *ctx, const char *expr,
+             int start)
+{
+       YY_BUFFER_STATE buffer;
+       void *scanner;
+       int ret;
+
+       ret = expr_lex_init_extra(start, &scanner);
+       if (ret)
+               return ret;
+
+       buffer = expr__scan_string(expr, scanner);
+
+#ifdef PARSER_DEBUG
+       expr_debug = 1;
+#endif
+
+       ret = expr_parse(val, ctx, scanner);
+
+       expr__flush_buffer(buffer, scanner);
+       expr__delete_buffer(buffer, scanner);
+       expr_lex_destroy(scanner);
+       return ret;
+}
+
+int expr__parse(double *final_val, struct parse_ctx *ctx, const char *expr)
+{
+       return __expr__parse(final_val, ctx, expr, EXPR_PARSE) ? -1 : 0;
+}
+
+static bool
+already_seen(const char *val, const char *one, const char **other,
+            int num_other)
+{
+       int i;
+
+       if (one && !strcasecmp(one, val))
+               return true;
+       for (i = 0; i < num_other; i++)
+               if (!strcasecmp(other[i], val))
+                       return true;
+       return false;
+}
+
+int expr__find_other(const char *expr, const char *one, const char ***other,
+                    int *num_other)
+{
+       int err, i = 0, j = 0;
+       struct parse_ctx ctx;
+
+       expr__ctx_init(&ctx);
+       err = __expr__parse(NULL, &ctx, expr, EXPR_OTHER);
+       if (err)
+               return -1;
+
+       *other = malloc((ctx.num_ids + 1) * sizeof(char *));
+       if (!*other)
+               return -ENOMEM;
+
+       for (i = 0, j = 0; i < ctx.num_ids; i++) {
+               const char *str = ctx.ids[i].name;
+
+               if (already_seen(str, one, *other, j))
+                       continue;
+
+               str = strdup(str);
+               if (!str)
+                       goto out;
+               (*other)[j++] = str;
+       }
+       (*other)[j] = NULL;
+
+out:
+       if (i != ctx.num_ids) {
+               while (--j)
+                       free((char *) (*other)[i]);
+               free(*other);
+               err = -1;
+       }
+
+       *num_other = j;
+       return err;
+}
index 0461608..9377538 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef PARSE_CTX_H
 #define PARSE_CTX_H 1
 
-#define EXPR_MAX_OTHER 15
+#define EXPR_MAX_OTHER 20
 #define MAX_PARSE_ID EXPR_MAX_OTHER
 
 struct parse_id {
@@ -17,10 +17,8 @@ struct parse_ctx {
 
 void expr__ctx_init(struct parse_ctx *ctx);
 void expr__add_id(struct parse_ctx *ctx, const char *id, double val);
-#ifndef IN_EXPR_Y
-int expr__parse(double *final_val, struct parse_ctx *ctx, const char **pp);
-#endif
-int expr__find_other(const char *p, const char *one, const char ***other,
+int expr__parse(double *final_val, struct parse_ctx *ctx, const char *expr);
+int expr__find_other(const char *expr, const char *one, const char ***other,
                int *num_other);
 
 #endif
diff --git a/tools/perf/util/expr.l b/tools/perf/util/expr.l
new file mode 100644 (file)
index 0000000..eaad292
--- /dev/null
@@ -0,0 +1,114 @@
+%option prefix="expr_"
+%option reentrant
+%option bison-bridge
+
+%{
+#include <linux/compiler.h>
+#include "expr.h"
+#include "expr-bison.h"
+
+char *expr_get_text(yyscan_t yyscanner);
+YYSTYPE *expr_get_lval(yyscan_t yyscanner);
+
+static int __value(YYSTYPE *yylval, char *str, int base, int token)
+{
+       u64 num;
+
+       errno = 0;
+       num = strtoull(str, NULL, base);
+       if (errno)
+               return EXPR_ERROR;
+
+       yylval->num = num;
+       return token;
+}
+
+static int value(yyscan_t scanner, int base)
+{
+       YYSTYPE *yylval = expr_get_lval(scanner);
+       char *text = expr_get_text(scanner);
+
+       return __value(yylval, text, base, NUMBER);
+}
+
+/*
+ * Allow @ instead of / to be able to specify pmu/event/ without
+ * conflicts with normal division.
+ */
+static char *normalize(char *str)
+{
+       char *ret = str;
+       char *dst = str;
+
+       while (*str) {
+               if (*str == '@')
+                       *dst++ = '/';
+               else if (*str == '\\')
+                       *dst++ = *++str;
+               else
+                       *dst++ = *str;
+               str++;
+       }
+
+       *dst = 0x0;
+       return ret;
+}
+
+static int str(yyscan_t scanner, int token)
+{
+       YYSTYPE *yylval = expr_get_lval(scanner);
+       char *text = expr_get_text(scanner);
+
+       yylval->str = normalize(strdup(text));
+       if (!yylval->str)
+               return EXPR_ERROR;
+
+       yylval->str = normalize(yylval->str);
+       return token;
+}
+%}
+
+number         [0-9]+
+
+sch            [-,=]
+spec           \\{sch}
+sym            [0-9a-zA-Z_\.:@]+
+symbol         {spec}*{sym}*{spec}*{sym}*
+
+%%
+       {
+               int start_token;
+
+               start_token = expr_get_extra(yyscanner);
+
+               if (start_token) {
+                       expr_set_extra(NULL, yyscanner);
+                       return start_token;
+               }
+       }
+
+max            { return MAX; }
+min            { return MIN; }
+if             { return IF; }
+else           { return ELSE; }
+#smt_on                { return SMT_ON; }
+{number}       { return value(yyscanner, 10); }
+{symbol}       { return str(yyscanner, ID); }
+"|"            { return '|'; }
+"^"            { return '^'; }
+"&"            { return '&'; }
+"-"            { return '-'; }
+"+"            { return '+'; }
+"*"            { return '*'; }
+"/"            { return '/'; }
+"%"            { return '%'; }
+"("            { return '('; }
+")"            { return ')'; }
+","            { return ','; }
+.              { }
+%%
+
+int expr_wrap(void *scanner __maybe_unused)
+{
+       return 1;
+}
index 7d22624..4720cbe 100644 (file)
@@ -1,31 +1,32 @@
 /* Simple expression parser */
 %{
+#define YYDEBUG 1
+#include <stdio.h>
 #include "util.h"
 #include "util/debug.h"
 #include <stdlib.h> // strtod()
 #define IN_EXPR_Y 1
 #include "expr.h"
 #include "smt.h"
-#include <assert.h>
 #include <string.h>
 
-#define MAXIDLEN 256
 %}
 
 %define api.pure full
 
 %parse-param { double *final_val }
 %parse-param { struct parse_ctx *ctx }
-%parse-param { const char **pp }
-%lex-param { const char **pp }
+%parse-param {void *scanner}
+%lex-param {void* scanner}
 
 %union {
-       double num;
-       char id[MAXIDLEN+1];
+       double   num;
+       char    *str;
 }
 
+%token EXPR_PARSE EXPR_OTHER EXPR_ERROR
 %token <num> NUMBER
-%token <id> ID
+%token <str> ID
 %token MIN MAX IF ELSE SMT_ON
 %left MIN MAX IF
 %left '|'
 %type <num> expr if_expr
 
 %{
-static int expr__lex(YYSTYPE *res, const char **pp);
-
-static void expr__error(double *final_val __maybe_unused,
+static void expr_error(double *final_val __maybe_unused,
                       struct parse_ctx *ctx __maybe_unused,
-                      const char **pp __maybe_unused,
+                      void *scanner,
                       const char *s)
 {
        pr_debug("%s\n", s);
@@ -63,6 +62,27 @@ static int lookup_id(struct parse_ctx *ctx, char *id, double *val)
 %}
 %%
 
+start:
+EXPR_PARSE all_expr
+|
+EXPR_OTHER all_other
+
+all_other: all_other other
+|
+
+other: ID
+{
+       if (ctx->num_ids + 1 >= EXPR_MAX_OTHER) {
+               pr_err("failed: way too many variables");
+               YYABORT;
+       }
+
+       ctx->ids[ctx->num_ids++].name = $1;
+}
+|
+MIN | MAX | IF | ELSE | SMT_ON | NUMBER | '|' | '^' | '&' | '-' | '+' | '*' | '/' | '%' | '(' | ')'
+
+
 all_expr: if_expr                      { *final_val = $1; }
        ;
 
@@ -93,146 +113,3 @@ expr:        NUMBER
        ;
 
 %%
-
-static int expr__symbol(YYSTYPE *res, const char *p, const char **pp)
-{
-       char *dst = res->id;
-       const char *s = p;
-
-       if (*p == '#')
-               *dst++ = *p++;
-
-       while (isalnum(*p) || *p == '_' || *p == '.' || *p == ':' || *p == '@' || *p == '\\') {
-               if (p - s >= MAXIDLEN)
-                       return -1;
-               /*
-                * Allow @ instead of / to be able to specify pmu/event/ without
-                * conflicts with normal division.
-                */
-               if (*p == '@')
-                       *dst++ = '/';
-               else if (*p == '\\')
-                       *dst++ = *++p;
-               else
-                       *dst++ = *p;
-               p++;
-       }
-       *dst = 0;
-       *pp = p;
-       dst = res->id;
-       switch (dst[0]) {
-       case 'm':
-               if (!strcmp(dst, "min"))
-                       return MIN;
-               if (!strcmp(dst, "max"))
-                       return MAX;
-               break;
-       case 'i':
-               if (!strcmp(dst, "if"))
-                       return IF;
-               break;
-       case 'e':
-               if (!strcmp(dst, "else"))
-                       return ELSE;
-               break;
-       case '#':
-               if (!strcasecmp(dst, "#smt_on"))
-                       return SMT_ON;
-               break;
-       }
-       return ID;
-}
-
-static int expr__lex(YYSTYPE *res, const char **pp)
-{
-       int tok;
-       const char *s;
-       const char *p = *pp;
-
-       while (isspace(*p))
-               p++;
-       s = p;
-       switch (*p++) {
-       case '#':
-       case 'a' ... 'z':
-       case 'A' ... 'Z':
-               return expr__symbol(res, p - 1, pp);
-       case '0' ... '9': case '.':
-               res->num = strtod(s, (char **)&p);
-               tok = NUMBER;
-               break;
-       default:
-               tok = *s;
-               break;
-       }
-       *pp = p;
-       return tok;
-}
-
-/* Caller must make sure id is allocated */
-void expr__add_id(struct parse_ctx *ctx, const char *name, double val)
-{
-       int idx;
-       assert(ctx->num_ids < MAX_PARSE_ID);
-       idx = ctx->num_ids++;
-       ctx->ids[idx].name = name;
-       ctx->ids[idx].val = val;
-}
-
-void expr__ctx_init(struct parse_ctx *ctx)
-{
-       ctx->num_ids = 0;
-}
-
-static bool already_seen(const char *val, const char *one, const char **other,
-                        int num_other)
-{
-       int i;
-
-       if (one && !strcasecmp(one, val))
-               return true;
-       for (i = 0; i < num_other; i++)
-               if (!strcasecmp(other[i], val))
-                       return true;
-       return false;
-}
-
-int expr__find_other(const char *p, const char *one, const char ***other,
-                    int *num_otherp)
-{
-       const char *orig = p;
-       int err = -1;
-       int num_other;
-
-       *other = malloc((EXPR_MAX_OTHER + 1) * sizeof(char *));
-       if (!*other)
-               return -1;
-
-       num_other = 0;
-       for (;;) {
-               YYSTYPE val;
-               int tok = expr__lex(&val, &p);
-               if (tok == 0) {
-                       err = 0;
-                       break;
-               }
-               if (tok == ID && !already_seen(val.id, one, *other, num_other)) {
-                       if (num_other >= EXPR_MAX_OTHER - 1) {
-                               pr_debug("Too many extra events in %s\n", orig);
-                               break;
-                       }
-                       (*other)[num_other] = strdup(val.id);
-                       if (!(*other)[num_other])
-                               return -1;
-                       num_other++;
-               }
-       }
-       (*other)[num_other] = NULL;
-       *num_otherp = num_other;
-       if (err) {
-               *num_otherp = 0;
-               free(*other);
-               *other = NULL;
-       }
-       return err;
-}
index 4246e74..acbd046 100644 (file)
@@ -1590,6 +1590,40 @@ static void free_event_desc(struct evsel *events)
        free(events);
 }
 
+static bool perf_attr_check(struct perf_event_attr *attr)
+{
+       if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3) {
+               pr_warning("Reserved bits are set unexpectedly. "
+                          "Please update perf tool.\n");
+               return false;
+       }
+
+       if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) {
+               pr_warning("Unknown sample type (0x%llx) is detected. "
+                          "Please update perf tool.\n",
+                          attr->sample_type);
+               return false;
+       }
+
+       if (attr->read_format & ~(PERF_FORMAT_MAX-1)) {
+               pr_warning("Unknown read format (0x%llx) is detected. "
+                          "Please update perf tool.\n",
+                          attr->read_format);
+               return false;
+       }
+
+       if ((attr->sample_type & PERF_SAMPLE_BRANCH_STACK) &&
+           (attr->branch_sample_type & ~(PERF_SAMPLE_BRANCH_MAX-1))) {
+               pr_warning("Unknown branch sample type (0x%llx) is detected. "
+                          "Please update perf tool.\n",
+                          attr->branch_sample_type);
+
+               return false;
+       }
+
+       return true;
+}
+
 static struct evsel *read_event_desc(struct feat_fd *ff)
 {
        struct evsel *evsel, *events = NULL;
@@ -1634,6 +1668,9 @@ static struct evsel *read_event_desc(struct feat_fd *ff)
 
                memcpy(&evsel->core.attr, buf, msz);
 
+               if (!perf_attr_check(&evsel->core.attr))
+                       goto error;
+
                if (do_read_u32(ff, &nr))
                        goto error;
 
index ca5a8f4..e74a5ac 100644 (file)
@@ -2584,9 +2584,10 @@ void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
                          u64 *total_cycles)
 {
        struct branch_info *bi;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
 
        /* If we have branch cycles always annotate them. */
-       if (bs && bs->nr && bs->entries[0].flags.cycles) {
+       if (bs && bs->nr && entries[0].flags.cycles) {
                int i;
 
                bi = sample__resolve_bstack(sample, al);
index 33cf892..23c8289 100644 (file)
@@ -1295,6 +1295,7 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq)
        struct perf_sample sample = { .ip = 0, };
        struct dummy_branch_stack {
                u64                     nr;
+               u64                     hw_idx;
                struct branch_entry     entries;
        } dummy_bs;
 
@@ -1316,6 +1317,7 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq)
        if (pt->synth_opts.last_branch && sort__mode == SORT_MODE__BRANCH) {
                dummy_bs = (struct dummy_branch_stack){
                        .nr = 1,
+                       .hw_idx = -1ULL,
                        .entries = {
                                .from = sample.ip,
                                .to = sample.addr,
index b5af680..dbdffb6 100644 (file)
@@ -265,6 +265,8 @@ static int detect_kbuild_dir(char **kbuild_dir)
                        return -ENOMEM;
                return 0;
        }
+       pr_debug("%s: Couldn't find \"%s\", missing kernel-devel package?.\n",
+                __func__, autoconf_path);
        free(autoconf_path);
        return -ENOENT;
 }
index fb5c2cd..fd14f14 100644 (file)
@@ -2081,15 +2081,16 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
 {
        unsigned int i;
        const struct branch_stack *bs = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info));
 
        if (!bi)
                return NULL;
 
        for (i = 0; i < bs->nr; i++) {
-               ip__resolve_ams(al->thread, &bi[i].to, bs->entries[i].to);
-               ip__resolve_ams(al->thread, &bi[i].from, bs->entries[i].from);
-               bi[i].flags = bs->entries[i].flags;
+               ip__resolve_ams(al->thread, &bi[i].to, entries[i].to);
+               ip__resolve_ams(al->thread, &bi[i].from, entries[i].from);
+               bi[i].flags = entries[i].flags;
        }
        return bi;
 }
@@ -2185,6 +2186,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
        /* LBR only affects the user callchain */
        if (i != chain_nr) {
                struct branch_stack *lbr_stack = sample->branch_stack;
+               struct branch_entry *entries = perf_sample__branch_entries(sample);
                int lbr_nr = lbr_stack->nr, j, k;
                bool branch;
                struct branch_flags *flags;
@@ -2210,31 +2212,29 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
                                        ip = chain->ips[j];
                                else if (j > i + 1) {
                                        k = j - i - 2;
-                                       ip = lbr_stack->entries[k].from;
+                                       ip = entries[k].from;
                                        branch = true;
-                                       flags = &lbr_stack->entries[k].flags;
+                                       flags = &entries[k].flags;
                                } else {
-                                       ip = lbr_stack->entries[0].to;
+                                       ip = entries[0].to;
                                        branch = true;
-                                       flags = &lbr_stack->entries[0].flags;
-                                       branch_from =
-                                               lbr_stack->entries[0].from;
+                                       flags = &entries[0].flags;
+                                       branch_from = entries[0].from;
                                }
                        } else {
                                if (j < lbr_nr) {
                                        k = lbr_nr - j - 1;
-                                       ip = lbr_stack->entries[k].from;
+                                       ip = entries[k].from;
                                        branch = true;
-                                       flags = &lbr_stack->entries[k].flags;
+                                       flags = &entries[k].flags;
                                }
                                else if (j > lbr_nr)
                                        ip = chain->ips[i + 1 - (j - lbr_nr)];
                                else {
-                                       ip = lbr_stack->entries[0].to;
+                                       ip = entries[0].to;
                                        branch = true;
-                                       flags = &lbr_stack->entries[0].flags;
-                                       branch_from =
-                                               lbr_stack->entries[0].from;
+                                       flags = &entries[0].flags;
+                                       branch_from = entries[0].from;
                                }
                        }
 
@@ -2281,6 +2281,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
                                            int max_stack)
 {
        struct branch_stack *branch = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        struct ip_callchain *chain = sample->callchain;
        int chain_nr = 0;
        u8 cpumode = PERF_RECORD_MISC_USER;
@@ -2328,7 +2329,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
 
                for (i = 0; i < nr; i++) {
                        if (callchain_param.order == ORDER_CALLEE) {
-                               be[i] = branch->entries[i];
+                               be[i] = entries[i];
 
                                if (chain == NULL)
                                        continue;
@@ -2347,7 +2348,7 @@ static int thread__resolve_callchain_sample(struct thread *thread,
                                    be[i].from >= chain->ips[first_call] - 8)
                                        first_call++;
                        } else
-                               be[i] = branch->entries[branch->nr - i - 1];
+                               be[i] = entries[branch->nr - i - 1];
                }
 
                memset(iter, 0, sizeof(struct iterations) * nr);
index a08ca27..53d9661 100644 (file)
@@ -44,8 +44,8 @@ static inline int is_no_dso_memory(const char *filename)
 
 static inline int is_android_lib(const char *filename)
 {
-       return !strncmp(filename, "/data/app-lib", 13) ||
-              !strncmp(filename, "/system/lib", 11);
+       return strstarts(filename, "/data/app-lib/") ||
+              strstarts(filename, "/system/lib/");
 }
 
 static inline bool replace_android_lib(const char *filename, char *newfilename)
@@ -65,7 +65,7 @@ static inline bool replace_android_lib(const char *filename, char *newfilename)
 
        app_abi_length = strlen(app_abi);
 
-       if (!strncmp(filename, "/data/app-lib", 13)) {
+       if (strstarts(filename, "/data/app-lib/")) {
                char *apk_path;
 
                if (!app_abi_length)
@@ -89,7 +89,7 @@ static inline bool replace_android_lib(const char *filename, char *newfilename)
                return true;
        }
 
-       if (!strncmp(filename, "/system/lib/", 11)) {
+       if (strstarts(filename, "/system/lib/")) {
                char *ndk, *app;
                const char *arch;
                size_t ndk_length;
@@ -431,7 +431,7 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
 
        if (map && map->dso) {
                char *srcline = map__srcline(map, addr, NULL);
-               if (srcline != SRCLINE_UNKNOWN)
+               if (strncmp(srcline, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0)
                        ret = fprintf(fp, "%s%s", prefix, srcline);
                free_srcline(srcline);
        }
index 02aee94..c3a8c70 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/string.h>
 #include <linux/zalloc.h>
 #include <subcmd/parse-options.h>
+#include <api/fs/fs.h>
+#include "util.h"
 
 struct metric_event *metricgroup__lookup(struct rblist *metric_events,
                                         struct evsel *evsel,
@@ -399,13 +401,85 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
        strlist__delete(metriclist);
 }
 
+static void metricgroup__add_metric_weak_group(struct strbuf *events,
+                                              const char **ids,
+                                              int idnum)
+{
+       bool no_group = false;
+       int i;
+
+       for (i = 0; i < idnum; i++) {
+               pr_debug("found event %s\n", ids[i]);
+               /*
+                * Duration time maps to a software event and can make
+                * groups not count. Always use it outside a
+                * group.
+                */
+               if (!strcmp(ids[i], "duration_time")) {
+                       if (i > 0)
+                               strbuf_addf(events, "}:W,");
+                       strbuf_addf(events, "duration_time");
+                       no_group = true;
+                       continue;
+               }
+               strbuf_addf(events, "%s%s",
+                       i == 0 || no_group ? "{" : ",",
+                       ids[i]);
+               no_group = false;
+       }
+       if (!no_group)
+               strbuf_addf(events, "}:W");
+}
+
+static void metricgroup__add_metric_non_group(struct strbuf *events,
+                                             const char **ids,
+                                             int idnum)
+{
+       int i;
+
+       for (i = 0; i < idnum; i++)
+               strbuf_addf(events, ",%s", ids[i]);
+}
+
+static void metricgroup___watchdog_constraint_hint(const char *name, bool foot)
+{
+       static bool violate_nmi_constraint;
+
+       if (!foot) {
+               pr_warning("Splitting metric group %s into standalone metrics.\n", name);
+               violate_nmi_constraint = true;
+               return;
+       }
+
+       if (!violate_nmi_constraint)
+               return;
+
+       pr_warning("Try disabling the NMI watchdog to comply NO_NMI_WATCHDOG metric constraint:\n"
+                  "    echo 0 > /proc/sys/kernel/nmi_watchdog\n"
+                  "    perf stat ...\n"
+                  "    echo 1 > /proc/sys/kernel/nmi_watchdog\n");
+}
+
+static bool metricgroup__has_constraint(struct pmu_event *pe)
+{
+       if (!pe->metric_constraint)
+               return false;
+
+       if (!strcmp(pe->metric_constraint, "NO_NMI_WATCHDOG") &&
+           sysctl__nmi_watchdog_enabled()) {
+               metricgroup___watchdog_constraint_hint(pe->metric_name, false);
+               return true;
+       }
+
+       return false;
+}
+
 static int metricgroup__add_metric(const char *metric, struct strbuf *events,
                                   struct list_head *group_list)
 {
        struct pmu_events_map *map = perf_pmu__find_map(NULL);
        struct pmu_event *pe;
-       int ret = -EINVAL;
-       int i, j;
+       int i, ret = -EINVAL;
 
        if (!map)
                return 0;
@@ -422,7 +496,6 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events,
                        const char **ids;
                        int idnum;
                        struct egroup *eg;
-                       bool no_group = false;
 
                        pr_debug("metric expr %s for %s\n", pe->metric_expr, pe->metric_name);
 
@@ -431,27 +504,11 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events,
                                continue;
                        if (events->len > 0)
                                strbuf_addf(events, ",");
-                       for (j = 0; j < idnum; j++) {
-                               pr_debug("found event %s\n", ids[j]);
-                               /*
-                                * Duration time maps to a software event and can make
-                                * groups not count. Always use it outside a
-                                * group.
-                                */
-                               if (!strcmp(ids[j], "duration_time")) {
-                                       if (j > 0)
-                                               strbuf_addf(events, "}:W,");
-                                       strbuf_addf(events, "duration_time");
-                                       no_group = true;
-                                       continue;
-                               }
-                               strbuf_addf(events, "%s%s",
-                                       j == 0 || no_group ? "{" : ",",
-                                       ids[j]);
-                               no_group = false;
-                       }
-                       if (!no_group)
-                               strbuf_addf(events, "}:W");
+
+                       if (metricgroup__has_constraint(pe))
+                               metricgroup__add_metric_non_group(events, ids, idnum);
+                       else
+                               metricgroup__add_metric_weak_group(events, ids, idnum);
 
                        eg = malloc(sizeof(struct egroup));
                        if (!eg) {
@@ -493,6 +550,10 @@ static int metricgroup__add_metric_list(const char *list, struct strbuf *events,
                }
        }
        free(nlist);
+
+       if (!ret)
+               metricgroup___watchdog_constraint_hint(NULL, true);
+
        return ret;
 }
 
index 3b664fa..ab7108d 100644 (file)
@@ -98,20 +98,29 @@ static int perf_mmap__aio_bind(struct mmap *map, int idx, int cpu, int affinity)
 {
        void *data;
        size_t mmap_len;
-       unsigned long node_mask;
+       unsigned long *node_mask;
+       unsigned long node_index;
+       int err = 0;
 
        if (affinity != PERF_AFFINITY_SYS && cpu__max_node() > 1) {
                data = map->aio.data[idx];
                mmap_len = mmap__mmap_len(map);
-               node_mask = 1UL << cpu__get_node(cpu);
-               if (mbind(data, mmap_len, MPOL_BIND, &node_mask, 1, 0)) {
-                       pr_err("Failed to bind [%p-%p] AIO buffer to node %d: error %m\n",
-                               data, data + mmap_len, cpu__get_node(cpu));
+               node_index = cpu__get_node(cpu);
+               node_mask = bitmap_alloc(node_index + 1);
+               if (!node_mask) {
+                       pr_err("Failed to allocate node mask for mbind: error %m\n");
                        return -1;
                }
+               set_bit(node_index, node_mask);
+               if (mbind(data, mmap_len, MPOL_BIND, node_mask, node_index + 1 + 1, 0)) {
+                       pr_err("Failed to bind [%p-%p] AIO buffer to node %lu: error %m\n",
+                               data, data + mmap_len, node_index);
+                       err = -1;
+               }
+               bitmap_free(node_mask);
        }
 
-       return 0;
+       return err;
 }
 #else /* !HAVE_LIBNUMA_SUPPORT */
 static int perf_mmap__aio_alloc(struct mmap *map, int idx)
index c01ba6f..a7dc0b0 100644 (file)
@@ -257,21 +257,15 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
                                path = zalloc(sizeof(*path));
                                if (!path)
                                        return NULL;
-                               path->system = malloc(MAX_EVENT_LENGTH);
-                               if (!path->system) {
+                               if (asprintf(&path->system, "%.*s", MAX_EVENT_LENGTH, sys_dirent->d_name) < 0) {
                                        free(path);
                                        return NULL;
                                }
-                               path->name = malloc(MAX_EVENT_LENGTH);
-                               if (!path->name) {
+                               if (asprintf(&path->name, "%.*s", MAX_EVENT_LENGTH, evt_dirent->d_name) < 0) {
                                        zfree(&path->system);
                                        free(path);
                                        return NULL;
                                }
-                               strncpy(path->system, sys_dirent->d_name,
-                                       MAX_EVENT_LENGTH);
-                               strncpy(path->name, evt_dirent->d_name,
-                                       MAX_EVENT_LENGTH);
                                return path;
                        }
                }
@@ -1219,7 +1213,7 @@ static int config_attr(struct perf_event_attr *attr,
 static int get_config_terms(struct list_head *head_config,
                            struct list_head *head_terms __maybe_unused)
 {
-#define ADD_CONFIG_TERM(__type)                                        \
+#define ADD_CONFIG_TERM(__type, __weak)                                \
        struct perf_evsel_config_term *__t;                     \
                                                                \
        __t = zalloc(sizeof(*__t));                             \
@@ -1228,18 +1222,18 @@ static int get_config_terms(struct list_head *head_config,
                                                                \
        INIT_LIST_HEAD(&__t->list);                             \
        __t->type       = PERF_EVSEL__CONFIG_TERM_ ## __type;   \
-       __t->weak       = term->weak;                           \
+       __t->weak       = __weak;                               \
        list_add_tail(&__t->list, head_terms)
 
-#define ADD_CONFIG_TERM_VAL(__type, __name, __val)             \
+#define ADD_CONFIG_TERM_VAL(__type, __name, __val, __weak)     \
 do {                                                           \
-       ADD_CONFIG_TERM(__type);                                \
+       ADD_CONFIG_TERM(__type, __weak);                        \
        __t->val.__name = __val;                                \
 } while (0)
 
-#define ADD_CONFIG_TERM_STR(__type, __val)                     \
+#define ADD_CONFIG_TERM_STR(__type, __val, __weak)             \
 do {                                                           \
-       ADD_CONFIG_TERM(__type);                                \
+       ADD_CONFIG_TERM(__type, __weak);                        \
        __t->val.str = strdup(__val);                           \
        if (!__t->val.str) {                                    \
                zfree(&__t);                                    \
@@ -1253,62 +1247,62 @@ do {                                                            \
        list_for_each_entry(term, head_config, list) {
                switch (term->type_term) {
                case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
-                       ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num);
+                       ADD_CONFIG_TERM_VAL(PERIOD, period, term->val.num, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ:
-                       ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num);
+                       ADD_CONFIG_TERM_VAL(FREQ, freq, term->val.num, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_TIME:
-                       ADD_CONFIG_TERM_VAL(TIME, time, term->val.num);
+                       ADD_CONFIG_TERM_VAL(TIME, time, term->val.num, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
-                       ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str);
+                       ADD_CONFIG_TERM_STR(CALLGRAPH, term->val.str, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
-                       ADD_CONFIG_TERM_STR(BRANCH, term->val.str);
+                       ADD_CONFIG_TERM_STR(BRANCH, term->val.str, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
                        ADD_CONFIG_TERM_VAL(STACK_USER, stack_user,
-                                           term->val.num);
+                                           term->val.num, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_INHERIT:
                        ADD_CONFIG_TERM_VAL(INHERIT, inherit,
-                                           term->val.num ? 1 : 0);
+                                           term->val.num ? 1 : 0, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_NOINHERIT:
                        ADD_CONFIG_TERM_VAL(INHERIT, inherit,
-                                           term->val.num ? 0 : 1);
+                                           term->val.num ? 0 : 1, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_MAX_STACK:
                        ADD_CONFIG_TERM_VAL(MAX_STACK, max_stack,
-                                           term->val.num);
+                                           term->val.num, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS:
                        ADD_CONFIG_TERM_VAL(MAX_EVENTS, max_events,
-                                           term->val.num);
+                                           term->val.num, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_OVERWRITE:
                        ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
-                                           term->val.num ? 1 : 0);
+                                           term->val.num ? 1 : 0, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE:
                        ADD_CONFIG_TERM_VAL(OVERWRITE, overwrite,
-                                           term->val.num ? 0 : 1);
+                                           term->val.num ? 0 : 1, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_DRV_CFG:
-                       ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str);
+                       ADD_CONFIG_TERM_STR(DRV_CFG, term->val.str, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_PERCORE:
                        ADD_CONFIG_TERM_VAL(PERCORE, percore,
-                                           term->val.num ? true : false);
+                                           term->val.num ? true : false, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT:
                        ADD_CONFIG_TERM_VAL(AUX_OUTPUT, aux_output,
-                                           term->val.num ? 1 : 0);
+                                           term->val.num ? 1 : 0, term->weak);
                        break;
                case PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE:
                        ADD_CONFIG_TERM_VAL(AUX_SAMPLE_SIZE, aux_sample_size,
-                                           term->val.num);
+                                           term->val.num, term->weak);
                        break;
                default:
                        break;
@@ -1345,7 +1339,7 @@ static int get_config_chgs(struct perf_pmu *pmu, struct list_head *head_config,
        }
 
        if (bits)
-               ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits);
+               ADD_CONFIG_TERM_VAL(CFG_CHG, cfg_chg, bits, false);
 
 #undef ADD_CONFIG_TERM
        return 0;
index 6512031..355d345 100644 (file)
@@ -50,6 +50,7 @@ static void __p_branch_sample_type(char *buf, size_t size, u64 value)
                bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX),
                bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP),
                bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES),
+               bit_name(HW_INDEX),
                { .name = NULL, }
        };
 #undef bit_name
index 5003ba4..8c85294 100644 (file)
@@ -206,6 +206,9 @@ static struct strlist *__probe_file__get_namelist(int fd, bool include_group)
                } else
                        ret = strlist__add(sl, tev.event);
                clear_probe_trace_event(&tev);
+               /* Skip if there is same name multi-probe event in the list */
+               if (ret == -EEXIST)
+                       ret = 0;
                if (ret < 0)
                        break;
        }
@@ -301,10 +304,15 @@ int probe_file__get_events(int fd, struct strfilter *filter,
                p = strchr(ent->s, ':');
                if ((p && strfilter__compare(filter, p + 1)) ||
                    strfilter__compare(filter, ent->s)) {
-                       strlist__add(plist, ent->s);
+                       ret = strlist__add(plist, ent->s);
+                       if (ret == -ENOMEM) {
+                               pr_err("strlist__add failed with -ENOMEM\n");
+                               goto out;
+                       }
                        ret = 0;
                }
        }
+out:
        strlist__delete(namelist);
 
        return ret;
@@ -511,7 +519,11 @@ static int probe_cache__load(struct probe_cache *pcache)
                                ret = -EINVAL;
                                goto out;
                        }
-                       strlist__add(entry->tevlist, buf);
+                       ret = strlist__add(entry->tevlist, buf);
+                       if (ret == -ENOMEM) {
+                               pr_err("strlist__add failed with -ENOMEM\n");
+                               goto out;
+                       }
                }
        }
 out:
@@ -672,7 +684,12 @@ int probe_cache__add_entry(struct probe_cache *pcache,
                command = synthesize_probe_trace_command(&tevs[i]);
                if (!command)
                        goto out_err;
-               strlist__add(entry->tevlist, command);
+               ret = strlist__add(entry->tevlist, command);
+               if (ret == -ENOMEM) {
+                       pr_err("strlist__add failed with -ENOMEM\n");
+                       goto out_err;
+               }
+
                free(command);
        }
        list_add_tail(&entry->node, &pcache->entries);
@@ -853,9 +870,15 @@ int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
                        break;
                }
 
-               strlist__add(entry->tevlist, buf);
+               ret = strlist__add(entry->tevlist, buf);
+
                free(buf);
                entry = NULL;
+
+               if (ret == -ENOMEM) {
+                       pr_err("strlist__add failed with -ENOMEM\n");
+                       break;
+               }
        }
        if (entry) {
                list_del_init(&entry->node);
index 1c817ad..e4cff49 100644 (file)
@@ -637,14 +637,19 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
                return -EINVAL;
        }
 
-       /* Try to get actual symbol name from symtab */
-       symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+       if (dwarf_entrypc(sp_die, &eaddr) == 0) {
+               /* If the DIE has entrypc, use it. */
+               symbol = dwarf_diename(sp_die);
+       } else {
+               /* Try to get actual symbol name and address from symtab */
+               symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL);
+               eaddr = sym.st_value;
+       }
        if (!symbol) {
                pr_warning("Failed to find symbol at 0x%lx\n",
                           (unsigned long)paddr);
                return -ENOENT;
        }
-       eaddr = sym.st_value;
 
        tp->offset = (unsigned long)(paddr - eaddr);
        tp->address = (unsigned long)paddr;
index 80ca5d0..8c1b27c 100644 (file)
@@ -464,6 +464,7 @@ static PyObject *python_process_brstack(struct perf_sample *sample,
                                        struct thread *thread)
 {
        struct branch_stack *br = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        PyObject *pylist;
        u64 i;
 
@@ -484,28 +485,28 @@ static PyObject *python_process_brstack(struct perf_sample *sample,
                        Py_FatalError("couldn't create Python dictionary");
 
                pydict_set_item_string_decref(pyelem, "from",
-                   PyLong_FromUnsignedLongLong(br->entries[i].from));
+                   PyLong_FromUnsignedLongLong(entries[i].from));
                pydict_set_item_string_decref(pyelem, "to",
-                   PyLong_FromUnsignedLongLong(br->entries[i].to));
+                   PyLong_FromUnsignedLongLong(entries[i].to));
                pydict_set_item_string_decref(pyelem, "mispred",
-                   PyBool_FromLong(br->entries[i].flags.mispred));
+                   PyBool_FromLong(entries[i].flags.mispred));
                pydict_set_item_string_decref(pyelem, "predicted",
-                   PyBool_FromLong(br->entries[i].flags.predicted));
+                   PyBool_FromLong(entries[i].flags.predicted));
                pydict_set_item_string_decref(pyelem, "in_tx",
-                   PyBool_FromLong(br->entries[i].flags.in_tx));
+                   PyBool_FromLong(entries[i].flags.in_tx));
                pydict_set_item_string_decref(pyelem, "abort",
-                   PyBool_FromLong(br->entries[i].flags.abort));
+                   PyBool_FromLong(entries[i].flags.abort));
                pydict_set_item_string_decref(pyelem, "cycles",
-                   PyLong_FromUnsignedLongLong(br->entries[i].flags.cycles));
+                   PyLong_FromUnsignedLongLong(entries[i].flags.cycles));
 
                thread__find_map_fb(thread, sample->cpumode,
-                                   br->entries[i].from, &al);
+                                   entries[i].from, &al);
                dsoname = get_dsoname(al.map);
                pydict_set_item_string_decref(pyelem, "from_dsoname",
                                              _PyUnicode_FromString(dsoname));
 
                thread__find_map_fb(thread, sample->cpumode,
-                                   br->entries[i].to, &al);
+                                   entries[i].to, &al);
                dsoname = get_dsoname(al.map);
                pydict_set_item_string_decref(pyelem, "to_dsoname",
                                              _PyUnicode_FromString(dsoname));
@@ -561,6 +562,7 @@ static PyObject *python_process_brstacksym(struct perf_sample *sample,
                                           struct thread *thread)
 {
        struct branch_stack *br = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        PyObject *pylist;
        u64 i;
        char bf[512];
@@ -581,22 +583,22 @@ static PyObject *python_process_brstacksym(struct perf_sample *sample,
                        Py_FatalError("couldn't create Python dictionary");
 
                thread__find_symbol_fb(thread, sample->cpumode,
-                                      br->entries[i].from, &al);
+                                      entries[i].from, &al);
                get_symoff(al.sym, &al, true, bf, sizeof(bf));
                pydict_set_item_string_decref(pyelem, "from",
                                              _PyUnicode_FromString(bf));
 
                thread__find_symbol_fb(thread, sample->cpumode,
-                                      br->entries[i].to, &al);
+                                      entries[i].to, &al);
                get_symoff(al.sym, &al, true, bf, sizeof(bf));
                pydict_set_item_string_decref(pyelem, "to",
                                              _PyUnicode_FromString(bf));
 
-               get_br_mspred(&br->entries[i].flags, bf, sizeof(bf));
+               get_br_mspred(&entries[i].flags, bf, sizeof(bf));
                pydict_set_item_string_decref(pyelem, "pred",
                                              _PyUnicode_FromString(bf));
 
-               if (br->entries[i].flags.in_tx) {
+               if (entries[i].flags.in_tx) {
                        pydict_set_item_string_decref(pyelem, "in_tx",
                                              _PyUnicode_FromString("X"));
                } else {
@@ -604,7 +606,7 @@ static PyObject *python_process_brstacksym(struct perf_sample *sample,
                                              _PyUnicode_FromString("-"));
                }
 
-               if (br->entries[i].flags.abort) {
+               if (entries[i].flags.abort) {
                        pydict_set_item_string_decref(pyelem, "abort",
                                              _PyUnicode_FromString("A"));
                } else {
index d0d7d25..055b00a 100644 (file)
@@ -1007,6 +1007,7 @@ static void callchain__lbr_callstack_printf(struct perf_sample *sample)
 {
        struct ip_callchain *callchain = sample->callchain;
        struct branch_stack *lbr_stack = sample->branch_stack;
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        u64 kernel_callchain_nr = callchain->nr;
        unsigned int i;
 
@@ -1043,10 +1044,10 @@ static void callchain__lbr_callstack_printf(struct perf_sample *sample)
                               i, callchain->ips[i]);
 
                printf("..... %2d: %016" PRIx64 "\n",
-                      (int)(kernel_callchain_nr), lbr_stack->entries[0].to);
+                      (int)(kernel_callchain_nr), entries[0].to);
                for (i = 0; i < lbr_stack->nr; i++)
                        printf("..... %2d: %016" PRIx64 "\n",
-                              (int)(i + kernel_callchain_nr + 1), lbr_stack->entries[i].from);
+                              (int)(i + kernel_callchain_nr + 1), entries[i].from);
        }
 }
 
@@ -1068,6 +1069,7 @@ static void callchain__printf(struct evsel *evsel,
 
 static void branch_stack__printf(struct perf_sample *sample, bool callstack)
 {
+       struct branch_entry *entries = perf_sample__branch_entries(sample);
        uint64_t i;
 
        printf("%s: nr:%" PRIu64 "\n",
@@ -1075,7 +1077,7 @@ static void branch_stack__printf(struct perf_sample *sample, bool callstack)
                sample->branch_stack->nr);
 
        for (i = 0; i < sample->branch_stack->nr; i++) {
-               struct branch_entry *e = &sample->branch_stack->entries[i];
+               struct branch_entry *e = &entries[i];
 
                if (!callstack) {
                        printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x\n",
index aa344a1..8a065a6 100644 (file)
@@ -2,11 +2,13 @@ from os import getenv
 from subprocess import Popen, PIPE
 from re import sub
 
+cc = getenv("CC")
+cc_is_clang = b"clang version" in Popen([cc, "-v"], stderr=PIPE).stderr.readline()
+
 def clang_has_option(option):
-    return [o for o in Popen(['clang', option], stderr=PIPE).stderr.readlines() if b"unknown argument" in o] == [ ]
+    return [o for o in Popen([cc, option], stderr=PIPE).stderr.readlines() if b"unknown argument" in o] == [ ]
 
-cc = getenv("CC")
-if cc == "clang":
+if cc_is_clang:
     from distutils.sysconfig import get_config_vars
     vars = get_config_vars()
     for var in ('CFLAGS', 'OPT'):
@@ -40,7 +42,7 @@ class install_lib(_install_lib):
 cflags = getenv('CFLAGS', '').split()
 # switch off several checks (need to be at the end of cflags list)
 cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter', '-Wno-redundant-decls' ]
-if cc != "clang":
+if not cc_is_clang:
     cflags += ['-Wno-cast-function-type' ]
 
 src_perf  = getenv('srctree') + '/tools/perf'
index bc31fcc..76c6052 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/ctype.h>
 #include "cgroup.h"
 #include <api/fs/fs.h>
+#include "util.h"
 
 #define CNTR_NOT_SUPPORTED     "<not supported>"
 #define CNTR_NOT_COUNTED       "<not counted>"
@@ -110,7 +111,7 @@ static void aggr_printout(struct perf_stat_config *config,
                        config->csv_sep);
                        break;
        case AGGR_NONE:
-               if (evsel->percore) {
+               if (evsel->percore && !config->percore_show_thread) {
                        fprintf(config->output, "S%d-D%d-C%*d%s",
                                cpu_map__id_to_socket(id),
                                cpu_map__id_to_die(id),
@@ -628,7 +629,7 @@ static void aggr_cb(struct perf_stat_config *config,
 static void print_counter_aggrdata(struct perf_stat_config *config,
                                   struct evsel *counter, int s,
                                   char *prefix, bool metric_only,
-                                  bool *first)
+                                  bool *first, int cpu)
 {
        struct aggr_data ad;
        FILE *output = config->output;
@@ -654,7 +655,7 @@ static void print_counter_aggrdata(struct perf_stat_config *config,
                fprintf(output, "%s", prefix);
 
        uval = val * counter->scale;
-       printout(config, id, nr, counter, uval, prefix,
+       printout(config, cpu != -1 ? cpu : id, nr, counter, uval, prefix,
                 run, ena, 1.0, &rt_stat);
        if (!metric_only)
                fputc('\n', output);
@@ -687,7 +688,7 @@ static void print_aggr(struct perf_stat_config *config,
                evlist__for_each_entry(evlist, counter) {
                        print_counter_aggrdata(config, counter, s,
                                               prefix, metric_only,
-                                              &first);
+                                              &first, -1);
                }
                if (metric_only)
                        fputc('\n', output);
@@ -1097,7 +1098,6 @@ static void print_footer(struct perf_stat_config *config)
 {
        double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
        FILE *output = config->output;
-       int n;
 
        if (!config->null_run)
                fprintf(output, "\n");
@@ -1131,9 +1131,7 @@ static void print_footer(struct perf_stat_config *config)
        }
        fprintf(output, "\n\n");
 
-       if (config->print_free_counters_hint &&
-           sysctl__read_int("kernel/nmi_watchdog", &n) >= 0 &&
-           n > 0)
+       if (config->print_free_counters_hint && sysctl__nmi_watchdog_enabled())
                fprintf(output,
 "Some events weren't counted. Try disabling the NMI watchdog:\n"
 "      echo 0 > /proc/sys/kernel/nmi_watchdog\n"
@@ -1146,6 +1144,26 @@ static void print_footer(struct perf_stat_config *config)
                        "the same PMU. Try reorganizing the group.\n");
 }
 
+static void print_percore_thread(struct perf_stat_config *config,
+                                struct evsel *counter, char *prefix)
+{
+       int s, s2, id;
+       bool first = true;
+
+       for (int i = 0; i < perf_evsel__nr_cpus(counter); i++) {
+               s2 = config->aggr_get_id(config, evsel__cpus(counter), i);
+               for (s = 0; s < config->aggr_map->nr; s++) {
+                       id = config->aggr_map->map[s];
+                       if (s2 == id)
+                               break;
+               }
+
+               print_counter_aggrdata(config, counter, s,
+                                      prefix, false,
+                                      &first, i);
+       }
+}
+
 static void print_percore(struct perf_stat_config *config,
                          struct evsel *counter, char *prefix)
 {
@@ -1157,13 +1175,16 @@ static void print_percore(struct perf_stat_config *config,
        if (!(config->aggr_map || config->aggr_get_id))
                return;
 
+       if (config->percore_show_thread)
+               return print_percore_thread(config, counter, prefix);
+
        for (s = 0; s < config->aggr_map->nr; s++) {
                if (prefix && metric_only)
                        fprintf(output, "%s", prefix);
 
                print_counter_aggrdata(config, counter, s,
                                       prefix, metric_only,
-                                      &first);
+                                      &first, -1);
        }
 
        if (metric_only)
index 90d23cc..0fd713d 100644 (file)
@@ -777,9 +777,7 @@ static void generic_metric(struct perf_stat_config *config,
        }
 
        if (!metric_events[i]) {
-               const char *p = metric_expr;
-
-               if (expr__parse(&ratio, &pctx, &p) == 0) {
+               if (expr__parse(&ratio, &pctx, metric_expr) == 0) {
                        char *unit;
                        char metric_bf[64];
 
index fb990ef..b4fdfaa 100644 (file)
@@ -109,6 +109,7 @@ struct perf_stat_config {
        bool                     walltime_run_table;
        bool                     all_kernel;
        bool                     all_user;
+       bool                     percore_show_thread;
        FILE                    *output;
        unsigned int             interval;
        unsigned int             timeout;
index 1077013..26bc6a0 100644 (file)
@@ -1622,7 +1622,12 @@ int dso__load(struct dso *dso, struct map *map)
                goto out;
        }
 
-       if (dso->kernel) {
+       kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
+               dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+
+       if (dso->kernel && !kmod) {
                if (dso->kernel == DSO_TYPE_KERNEL)
                        ret = dso__load_kernel_sym(dso, map);
                else if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
@@ -1650,12 +1655,6 @@ int dso__load(struct dso *dso, struct map *map)
        if (!name)
                goto out;
 
-       kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
-               dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
-               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
-               dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
-
-
        /*
         * Read the build id if possible. This is required for
         * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
index c423298..3f28af3 100644 (file)
@@ -345,6 +345,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                        continue;
 
                event->mmap2.ino = (u64)ino;
+               event->mmap2.ino_generation = 0;
 
                /*
                 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
@@ -1183,7 +1184,8 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
 
        if (type & PERF_SAMPLE_BRANCH_STACK) {
                sz = sample->branch_stack->nr * sizeof(struct branch_entry);
-               sz += sizeof(u64);
+               /* nr, hw_idx */
+               sz += 2 * sizeof(u64);
                result += sz;
        }
 
@@ -1344,7 +1346,8 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
 
        if (type & PERF_SAMPLE_BRANCH_STACK) {
                sz = sample->branch_stack->nr * sizeof(struct branch_entry);
-               sz += sizeof(u64);
+               /* nr, hw_idx */
+               sz += 2 * sizeof(u64);
                memcpy(array, sample->branch_stack, sz);
                array = (void *)array + sz;
        }
index 969ae56..d707c96 100644 (file)
@@ -55,6 +55,24 @@ int sysctl__max_stack(void)
        return sysctl_perf_event_max_stack;
 }
 
+bool sysctl__nmi_watchdog_enabled(void)
+{
+       static bool cached;
+       static bool nmi_watchdog;
+       int value;
+
+       if (cached)
+               return nmi_watchdog;
+
+       if (sysctl__read_int("kernel/nmi_watchdog", &value) < 0)
+               return false;
+
+       nmi_watchdog = (value > 0) ? true : false;
+       cached = true;
+
+       return nmi_watchdog;
+}
+
 bool test_attr__enabled;
 
 bool perf_host  = true;
index 9969b8b..f486fdd 100644 (file)
@@ -29,6 +29,8 @@ size_t hex_width(u64 v);
 
 int sysctl__max_stack(void);
 
+bool sysctl__nmi_watchdog_enabled(void);
+
 int fetch_kernel_version(unsigned int *puint,
                         char *str, size_t str_sz);
 #define KVER_VERSION(x)                (((x) >> 16) & 0xff)
index 33dc34d..20f4634 100644 (file)
@@ -82,7 +82,7 @@ static struct pci_access *pci_acc;
 static struct pci_dev *amd_fam14h_pci_dev;
 static int nbp1_entered;
 
-struct timespec start_time;
+static struct timespec start_time;
 static unsigned long long timediff;
 
 #ifdef DEBUG
index 3c4cee1..a65f7d0 100644 (file)
@@ -19,7 +19,7 @@ struct cpuidle_monitor cpuidle_sysfs_monitor;
 
 static unsigned long long **previous_count;
 static unsigned long long **current_count;
-struct timespec start_time;
+static struct timespec start_time;
 static unsigned long long timediff;
 
 static int cpuidle_get_count_percent(unsigned int id, double *percent,
index 6d44fec..7c77045 100644 (file)
@@ -27,6 +27,8 @@ struct cpuidle_monitor *all_monitors[] = {
 0
 };
 
+int cpu_count;
+
 static struct cpuidle_monitor *monitors[MONITORS_MAX];
 static unsigned int avail_monitors;
 
index 5b5eb1d..c559d31 100644 (file)
@@ -25,7 +25,7 @@
 #endif
 #define CSTATE_DESC_LEN 60
 
-int cpu_count;
+extern int cpu_count;
 
 /* Hard to define the right names ...: */
 enum power_range_e {
index 256199c..3c47865 100755 (executable)
@@ -235,7 +235,6 @@ def plot_duration_cpu():
     output_png = 'all_cpu_durations.png'
     g_plot = common_all_gnuplot_settings(output_png)
 #   autoscale this one, no set y range
-    g_plot('set ytics 0, 500')
     g_plot('set ylabel "Timer Duration (MilliSeconds)"')
     g_plot('set title "{} : cpu durations : {:%F %H:%M}"'.format(testname, datetime.now()))
 
index 13f1e8b..2b65512 100644 (file)
@@ -16,7 +16,7 @@ override CFLAGS +=    -D_FORTIFY_SOURCE=2
 
 %: %.c
        @mkdir -p $(BUILD_OUTPUT)
-       $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS)
+       $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS) -lcap
 
 .PHONY : clean
 clean :
index 31c1ca0..33b3708 100644 (file)
@@ -30,7 +30,7 @@
 #include <sched.h>
 #include <time.h>
 #include <cpuid.h>
-#include <linux/capability.h>
+#include <sys/capability.h>
 #include <errno.h>
 #include <math.h>
 
@@ -304,6 +304,10 @@ int *irqs_per_cpu;         /* indexed by cpu_num */
 
 void setup_all_buffers(void);
 
+char *sys_lpi_file;
+char *sys_lpi_file_sysfs = "/sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us";
+char *sys_lpi_file_debugfs = "/sys/kernel/debug/pmc_core/slp_s0_residency_usec";
+
 int cpu_is_not_present(int cpu)
 {
        return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set);
@@ -2916,8 +2920,6 @@ int snapshot_gfx_mhz(void)
  *
  * record snapshot of
  * /sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us
- *
- * return 1 if config change requires a restart, else return 0
  */
 int snapshot_cpu_lpi_us(void)
 {
@@ -2941,17 +2943,14 @@ int snapshot_cpu_lpi_us(void)
 /*
  * snapshot_sys_lpi()
  *
- * record snapshot of
- * /sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us
- *
- * return 1 if config change requires a restart, else return 0
+ * record snapshot of sys_lpi_file
  */
 int snapshot_sys_lpi_us(void)
 {
        FILE *fp;
        int retval;
 
-       fp = fopen_or_die("/sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us", "r");
+       fp = fopen_or_die(sys_lpi_file, "r");
 
        retval = fscanf(fp, "%lld", &cpuidle_cur_sys_lpi_us);
        if (retval != 1) {
@@ -3151,28 +3150,42 @@ void check_dev_msr()
                        err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
 }
 
-void check_permissions()
+/*
+ * check for CAP_SYS_RAWIO
+ * return 0 on success
+ * return 1 on fail
+ */
+int check_for_cap_sys_rawio(void)
 {
-       struct __user_cap_header_struct cap_header_data;
-       cap_user_header_t cap_header = &cap_header_data;
-       struct __user_cap_data_struct cap_data_data;
-       cap_user_data_t cap_data = &cap_data_data;
-       extern int capget(cap_user_header_t hdrp, cap_user_data_t datap);
-       int do_exit = 0;
-       char pathname[32];
+       cap_t caps;
+       cap_flag_value_t cap_flag_value;
 
-       /* check for CAP_SYS_RAWIO */
-       cap_header->pid = getpid();
-       cap_header->version = _LINUX_CAPABILITY_VERSION;
-       if (capget(cap_header, cap_data) < 0)
-               err(-6, "capget(2) failed");
+       caps = cap_get_proc();
+       if (caps == NULL)
+               err(-6, "cap_get_proc\n");
 
-       if ((cap_data->effective & (1 << CAP_SYS_RAWIO)) == 0) {
-               do_exit++;
+       if (cap_get_flag(caps, CAP_SYS_RAWIO, CAP_EFFECTIVE, &cap_flag_value))
+               err(-6, "cap_get\n");
+
+       if (cap_flag_value != CAP_SET) {
                warnx("capget(CAP_SYS_RAWIO) failed,"
                        " try \"# setcap cap_sys_rawio=ep %s\"", progname);
+               return 1;
        }
 
+       if (cap_free(caps) == -1)
+               err(-6, "cap_free\n");
+
+       return 0;
+}
+void check_permissions(void)
+{
+       int do_exit = 0;
+       char pathname[32];
+
+       /* check for CAP_SYS_RAWIO */
+       do_exit += check_for_cap_sys_rawio();
+
        /* test file permissions */
        sprintf(pathname, "/dev/cpu/%d/msr", base_cpu);
        if (euidaccess(pathname, R_OK)) {
@@ -3265,6 +3278,7 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
        case INTEL_FAM6_ATOM_GOLDMONT:  /* BXT */
        case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
        case INTEL_FAM6_ATOM_GOLDMONT_D:        /* DNV */
+       case INTEL_FAM6_ATOM_TREMONT:   /* EHL */
                pkg_cstate_limits = glm_pkg_cstate_limits;
                break;
        default:
@@ -3336,6 +3350,17 @@ int is_skx(unsigned int family, unsigned int model)
        }
        return 0;
 }
+int is_ehl(unsigned int family, unsigned int model)
+{
+       if (!genuine_intel)
+               return 0;
+
+       switch (model) {
+       case INTEL_FAM6_ATOM_TREMONT:
+               return 1;
+       }
+       return 0;
+}
 
 int has_turbo_ratio_limit(unsigned int family, unsigned int model)
 {
@@ -3478,6 +3503,23 @@ dump_cstate_pstate_config_info(unsigned int family, unsigned int model)
        dump_nhm_cst_cfg();
 }
 
+static void dump_sysfs_file(char *path)
+{
+       FILE *input;
+       char cpuidle_buf[64];
+
+       input = fopen(path, "r");
+       if (input == NULL) {
+               if (debug)
+                       fprintf(outf, "NSFOD %s\n", path);
+               return;
+       }
+       if (!fgets(cpuidle_buf, sizeof(cpuidle_buf), input))
+               err(1, "%s: failed to read file", path);
+       fclose(input);
+
+       fprintf(outf, "%s: %s", strrchr(path, '/') + 1, cpuidle_buf);
+}
 static void
 dump_sysfs_cstate_config(void)
 {
@@ -3491,6 +3533,15 @@ dump_sysfs_cstate_config(void)
        if (!DO_BIC(BIC_sysfs))
                return;
 
+       if (access("/sys/devices/system/cpu/cpuidle", R_OK)) {
+               fprintf(outf, "cpuidle not loaded\n");
+               return;
+       }
+
+       dump_sysfs_file("/sys/devices/system/cpu/cpuidle/current_driver");
+       dump_sysfs_file("/sys/devices/system/cpu/cpuidle/current_governor");
+       dump_sysfs_file("/sys/devices/system/cpu/cpuidle/current_governor_ro");
+
        for (state = 0; state < 10; ++state) {
 
                sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name",
@@ -3894,6 +3945,20 @@ void rapl_probe_intel(unsigned int family, unsigned int model)
                else
                        BIC_PRESENT(BIC_PkgWatt);
                break;
+       case INTEL_FAM6_ATOM_TREMONT:   /* EHL */
+               do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_GFX | RAPL_PKG_POWER_INFO;
+               if (rapl_joules) {
+                       BIC_PRESENT(BIC_Pkg_J);
+                       BIC_PRESENT(BIC_Cor_J);
+                       BIC_PRESENT(BIC_RAM_J);
+                       BIC_PRESENT(BIC_GFX_J);
+               } else {
+                       BIC_PRESENT(BIC_PkgWatt);
+                       BIC_PRESENT(BIC_CorWatt);
+                       BIC_PRESENT(BIC_RAMWatt);
+                       BIC_PRESENT(BIC_GFXWatt);
+               }
+               break;
        case INTEL_FAM6_SKYLAKE_L:      /* SKL */
        case INTEL_FAM6_CANNONLAKE_L:   /* CNL */
                do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_GFX | RAPL_PKG_POWER_INFO;
@@ -4295,6 +4360,7 @@ int has_snb_msrs(unsigned int family, unsigned int model)
        case INTEL_FAM6_ATOM_GOLDMONT:          /* BXT */
        case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
        case INTEL_FAM6_ATOM_GOLDMONT_D:        /* DNV */
+       case INTEL_FAM6_ATOM_TREMONT:           /* EHL */
                return 1;
        }
        return 0;
@@ -4324,6 +4390,7 @@ int has_c8910_msrs(unsigned int family, unsigned int model)
        case INTEL_FAM6_CANNONLAKE_L:   /* CNL */
        case INTEL_FAM6_ATOM_GOLDMONT:  /* BXT */
        case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
+       case INTEL_FAM6_ATOM_TREMONT:   /* EHL */
                return 1;
        }
        return 0;
@@ -4610,14 +4677,24 @@ unsigned int intel_model_duplicates(unsigned int model)
        case INTEL_FAM6_SKYLAKE:
        case INTEL_FAM6_KABYLAKE_L:
        case INTEL_FAM6_KABYLAKE:
+       case INTEL_FAM6_COMETLAKE_L:
+       case INTEL_FAM6_COMETLAKE:
                return INTEL_FAM6_SKYLAKE_L;
 
        case INTEL_FAM6_ICELAKE_L:
        case INTEL_FAM6_ICELAKE_NNPI:
+       case INTEL_FAM6_TIGERLAKE_L:
+       case INTEL_FAM6_TIGERLAKE:
                return INTEL_FAM6_CANNONLAKE_L;
 
        case INTEL_FAM6_ATOM_TREMONT_D:
                return INTEL_FAM6_ATOM_GOLDMONT_D;
+
+       case INTEL_FAM6_ATOM_TREMONT_L:
+               return INTEL_FAM6_ATOM_TREMONT;
+
+       case INTEL_FAM6_ICELAKE_X:
+               return INTEL_FAM6_SKYLAKE_X;
        }
        return model;
 }
@@ -4872,7 +4949,8 @@ void process_cpuid()
        do_slm_cstates = is_slm(family, model);
        do_knl_cstates  = is_knl(family, model);
 
-       if (do_slm_cstates || do_knl_cstates || is_cnl(family, model))
+       if (do_slm_cstates || do_knl_cstates || is_cnl(family, model) ||
+           is_ehl(family, model))
                BIC_NOT_PRESENT(BIC_CPU_c3);
 
        if (!quiet)
@@ -4907,10 +4985,16 @@ void process_cpuid()
        else
                BIC_NOT_PRESENT(BIC_CPU_LPI);
 
-       if (!access("/sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us", R_OK))
+       if (!access(sys_lpi_file_sysfs, R_OK)) {
+               sys_lpi_file = sys_lpi_file_sysfs;
                BIC_PRESENT(BIC_SYS_LPI);
-       else
+       } else if (!access(sys_lpi_file_debugfs, R_OK)) {
+               sys_lpi_file = sys_lpi_file_debugfs;
+               BIC_PRESENT(BIC_SYS_LPI);
+       } else {
+               sys_lpi_file_sysfs = NULL;
                BIC_NOT_PRESENT(BIC_SYS_LPI);
+       }
 
        if (!quiet)
                decode_misc_feature_control();
@@ -5306,7 +5390,7 @@ int get_and_dump_counters(void)
 }
 
 void print_version() {
-       fprintf(outf, "turbostat version 19.08.31"
+       fprintf(outf, "turbostat version 20.03.20"
                " - Len Brown <lenb@kernel.org>\n");
 }
 
@@ -5323,9 +5407,9 @@ int add_counter(unsigned int msr_num, char *path, char *name,
        }
 
        msrp->msr_num = msr_num;
-       strncpy(msrp->name, name, NAME_BYTES);
+       strncpy(msrp->name, name, NAME_BYTES - 1);
        if (path)
-               strncpy(msrp->path, path, PATH_BYTES);
+               strncpy(msrp->path, path, PATH_BYTES - 1);
        msrp->width = width;
        msrp->type = type;
        msrp->format = format;
index ded7a95..6d2f3a1 100644 (file)
@@ -1,8 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 ifneq ($(O),)
 ifeq ($(origin O), command line)
-       dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),)
-       ABSOLUTE_O := $(shell cd $(O) ; pwd)
+       dummy := $(if $(shell cd $(PWD); test -d $(O) || echo $(O)),$(error O=$(O) does not exist),)
+       ABSOLUTE_O := $(shell cd $(PWD); cd $(O) ; pwd)
        OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/)
        COMMAND_O := O=$(ABSOLUTE_O)
 ifeq ($(objtree),)
index 5c342e6..2249a15 100644 (file)
@@ -51,7 +51,7 @@ $(OUTPUT)spidev_fdx: $(SPIDEV_FDX_IN)
 
 clean:
        rm -f $(ALL_PROGRAMS)
-       rm -f $(OUTPUT)include/linux/spi/spidev.h
+       rm -rf $(OUTPUT)include/
        find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
 
 install: $(ALL_PROGRAMS)
index 3559e76..27967dd 100644 (file)
@@ -13,6 +13,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <getopt.h>
 #include <fcntl.h>
 #include <time.h>
 
 static void pabort(const char *s)
 {
-       perror(s);
+       if (errno != 0)
+               perror(s);
+       else
+               printf("%s\n", s);
+
        abort();
 }
 
@@ -283,7 +288,6 @@ static void parse_opts(int argc, char *argv[])
                        break;
                default:
                        print_usage(argv[0]);
-                       break;
                }
        }
        if (mode & SPI_LOOP) {
@@ -405,6 +409,9 @@ int main(int argc, char *argv[])
 
        parse_opts(argc, argv);
 
+       if (input_tx && input_file)
+               pabort("only one of -p and --input may be selected");
+
        fd = open(device, O_RDWR);
        if (fd < 0)
                pabort("can't open device");
@@ -446,9 +453,6 @@ int main(int argc, char *argv[])
        printf("bits per word: %d\n", bits);
        printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
 
-       if (input_tx && input_file)
-               pabort("only one of -p and --input may be selected");
-
        if (input_tx)
                transfer_escaped_string(fd, input_tx);
        else if (input_file)
index 220d04f..7570e36 100755 (executable)
@@ -30,7 +30,7 @@ my %default = (
     "EMAIL_WHEN_STARTED"       => 0,
     "NUM_TESTS"                        => 1,
     "TEST_TYPE"                        => "build",
-    "BUILD_TYPE"               => "randconfig",
+    "BUILD_TYPE"               => "oldconfig",
     "MAKE_CMD"                 => "make",
     "CLOSE_CONSOLE_SIGNAL"     => "INT",
     "TIMEOUT"                  => 120,
@@ -1030,7 +1030,7 @@ sub __read_config {
            }
 
            if (!$skip && $rest !~ /^\s*$/) {
-               die "$name: $.: Gargbage found after $type\n$_";
+               die "$name: $.: Garbage found after $type\n$_";
            }
 
            if ($skip && $type eq "TEST_START") {
@@ -1063,7 +1063,7 @@ sub __read_config {
            }
 
            if ($rest !~ /^\s*$/) {
-               die "$name: $.: Gargbage found after DEFAULTS\n$_";
+               die "$name: $.: Garbage found after DEFAULTS\n$_";
            }
 
        } elsif (/^\s*INCLUDE\s+(\S+)/) {
@@ -1154,7 +1154,7 @@ sub __read_config {
            # on of these sections that have SKIP defined.
            # The save variable can be
            # defined multiple times and the new one simply overrides
-           # the prevous one.
+           # the previous one.
            set_variable($lvalue, $rvalue);
 
        } else {
@@ -1234,7 +1234,7 @@ sub read_config {
        foreach my $option (keys %not_used) {
            print "$option\n";
        }
-       print "Set IGRNORE_UNUSED = 1 to have ktest ignore unused variables\n";
+       print "Set IGNORE_UNUSED = 1 to have ktest ignore unused variables\n";
        if (!read_yn "Do you want to continue?") {
            exit -1;
        }
@@ -1345,7 +1345,7 @@ sub eval_option {
        # Check for recursive evaluations.
        # 100 deep should be more than enough.
        if ($r++ > 100) {
-           die "Over 100 evaluations accurred with $option\n" .
+           die "Over 100 evaluations occurred with $option\n" .
                "Check for recursive variables\n";
        }
        $prev = $option;
@@ -1383,7 +1383,7 @@ sub reboot {
 
     } else {
        # Make sure everything has been written to disk
-       run_ssh("sync");
+       run_ssh("sync", 10);
 
        if (defined($time)) {
            start_monitor;
@@ -1461,7 +1461,7 @@ sub get_test_name() {
 
 sub dodie {
 
-    # avoid recusion
+    # avoid recursion
     return if ($in_die);
     $in_die = 1;
 
index c3bc933..27666b8 100644 (file)
@@ -10,7 +10,7 @@
 #
 
 # Options set in the beginning of the file are considered to be
-# default options. These options can be overriden by test specific
+# default options. These options can be overridden by test specific
 # options, with the following exceptions:
 #
 #  LOG_FILE
 #
 # This config file can also contain "config variables".
 # These are assigned with ":=" instead of the ktest option
-# assigment "=".
+# assignment "=".
 #
 # The difference between ktest options and config variables
 # is that config variables can be used multiple times,
 #### Using options in other options ####
 #
 # Options that are defined in the config file may also be used
-# by other options. All options are evaulated at time of
+# by other options. All options are evaluated at time of
 # use (except that config variables are evaluated at config
 # processing time).
 #
 #TEST = ssh user@machine /root/run_test
 
 # The build type is any make config type or special command
-#  (default randconfig)
+#  (default oldconfig)
 #   nobuild - skip the clean and build step
 #   useconfig:/path/to/config - use the given config and run
 #              oldconfig on it.
 
 # Line to define a successful boot up in console output.
 # This is what the line contains, not the entire line. If you need
-# the entire line to match, then use regural expression syntax like:
+# the entire line to match, then use regular expression syntax like:
 #  (do not add any quotes around it)
 #
 #  SUCCESS_LINE = ^MyBox Login:$
 # (ignored if POWEROFF_ON_SUCCESS is set)
 #REBOOT_ON_SUCCESS = 1
 
-# In case there are isses with rebooting, you can specify this
+# In case there are issues with rebooting, you can specify this
 # to always powercycle after this amount of time after calling
 # reboot.
 # Note, POWERCYCLE_AFTER_REBOOT = 0 does NOT disable it. It just
 # (default undefined)
 #POWERCYCLE_AFTER_REBOOT = 5
 
-# In case there's isses with halting, you can specify this
+# In case there's issues with halting, you can specify this
 # to always poweroff after this amount of time after calling
 # halt.
 # Note, POWEROFF_AFTER_HALT = 0 does NOT disable it. It just
 #
 #  PATCHCHECK_START is required and is the first patch to
 #   test (the SHA1 of the commit). You may also specify anything
-#   that git checkout allows (branch name, tage, HEAD~3).
+#   that git checkout allows (branch name, tag, HEAD~3).
 #
 #  PATCHCHECK_END is the last patch to check (default HEAD)
 #
 #     IGNORE_WARNINGS is set for the given commit's sha1
 #
 #   IGNORE_WARNINGS can be used to disable the failure of patchcheck
-#     on a particuler commit (SHA1). You can add more than one commit
+#     on a particular commit (SHA1). You can add more than one commit
 #     by adding a list of SHA1s that are space delimited.
 #
 #   If BUILD_NOCLEAN is set, then make mrproper will not be run on
 #   whatever reason. (Can't reboot, want to inspect each iteration)
 #   Doing a BISECT_MANUAL will have the test wait for you to
 #   tell it if the test passed or failed after each iteration.
-#   This is basicall the same as running git bisect yourself
+#   This is basically the same as running git bisect yourself
 #   but ktest will rebuild and install the kernel for you.
 #
 # BISECT_CHECK = 1 (optional, default 0)
 #
 # CONFIG_BISECT_EXEC (optional)
 #  The config bisect is a separate program that comes with ktest.pl.
-#  By befault, it will look for:
+#  By default, it will look for:
 #    `pwd`/config-bisect.pl # the location ktest.pl was executed from.
 #  If it does not find it there, it will look for:
 #    `dirname <ktest.pl>`/config-bisect.pl # The directory that holds ktest.pl
index e59eb9e..180ad1e 100755 (executable)
@@ -24,6 +24,8 @@ KunitResult = namedtuple('KunitResult', ['status','result'])
 
 KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 'build_dir', 'defconfig'])
 
+KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0]
+
 class KunitStatus(Enum):
        SUCCESS = auto()
        CONFIG_FAILURE = auto()
@@ -35,6 +37,13 @@ def create_default_kunitconfig():
                shutil.copyfile('arch/um/configs/kunit_defconfig',
                                kunit_kernel.kunitconfig_path)
 
+def get_kernel_root_path():
+       parts = sys.argv[0] if not __file__ else __file__
+       parts = os.path.realpath(parts).split('tools/testing/kunit')
+       if len(parts) != 2:
+               sys.exit(1)
+       return parts[0]
+
 def run_tests(linux: kunit_kernel.LinuxSourceTree,
              request: KunitRequest) -> KunitResult:
        config_start = time.time()
@@ -114,6 +123,9 @@ def main(argv, linux=None):
        cli_args = parser.parse_args(argv)
 
        if cli_args.subcommand == 'run':
+               if get_kernel_root_path():
+                       os.chdir(get_kernel_root_path())
+
                if cli_args.build_dir:
                        if not os.path.exists(cli_args.build_dir):
                                os.mkdir(cli_args.build_dir)
index cc5d844..d99ae75 100644 (file)
@@ -93,6 +93,20 @@ class LinuxSourceTree(object):
                        return False
                return True
 
+       def validate_config(self, build_dir):
+               kconfig_path = get_kconfig_path(build_dir)
+               validated_kconfig = kunit_config.Kconfig()
+               validated_kconfig.read_from_file(kconfig_path)
+               if not self._kconfig.is_subset_of(validated_kconfig):
+                       invalid = self._kconfig.entries() - validated_kconfig.entries()
+                       message = 'Provided Kconfig is not contained in validated .config. Following fields found in kunitconfig, ' \
+                                         'but not in .config: %s' % (
+                                       ', '.join([str(e) for e in invalid])
+                       )
+                       logging.error(message)
+                       return False
+               return True
+
        def build_config(self, build_dir):
                kconfig_path = get_kconfig_path(build_dir)
                if build_dir and not os.path.exists(build_dir):
@@ -103,12 +117,7 @@ class LinuxSourceTree(object):
                except ConfigError as e:
                        logging.error(e)
                        return False
-               validated_kconfig = kunit_config.Kconfig()
-               validated_kconfig.read_from_file(kconfig_path)
-               if not self._kconfig.is_subset_of(validated_kconfig):
-                       logging.error('Provided Kconfig is not contained in validated .config!')
-                       return False
-               return True
+               return self.validate_config(build_dir)
 
        def build_reconfig(self, build_dir):
                """Creates a new .config if it is not a subset of the .kunitconfig."""
@@ -133,12 +142,7 @@ class LinuxSourceTree(object):
                except (ConfigError, BuildError) as e:
                        logging.error(e)
                        return False
-               used_kconfig = kunit_config.Kconfig()
-               used_kconfig.read_from_file(get_kconfig_path(build_dir))
-               if not self._kconfig.is_subset_of(used_kconfig):
-                       logging.error('Provided Kconfig is not contained in final config!')
-                       return False
-               return True
+               return self.validate_config(build_dir)
 
        def run_kernel(self, args=[], timeout=None, build_dir=''):
                args.extend(['mem=256M'])
index 6ec5039..b93fa64 100644 (file)
@@ -33,6 +33,7 @@ TARGETS += memory-hotplug
 TARGETS += mount
 TARGETS += mqueue
 TARGETS += net
+TARGETS += net/forwarding
 TARGETS += net/mptcp
 TARGETS += netfilter
 TARGETS += networking/timestamping
diff --git a/tools/testing/selftests/bpf/prog_tests/send_signal_sched_switch.c b/tools/testing/selftests/bpf/prog_tests/send_signal_sched_switch.c
new file mode 100644 (file)
index 0000000..189a34a
--- /dev/null
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "test_send_signal_kern.skel.h"
+
+static void sigusr1_handler(int signum)
+{
+}
+
+#define THREAD_COUNT 100
+
+static void *worker(void *p)
+{
+       int i;
+
+       for ( i = 0; i < 1000; i++)
+               usleep(1);
+
+       return NULL;
+}
+
+void test_send_signal_sched_switch(void)
+{
+       struct test_send_signal_kern *skel;
+       pthread_t threads[THREAD_COUNT];
+       u32 duration = 0;
+       int i, err;
+
+       signal(SIGUSR1, sigusr1_handler);
+
+       skel = test_send_signal_kern__open_and_load();
+       if (CHECK(!skel, "skel_open_and_load", "skeleton open_and_load failed\n"))
+               return;
+
+       skel->bss->pid = getpid();
+       skel->bss->sig = SIGUSR1;
+
+       err = test_send_signal_kern__attach(skel);
+       if (CHECK(err, "skel_attach", "skeleton attach failed\n"))
+               goto destroy_skel;
+
+       for (i = 0; i < THREAD_COUNT; i++) {
+               err = pthread_create(threads + i, NULL, worker, NULL);
+               if (CHECK(err, "pthread_create", "Error creating thread, %s\n",
+                         strerror(errno)))
+                       goto destroy_skel;
+       }
+
+       for (i = 0; i < THREAD_COUNT; i++)
+               pthread_join(threads[i], NULL);
+
+destroy_skel:
+       test_send_signal_kern__destroy(skel);
+}
index 1acc91e..b4233d3 100644 (file)
@@ -31,6 +31,12 @@ int send_signal_tp(void *ctx)
        return bpf_send_signal_test(ctx);
 }
 
+SEC("tracepoint/sched/sched_switch")
+int send_signal_tp_sched(void *ctx)
+{
+       return bpf_send_signal_test(ctx);
+}
+
 SEC("perf_event")
 int send_signal_perf(void *ctx)
 {
index 93040ca..8da77cd 100644 (file)
@@ -1062,6 +1062,48 @@ static struct btf_raw_test raw_tests[] = {
        .err_str = "Member exceeds struct_size",
 },
 
+/* Test member unexceeds the size of struct
+ *
+ * enum E {
+ *     E0,
+ *     E1,
+ * };
+ *
+ * struct A {
+ *     char m;
+ *     enum E __attribute__((packed)) n;
+ * };
+ */
+{
+       .descr = "size check test #5",
+       .raw_types = {
+               /* int */                       /* [1] */
+               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, sizeof(int)),
+               /* char */                      /* [2] */
+               BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1),
+               /* enum E { */                  /* [3] */
+               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 2), 1),
+               BTF_ENUM_ENC(NAME_TBD, 0),
+               BTF_ENUM_ENC(NAME_TBD, 1),
+               /* } */
+               /* struct A { */                /* [4] */
+               BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 2),
+               BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* char m; */
+               BTF_MEMBER_ENC(NAME_TBD, 3, 8),/* enum E __attribute__((packed)) n; */
+               /* } */
+               BTF_END_RAW,
+       },
+       .str_sec = "\0E\0E0\0E1\0A\0m\0n",
+       .str_sec_size = sizeof("\0E\0E0\0E1\0A\0m\0n"),
+       .map_type = BPF_MAP_TYPE_ARRAY,
+       .map_name = "size_check5_map",
+       .key_size = sizeof(int),
+       .value_size = 2,
+       .key_type_id = 1,
+       .value_type_id = 4,
+       .max_entries = 4,
+},
+
 /* typedef const void * const_void_ptr;
  * struct A {
  *     const_void_ptr m;
index bf0322e..bd5cae4 100644 (file)
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
 {
+       "jset32: ignores upper bits",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 0),
+       BPF_LD_IMM64(BPF_REG_7, 0x8000000000000000),
+       BPF_LD_IMM64(BPF_REG_8, 0x8000000000000000),
+       BPF_JMP_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1),
+       BPF_EXIT_INSN(),
+       BPF_JMP32_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1),
+       BPF_MOV64_IMM(BPF_REG_0, 2),
+       BPF_EXIT_INSN(),
+       },
+       .result = ACCEPT,
+       .retval = 2,
+},
+{
        "jset32: min/max deduction",
        .insns = {
        BPF_RAND_UEXT_R7,
index 012b2cf..40211cd 100644 (file)
@@ -1,13 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0-only
 # Makefile for firmware loading selftests
-
-# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
-all:
+CFLAGS = -Wall \
+         -O2
 
 TEST_PROGS := fw_run_tests.sh
 TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_lib.sh
+TEST_GEN_FILES := fw_namespace
 
 include ../lib.mk
-
-# Nothing to clean up.
-clean:
index 5689447..fcc2813 100755 (executable)
@@ -86,6 +86,29 @@ else
        fi
 fi
 
+# Try platform (EFI embedded fw) loading too
+if [ ! -e "$DIR"/trigger_request_platform ]; then
+       echo "$0: firmware loading: platform trigger not present, ignoring test" >&2
+else
+       if printf '\000' >"$DIR"/trigger_request_platform 2> /dev/null; then
+               echo "$0: empty filename should not succeed (platform)" >&2
+               exit 1
+       fi
+
+       # Note we echo a non-existing name, since files on the file-system
+       # are preferred over firmware embedded inside the platform's firmware
+       # The test adds a fake entry with the requested name to the platform's
+       # fw list, so the name does not matter as long as it does not exist
+       if ! echo -n "nope-$NAME" >"$DIR"/trigger_request_platform ; then
+               echo "$0: could not trigger request platform" >&2
+               exit 1
+       fi
+
+       # The test verifies itself that the loaded firmware contents matches
+       # the contents for the fake platform fw entry it added.
+       echo "$0: platform loading works"
+fi
+
 ### Batched requests tests
 test_config_present()
 {
diff --git a/tools/testing/selftests/firmware/fw_namespace.c b/tools/testing/selftests/firmware/fw_namespace.c
new file mode 100644 (file)
index 0000000..5ebc1ae
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Test triggering of loading of firmware from different mount
+ * namespaces. Expect firmware to be always loaded from the mount
+ * namespace of PID 1. */
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifndef CLONE_NEWNS
+# define CLONE_NEWNS 0x00020000
+#endif
+
+static char *fw_path = NULL;
+
+static void die(char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       if (fw_path)
+               unlink(fw_path);
+       umount("/lib/firmware");
+       exit(EXIT_FAILURE);
+}
+
+static void trigger_fw(const char *fw_name, const char *sys_path)
+{
+       int fd;
+
+       fd = open(sys_path, O_WRONLY);
+       if (fd < 0)
+               die("open failed: %s\n",
+                   strerror(errno));
+       if (write(fd, fw_name, strlen(fw_name)) != strlen(fw_name))
+               exit(EXIT_FAILURE);
+       close(fd);
+}
+
+static void setup_fw(const char *fw_path)
+{
+       int fd;
+       const char fw[] = "ABCD0123";
+
+       fd = open(fw_path, O_WRONLY | O_CREAT, 0600);
+       if (fd < 0)
+               die("open failed: %s\n",
+                   strerror(errno));
+       if (write(fd, fw, sizeof(fw) -1) != sizeof(fw) -1)
+               die("write failed: %s\n",
+                   strerror(errno));
+       close(fd);
+}
+
+static bool test_fw_in_ns(const char *fw_name, const char *sys_path, bool block_fw_in_parent_ns)
+{
+       pid_t child;
+
+       if (block_fw_in_parent_ns)
+               if (mount("test", "/lib/firmware", "tmpfs", MS_RDONLY, NULL) == -1)
+                       die("blocking firmware in parent ns failed\n");
+
+       child = fork();
+       if (child == -1) {
+               die("fork failed: %s\n",
+                       strerror(errno));
+       }
+       if (child != 0) { /* parent */
+               pid_t pid;
+               int status;
+
+               pid = waitpid(child, &status, 0);
+               if (pid == -1) {
+                       die("waitpid failed: %s\n",
+                               strerror(errno));
+               }
+               if (pid != child) {
+                       die("waited for %d got %d\n",
+                               child, pid);
+               }
+               if (!WIFEXITED(status)) {
+                       die("child did not terminate cleanly\n");
+               }
+               if (block_fw_in_parent_ns)
+                       umount("/lib/firmware");
+               return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false;
+       }
+
+       if (unshare(CLONE_NEWNS) != 0) {
+               die("unshare(CLONE_NEWNS) failed: %s\n",
+                       strerror(errno));
+       }
+       if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) == -1)
+               die("remount root in child ns failed\n");
+
+       if (!block_fw_in_parent_ns) {
+               if (mount("test", "/lib/firmware", "tmpfs", MS_RDONLY, NULL) == -1)
+                       die("blocking firmware in child ns failed\n");
+       } else
+               umount("/lib/firmware");
+
+       trigger_fw(fw_name, sys_path);
+
+       exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv)
+{
+       const char *fw_name = "test-firmware.bin";
+       char *sys_path;
+       if (argc != 2)
+               die("usage: %s sys_path\n", argv[0]);
+
+       /* Mount tmpfs to /lib/firmware so we don't have to assume
+          that it is writable for us.*/
+       if (mount("test", "/lib/firmware", "tmpfs", 0, NULL) == -1)
+               die("mounting tmpfs to /lib/firmware failed\n");
+
+       sys_path = argv[1];
+       asprintf(&fw_path, "/lib/firmware/%s", fw_name);
+
+       setup_fw(fw_path);
+
+       setvbuf(stdout, NULL, _IONBF, 0);
+       /* Positive case: firmware in PID1 mount namespace */
+       printf("Testing with firmware in parent namespace (assumed to be same file system as PID1)\n");
+       if (!test_fw_in_ns(fw_name, sys_path, false))
+               die("error: failed to access firmware\n");
+
+       /* Negative case: firmware in child mount namespace, expected to fail */
+       printf("Testing with firmware in child namespace\n");
+       if (test_fw_in_ns(fw_name, sys_path, true))
+               die("error: firmware access did not fail\n");
+
+       unlink(fw_path);
+       free(fw_path);
+       umount("/lib/firmware");
+       exit(EXIT_SUCCESS);
+}
index 8e14d55..7773770 100755 (executable)
@@ -61,6 +61,10 @@ run_test_config_0003()
 check_mods
 check_setup
 
+echo "Running namespace test: "
+$TEST_DIR/fw_namespace $DIR/trigger_request
+echo "OK"
+
 if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then
        run_test_config_0001
        run_test_config_0002
index cd1f5b3..d6e106f 100644 (file)
@@ -2,7 +2,7 @@
 all:
 
 TEST_PROGS := ftracetest
-TEST_FILES := test.d
+TEST_FILES := test.d settings
 EXTRA_CLEAN := $(OUTPUT)/logs/*
 
 include ../lib.mk
index 3876d8d..1acc9e1 100644 (file)
@@ -8,4 +8,6 @@ TEST_PROGS := \
        test-state.sh \
        test-ftrace.sh
 
+TEST_FILES := settings
+
 include ../lib.mk
diff --git a/tools/testing/selftests/lkdtm/.gitignore b/tools/testing/selftests/lkdtm/.gitignore
new file mode 100644 (file)
index 0000000..f262126
--- /dev/null
@@ -0,0 +1,2 @@
+*.sh
+!run.sh
index 287ae91..4c1bd03 100644 (file)
@@ -11,7 +11,9 @@ TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh
 TEST_PROGS += udpgro_bench.sh udpgro.sh test_vxlan_under_vrf.sh reuseport_addr_any.sh
 TEST_PROGS += test_vxlan_fdb_changelink.sh so_txtime.sh ipv6_flowlabel.sh
 TEST_PROGS += tcp_fastopen_backup_key.sh fcnal-test.sh l2tp.sh traceroute.sh
-TEST_PROGS += fin_ack_lat.sh
+TEST_PROGS += fin_ack_lat.sh fib_nexthop_multiprefix.sh fib_nexthops.sh
+TEST_PROGS += altnames.sh icmp_redirect.sh ip6_gre_headroom.sh
+TEST_PROGS += route_localnet.sh
 TEST_PROGS_EXTENDED := in_netns.sh
 TEST_GEN_FILES =  socket nettest
 TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any
index 60273f1..b761670 100755 (executable)
@@ -1041,6 +1041,27 @@ ipv6_addr_metric_test()
        fi
        log_test $rc 0 "Prefix route with metric on link up"
 
+       # verify peer metric added correctly
+       set -e
+       run_cmd "$IP -6 addr flush dev dummy2"
+       run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
+       set +e
+
+       check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
+       log_test $? 0 "Set metric with peer route on local side"
+       log_test $? 0 "User specified metric on local address"
+       check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
+       log_test $? 0 "Set metric with peer route on peer side"
+
+       set -e
+       run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
+       set +e
+
+       check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
+       log_test $? 0 "Modify metric and peer address on local side"
+       check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
+       log_test $? 0 "Modify metric and peer address on peer side"
+
        $IP li del dummy1
        $IP li del dummy2
        cleanup
@@ -1457,13 +1478,20 @@ ipv4_addr_metric_test()
 
        run_cmd "$IP addr flush dev dummy2"
        run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
-       run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 261"
        rc=$?
        if [ $rc -eq 0 ]; then
-               check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
+               check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
+               rc=$?
+       fi
+       log_test $rc 0 "Set metric of address with peer route"
+
+       run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
+       rc=$?
+       if [ $rc -eq 0 ]; then
+               check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
                rc=$?
        fi
-       log_test $rc 0 "Modify metric of address with peer route"
+       log_test $rc 0 "Modify metric and peer address for peer route"
 
        $IP li del dummy1
        $IP li del dummy2
diff --git a/tools/testing/selftests/net/forwarding/Makefile b/tools/testing/selftests/net/forwarding/Makefile
new file mode 100644 (file)
index 0000000..250fbb2
--- /dev/null
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: GPL-2.0+ OR MIT
+
+TEST_PROGS = bridge_igmp.sh \
+       bridge_port_isolation.sh \
+       bridge_sticky_fdb.sh \
+       bridge_vlan_aware.sh \
+       bridge_vlan_unaware.sh \
+       ethtool.sh \
+       gre_inner_v4_multipath.sh \
+       gre_inner_v6_multipath.sh \
+       gre_multipath.sh \
+       ip6gre_inner_v4_multipath.sh \
+       ip6gre_inner_v6_multipath.sh \
+       ipip_flat_gre_key.sh \
+       ipip_flat_gre_keys.sh \
+       ipip_flat_gre.sh \
+       ipip_hier_gre_key.sh \
+       ipip_hier_gre_keys.sh \
+       ipip_hier_gre.sh \
+       loopback.sh \
+       mirror_gre_bound.sh \
+       mirror_gre_bridge_1d.sh \
+       mirror_gre_bridge_1d_vlan.sh \
+       mirror_gre_bridge_1q_lag.sh \
+       mirror_gre_bridge_1q.sh \
+       mirror_gre_changes.sh \
+       mirror_gre_flower.sh \
+       mirror_gre_lag_lacp.sh \
+       mirror_gre_neigh.sh \
+       mirror_gre_nh.sh \
+       mirror_gre.sh \
+       mirror_gre_vlan_bridge_1q.sh \
+       mirror_gre_vlan.sh \
+       mirror_vlan.sh \
+       router_bridge.sh \
+       router_bridge_vlan.sh \
+       router_broadcast.sh \
+       router_mpath_nh.sh \
+       router_multicast.sh \
+       router_multipath.sh \
+       router.sh \
+       router_vid_1.sh \
+       sch_ets.sh \
+       sch_tbf_ets.sh \
+       sch_tbf_prio.sh \
+       sch_tbf_root.sh \
+       tc_actions.sh \
+       tc_chains.sh \
+       tc_flower_router.sh \
+       tc_flower.sh \
+       tc_shblocks.sh \
+       tc_vlan_modify.sh \
+       vxlan_asymmetric.sh \
+       vxlan_bridge_1d_port_8472.sh \
+       vxlan_bridge_1d.sh \
+       vxlan_bridge_1q_port_8472.sh \
+       vxlan_bridge_1q.sh \
+       vxlan_symmetric.sh
+
+TEST_PROGS_EXTENDED := devlink_lib.sh \
+       ethtool_lib.sh \
+       fib_offload_lib.sh \
+       forwarding.config.sample \
+       ipip_lib.sh \
+       lib.sh \
+       mirror_gre_lib.sh \
+       mirror_gre_topo_lib.sh \
+       mirror_lib.sh \
+       mirror_topo_lib.sh \
+       sch_ets_core.sh \
+       sch_ets_tests.sh \
+       sch_tbf_core.sh \
+       sch_tbf_etsprio.sh \
+       tc_common.sh
+
+include ../../lib.mk
index 93de520..ba450e6 100644 (file)
@@ -8,6 +8,8 @@ TEST_PROGS := mptcp_connect.sh
 
 TEST_GEN_FILES = mptcp_connect
 
+TEST_FILES := settings
+
 EXTRA_CLEAN := *.pcap
 
 include ../../lib.mk
index c623393..b8475cb 100644 (file)
 #include <sys/socket.h>
 #include <unistd.h>
 
+#ifndef SOL_DCCP
+#define SOL_DCCP 269
+#endif
+
 static const char *IP4_ADDR = "127.0.0.1";
 static const char *IP6_ADDR = "::1";
 static const char *IP4_MAPPED6 = "::ffff:127.0.0.1";
index 08194aa..9c0f758 100644 (file)
@@ -3,6 +3,10 @@
 
 TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \
        conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
-       nft_concat_range.sh
+       nft_concat_range.sh \
+       nft_queue.sh
+
+LDLIBS = -lmnl
+TEST_GEN_FILES =  nf-queue
 
 include ../lib.mk
index 59caa8f..4faf2ce 100644 (file)
@@ -1,2 +1,8 @@
 CONFIG_NET_NS=y
 CONFIG_NF_TABLES_INET=y
+CONFIG_NFT_QUEUE=m
+CONFIG_NFT_NAT=m
+CONFIG_NFT_REDIR=m
+CONFIG_NFT_MASQ=m
+CONFIG_NFT_FLOW_OFFLOAD=m
+CONFIG_NF_CT_NETLINK=m
diff --git a/tools/testing/selftests/netfilter/nf-queue.c b/tools/testing/selftests/netfilter/nf-queue.c
new file mode 100644 (file)
index 0000000..29c73bc
--- /dev/null
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <arpa/inet.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+
+struct options {
+       bool count_packets;
+       int verbose;
+       unsigned int queue_num;
+       unsigned int timeout;
+};
+
+static unsigned int queue_stats[5];
+static struct options opts;
+
+static void help(const char *p)
+{
+       printf("Usage: %s [-c|-v [-vv] ] [-t timeout] [-q queue_num]\n", p);
+}
+
+static int parse_attr_cb(const struct nlattr *attr, void *data)
+{
+       const struct nlattr **tb = data;
+       int type = mnl_attr_get_type(attr);
+
+       /* skip unsupported attribute in user-space */
+       if (mnl_attr_type_valid(attr, NFQA_MAX) < 0)
+               return MNL_CB_OK;
+
+       switch (type) {
+       case NFQA_MARK:
+       case NFQA_IFINDEX_INDEV:
+       case NFQA_IFINDEX_OUTDEV:
+       case NFQA_IFINDEX_PHYSINDEV:
+       case NFQA_IFINDEX_PHYSOUTDEV:
+               if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+                       perror("mnl_attr_validate");
+                       return MNL_CB_ERROR;
+               }
+               break;
+       case NFQA_TIMESTAMP:
+               if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
+                   sizeof(struct nfqnl_msg_packet_timestamp)) < 0) {
+                       perror("mnl_attr_validate2");
+                       return MNL_CB_ERROR;
+               }
+               break;
+       case NFQA_HWADDR:
+               if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC,
+                   sizeof(struct nfqnl_msg_packet_hw)) < 0) {
+                       perror("mnl_attr_validate2");
+                       return MNL_CB_ERROR;
+               }
+               break;
+       case NFQA_PAYLOAD:
+               break;
+       }
+       tb[type] = attr;
+       return MNL_CB_OK;
+}
+
+static int queue_cb(const struct nlmsghdr *nlh, void *data)
+{
+       struct nlattr *tb[NFQA_MAX+1] = { 0 };
+       struct nfqnl_msg_packet_hdr *ph = NULL;
+       uint32_t id = 0;
+
+       (void)data;
+
+       mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb);
+       if (tb[NFQA_PACKET_HDR]) {
+               ph = mnl_attr_get_payload(tb[NFQA_PACKET_HDR]);
+               id = ntohl(ph->packet_id);
+
+               if (opts.verbose > 0)
+                       printf("packet hook=%u, hwproto 0x%x",
+                               ntohs(ph->hw_protocol), ph->hook);
+
+               if (ph->hook >= 5) {
+                       fprintf(stderr, "Unknown hook %d\n", ph->hook);
+                       return MNL_CB_ERROR;
+               }
+
+               if (opts.verbose > 0) {
+                       uint32_t skbinfo = 0;
+
+                       if (tb[NFQA_SKB_INFO])
+                               skbinfo = ntohl(mnl_attr_get_u32(tb[NFQA_SKB_INFO]));
+                       if (skbinfo & NFQA_SKB_CSUMNOTREADY)
+                               printf(" csumnotready");
+                       if (skbinfo & NFQA_SKB_GSO)
+                               printf(" gso");
+                       if (skbinfo & NFQA_SKB_CSUM_NOTVERIFIED)
+                               printf(" csumnotverified");
+                       puts("");
+               }
+
+               if (opts.count_packets)
+                       queue_stats[ph->hook]++;
+       }
+
+       return MNL_CB_OK + id;
+}
+
+static struct nlmsghdr *
+nfq_build_cfg_request(char *buf, uint8_t command, int queue_num)
+{
+       struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+       struct nfqnl_msg_config_cmd cmd = {
+               .command = command,
+               .pf = htons(AF_INET),
+       };
+       struct nfgenmsg *nfg;
+
+       nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG;
+       nlh->nlmsg_flags = NLM_F_REQUEST;
+
+       nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+
+       nfg->nfgen_family = AF_UNSPEC;
+       nfg->version = NFNETLINK_V0;
+       nfg->res_id = htons(queue_num);
+
+       mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd);
+
+       return nlh;
+}
+
+static struct nlmsghdr *
+nfq_build_cfg_params(char *buf, uint8_t mode, int range, int queue_num)
+{
+       struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+       struct nfqnl_msg_config_params params = {
+               .copy_range = htonl(range),
+               .copy_mode = mode,
+       };
+       struct nfgenmsg *nfg;
+
+       nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG;
+       nlh->nlmsg_flags = NLM_F_REQUEST;
+
+       nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+       nfg->nfgen_family = AF_UNSPEC;
+       nfg->version = NFNETLINK_V0;
+       nfg->res_id = htons(queue_num);
+
+       mnl_attr_put(nlh, NFQA_CFG_PARAMS, sizeof(params), &params);
+
+       return nlh;
+}
+
+static struct nlmsghdr *
+nfq_build_verdict(char *buf, int id, int queue_num, int verd)
+{
+       struct nfqnl_msg_verdict_hdr vh = {
+               .verdict = htonl(verd),
+               .id = htonl(id),
+       };
+       struct nlmsghdr *nlh;
+       struct nfgenmsg *nfg;
+
+       nlh = mnl_nlmsg_put_header(buf);
+       nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT;
+       nlh->nlmsg_flags = NLM_F_REQUEST;
+       nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+       nfg->nfgen_family = AF_UNSPEC;
+       nfg->version = NFNETLINK_V0;
+       nfg->res_id = htons(queue_num);
+
+       mnl_attr_put(nlh, NFQA_VERDICT_HDR, sizeof(vh), &vh);
+
+       return nlh;
+}
+
+static void print_stats(void)
+{
+       unsigned int last, total;
+       int i;
+
+       if (!opts.count_packets)
+               return;
+
+       total = 0;
+       last = queue_stats[0];
+
+       for (i = 0; i < 5; i++) {
+               printf("hook %d packets %08u\n", i, queue_stats[i]);
+               last = queue_stats[i];
+               total += last;
+       }
+
+       printf("%u packets total\n", total);
+}
+
+struct mnl_socket *open_queue(void)
+{
+       char buf[MNL_SOCKET_BUFFER_SIZE];
+       unsigned int queue_num;
+       struct mnl_socket *nl;
+       struct nlmsghdr *nlh;
+       struct timeval tv;
+       uint32_t flags;
+
+       nl = mnl_socket_open(NETLINK_NETFILTER);
+       if (nl == NULL) {
+               perror("mnl_socket_open");
+               exit(EXIT_FAILURE);
+       }
+
+       if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
+               perror("mnl_socket_bind");
+               exit(EXIT_FAILURE);
+       }
+
+       queue_num = opts.queue_num;
+       nlh = nfq_build_cfg_request(buf, NFQNL_CFG_CMD_BIND, queue_num);
+
+       if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+               perror("mnl_socket_sendto");
+               exit(EXIT_FAILURE);
+       }
+
+       nlh = nfq_build_cfg_params(buf, NFQNL_COPY_PACKET, 0xFFFF, queue_num);
+
+       flags = NFQA_CFG_F_GSO | NFQA_CFG_F_UID_GID;
+       mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(flags));
+       mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(flags));
+
+       if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+               perror("mnl_socket_sendto");
+               exit(EXIT_FAILURE);
+       }
+
+       memset(&tv, 0, sizeof(tv));
+       tv.tv_sec = opts.timeout;
+       if (opts.timeout && setsockopt(mnl_socket_get_fd(nl),
+                                      SOL_SOCKET, SO_RCVTIMEO,
+                                      &tv, sizeof(tv))) {
+               perror("setsockopt(SO_RCVTIMEO)");
+               exit(EXIT_FAILURE);
+       }
+
+       return nl;
+}
+
+static int mainloop(void)
+{
+       unsigned int buflen = 64 * 1024 + MNL_SOCKET_BUFFER_SIZE;
+       struct mnl_socket *nl;
+       struct nlmsghdr *nlh;
+       unsigned int portid;
+       char *buf;
+       int ret;
+
+       buf = malloc(buflen);
+       if (!buf) {
+               perror("malloc");
+               exit(EXIT_FAILURE);
+       }
+
+       nl = open_queue();
+       portid = mnl_socket_get_portid(nl);
+
+       for (;;) {
+               uint32_t id;
+
+               ret = mnl_socket_recvfrom(nl, buf, buflen);
+               if (ret == -1) {
+                       if (errno == ENOBUFS)
+                               continue;
+
+                       if (errno == EAGAIN) {
+                               errno = 0;
+                               ret = 0;
+                               break;
+                       }
+
+                       perror("mnl_socket_recvfrom");
+                       exit(EXIT_FAILURE);
+               }
+
+               ret = mnl_cb_run(buf, ret, 0, portid, queue_cb, NULL);
+               if (ret < 0) {
+                       perror("mnl_cb_run");
+                       exit(EXIT_FAILURE);
+               }
+
+               id = ret - MNL_CB_OK;
+               nlh = nfq_build_verdict(buf, id, opts.queue_num, NF_ACCEPT);
+               if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+                       perror("mnl_socket_sendto");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       mnl_socket_close(nl);
+
+       return ret;
+}
+
+static void parse_opts(int argc, char **argv)
+{
+       int c;
+
+       while ((c = getopt(argc, argv, "chvt:q:")) != -1) {
+               switch (c) {
+               case 'c':
+                       opts.count_packets = true;
+                       break;
+               case 'h':
+                       help(argv[0]);
+                       exit(0);
+                       break;
+               case 'q':
+                       opts.queue_num = atoi(optarg);
+                       if (opts.queue_num > 0xffff)
+                               opts.queue_num = 0;
+                       break;
+               case 't':
+                       opts.timeout = atoi(optarg);
+                       break;
+               case 'v':
+                       opts.verbose++;
+                       break;
+               }
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       int ret;
+
+       parse_opts(argc, argv);
+
+       ret = mainloop();
+       if (opts.count_packets)
+               print_stats();
+
+       return ret;
+}
index aca21dd..5a4938d 100755 (executable)
 KSELFTEST_SKIP=4
 
 # Available test groups:
+# - reported_issues: check for issues that were reported in the past
 # - correctness: check that packets match given entries, and only those
 # - concurrency: attempt races between insertion, deletion and lookup
 # - timeout: check that packets match entries until they expire
 # - performance: estimate matching rate, compare with rbtree and hash baselines
-TESTS="correctness concurrency timeout"
+TESTS="reported_issues correctness concurrency timeout"
 [ "${quicktest}" != "1" ] && TESTS="${TESTS} performance"
 
 # Set types, defined by TYPE_ variables below
@@ -25,6 +26,9 @@ TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
        net_port_net net_mac net_mac_icmp net6_mac_icmp net6_port_net6_port
        net_port_mac_proto_net"
 
+# Reported bugs, also described by TYPE_ variables below
+BUGS="flush_remove_add"
+
 # List of possible paths to pktgen script from kernel tree for performance tests
 PKTGEN_SCRIPT_PATHS="
        ../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -327,6 +331,12 @@ flood_spec ip daddr . tcp dport . meta l4proto . ip saddr
 perf_duration  0
 "
 
+# Definition of tests for bugs reported in the past:
+# display      display text for test report
+TYPE_flush_remove_add="
+display                Add two elements, flush, re-add
+"
+
 # Set template for all tests, types and rules are filled in depending on test
 set_template='
 flush ruleset
@@ -440,6 +450,8 @@ setup_set() {
 
 # Check that at least one of the needed tools is available
 check_tools() {
+       [ -z "${tools}" ] && return 0
+
        __tools=
        for tool in ${tools}; do
                if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \
@@ -1025,7 +1037,7 @@ format_noconcat() {
 add() {
        if ! nft add element inet filter test "${1}"; then
                err "Failed to add ${1} given ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1045,7 +1057,7 @@ add_perf() {
 add_perf_norange() {
        if ! nft add element netdev perf norange "${1}"; then
                err "Failed to add ${1} given ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1054,7 +1066,7 @@ add_perf_norange() {
 add_perf_noconcat() {
        if ! nft add element netdev perf noconcat "${1}"; then
                err "Failed to add ${1} given ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1063,7 +1075,7 @@ add_perf_noconcat() {
 del() {
        if ! nft delete element inet filter test "${1}"; then
                err "Failed to delete ${1} given ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1134,7 +1146,7 @@ send_match() {
                err "  $(for f in ${src}; do
                         eval format_\$f "${2}"; printf ' '; done)"
                err "should have matched ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
        nft reset counter inet filter test >/dev/null
@@ -1160,7 +1172,7 @@ send_nomatch() {
                err "  $(for f in ${src}; do
                         eval format_\$f "${2}"; printf ' '; done)"
                err "should not have matched ruleset:"
-               err "$(nft list ruleset -a)"
+               err "$(nft -a list ruleset)"
                return 1
        fi
 }
@@ -1430,6 +1442,23 @@ test_performance() {
        kill "${perf_pid}"
 }
 
+test_bug_flush_remove_add() {
+       set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }'
+       elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }'
+       elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }'
+       for i in `seq 1 100`; do
+               nft add table t ${set_cmd}      || return ${KSELFTEST_SKIP}
+               nft add element t s ${elem1}    2>/dev/null || return 1
+               nft flush set t s               2>/dev/null || return 1
+               nft add element t s ${elem2}    2>/dev/null || return 1
+       done
+       nft flush ruleset
+}
+
+test_reported_issues() {
+       eval test_bug_"${subtest}"
+}
+
 # Run everything in a separate network namespace
 [ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
 tmp="$(mktemp)"
@@ -1438,9 +1467,15 @@ trap cleanup EXIT
 # Entry point for test runs
 passed=0
 for name in ${TESTS}; do
-       printf "TEST: %s\n" "${name}"
-       for type in ${TYPES}; do
-               eval desc=\$TYPE_"${type}"
+       printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')"
+       if [ "${name}" = "reported_issues" ]; then
+               SUBTESTS="${BUGS}"
+       else
+               SUBTESTS="${TYPES}"
+       fi
+
+       for subtest in ${SUBTESTS}; do
+               eval desc=\$TYPE_"${subtest}"
                IFS='
 '
                for __line in ${desc}; do
diff --git a/tools/testing/selftests/netfilter/nft_queue.sh b/tools/testing/selftests/netfilter/nft_queue.sh
new file mode 100755 (executable)
index 0000000..6898448
--- /dev/null
@@ -0,0 +1,332 @@
+#!/bin/bash
+#
+# This tests nf_queue:
+# 1. can process packets from all hooks
+# 2. support running nfqueue from more than one base chain
+#
+# Kselftest framework requirement - SKIP code is 4.
+ksft_skip=4
+ret=0
+
+sfx=$(mktemp -u "XXXXXXXX")
+ns1="ns1-$sfx"
+ns2="ns2-$sfx"
+nsrouter="nsrouter-$sfx"
+
+cleanup()
+{
+       ip netns del ${ns1}
+       ip netns del ${ns2}
+       ip netns del ${nsrouter}
+       rm -f "$TMPFILE0"
+       rm -f "$TMPFILE1"
+}
+
+nft --version > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without nft tool"
+       exit $ksft_skip
+fi
+
+ip -Version > /dev/null 2>&1
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not run test without ip tool"
+       exit $ksft_skip
+fi
+
+ip netns add ${nsrouter}
+if [ $? -ne 0 ];then
+       echo "SKIP: Could not create net namespace"
+       exit $ksft_skip
+fi
+
+TMPFILE0=$(mktemp)
+TMPFILE1=$(mktemp)
+trap cleanup EXIT
+
+ip netns add ${ns1}
+ip netns add ${ns2}
+
+ip link add veth0 netns ${nsrouter} type veth peer name eth0 netns ${ns1} > /dev/null 2>&1
+if [ $? -ne 0 ];then
+    echo "SKIP: No virtual ethernet pair device support in kernel"
+    exit $ksft_skip
+fi
+ip link add veth1 netns ${nsrouter} type veth peer name eth0 netns ${ns2}
+
+ip -net ${nsrouter} link set lo up
+ip -net ${nsrouter} link set veth0 up
+ip -net ${nsrouter} addr add 10.0.1.1/24 dev veth0
+ip -net ${nsrouter} addr add dead:1::1/64 dev veth0
+
+ip -net ${nsrouter} link set veth1 up
+ip -net ${nsrouter} addr add 10.0.2.1/24 dev veth1
+ip -net ${nsrouter} addr add dead:2::1/64 dev veth1
+
+ip -net ${ns1} link set lo up
+ip -net ${ns1} link set eth0 up
+
+ip -net ${ns2} link set lo up
+ip -net ${ns2} link set eth0 up
+
+ip -net ${ns1} addr add 10.0.1.99/24 dev eth0
+ip -net ${ns1} addr add dead:1::99/64 dev eth0
+ip -net ${ns1} route add default via 10.0.1.1
+ip -net ${ns1} route add default via dead:1::1
+
+ip -net ${ns2} addr add 10.0.2.99/24 dev eth0
+ip -net ${ns2} addr add dead:2::99/64 dev eth0
+ip -net ${ns2} route add default via 10.0.2.1
+ip -net ${ns2} route add default via dead:2::1
+
+load_ruleset() {
+       local name=$1
+       local prio=$2
+
+ip netns exec ${nsrouter} nft -f - <<EOF
+table inet $name {
+       chain nfq {
+               ip protocol icmp queue bypass
+               icmpv6 type { "echo-request", "echo-reply" } queue num 1 bypass
+       }
+       chain pre {
+               type filter hook prerouting priority $prio; policy accept;
+               jump nfq
+       }
+       chain input {
+               type filter hook input priority $prio; policy accept;
+               jump nfq
+       }
+       chain forward {
+               type filter hook forward priority $prio; policy accept;
+               tcp dport 12345 queue num 2
+               jump nfq
+       }
+       chain output {
+               type filter hook output priority $prio; policy accept;
+               tcp dport 12345 queue num 3
+               jump nfq
+       }
+       chain post {
+               type filter hook postrouting priority $prio; policy accept;
+               jump nfq
+       }
+}
+EOF
+}
+
+load_counter_ruleset() {
+       local prio=$1
+
+ip netns exec ${nsrouter} nft -f - <<EOF
+table inet countrules {
+       chain pre {
+               type filter hook prerouting priority $prio; policy accept;
+               counter
+       }
+       chain input {
+               type filter hook input priority $prio; policy accept;
+               counter
+       }
+       chain forward {
+               type filter hook forward priority $prio; policy accept;
+               counter
+       }
+       chain output {
+               type filter hook output priority $prio; policy accept;
+               counter
+       }
+       chain post {
+               type filter hook postrouting priority $prio; policy accept;
+               counter
+       }
+}
+EOF
+}
+
+test_ping() {
+  ip netns exec ${ns1} ping -c 1 -q 10.0.2.99 > /dev/null
+  if [ $? -ne 0 ];then
+       return 1
+  fi
+
+  ip netns exec ${ns1} ping -c 1 -q dead:2::99 > /dev/null
+  if [ $? -ne 0 ];then
+       return 1
+  fi
+
+  return 0
+}
+
+test_ping_router() {
+  ip netns exec ${ns1} ping -c 1 -q 10.0.2.1 > /dev/null
+  if [ $? -ne 0 ];then
+       return 1
+  fi
+
+  ip netns exec ${ns1} ping -c 1 -q dead:2::1 > /dev/null
+  if [ $? -ne 0 ];then
+       return 1
+  fi
+
+  return 0
+}
+
+test_queue_blackhole() {
+       local proto=$1
+
+ip netns exec ${nsrouter} nft -f - <<EOF
+table $proto blackh {
+       chain forward {
+       type filter hook forward priority 0; policy accept;
+               queue num 600
+       }
+}
+EOF
+       if [ $proto = "ip" ] ;then
+               ip netns exec ${ns1} ping -c 1 -q 10.0.2.99 > /dev/null
+               lret=$?
+       elif [ $proto = "ip6" ]; then
+               ip netns exec ${ns1} ping -c 1 -q dead:2::99 > /dev/null
+               lret=$?
+       else
+               lret=111
+       fi
+
+       # queue without bypass keyword should drop traffic if no listener exists.
+       if [ $lret -eq 0 ];then
+               echo "FAIL: $proto expected failure, got $lret" 1>&2
+               exit 1
+       fi
+
+       ip netns exec ${nsrouter} nft delete table $proto blackh
+       if [ $? -ne 0 ] ;then
+               echo "FAIL: $proto: Could not delete blackh table"
+               exit 1
+       fi
+
+        echo "PASS: $proto: statement with no listener results in packet drop"
+}
+
+test_queue()
+{
+       local expected=$1
+       local last=""
+
+       # spawn nf-queue listeners
+       ip netns exec ${nsrouter} ./nf-queue -c -q 0 -t 3 > "$TMPFILE0" &
+       ip netns exec ${nsrouter} ./nf-queue -c -q 1 -t 3 > "$TMPFILE1" &
+       sleep 1
+       test_ping
+       ret=$?
+       if [ $ret -ne 0 ];then
+               echo "FAIL: netns routing/connectivity with active listener on queue $queue: $ret" 1>&2
+               exit $ret
+       fi
+
+       test_ping_router
+       ret=$?
+       if [ $ret -ne 0 ];then
+               echo "FAIL: netns router unreachable listener on queue $queue: $ret" 1>&2
+               exit $ret
+       fi
+
+       wait
+       ret=$?
+
+       for file in $TMPFILE0 $TMPFILE1; do
+               last=$(tail -n1 "$file")
+               if [ x"$last" != x"$expected packets total" ]; then
+                       echo "FAIL: Expected $expected packets total, but got $last" 1>&2
+                       cat "$file" 1>&2
+
+                       ip netns exec ${nsrouter} nft list ruleset
+                       exit 1
+               fi
+       done
+
+       echo "PASS: Expected and received $last"
+}
+
+test_tcp_forward()
+{
+       ip netns exec ${nsrouter} ./nf-queue -q 2 -t 10 &
+       local nfqpid=$!
+
+       tmpfile=$(mktemp) || exit 1
+       dd conv=sparse status=none if=/dev/zero bs=1M count=100 of=$tmpfile
+       ip netns exec ${ns2} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null &
+       local rpid=$!
+
+       sleep 1
+       ip netns exec ${ns1} nc -w 5 10.0.2.99 12345 <"$tmpfile" >/dev/null &
+
+       rm -f "$tmpfile"
+
+       wait $rpid
+       wait $lpid
+       [ $? -eq 0 ] && echo "PASS: tcp and nfqueue in forward chain"
+}
+
+test_tcp_localhost()
+{
+       tc -net "${nsrouter}" qdisc add dev lo root netem loss random 1%
+
+       tmpfile=$(mktemp) || exit 1
+
+       dd conv=sparse status=none if=/dev/zero bs=1M count=900 of=$tmpfile
+       ip netns exec ${nsrouter} nc -w 5 -l -p 12345 <"$tmpfile" >/dev/null &
+       local rpid=$!
+
+       ip netns exec ${nsrouter} ./nf-queue -q 3 -t 30 &
+       local nfqpid=$!
+
+       sleep 1
+       ip netns exec ${nsrouter} nc -w 5 127.0.0.1 12345 <"$tmpfile" > /dev/null
+       rm -f "$tmpfile"
+
+       wait $rpid
+       [ $? -eq 0 ] && echo "PASS: tcp via loopback"
+}
+
+ip netns exec ${nsrouter} sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
+ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
+ip netns exec ${nsrouter} sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
+
+load_ruleset "filter" 0
+
+sleep 3
+
+test_ping
+ret=$?
+if [ $ret -eq 0 ];then
+       # queue bypass works (rules were skipped, no listener)
+       echo "PASS: ${ns1} can reach ${ns2}"
+else
+       echo "FAIL: ${ns1} cannot reach ${ns2}: $ret" 1>&2
+       exit $ret
+fi
+
+test_queue_blackhole ip
+test_queue_blackhole ip6
+
+# dummy ruleset to add base chains between the
+# queueing rules.  We don't want the second reinject
+# to re-execute the old hooks.
+load_counter_ruleset 10
+
+# we are hooking all: prerouting/input/forward/output/postrouting.
+# we ping ${ns2} from ${ns1} via ${nsrouter} using ipv4 and ipv6, so:
+# 1x icmp prerouting,forward,postrouting -> 3 queue events (6 incl. reply).
+# 1x icmp prerouting,input,output postrouting -> 4 queue events incl. reply.
+# so we expect that userspace program receives 10 packets.
+test_queue 10
+
+# same.  We queue to a second program as well.
+load_ruleset "filter2" 20
+test_queue 20
+
+test_tcp_forward
+test_tcp_localhost
+
+exit $ret
index 3a779c0..39559d7 100644 (file)
@@ -2,4 +2,5 @@ pidfd_open_test
 pidfd_poll_test
 pidfd_test
 pidfd_wait
+pidfd_fdinfo_test
 pidfd_getfd_test
index c3a49fb..1281022 100644 (file)
@@ -12,7 +12,7 @@
 # Returns 1 if the specified boot-parameter string tells rcutorture to
 # test CPU-hotplug operations.
 bootparam_hotplug_cpu () {
-       echo "$1" | grep -q "rcutorture\.onoff_"
+       echo "$1" | grep -q "torture\.onoff_"
 }
 
 # checkarg --argname argtype $# arg mustmatch cannotmatch
index 1871d00..6f50722 100755 (executable)
@@ -20,7 +20,9 @@
 rundir="${1}"
 if test -z "$rundir" -o ! -d "$rundir"
 then
+       echo Directory "$rundir" not found.
        echo Usage: $0 directory
+       exit 1
 fi
 editor=${EDITOR-vi}
 
index e5edd51..0326f4a 100755 (executable)
@@ -13,6 +13,9 @@
 #
 # Authors: Paul E. McKenney <paulmck@linux.ibm.com>
 
+T=/tmp/kvm-recheck.sh.$$
+trap 'rm -f $T' 0 2
+
 PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH
 . functions.sh
 for rd in "$@"
@@ -68,4 +71,16 @@ do
                fi
        done
 done
-EDITOR=echo kvm-find-errors.sh "${@: -1}" > /dev/null 2>&1
+EDITOR=echo kvm-find-errors.sh "${@: -1}" > $T 2>&1
+ret=$?
+builderrors="`tr ' ' '\012' < $T | grep -c '/Make.out.diags'`"
+if test "$builderrors" -gt 0
+then
+       echo $builderrors runs with build errors.
+fi
+runerrors="`tr ' ' '\012' < $T | grep -c '/console.log.diags'`"
+if test "$runerrors" -gt 0
+then
+       echo $runerrors runs with runtime errors.
+fi
+exit $ret
index 78d18ab..2315e2e 100755 (executable)
@@ -39,7 +39,7 @@ TORTURE_TRUST_MAKE=""
 resdir=""
 configs=""
 cpus=0
-ds=`date +%Y.%m.%d-%H:%M:%S`
+ds=`date +%Y.%m.%d-%H.%M.%S`
 jitter="-1"
 
 usage () {
index e19a444..0e92d85 100644 (file)
@@ -3,3 +3,5 @@ CONFIG_PRINTK_TIME=y
 CONFIG_HYPERVISOR_GUEST=y
 CONFIG_PARAVIRT=y
 CONFIG_KVM_GUEST=y
+CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC=n
+CONFIG_KCSAN_REPORT_VALUE_CHANGE_ONLY=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE10 b/tools/testing/selftests/rcutorture/configs/rcu/TREE10
new file mode 100644 (file)
index 0000000..2debe78
--- /dev/null
@@ -0,0 +1,18 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=100
+CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=n
+#CHECK#CONFIG_TREE_RCU=y
+CONFIG_HZ_PERIODIC=n
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_FAST_NO_HZ=n
+CONFIG_RCU_TRACE=n
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_LOCKING=n
+#CHECK#CONFIG_PROVE_RCU=n
+CONFIG_DEBUG_OBJECTS=n
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=n
index d646953..2af9d39 100644 (file)
@@ -4,7 +4,7 @@ ifneq ($(shell $(CC) --version 2>&1 | head -n 1 | grep clang),)
 CLANG_FLAGS += -no-integrated-as
 endif
 
-CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/ -L./ -Wl,-rpath=./ \
+CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/ -L$(OUTPUT) -Wl,-rpath=./ \
          $(CLANG_FLAGS)
 LDLIBS += -lpthread
 
@@ -19,6 +19,8 @@ TEST_GEN_PROGS_EXTENDED = librseq.so
 
 TEST_PROGS = run_param_test.sh
 
+TEST_FILES := settings
+
 include ../lib.mk
 
 $(OUTPUT)/librseq.so: rseq.c rseq.h rseq-*.h
index 2d93d65..55198ec 100644 (file)
@@ -6,4 +6,6 @@ TEST_GEN_PROGS = rtctest
 
 TEST_GEN_PROGS_EXTENDED = setdate
 
+TEST_FILES := settings
+
 include ../lib.mk
index ee1b727..a9ad3bd 100644 (file)
@@ -212,6 +212,10 @@ struct seccomp_notif_sizes {
 #define SECCOMP_USER_NOTIF_FLAG_CONTINUE 0x00000001
 #endif
 
+#ifndef SECCOMP_FILTER_FLAG_TSYNC_ESRCH
+#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4)
+#endif
+
 #ifndef seccomp
 int seccomp(unsigned int op, unsigned int flags, void *args)
 {
@@ -2187,7 +2191,8 @@ TEST(detect_seccomp_filter_flags)
        unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC,
                                 SECCOMP_FILTER_FLAG_LOG,
                                 SECCOMP_FILTER_FLAG_SPEC_ALLOW,
-                                SECCOMP_FILTER_FLAG_NEW_LISTENER };
+                                SECCOMP_FILTER_FLAG_NEW_LISTENER,
+                                SECCOMP_FILTER_FLAG_TSYNC_ESRCH };
        unsigned int exclusive[] = {
                                SECCOMP_FILTER_FLAG_TSYNC,
                                SECCOMP_FILTER_FLAG_NEW_LISTENER };
@@ -2645,6 +2650,55 @@ TEST_F(TSYNC, two_siblings_with_one_divergence)
        EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
 }
 
+TEST_F(TSYNC, two_siblings_with_one_divergence_no_tid_in_err)
+{
+       long ret, flags;
+       void *status;
+
+       ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+               TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
+       }
+
+       ret = seccomp(SECCOMP_SET_MODE_FILTER, 0, &self->root_prog);
+       ASSERT_NE(ENOSYS, errno) {
+               TH_LOG("Kernel does not support seccomp syscall!");
+       }
+       ASSERT_EQ(0, ret) {
+               TH_LOG("Kernel does not support SECCOMP_SET_MODE_FILTER!");
+       }
+       self->sibling[0].diverge = 1;
+       tsync_start_sibling(&self->sibling[0]);
+       tsync_start_sibling(&self->sibling[1]);
+
+       while (self->sibling_count < TSYNC_SIBLINGS) {
+               sem_wait(&self->started);
+               self->sibling_count++;
+       }
+
+       flags = SECCOMP_FILTER_FLAG_TSYNC | \
+               SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
+       ret = seccomp(SECCOMP_SET_MODE_FILTER, flags, &self->apply_prog);
+       ASSERT_EQ(ESRCH, errno) {
+               TH_LOG("Did not return ESRCH for diverged sibling.");
+       }
+       ASSERT_EQ(-1, ret) {
+               TH_LOG("Did not fail on diverged sibling.");
+       }
+
+       /* Wake the threads */
+       pthread_mutex_lock(&self->mutex);
+       ASSERT_EQ(0, pthread_cond_broadcast(&self->cond)) {
+               TH_LOG("cond broadcast non-zero");
+       }
+       pthread_mutex_unlock(&self->mutex);
+
+       /* Ensure they are both unkilled. */
+       PTHREAD_JOIN(self->sibling[0].tid, &status);
+       EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
+       PTHREAD_JOIN(self->sibling[1].tid, &status);
+       EXPECT_EQ(SIBLING_EXIT_UNKILLED, (long)status);
+}
+
 TEST_F(TSYNC, two_siblings_not_under_filter)
 {
        long ret, sib;
@@ -3196,6 +3250,24 @@ TEST(user_notification_basic)
        EXPECT_EQ(0, WEXITSTATUS(status));
 }
 
+TEST(user_notification_with_tsync)
+{
+       int ret;
+       unsigned int flags;
+
+       /* these were exclusive */
+       flags = SECCOMP_FILTER_FLAG_NEW_LISTENER |
+               SECCOMP_FILTER_FLAG_TSYNC;
+       ASSERT_EQ(-1, user_trap_syscall(__NR_getppid, flags));
+       ASSERT_EQ(EINVAL, errno);
+
+       /* but now they're not */
+       flags |= SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
+       ret = user_trap_syscall(__NR_getppid, flags);
+       close(ret);
+       ASSERT_LE(0, ret);
+}
+
 TEST(user_notification_kill_in_middle)
 {
        pid_t pid;
index 477bc61..c03af46 100644 (file)
@@ -57,3 +57,4 @@ CONFIG_NET_IFE_SKBMARK=m
 CONFIG_NET_IFE_SKBPRIO=m
 CONFIG_NET_IFE_SKBTCINDEX=m
 CONFIG_NET_SCH_FIFO=y
+CONFIG_NET_SCH_ETS=m
index 138d46b..936e1ca 100755 (executable)
@@ -527,11 +527,16 @@ n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0
 n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75
 n0 wg set wg0 peer "$pub2" allowed-ips ::/0
 n0 wg set wg0 peer "$pub2" remove
-low_order_points=( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38= )
-n0 wg set wg0 private-key /dev/null ${low_order_points[@]/#/peer }
-[[ -z $(n0 wg show wg0 peers) ]]
-n0 wg set wg0 private-key <(echo "$key1") ${low_order_points[@]/#/peer }
-[[ -z $(n0 wg show wg0 peers) ]]
+for low_order_point in AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 4Ot6fDtBuK4WVuP68Z/EatoJjeucMrH9hmIFFl9JuAA= X5yVvKNQjCSx0LFVnIPvWwREXMRYHI6G2CJO3dCfEVc= 7P///////////////////////////////////////38= 7f///////////////////////////////////////38= 7v///////////////////////////////////////38=; do
+       n0 wg set wg0 peer "$low_order_point" persistent-keepalive 1 endpoint 127.0.0.1:1111
+done
+[[ -n $(n0 wg show wg0 peers) ]]
+exec 4< <(n0 ncat -l -u -p 1111)
+ncat_pid=$!
+waitncatudp $netns0 $ncat_pid
+ip0 link set wg0 up
+! read -r -n 1 -t 2 <&4 || false
+kill $ncat_pid
 ip0 link del wg0
 
 declare -A objects
index 28d4776..90598a4 100644 (file)
@@ -41,7 +41,7 @@ $(DISTFILES_PATH)/$(1):
        flock -x $$@.lock -c '[ -f $$@ ] && exit 0; wget -O $$@.tmp $(MIRROR)$(1) || wget -O $$@.tmp $(2)$(1) || rm -f $$@.tmp; [ -f $$@.tmp ] || exit 1; if echo "$(3)  $$@.tmp" | sha256sum -c -; then mv $$@.tmp $$@; else rm -f $$@.tmp; exit 71; fi'
 endef
 
-$(eval $(call tar_download,MUSL,musl,1.1.24,.tar.gz,https://www.musl-libc.org/releases/,1370c9a812b2cf2a7d92802510cca0058cc37e66a7bedd70051f0a34015022a3))
+$(eval $(call tar_download,MUSL,musl,1.2.0,.tar.gz,https://musl.libc.org/releases/,c6de7b191139142d3f9a7b5b702c9cae1b5ee6e7f57e582da9328629408fd4e8))
 $(eval $(call tar_download,IPERF,iperf,3.7,.tar.gz,https://downloads.es.net/pub/iperf/,d846040224317caf2f75c843d309a950a7db23f9b44b94688ccbe557d6d1710c))
 $(eval $(call tar_download,BASH,bash,5.0,.tar.gz,https://ftp.gnu.org/gnu/bash/,b4a80f2ac66170b2913efbfb9f2594f1f76c7b1afd11f799e22035d63077fb4d))
 $(eval $(call tar_download,IPROUTE2,iproute2,5.4.0,.tar.xz,https://www.kernel.org/pub/linux/utils/net/iproute2/,fe97aa60a0d4c5ac830be18937e18dc3400ca713a33a89ad896ff1e3d46086ae))
index 90bc981..c969812 100644 (file)
@@ -13,7 +13,6 @@
 #include <fcntl.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
-#include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/io.h>
index af9323a..d531de1 100644 (file)
@@ -56,7 +56,6 @@ CONFIG_NO_HZ_IDLE=y
 CONFIG_NO_HZ_FULL=n
 CONFIG_HZ_PERIODIC=n
 CONFIG_HIGH_RES_TIMERS=y
-CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_ARCH_RANDOM=y
 CONFIG_FILE_LOCKING=y
 CONFIG_POSIX_TIMERS=y
index bdf5bbd..96afb03 100644 (file)
@@ -124,17 +124,6 @@ choice
 
          If in doubt, select 'None'
 
-config INITRAMFS_COMPRESSION_NONE
-       bool "None"
-       help
-         Do not compress the built-in initramfs at all. This may sound wasteful
-         in space, but, you should be aware that the built-in initramfs will be
-         compressed at a later stage anyways along with the rest of the kernel,
-         on those architectures that support this. However, not compressing the
-         initramfs may lead to slightly higher memory consumption during a
-         short time at boot, while both the cpio image and the unpacked
-         filesystem image will be present in memory simultaneously
-
 config INITRAMFS_COMPRESSION_GZIP
        bool "Gzip"
        depends on RD_GZIP
@@ -207,4 +196,15 @@ config INITRAMFS_COMPRESSION_LZ4
          If you choose this, keep in mind that most distros don't provide lz4
          by default which could cause a build failure.
 
+config INITRAMFS_COMPRESSION_NONE
+       bool "None"
+       help
+         Do not compress the built-in initramfs at all. This may sound wasteful
+         in space, but, you should be aware that the built-in initramfs will be
+         compressed at a later stage anyways along with the rest of the kernel,
+         on those architectures that support this. However, not compressing the
+         initramfs may lead to slightly higher memory consumption during a
+         short time at boot, while both the cpio image and the unpacked
+         filesystem image will be present in memory simultaneously
+
 endchoice
index d65a0fa..eda7b62 100644 (file)
@@ -742,9 +742,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                guest_enter_irqoff();
 
                if (has_vhe()) {
-                       kvm_arm_vhe_guest_enter();
                        ret = kvm_vcpu_run_vhe(vcpu);
-                       kvm_arm_vhe_guest_exit();
                } else {
                        ret = kvm_call_hyp_ret(__kvm_vcpu_run_nvhe, vcpu);
                }
index 204d210..cc94ccc 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <kvm/arm_arch_timer.h>
 #include <linux/tracepoint.h>
+#include <asm/kvm_arm.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM kvm
index f45635a..1bc09b5 100644 (file)
@@ -595,7 +595,9 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
        /* GICv4 support? */
        if (info->has_v4) {
                kvm_vgic_global_state.has_gicv4 = gicv4_enable;
-               kvm_info("GICv4 support %sabled\n",
+               kvm_vgic_global_state.has_gicv4_1 = info->has_v4_1 && gicv4_enable;
+               kvm_info("GICv4%s support %sabled\n",
+                        kvm_vgic_global_state.has_gicv4_1 ? ".1" : "",
                         gicv4_enable ? "en" : "dis");
        }
 
index 46f8755..1eb0f8c 100644 (file)
  * it. And if we've migrated our vcpu from one CPU to another, we must
  * tell the ITS (so that the messages reach the right redistributor).
  * This is done in two steps: first issue a irq_set_affinity() on the
- * irq corresponding to the vcpu, then call its_schedule_vpe(). You
- * must be in a non-preemptible context. On exit, another call to
- * its_schedule_vpe() tells the redistributor that we're done with the
- * vcpu.
+ * irq corresponding to the vcpu, then call its_make_vpe_resident().
+ * You must be in a non-preemptible context. On exit, a call to
+ * its_make_vpe_non_resident() tells the redistributor that we're done
+ * with the vcpu.
  *
  * Finally, the doorbell handling: Each vcpu is allocated an interrupt
  * which will fire each time a VLPI is made pending whilst the vcpu is
@@ -86,7 +86,8 @@ static irqreturn_t vgic_v4_doorbell_handler(int irq, void *info)
        struct kvm_vcpu *vcpu = info;
 
        /* We got the message, no need to fire again */
-       if (!irqd_irq_disabled(&irq_to_desc(irq)->irq_data))
+       if (!kvm_vgic_global_state.has_gicv4_1 &&
+           !irqd_irq_disabled(&irq_to_desc(irq)->irq_data))
                disable_irq_nosync(irq);
 
        vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last = true;
@@ -199,19 +200,11 @@ void vgic_v4_teardown(struct kvm *kvm)
 int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db)
 {
        struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
-       struct irq_desc *desc = irq_to_desc(vpe->irq);
 
        if (!vgic_supports_direct_msis(vcpu->kvm) || !vpe->resident)
                return 0;
 
-       /*
-        * If blocking, a doorbell is required. Undo the nested
-        * disable_irq() calls...
-        */
-       while (need_db && irqd_irq_disabled(&desc->irq_data))
-               enable_irq(vpe->irq);
-
-       return its_schedule_vpe(vpe, false);
+       return its_make_vpe_non_resident(vpe, need_db);
 }
 
 int vgic_v4_load(struct kvm_vcpu *vcpu)
@@ -232,18 +225,19 @@ int vgic_v4_load(struct kvm_vcpu *vcpu)
        if (err)
                return err;
 
-       /* Disabled the doorbell, as we're about to enter the guest */
-       disable_irq_nosync(vpe->irq);
-
-       err = its_schedule_vpe(vpe, true);
+       err = its_make_vpe_resident(vpe, false, vcpu->kvm->arch.vgic.enabled);
        if (err)
                return err;
 
        /*
         * Now that the VPE is resident, let's get rid of a potential
-        * doorbell interrupt that would still be pending.
+        * doorbell interrupt that would still be pending. This is a
+        * GICv4.0 only "feature"...
         */
-       return irq_set_irqchip_state(vpe->irq, IRQCHIP_STATE_PENDING, false);
+       if (!kvm_vgic_global_state.has_gicv4_1)
+               err = irq_set_irqchip_state(vpe->irq, IRQCHIP_STATE_PENDING, false);
+
+       return err;
 }
 
 static struct vgic_its *vgic_get_its(struct kvm *kvm,